Leaked source code of windows server 2003
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.

698 lines
16 KiB

  1. // TITLE("Debug Support Functions")
  2. //++
  3. //
  4. // Copyright (c) 1990 Microsoft Corporation
  5. //
  6. // Module Name:
  7. //
  8. // debug.c
  9. //
  10. // Abstract:
  11. //
  12. // This module implements functions to support debugging NT. They call
  13. // architecture specific routines to do the actual work.
  14. //
  15. // Author:
  16. //
  17. // Steven R. Wood (stevewo) 8-Nov-1994
  18. //
  19. // Environment:
  20. //
  21. // Any mode.
  22. //
  23. // Revision History:
  24. //
  25. //--
  26. #include "stdarg.h"
  27. #include "stdio.h"
  28. #include "ntrtlp.h"
  29. #define NOEXTAPI
  30. #include "wdbgexts.h"
  31. #include <ntdbg.h>
  32. #if !defined(BLDR_KERNEL_RUNTIME) || (defined(BLDR_KERNEL_RUNTIME) && defined(ENABLE_LOADER_DEBUG))
  33. ULONG
  34. DbgPrint(
  35. IN PCHAR Format,
  36. ...
  37. )
  38. //++
  39. //
  40. // Routine Description:
  41. //
  42. // This routine provides a "printf" style capability for the kernel
  43. // debugger.
  44. //
  45. // Note: control-C is consumed by the debugger and returned to
  46. // this routine as status. If status indicates control-C was
  47. // pressed, this routine breakpoints.
  48. //
  49. // Arguments:
  50. //
  51. // Format - printf style format string
  52. // ... - additional arguments consumed according to the
  53. // format string.
  54. //
  55. // Return Value:
  56. //
  57. // Defined as returning a ULONG, actually returns status.
  58. //
  59. //--
  60. {
  61. va_list arglist;
  62. va_start(arglist, Format);
  63. return vDbgPrintExWithPrefix("", -1, 0, Format, arglist);
  64. }
  65. ULONG
  66. DbgPrintEx(
  67. IN ULONG ComponentId,
  68. IN ULONG Level,
  69. PCHAR Format,
  70. ...
  71. )
  72. //++
  73. //
  74. // Routine Description:
  75. //
  76. // This routine provides a "printf" style capability for the kernel
  77. // debugger.
  78. //
  79. // Note: control-C is consumed by the debugger and returned to
  80. // this routine as status. If status indicates control-C was
  81. // pressed, this routine breakpoints.
  82. //
  83. // Arguments:
  84. //
  85. // ComponentId - Supplies the Id of the calling component.
  86. // Level - Supplies the output filter level.
  87. // Format - printf style format string
  88. // ... - additional arguments consumed according to the
  89. // format string.
  90. //
  91. // Return Value:
  92. //
  93. // Defined as returning a ULONG, actually returns status.
  94. //
  95. //--
  96. {
  97. va_list arglist;
  98. va_start(arglist, Format);
  99. return vDbgPrintExWithPrefix("", ComponentId, Level, Format, arglist);
  100. }
  101. ULONG
  102. vDbgPrintEx(
  103. IN ULONG ComponentId,
  104. IN ULONG Level,
  105. IN PCHAR Format,
  106. va_list arglist
  107. )
  108. //++
  109. //
  110. // Routine Description:
  111. //
  112. // This routine provides a "printf" style capability for the kernel
  113. // debugger.
  114. //
  115. // Note: control-C is consumed by the debugger and returned to
  116. // this routine as status. If status indicates control-C was
  117. // pressed, this routine breakpoints.
  118. //
  119. // Arguments:
  120. //
  121. // ComponentId - Supplies the Id of the calling component.
  122. //
  123. // Level - Supplies the output filter level or mask.
  124. //
  125. // Arguments - Supplies a pointer to a variable argument list.
  126. //
  127. // Return Value:
  128. //
  129. // Defined as returning a ULONG, actually returns status.
  130. //
  131. //--
  132. {
  133. return vDbgPrintExWithPrefix("", ComponentId, Level, Format, arglist);
  134. }
  135. ULONG
  136. vDbgPrintExWithPrefix(
  137. IN PCH Prefix,
  138. IN ULONG ComponentId,
  139. IN ULONG Level,
  140. IN PCHAR Format,
  141. va_list arglist
  142. )
  143. //++
  144. //
  145. // Routine Description:
  146. //
  147. // This routine provides a "printf" style capability for the kernel
  148. // debugger.
  149. //
  150. // Note: control-C is consumed by the debugger and returned to
  151. // this routine as status. If status indicates control-C was
  152. // pressed, this routine breakpoints.
  153. //
  154. // Arguments:
  155. //
  156. // Prefix - Supplies a pointer to text that is to prefix the formatted
  157. // output.
  158. //
  159. // ComponentId - Supplies the Id of the calling component.
  160. //
  161. // Level - Supplies the output filter level or mask.
  162. //
  163. // Arguments - Supplies a pointer to a variable argument list.
  164. //
  165. // Return Value:
  166. //
  167. // Defined as returning a ULONG, actually returns status.
  168. //
  169. //--
  170. {
  171. UCHAR Buffer[512];
  172. int cb;
  173. int Length;
  174. STRING Output;
  175. NTSTATUS Status;
  176. //
  177. // If the debug output will be suppressed, then return success
  178. // immediately.
  179. //
  180. #if !defined(BLDR_KERNEL_RUNTIME)
  181. if ((ComponentId != -1) &&
  182. (NtQueryDebugFilterState(ComponentId, Level) == FALSE)) {
  183. return STATUS_SUCCESS;
  184. }
  185. #endif
  186. #if !defined(BLDR_KERNEL_RUNTIME) && !defined(NTOS_KERNEL_RUNTIME)
  187. if (NtCurrentTeb()->InDbgPrint) {
  188. return STATUS_SUCCESS;
  189. }
  190. NtCurrentTeb()->InDbgPrint = TRUE;
  191. #endif
  192. //
  193. // Format the output into a buffer and then print it.
  194. //
  195. #if !defined(BLDR_KERNEL_RUNTIME)
  196. try {
  197. cb = strlen(Prefix);
  198. if (cb > sizeof(Buffer)) {
  199. cb = sizeof(Buffer);
  200. }
  201. strncpy(Buffer, Prefix, cb);
  202. Length = _vsnprintf(Buffer + cb , sizeof(Buffer) - cb, Format, arglist);
  203. } except (EXCEPTION_EXECUTE_HANDLER) {
  204. #if !defined(NTOS_KERNEL_RUNTIME)
  205. NtCurrentTeb()->InDbgPrint = FALSE;
  206. #endif
  207. return GetExceptionCode();
  208. }
  209. #else
  210. cb = strlen(Prefix);
  211. strcpy(Buffer, Prefix);
  212. Length = _vsnprintf(Buffer + cb, sizeof(Buffer) - cb, Format, arglist);
  213. #endif
  214. //
  215. // Check if buffer overflow occurred during formatting. If buffer overflow
  216. // occurred, then terminate the buffer with an end of line.
  217. //
  218. if (Length == -1) {
  219. Buffer[sizeof(Buffer) - 1] = '\n';
  220. Length = sizeof(Buffer);
  221. } else {
  222. Length += cb;
  223. }
  224. Output.Buffer = Buffer;
  225. Output.Length = (USHORT)Length;
  226. //
  227. // If APP is being debugged, raise an exception and the debugger
  228. // will catch and handle this. Otherwise, kernel debugger service
  229. // is called.
  230. //
  231. #if !defined(BLDR_KERNEL_RUNTIME) && !defined(NTOS_KERNEL_RUNTIME)
  232. //
  233. // For non-Intel architectures, can't raise exceptions until the PebLock
  234. // is initialized, since the Function Table lookup code uses the PebLock
  235. // to serialize access to the loaded module database.
  236. //
  237. #if !i386
  238. if (NtCurrentPeb()->FastPebLock != NULL)
  239. #endif //!i386
  240. if (NtCurrentPeb()->BeingDebugged) {
  241. EXCEPTION_RECORD ExceptionRecord;
  242. //
  243. // Construct an exception record.
  244. //
  245. ExceptionRecord.ExceptionCode = DBG_PRINTEXCEPTION_C;
  246. ExceptionRecord.ExceptionRecord = (PEXCEPTION_RECORD)NULL;
  247. ExceptionRecord.NumberParameters = 2;
  248. ExceptionRecord.ExceptionFlags = 0;
  249. ExceptionRecord.ExceptionInformation[ 0 ] = Output.Length + 1;
  250. ExceptionRecord.ExceptionInformation[ 1 ] = (ULONG_PTR)(Output.Buffer);
  251. try {
  252. RtlRaiseException( &ExceptionRecord );
  253. } except (EXCEPTION_EXECUTE_HANDLER) {
  254. }
  255. #if !defined(BLDR_KERNEL_RUNTIME) && !defined(NTOS_KERNEL_RUNTIME)
  256. NtCurrentTeb()->InDbgPrint = FALSE;
  257. #endif
  258. return STATUS_SUCCESS;
  259. }
  260. #endif
  261. Status = DebugPrint(&Output, ComponentId, Level);
  262. if (Status == STATUS_BREAKPOINT) {
  263. DbgBreakPointWithStatus(DBG_STATUS_CONTROL_C);
  264. Status = STATUS_SUCCESS;
  265. }
  266. #if !defined(BLDR_KERNEL_RUNTIME) && !defined(NTOS_KERNEL_RUNTIME)
  267. NtCurrentTeb()->InDbgPrint = FALSE;
  268. #endif
  269. return Status;
  270. }
  271. ULONG
  272. DbgPrintReturnControlC(
  273. PCHAR Format,
  274. ...
  275. )
  276. //++
  277. //
  278. // Routine Description:
  279. //
  280. // This routine provides a "printf" style capability for the kernel
  281. // debugger.
  282. //
  283. // This routine is exactly the same as DbgPrint except that control-C
  284. // is NOT handled here. Instead, status indicating control-C is
  285. // returned to the caller to do with as they will.
  286. //
  287. // Arguments:
  288. //
  289. // Format - printf style format string
  290. // ... - additional arguments consumed according to the
  291. // format string.
  292. //
  293. // Return Value:
  294. //
  295. // Defined as returning a ULONG, actually returns status.
  296. //
  297. //--
  298. {
  299. va_list arglist;
  300. UCHAR Buffer[512];
  301. int cb;
  302. STRING Output;
  303. #if !defined(BLDR_KERNEL_RUNTIME) && !defined(NTOS_KERNEL_RUNTIME)
  304. CONST PPEB Peb = NtCurrentPeb();
  305. #endif
  306. //
  307. // Format the output into a buffer and then print it.
  308. //
  309. va_start(arglist, Format);
  310. Buffer[sizeof(Buffer) - 1] = 0;
  311. cb = _vsnprintf(Buffer, sizeof(Buffer) - 1, Format, arglist);
  312. if (cb == -1) { // detect buffer overflow
  313. cb = sizeof(Buffer);
  314. Buffer[sizeof(Buffer) - 1] = '\n';
  315. }
  316. Output.Buffer = Buffer;
  317. Output.Length = (USHORT) cb;
  318. //
  319. // If APP is being debugged, raise an exception and the debugger
  320. // will catch and handle this. Otherwise, kernel debugger service
  321. // is called.
  322. //
  323. #if !defined(BLDR_KERNEL_RUNTIME) && !defined(NTOS_KERNEL_RUNTIME)
  324. #if !i386
  325. //
  326. // For non-Intel architectures, can't raise exceptions until the PebLock
  327. // is initialized, since the Function Table lookup code uses the PebLock
  328. // to serialize access to the loaded module database. What a crock
  329. //
  330. if (Peb->FastPebLock != NULL)
  331. //
  332. // For IA64 and probably AMD64, can't raise exceptions until ntdll is in
  333. // Peb->Ldr, so that RtlPcToFileHeader can find ntdll in Peb->Ldr. The
  334. // dbgprints / exceptions are necessarily from ntdll at this point.
  335. // The first two things in Peb->Ldr are the .exe and ntdll.dll, so
  336. // check that there are two things in the list.
  337. //
  338. if ((Peb->Ldr != NULL) &&
  339. (Peb->Ldr->InLoadOrderModuleList.Flink != &Peb->Ldr->InLoadOrderModuleList) &&
  340. (Peb->Ldr->InLoadOrderModuleList.Blink != Peb->Ldr->InLoadOrderModuleList.Flink))
  341. #endif //!i386
  342. if (Peb->BeingDebugged) {
  343. EXCEPTION_RECORD ExceptionRecord;
  344. //
  345. // Construct an exception record.
  346. //
  347. ExceptionRecord.ExceptionCode = DBG_PRINTEXCEPTION_C;
  348. ExceptionRecord.ExceptionRecord = (PEXCEPTION_RECORD)NULL;
  349. ExceptionRecord.NumberParameters = 2;
  350. ExceptionRecord.ExceptionFlags = 0;
  351. ExceptionRecord.ExceptionInformation[ 0 ] = Output.Length + 1;
  352. ExceptionRecord.ExceptionInformation[ 1 ] = (ULONG_PTR)(Output.Buffer);
  353. try {
  354. RtlRaiseException( &ExceptionRecord );
  355. } except (EXCEPTION_EXECUTE_HANDLER) {
  356. }
  357. return STATUS_SUCCESS;
  358. }
  359. #endif
  360. return DebugPrint(&Output, 0, 0);
  361. }
  362. ULONG
  363. DbgPrompt(
  364. IN PCHAR Prompt,
  365. OUT PCHAR Response,
  366. IN ULONG MaximumResponseLength
  367. )
  368. //++
  369. //
  370. // Routine Description:
  371. //
  372. // This function displays the prompt string on the debugging console and
  373. // then reads a line of text from the debugging console. The line read
  374. // is returned in the memory pointed to by the second parameter. The
  375. // third parameter specifies the maximum number of characters that can
  376. // be stored in the response area.
  377. //
  378. // Arguments:
  379. //
  380. // Prompt - specifies the text to display as the prompt.
  381. //
  382. // Response - specifies where to store the response read from the
  383. // debugging console.
  384. //
  385. // Prompt - specifies the maximum number of characters that can be
  386. // stored in the Response buffer.
  387. //
  388. // Return Value:
  389. //
  390. // Number of characters stored in the Response buffer. Includes the
  391. // terminating newline character, but not the null character after
  392. // that.
  393. //
  394. //--
  395. {
  396. STRING Input;
  397. STRING Output;
  398. //
  399. // Output the prompt string and read input.
  400. //
  401. Input.MaximumLength = (USHORT)MaximumResponseLength;
  402. Input.Buffer = Response;
  403. Output.Length = (USHORT)strlen( Prompt );
  404. Output.Buffer = Prompt;
  405. return DebugPrompt( &Output, &Input );
  406. }
  407. #if defined(NTOS_KERNEL_RUNTIME) || defined(BLDR_KERNEL_RUNTIME)
  408. VOID
  409. DbgLoadImageSymbols(
  410. IN PSTRING FileName,
  411. IN PVOID ImageBase,
  412. IN ULONG_PTR ProcessId
  413. )
  414. //++
  415. //
  416. // Routine Description:
  417. //
  418. // Tells the debugger about newly loaded symbols.
  419. //
  420. // Arguments:
  421. //
  422. // Return Value:
  423. //
  424. //--
  425. {
  426. PIMAGE_NT_HEADERS NtHeaders;
  427. KD_SYMBOLS_INFO SymbolInfo;
  428. SymbolInfo.BaseOfDll = ImageBase;
  429. SymbolInfo.ProcessId = ProcessId;
  430. NtHeaders = RtlImageNtHeader( ImageBase );
  431. if (NtHeaders != NULL) {
  432. SymbolInfo.CheckSum = (ULONG)NtHeaders->OptionalHeader.CheckSum;
  433. SymbolInfo.SizeOfImage = (ULONG)NtHeaders->OptionalHeader.SizeOfImage;
  434. } else {
  435. #if defined(BLDR_KERNEL_RUNTIME)
  436. //
  437. // There is only one image loaded in the loader environment that
  438. // does not have an NT image header. The image is the OS loader
  439. // and it is loaded by the firmware which strips the file header
  440. // and the optional ROM header. All the debugger requires is a
  441. // good guest at the size of the image.
  442. //
  443. SymbolInfo.SizeOfImage = 0x100000;
  444. #else
  445. SymbolInfo.SizeOfImage = 0;
  446. #endif
  447. SymbolInfo.CheckSum = 0;
  448. }
  449. DebugService2(FileName, &SymbolInfo, BREAKPOINT_LOAD_SYMBOLS);
  450. return;
  451. }
  452. VOID
  453. DbgUnLoadImageSymbols (
  454. IN PSTRING FileName,
  455. IN PVOID ImageBase,
  456. IN ULONG_PTR ProcessId
  457. )
  458. //++
  459. //
  460. // Routine Description:
  461. //
  462. // Tells the debugger about newly unloaded symbols.
  463. //
  464. // Arguments:
  465. //
  466. // Return Value:
  467. //
  468. //--
  469. {
  470. KD_SYMBOLS_INFO SymbolInfo;
  471. SymbolInfo.BaseOfDll = ImageBase;
  472. SymbolInfo.ProcessId = ProcessId;
  473. SymbolInfo.CheckSum = 0;
  474. SymbolInfo.SizeOfImage = 0;
  475. DebugService2(FileName, &SymbolInfo, BREAKPOINT_UNLOAD_SYMBOLS);
  476. return;
  477. }
  478. VOID
  479. DbgCommandString(
  480. IN PCH Name,
  481. IN PCH Command
  482. )
  483. //++
  484. //
  485. // Routine Description:
  486. //
  487. // Tells the debugger to execute a command string
  488. //
  489. // Arguments:
  490. //
  491. // Name - Identifies the originator of the command.
  492. //
  493. // Command - Command string.
  494. //
  495. // Return Value:
  496. //
  497. //--
  498. {
  499. STRING NameStr, CommandStr;
  500. NameStr.Buffer = Name;
  501. NameStr.Length = (USHORT)strlen(Name);
  502. CommandStr.Buffer = Command;
  503. CommandStr.Length = (USHORT)strlen(Command);
  504. DebugService2(&NameStr, &CommandStr, BREAKPOINT_COMMAND_STRING);
  505. }
  506. #endif // defined(NTOS_KERNEL_RUNTIME)
  507. #if !defined(BLDR_KERNEL_RUNTIME)
  508. NTSTATUS
  509. DbgQueryDebugFilterState(
  510. IN ULONG ComponentId,
  511. IN ULONG Level
  512. )
  513. //++
  514. //
  515. // Routine Description:
  516. //
  517. // This function queries the debug print enable for a specified component
  518. // level. If Level is > 31, it's assumed to be a mask otherwise, it indicates
  519. // a specific debug level to test for (ERROR/WARNING/TRACE/INFO, etc).
  520. //
  521. // Arguments:
  522. //
  523. // ComponentId - Supplies the component id.
  524. //
  525. // Level - Supplies the debug filter level number or mask.
  526. //
  527. // Return Value:
  528. //
  529. // STATUS_INVALID_PARAMETER_1 is returned if the component id is not
  530. // valid.
  531. //
  532. // TRUE is returned if output is enabled for the specified component
  533. // and level or is enabled for the system.
  534. //
  535. // FALSE is returned if output is not enabled for the specified component
  536. // and level and is not enabled for the system.
  537. //
  538. //--
  539. {
  540. return NtQueryDebugFilterState(ComponentId, Level);
  541. }
  542. NTSTATUS
  543. DbgSetDebugFilterState(
  544. IN ULONG ComponentId,
  545. IN ULONG Level,
  546. IN BOOLEAN State
  547. )
  548. //++
  549. //
  550. // Routine Description:
  551. //
  552. // This function sets the state of the debug print enable for a specified
  553. // component and level. The debug print enable state for the system is set
  554. // by specifying the distinguished value -1 for the component id.
  555. //
  556. // Arguments:
  557. //
  558. // ComponentId - Supplies the Id of the calling component.
  559. //
  560. // Level - Supplies the output filter level or mask.
  561. //
  562. // State - Supplies a boolean value that determines the new state.
  563. //
  564. // Return Value:
  565. //
  566. // STATUS_ACCESS_DENIED is returned if the required privilege is not held.
  567. //
  568. // STATUS_INVALID_PARAMETER_1 is returned if the component id is not
  569. // valid.
  570. //
  571. // STATUS_SUCCESS is returned if the debug print enable state is set for
  572. // the specified component.
  573. //
  574. //--
  575. {
  576. return NtSetDebugFilterState(ComponentId, Level, State);
  577. }
  578. #endif
  579. #endif // !defined(BLDR_KERNEL_RUNTIME)