15ffd83dbSDimitry Andric //===-- ThreadPlanRunToAddress.cpp ----------------------------------------===//
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"
1481ad6265SDimitry Andric #include "lldb/Utility/LLDBLog.h"
150b57cec5SDimitry Andric #include "lldb/Utility/Log.h"
160b57cec5SDimitry Andric #include "lldb/Utility/Stream.h"
170b57cec5SDimitry Andric 
180b57cec5SDimitry Andric using namespace lldb;
190b57cec5SDimitry Andric using namespace lldb_private;
200b57cec5SDimitry Andric 
210b57cec5SDimitry Andric // ThreadPlanRunToAddress: Continue plan
220b57cec5SDimitry Andric 
ThreadPlanRunToAddress(Thread & thread,Address & address,bool stop_others)230b57cec5SDimitry Andric ThreadPlanRunToAddress::ThreadPlanRunToAddress(Thread &thread, Address &address,
240b57cec5SDimitry Andric                                                bool stop_others)
250b57cec5SDimitry Andric     : ThreadPlan(ThreadPlan::eKindRunToAddress, "Run to address plan", thread,
260b57cec5SDimitry Andric                  eVoteNoOpinion, eVoteNoOpinion),
270b57cec5SDimitry Andric       m_stop_others(stop_others), m_addresses(), m_break_ids() {
280b57cec5SDimitry Andric   m_addresses.push_back(
295ffd83dbSDimitry Andric       address.GetOpcodeLoadAddress(thread.CalculateTarget().get()));
300b57cec5SDimitry Andric   SetInitialBreakpoints();
310b57cec5SDimitry Andric }
320b57cec5SDimitry Andric 
ThreadPlanRunToAddress(Thread & thread,lldb::addr_t address,bool stop_others)330b57cec5SDimitry Andric ThreadPlanRunToAddress::ThreadPlanRunToAddress(Thread &thread,
340b57cec5SDimitry Andric                                                lldb::addr_t address,
350b57cec5SDimitry Andric                                                bool stop_others)
360b57cec5SDimitry Andric     : ThreadPlan(ThreadPlan::eKindRunToAddress, "Run to address plan", thread,
370b57cec5SDimitry Andric                  eVoteNoOpinion, eVoteNoOpinion),
380b57cec5SDimitry Andric       m_stop_others(stop_others), m_addresses(), m_break_ids() {
390b57cec5SDimitry Andric   m_addresses.push_back(
405ffd83dbSDimitry Andric       thread.CalculateTarget()->GetOpcodeLoadAddress(address));
410b57cec5SDimitry Andric   SetInitialBreakpoints();
420b57cec5SDimitry Andric }
430b57cec5SDimitry Andric 
ThreadPlanRunToAddress(Thread & thread,const std::vector<lldb::addr_t> & addresses,bool stop_others)440b57cec5SDimitry Andric ThreadPlanRunToAddress::ThreadPlanRunToAddress(
450b57cec5SDimitry Andric     Thread &thread, const std::vector<lldb::addr_t> &addresses,
460b57cec5SDimitry Andric     bool stop_others)
470b57cec5SDimitry Andric     : ThreadPlan(ThreadPlan::eKindRunToAddress, "Run to address plan", thread,
480b57cec5SDimitry Andric                  eVoteNoOpinion, eVoteNoOpinion),
490b57cec5SDimitry Andric       m_stop_others(stop_others), m_addresses(addresses), m_break_ids() {
500b57cec5SDimitry Andric   // Convert all addresses into opcode addresses to make sure we set
510b57cec5SDimitry Andric   // breakpoints at the correct address.
520b57cec5SDimitry Andric   Target &target = thread.GetProcess()->GetTarget();
530b57cec5SDimitry Andric   std::vector<lldb::addr_t>::iterator pos, end = m_addresses.end();
540b57cec5SDimitry Andric   for (pos = m_addresses.begin(); pos != end; ++pos)
550b57cec5SDimitry Andric     *pos = target.GetOpcodeLoadAddress(*pos);
560b57cec5SDimitry Andric 
570b57cec5SDimitry Andric   SetInitialBreakpoints();
580b57cec5SDimitry Andric }
590b57cec5SDimitry Andric 
SetInitialBreakpoints()600b57cec5SDimitry Andric void ThreadPlanRunToAddress::SetInitialBreakpoints() {
610b57cec5SDimitry Andric   size_t num_addresses = m_addresses.size();
620b57cec5SDimitry Andric   m_break_ids.resize(num_addresses);
630b57cec5SDimitry Andric 
640b57cec5SDimitry Andric   for (size_t i = 0; i < num_addresses; i++) {
650b57cec5SDimitry Andric     Breakpoint *breakpoint;
665ffd83dbSDimitry Andric     breakpoint =
675ffd83dbSDimitry Andric         GetTarget().CreateBreakpoint(m_addresses[i], true, false).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();
725ffd83dbSDimitry Andric       breakpoint->SetThreadID(m_tid);
730b57cec5SDimitry Andric       breakpoint->SetBreakpointKind("run-to-address");
740b57cec5SDimitry Andric     }
750b57cec5SDimitry Andric   }
760b57cec5SDimitry Andric }
770b57cec5SDimitry Andric 
~ThreadPlanRunToAddress()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++) {
815ffd83dbSDimitry Andric     GetTarget().RemoveBreakpointByID(m_break_ids[i]);
820b57cec5SDimitry Andric   }
830b57cec5SDimitry Andric   m_could_not_resolve_hw_bp = false;
840b57cec5SDimitry Andric }
850b57cec5SDimitry Andric 
GetDescription(Stream * s,lldb::DescriptionLevel level)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++) {
100480093f4SDimitry Andric       DumpAddress(s->AsRawOstream(), 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 
119480093f4SDimitry Andric       DumpAddress(s->AsRawOstream(), m_addresses[i], sizeof(addr_t));
1200b57cec5SDimitry Andric       s->Printf(" using breakpoint: %d - ", m_break_ids[i]);
1210b57cec5SDimitry Andric       Breakpoint *breakpoint =
1225ffd83dbSDimitry Andric           GetTarget().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 
ValidatePlan(Stream * error)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: ");
146480093f4SDimitry Andric         DumpAddress(error->AsRawOstream(), 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 
DoPlanExplainsStop(Event * event_ptr)1540b57cec5SDimitry Andric bool ThreadPlanRunToAddress::DoPlanExplainsStop(Event *event_ptr) {
1550b57cec5SDimitry Andric   return AtOurAddress();
1560b57cec5SDimitry Andric }
1570b57cec5SDimitry Andric 
ShouldStop(Event * event_ptr)1580b57cec5SDimitry Andric bool ThreadPlanRunToAddress::ShouldStop(Event *event_ptr) {
1590b57cec5SDimitry Andric   return AtOurAddress();
1600b57cec5SDimitry Andric }
1610b57cec5SDimitry Andric 
StopOthers()1620b57cec5SDimitry Andric bool ThreadPlanRunToAddress::StopOthers() { return m_stop_others; }
1630b57cec5SDimitry Andric 
SetStopOthers(bool new_value)1640b57cec5SDimitry Andric void ThreadPlanRunToAddress::SetStopOthers(bool new_value) {
1650b57cec5SDimitry Andric   m_stop_others = new_value;
1660b57cec5SDimitry Andric }
1670b57cec5SDimitry Andric 
GetPlanRunState()1680b57cec5SDimitry Andric StateType ThreadPlanRunToAddress::GetPlanRunState() { return eStateRunning; }
1690b57cec5SDimitry Andric 
WillStop()1700b57cec5SDimitry Andric bool ThreadPlanRunToAddress::WillStop() { return true; }
1710b57cec5SDimitry Andric 
MischiefManaged()1720b57cec5SDimitry Andric bool ThreadPlanRunToAddress::MischiefManaged() {
17381ad6265SDimitry Andric   Log *log = GetLog(LLDBLog::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) {
1815ffd83dbSDimitry Andric         GetTarget().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 
AtOurAddress()1920b57cec5SDimitry Andric bool ThreadPlanRunToAddress::AtOurAddress() {
1935ffd83dbSDimitry Andric   lldb::addr_t current_address = GetThread().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