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