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