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.

1576 lines
35 KiB

  1. /*++
  2. Copyright (c) 2000-2001 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. //
  16. // Valid for the lifetime of the debug session.
  17. //
  18. WINDBG_EXTENSION_APIS ExtensionApis;
  19. ULONG TargetMachine;
  20. BOOL Connected;
  21. ULONG g_TargetClass;
  22. //
  23. // Valid only during an extension API call
  24. //
  25. PDEBUG_ADVANCED g_ExtAdvanced;
  26. PDEBUG_CLIENT g_ExtClient;
  27. PDEBUG_CONTROL g_ExtControl;
  28. PDEBUG_DATA_SPACES g_ExtData;
  29. PDEBUG_REGISTERS g_ExtRegisters;
  30. PDEBUG_SYMBOLS g_ExtSymbols;
  31. PDEBUG_SYSTEM_OBJECTS g_ExtSystem;
  32. // Version 2 Interfaces
  33. PDEBUG_CONTROL2 g_ExtControl2;
  34. // Queries for all debugger interfaces.
  35. extern "C" HRESULT
  36. ExtQuery(PDEBUG_CLIENT Client)
  37. {
  38. HRESULT Status;
  39. if ((Status = Client->QueryInterface(__uuidof(IDebugAdvanced),
  40. (void **)&g_ExtAdvanced)) != S_OK)
  41. {
  42. goto Fail;
  43. }
  44. if ((Status = Client->QueryInterface(__uuidof(IDebugControl),
  45. (void **)&g_ExtControl)) != S_OK)
  46. {
  47. goto Fail;
  48. }
  49. if ((Status = Client->QueryInterface(__uuidof(IDebugDataSpaces),
  50. (void **)&g_ExtData)) != S_OK)
  51. {
  52. goto Fail;
  53. }
  54. if ((Status = Client->QueryInterface(__uuidof(IDebugRegisters),
  55. (void **)&g_ExtRegisters)) != S_OK)
  56. {
  57. goto Fail;
  58. }
  59. if ((Status = Client->QueryInterface(__uuidof(IDebugSymbols),
  60. (void **)&g_ExtSymbols)) != S_OK)
  61. {
  62. goto Fail;
  63. }
  64. if ((Status = Client->QueryInterface(__uuidof(IDebugSystemObjects),
  65. (void **)&g_ExtSystem)) != S_OK)
  66. {
  67. goto Fail;
  68. }
  69. if ((Status = Client->QueryInterface(__uuidof(IDebugControl2),
  70. (void **)&g_ExtControl2)) != S_OK)
  71. {
  72. goto Fail;
  73. }
  74. g_ExtClient = Client;
  75. return S_OK;
  76. Fail:
  77. ExtRelease();
  78. return Status;
  79. }
  80. // Cleans up all debugger interfaces.
  81. void
  82. ExtRelease(void)
  83. {
  84. g_ExtClient = NULL;
  85. EXT_RELEASE(g_ExtAdvanced);
  86. EXT_RELEASE(g_ExtControl);
  87. EXT_RELEASE(g_ExtData);
  88. EXT_RELEASE(g_ExtRegisters);
  89. EXT_RELEASE(g_ExtSymbols);
  90. EXT_RELEASE(g_ExtSystem);
  91. EXT_RELEASE(g_ExtControl2);
  92. }
  93. // Normal output.
  94. void __cdecl
  95. ExtOut(PCSTR Format, ...)
  96. {
  97. va_list Args;
  98. va_start(Args, Format);
  99. g_ExtControl->OutputVaList(DEBUG_OUTPUT_NORMAL, Format, Args);
  100. va_end(Args);
  101. }
  102. // Error output.
  103. void __cdecl
  104. ExtErr(PCSTR Format, ...)
  105. {
  106. va_list Args;
  107. va_start(Args, Format);
  108. g_ExtControl->OutputVaList(DEBUG_OUTPUT_ERROR, Format, Args);
  109. va_end(Args);
  110. }
  111. // Warning output.
  112. void __cdecl
  113. ExtWarn(PCSTR Format, ...)
  114. {
  115. va_list Args;
  116. va_start(Args, Format);
  117. g_ExtControl->OutputVaList(DEBUG_OUTPUT_WARNING, Format, Args);
  118. va_end(Args);
  119. }
  120. // Verbose output.
  121. void __cdecl
  122. ExtVerb(PCSTR Format, ...)
  123. {
  124. va_list Args;
  125. va_start(Args, Format);
  126. g_ExtControl->OutputVaList(DEBUG_OUTPUT_VERBOSE, Format, Args);
  127. va_end(Args);
  128. }
  129. extern "C"
  130. HRESULT
  131. CALLBACK
  132. DebugExtensionInitialize(PULONG Version, PULONG Flags)
  133. {
  134. IDebugClient *DebugClient;
  135. PDEBUG_CONTROL DebugControl;
  136. HRESULT Hr;
  137. *Version = DEBUG_EXTENSION_VERSION(1, 0);
  138. *Flags = 0;
  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. &TargetMachine)) == S_OK)
  183. {
  184. Connected = TRUE;
  185. }
  186. ULONG Qualifier;
  187. if ((Hr = DebugControl->GetDebuggeeType(&g_TargetClass, &Qualifier)) == S_OK)
  188. {
  189. }
  190. DebugControl->Release();
  191. }
  192. DebugClient->Release();
  193. }
  194. }
  195. if (Notify == DEBUG_NOTIFY_SESSION_INACTIVE)
  196. {
  197. Connected = FALSE;
  198. TargetMachine = 0;
  199. }
  200. return;
  201. }
  202. extern "C"
  203. void
  204. CALLBACK
  205. DebugExtensionUninitialize(void)
  206. {
  207. return;
  208. }
  209. DllInit(
  210. HANDLE hModule,
  211. DWORD dwReason,
  212. DWORD dwReserved
  213. )
  214. {
  215. switch (dwReason) {
  216. case DLL_THREAD_ATTACH:
  217. break;
  218. case DLL_THREAD_DETACH:
  219. break;
  220. case DLL_PROCESS_DETACH:
  221. break;
  222. case DLL_PROCESS_ATTACH:
  223. break;
  224. }
  225. return TRUE;
  226. }
  227. LegacyCommands()
  228. {
  229. dprintf("\n");
  230. dprintf(" !cxr !exr, !trap and !tss has been replaced with the new built-in debugger \n");
  231. dprintf(" command .cxr, .exr, .trap and .tss. There is also a new \".thread\" command. \n");
  232. dprintf("\n");
  233. dprintf(" These new commands no longer require symbols to work correctly.\n");
  234. dprintf("\n");
  235. dprintf(" Another change that comes with these new commands is that they actually\n");
  236. dprintf(" change the internal state of the debugger engine \"permanently\" (until\n");
  237. dprintf(" reverted). Any other debugger or extension command issued after the \n");
  238. dprintf(" \".cxr\", \".trap\" or \".thread\" command will be executed with the new context.\n");
  239. dprintf("\n");
  240. dprintf(" For example, commands such as stack walk (\"k\", \"kb\", \"kv\" ), \"r\" and \"dv\"\n");
  241. dprintf(" (show local variables) will all work based off the new context that was\n");
  242. dprintf(" supplied by \".cxr\", \".trap\" or \".thread\".\n");
  243. dprintf("\n");
  244. dprintf(" \".cxr\", \".trap\" and \".thread\" also apply to WinDBG:\n");
  245. dprintf(" using \".cxr\" , \".trap\" and \".thread\" will automatically show you the\n");
  246. dprintf(" new stack in the WinDBG stack window and allow you to click on a frame and\n");
  247. dprintf(" see local variables and source code (if source is available).\n");
  248. dprintf("\n");
  249. dprintf(" \".cxr\", \".trap\" or \".thread\" with no parameters will give you back the\n");
  250. dprintf(" default context that was in effect before the command was executed.\n");
  251. dprintf("\n");
  252. dprintf(" For example, to exactly duplicate \n");
  253. dprintf("\n");
  254. dprintf(" !cxr <foo> !trap <foo>\n");
  255. dprintf(" !kb !kb\n");
  256. dprintf("\n");
  257. dprintf(" you would now use\n");
  258. dprintf("\n");
  259. dprintf(" .cxr <foo> .trap <foo>\n");
  260. dprintf(" kb kb\n");
  261. dprintf(" .cxr .trap\n");
  262. dprintf("\n");
  263. return S_OK;
  264. }
  265. DECLARE_API ( cxr )
  266. {
  267. LegacyCommands();
  268. return S_OK;
  269. }
  270. DECLARE_API ( exr )
  271. {
  272. LegacyCommands();
  273. return S_OK;
  274. }
  275. DECLARE_API ( trap )
  276. {
  277. LegacyCommands();
  278. return S_OK;
  279. }
  280. DECLARE_API ( tss )
  281. {
  282. LegacyCommands();
  283. return S_OK;
  284. }
  285. DECLARE_API( cpuid )
  286. /*++
  287. Routine Description:
  288. Print out the version number for all CPUs, if available.
  289. Arguments:
  290. None
  291. Return Value:
  292. None
  293. --*/
  294. {
  295. ULONG64 Val;
  296. BOOL First = TRUE;
  297. ULONG Processor;
  298. ULONG NumProcessors;
  299. DEBUG_PROCESSOR_IDENTIFICATION_ALL IdAll;
  300. INIT_API();
  301. if (g_ExtControl->GetNumberProcessors(&NumProcessors) != S_OK)
  302. {
  303. NumProcessors = 0;
  304. }
  305. if (GetExpressionEx(args, &Val, &args))
  306. {
  307. //
  308. // The user specified a procesor number.
  309. //
  310. Processor = (ULONG)Val;
  311. if (Processor >= NumProcessors)
  312. {
  313. dprintf("Invalid processor number specified\n");
  314. }
  315. else
  316. {
  317. NumProcessors = Processor + 1;
  318. }
  319. }
  320. else
  321. {
  322. //
  323. // Enumerate all the processors
  324. //
  325. Processor = 0;
  326. }
  327. while (Processor < NumProcessors)
  328. {
  329. if (g_ExtData->
  330. ReadProcessorSystemData(Processor,
  331. DEBUG_DATA_PROCESSOR_IDENTIFICATION,
  332. &IdAll, sizeof(IdAll), NULL) != S_OK)
  333. {
  334. dprintf("Unable to get processor %d ID information\n",
  335. Processor);
  336. break;
  337. }
  338. switch( TargetMachine )
  339. {
  340. case IMAGE_FILE_MACHINE_I386:
  341. if (First)
  342. {
  343. dprintf("CP F/M/S Manufacturer\n");
  344. }
  345. dprintf("%2d %2d,%d,%-2d %-16.16s\n",
  346. Processor,
  347. IdAll.X86.Family,
  348. IdAll.X86.Model,
  349. IdAll.X86.Stepping,
  350. IdAll.X86.VendorString);
  351. break;
  352. case IMAGE_FILE_MACHINE_AMD64:
  353. if (First)
  354. {
  355. dprintf("CP F/M/S Manufacturer\n");
  356. }
  357. dprintf("%2d %2d,%d,%-2d %-16.16s\n",
  358. Processor,
  359. IdAll.Amd64.Family,
  360. IdAll.Amd64.Model,
  361. IdAll.Amd64.Stepping,
  362. IdAll.Amd64.VendorString);
  363. break;
  364. case IMAGE_FILE_MACHINE_IA64:
  365. if (First)
  366. {
  367. dprintf("CP M/R/F/A Manufacturer\n");
  368. }
  369. dprintf("%2d %d,%d,%d,%d %-16.16s\n",
  370. Processor,
  371. IdAll.Ia64.Model,
  372. IdAll.Ia64.Revision,
  373. IdAll.Ia64.Family,
  374. IdAll.Ia64.ArchRev,
  375. IdAll.Ia64.VendorString);
  376. break;
  377. default:
  378. dprintf("Not supported for this target machine: %ld\n",
  379. TargetMachine);
  380. Processor = NumProcessors;
  381. break;
  382. }
  383. Processor++;
  384. First = FALSE;
  385. }
  386. EXIT_API();
  387. return S_OK;
  388. }
  389. HRESULT
  390. PrintString(
  391. BOOL Unicode,
  392. PDEBUG_CLIENT Client,
  393. LPCSTR args
  394. )
  395. {
  396. ULONG64 AddrString;
  397. ULONG64 Displacement;
  398. STRING32 String;
  399. UNICODE_STRING UnicodeString;
  400. ULONG64 AddrBuffer;
  401. CHAR Symbol[1024];
  402. LPSTR StringData;
  403. HRESULT hResult;
  404. BOOL b;
  405. AddrString = GetExpression(args);
  406. if (!AddrString)
  407. {
  408. return E_FAIL;
  409. }
  410. //
  411. // Get the symbolic name of the string
  412. //
  413. GetSymbol(AddrString, Symbol, &Displacement);
  414. //
  415. // Read the string from the debuggees address space into our
  416. // own.
  417. b = ReadMemory(AddrString, &String, sizeof(String), NULL);
  418. if ( !b )
  419. {
  420. return E_FAIL;
  421. }
  422. INIT_API();
  423. if (IsPtr64())
  424. {
  425. hResult = g_ExtData->ReadPointersVirtual(1,
  426. AddrString + FIELD_OFFSET(STRING64, Buffer),
  427. &AddrBuffer);
  428. }
  429. else
  430. {
  431. hResult = g_ExtData->ReadPointersVirtual(1,
  432. AddrString + FIELD_OFFSET(STRING32, Buffer),
  433. &AddrBuffer);
  434. }
  435. EXIT_API();
  436. if (hResult != S_OK)
  437. {
  438. return E_FAIL;
  439. }
  440. StringData = (LPSTR) LocalAlloc(LMEM_ZEROINIT,
  441. String.Length + sizeof(UNICODE_NULL));
  442. if (!StringData)
  443. {
  444. return E_FAIL;
  445. }
  446. dprintf("String(%d,%d)", String.Length, String.MaximumLength);
  447. if (Symbol[0])
  448. {
  449. dprintf(" %s+%p", Symbol, Displacement);
  450. }
  451. b = ReadMemory(AddrBuffer, StringData, String.Length, NULL);
  452. if ( b )
  453. {
  454. if (Unicode)
  455. {
  456. ANSI_STRING AnsiString;
  457. UnicodeString.Buffer = (PWSTR)StringData;
  458. UnicodeString.Length = String.Length;
  459. UnicodeString.MaximumLength = String.Length+sizeof(UNICODE_NULL);
  460. RtlUnicodeStringToAnsiString(&AnsiString, &UnicodeString,TRUE);
  461. dprintf(" at %p: %s\n", AddrString, AnsiString.Buffer);
  462. RtlFreeAnsiString(&AnsiString);
  463. }
  464. else
  465. {
  466. dprintf(" at %p: %s\n", AddrString, StringData);
  467. }
  468. LocalFree(StringData);
  469. return S_OK;
  470. }
  471. else
  472. {
  473. LocalFree(StringData);
  474. return E_FAIL;
  475. }
  476. }
  477. DECLARE_API( str )
  478. /*++
  479. Routine Description:
  480. This function is called to format and dump counted (ansi) string.
  481. Arguments:
  482. args - Address
  483. Return Value:
  484. None.
  485. --*/
  486. {
  487. return PrintString(FALSE, Client, args);
  488. }
  489. DECLARE_API( ustr )
  490. /*++
  491. Routine Description:
  492. This function is called to format and dump counted (unicode) string.
  493. Arguments:
  494. args - Address
  495. Return Value:
  496. None.
  497. --*/
  498. {
  499. return PrintString(TRUE, Client, args);
  500. }
  501. DECLARE_API( obja )
  502. /*++
  503. Routine Description:
  504. This function is called to format and dump an object attributes structure.
  505. Arguments:
  506. args - Address
  507. Return Value:
  508. None.
  509. --*/
  510. {
  511. ULONG64 AddrObja;
  512. ULONG64 Displacement;
  513. ULONG64 AddrString;
  514. STRING32 String;
  515. ULONG64 StrAddr = NULL;
  516. CHAR Symbol[1024];
  517. LPSTR StringData;
  518. BOOL b;
  519. ULONG Attr;
  520. HRESULT hResult;
  521. ULONG ObjectNameOffset;
  522. ULONG AttrOffset;
  523. ULONG StringOffset;
  524. if (IsPtr64())
  525. {
  526. ObjectNameOffset = FIELD_OFFSET(OBJECT_ATTRIBUTES64, ObjectName);
  527. AttrOffset = FIELD_OFFSET(OBJECT_ATTRIBUTES64, Attributes);
  528. StringOffset = FIELD_OFFSET(STRING64, Buffer);
  529. }
  530. else
  531. {
  532. ObjectNameOffset = FIELD_OFFSET(OBJECT_ATTRIBUTES32, ObjectName);
  533. AttrOffset = FIELD_OFFSET(OBJECT_ATTRIBUTES32, Attributes);
  534. StringOffset = FIELD_OFFSET(STRING32, Buffer);
  535. }
  536. AddrObja = GetExpression(args);
  537. if (!AddrObja)
  538. {
  539. return E_FAIL;
  540. }
  541. //
  542. // Get the symbolic name of the Obja
  543. //
  544. GetSymbol(AddrObja, Symbol, &Displacement);
  545. dprintf("Obja %s+%p at %p:\n", Symbol, Displacement, AddrObja);
  546. INIT_API();
  547. hResult = g_ExtData->ReadPointersVirtual(1,
  548. AddrObja + ObjectNameOffset,
  549. &AddrString);
  550. if (hResult != S_OK)
  551. {
  552. return E_FAIL;
  553. }
  554. if (AddrString)
  555. {
  556. b = ReadMemory(AddrString, &String, sizeof(String), NULL);
  557. hResult = g_ExtData->ReadPointersVirtual(1,
  558. AddrString + StringOffset,
  559. &StrAddr);
  560. }
  561. EXIT_API();
  562. if (StrAddr)
  563. {
  564. StringData = (LPSTR)LocalAlloc(LMEM_ZEROINIT,
  565. String.Length+sizeof(UNICODE_NULL));
  566. if (StringData)
  567. {
  568. b = ReadMemory(StrAddr, StringData, String.Length, NULL);
  569. if (b)
  570. {
  571. dprintf("\tName is %ws\n", StringData);
  572. }
  573. LocalFree(StringData);
  574. }
  575. }
  576. b = ReadMemory(AddrObja + AttrOffset, &Attr, sizeof(Attr), NULL);
  577. if (!b)
  578. {
  579. return E_FAIL;
  580. }
  581. if (Attr & OBJ_INHERIT )
  582. {
  583. dprintf("\tOBJ_INHERIT\n");
  584. }
  585. if (Attr & OBJ_PERMANENT )
  586. {
  587. dprintf("\tOBJ_PERMANENT\n");
  588. }
  589. if (Attr & OBJ_EXCLUSIVE )
  590. {
  591. dprintf("\tOBJ_EXCLUSIVE\n");
  592. }
  593. if (Attr & OBJ_CASE_INSENSITIVE )
  594. {
  595. dprintf("\tOBJ_CASE_INSENSITIVE\n");
  596. }
  597. if (Attr & OBJ_OPENIF )
  598. {
  599. dprintf("\tOBJ_OPENIF\n");
  600. }
  601. return S_OK;
  602. }
  603. VOID
  604. DecodeErrorForMessage(
  605. PDEBUG_DECODE_ERROR pDecodeError
  606. )
  607. {
  608. HANDLE Dll;
  609. PSTR Source;
  610. CHAR Message[ 512 ];
  611. PCHAR s;
  612. ULONG Code;
  613. BOOL TreatAsStatus;
  614. Code = pDecodeError->Code;
  615. TreatAsStatus = pDecodeError->TreatAsStatus;
  616. if ( !pDecodeError->TreatAsStatus )
  617. {
  618. //
  619. // The value "type" is not known. Try and figure out what it
  620. // is.
  621. //
  622. if ( (Code & 0xC0000000) == 0xC0000000 )
  623. {
  624. //
  625. // Easy: NTSTATUS failure case
  626. //
  627. Dll = GetModuleHandle( "NTDLL.DLL" );
  628. Source = "NTSTATUS" ;
  629. TreatAsStatus = TRUE ;
  630. }
  631. else if ( ( Code & 0xF0000000 ) == 0xD0000000 )
  632. {
  633. //
  634. // HRESULT from NTSTATUS
  635. //
  636. Dll = GetModuleHandle( "NTDLL.DLL" );
  637. Source = "NTSTATUS" ;
  638. Code &= 0xCFFFFFFF ;
  639. TreatAsStatus = TRUE ;
  640. }
  641. else if ( ( Code & 0x80000000 ) == 0x80000000 )
  642. {
  643. //
  644. // Note, this can overlap with NTSTATUS warning area. In that
  645. // case, force the NTSTATUS.
  646. //
  647. Dll = GetModuleHandle( "KERNEL32.DLL" );
  648. Source = "HRESULT" ;
  649. }
  650. else
  651. {
  652. //
  653. // Sign bit is off. Explore some known ranges:
  654. //
  655. if ( (Code >= WSABASEERR) && (Code <= WSABASEERR + 1000 ))
  656. {
  657. Dll = LoadLibrary( "wsock32.dll" );
  658. Source = "Winsock" ;
  659. }
  660. else if ( ( Code >= NERR_BASE ) && ( Code <= MAX_NERR ) )
  661. {
  662. Dll = LoadLibrary( "netmsg.dll" );
  663. Source = "NetAPI" ;
  664. }
  665. else
  666. {
  667. Dll = GetModuleHandle( "KERNEL32.DLL" );
  668. Source = "Win32" ;
  669. }
  670. }
  671. }
  672. else
  673. {
  674. Dll = GetModuleHandle( "NTDLL.DLL" );
  675. Source = "NTSTATUS" ;
  676. }
  677. if (!FormatMessage(FORMAT_MESSAGE_IGNORE_INSERTS |
  678. FORMAT_MESSAGE_FROM_HMODULE,
  679. Dll,
  680. Code,
  681. 0,
  682. Message,
  683. sizeof( Message ),
  684. NULL ) )
  685. {
  686. strcpy( Message, "No mapped error code" );
  687. }
  688. s = Message ;
  689. while (*s)
  690. {
  691. if (*s < ' ')
  692. {
  693. *s = ' ';
  694. }
  695. s++;
  696. }
  697. pDecodeError->TreatAsStatus = TreatAsStatus;
  698. strcpy(pDecodeError->Source, Source);
  699. if (strlen(Message) < sizeof(pDecodeError->Message)) {
  700. strcpy(pDecodeError->Message, Message);
  701. }
  702. }
  703. VOID
  704. DecodeError(
  705. PSTR Banner,
  706. ULONG Code,
  707. BOOL TreatAsStatus
  708. )
  709. {
  710. DEBUG_DECODE_ERROR Err;
  711. Err.Code = Code;
  712. Err.TreatAsStatus = TreatAsStatus;
  713. DecodeErrorForMessage(&Err);
  714. if (!TreatAsStatus)
  715. {
  716. dprintf("%s: (%s) %#x (%u) - %s\n",
  717. Banner, Err.Source, Code, Code, Err.Message);
  718. }
  719. else
  720. {
  721. dprintf("%s: (%s) %#x - %s\n",
  722. Banner, Err.Source, Code, Err.Message);
  723. }
  724. }
  725. DECLARE_API( error )
  726. {
  727. ULONG err ;
  728. err = (ULONG) GetExpression( args );
  729. DecodeError( "Error code", err, FALSE );
  730. return S_OK;
  731. }
  732. #if 1
  733. DECLARE_API( gle )
  734. {
  735. NTSTATUS Status;
  736. ULONG64 Address;
  737. TEB Teb;
  738. GetTebAddress(&Address);
  739. if (ReadMemory(Address, &Teb, sizeof(Teb), NULL))
  740. {
  741. DecodeError( "LastErrorValue", Teb.LastErrorValue, FALSE );
  742. DecodeError( "LastStatusValue", Teb.LastStatusValue, TRUE );
  743. return S_OK;
  744. }
  745. else
  746. {
  747. dprintf("Unable to read current thread's TEB\n" );
  748. return E_FAIL;
  749. }
  750. }
  751. void
  752. DispalyTime(
  753. ULONG64 Time,
  754. PCHAR TimeString
  755. )
  756. {
  757. if (Time) {
  758. ULONG seconds = (ULONG) Time;
  759. ULONG minutes = seconds / 60;
  760. ULONG hours = minutes / 60;
  761. ULONG days = hours / 24;
  762. dprintf("%s %d days %d:%02d:%02d \n",
  763. TimeString,
  764. days, hours%24, minutes%60, seconds%60);
  765. }
  766. }
  767. extern PCHAR gTargetMode[], gAllOsTypes[];
  768. DECLARE_API( targetinfo )
  769. {
  770. TARGET_DEBUG_INFO TargetInfo;
  771. EXT_TARGET_INFO GetTargetInfo;
  772. INIT_API();
  773. if (g_ExtControl->GetExtensionFunction(0, "GetTargetInfo", (FARPROC *)&GetTargetInfo) == S_OK) {
  774. TargetInfo.SizeOfStruct = sizeof(TargetInfo);
  775. if ((*GetTargetInfo)(Client, &TargetInfo) != S_OK) {
  776. dprintf("GetTargetInfo failed\n");
  777. } else {
  778. const char * time;
  779. dprintf("TargetInfo:\n");
  780. dprintf("%s\n", gTargetMode[ TargetInfo.Mode ]);
  781. if ((time = ctime((time_t *) &TargetInfo.CrashTime)) != NULL) {
  782. dprintf("\tCrashtime: %s", time);
  783. }
  784. if (TargetInfo.SysUpTime) {
  785. DispalyTime(TargetInfo.SysUpTime,
  786. "\tSystem Uptime: ");
  787. }
  788. else
  789. {
  790. dprintf("\tSystem Uptime: not available\n");
  791. }
  792. if (TargetInfo.Mode == UserModeTarget) {
  793. DispalyTime(TargetInfo.AppUpTime, "\tProcess Uptime: ");
  794. }
  795. if ((time = ctime((time_t *) &TargetInfo.EntryDate)) != NULL) {
  796. dprintf("\tEntry Date: %s", time);
  797. }
  798. if (TargetInfo.OsInfo.Type) {
  799. dprintf(gAllOsTypes[TargetInfo.OsInfo.Type]);
  800. dprintf(" ");
  801. }
  802. // dprintf("OS Type %lx, Probcuct %lx, suite %lx\n",
  803. // TargetInfo.OsInfo.Type, TargetInfo.OsInfo.ProductType,
  804. // TargetInfo.OsInfo.Suite);
  805. dprintf("%s, %s ",
  806. TargetInfo.OsInfo.OsString,
  807. TargetInfo.OsInfo.ServicePackString);
  808. dprintf("Version %ld.%ld\n",
  809. TargetInfo.OsInfo.Version.Major, TargetInfo.OsInfo.Version.Minor);
  810. dprintf("%d procs, %d current processor, type %lx\n",
  811. TargetInfo.Cpu.NumCPUs,
  812. TargetInfo.Cpu.CurrentProc,
  813. TargetInfo.Cpu.Type);
  814. for (ULONG i =0; i<TargetInfo.Cpu.NumCPUs; i++) {
  815. if (TargetInfo.Cpu.Type == IMAGE_FILE_MACHINE_I386) {
  816. dprintf("CPU %lx Family %lx Model %lx Ste %lx Vendor %-12.12s\n",
  817. i,
  818. TargetInfo.Cpu.ProcInfo[i].X86.Family,
  819. TargetInfo.Cpu.ProcInfo[i].X86.Model,
  820. TargetInfo.Cpu.ProcInfo[i].X86.Stepping,
  821. TargetInfo.Cpu.ProcInfo[i].X86.VendorString);
  822. } else if (TargetInfo.Cpu.Type == IMAGE_FILE_MACHINE_IA64) {
  823. dprintf("CPU %lx Family %lx Model %lx Rev %lx Vendor %-12.12s\n",
  824. i,
  825. TargetInfo.Cpu.ProcInfo[i].Ia64.Family,
  826. TargetInfo.Cpu.ProcInfo[i].Ia64.Model,
  827. TargetInfo.Cpu.ProcInfo[i].Ia64.Revision,
  828. TargetInfo.Cpu.ProcInfo[i].Ia64.VendorString);
  829. }
  830. }
  831. }
  832. }
  833. EXIT_API();
  834. return S_OK;
  835. }
  836. #endif
  837. BOOL
  838. GetOwner(
  839. PSTR OwnerBuffer,
  840. ULONG OwnerBufferSize,
  841. PSTR SymbolName
  842. )
  843. {
  844. PSTR Bang;
  845. CHAR Owner2[MAX_PATH];
  846. ULONG Found = 0;
  847. PSTR SymName;
  848. static CHAR szTriageFileName[MAX_PATH+50];
  849. static BOOL GotTriageFIleName = FALSE;
  850. if (!GotTriageFIleName)
  851. {
  852. PCHAR ExeDir;
  853. ExeDir = &szTriageFileName[0];
  854. *ExeDir = 0;
  855. // Get the directory the debugger executable is in.
  856. if (!GetModuleFileName(NULL, ExeDir, MAX_PATH))
  857. {
  858. // Error. Use the current directory.
  859. strcpy(ExeDir, ".");
  860. } else
  861. {
  862. // Remove the executable name.
  863. PCHAR pszTmp = strrchr(ExeDir, '\\');
  864. if (pszTmp)
  865. {
  866. *pszTmp = 0;
  867. }
  868. GotTriageFIleName = TRUE;
  869. }
  870. strcat(ExeDir, "\\triage\\triage.ini");
  871. }
  872. //
  873. // First extract the module name from the symbol name.
  874. //
  875. Bang = strstr(SymbolName, "!");
  876. if (Bang)
  877. {
  878. *Bang = 0;
  879. }
  880. Found = GetPrivateProfileString("owners", SymbolName, "[default]",
  881. OwnerBuffer, OwnerBufferSize,
  882. szTriageFileName);
  883. if (!Found ||
  884. !strcmp(OwnerBuffer, "ignore"))
  885. {
  886. return FALSE;
  887. }
  888. if (OwnerBuffer[0] != '[')
  889. {
  890. return TRUE;
  891. }
  892. //
  893. // The string points to another section to handle substrings in the module
  894. // For each substring, starting with the longest one, search the
  895. // section.
  896. //
  897. PSTR End = NULL;
  898. SymName = NULL;
  899. if (Bang)
  900. {
  901. SymName = Bang+1;
  902. End = SymName+ strlen(SymName);
  903. }
  904. strcpy(Owner2, OwnerBuffer+1);
  905. *(Owner2+strlen(Owner2)-1) = 0;
  906. while (End > SymName)
  907. {
  908. Found = GetPrivateProfileString(Owner2, SymName, "ignore",
  909. OwnerBuffer, OwnerBufferSize,
  910. szTriageFileName);
  911. if (Found && strcmp(OwnerBuffer, "ignore"))
  912. {
  913. return TRUE;
  914. }
  915. *--End = 0;
  916. }
  917. //
  918. // We did not find the subcomponent - Look for the default entry.
  919. //
  920. Found = GetPrivateProfileString(Owner2, "default", "ignore",
  921. OwnerBuffer, OwnerBufferSize,
  922. szTriageFileName);
  923. if (Found && strcmp(OwnerBuffer, "ignore"))
  924. {
  925. return TRUE;
  926. }
  927. return FALSE;
  928. }
  929. BOOL
  930. _EFN_GetTriageFollowupFromSymbol(
  931. IN PSTR SymbolName,
  932. OUT PDEBUG_TRIAGE_FOLLOWUP_INFO OwnerInfo
  933. )
  934. {
  935. if (OwnerInfo->SizeOfStruct != sizeof(DEBUG_TRIAGE_FOLLOWUP_INFO))
  936. {
  937. return FALSE;
  938. }
  939. if (GetOwner(OwnerInfo->OwnerName.Buffer, OwnerInfo->OwnerName.MaximumLength, SymbolName)) {
  940. OwnerInfo->OwnerName.Length = (USHORT)strlen(OwnerInfo->OwnerName.Buffer);
  941. return TRUE;
  942. }
  943. return FALSE;
  944. }
  945. DECLARE_API( triage )
  946. /*++
  947. Routine Description:
  948. This function can be called to triage the owner of a stack trace.
  949. Arguments:
  950. args - none
  951. Return Value:
  952. None.
  953. --*/
  954. {
  955. ULONG NumFrames = 20;
  956. ULONG FramesFound = 0;
  957. ULONG i;
  958. BOOL bOwner = FALSE;
  959. CHAR NameBuffer[MAX_PATH + 2000 + 20];
  960. CHAR CurrentOwner[MAX_PATH];
  961. // Allocate a separate buffer to hold the frames while
  962. // calling OutputStackTrace on them. We can't just pass
  963. // in the state buffer pointer as resizing of the state
  964. // buffer may cause the data pointer to change.
  965. PDEBUG_STACK_FRAME RawFrames =
  966. (PDEBUG_STACK_FRAME)malloc(NumFrames * sizeof(DEBUG_STACK_FRAME));
  967. PDEBUG_STACK_FRAME CurrentFrame = RawFrames;
  968. if (RawFrames == NULL)
  969. {
  970. return E_OUTOFMEMORY;
  971. }
  972. INIT_API();
  973. Status = g_ExtControl->GetStackTrace(0, 0, 0, RawFrames, NumFrames,
  974. &FramesFound);
  975. if (Status == S_OK)
  976. {
  977. for(i=0; i < FramesFound; i++)
  978. {
  979. //
  980. // Get the symbol from the address and look it up in the
  981. // list of owners
  982. //
  983. Status = g_ExtSymbols->GetNameByOffset(CurrentFrame->InstructionOffset,
  984. NameBuffer,
  985. sizeof(NameBuffer),
  986. NULL,
  987. NULL);
  988. CurrentFrame++;
  989. if (Status != S_OK)
  990. {
  991. continue;
  992. }
  993. if (bOwner = GetOwner(CurrentOwner, sizeof(CurrentOwner), NameBuffer))
  994. {
  995. break;
  996. }
  997. }
  998. }
  999. if (!bOwner)
  1000. {
  1001. GetOwner(CurrentOwner, sizeof(CurrentOwner), "default");
  1002. }
  1003. g_ExtControl->OutputStackTrace(DEBUG_OUTCTL_ALL_CLIENTS,
  1004. RawFrames, FramesFound, 0);
  1005. dprintf("\n********************\nFollow-up: %s\n********************\n\n",
  1006. CurrentOwner);
  1007. EXIT_API();
  1008. free(RawFrames);
  1009. return Status;
  1010. }
  1011. void
  1012. _EFN_DecodeError(
  1013. PDEBUG_DECODE_ERROR pDecodeError
  1014. )
  1015. {
  1016. if (pDecodeError->SizeOfStruct != sizeof(DEBUG_DECODE_ERROR))
  1017. {
  1018. return;
  1019. }
  1020. return DecodeErrorForMessage(pDecodeError);
  1021. }
  1022. DECLARE_API( elog_str )
  1023. {
  1024. HANDLE EventSource = NULL;
  1025. INIT_API();
  1026. if (args)
  1027. {
  1028. while (isspace(*args))
  1029. {
  1030. args++;
  1031. }
  1032. }
  1033. if (!args || !args[0])
  1034. {
  1035. Status = E_INVALIDARG;
  1036. ExtErr("Usage: elog_str string\n");
  1037. goto Exit;
  1038. }
  1039. // Get a handle to the NT application log.
  1040. EventSource = OpenEventLog(NULL, "Application");
  1041. if (!EventSource)
  1042. {
  1043. Status = HRESULT_FROM_WIN32(GetLastError());
  1044. ExtErr("Unable to open event log, 0x%08X\n", Status);
  1045. goto Exit;
  1046. }
  1047. if (!ReportEvent(EventSource, EVENTLOG_ERROR_TYPE, 0, 0, NULL,
  1048. 1, 0, &args, NULL))
  1049. {
  1050. Status = HRESULT_FROM_WIN32(GetLastError());
  1051. ExtErr("Unable to report event, 0x%08X\n", Status);
  1052. goto Exit;
  1053. }
  1054. Status = S_OK;
  1055. Exit:
  1056. if (EventSource)
  1057. {
  1058. CloseEventLog(EventSource);
  1059. }
  1060. EXIT_API();
  1061. return Status;
  1062. }
  1063. HRESULT
  1064. AnsiToUnicode(PCSTR StrA, PWSTR* StrW)
  1065. {
  1066. ULONG Len;
  1067. // No input is an error.
  1068. if (NULL == StrA)
  1069. {
  1070. return E_INVALIDARG;
  1071. }
  1072. Len = strlen(StrA) + 1;
  1073. *StrW = (PWSTR)malloc(Len * sizeof(WCHAR));
  1074. if (*StrW == NULL)
  1075. {
  1076. ExtErr("Unable to allocate memory\n");
  1077. return E_OUTOFMEMORY;
  1078. }
  1079. if (0 == MultiByteToWideChar(CP_ACP, 0, StrA, Len, *StrW, Len))
  1080. {
  1081. HRESULT Status = HRESULT_FROM_WIN32(GetLastError());
  1082. free(*StrW);
  1083. ExtErr("Unable to convert string, 0x%08X\n", Status);
  1084. return Status;
  1085. }
  1086. return S_OK;
  1087. }
  1088. typedef NET_API_STATUS (NET_API_FUNCTION* PFN_NetMessageBufferSend)
  1089. (
  1090. IN LPCWSTR servername,
  1091. IN LPCWSTR msgname,
  1092. IN LPCWSTR fromname,
  1093. IN LPBYTE buf,
  1094. IN DWORD buflen
  1095. );
  1096. DECLARE_API( net_send )
  1097. {
  1098. PWSTR ArgsW = NULL;
  1099. PWSTR Tokens[4];
  1100. ULONG i;
  1101. HMODULE NetLib = NULL;
  1102. PFN_NetMessageBufferSend Send;
  1103. ULONG Result;
  1104. PWSTR ArgsEnd;
  1105. INIT_API();
  1106. NetLib = LoadLibrary("netapi32.dll");
  1107. if (!NetLib)
  1108. {
  1109. Status = HRESULT_FROM_WIN32(GetLastError());
  1110. ExtErr("Platform does not support net send\n");
  1111. goto Exit;
  1112. }
  1113. Send = (PFN_NetMessageBufferSend)
  1114. GetProcAddress(NetLib, "NetMessageBufferSend");
  1115. if (!Send)
  1116. {
  1117. Status = E_NOTIMPL;
  1118. ExtErr("Platform does not support net send\n");
  1119. goto Exit;
  1120. }
  1121. Status = AnsiToUnicode(args, &ArgsW);
  1122. if (Status != S_OK)
  1123. {
  1124. goto Exit;
  1125. }
  1126. ArgsEnd = ArgsW + wcslen(ArgsW);
  1127. // The message text is the entire remainder of the argument
  1128. // string after parsing the first separate tokens, so
  1129. // only wcstok up to the next-to-last token.
  1130. for (i = 0; i < sizeof(Tokens) / sizeof(Tokens[0]) - 1; i++)
  1131. {
  1132. Tokens[i] = wcstok(i == 0 ? ArgsW : NULL, L" \t");
  1133. if (Tokens[i] == NULL)
  1134. {
  1135. Status = E_INVALIDARG;
  1136. ExtErr("USAGE: net_send <targetserver> <targetuser> "
  1137. "<fromuser> <msg>\n");
  1138. goto Exit;
  1139. }
  1140. }
  1141. Tokens[i] = Tokens[i - 1] + wcslen(Tokens[i - 1]) + 1;
  1142. while (Tokens[i] < ArgsEnd &&
  1143. (*Tokens[i] == ' ' || *Tokens[i] == '\t'))
  1144. {
  1145. Tokens[i]++;
  1146. }
  1147. if (Tokens[i] >= ArgsEnd)
  1148. {
  1149. Status = E_INVALIDARG;
  1150. ExtErr("USAGE: net_send <targetserver> <targetuser> "
  1151. "<fromuser> <msg>\n");
  1152. goto Exit;
  1153. }
  1154. Result = Send(Tokens[0], Tokens[1], Tokens[2], (PBYTE)Tokens[3],
  1155. (wcslen(Tokens[3]) + 1) * sizeof(WCHAR));
  1156. if (Result != NERR_Success)
  1157. {
  1158. Status = HRESULT_FROM_WIN32(Result);;
  1159. ExtErr("Unable to send message, 0x%08X\n", Status);
  1160. goto Exit;
  1161. }
  1162. Status = S_OK;
  1163. Exit:
  1164. if (ArgsW)
  1165. {
  1166. free(ArgsW);
  1167. }
  1168. if (NetLib)
  1169. {
  1170. FreeLibrary(NetLib);
  1171. }
  1172. EXIT_API();
  1173. return Status;
  1174. }
  1175. // XXX drewb - This function just starts a mail message; the
  1176. // UI comes up and the user must finish and send the message.
  1177. // Therefore it doesn't have much value over the
  1178. // user just deciding to send a message.
  1179. #if 0
  1180. typedef ULONG (FAR PASCAL *PFN_MapiSendMail)
  1181. (
  1182. LHANDLE lhSession,
  1183. ULONG ulUIParam,
  1184. lpMapiMessage lpMessage,
  1185. FLAGS flFlags,
  1186. ULONG ulReserved
  1187. );
  1188. DECLARE_API( mapi_send )
  1189. {
  1190. HMODULE MapiLib = NULL;
  1191. PFN_MapiSendMail Send;
  1192. MapiMessage Mail;
  1193. INIT_API();
  1194. MapiLib = LoadLibrary("mapi.dll");
  1195. if (!MapiLib)
  1196. {
  1197. Status = HRESULT_FROM_WIN32(GetLastError());
  1198. ExtErr("Platform does not support MAPI\n");
  1199. goto Exit;
  1200. }
  1201. Send = (PFN_MapiSendMail)
  1202. GetProcAddress(MapiLib, "MAPISendMail");
  1203. if (!Send)
  1204. {
  1205. Status = E_NOTIMPL;
  1206. ExtErr("Platform does not support MAPI\n");
  1207. goto Exit;
  1208. }
  1209. ZeroMemory(&Mail, sizeof(Mail));
  1210. if (!Send(0, // use implicit session.
  1211. 0, // ulUIParam; 0 is always valid
  1212. &Mail, // the message being sent
  1213. MAPI_DIALOG, // allow the user to edit the message
  1214. 0 // reserved; must be 0
  1215. ))
  1216. {
  1217. Status = E_FAIL;
  1218. ExtErr("Unable to send mail\n");
  1219. goto Exit;
  1220. }
  1221. Status = S_OK;
  1222. Exit:
  1223. if (MapiLib)
  1224. {
  1225. FreeLibrary(MapiLib);
  1226. }
  1227. EXIT_API();
  1228. return Status;
  1229. }
  1230. #endif
  1231. DECLARE_API( imggp )
  1232. {
  1233. ULONG64 ImageBase;
  1234. IMAGE_DOS_HEADER DosHdr;
  1235. IMAGE_NT_HEADERS64 NtHdr;
  1236. ULONG Done;
  1237. INIT_API();
  1238. ImageBase = GetExpression(args);
  1239. if (g_ExtData->ReadVirtual(ImageBase, &DosHdr, sizeof(DosHdr),
  1240. &Done) != S_OK ||
  1241. Done != sizeof(DosHdr))
  1242. {
  1243. ExtErr("Unable to read DOS header at %p\n", ImageBase);
  1244. goto Exit;
  1245. }
  1246. if (DosHdr.e_magic != IMAGE_DOS_SIGNATURE)
  1247. {
  1248. ExtErr("Invalid DOS header at %p\n", ImageBase);
  1249. goto Exit;
  1250. }
  1251. if (g_ExtData->ReadVirtual(ImageBase + DosHdr.e_lfanew,
  1252. &NtHdr, sizeof(NtHdr),
  1253. &Done) != S_OK ||
  1254. Done != sizeof(NtHdr))
  1255. {
  1256. ExtErr("Unable to read NT header at %p\n",
  1257. ImageBase + DosHdr.e_lfanew);
  1258. goto Exit;
  1259. }
  1260. if (NtHdr.Signature != IMAGE_NT_SIGNATURE)
  1261. {
  1262. ExtErr("Invalid NT header at %p\n", ImageBase + DosHdr.e_lfanew);
  1263. goto Exit;
  1264. }
  1265. if (NtHdr.OptionalHeader.Magic != IMAGE_NT_OPTIONAL_HDR64_MAGIC)
  1266. {
  1267. ExtErr("Image is not 64-bit\n");
  1268. goto Exit;
  1269. }
  1270. if (NtHdr.OptionalHeader.NumberOfRvaAndSizes <=
  1271. IMAGE_DIRECTORY_ENTRY_GLOBALPTR)
  1272. {
  1273. ExtErr("Image does not have a GP directory entry\n");
  1274. goto Exit;
  1275. }
  1276. ExtOut("Image at %p has a GP value of %p\n",
  1277. ImageBase, ImageBase +
  1278. NtHdr.OptionalHeader.DataDirectory
  1279. [IMAGE_DIRECTORY_ENTRY_GLOBALPTR].VirtualAddress);
  1280. Exit:
  1281. EXIT_API();
  1282. return S_OK;
  1283. }