180814287SRaphael Isemann //===-- ThreadPlanRunToAddress.cpp ----------------------------------------===//
230fdc8d8SChris Lattner //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
630fdc8d8SChris Lattner //
730fdc8d8SChris Lattner //===----------------------------------------------------------------------===//
830fdc8d8SChris Lattner
9e65b2cf2SEugene Zelenko #include "lldb/Target/ThreadPlanRunToAddress.h"
1030fdc8d8SChris Lattner #include "lldb/Target/Process.h"
1130fdc8d8SChris Lattner #include "lldb/Target/RegisterContext.h"
12b9c1b51eSKate Stone #include "lldb/Target/Target.h"
13b9c1b51eSKate Stone #include "lldb/Target/Thread.h"
14*c34698a8SPavel Labath #include "lldb/Utility/LLDBLog.h"
156f9e6901SZachary Turner #include "lldb/Utility/Log.h"
16bf9a7730SZachary Turner #include "lldb/Utility/Stream.h"
1730fdc8d8SChris Lattner
1830fdc8d8SChris Lattner using namespace lldb;
1930fdc8d8SChris Lattner using namespace lldb_private;
2030fdc8d8SChris Lattner
2130fdc8d8SChris Lattner // ThreadPlanRunToAddress: Continue plan
2230fdc8d8SChris Lattner
ThreadPlanRunToAddress(Thread & thread,Address & address,bool stop_others)23b9c1b51eSKate Stone ThreadPlanRunToAddress::ThreadPlanRunToAddress(Thread &thread, Address &address,
24b9c1b51eSKate Stone bool stop_others)
25b9c1b51eSKate Stone : ThreadPlan(ThreadPlan::eKindRunToAddress, "Run to address plan", thread,
26b9c1b51eSKate Stone eVoteNoOpinion, eVoteNoOpinion),
27b9c1b51eSKate Stone m_stop_others(stop_others), m_addresses(), m_break_ids() {
28b9c1b51eSKate Stone m_addresses.push_back(
29e4598dc0SJim Ingham address.GetOpcodeLoadAddress(thread.CalculateTarget().get()));
3008b87e0dSJim Ingham SetInitialBreakpoints();
3130fdc8d8SChris Lattner }
3230fdc8d8SChris Lattner
ThreadPlanRunToAddress(Thread & thread,lldb::addr_t address,bool stop_others)33b9c1b51eSKate Stone ThreadPlanRunToAddress::ThreadPlanRunToAddress(Thread &thread,
3430fdc8d8SChris Lattner lldb::addr_t address,
35b9c1b51eSKate Stone bool stop_others)
36b9c1b51eSKate Stone : ThreadPlan(ThreadPlan::eKindRunToAddress, "Run to address plan", thread,
37b9c1b51eSKate Stone eVoteNoOpinion, eVoteNoOpinion),
38b9c1b51eSKate Stone m_stop_others(stop_others), m_addresses(), m_break_ids() {
39b9c1b51eSKate Stone m_addresses.push_back(
40e4598dc0SJim Ingham thread.CalculateTarget()->GetOpcodeLoadAddress(address));
4108b87e0dSJim Ingham SetInitialBreakpoints();
4208b87e0dSJim Ingham }
4308b87e0dSJim Ingham
ThreadPlanRunToAddress(Thread & thread,const std::vector<lldb::addr_t> & addresses,bool stop_others)44b9c1b51eSKate Stone ThreadPlanRunToAddress::ThreadPlanRunToAddress(
45b9c1b51eSKate Stone Thread &thread, const std::vector<lldb::addr_t> &addresses,
46b9c1b51eSKate Stone bool stop_others)
47b9c1b51eSKate Stone : ThreadPlan(ThreadPlan::eKindRunToAddress, "Run to address plan", thread,
48b9c1b51eSKate Stone eVoteNoOpinion, eVoteNoOpinion),
49b9c1b51eSKate Stone m_stop_others(stop_others), m_addresses(addresses), m_break_ids() {
50d93c4a33SBruce Mitchener // Convert all addresses into opcode addresses to make sure we set
51f3ef3d2aSGreg Clayton // breakpoints at the correct address.
521ac04c30SGreg Clayton Target &target = thread.GetProcess()->GetTarget();
53f3ef3d2aSGreg Clayton std::vector<lldb::addr_t>::iterator pos, end = m_addresses.end();
54f3ef3d2aSGreg Clayton for (pos = m_addresses.begin(); pos != end; ++pos)
55f3ef3d2aSGreg Clayton *pos = target.GetOpcodeLoadAddress(*pos);
56f3ef3d2aSGreg Clayton
5708b87e0dSJim Ingham SetInitialBreakpoints();
5830fdc8d8SChris Lattner }
5930fdc8d8SChris Lattner
SetInitialBreakpoints()60b9c1b51eSKate Stone void ThreadPlanRunToAddress::SetInitialBreakpoints() {
6108b87e0dSJim Ingham size_t num_addresses = m_addresses.size();
6208b87e0dSJim Ingham m_break_ids.resize(num_addresses);
6308b87e0dSJim Ingham
64b9c1b51eSKate Stone for (size_t i = 0; i < num_addresses; i++) {
6530fdc8d8SChris Lattner Breakpoint *breakpoint;
66e4598dc0SJim Ingham breakpoint =
67e4598dc0SJim Ingham GetTarget().CreateBreakpoint(m_addresses[i], true, false).get();
68b9c1b51eSKate Stone if (breakpoint != nullptr) {
69e103ae92SJonas Devlieghere if (breakpoint->IsHardware() && !breakpoint->HasResolvedLocations())
70e103ae92SJonas Devlieghere m_could_not_resolve_hw_bp = true;
7108b87e0dSJim Ingham m_break_ids[i] = breakpoint->GetID();
72e4598dc0SJim Ingham breakpoint->SetThreadID(m_tid);
732995077dSJim Ingham breakpoint->SetBreakpointKind("run-to-address");
7430fdc8d8SChris Lattner }
7530fdc8d8SChris Lattner }
7608b87e0dSJim Ingham }
7730fdc8d8SChris Lattner
~ThreadPlanRunToAddress()78b9c1b51eSKate Stone ThreadPlanRunToAddress::~ThreadPlanRunToAddress() {
7908b87e0dSJim Ingham size_t num_break_ids = m_break_ids.size();
80b9c1b51eSKate Stone for (size_t i = 0; i < num_break_ids; i++) {
81e4598dc0SJim Ingham GetTarget().RemoveBreakpointByID(m_break_ids[i]);
8230fdc8d8SChris Lattner }
83e103ae92SJonas Devlieghere m_could_not_resolve_hw_bp = false;
8430fdc8d8SChris Lattner }
8530fdc8d8SChris Lattner
GetDescription(Stream * s,lldb::DescriptionLevel level)86b9c1b51eSKate Stone void ThreadPlanRunToAddress::GetDescription(Stream *s,
87b9c1b51eSKate Stone lldb::DescriptionLevel level) {
8808b87e0dSJim Ingham size_t num_addresses = m_addresses.size();
8908b87e0dSJim Ingham
90b9c1b51eSKate Stone if (level == lldb::eDescriptionLevelBrief) {
91b9c1b51eSKate Stone if (num_addresses == 0) {
9208b87e0dSJim Ingham s->Printf("run to address with no addresses given.");
9308b87e0dSJim Ingham return;
94b9c1b51eSKate Stone } else if (num_addresses == 1)
9530fdc8d8SChris Lattner s->Printf("run to address: ");
9608b87e0dSJim Ingham else
9708b87e0dSJim Ingham s->Printf("run to addresses: ");
9808b87e0dSJim Ingham
99b9c1b51eSKate Stone for (size_t i = 0; i < num_addresses; i++) {
1001462f5a4SRaphael Isemann DumpAddress(s->AsRawOstream(), m_addresses[i], sizeof(addr_t));
10108b87e0dSJim Ingham s->Printf(" ");
10208b87e0dSJim Ingham }
103b9c1b51eSKate Stone } else {
104b9c1b51eSKate Stone if (num_addresses == 0) {
10508b87e0dSJim Ingham s->Printf("run to address with no addresses given.");
10608b87e0dSJim Ingham return;
107b9c1b51eSKate Stone } else if (num_addresses == 1)
10830fdc8d8SChris Lattner s->Printf("Run to address: ");
109b9c1b51eSKate Stone else {
11008b87e0dSJim Ingham s->Printf("Run to addresses: ");
11108b87e0dSJim Ingham }
11208b87e0dSJim Ingham
113b9c1b51eSKate Stone for (size_t i = 0; i < num_addresses; i++) {
114b9c1b51eSKate Stone if (num_addresses > 1) {
11508b87e0dSJim Ingham s->Printf("\n");
11608b87e0dSJim Ingham s->Indent();
11708b87e0dSJim Ingham }
11808b87e0dSJim Ingham
1191462f5a4SRaphael Isemann DumpAddress(s->AsRawOstream(), m_addresses[i], sizeof(addr_t));
120f58a0487SJim Ingham s->Printf(" using breakpoint: %d - ", m_break_ids[i]);
121b9c1b51eSKate Stone Breakpoint *breakpoint =
122e4598dc0SJim Ingham GetTarget().GetBreakpointByID(m_break_ids[i]).get();
12330fdc8d8SChris Lattner if (breakpoint)
12430fdc8d8SChris Lattner breakpoint->Dump(s);
12530fdc8d8SChris Lattner else
12630fdc8d8SChris Lattner s->Printf("but the breakpoint has been deleted.");
12730fdc8d8SChris Lattner }
12830fdc8d8SChris Lattner }
12908b87e0dSJim Ingham }
13030fdc8d8SChris Lattner
ValidatePlan(Stream * error)131b9c1b51eSKate Stone bool ThreadPlanRunToAddress::ValidatePlan(Stream *error) {
132e103ae92SJonas Devlieghere if (m_could_not_resolve_hw_bp) {
133e103ae92SJonas Devlieghere if (error)
134e103ae92SJonas Devlieghere error->Printf("Could not set hardware breakpoint(s)");
135e103ae92SJonas Devlieghere return false;
136e103ae92SJonas Devlieghere }
137e103ae92SJonas Devlieghere
13805097246SAdrian Prantl // If we couldn't set the breakpoint for some reason, then this won't work.
13908b87e0dSJim Ingham bool all_bps_good = true;
14008b87e0dSJim Ingham size_t num_break_ids = m_break_ids.size();
141b9c1b51eSKate Stone for (size_t i = 0; i < num_break_ids; i++) {
142b9c1b51eSKate Stone if (m_break_ids[i] == LLDB_INVALID_BREAK_ID) {
14308b87e0dSJim Ingham all_bps_good = false;
144b9c1b51eSKate Stone if (error) {
14508b87e0dSJim Ingham error->Printf("Could not set breakpoint for address: ");
1461462f5a4SRaphael Isemann DumpAddress(error->AsRawOstream(), m_addresses[i], sizeof(addr_t));
14708b87e0dSJim Ingham error->Printf("\n");
14808b87e0dSJim Ingham }
14908b87e0dSJim Ingham }
150f48169bbSJim Ingham }
15108b87e0dSJim Ingham return all_bps_good;
15230fdc8d8SChris Lattner }
15330fdc8d8SChris Lattner
DoPlanExplainsStop(Event * event_ptr)154b9c1b51eSKate Stone bool ThreadPlanRunToAddress::DoPlanExplainsStop(Event *event_ptr) {
15530fdc8d8SChris Lattner return AtOurAddress();
15630fdc8d8SChris Lattner }
15730fdc8d8SChris Lattner
ShouldStop(Event * event_ptr)158b9c1b51eSKate Stone bool ThreadPlanRunToAddress::ShouldStop(Event *event_ptr) {
1591fd2f08eSJim Ingham return AtOurAddress();
16030fdc8d8SChris Lattner }
16130fdc8d8SChris Lattner
StopOthers()162b9c1b51eSKate Stone bool ThreadPlanRunToAddress::StopOthers() { return m_stop_others; }
16330fdc8d8SChris Lattner
SetStopOthers(bool new_value)164b9c1b51eSKate Stone void ThreadPlanRunToAddress::SetStopOthers(bool new_value) {
16530fdc8d8SChris Lattner m_stop_others = new_value;
16630fdc8d8SChris Lattner }
16730fdc8d8SChris Lattner
GetPlanRunState()168b9c1b51eSKate Stone StateType ThreadPlanRunToAddress::GetPlanRunState() { return eStateRunning; }
16930fdc8d8SChris Lattner
WillStop()170b9c1b51eSKate Stone bool ThreadPlanRunToAddress::WillStop() { return true; }
17130fdc8d8SChris Lattner
MischiefManaged()172b9c1b51eSKate Stone bool ThreadPlanRunToAddress::MischiefManaged() {
173a007a6d8SPavel Labath Log *log = GetLog(LLDBLog::Step);
17430fdc8d8SChris Lattner
175b9c1b51eSKate Stone if (AtOurAddress()) {
17630fdc8d8SChris Lattner // Remove the breakpoint
17708b87e0dSJim Ingham size_t num_break_ids = m_break_ids.size();
17830fdc8d8SChris Lattner
179b9c1b51eSKate Stone for (size_t i = 0; i < num_break_ids; i++) {
180b9c1b51eSKate Stone if (m_break_ids[i] != LLDB_INVALID_BREAK_ID) {
181e4598dc0SJim Ingham GetTarget().RemoveBreakpointByID(m_break_ids[i]);
18208b87e0dSJim Ingham m_break_ids[i] = LLDB_INVALID_BREAK_ID;
18308b87e0dSJim Ingham }
18408b87e0dSJim Ingham }
18563e5fb76SJonas Devlieghere LLDB_LOGF(log, "Completed run to address plan.");
18630fdc8d8SChris Lattner ThreadPlan::MischiefManaged();
18730fdc8d8SChris Lattner return true;
188b9c1b51eSKate Stone } else
18930fdc8d8SChris Lattner return false;
19030fdc8d8SChris Lattner }
19130fdc8d8SChris Lattner
AtOurAddress()192b9c1b51eSKate Stone bool ThreadPlanRunToAddress::AtOurAddress() {
193e4598dc0SJim Ingham lldb::addr_t current_address = GetThread().GetRegisterContext()->GetPC();
19408b87e0dSJim Ingham bool found_it = false;
1954bf570d6SJim Ingham size_t num_addresses = m_addresses.size();
196b9c1b51eSKate Stone for (size_t i = 0; i < num_addresses; i++) {
197b9c1b51eSKate Stone if (m_addresses[i] == current_address) {
19808b87e0dSJim Ingham found_it = true;
19908b87e0dSJim Ingham break;
20008b87e0dSJim Ingham }
20108b87e0dSJim Ingham }
20208b87e0dSJim Ingham return found_it;
20330fdc8d8SChris Lattner }
204