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.

941 lines
22 KiB

  1. /*++
  2. Copyright (c) 1993-2000 Microsoft Corporation
  3. Module Name:
  4. exts.c
  5. Abstract:
  6. This file contains the generic routines and initialization code
  7. for the kernel debugger extensions dll.
  8. Environment:
  9. User Mode
  10. --*/
  11. #include "precomp.h"
  12. #pragma hdrstop
  13. #include <ntverp.h>
  14. //
  15. // Valid for the lifetime of the debug session.
  16. //
  17. WINDBG_EXTENSION_APIS ExtensionApis;
  18. ULONG TargetMachine;
  19. BOOL Connected;
  20. ULONG g_TargetClass;
  21. //
  22. // Valid only during an extension API call
  23. //
  24. PDEBUG_ADVANCED g_ExtAdvanced;
  25. PDEBUG_CLIENT g_ExtClient;
  26. PDEBUG_CONTROL g_ExtControl;
  27. PDEBUG_DATA_SPACES g_ExtData;
  28. PDEBUG_REGISTERS g_ExtRegisters;
  29. PDEBUG_SYMBOLS2 g_ExtSymbols;
  30. PDEBUG_SYSTEM_OBJECTS g_ExtSystem;
  31. #define SKIP_WSPACE(s) while (*s && (*s == ' ' || *s == '\t')) {++s;}
  32. // Queries for all debugger interfaces.
  33. extern "C" HRESULT
  34. ExtQuery(PDEBUG_CLIENT Client)
  35. {
  36. HRESULT Status;
  37. if ((Status = Client->QueryInterface(__uuidof(IDebugAdvanced),
  38. (void **)&g_ExtAdvanced)) != S_OK)
  39. {
  40. goto Fail;
  41. }
  42. if ((Status = Client->QueryInterface(__uuidof(IDebugControl),
  43. (void **)&g_ExtControl)) != S_OK)
  44. {
  45. goto Fail;
  46. }
  47. if ((Status = Client->QueryInterface(__uuidof(IDebugDataSpaces),
  48. (void **)&g_ExtData)) != S_OK)
  49. {
  50. goto Fail;
  51. }
  52. if ((Status = Client->QueryInterface(__uuidof(IDebugRegisters),
  53. (void **)&g_ExtRegisters)) != S_OK)
  54. {
  55. goto Fail;
  56. }
  57. if ((Status = Client->QueryInterface(__uuidof(IDebugSymbols2),
  58. (void **)&g_ExtSymbols)) != S_OK)
  59. {
  60. goto Fail;
  61. }
  62. if ((Status = Client->QueryInterface(__uuidof(IDebugSystemObjects),
  63. (void **)&g_ExtSystem)) != S_OK)
  64. {
  65. goto Fail;
  66. }
  67. g_ExtClient = Client;
  68. return S_OK;
  69. Fail:
  70. ExtRelease();
  71. return Status;
  72. }
  73. // Cleans up all debugger interfaces.
  74. void
  75. ExtRelease(void)
  76. {
  77. g_ExtClient = NULL;
  78. EXT_RELEASE(g_ExtAdvanced);
  79. EXT_RELEASE(g_ExtControl);
  80. EXT_RELEASE(g_ExtData);
  81. EXT_RELEASE(g_ExtRegisters);
  82. EXT_RELEASE(g_ExtSymbols);
  83. EXT_RELEASE(g_ExtSystem);
  84. }
  85. // Normal output.
  86. void __cdecl
  87. ExtOut(PCSTR Format, ...)
  88. {
  89. va_list Args;
  90. va_start(Args, Format);
  91. g_ExtControl->OutputVaList(DEBUG_OUTPUT_NORMAL, Format, Args);
  92. va_end(Args);
  93. }
  94. // Error output.
  95. void __cdecl
  96. ExtErr(PCSTR Format, ...)
  97. {
  98. va_list Args;
  99. va_start(Args, Format);
  100. g_ExtControl->OutputVaList(DEBUG_OUTPUT_ERROR, Format, Args);
  101. va_end(Args);
  102. }
  103. // Warning output.
  104. void __cdecl
  105. ExtWarn(PCSTR Format, ...)
  106. {
  107. va_list Args;
  108. va_start(Args, Format);
  109. g_ExtControl->OutputVaList(DEBUG_OUTPUT_WARNING, Format, Args);
  110. va_end(Args);
  111. }
  112. // Verbose output.
  113. void __cdecl
  114. ExtVerb(PCSTR Format, ...)
  115. {
  116. va_list Args;
  117. va_start(Args, Format);
  118. g_ExtControl->OutputVaList(DEBUG_OUTPUT_VERBOSE, Format, Args);
  119. va_end(Args);
  120. }
  121. extern "C"
  122. HRESULT
  123. CALLBACK
  124. DebugExtensionInitialize(PULONG Version, PULONG Flags)
  125. {
  126. IDebugClient *DebugClient;
  127. PDEBUG_CONTROL DebugControl;
  128. HRESULT Hr;
  129. *Version = DEBUG_EXTENSION_VERSION(1, 0);
  130. *Flags = 0;
  131. if ((Hr = DebugCreate(__uuidof(IDebugClient),
  132. (void **)&DebugClient)) != S_OK)
  133. {
  134. return Hr;
  135. }
  136. if ((Hr = DebugClient->QueryInterface(__uuidof(IDebugControl),
  137. (void **)&DebugControl)) != S_OK)
  138. {
  139. return Hr;
  140. }
  141. ExtensionApis.nSize = sizeof (ExtensionApis);
  142. if ((Hr = DebugControl->GetWindbgExtensionApis64(&ExtensionApis)) != S_OK) {
  143. return Hr;
  144. }
  145. DebugControl->Release();
  146. DebugClient->Release();
  147. return S_OK;
  148. }
  149. extern "C"
  150. void
  151. CALLBACK
  152. DebugExtensionNotify(ULONG Notify, ULONG64 Argument)
  153. {
  154. //
  155. // The first time we actually connect to a target, get the page size
  156. //
  157. if ((Notify == DEBUG_NOTIFY_SESSION_ACCESSIBLE) && (!Connected))
  158. {
  159. IDebugClient *DebugClient;
  160. PDEBUG_DATA_SPACES DebugDataSpaces;
  161. PDEBUG_CONTROL DebugControl;
  162. HRESULT Hr;
  163. ULONG64 Page;
  164. if ((Hr = DebugCreate(__uuidof(IDebugClient),
  165. (void **)&DebugClient)) == S_OK)
  166. {
  167. //
  168. // Get the page size and PAE enable flag
  169. //
  170. if ((Hr = DebugClient->QueryInterface(__uuidof(IDebugDataSpaces),
  171. (void **)&DebugDataSpaces)) == S_OK)
  172. {
  173. if ((Hr = DebugDataSpaces->ReadDebuggerData(
  174. DEBUG_DATA_MmPageSize, &Page,
  175. sizeof(Page), NULL)) == S_OK)
  176. {
  177. PageSize = (ULONG)(ULONG_PTR)Page;
  178. }
  179. DebugDataSpaces->Release();
  180. }
  181. //
  182. // Get the architecture type.
  183. //
  184. if ((Hr = DebugClient->QueryInterface(__uuidof(IDebugControl),
  185. (void **)&DebugControl)) == S_OK)
  186. {
  187. if ((Hr = DebugControl->GetActualProcessorType(
  188. &TargetMachine)) == S_OK)
  189. {
  190. Connected = TRUE;
  191. }
  192. ULONG Qualifier;
  193. if ((Hr = DebugControl->GetDebuggeeType(&g_TargetClass, &Qualifier)) == S_OK)
  194. {
  195. }
  196. DebugControl->Release();
  197. }
  198. DebugClient->Release();
  199. }
  200. }
  201. if (Notify == DEBUG_NOTIFY_SESSION_INACTIVE)
  202. {
  203. Connected = FALSE;
  204. PageSize = 0;
  205. TargetMachine = 0;
  206. }
  207. return;
  208. }
  209. extern "C"
  210. void
  211. CALLBACK
  212. DebugExtensionUninitialize(void)
  213. {
  214. return;
  215. }
  216. DllInit(
  217. HANDLE hModule,
  218. DWORD dwReason,
  219. DWORD dwReserved
  220. )
  221. {
  222. switch (dwReason) {
  223. case DLL_THREAD_ATTACH:
  224. break;
  225. case DLL_THREAD_DETACH:
  226. break;
  227. case DLL_PROCESS_DETACH:
  228. break;
  229. case DLL_PROCESS_ATTACH:
  230. break;
  231. }
  232. return TRUE;
  233. }
  234. VOID
  235. CxrHelp()
  236. {
  237. dprintf("\n");
  238. dprintf(" !cxr has been replaced with the new built-in debugger command .cxr\n");
  239. dprintf(" !exr, !trap and !tss (both Kernelmode only) too are built-in . commands now\n");
  240. dprintf(" There is also a new \".thread\" command.\n");
  241. dprintf("\n");
  242. dprintf(" These new commands no longer require symbols to work correctly.\n");
  243. dprintf("\n");
  244. dprintf(" Another change that comes with these new commands is that they actually\n");
  245. dprintf(" change the internal state of the debugger engine \"permanently\" (until\n");
  246. dprintf(" reverted). Any other debugger or extension command issued after the \n");
  247. dprintf(" \".cxr\", \".trap\" or \".thread\" command will be executed with the new context.\n");
  248. dprintf("\n");
  249. dprintf(" For example, commands such as stack walk (\"k\", \"kb\", \"kv\" ), \"r\" and \"dv\"\n");
  250. dprintf(" (show local variables) will all work based off the new context that was\n");
  251. dprintf(" supplied by \".cxr\", \".trap\" or \".thread\".\n");
  252. dprintf("\n");
  253. dprintf(" \".cxr\", \".trap\" and \".thread\" also apply to WinDBG:\n");
  254. dprintf(" using \".cxr\" , \".trap\" and \".thread\" will automatically show you the\n");
  255. dprintf(" new stack in the WinDBG stack window and allow you to click on a frame and\n");
  256. dprintf(" see local variables and source code (if source is available).\n");
  257. dprintf("\n");
  258. dprintf(" \".cxr\", \".trap\" or \".thread\" with no parameters will give you back the\n");
  259. dprintf(" default context that was in effect before the command was executed.\n");
  260. dprintf("\n");
  261. dprintf(" For example, to exactly duplicate \n");
  262. dprintf("\n");
  263. dprintf(" !cxr <foo> !trap <foo>\n");
  264. dprintf(" !kb !kb\n");
  265. dprintf("\n");
  266. dprintf(" you would now use\n");
  267. dprintf("\n");
  268. dprintf(" .cxr <foo> .trap <foo>\n");
  269. dprintf(" kb kb\n");
  270. dprintf(" .cxr .trap\n");
  271. dprintf("\n");
  272. }
  273. DECLARE_API ( cxr )
  274. {
  275. CxrHelp();
  276. return S_OK;
  277. }
  278. DECLARE_API ( exr )
  279. {
  280. CHAR Cmd[400];
  281. dprintf("*** !exr obsolete: Use '.exr %s'\n", args);
  282. sprintf(Cmd, ".exr %s", args);
  283. if (Client &&
  284. (ExtQuery(Client) == S_OK)) {
  285. g_ExtControl->Execute(DEBUG_OUTCTL_ALL_CLIENTS |
  286. DEBUG_OUTCTL_OVERRIDE_MASK |
  287. DEBUG_OUTCTL_NOT_LOGGED,
  288. Cmd, DEBUG_EXECUTE_DEFAULT );
  289. ExtRelease();
  290. return S_OK;
  291. }
  292. return E_FAIL;
  293. }
  294. HRESULT
  295. PrintString(
  296. BOOL Unicode,
  297. PDEBUG_CLIENT Client,
  298. LPCSTR args
  299. )
  300. {
  301. ULONG64 AddrString;
  302. ULONG64 Displacement;
  303. STRING32 String;
  304. UNICODE_STRING UnicodeString;
  305. ULONG64 AddrBuffer;
  306. CHAR Symbol[1024];
  307. LPSTR StringData;
  308. HRESULT hResult;
  309. BOOL b;
  310. AddrString = GetExpression(args);
  311. if (!AddrString)
  312. {
  313. return E_FAIL;
  314. }
  315. //
  316. // Get the symbolic name of the string
  317. //
  318. GetSymbol(AddrString, Symbol, &Displacement);
  319. //
  320. // Read the string from the debuggees address space into our
  321. // own.
  322. b = ReadMemory(AddrString, &String, sizeof(String), NULL);
  323. if ( !b )
  324. {
  325. return E_FAIL;
  326. }
  327. INIT_API();
  328. if (IsPtr64())
  329. {
  330. hResult = g_ExtData->ReadPointersVirtual(1,
  331. AddrString + FIELD_OFFSET(STRING64, Buffer),
  332. &AddrBuffer);
  333. }
  334. else
  335. {
  336. hResult = g_ExtData->ReadPointersVirtual(1,
  337. AddrString + FIELD_OFFSET(STRING32, Buffer),
  338. &AddrBuffer);
  339. }
  340. EXIT_API();
  341. if (hResult != S_OK)
  342. {
  343. return E_FAIL;
  344. }
  345. StringData = (LPSTR) LocalAlloc(LMEM_ZEROINIT,
  346. String.Length + sizeof(UNICODE_NULL));
  347. if (!StringData)
  348. {
  349. return E_FAIL;
  350. }
  351. dprintf("String(%d,%d)", String.Length, String.MaximumLength);
  352. if (Symbol[0])
  353. {
  354. dprintf(" %s+%p", Symbol, Displacement);
  355. }
  356. b = ReadMemory(AddrBuffer, StringData, String.Length, NULL);
  357. if ( b )
  358. {
  359. if (Unicode)
  360. {
  361. ANSI_STRING AnsiString;
  362. UnicodeString.Buffer = (PWSTR)StringData;
  363. UnicodeString.Length = String.Length;
  364. UnicodeString.MaximumLength = String.Length+sizeof(UNICODE_NULL);
  365. RtlUnicodeStringToAnsiString(&AnsiString, &UnicodeString,TRUE);
  366. dprintf(" at %p: %s\n", AddrString, AnsiString.Buffer);
  367. RtlFreeAnsiString(&AnsiString);
  368. }
  369. else
  370. {
  371. dprintf(" at %p: %s\n", AddrString, StringData);
  372. }
  373. LocalFree(StringData);
  374. return S_OK;
  375. }
  376. else
  377. {
  378. LocalFree(StringData);
  379. return E_FAIL;
  380. }
  381. }
  382. DECLARE_API( str )
  383. /*++
  384. Routine Description:
  385. This function is called to format and dump counted (ansi) string.
  386. Arguments:
  387. args - Address
  388. Return Value:
  389. None.
  390. --*/
  391. {
  392. return PrintString(FALSE, Client, args);
  393. }
  394. DECLARE_API( ustr )
  395. /*++
  396. Routine Description:
  397. This function is called to format and dump counted (unicode) string.
  398. Arguments:
  399. args - Address
  400. Return Value:
  401. None.
  402. --*/
  403. {
  404. return PrintString(TRUE, Client, args);
  405. }
  406. DECLARE_API( obja )
  407. /*++
  408. Routine Description:
  409. This function is called to format and dump an object attributes structure.
  410. Arguments:
  411. args - Address
  412. Return Value:
  413. None.
  414. --*/
  415. {
  416. ULONG64 AddrObja;
  417. ULONG64 Displacement;
  418. ULONG64 AddrString;
  419. STRING32 String;
  420. ULONG64 StrAddr = NULL;
  421. CHAR Symbol[1024];
  422. LPSTR StringData;
  423. BOOL b;
  424. ULONG Attr;
  425. HRESULT hResult;
  426. ULONG ObjectNameOffset;
  427. ULONG AttrOffset;
  428. ULONG StringOffset;
  429. if (IsPtr64())
  430. {
  431. ObjectNameOffset = FIELD_OFFSET(OBJECT_ATTRIBUTES64, ObjectName);
  432. AttrOffset = FIELD_OFFSET(OBJECT_ATTRIBUTES64, Attributes);
  433. StringOffset = FIELD_OFFSET(STRING64, Buffer);
  434. }
  435. else
  436. {
  437. ObjectNameOffset = FIELD_OFFSET(OBJECT_ATTRIBUTES32, ObjectName);
  438. AttrOffset = FIELD_OFFSET(OBJECT_ATTRIBUTES32, Attributes);
  439. StringOffset = FIELD_OFFSET(STRING32, Buffer);
  440. }
  441. AddrObja = GetExpression(args);
  442. if (!AddrObja)
  443. {
  444. return E_FAIL;
  445. }
  446. //
  447. // Get the symbolic name of the Obja
  448. //
  449. GetSymbol(AddrObja, Symbol, &Displacement);
  450. dprintf("Obja %s+%p at %p:\n", Symbol, Displacement, AddrObja);
  451. INIT_API();
  452. hResult = g_ExtData->ReadPointersVirtual(1,
  453. AddrObja + ObjectNameOffset,
  454. &AddrString);
  455. if (hResult != S_OK)
  456. {
  457. return E_FAIL;
  458. }
  459. if (AddrString)
  460. {
  461. b = ReadMemory(AddrString, &String, sizeof(String), NULL);
  462. hResult = g_ExtData->ReadPointersVirtual(1,
  463. AddrString + StringOffset,
  464. &StrAddr);
  465. }
  466. EXIT_API();
  467. if (StrAddr)
  468. {
  469. StringData = (LPSTR)LocalAlloc(LMEM_ZEROINIT,
  470. String.Length+sizeof(UNICODE_NULL));
  471. if (StringData)
  472. {
  473. b = ReadMemory(StrAddr, StringData, String.Length, NULL);
  474. if (b)
  475. {
  476. dprintf("\tName is %ws\n", StringData);
  477. }
  478. LocalFree(StringData);
  479. }
  480. }
  481. b = ReadMemory(AddrObja + AttrOffset, &Attr, sizeof(Attr), NULL);
  482. if (!b)
  483. {
  484. return E_FAIL;
  485. }
  486. if (Attr & OBJ_INHERIT )
  487. {
  488. dprintf("\tOBJ_INHERIT\n");
  489. }
  490. if (Attr & OBJ_PERMANENT )
  491. {
  492. dprintf("\tOBJ_PERMANENT\n");
  493. }
  494. if (Attr & OBJ_EXCLUSIVE )
  495. {
  496. dprintf("\tOBJ_EXCLUSIVE\n");
  497. }
  498. if (Attr & OBJ_CASE_INSENSITIVE )
  499. {
  500. dprintf("\tOBJ_CASE_INSENSITIVE\n");
  501. }
  502. if (Attr & OBJ_OPENIF )
  503. {
  504. dprintf("\tOBJ_OPENIF\n");
  505. }
  506. return S_OK;
  507. }
  508. typedef struct _LIST_TYPE_PARAMS {
  509. PCHAR Command;
  510. PCHAR CommandArgs;
  511. ULONG FieldOffset;
  512. ULONG nElement;
  513. } LIST_TYPE_PARAMS, *PLIST_TYPE_PARAMS;
  514. ULONG
  515. ListCallback(
  516. PFIELD_INFO Field,
  517. PVOID Context
  518. )
  519. {
  520. CHAR Execute[MAX_PATH];
  521. PCHAR Buffer;
  522. PLIST_TYPE_PARAMS pListParams = (PLIST_TYPE_PARAMS) Context;
  523. // Execute command
  524. sprintf(Execute,
  525. "%s %I64lx %s",
  526. pListParams->Command,
  527. Field->address,// - pListParams->FieldOffset,
  528. pListParams->CommandArgs);
  529. g_ExtControl->Execute(DEBUG_OUTCTL_AMBIENT,Execute,DEBUG_EXECUTE_DEFAULT);
  530. dprintf("\n");
  531. if (CheckControlC()) {
  532. return TRUE;
  533. }
  534. return FALSE;
  535. }
  536. /*
  537. !list [-type <Type>] [-x "<Command>"] <address>
  538. This dumps out a list starting at ginve <address>
  539. <Type> If types is specified, it'll list that particular type accoring to
  540. the given field.
  541. <Command> If specified it'll execute the command for every list element.
  542. */
  543. DECLARE_API ( list )
  544. {
  545. CHAR Command[MAX_PATH], CmdArgs[MAX_PATH];
  546. CHAR Type[MAX_PATH];
  547. CHAR Field[MAX_PATH];
  548. ULONG64 Start;
  549. ULONG i, Offset, Commandlen;
  550. ULONG64 Next, Current;
  551. LIST_TYPE_PARAMS ListParams;
  552. ZeroMemory(Type, sizeof(Type));
  553. ZeroMemory(Field, sizeof(Field));
  554. ZeroMemory(Command, sizeof(Command));
  555. CmdArgs[0] = 0;
  556. Start = 0;
  557. while (args && *args) {
  558. SKIP_WSPACE(args);
  559. if (*args == '-' || *args == '/') {
  560. ++args;
  561. if (*args == 't') {
  562. PCHAR Dot;
  563. args++;
  564. SKIP_WSPACE(args);
  565. Dot = strchr(args, '.');
  566. if (Dot) {
  567. strncpy(Type, args, (ULONG) (ULONG_PTR) (Dot-args));
  568. Dot++;
  569. i=0;
  570. while (*Dot && (i < MAX_PATH-1) && (*Dot != ' ') && (*Dot != '\t'))
  571. Field[i++] = *Dot++;
  572. args = Dot;
  573. }
  574. } else if (*args == 'x') {
  575. ++args;
  576. SKIP_WSPACE(args);
  577. i=0;
  578. if (*args == '"') {
  579. ++args;
  580. while (*args && (i < MAX_PATH-1) && (*args != '"'))
  581. Command[i++] = *args++;
  582. ++args;
  583. } else {
  584. dprintf("Invalid command specification. See !list -h\n");
  585. return E_INVALIDARG;
  586. }
  587. } else if (*args == 'a') {
  588. ++args;
  589. SKIP_WSPACE(args);
  590. i=0;
  591. if (*args == '"') {
  592. ++args;
  593. while (*args && (i < MAX_PATH-1) && (*args != '"'))
  594. CmdArgs[i++] = *args++;
  595. ++args;
  596. CmdArgs[i] = 0;
  597. } else {
  598. dprintf("Invalid command argument specification. See !list -h\n");
  599. return E_INVALIDARG;
  600. }
  601. } else if (*args == 'h' || *args == '?') {
  602. dprintf("Usage: !list -t [mod!]TYPE.Field <Start-Address>\n"
  603. " -x \"Command-for-each-element\"\n"
  604. " -a \"Command-arguments\"\n"
  605. " -h\n"
  606. "Command after -x is executed for each list element. Its first argument is\n"
  607. "list-head address and remaining arguments are specified after -a\n"
  608. "eg. !list -t MYTYPE.l.Flink -x \"dd\" -a \"l2\" 0x6bc00\n"
  609. " dumps first 2 dwords in list of MYTYPE at 0x6bc00\n\n"
  610. );
  611. return S_OK;
  612. } else {
  613. dprintf("Invalid flag -%c in !list\n", *args);
  614. return E_INVALIDARG;
  615. }
  616. } else {
  617. if (!GetExpressionEx(args, &Start, &args)) {
  618. dprintf("Invalid expression in %s\n", args);
  619. return E_FAIL;
  620. }
  621. }
  622. }
  623. Offset = 0;
  624. if (!Command[0]) {
  625. strcat(Command, "dp");
  626. }
  627. if (Type[0] && Field[0]) {
  628. if (GetFieldOffset(Type, Field, &Offset)) {
  629. dprintf("GetFieldOffset failed for %s.%s\n", Type, Field);
  630. return E_FAIL;
  631. }
  632. ListParams.Command = Command;
  633. ListParams.CommandArgs = CmdArgs;
  634. ListParams.FieldOffset = Offset;
  635. ListParams.nElement = 0;
  636. INIT_API();
  637. ListType(Type, Start, FALSE, Field, (PVOID) &ListParams, &ListCallback );
  638. EXIT_API();
  639. return S_OK;
  640. }
  641. Current = Start;
  642. Next = 0;
  643. INIT_API();
  644. while (Next != Start) {
  645. CHAR Execute[MAX_PATH];
  646. PCHAR Buffer;
  647. // Execute command
  648. sprintf(Execute, "%s %I64lx %s", Command, Current, CmdArgs);
  649. g_ExtControl->Execute(DEBUG_OUTCTL_AMBIENT,Execute,DEBUG_EXECUTE_DEFAULT);
  650. dprintf("\n");
  651. if (!ReadPointer(Current + Offset, &Next)) {
  652. dprintf("Cannot read next element at %p\n",
  653. Current + Offset);
  654. break;
  655. }
  656. if (!Next) {
  657. break;
  658. }
  659. Next -= Offset;
  660. Current = Next;
  661. if (CheckControlC()) {
  662. break;
  663. }
  664. }
  665. EXIT_API();
  666. return S_OK;
  667. }
  668. BOOL
  669. AnalyzeExceptionPointer(
  670. ULONG64 ExcepPtr
  671. )
  672. {
  673. ULONG64 Exr, Cxr;
  674. ULONG PtrSize= IsPtr64() ? 8 : 4;
  675. if (!ReadPointer(ExcepPtr, &Exr) ||
  676. !ReadPointer(ExcepPtr + PtrSize, &Cxr)) {
  677. dprintf("Unable to read exception poointers at %p\n", ExcepPtr);
  678. return FALSE;
  679. }
  680. CHAR Cmd[100];
  681. sprintf(Cmd, ".exr %I64lx", Exr);
  682. g_ExtControl->Execute(DEBUG_OUTCTL_ALL_CLIENTS |
  683. DEBUG_OUTCTL_OVERRIDE_MASK,
  684. Cmd, DEBUG_EXECUTE_DEFAULT);
  685. sprintf(Cmd, ".cxr %I64lx", Cxr);
  686. g_ExtControl->Execute(DEBUG_OUTCTL_ALL_CLIENTS |
  687. DEBUG_OUTCTL_OVERRIDE_MASK,
  688. Cmd, DEBUG_EXECUTE_DEFAULT);
  689. g_ExtControl->Execute(DEBUG_OUTCTL_ALL_CLIENTS |
  690. DEBUG_OUTCTL_OVERRIDE_MASK,
  691. "kb", DEBUG_EXECUTE_DEFAULT);
  692. g_ExtControl->Execute(DEBUG_OUTCTL_ALL_CLIENTS |
  693. DEBUG_OUTCTL_OVERRIDE_MASK,
  694. ".cxr", DEBUG_EXECUTE_DEFAULT);
  695. return TRUE;
  696. }
  697. BOOL
  698. IsFunctionAddr(
  699. ULONG64 IP,
  700. PSTR FuncName
  701. )
  702. // Check if IP is in the function FuncName
  703. {
  704. CHAR Buffer[MAX_PATH], *scan, *FnIP;
  705. ULONG64 Disp;
  706. GetSymbol(IP, Buffer, &Disp);
  707. if (scan = strchr(Buffer, '!')) {
  708. FnIP = scan+1;
  709. while (*FnIP == '_') ++FnIP;
  710. } else {
  711. FnIP = &Buffer[0];
  712. }
  713. return !strncmp(FnIP, FuncName, strlen(FuncName));
  714. }
  715. BOOL
  716. GetExceptionPointerFromStack(
  717. PULONG64 pExcePtr
  718. )
  719. {
  720. #define MAX_STACK_FRAMES 50
  721. DEBUG_STACK_FRAME stk[MAX_STACK_FRAMES], *Frame;
  722. ULONG nFrames;
  723. if (g_ExtControl->GetStackTrace(0, 0, 0, stk, MAX_STACK_FRAMES, &nFrames ) == S_OK) {
  724. for (unsigned int i=0; i<nFrames; ++i) {
  725. if (IsFunctionAddr(stk[i].InstructionOffset, "UnhandledExceptionFilter")) {
  726. *pExcePtr = stk[i].Params[0];
  727. return TRUE;
  728. }
  729. }
  730. }
  731. return FALSE;
  732. }
  733. /*****************************************************************************************
  734. *
  735. * Do analysis for a given exception pointer
  736. *
  737. ******************************************************************************************/
  738. DECLARE_API ( analyzeexcep )
  739. {
  740. ULONG64 ExcepPtr=0;
  741. INIT_API();
  742. GetExpressionEx(args, &ExcepPtr, &args);
  743. if (!ExcepPtr) {
  744. GetExceptionPointerFromStack(&ExcepPtr);
  745. }
  746. if (ExcepPtr) {
  747. AnalyzeExceptionPointer(ExcepPtr);
  748. } else {
  749. dprintf("Cannot get exception pointer\n");
  750. }
  751. EXIT_API();
  752. return S_OK;
  753. }