summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--lldb/include/lldb/Symbol/Function.h94
-rw-r--r--lldb/include/lldb/Symbol/SymbolFile.h3
-rw-r--r--lldb/packages/Python/lldbsuite/test/functionalities/param_entry_vals/basic_entry_values_x86_64/main.cpp31
-rw-r--r--lldb/source/Expression/DWARFExpression.cpp12
-rw-r--r--lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp94
-rw-r--r--lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h2
-rw-r--r--lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.cpp2
-rw-r--r--lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.h2
-rw-r--r--lldb/source/Symbol/Function.cpp91
-rw-r--r--lldb/source/Target/StackFrameList.cpp25
10 files changed, 257 insertions, 99 deletions
diff --git a/lldb/include/lldb/Symbol/Function.h b/lldb/include/lldb/Symbol/Function.h
index 1fef4f0177e..f675b5fdffa 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<CallSiteParameter, 0>;
/// 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<CallSiteParameter> GetCallSiteParameters() const;
+ llvm::ArrayRef<CallSiteParameter> GetCallSiteParameters() const {
+ return parameters;
+ }
+
+protected:
+ CallEdge(lldb::addr_t return_pc, CallSiteParameterArray &&parameters)
+ : 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 &&parameters)
+ : 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 &&parameters)
+ : 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<CallEdge> GetCallEdges();
+ llvm::ArrayRef<std::unique_ptr<CallEdge>> GetCallEdges();
/// Get the outgoing tail-calling edges from this function. If none exist,
/// return None.
- llvm::MutableArrayRef<CallEdge> GetTailCallingEdges();
+ llvm::ArrayRef<std::unique_ptr<CallEdge>> 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<CallEdge> m_call_edges; ///< Outgoing call edges.
+ std::vector<std::unique_ptr<CallEdge>> 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 2fb87962ea7..fdd812eb516 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<CallEdge> ParseCallEdgesInFunction(UserID func_id) {
+ virtual std::vector<std::unique_ptr<CallEdge>>
+ 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 5a38376b680..ff72a81c6b2 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 79e155e7e8f..a063da0f4e4 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<Value> &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<Value> &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<Value> &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<Value> &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 &param_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 08dcfa57ffe..fcdff01dd20 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<DWARFExpression> LocationInCallee = {};
- llvm::Optional<DWARFExpression> LocationInCaller = {};
+ llvm::Optional<DWARFExpression> LocationInCallee;
+ llvm::Optional<DWARFExpression> 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<lldb_private::CallEdge>
+static std::vector<std::unique_ptr<lldb_private::CallEdge>>
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<CallEdge> call_edges;
+ std::vector<std::unique_ptr<CallEdge>> 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<DWARFDIE> call_origin;
+ llvm::Optional<DWARFExpression> 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<CallEdge> 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<DirectCallEdge>(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<IndirectCallEdge>(*call_target, return_pc,
+ std::move(parameters));
+ }
+
if (log && parameters.size()) {
for (const CallSiteParameter &param : 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<lldb_private::CallEdge>
+std::vector<std::unique_ptr<lldb_private::CallEdge>>
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 a86350844ef..9e4e4279eec 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<lldb_private::CallEdge>
+ std::vector<std::unique_ptr<lldb_private::CallEdge>>
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 4cac7e73d74..dbdbf499294 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<lldb_private::CallEdge>
+std::vector<std::unique_ptr<lldb_private::CallEdge>>
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 0f47348bc84..035a902498b 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<lldb_private::CallEdge>
+ std::vector<std::unique_ptr<lldb_private::CallEdge>>
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 a4c2d3b4b44..9e81b6140eb 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<CallSiteParameter> 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<CallEdge> Function::GetCallEdges() {
+llvm::ArrayRef<std::unique_ptr<CallEdge>> Function::GetCallEdges() {
if (m_call_edges_resolved)
return m_call_edges;
@@ -267,19 +299,20 @@ llvm::MutableArrayRef<CallEdge> 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<CallEdge> &LHS,
+ const std::unique_ptr<CallEdge> &RHS) {
+ return LHS->GetUnresolvedReturnPCAddress() <
+ RHS->GetUnresolvedReturnPCAddress();
});
return m_call_edges;
}
-llvm::MutableArrayRef<CallEdge> Function::GetTailCallingEdges() {
+llvm::ArrayRef<std::unique_ptr<CallEdge>> 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<CallEdge> &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<CallEdge> &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<CallEdge &>(*edge_it);
+ return &const_cast<CallEdge &>(*edge_it->get());
}
Block &Function::GetBlock(bool can_create) {
diff --git a/lldb/source/Target/StackFrameList.cpp b/lldb/source/Target/StackFrameList.cpp
index 6d0c46259c2..87b49849bc9 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<Function *> &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<Function *> &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)) {
OpenPOWER on IntegriCloud