10b57cec5SDimitry Andric //===-- ThreadPlanRunToAddress.cpp ------------------------------*- C++ -*-===// 20b57cec5SDimitry Andric // 30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60b57cec5SDimitry Andric // 70b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 80b57cec5SDimitry Andric 90b57cec5SDimitry Andric #include "lldb/Target/ThreadPlanRunToAddress.h" 100b57cec5SDimitry Andric #include "lldb/Target/Process.h" 110b57cec5SDimitry Andric #include "lldb/Target/RegisterContext.h" 120b57cec5SDimitry Andric #include "lldb/Target/Target.h" 130b57cec5SDimitry Andric #include "lldb/Target/Thread.h" 140b57cec5SDimitry Andric #include "lldb/Utility/Log.h" 150b57cec5SDimitry Andric #include "lldb/Utility/Stream.h" 160b57cec5SDimitry Andric 170b57cec5SDimitry Andric using namespace lldb; 180b57cec5SDimitry Andric using namespace lldb_private; 190b57cec5SDimitry Andric 200b57cec5SDimitry Andric // ThreadPlanRunToAddress: Continue plan 210b57cec5SDimitry Andric 220b57cec5SDimitry Andric ThreadPlanRunToAddress::ThreadPlanRunToAddress(Thread &thread, Address &address, 230b57cec5SDimitry Andric bool stop_others) 240b57cec5SDimitry Andric : ThreadPlan(ThreadPlan::eKindRunToAddress, "Run to address plan", thread, 250b57cec5SDimitry Andric eVoteNoOpinion, eVoteNoOpinion), 260b57cec5SDimitry Andric m_stop_others(stop_others), m_addresses(), m_break_ids() { 270b57cec5SDimitry Andric m_addresses.push_back( 280b57cec5SDimitry Andric address.GetOpcodeLoadAddress(m_thread.CalculateTarget().get())); 290b57cec5SDimitry Andric SetInitialBreakpoints(); 300b57cec5SDimitry Andric } 310b57cec5SDimitry Andric 320b57cec5SDimitry Andric ThreadPlanRunToAddress::ThreadPlanRunToAddress(Thread &thread, 330b57cec5SDimitry Andric lldb::addr_t address, 340b57cec5SDimitry Andric bool stop_others) 350b57cec5SDimitry Andric : ThreadPlan(ThreadPlan::eKindRunToAddress, "Run to address plan", thread, 360b57cec5SDimitry Andric eVoteNoOpinion, eVoteNoOpinion), 370b57cec5SDimitry Andric m_stop_others(stop_others), m_addresses(), m_break_ids() { 380b57cec5SDimitry Andric m_addresses.push_back( 390b57cec5SDimitry Andric m_thread.CalculateTarget()->GetOpcodeLoadAddress(address)); 400b57cec5SDimitry Andric SetInitialBreakpoints(); 410b57cec5SDimitry Andric } 420b57cec5SDimitry Andric 430b57cec5SDimitry Andric ThreadPlanRunToAddress::ThreadPlanRunToAddress( 440b57cec5SDimitry Andric Thread &thread, const std::vector<lldb::addr_t> &addresses, 450b57cec5SDimitry Andric bool stop_others) 460b57cec5SDimitry Andric : ThreadPlan(ThreadPlan::eKindRunToAddress, "Run to address plan", thread, 470b57cec5SDimitry Andric eVoteNoOpinion, eVoteNoOpinion), 480b57cec5SDimitry Andric m_stop_others(stop_others), m_addresses(addresses), m_break_ids() { 490b57cec5SDimitry Andric // Convert all addresses into opcode addresses to make sure we set 500b57cec5SDimitry Andric // breakpoints at the correct address. 510b57cec5SDimitry Andric Target &target = thread.GetProcess()->GetTarget(); 520b57cec5SDimitry Andric std::vector<lldb::addr_t>::iterator pos, end = m_addresses.end(); 530b57cec5SDimitry Andric for (pos = m_addresses.begin(); pos != end; ++pos) 540b57cec5SDimitry Andric *pos = target.GetOpcodeLoadAddress(*pos); 550b57cec5SDimitry Andric 560b57cec5SDimitry Andric SetInitialBreakpoints(); 570b57cec5SDimitry Andric } 580b57cec5SDimitry Andric 590b57cec5SDimitry Andric void ThreadPlanRunToAddress::SetInitialBreakpoints() { 600b57cec5SDimitry Andric size_t num_addresses = m_addresses.size(); 610b57cec5SDimitry Andric m_break_ids.resize(num_addresses); 620b57cec5SDimitry Andric 630b57cec5SDimitry Andric for (size_t i = 0; i < num_addresses; i++) { 640b57cec5SDimitry Andric Breakpoint *breakpoint; 650b57cec5SDimitry Andric breakpoint = m_thread.CalculateTarget() 660b57cec5SDimitry Andric ->CreateBreakpoint(m_addresses[i], true, false) 670b57cec5SDimitry Andric .get(); 680b57cec5SDimitry Andric if (breakpoint != nullptr) { 690b57cec5SDimitry Andric if (breakpoint->IsHardware() && !breakpoint->HasResolvedLocations()) 700b57cec5SDimitry Andric m_could_not_resolve_hw_bp = true; 710b57cec5SDimitry Andric m_break_ids[i] = breakpoint->GetID(); 720b57cec5SDimitry Andric breakpoint->SetThreadID(m_thread.GetID()); 730b57cec5SDimitry Andric breakpoint->SetBreakpointKind("run-to-address"); 740b57cec5SDimitry Andric } 750b57cec5SDimitry Andric } 760b57cec5SDimitry Andric } 770b57cec5SDimitry Andric 780b57cec5SDimitry Andric ThreadPlanRunToAddress::~ThreadPlanRunToAddress() { 790b57cec5SDimitry Andric size_t num_break_ids = m_break_ids.size(); 800b57cec5SDimitry Andric for (size_t i = 0; i < num_break_ids; i++) { 810b57cec5SDimitry Andric m_thread.CalculateTarget()->RemoveBreakpointByID(m_break_ids[i]); 820b57cec5SDimitry Andric } 830b57cec5SDimitry Andric m_could_not_resolve_hw_bp = false; 840b57cec5SDimitry Andric } 850b57cec5SDimitry Andric 860b57cec5SDimitry Andric void ThreadPlanRunToAddress::GetDescription(Stream *s, 870b57cec5SDimitry Andric lldb::DescriptionLevel level) { 880b57cec5SDimitry Andric size_t num_addresses = m_addresses.size(); 890b57cec5SDimitry Andric 900b57cec5SDimitry Andric if (level == lldb::eDescriptionLevelBrief) { 910b57cec5SDimitry Andric if (num_addresses == 0) { 920b57cec5SDimitry Andric s->Printf("run to address with no addresses given."); 930b57cec5SDimitry Andric return; 940b57cec5SDimitry Andric } else if (num_addresses == 1) 950b57cec5SDimitry Andric s->Printf("run to address: "); 960b57cec5SDimitry Andric else 970b57cec5SDimitry Andric s->Printf("run to addresses: "); 980b57cec5SDimitry Andric 990b57cec5SDimitry Andric for (size_t i = 0; i < num_addresses; i++) { 1000b57cec5SDimitry Andric s->Address(m_addresses[i], sizeof(addr_t)); 1010b57cec5SDimitry Andric s->Printf(" "); 1020b57cec5SDimitry Andric } 1030b57cec5SDimitry Andric } else { 1040b57cec5SDimitry Andric if (num_addresses == 0) { 1050b57cec5SDimitry Andric s->Printf("run to address with no addresses given."); 1060b57cec5SDimitry Andric return; 1070b57cec5SDimitry Andric } else if (num_addresses == 1) 1080b57cec5SDimitry Andric s->Printf("Run to address: "); 1090b57cec5SDimitry Andric else { 1100b57cec5SDimitry Andric s->Printf("Run to addresses: "); 1110b57cec5SDimitry Andric } 1120b57cec5SDimitry Andric 1130b57cec5SDimitry Andric for (size_t i = 0; i < num_addresses; i++) { 1140b57cec5SDimitry Andric if (num_addresses > 1) { 1150b57cec5SDimitry Andric s->Printf("\n"); 1160b57cec5SDimitry Andric s->Indent(); 1170b57cec5SDimitry Andric } 1180b57cec5SDimitry Andric 1190b57cec5SDimitry Andric s->Address(m_addresses[i], sizeof(addr_t)); 1200b57cec5SDimitry Andric s->Printf(" using breakpoint: %d - ", m_break_ids[i]); 1210b57cec5SDimitry Andric Breakpoint *breakpoint = 1220b57cec5SDimitry Andric m_thread.CalculateTarget()->GetBreakpointByID(m_break_ids[i]).get(); 1230b57cec5SDimitry Andric if (breakpoint) 1240b57cec5SDimitry Andric breakpoint->Dump(s); 1250b57cec5SDimitry Andric else 1260b57cec5SDimitry Andric s->Printf("but the breakpoint has been deleted."); 1270b57cec5SDimitry Andric } 1280b57cec5SDimitry Andric } 1290b57cec5SDimitry Andric } 1300b57cec5SDimitry Andric 1310b57cec5SDimitry Andric bool ThreadPlanRunToAddress::ValidatePlan(Stream *error) { 1320b57cec5SDimitry Andric if (m_could_not_resolve_hw_bp) { 1330b57cec5SDimitry Andric if (error) 1340b57cec5SDimitry Andric error->Printf("Could not set hardware breakpoint(s)"); 1350b57cec5SDimitry Andric return false; 1360b57cec5SDimitry Andric } 1370b57cec5SDimitry Andric 1380b57cec5SDimitry Andric // If we couldn't set the breakpoint for some reason, then this won't work. 1390b57cec5SDimitry Andric bool all_bps_good = true; 1400b57cec5SDimitry Andric size_t num_break_ids = m_break_ids.size(); 1410b57cec5SDimitry Andric for (size_t i = 0; i < num_break_ids; i++) { 1420b57cec5SDimitry Andric if (m_break_ids[i] == LLDB_INVALID_BREAK_ID) { 1430b57cec5SDimitry Andric all_bps_good = false; 1440b57cec5SDimitry Andric if (error) { 1450b57cec5SDimitry Andric error->Printf("Could not set breakpoint for address: "); 1460b57cec5SDimitry Andric error->Address(m_addresses[i], sizeof(addr_t)); 1470b57cec5SDimitry Andric error->Printf("\n"); 1480b57cec5SDimitry Andric } 1490b57cec5SDimitry Andric } 1500b57cec5SDimitry Andric } 1510b57cec5SDimitry Andric return all_bps_good; 1520b57cec5SDimitry Andric } 1530b57cec5SDimitry Andric 1540b57cec5SDimitry Andric bool ThreadPlanRunToAddress::DoPlanExplainsStop(Event *event_ptr) { 1550b57cec5SDimitry Andric return AtOurAddress(); 1560b57cec5SDimitry Andric } 1570b57cec5SDimitry Andric 1580b57cec5SDimitry Andric bool ThreadPlanRunToAddress::ShouldStop(Event *event_ptr) { 1590b57cec5SDimitry Andric return AtOurAddress(); 1600b57cec5SDimitry Andric } 1610b57cec5SDimitry Andric 1620b57cec5SDimitry Andric bool ThreadPlanRunToAddress::StopOthers() { return m_stop_others; } 1630b57cec5SDimitry Andric 1640b57cec5SDimitry Andric void ThreadPlanRunToAddress::SetStopOthers(bool new_value) { 1650b57cec5SDimitry Andric m_stop_others = new_value; 1660b57cec5SDimitry Andric } 1670b57cec5SDimitry Andric 1680b57cec5SDimitry Andric StateType ThreadPlanRunToAddress::GetPlanRunState() { return eStateRunning; } 1690b57cec5SDimitry Andric 1700b57cec5SDimitry Andric bool ThreadPlanRunToAddress::WillStop() { return true; } 1710b57cec5SDimitry Andric 1720b57cec5SDimitry Andric bool ThreadPlanRunToAddress::MischiefManaged() { 1730b57cec5SDimitry Andric Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP)); 1740b57cec5SDimitry Andric 1750b57cec5SDimitry Andric if (AtOurAddress()) { 1760b57cec5SDimitry Andric // Remove the breakpoint 1770b57cec5SDimitry Andric size_t num_break_ids = m_break_ids.size(); 1780b57cec5SDimitry Andric 1790b57cec5SDimitry Andric for (size_t i = 0; i < num_break_ids; i++) { 1800b57cec5SDimitry Andric if (m_break_ids[i] != LLDB_INVALID_BREAK_ID) { 1810b57cec5SDimitry Andric m_thread.CalculateTarget()->RemoveBreakpointByID(m_break_ids[i]); 1820b57cec5SDimitry Andric m_break_ids[i] = LLDB_INVALID_BREAK_ID; 1830b57cec5SDimitry Andric } 1840b57cec5SDimitry Andric } 1859dba64beSDimitry Andric LLDB_LOGF(log, "Completed run to address plan."); 1860b57cec5SDimitry Andric ThreadPlan::MischiefManaged(); 1870b57cec5SDimitry Andric return true; 1880b57cec5SDimitry Andric } else 1890b57cec5SDimitry Andric return false; 1900b57cec5SDimitry Andric } 1910b57cec5SDimitry Andric 1920b57cec5SDimitry Andric bool ThreadPlanRunToAddress::AtOurAddress() { 1930b57cec5SDimitry Andric lldb::addr_t current_address = m_thread.GetRegisterContext()->GetPC(); 1940b57cec5SDimitry Andric bool found_it = false; 1950b57cec5SDimitry Andric size_t num_addresses = m_addresses.size(); 1960b57cec5SDimitry Andric for (size_t i = 0; i < num_addresses; i++) { 1970b57cec5SDimitry Andric if (m_addresses[i] == current_address) { 1980b57cec5SDimitry Andric found_it = true; 1990b57cec5SDimitry Andric break; 2000b57cec5SDimitry Andric } 2010b57cec5SDimitry Andric } 2020b57cec5SDimitry Andric return found_it; 2030b57cec5SDimitry Andric } 204