summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorZachary Turner <zturner@google.com>2018-12-07 19:34:02 +0000
committerZachary Turner <zturner@google.com>2018-12-07 19:34:02 +0000
commita42bbe3981645c03222161e7d292fdb794f14f56 (patch)
tree6f454ff41cc5ba7696a5101b49fd00fcede0e089
parent992fc88111578d04b21ed1f9c5ade82a502423d5 (diff)
downloadbcm5719-llvm-a42bbe3981645c03222161e7d292fdb794f14f56.tar.gz
bcm5719-llvm-a42bbe3981645c03222161e7d292fdb794f14f56.zip
[NativePDB] Reconstruct function declarations from debug info.
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. Differential Revision: https://reviews.llvm.org/D55384 llvm-svn: 348631
-rw-r--r--lldb/lit/SymbolFile/NativePDB/Inputs/ast-functions.lldbinit8
-rw-r--r--lldb/lit/SymbolFile/NativePDB/Inputs/ast-types.lldbinit (renamed from lldb/lit/SymbolFile/NativePDB/Inputs/ast-reconstruction.lldbinit)0
-rw-r--r--lldb/lit/SymbolFile/NativePDB/ast-functions-msvc.cpp7
-rw-r--r--lldb/lit/SymbolFile/NativePDB/ast-functions.cpp29
-rw-r--r--lldb/lit/SymbolFile/NativePDB/ast-types.cpp (renamed from lldb/lit/SymbolFile/NativePDB/ast-reconstruction.cpp)2
-rw-r--r--lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp137
-rw-r--r--lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.h4
-rw-r--r--llvm/include/llvm/DebugInfo/CodeView/SymbolRecordHelpers.h6
-rw-r--r--llvm/include/llvm/Support/BinaryStreamArray.h9
-rw-r--r--llvm/lib/DebugInfo/CodeView/SymbolRecordHelpers.cpp13
10 files changed, 206 insertions, 9 deletions
diff --git a/lldb/lit/SymbolFile/NativePDB/Inputs/ast-functions.lldbinit b/lldb/lit/SymbolFile/NativePDB/Inputs/ast-functions.lldbinit
new file mode 100644
index 00000000000..c25d96c531d
--- /dev/null
+++ b/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
diff --git a/lldb/lit/SymbolFile/NativePDB/Inputs/ast-reconstruction.lldbinit b/lldb/lit/SymbolFile/NativePDB/Inputs/ast-types.lldbinit
index 3c0cf6d3cdf..3c0cf6d3cdf 100644
--- a/lldb/lit/SymbolFile/NativePDB/Inputs/ast-reconstruction.lldbinit
+++ b/lldb/lit/SymbolFile/NativePDB/Inputs/ast-types.lldbinit
diff --git a/lldb/lit/SymbolFile/NativePDB/ast-functions-msvc.cpp b/lldb/lit/SymbolFile/NativePDB/ast-functions-msvc.cpp
new file mode 100644
index 00000000000..b8154168aff
--- /dev/null
+++ b/lldb/lit/SymbolFile/NativePDB/ast-functions-msvc.cpp
@@ -0,0 +1,7 @@
+// clang-format off
+// REQUIRES: msvc
+
+// RUN: %build --compiler=msvc --nodefaultlib -o %t.exe -- %S/ast-functions.cpp
+
+// RUN: env LLDB_USE_NATIVE_PDB_READER=1 %lldb -f %t.exe -s \
+// RUN: %p/Inputs/ast-functions.lldbinit 2>&1 | FileCheck %S/ast-functions.cpp
diff --git a/lldb/lit/SymbolFile/NativePDB/ast-functions.cpp b/lldb/lit/SymbolFile/NativePDB/ast-functions.cpp
new file mode 100644
index 00000000000..05c80c7298f
--- /dev/null
+++ b/lldb/lit/SymbolFile/NativePDB/ast-functions.cpp
@@ -0,0 +1,29 @@
+// 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>
diff --git a/lldb/lit/SymbolFile/NativePDB/ast-reconstruction.cpp b/lldb/lit/SymbolFile/NativePDB/ast-types.cpp
index dae6e6195fa..224c7c26e84 100644
--- a/lldb/lit/SymbolFile/NativePDB/ast-reconstruction.cpp
+++ b/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 {};
diff --git a/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp b/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp
index 59d1d04f188..e521c928ef9 100644
--- a/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp
+++ b/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,114 @@ lldb::FunctionSP SymbolFileNativePDB::CreateFunction(PdbCompilandSymId func_id,
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;
+
+ // 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));
+
+ CompilerDeclContext context =
+ GetDeclContextContainingUID(toOpaqueUid(func_id));
+
+ clang::DeclContext *decl_context =
+ static_cast<clang::DeclContext *>(context.GetOpaqueDeclContext());
+ clang::FunctionDecl *function_decl = m_clang->CreateFunctionDeclaration(
+ decl_context, proc.Name.str().c_str(),
+ func_type->GetForwardCompilerType(), storage, false);
+
+ lldbassert(m_uid_to_decl.count(toOpaqueUid(func_id)) == 0);
+ m_uid_to_decl[toOpaqueUid(func_id)] = function_decl;
+ 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) {
+ uint32_t record_offset = begin.offset();
+ 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;
+ }
+ case S_BLOCK32:
+ // All parameters should come before the first block. If that isn't the
+ // case, then perhaps this is bad debug info that doesn't contain
+ // information about all parameters.
+ params_remaining = 0;
+ continue;
+ default:
+ continue;
+ }
+
+ PdbCompilandSymId param_uid(func_id.modi, record_offset);
+ TypeSP type_sp = GetOrCreateType(param_type);
+ clang::ParmVarDecl *param = m_clang->CreateParameterDeclaration(
+ param_name.str().c_str(), type_sp->GetForwardCompilerType(),
+ clang::SC_None);
+ lldbassert(m_uid_to_decl.count(toOpaqueUid(param_uid)) == 0);
+
+ m_uid_to_decl[toOpaqueUid(param_uid)] = param;
+ params.push_back(param);
+ --params_remaining;
+ }
+
+ if (!params.empty())
+ m_clang->SetFunctionParameters(function_decl, params.data(), params.size());
+
return func_sp;
}
@@ -714,6 +813,8 @@ AnyScopesHaveTemplateParams(llvm::ArrayRef<llvm::ms_demangle::Node *> scopes) {
std::pair<clang::DeclContext *, std::string>
SymbolFileNativePDB::CreateDeclInfoForType(const TagRecord &record,
TypeIndex ti) {
+ // FIXME: Move this to GetDeclContextContainingUID.
+
llvm::ms_demangle::Demangler demangler;
StringView sv(record.UniqueName.begin(), record.UniqueName.size());
llvm::ms_demangle::TagTypeNode *ttn = demangler.parseTagUniqueName(sv);
@@ -1520,6 +1621,32 @@ size_t SymbolFileNativePDB::FindTypesByName(llvm::StringRef name,
size_t SymbolFileNativePDB::ParseTypes(const SymbolContext &sc) { return 0; }
+CompilerDeclContext
+SymbolFileNativePDB::GetDeclContextContainingUID(lldb::user_id_t uid) {
+ // FIXME: This should look up the uid, decide if it's a symbol or a type, and
+ // depending which it is, find the appropriate DeclContext. Possibilities:
+ // For classes and typedefs:
+ // * Function
+ // * Namespace
+ // * Global
+ // * Block
+ // * Class
+ // For field list members:
+ // * Class
+ // For variables:
+ // * Function
+ // * Namespace
+ // * Global
+ // * Block
+ // For functions:
+ // * Namespace
+ // * Global
+ // * Class
+ //
+ // It is an error to call this function with a uid for any other symbol type.
+ return {m_clang, m_clang->GetTranslationUnitDecl()};
+}
+
Type *SymbolFileNativePDB::ResolveTypeUID(lldb::user_id_t type_uid) {
auto iter = m_types.find(type_uid);
// lldb should not be passing us non-sensical type uids. the only way it
diff --git a/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.h b/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.h
index 980d4852b6e..981a84caaad 100644
--- a/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.h
+++ b/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.h
@@ -112,6 +112,8 @@ public:
size_t ParseVariablesForContext(const SymbolContext &sc) override {
return 0;
}
+
+ CompilerDeclContext GetDeclContextContainingUID(lldb::user_id_t uid) override;
Type *ResolveTypeUID(lldb::user_id_t type_uid) override;
llvm::Optional<ArrayInfo> GetDynamicArrayInfoForUID(
lldb::user_id_t type_uid,
@@ -217,7 +219,7 @@ private:
llvm::DenseMap<clang::TagDecl *, DeclStatus> m_decl_to_status;
- llvm::DenseMap<lldb::user_id_t, clang::TagDecl *> m_uid_to_decl;
+ llvm::DenseMap<lldb::user_id_t, clang::Decl *> m_uid_to_decl;
llvm::DenseMap<llvm::codeview::TypeIndex, llvm::codeview::TypeIndex>
m_parent_types;
diff --git a/llvm/include/llvm/DebugInfo/CodeView/SymbolRecordHelpers.h b/llvm/include/llvm/DebugInfo/CodeView/SymbolRecordHelpers.h
index 8c01bd47f6b..6bfd1b1eb21 100644
--- a/llvm/include/llvm/DebugInfo/CodeView/SymbolRecordHelpers.h
+++ b/llvm/include/llvm/DebugInfo/CodeView/SymbolRecordHelpers.h
@@ -50,7 +50,11 @@ inline bool symbolEndsScope(SymbolKind Kind) {
/// 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
diff --git a/llvm/include/llvm/Support/BinaryStreamArray.h b/llvm/include/llvm/Support/BinaryStreamArray.h
index 78e3c066235..049cf56f4f3 100644
--- a/llvm/include/llvm/Support/BinaryStreamArray.h
+++ b/llvm/include/llvm/Support/BinaryStreamArray.h
@@ -113,6 +113,15 @@ public:
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
diff --git a/llvm/lib/DebugInfo/CodeView/SymbolRecordHelpers.cpp b/llvm/lib/DebugInfo/CodeView/SymbolRecordHelpers.cpp
index f44fc8f01df..79f39591929 100644
--- a/llvm/lib/DebugInfo/CodeView/SymbolRecordHelpers.cpp
+++ b/llvm/lib/DebugInfo/CodeView/SymbolRecordHelpers.cpp
@@ -50,4 +50,15 @@ llvm::codeview::getScopeEndOffset(const llvm::codeview::CVSymbol &Sym) {
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);
+}
OpenPOWER on IntegriCloud