1dda28197Spatrick //===-- ThreadPlanRunToAddress.cpp ----------------------------------------===//
2061da546Spatrick //
3061da546Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4061da546Spatrick // See https://llvm.org/LICENSE.txt for license information.
5061da546Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6061da546Spatrick //
7061da546Spatrick //===----------------------------------------------------------------------===//
8061da546Spatrick
9061da546Spatrick #include "lldb/Target/ThreadPlanRunToAddress.h"
10061da546Spatrick #include "lldb/Target/Process.h"
11061da546Spatrick #include "lldb/Target/RegisterContext.h"
12061da546Spatrick #include "lldb/Target/Target.h"
13061da546Spatrick #include "lldb/Target/Thread.h"
14*f6aab3d8Srobert #include "lldb/Utility/LLDBLog.h"
15061da546Spatrick #include "lldb/Utility/Log.h"
16061da546Spatrick #include "lldb/Utility/Stream.h"
17061da546Spatrick
18061da546Spatrick using namespace lldb;
19061da546Spatrick using namespace lldb_private;
20061da546Spatrick
21061da546Spatrick // ThreadPlanRunToAddress: Continue plan
22061da546Spatrick
ThreadPlanRunToAddress(Thread & thread,Address & address,bool stop_others)23061da546Spatrick ThreadPlanRunToAddress::ThreadPlanRunToAddress(Thread &thread, Address &address,
24061da546Spatrick bool stop_others)
25061da546Spatrick : ThreadPlan(ThreadPlan::eKindRunToAddress, "Run to address plan", thread,
26061da546Spatrick eVoteNoOpinion, eVoteNoOpinion),
27061da546Spatrick m_stop_others(stop_others), m_addresses(), m_break_ids() {
28061da546Spatrick m_addresses.push_back(
29dda28197Spatrick address.GetOpcodeLoadAddress(thread.CalculateTarget().get()));
30061da546Spatrick SetInitialBreakpoints();
31061da546Spatrick }
32061da546Spatrick
ThreadPlanRunToAddress(Thread & thread,lldb::addr_t address,bool stop_others)33061da546Spatrick ThreadPlanRunToAddress::ThreadPlanRunToAddress(Thread &thread,
34061da546Spatrick lldb::addr_t address,
35061da546Spatrick bool stop_others)
36061da546Spatrick : ThreadPlan(ThreadPlan::eKindRunToAddress, "Run to address plan", thread,
37061da546Spatrick eVoteNoOpinion, eVoteNoOpinion),
38061da546Spatrick m_stop_others(stop_others), m_addresses(), m_break_ids() {
39061da546Spatrick m_addresses.push_back(
40dda28197Spatrick thread.CalculateTarget()->GetOpcodeLoadAddress(address));
41061da546Spatrick SetInitialBreakpoints();
42061da546Spatrick }
43061da546Spatrick
ThreadPlanRunToAddress(Thread & thread,const std::vector<lldb::addr_t> & addresses,bool stop_others)44061da546Spatrick ThreadPlanRunToAddress::ThreadPlanRunToAddress(
45061da546Spatrick Thread &thread, const std::vector<lldb::addr_t> &addresses,
46061da546Spatrick bool stop_others)
47061da546Spatrick : ThreadPlan(ThreadPlan::eKindRunToAddress, "Run to address plan", thread,
48061da546Spatrick eVoteNoOpinion, eVoteNoOpinion),
49061da546Spatrick m_stop_others(stop_others), m_addresses(addresses), m_break_ids() {
50061da546Spatrick // Convert all addresses into opcode addresses to make sure we set
51061da546Spatrick // breakpoints at the correct address.
52061da546Spatrick Target &target = thread.GetProcess()->GetTarget();
53061da546Spatrick std::vector<lldb::addr_t>::iterator pos, end = m_addresses.end();
54061da546Spatrick for (pos = m_addresses.begin(); pos != end; ++pos)
55061da546Spatrick *pos = target.GetOpcodeLoadAddress(*pos);
56061da546Spatrick
57061da546Spatrick SetInitialBreakpoints();
58061da546Spatrick }
59061da546Spatrick
SetInitialBreakpoints()60061da546Spatrick void ThreadPlanRunToAddress::SetInitialBreakpoints() {
61061da546Spatrick size_t num_addresses = m_addresses.size();
62061da546Spatrick m_break_ids.resize(num_addresses);
63061da546Spatrick
64061da546Spatrick for (size_t i = 0; i < num_addresses; i++) {
65061da546Spatrick Breakpoint *breakpoint;
66dda28197Spatrick breakpoint =
67dda28197Spatrick GetTarget().CreateBreakpoint(m_addresses[i], true, false).get();
68061da546Spatrick if (breakpoint != nullptr) {
69061da546Spatrick if (breakpoint->IsHardware() && !breakpoint->HasResolvedLocations())
70061da546Spatrick m_could_not_resolve_hw_bp = true;
71061da546Spatrick m_break_ids[i] = breakpoint->GetID();
72dda28197Spatrick breakpoint->SetThreadID(m_tid);
73061da546Spatrick breakpoint->SetBreakpointKind("run-to-address");
74061da546Spatrick }
75061da546Spatrick }
76061da546Spatrick }
77061da546Spatrick
~ThreadPlanRunToAddress()78061da546Spatrick ThreadPlanRunToAddress::~ThreadPlanRunToAddress() {
79061da546Spatrick size_t num_break_ids = m_break_ids.size();
80061da546Spatrick for (size_t i = 0; i < num_break_ids; i++) {
81dda28197Spatrick GetTarget().RemoveBreakpointByID(m_break_ids[i]);
82061da546Spatrick }
83061da546Spatrick m_could_not_resolve_hw_bp = false;
84061da546Spatrick }
85061da546Spatrick
GetDescription(Stream * s,lldb::DescriptionLevel level)86061da546Spatrick void ThreadPlanRunToAddress::GetDescription(Stream *s,
87061da546Spatrick lldb::DescriptionLevel level) {
88061da546Spatrick size_t num_addresses = m_addresses.size();
89061da546Spatrick
90061da546Spatrick if (level == lldb::eDescriptionLevelBrief) {
91061da546Spatrick if (num_addresses == 0) {
92061da546Spatrick s->Printf("run to address with no addresses given.");
93061da546Spatrick return;
94061da546Spatrick } else if (num_addresses == 1)
95061da546Spatrick s->Printf("run to address: ");
96061da546Spatrick else
97061da546Spatrick s->Printf("run to addresses: ");
98061da546Spatrick
99061da546Spatrick for (size_t i = 0; i < num_addresses; i++) {
100061da546Spatrick DumpAddress(s->AsRawOstream(), m_addresses[i], sizeof(addr_t));
101061da546Spatrick s->Printf(" ");
102061da546Spatrick }
103061da546Spatrick } else {
104061da546Spatrick if (num_addresses == 0) {
105061da546Spatrick s->Printf("run to address with no addresses given.");
106061da546Spatrick return;
107061da546Spatrick } else if (num_addresses == 1)
108061da546Spatrick s->Printf("Run to address: ");
109061da546Spatrick else {
110061da546Spatrick s->Printf("Run to addresses: ");
111061da546Spatrick }
112061da546Spatrick
113061da546Spatrick for (size_t i = 0; i < num_addresses; i++) {
114061da546Spatrick if (num_addresses > 1) {
115061da546Spatrick s->Printf("\n");
116061da546Spatrick s->Indent();
117061da546Spatrick }
118061da546Spatrick
119061da546Spatrick DumpAddress(s->AsRawOstream(), m_addresses[i], sizeof(addr_t));
120061da546Spatrick s->Printf(" using breakpoint: %d - ", m_break_ids[i]);
121061da546Spatrick Breakpoint *breakpoint =
122dda28197Spatrick GetTarget().GetBreakpointByID(m_break_ids[i]).get();
123061da546Spatrick if (breakpoint)
124061da546Spatrick breakpoint->Dump(s);
125061da546Spatrick else
126061da546Spatrick s->Printf("but the breakpoint has been deleted.");
127061da546Spatrick }
128061da546Spatrick }
129061da546Spatrick }
130061da546Spatrick
ValidatePlan(Stream * error)131061da546Spatrick bool ThreadPlanRunToAddress::ValidatePlan(Stream *error) {
132061da546Spatrick if (m_could_not_resolve_hw_bp) {
133061da546Spatrick if (error)
134061da546Spatrick error->Printf("Could not set hardware breakpoint(s)");
135061da546Spatrick return false;
136061da546Spatrick }
137061da546Spatrick
138061da546Spatrick // If we couldn't set the breakpoint for some reason, then this won't work.
139061da546Spatrick bool all_bps_good = true;
140061da546Spatrick size_t num_break_ids = m_break_ids.size();
141061da546Spatrick for (size_t i = 0; i < num_break_ids; i++) {
142061da546Spatrick if (m_break_ids[i] == LLDB_INVALID_BREAK_ID) {
143061da546Spatrick all_bps_good = false;
144061da546Spatrick if (error) {
145061da546Spatrick error->Printf("Could not set breakpoint for address: ");
146061da546Spatrick DumpAddress(error->AsRawOstream(), m_addresses[i], sizeof(addr_t));
147061da546Spatrick error->Printf("\n");
148061da546Spatrick }
149061da546Spatrick }
150061da546Spatrick }
151061da546Spatrick return all_bps_good;
152061da546Spatrick }
153061da546Spatrick
DoPlanExplainsStop(Event * event_ptr)154061da546Spatrick bool ThreadPlanRunToAddress::DoPlanExplainsStop(Event *event_ptr) {
155061da546Spatrick return AtOurAddress();
156061da546Spatrick }
157061da546Spatrick
ShouldStop(Event * event_ptr)158061da546Spatrick bool ThreadPlanRunToAddress::ShouldStop(Event *event_ptr) {
159061da546Spatrick return AtOurAddress();
160061da546Spatrick }
161061da546Spatrick
StopOthers()162061da546Spatrick bool ThreadPlanRunToAddress::StopOthers() { return m_stop_others; }
163061da546Spatrick
SetStopOthers(bool new_value)164061da546Spatrick void ThreadPlanRunToAddress::SetStopOthers(bool new_value) {
165061da546Spatrick m_stop_others = new_value;
166061da546Spatrick }
167061da546Spatrick
GetPlanRunState()168061da546Spatrick StateType ThreadPlanRunToAddress::GetPlanRunState() { return eStateRunning; }
169061da546Spatrick
WillStop()170061da546Spatrick bool ThreadPlanRunToAddress::WillStop() { return true; }
171061da546Spatrick
MischiefManaged()172061da546Spatrick bool ThreadPlanRunToAddress::MischiefManaged() {
173*f6aab3d8Srobert Log *log = GetLog(LLDBLog::Step);
174061da546Spatrick
175061da546Spatrick if (AtOurAddress()) {
176061da546Spatrick // Remove the breakpoint
177061da546Spatrick size_t num_break_ids = m_break_ids.size();
178061da546Spatrick
179061da546Spatrick for (size_t i = 0; i < num_break_ids; i++) {
180061da546Spatrick if (m_break_ids[i] != LLDB_INVALID_BREAK_ID) {
181dda28197Spatrick GetTarget().RemoveBreakpointByID(m_break_ids[i]);
182061da546Spatrick m_break_ids[i] = LLDB_INVALID_BREAK_ID;
183061da546Spatrick }
184061da546Spatrick }
185061da546Spatrick LLDB_LOGF(log, "Completed run to address plan.");
186061da546Spatrick ThreadPlan::MischiefManaged();
187061da546Spatrick return true;
188061da546Spatrick } else
189061da546Spatrick return false;
190061da546Spatrick }
191061da546Spatrick
AtOurAddress()192061da546Spatrick bool ThreadPlanRunToAddress::AtOurAddress() {
193dda28197Spatrick lldb::addr_t current_address = GetThread().GetRegisterContext()->GetPC();
194061da546Spatrick bool found_it = false;
195061da546Spatrick size_t num_addresses = m_addresses.size();
196061da546Spatrick for (size_t i = 0; i < num_addresses; i++) {
197061da546Spatrick if (m_addresses[i] == current_address) {
198061da546Spatrick found_it = true;
199061da546Spatrick break;
200061da546Spatrick }
201061da546Spatrick }
202061da546Spatrick return found_it;
203061da546Spatrick }
204