summaryrefslogtreecommitdiff
path: root/lldb/source/Target/StackFrameList.cpp
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2020-07-26 19:36:28 +0000
committerDimitry Andric <dim@FreeBSD.org>2020-07-26 19:36:28 +0000
commitcfca06d7963fa0909f90483b42a6d7d194d01e08 (patch)
tree209fb2a2d68f8f277793fc8df46c753d31bc853b /lldb/source/Target/StackFrameList.cpp
parent706b4fc47bbc608932d3b491ae19a3b9cde9497b (diff)
Notes
Diffstat (limited to 'lldb/source/Target/StackFrameList.cpp')
-rw-r--r--lldb/source/Target/StackFrameList.cpp126
1 files changed, 70 insertions, 56 deletions
diff --git a/lldb/source/Target/StackFrameList.cpp b/lldb/source/Target/StackFrameList.cpp
index 87b49849bc99..e4f5d3028366 100644
--- a/lldb/source/Target/StackFrameList.cpp
+++ b/lldb/source/Target/StackFrameList.cpp
@@ -1,4 +1,4 @@
-//===-- StackFrameList.cpp --------------------------------------*- C++ -*-===//
+//===-- StackFrameList.cpp ------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
@@ -218,17 +218,14 @@ void StackFrameList::SetCurrentInlinedDepth(uint32_t new_depth) {
}
void StackFrameList::GetOnlyConcreteFramesUpTo(uint32_t end_idx,
- Unwind *unwinder) {
+ Unwind &unwinder) {
assert(m_thread.IsValid() && "Expected valid thread");
assert(m_frames.size() <= end_idx && "Expected there to be frames to fill");
if (end_idx < m_concrete_frames_fetched)
return;
- if (!unwinder)
- return;
-
- uint32_t num_frames = unwinder->GetFramesUpTo(end_idx);
+ uint32_t num_frames = unwinder.GetFramesUpTo(end_idx);
if (num_frames <= end_idx + 1) {
// Done unwinding.
m_concrete_frames_fetched = UINT32_MAX;
@@ -239,13 +236,22 @@ void StackFrameList::GetOnlyConcreteFramesUpTo(uint32_t end_idx,
m_frames.resize(num_frames);
}
+/// A sequence of calls that comprise some portion of a backtrace. Each frame
+/// is represented as a pair of a callee (Function *) and an address within the
+/// callee.
+struct CallDescriptor {
+ Function *func;
+ CallEdge::AddrType address_type = CallEdge::AddrType::Call;
+ addr_t address = LLDB_INVALID_ADDRESS;
+};
+using CallSequence = std::vector<CallDescriptor>;
+
/// Find the unique path through the call graph from \p begin (with return PC
/// \p return_pc) to \p end. On success this path is stored into \p path, and
/// on failure \p path is unchanged.
static void FindInterveningFrames(Function &begin, Function &end,
ExecutionContext &exe_ctx, Target &target,
- addr_t return_pc,
- std::vector<Function *> &path,
+ addr_t return_pc, CallSequence &path,
ModuleList &images, Log *log) {
LLDB_LOG(log, "Finding frames between {0} and {1}, retn-pc={2:x}",
begin.GetDisplayName(), end.GetDisplayName(), return_pc);
@@ -278,24 +284,27 @@ static void FindInterveningFrames(Function &begin, Function &end,
// Fully explore the set of functions reachable from the first edge via tail
// calls in order to detect ambiguous executions.
struct DFS {
- std::vector<Function *> active_path = {};
- std::vector<Function *> solution_path = {};
+ CallSequence active_path = {};
+ CallSequence solution_path = {};
llvm::SmallPtrSet<Function *, 2> visited_nodes = {};
bool ambiguous = false;
Function *end;
ModuleList &images;
+ Target &target;
ExecutionContext &context;
- DFS(Function *end, ModuleList &images, ExecutionContext &context)
- : end(end), images(images), context(context) {}
+ DFS(Function *end, ModuleList &images, Target &target,
+ ExecutionContext &context)
+ : end(end), images(images), target(target), context(context) {}
- void search(Function &first_callee, std::vector<Function *> &path) {
- dfs(first_callee);
+ void search(CallEdge &first_edge, Function &first_callee,
+ CallSequence &path) {
+ dfs(first_edge, first_callee);
if (!ambiguous)
path = std::move(solution_path);
}
- void dfs(Function &callee) {
+ void dfs(CallEdge &current_edge, Function &callee) {
// Found a path to the target function.
if (&callee == end) {
if (solution_path.empty())
@@ -315,13 +324,16 @@ static void FindInterveningFrames(Function &begin, Function &end,
}
// Search the calls made from this callee.
- active_path.push_back(&callee);
+ active_path.push_back(CallDescriptor{&callee});
for (const auto &edge : callee.GetTailCallingEdges()) {
Function *next_callee = edge->GetCallee(images, context);
if (!next_callee)
continue;
- dfs(*next_callee);
+ std::tie(active_path.back().address_type, active_path.back().address) =
+ edge->GetCallerAddress(callee, target);
+
+ dfs(*edge, *next_callee);
if (ambiguous)
return;
}
@@ -329,7 +341,7 @@ static void FindInterveningFrames(Function &begin, Function &end,
}
};
- DFS(&end, images, exe_ctx).search(*first_callee, path);
+ DFS(&end, images, target, exe_ctx).search(*first_edge, *first_callee, path);
}
/// Given that \p next_frame will be appended to the frame list, synthesize
@@ -348,6 +360,11 @@ static void FindInterveningFrames(Function &begin, Function &end,
/// | ... | <- Not-yet-visited frames.
/// --------------
void StackFrameList::SynthesizeTailCallFrames(StackFrame &next_frame) {
+ // Cannot synthesize tail call frames when the stack is empty (there is no
+ // "previous" frame).
+ if (m_frames.empty())
+ return;
+
TargetSP target_sp = next_frame.CalculateTarget();
if (!target_sp)
return;
@@ -358,7 +375,6 @@ void StackFrameList::SynthesizeTailCallFrames(StackFrame &next_frame) {
Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP));
- assert(!m_frames.empty() && "Cannot synthesize frames in an empty stack");
StackFrame &prev_frame = *m_frames.back().get();
// Find the functions prev_frame and next_frame are stopped in. The function
@@ -378,7 +394,7 @@ void StackFrameList::SynthesizeTailCallFrames(StackFrame &next_frame) {
// Try to find the unique sequence of (tail) calls which led from next_frame
// to prev_frame.
- std::vector<Function *> path;
+ CallSequence path;
addr_t return_pc = next_reg_ctx_sp->GetPC();
Target &target = *target_sp.get();
ModuleList &images = next_frame.CalculateTarget()->GetImages();
@@ -388,14 +404,17 @@ void StackFrameList::SynthesizeTailCallFrames(StackFrame &next_frame) {
path, images, log);
// Push synthetic tail call frames.
- for (Function *callee : llvm::reverse(path)) {
+ for (auto calleeInfo : llvm::reverse(path)) {
+ Function *callee = calleeInfo.func;
uint32_t frame_idx = m_frames.size();
uint32_t concrete_frame_idx = next_frame.GetConcreteFrameIndex();
addr_t cfa = LLDB_INVALID_ADDRESS;
bool cfa_is_valid = false;
- addr_t pc =
- callee->GetAddressRange().GetBaseAddress().GetLoadAddress(&target);
- constexpr bool behaves_like_zeroth_frame = false;
+ addr_t pc = calleeInfo.address;
+ // If the callee address refers to the call instruction, we do not want to
+ // subtract 1 from this value.
+ const bool behaves_like_zeroth_frame =
+ calleeInfo.address_type == CallEdge::AddrType::Call;
SymbolContext sc;
callee->CalculateSymbolContext(&sc);
auto synth_frame = std::make_shared<StackFrame>(
@@ -403,7 +422,7 @@ void StackFrameList::SynthesizeTailCallFrames(StackFrame &next_frame) {
cfa_is_valid, pc, StackFrame::Kind::Artificial,
behaves_like_zeroth_frame, &sc);
m_frames.push_back(synth_frame);
- LLDB_LOG(log, "Pushed frame {0}", callee->GetDisplayName());
+ LLDB_LOG(log, "Pushed frame {0} at {1:x}", callee->GetDisplayName(), pc);
}
// If any frames were created, adjust next_frame's index.
@@ -421,7 +440,7 @@ void StackFrameList::GetFramesUpTo(uint32_t end_idx) {
if (m_frames.size() > end_idx || GetAllFramesFetched())
return;
- Unwind *unwinder = m_thread.GetUnwinder();
+ Unwind &unwinder = m_thread.GetUnwinder();
if (!m_show_inlined_frames) {
GetOnlyConcreteFramesUpTo(end_idx, unwinder);
@@ -459,9 +478,8 @@ void StackFrameList::GetFramesUpTo(uint32_t end_idx) {
RegisterContextSP reg_ctx_sp(m_thread.GetRegisterContext());
if (reg_ctx_sp) {
- const bool success = unwinder &&
- unwinder->GetFrameInfoAtIndex(
- idx, cfa, pc, behaves_like_zeroth_frame);
+ const bool success = unwinder.GetFrameInfoAtIndex(
+ idx, cfa, pc, behaves_like_zeroth_frame);
// There shouldn't be any way not to get the frame info for frame
// 0. But if the unwinder can't make one, lets make one by hand
// with the SP as the CFA and see if that gets any further.
@@ -480,9 +498,8 @@ void StackFrameList::GetFramesUpTo(uint32_t end_idx) {
cfa = unwind_frame_sp->m_id.GetCallFrameAddress();
}
} else {
- const bool success = unwinder &&
- unwinder->GetFrameInfoAtIndex(
- idx, cfa, pc, behaves_like_zeroth_frame);
+ const bool success =
+ unwinder.GetFrameInfoAtIndex(idx, cfa, pc, behaves_like_zeroth_frame);
if (!success) {
// We've gotten to the end of the stack.
SetAllFramesFetched();
@@ -665,31 +682,28 @@ StackFrameSP StackFrameList::GetFrameAtIndex(uint32_t idx) {
// GetFramesUpTo.
frame_sp = m_frames[idx];
} else {
- Unwind *unwinder = m_thread.GetUnwinder();
- if (unwinder) {
- addr_t pc, cfa;
- bool behaves_like_zeroth_frame = (idx == 0);
- if (unwinder->GetFrameInfoAtIndex(idx, cfa, pc,
- behaves_like_zeroth_frame)) {
- const bool cfa_is_valid = true;
- frame_sp = std::make_shared<StackFrame>(
- m_thread.shared_from_this(), idx, idx, cfa, cfa_is_valid, pc,
- StackFrame::Kind::Regular, behaves_like_zeroth_frame, nullptr);
-
- Function *function =
- frame_sp->GetSymbolContext(eSymbolContextFunction).function;
- if (function) {
- // When we aren't showing inline functions we always use the top
- // most function block as the scope.
- frame_sp->SetSymbolContextScope(&function->GetBlock(false));
- } else {
- // Set the symbol scope from the symbol regardless if it is nullptr
- // or valid.
- frame_sp->SetSymbolContextScope(
- frame_sp->GetSymbolContext(eSymbolContextSymbol).symbol);
- }
- SetFrameAtIndex(idx, frame_sp);
+ addr_t pc, cfa;
+ bool behaves_like_zeroth_frame = (idx == 0);
+ if (m_thread.GetUnwinder().GetFrameInfoAtIndex(
+ idx, cfa, pc, behaves_like_zeroth_frame)) {
+ const bool cfa_is_valid = true;
+ frame_sp = std::make_shared<StackFrame>(
+ m_thread.shared_from_this(), idx, idx, cfa, cfa_is_valid, pc,
+ StackFrame::Kind::Regular, behaves_like_zeroth_frame, nullptr);
+
+ Function *function =
+ frame_sp->GetSymbolContext(eSymbolContextFunction).function;
+ if (function) {
+ // When we aren't showing inline functions we always use the top
+ // most function block as the scope.
+ frame_sp->SetSymbolContextScope(&function->GetBlock(false));
+ } else {
+ // Set the symbol scope from the symbol regardless if it is nullptr
+ // or valid.
+ frame_sp->SetSymbolContextScope(
+ frame_sp->GetSymbolContext(eSymbolContextSymbol).symbol);
}
+ SetFrameAtIndex(idx, frame_sp);
}
}
} else if (original_idx == 0) {