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:
@@ -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) {
|
||||
|
||||
Reference in New Issue
Block a user