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