forked from OSchip/llvm-project
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 llvm-svn: 346920
This commit is contained in:
parent
df14b94243
commit
e103ae92ef
|
@ -129,6 +129,8 @@ public:
|
|||
static uint32_t
|
||||
GetNumBreakpointLocationsFromEvent(const lldb::SBEvent &event_sp);
|
||||
|
||||
bool IsHardware() const;
|
||||
|
||||
// Can only be called from a ScriptedBreakpointResolver...
|
||||
SBError
|
||||
AddLocation(SBAddress &address);
|
||||
|
|
|
@ -79,16 +79,28 @@ public:
|
|||
// plans...
|
||||
SBThreadPlan QueueThreadPlanForStepOverRange(SBAddress &start_address,
|
||||
lldb::addr_t range_size);
|
||||
SBThreadPlan QueueThreadPlanForStepOverRange(SBAddress &start_address,
|
||||
lldb::addr_t range_size,
|
||||
SBError &error);
|
||||
|
||||
SBThreadPlan QueueThreadPlanForStepInRange(SBAddress &start_address,
|
||||
lldb::addr_t range_size);
|
||||
SBThreadPlan QueueThreadPlanForStepInRange(SBAddress &start_address,
|
||||
lldb::addr_t range_size,
|
||||
SBError &error);
|
||||
|
||||
SBThreadPlan QueueThreadPlanForStepOut(uint32_t frame_idx_to_step_to,
|
||||
bool first_insn = false);
|
||||
SBThreadPlan QueueThreadPlanForStepOut(uint32_t frame_idx_to_step_to,
|
||||
bool first_insn, SBError &error);
|
||||
|
||||
SBThreadPlan QueueThreadPlanForRunToAddress(SBAddress address);
|
||||
SBThreadPlan QueueThreadPlanForRunToAddress(SBAddress address,
|
||||
SBError &error);
|
||||
|
||||
SBThreadPlan QueueThreadPlanForStepScripted(const char *script_class_name);
|
||||
SBThreadPlan QueueThreadPlanForStepScripted(const char *script_class_name,
|
||||
SBError &error);
|
||||
|
||||
#ifndef SWIG
|
||||
lldb_private::ThreadPlan *get();
|
||||
|
|
|
@ -498,6 +498,14 @@ public:
|
|||
//------------------------------------------------------------------
|
||||
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.
|
||||
///
|
||||
|
|
|
@ -198,6 +198,10 @@ public:
|
|||
|
||||
bool GetUseModernTypeLookup() const;
|
||||
|
||||
void SetRequireHardwareBreakpoints(bool b);
|
||||
|
||||
bool GetRequireHardwareBreakpoints() const;
|
||||
|
||||
private:
|
||||
//------------------------------------------------------------------
|
||||
// Callbacks for m_launch_info.
|
||||
|
|
|
@ -53,7 +53,7 @@ public:
|
|||
bool GetStepInAvoidsNoDebug() const;
|
||||
|
||||
bool GetStepOutAvoidsNoDebug() const;
|
||||
|
||||
|
||||
uint64_t GetMaxBacktraceDepth() const;
|
||||
};
|
||||
|
||||
|
@ -494,9 +494,9 @@ public:
|
|||
|
||||
// If stop_format is true, this will be the form used when we print stop
|
||||
// info. If false, it will be the form we use for thread list and co.
|
||||
void DumpUsingSettingsFormat(Stream &strm, uint32_t frame_idx,
|
||||
void DumpUsingSettingsFormat(Stream &strm, uint32_t frame_idx,
|
||||
bool stop_format);
|
||||
|
||||
|
||||
bool GetDescription(Stream &s, lldb::DescriptionLevel level,
|
||||
bool print_json_thread, bool print_json_stopinfo);
|
||||
|
||||
|
@ -653,12 +653,16 @@ public:
|
|||
/// @param[in] stop_other_threads
|
||||
/// \b true if we will stop other threads while we single step this one.
|
||||
///
|
||||
/// @param[out] status
|
||||
/// A status with an error if queuing failed.
|
||||
///
|
||||
/// @return
|
||||
/// 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);
|
||||
bool step_over, bool abort_other_plans, bool stop_other_threads,
|
||||
Status &status);
|
||||
|
||||
//------------------------------------------------------------------
|
||||
/// Queues the plan used to step through an address range, stepping over
|
||||
|
@ -688,6 +692,9 @@ public:
|
|||
/// @param[in] stop_other_threads
|
||||
/// \b true if we will stop other threads while we single step this one.
|
||||
///
|
||||
/// @param[out] status
|
||||
/// A status with an error if queuing failed.
|
||||
///
|
||||
/// @param[in] step_out_avoids_code_without_debug_info
|
||||
/// If eLazyBoolYes, if the step over steps out it will continue to step
|
||||
/// out till it comes to a frame with debug info.
|
||||
|
@ -700,6 +707,7 @@ public:
|
|||
virtual lldb::ThreadPlanSP QueueThreadPlanForStepOverRange(
|
||||
bool abort_other_plans, const AddressRange &range,
|
||||
const SymbolContext &addr_context, lldb::RunMode stop_other_threads,
|
||||
Status &status,
|
||||
LazyBool step_out_avoids_code_without_debug_info = eLazyBoolCalculate);
|
||||
|
||||
// Helper function that takes a LineEntry to step, insted of an AddressRange.
|
||||
|
@ -708,6 +716,7 @@ public:
|
|||
virtual lldb::ThreadPlanSP QueueThreadPlanForStepOverRange(
|
||||
bool abort_other_plans, const LineEntry &line_entry,
|
||||
const SymbolContext &addr_context, lldb::RunMode stop_other_threads,
|
||||
Status &status,
|
||||
LazyBool step_out_avoids_code_without_debug_info = eLazyBoolCalculate);
|
||||
|
||||
//------------------------------------------------------------------
|
||||
|
@ -742,6 +751,9 @@ public:
|
|||
/// @param[in] stop_other_threads
|
||||
/// \b true if we will stop other threads while we single step this one.
|
||||
///
|
||||
/// @param[out] status
|
||||
/// A status with an error if queuing failed.
|
||||
///
|
||||
/// @param[in] step_in_avoids_code_without_debug_info
|
||||
/// If eLazyBoolYes we will step out if we step into code with no debug
|
||||
/// info.
|
||||
|
@ -759,7 +771,7 @@ public:
|
|||
virtual lldb::ThreadPlanSP 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 = eLazyBoolCalculate,
|
||||
LazyBool step_out_avoids_code_without_debug_info = eLazyBoolCalculate);
|
||||
|
||||
|
@ -769,7 +781,7 @@ public:
|
|||
virtual lldb::ThreadPlanSP 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 = eLazyBoolCalculate,
|
||||
LazyBool step_out_avoids_code_without_debug_info = eLazyBoolCalculate);
|
||||
|
||||
|
@ -801,6 +813,9 @@ public:
|
|||
/// @param[in] run_vote
|
||||
/// See standard meanings for the stop & run votes in ThreadPlan.h.
|
||||
///
|
||||
/// @param[out] status
|
||||
/// A status with an error if queuing failed.
|
||||
///
|
||||
/// @param[in] step_out_avoids_code_without_debug_info
|
||||
/// If eLazyBoolYes, if the step over steps out it will continue to step
|
||||
/// out till it comes to a frame with debug info.
|
||||
|
@ -812,10 +827,8 @@ public:
|
|||
//------------------------------------------------------------------
|
||||
virtual lldb::ThreadPlanSP QueueThreadPlanForStepOut(
|
||||
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 stop_other_threads, Vote stop_vote, Vote run_vote,
|
||||
uint32_t frame_idx, Status &status,
|
||||
LazyBool step_out_avoids_code_without_debug_info = eLazyBoolCalculate);
|
||||
|
||||
//------------------------------------------------------------------
|
||||
|
@ -846,9 +859,15 @@ public:
|
|||
/// \b true if we will stop other threads while we single step this one.
|
||||
///
|
||||
/// @param[in] stop_vote
|
||||
///
|
||||
/// @param[in] run_vote
|
||||
/// See standard meanings for the stop & run votes in ThreadPlan.h.
|
||||
///
|
||||
/// @param[in] frame_idx
|
||||
///
|
||||
/// @param[out] status
|
||||
/// A status with an error if queuing failed.
|
||||
///
|
||||
/// @param[in] continue_to_next_branch
|
||||
/// Normally this will enqueue a plan that will put a breakpoint on the
|
||||
/// return address and continue
|
||||
|
@ -872,16 +891,13 @@ public:
|
|||
//------------------------------------------------------------------
|
||||
virtual lldb::ThreadPlanSP QueueThreadPlanForStepOutNoShouldStop(
|
||||
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);
|
||||
bool stop_other_threads, Vote stop_vote, Vote run_vote,
|
||||
uint32_t frame_idx, Status &status, bool continue_to_next_branch = false);
|
||||
|
||||
//------------------------------------------------------------------
|
||||
/// Gets the plan used to step through the code that steps from a function
|
||||
/// call site at the current PC into the actual function call.
|
||||
///
|
||||
///
|
||||
/// @param[in] return_stack_id
|
||||
/// The stack id that we will return to (by setting backstop breakpoints on
|
||||
/// the return
|
||||
|
@ -895,14 +911,17 @@ public:
|
|||
/// @param[in] stop_other_threads
|
||||
/// \b true if we will stop other threads while we single step this one.
|
||||
///
|
||||
/// @param[out] status
|
||||
/// A status with an error if queuing failed.
|
||||
///
|
||||
/// @return
|
||||
/// A shared pointer to the newly queued thread plan, or nullptr if the
|
||||
/// plan could not be queued.
|
||||
//------------------------------------------------------------------
|
||||
virtual lldb::ThreadPlanSP
|
||||
QueueThreadPlanForStepThrough(StackID &return_stack_id,
|
||||
bool abort_other_plans,
|
||||
bool stop_other_threads);
|
||||
bool abort_other_plans, bool stop_other_threads,
|
||||
Status &status);
|
||||
|
||||
//------------------------------------------------------------------
|
||||
/// Gets the plan used to continue from the current PC.
|
||||
|
@ -920,22 +939,24 @@ public:
|
|||
/// @param[in] stop_other_threads
|
||||
/// \b true if we will stop other threads while we single step this one.
|
||||
///
|
||||
/// @param[out] status
|
||||
/// A status with an error if queuing failed.
|
||||
///
|
||||
/// @return
|
||||
/// A shared pointer to the newly queued thread plan, or nullptr if the
|
||||
/// plan could not be queued.
|
||||
//------------------------------------------------------------------
|
||||
virtual lldb::ThreadPlanSP
|
||||
QueueThreadPlanForRunToAddress(bool abort_other_plans, Address &target_addr,
|
||||
bool stop_other_threads);
|
||||
bool stop_other_threads, Status &status);
|
||||
|
||||
virtual lldb::ThreadPlanSP
|
||||
QueueThreadPlanForStepUntil(bool abort_other_plans,
|
||||
lldb::addr_t *address_list, size_t num_addresses,
|
||||
bool stop_others, uint32_t frame_idx);
|
||||
virtual lldb::ThreadPlanSP QueueThreadPlanForStepUntil(
|
||||
bool abort_other_plans, lldb::addr_t *address_list, size_t num_addresses,
|
||||
bool stop_others, uint32_t frame_idx, Status &status);
|
||||
|
||||
virtual lldb::ThreadPlanSP
|
||||
QueueThreadPlanForStepScripted(bool abort_other_plans, const char *class_name,
|
||||
bool stop_other_threads);
|
||||
bool stop_other_threads, Status &status);
|
||||
|
||||
//------------------------------------------------------------------
|
||||
// Thread Plan accessors:
|
||||
|
@ -1021,7 +1042,7 @@ public:
|
|||
/// false otherwise.
|
||||
//------------------------------------------------------------------
|
||||
bool CompletedPlanOverridesBreakpoint();
|
||||
|
||||
|
||||
//------------------------------------------------------------------
|
||||
/// Queues a generic thread plan.
|
||||
///
|
||||
|
@ -1036,7 +1057,7 @@ public:
|
|||
/// @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
|
||||
|
|
|
@ -596,10 +596,12 @@ protected:
|
|||
|
||||
bool IsUsuallyUnexplainedStopReason(lldb::StopReason);
|
||||
|
||||
Status m_status;
|
||||
Thread &m_thread;
|
||||
Vote m_stop_vote;
|
||||
Vote m_run_vote;
|
||||
bool m_takes_iteration_count = false;
|
||||
bool m_takes_iteration_count;
|
||||
bool m_could_not_resolve_hw_bp;
|
||||
int32_t m_iteration_count = 1;
|
||||
|
||||
private:
|
||||
|
@ -651,6 +653,8 @@ public:
|
|||
|
||||
bool OkayToDiscard() override { return false; }
|
||||
|
||||
const Status &GetStatus() { return m_status; }
|
||||
|
||||
protected:
|
||||
bool DoPlanExplainsStop(Event *event_ptr) override;
|
||||
|
||||
|
|
|
@ -59,6 +59,7 @@ protected:
|
|||
private:
|
||||
std::string m_class_name;
|
||||
StructuredData::ObjectSP m_implementation_sp;
|
||||
bool m_did_push;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(ThreadPlanPython);
|
||||
};
|
||||
|
|
|
@ -97,10 +97,12 @@ public:
|
|||
|
||||
void ClearShouldStopHereCallbacks() { m_callbacks.Clear(); }
|
||||
|
||||
bool InvokeShouldStopHereCallback(lldb::FrameComparison operation);
|
||||
bool InvokeShouldStopHereCallback(lldb::FrameComparison operation,
|
||||
Status &status);
|
||||
|
||||
lldb::ThreadPlanSP
|
||||
CheckShouldStopHereAndQueueStepOut(lldb::FrameComparison operation);
|
||||
CheckShouldStopHereAndQueueStepOut(lldb::FrameComparison operation,
|
||||
Status &status);
|
||||
|
||||
lldb_private::Flags &GetFlags() { return m_flags; }
|
||||
|
||||
|
@ -110,14 +112,16 @@ protected:
|
|||
static bool DefaultShouldStopHereCallback(ThreadPlan *current_plan,
|
||||
Flags &flags,
|
||||
lldb::FrameComparison operation,
|
||||
void *baton);
|
||||
Status &status, void *baton);
|
||||
|
||||
static lldb::ThreadPlanSP
|
||||
DefaultStepFromHereCallback(ThreadPlan *current_plan, Flags &flags,
|
||||
lldb::FrameComparison operation, void *baton);
|
||||
lldb::FrameComparison operation, Status &status,
|
||||
void *baton);
|
||||
|
||||
virtual lldb::ThreadPlanSP
|
||||
QueueStepOutFromHerePlan(Flags &flags, lldb::FrameComparison operation);
|
||||
QueueStepOutFromHerePlan(Flags &flags, lldb::FrameComparison operation,
|
||||
Status &status);
|
||||
|
||||
// Implement this, and call it in the plan's constructor to set the default
|
||||
// flags.
|
||||
|
|
|
@ -54,7 +54,7 @@ protected:
|
|||
static bool DefaultShouldStopHereCallback(ThreadPlan *current_plan,
|
||||
Flags &flags,
|
||||
lldb::FrameComparison operation,
|
||||
void *baton);
|
||||
Status &status, void *baton);
|
||||
|
||||
bool DoWillResume(lldb::StateType resume_state, bool current_plan) override;
|
||||
|
||||
|
@ -76,11 +76,11 @@ private:
|
|||
friend lldb::ThreadPlanSP Thread::QueueThreadPlanForStepOverRange(
|
||||
bool abort_other_plans, const AddressRange &range,
|
||||
const SymbolContext &addr_context, lldb::RunMode stop_others,
|
||||
LazyBool avoid_code_without_debug_info);
|
||||
Status &status, LazyBool avoid_code_without_debug_info);
|
||||
friend lldb::ThreadPlanSP Thread::QueueThreadPlanForStepInRange(
|
||||
bool abort_other_plans, const AddressRange &range,
|
||||
const SymbolContext &addr_context, const char *step_in_target,
|
||||
lldb::RunMode stop_others,
|
||||
lldb::RunMode stop_others, Status &status,
|
||||
LazyBool step_in_avoids_code_without_debug_info,
|
||||
LazyBool step_out_avoids_code_without_debug_info);
|
||||
|
||||
|
|
|
@ -39,7 +39,8 @@ protected:
|
|||
|
||||
private:
|
||||
friend lldb::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);
|
||||
|
||||
lldb::addr_t m_instruction_addr;
|
||||
bool m_stop_other_threads;
|
||||
|
|
|
@ -77,7 +77,7 @@ private:
|
|||
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, 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
|
||||
|
|
|
@ -41,10 +41,9 @@ protected:
|
|||
|
||||
private:
|
||||
friend lldb::ThreadPlanSP
|
||||
|
||||
Thread::QueueThreadPlanForStepThrough(StackID &return_stack_id,
|
||||
bool abort_other_plans,
|
||||
bool stop_others);
|
||||
bool stop_others, Status &status);
|
||||
|
||||
void ClearBackstopBreakpoint();
|
||||
|
||||
|
|
|
@ -55,7 +55,7 @@ private:
|
|||
|
||||
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);
|
||||
bool stop_others, uint32_t frame_idx, Status &status);
|
||||
|
||||
// Need an appropriate marker for the current stack so we can tell step out
|
||||
// from step in.
|
||||
|
|
|
@ -84,10 +84,10 @@ typedef void (*OptionValueChangedCallback)(void *baton,
|
|||
OptionValue *option_value);
|
||||
typedef bool (*ThreadPlanShouldStopHereCallback)(
|
||||
ThreadPlan *current_plan, Flags &flags, lldb::FrameComparison operation,
|
||||
void *baton);
|
||||
Status &status, void *baton);
|
||||
typedef lldb::ThreadPlanSP (*ThreadPlanStepFromHereCallback)(
|
||||
ThreadPlan *current_plan, Flags &flags, lldb::FrameComparison operation,
|
||||
void *baton);
|
||||
Status &status, void *baton);
|
||||
typedef UnwindAssembly *(*UnwindAssemblyCreateInstance)(const ArchSpec &arch);
|
||||
typedef lldb::MemoryHistorySP (*MemoryHistoryCreateInstance)(
|
||||
const lldb::ProcessSP &process_sp);
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
LEVEL = ../../../make
|
||||
|
||||
C_SOURCES := main.c
|
||||
|
||||
ifneq (,$(findstring icc,$(CC)))
|
||||
CFLAGS += -debug inline-debug-info
|
||||
endif
|
||||
|
||||
include $(LEVEL)/Makefile.rules
|
|
@ -0,0 +1,102 @@
|
|||
"""
|
||||
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):
|
||||
NO_DEBUG_INFO_TESTCASE = True
|
||||
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()
|
||||
|
||||
_, _, thread, _ = lldbutil.run_to_line_breakpoint(
|
||||
self, lldb.SBFileSpec("main.c"), 1)
|
||||
|
||||
self.runCmd("settings set target.require-hardware-breakpoint true")
|
||||
|
||||
# Ensure we fail in the interpreter.
|
||||
self.expect("thread step-in")
|
||||
self.expect("thread step-in", error=True)
|
||||
|
||||
# Ensure we fail when stepping through the API.
|
||||
error = lldb.SBError()
|
||||
thread.StepInto('', 4, error)
|
||||
self.assertTrue(error.Fail())
|
||||
self.assertTrue("Could not create hardware breakpoint for thread plan"
|
||||
in error.GetCString())
|
||||
|
||||
def test_step_out(self):
|
||||
"""Test stepping out when hardware breakpoints are required."""
|
||||
self.build()
|
||||
|
||||
_, _, thread, _ = lldbutil.run_to_line_breakpoint(
|
||||
self, lldb.SBFileSpec("main.c"), 1)
|
||||
|
||||
self.runCmd("settings set target.require-hardware-breakpoint true")
|
||||
|
||||
# Ensure this fails in the command interpreter.
|
||||
self.expect("thread step-out", error=True)
|
||||
|
||||
# Ensure we fail when stepping through the API.
|
||||
error = lldb.SBError()
|
||||
thread.StepOut(error)
|
||||
self.assertTrue(error.Fail())
|
||||
self.assertTrue("Could not create hardware breakpoint for thread plan"
|
||||
in error.GetCString())
|
||||
|
||||
def test_step_over(self):
|
||||
"""Test stepping over when hardware breakpoints are required."""
|
||||
self.build()
|
||||
|
||||
_, _, thread, _ = lldbutil.run_to_line_breakpoint(
|
||||
self, lldb.SBFileSpec("main.c"), 7)
|
||||
|
||||
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=[
|
||||
'step over failed',
|
||||
'Could not create hardware breakpoint for thread plan'
|
||||
])
|
||||
|
||||
def test_step_until(self):
|
||||
"""Test stepping until when hardware breakpoints are required."""
|
||||
self.build()
|
||||
|
||||
_, _, thread, _ = lldbutil.run_to_line_breakpoint(
|
||||
self, lldb.SBFileSpec("main.c"), 7)
|
||||
|
||||
self.runCmd("settings set target.require-hardware-breakpoint true")
|
||||
|
||||
self.expect("thread until 5", error=True)
|
||||
|
||||
# Ensure we fail when stepping through the API.
|
||||
error = thread.StepOverUntil(lldb.SBFrame(), lldb.SBFileSpec(), 5)
|
||||
self.assertTrue(error.Fail())
|
||||
self.assertTrue("Could not create hardware breakpoint for thread plan"
|
||||
in error.GetCString())
|
|
@ -0,0 +1,9 @@
|
|||
int break_on_me() {
|
||||
int i = 10;
|
||||
i++;
|
||||
return i;
|
||||
}
|
||||
|
||||
int main() {
|
||||
return break_on_me();
|
||||
}
|
|
@ -35,7 +35,7 @@ class StepScriptedTestCase(TestBase):
|
|||
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())
|
||||
|
|
|
@ -251,6 +251,9 @@ public:
|
|||
static uint32_t
|
||||
GetNumBreakpointLocationsFromEvent (const lldb::SBEvent &event_sp);
|
||||
|
||||
bool
|
||||
IsHardware ();
|
||||
|
||||
%pythoncode %{
|
||||
|
||||
class locations_access(object):
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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_ =
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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
|
||||
);
|
||||
);
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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 {
|
||||
} else if (m_return_bp_id == LLDB_INVALID_BREAK_ID) {
|
||||
if (error)
|
||||
error->PutCString("Could not create return breakpoint.");
|
||||
return false;
|
||||
} 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))
|
||||
|
|
Loading…
Reference in New Issue