You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1072 lines
28 KiB
1072 lines
28 KiB
|
|
/*******************************************************************************
|
|
*
|
|
* TRACE.C
|
|
* This module implements the trace functions
|
|
*
|
|
* Copyright 1998, Microsoft.
|
|
*
|
|
*
|
|
******************************************************************************/
|
|
|
|
/*
|
|
* Includes
|
|
*/
|
|
#include <precomp.h>
|
|
#pragma hdrstop
|
|
|
|
#include <ctxdd.h>
|
|
|
|
|
|
/*=============================================================================
|
|
== External Functions Defined
|
|
=============================================================================*/
|
|
|
|
NTSTATUS IcaStartStopTrace( PICA_TRACE_INFO, PICA_TRACE );
|
|
|
|
VOID _cdecl IcaSystemTrace( ULONG, ULONG, CHAR *, ... );
|
|
VOID IcaSystemTraceBuffer( ULONG, ULONG, PVOID, ULONG );
|
|
|
|
VOID _cdecl IcaStackTrace( PSDCONTEXT, ULONG, ULONG, CHAR *, ... );
|
|
VOID IcaStackTraceBuffer( PSDCONTEXT, ULONG, ULONG, PVOID, ULONG );
|
|
|
|
VOID IcaTraceFormat( PICA_TRACE_INFO, ULONG, ULONG, CHAR * );
|
|
|
|
VOID _cdecl _IcaTrace( PICA_CONNECTION, ULONG, ULONG, CHAR *, ... );
|
|
VOID _cdecl _IcaStackTrace( PICA_STACK, ULONG, ULONG, CHAR *, ... );
|
|
VOID _IcaStackTraceBuffer( PICA_STACK, ULONG, ULONG, PVOID, ULONG );
|
|
VOID _cdecl _IcaChannelTrace( PICA_CHANNEL, ULONG, ULONG, CHAR *, ... );
|
|
|
|
|
|
/*=============================================================================
|
|
== Internal functions
|
|
=============================================================================*/
|
|
|
|
NTSTATUS _IcaOpenTraceFile( PICA_TRACE_INFO, PWCHAR );
|
|
VOID _IcaCloseTraceFile( PICA_TRACE_INFO );
|
|
VOID _IcaTraceWrite( PICA_TRACE_INFO, PVOID );
|
|
VOID _IcaFlushDeferredTrace( PICA_TRACE_INFO );
|
|
int _FormatTime( CHAR *, ULONG );
|
|
int _FormatThreadId( CHAR *, ULONG );
|
|
VOID _WriteHexData( PICA_TRACE_INFO, PVOID, ULONG );
|
|
|
|
|
|
/*=============================================================================
|
|
== Global variables
|
|
=============================================================================*/
|
|
|
|
/*
|
|
* Trace info
|
|
*/
|
|
ICA_TRACE_INFO G_TraceInfo = { 0, 0, FALSE, FALSE, NULL, NULL, NULL };
|
|
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* IcaStartStopTrace
|
|
*
|
|
* Start/stop tracing
|
|
*
|
|
* ENTRY:
|
|
* pTraceInfo (input)
|
|
* pointer to ICA_TRACE_INFO struct
|
|
* pTrace (input)
|
|
* pointer to ICA_TRACE (IOCTL) trace settings
|
|
*
|
|
* EXIT:
|
|
* STATUS_SUCCESS - no error
|
|
*
|
|
******************************************************************************/
|
|
|
|
NTSTATUS
|
|
IcaStartStopTrace(
|
|
IN PICA_TRACE_INFO pTraceInfo,
|
|
IN PICA_TRACE pTrace
|
|
)
|
|
{
|
|
NTSTATUS Status;
|
|
|
|
/*
|
|
* If a trace file was specified,
|
|
* then open it and save a pointer to the file object.
|
|
*/
|
|
if ( pTrace->TraceFile[0] ) {
|
|
/*
|
|
* Force a null termination for file name.
|
|
*/
|
|
pTrace->TraceFile[255] = (WCHAR)0;
|
|
Status = _IcaOpenTraceFile( pTraceInfo, pTrace->TraceFile );
|
|
if ( !NT_SUCCESS( Status ) )
|
|
return( Status );
|
|
|
|
/*
|
|
* If no trace file specified, then close any existing trace file
|
|
*/
|
|
} else if ( pTraceInfo->pTraceFileName ) {
|
|
_IcaCloseTraceFile( pTraceInfo );
|
|
}
|
|
|
|
/*
|
|
* Set trace flags
|
|
*/
|
|
pTraceInfo->fTraceDebugger = pTrace->fDebugger;
|
|
pTraceInfo->fTraceTimestamp = pTrace->fTimestamp;
|
|
pTraceInfo->TraceClass = pTrace->TraceClass;
|
|
pTraceInfo->TraceEnable = pTrace->TraceEnable;
|
|
|
|
|
|
return( STATUS_SUCCESS );
|
|
}
|
|
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* IcaSystemTrace
|
|
*
|
|
* This routine conditional writes a trace record to the system trace file
|
|
*
|
|
* ENTRY:
|
|
* TraceClass (input)
|
|
* trace class bit mask
|
|
* TraceEnable (input)
|
|
* trace type bit mask
|
|
* Format (input)
|
|
* format string
|
|
* ... (input)
|
|
* enough arguments to satisfy format string
|
|
*
|
|
* EXIT:
|
|
* nothing
|
|
*
|
|
******************************************************************************/
|
|
|
|
VOID _cdecl
|
|
IcaSystemTrace( IN ULONG TraceClass,
|
|
IN ULONG TraceEnable,
|
|
IN CHAR * Format,
|
|
IN ... )
|
|
{
|
|
va_list arg_marker;
|
|
char Buffer[256];
|
|
|
|
va_start( arg_marker, Format );
|
|
|
|
/*
|
|
* Check if this trace record should be output
|
|
*/
|
|
if ( !(TraceClass & G_TraceInfo.TraceClass) || !(TraceEnable & G_TraceInfo.TraceEnable) )
|
|
return;
|
|
|
|
/*
|
|
* Format trace data
|
|
*/
|
|
_vsnprintf( Buffer, sizeof(Buffer), Format, arg_marker );
|
|
Buffer[sizeof(Buffer) -1] = '\0';
|
|
|
|
/*
|
|
* Write trace data
|
|
*/
|
|
IcaTraceFormat( &G_TraceInfo, TraceClass, TraceEnable, Buffer );
|
|
}
|
|
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* IcaSystemTraceBuffer
|
|
*
|
|
* This routine conditional writes a data buffer to the system trace file
|
|
*
|
|
* ENTRY:
|
|
* TraceClass (input)
|
|
* trace class bit mask
|
|
* TraceEnable (input)
|
|
* trace type bit mask
|
|
* pBuffer (input)
|
|
* pointer to data buffer
|
|
* ByteCount (input)
|
|
* length of buffer
|
|
*
|
|
* EXIT:
|
|
* nothing
|
|
*
|
|
******************************************************************************/
|
|
|
|
VOID
|
|
IcaSystemTraceBuffer( IN ULONG TraceClass,
|
|
IN ULONG TraceEnable,
|
|
IN PVOID pBuffer,
|
|
IN ULONG ByteCount )
|
|
{
|
|
/*
|
|
* Check if this trace record should be output
|
|
*/
|
|
if ( !(TraceClass & G_TraceInfo.TraceClass) ||
|
|
!(TraceEnable & G_TraceInfo.TraceEnable) )
|
|
return;
|
|
|
|
/*
|
|
* Write trace data
|
|
*/
|
|
_WriteHexData( &G_TraceInfo, pBuffer, ByteCount );
|
|
}
|
|
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* IcaStackTrace
|
|
*
|
|
* This routine conditional writes a trace record depending on the trace mask
|
|
*
|
|
* ENTRY:
|
|
* pContext (input)
|
|
* pointer to stack driver context
|
|
* TraceClass (input)
|
|
* trace class bit mask
|
|
* TraceEnable (input)
|
|
* trace type bit mask
|
|
* Format (input)
|
|
* format string
|
|
* ... (input)
|
|
* enough arguments to satisfy format string
|
|
*
|
|
* EXIT:
|
|
* nothing
|
|
*
|
|
******************************************************************************/
|
|
|
|
VOID _cdecl
|
|
IcaStackTrace( IN PSDCONTEXT pContext,
|
|
IN ULONG TraceClass,
|
|
IN ULONG TraceEnable,
|
|
IN CHAR * Format,
|
|
IN ... )
|
|
{
|
|
va_list arg_marker;
|
|
char Buffer[256];
|
|
PICA_STACK pStack;
|
|
PICA_CONNECTION pConnect;
|
|
PICA_TRACE_INFO pTraceInfo;
|
|
|
|
va_start( arg_marker, Format );
|
|
|
|
/*
|
|
* Use SD passed context to get the STACK object pointer.
|
|
*/
|
|
pStack = (CONTAINING_RECORD( pContext, SDLINK, SdContext ))->pStack;
|
|
pConnect = IcaGetConnectionForStack( pStack );
|
|
|
|
/*
|
|
* Check if this trace record should be output
|
|
*/
|
|
pTraceInfo = &pConnect->TraceInfo;
|
|
if ( !(TraceClass & pTraceInfo->TraceClass) ||
|
|
!(TraceEnable & pTraceInfo->TraceEnable) )
|
|
return;
|
|
|
|
/*
|
|
* Format trace data
|
|
*/
|
|
_vsnprintf( Buffer, sizeof(Buffer), Format, arg_marker );
|
|
Buffer[sizeof(Buffer) -1] = '\0';
|
|
|
|
/*
|
|
* Write trace data
|
|
*/
|
|
IcaTraceFormat( pTraceInfo, TraceClass, TraceEnable, Buffer );
|
|
}
|
|
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* IcaStackTraceBuffer
|
|
*
|
|
* This routine conditional writes a data buffer to the trace file
|
|
*
|
|
* ENTRY:
|
|
* pContext (input)
|
|
* pointer to stack driver context
|
|
* TraceClass (input)
|
|
* trace class bit mask
|
|
* TraceEnable (input)
|
|
* trace type bit mask
|
|
* pBuffer (input)
|
|
* pointer to data buffer
|
|
* ByteCount (input)
|
|
* length of buffer
|
|
*
|
|
* EXIT:
|
|
* nothing
|
|
*
|
|
******************************************************************************/
|
|
|
|
VOID
|
|
IcaStackTraceBuffer( IN PSDCONTEXT pContext,
|
|
IN ULONG TraceClass,
|
|
IN ULONG TraceEnable,
|
|
IN PVOID pBuffer,
|
|
IN ULONG ByteCount )
|
|
{
|
|
PICA_TRACE_INFO pTraceInfo;
|
|
PICA_STACK pStack;
|
|
PICA_CONNECTION pConnect;
|
|
|
|
/*
|
|
* Use SD passed context to get the STACK object pointer.
|
|
*/
|
|
pStack = (CONTAINING_RECORD( pContext, SDLINK, SdContext ))->pStack;
|
|
pConnect = IcaGetConnectionForStack( pStack );
|
|
|
|
/*
|
|
* Check if this trace record should be output
|
|
*/
|
|
pTraceInfo = &pConnect->TraceInfo;
|
|
if ( !(TraceClass & pTraceInfo->TraceClass) ||
|
|
!(TraceEnable & pTraceInfo->TraceEnable) )
|
|
return;
|
|
|
|
/*
|
|
* Write trace data
|
|
*/
|
|
_WriteHexData( pTraceInfo, pBuffer, ByteCount );
|
|
}
|
|
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* IcaTraceFormat
|
|
*
|
|
* This routine conditional writes trace data depending on the trace mask
|
|
*
|
|
* ENTRY:
|
|
* pTraceInfo (input)
|
|
* pointer to ICA_TRACE_INFO struct
|
|
* TraceClass (input)
|
|
* trace class bit mask
|
|
* TraceEnable (input)
|
|
* trace type bit mask
|
|
* pData (input)
|
|
* pointer to null terminated trace data
|
|
*
|
|
* EXIT:
|
|
* nothing
|
|
*
|
|
******************************************************************************/
|
|
|
|
VOID
|
|
IcaTraceFormat( IN PICA_TRACE_INFO pTraceInfo,
|
|
IN ULONG TraceClass,
|
|
IN ULONG TraceEnable,
|
|
IN CHAR * pData )
|
|
{
|
|
char Buffer[256];
|
|
char * pBuf;
|
|
int len = 0;
|
|
int i;
|
|
|
|
/*
|
|
* Check if this trace record should be output
|
|
*/
|
|
if ( !(TraceClass & pTraceInfo->TraceClass) || !(TraceEnable & pTraceInfo->TraceEnable) )
|
|
return;
|
|
|
|
pBuf = Buffer;
|
|
|
|
/*
|
|
* Append time stamp
|
|
*/
|
|
if ( pTraceInfo->fTraceTimestamp ) {
|
|
len = _FormatTime( pBuf, sizeof(Buffer) );
|
|
pBuf += len;
|
|
}
|
|
|
|
/*
|
|
* Append thread id
|
|
*/
|
|
i = _FormatThreadId( pBuf, sizeof(Buffer) - len );
|
|
len += i;
|
|
pBuf += i;
|
|
|
|
/*
|
|
* Append trace data
|
|
*/
|
|
_snprintf( pBuf, sizeof(Buffer) - len, pData );
|
|
|
|
/*
|
|
* Write trace data
|
|
*/
|
|
_IcaTraceWrite( pTraceInfo, Buffer );
|
|
}
|
|
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* _IcaTrace
|
|
*
|
|
* Write a trace record to the winstation trace file
|
|
*
|
|
* ENTRY:
|
|
* pConnect (input)
|
|
* pointer to connection structure
|
|
* TraceClass (input)
|
|
* trace class bit mask
|
|
* TraceEnable (input)
|
|
* trace type bit mask
|
|
* Format (input)
|
|
* format string
|
|
* ... (input)
|
|
* enough arguments to satisfy format string
|
|
*
|
|
* EXIT:
|
|
* nothing
|
|
*
|
|
******************************************************************************/
|
|
|
|
VOID _cdecl
|
|
_IcaTrace( IN PICA_CONNECTION pConnect,
|
|
IN ULONG TraceClass,
|
|
IN ULONG TraceEnable,
|
|
IN CHAR * Format,
|
|
IN ... )
|
|
{
|
|
va_list arg_marker;
|
|
char Buffer[256];
|
|
PICA_TRACE_INFO pTraceInfo;
|
|
|
|
ASSERT( pConnect->Header.Type == IcaType_Connection );
|
|
|
|
va_start( arg_marker, Format );
|
|
|
|
pTraceInfo = &pConnect->TraceInfo;
|
|
|
|
/*
|
|
* Check if this trace record should be output
|
|
*/
|
|
if ( !(TraceClass & pTraceInfo->TraceClass) || !(TraceEnable & pTraceInfo->TraceEnable) )
|
|
return;
|
|
|
|
/*
|
|
* Format trace data
|
|
*/
|
|
_vsnprintf( Buffer, sizeof(Buffer), Format, arg_marker );
|
|
Buffer[sizeof(Buffer) -1] = '\0';
|
|
|
|
/*
|
|
* Write trace data
|
|
*/
|
|
IcaTraceFormat( pTraceInfo, TraceClass, TraceEnable, Buffer );
|
|
}
|
|
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* _IcaStackTrace
|
|
*
|
|
* Write a trace record to the winstation trace file
|
|
*
|
|
* ENTRY:
|
|
* pStack (input)
|
|
* pointer to stack structure
|
|
* TraceClass (input)
|
|
* trace class bit mask
|
|
* TraceEnable (input)
|
|
* trace type bit mask
|
|
* Format (input)
|
|
* format string
|
|
* ... (input)
|
|
* enough arguments to satisfy format string
|
|
*
|
|
* EXIT:
|
|
* nothing
|
|
*
|
|
******************************************************************************/
|
|
|
|
VOID _cdecl
|
|
_IcaStackTrace( IN PICA_STACK pStack,
|
|
IN ULONG TraceClass,
|
|
IN ULONG TraceEnable,
|
|
IN CHAR * Format,
|
|
IN ... )
|
|
{
|
|
va_list arg_marker;
|
|
char Buffer[256];
|
|
PICA_CONNECTION pConnect;
|
|
PICA_TRACE_INFO pTraceInfo;
|
|
|
|
ASSERT( pStack->Header.Type == IcaType_Stack );
|
|
|
|
va_start( arg_marker, Format );
|
|
|
|
pConnect = IcaGetConnectionForStack( pStack );
|
|
|
|
/*
|
|
* Check if this trace record should be output
|
|
*/
|
|
pTraceInfo = &pConnect->TraceInfo;
|
|
if ( !(TraceClass & pTraceInfo->TraceClass) ||
|
|
!(TraceEnable & pTraceInfo->TraceEnable) )
|
|
return;
|
|
|
|
/*
|
|
* Format trace data
|
|
*/
|
|
_vsnprintf( Buffer, sizeof(Buffer), Format, arg_marker );
|
|
Buffer[sizeof(Buffer) -1] = '\0';
|
|
|
|
/*
|
|
* Write trace data
|
|
*/
|
|
IcaTraceFormat( pTraceInfo, TraceClass, TraceEnable, Buffer );
|
|
}
|
|
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* _IcaStackTraceBuffer
|
|
*
|
|
* This routine conditional writes a data buffer to the trace file
|
|
*
|
|
* ENTRY:
|
|
* pStack (input)
|
|
* pointer to stack structure
|
|
* TraceClass (input)
|
|
* trace class bit mask
|
|
* TraceEnable (input)
|
|
* trace type bit mask
|
|
* pBuffer (input)
|
|
* pointer to data buffer
|
|
* ByteCount (input)
|
|
* length of buffer
|
|
*
|
|
* EXIT:
|
|
* nothing
|
|
*
|
|
******************************************************************************/
|
|
|
|
VOID
|
|
_IcaStackTraceBuffer( IN PICA_STACK pStack,
|
|
IN ULONG TraceClass,
|
|
IN ULONG TraceEnable,
|
|
IN PVOID pBuffer,
|
|
IN ULONG ByteCount )
|
|
{
|
|
PICA_CONNECTION pConnect;
|
|
PICA_TRACE_INFO pTraceInfo;
|
|
|
|
ASSERT( pStack->Header.Type == IcaType_Stack );
|
|
|
|
pConnect = IcaGetConnectionForStack( pStack );
|
|
|
|
/*
|
|
* Check if this trace record should be output
|
|
*/
|
|
pTraceInfo = &pConnect->TraceInfo;
|
|
if ( !(TraceClass & pTraceInfo->TraceClass) ||
|
|
!(TraceEnable & pTraceInfo->TraceEnable) )
|
|
return;
|
|
|
|
/*
|
|
* Write trace data
|
|
*/
|
|
_WriteHexData( pTraceInfo, pBuffer, ByteCount );
|
|
}
|
|
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* _IcaChannelTrace
|
|
*
|
|
* Write a trace record to the winstation trace file
|
|
*
|
|
* ENTRY:
|
|
* pChannel (input)
|
|
* pointer to Channel structure
|
|
* TraceClass (input)
|
|
* trace class bit mask
|
|
* TraceEnable (input)
|
|
* trace type bit mask
|
|
* Format (input)
|
|
* format string
|
|
* ... (input)
|
|
* enough arguments to satisfy format string
|
|
*
|
|
* EXIT:
|
|
* nothing
|
|
*
|
|
******************************************************************************/
|
|
|
|
VOID _cdecl
|
|
_IcaChannelTrace( IN PICA_CHANNEL pChannel,
|
|
IN ULONG TraceClass,
|
|
IN ULONG TraceEnable,
|
|
IN CHAR * Format,
|
|
IN ... )
|
|
{
|
|
va_list arg_marker;
|
|
char Buffer[256];
|
|
PICA_TRACE_INFO pTraceInfo;
|
|
|
|
ASSERT( pChannel->Header.Type == IcaType_Channel );
|
|
|
|
va_start( arg_marker, Format );
|
|
|
|
pTraceInfo = &pChannel->pConnect->TraceInfo;
|
|
|
|
/*
|
|
* Check if this trace record should be output
|
|
*/
|
|
if ( !(TraceClass & pTraceInfo->TraceClass) || !(TraceEnable & pTraceInfo->TraceEnable) )
|
|
return;
|
|
|
|
/*
|
|
* Format trace data
|
|
*/
|
|
_vsnprintf( Buffer, sizeof(Buffer), Format, arg_marker );
|
|
Buffer[sizeof(Buffer) -1] = '\0';
|
|
|
|
/*
|
|
* Write trace data
|
|
*/
|
|
IcaTraceFormat( pTraceInfo, TraceClass, TraceEnable, Buffer );
|
|
}
|
|
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* _IcaOpenTraceFile
|
|
*
|
|
* Open a trace file
|
|
*
|
|
* ENTRY:
|
|
* pTraceInfo (input)
|
|
* pointer to ICA_TRACE_INFO struct
|
|
* pTraceFile (input)
|
|
* pointer to trace file name
|
|
*
|
|
* EXIT:
|
|
* STATUS_SUCCESS - no error
|
|
*
|
|
******************************************************************************/
|
|
|
|
#define NAMEPREFIX L"\\DosDevices\\"
|
|
|
|
NTSTATUS
|
|
_IcaOpenTraceFile(
|
|
IN PICA_TRACE_INFO pTraceInfo,
|
|
IN PWCHAR pTraceFile
|
|
)
|
|
{
|
|
UNICODE_STRING TraceString;
|
|
OBJECT_ATTRIBUTES ObjectAttributes;
|
|
IO_STATUS_BLOCK iosb;
|
|
HANDLE TraceFileHandle;
|
|
PFILE_OBJECT pTraceFileObject;
|
|
ULONG PrefixLength;
|
|
ULONG TraceFileLength;
|
|
NTSTATUS Status;
|
|
|
|
PrefixLength = wcslen( NAMEPREFIX ) * sizeof(WCHAR);
|
|
TraceFileLength = wcslen( pTraceFile ) * sizeof(WCHAR);
|
|
|
|
TraceString.Length = (USHORT) (PrefixLength + TraceFileLength);
|
|
TraceString.MaximumLength = TraceString.Length + sizeof(UNICODE_NULL);
|
|
TraceString.Buffer = ICA_ALLOCATE_POOL( NonPagedPool, TraceString.MaximumLength );
|
|
|
|
if (TraceString.Buffer != NULL) {
|
|
RtlCopyMemory( TraceString.Buffer, NAMEPREFIX, PrefixLength );
|
|
RtlCopyMemory( (char *)TraceString.Buffer + PrefixLength, pTraceFile, TraceFileLength );
|
|
TraceString.Buffer[(PrefixLength + TraceFileLength) / sizeof(WCHAR)] = UNICODE_NULL;
|
|
}
|
|
else {
|
|
return STATUS_NO_MEMORY;
|
|
}
|
|
|
|
/*
|
|
* If we already have a trace file and the name is the same
|
|
* as a previous call, then there's nothing to be done.
|
|
*/
|
|
if ( pTraceInfo->pTraceFileName != NULL &&
|
|
!_wcsicmp( TraceString.Buffer, pTraceInfo->pTraceFileName ) ) {
|
|
ICA_FREE_POOL( TraceString.Buffer );
|
|
return( STATUS_SUCCESS );
|
|
}
|
|
|
|
/*
|
|
* Close the existing trace file if there is one
|
|
*/
|
|
if ( pTraceInfo->pTraceFileName ) {
|
|
_IcaCloseTraceFile( pTraceInfo );
|
|
}
|
|
|
|
InitializeObjectAttributes( &ObjectAttributes, &TraceString,
|
|
OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL );
|
|
|
|
Status = ZwCreateFile(
|
|
&TraceFileHandle,
|
|
GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE,
|
|
&ObjectAttributes,
|
|
&iosb, // returned status information.
|
|
0, // block size (unused).
|
|
0, // file attributes.
|
|
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
|
FILE_OVERWRITE_IF, // create disposition.
|
|
0, // create options.
|
|
NULL,
|
|
0
|
|
);
|
|
if ( !NT_SUCCESS( Status ) ) {
|
|
ICA_FREE_POOL( TraceString.Buffer );
|
|
return( Status );
|
|
}
|
|
|
|
/*
|
|
* Use the trace file handle to get a pointer to the file object.
|
|
*/
|
|
Status = ObReferenceObjectByHandle(
|
|
TraceFileHandle,
|
|
0L, // DesiredAccess
|
|
*IoFileObjectType,
|
|
KernelMode,
|
|
(PVOID *)&pTraceFileObject,
|
|
NULL
|
|
);
|
|
ZwClose( TraceFileHandle );
|
|
if ( !NT_SUCCESS( Status ) ) {
|
|
ICA_FREE_POOL( TraceString.Buffer );
|
|
return( Status );
|
|
}
|
|
|
|
/*
|
|
* Save Trace file name and file object pointer
|
|
*/
|
|
pTraceInfo->pTraceFileName = TraceString.Buffer;
|
|
pTraceInfo->pTraceFileObject = pTraceFileObject;
|
|
|
|
return( STATUS_SUCCESS );
|
|
}
|
|
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* _IcaCloseTraceFile
|
|
*
|
|
* Close a trace file
|
|
*
|
|
* ENTRY:
|
|
* pTraceInfo (input)
|
|
* pointer to ICA_TRACE_INFO struct
|
|
*
|
|
* EXIT:
|
|
* STATUS_SUCCESS - no error
|
|
*
|
|
******************************************************************************/
|
|
|
|
VOID
|
|
_IcaCloseTraceFile(
|
|
IN PICA_TRACE_INFO pTraceInfo
|
|
)
|
|
{
|
|
PWCHAR pTraceFileName;
|
|
PFILE_OBJECT pTraceFileObject;
|
|
|
|
/*
|
|
* First write out any deferred trace records that exist
|
|
*/
|
|
_IcaFlushDeferredTrace( pTraceInfo );
|
|
|
|
/*
|
|
* Get/reset trace info fields
|
|
*/
|
|
pTraceFileName = pTraceInfo->pTraceFileName;
|
|
pTraceFileObject = pTraceInfo->pTraceFileObject;
|
|
pTraceInfo->pTraceFileName = NULL;
|
|
pTraceInfo->pTraceFileObject = NULL;
|
|
|
|
/*
|
|
* Close trace file and free resources
|
|
*/
|
|
ICA_FREE_POOL( pTraceFileName );
|
|
ObDereferenceObject( pTraceFileObject );
|
|
}
|
|
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* _IcaTraceWrite
|
|
*
|
|
* Write a trace file entry
|
|
*
|
|
* ENTRY:
|
|
* pTraceInfo (input)
|
|
* pointer to ICA_TRACE_INFO struct
|
|
* Buffer (input)
|
|
* pointer to trace buffer to write
|
|
*
|
|
* EXIT:
|
|
* nothing
|
|
*
|
|
******************************************************************************/
|
|
|
|
VOID
|
|
_IcaTraceWrite(
|
|
IN PICA_TRACE_INFO pTraceInfo,
|
|
IN PVOID Buffer
|
|
)
|
|
{
|
|
KIRQL irql;
|
|
ULONG Length;
|
|
PDEFERRED_TRACE pDeferred;
|
|
PDEFERRED_TRACE *ppDeferredTrace;
|
|
NTSTATUS Status;
|
|
|
|
/*
|
|
* Write to kernel debugger if necessary
|
|
*/
|
|
if ( pTraceInfo->fTraceDebugger )
|
|
DbgPrint( "%s", Buffer );
|
|
|
|
/*
|
|
* If no file object pointer, then we're done
|
|
*/
|
|
if ( pTraceInfo->pTraceFileObject == NULL )
|
|
return;
|
|
|
|
Length = strlen(Buffer);
|
|
|
|
/*
|
|
* If current Irql is DISPATCH_LEVEL or higher, then we can't
|
|
* write the data now, so queue it for later writing.
|
|
*/
|
|
irql = KeGetCurrentIrql();
|
|
if ( irql >= DISPATCH_LEVEL ) {
|
|
KIRQL oldIrql;
|
|
|
|
/*
|
|
* Allocate and initialize a deferred trace entry
|
|
*/
|
|
pDeferred = ICA_ALLOCATE_POOL( NonPagedPool, sizeof(*pDeferred) + Length );
|
|
if ( pDeferred == NULL )
|
|
return;
|
|
pDeferred->Next = NULL;
|
|
pDeferred->Length = Length;
|
|
RtlCopyMemory( pDeferred->Buffer, Buffer, Length );
|
|
|
|
/*
|
|
* Since the deferred list may be manipulated in
|
|
* _IcaFlushDeferredTrace on behalf of an IOCTL_SYSTEM_TRACE
|
|
* which does not hold any locks, IcaSpinLock is used to
|
|
* ensure the list's integrity.
|
|
*/
|
|
IcaAcquireSpinLock( &IcaTraceSpinLock, &oldIrql );
|
|
|
|
/*
|
|
* Add it to the end of the list
|
|
*/
|
|
ppDeferredTrace = &pTraceInfo->pDeferredTrace;
|
|
while ( *ppDeferredTrace )
|
|
ppDeferredTrace = &(*ppDeferredTrace)->Next;
|
|
*ppDeferredTrace = pDeferred;
|
|
|
|
IcaReleaseSpinLock( &IcaTraceSpinLock, oldIrql );
|
|
return;
|
|
}
|
|
|
|
/*
|
|
* Write out any deferred trace records that exist
|
|
*/
|
|
_IcaFlushDeferredTrace( pTraceInfo );
|
|
|
|
/*
|
|
* Now write the current trace buffer
|
|
*/
|
|
CtxWriteFile( pTraceInfo->pTraceFileObject, Buffer, Length, NULL, NULL, NULL );
|
|
}
|
|
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* _IcaFlushDeferredTrace
|
|
*
|
|
* Write any deferred trace file entries
|
|
*
|
|
* ENTRY:
|
|
* pTraceInfo (input)
|
|
* pointer to ICA_TRACE_INFO struct
|
|
*
|
|
* EXIT:
|
|
* nothing
|
|
*
|
|
******************************************************************************/
|
|
|
|
VOID
|
|
_IcaFlushDeferredTrace( PICA_TRACE_INFO pTraceInfo )
|
|
{
|
|
KIRQL oldIrql;
|
|
PDEFERRED_TRACE pDeferred;
|
|
|
|
IcaAcquireSpinLock( &IcaTraceSpinLock, &oldIrql );
|
|
while ( (pDeferred = pTraceInfo->pDeferredTrace) ) {
|
|
pTraceInfo->pDeferredTrace = pDeferred->Next;
|
|
IcaReleaseSpinLock( &IcaTraceSpinLock, oldIrql );
|
|
|
|
CtxWriteFile( pTraceInfo->pTraceFileObject, pDeferred->Buffer,
|
|
pDeferred->Length, NULL, NULL, NULL );
|
|
ICA_FREE_POOL( pDeferred );
|
|
|
|
IcaAcquireSpinLock( &IcaTraceSpinLock, &oldIrql );
|
|
}
|
|
IcaReleaseSpinLock( &IcaTraceSpinLock, oldIrql );
|
|
}
|
|
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* _FormatTime
|
|
*
|
|
* format current time into buffer
|
|
*
|
|
* ENTRY:
|
|
* pBuffer (output)
|
|
* pointer to buffer
|
|
* Length (input)
|
|
* length of buffer
|
|
*
|
|
* EXIT:
|
|
* length of formated time
|
|
*
|
|
******************************************************************************/
|
|
|
|
int
|
|
_FormatTime( CHAR * pBuffer, ULONG Length )
|
|
{
|
|
LARGE_INTEGER SystemTime;
|
|
LARGE_INTEGER LocalTime;
|
|
TIME_FIELDS TimeFields;
|
|
int len;
|
|
|
|
/*
|
|
* Get local time
|
|
*/
|
|
KeQuerySystemTime( &SystemTime );
|
|
ExSystemTimeToLocalTime( &SystemTime, &LocalTime );
|
|
RtlTimeToTimeFields( &LocalTime, &TimeFields );
|
|
|
|
/*
|
|
* Format buffer
|
|
*/
|
|
len = _snprintf( pBuffer,
|
|
Length,
|
|
"%02d:%02d:%02d.%03d ",
|
|
TimeFields.Hour,
|
|
TimeFields.Minute,
|
|
TimeFields.Second,
|
|
TimeFields.Milliseconds );
|
|
|
|
return( len );
|
|
}
|
|
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* _FormatThreadId
|
|
*
|
|
* format thread id into buffer
|
|
*
|
|
* ENTRY:
|
|
* pBuffer (output)
|
|
* pointer to buffer
|
|
* Length (input)
|
|
* length of buffer
|
|
*
|
|
* EXIT:
|
|
* length of formated time
|
|
*
|
|
******************************************************************************/
|
|
|
|
#define TEB_CLIENTID_OFFSET 0x1e0
|
|
|
|
int
|
|
_FormatThreadId( CHAR * pBuffer, ULONG Length )
|
|
{
|
|
PCLIENT_ID pClientId;
|
|
char Number[40]; //on WIN64, %p is 16 chars, we need two of these. So 32 + 2 bytes for "." and "\0". Use 40 just in case
|
|
int len;
|
|
|
|
/*
|
|
* Get pointer to clientid structure in teb
|
|
* - use hardcoded teb offset
|
|
*/
|
|
pClientId = (PCLIENT_ID) ((char*)PsGetCurrentThread() + TEB_CLIENTID_OFFSET);
|
|
|
|
/*
|
|
* Format buffer
|
|
*/
|
|
_snprintf( Number, sizeof(Number), "%p.%p",
|
|
pClientId->UniqueProcess, pClientId->UniqueThread );
|
|
|
|
Number[39] = '\0';
|
|
|
|
len = _snprintf( pBuffer, Length, "%-7s ", Number );
|
|
|
|
return( len );
|
|
}
|
|
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* _WriteHexData
|
|
*
|
|
* format and write hex data
|
|
*
|
|
* ENTRY:
|
|
* pTraceInfo (input)
|
|
* pointer to ICA_TRACE_INFO struct
|
|
* pBuffer (output)
|
|
* pointer to buffer
|
|
* Length (input)
|
|
* length of buffer
|
|
*
|
|
* EXIT:
|
|
* length of formated time
|
|
*
|
|
******************************************************************************/
|
|
|
|
VOID
|
|
_WriteHexData(
|
|
IN PICA_TRACE_INFO pTraceInfo,
|
|
IN PVOID pBuffer,
|
|
IN ULONG ByteCount
|
|
)
|
|
{
|
|
PUCHAR pData;
|
|
ULONG i;
|
|
ULONG j;
|
|
char Buffer[256];
|
|
|
|
/*
|
|
* Output data
|
|
*/
|
|
pData = (PUCHAR) pBuffer;
|
|
for ( i=0; i < ByteCount; i += 16 ) {
|
|
ULONG c = 0;
|
|
for ( j=0; j < 16 && (i+j) < ByteCount; j++ )
|
|
c += _snprintf( &Buffer[c], sizeof(Buffer)-c, "%02X ", pData[j] );
|
|
for ( ; j < 16; j++ ) {
|
|
Buffer[c++] = ' ';
|
|
Buffer[c++] = ' ';
|
|
Buffer[c++] = ' ';
|
|
}
|
|
Buffer[c++] = ' ';
|
|
Buffer[c++] = ' ';
|
|
for ( j=0; j < 16 && (i+j) < ByteCount; j++, pData++ ) {
|
|
if ( *pData < 0x20 || *pData > 0x7f )
|
|
Buffer[c++] = '.';
|
|
else
|
|
Buffer[c++] = *pData;
|
|
}
|
|
Buffer[c++] = '\n';
|
|
Buffer[c++] = '\0';
|
|
_IcaTraceWrite( pTraceInfo, Buffer );
|
|
}
|
|
}
|
|
|
|
|