Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

3687 lines
96 KiB

  1. //----------------------------------------------------------------------------
  2. //
  3. // Breakpoint handling functions.
  4. //
  5. // Copyright (C) Microsoft Corporation, 1997-2001.
  6. //
  7. //----------------------------------------------------------------------------
  8. #include "ntsdp.hpp"
  9. // Currently used only to watch for list changes when
  10. // doing callbacks for breakpoint hit notifications.
  11. BOOL g_BreakpointListChanged;
  12. // Always update data breakpoints the very first time in
  13. // order to flush out any stale data breakpoints.
  14. BOOL g_UpdateDataBreakpoints = TRUE;
  15. BOOL g_DataBreakpointsChanged;
  16. BOOL g_BreakpointsSuspended;
  17. Breakpoint* g_StepTraceBp; // Trace breakpoint.
  18. CHAR g_StepTraceCmdState;
  19. Breakpoint* g_DeferBp; // Deferred breakpoint.
  20. BOOL g_DeferDefined; // TRUE if deferred breakpoint is active.
  21. Breakpoint* g_LastBreakpointHit;
  22. ADDR g_LastBreakpointHitPc;
  23. ADDR g_PrevRelatedPc;
  24. HRESULT
  25. BreakpointInit(void)
  26. {
  27. // These breakpoints are never put in any list so their
  28. // IDs can be anything. Pick unusual numbers to make them
  29. // easy to identify when debugging the debugger.
  30. g_StepTraceBp = new
  31. CodeBreakpoint(NULL, 0xffff0000, IMAGE_FILE_MACHINE_UNKNOWN);
  32. g_StepTraceCmdState = 't';
  33. g_DeferBp = new
  34. CodeBreakpoint(NULL, 0xffff0001, IMAGE_FILE_MACHINE_UNKNOWN);
  35. if (g_StepTraceBp == NULL ||
  36. g_DeferBp == NULL)
  37. {
  38. ErrOut("Unable to allocate private breakpoints\n");
  39. delete g_StepTraceBp;
  40. g_StepTraceBp = NULL;
  41. delete g_DeferBp;
  42. g_DeferBp = NULL;
  43. return E_OUTOFMEMORY;
  44. }
  45. return S_OK;
  46. }
  47. //----------------------------------------------------------------------------
  48. //
  49. // Breakpoint.
  50. //
  51. //----------------------------------------------------------------------------
  52. Breakpoint::Breakpoint(DebugClient* Adder, ULONG Id, ULONG Type,
  53. ULONG ProcType)
  54. {
  55. m_Next = NULL;
  56. m_Prev = NULL;
  57. m_Id = Id;
  58. m_BreakType = Type;
  59. // Breakpoints are always created disabled since they
  60. // are not initialized at the time of creation.
  61. m_Flags = 0;
  62. ADDRFLAT(&m_Addr, 0);
  63. // Initial data parameters must be set to something
  64. // valid so that Validate calls will allow the offset
  65. // to be changed.
  66. m_DataSize = 1;
  67. m_DataAccessType = DEBUG_BREAK_EXECUTE;
  68. m_PassCount = 1;
  69. m_CurPassCount = 1;
  70. m_CommandLen = 0;
  71. m_Command = NULL;
  72. m_MatchThread = NULL;
  73. m_Process = g_CurrentProcess;
  74. m_OffsetExprLen = 0;
  75. m_OffsetExpr = NULL;
  76. m_Adder = Adder;
  77. m_MatchThreadData = 0;
  78. m_MatchProcessData = 0;
  79. SetProcType(ProcType);
  80. if (m_BreakType == DEBUG_BREAKPOINT_DATA)
  81. {
  82. g_DataBreakpointsChanged = TRUE;
  83. }
  84. }
  85. Breakpoint::~Breakpoint(void)
  86. {
  87. // There used to be an assert here checking that
  88. // the inserted flag wasn't set before a breakpoint
  89. // structure was deleted. However, the inserted flag
  90. // might still be set at this point if a breakpoint
  91. // restore failed, so the assert is not valid.
  92. if (m_BreakType == DEBUG_BREAKPOINT_DATA)
  93. {
  94. g_DataBreakpointsChanged = TRUE;
  95. }
  96. if (this == g_LastBreakpointHit)
  97. {
  98. g_LastBreakpointHit = NULL;
  99. }
  100. // Take this item out of the list if necessary.
  101. if (m_Flags & BREAKPOINT_IN_LIST)
  102. {
  103. UnlinkFromList();
  104. }
  105. delete [] (PSTR)m_Command;
  106. delete [] (PSTR)m_OffsetExpr;
  107. }
  108. STDMETHODIMP
  109. Breakpoint::QueryInterface(
  110. THIS_
  111. IN REFIID InterfaceId,
  112. OUT PVOID* Interface
  113. )
  114. {
  115. *Interface = NULL;
  116. // Interface specific casts are necessary in order to
  117. // get the right vtable pointer in our multiple
  118. // inheritance scheme.
  119. if (DbgIsEqualIID(InterfaceId, IID_IUnknown) ||
  120. DbgIsEqualIID(InterfaceId, IID_IDebugBreakpoint))
  121. {
  122. *Interface = (IDebugBreakpoint *)this;
  123. AddRef();
  124. return S_OK;
  125. }
  126. else
  127. {
  128. return E_NOINTERFACE;
  129. }
  130. }
  131. STDMETHODIMP_(ULONG)
  132. Breakpoint::AddRef(
  133. THIS
  134. )
  135. {
  136. // This object's lifetime is not controlled by
  137. // the interface.
  138. return 1;
  139. }
  140. STDMETHODIMP_(ULONG)
  141. Breakpoint::Release(
  142. THIS
  143. )
  144. {
  145. // This object's lifetime is not controlled by
  146. // the interface.
  147. return 0;
  148. }
  149. STDMETHODIMP
  150. Breakpoint::GetId(
  151. THIS_
  152. OUT PULONG Id
  153. )
  154. {
  155. ENTER_ENGINE();
  156. *Id = m_Id;
  157. LEAVE_ENGINE();
  158. return S_OK;
  159. }
  160. STDMETHODIMP
  161. Breakpoint::GetType(
  162. THIS_
  163. OUT PULONG BreakType,
  164. OUT PULONG ProcType
  165. )
  166. {
  167. ENTER_ENGINE();
  168. *BreakType = m_BreakType;
  169. *ProcType = m_ProcType;
  170. LEAVE_ENGINE();
  171. return S_OK;
  172. }
  173. STDMETHODIMP
  174. Breakpoint::GetAdder(
  175. THIS_
  176. OUT PDEBUG_CLIENT* Adder
  177. )
  178. {
  179. ENTER_ENGINE();
  180. *Adder = (PDEBUG_CLIENT)m_Adder;
  181. m_Adder->AddRef();
  182. LEAVE_ENGINE();
  183. return S_OK;
  184. }
  185. STDMETHODIMP
  186. Breakpoint::GetFlags(
  187. THIS_
  188. OUT PULONG Flags
  189. )
  190. {
  191. ENTER_ENGINE();
  192. *Flags = m_Flags & BREAKPOINT_EXTERNAL_FLAGS;
  193. LEAVE_ENGINE();
  194. return S_OK;
  195. }
  196. STDMETHODIMP
  197. Breakpoint::AddFlags(
  198. THIS_
  199. IN ULONG Flags
  200. )
  201. {
  202. if (Flags & ~BREAKPOINT_EXTERNAL_MODIFY_FLAGS)
  203. {
  204. return E_INVALIDARG;
  205. }
  206. ENTER_ENGINE();
  207. m_Flags |= Flags;
  208. if (m_BreakType == DEBUG_BREAKPOINT_DATA)
  209. {
  210. g_DataBreakpointsChanged = TRUE;
  211. }
  212. UpdateInternal();
  213. NotifyChangeEngineState(DEBUG_CES_BREAKPOINTS, m_Id, TRUE);
  214. LEAVE_ENGINE();
  215. return S_OK;
  216. }
  217. STDMETHODIMP
  218. Breakpoint::RemoveFlags(
  219. THIS_
  220. IN ULONG Flags
  221. )
  222. {
  223. if (Flags & ~BREAKPOINT_EXTERNAL_MODIFY_FLAGS)
  224. {
  225. return E_INVALIDARG;
  226. }
  227. ENTER_ENGINE();
  228. m_Flags &= ~Flags;
  229. if (m_BreakType == DEBUG_BREAKPOINT_DATA)
  230. {
  231. g_DataBreakpointsChanged = TRUE;
  232. }
  233. UpdateInternal();
  234. NotifyChangeEngineState(DEBUG_CES_BREAKPOINTS, m_Id, TRUE);
  235. LEAVE_ENGINE();
  236. return S_OK;
  237. }
  238. STDMETHODIMP
  239. Breakpoint::SetFlags(
  240. THIS_
  241. IN ULONG Flags
  242. )
  243. {
  244. if (Flags & ~BREAKPOINT_EXTERNAL_MODIFY_FLAGS)
  245. {
  246. return E_INVALIDARG;
  247. }
  248. ENTER_ENGINE();
  249. m_Flags = (m_Flags & ~BREAKPOINT_EXTERNAL_MODIFY_FLAGS) |
  250. (Flags & BREAKPOINT_EXTERNAL_MODIFY_FLAGS);
  251. if (m_BreakType == DEBUG_BREAKPOINT_DATA)
  252. {
  253. g_DataBreakpointsChanged = TRUE;
  254. }
  255. UpdateInternal();
  256. NotifyChangeEngineState(DEBUG_CES_BREAKPOINTS, m_Id, TRUE);
  257. LEAVE_ENGINE();
  258. return S_OK;
  259. }
  260. STDMETHODIMP
  261. Breakpoint::GetOffset(
  262. THIS_
  263. OUT PULONG64 Offset
  264. )
  265. {
  266. if (m_Flags & DEBUG_BREAKPOINT_DEFERRED)
  267. {
  268. return E_NOINTERFACE;
  269. }
  270. ENTER_ENGINE();
  271. *Offset = Flat(m_Addr);
  272. LEAVE_ENGINE();
  273. return S_OK;
  274. }
  275. STDMETHODIMP
  276. Breakpoint::SetOffset(
  277. THIS_
  278. IN ULONG64 Offset
  279. )
  280. {
  281. if (m_Flags & DEBUG_BREAKPOINT_DEFERRED)
  282. {
  283. return E_UNEXPECTED;
  284. }
  285. ENTER_ENGINE();
  286. ADDR Addr;
  287. HRESULT Status;
  288. ADDRFLAT(&Addr, Offset);
  289. Status = SetAddr(&Addr, BREAKPOINT_WARN_MATCH);
  290. if (Status == S_OK)
  291. {
  292. NotifyChangeEngineState(DEBUG_CES_BREAKPOINTS, m_Id, TRUE);
  293. }
  294. LEAVE_ENGINE();
  295. return Status;
  296. }
  297. STDMETHODIMP
  298. Breakpoint::GetDataParameters(
  299. THIS_
  300. OUT PULONG Size,
  301. OUT PULONG AccessType
  302. )
  303. {
  304. if (m_BreakType != DEBUG_BREAKPOINT_DATA)
  305. {
  306. return E_NOINTERFACE;
  307. }
  308. ENTER_ENGINE();
  309. *Size = m_DataSize;
  310. *AccessType = m_DataAccessType;
  311. LEAVE_ENGINE();
  312. return S_OK;
  313. }
  314. STDMETHODIMP
  315. Breakpoint::SetDataParameters(
  316. THIS_
  317. IN ULONG Size,
  318. IN ULONG AccessType
  319. )
  320. {
  321. if (m_BreakType != DEBUG_BREAKPOINT_DATA)
  322. {
  323. return E_NOINTERFACE;
  324. }
  325. ENTER_ENGINE();
  326. ULONG OldSize = m_DataSize;
  327. ULONG OldAccess = m_DataAccessType;
  328. HRESULT Status;
  329. m_DataSize = Size;
  330. m_DataAccessType = AccessType;
  331. Status = Validate();
  332. if (Status != S_OK)
  333. {
  334. m_DataSize = OldSize;
  335. m_DataAccessType = OldAccess;
  336. }
  337. else
  338. {
  339. g_DataBreakpointsChanged = TRUE;
  340. NotifyChangeEngineState(DEBUG_CES_BREAKPOINTS, m_Id, TRUE);
  341. }
  342. LEAVE_ENGINE();
  343. return Status;
  344. }
  345. STDMETHODIMP
  346. Breakpoint::GetPassCount(
  347. THIS_
  348. OUT PULONG Count
  349. )
  350. {
  351. ENTER_ENGINE();
  352. *Count = m_PassCount;
  353. LEAVE_ENGINE();
  354. return S_OK;
  355. }
  356. STDMETHODIMP
  357. Breakpoint::SetPassCount(
  358. THIS_
  359. IN ULONG Count
  360. )
  361. {
  362. ENTER_ENGINE();
  363. m_PassCount = Count;
  364. m_CurPassCount = Count;
  365. NotifyChangeEngineState(DEBUG_CES_BREAKPOINTS, m_Id, TRUE);
  366. LEAVE_ENGINE();
  367. return S_OK;
  368. }
  369. STDMETHODIMP
  370. Breakpoint::GetCurrentPassCount(
  371. THIS_
  372. OUT PULONG Count
  373. )
  374. {
  375. ENTER_ENGINE();
  376. *Count = m_CurPassCount;
  377. LEAVE_ENGINE();
  378. return S_OK;
  379. }
  380. STDMETHODIMP
  381. Breakpoint::GetMatchThreadId(
  382. THIS_
  383. OUT PULONG Id
  384. )
  385. {
  386. HRESULT Status;
  387. ENTER_ENGINE();
  388. if (m_MatchThread)
  389. {
  390. *Id = m_MatchThread->UserId;
  391. Status = S_OK;
  392. }
  393. else
  394. {
  395. Status = E_NOINTERFACE;
  396. }
  397. LEAVE_ENGINE();
  398. return Status;
  399. }
  400. STDMETHODIMP
  401. Breakpoint::SetMatchThreadId(
  402. THIS_
  403. IN ULONG Id
  404. )
  405. {
  406. if (IS_KERNEL_TARGET() &&
  407. m_BreakType == DEBUG_BREAKPOINT_DATA)
  408. {
  409. ErrOut("Kernel data breakpoints cannot be limited to a processor\n");
  410. return E_INVALIDARG;
  411. }
  412. HRESULT Status;
  413. ENTER_ENGINE();
  414. PTHREAD_INFO Thread = FindThreadByUserId(NULL, Id);
  415. if (Thread != NULL)
  416. {
  417. m_MatchThread = Thread;
  418. NotifyChangeEngineState(DEBUG_CES_BREAKPOINTS, m_Id, TRUE);
  419. Status = S_OK;
  420. }
  421. else
  422. {
  423. Status = E_NOINTERFACE;
  424. }
  425. LEAVE_ENGINE();
  426. return Status;
  427. }
  428. STDMETHODIMP
  429. Breakpoint::GetCommand(
  430. THIS_
  431. OUT OPTIONAL PSTR Buffer,
  432. IN ULONG BufferSize,
  433. OUT OPTIONAL PULONG CommandSize
  434. )
  435. {
  436. ENTER_ENGINE();
  437. HRESULT Status = FillStringBuffer(m_Command, m_CommandLen,
  438. Buffer, BufferSize, CommandSize);
  439. LEAVE_ENGINE();
  440. return Status;
  441. }
  442. STDMETHODIMP
  443. Breakpoint::SetCommand(
  444. THIS_
  445. IN PCSTR Command
  446. )
  447. {
  448. HRESULT Status;
  449. ENTER_ENGINE();
  450. Status = ChangeString((PSTR*)&m_Command, &m_CommandLen, Command);
  451. if (Status == S_OK)
  452. {
  453. NotifyChangeEngineState(DEBUG_CES_BREAKPOINTS, m_Id, TRUE);
  454. }
  455. LEAVE_ENGINE();
  456. return Status;
  457. }
  458. STDMETHODIMP
  459. Breakpoint::GetOffsetExpression(
  460. THIS_
  461. OUT OPTIONAL PSTR Buffer,
  462. IN ULONG BufferSize,
  463. OUT OPTIONAL PULONG ExpressionSize
  464. )
  465. {
  466. ENTER_ENGINE();
  467. HRESULT Status = FillStringBuffer(m_OffsetExpr, m_OffsetExprLen,
  468. Buffer, BufferSize, ExpressionSize);
  469. LEAVE_ENGINE();
  470. return Status;
  471. }
  472. STDMETHODIMP
  473. Breakpoint::SetOffsetExpression(
  474. THIS_
  475. IN PCSTR Expression
  476. )
  477. {
  478. HRESULT Status;
  479. ENTER_ENGINE();
  480. Status = ChangeString((PSTR*)&m_OffsetExpr, &m_OffsetExprLen, Expression);
  481. if (Status == S_OK)
  482. {
  483. if (Expression != NULL)
  484. {
  485. // Do initial evaluation in case the expression can be
  486. // resolved right away. This will also set the deferred
  487. // flag if the expression can't be evaluated.
  488. EvalOffsetExpr();
  489. }
  490. else
  491. {
  492. // This breakpoint is no longer deferred since there's
  493. // no way to activate it later any more.
  494. m_Flags &= ~DEBUG_BREAKPOINT_DEFERRED;
  495. UpdateInternal();
  496. }
  497. NotifyChangeEngineState(DEBUG_CES_BREAKPOINTS, m_Id, TRUE);
  498. }
  499. LEAVE_ENGINE();
  500. return Status;
  501. }
  502. STDMETHODIMP
  503. Breakpoint::GetParameters(
  504. THIS_
  505. OUT PDEBUG_BREAKPOINT_PARAMETERS Params
  506. )
  507. {
  508. ENTER_ENGINE();
  509. if (m_Flags & DEBUG_BREAKPOINT_DEFERRED)
  510. {
  511. Params->Offset = DEBUG_INVALID_OFFSET;
  512. }
  513. else
  514. {
  515. Params->Offset = Flat(m_Addr);
  516. }
  517. Params->Id = m_Id;
  518. Params->BreakType = m_BreakType;
  519. Params->ProcType = m_ProcType;
  520. Params->Flags = m_Flags & BREAKPOINT_EXTERNAL_FLAGS;
  521. if (m_BreakType == DEBUG_BREAKPOINT_DATA)
  522. {
  523. Params->DataSize = m_DataSize;
  524. Params->DataAccessType = m_DataAccessType;
  525. }
  526. else
  527. {
  528. Params->DataSize = 0;
  529. Params->DataAccessType = 0;
  530. }
  531. Params->PassCount = m_PassCount;
  532. Params->CurrentPassCount = m_CurPassCount;
  533. Params->MatchThread = m_MatchThread != NULL ?
  534. m_MatchThread->UserId : DEBUG_ANY_ID;
  535. Params->CommandSize = m_CommandLen;
  536. Params->OffsetExpressionSize = m_OffsetExprLen;
  537. LEAVE_ENGINE();
  538. return S_OK;
  539. }
  540. void
  541. Breakpoint::LinkIntoList(void)
  542. {
  543. Breakpoint* NextBp;
  544. Breakpoint* PrevBp;
  545. DBG_ASSERT((m_Flags & BREAKPOINT_IN_LIST) == 0);
  546. // Link into list sorted by ID.
  547. PrevBp = NULL;
  548. for (NextBp = m_Process->Breakpoints;
  549. NextBp != NULL;
  550. NextBp = NextBp->m_Next)
  551. {
  552. if (m_Id < NextBp->m_Id)
  553. {
  554. break;
  555. }
  556. PrevBp = NextBp;
  557. }
  558. m_Prev = PrevBp;
  559. if (PrevBp == NULL)
  560. {
  561. m_Process->Breakpoints = this;
  562. }
  563. else
  564. {
  565. PrevBp->m_Next = this;
  566. }
  567. m_Next = NextBp;
  568. if (NextBp == NULL)
  569. {
  570. m_Process->BreakpointsTail = this;
  571. }
  572. else
  573. {
  574. NextBp->m_Prev = this;
  575. }
  576. m_Flags |= BREAKPOINT_IN_LIST;
  577. m_Process->NumBreakpoints++;
  578. g_BreakpointListChanged = TRUE;
  579. }
  580. void
  581. Breakpoint::UnlinkFromList(void)
  582. {
  583. DBG_ASSERT(m_Flags & BREAKPOINT_IN_LIST);
  584. if (m_Prev == NULL)
  585. {
  586. m_Process->Breakpoints = m_Next;
  587. }
  588. else
  589. {
  590. m_Prev->m_Next = m_Next;
  591. }
  592. if (m_Next == NULL)
  593. {
  594. m_Process->BreakpointsTail = m_Prev;
  595. }
  596. else
  597. {
  598. m_Next->m_Prev = m_Prev;
  599. }
  600. m_Flags &= ~BREAKPOINT_IN_LIST;
  601. m_Process->NumBreakpoints--;
  602. g_BreakpointListChanged = TRUE;
  603. }
  604. void
  605. Breakpoint::UpdateInternal(void)
  606. {
  607. // This only has an effect with internal breakpoints.
  608. if ((m_Flags & BREAKPOINT_KD_INTERNAL) == 0)
  609. {
  610. return;
  611. }
  612. // If the breakpoint is ready turn it on, otherwise
  613. // turn it off.
  614. ULONG Flags;
  615. if ((m_Flags & (DEBUG_BREAKPOINT_ENABLED |
  616. DEBUG_BREAKPOINT_DEFERRED)) == DEBUG_BREAKPOINT_ENABLED)
  617. {
  618. Flags = (m_Flags & BREAKPOINT_KD_COUNT_ONLY) ?
  619. DBGKD_INTERNAL_BP_FLAG_COUNTONLY : 0;
  620. }
  621. else
  622. {
  623. Flags = DBGKD_INTERNAL_BP_FLAG_INVALID;
  624. }
  625. BpOut("Set internal bp at %s to %X\n",
  626. FormatAddr64(Flat(m_Addr)), Flags);
  627. DbgKdSetInternalBp(Flat(m_Addr), Flags);
  628. }
  629. enum
  630. {
  631. EVAL_RESOLVED,
  632. EVAL_RESOLVED_NO_MODULE,
  633. EVAL_UNRESOLVED,
  634. EVAL_ERROR
  635. };
  636. ULONG
  637. EvalAddrExpression(PPROCESS_INFO Process, ULONG Machine, PADDR Addr)
  638. {
  639. BOOL Error = FALSE;
  640. // This function can be reentered if evaluating an
  641. // expression causes symbol changes which provoke
  642. // reevaluation of existing address expressions.
  643. // Save away current settings to support nesting.
  644. BOOL OldAllow = g_AllowUnresolvedSymbols;
  645. ULONG OldNum = g_NumUnresolvedSymbols;
  646. ULONG NumUn;
  647. PPROCESS_INFO OldProcess = g_CurrentProcess;
  648. // Evaluate the expression in the context of the breakpoint's
  649. // machine type so that registers and such are available.
  650. ULONG OldMachine = g_EffMachine;
  651. SetEffMachine(Machine, FALSE);
  652. g_AllowUnresolvedSymbols = TRUE;
  653. g_NumUnresolvedSymbols = 0;
  654. g_CurrentProcess = Process;
  655. __try
  656. {
  657. GetAddrExpression(SEGREG_CODE, Addr);
  658. }
  659. __except(CommandExceptionFilter(GetExceptionInformation()))
  660. {
  661. Error = TRUE;
  662. }
  663. NumUn = g_NumUnresolvedSymbols;
  664. SetEffMachine(OldMachine, FALSE);
  665. g_AllowUnresolvedSymbols = OldAllow;
  666. g_NumUnresolvedSymbols = OldNum;
  667. g_CurrentProcess = OldProcess;
  668. if (Error)
  669. {
  670. return EVAL_ERROR;
  671. }
  672. else if (NumUn > 0)
  673. {
  674. return EVAL_UNRESOLVED;
  675. }
  676. else
  677. {
  678. PDEBUG_IMAGE_INFO Image;
  679. // Check if this address falls within an existing module.
  680. for (Image = Process->ImageHead;
  681. Image != NULL;
  682. Image = Image->Next)
  683. {
  684. if (Flat(*Addr) >= Image->BaseOfImage &&
  685. Flat(*Addr) < Image->BaseOfImage + Image->SizeOfImage)
  686. {
  687. return EVAL_RESOLVED;
  688. }
  689. }
  690. return EVAL_RESOLVED_NO_MODULE;
  691. }
  692. }
  693. BOOL
  694. Breakpoint::EvalOffsetExpr(void)
  695. {
  696. ADDR Addr;
  697. PSTR CurCommand = g_CurCmd;
  698. ULONG OldFlags = m_Flags;
  699. ULONG Valid;
  700. DBG_ASSERT(m_OffsetExpr != NULL);
  701. g_CurCmd = (PSTR)m_OffsetExpr;
  702. g_DisableErrorPrint = TRUE;
  703. g_PrefixSymbols = TRUE;
  704. Valid = EvalAddrExpression(m_Process, m_ProcType, &Addr);
  705. g_PrefixSymbols = FALSE;
  706. g_DisableErrorPrint = FALSE;
  707. g_CurCmd = CurCommand;
  708. // Silently allow matching breakpoints when resolving
  709. // as it is difficult for the expression setter to know
  710. // whether there'll be matches or not at the time
  711. // the expression is set.
  712. if (Valid == EVAL_RESOLVED)
  713. {
  714. m_Flags &= ~DEBUG_BREAKPOINT_DEFERRED;
  715. if (SetAddr(&Addr, BREAKPOINT_ALLOW_MATCH) != S_OK)
  716. {
  717. m_Flags |= DEBUG_BREAKPOINT_DEFERRED;
  718. }
  719. }
  720. else
  721. {
  722. m_Flags |= DEBUG_BREAKPOINT_DEFERRED;
  723. // The module containing the breakpoint is being
  724. // unloaded so just mark this breakpoint as not-inserted.
  725. m_Flags &= ~BREAKPOINT_INSERTED;
  726. }
  727. if ((OldFlags ^ m_Flags) & DEBUG_BREAKPOINT_DEFERRED)
  728. {
  729. // Update internal BP status.
  730. UpdateInternal();
  731. if (m_Flags & DEBUG_BREAKPOINT_DEFERRED)
  732. {
  733. BpOut("Deferring %d '%s'\n", m_Id, m_OffsetExpr);
  734. }
  735. else
  736. {
  737. BpOut("Enabling deferred %d '%s' at %s\n",
  738. m_Id, m_OffsetExpr, FormatAddr64(Flat(m_Addr)));
  739. }
  740. return TRUE;
  741. }
  742. return FALSE;
  743. }
  744. HRESULT
  745. Breakpoint::SetAddr(PADDR Addr, BreakpointMatchAction MatchAction)
  746. {
  747. if (m_Flags & DEBUG_BREAKPOINT_DEFERRED)
  748. {
  749. // Address is unknown.
  750. return S_OK;
  751. }
  752. // Lock the breakpoint processor type to the
  753. // type of the module containing it.
  754. ULONG ProcType = m_ProcType;
  755. if (m_BreakType == DEBUG_BREAKPOINT_CODE)
  756. {
  757. ProcType = ModuleMachineType(m_Process, Flat(*Addr));
  758. if (ProcType == IMAGE_FILE_MACHINE_UNKNOWN)
  759. {
  760. ProcType = m_ProcType;
  761. }
  762. }
  763. if (m_Flags & BREAKPOINT_VIRT_ADDR)
  764. {
  765. if (ProcType == IMAGE_FILE_MACHINE_AXP64)
  766. {
  767. PIMAGE_FUNCTION_ENTRY64 FunctionEntry;
  768. FunctionEntry = (PIMAGE_FUNCTION_ENTRY64)
  769. SymFunctionTableAccess64( m_Process->Handle,
  770. Flat(*Addr) );
  771. if (FunctionEntry != NULL)
  772. {
  773. if ( (Flat(*Addr) >= FunctionEntry->StartingAddress) &&
  774. (Flat(*Addr) < FunctionEntry->EndOfPrologue))
  775. {
  776. ADDRFLAT(Addr, FunctionEntry->EndOfPrologue & -4I64 );
  777. }
  778. }
  779. }
  780. else if (ProcType == IMAGE_FILE_MACHINE_ALPHA)
  781. {
  782. PIMAGE_FUNCTION_ENTRY FunctionEntry;
  783. FunctionEntry = (PIMAGE_FUNCTION_ENTRY)
  784. SymFunctionTableAccess64( m_Process->Handle,
  785. Flat(*Addr) );
  786. if (FunctionEntry != NULL)
  787. {
  788. if ( (Flat(*Addr) >= FunctionEntry->StartingAddress) &&
  789. (Flat(*Addr) < FunctionEntry->EndOfPrologue))
  790. {
  791. ADDRFLAT(Addr, FunctionEntry->EndOfPrologue & -4);
  792. }
  793. }
  794. }
  795. }
  796. ADDR OldAddr = m_Addr;
  797. HRESULT Valid;
  798. m_Addr = *Addr;
  799. Valid = Validate();
  800. if (Valid != S_OK)
  801. {
  802. m_Addr = OldAddr;
  803. return Valid;
  804. }
  805. if (ProcType != m_ProcType)
  806. {
  807. SetProcType(ProcType);
  808. }
  809. if (m_BreakType == DEBUG_BREAKPOINT_DATA)
  810. {
  811. g_DataBreakpointsChanged = TRUE;
  812. }
  813. if (MatchAction == BREAKPOINT_ALLOW_MATCH)
  814. {
  815. return S_OK;
  816. }
  817. for (;;)
  818. {
  819. Breakpoint* MatchBp;
  820. MatchBp = CheckMatchingBreakpoints(this, TRUE, 0xffffffff);
  821. if (MatchBp == NULL)
  822. {
  823. break;
  824. }
  825. if (MatchAction == BREAKPOINT_REMOVE_MATCH)
  826. {
  827. ULONG MoveId;
  828. WarnOut("breakpoint %ld redefined\n", MatchBp->m_Id);
  829. // Move breakpoint towards lower IDs.
  830. if (MatchBp->m_Id < m_Id)
  831. {
  832. MoveId = MatchBp->m_Id;
  833. }
  834. else
  835. {
  836. MoveId = DEBUG_ANY_ID;
  837. }
  838. RemoveBreakpoint(MatchBp);
  839. if (MoveId != DEBUG_ANY_ID)
  840. {
  841. // Take over the removed ID.
  842. UnlinkFromList();
  843. m_Id = MoveId;
  844. LinkIntoList();
  845. }
  846. }
  847. else
  848. {
  849. WarnOut("Breakpoints %d and %d match\n",
  850. m_Id, MatchBp->m_Id);
  851. break;
  852. }
  853. }
  854. return S_OK;
  855. }
  856. #define INSERTION_MATCH_FLAGS \
  857. (BREAKPOINT_KD_INTERNAL | BREAKPOINT_VIRT_ADDR)
  858. BOOL
  859. Breakpoint::IsInsertionMatch(Breakpoint* Match)
  860. {
  861. if ((m_Flags & DEBUG_BREAKPOINT_DEFERRED) ||
  862. (Match->m_Flags & DEBUG_BREAKPOINT_DEFERRED) ||
  863. m_BreakType != Match->m_BreakType ||
  864. ((m_Flags ^ Match->m_Flags) & INSERTION_MATCH_FLAGS) ||
  865. !AddrEqu(m_Addr, Match->m_Addr) ||
  866. m_Process != Match->m_Process ||
  867. (m_BreakType == DEBUG_BREAKPOINT_DATA &&
  868. m_MatchThread != Match->m_MatchThread))
  869. {
  870. return FALSE;
  871. }
  872. else
  873. {
  874. return TRUE;
  875. }
  876. }
  877. #define PUBLIC_MATCH_FLAGS \
  878. (BREAKPOINT_HIDDEN | DEBUG_BREAKPOINT_ADDER_ONLY)
  879. BOOL
  880. Breakpoint::IsPublicMatch(Breakpoint* Match)
  881. {
  882. if (!IsInsertionMatch(Match) ||
  883. m_ProcType != Match->m_ProcType ||
  884. ((m_Flags ^ Match->m_Flags) & PUBLIC_MATCH_FLAGS) ||
  885. ((m_Flags & DEBUG_BREAKPOINT_ADDER_ONLY) &&
  886. m_Adder != Match->m_Adder) ||
  887. m_MatchThread != Match->m_MatchThread ||
  888. m_MatchThreadData != Match->m_MatchThreadData ||
  889. m_MatchProcessData != Match->m_MatchProcessData)
  890. {
  891. return FALSE;
  892. }
  893. else
  894. {
  895. return TRUE;
  896. }
  897. }
  898. BOOL
  899. Breakpoint::MatchesCurrentState(void)
  900. {
  901. HRESULT Status;
  902. ULONG64 ThreadData = 0, ProcData = 0;
  903. // If querying the current state fails go ahead
  904. // and return a match so that the breakpoint will
  905. // break as often as possible.
  906. if (m_MatchThreadData)
  907. {
  908. if ((Status = g_Target->
  909. GetThreadInfoDataOffset(g_EventThread, 0, &ThreadData)) != S_OK)
  910. {
  911. ErrOut("Unable to determine current thread data, %s\n",
  912. FormatStatusCode(Status));
  913. return TRUE;
  914. }
  915. }
  916. if (m_MatchProcessData)
  917. {
  918. if ((Status = g_Target->
  919. GetProcessInfoDataOffset(g_EventThread, 0, 0, &ProcData)) != S_OK)
  920. {
  921. ErrOut("Unable to determine current process data, %s\n",
  922. FormatStatusCode(Status));
  923. return TRUE;
  924. }
  925. }
  926. return
  927. (m_MatchThread == NULL ||
  928. m_MatchThread == g_EventThread) &&
  929. m_MatchThreadData == ThreadData &&
  930. m_MatchProcessData == ProcData;
  931. }
  932. //----------------------------------------------------------------------------
  933. //
  934. // CodeBreakpoint.
  935. //
  936. //----------------------------------------------------------------------------
  937. HRESULT
  938. CodeBreakpoint::Validate(void)
  939. {
  940. // No easy way to check for validity of offset.
  941. return S_OK;
  942. }
  943. HRESULT
  944. CodeBreakpoint::Insert(void)
  945. {
  946. if (m_Flags & BREAKPOINT_INSERTED)
  947. {
  948. // Nothing to insert. This can happen in cases where
  949. // the breakpoint remove failed.
  950. return S_OK;
  951. }
  952. HRESULT Status;
  953. DBG_ASSERT((m_Flags & (DEBUG_BREAKPOINT_DEFERRED |
  954. BREAKPOINT_KD_INTERNAL)) == 0);
  955. // Force recomputation of flat address.
  956. NotFlat(m_Addr);
  957. ComputeFlatAddress(&m_Addr, NULL);
  958. Status = g_Target->InsertCodeBreakpoint(m_Process,
  959. g_AllMachines[m_ProcIndex],
  960. &m_Addr,
  961. m_InsertStorage);
  962. if (Status == S_OK)
  963. {
  964. BpOut(" inserted bp %d at %s\n",
  965. m_Id, FormatAddr64(Flat(m_Addr)));
  966. m_Flags |= BREAKPOINT_INSERTED;
  967. return S_OK;
  968. }
  969. else
  970. {
  971. ErrOut("Unable to write breakpoint %d at %s, 0x%X\n",
  972. m_Id, FormatAddr64(Flat(m_Addr)), Status);
  973. return Status;
  974. }
  975. }
  976. HRESULT
  977. CodeBreakpoint::Remove(void)
  978. {
  979. if ((m_Flags & BREAKPOINT_INSERTED) == 0)
  980. {
  981. // Nothing to remove. This can happen in cases where
  982. // the breakpoint insertion failed.
  983. return S_OK;
  984. }
  985. HRESULT Status;
  986. DBG_ASSERT((m_Flags & (DEBUG_BREAKPOINT_DEFERRED |
  987. BREAKPOINT_KD_INTERNAL)) == 0);
  988. // Force recomputation of flat address.
  989. NotFlat(m_Addr);
  990. ComputeFlatAddress(&m_Addr, NULL);
  991. Status = g_Target->RemoveCodeBreakpoint(m_Process,
  992. g_AllMachines[m_ProcIndex],
  993. &m_Addr,
  994. m_InsertStorage);
  995. if (Status == S_OK)
  996. {
  997. BpOut(" removed bp %d from %s\n",
  998. m_Id, FormatAddr64(Flat(m_Addr)));
  999. m_Flags &= ~BREAKPOINT_INSERTED;
  1000. return S_OK;
  1001. }
  1002. else
  1003. {
  1004. ErrOut("Unable to restore breakpoint %d at %s, 0x%X\n",
  1005. m_Id, FormatAddr64(Flat(m_Addr)), Status);
  1006. return Status;
  1007. }
  1008. }
  1009. ULONG
  1010. CodeBreakpoint::IsHit(PADDR Addr)
  1011. {
  1012. // Code breakpoints are code modifications and
  1013. // therefore aren't restricted to a particular
  1014. // thread.
  1015. // If this breakpoint can only match hits on
  1016. // a particular thread this is a partial hit
  1017. // because the exception occurred but it's
  1018. // being ignored.
  1019. if (AddrEqu(m_Addr, *Addr))
  1020. {
  1021. if (MatchesCurrentState())
  1022. {
  1023. return BREAKPOINT_HIT;
  1024. }
  1025. else
  1026. {
  1027. return BREAKPOINT_HIT_IGNORED;
  1028. }
  1029. }
  1030. else
  1031. {
  1032. return BREAKPOINT_NOT_HIT;
  1033. }
  1034. }
  1035. //----------------------------------------------------------------------------
  1036. //
  1037. // DataBreakpoint.
  1038. //
  1039. //----------------------------------------------------------------------------
  1040. HRESULT
  1041. DataBreakpoint::Insert(void)
  1042. {
  1043. PTHREAD_INFO Thread;
  1044. DBG_ASSERT((m_Flags & (BREAKPOINT_INSERTED |
  1045. DEBUG_BREAKPOINT_DEFERRED)) == 0);
  1046. // Force recomputation of flat address for non-I/O breakpoints.
  1047. if (m_Flags & BREAKPOINT_VIRT_ADDR)
  1048. {
  1049. NotFlat(m_Addr);
  1050. ComputeFlatAddress(&m_Addr, NULL);
  1051. }
  1052. // If this breakpoint is restricted to a thread
  1053. // only modify that thread's state. Otherwise
  1054. // update all threads in the process.
  1055. Thread = m_Process->ThreadHead;
  1056. while (Thread)
  1057. {
  1058. if (Thread->NumDataBreaks >= g_Machine->m_MaxDataBreakpoints)
  1059. {
  1060. ErrOut("Too many data breakpoints for %s %d\n",
  1061. IS_KERNEL_TARGET() ? "processor" : "thread",
  1062. Thread->UserId);
  1063. return HRESULT_FROM_WIN32(ERROR_BUFFER_OVERFLOW);
  1064. }
  1065. else if (m_MatchThread == NULL || m_MatchThread == Thread)
  1066. {
  1067. BpOut("Add %s data bp %d to thread %d\n",
  1068. g_AllMachines[m_ProcIndex]->m_AbbrevName,
  1069. m_Id, Thread->UserId);
  1070. AddToThread(Thread);
  1071. }
  1072. Thread = Thread->Next;
  1073. }
  1074. g_UpdateDataBreakpoints = TRUE;
  1075. m_Flags |= BREAKPOINT_INSERTED;
  1076. return S_OK;
  1077. }
  1078. HRESULT
  1079. DataBreakpoint::Remove(void)
  1080. {
  1081. if ((m_Flags & BREAKPOINT_INSERTED) == 0)
  1082. {
  1083. // Nothing to remove. This can happen in cases where
  1084. // the breakpoint insertion failed.
  1085. return S_OK;
  1086. }
  1087. DBG_ASSERT((m_Flags & DEBUG_BREAKPOINT_DEFERRED) == 0);
  1088. // When breakpoints are inserted the data breakpoint state
  1089. // is always started completely empty to no special
  1090. // work needs to be done when removing.
  1091. g_UpdateDataBreakpoints = TRUE;
  1092. m_Flags &= ~BREAKPOINT_INSERTED;
  1093. return S_OK;
  1094. }
  1095. void
  1096. DataBreakpoint::ClearThreadDataBreaks(PTHREAD_INFO Thread)
  1097. {
  1098. Thread->NumDataBreaks = 0;
  1099. memset(Thread->DataBreakBps, 0, sizeof(Thread->DataBreakBps));
  1100. }
  1101. void
  1102. DataBreakpoint::AddToThread(PTHREAD_INFO Thread)
  1103. {
  1104. DBG_ASSERT(Thread->NumDataBreaks < g_Machine->m_MaxDataBreakpoints);
  1105. Thread->DataBreakBps[Thread->NumDataBreaks] = this;
  1106. Thread->NumDataBreaks++;
  1107. }
  1108. //----------------------------------------------------------------------------
  1109. //
  1110. // X86DataBreakpoint.
  1111. //
  1112. //----------------------------------------------------------------------------
  1113. HRESULT
  1114. X86DataBreakpoint::Validate(void)
  1115. {
  1116. ULONG Dr7Bits;
  1117. ULONG Align;
  1118. if (!IsPow2(m_DataSize) || m_DataSize == 0 || m_DataSize > 4)
  1119. {
  1120. ErrOut("Unsupported data breakpoint size\n");
  1121. return E_INVALIDARG;
  1122. }
  1123. Align = (ULONG)(Flat(m_Addr) & (m_DataSize - 1));
  1124. if (Align != 0)
  1125. {
  1126. ErrOut("Data breakpoint must be aligned\n");
  1127. return E_INVALIDARG;
  1128. }
  1129. Dr7Bits = (m_DataSize - 1) << X86_DR7_LEN0_SHIFT;
  1130. switch(m_DataAccessType)
  1131. {
  1132. case DEBUG_BREAK_EXECUTE:
  1133. Dr7Bits |= X86_DR7_RW0_EXECUTE;
  1134. // Code execution breakpoints must have a
  1135. // size of one.
  1136. // They must also be at the beginning
  1137. // of an instruction. This could be checked via
  1138. // examining the instructions but it doesn't seem
  1139. // that worth the trouble.
  1140. if (m_DataSize > 1)
  1141. {
  1142. ErrOut("Execution data breakpoint too large\n");
  1143. return E_INVALIDARG;
  1144. }
  1145. break;
  1146. case DEBUG_BREAK_WRITE:
  1147. Dr7Bits |= X86_DR7_RW0_WRITE;
  1148. break;
  1149. case DEBUG_BREAK_IO:
  1150. if (IS_USER_TARGET() ||
  1151. !(GetRegVal32(m_Cr4Reg) & X86_CR4_DEBUG_EXTENSIONS))
  1152. {
  1153. ErrOut("I/O breakpoints not enabled\n");
  1154. return E_INVALIDARG;
  1155. }
  1156. if (Flat(m_Addr) > 0xffff)
  1157. {
  1158. ErrOut("I/O breakpoint port too large\n");
  1159. return E_INVALIDARG;
  1160. }
  1161. Dr7Bits |= X86_DR7_RW0_IO;
  1162. break;
  1163. case DEBUG_BREAK_READ:
  1164. case DEBUG_BREAK_READ | DEBUG_BREAK_WRITE:
  1165. // There is no pure read-only option so
  1166. // lump it in with read-write.
  1167. Dr7Bits |= X86_DR7_RW0_READ_WRITE;
  1168. break;
  1169. default:
  1170. ErrOut("Unsupported data breakpoint access type\n");
  1171. return E_INVALIDARG;
  1172. }
  1173. m_Dr7Bits = Dr7Bits | X86_DR7_L0_ENABLE;
  1174. if (m_DataAccessType == DEBUG_BREAK_IO)
  1175. {
  1176. m_Flags &= ~BREAKPOINT_VIRT_ADDR;
  1177. }
  1178. else
  1179. {
  1180. m_Flags |= BREAKPOINT_VIRT_ADDR;
  1181. }
  1182. return S_OK;
  1183. }
  1184. ULONG
  1185. X86DataBreakpoint::IsHit(PADDR Addr)
  1186. {
  1187. ULONG i;
  1188. PTHREAD_INFO Thread = g_EventThread;
  1189. // Data breakpoints are only active on particular
  1190. // threads so if the event thread doesn't match
  1191. // the breakpoint can't be hit.
  1192. if (!MatchesCurrentState())
  1193. {
  1194. return BREAKPOINT_NOT_HIT;
  1195. }
  1196. // Locate this breakpoint in the thread's data breakpoints
  1197. // if possible.
  1198. for (i = 0; i < Thread->NumDataBreaks; i++)
  1199. {
  1200. // Check for match in addition to equality to handle
  1201. // multiple identical data breakpoints.
  1202. if (Thread->DataBreakBps[i] == this ||
  1203. IsInsertionMatch(Thread->DataBreakBps[i]))
  1204. {
  1205. // Is this breakpoint's index set in the debug status register?
  1206. // Address is not meaningful so this is the only way to check.
  1207. if ((GetRegVal32(m_Dr6Reg) >> i) & 1)
  1208. {
  1209. return BREAKPOINT_HIT;
  1210. }
  1211. else
  1212. {
  1213. // Breakpoint can't be listed in more than one slot
  1214. // so there's no need to finish the loop.
  1215. return BREAKPOINT_NOT_HIT;
  1216. }
  1217. }
  1218. }
  1219. return BREAKPOINT_NOT_HIT;
  1220. }
  1221. //----------------------------------------------------------------------------
  1222. //
  1223. // Ia64DataBreakpoint.
  1224. //
  1225. //----------------------------------------------------------------------------
  1226. HRESULT
  1227. Ia64DataBreakpoint::Validate(void)
  1228. {
  1229. if (!IsPow2(m_DataSize))
  1230. {
  1231. ErrOut("Hardware breakpoint size must be power of 2\n");
  1232. return E_INVALIDARG;
  1233. }
  1234. if (Flat(m_Addr) & (m_DataSize - 1))
  1235. {
  1236. ErrOut("Hardware breakpoint must be size aligned\n");
  1237. return E_INVALIDARG;
  1238. }
  1239. switch (m_DataAccessType)
  1240. {
  1241. case DEBUG_BREAK_WRITE:
  1242. case DEBUG_BREAK_READ:
  1243. case DEBUG_BREAK_READ | DEBUG_BREAK_WRITE:
  1244. break;
  1245. case DEBUG_BREAK_EXECUTE:
  1246. if (m_DataSize & 0xf)
  1247. {
  1248. if (m_DataSize > 0xf)
  1249. {
  1250. ErrOut("Execution breakpoint size must be bundle aligned.\n");
  1251. return E_INVALIDARG;
  1252. }
  1253. else
  1254. {
  1255. WarnOut("Execution breakpoint size extended to bundle size "
  1256. "(16 bytes).\n");
  1257. m_DataSize = 0x10;
  1258. }
  1259. }
  1260. break;
  1261. default:
  1262. ErrOut("Unsupported data breakpoint access type\n");
  1263. return E_INVALIDARG;
  1264. }
  1265. m_Control = GetControl(m_DataAccessType, m_DataSize);
  1266. m_Flags |= BREAKPOINT_VIRT_ADDR;
  1267. return S_OK;
  1268. }
  1269. ULONG
  1270. Ia64DataBreakpoint::IsHit(PADDR Addr)
  1271. {
  1272. ULONG i;
  1273. PTHREAD_INFO Thread = g_EventThread;
  1274. // Data breakpoints are only active on particular
  1275. // threads so if the event thread doesn't match
  1276. // the breakpoint can't be hit.
  1277. if (m_MatchThread != NULL && m_MatchThread != Thread)
  1278. {
  1279. return BREAKPOINT_NOT_HIT;
  1280. }
  1281. // Locate this breakpoint in the thread's data breakpoints
  1282. // if possible.
  1283. for (i = 0; i < Thread->NumDataBreaks; i++)
  1284. {
  1285. // Check for match in addition to equality to handle
  1286. // multiple identical data breakpoints.
  1287. if (Thread->DataBreakBps[i] == this ||
  1288. IsInsertionMatch(Thread->DataBreakBps[i]))
  1289. {
  1290. if ((Flat(*Thread->DataBreakBps[i]->GetAddr()) ^
  1291. Flat(*Addr)) &
  1292. (m_Control & IA64_DBG_MASK_MASK))
  1293. {
  1294. // Breakpoint can't be listed in more than one slot
  1295. // so there's no need to finish the loop.
  1296. return BREAKPOINT_NOT_HIT;
  1297. }
  1298. else
  1299. {
  1300. return BREAKPOINT_HIT;
  1301. }
  1302. }
  1303. }
  1304. return BREAKPOINT_NOT_HIT;
  1305. }
  1306. ULONG64
  1307. Ia64DataBreakpoint::GetControl(ULONG AccessType, ULONG Size)
  1308. {
  1309. ULONG64 Control = (ULONG64(IA64_DBG_REG_PLM_ALL) |
  1310. ULONG64(IA64_DBG_MASK_MASK)) &
  1311. ~ULONG64(Size - 1);
  1312. switch (AccessType)
  1313. {
  1314. case DEBUG_BREAK_WRITE:
  1315. Control |= IA64_DBR_WR;
  1316. break;
  1317. case DEBUG_BREAK_READ:
  1318. Control |= IA64_DBR_RD;
  1319. break;
  1320. case DEBUG_BREAK_READ | DEBUG_BREAK_WRITE:
  1321. Control |= IA64_DBR_RDWR;
  1322. break;
  1323. case DEBUG_BREAK_EXECUTE:
  1324. Control |= IA64_DBR_EXEC;
  1325. break;
  1326. }
  1327. return Control;
  1328. }
  1329. //----------------------------------------------------------------------------
  1330. //
  1331. // X86OnIa64DataBreakpoint.
  1332. //
  1333. //----------------------------------------------------------------------------
  1334. X86OnIa64DataBreakpoint::X86OnIa64DataBreakpoint(DebugClient* Adder, ULONG Id)
  1335. : X86DataBreakpoint(Adder, Id, X86_CR4, X86_DR6, IMAGE_FILE_MACHINE_I386)
  1336. {
  1337. m_Control = 0;
  1338. }
  1339. HRESULT
  1340. X86OnIa64DataBreakpoint::Validate(void)
  1341. {
  1342. HRESULT Status = X86DataBreakpoint::Validate();
  1343. if (Status != S_OK)
  1344. {
  1345. return Status;
  1346. }
  1347. switch (m_DataAccessType)
  1348. {
  1349. case DEBUG_BREAK_WRITE:
  1350. case DEBUG_BREAK_READ:
  1351. case DEBUG_BREAK_READ | DEBUG_BREAK_WRITE:
  1352. case DEBUG_BREAK_EXECUTE:
  1353. break;
  1354. default:
  1355. ErrOut("Unsupported data breakpoint access type\n");
  1356. return E_INVALIDARG;
  1357. }
  1358. m_Control = Ia64DataBreakpoint::GetControl(m_DataAccessType, m_DataSize);
  1359. return S_OK;
  1360. }
  1361. // XXX olegk -This is pure hack
  1362. // (see X86OnIa64MachineInfo::IsBreakpointOrStepException implementation
  1363. // for more info)
  1364. ULONG
  1365. X86OnIa64DataBreakpoint::IsHit(PADDR Addr)
  1366. {
  1367. ULONG i;
  1368. PTHREAD_INFO Thread = g_EventThread;
  1369. // Data breakpoints are only active on particular
  1370. // threads so if the event thread doesn't match
  1371. // the breakpoint can't be hit.
  1372. if (m_MatchThread != NULL && m_MatchThread != Thread)
  1373. {
  1374. return BREAKPOINT_NOT_HIT;
  1375. }
  1376. // Locate this breakpoint in the thread's data breakpoints
  1377. // if possible.
  1378. for (i = 0; i < Thread->NumDataBreaks; i++)
  1379. {
  1380. // Check for match in addition to equality to handle
  1381. // multiple identical data breakpoints.
  1382. if (Thread->DataBreakBps[i] == this ||
  1383. IsInsertionMatch(Thread->DataBreakBps[i]))
  1384. {
  1385. if (((ULONG)Flat(*Thread->DataBreakBps[i]->GetAddr()) ^
  1386. (ULONG)Flat(*Addr)) &
  1387. (ULONG)(m_Control & IA64_DBG_MASK_MASK))
  1388. {
  1389. // Breakpoint can't be listed in more than one slot
  1390. // so there's no need to finish the loop.
  1391. return BREAKPOINT_NOT_HIT;
  1392. }
  1393. else
  1394. {
  1395. return BREAKPOINT_HIT;
  1396. }
  1397. }
  1398. }
  1399. return BREAKPOINT_NOT_HIT;
  1400. }
  1401. //----------------------------------------------------------------------------
  1402. //
  1403. // Functions.
  1404. //
  1405. //----------------------------------------------------------------------------
  1406. BOOL
  1407. BreakpointNeedsToBeDeferred(Breakpoint* Bp, PADDR PcAddr)
  1408. {
  1409. if (IS_CONTEXT_POSSIBLE() &&
  1410. (Bp->m_Process == g_CurrentProcess))
  1411. {
  1412. if (AddrEqu(*Bp->GetAddr(), *PcAddr) &&
  1413. (Bp->m_Flags & BREAKPOINT_VIRT_ADDR))
  1414. {
  1415. return TRUE;
  1416. }
  1417. if ((Bp == g_LastBreakpointHit) && Bp->PcAtHit() &&
  1418. AddrEqu(g_LastBreakpointHitPc, *PcAddr))
  1419. {
  1420. if (g_ContextChanged)
  1421. {
  1422. WarnOut("Breakpoint %ld will not be deferred because "
  1423. "changes in the context. Breakpoint may hit again.\n",
  1424. Bp->m_Id);
  1425. return FALSE;
  1426. }
  1427. return TRUE;
  1428. }
  1429. }
  1430. return FALSE;
  1431. }
  1432. //----------------------------------------------------------------------------
  1433. //
  1434. // Modify debuggee to activate current breakpoints.
  1435. //
  1436. //----------------------------------------------------------------------------
  1437. HRESULT
  1438. InsertBreakpoints(void)
  1439. {
  1440. HRESULT Status = S_OK;
  1441. ADDR PcAddr;
  1442. BOOL DeferredData = FALSE;
  1443. PTHREAD_INFO OldThread;
  1444. MachineInfo* Machine;
  1445. if (g_CurrentProcess != NULL &&
  1446. g_CurrentProcess->CurrentThread != NULL)
  1447. {
  1448. // Aggressively clear this flag always in order to be
  1449. // as conservative as possible when recognizing
  1450. // trace events. We would rather misrecognize
  1451. // single-step events and break in instead of
  1452. // misrecognizing an app-generated single-step and
  1453. // ignoring it.
  1454. g_CurrentProcess->CurrentThread->Flags &= ~ENG_THREAD_DEFER_BP_TRACE;
  1455. }
  1456. if ((g_EngStatus & ENG_STATUS_BREAKPOINTS_INSERTED) ||
  1457. (g_EngStatus & ENG_STATUS_SUSPENDED) == 0 ||
  1458. IS_DUMP_TARGET())
  1459. {
  1460. return Status;
  1461. }
  1462. g_DeferDefined = FALSE;
  1463. // Switch to the event thread to get the event thread's
  1464. // PC so we can see if we need to defer breakpoints in
  1465. // order to allow the event thread to keep running.
  1466. OldThread = g_RegContextThread;
  1467. ChangeRegContext(g_EventThread);
  1468. Machine = g_Machine;
  1469. if (g_BreakpointsSuspended)
  1470. {
  1471. goto StepTraceOnly;
  1472. }
  1473. //
  1474. // Turn off all data breakpoints. (We will turn the enabled ones back
  1475. // on when we restart execution).
  1476. //
  1477. PTHREAD_INFO Thread;
  1478. PPROCESS_INFO Process;
  1479. // Clear each thread in each process.
  1480. Process = g_ProcessHead;
  1481. while (Process)
  1482. {
  1483. Thread = Process->ThreadHead;
  1484. while (Thread)
  1485. {
  1486. DataBreakpoint::ClearThreadDataBreaks(Thread);
  1487. Thread = Thread->Next;
  1488. }
  1489. Process = Process->Next;
  1490. }
  1491. if (IS_CONTEXT_POSSIBLE())
  1492. {
  1493. Machine->GetPC(&PcAddr);
  1494. }
  1495. BpOut("InsertBreakpoints PC ");
  1496. if (IS_CONTEXT_POSSIBLE())
  1497. {
  1498. MaskOutAddr(DEBUG_IOUTPUT_BREAKPOINT, &PcAddr);
  1499. BpOut("\n");
  1500. }
  1501. else
  1502. {
  1503. BpOut("?\n");
  1504. }
  1505. //
  1506. // Set any appropriate permanent breakpoints.
  1507. //
  1508. Breakpoint* Bp;
  1509. for (Process = g_ProcessHead; Process; Process = Process->Next)
  1510. {
  1511. BpOut(" Process %d with %d bps\n", Process->UserId,
  1512. Process->NumBreakpoints);
  1513. for (Bp = Process->Breakpoints; Bp != NULL; Bp = Bp->m_Next)
  1514. {
  1515. if (Bp->IsNormalEnabled() &&
  1516. (g_CmdState == 'g' ||
  1517. (Bp->m_Flags & DEBUG_BREAKPOINT_GO_ONLY) == 0))
  1518. {
  1519. Bp->ForceFlatAddr();
  1520. // Check if this breakpoint matches a previously
  1521. // inserted breakpoint. If so there's no need
  1522. // to insert this one.
  1523. Breakpoint* MatchBp;
  1524. for (MatchBp = Bp->m_Prev;
  1525. MatchBp != NULL;
  1526. MatchBp = MatchBp->m_Prev)
  1527. {
  1528. if ((MatchBp->m_Flags & BREAKPOINT_INSERTED) &&
  1529. Bp->IsInsertionMatch(MatchBp))
  1530. {
  1531. break;
  1532. }
  1533. }
  1534. if (MatchBp != NULL)
  1535. {
  1536. // Skip this breakpoint. It won't be marked as
  1537. // inserted so Remove is automatically handled.
  1538. continue;
  1539. }
  1540. if (BreakpointNeedsToBeDeferred(Bp, &PcAddr))
  1541. {
  1542. g_DeferDefined = TRUE;
  1543. if (Bp->m_BreakType == DEBUG_BREAKPOINT_DATA)
  1544. {
  1545. DeferredData = TRUE;
  1546. }
  1547. }
  1548. else
  1549. {
  1550. HRESULT InsertStatus;
  1551. InsertStatus = Bp->Insert();
  1552. if (InsertStatus != S_OK)
  1553. {
  1554. if (Bp->m_Flags & DEBUG_BREAKPOINT_GO_ONLY)
  1555. {
  1556. ErrOut("go ");
  1557. }
  1558. ErrOut("bp%d at ", Bp->m_Id);
  1559. MaskOutAddr(DEBUG_OUTPUT_ERROR, Bp->GetAddr());
  1560. ErrOut("failed\n");
  1561. Status = InsertStatus;
  1562. }
  1563. }
  1564. }
  1565. }
  1566. }
  1567. // Enable data breakpoints if necessary.
  1568. if (g_UpdateDataBreakpoints)
  1569. {
  1570. // It's the target machine's responsibility to manage
  1571. // all data breakpoints for all machines, so always
  1572. // force the usage of the target machine here.
  1573. g_TargetMachine->InsertAllDataBreakpoints();
  1574. // If we deferred a data breakpoint we haven't
  1575. // fully updated the data breakpoint state
  1576. // so leave the update flags set.
  1577. if (!DeferredData)
  1578. {
  1579. g_UpdateDataBreakpoints = FALSE;
  1580. g_DataBreakpointsChanged = FALSE;
  1581. }
  1582. }
  1583. StepTraceOnly:
  1584. // set the step/trace breakpoint if appropriate
  1585. if (g_StepTraceBp->m_Flags & DEBUG_BREAKPOINT_ENABLED)
  1586. {
  1587. BpOut("Step/trace addr = ");
  1588. MaskOutAddr(DEBUG_IOUTPUT_BREAKPOINT, g_StepTraceBp->GetAddr());
  1589. BpOut("\n");
  1590. if (Flat(*g_StepTraceBp->GetAddr()) == OFFSET_TRACE)
  1591. {
  1592. if (IS_USER_TARGET())
  1593. {
  1594. ChangeRegContext(g_StepTraceBp->m_MatchThread);
  1595. }
  1596. BpOut("Setting trace flag for step/trace thread %d:%x\n",
  1597. g_RegContextThread ? g_RegContextThread->UserId : 0,
  1598. g_RegContextThread ? g_RegContextThread->SystemId : 0);
  1599. Machine->QuietSetTraceMode(g_StepTraceCmdState == 'b' ?
  1600. TRACE_TAKEN_BRANCH :
  1601. TRACE_INSTRUCTION);
  1602. if (IS_USER_TARGET())
  1603. {
  1604. ChangeRegContext(g_EventThread);
  1605. }
  1606. }
  1607. else if (IS_CONTEXT_POSSIBLE() &&
  1608. AddrEqu(*g_StepTraceBp->GetAddr(), PcAddr))
  1609. {
  1610. BpOut("Setting defer flag for step/trace\n");
  1611. g_DeferDefined = TRUE;
  1612. }
  1613. else if (CheckMatchingBreakpoints(g_StepTraceBp, FALSE,
  1614. BREAKPOINT_INSERTED))
  1615. {
  1616. // There's already a breakpoint inserted at the
  1617. // step/trace address so we don't need to set another.
  1618. BpOut("Trace bp matches existing bp\n");
  1619. }
  1620. else
  1621. {
  1622. if (g_StepTraceBp->Insert() != S_OK)
  1623. {
  1624. ErrOut("Trace bp at addr ");
  1625. MaskOutAddr(DEBUG_OUTPUT_ERROR, g_StepTraceBp->GetAddr());
  1626. ErrOut("failed\n");
  1627. Status = E_FAIL;
  1628. }
  1629. else
  1630. {
  1631. BpOut("Trace bp at addr ");
  1632. MaskOutAddr(DEBUG_IOUTPUT_BREAKPOINT,
  1633. g_StepTraceBp->GetAddr());
  1634. BpOut("succeeded\n");
  1635. }
  1636. }
  1637. }
  1638. // Process deferred breakpoint.
  1639. // If a deferred breakpoint is active it means that
  1640. // the debugger needs to do some work on the current instruction
  1641. // so it wants to step forward one instruction and then
  1642. // get control back. The deferred breakpoint forces a break
  1643. // back to the debugger as soon as possible so that it
  1644. // can carry out any deferred work.
  1645. if (g_DeferDefined)
  1646. {
  1647. ULONG NextMachine;
  1648. g_DeferBp->m_Process = g_CurrentProcess;
  1649. Machine->GetNextOffset(FALSE, g_DeferBp->GetAddr(), &NextMachine);
  1650. g_DeferBp->SetProcType(NextMachine);
  1651. BpOut("Defer addr = ");
  1652. MaskOutAddr(DEBUG_IOUTPUT_BREAKPOINT, g_DeferBp->GetAddr());
  1653. BpOut("\n");
  1654. if ((g_EngOptions & DEBUG_ENGOPT_SYNCHRONIZE_BREAKPOINTS) &&
  1655. IS_USER_TARGET() &&
  1656. g_SelectExecutionThread == SELTHREAD_ANY &&
  1657. g_SelectedThread == NULL)
  1658. {
  1659. // The user wants breakpoint management to occur
  1660. // precisely in order to properly handle breakpoints
  1661. // in code executed by multiple threads. Force
  1662. // the defer thread to be the only thread executing
  1663. // in order to avoid other threads running through
  1664. // the breakpoint location or generating events.
  1665. g_SelectExecutionThread = SELTHREAD_INTERNAL_THREAD;
  1666. g_SelectedThread = g_EventThread;
  1667. }
  1668. if (Flat(*g_DeferBp->GetAddr()) == OFFSET_TRACE)
  1669. {
  1670. BpOut("Setting trace flag for defer thread %d:%x\n",
  1671. g_RegContextThread ? g_RegContextThread->UserId : 0,
  1672. g_RegContextThread ? g_RegContextThread->SystemId : 0);
  1673. Machine->QuietSetTraceMode(TRACE_INSTRUCTION);
  1674. if (IS_USER_TARGET() &&
  1675. g_CurrentProcess != NULL &&
  1676. g_CurrentProcess->CurrentThread != NULL)
  1677. {
  1678. // If the debugger is setting the trace flag
  1679. // for the current thread remember that it
  1680. // did so in order to properly recognize
  1681. // debugger-provoked single-step events even
  1682. // when events occur on other threads before
  1683. // the single-step event comes back.
  1684. g_CurrentProcess->CurrentThread->Flags |=
  1685. ENG_THREAD_DEFER_BP_TRACE;
  1686. }
  1687. }
  1688. else
  1689. {
  1690. // If an existing breakpoint or the step/trace breakpoint
  1691. // isn't already set on the next offset, insert the deferred
  1692. // breakpoint.
  1693. if (CheckMatchingBreakpoints(g_DeferBp, FALSE,
  1694. BREAKPOINT_INSERTED) == NULL &&
  1695. ((g_StepTraceBp->m_Flags & BREAKPOINT_INSERTED) == 0 ||
  1696. !AddrEqu(*g_StepTraceBp->GetAddr(), *g_DeferBp->GetAddr())))
  1697. {
  1698. if (g_DeferBp->Insert() != S_OK)
  1699. {
  1700. ErrOut("Deferred bp at addr ");
  1701. MaskOutAddr(DEBUG_OUTPUT_ERROR, g_DeferBp->GetAddr());
  1702. ErrOut("failed\n");
  1703. Status = E_FAIL;
  1704. }
  1705. else
  1706. {
  1707. BpOut("Deferred bp at addr ");
  1708. MaskOutAddr(DEBUG_IOUTPUT_BREAKPOINT,
  1709. g_DeferBp->GetAddr());
  1710. BpOut("succeeded\n");
  1711. }
  1712. }
  1713. else
  1714. {
  1715. BpOut("Defer bp matches existing bp\n");
  1716. }
  1717. }
  1718. }
  1719. ChangeRegContext(OldThread);
  1720. // Always consider breakpoints inserted since some
  1721. // of them may have been inserted even if some failed.
  1722. g_EngStatus |= ENG_STATUS_BREAKPOINTS_INSERTED;
  1723. return Status;
  1724. }
  1725. //----------------------------------------------------------------------------
  1726. //
  1727. // Reverse any debuggee changes caused by breakpoint insertion.
  1728. //
  1729. //----------------------------------------------------------------------------
  1730. BOOL
  1731. RemoveBreakpoints(void)
  1732. {
  1733. if ((g_EngStatus & ENG_STATUS_BREAKPOINTS_INSERTED) == 0 ||
  1734. (g_EngStatus & ENG_STATUS_SUSPENDED) == 0 ||
  1735. IS_DUMP_TARGET())
  1736. {
  1737. return FALSE; // do nothing
  1738. }
  1739. BpOut("RemoveBreakpoints\n");
  1740. // restore the deferred breakpoint if set
  1741. g_DeferBp->Remove();
  1742. // restore the step/trace breakpoint if set
  1743. g_StepTraceBp->Remove();
  1744. if (!g_BreakpointsSuspended)
  1745. {
  1746. //
  1747. // Restore any appropriate permanent breakpoints (reverse order).
  1748. //
  1749. PPROCESS_INFO Process;
  1750. Breakpoint* Bp;
  1751. for (Process = g_ProcessHead; Process; Process = Process->Next)
  1752. {
  1753. BpOut(" Process %d with %d bps\n", Process->UserId,
  1754. Process->NumBreakpoints);
  1755. for (Bp = Process->BreakpointsTail; Bp != NULL; Bp = Bp->m_Prev)
  1756. {
  1757. Bp->Remove();
  1758. }
  1759. }
  1760. }
  1761. g_EngStatus &= ~ENG_STATUS_BREAKPOINTS_INSERTED;
  1762. return TRUE;
  1763. }
  1764. //----------------------------------------------------------------------------
  1765. //
  1766. // Create a new breakpoint object.
  1767. //
  1768. //----------------------------------------------------------------------------
  1769. HRESULT
  1770. AddBreakpoint(DebugClient* Client,
  1771. ULONG Type,
  1772. ULONG DesiredId,
  1773. Breakpoint** RetBp)
  1774. {
  1775. Breakpoint* Bp;
  1776. ULONG Id;
  1777. PPROCESS_INFO Process;
  1778. if (!IS_MACHINE_SET() || !g_CurrentProcess)
  1779. {
  1780. return E_UNEXPECTED;
  1781. }
  1782. if (DesiredId == DEBUG_ANY_ID)
  1783. {
  1784. // Find the lowest unused ID across all processes.
  1785. // Breakpoint IDs are kept unique across all
  1786. // breakpoints to prevent user confusion and also
  1787. // to give extensions a unique ID for breakpoints.
  1788. Id = 0;
  1789. for (;;)
  1790. {
  1791. // Search all bps to see if the current ID is in use.
  1792. for (Process = g_ProcessHead; Process; Process = Process->Next)
  1793. {
  1794. for (Bp = Process->Breakpoints; Bp; Bp = Bp->m_Next)
  1795. {
  1796. if (Bp->m_Id == Id)
  1797. {
  1798. break;
  1799. }
  1800. }
  1801. if (Bp != NULL)
  1802. {
  1803. break;
  1804. }
  1805. }
  1806. if (Process != NULL)
  1807. {
  1808. // A breakpoint is already using the current ID.
  1809. // Try the next one.
  1810. Id++;
  1811. }
  1812. else
  1813. {
  1814. break;
  1815. }
  1816. }
  1817. }
  1818. else
  1819. {
  1820. // Check to see if the desired ID is in use.
  1821. for (Process = g_ProcessHead; Process; Process = Process->Next)
  1822. {
  1823. for (Bp = Process->Breakpoints; Bp != NULL; Bp = Bp->m_Next)
  1824. {
  1825. if (Bp->m_Id == DesiredId)
  1826. {
  1827. return E_INVALIDARG;
  1828. }
  1829. }
  1830. }
  1831. Id = DesiredId;
  1832. }
  1833. HRESULT Status = g_Machine->NewBreakpoint(Client, Type, Id, &Bp);
  1834. if (Status != S_OK)
  1835. {
  1836. return Status;
  1837. }
  1838. *RetBp = Bp;
  1839. Bp->LinkIntoList();
  1840. // If this is an internal, hidden breakpoint set
  1841. // the flag immediately and do not notify.
  1842. if (Type & BREAKPOINT_HIDDEN)
  1843. {
  1844. Bp->m_Flags |= BREAKPOINT_HIDDEN;
  1845. }
  1846. else
  1847. {
  1848. NotifyChangeEngineState(DEBUG_CES_BREAKPOINTS, Id, TRUE);
  1849. }
  1850. return S_OK;
  1851. }
  1852. //----------------------------------------------------------------------------
  1853. //
  1854. // Delete a breakpoint object.
  1855. //
  1856. //----------------------------------------------------------------------------
  1857. void
  1858. DiscardBreakpoint(Breakpoint* Bp)
  1859. {
  1860. ULONG i;
  1861. // Make sure stale pointers aren't left in the
  1862. // go breakpoints array. This can happen if
  1863. // a process exits or the target reboots while
  1864. // go breakpoints are active.
  1865. for (i = 0; i < g_NumGoBreakpoints; i++)
  1866. {
  1867. if (g_GoBreakpoints[i] == Bp)
  1868. {
  1869. g_GoBreakpoints[i] = NULL;
  1870. }
  1871. }
  1872. delete Bp;
  1873. }
  1874. void
  1875. RemoveBreakpoint(Breakpoint* Bp)
  1876. {
  1877. ULONG Id = Bp->m_Id;
  1878. ULONG Flags = Bp->m_Flags;
  1879. DiscardBreakpoint(Bp);
  1880. if ((Flags & BREAKPOINT_HIDDEN) == 0)
  1881. {
  1882. NotifyChangeEngineState(DEBUG_CES_BREAKPOINTS, Id, TRUE);
  1883. }
  1884. }
  1885. //----------------------------------------------------------------------------
  1886. //
  1887. // Clean up breakpoints owned by a particular process or thread.
  1888. //
  1889. //----------------------------------------------------------------------------
  1890. void
  1891. RemoveProcessBreakpoints(PPROCESS_INFO Process)
  1892. {
  1893. g_EngNotify++;
  1894. Breakpoint* Bp;
  1895. Breakpoint* NextBp;
  1896. BOOL NeedNotify = FALSE;
  1897. for (Bp = Process->Breakpoints; Bp != NULL; Bp = NextBp)
  1898. {
  1899. NextBp = Bp->m_Next;
  1900. DBG_ASSERT(Bp->m_Process == Process);
  1901. RemoveBreakpoint(Bp);
  1902. NeedNotify = TRUE;
  1903. }
  1904. g_EngNotify--;
  1905. if (NeedNotify)
  1906. {
  1907. NotifyChangeEngineState(DEBUG_CES_BREAKPOINTS, DEBUG_ANY_ID, TRUE);
  1908. }
  1909. }
  1910. void
  1911. RemoveThreadBreakpoints(PTHREAD_INFO Thread)
  1912. {
  1913. g_EngNotify++;
  1914. Breakpoint* Bp;
  1915. Breakpoint* NextBp;
  1916. BOOL NeedNotify = FALSE;
  1917. DBG_ASSERT(Thread->Process);
  1918. for (Bp = Thread->Process->Breakpoints; Bp != NULL; Bp = NextBp)
  1919. {
  1920. NextBp = Bp->m_Next;
  1921. DBG_ASSERT(Bp->m_Process == Thread->Process);
  1922. if (Bp->m_MatchThread == Thread)
  1923. {
  1924. RemoveBreakpoint(Bp);
  1925. NeedNotify = TRUE;
  1926. }
  1927. }
  1928. g_EngNotify--;
  1929. if (NeedNotify)
  1930. {
  1931. NotifyChangeEngineState(DEBUG_CES_BREAKPOINTS, DEBUG_ANY_ID, TRUE);
  1932. }
  1933. }
  1934. //----------------------------------------------------------------------------
  1935. //
  1936. // Forces the target machine to remove all kernel breakpoints.
  1937. //
  1938. //----------------------------------------------------------------------------
  1939. void
  1940. RemoveAllKernelBreakpoints(void)
  1941. {
  1942. ULONG i;
  1943. // Indices are array index plus one.
  1944. for (i = 1; i <= BREAKPOINT_TABLE_SIZE; i++)
  1945. {
  1946. DbgKdRestoreBreakPoint(i);
  1947. }
  1948. // This API was added for Whistler so it fails against
  1949. // any previous OS. Ignore any failure return.
  1950. DbgKdClearAllInternalBreakpoints();
  1951. }
  1952. //----------------------------------------------------------------------------
  1953. //
  1954. // Remove all breakpoints and reset breakpoint state.
  1955. //
  1956. //----------------------------------------------------------------------------
  1957. void
  1958. RemoveAllBreakpoints(ULONG Reason)
  1959. {
  1960. PPROCESS_INFO Process;
  1961. g_EngNotify++;
  1962. for (Process = g_ProcessHead; Process; Process = Process->Next)
  1963. {
  1964. while (Process->Breakpoints != NULL)
  1965. {
  1966. RemoveBreakpoint(Process->Breakpoints);
  1967. }
  1968. }
  1969. g_EngNotify--;
  1970. NotifyChangeEngineState(DEBUG_CES_BREAKPOINTS, DEBUG_ANY_ID, TRUE);
  1971. g_NumGoBreakpoints = 0;
  1972. // If the machine is shutting down we can't
  1973. // remove breakpoints.
  1974. if (Reason != DEBUG_SESSION_REBOOT &&
  1975. Reason != DEBUG_SESSION_HIBERNATE &&
  1976. Reason != DEBUG_SESSION_FAILURE &&
  1977. IS_CONN_KERNEL_TARGET() &&
  1978. g_DbgKdTransport->m_WaitingThread == 0)
  1979. {
  1980. RemoveAllKernelBreakpoints();
  1981. // If there were any data breakpoints active
  1982. // remove them from all processors. This can't be in
  1983. // RemoveAllKernelBreakpoints as that
  1984. // code is called in the middle of state
  1985. // change processing when the context hasn't
  1986. // been initialized.
  1987. if (g_UpdateDataBreakpoints)
  1988. {
  1989. ULONG Proc;
  1990. SetEffMachine(g_TargetMachineType, FALSE);
  1991. g_EngNotify++;
  1992. for (Proc = 0; Proc < g_TargetNumberProcessors; Proc++)
  1993. {
  1994. SetCurrentProcessorThread(Proc, TRUE);
  1995. // Force the context to be dirty so it
  1996. // gets written back.
  1997. g_Machine->GetContextState(MCTX_DIRTY);
  1998. g_Machine->RemoveAllDataBreakpoints();
  1999. }
  2000. g_EngNotify--;
  2001. // Flush final context.
  2002. ChangeRegContext(NULL);
  2003. }
  2004. }
  2005. // Always update data breakpoints the very first time in
  2006. // order to flush out any stale data breakpoints.
  2007. g_UpdateDataBreakpoints = TRUE;
  2008. g_DataBreakpointsChanged = FALSE;
  2009. g_BreakpointsSuspended = FALSE;
  2010. delete g_StepTraceBp;
  2011. g_StepTraceBp = NULL;
  2012. delete g_DeferBp;
  2013. g_DeferBp = NULL;
  2014. g_DeferDefined = FALSE;
  2015. }
  2016. //----------------------------------------------------------------------------
  2017. //
  2018. // Look up breakpoints.
  2019. //
  2020. //----------------------------------------------------------------------------
  2021. Breakpoint*
  2022. GetBreakpointByIndex(DebugClient* Client, ULONG Index)
  2023. {
  2024. Breakpoint* Bp;
  2025. DBG_ASSERT(g_CurrentProcess);
  2026. for (Bp = g_CurrentProcess->Breakpoints;
  2027. Bp != NULL && Index > 0;
  2028. Bp = Bp->m_Next)
  2029. {
  2030. Index--;
  2031. }
  2032. if (Bp != NULL &&
  2033. (Bp->m_Flags & BREAKPOINT_HIDDEN) == 0 &&
  2034. ((Bp->m_Flags & DEBUG_BREAKPOINT_ADDER_ONLY) == 0 ||
  2035. Bp->m_Adder == Client))
  2036. {
  2037. return Bp;
  2038. }
  2039. return NULL;
  2040. }
  2041. Breakpoint*
  2042. GetBreakpointById(DebugClient* Client, ULONG Id)
  2043. {
  2044. Breakpoint* Bp;
  2045. DBG_ASSERT(g_CurrentProcess);
  2046. for (Bp = g_CurrentProcess->Breakpoints; Bp != NULL; Bp = Bp->m_Next)
  2047. {
  2048. if (Bp->m_Id == Id)
  2049. {
  2050. if ((Bp->m_Flags & BREAKPOINT_HIDDEN) == 0 &&
  2051. ((Bp->m_Flags & DEBUG_BREAKPOINT_ADDER_ONLY) == 0 ||
  2052. Bp->m_Adder == Client))
  2053. {
  2054. return Bp;
  2055. }
  2056. break;
  2057. }
  2058. }
  2059. return NULL;
  2060. }
  2061. //----------------------------------------------------------------------------
  2062. //
  2063. // Check to see if two breakpoints refer to the same breakpoint
  2064. // conditions.
  2065. //
  2066. //----------------------------------------------------------------------------
  2067. Breakpoint*
  2068. CheckMatchingBreakpoints(Breakpoint* Match, BOOL Public, ULONG IncFlags)
  2069. {
  2070. Breakpoint* Bp;
  2071. for (Bp = Match->m_Process->Breakpoints; Bp != NULL; Bp = Bp->m_Next)
  2072. {
  2073. if (Bp == Match || (Bp->m_Flags & IncFlags) == 0)
  2074. {
  2075. continue;
  2076. }
  2077. if ((Public && Bp->IsPublicMatch(Match)) ||
  2078. (!Public && Bp->IsInsertionMatch(Match)))
  2079. {
  2080. return Bp;
  2081. }
  2082. }
  2083. return NULL;
  2084. }
  2085. //----------------------------------------------------------------------------
  2086. //
  2087. // Starting at the given breakpoint, check to see if a breakpoint
  2088. // is hit with the current processor state. Breakpoint types
  2089. // can be included or excluded by flags.
  2090. //
  2091. //----------------------------------------------------------------------------
  2092. Breakpoint*
  2093. CheckBreakpointHit(PPROCESS_INFO Process, Breakpoint* Start, PADDR Addr,
  2094. ULONG ExbsType, ULONG IncFlags, ULONG ExcFlags,
  2095. PULONG HitType,
  2096. BOOL SetLastBreakpointHit)
  2097. {
  2098. DBG_ASSERT(ExbsType & EXBS_BREAKPOINT_ANY);
  2099. ULONG BreakType;
  2100. switch(ExbsType)
  2101. {
  2102. case EXBS_BREAKPOINT_CODE:
  2103. BreakType = DEBUG_BREAKPOINT_CODE;
  2104. break;
  2105. case EXBS_BREAKPOINT_DATA:
  2106. BreakType = DEBUG_BREAKPOINT_DATA;
  2107. break;
  2108. default:
  2109. ExbsType = EXBS_BREAKPOINT_ANY;
  2110. break;
  2111. }
  2112. Breakpoint* Bp;
  2113. BpOut("CheckBp addr ");
  2114. MaskOutAddr(DEBUG_IOUTPUT_BREAKPOINT, Addr);
  2115. BpOut("\n");
  2116. for (Bp = (Start == NULL ? Process->Breakpoints : Start);
  2117. Bp != NULL;
  2118. Bp = Bp->m_Next)
  2119. {
  2120. // Allow different kinds of breakpoints to be scanned
  2121. // separately if desired.
  2122. if ((ExbsType != EXBS_BREAKPOINT_ANY &&
  2123. Bp->m_BreakType != BreakType) ||
  2124. (Bp->m_Flags & IncFlags) == 0 ||
  2125. (Bp->m_Flags & ExcFlags) != 0)
  2126. {
  2127. continue;
  2128. }
  2129. // Common code is inlined here rather than in the
  2130. // base class because both pre- and post-derived
  2131. // checks are necessary.
  2132. // Force recomputation of flat address.
  2133. if (Bp->m_Flags & BREAKPOINT_VIRT_ADDR)
  2134. {
  2135. NotFlat(*Bp->GetAddr());
  2136. ComputeFlatAddress(Bp->GetAddr(), NULL);
  2137. }
  2138. if (Bp->IsNormalEnabled())
  2139. {
  2140. // We've got a partial match. Further checks
  2141. // depend on what kind of breakpoint it is.
  2142. *HitType = Bp->IsHit(Addr);
  2143. if (*HitType != BREAKPOINT_NOT_HIT)
  2144. {
  2145. // Do a final check for the pass count. If the
  2146. // pass count is nonzero this will become a partial hit.
  2147. if (*HitType == BREAKPOINT_HIT &&
  2148. !Bp->PassHit())
  2149. {
  2150. *HitType = BREAKPOINT_HIT_IGNORED;
  2151. }
  2152. BpOut(" hit %d\n", Bp->m_Id);
  2153. if (SetLastBreakpointHit)
  2154. {
  2155. g_LastBreakpointHit = Bp;
  2156. g_Machine->GetPC(&g_LastBreakpointHitPc);
  2157. }
  2158. return Bp;
  2159. }
  2160. }
  2161. }
  2162. BpOut(" no hit\n");
  2163. *HitType = BREAKPOINT_NOT_HIT;
  2164. if (SetLastBreakpointHit)
  2165. {
  2166. g_LastBreakpointHit = NULL;
  2167. ZeroMemory(&g_LastBreakpointHitPc, sizeof(g_LastBreakpointHitPc));
  2168. }
  2169. return NULL;
  2170. }
  2171. //----------------------------------------------------------------------------
  2172. //
  2173. // Walk the breakpoint list and invoke event callbacks for
  2174. // any breakpoints that need it. Watch for and handle list changes
  2175. // caused by callbacks.
  2176. //
  2177. //----------------------------------------------------------------------------
  2178. ULONG
  2179. NotifyHitBreakpoints(ULONG EventStatus)
  2180. {
  2181. Breakpoint* Bp;
  2182. PPROCESS_INFO Process;
  2183. for (;;)
  2184. {
  2185. g_BreakpointListChanged = FALSE;
  2186. for (Process = g_ProcessHead; Process; Process = Process->Next)
  2187. {
  2188. for (Bp = Process->Breakpoints; Bp != NULL; Bp = Bp->m_Next)
  2189. {
  2190. if (Bp->m_Flags & BREAKPOINT_NOTIFY)
  2191. {
  2192. Bp->m_Flags &= ~BREAKPOINT_NOTIFY;
  2193. EventStatus = NotifyBreakpointEvent(EventStatus, Bp);
  2194. // If the callback caused the breakpoint list to
  2195. // change we can no longer rely on the pointer
  2196. // we have and we need to restart the iteration.
  2197. if (g_BreakpointListChanged)
  2198. {
  2199. break;
  2200. }
  2201. }
  2202. }
  2203. if (Bp)
  2204. {
  2205. break;
  2206. }
  2207. }
  2208. if (Process == NULL)
  2209. {
  2210. break;
  2211. }
  2212. }
  2213. return EventStatus;
  2214. }
  2215. //----------------------------------------------------------------------------
  2216. //
  2217. // A module load/unload event has occurred so go through every
  2218. // breakpoint with an offset expression and reevaluate it.
  2219. //
  2220. //----------------------------------------------------------------------------
  2221. void
  2222. EvaluateOffsetExpressions(PPROCESS_INFO Process, ULONG Flags)
  2223. {
  2224. static BOOL s_Evaluating;
  2225. // Don't reevaluate when not notifying because
  2226. // lack of notification usually means that a group
  2227. // of operations is being done and that notify/reevaluate
  2228. // will be done later after all of them are finished.
  2229. // It is also possible to have nested evaluations as
  2230. // evaluation may provoke symbol loads on deferred
  2231. // modules, which leads to a symbol notification and
  2232. // thus another evaluation. If we're already evaluating
  2233. // there's no need to evaluate again.
  2234. if (g_EngNotify > 0 || s_Evaluating)
  2235. {
  2236. return;
  2237. }
  2238. s_Evaluating = TRUE;
  2239. Breakpoint* Bp;
  2240. BOOL AnyEnabled = FALSE;
  2241. for (Bp = Process->Breakpoints; Bp != NULL; Bp = Bp->m_Next)
  2242. {
  2243. // Optimize evaluation somewhat.
  2244. // If a module is added then deferred breakpoints
  2245. // can become active. If a module is removed then
  2246. // active breakpoints can become deferred.
  2247. // XXX drewb - This doesn't hold up with general
  2248. // conditional expressions but currently the
  2249. // only thing that is officially supported is a simple symbol.
  2250. if (Bp->m_OffsetExpr != NULL &&
  2251. (((Flags & DEBUG_CSS_LOADS) &&
  2252. (Bp->m_Flags & DEBUG_BREAKPOINT_DEFERRED)) ||
  2253. ((Flags & DEBUG_CSS_UNLOADS) &&
  2254. (Bp->m_Flags & DEBUG_BREAKPOINT_DEFERRED) == 0)))
  2255. {
  2256. if (Bp->EvalOffsetExpr() &&
  2257. (Bp->m_Flags & DEBUG_BREAKPOINT_DEFERRED) == 0)
  2258. {
  2259. // No need to update on newly disabled breakpoints
  2260. // as the module is being unloaded so they'll
  2261. // go away anyway. The disabled breakpoint
  2262. // is simply marked not-inserted in EvalOffsetExpr.
  2263. AnyEnabled = TRUE;
  2264. }
  2265. }
  2266. if (g_EngStatus & (ENG_STATUS_USER_INTERRUPT |
  2267. ENG_STATUS_PENDING_BREAK_IN))
  2268. {
  2269. // Leave the interrupt set as this may be
  2270. // called in the middle of a symbol operation
  2271. // and we want the interrupt to interrupt
  2272. // the entire symbol operation.
  2273. break;
  2274. }
  2275. }
  2276. if (AnyEnabled)
  2277. {
  2278. // A deferred breakpoint has become enabled.
  2279. // Force a refresh of the breakpoints so
  2280. // that the newly enabled breakpoints get inserted.
  2281. SuspendExecution();
  2282. RemoveBreakpoints();
  2283. }
  2284. s_Evaluating = FALSE;
  2285. }
  2286. //----------------------------------------------------------------------------
  2287. //
  2288. // Alters breakpoint state for b[cde]<idlist>.
  2289. //
  2290. //----------------------------------------------------------------------------
  2291. void
  2292. ChangeBreakpointState(DebugClient* Client, PPROCESS_INFO ForProcess,
  2293. ULONG Id, UCHAR StateChange)
  2294. {
  2295. Breakpoint* Bp;
  2296. Breakpoint* NextBp;
  2297. PPROCESS_INFO Process;
  2298. for (Process = g_ProcessHead; Process; Process = Process->Next)
  2299. {
  2300. if (ForProcess != NULL && Process != ForProcess)
  2301. {
  2302. continue;
  2303. }
  2304. for (Bp = Process->Breakpoints; Bp != NULL; Bp = NextBp)
  2305. {
  2306. // Prefetch the next breakpoint in case we remove
  2307. // the current breakpoint from the list.
  2308. NextBp = Bp->m_Next;
  2309. if ((Id == ALL_ID_LIST || Bp->m_Id == Id) &&
  2310. (Bp->m_Flags & BREAKPOINT_HIDDEN) == 0 &&
  2311. ((Bp->m_Flags & DEBUG_BREAKPOINT_ADDER_ONLY) == 0 ||
  2312. Bp->m_Adder == Client))
  2313. {
  2314. if (StateChange == 'c')
  2315. {
  2316. RemoveBreakpoint(Bp);
  2317. }
  2318. else
  2319. {
  2320. if (StateChange == 'e')
  2321. {
  2322. Bp->AddFlags(DEBUG_BREAKPOINT_ENABLED);
  2323. }
  2324. else
  2325. {
  2326. Bp->RemoveFlags(DEBUG_BREAKPOINT_ENABLED);
  2327. }
  2328. }
  2329. }
  2330. }
  2331. }
  2332. }
  2333. //----------------------------------------------------------------------------
  2334. //
  2335. // Lists current breakpoints for bl.
  2336. //
  2337. //----------------------------------------------------------------------------
  2338. void
  2339. ListBreakpoints(DebugClient* Client, PPROCESS_INFO ForProcess,
  2340. ULONG Id)
  2341. {
  2342. PPROCESS_INFO ProcessSaved = g_CurrentProcess;
  2343. Breakpoint* Bp;
  2344. PPROCESS_INFO Process;
  2345. for (Process = g_ProcessHead; Process; Process = Process->Next)
  2346. {
  2347. if (ForProcess != NULL && Process != ForProcess)
  2348. {
  2349. continue;
  2350. }
  2351. for (Bp = Process->Breakpoints; Bp != NULL; Bp = Bp->m_Next)
  2352. {
  2353. char StatusChar;
  2354. if ((Bp->m_Flags & BREAKPOINT_HIDDEN) ||
  2355. ((Bp->m_Flags & DEBUG_BREAKPOINT_ADDER_ONLY) &&
  2356. Client != Bp->m_Adder) ||
  2357. (Id != ALL_ID_LIST && Bp->m_Id != Id))
  2358. {
  2359. continue;
  2360. }
  2361. if (Bp->m_Flags & DEBUG_BREAKPOINT_ENABLED)
  2362. {
  2363. if (Bp->m_Flags & BREAKPOINT_KD_INTERNAL)
  2364. {
  2365. StatusChar =
  2366. (Bp->m_Flags & BREAKPOINT_KD_COUNT_ONLY) ? 'i' : 'w';
  2367. }
  2368. else
  2369. {
  2370. StatusChar = 'e';
  2371. }
  2372. }
  2373. else
  2374. {
  2375. StatusChar = 'd';
  2376. }
  2377. dprintf("%2ld %c", Bp->m_Id, StatusChar);
  2378. if (Bp->GetProcType() != g_TargetMachineType)
  2379. {
  2380. dprintf("%s ",
  2381. g_AllMachines[Bp->GetProcIndex()]->m_AbbrevName);
  2382. }
  2383. if ((Bp->m_Flags & DEBUG_BREAKPOINT_DEFERRED) == 0)
  2384. {
  2385. dprintf(" ");
  2386. if (Bp->m_BreakType == DEBUG_BREAKPOINT_CODE &&
  2387. (g_SrcOptions & SRCOPT_STEP_SOURCE))
  2388. {
  2389. IMAGEHLP_LINE Line;
  2390. DWORD Disp;
  2391. Line.SizeOfStruct = sizeof(Line);
  2392. if (g_CurrentProcess != NULL &&
  2393. SymGetLineFromAddr(g_CurrentProcess->Handle,
  2394. Flat(*Bp->GetAddr()),
  2395. &Disp, &Line))
  2396. {
  2397. dprintf("[%s @ %d]", Line.FileName, Line.LineNumber);
  2398. }
  2399. else
  2400. {
  2401. dprintAddr(Bp->GetAddr());
  2402. }
  2403. }
  2404. else
  2405. {
  2406. dprintAddr(Bp->GetAddr());
  2407. }
  2408. }
  2409. else if (g_TargetMachine->m_Ptr64)
  2410. {
  2411. dprintf("u ");
  2412. }
  2413. else
  2414. {
  2415. dprintf("u ");
  2416. }
  2417. char OptionChar;
  2418. if (Bp->m_BreakType == DEBUG_BREAKPOINT_DATA)
  2419. {
  2420. switch(Bp->m_DataAccessType)
  2421. {
  2422. case DEBUG_BREAK_EXECUTE:
  2423. OptionChar = 'e';
  2424. break;
  2425. case DEBUG_BREAK_WRITE:
  2426. OptionChar = 'w';
  2427. break;
  2428. case DEBUG_BREAK_IO:
  2429. OptionChar = 'i';
  2430. break;
  2431. case DEBUG_BREAK_READ:
  2432. case DEBUG_BREAK_READ | DEBUG_BREAK_WRITE:
  2433. OptionChar = 'r';
  2434. break;
  2435. default:
  2436. OptionChar = '?';
  2437. break;
  2438. }
  2439. dprintf("%c %d", OptionChar, Bp->m_DataSize);
  2440. }
  2441. else
  2442. {
  2443. dprintf(" ");
  2444. }
  2445. dprintf(" %04lx (%04lx) ", Bp->m_CurPassCount, Bp->m_PassCount);
  2446. if ((Bp->m_Flags & DEBUG_BREAKPOINT_DEFERRED) == 0)
  2447. {
  2448. if (IS_USER_TARGET())
  2449. {
  2450. dprintf("%2ld:", Bp->m_Process->UserId);
  2451. if (Bp->m_MatchThread != NULL)
  2452. {
  2453. dprintf("~%03ld ", Bp->m_MatchThread->UserId);
  2454. }
  2455. else
  2456. {
  2457. dprintf("*** ");
  2458. }
  2459. }
  2460. g_CurrentProcess = Bp->m_Process;
  2461. OutputSymAddr(Flat(*Bp->GetAddr()), SYMADDR_FORCE);
  2462. if (Bp->m_Command != NULL)
  2463. {
  2464. dprintf("\"%s\"", Bp->m_Command);
  2465. }
  2466. }
  2467. else
  2468. {
  2469. dprintf(" (%s)", Bp->m_OffsetExpr);
  2470. }
  2471. dprintf("\n");
  2472. if (Bp->m_MatchThreadData || Bp->m_MatchProcessData)
  2473. {
  2474. dprintf(" ");
  2475. if (Bp->m_MatchThreadData)
  2476. {
  2477. dprintf(" Match thread data %s",
  2478. FormatAddr64(Bp->m_MatchThreadData));
  2479. }
  2480. if (Bp->m_MatchProcessData)
  2481. {
  2482. dprintf(" Match process data %s",
  2483. FormatAddr64(Bp->m_MatchProcessData));
  2484. }
  2485. dprintf("\n");
  2486. }
  2487. }
  2488. }
  2489. if (IS_KERNEL_TARGET())
  2490. {
  2491. dprintf("\n");
  2492. for (Process = g_ProcessHead; Process; Process = Process->Next)
  2493. {
  2494. if (ForProcess != NULL && Process != ForProcess)
  2495. {
  2496. continue;
  2497. }
  2498. for (Bp = Process->Breakpoints; Bp != NULL; Bp = Bp->m_Next)
  2499. {
  2500. if (Bp->m_Flags & BREAKPOINT_KD_INTERNAL)
  2501. {
  2502. ULONG flags, calls, minInst, maxInst, totInst, maxCPS;
  2503. DbgKdGetInternalBp(Flat(*Bp->GetAddr()), &flags, &calls,
  2504. &minInst, &maxInst, &totInst, &maxCPS);
  2505. dprintf("%s %6d %8d %8d %8d %2x %4d ",
  2506. FormatAddr64(Flat(*Bp->GetAddr())),
  2507. calls, minInst, maxInst,
  2508. totInst, flags, maxCPS);
  2509. g_CurrentProcess = Bp->m_Process;
  2510. OutputSymAddr(Flat(*Bp->GetAddr()), SYMADDR_FORCE);
  2511. dprintf("\n");
  2512. }
  2513. }
  2514. }
  2515. }
  2516. g_CurrentProcess = ProcessSaved;
  2517. }
  2518. //----------------------------------------------------------------------------
  2519. //
  2520. // Outputs commands necessary to recreate current breakpoints.
  2521. //
  2522. //----------------------------------------------------------------------------
  2523. void
  2524. ListBreakpointsAsCommands(DebugClient* Client, PPROCESS_INFO Process,
  2525. ULONG Flags)
  2526. {
  2527. Breakpoint* Bp;
  2528. if (Process == NULL)
  2529. {
  2530. return;
  2531. }
  2532. for (Bp = Process->Breakpoints; Bp != NULL; Bp = Bp->m_Next)
  2533. {
  2534. if ((Bp->m_Flags & BREAKPOINT_HIDDEN) ||
  2535. ((Bp->m_Flags & DEBUG_BREAKPOINT_ADDER_ONLY) &&
  2536. Client != Bp->m_Adder) ||
  2537. ((Flags & BPCMDS_EXPR_ONLY && Bp->m_OffsetExpr == NULL)))
  2538. {
  2539. continue;
  2540. }
  2541. if (IS_USER_TARGET())
  2542. {
  2543. if (Bp->m_MatchThread != NULL ||
  2544. Bp->m_MatchThreadData ||
  2545. Bp->m_MatchProcessData)
  2546. {
  2547. // Ignore thread- and data-specific breakpoints
  2548. // as the things they are specific to may
  2549. // not exist in a new session.
  2550. continue;
  2551. }
  2552. }
  2553. if (Bp->GetProcType() != g_TargetMachineType)
  2554. {
  2555. dprintf(".effmach %s;%c",
  2556. g_AllMachines[Bp->GetProcIndex()]->m_AbbrevName,
  2557. (Flags & BPCMDS_ONE_LINE) ? ' ' : '\n');
  2558. }
  2559. if ((Flags & BPCMDS_MODULE_HINT) &&
  2560. (Bp->m_Flags & (DEBUG_BREAKPOINT_DEFERRED |
  2561. BREAKPOINT_VIRT_ADDR)) == BREAKPOINT_VIRT_ADDR)
  2562. {
  2563. PDEBUG_IMAGE_INFO Image =
  2564. GetImageByOffset(Bp->m_Process, Flat(*Bp->GetAddr()));
  2565. if (Image != NULL)
  2566. {
  2567. dprintf("ld %s;%c", Image->ModuleName,
  2568. (Flags & BPCMDS_ONE_LINE) ? ' ' : '\n');
  2569. }
  2570. }
  2571. char TypeChar;
  2572. if (Bp->m_Flags & BREAKPOINT_KD_INTERNAL)
  2573. {
  2574. TypeChar = (Bp->m_Flags & BREAKPOINT_KD_COUNT_ONLY) ? 'i' : 'w';
  2575. }
  2576. else if (Bp->m_BreakType == DEBUG_BREAKPOINT_CODE)
  2577. {
  2578. TypeChar = Bp->m_OffsetExpr != NULL ? 'u' : 'p';
  2579. }
  2580. else
  2581. {
  2582. TypeChar = 'a';
  2583. }
  2584. dprintf("b%c%d", TypeChar, Bp->m_Id);
  2585. char OptionChar;
  2586. if (Bp->m_BreakType == DEBUG_BREAKPOINT_DATA)
  2587. {
  2588. switch(Bp->m_DataAccessType)
  2589. {
  2590. case DEBUG_BREAK_EXECUTE:
  2591. OptionChar = 'e';
  2592. break;
  2593. case DEBUG_BREAK_WRITE:
  2594. OptionChar = 'w';
  2595. break;
  2596. case DEBUG_BREAK_IO:
  2597. OptionChar = 'i';
  2598. break;
  2599. case DEBUG_BREAK_READ:
  2600. case DEBUG_BREAK_READ | DEBUG_BREAK_WRITE:
  2601. OptionChar = 'r';
  2602. break;
  2603. default:
  2604. continue;
  2605. }
  2606. dprintf(" %c%d", OptionChar, Bp->m_DataSize);
  2607. }
  2608. if (Bp->m_OffsetExpr != NULL)
  2609. {
  2610. dprintf(" %s", Bp->m_OffsetExpr);
  2611. }
  2612. else
  2613. {
  2614. dprintf(" 0x");
  2615. dprintAddr(Bp->GetAddr());
  2616. }
  2617. if (Bp->m_PassCount > 1)
  2618. {
  2619. dprintf(" 0x%x", Bp->m_PassCount);
  2620. }
  2621. if (Bp->m_Command != NULL)
  2622. {
  2623. dprintf(" \"%s\"", Bp->m_Command);
  2624. }
  2625. dprintf(";%c", (Flags & BPCMDS_ONE_LINE) ? ' ' : '\n');
  2626. if ((Flags & BPCMDS_FORCE_DISABLE) ||
  2627. (Bp->m_Flags & DEBUG_BREAKPOINT_ENABLED) == 0)
  2628. {
  2629. dprintf("bd %d;%c", Bp->m_Id,
  2630. (Flags & BPCMDS_ONE_LINE) ? ' ' : '\n');
  2631. }
  2632. if (Bp->GetProcType() != g_TargetMachineType)
  2633. {
  2634. dprintf(".effmach .;%c",
  2635. (Flags & BPCMDS_ONE_LINE) ? ' ' : '\n');
  2636. }
  2637. }
  2638. if (Flags & BPCMDS_ONE_LINE)
  2639. {
  2640. dprintf("\n");
  2641. }
  2642. }
  2643. //----------------------------------------------------------------------------
  2644. //
  2645. // Parses command-line breakpoint commands for b[aipw].
  2646. //
  2647. //----------------------------------------------------------------------------
  2648. PDEBUG_BREAKPOINT
  2649. ParseBpCmd(DebugClient* Client,
  2650. UCHAR Type,
  2651. PTHREAD_INFO Thread)
  2652. {
  2653. ULONG UserId = DEBUG_ANY_ID;
  2654. UCHAR ch;
  2655. ADDR Addr;
  2656. Breakpoint* Bp;
  2657. if (IS_LOCAL_KERNEL_TARGET() || IS_DUMP_TARGET())
  2658. {
  2659. error(SESSIONNOTSUP);
  2660. }
  2661. if (!IS_CONTEXT_ACCESSIBLE())
  2662. {
  2663. error(BADTHREAD);
  2664. }
  2665. if (IS_LIVE_USER_TARGET() && Type == 'a' &&
  2666. (g_EngStatus & ENG_STATUS_AT_INITIAL_BREAK))
  2667. {
  2668. ErrOut("The system resets thread contexts after the process\n");
  2669. ErrOut("breakpoint so hardware breakpoints cannot be set.\n");
  2670. ErrOut("Go to the executable's entry point and set it then.\n");
  2671. *g_CurCmd = 0;
  2672. return NULL;
  2673. }
  2674. // get the breakpoint number if given
  2675. ch = *g_CurCmd;
  2676. if (ch == '[')
  2677. {
  2678. UserId = (ULONG)GetTermExprDesc("Breakpoint ID missing from");
  2679. }
  2680. else if (ch >= '0' && ch <= '9')
  2681. {
  2682. UserId = ch - '0';
  2683. ch = *++g_CurCmd;
  2684. while (ch >= '0' && ch <= '9')
  2685. {
  2686. UserId = UserId * 10 + ch - '0';
  2687. ch = *++g_CurCmd;
  2688. }
  2689. if (ch != ' ' && ch != '\t' && ch != '\0')
  2690. {
  2691. error(SYNTAX);
  2692. }
  2693. }
  2694. if (UserId != DEBUG_ANY_ID)
  2695. {
  2696. // Remove any existing breakpoint with the given ID.
  2697. Breakpoint* IdBp;
  2698. if ((IdBp = GetBreakpointById(Client, UserId)) != NULL)
  2699. {
  2700. WarnOut("breakpoint %ld exists, redefining\n", UserId);
  2701. RemoveBreakpoint(IdBp);
  2702. }
  2703. }
  2704. // Create a new breakpoint.
  2705. if (AddBreakpoint(Client, Type == 'a' ?
  2706. DEBUG_BREAKPOINT_DATA : DEBUG_BREAKPOINT_CODE,
  2707. UserId, &Bp) != S_OK)
  2708. {
  2709. error(BPLISTFULL);
  2710. }
  2711. // Add in KD internal flags if necessary.
  2712. if (Type == 'i' || Type == 'w')
  2713. {
  2714. if (IS_KERNEL_TARGET())
  2715. {
  2716. Bp->m_Flags = Bp->m_Flags | BREAKPOINT_KD_INTERNAL |
  2717. (Type == 'i' ? BREAKPOINT_KD_COUNT_ONLY : 0);
  2718. if (Type == 'w')
  2719. {
  2720. SetupSpecialCalls();
  2721. }
  2722. }
  2723. else
  2724. {
  2725. // KD internal breakpoints are only supported in
  2726. // kernel debugging.
  2727. DiscardBreakpoint(Bp);
  2728. error(SYNTAX);
  2729. }
  2730. }
  2731. // if data breakpoint, get option and size values
  2732. if (Type == 'a')
  2733. {
  2734. ULONG64 Size;
  2735. ULONG AccessType;
  2736. ch = PeekChar();
  2737. ch = (UCHAR)tolower(ch);
  2738. if (ch == 'e')
  2739. {
  2740. AccessType = DEBUG_BREAK_EXECUTE;
  2741. }
  2742. else if (ch == 'w')
  2743. {
  2744. AccessType = DEBUG_BREAK_WRITE;
  2745. }
  2746. else if (ch == 'i')
  2747. {
  2748. AccessType = DEBUG_BREAK_IO;
  2749. }
  2750. else if (ch == 'r')
  2751. {
  2752. AccessType = DEBUG_BREAK_READ;
  2753. }
  2754. else
  2755. {
  2756. DiscardBreakpoint(Bp);
  2757. error(SYNTAX);
  2758. }
  2759. g_CurCmd++;
  2760. Size = GetTermExprDesc("Hardware breakpoint length missing from");
  2761. if (Size & ~ULONG(-1))
  2762. {
  2763. ErrOut("Breakpoint length too big\n");
  2764. DiscardBreakpoint(Bp);
  2765. error(SYNTAX);
  2766. }
  2767. // Validate the selections. This assumes that
  2768. // the default offset of zero won't cause problems.
  2769. if (Bp->SetDataParameters((ULONG)Size, AccessType) != S_OK)
  2770. {
  2771. DiscardBreakpoint(Bp);
  2772. error(SYNTAX);
  2773. }
  2774. g_CurCmd++;
  2775. }
  2776. //
  2777. // Parse breakpoint options.
  2778. //
  2779. while (PeekChar() == '/')
  2780. {
  2781. g_CurCmd++;
  2782. switch(*g_CurCmd++)
  2783. {
  2784. case 'p':
  2785. Bp->m_MatchProcessData = GetTermExprDesc(NULL);
  2786. break;
  2787. case 't':
  2788. Bp->m_MatchThreadData = GetTermExprDesc(NULL);
  2789. break;
  2790. default:
  2791. ErrOut("Unknown option '%c'\n", *g_CurCmd);
  2792. break;
  2793. }
  2794. }
  2795. // get the breakpoint address, if given, in addr
  2796. // default to PC
  2797. ULONG AddrValid = EVAL_RESOLVED;
  2798. g_Machine->GetPC(&Addr);
  2799. ch = PeekChar();
  2800. if (ch != '"' && ch != '\0')
  2801. {
  2802. PCHAR ExprStart = (PCHAR)g_CurCmd;
  2803. g_PrefixSymbols = Type == 'p' || Type == 'u';
  2804. AddrValid = EvalAddrExpression(g_CurrentProcess, g_EffMachine,
  2805. &Addr);
  2806. g_PrefixSymbols = FALSE;
  2807. if (AddrValid == EVAL_ERROR)
  2808. {
  2809. DiscardBreakpoint(Bp);
  2810. return NULL;
  2811. }
  2812. // If an unresolved symbol was encountered this
  2813. // breakpoint will be deferred. Users can also force
  2814. // breakpoints to use expressions for cases where the
  2815. // address could be resolved but also may become invalid
  2816. // later.
  2817. if (Type == 'u' || AddrValid == EVAL_UNRESOLVED)
  2818. {
  2819. HRESULT Status;
  2820. UCHAR Save = *g_CurCmd;
  2821. *g_CurCmd = 0;
  2822. Status = Bp->SetOffsetExpression(ExprStart);
  2823. if (Type != 'u' && Status == S_OK)
  2824. {
  2825. WarnOut("Bp expression '%s' could not be resolved, "
  2826. "adding deferred bp\n", ExprStart);
  2827. }
  2828. *g_CurCmd = Save;
  2829. if (Status != S_OK)
  2830. {
  2831. DiscardBreakpoint(Bp);
  2832. error(BPLISTFULL);
  2833. }
  2834. }
  2835. ch = PeekChar();
  2836. }
  2837. if (AddrValid != EVAL_UNRESOLVED)
  2838. {
  2839. ULONG AddrSpace, AddrFlags;
  2840. if (g_Target->
  2841. QueryAddressInformation(Flat(Addr), DBGKD_QUERY_MEMORY_VIRTUAL,
  2842. &AddrSpace, &AddrFlags) != S_OK)
  2843. {
  2844. ErrOut("Invalid breakpoint address\n");
  2845. DiscardBreakpoint(Bp);
  2846. error(MEMORY);
  2847. }
  2848. if (Type != 'a' &&
  2849. !(AddrFlags & DBGKD_QUERY_MEMORY_WRITE) ||
  2850. (AddrFlags & DBGKD_QUERY_MEMORY_FIXED))
  2851. {
  2852. ErrOut("Software breakpoints cannot be used on ROM code or\n"
  2853. "other read-only memory. "
  2854. "Use hardware execution breakpoints (ba e) instead.\n");
  2855. DiscardBreakpoint(Bp);
  2856. error(MEMORY);
  2857. }
  2858. if (Type != 'a' && AddrSpace == DBGKD_QUERY_MEMORY_SESSION)
  2859. {
  2860. WarnOut("WARNING: Software breakpoints on session "
  2861. "addresses can cause bugchecks.\n"
  2862. "Use hardware execution breakpoints (ba e) "
  2863. "if possible.\n");
  2864. }
  2865. }
  2866. // The public interface only supports flat addresses
  2867. // so use an internal method to set the true address.
  2868. // Do not allow matching breakpoints through the parsing
  2869. // interface as that was the previous behavior.
  2870. if (Bp->SetAddr(&Addr, BREAKPOINT_REMOVE_MATCH) != S_OK)
  2871. {
  2872. DiscardBreakpoint(Bp);
  2873. error(SYNTAX);
  2874. }
  2875. // get the pass count, if given
  2876. if (ch != '"' && ch != ';' && ch != '\0')
  2877. {
  2878. Bp->SetPassCount((ULONG)GetExpression());
  2879. ch = PeekChar();
  2880. }
  2881. // if next character is double quote, get the command string
  2882. if (ch == '"')
  2883. {
  2884. PSTR Str;
  2885. CHAR Save;
  2886. Str = StringValue(STRV_ESCAPED_CHARACTERS, &Save);
  2887. if (Bp->SetCommand(Str) != S_OK)
  2888. {
  2889. DiscardBreakpoint(Bp);
  2890. error(BPLISTFULL);
  2891. }
  2892. *g_CurCmd = Save;
  2893. }
  2894. // Set some final information.
  2895. if (Thread != NULL)
  2896. {
  2897. Bp->SetMatchThreadId(Thread->UserId);
  2898. }
  2899. // Turn breakpoint on.
  2900. Bp->AddFlags(DEBUG_BREAKPOINT_ENABLED);
  2901. return Bp;
  2902. }
  2903. inline BOOL
  2904. IsCodeBreakpointInsertedInRange(Breakpoint* Bp,
  2905. ULONG64 Start, ULONG64 End)
  2906. {
  2907. return (Bp->m_Flags & BREAKPOINT_INSERTED) &&
  2908. Bp->m_BreakType == DEBUG_BREAKPOINT_CODE &&
  2909. Flat(*Bp->GetAddr()) >= Start &&
  2910. Flat(*Bp->GetAddr()) <= End;
  2911. }
  2912. BOOL
  2913. CheckBreakpointInsertedInRange(PPROCESS_INFO Process,
  2914. ULONG64 Start, ULONG64 End)
  2915. {
  2916. if ((g_EngStatus & ENG_STATUS_BREAKPOINTS_INSERTED) == 0)
  2917. {
  2918. return FALSE;
  2919. }
  2920. //
  2921. // Check for a breakpoint that might have caused
  2922. // a break instruction to be inserted in the given
  2923. // offset range. Data breakpoints don't count
  2924. // as they don't actually modify the address they
  2925. // break on.
  2926. //
  2927. Breakpoint* Bp;
  2928. for (Bp = Process->Breakpoints; Bp != NULL; Bp = Bp->m_Next)
  2929. {
  2930. if (IsCodeBreakpointInsertedInRange(Bp, Start, End))
  2931. {
  2932. return TRUE;
  2933. }
  2934. }
  2935. if ((g_DeferBp->m_Process == Process &&
  2936. IsCodeBreakpointInsertedInRange(g_DeferBp, Start, End)) ||
  2937. (g_StepTraceBp->m_Process == Process &&
  2938. IsCodeBreakpointInsertedInRange(g_StepTraceBp, Start, End)))
  2939. {
  2940. return TRUE;
  2941. }
  2942. return FALSE;
  2943. }
  2944. void
  2945. DbgKdpAcquireHardwareBp(PDBGKD_CONTROL_REQUEST BpRequest)
  2946. {
  2947. BpRequest->u.RequestBreakpoint.Available = FALSE;
  2948. g_DbgKdTransport->WritePacket(BpRequest,
  2949. sizeof(*BpRequest),
  2950. PACKET_TYPE_KD_CONTROL_REQUEST,
  2951. NULL,
  2952. 0);
  2953. }
  2954. void
  2955. DbgKdpReleaseHardwareBp(PDBGKD_CONTROL_REQUEST BpRequest)
  2956. {
  2957. BpRequest->u.ReleaseBreakpoint.Released = TRUE;
  2958. g_DbgKdTransport->WritePacket(BpRequest,
  2959. sizeof(*BpRequest),
  2960. PACKET_TYPE_KD_CONTROL_REQUEST,
  2961. NULL,
  2962. 0);
  2963. }
  2964. //----------------------------------------------------------------------------
  2965. //
  2966. // TargetInfo methods.
  2967. //
  2968. //----------------------------------------------------------------------------
  2969. HRESULT
  2970. ConnLiveKernelTargetInfo::InsertCodeBreakpoint(PPROCESS_INFO Process,
  2971. MachineInfo* Machine,
  2972. PADDR Addr,
  2973. PUCHAR StorageSpace)
  2974. {
  2975. NTSTATUS Status = DbgKdWriteBreakPoint(Flat(*Addr),
  2976. (PULONG_PTR)StorageSpace);
  2977. return CONV_NT_STATUS(Status);
  2978. }
  2979. HRESULT
  2980. ConnLiveKernelTargetInfo::RemoveCodeBreakpoint(PPROCESS_INFO Process,
  2981. MachineInfo* Machine,
  2982. PADDR Addr,
  2983. PUCHAR StorageSpace)
  2984. {
  2985. // When the kernel fills out the CONTROL_REPORT.InstructionStream
  2986. // array it clears any breakpoints that might fall within the
  2987. // array. This means that some breakpoints may already be
  2988. // restored, so the restore call will fail. We could do some
  2989. // checks to try and figure out which ones might be affected
  2990. // but it doesn't seem worthwhile. Just ignore the return
  2991. // value from the restore.
  2992. DbgKdRestoreBreakPoint(*(PULONG_PTR)StorageSpace);
  2993. return S_OK;
  2994. }
  2995. HRESULT
  2996. ExdiLiveKernelTargetInfo::InsertCodeBreakpoint(PPROCESS_INFO Process,
  2997. MachineInfo* Machine,
  2998. PADDR Addr,
  2999. PUCHAR StorageSpace)
  3000. {
  3001. HRESULT Status = m_Server->
  3002. AddCodeBreakpoint(Flat(*Addr), m_CodeBpType, mtVirtual, 0, 0,
  3003. (IeXdiCodeBreakpoint**)StorageSpace);
  3004. if (Status == S_OK)
  3005. {
  3006. // Breakpoints are created disabled so enable it.
  3007. Status = (*(IeXdiCodeBreakpoint**)StorageSpace)->SetState(TRUE, TRUE);
  3008. if (Status != S_OK)
  3009. {
  3010. m_Server->DelCodeBreakpoint(*(IeXdiCodeBreakpoint**)StorageSpace);
  3011. }
  3012. }
  3013. return Status;
  3014. }
  3015. HRESULT
  3016. ExdiLiveKernelTargetInfo::RemoveCodeBreakpoint(PPROCESS_INFO Process,
  3017. MachineInfo* Machine,
  3018. PADDR Addr,
  3019. PUCHAR StorageSpace)
  3020. {
  3021. HRESULT Status = m_Server->
  3022. DelCodeBreakpoint(*(IeXdiCodeBreakpoint**)StorageSpace);
  3023. return Status;
  3024. }
  3025. HRESULT
  3026. UserTargetInfo::InsertCodeBreakpoint(PPROCESS_INFO Process,
  3027. MachineInfo* Machine,
  3028. PADDR Addr,
  3029. PUCHAR StorageSpace)
  3030. {
  3031. HRESULT Status;
  3032. if (m_ServiceFlags & DBGSVC_GENERIC_CODE_BREAKPOINTS)
  3033. {
  3034. ULONG64 ChangeStart;
  3035. ULONG ChangeLen;
  3036. Status = Machine->
  3037. InsertBreakpointInstruction(m_Services, Process->FullHandle,
  3038. Flat(*Addr), StorageSpace,
  3039. &ChangeStart, &ChangeLen);
  3040. if ((Status == HRESULT_FROM_WIN32(ERROR_PARTIAL_COPY) ||
  3041. Status == HRESULT_FROM_WIN32(ERROR_NOACCESS) ||
  3042. Status == HRESULT_FROM_WIN32(ERROR_WRITE_FAULT)) &&
  3043. (g_EngOptions & DEBUG_ENGOPT_ALLOW_READ_ONLY_BREAKPOINTS))
  3044. {
  3045. HRESULT NewStatus;
  3046. ULONG OldProtect;
  3047. // Change the page protections to read-write and try again.
  3048. NewStatus = m_Services->
  3049. ProtectVirtual(Process->FullHandle, ChangeStart, ChangeLen,
  3050. PAGE_READWRITE, &OldProtect);
  3051. if (NewStatus == S_OK)
  3052. {
  3053. // If the page was already writable there's no point in
  3054. // retrying
  3055. if ((OldProtect & (PAGE_READWRITE |
  3056. PAGE_WRITECOPY |
  3057. PAGE_EXECUTE_READWRITE |
  3058. PAGE_EXECUTE_WRITECOPY)) == 0)
  3059. {
  3060. NewStatus = Machine->
  3061. InsertBreakpointInstruction(m_Services,
  3062. Process->FullHandle,
  3063. Flat(*Addr), StorageSpace,
  3064. &ChangeStart, &ChangeLen);
  3065. if (NewStatus == S_OK)
  3066. {
  3067. Status = S_OK;
  3068. }
  3069. }
  3070. NewStatus = m_Services->
  3071. ProtectVirtual(Process->FullHandle, ChangeStart, ChangeLen,
  3072. OldProtect, &OldProtect);
  3073. if (NewStatus != S_OK)
  3074. {
  3075. // Couldn't restore page permissions so fail.
  3076. if (Status == S_OK)
  3077. {
  3078. Machine->
  3079. RemoveBreakpointInstruction(m_Services,
  3080. Process->FullHandle,
  3081. Flat(*Addr),
  3082. StorageSpace,
  3083. &ChangeStart,
  3084. &ChangeLen);
  3085. }
  3086. Status = NewStatus;
  3087. }
  3088. }
  3089. }
  3090. return Status;
  3091. }
  3092. else
  3093. {
  3094. return m_Services->
  3095. InsertCodeBreakpoint(Process->FullHandle,
  3096. Flat(*Addr), Machine->m_ExecTypes[0],
  3097. StorageSpace, MAX_BREAKPOINT_LENGTH);
  3098. }
  3099. }
  3100. HRESULT
  3101. UserTargetInfo::RemoveCodeBreakpoint(PPROCESS_INFO Process,
  3102. MachineInfo* Machine,
  3103. PADDR Addr,
  3104. PUCHAR StorageSpace)
  3105. {
  3106. HRESULT Status;
  3107. if (m_ServiceFlags & DBGSVC_GENERIC_CODE_BREAKPOINTS)
  3108. {
  3109. ULONG64 ChangeStart;
  3110. ULONG ChangeLen;
  3111. Status = Machine->
  3112. RemoveBreakpointInstruction(m_Services, Process->FullHandle,
  3113. Flat(*Addr), StorageSpace,
  3114. &ChangeStart, &ChangeLen);
  3115. if ((Status == HRESULT_FROM_WIN32(ERROR_PARTIAL_COPY) ||
  3116. Status == HRESULT_FROM_WIN32(ERROR_NOACCESS) ||
  3117. Status == HRESULT_FROM_WIN32(ERROR_WRITE_FAULT)) &&
  3118. (g_EngOptions & DEBUG_ENGOPT_ALLOW_READ_ONLY_BREAKPOINTS))
  3119. {
  3120. HRESULT NewStatus;
  3121. ULONG OldProtect;
  3122. // Change the page protections to read-write and try again.
  3123. NewStatus = m_Services->
  3124. ProtectVirtual(Process->FullHandle, ChangeStart, ChangeLen,
  3125. PAGE_READWRITE, &OldProtect);
  3126. if (NewStatus == S_OK)
  3127. {
  3128. // If the page was already writable there's no point in
  3129. // retrying
  3130. if ((OldProtect & (PAGE_READWRITE |
  3131. PAGE_WRITECOPY |
  3132. PAGE_EXECUTE_READWRITE |
  3133. PAGE_EXECUTE_WRITECOPY)) == 0)
  3134. {
  3135. NewStatus = Machine->
  3136. RemoveBreakpointInstruction(m_Services,
  3137. Process->FullHandle,
  3138. Flat(*Addr), StorageSpace,
  3139. &ChangeStart, &ChangeLen);
  3140. if (NewStatus == S_OK)
  3141. {
  3142. Status = S_OK;
  3143. }
  3144. }
  3145. NewStatus = m_Services->
  3146. ProtectVirtual(Process->FullHandle, ChangeStart, ChangeLen,
  3147. OldProtect, &OldProtect);
  3148. if (NewStatus != S_OK)
  3149. {
  3150. // Couldn't restore page permissions so fail.
  3151. if (Status == S_OK)
  3152. {
  3153. Machine->
  3154. InsertBreakpointInstruction(m_Services,
  3155. Process->FullHandle,
  3156. Flat(*Addr),
  3157. StorageSpace,
  3158. &ChangeStart,
  3159. &ChangeLen);
  3160. }
  3161. Status = NewStatus;
  3162. }
  3163. }
  3164. }
  3165. return Status;
  3166. }
  3167. else
  3168. {
  3169. return m_Services->
  3170. RemoveCodeBreakpoint(Process->FullHandle,
  3171. Flat(*Addr), Machine->m_ExecTypes[0],
  3172. StorageSpace, MAX_BREAKPOINT_LENGTH);
  3173. }
  3174. }