//===-- StopInfo.cpp ------------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// #include #include "lldb/Breakpoint/Breakpoint.h" #include "lldb/Breakpoint/BreakpointLocation.h" #include "lldb/Breakpoint/StoppointCallbackContext.h" #include "lldb/Breakpoint/Watchpoint.h" #include "lldb/Core/Debugger.h" #include "lldb/Core/ValueObject.h" #include "lldb/Expression/UserExpression.h" #include "lldb/Target/Process.h" #include "lldb/Target/StopInfo.h" #include "lldb/Target/Target.h" #include "lldb/Target/Thread.h" #include "lldb/Target/ThreadPlan.h" #include "lldb/Target/UnixSignals.h" #include "lldb/Utility/Log.h" #include "lldb/Utility/StreamString.h" using namespace lldb; using namespace lldb_private; StopInfo::StopInfo(Thread &thread, uint64_t value) : m_thread_wp(thread.shared_from_this()), m_stop_id(thread.GetProcess()->GetStopID()), m_resume_id(thread.GetProcess()->GetResumeID()), m_value(value), m_description(), m_override_should_notify(eLazyBoolCalculate), m_override_should_stop(eLazyBoolCalculate), m_extended_info() {} bool StopInfo::IsValid() const { ThreadSP thread_sp(m_thread_wp.lock()); if (thread_sp) return thread_sp->GetProcess()->GetStopID() == m_stop_id; return false; } void StopInfo::MakeStopInfoValid() { ThreadSP thread_sp(m_thread_wp.lock()); if (thread_sp) { m_stop_id = thread_sp->GetProcess()->GetStopID(); m_resume_id = thread_sp->GetProcess()->GetResumeID(); } } bool StopInfo::HasTargetRunSinceMe() { ThreadSP thread_sp(m_thread_wp.lock()); if (thread_sp) { lldb::StateType ret_type = thread_sp->GetProcess()->GetPrivateState(); if (ret_type == eStateRunning) { return true; } else if (ret_type == eStateStopped) { // This is a little tricky. We want to count "run and stopped again // before you could ask this question as a "TRUE" answer to // HasTargetRunSinceMe. But we don't want to include any running of the // target done for expressions. So we track both resumes, and resumes // caused by expressions, and check if there are any resumes // NOT caused // by expressions. uint32_t curr_resume_id = thread_sp->GetProcess()->GetResumeID(); uint32_t last_user_expression_id = thread_sp->GetProcess()->GetLastUserExpressionResumeID(); if (curr_resume_id == m_resume_id) { return false; } else if (curr_resume_id > last_user_expression_id) { return true; } } } return false; } // StopInfoBreakpoint namespace lldb_private { class StopInfoBreakpoint : public StopInfo { public: StopInfoBreakpoint(Thread &thread, break_id_t break_id) : StopInfo(thread, break_id), m_should_stop(false), m_should_stop_is_valid(false), m_should_perform_action(true), m_address(LLDB_INVALID_ADDRESS), m_break_id(LLDB_INVALID_BREAK_ID), m_was_one_shot(false) { StoreBPInfo(); } StopInfoBreakpoint(Thread &thread, break_id_t break_id, bool should_stop) : StopInfo(thread, break_id), m_should_stop(should_stop), m_should_stop_is_valid(true), m_should_perform_action(true), m_address(LLDB_INVALID_ADDRESS), m_break_id(LLDB_INVALID_BREAK_ID), m_was_one_shot(false) { StoreBPInfo(); } ~StopInfoBreakpoint() override = default; void StoreBPInfo() { ThreadSP thread_sp(m_thread_wp.lock()); if (thread_sp) { BreakpointSiteSP bp_site_sp( thread_sp->GetProcess()->GetBreakpointSiteList().FindByID(m_value)); if (bp_site_sp) { if (bp_site_sp->GetNumberOfOwners() == 1) { BreakpointLocationSP bp_loc_sp = bp_site_sp->GetOwnerAtIndex(0); if (bp_loc_sp) { m_break_id = bp_loc_sp->GetBreakpoint().GetID(); m_was_one_shot = bp_loc_sp->GetBreakpoint().IsOneShot(); } } m_address = bp_site_sp->GetLoadAddress(); } } } bool IsValidForOperatingSystemThread(Thread &thread) override { ProcessSP process_sp(thread.GetProcess()); if (process_sp) { BreakpointSiteSP bp_site_sp( process_sp->GetBreakpointSiteList().FindByID(m_value)); if (bp_site_sp) return bp_site_sp->ValidForThisThread(&thread); } return false; } StopReason GetStopReason() const override { return eStopReasonBreakpoint; } bool ShouldStopSynchronous(Event *event_ptr) override { ThreadSP thread_sp(m_thread_wp.lock()); if (thread_sp) { if (!m_should_stop_is_valid) { // Only check once if we should stop at a breakpoint BreakpointSiteSP bp_site_sp( thread_sp->GetProcess()->GetBreakpointSiteList().FindByID(m_value)); if (bp_site_sp) { ExecutionContext exe_ctx(thread_sp->GetStackFrameAtIndex(0)); StoppointCallbackContext context(event_ptr, exe_ctx, true); bp_site_sp->BumpHitCounts(); m_should_stop = bp_site_sp->ShouldStop(&context); } else { Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS)); LLDB_LOGF(log, "Process::%s could not find breakpoint site id: %" PRId64 "...", __FUNCTION__, m_value); m_should_stop = true; } m_should_stop_is_valid = true; } return m_should_stop; } return false; } bool DoShouldNotify(Event *event_ptr) override { ThreadSP thread_sp(m_thread_wp.lock()); if (thread_sp) { BreakpointSiteSP bp_site_sp( thread_sp->GetProcess()->GetBreakpointSiteList().FindByID(m_value)); if (bp_site_sp) { bool all_internal = true; for (uint32_t i = 0; i < bp_site_sp->GetNumberOfOwners(); i++) { if (!bp_site_sp->GetOwnerAtIndex(i)->GetBreakpoint().IsInternal()) { all_internal = false; break; } } return !all_internal; } } return true; } const char *GetDescription() override { if (m_description.empty()) { ThreadSP thread_sp(m_thread_wp.lock()); if (thread_sp) { BreakpointSiteSP bp_site_sp( thread_sp->GetProcess()->GetBreakpointSiteList().FindByID(m_value)); if (bp_site_sp) { StreamString strm; // If we have just hit an internal breakpoint, and it has a kind // description, print that instead of the full breakpoint printing: if (bp_site_sp->IsInternal()) { size_t num_owners = bp_site_sp->GetNumberOfOwners(); for (size_t idx = 0; idx < num_owners; idx++) { const char *kind = bp_site_sp->GetOwnerAtIndex(idx) ->GetBreakpoint() .GetBreakpointKind(); if (kind != nullptr) { m_description.assign(kind); return kind; } } } strm.Printf("breakpoint "); bp_site_sp->GetDescription(&strm, eDescriptionLevelBrief); m_description = std::string(strm.GetString()); } else { StreamString strm; if (m_break_id != LLDB_INVALID_BREAK_ID) { BreakpointSP break_sp = thread_sp->GetProcess()->GetTarget().GetBreakpointByID( m_break_id); if (break_sp) { if (break_sp->IsInternal()) { const char *kind = break_sp->GetBreakpointKind(); if (kind) strm.Printf("internal %s breakpoint(%d).", kind, m_break_id); else strm.Printf("internal breakpoint(%d).", m_break_id); } else { strm.Printf("breakpoint %d.", m_break_id); } } else { if (m_was_one_shot) strm.Printf("one-shot breakpoint %d", m_break_id); else strm.Printf("breakpoint %d which has been deleted.", m_break_id); } } else if (m_address == LLDB_INVALID_ADDRESS) strm.Printf("breakpoint site %" PRIi64 " which has been deleted - unknown address", m_value); else strm.Printf("breakpoint site %" PRIi64 " which has been deleted - was at 0x%" PRIx64, m_value, m_address); m_description = std::string(strm.GetString()); } } } return m_description.c_str(); } protected: bool ShouldStop(Event *event_ptr) override { // This just reports the work done by PerformAction or the synchronous // stop. It should only ever get called after they have had a chance to // run. assert(m_should_stop_is_valid); return m_should_stop; } void PerformAction(Event *event_ptr) override { if (!m_should_perform_action) return; m_should_perform_action = false; bool internal_breakpoint = true; ThreadSP thread_sp(m_thread_wp.lock()); if (thread_sp) { Log *log = lldb_private::GetLogIfAnyCategoriesSet( LIBLLDB_LOG_BREAKPOINTS | LIBLLDB_LOG_STEP); if (!thread_sp->IsValid()) { // This shouldn't ever happen, but just in case, don't do more harm. if (log) { LLDB_LOGF(log, "PerformAction got called with an invalid thread."); } m_should_stop = true; m_should_stop_is_valid = true; return; } BreakpointSiteSP bp_site_sp( thread_sp->GetProcess()->GetBreakpointSiteList().FindByID(m_value)); std::unordered_set precondition_breakpoints; if (bp_site_sp) { // Let's copy the owners list out of the site and store them in a local // list. That way if one of the breakpoint actions changes the site, // then we won't be operating on a bad list. BreakpointLocationCollection site_locations; size_t num_owners = bp_site_sp->CopyOwnersList(site_locations); if (num_owners == 0) { m_should_stop = true; } else { // We go through each location, and test first its precondition - // this overrides everything. Note, we only do this once per // breakpoint - not once per location... Then check the condition. // If the condition says to stop, then we run the callback for that // location. If that callback says to stop as well, then we set // m_should_stop to true; we are going to stop. But we still want to // give all the breakpoints whose conditions say we are going to stop // a chance to run their callbacks. Of course if any callback // restarts the target by putting "continue" in the callback, then // we're going to restart, without running the rest of the callbacks. // And in this case we will end up not stopping even if another // location said we should stop. But that's better than not running // all the callbacks. m_should_stop = false; // We don't select threads as we go through them testing breakpoint // conditions and running commands. So we need to set the thread for // expression evaluation here: ThreadList::ExpressionExecutionThreadPusher thread_pusher(thread_sp); ExecutionContext exe_ctx(thread_sp->GetStackFrameAtIndex(0)); Process *process = exe_ctx.GetProcessPtr(); if (process->GetModIDRef().IsLastResumeForUserExpression()) { // If we are in the middle of evaluating an expression, don't run // asynchronous breakpoint commands or expressions. That could // lead to infinite recursion if the command or condition re-calls // the function with this breakpoint. // TODO: We can keep a list of the breakpoints we've seen while // running expressions in the nested // PerformAction calls that can arise when the action runs a // function that hits another breakpoint, and only stop running // commands when we see the same breakpoint hit a second time. m_should_stop_is_valid = true; // It is possible that the user has a breakpoint at the same site // as the completed plan had (e.g. user has a breakpoint // on a module entry point, and `ThreadPlanCallFunction` ends // also there). We can't find an internal breakpoint in the loop // later because it was already removed on the plan completion. // So check if the plan was completed, and stop if so. if (thread_sp->CompletedPlanOverridesBreakpoint()) { m_should_stop = true; thread_sp->ResetStopInfo(); return; } LLDB_LOGF(log, "StopInfoBreakpoint::PerformAction - Hit a " "breakpoint while running an expression," " not running commands to avoid recursion."); bool ignoring_breakpoints = process->GetIgnoreBreakpointsInExpressions(); if (ignoring_breakpoints) { m_should_stop = false; // Internal breakpoints will always stop. for (size_t j = 0; j < num_owners; j++) { lldb::BreakpointLocationSP bp_loc_sp = bp_site_sp->GetOwnerAtIndex(j); if (bp_loc_sp->GetBreakpoint().IsInternal()) { m_should_stop = true; break; } } } else { m_should_stop = true; } LLDB_LOGF(log, "StopInfoBreakpoint::PerformAction - in expression, " "continuing: %s.", m_should_stop ? "true" : "false"); process->GetTarget().GetDebugger().GetAsyncOutputStream()->Printf( "Warning: hit breakpoint while running function, skipping " "commands and conditions to prevent recursion.\n"); return; } StoppointCallbackContext context(event_ptr, exe_ctx, false); // For safety's sake let's also grab an extra reference to the // breakpoint owners of the locations we're going to examine, since // the locations are going to have to get back to their breakpoints, // and the locations don't keep their owners alive. I'm just // sticking the BreakpointSP's in a vector since I'm only using it to // locally increment their retain counts. std::vector location_owners; for (size_t j = 0; j < num_owners; j++) { BreakpointLocationSP loc(site_locations.GetByIndex(j)); location_owners.push_back(loc->GetBreakpoint().shared_from_this()); } for (size_t j = 0; j < num_owners; j++) { lldb::BreakpointLocationSP bp_loc_sp = site_locations.GetByIndex(j); StreamString loc_desc; if (log) { bp_loc_sp->GetDescription(&loc_desc, eDescriptionLevelBrief); } // If another action disabled this breakpoint or its location, then // don't run the actions. if (!bp_loc_sp->IsEnabled() || !bp_loc_sp->GetBreakpoint().IsEnabled()) continue; // The breakpoint site may have many locations associated with it, // not all of them valid for this thread. Skip the ones that // aren't: if (!bp_loc_sp->ValidForThisThread(thread_sp.get())) { if (log) { LLDB_LOGF(log, "Breakpoint %s hit on thread 0x%llx but it was not " "for this thread, continuing.", loc_desc.GetData(), static_cast(thread_sp->GetID())); } continue; } internal_breakpoint = bp_loc_sp->GetBreakpoint().IsInternal(); // First run the precondition, but since the precondition is per // breakpoint, only run it once per breakpoint. std::pair::iterator, bool> result = precondition_breakpoints.insert( bp_loc_sp->GetBreakpoint().GetID()); if (!result.second) continue; bool precondition_result = bp_loc_sp->GetBreakpoint().EvaluatePrecondition(context); if (!precondition_result) continue; // Next run the condition for the breakpoint. If that says we // should stop, then we'll run the callback for the breakpoint. If // the callback says we shouldn't stop that will win. if (bp_loc_sp->GetConditionText() != nullptr) { Status condition_error; bool condition_says_stop = bp_loc_sp->ConditionSaysStop(exe_ctx, condition_error); if (!condition_error.Success()) { Debugger &debugger = exe_ctx.GetTargetRef().GetDebugger(); StreamSP error_sp = debugger.GetAsyncErrorStream(); error_sp->Printf("Stopped due to an error evaluating condition " "of breakpoint "); bp_loc_sp->GetDescription(error_sp.get(), eDescriptionLevelBrief); error_sp->Printf(": \"%s\"", bp_loc_sp->GetConditionText()); error_sp->EOL(); const char *err_str = condition_error.AsCString(""); LLDB_LOGF(log, "Error evaluating condition: \"%s\"\n", err_str); error_sp->PutCString(err_str); error_sp->EOL(); error_sp->Flush(); } else { LLDB_LOGF(log, "Condition evaluated for breakpoint %s on thread " "0x%llx condition_says_stop: %i.", loc_desc.GetData(), static_cast(thread_sp->GetID()), condition_says_stop); if (!condition_says_stop) { // We don't want to increment the hit count of breakpoints if // the condition fails. We've already bumped it by the time // we get here, so undo the bump: bp_loc_sp->UndoBumpHitCount(); continue; } } } // Check the auto-continue bit on the location, do this before the // callback since it may change this, but that would be for the // NEXT hit. Note, you might think you could check auto-continue // before the condition, and not evaluate the condition if it says // to continue. But failing the condition means the breakpoint was // effectively NOT HIT. So these two states are different. bool auto_continue_says_stop = true; if (bp_loc_sp->IsAutoContinue()) { LLDB_LOGF(log, "Continuing breakpoint %s as AutoContinue was set.", loc_desc.GetData()); // We want this stop reported, so you will know we auto-continued // but only for external breakpoints: if (!internal_breakpoint) thread_sp->SetShouldReportStop(eVoteYes); auto_continue_says_stop = false; } bool callback_says_stop = true; // FIXME: For now the callbacks have to run in async mode - the // first time we restart we need // to get out of there. So set it here. // When we figure out how to nest breakpoint hits then this will // change. Debugger &debugger = thread_sp->CalculateTarget()->GetDebugger(); bool old_async = debugger.GetAsyncExecution(); debugger.SetAsyncExecution(true); callback_says_stop = bp_loc_sp->InvokeCallback(&context); debugger.SetAsyncExecution(old_async); if (callback_says_stop && auto_continue_says_stop) m_should_stop = true; // If we are going to stop for this breakpoint, then remove the // breakpoint. if (callback_says_stop && bp_loc_sp && bp_loc_sp->GetBreakpoint().IsOneShot()) { thread_sp->GetProcess()->GetTarget().RemoveBreakpointByID( bp_loc_sp->GetBreakpoint().GetID()); } // Also make sure that the callback hasn't continued the target. If // it did, when we'll set m_should_start to false and get out of // here. if (HasTargetRunSinceMe()) { m_should_stop = false; break; } } } // We've figured out what this stop wants to do, so mark it as valid so // we don't compute it again. m_should_stop_is_valid = true; } else { m_should_stop = true; m_should_stop_is_valid = true; Log *log_process( lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS)); LLDB_LOGF(log_process, "Process::%s could not find breakpoint site id: %" PRId64 "...", __FUNCTION__, m_value); } if ((!m_should_stop || internal_breakpoint) && thread_sp->CompletedPlanOverridesBreakpoint()) { // Override should_stop decision when we have completed step plan // additionally to the breakpoint m_should_stop = true; // We know we're stopping for a completed plan and we don't want to // show the breakpoint stop, so compute the public stop info immediately // here. thread_sp->CalculatePublicStopInfo(); } LLDB_LOGF(log, "Process::%s returning from action with m_should_stop: %d.", __FUNCTION__, m_should_stop); } } private: bool m_should_stop; bool m_should_stop_is_valid; bool m_should_perform_action; // Since we are trying to preserve the "state" // of the system even if we run functions // etc. behind the users backs, we need to make sure we only REALLY perform // the action once. lldb::addr_t m_address; // We use this to capture the breakpoint site address // when we create the StopInfo, // in case somebody deletes it between the time the StopInfo is made and the // description is asked for. lldb::break_id_t m_break_id; bool m_was_one_shot; }; // StopInfoWatchpoint class StopInfoWatchpoint : public StopInfo { public: // Make sure watchpoint is properly disabled and subsequently enabled while // performing watchpoint actions. class WatchpointSentry { public: WatchpointSentry(ProcessSP p_sp, WatchpointSP w_sp) : process_sp(p_sp), watchpoint_sp(w_sp) { if (process_sp && watchpoint_sp) { const bool notify = false; watchpoint_sp->TurnOnEphemeralMode(); process_sp->DisableWatchpoint(watchpoint_sp.get(), notify); process_sp->AddPreResumeAction(SentryPreResumeAction, this); } } void DoReenable() { if (process_sp && watchpoint_sp) { bool was_disabled = watchpoint_sp->IsDisabledDuringEphemeralMode(); watchpoint_sp->TurnOffEphemeralMode(); const bool notify = false; if (was_disabled) { process_sp->DisableWatchpoint(watchpoint_sp.get(), notify); } else { process_sp->EnableWatchpoint(watchpoint_sp.get(), notify); } } } ~WatchpointSentry() { DoReenable(); if (process_sp) process_sp->ClearPreResumeAction(SentryPreResumeAction, this); } static bool SentryPreResumeAction(void *sentry_void) { WatchpointSentry *sentry = (WatchpointSentry *) sentry_void; sentry->DoReenable(); return true; } private: ProcessSP process_sp; WatchpointSP watchpoint_sp; }; StopInfoWatchpoint(Thread &thread, break_id_t watch_id, lldb::addr_t watch_hit_addr) : StopInfo(thread, watch_id), m_should_stop(false), m_should_stop_is_valid(false), m_watch_hit_addr(watch_hit_addr) {} ~StopInfoWatchpoint() override = default; StopReason GetStopReason() const override { return eStopReasonWatchpoint; } const char *GetDescription() override { if (m_description.empty()) { StreamString strm; strm.Printf("watchpoint %" PRIi64, m_value); m_description = std::string(strm.GetString()); } return m_description.c_str(); } protected: bool ShouldStopSynchronous(Event *event_ptr) override { // ShouldStop() method is idempotent and should not affect hit count. See // Process::RunPrivateStateThread()->Process()->HandlePrivateEvent() // -->Process()::ShouldBroadcastEvent()->ThreadList::ShouldStop()-> // Thread::ShouldStop()->ThreadPlanBase::ShouldStop()-> // StopInfoWatchpoint::ShouldStop() and // Event::DoOnRemoval()->Process::ProcessEventData::DoOnRemoval()-> // StopInfoWatchpoint::PerformAction(). if (m_should_stop_is_valid) return m_should_stop; ThreadSP thread_sp(m_thread_wp.lock()); if (thread_sp) { WatchpointSP wp_sp( thread_sp->CalculateTarget()->GetWatchpointList().FindByID( GetValue())); if (wp_sp) { // Check if we should stop at a watchpoint. ExecutionContext exe_ctx(thread_sp->GetStackFrameAtIndex(0)); StoppointCallbackContext context(event_ptr, exe_ctx, true); m_should_stop = wp_sp->ShouldStop(&context); } else { Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS)); LLDB_LOGF(log, "Process::%s could not find watchpoint location id: %" PRId64 "...", __FUNCTION__, GetValue()); m_should_stop = true; } } m_should_stop_is_valid = true; return m_should_stop; } bool ShouldStop(Event *event_ptr) override { // This just reports the work done by PerformAction or the synchronous // stop. It should only ever get called after they have had a chance to // run. assert(m_should_stop_is_valid); return m_should_stop; } void PerformAction(Event *event_ptr) override { Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_WATCHPOINTS); // We're going to calculate if we should stop or not in some way during the // course of this code. Also by default we're going to stop, so set that // here. m_should_stop = true; ThreadSP thread_sp(m_thread_wp.lock()); if (thread_sp) { WatchpointSP wp_sp( thread_sp->CalculateTarget()->GetWatchpointList().FindByID( GetValue())); if (wp_sp) { ExecutionContext exe_ctx(thread_sp->GetStackFrameAtIndex(0)); ProcessSP process_sp = exe_ctx.GetProcessSP(); { // check if this process is running on an architecture where // watchpoints trigger before the associated instruction runs. if so, // disable the WP, single-step and then re-enable the watchpoint if (process_sp) { uint32_t num; bool wp_triggers_after; if (process_sp->GetWatchpointSupportInfo(num, wp_triggers_after) .Success()) { if (!wp_triggers_after) { // We need to preserve the watch_index before watchpoint is // disable. Since Watchpoint::SetEnabled will clear the watch // index. This will fix TestWatchpointIter failure Watchpoint *wp = wp_sp.get(); uint32_t watch_index = wp->GetHardwareIndex(); process_sp->DisableWatchpoint(wp, false); StopInfoSP stored_stop_info_sp = thread_sp->GetStopInfo(); assert(stored_stop_info_sp.get() == this); Status new_plan_status; ThreadPlanSP new_plan_sp( thread_sp->QueueThreadPlanForStepSingleInstruction( false, // step-over false, // abort_other_plans true, // stop_other_threads new_plan_status)); if (new_plan_sp && new_plan_status.Success()) { new_plan_sp->SetIsMasterPlan(true); new_plan_sp->SetOkayToDiscard(false); new_plan_sp->SetPrivate(true); } process_sp->GetThreadList().SetSelectedThreadByID( thread_sp->GetID()); process_sp->ResumeSynchronous(nullptr); process_sp->GetThreadList().SetSelectedThreadByID( thread_sp->GetID()); thread_sp->SetStopInfo(stored_stop_info_sp); process_sp->EnableWatchpoint(wp, false); wp->SetHardwareIndex(watch_index); } } } } // This sentry object makes sure the current watchpoint is disabled // while performing watchpoint actions, and it is then enabled after we // are finished. WatchpointSentry sentry(process_sp, wp_sp); /* * MIPS: Last 3bits of the watchpoint address are masked by the kernel. * For example: * 'n' is at 0x120010d00 and 'm' is 0x120010d04. When a watchpoint is * set at 'm', then * watch exception is generated even when 'n' is read/written. To handle * this case, * server emulates the instruction at PC and finds the base address of * the load/store * instruction and appends it in the description of the stop-info * packet. If watchpoint * is not set on this address by user then this do not stop. */ if (m_watch_hit_addr != LLDB_INVALID_ADDRESS) { WatchpointSP wp_hit_sp = thread_sp->CalculateTarget()->GetWatchpointList().FindByAddress( m_watch_hit_addr); if (!wp_hit_sp) { m_should_stop = false; wp_sp->IncrementFalseAlarmsAndReviseHitCount(); } } // TODO: This condition should be checked in the synchronous part of the // watchpoint code // (Watchpoint::ShouldStop), so that we avoid pulling an event even if // the watchpoint fails the ignore count condition. It is moved here // temporarily, because for archs with // watchpoint_exceptions_received=before, the code in the previous // lines takes care of moving the inferior to next PC. We have to check // the ignore count condition after this is done, otherwise we will hit // same watchpoint multiple times until we pass ignore condition, but // we won't actually be ignoring them. if (wp_sp->GetHitCount() <= wp_sp->GetIgnoreCount()) m_should_stop = false; Debugger &debugger = exe_ctx.GetTargetRef().GetDebugger(); if (m_should_stop && wp_sp->GetConditionText() != nullptr) { // We need to make sure the user sees any parse errors in their // condition, so we'll hook the constructor errors up to the // debugger's Async I/O. ExpressionResults result_code; EvaluateExpressionOptions expr_options; expr_options.SetUnwindOnError(true); expr_options.SetIgnoreBreakpoints(true); ValueObjectSP result_value_sp; Status error; result_code = UserExpression::Evaluate( exe_ctx, expr_options, wp_sp->GetConditionText(), llvm::StringRef(), result_value_sp, error); if (result_code == eExpressionCompleted) { if (result_value_sp) { Scalar scalar_value; if (result_value_sp->ResolveValue(scalar_value)) { if (scalar_value.ULongLong(1) == 0) { // We have been vetoed. This takes precedence over querying // the watchpoint whether it should stop (aka ignore count // and friends). See also StopInfoWatchpoint::ShouldStop() // as well as Process::ProcessEventData::DoOnRemoval(). m_should_stop = false; } else m_should_stop = true; LLDB_LOGF(log, "Condition successfully evaluated, result is %s.\n", m_should_stop ? "true" : "false"); } else { m_should_stop = true; LLDB_LOGF( log, "Failed to get an integer result from the expression."); } } } else { StreamSP error_sp = debugger.GetAsyncErrorStream(); error_sp->Printf( "Stopped due to an error evaluating condition of watchpoint "); wp_sp->GetDescription(error_sp.get(), eDescriptionLevelBrief); error_sp->Printf(": \"%s\"", wp_sp->GetConditionText()); error_sp->EOL(); const char *err_str = error.AsCString(""); LLDB_LOGF(log, "Error evaluating condition: \"%s\"\n", err_str); error_sp->PutCString(err_str); error_sp->EOL(); error_sp->Flush(); // If the condition fails to be parsed or run, we should stop. m_should_stop = true; } } // If the condition says to stop, we run the callback to further decide // whether to stop. if (m_should_stop) { // FIXME: For now the callbacks have to run in async mode - the // first time we restart we need // to get out of there. So set it here. // When we figure out how to nest watchpoint hits then this will // change. bool old_async = debugger.GetAsyncExecution(); debugger.SetAsyncExecution(true); StoppointCallbackContext context(event_ptr, exe_ctx, false); bool stop_requested = wp_sp->InvokeCallback(&context); debugger.SetAsyncExecution(old_async); // Also make sure that the callback hasn't continued the target. If // it did, when we'll set m_should_stop to false and get out of here. if (HasTargetRunSinceMe()) m_should_stop = false; if (m_should_stop && !stop_requested) { // We have been vetoed by the callback mechanism. m_should_stop = false; } } // Finally, if we are going to stop, print out the new & old values: if (m_should_stop) { wp_sp->CaptureWatchedValue(exe_ctx); Debugger &debugger = exe_ctx.GetTargetRef().GetDebugger(); StreamSP output_sp = debugger.GetAsyncOutputStream(); wp_sp->DumpSnapshots(output_sp.get()); output_sp->EOL(); output_sp->Flush(); } } else { Log *log_process( lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS)); LLDB_LOGF(log_process, "Process::%s could not find watchpoint id: %" PRId64 "...", __FUNCTION__, m_value); } LLDB_LOGF(log, "Process::%s returning from action with m_should_stop: %d.", __FUNCTION__, m_should_stop); m_should_stop_is_valid = true; } } private: bool m_should_stop; bool m_should_stop_is_valid; lldb::addr_t m_watch_hit_addr; }; // StopInfoUnixSignal class StopInfoUnixSignal : public StopInfo { public: StopInfoUnixSignal(Thread &thread, int signo, const char *description) : StopInfo(thread, signo) { SetDescription(description); } ~StopInfoUnixSignal() override = default; StopReason GetStopReason() const override { return eStopReasonSignal; } bool ShouldStopSynchronous(Event *event_ptr) override { ThreadSP thread_sp(m_thread_wp.lock()); if (thread_sp) return thread_sp->GetProcess()->GetUnixSignals()->GetShouldStop(m_value); return false; } bool ShouldStop(Event *event_ptr) override { ThreadSP thread_sp(m_thread_wp.lock()); if (thread_sp) return thread_sp->GetProcess()->GetUnixSignals()->GetShouldStop(m_value); return false; } // If should stop returns false, check if we should notify of this event bool DoShouldNotify(Event *event_ptr) override { ThreadSP thread_sp(m_thread_wp.lock()); if (thread_sp) { bool should_notify = thread_sp->GetProcess()->GetUnixSignals()->GetShouldNotify(m_value); if (should_notify) { StreamString strm; strm.Printf( "thread %d received signal: %s", thread_sp->GetIndexID(), thread_sp->GetProcess()->GetUnixSignals()->GetSignalAsCString( m_value)); Process::ProcessEventData::AddRestartedReason(event_ptr, strm.GetData()); } return should_notify; } return true; } void WillResume(lldb::StateType resume_state) override { ThreadSP thread_sp(m_thread_wp.lock()); if (thread_sp) { if (!thread_sp->GetProcess()->GetUnixSignals()->GetShouldSuppress( m_value)) thread_sp->SetResumeSignal(m_value); } } const char *GetDescription() override { if (m_description.empty()) { ThreadSP thread_sp(m_thread_wp.lock()); if (thread_sp) { StreamString strm; const char *signal_name = thread_sp->GetProcess()->GetUnixSignals()->GetSignalAsCString( m_value); if (signal_name) strm.Printf("signal %s", signal_name); else strm.Printf("signal %" PRIi64, m_value); m_description = std::string(strm.GetString()); } } return m_description.c_str(); } }; // StopInfoTrace class StopInfoTrace : public StopInfo { public: StopInfoTrace(Thread &thread) : StopInfo(thread, LLDB_INVALID_UID) {} ~StopInfoTrace() override = default; StopReason GetStopReason() const override { return eStopReasonTrace; } const char *GetDescription() override { if (m_description.empty()) return "trace"; else return m_description.c_str(); } }; // StopInfoException class StopInfoException : public StopInfo { public: StopInfoException(Thread &thread, const char *description) : StopInfo(thread, LLDB_INVALID_UID) { if (description) SetDescription(description); } ~StopInfoException() override = default; StopReason GetStopReason() const override { return eStopReasonException; } const char *GetDescription() override { if (m_description.empty()) return "exception"; else return m_description.c_str(); } }; // StopInfoThreadPlan class StopInfoThreadPlan : public StopInfo { public: StopInfoThreadPlan(ThreadPlanSP &plan_sp, ValueObjectSP &return_valobj_sp, ExpressionVariableSP &expression_variable_sp) : StopInfo(plan_sp->GetThread(), LLDB_INVALID_UID), m_plan_sp(plan_sp), m_return_valobj_sp(return_valobj_sp), m_expression_variable_sp(expression_variable_sp) {} ~StopInfoThreadPlan() override = default; StopReason GetStopReason() const override { return eStopReasonPlanComplete; } const char *GetDescription() override { if (m_description.empty()) { StreamString strm; m_plan_sp->GetDescription(&strm, eDescriptionLevelBrief); m_description = std::string(strm.GetString()); } return m_description.c_str(); } ValueObjectSP GetReturnValueObject() { return m_return_valobj_sp; } ExpressionVariableSP GetExpressionVariable() { return m_expression_variable_sp; } protected: bool ShouldStop(Event *event_ptr) override { if (m_plan_sp) return m_plan_sp->ShouldStop(event_ptr); else return StopInfo::ShouldStop(event_ptr); } private: ThreadPlanSP m_plan_sp; ValueObjectSP m_return_valobj_sp; ExpressionVariableSP m_expression_variable_sp; }; // StopInfoExec class StopInfoExec : public StopInfo { public: StopInfoExec(Thread &thread) : StopInfo(thread, LLDB_INVALID_UID), m_performed_action(false) {} ~StopInfoExec() override = default; bool ShouldStop(Event *event_ptr) override { ThreadSP thread_sp(m_thread_wp.lock()); if (thread_sp) return thread_sp->GetProcess()->GetStopOnExec(); return false; } StopReason GetStopReason() const override { return eStopReasonExec; } const char *GetDescription() override { return "exec"; } protected: void PerformAction(Event *event_ptr) override { // Only perform the action once if (m_performed_action) return; m_performed_action = true; ThreadSP thread_sp(m_thread_wp.lock()); if (thread_sp) thread_sp->GetProcess()->DidExec(); } bool m_performed_action; }; } // namespace lldb_private StopInfoSP StopInfo::CreateStopReasonWithBreakpointSiteID(Thread &thread, break_id_t break_id) { return StopInfoSP(new StopInfoBreakpoint(thread, break_id)); } StopInfoSP StopInfo::CreateStopReasonWithBreakpointSiteID(Thread &thread, break_id_t break_id, bool should_stop) { return StopInfoSP(new StopInfoBreakpoint(thread, break_id, should_stop)); } StopInfoSP StopInfo::CreateStopReasonWithWatchpointID(Thread &thread, break_id_t watch_id, lldb::addr_t watch_hit_addr) { return StopInfoSP(new StopInfoWatchpoint(thread, watch_id, watch_hit_addr)); } StopInfoSP StopInfo::CreateStopReasonWithSignal(Thread &thread, int signo, const char *description) { return StopInfoSP(new StopInfoUnixSignal(thread, signo, description)); } StopInfoSP StopInfo::CreateStopReasonToTrace(Thread &thread) { return StopInfoSP(new StopInfoTrace(thread)); } StopInfoSP StopInfo::CreateStopReasonWithPlan( ThreadPlanSP &plan_sp, ValueObjectSP return_valobj_sp, ExpressionVariableSP expression_variable_sp) { return StopInfoSP(new StopInfoThreadPlan(plan_sp, return_valobj_sp, expression_variable_sp)); } StopInfoSP StopInfo::CreateStopReasonWithException(Thread &thread, const char *description) { return StopInfoSP(new StopInfoException(thread, description)); } StopInfoSP StopInfo::CreateStopReasonWithExec(Thread &thread) { return StopInfoSP(new StopInfoExec(thread)); } ValueObjectSP StopInfo::GetReturnValueObject(StopInfoSP &stop_info_sp) { if (stop_info_sp && stop_info_sp->GetStopReason() == eStopReasonPlanComplete) { StopInfoThreadPlan *plan_stop_info = static_cast(stop_info_sp.get()); return plan_stop_info->GetReturnValueObject(); } else return ValueObjectSP(); } ExpressionVariableSP StopInfo::GetExpressionVariable(StopInfoSP &stop_info_sp) { if (stop_info_sp && stop_info_sp->GetStopReason() == eStopReasonPlanComplete) { StopInfoThreadPlan *plan_stop_info = static_cast(stop_info_sp.get()); return plan_stop_info->GetExpressionVariable(); } else return ExpressionVariableSP(); } lldb::ValueObjectSP StopInfo::GetCrashingDereference(StopInfoSP &stop_info_sp, lldb::addr_t *crashing_address) { if (!stop_info_sp) { return ValueObjectSP(); } const char *description = stop_info_sp->GetDescription(); if (!description) { return ValueObjectSP(); } ThreadSP thread_sp = stop_info_sp->GetThread(); if (!thread_sp) { return ValueObjectSP(); } StackFrameSP frame_sp = thread_sp->GetSelectedFrame(); if (!frame_sp) { return ValueObjectSP(); } const char address_string[] = "address="; const char *address_loc = strstr(description, address_string); if (!address_loc) { return ValueObjectSP(); } address_loc += (sizeof(address_string) - 1); uint64_t address = strtoull(address_loc, nullptr, 0); if (crashing_address) { *crashing_address = address; } return frame_sp->GuessValueForAddress(address); }