Source code of Windows XP (NT5)
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

  1. /*
  2. (C) Copyright 1998
  3. All rights reserved.
  4. Portions of this software are:
  5. (C) Copyright 1994 TriplePoint, Inc. -- http://www.TriplePoint.com
  6. License to use this software is granted under the same terms
  7. outlined in the Microsoft Windows Device Driver Development Kit.
  8. (C) Copyright 1992 Microsoft Corp. -- http://www.Microsoft.com
  9. License to use this software is granted under the terms outlined in
  10. the Microsoft Windows Device Driver Development Kit.
  11. @doc INTERNAL TpiDebug TpiDebug_c
  12. @module TpiDebug.c |
  13. This module, along with <f TpiDebug\.h>, implements code and macros to
  14. support NDIS driver debugging. This file must be linked with the driver
  15. to support debug dumps and logging.
  16. @comm
  17. The code and macros defined by these modules is only generated during
  18. development debugging when the C pre-processor macro flag (DBG == 1).
  19. If (DBG == 0) no code will be generated, and all debug strings will be
  20. removed from the image.
  21. This is a device independent module which can be re-used, without
  22. change, by any driver or application.
  23. @head3 Contents |
  24. @index class,mfunc,func,msg,mdata,struct,enum | TpiDebug_c
  25. @end
  26. */
  27. #if defined(_EXE_) || defined(_DLL_)
  28. typedef char CHAR, *PCHAR;
  29. typedef unsigned char UCHAR, *PUCHAR;
  30. typedef unsigned short USHORT, *PUSHORT;
  31. typedef unsigned long ULONG, *PULONG;
  32. typedef unsigned int *PUINT;
  33. # include <windows.h>
  34. #elif defined(_VXD_)
  35. # include <basedef.h>
  36. # include <vmm.h>
  37. # pragma VxD_LOCKED_CODE_SEG
  38. # pragma VxD_LOCKED_DATA_SEG
  39. #else
  40. # include <windef.h>
  41. #endif
  42. #include "TpiDebug.h"
  43. #if DBG
  44. /*
  45. // Sometimes the debug output seriously impacts the run-time performance,
  46. // so it is necessary to turn off the debug output. In this case, you can
  47. // capture some debug trace information into the DbgLogBuffer, and it can
  48. // be examined later without impacting the run-time performance.
  49. */
  50. #define DBG_LOG_ENTRIES 100 // Maximum number of FIFO log entries.
  51. #define DBG_LOG_SIZE 128 // Maximum number of bytes per entry.
  52. #if defined(_VXD_)
  53. DBG_SETTINGS DbgSettings = { DBG_DEFAULTS, {'V','X','D',0 } };
  54. #elif defined(_EXE_)
  55. DBG_SETTINGS DbgSettings = { DBG_DEFAULTS, {'E','X','E',0 } };
  56. #elif defined(_DLL_)
  57. DBG_SETTINGS DbgSettings = { DBG_DEFAULTS, {'D','L','L',0 } };
  58. #elif defined(_SYS_)
  59. DBG_SETTINGS DbgSettings = { DBG_DEFAULTS, {'S','Y','S',0 } };
  60. #else
  61. DBG_SETTINGS DbgSettings = { DBG_DEFAULTS, {'T','P','I',0 } };
  62. #endif
  63. PDBG_SETTINGS DbgInfo = &DbgSettings;
  64. UINT DbgLogIndex = 0;
  65. UCHAR DbgLogBuffer[DBG_LOG_ENTRIES][DBG_LOG_SIZE] = { { 0 } };
  66. /* @doc INTERNAL TpiDebug TpiDebug_c DbgPrintData
  67. @func
  68. <f DbgPrintData> outputs data to the debug display formatted in HEX and
  69. ASCII for easy viewing.
  70. <f Note>: This routine is used for debug output only.
  71. It is not compiled into the retail version.
  72. @ex <tab> |
  73. DbgPrintData(ReceiveBuffer, 14, 0); // Packet header
  74. DbgPrintData(ReceiveBuffer+14, BytesReceived-14, 14); // Packet data
  75. 0000: ff ff ff ff ff ff 0a 22 23 01 02 03 00 10 ......."#.....
  76. 000E: 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 40 ABCDEFGHIJKMNOPQ
  77. */
  78. VOID DbgPrintData(
  79. IN PUCHAR Data, // @parm
  80. // Pointer to first byte of data to be displayed.
  81. IN UINT NumBytes, // @parm
  82. // Number of bytes to be displayed.
  83. IN ULONG Offset // @parm
  84. // Value to be added to the offset counter displayed at the start of each
  85. // line. This is useful for viewing data whose base offset is relative to
  86. // another, non-zero starting address.
  87. )
  88. {
  89. UINT LineStart;
  90. UINT LineIndex;
  91. /*
  92. // Display the caller's buffer with up to 16 bytes per line.
  93. */
  94. for (LineStart = 0; LineStart < NumBytes; LineStart += 16)
  95. {
  96. /*
  97. // Display the starting offset of the line.
  98. */
  99. DbgPrint("%04lx: ", LineStart + Offset);
  100. /*
  101. // Display a line of HEX byte values.
  102. */
  103. for (LineIndex = LineStart; LineIndex < (LineStart+16); LineIndex++)
  104. {
  105. if (LineIndex < NumBytes)
  106. {
  107. DbgPrint("%02x ",(UINT)((UCHAR)*(Data+LineIndex)));
  108. }
  109. else
  110. {
  111. DbgPrint(" ");
  112. }
  113. }
  114. DbgPrint(" "); // A little white space between HEX and ASCII.
  115. /*
  116. // Display the corresponding ASCII byte values if they are printable.
  117. // (i.e. 0x20 <= N <= 0x7F).
  118. */
  119. for (LineIndex = LineStart; LineIndex < (LineStart+16); LineIndex++)
  120. {
  121. if (LineIndex < NumBytes)
  122. {
  123. char c = *(Data+LineIndex);
  124. if (c < ' ' || c > 'z')
  125. {
  126. c = '.';
  127. }
  128. DbgPrint("%c", (UINT)c);
  129. }
  130. else
  131. {
  132. DbgPrint(" ");
  133. }
  134. }
  135. DbgPrint("\n"); // End of line.
  136. }
  137. }
  138. /* @doc INTERNAL TpiDebug TpiDebug_c DbgQueueData
  139. @func
  140. <f DbgQueueData> saves data to the DbgLogBuffer so it can be viewed later
  141. with the debugger.
  142. <f Note>: This routine is used for debug output only.
  143. It is not compiled into the retail version.
  144. */
  145. VOID DbgQueueData(
  146. IN PUCHAR Data, // @parm
  147. // Pointer to first byte of data to be displayed.
  148. IN UINT NumBytes, // @parm
  149. // Number of bytes to be displayed.
  150. IN UINT Flags // @parm
  151. // A flag descriptor to help identify the log entry.
  152. )
  153. {
  154. /*
  155. // Point to the next available entry in the DbgLogBuffer.
  156. */
  157. PUCHAR LogEntry = &DbgLogBuffer[DbgLogIndex++][0];
  158. /*
  159. // Wrap around on the next entry if needed.
  160. */
  161. if (DbgLogIndex >= DBG_LOG_ENTRIES)
  162. {
  163. DbgLogIndex = 0;
  164. }
  165. /*
  166. // Save the flags parameter in the first WORD of the log buffer.
  167. */
  168. *((PUSHORT) LogEntry) = (USHORT) Flags;
  169. LogEntry += sizeof(PUSHORT);
  170. /*
  171. // Save the NumBytes parameter in the second WORD of the log buffer.
  172. */
  173. *((PUSHORT) LogEntry) = (USHORT) NumBytes;
  174. LogEntry += sizeof(NumBytes);
  175. /*
  176. // Don't try to save more than we have room for.
  177. */
  178. if (NumBytes > DBG_LOG_SIZE - sizeof(USHORT) * 2)
  179. {
  180. NumBytes = DBG_LOG_SIZE - sizeof(USHORT) * 2;
  181. }
  182. /*
  183. // Save the rest of the data in the remaining portion of the log buffer.
  184. */
  185. while (NumBytes--)
  186. {
  187. *LogEntry++ = *Data++;
  188. }
  189. }
  190. /* @doc INTERNAL TpiDebug TpiDebug_c DbgBreakPoint
  191. @func VOID | DbgBreakPoint |
  192. <f DbgBreakPoint> is defined in the NT kernel for SYS drivers, but we
  193. override it here so we can support for SYS's, EXE's, VXD's, and DLL's.
  194. */
  195. #if defined(_MSC_VER) && (_MSC_VER <= 800)
  196. // Must be building with 16-bit compiler
  197. VOID __cdecl DbgBreakPoint(VOID)
  198. #else
  199. // Must be building with 32-bit compiler
  200. VOID __stdcall DbgBreakPoint(VOID)
  201. #endif
  202. {
  203. #if !defined(_WIN64)
  204. __asm int 3;
  205. #endif
  206. }
  207. /* @doc INTERNAL TpiDebug TpiDebug_c DbgPrint
  208. @func ULONG __cdecl | DbgPrint |
  209. <f DbgPrint> is defined in the kernel for SYS drivers, otherwise it is
  210. supported here for EXE's, VXD's, and DLL's.
  211. @parm PCHAR | Format |
  212. printf style format string.
  213. @parm OPTIONAL | Params |
  214. Zero or more optional parameters as needed by the format string.
  215. */
  216. #if defined(_VXD_)
  217. #if !defined(NDIS_DOS)
  218. ULONG __cdecl DbgPrint(PCHAR Format, ...)
  219. {
  220. ULONG result = 0;
  221. __asm lea eax, (Format + 4)
  222. __asm push eax
  223. __asm push Format
  224. VMMCall(_Debug_Printf_Service)
  225. __asm add esp, 4*2
  226. __asm mov result, eax
  227. return (result);
  228. }
  229. #endif
  230. #elif defined(_EXE_) || defined(_DLL_)
  231. UCHAR DbgString[1024];
  232. ULONG __cdecl DbgPrint(PCHAR Format, ...)
  233. {
  234. ULONG result;
  235. result = wvsprintf(DbgString, Format, ((PCHAR) &Format) + sizeof(PCHAR));
  236. OutputDebugString(DbgString);
  237. if (result >= sizeof(DbgString))
  238. {
  239. // We just blew the stack!
  240. // Since we can't return, we have to generate a stack-fault interrupt
  241. __asm int 1;
  242. __asm int 3;
  243. __asm int 12;
  244. }
  245. return (result);
  246. }
  247. #endif // DbgPrint
  248. /*
  249. * If DBG_SILENT is set, all TERSE debug goes here. An assertion
  250. * will dump the block.
  251. */
  252. #define DBG_QUEUE_LEN 4096
  253. UINT DbgIndex=0;
  254. UINT DbgLen=0;
  255. UCHAR DbgQueue[DBG_QUEUE_LEN] = {0};
  256. UCHAR DbgLock=0;
  257. /* @doc INTERNAL TpiDebug TpiDebug_c DbgDumpSilentQueue
  258. @func
  259. <f DbgDumpSilentQueue> dumps the contents of the silent debug queue to
  260. the monitor.
  261. */
  262. void DbgDumpSilentQueue(
  263. void
  264. )
  265. {
  266. if (DbgLen >= DBG_QUEUE_LEN)
  267. {
  268. DbgPrintData(
  269. &DbgQueue[DbgIndex],
  270. DBG_QUEUE_LEN-DbgIndex,
  271. 0);
  272. if (DbgIndex)
  273. {
  274. DbgPrint("\n");
  275. DbgPrintData(
  276. DbgQueue,
  277. DbgIndex-1,
  278. 0);
  279. }
  280. DbgPrint("\n");
  281. }
  282. else if (DbgLen)
  283. {
  284. DbgPrintData(
  285. DbgQueue,
  286. DbgIndex-1,
  287. 0);
  288. DbgPrint("\n");
  289. }
  290. }
  291. #if NDIS_NT
  292. /* @doc INTERNAL TpiDebug TpiDebug_c _assert
  293. @func
  294. <f _assert> overrides the assertion function provided by the operating
  295. system. Dumps the contents of debug queue, prints the assertion, and
  296. then traps to the debugger. Used for debugging only.
  297. */
  298. void _CRTAPI1 _assert(
  299. void * exp, // @parm
  300. // ASCIIZ pointer to the expression causing the fault.
  301. void * file, // @parm
  302. // ASCIIZ pointer to the name of the file.
  303. unsigned line // @parm
  304. // Line offset within the file where the assertion is defined.
  305. )
  306. {
  307. DbgDumpSilentQueue();
  308. DbgPrint("Assertion Failed: %s at %s:%d\n",exp,file,line);
  309. DbgBreakPoint();
  310. }
  311. #endif
  312. /* @doc INTERNAL TpiDebug TpiDebug_c DbgSilentQueue
  313. @func
  314. <f DbgSilentQueue> logs a string to the debug queue which can be
  315. displayed later using <f DbgDumpSilentQueue>. Used for debugging only.
  316. */
  317. void DbgSilentQueue(
  318. PUCHAR str // @parm
  319. // Pointer to string to be placed in DbgQueue.
  320. )
  321. {
  322. /*
  323. // If the debug queue is busy, just
  324. // bail out.
  325. */
  326. if ((++DbgLock) > 1)
  327. {
  328. goto exit;
  329. }
  330. while (str && *str)
  331. {
  332. DbgQueue[DbgIndex] = *str++;
  333. DbgLen++;
  334. if ((++DbgIndex) >= DBG_QUEUE_LEN)
  335. {
  336. DbgIndex = 0;
  337. }
  338. }
  339. exit:
  340. DbgLock--;
  341. }
  342. /* @doc INTERNAL TpiDebug TpiDebug_c DbgPrintFieldTable
  343. @func
  344. <f DbgPrintFieldTable> displays the contents of a C data structure in
  345. a formatted output to the debugger. This can be used when symbolic
  346. debugging is not available on the target platform.
  347. */
  348. void DbgPrintFieldTable(
  349. IN PDBG_FIELD_TABLE pFields, // @parm
  350. // A pointer to an array of field records <t DBG_FIELD_TABLE>.
  351. IN PUCHAR pBaseContext, // @parm
  352. // References the base of the structure where the values will be displayed
  353. // from. This should be a pointer to the first byte of the structure.
  354. IN PUCHAR pBaseName // @parm
  355. // Pointer to C string containing the name of the structure being displayed.
  356. )
  357. {
  358. DbgPrint("STRUCTURE: @0x%08X %s\n", pBaseContext, pBaseName);
  359. while (pFields->FieldName)
  360. {
  361. switch (pFields->FieldType)
  362. {
  363. case sizeof(ULONG):
  364. DbgPrint("\t%04X: %-32s=0x%08X\n", pFields->FieldOffset,
  365. pFields->FieldName,
  366. *(PULONG)(pBaseContext+pFields->FieldOffset));
  367. break;
  368. case sizeof(USHORT):
  369. DbgPrint("\t%04X: %-32s=0x%04X\n", pFields->FieldOffset,
  370. pFields->FieldName,
  371. *(PUSHORT)(pBaseContext+pFields->FieldOffset));
  372. break;
  373. case sizeof(UCHAR):
  374. DbgPrint("\t%04X: %-32s=0x%02X\n", pFields->FieldOffset,
  375. pFields->FieldName,
  376. *(PUCHAR)(pBaseContext+pFields->FieldOffset));
  377. break;
  378. default:
  379. ASSERT(0);
  380. break;
  381. }
  382. pFields++;
  383. }
  384. }
  385. #endif // DBG