204 lines · cpp
1//===-- ThreadPlanRunToAddress.cpp ----------------------------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#include "lldb/Target/ThreadPlanRunToAddress.h"10#include "lldb/Target/Process.h"11#include "lldb/Target/RegisterContext.h"12#include "lldb/Target/Target.h"13#include "lldb/Target/Thread.h"14#include "lldb/Utility/LLDBLog.h"15#include "lldb/Utility/Log.h"16#include "lldb/Utility/Stream.h"17 18using namespace lldb;19using namespace lldb_private;20 21// ThreadPlanRunToAddress: Continue plan22 23ThreadPlanRunToAddress::ThreadPlanRunToAddress(Thread &thread, Address &address,24 bool stop_others)25 : ThreadPlan(ThreadPlan::eKindRunToAddress, "Run to address plan", thread,26 eVoteNoOpinion, eVoteNoOpinion),27 m_stop_others(stop_others), m_addresses(), m_break_ids() {28 m_addresses.push_back(29 address.GetOpcodeLoadAddress(thread.CalculateTarget().get()));30 SetInitialBreakpoints();31}32 33ThreadPlanRunToAddress::ThreadPlanRunToAddress(Thread &thread,34 lldb::addr_t address,35 bool stop_others)36 : ThreadPlan(ThreadPlan::eKindRunToAddress, "Run to address plan", thread,37 eVoteNoOpinion, eVoteNoOpinion),38 m_stop_others(stop_others), m_addresses(), m_break_ids() {39 m_addresses.push_back(40 thread.CalculateTarget()->GetOpcodeLoadAddress(address));41 SetInitialBreakpoints();42}43 44ThreadPlanRunToAddress::ThreadPlanRunToAddress(45 Thread &thread, const std::vector<lldb::addr_t> &addresses,46 bool stop_others)47 : ThreadPlan(ThreadPlan::eKindRunToAddress, "Run to address plan", thread,48 eVoteNoOpinion, eVoteNoOpinion),49 m_stop_others(stop_others), m_addresses(addresses), m_break_ids() {50 // Convert all addresses into opcode addresses to make sure we set51 // breakpoints at the correct address.52 Target &target = thread.GetProcess()->GetTarget();53 std::vector<lldb::addr_t>::iterator pos, end = m_addresses.end();54 for (pos = m_addresses.begin(); pos != end; ++pos)55 *pos = target.GetOpcodeLoadAddress(*pos);56 57 SetInitialBreakpoints();58}59 60void ThreadPlanRunToAddress::SetInitialBreakpoints() {61 size_t num_addresses = m_addresses.size();62 m_break_ids.resize(num_addresses);63 64 for (size_t i = 0; i < num_addresses; i++) {65 Breakpoint *breakpoint;66 breakpoint =67 GetTarget().CreateBreakpoint(m_addresses[i], true, false).get();68 if (breakpoint != nullptr) {69 if (breakpoint->IsHardware() && !breakpoint->HasResolvedLocations())70 m_could_not_resolve_hw_bp = true;71 m_break_ids[i] = breakpoint->GetID();72 breakpoint->SetThreadID(m_tid);73 breakpoint->SetBreakpointKind("run-to-address");74 }75 }76}77 78ThreadPlanRunToAddress::~ThreadPlanRunToAddress() {79 size_t num_break_ids = m_break_ids.size();80 for (size_t i = 0; i < num_break_ids; i++) {81 GetTarget().RemoveBreakpointByID(m_break_ids[i]);82 }83 m_could_not_resolve_hw_bp = false;84}85 86void ThreadPlanRunToAddress::GetDescription(Stream *s,87 lldb::DescriptionLevel level) {88 size_t num_addresses = m_addresses.size();89 90 if (level == lldb::eDescriptionLevelBrief) {91 if (num_addresses == 0) {92 s->Printf("run to address with no addresses given.");93 return;94 } else if (num_addresses == 1)95 s->Printf("run to address: ");96 else97 s->Printf("run to addresses: ");98 99 for (size_t i = 0; i < num_addresses; i++) {100 DumpAddress(s->AsRawOstream(), m_addresses[i], sizeof(addr_t));101 s->Printf(" ");102 }103 } else {104 if (num_addresses == 0) {105 s->Printf("run to address with no addresses given.");106 return;107 } else if (num_addresses == 1)108 s->Printf("Run to address: ");109 else {110 s->Printf("Run to addresses: ");111 }112 113 for (size_t i = 0; i < num_addresses; i++) {114 if (num_addresses > 1) {115 s->Printf("\n");116 s->Indent();117 }118 119 DumpAddress(s->AsRawOstream(), m_addresses[i], sizeof(addr_t));120 s->Printf(" using breakpoint: %d - ", m_break_ids[i]);121 Breakpoint *breakpoint =122 GetTarget().GetBreakpointByID(m_break_ids[i]).get();123 if (breakpoint)124 breakpoint->Dump(s);125 else126 s->Printf("but the breakpoint has been deleted.");127 }128 }129}130 131bool ThreadPlanRunToAddress::ValidatePlan(Stream *error) {132 if (m_could_not_resolve_hw_bp) {133 if (error)134 error->Printf("Could not set hardware breakpoint(s)");135 return false;136 }137 138 // If we couldn't set the breakpoint for some reason, then this won't work.139 bool all_bps_good = true;140 size_t num_break_ids = m_break_ids.size();141 for (size_t i = 0; i < num_break_ids; i++) {142 if (m_break_ids[i] == LLDB_INVALID_BREAK_ID) {143 all_bps_good = false;144 if (error) {145 error->Printf("Could not set breakpoint for address: ");146 DumpAddress(error->AsRawOstream(), m_addresses[i], sizeof(addr_t));147 error->Printf("\n");148 }149 }150 }151 return all_bps_good;152}153 154bool ThreadPlanRunToAddress::DoPlanExplainsStop(Event *event_ptr) {155 return AtOurAddress();156}157 158bool ThreadPlanRunToAddress::ShouldStop(Event *event_ptr) {159 return AtOurAddress();160}161 162bool ThreadPlanRunToAddress::StopOthers() { return m_stop_others; }163 164void ThreadPlanRunToAddress::SetStopOthers(bool new_value) {165 m_stop_others = new_value;166}167 168StateType ThreadPlanRunToAddress::GetPlanRunState() { return eStateRunning; }169 170bool ThreadPlanRunToAddress::WillStop() { return true; }171 172bool ThreadPlanRunToAddress::MischiefManaged() {173 Log *log = GetLog(LLDBLog::Step);174 175 if (AtOurAddress()) {176 // Remove the breakpoint177 size_t num_break_ids = m_break_ids.size();178 179 for (size_t i = 0; i < num_break_ids; i++) {180 if (m_break_ids[i] != LLDB_INVALID_BREAK_ID) {181 GetTarget().RemoveBreakpointByID(m_break_ids[i]);182 m_break_ids[i] = LLDB_INVALID_BREAK_ID;183 }184 }185 LLDB_LOGF(log, "Completed run to address plan.");186 ThreadPlan::MischiefManaged();187 return true;188 } else189 return false;190}191 192bool ThreadPlanRunToAddress::AtOurAddress() {193 lldb::addr_t current_address = GetThread().GetRegisterContext()->GetPC();194 bool found_it = false;195 size_t num_addresses = m_addresses.size();196 for (size_t i = 0; i < num_addresses; i++) {197 if (m_addresses[i] == current_address) {198 found_it = true;199 break;200 }201 }202 return found_it;203}204