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.

593 lines
15 KiB

  1. /*++
  2. Copyright (c) 2000-2001 Microsoft Corporation
  3. Module Name:
  4. print.c
  5. Abstract:
  6. This module contains the common code to filter and print debug
  7. messages.
  8. Author:
  9. David N. Cutler (davec) 12-Jan-2000
  10. Revision History:
  11. --*/
  12. #include "kdp.h"
  13. #pragma hdrstop
  14. #include <malloc.h>
  15. #ifdef ALLOC_PRAGMA
  16. #pragma alloc_text(PAGEKD, KdpPrint)
  17. #pragma alloc_text(PAGEKD, KdpPrompt)
  18. #pragma alloc_text(PAGEKD, KdpSymbol)
  19. #pragma alloc_text(PAGEKD, KdpCommandString)
  20. #endif // ALLOC_PRAGMA
  21. #if 0
  22. ULONG gLdrHits;
  23. #endif
  24. NTSTATUS
  25. KdpPrint(
  26. IN ULONG ComponentId,
  27. IN ULONG Level,
  28. IN PCHAR Message,
  29. IN USHORT Length,
  30. IN KPROCESSOR_MODE PreviousMode,
  31. IN PKTRAP_FRAME TrapFrame,
  32. IN PKEXCEPTION_FRAME ExceptionFrame,
  33. OUT PBOOLEAN Completion
  34. )
  35. /*++
  36. Routine Description:
  37. This function filters debug print requests, probes and saves user mode
  38. message buffers on the stack, logs the print message, and prints the
  39. message on the debug terminal if apprpriate.
  40. Arguments:
  41. ComponentId - Supplies the component id of the component that issued
  42. the debug print.
  43. Level - Supplies the debug filer level number or mask.
  44. Message - Supplies a pointer to the output message.
  45. Length - Supplies the length of the output message.
  46. PreviousMode - Supplies the previous processor mode.
  47. TrapFrame - Supplies a pointer to a trap frame.
  48. ExceptionFrame - Supplies a pointer to a exception.
  49. Completion - Supplies a pointer to the variable that receives the
  50. debug print completion status.
  51. Return Value:
  52. STATUS_SUCCESS - Is returned if the debug print is filtered or is
  53. successfully printed.
  54. STATUS_BREAKPOINT - Is returned if ...
  55. STATUS_DEVICE_NOT_CONNECTED - Is returned if the kernel debugger is
  56. not enabled and the debug print message was not filtered.
  57. STATUS_ACCESS_VIOLATION - Is returned if an access violation occurs
  58. while attempting to copy a user mode buffer to the kernel stack.
  59. --*/
  60. {
  61. PCHAR Buffer;
  62. BOOLEAN Enable;
  63. ULONG Mask;
  64. STRING Output;
  65. NTSTATUS Status;
  66. //
  67. // If the the component id if out of range or output is enabled for the
  68. // specified filter level, then attempt to print the output. Otherwise,
  69. // immediately return success.
  70. //
  71. *Completion = FALSE;
  72. if (Level > 31) {
  73. Mask = Level;
  74. } else {
  75. Mask = 1 << Level;
  76. }
  77. if (((Mask & Kd_WIN2000_Mask) == 0) &&
  78. (ComponentId < KdComponentTableSize) &&
  79. ((Mask & *KdComponentTable[ComponentId]) == 0)) {
  80. Status = STATUS_SUCCESS;
  81. } else {
  82. //
  83. // Limit the message length to 512 bytes.
  84. //
  85. if (Length > 512) {
  86. Length = 512;
  87. }
  88. //
  89. // If the previous mode is user, then probe and capture the
  90. // message buffer on the stack.
  91. //
  92. if (PreviousMode != KernelMode) {
  93. try {
  94. ProbeForRead(Message, Length, sizeof(UCHAR));
  95. Buffer = alloca(512);
  96. KdpQuickMoveMemory(Buffer, Message, Length);
  97. Message = Buffer;
  98. } except (EXCEPTION_EXECUTE_HANDLER) {
  99. return STATUS_ACCESS_VIOLATION;
  100. }
  101. }
  102. //
  103. // Log debug output in circular buffer and print output
  104. // if debugger is enabled.
  105. //
  106. Output.Buffer = Message;
  107. Output.Length = Length;
  108. KdLogDbgPrint(&Output);
  109. if (KdDebuggerNotPresent == FALSE) {
  110. Enable = KdEnterDebugger(TrapFrame, ExceptionFrame);
  111. if (KdpPrintString(&Output)) {
  112. Status = STATUS_BREAKPOINT;
  113. } else {
  114. Status = STATUS_SUCCESS;
  115. }
  116. KdExitDebugger(Enable);
  117. } else {
  118. Status = STATUS_DEVICE_NOT_CONNECTED;
  119. }
  120. }
  121. *Completion = TRUE;
  122. return Status;
  123. }
  124. USHORT
  125. KdpPrompt(
  126. IN PCHAR Message,
  127. IN USHORT MessageLength,
  128. IN OUT PCHAR Reply,
  129. IN USHORT ReplyLength,
  130. IN KPROCESSOR_MODE PreviousMode,
  131. IN PKTRAP_FRAME TrapFrame,
  132. IN PKEXCEPTION_FRAME ExceptionFrame
  133. )
  134. /*++
  135. Routine Description:
  136. This function filters debug print requests, probes and saves user mode
  137. message buffers on the stack, logs the print message, and prints the
  138. message on the debug terminal if apprpriate.
  139. Arguments:
  140. Message - Supplies a pointer to the output message.
  141. MessageLength - Supplies the length of the output message.
  142. Reply - Supplies a pointer to the input buffer.
  143. ReplyLength - Supplies the length of the output message.
  144. PreviousMode - Supplies the previous processor mode.
  145. TrapFrame - Supplies a pointer to a trap frame.
  146. ExceptionFrame - Supplies a pointer to a exception.
  147. Return Value:
  148. The length of the input message is returned as the function value.
  149. --*/
  150. {
  151. PCHAR Buffer;
  152. BOOLEAN Enable;
  153. STRING Input;
  154. STRING Output;
  155. //
  156. // Limit the output and input message length to 512 bytes.
  157. //
  158. if (MessageLength > 512) {
  159. MessageLength = 512;
  160. }
  161. if (ReplyLength > 512) {
  162. ReplyLength = 512;
  163. }
  164. //
  165. // If the previous mode is user, then probe and capture the
  166. // message buffer on the stack.
  167. //
  168. if (PreviousMode != KernelMode) {
  169. try {
  170. ProbeForRead(Message, MessageLength, sizeof(UCHAR));
  171. Buffer = alloca(512);
  172. KdpQuickMoveMemory(Buffer, Message, MessageLength);
  173. Message = Buffer;
  174. ProbeForWrite(Reply, ReplyLength, sizeof(UCHAR));
  175. Buffer = alloca(512);
  176. } except (EXCEPTION_EXECUTE_HANDLER) {
  177. return 0;
  178. }
  179. } else {
  180. Buffer = Reply;
  181. }
  182. Input.Buffer = Buffer;
  183. Input.Length = 0;
  184. Input.MaximumLength = ReplyLength;
  185. Output.Buffer = Message;
  186. Output.Length = MessageLength;
  187. //
  188. // Log debug output in circular buffer and print the prompt message.
  189. //
  190. KdLogDbgPrint(&Output);
  191. Enable = KdEnterDebugger(TrapFrame, ExceptionFrame);
  192. do {
  193. } while (KdpPromptString(&Output, &Input) == TRUE);
  194. KdExitDebugger(Enable);
  195. //
  196. // If the previous mode was user, then copy the prompt input to the
  197. // reply buffer.
  198. //
  199. if (PreviousMode == UserMode) {
  200. try {
  201. KdpQuickMoveMemory(Reply, Input.Buffer, Input.Length);
  202. } except (EXCEPTION_EXECUTE_HANDLER) {
  203. }
  204. }
  205. return Input.Length;
  206. }
  207. BOOLEAN
  208. KdpReport(
  209. IN PKTRAP_FRAME TrapFrame,
  210. IN PKEXCEPTION_FRAME ExceptionFrame,
  211. IN PEXCEPTION_RECORD ExceptionRecord,
  212. IN PCONTEXT ContextRecord,
  213. IN KPROCESSOR_MODE PreviousMode,
  214. IN BOOLEAN SecondChance
  215. )
  216. /*++
  217. Routine Description:
  218. This function reports an exception to the host kernel debugger.
  219. Arguments:
  220. TrapFrame - Supplies a pointer to a trap frame that describes the
  221. trap.
  222. ExceptionFrame - Supplies a pointer to a exception frame that describes
  223. the exception.
  224. ExceptionRecord - Supplies a pointer to an exception record that
  225. describes the exception.
  226. ContextRecord - Supplies the context at the time of the exception.
  227. SecondChance - Supplies a boolean value that determines whether this is
  228. the second chance (TRUE) that the exception has been raised.
  229. Return Value:
  230. The disposition of whether the exception was handled (TRUE) or not is
  231. returned as the function value.
  232. --*/
  233. {
  234. BOOLEAN Completion;
  235. BOOLEAN Enable;
  236. PKPRCB Prcb;
  237. //
  238. // If the exception code is a breakpoint or single step, or stop
  239. // on exeception is set, or this is the second change to handle
  240. // the exception, then attempt to enter the kernel debugger.
  241. //
  242. if ((ExceptionRecord->ExceptionCode == STATUS_BREAKPOINT) ||
  243. (ExceptionRecord->ExceptionCode == STATUS_SINGLE_STEP) ||
  244. ((NtGlobalFlag & FLG_STOP_ON_EXCEPTION) != 0) ||
  245. (SecondChance != FALSE)) {
  246. //
  247. // If this is the first chance to handle the exception and the
  248. // exception code is either a port disconnected or success code,
  249. // then do not enter the kernel debugger.
  250. //
  251. if ((SecondChance == FALSE) &&
  252. ((ExceptionRecord->ExceptionCode == STATUS_PORT_DISCONNECTED) ||
  253. (NT_SUCCESS(ExceptionRecord->ExceptionCode)))) {
  254. //
  255. // This exception should not be reported to the kernel debugger.
  256. //
  257. return FALSE;
  258. }
  259. //
  260. // Debugging help:
  261. //
  262. // For user mode breakpoints going to the kernel debugger,
  263. // try to get the user mode module list and image headers
  264. // paged in before we call the debugger. Walk the list twice
  265. // in case paging in some modules pages out some
  266. // previously paged in data.
  267. //
  268. #if 0
  269. if (PreviousMode == UserMode)
  270. {
  271. PPEB Peb = PsGetCurrentProcess()->Peb;
  272. PPEB_LDR_DATA Ldr;
  273. PLIST_ENTRY LdrHead, LdrNext;
  274. PLDR_DATA_TABLE_ENTRY LdrEntry;
  275. UCHAR DataHeader;
  276. ULONG i,j;
  277. try {
  278. Ldr = Peb->Ldr;
  279. LdrHead = &Ldr->InLoadOrderModuleList;
  280. ProbeForRead (LdrHead, sizeof (LIST_ENTRY), sizeof (UCHAR));
  281. for (j=0; j<2; j++) {
  282. for (LdrNext = LdrHead->Flink, i = 0;
  283. LdrNext != LdrHead && i < 500;
  284. LdrNext = LdrNext->Flink, i++) {
  285. // BUGBUG
  286. gLdrHits++;
  287. LdrEntry = CONTAINING_RECORD (LdrNext, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks);
  288. ProbeForRead (LdrEntry, sizeof (LDR_DATA_TABLE_ENTRY), sizeof (UCHAR));
  289. DataHeader = ProbeAndReadUchar((PUCHAR)LdrEntry->DllBase);
  290. }
  291. }
  292. } except (EXCEPTION_EXECUTE_HANDLER) {
  293. }
  294. }
  295. #endif
  296. //
  297. // Report state change to the host kernel debugger.
  298. //
  299. Enable = KdEnterDebugger(TrapFrame, ExceptionFrame);
  300. Prcb = KeGetCurrentPrcb();
  301. KiSaveProcessorControlState(&Prcb->ProcessorState);
  302. KdpQuickMoveMemory((PCHAR)&Prcb->ProcessorState.ContextFrame,
  303. (PCHAR)ContextRecord,
  304. sizeof(CONTEXT));
  305. Completion =
  306. KdpReportExceptionStateChange(ExceptionRecord,
  307. &Prcb->ProcessorState.ContextFrame,
  308. SecondChance);
  309. KdpQuickMoveMemory((PCHAR)ContextRecord,
  310. (PCHAR)&Prcb->ProcessorState.ContextFrame,
  311. sizeof(CONTEXT));
  312. KiRestoreProcessorControlState(&Prcb->ProcessorState);
  313. KdExitDebugger(Enable);
  314. KdpControlCPressed = FALSE;
  315. return Completion;
  316. } else {
  317. //
  318. // This exception should not be reported to the kernel debugger.
  319. //
  320. return FALSE;
  321. }
  322. }
  323. VOID
  324. KdpSymbol(
  325. IN PSTRING String,
  326. IN PKD_SYMBOLS_INFO Symbol,
  327. IN BOOLEAN Unload,
  328. IN KPROCESSOR_MODE PreviousMode,
  329. IN PCONTEXT ContextRecord,
  330. IN PKTRAP_FRAME TrapFrame,
  331. IN PKEXCEPTION_FRAME ExceptionFrame
  332. )
  333. /*++
  334. Routine Description:
  335. This function loads or unloads debug symbols.
  336. Arguments:
  337. String - Supplies a pointer to a string descriptor.
  338. Symbol - Supplies a pointer to the symbol information.
  339. Unload - Supplies a boolean value that determines whether the symbols
  340. are being unloaded (TRUE) or loaded (FALSE).
  341. PreviousMode - Supplies the previous processor mode.
  342. ContextRecord - Supplies a pointer to a context record.
  343. TrapFrame - Supplies a pointer to a trap frame.
  344. ExceptionFrame - Supplies a pointer to a exception.
  345. Return Value:
  346. None.
  347. --*/
  348. {
  349. BOOLEAN Enable;
  350. PKPRCB Prcb;
  351. //
  352. // If the previous mode is kernel and the kernel debugger is present,
  353. // then load or unload symbols.
  354. //
  355. if ((PreviousMode == KernelMode) &&
  356. (KdDebuggerNotPresent == FALSE)) {
  357. //
  358. // Save and restore the processor context in case the
  359. // kernel debugger has been configured to stop on dll
  360. // loads.
  361. //
  362. Enable = KdEnterDebugger(TrapFrame, ExceptionFrame);
  363. Prcb = KeGetCurrentPrcb();
  364. KiSaveProcessorControlState(&Prcb->ProcessorState);
  365. KdpQuickMoveMemory((PCHAR)&Prcb->ProcessorState.ContextFrame,
  366. (PCHAR)ContextRecord,
  367. sizeof(CONTEXT));
  368. KdpReportLoadSymbolsStateChange(String,
  369. Symbol,
  370. Unload,
  371. &Prcb->ProcessorState.ContextFrame);
  372. KdpQuickMoveMemory((PCHAR)ContextRecord,
  373. (PCHAR)&Prcb->ProcessorState.ContextFrame,
  374. sizeof(CONTEXT));
  375. KiRestoreProcessorControlState(&Prcb->ProcessorState);
  376. KdExitDebugger(Enable);
  377. }
  378. return;
  379. }
  380. VOID
  381. KdpCommandString(
  382. IN PSTRING Name,
  383. IN PSTRING Command,
  384. IN KPROCESSOR_MODE PreviousMode,
  385. IN PCONTEXT ContextRecord,
  386. IN PKTRAP_FRAME TrapFrame,
  387. IN PKEXCEPTION_FRAME ExceptionFrame
  388. )
  389. /*++
  390. Routine Description:
  391. This function reports an exception to the host kernel debugger.
  392. Arguments:
  393. Name - Identification of the originator of the command.
  394. Command - Command string.
  395. PreviousMode - Supplies the previous processor mode.
  396. ContextRecord - Supplies a pointer to a context record.
  397. TrapFrame - Supplies a pointer to a trap frame that describes the
  398. trap.
  399. ExceptionFrame - Supplies a pointer to a exception frame that describes
  400. the exception.
  401. Return Value:
  402. None.
  403. --*/
  404. {
  405. //
  406. // Report state change to the host kernel debugger.
  407. //
  408. if ((PreviousMode == KernelMode) &&
  409. (KdDebuggerNotPresent == FALSE)) {
  410. BOOLEAN Enable;
  411. PKPRCB Prcb;
  412. Enable = KdEnterDebugger(TrapFrame, ExceptionFrame);
  413. Prcb = KeGetCurrentPrcb();
  414. KiSaveProcessorControlState(&Prcb->ProcessorState);
  415. KdpQuickMoveMemory((PCHAR)&Prcb->ProcessorState.ContextFrame,
  416. (PCHAR)ContextRecord,
  417. sizeof(CONTEXT));
  418. KdpReportCommandStringStateChange(Name, Command,
  419. &Prcb->ProcessorState.ContextFrame);
  420. KdpQuickMoveMemory((PCHAR)ContextRecord,
  421. (PCHAR)&Prcb->ProcessorState.ContextFrame,
  422. sizeof(CONTEXT));
  423. KiRestoreProcessorControlState(&Prcb->ProcessorState);
  424. KdExitDebugger(Enable);
  425. }
  426. }