zturner created this revision.
zturner added reviewers: aleksandr.urakov, amccarth, labath, lemo.
Herald added subscribers: hiraditya, aprantl.

Previously we would create an `lldb::Function` object for each function parsed, 
but we would not add these to the clang AST.  This is a first step towards 
getting local variable support working, as we first need an AST decl so that 
when we create local variable entries, they have the proper `DeclContext`.


https://reviews.llvm.org/D55384

Files:
  lldb/lit/SymbolFile/NativePDB/Inputs/ast-functions.lldbinit
  lldb/lit/SymbolFile/NativePDB/Inputs/ast-reconstruction.lldbinit
  lldb/lit/SymbolFile/NativePDB/Inputs/ast-types.lldbinit
  lldb/lit/SymbolFile/NativePDB/ast-functions.cpp
  lldb/lit/SymbolFile/NativePDB/ast-reconstruction.cpp
  lldb/lit/SymbolFile/NativePDB/ast-types.cpp
  lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp
  llvm/include/llvm/DebugInfo/CodeView/SymbolRecordHelpers.h
  llvm/include/llvm/Support/BinaryStreamArray.h
  llvm/lib/DebugInfo/CodeView/SymbolRecordHelpers.cpp

Index: llvm/lib/DebugInfo/CodeView/SymbolRecordHelpers.cpp
===================================================================
--- llvm/lib/DebugInfo/CodeView/SymbolRecordHelpers.cpp
+++ llvm/lib/DebugInfo/CodeView/SymbolRecordHelpers.cpp
@@ -50,4 +50,15 @@
     assert(false && "Unknown record type");
     return 0;
   }
-}
\ No newline at end of file
+}
+
+CVSymbolArray
+llvm::codeview::limitSymbolArrayToScope(const CVSymbolArray &Symbols,
+                                        uint32_t ScopeBegin) {
+  CVSymbol Opener = *Symbols.at(ScopeBegin);
+  assert(symbolOpensScope(Opener.kind()));
+  uint32_t EndOffset = getScopeEndOffset(Opener);
+  CVSymbol Closer = *Symbols.at(EndOffset);
+  EndOffset += Closer.RecordData.size();
+  return Symbols.substream(ScopeBegin, EndOffset);
+}
Index: llvm/include/llvm/Support/BinaryStreamArray.h
===================================================================
--- llvm/include/llvm/Support/BinaryStreamArray.h
+++ llvm/include/llvm/Support/BinaryStreamArray.h
@@ -113,6 +113,15 @@
 
   bool empty() const { return Stream.getLength() == 0; }
 
+  VarStreamArray<ValueType, Extractor> substream(uint32_t Begin,
+                                                 uint32_t End) const {
+    assert(Begin >= Skew);
+    // We should never cut off the beginning of the stream since it might be
+    // skewed, meaning the initial bytes are important.
+    BinaryStreamRef NewStream = Stream.slice(0, End);
+    return {NewStream, E, Begin};
+  }
+
   /// given an offset into the array's underlying stream, return an
   /// iterator to the record at that offset.  This is considered unsafe
   /// since the behavior is undefined if \p Offset does not refer to the
Index: llvm/include/llvm/DebugInfo/CodeView/SymbolRecordHelpers.h
===================================================================
--- llvm/include/llvm/DebugInfo/CodeView/SymbolRecordHelpers.h
+++ llvm/include/llvm/DebugInfo/CodeView/SymbolRecordHelpers.h
@@ -50,7 +50,11 @@
 
 /// Given a symbol P for which symbolOpensScope(P) == true, return the
 /// corresponding end offset.
-uint32_t getScopeEndOffset(const CVSymbol &symbol);
+uint32_t getScopeEndOffset(const CVSymbol &Symbol);
+
+CVSymbolArray limitSymbolArrayToScope(const CVSymbolArray &Symbols,
+                                      uint32_t ScopeBegin);
+
 } // namespace codeview
 } // namespace llvm
 
Index: lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp
===================================================================
--- lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp
+++ lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp
@@ -37,6 +37,7 @@
 #include "llvm/DebugInfo/CodeView/LazyRandomTypeCollection.h"
 #include "llvm/DebugInfo/CodeView/RecordName.h"
 #include "llvm/DebugInfo/CodeView/SymbolDeserializer.h"
+#include "llvm/DebugInfo/CodeView/SymbolRecordHelpers.h"
 #include "llvm/DebugInfo/CodeView/TypeDeserializer.h"
 #include "llvm/DebugInfo/PDB/Native/DbiStream.h"
 #include "llvm/DebugInfo/PDB/Native/GlobalsStream.h"
@@ -538,16 +539,97 @@
   if (!func_range.GetBaseAddress().IsValid())
     return nullptr;
 
-  Type *func_type = nullptr;
+  ProcSym proc(static_cast<SymbolRecordKind>(sym_record.kind()));
+  cantFail(SymbolDeserializer::deserializeAs<ProcSym>(sym_record, proc));
+  TypeSP func_type = GetOrCreateType(proc.FunctionType);
 
-  // FIXME: Resolve types and mangled names.
-  PdbTypeSymId sig_id(TypeIndex::None(), false);
-  Mangled mangled(getSymbolName(sym_record));
+  PdbTypeSymId sig_id(proc.FunctionType, false);
+  Mangled mangled(proc.Name);
   FunctionSP func_sp = std::make_shared<Function>(
       sc.comp_unit, toOpaqueUid(func_id), toOpaqueUid(sig_id), mangled,
-      func_type, func_range);
+      func_type.get(), func_range);
 
   sc.comp_unit->AddFunction(func_sp);
+
+  clang::StorageClass storage = clang::SC_None;
+  if (sym_record.kind() == S_LPROC32)
+    storage = clang::SC_Static;
+
+  clang::DeclContext *decl_context = m_clang->GetTranslationUnitDecl();
+  clang::FunctionDecl *function_decl = m_clang->CreateFunctionDeclaration(
+      decl_context, proc.Name.str().c_str(),
+      func_type->GetForwardCompilerType(), storage, false);
+
+  // There are two ways we could retrieve the parameter list.  The first is by
+  // iterating the arguments on the function signature type, however that would
+  // only tell us the types of the arguments and not the names.  The second is
+  // to iterate the CVSymbol records that follow the S_GPROC32 / S_LPROC32 until
+  // we have the correct number of arguments as stated by the function
+  // signature. The latter has more potential to go wrong in the face of
+  // improper debug info simply because we're assuming more about the layout of
+  // the records, but it is the only way to get argument names.
+  CVType sig_cvt;
+  CVType arg_list_cvt;
+  ProcedureRecord sig_record;
+  ArgListRecord arg_list_record;
+
+  sig_cvt = m_index->tpi().getType(proc.FunctionType);
+  if (sig_cvt.kind() != LF_PROCEDURE)
+    return func_sp;
+  cantFail(
+      TypeDeserializer::deserializeAs<ProcedureRecord>(sig_cvt, sig_record));
+
+  CVSymbolArray scope = limitSymbolArrayToScope(
+      cci->m_debug_stream.getSymbolArray(), func_id.offset);
+
+  uint32_t params_remaining = sig_record.getParameterCount();
+  auto begin = scope.begin();
+  auto end = scope.end();
+  std::vector<clang::ParmVarDecl *> params;
+  while (begin != end && params_remaining > 0) {
+    CVSymbol sym = *begin++;
+
+    TypeIndex param_type;
+    llvm::StringRef param_name;
+    switch (sym.kind()) {
+    case S_REGREL32: {
+      RegRelativeSym reg(SymbolRecordKind::RegRelativeSym);
+      cantFail(SymbolDeserializer::deserializeAs<RegRelativeSym>(sym, reg));
+      param_type = reg.Type;
+      param_name = reg.Name;
+      break;
+    }
+    case S_REGISTER: {
+      RegisterSym reg(SymbolRecordKind::RegisterSym);
+      cantFail(SymbolDeserializer::deserializeAs<RegisterSym>(sym, reg));
+      param_type = reg.Index;
+      param_name = reg.Name;
+      break;
+    }
+    case S_LOCAL: {
+      LocalSym local(SymbolRecordKind::LocalSym);
+      cantFail(SymbolDeserializer::deserializeAs<LocalSym>(sym, local));
+      if ((local.Flags & LocalSymFlags::IsParameter) == LocalSymFlags::None)
+        continue;
+      param_type = local.Type;
+      param_name = local.Name;
+      break;
+    }
+    default:
+      continue;
+    }
+
+    TypeSP type_sp = GetOrCreateType(param_type);
+    clang::ParmVarDecl *param = m_clang->CreateParameterDeclaration(
+        param_name.str().c_str(), type_sp->GetForwardCompilerType(),
+        clang::SC_None);
+    params.push_back(param);
+    --params_remaining;
+  }
+
+  if (!params.empty())
+    m_clang->SetFunctionParameters(function_decl, params.data(), params.size());
+
   return func_sp;
 }
 
Index: lldb/lit/SymbolFile/NativePDB/ast-types.cpp
===================================================================
--- lldb/lit/SymbolFile/NativePDB/ast-types.cpp
+++ lldb/lit/SymbolFile/NativePDB/ast-types.cpp
@@ -4,7 +4,7 @@
 // Test various interesting cases for AST reconstruction.
 // RUN: %build --compiler=clang-cl --nodefaultlib -o %t.exe -- %s
 // RUN: env LLDB_USE_NATIVE_PDB_READER=1 %lldb -f %t.exe -s \
-// RUN:     %p/Inputs/ast-reconstruction.lldbinit 2>&1 | FileCheck %s
+// RUN:     %p/Inputs/ast-types.lldbinit 2>&1 | FileCheck %s
 
 // Test trivial versions of each tag type.
 class TrivialC {};
Index: lldb/lit/SymbolFile/NativePDB/ast-functions.cpp
===================================================================
--- /dev/null
+++ lldb/lit/SymbolFile/NativePDB/ast-functions.cpp
@@ -0,0 +1,28 @@
+// clang-format off
+// REQUIRES: lld
+
+// RUN: %build --compiler=clang-cl --nodefaultlib -o %t.exe -- %s
+// RUN: env LLDB_USE_NATIVE_PDB_READER=1 %lldb -f %t.exe -s \
+// RUN:     %p/Inputs/ast-functions.lldbinit 2>&1 | FileCheck %s
+
+static int static_fn() {
+  return 42;
+}
+
+int varargs_fn(int x, int y, ...) {
+  return x + y;
+}
+
+int main(int argc, char **argv) {
+  return static_fn() + varargs_fn(argc, argc);
+}
+
+// CHECK:      TranslationUnitDecl
+// CHECK-NEXT: |-FunctionDecl {{.*}} main 'int (int, char **)'
+// CHECK-NEXT: | |-ParmVarDecl {{.*}} argc 'int'
+// CHECK-NEXT: | `-ParmVarDecl {{.*}} argv 'char **'
+// CHECK-NEXT: |-FunctionDecl {{.*}} static_fn 'int ()' static
+// CHECK-NEXT: |-FunctionDecl {{.*}} varargs_fn 'int (int, int, ...)'
+// CHECK-NEXT: | |-ParmVarDecl {{.*}} x 'int'
+// CHECK-NEXT: | `-ParmVarDecl {{.*}} y 'int'
+// CHECK-NEXT: `-<undeserialized declarations>
Index: lldb/lit/SymbolFile/NativePDB/Inputs/ast-functions.lldbinit
===================================================================
--- /dev/null
+++ lldb/lit/SymbolFile/NativePDB/Inputs/ast-functions.lldbinit
@@ -0,0 +1,8 @@
+
+break set -n main
+break set -n static_fn
+break set -n varargs_fn
+
+target modules dump ast
+
+quit
_______________________________________________
lldb-commits mailing list
lldb-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to