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