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.

1100 lines
31 KiB

  1. /*++
  2. Copyright (c) 1993-2002 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. LoadRcStringBuf( IDS_UNKNOWN_MACHINE,
  260. mySi.szMachineName, _tsizeof(mySi.szMachineName) );
  261. LoadRcStringBuf( IDS_UNKNOWN_USER,
  262. mySi.szUserName, _tsizeof(mySi.szUserName) );
  263. // Attempt to get the actual values.
  264. // The storage passed to the get thread is not taken
  265. // from this thread's stack so that this function can exit
  266. // without leaving the other thread with stale stack pointers.
  267. threadSi = (SYSINFO*)malloc(sizeof(*threadSi));
  268. if (threadSi != NULL) {
  269. hThread = CreateThread( NULL,
  270. 16000,
  271. (LPTHREAD_START_ROUTINE)SysInfoThread,
  272. threadSi,
  273. 0,
  274. &dwThreadId
  275. );
  276. if (hThread != NULL) {
  277. // Let the thread run for a little while since
  278. // the get calls can be slow. If the thread doesn't
  279. // finish in the time allotted we'll just go ahead
  280. // with the default values and forget about the get thread.
  281. Sleep( 0 );
  282. if (WaitForSingleObject( hThread, 30000 ) == WAIT_OBJECT_0) {
  283. // Thread finished so we have the real values.
  284. _tcscpy(mySi.szMachineName, threadSi->szMachineName);
  285. _tcscpy(mySi.szUserName, threadSi->szUserName);
  286. free(threadSi);
  287. }
  288. CloseHandle( hThread );
  289. } else {
  290. free(threadSi);
  291. }
  292. }
  293. lprintf( MSG_SYSINFO_COMPUTER, mySi.szMachineName );
  294. lprintf( MSG_SYSINFO_USER, mySi.szUserName );
  295. ProcessIdToSessionId(dp->dwPidToDebug, &TSid);
  296. _stprintf( buf, _T("%d"), TSid );
  297. lprintf( MSG_SYSINFO_TERMINAL_SESSION, buf );
  298. GetSystemInfo( &si );
  299. _stprintf( buf, _T("%d"), si.dwNumberOfProcessors );
  300. lprintf( MSG_SYSINFO_NUM_PROC, buf );
  301. RegLogProcessorType();
  302. ver = GetVersion();
  303. _stprintf( buf, _T("%d.%d"), LOBYTE(LOWORD(ver)), HIBYTE(LOWORD(ver)) );
  304. lprintf( MSG_SYSINFO_WINVER, buf );
  305. RegLogCurrentVersion();
  306. lprintfs( _T("\r\n") );
  307. }
  308. void
  309. LogTaskList(
  310. PDEBUGPACKET dp
  311. )
  312. /*++
  313. Routine Description:
  314. This function gets the current task list and logs the process id &
  315. process name to the log file.
  316. --*/
  317. {
  318. HRESULT Status;
  319. #define MAX_IDS 8192
  320. PULONG Ids = NULL;
  321. ULONG IdCount;
  322. ULONG i;
  323. Ids = (PULONG)malloc(sizeof(*Ids) * MAX_IDS);
  324. if (Ids == NULL) {
  325. goto Error;
  326. }
  327. if ((Status = dp->DbgClient->
  328. GetRunningProcessSystemIds(0, Ids, MAX_IDS,
  329. &IdCount)) != S_OK) {
  330. goto Error;
  331. }
  332. if (IdCount > MAX_IDS) {
  333. // Incomplete process list is good enough.
  334. IdCount = MAX_IDS;
  335. }
  336. lprintf( MSG_TASK_LIST );
  337. for (i = 0; i < IdCount; i++) {
  338. char ExeName[MAX_PATH];
  339. if ((Status = dp->DbgClient->
  340. GetRunningProcessDescription(0, Ids[i],
  341. DEBUG_PROC_DESC_NO_PATHS,
  342. ExeName, sizeof(ExeName),
  343. NULL, NULL, 0, NULL)) != S_OK) {
  344. lprintfs(_T("%4d Error 0x%08X\r\n"), Ids[i], Status);
  345. } else {
  346. lprintfs(_T("%4d %hs\r\n"), Ids[i], ExeName);
  347. }
  348. }
  349. lprintfs( _T("\r\n") );
  350. free(Ids);
  351. return;
  352. Error:
  353. _tprintf( _T("ERROR: could not get the task list\n") );
  354. free(Ids);
  355. }
  356. void
  357. LogModuleList(
  358. PDEBUGPACKET dp
  359. )
  360. {
  361. HRESULT Status;
  362. ULONG NumMod;
  363. ULONG i;
  364. char Image[MAX_PATH];
  365. DEBUG_MODULE_PARAMETERS Params;
  366. lprintf( MSG_MODULE_LIST );
  367. if ((Status = dp->DbgSymbols->GetNumberModules(&NumMod, &i)) != S_OK) {
  368. lprintfs(_T("Error 0x%08X\r\n"), Status);
  369. return;
  370. }
  371. for (i = 0; i < NumMod; i++) {
  372. if ((Status = dp->DbgSymbols->
  373. GetModuleParameters(1, NULL, i, &Params)) != S_OK ||
  374. FAILED(Status = dp->DbgSymbols->
  375. GetModuleNames(i, 0, Image, sizeof(Image), NULL,
  376. NULL, 0, NULL, NULL, 0, NULL))) {
  377. lprintfs(_T("Error 0x%08X\r\n"), Status);
  378. } else {
  379. lprintfs(_T("%016I64x - %016I64x: %hs\r\n"),
  380. Params.Base, Params.Base + Params.Size,
  381. Image);
  382. }
  383. }
  384. lprintfs( _T("\r\n") );
  385. }
  386. void
  387. LogStackDump(
  388. PDEBUGPACKET dp
  389. )
  390. {
  391. HRESULT Status;
  392. DWORD i;
  393. DWORD j;
  394. BYTE stack[1024] = {0};
  395. ULONG64 StackOffset;
  396. if ((Status = dp->DbgRegisters->GetStackOffset(&StackOffset)) != S_OK ||
  397. (Status = dp->DbgData->ReadVirtual(StackOffset,
  398. stack,
  399. sizeof(stack),
  400. &i)) != S_OK) {
  401. lprintfs(_T("Error 0x%08X\r\n"), Status);
  402. return;
  403. }
  404. lprintf( MSG_STACK_DUMP_HEADER );
  405. for( i = 0; i < 20; i++ ) {
  406. j = i * 16;
  407. lprintfs( _T("%016I64x %02x %02x %02x %02x %02x %02x %02x %02x - ")
  408. _T("%02x %02x %02x %02x %02x %02x %02x %02x ")
  409. _T("%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c\r\n"),
  410. j + StackOffset,
  411. stack[ j + 0 ],
  412. stack[ j + 1 ],
  413. stack[ j + 2 ],
  414. stack[ j + 3 ],
  415. stack[ j + 4 ],
  416. stack[ j + 5 ],
  417. stack[ j + 6 ],
  418. stack[ j + 7 ],
  419. stack[ j + 8 ],
  420. stack[ j + 9 ],
  421. stack[ j + 10 ],
  422. stack[ j + 11 ],
  423. stack[ j + 12 ],
  424. stack[ j + 13 ],
  425. stack[ j + 14 ],
  426. stack[ j + 15 ],
  427. isprint( stack[ j + 0 ]) ? stack[ j + 0 ] : _T('.'),
  428. isprint( stack[ j + 1 ]) ? stack[ j + 1 ] : _T('.'),
  429. isprint( stack[ j + 2 ]) ? stack[ j + 2 ] : _T('.'),
  430. isprint( stack[ j + 3 ]) ? stack[ j + 3 ] : _T('.'),
  431. isprint( stack[ j + 4 ]) ? stack[ j + 4 ] : _T('.'),
  432. isprint( stack[ j + 5 ]) ? stack[ j + 5 ] : _T('.'),
  433. isprint( stack[ j + 6 ]) ? stack[ j + 6 ] : _T('.'),
  434. isprint( stack[ j + 7 ]) ? stack[ j + 7 ] : _T('.'),
  435. isprint( stack[ j + 8 ]) ? stack[ j + 8 ] : _T('.'),
  436. isprint( stack[ j + 9 ]) ? stack[ j + 9 ] : _T('.'),
  437. isprint( stack[ j + 10 ]) ? stack[ j + 10 ] : _T('.'),
  438. isprint( stack[ j + 11 ]) ? stack[ j + 11 ] : _T('.'),
  439. isprint( stack[ j + 12 ]) ? stack[ j + 12 ] : _T('.'),
  440. isprint( stack[ j + 13 ]) ? stack[ j + 13 ] : _T('.'),
  441. isprint( stack[ j + 14 ]) ? stack[ j + 14 ] : _T('.'),
  442. isprint( stack[ j + 15 ]) ? stack[ j + 15 ] : _T('.')
  443. );
  444. }
  445. lprintfs( _T("\r\n") );
  446. }
  447. void
  448. LogCurrentThreadInformation(
  449. PDEBUGPACKET dp,
  450. PCRASHES crash
  451. )
  452. {
  453. HRESULT Status;
  454. ULONG ThreadId;
  455. _TCHAR IdBuf[16];
  456. ULONG64 InstrOffs;
  457. DWORD InstrWindow;
  458. // The size should match the size of pCrash->szFunction
  459. char FuncNameA[256];
  460. WCHAR FuncNameW[256];
  461. ULONG64 Displ;
  462. if ((Status = dp->DbgSystem->
  463. GetCurrentThreadSystemId(&ThreadId)) != S_OK) {
  464. ThreadId = 0xffffffff;
  465. }
  466. _stprintf( IdBuf, _T("%x"), ThreadId );
  467. lprintf( MSG_STATE_DUMP, IdBuf );
  468. dp->DbgClient->SetOutputCallbacks(&g_LogOutCb);
  469. if ((Status = dp->DbgRegisters->
  470. OutputRegisters(DEBUG_OUTCTL_THIS_CLIENT,
  471. DEBUG_REGISTERS_DEFAULT)) != S_OK) {
  472. lprintfs(_T("Error 0x%08X\r\n"), Status);
  473. }
  474. lprintfs( _T("\r\n") );
  475. InstrWindow = dp->options.dwInstructions;
  476. if (InstrWindow > 500) {
  477. InstrWindow = 500;
  478. }
  479. strcpy(FuncNameA, "<nosymbols>");
  480. wcscpy(FuncNameW, L"<nosymbols>");
  481. if ((Status = dp->DbgRegisters->
  482. GetInstructionOffset(&InstrOffs)) != S_OK) {
  483. lprintfs(_T("Error 0x%08X\r\n"), Status);
  484. } else {
  485. if (FAILED(Status = dp->DbgSymbols->
  486. GetNameByOffset(InstrOffs, FuncNameA, sizeof(FuncNameA),
  487. NULL, &Displ))) {
  488. strcpy(FuncNameA, "<nosymbols>");
  489. }
  490. #ifdef UNICODE
  491. if (MultiByteToWideChar(CP_ACP, 0, FuncNameA, -1,
  492. FuncNameW,
  493. sizeof(FuncNameW) / sizeof(WCHAR)) == 0) {
  494. wcscpy(FuncNameW, L"<nosymbols");
  495. }
  496. lprintf( MSG_FUNCTION, FuncNameW );
  497. #else
  498. lprintf( MSG_FUNCTION, FuncNameA );
  499. #endif
  500. dp->DbgClient->SetOutputLinePrefix(" ");
  501. if ((Status = dp->DbgControl->
  502. OutputDisassemblyLines(DEBUG_OUTCTL_THIS_CLIENT, InstrWindow,
  503. InstrWindow, InstrOffs,
  504. DEBUG_DISASM_MATCHING_SYMBOLS,
  505. NULL, NULL, NULL, NULL)) != S_OK) {
  506. lprintfs(_T("Error 0x%08X\r\n"), Status);
  507. }
  508. // If this is the event thread output a message
  509. // indicating the faulting instruction.
  510. if (crash) {
  511. dp->DbgClient->SetOutputLinePrefix(NULL);
  512. lprintf( MSG_FAULT );
  513. }
  514. if ((Status = dp->DbgControl->
  515. OutputDisassembly(DEBUG_OUTCTL_THIS_CLIENT, InstrOffs,
  516. DEBUG_DISASM_EFFECTIVE_ADDRESS |
  517. DEBUG_DISASM_MATCHING_SYMBOLS,
  518. &InstrOffs)) != S_OK) {
  519. lprintfs(_T("Error 0x%08X\r\n"), Status);
  520. }
  521. dp->DbgClient->SetOutputLinePrefix(" ");
  522. if ((Status = dp->DbgControl->
  523. OutputDisassemblyLines(DEBUG_OUTCTL_THIS_CLIENT, 0,
  524. InstrWindow, InstrOffs,
  525. DEBUG_DISASM_EFFECTIVE_ADDRESS |
  526. DEBUG_DISASM_MATCHING_SYMBOLS,
  527. NULL, NULL, NULL, NULL)) != S_OK) {
  528. lprintfs(_T("Error 0x%08X\r\n"), Status);
  529. }
  530. dp->DbgClient->SetOutputLinePrefix(NULL);
  531. }
  532. lprintfs( _T("\r\n") );
  533. if (crash) {
  534. #ifdef UNICODE
  535. wcscpy(crash->szFunction, FuncNameW);
  536. #else
  537. strcpy(crash->szFunction, FuncNameA);
  538. #endif
  539. }
  540. lprintf( MSG_STACKTRACE );
  541. if ((Status = dp->DbgControl->
  542. OutputStackTrace(DEBUG_OUTCTL_THIS_CLIENT, NULL, 100,
  543. DEBUG_STACK_ARGUMENTS |
  544. DEBUG_STACK_FUNCTION_INFO |
  545. DEBUG_STACK_FRAME_ADDRESSES |
  546. DEBUG_STACK_COLUMN_NAMES)) != S_OK) {
  547. lprintfs(_T("Error 0x%08X\r\n"), Status);
  548. }
  549. lprintfs( _T("\r\n") );
  550. dp->DbgClient->SetOutputCallbacks(NULL);
  551. LogStackDump( dp );
  552. }
  553. void
  554. LogAllThreadInformation(
  555. PDEBUGPACKET dp,
  556. PCRASHES crash
  557. )
  558. {
  559. HRESULT Status;
  560. ULONG NumThreads;
  561. ULONG i;
  562. ULONG ThreadId;
  563. ULONG EventTid;
  564. if (!dp->options.fDumpAllThreads) {
  565. // Just log the current event thread's information.
  566. LogCurrentThreadInformation(dp, crash);
  567. return;
  568. }
  569. if ((Status = dp->DbgSystem->GetNumberThreads(&NumThreads)) != S_OK ||
  570. (Status = dp->DbgSystem->GetEventThread(&EventTid)) != S_OK) {
  571. lprintfs(_T("Error 0x%08X\r\n"), Status);
  572. return;
  573. }
  574. for (i = 0; i < NumThreads; i++) {
  575. if ((Status = dp->DbgSystem->
  576. GetThreadIdsByIndex(i, 1, &ThreadId, NULL)) != S_OK ||
  577. (Status = dp->DbgSystem->SetCurrentThreadId(ThreadId)) != S_OK) {
  578. lprintfs(_T("Error 0x%08X\r\n"), Status);
  579. continue;
  580. }
  581. LogCurrentThreadInformation(dp, ThreadId == EventTid ? crash : NULL);
  582. }
  583. dp->DbgSystem->SetCurrentThreadId(EventTid);
  584. }
  585. void
  586. LogSymbols(
  587. PDEBUGPACKET dp
  588. )
  589. {
  590. HRESULT Status;
  591. char ModName[64];
  592. char Buf[MAX_PATH];
  593. ULONG64 InstrOffs;
  594. ULONG64 ModBase;
  595. lprintf( MSG_SYMBOL_TABLE );
  596. if ((Status = dp->DbgRegisters->
  597. GetInstructionOffset(&InstrOffs)) != S_OK ||
  598. (Status = dp->DbgSymbols->
  599. GetModuleByOffset(InstrOffs, 0, NULL, &ModBase)) != S_OK ||
  600. FAILED(Status = dp->DbgSymbols->
  601. GetModuleNames(DEBUG_ANY_ID, ModBase,
  602. Buf, sizeof(Buf), NULL,
  603. ModName, sizeof(ModName), NULL,
  604. NULL, 0, NULL))) {
  605. lprintfs(_T("Error 0x%08X\r\n"), Status);
  606. return;
  607. }
  608. lprintfs(_T("%hs\r\n\r\n"), Buf);
  609. sprintf(Buf, "x %s!*", ModName);
  610. dp->DbgClient->SetOutputCallbacks(&g_LogOutCb);
  611. dp->DbgControl->Execute(DEBUG_OUTCTL_THIS_CLIENT, Buf,
  612. DEBUG_EXECUTE_DEFAULT);
  613. dp->DbgClient->SetOutputCallbacks(NULL);
  614. }
  615. void
  616. PostMortemDump(
  617. PDEBUGPACKET dp,
  618. PDEBUG_LAST_EVENT_INFO_EXCEPTION Exception
  619. )
  620. {
  621. _TCHAR dbuf[MAX_PATH];
  622. _TCHAR szDate[20];
  623. _TCHAR szTime[20];
  624. CRASHES crash = {0};
  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. _sntprintf( szTime, _tsizeof(szTime),
  647. _T("%02d:%02d:%02d.%03d"),
  648. crash.time.wHour,
  649. crash.time.wMinute,
  650. crash.time.wSecond,
  651. crash.time.wMilliseconds );
  652. szTime[_tsizeof(szTime) - 1] = 0;
  653. lprintf( MSG_APP_EXEP_WHEN, szDate, szTime );
  654. _stprintf( dbuf, _T("%08lx"), Exception->ExceptionRecord.ExceptionCode );
  655. lprintf( MSG_EXCEPTION_NUMBER, dbuf );
  656. lprintfs( _T("(%s)\r\n\r\n"),
  657. GetExceptionText(Exception->ExceptionRecord.ExceptionCode) );
  658. LogSystemInformation( dp );
  659. LogTaskList( dp );
  660. LogModuleList( dp );
  661. LogAllThreadInformation(dp, &crash);
  662. if (dp->options.fDumpSymbols) {
  663. LogSymbols( dp );
  664. }
  665. ElSaveCrash( &crash, dp->options.dwMaxCrashes );
  666. dp->ExitStatus = Exception->ExceptionRecord.ExceptionCode;
  667. return;
  668. }
  669. // Valid range: [1-7]
  670. #define NUM_DIGITS_FNAME 2
  671. void
  672. CalcNextFileName(
  673. IN PTSTR pszUserName,
  674. OUT PSTR pszFileName,
  675. IN OUT PINT pnCurrentValue,
  676. IN BOOL bUseLongFileNames
  677. )
  678. {
  679. TCHAR szDrive[_MAX_DRIVE];
  680. TCHAR szPath[_MAX_PATH];
  681. TCHAR szFName[_MAX_FNAME];
  682. TCHAR szExt[_MAX_EXT];
  683. int nLargestPossibleNum;
  684. int nCnt;
  685. Assert(pszUserName);
  686. Assert(pnCurrentValue);
  687. Assert(1 <= NUM_DIGITS_FNAME);
  688. Assert(NUM_DIGITS_FNAME <= 7);
  689. // Given the number of digits, this is the largest number +1
  690. // we can have. If we could raise int to an int, this would
  691. // be easy.
  692. // nLargestPossibleNum = 10^NUM_DIGITS_FNAME
  693. // We are intentionally over by one, the actual range is
  694. // [0, 10^NUM_DIGITS_FNAME-1]
  695. nLargestPossibleNum = 1;
  696. for (nCnt = 0; nCnt<NUM_DIGITS_FNAME; nCnt++) {
  697. nLargestPossibleNum *= 10;
  698. }
  699. _tsplitpath(pszUserName, szDrive, szPath, szFName, szExt);
  700. if (!bUseLongFileNames) {
  701. // Shorten the file name len to 6, so that we can
  702. // add the 2 digit sequence.
  703. // MSDOS FName len == 8
  704. szFName[8 - NUM_DIGITS_FNAME] = 0;
  705. }
  706. sprintf(pszFileName,
  707. #ifdef UNICODE
  708. "%ls%ls%ls%0*d%ls",
  709. #else
  710. "%s%s%s%0*d%s",
  711. #endif
  712. szDrive,
  713. szPath,
  714. szFName,
  715. NUM_DIGITS_FNAME,
  716. *pnCurrentValue++,
  717. szExt
  718. );
  719. // Make sure we stay in the range [0, 10^NUM_DIGITS_FNAME]
  720. *pnCurrentValue = ++(*pnCurrentValue) % nLargestPossibleNum;
  721. }
  722. BOOL
  723. CreateDumpFile(
  724. PDEBUGPACKET dp
  725. )
  726. /*++
  727. Routine Description:
  728. This function creates a crash dump file.
  729. Arguments:
  730. dp - debug packet for current process
  731. Return Value:
  732. TRUE - Crash dump was created
  733. FALSE - Crash dump was NOT created
  734. --*/
  735. {
  736. PTSTR p;
  737. PCSTR Comment = "Dr. Watson generated MiniDump";
  738. ULONG Qual, Format = DEBUG_FORMAT_DEFAULT;
  739. HRESULT Status;
  740. char FileName[MAX_PATH];
  741. p = ExpandPath( dp->options.szCrashDump );
  742. if (!p) {
  743. return FALSE;
  744. }
  745. if (dp->options.fUseSequentialNaming) {
  746. // Figure out what the next file name should be.
  747. CalcNextFileName(p,
  748. FileName,
  749. &dp->options.nNextDumpSequence,
  750. dp->options.fUseLongFileNames
  751. );
  752. // Save the next value of nCurrent
  753. RegSave(&dp->options);
  754. } else {
  755. #ifdef UNICODE
  756. if (WideCharToMultiByte(CP_ACP, 0, p, -1, FileName, _tsizeof(FileName),
  757. NULL, NULL) == 0) {
  758. return FALSE;
  759. }
  760. #else
  761. lstrcpyn(FileName, p, _tsizeof(FileName));
  762. #endif
  763. }
  764. switch (dp->options.dwType) {
  765. case FullDump:
  766. Qual = DEBUG_USER_WINDOWS_DUMP;
  767. Comment = NULL;
  768. break;
  769. case FullMiniDump:
  770. Format = DEBUG_FORMAT_USER_SMALL_FULL_MEMORY |
  771. DEBUG_FORMAT_USER_SMALL_HANDLE_DATA;
  772. // Fall through.
  773. case MiniDump:
  774. Qual = DEBUG_USER_WINDOWS_SMALL_DUMP;
  775. break;
  776. default:
  777. return FALSE;
  778. }
  779. Status = dp->DbgClient->WriteDumpFile2(FileName, Qual, Format, Comment);
  780. free( p );
  781. return Status == S_OK;
  782. }
  783. DWORD
  784. DispatchDebugEventThread(
  785. PDEBUGPACKET dp
  786. )
  787. /*++
  788. Routine Description:
  789. This is the entry point for DRWTSN32
  790. Arguments:
  791. None.
  792. Return Value:
  793. None.
  794. --*/
  795. {
  796. _TCHAR szLogFileName[1024];
  797. _TCHAR buf[1024];
  798. PTSTR p;
  799. if (dp->dwPidToDebug == 0) {
  800. goto exit;
  801. }
  802. CreateEngineInterfaces(dp);
  803. SetErrorMode( SEM_FAILCRITICALERRORS |
  804. SEM_NOGPFAULTERRORBOX |
  805. SEM_NOOPENFILEERRORBOX );
  806. AttachToActiveProcess( dp );
  807. p = ExpandPath(dp->options.szLogPath);
  808. if (p) {
  809. lstrcpyn( szLogFileName, p, _tsizeof(szLogFileName) );
  810. free( p );
  811. } else {
  812. _tcscpy( szLogFileName, dp->options.szLogPath );
  813. }
  814. MakeLogFileName( szLogFileName );
  815. OpenLogFile( szLogFileName,
  816. dp->options.fAppendToLogFile,
  817. dp->options.fVisual
  818. );
  819. for (;;) {
  820. ULONG Type, Process, Thread;
  821. DEBUG_LAST_EVENT_INFO_EXCEPTION LastEx;
  822. DWORD dwThreadId;
  823. HANDLE hThread;
  824. if (dp->DbgControl->
  825. WaitForEvent(DEBUG_WAIT_DEFAULT, 30000) != S_OK ||
  826. dp->DbgControl->
  827. GetLastEventInformation(&Type, &Process, &Thread,
  828. &LastEx, sizeof(LastEx), NULL,
  829. NULL, 0, NULL) != S_OK) {
  830. break;
  831. }
  832. switch (Type) {
  833. case DEBUG_EVENT_EXCEPTION:
  834. if (LastEx.ExceptionRecord.ExceptionCode == STATUS_BREAKPOINT) {
  835. //
  836. // If there is no event to signal, just use the first
  837. // breakpoint as the stop event.
  838. //
  839. if (dp->hEventToSignal && LastEx.FirstChance) {
  840. //
  841. // The aedebug event will be signalled AFTER this
  842. // thread exits, so that it will disappear before
  843. // the dump snapshot is taken.
  844. //
  845. dp->DbgControl->SetExecutionStatus(DEBUG_STATUS_GO_HANDLED);
  846. break;
  847. }
  848. }
  849. if (dp->options.fVisual) {
  850. //
  851. // this notification is necessary because the shell must know when
  852. // the debugee has been attached. if it doesn't know and the user is
  853. // allowed to terminate drwatson then the system may intervene with
  854. // a popup.
  855. //
  856. SendMessage( dp->hwnd, WM_ATTACHCOMPLETE, 0, 0 );
  857. _sntprintf( buf, _tsizeof(buf),
  858. LoadRcString( IDS_AE_TEXT ),
  859. GetExceptionText(LastEx.ExceptionRecord.ExceptionCode),
  860. LastEx.ExceptionRecord.ExceptionCode,
  861. LastEx.ExceptionRecord.ExceptionAddress );
  862. buf[_tsizeof(buf) - 1] = 0;
  863. SendMessage( dp->hwnd, WM_EXCEPTIONINFO, 0, (LPARAM) buf );
  864. }
  865. PostMortemDump( dp, &LastEx );
  866. if (dp->options.fCrash) {
  867. CreateDumpFile( dp );
  868. }
  869. //
  870. // Attempt to terminate the debuggee. Continue
  871. // on if this doesn't work as the debuggee should
  872. // be killed anyway when Dr. Watson exits.
  873. //
  874. hThread = CreateThread( NULL,
  875. 16000,
  876. (LPTHREAD_START_ROUTINE)TerminationThread,
  877. dp,
  878. 0,
  879. &dwThreadId
  880. );
  881. if (hThread) {
  882. WaitForSingleObject( hThread, 30000 );
  883. CloseHandle( hThread );
  884. }
  885. dp->DbgControl->SetExecutionStatus(DEBUG_STATUS_GO_NOT_HANDLED);
  886. break;
  887. case DEBUG_EVENT_EXIT_THREAD:
  888. if ( dp->hEventToSignal ) {
  889. SetEvent(dp->hEventToSignal);
  890. dp->hEventToSignal = 0L;
  891. }
  892. dp->DbgControl->SetExecutionStatus(DEBUG_STATUS_GO);
  893. break;
  894. }
  895. }
  896. exit:
  897. CloseLogFile();
  898. if (dp->options.fVisual) {
  899. SendMessage( dp->hwnd, WM_DUMPCOMPLETE, 0, 0 );
  900. }
  901. return 0;
  902. }
  903. DWORD
  904. TerminationThread(
  905. PDEBUGPACKET dp
  906. )
  907. {
  908. HANDLE hProcess;
  909. hProcess = OpenProcess( PROCESS_TERMINATE, FALSE, dp->dwPidToDebug );
  910. if (hProcess != NULL) {
  911. TerminateProcess( hProcess, dp->ExitStatus );
  912. CloseHandle( hProcess );
  913. }
  914. return 0;
  915. }