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