vsk updated this revision to Diff 228920.
vsk marked 3 inline comments as done.
vsk added a comment.

- Add doxygen comments describing {Direct,Indirect}CallEdge & address the rest 
of Adrian's comments.


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D70100/new/

https://reviews.llvm.org/D70100

Files:
  lldb/include/lldb/Symbol/Function.h
  lldb/include/lldb/Symbol/SymbolFile.h
  
lldb/packages/Python/lldbsuite/test/functionalities/param_entry_vals/basic_entry_values_x86_64/main.cpp
  lldb/source/Expression/DWARFExpression.cpp
  lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
  lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h
  lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.cpp
  lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.h
  lldb/source/Symbol/Function.cpp
  lldb/source/Target/StackFrameList.cpp

Index: lldb/source/Target/StackFrameList.cpp
===================================================================
--- lldb/source/Target/StackFrameList.cpp
+++ lldb/source/Target/StackFrameList.cpp
@@ -243,7 +243,8 @@
 /// \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 @@
 
   // 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 @@
   }
 
   // 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 @@
     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 @@
 
       // 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 @@
     }
   };
 
-  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 @@
   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)) {
Index: lldb/source/Symbol/Function.cpp
===================================================================
--- lldb/source/Symbol/Function.cpp
+++ 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 @@
   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 @@
     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 @@
   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 @@
   }
 }
 
-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 @@
 
   // 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 @@
   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) {
Index: lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.h
===================================================================
--- lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.h
+++ lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.h
@@ -120,7 +120,7 @@
   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;
Index: lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.cpp
===================================================================
--- lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.cpp
+++ lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.cpp
@@ -1071,7 +1071,7 @@
   }
 }
 
-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);
Index: lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h
===================================================================
--- lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h
+++ lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h
@@ -292,7 +292,7 @@
   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;
Index: lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
===================================================================
--- lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
+++ lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
@@ -3685,8 +3685,8 @@
     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);
@@ -3725,7 +3725,7 @@
 }
 
 /// 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.
@@ -3743,32 +3743,87 @@
   // 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;
@@ -3783,13 +3838,12 @@
       }
     }
 
-    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())
Index: lldb/source/Expression/DWARFExpression.cpp
===================================================================
--- lldb/source/Expression/DWARFExpression.cpp
+++ lldb/source/Expression/DWARFExpression.cpp
@@ -830,6 +830,8 @@
 
   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 @@
                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 @@
     // 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 @@
   // 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(),
Index: lldb/packages/Python/lldbsuite/test/functionalities/param_entry_vals/basic_entry_values_x86_64/main.cpp
===================================================================
--- lldb/packages/Python/lldbsuite/test/functionalities/param_entry_vals/basic_entry_values_x86_64/main.cpp
+++ lldb/packages/Python/lldbsuite/test/functionalities/param_entry_vals/basic_entry_values_x86_64/main.cpp
@@ -140,6 +140,34 @@
   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 @@
   // 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;
 }
Index: lldb/include/lldb/Symbol/SymbolFile.h
===================================================================
--- lldb/include/lldb/Symbol/SymbolFile.h
+++ lldb/include/lldb/Symbol/SymbolFile.h
@@ -220,7 +220,8 @@
   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 {};
   }
 
Index: lldb/include/lldb/Symbol/Function.h
===================================================================
--- lldb/include/lldb/Symbol/Function.h
+++ 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 @@
 /// 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,17 +286,13 @@
   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;
+  }
 
-private:
-  void ParseSymbolFileAndResolve(ModuleList &images);
-
-  /// Either the callee's mangled name or its definition, discriminated by
-  /// \ref resolved.
-  union {
-    const char *symbol_name;
-    Function *def;
-  } lazy_callee;
+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
@@ -311,11 +300,58 @@
   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);
+
+  // 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;
 
   /// Whether or not an attempt was made to find the callee's definition.
-  bool resolved;
+  bool resolved = false;
+};
 
-  DISALLOW_COPY_AND_ASSIGN(CallEdge);
+/// 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)) {}
+
+  Function *GetCallee(ModuleList &images, ExecutionContext &exe_ctx) override;
+
+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 @@
 
   /// 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 @@
   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);
 };
_______________________________________________
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to