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.

549 lines
17 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. #define UNICODE 1
  12. #define _UNICODE 1
  13. #include "resmonp.h"
  14. #include "dbghelp.h"
  15. // Make typedefs for some dbghelp.DLL functions so that we can use them
  16. // with GetProcAddress
  17. typedef BOOL (__stdcall * SYMINITIALIZEPROC)( HANDLE, LPSTR, BOOL );
  18. typedef BOOL (__stdcall *SYMCLEANUPPROC)( HANDLE );
  19. typedef BOOL (__stdcall * STACKWALKPROC)
  20. ( DWORD, HANDLE, HANDLE, LPSTACKFRAME, LPVOID,
  21. PREAD_PROCESS_MEMORY_ROUTINE,
  22. PFUNCTION_TABLE_ACCESS_ROUTINE,
  23. PGET_MODULE_BASE_ROUTINE, PTRANSLATE_ADDRESS_ROUTINE );
  24. typedef LPVOID (__stdcall *SYMFUNCTIONTABLEACCESSPROC)( HANDLE, ULONG_PTR );
  25. typedef ULONG_PTR (__stdcall *SYMGETMODULEBASEPROC)( HANDLE, ULONG_PTR );
  26. typedef BOOL (__stdcall *SYMGETSYMFROMADDRPROC)
  27. ( HANDLE, ULONG_PTR, PULONG_PTR, PIMAGEHLP_SYMBOL );
  28. typedef BOOL (__stdcall *SYMFROMADDRPROC)
  29. ( HANDLE, DWORD64, PDWORD64, PSYMBOL_INFO );
  30. typedef BOOL (__stdcall *MINIDUMPWRITEDUMP)
  31. ( HANDLE, DWORD, HANDLE, MINIDUMP_TYPE,
  32. PMINIDUMP_EXCEPTION_INFORMATION,
  33. PMINIDUMP_USER_STREAM_INFORMATION,
  34. PMINIDUMP_CALLBACK_INFORMATION );
  35. SYMINITIALIZEPROC _SymInitialize = 0;
  36. SYMCLEANUPPROC _SymCleanup = 0;
  37. STACKWALKPROC _StackWalk = 0;
  38. SYMFUNCTIONTABLEACCESSPROC _SymFunctionTableAccess = 0;
  39. SYMGETMODULEBASEPROC _SymGetModuleBase = 0;
  40. SYMGETSYMFROMADDRPROC _SymGetSymFromAddr = 0;
  41. SYMFROMADDRPROC _SymFromAddr = 0;
  42. MINIDUMPWRITEDUMP _MiniDumpWriteDump = NULL;
  43. //local prototypes for forward use
  44. BOOL InitImagehlpFunctions();
  45. void ImagehlpStackWalk( IN PCONTEXT pContext );
  46. BOOL GetLogicalAddress(
  47. IN PVOID addr,
  48. OUT LPWSTR szModule,
  49. IN DWORD len,
  50. OUT LPDWORD section,
  51. OUT PULONG_PTR offset );
  52. VOID
  53. GenerateMemoryDump(
  54. IN PEXCEPTION_POINTERS pExceptionInfo
  55. );
  56. VOID
  57. DumpCriticalSection(
  58. IN PCRITICAL_SECTION CriticalSection
  59. )
  60. /*++
  61. Routine Description:
  62. Inputs:
  63. Outputs:
  64. --*/
  65. {
  66. DWORD status;
  67. ClRtlLogPrint(LOG_CRITICAL, "[RM] Dumping Critical Section at %1!08LX!\n",
  68. CriticalSection );
  69. try {
  70. if ( CriticalSection->LockCount == -1 ) {
  71. ClRtlLogPrint(LOG_CRITICAL, " LockCount NOT LOCKED\n" );
  72. } else {
  73. ClRtlLogPrint(LOG_CRITICAL, " LockCount %1!u!\n",
  74. CriticalSection->LockCount );
  75. }
  76. ClRtlLogPrint(LOG_CRITICAL, " RecursionCount %1!x!\n",
  77. CriticalSection->RecursionCount );
  78. ClRtlLogPrint(LOG_CRITICAL, " OwningThread %1!x!\n",
  79. CriticalSection->OwningThread );
  80. ClRtlLogPrint(LOG_CRITICAL, " EntryCount %1!x!\n",
  81. CriticalSection->DebugInfo->EntryCount );
  82. ClRtlLogPrint(LOG_CRITICAL, " ContentionCount %1!x!\n\n",
  83. CriticalSection->DebugInfo->ContentionCount );
  84. } except ( EXCEPTION_EXECUTE_HANDLER ) {
  85. status = GetExceptionCode();
  86. ClRtlLogPrint(LOG_CRITICAL, "[RM] Exception %1!lx! occurred while dumping critsec\n\n",
  87. status );
  88. }
  89. } // DumpCriticalSection
  90. VOID
  91. GenerateMemoryDump(
  92. IN PEXCEPTION_POINTERS pExceptionInfo
  93. )
  94. /*++
  95. Routine Description:
  96. Generates a memory dump for the resource monitor process.
  97. Arguments:
  98. pExceptionInfo - Supplies the exception information
  99. Return Value:
  100. None.
  101. --*/
  102. {
  103. DWORD dwStatus = ERROR_SUCCESS;
  104. WCHAR szFileName[ MAX_PATH + RTL_NUMBER_OF ( RM_DMP_FILE_NAME ) + 1 ];
  105. HANDLE hDumpFile = INVALID_HANDLE_VALUE;
  106. MINIDUMP_EXCEPTION_INFORMATION mdumpExceptionInfo;
  107. if ( !_MiniDumpWriteDump )
  108. {
  109. dwStatus = ERROR_INVALID_PARAMETER;
  110. ClRtlLogPrint(LOG_CRITICAL, "[RM] GenerateMemoryDump: _MiniDumpWriteDump fn ptr is invalid, Status=%1!u!\n",
  111. dwStatus);
  112. goto FnExit;
  113. }
  114. dwStatus = ClRtlGetClusterDirectory( szFileName, RTL_NUMBER_OF ( szFileName ) );
  115. if ( dwStatus != ERROR_SUCCESS )
  116. {
  117. ClRtlLogPrint(LOG_CRITICAL, "[RM] GenerateMemoryDump: Could not get cluster dir, Status=%1!u!\n",
  118. dwStatus);
  119. goto FnExit;
  120. }
  121. wcsncat( szFileName,
  122. RM_DMP_FILE_NAME,
  123. RTL_NUMBER_OF ( szFileName ) -
  124. ( wcslen ( szFileName ) + 1 ) );
  125. szFileName [ RTL_NUMBER_OF ( szFileName ) - 1 ] = UNICODE_NULL;
  126. hDumpFile = CreateFile( szFileName,
  127. GENERIC_WRITE,
  128. 0,
  129. NULL,
  130. OPEN_ALWAYS,
  131. 0,
  132. NULL );
  133. if ( hDumpFile == INVALID_HANDLE_VALUE )
  134. {
  135. dwStatus = GetLastError ();
  136. ClRtlLogPrint(LOG_CRITICAL, "[RM] GenerateMemoryDump: Could not create file %1!ws!, Status=%2!u!\n",
  137. szFileName,
  138. dwStatus);
  139. goto FnExit;
  140. }
  141. mdumpExceptionInfo.ThreadId = GetCurrentThreadId ();
  142. mdumpExceptionInfo.ExceptionPointers = pExceptionInfo;
  143. mdumpExceptionInfo.ClientPointers = TRUE;
  144. ClRtlLogPrint(LOG_NOISE, "[RM] GenerateMemoryDump: Start memory dump to file %1!ws!\n",
  145. szFileName);
  146. if( !_MiniDumpWriteDump( GetCurrentProcess(),
  147. GetCurrentProcessId(),
  148. hDumpFile,
  149. MiniDumpNormal | MiniDumpWithHandleData,
  150. &mdumpExceptionInfo,
  151. NULL,
  152. NULL ) )
  153. {
  154. dwStatus = GetLastError ();
  155. ClRtlLogPrint(LOG_CRITICAL, "[CS] GenerateMemoryDump: Could not write dump, Status=%1!u!\n",
  156. dwStatus);
  157. goto FnExit;
  158. }
  159. FnExit:
  160. if ( hDumpFile != INVALID_HANDLE_VALUE ) CloseHandle ( hDumpFile );
  161. ClRtlLogPrint(LOG_NOISE, "[RM] GenerateMemoryDump: Memory dump status %1!u!\n",
  162. dwStatus);
  163. return;
  164. }// GenerateMemoryDump
  165. void GenerateExceptionReport(
  166. IN PEXCEPTION_POINTERS pExceptionInfo)
  167. /*++
  168. Routine Description:
  169. Top level exception handler for the cluster service process.
  170. Currently this just exits immediately and assumes that the
  171. cluster proxy will notice and restart us as appropriate.
  172. Arguments:
  173. ExceptionInfo - Supplies the exception information
  174. Return Value:
  175. None.
  176. --*/
  177. {
  178. PCONTEXT pCtxt = pExceptionInfo->ContextRecord;
  179. if ( !InitImagehlpFunctions() )
  180. {
  181. ClRtlLogPrint(LOG_CRITICAL, "[RM] Dbghelp.dll or its exported procs not found\r\n");
  182. #if 0
  183. #ifdef _M_IX86 // Intel Only!
  184. // Walk the stack using x86 specific code
  185. IntelStackWalk( pCtx );
  186. #endif
  187. #endif
  188. return;
  189. }
  190. GenerateMemoryDump ( pExceptionInfo );
  191. ImagehlpStackWalk( pCtxt );
  192. _SymCleanup( GetCurrentProcess() );
  193. }
  194. BOOL InitImagehlpFunctions()
  195. /*++
  196. Routine Description:
  197. Initializes the imagehlp functions/data.
  198. Arguments:
  199. None.
  200. Return Value:
  201. None.
  202. --*/
  203. {
  204. HMODULE hModImagehlp = LoadLibraryW( L"DBGHELP.DLL" );
  205. if ( !hModImagehlp )
  206. return FALSE;
  207. _SymInitialize = (SYMINITIALIZEPROC)GetProcAddress( hModImagehlp,
  208. "SymInitialize" );
  209. if ( !_SymInitialize )
  210. return FALSE;
  211. _SymCleanup = (SYMCLEANUPPROC)GetProcAddress( hModImagehlp, "SymCleanup" );
  212. if ( !_SymCleanup )
  213. return FALSE;
  214. _StackWalk = (STACKWALKPROC)GetProcAddress( hModImagehlp, "StackWalk" );
  215. if ( !_StackWalk )
  216. return FALSE;
  217. _SymFunctionTableAccess = (SYMFUNCTIONTABLEACCESSPROC)
  218. GetProcAddress( hModImagehlp, "SymFunctionTableAccess" );
  219. if ( !_SymFunctionTableAccess )
  220. return FALSE;
  221. _SymGetModuleBase=(SYMGETMODULEBASEPROC)GetProcAddress( hModImagehlp,
  222. "SymGetModuleBase");
  223. if ( !_SymGetModuleBase )
  224. return FALSE;
  225. _SymGetSymFromAddr=(SYMGETSYMFROMADDRPROC)GetProcAddress( hModImagehlp,
  226. "SymGetSymFromAddr" );
  227. if ( !_SymGetSymFromAddr )
  228. return FALSE;
  229. _SymFromAddr=(SYMFROMADDRPROC)GetProcAddress( hModImagehlp,
  230. "SymFromAddr" );
  231. if ( !_SymFromAddr )
  232. return FALSE;
  233. _MiniDumpWriteDump = (MINIDUMPWRITEDUMP)GetProcAddress( hModImagehlp,
  234. "MiniDumpWriteDump" );
  235. if ( !_MiniDumpWriteDump )
  236. return FALSE;
  237. // Set the current directory so that the symbol handler functions will pick up any PDBs that happen to be in
  238. // the cluster dir.
  239. // No need to save and restore the previous current dir since we will be dying after this.
  240. {
  241. WCHAR currentDir[ MAX_PATH + 1 ];
  242. UINT windirLen = GetWindowsDirectory( currentDir, MAX_PATH );
  243. if ( windirLen != 0 && windirLen <= MAX_PATH - wcslen( L"\\Cluster" ) )
  244. {
  245. wcscat( currentDir, L"\\Cluster" );
  246. if ( !SetCurrentDirectory( currentDir ))
  247. {
  248. ClRtlLogPrint( LOG_CRITICAL, "Failed to set current directory to %1!ws!, error %2!d!\n", currentDir, GetLastError() );
  249. }
  250. }
  251. }
  252. if ( !_SymInitialize( GetCurrentProcess(), NULL, TRUE ) )
  253. return FALSE;
  254. return TRUE;
  255. } // InitImagehlpFunctions
  256. void ImagehlpStackWalk(
  257. IN PCONTEXT pContext )
  258. /*++
  259. Routine Description:
  260. Walks the stack, and writes the results to the report file
  261. Arguments:
  262. ExceptionInfo - Supplies the exception information
  263. Return Value:
  264. None.
  265. --*/
  266. {
  267. STACKFRAME sf;
  268. BYTE symbolBuffer[ sizeof(IMAGEHLP_SYMBOL) + 512 ];
  269. PSYMBOL_INFO pSymbol = (PSYMBOL_INFO)symbolBuffer;
  270. DWORD64 symDisplacement = 0; // Displacement of the input address,
  271. // relative to the start of the symbol
  272. DWORD dwMachineType;
  273. UCHAR printBuffer[512];
  274. DWORD nextPrtBufChar;
  275. ClRtlLogPrint(LOG_CRITICAL,
  276. "[RM] CallStack:\n");
  277. ClRtlLogPrint(LOG_CRITICAL,
  278. "[RM] Frame Address\n");
  279. // Could use SymSetOptions here to add the SYMOPT_DEFERRED_LOADS flag
  280. memset( &sf, 0, sizeof(sf) );
  281. #if defined (_M_IX86)
  282. dwMachineType = IMAGE_FILE_MACHINE_I386;
  283. sf.AddrPC.Offset = pContext->Eip;
  284. sf.AddrPC.Mode = AddrModeFlat;
  285. sf.AddrStack.Offset = pContext->Esp;
  286. sf.AddrStack.Mode = AddrModeFlat;
  287. sf.AddrFrame.Offset = pContext->Ebp;
  288. sf.AddrFrame.Mode = AddrModeFlat;
  289. #elif defined(_M_AMD64)
  290. dwMachineType = IMAGE_FILE_MACHINE_AMD64;
  291. sf.AddrPC.Offset = pContext->Rip;
  292. sf.AddrPC.Mode = AddrModeFlat;
  293. sf.AddrStack.Offset = pContext->Rsp;
  294. sf.AddrStack.Mode = AddrModeFlat;
  295. #elif defined(_M_IA64)
  296. dwMachineType = IMAGE_FILE_MACHINE_IA64;
  297. sf.AddrPC.Offset = pContext->StIIP;
  298. sf.AddrPC.Mode = AddrModeFlat;
  299. sf.AddrStack.Offset = pContext->IntSp;
  300. sf.AddrStack.Mode = AddrModeFlat;
  301. #else
  302. #error "No Target Architecture"
  303. #endif // defined(_M_IX86)
  304. while ( 1 )
  305. {
  306. if ( ! _StackWalk( dwMachineType,
  307. GetCurrentProcess(),
  308. GetCurrentThread(),
  309. &sf,
  310. pContext,
  311. 0,
  312. _SymFunctionTableAccess,
  313. _SymGetModuleBase,
  314. 0 ) )
  315. break;
  316. if ( 0 == sf.AddrFrame.Offset ) // Basic sanity check to make sure
  317. break; // the frame is OK. Bail if not.
  318. nextPrtBufChar = _snprintf(printBuffer,
  319. sizeof(printBuffer),
  320. " %p %p ",
  321. sf.AddrFrame.Offset, sf.AddrPC.Offset );
  322. // IMAGEHLP is wacky, and requires you to pass in a pointer to an
  323. // IMAGEHLP_SYMBOL structure. The problem is that this structure is
  324. // variable length. That is, you determine how big the structure is
  325. // at runtime. This means that you can't use sizeof(struct).
  326. // So...make a buffer that's big enough, and make a pointer
  327. // to the buffer. We also need to initialize not one, but TWO
  328. // members of the structure before it can be used.
  329. pSymbol->SizeOfStruct = sizeof(symbolBuffer);
  330. pSymbol->MaxNameLen = 512;
  331. if ( _SymFromAddr(GetCurrentProcess(), sf.AddrPC.Offset,
  332. &symDisplacement, pSymbol) )
  333. {
  334. sprintf(printBuffer+nextPrtBufChar,
  335. "%hs+%p\n",
  336. pSymbol->Name, symDisplacement);
  337. }
  338. else // No symbol found. Print out the logical address instead.
  339. {
  340. WCHAR szModule[MAX_PATH] = L"";
  341. DWORD section = 0;
  342. ULONG_PTR offset = 0;
  343. GetLogicalAddress( (PVOID)sf.AddrPC.Offset,
  344. szModule, sizeof(szModule)/sizeof(WCHAR),
  345. &section, &offset );
  346. sprintf(printBuffer+nextPrtBufChar,
  347. "%04X:%08p %S\n",
  348. section, offset, szModule );
  349. }
  350. ClRtlLogPrint(LOG_CRITICAL, "%1!hs!", printBuffer);
  351. }
  352. }
  353. BOOL GetLogicalAddress(
  354. IN PVOID addr,
  355. OUT LPWSTR szModule,
  356. IN DWORD len,
  357. OUT LPDWORD section,
  358. OUT PULONG_PTR offset )
  359. /*++
  360. Routine Description:
  361. Given a linear address, locates the module, section, and offset containing
  362. that address.
  363. Note: the szModule paramater buffer is an output buffer of length specified
  364. by the len parameter (in characters!)
  365. Arguments:
  366. ExceptionInfo - Supplies the exception information
  367. Return Value:
  368. None.
  369. --*/
  370. {
  371. MEMORY_BASIC_INFORMATION mbi;
  372. ULONG_PTR hMod;
  373. // Point to the DOS header in memory
  374. PIMAGE_DOS_HEADER pDosHdr;
  375. // From the DOS header, find the NT (PE) header
  376. PIMAGE_NT_HEADERS pNtHdr;
  377. PIMAGE_SECTION_HEADER pSection;
  378. ULONG_PTR rva ;
  379. int i;
  380. if ( !VirtualQuery( addr, &mbi, sizeof(mbi) ) )
  381. return FALSE;
  382. hMod = (ULONG_PTR)mbi.AllocationBase;
  383. if ( !GetModuleFileName( (HMODULE)hMod, szModule, len ) )
  384. return FALSE;
  385. rva = (ULONG_PTR)addr - hMod; // RVA is offset from module load address
  386. pDosHdr = (PIMAGE_DOS_HEADER)hMod;
  387. pNtHdr = (PIMAGE_NT_HEADERS)(hMod + pDosHdr->e_lfanew);
  388. pSection = IMAGE_FIRST_SECTION( pNtHdr );
  389. // Iterate through the section table, looking for the one that encompasses
  390. // the linear address.
  391. for ( i = 0; i < pNtHdr->FileHeader.NumberOfSections;
  392. i++, pSection++ )
  393. {
  394. ULONG_PTR sectionStart = pSection->VirtualAddress;
  395. ULONG_PTR sectionEnd = sectionStart
  396. + max(pSection->SizeOfRawData, pSection->Misc.VirtualSize);
  397. // Is the address in this section???
  398. if ( (rva >= sectionStart) && (rva <= sectionEnd) )
  399. {
  400. // Yes, address is in the section. Calculate section and offset,
  401. // and store in the "section" & "offset" params, which were
  402. // passed by reference.
  403. *section = i+1;
  404. *offset = rva - sectionStart;
  405. return TRUE;
  406. }
  407. }
  408. return FALSE; // Should never get here!
  409. }