1 //===-- ThreadPlanStepUntil.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 //m_should_stop 10 11 // 12 //===----------------------------------------------------------------------===// 13 14 #include "lldb/Target/ThreadPlanStepUntil.h" 15 16 // C Includes 17 // C++ Includes 18 // Other libraries and framework includes 19 // Project includes 20 #include "lldb/Breakpoint/Breakpoint.h" 21 #include "lldb/lldb-private-log.h" 22 #include "lldb/Core/Log.h" 23 #include "lldb/Target/Process.h" 24 #include "lldb/Target/RegisterContext.h" 25 #include "lldb/Target/Target.h" 26 27 using namespace lldb; 28 using namespace lldb_private; 29 30 //---------------------------------------------------------------------- 31 // ThreadPlanStepUntil: Run until we reach a given line number or step out of the current frame 32 //---------------------------------------------------------------------- 33 34 ThreadPlanStepUntil::ThreadPlanStepUntil 35 ( 36 Thread &thread, 37 lldb::addr_t *address_list, 38 size_t num_addresses, 39 bool stop_others 40 ) : 41 ThreadPlan (ThreadPlan::eKindStepUntil, "Step until", thread, eVoteNoOpinion, eVoteNoOpinion), 42 m_step_from_insn (LLDB_INVALID_ADDRESS), 43 m_return_addr (LLDB_INVALID_ADDRESS), 44 m_return_bp_id(LLDB_INVALID_BREAK_ID), 45 m_stepped_out(false), 46 m_should_stop(false), 47 m_explains_stop(false), 48 m_ran_analyze (false), 49 m_stop_others (stop_others) 50 { 51 52 SetOkayToDiscard(true); 53 // Stash away our "until" addresses: 54 Target &target = m_thread.GetProcess().GetTarget(); 55 56 m_step_from_insn = m_thread.GetRegisterContext()->GetPC(0); 57 lldb::user_id_t thread_id = m_thread.GetID(); 58 59 // Find the return address and set a breakpoint there: 60 // FIXME - can we do this more securely if we know first_insn? 61 62 StackFrame *return_frame = m_thread.GetStackFrameAtIndex(1).get(); 63 m_return_addr = return_frame->GetPC().GetLoadAddress(&m_thread.GetProcess()); 64 Breakpoint *return_bp = target.CreateBreakpoint (m_return_addr, true).get(); 65 if (return_bp != NULL) 66 { 67 return_bp->SetThreadID(thread_id); 68 m_return_bp_id = return_bp->GetID(); 69 } 70 else 71 { 72 m_return_bp_id = LLDB_INVALID_BREAK_ID; 73 } 74 75 m_stack_depth = m_thread.GetStackFrameCount(); 76 77 // Now set breakpoints on all our return addresses: 78 for (int i = 0; i < num_addresses; i++) 79 { 80 Breakpoint *until_bp = target.CreateBreakpoint (address_list[i], true).get(); 81 if (until_bp != NULL) 82 { 83 until_bp->SetThreadID(thread_id); 84 m_until_points[address_list[i]] = until_bp->GetID(); 85 } 86 else 87 { 88 m_until_points[address_list[i]] = LLDB_INVALID_BREAK_ID; 89 } 90 } 91 } 92 93 ThreadPlanStepUntil::~ThreadPlanStepUntil () 94 { 95 Clear(); 96 } 97 98 void 99 ThreadPlanStepUntil::Clear() 100 { 101 Target &target = m_thread.GetProcess().GetTarget(); 102 if (m_return_bp_id != LLDB_INVALID_BREAK_ID) 103 { 104 target.RemoveBreakpointByID(m_return_bp_id); 105 m_return_bp_id = LLDB_INVALID_BREAK_ID; 106 } 107 108 until_collection::iterator pos, end = m_until_points.end(); 109 for (pos = m_until_points.begin(); pos != end; pos++) 110 { 111 target.RemoveBreakpointByID((*pos).second); 112 } 113 m_until_points.clear(); 114 } 115 116 void 117 ThreadPlanStepUntil::GetDescription (Stream *s, lldb::DescriptionLevel level) 118 { 119 if (level == lldb::eDescriptionLevelBrief) 120 { 121 s->Printf ("step until"); 122 if (m_stepped_out) 123 s->Printf (" - stepped out"); 124 } 125 else 126 { 127 if (m_until_points.size() == 1) 128 s->Printf ("Stepping from address 0x%llx until we reach 0x%llx using breakpoint %d", 129 (uint64_t)m_step_from_insn, 130 (uint64_t) (*m_until_points.begin()).first, 131 (*m_until_points.begin()).second); 132 else 133 { 134 until_collection::iterator pos, end = m_until_points.end(); 135 s->Printf ("Stepping from address 0x%llx until we reach one of:", 136 (uint64_t)m_step_from_insn); 137 for (pos = m_until_points.begin(); pos != end; pos++) 138 { 139 s->Printf ("\n\t0x%llx (bp: %d)", (uint64_t) (*pos).first, (*pos).second); 140 } 141 } 142 s->Printf(" stepped out address is 0x%lx.", (uint64_t) m_return_addr); 143 } 144 } 145 146 bool 147 ThreadPlanStepUntil::ValidatePlan (Stream *error) 148 { 149 if (m_return_bp_id == LLDB_INVALID_BREAK_ID) 150 return false; 151 else 152 { 153 until_collection::iterator pos, end = m_until_points.end(); 154 for (pos = m_until_points.begin(); pos != end; pos++) 155 { 156 if (!LLDB_BREAK_ID_IS_VALID ((*pos).second)) 157 return false; 158 } 159 return true; 160 } 161 } 162 163 void 164 ThreadPlanStepUntil::AnalyzeStop() 165 { 166 if (m_ran_analyze) 167 return; 168 169 Thread::StopInfo info; 170 m_should_stop = true; 171 m_explains_stop = false; 172 173 if (m_thread.GetStopInfo (&info)) 174 { 175 StopReason reason = info.GetStopReason(); 176 177 switch (reason) 178 { 179 case eStopReasonBreakpoint: 180 { 181 // If this is OUR breakpoint, we're fine, otherwise we don't know why this happened... 182 BreakpointSiteSP this_site = m_thread.GetProcess().GetBreakpointSiteList().FindByID (info.GetBreakpointSiteID()); 183 if (!this_site) 184 { 185 m_explains_stop = false; 186 return; 187 } 188 189 if (this_site->IsBreakpointAtThisSite (m_return_bp_id)) 190 { 191 // If we are at our "step out" breakpoint, and the stack depth has shrunk, then 192 // this is indeed our stop. 193 // If the stack depth has grown, then we've hit our step out breakpoint recursively. 194 // If we are the only breakpoint at that location, then we do explain the stop, and 195 // we'll just continue. 196 // If there was another breakpoint here, then we don't explain the stop, but we won't 197 // mark ourselves Completed, because maybe that breakpoint will continue, and then 198 // we'll finish the "until". 199 if (m_stack_depth > m_thread.GetStackFrameCount()) 200 { 201 m_stepped_out = true; 202 SetPlanComplete(); 203 } 204 else 205 m_should_stop = false; 206 207 if (this_site->GetNumberOfOwners() == 1) 208 m_explains_stop = true; 209 else 210 m_explains_stop = false; 211 return; 212 } 213 else 214 { 215 // Check if we've hit one of our "until" breakpoints. 216 until_collection::iterator pos, end = m_until_points.end(); 217 for (pos = m_until_points.begin(); pos != end; pos++) 218 { 219 if (this_site->IsBreakpointAtThisSite ((*pos).second)) 220 { 221 // If we're at the right stack depth, then we're done. 222 if (m_stack_depth == m_thread.GetStackFrameCount()) 223 SetPlanComplete(); 224 else 225 m_should_stop = false; 226 227 // Otherwise we've hit this breakpoint recursively. If we're the 228 // only breakpoint here, then we do explain the stop, and we'll continue. 229 // If not then we should let higher plans handle this stop. 230 if (this_site->GetNumberOfOwners() == 1) 231 m_explains_stop = true; 232 else 233 { 234 m_should_stop = true; 235 m_explains_stop = false; 236 } 237 return; 238 } 239 } 240 } 241 // If we get here we haven't hit any of our breakpoints, so let the higher 242 // plans take care of the stop. 243 m_explains_stop = false; 244 return; 245 } 246 case eStopReasonWatchpoint: 247 case eStopReasonSignal: 248 case eStopReasonException: 249 m_explains_stop = false; 250 break; 251 default: 252 m_explains_stop = true; 253 break; 254 } 255 } 256 } 257 258 bool 259 ThreadPlanStepUntil::PlanExplainsStop () 260 { 261 // We don't explain signals or breakpoints (breakpoints that handle stepping in or 262 // out will be handled by a child plan. 263 AnalyzeStop(); 264 return m_explains_stop; 265 } 266 267 bool 268 ThreadPlanStepUntil::ShouldStop (Event *event_ptr) 269 { 270 // If we've told our self in ExplainsStop that we plan to continue, then 271 // do so here. Otherwise, as long as this thread has stopped for a reason, 272 // we will stop. 273 274 Thread::StopInfo stop_info (&m_thread); 275 if (!m_thread.GetStopInfo(&stop_info) 276 || stop_info.GetStopReason() == eStopReasonNone) 277 return false; 278 279 AnalyzeStop(); 280 return m_should_stop; 281 } 282 283 bool 284 ThreadPlanStepUntil::StopOthers () 285 { 286 return m_stop_others; 287 } 288 289 StateType 290 ThreadPlanStepUntil::RunState () 291 { 292 return eStateRunning; 293 } 294 295 bool 296 ThreadPlanStepUntil::WillResume (StateType resume_state, bool current_plan) 297 { 298 ThreadPlan::WillResume (resume_state, current_plan); 299 if (current_plan) 300 { 301 Target &target = m_thread.GetProcess().GetTarget(); 302 Breakpoint *return_bp = target.GetBreakpointByID(m_return_bp_id).get(); 303 if (return_bp != NULL) 304 return_bp->SetEnabled (true); 305 306 until_collection::iterator pos, end = m_until_points.end(); 307 for (pos = m_until_points.begin(); pos != end; pos++) 308 { 309 Breakpoint *until_bp = target.GetBreakpointByID((*pos).second).get(); 310 if (until_bp != NULL) 311 until_bp->SetEnabled (true); 312 } 313 } 314 315 m_should_stop = true; 316 m_ran_analyze = false; 317 m_explains_stop = false; 318 return true; 319 } 320 321 bool 322 ThreadPlanStepUntil::WillStop () 323 { 324 Target &target = m_thread.GetProcess().GetTarget(); 325 Breakpoint *return_bp = target.GetBreakpointByID(m_return_bp_id).get(); 326 if (return_bp != NULL) 327 return_bp->SetEnabled (false); 328 329 until_collection::iterator pos, end = m_until_points.end(); 330 for (pos = m_until_points.begin(); pos != end; pos++) 331 { 332 Breakpoint *until_bp = target.GetBreakpointByID((*pos).second).get(); 333 if (until_bp != NULL) 334 until_bp->SetEnabled (false); 335 } 336 return true; 337 } 338 339 bool 340 ThreadPlanStepUntil::MischiefManaged () 341 { 342 343 // I'm letting "PlanExplainsStop" do all the work, and just reporting that here. 344 bool done = false; 345 if (IsPlanComplete()) 346 { 347 Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP); 348 if (log) 349 log->Printf("Completed step until plan."); 350 351 Clear(); 352 done = true; 353 } 354 if (done) 355 ThreadPlan::MischiefManaged (); 356 357 return done; 358 359 } 360 361