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.

541 lines
14 KiB

  1. /*++
  2. Copyright (c) 1990-2001 Microsoft Corporation
  3. Module Name:
  4. kdinit.c
  5. Abstract:
  6. This module implements the initialization for the portable kernel debgger.
  7. Author:
  8. David N. Cutler 27-July-1990
  9. Revision History:
  10. --*/
  11. #include "kdp.h"
  12. BOOLEAN
  13. KdRegisterDebuggerDataBlock(
  14. IN ULONG Tag,
  15. IN PDBGKD_DEBUG_DATA_HEADER64 DataHeader,
  16. IN ULONG Size
  17. );
  18. #ifdef ALLOC_PRAGMA
  19. #pragma alloc_text(PAGEKD, KdInitSystem)
  20. #pragma alloc_text(PAGEKD, KdUpdateDataBlock)
  21. #pragma alloc_text(PAGEKD, KdRegisterDebuggerDataBlock)
  22. #endif
  23. BOOLEAN KdBreakAfterSymbolLoad;
  24. VOID
  25. KdUpdateDataBlock(
  26. VOID
  27. )
  28. /*++
  29. Routine Description:
  30. We have to update this variable seperately since it is initialized at a
  31. later time by PS. PS will call us to update the data block.
  32. --*/
  33. {
  34. KdDebuggerDataBlock.KeUserCallbackDispatcher = (ULONG_PTR) KeUserCallbackDispatcher;
  35. }
  36. ULONG_PTR
  37. KdGetDataBlock(
  38. VOID
  39. )
  40. /*++
  41. Routine Description:
  42. Called by crashdump to get the address of this data block
  43. This routine can not be paged.
  44. --*/
  45. {
  46. return (ULONG_PTR)(&KdDebuggerDataBlock);
  47. }
  48. BOOLEAN
  49. KdInitSystem(
  50. IN ULONG Phase,
  51. IN PLOADER_PARAMETER_BLOCK LoaderBlock OPTIONAL
  52. )
  53. /*++
  54. Routine Description:
  55. This routine initializes the portable kernel debugger.
  56. Arguments:
  57. Phase - Initialization phase
  58. LoaderBlock - Supplies a pointer to the LOADER_PARAMETER_BLOCK passed
  59. in from the OS Loader.
  60. Return Value:
  61. None.
  62. --*/
  63. {
  64. PCHAR BaudOption;
  65. ULONG Index;
  66. BOOLEAN Initialize;
  67. PLIST_ENTRY NextEntry;
  68. PCHAR Options;
  69. PCHAR PortOption;
  70. if (Phase == 0) {
  71. //
  72. // If kernel debugger is already initialized, then return.
  73. //
  74. if (KdDebuggerEnabled != FALSE) {
  75. return TRUE;
  76. }
  77. KiDebugRoutine = KdpStub;
  78. KdBreakAfterSymbolLoad = FALSE;
  79. //
  80. // Determine whether or not the debugger should be enabled.
  81. //
  82. // Note that if LoaderBlock == NULL, then KdInitSystem was called
  83. // from BugCheck code. For this case the debugger is always enabled
  84. // to report the bugcheck if possible.
  85. //
  86. if (!KdpDebuggerDataListHead.Flink)
  87. {
  88. InitializeListHead(&KdpDebuggerDataListHead);
  89. KdRegisterDebuggerDataBlock(KDBG_TAG,
  90. &KdDebuggerDataBlock.Header,
  91. sizeof(KdDebuggerDataBlock));
  92. KdVersionBlock.MinorVersion = (short)NtBuildNumber;
  93. KdVersionBlock.MajorVersion = (short)((NtBuildNumber >> 28) & 0xFFFFFFF);
  94. KdVersionBlock.MaxStateChange =
  95. (UCHAR)(DbgKdMaximumStateChange - DbgKdMinimumStateChange);
  96. KdVersionBlock.MaxManipulate =
  97. (UCHAR)(DbgKdMaximumManipulate - DbgKdMinimumManipulate);
  98. KdVersionBlock.PsLoadedModuleList =
  99. (ULONG64)(LONG64)(LONG_PTR)&PsLoadedModuleList;
  100. KdVersionBlock.DebuggerDataList =
  101. (ULONG64)(LONG64)(LONG_PTR)&KdpDebuggerDataListHead;
  102. #if !defined(NT_UP)
  103. KdVersionBlock.Flags |= DBGKD_VERS_FLAG_MP;
  104. #endif
  105. #if defined(_AMD64_) || defined(_X86_)
  106. //
  107. // Enable this for all platforms when VersionBlock is added
  108. // to all the KPCR definitions.
  109. //
  110. KeGetPcr()->KdVersionBlock = &KdVersionBlock;
  111. #endif
  112. }
  113. if (LoaderBlock != NULL) {
  114. // If the debugger is being initialized during boot, PsNtosImageBase
  115. // and PsLoadedModuleList are not yet valid. KdInitSystem got
  116. // the image base from the loader block.
  117. // On the other hand, if the debugger was initialized by a bugcheck,
  118. // it didn't get a loader block to look at, but the system was
  119. // running so the other variables are valid.
  120. //
  121. KdVersionBlock.KernBase = (ULONG64)(LONG64)(LONG_PTR)
  122. CONTAINING_RECORD(
  123. (LoaderBlock->LoadOrderListHead.Flink),
  124. KLDR_DATA_TABLE_ENTRY,
  125. InLoadOrderLinks)->DllBase;
  126. //
  127. // Fill in and register the debugger's debugger data blocks.
  128. // Most fields are already initialized, some fields will not be
  129. // filled in until later.
  130. //
  131. if (LoaderBlock->LoadOptions != NULL) {
  132. Options = LoaderBlock->LoadOptions;
  133. _strupr(Options);
  134. //
  135. // If any of the port option, baud option, or debug is
  136. // specified, then enable the debugger unless it is explictly
  137. // disabled.
  138. //
  139. Initialize = TRUE;
  140. if (strstr(Options, "DEBUG") == NULL) {
  141. Initialize = FALSE;
  142. }
  143. //
  144. // If the debugger is explicitly disabled, then set to NODEBUG.
  145. //
  146. if (strstr(Options, "NODEBUG")) {
  147. Initialize = FALSE;
  148. KdPitchDebugger = TRUE;
  149. }
  150. if (strstr(Options, "CRASHDEBUG")) {
  151. Initialize = FALSE;
  152. KdPitchDebugger = FALSE;
  153. }
  154. } else {
  155. //
  156. // If the load options are not specified, then set to NODEBUG.
  157. //
  158. KdPitchDebugger = TRUE;
  159. Initialize = FALSE;
  160. }
  161. } else {
  162. KdVersionBlock.KernBase = (ULONG64)(LONG64)(LONG_PTR)PsNtosImageBase;
  163. Initialize = TRUE;
  164. }
  165. KdDebuggerDataBlock.KernBase = (ULONG_PTR) KdVersionBlock.KernBase;
  166. if (Initialize == FALSE) {
  167. return(TRUE);
  168. }
  169. if (!NT_SUCCESS(KdDebuggerInitialize0(LoaderBlock))) {
  170. return TRUE;
  171. }
  172. //
  173. // Set address of kernel debugger trap routine.
  174. //
  175. KiDebugRoutine = KdpTrap;
  176. if (!KdpDebuggerStructuresInitialized) {
  177. KdpContext.KdpControlCPending = FALSE;
  178. // Retries are set to this after boot
  179. KdpContext.KdpDefaultRetries = MAXIMUM_RETRIES;
  180. KiDebugSwitchRoutine = KdpSwitchProcessor;
  181. //
  182. // Initialize TimeSlip
  183. //
  184. KeInitializeDpc(&KdpTimeSlipDpc, KdpTimeSlipDpcRoutine, NULL);
  185. KeInitializeTimer(&KdpTimeSlipTimer);
  186. ExInitializeWorkItem(&KdpTimeSlipWorkItem, KdpTimeSlipWork, NULL);
  187. KdpDebuggerStructuresInitialized = TRUE ;
  188. }
  189. KdTimerStart.HighPart = 0L;
  190. KdTimerStart.LowPart = 0L;
  191. //
  192. // Mark debugger enabled.
  193. //
  194. KdPitchDebugger = FALSE;
  195. KdDebuggerEnabled = TRUE;
  196. SharedUserData->KdDebuggerEnabled = 0x00000001;
  197. //
  198. // If the loader block address is specified, then scan the loaded
  199. // module list and load the image symbols via the kernel debugger
  200. // for the system and the HAL. If the host debugger has been started
  201. // with the -d option a break into the kernel debugger will occur at
  202. // this point.
  203. //
  204. if (LoaderBlock != NULL) {
  205. Index = 0;
  206. NextEntry = LoaderBlock->LoadOrderListHead.Flink;
  207. while ((NextEntry != &LoaderBlock->LoadOrderListHead) &&
  208. (Index < 2)) {
  209. CHAR Buffer[256];
  210. ULONG Count;
  211. PKLDR_DATA_TABLE_ENTRY DataTableEntry;
  212. WCHAR *Filename;
  213. ULONG Length;
  214. STRING NameString;
  215. //
  216. // Get the address of the data table entry for the next component.
  217. //
  218. DataTableEntry = CONTAINING_RECORD(NextEntry,
  219. KLDR_DATA_TABLE_ENTRY,
  220. InLoadOrderLinks);
  221. //
  222. // Load the symbols for the next component.
  223. //
  224. Filename = DataTableEntry->FullDllName.Buffer;
  225. Length = DataTableEntry->FullDllName.Length / sizeof(WCHAR);
  226. Count = 0;
  227. do {
  228. Buffer[Count++] = (CHAR)*Filename++;
  229. } while (Count < Length);
  230. Buffer[Count] = 0;
  231. RtlInitString(&NameString, Buffer);
  232. DbgLoadImageSymbols(&NameString,
  233. DataTableEntry->DllBase,
  234. (ULONG)-1);
  235. NextEntry = NextEntry->Flink;
  236. Index += 1;
  237. }
  238. }
  239. //
  240. // If -b was specified when the host debugger was started, then set up
  241. // to break after symbols are loaded for the kernel, hal, and drivers
  242. // that were loaded by the loader.
  243. //
  244. if (LoaderBlock != NULL) {
  245. KdBreakAfterSymbolLoad = KdPollBreakIn();
  246. }
  247. } else {
  248. //
  249. // Initialize timer facility - HACKHACK
  250. //
  251. KeQueryPerformanceCounter(&KdPerformanceCounterRate);
  252. }
  253. return TRUE;
  254. }
  255. BOOLEAN
  256. KdRegisterDebuggerDataBlock(
  257. IN ULONG Tag,
  258. IN PDBGKD_DEBUG_DATA_HEADER64 DataHeader,
  259. IN ULONG Size
  260. )
  261. /*++
  262. Routine Description:
  263. This routine is called by a component or driver to register a
  264. debugger data block. The data block is made accessible to the
  265. kernel debugger, thus providing a reliable method of exposing
  266. random data to debugger extensions.
  267. Arguments:
  268. Tag - Supplies a unique 4 byte tag which is used to identify the
  269. data block.
  270. DataHeader - Supplies the address of the debugger data block header.
  271. The OwnerTag field must contain a unique value, and the Size
  272. field must contain the size of the data block, including the
  273. header. If this block is already present, or there is
  274. already a block with the same value for OwnerTag, this one
  275. will not be inserted. If Size is incorrect, this code will
  276. not notice, but the usermode side of the debugger might not
  277. function correctly.
  278. Size - Supplies the size of the data block, including the header.
  279. Return Value:
  280. TRUE if the block was added to the list, FALSE if not.
  281. --*/
  282. {
  283. KIRQL OldIrql;
  284. PLIST_ENTRY List;
  285. PDBGKD_DEBUG_DATA_HEADER64 Header;
  286. KeAcquireSpinLock(&KdpDataSpinLock, &OldIrql);
  287. //
  288. // Look for a record with the same tag or address
  289. //
  290. List = KdpDebuggerDataListHead.Flink;
  291. while (List != &KdpDebuggerDataListHead) {
  292. Header = CONTAINING_RECORD(List, DBGKD_DEBUG_DATA_HEADER64, List);
  293. List = List->Flink;
  294. if ((Header == DataHeader) || (Header->OwnerTag == Tag)) {
  295. KeReleaseSpinLock(&KdpDataSpinLock, OldIrql);
  296. return FALSE;
  297. }
  298. }
  299. //
  300. // It wasn't already there, so add it.
  301. //
  302. DataHeader->OwnerTag = Tag;
  303. DataHeader->Size = Size;
  304. InsertTailList(&KdpDebuggerDataListHead, (PLIST_ENTRY)(&DataHeader->List));
  305. KeReleaseSpinLock(&KdpDataSpinLock, OldIrql);
  306. return TRUE;
  307. }
  308. VOID
  309. KdDeregisterDebuggerDataBlock(
  310. IN PDBGKD_DEBUG_DATA_HEADER64 DataHeader
  311. )
  312. /*++
  313. Routine Description:
  314. This routine is called to deregister a data block previously
  315. registered with KdRegisterDebuggerDataBlock. If the block is
  316. found in the list, it is removed.
  317. Arguments:
  318. DataHeader - Supplies the address of the data block which is
  319. to be removed from the list.
  320. Return Value:
  321. None
  322. --*/
  323. {
  324. KIRQL OldIrql;
  325. PLIST_ENTRY List;
  326. PDBGKD_DEBUG_DATA_HEADER64 Header;
  327. KeAcquireSpinLock(&KdpDataSpinLock, &OldIrql);
  328. //
  329. // Make sure the data block is on our list before removing it.
  330. //
  331. List = KdpDebuggerDataListHead.Flink;
  332. while (List != &KdpDebuggerDataListHead) {
  333. Header = CONTAINING_RECORD(List, DBGKD_DEBUG_DATA_HEADER64, List);
  334. List = List->Flink;
  335. if (DataHeader == Header) {
  336. RemoveEntryList((PLIST_ENTRY)(&DataHeader->List));
  337. break;
  338. }
  339. }
  340. KeReleaseSpinLock(&KdpDataSpinLock, OldIrql);
  341. }
  342. VOID
  343. KdLogDbgPrint(
  344. IN PSTRING String
  345. )
  346. {
  347. KIRQL OldIrql;
  348. ULONG Length;
  349. ULONG LengthCopied;
  350. for (; ;) {
  351. if (KeTestSpinLock (&KdpPrintSpinLock)) {
  352. KeRaiseIrql (HIGH_LEVEL, &OldIrql);
  353. if (KeTryToAcquireSpinLockAtDpcLevel(&KdpPrintSpinLock)) {
  354. break; // got the lock
  355. }
  356. KeLowerIrql(OldIrql);
  357. }
  358. }
  359. if (KdPrintCircularBuffer) {
  360. Length = String->Length;
  361. //
  362. // truncate ridiculous strings
  363. //
  364. if (Length > KDPRINTBUFFERSIZE) {
  365. Length = KDPRINTBUFFERSIZE;
  366. }
  367. if (KdPrintWritePointer + Length <= KdPrintCircularBuffer+KDPRINTBUFFERSIZE) {
  368. KdpCopyFromPtr(KdPrintWritePointer, String->Buffer, Length, &LengthCopied);
  369. KdPrintWritePointer += LengthCopied;
  370. if (KdPrintWritePointer >= KdPrintCircularBuffer+KDPRINTBUFFERSIZE) {
  371. KdPrintWritePointer = KdPrintCircularBuffer;
  372. KdPrintRolloverCount++;
  373. }
  374. } else {
  375. ULONG First = (ULONG)(KdPrintCircularBuffer + KDPRINTBUFFERSIZE - KdPrintWritePointer);
  376. KdpCopyFromPtr(KdPrintWritePointer,
  377. String->Buffer,
  378. First,
  379. &LengthCopied);
  380. if (LengthCopied == First) {
  381. KdpCopyFromPtr(KdPrintCircularBuffer,
  382. String->Buffer + First,
  383. Length - First,
  384. &LengthCopied);
  385. LengthCopied += First;
  386. }
  387. if (LengthCopied > First) {
  388. KdPrintWritePointer = KdPrintCircularBuffer + LengthCopied - First;
  389. KdPrintRolloverCount++;
  390. } else {
  391. KdPrintWritePointer += LengthCopied;
  392. if (KdPrintWritePointer >= KdPrintCircularBuffer+KDPRINTBUFFERSIZE) {
  393. KdPrintWritePointer = KdPrintCircularBuffer;
  394. KdPrintRolloverCount++;
  395. }
  396. }
  397. }
  398. }
  399. KiReleaseSpinLock(&KdpPrintSpinLock);
  400. KeLowerIrql(OldIrql);
  401. }