/* §§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§ (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 , 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 #elif defined(_VXD_) # include # include # pragma VxD_LOCKED_CODE_SEG # pragma VxD_LOCKED_DATA_SEG #else # include #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 outputs data to the debug display formatted in HEX and ASCII for easy viewing. : This routine is used for debug output only. It is not compiled into the retail version. @ex | 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 saves data to the DbgLogBuffer so it can be viewed later with the debugger. : 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 | 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 | 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 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 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 logs a string to the debug queue which can be displayed later using . 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 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 . 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