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