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/LLDBLog.h"
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 
ThreadPlanRunToAddress(Thread & thread,Address & address,bool stop_others)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(
29       address.GetOpcodeLoadAddress(thread.CalculateTarget().get()));
30   SetInitialBreakpoints();
31 }
32 
ThreadPlanRunToAddress(Thread & thread,lldb::addr_t address,bool stop_others)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(
40       thread.CalculateTarget()->GetOpcodeLoadAddress(address));
41   SetInitialBreakpoints();
42 }
43 
ThreadPlanRunToAddress(Thread & thread,const std::vector<lldb::addr_t> & addresses,bool stop_others)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 
SetInitialBreakpoints()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;
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 
~ThreadPlanRunToAddress()78 ThreadPlanRunToAddress::~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 
GetDescription(Stream * s,lldb::DescriptionLevel level)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 =
122           GetTarget().GetBreakpointByID(m_break_ids[i]).get();
123       if (breakpoint)
124         breakpoint->Dump(s);
125       else
126         s->Printf("but the breakpoint has been deleted.");
127     }
128   }
129 }
130 
ValidatePlan(Stream * error)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 
DoPlanExplainsStop(Event * event_ptr)154 bool ThreadPlanRunToAddress::DoPlanExplainsStop(Event *event_ptr) {
155   return AtOurAddress();
156 }
157 
ShouldStop(Event * event_ptr)158 bool ThreadPlanRunToAddress::ShouldStop(Event *event_ptr) {
159   return AtOurAddress();
160 }
161 
StopOthers()162 bool ThreadPlanRunToAddress::StopOthers() { return m_stop_others; }
163 
SetStopOthers(bool new_value)164 void ThreadPlanRunToAddress::SetStopOthers(bool new_value) {
165   m_stop_others = new_value;
166 }
167 
GetPlanRunState()168 StateType ThreadPlanRunToAddress::GetPlanRunState() { return eStateRunning; }
169 
WillStop()170 bool ThreadPlanRunToAddress::WillStop() { return true; }
171 
MischiefManaged()172 bool ThreadPlanRunToAddress::MischiefManaged() {
173   Log *log = GetLog(LLDBLog::Step);
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) {
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   } else
189     return false;
190 }
191 
AtOurAddress()192 bool 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