Index: include/lldb/API/SBBreakpoint.h =================================================================== --- include/lldb/API/SBBreakpoint.h +++ include/lldb/API/SBBreakpoint.h @@ -129,6 +129,8 @@ static uint32_t GetNumBreakpointLocationsFromEvent(const lldb::SBEvent &event_sp); + bool IsHardware() const; + // Can only be called from a ScriptedBreakpointResolver... SBError AddLocation(SBAddress &address); Index: include/lldb/Breakpoint/Breakpoint.h =================================================================== --- include/lldb/Breakpoint/Breakpoint.h +++ include/lldb/Breakpoint/Breakpoint.h @@ -502,6 +502,14 @@ //------------------------------------------------------------------ size_t GetNumResolvedLocations() const; + //------------------------------------------------------------------ + /// Return whether this breakpoint has any resolved locations. + /// + /// @return + /// True if GetNumResolvedLocations > 0 + //------------------------------------------------------------------ + bool HasResolvedLocations() const; + //------------------------------------------------------------------ /// Return the number of breakpoint locations. /// Index: include/lldb/Target/Target.h =================================================================== --- include/lldb/Target/Target.h +++ include/lldb/Target/Target.h @@ -202,6 +202,10 @@ bool GetUseModernTypeLookup() const; + void SetRequireHardwareBreakpoints(bool b); + + bool GetRequireHardwareBreakpoints() const; + private: //------------------------------------------------------------------ // Callbacks for m_launch_info. Index: include/lldb/Target/Thread.h =================================================================== --- include/lldb/Target/Thread.h +++ include/lldb/Target/Thread.h @@ -640,7 +640,8 @@ /// A shared pointer to the newly queued thread plan, or nullptr if the /// plan could not be queued. //------------------------------------------------------------------ - virtual lldb::ThreadPlanSP QueueFundamentalPlan(bool abort_other_plans); + virtual lldb::ThreadPlanSP QueueFundamentalPlan(Status &status, + bool abort_other_plans); //------------------------------------------------------------------ /// Queues the plan used to step one instruction from the current PC of \a @@ -661,8 +662,10 @@ /// A shared pointer to the newly queued thread plan, or nullptr if the /// plan could not be queued. //------------------------------------------------------------------ - virtual lldb::ThreadPlanSP QueueThreadPlanForStepSingleInstruction( - bool step_over, bool abort_other_plans, bool stop_other_threads); + virtual lldb::ThreadPlanSP + QueueThreadPlanForStepSingleInstruction(Status &status, bool step_over, + bool abort_other_plans, + bool stop_other_threads); //------------------------------------------------------------------ /// Queues the plan used to step through an address range, stepping over @@ -702,7 +705,7 @@ /// plan could not be queued. //------------------------------------------------------------------ virtual lldb::ThreadPlanSP QueueThreadPlanForStepOverRange( - bool abort_other_plans, const AddressRange &range, + Status &status, bool abort_other_plans, const AddressRange &range, const SymbolContext &addr_context, lldb::RunMode stop_other_threads, LazyBool step_out_avoids_code_without_debug_info = eLazyBoolCalculate); @@ -710,7 +713,7 @@ // This may combine multiple LineEntries of the same source line number to // step over a longer address range in a single operation. virtual lldb::ThreadPlanSP QueueThreadPlanForStepOverRange( - bool abort_other_plans, const LineEntry &line_entry, + Status &status, bool abort_other_plans, const LineEntry &line_entry, const SymbolContext &addr_context, lldb::RunMode stop_other_threads, LazyBool step_out_avoids_code_without_debug_info = eLazyBoolCalculate); @@ -761,7 +764,7 @@ /// plan could not be queued. //------------------------------------------------------------------ virtual lldb::ThreadPlanSP QueueThreadPlanForStepInRange( - bool abort_other_plans, const AddressRange &range, + Status &status, bool abort_other_plans, const AddressRange &range, const SymbolContext &addr_context, const char *step_in_target, lldb::RunMode stop_other_threads, LazyBool step_in_avoids_code_without_debug_info = eLazyBoolCalculate, @@ -771,7 +774,7 @@ // This may combine multiple LineEntries of the same source line number to // step over a longer address range in a single operation. virtual lldb::ThreadPlanSP QueueThreadPlanForStepInRange( - bool abort_other_plans, const LineEntry &line_entry, + Status &status, bool abort_other_plans, const LineEntry &line_entry, const SymbolContext &addr_context, const char *step_in_target, lldb::RunMode stop_other_threads, LazyBool step_in_avoids_code_without_debug_info = eLazyBoolCalculate, @@ -815,8 +818,8 @@ /// plan could not be queued. //------------------------------------------------------------------ virtual lldb::ThreadPlanSP QueueThreadPlanForStepOut( - bool abort_other_plans, SymbolContext *addr_context, bool first_insn, - bool stop_other_threads, + Status &status, bool abort_other_plans, SymbolContext *addr_context, + bool first_insn, bool stop_other_threads, Vote stop_vote, // = eVoteYes, Vote run_vote, // = eVoteNoOpinion); uint32_t frame_idx, @@ -875,8 +878,8 @@ /// plan could not be queued. //------------------------------------------------------------------ virtual lldb::ThreadPlanSP QueueThreadPlanForStepOutNoShouldStop( - bool abort_other_plans, SymbolContext *addr_context, bool first_insn, - bool stop_other_threads, + Status &status, bool abort_other_plans, SymbolContext *addr_context, + bool first_insn, bool stop_other_threads, Vote stop_vote, // = eVoteYes, Vote run_vote, // = eVoteNoOpinion); uint32_t frame_idx, bool continue_to_next_branch = false); @@ -904,7 +907,7 @@ /// plan could not be queued. //------------------------------------------------------------------ virtual lldb::ThreadPlanSP - QueueThreadPlanForStepThrough(StackID &return_stack_id, + QueueThreadPlanForStepThrough(Status &status, StackID &return_stack_id, bool abort_other_plans, bool stop_other_threads); @@ -929,16 +932,17 @@ /// plan could not be queued. //------------------------------------------------------------------ virtual lldb::ThreadPlanSP - QueueThreadPlanForRunToAddress(bool abort_other_plans, Address &target_addr, - bool stop_other_threads); + QueueThreadPlanForRunToAddress(Status &status, bool abort_other_plans, + Address &target_addr, bool stop_other_threads); virtual lldb::ThreadPlanSP - QueueThreadPlanForStepUntil(bool abort_other_plans, + QueueThreadPlanForStepUntil(Status &status, bool abort_other_plans, lldb::addr_t *address_list, size_t num_addresses, bool stop_others, uint32_t frame_idx); virtual lldb::ThreadPlanSP - QueueThreadPlanForStepScripted(bool abort_other_plans, const char *class_name, + QueueThreadPlanForStepScripted(Status &status, bool abort_other_plans, + const char *class_name, bool stop_other_threads); //------------------------------------------------------------------ @@ -1040,7 +1044,7 @@ /// @return /// A pointer to the last completed plan. //------------------------------------------------------------------ - void QueueThreadPlan(lldb::ThreadPlanSP &plan_sp, bool abort_other_plans); + Status QueueThreadPlan(lldb::ThreadPlanSP &plan_sp, bool abort_other_plans); //------------------------------------------------------------------ /// Discards the plans queued on the plan stack of the current thread. This Index: include/lldb/Target/ThreadPlanBase.h =================================================================== --- include/lldb/Target/ThreadPlanBase.h +++ include/lldb/Target/ThreadPlanBase.h @@ -52,7 +52,7 @@ private: friend lldb::ThreadPlanSP - Thread::QueueFundamentalPlan(bool abort_other_plans); + Thread::QueueFundamentalPlan(Status &status, bool abort_other_plans); DISALLOW_COPY_AND_ASSIGN(ThreadPlanBase); }; Index: include/lldb/Target/ThreadPlanRunToAddress.h =================================================================== --- include/lldb/Target/ThreadPlanRunToAddress.h +++ include/lldb/Target/ThreadPlanRunToAddress.h @@ -63,6 +63,7 @@ // TODO: Would it be useful to have multiple addresses? std::vector m_break_ids; // This is the breakpoint we are // using to stop us at m_address. + bool m_could_not_resolve_hw_bp; DISALLOW_COPY_AND_ASSIGN(ThreadPlanRunToAddress); }; Index: include/lldb/Target/ThreadPlanStepInRange.h =================================================================== --- include/lldb/Target/ThreadPlanStepInRange.h +++ include/lldb/Target/ThreadPlanStepInRange.h @@ -78,11 +78,11 @@ private: friend lldb::ThreadPlanSP Thread::QueueThreadPlanForStepOverRange( - bool abort_other_plans, const AddressRange &range, + Status &status, bool abort_other_plans, const AddressRange &range, const SymbolContext &addr_context, lldb::RunMode stop_others, LazyBool avoid_code_without_debug_info); friend lldb::ThreadPlanSP Thread::QueueThreadPlanForStepInRange( - bool abort_other_plans, const AddressRange &range, + Status &status, bool abort_other_plans, const AddressRange &range, const SymbolContext &addr_context, const char *step_in_target, lldb::RunMode stop_others, LazyBool step_in_avoids_code_without_debug_info, Index: include/lldb/Target/ThreadPlanStepInstruction.h =================================================================== --- include/lldb/Target/ThreadPlanStepInstruction.h +++ include/lldb/Target/ThreadPlanStepInstruction.h @@ -43,7 +43,8 @@ private: friend lldb::ThreadPlanSP Thread::QueueThreadPlanForStepSingleInstruction( - bool step_over, bool abort_other_plans, bool stop_other_threads); + Status &status, bool step_over, bool abort_other_plans, + bool stop_other_threads); lldb::addr_t m_instruction_addr; bool m_stop_other_threads; Index: include/lldb/Target/ThreadPlanStepOut.h =================================================================== --- include/lldb/Target/ThreadPlanStepOut.h +++ include/lldb/Target/ThreadPlanStepOut.h @@ -77,11 +77,12 @@ std::vector m_stepped_past_frames; lldb::ValueObjectSP m_return_valobj_sp; bool m_calculate_return_value; + bool m_could_not_resolve_hw_bp; friend lldb::ThreadPlanSP Thread::QueueThreadPlanForStepOut( - bool abort_other_plans, SymbolContext *addr_context, bool first_insn, - bool stop_others, Vote stop_vote, Vote run_vote, uint32_t frame_idx, - LazyBool step_out_avoids_code_without_debug_info); + Status &status, bool abort_other_plans, SymbolContext *addr_context, + bool first_insn, bool stop_others, Vote stop_vote, Vote run_vote, + uint32_t frame_idx, LazyBool step_out_avoids_code_without_debug_info); void SetupAvoidNoDebug(LazyBool step_out_avoids_code_without_debug_info); // Need an appropriate marker for the current stack so we can tell step out Index: include/lldb/Target/ThreadPlanStepRange.h =================================================================== --- include/lldb/Target/ThreadPlanStepRange.h +++ include/lldb/Target/ThreadPlanStepRange.h @@ -81,6 +81,7 @@ lldb::BreakpointSP m_next_branch_bp_sp; bool m_use_fast_step; bool m_given_ranges_only; + bool m_could_not_resolve_hw_bp; private: std::vector m_instruction_ranges; Index: include/lldb/Target/ThreadPlanStepThrough.h =================================================================== --- include/lldb/Target/ThreadPlanStepThrough.h +++ include/lldb/Target/ThreadPlanStepThrough.h @@ -44,11 +44,9 @@ bool HitOurBackstopBreakpoint(); private: - friend lldb::ThreadPlanSP - - Thread::QueueThreadPlanForStepThrough(StackID &return_stack_id, - bool abort_other_plans, - bool stop_others); + friend lldb::ThreadPlanSP Thread::QueueThreadPlanForStepThrough( + Status &status, StackID &return_stack_id, bool abort_other_plans, + bool stop_others); void ClearBackstopBreakpoint(); @@ -58,6 +56,7 @@ lldb::addr_t m_backstop_addr; StackID m_return_stack_id; bool m_stop_others; + bool m_could_not_resolve_hw_bp; DISALLOW_COPY_AND_ASSIGN(ThreadPlanStepThrough); }; Index: include/lldb/Target/ThreadPlanStepUntil.h =================================================================== --- include/lldb/Target/ThreadPlanStepUntil.h +++ include/lldb/Target/ThreadPlanStepUntil.h @@ -54,12 +54,13 @@ typedef std::map until_collection; until_collection m_until_points; bool m_stop_others; + bool m_could_not_resolve_hw_bp; void Clear(); friend lldb::ThreadPlanSP Thread::QueueThreadPlanForStepUntil( - bool abort_other_plans, lldb::addr_t *address_list, size_t num_addresses, - bool stop_others, uint32_t frame_idx); + Status &status, bool abort_other_plans, lldb::addr_t *address_list, + size_t num_addresses, bool stop_others, uint32_t frame_idx); // Need an appropriate marker for the current stack so we can tell step out // from step in. Index: packages/Python/lldbsuite/test/functionalities/breakpoint/require_hw_breakpoints/Makefile =================================================================== --- /dev/null +++ packages/Python/lldbsuite/test/functionalities/breakpoint/require_hw_breakpoints/Makefile @@ -0,0 +1,9 @@ +LEVEL = ../../../make + +C_SOURCES := main.c + +ifneq (,$(findstring icc,$(CC))) + CFLAGS += -debug inline-debug-info +endif + +include $(LEVEL)/Makefile.rules Index: packages/Python/lldbsuite/test/functionalities/breakpoint/require_hw_breakpoints/TestRequireHWBreakpoints.py =================================================================== --- /dev/null +++ packages/Python/lldbsuite/test/functionalities/breakpoint/require_hw_breakpoints/TestRequireHWBreakpoints.py @@ -0,0 +1,107 @@ +""" +Test require hardware breakpoints. +""" + +from __future__ import print_function + +import os +import time +import lldb +from lldbsuite.test.decorators import * +from lldbsuite.test.lldbtest import * +from lldbsuite.test import lldbutil + + +class BreakpointLocationsTestCase(TestBase): + + mydir = TestBase.compute_mydir(__file__) + + def test_breakpoint(self): + """Test regular breakpoints when hardware breakpoints are required.""" + self.build() + exe = self.getBuildArtifact("a.out") + target = self.dbg.CreateTarget(exe) + + self.runCmd("settings set target.require-hardware-breakpoint true") + + breakpoint = target.BreakpointCreateByLocation("main.c", 1) + self.assertTrue(breakpoint.IsHardware()) + + def test_step_range(self): + """Test stepping when hardware breakpoints are required.""" + self.build() + exe = self.getBuildArtifact("a.out") + target = self.dbg.CreateTarget(exe) + + breakpoint = target.BreakpointCreateByLocation("main.c", 1) + + self.runCmd("run") + + stepping_thread = lldbutil.get_one_thread_stopped_at_breakpoint( + target.GetProcess(), breakpoint) + self.assertTrue(stepping_thread.IsValid(), + "We stopped at the right breakpoint") + + self.runCmd("settings set target.require-hardware-breakpoint true") + + self.expect("thread step-in") + self.expect("thread step-in", error=True) + + def test_step_out(self): + """Test stepping out when hardware breakpoints are required.""" + self.build() + exe = self.getBuildArtifact("a.out") + target = self.dbg.CreateTarget(exe) + + breakpoint = target.BreakpointCreateByLocation("main.c", 1) + + self.runCmd("run") + + stepping_thread = lldbutil.get_one_thread_stopped_at_breakpoint( + target.GetProcess(), breakpoint) + self.assertTrue(stepping_thread.IsValid(), + "We stopped at the right breakpoint") + + self.runCmd("settings set target.require-hardware-breakpoint true") + + self.expect("thread step-out", error=True) + + def test_step_over(self): + """Test stepping over when hardware breakpoints are required.""" + self.build() + exe = self.getBuildArtifact("a.out") + target = self.dbg.CreateTarget(exe) + + breakpoint = target.BreakpointCreateByLocation("main.c", 7) + + self.runCmd("run") + + stepping_thread = lldbutil.get_one_thread_stopped_at_breakpoint( + target.GetProcess(), breakpoint) + self.assertTrue(stepping_thread.IsValid(), + "We stopped at the right breakpoint") + + self.runCmd("settings set target.require-hardware-breakpoint true") + + # Step over doesn't fail immediately but fails later on. + self.expect("thread step-over") + self.expect("process status", substrs=['stop reason = step over (FAILED)']) + + def test_step_until(self): + """Test stepping until when hardware breakpoints are required.""" + self.build() + exe = self.getBuildArtifact("a.out") + target = self.dbg.CreateTarget(exe) + + breakpoint = target.BreakpointCreateByLocation("main.c", 7) + + self.runCmd("run") + + stepping_thread = lldbutil.get_one_thread_stopped_at_breakpoint( + target.GetProcess(), breakpoint) + self.assertTrue(stepping_thread.IsValid(), + "We stopped at the right breakpoint") + + self.runCmd("settings set target.require-hardware-breakpoint true") + + self.expect("thread until 5", error=True) Index: packages/Python/lldbsuite/test/functionalities/breakpoint/require_hw_breakpoints/main.c =================================================================== --- /dev/null +++ packages/Python/lldbsuite/test/functionalities/breakpoint/require_hw_breakpoints/main.c @@ -0,0 +1,9 @@ +int break_on_me() { + int i = 10; + i++; + return i; +} + +int main() { + return break_on_me(); +} Index: packages/Python/lldbsuite/test/functionalities/step_scripted/TestStepScripted.py =================================================================== --- packages/Python/lldbsuite/test/functionalities/step_scripted/TestStepScripted.py +++ packages/Python/lldbsuite/test/functionalities/step_scripted/TestStepScripted.py @@ -35,7 +35,7 @@ self.assertEqual("foo", frame.GetFunctionName()) err = thread.StepUsingScriptedThreadPlan(name) - self.assertTrue(err.Success(), "Failed to step out") + self.assertTrue(err.Success(), err.GetCString()) frame = thread.GetFrameAtIndex(0) self.assertEqual("main", frame.GetFunctionName()) Index: scripts/interface/SBBreakpoint.i =================================================================== --- scripts/interface/SBBreakpoint.i +++ scripts/interface/SBBreakpoint.i @@ -251,6 +251,9 @@ static uint32_t GetNumBreakpointLocationsFromEvent (const lldb::SBEvent &event_sp); + bool + IsHardware (); + %pythoncode %{ class locations_access(object): Index: source/API/SBBreakpoint.cpp =================================================================== --- source/API/SBBreakpoint.cpp +++ source/API/SBBreakpoint.cpp @@ -692,6 +692,13 @@ 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. Index: source/API/SBThread.cpp =================================================================== --- source/API/SBThread.cpp +++ source/API/SBThread.cpp @@ -657,17 +657,18 @@ 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()) { const LazyBool avoid_no_debug = eLazyBoolCalculate; 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, abort_other_plans, sc.line_entry, sc, + stop_other_threads, avoid_no_debug); } else { new_plan_sp = thread->QueueThreadPlanForStepSingleInstruction( - true, abort_other_plans, stop_other_threads); + new_plan_status, true, abort_other_plans, stop_other_threads); } } error = ResumeNewPlan(exe_ctx, new_plan_sp.get()); @@ -707,6 +708,7 @@ 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)); @@ -723,12 +725,12 @@ const LazyBool step_in_avoids_code_without_debug_info = 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, abort_other_plans, range, sc, target_name, + stop_other_threads, 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); + new_plan_status, false, abort_other_plans, stop_other_threads); } error = ResumeNewPlan(exe_ctx, new_plan_sp.get()); } @@ -759,9 +761,10 @@ 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)); + new_plan_status, abort_other_plans, NULL, false, stop_other_threads, + eVoteYes, eVoteNoOpinion, 0, avoid_no_debug)); error = ResumeNewPlan(exe_ctx, new_plan_sp.get()); } @@ -812,9 +815,10 @@ return; } + Status new_plan_status; ThreadPlanSP new_plan_sp(thread->QueueThreadPlanForStepOut( - abort_other_plans, NULL, false, stop_other_threads, eVoteYes, - eVoteNoOpinion, frame_sp->GetFrameIndex())); + new_plan_status, abort_other_plans, NULL, false, stop_other_threads, + eVoteYes, eVoteNoOpinion, frame_sp->GetFrameIndex())); error = ResumeNewPlan(exe_ctx, new_plan_sp.get()); } @@ -840,8 +844,9 @@ } 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( + new_plan_status, step_over, true, true)); error = ResumeNewPlan(exe_ctx, new_plan_sp.get()); } @@ -873,8 +878,9 @@ Thread *thread = exe_ctx.GetThreadPtr(); + Status new_plan_status; ThreadPlanSP new_plan_sp(thread->QueueThreadPlanForRunToAddress( - abort_other_plans, target_addr, stop_other_threads)); + new_plan_status, abort_other_plans, target_addr, stop_other_threads)); error = ResumeNewPlan(exe_ctx, new_plan_sp.get()); } @@ -988,8 +994,9 @@ } 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], + new_plan_status, abort_other_plans, &step_over_until_addrs[0], step_over_until_addrs.size(), stop_other_threads, frame_sp->GetFrameIndex())); @@ -1024,12 +1031,14 @@ } Thread *thread = exe_ctx.GetThreadPtr(); - ThreadPlanSP thread_plan_sp = - thread->QueueThreadPlanForStepScripted(false, script_class_name, false); + Status thread_plan_status; + ThreadPlanSP thread_plan_sp = thread->QueueThreadPlanForStepScripted( + thread_plan_status, false, script_class_name, false); if (!thread_plan_sp) { sb_error.SetErrorStringWithFormat( - "Error queueing thread plan for class: %s", script_class_name); + "Error queueing thread plan for class: %s: %s", script_class_name, + thread_plan_status.AsCString()); return sb_error; } @@ -1041,7 +1050,8 @@ sb_error = ResumeNewPlan(exe_ctx, thread_plan_sp.get()); else { sb_error.SetErrorStringWithFormat( - "Error resuming thread plan for class: %s.", script_class_name); + "Error resuming thread plan for class: %s: %s", script_class_name, + thread_plan_status.AsCString()); if (log) log->Printf("SBThread(%p)::StepUsingScriptedThreadPlan: Error queuing " "thread plan for class: %s", Index: source/API/SBThreadPlan.cpp =================================================================== --- source/API/SBThreadPlan.cpp +++ source/API/SBThreadPlan.cpp @@ -152,9 +152,10 @@ AddressRange range(*start_address, size); SymbolContext sc; start_address->CalculateSymbolContext(&sc); + Status plan_status; return SBThreadPlan( m_opaque_sp->GetThread().QueueThreadPlanForStepOverRange( - false, range, sc, eAllThreads)); + plan_status, false, range, sc, eAllThreads)); } else { return SBThreadPlan(); } @@ -172,8 +173,9 @@ AddressRange range(*start_address, size); SymbolContext sc; start_address->CalculateSymbolContext(&sc); + Status plan_status; return SBThreadPlan(m_opaque_sp->GetThread().QueueThreadPlanForStepInRange( - false, range, sc, NULL, eAllThreads)); + plan_status, false, range, sc, NULL, eAllThreads)); } else { return SBThreadPlan(); } @@ -184,10 +186,11 @@ bool first_insn) { if (m_opaque_sp) { SymbolContext sc; + Status status; sc = m_opaque_sp->GetThread().GetStackFrameAtIndex(0)->GetSymbolContext( lldb::eSymbolContextEverything); return SBThreadPlan(m_opaque_sp->GetThread().QueueThreadPlanForStepOut( - false, &sc, first_insn, false, eVoteYes, eVoteNoOpinion, + status, false, &sc, first_insn, false, eVoteYes, eVoteNoOpinion, frame_idx_to_step_to)); } else { return SBThreadPlan(); @@ -201,8 +204,9 @@ if (!address) return SBThreadPlan(); + Status status; return SBThreadPlan(m_opaque_sp->GetThread().QueueThreadPlanForRunToAddress( - false, *address, false)); + status, false, *address, false)); } else { return SBThreadPlan(); } @@ -211,8 +215,9 @@ SBThreadPlan SBThreadPlan::QueueThreadPlanForStepScripted(const char *script_class_name) { if (m_opaque_sp) { + Status status; return SBThreadPlan(m_opaque_sp->GetThread().QueueThreadPlanForStepScripted( - false, script_class_name, false)); + status, false, script_class_name, false)); } else { return SBThreadPlan(); } Index: source/Breakpoint/Breakpoint.cpp =================================================================== --- source/Breakpoint/Breakpoint.cpp +++ source/Breakpoint/Breakpoint.cpp @@ -857,6 +857,10 @@ 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) { Index: source/Commands/CommandObjectThread.cpp =================================================================== --- source/Commands/CommandObjectThread.cpp +++ source/Commands/CommandObjectThread.cpp @@ -654,6 +654,7 @@ bool_stop_other_threads = true; ThreadPlanSP new_plan_sp; + Status new_plan_status; if (m_step_type == eStepTypeInto) { StackFrame *frame = thread->GetStackFrameAtIndex(0).get(); @@ -700,7 +701,7 @@ } new_plan_sp = thread->QueueThreadPlanForStepInRange( - abort_other_plans, range, + new_plan_status, 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, @@ -713,33 +714,33 @@ } } else new_plan_sp = thread->QueueThreadPlanForStepSingleInstruction( - false, abort_other_plans, bool_stop_other_threads); + new_plan_status, false, abort_other_plans, bool_stop_other_threads); } else if (m_step_type == eStepTypeOver) { StackFrame *frame = thread->GetStackFrameAtIndex(0).get(); if (frame->HasDebugInformation()) new_plan_sp = thread->QueueThreadPlanForStepOverRange( - abort_other_plans, + new_plan_status, abort_other_plans, frame->GetSymbolContext(eSymbolContextEverything).line_entry, frame->GetSymbolContext(eSymbolContextEverything), stop_other_threads, m_options.m_step_out_avoid_no_debug); else new_plan_sp = thread->QueueThreadPlanForStepSingleInstruction( - true, abort_other_plans, bool_stop_other_threads); + new_plan_status, true, abort_other_plans, bool_stop_other_threads); } else if (m_step_type == eStepTypeTrace) { new_plan_sp = thread->QueueThreadPlanForStepSingleInstruction( - false, abort_other_plans, bool_stop_other_threads); + new_plan_status, false, abort_other_plans, bool_stop_other_threads); } else if (m_step_type == eStepTypeTraceOver) { new_plan_sp = thread->QueueThreadPlanForStepSingleInstruction( - true, abort_other_plans, bool_stop_other_threads); + new_plan_status, true, abort_other_plans, bool_stop_other_threads); } else if (m_step_type == eStepTypeOut) { new_plan_sp = thread->QueueThreadPlanForStepOut( - abort_other_plans, nullptr, false, bool_stop_other_threads, eVoteYes, - eVoteNoOpinion, thread->GetSelectedFrameIndex(), - m_options.m_step_out_avoid_no_debug); + new_plan_status, abort_other_plans, nullptr, false, + bool_stop_other_threads, eVoteYes, eVoteNoOpinion, + thread->GetSelectedFrameIndex(), 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(), + new_plan_status, abort_other_plans, m_options.m_class_name.c_str(), bool_stop_other_threads); } else { result.AppendError("step type is not supported"); @@ -798,6 +799,7 @@ result.SetStatus(eReturnStatusSuccessContinuingNoResult); } } else { + result.SetError(new_plan_status); result.AppendError("Couldn't find thread plan to implement step type."); result.SetStatus(eReturnStatusFailed); } @@ -1194,6 +1196,7 @@ } ThreadPlanSP new_plan_sp; + Status new_plan_status; if (frame->HasDebugInformation()) { // Finally we got here... Translate the given line number to a bunch @@ -1273,14 +1276,21 @@ } 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); + new_plan_status, abort_other_plans, &address_list.front(), + address_list.size(), m_options.m_stop_others, + m_options.m_frame_idx); + 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", Index: source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleThreadPlanStepThroughObjCTrampoline.cpp =================================================================== --- source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleThreadPlanStepThroughObjCTrampoline.cpp +++ source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleThreadPlanStepThroughObjCTrampoline.cpp @@ -161,12 +161,13 @@ 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); + status, abort_other_plans, &sc, first_insn, m_stop_others, + eVoteNoOpinion, eVoteNoOpinion, frame_idx); m_run_to_sp->SetPrivate(true); return false; } Index: source/Target/Process.cpp =================================================================== --- source/Target/Process.cpp +++ source/Target/Process.cpp @@ -1924,7 +1924,7 @@ 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 Index: source/Target/StopInfo.cpp =================================================================== --- source/Target/StopInfo.cpp +++ source/Target/StopInfo.cpp @@ -720,11 +720,14 @@ 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, + 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); @@ -1042,6 +1045,8 @@ if (m_description.empty()) { StreamString strm; m_plan_sp->GetDescription(&strm, eDescriptionLevelBrief); + if (!m_plan_sp->PlanSucceeded()) + strm << " (FAILED)"; m_description = strm.GetString(); } return m_description.c_str(); Index: source/Target/Target.cpp =================================================================== --- source/Target/Target.cpp +++ source/Target/Target.cpp @@ -631,7 +631,8 @@ 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); @@ -3133,6 +3134,7 @@ // class TargetProperties //-------------------------------------------------------------- +// clang-format off static constexpr OptionEnumValueElement g_dynamic_value_types[] = { {eNoDynamicValues, "no-dynamic-values", "Don't calculate the dynamic type of values"}, @@ -3360,7 +3362,10 @@ 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, @@ -3405,7 +3410,8 @@ ePropertyTrapHandlerNames, ePropertyDisplayRuntimeSupportValues, ePropertyNonStopModeEnabled, - ePropertyExperimental + ePropertyRequireHardwareBreakpoints, + ePropertyExperimental, }; class TargetOptionValueProperties : public OptionValueProperties { @@ -4003,6 +4009,17 @@ 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_ = Index: source/Target/Thread.cpp =================================================================== --- source/Target/Thread.cpp +++ source/Target/Thread.cpp @@ -266,7 +266,9 @@ static_cast(this), GetID()); CheckInWithManager(); - QueueFundamentalPlan(true); + + Status status; + QueueFundamentalPlan(status, true); } Thread::~Thread() { @@ -399,13 +401,14 @@ 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 { @@ -1177,12 +1180,34 @@ 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) { @@ -1340,22 +1365,25 @@ return error; } -ThreadPlanSP Thread::QueueFundamentalPlan(bool abort_other_plans) { +ThreadPlanSP Thread::QueueFundamentalPlan(Status &status, + bool abort_other_plans) { ThreadPlanSP thread_plan_sp(new ThreadPlanBase(*this)); - QueueThreadPlan(thread_plan_sp, abort_other_plans); + status = QueueThreadPlan(thread_plan_sp, abort_other_plans); return thread_plan_sp; } -ThreadPlanSP Thread::QueueThreadPlanForStepSingleInstruction( - bool step_over, bool abort_other_plans, bool stop_other_threads) { +ThreadPlanSP +Thread::QueueThreadPlanForStepSingleInstruction(Status &status, bool step_over, + bool abort_other_plans, + bool stop_other_threads) { 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, + Status &status, bool abort_other_plans, const AddressRange &range, const SymbolContext &addr_context, lldb::RunMode stop_other_threads, LazyBool step_out_avoids_code_withoug_debug_info) { ThreadPlanSP thread_plan_sp; @@ -1363,24 +1391,24 @@ *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; } // Call the QueueThreadPlanForStepOverRange method which takes an address // range. ThreadPlanSP Thread::QueueThreadPlanForStepOverRange( - bool abort_other_plans, const LineEntry &line_entry, + Status &status, 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) { return QueueThreadPlanForStepOverRange( - abort_other_plans, line_entry.GetSameLineContiguousAddressRange(), + status, abort_other_plans, line_entry.GetSameLineContiguousAddressRange(), addr_context, stop_other_threads, step_out_avoids_code_withoug_debug_info); } ThreadPlanSP Thread::QueueThreadPlanForStepInRange( - bool abort_other_plans, const AddressRange &range, + Status &status, bool abort_other_plans, const AddressRange &range, const SymbolContext &addr_context, const char *step_in_target, lldb::RunMode stop_other_threads, LazyBool step_in_avoids_code_without_debug_info, @@ -1395,44 +1423,40 @@ 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; } // Call the QueueThreadPlanForStepInRange method which takes an address range. ThreadPlanSP Thread::QueueThreadPlanForStepInRange( - bool abort_other_plans, const LineEntry &line_entry, + Status &status, bool abort_other_plans, const LineEntry &line_entry, const SymbolContext &addr_context, const char *step_in_target, lldb::RunMode stop_other_threads, LazyBool step_in_avoids_code_without_debug_info, LazyBool step_out_avoids_code_without_debug_info) { return QueueThreadPlanForStepInRange( - abort_other_plans, line_entry.GetSameLineContiguousAddressRange(), + status, abort_other_plans, line_entry.GetSameLineContiguousAddressRange(), addr_context, step_in_target, stop_other_threads, step_in_avoids_code_without_debug_info, step_out_avoids_code_without_debug_info); } 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, 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) { 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 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) { const bool calculate_return_value = false; // No need to calculate the return value here. ThreadPlanSP thread_plan_sp(new ThreadPlanStepOut( @@ -1443,15 +1467,12 @@ static_cast(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, +ThreadPlanSP Thread::QueueThreadPlanForStepThrough(Status &status, + StackID &return_stack_id, bool abort_other_plans, bool stop_other_threads) { ThreadPlanSP thread_plan_sp( @@ -1459,43 +1480,39 @@ 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, +ThreadPlanSP Thread::QueueThreadPlanForRunToAddress(Status &status, + bool abort_other_plans, Address &target_addr, bool stop_other_threads) { 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( + Status &status, bool abort_other_plans, lldb::addr_t *address_list, + size_t num_addresses, bool stop_other_threads, uint32_t frame_idx) { 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) { +lldb::ThreadPlanSP +Thread::QueueThreadPlanForStepScripted(Status &status, bool abort_other_plans, + const char *class_name, + bool stop_other_threads) { 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; } @@ -2114,12 +2131,12 @@ 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, + error, abort_other_plans, sc.line_entry, sc, nullptr, run_mode, 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); + error, false, abort_other_plans, run_mode); } new_plan_sp->SetIsMasterPlan(true); @@ -2148,11 +2165,11 @@ 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, + error, abort_other_plans, sc.line_entry, sc, run_mode, step_out_avoids_code_without_debug_info); } else { new_plan_sp = QueueThreadPlanForStepSingleInstruction( - true, abort_other_plans, run_mode); + error, true, abort_other_plans, run_mode); } new_plan_sp->SetIsMasterPlan(true); @@ -2176,8 +2193,8 @@ const bool abort_other_plans = false; ThreadPlanSP new_plan_sp(QueueThreadPlanForStepOut( - abort_other_plans, nullptr, first_instruction, stop_other_threads, - eVoteYes, eVoteNoOpinion, 0)); + error, abort_other_plans, nullptr, first_instruction, + stop_other_threads, eVoteYes, eVoteNoOpinion, 0)); new_plan_sp->SetIsMasterPlan(true); new_plan_sp->SetOkayToDiscard(false); Index: source/Target/ThreadPlanCallOnFunctionExit.cpp =================================================================== --- source/Target/ThreadPlanCallOnFunctionExit.cpp +++ source/Target/ThreadPlanCallOnFunctionExit.cpp @@ -27,7 +27,9 @@ // completes. // Set stop vote to eVoteNo. + Status status; m_step_out_threadplan_sp = GetThread().QueueThreadPlanForStepOut( + status, false, // abort other plans nullptr, // addr_context true, // first instruction @@ -37,7 +39,7 @@ // run state broadcasting 0, // frame_idx eLazyBoolCalculate // avoid code w/o debinfo - ); + ); } // ------------------------------------------------------------------------- Index: source/Target/ThreadPlanPython.cpp =================================================================== --- source/Target/ThreadPlanPython.cpp +++ source/Target/ThreadPlanPython.cpp @@ -46,16 +46,7 @@ // to make it go away? } -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) - return true; - else - return false; -} +bool ThreadPlanPython::ValidatePlan(Stream *error) { return true; } void ThreadPlanPython::DidPush() { // We set up the script side in DidPush, so that it can push other plans in Index: source/Target/ThreadPlanRunToAddress.cpp =================================================================== --- source/Target/ThreadPlanRunToAddress.cpp +++ source/Target/ThreadPlanRunToAddress.cpp @@ -30,7 +30,8 @@ bool stop_others) : ThreadPlan(ThreadPlan::eKindRunToAddress, "Run to address plan", thread, eVoteNoOpinion, eVoteNoOpinion), - m_stop_others(stop_others), m_addresses(), m_break_ids() { + m_stop_others(stop_others), m_addresses(), m_break_ids(), + m_could_not_resolve_hw_bp(false) { m_addresses.push_back( address.GetOpcodeLoadAddress(m_thread.CalculateTarget().get())); SetInitialBreakpoints(); @@ -41,7 +42,8 @@ bool stop_others) : ThreadPlan(ThreadPlan::eKindRunToAddress, "Run to address plan", thread, eVoteNoOpinion, eVoteNoOpinion), - m_stop_others(stop_others), m_addresses(), m_break_ids() { + m_stop_others(stop_others), m_addresses(), m_break_ids(), + m_could_not_resolve_hw_bp(false) { m_addresses.push_back( m_thread.CalculateTarget()->GetOpcodeLoadAddress(address)); SetInitialBreakpoints(); @@ -73,6 +75,8 @@ ->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"); @@ -85,6 +89,7 @@ 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, @@ -133,10 +138,15 @@ } 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; Index: source/Target/ThreadPlanShouldStopHere.cpp =================================================================== --- source/Target/ThreadPlanShouldStopHere.cpp +++ source/Target/ThreadPlanShouldStopHere.cpp @@ -103,6 +103,7 @@ void *baton) { const bool stop_others = false; const size_t frame_index = 0; + Status return_plan_status; ThreadPlanSP return_plan_sp; // If we are stepping through code at line number 0, then we need to step // over this range. Otherwise we will step out. @@ -137,16 +138,16 @@ "Queueing StepInRange plan to step through line 0 code."); return_plan_sp = current_plan->GetThread().QueueThreadPlanForStepInRange( - false, range, sc, NULL, eOnlyDuringStepping, eLazyBoolCalculate, - eLazyBoolNo); + return_plan_status, false, range, sc, NULL, eOnlyDuringStepping, + eLazyBoolCalculate, eLazyBoolNo); } } if (!return_plan_sp) return_plan_sp = current_plan->GetThread().QueueThreadPlanForStepOutNoShouldStop( - false, nullptr, true, stop_others, eVoteNo, eVoteNoOpinion, - frame_index, true); + return_plan_status, false, nullptr, true, stop_others, eVoteNo, + eVoteNoOpinion, frame_index, true); return return_plan_sp; } Index: source/Target/ThreadPlanStepInRange.cpp =================================================================== --- source/Target/ThreadPlanStepInRange.cpp +++ source/Target/ThreadPlanStepInRange.cpp @@ -168,6 +168,7 @@ // record which in the m_virtual_step. m_sub_plan_sp = CheckShouldStopHereAndQueueStepOut(eFrameCompareYounger); } else { + Status sub_plan_status; // Stepping through should be done running other threads in general, since // we're setting a breakpoint and continuing. So only stop others if we // are explicitly told to do so. @@ -185,8 +186,8 @@ // 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( + sub_plan_status, m_stack_id, false, stop_others); if (!m_sub_plan_sp) { // Otherwise check the ShouldStopHere for step out: m_sub_plan_sp = CheckShouldStopHereAndQueueStepOut(frame_order); @@ -227,8 +228,8 @@ // 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( + sub_plan_status, m_stack_id, false, stop_others); if (log) { if (m_sub_plan_sp) @@ -288,7 +289,7 @@ log->Printf("Pushing past prologue "); m_sub_plan_sp = m_thread.QueueThreadPlanForRunToAddress( - false, func_start_address, true); + sub_plan_status, false, func_start_address, true); } } } Index: source/Target/ThreadPlanStepInstruction.cpp =================================================================== --- source/Target/ThreadPlanStepInstruction.cpp +++ source/Target/ThreadPlanStepInstruction.cpp @@ -191,8 +191,10 @@ // StepInstruction should probably have the tri-state RunMode, but // for now it is safer to run others. const bool stop_others = false; + Status status; m_thread.QueueThreadPlanForStepOutNoShouldStop( - false, nullptr, true, stop_others, eVoteNo, eVoteNoOpinion, 0); + status, false, nullptr, true, stop_others, eVoteNo, + eVoteNoOpinion, 0); return false; } else { if (log) { Index: source/Target/ThreadPlanStepOut.cpp =================================================================== --- source/Target/ThreadPlanStepOut.cpp +++ source/Target/ThreadPlanStepOut.cpp @@ -47,7 +47,8 @@ m_return_bp_id(LLDB_INVALID_BREAK_ID), m_return_addr(LLDB_INVALID_ADDRESS), m_stop_others(stop_others), m_immediate_step_from_function(nullptr), - m_calculate_return_value(gather_return_value) { + m_calculate_return_value(gather_return_value), + m_could_not_resolve_hw_bp(false) { Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP)); SetFlagsToDefault(); SetupAvoidNoDebug(step_out_avoids_code_without_debug_info); @@ -133,7 +134,10 @@ 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"); @@ -227,14 +231,24 @@ 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) { Index: source/Target/ThreadPlanStepOverRange.cpp =================================================================== --- source/Target/ThreadPlanStepOverRange.cpp +++ source/Target/ThreadPlanStepOverRange.cpp @@ -139,6 +139,7 @@ // forcing running one thread. bool stop_others = (m_stop_others == lldb::eOnlyThisThread); ThreadPlanSP new_plan_sp; + Status new_plan_status; FrameComparison frame_order = CompareCurrentFrameToStartFrame(); if (frame_order == eFrameCompareOlder) { @@ -151,8 +152,8 @@ // 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( + new_plan_status, m_stack_id, false, stop_others); if (new_plan_sp && log) log->Printf( @@ -172,12 +173,12 @@ older_frame_sp->GetSymbolContext(eSymbolContextEverything); if (IsEquivalentContext(older_context)) { new_plan_sp = m_thread.QueueThreadPlanForStepOutNoShouldStop( - false, nullptr, true, stop_others, eVoteNo, eVoteNoOpinion, 0, - true); + new_plan_status, false, nullptr, true, stop_others, eVoteNo, + eVoteNoOpinion, 0, true); break; } else { - new_plan_sp = m_thread.QueueThreadPlanForStepThrough(m_stack_id, false, - stop_others); + new_plan_sp = m_thread.QueueThreadPlanForStepThrough( + new_plan_status, m_stack_id, false, stop_others); // If we found a way through, then we should stop recursing. if (new_plan_sp) break; @@ -196,8 +197,8 @@ // 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( + new_plan_status, m_stack_id, false, stop_others); } 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 @@ -287,7 +288,7 @@ cur_pc); new_plan_sp = m_thread.QueueThreadPlanForStepOverRange( - abort_other_plans, step_range, sc, + new_plan_status, abort_other_plans, step_range, sc, stop_other_threads); break; } @@ -323,7 +324,7 @@ 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(new_plan_status.Success()); return true; } else return false; Index: source/Target/ThreadPlanStepRange.cpp =================================================================== --- source/Target/ThreadPlanStepRange.cpp +++ source/Target/ThreadPlanStepRange.cpp @@ -45,7 +45,7 @@ m_addr_context(addr_context), m_address_ranges(), m_stop_others(stop_others), m_stack_id(), m_parent_stack_id(), m_no_more_plans(false), m_first_run_event(true), m_use_fast_step(false), - m_given_ranges_only(given_ranges_only) { + m_given_ranges_only(given_ranges_only), m_could_not_resolve_hw_bp(false) { m_use_fast_step = GetTarget().GetUseFastStepping(); AddRange(range); m_stack_id = m_thread.GetStackFrameAtIndex(0)->GetStackID(); @@ -61,7 +61,15 @@ 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)); @@ -285,6 +293,7 @@ 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; } } @@ -335,6 +344,11 @@ 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 = @@ -351,8 +365,10 @@ 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; Index: source/Target/ThreadPlanStepThrough.cpp =================================================================== --- source/Target/ThreadPlanStepThrough.cpp +++ source/Target/ThreadPlanStepThrough.cpp @@ -40,7 +40,7 @@ eVoteNoOpinion, eVoteNoOpinion), m_start_address(0), m_backstop_bkpt_id(LLDB_INVALID_BREAK_ID), m_backstop_addr(LLDB_INVALID_ADDRESS), m_return_stack_id(m_stack_id), - m_stop_others(stop_others) { + m_stop_others(stop_others), m_could_not_resolve_hw_bp(false) { LookForPlanToStepThroughFromCurrentPC(); // If we don't get a valid step through plan, don't bother to set up a @@ -62,7 +62,10 @@ ->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"); @@ -139,7 +142,26 @@ } 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) { @@ -215,6 +237,7 @@ 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; } } Index: source/Target/ThreadPlanStepUntil.cpp =================================================================== --- source/Target/ThreadPlanStepUntil.cpp +++ source/Target/ThreadPlanStepUntil.cpp @@ -39,7 +39,8 @@ m_return_bp_id(LLDB_INVALID_BREAK_ID), m_return_addr(LLDB_INVALID_ADDRESS), m_stepped_out(false), m_should_stop(false), m_ran_analyze(false), m_explains_stop(false), - m_until_points(), m_stop_others(stop_others) { + m_until_points(), m_stop_others(stop_others), + m_could_not_resolve_hw_bp(false) { // Stash away our "until" addresses: TargetSP target_sp(m_thread.CalculateTarget()); @@ -57,7 +58,10 @@ 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"); @@ -97,6 +101,7 @@ } } m_until_points.clear(); + m_could_not_resolve_hw_bp = false; } void ThreadPlanStepUntil::GetDescription(Stream *s, @@ -127,9 +132,16 @@ } 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))