mirror of https://github.com/tongzx/nt5src
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.
505 lines
13 KiB
505 lines
13 KiB
/*
|
|
§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§
|
|
|
|
(C) Copyright 1998
|
|
All rights reserved.
|
|
|
|
§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§
|
|
|
|
Portions of this software are:
|
|
|
|
(C) Copyright 1994 TriplePoint, Inc. -- http://www.TriplePoint.com
|
|
License to use this software is granted under the same terms
|
|
outlined in the Microsoft Windows Device Driver Development Kit.
|
|
|
|
(C) Copyright 1992 Microsoft Corp. -- http://www.Microsoft.com
|
|
License to use this software is granted under the terms outlined in
|
|
the Microsoft Windows Device Driver Development Kit.
|
|
|
|
§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§
|
|
|
|
@doc INTERNAL TpiDebug TpiDebug_c
|
|
|
|
@module TpiDebug.c |
|
|
|
|
This module, along with <f TpiDebug\.h>, implements code and macros to
|
|
support NDIS driver debugging. This file must be linked with the driver
|
|
to support debug dumps and logging.
|
|
|
|
@comm
|
|
|
|
The code and macros defined by these modules is only generated during
|
|
development debugging when the C pre-processor macro flag (DBG == 1).
|
|
If (DBG == 0) no code will be generated, and all debug strings will be
|
|
removed from the image.
|
|
|
|
This is a device independent module which can be re-used, without
|
|
change, by any driver or application.
|
|
|
|
@head3 Contents |
|
|
@index class,mfunc,func,msg,mdata,struct,enum | TpiDebug_c
|
|
|
|
@end
|
|
§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§
|
|
*/
|
|
|
|
#if defined(_EXE_) || defined(_DLL_)
|
|
typedef char CHAR, *PCHAR;
|
|
typedef unsigned char UCHAR, *PUCHAR;
|
|
typedef unsigned short USHORT, *PUSHORT;
|
|
typedef unsigned long ULONG, *PULONG;
|
|
typedef unsigned int *PUINT;
|
|
|
|
# include <windows.h>
|
|
#elif defined(_VXD_)
|
|
# include <basedef.h>
|
|
# include <vmm.h>
|
|
# pragma VxD_LOCKED_CODE_SEG
|
|
# pragma VxD_LOCKED_DATA_SEG
|
|
#else
|
|
# include <windef.h>
|
|
#endif
|
|
|
|
#include "TpiDebug.h"
|
|
|
|
#if DBG
|
|
|
|
/*
|
|
// Sometimes the debug output seriously impacts the run-time performance,
|
|
// so it is necessary to turn off the debug output. In this case, you can
|
|
// capture some debug trace information into the DbgLogBuffer, and it can
|
|
// be examined later without impacting the run-time performance.
|
|
*/
|
|
#define DBG_LOG_ENTRIES 100 // Maximum number of FIFO log entries.
|
|
#define DBG_LOG_SIZE 128 // Maximum number of bytes per entry.
|
|
|
|
#if defined(_VXD_)
|
|
DBG_SETTINGS DbgSettings = { DBG_DEFAULTS, {'V','X','D',0 } };
|
|
#elif defined(_EXE_)
|
|
DBG_SETTINGS DbgSettings = { DBG_DEFAULTS, {'E','X','E',0 } };
|
|
#elif defined(_DLL_)
|
|
DBG_SETTINGS DbgSettings = { DBG_DEFAULTS, {'D','L','L',0 } };
|
|
#elif defined(_SYS_)
|
|
DBG_SETTINGS DbgSettings = { DBG_DEFAULTS, {'S','Y','S',0 } };
|
|
#else
|
|
DBG_SETTINGS DbgSettings = { DBG_DEFAULTS, {'T','P','I',0 } };
|
|
#endif
|
|
|
|
PDBG_SETTINGS DbgInfo = &DbgSettings;
|
|
UINT DbgLogIndex = 0;
|
|
UCHAR DbgLogBuffer[DBG_LOG_ENTRIES][DBG_LOG_SIZE] = { { 0 } };
|
|
|
|
|
|
/* @doc INTERNAL TpiDebug TpiDebug_c DbgPrintData
|
|
§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§
|
|
|
|
@func
|
|
|
|
<f DbgPrintData> outputs data to the debug display formatted in HEX and
|
|
ASCII for easy viewing.
|
|
|
|
<f Note>: This routine is used for debug output only.
|
|
It is not compiled into the retail version.
|
|
|
|
@ex <tab> |
|
|
DbgPrintData(ReceiveBuffer, 14, 0); // Packet header
|
|
DbgPrintData(ReceiveBuffer+14, BytesReceived-14, 14); // Packet data
|
|
|
|
0000: ff ff ff ff ff ff 0a 22 23 01 02 03 00 10 ......."#.....
|
|
000E: 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 40 ABCDEFGHIJKMNOPQ
|
|
|
|
*/
|
|
|
|
VOID DbgPrintData(
|
|
IN PUCHAR Data, // @parm
|
|
// Pointer to first byte of data to be displayed.
|
|
|
|
IN UINT NumBytes, // @parm
|
|
// Number of bytes to be displayed.
|
|
|
|
IN ULONG Offset // @parm
|
|
// Value to be added to the offset counter displayed at the start of each
|
|
// line. This is useful for viewing data whose base offset is relative to
|
|
// another, non-zero starting address.
|
|
|
|
)
|
|
{
|
|
UINT LineStart;
|
|
UINT LineIndex;
|
|
|
|
/*
|
|
// Display the caller's buffer with up to 16 bytes per line.
|
|
*/
|
|
for (LineStart = 0; LineStart < NumBytes; LineStart += 16)
|
|
{
|
|
/*
|
|
// Display the starting offset of the line.
|
|
*/
|
|
DbgPrint("%04lx: ", LineStart + Offset);
|
|
|
|
/*
|
|
// Display a line of HEX byte values.
|
|
*/
|
|
for (LineIndex = LineStart; LineIndex < (LineStart+16); LineIndex++)
|
|
{
|
|
if (LineIndex < NumBytes)
|
|
{
|
|
DbgPrint("%02x ",(UINT)((UCHAR)*(Data+LineIndex)));
|
|
}
|
|
else
|
|
{
|
|
DbgPrint(" ");
|
|
}
|
|
}
|
|
DbgPrint(" "); // A little white space between HEX and ASCII.
|
|
|
|
/*
|
|
// Display the corresponding ASCII byte values if they are printable.
|
|
// (i.e. 0x20 <= N <= 0x7F).
|
|
*/
|
|
for (LineIndex = LineStart; LineIndex < (LineStart+16); LineIndex++)
|
|
{
|
|
if (LineIndex < NumBytes)
|
|
{
|
|
char c = *(Data+LineIndex);
|
|
|
|
if (c < ' ' || c > 'z')
|
|
{
|
|
c = '.';
|
|
}
|
|
DbgPrint("%c", (UINT)c);
|
|
}
|
|
else
|
|
{
|
|
DbgPrint(" ");
|
|
}
|
|
}
|
|
DbgPrint("\n"); // End of line.
|
|
}
|
|
}
|
|
|
|
|
|
/* @doc INTERNAL TpiDebug TpiDebug_c DbgQueueData
|
|
§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§
|
|
|
|
@func
|
|
|
|
<f DbgQueueData> saves data to the DbgLogBuffer so it can be viewed later
|
|
with the debugger.
|
|
|
|
<f Note>: This routine is used for debug output only.
|
|
It is not compiled into the retail version.
|
|
|
|
*/
|
|
|
|
VOID DbgQueueData(
|
|
IN PUCHAR Data, // @parm
|
|
// Pointer to first byte of data to be displayed.
|
|
|
|
IN UINT NumBytes, // @parm
|
|
// Number of bytes to be displayed.
|
|
|
|
IN UINT Flags // @parm
|
|
// A flag descriptor to help identify the log entry.
|
|
)
|
|
{
|
|
/*
|
|
// Point to the next available entry in the DbgLogBuffer.
|
|
*/
|
|
PUCHAR LogEntry = &DbgLogBuffer[DbgLogIndex++][0];
|
|
|
|
/*
|
|
// Wrap around on the next entry if needed.
|
|
*/
|
|
if (DbgLogIndex >= DBG_LOG_ENTRIES)
|
|
{
|
|
DbgLogIndex = 0;
|
|
}
|
|
|
|
/*
|
|
// Save the flags parameter in the first WORD of the log buffer.
|
|
*/
|
|
*((PUSHORT) LogEntry) = (USHORT) Flags;
|
|
LogEntry += sizeof(PUSHORT);
|
|
|
|
/*
|
|
// Save the NumBytes parameter in the second WORD of the log buffer.
|
|
*/
|
|
*((PUSHORT) LogEntry) = (USHORT) NumBytes;
|
|
LogEntry += sizeof(NumBytes);
|
|
|
|
/*
|
|
// Don't try to save more than we have room for.
|
|
*/
|
|
if (NumBytes > DBG_LOG_SIZE - sizeof(USHORT) * 2)
|
|
{
|
|
NumBytes = DBG_LOG_SIZE - sizeof(USHORT) * 2;
|
|
}
|
|
|
|
/*
|
|
// Save the rest of the data in the remaining portion of the log buffer.
|
|
*/
|
|
while (NumBytes--)
|
|
{
|
|
*LogEntry++ = *Data++;
|
|
}
|
|
}
|
|
|
|
|
|
/* @doc INTERNAL TpiDebug TpiDebug_c DbgBreakPoint
|
|
§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§
|
|
|
|
@func VOID | DbgBreakPoint |
|
|
|
|
<f DbgBreakPoint> is defined in the NT kernel for SYS drivers, but we
|
|
override it here so we can support for SYS's, EXE's, VXD's, and DLL's.
|
|
|
|
*/
|
|
#if defined(_MSC_VER) && (_MSC_VER <= 800)
|
|
// Must be building with 16-bit compiler
|
|
VOID __cdecl DbgBreakPoint(VOID)
|
|
#else
|
|
// Must be building with 32-bit compiler
|
|
VOID __stdcall DbgBreakPoint(VOID)
|
|
#endif
|
|
{
|
|
#if !defined(_WIN64)
|
|
__asm int 3;
|
|
#endif
|
|
}
|
|
|
|
|
|
/* @doc INTERNAL TpiDebug TpiDebug_c DbgPrint
|
|
§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§
|
|
|
|
@func ULONG __cdecl | DbgPrint |
|
|
|
|
<f DbgPrint> is defined in the kernel for SYS drivers, otherwise it is
|
|
supported here for EXE's, VXD's, and DLL's.
|
|
|
|
@parm PCHAR | Format |
|
|
printf style format string.
|
|
|
|
@parm OPTIONAL | Params |
|
|
Zero or more optional parameters as needed by the format string.
|
|
|
|
*/
|
|
|
|
#if defined(_VXD_)
|
|
|
|
#if !defined(NDIS_DOS)
|
|
ULONG __cdecl DbgPrint(PCHAR Format, ...)
|
|
{
|
|
ULONG result = 0;
|
|
|
|
__asm lea eax, (Format + 4)
|
|
__asm push eax
|
|
__asm push Format
|
|
VMMCall(_Debug_Printf_Service)
|
|
__asm add esp, 4*2
|
|
__asm mov result, eax
|
|
|
|
return (result);
|
|
}
|
|
#endif
|
|
|
|
#elif defined(_EXE_) || defined(_DLL_)
|
|
|
|
UCHAR DbgString[1024];
|
|
|
|
ULONG __cdecl DbgPrint(PCHAR Format, ...)
|
|
{
|
|
ULONG result;
|
|
|
|
result = wvsprintf(DbgString, Format, ((PCHAR) &Format) + sizeof(PCHAR));
|
|
|
|
OutputDebugString(DbgString);
|
|
|
|
if (result >= sizeof(DbgString))
|
|
{
|
|
// We just blew the stack!
|
|
// Since we can't return, we have to generate a stack-fault interrupt
|
|
__asm int 1;
|
|
__asm int 3;
|
|
__asm int 12;
|
|
}
|
|
return (result);
|
|
}
|
|
#endif // DbgPrint
|
|
|
|
/*
|
|
* If DBG_SILENT is set, all TERSE debug goes here. An assertion
|
|
* will dump the block.
|
|
*/
|
|
#define DBG_QUEUE_LEN 4096
|
|
UINT DbgIndex=0;
|
|
UINT DbgLen=0;
|
|
UCHAR DbgQueue[DBG_QUEUE_LEN] = {0};
|
|
UCHAR DbgLock=0;
|
|
|
|
|
|
/* @doc INTERNAL TpiDebug TpiDebug_c DbgDumpSilentQueue
|
|
§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§
|
|
|
|
@func
|
|
|
|
<f DbgDumpSilentQueue> dumps the contents of the silent debug queue to
|
|
the monitor.
|
|
|
|
*/
|
|
|
|
void DbgDumpSilentQueue(
|
|
void
|
|
)
|
|
{
|
|
if (DbgLen >= DBG_QUEUE_LEN)
|
|
{
|
|
DbgPrintData(
|
|
&DbgQueue[DbgIndex],
|
|
DBG_QUEUE_LEN-DbgIndex,
|
|
0);
|
|
if (DbgIndex)
|
|
{
|
|
DbgPrint("\n");
|
|
DbgPrintData(
|
|
DbgQueue,
|
|
DbgIndex-1,
|
|
0);
|
|
}
|
|
DbgPrint("\n");
|
|
}
|
|
else if (DbgLen)
|
|
{
|
|
DbgPrintData(
|
|
DbgQueue,
|
|
DbgIndex-1,
|
|
0);
|
|
DbgPrint("\n");
|
|
}
|
|
}
|
|
|
|
#if NDIS_NT
|
|
|
|
/* @doc INTERNAL TpiDebug TpiDebug_c _assert
|
|
§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§
|
|
|
|
@func
|
|
|
|
<f _assert> overrides the assertion function provided by the operating
|
|
system. Dumps the contents of debug queue, prints the assertion, and
|
|
then traps to the debugger. Used for debugging only.
|
|
|
|
*/
|
|
|
|
void _CRTAPI1 _assert(
|
|
void * exp, // @parm
|
|
// ASCIIZ pointer to the expression causing the fault.
|
|
|
|
void * file, // @parm
|
|
// ASCIIZ pointer to the name of the file.
|
|
|
|
unsigned line // @parm
|
|
// Line offset within the file where the assertion is defined.
|
|
)
|
|
{
|
|
DbgDumpSilentQueue();
|
|
DbgPrint("Assertion Failed: %s at %s:%d\n",exp,file,line);
|
|
DbgBreakPoint();
|
|
}
|
|
#endif
|
|
|
|
|
|
/* @doc INTERNAL TpiDebug TpiDebug_c DbgSilentQueue
|
|
§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§
|
|
|
|
@func
|
|
|
|
<f DbgSilentQueue> logs a string to the debug queue which can be
|
|
displayed later using <f DbgDumpSilentQueue>. Used for debugging only.
|
|
|
|
*/
|
|
|
|
void DbgSilentQueue(
|
|
PUCHAR str // @parm
|
|
// Pointer to string to be placed in DbgQueue.
|
|
)
|
|
{
|
|
/*
|
|
// If the debug queue is busy, just
|
|
// bail out.
|
|
*/
|
|
if ((++DbgLock) > 1)
|
|
{
|
|
goto exit;
|
|
}
|
|
|
|
while (str && *str)
|
|
{
|
|
DbgQueue[DbgIndex] = *str++;
|
|
DbgLen++;
|
|
if ((++DbgIndex) >= DBG_QUEUE_LEN)
|
|
{
|
|
DbgIndex = 0;
|
|
}
|
|
}
|
|
exit:
|
|
DbgLock--;
|
|
}
|
|
|
|
|
|
/* @doc INTERNAL TpiDebug TpiDebug_c DbgPrintFieldTable
|
|
§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§
|
|
|
|
@func
|
|
|
|
<f DbgPrintFieldTable> displays the contents of a C data structure in
|
|
a formatted output to the debugger. This can be used when symbolic
|
|
debugging is not available on the target platform.
|
|
|
|
*/
|
|
|
|
void DbgPrintFieldTable(
|
|
IN PDBG_FIELD_TABLE pFields, // @parm
|
|
// A pointer to an array of field records <t DBG_FIELD_TABLE>.
|
|
|
|
IN PUCHAR pBaseContext, // @parm
|
|
// References the base of the structure where the values will be displayed
|
|
// from. This should be a pointer to the first byte of the structure.
|
|
|
|
IN PUCHAR pBaseName // @parm
|
|
// Pointer to C string containing the name of the structure being displayed.
|
|
)
|
|
{
|
|
DbgPrint("STRUCTURE: @0x%08X %s\n", pBaseContext, pBaseName);
|
|
|
|
while (pFields->FieldName)
|
|
{
|
|
switch (pFields->FieldType)
|
|
{
|
|
case sizeof(ULONG):
|
|
DbgPrint("\t%04X: %-32s=0x%08X\n", pFields->FieldOffset,
|
|
pFields->FieldName,
|
|
*(PULONG)(pBaseContext+pFields->FieldOffset));
|
|
break;
|
|
|
|
case sizeof(USHORT):
|
|
DbgPrint("\t%04X: %-32s=0x%04X\n", pFields->FieldOffset,
|
|
pFields->FieldName,
|
|
*(PUSHORT)(pBaseContext+pFields->FieldOffset));
|
|
break;
|
|
|
|
case sizeof(UCHAR):
|
|
DbgPrint("\t%04X: %-32s=0x%02X\n", pFields->FieldOffset,
|
|
pFields->FieldName,
|
|
*(PUCHAR)(pBaseContext+pFields->FieldOffset));
|
|
break;
|
|
|
|
default:
|
|
ASSERT(0);
|
|
break;
|
|
}
|
|
pFields++;
|
|
}
|
|
}
|
|
|
|
#endif // DBG
|