diff options
| author | Vedant Kumar <vsk@apple.com> | 2020-03-17 17:59:08 -0700 |
|---|---|---|
| committer | Vedant Kumar <vsk@apple.com> | 2020-03-24 12:54:40 -0700 |
| commit | 03e29e2c19a8e1f6a225b1878df3eed4e54891e5 (patch) | |
| tree | 66a8b9d09a48905180cba6df854c07e655c34a63 /lldb/source/Target/StackFrameList.cpp | |
| parent | e8d67ada2df35ca6c70dbbe8185b0edbb18c1150 (diff) | |
[lldb/DWARF] Reland: Use DW_AT_call_pc to determine artificial frame address
Reland with changes: the test modified in this change originally failed
on a Debian/x86_64 builder, and I suspect the cause was that lldb looked
up the line location for an artificial frame by subtracting 1 from the
frame's address. For artificial frames, the subtraction must not happen
because the address is already exact.
---
lldb currently guesses the address to use when creating an artificial
frame (i.e., a frame constructed by determining the sequence of (tail)
calls which must have happened).
Guessing the address creates problems -- use the actual address provided
by the DW_AT_call_pc attribute instead.
Depends on D76336.
rdar://60307600
Differential Revision: https://reviews.llvm.org/D76337
Diffstat (limited to 'lldb/source/Target/StackFrameList.cpp')
| -rw-r--r-- | lldb/source/Target/StackFrameList.cpp | 49 |
1 files changed, 31 insertions, 18 deletions
diff --git a/lldb/source/Target/StackFrameList.cpp b/lldb/source/Target/StackFrameList.cpp index e8e72203e204..1a75986a80cf 100644 --- a/lldb/source/Target/StackFrameList.cpp +++ b/lldb/source/Target/StackFrameList.cpp @@ -236,13 +236,17 @@ 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. +using CallSequence = std::vector<std::pair<Function *, addr_t>>; + /// 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); @@ -275,24 +279,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 ⌖ 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 ¤t_edge, Function &callee) { // Found a path to the target function. if (&callee == end) { if (solution_path.empty()) @@ -312,13 +319,16 @@ static void FindInterveningFrames(Function &begin, Function &end, } // Search the calls made from this callee. - active_path.push_back(&callee); + active_path.emplace_back(&callee, LLDB_INVALID_ADDRESS); for (const auto &edge : callee.GetTailCallingEdges()) { Function *next_callee = edge->GetCallee(images, context); if (!next_callee) continue; - dfs(*next_callee); + addr_t tail_call_pc = edge->GetCallInstPC(callee, target); + active_path.back().second = tail_call_pc; + + dfs(*edge, *next_callee); if (ambiguous) return; } @@ -326,7 +336,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 @@ -379,7 +389,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(); @@ -389,14 +399,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.first; 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.second; + // We do not want to subtract 1 from this PC, as it's the actual address + // of the tail-calling branch instruction. This address is provided by the + // compiler via DW_AT_call_pc. + constexpr bool behaves_like_zeroth_frame = true; SymbolContext sc; callee->CalculateSymbolContext(&sc); auto synth_frame = std::make_shared<StackFrame>( @@ -404,7 +417,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. |
