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.

2327 lines
56 KiB

  1. /*++
  2. Copyright (c) 2000-2002 Microsoft Corporation
  3. Module Name:
  4. ext.cpp
  5. Abstract:
  6. Generic cross-platform and cross-processor extensions.
  7. Environment:
  8. User Mode
  9. --*/
  10. #include "precomp.h"
  11. #pragma hdrstop
  12. #include <ntverp.h>
  13. #include <time.h>
  14. #include <lm.h>
  15. #include <strsafe.h>
  16. extern CTriager *g_pTriager;
  17. //
  18. // Valid for the lifetime of the debug session.
  19. //
  20. WINDBG_EXTENSION_APIS ExtensionApis;
  21. ULONG g_TargetMachine;
  22. BOOL Connected;
  23. ULONG g_TargetClass;
  24. ULONG g_TargetQualifier;
  25. ULONG g_TargetBuild;
  26. ULONG g_TargetPlatform;
  27. //
  28. // Valid only during an extension API call
  29. //
  30. PDEBUG_ADVANCED g_ExtAdvanced;
  31. PDEBUG_CLIENT g_ExtClient;
  32. PDEBUG_DATA_SPACES3 g_ExtData;
  33. PDEBUG_REGISTERS g_ExtRegisters;
  34. PDEBUG_SYMBOLS2 g_ExtSymbols;
  35. PDEBUG_SYSTEM_OBJECTS3 g_ExtSystem;
  36. // Version 3 Interfaces
  37. PDEBUG_CONTROL3 g_ExtControl;
  38. // Queries for all debugger interfaces.
  39. extern "C" HRESULT
  40. ExtQuery(PDEBUG_CLIENT Client)
  41. {
  42. HRESULT Status;
  43. if ((Status = Client->QueryInterface(__uuidof(IDebugAdvanced),
  44. (void **)&g_ExtAdvanced)) != S_OK)
  45. {
  46. goto Fail;
  47. }
  48. if ((Status = Client->QueryInterface(__uuidof(IDebugDataSpaces3),
  49. (void **)&g_ExtData)) != S_OK)
  50. {
  51. goto Fail;
  52. }
  53. if ((Status = Client->QueryInterface(__uuidof(IDebugRegisters),
  54. (void **)&g_ExtRegisters)) != S_OK)
  55. {
  56. goto Fail;
  57. }
  58. if ((Status = Client->QueryInterface(__uuidof(IDebugSymbols),
  59. (void **)&g_ExtSymbols)) != S_OK)
  60. {
  61. goto Fail;
  62. }
  63. if ((Status = Client->QueryInterface(__uuidof(IDebugSystemObjects3),
  64. (void **)&g_ExtSystem)) != S_OK)
  65. {
  66. goto Fail;
  67. }
  68. if ((Status = Client->QueryInterface(__uuidof(IDebugControl3),
  69. (void **)&g_ExtControl)) != S_OK)
  70. {
  71. goto Fail;
  72. }
  73. g_ExtClient = Client;
  74. return S_OK;
  75. Fail:
  76. ExtRelease();
  77. return Status;
  78. }
  79. // Cleans up all debugger interfaces.
  80. void
  81. ExtRelease(void)
  82. {
  83. g_ExtClient = NULL;
  84. EXT_RELEASE(g_ExtAdvanced);
  85. EXT_RELEASE(g_ExtData);
  86. EXT_RELEASE(g_ExtRegisters);
  87. EXT_RELEASE(g_ExtSymbols);
  88. EXT_RELEASE(g_ExtSystem);
  89. EXT_RELEASE(g_ExtControl);
  90. }
  91. // Normal output.
  92. void __cdecl
  93. ExtOut(PCSTR Format, ...)
  94. {
  95. va_list Args;
  96. va_start(Args, Format);
  97. g_ExtControl->OutputVaList(DEBUG_OUTPUT_NORMAL, Format, Args);
  98. va_end(Args);
  99. }
  100. // Error output.
  101. void __cdecl
  102. ExtErr(PCSTR Format, ...)
  103. {
  104. va_list Args;
  105. va_start(Args, Format);
  106. g_ExtControl->OutputVaList(DEBUG_OUTPUT_ERROR, Format, Args);
  107. va_end(Args);
  108. }
  109. // Warning output.
  110. void __cdecl
  111. ExtWarn(PCSTR Format, ...)
  112. {
  113. va_list Args;
  114. va_start(Args, Format);
  115. g_ExtControl->OutputVaList(DEBUG_OUTPUT_WARNING, Format, Args);
  116. va_end(Args);
  117. }
  118. // Verbose output.
  119. void __cdecl
  120. ExtVerb(PCSTR Format, ...)
  121. {
  122. va_list Args;
  123. va_start(Args, Format);
  124. g_ExtControl->OutputVaList(DEBUG_OUTPUT_VERBOSE, Format, Args);
  125. va_end(Args);
  126. }
  127. extern "C"
  128. HRESULT
  129. CALLBACK
  130. DebugExtensionInitialize(PULONG Version, PULONG Flags)
  131. {
  132. IDebugClient *DebugClient;
  133. PDEBUG_CONTROL DebugControl;
  134. HRESULT Hr;
  135. *Version = DEBUG_EXTENSION_VERSION(1, 0);
  136. *Flags = 0;
  137. // Ignore errors as there are no critical routines required.
  138. InitDynamicCalls(&g_NtDllCallsDesc);
  139. if ((Hr = DebugCreate(__uuidof(IDebugClient),
  140. (void **)&DebugClient)) != S_OK)
  141. {
  142. return Hr;
  143. }
  144. if ((Hr = DebugClient->QueryInterface(__uuidof(IDebugControl),
  145. (void **)&DebugControl)) != S_OK)
  146. {
  147. return Hr;
  148. }
  149. ExtensionApis.nSize = sizeof (ExtensionApis);
  150. if ((Hr = DebugControl->GetWindbgExtensionApis64(&ExtensionApis)) != S_OK) {
  151. return Hr;
  152. }
  153. DebugControl->Release();
  154. DebugClient->Release();
  155. return S_OK;
  156. }
  157. extern "C"
  158. void
  159. CALLBACK
  160. DebugExtensionNotify(ULONG Notify, ULONG64 Argument)
  161. {
  162. //
  163. // The first time we actually connect to a target, get the page size
  164. //
  165. if ((Notify == DEBUG_NOTIFY_SESSION_ACCESSIBLE) && (!Connected))
  166. {
  167. IDebugClient *DebugClient;
  168. PDEBUG_DATA_SPACES DebugDataSpaces;
  169. PDEBUG_CONTROL DebugControl;
  170. HRESULT Hr;
  171. ULONG64 Page;
  172. if ((Hr = DebugCreate(__uuidof(IDebugClient),
  173. (void **)&DebugClient)) == S_OK)
  174. {
  175. //
  176. // Get the architecture type.
  177. //
  178. if ((Hr = DebugClient->QueryInterface(__uuidof(IDebugControl),
  179. (void **)&DebugControl)) == S_OK)
  180. {
  181. if ((Hr = DebugControl->GetActualProcessorType(
  182. &g_TargetMachine)) == S_OK)
  183. {
  184. Connected = TRUE;
  185. }
  186. ULONG MajorVer, SrvPack;
  187. if ((Hr = DebugControl->GetSystemVersion(
  188. &g_TargetPlatform, &MajorVer,
  189. &g_TargetBuild, NULL,
  190. 0, NULL,
  191. &SrvPack, NULL,
  192. 0, NULL)) == S_OK) {
  193. }
  194. ULONG Qualifier;
  195. if ((Hr = DebugControl->GetDebuggeeType(&g_TargetClass, &g_TargetQualifier)) == S_OK)
  196. {
  197. }
  198. ULONG EventType, EventProcess, EventThread;
  199. if (DebugControl->GetLastEventInformation(&EventType, &EventProcess, &EventThread,
  200. NULL, 0, NULL, NULL, 0, NULL) == S_OK)
  201. {
  202. }
  203. DebugControl->Release();
  204. }
  205. if (g_pTriager == NULL)
  206. {
  207. g_pTriager = new CTriager();
  208. }
  209. DebugClient->Release();
  210. }
  211. }
  212. if (Notify == DEBUG_NOTIFY_SESSION_INACTIVE)
  213. {
  214. Connected = FALSE;
  215. g_TargetMachine = 0;
  216. }
  217. return;
  218. }
  219. extern "C"
  220. void
  221. CALLBACK
  222. DebugExtensionUninitialize(void)
  223. {
  224. if (g_pTriager)
  225. {
  226. delete g_pTriager;
  227. g_pTriager = NULL;
  228. }
  229. UnInitializeDatabaseHandlers(TRUE);
  230. return;
  231. }
  232. DllInit(
  233. HANDLE hModule,
  234. DWORD dwReason,
  235. DWORD dwReserved
  236. )
  237. {
  238. switch (dwReason) {
  239. case DLL_THREAD_ATTACH:
  240. break;
  241. case DLL_THREAD_DETACH:
  242. break;
  243. case DLL_PROCESS_DETACH:
  244. DebugExtensionUninitialize();
  245. break;
  246. case DLL_PROCESS_ATTACH:
  247. break;
  248. }
  249. return TRUE;
  250. }
  251. void
  252. wchr2ansi(
  253. PWCHAR wstr,
  254. PCHAR astr
  255. )
  256. {
  257. do
  258. {
  259. *astr++ = (CHAR)*wstr++;
  260. } while (*wstr);
  261. }
  262. void
  263. ansi2wchr(
  264. const PCHAR astr,
  265. PWCHAR wstr
  266. )
  267. // both could point to same buffer
  268. {
  269. ULONG i = strlen(astr);
  270. do
  271. {
  272. wstr[i] = astr[i];
  273. } while (i--);
  274. }
  275. LegacyCommands()
  276. {
  277. dprintf("\n");
  278. dprintf(" !cxr !exr, and !trap have been replaced with the new built-in debugger \n");
  279. dprintf(" commands .cxr, .exr, .trap and .tss. There is also a new \".thread\" command. \n");
  280. dprintf("\n");
  281. dprintf(" These new commands no longer require symbols to work correctly.\n");
  282. dprintf("\n");
  283. dprintf(" Another change that comes with these new commands is that they actually\n");
  284. dprintf(" change the internal state of the debugger engine \"permanently\" (until\n");
  285. dprintf(" reverted). Any other debugger or extension command issued after the \n");
  286. dprintf(" \".cxr\", \".trap\" or \".thread\" command will be executed with the new context.\n");
  287. dprintf("\n");
  288. dprintf(" For example, commands such as stack walk (\"k\", \"kb\", \"kv\" ), \"r\" and \"dv\"\n");
  289. dprintf(" (show local variables) will all work based off the new context that was\n");
  290. dprintf(" supplied by \".cxr\", \".trap\" or \".thread\".\n");
  291. dprintf("\n");
  292. dprintf(" \".cxr\", \".trap\" and \".thread\" also apply to WinDBG:\n");
  293. dprintf(" using \".cxr\" , \".trap\" and \".thread\" will automatically show you the\n");
  294. dprintf(" new stack in the WinDBG stack window and allow you to click on a frame and\n");
  295. dprintf(" see local variables and source code (if source is available).\n");
  296. dprintf("\n");
  297. dprintf(" \".cxr\", \".trap\" or \".thread\" with no parameters will give you back the\n");
  298. dprintf(" default context that was in effect before the command was executed.\n");
  299. dprintf("\n");
  300. dprintf(" For example, to exactly duplicate \n");
  301. dprintf("\n");
  302. dprintf(" !cxr <foo> !trap <foo>\n");
  303. dprintf(" !kb !kb\n");
  304. dprintf("\n");
  305. dprintf(" you would now use\n");
  306. dprintf("\n");
  307. dprintf(" .cxr <foo> .trap <foo>\n");
  308. dprintf(" kb kb\n");
  309. dprintf(" .cxr .trap\n");
  310. dprintf("\n");
  311. return S_OK;
  312. }
  313. DECLARE_API ( cxr )
  314. {
  315. LegacyCommands();
  316. return S_OK;
  317. }
  318. DECLARE_API ( exr )
  319. {
  320. LegacyCommands();
  321. return S_OK;
  322. }
  323. DECLARE_API ( trap )
  324. {
  325. LegacyCommands();
  326. return S_OK;
  327. }
  328. DECLARE_API ( tss )
  329. {
  330. dprintf("\n");
  331. dprintf(" !tss has been replaced with the new built-in debugger command .tss.\n");
  332. dprintf("\n");
  333. return S_OK;
  334. }
  335. DECLARE_API ( sel )
  336. {
  337. dprintf("\n");
  338. dprintf(" !sel has been replaced with the built-in debugger command dg.\n");
  339. dprintf("\n");
  340. return S_OK;
  341. }
  342. DECLARE_API( cpuid )
  343. /*++
  344. Routine Description:
  345. Print out the version number for all CPUs, if available.
  346. Arguments:
  347. None
  348. Return Value:
  349. None
  350. --*/
  351. {
  352. ULONG64 Val;
  353. BOOL First = TRUE;
  354. ULONG Processor;
  355. ULONG NumProcessors;
  356. DEBUG_PROCESSOR_IDENTIFICATION_ALL IdAll;
  357. ULONG Mhz;
  358. INIT_API();
  359. if (g_ExtControl->GetNumberProcessors(&NumProcessors) != S_OK)
  360. {
  361. NumProcessors = 0;
  362. }
  363. if (GetExpressionEx(args, &Val, &args))
  364. {
  365. //
  366. // The user specified a procesor number.
  367. //
  368. Processor = (ULONG)Val;
  369. if (Processor >= NumProcessors)
  370. {
  371. dprintf("Invalid processor number specified\n");
  372. }
  373. else
  374. {
  375. NumProcessors = Processor + 1;
  376. }
  377. }
  378. else
  379. {
  380. //
  381. // Enumerate all the processors
  382. //
  383. Processor = 0;
  384. }
  385. while (Processor < NumProcessors)
  386. {
  387. if (g_ExtData->
  388. ReadProcessorSystemData(Processor,
  389. DEBUG_DATA_PROCESSOR_IDENTIFICATION,
  390. &IdAll, sizeof(IdAll), NULL) != S_OK)
  391. {
  392. dprintf("Unable to get information for processor %d\n",
  393. Processor);
  394. Processor++;
  395. continue;
  396. }
  397. if (g_ExtData->
  398. ReadProcessorSystemData(Processor,
  399. DEBUG_DATA_PROCESSOR_SPEED,
  400. &Mhz, sizeof(Mhz), NULL) != S_OK)
  401. {
  402. Mhz = 0;
  403. }
  404. switch( g_TargetMachine )
  405. {
  406. case IMAGE_FILE_MACHINE_I386:
  407. if (First)
  408. {
  409. dprintf("CP F/M/S Manufacturer");
  410. if (Mhz)
  411. {
  412. dprintf(" MHz");
  413. }
  414. dprintf("\n");
  415. }
  416. dprintf("%2d %2d,%d,%-2d %-16.16s",
  417. Processor,
  418. IdAll.X86.Family,
  419. IdAll.X86.Model,
  420. IdAll.X86.Stepping,
  421. IdAll.X86.VendorString);
  422. if (Mhz)
  423. {
  424. dprintf("%4d", Mhz);
  425. }
  426. dprintf("\n");
  427. break;
  428. case IMAGE_FILE_MACHINE_AMD64:
  429. if (First)
  430. {
  431. dprintf("CP F/M/S Manufacturer");
  432. if (Mhz)
  433. {
  434. dprintf(" MHz");
  435. }
  436. dprintf("\n");
  437. }
  438. dprintf("%2d %2d,%d,%-2d %-16.16s",
  439. Processor,
  440. IdAll.Amd64.Family,
  441. IdAll.Amd64.Model,
  442. IdAll.Amd64.Stepping,
  443. IdAll.Amd64.VendorString);
  444. if (Mhz)
  445. {
  446. dprintf("%4d", Mhz);
  447. }
  448. dprintf("\n");
  449. break;
  450. case IMAGE_FILE_MACHINE_IA64:
  451. if (First)
  452. {
  453. dprintf("CP M/R/F/A Manufacturer");
  454. if (Mhz)
  455. {
  456. dprintf(" MHz");
  457. }
  458. dprintf("\n");
  459. }
  460. dprintf("%2d %d,%d,%d,%d %-16.16s",
  461. Processor,
  462. IdAll.Ia64.Model,
  463. IdAll.Ia64.Revision,
  464. IdAll.Ia64.Family,
  465. IdAll.Ia64.ArchRev,
  466. IdAll.Ia64.VendorString);
  467. if (Mhz)
  468. {
  469. dprintf("%4d", Mhz);
  470. }
  471. dprintf("\n");
  472. break;
  473. default:
  474. dprintf("Not supported for this target machine: %ld\n",
  475. g_TargetMachine);
  476. Processor = NumProcessors;
  477. break;
  478. }
  479. Processor++;
  480. First = FALSE;
  481. }
  482. EXIT_API();
  483. return S_OK;
  484. }
  485. HRESULT
  486. PrintTargetString(
  487. BOOL Unicode,
  488. PDEBUG_CLIENT Client,
  489. LPCSTR args
  490. )
  491. {
  492. ULONG64 AddrString;
  493. ULONG64 Displacement;
  494. STRING32 String;
  495. UNICODE_STRING UnicodeString;
  496. ULONG64 AddrBuffer;
  497. CHAR Symbol[1024];
  498. LPSTR StringData;
  499. HRESULT hResult;
  500. BOOL b;
  501. AddrString = GetExpression(args);
  502. if (!AddrString)
  503. {
  504. return E_FAIL;
  505. }
  506. //
  507. // Get the symbolic name of the string
  508. //
  509. GetSymbol(AddrString, Symbol, &Displacement);
  510. //
  511. // Read the string from the debuggees address space into our
  512. // own.
  513. b = ReadMemory(AddrString, &String, sizeof(String), NULL);
  514. if ( !b )
  515. {
  516. return E_FAIL;
  517. }
  518. INIT_API();
  519. if (IsPtr64())
  520. {
  521. hResult = g_ExtData->ReadPointersVirtual(1,
  522. AddrString + FIELD_OFFSET(STRING64, Buffer),
  523. &AddrBuffer);
  524. }
  525. else
  526. {
  527. hResult = g_ExtData->ReadPointersVirtual(1,
  528. AddrString + FIELD_OFFSET(STRING32, Buffer),
  529. &AddrBuffer);
  530. }
  531. EXIT_API();
  532. if (hResult != S_OK)
  533. {
  534. return E_FAIL;
  535. }
  536. StringData = (LPSTR) LocalAlloc(LMEM_ZEROINIT,
  537. String.Length + sizeof(UNICODE_NULL));
  538. if (!StringData)
  539. {
  540. return E_FAIL;
  541. }
  542. dprintf("String(%d,%d)", String.Length, String.MaximumLength);
  543. if (Symbol[0])
  544. {
  545. dprintf(" %s+%p", Symbol, Displacement);
  546. }
  547. b = ReadMemory(AddrBuffer, StringData, String.Length, NULL);
  548. if ( b )
  549. {
  550. if (Unicode)
  551. {
  552. ANSI_STRING AnsiString;
  553. UnicodeString.Buffer = (PWSTR)StringData;
  554. UnicodeString.Length = String.Length;
  555. UnicodeString.MaximumLength = String.Length+sizeof(UNICODE_NULL);
  556. RtlUnicodeStringToAnsiString(&AnsiString, &UnicodeString,TRUE);
  557. dprintf(" at %p: %s\n", AddrString, AnsiString.Buffer);
  558. RtlFreeAnsiString(&AnsiString);
  559. }
  560. else
  561. {
  562. dprintf(" at %p: %s\n", AddrString, StringData);
  563. }
  564. LocalFree(StringData);
  565. return S_OK;
  566. }
  567. else
  568. {
  569. LocalFree(StringData);
  570. return E_FAIL;
  571. }
  572. }
  573. DECLARE_API( str )
  574. /*++
  575. Routine Description:
  576. This function is called to format and dump counted (ansi) string.
  577. Arguments:
  578. args - Address
  579. Return Value:
  580. None.
  581. --*/
  582. {
  583. return PrintTargetString(FALSE, Client, args);
  584. }
  585. DECLARE_API( ustr )
  586. /*++
  587. Routine Description:
  588. This function is called to format and dump counted (unicode) string.
  589. Arguments:
  590. args - Address
  591. Return Value:
  592. None.
  593. --*/
  594. {
  595. return PrintTargetString(TRUE, Client, args);
  596. }
  597. DECLARE_API( obja )
  598. /*++
  599. Routine Description:
  600. This function is called to format and dump an object attributes structure.
  601. Arguments:
  602. args - Address
  603. Return Value:
  604. None.
  605. --*/
  606. {
  607. ULONG64 AddrObja;
  608. ULONG64 Displacement;
  609. ULONG64 AddrString;
  610. STRING32 String;
  611. ULONG64 StrAddr = NULL;
  612. CHAR Symbol[1024];
  613. LPSTR StringData;
  614. BOOL b;
  615. ULONG Attr;
  616. HRESULT hResult;
  617. ULONG ObjectNameOffset;
  618. ULONG AttrOffset;
  619. ULONG StringOffset;
  620. if (IsPtr64())
  621. {
  622. ObjectNameOffset = FIELD_OFFSET(OBJECT_ATTRIBUTES64, ObjectName);
  623. AttrOffset = FIELD_OFFSET(OBJECT_ATTRIBUTES64, Attributes);
  624. StringOffset = FIELD_OFFSET(STRING64, Buffer);
  625. }
  626. else
  627. {
  628. ObjectNameOffset = FIELD_OFFSET(OBJECT_ATTRIBUTES32, ObjectName);
  629. AttrOffset = FIELD_OFFSET(OBJECT_ATTRIBUTES32, Attributes);
  630. StringOffset = FIELD_OFFSET(STRING32, Buffer);
  631. }
  632. AddrObja = GetExpression(args);
  633. if (!AddrObja)
  634. {
  635. return E_FAIL;
  636. }
  637. //
  638. // Get the symbolic name of the Obja
  639. //
  640. GetSymbol(AddrObja, Symbol, &Displacement);
  641. dprintf("Obja %s+%p at %p:\n", Symbol, Displacement, AddrObja);
  642. INIT_API();
  643. hResult = g_ExtData->ReadPointersVirtual(1,
  644. AddrObja + ObjectNameOffset,
  645. &AddrString);
  646. if ((hResult == S_OK) && AddrString)
  647. {
  648. b = ReadMemory(AddrString, &String, sizeof(String), NULL);
  649. hResult = g_ExtData->ReadPointersVirtual(1,
  650. AddrString + StringOffset,
  651. &StrAddr);
  652. }
  653. EXIT_API();
  654. if (!StrAddr)
  655. {
  656. dprintf("Could not read address of Object Name\n");
  657. return E_FAIL;
  658. }
  659. StringData = (LPSTR)LocalAlloc(LMEM_ZEROINIT,
  660. String.Length+sizeof(UNICODE_NULL));
  661. if (StringData)
  662. {
  663. b = ReadMemory(StrAddr, StringData, String.Length, NULL);
  664. if (b)
  665. {
  666. dprintf("\tName is %ws\n", StringData);
  667. }
  668. LocalFree(StringData);
  669. }
  670. b = ReadMemory(AddrObja + AttrOffset, &Attr, sizeof(Attr), NULL);
  671. if (!b)
  672. {
  673. return E_FAIL;
  674. }
  675. if (Attr & OBJ_INHERIT )
  676. {
  677. dprintf("\tOBJ_INHERIT\n");
  678. }
  679. if (Attr & OBJ_PERMANENT )
  680. {
  681. dprintf("\tOBJ_PERMANENT\n");
  682. }
  683. if (Attr & OBJ_EXCLUSIVE )
  684. {
  685. dprintf("\tOBJ_EXCLUSIVE\n");
  686. }
  687. if (Attr & OBJ_CASE_INSENSITIVE )
  688. {
  689. dprintf("\tOBJ_CASE_INSENSITIVE\n");
  690. }
  691. if (Attr & OBJ_OPENIF )
  692. {
  693. dprintf("\tOBJ_OPENIF\n");
  694. }
  695. return S_OK;
  696. }
  697. VOID
  698. DecodeErrorForMessage(
  699. PDEBUG_DECODE_ERROR pDecodeError
  700. )
  701. {
  702. PSTR Text;
  703. PSTR Source;
  704. BOOL TreatAsStatus = pDecodeError->TreatAsStatus;
  705. Text = FormatAnyStatus(pDecodeError->Code, NULL,
  706. &TreatAsStatus, &Source);
  707. pDecodeError->TreatAsStatus = TreatAsStatus;
  708. CopyString(pDecodeError->Source, Source, sizeof(pDecodeError->Source));
  709. CopyString(pDecodeError->Message, Text, sizeof(pDecodeError->Message));
  710. }
  711. VOID
  712. DecodeError(
  713. PSTR Banner,
  714. ULONG Code,
  715. BOOL TreatAsStatus
  716. )
  717. {
  718. DEBUG_DECODE_ERROR Err;
  719. Err.Code = Code;
  720. Err.TreatAsStatus = TreatAsStatus;
  721. DecodeErrorForMessage(&Err);
  722. if (!TreatAsStatus)
  723. {
  724. dprintf("%s: (%s) %#x (%u) - %s\n",
  725. Banner, Err.Source, Code, Code, Err.Message);
  726. }
  727. else
  728. {
  729. dprintf("%s: (%s) %#x - %s\n",
  730. Banner, Err.Source, Code, Err.Message);
  731. }
  732. }
  733. DECLARE_API( error )
  734. {
  735. BOOL TreatAsStatus = FALSE ;
  736. ULONG64 err = 0;
  737. if (GetExpressionEx( args, &err, &args ))
  738. {
  739. TreatAsStatus = (BOOL) GetExpression(args);
  740. }
  741. DecodeError( "Error code", (ULONG) err, TreatAsStatus );
  742. return S_OK;
  743. }
  744. typedef BOOL
  745. (CALLBACK *PENUMERATE_UMODE_THREADS_CALLBACK)(
  746. ULONG ThreadUserId,
  747. PVOID UserContext
  748. );
  749. ULONG GetCurrentThreadUserID(void)
  750. {
  751. ULONG Id;
  752. if (!g_ExtSystem) {
  753. return 0;
  754. }
  755. if (g_ExtSystem->GetCurrentThreadId(&Id) != S_OK) {
  756. return 0;
  757. }
  758. return Id;
  759. }
  760. BOOL
  761. EnumerateUModeThreads(
  762. PENUMERATE_UMODE_THREADS_CALLBACK Callback,
  763. PVOID UserContext
  764. )
  765. {
  766. ULONG CurrentThreadId;
  767. ULONG ThreadId;
  768. if (!g_ExtSystem) {
  769. return FALSE;
  770. }
  771. // Remember thread we started with
  772. if (g_ExtSystem->GetCurrentThreadId(&CurrentThreadId) != S_OK) {
  773. return FALSE;
  774. }
  775. // Loop through all threads
  776. for (ThreadId=0;;ThreadId++) {
  777. // set ThreadId as current thread
  778. if (g_ExtSystem->SetCurrentThreadId(ThreadId) != S_OK) {
  779. // finished enumerateing threads
  780. break;
  781. }
  782. // call the callback routine
  783. if (!((*Callback)(ThreadId, UserContext))) {
  784. // callback failed, break out
  785. break;
  786. }
  787. }
  788. // Set current thread back to original value
  789. g_ExtSystem->SetCurrentThreadId(CurrentThreadId);
  790. return TRUE;
  791. }
  792. BOOL
  793. DumpLastErrorForTeb(
  794. ULONG64 Address
  795. )
  796. {
  797. TEB Teb;
  798. if (ReadMemory( (ULONG_PTR)Address,
  799. &Teb,
  800. sizeof(Teb),
  801. NULL
  802. )
  803. ) {
  804. DecodeError( "LastErrorValue", Teb.LastErrorValue, FALSE );
  805. DecodeError( "LastStatusValue", Teb.LastStatusValue, TRUE );
  806. return TRUE;
  807. }
  808. dprintf("Unable to read TEB at %p\n", Address );
  809. return FALSE;
  810. }
  811. BOOL
  812. DumpCurrentThreadLastError(
  813. ULONG CurrThreadID,
  814. PVOID Context
  815. )
  816. {
  817. NTSTATUS Status;
  818. THREAD_BASIC_INFORMATION ThreadInformation;
  819. ULONGLONG Address = 0;
  820. if (Context) {
  821. dprintf("Last error for thread %lx:\n", CurrThreadID);
  822. }
  823. Address = GetExpression("@$teb");
  824. if (Address) {
  825. DumpLastErrorForTeb(Address);
  826. } else {
  827. dprintf("Unable to read thread %lx's TEB\n", CurrThreadID );
  828. }
  829. if (Context) {
  830. dprintf("\n");
  831. }
  832. return TRUE;
  833. }
  834. DECLARE_API( gle )
  835. {
  836. INIT_API();
  837. if (!strcmp(args, "-all")) {
  838. EnumerateUModeThreads(&DumpCurrentThreadLastError, Client);
  839. } else {
  840. DumpCurrentThreadLastError(GetCurrentThreadUserID(), NULL);
  841. }
  842. EXIT_API();
  843. return S_OK;
  844. }
  845. void
  846. DispalyTime(
  847. ULONG64 Time,
  848. PCHAR TimeString
  849. )
  850. {
  851. if (Time) {
  852. ULONG seconds = (ULONG) Time;
  853. ULONG minutes = seconds / 60;
  854. ULONG hours = minutes / 60;
  855. ULONG days = hours / 24;
  856. dprintf("%s %d days %d:%02d:%02d \n",
  857. TimeString,
  858. days, hours%24, minutes%60, seconds%60);
  859. }
  860. }
  861. extern PCHAR gTargetMode[], gAllOsTypes[];
  862. #if 1
  863. DECLARE_API( targetinfo )
  864. {
  865. TARGET_DEBUG_INFO TargetInfo;
  866. EXT_TARGET_INFO GetTargetInfo;
  867. INIT_API();
  868. if (g_ExtControl->GetExtensionFunction(0, "GetTargetInfo", (FARPROC *)&GetTargetInfo) == S_OK) {
  869. TargetInfo.SizeOfStruct = sizeof(TargetInfo);
  870. if ((*GetTargetInfo)(Client, &TargetInfo) != S_OK) {
  871. dprintf("GetTargetInfo failed\n");
  872. } else {
  873. const char * time;
  874. dprintf("TargetInfo: ");
  875. dprintf("%s\n", gTargetMode[ TargetInfo.Mode ]);
  876. if ((time = ctime((time_t *) &TargetInfo.CrashTime)) != NULL) {
  877. dprintf("Crash Time: %s", time);
  878. }
  879. if (TargetInfo.SysUpTime) {
  880. DispalyTime(TargetInfo.SysUpTime,
  881. "System Uptime:");
  882. }
  883. else
  884. {
  885. dprintf("System Uptime: not available\n");
  886. }
  887. if (TargetInfo.Mode == UserModeTarget) {
  888. DispalyTime(TargetInfo.AppUpTime, "Process Uptime:");
  889. }
  890. if ((time = ctime((time_t *) &TargetInfo.EntryDate)) != NULL) {
  891. dprintf("Entry Date: %s", time);
  892. }
  893. if (TargetInfo.OsInfo.Type) {
  894. dprintf(gAllOsTypes[TargetInfo.OsInfo.Type]);
  895. dprintf(" ");
  896. }
  897. // dprintf("OS Type %lx, Product %lx, Suite %lx\n",
  898. // TargetInfo.OsInfo.Type, TargetInfo.OsInfo.ProductType,
  899. // TargetInfo.OsInfo.Suite);
  900. dprintf("%s, %s ",
  901. TargetInfo.OsInfo.OsString,
  902. TargetInfo.OsInfo.ServicePackString);
  903. dprintf("Version %ld.%ld\n",
  904. TargetInfo.OsInfo.Version.Major, TargetInfo.OsInfo.Version.Minor);
  905. dprintf("%d procs, %d current processor, type %lx\n",
  906. TargetInfo.Cpu.NumCPUs,
  907. TargetInfo.Cpu.CurrentProc,
  908. TargetInfo.Cpu.Type);
  909. for (ULONG i =0; i<TargetInfo.Cpu.NumCPUs; i++) {
  910. if (TargetInfo.Cpu.Type == IMAGE_FILE_MACHINE_I386) {
  911. dprintf("CPU %lx Family %lx Model %lx Stepping %lx Vendor %-12.12s\n",
  912. i,
  913. TargetInfo.Cpu.ProcInfo[i].X86.Family,
  914. TargetInfo.Cpu.ProcInfo[i].X86.Model,
  915. TargetInfo.Cpu.ProcInfo[i].X86.Stepping,
  916. TargetInfo.Cpu.ProcInfo[i].X86.VendorString);
  917. } else if (TargetInfo.Cpu.Type == IMAGE_FILE_MACHINE_IA64) {
  918. dprintf("CPU %lx Family %lx Model %lx Revision %lx Vendor %-12.12s\n",
  919. i,
  920. TargetInfo.Cpu.ProcInfo[i].Ia64.Family,
  921. TargetInfo.Cpu.ProcInfo[i].Ia64.Model,
  922. TargetInfo.Cpu.ProcInfo[i].Ia64.Revision,
  923. TargetInfo.Cpu.ProcInfo[i].Ia64.VendorString);
  924. }
  925. }
  926. }
  927. }
  928. EXIT_API();
  929. return S_OK;
  930. }
  931. #endif
  932. DWORD
  933. _EFN_GetTriageFollowupFromSymbol(
  934. IN PDEBUG_CLIENT Client,
  935. IN PSTR SymbolName,
  936. OUT PDEBUG_TRIAGE_FOLLOWUP_INFO OwnerInfo
  937. )
  938. {
  939. DWORD ret;
  940. BOOL Enter = (g_ExtClient != Client);
  941. if (!Client && Enter)
  942. {
  943. return FALSE;
  944. }
  945. if (OwnerInfo->SizeOfStruct != sizeof(DEBUG_TRIAGE_FOLLOWUP_INFO))
  946. {
  947. return FALSE;
  948. }
  949. if (Enter)
  950. {
  951. INIT_API()
  952. }
  953. if (g_pTriager == NULL)
  954. {
  955. g_pTriager = new CTriager();
  956. }
  957. if (g_pTriager != NULL)
  958. {
  959. ret = g_pTriager->GetFollowup(OwnerInfo->OwnerName,
  960. OwnerInfo->OwnerNameSize,
  961. SymbolName);
  962. } else
  963. {
  964. ret = TRIAGE_FOLLOWUP_FAIL;
  965. }
  966. if (Enter)
  967. {
  968. EXIT_API();
  969. }
  970. return ret;
  971. }
  972. DECLARE_API( owner )
  973. {
  974. CHAR Input[2000];
  975. CHAR Owner[200];
  976. ULONG status = TRIAGE_FOLLOWUP_DEFAULT;
  977. PDEBUG_FAILURE_ANALYSIS pAnalysis = NULL;
  978. FA_ENTRY* Entry;
  979. INIT_API();
  980. Input[0] = 0;
  981. if (!sscanf(args, "%s", Input))
  982. {
  983. Input[0] = 0;
  984. }
  985. //
  986. // If we have a string, look for that - otherwise, do an analysis and
  987. // get the followup string from that.
  988. //
  989. if (*Input)
  990. {
  991. status = g_pTriager->GetFollowup(Owner, sizeof(Owner), Input);
  992. }
  993. else
  994. {
  995. _EFN_GetFailureAnalysis(Client, 0, &pAnalysis);
  996. if (pAnalysis)
  997. {
  998. Entry = pAnalysis->Get(DEBUG_FLR_FOLLOWUP_NAME);
  999. CopyString(Owner, FA_ENTRY_DATA(PCHAR, Entry), sizeof(Owner));
  1000. pAnalysis->Release();
  1001. status = TRIAGE_FOLLOWUP_SUCCESS;
  1002. }
  1003. }
  1004. if (status == TRIAGE_FOLLOWUP_FAIL)
  1005. {
  1006. dprintf("Internal error getting followup - contact Debugger team\n");
  1007. }
  1008. else
  1009. {
  1010. dprintf("Followup: %s\n", Owner);
  1011. }
  1012. EXIT_API();
  1013. return S_OK;
  1014. }
  1015. void
  1016. _EFN_DecodeError(
  1017. PDEBUG_DECODE_ERROR pDecodeError
  1018. )
  1019. {
  1020. if (pDecodeError->SizeOfStruct != sizeof(DEBUG_DECODE_ERROR))
  1021. {
  1022. return;
  1023. }
  1024. return DecodeErrorForMessage(pDecodeError);
  1025. }
  1026. DECLARE_API( elog_str )
  1027. {
  1028. HANDLE EventSource = NULL;
  1029. INIT_API();
  1030. if (args)
  1031. {
  1032. while (isspace(*args))
  1033. {
  1034. args++;
  1035. }
  1036. }
  1037. if (!args || !args[0])
  1038. {
  1039. Status = E_INVALIDARG;
  1040. ExtErr("Usage: elog_str string\n");
  1041. goto Exit;
  1042. }
  1043. // Get a handle to the NT application log.
  1044. EventSource = OpenEventLog(NULL, "Application");
  1045. if (!EventSource)
  1046. {
  1047. Status = HRESULT_FROM_WIN32(GetLastError());
  1048. ExtErr("Unable to open event log, 0x%08X\n", Status);
  1049. goto Exit;
  1050. }
  1051. if (!ReportEvent(EventSource, EVENTLOG_ERROR_TYPE, 0, 0, NULL,
  1052. 1, 0, &args, NULL))
  1053. {
  1054. Status = HRESULT_FROM_WIN32(GetLastError());
  1055. ExtErr("Unable to report event, 0x%08X\n", Status);
  1056. goto Exit;
  1057. }
  1058. Status = S_OK;
  1059. Exit:
  1060. if (EventSource)
  1061. {
  1062. CloseEventLog(EventSource);
  1063. }
  1064. EXIT_API();
  1065. return Status;
  1066. }
  1067. HRESULT
  1068. AnsiToUnicode(PCSTR StrA, PWSTR* StrW)
  1069. {
  1070. ULONG Len;
  1071. // No input is an error.
  1072. if (NULL == StrA)
  1073. {
  1074. return E_INVALIDARG;
  1075. }
  1076. Len = strlen(StrA) + 1;
  1077. *StrW = (PWSTR)malloc(Len * sizeof(WCHAR));
  1078. if (*StrW == NULL)
  1079. {
  1080. ExtErr("Unable to allocate memory\n");
  1081. return E_OUTOFMEMORY;
  1082. }
  1083. if (0 == MultiByteToWideChar(CP_ACP, 0, StrA, Len, *StrW, Len))
  1084. {
  1085. HRESULT Status = HRESULT_FROM_WIN32(GetLastError());
  1086. free(*StrW);
  1087. ExtErr("Unable to convert string, 0x%08X\n", Status);
  1088. return Status;
  1089. }
  1090. return S_OK;
  1091. }
  1092. typedef NET_API_STATUS (NET_API_FUNCTION* PFN_NetMessageBufferSend)
  1093. (
  1094. IN LPCWSTR servername,
  1095. IN LPCWSTR msgname,
  1096. IN LPCWSTR fromname,
  1097. IN LPBYTE buf,
  1098. IN DWORD buflen
  1099. );
  1100. DECLARE_API( net_send )
  1101. {
  1102. PWSTR ArgsW = NULL;
  1103. PWSTR Tokens[4];
  1104. ULONG i;
  1105. HMODULE NetLib = NULL;
  1106. PFN_NetMessageBufferSend Send;
  1107. ULONG Result;
  1108. PWSTR ArgsEnd;
  1109. INIT_API();
  1110. NetLib = LoadLibrary("netapi32.dll");
  1111. if (!NetLib)
  1112. {
  1113. Status = HRESULT_FROM_WIN32(GetLastError());
  1114. ExtErr("Platform does not support net send\n");
  1115. goto Exit;
  1116. }
  1117. Send = (PFN_NetMessageBufferSend)
  1118. GetProcAddress(NetLib, "NetMessageBufferSend");
  1119. if (!Send)
  1120. {
  1121. Status = E_NOTIMPL;
  1122. ExtErr("Platform does not support net send\n");
  1123. goto Exit;
  1124. }
  1125. Status = AnsiToUnicode(args, &ArgsW);
  1126. if (Status != S_OK)
  1127. {
  1128. goto Exit;
  1129. }
  1130. ArgsEnd = ArgsW + wcslen(ArgsW);
  1131. // The message text is the entire remainder of the argument
  1132. // string after parsing the first separate tokens, so
  1133. // only wcstok up to the next-to-last token.
  1134. for (i = 0; i < sizeof(Tokens) / sizeof(Tokens[0]) - 1; i++)
  1135. {
  1136. Tokens[i] = wcstok(i == 0 ? ArgsW : NULL, L" \t");
  1137. if (Tokens[i] == NULL)
  1138. {
  1139. Status = E_INVALIDARG;
  1140. ExtErr("USAGE: net_send <targetserver> <targetuser> "
  1141. "<fromuser> <msg>\n");
  1142. goto Exit;
  1143. }
  1144. }
  1145. Tokens[i] = Tokens[i - 1] + wcslen(Tokens[i - 1]) + 1;
  1146. while (Tokens[i] < ArgsEnd &&
  1147. (*Tokens[i] == ' ' || *Tokens[i] == '\t'))
  1148. {
  1149. Tokens[i]++;
  1150. }
  1151. if (Tokens[i] >= ArgsEnd)
  1152. {
  1153. Status = E_INVALIDARG;
  1154. ExtErr("USAGE: net_send <execmachine> <targetmachine> "
  1155. "<sender> <msg>\n");
  1156. goto Exit;
  1157. }
  1158. Result = Send(Tokens[0], Tokens[1], Tokens[2], (PBYTE)Tokens[3],
  1159. (wcslen(Tokens[3]) + 1) * sizeof(WCHAR));
  1160. if (Result != NERR_Success)
  1161. {
  1162. Status = HRESULT_FROM_WIN32(Result);;
  1163. ExtErr("Unable to send message, 0x%08X\n", Status);
  1164. goto Exit;
  1165. }
  1166. Status = S_OK;
  1167. Exit:
  1168. if (ArgsW)
  1169. {
  1170. free(ArgsW);
  1171. }
  1172. if (NetLib)
  1173. {
  1174. FreeLibrary(NetLib);
  1175. }
  1176. EXIT_API();
  1177. return Status;
  1178. }
  1179. // XXX drewb - This function just starts a mail message; the
  1180. // UI comes up and the user must finish and send the message.
  1181. // Therefore it doesn't have much value over the
  1182. // user just deciding to send a message.
  1183. #if 0
  1184. typedef ULONG (FAR PASCAL *PFN_MapiSendMail)
  1185. (
  1186. LHANDLE lhSession,
  1187. ULONG ulUIParam,
  1188. lpMapiMessage lpMessage,
  1189. FLAGS flFlags,
  1190. ULONG ulReserved
  1191. );
  1192. DECLARE_API( mapi_send )
  1193. {
  1194. HMODULE MapiLib = NULL;
  1195. PFN_MapiSendMail Send;
  1196. MapiMessage Mail;
  1197. INIT_API();
  1198. MapiLib = LoadLibrary("mapi.dll");
  1199. if (!MapiLib)
  1200. {
  1201. Status = HRESULT_FROM_WIN32(GetLastError());
  1202. ExtErr("Platform does not support MAPI\n");
  1203. goto Exit;
  1204. }
  1205. Send = (PFN_MapiSendMail)
  1206. GetProcAddress(MapiLib, "MAPISendMail");
  1207. if (!Send)
  1208. {
  1209. Status = E_NOTIMPL;
  1210. ExtErr("Platform does not support MAPI\n");
  1211. goto Exit;
  1212. }
  1213. ZeroMemory(&Mail, sizeof(Mail));
  1214. if (!Send(0, // use implicit session.
  1215. 0, // ulUIParam; 0 is always valid
  1216. &Mail, // the message being sent
  1217. MAPI_DIALOG, // allow the user to edit the message
  1218. 0 // reserved; must be 0
  1219. ))
  1220. {
  1221. Status = E_FAIL;
  1222. ExtErr("Unable to send mail\n");
  1223. goto Exit;
  1224. }
  1225. Status = S_OK;
  1226. Exit:
  1227. if (MapiLib)
  1228. {
  1229. FreeLibrary(MapiLib);
  1230. }
  1231. EXIT_API();
  1232. return Status;
  1233. }
  1234. #endif
  1235. DECLARE_API( imggp )
  1236. {
  1237. ULONG64 ImageBase;
  1238. IMAGE_NT_HEADERS64 NtHdr;
  1239. INIT_API();
  1240. ImageBase = GetExpression(args);
  1241. if (g_ExtData->ReadImageNtHeaders(ImageBase, &NtHdr) != S_OK)
  1242. {
  1243. ExtErr("Unable to read image header at %p\n", ImageBase);
  1244. goto Exit;
  1245. }
  1246. if (NtHdr.OptionalHeader.Magic != IMAGE_NT_OPTIONAL_HDR64_MAGIC)
  1247. {
  1248. ExtErr("Image is not 64-bit\n");
  1249. goto Exit;
  1250. }
  1251. if (NtHdr.OptionalHeader.NumberOfRvaAndSizes <=
  1252. IMAGE_DIRECTORY_ENTRY_GLOBALPTR)
  1253. {
  1254. ExtErr("Image does not have a GP directory entry\n");
  1255. goto Exit;
  1256. }
  1257. ExtOut("Image at %p has a GP value of %p\n",
  1258. ImageBase, ImageBase +
  1259. NtHdr.OptionalHeader.DataDirectory
  1260. [IMAGE_DIRECTORY_ENTRY_GLOBALPTR].VirtualAddress);
  1261. Exit:
  1262. EXIT_API();
  1263. return S_OK;
  1264. }
  1265. DECLARE_API( imgreloc )
  1266. {
  1267. ULONG64 ImageBase;
  1268. IMAGE_NT_HEADERS64 NtHdr;
  1269. ULONG NumMod;
  1270. ULONG i;
  1271. PDEBUG_MODULE_PARAMETERS Mod = NULL;
  1272. INIT_API();
  1273. ImageBase = GetExpression(args);
  1274. if (g_ExtSymbols->GetNumberModules(&NumMod, &i) != S_OK ||
  1275. !(Mod = (PDEBUG_MODULE_PARAMETERS)malloc(NumMod * sizeof(*Mod))) ||
  1276. g_ExtSymbols->GetModuleParameters(NumMod, NULL, 0, Mod) != S_OK)
  1277. {
  1278. ExtErr("Unable to get module information\n");
  1279. goto Exit;
  1280. }
  1281. for (i = 0; i < NumMod; i++)
  1282. {
  1283. char Name[MAX_PATH];
  1284. if (g_ExtData->ReadImageNtHeaders(Mod[i].Base, &NtHdr) != S_OK)
  1285. {
  1286. ExtErr("Unable to read image header at %p\n", Mod[i].Base);
  1287. continue;
  1288. }
  1289. if (FAILED(g_ExtSymbols->
  1290. GetModuleNames(DEBUG_ANY_ID, Mod[i].Base,
  1291. NULL, 0, NULL,
  1292. Name, sizeof(Name), NULL,
  1293. NULL, 0, NULL)))
  1294. {
  1295. StringCchCopy(Name, sizeof(Name), "<Error>");
  1296. }
  1297. ExtOut("%p %s - ", Mod[i].Base, Name);
  1298. if (NtHdr.OptionalHeader.ImageBase != Mod[i].Base)
  1299. {
  1300. ExtOut("RELOCATED from %p\n",
  1301. NtHdr.OptionalHeader.ImageBase);
  1302. }
  1303. else
  1304. {
  1305. ExtOut("at preferred address\n");
  1306. }
  1307. }
  1308. Exit:
  1309. free(Mod);
  1310. EXIT_API();
  1311. return S_OK;
  1312. }
  1313. VOID
  1314. GetNtTimeStamp(
  1315. PULONG TimeStamp
  1316. )
  1317. {
  1318. ULONG64 ModBase;
  1319. IMAGE_NT_HEADERS64 NtHdr;
  1320. if (!TimeStamp)
  1321. {
  1322. return;
  1323. }
  1324. if (g_ExtSymbols->GetModuleByModuleName("nt", 0, NULL, &ModBase) != S_OK)
  1325. {
  1326. return;
  1327. }
  1328. NtHdr.FileHeader.TimeDateStamp = 0;
  1329. if (g_ExtData->ReadImageNtHeaders(ModBase, &NtHdr) != S_OK)
  1330. {
  1331. return;
  1332. }
  1333. *TimeStamp = NtHdr.FileHeader.TimeDateStamp;
  1334. }
  1335. VOID
  1336. GetSkuFromProductType(
  1337. ULONG ProductType,
  1338. ULONG Suite,
  1339. PULONG pSku
  1340. )
  1341. {
  1342. ULONG Sku = 0;
  1343. if (!pSku)
  1344. {
  1345. return;
  1346. }
  1347. *pSku = 0;
  1348. if (ProductType == VER_NT_WORKSTATION)
  1349. {
  1350. if (Suite & VER_SUITE_PERSONAL)
  1351. {
  1352. Sku = CiOsHomeEdition;
  1353. }
  1354. else
  1355. {
  1356. Sku = CiOsProfessional;
  1357. }
  1358. }
  1359. else
  1360. {
  1361. if (Suite & VER_SUITE_DATACENTER)
  1362. {
  1363. Sku = CiOsDataCenter;
  1364. }
  1365. else if (Suite & VER_SUITE_ENTERPRISE)
  1366. {
  1367. Sku = CiOsAdvancedServer;
  1368. }
  1369. else if (Suite & VER_SUITE_BLADE)
  1370. {
  1371. Sku = CiOsWebServer;
  1372. }
  1373. else
  1374. {
  1375. Sku = CiOsServer;
  1376. }
  1377. }
  1378. *pSku = Sku;
  1379. }
  1380. HRESULT
  1381. InitializeCrashInstance(
  1382. PCRASH_INSTANCE pCrash
  1383. )
  1384. {
  1385. return 0;
  1386. }
  1387. PCHAR
  1388. GetLogFileName(
  1389. void
  1390. )
  1391. {
  1392. static CHAR szLogFileName[MAX_PATH+50];
  1393. PCHAR ExeDir;
  1394. ExeDir = &szLogFileName[0];
  1395. *ExeDir = 0;
  1396. // Get the directory the debugger executable is in.
  1397. if (!GetModuleFileName(NULL, ExeDir, MAX_PATH))
  1398. {
  1399. // Error. Use the current directory.
  1400. StringCchCopy(ExeDir, sizeof(szLogFileName), ".");
  1401. } else
  1402. {
  1403. // Remove the executable name.
  1404. PCHAR pszTmp = strrchr(ExeDir, '\\');
  1405. if (pszTmp)
  1406. {
  1407. *pszTmp = 0;
  1408. }
  1409. }
  1410. StringCchCat(ExeDir, sizeof(szLogFileName), "\\FailedAddCrash.log");
  1411. return &szLogFileName[0];
  1412. }
  1413. #define DB_LOOKUP_CRASH 1
  1414. #define DB_ADD_CRASH 2
  1415. #define DB_RETRIAGE_CRASH 4
  1416. #define DB_PRINT_CRASH 8
  1417. #define DB_SEND_MAIL 0x10
  1418. #define DB_NO_CUSTOMER 0x20
  1419. HRESULT
  1420. AddCrashToDB(
  1421. ULONG Flag,
  1422. PCRASH_INSTANCE pCrash
  1423. )
  1424. {
  1425. HRESULT Hr;
  1426. CrashDatabaseHandler *CrDb;
  1427. PDEBUG_FAILURE_ANALYSIS Analysis;
  1428. CHAR Bucket[100], Followup[50], DefaultBucket[100], Driver[100];
  1429. TARGET_DEBUG_INFO TargetInfo;
  1430. BOOL AddCrash = Flag & DB_ADD_CRASH;
  1431. BOOL LookupCrash = Flag & DB_LOOKUP_CRASH;
  1432. if ((Hr = _EFN_GetFailureAnalysis(g_ExtClient,
  1433. 0,
  1434. &Analysis)) != S_OK)
  1435. {
  1436. return Hr;
  1437. }
  1438. // Construct CRASH_INSTANCE
  1439. Followup[0] = Bucket[0] = Driver[0] = 0;
  1440. Analysis->GetString(DEBUG_FLR_BUCKET_ID,
  1441. Bucket,
  1442. sizeof(Bucket));
  1443. Analysis->GetString(DEBUG_FLR_DEFAULT_BUCKET_ID,
  1444. DefaultBucket,
  1445. sizeof(DefaultBucket));
  1446. Analysis->GetString(DEBUG_FLR_FOLLOWUP_NAME,
  1447. Followup,
  1448. sizeof(Followup));
  1449. Analysis->GetString(DEBUG_FLR_IMAGE_NAME,
  1450. Driver,
  1451. sizeof(Driver));
  1452. if (!isprint(Driver[0]))
  1453. {
  1454. Driver[0] = 0;
  1455. }
  1456. if (Analysis->Get(DEBUG_FLR_CPU_OVERCLOCKED))
  1457. {
  1458. pCrash->OverClocked = TRUE;
  1459. }
  1460. else
  1461. {
  1462. pCrash->OverClocked = FALSE;
  1463. }
  1464. pCrash->StopCode = Analysis->GetFailureCode();
  1465. pCrash->FailureType = Analysis->GetFailureType();
  1466. pCrash->SolutionType = CiSolUnsolved;
  1467. Analysis->GetUlong(DEBUG_FLR_SOLUTION_ID, &pCrash->SolutionId);
  1468. Analysis->GetUlong(DEBUG_FLR_SOLUTION_TYPE, (PULONG) &pCrash->SolutionType);
  1469. Analysis->GetUlong(DEBUG_FLR_DEFAULT_SOLUTION_ID, &pCrash->GenericSolId);
  1470. Analysis->Release();
  1471. if (!Followup[0] || !Bucket[0])
  1472. {
  1473. return E_FAIL;
  1474. }
  1475. pCrash->Build = g_TargetBuild; // make room for service pack
  1476. if (pCrash->Bucket)
  1477. {
  1478. StringCchCopy(pCrash->Bucket, pCrash->BucketSize, Bucket);
  1479. } else
  1480. {
  1481. pCrash->Bucket = Bucket;
  1482. pCrash->BucketSize = sizeof(Bucket);
  1483. }
  1484. if (pCrash->DefaultBucket)
  1485. {
  1486. StringCchCopy(pCrash->DefaultBucket, pCrash->DefaultBucketSize, DefaultBucket);
  1487. } else
  1488. {
  1489. pCrash->DefaultBucket = DefaultBucket;
  1490. pCrash->DefaultBucketSize = sizeof(DefaultBucket);
  1491. }
  1492. pCrash->Followup = Followup;
  1493. pCrash->FaultyDriver = Driver;
  1494. pCrash->DumpClass = g_TargetQualifier;
  1495. // GetNtTimeStamp(&pCrash->NtTimeStamp);
  1496. //
  1497. // extract the incident ID from the dump name
  1498. // there are 2 types of filenames we could have to support.
  1499. // The old version is id@*.*
  1500. // The new version is id.*
  1501. //
  1502. CHAR FileName[MAX_PATH];
  1503. DWORD ID;
  1504. _splitpath(pCrash->Path, NULL, NULL, FileName, NULL);
  1505. //
  1506. // Extract the name of the original dump file in the cab.
  1507. //
  1508. pCrash->OriginalDumpFileName = NULL;
  1509. if (g_ExtSystem->GetCurrentSystemServerName(FileName, sizeof(FileName),
  1510. NULL) == S_OK)
  1511. {
  1512. pCrash->OriginalDumpFileName = strrchr(FileName, '_');
  1513. if (pCrash->OriginalDumpFileName)
  1514. {
  1515. pCrash->OriginalDumpFileName +=1;
  1516. }
  1517. }
  1518. TargetInfo.SizeOfStruct = sizeof(TARGET_DEBUG_INFO);
  1519. if (FillTargetDebugInfo(g_ExtClient, &TargetInfo) == S_OK)
  1520. {
  1521. switch (TargetInfo.Cpu.Type)
  1522. {
  1523. case IMAGE_FILE_MACHINE_I386:
  1524. pCrash->CpuId =
  1525. (TargetInfo.Cpu.ProcInfo[0].X86.Family << 16) |
  1526. (TargetInfo.Cpu.ProcInfo[0].X86.Model << 8) |
  1527. (TargetInfo.Cpu.ProcInfo[0].X86.Stepping);
  1528. break;
  1529. case IMAGE_FILE_MACHINE_IA64:
  1530. pCrash->CpuId =
  1531. (TargetInfo.Cpu.ProcInfo[0].Ia64.Family << 16) |
  1532. (TargetInfo.Cpu.ProcInfo[0].Ia64.Model << 8) |
  1533. (TargetInfo.Cpu.ProcInfo[0].Ia64.Revision);
  1534. break;
  1535. case IMAGE_FILE_MACHINE_AMD64:
  1536. pCrash->CpuId =
  1537. (TargetInfo.Cpu.ProcInfo[0].Amd64.Family << 16) |
  1538. (TargetInfo.Cpu.ProcInfo[0].Amd64.Model << 8) |
  1539. (TargetInfo.Cpu.ProcInfo[0].Amd64.Stepping);
  1540. break;
  1541. }
  1542. pCrash->CpuType = TargetInfo.Cpu.Type;
  1543. pCrash->NumProc = TargetInfo.Cpu.NumCPUs;
  1544. pCrash->UpTime = (ULONG) TargetInfo.SysUpTime;
  1545. pCrash->CrashTime = (ULONG) TargetInfo.CrashTime;
  1546. pCrash->ServicePack =
  1547. (TargetInfo.OsInfo.SrvPackNumber & 0xFFFF0000) ?
  1548. (TargetInfo.OsInfo.SrvPackNumber & 0xFFFF0000) >> 16 :
  1549. ((TargetInfo.OsInfo.SrvPackNumber & 0xFFFF) >> 8) * 1000;
  1550. GetSkuFromProductType(TargetInfo.OsInfo.ProductType,
  1551. TargetInfo.OsInfo.Suite,
  1552. (PULONG) &pCrash->Sku);
  1553. if (Flag & DB_PRINT_CRASH)
  1554. {
  1555. dprintf("CRASH DATA FOR DB\n----------------------\n");
  1556. dprintf("CrashId : %ld - %ld\n", pCrash->CrashTime , pCrash->UpTime);
  1557. dprintf("BucketId : %s\n", pCrash->Bucket);
  1558. dprintf("FollowUp : %s\n", pCrash->Followup);
  1559. dprintf("Build : %u\n", pCrash->Build);
  1560. dprintf("CpuId : %ld - %ld\n", pCrash->uCpu >> 32, (ULONG) pCrash->uCpu);
  1561. dprintf("Overclocked : %s\n", pCrash->OverClocked ? "TRUE" : "FALSE");
  1562. }
  1563. }
  1564. if (!(Flag & ~DB_PRINT_CRASH))
  1565. {
  1566. return S_OK;
  1567. }
  1568. pCrash->bSendMail = Flag & DB_SEND_MAIL;
  1569. pCrash->bUpdateCustomer = FALSE; // Disable customer DB
  1570. if (AddCrash && !(Flag & DB_RETRIAGE_CRASH))
  1571. {
  1572. Hr = _EFN_DbAddCrashDirect(pCrash, g_ExtControl);
  1573. }
  1574. else if (Flag & DB_RETRIAGE_CRASH)
  1575. {
  1576. // reset crash bucket mapping
  1577. pCrash->bResetBucket = TRUE;
  1578. pCrash->bUpdateCustomer = !(Flag & DB_NO_CUSTOMER);
  1579. Hr = _EFN_DbAddCrashDirect(pCrash, g_ExtControl);
  1580. }
  1581. else if (LookupCrash)
  1582. {
  1583. CHAR SolText[ SOLUTION_TEXT_SIZE ], OSVer[ OS_VER_SIZE ];
  1584. ULONG Count=0;
  1585. CCrashInstance CrashInstance;
  1586. if ((Hr = InitializeDatabaseHandlers(g_ExtControl, 7)) != S_OK)
  1587. {
  1588. return Hr;
  1589. }
  1590. g_CrDb->BuildQueryForCrashInstance(pCrash);
  1591. g_CrDb->m_pADOResult = &CrashInstance;
  1592. g_CrDb->m_fPrintIt = TRUE;
  1593. g_CrDb->GetRecords(&Count, TRUE);
  1594. if (Count)
  1595. {
  1596. dprintf("This crash has already been added to database\n");
  1597. CrashInstance.OutPut();
  1598. }
  1599. g_CrDb->m_fPrintIt = FALSE;
  1600. if (g_SolDb->GetSolution(pCrash) == S_OK)
  1601. {
  1602. dprintf("Solution found for bucket:\n%s\n", SolText);
  1603. }
  1604. }
  1605. return Hr;
  1606. }
  1607. DECLARE_API( dbaddcrash )
  1608. {
  1609. CHAR Path[MAX_PATH]={0};
  1610. CHAR CrashGUID[50] = {0};
  1611. CHAR MQConnectStr[100] = {0};
  1612. CHAR SrNumber[100] = {0};
  1613. CRASH_INSTANCE Crash = {0};
  1614. CHAR Buffer[50];
  1615. BOOL Retriage = FALSE;
  1616. BOOL Print = FALSE;
  1617. BOOL bParseError = FALSE;
  1618. ULONG Flag = 0;
  1619. HRESULT Hr;
  1620. PCSTR argssave = args;
  1621. INIT_API();
  1622. while (*args)
  1623. {
  1624. if (*args == ' ' || *args == '\t')
  1625. {
  1626. ++args;
  1627. continue;
  1628. }
  1629. else if (*args == '-' || *args == '/')
  1630. {
  1631. ++args;
  1632. switch (*args)
  1633. {
  1634. case 'g': // GUID identifying this crash, return bucket along with this
  1635. ++args;
  1636. while (*args == ' ') ++args;
  1637. if (!sscanf(args,"%50s", CrashGUID))
  1638. {
  1639. CrashGUID[0] = 0;
  1640. }
  1641. args+=strlen(CrashGUID);
  1642. Crash.MesgGuid = CrashGUID;
  1643. break;
  1644. case 'm':
  1645. if (!strncmp(args, "mail", 4))
  1646. {
  1647. Flag |= DB_SEND_MAIL ;
  1648. args+=4;
  1649. }
  1650. break;
  1651. case 'n':
  1652. if (!strncmp(args, "nocust", 6))
  1653. {
  1654. Flag |= DB_NO_CUSTOMER ;
  1655. args+=6;
  1656. }
  1657. break;
  1658. case 'o':
  1659. Print = TRUE;
  1660. break;
  1661. case 'p':
  1662. ++args;
  1663. while (*args == ' ') ++args;
  1664. if (!sscanf(args,"%240s", Path))
  1665. {
  1666. Path[0] = 0;
  1667. }
  1668. args+=strlen(Path);
  1669. Crash.Path = Path;
  1670. break;
  1671. case 'r':
  1672. if (!strncmp(args, "retriage", 8))
  1673. {
  1674. Retriage = TRUE;
  1675. args+=8;
  1676. }
  1677. break;
  1678. case 's': // queue connection string to send bucketid back
  1679. if (!strncmp(args, "source", 6))
  1680. {
  1681. ULONG Source;
  1682. args+=6;
  1683. while (*args == ' ') ++args;
  1684. if (isdigit(*args))
  1685. {
  1686. Source = atoi(args);
  1687. if (Source < (ULONG) CiSrcMax)
  1688. {
  1689. Crash.SourceId = (CI_SOURCE) Source;
  1690. }
  1691. while (isdigit(*args)) ++args;
  1692. }
  1693. } else if (!strncmp(args, "sr", 2))
  1694. {
  1695. args+=2;
  1696. while (*args == ' ') ++args;
  1697. if (!sscanf(args,"%100s", SrNumber))
  1698. {
  1699. SrNumber[0] = 0;
  1700. }
  1701. args+= strlen(SrNumber);
  1702. Crash.PssSr = SrNumber;
  1703. } else
  1704. {
  1705. ++args;
  1706. while (*args == ' ') ++args;
  1707. if (!sscanf(args,"%100s", MQConnectStr))
  1708. {
  1709. MQConnectStr[0] = 0;
  1710. }
  1711. args+=strlen(MQConnectStr);
  1712. Crash.MqConnectStr = MQConnectStr;
  1713. }
  1714. break;
  1715. default:
  1716. ++args;
  1717. break;
  1718. }
  1719. }
  1720. else
  1721. {
  1722. dprintf("Error in '%s'\n", args);
  1723. bParseError = TRUE;
  1724. break;
  1725. }
  1726. }
  1727. if (*Path && !bParseError)
  1728. {
  1729. if (Retriage)
  1730. {
  1731. dprintf("Retriag crash\n");
  1732. Hr = AddCrashToDB(DB_RETRIAGE_CRASH | Flag, &Crash);
  1733. }
  1734. else
  1735. {
  1736. Hr = AddCrashToDB(DB_ADD_CRASH | Flag, &Crash);
  1737. }
  1738. }
  1739. else if (Print && !bParseError)
  1740. {
  1741. Hr = AddCrashToDB(DB_PRINT_CRASH, NULL);
  1742. }
  1743. else
  1744. {
  1745. dprintf("Bad argument: %s\n", argssave);
  1746. dprintf("Usage: !dbaddcrash -o -mail -p <dumppath> -retriage\n");
  1747. Hr = E_FAIL;
  1748. }
  1749. if (FAILED (Hr))
  1750. {
  1751. int g_LogFile;
  1752. g_LogFile = _open(GetLogFileName(), O_APPEND | O_CREAT | O_RDWR,
  1753. S_IREAD | S_IWRITE);
  1754. if (g_LogFile != -1)
  1755. {
  1756. _write(g_LogFile, Path, strlen(Path));
  1757. _write(g_LogFile, "\n", strlen("\n"));
  1758. _close(g_LogFile);
  1759. }
  1760. }
  1761. EXIT_API();
  1762. return S_OK;
  1763. }
  1764. DECLARE_API( dblookupcrash )
  1765. {
  1766. CHAR Bucket[MAX_PATH]={0};
  1767. INIT_API();
  1768. while (*args)
  1769. {
  1770. if (*args == ' ' || *args == '\t')
  1771. {
  1772. ++args;
  1773. continue;
  1774. } else if (*args == '-' || *args == '/')
  1775. {
  1776. ++args;
  1777. switch (*args)
  1778. {
  1779. case 'b':
  1780. ++args;
  1781. while (*args == ' ') ++args;
  1782. if (sscanf(args,"%s", Bucket))
  1783. {
  1784. args+=strlen(Bucket);
  1785. }
  1786. break;
  1787. }
  1788. }
  1789. ++args;
  1790. }
  1791. AddCrashToDB(DB_LOOKUP_CRASH, NULL);
  1792. EXIT_API();
  1793. return S_OK;
  1794. }
  1795. DECLARE_API( help )
  1796. {
  1797. dprintf("diskspace <DriveLetter>[:] - Displays free disk space for specified volume\n");
  1798. dprintf("analyze [-v] - Analyzes current exception or bugcheck\n");
  1799. dprintf("cpuid [processor] - Displays CPU version info for all CPUs\n");
  1800. dprintf("elog_str <message> - Logs simple message to host event log\n");
  1801. dprintf("error [errorcode] - Displays Win32 & NTSTATUS error string\n");
  1802. dprintf("exchain - Displays exception chain for current thread\n");
  1803. dprintf("gle [-all] - Displays last error & status for current thread\n");
  1804. dprintf("imggp <imagebase> - Displays GP directory entry for 64-bit image\n");
  1805. dprintf("imgreloc <imagebase> - Relocates modules for an image\n");
  1806. dprintf("obja <address> - Displays OBJECT_ATTRIBUTES[32|64]\n");
  1807. dprintf("owner [symbol!module] - Detects owner for current exception or\n");
  1808. dprintf(" bugcheck from triage.ini\n");
  1809. dprintf("str <address> - Displays ANSI_STRING or OEM_STRING\n");
  1810. dprintf("ustr <address> - Displays UNICODE_STRING\n");
  1811. dprintf("\nType \".hh [command]\" for more detailed help\n");
  1812. return S_OK;
  1813. }
  1814. void
  1815. DumpCrtEhX86(ULONG64 RecAddr)
  1816. {
  1817. // struct _EH3_EXCEPTION_REGISTRATION *Next;
  1818. // PVOID ExceptionHandler;
  1819. // PSCOPETABLE_ENTRY ScopeTable;
  1820. // DWORD TryLevel;
  1821. ULONG64 Record[4];
  1822. if (g_ExtData->ReadPointersVirtual(4, RecAddr, Record) != S_OK)
  1823. {
  1824. return;
  1825. }
  1826. ULONG64 ScopeBase = Record[2];
  1827. LONG Level = (LONG)Record[3];
  1828. while (Level > -1)
  1829. {
  1830. // int enclosing_level;
  1831. // int (*filter)(PEXCEPTION_RECORD);
  1832. // void (*specific_handler)(void);
  1833. ULONG64 ScopeRec[3];
  1834. if (g_ExtData->ReadPointersVirtual(3, ScopeBase + Level * 12,
  1835. ScopeRec) != S_OK)
  1836. {
  1837. return;
  1838. }
  1839. ExtOut(" CRT scope %2d, ", Level);
  1840. char Sym[256];
  1841. ULONG64 Disp;
  1842. if (ScopeRec[1])
  1843. {
  1844. ExtOut("filter: ");
  1845. if (FAILED(g_ExtSymbols->
  1846. GetNameByOffset(ScopeRec[1], Sym, sizeof(Sym),
  1847. NULL, &Disp)) ||
  1848. !Sym[0])
  1849. {
  1850. ExtOut("%p", ScopeRec[1]);
  1851. }
  1852. else
  1853. {
  1854. ExtOut("%s+%I64x (%p)", Sym, Disp, ScopeRec[1]);
  1855. }
  1856. dprintf("\n ");
  1857. }
  1858. ExtOut("func: ");
  1859. if (FAILED(g_ExtSymbols->
  1860. GetNameByOffset(ScopeRec[2], Sym, sizeof(Sym),
  1861. NULL, &Disp)) ||
  1862. !Sym[0])
  1863. {
  1864. ExtOut("%p", ScopeRec[2]);
  1865. }
  1866. else
  1867. {
  1868. ExtOut("%s+%I64x (%p)", Sym, Disp, ScopeRec[2]);
  1869. }
  1870. ExtOut("\n");
  1871. Level = (LONG)ScopeRec[0];
  1872. }
  1873. }
  1874. void
  1875. DumpExceptionChainX86(ULONG64 Teb)
  1876. {
  1877. // struct _EXCEPTION_REGISTRATION_RECORD *ExceptionList;
  1878. // PVOID StackBase;
  1879. // PVOID StackLimit;
  1880. ULONG64 TibInfo[3];
  1881. if (g_ExtData->ReadPointersVirtual(3, Teb, TibInfo) != S_OK)
  1882. {
  1883. ExtErr("Unable to read TIB\n");
  1884. return;
  1885. }
  1886. ULONG64 RecAddr = TibInfo[0];
  1887. while (RecAddr != (ULONG64)-1)
  1888. {
  1889. ULONG64 Record[2];
  1890. if (RecAddr < TibInfo[2] ||
  1891. RecAddr + 8 > TibInfo[1] ||
  1892. (RecAddr & 3))
  1893. {
  1894. ExtErr("Invalid exception stack at %p\n", RecAddr);
  1895. return;
  1896. }
  1897. if (g_ExtData->ReadPointersVirtual(2, RecAddr, Record) != S_OK)
  1898. {
  1899. ExtErr("Unable to read exception record at %p\n", RecAddr);
  1900. return;
  1901. }
  1902. char Sym[256];
  1903. ULONG64 Disp;
  1904. ExtOut("%p: ", RecAddr);
  1905. if (FAILED(g_ExtSymbols->
  1906. GetNameByOffset(Record[1], Sym, sizeof(Sym),
  1907. NULL, &Disp)) ||
  1908. !Sym[0])
  1909. {
  1910. ExtOut("%p\n", Record[1]);
  1911. }
  1912. else
  1913. {
  1914. ExtOut("%s+%I64x (%p)\n", Sym, Disp, Record[1]);
  1915. // Check and see if this is the CRT exception
  1916. // handling function because in that case we
  1917. // have to go through the CRT tables to
  1918. // find the real exception handler.
  1919. PSTR Scan = strchr(Sym, '!');
  1920. if (Scan)
  1921. {
  1922. while (*++Scan == '_')
  1923. {
  1924. // Empty.
  1925. }
  1926. if (!strcmp(Scan, "except_handler3"))
  1927. {
  1928. DumpCrtEhX86(RecAddr);
  1929. }
  1930. }
  1931. }
  1932. RecAddr = Record[0];
  1933. }
  1934. }
  1935. DECLARE_API( exchain )
  1936. {
  1937. INIT_API();
  1938. ULONG64 Teb;
  1939. if (g_ExtSystem->GetCurrentThreadTeb(&Teb) != S_OK)
  1940. {
  1941. ExtErr("Unable to get TEB address\n");
  1942. goto Exit;
  1943. }
  1944. switch(g_TargetMachine)
  1945. {
  1946. case IMAGE_FILE_MACHINE_I386:
  1947. DumpExceptionChainX86(Teb);
  1948. break;
  1949. default:
  1950. ExtErr("exchain is x86 only\n");
  1951. break;
  1952. }
  1953. Exit:
  1954. EXIT_API();
  1955. return S_OK;
  1956. }