949 lines · cpp
1//===-- StackFrameList.cpp ------------------------------------------------===//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-exception6//7//===----------------------------------------------------------------------===//8 9#include "lldb/Target/StackFrameList.h"10#include "lldb/Breakpoint/Breakpoint.h"11#include "lldb/Breakpoint/BreakpointLocation.h"12#include "lldb/Core/Debugger.h"13#include "lldb/Core/SourceManager.h"14#include "lldb/Host/StreamFile.h"15#include "lldb/Symbol/Block.h"16#include "lldb/Symbol/Function.h"17#include "lldb/Symbol/Symbol.h"18#include "lldb/Target/Process.h"19#include "lldb/Target/RegisterContext.h"20#include "lldb/Target/StackFrame.h"21#include "lldb/Target/StackFrameRecognizer.h"22#include "lldb/Target/StopInfo.h"23#include "lldb/Target/Target.h"24#include "lldb/Target/Thread.h"25#include "lldb/Target/Unwind.h"26#include "lldb/Utility/LLDBLog.h"27#include "lldb/Utility/Log.h"28#include "llvm/ADT/SmallPtrSet.h"29 30#include <memory>31 32//#define DEBUG_STACK_FRAMES 133 34using namespace lldb;35using namespace lldb_private;36 37// StackFrameList constructor38StackFrameList::StackFrameList(Thread &thread,39 const lldb::StackFrameListSP &prev_frames_sp,40 bool show_inline_frames)41 : m_thread(thread), m_prev_frames_sp(prev_frames_sp), m_frames(),42 m_selected_frame_idx(), m_concrete_frames_fetched(0),43 m_current_inlined_depth(UINT32_MAX),44 m_current_inlined_pc(LLDB_INVALID_ADDRESS),45 m_show_inlined_frames(show_inline_frames) {46 if (prev_frames_sp) {47 m_current_inlined_depth = prev_frames_sp->m_current_inlined_depth;48 m_current_inlined_pc = prev_frames_sp->m_current_inlined_pc;49 }50}51 52StackFrameList::~StackFrameList() {53 // Call clear since this takes a lock and clears the stack frame list in case54 // another thread is currently using this stack frame list55 Clear();56}57 58void StackFrameList::CalculateCurrentInlinedDepth() {59 uint32_t cur_inlined_depth = GetCurrentInlinedDepth();60 if (cur_inlined_depth == UINT32_MAX) {61 ResetCurrentInlinedDepth();62 }63}64 65uint32_t StackFrameList::GetCurrentInlinedDepth() {66 std::lock_guard<std::mutex> guard(m_inlined_depth_mutex);67 if (m_show_inlined_frames && m_current_inlined_pc != LLDB_INVALID_ADDRESS) {68 lldb::addr_t cur_pc = m_thread.GetRegisterContext()->GetPC();69 if (cur_pc != m_current_inlined_pc) {70 m_current_inlined_pc = LLDB_INVALID_ADDRESS;71 m_current_inlined_depth = UINT32_MAX;72 Log *log = GetLog(LLDBLog::Step);73 if (log && log->GetVerbose())74 LLDB_LOGF(75 log,76 "GetCurrentInlinedDepth: invalidating current inlined depth.\n");77 }78 return m_current_inlined_depth;79 } else {80 return UINT32_MAX;81 }82}83 84void StackFrameList::ResetCurrentInlinedDepth() {85 if (!m_show_inlined_frames)86 return;87 88 StopInfoSP stop_info_sp = m_thread.GetStopInfo();89 if (!stop_info_sp)90 return;91 92 bool inlined = true;93 auto inline_depth = stop_info_sp->GetSuggestedStackFrameIndex(inlined);94 // We're only adjusting the inlined stack here.95 Log *log = GetLog(LLDBLog::Step);96 if (inline_depth) {97 std::lock_guard<std::mutex> guard(m_inlined_depth_mutex);98 m_current_inlined_depth = *inline_depth;99 m_current_inlined_pc = m_thread.GetRegisterContext()->GetPC();100 101 if (log && log->GetVerbose())102 LLDB_LOGF(log,103 "ResetCurrentInlinedDepth: setting inlined "104 "depth: %d 0x%" PRIx64 ".\n",105 m_current_inlined_depth, m_current_inlined_pc);106 } else {107 std::lock_guard<std::mutex> guard(m_inlined_depth_mutex);108 m_current_inlined_pc = LLDB_INVALID_ADDRESS;109 m_current_inlined_depth = UINT32_MAX;110 if (log && log->GetVerbose())111 LLDB_LOGF(112 log,113 "ResetCurrentInlinedDepth: Invalidating current inlined depth.\n");114 }115}116 117bool StackFrameList::DecrementCurrentInlinedDepth() {118 if (m_show_inlined_frames) {119 uint32_t current_inlined_depth = GetCurrentInlinedDepth();120 if (current_inlined_depth != UINT32_MAX) {121 if (current_inlined_depth > 0) {122 std::lock_guard<std::mutex> guard(m_inlined_depth_mutex);123 m_current_inlined_depth--;124 return true;125 }126 }127 }128 return false;129}130 131void StackFrameList::SetCurrentInlinedDepth(uint32_t new_depth) {132 std::lock_guard<std::mutex> guard(m_inlined_depth_mutex);133 m_current_inlined_depth = new_depth;134 if (new_depth == UINT32_MAX)135 m_current_inlined_pc = LLDB_INVALID_ADDRESS;136 else137 m_current_inlined_pc = m_thread.GetRegisterContext()->GetPC();138}139 140bool StackFrameList::WereAllFramesFetched() const {141 std::shared_lock<std::shared_mutex> guard(m_list_mutex);142 return GetAllFramesFetched();143}144 145/// A sequence of calls that comprise some portion of a backtrace. Each frame146/// is represented as a pair of a callee (Function *) and an address within the147/// callee.148struct CallDescriptor {149 Function *func;150 CallEdge::AddrType address_type = CallEdge::AddrType::Call;151 addr_t address = LLDB_INVALID_ADDRESS;152};153using CallSequence = std::vector<CallDescriptor>;154 155/// Find the unique path through the call graph from \p begin (with return PC156/// \p return_pc) to \p end. On success this path is stored into \p path, and157/// on failure \p path is unchanged.158/// This function doesn't currently access StackFrameLists at all, it only looks159/// at the frame set in the ExecutionContext it passes around.160static void FindInterveningFrames(Function &begin, Function &end,161 ExecutionContext &exe_ctx, Target &target,162 addr_t return_pc, CallSequence &path,163 ModuleList &images, Log *log) {164 LLDB_LOG(log, "Finding frames between {0} and {1}, retn-pc={2:x}",165 begin.GetDisplayName(), end.GetDisplayName(), return_pc);166 167 // Find a non-tail calling edge with the correct return PC.168 if (log)169 for (const auto &edge : begin.GetCallEdges())170 LLDB_LOG(log, "FindInterveningFrames: found call with retn-PC = {0:x}",171 edge->GetReturnPCAddress(begin, target));172 CallEdge *first_edge = begin.GetCallEdgeForReturnAddress(return_pc, target);173 if (!first_edge) {174 LLDB_LOG(log, "No call edge outgoing from {0} with retn-PC == {1:x}",175 begin.GetDisplayName(), return_pc);176 return;177 }178 179 // The first callee may not be resolved, or there may be nothing to fill in.180 Function *first_callee = first_edge->GetCallee(images, exe_ctx);181 if (!first_callee) {182 LLDB_LOG(log, "Could not resolve callee");183 return;184 }185 if (first_callee == &end) {186 LLDB_LOG(log, "Not searching further, first callee is {0} (retn-PC: {1:x})",187 end.GetDisplayName(), return_pc);188 return;189 }190 191 // Run DFS on the tail-calling edges out of the first callee to find \p end.192 // Fully explore the set of functions reachable from the first edge via tail193 // calls in order to detect ambiguous executions.194 struct DFS {195 CallSequence active_path = {};196 CallSequence solution_path = {};197 llvm::SmallPtrSet<Function *, 2> visited_nodes = {};198 bool ambiguous = false;199 Function *end;200 ModuleList &images;201 Target ⌖202 ExecutionContext &context;203 204 DFS(Function *end, ModuleList &images, Target &target,205 ExecutionContext &context)206 : end(end), images(images), target(target), context(context) {}207 208 void search(CallEdge &first_edge, Function &first_callee,209 CallSequence &path) {210 dfs(first_edge, first_callee);211 if (!ambiguous)212 path = std::move(solution_path);213 }214 215 void dfs(CallEdge ¤t_edge, Function &callee) {216 // Found a path to the target function.217 if (&callee == end) {218 if (solution_path.empty())219 solution_path = active_path;220 else221 ambiguous = true;222 return;223 }224 225 // Terminate the search if tail recursion is found, or more generally if226 // there's more than one way to reach a target. This errs on the side of227 // caution: it conservatively stops searching when some solutions are228 // still possible to save time in the average case.229 if (!visited_nodes.insert(&callee).second) {230 ambiguous = true;231 return;232 }233 234 // Search the calls made from this callee.235 active_path.push_back(CallDescriptor{&callee});236 for (const auto &edge : callee.GetTailCallingEdges()) {237 Function *next_callee = edge->GetCallee(images, context);238 if (!next_callee)239 continue;240 241 std::tie(active_path.back().address_type, active_path.back().address) =242 edge->GetCallerAddress(callee, target);243 244 dfs(*edge, *next_callee);245 if (ambiguous)246 return;247 }248 active_path.pop_back();249 }250 };251 252 DFS(&end, images, target, exe_ctx).search(*first_edge, *first_callee, path);253}254 255/// Given that \p next_frame will be appended to the frame list, synthesize256/// tail call frames between the current end of the list and \p next_frame.257/// If any frames are added, adjust the frame index of \p next_frame.258///259/// --------------260/// | ... | <- Completed frames.261/// --------------262/// | prev_frame |263/// --------------264/// | ... | <- Artificial frames inserted here.265/// --------------266/// | next_frame |267/// --------------268/// | ... | <- Not-yet-visited frames.269/// --------------270void StackFrameList::SynthesizeTailCallFrames(StackFrame &next_frame) {271 // Cannot synthesize tail call frames when the stack is empty (there is no272 // "previous" frame).273 if (m_frames.empty())274 return;275 276 TargetSP target_sp = next_frame.CalculateTarget();277 if (!target_sp)278 return;279 280 lldb::RegisterContextSP next_reg_ctx_sp = next_frame.GetRegisterContext();281 if (!next_reg_ctx_sp)282 return;283 284 Log *log = GetLog(LLDBLog::Step);285 286 StackFrame &prev_frame = *m_frames.back().get();287 288 // Find the functions prev_frame and next_frame are stopped in. The function289 // objects are needed to search the lazy call graph for intervening frames.290 Function *prev_func =291 prev_frame.GetSymbolContext(eSymbolContextFunction).function;292 if (!prev_func) {293 LLDB_LOG(log, "SynthesizeTailCallFrames: can't find previous function");294 return;295 }296 Function *next_func =297 next_frame.GetSymbolContext(eSymbolContextFunction).function;298 if (!next_func) {299 LLDB_LOG(log, "SynthesizeTailCallFrames: can't find next function");300 return;301 }302 303 // Try to find the unique sequence of (tail) calls which led from next_frame304 // to prev_frame.305 CallSequence path;306 addr_t return_pc = next_reg_ctx_sp->GetPC();307 Target &target = *target_sp.get();308 ModuleList &images = next_frame.CalculateTarget()->GetImages();309 ExecutionContext exe_ctx(target_sp, /*get_process=*/true);310 exe_ctx.SetFramePtr(&next_frame);311 FindInterveningFrames(*next_func, *prev_func, exe_ctx, target, return_pc,312 path, images, log);313 314 // Push synthetic tail call frames.315 for (auto calleeInfo : llvm::reverse(path)) {316 Function *callee = calleeInfo.func;317 uint32_t frame_idx = m_frames.size();318 uint32_t concrete_frame_idx = next_frame.GetConcreteFrameIndex();319 addr_t cfa = LLDB_INVALID_ADDRESS;320 bool cfa_is_valid = false;321 addr_t pc = calleeInfo.address;322 // If the callee address refers to the call instruction, we do not want to323 // subtract 1 from this value.324 const bool artificial = true;325 const bool behaves_like_zeroth_frame =326 calleeInfo.address_type == CallEdge::AddrType::Call;327 SymbolContext sc;328 callee->CalculateSymbolContext(&sc);329 auto synth_frame = std::make_shared<StackFrame>(330 m_thread.shared_from_this(), frame_idx, concrete_frame_idx, cfa,331 cfa_is_valid, pc, StackFrame::Kind::Regular, artificial,332 behaves_like_zeroth_frame, &sc);333 m_frames.push_back(synth_frame);334 LLDB_LOG(log, "Pushed frame {0} at {1:x}", callee->GetDisplayName(), pc);335 }336 337 // If any frames were created, adjust next_frame's index.338 if (!path.empty())339 next_frame.SetFrameIndex(m_frames.size());340}341 342bool StackFrameList::GetFramesUpTo(uint32_t end_idx,343 InterruptionControl allow_interrupt) {344 // GetFramesUpTo is always called with the intent to add frames, so get the345 // writer lock:346 std::unique_lock<std::shared_mutex> guard(m_list_mutex);347 // Now that we have the lock, check to make sure someone didn't get there348 // ahead of us:349 if (m_frames.size() > end_idx || GetAllFramesFetched())350 return false;351 352 // Do not fetch frames for an invalid thread.353 bool was_interrupted = false;354 if (!m_thread.IsValid())355 return false;356 357 // lock the writer side of m_list_mutex as we're going to add frames here:358 if (!m_show_inlined_frames) {359 if (end_idx < m_concrete_frames_fetched)360 return false;361 // We're adding concrete frames now:362 // FIXME: This should also be interruptible:363 FetchOnlyConcreteFramesUpTo(end_idx);364 return false;365 }366 367 // We're adding concrete and inlined frames now:368 was_interrupted = FetchFramesUpTo(end_idx, allow_interrupt);369 370#if defined(DEBUG_STACK_FRAMES)371 s.PutCString("\n\nNew frames:\n");372 Dump(&s);373 s.EOL();374#endif375 return was_interrupted;376}377 378void StackFrameList::FetchOnlyConcreteFramesUpTo(uint32_t end_idx) {379 assert(m_thread.IsValid() && "Expected valid thread");380 assert(m_frames.size() <= end_idx && "Expected there to be frames to fill");381 382 Unwind &unwinder = m_thread.GetUnwinder();383 384 if (end_idx < m_concrete_frames_fetched)385 return;386 387 uint32_t num_frames = unwinder.GetFramesUpTo(end_idx);388 if (num_frames <= end_idx + 1) {389 // Done unwinding.390 m_concrete_frames_fetched = UINT32_MAX;391 }392 393 // Don't create the frames eagerly. Defer this work to GetFrameAtIndex,394 // which can lazily query the unwinder to create frames.395 m_frames.resize(num_frames);396}397 398bool StackFrameList::FetchFramesUpTo(uint32_t end_idx,399 InterruptionControl allow_interrupt) {400 Unwind &unwinder = m_thread.GetUnwinder();401 bool was_interrupted = false;402 403#if defined(DEBUG_STACK_FRAMES)404 StreamFile s(stdout, false);405#endif406 // If we are hiding some frames from the outside world, we need to add407 // those onto the total count of frames to fetch. However, we don't need408 // to do that if end_idx is 0 since in that case we always get the first409 // concrete frame and all the inlined frames below it... And of course, if410 // end_idx is UINT32_MAX that means get all, so just do that...411 412 uint32_t inlined_depth = 0;413 if (end_idx > 0 && end_idx != UINT32_MAX) {414 inlined_depth = GetCurrentInlinedDepth();415 if (inlined_depth != UINT32_MAX) {416 if (end_idx > 0)417 end_idx += inlined_depth;418 }419 }420 421 StackFrameSP unwind_frame_sp;422 Debugger &dbg = m_thread.GetProcess()->GetTarget().GetDebugger();423 do {424 uint32_t idx = m_concrete_frames_fetched++;425 lldb::addr_t pc = LLDB_INVALID_ADDRESS;426 lldb::addr_t cfa = LLDB_INVALID_ADDRESS;427 bool behaves_like_zeroth_frame = (idx == 0);428 if (idx == 0) {429 // We might have already created frame zero, only create it if we need430 // to.431 if (m_frames.empty()) {432 RegisterContextSP reg_ctx_sp(m_thread.GetRegisterContext());433 434 if (reg_ctx_sp) {435 const bool success = unwinder.GetFrameInfoAtIndex(436 idx, cfa, pc, behaves_like_zeroth_frame);437 // There shouldn't be any way not to get the frame info for frame438 // 0. But if the unwinder can't make one, lets make one by hand439 // with the SP as the CFA and see if that gets any further.440 if (!success) {441 cfa = reg_ctx_sp->GetSP();442 pc = reg_ctx_sp->GetPC();443 }444 445 unwind_frame_sp = std::make_shared<StackFrame>(446 m_thread.shared_from_this(), m_frames.size(), idx, reg_ctx_sp,447 cfa, pc, behaves_like_zeroth_frame, nullptr);448 m_frames.push_back(unwind_frame_sp);449 }450 } else {451 unwind_frame_sp = m_frames.front();452 cfa = unwind_frame_sp->m_id.GetCallFrameAddressWithoutMetadata();453 }454 } else {455 // Check for interruption when building the frames.456 // Do the check in idx > 0 so that we'll always create a 0th frame.457 if (allow_interrupt &&458 INTERRUPT_REQUESTED(dbg, "Interrupted having fetched {0} frames",459 m_frames.size())) {460 was_interrupted = true;461 break;462 }463 464 const bool success =465 unwinder.GetFrameInfoAtIndex(idx, cfa, pc, behaves_like_zeroth_frame);466 if (!success) {467 // We've gotten to the end of the stack.468 SetAllFramesFetched();469 break;470 }471 const bool cfa_is_valid = true;472 unwind_frame_sp = std::make_shared<StackFrame>(473 m_thread.shared_from_this(), m_frames.size(), idx, cfa, cfa_is_valid,474 pc, StackFrame::Kind::Regular, false, behaves_like_zeroth_frame,475 nullptr);476 477 // Create synthetic tail call frames between the previous frame and the478 // newly-found frame. The new frame's index may change after this call,479 // although its concrete index will stay the same.480 SynthesizeTailCallFrames(*unwind_frame_sp.get());481 482 m_frames.push_back(unwind_frame_sp);483 }484 485 assert(unwind_frame_sp);486 SymbolContext unwind_sc = unwind_frame_sp->GetSymbolContext(487 eSymbolContextBlock | eSymbolContextFunction);488 Block *unwind_block = unwind_sc.block;489 TargetSP target_sp = m_thread.CalculateTarget();490 if (unwind_block) {491 Address curr_frame_address(492 unwind_frame_sp->GetFrameCodeAddressForSymbolication());493 494 SymbolContext next_frame_sc;495 Address next_frame_address;496 497 while (unwind_sc.GetParentOfInlinedScope(498 curr_frame_address, next_frame_sc, next_frame_address)) {499 next_frame_sc.line_entry.ApplyFileMappings(target_sp);500 behaves_like_zeroth_frame = false;501 StackFrameSP frame_sp(new StackFrame(502 m_thread.shared_from_this(), m_frames.size(), idx,503 unwind_frame_sp->GetRegisterContextSP(), cfa, next_frame_address,504 behaves_like_zeroth_frame, &next_frame_sc));505 506 m_frames.push_back(frame_sp);507 unwind_sc = next_frame_sc;508 curr_frame_address = next_frame_address;509 }510 }511 } while (m_frames.size() - 1 < end_idx);512 513 // Don't try to merge till you've calculated all the frames in this stack.514 if (GetAllFramesFetched() && m_prev_frames_sp) {515 StackFrameList *prev_frames = m_prev_frames_sp.get();516 StackFrameList *curr_frames = this;517 518#if defined(DEBUG_STACK_FRAMES)519 s.PutCString("\nprev_frames:\n");520 prev_frames->Dump(&s);521 s.PutCString("\ncurr_frames:\n");522 curr_frames->Dump(&s);523 s.EOL();524#endif525 size_t curr_frame_num, prev_frame_num;526 527 for (curr_frame_num = curr_frames->m_frames.size(),528 prev_frame_num = prev_frames->m_frames.size();529 curr_frame_num > 0 && prev_frame_num > 0;530 --curr_frame_num, --prev_frame_num) {531 const size_t curr_frame_idx = curr_frame_num - 1;532 const size_t prev_frame_idx = prev_frame_num - 1;533 StackFrameSP curr_frame_sp(curr_frames->m_frames[curr_frame_idx]);534 StackFrameSP prev_frame_sp(prev_frames->m_frames[prev_frame_idx]);535 536#if defined(DEBUG_STACK_FRAMES)537 s.Printf("\n\nCurr frame #%u ", curr_frame_idx);538 if (curr_frame_sp)539 curr_frame_sp->Dump(&s, true, false);540 else541 s.PutCString("NULL");542 s.Printf("\nPrev frame #%u ", prev_frame_idx);543 if (prev_frame_sp)544 prev_frame_sp->Dump(&s, true, false);545 else546 s.PutCString("NULL");547#endif548 549 StackFrame *curr_frame = curr_frame_sp.get();550 StackFrame *prev_frame = prev_frame_sp.get();551 552 if (curr_frame == nullptr || prev_frame == nullptr)553 break;554 555 // Check the stack ID to make sure they are equal.556 if (curr_frame->GetStackID() != prev_frame->GetStackID())557 break;558 559 prev_frame->UpdatePreviousFrameFromCurrentFrame(*curr_frame);560 // Now copy the fixed up previous frame into the current frames so the561 // pointer doesn't change.562 m_frames[curr_frame_idx] = prev_frame_sp;563 564#if defined(DEBUG_STACK_FRAMES)565 s.Printf("\n Copying previous frame to current frame");566#endif567 }568 // We are done with the old stack frame list, we can release it now.569 m_prev_frames_sp.reset();570 }571 // Don't report interrupted if we happen to have gotten all the frames:572 if (!GetAllFramesFetched())573 return was_interrupted;574 return false;575}576 577uint32_t StackFrameList::GetNumFrames(bool can_create) {578 if (!WereAllFramesFetched() && can_create) {579 // Don't allow interrupt or we might not return the correct count580 GetFramesUpTo(UINT32_MAX, DoNotAllowInterruption);581 }582 uint32_t frame_idx;583 {584 std::shared_lock<std::shared_mutex> guard(m_list_mutex);585 frame_idx = GetVisibleStackFrameIndex(m_frames.size());586 }587 return frame_idx;588}589 590void StackFrameList::Dump(Stream *s) {591 if (s == nullptr)592 return;593 594 std::shared_lock<std::shared_mutex> guard(m_list_mutex);595 596 const_iterator pos, begin = m_frames.begin(), end = m_frames.end();597 for (pos = begin; pos != end; ++pos) {598 StackFrame *frame = (*pos).get();599 s->Printf("%p: ", static_cast<void *>(frame));600 if (frame) {601 frame->GetStackID().Dump(s);602 frame->DumpUsingSettingsFormat(s);603 } else604 s->Printf("frame #%u", (uint32_t)std::distance(begin, pos));605 s->EOL();606 }607 s->EOL();608}609 610StackFrameSP StackFrameList::GetFrameAtIndex(uint32_t idx) {611 StackFrameSP frame_sp;612 uint32_t original_idx = idx;613 614 // We're going to consult the m_frames.size, but if there are already615 // enough frames for our request we don't want to block other readers, so616 // first acquire the shared lock:617 { // Scope for shared lock:618 std::shared_lock<std::shared_mutex> guard(m_list_mutex);619 620 uint32_t inlined_depth = GetCurrentInlinedDepth();621 if (inlined_depth != UINT32_MAX)622 idx += inlined_depth;623 624 if (idx < m_frames.size())625 frame_sp = m_frames[idx];626 627 if (frame_sp)628 return frame_sp;629 } // End of reader lock scope630 631 // GetFramesUpTo will fill m_frames with as many frames as you asked for, if632 // there are that many. If there weren't then you asked for too many frames.633 // GetFramesUpTo returns true if interrupted:634 if (GetFramesUpTo(idx, AllowInterruption)) {635 Log *log = GetLog(LLDBLog::Thread);636 LLDB_LOG(log, "GetFrameAtIndex was interrupted");637 return {};638 }639 640 { // Now we're accessing m_frames as a reader, so acquire the reader lock.641 std::shared_lock<std::shared_mutex> guard(m_list_mutex);642 if (idx < m_frames.size()) {643 frame_sp = m_frames[idx];644 } else if (original_idx == 0) {645 // There should ALWAYS be a frame at index 0. If something went wrong646 // with the CurrentInlinedDepth such that there weren't as many frames as647 // we thought taking that into account, then reset the current inlined648 // depth and return the real zeroth frame.649 if (m_frames.empty()) {650 // Why do we have a thread with zero frames, that should not ever651 // happen...652 assert(!m_thread.IsValid() && "A valid thread has no frames.");653 } else {654 ResetCurrentInlinedDepth();655 frame_sp = m_frames[original_idx];656 }657 }658 } // End of reader lock scope659 660 return frame_sp;661}662 663StackFrameSP664StackFrameList::GetFrameWithConcreteFrameIndex(uint32_t unwind_idx) {665 // First try assuming the unwind index is the same as the frame index. The666 // unwind index is always greater than or equal to the frame index, so it is667 // a good place to start. If we have inlined frames we might have 5 concrete668 // frames (frame unwind indexes go from 0-4), but we might have 15 frames669 // after we make all the inlined frames. Most of the time the unwind frame670 // index (or the concrete frame index) is the same as the frame index.671 uint32_t frame_idx = unwind_idx;672 StackFrameSP frame_sp(GetFrameAtIndex(frame_idx));673 while (frame_sp) {674 if (frame_sp->GetFrameIndex() == unwind_idx)675 break;676 frame_sp = GetFrameAtIndex(++frame_idx);677 }678 return frame_sp;679}680 681static bool CompareStackID(const StackFrameSP &stack_sp,682 const StackID &stack_id) {683 return stack_sp->GetStackID() < stack_id;684}685 686StackFrameSP StackFrameList::GetFrameWithStackID(const StackID &stack_id) {687 StackFrameSP frame_sp;688 689 if (stack_id.IsValid()) {690 uint32_t frame_idx = 0;691 {692 // First see if the frame is already realized. This is the scope for693 // the shared mutex:694 std::shared_lock<std::shared_mutex> guard(m_list_mutex);695 // Do a binary search in case the stack frame is already in our cache696 collection::const_iterator pos =697 llvm::lower_bound(m_frames, stack_id, CompareStackID);698 if (pos != m_frames.end() && (*pos)->GetStackID() == stack_id)699 return *pos;700 }701 // If we needed to add more frames, we would get to here.702 do {703 frame_sp = GetFrameAtIndex(frame_idx);704 if (frame_sp && frame_sp->GetStackID() == stack_id)705 break;706 frame_idx++;707 } while (frame_sp);708 }709 return frame_sp;710}711 712bool StackFrameList::SetFrameAtIndex(uint32_t idx, StackFrameSP &frame_sp) {713 std::unique_lock<std::shared_mutex> guard(m_list_mutex);714 if (idx >= m_frames.size())715 m_frames.resize(idx + 1);716 // Make sure allocation succeeded by checking bounds again717 if (idx < m_frames.size()) {718 m_frames[idx] = frame_sp;719 return true;720 }721 return false; // resize failed, out of memory?722}723 724void StackFrameList::SelectMostRelevantFrame() {725 // Don't call into the frame recognizers on the private state thread as726 // they can cause code to run in the target, and that can cause deadlocks727 // when fetching stop events for the expression.728 if (m_thread.GetProcess()->CurrentThreadPosesAsPrivateStateThread())729 return;730 731 Log *log = GetLog(LLDBLog::Thread);732 733 // Only the top frame should be recognized.734 StackFrameSP frame_sp = GetFrameAtIndex(0);735 if (!frame_sp) {736 LLDB_LOG(log, "Failed to construct Frame #0");737 return;738 }739 740 RecognizedStackFrameSP recognized_frame_sp = frame_sp->GetRecognizedFrame();741 742 if (recognized_frame_sp) {743 if (StackFrameSP most_relevant_frame_sp =744 recognized_frame_sp->GetMostRelevantFrame()) {745 LLDB_LOG(log, "Found most relevant frame at index {0}",746 most_relevant_frame_sp->GetFrameIndex());747 SetSelectedFrame(most_relevant_frame_sp.get());748 return;749 }750 }751 LLDB_LOG(log, "Frame #0 not recognized");752 753 // If this thread has a non-trivial StopInfo, then let it suggest754 // a most relevant frame:755 StopInfoSP stop_info_sp = m_thread.GetStopInfo();756 uint32_t stack_idx = 0;757 bool found_relevant = false;758 if (stop_info_sp) {759 // Here we're only asking the stop info if it wants to adjust the real stack760 // index. We have to ask about the m_inlined_stack_depth in761 // Thread::ShouldStop since the plans need to reason with that info.762 bool inlined = false;763 std::optional<uint32_t> stack_opt =764 stop_info_sp->GetSuggestedStackFrameIndex(inlined);765 if (stack_opt) {766 stack_idx = *stack_opt;767 found_relevant = true;768 }769 }770 771 frame_sp = GetFrameAtIndex(stack_idx);772 if (!frame_sp)773 LLDB_LOG(log, "Stop info suggested relevant frame {0} but it didn't exist",774 stack_idx);775 else if (found_relevant)776 LLDB_LOG(log, "Setting selected frame from stop info to {0}", stack_idx);777 // Note, we don't have to worry about "inlined" frames here, because we've778 // already calculated the inlined frame in Thread::ShouldStop, and779 // SetSelectedFrame will take care of that adjustment for us.780 SetSelectedFrame(frame_sp.get());781 782 if (!found_relevant)783 LLDB_LOG(log, "No relevant frame!");784}785 786uint32_t787StackFrameList::GetSelectedFrameIndex(SelectMostRelevant select_most_relevant) {788 std::lock_guard<std::recursive_mutex> guard(m_selected_frame_mutex);789 790 if (!m_selected_frame_idx && select_most_relevant)791 SelectMostRelevantFrame();792 if (!m_selected_frame_idx) {793 // If we aren't selecting the most relevant frame, and the selected frame794 // isn't set, then don't force a selection here, just return 0.795 if (!select_most_relevant)796 return 0;797 // If the inlined stack frame is set, then use that:798 m_selected_frame_idx = 0;799 }800 return *m_selected_frame_idx;801}802 803uint32_t StackFrameList::SetSelectedFrame(lldb_private::StackFrame *frame) {804 std::shared_lock<std::shared_mutex> guard(m_list_mutex);805 std::lock_guard<std::recursive_mutex> selected_frame_guard(806 m_selected_frame_mutex);807 808 const_iterator pos;809 const_iterator begin = m_frames.begin();810 const_iterator end = m_frames.end();811 m_selected_frame_idx = 0;812 813 for (pos = begin; pos != end; ++pos) {814 if (pos->get() == frame) {815 m_selected_frame_idx = std::distance(begin, pos);816 uint32_t inlined_depth = GetCurrentInlinedDepth();817 if (inlined_depth != UINT32_MAX)818 m_selected_frame_idx = *m_selected_frame_idx - inlined_depth;819 break;820 }821 }822 SetDefaultFileAndLineToSelectedFrame();823 return *m_selected_frame_idx;824}825 826bool StackFrameList::SetSelectedFrameByIndex(uint32_t idx) {827 StackFrameSP frame_sp(GetFrameAtIndex(idx));828 if (frame_sp) {829 SetSelectedFrame(frame_sp.get());830 return true;831 } else832 return false;833}834 835void StackFrameList::SetDefaultFileAndLineToSelectedFrame() {836 if (m_thread.GetID() ==837 m_thread.GetProcess()->GetThreadList().GetSelectedThread()->GetID()) {838 StackFrameSP frame_sp(839 GetFrameAtIndex(GetSelectedFrameIndex(DoNoSelectMostRelevantFrame)));840 if (frame_sp) {841 SymbolContext sc = frame_sp->GetSymbolContext(eSymbolContextLineEntry);842 if (sc.line_entry.GetFile())843 m_thread.CalculateTarget()->GetSourceManager().SetDefaultFileAndLine(844 sc.line_entry.file_sp, sc.line_entry.line);845 }846 }847}848 849// The thread has been run, reset the number stack frames to zero so we can850// determine how many frames we have lazily.851// Note, we don't actually re-use StackFrameLists, we always make a new852// StackFrameList every time we stop, and then copy frame information frame853// by frame from the old to the new StackFrameList. So the comment above,854// does not describe how StackFrameLists are currently used.855// Clear is currently only used to clear the list in the destructor.856void StackFrameList::Clear() {857 std::unique_lock<std::shared_mutex> guard(m_list_mutex);858 m_frames.clear();859 m_concrete_frames_fetched = 0;860 std::lock_guard<std::recursive_mutex> selected_frame_guard(861 m_selected_frame_mutex);862 m_selected_frame_idx.reset();863}864 865lldb::StackFrameSP866StackFrameList::GetStackFrameSPForStackFramePtr(StackFrame *stack_frame_ptr) {867 std::shared_lock<std::shared_mutex> guard(m_list_mutex);868 const_iterator pos;869 const_iterator begin = m_frames.begin();870 const_iterator end = m_frames.end();871 lldb::StackFrameSP ret_sp;872 873 for (pos = begin; pos != end; ++pos) {874 if (pos->get() == stack_frame_ptr) {875 ret_sp = (*pos);876 break;877 }878 }879 return ret_sp;880}881 882size_t StackFrameList::GetStatus(Stream &strm, uint32_t first_frame,883 uint32_t num_frames, bool show_frame_info,884 uint32_t num_frames_with_source,885 bool show_unique, bool show_hidden,886 const char *selected_frame_marker) {887 size_t num_frames_displayed = 0;888 889 if (num_frames == 0)890 return 0;891 892 StackFrameSP frame_sp;893 uint32_t frame_idx = 0;894 uint32_t last_frame;895 896 // Don't let the last frame wrap around...897 if (num_frames == UINT32_MAX)898 last_frame = UINT32_MAX;899 else900 last_frame = first_frame + num_frames;901 902 StackFrameSP selected_frame_sp =903 m_thread.GetSelectedFrame(DoNoSelectMostRelevantFrame);904 const char *unselected_marker = nullptr;905 std::string buffer;906 if (selected_frame_marker) {907 size_t len = strlen(selected_frame_marker);908 buffer.insert(buffer.begin(), len, ' ');909 unselected_marker = buffer.c_str();910 }911 const char *marker = nullptr;912 for (frame_idx = first_frame; frame_idx < last_frame; ++frame_idx) {913 frame_sp = GetFrameAtIndex(frame_idx);914 if (!frame_sp)915 break;916 917 if (selected_frame_marker != nullptr) {918 if (frame_sp == selected_frame_sp)919 marker = selected_frame_marker;920 else921 marker = unselected_marker;922 }923 924 // Hide uninteresting frames unless it's the selected frame.925 if (!show_hidden && frame_sp != selected_frame_sp && frame_sp->IsHidden())926 continue;927 928 // Check for interruption here. If we're fetching arguments, this loop929 // can go slowly:930 Debugger &dbg = m_thread.GetProcess()->GetTarget().GetDebugger();931 if (INTERRUPT_REQUESTED(932 dbg, "Interrupted dumping stack for thread {0:x} with {1} shown.",933 m_thread.GetID(), num_frames_displayed))934 break;935 936 937 if (!frame_sp->GetStatus(strm, show_frame_info,938 num_frames_with_source > (first_frame - frame_idx),939 show_unique, marker))940 break;941 ++num_frames_displayed;942 }943 944 strm.IndentLess();945 return num_frames_displayed;946}947 948void StackFrameList::ClearSelectedFrameIndex() { m_selected_frame_idx.reset(); }949