1 //===-- ThreadPlanRunToAddress.cpp ------------------------------*- C++ -*-===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 10 #include "lldb/Target/ThreadPlanRunToAddress.h" 11 #include "lldb/Target/Process.h" 12 #include "lldb/Target/RegisterContext.h" 13 #include "lldb/Target/Target.h" 14 #include "lldb/Target/Thread.h" 15 #include "lldb/Utility/Log.h" 16 #include "lldb/Utility/Stream.h" 17 18 using namespace lldb; 19 using namespace lldb_private; 20 21 //---------------------------------------------------------------------- 22 // ThreadPlanRunToAddress: Continue plan 23 //---------------------------------------------------------------------- 24 25 ThreadPlanRunToAddress::ThreadPlanRunToAddress(Thread &thread, Address &address, 26 bool stop_others) 27 : ThreadPlan(ThreadPlan::eKindRunToAddress, "Run to address plan", thread, 28 eVoteNoOpinion, eVoteNoOpinion), 29 m_stop_others(stop_others), m_addresses(), m_break_ids() { 30 m_addresses.push_back( 31 address.GetOpcodeLoadAddress(m_thread.CalculateTarget().get())); 32 SetInitialBreakpoints(); 33 } 34 35 ThreadPlanRunToAddress::ThreadPlanRunToAddress(Thread &thread, 36 lldb::addr_t address, 37 bool stop_others) 38 : ThreadPlan(ThreadPlan::eKindRunToAddress, "Run to address plan", thread, 39 eVoteNoOpinion, eVoteNoOpinion), 40 m_stop_others(stop_others), m_addresses(), m_break_ids() { 41 m_addresses.push_back( 42 m_thread.CalculateTarget()->GetOpcodeLoadAddress(address)); 43 SetInitialBreakpoints(); 44 } 45 46 ThreadPlanRunToAddress::ThreadPlanRunToAddress( 47 Thread &thread, const std::vector<lldb::addr_t> &addresses, 48 bool stop_others) 49 : ThreadPlan(ThreadPlan::eKindRunToAddress, "Run to address plan", thread, 50 eVoteNoOpinion, eVoteNoOpinion), 51 m_stop_others(stop_others), m_addresses(addresses), m_break_ids() { 52 // Convert all addresses into opcode addresses to make sure we set 53 // breakpoints at the correct address. 54 Target &target = thread.GetProcess()->GetTarget(); 55 std::vector<lldb::addr_t>::iterator pos, end = m_addresses.end(); 56 for (pos = m_addresses.begin(); pos != end; ++pos) 57 *pos = target.GetOpcodeLoadAddress(*pos); 58 59 SetInitialBreakpoints(); 60 } 61 62 void ThreadPlanRunToAddress::SetInitialBreakpoints() { 63 size_t num_addresses = m_addresses.size(); 64 m_break_ids.resize(num_addresses); 65 66 for (size_t i = 0; i < num_addresses; i++) { 67 Breakpoint *breakpoint; 68 breakpoint = m_thread.CalculateTarget() 69 ->CreateBreakpoint(m_addresses[i], true, false) 70 .get(); 71 if (breakpoint != nullptr) { 72 m_break_ids[i] = breakpoint->GetID(); 73 breakpoint->SetThreadID(m_thread.GetID()); 74 breakpoint->SetBreakpointKind("run-to-address"); 75 } 76 } 77 } 78 79 ThreadPlanRunToAddress::~ThreadPlanRunToAddress() { 80 size_t num_break_ids = m_break_ids.size(); 81 for (size_t i = 0; i < num_break_ids; i++) { 82 m_thread.CalculateTarget()->RemoveBreakpointByID(m_break_ids[i]); 83 } 84 } 85 86 void ThreadPlanRunToAddress::GetDescription(Stream *s, 87 lldb::DescriptionLevel level) { 88 size_t num_addresses = m_addresses.size(); 89 90 if (level == lldb::eDescriptionLevelBrief) { 91 if (num_addresses == 0) { 92 s->Printf("run to address with no addresses given."); 93 return; 94 } else if (num_addresses == 1) 95 s->Printf("run to address: "); 96 else 97 s->Printf("run to addresses: "); 98 99 for (size_t i = 0; i < num_addresses; i++) { 100 s->Address(m_addresses[i], sizeof(addr_t)); 101 s->Printf(" "); 102 } 103 } else { 104 if (num_addresses == 0) { 105 s->Printf("run to address with no addresses given."); 106 return; 107 } else if (num_addresses == 1) 108 s->Printf("Run to address: "); 109 else { 110 s->Printf("Run to addresses: "); 111 } 112 113 for (size_t i = 0; i < num_addresses; i++) { 114 if (num_addresses > 1) { 115 s->Printf("\n"); 116 s->Indent(); 117 } 118 119 s->Address(m_addresses[i], sizeof(addr_t)); 120 s->Printf(" using breakpoint: %d - ", m_break_ids[i]); 121 Breakpoint *breakpoint = 122 m_thread.CalculateTarget()->GetBreakpointByID(m_break_ids[i]).get(); 123 if (breakpoint) 124 breakpoint->Dump(s); 125 else 126 s->Printf("but the breakpoint has been deleted."); 127 } 128 } 129 } 130 131 bool ThreadPlanRunToAddress::ValidatePlan(Stream *error) { 132 // If we couldn't set the breakpoint for some reason, then this won't work. 133 bool all_bps_good = true; 134 size_t num_break_ids = m_break_ids.size(); 135 136 for (size_t i = 0; i < num_break_ids; i++) { 137 if (m_break_ids[i] == LLDB_INVALID_BREAK_ID) { 138 all_bps_good = false; 139 if (error) { 140 error->Printf("Could not set breakpoint for address: "); 141 error->Address(m_addresses[i], sizeof(addr_t)); 142 error->Printf("\n"); 143 } 144 } 145 } 146 return all_bps_good; 147 } 148 149 bool ThreadPlanRunToAddress::DoPlanExplainsStop(Event *event_ptr) { 150 return AtOurAddress(); 151 } 152 153 bool ThreadPlanRunToAddress::ShouldStop(Event *event_ptr) { 154 return AtOurAddress(); 155 } 156 157 bool ThreadPlanRunToAddress::StopOthers() { return m_stop_others; } 158 159 void ThreadPlanRunToAddress::SetStopOthers(bool new_value) { 160 m_stop_others = new_value; 161 } 162 163 StateType ThreadPlanRunToAddress::GetPlanRunState() { return eStateRunning; } 164 165 bool ThreadPlanRunToAddress::WillStop() { return true; } 166 167 bool ThreadPlanRunToAddress::MischiefManaged() { 168 Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP)); 169 170 if (AtOurAddress()) { 171 // Remove the breakpoint 172 size_t num_break_ids = m_break_ids.size(); 173 174 for (size_t i = 0; i < num_break_ids; i++) { 175 if (m_break_ids[i] != LLDB_INVALID_BREAK_ID) { 176 m_thread.CalculateTarget()->RemoveBreakpointByID(m_break_ids[i]); 177 m_break_ids[i] = LLDB_INVALID_BREAK_ID; 178 } 179 } 180 if (log) 181 log->Printf("Completed run to address plan."); 182 ThreadPlan::MischiefManaged(); 183 return true; 184 } else 185 return false; 186 } 187 188 bool ThreadPlanRunToAddress::AtOurAddress() { 189 lldb::addr_t current_address = m_thread.GetRegisterContext()->GetPC(); 190 bool found_it = false; 191 size_t num_addresses = m_addresses.size(); 192 for (size_t i = 0; i < num_addresses; i++) { 193 if (m_addresses[i] == current_address) { 194 found_it = true; 195 break; 196 } 197 } 198 return found_it; 199 } 200