180814287SRaphael Isemann //===-- ThreadPlanRunToAddress.cpp ----------------------------------------===//
230fdc8d8SChris Lattner //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
630fdc8d8SChris Lattner //
730fdc8d8SChris Lattner //===----------------------------------------------------------------------===//
830fdc8d8SChris Lattner 
9e65b2cf2SEugene Zelenko #include "lldb/Target/ThreadPlanRunToAddress.h"
1030fdc8d8SChris Lattner #include "lldb/Target/Process.h"
1130fdc8d8SChris Lattner #include "lldb/Target/RegisterContext.h"
12b9c1b51eSKate Stone #include "lldb/Target/Target.h"
13b9c1b51eSKate Stone #include "lldb/Target/Thread.h"
146f9e6901SZachary Turner #include "lldb/Utility/Log.h"
15bf9a7730SZachary Turner #include "lldb/Utility/Stream.h"
1630fdc8d8SChris Lattner 
1730fdc8d8SChris Lattner using namespace lldb;
1830fdc8d8SChris Lattner using namespace lldb_private;
1930fdc8d8SChris Lattner 
2030fdc8d8SChris Lattner // ThreadPlanRunToAddress: Continue plan
2130fdc8d8SChris Lattner 
22b9c1b51eSKate Stone ThreadPlanRunToAddress::ThreadPlanRunToAddress(Thread &thread, Address &address,
23b9c1b51eSKate Stone                                                bool stop_others)
24b9c1b51eSKate Stone     : ThreadPlan(ThreadPlan::eKindRunToAddress, "Run to address plan", thread,
25b9c1b51eSKate Stone                  eVoteNoOpinion, eVoteNoOpinion),
26b9c1b51eSKate Stone       m_stop_others(stop_others), m_addresses(), m_break_ids() {
27b9c1b51eSKate Stone   m_addresses.push_back(
28*e4598dc0SJim Ingham       address.GetOpcodeLoadAddress(thread.CalculateTarget().get()));
2908b87e0dSJim Ingham   SetInitialBreakpoints();
3030fdc8d8SChris Lattner }
3130fdc8d8SChris Lattner 
32b9c1b51eSKate Stone ThreadPlanRunToAddress::ThreadPlanRunToAddress(Thread &thread,
3330fdc8d8SChris Lattner                                                lldb::addr_t address,
34b9c1b51eSKate Stone                                                bool stop_others)
35b9c1b51eSKate Stone     : ThreadPlan(ThreadPlan::eKindRunToAddress, "Run to address plan", thread,
36b9c1b51eSKate Stone                  eVoteNoOpinion, eVoteNoOpinion),
37b9c1b51eSKate Stone       m_stop_others(stop_others), m_addresses(), m_break_ids() {
38b9c1b51eSKate Stone   m_addresses.push_back(
39*e4598dc0SJim Ingham       thread.CalculateTarget()->GetOpcodeLoadAddress(address));
4008b87e0dSJim Ingham   SetInitialBreakpoints();
4108b87e0dSJim Ingham }
4208b87e0dSJim Ingham 
43b9c1b51eSKate Stone ThreadPlanRunToAddress::ThreadPlanRunToAddress(
44b9c1b51eSKate Stone     Thread &thread, const std::vector<lldb::addr_t> &addresses,
45b9c1b51eSKate Stone     bool stop_others)
46b9c1b51eSKate Stone     : ThreadPlan(ThreadPlan::eKindRunToAddress, "Run to address plan", thread,
47b9c1b51eSKate Stone                  eVoteNoOpinion, eVoteNoOpinion),
48b9c1b51eSKate Stone       m_stop_others(stop_others), m_addresses(addresses), m_break_ids() {
49d93c4a33SBruce Mitchener   // Convert all addresses into opcode addresses to make sure we set
50f3ef3d2aSGreg Clayton   // breakpoints at the correct address.
511ac04c30SGreg Clayton   Target &target = thread.GetProcess()->GetTarget();
52f3ef3d2aSGreg Clayton   std::vector<lldb::addr_t>::iterator pos, end = m_addresses.end();
53f3ef3d2aSGreg Clayton   for (pos = m_addresses.begin(); pos != end; ++pos)
54f3ef3d2aSGreg Clayton     *pos = target.GetOpcodeLoadAddress(*pos);
55f3ef3d2aSGreg Clayton 
5608b87e0dSJim Ingham   SetInitialBreakpoints();
5730fdc8d8SChris Lattner }
5830fdc8d8SChris Lattner 
59b9c1b51eSKate Stone void ThreadPlanRunToAddress::SetInitialBreakpoints() {
6008b87e0dSJim Ingham   size_t num_addresses = m_addresses.size();
6108b87e0dSJim Ingham   m_break_ids.resize(num_addresses);
6208b87e0dSJim Ingham 
63b9c1b51eSKate Stone   for (size_t i = 0; i < num_addresses; i++) {
6430fdc8d8SChris Lattner     Breakpoint *breakpoint;
65*e4598dc0SJim Ingham     breakpoint =
66*e4598dc0SJim Ingham         GetTarget().CreateBreakpoint(m_addresses[i], true, false).get();
67b9c1b51eSKate Stone     if (breakpoint != nullptr) {
68e103ae92SJonas Devlieghere       if (breakpoint->IsHardware() && !breakpoint->HasResolvedLocations())
69e103ae92SJonas Devlieghere         m_could_not_resolve_hw_bp = true;
7008b87e0dSJim Ingham       m_break_ids[i] = breakpoint->GetID();
71*e4598dc0SJim Ingham       breakpoint->SetThreadID(m_tid);
722995077dSJim Ingham       breakpoint->SetBreakpointKind("run-to-address");
7330fdc8d8SChris Lattner     }
7430fdc8d8SChris Lattner   }
7508b87e0dSJim Ingham }
7630fdc8d8SChris Lattner 
77b9c1b51eSKate Stone ThreadPlanRunToAddress::~ThreadPlanRunToAddress() {
7808b87e0dSJim Ingham   size_t num_break_ids = m_break_ids.size();
79b9c1b51eSKate Stone   for (size_t i = 0; i < num_break_ids; i++) {
80*e4598dc0SJim Ingham     GetTarget().RemoveBreakpointByID(m_break_ids[i]);
8130fdc8d8SChris Lattner   }
82e103ae92SJonas Devlieghere   m_could_not_resolve_hw_bp = false;
8330fdc8d8SChris Lattner }
8430fdc8d8SChris Lattner 
85b9c1b51eSKate Stone void ThreadPlanRunToAddress::GetDescription(Stream *s,
86b9c1b51eSKate Stone                                             lldb::DescriptionLevel level) {
8708b87e0dSJim Ingham   size_t num_addresses = m_addresses.size();
8808b87e0dSJim Ingham 
89b9c1b51eSKate Stone   if (level == lldb::eDescriptionLevelBrief) {
90b9c1b51eSKate Stone     if (num_addresses == 0) {
9108b87e0dSJim Ingham       s->Printf("run to address with no addresses given.");
9208b87e0dSJim Ingham       return;
93b9c1b51eSKate Stone     } else if (num_addresses == 1)
9430fdc8d8SChris Lattner       s->Printf("run to address: ");
9508b87e0dSJim Ingham     else
9608b87e0dSJim Ingham       s->Printf("run to addresses: ");
9708b87e0dSJim Ingham 
98b9c1b51eSKate Stone     for (size_t i = 0; i < num_addresses; i++) {
991462f5a4SRaphael Isemann       DumpAddress(s->AsRawOstream(), m_addresses[i], sizeof(addr_t));
10008b87e0dSJim Ingham       s->Printf(" ");
10108b87e0dSJim Ingham     }
102b9c1b51eSKate Stone   } else {
103b9c1b51eSKate Stone     if (num_addresses == 0) {
10408b87e0dSJim Ingham       s->Printf("run to address with no addresses given.");
10508b87e0dSJim Ingham       return;
106b9c1b51eSKate Stone     } else if (num_addresses == 1)
10730fdc8d8SChris Lattner       s->Printf("Run to address: ");
108b9c1b51eSKate Stone     else {
10908b87e0dSJim Ingham       s->Printf("Run to addresses: ");
11008b87e0dSJim Ingham     }
11108b87e0dSJim Ingham 
112b9c1b51eSKate Stone     for (size_t i = 0; i < num_addresses; i++) {
113b9c1b51eSKate Stone       if (num_addresses > 1) {
11408b87e0dSJim Ingham         s->Printf("\n");
11508b87e0dSJim Ingham         s->Indent();
11608b87e0dSJim Ingham       }
11708b87e0dSJim Ingham 
1181462f5a4SRaphael Isemann       DumpAddress(s->AsRawOstream(), m_addresses[i], sizeof(addr_t));
119f58a0487SJim Ingham       s->Printf(" using breakpoint: %d - ", m_break_ids[i]);
120b9c1b51eSKate Stone       Breakpoint *breakpoint =
121*e4598dc0SJim Ingham           GetTarget().GetBreakpointByID(m_break_ids[i]).get();
12230fdc8d8SChris Lattner       if (breakpoint)
12330fdc8d8SChris Lattner         breakpoint->Dump(s);
12430fdc8d8SChris Lattner       else
12530fdc8d8SChris Lattner         s->Printf("but the breakpoint has been deleted.");
12630fdc8d8SChris Lattner     }
12730fdc8d8SChris Lattner   }
12808b87e0dSJim Ingham }
12930fdc8d8SChris Lattner 
130b9c1b51eSKate Stone bool ThreadPlanRunToAddress::ValidatePlan(Stream *error) {
131e103ae92SJonas Devlieghere   if (m_could_not_resolve_hw_bp) {
132e103ae92SJonas Devlieghere     if (error)
133e103ae92SJonas Devlieghere       error->Printf("Could not set hardware breakpoint(s)");
134e103ae92SJonas Devlieghere     return false;
135e103ae92SJonas Devlieghere   }
136e103ae92SJonas Devlieghere 
13705097246SAdrian Prantl   // If we couldn't set the breakpoint for some reason, then this won't work.
13808b87e0dSJim Ingham   bool all_bps_good = true;
13908b87e0dSJim Ingham   size_t num_break_ids = m_break_ids.size();
140b9c1b51eSKate Stone   for (size_t i = 0; i < num_break_ids; i++) {
141b9c1b51eSKate Stone     if (m_break_ids[i] == LLDB_INVALID_BREAK_ID) {
14208b87e0dSJim Ingham       all_bps_good = false;
143b9c1b51eSKate Stone       if (error) {
14408b87e0dSJim Ingham         error->Printf("Could not set breakpoint for address: ");
1451462f5a4SRaphael Isemann         DumpAddress(error->AsRawOstream(), m_addresses[i], sizeof(addr_t));
14608b87e0dSJim Ingham         error->Printf("\n");
14708b87e0dSJim Ingham       }
14808b87e0dSJim Ingham     }
149f48169bbSJim Ingham   }
15008b87e0dSJim Ingham   return all_bps_good;
15130fdc8d8SChris Lattner }
15230fdc8d8SChris Lattner 
153b9c1b51eSKate Stone bool ThreadPlanRunToAddress::DoPlanExplainsStop(Event *event_ptr) {
15430fdc8d8SChris Lattner   return AtOurAddress();
15530fdc8d8SChris Lattner }
15630fdc8d8SChris Lattner 
157b9c1b51eSKate Stone bool ThreadPlanRunToAddress::ShouldStop(Event *event_ptr) {
1581fd2f08eSJim Ingham   return AtOurAddress();
15930fdc8d8SChris Lattner }
16030fdc8d8SChris Lattner 
161b9c1b51eSKate Stone bool ThreadPlanRunToAddress::StopOthers() { return m_stop_others; }
16230fdc8d8SChris Lattner 
163b9c1b51eSKate Stone void ThreadPlanRunToAddress::SetStopOthers(bool new_value) {
16430fdc8d8SChris Lattner   m_stop_others = new_value;
16530fdc8d8SChris Lattner }
16630fdc8d8SChris Lattner 
167b9c1b51eSKate Stone StateType ThreadPlanRunToAddress::GetPlanRunState() { return eStateRunning; }
16830fdc8d8SChris Lattner 
169b9c1b51eSKate Stone bool ThreadPlanRunToAddress::WillStop() { return true; }
17030fdc8d8SChris Lattner 
171b9c1b51eSKate Stone bool ThreadPlanRunToAddress::MischiefManaged() {
1725160ce5cSGreg Clayton   Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP));
17330fdc8d8SChris Lattner 
174b9c1b51eSKate Stone   if (AtOurAddress()) {
17530fdc8d8SChris Lattner     // Remove the breakpoint
17608b87e0dSJim Ingham     size_t num_break_ids = m_break_ids.size();
17730fdc8d8SChris Lattner 
178b9c1b51eSKate Stone     for (size_t i = 0; i < num_break_ids; i++) {
179b9c1b51eSKate Stone       if (m_break_ids[i] != LLDB_INVALID_BREAK_ID) {
180*e4598dc0SJim Ingham         GetTarget().RemoveBreakpointByID(m_break_ids[i]);
18108b87e0dSJim Ingham         m_break_ids[i] = LLDB_INVALID_BREAK_ID;
18208b87e0dSJim Ingham       }
18308b87e0dSJim Ingham     }
18463e5fb76SJonas Devlieghere     LLDB_LOGF(log, "Completed run to address plan.");
18530fdc8d8SChris Lattner     ThreadPlan::MischiefManaged();
18630fdc8d8SChris Lattner     return true;
187b9c1b51eSKate Stone   } else
18830fdc8d8SChris Lattner     return false;
18930fdc8d8SChris Lattner }
19030fdc8d8SChris Lattner 
191b9c1b51eSKate Stone bool ThreadPlanRunToAddress::AtOurAddress() {
192*e4598dc0SJim Ingham   lldb::addr_t current_address = GetThread().GetRegisterContext()->GetPC();
19308b87e0dSJim Ingham   bool found_it = false;
1944bf570d6SJim Ingham   size_t num_addresses = m_addresses.size();
195b9c1b51eSKate Stone   for (size_t i = 0; i < num_addresses; i++) {
196b9c1b51eSKate Stone     if (m_addresses[i] == current_address) {
19708b87e0dSJim Ingham       found_it = true;
19808b87e0dSJim Ingham       break;
19908b87e0dSJim Ingham     }
20008b87e0dSJim Ingham   }
20108b87e0dSJim Ingham   return found_it;
20230fdc8d8SChris Lattner }
203