150
|
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-exception
|
|
6 //
|
|
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"
|
236
|
14 #include "lldb/Utility/LLDBLog.h"
|
150
|
15 #include "lldb/Utility/Log.h"
|
|
16 #include "lldb/Utility/Stream.h"
|
|
17
|
|
18 using namespace lldb;
|
|
19 using namespace lldb_private;
|
|
20
|
|
21 // ThreadPlanRunToAddress: Continue plan
|
|
22
|
|
23 ThreadPlanRunToAddress::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(
|
173
|
29 address.GetOpcodeLoadAddress(thread.CalculateTarget().get()));
|
150
|
30 SetInitialBreakpoints();
|
|
31 }
|
|
32
|
|
33 ThreadPlanRunToAddress::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(
|
173
|
40 thread.CalculateTarget()->GetOpcodeLoadAddress(address));
|
150
|
41 SetInitialBreakpoints();
|
|
42 }
|
|
43
|
|
44 ThreadPlanRunToAddress::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 set
|
|
51 // 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
|
|
60 void 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;
|
173
|
66 breakpoint =
|
|
67 GetTarget().CreateBreakpoint(m_addresses[i], true, false).get();
|
150
|
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();
|
173
|
72 breakpoint->SetThreadID(m_tid);
|
150
|
73 breakpoint->SetBreakpointKind("run-to-address");
|
|
74 }
|
|
75 }
|
|
76 }
|
|
77
|
|
78 ThreadPlanRunToAddress::~ThreadPlanRunToAddress() {
|
|
79 size_t num_break_ids = m_break_ids.size();
|
|
80 for (size_t i = 0; i < num_break_ids; i++) {
|
173
|
81 GetTarget().RemoveBreakpointByID(m_break_ids[i]);
|
150
|
82 }
|
|
83 m_could_not_resolve_hw_bp = false;
|
|
84 }
|
|
85
|
|
86 void 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 else
|
|
97 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 =
|
173
|
122 GetTarget().GetBreakpointByID(m_break_ids[i]).get();
|
150
|
123 if (breakpoint)
|
|
124 breakpoint->Dump(s);
|
|
125 else
|
|
126 s->Printf("but the breakpoint has been deleted.");
|
|
127 }
|
|
128 }
|
|
129 }
|
|
130
|
|
131 bool 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
|
|
154 bool ThreadPlanRunToAddress::DoPlanExplainsStop(Event *event_ptr) {
|
|
155 return AtOurAddress();
|
|
156 }
|
|
157
|
|
158 bool ThreadPlanRunToAddress::ShouldStop(Event *event_ptr) {
|
|
159 return AtOurAddress();
|
|
160 }
|
|
161
|
|
162 bool ThreadPlanRunToAddress::StopOthers() { return m_stop_others; }
|
|
163
|
|
164 void ThreadPlanRunToAddress::SetStopOthers(bool new_value) {
|
|
165 m_stop_others = new_value;
|
|
166 }
|
|
167
|
|
168 StateType ThreadPlanRunToAddress::GetPlanRunState() { return eStateRunning; }
|
|
169
|
|
170 bool ThreadPlanRunToAddress::WillStop() { return true; }
|
|
171
|
|
172 bool ThreadPlanRunToAddress::MischiefManaged() {
|
236
|
173 Log *log = GetLog(LLDBLog::Step);
|
150
|
174
|
|
175 if (AtOurAddress()) {
|
|
176 // Remove the breakpoint
|
|
177 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) {
|
173
|
181 GetTarget().RemoveBreakpointByID(m_break_ids[i]);
|
150
|
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 } else
|
|
189 return false;
|
|
190 }
|
|
191
|
|
192 bool ThreadPlanRunToAddress::AtOurAddress() {
|
173
|
193 lldb::addr_t current_address = GetThread().GetRegisterContext()->GetPC();
|
150
|
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 }
|