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