1 //===-- ThreadPlanStepOut.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/ThreadPlanStepOut.h" 11 12 // C Includes 13 // C++ Includes 14 // Other libraries and framework includes 15 // Project includes 16 #include "lldb/Breakpoint/Breakpoint.h" 17 #include "lldb/lldb-private-log.h" 18 #include "lldb/Core/Log.h" 19 #include "lldb/Target/Process.h" 20 #include "lldb/Target/RegisterContext.h" 21 #include "lldb/Target/StopInfo.h" 22 #include "lldb/Target/Target.h" 23 #include "lldb/Target/ThreadPlanStepOverRange.h" 24 25 using namespace lldb; 26 using namespace lldb_private; 27 28 //---------------------------------------------------------------------- 29 // ThreadPlanStepOut: Step out of the current frame 30 //---------------------------------------------------------------------- 31 32 ThreadPlanStepOut::ThreadPlanStepOut 33 ( 34 Thread &thread, 35 SymbolContext *context, 36 bool first_insn, 37 bool stop_others, 38 Vote stop_vote, 39 Vote run_vote, 40 uint32_t frame_idx 41 ) : 42 ThreadPlan (ThreadPlan::eKindStepOut, "Step out", thread, stop_vote, run_vote), 43 m_step_from_context (context), 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_first_insn (first_insn), 48 m_stop_others (stop_others), 49 m_step_through_inline_plan_sp(), 50 m_step_out_plan_sp () 51 52 { 53 m_step_from_insn = m_thread.GetRegisterContext()->GetPC(0); 54 55 StackFrameSP return_frame_sp (m_thread.GetStackFrameAtIndex(frame_idx + 1)); 56 StackFrameSP immediate_return_from_sp (m_thread.GetStackFrameAtIndex (frame_idx)); 57 58 m_stack_depth = m_thread.GetStackFrameCount() - frame_idx; 59 60 // If the frame directly below the one we are returning to is inlined, we have to be 61 // a little more careful. It is non-trivial to determine the real "return code address" for 62 // an inlined frame, so we have to work our way to that frame and then step out. 63 if (immediate_return_from_sp && immediate_return_from_sp->IsInlined()) 64 { 65 if (frame_idx > 0) 66 { 67 // First queue a plan that gets us to this inlined frame, and when we get there we'll queue a second 68 // plan that walks us out of this frame. 69 m_step_out_plan_sp.reset (new ThreadPlanStepOut(m_thread, NULL, false, stop_others, eVoteNoOpinion, eVoteNoOpinion, frame_idx - 1)); 70 m_step_out_plan_sp->SetOkayToDiscard(true); 71 } 72 else 73 { 74 // If we're already at the inlined frame we're stepping through, then just do that now. 75 QueueInlinedStepPlan(false); 76 } 77 78 } 79 else if (return_frame_sp) 80 { 81 // Find the return address and set a breakpoint there: 82 // FIXME - can we do this more securely if we know first_insn? 83 84 m_return_addr = return_frame_sp->GetFrameCodeAddress().GetLoadAddress(&m_thread.GetProcess().GetTarget()); 85 Breakpoint *return_bp = m_thread.GetProcess().GetTarget().CreateBreakpoint (m_return_addr, true).get(); 86 if (return_bp != NULL) 87 { 88 return_bp->SetThreadID(m_thread.GetID()); 89 m_return_bp_id = return_bp->GetID(); 90 } 91 } 92 93 } 94 95 void 96 ThreadPlanStepOut::DidPush() 97 { 98 if (m_step_out_plan_sp) 99 m_thread.QueueThreadPlan(m_step_out_plan_sp, false); 100 else if (m_step_through_inline_plan_sp) 101 m_thread.QueueThreadPlan(m_step_through_inline_plan_sp, false); 102 } 103 104 ThreadPlanStepOut::~ThreadPlanStepOut () 105 { 106 if (m_return_bp_id != LLDB_INVALID_BREAK_ID) 107 m_thread.GetProcess().GetTarget().RemoveBreakpointByID(m_return_bp_id); 108 } 109 110 void 111 ThreadPlanStepOut::GetDescription (Stream *s, lldb::DescriptionLevel level) 112 { 113 if (level == lldb::eDescriptionLevelBrief) 114 s->Printf ("step out"); 115 else 116 { 117 if (m_step_out_plan_sp) 118 s->Printf ("Stepping out to inlined frame at depth: %d so we can walk through it.", m_stack_depth); 119 else if (m_step_through_inline_plan_sp) 120 s->Printf ("Stepping out by stepping through inlined function."); 121 else 122 s->Printf ("Stepping out from address 0x%llx to return address 0x%llx at depth: %d using breakpoint site %d", 123 (uint64_t)m_step_from_insn, 124 (uint64_t)m_return_addr, 125 m_stack_depth, 126 m_return_bp_id); 127 } 128 } 129 130 bool 131 ThreadPlanStepOut::ValidatePlan (Stream *error) 132 { 133 if (m_step_out_plan_sp) 134 return m_step_out_plan_sp->ValidatePlan (error); 135 else if (m_step_through_inline_plan_sp) 136 return m_step_through_inline_plan_sp->ValidatePlan (error); 137 else if (m_return_bp_id == LLDB_INVALID_BREAK_ID) 138 { 139 error->PutCString("Could not create return address breakpoint."); 140 return false; 141 } 142 else 143 return true; 144 } 145 146 bool 147 ThreadPlanStepOut::PlanExplainsStop () 148 { 149 // If one of our child plans just finished, then we do explain the stop. 150 if (m_step_out_plan_sp) 151 { 152 if (m_step_out_plan_sp->MischiefManaged()) 153 { 154 // If this one is done, then we are all done. 155 SetPlanComplete(); 156 return true; 157 } 158 else 159 return false; 160 } 161 else if (m_step_through_inline_plan_sp) 162 { 163 if (m_step_through_inline_plan_sp->MischiefManaged()) 164 return true; 165 else 166 return false; 167 } 168 169 // We don't explain signals or breakpoints (breakpoints that handle stepping in or 170 // out will be handled by a child plan. 171 172 StopInfoSP stop_info_sp = GetPrivateStopReason(); 173 if (stop_info_sp) 174 { 175 StopReason reason = stop_info_sp->GetStopReason(); 176 switch (reason) 177 { 178 case eStopReasonBreakpoint: 179 { 180 // If this is OUR breakpoint, we're fine, otherwise we don't know why this happened... 181 BreakpointSiteSP site_sp (m_thread.GetProcess().GetBreakpointSiteList().FindByID (stop_info_sp->GetValue())); 182 if (site_sp && site_sp->IsBreakpointAtThisSite (m_return_bp_id)) 183 { 184 const uint32_t num_frames = m_thread.GetStackFrameCount(); 185 if (m_stack_depth > num_frames) 186 SetPlanComplete(); 187 188 // If there was only one owner, then we're done. But if we also hit some 189 // user breakpoint on our way out, we should mark ourselves as done, but 190 // also not claim to explain the stop, since it is more important to report 191 // the user breakpoint than the step out completion. 192 193 if (site_sp->GetNumberOfOwners() == 1) 194 return true; 195 196 } 197 return false; 198 } 199 case eStopReasonWatchpoint: 200 case eStopReasonSignal: 201 case eStopReasonException: 202 return false; 203 204 default: 205 return true; 206 } 207 } 208 return true; 209 } 210 211 bool 212 ThreadPlanStepOut::ShouldStop (Event *event_ptr) 213 { 214 if (IsPlanComplete()) 215 { 216 return true; 217 } 218 else if (m_stack_depth > m_thread.GetStackFrameCount()) 219 { 220 SetPlanComplete(); 221 return true; 222 } 223 else 224 { 225 if (m_step_out_plan_sp) 226 { 227 if (m_step_out_plan_sp->MischiefManaged()) 228 { 229 // Now step through the inlined stack we are in: 230 if (QueueInlinedStepPlan(true)) 231 { 232 return false; 233 } 234 else 235 { 236 SetPlanComplete (); 237 return true; 238 } 239 } 240 else 241 return m_step_out_plan_sp->ShouldStop(event_ptr); 242 } 243 else if (m_step_through_inline_plan_sp) 244 { 245 if (m_step_through_inline_plan_sp->MischiefManaged()) 246 { 247 SetPlanComplete(); 248 return true; 249 } 250 else 251 return m_step_through_inline_plan_sp->ShouldStop(event_ptr); 252 } 253 else 254 return false; 255 } 256 } 257 258 bool 259 ThreadPlanStepOut::StopOthers () 260 { 261 return m_stop_others; 262 } 263 264 StateType 265 ThreadPlanStepOut::GetPlanRunState () 266 { 267 return eStateRunning; 268 } 269 270 bool 271 ThreadPlanStepOut::WillResume (StateType resume_state, bool current_plan) 272 { 273 ThreadPlan::WillResume (resume_state, current_plan); 274 if (m_step_out_plan_sp || m_step_through_inline_plan_sp) 275 return true; 276 277 if (m_return_bp_id == LLDB_INVALID_BREAK_ID) 278 return false; 279 280 if (current_plan) 281 { 282 Breakpoint *return_bp = m_thread.GetProcess().GetTarget().GetBreakpointByID(m_return_bp_id).get(); 283 if (return_bp != NULL) 284 return_bp->SetEnabled (true); 285 } 286 return true; 287 } 288 289 bool 290 ThreadPlanStepOut::WillStop () 291 { 292 if (m_return_bp_id != LLDB_INVALID_BREAK_ID) 293 { 294 Breakpoint *return_bp = m_thread.GetProcess().GetTarget().GetBreakpointByID(m_return_bp_id).get(); 295 if (return_bp != NULL) 296 return_bp->SetEnabled (false); 297 } 298 299 return true; 300 } 301 302 bool 303 ThreadPlanStepOut::MischiefManaged () 304 { 305 if (IsPlanComplete()) 306 { 307 // Did I reach my breakpoint? If so I'm done. 308 // 309 // I also check the stack depth, since if we've blown past the breakpoint for some 310 // reason and we're now stopping for some other reason altogether, then we're done 311 // with this step out operation. 312 313 LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP)); 314 if (log) 315 log->Printf("Completed step out plan."); 316 if (m_return_bp_id != LLDB_INVALID_BREAK_ID) 317 { 318 m_thread.GetProcess().GetTarget().RemoveBreakpointByID (m_return_bp_id); 319 m_return_bp_id = LLDB_INVALID_BREAK_ID; 320 } 321 322 ThreadPlan::MischiefManaged (); 323 return true; 324 } 325 else 326 { 327 return false; 328 } 329 } 330 331 bool 332 ThreadPlanStepOut::QueueInlinedStepPlan (bool queue_now) 333 { 334 // Now figure out the range of this inlined block, and set up a "step through range" 335 // plan for that. If we've been provided with a context, then use the block in that 336 // context. 337 StackFrameSP immediate_return_from_sp (m_thread.GetStackFrameAtIndex (0)); 338 if (!immediate_return_from_sp) 339 return false; 340 341 LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP)); 342 if (log) 343 { 344 StreamString s; 345 immediate_return_from_sp->Dump(&s, true, false); 346 log->Printf("Queuing inlined frame to step past: %s.", s.GetData()); 347 } 348 349 Block *from_block = immediate_return_from_sp->GetFrameBlock(); 350 if (from_block) 351 { 352 Block *inlined_block = from_block->GetContainingInlinedBlock(); 353 if (inlined_block) 354 { 355 size_t num_ranges = inlined_block->GetNumRanges(); 356 AddressRange inline_range; 357 if (inlined_block->GetRangeAtIndex(0, inline_range)) 358 { 359 SymbolContext inlined_sc; 360 inlined_block->CalculateSymbolContext(&inlined_sc); 361 RunMode run_mode = m_stop_others ? lldb::eOnlyThisThread : lldb::eAllThreads; 362 ThreadPlanStepOverRange *step_through_inline_plan_ptr = new ThreadPlanStepOverRange(m_thread, 363 inline_range, 364 inlined_sc, 365 run_mode); 366 step_through_inline_plan_ptr->SetOkayToDiscard(true); 367 StreamString errors; 368 if (!step_through_inline_plan_ptr->ValidatePlan(&errors)) 369 { 370 //FIXME: Log this failure. 371 delete step_through_inline_plan_ptr; 372 return false; 373 } 374 375 for (size_t i = 1; i < num_ranges; i++) 376 { 377 if (inlined_block->GetRangeAtIndex (i, inline_range)) 378 step_through_inline_plan_ptr->AddRange (inline_range); 379 } 380 m_step_through_inline_plan_sp.reset (step_through_inline_plan_ptr); 381 if (queue_now) 382 m_thread.QueueThreadPlan (m_step_through_inline_plan_sp, false); 383 return true; 384 } 385 } 386 } 387 388 return false; 389 } 390