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.

3447 lines
92 KiB

  1. //----------------------------------------------------------------------------
  2. //
  3. // Extension DLL support.
  4. //
  5. // Copyright (C) Microsoft Corporation, 1997-2001.
  6. //
  7. //----------------------------------------------------------------------------
  8. #include "ntsdp.hpp"
  9. #include <time.h>
  10. /*
  11. * _NT_DEBUG_OPTIONS support. Each option in g_EnvDbgOptionNames must have a
  12. * corresponding OPTION_* define, in the same order.
  13. */
  14. DWORD g_EnvDbgOptions;
  15. char * g_EnvDbgOptionNames [OPTION_COUNT] =
  16. {
  17. "NOEXTWARNING",
  18. "NOVERSIONCHECK",
  19. };
  20. ULONG g_PipeSerialNumber;
  21. EXTDLL *g_ExtDlls;
  22. LPTSTR g_ExtensionSearchPath = NULL;
  23. ULONG64 g_ExtThread;
  24. ULONG g_ExtGetExpressionRemainderIndex;
  25. BOOL g_ExtGetExpressionSuccess;
  26. WOW64EXTSPROC g_Wow64exts;
  27. WMI_FORMAT_TRACE_DATA g_WmiFormatTraceData;
  28. DEBUG_SCOPE g_ExtThreadSavedScope;
  29. BOOL g_ExtThreadScopeSaved;
  30. WINDBG_EXTENSION_APIS64 g_WindbgExtensions64 =
  31. {
  32. sizeof(g_WindbgExtensions64),
  33. ExtOutput64,
  34. ExtGetExpression,
  35. ExtGetSymbol,
  36. ExtDisasm,
  37. CheckUserInterrupt,
  38. (PWINDBG_READ_PROCESS_MEMORY_ROUTINE64)ExtReadVirtualMemory,
  39. ExtWriteVirtualMemory,
  40. (PWINDBG_GET_THREAD_CONTEXT_ROUTINE)ExtGetThreadContext,
  41. (PWINDBG_SET_THREAD_CONTEXT_ROUTINE)ExtSetThreadContext,
  42. (PWINDBG_IOCTL_ROUTINE)ExtIoctl,
  43. ExtCallStack
  44. };
  45. WINDBG_EXTENSION_APIS32 g_WindbgExtensions32 =
  46. {
  47. sizeof(g_WindbgExtensions32),
  48. ExtOutput32,
  49. ExtGetExpression32,
  50. ExtGetSymbol32,
  51. ExtDisasm32,
  52. CheckUserInterrupt,
  53. (PWINDBG_READ_PROCESS_MEMORY_ROUTINE32)ExtReadVirtualMemory32,
  54. ExtWriteVirtualMemory32,
  55. (PWINDBG_GET_THREAD_CONTEXT_ROUTINE)ExtGetThreadContext,
  56. (PWINDBG_SET_THREAD_CONTEXT_ROUTINE)ExtSetThreadContext,
  57. (PWINDBG_IOCTL_ROUTINE)ExtIoctl32,
  58. ExtCallStack32
  59. };
  60. WINDBG_OLDKD_EXTENSION_APIS g_KdExtensions =
  61. {
  62. sizeof(g_KdExtensions),
  63. ExtOutput32,
  64. ExtGetExpression32,
  65. ExtGetSymbol32,
  66. ExtDisasm32,
  67. CheckUserInterrupt,
  68. (PWINDBG_READ_PROCESS_MEMORY_ROUTINE32)ExtReadVirtualMemory32,
  69. ExtWriteVirtualMemory32,
  70. (PWINDBG_OLDKD_READ_PHYSICAL_MEMORY)ExtReadPhysicalMemory,
  71. (PWINDBG_OLDKD_WRITE_PHYSICAL_MEMORY)ExtWritePhysicalMemory
  72. };
  73. NTSD_EXTENSION_APIS g_NtsdExtensions64 =
  74. {
  75. sizeof(g_NtsdExtensions64),
  76. (PNTSD_OUTPUT_ROUTINE)ExtOutput32,
  77. (PNTSD_GET_EXPRESSION)ExtGetExpression,
  78. (PNTSD_GET_SYMBOL)ExtGetSymbol,
  79. (PNTSD_DISASM)ExtDisasm,
  80. (PNTSD_CHECK_CONTROL_C)CheckUserInterrupt,
  81. };
  82. NTSD_EXTENSION_APIS g_NtsdExtensions32 =
  83. {
  84. sizeof(g_NtsdExtensions32),
  85. (PNTSD_OUTPUT_ROUTINE)ExtOutput32,
  86. (PNTSD_GET_EXPRESSION)ExtGetExpression32,
  87. (PNTSD_GET_SYMBOL)ExtGetSymbol32,
  88. (PNTSD_DISASM)ExtDisasm32,
  89. (PNTSD_CHECK_CONTROL_C)CheckUserInterrupt,
  90. };
  91. VOID WDBGAPIV
  92. ExtOutput64(
  93. PCSTR lpFormat,
  94. ...
  95. )
  96. {
  97. va_list Args;
  98. va_start(Args, lpFormat);
  99. MaskOutVa(DEBUG_OUTPUT_NORMAL, lpFormat, Args, TRUE);
  100. va_end(Args);
  101. // Make sure output for long-running extensions appears regularly.
  102. TimedFlushCallbacks();
  103. }
  104. VOID WDBGAPIV
  105. ExtOutput32(
  106. PCSTR lpFormat,
  107. ...
  108. )
  109. {
  110. va_list Args;
  111. va_start(Args, lpFormat);
  112. MaskOutVa(DEBUG_OUTPUT_NORMAL, lpFormat, Args, FALSE);
  113. va_end(Args);
  114. // Make sure output for long-running extensions appears regularly.
  115. TimedFlushCallbacks();
  116. }
  117. ULONG64
  118. ExtGetExpression(
  119. PCSTR CommandString
  120. )
  121. {
  122. g_ExtGetExpressionSuccess = FALSE;
  123. if (CommandString == NULL)
  124. {
  125. return 0;
  126. }
  127. ULONG64 ReturnValue;
  128. PSTR SaveCommand;
  129. PSTR SaveStart = g_CommandStart;
  130. if (IS_USER_TARGET())
  131. {
  132. if ( strcmp(CommandString, "WOW_BIG_BDE_HACK") == 0 )
  133. {
  134. return( (ULONG_PTR)(&segtable[0]) );
  135. }
  136. //
  137. // this is because the kdexts MUST include the address-of operator
  138. // on all getexpression calls for windbg/c expression evaluators
  139. //
  140. if (*CommandString == '&')
  141. {
  142. CommandString++;
  143. }
  144. }
  145. SaveCommand = g_CurCmd;
  146. g_CurCmd = (PSTR)CommandString;
  147. g_CommandStart = (PSTR)CommandString;
  148. g_DisableErrorPrint = TRUE;
  149. __try
  150. {
  151. ReturnValue = GetExpression();
  152. g_ExtGetExpressionSuccess = TRUE;
  153. }
  154. __except(CommandExceptionFilter(GetExceptionInformation()))
  155. {
  156. ReturnValue = 0;
  157. }
  158. g_ExtGetExpressionRemainderIndex =
  159. (ULONG)(g_CurCmd - g_CommandStart);
  160. g_DisableErrorPrint = FALSE;
  161. g_CurCmd = SaveCommand;
  162. g_CommandStart = SaveStart;
  163. // Make sure output for long-running extensions appears regularly.
  164. TimedFlushCallbacks();
  165. return ReturnValue;
  166. }
  167. ULONG
  168. ExtGetExpression32(
  169. LPCSTR CommandString
  170. )
  171. {
  172. return (ULONG)ExtGetExpression(CommandString);
  173. }
  174. void
  175. ExtGetSymbol (
  176. ULONG64 offset,
  177. PCHAR pchBuffer,
  178. PULONG64 pDisplacement
  179. )
  180. {
  181. // No way to know how much space we're given, so
  182. // just assume 256, which many extensions pass in
  183. GetSymbolStdCall(offset, pchBuffer, 256, pDisplacement, NULL);
  184. // Make sure output for long-running extensions appears regularly.
  185. TimedFlushCallbacks();
  186. }
  187. void
  188. ExtGetSymbol32(
  189. ULONG offset,
  190. PCHAR pchBuffer,
  191. PULONG pDisplacement
  192. )
  193. {
  194. ULONG64 Displacement;
  195. // No way to know how much space we're given, so
  196. // just assume 256, which many extensions pass in
  197. GetSymbolStdCall(EXTEND64(offset), pchBuffer, 256,
  198. &Displacement, NULL);
  199. *pDisplacement = (ULONG)Displacement;
  200. // Make sure output for long-running extensions appears regularly.
  201. TimedFlushCallbacks();
  202. }
  203. DWORD
  204. ExtDisasm(
  205. ULONG64 *lpOffset,
  206. PCSTR lpBuffer,
  207. ULONG fShowEA
  208. )
  209. {
  210. if (!IS_MACHINE_ACCESSIBLE())
  211. {
  212. ErrOut("ExtDisasm called before debugger initialized\n");
  213. return FALSE;
  214. }
  215. ADDR tempAddr;
  216. BOOL ret;
  217. Type(tempAddr) = ADDR_FLAT | FLAT_COMPUTED;
  218. Off(tempAddr) = Flat(tempAddr) = *lpOffset;
  219. ret = g_Machine->Disassemble(&tempAddr, (PSTR)lpBuffer, (BOOL) fShowEA);
  220. *lpOffset = Flat(tempAddr);
  221. return ret;
  222. }
  223. DWORD
  224. ExtDisasm32(
  225. ULONG *lpOffset,
  226. PCSTR lpBuffer,
  227. ULONG fShowEA
  228. )
  229. {
  230. ULONG64 Offset = EXTEND64(*lpOffset);
  231. DWORD rval = ExtDisasm(&Offset, lpBuffer, fShowEA);
  232. *lpOffset = (ULONG)Offset;
  233. return rval;
  234. }
  235. BOOL
  236. ExtGetThreadContext(
  237. DWORD Processor,
  238. PVOID lpContext,
  239. DWORD cbSizeOfContext
  240. )
  241. {
  242. if (!IS_MACHINE_ACCESSIBLE())
  243. {
  244. return FALSE;
  245. }
  246. // This get may be getting the context of the thread
  247. // currently cached by the register code. Make sure
  248. // the cache is flushed.
  249. FlushRegContext();
  250. CROSS_PLATFORM_CONTEXT TargetContext;
  251. g_TargetMachine->InitializeContextFlags(&TargetContext, g_SystemVersion);
  252. if (g_Target->GetContext(IS_KERNEL_TARGET() ?
  253. VIRTUAL_THREAD_HANDLE(Processor) : Processor,
  254. &TargetContext) == S_OK &&
  255. g_Machine->ConvertContextTo(&TargetContext, g_SystemVersion,
  256. cbSizeOfContext, lpContext) == S_OK)
  257. {
  258. return TRUE;
  259. }
  260. return FALSE;
  261. }
  262. BOOL
  263. ExtSetThreadContext(
  264. DWORD Processor,
  265. PVOID lpContext,
  266. DWORD cbSizeOfContext
  267. )
  268. {
  269. if (!IS_MACHINE_ACCESSIBLE())
  270. {
  271. return FALSE;
  272. }
  273. BOOL Status;
  274. // This set may be setting the context of the thread
  275. // currently cached by the register code. Make sure
  276. // the cache is invalidated.
  277. ChangeRegContext(NULL);
  278. CROSS_PLATFORM_CONTEXT TargetContext;
  279. if (g_Machine->ConvertContextFrom(&TargetContext, g_SystemVersion,
  280. cbSizeOfContext, lpContext) == S_OK &&
  281. g_Target->SetContext(IS_KERNEL_TARGET() ?
  282. VIRTUAL_THREAD_HANDLE(Processor) : Processor,
  283. &TargetContext) == S_OK)
  284. {
  285. Status = TRUE;
  286. }
  287. else
  288. {
  289. Status = FALSE;
  290. }
  291. // Reset the current thread.
  292. ChangeRegContext(g_CurrentProcess->CurrentThread);
  293. return Status;
  294. }
  295. BOOL
  296. ExtReadVirtualMemory(
  297. IN ULONG64 pBufSrc,
  298. OUT PUCHAR pBufDest,
  299. IN ULONG count,
  300. OUT PULONG pcTotalBytesRead
  301. )
  302. {
  303. // Make sure output for long-running extensions appears regularly.
  304. TimedFlushCallbacks();
  305. ULONG BytesTemp;
  306. return g_Target->
  307. ReadVirtual(pBufSrc, pBufDest, count, pcTotalBytesRead != NULL ?
  308. pcTotalBytesRead : &BytesTemp) == S_OK;
  309. }
  310. BOOL
  311. ExtReadVirtualMemory32(
  312. IN ULONG pBufSrc,
  313. OUT PUCHAR pBufDest,
  314. IN ULONG count,
  315. OUT PULONG pcTotalBytesRead
  316. )
  317. {
  318. // Make sure output for long-running extensions appears regularly.
  319. TimedFlushCallbacks();
  320. ULONG BytesTemp;
  321. return g_Target->
  322. ReadVirtual(EXTEND64(pBufSrc), pBufDest, count,
  323. pcTotalBytesRead != NULL ?
  324. pcTotalBytesRead : &BytesTemp) == S_OK;
  325. }
  326. DWORD
  327. ExtWriteVirtualMemory(
  328. IN ULONG64 addr,
  329. IN LPCVOID buffer,
  330. IN ULONG count,
  331. OUT PULONG pcBytesWritten
  332. )
  333. {
  334. ULONG BytesTemp;
  335. return (g_Target->WriteVirtual(addr, (PVOID)buffer, count,
  336. pcBytesWritten != NULL ?
  337. pcBytesWritten : &BytesTemp) == S_OK);
  338. }
  339. ULONG
  340. ExtWriteVirtualMemory32 (
  341. IN ULONG addr,
  342. IN LPCVOID buffer,
  343. IN ULONG count,
  344. OUT PULONG pcBytesWritten
  345. )
  346. {
  347. ULONG BytesTemp;
  348. return (g_Target->WriteVirtual(EXTEND64(addr),
  349. (PVOID)buffer, count,
  350. pcBytesWritten != NULL ?
  351. pcBytesWritten : &BytesTemp) == S_OK);
  352. }
  353. BOOL
  354. ExtReadPhysicalMemory(
  355. ULONGLONG pBufSrc,
  356. PVOID pBufDest,
  357. ULONG count,
  358. PULONG pcTotalBytesRead
  359. )
  360. {
  361. // Make sure output for long-running extensions appears regularly.
  362. TimedFlushCallbacks();
  363. if (ARGUMENT_PRESENT(pcTotalBytesRead)) {
  364. *pcTotalBytesRead = 0;
  365. }
  366. ULONG BytesTemp;
  367. return g_Target->ReadPhysical(pBufSrc, pBufDest, count,
  368. pcTotalBytesRead != NULL ?
  369. pcTotalBytesRead : &BytesTemp) == S_OK;
  370. }
  371. BOOL
  372. ExtWritePhysicalMemory (
  373. ULONGLONG pBufDest,
  374. LPCVOID pBufSrc,
  375. ULONG count,
  376. PULONG pcTotalBytesWritten
  377. )
  378. {
  379. if (ARGUMENT_PRESENT(pcTotalBytesWritten)) {
  380. *pcTotalBytesWritten = 0;
  381. }
  382. ULONG BytesTemp;
  383. return g_Target->WritePhysical(pBufDest, (PVOID)pBufSrc, count,
  384. pcTotalBytesWritten != NULL ?
  385. pcTotalBytesWritten : &BytesTemp) == S_OK;
  386. }
  387. DWORD
  388. ExtCallStack(
  389. DWORD64 FramePointer,
  390. DWORD64 StackPointer,
  391. DWORD64 ProgramCounter,
  392. PEXTSTACKTRACE64 ExtStackFrames,
  393. DWORD Frames
  394. )
  395. {
  396. PDEBUG_STACK_FRAME StackFrames;
  397. DWORD FrameCount;
  398. DWORD i;
  399. StackFrames = (PDEBUG_STACK_FRAME)
  400. malloc( sizeof(StackFrames[0]) * Frames );
  401. if (!StackFrames)
  402. {
  403. return 0;
  404. }
  405. FrameCount = StackTrace( FramePointer, StackPointer, ProgramCounter,
  406. StackFrames, Frames, g_ExtThread, 0, FALSE );
  407. for (i = 0; i < FrameCount; i++)
  408. {
  409. ExtStackFrames[i].FramePointer = StackFrames[i].FrameOffset;
  410. ExtStackFrames[i].ProgramCounter = StackFrames[i].InstructionOffset;
  411. ExtStackFrames[i].ReturnAddress = StackFrames[i].ReturnOffset;
  412. ExtStackFrames[i].Args[0] = StackFrames[i].Params[0];
  413. ExtStackFrames[i].Args[1] = StackFrames[i].Params[1];
  414. ExtStackFrames[i].Args[2] = StackFrames[i].Params[2];
  415. ExtStackFrames[i].Args[3] = StackFrames[i].Params[3];
  416. }
  417. free( StackFrames );
  418. if (g_ExtThreadScopeSaved)
  419. {
  420. PopScope(&g_ExtThreadSavedScope);
  421. g_ExtThreadScopeSaved = FALSE;
  422. }
  423. g_ExtThread = 0;
  424. return FrameCount;
  425. }
  426. DWORD
  427. ExtCallStack32(
  428. DWORD FramePointer,
  429. DWORD StackPointer,
  430. DWORD ProgramCounter,
  431. PEXTSTACKTRACE32 ExtStackFrames,
  432. DWORD Frames
  433. )
  434. {
  435. PDEBUG_STACK_FRAME StackFrames;
  436. DWORD FrameCount;
  437. DWORD i;
  438. StackFrames = (PDEBUG_STACK_FRAME)
  439. malloc( sizeof(StackFrames[0]) * Frames );
  440. if (!StackFrames)
  441. {
  442. return 0;
  443. }
  444. FrameCount = StackTrace(EXTEND64(FramePointer),
  445. EXTEND64(StackPointer),
  446. EXTEND64(ProgramCounter),
  447. StackFrames,
  448. Frames,
  449. g_ExtThread,
  450. 0,
  451. FALSE);
  452. for (i=0; i<FrameCount; i++)
  453. {
  454. ExtStackFrames[i].FramePointer = (ULONG)StackFrames[i].FrameOffset;
  455. ExtStackFrames[i].ProgramCounter = (ULONG)StackFrames[i].InstructionOffset;
  456. ExtStackFrames[i].ReturnAddress = (ULONG)StackFrames[i].ReturnOffset;
  457. ExtStackFrames[i].Args[0] = (ULONG)StackFrames[i].Params[0];
  458. ExtStackFrames[i].Args[1] = (ULONG)StackFrames[i].Params[1];
  459. ExtStackFrames[i].Args[2] = (ULONG)StackFrames[i].Params[2];
  460. ExtStackFrames[i].Args[3] = (ULONG)StackFrames[i].Params[3];
  461. }
  462. free( StackFrames );
  463. if (g_ExtThreadScopeSaved)
  464. {
  465. PopScope(&g_ExtThreadSavedScope);
  466. g_ExtThreadScopeSaved = FALSE;
  467. }
  468. g_ExtThread = 0;
  469. return FrameCount;
  470. }
  471. BOOL
  472. ExtIoctl(
  473. USHORT IoctlType,
  474. LPVOID lpvData,
  475. DWORD cbSize
  476. )
  477. {
  478. HRESULT Status;
  479. BOOL Bool;
  480. DWORD cb = 0;
  481. PPHYSICAL phy;
  482. PIOSPACE64 is;
  483. PIOSPACE_EX64 isex;
  484. PBUSDATA busdata;
  485. PREAD_WRITE_MSR msr;
  486. PREADCONTROLSPACE64 prc;
  487. PPROCESSORINFO pi;
  488. PSEARCHMEMORY psr;
  489. PSYM_DUMP_PARAM pSym;
  490. PGET_CURRENT_THREAD_ADDRESS pct;
  491. PGET_CURRENT_PROCESS_ADDRESS pcp;
  492. // Make sure output for long-running extensions appears regularly.
  493. TimedFlushCallbacks();
  494. switch( IoctlType )
  495. {
  496. case IG_KD_CONTEXT:
  497. pi = (PPROCESSORINFO) lpvData;
  498. pi->Processor = (USHORT)CURRENT_PROC;
  499. pi->NumberProcessors = (USHORT) g_TargetNumberProcessors;
  500. return TRUE;
  501. case IG_READ_CONTROL_SPACE:
  502. // KSPECIAL_REGISTER content is kept in control space
  503. // so accessing control space may touch data that's
  504. // cached in the current machine KSPECIAL_REGISTERS.
  505. // Flush the current machine to maintain consistency.
  506. if (IS_MACHINE_ACCESSIBLE())
  507. {
  508. FlushRegContext();
  509. }
  510. prc = (PREADCONTROLSPACE64)lpvData;
  511. Status = g_Target->ReadControl( prc->Processor,
  512. prc->Address,
  513. prc->Buf,
  514. prc->BufLen,
  515. &cb
  516. );
  517. prc->BufLen = cb;
  518. return Status == S_OK;
  519. case IG_WRITE_CONTROL_SPACE:
  520. // KSPECIAL_REGISTER content is kept in control space
  521. // so accessing control space may touch data that's
  522. // cached in the current machine KSPECIAL_REGISTERS.
  523. // Flush the current machine to maintain consistency.
  524. if (IS_MACHINE_ACCESSIBLE())
  525. {
  526. FlushRegContext();
  527. }
  528. prc = (PREADCONTROLSPACE64)lpvData;
  529. Status = g_Target->WriteControl( prc->Processor,
  530. prc->Address,
  531. prc->Buf,
  532. prc->BufLen,
  533. &cb
  534. );
  535. prc->BufLen = cb;
  536. return Status == S_OK;
  537. case IG_READ_IO_SPACE:
  538. is = (PIOSPACE64)lpvData;
  539. Status = g_Target->ReadIo( Isa, 0, 1, is->Address, &is->Data,
  540. is->Length, &cb );
  541. return Status == S_OK;
  542. case IG_WRITE_IO_SPACE:
  543. is = (PIOSPACE64)lpvData;
  544. Status = g_Target->WriteIo( Isa, 0, 1, is->Address, &is->Data,
  545. is->Length, &cb );
  546. return Status == S_OK;
  547. case IG_READ_IO_SPACE_EX:
  548. isex = (PIOSPACE_EX64)lpvData;
  549. Status = g_Target->ReadIo( isex->InterfaceType,
  550. isex->BusNumber,
  551. isex->AddressSpace,
  552. isex->Address,
  553. &isex->Data,
  554. isex->Length,
  555. &cb
  556. );
  557. return Status == S_OK;
  558. case IG_WRITE_IO_SPACE_EX:
  559. isex = (PIOSPACE_EX64)lpvData;
  560. Status = g_Target->WriteIo( isex->InterfaceType,
  561. isex->BusNumber,
  562. isex->AddressSpace,
  563. isex->Address,
  564. &isex->Data,
  565. isex->Length,
  566. &cb
  567. );
  568. return Status == S_OK;
  569. case IG_READ_PHYSICAL:
  570. phy = (PPHYSICAL)lpvData;
  571. Bool =
  572. ExtReadPhysicalMemory( phy->Address, phy->Buf, phy->BufLen, &cb );
  573. phy->BufLen = cb;
  574. return Bool;
  575. case IG_WRITE_PHYSICAL:
  576. phy = (PPHYSICAL)lpvData;
  577. Bool =
  578. ExtWritePhysicalMemory( phy->Address, phy->Buf, phy->BufLen, &cb );
  579. phy->BufLen = cb;
  580. return Bool;
  581. case IG_LOWMEM_CHECK:
  582. Status = g_Target->CheckLowMemory();
  583. return Status == S_OK;
  584. case IG_SEARCH_MEMORY:
  585. psr = (PSEARCHMEMORY)lpvData;
  586. Status = g_Target->SearchVirtual(psr->SearchAddress,
  587. psr->SearchLength,
  588. psr->Pattern,
  589. psr->PatternLength,
  590. 1,
  591. &psr->FoundAddress);
  592. return Status == S_OK;
  593. case IG_SET_THREAD:
  594. Bool = FALSE;
  595. if (IS_KERNEL_TARGET())
  596. {
  597. g_EngNotify++; // Turn off engine notifications since this setthread is temporary
  598. PushScope(&g_ExtThreadSavedScope);
  599. g_ExtThread = *(PULONG64)lpvData;
  600. Bool = SetContextFromThreadData(g_ExtThread, FALSE) == S_OK;
  601. g_ExtThreadScopeSaved = TRUE;
  602. g_EngNotify--;
  603. }
  604. return Bool;
  605. case IG_READ_MSR:
  606. msr = (PREAD_WRITE_MSR)lpvData;
  607. Status = g_Target->ReadMsr (msr->Msr, (PULONG64)&msr->Value);
  608. return Status == S_OK;
  609. case IG_WRITE_MSR:
  610. msr = (PREAD_WRITE_MSR)lpvData;
  611. Status = g_Target->WriteMsr (msr->Msr, msr->Value);
  612. return Status == S_OK;
  613. case IG_GET_KERNEL_VERSION:
  614. *((PDBGKD_GET_VERSION64)lpvData) = g_KdVersion;
  615. return TRUE;
  616. case IG_GET_BUS_DATA:
  617. busdata = (PBUSDATA)lpvData;
  618. Status = g_Target->ReadBusData( busdata->BusDataType,
  619. busdata->BusNumber,
  620. busdata->SlotNumber,
  621. busdata->Offset,
  622. busdata->Buffer,
  623. busdata->Length,
  624. &cb
  625. );
  626. busdata->Length = cb;
  627. return Status == S_OK;
  628. case IG_SET_BUS_DATA:
  629. busdata = (PBUSDATA)lpvData;
  630. Status = g_Target->WriteBusData( busdata->BusDataType,
  631. busdata->BusNumber,
  632. busdata->SlotNumber,
  633. busdata->Offset,
  634. busdata->Buffer,
  635. busdata->Length,
  636. &cb
  637. );
  638. busdata->Length = cb;
  639. return Status == S_OK;
  640. case IG_GET_CURRENT_THREAD:
  641. pct = (PGET_CURRENT_THREAD_ADDRESS) lpvData;
  642. return g_Target->
  643. GetThreadInfoDataOffset(NULL,
  644. VIRTUAL_THREAD_HANDLE(pct->Processor),
  645. &pct->Address) == S_OK;
  646. case IG_GET_CURRENT_PROCESS:
  647. pcp = (PGET_CURRENT_PROCESS_ADDRESS) lpvData;
  648. return g_Target->
  649. GetProcessInfoDataOffset(NULL,
  650. pcp->Processor,
  651. pcp->CurrentThread,
  652. &pcp->Address) == S_OK;
  653. case IG_GET_DEBUGGER_DATA:
  654. if (!IS_KERNEL_TARGET() ||
  655. ((PDBGKD_DEBUG_DATA_HEADER64)lpvData)->OwnerTag != KDBG_TAG)
  656. {
  657. return FALSE;
  658. }
  659. // Don't refresh if asking for the kernel header.
  660. memcpy(lpvData, &KdDebuggerData, min(sizeof(KdDebuggerData), cbSize));
  661. return TRUE;
  662. case IG_RELOAD_SYMBOLS:
  663. return g_Target->Reload((PCHAR)lpvData) == S_OK;
  664. case IG_GET_SET_SYMPATH:
  665. PGET_SET_SYMPATH pgs;
  666. pgs = (PGET_SET_SYMPATH)lpvData;
  667. bangSymPath((PCHAR)pgs->Args, FALSE, (PCHAR)pgs->Result,
  668. pgs->Length);
  669. return TRUE;
  670. case IG_IS_PTR64:
  671. *((PBOOL)lpvData) = g_TargetMachine->m_Ptr64;
  672. return TRUE;
  673. case IG_DUMP_SYMBOL_INFO:
  674. pSym = (PSYM_DUMP_PARAM) lpvData;
  675. SymbolTypeDump(g_CurrentProcess->Handle,
  676. g_CurrentProcess->ImageHead,
  677. pSym, (PULONG)&Status);
  678. return Status;
  679. case IG_GET_TYPE_SIZE:
  680. pSym = (PSYM_DUMP_PARAM) lpvData;
  681. return SymbolTypeDump(g_CurrentProcess->Handle,
  682. g_CurrentProcess->ImageHead,
  683. pSym, (PULONG)&Status);
  684. case IG_GET_TEB_ADDRESS:
  685. PGET_TEB_ADDRESS pTeb;
  686. pTeb = (PGET_TEB_ADDRESS) lpvData;
  687. return g_Target->
  688. GetThreadInfoTeb(NULL,
  689. 0,
  690. NULL,
  691. &pTeb->Address) == S_OK;
  692. case IG_GET_PEB_ADDRESS:
  693. PGET_PEB_ADDRESS pPeb;
  694. pPeb = (PGET_PEB_ADDRESS) lpvData;
  695. return g_Target->
  696. GetProcessInfoPeb(NULL,
  697. 0,
  698. pPeb->CurrentThread,
  699. &pPeb->Address) == S_OK;
  700. case IG_GET_CURRENT_PROCESS_HANDLE:
  701. *(PHANDLE)lpvData = g_CurrentProcess->Handle;
  702. return TRUE;
  703. case IG_GET_INPUT_LINE:
  704. PGET_INPUT_LINE Gil;
  705. Gil = (PGET_INPUT_LINE)lpvData;
  706. Gil->InputSize = GetInput(Gil->Prompt, Gil->Buffer, Gil->BufferSize);
  707. return TRUE;
  708. case IG_GET_EXPRESSION_EX:
  709. PGET_EXPRESSION_EX Gee;
  710. Gee = (PGET_EXPRESSION_EX)lpvData;
  711. Gee->Value = ExtGetExpression(Gee->Expression);
  712. Gee->Remainder = Gee->Expression + g_ExtGetExpressionRemainderIndex;
  713. return g_ExtGetExpressionSuccess;
  714. case IG_TRANSLATE_VIRTUAL_TO_PHYSICAL:
  715. if (!IS_MACHINE_ACCESSIBLE())
  716. {
  717. return FALSE;
  718. }
  719. PTRANSLATE_VIRTUAL_TO_PHYSICAL Tvtp;
  720. Tvtp = (PTRANSLATE_VIRTUAL_TO_PHYSICAL)lpvData;
  721. ULONG Levels, PfIndex;
  722. return g_Machine->
  723. GetVirtualTranslationPhysicalOffsets(Tvtp->Virtual, NULL, 0,
  724. &Levels, &PfIndex,
  725. &Tvtp->Physical) == S_OK;
  726. case IG_GET_CACHE_SIZE:
  727. PULONG64 pCacheSize;
  728. pCacheSize = (PULONG64)lpvData;
  729. if (IS_KERNEL_TARGET()) {
  730. *pCacheSize = g_VirtualCache.m_MaxSize;
  731. return TRUE;
  732. }
  733. return FALSE;
  734. default:
  735. ErrOut( "\n*** Bad IOCTL request from an extension [%d]\n\n",
  736. IoctlType );
  737. return FALSE;
  738. }
  739. // NOTREACHED.
  740. DBG_ASSERT(FALSE);
  741. return FALSE;
  742. }
  743. BOOL
  744. ExtIoctl32(
  745. USHORT IoctlType,
  746. LPVOID lpvData,
  747. DWORD cbSize
  748. )
  749. /*++
  750. Routine Description:
  751. This is the extension Ioctl routine for backward compatibility with
  752. old extension dlls. This routine is frozen, and new ioctl support
  753. should not be added to it.
  754. Arguments:
  755. Return Value:
  756. --*/
  757. {
  758. HRESULT Status;
  759. DWORD cb = 0;
  760. PIOSPACE32 is;
  761. PIOSPACE_EX32 isex;
  762. PREADCONTROLSPACE prc;
  763. PDBGKD_DEBUG_DATA_HEADER32 hdr;
  764. PDBGKD_GET_VERSION32 pv32;
  765. PKDDEBUGGER_DATA32 pdbg32;
  766. // Make sure output for long-running extensions appears regularly.
  767. TimedFlushCallbacks();
  768. switch( IoctlType )
  769. {
  770. case IG_READ_CONTROL_SPACE:
  771. // KSPECIAL_REGISTER content is kept in control space
  772. // so accessing control space may touch data that's
  773. // cached in the current machine KSPECIAL_REGISTERS.
  774. // Flush the current machine to maintain consistency.
  775. if (IS_MACHINE_ACCESSIBLE())
  776. {
  777. FlushRegContext();
  778. }
  779. prc = (PREADCONTROLSPACE)lpvData;
  780. Status = g_Target->ReadControl( prc->Processor,
  781. prc->Address,
  782. prc->Buf,
  783. prc->BufLen,
  784. &cb
  785. );
  786. prc->BufLen = cb;
  787. return Status == S_OK;
  788. case IG_WRITE_CONTROL_SPACE:
  789. // KSPECIAL_REGISTER content is kept in control space
  790. // so accessing control space may touch data that's
  791. // cached in the current machine KSPECIAL_REGISTERS.
  792. // Flush the current machine to maintain consistency.
  793. if (IS_MACHINE_ACCESSIBLE())
  794. {
  795. FlushRegContext();
  796. }
  797. prc = (PREADCONTROLSPACE)lpvData;
  798. Status = g_Target->WriteControl( prc->Processor,
  799. prc->Address,
  800. prc->Buf,
  801. prc->BufLen,
  802. &cb
  803. );
  804. prc->BufLen = cb;
  805. return Status == S_OK;
  806. case IG_READ_IO_SPACE:
  807. is = (PIOSPACE32)lpvData;
  808. Status = g_Target->ReadIo( Isa, 0, 1, is->Address, &is->Data,
  809. is->Length, &cb );
  810. return Status == S_OK;
  811. case IG_WRITE_IO_SPACE:
  812. is = (PIOSPACE32)lpvData;
  813. Status = g_Target->WriteIo( Isa, 0, 1, is->Address, &is->Data,
  814. is->Length, &cb );
  815. return Status == S_OK;
  816. case IG_READ_IO_SPACE_EX:
  817. isex = (PIOSPACE_EX32)lpvData;
  818. Status = g_Target->ReadIo( isex->InterfaceType,
  819. isex->BusNumber,
  820. isex->AddressSpace,
  821. isex->Address,
  822. &isex->Data,
  823. isex->Length,
  824. &cb
  825. );
  826. return Status == S_OK;
  827. case IG_WRITE_IO_SPACE_EX:
  828. isex = (PIOSPACE_EX32)lpvData;
  829. Status = g_Target->WriteIo( isex->InterfaceType,
  830. isex->BusNumber,
  831. isex->AddressSpace,
  832. isex->Address,
  833. &isex->Data,
  834. isex->Length,
  835. &cb
  836. );
  837. return Status == S_OK;
  838. case IG_SET_THREAD:
  839. if (IS_KERNEL_TARGET())
  840. {
  841. g_EngNotify++; // Turn off engine notifications since this setthread is temporary
  842. g_ExtThread = EXTEND64(*(PULONG)lpvData);
  843. PushScope(&g_ExtThreadSavedScope);
  844. SetContextFromThreadData(g_ExtThread, FALSE);
  845. g_ExtThreadScopeSaved = TRUE;
  846. g_EngNotify--;
  847. return TRUE;
  848. }
  849. else
  850. {
  851. return FALSE;
  852. }
  853. case IG_GET_KERNEL_VERSION:
  854. //
  855. // Convert to 32 bit
  856. //
  857. pv32 = (PDBGKD_GET_VERSION32)lpvData;
  858. pv32->MajorVersion = g_KdVersion.MajorVersion;
  859. pv32->MinorVersion = g_KdVersion.MinorVersion;
  860. pv32->ProtocolVersion = g_KdVersion.ProtocolVersion;
  861. pv32->Flags = g_KdVersion.Flags;
  862. pv32->KernBase = (ULONG)g_KdVersion.KernBase;
  863. pv32->PsLoadedModuleList = (ULONG)g_KdVersion.PsLoadedModuleList;
  864. pv32->MachineType = g_KdVersion.MachineType;
  865. pv32->DebuggerDataList = (ULONG)g_KdVersion.DebuggerDataList;
  866. pv32->ThCallbackStack = KdDebuggerData.ThCallbackStack;
  867. pv32->NextCallback = KdDebuggerData.NextCallback;
  868. pv32->FramePointer = KdDebuggerData.FramePointer;
  869. pv32->KiCallUserMode =
  870. (ULONG)KdDebuggerData.KiCallUserMode;
  871. pv32->KeUserCallbackDispatcher =
  872. (ULONG)KdDebuggerData.KeUserCallbackDispatcher;
  873. pv32->BreakpointWithStatus =
  874. (ULONG)KdDebuggerData.BreakpointWithStatus;
  875. return TRUE;
  876. case IG_GET_DEBUGGER_DATA:
  877. if (!IS_KERNEL_TARGET() ||
  878. ((PDBGKD_DEBUG_DATA_HEADER32)lpvData)->OwnerTag != KDBG_TAG)
  879. {
  880. return FALSE;
  881. }
  882. // Don't refresh if asking for the kernel header.
  883. pdbg32 = (PKDDEBUGGER_DATA32)lpvData;
  884. pdbg32->Header.List.Flink = (ULONG)KdDebuggerData.Header.List.Flink;
  885. pdbg32->Header.List.Blink = (ULONG)KdDebuggerData.Header.List.Blink;
  886. pdbg32->Header.OwnerTag = KDBG_TAG;
  887. pdbg32->Header.Size = sizeof(KDDEBUGGER_DATA32);
  888. #undef UIP
  889. #undef CP
  890. #define UIP(f) pdbg32->f = (ULONG)(KdDebuggerData.f)
  891. #define CP(f) pdbg32->f = (KdDebuggerData.f)
  892. UIP(KernBase);
  893. UIP(BreakpointWithStatus);
  894. UIP(SavedContext);
  895. CP(ThCallbackStack);
  896. CP(NextCallback);
  897. CP(FramePointer);
  898. CP(PaeEnabled);
  899. UIP(KiCallUserMode);
  900. UIP(KeUserCallbackDispatcher);
  901. UIP(PsLoadedModuleList);
  902. UIP(PsActiveProcessHead);
  903. UIP(PspCidTable);
  904. UIP(ExpSystemResourcesList);
  905. UIP(ExpPagedPoolDescriptor);
  906. UIP(ExpNumberOfPagedPools);
  907. UIP(KeTimeIncrement);
  908. UIP(KeBugCheckCallbackListHead);
  909. UIP(KiBugcheckData);
  910. UIP(IopErrorLogListHead);
  911. UIP(ObpRootDirectoryObject);
  912. UIP(ObpTypeObjectType);
  913. UIP(MmSystemCacheStart);
  914. UIP(MmSystemCacheEnd);
  915. UIP(MmSystemCacheWs);
  916. UIP(MmPfnDatabase);
  917. UIP(MmSystemPtesStart);
  918. UIP(MmSystemPtesEnd);
  919. UIP(MmSubsectionBase);
  920. UIP(MmNumberOfPagingFiles);
  921. UIP(MmLowestPhysicalPage);
  922. UIP(MmHighestPhysicalPage);
  923. UIP(MmNumberOfPhysicalPages);
  924. UIP(MmMaximumNonPagedPoolInBytes);
  925. UIP(MmNonPagedSystemStart);
  926. UIP(MmNonPagedPoolStart);
  927. UIP(MmNonPagedPoolEnd);
  928. UIP(MmPagedPoolStart);
  929. UIP(MmPagedPoolEnd);
  930. UIP(MmPagedPoolInformation);
  931. UIP(MmPageSize);
  932. UIP(MmSizeOfPagedPoolInBytes);
  933. UIP(MmTotalCommitLimit);
  934. UIP(MmTotalCommittedPages);
  935. UIP(MmSharedCommit);
  936. UIP(MmDriverCommit);
  937. UIP(MmProcessCommit);
  938. UIP(MmPagedPoolCommit);
  939. UIP(MmExtendedCommit);
  940. UIP(MmZeroedPageListHead);
  941. UIP(MmFreePageListHead);
  942. UIP(MmStandbyPageListHead);
  943. UIP(MmModifiedPageListHead);
  944. UIP(MmModifiedNoWritePageListHead);
  945. UIP(MmAvailablePages);
  946. UIP(MmResidentAvailablePages);
  947. UIP(PoolTrackTable);
  948. UIP(NonPagedPoolDescriptor);
  949. UIP(MmHighestUserAddress);
  950. UIP(MmSystemRangeStart);
  951. UIP(MmUserProbeAddress);
  952. UIP(KdPrintCircularBuffer);
  953. UIP(KdPrintCircularBufferEnd);
  954. UIP(KdPrintWritePointer);
  955. UIP(KdPrintRolloverCount);
  956. UIP(MmLoadedUserImageList);
  957. //
  958. // DO NOT ADD ANY FIELDS HERE
  959. // The 32 bit structure should not be changed
  960. //
  961. return TRUE;
  962. case IG_KD_CONTEXT:
  963. case IG_READ_PHYSICAL:
  964. case IG_WRITE_PHYSICAL:
  965. case IG_LOWMEM_CHECK:
  966. case IG_SEARCH_MEMORY:
  967. case IG_READ_MSR:
  968. case IG_WRITE_MSR:
  969. case IG_GET_BUS_DATA:
  970. case IG_SET_BUS_DATA:
  971. case IG_GET_CURRENT_THREAD:
  972. case IG_GET_CURRENT_PROCESS:
  973. case IG_RELOAD_SYMBOLS:
  974. case IG_GET_SET_SYMPATH:
  975. case IG_IS_PTR64:
  976. case IG_DUMP_SYMBOL_INFO:
  977. case IG_GET_TYPE_SIZE:
  978. case IG_GET_TEB_ADDRESS:
  979. case IG_GET_PEB_ADDRESS:
  980. case IG_GET_INPUT_LINE:
  981. case IG_GET_EXPRESSION_EX:
  982. case IG_TRANSLATE_VIRTUAL_TO_PHYSICAL:
  983. // All of these ioctls are handled identically for
  984. // 32 and 64 bits. Avoid duplicating all the code.
  985. return ExtIoctl(IoctlType, lpvData, cbSize);
  986. default:
  987. ErrOut( "\n*** Bad IOCTL32 request from an extension [%d]\n\n",
  988. IoctlType );
  989. return FALSE;
  990. }
  991. // NOTREACHED.
  992. DBG_ASSERT(FALSE);
  993. return FALSE;
  994. }
  995. LONG
  996. ExtensionExceptionFilter(
  997. struct _EXCEPTION_POINTERS *ExceptionInfo,
  998. PCSTR Module,
  999. PCSTR Func
  1000. )
  1001. {
  1002. // Any references to objects will be leaked.
  1003. // There's not much the engine can do about this, although
  1004. // it would be possible to record old refcounts and
  1005. // try to restore them.
  1006. if (Module != NULL && Func != NULL)
  1007. {
  1008. ErrOut("%08x Exception in %s.%s debugger extension.\n",
  1009. ExceptionInfo->ExceptionRecord->ExceptionCode,
  1010. Module,
  1011. Func
  1012. );
  1013. }
  1014. else
  1015. {
  1016. ErrOut("%08x Exception in debugger client %s callback.\n",
  1017. ExceptionInfo->ExceptionRecord->ExceptionCode,
  1018. Func
  1019. );
  1020. }
  1021. ErrOut(" PC: %s VA: %s R/W: %x Parameter: %s\n",
  1022. FormatAddr64((ULONG_PTR)ExceptionInfo->ExceptionRecord->ExceptionAddress),
  1023. FormatAddr64(ExceptionInfo->ExceptionRecord->ExceptionInformation[1]),
  1024. ExceptionInfo->ExceptionRecord->ExceptionInformation[0],
  1025. FormatAddr64(ExceptionInfo->ExceptionRecord->ExceptionInformation[2])
  1026. );
  1027. return EXCEPTION_EXECUTE_HANDLER;
  1028. }
  1029. BOOL
  1030. CallExtension(
  1031. DebugClient* Client,
  1032. EXTDLL *Ext,
  1033. PSTR Func,
  1034. PCSTR Args,
  1035. HRESULT* ExtStatus
  1036. )
  1037. {
  1038. FARPROC Routine;
  1039. ADDR TempAddr;
  1040. if (IS_KERNEL_TARGET())
  1041. {
  1042. _strlwr(Func);
  1043. }
  1044. Routine = GetProcAddress(Ext->Dll, Func);
  1045. if (Routine == NULL)
  1046. {
  1047. return FALSE;
  1048. }
  1049. if (!(g_EnvDbgOptions & OPTION_NOVERSIONCHECK) && Ext->CheckVersionRoutine)
  1050. {
  1051. Ext->CheckVersionRoutine();
  1052. }
  1053. if (IS_KERNEL_TARGET() && !strcmp(Func, "version"))
  1054. {
  1055. //
  1056. // This is a bit of a hack to avoid a problem with the
  1057. // extension version checking. Extension version checking
  1058. // comes before the KD connection is established so there's
  1059. // no register context. If the version checking fails it
  1060. // prints out version information, which tries to call
  1061. // version extensions, which will get here when there's
  1062. // no register context.
  1063. //
  1064. // To work around this, just pass zero to the version extension
  1065. // function since it presumably doesn't care about the
  1066. // address.
  1067. //
  1068. ADDRFLAT(&TempAddr, 0);
  1069. }
  1070. else if (IS_CONTEXT_POSSIBLE())
  1071. {
  1072. g_Machine->GetPC(&TempAddr);
  1073. }
  1074. else
  1075. {
  1076. if (!IS_LOCAL_KERNEL_TARGET())
  1077. {
  1078. WarnOut("Extension called without current PC\n");
  1079. }
  1080. ADDRFLAT(&TempAddr, 0);
  1081. }
  1082. *ExtStatus = S_OK;
  1083. __try
  1084. {
  1085. switch(Ext->ExtensionType)
  1086. {
  1087. case NTSD_EXTENSION_TYPE:
  1088. //
  1089. // NOTE:
  1090. // Eventhough this type should receive an NTSD_EXTENSION_API
  1091. // structure, ntsdexts.dll (and possibly others) depend on
  1092. // receiving the WinDBG version of the extensions, because they
  1093. // check the size of the structure, and actually use some of the
  1094. // newer exports. This works because the WinDBG extension API was
  1095. // a superset of the NTSD version.
  1096. //
  1097. ((PNTSD_EXTENSION_ROUTINE)Routine)
  1098. (g_CurrentProcess->Handle,
  1099. OS_HANDLE(g_CurrentProcess->CurrentThread->Handle),
  1100. (ULONG)Flat(TempAddr),
  1101. g_TargetMachine->m_Ptr64 ?
  1102. (PNTSD_EXTENSION_APIS)&g_WindbgExtensions64 :
  1103. (PNTSD_EXTENSION_APIS)&g_WindbgExtensions32,
  1104. (PSTR)Args
  1105. );
  1106. break;
  1107. case DEBUG_EXTENSION_TYPE:
  1108. if (Client == NULL)
  1109. {
  1110. ErrOut("Unable to call client-style extension "
  1111. "without a client\n");
  1112. }
  1113. else
  1114. {
  1115. *ExtStatus = ((PDEBUG_EXTENSION_CALL)Routine)
  1116. ((PDEBUG_CLIENT)(IDebugClientN *)Client, Args);
  1117. }
  1118. break;
  1119. case WINDBG_EXTENSION_TYPE:
  1120. //
  1121. // Support Windbg type extensions for ntsd too
  1122. //
  1123. if (Ext->ApiVersion.Revision < 6 )
  1124. {
  1125. ((PWINDBG_EXTENSION_ROUTINE32)Routine) (
  1126. g_CurrentProcess->Handle,
  1127. OS_HANDLE(g_CurrentProcess->CurrentThread->Handle),
  1128. (ULONG)Flat(TempAddr),
  1129. CURRENT_PROC,
  1130. Args
  1131. );
  1132. }
  1133. else
  1134. {
  1135. ((PWINDBG_EXTENSION_ROUTINE64)Routine) (
  1136. g_CurrentProcess->Handle,
  1137. OS_HANDLE(g_CurrentProcess->CurrentThread->Handle),
  1138. Flat(TempAddr),
  1139. CURRENT_PROC,
  1140. Args
  1141. );
  1142. }
  1143. break;
  1144. case WINDBG_OLDKD_EXTENSION_TYPE:
  1145. ((PWINDBG_OLDKD_EXTENSION_ROUTINE)Routine) (
  1146. (ULONG)Flat(TempAddr),
  1147. &g_KdExtensions,
  1148. Args
  1149. );
  1150. break;
  1151. }
  1152. }
  1153. __except(ExtensionExceptionFilter(GetExceptionInformation(),
  1154. Ext->Name, Func))
  1155. {
  1156. ;
  1157. }
  1158. return TRUE;
  1159. }
  1160. void
  1161. LinkExtensionDll(
  1162. EXTDLL* Ext
  1163. )
  1164. {
  1165. // Put user-loaded DLLs before default DLLs.
  1166. if (Ext->UserLoaded)
  1167. {
  1168. Ext->Next = g_ExtDlls;
  1169. g_ExtDlls = Ext;
  1170. }
  1171. else
  1172. {
  1173. EXTDLL* Prev;
  1174. EXTDLL* Cur;
  1175. Prev = NULL;
  1176. for (Cur = g_ExtDlls; Cur != NULL; Cur = Cur->Next)
  1177. {
  1178. if (!Cur->UserLoaded)
  1179. {
  1180. break;
  1181. }
  1182. Prev = Cur;
  1183. }
  1184. Ext->Next = Cur;
  1185. if (Prev == NULL)
  1186. {
  1187. g_ExtDlls = Ext;
  1188. }
  1189. else
  1190. {
  1191. Prev->Next = Ext;
  1192. }
  1193. }
  1194. }
  1195. EXTDLL *
  1196. AddExtensionDll(
  1197. char *Name,
  1198. BOOL UserLoaded,
  1199. char **End
  1200. )
  1201. {
  1202. EXTDLL *Ext;
  1203. ULONG Len;
  1204. char *Last;
  1205. while (*Name == ' ' || *Name == '\t')
  1206. {
  1207. Name++;
  1208. }
  1209. if (*Name == 0)
  1210. {
  1211. ErrOut("No extension DLL name provided\n");
  1212. return NULL;
  1213. }
  1214. Last = Name;
  1215. while (*Last != 0 && *Last != ' ' && *Last != '\t')
  1216. {
  1217. Last++;
  1218. }
  1219. if (End != NULL)
  1220. {
  1221. *End = Last;
  1222. }
  1223. Len = (ULONG)(Last - Name);
  1224. // See if it's already in the list.
  1225. for (Ext = g_ExtDlls; Ext != NULL; Ext = Ext->Next)
  1226. {
  1227. if (strlen(Ext->Name) == Len && !_memicmp(Name, Ext->Name, Len))
  1228. {
  1229. return Ext;
  1230. }
  1231. }
  1232. Ext = (EXTDLL *)malloc(sizeof(EXTDLL) + Len);
  1233. if (Ext == NULL)
  1234. {
  1235. ErrOut("Unable to allocate memory for extension DLL\n");
  1236. return NULL;
  1237. }
  1238. ZeroMemory(Ext, sizeof(EXTDLL) + Len);
  1239. memcpy(Ext->Name, Name, Len + 1);
  1240. Ext->UserLoaded = UserLoaded;
  1241. LinkExtensionDll(Ext);
  1242. NotifyChangeEngineState(DEBUG_CES_EXTENSIONS, 0, TRUE);
  1243. return Ext;
  1244. }
  1245. PCTSTR
  1246. BuildExtensionSearchPath(
  1247. VOID
  1248. )
  1249. {
  1250. DWORD dwSize;
  1251. DWORD dwTotalSize;
  1252. CHAR ExeDir[MAX_PATH];
  1253. int ExeRootLen;
  1254. PSTR OsDirPath;
  1255. CHAR OsDirTail[32];
  1256. BOOL PriPaths = FALSE;
  1257. //
  1258. // If we are not connected, don't build a path, since we have to pick
  1259. // up extensions based on the OS version.
  1260. //
  1261. if (g_ActualSystemVersion == SVER_INVALID)
  1262. {
  1263. return NULL;
  1264. }
  1265. //
  1266. // If we already have a search path, do not rebuild it.
  1267. //
  1268. if (g_ExtensionSearchPath)
  1269. {
  1270. return g_ExtensionSearchPath;
  1271. }
  1272. // Get the directory the debugger executable is in.
  1273. // -8 because we assume we're adding \w2kfre to the path.
  1274. if (!GetModuleFileName(NULL, ExeDir, MAX_PATH - 8))
  1275. {
  1276. // Error. Use the current directory.
  1277. strcpy(ExeDir, ".");
  1278. ExeRootLen = 1;
  1279. }
  1280. else
  1281. {
  1282. // Remove the executable name.
  1283. LPSTR pszTmp = strrchr(ExeDir, '\\');
  1284. if (pszTmp)
  1285. {
  1286. *pszTmp = 0;
  1287. }
  1288. if (ExeDir[0] == '\\' && ExeDir[1] == '\\')
  1289. {
  1290. PSTR ExeRootEnd;
  1291. // UNC path root.
  1292. ExeRootEnd = strchr(ExeDir + 2, '\\');
  1293. if (ExeRootEnd != NULL)
  1294. {
  1295. ExeRootEnd = strchr(ExeRootEnd + 1, '\\');
  1296. }
  1297. if (ExeRootEnd == NULL)
  1298. {
  1299. ExeRootLen = strlen(ExeDir);
  1300. }
  1301. else
  1302. {
  1303. ExeRootLen = (int)(ExeRootEnd - ExeDir);
  1304. }
  1305. }
  1306. else
  1307. {
  1308. // Drive letter and colon root.
  1309. ExeRootLen = 2;
  1310. }
  1311. }
  1312. //
  1313. // Calc how much space we will need to use.
  1314. //
  1315. // Leave extra room for the current directory, path, and directory of
  1316. // where debugger extensions are located.
  1317. //
  1318. dwTotalSize = GetEnvironmentVariable("PATH", NULL, 0) +
  1319. GetEnvironmentVariable("_NT_DEBUGGER_EXTENSION_PATH",
  1320. NULL, 0) +
  1321. MAX_PATH * 3;
  1322. g_ExtensionSearchPath = (LPTSTR)calloc(dwTotalSize, sizeof(TCHAR));
  1323. if (!g_ExtensionSearchPath)
  1324. {
  1325. return NULL;
  1326. }
  1327. *g_ExtensionSearchPath = 0;
  1328. //
  1329. // 1 - User specified search path
  1330. //
  1331. if (GetEnvironmentVariable("_NT_DEBUGGER_EXTENSION_PATH",
  1332. g_ExtensionSearchPath,
  1333. dwTotalSize - 2))
  1334. {
  1335. strcat(g_ExtensionSearchPath, ";");
  1336. }
  1337. //
  1338. // Figure out whether we need NT6, or NT5/NT4 free or checked extensions
  1339. //
  1340. if (g_ActualSystemVersion > BIG_SVER_START &&
  1341. g_ActualSystemVersion < BIG_SVER_END)
  1342. {
  1343. OsDirPath = "DbgExt";
  1344. strcpy(OsDirTail, "BIG");
  1345. }
  1346. else if (g_ActualSystemVersion > XBOX_SVER_START &&
  1347. g_ActualSystemVersion < XBOX_SVER_END)
  1348. {
  1349. OsDirPath = "DbgExt";
  1350. strcpy(OsDirTail, "XBox");
  1351. }
  1352. else if (g_ActualSystemVersion > NTBD_SVER_START &&
  1353. g_ActualSystemVersion < NTBD_SVER_END)
  1354. {
  1355. OsDirPath = "DbgExt";
  1356. strcpy(OsDirTail, "NtBd");
  1357. }
  1358. else if (g_ActualSystemVersion > EFI_SVER_START &&
  1359. g_ActualSystemVersion < EFI_SVER_END)
  1360. {
  1361. OsDirPath = "DbgExt";
  1362. strcpy(OsDirTail, "EFI");
  1363. }
  1364. else
  1365. {
  1366. // Treat everything else as an NT system. Use
  1367. // the translated system version now rather than
  1368. // the actual system version.
  1369. PriPaths = TRUE;
  1370. // Skip root as it is already taken from ExeDir.
  1371. OsDirPath = ExeDir + ExeRootLen;
  1372. if (*OsDirPath == '\\')
  1373. {
  1374. OsDirPath++;
  1375. }
  1376. if (g_SystemVersion > NT_SVER_W2K)
  1377. {
  1378. strcpy(OsDirTail, "WINXP");
  1379. }
  1380. else
  1381. {
  1382. if (g_SystemVersion <= NT_SVER_NT4)
  1383. {
  1384. strcpy(OsDirTail, "NT4");
  1385. }
  1386. else
  1387. {
  1388. strcpy(OsDirTail, "W2K");
  1389. }
  1390. if (0xC == g_TargetCheckedBuild)
  1391. {
  1392. strcat(OsDirTail, "Chk");
  1393. }
  1394. else
  1395. {
  1396. strcat(OsDirTail, "Fre");
  1397. }
  1398. }
  1399. }
  1400. //
  1401. // 2 - OS specific subdirectories from where we launched the debugger.
  1402. // 3 - pri subdirectory from where we launched the debugger.
  1403. // 4 - Directory from where we launched the debugger.
  1404. //
  1405. PSTR End;
  1406. dwSize = strlen(g_ExtensionSearchPath);
  1407. End = g_ExtensionSearchPath + dwSize;
  1408. memcpy(End, ExeDir, ExeRootLen);
  1409. End += ExeRootLen;
  1410. if (*OsDirPath)
  1411. {
  1412. *End++ = '\\';
  1413. strcpy(End, OsDirPath);
  1414. End += strlen(End);
  1415. }
  1416. if (PriPaths)
  1417. {
  1418. sprintf(End, "\\winext;%s\\pri;%s", ExeDir, ExeDir);
  1419. End += strlen(End);
  1420. }
  1421. sprintf(End, "\\%s;%s", OsDirTail, ExeDir);
  1422. End += strlen(End) - 1;
  1423. if (*End == ':')
  1424. {
  1425. *++End = '\\';
  1426. }
  1427. *++End = ';';
  1428. *++End = 0;
  1429. //
  1430. // 4 - Copy environment path
  1431. //
  1432. dwSize = strlen(g_ExtensionSearchPath);
  1433. GetEnvironmentVariable("PATH",
  1434. g_ExtensionSearchPath + dwSize,
  1435. dwTotalSize - dwSize - sizeof(TCHAR));
  1436. return g_ExtensionSearchPath;
  1437. }
  1438. BOOL
  1439. IsAbsolutePath(
  1440. PCTSTR Path
  1441. )
  1442. /*++
  1443. Routine Description:
  1444. Is this path an absolute path? Does not guarentee that the path exists. The
  1445. method is:
  1446. "\\<anything>" is an absolute path
  1447. "{char}:\<anything>" is an absolute path
  1448. anything else is not
  1449. --*/
  1450. {
  1451. BOOL ret;
  1452. if ( (Path [0] == '\\' && Path [1] == '\\') ||
  1453. (isalpha ( Path [0] ) && Path [1] == ':' && Path [ 2 ] == '\\') )
  1454. {
  1455. ret = TRUE;
  1456. }
  1457. else
  1458. {
  1459. ret = FALSE;
  1460. }
  1461. return ret;
  1462. }
  1463. BOOL
  1464. LoadExtensionDll(
  1465. EXTDLL *Ext
  1466. )
  1467. {
  1468. BOOL Found;
  1469. TCHAR szExtPath[_MAX_PATH];
  1470. if (Ext->Dll != NULL)
  1471. {
  1472. // Extension is already loaded.
  1473. return TRUE;
  1474. }
  1475. //
  1476. // If we are not allowing network paths, verify that the extension will
  1477. // not be loaded from a network path.
  1478. //
  1479. if (g_EngOptions & DEBUG_ENGOPT_DISALLOW_NETWORK_PATHS)
  1480. {
  1481. DWORD NetCheck;
  1482. NetCheck = NetworkPathCheck (BuildExtensionSearchPath ());
  1483. //
  1484. // Check full path of the extension.
  1485. //
  1486. if (NetCheck != ERROR_FILE_OFFLINE)
  1487. {
  1488. CHAR Drive [ _MAX_DRIVE + 1];
  1489. CHAR Dir [ _MAX_DIR + 1];
  1490. CHAR Path [ _MAX_PATH + 1];
  1491. *Drive = '\000';
  1492. *Dir = '\000';
  1493. _splitpath (Ext->Name, Drive, Dir, NULL, NULL);
  1494. _makepath (Path, Drive, Dir, NULL, NULL);
  1495. NetCheck = NetworkPathCheck (Path);
  1496. }
  1497. if (NetCheck == ERROR_FILE_OFFLINE)
  1498. {
  1499. ErrOut("ERROR: extension search path contains "
  1500. "network references.\n");
  1501. return FALSE;
  1502. }
  1503. }
  1504. Found = SearchPath(BuildExtensionSearchPath(),
  1505. Ext->Name,
  1506. ".dll",
  1507. sizeof(szExtPath),
  1508. szExtPath,
  1509. NULL);
  1510. UINT OldMode = SetErrorMode(SEM_FAILCRITICALERRORS);
  1511. if ( Found )
  1512. {
  1513. Ext->Dll = LoadLibrary ( szExtPath );
  1514. }
  1515. else if (IsAbsolutePath ( Ext->Name ))
  1516. {
  1517. Ext->Dll = LoadLibrary ( Ext->Name );
  1518. }
  1519. SetErrorMode(OldMode);
  1520. if (Ext->Dll == NULL)
  1521. {
  1522. ErrOut("The call to LoadLibrary(%s) failed with error %d.\n"
  1523. "Please check your debugger configuration "
  1524. "and/or network access\n",
  1525. Ext->Name, GetLastError());
  1526. return FALSE;
  1527. }
  1528. if (!_stricmp(Ext->Name, "wow64exts.dll") ||
  1529. !_stricmp(Ext->Name, "wow64exts"))
  1530. {
  1531. g_Wow64exts = (WOW64EXTSPROC)GetProcAddress(Ext->Dll,"Wow64extsfn");
  1532. DBG_ASSERT(g_Wow64exts);
  1533. }
  1534. if (!_stricmp(Ext->Name, "wmikd.dll") ||
  1535. !_stricmp(Ext->Name, "wmikd"))
  1536. {
  1537. g_WmiFormatTraceData = (WMI_FORMAT_TRACE_DATA)
  1538. GetProcAddress(Ext->Dll, "WmiFormatTraceData");
  1539. }
  1540. if (!g_QuietMode)
  1541. {
  1542. dprintf("Loaded %s extension DLL\n", Ext->Name);
  1543. }
  1544. //
  1545. // Now that the extension is loaded, refresh it.
  1546. //
  1547. Ext->Uninit = NULL;
  1548. PDEBUG_EXTENSION_INITIALIZE EngExt;
  1549. EngExt = (PDEBUG_EXTENSION_INITIALIZE)
  1550. GetProcAddress(Ext->Dll, "DebugExtensionInitialize");
  1551. if (EngExt != NULL)
  1552. {
  1553. ULONG Version, Flags;
  1554. HRESULT Status;
  1555. // This is an engine extension. Initialize it.
  1556. Status = EngExt(&Version, &Flags);
  1557. if (Status != S_OK)
  1558. {
  1559. ErrOut("%s!DebugExtensionInitialize failed with 0x%08lX\n",
  1560. Ext->Name, Status);
  1561. FreeLibrary(Ext->Dll);
  1562. Ext->Dll = NULL;
  1563. return FALSE;
  1564. }
  1565. Ext->ApiVersion.MajorVersion = HIWORD(Version);
  1566. Ext->ApiVersion.MinorVersion = LOWORD(Version);
  1567. Ext->ApiVersion.Revision = 0;
  1568. Ext->Notify = (PDEBUG_EXTENSION_NOTIFY)
  1569. GetProcAddress(Ext->Dll, "DebugExtensionNotify");
  1570. Ext->Uninit = (PDEBUG_EXTENSION_UNINITIALIZE)
  1571. GetProcAddress(Ext->Dll, "DebugExtensionUninitialize");
  1572. Ext->ExtensionType = DEBUG_EXTENSION_TYPE;
  1573. Ext->Init = NULL;
  1574. Ext->ApiVersionRoutine = NULL;
  1575. Ext->CheckVersionRoutine = NULL;
  1576. goto VersionCheck;
  1577. }
  1578. Ext->Init = (PWINDBG_EXTENSION_DLL_INIT64)
  1579. GetProcAddress(Ext->Dll, "WinDbgExtensionDllInit");
  1580. // Windbg Api
  1581. if (Ext->Init != NULL)
  1582. {
  1583. Ext->ExtensionType = WINDBG_EXTENSION_TYPE;
  1584. Ext->ApiVersionRoutine = (PWINDBG_EXTENSION_API_VERSION)
  1585. GetProcAddress(Ext->Dll, "ExtensionApiVersion");
  1586. if (Ext->ApiVersionRoutine == NULL)
  1587. {
  1588. FreeLibrary(Ext->Dll);
  1589. Ext->Dll = NULL;
  1590. ErrOut("%s is not a valid windbg extension DLL\n",
  1591. Ext->Name);
  1592. return FALSE;
  1593. }
  1594. Ext->CheckVersionRoutine = (PWINDBG_CHECK_VERSION)
  1595. GetProcAddress(Ext->Dll, "CheckVersion");
  1596. Ext->ApiVersion = *(Ext->ApiVersionRoutine());
  1597. if (Ext->ApiVersion.Revision >= 6)
  1598. {
  1599. (Ext->Init)(&g_WindbgExtensions64,
  1600. (USHORT)g_TargetCheckedBuild,
  1601. (USHORT)g_TargetBuildNumber);
  1602. }
  1603. else
  1604. {
  1605. (Ext->Init)((PWINDBG_EXTENSION_APIS64)&g_WindbgExtensions32,
  1606. (USHORT)g_TargetCheckedBuild,
  1607. (USHORT)g_TargetBuildNumber);
  1608. }
  1609. }
  1610. else
  1611. {
  1612. Ext->ApiVersion.Revision = EXT_API_VERSION_NUMBER;
  1613. Ext->ApiVersionRoutine = NULL;
  1614. Ext->CheckVersionRoutine = NULL;
  1615. if (GetProcAddress(Ext->Dll, "NtsdExtensionDllInit"))
  1616. {
  1617. Ext->ExtensionType = NTSD_EXTENSION_TYPE;
  1618. }
  1619. else
  1620. {
  1621. Ext->ExtensionType = IS_KERNEL_TARGET() ?
  1622. WINDBG_OLDKD_EXTENSION_TYPE : NTSD_EXTENSION_TYPE;
  1623. }
  1624. }
  1625. VersionCheck:
  1626. #if 0
  1627. // Temporarily remove this print statements.
  1628. if (!(g_EnvDbgOptions & OPTION_NOVERSIONCHECK))
  1629. {
  1630. if (Ext->ApiVersion.Revision < 6)
  1631. {
  1632. dprintf("%s uses the old 32 bit extension API and may not be fully\n", Ext->Name);
  1633. dprintf("compatible with current systems.\n");
  1634. }
  1635. else if (Ext->ApiVersion.Revision < EXT_API_VERSION_NUMBER)
  1636. {
  1637. dprintf("%s uses an earlier version of the extension API than that\n", Ext->Name);
  1638. dprintf("supported by this debugger, and should work properly, but there\n");
  1639. dprintf("may be unexpected incompatibilities.\n");
  1640. }
  1641. else if (Ext->ApiVersion.Revision > EXT_API_VERSION_NUMBER)
  1642. {
  1643. dprintf("%s uses a later version of the extension API than that\n", Ext->Name);
  1644. dprintf("supported by this debugger, and might not function correctly.\n");
  1645. dprintf("You should use the debugger from the SDK or DDK which was used\n");
  1646. dprintf("to build the extension library.\n");
  1647. }
  1648. }
  1649. #endif
  1650. // If the extension has a notification routine send
  1651. // notifications appropriate to the current state.
  1652. if (Ext->Notify != NULL)
  1653. {
  1654. if (IS_MACHINE_SET())
  1655. {
  1656. Ext->Notify(DEBUG_NOTIFY_SESSION_ACTIVE, 0);
  1657. }
  1658. if (IS_MACHINE_ACCESSIBLE())
  1659. {
  1660. Ext->Notify(DEBUG_NOTIFY_SESSION_ACCESSIBLE, 0);
  1661. }
  1662. }
  1663. return TRUE;
  1664. }
  1665. void
  1666. UnlinkExtensionDll(
  1667. EXTDLL* Match
  1668. )
  1669. {
  1670. EXTDLL *Ext;
  1671. EXTDLL *Prev;
  1672. Prev = NULL;
  1673. for (Ext = g_ExtDlls; Ext != NULL; Ext = Ext->Next)
  1674. {
  1675. if (Match == Ext)
  1676. {
  1677. break;
  1678. }
  1679. Prev = Ext;
  1680. }
  1681. if (Ext == NULL) {
  1682. ErrOut("! Extension DLL list inconsistency !\n");
  1683. } else if (Prev == NULL) {
  1684. g_ExtDlls = Ext->Next;
  1685. } else {
  1686. Prev->Next = Ext->Next;
  1687. }
  1688. }
  1689. void
  1690. DeferExtensionDll(
  1691. EXTDLL *Ext
  1692. )
  1693. {
  1694. if (Ext->Dll == NULL)
  1695. {
  1696. // Already deferred.
  1697. return;
  1698. }
  1699. Ext->Init = NULL;
  1700. Ext->Notify = NULL;
  1701. Ext->ApiVersionRoutine = NULL;
  1702. Ext->CheckVersionRoutine = NULL;
  1703. if (Ext->Uninit != NULL)
  1704. {
  1705. Ext->Uninit();
  1706. Ext->Uninit = NULL;
  1707. }
  1708. if (Ext->Dll != NULL)
  1709. {
  1710. if (!g_QuietMode)
  1711. {
  1712. dprintf("Unloading %s extension DLL\n", Ext->Name);
  1713. }
  1714. FreeLibrary(Ext->Dll);
  1715. Ext->Dll = NULL;
  1716. }
  1717. }
  1718. void
  1719. UnloadExtensionDll(
  1720. EXTDLL *Ext
  1721. )
  1722. {
  1723. UnlinkExtensionDll(Ext);
  1724. DeferExtensionDll(Ext);
  1725. free(Ext);
  1726. NotifyChangeEngineState(DEBUG_CES_EXTENSIONS, 0, TRUE);
  1727. }
  1728. void
  1729. MoveExtensionToHead(EXTDLL* Ext)
  1730. {
  1731. UnlinkExtensionDll(Ext);
  1732. LinkExtensionDll(Ext);
  1733. }
  1734. BOOL
  1735. CallAnyExtension(DebugClient* Client,
  1736. EXTDLL* Ext, PSTR Function, PCSTR Arguments,
  1737. BOOL ModuleSpecified, BOOL ShowWarnings,
  1738. HRESULT* ExtStatus)
  1739. {
  1740. if (Ext == NULL)
  1741. {
  1742. Ext = g_ExtDlls;
  1743. }
  1744. // Walk through the list of extension DLLs and attempt to
  1745. // call the given extension function on them.
  1746. while (Ext != NULL)
  1747. {
  1748. //
  1749. // hack : only dbghelp extensions or analyzebugcheck
  1750. // will work on minidump files right now.
  1751. //
  1752. char Name[_MAX_FNAME + 1];
  1753. _splitpath(Ext->Name,NULL,NULL,Name,NULL);
  1754. if (!IS_KERNEL_TRIAGE_DUMP() ||
  1755. !strcmp(Name, "dbghelp") ||
  1756. !_stricmp(Name, "dbgtstext") ||
  1757. !_stricmp(Function, "triage") ||
  1758. !_stricmp(Function, "analyzebugcheck"))
  1759. {
  1760. if (LoadExtensionDll(Ext))
  1761. {
  1762. BOOL DidCall;
  1763. DidCall = CallExtension(Client, Ext, Function, Arguments,
  1764. ExtStatus);
  1765. if (DidCall &&
  1766. *ExtStatus != DEBUG_EXTENSION_CONTINUE_SEARCH)
  1767. {
  1768. return TRUE;
  1769. }
  1770. if (!DidCall && ModuleSpecified)
  1771. {
  1772. // If a DLL was explicitly specified then the
  1773. // missing function is an error.
  1774. if (ShowWarnings &&
  1775. !(g_EnvDbgOptions & OPTION_NOEXTWARNING))
  1776. {
  1777. MaskOut(DEBUG_OUTPUT_EXTENSION_WARNING,
  1778. "%s has no %s export\n", Ext->Name, Function);
  1779. }
  1780. return FALSE;
  1781. }
  1782. }
  1783. }
  1784. Ext = Ext->Next;
  1785. }
  1786. if (ShowWarnings && IS_KERNEL_TRIAGE_DUMP())
  1787. {
  1788. ErrOut("Standard debugger extensions do not work with kernel minidump\n"
  1789. "files because no data is present in the dump file.\n"
  1790. "Consult the debugger documentation for more information on\n"
  1791. "kernel minidump files\n");
  1792. }
  1793. else if (ShowWarnings && !(g_EnvDbgOptions & OPTION_NOEXTWARNING))
  1794. {
  1795. MaskOut(DEBUG_OUTPUT_EXTENSION_WARNING,
  1796. "No export %s found\n", Function);
  1797. }
  1798. return FALSE;
  1799. }
  1800. void
  1801. OutputModuleIdInfo(HMODULE Mod, PSTR ModFile, LPEXT_API_VERSION ApiVer)
  1802. {
  1803. char FileBuf[MAX_IMAGE_PATH];
  1804. char *File;
  1805. time_t TimeStamp;
  1806. char *TimeStr;
  1807. char VerStr[64];
  1808. if (Mod == NULL)
  1809. {
  1810. Mod = GetModuleHandle(ModFile);
  1811. }
  1812. if (GetFileStringFileInfo(ModFile, "ProductVersion",
  1813. VerStr, sizeof(VerStr)))
  1814. {
  1815. dprintf("image %s, ", VerStr);
  1816. }
  1817. if (ApiVer != NULL)
  1818. {
  1819. dprintf("API %d.%d.%d, ",
  1820. ApiVer->MajorVersion,
  1821. ApiVer->MinorVersion,
  1822. ApiVer->Revision);
  1823. }
  1824. TimeStamp = GetTimestampForLoadedLibrary(Mod);
  1825. TimeStr = ctime(&TimeStamp);
  1826. // Delete newline.
  1827. TimeStr[strlen(TimeStr) - 1] = 0;
  1828. if (GetModuleFileName(Mod, FileBuf, sizeof(FileBuf) - 1) == 0)
  1829. {
  1830. File = "Unable to get filename";
  1831. }
  1832. else
  1833. {
  1834. File = FileBuf;
  1835. }
  1836. dprintf("built %s\n [path: %s]\n", TimeStr, File);
  1837. }
  1838. void
  1839. OutputExtensions(DebugClient* Client, BOOL Versions)
  1840. {
  1841. if (g_ExtensionSearchPath != NULL)
  1842. {
  1843. dprintf("Extension DLL search Path:\n %s\n",
  1844. g_ExtensionSearchPath);
  1845. }
  1846. else
  1847. {
  1848. dprintf("Default extension DLLs are not loaded until "
  1849. "after initial connection\n");
  1850. if (g_ExtDlls == NULL)
  1851. {
  1852. return;
  1853. }
  1854. }
  1855. dprintf("Extension DLL chain:\n");
  1856. if (g_ExtDlls == NULL)
  1857. {
  1858. dprintf(" <Empty>\n");
  1859. return;
  1860. }
  1861. EXTDLL *Ext;
  1862. for (Ext = g_ExtDlls; Ext != NULL; Ext = Ext->Next)
  1863. {
  1864. if (Versions & (Ext->Dll == NULL))
  1865. {
  1866. LoadExtensionDll(Ext);
  1867. }
  1868. dprintf(" %s: ", Ext->Name);
  1869. if (Ext->Dll != NULL)
  1870. {
  1871. LPEXT_API_VERSION ApiVer;
  1872. if ((Ext->ExtensionType == DEBUG_EXTENSION_TYPE) ||
  1873. (Ext->ApiVersionRoutine != NULL))
  1874. {
  1875. ApiVer = &Ext->ApiVersion;
  1876. }
  1877. else
  1878. {
  1879. ApiVer = NULL;
  1880. }
  1881. OutputModuleIdInfo(Ext->Dll, Ext->Name, ApiVer);
  1882. if (Versions)
  1883. {
  1884. HRESULT ExtStatus;
  1885. CallExtension(Client, Ext, "version", "", &ExtStatus);
  1886. }
  1887. }
  1888. else
  1889. {
  1890. dprintf("(Not loaded)\n");
  1891. }
  1892. }
  1893. }
  1894. void
  1895. LoadMachineExtensions(void)
  1896. {
  1897. // Only notify once for all the adds in this function;
  1898. g_EngNotify++;
  1899. //
  1900. // Now that we have determined the type of architecture,
  1901. // we can load the right debugger extensions
  1902. //
  1903. if (g_ActualSystemVersion > BIG_SVER_START &&
  1904. g_ActualSystemVersion < BIG_SVER_END)
  1905. {
  1906. goto Refresh;
  1907. }
  1908. if (g_ActualSystemVersion > XBOX_SVER_START &&
  1909. g_ActualSystemVersion < XBOX_SVER_END)
  1910. {
  1911. AddExtensionDll("kdextx86", FALSE, NULL);
  1912. goto Refresh;
  1913. }
  1914. if (g_ActualSystemVersion > NTBD_SVER_START &&
  1915. g_ActualSystemVersion < NTBD_SVER_END)
  1916. {
  1917. goto Refresh;
  1918. }
  1919. // Treat everything else as an NT system.
  1920. if (IS_KERNEL_TARGET())
  1921. {
  1922. if (g_TargetMachineType == IMAGE_FILE_MACHINE_IA64)
  1923. {
  1924. //
  1925. // We rely on force loading of extensions at the end of this
  1926. // routine in order to get the entry point the debugger needs.
  1927. //
  1928. AddExtensionDll("wow64exts", FALSE, NULL);
  1929. }
  1930. switch (g_TargetMachineType)
  1931. {
  1932. case IMAGE_FILE_MACHINE_ALPHA:
  1933. AddExtensionDll("kdextalp", FALSE, NULL);
  1934. break;
  1935. case IMAGE_FILE_MACHINE_I386:
  1936. if (g_SystemVersion > NT_SVER_START &&
  1937. g_SystemVersion <= NT_SVER_W2K)
  1938. {
  1939. AddExtensionDll("kdextx86", FALSE, NULL);
  1940. break;
  1941. }
  1942. // Fall through
  1943. default:
  1944. //
  1945. // For all new architectures and new X86 builds, load
  1946. // kdexts
  1947. //
  1948. AddExtensionDll("kdexts", FALSE, NULL);
  1949. break;
  1950. }
  1951. //
  1952. // Extensions that work on all versions of the OS for kernel mode
  1953. // Many of these are messages about legacy extensions.
  1954. AddExtensionDll("kext", FALSE, NULL);
  1955. }
  1956. else
  1957. {
  1958. // User mode only extensions
  1959. AddExtensionDll("ntsdexts", FALSE, NULL);
  1960. AddExtensionDll("uext", FALSE, NULL);
  1961. }
  1962. // Use the translated system version now rather than
  1963. // the actual system version.
  1964. if (g_SystemVersion > NT_SVER_W2K &&
  1965. g_SystemVersion < NT_SVER_END)
  1966. {
  1967. AddExtensionDll("exts", FALSE, NULL);
  1968. }
  1969. // Load ext.dll for all NT versions
  1970. AddExtensionDll("ext", FALSE, NULL);
  1971. Refresh:
  1972. // Always load the Dbghelp extensions last so they are first on the list
  1973. AddExtensionDll("dbghelp", FALSE, NULL);
  1974. EXTDLL *Ext;
  1975. for (Ext = g_ExtDlls; Ext != NULL; Ext = Ext->Next)
  1976. {
  1977. LoadExtensionDll(Ext);
  1978. }
  1979. g_EngNotify--;
  1980. NotifyChangeEngineState(DEBUG_CES_EXTENSIONS, 0, TRUE);
  1981. }
  1982. void
  1983. NotifyExtensions(ULONG Notify, ULONG64 Argument)
  1984. {
  1985. EXTDLL *Ext;
  1986. // This routine deliberately does not provoke
  1987. // a DLL load.
  1988. for (Ext = g_ExtDlls; Ext != NULL; Ext = Ext->Next)
  1989. {
  1990. if (Ext->Notify != NULL)
  1991. {
  1992. Ext->Notify(Notify, Argument);
  1993. }
  1994. }
  1995. }
  1996. struct SHELL_READER_INFO
  1997. {
  1998. HANDLE IoHandles[3];
  1999. HANDLE OutEvent;
  2000. };
  2001. DWORD WINAPI
  2002. ShellReaderThread(
  2003. LPVOID Param
  2004. )
  2005. {
  2006. SHELL_READER_INFO* ReaderInfo = (SHELL_READER_INFO*)Param;
  2007. OVERLAPPED Overlapped;
  2008. HANDLE WaitHandles[2];
  2009. DWORD Error;
  2010. UCHAR Buffer[_MAX_PATH];
  2011. DWORD BytesRead;
  2012. DWORD WaitStatus;
  2013. memset(&Overlapped, 0, sizeof(Overlapped));
  2014. Overlapped.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
  2015. if (Overlapped.hEvent == NULL)
  2016. {
  2017. return ERROR_NOT_ENOUGH_MEMORY;
  2018. }
  2019. WaitHandles[0] = Overlapped.hEvent;
  2020. WaitHandles[1] = ReaderInfo->IoHandles[2];
  2021. //
  2022. // wait for data on handle 1.
  2023. // wait for signal on handle 2.
  2024. //
  2025. while (1)
  2026. {
  2027. //
  2028. // initiate the read
  2029. //
  2030. ResetEvent( Overlapped.hEvent );
  2031. if (ReadFile(ReaderInfo->IoHandles[1], Buffer, sizeof(Buffer) - 1,
  2032. &BytesRead, &Overlapped))
  2033. {
  2034. //
  2035. // Read has successfully completed, print and repeat.
  2036. //
  2037. Buffer[BytesRead] = 0;
  2038. dprintf("%s", Buffer);
  2039. // Notify the main thread that output was produced.
  2040. SetEvent(ReaderInfo->OutEvent);
  2041. }
  2042. else
  2043. {
  2044. Error = GetLastError();
  2045. if (Error != ERROR_IO_PENDING)
  2046. {
  2047. dprintf(".shell: ReadFile failed, error == %d\n", Error);
  2048. break;
  2049. }
  2050. // Flush output before waiting.
  2051. FlushCallbacks();
  2052. WaitStatus = WaitForMultipleObjects(2, WaitHandles, FALSE,
  2053. INFINITE);
  2054. if (WaitStatus == WAIT_OBJECT_0)
  2055. {
  2056. if (GetOverlappedResult(ReaderInfo->IoHandles[1], &Overlapped,
  2057. &BytesRead, TRUE))
  2058. {
  2059. //
  2060. // Read has successfully completed
  2061. //
  2062. Buffer[BytesRead] = 0;
  2063. dprintf("%s", Buffer);
  2064. // Notify the main thread that output was produced.
  2065. SetEvent(ReaderInfo->OutEvent);
  2066. }
  2067. else
  2068. {
  2069. Error = GetLastError();
  2070. dprintf(".shell: GetOverlappedResult failed, "
  2071. "error == %d\n",
  2072. Error);
  2073. break;
  2074. }
  2075. }
  2076. else if (WaitStatus == WAIT_OBJECT_0 + 1)
  2077. {
  2078. //
  2079. // process exited.
  2080. //
  2081. dprintf(".shell: Process exited\n");
  2082. break;
  2083. }
  2084. else
  2085. {
  2086. dprintf(".shell: WaitForMultipleObjects failed; error == %d\n",
  2087. Error);
  2088. break;
  2089. }
  2090. }
  2091. }
  2092. CloseHandle(Overlapped.hEvent);
  2093. dprintf("Press ENTER to continue\n");
  2094. // Flush all remaining output.
  2095. FlushCallbacks();
  2096. // Notify the main thread that output was produced.
  2097. SetEvent(ReaderInfo->OutEvent);
  2098. return 0;
  2099. }
  2100. BOOL
  2101. APIENTRY
  2102. MyCreatePipeEx(
  2103. OUT LPHANDLE lpReadPipe,
  2104. OUT LPHANDLE lpWritePipe,
  2105. IN LPSECURITY_ATTRIBUTES lpPipeAttributes,
  2106. IN DWORD nSize,
  2107. DWORD dwReadMode,
  2108. DWORD dwWriteMode
  2109. )
  2110. /*++
  2111. Routine Description:
  2112. The CreatePipeEx API is used to create an anonymous pipe I/O device.
  2113. Unlike CreatePipe FILE_FLAG_OVERLAPPED may be specified for one or
  2114. both handles.
  2115. Two handles to the device are created. One handle is opened for
  2116. reading and the other is opened for writing. These handles may be
  2117. used in subsequent calls to ReadFile and WriteFile to transmit data
  2118. through the pipe.
  2119. Arguments:
  2120. lpReadPipe - Returns a handle to the read side of the pipe. Data
  2121. may be read from the pipe by specifying this handle value in a
  2122. subsequent call to ReadFile.
  2123. lpWritePipe - Returns a handle to the write side of the pipe. Data
  2124. may be written to the pipe by specifying this handle value in a
  2125. subsequent call to WriteFile.
  2126. lpPipeAttributes - An optional parameter that may be used to specify
  2127. the attributes of the new pipe. If the parameter is not
  2128. specified, then the pipe is created without a security
  2129. descriptor, and the resulting handles are not inherited on
  2130. process creation. Otherwise, the optional security attributes
  2131. are used on the pipe, and the inherit handles flag effects both
  2132. pipe handles.
  2133. nSize - Supplies the requested buffer size for the pipe. This is
  2134. only a suggestion and is used by the operating system to
  2135. calculate an appropriate buffering mechanism. A value of zero
  2136. indicates that the system is to choose the default buffering
  2137. scheme.
  2138. Return Value:
  2139. TRUE - The operation was successful.
  2140. FALSE/NULL - The operation failed. Extended error status is available
  2141. using GetLastError.
  2142. --*/
  2143. {
  2144. HANDLE ReadPipeHandle, WritePipeHandle;
  2145. DWORD dwError;
  2146. CHAR PipeNameBuffer[ MAX_PATH ];
  2147. //
  2148. // Only one valid OpenMode flag - FILE_FLAG_OVERLAPPED
  2149. //
  2150. if ((dwReadMode | dwWriteMode) & (~FILE_FLAG_OVERLAPPED))
  2151. {
  2152. SetLastError(ERROR_INVALID_PARAMETER);
  2153. return FALSE;
  2154. }
  2155. //
  2156. // Set the default timeout to 120 seconds
  2157. //
  2158. if (nSize == 0)
  2159. {
  2160. nSize = 4096;
  2161. }
  2162. sprintf( PipeNameBuffer,
  2163. "\\\\.\\Pipe\\Win32PipesEx.%08x.%08x",
  2164. GetCurrentProcessId(),
  2165. g_PipeSerialNumber++
  2166. );
  2167. ReadPipeHandle = CreateNamedPipeA(
  2168. PipeNameBuffer,
  2169. PIPE_ACCESS_INBOUND | dwReadMode,
  2170. PIPE_TYPE_BYTE | PIPE_WAIT,
  2171. 1, // Number of pipes
  2172. nSize, // Out buffer size
  2173. nSize, // In buffer size
  2174. 120 * 1000, // Timeout in ms
  2175. lpPipeAttributes
  2176. );
  2177. if (ReadPipeHandle == INVALID_HANDLE_VALUE)
  2178. {
  2179. return FALSE;
  2180. }
  2181. WritePipeHandle = CreateFileA(
  2182. PipeNameBuffer,
  2183. GENERIC_WRITE,
  2184. 0, // No sharing
  2185. lpPipeAttributes,
  2186. OPEN_EXISTING,
  2187. FILE_ATTRIBUTE_NORMAL | dwWriteMode,
  2188. NULL // Template file
  2189. );
  2190. if (INVALID_HANDLE_VALUE == WritePipeHandle)
  2191. {
  2192. dwError = GetLastError();
  2193. CloseHandle( ReadPipeHandle );
  2194. SetLastError(dwError);
  2195. return FALSE;
  2196. }
  2197. *lpReadPipe = ReadPipeHandle;
  2198. *lpWritePipe = WritePipeHandle;
  2199. return( TRUE );
  2200. }
  2201. VOID
  2202. fnShell(
  2203. PCSTR Args
  2204. )
  2205. {
  2206. //
  2207. // If the debugger always ran through stdin/stdout, we
  2208. // could just run a shell and wait for it. However, in order
  2209. // to handle fDebugOutput, we have to open pipes and manage
  2210. // the i/o stream for the shell. Since we need to have that
  2211. // code anyway, always use it.
  2212. //
  2213. //
  2214. // handles 0 and 1 are stdin, stdout.
  2215. // the third handle on the debugger side is
  2216. // the process handle, and the third handle
  2217. // on the shell side is stderr, which is a dup
  2218. // of stdout.
  2219. // The other handle for the debugger is an output event handle
  2220. // that is set by the reader thread when output is generated.
  2221. //
  2222. SHELL_READER_INFO ReaderInfo;
  2223. HANDLE HandlesForShell[3] = {0};
  2224. HANDLE ReaderThreadHandle = 0;
  2225. DWORD ThreadId;
  2226. SECURITY_ATTRIBUTES sa;
  2227. CHAR Shell[_MAX_PATH];
  2228. CHAR Command[2 * _MAX_PATH];
  2229. STARTUPINFO si;
  2230. PROCESS_INFORMATION pi;
  2231. CHAR InputBuffer[_MAX_PATH];
  2232. DWORD Bytes;
  2233. DWORD BytesWritten;
  2234. int i;
  2235. C_ASSERT(DIMA(ReaderInfo.IoHandles) == DIMA(HandlesForShell));
  2236. if (g_EngOptions & DEBUG_ENGOPT_DISALLOW_SHELL_COMMANDS)
  2237. {
  2238. ErrOut(".shell has been disabled\n");
  2239. return;
  2240. }
  2241. if (SYSTEM_PROCESSES())
  2242. {
  2243. ErrOut(".shell: can't create a process while debugging CSRSS.\n");
  2244. return;
  2245. }
  2246. ZeroMemory(&ReaderInfo, sizeof(ReaderInfo));
  2247. ZeroMemory(&pi, sizeof(pi));
  2248. sa.nLength = sizeof(sa);
  2249. sa.lpSecurityDescriptor = NULL;
  2250. sa.bInheritHandle = TRUE;
  2251. __try
  2252. {
  2253. //
  2254. // Create stdin pipe for ntsd->shell.
  2255. // Neither end needs to be overlapped.
  2256. //
  2257. if ( ! MyCreatePipeEx(
  2258. &HandlesForShell[0], // read handle
  2259. &ReaderInfo.IoHandles[0], // write handle
  2260. &sa, // security
  2261. 0, // size
  2262. 0, // read handle overlapped?
  2263. 0 // write handle overlapped?
  2264. ))
  2265. {
  2266. ErrOut(".shell: Unable to create stdin pipe.\n");
  2267. __leave;
  2268. }
  2269. //
  2270. // We don't want the shell to inherit our end of the pipe
  2271. // so duplicate it to a non-inheritable one.
  2272. //
  2273. if ( ! DuplicateHandle(
  2274. GetCurrentProcess(), // src process
  2275. ReaderInfo.IoHandles[0], // src handle
  2276. GetCurrentProcess(), // targ process
  2277. &ReaderInfo.IoHandles[0], // targ handle
  2278. 0, // access
  2279. FALSE, // inheritable
  2280. DUPLICATE_SAME_ACCESS |
  2281. DUPLICATE_CLOSE_SOURCE // options
  2282. ))
  2283. {
  2284. ErrOut(".shell: Unable to duplicate stdin handle.\n");
  2285. __leave;
  2286. }
  2287. //
  2288. // Create stdout shell->ntsd pipe
  2289. //
  2290. if ( ! MyCreatePipeEx(
  2291. &ReaderInfo.IoHandles[1], // read handle
  2292. &HandlesForShell[1], // write handle
  2293. &sa, // security
  2294. 0, // size
  2295. FILE_FLAG_OVERLAPPED, // read handle overlapped?
  2296. 0 // write handle overlapped?
  2297. ))
  2298. {
  2299. ErrOut(".shell: Unable to create stdout pipe.\n");
  2300. __leave;
  2301. }
  2302. //
  2303. // We don't want the shell to inherit our end of the pipe
  2304. // so duplicate it to a non-inheritable one.
  2305. //
  2306. if ( ! DuplicateHandle(
  2307. GetCurrentProcess(), // src process
  2308. ReaderInfo.IoHandles[1], // src handle
  2309. GetCurrentProcess(), // targ process
  2310. &ReaderInfo.IoHandles[1], // targ handle
  2311. 0, // access
  2312. FALSE, // inheritable
  2313. DUPLICATE_SAME_ACCESS |
  2314. DUPLICATE_CLOSE_SOURCE // options
  2315. ))
  2316. {
  2317. ErrOut(".shell: Unable to duplicate local stdout handle.\n");
  2318. __leave;
  2319. }
  2320. //
  2321. // Duplicate shell's stdout to a new stderr.
  2322. //
  2323. if ( ! DuplicateHandle(
  2324. GetCurrentProcess(), // src process
  2325. HandlesForShell[1], // src handle
  2326. GetCurrentProcess(), // targ process
  2327. &HandlesForShell[2], // targ handle
  2328. 0, // access
  2329. TRUE, // inheritable
  2330. DUPLICATE_SAME_ACCESS // options
  2331. ))
  2332. {
  2333. ErrOut(".shell: Unable to duplicate stdout handle for stderr.\n");
  2334. __leave;
  2335. }
  2336. //
  2337. // Create an event for output monitoring.
  2338. //
  2339. ReaderInfo.OutEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
  2340. if (ReaderInfo.OutEvent == NULL)
  2341. {
  2342. ErrOut(".shell: Unable to allocate event.\n");
  2343. __leave;
  2344. }
  2345. if (!GetEnvironmentVariable("SHELL", Shell, sizeof(Shell)))
  2346. {
  2347. if (!GetEnvironmentVariable("ComSpec", Shell, sizeof(Shell)))
  2348. {
  2349. strcpy(Shell, "cmd.exe");
  2350. }
  2351. }
  2352. // Skip leading whitespace on the command string.
  2353. // Some commands, such as "net use", can't handle it.
  2354. if (Args != NULL)
  2355. {
  2356. while (isspace(*Args))
  2357. {
  2358. Args++;
  2359. }
  2360. }
  2361. if (Args && *Args)
  2362. {
  2363. //
  2364. // If there was a command, use SHELL /c Command
  2365. //
  2366. sprintf(Command, "%s /c \"%s\"", Shell, Args);
  2367. }
  2368. else
  2369. {
  2370. //
  2371. // If there was no command, just run the shell
  2372. //
  2373. sprintf(Command, "%s", Shell);
  2374. }
  2375. ZeroMemory(&si, sizeof(si));
  2376. si.cb = sizeof(si);
  2377. si.dwFlags = STARTF_USESTDHANDLES;
  2378. si.hStdInput = HandlesForShell[0];
  2379. si.hStdOutput = HandlesForShell[1];
  2380. si.hStdError = HandlesForShell[2];
  2381. si.wShowWindow = SW_SHOW;
  2382. //
  2383. // Create Child Process
  2384. //
  2385. if ( ! CreateProcess(
  2386. NULL,
  2387. Command,
  2388. NULL,
  2389. NULL,
  2390. TRUE,
  2391. GetPriorityClass( GetCurrentProcess() ),
  2392. NULL,
  2393. NULL,
  2394. &si,
  2395. &pi))
  2396. {
  2397. if (GetLastError() == ERROR_FILE_NOT_FOUND)
  2398. {
  2399. dprintf("%s not found\n", Shell);
  2400. }
  2401. else
  2402. {
  2403. ErrOut("CreateProcess(%s) failed, error %d.\n",
  2404. Command, GetLastError());
  2405. }
  2406. __leave;
  2407. }
  2408. ReaderInfo.IoHandles[2] = pi.hProcess;
  2409. //
  2410. // Start reader thread to copy shell output
  2411. //
  2412. ReaderThreadHandle = CreateThread(
  2413. NULL,
  2414. 0,
  2415. ShellReaderThread,
  2416. &ReaderInfo,
  2417. 0,
  2418. &ThreadId
  2419. );
  2420. ULONG Timeout = 1000;
  2421. //
  2422. // Feed input to shell; wait for it to exit.
  2423. //
  2424. while (1)
  2425. {
  2426. ULONG WaitStatus;
  2427. // Give the other process a little time to run.
  2428. // This is critical when output is being piped
  2429. // across kd as GetInput causes the machine to
  2430. // sit in the kernel debugger input routine and
  2431. // nobody gets any time to run.
  2432. WaitStatus = WaitForSingleObject(ReaderInfo.OutEvent, 100);
  2433. if (WaitStatus == WAIT_OBJECT_0)
  2434. {
  2435. // Reset the timeout since the process seems to
  2436. // be active.
  2437. Timeout = 1000;
  2438. // Some output was produced so let the child keep
  2439. // running to keep the output flowing. If this
  2440. // was the final output of the process, though,
  2441. // go to the last input request.
  2442. if (WaitForSingleObject(pi.hProcess, 0) != WAIT_OBJECT_0)
  2443. {
  2444. continue;
  2445. }
  2446. }
  2447. // We've run out of immediate output, so wait for a
  2448. // larger interval to give the process a reasonable
  2449. // amount of time to run. Show a message to keep
  2450. // users in the loop.
  2451. dprintf("<.shell waiting %d second(s) for process>\n",
  2452. Timeout / 1000);
  2453. FlushCallbacks();
  2454. WaitStatus = WaitForSingleObject(ReaderInfo.OutEvent, Timeout);
  2455. if (WaitStatus == WAIT_OBJECT_0 &&
  2456. WaitForSingleObject(pi.hProcess, 0) != WAIT_OBJECT_0)
  2457. {
  2458. // Reset the timeout since the process seems to
  2459. // be active.
  2460. Timeout = 1000;
  2461. continue;
  2462. }
  2463. Bytes = GetInput("<.shell process may need input>",
  2464. InputBuffer, sizeof(InputBuffer) - 2);
  2465. // The user may not want to wait, so check for
  2466. // a magic input string that'll abandon the process.
  2467. if (!_strcmpi(InputBuffer, ".shell_quit"))
  2468. {
  2469. break;
  2470. }
  2471. //
  2472. // see if client is still running
  2473. //
  2474. if (WaitForSingleObject(pi.hProcess, 0) == WAIT_OBJECT_0)
  2475. {
  2476. break;
  2477. }
  2478. //
  2479. // GetInput always returns a string without a newline
  2480. //
  2481. strcat(InputBuffer, "\n");
  2482. if (!WriteFile( ReaderInfo.IoHandles[0],
  2483. InputBuffer,
  2484. strlen(InputBuffer),
  2485. &BytesWritten,
  2486. NULL
  2487. ))
  2488. {
  2489. //
  2490. // if the write fails, we're done...
  2491. //
  2492. break;
  2493. }
  2494. // The process has some input to chew on so
  2495. // increase the amount of time we'll wait for it.
  2496. Timeout *= 2;
  2497. }
  2498. }
  2499. __finally
  2500. {
  2501. //
  2502. // Close all of the i/o handles first.
  2503. // That will make the reader thread exit if it was running.
  2504. //
  2505. for (i = 0; i < DIMA(ReaderInfo.IoHandles); i++)
  2506. {
  2507. if (ReaderInfo.IoHandles[i])
  2508. {
  2509. CloseHandle(ReaderInfo.IoHandles[i]);
  2510. }
  2511. if (HandlesForShell[i])
  2512. {
  2513. CloseHandle(HandlesForShell[i]);
  2514. }
  2515. }
  2516. if (pi.hThread)
  2517. {
  2518. CloseHandle(pi.hThread);
  2519. }
  2520. if (ReaderThreadHandle)
  2521. {
  2522. WaitForSingleObject(ReaderThreadHandle, INFINITE);
  2523. CloseHandle(ReaderThreadHandle);
  2524. }
  2525. // Close this handle after the thread has exited
  2526. // to avoid it using a bad handle.
  2527. CloseHandle(ReaderInfo.OutEvent);
  2528. }
  2529. }
  2530. VOID
  2531. fnBangCmd(
  2532. DebugClient* Client,
  2533. PSTR ArgString,
  2534. PSTR *ArgNext,
  2535. BOOL BuiltInOnly
  2536. )
  2537. {
  2538. PCHAR pc;
  2539. PCHAR pc1;
  2540. PCHAR ModName;
  2541. PCHAR FnName;
  2542. CHAR String[MAX_COMMAND];
  2543. EXTDLL *Ext;
  2544. CHAR Save;
  2545. PSTR FnArgs;
  2546. //
  2547. // Shell escape always consumes the entire string.
  2548. //
  2549. if (*ArgString == '!')
  2550. {
  2551. if (ArgNext)
  2552. {
  2553. *ArgNext = ArgString + strlen(ArgString);
  2554. }
  2555. fnShell(ArgString + 1);
  2556. return;
  2557. }
  2558. // Copy the command into a local buffer so that we
  2559. // can modify it.
  2560. strcpy(String, ArgString);
  2561. //
  2562. // Syntax is [path-without-spaces]module.function argument-string.
  2563. //
  2564. pc = String;
  2565. while ((*pc == ' ') || (*pc == '\t'))
  2566. {
  2567. pc++;
  2568. }
  2569. ModName = pc;
  2570. FnName = NULL;
  2571. while ((*pc != ' ') && (*pc != '\t') && (*pc != '\0') &&
  2572. (*pc != ';') && (*pc != '"'))
  2573. {
  2574. pc++;
  2575. }
  2576. pc1 = pc;
  2577. if (*pc != '\000' && *pc != ';' && *pc != '"')
  2578. {
  2579. *pc = '\000';
  2580. pc++; // now pc points to any args
  2581. }
  2582. while (*pc1 != '.' && pc1 != ModName)
  2583. {
  2584. pc1--;
  2585. }
  2586. if (*pc1 == '.' && !BuiltInOnly)
  2587. {
  2588. *pc1 = '\0';
  2589. pc1++;
  2590. FnName = pc1;
  2591. }
  2592. else
  2593. {
  2594. FnName = ModName;
  2595. ModName = NULL;
  2596. }
  2597. if ((FnArgs = BufferStringValue(&pc, STRV_ESCAPED_CHARACTERS,
  2598. &Save)) == NULL)
  2599. {
  2600. ErrOut("Syntax error in extension string\n");
  2601. return;
  2602. }
  2603. //
  2604. // point to next command:
  2605. //
  2606. if (ArgNext)
  2607. {
  2608. *ArgNext = ArgString + (pc - String);
  2609. }
  2610. //
  2611. // ModName -> Name of module
  2612. // FnName -> Name of command to process
  2613. // FnArgs -> argument to command
  2614. //
  2615. if (ModName != NULL)
  2616. {
  2617. Ext = AddExtensionDll(ModName, TRUE, NULL);
  2618. if (Ext == NULL)
  2619. {
  2620. return;
  2621. }
  2622. }
  2623. else
  2624. {
  2625. Ext = g_ExtDlls;
  2626. }
  2627. if (!_stricmp(FnName, "load"))
  2628. {
  2629. if (ModName == NULL)
  2630. {
  2631. Ext = AddExtensionDll(FnArgs, TRUE, NULL);
  2632. if (Ext == NULL)
  2633. {
  2634. return;
  2635. }
  2636. }
  2637. LoadExtensionDll(Ext);
  2638. return;
  2639. }
  2640. else if (!_stricmp(FnName, "setdll"))
  2641. {
  2642. if (ModName == NULL)
  2643. {
  2644. Ext = AddExtensionDll(FnArgs, TRUE, NULL);
  2645. if (Ext == NULL)
  2646. {
  2647. return;
  2648. }
  2649. }
  2650. MoveExtensionToHead(Ext);
  2651. if (ModName != NULL && Ext->Dll == NULL)
  2652. {
  2653. dprintf("Added %s to extension DLL chain\n", Ext->Name);
  2654. }
  2655. return;
  2656. }
  2657. else if (!_stricmp(FnName, "unload"))
  2658. {
  2659. if (ModName == NULL)
  2660. {
  2661. if (*FnArgs == '\0')
  2662. {
  2663. Ext = g_ExtDlls;
  2664. }
  2665. else
  2666. {
  2667. Ext = AddExtensionDll(FnArgs, TRUE, NULL);
  2668. }
  2669. if (Ext == NULL)
  2670. {
  2671. return;
  2672. }
  2673. }
  2674. if (Ext != NULL)
  2675. {
  2676. UnloadExtensionDll(Ext);
  2677. }
  2678. return;
  2679. }
  2680. else if (!_stricmp(FnName, "unloadall"))
  2681. {
  2682. g_EngNotify++;
  2683. while (g_ExtDlls != NULL)
  2684. {
  2685. UnloadExtensionDll(g_ExtDlls);
  2686. }
  2687. g_EngNotify--;
  2688. NotifyChangeEngineState(DEBUG_CES_EXTENSIONS, 0, TRUE);
  2689. return;
  2690. }
  2691. if (ModName == NULL)
  2692. {
  2693. // Handle built-in commands.
  2694. if (!_stricmp(FnName, "chain"))
  2695. {
  2696. OutputExtensions(Client, FALSE);
  2697. return;
  2698. }
  2699. else if (!_stricmp(FnName, "lines"))
  2700. {
  2701. ParseLines(FnArgs);
  2702. return;
  2703. }
  2704. else if (!_stricmp(FnName, "noversion"))
  2705. {
  2706. dprintf("Extension DLL system version checking is disabled\n");
  2707. g_EnvDbgOptions |= OPTION_NOVERSIONCHECK;
  2708. return;
  2709. }
  2710. else if (!_stricmp(FnName, "reload"))
  2711. {
  2712. g_Target->Reload(FnArgs);
  2713. ClearStoredTypes(0);
  2714. return;
  2715. }
  2716. else if (!_stricmp(FnName, "srcpath") ||
  2717. !_stricmp(FnName, "srcpath+"))
  2718. {
  2719. //
  2720. // .srcpath needs complete command tail not
  2721. // stopping at semicolons
  2722. //
  2723. FnArgs = ArgString + (FnArgs - String);
  2724. if (ArgNext)
  2725. {
  2726. *ArgNext = FnArgs + strlen(FnArgs);
  2727. }
  2728. ChangeSrcPath(FnArgs, FnName[7] == '+');
  2729. return;
  2730. }
  2731. else if (!_stricmp(FnName, "sympath") ||
  2732. !_stricmp(FnName, "sympath+"))
  2733. {
  2734. //
  2735. // .sympath needs complete command tail not
  2736. // stopping at semicolons
  2737. //
  2738. FnArgs = ArgString + (FnArgs - String);
  2739. if (ArgNext)
  2740. {
  2741. *ArgNext = FnArgs + strlen(FnArgs);
  2742. }
  2743. bangSymPath(FnArgs, FnName[7] == '+', NULL, 0);
  2744. return;
  2745. }
  2746. else if (!_stricmp(FnName, "exepath") ||
  2747. !_stricmp(FnName, "exepath+"))
  2748. {
  2749. //
  2750. // .exepath needs complete command tail not
  2751. // stopping at semicolons
  2752. //
  2753. FnArgs = ArgString + (FnArgs - String);
  2754. if (ArgNext)
  2755. {
  2756. *ArgNext = FnArgs + strlen(FnArgs);
  2757. }
  2758. ChangeExePath(FnArgs, FnName[7] == '+');
  2759. return;
  2760. }
  2761. else if (!_stricmp(FnName, "netsyms"))
  2762. {
  2763. if (_stricmp(FnArgs, "1") == 0 ||
  2764. _stricmp(FnArgs, "true") == 0 ||
  2765. _stricmp(FnArgs, "yes") == 0)
  2766. {
  2767. g_EngOptions |= DEBUG_ENGOPT_ALLOW_NETWORK_PATHS;
  2768. g_EngOptions &= ~DEBUG_ENGOPT_DISALLOW_NETWORK_PATHS;
  2769. }
  2770. else if (_stricmp(FnArgs, "0") == 0 ||
  2771. _stricmp(FnArgs, "false") == 0 ||
  2772. _stricmp(FnArgs, "no") == 0)
  2773. {
  2774. g_EngOptions |= DEBUG_ENGOPT_DISALLOW_NETWORK_PATHS;
  2775. g_EngOptions &= ~DEBUG_ENGOPT_ALLOW_NETWORK_PATHS;
  2776. }
  2777. if (g_EngOptions & DEBUG_ENGOPT_ALLOW_NETWORK_PATHS)
  2778. {
  2779. dprintf("netsyms = yes\n");
  2780. }
  2781. else if (g_EngOptions & DEBUG_ENGOPT_DISALLOW_NETWORK_PATHS)
  2782. {
  2783. dprintf("netsyms = no\n");
  2784. }
  2785. else
  2786. {
  2787. dprintf("netsyms = don't care\n");
  2788. }
  2789. return;
  2790. }
  2791. else if (!_stricmp(FnName, "context"))
  2792. {
  2793. if (*FnArgs != 0)
  2794. {
  2795. ULONG64 Base = ExtGetExpression(FnArgs);
  2796. ULONG NextIdx;
  2797. if (g_Machine->SetPageDirectory(PAGE_DIR_USER, Base,
  2798. &NextIdx) != S_OK)
  2799. {
  2800. WarnOut("WARNING: Unable to reset page directory base\n");
  2801. }
  2802. // Flush the cache as anything we read from user mode is
  2803. // no longer valid
  2804. g_VirtualCache.Empty();
  2805. if (Base && !g_VirtualCache.m_ForceDecodePTEs)
  2806. {
  2807. WarnOut("WARNING: "
  2808. ".cache forcedecodeptes is not enabled\n");
  2809. }
  2810. }
  2811. else
  2812. {
  2813. dprintf("User-mode page directory base is %I64x\n",
  2814. g_Machine->m_PageDirectories[PAGE_DIR_USER]);
  2815. }
  2816. return;
  2817. }
  2818. else if (!_stricmp(FnName, "symfix"))
  2819. {
  2820. bangSymPath("symsrv*symsrv.dll*\\\\symbols\\symbols",
  2821. FALSE, NULL, 0);
  2822. return;
  2823. }
  2824. }
  2825. if (BuiltInOnly)
  2826. {
  2827. error(SYNTAX);
  2828. }
  2829. HRESULT ExtStatus;
  2830. CallAnyExtension(Client, Ext, FnName, FnArgs, ModName != NULL, TRUE,
  2831. &ExtStatus);
  2832. }
  2833. BOOL
  2834. bangSymPath(
  2835. IN PCSTR args,
  2836. IN BOOL Append,
  2837. OUT PSTR string,
  2838. IN ULONG len
  2839. )
  2840. {
  2841. PPROCESS_INFO pProcess;
  2842. __try
  2843. {
  2844. if (args != NULL)
  2845. {
  2846. while (*args == ' ' || *args == '\t')
  2847. {
  2848. args++;
  2849. }
  2850. }
  2851. if ( args != NULL && *args )
  2852. {
  2853. if (ChangePath(&g_SymbolSearchPath, args, Append,
  2854. DEBUG_CSS_PATHS) != S_OK)
  2855. {
  2856. return FALSE;
  2857. }
  2858. pProcess = g_ProcessHead;
  2859. while (pProcess)
  2860. {
  2861. SymSetSearchPath( pProcess->Handle, g_SymbolSearchPath );
  2862. pProcess = pProcess->Next;
  2863. }
  2864. }
  2865. if (string)
  2866. {
  2867. strncpy( string, g_SymbolSearchPath, len );
  2868. string[len - 1] = 0;
  2869. }
  2870. else
  2871. {
  2872. dprintf( "Symbol search path is: %s\n", g_SymbolSearchPath );
  2873. CheckPath(g_SymbolSearchPath);
  2874. }
  2875. }
  2876. __except(EXCEPTION_EXECUTE_HANDLER)
  2877. {
  2878. return FALSE;
  2879. }
  2880. return TRUE;
  2881. }
  2882. void
  2883. ReadDebugOptions (BOOL fQuiet, char * pszOptionsStr)
  2884. /*++
  2885. Routine Description:
  2886. Parses an options string (see g_EnvDbgOptionNames) and maps
  2887. it to OPTION_ flags (in g_EnvDbgOptions).
  2888. Arguments:
  2889. fQuiet - If TRUE, do not print option settings.
  2890. pszOptionsStr - Options string; if NULL, get it from _NT_DEBUG_OPTIONS
  2891. Return Value:
  2892. None
  2893. --*/
  2894. {
  2895. BOOL fInit;
  2896. char ** ppszOption;
  2897. char * psz;
  2898. DWORD dwMask;
  2899. int iOptionCount;
  2900. fInit = (pszOptionsStr == NULL);
  2901. if (fInit)
  2902. {
  2903. g_EnvDbgOptions = 0;
  2904. pszOptionsStr = getenv("_NT_DEBUG_OPTIONS");
  2905. }
  2906. if (pszOptionsStr == NULL)
  2907. {
  2908. if (!fQuiet)
  2909. {
  2910. dprintf("_NT_DEBUG_OPTIONS is not defined\n");
  2911. }
  2912. return;
  2913. }
  2914. psz = pszOptionsStr;
  2915. while (*psz != '\0')
  2916. {
  2917. *psz = (char)toupper(*psz);
  2918. psz++;
  2919. }
  2920. ppszOption = g_EnvDbgOptionNames;
  2921. for (iOptionCount = 0;
  2922. iOptionCount < OPTION_COUNT;
  2923. iOptionCount++, ppszOption++)
  2924. {
  2925. if ((strstr(pszOptionsStr, *ppszOption) == NULL))
  2926. {
  2927. continue;
  2928. }
  2929. dwMask = (1 << iOptionCount);
  2930. if (fInit)
  2931. {
  2932. g_EnvDbgOptions |= dwMask;
  2933. }
  2934. else
  2935. {
  2936. g_EnvDbgOptions ^= dwMask;
  2937. }
  2938. }
  2939. if (!fQuiet)
  2940. {
  2941. dprintf("Debug Options:");
  2942. if (g_EnvDbgOptions == 0)
  2943. {
  2944. dprintf(" <none>\n");
  2945. }
  2946. else
  2947. {
  2948. dwMask = g_EnvDbgOptions;
  2949. ppszOption = g_EnvDbgOptionNames;
  2950. while (dwMask != 0)
  2951. {
  2952. if (dwMask & 0x1)
  2953. {
  2954. dprintf(" %s", *ppszOption);
  2955. }
  2956. dwMask >>= 1;
  2957. ppszOption++;
  2958. }
  2959. dprintf("\n");
  2960. }
  2961. }
  2962. }
  2963. //----------------------------------------------------------------------------
  2964. //
  2965. // LoadWow64ExtsIfNeeded
  2966. //
  2967. //----------------------------------------------------------------------------
  2968. VOID
  2969. LoadWow64ExtsIfNeeded(
  2970. VOID
  2971. )
  2972. {
  2973. LONG_PTR Wow64Info;
  2974. NTSTATUS Status;
  2975. EXTDLL * Extension;
  2976. // Win9x doesn't support wx86.
  2977. if (g_DebuggerPlatformId != VER_PLATFORM_WIN32_NT)
  2978. {
  2979. return;
  2980. }
  2981. //
  2982. // if New process is a Wx86 process, load in the wx86 extensions
  2983. // dll. This will stay loaded until ntsd exits.
  2984. //
  2985. Status = g_NtDllCalls.NtQueryInformationProcess(g_CurrentProcess->Handle,
  2986. ProcessWow64Information,
  2987. &Wow64Info,
  2988. sizeof(Wow64Info),
  2989. NULL
  2990. );
  2991. if (NT_SUCCESS(Status) && Wow64Info)
  2992. {
  2993. Extension = AddExtensionDll("wow64exts", FALSE, NULL);
  2994. //
  2995. // Force load it so we get the entry point the debugger needs
  2996. //
  2997. LoadExtensionDll(Extension);
  2998. }
  2999. }