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.

1841 lines
45 KiB

  1. //----------------------------------------------------------------------------
  2. //
  3. // Debuggee state buffers.
  4. //
  5. // Copyright (C) Microsoft Corporation, 1999-2002.
  6. //
  7. //----------------------------------------------------------------------------
  8. #include "precomp.hxx"
  9. #pragma hdrstop
  10. #include <malloc.h>
  11. #if 0
  12. #define DBG_BUFFER
  13. #endif
  14. StateBuffer g_UiOutputCapture(256);
  15. #define MAX_REG_NAMES 8
  16. RegisterNamesStateBuffer g_RegisterNameBuffers[MAX_REG_NAMES];
  17. //----------------------------------------------------------------------------
  18. //
  19. // StateBuffer.
  20. //
  21. //----------------------------------------------------------------------------
  22. StateBuffer::StateBuffer(ULONG ChangeBy)
  23. {
  24. Dbg_InitializeCriticalSection(&m_Lock);
  25. Flink = NULL;
  26. Blink = NULL;
  27. m_ChangeBy = ChangeBy;
  28. m_Win = NULL;
  29. m_UpdateTypes = 0;
  30. m_UpdateType = UPDATE_BUFFER;
  31. m_UpdateMessage = WU_UPDATE;
  32. m_Status = S_OK;
  33. // The buffer must start out with an outstanding
  34. // read request to indicate that it doesn't have valid content.
  35. m_ReadRequest = 1;
  36. m_ReadDone = 0;
  37. SetNoData();
  38. }
  39. StateBuffer::~StateBuffer(void)
  40. {
  41. Free();
  42. Dbg_DeleteCriticalSection(&m_Lock);
  43. }
  44. PVOID
  45. StateBuffer::AddData(ULONG Len)
  46. {
  47. PVOID Ret;
  48. ULONG Needed;
  49. Needed = m_DataUsed + Len;
  50. if (Needed > m_DataLen)
  51. {
  52. if (Resize(Needed) != S_OK)
  53. {
  54. return NULL;
  55. }
  56. }
  57. Ret = m_Data + m_DataUsed;
  58. m_DataUsed += Len;
  59. return Ret;
  60. }
  61. BOOL
  62. StateBuffer::AddString(PCSTR Str, BOOL SoftTerminate)
  63. {
  64. ULONG Len = strlen(Str) + 1;
  65. PSTR Buf = (PSTR)AddData(Len);
  66. if (Buf != NULL)
  67. {
  68. memcpy(Buf, Str, Len);
  69. if (SoftTerminate)
  70. {
  71. // Back up to pack strings without intervening
  72. // terminators. Buffer isn't shrunk so terminator
  73. // remains to terminate the overall buffer until
  74. // new data.
  75. RemoveTail(1);
  76. }
  77. return TRUE;
  78. }
  79. return FALSE;
  80. }
  81. void
  82. StateBuffer::RemoveHead(ULONG Len)
  83. {
  84. if (Len > m_DataUsed)
  85. {
  86. Len = m_DataUsed;
  87. }
  88. ULONG Left = m_DataUsed - Len;
  89. if (Len > 0 && Left > 0)
  90. {
  91. memmove(m_Data, (PBYTE)m_Data + Len, Left);
  92. }
  93. m_DataUsed = Left;
  94. }
  95. void
  96. StateBuffer::RemoveMiddle(ULONG Start, ULONG Len)
  97. {
  98. if (Start >= m_DataUsed)
  99. {
  100. return;
  101. }
  102. if (Start + Len > m_DataUsed)
  103. {
  104. Len = m_DataUsed - Start;
  105. }
  106. ULONG Left = m_DataUsed - Len - Start;
  107. if (Len > 0 && Left > 0)
  108. {
  109. memmove(m_Data + Start, (PBYTE)m_Data + Start + Len, Left);
  110. }
  111. m_DataUsed = Start + Left;
  112. }
  113. void
  114. StateBuffer::RemoveTail(ULONG Len)
  115. {
  116. if (Len > m_DataUsed)
  117. {
  118. Len = m_DataUsed;
  119. }
  120. m_DataUsed -= Len;
  121. }
  122. HRESULT
  123. StateBuffer::Resize(ULONG Len)
  124. {
  125. PBYTE NewData;
  126. ULONG NewLen;
  127. if (Len == m_DataLen)
  128. {
  129. return S_OK;
  130. }
  131. NewLen = m_DataLen;
  132. if (Len < NewLen)
  133. {
  134. do
  135. {
  136. NewLen -= m_ChangeBy;
  137. }
  138. while (NewLen > Len);
  139. NewLen += m_ChangeBy;
  140. }
  141. else
  142. {
  143. do
  144. {
  145. NewLen += m_ChangeBy;
  146. }
  147. while (NewLen < Len);
  148. }
  149. #if DBG
  150. // Force every resize to go to a new memory block
  151. // and backfill the old block to make it obvious
  152. // when pointers are being held across resizes.
  153. if (NewLen == 0)
  154. {
  155. free(m_Data);
  156. NewData = NULL;
  157. }
  158. else
  159. {
  160. NewData = (PBYTE)malloc(NewLen);
  161. if (NewData != NULL && m_Data != NULL)
  162. {
  163. ULONG OldLen = _msize(m_Data);
  164. ULONG CopyLen = min(OldLen, NewLen);
  165. memcpy(NewData, m_Data, CopyLen);
  166. memset(m_Data, 0xfe, OldLen);
  167. free(m_Data);
  168. }
  169. }
  170. #else
  171. NewData = (PBYTE)realloc(m_Data, NewLen);
  172. #endif
  173. if (NewLen > 0 && NewData == NULL)
  174. {
  175. return E_OUTOFMEMORY;
  176. }
  177. m_Data = NewData;
  178. m_DataLen = NewLen;
  179. return S_OK;
  180. }
  181. void
  182. StateBuffer::Free(void)
  183. {
  184. free(m_Data);
  185. SetNoData();
  186. }
  187. HRESULT
  188. StateBuffer::Update(void)
  189. {
  190. ULONG Request;
  191. // First sample the request value. This
  192. // value will be set as the done value if
  193. // a read is performed and therefore must
  194. // be sampled first to make it the most
  195. // conservative estimate of what was done.
  196. Request = m_ReadRequest;
  197. if (Request != m_ReadDone)
  198. {
  199. LockStateBuffer(this);
  200. m_Status = ReadState();
  201. // Always mark the buffer with the latest completed
  202. // sequence so that errors get picked up in addition
  203. // to successful reads.
  204. m_ReadDone = Request;
  205. #ifdef DBG_BUFFER
  206. if (m_Status != S_OK)
  207. {
  208. DebugPrint("State buffer %p:%d fill failed, 0x%X\n",
  209. this, m_enumType, m_Status);
  210. }
  211. if (m_ReadRequest != m_ReadDone)
  212. {
  213. DebugPrint("State buffer %p:%d fill out of date, "
  214. "req %X, done %X\n",
  215. this, m_enumType, m_ReadRequest, m_ReadDone);
  216. }
  217. #endif
  218. UnlockStateBuffer(this);
  219. if (m_Win != NULL)
  220. {
  221. PostMessage(m_Win, m_UpdateMessage, 0, 0);
  222. }
  223. if (m_Status == S_OK && m_UpdateTypes)
  224. {
  225. UpdateBufferWindows(m_UpdateTypes, m_UpdateType);
  226. }
  227. }
  228. return m_Status;
  229. }
  230. void
  231. StateBuffer::UiRequestRead(void)
  232. {
  233. //
  234. // Called on the UI thread.
  235. //
  236. // No need to lock here as a race for
  237. // the read request value is not a problem.
  238. // If the read request value is sampled early
  239. // and a read request does not occur it'll
  240. // happen the next time around since this routine
  241. // also wakes the engine.
  242. RequestRead();
  243. UpdateEngine();
  244. }
  245. HRESULT
  246. StateBuffer::UiLockForRead(void)
  247. {
  248. ULONG Done;
  249. //
  250. // Called on the UI thread.
  251. //
  252. // First sample the read count without locking.
  253. Done = m_ReadDone;
  254. // Now check whether the request is newer than the
  255. // last read done. The UI thread is the only thread
  256. // that updates the request count so this should be safe.
  257. if (Done == m_ReadRequest)
  258. {
  259. HRESULT Status;
  260. LockStateBuffer(this);
  261. Status = m_Status;
  262. if (FAILED(Status))
  263. {
  264. // If there was an error when filling the buffer
  265. // return it and leave the buffer unlocked.
  266. UnlockStateBuffer(this);
  267. return Status;
  268. }
  269. // Buffer is locked and valid.
  270. return S_OK;
  271. }
  272. else
  273. {
  274. // Buffer content is out-of-date so don't lock.
  275. // Make sure the engine is active to update the buffer.
  276. return S_FALSE;
  277. }
  278. }
  279. HRESULT
  280. StateBuffer::ReadState(void)
  281. {
  282. return S_OK;
  283. }
  284. //----------------------------------------------------------------------------
  285. //
  286. // OutputToStateBuffer.
  287. //
  288. //----------------------------------------------------------------------------
  289. HRESULT
  290. OutputToStateBuffer::Start(BOOL Empty)
  291. {
  292. if (Empty)
  293. {
  294. m_Buffer->Empty();
  295. }
  296. m_DataStart = m_Buffer->GetDataLen();
  297. m_Status = S_OK;
  298. m_NewLineCount = 0;
  299. m_PartialLine = 0;
  300. return S_OK;
  301. }
  302. HRESULT
  303. OutputToStateBuffer::End(BOOL RemoveLastNewLine)
  304. {
  305. if (RemoveLastNewLine && m_PartialLine == 0)
  306. {
  307. // Remove the final newline so that richedit doesn't leave
  308. // a blank line at the bottom of the window when the
  309. // text is displayed.
  310. *((PSTR)m_Buffer->GetDataBuffer() + m_Buffer->GetDataLen() - 1) = 0;
  311. }
  312. else
  313. {
  314. // Every individual line allocates space for a terminator
  315. // and then backs up. This requested space should always
  316. // be available.
  317. PVOID Data = m_Buffer->AddData(1);
  318. Assert(Data != NULL);
  319. }
  320. return m_Status;
  321. }
  322. void
  323. OutputToStateBuffer::ReplaceChar(char From, char To)
  324. {
  325. PSTR Buf = (PSTR)m_Buffer->GetDataBuffer() + m_DataStart;
  326. PSTR End = (PSTR)m_Buffer->GetDataBuffer() + m_Buffer->GetDataLen();
  327. while (Buf < End)
  328. {
  329. if (*Buf == From)
  330. {
  331. *Buf = To;
  332. }
  333. Buf++;
  334. }
  335. }
  336. STDMETHODIMP
  337. OutputToStateBuffer::Output(
  338. THIS_
  339. IN ULONG Mask,
  340. IN PCSTR Text
  341. )
  342. {
  343. if (!m_Buffer->AddString(Text, TRUE))
  344. {
  345. return E_OUTOFMEMORY;
  346. }
  347. AddLines(Text);
  348. return S_OK;
  349. }
  350. void
  351. OutputToStateBuffer::AddLines(PCSTR Start)
  352. {
  353. PCSTR LastNl = Start;
  354. PCSTR Nl;
  355. for (;;)
  356. {
  357. Nl = strchr(LastNl, '\n');
  358. if (Nl == NULL)
  359. {
  360. break;
  361. }
  362. m_NewLineCount++;
  363. LastNl = Nl + 1;
  364. }
  365. // If the last newline wasn't at the end of the text there's
  366. // a partial line which needs to count in the line count
  367. // but only until a finishing newline comes in.
  368. m_PartialLine = *LastNl != 0 ? 1 : 0;
  369. }
  370. OutputToStateBuffer g_OutStateBuf;
  371. OutputToStateBuffer g_UiOutStateBuf;
  372. //----------------------------------------------------------------------------
  373. //
  374. // Dynamic state buffers.
  375. //
  376. //----------------------------------------------------------------------------
  377. // Keep the amount of text retrieved for the system name short
  378. // so that it doesn't dominate the status bar.
  379. #define MAX_SYSNAME 8
  380. LIST_ENTRY g_StateList;
  381. DBG_CRITICAL_SECTION g_QuickLock;
  382. ULONG64 g_CodeIp;
  383. char g_CodeFileFound[MAX_SOURCE_PATH];
  384. char g_CodeSymFile[MAX_SOURCE_PATH];
  385. char g_CodePathComponent[MAX_SOURCE_PATH];
  386. ULONG g_CodeLine;
  387. BOOL g_CodeUserActivated;
  388. ULONG g_CodeBufferSequence;
  389. ULONG64 g_EventIp;
  390. ULONG g_CurSystemId;
  391. char g_CurSystemName[MAX_SYSNAME];
  392. ULONG g_CurProcessId, g_CurProcessSysId;
  393. ULONG g_CurThreadId, g_CurThreadSysId;
  394. ULONG g_EventBufferRequest;
  395. ULONG g_EventBufferDone;
  396. void
  397. FillCodeBuffer(ULONG64 Ip, BOOL UserActivated)
  398. {
  399. char File[MAX_SOURCE_PATH];
  400. char Found[MAX_SOURCE_PATH];
  401. char PathComp[MAX_SOURCE_PATH];
  402. ULONG Line;
  403. ULONG64 Disp;
  404. BOOL Changed;
  405. // Fill local information rather than global information
  406. // to avoid changing the global information until all
  407. // event information has been collected.
  408. if (g_pDbgSymbols->
  409. GetLineByOffset(Ip, &Line, File, sizeof(File), NULL, &Disp) != S_OK)
  410. {
  411. // This will be hit if the buffer is too small
  412. // to hold the filename. This could be switched to dynamically
  413. // allocate the filename buffer but that seems like overkill.
  414. File[0] = 0;
  415. Found[0] = 0;
  416. }
  417. else
  418. {
  419. ULONG FoundElt;
  420. // Source information is one-based but the source
  421. // window lines are zero-based.
  422. Line--;
  423. // Look up the reported file along the source path.
  424. // XXX drewb - Use first-match and then element walk to
  425. // determine ambiguities and display resolution UI.
  426. if (g_pLocSymbols->
  427. FindSourceFile(0, File,
  428. DEBUG_FIND_SOURCE_BEST_MATCH |
  429. DEBUG_FIND_SOURCE_FULL_PATH,
  430. &FoundElt, Found, sizeof(Found), NULL) != S_OK)
  431. {
  432. // XXX drewb - Display UI instead of just disabling source?
  433. Found[0] = 0;
  434. }
  435. else if (g_pLocSymbols->
  436. GetSourcePathElement(FoundElt, PathComp, sizeof(PathComp),
  437. NULL) != S_OK)
  438. {
  439. PathComp[0] = 0;
  440. }
  441. }
  442. // Now that all of the information has been collected
  443. // take the lock and update the global state.
  444. Dbg_EnterCriticalSection(&g_QuickLock);
  445. //
  446. // Avoid updating the code buffer unless there's been
  447. // an actual change to avoid excessive window position changes
  448. // when the current-IP location is brought to the front.
  449. //
  450. // If the user has requested the change, always do it
  451. // to force such window changes.
  452. //
  453. Changed = FALSE;
  454. if (g_CodeIp != Ip)
  455. {
  456. g_CodeIp = Ip;
  457. Changed = TRUE;
  458. }
  459. if (strcmp(g_CodeFileFound, Found))
  460. {
  461. strcpy(g_CodeFileFound, Found);
  462. Changed = TRUE;
  463. }
  464. if (strcmp(g_CodeSymFile, File))
  465. {
  466. strcpy(g_CodeSymFile, File);
  467. Changed = TRUE;
  468. }
  469. if (strcmp(g_CodePathComponent, PathComp))
  470. {
  471. strcpy(g_CodePathComponent, PathComp);
  472. Changed = TRUE;
  473. }
  474. if (g_CodeLine != Line)
  475. {
  476. g_CodeLine = Line;
  477. Changed = TRUE;
  478. }
  479. if (g_CodeUserActivated != UserActivated)
  480. {
  481. g_CodeUserActivated = UserActivated;
  482. Changed = TRUE;
  483. }
  484. if (Changed || UserActivated)
  485. {
  486. g_CodeBufferSequence++;
  487. }
  488. Dbg_LeaveCriticalSection(&g_QuickLock);
  489. // Wake up the UI thread to process the new event location.
  490. UpdateUi();
  491. }
  492. void
  493. FillEventBuffer(void)
  494. {
  495. ULONG64 Ip;
  496. ULONG64 ScopeIp;
  497. ULONG SystemId;
  498. char FullSysName[MAX_PATH + 32];
  499. char SystemName[MAX_SYSNAME];
  500. ULONG ProcessId, ProcessSysId;
  501. ULONG ThreadId, ThreadSysId;
  502. ULONG Done = g_EventBufferRequest;
  503. HRESULT Status;
  504. if (g_pDbgRegisters->GetInstructionOffset(&Ip) != S_OK ||
  505. g_pDbgSystem->GetCurrentProcessId(&ProcessId) != S_OK ||
  506. g_pDbgSystem->GetCurrentThreadId(&ThreadId) != S_OK)
  507. {
  508. return;
  509. }
  510. if (g_pDbgSystem3)
  511. {
  512. if (g_pDbgSystem3->GetCurrentSystemId(&SystemId) != S_OK ||
  513. FAILED(g_pDbgSystem3->
  514. GetCurrentSystemServerName(FullSysName, sizeof(FullSysName),
  515. NULL)))
  516. {
  517. return;
  518. }
  519. PSTR Scan;
  520. // System names are generally "<Type>: <Specifics>". As
  521. // we only have a small amount of space, strip off the type.
  522. Scan = strchr(FullSysName, ':');
  523. if (Scan)
  524. {
  525. Scan++;
  526. if (*Scan == ' ')
  527. {
  528. Scan++;
  529. }
  530. }
  531. else
  532. {
  533. Scan = FullSysName;
  534. }
  535. CopyString(SystemName, Scan, DIMA(SystemName));
  536. }
  537. else
  538. {
  539. // Old dbgeng.dll which doesn't support multisystem.
  540. SystemId = 0;
  541. strcpy(SystemName, "<Old>");
  542. }
  543. // Kernel mode doesn't implement system IDs as the process
  544. // and threads are fakes and not real system objects. Just
  545. // use zero if E_NOTIMPL is returned.
  546. if ((Status = g_pDbgSystem->
  547. GetCurrentProcessSystemId(&ProcessSysId)) != S_OK)
  548. {
  549. if (Status == E_NOTIMPL)
  550. {
  551. ProcessSysId = 0;
  552. }
  553. else
  554. {
  555. // Unexpected error, must be a real problem.
  556. return;
  557. }
  558. }
  559. if ((Status = g_pDbgSystem->
  560. GetCurrentThreadSystemId(&ThreadSysId)) != S_OK)
  561. {
  562. if (Status == E_NOTIMPL)
  563. {
  564. ThreadSysId = 0;
  565. }
  566. else
  567. {
  568. // Unexpected error, must be a real problem.
  569. return;
  570. }
  571. }
  572. // Fill code buffer with scope Ip
  573. if (g_pDbgSymbols->GetScope(&ScopeIp, NULL, NULL, 0) != S_OK)
  574. {
  575. return;
  576. }
  577. FillCodeBuffer(ScopeIp, FALSE);
  578. g_EventIp = Ip;
  579. g_CurSystemId = SystemId;
  580. strcpy(g_CurSystemName, SystemName);
  581. g_CurProcessId = ProcessId;
  582. g_CurProcessSysId = ProcessSysId;
  583. g_CurThreadId = ThreadId;
  584. g_CurThreadSysId = ThreadSysId;
  585. if (!g_CodeLevelLocked)
  586. {
  587. ULONG CodeLevel;
  588. if (g_CodeFileFound[0] == 0)
  589. {
  590. // No source so switch to assembly mode.
  591. CodeLevel = DEBUG_LEVEL_ASSEMBLY;
  592. }
  593. else
  594. {
  595. if (GetSrcMode_StatusBar())
  596. {
  597. CodeLevel = DEBUG_LEVEL_SOURCE;
  598. }
  599. else
  600. {
  601. CodeLevel = DEBUG_LEVEL_ASSEMBLY;
  602. }
  603. }
  604. g_IgnoreCodeLevelChange = TRUE;
  605. g_pDbgControl->SetCodeLevel(CodeLevel);
  606. g_IgnoreCodeLevelChange = FALSE;
  607. }
  608. g_EventBufferDone = Done;
  609. PostMessage(g_hwndFrame, WU_UPDATE, UPDATE_EXEC, 0);
  610. }
  611. class BpStateBuffer : public StateBuffer
  612. {
  613. public:
  614. BpStateBuffer(void) :
  615. StateBuffer(256)
  616. {
  617. m_enumType = BP_BIT;
  618. m_UpdateMessage = LB_RESETCONTENT;
  619. m_UpdateTypes = (1 << DOC_WINDOW) | (1 << DISASM_WINDOW);
  620. m_UpdateType = UPDATE_BP;
  621. }
  622. virtual HRESULT ReadState(void);
  623. };
  624. // #define DBG_BPBUF
  625. #define BP_EXTRA_ENTRIES 8
  626. ULONG g_BpCount;
  627. BpStateBuffer g_PrivateBpBuffer;
  628. StateBuffer* g_BpBuffer = &g_PrivateBpBuffer;
  629. ULONG g_BpTextOffset;
  630. HRESULT
  631. BpStateBuffer::ReadState(void)
  632. {
  633. HRESULT Status;
  634. ULONG Count;
  635. ULONG TextOffset;
  636. BpBufferData* Data;
  637. ULONG i;
  638. PDEBUG_BREAKPOINT_PARAMETERS Params;
  639. char FileBuf[MAX_SOURCE_PATH];
  640. // Reserve room for BP descriptions in front of the text.
  641. // When doing so, reserve extra slots to allow for free
  642. // slots the next time around.
  643. Empty();
  644. Status = g_pDbgControl->GetNumberBreakpoints(&Count);
  645. if (Status != S_OK)
  646. {
  647. return Status;
  648. }
  649. TextOffset = (Count + BP_EXTRA_ENTRIES) * sizeof(BpBufferData);
  650. Data = (BpBufferData*)AddData(TextOffset);
  651. if (Data == NULL)
  652. {
  653. return E_OUTOFMEMORY;
  654. }
  655. // Allocate a temporary buffer for bulk breakpoint retrieval.
  656. Params = new DEBUG_BREAKPOINT_PARAMETERS[Count];
  657. if (Params == NULL)
  658. {
  659. return E_OUTOFMEMORY;
  660. }
  661. // GetBreakpointParameters can return S_FALSE when there
  662. // are hidden breakpoints.
  663. if (FAILED(Status = g_pDbgControl->
  664. GetBreakpointParameters(Count, NULL, 0, Params)) != S_OK)
  665. {
  666. delete [] Params;
  667. return Status;
  668. }
  669. // Iterate over breakpoints and retrieve offsets for
  670. // all execution breakpoints.
  671. // Take advantage of the fact that Empty does not actually
  672. // discard data to distinguish changed breakpoints from
  673. // unchanged breakpoints.
  674. ULONG Write = 0;
  675. for (i = 0; i < Count; i++)
  676. {
  677. if (Params[i].Id == DEBUG_ANY_ID ||
  678. Params[i].Offset == DEBUG_INVALID_OFFSET ||
  679. (Params[i].BreakType == DEBUG_BREAKPOINT_DATA &&
  680. Params[i].DataAccessType != DEBUG_BREAK_EXECUTE))
  681. {
  682. // Not a breakpoint that we care about, skip.
  683. continue;
  684. }
  685. // Check and see if this offset is already known.
  686. ULONG Match;
  687. for (Match = 0; Match < g_BpCount; Match++)
  688. {
  689. // NOTE: This compresses duplicate breakpoints
  690. // with a first-writer-wins on the ID.
  691. if (Data[Match].Offset == Params[i].Offset)
  692. {
  693. break;
  694. }
  695. }
  696. if (Match < g_BpCount)
  697. {
  698. BpBufferData Temp;
  699. // Keep the old record for this offset to minimize
  700. // UI updates.
  701. if (Match > Write)
  702. {
  703. Temp = Data[Match];
  704. Data[Match] = Data[Write];
  705. Data[Write] = Temp;
  706. Match = Write;
  707. }
  708. #ifdef DBG_BPBUF
  709. DebugPrint("Match %d:%I64X %d:%d into %d\n",
  710. Params[i].Id, Params[i].Offset, Data[Match].Id,
  711. Match, Write);
  712. #endif
  713. Write++;
  714. // We mostly ignore flag differences. ENABLED, however,
  715. // is important to have accurate and in the most-enabled
  716. // way.
  717. if ((Data[Match].Flags ^ Params[i].Flags) &
  718. DEBUG_BREAKPOINT_ENABLED)
  719. {
  720. if (Data[Match].Id != Params[i].Id)
  721. {
  722. Data[Match].Flags |=
  723. Params[i].Flags & DEBUG_BREAKPOINT_ENABLED;
  724. }
  725. else
  726. {
  727. Data[Match].Flags = Params[i].Flags;
  728. }
  729. Data[Match].Thread = Params[i].MatchThread;
  730. Data[Match].Sequence = g_CommandSequence;
  731. }
  732. }
  733. else
  734. {
  735. // Fill in a new record. This will potentially destroy
  736. // an old record and so reduce the effectivess of delta
  737. // checking but the front of the buffer is packed
  738. // with the extra entries to handle these changes hopefully
  739. // without eating into the actual entries.
  740. #ifdef DBG_BPBUF
  741. DebugPrint("Write %d:%I64X into %d\n", Params[i].Id,
  742. Params[i].Offset, Write);
  743. #endif
  744. Data[Write].Offset = Params[i].Offset;
  745. Data[Write].Id = Params[i].Id;
  746. Data[Write].Flags = Params[i].Flags;
  747. Data[Write].Thread = Params[i].MatchThread;
  748. Data[Write].Sequence = g_CommandSequence;
  749. Write++;
  750. }
  751. }
  752. delete [] Params;
  753. // Pack unused entries at the front of the buffer so that
  754. // they get used first in the next delta computation.
  755. Count += BP_EXTRA_ENTRIES;
  756. #ifdef DBG_BPBUF
  757. DebugPrint("Used %d of %d\n", Write, Count);
  758. #endif
  759. if (Write < Count)
  760. {
  761. ULONG Extra = Count - Write;
  762. memmove(Data + Extra, Data, Write * sizeof(*Data));
  763. for (i = 0; i < Extra; i++)
  764. {
  765. Data[i].Offset = DEBUG_INVALID_OFFSET;
  766. }
  767. }
  768. //
  769. // Now go through the valid breakpoints and look up
  770. // what file they're in, if any.
  771. //
  772. for (i = 0; i < Count; i++)
  773. {
  774. ULONG Line;
  775. PSTR FileSpace;
  776. // Refresh every time since growth may have caused
  777. // a realloc.
  778. Data = (BpBufferData*)m_Data;
  779. Data[i].FileOffset = 0;
  780. if (Data[i].Offset != DEBUG_INVALID_OFFSET &&
  781. g_pDbgSymbols->GetLineByOffset(Data[i].Offset, &Line,
  782. FileBuf, sizeof(FileBuf), NULL,
  783. NULL) == S_OK)
  784. {
  785. // Do this first before m_DataUsed is updated and
  786. // Data is invalidated.
  787. Data[i].FileOffset = m_DataUsed;
  788. FileSpace = (PSTR)AddData(sizeof(Line) + strlen(FileBuf) + 1);
  789. if (FileSpace == NULL)
  790. {
  791. return E_OUTOFMEMORY;
  792. }
  793. *(ULONG UNALIGNED *)FileSpace = Line;
  794. FileSpace += sizeof(Line);
  795. strcpy(FileSpace, FileBuf);
  796. }
  797. }
  798. TextOffset = m_DataUsed;
  799. g_OutStateBuf.SetBuffer(this);
  800. if ((Status = g_OutStateBuf.Start(FALSE)) != S_OK)
  801. {
  802. return Status;
  803. }
  804. // Get breakpoint list.
  805. Status = g_pOutCapControl->Execute(DEBUG_OUTCTL_THIS_CLIENT |
  806. DEBUG_OUTCTL_OVERRIDE_MASK |
  807. DEBUG_OUTCTL_NOT_LOGGED,
  808. "bl", DEBUG_EXECUTE_NOT_LOGGED |
  809. DEBUG_EXECUTE_NO_REPEAT);
  810. if (Status == S_OK)
  811. {
  812. Status = g_OutStateBuf.End(FALSE);
  813. if (Status == S_OK)
  814. {
  815. // Separate lines by nulls to make them easier
  816. // to process as individual strings.
  817. g_OutStateBuf.ReplaceChar('\n', 0);
  818. }
  819. }
  820. else
  821. {
  822. g_OutStateBuf.End(FALSE);
  823. }
  824. if (Status == S_OK)
  825. {
  826. g_BpCount = Count;
  827. g_BpTextOffset = TextOffset;
  828. }
  829. return Status;
  830. }
  831. class BpCmdsStateBuffer : public StateBuffer
  832. {
  833. public:
  834. BpCmdsStateBuffer(void) :
  835. StateBuffer(256)
  836. {
  837. m_enumType = BP_CMDS_BIT;
  838. }
  839. virtual HRESULT ReadState(void);
  840. };
  841. BpCmdsStateBuffer g_PrivateBpCmdsBuffer;
  842. StateBuffer* g_BpCmdsBuffer = &g_PrivateBpCmdsBuffer;
  843. HRESULT
  844. BpCmdsStateBuffer::ReadState(void)
  845. {
  846. HRESULT Status;
  847. g_OutStateBuf.SetBuffer(this);
  848. if ((Status = g_OutStateBuf.Start(TRUE)) != S_OK)
  849. {
  850. return Status;
  851. }
  852. // Get breakpoint commands.
  853. Status = g_pOutCapControl->Execute(DEBUG_OUTCTL_THIS_CLIENT |
  854. DEBUG_OUTCTL_OVERRIDE_MASK |
  855. DEBUG_OUTCTL_NOT_LOGGED,
  856. ".bpcmds -e -m -p 0",
  857. DEBUG_EXECUTE_NOT_LOGGED |
  858. DEBUG_EXECUTE_NO_REPEAT);
  859. if (Status == S_OK)
  860. {
  861. Status = g_OutStateBuf.End(FALSE);
  862. }
  863. else
  864. {
  865. g_OutStateBuf.End(FALSE);
  866. }
  867. return Status;
  868. }
  869. class FilterTextStateBuffer : public StateBuffer
  870. {
  871. public:
  872. FilterTextStateBuffer(void) :
  873. StateBuffer(256)
  874. {
  875. m_enumType = MINVAL_WINDOW;
  876. m_UpdateMessage = 0;
  877. }
  878. virtual HRESULT ReadState(void);
  879. };
  880. FilterTextStateBuffer g_PrivateFilterTextBuffer;
  881. StateBuffer* g_FilterTextBuffer = &g_PrivateFilterTextBuffer;
  882. HRESULT
  883. FilterTextStateBuffer::ReadState(void)
  884. {
  885. HRESULT Status;
  886. ULONG SpecEvents, SpecEx, ArbEx;
  887. ULONG i;
  888. PSTR Text;
  889. if ((Status = g_pDbgControl->
  890. GetNumberEventFilters(&SpecEvents, &SpecEx, &ArbEx)) != S_OK)
  891. {
  892. return Status;
  893. }
  894. Empty();
  895. DEBUG_SPECIFIC_FILTER_PARAMETERS SpecParams;
  896. for (i = 0; i < SpecEvents; i++)
  897. {
  898. if ((Status = g_pDbgControl->
  899. GetSpecificFilterParameters(i, 1, &SpecParams)) != S_OK)
  900. {
  901. return Status;
  902. }
  903. if (SpecParams.TextSize == 0)
  904. {
  905. // Put a terminator in anyway to keep the
  906. // indexing correct.
  907. if ((Text = (PSTR)AddData(1)) == NULL)
  908. {
  909. return E_OUTOFMEMORY;
  910. }
  911. *Text = 0;
  912. }
  913. else
  914. {
  915. if ((Text = (PSTR)AddData(SpecParams.TextSize)) == NULL)
  916. {
  917. return E_OUTOFMEMORY;
  918. }
  919. if ((Status = g_pDbgControl->
  920. GetEventFilterText(i, Text, SpecParams.TextSize,
  921. NULL)) != S_OK)
  922. {
  923. return Status;
  924. }
  925. }
  926. }
  927. DEBUG_EXCEPTION_FILTER_PARAMETERS ExParams;
  928. for (i = 0; i < SpecEx; i++)
  929. {
  930. if ((Status = g_pDbgControl->
  931. GetExceptionFilterParameters(1, NULL, i + SpecEvents,
  932. &ExParams)) != S_OK)
  933. {
  934. return Status;
  935. }
  936. if (ExParams.TextSize == 0)
  937. {
  938. // Put a terminator in anyway to keep the
  939. // indexing correct.
  940. if ((Text = (PSTR)AddData(1)) == NULL)
  941. {
  942. return E_OUTOFMEMORY;
  943. }
  944. *Text = 0;
  945. }
  946. else
  947. {
  948. if ((Text = (PSTR)AddData(ExParams.TextSize)) == NULL)
  949. {
  950. return E_OUTOFMEMORY;
  951. }
  952. if ((Status = g_pDbgControl->
  953. GetEventFilterText(i + SpecEvents, Text, ExParams.TextSize,
  954. NULL)) != S_OK)
  955. {
  956. return Status;
  957. }
  958. }
  959. }
  960. return S_OK;
  961. }
  962. class FilterStateBuffer : public StateBuffer
  963. {
  964. public:
  965. FilterStateBuffer(void) :
  966. StateBuffer(256)
  967. {
  968. m_enumType = FILTER_BIT;
  969. m_UpdateMessage = LB_RESETCONTENT;
  970. }
  971. virtual HRESULT ReadState(void);
  972. };
  973. FilterStateBuffer g_PrivateFilterBuffer;
  974. StateBuffer* g_FilterBuffer = &g_PrivateFilterBuffer;
  975. ULONG g_FilterArgsOffset;
  976. ULONG g_FilterCmdsOffset;
  977. ULONG g_FilterWspCmdsOffset;
  978. ULONG g_NumSpecEvents, g_NumSpecEx, g_NumArbEx;
  979. HRESULT
  980. FilterStateBuffer::ReadState(void)
  981. {
  982. ULONG SpecEvents, SpecEx, ArbEx;
  983. HRESULT Status;
  984. ULONG ArgsOffset, CmdsOffset, WspCmdsOffset;
  985. PDEBUG_SPECIFIC_FILTER_PARAMETERS SpecParams;
  986. PDEBUG_EXCEPTION_FILTER_PARAMETERS ExParams;
  987. ULONG i;
  988. if ((Status = g_pDbgControl->
  989. GetNumberEventFilters(&SpecEvents, &SpecEx, &ArbEx)) != S_OK)
  990. {
  991. return Status;
  992. }
  993. Empty();
  994. if ((SpecParams = (PDEBUG_SPECIFIC_FILTER_PARAMETERS)
  995. AddData((SpecEvents * sizeof(*SpecParams) +
  996. (SpecEx + ArbEx) * sizeof(*ExParams)))) == NULL)
  997. {
  998. return E_OUTOFMEMORY;
  999. }
  1000. ExParams = (PDEBUG_EXCEPTION_FILTER_PARAMETERS)(SpecParams + SpecEvents);
  1001. if ((Status = g_pDbgControl->
  1002. GetSpecificFilterParameters(0, SpecEvents, SpecParams)) != S_OK ||
  1003. (Status = g_pDbgControl->
  1004. GetExceptionFilterParameters(SpecEx + ArbEx, NULL, SpecEvents,
  1005. ExParams)) != S_OK)
  1006. {
  1007. return Status;
  1008. }
  1009. ArgsOffset = m_DataUsed;
  1010. for (i = 0; i < SpecEvents; i++)
  1011. {
  1012. if (SpecParams[i].ArgumentSize > 1)
  1013. {
  1014. PSTR Arg = (PSTR)AddData(SpecParams[i].ArgumentSize);
  1015. if (Arg == NULL)
  1016. {
  1017. return E_OUTOFMEMORY;
  1018. }
  1019. if ((Status = g_pDbgControl->
  1020. GetSpecificFilterArgument(i, Arg, SpecParams[i].ArgumentSize,
  1021. NULL)) != S_OK)
  1022. {
  1023. return Status;
  1024. }
  1025. }
  1026. }
  1027. CmdsOffset = m_DataUsed;
  1028. for (i = 0; i < SpecEvents; i++)
  1029. {
  1030. if (SpecParams[i].CommandSize > 0)
  1031. {
  1032. PSTR Cmd = (PSTR)AddData(SpecParams[i].CommandSize);
  1033. if (Cmd == NULL)
  1034. {
  1035. return E_OUTOFMEMORY;
  1036. }
  1037. if ((Status = g_pDbgControl->
  1038. GetEventFilterCommand(i, Cmd, SpecParams[i].CommandSize,
  1039. NULL)) != S_OK)
  1040. {
  1041. return Status;
  1042. }
  1043. }
  1044. }
  1045. for (i = 0; i < SpecEx + ArbEx; i++)
  1046. {
  1047. if (ExParams[i].CommandSize > 0)
  1048. {
  1049. PSTR Cmd = (PSTR)AddData(ExParams[i].CommandSize);
  1050. if (Cmd == NULL)
  1051. {
  1052. return E_OUTOFMEMORY;
  1053. }
  1054. if ((Status = g_pDbgControl->
  1055. GetEventFilterCommand(i + SpecEvents,
  1056. Cmd, ExParams[i].CommandSize,
  1057. NULL)) != S_OK)
  1058. {
  1059. return Status;
  1060. }
  1061. }
  1062. if (ExParams[i].SecondCommandSize > 0)
  1063. {
  1064. PSTR Cmd = (PSTR)AddData(ExParams[i].SecondCommandSize);
  1065. if (Cmd == NULL)
  1066. {
  1067. return E_OUTOFMEMORY;
  1068. }
  1069. if ((Status = g_pDbgControl->
  1070. GetExceptionFilterSecondCommand(i + SpecEvents,
  1071. Cmd,
  1072. ExParams[i].SecondCommandSize,
  1073. NULL)) != S_OK)
  1074. {
  1075. return Status;
  1076. }
  1077. }
  1078. }
  1079. WspCmdsOffset = m_DataUsed;
  1080. g_OutStateBuf.SetBuffer(this);
  1081. if ((Status = g_OutStateBuf.Start(FALSE)) != S_OK)
  1082. {
  1083. return Status;
  1084. }
  1085. // Get filter commands.
  1086. Status = g_pOutCapControl->Execute(DEBUG_OUTCTL_THIS_CLIENT |
  1087. DEBUG_OUTCTL_OVERRIDE_MASK |
  1088. DEBUG_OUTCTL_NOT_LOGGED,
  1089. ".sxcmds",
  1090. DEBUG_EXECUTE_NOT_LOGGED |
  1091. DEBUG_EXECUTE_NO_REPEAT);
  1092. if (Status == S_OK)
  1093. {
  1094. Status = g_OutStateBuf.End(FALSE);
  1095. }
  1096. else
  1097. {
  1098. g_OutStateBuf.End(FALSE);
  1099. }
  1100. if (Status == S_OK)
  1101. {
  1102. g_FilterArgsOffset = ArgsOffset;
  1103. g_FilterCmdsOffset = CmdsOffset;
  1104. g_FilterWspCmdsOffset = WspCmdsOffset;
  1105. g_NumSpecEvents = SpecEvents;
  1106. g_NumSpecEx = SpecEx;
  1107. g_NumArbEx = ArbEx;
  1108. }
  1109. return Status;
  1110. }
  1111. class ModuleStateBuffer : public StateBuffer
  1112. {
  1113. public:
  1114. ModuleStateBuffer(void) :
  1115. StateBuffer(256)
  1116. {
  1117. m_enumType = MODULE_BIT;
  1118. m_UpdateMessage = LB_RESETCONTENT;
  1119. }
  1120. virtual HRESULT ReadState(void);
  1121. };
  1122. ModuleStateBuffer g_PrivateModuleBuffer;
  1123. StateBuffer* g_ModuleBuffer = &g_PrivateModuleBuffer;
  1124. ULONG g_NumModules;
  1125. HRESULT
  1126. ModuleStateBuffer::ReadState(void)
  1127. {
  1128. HRESULT Status;
  1129. ULONG NumModules, Loaded, Unloaded;
  1130. PDEBUG_MODULE_PARAMETERS Params;
  1131. if ((Status = g_pDbgSymbols->GetNumberModules(&Loaded,
  1132. &Unloaded)) != S_OK)
  1133. {
  1134. return Status;
  1135. }
  1136. Empty();
  1137. NumModules = Loaded + Unloaded;
  1138. if (NumModules > 0)
  1139. {
  1140. if ((Params = (PDEBUG_MODULE_PARAMETERS)
  1141. AddData(NumModules * sizeof(*Params))) == NULL)
  1142. {
  1143. return E_OUTOFMEMORY;
  1144. }
  1145. if ((Status = g_pDbgSymbols->
  1146. GetModuleParameters(NumModules, NULL, 0, Params)) != S_OK)
  1147. {
  1148. return Status;
  1149. }
  1150. }
  1151. g_NumModules = NumModules;
  1152. return S_OK;
  1153. }
  1154. class AliasStateBuffer : public StateBuffer
  1155. {
  1156. public:
  1157. AliasStateBuffer(void) :
  1158. StateBuffer(256)
  1159. {
  1160. m_enumType = ALIAS_BIT;
  1161. }
  1162. virtual HRESULT ReadState(void);
  1163. };
  1164. AliasStateBuffer g_PrivateAliasBuffer;
  1165. StateBuffer* g_AliasBuffer = &g_PrivateAliasBuffer;
  1166. HRESULT
  1167. AliasStateBuffer::ReadState(void)
  1168. {
  1169. HRESULT Status;
  1170. g_OutStateBuf.SetBuffer(this);
  1171. if ((Status = g_OutStateBuf.Start(TRUE)) != S_OK)
  1172. {
  1173. return Status;
  1174. }
  1175. Status = g_pOutCapControl->Execute(DEBUG_OUTCTL_THIS_CLIENT |
  1176. DEBUG_OUTCTL_OVERRIDE_MASK |
  1177. DEBUG_OUTCTL_NOT_LOGGED,
  1178. ".aliascmds",
  1179. DEBUG_EXECUTE_NOT_LOGGED |
  1180. DEBUG_EXECUTE_NO_REPEAT);
  1181. if (Status == S_OK)
  1182. {
  1183. Status = g_OutStateBuf.End(FALSE);
  1184. }
  1185. else
  1186. {
  1187. g_OutStateBuf.End(FALSE);
  1188. }
  1189. return Status;
  1190. }
  1191. void
  1192. ReadStateBuffers(void)
  1193. {
  1194. ULONG i;
  1195. // Fill event information first so other fills can
  1196. // refer to it.
  1197. if (g_EventBufferRequest != g_EventBufferDone)
  1198. {
  1199. FillEventBuffer();
  1200. }
  1201. g_BpBuffer->Update();
  1202. g_BpCmdsBuffer->Update();
  1203. g_FilterBuffer->Update();
  1204. g_ModuleBuffer->Update();
  1205. g_AliasBuffer->Update();
  1206. for (i = 0; i < MAX_REG_NAMES; i++)
  1207. {
  1208. if (g_RegisterNameBuffers[i].m_ProcType !=
  1209. IMAGE_FILE_MACHINE_UNKNOWN)
  1210. {
  1211. g_RegisterNameBuffers[i].Update();
  1212. }
  1213. }
  1214. // No need to lock to sample the list head.
  1215. StateBuffer* Buffer = (StateBuffer*)g_StateList.Flink;
  1216. StateBuffer* BufferNext;
  1217. while (Buffer != &g_StateList)
  1218. {
  1219. BufferNext = (StateBuffer*)Buffer->Flink;
  1220. if (Buffer->m_Win == NULL)
  1221. {
  1222. // This window has been closed and can be cleaned up.
  1223. Dbg_EnterCriticalSection(&g_QuickLock);
  1224. RemoveEntryList(Buffer);
  1225. Dbg_LeaveCriticalSection(&g_QuickLock);
  1226. delete Buffer;
  1227. }
  1228. else
  1229. {
  1230. Buffer->Update();
  1231. }
  1232. Buffer = BufferNext;
  1233. }
  1234. }
  1235. void
  1236. InvalidateStateBuffers(ULONG Types)
  1237. {
  1238. // This routine can be called from both
  1239. // the engine thread and the UI thread.
  1240. // Care should be taken to make the code
  1241. // here work in both threads.
  1242. if (Types & (1 << EVENT_BIT))
  1243. {
  1244. InterlockedIncrement((PLONG)&g_EventBufferRequest);
  1245. }
  1246. if (Types & (1 << BP_BIT))
  1247. {
  1248. g_BpBuffer->RequestRead();
  1249. }
  1250. if (Types & (1 << BP_CMDS_BIT))
  1251. {
  1252. g_BpCmdsBuffer->RequestRead();
  1253. }
  1254. if (Types & (1 << FILTER_BIT))
  1255. {
  1256. g_FilterBuffer->RequestRead();
  1257. }
  1258. if (Types & (1 << MODULE_BIT))
  1259. {
  1260. g_ModuleBuffer->RequestRead();
  1261. }
  1262. if (Types & (1 << ALIAS_BIT))
  1263. {
  1264. g_AliasBuffer->RequestRead();
  1265. }
  1266. // This routine must hold the list lock so that it
  1267. // can traverse the list properly in the UI thread
  1268. // when the engine thread might be deleting things.
  1269. // The code in the lock should execute quickly to
  1270. // avoid contention.
  1271. Dbg_EnterCriticalSection(&g_QuickLock);
  1272. StateBuffer* Buffer = (StateBuffer*)g_StateList.Flink;
  1273. while (Buffer != &g_StateList)
  1274. {
  1275. if (Types & (1 << Buffer->m_enumType))
  1276. {
  1277. // Request a read but do not send an update to
  1278. // the window. The window will display the old
  1279. // content until the buffer is updated.
  1280. Buffer->RequestRead();
  1281. }
  1282. Buffer = (StateBuffer*)Buffer->Flink;
  1283. }
  1284. Dbg_LeaveCriticalSection(&g_QuickLock);
  1285. }
  1286. void
  1287. UpdateBufferWindows(ULONG Types, UpdateType Type)
  1288. {
  1289. // This routine can be called from both
  1290. // the engine thread and the UI thread.
  1291. // Care should be taken to make the code
  1292. // here work in both threads.
  1293. // This routine must hold the list lock so that it
  1294. // can traverse the list properly in the UI thread
  1295. // when the engine thread might be deleting things.
  1296. // The code in the lock should execute quickly to
  1297. // avoid contention.
  1298. Dbg_EnterCriticalSection(&g_QuickLock);
  1299. StateBuffer* Buffer = (StateBuffer*)g_StateList.Flink;
  1300. while (Buffer != &g_StateList)
  1301. {
  1302. if ((Types & (1 << Buffer->m_enumType)) &&
  1303. Buffer->m_Win != NULL)
  1304. {
  1305. PostMessage(Buffer->m_Win, WU_UPDATE, Type, 0);
  1306. }
  1307. Buffer = (StateBuffer*)Buffer->Flink;
  1308. }
  1309. Dbg_LeaveCriticalSection(&g_QuickLock);
  1310. }
  1311. //----------------------------------------------------------------------------
  1312. //
  1313. // Static state buffers.
  1314. //
  1315. //----------------------------------------------------------------------------
  1316. HRESULT
  1317. RegisterNamesStateBuffer::ReadState(void)
  1318. {
  1319. HRESULT Status;
  1320. char Name[1024];
  1321. DEBUG_REGISTER_DESCRIPTION Desc;
  1322. ULONG i;
  1323. PSTR BufName;
  1324. ULONG Len;
  1325. ULONG NumReg;
  1326. ULONG OldProcType;
  1327. ULONG NamesOffset;
  1328. PULONG Type;
  1329. if (m_ProcType == IMAGE_FILE_MACHINE_UNKNOWN)
  1330. {
  1331. return E_UNEXPECTED;
  1332. }
  1333. if ((Status = g_pDbgControl->
  1334. GetEffectiveProcessorType(&OldProcType)) != S_OK ||
  1335. (Status = g_pDbgControl->
  1336. SetEffectiveProcessorType(m_ProcType)) != S_OK)
  1337. {
  1338. return Status;
  1339. }
  1340. if ((Status = g_pDbgRegisters->
  1341. GetNumberRegisters(&NumReg)) != S_OK)
  1342. {
  1343. goto EH_EffProc;
  1344. }
  1345. Empty();
  1346. NamesOffset = NumReg * 2 * sizeof(ULONG);
  1347. if (!AddData(NamesOffset))
  1348. {
  1349. Status = E_OUTOFMEMORY;
  1350. goto EH_EffProc;
  1351. }
  1352. for (i = 0; i < NumReg; i++)
  1353. {
  1354. if ((Status = g_pDbgRegisters->GetDescription(i, Name, sizeof(Name),
  1355. NULL, &Desc)) != S_OK)
  1356. {
  1357. goto EH_EffProc;
  1358. }
  1359. Len = strlen(Name) + 1;
  1360. BufName = (PSTR)AddData(Len);
  1361. if (BufName == NULL)
  1362. {
  1363. Status = E_OUTOFMEMORY;
  1364. goto EH_EffProc;
  1365. }
  1366. memcpy(BufName, Name, Len);
  1367. Type = (PULONG)GetDataBuffer() + 2 * i;
  1368. Type[0] = Desc.Type;
  1369. Type[1] = Desc.Flags;
  1370. }
  1371. Status = S_OK;
  1372. m_NumRegisters = NumReg;
  1373. m_NamesOffset = NamesOffset;
  1374. EH_EffProc:
  1375. g_pDbgControl->SetEffectiveProcessorType(OldProcType);
  1376. return Status;
  1377. }
  1378. void
  1379. RegisterNamesStateBuffer::GetRegisterMapText(HWND Edit)
  1380. {
  1381. ULONG i;
  1382. PSTR Name;
  1383. CHARRANGE Range;
  1384. AssertStateBufferLocked(this);
  1385. Range.cpMin = 0;
  1386. Range.cpMax = INT_MAX;
  1387. SendMessage(Edit, EM_EXSETSEL, 0, (LPARAM)&Range);
  1388. for (i = 0; i < m_NumRegisters; i++)
  1389. {
  1390. ULONG MapIndex = MapUserToEngine(i);
  1391. Name = (PSTR)GetDataBuffer() + m_NamesOffset;
  1392. while (MapIndex-- > 0)
  1393. {
  1394. Name += strlen(Name) + 1;
  1395. }
  1396. if (i > 0)
  1397. {
  1398. SendMessage(Edit, EM_REPLACESEL, 0, (LPARAM)" ");
  1399. }
  1400. SendMessage(Edit, EM_REPLACESEL, 0, (LPARAM)Name);
  1401. }
  1402. }
  1403. void
  1404. RegisterNamesStateBuffer::ScanRegisterMapText(HWND Edit)
  1405. {
  1406. PSTR Text, TextBuffer;
  1407. PULONG Used, UsedBuffer;
  1408. ULONG i;
  1409. AssertStateBufferLocked(this);
  1410. //
  1411. // Allocate a buffer for the control text
  1412. // and a new register map.
  1413. //
  1414. i = (ULONG)SendMessage(Edit, WM_GETTEXTLENGTH, 0, 0) + 1;
  1415. TextBuffer = new CHAR[i];
  1416. if (TextBuffer == NULL)
  1417. {
  1418. return;
  1419. }
  1420. Text = TextBuffer;
  1421. UsedBuffer = new ULONG[m_NumRegisters];
  1422. if (UsedBuffer == NULL)
  1423. {
  1424. delete [] TextBuffer;
  1425. return;
  1426. }
  1427. Used = UsedBuffer;
  1428. // Map may need to change size.
  1429. delete [] m_RegisterMap;
  1430. m_RegisterMap = new USHORT[m_NumRegisters];
  1431. if (m_RegisterMap == NULL)
  1432. {
  1433. delete [] TextBuffer;
  1434. delete [] UsedBuffer;
  1435. return;
  1436. }
  1437. m_RegisterMapEntries = m_NumRegisters;
  1438. ZeroMemory(Used, m_NumRegisters * sizeof(Used[0]));
  1439. //
  1440. // Retrieve the text and scan it for register names.
  1441. //
  1442. GetWindowText(Edit, Text, i);
  1443. Text[i - 1] = 0;
  1444. PSTR Name;
  1445. BOOL End;
  1446. PUSHORT Map;
  1447. PSTR Reg;
  1448. Map = m_RegisterMap;
  1449. for (;;)
  1450. {
  1451. while (isspace(*Text))
  1452. {
  1453. Text++;
  1454. }
  1455. if (*Text == 0)
  1456. {
  1457. break;
  1458. }
  1459. // Collect name.
  1460. Name = Text;
  1461. while (*Text && !isspace(*Text))
  1462. {
  1463. Text++;
  1464. }
  1465. End = *Text == 0;
  1466. *Text = 0;
  1467. // Check against known registers.
  1468. Reg = (PSTR)GetDataBuffer() + m_NamesOffset;
  1469. for (i = 0; i < m_NumRegisters; i++)
  1470. {
  1471. if (!Used[i] && !_strcmpi(Name, Reg))
  1472. {
  1473. Used[i] = TRUE;
  1474. *Map++ = (USHORT)i;
  1475. break;
  1476. }
  1477. Reg += strlen(Reg) + 1;
  1478. }
  1479. if (End)
  1480. {
  1481. break;
  1482. }
  1483. Text++;
  1484. }
  1485. //
  1486. // Fill out any remaining map entries with registers
  1487. // which aren't in the map so far.
  1488. //
  1489. PUSHORT MapEnd = m_RegisterMap + m_RegisterMapEntries;
  1490. i = 0;
  1491. while (Map < MapEnd)
  1492. {
  1493. while (Used[i])
  1494. {
  1495. i++;
  1496. }
  1497. Assert(i < m_NumRegisters);
  1498. *Map++ = (USHORT)(i++);
  1499. }
  1500. delete [] TextBuffer;
  1501. delete [] UsedBuffer;
  1502. }
  1503. void
  1504. RegisterNamesStateBuffer::SetRegisterMap(ULONG Count, PUSHORT Data)
  1505. {
  1506. delete m_RegisterMap;
  1507. m_RegisterMapEntries = 0;
  1508. m_RegisterMap = new USHORT[Count];
  1509. if (m_RegisterMap != NULL)
  1510. {
  1511. memcpy(m_RegisterMap, Data, Count * sizeof(*m_RegisterMap));
  1512. m_RegisterMapEntries = Count;
  1513. }
  1514. }
  1515. USHORT
  1516. RegisterNamesStateBuffer::MapEngineToUser(ULONG Eng)
  1517. {
  1518. ULONG i;
  1519. if (!m_RegisterMap)
  1520. {
  1521. return (USHORT)Eng;
  1522. }
  1523. for (i = 0; i < m_RegisterMapEntries; i++)
  1524. {
  1525. if (m_RegisterMap[i] == Eng)
  1526. {
  1527. return (USHORT)i;
  1528. }
  1529. }
  1530. return (USHORT)Eng;
  1531. }
  1532. RegisterNamesStateBuffer*
  1533. GetRegisterNames(ULONG ProcType)
  1534. {
  1535. ULONG i, Unused;
  1536. if (ProcType == IMAGE_FILE_MACHINE_UNKNOWN)
  1537. {
  1538. return NULL;
  1539. }
  1540. Dbg_EnterCriticalSection(&g_QuickLock);
  1541. Unused = MAX_REG_NAMES;
  1542. for (i = 0; i < MAX_REG_NAMES; i++)
  1543. {
  1544. if (g_RegisterNameBuffers[i].m_ProcType == ProcType)
  1545. {
  1546. Dbg_LeaveCriticalSection(&g_QuickLock);
  1547. return &g_RegisterNameBuffers[i];
  1548. }
  1549. if (g_RegisterNameBuffers[i].m_ProcType ==
  1550. IMAGE_FILE_MACHINE_UNKNOWN &&
  1551. Unused == MAX_REG_NAMES)
  1552. {
  1553. Unused = i;
  1554. }
  1555. }
  1556. if (Unused == MAX_REG_NAMES)
  1557. {
  1558. Dbg_LeaveCriticalSection(&g_QuickLock);
  1559. return NULL;
  1560. }
  1561. g_RegisterNameBuffers[Unused].m_ProcType = ProcType;
  1562. g_RegisterNameBuffers[Unused].UiRequestRead();
  1563. Dbg_LeaveCriticalSection(&g_QuickLock);
  1564. return &g_RegisterNameBuffers[Unused];
  1565. }