Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

4959 lines
108 KiB

  1. //----------------------------------------------------------------------------
  2. //
  3. // IDebugControl implementation.
  4. //
  5. // Copyright (C) Microsoft Corporation, 1999-2002.
  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 (!g_Target)
  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_Target) && 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. ::CloseLogFile();
  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. HRESULT Status;
  171. if (BufferSize < 2)
  172. {
  173. // Must have space for at least a character and a terminator.
  174. return E_INVALIDARG;
  175. }
  176. ENTER_ENGINE();
  177. ULONG Size;
  178. //
  179. // XXX drewb.
  180. // In condbg we needed a way to see how many clients
  181. // were available for input. Rather than define a new
  182. // interface and method just for this purpose we've added
  183. // this hack where you pass in a magic combination of parameters.
  184. // If a new IDebugControl ever gets defined this should be
  185. // formalized and the hack removed.
  186. //
  187. if (!Buffer && BufferSize == DEBUG_ANY_ID)
  188. {
  189. DebugClient* Client;
  190. Size = 0;
  191. for (Client = g_Clients; Client != NULL; Client = Client->m_Next)
  192. {
  193. if (Client->m_InputCb != NULL)
  194. {
  195. Size++;
  196. }
  197. }
  198. Status = S_OK;
  199. }
  200. else
  201. {
  202. Size = GetInput(NULL, Buffer, BufferSize, GETIN_DEFAULT);
  203. if (Size == 0)
  204. {
  205. Status = E_FAIL;
  206. goto Exit;
  207. }
  208. Status = Size > BufferSize ? S_FALSE : S_OK;
  209. }
  210. if (InputSize != NULL)
  211. {
  212. *InputSize = Size;
  213. }
  214. Exit:
  215. LEAVE_ENGINE();
  216. return Status;
  217. }
  218. STDMETHODIMP
  219. DebugClient::ReturnInput(
  220. THIS_
  221. IN PCSTR Buffer
  222. )
  223. {
  224. // This method is reentrant.
  225. HRESULT Status;
  226. ULONG Seq = (ULONG)InterlockedIncrement((PLONG)&g_InputSequence);
  227. if (Seq == m_InputSequence)
  228. {
  229. ULONG CopyLen = strlen(Buffer) + 1;
  230. CopyLen = min(CopyLen, INPUT_BUFFER_SIZE);
  231. memcpy(g_InputBuffer, Buffer, CopyLen);
  232. g_InputBuffer[INPUT_BUFFER_SIZE - 1] = 0;
  233. SetEvent(g_InputEvent);
  234. Status = S_OK;
  235. }
  236. else
  237. {
  238. Status = S_FALSE;
  239. }
  240. m_InputSequence = 0xffffffff;
  241. return Status;
  242. }
  243. STDMETHODIMPV
  244. DebugClient::Output(
  245. THIS_
  246. IN ULONG Mask,
  247. IN PCSTR Format,
  248. ...
  249. )
  250. {
  251. ENTER_ENGINE();
  252. va_list Args;
  253. va_start(Args, Format);
  254. MaskOutVa(Mask, Format, Args, TRUE);
  255. va_end(Args);
  256. LEAVE_ENGINE();
  257. return S_OK;
  258. }
  259. STDMETHODIMP
  260. DebugClient::OutputVaList(
  261. THIS_
  262. IN ULONG Mask,
  263. IN PCSTR Format,
  264. IN va_list Args
  265. )
  266. {
  267. ENTER_ENGINE();
  268. MaskOutVa(Mask, Format, Args, TRUE);
  269. LEAVE_ENGINE();
  270. return S_OK;
  271. }
  272. STDMETHODIMPV
  273. DebugClient::ControlledOutput(
  274. THIS_
  275. IN ULONG OutputControl,
  276. IN ULONG Mask,
  277. IN PCSTR Format,
  278. ...
  279. )
  280. {
  281. HRESULT Status;
  282. ENTER_ENGINE();
  283. OutCtlSave OldCtl;
  284. if (!PushOutCtl(OutputControl, this, &OldCtl))
  285. {
  286. Status = E_INVALIDARG;
  287. }
  288. else
  289. {
  290. va_list Args;
  291. va_start(Args, Format);
  292. MaskOutVa(Mask, Format, Args, TRUE);
  293. va_end(Args);
  294. Status = S_OK;
  295. PopOutCtl(&OldCtl);
  296. }
  297. LEAVE_ENGINE();
  298. return Status;
  299. }
  300. STDMETHODIMP
  301. DebugClient::ControlledOutputVaList(
  302. THIS_
  303. IN ULONG OutputControl,
  304. IN ULONG Mask,
  305. IN PCSTR Format,
  306. IN va_list Args
  307. )
  308. {
  309. HRESULT Status;
  310. ENTER_ENGINE();
  311. OutCtlSave OldCtl;
  312. if (!PushOutCtl(OutputControl, this, &OldCtl))
  313. {
  314. Status = E_INVALIDARG;
  315. }
  316. else
  317. {
  318. MaskOutVa(Mask, Format, Args, TRUE);
  319. Status = S_OK;
  320. PopOutCtl(&OldCtl);
  321. }
  322. LEAVE_ENGINE();
  323. return Status;
  324. }
  325. STDMETHODIMPV
  326. DebugClient::OutputPrompt(
  327. THIS_
  328. IN ULONG OutputControl,
  329. IN OPTIONAL PCSTR Format,
  330. ...
  331. )
  332. {
  333. HRESULT Status;
  334. ENTER_ENGINE();
  335. OutCtlSave OldCtl;
  336. if (!PushOutCtl(OutputControl, this, &OldCtl))
  337. {
  338. Status = E_INVALIDARG;
  339. }
  340. else
  341. {
  342. va_list Args;
  343. va_start(Args, Format);
  344. ::OutputPrompt(Format, Args);
  345. va_end(Args);
  346. Status = S_OK;
  347. PopOutCtl(&OldCtl);
  348. }
  349. LEAVE_ENGINE();
  350. return Status;
  351. }
  352. STDMETHODIMP
  353. DebugClient::OutputPromptVaList(
  354. THIS_
  355. IN ULONG OutputControl,
  356. IN OPTIONAL PCSTR Format,
  357. IN va_list Args
  358. )
  359. {
  360. HRESULT Status;
  361. ENTER_ENGINE();
  362. OutCtlSave OldCtl;
  363. if (!PushOutCtl(OutputControl, this, &OldCtl))
  364. {
  365. Status = E_INVALIDARG;
  366. }
  367. else
  368. {
  369. ::OutputPrompt(Format, Args);
  370. Status = S_OK;
  371. PopOutCtl(&OldCtl);
  372. }
  373. LEAVE_ENGINE();
  374. return Status;
  375. }
  376. STDMETHODIMP
  377. DebugClient::GetPromptText(
  378. THIS_
  379. OUT OPTIONAL PSTR Buffer,
  380. IN ULONG BufferSize,
  381. OUT OPTIONAL PULONG TextSize
  382. )
  383. {
  384. HRESULT Status;
  385. ENTER_ENGINE();
  386. Status = ::GetPromptText(Buffer, BufferSize, TextSize);
  387. LEAVE_ENGINE();
  388. return Status;
  389. }
  390. #define CURRENT_ALL DEBUG_CURRENT_DEFAULT
  391. STDMETHODIMP
  392. DebugClient::OutputCurrentState(
  393. THIS_
  394. IN ULONG OutputControl,
  395. IN ULONG Flags
  396. )
  397. {
  398. if (Flags & ~CURRENT_ALL)
  399. {
  400. return E_INVALIDARG;
  401. }
  402. HRESULT Status;
  403. ENTER_ENGINE();
  404. OutCtlSave OldCtl;
  405. if (!IS_CUR_MACHINE_ACCESSIBLE())
  406. {
  407. Status = E_UNEXPECTED;
  408. }
  409. else if (!PushOutCtl(OutputControl, this, &OldCtl))
  410. {
  411. Status = E_INVALIDARG;
  412. }
  413. else
  414. {
  415. ULONG Oci = 0;
  416. if (Flags & DEBUG_CURRENT_SYMBOL)
  417. {
  418. Oci |= OCI_SYMBOL;
  419. }
  420. if (Flags & DEBUG_CURRENT_DISASM)
  421. {
  422. Oci |= OCI_DISASM | OCI_ALLOW_EA;
  423. }
  424. if (Flags & DEBUG_CURRENT_REGISTERS)
  425. {
  426. Oci |= OCI_ALLOW_REG;
  427. }
  428. if (Flags & DEBUG_CURRENT_SOURCE_LINE)
  429. {
  430. Oci |= OCI_ALLOW_SOURCE;
  431. }
  432. OutCurInfo(Oci, g_Machine->m_AllMask, DEBUG_OUTPUT_PROMPT_REGISTERS);
  433. Status = S_OK;
  434. PopOutCtl(&OldCtl);
  435. }
  436. LEAVE_ENGINE();
  437. return Status;
  438. }
  439. STDMETHODIMP
  440. DebugClient::OutputVersionInformation(
  441. THIS_
  442. IN ULONG OutputControl
  443. )
  444. {
  445. HRESULT Status;
  446. // This method is reentrant. It uses many pieces of
  447. // global information, though, so try and get
  448. // the engine lock.
  449. Status = TRY_ENTER_ENGINE();
  450. if (Status != S_OK)
  451. {
  452. return Status;
  453. }
  454. OutCtlSave OldCtl;
  455. if (!PushOutCtl(OutputControl, this, &OldCtl))
  456. {
  457. return E_INVALIDARG;
  458. }
  459. ::OutputVersionInformation(this);
  460. PopOutCtl(&OldCtl);
  461. LEAVE_ENGINE();
  462. return S_OK;
  463. }
  464. STDMETHODIMP
  465. DebugClient::GetNotifyEventHandle(
  466. THIS_
  467. OUT PULONG64 Handle
  468. )
  469. {
  470. ENTER_ENGINE();
  471. *Handle = (ULONG64)g_EventToSignal;
  472. LEAVE_ENGINE();
  473. return S_OK;
  474. }
  475. STDMETHODIMP
  476. DebugClient::SetNotifyEventHandle(
  477. THIS_
  478. IN ULONG64 Handle
  479. )
  480. {
  481. if ((ULONG64)(HANDLE)Handle != Handle)
  482. {
  483. return E_INVALIDARG;
  484. }
  485. ENTER_ENGINE();
  486. g_EventToSignal = (HANDLE)Handle;
  487. LEAVE_ENGINE();
  488. return S_OK;
  489. }
  490. STDMETHODIMP
  491. DebugClient::Assemble(
  492. THIS_
  493. IN ULONG64 Offset,
  494. IN PCSTR Instr,
  495. OUT PULONG64 EndOffset
  496. )
  497. {
  498. HRESULT Status;
  499. ENTER_ENGINE();
  500. __try
  501. {
  502. if (!IS_CUR_CONTEXT_ACCESSIBLE())
  503. {
  504. Status = E_UNEXPECTED;
  505. __leave;
  506. }
  507. ADDR Addr;
  508. // Assume this is a code segment address so that assembly
  509. // picks up the appropriate type of address.
  510. g_Machine->FormAddr(SEGREG_CODE, Offset,
  511. FORM_SEGREG | FORM_CODE, &Addr);
  512. g_Machine->Assemble(g_Process, &Addr, (PSTR)Instr);
  513. *EndOffset = Flat(Addr);
  514. Status = S_OK;
  515. }
  516. __except(CommandExceptionFilter(GetExceptionInformation()))
  517. {
  518. Status = E_FAIL;
  519. }
  520. LEAVE_ENGINE();
  521. return Status;
  522. }
  523. STDMETHODIMP
  524. DebugClient::Disassemble(
  525. THIS_
  526. IN ULONG64 Offset,
  527. IN ULONG Flags,
  528. OUT OPTIONAL PSTR Buffer,
  529. IN ULONG BufferSize,
  530. OUT OPTIONAL PULONG DisassemblySize,
  531. OUT PULONG64 EndOffset
  532. )
  533. {
  534. if (Flags & ~DEBUG_DISASM_EFFECTIVE_ADDRESS)
  535. {
  536. return E_INVALIDARG;
  537. }
  538. HRESULT Status;
  539. ENTER_ENGINE();
  540. if (!IS_CUR_CONTEXT_ACCESSIBLE())
  541. {
  542. Status = E_UNEXPECTED;
  543. }
  544. else
  545. {
  546. ADDR Addr;
  547. CHAR Disasm[MAX_DISASM_LEN];
  548. // Assume this is a code segment address so that disassembly
  549. // picks up the appropriate type of address.
  550. g_Machine->FormAddr(SEGREG_CODE, Offset, FORM_SEGREG | FORM_CODE,
  551. &Addr);
  552. g_Machine->Disassemble(g_Process, &Addr, Disasm,
  553. (Flags & DEBUG_DISASM_EFFECTIVE_ADDRESS));
  554. Status = FillStringBuffer(Disasm, 0,
  555. Buffer, BufferSize, DisassemblySize);
  556. *EndOffset = Flat(Addr);
  557. }
  558. LEAVE_ENGINE();
  559. return Status;
  560. }
  561. STDMETHODIMP
  562. DebugClient::GetDisassembleEffectiveOffset(
  563. THIS_
  564. OUT PULONG64 Offset
  565. )
  566. {
  567. HRESULT Status;
  568. ENTER_ENGINE();
  569. if (!IS_CUR_CONTEXT_ACCESSIBLE())
  570. {
  571. Status = E_UNEXPECTED;
  572. }
  573. else
  574. {
  575. ADDR Addr;
  576. ULONG Size;
  577. g_Machine->GetEffectiveAddr(&Addr, &Size);
  578. *Offset = Flat(Addr);
  579. Status = S_OK;
  580. }
  581. LEAVE_ENGINE();
  582. return Status;
  583. }
  584. HRESULT
  585. DoOutputDisassembly(PADDR Addr, ULONG Flags,
  586. ULONG SkipLines, ULONG OutputLines,
  587. PULONG LineCount)
  588. {
  589. ULONG Lines = 0;
  590. CHAR Buffer[MAX_DISASM_LEN];
  591. PCHAR FirstLine;
  592. HRESULT Status;
  593. if (Flags & DEBUG_DISASM_MATCHING_SYMBOLS)
  594. {
  595. ULONG64 Disp;
  596. GetSymbol(Flat(*Addr), Buffer, sizeof(Buffer), &Disp);
  597. if (Disp == 0)
  598. {
  599. if (OutputLines > 0)
  600. {
  601. if (SkipLines == 0)
  602. {
  603. StartOutLine(DEBUG_OUTPUT_NORMAL, OUT_LINE_NO_TIMESTAMP);
  604. dprintf("%s:\n", Buffer);
  605. OutputLines--;
  606. }
  607. else
  608. {
  609. SkipLines--;
  610. }
  611. }
  612. Lines++;
  613. }
  614. }
  615. FirstLine = Buffer;
  616. if (!g_Machine->
  617. Disassemble(g_Process, Addr, Buffer,
  618. (Flags & DEBUG_DISASM_EFFECTIVE_ADDRESS) != 0))
  619. {
  620. // Return S_FALSE if the disassembly failed.
  621. // Output will still be produced, such as "???".
  622. // Update the address to the next potential instruction
  623. // locations so that callers that are satisfied with "???"
  624. // can just iterate.
  625. g_Machine->IncrementBySmallestInstruction(Addr);
  626. Lines++;
  627. Status = S_FALSE;
  628. if (SkipLines > 0 || OutputLines == 0)
  629. {
  630. *FirstLine = 0;
  631. }
  632. }
  633. else
  634. {
  635. PSTR Nl = Buffer;
  636. PSTR LastLine = Nl;
  637. // Count lines in output and determine line positions.
  638. while (*Nl)
  639. {
  640. Nl = strchr(Nl, '\n');
  641. DBG_ASSERT(Nl != NULL);
  642. Lines++;
  643. Nl++;
  644. if (SkipLines > 0)
  645. {
  646. FirstLine = Nl;
  647. SkipLines--;
  648. }
  649. if (OutputLines > 0)
  650. {
  651. LastLine = Nl;
  652. OutputLines--;
  653. }
  654. }
  655. *LastLine = 0;
  656. Status = S_OK;
  657. }
  658. if (*FirstLine)
  659. {
  660. StartOutLine(DEBUG_OUTPUT_NORMAL, OUT_LINE_NO_TIMESTAMP);
  661. dprintf("%s", FirstLine);
  662. }
  663. if (LineCount != NULL)
  664. {
  665. *LineCount = Lines;
  666. }
  667. return Status;
  668. }
  669. #define ALL_DISASM_FLAGS \
  670. (DEBUG_DISASM_EFFECTIVE_ADDRESS | DEBUG_DISASM_MATCHING_SYMBOLS)
  671. STDMETHODIMP
  672. DebugClient::OutputDisassembly(
  673. THIS_
  674. IN ULONG OutputControl,
  675. IN ULONG64 Offset,
  676. IN ULONG Flags,
  677. OUT PULONG64 EndOffset
  678. )
  679. {
  680. if (Flags & ~ALL_DISASM_FLAGS)
  681. {
  682. return E_INVALIDARG;
  683. }
  684. HRESULT Status;
  685. ENTER_ENGINE();
  686. if (!IS_CUR_CONTEXT_ACCESSIBLE())
  687. {
  688. Status = E_UNEXPECTED;
  689. goto Exit;
  690. }
  691. OutCtlSave OldCtl;
  692. if (!PushOutCtl(OutputControl, this, &OldCtl))
  693. {
  694. Status = E_INVALIDARG;
  695. goto Exit;
  696. }
  697. ADDR Addr;
  698. // Assume this is a code segment address so that disassembly
  699. // picks up the appropriate type of address.
  700. g_Machine->FormAddr(SEGREG_CODE, Offset, FORM_SEGREG | FORM_CODE, &Addr);
  701. Status = DoOutputDisassembly(&Addr, Flags, 0, 0xffffffff, NULL);
  702. *EndOffset = Flat(Addr);
  703. PopOutCtl(&OldCtl);
  704. Exit:
  705. LEAVE_ENGINE();
  706. return Status;
  707. }
  708. ULONG
  709. BackUpDisassemblyLines(ULONG Lines, PADDR Addr, ULONG Flags, PADDR PcAddr)
  710. {
  711. //
  712. // There's no easy way to predict how many lines of
  713. // output a particular disassembly will take so
  714. // just iteratively back up by the minimum amount until
  715. // the appropriate number of lines is reached.
  716. //
  717. ADDR BackAddr = *Addr;
  718. // Limit things so that failure can be detected.
  719. // Right now X86's maximum instruction length of 16
  720. // is big enough for all platforms so use that.
  721. ADDR LimitAddr = *Addr;
  722. ULONG BackBytes = X86_MAX_INSTRUCTION_LEN * Lines;
  723. if (BackBytes > LimitAddr.off)
  724. {
  725. LimitAddr.off = 0;
  726. }
  727. else
  728. {
  729. AddrSub(&LimitAddr, BackBytes);
  730. }
  731. ADDR TryAddr;
  732. ULONG TryLines;
  733. //
  734. // Reverse disassembly is difficult on x86 due
  735. // to the variable length instructions. First
  736. // just locate the nearest symbol and disassemble
  737. // from that since this has a better chance of
  738. // producing a valid disassembly.
  739. //
  740. CHAR Buffer[MAX_DISASM_LEN];
  741. ULONG64 Disp;
  742. ADDR DisAddr, StartAddr;
  743. GetSymbol(Flat(LimitAddr), Buffer, sizeof(Buffer), &Disp);
  744. ADDRFLAT(&DisAddr, Disp);
  745. if (!AddrEqu(LimitAddr, DisAddr) &&
  746. Disp <= 16 * X86_MAX_INSTRUCTION_LEN) // valid symbol
  747. {
  748. BOOL DoOneMore = FALSE;
  749. StartAddr = LimitAddr;
  750. AddrSub(&StartAddr, Disp);
  751. TryAddr = StartAddr;
  752. TryLines = 0;
  753. while (1)
  754. {
  755. ULONG DisLines;
  756. ULONG DisFlags;
  757. while (AddrLt(TryAddr, *Addr) && ((TryLines < Lines) || DoOneMore))
  758. {
  759. UCHAR MemTest;
  760. // If we can't read memory at this address there's
  761. // no chance of getting a valid disassembly so
  762. // just stop the whole process.
  763. if (fnotFlat(TryAddr) ||
  764. g_Target->
  765. ReadAllVirtual(g_Process, Flat(TryAddr),
  766. &MemTest, sizeof(MemTest)) != S_OK)
  767. {
  768. TryAddr = *Addr;
  769. break;
  770. }
  771. DisFlags = Flags;
  772. if (!AddrEqu(TryAddr, *PcAddr))
  773. {
  774. DisFlags &= ~DEBUG_DISASM_EFFECTIVE_ADDRESS;
  775. }
  776. DoOutputDisassembly(&TryAddr, DisFlags, 0, 0, &DisLines);
  777. TryLines += DisLines;
  778. DoOneMore = FALSE;
  779. }
  780. if (TryLines >= Lines && AddrEqu(TryAddr, *Addr))
  781. {
  782. *Addr = StartAddr;
  783. return TryLines;
  784. }
  785. else if (AddrLt(TryAddr, *Addr))
  786. {
  787. DisAddr = StartAddr;
  788. // Increase StartAddr
  789. DisFlags = Flags;
  790. if (!AddrEqu(StartAddr, *PcAddr))
  791. {
  792. DisFlags &= ~DEBUG_DISASM_EFFECTIVE_ADDRESS;
  793. }
  794. DoOutputDisassembly(&StartAddr, DisFlags, 0, 0, &DisLines);
  795. if ((DisLines == 1) || ((TryLines - DisLines) >= (Lines - 1)))
  796. {
  797. TryLines -= DisLines;
  798. }
  799. else
  800. {
  801. StartAddr = DisAddr;
  802. DoOneMore = TRUE;
  803. }
  804. }
  805. else
  806. {
  807. // couldn't find it
  808. break;
  809. }
  810. }
  811. }
  812. //
  813. // If we couldn't do something with symbols just
  814. // try a brute-force search backwards. This
  815. // has limited utility on variable-length instruction
  816. // sets but sometimes it works.
  817. //
  818. while (AddrGt(BackAddr, LimitAddr))
  819. {
  820. g_Machine->DecrementBySmallestInstruction(&BackAddr);
  821. TryAddr = BackAddr;
  822. TryLines = 0;
  823. while (AddrLt(TryAddr, *Addr))
  824. {
  825. UCHAR MemTest;
  826. // If we can't read memory at this address there's
  827. // no chance of getting a valid disassembly so
  828. // just stop the whole process.
  829. if (fnotFlat(TryAddr) ||
  830. g_Target->
  831. ReadAllVirtual(g_Process, Flat(TryAddr),
  832. &MemTest, sizeof(MemTest)) != S_OK)
  833. {
  834. BackAddr = LimitAddr;
  835. break;
  836. }
  837. ULONG DisLines;
  838. ULONG DisFlags = Flags;
  839. if (!AddrEqu(TryAddr, *PcAddr))
  840. {
  841. DisFlags &= ~DEBUG_DISASM_EFFECTIVE_ADDRESS;
  842. }
  843. DoOutputDisassembly(&TryAddr, DisFlags, 0, 0, &DisLines);
  844. TryLines += DisLines;
  845. }
  846. if (TryLines >= Lines && AddrEqu(TryAddr, *Addr))
  847. {
  848. *Addr = BackAddr;
  849. return TryLines;
  850. }
  851. }
  852. // Couldn't find a disassembly that worked.
  853. return 0;
  854. }
  855. STDMETHODIMP
  856. DebugClient::OutputDisassemblyLines(
  857. THIS_
  858. IN ULONG OutputControl,
  859. IN ULONG PreviousLines,
  860. IN ULONG TotalLines,
  861. IN ULONG64 Offset,
  862. IN ULONG Flags,
  863. OUT OPTIONAL PULONG OffsetLine,
  864. OUT OPTIONAL PULONG64 StartOffset,
  865. OUT OPTIONAL PULONG64 EndOffset,
  866. OUT OPTIONAL /* size_is(TotalLines) */ PULONG64 LineOffsets
  867. )
  868. {
  869. if ((Flags & ~ALL_DISASM_FLAGS) ||
  870. TotalLines < 1 || PreviousLines > TotalLines)
  871. {
  872. return E_INVALIDARG;
  873. }
  874. HRESULT Status;
  875. ENTER_ENGINE();
  876. if (!IS_CUR_CONTEXT_ACCESSIBLE())
  877. {
  878. Status = E_UNEXPECTED;
  879. goto Exit;
  880. }
  881. OutCtlSave OldCtl;
  882. if (!PushOutCtl(OutputControl, this, &OldCtl))
  883. {
  884. Status = E_INVALIDARG;
  885. goto Exit;
  886. }
  887. ULONG i;
  888. if (LineOffsets != NULL)
  889. {
  890. for (i = 0; i < TotalLines; i++)
  891. {
  892. LineOffsets[i] = DEBUG_INVALID_OFFSET;
  893. }
  894. }
  895. ULONG Line, Lines, SkipLines;
  896. ADDR Addr, PcAddr;
  897. // Assume this is a code segment address so that disassembly
  898. // picks up the appropriate type of address.
  899. g_Machine->FormAddr(SEGREG_CODE, Offset, FORM_SEGREG | FORM_CODE, &Addr);
  900. g_Machine->GetPC(&PcAddr);
  901. Line = 0;
  902. SkipLines = 0;
  903. if (PreviousLines > 0)
  904. {
  905. Lines = BackUpDisassemblyLines(PreviousLines, &Addr, Flags, &PcAddr);
  906. if (Lines == 0)
  907. {
  908. dprintf("No prior disassembly possible\n");
  909. Line = 1;
  910. Lines = 1;
  911. TotalLines--;
  912. }
  913. else if (Lines > PreviousLines)
  914. {
  915. SkipLines = Lines - PreviousLines;
  916. Lines = PreviousLines;
  917. }
  918. }
  919. else
  920. {
  921. Lines = 0;
  922. }
  923. if (OffsetLine != NULL)
  924. {
  925. *OffsetLine = Lines;
  926. }
  927. if (StartOffset != NULL)
  928. {
  929. *StartOffset = Flat(Addr);
  930. }
  931. while (TotalLines > 0)
  932. {
  933. if (LineOffsets != NULL)
  934. {
  935. LineOffsets[Line] = Flat(Addr);
  936. }
  937. ULONG DisFlags = Flags;
  938. if (!AddrEqu(Addr, PcAddr))
  939. {
  940. DisFlags &= ~DEBUG_DISASM_EFFECTIVE_ADDRESS;
  941. }
  942. DoOutputDisassembly(&Addr, DisFlags, SkipLines, TotalLines, &Lines);
  943. Lines -= SkipLines;
  944. if (TotalLines <= Lines)
  945. {
  946. break;
  947. }
  948. TotalLines -= Lines;
  949. Line += Lines;
  950. SkipLines = 0;
  951. }
  952. if (EndOffset != NULL)
  953. {
  954. *EndOffset = Flat(Addr);
  955. }
  956. Status = S_OK;
  957. PopOutCtl(&OldCtl);
  958. Exit:
  959. LEAVE_ENGINE();
  960. return Status;
  961. }
  962. STDMETHODIMP
  963. DebugClient::GetNearInstruction(
  964. THIS_
  965. IN ULONG64 Offset,
  966. IN LONG Delta,
  967. OUT PULONG64 NearOffset
  968. )
  969. {
  970. HRESULT Status;
  971. ENTER_ENGINE();
  972. if (!IS_CUR_MACHINE_ACCESSIBLE())
  973. {
  974. Status = E_UNEXPECTED;
  975. goto Exit;
  976. }
  977. Status = S_OK;
  978. switch(g_Target->m_EffMachineType)
  979. {
  980. case IMAGE_FILE_MACHINE_ARM:
  981. // Each instruction is 32 bits.
  982. Offset += (LONG64)Delta * 4;
  983. break;
  984. case IMAGE_FILE_MACHINE_IA64:
  985. ULONG Instr;
  986. // Each 128-bit bundle has three instructions.
  987. if (Delta < 0)
  988. {
  989. while (Delta++ < 0)
  990. {
  991. Instr = (ULONG)(Offset & 0xf);
  992. if (Instr == 0)
  993. {
  994. Offset -= 8;
  995. }
  996. else
  997. {
  998. Offset -= 4;
  999. }
  1000. }
  1001. }
  1002. else
  1003. {
  1004. while (Delta-- > 0)
  1005. {
  1006. Instr = (ULONG)(Offset & 0xf);
  1007. if (Instr == 8)
  1008. {
  1009. Offset += 8;
  1010. }
  1011. else
  1012. {
  1013. Offset += 4;
  1014. }
  1015. }
  1016. }
  1017. break;
  1018. case IMAGE_FILE_MACHINE_I386:
  1019. case IMAGE_FILE_MACHINE_AMD64:
  1020. ADDR Addr;
  1021. CHAR Buffer[MAX_DISASM_LEN];
  1022. // Instructions are highly variable. There isn't any
  1023. // way to really know whether a particular disassembly
  1024. // of a stretch of code is valid or not, so this
  1025. // routine is inherently fragile.
  1026. g_Machine->FormAddr(SEGREG_CODE, Offset,
  1027. FORM_SEGREG | FORM_CODE, &Addr);
  1028. if (Delta < 0)
  1029. {
  1030. // Back up byte-by-byte and disassemble. If the
  1031. // post-disassembly offset matches the current offset,
  1032. // a good-enough instruction sequence has been found.
  1033. for (;;)
  1034. {
  1035. ADDR TryAddr;
  1036. LONG TryDelta;
  1037. AddrSub(&Addr, 1);
  1038. TryAddr = Addr;
  1039. TryDelta = 0;
  1040. while (Flat(TryAddr) < Offset)
  1041. {
  1042. if (!g_Machine->
  1043. Disassemble(g_Process,&TryAddr, Buffer, FALSE))
  1044. {
  1045. break;
  1046. }
  1047. TryDelta--;
  1048. }
  1049. if (Flat(TryAddr) == Offset &&
  1050. TryDelta == Delta)
  1051. {
  1052. break;
  1053. }
  1054. // Limit things just as a precaution.
  1055. if (Flat(Addr) < Offset + Delta * X86_MAX_INSTRUCTION_LEN)
  1056. {
  1057. Status = E_FAIL;
  1058. break;
  1059. }
  1060. }
  1061. }
  1062. else
  1063. {
  1064. while (Delta-- > 0)
  1065. {
  1066. if (!g_Machine->Disassemble(g_Process, &Addr, Buffer, FALSE))
  1067. {
  1068. Status = E_FAIL;
  1069. break;
  1070. }
  1071. }
  1072. }
  1073. Offset = Flat(Addr);
  1074. break;
  1075. default:
  1076. Status = E_UNEXPECTED;
  1077. break;
  1078. }
  1079. if (SUCCEEDED(Status))
  1080. {
  1081. *NearOffset = Offset;
  1082. }
  1083. Exit:
  1084. LEAVE_ENGINE();
  1085. return Status;
  1086. }
  1087. STDMETHODIMP
  1088. DebugClient::GetStackTrace(
  1089. THIS_
  1090. IN ULONG64 FrameOffset,
  1091. IN ULONG64 StackOffset,
  1092. IN ULONG64 InstructionOffset,
  1093. OUT PDEBUG_STACK_FRAME Frames,
  1094. IN ULONG FramesSize,
  1095. OUT OPTIONAL PULONG FramesFilled
  1096. )
  1097. {
  1098. HRESULT Status;
  1099. ENTER_ENGINE();
  1100. if (!IS_CUR_CONTEXT_ACCESSIBLE())
  1101. {
  1102. Status = E_UNEXPECTED;
  1103. goto Exit;
  1104. }
  1105. ULONG FramesRet;
  1106. ULONG64 ThreadData;
  1107. if (g_ExtThread != 0)
  1108. {
  1109. ThreadData = g_ExtThread;
  1110. g_ExtThread = 0;
  1111. }
  1112. else
  1113. {
  1114. ThreadData = 0;
  1115. }
  1116. ULONG PtrDef =
  1117. (!InstructionOffset ? STACK_INSTR_DEFAULT : 0) |
  1118. (!StackOffset ? STACK_STACK_DEFAULT : 0) |
  1119. (!FrameOffset ? STACK_FRAME_DEFAULT : 0);
  1120. FramesRet = StackTrace(this,
  1121. FrameOffset, StackOffset, InstructionOffset,
  1122. PtrDef, Frames, FramesSize, ThreadData, 0, FALSE);
  1123. if (FramesRet > 0)
  1124. {
  1125. Status = S_OK;
  1126. if (FramesFilled != NULL)
  1127. {
  1128. *FramesFilled = FramesRet;
  1129. }
  1130. }
  1131. else
  1132. {
  1133. Status = E_FAIL;
  1134. }
  1135. if (g_ExtThreadScopeSaved)
  1136. {
  1137. PopScope(&g_ExtThreadSavedScope);
  1138. g_ExtThreadScopeSaved = FALSE;
  1139. }
  1140. Exit:
  1141. LEAVE_ENGINE();
  1142. return Status;
  1143. }
  1144. STDMETHODIMP
  1145. DebugClient::GetReturnOffset(
  1146. THIS_
  1147. OUT PULONG64 Offset
  1148. )
  1149. {
  1150. HRESULT Status;
  1151. ENTER_ENGINE();
  1152. if (!IS_CUR_CONTEXT_ACCESSIBLE())
  1153. {
  1154. Status = E_UNEXPECTED;
  1155. }
  1156. else
  1157. {
  1158. ADDR Addr;
  1159. g_Machine->GetRetAddr(&Addr);
  1160. *Offset = Flat(Addr);
  1161. Status = S_OK;
  1162. }
  1163. LEAVE_ENGINE();
  1164. return Status;
  1165. }
  1166. STDMETHODIMP
  1167. DebugClient::OutputStackTrace(
  1168. THIS_
  1169. IN ULONG OutputControl,
  1170. IN PDEBUG_STACK_FRAME Frames,
  1171. IN ULONG FramesSize,
  1172. IN ULONG Flags
  1173. )
  1174. {
  1175. if (Flags & ~(DEBUG_STACK_ARGUMENTS |
  1176. DEBUG_STACK_FUNCTION_INFO |
  1177. DEBUG_STACK_SOURCE_LINE |
  1178. DEBUG_STACK_FRAME_ADDRESSES |
  1179. DEBUG_STACK_COLUMN_NAMES |
  1180. DEBUG_STACK_NONVOLATILE_REGISTERS |
  1181. DEBUG_STACK_FRAME_NUMBERS |
  1182. DEBUG_STACK_PARAMETERS |
  1183. DEBUG_STACK_FRAME_ADDRESSES_RA_ONLY |
  1184. DEBUG_STACK_FRAME_MEMORY_USAGE))
  1185. {
  1186. return E_INVALIDARG;
  1187. }
  1188. HRESULT Status;
  1189. ENTER_ENGINE();
  1190. if (!IS_CUR_CONTEXT_ACCESSIBLE())
  1191. {
  1192. Status = E_UNEXPECTED;
  1193. goto Exit;
  1194. }
  1195. OutCtlSave OldCtl;
  1196. if (!PushOutCtl(OutputControl, this, &OldCtl))
  1197. {
  1198. Status = E_INVALIDARG;
  1199. goto Exit;
  1200. }
  1201. // Currently only IA64 supports nonvolatile register output.
  1202. if (g_Target->m_EffMachineType != IMAGE_FILE_MACHINE_IA64)
  1203. {
  1204. Flags &= ~DEBUG_STACK_NONVOLATILE_REGISTERS;
  1205. }
  1206. PDEBUG_STACK_FRAME LocalFrames;
  1207. LocalFrames = NULL;
  1208. if (Frames == NULL)
  1209. {
  1210. ULONG FramesFilled;
  1211. ULONG64 ThreadData;
  1212. if (g_ExtThread != 0)
  1213. {
  1214. ThreadData = g_ExtThread;
  1215. g_ExtThread = 0;
  1216. }
  1217. else
  1218. {
  1219. ThreadData = 0;
  1220. }
  1221. LocalFrames = new DEBUG_STACK_FRAME[FramesSize];
  1222. if (LocalFrames == NULL)
  1223. {
  1224. ErrOut("Unable to allocate memory for stack trace\n");
  1225. Status = E_OUTOFMEMORY;
  1226. goto PopExit;
  1227. }
  1228. //
  1229. // StackTrace will generate output if any flags are
  1230. // passed in. The only time we really require that
  1231. // it produce output is when nonvolatile registers
  1232. // are requested as they can only be displayed when
  1233. // the context is available during stack walking.
  1234. // In order to simplify later logic, we only
  1235. // pass flags if we have the nonvolatile register flag.
  1236. //
  1237. FramesFilled = StackTrace(this,
  1238. 0, 0, 0, STACK_ALL_DEFAULT,
  1239. LocalFrames, FramesSize, ThreadData,
  1240. (Flags & DEBUG_STACK_NONVOLATILE_REGISTERS) ?
  1241. Flags : 0, FALSE);
  1242. if (FramesFilled == 0)
  1243. {
  1244. delete [] LocalFrames;
  1245. goto PopExit;
  1246. }
  1247. Frames = LocalFrames;
  1248. FramesSize = FramesFilled;
  1249. }
  1250. else if (Flags & DEBUG_STACK_NONVOLATILE_REGISTERS)
  1251. {
  1252. // Can't dump nonvolatile registers without a full
  1253. // context so this is not an allowable options.
  1254. Status = E_INVALIDARG;
  1255. goto PopExit;
  1256. }
  1257. if (!(Flags & DEBUG_STACK_NONVOLATILE_REGISTERS))
  1258. {
  1259. PrintStackTrace(FramesSize, Frames, Flags);
  1260. }
  1261. Status = S_OK;
  1262. delete [] LocalFrames;
  1263. if (g_ExtThreadScopeSaved)
  1264. {
  1265. PopScope(&g_ExtThreadSavedScope);
  1266. g_ExtThreadScopeSaved = FALSE;
  1267. }
  1268. PopExit:
  1269. PopOutCtl(&OldCtl);
  1270. Exit:
  1271. LEAVE_ENGINE();
  1272. return Status;
  1273. }
  1274. STDMETHODIMP
  1275. DebugClient::GetDebuggeeType(
  1276. THIS_
  1277. OUT PULONG Class,
  1278. OUT PULONG Qualifier
  1279. )
  1280. {
  1281. HRESULT Status;
  1282. ENTER_ENGINE();
  1283. if (!g_Target)
  1284. {
  1285. *Class = DEBUG_CLASS_UNINITIALIZED;
  1286. *Qualifier = 0;
  1287. Status = S_OK;
  1288. }
  1289. else
  1290. {
  1291. *Class = g_Target->m_Class;
  1292. *Qualifier = g_Target->m_ClassQualifier;
  1293. Status = S_OK;
  1294. }
  1295. LEAVE_ENGINE();
  1296. return Status;
  1297. }
  1298. STDMETHODIMP
  1299. DebugClient::GetActualProcessorType(
  1300. THIS_
  1301. OUT PULONG Type
  1302. )
  1303. {
  1304. HRESULT Status;
  1305. ENTER_ENGINE();
  1306. if (!IS_MACHINE_SET(g_Target))
  1307. {
  1308. Status = E_UNEXPECTED;
  1309. }
  1310. else
  1311. {
  1312. *Type = g_Target->m_MachineType;
  1313. Status = S_OK;
  1314. }
  1315. LEAVE_ENGINE();
  1316. return Status;
  1317. }
  1318. STDMETHODIMP
  1319. DebugClient::GetExecutingProcessorType(
  1320. THIS_
  1321. OUT PULONG Type
  1322. )
  1323. {
  1324. HRESULT Status;
  1325. ENTER_ENGINE();
  1326. if (!g_EventMachine)
  1327. {
  1328. Status = E_UNEXPECTED;
  1329. }
  1330. else
  1331. {
  1332. *Type = g_EventMachine->m_ExecTypes[0];
  1333. Status = S_OK;
  1334. }
  1335. LEAVE_ENGINE();
  1336. return Status;
  1337. }
  1338. STDMETHODIMP
  1339. DebugClient::GetNumberPossibleExecutingProcessorTypes(
  1340. THIS_
  1341. OUT PULONG Number
  1342. )
  1343. {
  1344. HRESULT Status;
  1345. ENTER_ENGINE();
  1346. if (!IS_MACHINE_SET(g_Target))
  1347. {
  1348. Status = E_UNEXPECTED;
  1349. }
  1350. else
  1351. {
  1352. MachineInfo* Machine =
  1353. MachineTypeInfo(g_Target, g_Target->m_MachineType);
  1354. if (Machine == NULL)
  1355. {
  1356. Status = E_INVALIDARG;
  1357. }
  1358. else
  1359. {
  1360. *Number = Machine->m_NumExecTypes;
  1361. Status = S_OK;
  1362. }
  1363. }
  1364. LEAVE_ENGINE();
  1365. return Status;
  1366. }
  1367. STDMETHODIMP
  1368. DebugClient::GetPossibleExecutingProcessorTypes(
  1369. THIS_
  1370. IN ULONG Start,
  1371. IN ULONG Count,
  1372. OUT PULONG Types
  1373. )
  1374. {
  1375. HRESULT Status;
  1376. ENTER_ENGINE();
  1377. if (!IS_MACHINE_SET(g_Target))
  1378. {
  1379. Status = E_UNEXPECTED;
  1380. }
  1381. else
  1382. {
  1383. MachineInfo* Machine =
  1384. MachineTypeInfo(g_Target, g_Target->m_MachineType);
  1385. if (Machine == NULL ||
  1386. Start >= Machine->m_NumExecTypes ||
  1387. Start + Count > Machine->m_NumExecTypes)
  1388. {
  1389. Status = E_INVALIDARG;
  1390. }
  1391. else
  1392. {
  1393. Status = S_OK;
  1394. while (Count-- > 0)
  1395. {
  1396. *Types++ = Machine->m_ExecTypes[Start++];
  1397. }
  1398. }
  1399. }
  1400. LEAVE_ENGINE();
  1401. return Status;
  1402. }
  1403. STDMETHODIMP
  1404. DebugClient::GetNumberProcessors(
  1405. THIS_
  1406. OUT PULONG Number
  1407. )
  1408. {
  1409. HRESULT Status;
  1410. ENTER_ENGINE();
  1411. if (!IS_MACHINE_SET(g_Target))
  1412. {
  1413. Status = E_UNEXPECTED;
  1414. }
  1415. else
  1416. {
  1417. *Number = g_Target->m_NumProcessors;
  1418. Status = S_OK;
  1419. }
  1420. LEAVE_ENGINE();
  1421. return Status;
  1422. }
  1423. STDMETHODIMP
  1424. DebugClient::GetSystemVersion(
  1425. THIS_
  1426. OUT PULONG PlatformId,
  1427. OUT PULONG Major,
  1428. OUT PULONG Minor,
  1429. OUT OPTIONAL PSTR ServicePackString,
  1430. IN ULONG ServicePackStringSize,
  1431. OUT OPTIONAL PULONG ServicePackStringUsed,
  1432. OUT PULONG ServicePackNumber,
  1433. OUT OPTIONAL PSTR BuildString,
  1434. IN ULONG BuildStringSize,
  1435. OUT OPTIONAL PULONG BuildStringUsed
  1436. )
  1437. {
  1438. HRESULT Status;
  1439. ENTER_ENGINE();
  1440. // This is insufficient to distinguish
  1441. // the various system types supported but we don't
  1442. // want to publish identifiers for every possible
  1443. // system version family. PlatformId is as good
  1444. // as it gets.
  1445. if (!IS_MACHINE_SET(g_Target))
  1446. {
  1447. Status = E_UNEXPECTED;
  1448. }
  1449. else
  1450. {
  1451. *PlatformId = g_Target->m_PlatformId;
  1452. *Major = g_Target->m_CheckedBuild;
  1453. *Minor = g_Target->m_BuildNumber;
  1454. Status = FillStringBuffer(g_Target->m_ServicePackString, 0,
  1455. ServicePackString, ServicePackStringSize,
  1456. ServicePackStringUsed);
  1457. *ServicePackNumber = g_Target->m_ServicePackNumber;
  1458. if (FillStringBuffer(g_Target->m_BuildLabName, 0,
  1459. BuildString, BuildStringSize,
  1460. BuildStringUsed) == S_FALSE)
  1461. {
  1462. Status = S_FALSE;
  1463. }
  1464. }
  1465. LEAVE_ENGINE();
  1466. return Status;
  1467. }
  1468. STDMETHODIMP
  1469. DebugClient::GetPageSize(
  1470. THIS_
  1471. OUT PULONG Size
  1472. )
  1473. {
  1474. HRESULT Status;
  1475. ENTER_ENGINE();
  1476. if (!g_Machine)
  1477. {
  1478. Status = E_UNEXPECTED;
  1479. }
  1480. else
  1481. {
  1482. *Size = g_Machine->m_PageSize;
  1483. Status = S_OK;
  1484. }
  1485. LEAVE_ENGINE();
  1486. return Status;
  1487. }
  1488. STDMETHODIMP
  1489. DebugClient::IsPointer64Bit(
  1490. THIS
  1491. )
  1492. {
  1493. HRESULT Status;
  1494. ENTER_ENGINE();
  1495. if (!g_Machine)
  1496. {
  1497. Status = E_UNEXPECTED;
  1498. }
  1499. else
  1500. {
  1501. Status = g_Machine->m_Ptr64 ? S_OK : S_FALSE;
  1502. }
  1503. LEAVE_ENGINE();
  1504. return Status;
  1505. }
  1506. STDMETHODIMP
  1507. DebugClient::ReadBugCheckData(
  1508. THIS_
  1509. OUT PULONG Code,
  1510. OUT PULONG64 Arg1,
  1511. OUT PULONG64 Arg2,
  1512. OUT PULONG64 Arg3,
  1513. OUT PULONG64 Arg4
  1514. )
  1515. {
  1516. HRESULT Status;
  1517. ENTER_ENGINE();
  1518. if (!IS_KERNEL_TARGET(g_Target))
  1519. {
  1520. Status = E_UNEXPECTED;
  1521. }
  1522. else
  1523. {
  1524. ULONG64 Args[4];
  1525. Status = g_Target->ReadBugCheckData(Code, Args);
  1526. if (Status == S_OK)
  1527. {
  1528. *Arg1 = Args[0];
  1529. *Arg2 = Args[1];
  1530. *Arg3 = Args[2];
  1531. *Arg4 = Args[3];
  1532. }
  1533. }
  1534. LEAVE_ENGINE();
  1535. return Status;
  1536. }
  1537. STDMETHODIMP
  1538. DebugClient::GetNumberSupportedProcessorTypes(
  1539. THIS_
  1540. OUT PULONG Number
  1541. )
  1542. {
  1543. ENTER_ENGINE();
  1544. *Number = MACHIDX_COUNT;
  1545. LEAVE_ENGINE();
  1546. return S_OK;
  1547. }
  1548. STDMETHODIMP
  1549. DebugClient::GetSupportedProcessorTypes(
  1550. THIS_
  1551. IN ULONG Start,
  1552. IN ULONG Count,
  1553. OUT PULONG Types
  1554. )
  1555. {
  1556. if (Start >= MACHIDX_COUNT ||
  1557. Start + Count > MACHIDX_COUNT)
  1558. {
  1559. return E_INVALIDARG;
  1560. }
  1561. ENTER_ENGINE();
  1562. if (Count > 0)
  1563. {
  1564. while (Count-- > 0)
  1565. {
  1566. // First ExecTypes entry is the actual processor
  1567. // type so it's a convenient place to turn an
  1568. // index into a type.
  1569. *Types++ = g_PossibleProcessorTypes[Start++];
  1570. }
  1571. }
  1572. LEAVE_ENGINE();
  1573. return S_OK;
  1574. }
  1575. STDMETHODIMP
  1576. DebugClient::GetProcessorTypeNames(
  1577. THIS_
  1578. IN ULONG Type,
  1579. OUT OPTIONAL PSTR FullNameBuffer,
  1580. IN ULONG FullNameBufferSize,
  1581. OUT OPTIONAL PULONG FullNameSize,
  1582. OUT OPTIONAL PSTR AbbrevNameBuffer,
  1583. IN ULONG AbbrevNameBufferSize,
  1584. OUT OPTIONAL PULONG AbbrevNameSize
  1585. )
  1586. {
  1587. HRESULT Status;
  1588. ENTER_ENGINE();
  1589. MachineInfo* Machine = MachineTypeInfo(g_Target, Type);
  1590. if (Machine == NULL)
  1591. {
  1592. Status = E_INVALIDARG;
  1593. }
  1594. else
  1595. {
  1596. Status = FillStringBuffer(Machine->m_FullName, 0,
  1597. FullNameBuffer, FullNameBufferSize,
  1598. FullNameSize);
  1599. if (FillStringBuffer(Machine->m_AbbrevName, 0,
  1600. AbbrevNameBuffer, AbbrevNameBufferSize,
  1601. AbbrevNameSize) == S_FALSE)
  1602. {
  1603. Status = S_FALSE;
  1604. }
  1605. }
  1606. LEAVE_ENGINE();
  1607. return Status;
  1608. }
  1609. STDMETHODIMP
  1610. DebugClient::GetEffectiveProcessorType(
  1611. THIS_
  1612. OUT PULONG Type
  1613. )
  1614. {
  1615. HRESULT Status;
  1616. ENTER_ENGINE();
  1617. if (!g_Target)
  1618. {
  1619. Status = E_UNEXPECTED;
  1620. }
  1621. else
  1622. {
  1623. *Type = g_Target->m_EffMachineType;
  1624. Status = S_OK;
  1625. }
  1626. LEAVE_ENGINE();
  1627. return Status;
  1628. }
  1629. STDMETHODIMP
  1630. DebugClient::SetEffectiveProcessorType(
  1631. THIS_
  1632. IN ULONG Type
  1633. )
  1634. {
  1635. HRESULT Status;
  1636. ENTER_ENGINE();
  1637. if (!g_Target)
  1638. {
  1639. Status = E_UNEXPECTED;
  1640. }
  1641. else
  1642. {
  1643. MachineIndex Index = MachineTypeIndex(Type);
  1644. if (Index == MACHIDX_COUNT)
  1645. {
  1646. Status = E_INVALIDARG;
  1647. }
  1648. else
  1649. {
  1650. g_Target->SetEffMachine(Type, TRUE);
  1651. Status = S_OK;
  1652. }
  1653. }
  1654. LEAVE_ENGINE();
  1655. return Status;
  1656. }
  1657. ULONG
  1658. GetExecutionStatus(void)
  1659. {
  1660. if ((g_EngStatus & ENG_STATUS_STOP_SESSION) ||
  1661. !AnyActiveProcesses(TRUE))
  1662. {
  1663. return DEBUG_STATUS_NO_DEBUGGEE;
  1664. }
  1665. else if (g_CmdState == 'p')
  1666. {
  1667. return DEBUG_STATUS_STEP_OVER;
  1668. }
  1669. else if (g_CmdState == 't')
  1670. {
  1671. return DEBUG_STATUS_STEP_INTO;
  1672. }
  1673. else if (g_CmdState == 'b')
  1674. {
  1675. return DEBUG_STATUS_STEP_BRANCH;
  1676. }
  1677. else if (g_CmdState == 'g' || g_CmdState == 'e')
  1678. {
  1679. return DEBUG_STATUS_GO;
  1680. }
  1681. else
  1682. {
  1683. return DEBUG_STATUS_BREAK;
  1684. }
  1685. }
  1686. STDMETHODIMP
  1687. DebugClient::GetExecutionStatus(
  1688. THIS_
  1689. OUT PULONG Status
  1690. )
  1691. {
  1692. // This method is reentrant.
  1693. *Status = ::GetExecutionStatus();
  1694. return S_OK;
  1695. }
  1696. HRESULT
  1697. SetExecutionStatus(ULONG Status)
  1698. {
  1699. // If there's an outstanding request for input don't
  1700. // allow the execution status of the engine to change
  1701. // as it could lead to a wait which cannot
  1702. // be carried out in this situation. It's better to fail
  1703. // this call and have the caller try again.
  1704. if (g_InputNesting >= 1 ||
  1705. !g_Machine)
  1706. {
  1707. return E_UNEXPECTED;
  1708. }
  1709. if (IS_RUNNING(g_CmdState))
  1710. {
  1711. // Already running.
  1712. return S_OK;
  1713. }
  1714. ADDR PcAddr;
  1715. g_Machine->GetPC(&PcAddr);
  1716. // Notifications are sent in the step/go functions.
  1717. if (Status >= DEBUG_STATUS_GO &&
  1718. Status <= DEBUG_STATUS_GO_NOT_HANDLED)
  1719. {
  1720. SetExecGo(Status, &PcAddr, NULL, FALSE, 0, NULL, NULL);
  1721. }
  1722. else
  1723. {
  1724. DBG_ASSERT(Status == DEBUG_STATUS_STEP_OVER ||
  1725. Status == DEBUG_STATUS_STEP_INTO ||
  1726. Status == DEBUG_STATUS_STEP_BRANCH);
  1727. if (g_Machine->IsStepStatusSupported(Status))
  1728. {
  1729. char StepType;
  1730. switch (Status)
  1731. {
  1732. case DEBUG_STATUS_STEP_INTO:
  1733. StepType = 't';
  1734. break;
  1735. case DEBUG_STATUS_STEP_OVER:
  1736. StepType = 'p';
  1737. break;
  1738. case DEBUG_STATUS_STEP_BRANCH:
  1739. StepType = 'b';
  1740. break;
  1741. }
  1742. SetExecStepTrace(&PcAddr, 1, NULL, FALSE, FALSE, StepType);
  1743. }
  1744. else
  1745. {
  1746. char* Mode;
  1747. switch (Status)
  1748. {
  1749. case DEBUG_STATUS_STEP_BRANCH:
  1750. Mode = "Taken branch trace";
  1751. break;
  1752. default:
  1753. Mode = "Trace";
  1754. break;
  1755. }
  1756. ErrOut("%s mode not supported\n", Mode);
  1757. return E_INVALIDARG;
  1758. }
  1759. }
  1760. return S_OK;
  1761. }
  1762. STDMETHODIMP
  1763. DebugClient::SetExecutionStatus(
  1764. THIS_
  1765. IN ULONG Status
  1766. )
  1767. {
  1768. if ((Status <= DEBUG_STATUS_NO_CHANGE || Status >= DEBUG_STATUS_BREAK) &&
  1769. Status != DEBUG_STATUS_STEP_BRANCH)
  1770. {
  1771. return E_INVALIDARG;
  1772. }
  1773. HRESULT RetStatus;
  1774. ENTER_ENGINE();
  1775. if (!IS_MACHINE_SET(g_Target))
  1776. {
  1777. RetStatus = E_UNEXPECTED;
  1778. }
  1779. else
  1780. {
  1781. RetStatus = ::SetExecutionStatus(Status);
  1782. }
  1783. LEAVE_ENGINE();
  1784. return RetStatus;
  1785. }
  1786. STDMETHODIMP
  1787. DebugClient::GetCodeLevel(
  1788. THIS_
  1789. OUT PULONG Level
  1790. )
  1791. {
  1792. ENTER_ENGINE();
  1793. if (g_SrcOptions & SRCOPT_STEP_SOURCE)
  1794. {
  1795. *Level = DEBUG_LEVEL_SOURCE;
  1796. }
  1797. else
  1798. {
  1799. *Level = DEBUG_LEVEL_ASSEMBLY;
  1800. }
  1801. LEAVE_ENGINE();
  1802. return S_OK;
  1803. }
  1804. STDMETHODIMP
  1805. DebugClient::SetCodeLevel(
  1806. THIS_
  1807. IN ULONG Level
  1808. )
  1809. {
  1810. ENTER_ENGINE();
  1811. HRESULT Status = S_OK;
  1812. ULONG OldSrcOpt = g_SrcOptions;
  1813. switch(Level)
  1814. {
  1815. case DEBUG_LEVEL_ASSEMBLY:
  1816. g_SrcOptions &= ~SRCOPT_STEP_SOURCE;
  1817. break;
  1818. case DEBUG_LEVEL_SOURCE:
  1819. g_SrcOptions |= SRCOPT_STEP_SOURCE;
  1820. break;
  1821. default:
  1822. Status = E_INVALIDARG;
  1823. break;
  1824. }
  1825. if ((OldSrcOpt ^ g_SrcOptions) & SRCOPT_STEP_SOURCE)
  1826. {
  1827. NotifyChangeEngineState(DEBUG_CES_CODE_LEVEL,
  1828. (g_SrcOptions & SRCOPT_STEP_SOURCE) ?
  1829. DEBUG_LEVEL_SOURCE : DEBUG_LEVEL_ASSEMBLY,
  1830. TRUE);
  1831. }
  1832. LEAVE_ENGINE();
  1833. return Status;
  1834. }
  1835. STDMETHODIMP
  1836. DebugClient::GetEngineOptions(
  1837. THIS_
  1838. OUT PULONG Options
  1839. )
  1840. {
  1841. // This method is reentrant.
  1842. *Options = g_EngOptions;
  1843. return S_OK;
  1844. }
  1845. HRESULT
  1846. SetEngOptions(ULONG Options)
  1847. {
  1848. if (g_EngOptions != Options)
  1849. {
  1850. // Make sure allow and disallow network paths aren't both on.
  1851. if ((Options & ~DEBUG_ENGOPT_ALL) ||
  1852. ((Options & DEBUG_ENGOPT_NETWORK_PATHS) ==
  1853. DEBUG_ENGOPT_NETWORK_PATHS))
  1854. {
  1855. return E_INVALIDARG;
  1856. }
  1857. // Security options cannot be disabled.
  1858. if ((g_EngOptions & DEBUG_ENGOPT_DISALLOW_SHELL_COMMANDS) &&
  1859. !(Options & DEBUG_ENGOPT_DISALLOW_SHELL_COMMANDS))
  1860. {
  1861. return E_INVALIDARG;
  1862. }
  1863. g_EngOptions = Options;
  1864. ULONG Notify = DEBUG_CES_ENGINE_OPTIONS;
  1865. ULONG64 Arg = Options;
  1866. if (SyncFiltersWithOptions())
  1867. {
  1868. Notify |= DEBUG_CES_EVENT_FILTERS;
  1869. Arg = DEBUG_ANY_ID;
  1870. }
  1871. // XXX drewb - Notification without any lock.
  1872. NotifyChangeEngineState(Notify, Arg, FALSE);
  1873. }
  1874. return S_OK;
  1875. }
  1876. STDMETHODIMP
  1877. DebugClient::AddEngineOptions(
  1878. THIS_
  1879. IN ULONG Options
  1880. )
  1881. {
  1882. // This method is reentrant.
  1883. return SetEngOptions(g_EngOptions | Options);
  1884. }
  1885. STDMETHODIMP
  1886. DebugClient::RemoveEngineOptions(
  1887. THIS_
  1888. IN ULONG Options
  1889. )
  1890. {
  1891. // This method is reentrant.
  1892. return SetEngOptions(g_EngOptions & ~Options);
  1893. }
  1894. STDMETHODIMP
  1895. DebugClient::SetEngineOptions(
  1896. THIS_
  1897. IN ULONG Options
  1898. )
  1899. {
  1900. // This method is reentrant.
  1901. return SetEngOptions(Options);
  1902. }
  1903. STDMETHODIMP
  1904. DebugClient::GetSystemErrorControl(
  1905. THIS_
  1906. OUT PULONG OutputLevel,
  1907. OUT PULONG BreakLevel
  1908. )
  1909. {
  1910. ENTER_ENGINE();
  1911. *OutputLevel = g_SystemErrorOutput;
  1912. *BreakLevel = g_SystemErrorBreak;
  1913. LEAVE_ENGINE();
  1914. return S_OK;
  1915. }
  1916. STDMETHODIMP
  1917. DebugClient::SetSystemErrorControl(
  1918. THIS_
  1919. IN ULONG OutputLevel,
  1920. IN ULONG BreakLevel
  1921. )
  1922. {
  1923. if (OutputLevel > SLE_WARNING ||
  1924. BreakLevel > SLE_WARNING)
  1925. {
  1926. return E_INVALIDARG;
  1927. }
  1928. ENTER_ENGINE();
  1929. g_SystemErrorOutput = OutputLevel;
  1930. g_SystemErrorBreak = BreakLevel;
  1931. LEAVE_ENGINE();
  1932. return S_OK;
  1933. }
  1934. STDMETHODIMP
  1935. DebugClient::GetTextMacro(
  1936. THIS_
  1937. IN ULONG Slot,
  1938. OUT OPTIONAL PSTR Buffer,
  1939. IN ULONG BufferSize,
  1940. OUT OPTIONAL PULONG MacroSize
  1941. )
  1942. {
  1943. if (Slot >= REG_USER_COUNT)
  1944. {
  1945. return E_INVALIDARG;
  1946. }
  1947. HRESULT Status;
  1948. ENTER_ENGINE();
  1949. Status = FillStringBuffer(GetUserReg(REG_USER_FIRST + Slot), 0,
  1950. Buffer, BufferSize, MacroSize);
  1951. LEAVE_ENGINE();
  1952. return Status;
  1953. }
  1954. STDMETHODIMP
  1955. DebugClient::SetTextMacro(
  1956. THIS_
  1957. IN ULONG Slot,
  1958. IN PCSTR Macro
  1959. )
  1960. {
  1961. if (Slot >= REG_USER_COUNT)
  1962. {
  1963. return E_INVALIDARG;
  1964. }
  1965. HRESULT Status;
  1966. ENTER_ENGINE();
  1967. Status = SetUserReg(REG_USER_FIRST + Slot, Macro) ? S_OK : E_OUTOFMEMORY;
  1968. LEAVE_ENGINE();
  1969. return Status;
  1970. }
  1971. STDMETHODIMP
  1972. DebugClient::GetRadix(
  1973. THIS_
  1974. OUT PULONG Radix
  1975. )
  1976. {
  1977. ENTER_ENGINE();
  1978. *Radix = g_DefaultRadix;
  1979. LEAVE_ENGINE();
  1980. return S_OK;
  1981. }
  1982. STDMETHODIMP
  1983. DebugClient::SetRadix(
  1984. THIS_
  1985. IN ULONG Radix
  1986. )
  1987. {
  1988. if (Radix != 8 && Radix != 10 && Radix != 16)
  1989. {
  1990. return E_INVALIDARG;
  1991. }
  1992. ENTER_ENGINE();
  1993. g_DefaultRadix = Radix;
  1994. NotifyChangeEngineState(DEBUG_CES_RADIX, g_DefaultRadix, TRUE);
  1995. LEAVE_ENGINE();
  1996. return S_OK;
  1997. }
  1998. STDMETHODIMP
  1999. DebugClient::Evaluate(
  2000. THIS_
  2001. IN PCSTR Expression,
  2002. IN ULONG DesiredType,
  2003. OUT PDEBUG_VALUE Value,
  2004. OUT OPTIONAL PULONG RemainderIndex
  2005. )
  2006. {
  2007. char Copy[MAX_COMMAND];
  2008. if (Expression == NULL ||
  2009. strlen(Expression) >= sizeof(Copy))
  2010. {
  2011. return E_INVALIDARG;
  2012. }
  2013. HRESULT Status;
  2014. ENTER_ENGINE();
  2015. if (!IS_CUR_MACHINE_ACCESSIBLE())
  2016. {
  2017. Status = E_UNEXPECTED;
  2018. goto Exit;
  2019. }
  2020. PSTR SaveCommand;
  2021. PSTR SaveStart;
  2022. // This Evaluate may be coming from an extension invoked
  2023. // from a command so save all command state.
  2024. SaveCommand = g_CurCmd;
  2025. SaveStart = g_CommandStart;
  2026. g_DisableErrorPrint++;
  2027. // Copy const string to buffer to avoid read-only memory
  2028. // AVs as the command is modified during parsing.
  2029. strcpy(Copy, Expression);
  2030. g_CurCmd = Copy;
  2031. g_CommandStart = Copy;
  2032. RemoveDelChar(g_CurCmd);
  2033. ExpandUserRegs(Copy, DIMA(Copy));
  2034. __try
  2035. {
  2036. TypedData Result;
  2037. EvalExpression* Eval = GetCurEvaluator();
  2038. Eval->EvalCurrent(&Result);
  2039. ReleaseEvaluator(Eval);
  2040. if (Result.IsFloat())
  2041. {
  2042. if (Result.ConvertToF64())
  2043. {
  2044. Status = E_FAIL;
  2045. __leave;
  2046. }
  2047. Value->F64 = Result.m_F64;
  2048. Value->Type = DEBUG_VALUE_FLOAT64;
  2049. }
  2050. else
  2051. {
  2052. if (Result.ConvertToU64())
  2053. {
  2054. Status = E_FAIL;
  2055. __leave;
  2056. }
  2057. Value->I64 = Result.m_U64;
  2058. Value->Type = DEBUG_VALUE_INT64;
  2059. }
  2060. if (RemainderIndex != NULL)
  2061. {
  2062. *RemainderIndex = (ULONG)(g_CurCmd - g_CommandStart);
  2063. }
  2064. if (DesiredType != DEBUG_VALUE_INVALID &&
  2065. DesiredType != Value->Type)
  2066. {
  2067. DEBUG_VALUE Natural = *Value;
  2068. Status = CoerceValue(&Natural, DesiredType, Value);
  2069. }
  2070. else
  2071. {
  2072. Status = S_OK;
  2073. }
  2074. }
  2075. __except(CommandExceptionFilter(GetExceptionInformation()))
  2076. {
  2077. Status = E_FAIL;
  2078. }
  2079. g_DisableErrorPrint--;
  2080. g_CurCmd = SaveCommand;
  2081. g_CommandStart = SaveStart;
  2082. Exit:
  2083. LEAVE_ENGINE();
  2084. return Status;
  2085. }
  2086. #define IS_INT(Type) \
  2087. ((Type) >= DEBUG_VALUE_INT8 && (Type) <= DEBUG_VALUE_INT64)
  2088. #define IS_FLOAT(Type) \
  2089. ((Type) >= DEBUG_VALUE_FLOAT32 && (Type) <= DEBUG_VALUE_FLOAT128)
  2090. #define IS_VECTOR(Type) \
  2091. ((Type) >= DEBUG_VALUE_VECTOR64 && (Type) <= DEBUG_VALUE_VECTOR128)
  2092. STDMETHODIMP
  2093. DebugClient::CoerceValue(
  2094. THIS_
  2095. IN PDEBUG_VALUE In,
  2096. IN ULONG OutType,
  2097. OUT PDEBUG_VALUE Out
  2098. )
  2099. {
  2100. if (In->Type < DEBUG_VALUE_INT8 || In->Type >= DEBUG_VALUE_TYPES ||
  2101. OutType < DEBUG_VALUE_INT8 || OutType >= DEBUG_VALUE_TYPES)
  2102. {
  2103. return E_INVALIDARG;
  2104. }
  2105. if (In->Type == OutType)
  2106. {
  2107. *Out = *In;
  2108. return S_OK;
  2109. }
  2110. ENTER_ENGINE();
  2111. ZeroMemory(Out, sizeof(*Out));
  2112. Out->Type = OutType;
  2113. DEBUG_VALUE Inter;
  2114. char FloatStr[64];
  2115. ZeroMemory(&Inter, sizeof(Inter));
  2116. // Convert the input type to the largest
  2117. // matching type for intermediate operations.
  2118. switch(In->Type)
  2119. {
  2120. case DEBUG_VALUE_INT8:
  2121. Inter.I64 = In->I8;
  2122. Inter.Nat = FALSE;
  2123. break;
  2124. case DEBUG_VALUE_INT16:
  2125. Inter.I64 = In->I16;
  2126. Inter.Nat = FALSE;
  2127. break;
  2128. case DEBUG_VALUE_INT32:
  2129. Inter.I64 = In->I32;
  2130. Inter.Nat = FALSE;
  2131. break;
  2132. case DEBUG_VALUE_INT64:
  2133. Inter.I64 = In->I64;
  2134. Inter.Nat = In->Nat;
  2135. break;
  2136. case DEBUG_VALUE_FLOAT32:
  2137. // XXX drewb - Use direct conversion.
  2138. PrintString(FloatStr, DIMA(FloatStr), "%10g", In->F32);
  2139. _atoldbl((_ULDOUBLE*)Inter.RawBytes, FloatStr);
  2140. break;
  2141. case DEBUG_VALUE_FLOAT64:
  2142. // XXX drewb - Use direct conversion.
  2143. PrintString(FloatStr, DIMA(FloatStr), "%10lg", In->F64);
  2144. _atoldbl((_ULDOUBLE*)Inter.RawBytes, FloatStr);
  2145. break;
  2146. case DEBUG_VALUE_FLOAT80:
  2147. memcpy(Inter.RawBytes, In->F80Bytes, sizeof(In->F80Bytes));
  2148. break;
  2149. case DEBUG_VALUE_FLOAT82:
  2150. FLOAT128 f82;
  2151. memcpy(&f82, &(In->F82Bytes),
  2152. min(sizeof(f82), sizeof(In->F82Bytes)));
  2153. double f;
  2154. f = Float82ToDouble(&f82);
  2155. PrintString(FloatStr, DIMA(FloatStr), "%10g", f);
  2156. _atoldbl((_ULDOUBLE*)Inter.RawBytes, FloatStr);
  2157. break;
  2158. case DEBUG_VALUE_FLOAT128:
  2159. // XXX drewb - What's the format? How should this be supported.
  2160. memcpy(Inter.RawBytes, In->F128Bytes, sizeof(In->F128Bytes));
  2161. break;
  2162. case DEBUG_VALUE_VECTOR64:
  2163. memcpy(Inter.RawBytes, In->RawBytes, 8);
  2164. break;
  2165. case DEBUG_VALUE_VECTOR128:
  2166. memcpy(Inter.RawBytes, In->RawBytes, 16);
  2167. break;
  2168. default:
  2169. DBG_ASSERT(FALSE);
  2170. break;
  2171. }
  2172. // Convert between float, int and vector. There's
  2173. // no way to know what kind of data is in a vector
  2174. // so the raw bytes are just used directly.
  2175. if (IS_INT(In->Type) &&
  2176. IS_FLOAT(OutType))
  2177. {
  2178. // XXX drewb - Use direct conversion.
  2179. PrintString(FloatStr, DIMA(FloatStr), "%I64u", Inter.I64);
  2180. _atoldbl((_ULDOUBLE*)Inter.RawBytes, FloatStr);
  2181. }
  2182. else if (IS_FLOAT(In->Type) &&
  2183. IS_INT(OutType))
  2184. {
  2185. double TmpDbl;
  2186. // XXX drewb - Use direct conversion.
  2187. _uldtoa((_ULDOUBLE*)Inter.RawBytes, sizeof(FloatStr), FloatStr);
  2188. if (sscanf(FloatStr, "%lg", &TmpDbl) != 1)
  2189. {
  2190. TmpDbl = 0.0;
  2191. }
  2192. Inter.I64 = (ULONG64)TmpDbl;
  2193. Inter.Nat = FALSE;
  2194. }
  2195. // Convert the intermediate value down to the
  2196. // appropriate output size.
  2197. switch(OutType)
  2198. {
  2199. case DEBUG_VALUE_INT8:
  2200. Out->I8 = (UCHAR)Inter.I64;
  2201. break;
  2202. case DEBUG_VALUE_INT16:
  2203. Out->I16 = (USHORT)Inter.I64;
  2204. break;
  2205. case DEBUG_VALUE_INT32:
  2206. Out->I32 = (ULONG)Inter.I64;
  2207. break;
  2208. case DEBUG_VALUE_INT64:
  2209. Out->I64 = Inter.I64;
  2210. Out->Nat = Inter.Nat;
  2211. break;
  2212. case DEBUG_VALUE_FLOAT32:
  2213. // XXX drewb - Use direct conversion.
  2214. _uldtoa((_ULDOUBLE*)Inter.RawBytes, sizeof(FloatStr), FloatStr);
  2215. if (sscanf(FloatStr, "%g", &Out->F32) != 1)
  2216. {
  2217. Out->F32 = 0.0f;
  2218. }
  2219. break;
  2220. case DEBUG_VALUE_FLOAT64:
  2221. // XXX drewb - Use direct conversion.
  2222. _uldtoa((_ULDOUBLE*)Inter.RawBytes, sizeof(FloatStr), FloatStr);
  2223. if (sscanf(FloatStr, "%lg", &Out->F64) != 1)
  2224. {
  2225. Out->F64 = 0.0;
  2226. }
  2227. break;
  2228. case DEBUG_VALUE_FLOAT80:
  2229. memcpy(Out->F80Bytes, Inter.RawBytes, sizeof(Out->F80Bytes));
  2230. break;
  2231. case DEBUG_VALUE_FLOAT82:
  2232. _uldtoa((_ULDOUBLE*)Inter.RawBytes, sizeof(FloatStr), FloatStr);
  2233. double f;
  2234. if (sscanf(FloatStr, "%lg", &f) != 1)
  2235. {
  2236. f = 0.0;
  2237. }
  2238. FLOAT128 f82;
  2239. DoubleToFloat82(f, &f82);
  2240. memcpy(&(Out->F82Bytes), &f82,
  2241. min(sizeof(Out->F82Bytes), sizeof(f82)));
  2242. break;
  2243. case DEBUG_VALUE_FLOAT128:
  2244. // XXX drewb - What's the format? How should this be supported.
  2245. memcpy(Out->F128Bytes, Inter.RawBytes, sizeof(Out->F128Bytes));
  2246. break;
  2247. case DEBUG_VALUE_VECTOR64:
  2248. memcpy(Out->RawBytes, Inter.RawBytes, 8);
  2249. break;
  2250. case DEBUG_VALUE_VECTOR128:
  2251. memcpy(Out->RawBytes, Inter.RawBytes, 16);
  2252. break;
  2253. default:
  2254. DBG_ASSERT(FALSE);
  2255. break;
  2256. }
  2257. LEAVE_ENGINE();
  2258. return S_OK;
  2259. }
  2260. STDMETHODIMP
  2261. DebugClient::CoerceValues(
  2262. THIS_
  2263. IN ULONG Count,
  2264. IN /* size_is(Count) */ PDEBUG_VALUE In,
  2265. IN /* size_is(Count) */ PULONG OutTypes,
  2266. OUT /* size_is(Count) */ PDEBUG_VALUE Out
  2267. )
  2268. {
  2269. ENTER_ENGINE();
  2270. ULONG i;
  2271. HRESULT Status, SingleStatus;
  2272. Status = S_OK;
  2273. for (i = 0; i < Count; i++)
  2274. {
  2275. SingleStatus = CoerceValue(In, *OutTypes, Out);
  2276. if (SingleStatus != S_OK)
  2277. {
  2278. // Accumulate error and mark failed value.
  2279. Status = SingleStatus;
  2280. Out->Type = DEBUG_VALUE_INVALID;
  2281. }
  2282. In++;
  2283. OutTypes++;
  2284. Out++;
  2285. }
  2286. LEAVE_ENGINE();
  2287. return Status;
  2288. }
  2289. HRESULT
  2290. Execute(DebugClient* Client, PCSTR Command, ULONG Flags)
  2291. {
  2292. char Copy[MAX_COMMAND];
  2293. ULONG Len = strlen(Command);
  2294. if (Len >= MAX_COMMAND)
  2295. {
  2296. return E_INVALIDARG;
  2297. }
  2298. BOOL AddNewLine = Len == 0 || Command[Len - 1] != '\n';
  2299. if (Flags & DEBUG_EXECUTE_ECHO)
  2300. {
  2301. dprintf("%s", Command);
  2302. if (AddNewLine)
  2303. {
  2304. dprintf("\n");
  2305. }
  2306. }
  2307. else if ((Flags & DEBUG_EXECUTE_NOT_LOGGED) == 0)
  2308. {
  2309. lprintf(Command);
  2310. if (AddNewLine)
  2311. {
  2312. lprintf("\n");
  2313. }
  2314. }
  2315. HRESULT Status;
  2316. PSTR SaveCommand;
  2317. PSTR SaveStart;
  2318. // This Execute may be coming from an extension invoked
  2319. // from a command so save all command state.
  2320. SaveCommand = g_CurCmd;
  2321. SaveStart = g_CommandStart;
  2322. // Copy const string to buffer to avoid read-only memory
  2323. // AVs as the command is modified during parsing.
  2324. strcpy(Copy, Command);
  2325. g_CurCmd = Copy;
  2326. g_CommandStart = Copy;
  2327. RemoveDelChar(g_CurCmd);
  2328. ExpandUserRegs(Copy, DIMA(Copy));
  2329. ReplaceAliases(g_CurCmd, MAX_COMMAND);
  2330. if ((Flags & DEBUG_EXECUTE_NO_REPEAT) == 0 &&
  2331. (g_EngOptions & DEBUG_ENGOPT_NO_EXECUTE_REPEAT) == 0)
  2332. {
  2333. if (Copy[0] == 0)
  2334. {
  2335. strcpy(Copy, g_LastCommand);
  2336. }
  2337. else
  2338. {
  2339. strcpy(g_LastCommand, Copy);
  2340. }
  2341. }
  2342. for (;;)
  2343. {
  2344. Status = ProcessCommandsAndCatch(Client);
  2345. // If we're switching processors (g_CmdState == 's')
  2346. // we have to wait to allow the switch to occur.
  2347. if (g_CmdState != 's' &&
  2348. (Status != S_FALSE ||
  2349. (g_EngStatus & ENG_STATUS_NO_AUTO_WAIT)))
  2350. {
  2351. break;
  2352. }
  2353. if ((g_CmdState != 's' ||
  2354. !IS_CONN_KERNEL_TARGET(g_Target) ||
  2355. ((ConnLiveKernelTargetInfo*)g_Target)->
  2356. m_Transport->m_WaitingThread != 0) &&
  2357. GetCurrentThreadId() != g_SessionThread)
  2358. {
  2359. ErrOut("Non-primary client caused an implicit wait\n");
  2360. Status = E_FAIL;
  2361. break;
  2362. }
  2363. if ((Status =
  2364. RawWaitForEvent(DEBUG_WAIT_DEFAULT, INFINITE)) != S_OK)
  2365. {
  2366. break;
  2367. }
  2368. }
  2369. g_CurCmd = SaveCommand;
  2370. g_CommandStart = SaveStart;
  2371. return Status;
  2372. }
  2373. #define ALL_EXECUTE_FLAGS \
  2374. (DEBUG_EXECUTE_DEFAULT | \
  2375. DEBUG_EXECUTE_ECHO | \
  2376. DEBUG_EXECUTE_NOT_LOGGED | \
  2377. DEBUG_EXECUTE_NO_REPEAT)
  2378. STDMETHODIMP
  2379. DebugClient::Execute(
  2380. THIS_
  2381. IN ULONG OutputControl,
  2382. IN PCSTR Command,
  2383. IN ULONG Flags
  2384. )
  2385. {
  2386. if ((Flags & ~ALL_EXECUTE_FLAGS) ||
  2387. strlen(Command) >= MAX_COMMAND)
  2388. {
  2389. return E_INVALIDARG;
  2390. }
  2391. // We can't do a blanket IS_MACHINE_ACCESSIBLE check
  2392. // here as Execute's commands have a mix of requirements.
  2393. // Individual commands should check when necessary.
  2394. HRESULT Status;
  2395. ENTER_ENGINE();
  2396. OutCtlSave OldCtl;
  2397. if (!PushOutCtl(OutputControl, this, &OldCtl))
  2398. {
  2399. Status = E_INVALIDARG;
  2400. }
  2401. else
  2402. {
  2403. Status = ::Execute(this, Command, Flags);
  2404. PopOutCtl(&OldCtl);
  2405. }
  2406. LEAVE_ENGINE();
  2407. return Status;
  2408. }
  2409. HRESULT
  2410. ExecuteCommandFile(DebugClient* Client, PCSTR CommandFile, ULONG Flags)
  2411. {
  2412. HRESULT Status;
  2413. FILE* File;
  2414. File = fopen(CommandFile, "r");
  2415. if (File == NULL)
  2416. {
  2417. Status = HRESULT_FROM_WIN32(_doserrno);
  2418. }
  2419. else
  2420. {
  2421. char Command[MAX_COMMAND + 1];
  2422. va_list VaUnused;
  2423. // This value is only used as a placeholder so
  2424. // it doesn't really matter what it's initialized to.
  2425. ZeroMemory(&VaUnused, sizeof(VaUnused));
  2426. for (;;)
  2427. {
  2428. ULONG Len;
  2429. Command[sizeof(Command) - 2] = 0;
  2430. if (fgets(Command, sizeof(Command) - 1, File) == NULL)
  2431. {
  2432. if (feof(File))
  2433. {
  2434. Status = S_OK;
  2435. }
  2436. else
  2437. {
  2438. Status = E_FAIL;
  2439. }
  2440. break;
  2441. }
  2442. if (Command[sizeof(Command) - 2] != 0)
  2443. {
  2444. // Input line is too long.
  2445. Status = E_INVALIDARG;
  2446. break;
  2447. }
  2448. //
  2449. // If the line didn't end with a newline force it
  2450. // to have one for consistency.
  2451. //
  2452. Len = strlen(Command);
  2453. if (Len > 0 && Command[Len - 1] != '\n')
  2454. {
  2455. Command[Len] = '\n';
  2456. Command[Len + 1] = 0;
  2457. }
  2458. if (Flags & DEBUG_EXECUTE_ECHO)
  2459. {
  2460. OutputPrompt(" ", VaUnused);
  2461. // Command has a new-line built in.
  2462. dprintf("%s", Command);
  2463. }
  2464. else if ((Flags & DEBUG_EXECUTE_NOT_LOGGED) == 0)
  2465. {
  2466. ULONG OutCtl;
  2467. // Restrict output to the log only.
  2468. OutCtl = g_OutputControl;
  2469. g_OutputControl = (OutCtl & ~DEBUG_OUTCTL_SEND_MASK) |
  2470. DEBUG_OUTCTL_LOG_ONLY;
  2471. OutputPrompt(" ", VaUnused);
  2472. // Command has a new-line built in.
  2473. dprintf("%s", Command);
  2474. g_OutputControl = OutCtl;
  2475. }
  2476. // If a command exception is thrown we don't want to
  2477. // terminate execution of the script, so specifically
  2478. // check for the status code which indicates that
  2479. // an exception occurred and ignore it.
  2480. Status = Execute(Client, Command, DEBUG_EXECUTE_NOT_LOGGED |
  2481. (Flags & ~DEBUG_EXECUTE_ECHO));
  2482. if (Status != S_OK && Status != HR_PROCESS_EXCEPTION)
  2483. {
  2484. break;
  2485. }
  2486. }
  2487. fclose(File);
  2488. }
  2489. return Status;
  2490. }
  2491. STDMETHODIMP
  2492. DebugClient::ExecuteCommandFile(
  2493. THIS_
  2494. IN ULONG OutputControl,
  2495. IN PCSTR CommandFile,
  2496. IN ULONG Flags
  2497. )
  2498. {
  2499. if (Flags & ~ALL_EXECUTE_FLAGS)
  2500. {
  2501. return E_INVALIDARG;
  2502. }
  2503. // We can't do a blanket IS_MACHINE_ACCESSIBLE check
  2504. // here as Execute's commands have a mix of requirements.
  2505. // Individual commands should check when necessary.
  2506. HRESULT Status;
  2507. ENTER_ENGINE();
  2508. OutCtlSave OldCtl;
  2509. if (!PushOutCtl(OutputControl, this, &OldCtl))
  2510. {
  2511. return E_INVALIDARG;
  2512. }
  2513. else
  2514. {
  2515. Status = ::ExecuteCommandFile(this, CommandFile, Flags);
  2516. PopOutCtl(&OldCtl);
  2517. }
  2518. LEAVE_ENGINE();
  2519. return Status;
  2520. }
  2521. STDMETHODIMP
  2522. DebugClient::GetNumberBreakpoints(
  2523. THIS_
  2524. OUT PULONG Number
  2525. )
  2526. {
  2527. HRESULT Status;
  2528. ENTER_ENGINE();
  2529. if (g_Process == NULL)
  2530. {
  2531. Status = E_UNEXPECTED;
  2532. }
  2533. else
  2534. {
  2535. *Number = g_Process->m_NumBreakpoints;
  2536. Status = S_OK;
  2537. }
  2538. LEAVE_ENGINE();
  2539. return Status;
  2540. }
  2541. STDMETHODIMP
  2542. DebugClient::GetBreakpointByIndex(
  2543. THIS_
  2544. IN ULONG Index,
  2545. OUT PDEBUG_BREAKPOINT* RetBp
  2546. )
  2547. {
  2548. HRESULT Status;
  2549. ENTER_ENGINE();
  2550. if (g_Process == NULL)
  2551. {
  2552. Status = E_UNEXPECTED;
  2553. }
  2554. else
  2555. {
  2556. Breakpoint* Bp = ::GetBreakpointByIndex(this, Index);
  2557. if (Bp != NULL)
  2558. {
  2559. Bp->AddRef();
  2560. *RetBp = Bp;
  2561. Status = S_OK;
  2562. }
  2563. else
  2564. {
  2565. Status = E_NOINTERFACE;
  2566. }
  2567. }
  2568. LEAVE_ENGINE();
  2569. return Status;
  2570. }
  2571. STDMETHODIMP
  2572. DebugClient::GetBreakpointById(
  2573. THIS_
  2574. IN ULONG Id,
  2575. OUT PDEBUG_BREAKPOINT* RetBp
  2576. )
  2577. {
  2578. HRESULT Status;
  2579. ENTER_ENGINE();
  2580. if (g_Process == NULL)
  2581. {
  2582. Status = E_UNEXPECTED;
  2583. }
  2584. else
  2585. {
  2586. Breakpoint* Bp = ::GetBreakpointById(this, Id);
  2587. if (Bp != NULL)
  2588. {
  2589. Bp->AddRef();
  2590. *RetBp = Bp;
  2591. Status = S_OK;
  2592. }
  2593. else
  2594. {
  2595. Status = E_NOINTERFACE;
  2596. }
  2597. }
  2598. LEAVE_ENGINE();
  2599. return Status;
  2600. }
  2601. STDMETHODIMP
  2602. DebugClient::GetBreakpointParameters(
  2603. THIS_
  2604. IN ULONG Count,
  2605. IN OPTIONAL /* size_is(Count) */ PULONG Ids,
  2606. IN ULONG Start,
  2607. OUT /* size_is(Count) */ PDEBUG_BREAKPOINT_PARAMETERS Params
  2608. )
  2609. {
  2610. HRESULT Status;
  2611. ENTER_ENGINE();
  2612. if (g_Process == NULL)
  2613. {
  2614. Status = E_UNEXPECTED;
  2615. }
  2616. else
  2617. {
  2618. ULONG i;
  2619. Breakpoint* Bp;
  2620. Status = S_OK;
  2621. for (i = 0; i < Count; i++)
  2622. {
  2623. if (Ids != NULL)
  2624. {
  2625. Bp = ::GetBreakpointById(this, *Ids++);
  2626. }
  2627. else
  2628. {
  2629. Bp = ::GetBreakpointByIndex(this, Start++);
  2630. }
  2631. if (Bp == NULL)
  2632. {
  2633. ZeroMemory(Params, sizeof(*Params));
  2634. Params->Id = DEBUG_ANY_ID;
  2635. Status = S_FALSE;
  2636. }
  2637. else
  2638. {
  2639. Bp->GetParameters(Params);
  2640. }
  2641. Params++;
  2642. }
  2643. }
  2644. LEAVE_ENGINE();
  2645. return Status;
  2646. }
  2647. STDMETHODIMP
  2648. DebugClient::AddBreakpoint(
  2649. THIS_
  2650. IN ULONG Type,
  2651. IN ULONG DesiredId,
  2652. OUT PDEBUG_BREAKPOINT* Bp
  2653. )
  2654. {
  2655. if (
  2656. #if DEBUG_BREAKPOINT_CODE > 0
  2657. Type < DEBUG_BREAKPOINT_CODE ||
  2658. #endif
  2659. Type > DEBUG_BREAKPOINT_DATA)
  2660. {
  2661. return E_INVALIDARG;
  2662. }
  2663. HRESULT Status;
  2664. ENTER_ENGINE();
  2665. if (!IS_MACHINE_SET(g_Target) || !g_Process)
  2666. {
  2667. Status = E_UNEXPECTED;
  2668. }
  2669. else
  2670. {
  2671. Status = ::AddBreakpoint(this, g_Target->m_EffMachine,
  2672. Type, DesiredId, (Breakpoint**)Bp);
  2673. }
  2674. LEAVE_ENGINE();
  2675. return Status;
  2676. }
  2677. STDMETHODIMP
  2678. DebugClient::RemoveBreakpoint(
  2679. THIS_
  2680. IN PDEBUG_BREAKPOINT Bp
  2681. )
  2682. {
  2683. HRESULT Status;
  2684. ENTER_ENGINE();
  2685. if (g_Process == NULL)
  2686. {
  2687. Status = E_UNEXPECTED;
  2688. }
  2689. else
  2690. {
  2691. ::RemoveBreakpoint((Breakpoint*)Bp);
  2692. Status = S_OK;
  2693. }
  2694. LEAVE_ENGINE();
  2695. return Status;
  2696. }
  2697. STDMETHODIMP
  2698. DebugClient::AddExtension(
  2699. THIS_
  2700. IN PCSTR Path,
  2701. IN ULONG Flags,
  2702. OUT PULONG64 Handle
  2703. )
  2704. {
  2705. if (Flags & ~(DEBUG_EXTENSION_AT_ENGINE))
  2706. {
  2707. return E_INVALIDARG;
  2708. }
  2709. // Remote extensions aren't supported at the moment.
  2710. if (Flags != DEBUG_EXTENSION_AT_ENGINE)
  2711. {
  2712. return E_NOTIMPL;
  2713. }
  2714. HRESULT Status;
  2715. ENTER_ENGINE();
  2716. char* End;
  2717. EXTDLL* Ext;
  2718. if ((Ext = AddExtensionDll((PSTR)Path, TRUE, NULL, &End)) == NULL)
  2719. {
  2720. Status = E_OUTOFMEMORY;
  2721. }
  2722. else
  2723. {
  2724. *Handle = (ULONG64)Ext;
  2725. Status = S_OK;
  2726. }
  2727. LEAVE_ENGINE();
  2728. return Status;
  2729. }
  2730. STDMETHODIMP
  2731. DebugClient::RemoveExtension(
  2732. THIS_
  2733. IN ULONG64 Handle
  2734. )
  2735. {
  2736. ENTER_ENGINE();
  2737. UnloadExtensionDll((EXTDLL*)Handle, FALSE);
  2738. LEAVE_ENGINE();
  2739. return S_OK;
  2740. }
  2741. STDMETHODIMP
  2742. DebugClient::GetExtensionByPath(
  2743. THIS_
  2744. IN PCSTR Path,
  2745. OUT PULONG64 Handle
  2746. )
  2747. {
  2748. HRESULT Status;
  2749. ENTER_ENGINE();
  2750. EXTDLL* Ext;
  2751. Status = E_NOINTERFACE;
  2752. for (Ext = g_ExtDlls; Ext != NULL; Ext = Ext->Next)
  2753. {
  2754. if ((!Ext->Target || Ext->Target == g_Target) &&
  2755. !_strcmpi(Path, Ext->Name))
  2756. {
  2757. Status = S_OK;
  2758. *Handle = (ULONG64)Ext;
  2759. break;
  2760. }
  2761. }
  2762. LEAVE_ENGINE();
  2763. return Status;
  2764. }
  2765. STDMETHODIMP
  2766. DebugClient::CallExtension(
  2767. THIS_
  2768. IN OPTIONAL ULONG64 Handle,
  2769. IN PCSTR Function,
  2770. IN OPTIONAL PCSTR Arguments
  2771. )
  2772. {
  2773. char LocalFunc[MAX_COMMAND];
  2774. ULONG Len;
  2775. // Copy function name to temp buffer because it is
  2776. // modified.
  2777. Len = strlen(Function) + 1;
  2778. if (Len > sizeof(LocalFunc))
  2779. {
  2780. return E_INVALIDARG;
  2781. }
  2782. memcpy(LocalFunc, Function, Len);
  2783. HRESULT Status;
  2784. ENTER_ENGINE();
  2785. if (!IS_CUR_MACHINE_ACCESSIBLE())
  2786. {
  2787. Status = E_UNEXPECTED;
  2788. }
  2789. else if (!CallAnyExtension(this, (EXTDLL*)Handle, LocalFunc, Arguments,
  2790. Handle != 0, TRUE, &Status))
  2791. {
  2792. Status = E_FAIL;
  2793. }
  2794. LEAVE_ENGINE();
  2795. return Status;
  2796. }
  2797. STDMETHODIMP
  2798. DebugClient::GetExtensionFunction(
  2799. THIS_
  2800. IN ULONG64 Handle,
  2801. IN PCSTR FuncName,
  2802. OUT FARPROC* Function
  2803. )
  2804. {
  2805. HRESULT Status;
  2806. char ExpName[MAX_PATH + 16];
  2807. if (strlen(FuncName) >= MAX_PATH)
  2808. {
  2809. return E_INVALIDARG;
  2810. }
  2811. // Keep the namespace for extension function exports
  2812. // separate from the namespace for extension commands.
  2813. // Extension commands are exported under the same
  2814. // name as the command, so prefix extension functions
  2815. // to make them obviously different and to avoid
  2816. // name conflicts.
  2817. strcpy(ExpName, "_EFN_");
  2818. strcat(ExpName, FuncName);
  2819. ENTER_ENGINE();
  2820. EXTDLL* Ext;
  2821. FARPROC Routine;
  2822. Status = E_NOINTERFACE;
  2823. if (Handle != 0)
  2824. {
  2825. Ext = (EXTDLL*)(ULONG_PTR)Handle;
  2826. }
  2827. else
  2828. {
  2829. Ext = g_ExtDlls;
  2830. }
  2831. while (Ext != NULL)
  2832. {
  2833. if ((!Ext->Target || Ext->Target == g_Target) &&
  2834. LoadExtensionDll(g_Target, Ext))
  2835. {
  2836. Routine = GetProcAddress(Ext->Dll, ExpName);
  2837. if (Routine != NULL)
  2838. {
  2839. Status = S_OK;
  2840. *Function = Routine;
  2841. break;
  2842. }
  2843. }
  2844. // If the search was limited to a single extension stop looking.
  2845. if (Handle != 0)
  2846. {
  2847. break;
  2848. }
  2849. Ext = Ext->Next;
  2850. }
  2851. LEAVE_ENGINE();
  2852. return Status;
  2853. }
  2854. STDMETHODIMP
  2855. DebugClient::GetWindbgExtensionApis32(
  2856. THIS_
  2857. IN OUT PWINDBG_EXTENSION_APIS32 Api
  2858. )
  2859. {
  2860. if (Api->nSize != sizeof(*Api))
  2861. {
  2862. return E_INVALIDARG;
  2863. }
  2864. *Api = g_WindbgExtensions32;
  2865. return S_OK;
  2866. }
  2867. STDMETHODIMP
  2868. DebugClient::GetWindbgExtensionApis64(
  2869. THIS_
  2870. IN OUT PWINDBG_EXTENSION_APIS64 Api
  2871. )
  2872. {
  2873. if (Api->nSize != sizeof(*Api))
  2874. {
  2875. return E_INVALIDARG;
  2876. }
  2877. *Api = g_WindbgExtensions64;
  2878. return S_OK;
  2879. }
  2880. STDMETHODIMP
  2881. DebugClient::GetNumberEventFilters(
  2882. THIS_
  2883. OUT PULONG SpecificEvents,
  2884. OUT PULONG SpecificExceptions,
  2885. OUT PULONG ArbitraryExceptions
  2886. )
  2887. {
  2888. ENTER_ENGINE();
  2889. *SpecificEvents = FILTER_SPECIFIC_LAST - FILTER_SPECIFIC_FIRST + 1;
  2890. *SpecificExceptions = FILTER_EXCEPTION_LAST - FILTER_EXCEPTION_FIRST + 1;
  2891. *ArbitraryExceptions = g_NumOtherExceptions;
  2892. LEAVE_ENGINE();
  2893. return S_OK;
  2894. }
  2895. STDMETHODIMP
  2896. DebugClient::GetEventFilterText(
  2897. THIS_
  2898. IN ULONG Index,
  2899. OUT OPTIONAL PSTR Buffer,
  2900. IN ULONG BufferSize,
  2901. OUT OPTIONAL PULONG TextSize
  2902. )
  2903. {
  2904. HRESULT Status;
  2905. ENTER_ENGINE();
  2906. if (Index >= FILTER_COUNT)
  2907. {
  2908. Status = E_NOINTERFACE;
  2909. }
  2910. else
  2911. {
  2912. Status = FillStringBuffer(g_EventFilters[Index].Name, 0,
  2913. Buffer, BufferSize, TextSize);
  2914. }
  2915. LEAVE_ENGINE();
  2916. return Status;
  2917. }
  2918. HRESULT
  2919. GetEitherEventFilterCommand(ULONG Index, ULONG Which,
  2920. PSTR Buffer, ULONG BufferSize, PULONG CommandSize)
  2921. {
  2922. EVENT_COMMAND* EventCommand;
  2923. if (Index < FILTER_COUNT)
  2924. {
  2925. EventCommand = &g_EventFilters[Index].Command;
  2926. }
  2927. else if ((Index - FILTER_COUNT) < g_NumOtherExceptions)
  2928. {
  2929. EventCommand = &g_OtherExceptionCommands[Index - FILTER_COUNT];
  2930. }
  2931. else
  2932. {
  2933. return E_NOINTERFACE;
  2934. }
  2935. return FillStringBuffer(EventCommand->Command[Which],
  2936. EventCommand->CommandSize[Which],
  2937. Buffer, BufferSize, CommandSize);
  2938. }
  2939. STDMETHODIMP
  2940. DebugClient::GetEventFilterCommand(
  2941. THIS_
  2942. IN ULONG Index,
  2943. OUT OPTIONAL PSTR Buffer,
  2944. IN ULONG BufferSize,
  2945. OUT OPTIONAL PULONG CommandSize
  2946. )
  2947. {
  2948. HRESULT Status;
  2949. ENTER_ENGINE();
  2950. Status = GetEitherEventFilterCommand(Index, 0, Buffer, BufferSize,
  2951. CommandSize);
  2952. LEAVE_ENGINE();
  2953. return Status;
  2954. }
  2955. HRESULT
  2956. SetEitherEventFilterCommand(DebugClient* Client, ULONG Index, ULONG Which,
  2957. PCSTR Command)
  2958. {
  2959. EVENT_COMMAND* EventCommand;
  2960. if (Index < FILTER_COUNT)
  2961. {
  2962. EventCommand = &g_EventFilters[Index].Command;
  2963. }
  2964. else if ((Index - FILTER_COUNT) < g_NumOtherExceptions)
  2965. {
  2966. EventCommand = &g_OtherExceptionCommands[Index - FILTER_COUNT];
  2967. }
  2968. else
  2969. {
  2970. return E_NOINTERFACE;
  2971. }
  2972. HRESULT Status;
  2973. Status = ChangeString(&EventCommand->Command[Which],
  2974. &EventCommand->CommandSize[Which],
  2975. Command);
  2976. if (Status == S_OK)
  2977. {
  2978. if (Index < FILTER_COUNT)
  2979. {
  2980. g_EventFilters[Index].Flags |= FILTER_CHANGED_COMMAND;
  2981. }
  2982. EventCommand->Client = Client;
  2983. NotifyChangeEngineState(DEBUG_CES_EVENT_FILTERS, Index, TRUE);
  2984. }
  2985. return Status;
  2986. }
  2987. STDMETHODIMP
  2988. DebugClient::SetEventFilterCommand(
  2989. THIS_
  2990. IN ULONG Index,
  2991. IN PCSTR Command
  2992. )
  2993. {
  2994. HRESULT Status;
  2995. ENTER_ENGINE();
  2996. Status = SetEitherEventFilterCommand(this, Index, 0, Command);
  2997. LEAVE_ENGINE();
  2998. return Status;
  2999. }
  3000. STDMETHODIMP
  3001. DebugClient::GetSpecificFilterParameters(
  3002. THIS_
  3003. IN ULONG Start,
  3004. IN ULONG Count,
  3005. OUT /* size_is(Count) */ PDEBUG_SPECIFIC_FILTER_PARAMETERS Params
  3006. )
  3007. {
  3008. if (
  3009. #if FILTER_SPECIFIC_FIRST > 0
  3010. Start < FILTER_SPECIFIC_FIRST ||
  3011. #endif
  3012. Start > FILTER_SPECIFIC_LAST ||
  3013. Start + Count > FILTER_SPECIFIC_LAST + 1)
  3014. {
  3015. return E_INVALIDARG;
  3016. }
  3017. ENTER_ENGINE();
  3018. EVENT_FILTER* Filter;
  3019. for (ULONG i = 0; i < Count; i++)
  3020. {
  3021. Filter = g_EventFilters + (Start + i);
  3022. Params[i].ExecutionOption = Filter->Params.ExecutionOption;
  3023. Params[i].ContinueOption = Filter->Params.ContinueOption;
  3024. Params[i].TextSize = strlen(Filter->Name) + 1;
  3025. Params[i].CommandSize = Filter->Command.CommandSize[0];
  3026. Params[i].ArgumentSize = Filter->Argument != NULL ?
  3027. strlen(Filter->Argument) + 1 : 0;
  3028. }
  3029. LEAVE_ENGINE();
  3030. return S_OK;
  3031. }
  3032. STDMETHODIMP
  3033. DebugClient::SetSpecificFilterParameters(
  3034. THIS_
  3035. IN ULONG Start,
  3036. IN ULONG Count,
  3037. IN /* size_is(Count) */ PDEBUG_SPECIFIC_FILTER_PARAMETERS Params
  3038. )
  3039. {
  3040. if (
  3041. #if FILTER_SPECIFIC_FIRST > 0
  3042. Start < FILTER_SPECIFIC_FIRST ||
  3043. #endif
  3044. Start > FILTER_SPECIFIC_LAST ||
  3045. Start + Count > FILTER_SPECIFIC_LAST + 1)
  3046. {
  3047. return E_INVALIDARG;
  3048. }
  3049. HRESULT Status = S_OK;
  3050. ULONG Set = 0;
  3051. ULONG SetIndex = 0;
  3052. ENTER_ENGINE();
  3053. for (ULONG i = 0; i < Count; i++)
  3054. {
  3055. if (
  3056. #if DEBUG_FILTER_BREAK > 0
  3057. Params[i].ExecutionOption >= DEBUG_FILTER_BREAK &&
  3058. #endif
  3059. Params[i].ExecutionOption <= DEBUG_FILTER_IGNORE &&
  3060. #if DEBUG_FILTER_GO_HANDLED > 0
  3061. Params[i].ContinueOption >= DEBUG_FILTER_GO_HANDLED &&
  3062. #endif
  3063. Params[i].ContinueOption <= DEBUG_FILTER_GO_NOT_HANDLED)
  3064. {
  3065. g_EventFilters[Start + i].Params.ExecutionOption =
  3066. Params[i].ExecutionOption;
  3067. g_EventFilters[Start + i].Params.ContinueOption =
  3068. Params[i].ContinueOption;
  3069. g_EventFilters[Start + i].Flags |=
  3070. FILTER_CHANGED_EXECUTION | FILTER_CHANGED_CONTINUE;
  3071. Set++;
  3072. SetIndex = i;
  3073. }
  3074. else
  3075. {
  3076. Status = E_INVALIDARG;
  3077. }
  3078. }
  3079. if (SyncOptionsWithFilters())
  3080. {
  3081. NotifyChangeEngineState(DEBUG_CES_EVENT_FILTERS |
  3082. DEBUG_CES_ENGINE_OPTIONS,
  3083. DEBUG_ANY_ID, TRUE);
  3084. }
  3085. else if (Set == 1)
  3086. {
  3087. NotifyChangeEngineState(DEBUG_CES_EVENT_FILTERS, SetIndex, TRUE);
  3088. }
  3089. else if (Set > 1)
  3090. {
  3091. NotifyChangeEngineState(DEBUG_CES_EVENT_FILTERS, DEBUG_ANY_ID, TRUE);
  3092. }
  3093. LEAVE_ENGINE();
  3094. return Status;
  3095. }
  3096. STDMETHODIMP
  3097. DebugClient::GetSpecificFilterArgument(
  3098. THIS_
  3099. IN ULONG Index,
  3100. OUT OPTIONAL PSTR Buffer,
  3101. IN ULONG BufferSize,
  3102. OUT OPTIONAL PULONG ArgumentSize
  3103. )
  3104. {
  3105. if (
  3106. #if FILTER_SPECIFIC_FIRST > 0
  3107. Index < FILTER_SPECIFIC_FIRST ||
  3108. #endif
  3109. Index > FILTER_SPECIFIC_LAST ||
  3110. g_EventFilters[Index].Argument == NULL)
  3111. {
  3112. return E_INVALIDARG;
  3113. }
  3114. HRESULT Status;
  3115. ENTER_ENGINE();
  3116. Status = FillStringBuffer(g_EventFilters[Index].Argument, 0,
  3117. Buffer, BufferSize, ArgumentSize);
  3118. LEAVE_ENGINE();
  3119. return Status;
  3120. }
  3121. STDMETHODIMP
  3122. DebugClient::SetSpecificFilterArgument(
  3123. THIS_
  3124. IN ULONG Index,
  3125. IN PCSTR Argument
  3126. )
  3127. {
  3128. ULONG Len;
  3129. if (Argument == NULL)
  3130. {
  3131. Len = 1;
  3132. }
  3133. else
  3134. {
  3135. Len = strlen(Argument) + 1;
  3136. }
  3137. if (
  3138. #if FILTER_SPECIFIC_FIRST > 0
  3139. Index < FILTER_SPECIFIC_FIRST ||
  3140. #endif
  3141. Index > FILTER_SPECIFIC_LAST ||
  3142. g_EventFilters[Index].Argument == NULL ||
  3143. Len > FILTER_MAX_ARGUMENT)
  3144. {
  3145. return E_INVALIDARG;
  3146. }
  3147. ENTER_ENGINE();
  3148. if (Argument == NULL)
  3149. {
  3150. g_EventFilters[Index].Argument[0] = 0;
  3151. }
  3152. else
  3153. {
  3154. memcpy(g_EventFilters[Index].Argument, Argument, Len);
  3155. }
  3156. if (Index == DEBUG_FILTER_UNLOAD_MODULE)
  3157. {
  3158. g_UnloadDllBase = EvalStringNumAndCatch(Argument);
  3159. }
  3160. NotifyChangeEngineState(DEBUG_CES_EVENT_FILTERS, Index, TRUE);
  3161. LEAVE_ENGINE();
  3162. return S_OK;
  3163. }
  3164. void
  3165. GetExFilterParams(PCSTR Text,
  3166. PDEBUG_EXCEPTION_FILTER_PARAMETERS InParams,
  3167. EVENT_COMMAND* InCommand,
  3168. PDEBUG_EXCEPTION_FILTER_PARAMETERS OutParams)
  3169. {
  3170. OutParams->ExecutionOption = InParams->ExecutionOption;
  3171. OutParams->ContinueOption = InParams->ContinueOption;
  3172. OutParams->TextSize = Text != NULL ? strlen(Text) + 1 : 0;
  3173. OutParams->CommandSize = InCommand->CommandSize[0];
  3174. OutParams->SecondCommandSize = InCommand->CommandSize[1];
  3175. OutParams->ExceptionCode = InParams->ExceptionCode;
  3176. }
  3177. STDMETHODIMP
  3178. DebugClient::GetExceptionFilterParameters(
  3179. THIS_
  3180. IN ULONG Count,
  3181. IN OPTIONAL /* size_is(Count) */ PULONG Codes,
  3182. IN ULONG Start,
  3183. OUT /* size_is(Count) */ PDEBUG_EXCEPTION_FILTER_PARAMETERS Params
  3184. )
  3185. {
  3186. HRESULT Status = S_OK;
  3187. ENTER_ENGINE();
  3188. ULONG i, Index;
  3189. EVENT_FILTER* Filter;
  3190. if (Codes != NULL)
  3191. {
  3192. for (i = 0; i < Count; i++)
  3193. {
  3194. // Is this a specific exception?
  3195. Filter = g_EventFilters + FILTER_EXCEPTION_FIRST;
  3196. for (Index = FILTER_EXCEPTION_FIRST;
  3197. Index <= FILTER_EXCEPTION_LAST;
  3198. Index++)
  3199. {
  3200. if (Filter->Params.ExceptionCode == Codes[i])
  3201. {
  3202. GetExFilterParams(Filter->Name, &Filter->Params,
  3203. &Filter->Command, Params + i);
  3204. break;
  3205. }
  3206. Filter++;
  3207. }
  3208. if (Index > FILTER_EXCEPTION_LAST)
  3209. {
  3210. // Is this an other exception?
  3211. for (Index = 0; Index < g_NumOtherExceptions; Index++)
  3212. {
  3213. if (g_OtherExceptionList[Index].ExceptionCode == Codes[i])
  3214. {
  3215. GetExFilterParams(NULL, g_OtherExceptionList + Index,
  3216. g_OtherExceptionCommands + Index,
  3217. Params + i);
  3218. break;
  3219. }
  3220. }
  3221. if (Index >= g_NumOtherExceptions)
  3222. {
  3223. memset(Params + i, 0xff, sizeof(*Params));
  3224. Status = E_NOINTERFACE;
  3225. }
  3226. }
  3227. }
  3228. }
  3229. else
  3230. {
  3231. for (i = 0; i < Count; i++)
  3232. {
  3233. Index = Start + i;
  3234. // Is this a specific exception?
  3235. if (Index >= FILTER_EXCEPTION_FIRST &&
  3236. Index <= FILTER_EXCEPTION_LAST)
  3237. {
  3238. Filter = g_EventFilters + Index;
  3239. GetExFilterParams(Filter->Name, &Filter->Params,
  3240. &Filter->Command, Params + i);
  3241. }
  3242. // Is this an other exception?
  3243. else if (Index >= FILTER_COUNT &&
  3244. Index < FILTER_COUNT + g_NumOtherExceptions)
  3245. {
  3246. GetExFilterParams(NULL, g_OtherExceptionList +
  3247. (Index - FILTER_COUNT),
  3248. g_OtherExceptionCommands +
  3249. (Index - FILTER_COUNT),
  3250. Params + i);
  3251. }
  3252. else
  3253. {
  3254. memset(Params + i, 0xff, sizeof(*Params));
  3255. Status = E_INVALIDARG;
  3256. }
  3257. }
  3258. }
  3259. LEAVE_ENGINE();
  3260. return Status;
  3261. }
  3262. HRESULT
  3263. SetExFilterParams(PDEBUG_EXCEPTION_FILTER_PARAMETERS InParams,
  3264. PDEBUG_EXCEPTION_FILTER_PARAMETERS OutParams)
  3265. {
  3266. if (
  3267. #if DEBUG_FILTER_BREAK > 0
  3268. InParams->ExecutionOption >= DEBUG_FILTER_BREAK &&
  3269. #endif
  3270. InParams->ExecutionOption <= DEBUG_FILTER_IGNORE &&
  3271. #if DEBUG_FILTER_GO_HANDLED > 0
  3272. InParams->ContinueOption >= DEBUG_FILTER_GO_HANDLED &&
  3273. #endif
  3274. InParams->ContinueOption <= DEBUG_FILTER_GO_NOT_HANDLED)
  3275. {
  3276. OutParams->ExecutionOption = InParams->ExecutionOption;
  3277. OutParams->ContinueOption = InParams->ContinueOption;
  3278. return S_OK;
  3279. }
  3280. else
  3281. {
  3282. return E_INVALIDARG;
  3283. }
  3284. }
  3285. HRESULT
  3286. SetOtherExFilterParams(PDEBUG_EXCEPTION_FILTER_PARAMETERS InParams,
  3287. ULONG OutIndex, PULONG Set, PULONG SetIndex)
  3288. {
  3289. HRESULT Status;
  3290. if (OutIndex < g_NumOtherExceptions)
  3291. {
  3292. if (InParams->ExecutionOption == DEBUG_FILTER_REMOVE)
  3293. {
  3294. RemoveOtherException(OutIndex);
  3295. *Set += 2;
  3296. Status = S_OK;
  3297. }
  3298. else
  3299. {
  3300. Status = SetExFilterParams(InParams,
  3301. g_OtherExceptionList + OutIndex);
  3302. if (Status == S_OK)
  3303. {
  3304. (*Set)++;
  3305. *SetIndex = OutIndex + FILTER_COUNT;
  3306. }
  3307. }
  3308. }
  3309. else
  3310. {
  3311. if (g_NumOtherExceptions == OTHER_EXCEPTION_LIST_MAX)
  3312. {
  3313. Status = E_OUTOFMEMORY;
  3314. }
  3315. else
  3316. {
  3317. OutIndex = g_NumOtherExceptions;
  3318. g_OtherExceptionList[OutIndex].ExceptionCode =
  3319. InParams->ExceptionCode;
  3320. Status = SetExFilterParams(InParams,
  3321. g_OtherExceptionList + OutIndex);
  3322. if (Status == S_OK)
  3323. {
  3324. ZeroMemory(&g_OtherExceptionCommands[OutIndex],
  3325. sizeof(g_OtherExceptionCommands[OutIndex]));
  3326. g_NumOtherExceptions++;
  3327. (*Set)++;
  3328. *SetIndex = OutIndex + FILTER_COUNT;
  3329. }
  3330. }
  3331. }
  3332. return Status;
  3333. }
  3334. STDMETHODIMP
  3335. DebugClient::SetExceptionFilterParameters(
  3336. THIS_
  3337. IN ULONG Count,
  3338. IN /* size_is(Count) */ PDEBUG_EXCEPTION_FILTER_PARAMETERS Params
  3339. )
  3340. {
  3341. HRESULT Status = S_OK;
  3342. ENTER_ENGINE();
  3343. ULONG i, Index;
  3344. EVENT_FILTER* Filter;
  3345. ULONG Set = 0;
  3346. ULONG SetIndex = 0;
  3347. for (i = 0; i < Count; i++)
  3348. {
  3349. // Is this a specific exception?
  3350. Filter = g_EventFilters + FILTER_EXCEPTION_FIRST;
  3351. for (Index = FILTER_EXCEPTION_FIRST;
  3352. Index <= FILTER_EXCEPTION_LAST;
  3353. Index++)
  3354. {
  3355. if (Filter->Params.ExceptionCode == Params[i].ExceptionCode)
  3356. {
  3357. Status = SetExFilterParams(Params + i, &Filter->Params);
  3358. if (Status == S_OK)
  3359. {
  3360. Filter->Flags |= FILTER_CHANGED_EXECUTION |
  3361. FILTER_CHANGED_CONTINUE;
  3362. Set++;
  3363. SetIndex = Index;
  3364. }
  3365. break;
  3366. }
  3367. Filter++;
  3368. }
  3369. if (Index > FILTER_EXCEPTION_LAST)
  3370. {
  3371. // Is this an other exception?
  3372. for (Index = 0; Index < g_NumOtherExceptions; Index++)
  3373. {
  3374. if (g_OtherExceptionList[Index].ExceptionCode ==
  3375. Params[i].ExceptionCode)
  3376. {
  3377. break;
  3378. }
  3379. }
  3380. Status = SetOtherExFilterParams(Params + i, Index,
  3381. &Set, &SetIndex);
  3382. }
  3383. }
  3384. if (Set == 1)
  3385. {
  3386. NotifyChangeEngineState(DEBUG_CES_EVENT_FILTERS, SetIndex, TRUE);
  3387. }
  3388. else if (Set > 1)
  3389. {
  3390. NotifyChangeEngineState(DEBUG_CES_EVENT_FILTERS, DEBUG_ANY_ID, TRUE);
  3391. }
  3392. LEAVE_ENGINE();
  3393. return Status;
  3394. }
  3395. STDMETHODIMP
  3396. DebugClient::GetExceptionFilterSecondCommand(
  3397. THIS_
  3398. IN ULONG Index,
  3399. OUT OPTIONAL PSTR Buffer,
  3400. IN ULONG BufferSize,
  3401. OUT OPTIONAL PULONG CommandSize
  3402. )
  3403. {
  3404. HRESULT Status;
  3405. ENTER_ENGINE();
  3406. Status = GetEitherEventFilterCommand(Index, 1, Buffer, BufferSize,
  3407. CommandSize);
  3408. LEAVE_ENGINE();
  3409. return Status;
  3410. }
  3411. STDMETHODIMP
  3412. DebugClient::SetExceptionFilterSecondCommand(
  3413. THIS_
  3414. IN ULONG Index,
  3415. IN PCSTR Command
  3416. )
  3417. {
  3418. if (Index <= FILTER_SPECIFIC_LAST)
  3419. {
  3420. return E_INVALIDARG;
  3421. }
  3422. HRESULT Status;
  3423. ENTER_ENGINE();
  3424. Status = SetEitherEventFilterCommand(this, Index, 1, Command);
  3425. LEAVE_ENGINE();
  3426. return Status;
  3427. }
  3428. HRESULT
  3429. WaitForAnyTarget(ULONG Flags, ULONG Timeout, ULONG EventPoss,
  3430. ULONG ElapsedTime, PULONG EventStatus)
  3431. {
  3432. HRESULT Status;
  3433. TargetInfo* Target;
  3434. if (EventPoss == 1)
  3435. {
  3436. // If there's only one source find it and do a simple wait on it.
  3437. ForAllLayersToTarget()
  3438. {
  3439. if (Target->m_EventPossible)
  3440. {
  3441. Status = Target->
  3442. WaitForEvent(Flags, Timeout,
  3443. ElapsedTime - Target->m_WaitTimeBase,
  3444. EventStatus);
  3445. Target->m_FirstWait = FALSE;
  3446. return Status;
  3447. }
  3448. }
  3449. return E_UNEXPECTED;
  3450. }
  3451. for (;;)
  3452. {
  3453. //
  3454. // Poll all the available sources for an event.
  3455. // A zero timeout is used to get through them as
  3456. // quickly as possible so events are picked up right away.
  3457. //
  3458. // Sanity check the number of possible sources to
  3459. // avoid an infinite loop if something gets confused.
  3460. EventPoss = 0;
  3461. ForAllLayersToTarget()
  3462. {
  3463. if (!Target->m_EventPossible)
  3464. {
  3465. continue;
  3466. }
  3467. EventPoss++;
  3468. Status = Target->
  3469. WaitForEvent(Flags, 0,
  3470. ElapsedTime - Target->m_WaitTimeBase,
  3471. EventStatus);
  3472. Target->m_FirstWait = FALSE;
  3473. if (Status != S_FALSE)
  3474. {
  3475. return Status;
  3476. }
  3477. // If we've exhausted the timeout period return
  3478. // with a no-event status.
  3479. if (Timeout == 0)
  3480. {
  3481. return S_FALSE;
  3482. }
  3483. //
  3484. // No source had an event, so sleep for a little while.
  3485. //
  3486. ULONG UseTimeout = 500;
  3487. if (Timeout != INFINITE && UseTimeout > Timeout)
  3488. {
  3489. UseTimeout = Timeout;
  3490. }
  3491. SUSPEND_ENGINE();
  3492. Sleep(UseTimeout);
  3493. RESUME_ENGINE();
  3494. if (Timeout != INFINITE)
  3495. {
  3496. Timeout -= UseTimeout;
  3497. // Let the loop poll for events one more time
  3498. // before checking for a completed timeout.
  3499. }
  3500. }
  3501. if (!EventPoss)
  3502. {
  3503. // For some reason there are no longer any
  3504. // event sources.
  3505. return E_UNEXPECTED;
  3506. }
  3507. }
  3508. }
  3509. HRESULT
  3510. RawWaitForEvent(ULONG Flags, ULONG Timeout)
  3511. {
  3512. HRESULT Status;
  3513. ULONG ContinueStatus;
  3514. Status = PrepareForWait(Flags, &ContinueStatus);
  3515. if ((g_EngStatus & ENG_STATUS_WAITING) == 0)
  3516. {
  3517. // An error occurred or some kind of synthesized
  3518. // event is being returned.
  3519. goto Exit;
  3520. }
  3521. EventOut("> Executing\n");
  3522. BOOL FirstLoop = TRUE;
  3523. ULONG ElapsedTime = 0;
  3524. for (;;)
  3525. {
  3526. EventOut(">> Waiting, %d elapsed\n", ElapsedTime);
  3527. TargetInfo* Target;
  3528. ULONG EventPoss = 0;
  3529. ULONG DesiredTimeout;
  3530. ULONG UseTimeout = Timeout;
  3531. ForAllLayersToTarget()
  3532. {
  3533. if (FirstLoop)
  3534. {
  3535. Target->m_WaitTimeBase = 0;
  3536. }
  3537. if ((Status = Target->
  3538. WaitInitialize(Flags, Timeout,
  3539. FirstLoop ? WINIT_FIRST : WINIT_NOT_FIRST,
  3540. &DesiredTimeout)) != S_OK)
  3541. {
  3542. goto Calls;
  3543. }
  3544. if (Target->m_EventPossible)
  3545. {
  3546. EventPoss++;
  3547. UseTimeout = min(UseTimeout, DesiredTimeout);
  3548. }
  3549. }
  3550. if (!EventPoss)
  3551. {
  3552. DiscardTargets(DEBUG_SESSION_END);
  3553. Status = E_UNEXPECTED;
  3554. goto Calls;
  3555. }
  3556. FirstLoop = FALSE;
  3557. g_EngStatus &= ~ENG_STATUS_SPECIAL_EXECUTION;
  3558. // Don't process deferred work if this is
  3559. // just a processor switch.
  3560. if (g_CmdState != 's')
  3561. {
  3562. ProcessDeferredWork(&ContinueStatus);
  3563. }
  3564. if (g_EventTarget)
  3565. {
  3566. EventOut(">> Continue with %X\n", ContinueStatus);
  3567. if ((Status = g_EventTarget->
  3568. ReleaseLastEvent(ContinueStatus)) != S_OK)
  3569. {
  3570. goto Calls;
  3571. }
  3572. Target = g_EventTarget;
  3573. }
  3574. DiscardLastEvent();
  3575. g_EventTarget = NULL;
  3576. g_EngStatus &= ~ENG_STATUS_WAIT_SUCCESSFUL;
  3577. ULONG EventStatus;
  3578. if (g_EngStatus & ENG_STATUS_SPECIAL_EXECUTION)
  3579. {
  3580. // If this is special, directed execution we can only wait on
  3581. // the target that needs special execution.
  3582. Status = Target->
  3583. WaitForEvent(Flags, UseTimeout,
  3584. ElapsedTime - Target->m_WaitTimeBase,
  3585. &EventStatus);
  3586. Target->m_FirstWait = FALSE;
  3587. }
  3588. else
  3589. {
  3590. Status = WaitForAnyTarget(Flags, UseTimeout, EventPoss,
  3591. ElapsedTime, &EventStatus);
  3592. }
  3593. if (UseTimeout != INFINITE)
  3594. {
  3595. ElapsedTime += UseTimeout;
  3596. }
  3597. if (Timeout != INFINITE)
  3598. {
  3599. Timeout -= UseTimeout;
  3600. }
  3601. if (Status == S_FALSE && Timeout > 0)
  3602. {
  3603. // Everything timed out but we were using a
  3604. // timeout smaller than the caller's overall
  3605. // timeout, so loop around and keep waiting.
  3606. continue;
  3607. }
  3608. if (Status != S_OK)
  3609. {
  3610. goto Calls;
  3611. }
  3612. if (EventStatus != DEBUG_STATUS_NO_DEBUGGEE)
  3613. {
  3614. g_EngStatus |= ENG_STATUS_WAIT_SUCCESSFUL;
  3615. }
  3616. // Successfully retrieved an event so reset the timeout count.
  3617. ElapsedTime = 0;
  3618. ForAllLayersToTarget()
  3619. {
  3620. Target->m_WaitTimeBase = 0;
  3621. }
  3622. EventOut(">>> Event status %X\n", EventStatus);
  3623. if (EventStatus == DEBUG_STATUS_NO_DEBUGGEE)
  3624. {
  3625. // Machine has rebooted or something else
  3626. // which breaks the connection. Forget the
  3627. // connection and go back to waiting.
  3628. ContinueStatus = DBG_CONTINUE;
  3629. }
  3630. else if (EventStatus == DEBUG_STATUS_BREAK ||
  3631. (g_EngStatus & ENG_STATUS_SPECIAL_EXECUTION))
  3632. {
  3633. // If the event handlers requested a break return
  3634. // to the caller. This path is also taken
  3635. // during special execution to guarantee that
  3636. // the target doesn't start running when the
  3637. // engine is just executing for internal purposes.
  3638. Status = S_OK;
  3639. goto Calls;
  3640. }
  3641. else
  3642. {
  3643. // We're resuming execution so reverse any
  3644. // command preparation that may have occurred
  3645. // while processing the event.
  3646. if ((Status = PrepareForExecution(EventStatus)) != S_OK)
  3647. {
  3648. goto Calls;
  3649. }
  3650. ContinueStatus = EventStatusToContinue(EventStatus);
  3651. }
  3652. }
  3653. Calls:
  3654. g_EngStatus &= ~ENG_STATUS_WAITING;
  3655. // Control is passing back to the caller so the engine must
  3656. // be ready for command processing.
  3657. PrepareForCalls(0);
  3658. // If we did switch processors automatically
  3659. // update the page directory for the new processor.
  3660. if (IS_KERNEL_TARGET(g_EventTarget) &&
  3661. (g_EngStatus & ENG_STATUS_SPECIAL_EXECUTION) &&
  3662. g_EventTarget)
  3663. {
  3664. if (g_EventTarget->m_Machine->
  3665. SetDefaultPageDirectories(g_EventThread, PAGE_DIR_ALL) != S_OK)
  3666. {
  3667. WarnOut("WARNING: Unable to reset page directories\n");
  3668. }
  3669. }
  3670. g_EngStatus &= ~ENG_STATUS_SPECIAL_EXECUTION;
  3671. Exit:
  3672. EventOut("> Wait returning %X\n", Status);
  3673. return Status;
  3674. }
  3675. STDMETHODIMP
  3676. DebugClient::WaitForEvent(
  3677. THIS_
  3678. IN ULONG Flags,
  3679. IN ULONG Timeout
  3680. )
  3681. {
  3682. if (Flags != DEBUG_WAIT_DEFAULT)
  3683. {
  3684. return E_INVALIDARG;
  3685. }
  3686. HRESULT Status;
  3687. ENTER_ENGINE();
  3688. // If there's an outstanding request for input don't wait
  3689. // as it's very unlikely that the other thread
  3690. // can handle such an engine change.
  3691. if (g_InputNesting >= 1 ||
  3692. ::GetCurrentThreadId() != g_SessionThread ||
  3693. (g_EngStatus & ENG_STATUS_STOP_SESSION))
  3694. {
  3695. Status = E_UNEXPECTED;
  3696. goto Exit;
  3697. }
  3698. // If the caller is trying to force the engine to
  3699. // stop waiting return immediately.
  3700. if (g_EngStatus & ENG_STATUS_EXIT_CURRENT_WAIT)
  3701. {
  3702. Status = E_PENDING;
  3703. goto Exit;
  3704. }
  3705. // This constitutes interesting activity.
  3706. m_LastActivity = time(NULL);
  3707. if (g_EngStatus & ENG_STATUS_WAITING)
  3708. {
  3709. Status = E_FAIL;
  3710. goto Exit;
  3711. }
  3712. Status = RawWaitForEvent(Flags, Timeout);
  3713. Exit:
  3714. g_EngStatus &= ~ENG_STATUS_EXIT_CURRENT_WAIT;
  3715. LEAVE_ENGINE();
  3716. return Status;
  3717. }
  3718. STDMETHODIMP
  3719. DebugClient::GetLastEventInformation(
  3720. THIS_
  3721. OUT PULONG Type,
  3722. OUT PULONG ProcessId,
  3723. OUT PULONG ThreadId,
  3724. OUT OPTIONAL PVOID ExtraInformation,
  3725. IN ULONG ExtraInformationSize,
  3726. OUT OPTIONAL PULONG ExtraInformationUsed,
  3727. OUT OPTIONAL PSTR Description,
  3728. IN ULONG DescriptionSize,
  3729. OUT OPTIONAL PULONG DescriptionUsed
  3730. )
  3731. {
  3732. HRESULT Status;
  3733. ENTER_ENGINE();
  3734. *Type = g_LastEventType;
  3735. if (g_EventProcess != NULL)
  3736. {
  3737. *ProcessId = g_EventProcess->m_UserId;
  3738. *ThreadId = g_EventThread->m_UserId;
  3739. }
  3740. else
  3741. {
  3742. *ProcessId = DEBUG_ANY_ID;
  3743. *ThreadId = DEBUG_ANY_ID;
  3744. }
  3745. Status = FillDataBuffer(g_LastEventExtraData, g_LastEventExtraDataSize,
  3746. ExtraInformation, ExtraInformationSize,
  3747. ExtraInformationUsed);
  3748. if (FillStringBuffer(g_LastEventDesc, 0,
  3749. Description, DescriptionSize,
  3750. DescriptionUsed) == S_FALSE)
  3751. {
  3752. Status = S_FALSE;
  3753. }
  3754. LEAVE_ENGINE();
  3755. return Status;
  3756. }
  3757. STDMETHODIMP
  3758. DebugClient::GetCurrentTimeDate(
  3759. THIS_
  3760. OUT PULONG TimeDate
  3761. )
  3762. {
  3763. HRESULT Status;
  3764. ENTER_ENGINE();
  3765. if (!g_Target)
  3766. {
  3767. Status = E_UNEXPECTED;
  3768. }
  3769. else
  3770. {
  3771. *TimeDate =
  3772. FileTimeToTimeDateStamp(g_Target->GetCurrentTimeDateN());
  3773. Status = S_OK;
  3774. }
  3775. LEAVE_ENGINE();
  3776. return Status;
  3777. }
  3778. STDMETHODIMP
  3779. DebugClient::GetCurrentSystemUpTime(
  3780. THIS_
  3781. OUT PULONG UpTime
  3782. )
  3783. {
  3784. HRESULT Status;
  3785. ENTER_ENGINE();
  3786. if (!g_Target)
  3787. {
  3788. Status = E_UNEXPECTED;
  3789. }
  3790. else
  3791. {
  3792. *UpTime =
  3793. FileTimeToTime(g_Target->GetCurrentSystemUpTimeN());
  3794. Status = S_OK;
  3795. }
  3796. LEAVE_ENGINE();
  3797. return Status;
  3798. }
  3799. STDMETHODIMP
  3800. DebugClient::GetDumpFormatFlags(
  3801. THIS_
  3802. OUT PULONG FormatFlags
  3803. )
  3804. {
  3805. HRESULT Status;
  3806. ENTER_ENGINE();
  3807. if (!IS_DUMP_TARGET(g_Target))
  3808. {
  3809. Status = E_UNEXPECTED;
  3810. }
  3811. else
  3812. {
  3813. *FormatFlags = ((DumpTargetInfo*)g_Target)->m_FormatFlags;
  3814. Status = S_OK;
  3815. }
  3816. LEAVE_ENGINE();
  3817. return Status;
  3818. }
  3819. STDMETHODIMP
  3820. DebugClient::GetNumberTextReplacements(
  3821. THIS_
  3822. OUT PULONG NumRepl
  3823. )
  3824. {
  3825. HRESULT Status;
  3826. ENTER_ENGINE();
  3827. *NumRepl = g_NumAliases;
  3828. Status = S_OK;
  3829. LEAVE_ENGINE();
  3830. return Status;
  3831. }
  3832. STDMETHODIMP
  3833. DebugClient::GetTextReplacement(
  3834. THIS_
  3835. IN OPTIONAL PCSTR SrcText,
  3836. IN ULONG Index,
  3837. OUT OPTIONAL PSTR SrcBuffer,
  3838. IN ULONG SrcBufferSize,
  3839. OUT OPTIONAL PULONG SrcSize,
  3840. OUT OPTIONAL PSTR DstBuffer,
  3841. IN ULONG DstBufferSize,
  3842. OUT OPTIONAL PULONG DstSize
  3843. )
  3844. {
  3845. HRESULT Status;
  3846. ENTER_ENGINE();
  3847. PALIAS Scan = g_AliasListHead;
  3848. while (Scan != NULL &&
  3849. ((SrcText != NULL && strcmp(SrcText, Scan->Name)) ||
  3850. (SrcText == NULL && Index-- > 0)))
  3851. {
  3852. Scan = Scan->Next;
  3853. }
  3854. if (Scan != NULL)
  3855. {
  3856. Status = FillStringBuffer(Scan->Name, 0,
  3857. SrcBuffer, SrcBufferSize, SrcSize);
  3858. if (FillStringBuffer(Scan->Value, 0,
  3859. DstBuffer, DstBufferSize, DstSize) == S_FALSE)
  3860. {
  3861. Status = S_FALSE;
  3862. }
  3863. }
  3864. else
  3865. {
  3866. Status = E_NOINTERFACE;
  3867. }
  3868. LEAVE_ENGINE();
  3869. return Status;
  3870. }
  3871. STDMETHODIMP
  3872. DebugClient::SetTextReplacement(
  3873. THIS_
  3874. IN PCSTR SrcText,
  3875. IN OPTIONAL PCSTR DstText
  3876. )
  3877. {
  3878. HRESULT Status;
  3879. ENTER_ENGINE();
  3880. if (DstText != NULL)
  3881. {
  3882. Status = SetAlias(SrcText, DstText);
  3883. }
  3884. else
  3885. {
  3886. Status = DeleteAlias(SrcText);
  3887. }
  3888. LEAVE_ENGINE();
  3889. return Status;
  3890. }
  3891. STDMETHODIMP
  3892. DebugClient::RemoveTextReplacements(
  3893. THIS
  3894. )
  3895. {
  3896. HRESULT Status;
  3897. ENTER_ENGINE();
  3898. Status = DeleteAlias("*");
  3899. LEAVE_ENGINE();
  3900. return Status;
  3901. }
  3902. STDMETHODIMP
  3903. DebugClient::OutputTextReplacements(
  3904. THIS_
  3905. IN ULONG OutputControl,
  3906. IN ULONG Flags
  3907. )
  3908. {
  3909. HRESULT Status;
  3910. ENTER_ENGINE();
  3911. ListAliases();
  3912. Status = S_OK;
  3913. LEAVE_ENGINE();
  3914. return Status;
  3915. }
  3916. #define ASMOPT_ALL \
  3917. (DEBUG_ASMOPT_VERBOSE | \
  3918. DEBUG_ASMOPT_NO_CODE_BYTES | \
  3919. DEBUG_ASMOPT_IGNORE_OUTPUT_WIDTH)
  3920. STDMETHODIMP
  3921. DebugClient::GetAssemblyOptions(
  3922. THIS_
  3923. OUT PULONG Options
  3924. )
  3925. {
  3926. ENTER_ENGINE();
  3927. *Options = g_AsmOptions;
  3928. LEAVE_ENGINE();
  3929. return S_OK;
  3930. }
  3931. STDMETHODIMP
  3932. DebugClient::AddAssemblyOptions(
  3933. THIS_
  3934. IN ULONG Options
  3935. )
  3936. {
  3937. if (Options & ~ASMOPT_ALL)
  3938. {
  3939. return E_INVALIDARG;
  3940. }
  3941. ENTER_ENGINE();
  3942. g_AsmOptions |= Options;
  3943. NotifyChangeEngineState(DEBUG_CES_ASSEMBLY_OPTIONS, g_AsmOptions, TRUE);
  3944. LEAVE_ENGINE();
  3945. return S_OK;
  3946. }
  3947. STDMETHODIMP
  3948. DebugClient::RemoveAssemblyOptions(
  3949. THIS_
  3950. IN ULONG Options
  3951. )
  3952. {
  3953. if (Options & ~ASMOPT_ALL)
  3954. {
  3955. return E_INVALIDARG;
  3956. }
  3957. ENTER_ENGINE();
  3958. g_AsmOptions &= ~Options;
  3959. NotifyChangeEngineState(DEBUG_CES_ASSEMBLY_OPTIONS, g_AsmOptions, TRUE);
  3960. LEAVE_ENGINE();
  3961. return S_OK;
  3962. }
  3963. STDMETHODIMP
  3964. DebugClient::SetAssemblyOptions(
  3965. THIS_
  3966. IN ULONG Options
  3967. )
  3968. {
  3969. if (Options & ~ASMOPT_ALL)
  3970. {
  3971. return E_INVALIDARG;
  3972. }
  3973. ENTER_ENGINE();
  3974. g_AsmOptions = Options;
  3975. NotifyChangeEngineState(DEBUG_CES_ASSEMBLY_OPTIONS, g_AsmOptions, TRUE);
  3976. LEAVE_ENGINE();
  3977. return S_OK;
  3978. }
  3979. STDMETHODIMP
  3980. DebugClient::GetExpressionSyntax(
  3981. THIS_
  3982. OUT PULONG Flags
  3983. )
  3984. {
  3985. ENTER_ENGINE();
  3986. *Flags = g_EvalSyntax;
  3987. LEAVE_ENGINE();
  3988. return S_OK;
  3989. }
  3990. HRESULT
  3991. SetExprSyntax(ULONG Flags)
  3992. {
  3993. if (Flags >= EVAL_COUNT)
  3994. {
  3995. return E_INVALIDARG;
  3996. }
  3997. g_EvalSyntax = Flags;
  3998. NotifyChangeEngineState(DEBUG_CES_EXPRESSION_SYNTAX, Flags, TRUE);
  3999. return S_OK;
  4000. }
  4001. STDMETHODIMP
  4002. DebugClient::SetExpressionSyntax(
  4003. THIS_
  4004. IN ULONG Flags
  4005. )
  4006. {
  4007. HRESULT Status;
  4008. ENTER_ENGINE();
  4009. Status = ::SetExprSyntax(Flags);
  4010. LEAVE_ENGINE();
  4011. return Status;
  4012. }
  4013. HRESULT
  4014. SetExprSyntaxByName(PCSTR Name)
  4015. {
  4016. HRESULT Status;
  4017. EvalExpression* Eval;
  4018. if ((Status = GetEvaluatorByName(Name, TRUE, &Eval)) != S_OK)
  4019. {
  4020. return Status;
  4021. }
  4022. SetExprSyntax(Eval->m_Syntax);
  4023. ReleaseEvaluator(Eval);
  4024. return S_OK;
  4025. }
  4026. STDMETHODIMP
  4027. DebugClient::SetExpressionSyntaxByName(
  4028. THIS_
  4029. IN PCSTR AbbrevName
  4030. )
  4031. {
  4032. HRESULT Status;
  4033. ENTER_ENGINE();
  4034. Status = ::SetExprSyntaxByName(AbbrevName);
  4035. LEAVE_ENGINE();
  4036. return Status;
  4037. }
  4038. STDMETHODIMP
  4039. DebugClient::GetNumberExpressionSyntaxes(
  4040. THIS_
  4041. OUT PULONG Number
  4042. )
  4043. {
  4044. *Number = EVAL_COUNT;
  4045. return S_OK;
  4046. }
  4047. STDMETHODIMP
  4048. DebugClient::GetExpressionSyntaxNames(
  4049. THIS_
  4050. IN ULONG Index,
  4051. OUT OPTIONAL PSTR FullNameBuffer,
  4052. IN ULONG FullNameBufferSize,
  4053. OUT OPTIONAL PULONG FullNameSize,
  4054. OUT OPTIONAL PSTR AbbrevNameBuffer,
  4055. IN ULONG AbbrevNameBufferSize,
  4056. OUT OPTIONAL PULONG AbbrevNameSize
  4057. )
  4058. {
  4059. if (Index >= EVAL_COUNT)
  4060. {
  4061. return E_INVALIDARG;
  4062. }
  4063. HRESULT Status;
  4064. ENTER_ENGINE();
  4065. EvalExpression* Eval = GetEvaluator(Index, TRUE);
  4066. if (!Eval)
  4067. {
  4068. Status = E_OUTOFMEMORY;
  4069. }
  4070. else
  4071. {
  4072. Status = FillStringBuffer(Eval->m_FullName, 0,
  4073. FullNameBuffer, FullNameBufferSize,
  4074. FullNameSize);
  4075. if (FillStringBuffer(Eval->m_AbbrevName, 0,
  4076. AbbrevNameBuffer, AbbrevNameBufferSize,
  4077. AbbrevNameSize) == S_FALSE)
  4078. {
  4079. Status = S_FALSE;
  4080. }
  4081. ReleaseEvaluator(Eval);
  4082. }
  4083. LEAVE_ENGINE();
  4084. return Status;
  4085. }
  4086. STDMETHODIMP
  4087. DebugClient::GetNumberEvents(
  4088. THIS_
  4089. OUT PULONG Events
  4090. )
  4091. {
  4092. HRESULT Status;
  4093. ENTER_ENGINE();
  4094. if (!g_Target)
  4095. {
  4096. Status = E_UNEXPECTED;
  4097. }
  4098. else
  4099. {
  4100. *Events = g_Target->m_NumEvents;
  4101. Status = g_Target->m_DynamicEvents ? S_FALSE : S_OK;
  4102. }
  4103. LEAVE_ENGINE();
  4104. return Status;
  4105. }
  4106. STDMETHODIMP
  4107. DebugClient::GetEventIndexDescription(
  4108. THIS_
  4109. IN ULONG Index,
  4110. IN ULONG Which,
  4111. IN OPTIONAL PSTR Buffer,
  4112. IN ULONG BufferSize,
  4113. OUT OPTIONAL PULONG DescSize
  4114. )
  4115. {
  4116. HRESULT Status;
  4117. if (Which != DEBUG_EINDEX_NAME)
  4118. {
  4119. return E_INVALIDARG;
  4120. }
  4121. ENTER_ENGINE();
  4122. if (!g_Target)
  4123. {
  4124. Status = E_UNEXPECTED;
  4125. }
  4126. else if (Index > g_Target->m_NumEvents)
  4127. {
  4128. Status = E_INVALIDARG;
  4129. }
  4130. else
  4131. {
  4132. Status = g_Target->
  4133. GetEventIndexDescription(Index, Which,
  4134. Buffer, BufferSize, DescSize);
  4135. }
  4136. LEAVE_ENGINE();
  4137. return Status;
  4138. }
  4139. STDMETHODIMP
  4140. DebugClient::GetCurrentEventIndex(
  4141. THIS_
  4142. OUT PULONG Index
  4143. )
  4144. {
  4145. HRESULT Status;
  4146. ENTER_ENGINE();
  4147. if (!g_Target)
  4148. {
  4149. Status = E_UNEXPECTED;
  4150. }
  4151. else
  4152. {
  4153. *Index = g_Target->m_EventIndex;
  4154. Status = S_OK;
  4155. }
  4156. LEAVE_ENGINE();
  4157. return Status;
  4158. }
  4159. STDMETHODIMP
  4160. DebugClient::SetNextEventIndex(
  4161. THIS_
  4162. IN ULONG Relation,
  4163. IN ULONG Value,
  4164. OUT PULONG NextIndex
  4165. )
  4166. {
  4167. HRESULT Status;
  4168. ENTER_ENGINE();
  4169. if (!IS_MACHINE_SET(g_Target) ||
  4170. IS_RUNNING(g_CmdState))
  4171. {
  4172. Status = E_UNEXPECTED;
  4173. goto Exit;
  4174. }
  4175. switch(Relation)
  4176. {
  4177. case DEBUG_EINDEX_FROM_START:
  4178. // Value is start index.
  4179. if (Value >= g_Target->m_NumEvents)
  4180. {
  4181. Status = E_INVALIDARG;
  4182. goto Exit;
  4183. }
  4184. break;
  4185. case DEBUG_EINDEX_FROM_END:
  4186. // Value is end index.
  4187. if (Value >= g_Target->m_NumEvents)
  4188. {
  4189. Status = E_INVALIDARG;
  4190. goto Exit;
  4191. }
  4192. Value = g_Target->m_NumEvents - Value - 1;
  4193. break;
  4194. case DEBUG_EINDEX_FROM_CURRENT:
  4195. if ((LONG)Value < 0)
  4196. {
  4197. Value = -(LONG)Value;
  4198. if (Value > g_Target->m_EventIndex)
  4199. {
  4200. Status = E_INVALIDARG;
  4201. goto Exit;
  4202. }
  4203. Value = g_Target->m_EventIndex - Value;
  4204. }
  4205. else
  4206. {
  4207. if (Value >= g_Target->m_NumEvents - g_Target->m_EventIndex)
  4208. {
  4209. Status = E_INVALIDARG;
  4210. goto Exit;
  4211. }
  4212. Value = g_Target->m_EventIndex + Value;
  4213. }
  4214. break;
  4215. default:
  4216. Status = E_INVALIDARG;
  4217. goto Exit;
  4218. }
  4219. if (g_Target->m_EventIndex != Value)
  4220. {
  4221. g_Target->m_NextEventIndex = Value;
  4222. g_CmdState = 'e';
  4223. NotifyChangeEngineState(DEBUG_CES_EXECUTION_STATUS, DEBUG_STATUS_GO,
  4224. TRUE);
  4225. }
  4226. *NextIndex = Value;
  4227. Status = S_OK;
  4228. Exit:
  4229. LEAVE_ENGINE();
  4230. return Status;
  4231. }