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.

1537 lines
36 KiB

  1. /*++
  2. Copyright (c) 2000 Microsoft Corporation
  3. Module Name:
  4. output.cxx
  5. Abstract:
  6. This file contains output state control and output callback classes.
  7. Author:
  8. Jason Hartman (JasonHa) 2000-11-20
  9. Environment:
  10. User Mode
  11. --*/
  12. #include "precomp.hxx"
  13. HRESULT
  14. OutputControl::SetControl(
  15. ULONG OutputControl,
  16. PDEBUG_CLIENT Client
  17. )
  18. {
  19. ULONG SendMask = OutputControl & DEBUG_OUTCTL_SEND_MASK;
  20. if (OutputControl != DEBUG_OUTCTL_AMBIENT &&
  21. (
  22. #if DEBUG_OUTCTL_THIS_CLIENT > 0
  23. SendMask < DEBUG_OUTCTL_THIS_CLIENT ||
  24. #endif
  25. SendMask > DEBUG_OUTCTL_LOG_ONLY ||
  26. (OutputControl & ~(DEBUG_OUTCTL_SEND_MASK |
  27. DEBUG_OUTCTL_NOT_LOGGED |
  28. DEBUG_OUTCTL_OVERRIDE_MASK))))
  29. {
  30. return E_INVALIDARG;
  31. }
  32. if (Client != NULL)
  33. {
  34. HRESULT hr;
  35. PDEBUG_CONTROL NewControl;
  36. // Switch to new client
  37. if ((hr = Client->QueryInterface(__uuidof(IDebugControl),
  38. (void **)&NewControl)) != S_OK)
  39. {
  40. return hr;
  41. }
  42. if (Control != NULL) Control->Release();
  43. Control = NewControl;
  44. }
  45. OutCtl = OutputControl;
  46. return S_OK;
  47. }
  48. HRESULT
  49. OutputControl::Output(
  50. ULONG Mask,
  51. PCSTR Format,
  52. ...
  53. )
  54. {
  55. HRESULT hr;
  56. va_list Args;
  57. if (Control == NULL) return E_FAIL;
  58. va_start(Args, Format);
  59. if (OutCtl == DEBUG_OUTCTL_AMBIENT)
  60. {
  61. hr = Control->OutputVaList(Mask, Format, Args);
  62. }
  63. else
  64. {
  65. hr = Control->ControlledOutputVaList(OutCtl, Mask, Format, Args);
  66. }
  67. va_end(Args);
  68. return hr;
  69. }
  70. HRESULT
  71. OutputControl::OutputVaList(
  72. ULONG Mask,
  73. PCSTR Format,
  74. va_list Args
  75. )
  76. {
  77. HRESULT hr;
  78. if (Control == NULL) return E_FAIL;
  79. if (OutCtl == DEBUG_OUTCTL_AMBIENT)
  80. {
  81. hr = Control->OutputVaList(Mask, Format, Args);
  82. }
  83. else
  84. {
  85. hr = Control->ControlledOutputVaList(OutCtl, Mask, Format, Args);
  86. }
  87. return hr;
  88. }
  89. HRESULT
  90. OutputControl::Output(
  91. PCSTR Format,
  92. ...
  93. )
  94. {
  95. HRESULT hr;
  96. va_list Args;
  97. va_start(Args, Format);
  98. hr = OutputVaList(DEBUG_OUTPUT_NORMAL, Format, Args);
  99. va_end(Args);
  100. return hr;
  101. }
  102. HRESULT
  103. OutputControl::OutErr(
  104. PCSTR Format,
  105. ...
  106. )
  107. {
  108. HRESULT hr;
  109. va_list Args;
  110. va_start(Args, Format);
  111. hr = OutputVaList(DEBUG_OUTPUT_ERROR, Format, Args);
  112. va_end(Args);
  113. return hr;
  114. }
  115. HRESULT
  116. OutputControl::OutWarn(
  117. PCSTR Format,
  118. ...
  119. )
  120. {
  121. HRESULT hr;
  122. va_list Args;
  123. va_start(Args, Format);
  124. hr = OutputVaList(DEBUG_OUTPUT_WARNING, Format, Args);
  125. va_end(Args);
  126. return hr;
  127. }
  128. HRESULT
  129. OutputControl::OutVerb(
  130. PCSTR Format,
  131. ...
  132. )
  133. {
  134. HRESULT hr;
  135. va_list Args;
  136. va_start(Args, Format);
  137. hr = OutputVaList(DEBUG_OUTPUT_VERBOSE, Format, Args);
  138. va_end(Args);
  139. return hr;
  140. }
  141. HRESULT
  142. OutputControl::GetInterrupt(
  143. )
  144. {
  145. return (Control == NULL) ?
  146. E_FAIL :
  147. Control->GetInterrupt();
  148. }
  149. HRESULT
  150. OutputControl::SetInterrupt(
  151. ULONG Flags
  152. )
  153. {
  154. return (Control == NULL) ?
  155. E_FAIL :
  156. Control->SetInterrupt(Flags);
  157. }
  158. HRESULT
  159. OutputControl::Evaluate(
  160. IN PCSTR Expression,
  161. IN ULONG DesiredType,
  162. OUT PDEBUG_VALUE Value,
  163. OUT OPTIONAL PULONG RemainderIndex
  164. )
  165. {
  166. return (Control == NULL) ?
  167. E_FAIL :
  168. Control->Evaluate(Expression,
  169. DesiredType,
  170. Value,
  171. RemainderIndex);
  172. }
  173. HRESULT
  174. OutputControl::CoerceValue(
  175. IN PDEBUG_VALUE In,
  176. IN ULONG OutType,
  177. OUT PDEBUG_VALUE Out
  178. )
  179. {
  180. return (Control == NULL) ?
  181. E_FAIL :
  182. Control->CoerceValue(In,
  183. OutType,
  184. Out);
  185. }
  186. HRESULT
  187. OutputControl::IsPointer64Bit(
  188. )
  189. {
  190. return (Control == NULL) ?
  191. E_FAIL :
  192. Control->IsPointer64Bit();
  193. }
  194. OutputState::OutputState(
  195. PDEBUG_CLIENT OrgClient,
  196. BOOL SameClient
  197. )
  198. {
  199. hrInit = S_FALSE;
  200. Client = NULL;
  201. Control = NULL;
  202. Symbols = NULL;
  203. SetCallbacks = FALSE;
  204. CreatedClient = FALSE;
  205. Saved = FALSE;
  206. if (OrgClient != NULL)
  207. {
  208. if (SameClient)
  209. {
  210. Client = OrgClient;
  211. Client->AddRef();
  212. CreatedClient = TRUE;
  213. hrInit = S_OK;
  214. }
  215. else
  216. {
  217. hrInit = OrgClient->CreateClient(&Client);
  218. }
  219. }
  220. }
  221. OutputState::~OutputState()
  222. {
  223. if (!CreatedClient) Restore();
  224. EXT_RELEASE(Symbols);
  225. EXT_RELEASE(Control);
  226. // If Client was newly created for OutputState, then
  227. // there shouldn't be any other references to Client.
  228. if (CreatedClient)
  229. {
  230. ULONG RemainingRefs;
  231. RemainingRefs = Client->AddRef();
  232. if (RemainingRefs > 2)
  233. {
  234. DbgPrint("OutputState: %lu refs outstanding on created client.\n",
  235. RemainingRefs-2);
  236. DbgBreakPoint();
  237. // As a precaution, Restore the callbacks;
  238. // so, any set callback may be cleaned up.
  239. Restore();
  240. }
  241. Client->Release();
  242. }
  243. if (Client != NULL) Client->Release();
  244. }
  245. HRESULT
  246. OutputState::Setup(
  247. ULONG OutMask,
  248. PDEBUG_OUTPUT_CALLBACKS OutCallbacks
  249. )
  250. {
  251. HRESULT hr = hrInit;
  252. ULONG LastOutMask;
  253. if (hr == S_OK)
  254. {
  255. if (CreatedClient && !Saved)
  256. {
  257. if ((hr = Client->GetOutputMask(&OrgOutMask)) == S_OK &&
  258. (hr = Client->GetOutputCallbacks(&OrgOutCallbacks)) == S_OK)
  259. {
  260. Saved = TRUE;
  261. }
  262. }
  263. if (hr == S_OK &&
  264. (hr = Client->GetOutputMask(&LastOutMask)) == S_OK &&
  265. (hr = Client->SetOutputMask(OutMask)) == S_OK)
  266. {
  267. if (!Saved && !SetCallbacks)
  268. {
  269. OrgOutMask = LastOutMask;
  270. OrgOutCallbacks = NULL;
  271. }
  272. if ((hr = Client->SetOutputCallbacks(OutCallbacks)) == S_OK)
  273. {
  274. SetCallbacks = TRUE;
  275. }
  276. else
  277. {
  278. Client->SetOutputMask(LastOutMask);
  279. }
  280. }
  281. }
  282. if (hr == S_OK &&
  283. Symbols == NULL)
  284. {
  285. hr = Client->QueryInterface(__uuidof(IDebugSymbols), (void **)&Symbols);
  286. }
  287. return hr;
  288. }
  289. HRESULT
  290. OutputState::Execute(
  291. PCSTR pszCommand
  292. )
  293. {
  294. HRESULT hr = hrInit;
  295. if (hr == S_OK)
  296. {
  297. if (Control == NULL)
  298. {
  299. hr = Client->QueryInterface(__uuidof(IDebugControl), (void **)&Control);
  300. }
  301. if (hr == S_OK)
  302. {
  303. hr = Control->Execute(DEBUG_OUTCTL_THIS_CLIENT |
  304. DEBUG_OUTCTL_NOT_LOGGED |
  305. DEBUG_OUTCTL_OVERRIDE_MASK,
  306. pszCommand,
  307. DEBUG_EXECUTE_NOT_LOGGED |
  308. DEBUG_EXECUTE_NO_REPEAT);
  309. if (hr != S_OK)
  310. {
  311. DbgPrint("IDebugControl::Execute returned %s.\n",
  312. pszHRESULT(hr));
  313. }
  314. }
  315. }
  316. return hr;
  317. }
  318. HRESULT
  319. OutputState::OutputType(
  320. IN BOOL Physical,
  321. IN ULONG64 Offset,
  322. IN PCSTR Type,
  323. IN ULONG Flags
  324. )
  325. {
  326. HRESULT hr = hrInit;
  327. if (hr == S_OK)
  328. {
  329. if (Symbols == NULL)
  330. {
  331. hr = Client->QueryInterface(__uuidof(IDebugSymbols), (void **)&Symbols);
  332. }
  333. if (hr == S_OK)
  334. {
  335. ULONG64 Module;
  336. ULONG TypeId;
  337. hr = GetTypeId(Client, Type, &TypeId, &Module);
  338. if (hr != S_OK)
  339. {
  340. OutputControl OutCtl(Client);
  341. ULONG ModuleIndex = 0;
  342. while ((hr = Symbols->GetModuleByIndex(ModuleIndex, &Module)) == S_OK &&
  343. (Module != 0))
  344. {
  345. if ((hr = Symbols->GetTypeId(Module, Type, &TypeId)) == S_OK)
  346. {
  347. OutCtl.OutVerb("Found %s: TypeId 0x%lx in module @ %p.\n",
  348. Type, TypeId, Module);
  349. break;
  350. }
  351. ModuleIndex++;
  352. Module = 0;
  353. }
  354. if (hr == S_OK &&
  355. (Module == 0 || TypeId == 0))
  356. {
  357. hr = S_FALSE;
  358. }
  359. if (hr != S_OK)
  360. {
  361. OutCtl.OutVerb("Couldn't find %s in any of %lu modules.\n",
  362. Type, ModuleIndex);
  363. }
  364. }
  365. if (hr == S_OK)
  366. {
  367. hr = OutputType(Physical, Offset, Module, TypeId, Flags);
  368. }
  369. }
  370. }
  371. return hr;
  372. }
  373. HRESULT
  374. OutputState::OutputType(
  375. IN BOOL Physical,
  376. IN ULONG64 Offset,
  377. IN ULONG64 Module,
  378. IN ULONG TypeId,
  379. IN ULONG Flags
  380. )
  381. {
  382. HRESULT hr = hrInit;
  383. if (hr == S_OK)
  384. {
  385. if (Symbols == NULL)
  386. {
  387. hr = Client->QueryInterface(__uuidof(IDebugSymbols), (void **)&Symbols);
  388. }
  389. if (hr == S_OK)
  390. {
  391. if (Physical)
  392. {
  393. hr = Symbols->OutputTypedDataPhysical(DEBUG_OUTCTL_THIS_CLIENT |
  394. DEBUG_OUTCTL_NOT_LOGGED |
  395. DEBUG_OUTCTL_OVERRIDE_MASK,
  396. Offset,
  397. Module,
  398. TypeId,
  399. Flags);
  400. }
  401. else
  402. {
  403. hr = Symbols->OutputTypedDataVirtual(DEBUG_OUTCTL_THIS_CLIENT |
  404. DEBUG_OUTCTL_NOT_LOGGED |
  405. DEBUG_OUTCTL_OVERRIDE_MASK,
  406. Offset,
  407. Module,
  408. TypeId,
  409. Flags);
  410. }
  411. if (hr != S_OK)
  412. {
  413. DbgPrint("IDebugSymbols::OutputTypedData%s returned %s for 0x%I64x.\n",
  414. (Physical ? "Physical" : "Virtual"),
  415. pszHRESULT(hr),
  416. Offset);
  417. }
  418. }
  419. }
  420. return hr;
  421. }
  422. void OutputState::Restore()
  423. {
  424. if (SetCallbacks)
  425. {
  426. Client->SetOutputCallbacks(OrgOutCallbacks);
  427. Client->SetOutputMask(OrgOutMask);
  428. SetCallbacks = FALSE;
  429. }
  430. if (Saved)
  431. {
  432. if (OrgOutCallbacks != NULL) OrgOutCallbacks->Release();
  433. Saved = FALSE;
  434. }
  435. }
  436. //----------------------------------------------------------------------------
  437. //
  438. // Default output callbacks implementation, provides IUnknown for
  439. // static classes.
  440. //
  441. //----------------------------------------------------------------------------
  442. STDMETHODIMP
  443. DefOutputCallbacks::QueryInterface(
  444. THIS_
  445. IN REFIID InterfaceId,
  446. OUT PVOID* Interface
  447. )
  448. {
  449. *Interface = NULL;
  450. if (//(InterfaceId == IID_IUnknown) ||
  451. (InterfaceId == __uuidof(IDebugOutputCallbacks)))
  452. {
  453. *Interface = (IDebugOutputCallbacks *)this;
  454. AddRef();
  455. return S_OK;
  456. }
  457. else
  458. {
  459. return E_NOINTERFACE;
  460. }
  461. }
  462. STDMETHODIMP_(ULONG)
  463. DefOutputCallbacks::AddRef(
  464. THIS
  465. )
  466. {
  467. // This class is designed to be allocated on a
  468. // stack or statically, but we retain a refcount
  469. // for debugging purposes.
  470. return ++RefCount;
  471. }
  472. STDMETHODIMP_(ULONG)
  473. DefOutputCallbacks::Release(
  474. THIS
  475. )
  476. {
  477. // This class is designed to be allocated on a
  478. // stack or statically, but we retain a refcount
  479. // for debugging purposes.
  480. RefCount--;
  481. if (RefCount < 1)
  482. {
  483. DbgPrint("DefOutputCallbacks@0x%p::RefCount(%lu) < 1.\n", this, RefCount);
  484. DbgBreakPoint();
  485. }
  486. return RefCount;
  487. }
  488. STDMETHODIMP
  489. DefOutputCallbacks::Output(
  490. THIS_
  491. IN ULONG Mask,
  492. IN PCSTR Text
  493. )
  494. {
  495. // The default Output ignores all Output calls.
  496. return S_OK;
  497. }
  498. //----------------------------------------------------------------------------
  499. //
  500. // DebugOutputCallbacks::Output
  501. //
  502. //----------------------------------------------------------------------------
  503. STDMETHODIMP
  504. DebugOutputCallbacks::Output(
  505. THIS_
  506. IN ULONG Mask,
  507. IN PCSTR Text
  508. )
  509. {
  510. DbgPrint("Mask: 0x%lx\tOutput Begin:\n%s:Output End\n", Mask, Text);
  511. return S_OK;
  512. }
  513. //----------------------------------------------------------------------------
  514. //
  515. // OutputReader
  516. //
  517. // General DebugOutputCallback class to parse output.
  518. //
  519. //----------------------------------------------------------------------------
  520. STDMETHODIMP
  521. OutputReader::Output(
  522. THIS_
  523. IN ULONG Mask,
  524. IN PCSTR Text
  525. )
  526. {
  527. ULONG TextLen = strlen(Text);
  528. if (BufferLeft < TextLen)
  529. {
  530. PSTR NewBuffer;
  531. SIZE_T NewBufferSize;
  532. if (hHeap == NULL)
  533. {
  534. hHeap = GetProcessHeap();
  535. if (hHeap == NULL) return S_FALSE;
  536. }
  537. // New length we need plus some extra space
  538. NewBufferSize = BufferSize + TextLen + 256;
  539. NewBuffer = (PSTR) ((Buffer == NULL) ?
  540. HeapAlloc(hHeap, 0, NewBufferSize):
  541. HeapReAlloc(hHeap, 0, Buffer, NewBufferSize));
  542. if (NewBuffer == NULL)
  543. {
  544. DbgPrint("Buffer alloc failed.\n");
  545. return E_OUTOFMEMORY;
  546. }
  547. // How much was really allocated?
  548. NewBufferSize = HeapSize(hHeap, 0, NewBuffer);
  549. // If this was the first alloc, initialize
  550. // buffer and account for terminating zero.
  551. if (Buffer == NULL)
  552. {
  553. NewBuffer[0] = '\0';
  554. BufferLeft = -1;
  555. }
  556. // Update buffer data
  557. Buffer = NewBuffer;
  558. BufferLeft += NewBufferSize - BufferSize;
  559. BufferSize = NewBufferSize;
  560. }
  561. // Append new text
  562. strcat(Buffer, Text);
  563. BufferLeft -= TextLen;
  564. return S_OK;
  565. }
  566. // Discard any text left unused by Parse
  567. void
  568. OutputReader::DiscardOutput()
  569. {
  570. if (Buffer != NULL)
  571. {
  572. Buffer[0] = '\0';
  573. BufferLeft = BufferSize - 1;
  574. }
  575. }
  576. // Get a copy of the output buffer
  577. HRESULT
  578. OutputReader::GetOutputCopy(
  579. PSTR *Copy
  580. )
  581. {
  582. if (Copy == NULL) return E_INVALIDARG;
  583. *Copy = NULL;
  584. if (Buffer == NULL) return S_OK;
  585. SIZE_T BufferLength = BufferSize - BufferLeft;
  586. *Copy = (PSTR)HeapAlloc(hHeap, 0, BufferLength);
  587. if (*Copy != NULL)
  588. {
  589. RtlCopyMemory(*Copy, Buffer, BufferLength);
  590. return S_OK;
  591. }
  592. return E_OUTOFMEMORY;
  593. }
  594. //----------------------------------------------------------------------------
  595. //
  596. // OutputParser
  597. //
  598. // General DebugOutputCallback class to parse output.
  599. //
  600. //----------------------------------------------------------------------------
  601. HRESULT
  602. OutputParser::ParseOutput(FLONG Flags)
  603. {
  604. HRESULT hr;
  605. ULONG TextRemainingIndex;
  606. if (Buffer == NULL)
  607. {
  608. return S_OK;
  609. }
  610. if (Flags & PARSE_OUTPUT_ALL)
  611. {
  612. UnparsedIndex = 0;
  613. }
  614. if ((hr = Parse(Buffer + UnparsedIndex, &TextRemainingIndex)) == S_OK)
  615. {
  616. UnparsedIndex += TextRemainingIndex;
  617. if (((Flags & PARSE_OUTPUT_NO_DISCARD) == 0) &&
  618. (UnparsedIndex > 0))
  619. {
  620. RtlMoveMemory(Buffer,
  621. Buffer + UnparsedIndex,
  622. BufferSize - UnparsedIndex - BufferLeft + 1);
  623. BufferLeft += UnparsedIndex;
  624. UnparsedIndex = 0;
  625. }
  626. }
  627. return hr;
  628. }
  629. void
  630. OutputParser::DiscardOutput()
  631. {
  632. OutputReader::DiscardOutput();
  633. UnparsedIndex = 0;
  634. }
  635. //----------------------------------------------------------------------------
  636. //
  637. // BasicOutputParser
  638. //
  639. // Basic DebugOutputCallback class to parse output looking for
  640. // string keys and subsequent values.
  641. //
  642. //----------------------------------------------------------------------------
  643. HRESULT
  644. BasicOutputParser::LookFor(
  645. PDEBUG_VALUE Value,
  646. PCSTR Key,
  647. ULONG Type,
  648. ULONG Radix
  649. )
  650. {
  651. if ((1 > strlen(Key)) ||
  652. (strlen(Key) >= sizeof(Entries->Key)/sizeof(Entries->Key[0])))
  653. {
  654. return E_INVALIDARG;
  655. }
  656. if (NumEntries >= MaxEntries) return E_OUTOFMEMORY;
  657. Entries[NumEntries].Value = Value;
  658. strcpy(Entries[NumEntries].Key, Key);
  659. if (Value != NULL)
  660. {
  661. Value->Type = DEBUG_VALUE_INVALID;
  662. if (Radix == PARSER_UNSPECIFIED_RADIX)
  663. {
  664. // Set Radix to Hex since value is likely to be an address
  665. // Otherwise type a deafult of decimal.
  666. Radix = (Type == DEBUG_VALUE_INT64) ? 16 : 10;
  667. }
  668. Entries[NumEntries].Type = Type;
  669. Entries[NumEntries].Radix = Radix;
  670. }
  671. NumEntries++;
  672. return S_OK;
  673. }
  674. HRESULT
  675. BasicOutputParser::Parse(
  676. IN PCSTR Text,
  677. OUT OPTIONAL PULONG RemainderIndex
  678. )
  679. {
  680. HRESULT hr = S_OK;
  681. PCSTR pStrUnused = Text;
  682. PCSTR pStr;
  683. ULONG EvalLen;
  684. // DbgPrint("BasicOutputParser::Parse: Searching \"%s\"\n", pStrUnused);
  685. while (CurEntry < NumEntries)
  686. {
  687. pStr = strstr(pStrUnused, Entries[CurEntry].Key);
  688. if (pStr == NULL)
  689. {
  690. break;
  691. }
  692. pStr += strlen(Entries[CurEntry].Key);
  693. if (Entries[CurEntry].Value != NULL)
  694. {
  695. hr = Evaluate(Client,
  696. pStr,
  697. Entries[CurEntry].Type,
  698. Entries[CurEntry].Radix,
  699. Entries[CurEntry].Value,
  700. &EvalLen);
  701. if (hr != S_OK)
  702. {
  703. DbgPrint("Evaluate returned HRESULT 0x%lx.\n", hr);
  704. break;
  705. }
  706. // DbgPrint("BasicOutputParser::Parse: Found 0x%I64x after \"%s\".\n", Entries[CurEntry].Value->I64, Entries[CurEntry].Key);
  707. pStr += EvalLen;
  708. }
  709. CurEntry++;
  710. pStrUnused = pStr;
  711. }
  712. if (RemainderIndex != NULL)
  713. {
  714. *RemainderIndex = (ULONG)(pStrUnused - Text);
  715. }
  716. return hr;
  717. }
  718. //----------------------------------------------------------------------------
  719. //
  720. // BitFieldParser
  721. //
  722. // DebugOutputCallback class to parse bitfield type output
  723. //
  724. //----------------------------------------------------------------------------
  725. BitFieldParser::BitFieldParser(
  726. PDEBUG_CLIENT Client,
  727. BitFieldInfo *BFI
  728. ) :
  729. BitFieldReader(Client, 2)
  730. {
  731. if (BFI != NULL &&
  732. BitFieldReader.LookFor(&BitPos, ": Pos ", DEBUG_VALUE_INT32) == S_OK &&
  733. BitFieldReader.LookFor(&Bits, ", ", DEBUG_VALUE_INT32) == S_OK)
  734. {
  735. BitField = BFI;
  736. BitField->Valid = FALSE;
  737. BitField->BitPos = 0;
  738. BitField->Bits = 0;
  739. BitField->Mask = 0;
  740. }
  741. else
  742. {
  743. BitField = NULL;
  744. }
  745. }
  746. HRESULT
  747. BitFieldParser::Parse(
  748. IN PCSTR Text,
  749. OUT OPTIONAL PULONG RemainderIndex
  750. )
  751. {
  752. PCSTR pStrUnused = Text;
  753. ULONG UnusedIndex = 0;
  754. PCSTR pStrRemaining;
  755. BitFieldInfo Field;
  756. do
  757. {
  758. if (BitFieldReader.Complete() == S_OK)
  759. {
  760. BitFieldReader.Relook();
  761. }
  762. BitFieldReader.Parse(pStrUnused, &UnusedIndex);
  763. pStrUnused += UnusedIndex;
  764. if (BitFieldReader.Complete() != S_OK)
  765. {
  766. break;
  767. }
  768. if (!BitField->Valid)
  769. {
  770. BitField->Valid = BitField->Compose(BitPos.I32, Bits.I32);
  771. }
  772. else
  773. {
  774. // Full extent of bit fields seen so far
  775. BitField->Bits = Bits.I32 + BitPos.I32 - BitField->BitPos;
  776. // Full mask of bit fields seen so far
  777. if (Field.Compose(BitPos.I32, Bits.I32))
  778. {
  779. BitField->Mask |= Field.Mask;
  780. }
  781. }
  782. // See if there is anything else we might want to parse.
  783. pStrRemaining = pStrUnused;
  784. while (isspace(*pStrRemaining) || *pStrRemaining == '\n')
  785. {
  786. pStrRemaining++;
  787. }
  788. } while (pStrRemaining != '\0');
  789. if (RemainderIndex != NULL)
  790. {
  791. *RemainderIndex = (ULONG)(pStrUnused - Text);
  792. }
  793. return S_OK;
  794. }
  795. //----------------------------------------------------------------------------
  796. //
  797. // OutputFilter
  798. //
  799. // DebugOutputCallback class to filter output
  800. // by skipping/replacing lines.
  801. //
  802. //----------------------------------------------------------------------------
  803. STDMETHODIMP
  804. OutputFilter::Output(
  805. THIS_
  806. IN ULONG Mask,
  807. IN PCSTR Text
  808. )
  809. {
  810. return (Outputing) ?
  811. S_OK :
  812. OutputReader::Output(Mask, Text);
  813. }
  814. HRESULT
  815. OutputFilter::Query(
  816. PCSTR Query,
  817. PDEBUG_VALUE Value,
  818. ULONG Type,
  819. ULONG Radix
  820. )
  821. {
  822. if (Query == NULL) return E_INVALIDARG;
  823. if (Buffer == NULL) return S_FALSE;
  824. HRESULT hr;
  825. BasicOutputParser Parser(Client, 1);
  826. if ((hr = Parser.LookFor(Value, Query, Type, Radix)) == S_OK &&
  827. (hr = Parser.Parse(Buffer, NULL)) == S_OK)
  828. {
  829. hr = Parser.Complete();
  830. }
  831. return hr;
  832. }
  833. OutputFilter::QuerySpec::QuerySpec(
  834. ULONG QueryFlags,
  835. PCSTR QueryText
  836. )
  837. {
  838. Next = NULL;
  839. Flags = QueryFlags;
  840. QueryLen = (QueryText== NULL) ? 0 : strlen(QueryText);
  841. if (QueryLen)
  842. {
  843. Query = new CHAR[QueryLen+1];
  844. if (Query == NULL)
  845. {
  846. QueryLen = 0;
  847. }
  848. else
  849. {
  850. strcpy(Query, QueryText);
  851. }
  852. }
  853. else
  854. {
  855. Query = NULL;
  856. }
  857. }
  858. OutputFilter::ReplacementSpec::ReplacementSpec(
  859. ULONG QueryFlags,
  860. PCSTR QueryText,
  861. PCSTR ReplacementText
  862. ) : QuerySpec(QueryFlags, QueryText)
  863. {
  864. ReplacementLen = (ReplacementText== NULL) ? 0 : strlen(ReplacementText);
  865. if (ReplacementLen)
  866. {
  867. Replacement = new CHAR[ReplacementLen+1];
  868. if (Replacement == NULL)
  869. {
  870. ReplacementLen = 0;
  871. }
  872. else
  873. {
  874. strcpy(Replacement, ReplacementText);
  875. }
  876. }
  877. else
  878. {
  879. Replacement = NULL;
  880. }
  881. }
  882. OutputFilter::QuerySpec **
  883. OutputFilter::FindPrior(
  884. ULONG Flags,
  885. PCSTR Query,
  886. QuerySpec **List
  887. )
  888. {
  889. QuerySpec **Prior = List;
  890. QuerySpec *Next;
  891. for (Next = *Prior; Next != NULL; Next = Next->Next)
  892. {
  893. if (Flags > Next->Flags ||
  894. (Flags == Next->Flags &&
  895. strcmp(Query, Next->Query) >= 0))
  896. {
  897. break;
  898. }
  899. Prior = &Next->Next;
  900. }
  901. return Prior;
  902. }
  903. HRESULT
  904. OutputFilter::Replace(
  905. ULONG Flags,
  906. PCSTR Query,
  907. PCSTR Replacement
  908. )
  909. {
  910. if (Query == NULL ||
  911. (Flags & OUTFILTER_REPLACE_LINE) == 0 ||
  912. (Flags & OUTFILTER_REPLACE_LINE) == (OUTFILTER_REPLACE_BEFORE | OUTFILTER_REPLACE_AFTER))
  913. {
  914. return E_INVALIDARG;
  915. }
  916. // Don't support replacing one query each time in a single line.
  917. // This is ok if there can be no further replacements on a matching line.
  918. if (((Flags & (OUTFILTER_REPLACE_ONCE | OUTFILTER_QUERY_ONE_LINE)) ==
  919. (OUTFILTER_REPLACE_EVERY | OUTFILTER_QUERY_ONE_LINE)) &&
  920. !(Flags & (OUTFILTER_REPLACE_AFTER | OUTFILTER_REPLACE_NEXT_LINE)))
  921. {
  922. return E_NOTIMPL;
  923. }
  924. // Set priority to level 0 if not specified.
  925. if ((Flags & OUTFILTER_REPLACE_PRIORITY(7)) == 0)
  926. {
  927. Flags |= OUTFILTER_REPLACE_PRIORITY(0);
  928. }
  929. ReplacementSpec **PriorNext;
  930. ReplacementSpec *Next;
  931. ULONG ReplacementLen;
  932. ReplacementLen = (Replacement == NULL) ? 0 : strlen(Replacement);
  933. PriorNext = (ReplacementSpec **)FindPrior(Flags, Query, (QuerySpec**)&ReplaceList);
  934. Next = *PriorNext;
  935. if (Next != NULL &&
  936. Flags == Next->Flags &&
  937. strcmp(Query, Next->Query) == 0)
  938. {
  939. if (ReplacementLen == 0)
  940. {
  941. if (Next->Replacement != NULL)
  942. {
  943. Next->Replacement[0] = '\0';
  944. }
  945. }
  946. else
  947. {
  948. if (ReplacementLen > Next->ReplacementLen)
  949. {
  950. PSTR NewReplacement = new CHAR[ReplacementLen+1];
  951. if (NewReplacement == NULL) return E_OUTOFMEMORY;
  952. if (Next->Replacement != NULL)
  953. {
  954. delete[] Next->Replacement;
  955. Next->Replacement = NewReplacement;
  956. }
  957. }
  958. strcpy(Next->Replacement, Replacement);
  959. }
  960. Next->ReplacementLen = ReplacementLen;
  961. }
  962. else
  963. {
  964. ReplacementSpec *NewQuery;
  965. NewQuery = new ReplacementSpec(Flags, Query, Replacement);
  966. if (NewQuery == NULL) return E_OUTOFMEMORY;
  967. if (NewQuery->Query == NULL ||
  968. (ReplacementLen && NewQuery->Replacement == NULL))
  969. {
  970. delete NewQuery;
  971. return E_OUTOFMEMORY;
  972. }
  973. NewQuery->Next = Next;
  974. *PriorNext = NewQuery;
  975. }
  976. return S_OK;
  977. }
  978. HRESULT
  979. OutputFilter::Skip(
  980. ULONG Flags,
  981. PCSTR Query
  982. )
  983. {
  984. if (Query == NULL)
  985. {
  986. return E_INVALIDARG;
  987. }
  988. QuerySpec **PriorNext;
  989. QuerySpec *Next;
  990. PriorNext = FindPrior(Flags, Query, &SkipList);
  991. Next = *PriorNext;
  992. if (Next == NULL ||
  993. Flags != Next->Flags ||
  994. strcmp(Query, Next->Query) != 0)
  995. {
  996. QuerySpec *NewQuery;
  997. NewQuery = new QuerySpec(Flags, Query);
  998. if (NewQuery == NULL) return E_OUTOFMEMORY;
  999. if (NewQuery->Query == NULL)
  1000. {
  1001. delete NewQuery;
  1002. return E_OUTOFMEMORY;
  1003. }
  1004. NewQuery->Next = Next;
  1005. *PriorNext = NewQuery;
  1006. }
  1007. return S_OK;
  1008. }
  1009. OutputFilter::QuerySpec *
  1010. OutputFilter::FindMatch(
  1011. PCSTR Text,
  1012. QuerySpec *List,
  1013. ULONG Start,
  1014. ULONG Flags,
  1015. PULONG MatchPos
  1016. )
  1017. {
  1018. ULONG Remaining = strlen(Text);
  1019. PCSTR Search;
  1020. QuerySpec *Match;
  1021. if (MatchPos != NULL) *MatchPos = 0;
  1022. if (List == NULL ||
  1023. Text == NULL ||
  1024. (Remaining = strlen(Text)) <= Start) return NULL;
  1025. Search = Text + Start;
  1026. Remaining -= Start;
  1027. do
  1028. {
  1029. for (Match = List; Match != NULL; Match = Match->Next)
  1030. {
  1031. if (Match->Flags & OUTFILTER_QUERY_ENABLED &&
  1032. Remaining >= Match->QueryLen &&
  1033. strncmp(Search, Match->Query, Match->QueryLen) == 0)
  1034. {
  1035. if (Match->Flags & OUTFILTER_QUERY_WHOLE_WORD)
  1036. {
  1037. if ((Search > Text && iscsym(Search[-1])) ||
  1038. iscsym(Search[Match->QueryLen]))
  1039. {
  1040. continue;
  1041. }
  1042. }
  1043. /*
  1044. if (Match->Flags & OUTFILTER_QUERY_ONE_LINE)
  1045. {
  1046. Match->Flags &= ~OUTFILTER_QUERY_ENABLED;
  1047. }
  1048. */
  1049. Match->Flags |= OUTFILTER_QUERY_HIT;
  1050. if (MatchPos != NULL)
  1051. {
  1052. *MatchPos = (ULONG)(Search - Text);
  1053. }
  1054. return Match;
  1055. }
  1056. }
  1057. Search++;
  1058. Remaining--;
  1059. } while (Remaining &&
  1060. !(Flags & OUTFILTER_FINDMATCH_AT_START));
  1061. return NULL;
  1062. }
  1063. HRESULT
  1064. OutputFilter::OutputText(
  1065. OutputControl *OutCtl,
  1066. ULONG Mask
  1067. )
  1068. {
  1069. // 1. Get line of read buffer
  1070. // 2. Search for a skip query match
  1071. // 3. Search for any/all replace query matches
  1072. if (Buffer == NULL) return S_OK;
  1073. HRESULT hr;
  1074. PSTR pNextLine;
  1075. CHAR EndChar;
  1076. PSTR pFilter;
  1077. if (OutCtl == NULL)
  1078. {
  1079. OutCtl = new OutputControl(Client);
  1080. if (OutCtl == NULL)
  1081. {
  1082. return E_OUTOFMEMORY;
  1083. }
  1084. }
  1085. else
  1086. {
  1087. OutCtl->AddRef();
  1088. }
  1089. // Can we quickly just output all text?
  1090. if (SkipList == NULL && ReplaceList == NULL)
  1091. {
  1092. hr = OutCtl->Output(Mask, Buffer);
  1093. OutCtl->Release();
  1094. return hr;
  1095. }
  1096. Outputing = TRUE;
  1097. // Enable all queries and reset hit markings.
  1098. QuerySpec *Query;
  1099. for (Query = SkipList; Query != NULL; Query = Query->Next)
  1100. {
  1101. Query->Flags = (Query->Flags & ~OUTFILTER_QUERY_HIT) | OUTFILTER_QUERY_ENABLED;
  1102. }
  1103. for (Query = (QuerySpec *)ReplaceList; Query != NULL; Query = Query->Next)
  1104. {
  1105. Query->Flags = (Query->Flags & ~OUTFILTER_QUERY_HIT) | OUTFILTER_QUERY_ENABLED;
  1106. }
  1107. hr = S_OK;
  1108. pNextLine = Buffer;
  1109. while (hr == S_OK && *pNextLine != '\0')
  1110. {
  1111. if (OutCtl->GetInterrupt() == S_OK)
  1112. {
  1113. OutCtl->SetInterrupt(DEBUG_INTERRUPT_PASSIVE);
  1114. break;
  1115. }
  1116. pFilter = pNextLine;
  1117. // Find end of this line
  1118. while ((*pNextLine != '\0') &&
  1119. (*pNextLine != '\n') &&
  1120. (*pNextLine != '\r') &&
  1121. (*pNextLine != '\f'))
  1122. {
  1123. pNextLine++;
  1124. }
  1125. EndChar = *pNextLine;
  1126. *pNextLine = '\0';
  1127. // Search for a skip match
  1128. Query = FindMatch(pFilter, SkipList);
  1129. if (Query != NULL)
  1130. {
  1131. DbgPrint("Skipping line with %s.\n", Query->Query);
  1132. if (Query->Flags & OUTFILTER_QUERY_ONE_LINE)
  1133. {
  1134. Query->Flags &= ~OUTFILTER_QUERY_ENABLED;
  1135. }
  1136. *pNextLine = EndChar;
  1137. if (EndChar != '\0')
  1138. {
  1139. pNextLine++;
  1140. }
  1141. }
  1142. else
  1143. {
  1144. PSTR pFilterLine = pFilter;
  1145. ULONG MatchPos = 0;
  1146. ReplacementSpec *Replace;
  1147. for (Replace = ReplaceList;
  1148. Replace != NULL;
  1149. Replace = (ReplacementSpec *)Replace->Next)
  1150. {
  1151. if (!(Replace->Flags & (OUTFILTER_QUERY_ONE_LINE | OUTFILTER_QUERY_ENABLED)))
  1152. {
  1153. Replace->Flags |= OUTFILTER_QUERY_ENABLED;
  1154. }
  1155. }
  1156. while (pFilter < pNextLine &&
  1157. (Replace = (ReplacementSpec *)FindMatch(pFilterLine,
  1158. ReplaceList,
  1159. MatchPos,
  1160. OUTFILTER_FINDMATCH_DEFAULT,
  1161. &MatchPos)) != NULL)
  1162. {
  1163. if (Replace->Flags & (OUTFILTER_QUERY_ONE_LINE | OUTFILTER_REPLACE_ONCE))
  1164. {
  1165. Replace->Flags &= ~OUTFILTER_QUERY_ENABLED;
  1166. }
  1167. if (Replace->Flags & OUTFILTER_REPLACE_BEFORE)
  1168. {
  1169. if (Replace->ReplacementLen)
  1170. {
  1171. hr = OutCtl->Output(Mask, "%s", Replace->Replacement);
  1172. }
  1173. pFilter = pFilterLine + MatchPos;
  1174. if (!(Replace->Flags & OUTFILTER_REPLACE_NEXT_LINE) &&
  1175. !(Replace->Flags & OUTFILTER_REPLACE_ONCE) &&
  1176. !(Replace->Flags & OUTFILTER_REPLACE_TO_END))
  1177. {
  1178. // This replacement leaves the query text intact.
  1179. // Hence this query will keep matching; so, look for
  1180. // another query which will actually modify the
  1181. // query text or the text following it.
  1182. Replace = (ReplacementSpec *)Replace->Next;
  1183. while (Replace != NULL &&
  1184. Replace->Flags & OUTFILTER_REPLACE_BEFORE)
  1185. {
  1186. Replace = (ReplacementSpec *)Replace->Next;
  1187. }
  1188. Replace = (ReplacementSpec *)
  1189. FindMatch(pFilterLine,
  1190. Replace,
  1191. MatchPos,
  1192. OUTFILTER_FINDMATCH_AT_START |
  1193. OUTFILTER_FINDMATCH_NO_MARK);
  1194. if (Replace == NULL)
  1195. {
  1196. // Advance MatchPos, but not filtered text.
  1197. // This unfiltered text may yet be replaced.
  1198. MatchPos++;
  1199. continue;
  1200. }
  1201. }
  1202. }
  1203. if (!(Replace->Flags & OUTFILTER_REPLACE_BEFORE))
  1204. {
  1205. CHAR TempHolder;
  1206. ULONG BeginReplacePos = MatchPos;
  1207. if (!(Replace->Flags & OUTFILTER_REPLACE_THIS))
  1208. {
  1209. BeginReplacePos += Replace->QueryLen;
  1210. }
  1211. TempHolder = pFilterLine[BeginReplacePos];
  1212. pFilterLine[BeginReplacePos] = '\0';
  1213. if ((hr = OutCtl->Output(Mask, "%s", pFilter)) == S_OK &&
  1214. Replace->ReplacementLen)
  1215. {
  1216. hr = OutCtl->Output(Mask, "%s", Replace->Replacement);
  1217. }
  1218. pFilterLine[BeginReplacePos] = TempHolder;
  1219. }
  1220. if (Replace->Flags & OUTFILTER_REPLACE_AFTER)
  1221. {
  1222. pFilter = pNextLine;
  1223. }
  1224. else
  1225. {
  1226. if (Replace->Flags & OUTFILTER_REPLACE_THIS)
  1227. {
  1228. MatchPos += Replace->QueryLen;
  1229. }
  1230. pFilter = pFilterLine + MatchPos;
  1231. }
  1232. if (Replace->Flags & OUTFILTER_REPLACE_NEXT_LINE) break;
  1233. }
  1234. *pNextLine = EndChar;
  1235. if (EndChar != '\0')
  1236. {
  1237. pNextLine++;
  1238. // Include any following zero length lines
  1239. while ((*pNextLine == '\n') ||
  1240. (*pNextLine == '\r') ||
  1241. (*pNextLine == '\f'))
  1242. {
  1243. pNextLine++;
  1244. }
  1245. EndChar = *pNextLine;
  1246. *pNextLine = '\0';
  1247. }
  1248. // Output remaining portion of filtered line
  1249. hr = OutCtl->Output(Mask, pFilter);
  1250. if (EndChar != '\0')
  1251. {
  1252. *pNextLine = EndChar;
  1253. }
  1254. }
  1255. }
  1256. Outputing = FALSE;
  1257. OutCtl->Release();
  1258. return hr;
  1259. }