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.

352 lines
9.7 KiB

  1. /*++
  2. Copyright (c) 1996 Microsoft Corporation
  3. Module Name:
  4. excprt.c
  5. Abstract:
  6. This module uses imagehlp.dll to dump the stack when an exception occurs.
  7. Author:
  8. Sunita Shrivastava(sunitas) 11/5/1997
  9. Revision History:
  10. --*/
  11. #include "initp.h"
  12. #include "dbghelp.h"
  13. // Make typedefs for some IMAGEHLP.DLL functions so that we can use them
  14. // with GetProcAddress
  15. typedef BOOL (__stdcall * SYMINITIALIZEPROC)( HANDLE, LPSTR, BOOL );
  16. typedef BOOL (__stdcall *SYMCLEANUPPROC)( HANDLE );
  17. typedef BOOL (__stdcall * STACKWALKPROC)
  18. ( DWORD, HANDLE, HANDLE, LPSTACKFRAME, LPVOID,
  19. PREAD_PROCESS_MEMORY_ROUTINE,
  20. PFUNCTION_TABLE_ACCESS_ROUTINE,
  21. PGET_MODULE_BASE_ROUTINE, PTRANSLATE_ADDRESS_ROUTINE );
  22. typedef LPVOID (__stdcall *SYMFUNCTIONTABLEACCESSPROC)( HANDLE, ULONG_PTR );
  23. typedef ULONG_PTR (__stdcall *SYMGETMODULEBASEPROC)( HANDLE, ULONG_PTR );
  24. typedef BOOL (__stdcall *SYMGETSYMFROMADDRPROC)
  25. ( HANDLE, ULONG_PTR, PULONG_PTR, PIMAGEHLP_SYMBOL );
  26. SYMINITIALIZEPROC _SymInitialize = 0;
  27. SYMCLEANUPPROC _SymCleanup = 0;
  28. STACKWALKPROC _StackWalk = 0;
  29. SYMFUNCTIONTABLEACCESSPROC _SymFunctionTableAccess = 0;
  30. SYMGETMODULEBASEPROC _SymGetModuleBase = 0;
  31. SYMGETSYMFROMADDRPROC _SymGetSymFromAddr = 0;
  32. //local prototypes for forward use
  33. BOOL InitImagehlpFunctions();
  34. void ImagehlpStackWalk( IN PCONTEXT pContext );
  35. BOOL GetLogicalAddress(
  36. IN PVOID addr,
  37. OUT LPWSTR szModule,
  38. IN DWORD len,
  39. OUT LPDWORD section,
  40. OUT PULONG_PTR offset );
  41. void GenerateExceptionReport(
  42. IN PEXCEPTION_POINTERS pExceptionInfo)
  43. /*++
  44. Routine Description:
  45. Top level exception handler for the cluster service process.
  46. Currently this just exits immediately and assumes that the
  47. cluster proxy will notice and restart us as appropriate.
  48. Arguments:
  49. ExceptionInfo - Supplies the exception information
  50. Return Value:
  51. None.
  52. --*/
  53. {
  54. PCONTEXT pCtxt = pExceptionInfo->ContextRecord;
  55. if ( !InitImagehlpFunctions() )
  56. {
  57. ClRtlLogPrint(LOG_CRITICAL,
  58. "[CS] Dbghelp.dll or its exported procs not found\r\n");
  59. #if 0
  60. #ifdef _M_IX86 // Intel Only!
  61. // Walk the stack using x86 specific code
  62. IntelStackWalk( pCtx );
  63. #endif
  64. #endif
  65. return;
  66. }
  67. ImagehlpStackWalk( pCtxt );
  68. _SymCleanup( GetCurrentProcess() );
  69. }
  70. BOOL InitImagehlpFunctions()
  71. /*++
  72. Routine Description:
  73. Initializes the imagehlp functions/data.
  74. Arguments:
  75. None.
  76. Return Value:
  77. None.
  78. --*/
  79. {
  80. HMODULE hModImagehlp = LoadLibraryW( L"DBGHELP.DLL" );
  81. if ( !hModImagehlp )
  82. return FALSE;
  83. _SymInitialize = (SYMINITIALIZEPROC)GetProcAddress( hModImagehlp,
  84. "SymInitialize" );
  85. if ( !_SymInitialize )
  86. return FALSE;
  87. _SymCleanup = (SYMCLEANUPPROC)GetProcAddress( hModImagehlp, "SymCleanup" );
  88. if ( !_SymCleanup )
  89. return FALSE;
  90. _StackWalk = (STACKWALKPROC)GetProcAddress( hModImagehlp, "StackWalk" );
  91. if ( !_StackWalk )
  92. return FALSE;
  93. _SymFunctionTableAccess = (SYMFUNCTIONTABLEACCESSPROC)
  94. GetProcAddress( hModImagehlp, "SymFunctionTableAccess" );
  95. if ( !_SymFunctionTableAccess )
  96. return FALSE;
  97. _SymGetModuleBase=(SYMGETMODULEBASEPROC)GetProcAddress( hModImagehlp,
  98. "SymGetModuleBase");
  99. if ( !_SymGetModuleBase )
  100. return FALSE;
  101. _SymGetSymFromAddr=(SYMGETSYMFROMADDRPROC)GetProcAddress( hModImagehlp,
  102. "SymGetSymFromAddr" );
  103. if ( !_SymGetSymFromAddr )
  104. return FALSE;
  105. if ( !_SymInitialize( GetCurrentProcess(), 0, TRUE ) )
  106. return FALSE;
  107. return TRUE;
  108. }
  109. void ImagehlpStackWalk(
  110. IN PCONTEXT pContext )
  111. /*++
  112. Routine Description:
  113. Walks the stack, and writes the results to the report file
  114. Arguments:
  115. ExceptionInfo - Supplies the exception information
  116. Return Value:
  117. None.
  118. --*/
  119. {
  120. STACKFRAME sf;
  121. BYTE symbolBuffer[ sizeof(IMAGEHLP_SYMBOL) + 512 ];
  122. PIMAGEHLP_SYMBOL pSymbol = (PIMAGEHLP_SYMBOL)symbolBuffer;
  123. ULONG_PTR symDisplacement = 0; // Displacement of the input address,
  124. // relative to the start of the symbol
  125. DWORD dwMachineType;
  126. UCHAR printBuffer[512];
  127. DWORD nextPrtBufChar;
  128. #if defined (_M_IX86)
  129. dwMachineType = IMAGE_FILE_MACHINE_I386;
  130. #else if defined(_M_ALPHA)
  131. dwMachineType = IMAGE_FILE_MACHINE_ALPHA;
  132. #endif
  133. ClRtlLogPrint(LOG_CRITICAL,
  134. "[CS] CallStack:\r\n");
  135. ClRtlLogPrint(LOG_CRITICAL,
  136. "[CS] Frame Address\r\n");
  137. // Could use SymSetOptions here to add the SYMOPT_DEFERRED_LOADS flag
  138. memset( &sf, 0, sizeof(sf) );
  139. #if defined (_M_IX86)
  140. // Initialize the STACKFRAME structure for the first call. This is only
  141. // necessary for Intel CPUs, and isn't mentioned in the documentation.
  142. sf.AddrPC.Offset = pContext->Eip;
  143. sf.AddrPC.Mode = AddrModeFlat;
  144. sf.AddrStack.Offset = pContext->Esp;
  145. sf.AddrStack.Mode = AddrModeFlat;
  146. sf.AddrFrame.Offset = pContext->Ebp;
  147. sf.AddrFrame.Mode = AddrModeFlat;
  148. #endif // _M_IX86
  149. while ( 1 )
  150. {
  151. if ( ! _StackWalk( dwMachineType,
  152. GetCurrentProcess(),
  153. GetCurrentThread(),
  154. &sf,
  155. pContext,
  156. 0,
  157. _SymFunctionTableAccess,
  158. _SymGetModuleBase,
  159. 0 ) )
  160. break;
  161. if ( 0 == sf.AddrFrame.Offset ) // Basic sanity check to make sure
  162. break; // the frame is OK. Bail if not.
  163. nextPrtBufChar = sprintf(printBuffer,
  164. " %08X %08X ",
  165. sf.AddrFrame.Offset, sf.AddrPC.Offset );
  166. // IMAGEHLP is wacky, and requires you to pass in a pointer to an
  167. // IMAGEHLP_SYMBOL structure. The problem is that this structure is
  168. // variable length. That is, you determine how big the structure is
  169. // at runtime. This means that you can't use sizeof(struct).
  170. // So...make a buffer that's big enough, and make a pointer
  171. // to the buffer. We also need to initialize not one, but TWO
  172. // members of the structure before it can be used.
  173. pSymbol->SizeOfStruct = sizeof(symbolBuffer);
  174. pSymbol->MaxNameLength = 512;
  175. if ( _SymGetSymFromAddr(GetCurrentProcess(), sf.AddrPC.Offset,
  176. &symDisplacement, pSymbol) )
  177. {
  178. sprintf(printBuffer+nextPrtBufChar,
  179. "%hs+%p\n",
  180. pSymbol->Name, symDisplacement);
  181. }
  182. else // No symbol found. Print out the logical address instead.
  183. {
  184. WCHAR szModule[MAX_PATH] = L"";
  185. DWORD section = 0;
  186. ULONG_PTR offset = 0;
  187. GetLogicalAddress( (PVOID)sf.AddrPC.Offset,
  188. szModule, sizeof(szModule)/sizeof(WCHAR),
  189. &section, &offset );
  190. sprintf(printBuffer+nextPrtBufChar,
  191. "%04X:%08p %s\n",
  192. section, offset, szModule );
  193. }
  194. ClRtlLogPrint(LOG_CRITICAL, "%1!hs!\n", printBuffer );
  195. }
  196. }
  197. BOOL GetLogicalAddress(
  198. IN PVOID addr,
  199. OUT LPWSTR szModule,
  200. IN DWORD len,
  201. OUT LPDWORD section,
  202. OUT PULONG_PTR offset )
  203. /*++
  204. Routine Description:
  205. Given a linear address, locates the module, section, and offset containing
  206. that address.
  207. Note: the szModule paramater buffer is an output buffer of length specified
  208. by the len parameter (in characters!)
  209. Arguments:
  210. ExceptionInfo - Supplies the exception information
  211. Return Value:
  212. None.
  213. --*/
  214. {
  215. MEMORY_BASIC_INFORMATION mbi;
  216. ULONG_PTR hMod;
  217. // Point to the DOS header in memory
  218. PIMAGE_DOS_HEADER pDosHdr;
  219. // From the DOS header, find the NT (PE) header
  220. PIMAGE_NT_HEADERS pNtHdr;
  221. PIMAGE_SECTION_HEADER pSection;
  222. ULONG_PTR rva ;
  223. int i;
  224. if ( !VirtualQuery( addr, &mbi, sizeof(mbi) ) )
  225. return FALSE;
  226. hMod = (ULONG_PTR)mbi.AllocationBase;
  227. if ( !GetModuleFileName( (HMODULE)hMod, szModule, len ) )
  228. return FALSE;
  229. rva = (ULONG_PTR)addr - hMod; // RVA is offset from module load address
  230. pDosHdr = (PIMAGE_DOS_HEADER)hMod;
  231. pNtHdr = (PIMAGE_NT_HEADERS)(hMod + pDosHdr->e_lfanew);
  232. pSection = IMAGE_FIRST_SECTION( pNtHdr );
  233. // Iterate through the section table, looking for the one that encompasses
  234. // the linear address.
  235. for ( i = 0; i < pNtHdr->FileHeader.NumberOfSections;
  236. i++, pSection++ )
  237. {
  238. ULONG_PTR sectionStart = pSection->VirtualAddress;
  239. ULONG_PTR sectionEnd = sectionStart
  240. + max(pSection->SizeOfRawData, pSection->Misc.VirtualSize);
  241. // Is the address in this section???
  242. if ( (rva >= sectionStart) && (rva <= sectionEnd) )
  243. {
  244. // Yes, address is in the section. Calculate section and offset,
  245. // and store in the "section" & "offset" params, which were
  246. // passed by reference.
  247. *section = i+1;
  248. *offset = rva - sectionStart;
  249. return TRUE;
  250. }
  251. }
  252. return FALSE; // Should never get here!
  253. }