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