diff options
author | Jonas Devlieghere <jonas@devlieghere.com> | 2018-11-15 01:18:15 +0000 |
---|---|---|
committer | Jonas Devlieghere <jonas@devlieghere.com> | 2018-11-15 01:18:15 +0000 |
commit | 9fe0dd687cad8a04cec97277a7925545fb13141b (patch) | |
tree | 14c8b08570a8d3635d32ee56d9b682a18cce93ee /lldb/source | |
parent | de99818f8f46b8fd3f06e6e31b88774ab661f571 (diff) |
Add setting to require hardware breakpoints.
When debugging read-only memory we cannot use software breakpoint. We
already have support for hardware breakpoints and users can specify them
with `-H`. However, there's no option to force LLDB to use hardware
breakpoints internally, for example while stepping.
This patch adds a setting target.require-hardware-breakpoint that forces
LLDB to always use hardware breakpoints. Because hardware breakpoints
are a limited resource and can fail to resolve, this patch also extends
error handling in thread plans, where breakpoints are used for stepping.
Differential revision: https://reviews.llvm.org/D54221
Diffstat (limited to 'lldb/source')
22 files changed, 445 insertions, 192 deletions
diff --git a/lldb/source/API/SBBreakpoint.cpp b/lldb/source/API/SBBreakpoint.cpp index 11afa9946e4..b6720071e17 100644 --- a/lldb/source/API/SBBreakpoint.cpp +++ b/lldb/source/API/SBBreakpoint.cpp @@ -688,6 +688,13 @@ SBBreakpoint::GetNumBreakpointLocationsFromEvent(const lldb::SBEvent &event) { return num_locations; } +bool SBBreakpoint::IsHardware() const { + BreakpointSP bkpt_sp = GetSP(); + if (bkpt_sp) + return bkpt_sp->IsHardware(); + return false; +} + BreakpointSP SBBreakpoint::GetSP() const { return m_opaque_wp.lock(); } // This is simple collection of breakpoint id's and their target. diff --git a/lldb/source/API/SBThread.cpp b/lldb/source/API/SBThread.cpp index b7af4593add..a38b9f6a310 100644 --- a/lldb/source/API/SBThread.cpp +++ b/lldb/source/API/SBThread.cpp @@ -657,6 +657,7 @@ void SBThread::StepOver(lldb::RunMode stop_other_threads, SBError &error) { bool abort_other_plans = false; StackFrameSP frame_sp(thread->GetStackFrameAtIndex(0)); + Status new_plan_status; ThreadPlanSP new_plan_sp; if (frame_sp) { if (frame_sp->HasDebugInformation()) { @@ -664,10 +665,10 @@ void SBThread::StepOver(lldb::RunMode stop_other_threads, SBError &error) { SymbolContext sc(frame_sp->GetSymbolContext(eSymbolContextEverything)); new_plan_sp = thread->QueueThreadPlanForStepOverRange( abort_other_plans, sc.line_entry, sc, stop_other_threads, - avoid_no_debug); + new_plan_status, avoid_no_debug); } else { new_plan_sp = thread->QueueThreadPlanForStepSingleInstruction( - true, abort_other_plans, stop_other_threads); + true, abort_other_plans, stop_other_threads, new_plan_status); } } error = ResumeNewPlan(exe_ctx, new_plan_sp.get()); @@ -707,6 +708,7 @@ void SBThread::StepInto(const char *target_name, uint32_t end_line, Thread *thread = exe_ctx.GetThreadPtr(); StackFrameSP frame_sp(thread->GetStackFrameAtIndex(0)); ThreadPlanSP new_plan_sp; + Status new_plan_status; if (frame_sp && frame_sp->HasDebugInformation()) { SymbolContext sc(frame_sp->GetSymbolContext(eSymbolContextEverything)); @@ -724,13 +726,17 @@ void SBThread::StepInto(const char *target_name, uint32_t end_line, eLazyBoolCalculate; new_plan_sp = thread->QueueThreadPlanForStepInRange( abort_other_plans, range, sc, target_name, stop_other_threads, - step_in_avoids_code_without_debug_info, + new_plan_status, step_in_avoids_code_without_debug_info, step_out_avoids_code_without_debug_info); } else { new_plan_sp = thread->QueueThreadPlanForStepSingleInstruction( - false, abort_other_plans, stop_other_threads); + false, abort_other_plans, stop_other_threads, new_plan_status); } - error = ResumeNewPlan(exe_ctx, new_plan_sp.get()); + + if (new_plan_status.Success()) + error = ResumeNewPlan(exe_ctx, new_plan_sp.get()); + else + error.SetErrorString(new_plan_status.AsCString()); } void SBThread::StepOut() { @@ -759,11 +765,15 @@ void SBThread::StepOut(SBError &error) { Thread *thread = exe_ctx.GetThreadPtr(); const LazyBool avoid_no_debug = eLazyBoolCalculate; + Status new_plan_status; ThreadPlanSP new_plan_sp(thread->QueueThreadPlanForStepOut( abort_other_plans, NULL, false, stop_other_threads, eVoteYes, - eVoteNoOpinion, 0, avoid_no_debug)); + eVoteNoOpinion, 0, new_plan_status, avoid_no_debug)); - error = ResumeNewPlan(exe_ctx, new_plan_sp.get()); + if (new_plan_status.Success()) + error = ResumeNewPlan(exe_ctx, new_plan_sp.get()); + else + error.SetErrorString(new_plan_status.AsCString()); } void SBThread::StepOutOfFrame(SBFrame &sb_frame) { @@ -812,11 +822,15 @@ void SBThread::StepOutOfFrame(SBFrame &sb_frame, SBError &error) { return; } + Status new_plan_status; ThreadPlanSP new_plan_sp(thread->QueueThreadPlanForStepOut( abort_other_plans, NULL, false, stop_other_threads, eVoteYes, - eVoteNoOpinion, frame_sp->GetFrameIndex())); + eVoteNoOpinion, frame_sp->GetFrameIndex(), new_plan_status)); - error = ResumeNewPlan(exe_ctx, new_plan_sp.get()); + if (new_plan_status.Success()) + error = ResumeNewPlan(exe_ctx, new_plan_sp.get()); + else + error.SetErrorString(new_plan_status.AsCString()); } void SBThread::StepInstruction(bool step_over) { @@ -840,10 +854,14 @@ void SBThread::StepInstruction(bool step_over, SBError &error) { } Thread *thread = exe_ctx.GetThreadPtr(); - ThreadPlanSP new_plan_sp( - thread->QueueThreadPlanForStepSingleInstruction(step_over, true, true)); + Status new_plan_status; + ThreadPlanSP new_plan_sp(thread->QueueThreadPlanForStepSingleInstruction( + step_over, true, true, new_plan_status)); - error = ResumeNewPlan(exe_ctx, new_plan_sp.get()); + if (new_plan_status.Success()) + error = ResumeNewPlan(exe_ctx, new_plan_sp.get()); + else + error.SetErrorString(new_plan_status.AsCString()); } void SBThread::RunToAddress(lldb::addr_t addr) { @@ -873,10 +891,14 @@ void SBThread::RunToAddress(lldb::addr_t addr, SBError &error) { Thread *thread = exe_ctx.GetThreadPtr(); + Status new_plan_status; ThreadPlanSP new_plan_sp(thread->QueueThreadPlanForRunToAddress( - abort_other_plans, target_addr, stop_other_threads)); + abort_other_plans, target_addr, stop_other_threads, new_plan_status)); - error = ResumeNewPlan(exe_ctx, new_plan_sp.get()); + if (new_plan_status.Success()) + error = ResumeNewPlan(exe_ctx, new_plan_sp.get()); + else + error.SetErrorString(new_plan_status.AsCString()); } SBError SBThread::StepOverUntil(lldb::SBFrame &sb_frame, @@ -988,12 +1010,16 @@ SBError SBThread::StepOverUntil(lldb::SBFrame &sb_frame, } else sb_error.SetErrorString("step until target not in current function"); } else { + Status new_plan_status; ThreadPlanSP new_plan_sp(thread->QueueThreadPlanForStepUntil( abort_other_plans, &step_over_until_addrs[0], step_over_until_addrs.size(), stop_other_threads, - frame_sp->GetFrameIndex())); + frame_sp->GetFrameIndex(), new_plan_status)); - sb_error = ResumeNewPlan(exe_ctx, new_plan_sp.get()); + if (new_plan_status.Success()) + sb_error = ResumeNewPlan(exe_ctx, new_plan_sp.get()); + else + sb_error.SetErrorString(new_plan_status.AsCString()); } } else { sb_error.SetErrorString("this SBThread object is invalid"); @@ -1008,7 +1034,7 @@ SBError SBThread::StepUsingScriptedThreadPlan(const char *script_class_name) { SBError SBThread::StepUsingScriptedThreadPlan(const char *script_class_name, bool resume_immediately) { Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_API)); - SBError sb_error; + SBError error; std::unique_lock<std::recursive_mutex> lock; ExecutionContext exe_ctx(m_opaque_sp.get(), lock); @@ -1019,37 +1045,29 @@ SBError SBThread::StepUsingScriptedThreadPlan(const char *script_class_name, } if (!exe_ctx.HasThreadScope()) { - sb_error.SetErrorString("this SBThread object is invalid"); - return sb_error; + error.SetErrorString("this SBThread object is invalid"); + return error; } Thread *thread = exe_ctx.GetThreadPtr(); - ThreadPlanSP thread_plan_sp = - thread->QueueThreadPlanForStepScripted(false, script_class_name, false); + Status new_plan_status; + ThreadPlanSP new_plan_sp = thread->QueueThreadPlanForStepScripted( + false, script_class_name, false, new_plan_status); - if (!thread_plan_sp) { - sb_error.SetErrorStringWithFormat( - "Error queueing thread plan for class: %s", script_class_name); - return sb_error; + if (new_plan_status.Fail()) { + error.SetErrorString(new_plan_status.AsCString()); + return error; } - if (!resume_immediately) { - return sb_error; - } + if (!resume_immediately) + return error; - if (thread_plan_sp) - sb_error = ResumeNewPlan(exe_ctx, thread_plan_sp.get()); - else { - sb_error.SetErrorStringWithFormat( - "Error resuming thread plan for class: %s.", script_class_name); - if (log) - log->Printf("SBThread(%p)::StepUsingScriptedThreadPlan: Error queuing " - "thread plan for class: %s", - static_cast<void *>(exe_ctx.GetThreadPtr()), - script_class_name); - } + if (new_plan_status.Success()) + error = ResumeNewPlan(exe_ctx, new_plan_sp.get()); + else + error.SetErrorString(new_plan_status.AsCString()); - return sb_error; + return error; } SBError SBThread::JumpToLine(lldb::SBFileSpec &file_spec, uint32_t line) { diff --git a/lldb/source/API/SBThreadPlan.cpp b/lldb/source/API/SBThreadPlan.cpp index c15c39aab51..fc54f5b5f87 100644 --- a/lldb/source/API/SBThreadPlan.cpp +++ b/lldb/source/API/SBThreadPlan.cpp @@ -143,6 +143,12 @@ bool SBThreadPlan::IsValid() { SBThreadPlan SBThreadPlan::QueueThreadPlanForStepOverRange(SBAddress &sb_start_address, lldb::addr_t size) { + SBError error; + return QueueThreadPlanForStepOverRange(sb_start_address, size, error); +} + +SBThreadPlan SBThreadPlan::QueueThreadPlanForStepOverRange( + SBAddress &sb_start_address, lldb::addr_t size, SBError &error) { if (m_opaque_sp) { Address *start_address = sb_start_address.get(); if (!start_address) { @@ -152,9 +158,16 @@ SBThreadPlan::QueueThreadPlanForStepOverRange(SBAddress &sb_start_address, AddressRange range(*start_address, size); SymbolContext sc; start_address->CalculateSymbolContext(&sc); - return SBThreadPlan( - m_opaque_sp->GetThread().QueueThreadPlanForStepOverRange( - false, range, sc, eAllThreads)); + Status plan_status; + + SBThreadPlan plan = + SBThreadPlan(m_opaque_sp->GetThread().QueueThreadPlanForStepOverRange( + false, range, sc, eAllThreads, plan_status)); + + if (plan_status.Fail()) + error.SetErrorString(plan_status.AsCString()); + + return plan; } else { return SBThreadPlan(); } @@ -163,6 +176,13 @@ SBThreadPlan::QueueThreadPlanForStepOverRange(SBAddress &sb_start_address, SBThreadPlan SBThreadPlan::QueueThreadPlanForStepInRange(SBAddress &sb_start_address, lldb::addr_t size) { + SBError error; + return QueueThreadPlanForStepInRange(sb_start_address, size, error); +} + +SBThreadPlan +SBThreadPlan::QueueThreadPlanForStepInRange(SBAddress &sb_start_address, + lldb::addr_t size, SBError &error) { if (m_opaque_sp) { Address *start_address = sb_start_address.get(); if (!start_address) { @@ -172,8 +192,16 @@ SBThreadPlan::QueueThreadPlanForStepInRange(SBAddress &sb_start_address, AddressRange range(*start_address, size); SymbolContext sc; start_address->CalculateSymbolContext(&sc); - return SBThreadPlan(m_opaque_sp->GetThread().QueueThreadPlanForStepInRange( - false, range, sc, NULL, eAllThreads)); + + Status plan_status; + SBThreadPlan plan = + SBThreadPlan(m_opaque_sp->GetThread().QueueThreadPlanForStepInRange( + false, range, sc, NULL, eAllThreads, plan_status)); + + if (plan_status.Fail()) + error.SetErrorString(plan_status.AsCString()); + + return plan; } else { return SBThreadPlan(); } @@ -182,13 +210,28 @@ SBThreadPlan::QueueThreadPlanForStepInRange(SBAddress &sb_start_address, SBThreadPlan SBThreadPlan::QueueThreadPlanForStepOut(uint32_t frame_idx_to_step_to, bool first_insn) { + SBError error; + return QueueThreadPlanForStepOut(frame_idx_to_step_to, first_insn, error); +} + +SBThreadPlan +SBThreadPlan::QueueThreadPlanForStepOut(uint32_t frame_idx_to_step_to, + bool first_insn, SBError &error) { if (m_opaque_sp) { SymbolContext sc; sc = m_opaque_sp->GetThread().GetStackFrameAtIndex(0)->GetSymbolContext( lldb::eSymbolContextEverything); - return SBThreadPlan(m_opaque_sp->GetThread().QueueThreadPlanForStepOut( - false, &sc, first_insn, false, eVoteYes, eVoteNoOpinion, - frame_idx_to_step_to)); + + Status plan_status; + SBThreadPlan plan = + SBThreadPlan(m_opaque_sp->GetThread().QueueThreadPlanForStepOut( + false, &sc, first_insn, false, eVoteYes, eVoteNoOpinion, + frame_idx_to_step_to, plan_status)); + + if (plan_status.Fail()) + error.SetErrorString(plan_status.AsCString()); + + return plan; } else { return SBThreadPlan(); } @@ -196,13 +239,26 @@ SBThreadPlan::QueueThreadPlanForStepOut(uint32_t frame_idx_to_step_to, SBThreadPlan SBThreadPlan::QueueThreadPlanForRunToAddress(SBAddress sb_address) { + SBError error; + return QueueThreadPlanForRunToAddress(sb_address, error); +} + +SBThreadPlan SBThreadPlan::QueueThreadPlanForRunToAddress(SBAddress sb_address, + SBError &error) { if (m_opaque_sp) { Address *address = sb_address.get(); if (!address) return SBThreadPlan(); - return SBThreadPlan(m_opaque_sp->GetThread().QueueThreadPlanForRunToAddress( - false, *address, false)); + Status plan_status; + SBThreadPlan plan = + SBThreadPlan(m_opaque_sp->GetThread().QueueThreadPlanForRunToAddress( + false, *address, false, plan_status)); + + if (plan_status.Fail()) + error.SetErrorString(plan_status.AsCString()); + + return plan; } else { return SBThreadPlan(); } @@ -210,9 +266,23 @@ SBThreadPlan::QueueThreadPlanForRunToAddress(SBAddress sb_address) { SBThreadPlan SBThreadPlan::QueueThreadPlanForStepScripted(const char *script_class_name) { + SBError error; + return QueueThreadPlanForStepScripted(script_class_name, error); +} + +SBThreadPlan +SBThreadPlan::QueueThreadPlanForStepScripted(const char *script_class_name, + SBError &error) { if (m_opaque_sp) { - return SBThreadPlan(m_opaque_sp->GetThread().QueueThreadPlanForStepScripted( - false, script_class_name, false)); + Status plan_status; + SBThreadPlan plan = + SBThreadPlan(m_opaque_sp->GetThread().QueueThreadPlanForStepScripted( + false, script_class_name, false, plan_status)); + + if (plan_status.Fail()) + error.SetErrorString(plan_status.AsCString()); + + return plan; } else { return SBThreadPlan(); } diff --git a/lldb/source/Breakpoint/Breakpoint.cpp b/lldb/source/Breakpoint/Breakpoint.cpp index 6ee8a48ea07..131d2a707d4 100644 --- a/lldb/source/Breakpoint/Breakpoint.cpp +++ b/lldb/source/Breakpoint/Breakpoint.cpp @@ -853,6 +853,10 @@ size_t Breakpoint::GetNumResolvedLocations() const { return m_locations.GetNumResolvedLocations(); } +bool Breakpoint::HasResolvedLocations() const { + return GetNumResolvedLocations() > 0; +} + size_t Breakpoint::GetNumLocations() const { return m_locations.GetSize(); } bool Breakpoint::AddName(llvm::StringRef new_name) { diff --git a/lldb/source/Commands/CommandObjectThread.cpp b/lldb/source/Commands/CommandObjectThread.cpp index 94cba9da696..95c5666a56f 100644 --- a/lldb/source/Commands/CommandObjectThread.cpp +++ b/lldb/source/Commands/CommandObjectThread.cpp @@ -650,6 +650,7 @@ protected: bool_stop_other_threads = true; ThreadPlanSP new_plan_sp; + Status new_plan_status; if (m_step_type == eStepTypeInto) { StackFrame *frame = thread->GetStackFrameAtIndex(0).get(); @@ -699,7 +700,7 @@ protected: abort_other_plans, range, frame->GetSymbolContext(eSymbolContextEverything), m_options.m_step_in_target.c_str(), stop_other_threads, - m_options.m_step_in_avoid_no_debug, + new_plan_status, m_options.m_step_in_avoid_no_debug, m_options.m_step_out_avoid_no_debug); if (new_plan_sp && !m_options.m_avoid_regexp.empty()) { @@ -709,7 +710,7 @@ protected: } } else new_plan_sp = thread->QueueThreadPlanForStepSingleInstruction( - false, abort_other_plans, bool_stop_other_threads); + false, abort_other_plans, bool_stop_other_threads, new_plan_status); } else if (m_step_type == eStepTypeOver) { StackFrame *frame = thread->GetStackFrameAtIndex(0).get(); @@ -718,25 +719,26 @@ protected: abort_other_plans, frame->GetSymbolContext(eSymbolContextEverything).line_entry, frame->GetSymbolContext(eSymbolContextEverything), - stop_other_threads, m_options.m_step_out_avoid_no_debug); + stop_other_threads, new_plan_status, + m_options.m_step_out_avoid_no_debug); else new_plan_sp = thread->QueueThreadPlanForStepSingleInstruction( - true, abort_other_plans, bool_stop_other_threads); + true, abort_other_plans, bool_stop_other_threads, new_plan_status); } else if (m_step_type == eStepTypeTrace) { new_plan_sp = thread->QueueThreadPlanForStepSingleInstruction( - false, abort_other_plans, bool_stop_other_threads); + false, abort_other_plans, bool_stop_other_threads, new_plan_status); } else if (m_step_type == eStepTypeTraceOver) { new_plan_sp = thread->QueueThreadPlanForStepSingleInstruction( - true, abort_other_plans, bool_stop_other_threads); + true, abort_other_plans, bool_stop_other_threads, new_plan_status); } else if (m_step_type == eStepTypeOut) { new_plan_sp = thread->QueueThreadPlanForStepOut( abort_other_plans, nullptr, false, bool_stop_other_threads, eVoteYes, - eVoteNoOpinion, thread->GetSelectedFrameIndex(), + eVoteNoOpinion, thread->GetSelectedFrameIndex(), new_plan_status, m_options.m_step_out_avoid_no_debug); } else if (m_step_type == eStepTypeScripted) { new_plan_sp = thread->QueueThreadPlanForStepScripted( abort_other_plans, m_options.m_class_name.c_str(), - bool_stop_other_threads); + bool_stop_other_threads, new_plan_status); } else { result.AppendError("step type is not supported"); result.SetStatus(eReturnStatusFailed); @@ -794,7 +796,7 @@ protected: result.SetStatus(eReturnStatusSuccessContinuingNoResult); } } else { - result.AppendError("Couldn't find thread plan to implement step type."); + result.SetError(new_plan_status); result.SetStatus(eReturnStatusFailed); } return result.Succeeded(); @@ -1190,6 +1192,7 @@ protected: } ThreadPlanSP new_plan_sp; + Status new_plan_status; if (frame->HasDebugInformation()) { // Finally we got here... Translate the given line number to a bunch @@ -1270,13 +1273,19 @@ protected: new_plan_sp = thread->QueueThreadPlanForStepUntil( abort_other_plans, &address_list.front(), address_list.size(), - m_options.m_stop_others, m_options.m_frame_idx); - // User level plans should be master plans so they can be interrupted - // (e.g. by hitting a breakpoint) and other plans executed by the user - // (stepping around the breakpoint) and then a "continue" will resume - // the original plan. - new_plan_sp->SetIsMasterPlan(true); - new_plan_sp->SetOkayToDiscard(false); + m_options.m_stop_others, m_options.m_frame_idx, new_plan_status); + if (new_plan_sp) { + // User level plans should be master plans so they can be interrupted + // (e.g. by hitting a breakpoint) and other plans executed by the + // user (stepping around the breakpoint) and then a "continue" will + // resume the original plan. + new_plan_sp->SetIsMasterPlan(true); + new_plan_sp->SetOkayToDiscard(false); + } else { + result.SetError(new_plan_status); + result.SetStatus(eReturnStatusFailed); + return false; + } } else { result.AppendErrorWithFormat( "Frame index %u of thread %u has no debug information.\n", diff --git a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleThreadPlanStepThroughObjCTrampoline.cpp b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleThreadPlanStepThroughObjCTrampoline.cpp index d19ab445d4f..19d9676e8b0 100644 --- a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleThreadPlanStepThroughObjCTrampoline.cpp +++ b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleThreadPlanStepThroughObjCTrampoline.cpp @@ -157,13 +157,15 @@ bool AppleThreadPlanStepThroughObjCTrampoline::ShouldStop(Event *event_ptr) { SymbolContext sc = m_thread.GetStackFrameAtIndex(0)->GetSymbolContext( eSymbolContextEverything); + Status status; const bool abort_other_plans = false; const bool first_insn = true; const uint32_t frame_idx = 0; m_run_to_sp = m_thread.QueueThreadPlanForStepOutNoShouldStop( abort_other_plans, &sc, first_insn, m_stop_others, eVoteNoOpinion, - eVoteNoOpinion, frame_idx); - m_run_to_sp->SetPrivate(true); + eVoteNoOpinion, frame_idx, status); + if (m_run_to_sp && status.Success()) + m_run_to_sp->SetPrivate(true); return false; } diff --git a/lldb/source/Target/Process.cpp b/lldb/source/Target/Process.cpp index b80c9eb699b..7ec772b079e 100644 --- a/lldb/source/Target/Process.cpp +++ b/lldb/source/Target/Process.cpp @@ -1920,7 +1920,7 @@ Process::CreateBreakpointSite(const BreakpointLocationSP &owner, owner->SetBreakpointSite(bp_site_sp); return m_breakpoint_site_list.Add(bp_site_sp); } else { - if (show_error) { + if (show_error || use_hardware) { // Report error for setting breakpoint... GetTarget().GetDebugger().GetErrorFile()->Printf( "warning: failed to set breakpoint site at 0x%" PRIx64 diff --git a/lldb/source/Target/StopInfo.cpp b/lldb/source/Target/StopInfo.cpp index 1e885bdabc8..6965f585615 100644 --- a/lldb/source/Target/StopInfo.cpp +++ b/lldb/source/Target/StopInfo.cpp @@ -716,14 +716,18 @@ protected: 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_sp->SetIsMasterPlan(true); - new_plan_sp->SetOkayToDiscard(false); - new_plan_sp->SetPrivate(true); + 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); diff --git a/lldb/source/Target/Target.cpp b/lldb/source/Target/Target.cpp index c8fea3790c2..fe46c7b7d5d 100644 --- a/lldb/source/Target/Target.cpp +++ b/lldb/source/Target/Target.cpp @@ -627,7 +627,8 @@ BreakpointSP Target::CreateBreakpoint(SearchFilterSP &filter_sp, bool resolve_indirect_symbols) { BreakpointSP bp_sp; if (filter_sp && resolver_sp) { - bp_sp.reset(new Breakpoint(*this, filter_sp, resolver_sp, request_hardware, + const bool hardware = request_hardware || GetRequireHardwareBreakpoints(); + bp_sp.reset(new Breakpoint(*this, filter_sp, resolver_sp, hardware, resolve_indirect_symbols)); resolver_sp->SetBreakpoint(bp_sp.get()); AddBreakpoint(bp_sp, internal); @@ -3135,6 +3136,7 @@ void Target::StopHook::GetDescription(Stream *s, // class TargetProperties //-------------------------------------------------------------- +// clang-format off static constexpr OptionEnumValueElement g_dynamic_value_types[] = { {eNoDynamicValues, "no-dynamic-values", "Don't calculate the dynamic type of values"}, @@ -3362,7 +3364,10 @@ static constexpr PropertyDefinition g_properties[] = { nullptr, {}, "If true, LLDB will show variables that are meant to " "support the operation of a language's runtime support."}, {"non-stop-mode", OptionValue::eTypeBoolean, false, 0, nullptr, {}, - "Disable lock-step debugging, instead control threads independently."}}; + "Disable lock-step debugging, instead control threads independently."}, + {"require-hardware-breakpoint", OptionValue::eTypeBoolean, false, 0, + nullptr, {}, "Require all breakpoints to be hardware breakpoints."}}; +// clang-format on enum { ePropertyDefaultArch, @@ -3407,7 +3412,8 @@ enum { ePropertyTrapHandlerNames, ePropertyDisplayRuntimeSupportValues, ePropertyNonStopModeEnabled, - ePropertyExperimental + ePropertyRequireHardwareBreakpoints, + ePropertyExperimental, }; class TargetOptionValueProperties : public OptionValueProperties { @@ -4005,6 +4011,17 @@ void TargetProperties::SetProcessLaunchInfo( SetDisableSTDIO(launch_info.GetFlags().Test(lldb::eLaunchFlagDisableSTDIO)); } +bool TargetProperties::GetRequireHardwareBreakpoints() const { + const uint32_t idx = ePropertyRequireHardwareBreakpoints; + return m_collection_sp->GetPropertyAtIndexAsBoolean( + nullptr, idx, g_properties[idx].default_uint_value != 0); +} + +void TargetProperties::SetRequireHardwareBreakpoints(bool b) { + const uint32_t idx = ePropertyRequireHardwareBreakpoints; + m_collection_sp->SetPropertyAtIndexAsBoolean(nullptr, idx, b); +} + void TargetProperties::Arg0ValueChangedCallback(void *target_property_ptr, OptionValue *) { TargetProperties *this_ = diff --git a/lldb/source/Target/Thread.cpp b/lldb/source/Target/Thread.cpp index 0cd3ed61456..404847eabe0 100644 --- a/lldb/source/Target/Thread.cpp +++ b/lldb/source/Target/Thread.cpp @@ -262,6 +262,7 @@ Thread::Thread(Process &process, lldb::tid_t tid, bool use_invalid_index_id) static_cast<void *>(this), GetID()); CheckInWithManager(); + QueueFundamentalPlan(true); } @@ -395,13 +396,14 @@ lldb::StopInfoSP Thread::GetStopInfo() { m_stop_info_sp ->IsValid() && m_stop_info_stop_id == stop_id; bool have_valid_completed_plan = completed_plan_sp && completed_plan_sp->PlanSucceeded(); + bool plan_failed = completed_plan_sp && !completed_plan_sp->PlanSucceeded(); bool plan_overrides_trace = have_valid_stop_info && have_valid_completed_plan && (m_stop_info_sp->GetStopReason() == eStopReasonTrace); - if (have_valid_stop_info && !plan_overrides_trace) { + if (have_valid_stop_info && !plan_overrides_trace && !plan_failed) { return m_stop_info_sp; - } else if (have_valid_completed_plan) { + } else if (completed_plan_sp) { return StopInfo::CreateStopReasonWithPlan( completed_plan_sp, GetReturnValueObject(), GetExpressionVariable()); } else { @@ -1173,12 +1175,34 @@ ThreadPlan *Thread::GetPreviousPlan(ThreadPlan *current_plan) { return nullptr; } -void Thread::QueueThreadPlan(ThreadPlanSP &thread_plan_sp, - bool abort_other_plans) { +Status Thread::QueueThreadPlan(ThreadPlanSP &thread_plan_sp, + bool abort_other_plans) { + Status status; + StreamString s; + if (!thread_plan_sp->ValidatePlan(&s)) { + DiscardThreadPlansUpToPlan(thread_plan_sp); + thread_plan_sp.reset(); + status.SetErrorString(s.GetString()); + return status; + } + if (abort_other_plans) DiscardThreadPlans(true); PushPlan(thread_plan_sp); + + // This seems a little funny, but I don't want to have to split up the + // constructor and the DidPush in the scripted plan, that seems annoying. + // That means the constructor has to be in DidPush. So I have to validate the + // plan AFTER pushing it, and then take it off again... + if (!thread_plan_sp->ValidatePlan(&s)) { + DiscardThreadPlansUpToPlan(thread_plan_sp); + thread_plan_sp.reset(); + status.SetErrorString(s.GetString()); + return status; + } + + return status; } void Thread::EnableTracer(bool value, bool single_stepping) { @@ -1343,23 +1367,24 @@ ThreadPlanSP Thread::QueueFundamentalPlan(bool abort_other_plans) { } ThreadPlanSP Thread::QueueThreadPlanForStepSingleInstruction( - bool step_over, bool abort_other_plans, bool stop_other_threads) { + bool step_over, bool abort_other_plans, bool stop_other_threads, + Status &status) { ThreadPlanSP thread_plan_sp(new ThreadPlanStepInstruction( *this, step_over, stop_other_threads, eVoteNoOpinion, eVoteNoOpinion)); - QueueThreadPlan(thread_plan_sp, abort_other_plans); + status = QueueThreadPlan(thread_plan_sp, abort_other_plans); return thread_plan_sp; } ThreadPlanSP Thread::QueueThreadPlanForStepOverRange( bool abort_other_plans, const AddressRange &range, const SymbolContext &addr_context, lldb::RunMode stop_other_threads, - LazyBool step_out_avoids_code_withoug_debug_info) { + Status &status, LazyBool step_out_avoids_code_withoug_debug_info) { ThreadPlanSP thread_plan_sp; thread_plan_sp.reset(new ThreadPlanStepOverRange( *this, range, addr_context, stop_other_threads, step_out_avoids_code_withoug_debug_info)); - QueueThreadPlan(thread_plan_sp, abort_other_plans); + status = QueueThreadPlan(thread_plan_sp, abort_other_plans); return thread_plan_sp; } @@ -1368,17 +1393,17 @@ ThreadPlanSP Thread::QueueThreadPlanForStepOverRange( ThreadPlanSP Thread::QueueThreadPlanForStepOverRange( bool abort_other_plans, const LineEntry &line_entry, const SymbolContext &addr_context, lldb::RunMode stop_other_threads, - LazyBool step_out_avoids_code_withoug_debug_info) { + Status &status, LazyBool step_out_avoids_code_withoug_debug_info) { return QueueThreadPlanForStepOverRange( abort_other_plans, line_entry.GetSameLineContiguousAddressRange(), - addr_context, stop_other_threads, + addr_context, stop_other_threads, status, step_out_avoids_code_withoug_debug_info); } ThreadPlanSP Thread::QueueThreadPlanForStepInRange( bool abort_other_plans, const AddressRange &range, const SymbolContext &addr_context, const char *step_in_target, - lldb::RunMode stop_other_threads, + lldb::RunMode stop_other_threads, Status &status, LazyBool step_in_avoids_code_without_debug_info, LazyBool step_out_avoids_code_without_debug_info) { ThreadPlanSP thread_plan_sp( @@ -1391,7 +1416,7 @@ ThreadPlanSP Thread::QueueThreadPlanForStepInRange( if (step_in_target) plan->SetStepInTarget(step_in_target); - QueueThreadPlan(thread_plan_sp, abort_other_plans); + status = QueueThreadPlan(thread_plan_sp, abort_other_plans); return thread_plan_sp; } @@ -1399,12 +1424,12 @@ ThreadPlanSP Thread::QueueThreadPlanForStepInRange( ThreadPlanSP Thread::QueueThreadPlanForStepInRange( bool abort_other_plans, const LineEntry &line_entry, const SymbolContext &addr_context, const char *step_in_target, - lldb::RunMode stop_other_threads, + lldb::RunMode stop_other_threads, Status &status, LazyBool step_in_avoids_code_without_debug_info, LazyBool step_out_avoids_code_without_debug_info) { return QueueThreadPlanForStepInRange( abort_other_plans, line_entry.GetSameLineContiguousAddressRange(), - addr_context, step_in_target, stop_other_threads, + addr_context, step_in_target, stop_other_threads, status, step_in_avoids_code_without_debug_info, step_out_avoids_code_without_debug_info); } @@ -1412,23 +1437,19 @@ ThreadPlanSP Thread::QueueThreadPlanForStepInRange( ThreadPlanSP Thread::QueueThreadPlanForStepOut( bool abort_other_plans, SymbolContext *addr_context, bool first_insn, bool stop_other_threads, Vote stop_vote, Vote run_vote, uint32_t frame_idx, - LazyBool step_out_avoids_code_without_debug_info) { + Status &status, LazyBool step_out_avoids_code_without_debug_info) { ThreadPlanSP thread_plan_sp(new ThreadPlanStepOut( *this, addr_context, first_insn, stop_other_threads, stop_vote, run_vote, frame_idx, step_out_avoids_code_without_debug_info)); - if (thread_plan_sp->ValidatePlan(nullptr)) { - QueueThreadPlan(thread_plan_sp, abort_other_plans); - return thread_plan_sp; - } else { - return ThreadPlanSP(); - } + status = QueueThreadPlan(thread_plan_sp, abort_other_plans); + return thread_plan_sp; } ThreadPlanSP Thread::QueueThreadPlanForStepOutNoShouldStop( bool abort_other_plans, SymbolContext *addr_context, bool first_insn, bool stop_other_threads, Vote stop_vote, Vote run_vote, uint32_t frame_idx, - bool continue_to_next_branch) { + Status &status, bool continue_to_next_branch) { const bool calculate_return_value = false; // No need to calculate the return value here. ThreadPlanSP thread_plan_sp(new ThreadPlanStepOut( @@ -1439,59 +1460,51 @@ ThreadPlanSP Thread::QueueThreadPlanForStepOutNoShouldStop( static_cast<ThreadPlanStepOut *>(thread_plan_sp.get()); new_plan->ClearShouldStopHereCallbacks(); - if (thread_plan_sp->ValidatePlan(nullptr)) { - QueueThreadPlan(thread_plan_sp, abort_other_plans); - return thread_plan_sp; - } else { - return ThreadPlanSP(); - } + status = QueueThreadPlan(thread_plan_sp, abort_other_plans); + return thread_plan_sp; } ThreadPlanSP Thread::QueueThreadPlanForStepThrough(StackID &return_stack_id, bool abort_other_plans, - bool stop_other_threads) { + bool stop_other_threads, + Status &status) { ThreadPlanSP thread_plan_sp( new ThreadPlanStepThrough(*this, return_stack_id, stop_other_threads)); if (!thread_plan_sp || !thread_plan_sp->ValidatePlan(nullptr)) return ThreadPlanSP(); - QueueThreadPlan(thread_plan_sp, abort_other_plans); + status = QueueThreadPlan(thread_plan_sp, abort_other_plans); return thread_plan_sp; } ThreadPlanSP Thread::QueueThreadPlanForRunToAddress(bool abort_other_plans, Address &target_addr, - bool stop_other_threads) { + bool stop_other_threads, + Status &status) { ThreadPlanSP thread_plan_sp( new ThreadPlanRunToAddress(*this, target_addr, stop_other_threads)); - QueueThreadPlan(thread_plan_sp, abort_other_plans); + + status = QueueThreadPlan(thread_plan_sp, abort_other_plans); return thread_plan_sp; } -ThreadPlanSP Thread::QueueThreadPlanForStepUntil(bool abort_other_plans, - lldb::addr_t *address_list, - size_t num_addresses, - bool stop_other_threads, - uint32_t frame_idx) { +ThreadPlanSP Thread::QueueThreadPlanForStepUntil( + bool abort_other_plans, lldb::addr_t *address_list, size_t num_addresses, + bool stop_other_threads, uint32_t frame_idx, Status &status) { ThreadPlanSP thread_plan_sp(new ThreadPlanStepUntil( *this, address_list, num_addresses, stop_other_threads, frame_idx)); - QueueThreadPlan(thread_plan_sp, abort_other_plans); + + status = QueueThreadPlan(thread_plan_sp, abort_other_plans); return thread_plan_sp; } lldb::ThreadPlanSP Thread::QueueThreadPlanForStepScripted( - bool abort_other_plans, const char *class_name, bool stop_other_threads) { + bool abort_other_plans, const char *class_name, bool stop_other_threads, + Status &status) { ThreadPlanSP thread_plan_sp(new ThreadPlanPython(*this, class_name)); - QueueThreadPlan(thread_plan_sp, abort_other_plans); - // This seems a little funny, but I don't want to have to split up the - // constructor and the DidPush in the scripted plan, that seems annoying. - // That means the constructor has to be in DidPush. So I have to validate the - // plan AFTER pushing it, and then take it off again... - if (!thread_plan_sp->ValidatePlan(nullptr)) { - DiscardThreadPlansUpToPlan(thread_plan_sp); - return ThreadPlanSP(); - } else - return thread_plan_sp; + + status = QueueThreadPlan(thread_plan_sp, abort_other_plans); + return thread_plan_sp; } uint32_t Thread::GetIndexID() const { return m_index_id; } @@ -2110,12 +2123,12 @@ Status Thread::StepIn(bool source_step, if (source_step && frame_sp && frame_sp->HasDebugInformation()) { SymbolContext sc(frame_sp->GetSymbolContext(eSymbolContextEverything)); new_plan_sp = QueueThreadPlanForStepInRange( - abort_other_plans, sc.line_entry, sc, nullptr, run_mode, + abort_other_plans, sc.line_entry, sc, nullptr, run_mode, error, step_in_avoids_code_without_debug_info, step_out_avoids_code_without_debug_info); } else { new_plan_sp = QueueThreadPlanForStepSingleInstruction( - false, abort_other_plans, run_mode); + false, abort_other_plans, run_mode, error); } new_plan_sp->SetIsMasterPlan(true); @@ -2144,11 +2157,11 @@ Status Thread::StepOver(bool source_step, if (source_step && frame_sp && frame_sp->HasDebugInformation()) { SymbolContext sc(frame_sp->GetSymbolContext(eSymbolContextEverything)); new_plan_sp = QueueThreadPlanForStepOverRange( - abort_other_plans, sc.line_entry, sc, run_mode, + abort_other_plans, sc.line_entry, sc, run_mode, error, step_out_avoids_code_without_debug_info); } else { new_plan_sp = QueueThreadPlanForStepSingleInstruction( - true, abort_other_plans, run_mode); + true, abort_other_plans, run_mode, error); } new_plan_sp->SetIsMasterPlan(true); @@ -2173,7 +2186,7 @@ Status Thread::StepOut() { ThreadPlanSP new_plan_sp(QueueThreadPlanForStepOut( abort_other_plans, nullptr, first_instruction, stop_other_threads, - eVoteYes, eVoteNoOpinion, 0)); + eVoteYes, eVoteNoOpinion, 0, error)); new_plan_sp->SetIsMasterPlan(true); new_plan_sp->SetOkayToDiscard(false); diff --git a/lldb/source/Target/ThreadPlan.cpp b/lldb/source/Target/ThreadPlan.cpp index 1216bb51d55..1f2c69c6e8a 100644 --- a/lldb/source/Target/ThreadPlan.cpp +++ b/lldb/source/Target/ThreadPlan.cpp @@ -25,6 +25,7 @@ using namespace lldb_private; ThreadPlan::ThreadPlan(ThreadPlanKind kind, const char *name, Thread &thread, Vote stop_vote, Vote run_vote) : m_thread(thread), m_stop_vote(stop_vote), m_run_vote(run_vote), + m_takes_iteration_count(false), m_could_not_resolve_hw_bp(false), m_kind(kind), m_name(name), m_plan_complete_mutex(), m_cached_plan_explains_stop(eLazyBoolCalculate), m_plan_complete(false), m_plan_private(false), m_okay_to_discard(true), m_is_master_plan(false), diff --git a/lldb/source/Target/ThreadPlanCallOnFunctionExit.cpp b/lldb/source/Target/ThreadPlanCallOnFunctionExit.cpp index e8ea73f3c6a..2ea083dac45 100644 --- a/lldb/source/Target/ThreadPlanCallOnFunctionExit.cpp +++ b/lldb/source/Target/ThreadPlanCallOnFunctionExit.cpp @@ -27,17 +27,18 @@ void ThreadPlanCallOnFunctionExit::DidPush() { // completes. // Set stop vote to eVoteNo. + Status status; m_step_out_threadplan_sp = GetThread().QueueThreadPlanForStepOut( false, // abort other plans nullptr, // addr_context true, // first instruction true, // stop other threads eVoteNo, // do not say "we're stopping" - eVoteNoOpinion, // don't care about - // run state broadcasting + eVoteNoOpinion, // don't care about run state broadcasting 0, // frame_idx + status, // status eLazyBoolCalculate // avoid code w/o debinfo - ); + ); } // ------------------------------------------------------------------------- diff --git a/lldb/source/Target/ThreadPlanPython.cpp b/lldb/source/Target/ThreadPlanPython.cpp index 8db443b95b2..84b93bdc658 100644 --- a/lldb/source/Target/ThreadPlanPython.cpp +++ b/lldb/source/Target/ThreadPlanPython.cpp @@ -31,7 +31,7 @@ using namespace lldb_private; ThreadPlanPython::ThreadPlanPython(Thread &thread, const char *class_name) : ThreadPlan(ThreadPlan::eKindPython, "Python based Thread Plan", thread, eVoteNoOpinion, eVoteNoOpinion), - m_class_name(class_name) { + m_class_name(class_name), m_did_push(false) { SetIsMasterPlan(true); SetOkayToDiscard(true); SetPrivate(false); @@ -43,20 +43,22 @@ ThreadPlanPython::~ThreadPlanPython() { } bool ThreadPlanPython::ValidatePlan(Stream *error) { - // I have to postpone setting up the implementation till after the constructor - // because I need to call - // shared_from_this, which you can't do in the constructor. So I'll do it - // here. - if (m_implementation_sp) + if (!m_did_push) return true; - else + + if (!m_implementation_sp) { + if (error) + error->Printf("Python thread plan does not have an implementation"); return false; + } + + return true; } void ThreadPlanPython::DidPush() { // We set up the script side in DidPush, so that it can push other plans in // the constructor, and doesn't have to care about the details of DidPush. - + m_did_push = true; if (!m_class_name.empty()) { ScriptInterpreter *script_interp = m_thread.GetProcess() ->GetTarget() diff --git a/lldb/source/Target/ThreadPlanRunToAddress.cpp b/lldb/source/Target/ThreadPlanRunToAddress.cpp index 8091b8a1ab7..bd11f8b82f7 100644 --- a/lldb/source/Target/ThreadPlanRunToAddress.cpp +++ b/lldb/source/Target/ThreadPlanRunToAddress.cpp @@ -69,6 +69,8 @@ void ThreadPlanRunToAddress::SetInitialBreakpoints() { ->CreateBreakpoint(m_addresses[i], true, false) .get(); if (breakpoint != nullptr) { + if (breakpoint->IsHardware() && !breakpoint->HasResolvedLocations()) + m_could_not_resolve_hw_bp = true; m_break_ids[i] = breakpoint->GetID(); breakpoint->SetThreadID(m_thread.GetID()); breakpoint->SetBreakpointKind("run-to-address"); @@ -81,6 +83,7 @@ ThreadPlanRunToAddress::~ThreadPlanRunToAddress() { for (size_t i = 0; i < num_break_ids; i++) { m_thread.CalculateTarget()->RemoveBreakpointByID(m_break_ids[i]); } + m_could_not_resolve_hw_bp = false; } void ThreadPlanRunToAddress::GetDescription(Stream *s, @@ -129,10 +132,15 @@ void ThreadPlanRunToAddress::GetDescription(Stream *s, } bool ThreadPlanRunToAddress::ValidatePlan(Stream *error) { + if (m_could_not_resolve_hw_bp) { + if (error) + error->Printf("Could not set hardware breakpoint(s)"); + return false; + } + // If we couldn't set the breakpoint for some reason, then this won't work. bool all_bps_good = true; size_t num_break_ids = m_break_ids.size(); - for (size_t i = 0; i < num_break_ids; i++) { if (m_break_ids[i] == LLDB_INVALID_BREAK_ID) { all_bps_good = false; diff --git a/lldb/source/Target/ThreadPlanShouldStopHere.cpp b/lldb/source/Target/ThreadPlanShouldStopHere.cpp index 8141a66a0e7..8062d8059c1 100644 --- a/lldb/source/Target/ThreadPlanShouldStopHere.cpp +++ b/lldb/source/Target/ThreadPlanShouldStopHere.cpp @@ -39,11 +39,11 @@ ThreadPlanShouldStopHere::ThreadPlanShouldStopHere( ThreadPlanShouldStopHere::~ThreadPlanShouldStopHere() = default; bool ThreadPlanShouldStopHere::InvokeShouldStopHereCallback( - FrameComparison operation) { + FrameComparison operation, Status &status) { bool should_stop_here = true; if (m_callbacks.should_stop_here_callback) { should_stop_here = m_callbacks.should_stop_here_callback( - m_owner, m_flags, operation, m_baton); + m_owner, m_flags, operation, status, m_baton); Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP)); if (log) { lldb::addr_t current_addr = @@ -59,7 +59,7 @@ bool ThreadPlanShouldStopHere::InvokeShouldStopHereCallback( bool ThreadPlanShouldStopHere::DefaultShouldStopHereCallback( ThreadPlan *current_plan, Flags &flags, FrameComparison operation, - void *baton) { + Status &status, void *baton) { bool should_stop_here = true; StackFrame *frame = current_plan->GetThread().GetStackFrameAtIndex(0).get(); if (!frame) @@ -96,7 +96,7 @@ bool ThreadPlanShouldStopHere::DefaultShouldStopHereCallback( ThreadPlanSP ThreadPlanShouldStopHere::DefaultStepFromHereCallback( ThreadPlan *current_plan, Flags &flags, FrameComparison operation, - void *baton) { + Status &status, void *baton) { const bool stop_others = false; const size_t frame_index = 0; ThreadPlanSP return_plan_sp; @@ -133,8 +133,8 @@ ThreadPlanSP ThreadPlanShouldStopHere::DefaultStepFromHereCallback( "Queueing StepInRange plan to step through line 0 code."); return_plan_sp = current_plan->GetThread().QueueThreadPlanForStepInRange( - false, range, sc, NULL, eOnlyDuringStepping, eLazyBoolCalculate, - eLazyBoolNo); + false, range, sc, NULL, eOnlyDuringStepping, status, + eLazyBoolCalculate, eLazyBoolNo); } } @@ -142,24 +142,25 @@ ThreadPlanSP ThreadPlanShouldStopHere::DefaultStepFromHereCallback( return_plan_sp = current_plan->GetThread().QueueThreadPlanForStepOutNoShouldStop( false, nullptr, true, stop_others, eVoteNo, eVoteNoOpinion, - frame_index, true); + frame_index, status, true); return return_plan_sp; } ThreadPlanSP ThreadPlanShouldStopHere::QueueStepOutFromHerePlan( - lldb_private::Flags &flags, lldb::FrameComparison operation) { + lldb_private::Flags &flags, lldb::FrameComparison operation, + Status &status) { ThreadPlanSP return_plan_sp; if (m_callbacks.step_from_here_callback) { - return_plan_sp = - m_callbacks.step_from_here_callback(m_owner, flags, operation, m_baton); + return_plan_sp = m_callbacks.step_from_here_callback( + m_owner, flags, operation, status, m_baton); } return return_plan_sp; } lldb::ThreadPlanSP ThreadPlanShouldStopHere::CheckShouldStopHereAndQueueStepOut( - lldb::FrameComparison operation) { - if (!InvokeShouldStopHereCallback(operation)) - return QueueStepOutFromHerePlan(m_flags, operation); + lldb::FrameComparison operation, Status &status) { + if (!InvokeShouldStopHereCallback(operation, status)) + return QueueStepOutFromHerePlan(m_flags, operation, status); else return ThreadPlanSP(); } diff --git a/lldb/source/Target/ThreadPlanStepInRange.cpp b/lldb/source/Target/ThreadPlanStepInRange.cpp index 6784e89cab7..8f9889a9d68 100644 --- a/lldb/source/Target/ThreadPlanStepInRange.cpp +++ b/lldb/source/Target/ThreadPlanStepInRange.cpp @@ -108,8 +108,16 @@ void ThreadPlanStepInRange::SetupAvoidNoDebug( void ThreadPlanStepInRange::GetDescription(Stream *s, lldb::DescriptionLevel level) { + + auto PrintFailureIfAny = [&]() { + if (m_status.Success()) + return; + s->Printf(" failed (%s)", m_status.AsCString()); + }; + if (level == lldb::eDescriptionLevelBrief) { s->Printf("step in"); + PrintFailureIfAny(); return; } @@ -130,6 +138,8 @@ void ThreadPlanStepInRange::GetDescription(Stream *s, DumpRanges(s); } + PrintFailureIfAny(); + s->PutChar('.'); } @@ -162,7 +172,8 @@ bool ThreadPlanStepInRange::ShouldStop(Event *event_ptr) { // ShouldStopHere plan, and otherwise we're done. // FIXME - This can be both a step in and a step out. Probably should // record which in the m_virtual_step. - m_sub_plan_sp = CheckShouldStopHereAndQueueStepOut(eFrameCompareYounger); + m_sub_plan_sp = + CheckShouldStopHereAndQueueStepOut(eFrameCompareYounger, m_status); } else { // Stepping through should be done running other threads in general, since // we're setting a breakpoint and continuing. So only stop others if we @@ -181,11 +192,12 @@ bool ThreadPlanStepInRange::ShouldStop(Event *event_ptr) { // I'm going to make the assumption that you wouldn't RETURN to a // trampoline. So if we are in a trampoline we think the frame is older // because the trampoline confused the backtracer. - m_sub_plan_sp = m_thread.QueueThreadPlanForStepThrough(m_stack_id, false, - stop_others); + m_sub_plan_sp = m_thread.QueueThreadPlanForStepThrough( + m_stack_id, false, stop_others, m_status); if (!m_sub_plan_sp) { // Otherwise check the ShouldStopHere for step out: - m_sub_plan_sp = CheckShouldStopHereAndQueueStepOut(frame_order); + m_sub_plan_sp = + CheckShouldStopHereAndQueueStepOut(frame_order, m_status); if (log) { if (m_sub_plan_sp) log->Printf("ShouldStopHere found plan to step out of this frame."); @@ -223,8 +235,8 @@ bool ThreadPlanStepInRange::ShouldStop(Event *event_ptr) { // We may have set the plan up above in the FrameIsOlder section: if (!m_sub_plan_sp) - m_sub_plan_sp = m_thread.QueueThreadPlanForStepThrough(m_stack_id, false, - stop_others); + m_sub_plan_sp = m_thread.QueueThreadPlanForStepThrough( + m_stack_id, false, stop_others, m_status); if (log) { if (m_sub_plan_sp) @@ -236,7 +248,7 @@ bool ThreadPlanStepInRange::ShouldStop(Event *event_ptr) { // If not, give the "should_stop" callback a chance to push a plan to get // us out of here. But only do that if we actually have stepped in. if (!m_sub_plan_sp && frame_order == eFrameCompareYounger) - m_sub_plan_sp = CheckShouldStopHereAndQueueStepOut(frame_order); + m_sub_plan_sp = CheckShouldStopHereAndQueueStepOut(frame_order, m_status); // If we've stepped in and we are going to stop here, check to see if we // were asked to run past the prologue, and if so do that. @@ -284,7 +296,7 @@ bool ThreadPlanStepInRange::ShouldStop(Event *event_ptr) { log->Printf("Pushing past prologue "); m_sub_plan_sp = m_thread.QueueThreadPlanForRunToAddress( - false, func_start_address, true); + false, func_start_address, true, m_status); } } } @@ -380,7 +392,7 @@ bool ThreadPlanStepInRange::FrameMatchesAvoidCriteria() { bool ThreadPlanStepInRange::DefaultShouldStopHereCallback( ThreadPlan *current_plan, Flags &flags, FrameComparison operation, - void *baton) { + Status &status, void *baton) { bool should_stop_here = true; StackFrame *frame = current_plan->GetThread().GetStackFrameAtIndex(0).get(); Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP)); @@ -388,7 +400,7 @@ bool ThreadPlanStepInRange::DefaultShouldStopHereCallback( // First see if the ThreadPlanShouldStopHere default implementation thinks we // should get out of here: should_stop_here = ThreadPlanShouldStopHere::DefaultShouldStopHereCallback( - current_plan, flags, operation, baton); + current_plan, flags, operation, status, baton); if (!should_stop_here) return should_stop_here; diff --git a/lldb/source/Target/ThreadPlanStepInstruction.cpp b/lldb/source/Target/ThreadPlanStepInstruction.cpp index b2cecf3a121..7707454c979 100644 --- a/lldb/source/Target/ThreadPlanStepInstruction.cpp +++ b/lldb/source/Target/ThreadPlanStepInstruction.cpp @@ -53,11 +53,19 @@ void ThreadPlanStepInstruction::SetUpState() { void ThreadPlanStepInstruction::GetDescription(Stream *s, lldb::DescriptionLevel level) { + auto PrintFailureIfAny = [&]() { + if (m_status.Success()) + return; + s->Printf(" failed (%s)", m_status.AsCString()); + }; + if (level == lldb::eDescriptionLevelBrief) { if (m_step_over) s->Printf("instruction step over"); else s->Printf("instruction step into"); + + PrintFailureIfAny(); } else { s->Printf("Stepping one instruction past "); s->Address(m_instruction_addr, sizeof(addr_t)); @@ -68,6 +76,8 @@ void ThreadPlanStepInstruction::GetDescription(Stream *s, s->Printf(" stepping over calls"); else s->Printf(" stepping into calls"); + + PrintFailureIfAny(); } } @@ -188,7 +198,8 @@ bool ThreadPlanStepInstruction::ShouldStop(Event *event_ptr) { // for now it is safer to run others. const bool stop_others = false; m_thread.QueueThreadPlanForStepOutNoShouldStop( - false, nullptr, true, stop_others, eVoteNo, eVoteNoOpinion, 0); + false, nullptr, true, stop_others, eVoteNo, eVoteNoOpinion, 0, + m_status); return false; } else { if (log) { diff --git a/lldb/source/Target/ThreadPlanStepOut.cpp b/lldb/source/Target/ThreadPlanStepOut.cpp index db8ab9fb5b6..378de53fafd 100644 --- a/lldb/source/Target/ThreadPlanStepOut.cpp +++ b/lldb/source/Target/ThreadPlanStepOut.cpp @@ -129,7 +129,10 @@ ThreadPlanStepOut::ThreadPlanStepOut( Breakpoint *return_bp = m_thread.CalculateTarget() ->CreateBreakpoint(m_return_addr, true, false) .get(); + if (return_bp != nullptr) { + if (return_bp->IsHardware() && !return_bp->HasResolvedLocations()) + m_could_not_resolve_hw_bp = true; return_bp->SetThreadID(m_thread.GetID()); m_return_bp_id = return_bp->GetID(); return_bp->SetBreakpointKind("step-out"); @@ -223,14 +226,24 @@ void ThreadPlanStepOut::GetDescription(Stream *s, bool ThreadPlanStepOut::ValidatePlan(Stream *error) { if (m_step_out_to_inline_plan_sp) return m_step_out_to_inline_plan_sp->ValidatePlan(error); - else if (m_step_through_inline_plan_sp) + + if (m_step_through_inline_plan_sp) return m_step_through_inline_plan_sp->ValidatePlan(error); - else if (m_return_bp_id == LLDB_INVALID_BREAK_ID) { + + if (m_could_not_resolve_hw_bp) { + if (error) + error->PutCString( + "Could not create hardware breakpoint for thread plan."); + return false; + } + + if (m_return_bp_id == LLDB_INVALID_BREAK_ID) { if (error) error->PutCString("Could not create return address breakpoint."); return false; - } else - return true; + } + + return true; } bool ThreadPlanStepOut::DoPlanExplainsStop(Event *event_ptr) { @@ -277,7 +290,7 @@ bool ThreadPlanStepOut::DoPlanExplainsStop(Event *event_ptr) { } if (done) { - if (InvokeShouldStopHereCallback(eFrameCompareOlder)) { + if (InvokeShouldStopHereCallback(eFrameCompareOlder, m_status)) { CalculateReturnValue(); SetPlanComplete(); } @@ -339,12 +352,12 @@ bool ThreadPlanStepOut::ShouldStop(Event *event_ptr) { // is consult the ShouldStopHere, and we are done. if (done) { - if (InvokeShouldStopHereCallback(eFrameCompareOlder)) { + if (InvokeShouldStopHereCallback(eFrameCompareOlder, m_status)) { CalculateReturnValue(); SetPlanComplete(); } else { m_step_out_further_plan_sp = - QueueStepOutFromHerePlan(m_flags, eFrameCompareOlder); + QueueStepOutFromHerePlan(m_flags, eFrameCompareOlder, m_status); done = false; } } diff --git a/lldb/source/Target/ThreadPlanStepOverRange.cpp b/lldb/source/Target/ThreadPlanStepOverRange.cpp index 2043b96ba9a..a9fff1be124 100644 --- a/lldb/source/Target/ThreadPlanStepOverRange.cpp +++ b/lldb/source/Target/ThreadPlanStepOverRange.cpp @@ -47,10 +47,18 @@ ThreadPlanStepOverRange::~ThreadPlanStepOverRange() = default; void ThreadPlanStepOverRange::GetDescription(Stream *s, lldb::DescriptionLevel level) { + auto PrintFailureIfAny = [&]() { + if (m_status.Success()) + return; + s->Printf(" failed (%s)", m_status.AsCString()); + }; + if (level == lldb::eDescriptionLevelBrief) { s->Printf("step over"); + PrintFailureIfAny(); return; } + s->Printf("Stepping over"); bool printed_line_info = false; if (m_addr_context.line_entry.IsValid()) { @@ -64,6 +72,8 @@ void ThreadPlanStepOverRange::GetDescription(Stream *s, DumpRanges(s); } + PrintFailureIfAny(); + s->PutChar('.'); } @@ -147,8 +157,8 @@ bool ThreadPlanStepOverRange::ShouldStop(Event *event_ptr) { // because the trampoline confused the backtracer. As below, we step // through first, and then try to figure out how to get back out again. - new_plan_sp = - m_thread.QueueThreadPlanForStepThrough(m_stack_id, false, stop_others); + new_plan_sp = m_thread.QueueThreadPlanForStepThrough(m_stack_id, false, + stop_others, m_status); if (new_plan_sp && log) log->Printf( @@ -169,11 +179,11 @@ bool ThreadPlanStepOverRange::ShouldStop(Event *event_ptr) { if (IsEquivalentContext(older_context)) { new_plan_sp = m_thread.QueueThreadPlanForStepOutNoShouldStop( false, nullptr, true, stop_others, eVoteNo, eVoteNoOpinion, 0, - true); + m_status, true); break; } else { - new_plan_sp = m_thread.QueueThreadPlanForStepThrough(m_stack_id, false, - stop_others); + new_plan_sp = m_thread.QueueThreadPlanForStepThrough( + m_stack_id, false, stop_others, m_status); // If we found a way through, then we should stop recursing. if (new_plan_sp) break; @@ -192,8 +202,8 @@ bool ThreadPlanStepOverRange::ShouldStop(Event *event_ptr) { // we are in a stub then it's likely going to be hard to get out from // here. It is probably easiest to step into the stub, and then it will // be straight-forward to step out. - new_plan_sp = m_thread.QueueThreadPlanForStepThrough(m_stack_id, false, - stop_others); + new_plan_sp = m_thread.QueueThreadPlanForStepThrough( + m_stack_id, false, stop_others, m_status); } else { // The current clang (at least through 424) doesn't always get the // address range for the DW_TAG_inlined_subroutines right, so that when @@ -283,8 +293,8 @@ bool ThreadPlanStepOverRange::ShouldStop(Event *event_ptr) { cur_pc); new_plan_sp = m_thread.QueueThreadPlanForStepOverRange( - abort_other_plans, step_range, sc, - stop_other_threads); + abort_other_plans, step_range, sc, stop_other_threads, + m_status); break; } look_ahead_step++; @@ -305,7 +315,7 @@ bool ThreadPlanStepOverRange::ShouldStop(Event *event_ptr) { // If we haven't figured out something to do yet, then ask the ShouldStopHere // callback: if (!new_plan_sp) { - new_plan_sp = CheckShouldStopHereAndQueueStepOut(frame_order); + new_plan_sp = CheckShouldStopHereAndQueueStepOut(frame_order, m_status); } if (!new_plan_sp) @@ -319,7 +329,7 @@ bool ThreadPlanStepOverRange::ShouldStop(Event *event_ptr) { if (!new_plan_sp) { // For efficiencies sake, we know we're done here so we don't have to do // this calculation again in MischiefManaged. - SetPlanComplete(); + SetPlanComplete(m_status.Success()); return true; } else return false; diff --git a/lldb/source/Target/ThreadPlanStepRange.cpp b/lldb/source/Target/ThreadPlanStepRange.cpp index 507f0e7f3a3..7ba68ee8498 100644 --- a/lldb/source/Target/ThreadPlanStepRange.cpp +++ b/lldb/source/Target/ThreadPlanStepRange.cpp @@ -57,7 +57,15 @@ void ThreadPlanStepRange::DidPush() { SetNextBranchBreakpoint(); } -bool ThreadPlanStepRange::ValidatePlan(Stream *error) { return true; } +bool ThreadPlanStepRange::ValidatePlan(Stream *error) { + if (m_could_not_resolve_hw_bp) { + if (error) + error->PutCString( + "Could not create hardware breakpoint for thread plan."); + return false; + } + return true; +} Vote ThreadPlanStepRange::ShouldReportStop(Event *event_ptr) { Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP)); @@ -281,6 +289,7 @@ void ThreadPlanStepRange::ClearNextBranchBreakpoint() { m_next_branch_bp_sp->GetID()); GetTarget().RemoveBreakpointByID(m_next_branch_bp_sp->GetID()); m_next_branch_bp_sp.reset(); + m_could_not_resolve_hw_bp = false; } } @@ -331,6 +340,11 @@ bool ThreadPlanStepRange::SetNextBranchBreakpoint() { m_next_branch_bp_sp = GetTarget().CreateBreakpoint(run_to_address, is_internal, false); if (m_next_branch_bp_sp) { + + if (m_next_branch_bp_sp->IsHardware() && + !m_next_branch_bp_sp->HasResolvedLocations()) + m_could_not_resolve_hw_bp = true; + if (log) { lldb::break_id_t bp_site_id = LLDB_INVALID_BREAK_ID; BreakpointLocationSP bp_loc = @@ -347,8 +361,10 @@ bool ThreadPlanStepRange::SetNextBranchBreakpoint() { run_to_address.GetLoadAddress( &m_thread.GetProcess()->GetTarget())); } + m_next_branch_bp_sp->SetThreadID(m_thread.GetID()); m_next_branch_bp_sp->SetBreakpointKind("next-branch-location"); + return true; } else return false; diff --git a/lldb/source/Target/ThreadPlanStepThrough.cpp b/lldb/source/Target/ThreadPlanStepThrough.cpp index b373edbf8f3..d1f3c2219f6 100644 --- a/lldb/source/Target/ThreadPlanStepThrough.cpp +++ b/lldb/source/Target/ThreadPlanStepThrough.cpp @@ -58,7 +58,10 @@ ThreadPlanStepThrough::ThreadPlanStepThrough(Thread &thread, ->GetTarget() .CreateBreakpoint(m_backstop_addr, true, false) .get(); + if (return_bp != nullptr) { + if (return_bp->IsHardware() && !return_bp->HasResolvedLocations()) + m_could_not_resolve_hw_bp = true; return_bp->SetThreadID(m_thread.GetID()); m_backstop_bkpt_id = return_bp->GetID(); return_bp->SetBreakpointKind("step-through-backstop"); @@ -135,7 +138,26 @@ void ThreadPlanStepThrough::GetDescription(Stream *s, } bool ThreadPlanStepThrough::ValidatePlan(Stream *error) { - return m_sub_plan_sp.get() != nullptr; + if (m_could_not_resolve_hw_bp) { + if (error) + error->PutCString( + "Could not create hardware breakpoint for thread plan."); + return false; + } + + if (m_backstop_bkpt_id == LLDB_INVALID_BREAK_ID) { + if (error) + error->PutCString("Could not create backstop breakpoint."); + return false; + } + + if (!m_sub_plan_sp.get()) { + if (error) + error->PutCString("Does not have a subplan."); + return false; + } + + return true; } bool ThreadPlanStepThrough::DoPlanExplainsStop(Event *event_ptr) { @@ -211,6 +233,7 @@ void ThreadPlanStepThrough::ClearBackstopBreakpoint() { if (m_backstop_bkpt_id != LLDB_INVALID_BREAK_ID) { m_thread.GetProcess()->GetTarget().RemoveBreakpointByID(m_backstop_bkpt_id); m_backstop_bkpt_id = LLDB_INVALID_BREAK_ID; + m_could_not_resolve_hw_bp = false; } } diff --git a/lldb/source/Target/ThreadPlanStepUntil.cpp b/lldb/source/Target/ThreadPlanStepUntil.cpp index b0cd53a49a8..1335c62ba94 100644 --- a/lldb/source/Target/ThreadPlanStepUntil.cpp +++ b/lldb/source/Target/ThreadPlanStepUntil.cpp @@ -53,7 +53,10 @@ ThreadPlanStepUntil::ThreadPlanStepUntil(Thread &thread, m_return_addr = return_frame_sp->GetStackID().GetPC(); Breakpoint *return_bp = target_sp->CreateBreakpoint(m_return_addr, true, false).get(); + if (return_bp != nullptr) { + if (return_bp->IsHardware() && !return_bp->HasResolvedLocations()) + m_could_not_resolve_hw_bp = true; return_bp->SetThreadID(thread_id); m_return_bp_id = return_bp->GetID(); return_bp->SetBreakpointKind("until-return-backstop"); @@ -93,6 +96,7 @@ void ThreadPlanStepUntil::Clear() { } } m_until_points.clear(); + m_could_not_resolve_hw_bp = false; } void ThreadPlanStepUntil::GetDescription(Stream *s, @@ -123,9 +127,16 @@ void ThreadPlanStepUntil::GetDescription(Stream *s, } bool ThreadPlanStepUntil::ValidatePlan(Stream *error) { - if (m_return_bp_id == LLDB_INVALID_BREAK_ID) + if (m_could_not_resolve_hw_bp) { + if (error) + error->PutCString( + "Could not create hardware breakpoint for thread plan."); + return false; + } else if (m_return_bp_id == LLDB_INVALID_BREAK_ID) { + if (error) + error->PutCString("Could not create return breakpoint."); return false; - else { + } else { until_collection::iterator pos, end = m_until_points.end(); for (pos = m_until_points.begin(); pos != end; pos++) { if (!LLDB_BREAK_ID_IS_VALID((*pos).second)) |