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