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.

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