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.

391 lines
11 KiB

  1. /*++
  2. Copyright (c) 1989 Microsoft Corporation
  3. Module Name:
  4. excptdbg.c
  5. Abstract:
  6. This module implements an exception dispatcher logging facility.
  7. Author:
  8. Kent Forschmiedt (kentf) 05-Oct-1995
  9. Revision History:
  10. Jonathan Schwartz (jschwart) 16-Jun-2000
  11. Added RtlUnhandledExceptionFilter
  12. Jay Krell (a-JayK) November 2000
  13. Added RtlUnhandledExceptionFilter2, takes __FUNCTION__ parameter
  14. --*/
  15. #include "ntrtlp.h"
  16. PLAST_EXCEPTION_LOG RtlpExceptionLog;
  17. ULONG RtlpExceptionLogCount;
  18. ULONG RtlpExceptionLogSize;
  19. VOID
  20. RtlInitializeExceptionLog(
  21. IN ULONG Entries
  22. )
  23. /*++
  24. Routine Description:
  25. This routine allocates space for the exception dispatcher logging
  26. facility, and records the address and size of the log area in globals
  27. where they can be found by the debugger.
  28. If memory is not available, the table pointer will remain NULL
  29. and the logging functions will do nothing.
  30. Arguments:
  31. Entries - Supplies the number of entries to allocate for
  32. Return Value:
  33. None
  34. --*/
  35. {
  36. #if defined(NTOS_KERNEL_RUNTIME)
  37. RtlpExceptionLog = (PLAST_EXCEPTION_LOG)ExAllocatePoolWithTag( NonPagedPool, sizeof(LAST_EXCEPTION_LOG) * Entries, 'gbdE' );
  38. #else
  39. //RtlpExceptionLog = (PLAST_EXCEPTION_LOG)RtlAllocateHeap( RtlProcessHeap(), 0, sizeof(LAST_EXCEPTION_LOG) * Entries );
  40. #endif
  41. if (RtlpExceptionLog) {
  42. RtlpExceptionLogSize = Entries;
  43. }
  44. }
  45. ULONG
  46. RtlpLogExceptionHandler(
  47. IN PEXCEPTION_RECORD ExceptionRecord,
  48. IN PCONTEXT ContextRecord,
  49. IN ULONG_PTR ControlPc,
  50. IN PVOID HandlerData,
  51. IN ULONG Size
  52. )
  53. /*++
  54. Routine Description:
  55. Records the dispatching of exceptions to frame-based handlers.
  56. The debugger may inspect the table later and interpret the data
  57. to discover the address of the filters and handlers.
  58. Arguments:
  59. ExceptionRecord - Supplies an exception record
  60. ContextRecord - Supplies the context at the exception
  61. ControlPc - Supplies the PC where control left the frame being
  62. dispatched to.
  63. HandlerData - Supplies a pointer to the host-dependent exception
  64. data. On the RISC machines this is a RUNTIME_FUNCTION record;
  65. on x86 it is the registration record from the stack frame.
  66. Size - Supplies the size of HandlerData
  67. Returns:
  68. The index to the log entry used, so that if the handler returns
  69. a disposition it may be recorded.
  70. --*/
  71. {
  72. #if !defined(NTOS_KERNEL_RUNTIME)
  73. return 0;
  74. #else
  75. ULONG LogIndex;
  76. if (!RtlpExceptionLog) {
  77. return 0;
  78. }
  79. ASSERT(Size <= MAX_EXCEPTION_LOG_DATA_SIZE * sizeof(ULONG));
  80. do {
  81. LogIndex = RtlpExceptionLogCount;
  82. } while (LogIndex != (ULONG)InterlockedCompareExchange(
  83. (PLONG)&RtlpExceptionLogCount,
  84. ((LogIndex + 1) % MAX_EXCEPTION_LOG),
  85. LogIndex));
  86. //
  87. // the debugger will have to interpret the exception handler
  88. // data, because it cannot be done safely here.
  89. //
  90. RtlCopyMemory(RtlpExceptionLog[LogIndex].HandlerData,
  91. HandlerData,
  92. Size);
  93. RtlpExceptionLog[LogIndex].ExceptionRecord = *ExceptionRecord;
  94. RtlpExceptionLog[LogIndex].ContextRecord = *ContextRecord;
  95. RtlpExceptionLog[LogIndex].Disposition = -1;
  96. return LogIndex;
  97. #endif // !NTOS_KERNEL_RUNTIME
  98. }
  99. VOID
  100. RtlpLogLastExceptionDisposition(
  101. ULONG LogIndex,
  102. EXCEPTION_DISPOSITION Disposition
  103. )
  104. /*++
  105. Routine Description:
  106. Records the disposition from an exception handler.
  107. Arguments:
  108. LogIndex - Supplies the entry number of the exception log record.
  109. Disposition - Supplies the disposition code
  110. Return Value:
  111. None
  112. --*/
  113. {
  114. // If MAX_EXCEPTION_LOG or more exceptions were dispatched while
  115. // this one was being handled, this disposition will get written
  116. // on the wrong record. Oh well.
  117. if (RtlpExceptionLog) {
  118. RtlpExceptionLog[LogIndex].Disposition = Disposition;
  119. }
  120. }
  121. LONG
  122. NTAPI
  123. RtlUnhandledExceptionFilter(
  124. IN struct _EXCEPTION_POINTERS *ExceptionInfo
  125. )
  126. {
  127. return RtlUnhandledExceptionFilter2(ExceptionInfo, "");
  128. }
  129. LONG
  130. NTAPI
  131. RtlUnhandledExceptionFilter2(
  132. IN struct _EXCEPTION_POINTERS *ExceptionInfo,
  133. IN CONST CHAR* Function
  134. )
  135. /*++
  136. Routine Description:
  137. Default exception handler that prints info and does a DbgBreak if
  138. a debugger is attached to the machine.
  139. Arguments:
  140. ExceptionInfo - Structure containing the exception and context records
  141. Function - the function containing the __except, such as returned by __FUNCTION__
  142. Returns:
  143. EXCEPTION_CONTINUE_EXECUTION or EXCEPTION_CONTINUE_SEARCH
  144. --*/
  145. {
  146. LPCWSTR lpProcessName = NtCurrentPeb()->ProcessParameters->CommandLine.Buffer;
  147. BOOLEAN DebuggerPresent = NtCurrentPeb()->BeingDebugged;
  148. if (!DebuggerPresent)
  149. {
  150. SYSTEM_KERNEL_DEBUGGER_INFORMATION KdInfo = { 0 };
  151. NtQuerySystemInformation(
  152. SystemKernelDebuggerInformation,
  153. &KdInfo,
  154. sizeof(KdInfo),
  155. NULL);
  156. DebuggerPresent = KdInfo.KernelDebuggerEnabled;
  157. }
  158. if (DebuggerPresent)
  159. {
  160. switch ( ExceptionInfo->ExceptionRecord->ExceptionCode )
  161. {
  162. case STATUS_POSSIBLE_DEADLOCK:
  163. {
  164. PRTL_CRITICAL_SECTION CritSec;
  165. PRTL_CRITICAL_SECTION_DEBUG CritSecDebug;
  166. CritSec = (PRTL_CRITICAL_SECTION)
  167. ExceptionInfo->ExceptionRecord->ExceptionInformation[ 0 ];
  168. if ( CritSec )
  169. {
  170. try
  171. {
  172. CritSecDebug = CritSec->DebugInfo ;
  173. if ( CritSecDebug->Type == RTL_RESOURCE_TYPE )
  174. {
  175. PRTL_RESOURCE Resource = (PRTL_RESOURCE) CritSec;
  176. DbgPrint("\n\n *** Resource timeout (%p) in %ws:%s\n\n",
  177. Resource, lpProcessName, Function );
  178. if ( Resource->NumberOfActive < 0 )
  179. {
  180. DbgPrint("The resource is owned exclusively by thread %x\n",
  181. Resource->ExclusiveOwnerThread);
  182. }
  183. else if ( Resource->NumberOfActive > 0 )
  184. {
  185. DbgPrint("The resource is owned shared by %d threads\n",
  186. Resource->NumberOfActive);
  187. }
  188. else
  189. {
  190. DbgPrint("The resource is unowned. This usually implies a "
  191. "slow-moving machine due to memory pressure\n\n");
  192. }
  193. }
  194. else
  195. {
  196. DbgPrint("\n\n *** Critical Section Timeout (%p) in %ws:%s\n\n",
  197. CritSec, lpProcessName, Function );
  198. if (CritSec->OwningThread != 0)
  199. {
  200. DbgPrint("The critical section is owned by thread %x.\n",
  201. CritSec->OwningThread );
  202. DbgPrint("Go determine why that thread has not released "
  203. "the critical section.\n\n" );
  204. }
  205. else
  206. {
  207. DbgPrint("The critical section is unowned. This "
  208. "usually implies a slow-moving machine "
  209. "due to memory pressure\n\n");
  210. }
  211. }
  212. }
  213. except( EXCEPTION_EXECUTE_HANDLER )
  214. {
  215. NOTHING ;
  216. }
  217. }
  218. break;
  219. }
  220. case STATUS_IN_PAGE_ERROR:
  221. DbgPrint("\n\n *** Inpage error in %ws:%s\n\n", lpProcessName, Function );
  222. DbgPrint("The instruction at %p referenced memory at %p.\n",
  223. ExceptionInfo->ExceptionRecord->ExceptionAddress,
  224. ExceptionInfo->ExceptionRecord->ExceptionInformation[1]);
  225. DbgPrint("This failed because of error %x.\n\n",
  226. ExceptionInfo->ExceptionRecord->ExceptionInformation[2]);
  227. switch (ExceptionInfo->ExceptionRecord->ExceptionInformation[2])
  228. {
  229. case STATUS_INSUFFICIENT_RESOURCES:
  230. DbgPrint("This means the machine is out of memory. Use !vm "
  231. "to see where all the memory is being used.\n\n");
  232. break;
  233. case STATUS_DEVICE_DATA_ERROR:
  234. case STATUS_DISK_OPERATION_FAILED:
  235. DbgPrint("This means the data could not be read, typically because "
  236. "of a bad block on the disk. Check your hardware.\n\n");
  237. break;
  238. case STATUS_IO_DEVICE_ERROR:
  239. DbgPrint("This means that the I/O device reported an I/O error. "
  240. "Check your hardware.");
  241. break;
  242. }
  243. break;
  244. case STATUS_ACCESS_VIOLATION:
  245. DbgPrint("\n\n *** An Access Violation occurred in %ws:%s\n\n", lpProcessName, Function );
  246. DbgPrint("The instruction at %p tried to %s ",
  247. ExceptionInfo->ExceptionRecord->ExceptionAddress,
  248. ExceptionInfo->ExceptionRecord->ExceptionInformation[0] ?
  249. "write to" : "read from" );
  250. if ( ExceptionInfo->ExceptionRecord->ExceptionInformation[1] )
  251. {
  252. DbgPrint("an invalid address, %p\n\n",
  253. ExceptionInfo->ExceptionRecord->ExceptionInformation[1] );
  254. }
  255. else
  256. {
  257. DbgPrint("a NULL pointer\n\n" );
  258. }
  259. break;
  260. default:
  261. DbgPrint("\n\n *** Unhandled exception 0x%08lx, hit in %ws:%s\n\n", ExceptionInfo->ExceptionRecord->ExceptionCode, lpProcessName, Function);
  262. }
  263. DbgPrint(" *** enter .exr %p for the exception record\n",
  264. ExceptionInfo->ExceptionRecord);
  265. DbgPrint(" *** enter .cxr %p for the context\n",
  266. ExceptionInfo->ContextRecord);
  267. //
  268. // .cxr <foo> now changes the debugger state so kb
  269. // will do the trick (vs. !kb previously)
  270. //
  271. DbgPrint(" *** then kb to get the faulting stack\n\n");
  272. DbgBreakPoint();
  273. }
  274. if (ExceptionInfo->ExceptionRecord->ExceptionCode == STATUS_POSSIBLE_DEADLOCK)
  275. {
  276. if (DebuggerPresent)
  277. {
  278. DbgPrint(" *** Restarting wait on critsec or resource at %p (in %ws:%s)\n\n",
  279. ExceptionInfo->ExceptionRecord->ExceptionInformation[0],
  280. lpProcessName,
  281. Function);
  282. }
  283. return EXCEPTION_CONTINUE_EXECUTION;
  284. }
  285. return EXCEPTION_CONTINUE_SEARCH;
  286. }