blob: 5012d15b587c4004fd047287d99f7b24d3b835cb [file]
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#include "lldb/Target/ThreadPlanRunToBreakpoint.h"
#include "lldb/Breakpoint/BreakpointLocation.h"
#include "lldb/Target/Process.h"
#include "lldb/Target/RegisterContext.h"
#include "lldb/Target/Target.h"
#include "lldb/Target/Thread.h"
#include "lldb/Utility/LLDBLog.h"
#include "lldb/Utility/Log.h"
#include "lldb/Utility/Stream.h"
using namespace lldb;
using namespace lldb_private;
ThreadPlanRunToBreakpoint::ThreadPlanRunToBreakpoint(Thread &thread,
BreakpointSP bkpt_sp,
bool stop_others)
: ThreadPlan(ThreadPlan::eKindRunToBreakpoint, "Run to breakpoint plan",
thread, eVoteNoOpinion, eVoteNoOpinion),
m_stop_others(stop_others) {
if (bkpt_sp)
m_breakpoints.push_back(std::move(bkpt_sp));
}
ThreadPlanRunToBreakpoint::ThreadPlanRunToBreakpoint(
Thread &thread, const std::vector<BreakpointSP> &breakpoints,
bool stop_others)
: ThreadPlan(ThreadPlan::eKindRunToBreakpoint, "Run to breakpoint plan",
thread, eVoteNoOpinion, eVoteNoOpinion),
m_stop_others(stop_others) {
for (auto bkpt_sp : breakpoints) {
// Make the breakpoints thread specific:
if (bkpt_sp) {
bkpt_sp->SetThreadID(thread.GetID());
m_breakpoints.push_back(bkpt_sp);
}
}
}
ThreadPlanRunToBreakpoint::~ThreadPlanRunToBreakpoint() {
for (auto bkpt_sp : m_breakpoints)
GetTarget().RemoveBreakpointByID(bkpt_sp->GetID());
}
void ThreadPlanRunToBreakpoint::GetDescription(Stream *s,
lldb::DescriptionLevel level) {
size_t num_bkpts = m_breakpoints.size();
if (level == lldb::eDescriptionLevelBrief) {
if (num_bkpts == 0) {
s->PutCString("run to breakpoint with no breakpoints given.");
return;
} else if (num_bkpts == 1)
s->PutCString("run to breakpoint: ");
else
s->PutCString("run to breakpoints: ");
for (auto bkpt_sp : m_breakpoints) {
*s << llvm::formatv("{0} ", bkpt_sp->GetID());
}
} else {
if (num_bkpts == 0) {
s->PutCString("run to breakpoint with no breakpoints given.");
return;
} else if (num_bkpts == 1)
s->PutCString("Run to breakpoint: ");
else {
s->PutCString("Run to breakpoints: ");
}
// FIXME: I'm not preserving breakpoint ID's
// in case I'm asked GetDescription after I've removed them.
for (auto bkpt_sp : m_breakpoints) {
s->PutCString("\n");
s->Indent();
bkpt_sp->Dump(s);
}
}
}
bool ThreadPlanRunToBreakpoint::ValidatePlan(Stream *error) {
// We don't require that the breakpoints we were given actually
// resolve to something when the plan was pushed. The only error
// was not to have passed any breakpoints.
return m_breakpoints.size() != 0;
}
bool ThreadPlanRunToBreakpoint::DoPlanExplainsStop(Event *event_ptr) {
return AtOurBreakpoint();
}
bool ThreadPlanRunToBreakpoint::ShouldStop(Event *event_ptr) {
return AtOurBreakpoint();
}
bool ThreadPlanRunToBreakpoint::StopOthers() { return m_stop_others; }
void ThreadPlanRunToBreakpoint::SetStopOthers(bool new_value) {
m_stop_others = new_value;
}
StateType ThreadPlanRunToBreakpoint::GetPlanRunState() { return eStateRunning; }
bool ThreadPlanRunToBreakpoint::WillStop() { return true; }
bool ThreadPlanRunToBreakpoint::MischiefManaged() {
Log *log = GetLog(LLDBLog::Step);
if (AtOurBreakpoint()) {
// Remove the breakpoints
for (auto bkpt_sp : m_breakpoints) {
GetTarget().RemoveBreakpointByID(bkpt_sp->GetID());
}
m_breakpoints.clear();
LLDB_LOGF(log, "Completed run to breakpoint plan.");
ThreadPlan::MischiefManaged();
return true;
}
return false;
}
bool ThreadPlanRunToBreakpoint::AtOurBreakpoint() {
lldb::addr_t current_addr = GetThread().GetRegisterContext()->GetPC();
Address current_address;
current_address.SetLoadAddress(current_addr, &GetTarget());
bool found_it = false;
for (auto bkpt_sp : m_breakpoints) {
if (auto location_sp = bkpt_sp->FindLocationByAddress(current_address)) {
StreamString s;
location_sp->GetDescription(&s, eDescriptionLevelBrief);
LLDB_LOG(GetLog(LLDBLog::Step), "RunToBreakpoint hit breakpoint: {0}", s);
found_it = true;
break;
}
}
return found_it;
}