forked from OSchip/llvm-project
205 lines
6.5 KiB
C++
205 lines
6.5 KiB
C++
//===-- ThreadPlanRunToAddress.cpp ------------------------------*- C++ -*-===//
|
|
//
|
|
// The LLVM Compiler Infrastructure
|
|
//
|
|
// This file is distributed under the University of Illinois Open Source
|
|
// License. See LICENSE.TXT for details.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// C Includes
|
|
// C++ Includes
|
|
// Other libraries and framework includes
|
|
// Project includes
|
|
#include "lldb/Target/ThreadPlanRunToAddress.h"
|
|
#include "lldb/Core/Log.h"
|
|
#include "lldb/Core/Stream.h"
|
|
#include "lldb/Target/Process.h"
|
|
#include "lldb/Target/RegisterContext.h"
|
|
#include "lldb/Target/Target.h"
|
|
#include "lldb/Target/Thread.h"
|
|
|
|
using namespace lldb;
|
|
using namespace lldb_private;
|
|
|
|
//----------------------------------------------------------------------
|
|
// ThreadPlanRunToAddress: Continue plan
|
|
//----------------------------------------------------------------------
|
|
|
|
ThreadPlanRunToAddress::ThreadPlanRunToAddress(Thread &thread, Address &address,
|
|
bool stop_others)
|
|
: ThreadPlan(ThreadPlan::eKindRunToAddress, "Run to address plan", thread,
|
|
eVoteNoOpinion, eVoteNoOpinion),
|
|
m_stop_others(stop_others), m_addresses(), m_break_ids() {
|
|
m_addresses.push_back(
|
|
address.GetOpcodeLoadAddress(m_thread.CalculateTarget().get()));
|
|
SetInitialBreakpoints();
|
|
}
|
|
|
|
ThreadPlanRunToAddress::ThreadPlanRunToAddress(Thread &thread,
|
|
lldb::addr_t address,
|
|
bool stop_others)
|
|
: ThreadPlan(ThreadPlan::eKindRunToAddress, "Run to address plan", thread,
|
|
eVoteNoOpinion, eVoteNoOpinion),
|
|
m_stop_others(stop_others), m_addresses(), m_break_ids() {
|
|
m_addresses.push_back(
|
|
m_thread.CalculateTarget()->GetOpcodeLoadAddress(address));
|
|
SetInitialBreakpoints();
|
|
}
|
|
|
|
ThreadPlanRunToAddress::ThreadPlanRunToAddress(
|
|
Thread &thread, const std::vector<lldb::addr_t> &addresses,
|
|
bool stop_others)
|
|
: ThreadPlan(ThreadPlan::eKindRunToAddress, "Run to address plan", thread,
|
|
eVoteNoOpinion, eVoteNoOpinion),
|
|
m_stop_others(stop_others), m_addresses(addresses), m_break_ids() {
|
|
// Convert all addresses into opcode addresses to make sure we set
|
|
// breakpoints at the correct address.
|
|
Target &target = thread.GetProcess()->GetTarget();
|
|
std::vector<lldb::addr_t>::iterator pos, end = m_addresses.end();
|
|
for (pos = m_addresses.begin(); pos != end; ++pos)
|
|
*pos = target.GetOpcodeLoadAddress(*pos);
|
|
|
|
SetInitialBreakpoints();
|
|
}
|
|
|
|
void ThreadPlanRunToAddress::SetInitialBreakpoints() {
|
|
size_t num_addresses = m_addresses.size();
|
|
m_break_ids.resize(num_addresses);
|
|
|
|
for (size_t i = 0; i < num_addresses; i++) {
|
|
Breakpoint *breakpoint;
|
|
breakpoint = m_thread.CalculateTarget()
|
|
->CreateBreakpoint(m_addresses[i], true, false)
|
|
.get();
|
|
if (breakpoint != nullptr) {
|
|
m_break_ids[i] = breakpoint->GetID();
|
|
breakpoint->SetThreadID(m_thread.GetID());
|
|
breakpoint->SetBreakpointKind("run-to-address");
|
|
}
|
|
}
|
|
}
|
|
|
|
ThreadPlanRunToAddress::~ThreadPlanRunToAddress() {
|
|
size_t num_break_ids = m_break_ids.size();
|
|
for (size_t i = 0; i < num_break_ids; i++) {
|
|
m_thread.CalculateTarget()->RemoveBreakpointByID(m_break_ids[i]);
|
|
}
|
|
}
|
|
|
|
void ThreadPlanRunToAddress::GetDescription(Stream *s,
|
|
lldb::DescriptionLevel level) {
|
|
size_t num_addresses = m_addresses.size();
|
|
|
|
if (level == lldb::eDescriptionLevelBrief) {
|
|
if (num_addresses == 0) {
|
|
s->Printf("run to address with no addresses given.");
|
|
return;
|
|
} else if (num_addresses == 1)
|
|
s->Printf("run to address: ");
|
|
else
|
|
s->Printf("run to addresses: ");
|
|
|
|
for (size_t i = 0; i < num_addresses; i++) {
|
|
s->Address(m_addresses[i], sizeof(addr_t));
|
|
s->Printf(" ");
|
|
}
|
|
} else {
|
|
if (num_addresses == 0) {
|
|
s->Printf("run to address with no addresses given.");
|
|
return;
|
|
} else if (num_addresses == 1)
|
|
s->Printf("Run to address: ");
|
|
else {
|
|
s->Printf("Run to addresses: ");
|
|
}
|
|
|
|
for (size_t i = 0; i < num_addresses; i++) {
|
|
if (num_addresses > 1) {
|
|
s->Printf("\n");
|
|
s->Indent();
|
|
}
|
|
|
|
s->Address(m_addresses[i], sizeof(addr_t));
|
|
s->Printf(" using breakpoint: %d - ", m_break_ids[i]);
|
|
Breakpoint *breakpoint =
|
|
m_thread.CalculateTarget()->GetBreakpointByID(m_break_ids[i]).get();
|
|
if (breakpoint)
|
|
breakpoint->Dump(s);
|
|
else
|
|
s->Printf("but the breakpoint has been deleted.");
|
|
}
|
|
}
|
|
}
|
|
|
|
bool ThreadPlanRunToAddress::ValidatePlan(Stream *error) {
|
|
// 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;
|
|
if (error) {
|
|
error->Printf("Could not set breakpoint for address: ");
|
|
error->Address(m_addresses[i], sizeof(addr_t));
|
|
error->Printf("\n");
|
|
}
|
|
}
|
|
}
|
|
return all_bps_good;
|
|
}
|
|
|
|
bool ThreadPlanRunToAddress::DoPlanExplainsStop(Event *event_ptr) {
|
|
return AtOurAddress();
|
|
}
|
|
|
|
bool ThreadPlanRunToAddress::ShouldStop(Event *event_ptr) {
|
|
return AtOurAddress();
|
|
}
|
|
|
|
bool ThreadPlanRunToAddress::StopOthers() { return m_stop_others; }
|
|
|
|
void ThreadPlanRunToAddress::SetStopOthers(bool new_value) {
|
|
m_stop_others = new_value;
|
|
}
|
|
|
|
StateType ThreadPlanRunToAddress::GetPlanRunState() { return eStateRunning; }
|
|
|
|
bool ThreadPlanRunToAddress::WillStop() { return true; }
|
|
|
|
bool ThreadPlanRunToAddress::MischiefManaged() {
|
|
Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP));
|
|
|
|
if (AtOurAddress()) {
|
|
// Remove the breakpoint
|
|
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) {
|
|
m_thread.CalculateTarget()->RemoveBreakpointByID(m_break_ids[i]);
|
|
m_break_ids[i] = LLDB_INVALID_BREAK_ID;
|
|
}
|
|
}
|
|
if (log)
|
|
log->Printf("Completed run to address plan.");
|
|
ThreadPlan::MischiefManaged();
|
|
return true;
|
|
} else
|
|
return false;
|
|
}
|
|
|
|
bool ThreadPlanRunToAddress::AtOurAddress() {
|
|
lldb::addr_t current_address = m_thread.GetRegisterContext()->GetPC();
|
|
bool found_it = false;
|
|
size_t num_addresses = m_addresses.size();
|
|
for (size_t i = 0; i < num_addresses; i++) {
|
|
if (m_addresses[i] == current_address) {
|
|
found_it = true;
|
|
break;
|
|
}
|
|
}
|
|
return found_it;
|
|
}
|