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"
120b57cec5SDimitry Andric #include "lldb/Core/SourceManager.h"
130b57cec5SDimitry Andric #include "lldb/Core/StreamFile.h"
140b57cec5SDimitry Andric #include "lldb/Symbol/Block.h"
150b57cec5SDimitry Andric #include "lldb/Symbol/Function.h"
160b57cec5SDimitry Andric #include "lldb/Symbol/Symbol.h"
170b57cec5SDimitry Andric #include "lldb/Target/Process.h"
180b57cec5SDimitry Andric #include "lldb/Target/RegisterContext.h"
190b57cec5SDimitry Andric #include "lldb/Target/StackFrame.h"
200b57cec5SDimitry Andric #include "lldb/Target/StopInfo.h"
210b57cec5SDimitry Andric #include "lldb/Target/Target.h"
220b57cec5SDimitry Andric #include "lldb/Target/Thread.h"
230b57cec5SDimitry Andric #include "lldb/Target/Unwind.h"
240b57cec5SDimitry Andric #include "lldb/Utility/Log.h"
250b57cec5SDimitry Andric #include "llvm/ADT/SmallPtrSet.h"
260b57cec5SDimitry Andric 
270b57cec5SDimitry Andric #include <memory>
280b57cec5SDimitry Andric 
290b57cec5SDimitry Andric //#define DEBUG_STACK_FRAMES 1
300b57cec5SDimitry Andric 
310b57cec5SDimitry Andric using namespace lldb;
320b57cec5SDimitry Andric using namespace lldb_private;
330b57cec5SDimitry Andric 
340b57cec5SDimitry Andric // StackFrameList constructor
StackFrameList(Thread & thread,const lldb::StackFrameListSP & prev_frames_sp,bool show_inline_frames)350b57cec5SDimitry Andric StackFrameList::StackFrameList(Thread &thread,
360b57cec5SDimitry Andric                                const lldb::StackFrameListSP &prev_frames_sp,
370b57cec5SDimitry Andric                                bool show_inline_frames)
380b57cec5SDimitry Andric     : m_thread(thread), m_prev_frames_sp(prev_frames_sp), m_mutex(), m_frames(),
390b57cec5SDimitry Andric       m_selected_frame_idx(0), m_concrete_frames_fetched(0),
400b57cec5SDimitry Andric       m_current_inlined_depth(UINT32_MAX),
410b57cec5SDimitry Andric       m_current_inlined_pc(LLDB_INVALID_ADDRESS),
420b57cec5SDimitry Andric       m_show_inlined_frames(show_inline_frames) {
430b57cec5SDimitry Andric   if (prev_frames_sp) {
440b57cec5SDimitry Andric     m_current_inlined_depth = prev_frames_sp->m_current_inlined_depth;
450b57cec5SDimitry Andric     m_current_inlined_pc = prev_frames_sp->m_current_inlined_pc;
460b57cec5SDimitry Andric   }
470b57cec5SDimitry Andric }
480b57cec5SDimitry Andric 
~StackFrameList()490b57cec5SDimitry Andric StackFrameList::~StackFrameList() {
500b57cec5SDimitry Andric   // Call clear since this takes a lock and clears the stack frame list in case
510b57cec5SDimitry Andric   // another thread is currently using this stack frame list
520b57cec5SDimitry Andric   Clear();
530b57cec5SDimitry Andric }
540b57cec5SDimitry Andric 
CalculateCurrentInlinedDepth()550b57cec5SDimitry Andric void StackFrameList::CalculateCurrentInlinedDepth() {
560b57cec5SDimitry Andric   uint32_t cur_inlined_depth = GetCurrentInlinedDepth();
570b57cec5SDimitry Andric   if (cur_inlined_depth == UINT32_MAX) {
580b57cec5SDimitry Andric     ResetCurrentInlinedDepth();
590b57cec5SDimitry Andric   }
600b57cec5SDimitry Andric }
610b57cec5SDimitry Andric 
GetCurrentInlinedDepth()620b57cec5SDimitry Andric uint32_t StackFrameList::GetCurrentInlinedDepth() {
630b57cec5SDimitry Andric   if (m_show_inlined_frames && m_current_inlined_pc != LLDB_INVALID_ADDRESS) {
640b57cec5SDimitry Andric     lldb::addr_t cur_pc = m_thread.GetRegisterContext()->GetPC();
650b57cec5SDimitry Andric     if (cur_pc != m_current_inlined_pc) {
660b57cec5SDimitry Andric       m_current_inlined_pc = LLDB_INVALID_ADDRESS;
670b57cec5SDimitry Andric       m_current_inlined_depth = UINT32_MAX;
680b57cec5SDimitry Andric       Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP));
690b57cec5SDimitry Andric       if (log && log->GetVerbose())
709dba64beSDimitry Andric         LLDB_LOGF(
719dba64beSDimitry Andric             log,
720b57cec5SDimitry Andric             "GetCurrentInlinedDepth: invalidating current inlined depth.\n");
730b57cec5SDimitry Andric     }
740b57cec5SDimitry Andric     return m_current_inlined_depth;
750b57cec5SDimitry Andric   } else {
760b57cec5SDimitry Andric     return UINT32_MAX;
770b57cec5SDimitry Andric   }
780b57cec5SDimitry Andric }
790b57cec5SDimitry Andric 
ResetCurrentInlinedDepth()800b57cec5SDimitry Andric void StackFrameList::ResetCurrentInlinedDepth() {
810b57cec5SDimitry Andric   if (!m_show_inlined_frames)
820b57cec5SDimitry Andric     return;
830b57cec5SDimitry Andric 
840b57cec5SDimitry Andric   std::lock_guard<std::recursive_mutex> guard(m_mutex);
850b57cec5SDimitry Andric 
860b57cec5SDimitry Andric   GetFramesUpTo(0);
870b57cec5SDimitry Andric   if (m_frames.empty())
880b57cec5SDimitry Andric     return;
890b57cec5SDimitry Andric   if (!m_frames[0]->IsInlined()) {
900b57cec5SDimitry Andric     m_current_inlined_depth = UINT32_MAX;
910b57cec5SDimitry Andric     m_current_inlined_pc = LLDB_INVALID_ADDRESS;
920b57cec5SDimitry Andric     Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP));
930b57cec5SDimitry Andric     if (log && log->GetVerbose())
949dba64beSDimitry Andric       LLDB_LOGF(
959dba64beSDimitry Andric           log,
960b57cec5SDimitry Andric           "ResetCurrentInlinedDepth: Invalidating current inlined depth.\n");
970b57cec5SDimitry Andric     return;
980b57cec5SDimitry Andric   }
990b57cec5SDimitry Andric 
1000b57cec5SDimitry Andric   // We only need to do something special about inlined blocks when we are
1010b57cec5SDimitry Andric   // at the beginning of an inlined function:
1020b57cec5SDimitry Andric   // FIXME: We probably also have to do something special if the PC is at
1030b57cec5SDimitry Andric   // the END of an inlined function, which coincides with the end of either
1040b57cec5SDimitry Andric   // its containing function or another inlined function.
1050b57cec5SDimitry Andric 
1060b57cec5SDimitry Andric   Block *block_ptr = m_frames[0]->GetFrameBlock();
1070b57cec5SDimitry Andric   if (!block_ptr)
1080b57cec5SDimitry Andric     return;
1090b57cec5SDimitry Andric 
1100b57cec5SDimitry Andric   Address pc_as_address;
1110b57cec5SDimitry Andric   lldb::addr_t curr_pc = m_thread.GetRegisterContext()->GetPC();
1120b57cec5SDimitry Andric   pc_as_address.SetLoadAddress(curr_pc, &(m_thread.GetProcess()->GetTarget()));
1130b57cec5SDimitry Andric   AddressRange containing_range;
1140b57cec5SDimitry Andric   if (!block_ptr->GetRangeContainingAddress(pc_as_address, containing_range) ||
1150b57cec5SDimitry Andric       pc_as_address != containing_range.GetBaseAddress())
1160b57cec5SDimitry Andric     return;
1170b57cec5SDimitry Andric 
1180b57cec5SDimitry Andric   // If we got here because of a breakpoint hit, then set the inlined depth
1190b57cec5SDimitry Andric   // depending on where the breakpoint was set. If we got here because of a
1200b57cec5SDimitry Andric   // crash, then set the inlined depth to the deepest most block.  Otherwise,
1210b57cec5SDimitry Andric   // we stopped here naturally as the result of a step, so set ourselves in the
1220b57cec5SDimitry Andric   // containing frame of the whole set of nested inlines, so the user can then
1230b57cec5SDimitry Andric   // "virtually" step into the frames one by one, or next over the whole mess.
1240b57cec5SDimitry Andric   // Note: We don't have to handle being somewhere in the middle of the stack
1250b57cec5SDimitry Andric   // here, since ResetCurrentInlinedDepth doesn't get called if there is a
1260b57cec5SDimitry Andric   // valid inlined depth set.
1270b57cec5SDimitry Andric   StopInfoSP stop_info_sp = m_thread.GetStopInfo();
1280b57cec5SDimitry Andric   if (!stop_info_sp)
1290b57cec5SDimitry Andric     return;
1300b57cec5SDimitry Andric   switch (stop_info_sp->GetStopReason()) {
1310b57cec5SDimitry Andric   case eStopReasonWatchpoint:
1320b57cec5SDimitry Andric   case eStopReasonException:
1330b57cec5SDimitry Andric   case eStopReasonExec:
134*5f7ddb14SDimitry Andric   case eStopReasonFork:
135*5f7ddb14SDimitry Andric   case eStopReasonVFork:
136*5f7ddb14SDimitry Andric   case eStopReasonVForkDone:
1370b57cec5SDimitry Andric   case eStopReasonSignal:
1380b57cec5SDimitry Andric     // In all these cases we want to stop in the deepest frame.
1390b57cec5SDimitry Andric     m_current_inlined_pc = curr_pc;
1400b57cec5SDimitry Andric     m_current_inlined_depth = 0;
1410b57cec5SDimitry Andric     break;
1420b57cec5SDimitry Andric   case eStopReasonBreakpoint: {
1430b57cec5SDimitry Andric     // FIXME: Figure out what this break point is doing, and set the inline
1440b57cec5SDimitry Andric     // depth appropriately.  Be careful to take into account breakpoints that
1450b57cec5SDimitry Andric     // implement step over prologue, since that should do the default
1460b57cec5SDimitry Andric     // calculation. For now, if the breakpoints corresponding to this hit are
1470b57cec5SDimitry Andric     // all internal, I set the stop location to the top of the inlined stack,
1480b57cec5SDimitry Andric     // since that will make things like stepping over prologues work right.
1490b57cec5SDimitry Andric     // But if there are any non-internal breakpoints I do to the bottom of the
1500b57cec5SDimitry Andric     // stack, since that was the old behavior.
1510b57cec5SDimitry Andric     uint32_t bp_site_id = stop_info_sp->GetValue();
1520b57cec5SDimitry Andric     BreakpointSiteSP bp_site_sp(
1530b57cec5SDimitry Andric         m_thread.GetProcess()->GetBreakpointSiteList().FindByID(bp_site_id));
1540b57cec5SDimitry Andric     bool all_internal = true;
1550b57cec5SDimitry Andric     if (bp_site_sp) {
1560b57cec5SDimitry Andric       uint32_t num_owners = bp_site_sp->GetNumberOfOwners();
1570b57cec5SDimitry Andric       for (uint32_t i = 0; i < num_owners; i++) {
1580b57cec5SDimitry Andric         Breakpoint &bp_ref = bp_site_sp->GetOwnerAtIndex(i)->GetBreakpoint();
1590b57cec5SDimitry Andric         if (!bp_ref.IsInternal()) {
1600b57cec5SDimitry Andric           all_internal = false;
1610b57cec5SDimitry Andric         }
1620b57cec5SDimitry Andric       }
1630b57cec5SDimitry Andric     }
1640b57cec5SDimitry Andric     if (!all_internal) {
1650b57cec5SDimitry Andric       m_current_inlined_pc = curr_pc;
1660b57cec5SDimitry Andric       m_current_inlined_depth = 0;
1670b57cec5SDimitry Andric       break;
1680b57cec5SDimitry Andric     }
1690b57cec5SDimitry Andric   }
1700b57cec5SDimitry Andric     LLVM_FALLTHROUGH;
1710b57cec5SDimitry Andric   default: {
1720b57cec5SDimitry Andric     // Otherwise, we should set ourselves at the container of the inlining, so
1730b57cec5SDimitry Andric     // that the user can descend into them. So first we check whether we have
1740b57cec5SDimitry Andric     // more than one inlined block sharing this PC:
1750b57cec5SDimitry Andric     int num_inlined_functions = 0;
1760b57cec5SDimitry Andric 
1770b57cec5SDimitry Andric     for (Block *container_ptr = block_ptr->GetInlinedParent();
1780b57cec5SDimitry Andric          container_ptr != nullptr;
1790b57cec5SDimitry Andric          container_ptr = container_ptr->GetInlinedParent()) {
1800b57cec5SDimitry Andric       if (!container_ptr->GetRangeContainingAddress(pc_as_address,
1810b57cec5SDimitry Andric                                                     containing_range))
1820b57cec5SDimitry Andric         break;
1830b57cec5SDimitry Andric       if (pc_as_address != containing_range.GetBaseAddress())
1840b57cec5SDimitry Andric         break;
1850b57cec5SDimitry Andric 
1860b57cec5SDimitry Andric       num_inlined_functions++;
1870b57cec5SDimitry Andric     }
1880b57cec5SDimitry Andric     m_current_inlined_pc = curr_pc;
1890b57cec5SDimitry Andric     m_current_inlined_depth = num_inlined_functions + 1;
1900b57cec5SDimitry Andric     Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP));
1910b57cec5SDimitry Andric     if (log && log->GetVerbose())
1929dba64beSDimitry Andric       LLDB_LOGF(log,
1939dba64beSDimitry Andric                 "ResetCurrentInlinedDepth: setting inlined "
1940b57cec5SDimitry Andric                 "depth: %d 0x%" PRIx64 ".\n",
1950b57cec5SDimitry Andric                 m_current_inlined_depth, curr_pc);
1960b57cec5SDimitry Andric 
1970b57cec5SDimitry Andric     break;
1980b57cec5SDimitry Andric   }
1990b57cec5SDimitry Andric   }
2000b57cec5SDimitry Andric }
2010b57cec5SDimitry Andric 
DecrementCurrentInlinedDepth()2020b57cec5SDimitry Andric bool StackFrameList::DecrementCurrentInlinedDepth() {
2030b57cec5SDimitry Andric   if (m_show_inlined_frames) {
2040b57cec5SDimitry Andric     uint32_t current_inlined_depth = GetCurrentInlinedDepth();
2050b57cec5SDimitry Andric     if (current_inlined_depth != UINT32_MAX) {
2060b57cec5SDimitry Andric       if (current_inlined_depth > 0) {
2070b57cec5SDimitry Andric         m_current_inlined_depth--;
2080b57cec5SDimitry Andric         return true;
2090b57cec5SDimitry Andric       }
2100b57cec5SDimitry Andric     }
2110b57cec5SDimitry Andric   }
2120b57cec5SDimitry Andric   return false;
2130b57cec5SDimitry Andric }
2140b57cec5SDimitry Andric 
SetCurrentInlinedDepth(uint32_t new_depth)2150b57cec5SDimitry Andric void StackFrameList::SetCurrentInlinedDepth(uint32_t new_depth) {
2160b57cec5SDimitry Andric   m_current_inlined_depth = new_depth;
2170b57cec5SDimitry Andric   if (new_depth == UINT32_MAX)
2180b57cec5SDimitry Andric     m_current_inlined_pc = LLDB_INVALID_ADDRESS;
2190b57cec5SDimitry Andric   else
2200b57cec5SDimitry Andric     m_current_inlined_pc = m_thread.GetRegisterContext()->GetPC();
2210b57cec5SDimitry Andric }
2220b57cec5SDimitry Andric 
GetOnlyConcreteFramesUpTo(uint32_t end_idx,Unwind & unwinder)2230b57cec5SDimitry Andric void StackFrameList::GetOnlyConcreteFramesUpTo(uint32_t end_idx,
2245ffd83dbSDimitry Andric                                                Unwind &unwinder) {
2250b57cec5SDimitry Andric   assert(m_thread.IsValid() && "Expected valid thread");
2260b57cec5SDimitry Andric   assert(m_frames.size() <= end_idx && "Expected there to be frames to fill");
2270b57cec5SDimitry Andric 
2280b57cec5SDimitry Andric   if (end_idx < m_concrete_frames_fetched)
2290b57cec5SDimitry Andric     return;
2300b57cec5SDimitry Andric 
2315ffd83dbSDimitry Andric   uint32_t num_frames = unwinder.GetFramesUpTo(end_idx);
2320b57cec5SDimitry Andric   if (num_frames <= end_idx + 1) {
2330b57cec5SDimitry Andric     // Done unwinding.
2340b57cec5SDimitry Andric     m_concrete_frames_fetched = UINT32_MAX;
2350b57cec5SDimitry Andric   }
2360b57cec5SDimitry Andric 
2370b57cec5SDimitry Andric   // Don't create the frames eagerly. Defer this work to GetFrameAtIndex,
2380b57cec5SDimitry Andric   // which can lazily query the unwinder to create frames.
2390b57cec5SDimitry Andric   m_frames.resize(num_frames);
2400b57cec5SDimitry Andric }
2410b57cec5SDimitry Andric 
2425ffd83dbSDimitry Andric /// A sequence of calls that comprise some portion of a backtrace. Each frame
2435ffd83dbSDimitry Andric /// is represented as a pair of a callee (Function *) and an address within the
2445ffd83dbSDimitry Andric /// callee.
2455ffd83dbSDimitry Andric struct CallDescriptor {
2465ffd83dbSDimitry Andric   Function *func;
2475ffd83dbSDimitry Andric   CallEdge::AddrType address_type = CallEdge::AddrType::Call;
2485ffd83dbSDimitry Andric   addr_t address = LLDB_INVALID_ADDRESS;
2495ffd83dbSDimitry Andric };
2505ffd83dbSDimitry Andric using CallSequence = std::vector<CallDescriptor>;
2515ffd83dbSDimitry Andric 
2520b57cec5SDimitry Andric /// Find the unique path through the call graph from \p begin (with return PC
2530b57cec5SDimitry Andric /// \p return_pc) to \p end. On success this path is stored into \p path, and
2540b57cec5SDimitry 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)2550b57cec5SDimitry Andric static void FindInterveningFrames(Function &begin, Function &end,
256480093f4SDimitry Andric                                   ExecutionContext &exe_ctx, Target &target,
2575ffd83dbSDimitry Andric                                   addr_t return_pc, CallSequence &path,
2580b57cec5SDimitry Andric                                   ModuleList &images, Log *log) {
2590b57cec5SDimitry Andric   LLDB_LOG(log, "Finding frames between {0} and {1}, retn-pc={2:x}",
2600b57cec5SDimitry Andric            begin.GetDisplayName(), end.GetDisplayName(), return_pc);
2610b57cec5SDimitry Andric 
2620b57cec5SDimitry Andric   // Find a non-tail calling edge with the correct return PC.
2630b57cec5SDimitry Andric   if (log)
264480093f4SDimitry Andric     for (const auto &edge : begin.GetCallEdges())
2650b57cec5SDimitry Andric       LLDB_LOG(log, "FindInterveningFrames: found call with retn-PC = {0:x}",
266480093f4SDimitry Andric                edge->GetReturnPCAddress(begin, target));
2679dba64beSDimitry Andric   CallEdge *first_edge = begin.GetCallEdgeForReturnAddress(return_pc, target);
2689dba64beSDimitry Andric   if (!first_edge) {
2690b57cec5SDimitry Andric     LLDB_LOG(log, "No call edge outgoing from {0} with retn-PC == {1:x}",
2700b57cec5SDimitry Andric              begin.GetDisplayName(), return_pc);
2710b57cec5SDimitry Andric     return;
2720b57cec5SDimitry Andric   }
2730b57cec5SDimitry Andric 
2740b57cec5SDimitry Andric   // The first callee may not be resolved, or there may be nothing to fill in.
275480093f4SDimitry Andric   Function *first_callee = first_edge->GetCallee(images, exe_ctx);
2760b57cec5SDimitry Andric   if (!first_callee) {
2770b57cec5SDimitry Andric     LLDB_LOG(log, "Could not resolve callee");
2780b57cec5SDimitry Andric     return;
2790b57cec5SDimitry Andric   }
2800b57cec5SDimitry Andric   if (first_callee == &end) {
2810b57cec5SDimitry Andric     LLDB_LOG(log, "Not searching further, first callee is {0} (retn-PC: {1:x})",
2820b57cec5SDimitry Andric              end.GetDisplayName(), return_pc);
2830b57cec5SDimitry Andric     return;
2840b57cec5SDimitry Andric   }
2850b57cec5SDimitry Andric 
2860b57cec5SDimitry Andric   // Run DFS on the tail-calling edges out of the first callee to find \p end.
2870b57cec5SDimitry Andric   // Fully explore the set of functions reachable from the first edge via tail
2880b57cec5SDimitry Andric   // calls in order to detect ambiguous executions.
2890b57cec5SDimitry Andric   struct DFS {
2905ffd83dbSDimitry Andric     CallSequence active_path = {};
2915ffd83dbSDimitry Andric     CallSequence solution_path = {};
2920b57cec5SDimitry Andric     llvm::SmallPtrSet<Function *, 2> visited_nodes = {};
2930b57cec5SDimitry Andric     bool ambiguous = false;
2940b57cec5SDimitry Andric     Function *end;
2950b57cec5SDimitry Andric     ModuleList &images;
2965ffd83dbSDimitry Andric     Target &target;
297480093f4SDimitry Andric     ExecutionContext &context;
2980b57cec5SDimitry Andric 
2995ffd83dbSDimitry Andric     DFS(Function *end, ModuleList &images, Target &target,
3005ffd83dbSDimitry Andric         ExecutionContext &context)
3015ffd83dbSDimitry Andric         : end(end), images(images), target(target), context(context) {}
3020b57cec5SDimitry Andric 
3035ffd83dbSDimitry Andric     void search(CallEdge &first_edge, Function &first_callee,
3045ffd83dbSDimitry Andric                 CallSequence &path) {
3055ffd83dbSDimitry Andric       dfs(first_edge, first_callee);
3060b57cec5SDimitry Andric       if (!ambiguous)
3070b57cec5SDimitry Andric         path = std::move(solution_path);
3080b57cec5SDimitry Andric     }
3090b57cec5SDimitry Andric 
3105ffd83dbSDimitry Andric     void dfs(CallEdge &current_edge, Function &callee) {
3110b57cec5SDimitry Andric       // Found a path to the target function.
3129dba64beSDimitry Andric       if (&callee == end) {
3130b57cec5SDimitry Andric         if (solution_path.empty())
3140b57cec5SDimitry Andric           solution_path = active_path;
3150b57cec5SDimitry Andric         else
3160b57cec5SDimitry Andric           ambiguous = true;
3170b57cec5SDimitry Andric         return;
3180b57cec5SDimitry Andric       }
3190b57cec5SDimitry Andric 
3200b57cec5SDimitry Andric       // Terminate the search if tail recursion is found, or more generally if
3210b57cec5SDimitry Andric       // there's more than one way to reach a target. This errs on the side of
3220b57cec5SDimitry Andric       // caution: it conservatively stops searching when some solutions are
3230b57cec5SDimitry Andric       // still possible to save time in the average case.
3249dba64beSDimitry Andric       if (!visited_nodes.insert(&callee).second) {
3250b57cec5SDimitry Andric         ambiguous = true;
3260b57cec5SDimitry Andric         return;
3270b57cec5SDimitry Andric       }
3280b57cec5SDimitry Andric 
3290b57cec5SDimitry Andric       // Search the calls made from this callee.
3305ffd83dbSDimitry Andric       active_path.push_back(CallDescriptor{&callee});
331480093f4SDimitry Andric       for (const auto &edge : callee.GetTailCallingEdges()) {
332480093f4SDimitry Andric         Function *next_callee = edge->GetCallee(images, context);
3330b57cec5SDimitry Andric         if (!next_callee)
3340b57cec5SDimitry Andric           continue;
3350b57cec5SDimitry Andric 
3365ffd83dbSDimitry Andric         std::tie(active_path.back().address_type, active_path.back().address) =
3375ffd83dbSDimitry Andric             edge->GetCallerAddress(callee, target);
3385ffd83dbSDimitry Andric 
3395ffd83dbSDimitry Andric         dfs(*edge, *next_callee);
3400b57cec5SDimitry Andric         if (ambiguous)
3410b57cec5SDimitry Andric           return;
3420b57cec5SDimitry Andric       }
3430b57cec5SDimitry Andric       active_path.pop_back();
3440b57cec5SDimitry Andric     }
3450b57cec5SDimitry Andric   };
3460b57cec5SDimitry Andric 
3475ffd83dbSDimitry Andric   DFS(&end, images, target, exe_ctx).search(*first_edge, *first_callee, path);
3480b57cec5SDimitry Andric }
3490b57cec5SDimitry Andric 
3500b57cec5SDimitry Andric /// Given that \p next_frame will be appended to the frame list, synthesize
3510b57cec5SDimitry Andric /// tail call frames between the current end of the list and \p next_frame.
3520b57cec5SDimitry Andric /// If any frames are added, adjust the frame index of \p next_frame.
3530b57cec5SDimitry Andric ///
3540b57cec5SDimitry Andric ///   --------------
3550b57cec5SDimitry Andric ///   |    ...     | <- Completed frames.
3560b57cec5SDimitry Andric ///   --------------
3570b57cec5SDimitry Andric ///   | prev_frame |
3580b57cec5SDimitry Andric ///   --------------
3590b57cec5SDimitry Andric ///   |    ...     | <- Artificial frames inserted here.
3600b57cec5SDimitry Andric ///   --------------
3610b57cec5SDimitry Andric ///   | next_frame |
3620b57cec5SDimitry Andric ///   --------------
3630b57cec5SDimitry Andric ///   |    ...     | <- Not-yet-visited frames.
3640b57cec5SDimitry Andric ///   --------------
SynthesizeTailCallFrames(StackFrame & next_frame)3650b57cec5SDimitry Andric void StackFrameList::SynthesizeTailCallFrames(StackFrame &next_frame) {
3665ffd83dbSDimitry Andric   // Cannot synthesize tail call frames when the stack is empty (there is no
3675ffd83dbSDimitry Andric   // "previous" frame).
3685ffd83dbSDimitry Andric   if (m_frames.empty())
3695ffd83dbSDimitry Andric     return;
3705ffd83dbSDimitry Andric 
3710b57cec5SDimitry Andric   TargetSP target_sp = next_frame.CalculateTarget();
3720b57cec5SDimitry Andric   if (!target_sp)
3730b57cec5SDimitry Andric     return;
3740b57cec5SDimitry Andric 
3750b57cec5SDimitry Andric   lldb::RegisterContextSP next_reg_ctx_sp = next_frame.GetRegisterContext();
3760b57cec5SDimitry Andric   if (!next_reg_ctx_sp)
3770b57cec5SDimitry Andric     return;
3780b57cec5SDimitry Andric 
3790b57cec5SDimitry Andric   Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP));
3800b57cec5SDimitry Andric 
3810b57cec5SDimitry Andric   StackFrame &prev_frame = *m_frames.back().get();
3820b57cec5SDimitry Andric 
3830b57cec5SDimitry Andric   // Find the functions prev_frame and next_frame are stopped in. The function
3840b57cec5SDimitry Andric   // objects are needed to search the lazy call graph for intervening frames.
3850b57cec5SDimitry Andric   Function *prev_func =
3860b57cec5SDimitry Andric       prev_frame.GetSymbolContext(eSymbolContextFunction).function;
3870b57cec5SDimitry Andric   if (!prev_func) {
3880b57cec5SDimitry Andric     LLDB_LOG(log, "SynthesizeTailCallFrames: can't find previous function");
3890b57cec5SDimitry Andric     return;
3900b57cec5SDimitry Andric   }
3910b57cec5SDimitry Andric   Function *next_func =
3920b57cec5SDimitry Andric       next_frame.GetSymbolContext(eSymbolContextFunction).function;
3930b57cec5SDimitry Andric   if (!next_func) {
3940b57cec5SDimitry Andric     LLDB_LOG(log, "SynthesizeTailCallFrames: can't find next function");
3950b57cec5SDimitry Andric     return;
3960b57cec5SDimitry Andric   }
3970b57cec5SDimitry Andric 
3980b57cec5SDimitry Andric   // Try to find the unique sequence of (tail) calls which led from next_frame
3990b57cec5SDimitry Andric   // to prev_frame.
4005ffd83dbSDimitry Andric   CallSequence path;
4010b57cec5SDimitry Andric   addr_t return_pc = next_reg_ctx_sp->GetPC();
4020b57cec5SDimitry Andric   Target &target = *target_sp.get();
4030b57cec5SDimitry Andric   ModuleList &images = next_frame.CalculateTarget()->GetImages();
404480093f4SDimitry Andric   ExecutionContext exe_ctx(target_sp, /*get_process=*/true);
405480093f4SDimitry Andric   exe_ctx.SetFramePtr(&next_frame);
406480093f4SDimitry Andric   FindInterveningFrames(*next_func, *prev_func, exe_ctx, target, return_pc,
407480093f4SDimitry Andric                         path, images, log);
4080b57cec5SDimitry Andric 
4090b57cec5SDimitry Andric   // Push synthetic tail call frames.
4105ffd83dbSDimitry Andric   for (auto calleeInfo : llvm::reverse(path)) {
4115ffd83dbSDimitry Andric     Function *callee = calleeInfo.func;
4120b57cec5SDimitry Andric     uint32_t frame_idx = m_frames.size();
4130b57cec5SDimitry Andric     uint32_t concrete_frame_idx = next_frame.GetConcreteFrameIndex();
4140b57cec5SDimitry Andric     addr_t cfa = LLDB_INVALID_ADDRESS;
4150b57cec5SDimitry Andric     bool cfa_is_valid = false;
4165ffd83dbSDimitry Andric     addr_t pc = calleeInfo.address;
4175ffd83dbSDimitry Andric     // If the callee address refers to the call instruction, we do not want to
4185ffd83dbSDimitry Andric     // subtract 1 from this value.
4195ffd83dbSDimitry Andric     const bool behaves_like_zeroth_frame =
4205ffd83dbSDimitry Andric         calleeInfo.address_type == CallEdge::AddrType::Call;
4210b57cec5SDimitry Andric     SymbolContext sc;
4220b57cec5SDimitry Andric     callee->CalculateSymbolContext(&sc);
4230b57cec5SDimitry Andric     auto synth_frame = std::make_shared<StackFrame>(
4240b57cec5SDimitry Andric         m_thread.shared_from_this(), frame_idx, concrete_frame_idx, cfa,
4259dba64beSDimitry Andric         cfa_is_valid, pc, StackFrame::Kind::Artificial,
4269dba64beSDimitry Andric         behaves_like_zeroth_frame, &sc);
4270b57cec5SDimitry Andric     m_frames.push_back(synth_frame);
4285ffd83dbSDimitry Andric     LLDB_LOG(log, "Pushed frame {0} at {1:x}", callee->GetDisplayName(), pc);
4290b57cec5SDimitry Andric   }
4300b57cec5SDimitry Andric 
4310b57cec5SDimitry Andric   // If any frames were created, adjust next_frame's index.
4320b57cec5SDimitry Andric   if (!path.empty())
4330b57cec5SDimitry Andric     next_frame.SetFrameIndex(m_frames.size());
4340b57cec5SDimitry Andric }
4350b57cec5SDimitry Andric 
GetFramesUpTo(uint32_t end_idx)4360b57cec5SDimitry Andric void StackFrameList::GetFramesUpTo(uint32_t end_idx) {
4370b57cec5SDimitry Andric   // Do not fetch frames for an invalid thread.
4380b57cec5SDimitry Andric   if (!m_thread.IsValid())
4390b57cec5SDimitry Andric     return;
4400b57cec5SDimitry Andric 
4410b57cec5SDimitry Andric   // We've already gotten more frames than asked for, or we've already finished
4420b57cec5SDimitry Andric   // unwinding, return.
4430b57cec5SDimitry Andric   if (m_frames.size() > end_idx || GetAllFramesFetched())
4440b57cec5SDimitry Andric     return;
4450b57cec5SDimitry Andric 
4465ffd83dbSDimitry Andric   Unwind &unwinder = m_thread.GetUnwinder();
4470b57cec5SDimitry Andric 
4480b57cec5SDimitry Andric   if (!m_show_inlined_frames) {
4490b57cec5SDimitry Andric     GetOnlyConcreteFramesUpTo(end_idx, unwinder);
4500b57cec5SDimitry Andric     return;
4510b57cec5SDimitry Andric   }
4520b57cec5SDimitry Andric 
4530b57cec5SDimitry Andric #if defined(DEBUG_STACK_FRAMES)
4540b57cec5SDimitry Andric   StreamFile s(stdout, false);
4550b57cec5SDimitry Andric #endif
4560b57cec5SDimitry Andric   // If we are hiding some frames from the outside world, we need to add
4570b57cec5SDimitry Andric   // those onto the total count of frames to fetch.  However, we don't need
4580b57cec5SDimitry Andric   // to do that if end_idx is 0 since in that case we always get the first
4590b57cec5SDimitry Andric   // concrete frame and all the inlined frames below it...  And of course, if
4600b57cec5SDimitry Andric   // end_idx is UINT32_MAX that means get all, so just do that...
4610b57cec5SDimitry Andric 
4620b57cec5SDimitry Andric   uint32_t inlined_depth = 0;
4630b57cec5SDimitry Andric   if (end_idx > 0 && end_idx != UINT32_MAX) {
4640b57cec5SDimitry Andric     inlined_depth = GetCurrentInlinedDepth();
4650b57cec5SDimitry Andric     if (inlined_depth != UINT32_MAX) {
4660b57cec5SDimitry Andric       if (end_idx > 0)
4670b57cec5SDimitry Andric         end_idx += inlined_depth;
4680b57cec5SDimitry Andric     }
4690b57cec5SDimitry Andric   }
4700b57cec5SDimitry Andric 
4710b57cec5SDimitry Andric   StackFrameSP unwind_frame_sp;
4720b57cec5SDimitry Andric   do {
4730b57cec5SDimitry Andric     uint32_t idx = m_concrete_frames_fetched++;
4740b57cec5SDimitry Andric     lldb::addr_t pc = LLDB_INVALID_ADDRESS;
4750b57cec5SDimitry Andric     lldb::addr_t cfa = LLDB_INVALID_ADDRESS;
4769dba64beSDimitry Andric     bool behaves_like_zeroth_frame = (idx == 0);
4770b57cec5SDimitry Andric     if (idx == 0) {
4780b57cec5SDimitry Andric       // We might have already created frame zero, only create it if we need
4790b57cec5SDimitry Andric       // to.
4800b57cec5SDimitry Andric       if (m_frames.empty()) {
4810b57cec5SDimitry Andric         RegisterContextSP reg_ctx_sp(m_thread.GetRegisterContext());
4820b57cec5SDimitry Andric 
4830b57cec5SDimitry Andric         if (reg_ctx_sp) {
4845ffd83dbSDimitry Andric           const bool success = unwinder.GetFrameInfoAtIndex(
4859dba64beSDimitry Andric               idx, cfa, pc, behaves_like_zeroth_frame);
4860b57cec5SDimitry Andric           // There shouldn't be any way not to get the frame info for frame
4870b57cec5SDimitry Andric           // 0. But if the unwinder can't make one, lets make one by hand
4880b57cec5SDimitry Andric           // with the SP as the CFA and see if that gets any further.
4890b57cec5SDimitry Andric           if (!success) {
4900b57cec5SDimitry Andric             cfa = reg_ctx_sp->GetSP();
4910b57cec5SDimitry Andric             pc = reg_ctx_sp->GetPC();
4920b57cec5SDimitry Andric           }
4930b57cec5SDimitry Andric 
4940b57cec5SDimitry Andric           unwind_frame_sp = std::make_shared<StackFrame>(
4950b57cec5SDimitry Andric               m_thread.shared_from_this(), m_frames.size(), idx, reg_ctx_sp,
4969dba64beSDimitry Andric               cfa, pc, behaves_like_zeroth_frame, nullptr);
4970b57cec5SDimitry Andric           m_frames.push_back(unwind_frame_sp);
4980b57cec5SDimitry Andric         }
4990b57cec5SDimitry Andric       } else {
5000b57cec5SDimitry Andric         unwind_frame_sp = m_frames.front();
5010b57cec5SDimitry Andric         cfa = unwind_frame_sp->m_id.GetCallFrameAddress();
5020b57cec5SDimitry Andric       }
5030b57cec5SDimitry Andric     } else {
5045ffd83dbSDimitry Andric       const bool success =
5055ffd83dbSDimitry Andric           unwinder.GetFrameInfoAtIndex(idx, cfa, pc, behaves_like_zeroth_frame);
5060b57cec5SDimitry Andric       if (!success) {
5070b57cec5SDimitry Andric         // We've gotten to the end of the stack.
5080b57cec5SDimitry Andric         SetAllFramesFetched();
5090b57cec5SDimitry Andric         break;
5100b57cec5SDimitry Andric       }
5110b57cec5SDimitry Andric       const bool cfa_is_valid = true;
5120b57cec5SDimitry Andric       unwind_frame_sp = std::make_shared<StackFrame>(
5130b57cec5SDimitry Andric           m_thread.shared_from_this(), m_frames.size(), idx, cfa, cfa_is_valid,
5149dba64beSDimitry Andric           pc, StackFrame::Kind::Regular, behaves_like_zeroth_frame, nullptr);
5150b57cec5SDimitry Andric 
5160b57cec5SDimitry Andric       // Create synthetic tail call frames between the previous frame and the
5170b57cec5SDimitry Andric       // newly-found frame. The new frame's index may change after this call,
5180b57cec5SDimitry Andric       // although its concrete index will stay the same.
5190b57cec5SDimitry Andric       SynthesizeTailCallFrames(*unwind_frame_sp.get());
5200b57cec5SDimitry Andric 
5210b57cec5SDimitry Andric       m_frames.push_back(unwind_frame_sp);
5220b57cec5SDimitry Andric     }
5230b57cec5SDimitry Andric 
5240b57cec5SDimitry Andric     assert(unwind_frame_sp);
5250b57cec5SDimitry Andric     SymbolContext unwind_sc = unwind_frame_sp->GetSymbolContext(
5260b57cec5SDimitry Andric         eSymbolContextBlock | eSymbolContextFunction);
5270b57cec5SDimitry Andric     Block *unwind_block = unwind_sc.block;
5280b57cec5SDimitry Andric     TargetSP target_sp = m_thread.CalculateTarget();
529*5f7ddb14SDimitry Andric     if (unwind_block) {
530*5f7ddb14SDimitry Andric       Address curr_frame_address(
531*5f7ddb14SDimitry Andric           unwind_frame_sp->GetFrameCodeAddressForSymbolication());
5320b57cec5SDimitry Andric 
5330b57cec5SDimitry Andric       SymbolContext next_frame_sc;
5340b57cec5SDimitry Andric       Address next_frame_address;
5350b57cec5SDimitry Andric 
5360b57cec5SDimitry Andric       while (unwind_sc.GetParentOfInlinedScope(
5370b57cec5SDimitry Andric           curr_frame_address, next_frame_sc, next_frame_address)) {
5380b57cec5SDimitry Andric         next_frame_sc.line_entry.ApplyFileMappings(target_sp);
5399dba64beSDimitry Andric         behaves_like_zeroth_frame = false;
5409dba64beSDimitry Andric         StackFrameSP frame_sp(new StackFrame(
5419dba64beSDimitry Andric             m_thread.shared_from_this(), m_frames.size(), idx,
5429dba64beSDimitry Andric             unwind_frame_sp->GetRegisterContextSP(), cfa, next_frame_address,
5439dba64beSDimitry Andric             behaves_like_zeroth_frame, &next_frame_sc));
5440b57cec5SDimitry Andric 
5450b57cec5SDimitry Andric         m_frames.push_back(frame_sp);
5460b57cec5SDimitry Andric         unwind_sc = next_frame_sc;
5470b57cec5SDimitry Andric         curr_frame_address = next_frame_address;
5480b57cec5SDimitry Andric       }
5490b57cec5SDimitry Andric     }
5500b57cec5SDimitry Andric   } while (m_frames.size() - 1 < end_idx);
5510b57cec5SDimitry Andric 
5520b57cec5SDimitry Andric   // Don't try to merge till you've calculated all the frames in this stack.
5530b57cec5SDimitry Andric   if (GetAllFramesFetched() && m_prev_frames_sp) {
5540b57cec5SDimitry Andric     StackFrameList *prev_frames = m_prev_frames_sp.get();
5550b57cec5SDimitry Andric     StackFrameList *curr_frames = this;
5560b57cec5SDimitry Andric 
5570b57cec5SDimitry Andric #if defined(DEBUG_STACK_FRAMES)
5580b57cec5SDimitry Andric     s.PutCString("\nprev_frames:\n");
5590b57cec5SDimitry Andric     prev_frames->Dump(&s);
5600b57cec5SDimitry Andric     s.PutCString("\ncurr_frames:\n");
5610b57cec5SDimitry Andric     curr_frames->Dump(&s);
5620b57cec5SDimitry Andric     s.EOL();
5630b57cec5SDimitry Andric #endif
5640b57cec5SDimitry Andric     size_t curr_frame_num, prev_frame_num;
5650b57cec5SDimitry Andric 
5660b57cec5SDimitry Andric     for (curr_frame_num = curr_frames->m_frames.size(),
5670b57cec5SDimitry Andric         prev_frame_num = prev_frames->m_frames.size();
5680b57cec5SDimitry Andric          curr_frame_num > 0 && prev_frame_num > 0;
5690b57cec5SDimitry Andric          --curr_frame_num, --prev_frame_num) {
5700b57cec5SDimitry Andric       const size_t curr_frame_idx = curr_frame_num - 1;
5710b57cec5SDimitry Andric       const size_t prev_frame_idx = prev_frame_num - 1;
5720b57cec5SDimitry Andric       StackFrameSP curr_frame_sp(curr_frames->m_frames[curr_frame_idx]);
5730b57cec5SDimitry Andric       StackFrameSP prev_frame_sp(prev_frames->m_frames[prev_frame_idx]);
5740b57cec5SDimitry Andric 
5750b57cec5SDimitry Andric #if defined(DEBUG_STACK_FRAMES)
5760b57cec5SDimitry Andric       s.Printf("\n\nCurr frame #%u ", curr_frame_idx);
5770b57cec5SDimitry Andric       if (curr_frame_sp)
5780b57cec5SDimitry Andric         curr_frame_sp->Dump(&s, true, false);
5790b57cec5SDimitry Andric       else
5800b57cec5SDimitry Andric         s.PutCString("NULL");
5810b57cec5SDimitry Andric       s.Printf("\nPrev frame #%u ", prev_frame_idx);
5820b57cec5SDimitry Andric       if (prev_frame_sp)
5830b57cec5SDimitry Andric         prev_frame_sp->Dump(&s, true, false);
5840b57cec5SDimitry Andric       else
5850b57cec5SDimitry Andric         s.PutCString("NULL");
5860b57cec5SDimitry Andric #endif
5870b57cec5SDimitry Andric 
5880b57cec5SDimitry Andric       StackFrame *curr_frame = curr_frame_sp.get();
5890b57cec5SDimitry Andric       StackFrame *prev_frame = prev_frame_sp.get();
5900b57cec5SDimitry Andric 
5910b57cec5SDimitry Andric       if (curr_frame == nullptr || prev_frame == nullptr)
5920b57cec5SDimitry Andric         break;
5930b57cec5SDimitry Andric 
5940b57cec5SDimitry Andric       // Check the stack ID to make sure they are equal.
5950b57cec5SDimitry Andric       if (curr_frame->GetStackID() != prev_frame->GetStackID())
5960b57cec5SDimitry Andric         break;
5970b57cec5SDimitry Andric 
5980b57cec5SDimitry Andric       prev_frame->UpdatePreviousFrameFromCurrentFrame(*curr_frame);
5990b57cec5SDimitry Andric       // Now copy the fixed up previous frame into the current frames so the
6000b57cec5SDimitry Andric       // pointer doesn't change.
6010b57cec5SDimitry Andric       m_frames[curr_frame_idx] = prev_frame_sp;
6020b57cec5SDimitry Andric 
6030b57cec5SDimitry Andric #if defined(DEBUG_STACK_FRAMES)
6040b57cec5SDimitry Andric       s.Printf("\n    Copying previous frame to current frame");
6050b57cec5SDimitry Andric #endif
6060b57cec5SDimitry Andric     }
6070b57cec5SDimitry Andric     // We are done with the old stack frame list, we can release it now.
6080b57cec5SDimitry Andric     m_prev_frames_sp.reset();
6090b57cec5SDimitry Andric   }
6100b57cec5SDimitry Andric 
6110b57cec5SDimitry Andric #if defined(DEBUG_STACK_FRAMES)
6120b57cec5SDimitry Andric   s.PutCString("\n\nNew frames:\n");
6130b57cec5SDimitry Andric   Dump(&s);
6140b57cec5SDimitry Andric   s.EOL();
6150b57cec5SDimitry Andric #endif
6160b57cec5SDimitry Andric }
6170b57cec5SDimitry Andric 
GetNumFrames(bool can_create)6180b57cec5SDimitry Andric uint32_t StackFrameList::GetNumFrames(bool can_create) {
6190b57cec5SDimitry Andric   std::lock_guard<std::recursive_mutex> guard(m_mutex);
6200b57cec5SDimitry Andric 
6210b57cec5SDimitry Andric   if (can_create)
6220b57cec5SDimitry Andric     GetFramesUpTo(UINT32_MAX);
6230b57cec5SDimitry Andric 
6240b57cec5SDimitry Andric   return GetVisibleStackFrameIndex(m_frames.size());
6250b57cec5SDimitry Andric }
6260b57cec5SDimitry Andric 
Dump(Stream * s)6270b57cec5SDimitry Andric void StackFrameList::Dump(Stream *s) {
6280b57cec5SDimitry Andric   if (s == nullptr)
6290b57cec5SDimitry Andric     return;
6300b57cec5SDimitry Andric 
6310b57cec5SDimitry Andric   std::lock_guard<std::recursive_mutex> guard(m_mutex);
6320b57cec5SDimitry Andric 
6330b57cec5SDimitry Andric   const_iterator pos, begin = m_frames.begin(), end = m_frames.end();
6340b57cec5SDimitry Andric   for (pos = begin; pos != end; ++pos) {
6350b57cec5SDimitry Andric     StackFrame *frame = (*pos).get();
6360b57cec5SDimitry Andric     s->Printf("%p: ", static_cast<void *>(frame));
6370b57cec5SDimitry Andric     if (frame) {
6380b57cec5SDimitry Andric       frame->GetStackID().Dump(s);
6390b57cec5SDimitry Andric       frame->DumpUsingSettingsFormat(s);
6400b57cec5SDimitry Andric     } else
6410b57cec5SDimitry Andric       s->Printf("frame #%u", (uint32_t)std::distance(begin, pos));
6420b57cec5SDimitry Andric     s->EOL();
6430b57cec5SDimitry Andric   }
6440b57cec5SDimitry Andric   s->EOL();
6450b57cec5SDimitry Andric }
6460b57cec5SDimitry Andric 
GetFrameAtIndex(uint32_t idx)6470b57cec5SDimitry Andric StackFrameSP StackFrameList::GetFrameAtIndex(uint32_t idx) {
6480b57cec5SDimitry Andric   StackFrameSP frame_sp;
6490b57cec5SDimitry Andric   std::lock_guard<std::recursive_mutex> guard(m_mutex);
6500b57cec5SDimitry Andric   uint32_t original_idx = idx;
6510b57cec5SDimitry Andric 
6520b57cec5SDimitry Andric   uint32_t inlined_depth = GetCurrentInlinedDepth();
6530b57cec5SDimitry Andric   if (inlined_depth != UINT32_MAX)
6540b57cec5SDimitry Andric     idx += inlined_depth;
6550b57cec5SDimitry Andric 
6560b57cec5SDimitry Andric   if (idx < m_frames.size())
6570b57cec5SDimitry Andric     frame_sp = m_frames[idx];
6580b57cec5SDimitry Andric 
6590b57cec5SDimitry Andric   if (frame_sp)
6600b57cec5SDimitry Andric     return frame_sp;
6610b57cec5SDimitry Andric 
6620b57cec5SDimitry Andric   // GetFramesUpTo will fill m_frames with as many frames as you asked for, if
6630b57cec5SDimitry Andric   // there are that many.  If there weren't then you asked for too many frames.
6640b57cec5SDimitry Andric   GetFramesUpTo(idx);
6650b57cec5SDimitry Andric   if (idx < m_frames.size()) {
6660b57cec5SDimitry Andric     if (m_show_inlined_frames) {
6670b57cec5SDimitry Andric       // When inline frames are enabled we actually create all the frames in
6680b57cec5SDimitry Andric       // GetFramesUpTo.
6690b57cec5SDimitry Andric       frame_sp = m_frames[idx];
6700b57cec5SDimitry Andric     } else {
6710b57cec5SDimitry Andric       addr_t pc, cfa;
6729dba64beSDimitry Andric       bool behaves_like_zeroth_frame = (idx == 0);
6735ffd83dbSDimitry Andric       if (m_thread.GetUnwinder().GetFrameInfoAtIndex(
6745ffd83dbSDimitry Andric               idx, cfa, pc, behaves_like_zeroth_frame)) {
6750b57cec5SDimitry Andric         const bool cfa_is_valid = true;
6760b57cec5SDimitry Andric         frame_sp = std::make_shared<StackFrame>(
6770b57cec5SDimitry Andric             m_thread.shared_from_this(), idx, idx, cfa, cfa_is_valid, pc,
6789dba64beSDimitry Andric             StackFrame::Kind::Regular, behaves_like_zeroth_frame, nullptr);
6790b57cec5SDimitry Andric 
6800b57cec5SDimitry Andric         Function *function =
6810b57cec5SDimitry Andric             frame_sp->GetSymbolContext(eSymbolContextFunction).function;
6820b57cec5SDimitry Andric         if (function) {
6830b57cec5SDimitry Andric           // When we aren't showing inline functions we always use the top
6840b57cec5SDimitry Andric           // most function block as the scope.
6850b57cec5SDimitry Andric           frame_sp->SetSymbolContextScope(&function->GetBlock(false));
6860b57cec5SDimitry Andric         } else {
6870b57cec5SDimitry Andric           // Set the symbol scope from the symbol regardless if it is nullptr
6880b57cec5SDimitry Andric           // or valid.
6890b57cec5SDimitry Andric           frame_sp->SetSymbolContextScope(
6900b57cec5SDimitry Andric               frame_sp->GetSymbolContext(eSymbolContextSymbol).symbol);
6910b57cec5SDimitry Andric         }
6920b57cec5SDimitry Andric         SetFrameAtIndex(idx, frame_sp);
6930b57cec5SDimitry Andric       }
6940b57cec5SDimitry Andric     }
6950b57cec5SDimitry Andric   } else if (original_idx == 0) {
6960b57cec5SDimitry Andric     // There should ALWAYS be a frame at index 0.  If something went wrong with
6970b57cec5SDimitry Andric     // the CurrentInlinedDepth such that there weren't as many frames as we
6980b57cec5SDimitry Andric     // thought taking that into account, then reset the current inlined depth
6990b57cec5SDimitry Andric     // and return the real zeroth frame.
7000b57cec5SDimitry Andric     if (m_frames.empty()) {
7010b57cec5SDimitry Andric       // Why do we have a thread with zero frames, that should not ever
7020b57cec5SDimitry Andric       // happen...
7030b57cec5SDimitry Andric       assert(!m_thread.IsValid() && "A valid thread has no frames.");
7040b57cec5SDimitry Andric     } else {
7050b57cec5SDimitry Andric       ResetCurrentInlinedDepth();
7060b57cec5SDimitry Andric       frame_sp = m_frames[original_idx];
7070b57cec5SDimitry Andric     }
7080b57cec5SDimitry Andric   }
7090b57cec5SDimitry Andric 
7100b57cec5SDimitry Andric   return frame_sp;
7110b57cec5SDimitry Andric }
7120b57cec5SDimitry Andric 
7130b57cec5SDimitry Andric StackFrameSP
GetFrameWithConcreteFrameIndex(uint32_t unwind_idx)7140b57cec5SDimitry Andric StackFrameList::GetFrameWithConcreteFrameIndex(uint32_t unwind_idx) {
7150b57cec5SDimitry Andric   // First try assuming the unwind index is the same as the frame index. The
7160b57cec5SDimitry Andric   // unwind index is always greater than or equal to the frame index, so it is
7170b57cec5SDimitry Andric   // a good place to start. If we have inlined frames we might have 5 concrete
7180b57cec5SDimitry Andric   // frames (frame unwind indexes go from 0-4), but we might have 15 frames
7190b57cec5SDimitry Andric   // after we make all the inlined frames. Most of the time the unwind frame
7200b57cec5SDimitry Andric   // index (or the concrete frame index) is the same as the frame index.
7210b57cec5SDimitry Andric   uint32_t frame_idx = unwind_idx;
7220b57cec5SDimitry Andric   StackFrameSP frame_sp(GetFrameAtIndex(frame_idx));
7230b57cec5SDimitry Andric   while (frame_sp) {
7240b57cec5SDimitry Andric     if (frame_sp->GetFrameIndex() == unwind_idx)
7250b57cec5SDimitry Andric       break;
7260b57cec5SDimitry Andric     frame_sp = GetFrameAtIndex(++frame_idx);
7270b57cec5SDimitry Andric   }
7280b57cec5SDimitry Andric   return frame_sp;
7290b57cec5SDimitry Andric }
7300b57cec5SDimitry Andric 
CompareStackID(const StackFrameSP & stack_sp,const StackID & stack_id)7310b57cec5SDimitry Andric static bool CompareStackID(const StackFrameSP &stack_sp,
7320b57cec5SDimitry Andric                            const StackID &stack_id) {
7330b57cec5SDimitry Andric   return stack_sp->GetStackID() < stack_id;
7340b57cec5SDimitry Andric }
7350b57cec5SDimitry Andric 
GetFrameWithStackID(const StackID & stack_id)7360b57cec5SDimitry Andric StackFrameSP StackFrameList::GetFrameWithStackID(const StackID &stack_id) {
7370b57cec5SDimitry Andric   StackFrameSP frame_sp;
7380b57cec5SDimitry Andric 
7390b57cec5SDimitry Andric   if (stack_id.IsValid()) {
7400b57cec5SDimitry Andric     std::lock_guard<std::recursive_mutex> guard(m_mutex);
7410b57cec5SDimitry Andric     uint32_t frame_idx = 0;
7420b57cec5SDimitry Andric     // Do a binary search in case the stack frame is already in our cache
7430b57cec5SDimitry Andric     collection::const_iterator begin = m_frames.begin();
7440b57cec5SDimitry Andric     collection::const_iterator end = m_frames.end();
7450b57cec5SDimitry Andric     if (begin != end) {
7460b57cec5SDimitry Andric       collection::const_iterator pos =
7470b57cec5SDimitry Andric           std::lower_bound(begin, end, stack_id, CompareStackID);
7480b57cec5SDimitry Andric       if (pos != end) {
7490b57cec5SDimitry Andric         if ((*pos)->GetStackID() == stack_id)
7500b57cec5SDimitry Andric           return *pos;
7510b57cec5SDimitry Andric       }
7520b57cec5SDimitry Andric     }
7530b57cec5SDimitry Andric     do {
7540b57cec5SDimitry Andric       frame_sp = GetFrameAtIndex(frame_idx);
7550b57cec5SDimitry Andric       if (frame_sp && frame_sp->GetStackID() == stack_id)
7560b57cec5SDimitry Andric         break;
7570b57cec5SDimitry Andric       frame_idx++;
7580b57cec5SDimitry Andric     } while (frame_sp);
7590b57cec5SDimitry Andric   }
7600b57cec5SDimitry Andric   return frame_sp;
7610b57cec5SDimitry Andric }
7620b57cec5SDimitry Andric 
SetFrameAtIndex(uint32_t idx,StackFrameSP & frame_sp)7630b57cec5SDimitry Andric bool StackFrameList::SetFrameAtIndex(uint32_t idx, StackFrameSP &frame_sp) {
7640b57cec5SDimitry Andric   if (idx >= m_frames.size())
7650b57cec5SDimitry Andric     m_frames.resize(idx + 1);
7660b57cec5SDimitry Andric   // Make sure allocation succeeded by checking bounds again
7670b57cec5SDimitry Andric   if (idx < m_frames.size()) {
7680b57cec5SDimitry Andric     m_frames[idx] = frame_sp;
7690b57cec5SDimitry Andric     return true;
7700b57cec5SDimitry Andric   }
7710b57cec5SDimitry Andric   return false; // resize failed, out of memory?
7720b57cec5SDimitry Andric }
7730b57cec5SDimitry Andric 
GetSelectedFrameIndex() const7740b57cec5SDimitry Andric uint32_t StackFrameList::GetSelectedFrameIndex() const {
7750b57cec5SDimitry Andric   std::lock_guard<std::recursive_mutex> guard(m_mutex);
7760b57cec5SDimitry Andric   return m_selected_frame_idx;
7770b57cec5SDimitry Andric }
7780b57cec5SDimitry Andric 
SetSelectedFrame(lldb_private::StackFrame * frame)7790b57cec5SDimitry Andric uint32_t StackFrameList::SetSelectedFrame(lldb_private::StackFrame *frame) {
7800b57cec5SDimitry Andric   std::lock_guard<std::recursive_mutex> guard(m_mutex);
7810b57cec5SDimitry Andric   const_iterator pos;
7820b57cec5SDimitry Andric   const_iterator begin = m_frames.begin();
7830b57cec5SDimitry Andric   const_iterator end = m_frames.end();
7840b57cec5SDimitry Andric   m_selected_frame_idx = 0;
7850b57cec5SDimitry Andric   for (pos = begin; pos != end; ++pos) {
7860b57cec5SDimitry Andric     if (pos->get() == frame) {
7870b57cec5SDimitry Andric       m_selected_frame_idx = std::distance(begin, pos);
7880b57cec5SDimitry Andric       uint32_t inlined_depth = GetCurrentInlinedDepth();
7890b57cec5SDimitry Andric       if (inlined_depth != UINT32_MAX)
7900b57cec5SDimitry Andric         m_selected_frame_idx -= inlined_depth;
7910b57cec5SDimitry Andric       break;
7920b57cec5SDimitry Andric     }
7930b57cec5SDimitry Andric   }
7940b57cec5SDimitry Andric   SetDefaultFileAndLineToSelectedFrame();
7950b57cec5SDimitry Andric   return m_selected_frame_idx;
7960b57cec5SDimitry Andric }
7970b57cec5SDimitry Andric 
SetSelectedFrameByIndex(uint32_t idx)7980b57cec5SDimitry Andric bool StackFrameList::SetSelectedFrameByIndex(uint32_t idx) {
7990b57cec5SDimitry Andric   std::lock_guard<std::recursive_mutex> guard(m_mutex);
8000b57cec5SDimitry Andric   StackFrameSP frame_sp(GetFrameAtIndex(idx));
8010b57cec5SDimitry Andric   if (frame_sp) {
8020b57cec5SDimitry Andric     SetSelectedFrame(frame_sp.get());
8030b57cec5SDimitry Andric     return true;
8040b57cec5SDimitry Andric   } else
8050b57cec5SDimitry Andric     return false;
8060b57cec5SDimitry Andric }
8070b57cec5SDimitry Andric 
SetDefaultFileAndLineToSelectedFrame()8080b57cec5SDimitry Andric void StackFrameList::SetDefaultFileAndLineToSelectedFrame() {
8090b57cec5SDimitry Andric   if (m_thread.GetID() ==
8100b57cec5SDimitry Andric       m_thread.GetProcess()->GetThreadList().GetSelectedThread()->GetID()) {
8110b57cec5SDimitry Andric     StackFrameSP frame_sp(GetFrameAtIndex(GetSelectedFrameIndex()));
8120b57cec5SDimitry Andric     if (frame_sp) {
8130b57cec5SDimitry Andric       SymbolContext sc = frame_sp->GetSymbolContext(eSymbolContextLineEntry);
8140b57cec5SDimitry Andric       if (sc.line_entry.file)
8150b57cec5SDimitry Andric         m_thread.CalculateTarget()->GetSourceManager().SetDefaultFileAndLine(
8160b57cec5SDimitry Andric             sc.line_entry.file, sc.line_entry.line);
8170b57cec5SDimitry Andric     }
8180b57cec5SDimitry Andric   }
8190b57cec5SDimitry Andric }
8200b57cec5SDimitry Andric 
8210b57cec5SDimitry Andric // The thread has been run, reset the number stack frames to zero so we can
8220b57cec5SDimitry Andric // determine how many frames we have lazily.
Clear()8230b57cec5SDimitry Andric void StackFrameList::Clear() {
8240b57cec5SDimitry Andric   std::lock_guard<std::recursive_mutex> guard(m_mutex);
8250b57cec5SDimitry Andric   m_frames.clear();
8260b57cec5SDimitry Andric   m_concrete_frames_fetched = 0;
8270b57cec5SDimitry Andric }
8280b57cec5SDimitry Andric 
8290b57cec5SDimitry Andric lldb::StackFrameSP
GetStackFrameSPForStackFramePtr(StackFrame * stack_frame_ptr)8300b57cec5SDimitry Andric StackFrameList::GetStackFrameSPForStackFramePtr(StackFrame *stack_frame_ptr) {
8310b57cec5SDimitry Andric   const_iterator pos;
8320b57cec5SDimitry Andric   const_iterator begin = m_frames.begin();
8330b57cec5SDimitry Andric   const_iterator end = m_frames.end();
8340b57cec5SDimitry Andric   lldb::StackFrameSP ret_sp;
8350b57cec5SDimitry Andric 
8360b57cec5SDimitry Andric   for (pos = begin; pos != end; ++pos) {
8370b57cec5SDimitry Andric     if (pos->get() == stack_frame_ptr) {
8380b57cec5SDimitry Andric       ret_sp = (*pos);
8390b57cec5SDimitry Andric       break;
8400b57cec5SDimitry Andric     }
8410b57cec5SDimitry Andric   }
8420b57cec5SDimitry Andric   return ret_sp;
8430b57cec5SDimitry Andric }
8440b57cec5SDimitry 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)8450b57cec5SDimitry Andric size_t StackFrameList::GetStatus(Stream &strm, uint32_t first_frame,
8460b57cec5SDimitry Andric                                  uint32_t num_frames, bool show_frame_info,
8470b57cec5SDimitry Andric                                  uint32_t num_frames_with_source,
8480b57cec5SDimitry Andric                                  bool show_unique,
8490b57cec5SDimitry Andric                                  const char *selected_frame_marker) {
8500b57cec5SDimitry Andric   size_t num_frames_displayed = 0;
8510b57cec5SDimitry Andric 
8520b57cec5SDimitry Andric   if (num_frames == 0)
8530b57cec5SDimitry Andric     return 0;
8540b57cec5SDimitry Andric 
8550b57cec5SDimitry Andric   StackFrameSP frame_sp;
8560b57cec5SDimitry Andric   uint32_t frame_idx = 0;
8570b57cec5SDimitry Andric   uint32_t last_frame;
8580b57cec5SDimitry Andric 
8590b57cec5SDimitry Andric   // Don't let the last frame wrap around...
8600b57cec5SDimitry Andric   if (num_frames == UINT32_MAX)
8610b57cec5SDimitry Andric     last_frame = UINT32_MAX;
8620b57cec5SDimitry Andric   else
8630b57cec5SDimitry Andric     last_frame = first_frame + num_frames;
8640b57cec5SDimitry Andric 
8650b57cec5SDimitry Andric   StackFrameSP selected_frame_sp = m_thread.GetSelectedFrame();
8660b57cec5SDimitry Andric   const char *unselected_marker = nullptr;
8670b57cec5SDimitry Andric   std::string buffer;
8680b57cec5SDimitry Andric   if (selected_frame_marker) {
8690b57cec5SDimitry Andric     size_t len = strlen(selected_frame_marker);
8700b57cec5SDimitry Andric     buffer.insert(buffer.begin(), len, ' ');
8710b57cec5SDimitry Andric     unselected_marker = buffer.c_str();
8720b57cec5SDimitry Andric   }
8730b57cec5SDimitry Andric   const char *marker = nullptr;
8740b57cec5SDimitry Andric 
8750b57cec5SDimitry Andric   for (frame_idx = first_frame; frame_idx < last_frame; ++frame_idx) {
8760b57cec5SDimitry Andric     frame_sp = GetFrameAtIndex(frame_idx);
8770b57cec5SDimitry Andric     if (!frame_sp)
8780b57cec5SDimitry Andric       break;
8790b57cec5SDimitry Andric 
8800b57cec5SDimitry Andric     if (selected_frame_marker != nullptr) {
8810b57cec5SDimitry Andric       if (frame_sp == selected_frame_sp)
8820b57cec5SDimitry Andric         marker = selected_frame_marker;
8830b57cec5SDimitry Andric       else
8840b57cec5SDimitry Andric         marker = unselected_marker;
8850b57cec5SDimitry Andric     }
8860b57cec5SDimitry Andric 
8870b57cec5SDimitry Andric     if (!frame_sp->GetStatus(strm, show_frame_info,
8880b57cec5SDimitry Andric                              num_frames_with_source > (first_frame - frame_idx),
8890b57cec5SDimitry Andric                              show_unique, marker))
8900b57cec5SDimitry Andric       break;
8910b57cec5SDimitry Andric     ++num_frames_displayed;
8920b57cec5SDimitry Andric   }
8930b57cec5SDimitry Andric 
8940b57cec5SDimitry Andric   strm.IndentLess();
8950b57cec5SDimitry Andric   return num_frames_displayed;
8960b57cec5SDimitry Andric }
897