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.

1087 lines
29 KiB

  1. /*++
  2. Copyright (c) 1993-2001 Microsoft Corporation
  3. Module Name:
  4. debug.cpp
  5. Abstract:
  6. This file implements the debug module for drwatson. This module
  7. processes all debug events and generates the postmortem dump.
  8. Author:
  9. Wesley Witt (wesw) 1-May-1993
  10. Environment:
  11. User Mode
  12. --*/
  13. #include "pch.cpp"
  14. #define STATUS_POSSIBLE_DEADLOCK ((DWORD)0xC0000194L)
  15. #define STATUS_VDM_EVENT STATUS_SEGMENT_NOTIFICATION
  16. typedef struct tagSYSINFO {
  17. _TCHAR szUserName[MAX_PATH];
  18. _TCHAR szMachineName[MAX_PATH];
  19. } SYSINFO, *PSYSINFO;
  20. //----------------------------------------------------------------------------
  21. //
  22. // Log output callbacks.
  23. //
  24. //----------------------------------------------------------------------------
  25. class LogOutputCallbacks :
  26. public IDebugOutputCallbacks
  27. {
  28. public:
  29. // IUnknown.
  30. STDMETHOD(QueryInterface)(
  31. THIS_
  32. IN REFIID InterfaceId,
  33. OUT PVOID* Interface
  34. );
  35. STDMETHOD_(ULONG, AddRef)(
  36. THIS
  37. );
  38. STDMETHOD_(ULONG, Release)(
  39. THIS
  40. );
  41. // IDebugOutputCallbacks.
  42. STDMETHOD(Output)(
  43. THIS_
  44. IN ULONG Mask,
  45. IN PCSTR Text
  46. );
  47. };
  48. LogOutputCallbacks g_LogOutCb;
  49. STDMETHODIMP
  50. LogOutputCallbacks::QueryInterface(
  51. THIS_
  52. IN REFIID InterfaceId,
  53. OUT PVOID* Interface
  54. )
  55. {
  56. *Interface = NULL;
  57. if (IsEqualIID(InterfaceId, __uuidof(IUnknown)) ||
  58. IsEqualIID(InterfaceId, __uuidof(IDebugOutputCallbacks)))
  59. {
  60. *Interface = (IDebugOutputCallbacks *)this;
  61. AddRef();
  62. return S_OK;
  63. }
  64. else
  65. {
  66. return E_NOINTERFACE;
  67. }
  68. }
  69. STDMETHODIMP_(ULONG)
  70. LogOutputCallbacks::AddRef(
  71. THIS
  72. )
  73. {
  74. // This class is designed to be static so
  75. // there's no true refcount.
  76. return 1;
  77. }
  78. STDMETHODIMP_(ULONG)
  79. LogOutputCallbacks::Release(
  80. THIS
  81. )
  82. {
  83. // This class is designed to be static so
  84. // there's no true refcount.
  85. return 0;
  86. }
  87. STDMETHODIMP
  88. LogOutputCallbacks::Output(
  89. THIS_
  90. IN ULONG Mask,
  91. IN PCSTR Text
  92. )
  93. {
  94. PCSTR Scan;
  95. for (;;)
  96. {
  97. Scan = strchr(Text, '\n');
  98. if (Scan == NULL)
  99. {
  100. break;
  101. }
  102. lprintfs(_T("%.*hs\r\n"), (int)(Scan - Text), Text);
  103. Text = Scan + 1;
  104. }
  105. lprintfs(_T("%hs"), Text);
  106. return S_OK;
  107. }
  108. _TCHAR *
  109. GetExceptionText(
  110. DWORD dwExceptionCode
  111. )
  112. {
  113. static _TCHAR buf[80];
  114. DWORD dwFormatId = 0;
  115. memset( buf, 0, sizeof(buf) );
  116. switch (dwExceptionCode) {
  117. case STATUS_SINGLE_STEP:
  118. dwFormatId = MSG_SINGLE_STEP_EXCEPTION;
  119. break;
  120. case DBG_CONTROL_C:
  121. dwFormatId = MSG_CONTROLC_EXCEPTION;
  122. break;
  123. case DBG_CONTROL_BREAK:
  124. dwFormatId = MSG_CONTROL_BRK_EXCEPTION;
  125. break;
  126. case STATUS_ACCESS_VIOLATION:
  127. dwFormatId = MSG_ACCESS_VIOLATION_EXCEPTION;
  128. break;
  129. case STATUS_STACK_OVERFLOW:
  130. dwFormatId = MSG_STACK_OVERFLOW_EXCEPTION;
  131. break;
  132. case STATUS_INTEGER_DIVIDE_BY_ZERO:
  133. dwFormatId = MSG_INTEGER_DIVIDE_BY_ZERO_EXCEPTION;
  134. break;
  135. case STATUS_PRIVILEGED_INSTRUCTION:
  136. dwFormatId = MSG_PRIVILEGED_INSTRUCTION_EXCEPTION;
  137. break;
  138. case STATUS_ILLEGAL_INSTRUCTION:
  139. dwFormatId = MSG_ILLEGAL_INSTRUCTION_EXCEPTION;
  140. break;
  141. case STATUS_IN_PAGE_ERROR:
  142. dwFormatId = MSG_IN_PAGE_IO_EXCEPTION;
  143. break;
  144. case STATUS_DATATYPE_MISALIGNMENT:
  145. dwFormatId = MSG_DATATYPE_EXCEPTION;
  146. break;
  147. case STATUS_POSSIBLE_DEADLOCK:
  148. dwFormatId = MSG_DEADLOCK_EXCEPTION;
  149. break;
  150. case STATUS_VDM_EVENT:
  151. dwFormatId = MSG_VDM_EXCEPTION;
  152. break;
  153. case STATUS_BREAKPOINT:
  154. dwFormatId = MSG_BREAKPOINT_EXCEPTION;
  155. break;
  156. default:
  157. lprintfs( _T("\r\n") );
  158. break;
  159. }
  160. FormatMessage( FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_ARGUMENT_ARRAY,
  161. NULL,
  162. dwFormatId,
  163. MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
  164. buf,
  165. sizeof(buf) / sizeof(_TCHAR),
  166. NULL
  167. );
  168. return buf;
  169. }
  170. void
  171. CreateEngineInterfaces(
  172. PDEBUGPACKET dp
  173. )
  174. {
  175. HRESULT Status;
  176. if ((Status = DebugCreate(__uuidof(IDebugClient2),
  177. (void **)&dp->DbgClient)) != S_OK) {
  178. goto Error;
  179. }
  180. if ((Status = dp->DbgClient->
  181. QueryInterface(__uuidof(IDebugControl),
  182. (void **)&dp->DbgControl)) != S_OK ||
  183. (Status = dp->DbgClient->
  184. QueryInterface(__uuidof(IDebugDataSpaces),
  185. (void **)&dp->DbgData)) != S_OK ||
  186. (Status = dp->DbgClient->
  187. QueryInterface(__uuidof(IDebugRegisters),
  188. (void **)&dp->DbgRegisters)) != S_OK ||
  189. (Status = dp->DbgClient->
  190. QueryInterface(__uuidof(IDebugSymbols),
  191. (void **)&dp->DbgSymbols)) != S_OK ||
  192. (Status = dp->DbgClient->
  193. QueryInterface(__uuidof(IDebugSystemObjects),
  194. (void **)&dp->DbgSystem)) != S_OK) {
  195. goto Error;
  196. }
  197. if ((Status = dp->DbgSymbols->
  198. AddSymbolOptions(SYMOPT_FAIL_CRITICAL_ERRORS)) != S_OK ||
  199. (Status = dp->DbgControl->
  200. AddEngineOptions(DEBUG_ENGOPT_INITIAL_BREAK)) != S_OK ||
  201. (Status = dp->DbgControl->
  202. Execute(DEBUG_OUTCTL_IGNORE, "sxe et",
  203. DEBUG_EXECUTE_DEFAULT)) != S_OK) {
  204. goto Error;
  205. }
  206. return;
  207. Error:
  208. if (dp->options.fVisual) {
  209. FatalError( Status, LoadRcString(IDS_CANT_INIT_ENGINE) );
  210. }
  211. else {
  212. ExitProcess( 1 );
  213. }
  214. }
  215. void
  216. AttachToActiveProcess (
  217. PDEBUGPACKET dp
  218. )
  219. {
  220. HRESULT Status;
  221. if ((Status = dp->DbgClient->
  222. AttachProcess(0, dp->dwPidToDebug, DEBUG_ATTACH_DEFAULT)) != S_OK) {
  223. if (dp->options.fVisual) {
  224. FatalError( Status, LoadRcString(IDS_ATTACHFAIL) );
  225. }
  226. else {
  227. ExitProcess( 1 );
  228. }
  229. }
  230. return;
  231. }
  232. DWORD
  233. SysInfoThread(
  234. PSYSINFO si
  235. )
  236. {
  237. DWORD len;
  238. len = sizeof(si->szMachineName) / sizeof(_TCHAR);
  239. GetComputerName( si->szMachineName, &len );
  240. len = sizeof(si->szUserName) / sizeof(_TCHAR);
  241. GetUserName( si->szUserName, &len );
  242. return 0;
  243. }
  244. void
  245. LogSystemInformation(
  246. PDEBUGPACKET dp
  247. )
  248. {
  249. _TCHAR buf[1024];
  250. SYSTEM_INFO si;
  251. DWORD ver;
  252. SYSINFO mySi;
  253. SYSINFO* threadSi;
  254. DWORD dwThreadId;
  255. HANDLE hThread;
  256. DWORD TSid;
  257. lprintf( MSG_SYSINFO_HEADER );
  258. // Initialize default unknown values.
  259. _tcscpy( mySi.szMachineName, LoadRcString( IDS_UNKNOWN_MACHINE ) );
  260. _tcscpy( mySi.szUserName, LoadRcString( IDS_UNKNOWN_USER ) );
  261. // Attempt to get the actual values.
  262. // The storage passed to the get thread is not taken
  263. // from this thread's stack so that this function can exit
  264. // without leaving the other thread with stale stack pointers.
  265. threadSi = (SYSINFO*)malloc(sizeof(*threadSi));
  266. if (threadSi != NULL) {
  267. hThread = CreateThread( NULL,
  268. 16000,
  269. (LPTHREAD_START_ROUTINE)SysInfoThread,
  270. threadSi,
  271. 0,
  272. &dwThreadId
  273. );
  274. if (hThread != NULL) {
  275. // Let the thread run for a little while since
  276. // the get calls can be slow. If the thread doesn't
  277. // finish in the time allotted we'll just go ahead
  278. // with the default values and forget about the get thread.
  279. Sleep( 0 );
  280. if (WaitForSingleObject( hThread, 30000 ) == WAIT_OBJECT_0) {
  281. // Thread finished so we have the real values.
  282. _tcscpy(mySi.szMachineName, threadSi->szMachineName);
  283. _tcscpy(mySi.szUserName, threadSi->szUserName);
  284. free(threadSi);
  285. }
  286. CloseHandle( hThread );
  287. } else {
  288. free(threadSi);
  289. }
  290. }
  291. lprintf( MSG_SYSINFO_COMPUTER, mySi.szMachineName );
  292. lprintf( MSG_SYSINFO_USER, mySi.szUserName );
  293. ProcessIdToSessionId(dp->dwPidToDebug, &TSid);
  294. _stprintf( buf, _T("%d"), TSid );
  295. lprintf( MSG_SYSINFO_TERMINAL_SESSION, buf );
  296. GetSystemInfo( &si );
  297. _stprintf( buf, _T("%d"), si.dwNumberOfProcessors );
  298. lprintf( MSG_SYSINFO_NUM_PROC, buf );
  299. RegLogProcessorType();
  300. ver = GetVersion();
  301. _stprintf( buf, _T("%d.%d"), LOBYTE(LOWORD(ver)), HIBYTE(LOWORD(ver)) );
  302. lprintf( MSG_SYSINFO_WINVER, buf );
  303. RegLogCurrentVersion();
  304. lprintfs( _T("\r\n") );
  305. }
  306. void
  307. LogTaskList(
  308. PDEBUGPACKET dp
  309. )
  310. /*++
  311. Routine Description:
  312. This function gets the current task list and logs the process id &
  313. process name to the log file.
  314. --*/
  315. {
  316. HRESULT Status;
  317. #define MAX_IDS 8192
  318. PULONG Ids = NULL;
  319. ULONG IdCount;
  320. ULONG i;
  321. Ids = (PULONG)malloc(sizeof(*Ids) * MAX_IDS);
  322. if (Ids == NULL) {
  323. goto Error;
  324. }
  325. if ((Status = dp->DbgClient->
  326. GetRunningProcessSystemIds(0, Ids, MAX_IDS,
  327. &IdCount)) != S_OK) {
  328. goto Error;
  329. }
  330. if (IdCount > MAX_IDS) {
  331. // Incomplete process list is good enough.
  332. IdCount = MAX_IDS;
  333. }
  334. lprintf( MSG_TASK_LIST );
  335. for (i = 0; i < IdCount; i++) {
  336. char ExeName[MAX_PATH];
  337. if ((Status = dp->DbgClient->
  338. GetRunningProcessDescription(0, Ids[i],
  339. DEBUG_PROC_DESC_NO_PATHS,
  340. ExeName, sizeof(ExeName),
  341. NULL, NULL, 0, NULL)) != S_OK) {
  342. lprintfs(_T("%4d Error 0x%08X\r\n"), Ids[i], Status);
  343. } else {
  344. lprintfs(_T("%4d %hs\r\n"), Ids[i], ExeName);
  345. }
  346. }
  347. lprintfs( _T("\r\n") );
  348. free(Ids);
  349. return;
  350. Error:
  351. _tprintf( _T("ERROR: could not get the task list\n") );
  352. free(Ids);
  353. }
  354. void
  355. LogModuleList(
  356. PDEBUGPACKET dp
  357. )
  358. {
  359. HRESULT Status;
  360. ULONG NumMod;
  361. ULONG i;
  362. char Image[MAX_PATH];
  363. DEBUG_MODULE_PARAMETERS Params;
  364. lprintf( MSG_MODULE_LIST );
  365. if ((Status = dp->DbgSymbols->GetNumberModules(&NumMod, &i)) != S_OK) {
  366. lprintfs(_T("Error 0x%08X\r\n"), Status);
  367. return;
  368. }
  369. for (i = 0; i < NumMod; i++) {
  370. if ((Status = dp->DbgSymbols->
  371. GetModuleParameters(1, NULL, i, &Params)) != S_OK ||
  372. FAILED(Status = dp->DbgSymbols->
  373. GetModuleNames(i, 0, Image, sizeof(Image), NULL,
  374. NULL, 0, NULL, NULL, 0, NULL))) {
  375. lprintfs(_T("Error 0x%08X\r\n"), Status);
  376. } else {
  377. lprintfs(_T("(%016I64x - %016I64x: %hs\r\n"),
  378. Params.Base, Params.Base + Params.Size,
  379. Image);
  380. }
  381. }
  382. lprintfs( _T("\r\n") );
  383. }
  384. void
  385. LogStackDump(
  386. PDEBUGPACKET dp
  387. )
  388. {
  389. HRESULT Status;
  390. DWORD i;
  391. DWORD j;
  392. BYTE stack[1024] = {0};
  393. ULONG64 StackOffset;
  394. if ((Status = dp->DbgRegisters->GetStackOffset(&StackOffset)) != S_OK ||
  395. (Status = dp->DbgData->ReadVirtual(StackOffset,
  396. stack,
  397. sizeof(stack),
  398. &i)) != S_OK) {
  399. lprintfs(_T("Error 0x%08X\r\n"), Status);
  400. return;
  401. }
  402. lprintf( MSG_STACK_DUMP_HEADER );
  403. for( i = 0; i < 20; i++ ) {
  404. j = i * 16;
  405. lprintfs( _T("%016I64x %02x %02x %02x %02x %02x %02x %02x %02x - ")
  406. _T("%02x %02x %02x %02x %02x %02x %02x %02x ")
  407. _T("%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c\r\n"),
  408. j + StackOffset,
  409. stack[ j + 0 ],
  410. stack[ j + 1 ],
  411. stack[ j + 2 ],
  412. stack[ j + 3 ],
  413. stack[ j + 4 ],
  414. stack[ j + 5 ],
  415. stack[ j + 6 ],
  416. stack[ j + 7 ],
  417. stack[ j + 8 ],
  418. stack[ j + 9 ],
  419. stack[ j + 10 ],
  420. stack[ j + 11 ],
  421. stack[ j + 12 ],
  422. stack[ j + 13 ],
  423. stack[ j + 14 ],
  424. stack[ j + 15 ],
  425. isprint( stack[ j + 0 ]) ? stack[ j + 0 ] : _T('.'),
  426. isprint( stack[ j + 1 ]) ? stack[ j + 1 ] : _T('.'),
  427. isprint( stack[ j + 2 ]) ? stack[ j + 2 ] : _T('.'),
  428. isprint( stack[ j + 3 ]) ? stack[ j + 3 ] : _T('.'),
  429. isprint( stack[ j + 4 ]) ? stack[ j + 4 ] : _T('.'),
  430. isprint( stack[ j + 5 ]) ? stack[ j + 5 ] : _T('.'),
  431. isprint( stack[ j + 6 ]) ? stack[ j + 6 ] : _T('.'),
  432. isprint( stack[ j + 7 ]) ? stack[ j + 7 ] : _T('.'),
  433. isprint( stack[ j + 8 ]) ? stack[ j + 8 ] : _T('.'),
  434. isprint( stack[ j + 9 ]) ? stack[ j + 9 ] : _T('.'),
  435. isprint( stack[ j + 10 ]) ? stack[ j + 10 ] : _T('.'),
  436. isprint( stack[ j + 11 ]) ? stack[ j + 11 ] : _T('.'),
  437. isprint( stack[ j + 12 ]) ? stack[ j + 12 ] : _T('.'),
  438. isprint( stack[ j + 13 ]) ? stack[ j + 13 ] : _T('.'),
  439. isprint( stack[ j + 14 ]) ? stack[ j + 14 ] : _T('.'),
  440. isprint( stack[ j + 15 ]) ? stack[ j + 15 ] : _T('.')
  441. );
  442. }
  443. lprintfs( _T("\r\n") );
  444. }
  445. void
  446. LogCurrentThreadInformation(
  447. PDEBUGPACKET dp,
  448. PCRASHES crash
  449. )
  450. {
  451. HRESULT Status;
  452. ULONG ThreadId;
  453. _TCHAR IdBuf[16];
  454. ULONG64 InstrOffs;
  455. DWORD InstrWindow;
  456. // The size should match the size of pCrash->szFunction
  457. char FuncNameA[256];
  458. WCHAR FuncNameW[256];
  459. ULONG64 Displ;
  460. if ((Status = dp->DbgSystem->
  461. GetCurrentThreadSystemId(&ThreadId)) != S_OK) {
  462. ThreadId = 0xffffffff;
  463. }
  464. _stprintf( IdBuf, _T("%x"), ThreadId );
  465. lprintf( MSG_STATE_DUMP, IdBuf );
  466. dp->DbgClient->SetOutputCallbacks(&g_LogOutCb);
  467. if ((Status = dp->DbgRegisters->
  468. OutputRegisters(DEBUG_OUTCTL_THIS_CLIENT,
  469. DEBUG_REGISTERS_DEFAULT)) != S_OK) {
  470. lprintfs(_T("Error 0x%08X\r\n"), Status);
  471. }
  472. lprintfs( _T("\r\n") );
  473. InstrWindow = dp->options.dwInstructions;
  474. if (InstrWindow > 500) {
  475. InstrWindow = 500;
  476. }
  477. strcpy(FuncNameA, "<nosymbols>");
  478. wcscpy(FuncNameW, L"<nosymbols>");
  479. if ((Status = dp->DbgRegisters->
  480. GetInstructionOffset(&InstrOffs)) != S_OK) {
  481. lprintfs(_T("Error 0x%08X\r\n"), Status);
  482. } else {
  483. if (FAILED(Status = dp->DbgSymbols->
  484. GetNameByOffset(InstrOffs, FuncNameA, sizeof(FuncNameA),
  485. NULL, &Displ))) {
  486. strcpy(FuncNameA, "<nosymbols>");
  487. }
  488. #ifdef UNICODE
  489. if (MultiByteToWideChar(CP_ACP, 0, FuncNameA, -1,
  490. FuncNameW,
  491. sizeof(FuncNameW) / sizeof(WCHAR)) == 0) {
  492. wcscpy(FuncNameW, L"<nosymbols");
  493. }
  494. lprintf( MSG_FUNCTION, FuncNameW );
  495. #else
  496. lprintf( MSG_FUNCTION, FuncNameA );
  497. #endif
  498. dp->DbgClient->SetOutputLinePrefix(" ");
  499. if ((Status = dp->DbgControl->
  500. OutputDisassemblyLines(DEBUG_OUTCTL_THIS_CLIENT, InstrWindow,
  501. InstrWindow, InstrOffs,
  502. DEBUG_DISASM_MATCHING_SYMBOLS,
  503. NULL, NULL, NULL, NULL)) != S_OK) {
  504. lprintfs(_T("Error 0x%08X\r\n"), Status);
  505. }
  506. // If this is the event thread output a message
  507. // indicating the faulting instruction.
  508. if (crash) {
  509. dp->DbgClient->SetOutputLinePrefix(NULL);
  510. lprintf( MSG_FAULT );
  511. }
  512. if ((Status = dp->DbgControl->
  513. OutputDisassembly(DEBUG_OUTCTL_THIS_CLIENT, InstrOffs,
  514. DEBUG_DISASM_EFFECTIVE_ADDRESS |
  515. DEBUG_DISASM_MATCHING_SYMBOLS,
  516. &InstrOffs)) != S_OK) {
  517. lprintfs(_T("Error 0x%08X\r\n"), Status);
  518. }
  519. dp->DbgClient->SetOutputLinePrefix(" ");
  520. if ((Status = dp->DbgControl->
  521. OutputDisassemblyLines(DEBUG_OUTCTL_THIS_CLIENT, 0,
  522. InstrWindow, InstrOffs,
  523. DEBUG_DISASM_EFFECTIVE_ADDRESS |
  524. DEBUG_DISASM_MATCHING_SYMBOLS,
  525. NULL, NULL, NULL, NULL)) != S_OK) {
  526. lprintfs(_T("Error 0x%08X\r\n"), Status);
  527. }
  528. dp->DbgClient->SetOutputLinePrefix(NULL);
  529. }
  530. lprintfs( _T("\r\n") );
  531. if (crash) {
  532. #ifdef UNICODE
  533. wcscpy(crash->szFunction, FuncNameW);
  534. #else
  535. strcpy(crash->szFunction, FuncNameA);
  536. #endif
  537. }
  538. lprintf( MSG_STACKTRACE );
  539. if ((Status = dp->DbgControl->
  540. OutputStackTrace(DEBUG_OUTCTL_THIS_CLIENT, NULL, 100,
  541. DEBUG_STACK_ARGUMENTS |
  542. DEBUG_STACK_FUNCTION_INFO |
  543. DEBUG_STACK_FRAME_ADDRESSES |
  544. DEBUG_STACK_COLUMN_NAMES)) != S_OK) {
  545. lprintfs(_T("Error 0x%08X\r\n"), Status);
  546. }
  547. lprintfs( _T("\r\n") );
  548. dp->DbgClient->SetOutputCallbacks(NULL);
  549. LogStackDump( dp );
  550. }
  551. void
  552. LogAllThreadInformation(
  553. PDEBUGPACKET dp,
  554. PCRASHES crash
  555. )
  556. {
  557. HRESULT Status;
  558. ULONG NumThreads;
  559. ULONG i;
  560. ULONG ThreadId;
  561. ULONG EventTid;
  562. if (!dp->options.fDumpAllThreads) {
  563. // Just log the current event thread's information.
  564. LogCurrentThreadInformation(dp, crash);
  565. return;
  566. }
  567. if ((Status = dp->DbgSystem->GetNumberThreads(&NumThreads)) != S_OK ||
  568. (Status = dp->DbgSystem->GetEventThread(&EventTid)) != S_OK) {
  569. lprintfs(_T("Error 0x%08X\r\n"), Status);
  570. return;
  571. }
  572. for (i = 0; i < NumThreads; i++) {
  573. if ((Status = dp->DbgSystem->
  574. GetThreadIdsByIndex(i, 1, &ThreadId, NULL)) != S_OK ||
  575. (Status = dp->DbgSystem->SetCurrentThreadId(ThreadId)) != S_OK) {
  576. lprintfs(_T("Error 0x%08X\r\n"), Status);
  577. continue;
  578. }
  579. LogCurrentThreadInformation(dp, ThreadId == EventTid ? crash : NULL);
  580. }
  581. dp->DbgSystem->SetCurrentThreadId(EventTid);
  582. }
  583. void
  584. LogSymbols(
  585. PDEBUGPACKET dp
  586. )
  587. {
  588. HRESULT Status;
  589. char ModName[64];
  590. char Buf[MAX_PATH];
  591. ULONG64 InstrOffs;
  592. ULONG64 ModBase;
  593. lprintf( MSG_SYMBOL_TABLE );
  594. if ((Status = dp->DbgRegisters->
  595. GetInstructionOffset(&InstrOffs)) != S_OK ||
  596. (Status = dp->DbgSymbols->
  597. GetModuleByOffset(InstrOffs, 0, NULL, &ModBase)) != S_OK ||
  598. FAILED(Status = dp->DbgSymbols->
  599. GetModuleNames(DEBUG_ANY_ID, ModBase,
  600. Buf, sizeof(Buf), NULL,
  601. ModName, sizeof(ModName), NULL,
  602. NULL, 0, NULL))) {
  603. lprintfs(_T("Error 0x%08X\r\n"), Status);
  604. return;
  605. }
  606. lprintfs(_T("%hs\r\n\r\n"), Buf);
  607. sprintf(Buf, "x %s!*", ModName);
  608. dp->DbgClient->SetOutputCallbacks(&g_LogOutCb);
  609. dp->DbgControl->Execute(DEBUG_OUTCTL_THIS_CLIENT, Buf,
  610. DEBUG_EXECUTE_DEFAULT);
  611. dp->DbgClient->SetOutputCallbacks(NULL);
  612. }
  613. void
  614. PostMortemDump(
  615. PDEBUGPACKET dp,
  616. PDEBUG_LAST_EVENT_INFO_EXCEPTION Exception
  617. )
  618. {
  619. _TCHAR dbuf[MAX_PATH];
  620. _TCHAR szDate[20];
  621. _TCHAR szTime[20];
  622. CRASHES crash = {0};
  623. DWORD dwThreadId;
  624. HANDLE hThread;
  625. char ExeName[MAX_PATH];
  626. GetLocalTime( &crash.time );
  627. crash.dwExceptionCode = Exception->ExceptionRecord.ExceptionCode;
  628. crash.dwAddress = (DWORD_PTR)Exception->ExceptionRecord.ExceptionAddress;
  629. if (FAILED(dp->DbgSystem->
  630. GetCurrentProcessExecutableName(ExeName, sizeof(ExeName),
  631. NULL))) {
  632. strcpy(ExeName, "<unknown>");
  633. }
  634. #ifdef UNICODE
  635. if (MultiByteToWideChar(CP_ACP, 0, ExeName, -1,
  636. crash.szAppName,
  637. sizeof(crash.szAppName) / sizeof(TCHAR)) == 0) {
  638. _tcscpy(crash.szAppName, _T("<unknown>"));
  639. }
  640. #endif
  641. lprintf( MSG_APP_EXCEPTION );
  642. _stprintf( dbuf, _T("%d"), dp->dwPidToDebug );
  643. lprintf( MSG_APP_EXEP_NAME, crash.szAppName, dbuf );
  644. GetDateFormat(LOCALE_SYSTEM_DEFAULT, DATE_SHORTDATE, &crash.time,
  645. NULL, szDate, sizeof(szDate) / sizeof(_TCHAR));
  646. _stprintf( szTime, _T("%02d:%02d:%02d.%03d"), crash.time.wHour,
  647. crash.time.wMinute,
  648. crash.time.wSecond,
  649. crash.time.wMilliseconds );
  650. lprintf( MSG_APP_EXEP_WHEN, szDate, szTime );
  651. _stprintf( dbuf, _T("%08lx"), Exception->ExceptionRecord.ExceptionCode );
  652. lprintf( MSG_EXCEPTION_NUMBER, dbuf );
  653. lprintfs( _T("(%s)\r\n\r\n"),
  654. GetExceptionText(Exception->ExceptionRecord.ExceptionCode) );
  655. LogSystemInformation( dp );
  656. LogTaskList( dp );
  657. LogModuleList( dp );
  658. LogAllThreadInformation(dp, &crash);
  659. if (dp->options.fDumpSymbols) {
  660. LogSymbols( dp );
  661. }
  662. ElSaveCrash( &crash, dp->options.dwMaxCrashes );
  663. dp->ExitStatus = Exception->ExceptionRecord.ExceptionCode;
  664. hThread = CreateThread( NULL,
  665. 16000,
  666. (LPTHREAD_START_ROUTINE)TerminationThread,
  667. dp,
  668. 0,
  669. &dwThreadId
  670. );
  671. WaitForSingleObject( hThread, 30000 );
  672. CloseHandle( hThread );
  673. return;
  674. }
  675. // Valid range: [1-7]
  676. #define NUM_DIGITS_FNAME 2
  677. void
  678. CalcNextFileName(
  679. IN PTSTR pszUserName,
  680. OUT PSTR pszFileName,
  681. IN OUT PINT pnCurrentValue,
  682. IN BOOL bUseLongFileNames
  683. )
  684. {
  685. TCHAR szDrive[_MAX_DRIVE];
  686. TCHAR szPath[_MAX_PATH];
  687. TCHAR szFName[_MAX_FNAME];
  688. TCHAR szExt[_MAX_EXT];
  689. int nLargestPossibleNum;
  690. int nCnt;
  691. Assert(pszUserName);
  692. Assert(pnCurrentValue);
  693. Assert(1 <= NUM_DIGITS_FNAME);
  694. Assert(NUM_DIGITS_FNAME <= 7);
  695. // Given the number of digits, this is the largest number +1
  696. // we can have. If we could raise int to an int, this would
  697. // be easy.
  698. // nLargestPossibleNum = 10^NUM_DIGITS_FNAME
  699. // We are intentionally over by one, the actual range is
  700. // [0, 10^NUM_DIGITS_FNAME-1]
  701. nLargestPossibleNum = 1;
  702. for (nCnt = 0; nCnt<NUM_DIGITS_FNAME; nCnt++) {
  703. nLargestPossibleNum *= 10;
  704. }
  705. _tsplitpath(pszUserName, szDrive, szPath, szFName, szExt);
  706. if (!bUseLongFileNames) {
  707. // Shorten the file name len to 6, so that we can
  708. // add the 2 digit sequence.
  709. // MSDOS FName len == 8
  710. szFName[8 - NUM_DIGITS_FNAME] = 0;
  711. }
  712. sprintf(pszFileName,
  713. #ifdef UNICODE
  714. "%ls%ls%ls%0*d%ls",
  715. #else
  716. "%s%s%s%0*d%s",
  717. #endif
  718. szDrive,
  719. szPath,
  720. szFName,
  721. NUM_DIGITS_FNAME,
  722. *pnCurrentValue++,
  723. szExt
  724. );
  725. // Make sure we stay in the range [0, 10^NUM_DIGITS_FNAME]
  726. *pnCurrentValue = ++(*pnCurrentValue) % nLargestPossibleNum;
  727. }
  728. BOOL
  729. CreateDumpFile(
  730. PDEBUGPACKET dp
  731. )
  732. /*++
  733. Routine Description:
  734. This function creates a crash dump file.
  735. Arguments:
  736. dp - debug packet for current process
  737. Return Value:
  738. TRUE - Crash dump was created
  739. FALSE - Crash dump was NOT created
  740. --*/
  741. {
  742. PTSTR p;
  743. PCSTR Comment = "Dr. Watson generated MiniDump";
  744. ULONG Qual, Format = DEBUG_FORMAT_DEFAULT;
  745. HRESULT Status;
  746. char FileName[MAX_PATH];
  747. p = ExpandPath( dp->options.szCrashDump );
  748. if (!p) {
  749. return FALSE;
  750. }
  751. if (dp->options.fUseSequentialNaming) {
  752. // Figure out what the next file name should be.
  753. CalcNextFileName(p,
  754. FileName,
  755. &dp->options.nNextDumpSequence,
  756. dp->options.fUseLongFileNames
  757. );
  758. // Save the next value of nCurrent
  759. RegSave(&dp->options);
  760. } else {
  761. #ifdef UNICODE
  762. if (WideCharToMultiByte(CP_ACP, 0, p, -1, FileName, sizeof(FileName),
  763. NULL, NULL) == 0) {
  764. return FALSE;
  765. }
  766. #else
  767. strcpy(FileName, p);
  768. #endif
  769. }
  770. switch (dp->options.dwType) {
  771. case FullDump:
  772. Qual = DEBUG_USER_WINDOWS_DUMP;
  773. Comment = NULL;
  774. break;
  775. case FullMiniDump:
  776. Format = DEBUG_FORMAT_USER_SMALL_FULL_MEMORY |
  777. DEBUG_FORMAT_USER_SMALL_HANDLE_DATA;
  778. // Fall through.
  779. case MiniDump:
  780. Qual = DEBUG_USER_WINDOWS_SMALL_DUMP;
  781. break;
  782. default:
  783. return FALSE;
  784. }
  785. Status = dp->DbgClient->WriteDumpFile2(FileName, Qual, Format, Comment);
  786. free( p );
  787. return Status == S_OK;
  788. }
  789. DWORD
  790. DispatchDebugEventThread(
  791. PDEBUGPACKET dp
  792. )
  793. /*++
  794. Routine Description:
  795. This is the entry point for DRWTSN32
  796. Arguments:
  797. None.
  798. Return Value:
  799. None.
  800. --*/
  801. {
  802. _TCHAR szLogFileName[1024];
  803. _TCHAR buf[1024];
  804. PTSTR p;
  805. if (dp->dwPidToDebug == 0) {
  806. goto exit;
  807. }
  808. CreateEngineInterfaces(dp);
  809. SetErrorMode( SEM_FAILCRITICALERRORS |
  810. SEM_NOGPFAULTERRORBOX |
  811. SEM_NOOPENFILEERRORBOX );
  812. AttachToActiveProcess( dp );
  813. p = ExpandPath(dp->options.szLogPath);
  814. if (p) {
  815. _tcscpy( szLogFileName, p );
  816. free( p );
  817. } else {
  818. _tcscpy( szLogFileName, dp->options.szLogPath );
  819. }
  820. MakeLogFileName( szLogFileName );
  821. OpenLogFile( szLogFileName,
  822. dp->options.fAppendToLogFile,
  823. dp->options.fVisual
  824. );
  825. for (;;) {
  826. ULONG Type, Process, Thread;
  827. DEBUG_LAST_EVENT_INFO_EXCEPTION LastEx;
  828. if (dp->DbgControl->
  829. WaitForEvent(DEBUG_WAIT_DEFAULT, 30000) != S_OK ||
  830. dp->DbgControl->
  831. GetLastEventInformation(&Type, &Process, &Thread,
  832. &LastEx, sizeof(LastEx), NULL,
  833. NULL, 0, NULL) != S_OK) {
  834. break;
  835. }
  836. switch (Type) {
  837. case DEBUG_EVENT_EXCEPTION:
  838. if (LastEx.ExceptionRecord.ExceptionCode == STATUS_BREAKPOINT) {
  839. //
  840. // If there is no event to signal, just use the first
  841. // breakpoint as the stop event.
  842. //
  843. if (dp->hEventToSignal && LastEx.FirstChance) {
  844. //
  845. // The aedebug event will be signalled AFTER this
  846. // thread exits, so that it will disappear before
  847. // the dump snapshot is taken.
  848. //
  849. dp->DbgControl->SetExecutionStatus(DEBUG_STATUS_GO_HANDLED);
  850. break;
  851. }
  852. }
  853. if (dp->options.fVisual) {
  854. //
  855. // this notification is necessary because the shell must know when
  856. // the debugee has been attached. if it doesn't know and the user is
  857. // allowed to terminate drwatson then the system may intervene with
  858. // a popup.
  859. //
  860. SendMessage( dp->hwnd, WM_ATTACHCOMPLETE, 0, 0 );
  861. _stprintf( buf,
  862. LoadRcString( IDS_AE_TEXT ),
  863. GetExceptionText(LastEx.ExceptionRecord.ExceptionCode),
  864. LastEx.ExceptionRecord.ExceptionCode,
  865. LastEx.ExceptionRecord.ExceptionAddress );
  866. SendMessage( dp->hwnd, WM_EXCEPTIONINFO, 0, (LPARAM) buf );
  867. }
  868. PostMortemDump( dp, &LastEx );
  869. if (dp->options.fCrash) {
  870. CreateDumpFile( dp );
  871. }
  872. dp->DbgControl->SetExecutionStatus(DEBUG_STATUS_GO_NOT_HANDLED);
  873. break;
  874. case DEBUG_EVENT_EXIT_THREAD:
  875. if ( dp->hEventToSignal ) {
  876. SetEvent(dp->hEventToSignal);
  877. dp->hEventToSignal = 0L;
  878. }
  879. dp->DbgControl->SetExecutionStatus(DEBUG_STATUS_GO);
  880. break;
  881. }
  882. }
  883. exit:
  884. CloseLogFile();
  885. if (dp->options.fVisual) {
  886. SendMessage( dp->hwnd, WM_DUMPCOMPLETE, 0, 0 );
  887. }
  888. return 0;
  889. }
  890. DWORD
  891. TerminationThread(
  892. PDEBUGPACKET dp
  893. )
  894. {
  895. HANDLE hProcess;
  896. hProcess = OpenProcess( PROCESS_TERMINATE, FALSE, dp->dwPidToDebug );
  897. if (hProcess != NULL) {
  898. TerminateProcess( hProcess, dp->ExitStatus );
  899. CloseHandle( hProcess );
  900. }
  901. return 0;
  902. }