15ffd83dbSDimitry Andric //===-- StackFrameList.cpp ------------------------------------------------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric 
90b57cec5SDimitry Andric #include "lldb/Target/StackFrameList.h"
100b57cec5SDimitry Andric #include "lldb/Breakpoint/Breakpoint.h"
110b57cec5SDimitry Andric #include "lldb/Breakpoint/BreakpointLocation.h"
12fe013be4SDimitry Andric #include "lldb/Core/Debugger.h"
130b57cec5SDimitry Andric #include "lldb/Core/SourceManager.h"
14*c9157d92SDimitry Andric #include "lldb/Host/StreamFile.h"
150b57cec5SDimitry Andric #include "lldb/Symbol/Block.h"
160b57cec5SDimitry Andric #include "lldb/Symbol/Function.h"
170b57cec5SDimitry Andric #include "lldb/Symbol/Symbol.h"
180b57cec5SDimitry Andric #include "lldb/Target/Process.h"
190b57cec5SDimitry Andric #include "lldb/Target/RegisterContext.h"
200b57cec5SDimitry Andric #include "lldb/Target/StackFrame.h"
21fe013be4SDimitry Andric #include "lldb/Target/StackFrameRecognizer.h"
220b57cec5SDimitry Andric #include "lldb/Target/StopInfo.h"
230b57cec5SDimitry Andric #include "lldb/Target/Target.h"
240b57cec5SDimitry Andric #include "lldb/Target/Thread.h"
250b57cec5SDimitry Andric #include "lldb/Target/Unwind.h"
2681ad6265SDimitry Andric #include "lldb/Utility/LLDBLog.h"
270b57cec5SDimitry Andric #include "lldb/Utility/Log.h"
280b57cec5SDimitry Andric #include "llvm/ADT/SmallPtrSet.h"
290b57cec5SDimitry Andric 
300b57cec5SDimitry Andric #include <memory>
310b57cec5SDimitry Andric 
320b57cec5SDimitry Andric //#define DEBUG_STACK_FRAMES 1
330b57cec5SDimitry Andric 
340b57cec5SDimitry Andric using namespace lldb;
350b57cec5SDimitry Andric using namespace lldb_private;
360b57cec5SDimitry Andric 
370b57cec5SDimitry Andric // StackFrameList constructor
StackFrameList(Thread & thread,const lldb::StackFrameListSP & prev_frames_sp,bool show_inline_frames)380b57cec5SDimitry Andric StackFrameList::StackFrameList(Thread &thread,
390b57cec5SDimitry Andric                                const lldb::StackFrameListSP &prev_frames_sp,
400b57cec5SDimitry Andric                                bool show_inline_frames)
410b57cec5SDimitry Andric     : m_thread(thread), m_prev_frames_sp(prev_frames_sp), m_mutex(), m_frames(),
42fe013be4SDimitry Andric       m_selected_frame_idx(), m_concrete_frames_fetched(0),
430b57cec5SDimitry Andric       m_current_inlined_depth(UINT32_MAX),
440b57cec5SDimitry Andric       m_current_inlined_pc(LLDB_INVALID_ADDRESS),
450b57cec5SDimitry Andric       m_show_inlined_frames(show_inline_frames) {
460b57cec5SDimitry Andric   if (prev_frames_sp) {
470b57cec5SDimitry Andric     m_current_inlined_depth = prev_frames_sp->m_current_inlined_depth;
480b57cec5SDimitry Andric     m_current_inlined_pc = prev_frames_sp->m_current_inlined_pc;
490b57cec5SDimitry Andric   }
500b57cec5SDimitry Andric }
510b57cec5SDimitry Andric 
~StackFrameList()520b57cec5SDimitry Andric StackFrameList::~StackFrameList() {
530b57cec5SDimitry Andric   // Call clear since this takes a lock and clears the stack frame list in case
540b57cec5SDimitry Andric   // another thread is currently using this stack frame list
550b57cec5SDimitry Andric   Clear();
560b57cec5SDimitry Andric }
570b57cec5SDimitry Andric 
CalculateCurrentInlinedDepth()580b57cec5SDimitry Andric void StackFrameList::CalculateCurrentInlinedDepth() {
590b57cec5SDimitry Andric   uint32_t cur_inlined_depth = GetCurrentInlinedDepth();
600b57cec5SDimitry Andric   if (cur_inlined_depth == UINT32_MAX) {
610b57cec5SDimitry Andric     ResetCurrentInlinedDepth();
620b57cec5SDimitry Andric   }
630b57cec5SDimitry Andric }
640b57cec5SDimitry Andric 
GetCurrentInlinedDepth()650b57cec5SDimitry Andric uint32_t StackFrameList::GetCurrentInlinedDepth() {
660b57cec5SDimitry Andric   if (m_show_inlined_frames && m_current_inlined_pc != LLDB_INVALID_ADDRESS) {
670b57cec5SDimitry Andric     lldb::addr_t cur_pc = m_thread.GetRegisterContext()->GetPC();
680b57cec5SDimitry Andric     if (cur_pc != m_current_inlined_pc) {
690b57cec5SDimitry Andric       m_current_inlined_pc = LLDB_INVALID_ADDRESS;
700b57cec5SDimitry Andric       m_current_inlined_depth = UINT32_MAX;
7181ad6265SDimitry Andric       Log *log = GetLog(LLDBLog::Step);
720b57cec5SDimitry Andric       if (log && log->GetVerbose())
739dba64beSDimitry Andric         LLDB_LOGF(
749dba64beSDimitry Andric             log,
750b57cec5SDimitry Andric             "GetCurrentInlinedDepth: invalidating current inlined depth.\n");
760b57cec5SDimitry Andric     }
770b57cec5SDimitry Andric     return m_current_inlined_depth;
780b57cec5SDimitry Andric   } else {
790b57cec5SDimitry Andric     return UINT32_MAX;
800b57cec5SDimitry Andric   }
810b57cec5SDimitry Andric }
820b57cec5SDimitry Andric 
ResetCurrentInlinedDepth()830b57cec5SDimitry Andric void StackFrameList::ResetCurrentInlinedDepth() {
840b57cec5SDimitry Andric   if (!m_show_inlined_frames)
850b57cec5SDimitry Andric     return;
860b57cec5SDimitry Andric 
870b57cec5SDimitry Andric   std::lock_guard<std::recursive_mutex> guard(m_mutex);
880b57cec5SDimitry Andric 
89fe013be4SDimitry Andric   GetFramesUpTo(0, DoNotAllowInterruption);
900b57cec5SDimitry Andric   if (m_frames.empty())
910b57cec5SDimitry Andric     return;
920b57cec5SDimitry Andric   if (!m_frames[0]->IsInlined()) {
930b57cec5SDimitry Andric     m_current_inlined_depth = UINT32_MAX;
940b57cec5SDimitry Andric     m_current_inlined_pc = LLDB_INVALID_ADDRESS;
9581ad6265SDimitry Andric     Log *log = GetLog(LLDBLog::Step);
960b57cec5SDimitry Andric     if (log && log->GetVerbose())
979dba64beSDimitry Andric       LLDB_LOGF(
989dba64beSDimitry Andric           log,
990b57cec5SDimitry Andric           "ResetCurrentInlinedDepth: Invalidating current inlined depth.\n");
1000b57cec5SDimitry Andric     return;
1010b57cec5SDimitry Andric   }
1020b57cec5SDimitry Andric 
1030b57cec5SDimitry Andric   // We only need to do something special about inlined blocks when we are
1040b57cec5SDimitry Andric   // at the beginning of an inlined function:
1050b57cec5SDimitry Andric   // FIXME: We probably also have to do something special if the PC is at
1060b57cec5SDimitry Andric   // the END of an inlined function, which coincides with the end of either
1070b57cec5SDimitry Andric   // its containing function or another inlined function.
1080b57cec5SDimitry Andric 
1090b57cec5SDimitry Andric   Block *block_ptr = m_frames[0]->GetFrameBlock();
1100b57cec5SDimitry Andric   if (!block_ptr)
1110b57cec5SDimitry Andric     return;
1120b57cec5SDimitry Andric 
1130b57cec5SDimitry Andric   Address pc_as_address;
1140b57cec5SDimitry Andric   lldb::addr_t curr_pc = m_thread.GetRegisterContext()->GetPC();
1150b57cec5SDimitry Andric   pc_as_address.SetLoadAddress(curr_pc, &(m_thread.GetProcess()->GetTarget()));
1160b57cec5SDimitry Andric   AddressRange containing_range;
1170b57cec5SDimitry Andric   if (!block_ptr->GetRangeContainingAddress(pc_as_address, containing_range) ||
1180b57cec5SDimitry Andric       pc_as_address != containing_range.GetBaseAddress())
1190b57cec5SDimitry Andric     return;
1200b57cec5SDimitry Andric 
1210b57cec5SDimitry Andric   // If we got here because of a breakpoint hit, then set the inlined depth
1220b57cec5SDimitry Andric   // depending on where the breakpoint was set. If we got here because of a
1230b57cec5SDimitry Andric   // crash, then set the inlined depth to the deepest most block.  Otherwise,
1240b57cec5SDimitry Andric   // we stopped here naturally as the result of a step, so set ourselves in the
1250b57cec5SDimitry Andric   // containing frame of the whole set of nested inlines, so the user can then
1260b57cec5SDimitry Andric   // "virtually" step into the frames one by one, or next over the whole mess.
1270b57cec5SDimitry Andric   // Note: We don't have to handle being somewhere in the middle of the stack
1280b57cec5SDimitry Andric   // here, since ResetCurrentInlinedDepth doesn't get called if there is a
1290b57cec5SDimitry Andric   // valid inlined depth set.
1300b57cec5SDimitry Andric   StopInfoSP stop_info_sp = m_thread.GetStopInfo();
1310b57cec5SDimitry Andric   if (!stop_info_sp)
1320b57cec5SDimitry Andric     return;
1330b57cec5SDimitry Andric   switch (stop_info_sp->GetStopReason()) {
1340b57cec5SDimitry Andric   case eStopReasonWatchpoint:
1350b57cec5SDimitry Andric   case eStopReasonException:
1360b57cec5SDimitry Andric   case eStopReasonExec:
137fe6060f1SDimitry Andric   case eStopReasonFork:
138fe6060f1SDimitry Andric   case eStopReasonVFork:
139fe6060f1SDimitry Andric   case eStopReasonVForkDone:
1400b57cec5SDimitry Andric   case eStopReasonSignal:
1410b57cec5SDimitry Andric     // In all these cases we want to stop in the deepest frame.
1420b57cec5SDimitry Andric     m_current_inlined_pc = curr_pc;
1430b57cec5SDimitry Andric     m_current_inlined_depth = 0;
1440b57cec5SDimitry Andric     break;
1450b57cec5SDimitry Andric   case eStopReasonBreakpoint: {
1460b57cec5SDimitry Andric     // FIXME: Figure out what this break point is doing, and set the inline
1470b57cec5SDimitry Andric     // depth appropriately.  Be careful to take into account breakpoints that
1480b57cec5SDimitry Andric     // implement step over prologue, since that should do the default
1490b57cec5SDimitry Andric     // calculation. For now, if the breakpoints corresponding to this hit are
1500b57cec5SDimitry Andric     // all internal, I set the stop location to the top of the inlined stack,
1510b57cec5SDimitry Andric     // since that will make things like stepping over prologues work right.
1520b57cec5SDimitry Andric     // But if there are any non-internal breakpoints I do to the bottom of the
1530b57cec5SDimitry Andric     // stack, since that was the old behavior.
1540b57cec5SDimitry Andric     uint32_t bp_site_id = stop_info_sp->GetValue();
1550b57cec5SDimitry Andric     BreakpointSiteSP bp_site_sp(
1560b57cec5SDimitry Andric         m_thread.GetProcess()->GetBreakpointSiteList().FindByID(bp_site_id));
1570b57cec5SDimitry Andric     bool all_internal = true;
1580b57cec5SDimitry Andric     if (bp_site_sp) {
159*c9157d92SDimitry Andric       uint32_t num_owners = bp_site_sp->GetNumberOfConstituents();
1600b57cec5SDimitry Andric       for (uint32_t i = 0; i < num_owners; i++) {
161*c9157d92SDimitry Andric         Breakpoint &bp_ref =
162*c9157d92SDimitry Andric             bp_site_sp->GetConstituentAtIndex(i)->GetBreakpoint();
1630b57cec5SDimitry Andric         if (!bp_ref.IsInternal()) {
1640b57cec5SDimitry Andric           all_internal = false;
1650b57cec5SDimitry Andric         }
1660b57cec5SDimitry Andric       }
1670b57cec5SDimitry Andric     }
1680b57cec5SDimitry Andric     if (!all_internal) {
1690b57cec5SDimitry Andric       m_current_inlined_pc = curr_pc;
1700b57cec5SDimitry Andric       m_current_inlined_depth = 0;
1710b57cec5SDimitry Andric       break;
1720b57cec5SDimitry Andric     }
1730b57cec5SDimitry Andric   }
174bdd1243dSDimitry Andric     [[fallthrough]];
1750b57cec5SDimitry Andric   default: {
1760b57cec5SDimitry Andric     // Otherwise, we should set ourselves at the container of the inlining, so
1770b57cec5SDimitry Andric     // that the user can descend into them. So first we check whether we have
1780b57cec5SDimitry Andric     // more than one inlined block sharing this PC:
1790b57cec5SDimitry Andric     int num_inlined_functions = 0;
1800b57cec5SDimitry Andric 
1810b57cec5SDimitry Andric     for (Block *container_ptr = block_ptr->GetInlinedParent();
1820b57cec5SDimitry Andric          container_ptr != nullptr;
1830b57cec5SDimitry Andric          container_ptr = container_ptr->GetInlinedParent()) {
1840b57cec5SDimitry Andric       if (!container_ptr->GetRangeContainingAddress(pc_as_address,
1850b57cec5SDimitry Andric                                                     containing_range))
1860b57cec5SDimitry Andric         break;
1870b57cec5SDimitry Andric       if (pc_as_address != containing_range.GetBaseAddress())
1880b57cec5SDimitry Andric         break;
1890b57cec5SDimitry Andric 
1900b57cec5SDimitry Andric       num_inlined_functions++;
1910b57cec5SDimitry Andric     }
1920b57cec5SDimitry Andric     m_current_inlined_pc = curr_pc;
1930b57cec5SDimitry Andric     m_current_inlined_depth = num_inlined_functions + 1;
19481ad6265SDimitry Andric     Log *log = GetLog(LLDBLog::Step);
1950b57cec5SDimitry Andric     if (log && log->GetVerbose())
1969dba64beSDimitry Andric       LLDB_LOGF(log,
1979dba64beSDimitry Andric                 "ResetCurrentInlinedDepth: setting inlined "
1980b57cec5SDimitry Andric                 "depth: %d 0x%" PRIx64 ".\n",
1990b57cec5SDimitry Andric                 m_current_inlined_depth, curr_pc);
2000b57cec5SDimitry Andric 
2010b57cec5SDimitry Andric     break;
2020b57cec5SDimitry Andric   }
2030b57cec5SDimitry Andric   }
2040b57cec5SDimitry Andric }
2050b57cec5SDimitry Andric 
DecrementCurrentInlinedDepth()2060b57cec5SDimitry Andric bool StackFrameList::DecrementCurrentInlinedDepth() {
2070b57cec5SDimitry Andric   if (m_show_inlined_frames) {
2080b57cec5SDimitry Andric     uint32_t current_inlined_depth = GetCurrentInlinedDepth();
2090b57cec5SDimitry Andric     if (current_inlined_depth != UINT32_MAX) {
2100b57cec5SDimitry Andric       if (current_inlined_depth > 0) {
2110b57cec5SDimitry Andric         m_current_inlined_depth--;
2120b57cec5SDimitry Andric         return true;
2130b57cec5SDimitry Andric       }
2140b57cec5SDimitry Andric     }
2150b57cec5SDimitry Andric   }
2160b57cec5SDimitry Andric   return false;
2170b57cec5SDimitry Andric }
2180b57cec5SDimitry Andric 
SetCurrentInlinedDepth(uint32_t new_depth)2190b57cec5SDimitry Andric void StackFrameList::SetCurrentInlinedDepth(uint32_t new_depth) {
2200b57cec5SDimitry Andric   m_current_inlined_depth = new_depth;
2210b57cec5SDimitry Andric   if (new_depth == UINT32_MAX)
2220b57cec5SDimitry Andric     m_current_inlined_pc = LLDB_INVALID_ADDRESS;
2230b57cec5SDimitry Andric   else
2240b57cec5SDimitry Andric     m_current_inlined_pc = m_thread.GetRegisterContext()->GetPC();
2250b57cec5SDimitry Andric }
2260b57cec5SDimitry Andric 
GetOnlyConcreteFramesUpTo(uint32_t end_idx,Unwind & unwinder)2270b57cec5SDimitry Andric void StackFrameList::GetOnlyConcreteFramesUpTo(uint32_t end_idx,
2285ffd83dbSDimitry Andric                                                Unwind &unwinder) {
2290b57cec5SDimitry Andric   assert(m_thread.IsValid() && "Expected valid thread");
2300b57cec5SDimitry Andric   assert(m_frames.size() <= end_idx && "Expected there to be frames to fill");
2310b57cec5SDimitry Andric 
2320b57cec5SDimitry Andric   if (end_idx < m_concrete_frames_fetched)
2330b57cec5SDimitry Andric     return;
2340b57cec5SDimitry Andric 
2355ffd83dbSDimitry Andric   uint32_t num_frames = unwinder.GetFramesUpTo(end_idx);
2360b57cec5SDimitry Andric   if (num_frames <= end_idx + 1) {
2370b57cec5SDimitry Andric     // Done unwinding.
2380b57cec5SDimitry Andric     m_concrete_frames_fetched = UINT32_MAX;
2390b57cec5SDimitry Andric   }
2400b57cec5SDimitry Andric 
2410b57cec5SDimitry Andric   // Don't create the frames eagerly. Defer this work to GetFrameAtIndex,
2420b57cec5SDimitry Andric   // which can lazily query the unwinder to create frames.
2430b57cec5SDimitry Andric   m_frames.resize(num_frames);
2440b57cec5SDimitry Andric }
2450b57cec5SDimitry Andric 
2465ffd83dbSDimitry Andric /// A sequence of calls that comprise some portion of a backtrace. Each frame
2475ffd83dbSDimitry Andric /// is represented as a pair of a callee (Function *) and an address within the
2485ffd83dbSDimitry Andric /// callee.
2495ffd83dbSDimitry Andric struct CallDescriptor {
2505ffd83dbSDimitry Andric   Function *func;
2515ffd83dbSDimitry Andric   CallEdge::AddrType address_type = CallEdge::AddrType::Call;
2525ffd83dbSDimitry Andric   addr_t address = LLDB_INVALID_ADDRESS;
2535ffd83dbSDimitry Andric };
2545ffd83dbSDimitry Andric using CallSequence = std::vector<CallDescriptor>;
2555ffd83dbSDimitry Andric 
2560b57cec5SDimitry Andric /// Find the unique path through the call graph from \p begin (with return PC
2570b57cec5SDimitry Andric /// \p return_pc) to \p end. On success this path is stored into \p path, and
2580b57cec5SDimitry Andric /// on failure \p path is unchanged.
FindInterveningFrames(Function & begin,Function & end,ExecutionContext & exe_ctx,Target & target,addr_t return_pc,CallSequence & path,ModuleList & images,Log * log)2590b57cec5SDimitry Andric static void FindInterveningFrames(Function &begin, Function &end,
260480093f4SDimitry Andric                                   ExecutionContext &exe_ctx, Target &target,
2615ffd83dbSDimitry Andric                                   addr_t return_pc, CallSequence &path,
2620b57cec5SDimitry Andric                                   ModuleList &images, Log *log) {
2630b57cec5SDimitry Andric   LLDB_LOG(log, "Finding frames between {0} and {1}, retn-pc={2:x}",
2640b57cec5SDimitry Andric            begin.GetDisplayName(), end.GetDisplayName(), return_pc);
2650b57cec5SDimitry Andric 
2660b57cec5SDimitry Andric   // Find a non-tail calling edge with the correct return PC.
2670b57cec5SDimitry Andric   if (log)
268480093f4SDimitry Andric     for (const auto &edge : begin.GetCallEdges())
2690b57cec5SDimitry Andric       LLDB_LOG(log, "FindInterveningFrames: found call with retn-PC = {0:x}",
270480093f4SDimitry Andric                edge->GetReturnPCAddress(begin, target));
2719dba64beSDimitry Andric   CallEdge *first_edge = begin.GetCallEdgeForReturnAddress(return_pc, target);
2729dba64beSDimitry Andric   if (!first_edge) {
2730b57cec5SDimitry Andric     LLDB_LOG(log, "No call edge outgoing from {0} with retn-PC == {1:x}",
2740b57cec5SDimitry Andric              begin.GetDisplayName(), return_pc);
2750b57cec5SDimitry Andric     return;
2760b57cec5SDimitry Andric   }
2770b57cec5SDimitry Andric 
2780b57cec5SDimitry Andric   // The first callee may not be resolved, or there may be nothing to fill in.
279480093f4SDimitry Andric   Function *first_callee = first_edge->GetCallee(images, exe_ctx);
2800b57cec5SDimitry Andric   if (!first_callee) {
2810b57cec5SDimitry Andric     LLDB_LOG(log, "Could not resolve callee");
2820b57cec5SDimitry Andric     return;
2830b57cec5SDimitry Andric   }
2840b57cec5SDimitry Andric   if (first_callee == &end) {
2850b57cec5SDimitry Andric     LLDB_LOG(log, "Not searching further, first callee is {0} (retn-PC: {1:x})",
2860b57cec5SDimitry Andric              end.GetDisplayName(), return_pc);
2870b57cec5SDimitry Andric     return;
2880b57cec5SDimitry Andric   }
2890b57cec5SDimitry Andric 
2900b57cec5SDimitry Andric   // Run DFS on the tail-calling edges out of the first callee to find \p end.
2910b57cec5SDimitry Andric   // Fully explore the set of functions reachable from the first edge via tail
2920b57cec5SDimitry Andric   // calls in order to detect ambiguous executions.
2930b57cec5SDimitry Andric   struct DFS {
2945ffd83dbSDimitry Andric     CallSequence active_path = {};
2955ffd83dbSDimitry Andric     CallSequence solution_path = {};
2960b57cec5SDimitry Andric     llvm::SmallPtrSet<Function *, 2> visited_nodes = {};
2970b57cec5SDimitry Andric     bool ambiguous = false;
2980b57cec5SDimitry Andric     Function *end;
2990b57cec5SDimitry Andric     ModuleList &images;
3005ffd83dbSDimitry Andric     Target &target;
301480093f4SDimitry Andric     ExecutionContext &context;
3020b57cec5SDimitry Andric 
3035ffd83dbSDimitry Andric     DFS(Function *end, ModuleList &images, Target &target,
3045ffd83dbSDimitry Andric         ExecutionContext &context)
3055ffd83dbSDimitry Andric         : end(end), images(images), target(target), context(context) {}
3060b57cec5SDimitry Andric 
3075ffd83dbSDimitry Andric     void search(CallEdge &first_edge, Function &first_callee,
3085ffd83dbSDimitry Andric                 CallSequence &path) {
3095ffd83dbSDimitry Andric       dfs(first_edge, first_callee);
3100b57cec5SDimitry Andric       if (!ambiguous)
3110b57cec5SDimitry Andric         path = std::move(solution_path);
3120b57cec5SDimitry Andric     }
3130b57cec5SDimitry Andric 
3145ffd83dbSDimitry Andric     void dfs(CallEdge &current_edge, Function &callee) {
3150b57cec5SDimitry Andric       // Found a path to the target function.
3169dba64beSDimitry Andric       if (&callee == end) {
3170b57cec5SDimitry Andric         if (solution_path.empty())
3180b57cec5SDimitry Andric           solution_path = active_path;
3190b57cec5SDimitry Andric         else
3200b57cec5SDimitry Andric           ambiguous = true;
3210b57cec5SDimitry Andric         return;
3220b57cec5SDimitry Andric       }
3230b57cec5SDimitry Andric 
3240b57cec5SDimitry Andric       // Terminate the search if tail recursion is found, or more generally if
3250b57cec5SDimitry Andric       // there's more than one way to reach a target. This errs on the side of
3260b57cec5SDimitry Andric       // caution: it conservatively stops searching when some solutions are
3270b57cec5SDimitry Andric       // still possible to save time in the average case.
3289dba64beSDimitry Andric       if (!visited_nodes.insert(&callee).second) {
3290b57cec5SDimitry Andric         ambiguous = true;
3300b57cec5SDimitry Andric         return;
3310b57cec5SDimitry Andric       }
3320b57cec5SDimitry Andric 
3330b57cec5SDimitry Andric       // Search the calls made from this callee.
3345ffd83dbSDimitry Andric       active_path.push_back(CallDescriptor{&callee});
335480093f4SDimitry Andric       for (const auto &edge : callee.GetTailCallingEdges()) {
336480093f4SDimitry Andric         Function *next_callee = edge->GetCallee(images, context);
3370b57cec5SDimitry Andric         if (!next_callee)
3380b57cec5SDimitry Andric           continue;
3390b57cec5SDimitry Andric 
3405ffd83dbSDimitry Andric         std::tie(active_path.back().address_type, active_path.back().address) =
3415ffd83dbSDimitry Andric             edge->GetCallerAddress(callee, target);
3425ffd83dbSDimitry Andric 
3435ffd83dbSDimitry Andric         dfs(*edge, *next_callee);
3440b57cec5SDimitry Andric         if (ambiguous)
3450b57cec5SDimitry Andric           return;
3460b57cec5SDimitry Andric       }
3470b57cec5SDimitry Andric       active_path.pop_back();
3480b57cec5SDimitry Andric     }
3490b57cec5SDimitry Andric   };
3500b57cec5SDimitry Andric 
3515ffd83dbSDimitry Andric   DFS(&end, images, target, exe_ctx).search(*first_edge, *first_callee, path);
3520b57cec5SDimitry Andric }
3530b57cec5SDimitry Andric 
3540b57cec5SDimitry Andric /// Given that \p next_frame will be appended to the frame list, synthesize
3550b57cec5SDimitry Andric /// tail call frames between the current end of the list and \p next_frame.
3560b57cec5SDimitry Andric /// If any frames are added, adjust the frame index of \p next_frame.
3570b57cec5SDimitry Andric ///
3580b57cec5SDimitry Andric ///   --------------
3590b57cec5SDimitry Andric ///   |    ...     | <- Completed frames.
3600b57cec5SDimitry Andric ///   --------------
3610b57cec5SDimitry Andric ///   | prev_frame |
3620b57cec5SDimitry Andric ///   --------------
3630b57cec5SDimitry Andric ///   |    ...     | <- Artificial frames inserted here.
3640b57cec5SDimitry Andric ///   --------------
3650b57cec5SDimitry Andric ///   | next_frame |
3660b57cec5SDimitry Andric ///   --------------
3670b57cec5SDimitry Andric ///   |    ...     | <- Not-yet-visited frames.
3680b57cec5SDimitry Andric ///   --------------
SynthesizeTailCallFrames(StackFrame & next_frame)3690b57cec5SDimitry Andric void StackFrameList::SynthesizeTailCallFrames(StackFrame &next_frame) {
3705ffd83dbSDimitry Andric   // Cannot synthesize tail call frames when the stack is empty (there is no
3715ffd83dbSDimitry Andric   // "previous" frame).
3725ffd83dbSDimitry Andric   if (m_frames.empty())
3735ffd83dbSDimitry Andric     return;
3745ffd83dbSDimitry Andric 
3750b57cec5SDimitry Andric   TargetSP target_sp = next_frame.CalculateTarget();
3760b57cec5SDimitry Andric   if (!target_sp)
3770b57cec5SDimitry Andric     return;
3780b57cec5SDimitry Andric 
3790b57cec5SDimitry Andric   lldb::RegisterContextSP next_reg_ctx_sp = next_frame.GetRegisterContext();
3800b57cec5SDimitry Andric   if (!next_reg_ctx_sp)
3810b57cec5SDimitry Andric     return;
3820b57cec5SDimitry Andric 
38381ad6265SDimitry Andric   Log *log = GetLog(LLDBLog::Step);
3840b57cec5SDimitry Andric 
3850b57cec5SDimitry Andric   StackFrame &prev_frame = *m_frames.back().get();
3860b57cec5SDimitry Andric 
3870b57cec5SDimitry Andric   // Find the functions prev_frame and next_frame are stopped in. The function
3880b57cec5SDimitry Andric   // objects are needed to search the lazy call graph for intervening frames.
3890b57cec5SDimitry Andric   Function *prev_func =
3900b57cec5SDimitry Andric       prev_frame.GetSymbolContext(eSymbolContextFunction).function;
3910b57cec5SDimitry Andric   if (!prev_func) {
3920b57cec5SDimitry Andric     LLDB_LOG(log, "SynthesizeTailCallFrames: can't find previous function");
3930b57cec5SDimitry Andric     return;
3940b57cec5SDimitry Andric   }
3950b57cec5SDimitry Andric   Function *next_func =
3960b57cec5SDimitry Andric       next_frame.GetSymbolContext(eSymbolContextFunction).function;
3970b57cec5SDimitry Andric   if (!next_func) {
3980b57cec5SDimitry Andric     LLDB_LOG(log, "SynthesizeTailCallFrames: can't find next function");
3990b57cec5SDimitry Andric     return;
4000b57cec5SDimitry Andric   }
4010b57cec5SDimitry Andric 
4020b57cec5SDimitry Andric   // Try to find the unique sequence of (tail) calls which led from next_frame
4030b57cec5SDimitry Andric   // to prev_frame.
4045ffd83dbSDimitry Andric   CallSequence path;
4050b57cec5SDimitry Andric   addr_t return_pc = next_reg_ctx_sp->GetPC();
4060b57cec5SDimitry Andric   Target &target = *target_sp.get();
4070b57cec5SDimitry Andric   ModuleList &images = next_frame.CalculateTarget()->GetImages();
408480093f4SDimitry Andric   ExecutionContext exe_ctx(target_sp, /*get_process=*/true);
409480093f4SDimitry Andric   exe_ctx.SetFramePtr(&next_frame);
410480093f4SDimitry Andric   FindInterveningFrames(*next_func, *prev_func, exe_ctx, target, return_pc,
411480093f4SDimitry Andric                         path, images, log);
4120b57cec5SDimitry Andric 
4130b57cec5SDimitry Andric   // Push synthetic tail call frames.
4145ffd83dbSDimitry Andric   for (auto calleeInfo : llvm::reverse(path)) {
4155ffd83dbSDimitry Andric     Function *callee = calleeInfo.func;
4160b57cec5SDimitry Andric     uint32_t frame_idx = m_frames.size();
4170b57cec5SDimitry Andric     uint32_t concrete_frame_idx = next_frame.GetConcreteFrameIndex();
4180b57cec5SDimitry Andric     addr_t cfa = LLDB_INVALID_ADDRESS;
4190b57cec5SDimitry Andric     bool cfa_is_valid = false;
4205ffd83dbSDimitry Andric     addr_t pc = calleeInfo.address;
4215ffd83dbSDimitry Andric     // If the callee address refers to the call instruction, we do not want to
4225ffd83dbSDimitry Andric     // subtract 1 from this value.
4235ffd83dbSDimitry Andric     const bool behaves_like_zeroth_frame =
4245ffd83dbSDimitry Andric         calleeInfo.address_type == CallEdge::AddrType::Call;
4250b57cec5SDimitry Andric     SymbolContext sc;
4260b57cec5SDimitry Andric     callee->CalculateSymbolContext(&sc);
4270b57cec5SDimitry Andric     auto synth_frame = std::make_shared<StackFrame>(
4280b57cec5SDimitry Andric         m_thread.shared_from_this(), frame_idx, concrete_frame_idx, cfa,
4299dba64beSDimitry Andric         cfa_is_valid, pc, StackFrame::Kind::Artificial,
4309dba64beSDimitry Andric         behaves_like_zeroth_frame, &sc);
4310b57cec5SDimitry Andric     m_frames.push_back(synth_frame);
4325ffd83dbSDimitry Andric     LLDB_LOG(log, "Pushed frame {0} at {1:x}", callee->GetDisplayName(), pc);
4330b57cec5SDimitry Andric   }
4340b57cec5SDimitry Andric 
4350b57cec5SDimitry Andric   // If any frames were created, adjust next_frame's index.
4360b57cec5SDimitry Andric   if (!path.empty())
4370b57cec5SDimitry Andric     next_frame.SetFrameIndex(m_frames.size());
4380b57cec5SDimitry Andric }
4390b57cec5SDimitry Andric 
GetFramesUpTo(uint32_t end_idx,InterruptionControl allow_interrupt)440fe013be4SDimitry Andric bool StackFrameList::GetFramesUpTo(uint32_t end_idx,
441fe013be4SDimitry Andric                                    InterruptionControl allow_interrupt) {
4420b57cec5SDimitry Andric   // Do not fetch frames for an invalid thread.
443fe013be4SDimitry Andric   bool was_interrupted = false;
4440b57cec5SDimitry Andric   if (!m_thread.IsValid())
445fe013be4SDimitry Andric     return false;
4460b57cec5SDimitry Andric 
4470b57cec5SDimitry Andric   // We've already gotten more frames than asked for, or we've already finished
4480b57cec5SDimitry Andric   // unwinding, return.
4490b57cec5SDimitry Andric   if (m_frames.size() > end_idx || GetAllFramesFetched())
450fe013be4SDimitry Andric     return false;
4510b57cec5SDimitry Andric 
4525ffd83dbSDimitry Andric   Unwind &unwinder = m_thread.GetUnwinder();
4530b57cec5SDimitry Andric 
4540b57cec5SDimitry Andric   if (!m_show_inlined_frames) {
4550b57cec5SDimitry Andric     GetOnlyConcreteFramesUpTo(end_idx, unwinder);
456fe013be4SDimitry Andric     return false;
4570b57cec5SDimitry Andric   }
4580b57cec5SDimitry Andric 
4590b57cec5SDimitry Andric #if defined(DEBUG_STACK_FRAMES)
4600b57cec5SDimitry Andric   StreamFile s(stdout, false);
4610b57cec5SDimitry Andric #endif
4620b57cec5SDimitry Andric   // If we are hiding some frames from the outside world, we need to add
4630b57cec5SDimitry Andric   // those onto the total count of frames to fetch.  However, we don't need
4640b57cec5SDimitry Andric   // to do that if end_idx is 0 since in that case we always get the first
4650b57cec5SDimitry Andric   // concrete frame and all the inlined frames below it...  And of course, if
4660b57cec5SDimitry Andric   // end_idx is UINT32_MAX that means get all, so just do that...
4670b57cec5SDimitry Andric 
4680b57cec5SDimitry Andric   uint32_t inlined_depth = 0;
4690b57cec5SDimitry Andric   if (end_idx > 0 && end_idx != UINT32_MAX) {
4700b57cec5SDimitry Andric     inlined_depth = GetCurrentInlinedDepth();
4710b57cec5SDimitry Andric     if (inlined_depth != UINT32_MAX) {
4720b57cec5SDimitry Andric       if (end_idx > 0)
4730b57cec5SDimitry Andric         end_idx += inlined_depth;
4740b57cec5SDimitry Andric     }
4750b57cec5SDimitry Andric   }
4760b57cec5SDimitry Andric 
4770b57cec5SDimitry Andric   StackFrameSP unwind_frame_sp;
478fe013be4SDimitry Andric   Debugger &dbg = m_thread.GetProcess()->GetTarget().GetDebugger();
4790b57cec5SDimitry Andric   do {
4800b57cec5SDimitry Andric     uint32_t idx = m_concrete_frames_fetched++;
4810b57cec5SDimitry Andric     lldb::addr_t pc = LLDB_INVALID_ADDRESS;
4820b57cec5SDimitry Andric     lldb::addr_t cfa = LLDB_INVALID_ADDRESS;
4839dba64beSDimitry Andric     bool behaves_like_zeroth_frame = (idx == 0);
4840b57cec5SDimitry Andric     if (idx == 0) {
4850b57cec5SDimitry Andric       // We might have already created frame zero, only create it if we need
4860b57cec5SDimitry Andric       // to.
4870b57cec5SDimitry Andric       if (m_frames.empty()) {
4880b57cec5SDimitry Andric         RegisterContextSP reg_ctx_sp(m_thread.GetRegisterContext());
4890b57cec5SDimitry Andric 
4900b57cec5SDimitry Andric         if (reg_ctx_sp) {
4915ffd83dbSDimitry Andric           const bool success = unwinder.GetFrameInfoAtIndex(
4929dba64beSDimitry Andric               idx, cfa, pc, behaves_like_zeroth_frame);
4930b57cec5SDimitry Andric           // There shouldn't be any way not to get the frame info for frame
4940b57cec5SDimitry Andric           // 0. But if the unwinder can't make one, lets make one by hand
4950b57cec5SDimitry Andric           // with the SP as the CFA and see if that gets any further.
4960b57cec5SDimitry Andric           if (!success) {
4970b57cec5SDimitry Andric             cfa = reg_ctx_sp->GetSP();
4980b57cec5SDimitry Andric             pc = reg_ctx_sp->GetPC();
4990b57cec5SDimitry Andric           }
5000b57cec5SDimitry Andric 
5010b57cec5SDimitry Andric           unwind_frame_sp = std::make_shared<StackFrame>(
5020b57cec5SDimitry Andric               m_thread.shared_from_this(), m_frames.size(), idx, reg_ctx_sp,
5039dba64beSDimitry Andric               cfa, pc, behaves_like_zeroth_frame, nullptr);
5040b57cec5SDimitry Andric           m_frames.push_back(unwind_frame_sp);
5050b57cec5SDimitry Andric         }
5060b57cec5SDimitry Andric       } else {
5070b57cec5SDimitry Andric         unwind_frame_sp = m_frames.front();
5080b57cec5SDimitry Andric         cfa = unwind_frame_sp->m_id.GetCallFrameAddress();
5090b57cec5SDimitry Andric       }
5100b57cec5SDimitry Andric     } else {
511fe013be4SDimitry Andric       // Check for interruption when building the frames.
512fe013be4SDimitry Andric       // Do the check in idx > 0 so that we'll always create a 0th frame.
513fe013be4SDimitry Andric       if (allow_interrupt
514fe013be4SDimitry Andric           && INTERRUPT_REQUESTED(dbg, "Interrupted having fetched {0} frames",
515fe013be4SDimitry Andric                                  m_frames.size())) {
516fe013be4SDimitry Andric           was_interrupted = true;
517fe013be4SDimitry Andric           break;
518fe013be4SDimitry Andric       }
519fe013be4SDimitry Andric 
5205ffd83dbSDimitry Andric       const bool success =
5215ffd83dbSDimitry Andric           unwinder.GetFrameInfoAtIndex(idx, cfa, pc, behaves_like_zeroth_frame);
5220b57cec5SDimitry Andric       if (!success) {
5230b57cec5SDimitry Andric         // We've gotten to the end of the stack.
5240b57cec5SDimitry Andric         SetAllFramesFetched();
5250b57cec5SDimitry Andric         break;
5260b57cec5SDimitry Andric       }
5270b57cec5SDimitry Andric       const bool cfa_is_valid = true;
5280b57cec5SDimitry Andric       unwind_frame_sp = std::make_shared<StackFrame>(
5290b57cec5SDimitry Andric           m_thread.shared_from_this(), m_frames.size(), idx, cfa, cfa_is_valid,
5309dba64beSDimitry Andric           pc, StackFrame::Kind::Regular, behaves_like_zeroth_frame, nullptr);
5310b57cec5SDimitry Andric 
5320b57cec5SDimitry Andric       // Create synthetic tail call frames between the previous frame and the
5330b57cec5SDimitry Andric       // newly-found frame. The new frame's index may change after this call,
5340b57cec5SDimitry Andric       // although its concrete index will stay the same.
5350b57cec5SDimitry Andric       SynthesizeTailCallFrames(*unwind_frame_sp.get());
5360b57cec5SDimitry Andric 
5370b57cec5SDimitry Andric       m_frames.push_back(unwind_frame_sp);
5380b57cec5SDimitry Andric     }
5390b57cec5SDimitry Andric 
5400b57cec5SDimitry Andric     assert(unwind_frame_sp);
5410b57cec5SDimitry Andric     SymbolContext unwind_sc = unwind_frame_sp->GetSymbolContext(
5420b57cec5SDimitry Andric         eSymbolContextBlock | eSymbolContextFunction);
5430b57cec5SDimitry Andric     Block *unwind_block = unwind_sc.block;
5440b57cec5SDimitry Andric     TargetSP target_sp = m_thread.CalculateTarget();
545fe6060f1SDimitry Andric     if (unwind_block) {
546fe6060f1SDimitry Andric       Address curr_frame_address(
547fe6060f1SDimitry Andric           unwind_frame_sp->GetFrameCodeAddressForSymbolication());
5480b57cec5SDimitry Andric 
5490b57cec5SDimitry Andric       SymbolContext next_frame_sc;
5500b57cec5SDimitry Andric       Address next_frame_address;
5510b57cec5SDimitry Andric 
5520b57cec5SDimitry Andric       while (unwind_sc.GetParentOfInlinedScope(
5530b57cec5SDimitry Andric           curr_frame_address, next_frame_sc, next_frame_address)) {
5540b57cec5SDimitry Andric         next_frame_sc.line_entry.ApplyFileMappings(target_sp);
5559dba64beSDimitry Andric         behaves_like_zeroth_frame = false;
5569dba64beSDimitry Andric         StackFrameSP frame_sp(new StackFrame(
5579dba64beSDimitry Andric             m_thread.shared_from_this(), m_frames.size(), idx,
5589dba64beSDimitry Andric             unwind_frame_sp->GetRegisterContextSP(), cfa, next_frame_address,
5599dba64beSDimitry Andric             behaves_like_zeroth_frame, &next_frame_sc));
5600b57cec5SDimitry Andric 
5610b57cec5SDimitry Andric         m_frames.push_back(frame_sp);
5620b57cec5SDimitry Andric         unwind_sc = next_frame_sc;
5630b57cec5SDimitry Andric         curr_frame_address = next_frame_address;
5640b57cec5SDimitry Andric       }
5650b57cec5SDimitry Andric     }
5660b57cec5SDimitry Andric   } while (m_frames.size() - 1 < end_idx);
5670b57cec5SDimitry Andric 
5680b57cec5SDimitry Andric   // Don't try to merge till you've calculated all the frames in this stack.
5690b57cec5SDimitry Andric   if (GetAllFramesFetched() && m_prev_frames_sp) {
5700b57cec5SDimitry Andric     StackFrameList *prev_frames = m_prev_frames_sp.get();
5710b57cec5SDimitry Andric     StackFrameList *curr_frames = this;
5720b57cec5SDimitry Andric 
5730b57cec5SDimitry Andric #if defined(DEBUG_STACK_FRAMES)
5740b57cec5SDimitry Andric     s.PutCString("\nprev_frames:\n");
5750b57cec5SDimitry Andric     prev_frames->Dump(&s);
5760b57cec5SDimitry Andric     s.PutCString("\ncurr_frames:\n");
5770b57cec5SDimitry Andric     curr_frames->Dump(&s);
5780b57cec5SDimitry Andric     s.EOL();
5790b57cec5SDimitry Andric #endif
5800b57cec5SDimitry Andric     size_t curr_frame_num, prev_frame_num;
5810b57cec5SDimitry Andric 
5820b57cec5SDimitry Andric     for (curr_frame_num = curr_frames->m_frames.size(),
5830b57cec5SDimitry Andric         prev_frame_num = prev_frames->m_frames.size();
5840b57cec5SDimitry Andric          curr_frame_num > 0 && prev_frame_num > 0;
5850b57cec5SDimitry Andric          --curr_frame_num, --prev_frame_num) {
5860b57cec5SDimitry Andric       const size_t curr_frame_idx = curr_frame_num - 1;
5870b57cec5SDimitry Andric       const size_t prev_frame_idx = prev_frame_num - 1;
5880b57cec5SDimitry Andric       StackFrameSP curr_frame_sp(curr_frames->m_frames[curr_frame_idx]);
5890b57cec5SDimitry Andric       StackFrameSP prev_frame_sp(prev_frames->m_frames[prev_frame_idx]);
5900b57cec5SDimitry Andric 
5910b57cec5SDimitry Andric #if defined(DEBUG_STACK_FRAMES)
5920b57cec5SDimitry Andric       s.Printf("\n\nCurr frame #%u ", curr_frame_idx);
5930b57cec5SDimitry Andric       if (curr_frame_sp)
5940b57cec5SDimitry Andric         curr_frame_sp->Dump(&s, true, false);
5950b57cec5SDimitry Andric       else
5960b57cec5SDimitry Andric         s.PutCString("NULL");
5970b57cec5SDimitry Andric       s.Printf("\nPrev frame #%u ", prev_frame_idx);
5980b57cec5SDimitry Andric       if (prev_frame_sp)
5990b57cec5SDimitry Andric         prev_frame_sp->Dump(&s, true, false);
6000b57cec5SDimitry Andric       else
6010b57cec5SDimitry Andric         s.PutCString("NULL");
6020b57cec5SDimitry Andric #endif
6030b57cec5SDimitry Andric 
6040b57cec5SDimitry Andric       StackFrame *curr_frame = curr_frame_sp.get();
6050b57cec5SDimitry Andric       StackFrame *prev_frame = prev_frame_sp.get();
6060b57cec5SDimitry Andric 
6070b57cec5SDimitry Andric       if (curr_frame == nullptr || prev_frame == nullptr)
6080b57cec5SDimitry Andric         break;
6090b57cec5SDimitry Andric 
6100b57cec5SDimitry Andric       // Check the stack ID to make sure they are equal.
6110b57cec5SDimitry Andric       if (curr_frame->GetStackID() != prev_frame->GetStackID())
6120b57cec5SDimitry Andric         break;
6130b57cec5SDimitry Andric 
6140b57cec5SDimitry Andric       prev_frame->UpdatePreviousFrameFromCurrentFrame(*curr_frame);
6150b57cec5SDimitry Andric       // Now copy the fixed up previous frame into the current frames so the
6160b57cec5SDimitry Andric       // pointer doesn't change.
6170b57cec5SDimitry Andric       m_frames[curr_frame_idx] = prev_frame_sp;
6180b57cec5SDimitry Andric 
6190b57cec5SDimitry Andric #if defined(DEBUG_STACK_FRAMES)
6200b57cec5SDimitry Andric       s.Printf("\n    Copying previous frame to current frame");
6210b57cec5SDimitry Andric #endif
6220b57cec5SDimitry Andric     }
6230b57cec5SDimitry Andric     // We are done with the old stack frame list, we can release it now.
6240b57cec5SDimitry Andric     m_prev_frames_sp.reset();
6250b57cec5SDimitry Andric   }
6260b57cec5SDimitry Andric 
6270b57cec5SDimitry Andric #if defined(DEBUG_STACK_FRAMES)
6280b57cec5SDimitry Andric   s.PutCString("\n\nNew frames:\n");
6290b57cec5SDimitry Andric   Dump(&s);
6300b57cec5SDimitry Andric   s.EOL();
6310b57cec5SDimitry Andric #endif
632fe013be4SDimitry Andric   // Don't report interrupted if we happen to have gotten all the frames:
633fe013be4SDimitry Andric   if (!GetAllFramesFetched())
634fe013be4SDimitry Andric     return was_interrupted;
635fe013be4SDimitry Andric   return false;
6360b57cec5SDimitry Andric }
6370b57cec5SDimitry Andric 
GetNumFrames(bool can_create)6380b57cec5SDimitry Andric uint32_t StackFrameList::GetNumFrames(bool can_create) {
6390b57cec5SDimitry Andric   std::lock_guard<std::recursive_mutex> guard(m_mutex);
6400b57cec5SDimitry Andric 
641fe013be4SDimitry Andric   if (can_create) {
642fe013be4SDimitry Andric     // Don't allow interrupt or we might not return the correct count
643fe013be4SDimitry Andric     GetFramesUpTo(UINT32_MAX, DoNotAllowInterruption);
644fe013be4SDimitry Andric   }
6450b57cec5SDimitry Andric   return GetVisibleStackFrameIndex(m_frames.size());
6460b57cec5SDimitry Andric }
6470b57cec5SDimitry Andric 
Dump(Stream * s)6480b57cec5SDimitry Andric void StackFrameList::Dump(Stream *s) {
6490b57cec5SDimitry Andric   if (s == nullptr)
6500b57cec5SDimitry Andric     return;
6510b57cec5SDimitry Andric 
6520b57cec5SDimitry Andric   std::lock_guard<std::recursive_mutex> guard(m_mutex);
6530b57cec5SDimitry Andric 
6540b57cec5SDimitry Andric   const_iterator pos, begin = m_frames.begin(), end = m_frames.end();
6550b57cec5SDimitry Andric   for (pos = begin; pos != end; ++pos) {
6560b57cec5SDimitry Andric     StackFrame *frame = (*pos).get();
6570b57cec5SDimitry Andric     s->Printf("%p: ", static_cast<void *>(frame));
6580b57cec5SDimitry Andric     if (frame) {
6590b57cec5SDimitry Andric       frame->GetStackID().Dump(s);
6600b57cec5SDimitry Andric       frame->DumpUsingSettingsFormat(s);
6610b57cec5SDimitry Andric     } else
6620b57cec5SDimitry Andric       s->Printf("frame #%u", (uint32_t)std::distance(begin, pos));
6630b57cec5SDimitry Andric     s->EOL();
6640b57cec5SDimitry Andric   }
6650b57cec5SDimitry Andric   s->EOL();
6660b57cec5SDimitry Andric }
6670b57cec5SDimitry Andric 
GetFrameAtIndex(uint32_t idx)6680b57cec5SDimitry Andric StackFrameSP StackFrameList::GetFrameAtIndex(uint32_t idx) {
6690b57cec5SDimitry Andric   StackFrameSP frame_sp;
6700b57cec5SDimitry Andric   std::lock_guard<std::recursive_mutex> guard(m_mutex);
6710b57cec5SDimitry Andric   uint32_t original_idx = idx;
6720b57cec5SDimitry Andric 
6730b57cec5SDimitry Andric   uint32_t inlined_depth = GetCurrentInlinedDepth();
6740b57cec5SDimitry Andric   if (inlined_depth != UINT32_MAX)
6750b57cec5SDimitry Andric     idx += inlined_depth;
6760b57cec5SDimitry Andric 
6770b57cec5SDimitry Andric   if (idx < m_frames.size())
6780b57cec5SDimitry Andric     frame_sp = m_frames[idx];
6790b57cec5SDimitry Andric 
6800b57cec5SDimitry Andric   if (frame_sp)
6810b57cec5SDimitry Andric     return frame_sp;
6820b57cec5SDimitry Andric 
6830b57cec5SDimitry Andric   // GetFramesUpTo will fill m_frames with as many frames as you asked for, if
6840b57cec5SDimitry Andric   // there are that many.  If there weren't then you asked for too many frames.
685fe013be4SDimitry Andric   // GetFramesUpTo returns true if interrupted:
686fe013be4SDimitry Andric   if (GetFramesUpTo(idx)) {
687fe013be4SDimitry Andric     Log *log = GetLog(LLDBLog::Thread);
688fe013be4SDimitry Andric     LLDB_LOG(log, "GetFrameAtIndex was interrupted");
689fe013be4SDimitry Andric     return {};
690fe013be4SDimitry Andric   }
691fe013be4SDimitry Andric 
6920b57cec5SDimitry Andric   if (idx < m_frames.size()) {
6930b57cec5SDimitry Andric     if (m_show_inlined_frames) {
6940b57cec5SDimitry Andric       // When inline frames are enabled we actually create all the frames in
6950b57cec5SDimitry Andric       // GetFramesUpTo.
6960b57cec5SDimitry Andric       frame_sp = m_frames[idx];
6970b57cec5SDimitry Andric     } else {
6980b57cec5SDimitry Andric       addr_t pc, cfa;
6999dba64beSDimitry Andric       bool behaves_like_zeroth_frame = (idx == 0);
7005ffd83dbSDimitry Andric       if (m_thread.GetUnwinder().GetFrameInfoAtIndex(
7015ffd83dbSDimitry Andric               idx, cfa, pc, behaves_like_zeroth_frame)) {
7020b57cec5SDimitry Andric         const bool cfa_is_valid = true;
7030b57cec5SDimitry Andric         frame_sp = std::make_shared<StackFrame>(
7040b57cec5SDimitry Andric             m_thread.shared_from_this(), idx, idx, cfa, cfa_is_valid, pc,
7059dba64beSDimitry Andric             StackFrame::Kind::Regular, behaves_like_zeroth_frame, nullptr);
7060b57cec5SDimitry Andric 
7070b57cec5SDimitry Andric         Function *function =
7080b57cec5SDimitry Andric             frame_sp->GetSymbolContext(eSymbolContextFunction).function;
7090b57cec5SDimitry Andric         if (function) {
7100b57cec5SDimitry Andric           // When we aren't showing inline functions we always use the top
7110b57cec5SDimitry Andric           // most function block as the scope.
7120b57cec5SDimitry Andric           frame_sp->SetSymbolContextScope(&function->GetBlock(false));
7130b57cec5SDimitry Andric         } else {
7140b57cec5SDimitry Andric           // Set the symbol scope from the symbol regardless if it is nullptr
7150b57cec5SDimitry Andric           // or valid.
7160b57cec5SDimitry Andric           frame_sp->SetSymbolContextScope(
7170b57cec5SDimitry Andric               frame_sp->GetSymbolContext(eSymbolContextSymbol).symbol);
7180b57cec5SDimitry Andric         }
7190b57cec5SDimitry Andric         SetFrameAtIndex(idx, frame_sp);
7200b57cec5SDimitry Andric       }
7210b57cec5SDimitry Andric     }
7220b57cec5SDimitry Andric   } else if (original_idx == 0) {
7230b57cec5SDimitry Andric     // There should ALWAYS be a frame at index 0.  If something went wrong with
7240b57cec5SDimitry Andric     // the CurrentInlinedDepth such that there weren't as many frames as we
7250b57cec5SDimitry Andric     // thought taking that into account, then reset the current inlined depth
7260b57cec5SDimitry Andric     // and return the real zeroth frame.
7270b57cec5SDimitry Andric     if (m_frames.empty()) {
7280b57cec5SDimitry Andric       // Why do we have a thread with zero frames, that should not ever
7290b57cec5SDimitry Andric       // happen...
7300b57cec5SDimitry Andric       assert(!m_thread.IsValid() && "A valid thread has no frames.");
7310b57cec5SDimitry Andric     } else {
7320b57cec5SDimitry Andric       ResetCurrentInlinedDepth();
7330b57cec5SDimitry Andric       frame_sp = m_frames[original_idx];
7340b57cec5SDimitry Andric     }
7350b57cec5SDimitry Andric   }
7360b57cec5SDimitry Andric 
7370b57cec5SDimitry Andric   return frame_sp;
7380b57cec5SDimitry Andric }
7390b57cec5SDimitry Andric 
7400b57cec5SDimitry Andric StackFrameSP
GetFrameWithConcreteFrameIndex(uint32_t unwind_idx)7410b57cec5SDimitry Andric StackFrameList::GetFrameWithConcreteFrameIndex(uint32_t unwind_idx) {
7420b57cec5SDimitry Andric   // First try assuming the unwind index is the same as the frame index. The
7430b57cec5SDimitry Andric   // unwind index is always greater than or equal to the frame index, so it is
7440b57cec5SDimitry Andric   // a good place to start. If we have inlined frames we might have 5 concrete
7450b57cec5SDimitry Andric   // frames (frame unwind indexes go from 0-4), but we might have 15 frames
7460b57cec5SDimitry Andric   // after we make all the inlined frames. Most of the time the unwind frame
7470b57cec5SDimitry Andric   // index (or the concrete frame index) is the same as the frame index.
7480b57cec5SDimitry Andric   uint32_t frame_idx = unwind_idx;
7490b57cec5SDimitry Andric   StackFrameSP frame_sp(GetFrameAtIndex(frame_idx));
7500b57cec5SDimitry Andric   while (frame_sp) {
7510b57cec5SDimitry Andric     if (frame_sp->GetFrameIndex() == unwind_idx)
7520b57cec5SDimitry Andric       break;
7530b57cec5SDimitry Andric     frame_sp = GetFrameAtIndex(++frame_idx);
7540b57cec5SDimitry Andric   }
7550b57cec5SDimitry Andric   return frame_sp;
7560b57cec5SDimitry Andric }
7570b57cec5SDimitry Andric 
CompareStackID(const StackFrameSP & stack_sp,const StackID & stack_id)7580b57cec5SDimitry Andric static bool CompareStackID(const StackFrameSP &stack_sp,
7590b57cec5SDimitry Andric                            const StackID &stack_id) {
7600b57cec5SDimitry Andric   return stack_sp->GetStackID() < stack_id;
7610b57cec5SDimitry Andric }
7620b57cec5SDimitry Andric 
GetFrameWithStackID(const StackID & stack_id)7630b57cec5SDimitry Andric StackFrameSP StackFrameList::GetFrameWithStackID(const StackID &stack_id) {
7640b57cec5SDimitry Andric   StackFrameSP frame_sp;
7650b57cec5SDimitry Andric 
7660b57cec5SDimitry Andric   if (stack_id.IsValid()) {
7670b57cec5SDimitry Andric     std::lock_guard<std::recursive_mutex> guard(m_mutex);
7680b57cec5SDimitry Andric     uint32_t frame_idx = 0;
7690b57cec5SDimitry Andric     // Do a binary search in case the stack frame is already in our cache
7700b57cec5SDimitry Andric     collection::const_iterator begin = m_frames.begin();
7710b57cec5SDimitry Andric     collection::const_iterator end = m_frames.end();
7720b57cec5SDimitry Andric     if (begin != end) {
7730b57cec5SDimitry Andric       collection::const_iterator pos =
7740b57cec5SDimitry Andric           std::lower_bound(begin, end, stack_id, CompareStackID);
7750b57cec5SDimitry Andric       if (pos != end) {
7760b57cec5SDimitry Andric         if ((*pos)->GetStackID() == stack_id)
7770b57cec5SDimitry Andric           return *pos;
7780b57cec5SDimitry Andric       }
7790b57cec5SDimitry Andric     }
7800b57cec5SDimitry Andric     do {
7810b57cec5SDimitry Andric       frame_sp = GetFrameAtIndex(frame_idx);
7820b57cec5SDimitry Andric       if (frame_sp && frame_sp->GetStackID() == stack_id)
7830b57cec5SDimitry Andric         break;
7840b57cec5SDimitry Andric       frame_idx++;
7850b57cec5SDimitry Andric     } while (frame_sp);
7860b57cec5SDimitry Andric   }
7870b57cec5SDimitry Andric   return frame_sp;
7880b57cec5SDimitry Andric }
7890b57cec5SDimitry Andric 
SetFrameAtIndex(uint32_t idx,StackFrameSP & frame_sp)7900b57cec5SDimitry Andric bool StackFrameList::SetFrameAtIndex(uint32_t idx, StackFrameSP &frame_sp) {
7910b57cec5SDimitry Andric   if (idx >= m_frames.size())
7920b57cec5SDimitry Andric     m_frames.resize(idx + 1);
7930b57cec5SDimitry Andric   // Make sure allocation succeeded by checking bounds again
7940b57cec5SDimitry Andric   if (idx < m_frames.size()) {
7950b57cec5SDimitry Andric     m_frames[idx] = frame_sp;
7960b57cec5SDimitry Andric     return true;
7970b57cec5SDimitry Andric   }
7980b57cec5SDimitry Andric   return false; // resize failed, out of memory?
7990b57cec5SDimitry Andric }
8000b57cec5SDimitry Andric 
SelectMostRelevantFrame()801fe013be4SDimitry Andric void StackFrameList::SelectMostRelevantFrame() {
802fe013be4SDimitry Andric   // Don't call into the frame recognizers on the private state thread as
803fe013be4SDimitry Andric   // they can cause code to run in the target, and that can cause deadlocks
804fe013be4SDimitry Andric   // when fetching stop events for the expression.
805fe013be4SDimitry Andric   if (m_thread.GetProcess()->CurrentThreadIsPrivateStateThread())
806fe013be4SDimitry Andric     return;
807fe013be4SDimitry Andric 
808fe013be4SDimitry Andric   Log *log = GetLog(LLDBLog::Thread);
809fe013be4SDimitry Andric 
810fe013be4SDimitry Andric   // Only the top frame should be recognized.
811fe013be4SDimitry Andric   StackFrameSP frame_sp = GetFrameAtIndex(0);
812fe013be4SDimitry Andric   if (!frame_sp) {
813fe013be4SDimitry Andric     LLDB_LOG(log, "Failed to construct Frame #0");
814fe013be4SDimitry Andric     return;
815fe013be4SDimitry Andric   }
816fe013be4SDimitry Andric 
817fe013be4SDimitry Andric   RecognizedStackFrameSP recognized_frame_sp = frame_sp->GetRecognizedFrame();
818fe013be4SDimitry Andric 
819fe013be4SDimitry Andric   if (!recognized_frame_sp) {
820fe013be4SDimitry Andric     LLDB_LOG(log, "Frame #0 not recognized");
821fe013be4SDimitry Andric     return;
822fe013be4SDimitry Andric   }
823fe013be4SDimitry Andric 
824fe013be4SDimitry Andric   if (StackFrameSP most_relevant_frame_sp =
825fe013be4SDimitry Andric           recognized_frame_sp->GetMostRelevantFrame()) {
826fe013be4SDimitry Andric     LLDB_LOG(log, "Found most relevant frame at index {0}",
827fe013be4SDimitry Andric              most_relevant_frame_sp->GetFrameIndex());
828fe013be4SDimitry Andric     SetSelectedFrame(most_relevant_frame_sp.get());
829fe013be4SDimitry Andric   } else {
830fe013be4SDimitry Andric     LLDB_LOG(log, "No relevant frame!");
831fe013be4SDimitry Andric   }
832fe013be4SDimitry Andric }
833fe013be4SDimitry Andric 
GetSelectedFrameIndex(SelectMostRelevant select_most_relevant)834fe013be4SDimitry Andric uint32_t StackFrameList::GetSelectedFrameIndex(
835fe013be4SDimitry Andric     SelectMostRelevant select_most_relevant) {
8360b57cec5SDimitry Andric   std::lock_guard<std::recursive_mutex> guard(m_mutex);
837fe013be4SDimitry Andric   if (!m_selected_frame_idx && select_most_relevant)
838fe013be4SDimitry Andric     SelectMostRelevantFrame();
839fe013be4SDimitry Andric   if (!m_selected_frame_idx) {
840fe013be4SDimitry Andric     // If we aren't selecting the most relevant frame, and the selected frame
841fe013be4SDimitry Andric     // isn't set, then don't force a selection here, just return 0.
842fe013be4SDimitry Andric     if (!select_most_relevant)
843fe013be4SDimitry Andric       return 0;
844fe013be4SDimitry Andric     m_selected_frame_idx = 0;
845fe013be4SDimitry Andric   }
846fe013be4SDimitry Andric   return *m_selected_frame_idx;
8470b57cec5SDimitry Andric }
8480b57cec5SDimitry Andric 
SetSelectedFrame(lldb_private::StackFrame * frame)8490b57cec5SDimitry Andric uint32_t StackFrameList::SetSelectedFrame(lldb_private::StackFrame *frame) {
8500b57cec5SDimitry Andric   std::lock_guard<std::recursive_mutex> guard(m_mutex);
8510b57cec5SDimitry Andric   const_iterator pos;
8520b57cec5SDimitry Andric   const_iterator begin = m_frames.begin();
8530b57cec5SDimitry Andric   const_iterator end = m_frames.end();
8540b57cec5SDimitry Andric   m_selected_frame_idx = 0;
855fe013be4SDimitry Andric 
8560b57cec5SDimitry Andric   for (pos = begin; pos != end; ++pos) {
8570b57cec5SDimitry Andric     if (pos->get() == frame) {
8580b57cec5SDimitry Andric       m_selected_frame_idx = std::distance(begin, pos);
8590b57cec5SDimitry Andric       uint32_t inlined_depth = GetCurrentInlinedDepth();
8600b57cec5SDimitry Andric       if (inlined_depth != UINT32_MAX)
861fe013be4SDimitry Andric         m_selected_frame_idx = *m_selected_frame_idx - inlined_depth;
8620b57cec5SDimitry Andric       break;
8630b57cec5SDimitry Andric     }
8640b57cec5SDimitry Andric   }
865fe013be4SDimitry Andric 
8660b57cec5SDimitry Andric   SetDefaultFileAndLineToSelectedFrame();
867fe013be4SDimitry Andric   return *m_selected_frame_idx;
8680b57cec5SDimitry Andric }
8690b57cec5SDimitry Andric 
SetSelectedFrameByIndex(uint32_t idx)8700b57cec5SDimitry Andric bool StackFrameList::SetSelectedFrameByIndex(uint32_t idx) {
8710b57cec5SDimitry Andric   std::lock_guard<std::recursive_mutex> guard(m_mutex);
8720b57cec5SDimitry Andric   StackFrameSP frame_sp(GetFrameAtIndex(idx));
8730b57cec5SDimitry Andric   if (frame_sp) {
8740b57cec5SDimitry Andric     SetSelectedFrame(frame_sp.get());
8750b57cec5SDimitry Andric     return true;
8760b57cec5SDimitry Andric   } else
8770b57cec5SDimitry Andric     return false;
8780b57cec5SDimitry Andric }
8790b57cec5SDimitry Andric 
SetDefaultFileAndLineToSelectedFrame()8800b57cec5SDimitry Andric void StackFrameList::SetDefaultFileAndLineToSelectedFrame() {
8810b57cec5SDimitry Andric   if (m_thread.GetID() ==
8820b57cec5SDimitry Andric       m_thread.GetProcess()->GetThreadList().GetSelectedThread()->GetID()) {
883fe013be4SDimitry Andric     StackFrameSP frame_sp(
884fe013be4SDimitry Andric         GetFrameAtIndex(GetSelectedFrameIndex(DoNoSelectMostRelevantFrame)));
8850b57cec5SDimitry Andric     if (frame_sp) {
8860b57cec5SDimitry Andric       SymbolContext sc = frame_sp->GetSymbolContext(eSymbolContextLineEntry);
8870b57cec5SDimitry Andric       if (sc.line_entry.file)
8880b57cec5SDimitry Andric         m_thread.CalculateTarget()->GetSourceManager().SetDefaultFileAndLine(
8890b57cec5SDimitry Andric             sc.line_entry.file, sc.line_entry.line);
8900b57cec5SDimitry Andric     }
8910b57cec5SDimitry Andric   }
8920b57cec5SDimitry Andric }
8930b57cec5SDimitry Andric 
8940b57cec5SDimitry Andric // The thread has been run, reset the number stack frames to zero so we can
8950b57cec5SDimitry Andric // determine how many frames we have lazily.
896fe013be4SDimitry Andric // Note, we don't actually re-use StackFrameLists, we always make a new
897fe013be4SDimitry Andric // StackFrameList every time we stop, and then copy frame information frame
898fe013be4SDimitry Andric // by frame from the old to the new StackFrameList.  So the comment above,
899fe013be4SDimitry Andric // does not describe how StackFrameLists are currently used.
900fe013be4SDimitry Andric // Clear is currently only used to clear the list in the destructor.
Clear()9010b57cec5SDimitry Andric void StackFrameList::Clear() {
9020b57cec5SDimitry Andric   std::lock_guard<std::recursive_mutex> guard(m_mutex);
9030b57cec5SDimitry Andric   m_frames.clear();
9040b57cec5SDimitry Andric   m_concrete_frames_fetched = 0;
905fe013be4SDimitry Andric   m_selected_frame_idx.reset();
9060b57cec5SDimitry Andric }
9070b57cec5SDimitry Andric 
9080b57cec5SDimitry Andric lldb::StackFrameSP
GetStackFrameSPForStackFramePtr(StackFrame * stack_frame_ptr)9090b57cec5SDimitry Andric StackFrameList::GetStackFrameSPForStackFramePtr(StackFrame *stack_frame_ptr) {
9100b57cec5SDimitry Andric   const_iterator pos;
9110b57cec5SDimitry Andric   const_iterator begin = m_frames.begin();
9120b57cec5SDimitry Andric   const_iterator end = m_frames.end();
9130b57cec5SDimitry Andric   lldb::StackFrameSP ret_sp;
9140b57cec5SDimitry Andric 
9150b57cec5SDimitry Andric   for (pos = begin; pos != end; ++pos) {
9160b57cec5SDimitry Andric     if (pos->get() == stack_frame_ptr) {
9170b57cec5SDimitry Andric       ret_sp = (*pos);
9180b57cec5SDimitry Andric       break;
9190b57cec5SDimitry Andric     }
9200b57cec5SDimitry Andric   }
9210b57cec5SDimitry Andric   return ret_sp;
9220b57cec5SDimitry Andric }
9230b57cec5SDimitry Andric 
GetStatus(Stream & strm,uint32_t first_frame,uint32_t num_frames,bool show_frame_info,uint32_t num_frames_with_source,bool show_unique,const char * selected_frame_marker)9240b57cec5SDimitry Andric size_t StackFrameList::GetStatus(Stream &strm, uint32_t first_frame,
9250b57cec5SDimitry Andric                                  uint32_t num_frames, bool show_frame_info,
9260b57cec5SDimitry Andric                                  uint32_t num_frames_with_source,
9270b57cec5SDimitry Andric                                  bool show_unique,
9280b57cec5SDimitry Andric                                  const char *selected_frame_marker) {
9290b57cec5SDimitry Andric   size_t num_frames_displayed = 0;
9300b57cec5SDimitry Andric 
9310b57cec5SDimitry Andric   if (num_frames == 0)
9320b57cec5SDimitry Andric     return 0;
9330b57cec5SDimitry Andric 
9340b57cec5SDimitry Andric   StackFrameSP frame_sp;
9350b57cec5SDimitry Andric   uint32_t frame_idx = 0;
9360b57cec5SDimitry Andric   uint32_t last_frame;
9370b57cec5SDimitry Andric 
9380b57cec5SDimitry Andric   // Don't let the last frame wrap around...
9390b57cec5SDimitry Andric   if (num_frames == UINT32_MAX)
9400b57cec5SDimitry Andric     last_frame = UINT32_MAX;
9410b57cec5SDimitry Andric   else
9420b57cec5SDimitry Andric     last_frame = first_frame + num_frames;
9430b57cec5SDimitry Andric 
944fe013be4SDimitry Andric   StackFrameSP selected_frame_sp =
945fe013be4SDimitry Andric       m_thread.GetSelectedFrame(DoNoSelectMostRelevantFrame);
9460b57cec5SDimitry Andric   const char *unselected_marker = nullptr;
9470b57cec5SDimitry Andric   std::string buffer;
9480b57cec5SDimitry Andric   if (selected_frame_marker) {
9490b57cec5SDimitry Andric     size_t len = strlen(selected_frame_marker);
9500b57cec5SDimitry Andric     buffer.insert(buffer.begin(), len, ' ');
9510b57cec5SDimitry Andric     unselected_marker = buffer.c_str();
9520b57cec5SDimitry Andric   }
9530b57cec5SDimitry Andric   const char *marker = nullptr;
9540b57cec5SDimitry Andric 
9550b57cec5SDimitry Andric   for (frame_idx = first_frame; frame_idx < last_frame; ++frame_idx) {
9560b57cec5SDimitry Andric     frame_sp = GetFrameAtIndex(frame_idx);
9570b57cec5SDimitry Andric     if (!frame_sp)
9580b57cec5SDimitry Andric       break;
9590b57cec5SDimitry Andric 
9600b57cec5SDimitry Andric     if (selected_frame_marker != nullptr) {
9610b57cec5SDimitry Andric       if (frame_sp == selected_frame_sp)
9620b57cec5SDimitry Andric         marker = selected_frame_marker;
9630b57cec5SDimitry Andric       else
9640b57cec5SDimitry Andric         marker = unselected_marker;
9650b57cec5SDimitry Andric     }
966fe013be4SDimitry Andric     // Check for interruption here.  If we're fetching arguments, this loop
967fe013be4SDimitry Andric     // can go slowly:
968fe013be4SDimitry Andric     Debugger &dbg = m_thread.GetProcess()->GetTarget().GetDebugger();
969fe013be4SDimitry Andric     if (INTERRUPT_REQUESTED(dbg,
970fe013be4SDimitry Andric           "Interrupted dumping stack for thread {0:hex} with {1} shown.",
971fe013be4SDimitry Andric           m_thread.GetID(), num_frames_displayed))
972fe013be4SDimitry Andric       break;
973fe013be4SDimitry Andric 
9740b57cec5SDimitry Andric 
9750b57cec5SDimitry Andric     if (!frame_sp->GetStatus(strm, show_frame_info,
9760b57cec5SDimitry Andric                              num_frames_with_source > (first_frame - frame_idx),
9770b57cec5SDimitry Andric                              show_unique, marker))
9780b57cec5SDimitry Andric       break;
9790b57cec5SDimitry Andric     ++num_frames_displayed;
9800b57cec5SDimitry Andric   }
9810b57cec5SDimitry Andric 
9820b57cec5SDimitry Andric   strm.IndentLess();
9830b57cec5SDimitry Andric   return num_frames_displayed;
9840b57cec5SDimitry Andric }
985