xref: /freebsd-src/contrib/llvm-project/lldb/source/Target/StopInfo.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
15ffd83dbSDimitry Andric //===-- StopInfo.cpp ------------------------------------------------------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric 
90b57cec5SDimitry Andric #include <string>
100b57cec5SDimitry Andric 
110b57cec5SDimitry Andric #include "lldb/Breakpoint/Breakpoint.h"
120b57cec5SDimitry Andric #include "lldb/Breakpoint/BreakpointLocation.h"
130b57cec5SDimitry Andric #include "lldb/Breakpoint/StoppointCallbackContext.h"
140b57cec5SDimitry Andric #include "lldb/Breakpoint/Watchpoint.h"
155f757f3fSDimitry Andric #include "lldb/Breakpoint/WatchpointResource.h"
160b57cec5SDimitry Andric #include "lldb/Core/Debugger.h"
170b57cec5SDimitry Andric #include "lldb/Core/ValueObject.h"
180b57cec5SDimitry Andric #include "lldb/Expression/UserExpression.h"
190b57cec5SDimitry Andric #include "lldb/Target/Process.h"
200b57cec5SDimitry Andric #include "lldb/Target/StopInfo.h"
210b57cec5SDimitry Andric #include "lldb/Target/Target.h"
220b57cec5SDimitry Andric #include "lldb/Target/Thread.h"
230b57cec5SDimitry Andric #include "lldb/Target/ThreadPlan.h"
24bdd1243dSDimitry Andric #include "lldb/Target/ThreadPlanStepInstruction.h"
250b57cec5SDimitry Andric #include "lldb/Target/UnixSignals.h"
2681ad6265SDimitry Andric #include "lldb/Utility/LLDBLog.h"
270b57cec5SDimitry Andric #include "lldb/Utility/Log.h"
280b57cec5SDimitry Andric #include "lldb/Utility/StreamString.h"
290b57cec5SDimitry Andric 
300b57cec5SDimitry Andric using namespace lldb;
310b57cec5SDimitry Andric using namespace lldb_private;
320b57cec5SDimitry Andric 
330b57cec5SDimitry Andric StopInfo::StopInfo(Thread &thread, uint64_t value)
340b57cec5SDimitry Andric     : m_thread_wp(thread.shared_from_this()),
350b57cec5SDimitry Andric       m_stop_id(thread.GetProcess()->GetStopID()),
360b57cec5SDimitry Andric       m_resume_id(thread.GetProcess()->GetResumeID()), m_value(value),
370b57cec5SDimitry Andric       m_description(), m_override_should_notify(eLazyBoolCalculate),
380b57cec5SDimitry Andric       m_override_should_stop(eLazyBoolCalculate), m_extended_info() {}
390b57cec5SDimitry Andric 
400b57cec5SDimitry Andric bool StopInfo::IsValid() const {
410b57cec5SDimitry Andric   ThreadSP thread_sp(m_thread_wp.lock());
420b57cec5SDimitry Andric   if (thread_sp)
430b57cec5SDimitry Andric     return thread_sp->GetProcess()->GetStopID() == m_stop_id;
440b57cec5SDimitry Andric   return false;
450b57cec5SDimitry Andric }
460b57cec5SDimitry Andric 
470b57cec5SDimitry Andric void StopInfo::MakeStopInfoValid() {
480b57cec5SDimitry Andric   ThreadSP thread_sp(m_thread_wp.lock());
490b57cec5SDimitry Andric   if (thread_sp) {
500b57cec5SDimitry Andric     m_stop_id = thread_sp->GetProcess()->GetStopID();
510b57cec5SDimitry Andric     m_resume_id = thread_sp->GetProcess()->GetResumeID();
520b57cec5SDimitry Andric   }
530b57cec5SDimitry Andric }
540b57cec5SDimitry Andric 
550b57cec5SDimitry Andric bool StopInfo::HasTargetRunSinceMe() {
560b57cec5SDimitry Andric   ThreadSP thread_sp(m_thread_wp.lock());
570b57cec5SDimitry Andric 
580b57cec5SDimitry Andric   if (thread_sp) {
590b57cec5SDimitry Andric     lldb::StateType ret_type = thread_sp->GetProcess()->GetPrivateState();
600b57cec5SDimitry Andric     if (ret_type == eStateRunning) {
610b57cec5SDimitry Andric       return true;
620b57cec5SDimitry Andric     } else if (ret_type == eStateStopped) {
630b57cec5SDimitry Andric       // This is a little tricky.  We want to count "run and stopped again
640b57cec5SDimitry Andric       // before you could ask this question as a "TRUE" answer to
650b57cec5SDimitry Andric       // HasTargetRunSinceMe.  But we don't want to include any running of the
660b57cec5SDimitry Andric       // target done for expressions.  So we track both resumes, and resumes
670b57cec5SDimitry Andric       // caused by expressions, and check if there are any resumes
680b57cec5SDimitry Andric       // NOT caused
690b57cec5SDimitry Andric       // by expressions.
700b57cec5SDimitry Andric 
710b57cec5SDimitry Andric       uint32_t curr_resume_id = thread_sp->GetProcess()->GetResumeID();
720b57cec5SDimitry Andric       uint32_t last_user_expression_id =
730b57cec5SDimitry Andric           thread_sp->GetProcess()->GetLastUserExpressionResumeID();
740b57cec5SDimitry Andric       if (curr_resume_id == m_resume_id) {
750b57cec5SDimitry Andric         return false;
760b57cec5SDimitry Andric       } else if (curr_resume_id > last_user_expression_id) {
770b57cec5SDimitry Andric         return true;
780b57cec5SDimitry Andric       }
790b57cec5SDimitry Andric     }
800b57cec5SDimitry Andric   }
810b57cec5SDimitry Andric   return false;
820b57cec5SDimitry Andric }
830b57cec5SDimitry Andric 
840b57cec5SDimitry Andric // StopInfoBreakpoint
850b57cec5SDimitry Andric 
860b57cec5SDimitry Andric namespace lldb_private {
870b57cec5SDimitry Andric class StopInfoBreakpoint : public StopInfo {
880b57cec5SDimitry Andric public:
890b57cec5SDimitry Andric   StopInfoBreakpoint(Thread &thread, break_id_t break_id)
900b57cec5SDimitry Andric       : StopInfo(thread, break_id), m_should_stop(false),
910b57cec5SDimitry Andric         m_should_stop_is_valid(false), m_should_perform_action(true),
920b57cec5SDimitry Andric         m_address(LLDB_INVALID_ADDRESS), m_break_id(LLDB_INVALID_BREAK_ID),
9381ad6265SDimitry Andric         m_was_all_internal(false), m_was_one_shot(false) {
940b57cec5SDimitry Andric     StoreBPInfo();
950b57cec5SDimitry Andric   }
960b57cec5SDimitry Andric 
970b57cec5SDimitry Andric   StopInfoBreakpoint(Thread &thread, break_id_t break_id, bool should_stop)
980b57cec5SDimitry Andric       : StopInfo(thread, break_id), m_should_stop(should_stop),
990b57cec5SDimitry Andric         m_should_stop_is_valid(true), m_should_perform_action(true),
1000b57cec5SDimitry Andric         m_address(LLDB_INVALID_ADDRESS), m_break_id(LLDB_INVALID_BREAK_ID),
10181ad6265SDimitry Andric         m_was_all_internal(false), m_was_one_shot(false) {
1020b57cec5SDimitry Andric     StoreBPInfo();
1030b57cec5SDimitry Andric   }
1040b57cec5SDimitry Andric 
1050b57cec5SDimitry Andric   ~StopInfoBreakpoint() override = default;
1060b57cec5SDimitry Andric 
1070b57cec5SDimitry Andric   void StoreBPInfo() {
1080b57cec5SDimitry Andric     ThreadSP thread_sp(m_thread_wp.lock());
1090b57cec5SDimitry Andric     if (thread_sp) {
1100b57cec5SDimitry Andric       BreakpointSiteSP bp_site_sp(
1110b57cec5SDimitry Andric           thread_sp->GetProcess()->GetBreakpointSiteList().FindByID(m_value));
1120b57cec5SDimitry Andric       if (bp_site_sp) {
1135f757f3fSDimitry Andric         uint32_t num_constituents = bp_site_sp->GetNumberOfConstituents();
1145f757f3fSDimitry Andric         if (num_constituents == 1) {
1155f757f3fSDimitry Andric           BreakpointLocationSP bp_loc_sp = bp_site_sp->GetConstituentAtIndex(0);
1160b57cec5SDimitry Andric           if (bp_loc_sp) {
11781ad6265SDimitry Andric             Breakpoint & bkpt = bp_loc_sp->GetBreakpoint();
11881ad6265SDimitry Andric             m_break_id = bkpt.GetID();
11981ad6265SDimitry Andric             m_was_one_shot = bkpt.IsOneShot();
12081ad6265SDimitry Andric             m_was_all_internal = bkpt.IsInternal();
12181ad6265SDimitry Andric           }
12281ad6265SDimitry Andric         } else {
12381ad6265SDimitry Andric           m_was_all_internal = true;
1245f757f3fSDimitry Andric           for (uint32_t i = 0; i < num_constituents; i++) {
1255f757f3fSDimitry Andric             if (!bp_site_sp->GetConstituentAtIndex(i)
1265f757f3fSDimitry Andric                      ->GetBreakpoint()
1275f757f3fSDimitry Andric                      .IsInternal()) {
12881ad6265SDimitry Andric               m_was_all_internal = false;
12981ad6265SDimitry Andric               break;
13081ad6265SDimitry Andric             }
1310b57cec5SDimitry Andric           }
1320b57cec5SDimitry Andric         }
1330b57cec5SDimitry Andric         m_address = bp_site_sp->GetLoadAddress();
1340b57cec5SDimitry Andric       }
1350b57cec5SDimitry Andric     }
1360b57cec5SDimitry Andric   }
1370b57cec5SDimitry Andric 
1380b57cec5SDimitry Andric   bool IsValidForOperatingSystemThread(Thread &thread) override {
1390b57cec5SDimitry Andric     ProcessSP process_sp(thread.GetProcess());
1400b57cec5SDimitry Andric     if (process_sp) {
1410b57cec5SDimitry Andric       BreakpointSiteSP bp_site_sp(
1420b57cec5SDimitry Andric           process_sp->GetBreakpointSiteList().FindByID(m_value));
1430b57cec5SDimitry Andric       if (bp_site_sp)
144fe6060f1SDimitry Andric         return bp_site_sp->ValidForThisThread(thread);
1450b57cec5SDimitry Andric     }
1460b57cec5SDimitry Andric     return false;
1470b57cec5SDimitry Andric   }
1480b57cec5SDimitry Andric 
1490b57cec5SDimitry Andric   StopReason GetStopReason() const override { return eStopReasonBreakpoint; }
1500b57cec5SDimitry Andric 
1510b57cec5SDimitry Andric   bool ShouldStopSynchronous(Event *event_ptr) override {
1520b57cec5SDimitry Andric     ThreadSP thread_sp(m_thread_wp.lock());
1530b57cec5SDimitry Andric     if (thread_sp) {
1540b57cec5SDimitry Andric       if (!m_should_stop_is_valid) {
1550b57cec5SDimitry Andric         // Only check once if we should stop at a breakpoint
1560b57cec5SDimitry Andric         BreakpointSiteSP bp_site_sp(
1570b57cec5SDimitry Andric             thread_sp->GetProcess()->GetBreakpointSiteList().FindByID(m_value));
1580b57cec5SDimitry Andric         if (bp_site_sp) {
1590b57cec5SDimitry Andric           ExecutionContext exe_ctx(thread_sp->GetStackFrameAtIndex(0));
1600b57cec5SDimitry Andric           StoppointCallbackContext context(event_ptr, exe_ctx, true);
1610b57cec5SDimitry Andric           bp_site_sp->BumpHitCounts();
1620b57cec5SDimitry Andric           m_should_stop = bp_site_sp->ShouldStop(&context);
1630b57cec5SDimitry Andric         } else {
16481ad6265SDimitry Andric           Log *log = GetLog(LLDBLog::Process);
1650b57cec5SDimitry Andric 
1669dba64beSDimitry Andric           LLDB_LOGF(log,
1679dba64beSDimitry Andric                     "Process::%s could not find breakpoint site id: %" PRId64
1689dba64beSDimitry Andric                     "...",
1690b57cec5SDimitry Andric                     __FUNCTION__, m_value);
1700b57cec5SDimitry Andric 
1710b57cec5SDimitry Andric           m_should_stop = true;
1720b57cec5SDimitry Andric         }
1730b57cec5SDimitry Andric         m_should_stop_is_valid = true;
1740b57cec5SDimitry Andric       }
1750b57cec5SDimitry Andric       return m_should_stop;
1760b57cec5SDimitry Andric     }
1770b57cec5SDimitry Andric     return false;
1780b57cec5SDimitry Andric   }
1790b57cec5SDimitry Andric 
1800b57cec5SDimitry Andric   bool DoShouldNotify(Event *event_ptr) override {
18181ad6265SDimitry Andric     return !m_was_all_internal;
1820b57cec5SDimitry Andric   }
1830b57cec5SDimitry Andric 
1840b57cec5SDimitry Andric   const char *GetDescription() override {
1850b57cec5SDimitry Andric     if (m_description.empty()) {
1860b57cec5SDimitry Andric       ThreadSP thread_sp(m_thread_wp.lock());
1870b57cec5SDimitry Andric       if (thread_sp) {
1880b57cec5SDimitry Andric         BreakpointSiteSP bp_site_sp(
1890b57cec5SDimitry Andric             thread_sp->GetProcess()->GetBreakpointSiteList().FindByID(m_value));
1900b57cec5SDimitry Andric         if (bp_site_sp) {
1910b57cec5SDimitry Andric           StreamString strm;
1920b57cec5SDimitry Andric           // If we have just hit an internal breakpoint, and it has a kind
1930b57cec5SDimitry Andric           // description, print that instead of the full breakpoint printing:
1940b57cec5SDimitry Andric           if (bp_site_sp->IsInternal()) {
1955f757f3fSDimitry Andric             size_t num_constituents = bp_site_sp->GetNumberOfConstituents();
1965f757f3fSDimitry Andric             for (size_t idx = 0; idx < num_constituents; idx++) {
1975f757f3fSDimitry Andric               const char *kind = bp_site_sp->GetConstituentAtIndex(idx)
1980b57cec5SDimitry Andric                                      ->GetBreakpoint()
1990b57cec5SDimitry Andric                                      .GetBreakpointKind();
2000b57cec5SDimitry Andric               if (kind != nullptr) {
2010b57cec5SDimitry Andric                 m_description.assign(kind);
2020b57cec5SDimitry Andric                 return kind;
2030b57cec5SDimitry Andric               }
2040b57cec5SDimitry Andric             }
2050b57cec5SDimitry Andric           }
2060b57cec5SDimitry Andric 
2070b57cec5SDimitry Andric           strm.Printf("breakpoint ");
2080b57cec5SDimitry Andric           bp_site_sp->GetDescription(&strm, eDescriptionLevelBrief);
2095ffd83dbSDimitry Andric           m_description = std::string(strm.GetString());
2100b57cec5SDimitry Andric         } else {
2110b57cec5SDimitry Andric           StreamString strm;
2120b57cec5SDimitry Andric           if (m_break_id != LLDB_INVALID_BREAK_ID) {
2130b57cec5SDimitry Andric             BreakpointSP break_sp =
2140b57cec5SDimitry Andric                 thread_sp->GetProcess()->GetTarget().GetBreakpointByID(
2150b57cec5SDimitry Andric                     m_break_id);
2160b57cec5SDimitry Andric             if (break_sp) {
2170b57cec5SDimitry Andric               if (break_sp->IsInternal()) {
2180b57cec5SDimitry Andric                 const char *kind = break_sp->GetBreakpointKind();
2190b57cec5SDimitry Andric                 if (kind)
2200b57cec5SDimitry Andric                   strm.Printf("internal %s breakpoint(%d).", kind, m_break_id);
2210b57cec5SDimitry Andric                 else
2220b57cec5SDimitry Andric                   strm.Printf("internal breakpoint(%d).", m_break_id);
2230b57cec5SDimitry Andric               } else {
2240b57cec5SDimitry Andric                 strm.Printf("breakpoint %d.", m_break_id);
2250b57cec5SDimitry Andric               }
2260b57cec5SDimitry Andric             } else {
2270b57cec5SDimitry Andric               if (m_was_one_shot)
2280b57cec5SDimitry Andric                 strm.Printf("one-shot breakpoint %d", m_break_id);
2290b57cec5SDimitry Andric               else
2300b57cec5SDimitry Andric                 strm.Printf("breakpoint %d which has been deleted.",
2310b57cec5SDimitry Andric                             m_break_id);
2320b57cec5SDimitry Andric             }
2330b57cec5SDimitry Andric           } else if (m_address == LLDB_INVALID_ADDRESS)
2340b57cec5SDimitry Andric             strm.Printf("breakpoint site %" PRIi64
2350b57cec5SDimitry Andric                         " which has been deleted - unknown address",
2360b57cec5SDimitry Andric                         m_value);
2370b57cec5SDimitry Andric           else
2380b57cec5SDimitry Andric             strm.Printf("breakpoint site %" PRIi64
2390b57cec5SDimitry Andric                         " which has been deleted - was at 0x%" PRIx64,
2400b57cec5SDimitry Andric                         m_value, m_address);
2410b57cec5SDimitry Andric 
2425ffd83dbSDimitry Andric           m_description = std::string(strm.GetString());
2430b57cec5SDimitry Andric         }
2440b57cec5SDimitry Andric       }
2450b57cec5SDimitry Andric     }
2460b57cec5SDimitry Andric     return m_description.c_str();
2470b57cec5SDimitry Andric   }
2480b57cec5SDimitry Andric 
2490b57cec5SDimitry Andric protected:
2500b57cec5SDimitry Andric   bool ShouldStop(Event *event_ptr) override {
2510b57cec5SDimitry Andric     // This just reports the work done by PerformAction or the synchronous
2520b57cec5SDimitry Andric     // stop. It should only ever get called after they have had a chance to
2530b57cec5SDimitry Andric     // run.
2540b57cec5SDimitry Andric     assert(m_should_stop_is_valid);
2550b57cec5SDimitry Andric     return m_should_stop;
2560b57cec5SDimitry Andric   }
2570b57cec5SDimitry Andric 
2580b57cec5SDimitry Andric   void PerformAction(Event *event_ptr) override {
2590b57cec5SDimitry Andric     if (!m_should_perform_action)
2600b57cec5SDimitry Andric       return;
2610b57cec5SDimitry Andric     m_should_perform_action = false;
26206c3fb27SDimitry Andric     bool all_stopping_locs_internal = true;
2630b57cec5SDimitry Andric 
2640b57cec5SDimitry Andric     ThreadSP thread_sp(m_thread_wp.lock());
2650b57cec5SDimitry Andric 
2660b57cec5SDimitry Andric     if (thread_sp) {
26781ad6265SDimitry Andric       Log *log = GetLog(LLDBLog::Breakpoints | LLDBLog::Step);
2680b57cec5SDimitry Andric 
2690b57cec5SDimitry Andric       if (!thread_sp->IsValid()) {
2700b57cec5SDimitry Andric         // This shouldn't ever happen, but just in case, don't do more harm.
2710b57cec5SDimitry Andric         if (log) {
2729dba64beSDimitry Andric           LLDB_LOGF(log, "PerformAction got called with an invalid thread.");
2730b57cec5SDimitry Andric         }
2740b57cec5SDimitry Andric         m_should_stop = true;
2750b57cec5SDimitry Andric         m_should_stop_is_valid = true;
2760b57cec5SDimitry Andric         return;
2770b57cec5SDimitry Andric       }
2780b57cec5SDimitry Andric 
2790b57cec5SDimitry Andric       BreakpointSiteSP bp_site_sp(
2800b57cec5SDimitry Andric           thread_sp->GetProcess()->GetBreakpointSiteList().FindByID(m_value));
2810b57cec5SDimitry Andric       std::unordered_set<break_id_t> precondition_breakpoints;
28281ad6265SDimitry Andric       // Breakpoints that fail their condition check are not considered to
28381ad6265SDimitry Andric       // have been hit.  If the only locations at this site have failed their
28481ad6265SDimitry Andric       // conditions, we should change the stop-info to none.  Otherwise, if we
28581ad6265SDimitry Andric       // hit another breakpoint on a different thread which does stop, users
28681ad6265SDimitry Andric       // will see a breakpont hit with a failed condition, which is wrong.
28781ad6265SDimitry Andric       // Use this variable to tell us if that is true.
28881ad6265SDimitry Andric       bool actually_hit_any_locations = false;
2890b57cec5SDimitry Andric       if (bp_site_sp) {
2905f757f3fSDimitry Andric         // Let's copy the constituents list out of the site and store them in a
2915f757f3fSDimitry Andric         // local list.  That way if one of the breakpoint actions changes the
2925f757f3fSDimitry Andric         // site, then we won't be operating on a bad list.
2930b57cec5SDimitry Andric         BreakpointLocationCollection site_locations;
2945f757f3fSDimitry Andric         size_t num_constituents =
2955f757f3fSDimitry Andric             bp_site_sp->CopyConstituentsList(site_locations);
2960b57cec5SDimitry Andric 
2975f757f3fSDimitry Andric         if (num_constituents == 0) {
2980b57cec5SDimitry Andric           m_should_stop = true;
29981ad6265SDimitry Andric           actually_hit_any_locations = true;  // We're going to stop, don't
30081ad6265SDimitry Andric                                               // change the stop info.
3010b57cec5SDimitry Andric         } else {
3020b57cec5SDimitry Andric           // We go through each location, and test first its precondition -
3030b57cec5SDimitry Andric           // this overrides everything.  Note, we only do this once per
3040b57cec5SDimitry Andric           // breakpoint - not once per location... Then check the condition.
3050b57cec5SDimitry Andric           // If the condition says to stop, then we run the callback for that
3060b57cec5SDimitry Andric           // location.  If that callback says to stop as well, then we set
3070b57cec5SDimitry Andric           // m_should_stop to true; we are going to stop. But we still want to
3080b57cec5SDimitry Andric           // give all the breakpoints whose conditions say we are going to stop
3090b57cec5SDimitry Andric           // a chance to run their callbacks. Of course if any callback
3100b57cec5SDimitry Andric           // restarts the target by putting "continue" in the callback, then
3110b57cec5SDimitry Andric           // we're going to restart, without running the rest of the callbacks.
3120b57cec5SDimitry Andric           // And in this case we will end up not stopping even if another
3130b57cec5SDimitry Andric           // location said we should stop. But that's better than not running
3140b57cec5SDimitry Andric           // all the callbacks.
3150b57cec5SDimitry Andric 
316fe6060f1SDimitry Andric           // There's one other complication here.  We may have run an async
317fe6060f1SDimitry Andric           // breakpoint callback that said we should stop.  We only want to
318fe6060f1SDimitry Andric           // override that if another breakpoint action says we shouldn't
319fe6060f1SDimitry Andric           // stop.  If nobody else has an opinion, then we should stop if the
320fe6060f1SDimitry Andric           // async callback says we should.  An example of this is the async
321fe6060f1SDimitry Andric           // shared library load notification breakpoint and the setting
322fe6060f1SDimitry Andric           // stop-on-sharedlibrary-events.
323fe6060f1SDimitry Andric           // We'll keep the async value in async_should_stop, and track whether
324fe6060f1SDimitry Andric           // anyone said we should NOT stop in actually_said_continue.
325fe6060f1SDimitry Andric           bool async_should_stop = false;
326fe6060f1SDimitry Andric           if (m_should_stop_is_valid)
327fe6060f1SDimitry Andric             async_should_stop = m_should_stop;
328fe6060f1SDimitry Andric           bool actually_said_continue = false;
329fe6060f1SDimitry Andric 
3300b57cec5SDimitry Andric           m_should_stop = false;
3310b57cec5SDimitry Andric 
3320b57cec5SDimitry Andric           // We don't select threads as we go through them testing breakpoint
3330b57cec5SDimitry Andric           // conditions and running commands. So we need to set the thread for
3340b57cec5SDimitry Andric           // expression evaluation here:
3350b57cec5SDimitry Andric           ThreadList::ExpressionExecutionThreadPusher thread_pusher(thread_sp);
3360b57cec5SDimitry Andric 
3370b57cec5SDimitry Andric           ExecutionContext exe_ctx(thread_sp->GetStackFrameAtIndex(0));
3380b57cec5SDimitry Andric           Process *process = exe_ctx.GetProcessPtr();
33906c3fb27SDimitry Andric           if (process->GetModIDRef().IsRunningExpression()) {
3400b57cec5SDimitry Andric             // If we are in the middle of evaluating an expression, don't run
3410b57cec5SDimitry Andric             // asynchronous breakpoint commands or expressions.  That could
3420b57cec5SDimitry Andric             // lead to infinite recursion if the command or condition re-calls
3430b57cec5SDimitry Andric             // the function with this breakpoint.
3440b57cec5SDimitry Andric             // TODO: We can keep a list of the breakpoints we've seen while
3450b57cec5SDimitry Andric             // running expressions in the nested
3460b57cec5SDimitry Andric             // PerformAction calls that can arise when the action runs a
3470b57cec5SDimitry Andric             // function that hits another breakpoint, and only stop running
3480b57cec5SDimitry Andric             // commands when we see the same breakpoint hit a second time.
3490b57cec5SDimitry Andric 
3500b57cec5SDimitry Andric             m_should_stop_is_valid = true;
3510b57cec5SDimitry Andric 
3520b57cec5SDimitry Andric             // It is possible that the user has a breakpoint at the same site
3530b57cec5SDimitry Andric             // as the completed plan had (e.g. user has a breakpoint
3540b57cec5SDimitry Andric             // on a module entry point, and `ThreadPlanCallFunction` ends
3550b57cec5SDimitry Andric             // also there). We can't find an internal breakpoint in the loop
3560b57cec5SDimitry Andric             // later because it was already removed on the plan completion.
3570b57cec5SDimitry Andric             // So check if the plan was completed, and stop if so.
3580b57cec5SDimitry Andric             if (thread_sp->CompletedPlanOverridesBreakpoint()) {
3590b57cec5SDimitry Andric               m_should_stop = true;
3600b57cec5SDimitry Andric               thread_sp->ResetStopInfo();
3610b57cec5SDimitry Andric               return;
3620b57cec5SDimitry Andric             }
3630b57cec5SDimitry Andric 
3649dba64beSDimitry Andric             LLDB_LOGF(log, "StopInfoBreakpoint::PerformAction - Hit a "
3650b57cec5SDimitry Andric                            "breakpoint while running an expression,"
3660b57cec5SDimitry Andric                            " not running commands to avoid recursion.");
3670b57cec5SDimitry Andric             bool ignoring_breakpoints =
3680b57cec5SDimitry Andric                 process->GetIgnoreBreakpointsInExpressions();
369bdd1243dSDimitry Andric             // Internal breakpoints should be allowed to do their job, we
370bdd1243dSDimitry Andric             // can make sure they don't do anything that would cause recursive
371bdd1243dSDimitry Andric             // command execution:
372bdd1243dSDimitry Andric             if (!m_was_all_internal) {
373bdd1243dSDimitry Andric               m_should_stop = !ignoring_breakpoints;
3749dba64beSDimitry Andric               LLDB_LOGF(log,
3759dba64beSDimitry Andric                         "StopInfoBreakpoint::PerformAction - in expression, "
3760b57cec5SDimitry Andric                         "continuing: %s.",
3770b57cec5SDimitry Andric                         m_should_stop ? "true" : "false");
37881ad6265SDimitry Andric               Debugger::ReportWarning(
379bdd1243dSDimitry Andric                   "hit breakpoint while running function, skipping commands "
380bdd1243dSDimitry Andric                   "and conditions to prevent recursion",
38181ad6265SDimitry Andric                     process->GetTarget().GetDebugger().GetID());
3820b57cec5SDimitry Andric               return;
3830b57cec5SDimitry Andric             }
384bdd1243dSDimitry Andric           }
3850b57cec5SDimitry Andric 
3860b57cec5SDimitry Andric           StoppointCallbackContext context(event_ptr, exe_ctx, false);
3870b57cec5SDimitry Andric 
3880b57cec5SDimitry Andric           // For safety's sake let's also grab an extra reference to the
3895f757f3fSDimitry Andric           // breakpoint constituents of the locations we're going to examine,
3905f757f3fSDimitry Andric           // since the locations are going to have to get back to their
3915f757f3fSDimitry Andric           // breakpoints, and the locations don't keep their constituents alive.
3925f757f3fSDimitry Andric           // I'm just sticking the BreakpointSP's in a vector since I'm only
3935f757f3fSDimitry Andric           // using it to locally increment their retain counts.
3940b57cec5SDimitry Andric 
3955f757f3fSDimitry Andric           std::vector<lldb::BreakpointSP> location_constituents;
3960b57cec5SDimitry Andric 
3975f757f3fSDimitry Andric           for (size_t j = 0; j < num_constituents; j++) {
3980b57cec5SDimitry Andric             BreakpointLocationSP loc(site_locations.GetByIndex(j));
3995f757f3fSDimitry Andric             location_constituents.push_back(
4005f757f3fSDimitry Andric                 loc->GetBreakpoint().shared_from_this());
4010b57cec5SDimitry Andric           }
4020b57cec5SDimitry Andric 
4035f757f3fSDimitry Andric           for (size_t j = 0; j < num_constituents; j++) {
4040b57cec5SDimitry Andric             lldb::BreakpointLocationSP bp_loc_sp = site_locations.GetByIndex(j);
4050b57cec5SDimitry Andric             StreamString loc_desc;
4060b57cec5SDimitry Andric             if (log) {
4070b57cec5SDimitry Andric               bp_loc_sp->GetDescription(&loc_desc, eDescriptionLevelBrief);
4080b57cec5SDimitry Andric             }
4090b57cec5SDimitry Andric             // If another action disabled this breakpoint or its location, then
4100b57cec5SDimitry Andric             // don't run the actions.
4110b57cec5SDimitry Andric             if (!bp_loc_sp->IsEnabled() ||
4120b57cec5SDimitry Andric                 !bp_loc_sp->GetBreakpoint().IsEnabled())
4130b57cec5SDimitry Andric               continue;
4140b57cec5SDimitry Andric 
4150b57cec5SDimitry Andric             // The breakpoint site may have many locations associated with it,
4160b57cec5SDimitry Andric             // not all of them valid for this thread.  Skip the ones that
4170b57cec5SDimitry Andric             // aren't:
418fe6060f1SDimitry Andric             if (!bp_loc_sp->ValidForThisThread(*thread_sp)) {
4190b57cec5SDimitry Andric               if (log) {
4209dba64beSDimitry Andric                 LLDB_LOGF(log,
4219dba64beSDimitry Andric                           "Breakpoint %s hit on thread 0x%llx but it was not "
4220b57cec5SDimitry Andric                           "for this thread, continuing.",
4239dba64beSDimitry Andric                           loc_desc.GetData(),
4249dba64beSDimitry Andric                           static_cast<unsigned long long>(thread_sp->GetID()));
4250b57cec5SDimitry Andric               }
4260b57cec5SDimitry Andric               continue;
4270b57cec5SDimitry Andric             }
4280b57cec5SDimitry Andric 
4290b57cec5SDimitry Andric             // First run the precondition, but since the precondition is per
4300b57cec5SDimitry Andric             // breakpoint, only run it once per breakpoint.
4310b57cec5SDimitry Andric             std::pair<std::unordered_set<break_id_t>::iterator, bool> result =
4320b57cec5SDimitry Andric                 precondition_breakpoints.insert(
4330b57cec5SDimitry Andric                     bp_loc_sp->GetBreakpoint().GetID());
4340b57cec5SDimitry Andric             if (!result.second)
4350b57cec5SDimitry Andric               continue;
4360b57cec5SDimitry Andric 
4370b57cec5SDimitry Andric             bool precondition_result =
4380b57cec5SDimitry Andric                 bp_loc_sp->GetBreakpoint().EvaluatePrecondition(context);
439fe6060f1SDimitry Andric             if (!precondition_result) {
440fe6060f1SDimitry Andric               actually_said_continue = true;
4410b57cec5SDimitry Andric               continue;
442fe6060f1SDimitry Andric             }
4430b57cec5SDimitry Andric             // Next run the condition for the breakpoint.  If that says we
4440b57cec5SDimitry Andric             // should stop, then we'll run the callback for the breakpoint.  If
4450b57cec5SDimitry Andric             // the callback says we shouldn't stop that will win.
4460b57cec5SDimitry Andric 
44781ad6265SDimitry Andric             if (bp_loc_sp->GetConditionText() == nullptr)
44881ad6265SDimitry Andric               actually_hit_any_locations = true;
44981ad6265SDimitry Andric             else {
4500b57cec5SDimitry Andric               Status condition_error;
4510b57cec5SDimitry Andric               bool condition_says_stop =
4520b57cec5SDimitry Andric                   bp_loc_sp->ConditionSaysStop(exe_ctx, condition_error);
4530b57cec5SDimitry Andric 
4540b57cec5SDimitry Andric               if (!condition_error.Success()) {
45581ad6265SDimitry Andric                 // If the condition fails to evaluate, we are going to stop
45681ad6265SDimitry Andric                 // at it, so the location was hit.
45781ad6265SDimitry Andric                 actually_hit_any_locations = true;
4580b57cec5SDimitry Andric                 const char *err_str =
45981ad6265SDimitry Andric                     condition_error.AsCString("<unknown error>");
4609dba64beSDimitry Andric                 LLDB_LOGF(log, "Error evaluating condition: \"%s\"\n", err_str);
4610b57cec5SDimitry Andric 
46281ad6265SDimitry Andric                 StreamString strm;
46381ad6265SDimitry Andric                 strm << "stopped due to an error evaluating condition of "
46481ad6265SDimitry Andric                         "breakpoint ";
46581ad6265SDimitry Andric                 bp_loc_sp->GetDescription(&strm, eDescriptionLevelBrief);
46681ad6265SDimitry Andric                 strm << ": \"" << bp_loc_sp->GetConditionText() << "\"\n";
46781ad6265SDimitry Andric                 strm << err_str;
46881ad6265SDimitry Andric 
46981ad6265SDimitry Andric                 Debugger::ReportError(
47081ad6265SDimitry Andric                     strm.GetString().str(),
47181ad6265SDimitry Andric                     exe_ctx.GetTargetRef().GetDebugger().GetID());
4720b57cec5SDimitry Andric               } else {
4739dba64beSDimitry Andric                 LLDB_LOGF(log,
4749dba64beSDimitry Andric                           "Condition evaluated for breakpoint %s on thread "
4755ffd83dbSDimitry Andric                           "0x%llx condition_says_stop: %i.",
4760b57cec5SDimitry Andric                           loc_desc.GetData(),
4779dba64beSDimitry Andric                           static_cast<unsigned long long>(thread_sp->GetID()),
4780b57cec5SDimitry Andric                           condition_says_stop);
47981ad6265SDimitry Andric                 if (condition_says_stop)
48081ad6265SDimitry Andric                   actually_hit_any_locations = true;
48181ad6265SDimitry Andric                 else {
4820b57cec5SDimitry Andric                   // We don't want to increment the hit count of breakpoints if
4830b57cec5SDimitry Andric                   // the condition fails. We've already bumped it by the time
4840b57cec5SDimitry Andric                   // we get here, so undo the bump:
4850b57cec5SDimitry Andric                   bp_loc_sp->UndoBumpHitCount();
486fe6060f1SDimitry Andric                   actually_said_continue = true;
4870b57cec5SDimitry Andric                   continue;
4880b57cec5SDimitry Andric                 }
4890b57cec5SDimitry Andric               }
4900b57cec5SDimitry Andric             }
4910b57cec5SDimitry Andric 
492fe6060f1SDimitry Andric             // We've done all the checks whose failure means "we consider lldb
493fe6060f1SDimitry Andric             // not to have hit the breakpoint".  Now we're going to check for
494fe6060f1SDimitry Andric             // conditions that might continue after hitting.  Start with the
495fe6060f1SDimitry Andric             // ignore count:
496fe6060f1SDimitry Andric             if (!bp_loc_sp->IgnoreCountShouldStop()) {
497fe6060f1SDimitry Andric               actually_said_continue = true;
498fe6060f1SDimitry Andric               continue;
499fe6060f1SDimitry Andric             }
500fe6060f1SDimitry Andric 
5010b57cec5SDimitry Andric             // Check the auto-continue bit on the location, do this before the
5020b57cec5SDimitry Andric             // callback since it may change this, but that would be for the
5030b57cec5SDimitry Andric             // NEXT hit.  Note, you might think you could check auto-continue
5040b57cec5SDimitry Andric             // before the condition, and not evaluate the condition if it says
5050b57cec5SDimitry Andric             // to continue.  But failing the condition means the breakpoint was
5060b57cec5SDimitry Andric             // effectively NOT HIT.  So these two states are different.
5070b57cec5SDimitry Andric             bool auto_continue_says_stop = true;
5080b57cec5SDimitry Andric             if (bp_loc_sp->IsAutoContinue())
5090b57cec5SDimitry Andric             {
5109dba64beSDimitry Andric               LLDB_LOGF(log,
5119dba64beSDimitry Andric                         "Continuing breakpoint %s as AutoContinue was set.",
5120b57cec5SDimitry Andric                         loc_desc.GetData());
5130b57cec5SDimitry Andric               // We want this stop reported, so you will know we auto-continued
5140b57cec5SDimitry Andric               // but only for external breakpoints:
51506c3fb27SDimitry Andric               if (!bp_loc_sp->GetBreakpoint().IsInternal())
5160b57cec5SDimitry Andric                 thread_sp->SetShouldReportStop(eVoteYes);
5170b57cec5SDimitry Andric               auto_continue_says_stop = false;
5180b57cec5SDimitry Andric             }
5190b57cec5SDimitry Andric 
5200b57cec5SDimitry Andric             bool callback_says_stop = true;
5210b57cec5SDimitry Andric 
5220b57cec5SDimitry Andric             // FIXME: For now the callbacks have to run in async mode - the
5230b57cec5SDimitry Andric             // first time we restart we need
5240b57cec5SDimitry Andric             // to get out of there.  So set it here.
5250b57cec5SDimitry Andric             // When we figure out how to nest breakpoint hits then this will
5260b57cec5SDimitry Andric             // change.
5270b57cec5SDimitry Andric 
528fe6060f1SDimitry Andric             // Don't run async callbacks in PerformAction.  They have already
529fe6060f1SDimitry Andric             // been taken into account with async_should_stop.
530fe6060f1SDimitry Andric             if (!bp_loc_sp->IsCallbackSynchronous()) {
5310b57cec5SDimitry Andric               Debugger &debugger = thread_sp->CalculateTarget()->GetDebugger();
5320b57cec5SDimitry Andric               bool old_async = debugger.GetAsyncExecution();
5330b57cec5SDimitry Andric               debugger.SetAsyncExecution(true);
5340b57cec5SDimitry Andric 
5350b57cec5SDimitry Andric               callback_says_stop = bp_loc_sp->InvokeCallback(&context);
5360b57cec5SDimitry Andric 
5370b57cec5SDimitry Andric               debugger.SetAsyncExecution(old_async);
5380b57cec5SDimitry Andric 
5390b57cec5SDimitry Andric               if (callback_says_stop && auto_continue_says_stop)
5400b57cec5SDimitry Andric                 m_should_stop = true;
541fe6060f1SDimitry Andric               else
542fe6060f1SDimitry Andric                 actually_said_continue = true;
543fe6060f1SDimitry Andric             }
5440b57cec5SDimitry Andric 
54506c3fb27SDimitry Andric             if (m_should_stop && !bp_loc_sp->GetBreakpoint().IsInternal())
54606c3fb27SDimitry Andric               all_stopping_locs_internal = false;
54706c3fb27SDimitry Andric 
5480b57cec5SDimitry Andric             // If we are going to stop for this breakpoint, then remove the
5490b57cec5SDimitry Andric             // breakpoint.
5500b57cec5SDimitry Andric             if (callback_says_stop && bp_loc_sp &&
5510b57cec5SDimitry Andric                 bp_loc_sp->GetBreakpoint().IsOneShot()) {
5520b57cec5SDimitry Andric               thread_sp->GetProcess()->GetTarget().RemoveBreakpointByID(
5530b57cec5SDimitry Andric                   bp_loc_sp->GetBreakpoint().GetID());
5540b57cec5SDimitry Andric             }
5550b57cec5SDimitry Andric             // Also make sure that the callback hasn't continued the target. If
5560b57cec5SDimitry Andric             // it did, when we'll set m_should_start to false and get out of
5570b57cec5SDimitry Andric             // here.
5580b57cec5SDimitry Andric             if (HasTargetRunSinceMe()) {
5590b57cec5SDimitry Andric               m_should_stop = false;
560fe6060f1SDimitry Andric               actually_said_continue = true;
5610b57cec5SDimitry Andric               break;
5620b57cec5SDimitry Andric             }
5630b57cec5SDimitry Andric           }
564fe6060f1SDimitry Andric           // At this point if nobody actually told us to continue, we should
565fe6060f1SDimitry Andric           // give the async breakpoint callback a chance to weigh in:
566fe6060f1SDimitry Andric           if (!actually_said_continue && !m_should_stop) {
567fe6060f1SDimitry Andric             m_should_stop = async_should_stop;
568fe6060f1SDimitry Andric           }
5690b57cec5SDimitry Andric         }
5700b57cec5SDimitry Andric         // We've figured out what this stop wants to do, so mark it as valid so
5710b57cec5SDimitry Andric         // we don't compute it again.
5720b57cec5SDimitry Andric         m_should_stop_is_valid = true;
5730b57cec5SDimitry Andric       } else {
5740b57cec5SDimitry Andric         m_should_stop = true;
5750b57cec5SDimitry Andric         m_should_stop_is_valid = true;
57681ad6265SDimitry Andric         actually_hit_any_locations = true;
57781ad6265SDimitry Andric         Log *log_process(GetLog(LLDBLog::Process));
5780b57cec5SDimitry Andric 
5799dba64beSDimitry Andric         LLDB_LOGF(log_process,
5809dba64beSDimitry Andric                   "Process::%s could not find breakpoint site id: %" PRId64
5819dba64beSDimitry Andric                   "...",
5820b57cec5SDimitry Andric                   __FUNCTION__, m_value);
5830b57cec5SDimitry Andric       }
5840b57cec5SDimitry Andric 
58506c3fb27SDimitry Andric       if ((!m_should_stop || all_stopping_locs_internal) &&
5860b57cec5SDimitry Andric           thread_sp->CompletedPlanOverridesBreakpoint()) {
5870b57cec5SDimitry Andric 
5880b57cec5SDimitry Andric         // Override should_stop decision when we have completed step plan
5890b57cec5SDimitry Andric         // additionally to the breakpoint
5900b57cec5SDimitry Andric         m_should_stop = true;
5910b57cec5SDimitry Andric 
5929dba64beSDimitry Andric         // We know we're stopping for a completed plan and we don't want to
5939dba64beSDimitry Andric         // show the breakpoint stop, so compute the public stop info immediately
5949dba64beSDimitry Andric         // here.
5959dba64beSDimitry Andric         thread_sp->CalculatePublicStopInfo();
59681ad6265SDimitry Andric       } else if (!actually_hit_any_locations) {
59781ad6265SDimitry Andric         // In the end, we didn't actually have any locations that passed their
59881ad6265SDimitry Andric         // "was I hit" checks.  So say we aren't stopped.
59981ad6265SDimitry Andric         GetThread()->ResetStopInfo();
60081ad6265SDimitry Andric         LLDB_LOGF(log, "Process::%s all locations failed condition checks.",
60181ad6265SDimitry Andric           __FUNCTION__);
6020b57cec5SDimitry Andric       }
6030b57cec5SDimitry Andric 
6049dba64beSDimitry Andric       LLDB_LOGF(log,
6059dba64beSDimitry Andric                 "Process::%s returning from action with m_should_stop: %d.",
6060b57cec5SDimitry Andric                 __FUNCTION__, m_should_stop);
6070b57cec5SDimitry Andric     }
6080b57cec5SDimitry Andric   }
6090b57cec5SDimitry Andric 
6100b57cec5SDimitry Andric private:
6110b57cec5SDimitry Andric   bool m_should_stop;
6120b57cec5SDimitry Andric   bool m_should_stop_is_valid;
6130b57cec5SDimitry Andric   bool m_should_perform_action; // Since we are trying to preserve the "state"
6140b57cec5SDimitry Andric                                 // of the system even if we run functions
6150b57cec5SDimitry Andric   // etc. behind the users backs, we need to make sure we only REALLY perform
6160b57cec5SDimitry Andric   // the action once.
6170b57cec5SDimitry Andric   lldb::addr_t m_address; // We use this to capture the breakpoint site address
6180b57cec5SDimitry Andric                           // when we create the StopInfo,
6190b57cec5SDimitry Andric   // in case somebody deletes it between the time the StopInfo is made and the
6200b57cec5SDimitry Andric   // description is asked for.
6210b57cec5SDimitry Andric   lldb::break_id_t m_break_id;
62281ad6265SDimitry Andric   bool m_was_all_internal;
6230b57cec5SDimitry Andric   bool m_was_one_shot;
6240b57cec5SDimitry Andric };
6250b57cec5SDimitry Andric 
6260b57cec5SDimitry Andric // StopInfoWatchpoint
6270b57cec5SDimitry Andric 
6280b57cec5SDimitry Andric class StopInfoWatchpoint : public StopInfo {
6290b57cec5SDimitry Andric public:
6300b57cec5SDimitry Andric   // Make sure watchpoint is properly disabled and subsequently enabled while
6310b57cec5SDimitry Andric   // performing watchpoint actions.
6320b57cec5SDimitry Andric   class WatchpointSentry {
6330b57cec5SDimitry Andric   public:
6340b57cec5SDimitry Andric     WatchpointSentry(ProcessSP p_sp, WatchpointSP w_sp) : process_sp(p_sp),
6350b57cec5SDimitry Andric                      watchpoint_sp(w_sp) {
6360b57cec5SDimitry Andric       if (process_sp && watchpoint_sp) {
6370b57cec5SDimitry Andric         const bool notify = false;
6380b57cec5SDimitry Andric         watchpoint_sp->TurnOnEphemeralMode();
6395f757f3fSDimitry Andric         process_sp->DisableWatchpoint(watchpoint_sp, notify);
6400b57cec5SDimitry Andric         process_sp->AddPreResumeAction(SentryPreResumeAction, this);
6410b57cec5SDimitry Andric       }
6420b57cec5SDimitry Andric     }
6430b57cec5SDimitry Andric 
6440b57cec5SDimitry Andric     void DoReenable() {
6450b57cec5SDimitry Andric       if (process_sp && watchpoint_sp) {
6460b57cec5SDimitry Andric         bool was_disabled = watchpoint_sp->IsDisabledDuringEphemeralMode();
6470b57cec5SDimitry Andric         watchpoint_sp->TurnOffEphemeralMode();
6480b57cec5SDimitry Andric         const bool notify = false;
6490b57cec5SDimitry Andric         if (was_disabled) {
6505f757f3fSDimitry Andric           process_sp->DisableWatchpoint(watchpoint_sp, notify);
6510b57cec5SDimitry Andric         } else {
6525f757f3fSDimitry Andric           process_sp->EnableWatchpoint(watchpoint_sp, notify);
6530b57cec5SDimitry Andric         }
6540b57cec5SDimitry Andric       }
6550b57cec5SDimitry Andric     }
6560b57cec5SDimitry Andric 
6570b57cec5SDimitry Andric     ~WatchpointSentry() {
6580b57cec5SDimitry Andric         DoReenable();
6590b57cec5SDimitry Andric         if (process_sp)
6600b57cec5SDimitry Andric             process_sp->ClearPreResumeAction(SentryPreResumeAction, this);
6610b57cec5SDimitry Andric     }
6620b57cec5SDimitry Andric 
6630b57cec5SDimitry Andric     static bool SentryPreResumeAction(void *sentry_void) {
6640b57cec5SDimitry Andric         WatchpointSentry *sentry = (WatchpointSentry *) sentry_void;
6650b57cec5SDimitry Andric         sentry->DoReenable();
6660b57cec5SDimitry Andric         return true;
6670b57cec5SDimitry Andric     }
6680b57cec5SDimitry Andric 
6690b57cec5SDimitry Andric   private:
6700b57cec5SDimitry Andric     ProcessSP process_sp;
6710b57cec5SDimitry Andric     WatchpointSP watchpoint_sp;
6720b57cec5SDimitry Andric   };
6730b57cec5SDimitry Andric 
67406c3fb27SDimitry Andric   StopInfoWatchpoint(Thread &thread, break_id_t watch_id, bool silently_skip_wp)
67506c3fb27SDimitry Andric       : StopInfo(thread, watch_id), m_silently_skip_wp(silently_skip_wp) {}
6760b57cec5SDimitry Andric 
6770b57cec5SDimitry Andric   ~StopInfoWatchpoint() override = default;
6780b57cec5SDimitry Andric 
6790b57cec5SDimitry Andric   StopReason GetStopReason() const override { return eStopReasonWatchpoint; }
6800b57cec5SDimitry Andric 
6810b57cec5SDimitry Andric   const char *GetDescription() override {
6820b57cec5SDimitry Andric     if (m_description.empty()) {
6830b57cec5SDimitry Andric       StreamString strm;
6840b57cec5SDimitry Andric       strm.Printf("watchpoint %" PRIi64, m_value);
6855ffd83dbSDimitry Andric       m_description = std::string(strm.GetString());
6860b57cec5SDimitry Andric     }
6870b57cec5SDimitry Andric     return m_description.c_str();
6880b57cec5SDimitry Andric   }
6890b57cec5SDimitry Andric 
6900b57cec5SDimitry Andric protected:
691bdd1243dSDimitry Andric   using StopInfoWatchpointSP = std::shared_ptr<StopInfoWatchpoint>;
692bdd1243dSDimitry Andric   // This plan is used to orchestrate stepping over the watchpoint for
693bdd1243dSDimitry Andric   // architectures (e.g. ARM) that report the watch before running the watched
694bdd1243dSDimitry Andric   // access.  This is the sort of job you have to defer to the thread plans,
695bdd1243dSDimitry Andric   // if you try to do it directly in the stop info and there are other threads
696bdd1243dSDimitry Andric   // that needed to process this stop you will have yanked control away from
697bdd1243dSDimitry Andric   // them and they won't behave correctly.
698bdd1243dSDimitry Andric   class ThreadPlanStepOverWatchpoint : public ThreadPlanStepInstruction {
699bdd1243dSDimitry Andric   public:
700bdd1243dSDimitry Andric     ThreadPlanStepOverWatchpoint(Thread &thread,
701bdd1243dSDimitry Andric                                  StopInfoWatchpointSP stop_info_sp,
702bdd1243dSDimitry Andric                                  WatchpointSP watch_sp)
703bdd1243dSDimitry Andric         : ThreadPlanStepInstruction(thread, false, true, eVoteNoOpinion,
704bdd1243dSDimitry Andric                                     eVoteNoOpinion),
705bdd1243dSDimitry Andric           m_stop_info_sp(stop_info_sp), m_watch_sp(watch_sp) {
706bdd1243dSDimitry Andric       assert(watch_sp);
707bdd1243dSDimitry Andric     }
708bdd1243dSDimitry Andric 
709bdd1243dSDimitry Andric     bool DoWillResume(lldb::StateType resume_state,
710bdd1243dSDimitry Andric                       bool current_plan) override {
711bdd1243dSDimitry Andric       if (resume_state == eStateSuspended)
712bdd1243dSDimitry Andric         return true;
713bdd1243dSDimitry Andric 
714bdd1243dSDimitry Andric       if (!m_did_disable_wp) {
7155f757f3fSDimitry Andric         GetThread().GetProcess()->DisableWatchpoint(m_watch_sp, false);
716bdd1243dSDimitry Andric         m_did_disable_wp = true;
717bdd1243dSDimitry Andric       }
718bdd1243dSDimitry Andric       return true;
719bdd1243dSDimitry Andric     }
720bdd1243dSDimitry Andric 
721bdd1243dSDimitry Andric     bool DoPlanExplainsStop(Event *event_ptr) override {
722bdd1243dSDimitry Andric       if (ThreadPlanStepInstruction::DoPlanExplainsStop(event_ptr))
723bdd1243dSDimitry Andric         return true;
724bdd1243dSDimitry Andric       StopInfoSP stop_info_sp = GetThread().GetPrivateStopInfo();
725bdd1243dSDimitry Andric       // lldb-server resets the stop info for threads that didn't get to run,
726bdd1243dSDimitry Andric       // so we might have not gotten to run, but still have a watchpoint stop
727bdd1243dSDimitry Andric       // reason, in which case this will indeed be for us.
728bdd1243dSDimitry Andric       if (stop_info_sp
729bdd1243dSDimitry Andric           && stop_info_sp->GetStopReason() == eStopReasonWatchpoint)
730bdd1243dSDimitry Andric         return true;
731bdd1243dSDimitry Andric       return false;
732bdd1243dSDimitry Andric     }
733bdd1243dSDimitry Andric 
734bdd1243dSDimitry Andric     void DidPop() override {
735bdd1243dSDimitry Andric       // Don't artifically keep the watchpoint alive.
736bdd1243dSDimitry Andric       m_watch_sp.reset();
737bdd1243dSDimitry Andric     }
738bdd1243dSDimitry Andric 
739bdd1243dSDimitry Andric     bool ShouldStop(Event *event_ptr) override {
740bdd1243dSDimitry Andric       bool should_stop = ThreadPlanStepInstruction::ShouldStop(event_ptr);
741bdd1243dSDimitry Andric       bool plan_done = MischiefManaged();
742bdd1243dSDimitry Andric       if (plan_done) {
743bdd1243dSDimitry Andric         m_stop_info_sp->SetStepOverPlanComplete();
744bdd1243dSDimitry Andric         GetThread().SetStopInfo(m_stop_info_sp);
745bdd1243dSDimitry Andric         ResetWatchpoint();
746bdd1243dSDimitry Andric       }
747bdd1243dSDimitry Andric       return should_stop;
748bdd1243dSDimitry Andric     }
749bdd1243dSDimitry Andric 
750bdd1243dSDimitry Andric     bool ShouldRunBeforePublicStop() override {
751bdd1243dSDimitry Andric         return true;
752bdd1243dSDimitry Andric     }
753bdd1243dSDimitry Andric 
754bdd1243dSDimitry Andric   protected:
755bdd1243dSDimitry Andric     void ResetWatchpoint() {
756bdd1243dSDimitry Andric       if (!m_did_disable_wp)
757bdd1243dSDimitry Andric         return;
758bdd1243dSDimitry Andric       m_did_disable_wp = true;
7595f757f3fSDimitry Andric       GetThread().GetProcess()->EnableWatchpoint(m_watch_sp, true);
760bdd1243dSDimitry Andric     }
761bdd1243dSDimitry Andric 
762bdd1243dSDimitry Andric   private:
763bdd1243dSDimitry Andric     StopInfoWatchpointSP m_stop_info_sp;
764bdd1243dSDimitry Andric     WatchpointSP m_watch_sp;
765bdd1243dSDimitry Andric     bool m_did_disable_wp = false;
766bdd1243dSDimitry Andric   };
767bdd1243dSDimitry Andric 
7680b57cec5SDimitry Andric   bool ShouldStopSynchronous(Event *event_ptr) override {
769bdd1243dSDimitry Andric     // If we are running our step-over the watchpoint plan, stop if it's done
770bdd1243dSDimitry Andric     // and continue if it's not:
7710b57cec5SDimitry Andric     if (m_should_stop_is_valid)
7720b57cec5SDimitry Andric       return m_should_stop;
7730b57cec5SDimitry Andric 
774bdd1243dSDimitry Andric     // If we are running our step over plan, then stop here and let the regular
775bdd1243dSDimitry Andric     // ShouldStop figure out what we should do:  Otherwise, give our plan
776bdd1243dSDimitry Andric     // more time to get run:
777bdd1243dSDimitry Andric     if (m_using_step_over_plan)
778bdd1243dSDimitry Andric       return m_step_over_plan_complete;
779bdd1243dSDimitry Andric 
78081ad6265SDimitry Andric     Log *log = GetLog(LLDBLog::Process);
781bdd1243dSDimitry Andric     ThreadSP thread_sp(m_thread_wp.lock());
782bdd1243dSDimitry Andric     assert(thread_sp);
783bdd1243dSDimitry Andric 
784bdd1243dSDimitry Andric     if (thread_sp->GetTemporaryResumeState() == eStateSuspended) {
785bdd1243dSDimitry Andric       // This is the second firing of a watchpoint so don't process it again.
786bdd1243dSDimitry Andric       LLDB_LOG(log, "We didn't run but stopped with a StopInfoWatchpoint, we "
787bdd1243dSDimitry Andric                "have already handled this one, don't do it again.");
788bdd1243dSDimitry Andric       m_should_stop = false;
789bdd1243dSDimitry Andric       m_should_stop_is_valid = true;
790bdd1243dSDimitry Andric       return m_should_stop;
791bdd1243dSDimitry Andric     }
792bdd1243dSDimitry Andric 
793bdd1243dSDimitry Andric     WatchpointSP wp_sp(
794bdd1243dSDimitry Andric         thread_sp->CalculateTarget()->GetWatchpointList().FindByID(GetValue()));
795bdd1243dSDimitry Andric     // If we can no longer find the watchpoint, we just have to stop:
796bdd1243dSDimitry Andric     if (!wp_sp) {
7970b57cec5SDimitry Andric 
7989dba64beSDimitry Andric       LLDB_LOGF(log,
7990b57cec5SDimitry Andric                 "Process::%s could not find watchpoint location id: %" PRId64
8000b57cec5SDimitry Andric                 "...",
8010b57cec5SDimitry Andric                 __FUNCTION__, GetValue());
8020b57cec5SDimitry Andric 
8030b57cec5SDimitry Andric       m_should_stop = true;
8040b57cec5SDimitry Andric       m_should_stop_is_valid = true;
805bdd1243dSDimitry Andric       return true;
806bdd1243dSDimitry Andric     }
807bdd1243dSDimitry Andric 
808bdd1243dSDimitry Andric     ExecutionContext exe_ctx(thread_sp->GetStackFrameAtIndex(0));
809bdd1243dSDimitry Andric     StoppointCallbackContext context(event_ptr, exe_ctx, true);
810bdd1243dSDimitry Andric     m_should_stop = wp_sp->ShouldStop(&context);
811bdd1243dSDimitry Andric     if (!m_should_stop) {
812bdd1243dSDimitry Andric       // This won't happen at present because we only allow one watchpoint per
813bdd1243dSDimitry Andric       // watched range.  So we won't stop at a watched address with a disabled
814bdd1243dSDimitry Andric       // watchpoint.  If we start allowing overlapping watchpoints, then we
815bdd1243dSDimitry Andric       // will have to make watchpoints be real "WatchpointSite" and delegate to
816bdd1243dSDimitry Andric       // all the watchpoints sharing the site.  In that case, the code below
817bdd1243dSDimitry Andric       // would be the right thing to do.
818bdd1243dSDimitry Andric       m_should_stop_is_valid = true;
819bdd1243dSDimitry Andric       return m_should_stop;
820bdd1243dSDimitry Andric     }
821bdd1243dSDimitry Andric     // If this is a system where we need to execute the watchpoint by hand
822bdd1243dSDimitry Andric     // after the hit, queue a thread plan to do that, and then say not to stop.
823bdd1243dSDimitry Andric     // Otherwise, let the async action figure out whether the watchpoint should
824bdd1243dSDimitry Andric     // stop
825bdd1243dSDimitry Andric 
826bdd1243dSDimitry Andric     ProcessSP process_sp = exe_ctx.GetProcessSP();
82706c3fb27SDimitry Andric     bool wp_triggers_after = process_sp->GetWatchpointReportedAfter();
828bdd1243dSDimitry Andric 
829bdd1243dSDimitry Andric     if (!wp_triggers_after) {
830bdd1243dSDimitry Andric       // We have to step over the watchpoint before we know what to do:
831bdd1243dSDimitry Andric       StopInfoWatchpointSP me_as_siwp_sp
832bdd1243dSDimitry Andric           = std::static_pointer_cast<StopInfoWatchpoint>(shared_from_this());
833bdd1243dSDimitry Andric       ThreadPlanSP step_over_wp_sp(new ThreadPlanStepOverWatchpoint(
834bdd1243dSDimitry Andric           *(thread_sp.get()), me_as_siwp_sp, wp_sp));
83506c3fb27SDimitry Andric       // When this plan is done we want to stop, so set this as a Controlling
83606c3fb27SDimitry Andric       // plan.
83706c3fb27SDimitry Andric       step_over_wp_sp->SetIsControllingPlan(true);
83806c3fb27SDimitry Andric       step_over_wp_sp->SetOkayToDiscard(false);
83906c3fb27SDimitry Andric 
840bdd1243dSDimitry Andric       Status error;
841bdd1243dSDimitry Andric       error = thread_sp->QueueThreadPlan(step_over_wp_sp, false);
842bdd1243dSDimitry Andric       // If we couldn't push the thread plan, just stop here:
843bdd1243dSDimitry Andric       if (!error.Success()) {
844bdd1243dSDimitry Andric         LLDB_LOGF(log, "Could not push our step over watchpoint plan: %s",
845bdd1243dSDimitry Andric             error.AsCString());
846bdd1243dSDimitry Andric 
847bdd1243dSDimitry Andric         m_should_stop = true;
848bdd1243dSDimitry Andric         m_should_stop_is_valid = true;
849bdd1243dSDimitry Andric         return true;
850bdd1243dSDimitry Andric       } else {
851bdd1243dSDimitry Andric       // Otherwise, don't set m_should_stop, we don't know that yet.  Just
852bdd1243dSDimitry Andric       // say we should continue, and tell the thread we really should do so:
853bdd1243dSDimitry Andric         thread_sp->SetShouldRunBeforePublicStop(true);
854bdd1243dSDimitry Andric         m_using_step_over_plan = true;
855bdd1243dSDimitry Andric         return false;
856bdd1243dSDimitry Andric       }
857bdd1243dSDimitry Andric     } else {
858bdd1243dSDimitry Andric       // We didn't have to do anything special
859bdd1243dSDimitry Andric       m_should_stop_is_valid = true;
860bdd1243dSDimitry Andric       return m_should_stop;
861bdd1243dSDimitry Andric     }
862bdd1243dSDimitry Andric 
8630b57cec5SDimitry Andric     return m_should_stop;
8640b57cec5SDimitry Andric   }
8650b57cec5SDimitry Andric 
8660b57cec5SDimitry Andric   bool ShouldStop(Event *event_ptr) override {
8670b57cec5SDimitry Andric     // This just reports the work done by PerformAction or the synchronous
8680b57cec5SDimitry Andric     // stop. It should only ever get called after they have had a chance to
8690b57cec5SDimitry Andric     // run.
8700b57cec5SDimitry Andric     assert(m_should_stop_is_valid);
8710b57cec5SDimitry Andric     return m_should_stop;
8720b57cec5SDimitry Andric   }
8730b57cec5SDimitry Andric 
8740b57cec5SDimitry Andric   void PerformAction(Event *event_ptr) override {
87581ad6265SDimitry Andric     Log *log = GetLog(LLDBLog::Watchpoints);
8760b57cec5SDimitry Andric     // We're going to calculate if we should stop or not in some way during the
8770b57cec5SDimitry Andric     // course of this code.  Also by default we're going to stop, so set that
8780b57cec5SDimitry Andric     // here.
8790b57cec5SDimitry Andric     m_should_stop = true;
8800b57cec5SDimitry Andric 
8810b57cec5SDimitry Andric 
8820b57cec5SDimitry Andric     ThreadSP thread_sp(m_thread_wp.lock());
8830b57cec5SDimitry Andric     if (thread_sp) {
8840b57cec5SDimitry Andric 
8850b57cec5SDimitry Andric       WatchpointSP wp_sp(
8860b57cec5SDimitry Andric           thread_sp->CalculateTarget()->GetWatchpointList().FindByID(
8870b57cec5SDimitry Andric               GetValue()));
8880b57cec5SDimitry Andric       if (wp_sp) {
8890b57cec5SDimitry Andric         // This sentry object makes sure the current watchpoint is disabled
8900b57cec5SDimitry Andric         // while performing watchpoint actions, and it is then enabled after we
8910b57cec5SDimitry Andric         // are finished.
892bdd1243dSDimitry Andric         ExecutionContext exe_ctx(thread_sp->GetStackFrameAtIndex(0));
893bdd1243dSDimitry Andric         ProcessSP process_sp = exe_ctx.GetProcessSP();
894bdd1243dSDimitry Andric 
8950b57cec5SDimitry Andric         WatchpointSentry sentry(process_sp, wp_sp);
8960b57cec5SDimitry Andric 
89706c3fb27SDimitry Andric         if (m_silently_skip_wp) {
8980b57cec5SDimitry Andric           m_should_stop = false;
89906c3fb27SDimitry Andric           wp_sp->UndoHitCount();
9000b57cec5SDimitry Andric         }
9010b57cec5SDimitry Andric 
902bdd1243dSDimitry Andric         if (wp_sp->GetHitCount() <= wp_sp->GetIgnoreCount()) {
9030b57cec5SDimitry Andric           m_should_stop = false;
904bdd1243dSDimitry Andric           m_should_stop_is_valid = true;
905bdd1243dSDimitry Andric         }
9060b57cec5SDimitry Andric 
9070b57cec5SDimitry Andric         Debugger &debugger = exe_ctx.GetTargetRef().GetDebugger();
9080b57cec5SDimitry Andric 
9090b57cec5SDimitry Andric         if (m_should_stop && wp_sp->GetConditionText() != nullptr) {
9100b57cec5SDimitry Andric           // We need to make sure the user sees any parse errors in their
9110b57cec5SDimitry Andric           // condition, so we'll hook the constructor errors up to the
9120b57cec5SDimitry Andric           // debugger's Async I/O.
9130b57cec5SDimitry Andric           ExpressionResults result_code;
9140b57cec5SDimitry Andric           EvaluateExpressionOptions expr_options;
9150b57cec5SDimitry Andric           expr_options.SetUnwindOnError(true);
9160b57cec5SDimitry Andric           expr_options.SetIgnoreBreakpoints(true);
9170b57cec5SDimitry Andric           ValueObjectSP result_value_sp;
9180b57cec5SDimitry Andric           Status error;
9190b57cec5SDimitry Andric           result_code = UserExpression::Evaluate(
9200b57cec5SDimitry Andric               exe_ctx, expr_options, wp_sp->GetConditionText(),
9210b57cec5SDimitry Andric               llvm::StringRef(), result_value_sp, error);
9220b57cec5SDimitry Andric 
9230b57cec5SDimitry Andric           if (result_code == eExpressionCompleted) {
9240b57cec5SDimitry Andric             if (result_value_sp) {
9250b57cec5SDimitry Andric               Scalar scalar_value;
9260b57cec5SDimitry Andric               if (result_value_sp->ResolveValue(scalar_value)) {
9270b57cec5SDimitry Andric                 if (scalar_value.ULongLong(1) == 0) {
928bdd1243dSDimitry Andric                   // The condition failed, which we consider "not having hit
929bdd1243dSDimitry Andric                   // the watchpoint" so undo the hit count here.
930bdd1243dSDimitry Andric                   wp_sp->UndoHitCount();
9310b57cec5SDimitry Andric                   m_should_stop = false;
9320b57cec5SDimitry Andric                 } else
9330b57cec5SDimitry Andric                   m_should_stop = true;
9349dba64beSDimitry Andric                 LLDB_LOGF(log,
9350b57cec5SDimitry Andric                           "Condition successfully evaluated, result is %s.\n",
9360b57cec5SDimitry Andric                           m_should_stop ? "true" : "false");
9370b57cec5SDimitry Andric               } else {
9380b57cec5SDimitry Andric                 m_should_stop = true;
9399dba64beSDimitry Andric                 LLDB_LOGF(
9409dba64beSDimitry Andric                     log,
9410b57cec5SDimitry Andric                     "Failed to get an integer result from the expression.");
9420b57cec5SDimitry Andric               }
9430b57cec5SDimitry Andric             }
9440b57cec5SDimitry Andric           } else {
94581ad6265SDimitry Andric             const char *err_str = error.AsCString("<unknown error>");
9469dba64beSDimitry Andric             LLDB_LOGF(log, "Error evaluating condition: \"%s\"\n", err_str);
9470b57cec5SDimitry Andric 
94881ad6265SDimitry Andric             StreamString strm;
94981ad6265SDimitry Andric             strm << "stopped due to an error evaluating condition of "
95081ad6265SDimitry Andric                     "watchpoint ";
95181ad6265SDimitry Andric             wp_sp->GetDescription(&strm, eDescriptionLevelBrief);
95281ad6265SDimitry Andric             strm << ": \"" << wp_sp->GetConditionText() << "\"\n";
95381ad6265SDimitry Andric             strm << err_str;
95481ad6265SDimitry Andric 
95581ad6265SDimitry Andric             Debugger::ReportError(strm.GetString().str(),
95681ad6265SDimitry Andric                                   exe_ctx.GetTargetRef().GetDebugger().GetID());
9570b57cec5SDimitry Andric           }
9580b57cec5SDimitry Andric         }
9590b57cec5SDimitry Andric 
9600b57cec5SDimitry Andric         // If the condition says to stop, we run the callback to further decide
9610b57cec5SDimitry Andric         // whether to stop.
9620b57cec5SDimitry Andric         if (m_should_stop) {
9630b57cec5SDimitry Andric             // FIXME: For now the callbacks have to run in async mode - the
9640b57cec5SDimitry Andric             // first time we restart we need
9650b57cec5SDimitry Andric             // to get out of there.  So set it here.
9660b57cec5SDimitry Andric             // When we figure out how to nest watchpoint hits then this will
9670b57cec5SDimitry Andric             // change.
9680b57cec5SDimitry Andric 
9690b57cec5SDimitry Andric           bool old_async = debugger.GetAsyncExecution();
9700b57cec5SDimitry Andric           debugger.SetAsyncExecution(true);
9710b57cec5SDimitry Andric 
9720b57cec5SDimitry Andric           StoppointCallbackContext context(event_ptr, exe_ctx, false);
9730b57cec5SDimitry Andric           bool stop_requested = wp_sp->InvokeCallback(&context);
9740b57cec5SDimitry Andric 
9750b57cec5SDimitry Andric           debugger.SetAsyncExecution(old_async);
9760b57cec5SDimitry Andric 
9770b57cec5SDimitry Andric           // Also make sure that the callback hasn't continued the target. If
9780b57cec5SDimitry Andric           // it did, when we'll set m_should_stop to false and get out of here.
9790b57cec5SDimitry Andric           if (HasTargetRunSinceMe())
9800b57cec5SDimitry Andric             m_should_stop = false;
9810b57cec5SDimitry Andric 
9820b57cec5SDimitry Andric           if (m_should_stop && !stop_requested) {
9830b57cec5SDimitry Andric             // We have been vetoed by the callback mechanism.
9840b57cec5SDimitry Andric             m_should_stop = false;
9850b57cec5SDimitry Andric           }
9860b57cec5SDimitry Andric         }
9875f757f3fSDimitry Andric 
9885f757f3fSDimitry Andric         // Don't stop if the watched region value is unmodified, and
9895f757f3fSDimitry Andric         // this is a Modify-type watchpoint.
990*0fca6ea1SDimitry Andric         if (m_should_stop && !wp_sp->WatchedValueReportable(exe_ctx)) {
991*0fca6ea1SDimitry Andric           wp_sp->UndoHitCount();
9925f757f3fSDimitry Andric           m_should_stop = false;
993*0fca6ea1SDimitry Andric         }
9945f757f3fSDimitry Andric 
9950b57cec5SDimitry Andric         // Finally, if we are going to stop, print out the new & old values:
9960b57cec5SDimitry Andric         if (m_should_stop) {
9970b57cec5SDimitry Andric           wp_sp->CaptureWatchedValue(exe_ctx);
9980b57cec5SDimitry Andric 
9990b57cec5SDimitry Andric           Debugger &debugger = exe_ctx.GetTargetRef().GetDebugger();
10000b57cec5SDimitry Andric           StreamSP output_sp = debugger.GetAsyncOutputStream();
10015f757f3fSDimitry Andric           if (wp_sp->DumpSnapshots(output_sp.get())) {
10020b57cec5SDimitry Andric             output_sp->EOL();
10030b57cec5SDimitry Andric             output_sp->Flush();
10040b57cec5SDimitry Andric           }
10055f757f3fSDimitry Andric         }
10060b57cec5SDimitry Andric 
10070b57cec5SDimitry Andric       } else {
100881ad6265SDimitry Andric         Log *log_process(GetLog(LLDBLog::Process));
10090b57cec5SDimitry Andric 
10109dba64beSDimitry Andric         LLDB_LOGF(log_process,
10110b57cec5SDimitry Andric                   "Process::%s could not find watchpoint id: %" PRId64 "...",
10120b57cec5SDimitry Andric                   __FUNCTION__, m_value);
10130b57cec5SDimitry Andric       }
10149dba64beSDimitry Andric       LLDB_LOGF(log,
10159dba64beSDimitry Andric                 "Process::%s returning from action with m_should_stop: %d.",
10160b57cec5SDimitry Andric                 __FUNCTION__, m_should_stop);
10170b57cec5SDimitry Andric 
10180b57cec5SDimitry Andric       m_should_stop_is_valid = true;
10190b57cec5SDimitry Andric     }
10200b57cec5SDimitry Andric   }
10210b57cec5SDimitry Andric 
10220b57cec5SDimitry Andric private:
1023bdd1243dSDimitry Andric   void SetStepOverPlanComplete() {
1024bdd1243dSDimitry Andric     assert(m_using_step_over_plan);
1025bdd1243dSDimitry Andric     m_step_over_plan_complete = true;
1026bdd1243dSDimitry Andric   }
1027bdd1243dSDimitry Andric 
102881ad6265SDimitry Andric   bool m_should_stop = false;
102981ad6265SDimitry Andric   bool m_should_stop_is_valid = false;
103006c3fb27SDimitry Andric   // A false watchpoint hit has happened -
103106c3fb27SDimitry Andric   // the thread stopped with a watchpoint
103206c3fb27SDimitry Andric   // hit notification, but the watched region
103306c3fb27SDimitry Andric   // was not actually accessed (as determined
103406c3fb27SDimitry Andric   // by the gdb stub we're talking to).
103506c3fb27SDimitry Andric   // Continue past this watchpoint without
103606c3fb27SDimitry Andric   // notifying the user; on some targets this
103706c3fb27SDimitry Andric   // may mean disable wp, instruction step,
103806c3fb27SDimitry Andric   // re-enable wp, continue.
103906c3fb27SDimitry Andric   // On others, just continue.
104006c3fb27SDimitry Andric   bool m_silently_skip_wp = false;
1041bdd1243dSDimitry Andric   bool m_step_over_plan_complete = false;
1042bdd1243dSDimitry Andric   bool m_using_step_over_plan = false;
10430b57cec5SDimitry Andric };
10440b57cec5SDimitry Andric 
10450b57cec5SDimitry Andric // StopInfoUnixSignal
10460b57cec5SDimitry Andric 
10470b57cec5SDimitry Andric class StopInfoUnixSignal : public StopInfo {
10480b57cec5SDimitry Andric public:
104906c3fb27SDimitry Andric   StopInfoUnixSignal(Thread &thread, int signo, const char *description,
105006c3fb27SDimitry Andric                      std::optional<int> code)
105106c3fb27SDimitry Andric       : StopInfo(thread, signo), m_code(code) {
10520b57cec5SDimitry Andric     SetDescription(description);
10530b57cec5SDimitry Andric   }
10540b57cec5SDimitry Andric 
10550b57cec5SDimitry Andric   ~StopInfoUnixSignal() override = default;
10560b57cec5SDimitry Andric 
10570b57cec5SDimitry Andric   StopReason GetStopReason() const override { return eStopReasonSignal; }
10580b57cec5SDimitry Andric 
10590b57cec5SDimitry Andric   bool ShouldStopSynchronous(Event *event_ptr) override {
10600b57cec5SDimitry Andric     ThreadSP thread_sp(m_thread_wp.lock());
10610b57cec5SDimitry Andric     if (thread_sp)
10620b57cec5SDimitry Andric       return thread_sp->GetProcess()->GetUnixSignals()->GetShouldStop(m_value);
10630b57cec5SDimitry Andric     return false;
10640b57cec5SDimitry Andric   }
10650b57cec5SDimitry Andric 
10660b57cec5SDimitry Andric   bool ShouldStop(Event *event_ptr) override {
10670b57cec5SDimitry Andric     ThreadSP thread_sp(m_thread_wp.lock());
10680b57cec5SDimitry Andric     if (thread_sp)
10690b57cec5SDimitry Andric       return thread_sp->GetProcess()->GetUnixSignals()->GetShouldStop(m_value);
10700b57cec5SDimitry Andric     return false;
10710b57cec5SDimitry Andric   }
10720b57cec5SDimitry Andric 
10730b57cec5SDimitry Andric   // If should stop returns false, check if we should notify of this event
10740b57cec5SDimitry Andric   bool DoShouldNotify(Event *event_ptr) override {
10750b57cec5SDimitry Andric     ThreadSP thread_sp(m_thread_wp.lock());
10760b57cec5SDimitry Andric     if (thread_sp) {
10770b57cec5SDimitry Andric       bool should_notify =
10780b57cec5SDimitry Andric           thread_sp->GetProcess()->GetUnixSignals()->GetShouldNotify(m_value);
10790b57cec5SDimitry Andric       if (should_notify) {
10800b57cec5SDimitry Andric         StreamString strm;
10815f757f3fSDimitry Andric         strm.Format(
10825f757f3fSDimitry Andric             "thread {0:d} received signal: {1}", thread_sp->GetIndexID(),
10835f757f3fSDimitry Andric             thread_sp->GetProcess()->GetUnixSignals()->GetSignalAsStringRef(
10840b57cec5SDimitry Andric                 m_value));
10850b57cec5SDimitry Andric         Process::ProcessEventData::AddRestartedReason(event_ptr,
10860b57cec5SDimitry Andric                                                       strm.GetData());
10870b57cec5SDimitry Andric       }
10880b57cec5SDimitry Andric       return should_notify;
10890b57cec5SDimitry Andric     }
10900b57cec5SDimitry Andric     return true;
10910b57cec5SDimitry Andric   }
10920b57cec5SDimitry Andric 
10930b57cec5SDimitry Andric   void WillResume(lldb::StateType resume_state) override {
10940b57cec5SDimitry Andric     ThreadSP thread_sp(m_thread_wp.lock());
10950b57cec5SDimitry Andric     if (thread_sp) {
10960b57cec5SDimitry Andric       if (!thread_sp->GetProcess()->GetUnixSignals()->GetShouldSuppress(
10970b57cec5SDimitry Andric               m_value))
10980b57cec5SDimitry Andric         thread_sp->SetResumeSignal(m_value);
10990b57cec5SDimitry Andric     }
11000b57cec5SDimitry Andric   }
11010b57cec5SDimitry Andric 
11020b57cec5SDimitry Andric   const char *GetDescription() override {
11030b57cec5SDimitry Andric     if (m_description.empty()) {
11040b57cec5SDimitry Andric       ThreadSP thread_sp(m_thread_wp.lock());
11050b57cec5SDimitry Andric       if (thread_sp) {
110606c3fb27SDimitry Andric         UnixSignalsSP unix_signals = thread_sp->GetProcess()->GetUnixSignals();
11070b57cec5SDimitry Andric         StreamString strm;
110806c3fb27SDimitry Andric         strm << "signal ";
110906c3fb27SDimitry Andric 
111006c3fb27SDimitry Andric         std::string signal_name =
111106c3fb27SDimitry Andric             unix_signals->GetSignalDescription(m_value, m_code);
111206c3fb27SDimitry Andric         if (signal_name.size())
111306c3fb27SDimitry Andric           strm << signal_name;
11140b57cec5SDimitry Andric         else
111506c3fb27SDimitry Andric           strm.Printf("%" PRIi64, m_value);
111606c3fb27SDimitry Andric 
11175ffd83dbSDimitry Andric         m_description = std::string(strm.GetString());
11180b57cec5SDimitry Andric       }
11190b57cec5SDimitry Andric     }
11200b57cec5SDimitry Andric     return m_description.c_str();
11210b57cec5SDimitry Andric   }
112206c3fb27SDimitry Andric 
112306c3fb27SDimitry Andric private:
112406c3fb27SDimitry Andric   // In siginfo_t terms, if m_value is si_signo, m_code is si_code.
112506c3fb27SDimitry Andric   std::optional<int> m_code;
11260b57cec5SDimitry Andric };
11270b57cec5SDimitry Andric 
11280b57cec5SDimitry Andric // StopInfoTrace
11290b57cec5SDimitry Andric 
11300b57cec5SDimitry Andric class StopInfoTrace : public StopInfo {
11310b57cec5SDimitry Andric public:
11320b57cec5SDimitry Andric   StopInfoTrace(Thread &thread) : StopInfo(thread, LLDB_INVALID_UID) {}
11330b57cec5SDimitry Andric 
11340b57cec5SDimitry Andric   ~StopInfoTrace() override = default;
11350b57cec5SDimitry Andric 
11360b57cec5SDimitry Andric   StopReason GetStopReason() const override { return eStopReasonTrace; }
11370b57cec5SDimitry Andric 
11380b57cec5SDimitry Andric   const char *GetDescription() override {
11390b57cec5SDimitry Andric     if (m_description.empty())
11400b57cec5SDimitry Andric       return "trace";
11410b57cec5SDimitry Andric     else
11420b57cec5SDimitry Andric       return m_description.c_str();
11430b57cec5SDimitry Andric   }
11440b57cec5SDimitry Andric };
11450b57cec5SDimitry Andric 
11460b57cec5SDimitry Andric // StopInfoException
11470b57cec5SDimitry Andric 
11480b57cec5SDimitry Andric class StopInfoException : public StopInfo {
11490b57cec5SDimitry Andric public:
11500b57cec5SDimitry Andric   StopInfoException(Thread &thread, const char *description)
11510b57cec5SDimitry Andric       : StopInfo(thread, LLDB_INVALID_UID) {
11520b57cec5SDimitry Andric     if (description)
11530b57cec5SDimitry Andric       SetDescription(description);
11540b57cec5SDimitry Andric   }
11550b57cec5SDimitry Andric 
11560b57cec5SDimitry Andric   ~StopInfoException() override = default;
11570b57cec5SDimitry Andric 
11580b57cec5SDimitry Andric   StopReason GetStopReason() const override { return eStopReasonException; }
11590b57cec5SDimitry Andric 
11600b57cec5SDimitry Andric   const char *GetDescription() override {
11610b57cec5SDimitry Andric     if (m_description.empty())
11620b57cec5SDimitry Andric       return "exception";
11630b57cec5SDimitry Andric     else
11640b57cec5SDimitry Andric       return m_description.c_str();
11650b57cec5SDimitry Andric   }
11660b57cec5SDimitry Andric };
11670b57cec5SDimitry Andric 
1168fe6060f1SDimitry Andric // StopInfoProcessorTrace
1169fe6060f1SDimitry Andric 
1170fe6060f1SDimitry Andric class StopInfoProcessorTrace : public StopInfo {
1171fe6060f1SDimitry Andric public:
1172fe6060f1SDimitry Andric   StopInfoProcessorTrace(Thread &thread, const char *description)
1173fe6060f1SDimitry Andric       : StopInfo(thread, LLDB_INVALID_UID) {
1174fe6060f1SDimitry Andric     if (description)
1175fe6060f1SDimitry Andric       SetDescription(description);
1176fe6060f1SDimitry Andric   }
1177fe6060f1SDimitry Andric 
1178fe6060f1SDimitry Andric   ~StopInfoProcessorTrace() override = default;
1179fe6060f1SDimitry Andric 
1180fe6060f1SDimitry Andric   StopReason GetStopReason() const override {
1181fe6060f1SDimitry Andric     return eStopReasonProcessorTrace;
1182fe6060f1SDimitry Andric   }
1183fe6060f1SDimitry Andric 
1184fe6060f1SDimitry Andric   const char *GetDescription() override {
1185fe6060f1SDimitry Andric     if (m_description.empty())
1186fe6060f1SDimitry Andric       return "processor trace event";
1187fe6060f1SDimitry Andric     else
1188fe6060f1SDimitry Andric       return m_description.c_str();
1189fe6060f1SDimitry Andric   }
1190fe6060f1SDimitry Andric };
1191fe6060f1SDimitry Andric 
11920b57cec5SDimitry Andric // StopInfoThreadPlan
11930b57cec5SDimitry Andric 
11940b57cec5SDimitry Andric class StopInfoThreadPlan : public StopInfo {
11950b57cec5SDimitry Andric public:
11960b57cec5SDimitry Andric   StopInfoThreadPlan(ThreadPlanSP &plan_sp, ValueObjectSP &return_valobj_sp,
11970b57cec5SDimitry Andric                      ExpressionVariableSP &expression_variable_sp)
11980b57cec5SDimitry Andric       : StopInfo(plan_sp->GetThread(), LLDB_INVALID_UID), m_plan_sp(plan_sp),
11990b57cec5SDimitry Andric         m_return_valobj_sp(return_valobj_sp),
12000b57cec5SDimitry Andric         m_expression_variable_sp(expression_variable_sp) {}
12010b57cec5SDimitry Andric 
12020b57cec5SDimitry Andric   ~StopInfoThreadPlan() override = default;
12030b57cec5SDimitry Andric 
12040b57cec5SDimitry Andric   StopReason GetStopReason() const override { return eStopReasonPlanComplete; }
12050b57cec5SDimitry Andric 
12060b57cec5SDimitry Andric   const char *GetDescription() override {
12070b57cec5SDimitry Andric     if (m_description.empty()) {
12080b57cec5SDimitry Andric       StreamString strm;
12090b57cec5SDimitry Andric       m_plan_sp->GetDescription(&strm, eDescriptionLevelBrief);
12105ffd83dbSDimitry Andric       m_description = std::string(strm.GetString());
12110b57cec5SDimitry Andric     }
12120b57cec5SDimitry Andric     return m_description.c_str();
12130b57cec5SDimitry Andric   }
12140b57cec5SDimitry Andric 
12150b57cec5SDimitry Andric   ValueObjectSP GetReturnValueObject() { return m_return_valobj_sp; }
12160b57cec5SDimitry Andric 
12170b57cec5SDimitry Andric   ExpressionVariableSP GetExpressionVariable() {
12180b57cec5SDimitry Andric     return m_expression_variable_sp;
12190b57cec5SDimitry Andric   }
12200b57cec5SDimitry Andric 
12210b57cec5SDimitry Andric protected:
12220b57cec5SDimitry Andric   bool ShouldStop(Event *event_ptr) override {
12230b57cec5SDimitry Andric     if (m_plan_sp)
12240b57cec5SDimitry Andric       return m_plan_sp->ShouldStop(event_ptr);
12250b57cec5SDimitry Andric     else
12260b57cec5SDimitry Andric       return StopInfo::ShouldStop(event_ptr);
12270b57cec5SDimitry Andric   }
12280b57cec5SDimitry Andric 
12290b57cec5SDimitry Andric private:
12300b57cec5SDimitry Andric   ThreadPlanSP m_plan_sp;
12310b57cec5SDimitry Andric   ValueObjectSP m_return_valobj_sp;
12320b57cec5SDimitry Andric   ExpressionVariableSP m_expression_variable_sp;
12330b57cec5SDimitry Andric };
12340b57cec5SDimitry Andric 
12350b57cec5SDimitry Andric // StopInfoExec
12360b57cec5SDimitry Andric 
12370b57cec5SDimitry Andric class StopInfoExec : public StopInfo {
12380b57cec5SDimitry Andric public:
123981ad6265SDimitry Andric   StopInfoExec(Thread &thread) : StopInfo(thread, LLDB_INVALID_UID) {}
12400b57cec5SDimitry Andric 
12410b57cec5SDimitry Andric   ~StopInfoExec() override = default;
12420b57cec5SDimitry Andric 
12430b57cec5SDimitry Andric   bool ShouldStop(Event *event_ptr) override {
12440b57cec5SDimitry Andric     ThreadSP thread_sp(m_thread_wp.lock());
12450b57cec5SDimitry Andric     if (thread_sp)
12460b57cec5SDimitry Andric       return thread_sp->GetProcess()->GetStopOnExec();
12470b57cec5SDimitry Andric     return false;
12480b57cec5SDimitry Andric   }
12490b57cec5SDimitry Andric 
12500b57cec5SDimitry Andric   StopReason GetStopReason() const override { return eStopReasonExec; }
12510b57cec5SDimitry Andric 
12520b57cec5SDimitry Andric   const char *GetDescription() override { return "exec"; }
12530b57cec5SDimitry Andric 
12540b57cec5SDimitry Andric protected:
12550b57cec5SDimitry Andric   void PerformAction(Event *event_ptr) override {
12560b57cec5SDimitry Andric     // Only perform the action once
12570b57cec5SDimitry Andric     if (m_performed_action)
12580b57cec5SDimitry Andric       return;
12590b57cec5SDimitry Andric     m_performed_action = true;
12600b57cec5SDimitry Andric     ThreadSP thread_sp(m_thread_wp.lock());
12610b57cec5SDimitry Andric     if (thread_sp)
12620b57cec5SDimitry Andric       thread_sp->GetProcess()->DidExec();
12630b57cec5SDimitry Andric   }
12640b57cec5SDimitry Andric 
126581ad6265SDimitry Andric   bool m_performed_action = false;
12660b57cec5SDimitry Andric };
12670b57cec5SDimitry Andric 
1268349cc55cSDimitry Andric // StopInfoFork
1269349cc55cSDimitry Andric 
1270349cc55cSDimitry Andric class StopInfoFork : public StopInfo {
1271349cc55cSDimitry Andric public:
1272349cc55cSDimitry Andric   StopInfoFork(Thread &thread, lldb::pid_t child_pid, lldb::tid_t child_tid)
127381ad6265SDimitry Andric       : StopInfo(thread, child_pid), m_child_pid(child_pid),
127481ad6265SDimitry Andric         m_child_tid(child_tid) {}
1275349cc55cSDimitry Andric 
1276349cc55cSDimitry Andric   ~StopInfoFork() override = default;
1277349cc55cSDimitry Andric 
1278349cc55cSDimitry Andric   bool ShouldStop(Event *event_ptr) override { return false; }
1279349cc55cSDimitry Andric 
1280349cc55cSDimitry Andric   StopReason GetStopReason() const override { return eStopReasonFork; }
1281349cc55cSDimitry Andric 
1282349cc55cSDimitry Andric   const char *GetDescription() override { return "fork"; }
1283349cc55cSDimitry Andric 
1284349cc55cSDimitry Andric protected:
1285349cc55cSDimitry Andric   void PerformAction(Event *event_ptr) override {
1286349cc55cSDimitry Andric     // Only perform the action once
1287349cc55cSDimitry Andric     if (m_performed_action)
1288349cc55cSDimitry Andric       return;
1289349cc55cSDimitry Andric     m_performed_action = true;
1290349cc55cSDimitry Andric     ThreadSP thread_sp(m_thread_wp.lock());
1291349cc55cSDimitry Andric     if (thread_sp)
1292349cc55cSDimitry Andric       thread_sp->GetProcess()->DidFork(m_child_pid, m_child_tid);
1293349cc55cSDimitry Andric   }
1294349cc55cSDimitry Andric 
129581ad6265SDimitry Andric   bool m_performed_action = false;
1296349cc55cSDimitry Andric 
1297349cc55cSDimitry Andric private:
1298349cc55cSDimitry Andric   lldb::pid_t m_child_pid;
1299349cc55cSDimitry Andric   lldb::tid_t m_child_tid;
1300349cc55cSDimitry Andric };
1301349cc55cSDimitry Andric 
1302349cc55cSDimitry Andric // StopInfoVFork
1303349cc55cSDimitry Andric 
1304349cc55cSDimitry Andric class StopInfoVFork : public StopInfo {
1305349cc55cSDimitry Andric public:
1306349cc55cSDimitry Andric   StopInfoVFork(Thread &thread, lldb::pid_t child_pid, lldb::tid_t child_tid)
130781ad6265SDimitry Andric       : StopInfo(thread, child_pid), m_child_pid(child_pid),
130881ad6265SDimitry Andric         m_child_tid(child_tid) {}
1309349cc55cSDimitry Andric 
1310349cc55cSDimitry Andric   ~StopInfoVFork() override = default;
1311349cc55cSDimitry Andric 
1312349cc55cSDimitry Andric   bool ShouldStop(Event *event_ptr) override { return false; }
1313349cc55cSDimitry Andric 
1314349cc55cSDimitry Andric   StopReason GetStopReason() const override { return eStopReasonVFork; }
1315349cc55cSDimitry Andric 
1316349cc55cSDimitry Andric   const char *GetDescription() override { return "vfork"; }
1317349cc55cSDimitry Andric 
1318349cc55cSDimitry Andric protected:
1319349cc55cSDimitry Andric   void PerformAction(Event *event_ptr) override {
1320349cc55cSDimitry Andric     // Only perform the action once
1321349cc55cSDimitry Andric     if (m_performed_action)
1322349cc55cSDimitry Andric       return;
1323349cc55cSDimitry Andric     m_performed_action = true;
1324349cc55cSDimitry Andric     ThreadSP thread_sp(m_thread_wp.lock());
1325349cc55cSDimitry Andric     if (thread_sp)
1326349cc55cSDimitry Andric       thread_sp->GetProcess()->DidVFork(m_child_pid, m_child_tid);
1327349cc55cSDimitry Andric   }
1328349cc55cSDimitry Andric 
132981ad6265SDimitry Andric   bool m_performed_action = false;
1330349cc55cSDimitry Andric 
1331349cc55cSDimitry Andric private:
1332349cc55cSDimitry Andric   lldb::pid_t m_child_pid;
1333349cc55cSDimitry Andric   lldb::tid_t m_child_tid;
1334349cc55cSDimitry Andric };
1335349cc55cSDimitry Andric 
1336349cc55cSDimitry Andric // StopInfoVForkDone
1337349cc55cSDimitry Andric 
1338349cc55cSDimitry Andric class StopInfoVForkDone : public StopInfo {
1339349cc55cSDimitry Andric public:
134081ad6265SDimitry Andric   StopInfoVForkDone(Thread &thread) : StopInfo(thread, 0) {}
1341349cc55cSDimitry Andric 
1342349cc55cSDimitry Andric   ~StopInfoVForkDone() override = default;
1343349cc55cSDimitry Andric 
1344349cc55cSDimitry Andric   bool ShouldStop(Event *event_ptr) override { return false; }
1345349cc55cSDimitry Andric 
1346349cc55cSDimitry Andric   StopReason GetStopReason() const override { return eStopReasonVForkDone; }
1347349cc55cSDimitry Andric 
1348349cc55cSDimitry Andric   const char *GetDescription() override { return "vforkdone"; }
1349349cc55cSDimitry Andric 
1350349cc55cSDimitry Andric protected:
1351349cc55cSDimitry Andric   void PerformAction(Event *event_ptr) override {
1352349cc55cSDimitry Andric     // Only perform the action once
1353349cc55cSDimitry Andric     if (m_performed_action)
1354349cc55cSDimitry Andric       return;
1355349cc55cSDimitry Andric     m_performed_action = true;
1356349cc55cSDimitry Andric     ThreadSP thread_sp(m_thread_wp.lock());
1357349cc55cSDimitry Andric     if (thread_sp)
1358349cc55cSDimitry Andric       thread_sp->GetProcess()->DidVForkDone();
1359349cc55cSDimitry Andric   }
1360349cc55cSDimitry Andric 
136181ad6265SDimitry Andric   bool m_performed_action = false;
1362349cc55cSDimitry Andric };
1363349cc55cSDimitry Andric 
13640b57cec5SDimitry Andric } // namespace lldb_private
13650b57cec5SDimitry Andric 
13660b57cec5SDimitry Andric StopInfoSP StopInfo::CreateStopReasonWithBreakpointSiteID(Thread &thread,
13670b57cec5SDimitry Andric                                                           break_id_t break_id) {
13680b57cec5SDimitry Andric   return StopInfoSP(new StopInfoBreakpoint(thread, break_id));
13690b57cec5SDimitry Andric }
13700b57cec5SDimitry Andric 
13710b57cec5SDimitry Andric StopInfoSP StopInfo::CreateStopReasonWithBreakpointSiteID(Thread &thread,
13720b57cec5SDimitry Andric                                                           break_id_t break_id,
13730b57cec5SDimitry Andric                                                           bool should_stop) {
13740b57cec5SDimitry Andric   return StopInfoSP(new StopInfoBreakpoint(thread, break_id, should_stop));
13750b57cec5SDimitry Andric }
13760b57cec5SDimitry Andric 
13775f757f3fSDimitry Andric // LWP_TODO: We'll need a CreateStopReasonWithWatchpointResourceID akin
13785f757f3fSDimitry Andric // to CreateStopReasonWithBreakpointSiteID
137906c3fb27SDimitry Andric StopInfoSP StopInfo::CreateStopReasonWithWatchpointID(Thread &thread,
138006c3fb27SDimitry Andric                                                       break_id_t watch_id,
138106c3fb27SDimitry Andric                                                       bool silently_continue) {
138206c3fb27SDimitry Andric   return StopInfoSP(
138306c3fb27SDimitry Andric       new StopInfoWatchpoint(thread, watch_id, silently_continue));
13840b57cec5SDimitry Andric }
13850b57cec5SDimitry Andric 
13860b57cec5SDimitry Andric StopInfoSP StopInfo::CreateStopReasonWithSignal(Thread &thread, int signo,
138706c3fb27SDimitry Andric                                                 const char *description,
138806c3fb27SDimitry Andric                                                 std::optional<int> code) {
1389349cc55cSDimitry Andric   thread.GetProcess()->GetUnixSignals()->IncrementSignalHitCount(signo);
139006c3fb27SDimitry Andric   return StopInfoSP(new StopInfoUnixSignal(thread, signo, description, code));
13910b57cec5SDimitry Andric }
13920b57cec5SDimitry Andric 
13930b57cec5SDimitry Andric StopInfoSP StopInfo::CreateStopReasonToTrace(Thread &thread) {
13940b57cec5SDimitry Andric   return StopInfoSP(new StopInfoTrace(thread));
13950b57cec5SDimitry Andric }
13960b57cec5SDimitry Andric 
13970b57cec5SDimitry Andric StopInfoSP StopInfo::CreateStopReasonWithPlan(
13980b57cec5SDimitry Andric     ThreadPlanSP &plan_sp, ValueObjectSP return_valobj_sp,
13990b57cec5SDimitry Andric     ExpressionVariableSP expression_variable_sp) {
14000b57cec5SDimitry Andric   return StopInfoSP(new StopInfoThreadPlan(plan_sp, return_valobj_sp,
14010b57cec5SDimitry Andric                                            expression_variable_sp));
14020b57cec5SDimitry Andric }
14030b57cec5SDimitry Andric 
14040b57cec5SDimitry Andric StopInfoSP StopInfo::CreateStopReasonWithException(Thread &thread,
14050b57cec5SDimitry Andric                                                    const char *description) {
14060b57cec5SDimitry Andric   return StopInfoSP(new StopInfoException(thread, description));
14070b57cec5SDimitry Andric }
14080b57cec5SDimitry Andric 
1409fe6060f1SDimitry Andric StopInfoSP StopInfo::CreateStopReasonProcessorTrace(Thread &thread,
1410fe6060f1SDimitry Andric                                                     const char *description) {
1411fe6060f1SDimitry Andric   return StopInfoSP(new StopInfoProcessorTrace(thread, description));
1412fe6060f1SDimitry Andric }
1413fe6060f1SDimitry Andric 
14140b57cec5SDimitry Andric StopInfoSP StopInfo::CreateStopReasonWithExec(Thread &thread) {
14150b57cec5SDimitry Andric   return StopInfoSP(new StopInfoExec(thread));
14160b57cec5SDimitry Andric }
14170b57cec5SDimitry Andric 
1418349cc55cSDimitry Andric StopInfoSP StopInfo::CreateStopReasonFork(Thread &thread,
1419349cc55cSDimitry Andric                                           lldb::pid_t child_pid,
1420349cc55cSDimitry Andric                                           lldb::tid_t child_tid) {
1421349cc55cSDimitry Andric   return StopInfoSP(new StopInfoFork(thread, child_pid, child_tid));
1422349cc55cSDimitry Andric }
1423349cc55cSDimitry Andric 
1424349cc55cSDimitry Andric 
1425349cc55cSDimitry Andric StopInfoSP StopInfo::CreateStopReasonVFork(Thread &thread,
1426349cc55cSDimitry Andric                                            lldb::pid_t child_pid,
1427349cc55cSDimitry Andric                                            lldb::tid_t child_tid) {
1428349cc55cSDimitry Andric   return StopInfoSP(new StopInfoVFork(thread, child_pid, child_tid));
1429349cc55cSDimitry Andric }
1430349cc55cSDimitry Andric 
1431349cc55cSDimitry Andric StopInfoSP StopInfo::CreateStopReasonVForkDone(Thread &thread) {
1432349cc55cSDimitry Andric   return StopInfoSP(new StopInfoVForkDone(thread));
1433349cc55cSDimitry Andric }
1434349cc55cSDimitry Andric 
14350b57cec5SDimitry Andric ValueObjectSP StopInfo::GetReturnValueObject(StopInfoSP &stop_info_sp) {
14360b57cec5SDimitry Andric   if (stop_info_sp &&
14370b57cec5SDimitry Andric       stop_info_sp->GetStopReason() == eStopReasonPlanComplete) {
14380b57cec5SDimitry Andric     StopInfoThreadPlan *plan_stop_info =
14390b57cec5SDimitry Andric         static_cast<StopInfoThreadPlan *>(stop_info_sp.get());
14400b57cec5SDimitry Andric     return plan_stop_info->GetReturnValueObject();
14410b57cec5SDimitry Andric   } else
14420b57cec5SDimitry Andric     return ValueObjectSP();
14430b57cec5SDimitry Andric }
14440b57cec5SDimitry Andric 
14450b57cec5SDimitry Andric ExpressionVariableSP StopInfo::GetExpressionVariable(StopInfoSP &stop_info_sp) {
14460b57cec5SDimitry Andric   if (stop_info_sp &&
14470b57cec5SDimitry Andric       stop_info_sp->GetStopReason() == eStopReasonPlanComplete) {
14480b57cec5SDimitry Andric     StopInfoThreadPlan *plan_stop_info =
14490b57cec5SDimitry Andric         static_cast<StopInfoThreadPlan *>(stop_info_sp.get());
14500b57cec5SDimitry Andric     return plan_stop_info->GetExpressionVariable();
14510b57cec5SDimitry Andric   } else
14520b57cec5SDimitry Andric     return ExpressionVariableSP();
14530b57cec5SDimitry Andric }
14540b57cec5SDimitry Andric 
14550b57cec5SDimitry Andric lldb::ValueObjectSP
14560b57cec5SDimitry Andric StopInfo::GetCrashingDereference(StopInfoSP &stop_info_sp,
14570b57cec5SDimitry Andric                                  lldb::addr_t *crashing_address) {
14580b57cec5SDimitry Andric   if (!stop_info_sp) {
14590b57cec5SDimitry Andric     return ValueObjectSP();
14600b57cec5SDimitry Andric   }
14610b57cec5SDimitry Andric 
14620b57cec5SDimitry Andric   const char *description = stop_info_sp->GetDescription();
14630b57cec5SDimitry Andric   if (!description) {
14640b57cec5SDimitry Andric     return ValueObjectSP();
14650b57cec5SDimitry Andric   }
14660b57cec5SDimitry Andric 
14670b57cec5SDimitry Andric   ThreadSP thread_sp = stop_info_sp->GetThread();
14680b57cec5SDimitry Andric   if (!thread_sp) {
14690b57cec5SDimitry Andric     return ValueObjectSP();
14700b57cec5SDimitry Andric   }
14710b57cec5SDimitry Andric 
147206c3fb27SDimitry Andric   StackFrameSP frame_sp =
147306c3fb27SDimitry Andric       thread_sp->GetSelectedFrame(DoNoSelectMostRelevantFrame);
14740b57cec5SDimitry Andric 
14750b57cec5SDimitry Andric   if (!frame_sp) {
14760b57cec5SDimitry Andric     return ValueObjectSP();
14770b57cec5SDimitry Andric   }
14780b57cec5SDimitry Andric 
14790b57cec5SDimitry Andric   const char address_string[] = "address=";
14800b57cec5SDimitry Andric 
14810b57cec5SDimitry Andric   const char *address_loc = strstr(description, address_string);
14820b57cec5SDimitry Andric   if (!address_loc) {
14830b57cec5SDimitry Andric     return ValueObjectSP();
14840b57cec5SDimitry Andric   }
14850b57cec5SDimitry Andric 
14860b57cec5SDimitry Andric   address_loc += (sizeof(address_string) - 1);
14870b57cec5SDimitry Andric 
14880b57cec5SDimitry Andric   uint64_t address = strtoull(address_loc, nullptr, 0);
14890b57cec5SDimitry Andric   if (crashing_address) {
14900b57cec5SDimitry Andric     *crashing_address = address;
14910b57cec5SDimitry Andric   }
14920b57cec5SDimitry Andric 
14930b57cec5SDimitry Andric   return frame_sp->GuessValueForAddress(address);
14940b57cec5SDimitry Andric }
1495