From 4fdbc0728d4b8acb1921fc48301622e971fc3961 Mon Sep 17 00:00:00 2001 From: Vedant Kumar Date: Sat, 14 Sep 2019 19:43:16 -0700 Subject: [PATCH] [DWARF] Handle call sites with indirect call targets Split CallEdge into DirectCallEdge and IndirectCallEdge. Teach DWARFExpression how to evaluate entry values in cases where the current activation was created by an indirect call. rdar://57094085 Differential Revision: https://reviews.llvm.org/D70100 --- lldb/include/lldb/Symbol/Function.h | 94 +++++++++++++++------- lldb/include/lldb/Symbol/SymbolFile.h | 3 +- .../basic_entry_values_x86_64/main.cpp | 31 +++++++ lldb/source/Expression/DWARFExpression.cpp | 12 +-- .../Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp | 94 +++++++++++++++++----- .../Plugins/SymbolFile/DWARF/SymbolFileDWARF.h | 2 +- .../SymbolFile/DWARF/SymbolFileDWARFDebugMap.cpp | 2 +- .../SymbolFile/DWARF/SymbolFileDWARFDebugMap.h | 2 +- lldb/source/Symbol/Function.cpp | 91 ++++++++++++++------- lldb/source/Target/StackFrameList.cpp | 25 +++--- 10 files changed, 257 insertions(+), 99 deletions(-) diff --git a/lldb/include/lldb/Symbol/Function.h b/lldb/include/lldb/Symbol/Function.h index 1fef4f0..f675b5f 100644 --- a/lldb/include/lldb/Symbol/Function.h +++ b/lldb/include/lldb/Symbol/Function.h @@ -19,6 +19,8 @@ namespace lldb_private { +class ExecutionContext; + /// \class FunctionInfo Function.h "lldb/Symbol/Function.h" /// A class that contains generic function information. /// @@ -264,23 +266,14 @@ using CallSiteParameterArray = llvm::SmallVector; /// in the call graph between two functions, or to evaluate DW_OP_entry_value. class CallEdge { public: - /// Construct a call edge using a symbol name to identify the calling - /// function, and a return PC within the calling function to identify a - /// specific call site. - /// - /// TODO: A symbol name may not be globally unique. To disambiguate ODR - /// conflicts, it's necessary to determine the \c Target a call edge is - /// associated with before resolving it. - CallEdge(const char *symbol_name, lldb::addr_t return_pc, - CallSiteParameterArray parameters); - - CallEdge(CallEdge &&) = default; - CallEdge &operator=(CallEdge &&) = default; + virtual ~CallEdge() {} /// Get the callee's definition. /// - /// Note that this might lazily invoke the DWARF parser. - Function *GetCallee(ModuleList &images); + /// Note that this might lazily invoke the DWARF parser. A register context + /// from the caller's activation is needed to find indirect call targets. + virtual Function *GetCallee(ModuleList &images, + ExecutionContext &exe_ctx) = 0; /// Get the load PC address of the instruction which executes after the call /// returns. Returns LLDB_INVALID_ADDRESS iff this is a tail call. \p caller @@ -293,29 +286,72 @@ public: lldb::addr_t GetUnresolvedReturnPCAddress() const { return return_pc; } /// Get the call site parameters available at this call edge. - llvm::ArrayRef GetCallSiteParameters() const; + llvm::ArrayRef GetCallSiteParameters() const { + return parameters; + } + +protected: + CallEdge(lldb::addr_t return_pc, CallSiteParameterArray &¶meters) + : return_pc(return_pc), parameters(std::move(parameters)) {} + + /// An invalid address if this is a tail call. Otherwise, the function-local + /// PC offset. Adding this PC offset to the function's base load address + /// gives the return PC for the call. + lldb::addr_t return_pc; + + CallSiteParameterArray parameters; +}; + +/// A direct call site. Used to represent call sites where the address of the +/// callee is fixed (e.g. a function call in C in which the call target is not +/// a function pointer). +class DirectCallEdge : public CallEdge { +public: + /// Construct a call edge using a symbol name to identify the callee, and a + /// return PC within the calling function to identify a specific call site. + DirectCallEdge(const char *symbol_name, lldb::addr_t return_pc, + CallSiteParameterArray &¶meters) + : CallEdge(return_pc, std::move(parameters)) { + lazy_callee.symbol_name = symbol_name; + } + + Function *GetCallee(ModuleList &images, ExecutionContext &exe_ctx) override; private: void ParseSymbolFileAndResolve(ModuleList &images); - /// Either the callee's mangled name or its definition, discriminated by - /// \ref resolved. + // Used to describe a direct call. + // + // Either the callee's mangled name or its definition, discriminated by + // \ref resolved. union { const char *symbol_name; Function *def; } lazy_callee; - /// An invalid address if this is a tail call. Otherwise, the function-local - /// PC offset. Adding this PC offset to the function's base load address - /// gives the return PC for the call. - lldb::addr_t return_pc; + /// Whether or not an attempt was made to find the callee's definition. + bool resolved = false; +}; - CallSiteParameterArray parameters; +/// An indirect call site. Used to represent call sites where the address of +/// the callee is not fixed, e.g. a call to a C++ virtual function (where the +/// address is loaded out of a vtable), or a call to a function pointer in C. +class IndirectCallEdge : public CallEdge { +public: + /// Construct a call edge using a DWARFExpression to identify the callee, and + /// a return PC within the calling function to identify a specific call site. + IndirectCallEdge(DWARFExpression call_target, lldb::addr_t return_pc, + CallSiteParameterArray &¶meters) + : CallEdge(return_pc, std::move(parameters)), + call_target(std::move(call_target)) {} - /// Whether or not an attempt was made to find the callee's definition. - bool resolved; + Function *GetCallee(ModuleList &images, ExecutionContext &exe_ctx) override; - DISALLOW_COPY_AND_ASSIGN(CallEdge); +private: + // Used to describe an indirect call. + // + // Specifies the location of the callee address in the calling frame. + DWARFExpression call_target; }; /// \class Function Function.h "lldb/Symbol/Function.h" @@ -414,11 +450,11 @@ public: /// Get the outgoing call edges from this function, sorted by their return /// PC addresses (in increasing order). - llvm::MutableArrayRef GetCallEdges(); + llvm::ArrayRef> GetCallEdges(); /// Get the outgoing tail-calling edges from this function. If none exist, /// return None. - llvm::MutableArrayRef GetTailCallingEdges(); + llvm::ArrayRef> GetTailCallingEdges(); /// Get the outgoing call edge from this function which has the given return /// address \p return_pc, or return nullptr. Note that this will not return a @@ -587,11 +623,9 @@ protected: uint32_t m_prologue_byte_size; ///< Compute the prologue size once and cache it - // TODO: Use a layer of indirection to point to call edges, to save space - // when call info hasn't been parsed. bool m_call_edges_resolved = false; ///< Whether call site info has been /// parsed. - std::vector m_call_edges; ///< Outgoing call edges. + std::vector> m_call_edges; ///< Outgoing call edges. private: DISALLOW_COPY_AND_ASSIGN(Function); }; diff --git a/lldb/include/lldb/Symbol/SymbolFile.h b/lldb/include/lldb/Symbol/SymbolFile.h index 2fb8796..fdd812e 100644 --- a/lldb/include/lldb/Symbol/SymbolFile.h +++ b/lldb/include/lldb/Symbol/SymbolFile.h @@ -260,7 +260,8 @@ public: const ObjectFile *GetObjectFile() const { return m_objfile_sp.get(); } ObjectFile *GetMainObjectFile(); - virtual std::vector ParseCallEdgesInFunction(UserID func_id) { + virtual std::vector> + ParseCallEdgesInFunction(UserID func_id) { return {}; } diff --git a/lldb/packages/Python/lldbsuite/test/functionalities/param_entry_vals/basic_entry_values_x86_64/main.cpp b/lldb/packages/Python/lldbsuite/test/functionalities/param_entry_vals/basic_entry_values_x86_64/main.cpp index 5a38376..ff72a81 100644 --- a/lldb/packages/Python/lldbsuite/test/functionalities/param_entry_vals/basic_entry_values_x86_64/main.cpp +++ b/lldb/packages/Python/lldbsuite/test/functionalities/param_entry_vals/basic_entry_values_x86_64/main.cpp @@ -140,6 +140,34 @@ void func12(int &sink, int x) { func11_tailcalled(sink, x); } +__attribute__((noinline)) +void func13(int &sink, int x) { + //% self.filecheck("bt", "main.cpp", "-check-prefix=FUNC13-BT") + // FUNC13-BT: func13{{.*}} + // FUNC13-BT-NEXT: func14{{.*}} + use(x); + + // Destroy 'x' in the current frame. + DESTROY_RSI; + + //% self.filecheck("expr x", "main.cpp", "-check-prefix=FUNC13-EXPR") + // FUNC13-EXPR: (int) ${{.*}} = 123 + + ++sink; +} + +__attribute__((noinline, disable_tail_calls)) +void func14(int &sink, void (*target_no_tailcall)(int &, int)) { + // Move the call target into a register that won't get clobbered. Do this + // by calling the same indirect target twice, and hoping that regalloc is + // 'smart' enough to stash the call target in a non-clobbered register. + // + // llvm.org/PR43926 tracks work in the compiler to emit call targets which + // describe non-clobbered values. + target_no_tailcall(sink, 123); + target_no_tailcall(sink, 123); +} + __attribute__((disable_tail_calls)) int main() { int sink = 0; @@ -168,5 +196,8 @@ int main() { // Test that evaluation can "see through" tail calls. func12(sink, 123); + // Test that evaluation can "see through" an indirect tail call. + func14(sink, func13); + return 0; } diff --git a/lldb/source/Expression/DWARFExpression.cpp b/lldb/source/Expression/DWARFExpression.cpp index 79e155e..a063da0 100644 --- a/lldb/source/Expression/DWARFExpression.cpp +++ b/lldb/source/Expression/DWARFExpression.cpp @@ -830,6 +830,8 @@ static bool Evaluate_DW_OP_entry_value(std::vector &stack, CallEdge *call_edge = nullptr; ModuleList &modlist = target.GetImages(); + ExecutionContext parent_exe_ctx = *exe_ctx; + parent_exe_ctx.SetFrameSP(parent_frame); if (!parent_frame->IsArtificial()) { // If the parent frame is not artificial, the current activation may be // produced by an ambiguous tail call. In this case, refuse to proceed. @@ -841,7 +843,7 @@ static bool Evaluate_DW_OP_entry_value(std::vector &stack, return_pc, parent_func->GetName()); return false; } - Function *callee_func = call_edge->GetCallee(modlist); + Function *callee_func = call_edge->GetCallee(modlist, parent_exe_ctx); if (callee_func != current_func) { LLDB_LOG(log, "Evaluate_DW_OP_entry_value: ambiguous call sequence, " "can't find real parent frame"); @@ -851,9 +853,9 @@ static bool Evaluate_DW_OP_entry_value(std::vector &stack, // The StackFrameList solver machinery has deduced that an unambiguous tail // call sequence that produced the current activation. The first edge in // the parent that points to the current function must be valid. - for (CallEdge &edge : parent_func->GetTailCallingEdges()) { - if (edge.GetCallee(modlist) == current_func) { - call_edge = &edge; + for (auto &edge : parent_func->GetTailCallingEdges()) { + if (edge->GetCallee(modlist, parent_exe_ctx) == current_func) { + call_edge = edge.get(); break; } } @@ -907,8 +909,6 @@ static bool Evaluate_DW_OP_entry_value(std::vector &stack, // TODO: Add support for DW_OP_push_object_address within a DW_OP_entry_value // subexpresion whenever llvm does. Value result; - ExecutionContext parent_exe_ctx = *exe_ctx; - parent_exe_ctx.SetFrameSP(parent_frame); const DWARFExpression ¶m_expr = matched_param->LocationInCaller; if (!param_expr.Evaluate(&parent_exe_ctx, parent_frame->GetRegisterContext().get(), diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp index 08dcfa5..fcdff01 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp @@ -3781,8 +3781,8 @@ CollectCallSiteParameters(ModuleSP module, DWARFDIE call_site_die) { if (child.Tag() != DW_TAG_call_site_parameter) continue; - llvm::Optional LocationInCallee = {}; - llvm::Optional LocationInCaller = {}; + llvm::Optional LocationInCallee; + llvm::Optional LocationInCaller; DWARFAttributes attributes; const size_t num_attributes = child.GetAttributes(attributes); @@ -3821,7 +3821,7 @@ CollectCallSiteParameters(ModuleSP module, DWARFDIE call_site_die) { } /// Collect call graph edges present in a function DIE. -static std::vector +static std::vector> CollectCallEdges(ModuleSP module, DWARFDIE function_die) { // Check if the function has a supported call site-related attribute. // TODO: In the future it may be worthwhile to support call_all_source_calls. @@ -3839,32 +3839,87 @@ CollectCallEdges(ModuleSP module, DWARFDIE function_die) { // to be DWARF5-compliant. This may need to be done lazily to be performant. // For now, assume that all entries are nested directly under the subprogram // (this is the kind of DWARF LLVM produces) and parse them eagerly. - std::vector call_edges; + std::vector> call_edges; for (DWARFDIE child = function_die.GetFirstChild(); child.IsValid(); child = child.GetSibling()) { if (child.Tag() != DW_TAG_call_site) continue; - // Extract DW_AT_call_origin (the call target's DIE). - DWARFDIE call_origin = child.GetReferencedDIE(DW_AT_call_origin); - if (!call_origin.IsValid()) { - LLDB_LOG(log, "CollectCallEdges: Invalid call origin in {0}", - function_die.GetPubname()); + llvm::Optional call_origin; + llvm::Optional call_target; + addr_t return_pc = LLDB_INVALID_ADDRESS; + + DWARFAttributes attributes; + const size_t num_attributes = child.GetAttributes(attributes); + for (size_t i = 0; i < num_attributes; ++i) { + DWARFFormValue form_value; + if (!attributes.ExtractFormValueAtIndex(i, form_value)) { + LLDB_LOG(log, "CollectCallEdges: Could not extract TAG_call_site form"); + break; + } + + dw_attr_t attr = attributes.AttributeAtIndex(i); + + // Extract DW_AT_call_origin (the call target's DIE). + if (attr == DW_AT_call_origin) { + call_origin = form_value.Reference(); + if (!call_origin->IsValid()) { + LLDB_LOG(log, "CollectCallEdges: Invalid call origin in {0}", + function_die.GetPubname()); + break; + } + } + + // Extract DW_AT_call_return_pc (the PC the call returns to) if it's + // available. It should only ever be unavailable for tail call edges, in + // which case use LLDB_INVALID_ADDRESS. + if (attr == DW_AT_call_return_pc) + return_pc = form_value.Address(); + + // Extract DW_AT_call_target (the location of the address of the indirect + // call). + if (attr == DW_AT_call_target) { + if (!DWARFFormValue::IsBlockForm(form_value.Form())) { + LLDB_LOG(log, + "CollectCallEdges: AT_call_target does not have block form"); + break; + } + + auto data = child.GetData(); + uint32_t block_offset = form_value.BlockData() - data.GetDataStart(); + uint32_t block_length = form_value.Unsigned(); + call_target = DWARFExpression( + module, DataExtractor(data, block_offset, block_length), + child.GetCU()); + } + } + if (!call_origin && !call_target) { + LLDB_LOG(log, "CollectCallEdges: call site without any call target"); continue; } - // Extract DW_AT_call_return_pc (the PC the call returns to) if it's - // available. It should only ever be unavailable for tail call edges, in - // which case use LLDB_INVALID_ADDRESS. - addr_t return_pc = child.GetAttributeValueAsAddress(DW_AT_call_return_pc, - LLDB_INVALID_ADDRESS); - // Extract call site parameters. CallSiteParameterArray parameters = CollectCallSiteParameters(module, child); - LLDB_LOG(log, "CollectCallEdges: Found call origin: {0} (retn-PC: {1:x})", - call_origin.GetPubname(), return_pc); + std::unique_ptr edge; + if (call_origin) { + LLDB_LOG(log, "CollectCallEdges: Found call origin: {0} (retn-PC: {1:x})", + call_origin->GetPubname(), return_pc); + edge = std::make_unique(call_origin->GetMangledName(), + return_pc, std::move(parameters)); + } else { + if (log) { + StreamString call_target_desc; + call_target->GetDescription(&call_target_desc, eDescriptionLevelBrief, + LLDB_INVALID_ADDRESS, nullptr); + LLDB_LOG(log, "CollectCallEdges: Found indirect call target: {0}", + call_target_desc.GetString()); + } + edge = std::make_unique(*call_target, return_pc, + std::move(parameters)); + } + if (log && parameters.size()) { for (const CallSiteParameter ¶m : parameters) { StreamString callee_loc_desc, caller_loc_desc; @@ -3879,13 +3934,12 @@ CollectCallEdges(ModuleSP module, DWARFDIE function_die) { } } - call_edges.emplace_back(call_origin.GetMangledName(), return_pc, - std::move(parameters)); + call_edges.push_back(std::move(edge)); } return call_edges; } -std::vector +std::vector> SymbolFileDWARF::ParseCallEdgesInFunction(UserID func_id) { DWARFDIE func_die = GetDIE(func_id.GetID()); if (func_die.IsValid()) diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h index a863508..9e4e427 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h +++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h @@ -307,7 +307,7 @@ public: DIEInDeclContext(const lldb_private::CompilerDeclContext *parent_decl_ctx, const DWARFDIE &die); - std::vector + std::vector> ParseCallEdgesInFunction(UserID func_id) override; void Dump(lldb_private::Stream &s) override; diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.cpp b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.cpp index 4cac7e7..dbdbf49 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.cpp @@ -1076,7 +1076,7 @@ void SymbolFileDWARFDebugMap::GetTypes(SymbolContextScope *sc_scope, } } -std::vector +std::vector> SymbolFileDWARFDebugMap::ParseCallEdgesInFunction(UserID func_id) { uint32_t oso_idx = GetOSOIndexFromUserID(func_id.GetID()); SymbolFileDWARF *oso_dwarf = GetSymbolFileByOSOIndex(oso_idx); diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.h b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.h index 0f47348..035a902 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.h +++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.h @@ -136,7 +136,7 @@ public: void GetTypes(lldb_private::SymbolContextScope *sc_scope, lldb::TypeClass type_mask, lldb_private::TypeList &type_list) override; - std::vector + std::vector> ParseCallEdgesInFunction(lldb_private::UserID func_id) override; void DumpClangAST(lldb_private::Stream &s) override; diff --git a/lldb/source/Symbol/Function.cpp b/lldb/source/Symbol/Function.cpp index a4c2d3b..9e81b61 100644 --- a/lldb/source/Symbol/Function.cpp +++ b/lldb/source/Symbol/Function.cpp @@ -17,6 +17,7 @@ #include "lldb/Symbol/LineTable.h" #include "lldb/Symbol/SymbolFile.h" #include "lldb/Target/Language.h" +#include "lldb/Target/Target.h" #include "lldb/Utility/Log.h" #include "llvm/Support/Casting.h" @@ -127,23 +128,21 @@ size_t InlineFunctionInfo::MemorySize() const { return FunctionInfo::MemorySize() + m_mangled.MemorySize(); } -// -CallEdge::CallEdge(const char *symbol_name, lldb::addr_t return_pc, - CallSiteParameterArray parameters) - : return_pc(return_pc), parameters(std::move(parameters)), resolved(false) { - lazy_callee.symbol_name = symbol_name; -} +/// @name Call site related structures +/// @{ -llvm::ArrayRef CallEdge::GetCallSiteParameters() const { - return parameters; +lldb::addr_t CallEdge::GetReturnPCAddress(Function &caller, + Target &target) const { + const Address &base = caller.GetAddressRange().GetBaseAddress(); + return base.GetLoadAddress(&target) + return_pc; } -void CallEdge::ParseSymbolFileAndResolve(ModuleList &images) { +void DirectCallEdge::ParseSymbolFileAndResolve(ModuleList &images) { if (resolved) return; Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP)); - LLDB_LOG(log, "CallEdge: Lazily parsing the call graph for {0}", + LLDB_LOG(log, "DirectCallEdge: Lazily parsing the call graph for {0}", lazy_callee.symbol_name); auto resolve_lazy_callee = [&]() -> Function * { @@ -152,18 +151,19 @@ void CallEdge::ParseSymbolFileAndResolve(ModuleList &images) { images.FindFunctionSymbols(callee_name, eFunctionNameTypeAuto, sc_list); size_t num_matches = sc_list.GetSize(); if (num_matches == 0 || !sc_list[0].symbol) { - LLDB_LOG(log, "CallEdge: Found no symbols for {0}, cannot resolve it", + LLDB_LOG(log, + "DirectCallEdge: Found no symbols for {0}, cannot resolve it", callee_name); return nullptr; } Address callee_addr = sc_list[0].symbol->GetAddress(); if (!callee_addr.IsValid()) { - LLDB_LOG(log, "CallEdge: Invalid symbol address"); + LLDB_LOG(log, "DirectCallEdge: Invalid symbol address"); return nullptr; } Function *f = callee_addr.CalculateSymbolContextFunction(); if (!f) { - LLDB_LOG(log, "CallEdge: Could not find complete function"); + LLDB_LOG(log, "DirectCallEdge: Could not find complete function"); return nullptr; } return f; @@ -172,18 +172,50 @@ void CallEdge::ParseSymbolFileAndResolve(ModuleList &images) { resolved = true; } -Function *CallEdge::GetCallee(ModuleList &images) { +Function *DirectCallEdge::GetCallee(ModuleList &images, ExecutionContext &) { ParseSymbolFileAndResolve(images); assert(resolved && "Did not resolve lazy callee"); return lazy_callee.def; } -lldb::addr_t CallEdge::GetReturnPCAddress(Function &caller, - Target &target) const { - const Address &base = caller.GetAddressRange().GetBaseAddress(); - return base.GetLoadAddress(&target) + return_pc; +Function *IndirectCallEdge::GetCallee(ModuleList &images, + ExecutionContext &exe_ctx) { + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP)); + Status error; + Value callee_addr_val; + if (!call_target.Evaluate(&exe_ctx, exe_ctx.GetRegisterContext(), + /*loclist_base_addr=*/LLDB_INVALID_ADDRESS, + /*initial_value_ptr=*/nullptr, + /*object_address_ptr=*/nullptr, callee_addr_val, + &error)) { + LLDB_LOGF(log, "IndirectCallEdge: Could not evaluate expression: %s", + error.AsCString()); + return nullptr; + } + + addr_t raw_addr = callee_addr_val.GetScalar().ULongLong(LLDB_INVALID_ADDRESS); + if (raw_addr == LLDB_INVALID_ADDRESS) { + LLDB_LOG(log, "IndirectCallEdge: Could not extract address from scalar"); + return nullptr; + } + + Address callee_addr; + if (!exe_ctx.GetTargetPtr()->ResolveLoadAddress(raw_addr, callee_addr)) { + LLDB_LOG(log, "IndirectCallEdge: Could not resolve callee's load address"); + return nullptr; + } + + Function *f = callee_addr.CalculateSymbolContextFunction(); + if (!f) { + LLDB_LOG(log, "IndirectCallEdge: Could not find complete function"); + return nullptr; + } + + return f; } +/// @} + // Function::Function(CompileUnit *comp_unit, lldb::user_id_t func_uid, lldb::user_id_t type_uid, const Mangled &mangled, Type *type, @@ -246,7 +278,7 @@ void Function::GetEndLineSourceInfo(FileSpec &source_file, uint32_t &line_no) { } } -llvm::MutableArrayRef Function::GetCallEdges() { +llvm::ArrayRef> Function::GetCallEdges() { if (m_call_edges_resolved) return m_call_edges; @@ -267,19 +299,20 @@ llvm::MutableArrayRef Function::GetCallEdges() { // Sort the call edges to speed up return_pc lookups. llvm::sort(m_call_edges.begin(), m_call_edges.end(), - [](const CallEdge &LHS, const CallEdge &RHS) { - return LHS.GetUnresolvedReturnPCAddress() < - RHS.GetUnresolvedReturnPCAddress(); + [](const std::unique_ptr &LHS, + const std::unique_ptr &RHS) { + return LHS->GetUnresolvedReturnPCAddress() < + RHS->GetUnresolvedReturnPCAddress(); }); return m_call_edges; } -llvm::MutableArrayRef Function::GetTailCallingEdges() { +llvm::ArrayRef> Function::GetTailCallingEdges() { // Call edges are sorted by return PC, and tail calling edges have invalid // return PCs. Find them at the end of the list. - return GetCallEdges().drop_until([](const CallEdge &edge) { - return edge.GetUnresolvedReturnPCAddress() == LLDB_INVALID_ADDRESS; + return GetCallEdges().drop_until([](const std::unique_ptr &edge) { + return edge->GetUnresolvedReturnPCAddress() == LLDB_INVALID_ADDRESS; }); } @@ -288,13 +321,13 @@ CallEdge *Function::GetCallEdgeForReturnAddress(addr_t return_pc, auto edges = GetCallEdges(); auto edge_it = std::lower_bound(edges.begin(), edges.end(), return_pc, - [&](const CallEdge &edge, addr_t pc) { - return edge.GetReturnPCAddress(*this, target) < pc; + [&](const std::unique_ptr &edge, addr_t pc) { + return edge->GetReturnPCAddress(*this, target) < pc; }); if (edge_it == edges.end() || - edge_it->GetReturnPCAddress(*this, target) != return_pc) + edge_it->get()->GetReturnPCAddress(*this, target) != return_pc) return nullptr; - return &const_cast(*edge_it); + return &const_cast(*edge_it->get()); } Block &Function::GetBlock(bool can_create) { diff --git a/lldb/source/Target/StackFrameList.cpp b/lldb/source/Target/StackFrameList.cpp index 6d0c462..87b4984 100644 --- a/lldb/source/Target/StackFrameList.cpp +++ b/lldb/source/Target/StackFrameList.cpp @@ -243,7 +243,8 @@ void StackFrameList::GetOnlyConcreteFramesUpTo(uint32_t end_idx, /// \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, - Target &target, addr_t return_pc, + ExecutionContext &exe_ctx, Target &target, + addr_t return_pc, std::vector &path, ModuleList &images, Log *log) { LLDB_LOG(log, "Finding frames between {0} and {1}, retn-pc={2:x}", @@ -251,9 +252,9 @@ static void FindInterveningFrames(Function &begin, Function &end, // Find a non-tail calling edge with the correct return PC. if (log) - for (const CallEdge &edge : begin.GetCallEdges()) + for (const auto &edge : begin.GetCallEdges()) LLDB_LOG(log, "FindInterveningFrames: found call with retn-PC = {0:x}", - edge.GetReturnPCAddress(begin, target)); + edge->GetReturnPCAddress(begin, target)); CallEdge *first_edge = begin.GetCallEdgeForReturnAddress(return_pc, target); if (!first_edge) { LLDB_LOG(log, "No call edge outgoing from {0} with retn-PC == {1:x}", @@ -262,7 +263,7 @@ static void FindInterveningFrames(Function &begin, Function &end, } // The first callee may not be resolved, or there may be nothing to fill in. - Function *first_callee = first_edge->GetCallee(images); + Function *first_callee = first_edge->GetCallee(images, exe_ctx); if (!first_callee) { LLDB_LOG(log, "Could not resolve callee"); return; @@ -283,8 +284,10 @@ static void FindInterveningFrames(Function &begin, Function &end, bool ambiguous = false; Function *end; ModuleList &images; + ExecutionContext &context; - DFS(Function *end, ModuleList &images) : end(end), images(images) {} + DFS(Function *end, ModuleList &images, ExecutionContext &context) + : end(end), images(images), context(context) {} void search(Function &first_callee, std::vector &path) { dfs(first_callee); @@ -313,8 +316,8 @@ static void FindInterveningFrames(Function &begin, Function &end, // Search the calls made from this callee. active_path.push_back(&callee); - for (CallEdge &edge : callee.GetTailCallingEdges()) { - Function *next_callee = edge.GetCallee(images); + for (const auto &edge : callee.GetTailCallingEdges()) { + Function *next_callee = edge->GetCallee(images, context); if (!next_callee) continue; @@ -326,7 +329,7 @@ static void FindInterveningFrames(Function &begin, Function &end, } }; - DFS(&end, images).search(*first_callee, path); + DFS(&end, images, exe_ctx).search(*first_callee, path); } /// Given that \p next_frame will be appended to the frame list, synthesize @@ -379,8 +382,10 @@ void StackFrameList::SynthesizeTailCallFrames(StackFrame &next_frame) { addr_t return_pc = next_reg_ctx_sp->GetPC(); Target &target = *target_sp.get(); ModuleList &images = next_frame.CalculateTarget()->GetImages(); - FindInterveningFrames(*next_func, *prev_func, target, return_pc, path, images, - log); + ExecutionContext exe_ctx(target_sp, /*get_process=*/true); + exe_ctx.SetFramePtr(&next_frame); + FindInterveningFrames(*next_func, *prev_func, exe_ctx, target, return_pc, + path, images, log); // Push synthetic tail call frames. for (Function *callee : llvm::reverse(path)) { -- 2.7.4