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 ⌖
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 ¤t_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