1 //===-- ThreadPlanStepOut.cpp -----------------------------------*- C++ -*-===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #include "lldb/Target/ThreadPlanStepOut.h" 10 #include "lldb/Breakpoint/Breakpoint.h" 11 #include "lldb/Core/Value.h" 12 #include "lldb/Core/ValueObjectConstResult.h" 13 #include "lldb/Symbol/Block.h" 14 #include "lldb/Symbol/Function.h" 15 #include "lldb/Symbol/Symbol.h" 16 #include "lldb/Symbol/Type.h" 17 #include "lldb/Target/ABI.h" 18 #include "lldb/Target/Process.h" 19 #include "lldb/Target/RegisterContext.h" 20 #include "lldb/Target/StopInfo.h" 21 #include "lldb/Target/Target.h" 22 #include "lldb/Target/ThreadPlanStepOverRange.h" 23 #include "lldb/Target/ThreadPlanStepThrough.h" 24 #include "lldb/Utility/Log.h" 25 26 #include <memory> 27 28 using namespace lldb; 29 using namespace lldb_private; 30 31 uint32_t ThreadPlanStepOut::s_default_flag_values = 0; 32 33 //---------------------------------------------------------------------- 34 // ThreadPlanStepOut: Step out of the current frame 35 //---------------------------------------------------------------------- 36 ThreadPlanStepOut::ThreadPlanStepOut( 37 Thread &thread, SymbolContext *context, bool first_insn, bool stop_others, 38 Vote stop_vote, Vote run_vote, uint32_t frame_idx, 39 LazyBool step_out_avoids_code_without_debug_info, 40 bool continue_to_next_branch, bool gather_return_value) 41 : ThreadPlan(ThreadPlan::eKindStepOut, "Step out", thread, stop_vote, 42 run_vote), 43 ThreadPlanShouldStopHere(this), m_step_from_insn(LLDB_INVALID_ADDRESS), 44 m_return_bp_id(LLDB_INVALID_BREAK_ID), 45 m_return_addr(LLDB_INVALID_ADDRESS), m_stop_others(stop_others), 46 m_immediate_step_from_function(nullptr), 47 m_calculate_return_value(gather_return_value) { 48 Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP)); 49 SetFlagsToDefault(); 50 SetupAvoidNoDebug(step_out_avoids_code_without_debug_info); 51 52 m_step_from_insn = m_thread.GetRegisterContext()->GetPC(0); 53 54 uint32_t return_frame_index = frame_idx + 1; 55 StackFrameSP return_frame_sp( 56 m_thread.GetStackFrameAtIndex(return_frame_index)); 57 StackFrameSP immediate_return_from_sp( 58 m_thread.GetStackFrameAtIndex(frame_idx)); 59 60 if (!return_frame_sp || !immediate_return_from_sp) 61 return; // we can't do anything here. ValidatePlan() will return false. 62 63 // While stepping out, behave as-if artificial frames are not present. 64 while (return_frame_sp->IsArtificial()) { 65 m_stepped_past_frames.push_back(return_frame_sp); 66 67 ++return_frame_index; 68 return_frame_sp = m_thread.GetStackFrameAtIndex(return_frame_index); 69 70 // We never expect to see an artificial frame without a regular ancestor. 71 // If this happens, log the issue and defensively refuse to step out. 72 if (!return_frame_sp) { 73 LLDB_LOG(log, "Can't step out of frame with artificial ancestors"); 74 return; 75 } 76 } 77 78 m_step_out_to_id = return_frame_sp->GetStackID(); 79 m_immediate_step_from_id = immediate_return_from_sp->GetStackID(); 80 81 // If the frame directly below the one we are returning to is inlined, we 82 // have to be a little more careful. It is non-trivial to determine the real 83 // "return code address" for an inlined frame, so we have to work our way to 84 // that frame and then step out. 85 if (immediate_return_from_sp->IsInlined()) { 86 if (frame_idx > 0) { 87 // First queue a plan that gets us to this inlined frame, and when we get 88 // there we'll queue a second plan that walks us out of this frame. 89 m_step_out_to_inline_plan_sp = std::make_shared<ThreadPlanStepOut>( 90 m_thread, nullptr, false, stop_others, eVoteNoOpinion, eVoteNoOpinion, 91 frame_idx - 1, eLazyBoolNo, continue_to_next_branch); 92 static_cast<ThreadPlanStepOut *>(m_step_out_to_inline_plan_sp.get()) 93 ->SetShouldStopHereCallbacks(nullptr, nullptr); 94 m_step_out_to_inline_plan_sp->SetPrivate(true); 95 } else { 96 // If we're already at the inlined frame we're stepping through, then 97 // just do that now. 98 QueueInlinedStepPlan(false); 99 } 100 } else { 101 // Find the return address and set a breakpoint there: 102 // FIXME - can we do this more securely if we know first_insn? 103 104 Address return_address(return_frame_sp->GetFrameCodeAddress()); 105 if (continue_to_next_branch) { 106 SymbolContext return_address_sc; 107 AddressRange range; 108 Address return_address_decr_pc = return_address; 109 if (return_address_decr_pc.GetOffset() > 0) 110 return_address_decr_pc.Slide(-1); 111 112 return_address_decr_pc.CalculateSymbolContext( 113 &return_address_sc, lldb::eSymbolContextLineEntry); 114 if (return_address_sc.line_entry.IsValid()) { 115 range = 116 return_address_sc.line_entry.GetSameLineContiguousAddressRange(); 117 if (range.GetByteSize() > 0) { 118 return_address = 119 m_thread.GetProcess()->AdvanceAddressToNextBranchInstruction( 120 return_address, range); 121 } 122 } 123 } 124 m_return_addr = 125 return_address.GetLoadAddress(&m_thread.GetProcess()->GetTarget()); 126 127 if (m_return_addr == LLDB_INVALID_ADDRESS) 128 return; 129 130 Breakpoint *return_bp = m_thread.CalculateTarget() 131 ->CreateBreakpoint(m_return_addr, true, false) 132 .get(); 133 134 if (return_bp != nullptr) { 135 if (return_bp->IsHardware() && !return_bp->HasResolvedLocations()) 136 m_could_not_resolve_hw_bp = true; 137 return_bp->SetThreadID(m_thread.GetID()); 138 m_return_bp_id = return_bp->GetID(); 139 return_bp->SetBreakpointKind("step-out"); 140 } 141 142 if (immediate_return_from_sp) { 143 const SymbolContext &sc = 144 immediate_return_from_sp->GetSymbolContext(eSymbolContextFunction); 145 if (sc.function) { 146 m_immediate_step_from_function = sc.function; 147 } 148 } 149 } 150 } 151 152 void ThreadPlanStepOut::SetupAvoidNoDebug( 153 LazyBool step_out_avoids_code_without_debug_info) { 154 bool avoid_nodebug = true; 155 switch (step_out_avoids_code_without_debug_info) { 156 case eLazyBoolYes: 157 avoid_nodebug = true; 158 break; 159 case eLazyBoolNo: 160 avoid_nodebug = false; 161 break; 162 case eLazyBoolCalculate: 163 avoid_nodebug = m_thread.GetStepOutAvoidsNoDebug(); 164 break; 165 } 166 if (avoid_nodebug) 167 GetFlags().Set(ThreadPlanShouldStopHere::eStepOutAvoidNoDebug); 168 else 169 GetFlags().Clear(ThreadPlanShouldStopHere::eStepOutAvoidNoDebug); 170 } 171 172 void ThreadPlanStepOut::DidPush() { 173 if (m_step_out_to_inline_plan_sp) 174 m_thread.QueueThreadPlan(m_step_out_to_inline_plan_sp, false); 175 else if (m_step_through_inline_plan_sp) 176 m_thread.QueueThreadPlan(m_step_through_inline_plan_sp, false); 177 } 178 179 ThreadPlanStepOut::~ThreadPlanStepOut() { 180 if (m_return_bp_id != LLDB_INVALID_BREAK_ID) 181 m_thread.CalculateTarget()->RemoveBreakpointByID(m_return_bp_id); 182 } 183 184 void ThreadPlanStepOut::GetDescription(Stream *s, 185 lldb::DescriptionLevel level) { 186 if (level == lldb::eDescriptionLevelBrief) 187 s->Printf("step out"); 188 else { 189 if (m_step_out_to_inline_plan_sp) 190 s->Printf("Stepping out to inlined frame so we can walk through it."); 191 else if (m_step_through_inline_plan_sp) 192 s->Printf("Stepping out by stepping through inlined function."); 193 else { 194 s->Printf("Stepping out from "); 195 Address tmp_address; 196 if (tmp_address.SetLoadAddress(m_step_from_insn, &GetTarget())) { 197 tmp_address.Dump(s, &GetThread(), Address::DumpStyleResolvedDescription, 198 Address::DumpStyleLoadAddress); 199 } else { 200 s->Printf("address 0x%" PRIx64 "", (uint64_t)m_step_from_insn); 201 } 202 203 // FIXME: find some useful way to present the m_return_id, since there may 204 // be multiple copies of the 205 // same function on the stack. 206 207 s->Printf(" returning to frame at "); 208 if (tmp_address.SetLoadAddress(m_return_addr, &GetTarget())) { 209 tmp_address.Dump(s, &GetThread(), Address::DumpStyleResolvedDescription, 210 Address::DumpStyleLoadAddress); 211 } else { 212 s->Printf("address 0x%" PRIx64 "", (uint64_t)m_return_addr); 213 } 214 215 if (level == eDescriptionLevelVerbose) 216 s->Printf(" using breakpoint site %d", m_return_bp_id); 217 } 218 } 219 220 s->Printf("\n"); 221 for (StackFrameSP frame_sp : m_stepped_past_frames) { 222 s->Printf("Stepped out past: "); 223 frame_sp->DumpUsingSettingsFormat(s); 224 } 225 } 226 227 bool ThreadPlanStepOut::ValidatePlan(Stream *error) { 228 if (m_step_out_to_inline_plan_sp) 229 return m_step_out_to_inline_plan_sp->ValidatePlan(error); 230 231 if (m_step_through_inline_plan_sp) 232 return m_step_through_inline_plan_sp->ValidatePlan(error); 233 234 if (m_could_not_resolve_hw_bp) { 235 if (error) 236 error->PutCString( 237 "Could not create hardware breakpoint for thread plan."); 238 return false; 239 } 240 241 if (m_return_bp_id == LLDB_INVALID_BREAK_ID) { 242 if (error) 243 error->PutCString("Could not create return address breakpoint."); 244 return false; 245 } 246 247 return true; 248 } 249 250 bool ThreadPlanStepOut::DoPlanExplainsStop(Event *event_ptr) { 251 // If the step out plan is done, then we just need to step through the 252 // inlined frame. 253 if (m_step_out_to_inline_plan_sp) { 254 return m_step_out_to_inline_plan_sp->MischiefManaged(); 255 } else if (m_step_through_inline_plan_sp) { 256 if (m_step_through_inline_plan_sp->MischiefManaged()) { 257 CalculateReturnValue(); 258 SetPlanComplete(); 259 return true; 260 } else 261 return false; 262 } else if (m_step_out_further_plan_sp) { 263 return m_step_out_further_plan_sp->MischiefManaged(); 264 } 265 266 // We don't explain signals or breakpoints (breakpoints that handle stepping 267 // in or out will be handled by a child plan. 268 269 StopInfoSP stop_info_sp = GetPrivateStopInfo(); 270 if (stop_info_sp) { 271 StopReason reason = stop_info_sp->GetStopReason(); 272 if (reason == eStopReasonBreakpoint) { 273 // If this is OUR breakpoint, we're fine, otherwise we don't know why 274 // this happened... 275 BreakpointSiteSP site_sp( 276 m_thread.GetProcess()->GetBreakpointSiteList().FindByID( 277 stop_info_sp->GetValue())); 278 if (site_sp && site_sp->IsBreakpointAtThisSite(m_return_bp_id)) { 279 bool done; 280 281 StackID frame_zero_id = m_thread.GetStackFrameAtIndex(0)->GetStackID(); 282 283 if (m_step_out_to_id == frame_zero_id) 284 done = true; 285 else if (m_step_out_to_id < frame_zero_id) { 286 // Either we stepped past the breakpoint, or the stack ID calculation 287 // was incorrect and we should probably stop. 288 done = true; 289 } else { 290 done = (m_immediate_step_from_id < frame_zero_id); 291 } 292 293 if (done) { 294 if (InvokeShouldStopHereCallback(eFrameCompareOlder, m_status)) { 295 CalculateReturnValue(); 296 SetPlanComplete(); 297 } 298 } 299 300 // If there was only one owner, then we're done. But if we also hit 301 // some user breakpoint on our way out, we should mark ourselves as 302 // done, but also not claim to explain the stop, since it is more 303 // important to report the user breakpoint than the step out 304 // completion. 305 306 if (site_sp->GetNumberOfOwners() == 1) 307 return true; 308 } 309 return false; 310 } else if (IsUsuallyUnexplainedStopReason(reason)) 311 return false; 312 else 313 return true; 314 } 315 return true; 316 } 317 318 bool ThreadPlanStepOut::ShouldStop(Event *event_ptr) { 319 if (IsPlanComplete()) 320 return true; 321 322 bool done = false; 323 if (m_step_out_to_inline_plan_sp) { 324 if (m_step_out_to_inline_plan_sp->MischiefManaged()) { 325 // Now step through the inlined stack we are in: 326 if (QueueInlinedStepPlan(true)) { 327 // If we can't queue a plan to do this, then just call ourselves done. 328 m_step_out_to_inline_plan_sp.reset(); 329 SetPlanComplete(false); 330 return true; 331 } else 332 done = true; 333 } else 334 return m_step_out_to_inline_plan_sp->ShouldStop(event_ptr); 335 } else if (m_step_through_inline_plan_sp) { 336 if (m_step_through_inline_plan_sp->MischiefManaged()) 337 done = true; 338 else 339 return m_step_through_inline_plan_sp->ShouldStop(event_ptr); 340 } else if (m_step_out_further_plan_sp) { 341 if (m_step_out_further_plan_sp->MischiefManaged()) 342 m_step_out_further_plan_sp.reset(); 343 else 344 return m_step_out_further_plan_sp->ShouldStop(event_ptr); 345 } 346 347 if (!done) { 348 StackID frame_zero_id = m_thread.GetStackFrameAtIndex(0)->GetStackID(); 349 done = !(frame_zero_id < m_step_out_to_id); 350 } 351 352 // The normal step out computations think we are done, so all we need to do 353 // is consult the ShouldStopHere, and we are done. 354 355 if (done) { 356 if (InvokeShouldStopHereCallback(eFrameCompareOlder, m_status)) { 357 CalculateReturnValue(); 358 SetPlanComplete(); 359 } else { 360 m_step_out_further_plan_sp = 361 QueueStepOutFromHerePlan(m_flags, eFrameCompareOlder, m_status); 362 done = false; 363 } 364 } 365 366 return done; 367 } 368 369 bool ThreadPlanStepOut::StopOthers() { return m_stop_others; } 370 371 StateType ThreadPlanStepOut::GetPlanRunState() { return eStateRunning; } 372 373 bool ThreadPlanStepOut::DoWillResume(StateType resume_state, 374 bool current_plan) { 375 if (m_step_out_to_inline_plan_sp || m_step_through_inline_plan_sp) 376 return true; 377 378 if (m_return_bp_id == LLDB_INVALID_BREAK_ID) 379 return false; 380 381 if (current_plan) { 382 Breakpoint *return_bp = 383 m_thread.CalculateTarget()->GetBreakpointByID(m_return_bp_id).get(); 384 if (return_bp != nullptr) 385 return_bp->SetEnabled(true); 386 } 387 return true; 388 } 389 390 bool ThreadPlanStepOut::WillStop() { 391 if (m_return_bp_id != LLDB_INVALID_BREAK_ID) { 392 Breakpoint *return_bp = 393 m_thread.CalculateTarget()->GetBreakpointByID(m_return_bp_id).get(); 394 if (return_bp != nullptr) 395 return_bp->SetEnabled(false); 396 } 397 398 return true; 399 } 400 401 bool ThreadPlanStepOut::MischiefManaged() { 402 if (IsPlanComplete()) { 403 // Did I reach my breakpoint? If so I'm done. 404 // 405 // I also check the stack depth, since if we've blown past the breakpoint 406 // for some 407 // reason and we're now stopping for some other reason altogether, then 408 // we're done with this step out operation. 409 410 Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP)); 411 if (log) 412 log->Printf("Completed step out plan."); 413 if (m_return_bp_id != LLDB_INVALID_BREAK_ID) { 414 m_thread.CalculateTarget()->RemoveBreakpointByID(m_return_bp_id); 415 m_return_bp_id = LLDB_INVALID_BREAK_ID; 416 } 417 418 ThreadPlan::MischiefManaged(); 419 return true; 420 } else { 421 return false; 422 } 423 } 424 425 bool ThreadPlanStepOut::QueueInlinedStepPlan(bool queue_now) { 426 // Now figure out the range of this inlined block, and set up a "step through 427 // range" plan for that. If we've been provided with a context, then use the 428 // block in that context. 429 StackFrameSP immediate_return_from_sp(m_thread.GetStackFrameAtIndex(0)); 430 if (!immediate_return_from_sp) 431 return false; 432 433 Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP)); 434 if (log) { 435 StreamString s; 436 immediate_return_from_sp->Dump(&s, true, false); 437 log->Printf("Queuing inlined frame to step past: %s.", s.GetData()); 438 } 439 440 Block *from_block = immediate_return_from_sp->GetFrameBlock(); 441 if (from_block) { 442 Block *inlined_block = from_block->GetContainingInlinedBlock(); 443 if (inlined_block) { 444 size_t num_ranges = inlined_block->GetNumRanges(); 445 AddressRange inline_range; 446 if (inlined_block->GetRangeAtIndex(0, inline_range)) { 447 SymbolContext inlined_sc; 448 inlined_block->CalculateSymbolContext(&inlined_sc); 449 inlined_sc.target_sp = GetTarget().shared_from_this(); 450 RunMode run_mode = 451 m_stop_others ? lldb::eOnlyThisThread : lldb::eAllThreads; 452 const LazyBool avoid_no_debug = eLazyBoolNo; 453 454 m_step_through_inline_plan_sp = 455 std::make_shared<ThreadPlanStepOverRange>( 456 m_thread, inline_range, inlined_sc, run_mode, avoid_no_debug); 457 ThreadPlanStepOverRange *step_through_inline_plan_ptr = 458 static_cast<ThreadPlanStepOverRange *>( 459 m_step_through_inline_plan_sp.get()); 460 m_step_through_inline_plan_sp->SetPrivate(true); 461 462 step_through_inline_plan_ptr->SetOkayToDiscard(true); 463 StreamString errors; 464 if (!step_through_inline_plan_ptr->ValidatePlan(&errors)) { 465 // FIXME: Log this failure. 466 delete step_through_inline_plan_ptr; 467 return false; 468 } 469 470 for (size_t i = 1; i < num_ranges; i++) { 471 if (inlined_block->GetRangeAtIndex(i, inline_range)) 472 step_through_inline_plan_ptr->AddRange(inline_range); 473 } 474 475 if (queue_now) 476 m_thread.QueueThreadPlan(m_step_through_inline_plan_sp, false); 477 return true; 478 } 479 } 480 } 481 482 return false; 483 } 484 485 void ThreadPlanStepOut::CalculateReturnValue() { 486 if (m_return_valobj_sp) 487 return; 488 489 if (!m_calculate_return_value) 490 return; 491 492 if (m_immediate_step_from_function != nullptr) { 493 CompilerType return_compiler_type = 494 m_immediate_step_from_function->GetCompilerType() 495 .GetFunctionReturnType(); 496 if (return_compiler_type) { 497 lldb::ABISP abi_sp = m_thread.GetProcess()->GetABI(); 498 if (abi_sp) 499 m_return_valobj_sp = 500 abi_sp->GetReturnValueObject(m_thread, return_compiler_type); 501 } 502 } 503 } 504 505 bool ThreadPlanStepOut::IsPlanStale() { 506 // If we are still lower on the stack than the frame we are returning to, 507 // then there's something for us to do. Otherwise, we're stale. 508 509 StackID frame_zero_id = m_thread.GetStackFrameAtIndex(0)->GetStackID(); 510 return !(frame_zero_id < m_step_out_to_id); 511 } 512