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.

4103 lines
84 KiB

  1. //----------------------------------------------------------------------------
  2. //
  3. // IDebugControl implementation.
  4. //
  5. // Copyright (C) Microsoft Corporation, 1999-2001.
  6. //
  7. //----------------------------------------------------------------------------
  8. #include "ntsdp.hpp"
  9. ULONG g_LogMask = DEFAULT_OUT_MASK;
  10. STDMETHODIMP
  11. DebugClient::GetInterrupt(
  12. THIS
  13. )
  14. {
  15. // This method is reentrant.
  16. return CheckUserInterrupt() ? S_OK : S_FALSE;
  17. }
  18. STDMETHODIMP
  19. DebugClient::SetInterrupt(
  20. THIS_
  21. IN ULONG Flags
  22. )
  23. {
  24. // This method is reentrant.
  25. if (
  26. #if DEBUG_INTERRUPT_ACTIVE > 0
  27. Flags < DEBUG_INTERRUPT_ACTIVE ||
  28. #endif
  29. Flags > DEBUG_INTERRUPT_EXIT)
  30. {
  31. return E_INVALIDARG;
  32. }
  33. if (!IS_TARGET_SET())
  34. {
  35. return E_UNEXPECTED;
  36. }
  37. // If the debuggee isn't currently running
  38. // we just need to set the operation-interrupt
  39. // flag. If this is a passive interrupt that's
  40. // all that's ever done.
  41. if (Flags == DEBUG_INTERRUPT_PASSIVE ||
  42. (IS_MACHINE_SET() && g_CmdState == 'c'))
  43. {
  44. g_EngStatus |= ENG_STATUS_USER_INTERRUPT;
  45. return S_OK;
  46. }
  47. // If this is an exit interrupt we don't want
  48. // to actually interrupt the running debuggee,
  49. // we just want to terminate the current wait.
  50. if (Flags == DEBUG_INTERRUPT_EXIT)
  51. {
  52. g_EngStatus |= ENG_STATUS_EXIT_CURRENT_WAIT;
  53. return S_OK;
  54. }
  55. //
  56. // Force a break-in. Don't set user-interrupt in
  57. // this case as that's just a marker for
  58. // interrupting commands. Setting it can
  59. // interfere with break-in processing since commands
  60. // executed during break-in may be affected by it.
  61. //
  62. HRESULT Status = g_Target->RequestBreakIn();
  63. if (Status == S_OK)
  64. {
  65. g_EngStatus |= ENG_STATUS_PENDING_BREAK_IN;
  66. }
  67. return Status;
  68. }
  69. STDMETHODIMP
  70. DebugClient::GetInterruptTimeout(
  71. THIS_
  72. OUT PULONG Seconds
  73. )
  74. {
  75. ENTER_ENGINE();
  76. *Seconds = g_PendingBreakInTimeoutLimit;
  77. LEAVE_ENGINE();
  78. return S_OK;
  79. }
  80. STDMETHODIMP
  81. DebugClient::SetInterruptTimeout(
  82. THIS_
  83. IN ULONG Seconds
  84. )
  85. {
  86. if (Seconds < 1)
  87. {
  88. return E_INVALIDARG;
  89. }
  90. ENTER_ENGINE();
  91. g_PendingBreakInTimeoutLimit = Seconds;
  92. LEAVE_ENGINE();
  93. return S_OK;
  94. }
  95. STDMETHODIMP
  96. DebugClient::GetLogFile(
  97. THIS_
  98. OUT OPTIONAL PSTR Buffer,
  99. IN ULONG BufferSize,
  100. OUT OPTIONAL PULONG FileSize,
  101. OUT PBOOL Append
  102. )
  103. {
  104. HRESULT Status;
  105. ENTER_ENGINE();
  106. if (!g_OpenLogFileName[0])
  107. {
  108. Status = E_NOINTERFACE;
  109. *Append = FALSE;
  110. }
  111. else
  112. {
  113. Status = FillStringBuffer(g_OpenLogFileName, 0,
  114. Buffer, BufferSize, FileSize);
  115. *Append = g_OpenLogFileAppended;
  116. }
  117. LEAVE_ENGINE();
  118. return Status;
  119. }
  120. STDMETHODIMP
  121. DebugClient::OpenLogFile(
  122. THIS_
  123. IN PCSTR File,
  124. IN BOOL Append
  125. )
  126. {
  127. ENTER_ENGINE();
  128. ::OpenLogFile(File, Append);
  129. LEAVE_ENGINE();
  130. return S_OK;
  131. }
  132. STDMETHODIMP
  133. DebugClient::CloseLogFile(
  134. THIS
  135. )
  136. {
  137. ENTER_ENGINE();
  138. fnLogClose();
  139. LEAVE_ENGINE();
  140. return S_OK;
  141. }
  142. STDMETHODIMP
  143. DebugClient::GetLogMask(
  144. THIS_
  145. OUT PULONG Mask
  146. )
  147. {
  148. // This method is reentrant.
  149. *Mask = g_LogMask;
  150. return S_OK;
  151. }
  152. STDMETHODIMP
  153. DebugClient::SetLogMask(
  154. THIS_
  155. IN ULONG Mask
  156. )
  157. {
  158. // This method is reentrant.
  159. g_LogMask = Mask;
  160. return S_OK;
  161. }
  162. STDMETHODIMP
  163. DebugClient::Input(
  164. THIS_
  165. OUT PSTR Buffer,
  166. IN ULONG BufferSize,
  167. OUT OPTIONAL PULONG InputSize
  168. )
  169. {
  170. if (BufferSize < 2)
  171. {
  172. // Must have space for at least a character and a terminator.
  173. return E_INVALIDARG;
  174. }
  175. ENTER_ENGINE();
  176. ULONG Size;
  177. Size = GetInput(NULL, Buffer, BufferSize);
  178. if (Size == 0)
  179. {
  180. return E_FAIL;
  181. }
  182. if (InputSize != NULL)
  183. {
  184. *InputSize = Size;
  185. }
  186. LEAVE_ENGINE();
  187. return Size > BufferSize ? S_FALSE : S_OK;
  188. }
  189. STDMETHODIMP
  190. DebugClient::ReturnInput(
  191. THIS_
  192. IN PCSTR Buffer
  193. )
  194. {
  195. // This method is reentrant.
  196. HRESULT Status;
  197. ULONG Seq = (ULONG)InterlockedIncrement((PLONG)&g_InputSequence);
  198. if (Seq == m_InputSequence)
  199. {
  200. ULONG CopyLen = strlen(Buffer) + 1;
  201. CopyLen = min(CopyLen, INPUT_BUFFER_SIZE);
  202. memcpy(g_InputBuffer, Buffer, CopyLen);
  203. g_InputBuffer[INPUT_BUFFER_SIZE - 1] = 0;
  204. SetEvent(g_InputEvent);
  205. Status = S_OK;
  206. }
  207. else
  208. {
  209. Status = S_FALSE;
  210. }
  211. m_InputSequence = 0xffffffff;
  212. return Status;
  213. }
  214. STDMETHODIMPV
  215. DebugClient::Output(
  216. THIS_
  217. IN ULONG Mask,
  218. IN PCSTR Format,
  219. ...
  220. )
  221. {
  222. ENTER_ENGINE();
  223. va_list Args;
  224. va_start(Args, Format);
  225. MaskOutVa(Mask, Format, Args, TRUE);
  226. va_end(Args);
  227. LEAVE_ENGINE();
  228. return S_OK;
  229. }
  230. STDMETHODIMP
  231. DebugClient::OutputVaList(
  232. THIS_
  233. IN ULONG Mask,
  234. IN PCSTR Format,
  235. IN va_list Args
  236. )
  237. {
  238. ENTER_ENGINE();
  239. MaskOutVa(Mask, Format, Args, TRUE);
  240. LEAVE_ENGINE();
  241. return S_OK;
  242. }
  243. STDMETHODIMPV
  244. DebugClient::ControlledOutput(
  245. THIS_
  246. IN ULONG OutputControl,
  247. IN ULONG Mask,
  248. IN PCSTR Format,
  249. ...
  250. )
  251. {
  252. HRESULT Status;
  253. ENTER_ENGINE();
  254. OutCtlSave OldCtl;
  255. if (!PushOutCtl(OutputControl, this, &OldCtl))
  256. {
  257. Status = E_INVALIDARG;
  258. }
  259. else
  260. {
  261. va_list Args;
  262. va_start(Args, Format);
  263. MaskOutVa(Mask, Format, Args, TRUE);
  264. va_end(Args);
  265. Status = S_OK;
  266. PopOutCtl(&OldCtl);
  267. }
  268. LEAVE_ENGINE();
  269. return Status;
  270. }
  271. STDMETHODIMP
  272. DebugClient::ControlledOutputVaList(
  273. THIS_
  274. IN ULONG OutputControl,
  275. IN ULONG Mask,
  276. IN PCSTR Format,
  277. IN va_list Args
  278. )
  279. {
  280. HRESULT Status;
  281. ENTER_ENGINE();
  282. OutCtlSave OldCtl;
  283. if (!PushOutCtl(OutputControl, this, &OldCtl))
  284. {
  285. Status = E_INVALIDARG;
  286. }
  287. else
  288. {
  289. MaskOutVa(Mask, Format, Args, TRUE);
  290. Status = S_OK;
  291. PopOutCtl(&OldCtl);
  292. }
  293. LEAVE_ENGINE();
  294. return Status;
  295. }
  296. STDMETHODIMPV
  297. DebugClient::OutputPrompt(
  298. THIS_
  299. IN ULONG OutputControl,
  300. IN OPTIONAL PCSTR Format,
  301. ...
  302. )
  303. {
  304. HRESULT Status;
  305. ENTER_ENGINE();
  306. OutCtlSave OldCtl;
  307. if (!PushOutCtl(OutputControl, this, &OldCtl))
  308. {
  309. Status = E_INVALIDARG;
  310. }
  311. else
  312. {
  313. va_list Args;
  314. va_start(Args, Format);
  315. ::OutputPrompt(Format, Args);
  316. va_end(Args);
  317. Status = S_OK;
  318. PopOutCtl(&OldCtl);
  319. }
  320. LEAVE_ENGINE();
  321. return Status;
  322. }
  323. STDMETHODIMP
  324. DebugClient::OutputPromptVaList(
  325. THIS_
  326. IN ULONG OutputControl,
  327. IN OPTIONAL PCSTR Format,
  328. IN va_list Args
  329. )
  330. {
  331. HRESULT Status;
  332. ENTER_ENGINE();
  333. OutCtlSave OldCtl;
  334. if (!PushOutCtl(OutputControl, this, &OldCtl))
  335. {
  336. Status = E_INVALIDARG;
  337. }
  338. else
  339. {
  340. ::OutputPrompt(Format, Args);
  341. Status = S_OK;
  342. PopOutCtl(&OldCtl);
  343. }
  344. LEAVE_ENGINE();
  345. return Status;
  346. }
  347. STDMETHODIMP
  348. DebugClient::GetPromptText(
  349. THIS_
  350. OUT OPTIONAL PSTR Buffer,
  351. IN ULONG BufferSize,
  352. OUT OPTIONAL PULONG TextSize
  353. )
  354. {
  355. HRESULT Status;
  356. ENTER_ENGINE();
  357. Status = ::GetPromptText(Buffer, BufferSize, TextSize);
  358. LEAVE_ENGINE();
  359. return Status;
  360. }
  361. #define CURRENT_ALL DEBUG_CURRENT_DEFAULT
  362. STDMETHODIMP
  363. DebugClient::OutputCurrentState(
  364. THIS_
  365. IN ULONG OutputControl,
  366. IN ULONG Flags
  367. )
  368. {
  369. if (Flags & ~CURRENT_ALL)
  370. {
  371. return E_INVALIDARG;
  372. }
  373. HRESULT Status;
  374. ENTER_ENGINE();
  375. OutCtlSave OldCtl;
  376. if (!IS_MACHINE_ACCESSIBLE())
  377. {
  378. Status = E_UNEXPECTED;
  379. }
  380. else if (!PushOutCtl(OutputControl, this, &OldCtl))
  381. {
  382. Status = E_INVALIDARG;
  383. }
  384. else
  385. {
  386. ULONG Oci = 0;
  387. if (Flags & DEBUG_CURRENT_SYMBOL)
  388. {
  389. Oci |= OCI_SYMBOL;
  390. }
  391. if (Flags & DEBUG_CURRENT_DISASM)
  392. {
  393. Oci |= OCI_DISASM | OCI_ALLOW_EA;
  394. }
  395. if (Flags & DEBUG_CURRENT_REGISTERS)
  396. {
  397. Oci |= OCI_ALLOW_REG;
  398. }
  399. if (Flags & DEBUG_CURRENT_SOURCE_LINE)
  400. {
  401. Oci |= OCI_ALLOW_SOURCE;
  402. }
  403. OutCurInfo(Oci, g_Machine->m_AllMask, DEBUG_OUTPUT_PROMPT_REGISTERS);
  404. Status = S_OK;
  405. PopOutCtl(&OldCtl);
  406. }
  407. LEAVE_ENGINE();
  408. return Status;
  409. }
  410. STDMETHODIMP
  411. DebugClient::OutputVersionInformation(
  412. THIS_
  413. IN ULONG OutputControl
  414. )
  415. {
  416. HRESULT Status;
  417. // This method is reentrant. It uses many pieces of
  418. // global information, though, so try and get
  419. // the engine lock.
  420. Status = TRY_ENTER_ENGINE();
  421. if (Status != S_OK)
  422. {
  423. return Status;
  424. }
  425. OutCtlSave OldCtl;
  426. if (!PushOutCtl(OutputControl, this, &OldCtl))
  427. {
  428. return E_INVALIDARG;
  429. }
  430. ::OutputVersionInformation(this);
  431. PopOutCtl(&OldCtl);
  432. LEAVE_ENGINE();
  433. return S_OK;
  434. }
  435. STDMETHODIMP
  436. DebugClient::GetNotifyEventHandle(
  437. THIS_
  438. OUT PULONG64 Handle
  439. )
  440. {
  441. ENTER_ENGINE();
  442. *Handle = (ULONG64)g_EventToSignal;
  443. LEAVE_ENGINE();
  444. return S_OK;
  445. }
  446. STDMETHODIMP
  447. DebugClient::SetNotifyEventHandle(
  448. THIS_
  449. IN ULONG64 Handle
  450. )
  451. {
  452. if ((ULONG64)(HANDLE)Handle != Handle)
  453. {
  454. return E_INVALIDARG;
  455. }
  456. ENTER_ENGINE();
  457. g_EventToSignal = (HANDLE)Handle;
  458. LEAVE_ENGINE();
  459. return S_OK;
  460. }
  461. STDMETHODIMP
  462. DebugClient::Assemble(
  463. THIS_
  464. IN ULONG64 Offset,
  465. IN PCSTR Instr,
  466. OUT PULONG64 EndOffset
  467. )
  468. {
  469. HRESULT Status;
  470. ENTER_ENGINE();
  471. __try
  472. {
  473. if (!IS_CONTEXT_ACCESSIBLE())
  474. {
  475. Status = E_UNEXPECTED;
  476. __leave;
  477. }
  478. ADDR Addr;
  479. // Assume this is a code segment address so that assembly
  480. // picks up the appropriate type of address.
  481. g_Machine->FormAddr(SEGREG_CODE, Offset,
  482. FORM_SEGREG | FORM_CODE, &Addr);
  483. g_Machine->Assemble(&Addr, (PSTR)Instr);
  484. *EndOffset = Flat(Addr);
  485. Status = S_OK;
  486. }
  487. __except(CommandExceptionFilter(GetExceptionInformation()))
  488. {
  489. Status = E_FAIL;
  490. }
  491. LEAVE_ENGINE();
  492. return Status;
  493. }
  494. STDMETHODIMP
  495. DebugClient::Disassemble(
  496. THIS_
  497. IN ULONG64 Offset,
  498. IN ULONG Flags,
  499. OUT OPTIONAL PSTR Buffer,
  500. IN ULONG BufferSize,
  501. OUT OPTIONAL PULONG DisassemblySize,
  502. OUT PULONG64 EndOffset
  503. )
  504. {
  505. if (Flags & ~DEBUG_DISASM_EFFECTIVE_ADDRESS)
  506. {
  507. return E_INVALIDARG;
  508. }
  509. HRESULT Status;
  510. ENTER_ENGINE();
  511. if (!IS_CONTEXT_ACCESSIBLE())
  512. {
  513. Status = E_UNEXPECTED;
  514. }
  515. else
  516. {
  517. ADDR Addr;
  518. CHAR Disasm[MAX_DISASM_LEN];
  519. // Assume this is a code segment address so that disassembly
  520. // picks up the appropriate type of address.
  521. g_Machine->FormAddr(SEGREG_CODE, Offset, FORM_SEGREG | FORM_CODE,
  522. &Addr);
  523. g_Machine->Disassemble(&Addr, Disasm,
  524. (Flags & DEBUG_DISASM_EFFECTIVE_ADDRESS));
  525. Status = FillStringBuffer(Disasm, 0,
  526. Buffer, BufferSize, DisassemblySize);
  527. *EndOffset = Flat(Addr);
  528. }
  529. LEAVE_ENGINE();
  530. return Status;
  531. }
  532. STDMETHODIMP
  533. DebugClient::GetDisassembleEffectiveOffset(
  534. THIS_
  535. OUT PULONG64 Offset
  536. )
  537. {
  538. HRESULT Status;
  539. ENTER_ENGINE();
  540. if (!IS_CONTEXT_ACCESSIBLE())
  541. {
  542. Status = E_UNEXPECTED;
  543. }
  544. else
  545. {
  546. ADDR Addr;
  547. g_Machine->GetEffectiveAddr(&Addr);
  548. *Offset = Flat(Addr);
  549. Status = S_OK;
  550. }
  551. LEAVE_ENGINE();
  552. return Status;
  553. }
  554. HRESULT
  555. DoOutputDisassembly(PADDR Addr, ULONG Flags,
  556. ULONG SkipLines, ULONG OutputLines,
  557. PULONG LineCount)
  558. {
  559. ULONG Lines = 0;
  560. CHAR Buffer[MAX_DISASM_LEN];
  561. PCHAR FirstLine;
  562. HRESULT Status;
  563. if (Flags & DEBUG_DISASM_MATCHING_SYMBOLS)
  564. {
  565. ULONG64 Disp;
  566. GetSymbolStdCall(Flat(*Addr), Buffer, sizeof(Buffer), &Disp, NULL);
  567. if (Disp == 0)
  568. {
  569. if (OutputLines > 0)
  570. {
  571. if (SkipLines == 0)
  572. {
  573. StartOutLine(DEBUG_OUTPUT_NORMAL, OUT_LINE_NO_TIMESTAMP);
  574. dprintf("%s:\n", Buffer);
  575. OutputLines--;
  576. }
  577. else
  578. {
  579. SkipLines--;
  580. }
  581. }
  582. Lines++;
  583. }
  584. }
  585. FirstLine = Buffer;
  586. if (!g_Machine->
  587. Disassemble(Addr, Buffer,
  588. (Flags & DEBUG_DISASM_EFFECTIVE_ADDRESS) != 0))
  589. {
  590. // Return S_FALSE if the disassembly failed.
  591. // Output will still be produced, such as "???".
  592. // Update the address to the next potential instruction
  593. // locations so that callers that are satisfied with "???"
  594. // can just iterate.
  595. g_Machine->IncrementBySmallestInstruction(Addr);
  596. Lines++;
  597. Status = S_FALSE;
  598. if (SkipLines > 0 || OutputLines == 0)
  599. {
  600. *FirstLine = 0;
  601. }
  602. }
  603. else
  604. {
  605. PSTR Nl = Buffer;
  606. PSTR LastLine = Nl;
  607. // Count lines in output and determine line positions.
  608. while (*Nl)
  609. {
  610. Nl = strchr(Nl, '\n');
  611. DBG_ASSERT(Nl != NULL);
  612. Lines++;
  613. Nl++;
  614. if (SkipLines > 0)
  615. {
  616. FirstLine = Nl;
  617. SkipLines--;
  618. }
  619. if (OutputLines > 0)
  620. {
  621. LastLine = Nl;
  622. OutputLines--;
  623. }
  624. }
  625. *LastLine = 0;
  626. Status = S_OK;
  627. }
  628. if (*FirstLine)
  629. {
  630. StartOutLine(DEBUG_OUTPUT_NORMAL, OUT_LINE_NO_TIMESTAMP);
  631. dprintf("%s", FirstLine);
  632. }
  633. if (LineCount != NULL)
  634. {
  635. *LineCount = Lines;
  636. }
  637. return Status;
  638. }
  639. #define ALL_DISASM_FLAGS \
  640. (DEBUG_DISASM_EFFECTIVE_ADDRESS | DEBUG_DISASM_MATCHING_SYMBOLS)
  641. STDMETHODIMP
  642. DebugClient::OutputDisassembly(
  643. THIS_
  644. IN ULONG OutputControl,
  645. IN ULONG64 Offset,
  646. IN ULONG Flags,
  647. OUT PULONG64 EndOffset
  648. )
  649. {
  650. if (Flags & ~ALL_DISASM_FLAGS)
  651. {
  652. return E_INVALIDARG;
  653. }
  654. HRESULT Status;
  655. ENTER_ENGINE();
  656. if (!IS_CONTEXT_ACCESSIBLE())
  657. {
  658. Status = E_UNEXPECTED;
  659. goto Exit;
  660. }
  661. OutCtlSave OldCtl;
  662. if (!PushOutCtl(OutputControl, this, &OldCtl))
  663. {
  664. Status = E_INVALIDARG;
  665. goto Exit;
  666. }
  667. ADDR Addr;
  668. // Assume this is a code segment address so that disassembly
  669. // picks up the appropriate type of address.
  670. g_Machine->FormAddr(SEGREG_CODE, Offset, FORM_SEGREG | FORM_CODE, &Addr);
  671. Status = DoOutputDisassembly(&Addr, Flags, 0, 0xffffffff, NULL);
  672. *EndOffset = Flat(Addr);
  673. PopOutCtl(&OldCtl);
  674. Exit:
  675. LEAVE_ENGINE();
  676. return Status;
  677. }
  678. ULONG
  679. BackUpDisassemblyLines(ULONG Lines, PADDR Addr, ULONG Flags, PADDR PcAddr)
  680. {
  681. //
  682. // There's no easy way to predict how many lines of
  683. // output a particular disassembly will take so
  684. // just iteratively back up by the minimum amount until
  685. // the appropriate number of lines is reached.
  686. //
  687. ADDR BackAddr = *Addr;
  688. // Limit things so that failure can be detected.
  689. // Right now X86's maximum instruction length of 16
  690. // is big enough for all platforms so use that.
  691. ADDR LimitAddr = *Addr;
  692. ULONG BackBytes = X86_MAX_INSTRUCTION_LEN * Lines;
  693. if (BackBytes > LimitAddr.off)
  694. {
  695. LimitAddr.off = 0;
  696. }
  697. else
  698. {
  699. AddrSub(&LimitAddr, BackBytes);
  700. }
  701. ADDR TryAddr;
  702. ULONG TryLines;
  703. //
  704. // Reverse disassembly is difficult on x86 due
  705. // to the variable length instructions. First
  706. // just locate the nearest symbol and disassemble
  707. // from that since this has a better chance of
  708. // producing a valid disassembly.
  709. //
  710. CHAR Buffer[MAX_DISASM_LEN];
  711. ULONG64 Disp;
  712. ADDR DisAddr, StartAddr;
  713. GetSymbolStdCall(Flat(LimitAddr), Buffer, sizeof(Buffer), &Disp, NULL);
  714. ADDRFLAT(&DisAddr, Disp);
  715. if (!AddrEqu(LimitAddr, DisAddr) &&
  716. Disp <= 16 * X86_MAX_INSTRUCTION_LEN) // valid symbol
  717. {
  718. BOOL DoOneMore = FALSE;
  719. StartAddr = LimitAddr;
  720. AddrSub(&StartAddr, Disp);
  721. TryAddr = StartAddr;
  722. TryLines = 0;
  723. while (1)
  724. {
  725. ULONG DisLines;
  726. ULONG DisFlags;
  727. while (AddrLt(TryAddr, *Addr) && ((TryLines < Lines) || DoOneMore))
  728. {
  729. UCHAR MemTest;
  730. // If we can't read memory at this address there's
  731. // no chance of getting a valid disassembly so
  732. // just stop the whole process.
  733. if (!GetMemByte(&TryAddr, &MemTest))
  734. {
  735. TryAddr = *Addr;
  736. break;
  737. }
  738. DisFlags = Flags;
  739. if (!AddrEqu(TryAddr, *PcAddr))
  740. {
  741. DisFlags &= ~DEBUG_DISASM_EFFECTIVE_ADDRESS;
  742. }
  743. DoOutputDisassembly(&TryAddr, DisFlags, 0, 0, &DisLines);
  744. TryLines += DisLines;
  745. DoOneMore = FALSE;
  746. }
  747. if (TryLines >= Lines && AddrEqu(TryAddr, *Addr))
  748. {
  749. *Addr = StartAddr;
  750. return TryLines;
  751. }
  752. else if (AddrLt(TryAddr, *Addr))
  753. {
  754. DisAddr = StartAddr;
  755. // Increase StartAddr
  756. DisFlags = Flags;
  757. if (!AddrEqu(StartAddr, *PcAddr))
  758. {
  759. DisFlags &= ~DEBUG_DISASM_EFFECTIVE_ADDRESS;
  760. }
  761. DoOutputDisassembly(&StartAddr, DisFlags, 0, 0, &DisLines);
  762. if ((DisLines == 1) || ((TryLines - DisLines) >= (Lines - 1)))
  763. {
  764. TryLines -= DisLines;
  765. }
  766. else
  767. {
  768. StartAddr = DisAddr;
  769. DoOneMore = TRUE;
  770. }
  771. }
  772. else
  773. {
  774. // couldn't find it
  775. break;
  776. }
  777. }
  778. }
  779. //
  780. // If we couldn't do something with symbols just
  781. // try a brute-force search backwards. This
  782. // has limited utility on variable-length instruction
  783. // sets but sometimes it works.
  784. //
  785. while (AddrGt(BackAddr, LimitAddr))
  786. {
  787. g_Machine->DecrementBySmallestInstruction(&BackAddr);
  788. TryAddr = BackAddr;
  789. TryLines = 0;
  790. while (AddrLt(TryAddr, *Addr))
  791. {
  792. UCHAR MemTest;
  793. // If we can't read memory at this address there's
  794. // no chance of getting a valid disassembly so
  795. // just stop the whole process.
  796. if (!GetMemByte(&TryAddr, &MemTest))
  797. {
  798. BackAddr = LimitAddr;
  799. break;
  800. }
  801. ULONG DisLines;
  802. ULONG DisFlags = Flags;
  803. if (!AddrEqu(TryAddr, *PcAddr))
  804. {
  805. DisFlags &= ~DEBUG_DISASM_EFFECTIVE_ADDRESS;
  806. }
  807. DoOutputDisassembly(&TryAddr, DisFlags, 0, 0, &DisLines);
  808. TryLines += DisLines;
  809. }
  810. if (TryLines >= Lines && AddrEqu(TryAddr, *Addr))
  811. {
  812. *Addr = BackAddr;
  813. return TryLines;
  814. }
  815. }
  816. // Couldn't find a disassembly that worked.
  817. return 0;
  818. }
  819. STDMETHODIMP
  820. DebugClient::OutputDisassemblyLines(
  821. THIS_
  822. IN ULONG OutputControl,
  823. IN ULONG PreviousLines,
  824. IN ULONG TotalLines,
  825. IN ULONG64 Offset,
  826. IN ULONG Flags,
  827. OUT OPTIONAL PULONG OffsetLine,
  828. OUT OPTIONAL PULONG64 StartOffset,
  829. OUT OPTIONAL PULONG64 EndOffset,
  830. OUT OPTIONAL /* size_is(TotalLines) */ PULONG64 LineOffsets
  831. )
  832. {
  833. if ((Flags & ~ALL_DISASM_FLAGS) ||
  834. TotalLines < 1 || PreviousLines > TotalLines)
  835. {
  836. return E_INVALIDARG;
  837. }
  838. HRESULT Status;
  839. ENTER_ENGINE();
  840. if (!IS_CONTEXT_ACCESSIBLE())
  841. {
  842. Status = E_UNEXPECTED;
  843. goto Exit;
  844. }
  845. OutCtlSave OldCtl;
  846. if (!PushOutCtl(OutputControl, this, &OldCtl))
  847. {
  848. Status = E_INVALIDARG;
  849. goto Exit;
  850. }
  851. ULONG i;
  852. if (LineOffsets != NULL)
  853. {
  854. for (i = 0; i < TotalLines; i++)
  855. {
  856. LineOffsets[i] = DEBUG_INVALID_OFFSET;
  857. }
  858. }
  859. ULONG Line, Lines, SkipLines;
  860. ADDR Addr, PcAddr;
  861. // Assume this is a code segment address so that disassembly
  862. // picks up the appropriate type of address.
  863. g_Machine->FormAddr(SEGREG_CODE, Offset, FORM_SEGREG | FORM_CODE, &Addr);
  864. g_Machine->GetPC(&PcAddr);
  865. Line = 0;
  866. SkipLines = 0;
  867. if (PreviousLines > 0)
  868. {
  869. Lines = BackUpDisassemblyLines(PreviousLines, &Addr, Flags, &PcAddr);
  870. if (Lines == 0)
  871. {
  872. dprintf("No prior disassembly possible\n");
  873. Line = 1;
  874. Lines = 1;
  875. TotalLines--;
  876. }
  877. else if (Lines > PreviousLines)
  878. {
  879. SkipLines = Lines - PreviousLines;
  880. Lines = PreviousLines;
  881. }
  882. }
  883. else
  884. {
  885. Lines = 0;
  886. }
  887. if (OffsetLine != NULL)
  888. {
  889. *OffsetLine = Lines;
  890. }
  891. if (StartOffset != NULL)
  892. {
  893. *StartOffset = Flat(Addr);
  894. }
  895. while (TotalLines > 0)
  896. {
  897. if (LineOffsets != NULL)
  898. {
  899. LineOffsets[Line] = Flat(Addr);
  900. }
  901. ULONG DisFlags = Flags;
  902. if (!AddrEqu(Addr, PcAddr))
  903. {
  904. DisFlags &= ~DEBUG_DISASM_EFFECTIVE_ADDRESS;
  905. }
  906. DoOutputDisassembly(&Addr, DisFlags, SkipLines, TotalLines, &Lines);
  907. Lines -= SkipLines;
  908. if (TotalLines <= Lines)
  909. {
  910. break;
  911. }
  912. TotalLines -= Lines;
  913. Line += Lines;
  914. SkipLines = 0;
  915. }
  916. if (EndOffset != NULL)
  917. {
  918. *EndOffset = Flat(Addr);
  919. }
  920. Status = S_OK;
  921. PopOutCtl(&OldCtl);
  922. Exit:
  923. LEAVE_ENGINE();
  924. return Status;
  925. }
  926. STDMETHODIMP
  927. DebugClient::GetNearInstruction(
  928. THIS_
  929. IN ULONG64 Offset,
  930. IN LONG Delta,
  931. OUT PULONG64 NearOffset
  932. )
  933. {
  934. HRESULT Status;
  935. ENTER_ENGINE();
  936. if (!IS_MACHINE_ACCESSIBLE())
  937. {
  938. Status = E_UNEXPECTED;
  939. goto Exit;
  940. }
  941. Status = S_OK;
  942. switch(g_EffMachine)
  943. {
  944. case IMAGE_FILE_MACHINE_ALPHA:
  945. case IMAGE_FILE_MACHINE_AXP64:
  946. // Each instruction is 32 bits.
  947. Offset += (LONG64)Delta * 4;
  948. break;
  949. case IMAGE_FILE_MACHINE_IA64:
  950. ULONG Instr;
  951. // Each 128-bit bundle has three instructions.
  952. if (Delta < 0)
  953. {
  954. while (Delta++ < 0)
  955. {
  956. Instr = (ULONG)(Offset & 0xf);
  957. if (Instr == 0)
  958. {
  959. Offset -= 8;
  960. }
  961. else
  962. {
  963. Offset -= 4;
  964. }
  965. }
  966. }
  967. else
  968. {
  969. while (Delta-- > 0)
  970. {
  971. Instr = (ULONG)(Offset & 0xf);
  972. if (Instr == 8)
  973. {
  974. Offset += 8;
  975. }
  976. else
  977. {
  978. Offset += 4;
  979. }
  980. }
  981. }
  982. break;
  983. case IMAGE_FILE_MACHINE_I386:
  984. case IMAGE_FILE_MACHINE_AMD64:
  985. ADDR Addr;
  986. CHAR Buffer[MAX_DISASM_LEN];
  987. // Instructions are highly variable. There isn't any
  988. // way to really know whether a particular disassembly
  989. // of a stretch of code is valid or not, so this
  990. // routine is inherently fragile.
  991. g_Machine->FormAddr(SEGREG_CODE, Offset,
  992. FORM_SEGREG | FORM_CODE, &Addr);
  993. if (Delta < 0)
  994. {
  995. // Back up byte-by-byte and disassemble. If the
  996. // post-disassembly offset matches the current offset,
  997. // a good-enough instruction sequence has been found.
  998. for (;;)
  999. {
  1000. ADDR TryAddr;
  1001. LONG TryDelta;
  1002. AddrSub(&Addr, 1);
  1003. TryAddr = Addr;
  1004. TryDelta = 0;
  1005. while (Flat(TryAddr) < Offset)
  1006. {
  1007. if (!g_Machine->Disassemble(&TryAddr, Buffer, FALSE))
  1008. {
  1009. break;
  1010. }
  1011. TryDelta--;
  1012. }
  1013. if (Flat(TryAddr) == Offset &&
  1014. TryDelta == Delta)
  1015. {
  1016. break;
  1017. }
  1018. // Limit things just as a precaution.
  1019. if (Flat(Addr) < Offset + Delta * X86_MAX_INSTRUCTION_LEN)
  1020. {
  1021. Status = E_FAIL;
  1022. break;
  1023. }
  1024. }
  1025. }
  1026. else
  1027. {
  1028. while (Delta-- > 0)
  1029. {
  1030. if (!g_Machine->Disassemble(&Addr, Buffer, FALSE))
  1031. {
  1032. Status = E_FAIL;
  1033. break;
  1034. }
  1035. }
  1036. }
  1037. Offset = Flat(Addr);
  1038. break;
  1039. default:
  1040. Status = E_UNEXPECTED;
  1041. break;
  1042. }
  1043. if (SUCCEEDED(Status))
  1044. {
  1045. *NearOffset = Offset;
  1046. }
  1047. Exit:
  1048. LEAVE_ENGINE();
  1049. return Status;
  1050. }
  1051. STDMETHODIMP
  1052. DebugClient::GetStackTrace(
  1053. THIS_
  1054. IN ULONG64 FrameOffset,
  1055. IN ULONG64 StackOffset,
  1056. IN ULONG64 InstructionOffset,
  1057. OUT PDEBUG_STACK_FRAME Frames,
  1058. IN ULONG FramesSize,
  1059. OUT OPTIONAL PULONG FramesFilled
  1060. )
  1061. {
  1062. HRESULT Status;
  1063. ENTER_ENGINE();
  1064. if (!IS_CONTEXT_ACCESSIBLE())
  1065. {
  1066. Status = E_UNEXPECTED;
  1067. goto Exit;
  1068. }
  1069. ULONG FramesRet;
  1070. ULONG64 ThreadData;
  1071. if (g_ExtThread != 0)
  1072. {
  1073. ThreadData = g_ExtThread;
  1074. g_ExtThread = 0;
  1075. }
  1076. else
  1077. {
  1078. ThreadData = 0;
  1079. }
  1080. FramesRet = StackTrace(FrameOffset, StackOffset, InstructionOffset,
  1081. Frames, FramesSize, ThreadData, 0, FALSE);
  1082. if (FramesRet > 0)
  1083. {
  1084. Status = S_OK;
  1085. if (FramesFilled != NULL)
  1086. {
  1087. *FramesFilled = FramesRet;
  1088. }
  1089. }
  1090. else
  1091. {
  1092. Status = E_FAIL;
  1093. }
  1094. if (g_ExtThreadScopeSaved)
  1095. {
  1096. PopScope(&g_ExtThreadSavedScope);
  1097. g_ExtThreadScopeSaved = FALSE;
  1098. }
  1099. Exit:
  1100. LEAVE_ENGINE();
  1101. return Status;
  1102. }
  1103. STDMETHODIMP
  1104. DebugClient::GetReturnOffset(
  1105. THIS_
  1106. OUT PULONG64 Offset
  1107. )
  1108. {
  1109. HRESULT Status;
  1110. ENTER_ENGINE();
  1111. if (!IS_CONTEXT_ACCESSIBLE())
  1112. {
  1113. Status = E_UNEXPECTED;
  1114. }
  1115. else
  1116. {
  1117. ADDR Addr;
  1118. g_Machine->GetRetAddr(&Addr);
  1119. *Offset = Flat(Addr);
  1120. Status = S_OK;
  1121. }
  1122. LEAVE_ENGINE();
  1123. return Status;
  1124. }
  1125. STDMETHODIMP
  1126. DebugClient::OutputStackTrace(
  1127. THIS_
  1128. IN ULONG OutputControl,
  1129. IN PDEBUG_STACK_FRAME Frames,
  1130. IN ULONG FramesSize,
  1131. IN ULONG Flags
  1132. )
  1133. {
  1134. if (Flags & ~(DEBUG_STACK_ARGUMENTS |
  1135. DEBUG_STACK_FUNCTION_INFO |
  1136. DEBUG_STACK_SOURCE_LINE |
  1137. DEBUG_STACK_FRAME_ADDRESSES |
  1138. DEBUG_STACK_COLUMN_NAMES |
  1139. DEBUG_STACK_NONVOLATILE_REGISTERS |
  1140. DEBUG_STACK_FRAME_NUMBERS |
  1141. DEBUG_STACK_PARAMETERS |
  1142. DEBUG_STACK_FRAME_ADDRESSES_RA_ONLY))
  1143. {
  1144. return E_INVALIDARG;
  1145. }
  1146. HRESULT Status;
  1147. ENTER_ENGINE();
  1148. if (!IS_CONTEXT_ACCESSIBLE())
  1149. {
  1150. Status = E_UNEXPECTED;
  1151. goto Exit;
  1152. }
  1153. OutCtlSave OldCtl;
  1154. if (!PushOutCtl(OutputControl, this, &OldCtl))
  1155. {
  1156. Status = E_INVALIDARG;
  1157. goto Exit;
  1158. }
  1159. // Currently only IA64 supports nonvolatile register output.
  1160. if (g_EffMachine != IMAGE_FILE_MACHINE_IA64)
  1161. {
  1162. Flags &= ~DEBUG_STACK_NONVOLATILE_REGISTERS;
  1163. }
  1164. PDEBUG_STACK_FRAME LocalFrames;
  1165. LocalFrames = NULL;
  1166. if (Frames == NULL)
  1167. {
  1168. ULONG FramesFilled;
  1169. ULONG64 ThreadData;
  1170. if (g_ExtThread != 0)
  1171. {
  1172. ThreadData = g_ExtThread;
  1173. g_ExtThread = 0;
  1174. }
  1175. else
  1176. {
  1177. ThreadData = 0;
  1178. }
  1179. LocalFrames = new DEBUG_STACK_FRAME[FramesSize];
  1180. if (LocalFrames == NULL)
  1181. {
  1182. ErrOut("Unable to allocate memory for stack trace\n");
  1183. Status = E_OUTOFMEMORY;
  1184. goto PopExit;
  1185. }
  1186. //
  1187. // StackTrace will generate output if any flags are
  1188. // passed in. The only time we really require that
  1189. // it produce output is when nonvolatile registers
  1190. // are requested as they can only be displayed when
  1191. // the context is available during stack walking.
  1192. // In order to simplify later logic, we only
  1193. // pass flags if we have the nonvolatile register flag.
  1194. //
  1195. FramesFilled = StackTrace(0, 0, 0,
  1196. LocalFrames, FramesSize, ThreadData,
  1197. (Flags & DEBUG_STACK_NONVOLATILE_REGISTERS) ?
  1198. Flags : 0, FALSE);
  1199. if (FramesFilled == 0)
  1200. {
  1201. delete [] LocalFrames;
  1202. goto PopExit;
  1203. }
  1204. Frames = LocalFrames;
  1205. FramesSize = FramesFilled;
  1206. }
  1207. else if (Flags & DEBUG_STACK_NONVOLATILE_REGISTERS)
  1208. {
  1209. // Can't dump nonvolatile registers without a full
  1210. // context so this is not an allowable options.
  1211. Status = E_INVALIDARG;
  1212. goto PopExit;
  1213. }
  1214. if (!(Flags & DEBUG_STACK_NONVOLATILE_REGISTERS))
  1215. {
  1216. PrintStackTrace(FramesSize, Frames, Flags);
  1217. }
  1218. Status = S_OK;
  1219. delete [] LocalFrames;
  1220. if (g_ExtThreadScopeSaved)
  1221. {
  1222. PopScope(&g_ExtThreadSavedScope);
  1223. g_ExtThreadScopeSaved = FALSE;
  1224. }
  1225. PopExit:
  1226. PopOutCtl(&OldCtl);
  1227. Exit:
  1228. LEAVE_ENGINE();
  1229. return Status;
  1230. }
  1231. STDMETHODIMP
  1232. DebugClient::GetDebuggeeType(
  1233. THIS_
  1234. OUT PULONG Class,
  1235. OUT PULONG Qualifier
  1236. )
  1237. {
  1238. ENTER_ENGINE();
  1239. *Class = g_TargetClass;
  1240. *Qualifier = g_TargetClassQualifier;
  1241. LEAVE_ENGINE();
  1242. return S_OK;
  1243. }
  1244. STDMETHODIMP
  1245. DebugClient::GetActualProcessorType(
  1246. THIS_
  1247. OUT PULONG Type
  1248. )
  1249. {
  1250. ENTER_ENGINE();
  1251. *Type = g_TargetMachineType;
  1252. LEAVE_ENGINE();
  1253. return S_OK;
  1254. }
  1255. STDMETHODIMP
  1256. DebugClient::GetExecutingProcessorType(
  1257. THIS_
  1258. OUT PULONG Type
  1259. )
  1260. {
  1261. ENTER_ENGINE();
  1262. *Type = g_TargetExecMachine;
  1263. LEAVE_ENGINE();
  1264. return S_OK;
  1265. }
  1266. STDMETHODIMP
  1267. DebugClient::GetNumberPossibleExecutingProcessorTypes(
  1268. THIS_
  1269. OUT PULONG Number
  1270. )
  1271. {
  1272. HRESULT Status;
  1273. ENTER_ENGINE();
  1274. if (!IS_MACHINE_SET())
  1275. {
  1276. Status = E_UNEXPECTED;
  1277. }
  1278. else
  1279. {
  1280. MachineInfo* Machine = MachineTypeInfo(g_TargetMachineType);
  1281. if (Machine == NULL)
  1282. {
  1283. Status = E_INVALIDARG;
  1284. }
  1285. else
  1286. {
  1287. *Number = Machine->m_NumExecTypes;
  1288. Status = S_OK;
  1289. }
  1290. }
  1291. LEAVE_ENGINE();
  1292. return Status;
  1293. }
  1294. STDMETHODIMP
  1295. DebugClient::GetPossibleExecutingProcessorTypes(
  1296. THIS_
  1297. IN ULONG Start,
  1298. IN ULONG Count,
  1299. OUT PULONG Types
  1300. )
  1301. {
  1302. HRESULT Status;
  1303. ENTER_ENGINE();
  1304. if (!IS_MACHINE_SET())
  1305. {
  1306. Status = E_UNEXPECTED;
  1307. }
  1308. else
  1309. {
  1310. MachineInfo* Machine = MachineTypeInfo(g_TargetMachineType);
  1311. if (Machine == NULL ||
  1312. Start >= Machine->m_NumExecTypes ||
  1313. Start + Count > Machine->m_NumExecTypes)
  1314. {
  1315. Status = E_INVALIDARG;
  1316. }
  1317. else
  1318. {
  1319. Status = S_OK;
  1320. while (Count-- > 0)
  1321. {
  1322. *Types++ = Machine->m_ExecTypes[Start++];
  1323. }
  1324. }
  1325. }
  1326. LEAVE_ENGINE();
  1327. return Status;
  1328. }
  1329. STDMETHODIMP
  1330. DebugClient::GetNumberProcessors(
  1331. THIS_
  1332. OUT PULONG Number
  1333. )
  1334. {
  1335. ENTER_ENGINE();
  1336. *Number = g_TargetNumberProcessors;
  1337. LEAVE_ENGINE();
  1338. return S_OK;
  1339. }
  1340. STDMETHODIMP
  1341. DebugClient::GetSystemVersion(
  1342. THIS_
  1343. OUT PULONG PlatformId,
  1344. OUT PULONG Major,
  1345. OUT PULONG Minor,
  1346. OUT OPTIONAL PSTR ServicePackString,
  1347. IN ULONG ServicePackStringSize,
  1348. OUT OPTIONAL PULONG ServicePackStringUsed,
  1349. OUT PULONG ServicePackNumber,
  1350. OUT OPTIONAL PSTR BuildString,
  1351. IN ULONG BuildStringSize,
  1352. OUT OPTIONAL PULONG BuildStringUsed
  1353. )
  1354. {
  1355. HRESULT Status;
  1356. ENTER_ENGINE();
  1357. // This is insufficient to distinguish
  1358. // the various system types supported but we don't
  1359. // want to publish identifiers for every possible
  1360. // system version family. PlatformId is as good
  1361. // as it gets.
  1362. *PlatformId = g_TargetPlatformId;
  1363. *Major = g_TargetCheckedBuild;
  1364. *Minor = g_TargetBuildNumber;
  1365. Status = FillStringBuffer(g_TargetServicePackString, 0,
  1366. ServicePackString, ServicePackStringSize,
  1367. ServicePackStringUsed);
  1368. *ServicePackNumber = g_TargetServicePackNumber;
  1369. if (FillStringBuffer(g_TargetBuildLabName, 0,
  1370. BuildString, BuildStringSize,
  1371. BuildStringUsed) == S_FALSE)
  1372. {
  1373. Status = S_FALSE;
  1374. }
  1375. LEAVE_ENGINE();
  1376. return Status;
  1377. }
  1378. STDMETHODIMP
  1379. DebugClient::GetPageSize(
  1380. THIS_
  1381. OUT PULONG Size
  1382. )
  1383. {
  1384. HRESULT Status;
  1385. ENTER_ENGINE();
  1386. if (!IS_MACHINE_SET())
  1387. {
  1388. Status = E_UNEXPECTED;
  1389. }
  1390. else
  1391. {
  1392. *Size = g_Machine->m_PageSize;
  1393. Status = S_OK;
  1394. }
  1395. LEAVE_ENGINE();
  1396. return Status;
  1397. }
  1398. STDMETHODIMP
  1399. DebugClient::IsPointer64Bit(
  1400. THIS
  1401. )
  1402. {
  1403. HRESULT Status;
  1404. ENTER_ENGINE();
  1405. if (!IS_MACHINE_SET())
  1406. {
  1407. Status = E_UNEXPECTED;
  1408. }
  1409. else
  1410. {
  1411. Status = g_Machine->m_Ptr64 ? S_OK : S_FALSE;
  1412. }
  1413. LEAVE_ENGINE();
  1414. return Status;
  1415. }
  1416. STDMETHODIMP
  1417. DebugClient::ReadBugCheckData(
  1418. THIS_
  1419. OUT PULONG Code,
  1420. OUT PULONG64 Arg1,
  1421. OUT PULONG64 Arg2,
  1422. OUT PULONG64 Arg3,
  1423. OUT PULONG64 Arg4
  1424. )
  1425. {
  1426. HRESULT Status;
  1427. ENTER_ENGINE();
  1428. if (!IS_KERNEL_TARGET())
  1429. {
  1430. Status = E_UNEXPECTED;
  1431. }
  1432. else
  1433. {
  1434. ULONG64 Args[4];
  1435. Status = g_Target->ReadBugCheckData(Code, Args);
  1436. if (Status == S_OK)
  1437. {
  1438. *Arg1 = Args[0];
  1439. *Arg2 = Args[1];
  1440. *Arg3 = Args[2];
  1441. *Arg4 = Args[3];
  1442. }
  1443. }
  1444. LEAVE_ENGINE();
  1445. return Status;
  1446. }
  1447. STDMETHODIMP
  1448. DebugClient::GetNumberSupportedProcessorTypes(
  1449. THIS_
  1450. OUT PULONG Number
  1451. )
  1452. {
  1453. ENTER_ENGINE();
  1454. *Number = MACHIDX_COUNT;
  1455. LEAVE_ENGINE();
  1456. return S_OK;
  1457. }
  1458. STDMETHODIMP
  1459. DebugClient::GetSupportedProcessorTypes(
  1460. THIS_
  1461. IN ULONG Start,
  1462. IN ULONG Count,
  1463. OUT PULONG Types
  1464. )
  1465. {
  1466. if (Start >= MACHIDX_COUNT ||
  1467. Start + Count > MACHIDX_COUNT)
  1468. {
  1469. return E_INVALIDARG;
  1470. }
  1471. ENTER_ENGINE();
  1472. if (Count > 0)
  1473. {
  1474. while (Count-- > 0)
  1475. {
  1476. // First ExecTypes entry is the actual processor
  1477. // type so it's a convenient place to turn an
  1478. // index into a type.
  1479. *Types++ = g_AllMachines[Start++]->m_ExecTypes[0];
  1480. }
  1481. }
  1482. LEAVE_ENGINE();
  1483. return S_OK;
  1484. }
  1485. STDMETHODIMP
  1486. DebugClient::GetProcessorTypeNames(
  1487. THIS_
  1488. IN ULONG Type,
  1489. OUT OPTIONAL PSTR FullNameBuffer,
  1490. IN ULONG FullNameBufferSize,
  1491. OUT OPTIONAL PULONG FullNameSize,
  1492. OUT OPTIONAL PSTR AbbrevNameBuffer,
  1493. IN ULONG AbbrevNameBufferSize,
  1494. OUT OPTIONAL PULONG AbbrevNameSize
  1495. )
  1496. {
  1497. MachineInfo* Machine = MachineTypeInfo(Type);
  1498. if (Machine == NULL)
  1499. {
  1500. return E_INVALIDARG;
  1501. }
  1502. HRESULT Status;
  1503. ENTER_ENGINE();
  1504. Status = FillStringBuffer(Machine->m_FullName, 0,
  1505. FullNameBuffer, FullNameBufferSize,
  1506. FullNameSize);
  1507. if (FillStringBuffer(Machine->m_AbbrevName, 0,
  1508. AbbrevNameBuffer, AbbrevNameBufferSize,
  1509. AbbrevNameSize) == S_FALSE)
  1510. {
  1511. Status = S_FALSE;
  1512. }
  1513. LEAVE_ENGINE();
  1514. return Status;
  1515. }
  1516. STDMETHODIMP
  1517. DebugClient::GetEffectiveProcessorType(
  1518. THIS_
  1519. OUT PULONG Type
  1520. )
  1521. {
  1522. ENTER_ENGINE();
  1523. *Type = g_EffMachine;
  1524. LEAVE_ENGINE();
  1525. return S_OK;
  1526. }
  1527. STDMETHODIMP
  1528. DebugClient::SetEffectiveProcessorType(
  1529. THIS_
  1530. IN ULONG Type
  1531. )
  1532. {
  1533. MachineIndex Index = MachineTypeIndex(Type);
  1534. if (Index == MACHIDX_COUNT)
  1535. {
  1536. return E_INVALIDARG;
  1537. }
  1538. HRESULT Status;
  1539. ENTER_ENGINE();
  1540. if (!IS_TARGET_SET())
  1541. {
  1542. Status = E_UNEXPECTED;
  1543. }
  1544. else
  1545. {
  1546. SetEffMachine(Type, TRUE);
  1547. Status = S_OK;
  1548. }
  1549. LEAVE_ENGINE();
  1550. return Status;
  1551. }
  1552. ULONG
  1553. GetExecutionStatus(void)
  1554. {
  1555. if (!IS_MACHINE_SET() ||
  1556. (g_EngStatus & ENG_STATUS_STOP_SESSION) ||
  1557. g_ProcessHead == NULL)
  1558. {
  1559. return DEBUG_STATUS_NO_DEBUGGEE;
  1560. }
  1561. else if (g_CmdState == 'p')
  1562. {
  1563. return DEBUG_STATUS_STEP_OVER;
  1564. }
  1565. else if (g_CmdState == 't')
  1566. {
  1567. return DEBUG_STATUS_STEP_INTO;
  1568. }
  1569. else if (g_CmdState == 'b')
  1570. {
  1571. return DEBUG_STATUS_STEP_BRANCH;
  1572. }
  1573. else if (g_CmdState == 'g')
  1574. {
  1575. return DEBUG_STATUS_GO;
  1576. }
  1577. else
  1578. {
  1579. return DEBUG_STATUS_BREAK;
  1580. }
  1581. }
  1582. STDMETHODIMP
  1583. DebugClient::GetExecutionStatus(
  1584. THIS_
  1585. OUT PULONG Status
  1586. )
  1587. {
  1588. // This method is reentrant.
  1589. *Status = ::GetExecutionStatus();
  1590. return S_OK;
  1591. }
  1592. HRESULT
  1593. SetExecutionStatus(ULONG Status)
  1594. {
  1595. HRESULT Result = S_OK;
  1596. ENTER_ENGINE();
  1597. if (IS_RUNNING(g_CmdState))
  1598. {
  1599. // Already running.
  1600. goto Exit;
  1601. }
  1602. ADDR PcAddr;
  1603. g_Machine->GetPC(&PcAddr);
  1604. // Notifications are sent in the step/go functions.
  1605. if (Status >= DEBUG_STATUS_GO &&
  1606. Status <= DEBUG_STATUS_GO_NOT_HANDLED)
  1607. {
  1608. fnGoExecution(Status, &PcAddr, 0, NULL, FALSE, NULL);
  1609. }
  1610. else
  1611. {
  1612. DBG_ASSERT(Status == DEBUG_STATUS_STEP_OVER ||
  1613. Status == DEBUG_STATUS_STEP_INTO ||
  1614. Status == DEBUG_STATUS_STEP_BRANCH);
  1615. if (g_Machine->IsStepStatusSupported(Status))
  1616. {
  1617. char cmd;
  1618. switch (Status)
  1619. {
  1620. case DEBUG_STATUS_STEP_INTO:
  1621. cmd = 't';
  1622. break;
  1623. case DEBUG_STATUS_STEP_OVER:
  1624. cmd = 'p';
  1625. break;
  1626. case DEBUG_STATUS_STEP_BRANCH:
  1627. cmd = 'b';
  1628. break;
  1629. }
  1630. fnStepTrace(&PcAddr, 1, NULL, FALSE, cmd);
  1631. }
  1632. else
  1633. {
  1634. char* Mode;
  1635. switch (Status)
  1636. {
  1637. case DEBUG_STATUS_STEP_BRANCH:
  1638. Mode = "Taken branch trace";
  1639. break;
  1640. default:
  1641. Mode = "Trace";
  1642. break;
  1643. }
  1644. ErrOut("%s mode not supported\n", Mode);
  1645. Result = E_INVALIDARG;
  1646. }
  1647. }
  1648. Exit:
  1649. LEAVE_ENGINE();
  1650. return Result;
  1651. }
  1652. STDMETHODIMP
  1653. DebugClient::SetExecutionStatus(
  1654. THIS_
  1655. IN ULONG Status
  1656. )
  1657. {
  1658. if ((Status <= DEBUG_STATUS_NO_CHANGE || Status >= DEBUG_STATUS_BREAK) &&
  1659. Status != DEBUG_STATUS_STEP_BRANCH)
  1660. {
  1661. return E_INVALIDARG;
  1662. }
  1663. HRESULT RetStatus;
  1664. ENTER_ENGINE();
  1665. if (!IS_MACHINE_SET())
  1666. {
  1667. RetStatus = E_UNEXPECTED;
  1668. }
  1669. else
  1670. {
  1671. RetStatus = ::SetExecutionStatus(Status);
  1672. }
  1673. LEAVE_ENGINE();
  1674. return RetStatus;
  1675. }
  1676. STDMETHODIMP
  1677. DebugClient::GetCodeLevel(
  1678. THIS_
  1679. OUT PULONG Level
  1680. )
  1681. {
  1682. ENTER_ENGINE();
  1683. if (g_SrcOptions & SRCOPT_STEP_SOURCE)
  1684. {
  1685. *Level = DEBUG_LEVEL_SOURCE;
  1686. }
  1687. else
  1688. {
  1689. *Level = DEBUG_LEVEL_ASSEMBLY;
  1690. }
  1691. LEAVE_ENGINE();
  1692. return S_OK;
  1693. }
  1694. STDMETHODIMP
  1695. DebugClient::SetCodeLevel(
  1696. THIS_
  1697. IN ULONG Level
  1698. )
  1699. {
  1700. ENTER_ENGINE();
  1701. HRESULT Status = S_OK;
  1702. ULONG OldSrcOpt = g_SrcOptions;
  1703. switch(Level)
  1704. {
  1705. case DEBUG_LEVEL_ASSEMBLY:
  1706. g_SrcOptions &= ~SRCOPT_STEP_SOURCE;
  1707. break;
  1708. case DEBUG_LEVEL_SOURCE:
  1709. g_SrcOptions |= SRCOPT_STEP_SOURCE;
  1710. break;
  1711. default:
  1712. Status = E_INVALIDARG;
  1713. break;
  1714. }
  1715. if ((OldSrcOpt ^ g_SrcOptions) & SRCOPT_STEP_SOURCE)
  1716. {
  1717. NotifyChangeEngineState(DEBUG_CES_CODE_LEVEL,
  1718. (g_SrcOptions & SRCOPT_STEP_SOURCE) ?
  1719. DEBUG_LEVEL_SOURCE : DEBUG_LEVEL_ASSEMBLY,
  1720. TRUE);
  1721. }
  1722. LEAVE_ENGINE();
  1723. return Status;
  1724. }
  1725. STDMETHODIMP
  1726. DebugClient::GetEngineOptions(
  1727. THIS_
  1728. OUT PULONG Options
  1729. )
  1730. {
  1731. // This method is reentrant.
  1732. *Options = g_EngOptions;
  1733. return S_OK;
  1734. }
  1735. HRESULT
  1736. SetEngOptions(ULONG Options)
  1737. {
  1738. if (g_EngOptions != Options)
  1739. {
  1740. // Make sure allow and disallow network paths aren't both on.
  1741. if ((Options & ~DEBUG_ENGOPT_ALL) ||
  1742. ((Options & DEBUG_ENGOPT_NETWORK_PATHS) ==
  1743. DEBUG_ENGOPT_NETWORK_PATHS))
  1744. {
  1745. return E_INVALIDARG;
  1746. }
  1747. g_EngOptions = Options;
  1748. ULONG Notify = DEBUG_CES_ENGINE_OPTIONS;
  1749. ULONG64 Arg = Options;
  1750. if (SyncFiltersWithOptions())
  1751. {
  1752. Notify |= DEBUG_CES_EVENT_FILTERS;
  1753. Arg = DEBUG_ANY_ID;
  1754. }
  1755. // XXX drewb - Notification without any lock.
  1756. NotifyChangeEngineState(Notify, Arg, FALSE);
  1757. }
  1758. return S_OK;
  1759. }
  1760. STDMETHODIMP
  1761. DebugClient::AddEngineOptions(
  1762. THIS_
  1763. IN ULONG Options
  1764. )
  1765. {
  1766. // This method is reentrant.
  1767. return SetEngOptions(g_EngOptions | Options);
  1768. }
  1769. STDMETHODIMP
  1770. DebugClient::RemoveEngineOptions(
  1771. THIS_
  1772. IN ULONG Options
  1773. )
  1774. {
  1775. // This method is reentrant.
  1776. return SetEngOptions(g_EngOptions & ~Options);
  1777. }
  1778. STDMETHODIMP
  1779. DebugClient::SetEngineOptions(
  1780. THIS_
  1781. IN ULONG Options
  1782. )
  1783. {
  1784. // This method is reentrant.
  1785. return SetEngOptions(Options);
  1786. }
  1787. STDMETHODIMP
  1788. DebugClient::GetSystemErrorControl(
  1789. THIS_
  1790. OUT PULONG OutputLevel,
  1791. OUT PULONG BreakLevel
  1792. )
  1793. {
  1794. ENTER_ENGINE();
  1795. *OutputLevel = g_SystemErrorOutput;
  1796. *BreakLevel = g_SystemErrorBreak;
  1797. LEAVE_ENGINE();
  1798. return S_OK;
  1799. }
  1800. STDMETHODIMP
  1801. DebugClient::SetSystemErrorControl(
  1802. THIS_
  1803. IN ULONG OutputLevel,
  1804. IN ULONG BreakLevel
  1805. )
  1806. {
  1807. if (OutputLevel > SLE_WARNING ||
  1808. BreakLevel > SLE_WARNING)
  1809. {
  1810. return E_INVALIDARG;
  1811. }
  1812. ENTER_ENGINE();
  1813. g_SystemErrorOutput = OutputLevel;
  1814. g_SystemErrorBreak = BreakLevel;
  1815. LEAVE_ENGINE();
  1816. return S_OK;
  1817. }
  1818. STDMETHODIMP
  1819. DebugClient::GetTextMacro(
  1820. THIS_
  1821. IN ULONG Slot,
  1822. OUT OPTIONAL PSTR Buffer,
  1823. IN ULONG BufferSize,
  1824. OUT OPTIONAL PULONG MacroSize
  1825. )
  1826. {
  1827. if (Slot >= REG_USER_COUNT)
  1828. {
  1829. return E_INVALIDARG;
  1830. }
  1831. HRESULT Status;
  1832. ENTER_ENGINE();
  1833. Status = FillStringBuffer(GetUserReg(REG_USER_FIRST + Slot), 0,
  1834. Buffer, BufferSize, MacroSize);
  1835. LEAVE_ENGINE();
  1836. return Status;
  1837. }
  1838. STDMETHODIMP
  1839. DebugClient::SetTextMacro(
  1840. THIS_
  1841. IN ULONG Slot,
  1842. IN PCSTR Macro
  1843. )
  1844. {
  1845. if (Slot >= REG_USER_COUNT)
  1846. {
  1847. return E_INVALIDARG;
  1848. }
  1849. HRESULT Status;
  1850. ENTER_ENGINE();
  1851. Status = SetUserReg(REG_USER_FIRST + Slot, Macro) ? S_OK : E_OUTOFMEMORY;
  1852. LEAVE_ENGINE();
  1853. return Status;
  1854. }
  1855. STDMETHODIMP
  1856. DebugClient::GetRadix(
  1857. THIS_
  1858. OUT PULONG Radix
  1859. )
  1860. {
  1861. ENTER_ENGINE();
  1862. *Radix = g_DefaultRadix;
  1863. LEAVE_ENGINE();
  1864. return S_OK;
  1865. }
  1866. STDMETHODIMP
  1867. DebugClient::SetRadix(
  1868. THIS_
  1869. IN ULONG Radix
  1870. )
  1871. {
  1872. if (Radix != 8 && Radix != 10 && Radix != 16)
  1873. {
  1874. return E_INVALIDARG;
  1875. }
  1876. ENTER_ENGINE();
  1877. g_DefaultRadix = Radix;
  1878. NotifyChangeEngineState(DEBUG_CES_RADIX, g_DefaultRadix, TRUE);
  1879. LEAVE_ENGINE();
  1880. return S_OK;
  1881. }
  1882. STDMETHODIMP
  1883. DebugClient::Evaluate(
  1884. THIS_
  1885. IN PCSTR Expression,
  1886. IN ULONG DesiredType,
  1887. OUT PDEBUG_VALUE Value,
  1888. OUT OPTIONAL PULONG RemainderIndex
  1889. )
  1890. {
  1891. char Copy[MAX_COMMAND];
  1892. if (Expression == NULL ||
  1893. strlen(Expression) >= sizeof(Copy))
  1894. {
  1895. return E_INVALIDARG;
  1896. }
  1897. HRESULT Status;
  1898. ENTER_ENGINE();
  1899. if (!IS_MACHINE_ACCESSIBLE())
  1900. {
  1901. Status = E_UNEXPECTED;
  1902. goto Exit;
  1903. }
  1904. PSTR SaveCommand;
  1905. PSTR SaveStart;
  1906. // This Evaluate may be coming from an extension invoked
  1907. // from a command so save all command state.
  1908. SaveCommand = g_CurCmd;
  1909. SaveStart = g_CommandStart;
  1910. g_DisableErrorPrint = TRUE;
  1911. // Copy const string to buffer to avoid read-only memory
  1912. // AVs as the command is modified during parsing.
  1913. strcpy(Copy, Expression);
  1914. g_CurCmd = Copy;
  1915. g_CommandStart = Copy;
  1916. RemoveDelChar(g_CurCmd);
  1917. ExpandUserRegs(Copy);
  1918. __try
  1919. {
  1920. Value->I64 = GetExpression();
  1921. Value->Type = DEBUG_VALUE_INT64;
  1922. if (RemainderIndex != NULL)
  1923. {
  1924. *RemainderIndex = (ULONG)(g_CurCmd - g_CommandStart);
  1925. }
  1926. if (DesiredType != DEBUG_VALUE_INVALID &&
  1927. DesiredType != Value->Type)
  1928. {
  1929. DEBUG_VALUE Natural = *Value;
  1930. Status = CoerceValue(&Natural, DesiredType, Value);
  1931. }
  1932. else
  1933. {
  1934. Status = S_OK;
  1935. }
  1936. }
  1937. __except(CommandExceptionFilter(GetExceptionInformation()))
  1938. {
  1939. Status = E_FAIL;
  1940. }
  1941. g_DisableErrorPrint = FALSE;
  1942. g_CurCmd = SaveCommand;
  1943. g_CommandStart = SaveStart;
  1944. Exit:
  1945. LEAVE_ENGINE();
  1946. return Status;
  1947. }
  1948. #define IS_INT(Type) \
  1949. ((Type) >= DEBUG_VALUE_INT8 && (Type) <= DEBUG_VALUE_INT64)
  1950. #define IS_FLOAT(Type) \
  1951. ((Type) >= DEBUG_VALUE_FLOAT32 && (Type) <= DEBUG_VALUE_FLOAT128)
  1952. #define IS_VECTOR(Type) \
  1953. ((Type) >= DEBUG_VALUE_VECTOR64 && (Type) <= DEBUG_VALUE_VECTOR128)
  1954. STDMETHODIMP
  1955. DebugClient::CoerceValue(
  1956. THIS_
  1957. IN PDEBUG_VALUE In,
  1958. IN ULONG OutType,
  1959. OUT PDEBUG_VALUE Out
  1960. )
  1961. {
  1962. if (In->Type < DEBUG_VALUE_INT8 || In->Type >= DEBUG_VALUE_TYPES ||
  1963. OutType < DEBUG_VALUE_INT8 || OutType >= DEBUG_VALUE_TYPES)
  1964. {
  1965. return E_INVALIDARG;
  1966. }
  1967. if (In->Type == OutType)
  1968. {
  1969. *Out = *In;
  1970. return S_OK;
  1971. }
  1972. ENTER_ENGINE();
  1973. ZeroMemory(Out, sizeof(*Out));
  1974. Out->Type = OutType;
  1975. DEBUG_VALUE Inter;
  1976. char FloatStr[64];
  1977. ZeroMemory(&Inter, sizeof(Inter));
  1978. // Convert the input type to the largest
  1979. // matching type for intermediate operations.
  1980. switch(In->Type)
  1981. {
  1982. case DEBUG_VALUE_INT8:
  1983. Inter.I64 = In->I8;
  1984. Inter.Nat = FALSE;
  1985. break;
  1986. case DEBUG_VALUE_INT16:
  1987. Inter.I64 = In->I16;
  1988. Inter.Nat = FALSE;
  1989. break;
  1990. case DEBUG_VALUE_INT32:
  1991. Inter.I64 = In->I32;
  1992. Inter.Nat = FALSE;
  1993. break;
  1994. case DEBUG_VALUE_INT64:
  1995. Inter.I64 = In->I64;
  1996. Inter.Nat = In->Nat;
  1997. break;
  1998. case DEBUG_VALUE_FLOAT32:
  1999. // XXX drewb - Use direct conversion.
  2000. sprintf(FloatStr, "%10g", In->F32);
  2001. _atoldbl((_ULDOUBLE*)Inter.RawBytes, FloatStr);
  2002. break;
  2003. case DEBUG_VALUE_FLOAT64:
  2004. // XXX drewb - Use direct conversion.
  2005. sprintf(FloatStr, "%10lg", In->F64);
  2006. _atoldbl((_ULDOUBLE*)Inter.RawBytes, FloatStr);
  2007. break;
  2008. case DEBUG_VALUE_FLOAT80:
  2009. memcpy(Inter.RawBytes, In->F80Bytes, sizeof(In->F80Bytes));
  2010. break;
  2011. case DEBUG_VALUE_FLOAT82:
  2012. FLOAT128 f82;
  2013. memcpy(&f82, &(In->F82Bytes),
  2014. min(sizeof(f82), sizeof(In->F82Bytes)));
  2015. double f;
  2016. f = Float82ToDouble(&f82);
  2017. sprintf(FloatStr, "%10g", f);
  2018. _atoldbl((_ULDOUBLE*)Inter.RawBytes, FloatStr);
  2019. break;
  2020. case DEBUG_VALUE_FLOAT128:
  2021. // XXX drewb - What's the format? How should this be supported.
  2022. memcpy(Inter.RawBytes, In->F128Bytes, sizeof(In->F128Bytes));
  2023. break;
  2024. case DEBUG_VALUE_VECTOR64:
  2025. memcpy(Inter.RawBytes, In->RawBytes, 8);
  2026. break;
  2027. case DEBUG_VALUE_VECTOR128:
  2028. memcpy(Inter.RawBytes, In->RawBytes, 16);
  2029. break;
  2030. default:
  2031. DBG_ASSERT(FALSE);
  2032. break;
  2033. }
  2034. // Convert between float, int and vector. There's
  2035. // no way to know what kind of data is in a vector
  2036. // so the raw bytes are just used directly.
  2037. if (IS_INT(In->Type) &&
  2038. IS_FLOAT(OutType))
  2039. {
  2040. // XXX drewb - Use direct conversion.
  2041. sprintf(FloatStr, "%I64u", Inter.I64);
  2042. _atoldbl((_ULDOUBLE*)Inter.RawBytes, FloatStr);
  2043. }
  2044. else if (IS_FLOAT(In->Type) &&
  2045. IS_INT(OutType))
  2046. {
  2047. double TmpDbl;
  2048. // XXX drewb - Use direct conversion.
  2049. _uldtoa((_ULDOUBLE*)Inter.RawBytes, sizeof(FloatStr), FloatStr);
  2050. if (sscanf(FloatStr, "%10lg", &TmpDbl) != 1)
  2051. {
  2052. TmpDbl = 0.0;
  2053. }
  2054. Inter.I64 = (ULONG64)TmpDbl;
  2055. Inter.Nat = FALSE;
  2056. }
  2057. // Convert the intermediate value down to the
  2058. // appropriate output size.
  2059. switch(OutType)
  2060. {
  2061. case DEBUG_VALUE_INT8:
  2062. Out->I8 = (UCHAR)Inter.I64;
  2063. break;
  2064. case DEBUG_VALUE_INT16:
  2065. Out->I16 = (USHORT)Inter.I64;
  2066. break;
  2067. case DEBUG_VALUE_INT32:
  2068. Out->I32 = (ULONG)Inter.I64;
  2069. break;
  2070. case DEBUG_VALUE_INT64:
  2071. Out->I64 = Inter.I64;
  2072. Out->Nat = Inter.Nat;
  2073. break;
  2074. case DEBUG_VALUE_FLOAT32:
  2075. // XXX drewb - Use direct conversion.
  2076. _uldtoa((_ULDOUBLE*)Inter.RawBytes, sizeof(FloatStr), FloatStr);
  2077. if (sscanf(FloatStr, "%10g", &Out->F32) != 1)
  2078. {
  2079. Out->F32 = 0.0f;
  2080. }
  2081. break;
  2082. case DEBUG_VALUE_FLOAT64:
  2083. // XXX drewb - Use direct conversion.
  2084. _uldtoa((_ULDOUBLE*)Inter.RawBytes, sizeof(FloatStr), FloatStr);
  2085. if (sscanf(FloatStr, "%10lg", &Out->F64) != 1)
  2086. {
  2087. Out->F64 = 0.0;
  2088. }
  2089. break;
  2090. case DEBUG_VALUE_FLOAT80:
  2091. memcpy(Out->F80Bytes, Inter.RawBytes, sizeof(Out->F80Bytes));
  2092. break;
  2093. case DEBUG_VALUE_FLOAT82:
  2094. _uldtoa((_ULDOUBLE*)Inter.RawBytes, sizeof(FloatStr), FloatStr);
  2095. double f;
  2096. if (sscanf(FloatStr, "%10lg", &f) != 1)
  2097. {
  2098. f = 0.0;
  2099. }
  2100. FLOAT128 f82;
  2101. DoubleToFloat82(f, &f82);
  2102. memcpy(&(Out->F82Bytes), &f82,
  2103. min(sizeof(Out->F82Bytes), sizeof(f82)));
  2104. break;
  2105. case DEBUG_VALUE_FLOAT128:
  2106. // XXX drewb - What's the format? How should this be supported.
  2107. memcpy(Out->F128Bytes, Inter.RawBytes, sizeof(Out->F128Bytes));
  2108. break;
  2109. case DEBUG_VALUE_VECTOR64:
  2110. memcpy(Out->RawBytes, Inter.RawBytes, 8);
  2111. break;
  2112. case DEBUG_VALUE_VECTOR128:
  2113. memcpy(Out->RawBytes, Inter.RawBytes, 16);
  2114. break;
  2115. default:
  2116. DBG_ASSERT(FALSE);
  2117. break;
  2118. }
  2119. LEAVE_ENGINE();
  2120. return S_OK;
  2121. }
  2122. STDMETHODIMP
  2123. DebugClient::CoerceValues(
  2124. THIS_
  2125. IN ULONG Count,
  2126. IN /* size_is(Count) */ PDEBUG_VALUE In,
  2127. IN /* size_is(Count) */ PULONG OutTypes,
  2128. OUT /* size_is(Count) */ PDEBUG_VALUE Out
  2129. )
  2130. {
  2131. ENTER_ENGINE();
  2132. ULONG i;
  2133. HRESULT Status, SingleStatus;
  2134. Status = S_OK;
  2135. for (i = 0; i < Count; i++)
  2136. {
  2137. SingleStatus = CoerceValue(In, *OutTypes, Out);
  2138. if (SingleStatus != S_OK)
  2139. {
  2140. // Accumulate error and mark failed value.
  2141. Status = SingleStatus;
  2142. Out->Type = DEBUG_VALUE_INVALID;
  2143. }
  2144. In++;
  2145. OutTypes++;
  2146. Out++;
  2147. }
  2148. LEAVE_ENGINE();
  2149. return Status;
  2150. }
  2151. HRESULT
  2152. Execute(DebugClient* Client, PCSTR Command, ULONG Flags)
  2153. {
  2154. char Copy[MAX_COMMAND];
  2155. ULONG Len = strlen(Command);
  2156. BOOL AddNewLine = Len == 0 || Command[Len - 1] != '\n';
  2157. if (Flags & DEBUG_EXECUTE_ECHO)
  2158. {
  2159. dprintf("%s", Command);
  2160. if (AddNewLine)
  2161. {
  2162. dprintf("\n");
  2163. }
  2164. }
  2165. else if ((Flags & DEBUG_EXECUTE_NOT_LOGGED) == 0)
  2166. {
  2167. lprintf(Command);
  2168. if (AddNewLine)
  2169. {
  2170. lprintf("\n");
  2171. }
  2172. }
  2173. HRESULT Status;
  2174. PSTR SaveCommand;
  2175. PSTR SaveStart;
  2176. // This Execute may be coming from an extension invoked
  2177. // from a command so save all command state.
  2178. SaveCommand = g_CurCmd;
  2179. SaveStart = g_CommandStart;
  2180. // Copy const string to buffer to avoid read-only memory
  2181. // AVs as the command is modified during parsing.
  2182. strcpy(Copy, Command);
  2183. g_CurCmd = Copy;
  2184. g_CommandStart = Copy;
  2185. RemoveDelChar(g_CurCmd);
  2186. ExpandUserRegs(Copy);
  2187. ReplaceAliases(g_CurCmd);
  2188. if ((Flags & DEBUG_EXECUTE_NO_REPEAT) == 0 &&
  2189. (g_EngOptions & DEBUG_ENGOPT_NO_EXECUTE_REPEAT) == 0)
  2190. {
  2191. if (Copy[0] == 0)
  2192. {
  2193. strcpy(Copy, g_LastCommand);
  2194. }
  2195. else
  2196. {
  2197. strcpy(g_LastCommand, Copy);
  2198. }
  2199. }
  2200. for (;;)
  2201. {
  2202. Status = ProcessCommandsAndCatch(Client);
  2203. // If we're switching processors (cmdState == 's')
  2204. // we have to wait to allow the switch to occur.
  2205. if (g_CmdState != 's' &&
  2206. (Status != S_FALSE ||
  2207. (g_EngStatus & ENG_STATUS_NO_AUTO_WAIT)))
  2208. {
  2209. break;
  2210. }
  2211. if ((g_CmdState != 's' || !IS_CONN_KERNEL_TARGET() ||
  2212. g_DbgKdTransport->m_WaitingThread != 0) &&
  2213. GetCurrentThreadId() != g_SessionThread)
  2214. {
  2215. ErrOut("Non-primary client caused an implicit wait\n");
  2216. Status = E_FAIL;
  2217. break;
  2218. }
  2219. Status = g_Target->WaitForEvent(DEBUG_STATUS_GO, INFINITE);
  2220. if (Status != S_OK)
  2221. {
  2222. break;
  2223. }
  2224. }
  2225. g_CurCmd = SaveCommand;
  2226. g_CommandStart = SaveStart;
  2227. return Status;
  2228. }
  2229. #define ALL_EXECUTE_FLAGS \
  2230. (DEBUG_EXECUTE_DEFAULT | \
  2231. DEBUG_EXECUTE_ECHO | \
  2232. DEBUG_EXECUTE_NOT_LOGGED | \
  2233. DEBUG_EXECUTE_NO_REPEAT)
  2234. STDMETHODIMP
  2235. DebugClient::Execute(
  2236. THIS_
  2237. IN ULONG OutputControl,
  2238. IN PCSTR Command,
  2239. IN ULONG Flags
  2240. )
  2241. {
  2242. if ((Flags & ~ALL_EXECUTE_FLAGS) ||
  2243. strlen(Command) >= MAX_COMMAND)
  2244. {
  2245. return E_INVALIDARG;
  2246. }
  2247. // We can't do a blanket IS_MACHINE_ACCESSIBLE check
  2248. // here as Execute's commands have a mix of requirements.
  2249. // Individual commands should check when necessary.
  2250. HRESULT Status;
  2251. ENTER_ENGINE();
  2252. OutCtlSave OldCtl;
  2253. if (!PushOutCtl(OutputControl, this, &OldCtl))
  2254. {
  2255. Status = E_INVALIDARG;
  2256. }
  2257. else
  2258. {
  2259. Status = ::Execute(this, Command, Flags);
  2260. PopOutCtl(&OldCtl);
  2261. }
  2262. LEAVE_ENGINE();
  2263. return Status;
  2264. }
  2265. HRESULT
  2266. ExecuteCommandFile(DebugClient* Client, PCSTR CommandFile, ULONG Flags)
  2267. {
  2268. HRESULT Status;
  2269. FILE* File;
  2270. File = fopen(CommandFile, "r");
  2271. if (File == NULL)
  2272. {
  2273. Status = E_FAIL;
  2274. }
  2275. else
  2276. {
  2277. char Command[MAX_COMMAND];
  2278. va_list VaUnused;
  2279. // This value is only used as a placeholder so
  2280. // it doesn't really matter what it's initialized to.
  2281. ZeroMemory(&VaUnused, sizeof(VaUnused));
  2282. for (;;)
  2283. {
  2284. Command[sizeof(Command) - 2] = '\n';
  2285. Command[sizeof(Command) - 1] = 0;
  2286. if (fgets(Command, sizeof(Command), File) == NULL)
  2287. {
  2288. if (feof(File))
  2289. {
  2290. Status = S_OK;
  2291. }
  2292. else
  2293. {
  2294. Status = E_FAIL;
  2295. }
  2296. break;
  2297. }
  2298. if (Command[sizeof(Command) - 2] != '\n' ||
  2299. Command[sizeof(Command) - 1] != 0)
  2300. {
  2301. // Input line is too long.
  2302. Status = E_INVALIDARG;
  2303. break;
  2304. }
  2305. if (Flags & DEBUG_EXECUTE_ECHO)
  2306. {
  2307. OutputPrompt(" ", VaUnused);
  2308. // Command has a new-line built in.
  2309. dprintf("%s", Command);
  2310. }
  2311. else if ((Flags & DEBUG_EXECUTE_NOT_LOGGED) == 0)
  2312. {
  2313. ULONG OutCtl;
  2314. // Restrict output to the log only.
  2315. OutCtl = g_OutputControl;
  2316. g_OutputControl = (OutCtl & ~DEBUG_OUTCTL_SEND_MASK) |
  2317. DEBUG_OUTCTL_LOG_ONLY;
  2318. OutputPrompt(" ", VaUnused);
  2319. // Command has a new-line built in.
  2320. dprintf("%s", Command);
  2321. g_OutputControl = OutCtl;
  2322. }
  2323. Status = Execute(Client, Command, DEBUG_EXECUTE_NOT_LOGGED |
  2324. (Flags & ~DEBUG_EXECUTE_ECHO));
  2325. if (Status != S_OK)
  2326. {
  2327. break;
  2328. }
  2329. }
  2330. fclose(File);
  2331. }
  2332. return Status;
  2333. }
  2334. STDMETHODIMP
  2335. DebugClient::ExecuteCommandFile(
  2336. THIS_
  2337. IN ULONG OutputControl,
  2338. IN PCSTR CommandFile,
  2339. IN ULONG Flags
  2340. )
  2341. {
  2342. if (Flags & ~ALL_EXECUTE_FLAGS)
  2343. {
  2344. return E_INVALIDARG;
  2345. }
  2346. // We can't do a blanket IS_MACHINE_ACCESSIBLE check
  2347. // here as Execute's commands have a mix of requirements.
  2348. // Individual commands should check when necessary.
  2349. HRESULT Status;
  2350. ENTER_ENGINE();
  2351. OutCtlSave OldCtl;
  2352. if (!PushOutCtl(OutputControl, this, &OldCtl))
  2353. {
  2354. return E_INVALIDARG;
  2355. }
  2356. else
  2357. {
  2358. Status = ::ExecuteCommandFile(this, CommandFile, Flags);
  2359. PopOutCtl(&OldCtl);
  2360. }
  2361. LEAVE_ENGINE();
  2362. return Status;
  2363. }
  2364. STDMETHODIMP
  2365. DebugClient::GetNumberBreakpoints(
  2366. THIS_
  2367. OUT PULONG Number
  2368. )
  2369. {
  2370. HRESULT Status;
  2371. ENTER_ENGINE();
  2372. if (g_CurrentProcess == NULL)
  2373. {
  2374. Status = E_UNEXPECTED;
  2375. }
  2376. else
  2377. {
  2378. *Number = g_CurrentProcess->NumBreakpoints;
  2379. Status = S_OK;
  2380. }
  2381. LEAVE_ENGINE();
  2382. return Status;
  2383. }
  2384. STDMETHODIMP
  2385. DebugClient::GetBreakpointByIndex(
  2386. THIS_
  2387. IN ULONG Index,
  2388. OUT PDEBUG_BREAKPOINT* RetBp
  2389. )
  2390. {
  2391. HRESULT Status;
  2392. ENTER_ENGINE();
  2393. if (g_CurrentProcess == NULL)
  2394. {
  2395. Status = E_UNEXPECTED;
  2396. }
  2397. else
  2398. {
  2399. Breakpoint* Bp = ::GetBreakpointByIndex(this, Index);
  2400. if (Bp != NULL)
  2401. {
  2402. Bp->AddRef();
  2403. *RetBp = Bp;
  2404. Status = S_OK;
  2405. }
  2406. else
  2407. {
  2408. Status = E_NOINTERFACE;
  2409. }
  2410. }
  2411. LEAVE_ENGINE();
  2412. return Status;
  2413. }
  2414. STDMETHODIMP
  2415. DebugClient::GetBreakpointById(
  2416. THIS_
  2417. IN ULONG Id,
  2418. OUT PDEBUG_BREAKPOINT* RetBp
  2419. )
  2420. {
  2421. HRESULT Status;
  2422. ENTER_ENGINE();
  2423. if (g_CurrentProcess == NULL)
  2424. {
  2425. Status = E_UNEXPECTED;
  2426. }
  2427. else
  2428. {
  2429. Breakpoint* Bp = ::GetBreakpointById(this, Id);
  2430. if (Bp != NULL)
  2431. {
  2432. Bp->AddRef();
  2433. *RetBp = Bp;
  2434. Status = S_OK;
  2435. }
  2436. else
  2437. {
  2438. Status = E_NOINTERFACE;
  2439. }
  2440. }
  2441. LEAVE_ENGINE();
  2442. return Status;
  2443. }
  2444. STDMETHODIMP
  2445. DebugClient::GetBreakpointParameters(
  2446. THIS_
  2447. IN ULONG Count,
  2448. IN OPTIONAL /* size_is(Count) */ PULONG Ids,
  2449. IN ULONG Start,
  2450. OUT /* size_is(Count) */ PDEBUG_BREAKPOINT_PARAMETERS Params
  2451. )
  2452. {
  2453. HRESULT Status;
  2454. ENTER_ENGINE();
  2455. if (g_CurrentProcess == NULL)
  2456. {
  2457. Status = E_UNEXPECTED;
  2458. }
  2459. else
  2460. {
  2461. ULONG i;
  2462. Breakpoint* Bp;
  2463. Status = S_OK;
  2464. for (i = 0; i < Count; i++)
  2465. {
  2466. if (Ids != NULL)
  2467. {
  2468. Bp = ::GetBreakpointById(this, *Ids++);
  2469. }
  2470. else
  2471. {
  2472. Bp = ::GetBreakpointByIndex(this, Start++);
  2473. }
  2474. if (Bp == NULL)
  2475. {
  2476. ZeroMemory(Params, sizeof(*Params));
  2477. Params->Id = DEBUG_ANY_ID;
  2478. Status = S_FALSE;
  2479. }
  2480. else
  2481. {
  2482. Bp->GetParameters(Params);
  2483. }
  2484. Params++;
  2485. }
  2486. }
  2487. LEAVE_ENGINE();
  2488. return Status;
  2489. }
  2490. STDMETHODIMP
  2491. DebugClient::AddBreakpoint(
  2492. THIS_
  2493. IN ULONG Type,
  2494. IN ULONG DesiredId,
  2495. OUT PDEBUG_BREAKPOINT* Bp
  2496. )
  2497. {
  2498. if (
  2499. #if DEBUG_BREAKPOINT_CODE > 0
  2500. Type < DEBUG_BREAKPOINT_CODE ||
  2501. #endif
  2502. Type > DEBUG_BREAKPOINT_DATA)
  2503. {
  2504. return E_INVALIDARG;
  2505. }
  2506. ENTER_ENGINE();
  2507. HRESULT Status = ::AddBreakpoint(this, Type, DesiredId, (Breakpoint**)Bp);
  2508. LEAVE_ENGINE();
  2509. return Status;
  2510. }
  2511. STDMETHODIMP
  2512. DebugClient::RemoveBreakpoint(
  2513. THIS_
  2514. IN PDEBUG_BREAKPOINT Bp
  2515. )
  2516. {
  2517. HRESULT Status;
  2518. ENTER_ENGINE();
  2519. if (g_CurrentProcess == NULL)
  2520. {
  2521. Status = E_UNEXPECTED;
  2522. }
  2523. else
  2524. {
  2525. ::RemoveBreakpoint((Breakpoint*)Bp);
  2526. Status = S_OK;
  2527. }
  2528. LEAVE_ENGINE();
  2529. return Status;
  2530. }
  2531. STDMETHODIMP
  2532. DebugClient::AddExtension(
  2533. THIS_
  2534. IN PCSTR Path,
  2535. IN ULONG Flags,
  2536. OUT PULONG64 Handle
  2537. )
  2538. {
  2539. if (Flags & ~(DEBUG_EXTENSION_AT_ENGINE))
  2540. {
  2541. return E_INVALIDARG;
  2542. }
  2543. // Remote extensions aren't supported at the moment.
  2544. if (Flags != DEBUG_EXTENSION_AT_ENGINE)
  2545. {
  2546. return E_NOTIMPL;
  2547. }
  2548. HRESULT Status;
  2549. ENTER_ENGINE();
  2550. char* End;
  2551. EXTDLL* Ext;
  2552. if ((Ext = AddExtensionDll((PSTR)Path, TRUE, &End)) == NULL)
  2553. {
  2554. Status = E_OUTOFMEMORY;
  2555. }
  2556. else
  2557. {
  2558. *Handle = (ULONG64)Ext;
  2559. Status = S_OK;
  2560. }
  2561. LEAVE_ENGINE();
  2562. return Status;
  2563. }
  2564. STDMETHODIMP
  2565. DebugClient::RemoveExtension(
  2566. THIS_
  2567. IN ULONG64 Handle
  2568. )
  2569. {
  2570. ENTER_ENGINE();
  2571. UnloadExtensionDll((EXTDLL*)Handle);
  2572. LEAVE_ENGINE();
  2573. return S_OK;
  2574. }
  2575. STDMETHODIMP
  2576. DebugClient::GetExtensionByPath(
  2577. THIS_
  2578. IN PCSTR Path,
  2579. OUT PULONG64 Handle
  2580. )
  2581. {
  2582. HRESULT Status;
  2583. ENTER_ENGINE();
  2584. EXTDLL* Ext;
  2585. Status = E_NOINTERFACE;
  2586. for (Ext = g_ExtDlls; Ext != NULL; Ext = Ext->Next)
  2587. {
  2588. if (!_strcmpi(Path, Ext->Name))
  2589. {
  2590. Status = S_OK;
  2591. *Handle = (ULONG64)Ext;
  2592. break;
  2593. }
  2594. }
  2595. LEAVE_ENGINE();
  2596. return Status;
  2597. }
  2598. STDMETHODIMP
  2599. DebugClient::CallExtension(
  2600. THIS_
  2601. IN OPTIONAL ULONG64 Handle,
  2602. IN PCSTR Function,
  2603. IN OPTIONAL PCSTR Arguments
  2604. )
  2605. {
  2606. char LocalFunc[MAX_COMMAND];
  2607. ULONG Len;
  2608. // Copy function name to temp buffer because it is
  2609. // modified.
  2610. Len = strlen(Function) + 1;
  2611. if (Len > sizeof(LocalFunc))
  2612. {
  2613. return E_INVALIDARG;
  2614. }
  2615. memcpy(LocalFunc, Function, Len);
  2616. HRESULT Status;
  2617. ENTER_ENGINE();
  2618. if (!IS_MACHINE_ACCESSIBLE())
  2619. {
  2620. Status = E_UNEXPECTED;
  2621. }
  2622. else if (!CallAnyExtension(this, (EXTDLL*)Handle, LocalFunc, Arguments,
  2623. Handle != 0, TRUE, &Status))
  2624. {
  2625. Status = E_FAIL;
  2626. }
  2627. LEAVE_ENGINE();
  2628. return Status;
  2629. }
  2630. STDMETHODIMP
  2631. DebugClient::GetExtensionFunction(
  2632. THIS_
  2633. IN ULONG64 Handle,
  2634. IN PCSTR FuncName,
  2635. OUT FARPROC* Function
  2636. )
  2637. {
  2638. HRESULT Status;
  2639. char ExpName[MAX_PATH + 16];
  2640. if (strlen(FuncName) >= MAX_PATH)
  2641. {
  2642. return E_INVALIDARG;
  2643. }
  2644. // Keep the namespace for extension function exports
  2645. // separate from the namespace for extension commands.
  2646. // Extension commands are exported under the same
  2647. // name as the command, so prefix extension functions
  2648. // to make them obviously different and to avoid
  2649. // name conflicts.
  2650. strcpy(ExpName, "_EFN_");
  2651. strcat(ExpName, FuncName);
  2652. ENTER_ENGINE();
  2653. EXTDLL* Ext;
  2654. FARPROC Routine;
  2655. Status = E_NOINTERFACE;
  2656. if (Handle != 0)
  2657. {
  2658. Ext = (EXTDLL*)(ULONG_PTR)Handle;
  2659. }
  2660. else
  2661. {
  2662. Ext = g_ExtDlls;
  2663. }
  2664. while (Ext!=NULL)
  2665. {
  2666. if (LoadExtensionDll(Ext))
  2667. {
  2668. Routine = GetProcAddress(Ext->Dll, ExpName);
  2669. if (Routine != NULL)
  2670. {
  2671. Status = S_OK;
  2672. *Function = Routine;
  2673. break;
  2674. }
  2675. }
  2676. // If the search was limited to a single extension stop looking.
  2677. if (Handle != 0)
  2678. {
  2679. break;
  2680. }
  2681. Ext = Ext->Next;
  2682. }
  2683. LEAVE_ENGINE();
  2684. return Status;
  2685. }
  2686. STDMETHODIMP
  2687. DebugClient::GetWindbgExtensionApis32(
  2688. THIS_
  2689. IN OUT PWINDBG_EXTENSION_APIS32 Api
  2690. )
  2691. {
  2692. if (Api->nSize != sizeof(*Api))
  2693. {
  2694. return E_INVALIDARG;
  2695. }
  2696. *Api = g_WindbgExtensions32;
  2697. return S_OK;
  2698. }
  2699. STDMETHODIMP
  2700. DebugClient::GetWindbgExtensionApis64(
  2701. THIS_
  2702. IN OUT PWINDBG_EXTENSION_APIS64 Api
  2703. )
  2704. {
  2705. if (Api->nSize != sizeof(*Api))
  2706. {
  2707. return E_INVALIDARG;
  2708. }
  2709. *Api = g_WindbgExtensions64;
  2710. return S_OK;
  2711. }
  2712. STDMETHODIMP
  2713. DebugClient::GetNumberEventFilters(
  2714. THIS_
  2715. OUT PULONG SpecificEvents,
  2716. OUT PULONG SpecificExceptions,
  2717. OUT PULONG ArbitraryExceptions
  2718. )
  2719. {
  2720. ENTER_ENGINE();
  2721. *SpecificEvents = FILTER_SPECIFIC_LAST - FILTER_SPECIFIC_FIRST + 1;
  2722. *SpecificExceptions = FILTER_EXCEPTION_LAST - FILTER_EXCEPTION_FIRST + 1;
  2723. *ArbitraryExceptions = g_NumOtherExceptions;
  2724. LEAVE_ENGINE();
  2725. return S_OK;
  2726. }
  2727. STDMETHODIMP
  2728. DebugClient::GetEventFilterText(
  2729. THIS_
  2730. IN ULONG Index,
  2731. OUT OPTIONAL PSTR Buffer,
  2732. IN ULONG BufferSize,
  2733. OUT OPTIONAL PULONG TextSize
  2734. )
  2735. {
  2736. HRESULT Status;
  2737. ENTER_ENGINE();
  2738. if (Index >= FILTER_COUNT)
  2739. {
  2740. Status = E_NOINTERFACE;
  2741. }
  2742. else
  2743. {
  2744. Status = FillStringBuffer(g_EventFilters[Index].Name, 0,
  2745. Buffer, BufferSize, TextSize);
  2746. }
  2747. LEAVE_ENGINE();
  2748. return Status;
  2749. }
  2750. HRESULT
  2751. GetEitherEventFilterCommand(ULONG Index, ULONG Which,
  2752. PSTR Buffer, ULONG BufferSize, PULONG CommandSize)
  2753. {
  2754. EVENT_COMMAND* EventCommand;
  2755. if (Index < FILTER_COUNT)
  2756. {
  2757. EventCommand = &g_EventFilters[Index].Command;
  2758. }
  2759. else if ((Index - FILTER_COUNT) < g_NumOtherExceptions)
  2760. {
  2761. EventCommand = &g_OtherExceptionCommands[Index - FILTER_COUNT];
  2762. }
  2763. else
  2764. {
  2765. return E_NOINTERFACE;
  2766. }
  2767. return FillStringBuffer(EventCommand->Command[Which],
  2768. EventCommand->CommandSize[Which],
  2769. Buffer, BufferSize, CommandSize);
  2770. }
  2771. STDMETHODIMP
  2772. DebugClient::GetEventFilterCommand(
  2773. THIS_
  2774. IN ULONG Index,
  2775. OUT OPTIONAL PSTR Buffer,
  2776. IN ULONG BufferSize,
  2777. OUT OPTIONAL PULONG CommandSize
  2778. )
  2779. {
  2780. HRESULT Status;
  2781. ENTER_ENGINE();
  2782. Status = GetEitherEventFilterCommand(Index, 0, Buffer, BufferSize,
  2783. CommandSize);
  2784. LEAVE_ENGINE();
  2785. return Status;
  2786. }
  2787. HRESULT
  2788. SetEitherEventFilterCommand(DebugClient* Client, ULONG Index, ULONG Which,
  2789. PCSTR Command)
  2790. {
  2791. EVENT_COMMAND* EventCommand;
  2792. if (Index < FILTER_COUNT)
  2793. {
  2794. EventCommand = &g_EventFilters[Index].Command;
  2795. }
  2796. else if ((Index - FILTER_COUNT) < g_NumOtherExceptions)
  2797. {
  2798. EventCommand = &g_OtherExceptionCommands[Index - FILTER_COUNT];
  2799. }
  2800. else
  2801. {
  2802. return E_NOINTERFACE;
  2803. }
  2804. HRESULT Status;
  2805. Status = ChangeString(&EventCommand->Command[Which],
  2806. &EventCommand->CommandSize[Which],
  2807. Command);
  2808. if (Status == S_OK)
  2809. {
  2810. if (Index < FILTER_COUNT)
  2811. {
  2812. g_EventFilters[Index].Flags |= FILTER_CHANGED_COMMAND;
  2813. }
  2814. EventCommand->Client = Client;
  2815. NotifyChangeEngineState(DEBUG_CES_EVENT_FILTERS, Index, TRUE);
  2816. }
  2817. return Status;
  2818. }
  2819. STDMETHODIMP
  2820. DebugClient::SetEventFilterCommand(
  2821. THIS_
  2822. IN ULONG Index,
  2823. IN PCSTR Command
  2824. )
  2825. {
  2826. HRESULT Status;
  2827. ENTER_ENGINE();
  2828. Status = SetEitherEventFilterCommand(this, Index, 0, Command);
  2829. LEAVE_ENGINE();
  2830. return Status;
  2831. }
  2832. STDMETHODIMP
  2833. DebugClient::GetSpecificFilterParameters(
  2834. THIS_
  2835. IN ULONG Start,
  2836. IN ULONG Count,
  2837. OUT /* size_is(Count) */ PDEBUG_SPECIFIC_FILTER_PARAMETERS Params
  2838. )
  2839. {
  2840. if (
  2841. #if FILTER_SPECIFIC_FIRST > 0
  2842. Start < FILTER_SPECIFIC_FIRST ||
  2843. #endif
  2844. Start > FILTER_SPECIFIC_LAST ||
  2845. Start + Count > FILTER_SPECIFIC_LAST + 1)
  2846. {
  2847. return E_INVALIDARG;
  2848. }
  2849. ENTER_ENGINE();
  2850. EVENT_FILTER* Filter;
  2851. for (ULONG i = 0; i < Count; i++)
  2852. {
  2853. Filter = g_EventFilters + (Start + i);
  2854. Params[i].ExecutionOption = Filter->Params.ExecutionOption;
  2855. Params[i].ContinueOption = Filter->Params.ContinueOption;
  2856. Params[i].TextSize = strlen(Filter->Name) + 1;
  2857. Params[i].CommandSize = Filter->Command.CommandSize[0];
  2858. Params[i].ArgumentSize = Filter->Argument != NULL ?
  2859. strlen(Filter->Argument) + 1 : 0;
  2860. }
  2861. LEAVE_ENGINE();
  2862. return S_OK;
  2863. }
  2864. STDMETHODIMP
  2865. DebugClient::SetSpecificFilterParameters(
  2866. THIS_
  2867. IN ULONG Start,
  2868. IN ULONG Count,
  2869. IN /* size_is(Count) */ PDEBUG_SPECIFIC_FILTER_PARAMETERS Params
  2870. )
  2871. {
  2872. if (
  2873. #if FILTER_SPECIFIC_FIRST > 0
  2874. Start < FILTER_SPECIFIC_FIRST ||
  2875. #endif
  2876. Start > FILTER_SPECIFIC_LAST ||
  2877. Start + Count > FILTER_SPECIFIC_LAST + 1)
  2878. {
  2879. return E_INVALIDARG;
  2880. }
  2881. HRESULT Status = S_OK;
  2882. ULONG Set = 0;
  2883. ULONG SetIndex = 0;
  2884. ENTER_ENGINE();
  2885. for (ULONG i = 0; i < Count; i++)
  2886. {
  2887. if (
  2888. #if DEBUG_FILTER_BREAK > 0
  2889. Params[i].ExecutionOption >= DEBUG_FILTER_BREAK &&
  2890. #endif
  2891. Params[i].ExecutionOption <= DEBUG_FILTER_IGNORE &&
  2892. #if DEBUG_FILTER_GO_HANDLED > 0
  2893. Params[i].ContinueOption >= DEBUG_FILTER_GO_HANDLED &&
  2894. #endif
  2895. Params[i].ContinueOption <= DEBUG_FILTER_GO_NOT_HANDLED)
  2896. {
  2897. g_EventFilters[Start + i].Params.ExecutionOption =
  2898. Params[i].ExecutionOption;
  2899. g_EventFilters[Start + i].Params.ContinueOption =
  2900. Params[i].ContinueOption;
  2901. g_EventFilters[Start + i].Flags |=
  2902. FILTER_CHANGED_EXECUTION | FILTER_CHANGED_CONTINUE;
  2903. Set++;
  2904. SetIndex = i;
  2905. }
  2906. else
  2907. {
  2908. Status = E_INVALIDARG;
  2909. }
  2910. }
  2911. if (SyncOptionsWithFilters())
  2912. {
  2913. NotifyChangeEngineState(DEBUG_CES_EVENT_FILTERS |
  2914. DEBUG_CES_ENGINE_OPTIONS,
  2915. DEBUG_ANY_ID, TRUE);
  2916. }
  2917. else if (Set == 1)
  2918. {
  2919. NotifyChangeEngineState(DEBUG_CES_EVENT_FILTERS, SetIndex, TRUE);
  2920. }
  2921. else if (Set > 1)
  2922. {
  2923. NotifyChangeEngineState(DEBUG_CES_EVENT_FILTERS, DEBUG_ANY_ID, TRUE);
  2924. }
  2925. LEAVE_ENGINE();
  2926. return Status;
  2927. }
  2928. STDMETHODIMP
  2929. DebugClient::GetSpecificFilterArgument(
  2930. THIS_
  2931. IN ULONG Index,
  2932. OUT OPTIONAL PSTR Buffer,
  2933. IN ULONG BufferSize,
  2934. OUT OPTIONAL PULONG ArgumentSize
  2935. )
  2936. {
  2937. if (
  2938. #if FILTER_SPECIFIC_FIRST > 0
  2939. Index < FILTER_SPECIFIC_FIRST ||
  2940. #endif
  2941. Index > FILTER_SPECIFIC_LAST ||
  2942. g_EventFilters[Index].Argument == NULL)
  2943. {
  2944. return E_INVALIDARG;
  2945. }
  2946. HRESULT Status;
  2947. ENTER_ENGINE();
  2948. Status = FillStringBuffer(g_EventFilters[Index].Argument, 0,
  2949. Buffer, BufferSize, ArgumentSize);
  2950. LEAVE_ENGINE();
  2951. return Status;
  2952. }
  2953. STDMETHODIMP
  2954. DebugClient::SetSpecificFilterArgument(
  2955. THIS_
  2956. IN ULONG Index,
  2957. IN PCSTR Argument
  2958. )
  2959. {
  2960. ULONG Len;
  2961. if (Argument == NULL)
  2962. {
  2963. Len = 1;
  2964. }
  2965. else
  2966. {
  2967. Len = strlen(Argument) + 1;
  2968. }
  2969. if (
  2970. #if FILTER_SPECIFIC_FIRST > 0
  2971. Index < FILTER_SPECIFIC_FIRST ||
  2972. #endif
  2973. Index > FILTER_SPECIFIC_LAST ||
  2974. g_EventFilters[Index].Argument == NULL ||
  2975. Len > FILTER_MAX_ARGUMENT)
  2976. {
  2977. return E_INVALIDARG;
  2978. }
  2979. ENTER_ENGINE();
  2980. if (Argument == NULL)
  2981. {
  2982. g_EventFilters[Index].Argument[0] = 0;
  2983. }
  2984. else
  2985. {
  2986. memcpy(g_EventFilters[Index].Argument, Argument, Len);
  2987. }
  2988. if (Index == DEBUG_FILTER_UNLOAD_MODULE)
  2989. {
  2990. g_UnloadDllBase = ExtGetExpression(Argument);
  2991. }
  2992. NotifyChangeEngineState(DEBUG_CES_EVENT_FILTERS, Index, TRUE);
  2993. LEAVE_ENGINE();
  2994. return S_OK;
  2995. }
  2996. void
  2997. GetExFilterParams(PCSTR Text,
  2998. PDEBUG_EXCEPTION_FILTER_PARAMETERS InParams,
  2999. EVENT_COMMAND* InCommand,
  3000. PDEBUG_EXCEPTION_FILTER_PARAMETERS OutParams)
  3001. {
  3002. OutParams->ExecutionOption = InParams->ExecutionOption;
  3003. OutParams->ContinueOption = InParams->ContinueOption;
  3004. OutParams->TextSize = Text != NULL ? strlen(Text) + 1 : 0;
  3005. OutParams->CommandSize = InCommand->CommandSize[0];
  3006. OutParams->SecondCommandSize = InCommand->CommandSize[1];
  3007. OutParams->ExceptionCode = InParams->ExceptionCode;
  3008. }
  3009. STDMETHODIMP
  3010. DebugClient::GetExceptionFilterParameters(
  3011. THIS_
  3012. IN ULONG Count,
  3013. IN OPTIONAL /* size_is(Count) */ PULONG Codes,
  3014. IN ULONG Start,
  3015. OUT /* size_is(Count) */ PDEBUG_EXCEPTION_FILTER_PARAMETERS Params
  3016. )
  3017. {
  3018. HRESULT Status = S_OK;
  3019. ENTER_ENGINE();
  3020. ULONG i, Index;
  3021. EVENT_FILTER* Filter;
  3022. if (Codes != NULL)
  3023. {
  3024. for (i = 0; i < Count; i++)
  3025. {
  3026. // Is this a specific exception?
  3027. Filter = g_EventFilters + FILTER_EXCEPTION_FIRST;
  3028. for (Index = FILTER_EXCEPTION_FIRST;
  3029. Index <= FILTER_EXCEPTION_LAST;
  3030. Index++)
  3031. {
  3032. if (Filter->Params.ExceptionCode == Codes[i])
  3033. {
  3034. GetExFilterParams(Filter->Name, &Filter->Params,
  3035. &Filter->Command, Params + i);
  3036. break;
  3037. }
  3038. Filter++;
  3039. }
  3040. if (Index > FILTER_EXCEPTION_LAST)
  3041. {
  3042. // Is this an other exception?
  3043. for (Index = 0; Index < g_NumOtherExceptions; Index++)
  3044. {
  3045. if (g_OtherExceptionList[Index].ExceptionCode == Codes[i])
  3046. {
  3047. GetExFilterParams(NULL, g_OtherExceptionList + Index,
  3048. g_OtherExceptionCommands + Index,
  3049. Params + i);
  3050. break;
  3051. }
  3052. }
  3053. if (Index >= g_NumOtherExceptions)
  3054. {
  3055. memset(Params + i, 0xff, sizeof(*Params));
  3056. Status = E_NOINTERFACE;
  3057. }
  3058. }
  3059. }
  3060. }
  3061. else
  3062. {
  3063. for (i = 0; i < Count; i++)
  3064. {
  3065. Index = Start + i;
  3066. // Is this a specific exception?
  3067. if (Index >= FILTER_EXCEPTION_FIRST &&
  3068. Index <= FILTER_EXCEPTION_LAST)
  3069. {
  3070. Filter = g_EventFilters + Index;
  3071. GetExFilterParams(Filter->Name, &Filter->Params,
  3072. &Filter->Command, Params + i);
  3073. }
  3074. // Is this an other exception?
  3075. else if (Index >= FILTER_COUNT &&
  3076. Index < FILTER_COUNT + g_NumOtherExceptions)
  3077. {
  3078. GetExFilterParams(NULL, g_OtherExceptionList +
  3079. (Index - FILTER_COUNT),
  3080. g_OtherExceptionCommands +
  3081. (Index - FILTER_COUNT),
  3082. Params + i);
  3083. }
  3084. else
  3085. {
  3086. memset(Params + i, 0xff, sizeof(*Params));
  3087. Status = E_INVALIDARG;
  3088. }
  3089. }
  3090. }
  3091. LEAVE_ENGINE();
  3092. return Status;
  3093. }
  3094. HRESULT
  3095. SetExFilterParams(PDEBUG_EXCEPTION_FILTER_PARAMETERS InParams,
  3096. PDEBUG_EXCEPTION_FILTER_PARAMETERS OutParams)
  3097. {
  3098. if (
  3099. #if DEBUG_FILTER_BREAK > 0
  3100. InParams->ExecutionOption >= DEBUG_FILTER_BREAK &&
  3101. #endif
  3102. InParams->ExecutionOption <= DEBUG_FILTER_IGNORE &&
  3103. #if DEBUG_FILTER_GO_HANDLED > 0
  3104. InParams->ContinueOption >= DEBUG_FILTER_GO_HANDLED &&
  3105. #endif
  3106. InParams->ContinueOption <= DEBUG_FILTER_GO_NOT_HANDLED)
  3107. {
  3108. OutParams->ExecutionOption = InParams->ExecutionOption;
  3109. OutParams->ContinueOption = InParams->ContinueOption;
  3110. return S_OK;
  3111. }
  3112. else
  3113. {
  3114. return E_INVALIDARG;
  3115. }
  3116. }
  3117. HRESULT
  3118. SetOtherExFilterParams(PDEBUG_EXCEPTION_FILTER_PARAMETERS InParams,
  3119. ULONG OutIndex, PULONG Set, PULONG SetIndex)
  3120. {
  3121. HRESULT Status;
  3122. if (OutIndex < g_NumOtherExceptions)
  3123. {
  3124. if (InParams->ExecutionOption == DEBUG_FILTER_REMOVE)
  3125. {
  3126. g_NumOtherExceptions--;
  3127. memmove(g_OtherExceptionList + OutIndex,
  3128. g_OtherExceptionList + OutIndex + 1,
  3129. (g_NumOtherExceptions - OutIndex) *
  3130. sizeof(g_OtherExceptionList[0]));
  3131. *Set += 2;
  3132. Status = S_OK;
  3133. }
  3134. else
  3135. {
  3136. Status = SetExFilterParams(InParams,
  3137. g_OtherExceptionList + OutIndex);
  3138. if (Status == S_OK)
  3139. {
  3140. (*Set)++;
  3141. *SetIndex = OutIndex + FILTER_COUNT;
  3142. }
  3143. }
  3144. }
  3145. else
  3146. {
  3147. if (g_NumOtherExceptions == OTHER_EXCEPTION_LIST_MAX)
  3148. {
  3149. Status = E_OUTOFMEMORY;
  3150. }
  3151. else
  3152. {
  3153. OutIndex = g_NumOtherExceptions;
  3154. g_OtherExceptionList[OutIndex].ExceptionCode =
  3155. InParams->ExceptionCode;
  3156. Status = SetExFilterParams(InParams,
  3157. g_OtherExceptionList + OutIndex);
  3158. if (Status == S_OK)
  3159. {
  3160. g_NumOtherExceptions++;
  3161. (*Set)++;
  3162. *SetIndex = OutIndex + FILTER_COUNT;
  3163. }
  3164. }
  3165. }
  3166. return Status;
  3167. }
  3168. STDMETHODIMP
  3169. DebugClient::SetExceptionFilterParameters(
  3170. THIS_
  3171. IN ULONG Count,
  3172. IN /* size_is(Count) */ PDEBUG_EXCEPTION_FILTER_PARAMETERS Params
  3173. )
  3174. {
  3175. HRESULT Status = S_OK;
  3176. ENTER_ENGINE();
  3177. ULONG i, Index;
  3178. EVENT_FILTER* Filter;
  3179. ULONG Set = 0;
  3180. ULONG SetIndex = 0;
  3181. for (i = 0; i < Count; i++)
  3182. {
  3183. // Is this a specific exception?
  3184. Filter = g_EventFilters + FILTER_EXCEPTION_FIRST;
  3185. for (Index = FILTER_EXCEPTION_FIRST;
  3186. Index <= FILTER_EXCEPTION_LAST;
  3187. Index++)
  3188. {
  3189. if (Filter->Params.ExceptionCode == Params[i].ExceptionCode)
  3190. {
  3191. Status = SetExFilterParams(Params + i, &Filter->Params);
  3192. if (Status == S_OK)
  3193. {
  3194. Filter->Flags |= FILTER_CHANGED_EXECUTION |
  3195. FILTER_CHANGED_CONTINUE;
  3196. Set++;
  3197. SetIndex = Index;
  3198. }
  3199. break;
  3200. }
  3201. Filter++;
  3202. }
  3203. if (Index > FILTER_EXCEPTION_LAST)
  3204. {
  3205. // Is this an other exception?
  3206. for (Index = 0; Index < g_NumOtherExceptions; Index++)
  3207. {
  3208. if (g_OtherExceptionList[Index].ExceptionCode ==
  3209. Params[i].ExceptionCode)
  3210. {
  3211. break;
  3212. }
  3213. }
  3214. Status = SetOtherExFilterParams(Params + i, Index,
  3215. &Set, &SetIndex);
  3216. }
  3217. }
  3218. if (Set == 1)
  3219. {
  3220. NotifyChangeEngineState(DEBUG_CES_EVENT_FILTERS, SetIndex, TRUE);
  3221. }
  3222. else if (Set > 1)
  3223. {
  3224. NotifyChangeEngineState(DEBUG_CES_EVENT_FILTERS, DEBUG_ANY_ID, TRUE);
  3225. }
  3226. LEAVE_ENGINE();
  3227. return Status;
  3228. }
  3229. STDMETHODIMP
  3230. DebugClient::GetExceptionFilterSecondCommand(
  3231. THIS_
  3232. IN ULONG Index,
  3233. OUT OPTIONAL PSTR Buffer,
  3234. IN ULONG BufferSize,
  3235. OUT OPTIONAL PULONG CommandSize
  3236. )
  3237. {
  3238. HRESULT Status;
  3239. ENTER_ENGINE();
  3240. Status = GetEitherEventFilterCommand(Index, 1, Buffer, BufferSize,
  3241. CommandSize);
  3242. LEAVE_ENGINE();
  3243. return Status;
  3244. }
  3245. STDMETHODIMP
  3246. DebugClient::SetExceptionFilterSecondCommand(
  3247. THIS_
  3248. IN ULONG Index,
  3249. IN PCSTR Command
  3250. )
  3251. {
  3252. if (Index <= FILTER_SPECIFIC_LAST)
  3253. {
  3254. return E_INVALIDARG;
  3255. }
  3256. HRESULT Status;
  3257. ENTER_ENGINE();
  3258. Status = SetEitherEventFilterCommand(this, Index, 1, Command);
  3259. LEAVE_ENGINE();
  3260. return Status;
  3261. }
  3262. STDMETHODIMP
  3263. DebugClient::WaitForEvent(
  3264. THIS_
  3265. IN ULONG Flags,
  3266. IN ULONG Timeout
  3267. )
  3268. {
  3269. if (Flags != DEBUG_WAIT_DEFAULT ||
  3270. ::GetCurrentThreadId() != g_SessionThread)
  3271. {
  3272. return E_INVALIDARG;
  3273. }
  3274. HRESULT Status;
  3275. ENTER_ENGINE();
  3276. if (!IS_TARGET_SET() ||
  3277. (g_EngStatus & ENG_STATUS_STOP_SESSION))
  3278. {
  3279. Status = E_UNEXPECTED;
  3280. goto Exit;
  3281. }
  3282. // If the caller is trying to force the engine to
  3283. // stop waiting return immediately.
  3284. if (g_EngStatus & ENG_STATUS_EXIT_CURRENT_WAIT)
  3285. {
  3286. g_EngStatus &= ~ENG_STATUS_EXIT_CURRENT_WAIT;
  3287. Status = E_PENDING;
  3288. goto Exit;
  3289. }
  3290. // This constitutes interesting activity.
  3291. m_LastActivity = time(NULL);
  3292. if (g_EngStatus & ENG_STATUS_WAITING)
  3293. {
  3294. Status = E_FAIL;
  3295. }
  3296. else
  3297. {
  3298. Status = g_Target->WaitForEvent(Flags, Timeout);
  3299. }
  3300. g_EngStatus &= ~ENG_STATUS_EXIT_CURRENT_WAIT;
  3301. Exit:
  3302. LEAVE_ENGINE();
  3303. return Status;
  3304. }
  3305. STDMETHODIMP
  3306. DebugClient::GetLastEventInformation(
  3307. THIS_
  3308. OUT PULONG Type,
  3309. OUT PULONG ProcessId,
  3310. OUT PULONG ThreadId,
  3311. OUT OPTIONAL PVOID ExtraInformation,
  3312. IN ULONG ExtraInformationSize,
  3313. OUT OPTIONAL PULONG ExtraInformationUsed,
  3314. OUT OPTIONAL PSTR Description,
  3315. IN ULONG DescriptionSize,
  3316. OUT OPTIONAL PULONG DescriptionUsed
  3317. )
  3318. {
  3319. HRESULT Status;
  3320. ENTER_ENGINE();
  3321. *Type = g_LastEventType;
  3322. if (g_EventProcess != NULL)
  3323. {
  3324. *ProcessId = g_EventProcess->UserId;
  3325. *ThreadId = g_EventThread->UserId;
  3326. }
  3327. else
  3328. {
  3329. *ProcessId = DEBUG_ANY_ID;
  3330. *ThreadId = DEBUG_ANY_ID;
  3331. }
  3332. Status = FillDataBuffer(g_LastEventExtraData, g_LastEventExtraDataSize,
  3333. ExtraInformation, ExtraInformationSize,
  3334. ExtraInformationUsed);
  3335. if (FillStringBuffer(g_LastEventDesc, 0,
  3336. Description, DescriptionSize,
  3337. DescriptionUsed) == S_FALSE)
  3338. {
  3339. Status = S_FALSE;
  3340. }
  3341. LEAVE_ENGINE();
  3342. return Status;
  3343. }
  3344. STDMETHODIMP
  3345. DebugClient::GetCurrentTimeDate(
  3346. THIS_
  3347. OUT PULONG TimeDate
  3348. )
  3349. {
  3350. HRESULT Status;
  3351. ENTER_ENGINE();
  3352. if (!IS_TARGET_SET())
  3353. {
  3354. Status = E_UNEXPECTED;
  3355. }
  3356. else
  3357. {
  3358. *TimeDate = FileTimeToTimeDateStamp(g_Target->GetCurrentTimeDateN());
  3359. Status = S_OK;
  3360. }
  3361. LEAVE_ENGINE();
  3362. return Status;
  3363. }
  3364. STDMETHODIMP
  3365. DebugClient::GetCurrentSystemUpTime(
  3366. THIS_
  3367. OUT PULONG UpTime
  3368. )
  3369. {
  3370. HRESULT Status;
  3371. ENTER_ENGINE();
  3372. if (!IS_TARGET_SET())
  3373. {
  3374. Status = E_UNEXPECTED;
  3375. }
  3376. else
  3377. {
  3378. *UpTime = FileTimeToTime(g_Target->GetCurrentSystemUpTimeN());
  3379. Status = S_OK;
  3380. }
  3381. LEAVE_ENGINE();
  3382. return Status;
  3383. }
  3384. STDMETHODIMP
  3385. DebugClient::GetDumpFormatFlags(
  3386. THIS_
  3387. OUT PULONG FormatFlags
  3388. )
  3389. {
  3390. HRESULT Status;
  3391. ENTER_ENGINE();
  3392. if (!IS_DUMP_TARGET())
  3393. {
  3394. Status = E_UNEXPECTED;
  3395. }
  3396. else
  3397. {
  3398. *FormatFlags = g_DumpFormatFlags;
  3399. Status = S_OK;
  3400. }
  3401. LEAVE_ENGINE();
  3402. return Status;
  3403. }
  3404. STDMETHODIMP
  3405. DebugClient::GetNumberTextReplacements(
  3406. THIS_
  3407. OUT PULONG NumRepl
  3408. )
  3409. {
  3410. HRESULT Status;
  3411. ENTER_ENGINE();
  3412. *NumRepl = g_NumAliases;
  3413. Status = S_OK;
  3414. LEAVE_ENGINE();
  3415. return Status;
  3416. }
  3417. STDMETHODIMP
  3418. DebugClient::GetTextReplacement(
  3419. THIS_
  3420. IN OPTIONAL PCSTR SrcText,
  3421. IN ULONG Index,
  3422. OUT OPTIONAL PSTR SrcBuffer,
  3423. IN ULONG SrcBufferSize,
  3424. OUT OPTIONAL PULONG SrcSize,
  3425. OUT OPTIONAL PSTR DstBuffer,
  3426. IN ULONG DstBufferSize,
  3427. OUT OPTIONAL PULONG DstSize
  3428. )
  3429. {
  3430. HRESULT Status;
  3431. ENTER_ENGINE();
  3432. PALIAS Scan = g_AliasListHead;
  3433. ULONG i;
  3434. while (Scan != NULL &&
  3435. ((SrcText != NULL && strcmp(SrcText, Scan->Name)) ||
  3436. (SrcText == NULL && Index-- > 0)))
  3437. {
  3438. Scan = Scan->Next;
  3439. }
  3440. if (Scan != NULL)
  3441. {
  3442. Status = FillStringBuffer(Scan->Name, 0,
  3443. SrcBuffer, SrcBufferSize, SrcSize);
  3444. if (FillStringBuffer(Scan->Value, 0,
  3445. DstBuffer, DstBufferSize, DstSize) == S_FALSE)
  3446. {
  3447. Status = S_FALSE;
  3448. }
  3449. }
  3450. else
  3451. {
  3452. Status = E_NOINTERFACE;
  3453. }
  3454. LEAVE_ENGINE();
  3455. return Status;
  3456. }
  3457. STDMETHODIMP
  3458. DebugClient::SetTextReplacement(
  3459. THIS_
  3460. IN PCSTR SrcText,
  3461. IN OPTIONAL PCSTR DstText
  3462. )
  3463. {
  3464. HRESULT Status;
  3465. ENTER_ENGINE();
  3466. if (DstText != NULL)
  3467. {
  3468. Status = SetAlias(SrcText, DstText);
  3469. }
  3470. else
  3471. {
  3472. Status = DeleteAlias(SrcText);
  3473. }
  3474. LEAVE_ENGINE();
  3475. return Status;
  3476. }
  3477. STDMETHODIMP
  3478. DebugClient::RemoveTextReplacements(
  3479. THIS
  3480. )
  3481. {
  3482. HRESULT Status;
  3483. ENTER_ENGINE();
  3484. Status = DeleteAlias("*");
  3485. LEAVE_ENGINE();
  3486. return Status;
  3487. }
  3488. STDMETHODIMP
  3489. DebugClient::OutputTextReplacements(
  3490. THIS_
  3491. IN ULONG OutputControl,
  3492. IN ULONG Flags
  3493. )
  3494. {
  3495. HRESULT Status;
  3496. ENTER_ENGINE();
  3497. ListAliases();
  3498. Status = S_OK;
  3499. LEAVE_ENGINE();
  3500. return Status;
  3501. }