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