brintos

brintos / llvm-project-archived public Read only

0
0
Text · 32.8 KiB · ccf874f Raw
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 &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 &current_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