diff --git a/lldb/include/lldb/Symbol/Function.h b/lldb/include/lldb/Symbol/Function.h index 1fef4f0177e3ce..f675b5fdffa618 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 @@ class CallEdge { 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 @@ class Function : public UserID, public SymbolContextScope { /// 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 @@ class Function : public UserID, public SymbolContextScope { 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 2fb87962ea7cb0..fdd812eb5167fe 100644 --- a/lldb/include/lldb/Symbol/SymbolFile.h +++ b/lldb/include/lldb/Symbol/SymbolFile.h @@ -260,7 +260,8 @@ class SymbolFile : public PluginInterface { 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 5a38376b680e90..ff72a81c6b293b 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 79e155e7e8fc9a..a063da0f4e4014 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 08dcfa57ffee51..fcdff01dd20b9c 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 a86350844ef58c..9e4e4279eec9fc 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h +++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h @@ -307,7 +307,7 @@ class SymbolFileDWARF : public lldb_private::SymbolFile, 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 4cac7e73d74c3d..dbdbf499294128 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 0f47348bc84963..035a902498bea9 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.h +++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.h @@ -136,7 +136,7 @@ class SymbolFileDWARFDebugMap : public lldb_private::SymbolFile { 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 a4c2d3b4b44ad8..9e81b6140eb762 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 6d0c46259c20f4..87b49849bc99bb 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)) {