| //===-- ThreadPlanRunToAddress.cpp ------------------------------*- C++ -*-===// |
| // |
| // The LLVM Compiler Infrastructure |
| // |
| // This file is distributed under the University of Illinois Open Source |
| // License. See LICENSE.TXT for details. |
| // |
| //===----------------------------------------------------------------------===// |
| |
| // C Includes |
| // C++ Includes |
| // Other libraries and framework includes |
| // Project includes |
| #include "lldb/Target/ThreadPlanRunToAddress.h" |
| #include "lldb/Target/Process.h" |
| #include "lldb/Target/RegisterContext.h" |
| #include "lldb/Target/Target.h" |
| #include "lldb/Target/Thread.h" |
| #include "lldb/Utility/Log.h" |
| #include "lldb/Utility/Stream.h" |
| |
| using namespace lldb; |
| using namespace lldb_private; |
| |
| //---------------------------------------------------------------------- |
| // ThreadPlanRunToAddress: Continue plan |
| //---------------------------------------------------------------------- |
| |
| ThreadPlanRunToAddress::ThreadPlanRunToAddress(Thread &thread, Address &address, |
| bool stop_others) |
| : ThreadPlan(ThreadPlan::eKindRunToAddress, "Run to address plan", thread, |
| eVoteNoOpinion, eVoteNoOpinion), |
| m_stop_others(stop_others), m_addresses(), m_break_ids() { |
| m_addresses.push_back( |
| address.GetOpcodeLoadAddress(m_thread.CalculateTarget().get())); |
| SetInitialBreakpoints(); |
| } |
| |
| ThreadPlanRunToAddress::ThreadPlanRunToAddress(Thread &thread, |
| lldb::addr_t address, |
| bool stop_others) |
| : ThreadPlan(ThreadPlan::eKindRunToAddress, "Run to address plan", thread, |
| eVoteNoOpinion, eVoteNoOpinion), |
| m_stop_others(stop_others), m_addresses(), m_break_ids() { |
| m_addresses.push_back( |
| m_thread.CalculateTarget()->GetOpcodeLoadAddress(address)); |
| SetInitialBreakpoints(); |
| } |
| |
| ThreadPlanRunToAddress::ThreadPlanRunToAddress( |
| Thread &thread, const std::vector<lldb::addr_t> &addresses, |
| bool stop_others) |
| : ThreadPlan(ThreadPlan::eKindRunToAddress, "Run to address plan", thread, |
| eVoteNoOpinion, eVoteNoOpinion), |
| m_stop_others(stop_others), m_addresses(addresses), m_break_ids() { |
| // Convert all addresses into opcode addresses to make sure we set |
| // breakpoints at the correct address. |
| Target &target = thread.GetProcess()->GetTarget(); |
| std::vector<lldb::addr_t>::iterator pos, end = m_addresses.end(); |
| for (pos = m_addresses.begin(); pos != end; ++pos) |
| *pos = target.GetOpcodeLoadAddress(*pos); |
| |
| SetInitialBreakpoints(); |
| } |
| |
| void ThreadPlanRunToAddress::SetInitialBreakpoints() { |
| size_t num_addresses = m_addresses.size(); |
| m_break_ids.resize(num_addresses); |
| |
| for (size_t i = 0; i < num_addresses; i++) { |
| Breakpoint *breakpoint; |
| breakpoint = m_thread.CalculateTarget() |
| ->CreateBreakpoint(m_addresses[i], true, false) |
| .get(); |
| if (breakpoint != nullptr) { |
| m_break_ids[i] = breakpoint->GetID(); |
| breakpoint->SetThreadID(m_thread.GetID()); |
| breakpoint->SetBreakpointKind("run-to-address"); |
| } |
| } |
| } |
| |
| ThreadPlanRunToAddress::~ThreadPlanRunToAddress() { |
| size_t num_break_ids = m_break_ids.size(); |
| for (size_t i = 0; i < num_break_ids; i++) { |
| m_thread.CalculateTarget()->RemoveBreakpointByID(m_break_ids[i]); |
| } |
| } |
| |
| void ThreadPlanRunToAddress::GetDescription(Stream *s, |
| lldb::DescriptionLevel level) { |
| size_t num_addresses = m_addresses.size(); |
| |
| if (level == lldb::eDescriptionLevelBrief) { |
| if (num_addresses == 0) { |
| s->Printf("run to address with no addresses given."); |
| return; |
| } else if (num_addresses == 1) |
| s->Printf("run to address: "); |
| else |
| s->Printf("run to addresses: "); |
| |
| for (size_t i = 0; i < num_addresses; i++) { |
| s->Address(m_addresses[i], sizeof(addr_t)); |
| s->Printf(" "); |
| } |
| } else { |
| if (num_addresses == 0) { |
| s->Printf("run to address with no addresses given."); |
| return; |
| } else if (num_addresses == 1) |
| s->Printf("Run to address: "); |
| else { |
| s->Printf("Run to addresses: "); |
| } |
| |
| for (size_t i = 0; i < num_addresses; i++) { |
| if (num_addresses > 1) { |
| s->Printf("\n"); |
| s->Indent(); |
| } |
| |
| s->Address(m_addresses[i], sizeof(addr_t)); |
| s->Printf(" using breakpoint: %d - ", m_break_ids[i]); |
| Breakpoint *breakpoint = |
| m_thread.CalculateTarget()->GetBreakpointByID(m_break_ids[i]).get(); |
| if (breakpoint) |
| breakpoint->Dump(s); |
| else |
| s->Printf("but the breakpoint has been deleted."); |
| } |
| } |
| } |
| |
| bool ThreadPlanRunToAddress::ValidatePlan(Stream *error) { |
| // If we couldn't set the breakpoint for some reason, then this won't work. |
| bool all_bps_good = true; |
| size_t num_break_ids = m_break_ids.size(); |
| |
| for (size_t i = 0; i < num_break_ids; i++) { |
| if (m_break_ids[i] == LLDB_INVALID_BREAK_ID) { |
| all_bps_good = false; |
| if (error) { |
| error->Printf("Could not set breakpoint for address: "); |
| error->Address(m_addresses[i], sizeof(addr_t)); |
| error->Printf("\n"); |
| } |
| } |
| } |
| return all_bps_good; |
| } |
| |
| bool ThreadPlanRunToAddress::DoPlanExplainsStop(Event *event_ptr) { |
| return AtOurAddress(); |
| } |
| |
| bool ThreadPlanRunToAddress::ShouldStop(Event *event_ptr) { |
| return AtOurAddress(); |
| } |
| |
| bool ThreadPlanRunToAddress::StopOthers() { return m_stop_others; } |
| |
| void ThreadPlanRunToAddress::SetStopOthers(bool new_value) { |
| m_stop_others = new_value; |
| } |
| |
| StateType ThreadPlanRunToAddress::GetPlanRunState() { return eStateRunning; } |
| |
| bool ThreadPlanRunToAddress::WillStop() { return true; } |
| |
| bool ThreadPlanRunToAddress::MischiefManaged() { |
| Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP)); |
| |
| if (AtOurAddress()) { |
| // Remove the breakpoint |
| size_t num_break_ids = m_break_ids.size(); |
| |
| for (size_t i = 0; i < num_break_ids; i++) { |
| if (m_break_ids[i] != LLDB_INVALID_BREAK_ID) { |
| m_thread.CalculateTarget()->RemoveBreakpointByID(m_break_ids[i]); |
| m_break_ids[i] = LLDB_INVALID_BREAK_ID; |
| } |
| } |
| if (log) |
| log->Printf("Completed run to address plan."); |
| ThreadPlan::MischiefManaged(); |
| return true; |
| } else |
| return false; |
| } |
| |
| bool ThreadPlanRunToAddress::AtOurAddress() { |
| lldb::addr_t current_address = m_thread.GetRegisterContext()->GetPC(); |
| bool found_it = false; |
| size_t num_addresses = m_addresses.size(); |
| for (size_t i = 0; i < num_addresses; i++) { |
| if (m_addresses[i] == current_address) { |
| found_it = true; |
| break; |
| } |
| } |
| return found_it; |
| } |