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.

552 lines
11 KiB

  1. /*++
  2. Copyright (c) 1998 Microsoft Corporation
  3. Module Name:
  4. DBG.C
  5. Abstract:
  6. This module contains debug only code for DBCLASS driver
  7. Author:
  8. jdunn
  9. Environment:
  10. kernel mode only
  11. Notes:
  12. Revision History:
  13. 11-5-96 : created
  14. --*/
  15. #include <wdm.h>
  16. #include "stdarg.h"
  17. #include "stdio.h"
  18. #include "dbci.h"
  19. #include "dbclass.h"
  20. #include "dbfilter.h"
  21. #ifdef MAX_DEBUG
  22. #define DEBUG_HEAP
  23. #endif
  24. typedef struct _HEAP_TAG_BUFFER {
  25. ULONG Sig;
  26. ULONG Length;
  27. } HEAP_TAG_BUFFER, *PHEAP_TAG_BUFFER;
  28. #if DBG
  29. extern ULONG DBCLASS_Debug_Trace_Level;
  30. #ifdef NTKERN_TRACE
  31. ULONG DBCLASS_W98_Debug_Trace = 1;
  32. #else
  33. ULONG DBCLASS_W98_Debug_Trace = 0;
  34. #endif
  35. NTSTATUS
  36. DBCLASS_GetClassGlobalDebugRegistryParameters(
  37. )
  38. /*++
  39. Routine Description:
  40. Arguments:
  41. Return Value:
  42. --*/
  43. {
  44. NTSTATUS ntStatus;
  45. RTL_QUERY_REGISTRY_TABLE QueryTable[4];
  46. PWCHAR usb = L"class\\dbc";
  47. PAGED_CODE();
  48. //
  49. // Set up QueryTable to do the following:
  50. //
  51. // spew level
  52. QueryTable[0].QueryRoutine = DBCLASS_GetConfigValue;
  53. QueryTable[0].Flags = 0;
  54. QueryTable[0].Name = DEBUG_LEVEL_KEY;
  55. QueryTable[0].EntryContext = &DBCLASS_Debug_Trace_Level;
  56. QueryTable[0].DefaultType = REG_DWORD;
  57. QueryTable[0].DefaultData = &DBCLASS_Debug_Trace_Level;
  58. QueryTable[0].DefaultLength = sizeof(DBCLASS_Debug_Trace_Level);
  59. // ntkern trace buffer
  60. QueryTable[1].QueryRoutine = DBCLASS_GetConfigValue;
  61. QueryTable[1].Flags = 0;
  62. QueryTable[1].Name = DEBUG_WIN9X_KEY;
  63. QueryTable[1].EntryContext = &DBCLASS_W98_Debug_Trace;
  64. QueryTable[1].DefaultType = REG_DWORD;
  65. QueryTable[1].DefaultData = &DBCLASS_W98_Debug_Trace;
  66. QueryTable[1].DefaultLength = sizeof(DBCLASS_W98_Debug_Trace);
  67. // break on start
  68. QueryTable[2].QueryRoutine = DBCLASS_GetConfigValue;
  69. QueryTable[2].Flags = 0;
  70. QueryTable[2].Name = DEBUG_BREAK_ON;
  71. QueryTable[2].EntryContext = &DBCLASS_BreakOn;
  72. QueryTable[2].DefaultType = REG_DWORD;
  73. QueryTable[2].DefaultData = &DBCLASS_BreakOn;
  74. QueryTable[2].DefaultLength = sizeof(DBCLASS_BreakOn);
  75. //
  76. // Stop
  77. //
  78. QueryTable[3].QueryRoutine = NULL;
  79. QueryTable[3].Flags = 0;
  80. QueryTable[3].Name = NULL;
  81. ntStatus = RtlQueryRegistryValues(
  82. RTL_REGISTRY_SERVICES,
  83. usb,
  84. QueryTable, // QueryTable
  85. NULL, // Context
  86. NULL); // Environment
  87. if (NT_SUCCESS(ntStatus)) {
  88. DBCLASS_KdPrint((1, "'Debug Trace Level Set: (%d)\n", DBCLASS_Debug_Trace_Level));
  89. if (DBCLASS_W98_Debug_Trace) {
  90. DBCLASS_KdPrint((1, "'NTKERN Trace is ON\n"));
  91. } else {
  92. DBCLASS_KdPrint((1, "'NTKERN Trace is OFF\n"));
  93. }
  94. if (DBCLASS_BreakOn) {
  95. DBCLASS_KdPrint((1, "'DEBUG BREAK is ON\n"));
  96. }
  97. if (DBCLASS_Debug_Trace_Level > 0) {
  98. ULONG DBCLASS_Debug_Asserts = 1;
  99. }
  100. }
  101. if ( STATUS_OBJECT_NAME_NOT_FOUND == ntStatus ) {
  102. ntStatus = STATUS_SUCCESS;
  103. }
  104. return ntStatus;
  105. }
  106. VOID
  107. DBCLASS_AssertBaysEmpty(
  108. PDBC_CONTEXT DbcContext
  109. )
  110. {
  111. USHORT bay;
  112. for (bay=1; bay <=NUMBER_OF_BAYS(DbcContext); bay++) {
  113. DBCLASS_ASSERT(
  114. DbcContext->BayInformation[bay].DeviceFilterObject == NULL);
  115. }
  116. }
  117. VOID
  118. DBCLASS_Warning(
  119. PVOID Context,
  120. PUCHAR Message,
  121. BOOLEAN DebugBreak
  122. )
  123. {
  124. DbgPrint("DBCLASS: Warning *************************************************************\n");
  125. DbgPrint("%s", Message);
  126. DbgPrint("******************************************************************************\n");
  127. if (DebugBreak) {
  128. TRAP();
  129. }
  130. }
  131. VOID
  132. DBCLASS_Assert(
  133. IN PVOID FailedAssertion,
  134. IN PVOID FileName,
  135. IN ULONG LineNumber,
  136. IN PCHAR Message
  137. )
  138. /*++
  139. Routine Description:
  140. Debug Assert function.
  141. Arguments:
  142. DeviceObject - pointer to a device object
  143. Irp - pointer to an I/O Request Packet
  144. Return Value:
  145. --*/
  146. {
  147. // this makes the compiler generate a ret
  148. ULONG stop = 1;
  149. assert_loop:
  150. // just call the NT assert function and stop
  151. // in the debugger.
  152. RtlAssert( FailedAssertion, FileName, LineNumber, Message );
  153. // loop here to prevent users from going past
  154. // are assert before we can look at it
  155. TRAP();
  156. if (stop) {
  157. goto assert_loop;
  158. }
  159. return;
  160. }
  161. ULONG
  162. _cdecl
  163. DBCLASS_KdPrintX(
  164. ULONG l,
  165. PCH Format,
  166. ...
  167. )
  168. {
  169. va_list list;
  170. int i;
  171. int arg[6];
  172. if (DBCLASS_Debug_Trace_Level >= l) {
  173. if (l <= 1) {
  174. // dump line to debugger
  175. if (DBCLASS_W98_Debug_Trace) {
  176. DbgPrint("DBCLASS.SYS: ");
  177. *Format = ' ';
  178. } else {
  179. DbgPrint("'DBCLASS.SYS: ");
  180. }
  181. } else {
  182. // dump line to NTKERN buffer
  183. DbgPrint("'DBCLASS.SYS: ");
  184. if (DBCLASS_W98_Debug_Trace) {
  185. *Format = 0x27;
  186. }
  187. }
  188. va_start(list, Format);
  189. for (i=0; i<6; i++)
  190. arg[i] = va_arg(list, int);
  191. DbgPrint(Format, arg[0], arg[1], arg[2], arg[3], arg[4], arg[5]);
  192. }
  193. return 0;
  194. }
  195. PVOID
  196. DBCLASS_GetHeap(
  197. IN POOL_TYPE PoolType,
  198. IN ULONG NumberOfBytes,
  199. IN ULONG Signature,
  200. IN PLONG TotalAllocatedHeapSpace
  201. )
  202. /*++
  203. Routine Description:
  204. Debug routine, used to debug heap problems. We are using this since
  205. most NT debug functions are not supported by NTKERN.
  206. Arguments:
  207. PoolType - pool type passed to ExAllocatePool
  208. NumberOfBytes - number of bytes for item
  209. Signature - four byte signature supplied by caller
  210. TotalAllocatedHeapSpace - pointer to variable where client stores
  211. the total accumulated heap space allocated.
  212. Return Value:
  213. pointer to allocated memory
  214. --*/
  215. {
  216. PUCHAR p;
  217. #ifdef DEBUG_HEAP
  218. PHEAP_TAG_BUFFER tagBuffer;
  219. // we call ExAllocatePoolWithTag but no tag will be added
  220. // when running under NTKERN
  221. p = (PUCHAR) ExAllocatePoolWithTag(PoolType,
  222. NumberOfBytes + sizeof(HEAP_TAG_BUFFER)*2,
  223. Signature);
  224. if (p) {
  225. tagBuffer = (PHEAP_TAG_BUFFER) p;
  226. tagBuffer->Sig = Signature;
  227. tagBuffer->Length = NumberOfBytes;
  228. p += sizeof(HEAP_TAG_BUFFER);
  229. *TotalAllocatedHeapSpace += NumberOfBytes;
  230. tagBuffer = (PHEAP_TAG_BUFFER) (p + NumberOfBytes);
  231. tagBuffer->Sig = Signature;
  232. tagBuffer->Length = NumberOfBytes;
  233. }
  234. // LOGENTRY(LOG_MISC, (PUCHAR) &Signature, 0, 0, 0);
  235. // LOGENTRY(LOG_MISC, 'GetH', p, NumberOfBytes, stk[1] & 0x00FFFFFF);
  236. #else
  237. p = (PUCHAR) ExAllocatePoolWithTag(PoolType,
  238. NumberOfBytes,
  239. Signature);
  240. #endif /* DEBUG_HEAP */
  241. return p;
  242. }
  243. VOID
  244. DBCLASS_RetHeap(
  245. IN PVOID P,
  246. IN ULONG Signature,
  247. IN PLONG TotalAllocatedHeapSpace
  248. )
  249. /*++
  250. Routine Description:
  251. Debug routine, used to debug heap problems. We are using this since
  252. most NT debug functions are not supported by NTKERN.
  253. Arguments:
  254. P - pointer to free
  255. Return Value:
  256. none.
  257. --*/
  258. {
  259. #ifdef DEBUG_HEAP
  260. PHEAP_TAG_BUFFER endTagBuffer;
  261. PHEAP_TAG_BUFFER beginTagBuffer;
  262. DBCLASS_ASSERT(P != 0);
  263. beginTagBuffer = (PHEAP_TAG_BUFFER) ((PUCHAR)P - sizeof(HEAP_TAG_BUFFER));
  264. endTagBuffer = (PHEAP_TAG_BUFFER) ((PUCHAR)P + beginTagBuffer->Length);
  265. *TotalAllocatedHeapSpace -= beginTagBuffer->Length;
  266. // LOGENTRY(LOG_MISC, (PUCHAR) &Signature, 0, 0, 0);
  267. // LOGENTRY(LOG_MISC, 'RetH', P, tagBuffer->Length, stk[1] & 0x00FFFFFF);
  268. DBCLASS_ASSERT(*TotalAllocatedHeapSpace >= 0);
  269. DBCLASS_ASSERT(beginTagBuffer->Sig == Signature);
  270. DBCLASS_ASSERT(endTagBuffer->Sig == Signature);
  271. DBCLASS_ASSERT(endTagBuffer->Length == beginTagBuffer->Length);
  272. // fill the buffer with bad data
  273. RtlFillMemory(P, beginTagBuffer->Length, 0xff);
  274. beginTagBuffer->Sig = DBCLASS_FREE_TAG;
  275. // free the original block
  276. ExFreePool(beginTagBuffer);
  277. #else
  278. ExFreePool(P);
  279. #endif /* DEBUG_HEAP */
  280. }
  281. #endif /* DBG */
  282. #ifdef DEBUG_LOG
  283. KSPIN_LOCK LogSpinLock;
  284. struct LOG_ENTRY {
  285. ULONG le_sig; // Identifying string
  286. ULONG le_info1; // entry specific info
  287. ULONG le_info2; // entry specific info
  288. ULONG le_info3; // entry specific info
  289. }; /* USBD_LOG_ENTRY */
  290. struct LOG_ENTRY *DbclassLStart = 0; // No log yet
  291. struct LOG_ENTRY *DbclassLPtr;
  292. struct LOG_ENTRY *DbclassLEnd;
  293. #ifdef PROFILE
  294. ULONG LogMask = LOG_PROFILE;
  295. #else
  296. ULONG LogMask = 0xFFFFFFFF;
  297. #endif
  298. VOID
  299. DBCLASS_Debug_LogEntry(
  300. IN ULONG Mask,
  301. IN ULONG Sig,
  302. IN ULONG Info1,
  303. IN ULONG Info2,
  304. IN ULONG Info3
  305. )
  306. /*++
  307. Routine Description:
  308. Adds an Entry to USBH log.
  309. Arguments:
  310. Return Value:
  311. None.
  312. --*/
  313. {
  314. KIRQL irql;
  315. typedef union _SIG {
  316. struct {
  317. UCHAR Byte0;
  318. UCHAR Byte1;
  319. UCHAR Byte2;
  320. UCHAR Byte3;
  321. } b;
  322. ULONG l;
  323. } SIG, *PSIG;
  324. SIG sig, rsig;
  325. if (DbclassLStart == 0) {
  326. return;
  327. }
  328. if ((Mask & LogMask) == 0) {
  329. return;
  330. }
  331. irql = KeGetCurrentIrql();
  332. if (irql < DISPATCH_LEVEL) {
  333. KeAcquireSpinLock(&LogSpinLock, &irql);
  334. } else {
  335. KeAcquireSpinLockAtDpcLevel(&LogSpinLock);
  336. }
  337. if (DbclassLPtr > DbclassLStart) {
  338. DbclassLPtr -= 1; // Decrement to next entry
  339. } else {
  340. DbclassLPtr = DbclassLEnd;
  341. }
  342. if (irql < DISPATCH_LEVEL) {
  343. KeReleaseSpinLock(&LogSpinLock, irql);
  344. } else {
  345. KeReleaseSpinLockFromDpcLevel(&LogSpinLock);
  346. }
  347. DBCLASS_ASSERT(DbclassLPtr >= DbclassLStart);
  348. sig.l = Sig;
  349. rsig.b.Byte0 = sig.b.Byte3;
  350. rsig.b.Byte1 = sig.b.Byte2;
  351. rsig.b.Byte2 = sig.b.Byte1;
  352. rsig.b.Byte3 = sig.b.Byte0;
  353. DbclassLPtr->le_sig = rsig.l;
  354. DbclassLPtr->le_info1 = Info1;
  355. DbclassLPtr->le_info2 = Info2;
  356. DbclassLPtr->le_info3 = Info3;
  357. return;
  358. }
  359. VOID
  360. DBCLASS_LogInit(
  361. )
  362. /*++
  363. Routine Description:
  364. Init the debug log - remember interesting information in a circular buffer
  365. Arguments:
  366. Return Value:
  367. None.
  368. --*/
  369. {
  370. #ifdef MAX_DEBUG
  371. ULONG logSize = 4096*6;
  372. #else
  373. ULONG logSize = 4096*3;
  374. #endif
  375. KeInitializeSpinLock(&LogSpinLock);
  376. DbclassLStart = ExAllocatePoolWithTag(NonPagedPool,
  377. logSize,
  378. DBC_TAG);
  379. if (DbclassLStart) {
  380. DbclassLPtr = DbclassLStart;
  381. // Point the end (and first entry) 1 entry from the end of the segment
  382. DbclassLEnd = DbclassLStart + (logSize / sizeof(struct LOG_ENTRY)) - 1;
  383. } else {
  384. TRAP(); //no mem for log!
  385. }
  386. return;
  387. }
  388. VOID
  389. DBCLASS_LogFree(
  390. )
  391. /*++
  392. Routine Description:
  393. Init the debug log - remember interesting information in a circular buffer
  394. Arguments:
  395. Return Value:
  396. None.
  397. --*/
  398. {
  399. if (DbclassLStart) {
  400. ExFreePool(DbclassLStart);
  401. }
  402. }
  403. #endif /* DEBUG_LOG */