2018-10-12 19:47:13 +00:00
|
|
|
//===-- SymbolFileNativePDB.cpp ---------------------------------*- C++ -*-===//
|
|
|
|
|
//
|
2019-01-19 08:50:56 +00:00
|
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
|
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
|
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
2018-10-12 19:47:13 +00:00
|
|
|
//
|
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
|
|
#include "SymbolFileNativePDB.h"
|
|
|
|
|
|
2018-10-23 16:37:53 +00:00
|
|
|
#include "clang/AST/Attr.h"
|
|
|
|
|
#include "clang/AST/CharUnits.h"
|
|
|
|
|
#include "clang/AST/Decl.h"
|
|
|
|
|
#include "clang/AST/DeclCXX.h"
|
[NativePDB] Higher fidelity reconstruction of AST from Debug Info.
In order to accurately put a type into the correct location in the AST
we construct from debug info, we need to be able to determine what
DeclContext (namespace, global, nested class, etc) that it goes into.
PDB doesn't contain this mapping. It does, however, contain the reverse
mapping. That is, for a given class type T, you can determine all
classes Q1, Q2, ..., Qn that are nested inside of T. We need to know,
for a given class type Q, what type T is it nested inside of.
This patch builds this map as a pre-processing step when we first
load the PDB by scanning every type. Initial tests show that while
this can be slow in debug builds of LLDB, it is quite fast in release
builds (less than 2 seconds for a ~1GB PDB, and it only needs to happen
once).
Furthermore, having this pre-processing step in place allows us to
repurpose it for building up other kinds of indexing to it down the
line. For the time being, this gives us very accurate reconstruction
of the DeclContext hierarchy.
Differential Revision: https://reviews.llvm.org/D54216
llvm-svn: 346429
2018-11-08 18:50:11 +00:00
|
|
|
#include "clang/AST/Type.h"
|
2018-10-23 16:37:53 +00:00
|
|
|
|
2019-01-10 20:57:32 +00:00
|
|
|
#include "Plugins/Language/CPlusPlus/MSVCUndecoratedNameParser.h"
|
2018-10-12 19:47:13 +00:00
|
|
|
#include "lldb/Core/Module.h"
|
|
|
|
|
#include "lldb/Core/PluginManager.h"
|
[NativePDB] Add the ability to dump dump global variables.
LLDB has the ability to display global variables, even without a running
process, via the target variable command. This is because global
variables are linker initialized, so their values are embedded directly
into the executables. This gives us great power for testing native PDB
functionality in a cross-platform manner, because we don't actually need
a running process. We can just create a target using an EXE file, and
display global variables. And global variables can have arbitrarily
complex types, so in theory we can fully exercise the type system,
record layout, and data formatters for native PDB files and PE/COFF
executables on any host platform, as long as our type does not require a
dynamic initializer.
This patch adds basic support for finding variables by name, and adds an
exhaustive test for fundamental data types and pointers / references to
fundamental data types.
Subsequent patches will extend this to typedefs, classes, pointers to
functions, and other cases.
Differential Revision: https://reviews.llvm.org/D53731
llvm-svn: 345373
2018-10-26 09:06:38 +00:00
|
|
|
#include "lldb/Core/StreamBuffer.h"
|
[NativePDB] Higher fidelity reconstruction of AST from Debug Info.
In order to accurately put a type into the correct location in the AST
we construct from debug info, we need to be able to determine what
DeclContext (namespace, global, nested class, etc) that it goes into.
PDB doesn't contain this mapping. It does, however, contain the reverse
mapping. That is, for a given class type T, you can determine all
classes Q1, Q2, ..., Qn that are nested inside of T. We need to know,
for a given class type Q, what type T is it nested inside of.
This patch builds this map as a pre-processing step when we first
load the PDB by scanning every type. Initial tests show that while
this can be slow in debug builds of LLDB, it is quite fast in release
builds (less than 2 seconds for a ~1GB PDB, and it only needs to happen
once).
Furthermore, having this pre-processing step in place allows us to
repurpose it for building up other kinds of indexing to it down the
line. For the time being, this gives us very accurate reconstruction
of the DeclContext hierarchy.
Differential Revision: https://reviews.llvm.org/D54216
llvm-svn: 346429
2018-11-08 18:50:11 +00:00
|
|
|
#include "lldb/Core/StreamFile.h"
|
2018-10-23 16:37:53 +00:00
|
|
|
#include "lldb/Symbol/ClangASTContext.h"
|
|
|
|
|
#include "lldb/Symbol/ClangASTImporter.h"
|
|
|
|
|
#include "lldb/Symbol/ClangExternalASTSourceCommon.h"
|
[NativePDB] Higher fidelity reconstruction of AST from Debug Info.
In order to accurately put a type into the correct location in the AST
we construct from debug info, we need to be able to determine what
DeclContext (namespace, global, nested class, etc) that it goes into.
PDB doesn't contain this mapping. It does, however, contain the reverse
mapping. That is, for a given class type T, you can determine all
classes Q1, Q2, ..., Qn that are nested inside of T. We need to know,
for a given class type Q, what type T is it nested inside of.
This patch builds this map as a pre-processing step when we first
load the PDB by scanning every type. Initial tests show that while
this can be slow in debug builds of LLDB, it is quite fast in release
builds (less than 2 seconds for a ~1GB PDB, and it only needs to happen
once).
Furthermore, having this pre-processing step in place allows us to
repurpose it for building up other kinds of indexing to it down the
line. For the time being, this gives us very accurate reconstruction
of the DeclContext hierarchy.
Differential Revision: https://reviews.llvm.org/D54216
llvm-svn: 346429
2018-11-08 18:50:11 +00:00
|
|
|
#include "lldb/Symbol/ClangUtil.h"
|
2018-10-12 19:47:13 +00:00
|
|
|
#include "lldb/Symbol/CompileUnit.h"
|
|
|
|
|
#include "lldb/Symbol/LineTable.h"
|
|
|
|
|
#include "lldb/Symbol/ObjectFile.h"
|
|
|
|
|
#include "lldb/Symbol/SymbolContext.h"
|
|
|
|
|
#include "lldb/Symbol/SymbolVendor.h"
|
[NativePDB] Add the ability to dump dump global variables.
LLDB has the ability to display global variables, even without a running
process, via the target variable command. This is because global
variables are linker initialized, so their values are embedded directly
into the executables. This gives us great power for testing native PDB
functionality in a cross-platform manner, because we don't actually need
a running process. We can just create a target using an EXE file, and
display global variables. And global variables can have arbitrarily
complex types, so in theory we can fully exercise the type system,
record layout, and data formatters for native PDB files and PE/COFF
executables on any host platform, as long as our type does not require a
dynamic initializer.
This patch adds basic support for finding variables by name, and adds an
exhaustive test for fundamental data types and pointers / references to
fundamental data types.
Subsequent patches will extend this to typedefs, classes, pointers to
functions, and other cases.
Differential Revision: https://reviews.llvm.org/D53731
llvm-svn: 345373
2018-10-26 09:06:38 +00:00
|
|
|
#include "lldb/Symbol/Variable.h"
|
|
|
|
|
#include "lldb/Symbol/VariableList.h"
|
2018-10-12 19:47:13 +00:00
|
|
|
|
|
|
|
|
#include "llvm/DebugInfo/CodeView/CVRecord.h"
|
2018-10-23 16:37:53 +00:00
|
|
|
#include "llvm/DebugInfo/CodeView/CVTypeVisitor.h"
|
2018-10-12 19:47:13 +00:00
|
|
|
#include "llvm/DebugInfo/CodeView/DebugLinesSubsection.h"
|
2018-10-23 16:37:53 +00:00
|
|
|
#include "llvm/DebugInfo/CodeView/LazyRandomTypeCollection.h"
|
2018-10-12 19:47:13 +00:00
|
|
|
#include "llvm/DebugInfo/CodeView/RecordName.h"
|
|
|
|
|
#include "llvm/DebugInfo/CodeView/SymbolDeserializer.h"
|
2018-12-07 19:34:02 +00:00
|
|
|
#include "llvm/DebugInfo/CodeView/SymbolRecordHelpers.h"
|
2018-10-23 16:37:53 +00:00
|
|
|
#include "llvm/DebugInfo/CodeView/TypeDeserializer.h"
|
2018-10-12 19:47:13 +00:00
|
|
|
#include "llvm/DebugInfo/PDB/Native/DbiStream.h"
|
|
|
|
|
#include "llvm/DebugInfo/PDB/Native/GlobalsStream.h"
|
|
|
|
|
#include "llvm/DebugInfo/PDB/Native/InfoStream.h"
|
|
|
|
|
#include "llvm/DebugInfo/PDB/Native/ModuleDebugStream.h"
|
|
|
|
|
#include "llvm/DebugInfo/PDB/Native/PDBFile.h"
|
|
|
|
|
#include "llvm/DebugInfo/PDB/Native/SymbolStream.h"
|
2018-10-23 16:37:53 +00:00
|
|
|
#include "llvm/DebugInfo/PDB/Native/TpiStream.h"
|
2018-10-12 19:47:13 +00:00
|
|
|
#include "llvm/DebugInfo/PDB/PDBTypes.h"
|
[NativePDB] Higher fidelity reconstruction of AST from Debug Info.
In order to accurately put a type into the correct location in the AST
we construct from debug info, we need to be able to determine what
DeclContext (namespace, global, nested class, etc) that it goes into.
PDB doesn't contain this mapping. It does, however, contain the reverse
mapping. That is, for a given class type T, you can determine all
classes Q1, Q2, ..., Qn that are nested inside of T. We need to know,
for a given class type Q, what type T is it nested inside of.
This patch builds this map as a pre-processing step when we first
load the PDB by scanning every type. Initial tests show that while
this can be slow in debug builds of LLDB, it is quite fast in release
builds (less than 2 seconds for a ~1GB PDB, and it only needs to happen
once).
Furthermore, having this pre-processing step in place allows us to
repurpose it for building up other kinds of indexing to it down the
line. For the time being, this gives us very accurate reconstruction
of the DeclContext hierarchy.
Differential Revision: https://reviews.llvm.org/D54216
llvm-svn: 346429
2018-11-08 18:50:11 +00:00
|
|
|
#include "llvm/Demangle/MicrosoftDemangle.h"
|
2018-10-12 19:47:13 +00:00
|
|
|
#include "llvm/Object/COFF.h"
|
|
|
|
|
#include "llvm/Support/Allocator.h"
|
|
|
|
|
#include "llvm/Support/BinaryStreamReader.h"
|
[NativePDB] Higher fidelity reconstruction of AST from Debug Info.
In order to accurately put a type into the correct location in the AST
we construct from debug info, we need to be able to determine what
DeclContext (namespace, global, nested class, etc) that it goes into.
PDB doesn't contain this mapping. It does, however, contain the reverse
mapping. That is, for a given class type T, you can determine all
classes Q1, Q2, ..., Qn that are nested inside of T. We need to know,
for a given class type Q, what type T is it nested inside of.
This patch builds this map as a pre-processing step when we first
load the PDB by scanning every type. Initial tests show that while
this can be slow in debug builds of LLDB, it is quite fast in release
builds (less than 2 seconds for a ~1GB PDB, and it only needs to happen
once).
Furthermore, having this pre-processing step in place allows us to
repurpose it for building up other kinds of indexing to it down the
line. For the time being, this gives us very accurate reconstruction
of the DeclContext hierarchy.
Differential Revision: https://reviews.llvm.org/D54216
llvm-svn: 346429
2018-11-08 18:50:11 +00:00
|
|
|
#include "llvm/Support/Error.h"
|
2018-10-12 19:47:13 +00:00
|
|
|
#include "llvm/Support/ErrorOr.h"
|
|
|
|
|
#include "llvm/Support/MemoryBuffer.h"
|
|
|
|
|
|
2018-12-06 17:49:15 +00:00
|
|
|
#include "DWARFLocationExpression.h"
|
2018-12-17 19:43:33 +00:00
|
|
|
#include "PdbAstBuilder.h"
|
2018-10-12 19:47:13 +00:00
|
|
|
#include "PdbSymUid.h"
|
|
|
|
|
#include "PdbUtil.h"
|
2018-10-23 16:37:53 +00:00
|
|
|
#include "UdtRecordCompleter.h"
|
2018-10-12 19:47:13 +00:00
|
|
|
|
|
|
|
|
using namespace lldb;
|
|
|
|
|
using namespace lldb_private;
|
2018-10-23 16:37:53 +00:00
|
|
|
using namespace npdb;
|
2018-10-12 19:47:13 +00:00
|
|
|
using namespace llvm::codeview;
|
|
|
|
|
using namespace llvm::pdb;
|
|
|
|
|
|
|
|
|
|
static lldb::LanguageType TranslateLanguage(PDB_Lang lang) {
|
|
|
|
|
switch (lang) {
|
|
|
|
|
case PDB_Lang::Cpp:
|
|
|
|
|
return lldb::LanguageType::eLanguageTypeC_plus_plus;
|
|
|
|
|
case PDB_Lang::C:
|
|
|
|
|
return lldb::LanguageType::eLanguageTypeC;
|
|
|
|
|
default:
|
|
|
|
|
return lldb::LanguageType::eLanguageTypeUnknown;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static std::unique_ptr<PDBFile> loadPDBFile(std::string PdbPath,
|
|
|
|
|
llvm::BumpPtrAllocator &Allocator) {
|
|
|
|
|
llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> ErrorOrBuffer =
|
|
|
|
|
llvm::MemoryBuffer::getFile(PdbPath, /*FileSize=*/-1,
|
|
|
|
|
/*RequiresNullTerminator=*/false);
|
|
|
|
|
if (!ErrorOrBuffer)
|
|
|
|
|
return nullptr;
|
|
|
|
|
std::unique_ptr<llvm::MemoryBuffer> Buffer = std::move(*ErrorOrBuffer);
|
|
|
|
|
|
|
|
|
|
llvm::StringRef Path = Buffer->getBufferIdentifier();
|
|
|
|
|
auto Stream = llvm::make_unique<llvm::MemoryBufferByteStream>(
|
|
|
|
|
std::move(Buffer), llvm::support::little);
|
|
|
|
|
|
|
|
|
|
auto File = llvm::make_unique<PDBFile>(Path, std::move(Stream), Allocator);
|
2018-10-12 22:57:40 +00:00
|
|
|
if (auto EC = File->parseFileHeaders()) {
|
|
|
|
|
llvm::consumeError(std::move(EC));
|
2018-10-12 19:47:13 +00:00
|
|
|
return nullptr;
|
2018-10-12 22:57:40 +00:00
|
|
|
}
|
|
|
|
|
if (auto EC = File->parseStreamData()) {
|
|
|
|
|
llvm::consumeError(std::move(EC));
|
2018-10-12 19:47:13 +00:00
|
|
|
return nullptr;
|
2018-10-12 22:57:40 +00:00
|
|
|
}
|
2018-10-12 19:47:13 +00:00
|
|
|
|
|
|
|
|
return File;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static std::unique_ptr<PDBFile>
|
|
|
|
|
loadMatchingPDBFile(std::string exe_path, llvm::BumpPtrAllocator &allocator) {
|
|
|
|
|
// Try to find a matching PDB for an EXE.
|
|
|
|
|
using namespace llvm::object;
|
|
|
|
|
auto expected_binary = createBinary(exe_path);
|
|
|
|
|
|
|
|
|
|
// If the file isn't a PE/COFF executable, fail.
|
|
|
|
|
if (!expected_binary) {
|
|
|
|
|
llvm::consumeError(expected_binary.takeError());
|
|
|
|
|
return nullptr;
|
|
|
|
|
}
|
|
|
|
|
OwningBinary<Binary> binary = std::move(*expected_binary);
|
|
|
|
|
|
|
|
|
|
auto *obj = llvm::dyn_cast<llvm::object::COFFObjectFile>(binary.getBinary());
|
|
|
|
|
if (!obj)
|
|
|
|
|
return nullptr;
|
|
|
|
|
const llvm::codeview::DebugInfo *pdb_info = nullptr;
|
|
|
|
|
|
|
|
|
|
// If it doesn't have a debug directory, fail.
|
|
|
|
|
llvm::StringRef pdb_file;
|
|
|
|
|
auto ec = obj->getDebugPDBInfo(pdb_info, pdb_file);
|
|
|
|
|
if (ec)
|
|
|
|
|
return nullptr;
|
|
|
|
|
|
|
|
|
|
// if the file doesn't exist, is not a pdb, or doesn't have a matching guid,
|
|
|
|
|
// fail.
|
|
|
|
|
llvm::file_magic magic;
|
|
|
|
|
ec = llvm::identify_magic(pdb_file, magic);
|
|
|
|
|
if (ec || magic != llvm::file_magic::pdb)
|
|
|
|
|
return nullptr;
|
|
|
|
|
std::unique_ptr<PDBFile> pdb = loadPDBFile(pdb_file, allocator);
|
2018-10-12 22:57:40 +00:00
|
|
|
if (!pdb)
|
|
|
|
|
return nullptr;
|
|
|
|
|
|
2018-10-12 19:47:13 +00:00
|
|
|
auto expected_info = pdb->getPDBInfoStream();
|
|
|
|
|
if (!expected_info) {
|
|
|
|
|
llvm::consumeError(expected_info.takeError());
|
|
|
|
|
return nullptr;
|
|
|
|
|
}
|
|
|
|
|
llvm::codeview::GUID guid;
|
|
|
|
|
memcpy(&guid, pdb_info->PDB70.Signature, 16);
|
|
|
|
|
|
|
|
|
|
if (expected_info->getGuid() != guid)
|
|
|
|
|
return nullptr;
|
|
|
|
|
return pdb;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static bool IsFunctionPrologue(const CompilandIndexItem &cci,
|
|
|
|
|
lldb::addr_t addr) {
|
|
|
|
|
// FIXME: Implement this.
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static bool IsFunctionEpilogue(const CompilandIndexItem &cci,
|
|
|
|
|
lldb::addr_t addr) {
|
|
|
|
|
// FIXME: Implement this.
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2018-10-23 16:37:53 +00:00
|
|
|
static llvm::StringRef GetSimpleTypeName(SimpleTypeKind kind) {
|
|
|
|
|
switch (kind) {
|
|
|
|
|
case SimpleTypeKind::Boolean128:
|
|
|
|
|
case SimpleTypeKind::Boolean16:
|
|
|
|
|
case SimpleTypeKind::Boolean32:
|
|
|
|
|
case SimpleTypeKind::Boolean64:
|
|
|
|
|
case SimpleTypeKind::Boolean8:
|
|
|
|
|
return "bool";
|
|
|
|
|
case SimpleTypeKind::Byte:
|
|
|
|
|
case SimpleTypeKind::UnsignedCharacter:
|
|
|
|
|
return "unsigned char";
|
|
|
|
|
case SimpleTypeKind::NarrowCharacter:
|
|
|
|
|
return "char";
|
|
|
|
|
case SimpleTypeKind::SignedCharacter:
|
|
|
|
|
case SimpleTypeKind::SByte:
|
2018-10-23 22:15:05 +00:00
|
|
|
return "signed char";
|
2018-10-23 16:37:53 +00:00
|
|
|
case SimpleTypeKind::Character16:
|
|
|
|
|
return "char16_t";
|
|
|
|
|
case SimpleTypeKind::Character32:
|
|
|
|
|
return "char32_t";
|
|
|
|
|
case SimpleTypeKind::Complex80:
|
|
|
|
|
case SimpleTypeKind::Complex64:
|
|
|
|
|
case SimpleTypeKind::Complex32:
|
|
|
|
|
return "complex";
|
|
|
|
|
case SimpleTypeKind::Float128:
|
|
|
|
|
case SimpleTypeKind::Float80:
|
|
|
|
|
return "long double";
|
|
|
|
|
case SimpleTypeKind::Float64:
|
|
|
|
|
return "double";
|
|
|
|
|
case SimpleTypeKind::Float32:
|
|
|
|
|
return "float";
|
|
|
|
|
case SimpleTypeKind::Float16:
|
|
|
|
|
return "single";
|
|
|
|
|
case SimpleTypeKind::Int128:
|
|
|
|
|
return "__int128";
|
|
|
|
|
case SimpleTypeKind::Int64:
|
|
|
|
|
case SimpleTypeKind::Int64Quad:
|
2018-10-23 22:15:05 +00:00
|
|
|
return "int64_t";
|
2018-10-23 16:37:53 +00:00
|
|
|
case SimpleTypeKind::Int32:
|
|
|
|
|
return "int";
|
|
|
|
|
case SimpleTypeKind::Int16:
|
|
|
|
|
return "short";
|
|
|
|
|
case SimpleTypeKind::UInt128:
|
|
|
|
|
return "unsigned __int128";
|
|
|
|
|
case SimpleTypeKind::UInt64:
|
|
|
|
|
case SimpleTypeKind::UInt64Quad:
|
2018-10-23 22:15:05 +00:00
|
|
|
return "uint64_t";
|
2018-10-23 16:37:53 +00:00
|
|
|
case SimpleTypeKind::HResult:
|
|
|
|
|
return "HRESULT";
|
|
|
|
|
case SimpleTypeKind::UInt32:
|
|
|
|
|
return "unsigned";
|
|
|
|
|
case SimpleTypeKind::UInt16:
|
|
|
|
|
case SimpleTypeKind::UInt16Short:
|
|
|
|
|
return "unsigned short";
|
|
|
|
|
case SimpleTypeKind::Int32Long:
|
|
|
|
|
return "long";
|
|
|
|
|
case SimpleTypeKind::UInt32Long:
|
|
|
|
|
return "unsigned long";
|
|
|
|
|
case SimpleTypeKind::Void:
|
|
|
|
|
return "void";
|
|
|
|
|
case SimpleTypeKind::WideCharacter:
|
|
|
|
|
return "wchar_t";
|
|
|
|
|
default:
|
|
|
|
|
return "";
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static bool IsClassRecord(TypeLeafKind kind) {
|
|
|
|
|
switch (kind) {
|
|
|
|
|
case LF_STRUCTURE:
|
|
|
|
|
case LF_CLASS:
|
|
|
|
|
case LF_INTERFACE:
|
|
|
|
|
return true;
|
|
|
|
|
default:
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2018-10-12 19:47:13 +00:00
|
|
|
void SymbolFileNativePDB::Initialize() {
|
|
|
|
|
PluginManager::RegisterPlugin(GetPluginNameStatic(),
|
|
|
|
|
GetPluginDescriptionStatic(), CreateInstance,
|
|
|
|
|
DebuggerInitialize);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void SymbolFileNativePDB::Terminate() {
|
|
|
|
|
PluginManager::UnregisterPlugin(CreateInstance);
|
|
|
|
|
}
|
|
|
|
|
|
2018-10-22 16:19:07 +00:00
|
|
|
void SymbolFileNativePDB::DebuggerInitialize(Debugger &debugger) {}
|
2018-10-12 19:47:13 +00:00
|
|
|
|
2018-10-22 16:19:07 +00:00
|
|
|
ConstString SymbolFileNativePDB::GetPluginNameStatic() {
|
2018-10-12 19:47:13 +00:00
|
|
|
static ConstString g_name("native-pdb");
|
|
|
|
|
return g_name;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const char *SymbolFileNativePDB::GetPluginDescriptionStatic() {
|
|
|
|
|
return "Microsoft PDB debug symbol cross-platform file reader.";
|
|
|
|
|
}
|
|
|
|
|
|
2018-10-22 16:19:07 +00:00
|
|
|
SymbolFile *SymbolFileNativePDB::CreateInstance(ObjectFile *obj_file) {
|
2018-10-12 19:47:13 +00:00
|
|
|
return new SymbolFileNativePDB(obj_file);
|
|
|
|
|
}
|
|
|
|
|
|
2018-10-22 16:19:07 +00:00
|
|
|
SymbolFileNativePDB::SymbolFileNativePDB(ObjectFile *object_file)
|
2018-10-12 19:47:13 +00:00
|
|
|
: SymbolFile(object_file) {}
|
|
|
|
|
|
|
|
|
|
SymbolFileNativePDB::~SymbolFileNativePDB() {}
|
|
|
|
|
|
|
|
|
|
uint32_t SymbolFileNativePDB::CalculateAbilities() {
|
|
|
|
|
uint32_t abilities = 0;
|
|
|
|
|
if (!m_obj_file)
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
if (!m_index) {
|
|
|
|
|
// Lazily load and match the PDB file, but only do this once.
|
|
|
|
|
std::unique_ptr<PDBFile> file_up =
|
|
|
|
|
loadMatchingPDBFile(m_obj_file->GetFileSpec().GetPath(), m_allocator);
|
|
|
|
|
|
|
|
|
|
if (!file_up) {
|
|
|
|
|
auto module_sp = m_obj_file->GetModule();
|
|
|
|
|
if (!module_sp)
|
|
|
|
|
return 0;
|
|
|
|
|
// See if any symbol file is specified through `--symfile` option.
|
|
|
|
|
FileSpec symfile = module_sp->GetSymbolFileFileSpec();
|
|
|
|
|
if (!symfile)
|
|
|
|
|
return 0;
|
|
|
|
|
file_up = loadPDBFile(symfile.GetPath(), m_allocator);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!file_up)
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
auto expected_index = PdbIndex::create(std::move(file_up));
|
|
|
|
|
if (!expected_index) {
|
|
|
|
|
llvm::consumeError(expected_index.takeError());
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
m_index = std::move(*expected_index);
|
|
|
|
|
}
|
|
|
|
|
if (!m_index)
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
// We don't especially have to be precise here. We only distinguish between
|
|
|
|
|
// stripped and not stripped.
|
|
|
|
|
abilities = kAllAbilities;
|
|
|
|
|
|
|
|
|
|
if (m_index->dbi().isStripped())
|
|
|
|
|
abilities &= ~(Blocks | LocalVariables);
|
|
|
|
|
return abilities;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void SymbolFileNativePDB::InitializeObject() {
|
2019-02-18 11:06:57 +00:00
|
|
|
m_obj_load_address = m_obj_file->GetBaseAddress().GetFileAddress();
|
2018-10-12 19:47:13 +00:00
|
|
|
m_index->SetLoadAddress(m_obj_load_address);
|
|
|
|
|
m_index->ParseSectionContribs();
|
2018-10-23 16:37:53 +00:00
|
|
|
|
2018-12-17 19:43:33 +00:00
|
|
|
TypeSystem *ts = m_obj_file->GetModule()->GetTypeSystemForLanguage(
|
|
|
|
|
lldb::eLanguageTypeC_plus_plus);
|
|
|
|
|
if (ts)
|
|
|
|
|
ts->SetSymbolFile(this);
|
[NativePDB] Higher fidelity reconstruction of AST from Debug Info.
In order to accurately put a type into the correct location in the AST
we construct from debug info, we need to be able to determine what
DeclContext (namespace, global, nested class, etc) that it goes into.
PDB doesn't contain this mapping. It does, however, contain the reverse
mapping. That is, for a given class type T, you can determine all
classes Q1, Q2, ..., Qn that are nested inside of T. We need to know,
for a given class type Q, what type T is it nested inside of.
This patch builds this map as a pre-processing step when we first
load the PDB by scanning every type. Initial tests show that while
this can be slow in debug builds of LLDB, it is quite fast in release
builds (less than 2 seconds for a ~1GB PDB, and it only needs to happen
once).
Furthermore, having this pre-processing step in place allows us to
repurpose it for building up other kinds of indexing to it down the
line. For the time being, this gives us very accurate reconstruction
of the DeclContext hierarchy.
Differential Revision: https://reviews.llvm.org/D54216
llvm-svn: 346429
2018-11-08 18:50:11 +00:00
|
|
|
|
2018-12-17 19:43:33 +00:00
|
|
|
m_ast = llvm::make_unique<PdbAstBuilder>(*m_obj_file, *m_index);
|
[NativePDB] Higher fidelity reconstruction of AST from Debug Info.
In order to accurately put a type into the correct location in the AST
we construct from debug info, we need to be able to determine what
DeclContext (namespace, global, nested class, etc) that it goes into.
PDB doesn't contain this mapping. It does, however, contain the reverse
mapping. That is, for a given class type T, you can determine all
classes Q1, Q2, ..., Qn that are nested inside of T. We need to know,
for a given class type Q, what type T is it nested inside of.
This patch builds this map as a pre-processing step when we first
load the PDB by scanning every type. Initial tests show that while
this can be slow in debug builds of LLDB, it is quite fast in release
builds (less than 2 seconds for a ~1GB PDB, and it only needs to happen
once).
Furthermore, having this pre-processing step in place allows us to
repurpose it for building up other kinds of indexing to it down the
line. For the time being, this gives us very accurate reconstruction
of the DeclContext hierarchy.
Differential Revision: https://reviews.llvm.org/D54216
llvm-svn: 346429
2018-11-08 18:50:11 +00:00
|
|
|
}
|
|
|
|
|
|
2018-10-12 19:47:13 +00:00
|
|
|
uint32_t SymbolFileNativePDB::GetNumCompileUnits() {
|
|
|
|
|
const DbiModuleList &modules = m_index->dbi().modules();
|
|
|
|
|
uint32_t count = modules.getModuleCount();
|
|
|
|
|
if (count == 0)
|
|
|
|
|
return count;
|
|
|
|
|
|
|
|
|
|
// The linker can inject an additional "dummy" compilation unit into the
|
|
|
|
|
// PDB. Ignore this special compile unit for our purposes, if it is there.
|
|
|
|
|
// It is always the last one.
|
|
|
|
|
DbiModuleDescriptor last = modules.getModuleDescriptor(count - 1);
|
|
|
|
|
if (last.getModuleName() == "* Linker *")
|
|
|
|
|
--count;
|
|
|
|
|
return count;
|
|
|
|
|
}
|
|
|
|
|
|
2018-12-13 18:17:51 +00:00
|
|
|
Block &SymbolFileNativePDB::CreateBlock(PdbCompilandSymId block_id) {
|
|
|
|
|
CompilandIndexItem *cii = m_index->compilands().GetCompiland(block_id.modi);
|
|
|
|
|
CVSymbol sym = cii->m_debug_stream.readSymbolAtOffset(block_id.offset);
|
|
|
|
|
|
|
|
|
|
if (sym.kind() == S_GPROC32 || sym.kind() == S_LPROC32) {
|
|
|
|
|
// This is a function. It must be global. Creating the Function entry for
|
|
|
|
|
// it automatically creates a block for it.
|
|
|
|
|
CompUnitSP comp_unit = GetOrCreateCompileUnit(*cii);
|
|
|
|
|
return GetOrCreateFunction(block_id, *comp_unit)->GetBlock(false);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
lldbassert(sym.kind() == S_BLOCK32);
|
|
|
|
|
|
|
|
|
|
// This is a block. Its parent is either a function or another block. In
|
|
|
|
|
// either case, its parent can be viewed as a block (e.g. a function contains
|
|
|
|
|
// 1 big block. So just get the parent block and add this block to it.
|
|
|
|
|
BlockSym block(static_cast<SymbolRecordKind>(sym.kind()));
|
|
|
|
|
cantFail(SymbolDeserializer::deserializeAs<BlockSym>(sym, block));
|
|
|
|
|
lldbassert(block.Parent != 0);
|
|
|
|
|
PdbCompilandSymId parent_id(block_id.modi, block.Parent);
|
|
|
|
|
Block &parent_block = GetOrCreateBlock(parent_id);
|
|
|
|
|
lldb::user_id_t opaque_block_uid = toOpaqueUid(block_id);
|
|
|
|
|
BlockSP child_block = std::make_shared<Block>(opaque_block_uid);
|
|
|
|
|
parent_block.AddChild(child_block);
|
2018-12-17 19:43:33 +00:00
|
|
|
|
|
|
|
|
m_ast->GetOrCreateBlockDecl(block_id);
|
2018-12-13 18:17:51 +00:00
|
|
|
|
|
|
|
|
m_blocks.insert({opaque_block_uid, child_block});
|
|
|
|
|
return *child_block;
|
|
|
|
|
}
|
|
|
|
|
|
2018-11-16 02:42:32 +00:00
|
|
|
lldb::FunctionSP SymbolFileNativePDB::CreateFunction(PdbCompilandSymId func_id,
|
2018-12-13 18:17:51 +00:00
|
|
|
CompileUnit &comp_unit) {
|
2018-11-16 02:42:32 +00:00
|
|
|
const CompilandIndexItem *cci =
|
|
|
|
|
m_index->compilands().GetCompiland(func_id.modi);
|
2018-10-12 19:47:13 +00:00
|
|
|
lldbassert(cci);
|
2018-11-16 02:42:32 +00:00
|
|
|
CVSymbol sym_record = cci->m_debug_stream.readSymbolAtOffset(func_id.offset);
|
2018-10-12 19:47:13 +00:00
|
|
|
|
|
|
|
|
lldbassert(sym_record.kind() == S_LPROC32 || sym_record.kind() == S_GPROC32);
|
|
|
|
|
SegmentOffsetLength sol = GetSegmentOffsetAndLength(sym_record);
|
|
|
|
|
|
|
|
|
|
auto file_vm_addr = m_index->MakeVirtualAddress(sol.so);
|
|
|
|
|
if (file_vm_addr == LLDB_INVALID_ADDRESS || file_vm_addr == 0)
|
|
|
|
|
return nullptr;
|
|
|
|
|
|
|
|
|
|
AddressRange func_range(file_vm_addr, sol.length,
|
2018-12-13 18:17:51 +00:00
|
|
|
comp_unit.GetModule()->GetSectionList());
|
2018-10-12 19:47:13 +00:00
|
|
|
if (!func_range.GetBaseAddress().IsValid())
|
|
|
|
|
return nullptr;
|
|
|
|
|
|
2018-12-07 19:34:02 +00:00
|
|
|
ProcSym proc(static_cast<SymbolRecordKind>(sym_record.kind()));
|
|
|
|
|
cantFail(SymbolDeserializer::deserializeAs<ProcSym>(sym_record, proc));
|
2019-01-10 20:57:32 +00:00
|
|
|
if (proc.FunctionType == TypeIndex::None())
|
|
|
|
|
return nullptr;
|
2018-12-07 19:34:02 +00:00
|
|
|
TypeSP func_type = GetOrCreateType(proc.FunctionType);
|
2019-01-10 20:57:32 +00:00
|
|
|
if (!func_type)
|
|
|
|
|
return nullptr;
|
2018-10-12 19:47:13 +00:00
|
|
|
|
2018-12-07 19:34:02 +00:00
|
|
|
PdbTypeSymId sig_id(proc.FunctionType, false);
|
|
|
|
|
Mangled mangled(proc.Name);
|
2018-10-12 19:47:13 +00:00
|
|
|
FunctionSP func_sp = std::make_shared<Function>(
|
2018-12-13 18:17:51 +00:00
|
|
|
&comp_unit, toOpaqueUid(func_id), toOpaqueUid(sig_id), mangled,
|
2018-12-07 19:34:02 +00:00
|
|
|
func_type.get(), func_range);
|
2018-10-12 19:47:13 +00:00
|
|
|
|
2018-12-13 18:17:51 +00:00
|
|
|
comp_unit.AddFunction(func_sp);
|
|
|
|
|
|
2018-12-17 19:43:33 +00:00
|
|
|
m_ast->GetOrCreateFunctionDecl(func_id);
|
2018-12-07 19:34:02 +00:00
|
|
|
|
2018-10-12 19:47:13 +00:00
|
|
|
return func_sp;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
CompUnitSP
|
|
|
|
|
SymbolFileNativePDB::CreateCompileUnit(const CompilandIndexItem &cci) {
|
|
|
|
|
lldb::LanguageType lang =
|
|
|
|
|
cci.m_compile_opts ? TranslateLanguage(cci.m_compile_opts->getLanguage())
|
|
|
|
|
: lldb::eLanguageTypeUnknown;
|
|
|
|
|
|
|
|
|
|
LazyBool optimized = eLazyBoolNo;
|
|
|
|
|
if (cci.m_compile_opts && cci.m_compile_opts->hasOptimizations())
|
|
|
|
|
optimized = eLazyBoolYes;
|
|
|
|
|
|
2018-12-19 19:45:30 +00:00
|
|
|
llvm::SmallString<64> source_file_name =
|
2018-10-12 19:47:13 +00:00
|
|
|
m_index->compilands().GetMainSourceFile(cci);
|
2018-11-01 21:05:36 +00:00
|
|
|
FileSpec fs(source_file_name);
|
2018-10-12 19:47:13 +00:00
|
|
|
|
|
|
|
|
CompUnitSP cu_sp =
|
|
|
|
|
std::make_shared<CompileUnit>(m_obj_file->GetModule(), nullptr, fs,
|
2018-11-16 02:42:32 +00:00
|
|
|
toOpaqueUid(cci.m_id), lang, optimized);
|
2018-10-12 19:47:13 +00:00
|
|
|
|
2018-11-16 02:42:32 +00:00
|
|
|
m_obj_file->GetModule()->GetSymbolVendor()->SetCompileUnitAtIndex(
|
|
|
|
|
cci.m_id.modi, cu_sp);
|
2018-10-12 19:47:13 +00:00
|
|
|
return cu_sp;
|
|
|
|
|
}
|
|
|
|
|
|
2018-11-16 02:42:32 +00:00
|
|
|
lldb::TypeSP SymbolFileNativePDB::CreateModifierType(PdbTypeSymId type_id,
|
2018-12-17 19:43:33 +00:00
|
|
|
const ModifierRecord &mr,
|
|
|
|
|
CompilerType ct) {
|
2018-10-23 16:37:53 +00:00
|
|
|
TpiStream &stream = m_index->tpi();
|
|
|
|
|
|
|
|
|
|
std::string name;
|
|
|
|
|
if (mr.ModifiedType.isSimple())
|
|
|
|
|
name = GetSimpleTypeName(mr.ModifiedType.getSimpleKind());
|
|
|
|
|
else
|
|
|
|
|
name = computeTypeName(stream.typeCollection(), mr.ModifiedType);
|
|
|
|
|
Declaration decl;
|
2018-12-17 19:43:33 +00:00
|
|
|
lldb::TypeSP modified_type = GetOrCreateType(mr.ModifiedType);
|
|
|
|
|
|
|
|
|
|
return std::make_shared<Type>(toOpaqueUid(type_id), this, ConstString(name),
|
|
|
|
|
modified_type->GetByteSize(), nullptr,
|
2018-10-23 16:37:53 +00:00
|
|
|
LLDB_INVALID_UID, Type::eEncodingIsUID, decl,
|
|
|
|
|
ct, Type::eResolveStateFull);
|
|
|
|
|
}
|
|
|
|
|
|
2018-12-17 19:43:33 +00:00
|
|
|
lldb::TypeSP
|
|
|
|
|
SymbolFileNativePDB::CreatePointerType(PdbTypeSymId type_id,
|
|
|
|
|
const llvm::codeview::PointerRecord &pr,
|
|
|
|
|
CompilerType ct) {
|
2018-10-23 16:37:53 +00:00
|
|
|
TypeSP pointee = GetOrCreateType(pr.ReferentType);
|
2018-11-01 16:37:29 +00:00
|
|
|
if (!pointee)
|
|
|
|
|
return nullptr;
|
2018-10-23 16:37:53 +00:00
|
|
|
|
|
|
|
|
if (pr.isPointerToMember()) {
|
|
|
|
|
MemberPointerInfo mpi = pr.getMemberInfo();
|
2018-12-17 19:43:33 +00:00
|
|
|
GetOrCreateType(mpi.ContainingType);
|
2018-10-23 16:37:53 +00:00
|
|
|
}
|
|
|
|
|
|
2018-12-17 19:43:33 +00:00
|
|
|
Declaration decl;
|
|
|
|
|
return std::make_shared<Type>(toOpaqueUid(type_id), this, ConstString(),
|
|
|
|
|
pr.getSize(), nullptr, LLDB_INVALID_UID,
|
|
|
|
|
Type::eEncodingIsUID, decl, ct,
|
|
|
|
|
Type::eResolveStateFull);
|
2018-10-23 16:37:53 +00:00
|
|
|
}
|
|
|
|
|
|
2018-12-17 19:43:33 +00:00
|
|
|
lldb::TypeSP SymbolFileNativePDB::CreateSimpleType(TypeIndex ti,
|
|
|
|
|
CompilerType ct) {
|
2018-11-16 03:16:27 +00:00
|
|
|
uint64_t uid = toOpaqueUid(PdbTypeSymId(ti, false));
|
2018-11-01 16:37:29 +00:00
|
|
|
if (ti == TypeIndex::NullptrT()) {
|
|
|
|
|
Declaration decl;
|
2018-11-16 02:42:32 +00:00
|
|
|
return std::make_shared<Type>(
|
|
|
|
|
uid, this, ConstString("std::nullptr_t"), 0, nullptr, LLDB_INVALID_UID,
|
|
|
|
|
Type::eEncodingIsUID, decl, ct, Type::eResolveStateFull);
|
2018-11-01 16:37:29 +00:00
|
|
|
}
|
|
|
|
|
|
2018-10-23 16:37:53 +00:00
|
|
|
if (ti.getSimpleMode() != SimpleTypeMode::Direct) {
|
|
|
|
|
TypeSP direct_sp = GetOrCreateType(ti.makeDirect());
|
2018-10-23 22:15:05 +00:00
|
|
|
uint32_t pointer_size = 0;
|
2018-10-23 16:37:53 +00:00
|
|
|
switch (ti.getSimpleMode()) {
|
|
|
|
|
case SimpleTypeMode::FarPointer32:
|
|
|
|
|
case SimpleTypeMode::NearPointer32:
|
|
|
|
|
pointer_size = 4;
|
|
|
|
|
break;
|
|
|
|
|
case SimpleTypeMode::NearPointer64:
|
|
|
|
|
pointer_size = 8;
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
// 128-bit and 16-bit pointers unsupported.
|
|
|
|
|
return nullptr;
|
|
|
|
|
}
|
|
|
|
|
Declaration decl;
|
2018-12-17 19:43:33 +00:00
|
|
|
return std::make_shared<Type>(
|
|
|
|
|
uid, this, ConstString(), pointer_size, nullptr, LLDB_INVALID_UID,
|
|
|
|
|
Type::eEncodingIsUID, decl, ct, Type::eResolveStateFull);
|
2018-10-23 16:37:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (ti.getSimpleKind() == SimpleTypeKind::NotTranslated)
|
|
|
|
|
return nullptr;
|
|
|
|
|
|
|
|
|
|
size_t size = GetTypeSizeForSimpleKind(ti.getSimpleKind());
|
|
|
|
|
llvm::StringRef type_name = GetSimpleTypeName(ti.getSimpleKind());
|
|
|
|
|
|
|
|
|
|
Declaration decl;
|
2018-12-17 19:43:33 +00:00
|
|
|
return std::make_shared<Type>(uid, this, ConstString(type_name), size,
|
|
|
|
|
nullptr, LLDB_INVALID_UID, Type::eEncodingIsUID,
|
|
|
|
|
decl, ct, Type::eResolveStateFull);
|
2018-10-23 16:37:53 +00:00
|
|
|
}
|
|
|
|
|
|
2018-12-17 19:43:33 +00:00
|
|
|
static std::string GetUnqualifiedTypeName(const TagRecord &record) {
|
2019-01-10 20:57:32 +00:00
|
|
|
if (!record.hasUniqueName()) {
|
|
|
|
|
MSVCUndecoratedNameParser parser(record.Name);
|
|
|
|
|
llvm::ArrayRef<MSVCUndecoratedNameSpecifier> specs = parser.GetSpecifiers();
|
|
|
|
|
|
|
|
|
|
return specs.back().GetBaseName();
|
|
|
|
|
}
|
|
|
|
|
|
[NativePDB] Higher fidelity reconstruction of AST from Debug Info.
In order to accurately put a type into the correct location in the AST
we construct from debug info, we need to be able to determine what
DeclContext (namespace, global, nested class, etc) that it goes into.
PDB doesn't contain this mapping. It does, however, contain the reverse
mapping. That is, for a given class type T, you can determine all
classes Q1, Q2, ..., Qn that are nested inside of T. We need to know,
for a given class type Q, what type T is it nested inside of.
This patch builds this map as a pre-processing step when we first
load the PDB by scanning every type. Initial tests show that while
this can be slow in debug builds of LLDB, it is quite fast in release
builds (less than 2 seconds for a ~1GB PDB, and it only needs to happen
once).
Furthermore, having this pre-processing step in place allows us to
repurpose it for building up other kinds of indexing to it down the
line. For the time being, this gives us very accurate reconstruction
of the DeclContext hierarchy.
Differential Revision: https://reviews.llvm.org/D54216
llvm-svn: 346429
2018-11-08 18:50:11 +00:00
|
|
|
llvm::ms_demangle::Demangler demangler;
|
|
|
|
|
StringView sv(record.UniqueName.begin(), record.UniqueName.size());
|
|
|
|
|
llvm::ms_demangle::TagTypeNode *ttn = demangler.parseTagUniqueName(sv);
|
2019-01-10 20:57:32 +00:00
|
|
|
if (demangler.Error)
|
|
|
|
|
return record.Name;
|
|
|
|
|
|
[NativePDB] Higher fidelity reconstruction of AST from Debug Info.
In order to accurately put a type into the correct location in the AST
we construct from debug info, we need to be able to determine what
DeclContext (namespace, global, nested class, etc) that it goes into.
PDB doesn't contain this mapping. It does, however, contain the reverse
mapping. That is, for a given class type T, you can determine all
classes Q1, Q2, ..., Qn that are nested inside of T. We need to know,
for a given class type Q, what type T is it nested inside of.
This patch builds this map as a pre-processing step when we first
load the PDB by scanning every type. Initial tests show that while
this can be slow in debug builds of LLDB, it is quite fast in release
builds (less than 2 seconds for a ~1GB PDB, and it only needs to happen
once).
Furthermore, having this pre-processing step in place allows us to
repurpose it for building up other kinds of indexing to it down the
line. For the time being, this gives us very accurate reconstruction
of the DeclContext hierarchy.
Differential Revision: https://reviews.llvm.org/D54216
llvm-svn: 346429
2018-11-08 18:50:11 +00:00
|
|
|
llvm::ms_demangle::IdentifierNode *idn =
|
|
|
|
|
ttn->QualifiedName->getUnqualifiedIdentifier();
|
2018-12-17 19:43:33 +00:00
|
|
|
return idn->toString();
|
[NativePDB] Higher fidelity reconstruction of AST from Debug Info.
In order to accurately put a type into the correct location in the AST
we construct from debug info, we need to be able to determine what
DeclContext (namespace, global, nested class, etc) that it goes into.
PDB doesn't contain this mapping. It does, however, contain the reverse
mapping. That is, for a given class type T, you can determine all
classes Q1, Q2, ..., Qn that are nested inside of T. We need to know,
for a given class type Q, what type T is it nested inside of.
This patch builds this map as a pre-processing step when we first
load the PDB by scanning every type. Initial tests show that while
this can be slow in debug builds of LLDB, it is quite fast in release
builds (less than 2 seconds for a ~1GB PDB, and it only needs to happen
once).
Furthermore, having this pre-processing step in place allows us to
repurpose it for building up other kinds of indexing to it down the
line. For the time being, this gives us very accurate reconstruction
of the DeclContext hierarchy.
Differential Revision: https://reviews.llvm.org/D54216
llvm-svn: 346429
2018-11-08 18:50:11 +00:00
|
|
|
}
|
|
|
|
|
|
2018-12-17 19:43:33 +00:00
|
|
|
lldb::TypeSP
|
|
|
|
|
SymbolFileNativePDB::CreateClassStructUnion(PdbTypeSymId type_id,
|
|
|
|
|
const TagRecord &record,
|
|
|
|
|
size_t size, CompilerType ct) {
|
2018-10-23 16:37:53 +00:00
|
|
|
|
2018-12-17 19:43:33 +00:00
|
|
|
std::string uname = GetUnqualifiedTypeName(record);
|
2018-10-23 16:37:53 +00:00
|
|
|
|
|
|
|
|
// FIXME: Search IPI stream for LF_UDT_MOD_SRC_LINE.
|
|
|
|
|
Declaration decl;
|
2018-12-17 19:43:33 +00:00
|
|
|
return std::make_shared<Type>(toOpaqueUid(type_id), this, ConstString(uname),
|
|
|
|
|
size, nullptr, LLDB_INVALID_UID,
|
|
|
|
|
Type::eEncodingIsUID, decl, ct,
|
|
|
|
|
Type::eResolveStateForward);
|
2018-10-23 16:37:53 +00:00
|
|
|
}
|
|
|
|
|
|
2018-11-16 02:42:32 +00:00
|
|
|
lldb::TypeSP SymbolFileNativePDB::CreateTagType(PdbTypeSymId type_id,
|
2018-12-17 19:43:33 +00:00
|
|
|
const ClassRecord &cr,
|
|
|
|
|
CompilerType ct) {
|
|
|
|
|
return CreateClassStructUnion(type_id, cr, cr.getSize(), ct);
|
2018-10-23 16:37:53 +00:00
|
|
|
}
|
|
|
|
|
|
2018-11-16 02:42:32 +00:00
|
|
|
lldb::TypeSP SymbolFileNativePDB::CreateTagType(PdbTypeSymId type_id,
|
2018-12-17 19:43:33 +00:00
|
|
|
const UnionRecord &ur,
|
|
|
|
|
CompilerType ct) {
|
|
|
|
|
return CreateClassStructUnion(type_id, ur, ur.getSize(), ct);
|
2018-10-23 16:37:53 +00:00
|
|
|
}
|
|
|
|
|
|
2018-11-16 02:42:32 +00:00
|
|
|
lldb::TypeSP SymbolFileNativePDB::CreateTagType(PdbTypeSymId type_id,
|
2018-12-17 19:43:33 +00:00
|
|
|
const EnumRecord &er,
|
|
|
|
|
CompilerType ct) {
|
|
|
|
|
std::string uname = GetUnqualifiedTypeName(er);
|
2018-10-23 16:37:53 +00:00
|
|
|
|
|
|
|
|
Declaration decl;
|
|
|
|
|
TypeSP underlying_type = GetOrCreateType(er.UnderlyingType);
|
|
|
|
|
|
|
|
|
|
return std::make_shared<lldb_private::Type>(
|
2018-12-17 19:43:33 +00:00
|
|
|
toOpaqueUid(type_id), this, ConstString(uname),
|
2018-10-23 16:37:53 +00:00
|
|
|
underlying_type->GetByteSize(), nullptr, LLDB_INVALID_UID,
|
2018-12-17 19:43:33 +00:00
|
|
|
lldb_private::Type::eEncodingIsUID, decl, ct,
|
2018-10-23 16:37:53 +00:00
|
|
|
lldb_private::Type::eResolveStateForward);
|
|
|
|
|
}
|
|
|
|
|
|
2018-11-16 02:42:32 +00:00
|
|
|
TypeSP SymbolFileNativePDB::CreateArrayType(PdbTypeSymId type_id,
|
2018-12-17 19:43:33 +00:00
|
|
|
const ArrayRecord &ar,
|
|
|
|
|
CompilerType ct) {
|
[NativePDB] Add support for dumping global variables of class type.
Previous patches added support for dumping global variables of
primitive types, so we now do the same for class types.
For the most part, everything just worked, there was only one
minor bug needing fixed, which was that for variables of modified
types (e.g. const, volatile, etc) we can't resolve the forward
decl in CreateAndCacheType because the PdbSymUid must point to the
LF_MODIFIER which must point to the forward decl. So when it comes
time to call CompleteType, an assert was firing because we expected
to get a class, struct, union, or enum, but we were getting an
LF_MODIFIER instead.
The other issue is that one the newly added tests is for an array
member, which was not yet supported, so we add support for that
now in this patch.
There's probably room for other interesting layout test cases
here, but this at least should test the basics.
Differential Revision: https://reviews.llvm.org/D53822
llvm-svn: 345629
2018-10-30 18:57:08 +00:00
|
|
|
TypeSP element_type = GetOrCreateType(ar.ElementType);
|
|
|
|
|
|
|
|
|
|
Declaration decl;
|
|
|
|
|
TypeSP array_sp = std::make_shared<lldb_private::Type>(
|
2018-12-17 19:43:33 +00:00
|
|
|
toOpaqueUid(type_id), this, ConstString(), ar.Size, nullptr,
|
|
|
|
|
LLDB_INVALID_UID, lldb_private::Type::eEncodingIsUID, decl, ct,
|
|
|
|
|
lldb_private::Type::eResolveStateFull);
|
[NativePDB] Add support for dumping global variables of class type.
Previous patches added support for dumping global variables of
primitive types, so we now do the same for class types.
For the most part, everything just worked, there was only one
minor bug needing fixed, which was that for variables of modified
types (e.g. const, volatile, etc) we can't resolve the forward
decl in CreateAndCacheType because the PdbSymUid must point to the
LF_MODIFIER which must point to the forward decl. So when it comes
time to call CompleteType, an assert was firing because we expected
to get a class, struct, union, or enum, but we were getting an
LF_MODIFIER instead.
The other issue is that one the newly added tests is for an array
member, which was not yet supported, so we add support for that
now in this patch.
There's probably room for other interesting layout test cases
here, but this at least should test the basics.
Differential Revision: https://reviews.llvm.org/D53822
llvm-svn: 345629
2018-10-30 18:57:08 +00:00
|
|
|
array_sp->SetEncodingType(element_type.get());
|
|
|
|
|
return array_sp;
|
|
|
|
|
}
|
|
|
|
|
|
2018-11-16 02:42:32 +00:00
|
|
|
TypeSP SymbolFileNativePDB::CreateProcedureType(PdbTypeSymId type_id,
|
2018-12-17 19:43:33 +00:00
|
|
|
const ProcedureRecord &pr,
|
|
|
|
|
CompilerType ct) {
|
2018-11-01 16:37:29 +00:00
|
|
|
Declaration decl;
|
|
|
|
|
return std::make_shared<lldb_private::Type>(
|
2018-11-16 02:42:32 +00:00
|
|
|
toOpaqueUid(type_id), this, ConstString(), 0, nullptr, LLDB_INVALID_UID,
|
2018-12-17 19:43:33 +00:00
|
|
|
lldb_private::Type::eEncodingIsUID, decl, ct,
|
2018-11-01 16:37:29 +00:00
|
|
|
lldb_private::Type::eResolveStateFull);
|
|
|
|
|
}
|
|
|
|
|
|
2018-12-17 19:43:33 +00:00
|
|
|
TypeSP SymbolFileNativePDB::CreateType(PdbTypeSymId type_id, CompilerType ct) {
|
2018-11-16 02:42:32 +00:00
|
|
|
if (type_id.index.isSimple())
|
2018-12-17 19:43:33 +00:00
|
|
|
return CreateSimpleType(type_id.index, ct);
|
2018-10-23 16:37:53 +00:00
|
|
|
|
2018-11-16 02:42:32 +00:00
|
|
|
TpiStream &stream = type_id.is_ipi ? m_index->ipi() : m_index->tpi();
|
|
|
|
|
CVType cvt = stream.getType(type_id.index);
|
2018-10-23 16:37:53 +00:00
|
|
|
|
|
|
|
|
if (cvt.kind() == LF_MODIFIER) {
|
|
|
|
|
ModifierRecord modifier;
|
|
|
|
|
llvm::cantFail(
|
|
|
|
|
TypeDeserializer::deserializeAs<ModifierRecord>(cvt, modifier));
|
2018-12-17 19:43:33 +00:00
|
|
|
return CreateModifierType(type_id, modifier, ct);
|
2018-10-23 16:37:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (cvt.kind() == LF_POINTER) {
|
|
|
|
|
PointerRecord pointer;
|
|
|
|
|
llvm::cantFail(
|
|
|
|
|
TypeDeserializer::deserializeAs<PointerRecord>(cvt, pointer));
|
2018-12-17 19:43:33 +00:00
|
|
|
return CreatePointerType(type_id, pointer, ct);
|
2018-10-23 16:37:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (IsClassRecord(cvt.kind())) {
|
|
|
|
|
ClassRecord cr;
|
|
|
|
|
llvm::cantFail(TypeDeserializer::deserializeAs<ClassRecord>(cvt, cr));
|
2018-12-17 19:43:33 +00:00
|
|
|
return CreateTagType(type_id, cr, ct);
|
2018-10-23 16:37:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (cvt.kind() == LF_ENUM) {
|
|
|
|
|
EnumRecord er;
|
|
|
|
|
llvm::cantFail(TypeDeserializer::deserializeAs<EnumRecord>(cvt, er));
|
2018-12-17 19:43:33 +00:00
|
|
|
return CreateTagType(type_id, er, ct);
|
2018-10-23 16:37:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (cvt.kind() == LF_UNION) {
|
|
|
|
|
UnionRecord ur;
|
|
|
|
|
llvm::cantFail(TypeDeserializer::deserializeAs<UnionRecord>(cvt, ur));
|
2018-12-17 19:43:33 +00:00
|
|
|
return CreateTagType(type_id, ur, ct);
|
2018-10-23 16:37:53 +00:00
|
|
|
}
|
|
|
|
|
|
[NativePDB] Add support for dumping global variables of class type.
Previous patches added support for dumping global variables of
primitive types, so we now do the same for class types.
For the most part, everything just worked, there was only one
minor bug needing fixed, which was that for variables of modified
types (e.g. const, volatile, etc) we can't resolve the forward
decl in CreateAndCacheType because the PdbSymUid must point to the
LF_MODIFIER which must point to the forward decl. So when it comes
time to call CompleteType, an assert was firing because we expected
to get a class, struct, union, or enum, but we were getting an
LF_MODIFIER instead.
The other issue is that one the newly added tests is for an array
member, which was not yet supported, so we add support for that
now in this patch.
There's probably room for other interesting layout test cases
here, but this at least should test the basics.
Differential Revision: https://reviews.llvm.org/D53822
llvm-svn: 345629
2018-10-30 18:57:08 +00:00
|
|
|
if (cvt.kind() == LF_ARRAY) {
|
|
|
|
|
ArrayRecord ar;
|
|
|
|
|
llvm::cantFail(TypeDeserializer::deserializeAs<ArrayRecord>(cvt, ar));
|
2018-12-17 19:43:33 +00:00
|
|
|
return CreateArrayType(type_id, ar, ct);
|
[NativePDB] Add support for dumping global variables of class type.
Previous patches added support for dumping global variables of
primitive types, so we now do the same for class types.
For the most part, everything just worked, there was only one
minor bug needing fixed, which was that for variables of modified
types (e.g. const, volatile, etc) we can't resolve the forward
decl in CreateAndCacheType because the PdbSymUid must point to the
LF_MODIFIER which must point to the forward decl. So when it comes
time to call CompleteType, an assert was firing because we expected
to get a class, struct, union, or enum, but we were getting an
LF_MODIFIER instead.
The other issue is that one the newly added tests is for an array
member, which was not yet supported, so we add support for that
now in this patch.
There's probably room for other interesting layout test cases
here, but this at least should test the basics.
Differential Revision: https://reviews.llvm.org/D53822
llvm-svn: 345629
2018-10-30 18:57:08 +00:00
|
|
|
}
|
|
|
|
|
|
2018-11-01 16:37:29 +00:00
|
|
|
if (cvt.kind() == LF_PROCEDURE) {
|
|
|
|
|
ProcedureRecord pr;
|
|
|
|
|
llvm::cantFail(TypeDeserializer::deserializeAs<ProcedureRecord>(cvt, pr));
|
2018-12-17 19:43:33 +00:00
|
|
|
return CreateProcedureType(type_id, pr, ct);
|
2018-11-01 16:37:29 +00:00
|
|
|
}
|
|
|
|
|
|
2018-10-23 16:37:53 +00:00
|
|
|
return nullptr;
|
|
|
|
|
}
|
|
|
|
|
|
2018-11-16 02:42:32 +00:00
|
|
|
TypeSP SymbolFileNativePDB::CreateAndCacheType(PdbTypeSymId type_id) {
|
2018-10-23 16:37:53 +00:00
|
|
|
// If they search for a UDT which is a forward ref, try and resolve the full
|
|
|
|
|
// decl and just map the forward ref uid to the full decl record.
|
2018-11-16 02:42:32 +00:00
|
|
|
llvm::Optional<PdbTypeSymId> full_decl_uid;
|
|
|
|
|
if (IsForwardRefUdt(type_id, m_index->tpi())) {
|
|
|
|
|
auto expected_full_ti =
|
|
|
|
|
m_index->tpi().findFullDeclForForwardRef(type_id.index);
|
|
|
|
|
if (!expected_full_ti)
|
|
|
|
|
llvm::consumeError(expected_full_ti.takeError());
|
|
|
|
|
else if (*expected_full_ti != type_id.index) {
|
2018-11-16 03:16:27 +00:00
|
|
|
full_decl_uid = PdbTypeSymId(*expected_full_ti, false);
|
2018-11-16 02:42:32 +00:00
|
|
|
|
|
|
|
|
// It's possible that a lookup would occur for the full decl causing it
|
|
|
|
|
// to be cached, then a second lookup would occur for the forward decl.
|
|
|
|
|
// We don't want to create a second full decl, so make sure the full
|
|
|
|
|
// decl hasn't already been cached.
|
|
|
|
|
auto full_iter = m_types.find(toOpaqueUid(*full_decl_uid));
|
|
|
|
|
if (full_iter != m_types.end()) {
|
|
|
|
|
TypeSP result = full_iter->second;
|
|
|
|
|
// Map the forward decl to the TypeSP for the full decl so we can take
|
|
|
|
|
// the fast path next time.
|
|
|
|
|
m_types[toOpaqueUid(type_id)] = result;
|
|
|
|
|
return result;
|
2018-10-23 16:37:53 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2018-11-16 02:42:32 +00:00
|
|
|
PdbTypeSymId best_decl_id = full_decl_uid ? *full_decl_uid : type_id;
|
2018-12-17 19:43:33 +00:00
|
|
|
|
|
|
|
|
clang::QualType qt = m_ast->GetOrCreateType(best_decl_id);
|
|
|
|
|
|
|
|
|
|
TypeSP result = CreateType(best_decl_id, m_ast->ToCompilerType(qt));
|
2018-11-01 16:37:29 +00:00
|
|
|
if (!result)
|
|
|
|
|
return nullptr;
|
2018-11-16 02:42:32 +00:00
|
|
|
|
|
|
|
|
uint64_t best_uid = toOpaqueUid(best_decl_id);
|
|
|
|
|
m_types[best_uid] = result;
|
2018-10-23 16:37:53 +00:00
|
|
|
// If we had both a forward decl and a full decl, make both point to the new
|
|
|
|
|
// type.
|
|
|
|
|
if (full_decl_uid)
|
2018-11-16 02:42:32 +00:00
|
|
|
m_types[toOpaqueUid(type_id)] = result;
|
2018-10-23 16:37:53 +00:00
|
|
|
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
2018-11-16 02:42:32 +00:00
|
|
|
TypeSP SymbolFileNativePDB::GetOrCreateType(PdbTypeSymId type_id) {
|
2018-10-23 16:37:53 +00:00
|
|
|
// We can't use try_emplace / overwrite here because the process of creating
|
|
|
|
|
// a type could create nested types, which could invalidate iterators. So
|
|
|
|
|
// we have to do a 2-phase lookup / insert.
|
2018-11-16 02:42:32 +00:00
|
|
|
auto iter = m_types.find(toOpaqueUid(type_id));
|
2018-10-23 16:37:53 +00:00
|
|
|
if (iter != m_types.end())
|
|
|
|
|
return iter->second;
|
|
|
|
|
|
2019-01-10 20:57:32 +00:00
|
|
|
TypeSP type = CreateAndCacheType(type_id);
|
|
|
|
|
if (type)
|
|
|
|
|
m_obj_file->GetModule()->GetTypeList()->Insert(type);
|
|
|
|
|
return type;
|
2018-10-23 16:37:53 +00:00
|
|
|
}
|
|
|
|
|
|
2018-11-16 02:42:32 +00:00
|
|
|
VariableSP SymbolFileNativePDB::CreateGlobalVariable(PdbGlobalSymId var_id) {
|
|
|
|
|
CVSymbol sym = m_index->symrecords().readRecord(var_id.offset);
|
2018-11-13 20:07:57 +00:00
|
|
|
if (sym.kind() == S_CONSTANT)
|
2018-11-16 02:42:32 +00:00
|
|
|
return CreateConstantSymbol(var_id, sym);
|
2018-11-13 20:07:57 +00:00
|
|
|
|
[NativePDB] Add the ability to dump dump global variables.
LLDB has the ability to display global variables, even without a running
process, via the target variable command. This is because global
variables are linker initialized, so their values are embedded directly
into the executables. This gives us great power for testing native PDB
functionality in a cross-platform manner, because we don't actually need
a running process. We can just create a target using an EXE file, and
display global variables. And global variables can have arbitrarily
complex types, so in theory we can fully exercise the type system,
record layout, and data formatters for native PDB files and PE/COFF
executables on any host platform, as long as our type does not require a
dynamic initializer.
This patch adds basic support for finding variables by name, and adds an
exhaustive test for fundamental data types and pointers / references to
fundamental data types.
Subsequent patches will extend this to typedefs, classes, pointers to
functions, and other cases.
Differential Revision: https://reviews.llvm.org/D53731
llvm-svn: 345373
2018-10-26 09:06:38 +00:00
|
|
|
lldb::ValueType scope = eValueTypeInvalid;
|
|
|
|
|
TypeIndex ti;
|
|
|
|
|
llvm::StringRef name;
|
|
|
|
|
lldb::addr_t addr = 0;
|
|
|
|
|
uint16_t section = 0;
|
|
|
|
|
uint32_t offset = 0;
|
|
|
|
|
bool is_external = false;
|
|
|
|
|
switch (sym.kind()) {
|
|
|
|
|
case S_GDATA32:
|
|
|
|
|
is_external = true;
|
|
|
|
|
LLVM_FALLTHROUGH;
|
|
|
|
|
case S_LDATA32: {
|
|
|
|
|
DataSym ds(sym.kind());
|
|
|
|
|
llvm::cantFail(SymbolDeserializer::deserializeAs<DataSym>(sym, ds));
|
|
|
|
|
ti = ds.Type;
|
|
|
|
|
scope = (sym.kind() == S_GDATA32) ? eValueTypeVariableGlobal
|
|
|
|
|
: eValueTypeVariableStatic;
|
|
|
|
|
name = ds.Name;
|
|
|
|
|
section = ds.Segment;
|
|
|
|
|
offset = ds.DataOffset;
|
|
|
|
|
addr = m_index->MakeVirtualAddress(ds.Segment, ds.DataOffset);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case S_GTHREAD32:
|
|
|
|
|
is_external = true;
|
|
|
|
|
LLVM_FALLTHROUGH;
|
|
|
|
|
case S_LTHREAD32: {
|
|
|
|
|
ThreadLocalDataSym tlds(sym.kind());
|
|
|
|
|
llvm::cantFail(
|
|
|
|
|
SymbolDeserializer::deserializeAs<ThreadLocalDataSym>(sym, tlds));
|
|
|
|
|
ti = tlds.Type;
|
|
|
|
|
name = tlds.Name;
|
|
|
|
|
section = tlds.Segment;
|
|
|
|
|
offset = tlds.DataOffset;
|
|
|
|
|
addr = m_index->MakeVirtualAddress(tlds.Segment, tlds.DataOffset);
|
|
|
|
|
scope = eValueTypeVariableThreadLocal;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
default:
|
|
|
|
|
llvm_unreachable("unreachable!");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
CompUnitSP comp_unit;
|
|
|
|
|
llvm::Optional<uint16_t> modi = m_index->GetModuleIndexForVa(addr);
|
|
|
|
|
if (modi) {
|
2018-11-16 02:42:32 +00:00
|
|
|
CompilandIndexItem &cci = m_index->compilands().GetOrCreateCompiland(*modi);
|
[NativePDB] Add the ability to dump dump global variables.
LLDB has the ability to display global variables, even without a running
process, via the target variable command. This is because global
variables are linker initialized, so their values are embedded directly
into the executables. This gives us great power for testing native PDB
functionality in a cross-platform manner, because we don't actually need
a running process. We can just create a target using an EXE file, and
display global variables. And global variables can have arbitrarily
complex types, so in theory we can fully exercise the type system,
record layout, and data formatters for native PDB files and PE/COFF
executables on any host platform, as long as our type does not require a
dynamic initializer.
This patch adds basic support for finding variables by name, and adds an
exhaustive test for fundamental data types and pointers / references to
fundamental data types.
Subsequent patches will extend this to typedefs, classes, pointers to
functions, and other cases.
Differential Revision: https://reviews.llvm.org/D53731
llvm-svn: 345373
2018-10-26 09:06:38 +00:00
|
|
|
comp_unit = GetOrCreateCompileUnit(cci);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Declaration decl;
|
2018-11-16 03:16:27 +00:00
|
|
|
PdbTypeSymId tid(ti, false);
|
[NativePDB] Add the ability to dump dump global variables.
LLDB has the ability to display global variables, even without a running
process, via the target variable command. This is because global
variables are linker initialized, so their values are embedded directly
into the executables. This gives us great power for testing native PDB
functionality in a cross-platform manner, because we don't actually need
a running process. We can just create a target using an EXE file, and
display global variables. And global variables can have arbitrarily
complex types, so in theory we can fully exercise the type system,
record layout, and data formatters for native PDB files and PE/COFF
executables on any host platform, as long as our type does not require a
dynamic initializer.
This patch adds basic support for finding variables by name, and adds an
exhaustive test for fundamental data types and pointers / references to
fundamental data types.
Subsequent patches will extend this to typedefs, classes, pointers to
functions, and other cases.
Differential Revision: https://reviews.llvm.org/D53731
llvm-svn: 345373
2018-10-26 09:06:38 +00:00
|
|
|
SymbolFileTypeSP type_sp =
|
2018-11-16 02:42:32 +00:00
|
|
|
std::make_shared<SymbolFileType>(*this, toOpaqueUid(tid));
|
[NativePDB] Add the ability to dump dump global variables.
LLDB has the ability to display global variables, even without a running
process, via the target variable command. This is because global
variables are linker initialized, so their values are embedded directly
into the executables. This gives us great power for testing native PDB
functionality in a cross-platform manner, because we don't actually need
a running process. We can just create a target using an EXE file, and
display global variables. And global variables can have arbitrarily
complex types, so in theory we can fully exercise the type system,
record layout, and data formatters for native PDB files and PE/COFF
executables on any host platform, as long as our type does not require a
dynamic initializer.
This patch adds basic support for finding variables by name, and adds an
exhaustive test for fundamental data types and pointers / references to
fundamental data types.
Subsequent patches will extend this to typedefs, classes, pointers to
functions, and other cases.
Differential Revision: https://reviews.llvm.org/D53731
llvm-svn: 345373
2018-10-26 09:06:38 +00:00
|
|
|
Variable::RangeList ranges;
|
|
|
|
|
|
2019-01-02 18:33:54 +00:00
|
|
|
m_ast->GetOrCreateVariableDecl(var_id);
|
2018-12-20 23:32:37 +00:00
|
|
|
|
[NativePDB] Add the ability to dump dump global variables.
LLDB has the ability to display global variables, even without a running
process, via the target variable command. This is because global
variables are linker initialized, so their values are embedded directly
into the executables. This gives us great power for testing native PDB
functionality in a cross-platform manner, because we don't actually need
a running process. We can just create a target using an EXE file, and
display global variables. And global variables can have arbitrarily
complex types, so in theory we can fully exercise the type system,
record layout, and data formatters for native PDB files and PE/COFF
executables on any host platform, as long as our type does not require a
dynamic initializer.
This patch adds basic support for finding variables by name, and adds an
exhaustive test for fundamental data types and pointers / references to
fundamental data types.
Subsequent patches will extend this to typedefs, classes, pointers to
functions, and other cases.
Differential Revision: https://reviews.llvm.org/D53731
llvm-svn: 345373
2018-10-26 09:06:38 +00:00
|
|
|
DWARFExpression location = MakeGlobalLocationExpression(
|
|
|
|
|
section, offset, GetObjectFile()->GetModule());
|
|
|
|
|
|
|
|
|
|
std::string global_name("::");
|
|
|
|
|
global_name += name;
|
|
|
|
|
VariableSP var_sp = std::make_shared<Variable>(
|
2018-11-16 02:42:32 +00:00
|
|
|
toOpaqueUid(var_id), name.str().c_str(), global_name.c_str(), type_sp,
|
[NativePDB] Add the ability to dump dump global variables.
LLDB has the ability to display global variables, even without a running
process, via the target variable command. This is because global
variables are linker initialized, so their values are embedded directly
into the executables. This gives us great power for testing native PDB
functionality in a cross-platform manner, because we don't actually need
a running process. We can just create a target using an EXE file, and
display global variables. And global variables can have arbitrarily
complex types, so in theory we can fully exercise the type system,
record layout, and data formatters for native PDB files and PE/COFF
executables on any host platform, as long as our type does not require a
dynamic initializer.
This patch adds basic support for finding variables by name, and adds an
exhaustive test for fundamental data types and pointers / references to
fundamental data types.
Subsequent patches will extend this to typedefs, classes, pointers to
functions, and other cases.
Differential Revision: https://reviews.llvm.org/D53731
llvm-svn: 345373
2018-10-26 09:06:38 +00:00
|
|
|
scope, comp_unit.get(), ranges, &decl, location, is_external, false,
|
|
|
|
|
false);
|
|
|
|
|
var_sp->SetLocationIsConstantValueData(false);
|
|
|
|
|
|
|
|
|
|
return var_sp;
|
|
|
|
|
}
|
|
|
|
|
|
2018-11-13 20:07:57 +00:00
|
|
|
lldb::VariableSP
|
2018-11-16 02:42:32 +00:00
|
|
|
SymbolFileNativePDB::CreateConstantSymbol(PdbGlobalSymId var_id,
|
2018-11-13 20:07:57 +00:00
|
|
|
const CVSymbol &cvs) {
|
|
|
|
|
TpiStream &tpi = m_index->tpi();
|
|
|
|
|
ConstantSym constant(cvs.kind());
|
|
|
|
|
|
|
|
|
|
llvm::cantFail(SymbolDeserializer::deserializeAs<ConstantSym>(cvs, constant));
|
|
|
|
|
std::string global_name("::");
|
|
|
|
|
global_name += constant.Name;
|
2018-11-16 03:16:27 +00:00
|
|
|
PdbTypeSymId tid(constant.Type, false);
|
2018-11-13 20:07:57 +00:00
|
|
|
SymbolFileTypeSP type_sp =
|
2018-11-16 02:42:32 +00:00
|
|
|
std::make_shared<SymbolFileType>(*this, toOpaqueUid(tid));
|
2018-11-13 20:07:57 +00:00
|
|
|
|
|
|
|
|
Declaration decl;
|
|
|
|
|
Variable::RangeList ranges;
|
|
|
|
|
ModuleSP module = GetObjectFile()->GetModule();
|
2018-12-06 17:49:15 +00:00
|
|
|
DWARFExpression location = MakeConstantLocationExpression(
|
|
|
|
|
constant.Type, tpi, constant.Value, module);
|
2018-11-13 20:07:57 +00:00
|
|
|
|
|
|
|
|
VariableSP var_sp = std::make_shared<Variable>(
|
2018-11-16 02:42:32 +00:00
|
|
|
toOpaqueUid(var_id), constant.Name.str().c_str(), global_name.c_str(),
|
2018-11-13 20:07:57 +00:00
|
|
|
type_sp, eValueTypeVariableGlobal, module.get(), ranges, &decl, location,
|
|
|
|
|
false, false, false);
|
|
|
|
|
var_sp->SetLocationIsConstantValueData(true);
|
|
|
|
|
return var_sp;
|
|
|
|
|
}
|
|
|
|
|
|
2018-11-16 02:42:32 +00:00
|
|
|
VariableSP
|
|
|
|
|
SymbolFileNativePDB::GetOrCreateGlobalVariable(PdbGlobalSymId var_id) {
|
|
|
|
|
auto emplace_result = m_global_vars.try_emplace(toOpaqueUid(var_id), nullptr);
|
[NativePDB] Add the ability to dump dump global variables.
LLDB has the ability to display global variables, even without a running
process, via the target variable command. This is because global
variables are linker initialized, so their values are embedded directly
into the executables. This gives us great power for testing native PDB
functionality in a cross-platform manner, because we don't actually need
a running process. We can just create a target using an EXE file, and
display global variables. And global variables can have arbitrarily
complex types, so in theory we can fully exercise the type system,
record layout, and data formatters for native PDB files and PE/COFF
executables on any host platform, as long as our type does not require a
dynamic initializer.
This patch adds basic support for finding variables by name, and adds an
exhaustive test for fundamental data types and pointers / references to
fundamental data types.
Subsequent patches will extend this to typedefs, classes, pointers to
functions, and other cases.
Differential Revision: https://reviews.llvm.org/D53731
llvm-svn: 345373
2018-10-26 09:06:38 +00:00
|
|
|
if (emplace_result.second)
|
2018-11-16 02:42:32 +00:00
|
|
|
emplace_result.first->second = CreateGlobalVariable(var_id);
|
[NativePDB] Add the ability to dump dump global variables.
LLDB has the ability to display global variables, even without a running
process, via the target variable command. This is because global
variables are linker initialized, so their values are embedded directly
into the executables. This gives us great power for testing native PDB
functionality in a cross-platform manner, because we don't actually need
a running process. We can just create a target using an EXE file, and
display global variables. And global variables can have arbitrarily
complex types, so in theory we can fully exercise the type system,
record layout, and data formatters for native PDB files and PE/COFF
executables on any host platform, as long as our type does not require a
dynamic initializer.
This patch adds basic support for finding variables by name, and adds an
exhaustive test for fundamental data types and pointers / references to
fundamental data types.
Subsequent patches will extend this to typedefs, classes, pointers to
functions, and other cases.
Differential Revision: https://reviews.llvm.org/D53731
llvm-svn: 345373
2018-10-26 09:06:38 +00:00
|
|
|
|
|
|
|
|
return emplace_result.first->second;
|
|
|
|
|
}
|
|
|
|
|
|
2018-11-16 02:42:32 +00:00
|
|
|
lldb::TypeSP SymbolFileNativePDB::GetOrCreateType(TypeIndex ti) {
|
2018-11-16 03:16:27 +00:00
|
|
|
return GetOrCreateType(PdbTypeSymId(ti, false));
|
2018-10-23 16:37:53 +00:00
|
|
|
}
|
|
|
|
|
|
2018-11-16 02:42:32 +00:00
|
|
|
FunctionSP SymbolFileNativePDB::GetOrCreateFunction(PdbCompilandSymId func_id,
|
2018-12-13 18:17:51 +00:00
|
|
|
CompileUnit &comp_unit) {
|
2018-11-16 02:42:32 +00:00
|
|
|
auto emplace_result = m_functions.try_emplace(toOpaqueUid(func_id), nullptr);
|
2018-10-12 19:47:13 +00:00
|
|
|
if (emplace_result.second)
|
2018-12-13 18:17:51 +00:00
|
|
|
emplace_result.first->second = CreateFunction(func_id, comp_unit);
|
2018-10-12 19:47:13 +00:00
|
|
|
|
|
|
|
|
return emplace_result.first->second;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
CompUnitSP
|
|
|
|
|
SymbolFileNativePDB::GetOrCreateCompileUnit(const CompilandIndexItem &cci) {
|
2018-11-16 02:42:32 +00:00
|
|
|
|
2018-10-12 19:47:13 +00:00
|
|
|
auto emplace_result =
|
2018-11-16 02:42:32 +00:00
|
|
|
m_compilands.try_emplace(toOpaqueUid(cci.m_id), nullptr);
|
2018-10-12 19:47:13 +00:00
|
|
|
if (emplace_result.second)
|
|
|
|
|
emplace_result.first->second = CreateCompileUnit(cci);
|
|
|
|
|
|
|
|
|
|
lldbassert(emplace_result.first->second);
|
|
|
|
|
return emplace_result.first->second;
|
|
|
|
|
}
|
|
|
|
|
|
2018-12-13 18:17:51 +00:00
|
|
|
Block &SymbolFileNativePDB::GetOrCreateBlock(PdbCompilandSymId block_id) {
|
|
|
|
|
auto iter = m_blocks.find(toOpaqueUid(block_id));
|
|
|
|
|
if (iter != m_blocks.end())
|
|
|
|
|
return *iter->second;
|
|
|
|
|
|
|
|
|
|
return CreateBlock(block_id);
|
|
|
|
|
}
|
|
|
|
|
|
2019-01-02 18:33:54 +00:00
|
|
|
void SymbolFileNativePDB::ParseDeclsForContext(
|
|
|
|
|
lldb_private::CompilerDeclContext decl_ctx) {
|
|
|
|
|
clang::DeclContext *context = m_ast->FromCompilerDeclContext(decl_ctx);
|
|
|
|
|
if (!context)
|
|
|
|
|
return;
|
|
|
|
|
m_ast->ParseDeclsForContext(*context);
|
|
|
|
|
}
|
|
|
|
|
|
2018-10-12 19:47:13 +00:00
|
|
|
lldb::CompUnitSP SymbolFileNativePDB::ParseCompileUnitAtIndex(uint32_t index) {
|
|
|
|
|
if (index >= GetNumCompileUnits())
|
|
|
|
|
return CompUnitSP();
|
|
|
|
|
lldbassert(index < UINT16_MAX);
|
|
|
|
|
if (index >= UINT16_MAX)
|
|
|
|
|
return nullptr;
|
|
|
|
|
|
|
|
|
|
CompilandIndexItem &item = m_index->compilands().GetOrCreateCompiland(index);
|
|
|
|
|
|
|
|
|
|
return GetOrCreateCompileUnit(item);
|
|
|
|
|
}
|
|
|
|
|
|
2019-01-11 18:03:20 +00:00
|
|
|
lldb::LanguageType SymbolFileNativePDB::ParseLanguage(CompileUnit &comp_unit) {
|
|
|
|
|
PdbSymUid uid(comp_unit.GetID());
|
2018-11-16 02:42:32 +00:00
|
|
|
lldbassert(uid.kind() == PdbSymUidKind::Compiland);
|
2018-10-12 19:47:13 +00:00
|
|
|
|
2018-11-16 02:42:32 +00:00
|
|
|
CompilandIndexItem *item =
|
|
|
|
|
m_index->compilands().GetCompiland(uid.asCompiland().modi);
|
2018-10-12 19:47:13 +00:00
|
|
|
lldbassert(item);
|
|
|
|
|
if (!item->m_compile_opts)
|
|
|
|
|
return lldb::eLanguageTypeUnknown;
|
|
|
|
|
|
|
|
|
|
return TranslateLanguage(item->m_compile_opts->getLanguage());
|
|
|
|
|
}
|
|
|
|
|
|
2019-01-02 18:32:50 +00:00
|
|
|
void SymbolFileNativePDB::AddSymbols(Symtab &symtab) { return; }
|
|
|
|
|
|
2019-01-11 18:03:20 +00:00
|
|
|
size_t SymbolFileNativePDB::ParseFunctions(CompileUnit &comp_unit) {
|
|
|
|
|
PdbSymUid uid{comp_unit.GetID()};
|
2019-01-10 20:57:32 +00:00
|
|
|
lldbassert(uid.kind() == PdbSymUidKind::Compiland);
|
|
|
|
|
uint16_t modi = uid.asCompiland().modi;
|
|
|
|
|
CompilandIndexItem &cii = m_index->compilands().GetOrCreateCompiland(modi);
|
|
|
|
|
|
2019-01-11 18:03:20 +00:00
|
|
|
size_t count = comp_unit.GetNumFunctions();
|
2019-01-10 20:57:32 +00:00
|
|
|
const CVSymbolArray &syms = cii.m_debug_stream.getSymbolArray();
|
|
|
|
|
for (auto iter = syms.begin(); iter != syms.end(); ++iter) {
|
|
|
|
|
if (iter->kind() != S_LPROC32 && iter->kind() != S_GPROC32)
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
PdbCompilandSymId sym_id{modi, iter.offset()};
|
|
|
|
|
|
2019-01-11 18:03:20 +00:00
|
|
|
FunctionSP func = GetOrCreateFunction(sym_id, comp_unit);
|
2019-01-10 20:57:32 +00:00
|
|
|
}
|
|
|
|
|
|
2019-01-11 18:03:20 +00:00
|
|
|
size_t new_count = comp_unit.GetNumFunctions();
|
2019-01-10 20:57:32 +00:00
|
|
|
lldbassert(new_count >= count);
|
|
|
|
|
return new_count - count;
|
2018-10-12 19:47:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static bool NeedsResolvedCompileUnit(uint32_t resolve_scope) {
|
|
|
|
|
// If any of these flags are set, we need to resolve the compile unit.
|
|
|
|
|
uint32_t flags = eSymbolContextCompUnit;
|
|
|
|
|
flags |= eSymbolContextVariable;
|
|
|
|
|
flags |= eSymbolContextFunction;
|
|
|
|
|
flags |= eSymbolContextBlock;
|
|
|
|
|
flags |= eSymbolContextLineEntry;
|
|
|
|
|
return (resolve_scope & flags) != 0;
|
|
|
|
|
}
|
|
|
|
|
|
2018-10-25 20:45:19 +00:00
|
|
|
uint32_t SymbolFileNativePDB::ResolveSymbolContext(
|
|
|
|
|
const Address &addr, SymbolContextItem resolve_scope, SymbolContext &sc) {
|
2018-10-12 19:47:13 +00:00
|
|
|
uint32_t resolved_flags = 0;
|
|
|
|
|
lldb::addr_t file_addr = addr.GetFileAddress();
|
|
|
|
|
|
|
|
|
|
if (NeedsResolvedCompileUnit(resolve_scope)) {
|
|
|
|
|
llvm::Optional<uint16_t> modi = m_index->GetModuleIndexForVa(file_addr);
|
|
|
|
|
if (!modi)
|
|
|
|
|
return 0;
|
2018-11-16 02:42:32 +00:00
|
|
|
CompilandIndexItem *cci = m_index->compilands().GetCompiland(*modi);
|
2018-10-12 19:47:13 +00:00
|
|
|
if (!cci)
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
sc.comp_unit = GetOrCreateCompileUnit(*cci).get();
|
|
|
|
|
resolved_flags |= eSymbolContextCompUnit;
|
|
|
|
|
}
|
|
|
|
|
|
2018-12-13 18:17:51 +00:00
|
|
|
if (resolve_scope & eSymbolContextFunction ||
|
|
|
|
|
resolve_scope & eSymbolContextBlock) {
|
2018-10-12 19:47:13 +00:00
|
|
|
lldbassert(sc.comp_unit);
|
|
|
|
|
std::vector<SymbolAndUid> matches = m_index->FindSymbolsByVa(file_addr);
|
2018-12-13 18:17:51 +00:00
|
|
|
// Search the matches in reverse. This way if there are multiple matches
|
|
|
|
|
// (for example we are 3 levels deep in a nested scope) it will find the
|
|
|
|
|
// innermost one first.
|
|
|
|
|
for (const auto &match : llvm::reverse(matches)) {
|
2018-11-16 02:42:32 +00:00
|
|
|
if (match.uid.kind() != PdbSymUidKind::CompilandSym)
|
|
|
|
|
continue;
|
2018-12-13 18:17:51 +00:00
|
|
|
|
2018-11-16 02:42:32 +00:00
|
|
|
PdbCompilandSymId csid = match.uid.asCompilandSym();
|
|
|
|
|
CVSymbol cvs = m_index->ReadSymbolRecord(csid);
|
2018-12-13 18:17:51 +00:00
|
|
|
PDB_SymType type = CVSymToPDBSym(cvs.kind());
|
|
|
|
|
if (type != PDB_SymType::Function && type != PDB_SymType::Block)
|
2018-10-12 19:47:13 +00:00
|
|
|
continue;
|
2018-12-13 18:17:51 +00:00
|
|
|
if (type == PDB_SymType::Function) {
|
|
|
|
|
sc.function = GetOrCreateFunction(csid, *sc.comp_unit).get();
|
|
|
|
|
sc.block = sc.GetFunctionBlock();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (type == PDB_SymType::Block) {
|
|
|
|
|
sc.block = &GetOrCreateBlock(csid);
|
|
|
|
|
sc.function = sc.block->CalculateSymbolContextFunction();
|
|
|
|
|
}
|
2018-10-12 19:47:13 +00:00
|
|
|
resolved_flags |= eSymbolContextFunction;
|
2018-12-13 18:17:51 +00:00
|
|
|
resolved_flags |= eSymbolContextBlock;
|
|
|
|
|
break;
|
|
|
|
|
}
|
2018-10-12 19:47:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (resolve_scope & eSymbolContextLineEntry) {
|
|
|
|
|
lldbassert(sc.comp_unit);
|
|
|
|
|
if (auto *line_table = sc.comp_unit->GetLineTable()) {
|
|
|
|
|
if (line_table->FindLineEntryByAddress(addr, sc.line_entry))
|
|
|
|
|
resolved_flags |= eSymbolContextLineEntry;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return resolved_flags;
|
|
|
|
|
}
|
|
|
|
|
|
2019-01-02 18:32:50 +00:00
|
|
|
uint32_t SymbolFileNativePDB::ResolveSymbolContext(
|
|
|
|
|
const FileSpec &file_spec, uint32_t line, bool check_inlines,
|
|
|
|
|
lldb::SymbolContextItem resolve_scope, SymbolContextList &sc_list) {
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2018-10-12 19:47:13 +00:00
|
|
|
static void AppendLineEntryToSequence(LineTable &table, LineSequence &sequence,
|
|
|
|
|
const CompilandIndexItem &cci,
|
|
|
|
|
lldb::addr_t base_addr,
|
|
|
|
|
uint32_t file_number,
|
|
|
|
|
const LineFragmentHeader &block,
|
|
|
|
|
const LineNumberEntry &cur) {
|
|
|
|
|
LineInfo cur_info(cur.Flags);
|
|
|
|
|
|
|
|
|
|
if (cur_info.isAlwaysStepInto() || cur_info.isNeverStepInto())
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
uint64_t addr = base_addr + cur.Offset;
|
|
|
|
|
|
|
|
|
|
bool is_statement = cur_info.isStatement();
|
|
|
|
|
bool is_prologue = IsFunctionPrologue(cci, addr);
|
|
|
|
|
bool is_epilogue = IsFunctionEpilogue(cci, addr);
|
|
|
|
|
|
|
|
|
|
uint32_t lno = cur_info.getStartLine();
|
|
|
|
|
|
|
|
|
|
table.AppendLineEntryToSequence(&sequence, addr, lno, 0, file_number,
|
|
|
|
|
is_statement, false, is_prologue, is_epilogue,
|
|
|
|
|
false);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void TerminateLineSequence(LineTable &table,
|
|
|
|
|
const LineFragmentHeader &block,
|
|
|
|
|
lldb::addr_t base_addr, uint32_t file_number,
|
|
|
|
|
uint32_t last_line,
|
|
|
|
|
std::unique_ptr<LineSequence> seq) {
|
|
|
|
|
// The end is always a terminal entry, so insert it regardless.
|
|
|
|
|
table.AppendLineEntryToSequence(seq.get(), base_addr + block.CodeSize,
|
|
|
|
|
last_line, 0, file_number, false, false,
|
|
|
|
|
false, false, true);
|
|
|
|
|
table.InsertSequence(seq.release());
|
|
|
|
|
}
|
|
|
|
|
|
2019-01-11 18:03:20 +00:00
|
|
|
bool SymbolFileNativePDB::ParseLineTable(CompileUnit &comp_unit) {
|
2018-10-12 19:47:13 +00:00
|
|
|
// Unfortunately LLDB is set up to parse the entire compile unit line table
|
|
|
|
|
// all at once, even if all it really needs is line info for a specific
|
|
|
|
|
// function. In the future it would be nice if it could set the sc.m_function
|
|
|
|
|
// member, and we could only get the line info for the function in question.
|
2019-01-11 18:03:20 +00:00
|
|
|
PdbSymUid cu_id(comp_unit.GetID());
|
2018-11-16 02:42:32 +00:00
|
|
|
lldbassert(cu_id.kind() == PdbSymUidKind::Compiland);
|
|
|
|
|
CompilandIndexItem *cci =
|
|
|
|
|
m_index->compilands().GetCompiland(cu_id.asCompiland().modi);
|
2018-10-12 19:47:13 +00:00
|
|
|
lldbassert(cci);
|
2019-01-11 18:03:20 +00:00
|
|
|
auto line_table = llvm::make_unique<LineTable>(&comp_unit);
|
2018-10-12 19:47:13 +00:00
|
|
|
|
|
|
|
|
// This is basically a copy of the .debug$S subsections from all original COFF
|
|
|
|
|
// object files merged together with address relocations applied. We are
|
|
|
|
|
// looking for all DEBUG_S_LINES subsections.
|
|
|
|
|
for (const DebugSubsectionRecord &dssr :
|
|
|
|
|
cci->m_debug_stream.getSubsectionsArray()) {
|
|
|
|
|
if (dssr.kind() != DebugSubsectionKind::Lines)
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
DebugLinesSubsectionRef lines;
|
|
|
|
|
llvm::BinaryStreamReader reader(dssr.getRecordData());
|
|
|
|
|
if (auto EC = lines.initialize(reader)) {
|
|
|
|
|
llvm::consumeError(std::move(EC));
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const LineFragmentHeader *lfh = lines.header();
|
|
|
|
|
uint64_t virtual_addr =
|
|
|
|
|
m_index->MakeVirtualAddress(lfh->RelocSegment, lfh->RelocOffset);
|
|
|
|
|
|
|
|
|
|
const auto &checksums = cci->m_strings.checksums().getArray();
|
|
|
|
|
const auto &strings = cci->m_strings.strings();
|
|
|
|
|
for (const LineColumnEntry &group : lines) {
|
|
|
|
|
// Indices in this structure are actually offsets of records in the
|
|
|
|
|
// DEBUG_S_FILECHECKSUMS subsection. Those entries then have an index
|
|
|
|
|
// into the global PDB string table.
|
|
|
|
|
auto iter = checksums.at(group.NameIndex);
|
|
|
|
|
if (iter == checksums.end())
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
llvm::Expected<llvm::StringRef> efn =
|
|
|
|
|
strings.getString(iter->FileNameOffset);
|
|
|
|
|
if (!efn) {
|
|
|
|
|
llvm::consumeError(efn.takeError());
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// LLDB wants the index of the file in the list of support files.
|
|
|
|
|
auto fn_iter = llvm::find(cci->m_file_list, *efn);
|
|
|
|
|
lldbassert(fn_iter != cci->m_file_list.end());
|
2019-01-02 18:32:50 +00:00
|
|
|
// LLDB support file indices are 1-based.
|
|
|
|
|
uint32_t file_index =
|
|
|
|
|
1 + std::distance(cci->m_file_list.begin(), fn_iter);
|
2018-10-12 19:47:13 +00:00
|
|
|
|
|
|
|
|
std::unique_ptr<LineSequence> sequence(
|
|
|
|
|
line_table->CreateLineSequenceContainer());
|
|
|
|
|
lldbassert(!group.LineNumbers.empty());
|
|
|
|
|
|
|
|
|
|
for (const LineNumberEntry &entry : group.LineNumbers) {
|
|
|
|
|
AppendLineEntryToSequence(*line_table, *sequence, *cci, virtual_addr,
|
|
|
|
|
file_index, *lfh, entry);
|
|
|
|
|
}
|
|
|
|
|
LineInfo last_line(group.LineNumbers.back().Flags);
|
|
|
|
|
TerminateLineSequence(*line_table, *lfh, virtual_addr, file_index,
|
|
|
|
|
last_line.getEndLine(), std::move(sequence));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (line_table->GetSize() == 0)
|
|
|
|
|
return false;
|
|
|
|
|
|
2019-01-11 18:03:20 +00:00
|
|
|
comp_unit.SetLineTable(line_table.release());
|
2018-10-12 19:47:13 +00:00
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2019-01-11 18:03:20 +00:00
|
|
|
bool SymbolFileNativePDB::ParseDebugMacros(CompileUnit &comp_unit) {
|
2018-10-12 19:47:13 +00:00
|
|
|
// PDB doesn't contain information about macros
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2019-01-11 18:03:20 +00:00
|
|
|
bool SymbolFileNativePDB::ParseSupportFiles(CompileUnit &comp_unit,
|
|
|
|
|
FileSpecList &support_files) {
|
|
|
|
|
PdbSymUid cu_id(comp_unit.GetID());
|
2018-11-16 02:42:32 +00:00
|
|
|
lldbassert(cu_id.kind() == PdbSymUidKind::Compiland);
|
|
|
|
|
CompilandIndexItem *cci =
|
|
|
|
|
m_index->compilands().GetCompiland(cu_id.asCompiland().modi);
|
2018-10-12 19:47:13 +00:00
|
|
|
lldbassert(cci);
|
|
|
|
|
|
|
|
|
|
for (llvm::StringRef f : cci->m_file_list) {
|
|
|
|
|
FileSpec::Style style =
|
|
|
|
|
f.startswith("/") ? FileSpec::Style::posix : FileSpec::Style::windows;
|
2018-11-01 21:05:36 +00:00
|
|
|
FileSpec spec(f, style);
|
2018-10-12 19:47:13 +00:00
|
|
|
support_files.Append(spec);
|
|
|
|
|
}
|
|
|
|
|
|
2019-01-02 18:32:50 +00:00
|
|
|
llvm::SmallString<64> main_source_file =
|
|
|
|
|
m_index->compilands().GetMainSourceFile(*cci);
|
|
|
|
|
FileSpec::Style style = main_source_file.startswith("/")
|
|
|
|
|
? FileSpec::Style::posix
|
|
|
|
|
: FileSpec::Style::windows;
|
|
|
|
|
FileSpec spec(main_source_file, style);
|
|
|
|
|
support_files.Insert(0, spec);
|
2018-10-12 19:47:13 +00:00
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool SymbolFileNativePDB::ParseImportedModules(
|
2019-02-13 18:10:41 +00:00
|
|
|
const SymbolContext &sc, std::vector<SourceModule> &imported_modules) {
|
2018-10-12 19:47:13 +00:00
|
|
|
// PDB does not yet support module debug info
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2019-01-14 22:40:41 +00:00
|
|
|
size_t SymbolFileNativePDB::ParseBlocksRecursive(Function &func) {
|
|
|
|
|
GetOrCreateBlock(PdbSymUid(func.GetID()).asCompilandSym());
|
2018-12-13 18:17:51 +00:00
|
|
|
// FIXME: Parse child blocks
|
|
|
|
|
return 1;
|
2018-10-12 19:47:13 +00:00
|
|
|
}
|
|
|
|
|
|
2018-12-17 19:43:33 +00:00
|
|
|
void SymbolFileNativePDB::DumpClangAST(Stream &s) { m_ast->Dump(s); }
|
2018-11-05 17:40:28 +00:00
|
|
|
|
[NativePDB] Add the ability to dump dump global variables.
LLDB has the ability to display global variables, even without a running
process, via the target variable command. This is because global
variables are linker initialized, so their values are embedded directly
into the executables. This gives us great power for testing native PDB
functionality in a cross-platform manner, because we don't actually need
a running process. We can just create a target using an EXE file, and
display global variables. And global variables can have arbitrarily
complex types, so in theory we can fully exercise the type system,
record layout, and data formatters for native PDB files and PE/COFF
executables on any host platform, as long as our type does not require a
dynamic initializer.
This patch adds basic support for finding variables by name, and adds an
exhaustive test for fundamental data types and pointers / references to
fundamental data types.
Subsequent patches will extend this to typedefs, classes, pointers to
functions, and other cases.
Differential Revision: https://reviews.llvm.org/D53731
llvm-svn: 345373
2018-10-26 09:06:38 +00:00
|
|
|
uint32_t SymbolFileNativePDB::FindGlobalVariables(
|
|
|
|
|
const ConstString &name, const CompilerDeclContext *parent_decl_ctx,
|
|
|
|
|
uint32_t max_matches, VariableList &variables) {
|
|
|
|
|
using SymbolAndOffset = std::pair<uint32_t, llvm::codeview::CVSymbol>;
|
|
|
|
|
|
|
|
|
|
std::vector<SymbolAndOffset> results = m_index->globals().findRecordsByName(
|
|
|
|
|
name.GetStringRef(), m_index->symrecords());
|
|
|
|
|
for (const SymbolAndOffset &result : results) {
|
|
|
|
|
VariableSP var;
|
|
|
|
|
switch (result.second.kind()) {
|
|
|
|
|
case SymbolKind::S_GDATA32:
|
|
|
|
|
case SymbolKind::S_LDATA32:
|
|
|
|
|
case SymbolKind::S_GTHREAD32:
|
2018-11-13 20:07:57 +00:00
|
|
|
case SymbolKind::S_LTHREAD32:
|
|
|
|
|
case SymbolKind::S_CONSTANT: {
|
2018-11-16 03:16:27 +00:00
|
|
|
PdbGlobalSymId global(result.first, false);
|
2018-11-16 02:42:32 +00:00
|
|
|
var = GetOrCreateGlobalVariable(global);
|
[NativePDB] Add the ability to dump dump global variables.
LLDB has the ability to display global variables, even without a running
process, via the target variable command. This is because global
variables are linker initialized, so their values are embedded directly
into the executables. This gives us great power for testing native PDB
functionality in a cross-platform manner, because we don't actually need
a running process. We can just create a target using an EXE file, and
display global variables. And global variables can have arbitrarily
complex types, so in theory we can fully exercise the type system,
record layout, and data formatters for native PDB files and PE/COFF
executables on any host platform, as long as our type does not require a
dynamic initializer.
This patch adds basic support for finding variables by name, and adds an
exhaustive test for fundamental data types and pointers / references to
fundamental data types.
Subsequent patches will extend this to typedefs, classes, pointers to
functions, and other cases.
Differential Revision: https://reviews.llvm.org/D53731
llvm-svn: 345373
2018-10-26 09:06:38 +00:00
|
|
|
variables.AddVariable(var);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
default:
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return variables.GetSize();
|
|
|
|
|
}
|
|
|
|
|
|
2018-10-12 19:47:13 +00:00
|
|
|
uint32_t SymbolFileNativePDB::FindFunctions(
|
2018-10-22 16:19:07 +00:00
|
|
|
const ConstString &name, const CompilerDeclContext *parent_decl_ctx,
|
2018-10-25 20:45:40 +00:00
|
|
|
FunctionNameType name_type_mask, bool include_inlines, bool append,
|
2018-10-22 16:19:07 +00:00
|
|
|
SymbolContextList &sc_list) {
|
2018-10-12 19:47:13 +00:00
|
|
|
// For now we only support lookup by method name.
|
|
|
|
|
if (!(name_type_mask & eFunctionNameTypeMethod))
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
using SymbolAndOffset = std::pair<uint32_t, llvm::codeview::CVSymbol>;
|
|
|
|
|
|
|
|
|
|
std::vector<SymbolAndOffset> matches = m_index->globals().findRecordsByName(
|
|
|
|
|
name.GetStringRef(), m_index->symrecords());
|
|
|
|
|
for (const SymbolAndOffset &match : matches) {
|
|
|
|
|
if (match.second.kind() != S_PROCREF && match.second.kind() != S_LPROCREF)
|
|
|
|
|
continue;
|
|
|
|
|
ProcRefSym proc(match.second.kind());
|
|
|
|
|
cantFail(SymbolDeserializer::deserializeAs<ProcRefSym>(match.second, proc));
|
|
|
|
|
|
|
|
|
|
if (!IsValidRecord(proc))
|
|
|
|
|
continue;
|
|
|
|
|
|
2018-11-16 02:42:32 +00:00
|
|
|
CompilandIndexItem &cci =
|
|
|
|
|
m_index->compilands().GetOrCreateCompiland(proc.modi());
|
2018-10-22 16:19:07 +00:00
|
|
|
SymbolContext sc;
|
2018-10-12 19:47:13 +00:00
|
|
|
|
|
|
|
|
sc.comp_unit = GetOrCreateCompileUnit(cci).get();
|
2018-11-16 03:16:27 +00:00
|
|
|
PdbCompilandSymId func_id(proc.modi(), proc.SymOffset);
|
2018-12-13 18:17:51 +00:00
|
|
|
sc.function = GetOrCreateFunction(func_id, *sc.comp_unit).get();
|
2018-10-12 19:47:13 +00:00
|
|
|
|
|
|
|
|
sc_list.Append(sc);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return sc_list.GetSize();
|
|
|
|
|
}
|
|
|
|
|
|
2018-10-22 16:19:07 +00:00
|
|
|
uint32_t SymbolFileNativePDB::FindFunctions(const RegularExpression ®ex,
|
|
|
|
|
bool include_inlines, bool append,
|
|
|
|
|
SymbolContextList &sc_list) {
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
uint32_t SymbolFileNativePDB::FindTypes(
|
2019-01-14 22:41:21 +00:00
|
|
|
const ConstString &name, const CompilerDeclContext *parent_decl_ctx,
|
|
|
|
|
bool append, uint32_t max_matches,
|
|
|
|
|
llvm::DenseSet<SymbolFile *> &searched_symbol_files, TypeMap &types) {
|
2018-10-23 16:37:53 +00:00
|
|
|
if (!append)
|
|
|
|
|
types.Clear();
|
|
|
|
|
if (!name)
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
searched_symbol_files.clear();
|
|
|
|
|
searched_symbol_files.insert(this);
|
|
|
|
|
|
|
|
|
|
// There is an assumption 'name' is not a regex
|
|
|
|
|
size_t match_count = FindTypesByName(name.GetStringRef(), max_matches, types);
|
|
|
|
|
|
|
|
|
|
return match_count;
|
2018-10-22 16:19:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
size_t
|
|
|
|
|
SymbolFileNativePDB::FindTypes(const std::vector<CompilerContext> &context,
|
|
|
|
|
bool append, TypeMap &types) {
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2018-10-23 16:37:53 +00:00
|
|
|
size_t SymbolFileNativePDB::FindTypesByName(llvm::StringRef name,
|
|
|
|
|
uint32_t max_matches,
|
|
|
|
|
TypeMap &types) {
|
|
|
|
|
|
|
|
|
|
size_t match_count = 0;
|
|
|
|
|
std::vector<TypeIndex> matches = m_index->tpi().findRecordsByName(name);
|
|
|
|
|
if (max_matches > 0 && max_matches < matches.size())
|
|
|
|
|
matches.resize(max_matches);
|
|
|
|
|
|
|
|
|
|
for (TypeIndex ti : matches) {
|
|
|
|
|
TypeSP type = GetOrCreateType(ti);
|
|
|
|
|
if (!type)
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
types.Insert(type);
|
|
|
|
|
++match_count;
|
|
|
|
|
}
|
|
|
|
|
return match_count;
|
|
|
|
|
}
|
|
|
|
|
|
2019-01-11 18:03:20 +00:00
|
|
|
size_t SymbolFileNativePDB::ParseTypes(CompileUnit &comp_unit) {
|
2019-01-10 20:57:32 +00:00
|
|
|
// Only do the full type scan the first time.
|
|
|
|
|
if (m_done_full_type_scan)
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
size_t old_count = m_obj_file->GetModule()->GetTypeList()->GetSize();
|
|
|
|
|
LazyRandomTypeCollection &types = m_index->tpi().typeCollection();
|
|
|
|
|
|
|
|
|
|
// First process the entire TPI stream.
|
|
|
|
|
for (auto ti = types.getFirst(); ti; ti = types.getNext(*ti)) {
|
|
|
|
|
TypeSP type = GetOrCreateType(*ti);
|
|
|
|
|
if (type)
|
|
|
|
|
(void)type->GetFullCompilerType();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Next look for S_UDT records in the globals stream.
|
|
|
|
|
for (const uint32_t gid : m_index->globals().getGlobalsTable()) {
|
|
|
|
|
PdbGlobalSymId global{gid, false};
|
|
|
|
|
CVSymbol sym = m_index->ReadSymbolRecord(global);
|
|
|
|
|
if (sym.kind() != S_UDT)
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
UDTSym udt = llvm::cantFail(SymbolDeserializer::deserializeAs<UDTSym>(sym));
|
|
|
|
|
bool is_typedef = true;
|
|
|
|
|
if (IsTagRecord(PdbTypeSymId{udt.Type, false}, m_index->tpi())) {
|
|
|
|
|
CVType cvt = m_index->tpi().getType(udt.Type);
|
|
|
|
|
llvm::StringRef name = CVTagRecord::create(cvt).name();
|
|
|
|
|
if (name == udt.Name)
|
|
|
|
|
is_typedef = false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (is_typedef)
|
|
|
|
|
GetOrCreateTypedef(global);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
size_t new_count = m_obj_file->GetModule()->GetTypeList()->GetSize();
|
|
|
|
|
|
|
|
|
|
m_done_full_type_scan = true;
|
|
|
|
|
|
|
|
|
|
return new_count - old_count;
|
|
|
|
|
}
|
2018-10-22 16:19:07 +00:00
|
|
|
|
2018-12-13 18:17:51 +00:00
|
|
|
size_t
|
|
|
|
|
SymbolFileNativePDB::ParseVariablesForCompileUnit(CompileUnit &comp_unit,
|
|
|
|
|
VariableList &variables) {
|
|
|
|
|
PdbSymUid sym_uid(comp_unit.GetID());
|
|
|
|
|
lldbassert(sym_uid.kind() == PdbSymUidKind::Compiland);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
VariableSP SymbolFileNativePDB::CreateLocalVariable(PdbCompilandSymId scope_id,
|
|
|
|
|
PdbCompilandSymId var_id,
|
|
|
|
|
bool is_param) {
|
|
|
|
|
ModuleSP module = GetObjectFile()->GetModule();
|
2019-02-01 10:01:18 +00:00
|
|
|
Block &block = GetOrCreateBlock(scope_id);
|
|
|
|
|
VariableInfo var_info =
|
|
|
|
|
GetVariableLocationInfo(*m_index, var_id, block, module);
|
2019-01-10 20:57:32 +00:00
|
|
|
if (!var_info.location || !var_info.ranges)
|
|
|
|
|
return nullptr;
|
2018-12-13 18:17:51 +00:00
|
|
|
|
|
|
|
|
CompilandIndexItem *cii = m_index->compilands().GetCompiland(var_id.modi);
|
|
|
|
|
CompUnitSP comp_unit_sp = GetOrCreateCompileUnit(*cii);
|
|
|
|
|
TypeSP type_sp = GetOrCreateType(var_info.type);
|
|
|
|
|
std::string name = var_info.name.str();
|
|
|
|
|
Declaration decl;
|
|
|
|
|
SymbolFileTypeSP sftype =
|
|
|
|
|
std::make_shared<SymbolFileType>(*this, type_sp->GetID());
|
|
|
|
|
|
|
|
|
|
ValueType var_scope =
|
|
|
|
|
is_param ? eValueTypeVariableArgument : eValueTypeVariableLocal;
|
|
|
|
|
VariableSP var_sp = std::make_shared<Variable>(
|
|
|
|
|
toOpaqueUid(var_id), name.c_str(), name.c_str(), sftype, var_scope,
|
|
|
|
|
comp_unit_sp.get(), *var_info.ranges, &decl, *var_info.location, false,
|
|
|
|
|
false, false);
|
|
|
|
|
|
2018-12-17 19:43:33 +00:00
|
|
|
if (!is_param)
|
2019-01-02 18:33:54 +00:00
|
|
|
m_ast->GetOrCreateVariableDecl(scope_id, var_id);
|
2018-12-13 18:17:51 +00:00
|
|
|
|
|
|
|
|
m_local_variables[toOpaqueUid(var_id)] = var_sp;
|
|
|
|
|
return var_sp;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
VariableSP SymbolFileNativePDB::GetOrCreateLocalVariable(
|
|
|
|
|
PdbCompilandSymId scope_id, PdbCompilandSymId var_id, bool is_param) {
|
|
|
|
|
auto iter = m_local_variables.find(toOpaqueUid(var_id));
|
|
|
|
|
if (iter != m_local_variables.end())
|
|
|
|
|
return iter->second;
|
|
|
|
|
|
|
|
|
|
return CreateLocalVariable(scope_id, var_id, is_param);
|
|
|
|
|
}
|
|
|
|
|
|
2019-01-10 20:57:32 +00:00
|
|
|
TypeSP SymbolFileNativePDB::CreateTypedef(PdbGlobalSymId id) {
|
|
|
|
|
CVSymbol sym = m_index->ReadSymbolRecord(id);
|
|
|
|
|
lldbassert(sym.kind() == SymbolKind::S_UDT);
|
|
|
|
|
|
|
|
|
|
UDTSym udt = llvm::cantFail(SymbolDeserializer::deserializeAs<UDTSym>(sym));
|
|
|
|
|
|
|
|
|
|
TypeSP target_type = GetOrCreateType(udt.Type);
|
|
|
|
|
|
|
|
|
|
(void)m_ast->GetOrCreateTypedefDecl(id);
|
|
|
|
|
|
|
|
|
|
Declaration decl;
|
|
|
|
|
return std::make_shared<lldb_private::Type>(
|
|
|
|
|
toOpaqueUid(id), this, ConstString(udt.Name), target_type->GetByteSize(),
|
|
|
|
|
nullptr, target_type->GetID(), lldb_private::Type::eEncodingIsTypedefUID,
|
|
|
|
|
decl, target_type->GetForwardCompilerType(),
|
|
|
|
|
lldb_private::Type::eResolveStateForward);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TypeSP SymbolFileNativePDB::GetOrCreateTypedef(PdbGlobalSymId id) {
|
|
|
|
|
auto iter = m_types.find(toOpaqueUid(id));
|
|
|
|
|
if (iter != m_types.end())
|
|
|
|
|
return iter->second;
|
|
|
|
|
|
|
|
|
|
return CreateTypedef(id);
|
|
|
|
|
}
|
|
|
|
|
|
2018-12-13 18:17:51 +00:00
|
|
|
size_t SymbolFileNativePDB::ParseVariablesForBlock(PdbCompilandSymId block_id) {
|
|
|
|
|
Block &block = GetOrCreateBlock(block_id);
|
|
|
|
|
|
|
|
|
|
size_t count = 0;
|
|
|
|
|
|
|
|
|
|
CompilandIndexItem *cii = m_index->compilands().GetCompiland(block_id.modi);
|
|
|
|
|
CVSymbol sym = cii->m_debug_stream.readSymbolAtOffset(block_id.offset);
|
|
|
|
|
uint32_t params_remaining = 0;
|
|
|
|
|
switch (sym.kind()) {
|
|
|
|
|
case S_GPROC32:
|
|
|
|
|
case S_LPROC32: {
|
|
|
|
|
ProcSym proc(static_cast<SymbolRecordKind>(sym.kind()));
|
|
|
|
|
cantFail(SymbolDeserializer::deserializeAs<ProcSym>(sym, proc));
|
|
|
|
|
CVType signature = m_index->tpi().getType(proc.FunctionType);
|
|
|
|
|
ProcedureRecord sig;
|
|
|
|
|
cantFail(TypeDeserializer::deserializeAs<ProcedureRecord>(signature, sig));
|
|
|
|
|
params_remaining = sig.getParameterCount();
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case S_BLOCK32:
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
lldbassert(false && "Symbol is not a block!");
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
VariableListSP variables = block.GetBlockVariableList(false);
|
|
|
|
|
if (!variables) {
|
|
|
|
|
variables = std::make_shared<VariableList>();
|
|
|
|
|
block.SetVariableList(variables);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
CVSymbolArray syms = limitSymbolArrayToScope(
|
|
|
|
|
cii->m_debug_stream.getSymbolArray(), block_id.offset);
|
|
|
|
|
|
|
|
|
|
// Skip the first record since it's a PROC32 or BLOCK32, and there's
|
|
|
|
|
// no point examining it since we know it's not a local variable.
|
|
|
|
|
syms.drop_front();
|
|
|
|
|
auto iter = syms.begin();
|
|
|
|
|
auto end = syms.end();
|
|
|
|
|
|
|
|
|
|
while (iter != end) {
|
|
|
|
|
uint32_t record_offset = iter.offset();
|
|
|
|
|
CVSymbol variable_cvs = *iter;
|
|
|
|
|
PdbCompilandSymId child_sym_id(block_id.modi, record_offset);
|
|
|
|
|
++iter;
|
|
|
|
|
|
|
|
|
|
// If this is a block, recurse into its children and then skip it.
|
|
|
|
|
if (variable_cvs.kind() == S_BLOCK32) {
|
|
|
|
|
uint32_t block_end = getScopeEndOffset(variable_cvs);
|
|
|
|
|
count += ParseVariablesForBlock(child_sym_id);
|
|
|
|
|
iter = syms.at(block_end);
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool is_param = params_remaining > 0;
|
|
|
|
|
VariableSP variable;
|
|
|
|
|
switch (variable_cvs.kind()) {
|
|
|
|
|
case S_REGREL32:
|
|
|
|
|
case S_REGISTER:
|
|
|
|
|
case S_LOCAL:
|
|
|
|
|
variable = GetOrCreateLocalVariable(block_id, child_sym_id, is_param);
|
|
|
|
|
if (is_param)
|
|
|
|
|
--params_remaining;
|
2019-01-10 20:57:32 +00:00
|
|
|
if (variable)
|
|
|
|
|
variables->AddVariableIfUnique(variable);
|
2018-12-13 18:17:51 +00:00
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Pass false for set_children, since we call this recursively so that the
|
|
|
|
|
// children will call this for themselves.
|
|
|
|
|
block.SetDidParseVariables(true, false);
|
|
|
|
|
|
|
|
|
|
return count;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
size_t SymbolFileNativePDB::ParseVariablesForContext(const SymbolContext &sc) {
|
|
|
|
|
lldbassert(sc.function || sc.comp_unit);
|
|
|
|
|
|
|
|
|
|
VariableListSP variables;
|
|
|
|
|
if (sc.block) {
|
|
|
|
|
PdbSymUid block_id(sc.block->GetID());
|
|
|
|
|
|
|
|
|
|
size_t count = ParseVariablesForBlock(block_id.asCompilandSym());
|
|
|
|
|
return count;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (sc.function) {
|
|
|
|
|
PdbSymUid block_id(sc.function->GetID());
|
|
|
|
|
|
|
|
|
|
size_t count = ParseVariablesForBlock(block_id.asCompilandSym());
|
|
|
|
|
return count;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (sc.comp_unit) {
|
|
|
|
|
variables = sc.comp_unit->GetVariableList(false);
|
|
|
|
|
if (!variables) {
|
|
|
|
|
variables = std::make_shared<VariableList>();
|
|
|
|
|
sc.comp_unit->SetVariableList(variables);
|
|
|
|
|
}
|
|
|
|
|
return ParseVariablesForCompileUnit(*sc.comp_unit, *variables);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
llvm_unreachable("Unreachable!");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
CompilerDecl SymbolFileNativePDB::GetDeclForUID(lldb::user_id_t uid) {
|
2018-12-17 19:43:33 +00:00
|
|
|
clang::Decl *decl = m_ast->GetOrCreateDeclForUid(PdbSymUid(uid));
|
2018-12-13 18:17:51 +00:00
|
|
|
|
2018-12-17 19:43:33 +00:00
|
|
|
return m_ast->ToCompilerDecl(*decl);
|
2018-12-13 18:17:51 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
CompilerDeclContext
|
|
|
|
|
SymbolFileNativePDB::GetDeclContextForUID(lldb::user_id_t uid) {
|
2018-12-17 19:43:33 +00:00
|
|
|
clang::DeclContext *context =
|
|
|
|
|
m_ast->GetOrCreateDeclContextForUid(PdbSymUid(uid));
|
|
|
|
|
if (!context)
|
|
|
|
|
return {};
|
|
|
|
|
|
|
|
|
|
return m_ast->ToCompilerDeclContext(*context);
|
2018-12-13 18:17:51 +00:00
|
|
|
}
|
|
|
|
|
|
2018-12-07 19:34:02 +00:00
|
|
|
CompilerDeclContext
|
|
|
|
|
SymbolFileNativePDB::GetDeclContextContainingUID(lldb::user_id_t uid) {
|
2018-12-17 19:43:33 +00:00
|
|
|
clang::DeclContext *context = m_ast->GetParentDeclContext(PdbSymUid(uid));
|
|
|
|
|
return m_ast->ToCompilerDeclContext(*context);
|
2018-12-07 19:34:02 +00:00
|
|
|
}
|
|
|
|
|
|
2018-10-22 16:19:07 +00:00
|
|
|
Type *SymbolFileNativePDB::ResolveTypeUID(lldb::user_id_t type_uid) {
|
2018-10-23 16:37:53 +00:00
|
|
|
auto iter = m_types.find(type_uid);
|
|
|
|
|
// lldb should not be passing us non-sensical type uids. the only way it
|
|
|
|
|
// could have a type uid in the first place is if we handed it out, in which
|
[NativePDB] Add the ability to dump dump global variables.
LLDB has the ability to display global variables, even without a running
process, via the target variable command. This is because global
variables are linker initialized, so their values are embedded directly
into the executables. This gives us great power for testing native PDB
functionality in a cross-platform manner, because we don't actually need
a running process. We can just create a target using an EXE file, and
display global variables. And global variables can have arbitrarily
complex types, so in theory we can fully exercise the type system,
record layout, and data formatters for native PDB files and PE/COFF
executables on any host platform, as long as our type does not require a
dynamic initializer.
This patch adds basic support for finding variables by name, and adds an
exhaustive test for fundamental data types and pointers / references to
fundamental data types.
Subsequent patches will extend this to typedefs, classes, pointers to
functions, and other cases.
Differential Revision: https://reviews.llvm.org/D53731
llvm-svn: 345373
2018-10-26 09:06:38 +00:00
|
|
|
// case we should know about the type. However, that doesn't mean we've
|
|
|
|
|
// instantiated it yet. We can vend out a UID for a future type. So if the
|
|
|
|
|
// type doesn't exist, let's instantiate it now.
|
|
|
|
|
if (iter != m_types.end())
|
|
|
|
|
return &*iter->second;
|
|
|
|
|
|
2018-11-16 02:42:32 +00:00
|
|
|
PdbSymUid uid(type_uid);
|
|
|
|
|
lldbassert(uid.kind() == PdbSymUidKind::Type);
|
|
|
|
|
PdbTypeSymId type_id = uid.asTypeSym();
|
|
|
|
|
if (type_id.index.isNoneType())
|
2018-10-23 16:37:53 +00:00
|
|
|
return nullptr;
|
[NativePDB] Add the ability to dump dump global variables.
LLDB has the ability to display global variables, even without a running
process, via the target variable command. This is because global
variables are linker initialized, so their values are embedded directly
into the executables. This gives us great power for testing native PDB
functionality in a cross-platform manner, because we don't actually need
a running process. We can just create a target using an EXE file, and
display global variables. And global variables can have arbitrarily
complex types, so in theory we can fully exercise the type system,
record layout, and data formatters for native PDB files and PE/COFF
executables on any host platform, as long as our type does not require a
dynamic initializer.
This patch adds basic support for finding variables by name, and adds an
exhaustive test for fundamental data types and pointers / references to
fundamental data types.
Subsequent patches will extend this to typedefs, classes, pointers to
functions, and other cases.
Differential Revision: https://reviews.llvm.org/D53731
llvm-svn: 345373
2018-10-26 09:06:38 +00:00
|
|
|
|
2018-11-16 02:42:32 +00:00
|
|
|
TypeSP type_sp = CreateAndCacheType(type_id);
|
[NativePDB] Add the ability to dump dump global variables.
LLDB has the ability to display global variables, even without a running
process, via the target variable command. This is because global
variables are linker initialized, so their values are embedded directly
into the executables. This gives us great power for testing native PDB
functionality in a cross-platform manner, because we don't actually need
a running process. We can just create a target using an EXE file, and
display global variables. And global variables can have arbitrarily
complex types, so in theory we can fully exercise the type system,
record layout, and data formatters for native PDB files and PE/COFF
executables on any host platform, as long as our type does not require a
dynamic initializer.
This patch adds basic support for finding variables by name, and adds an
exhaustive test for fundamental data types and pointers / references to
fundamental data types.
Subsequent patches will extend this to typedefs, classes, pointers to
functions, and other cases.
Differential Revision: https://reviews.llvm.org/D53731
llvm-svn: 345373
2018-10-26 09:06:38 +00:00
|
|
|
return &*type_sp;
|
2018-10-22 16:19:07 +00:00
|
|
|
}
|
|
|
|
|
|
2018-11-05 20:49:07 +00:00
|
|
|
llvm::Optional<SymbolFile::ArrayInfo>
|
|
|
|
|
SymbolFileNativePDB::GetDynamicArrayInfoForUID(
|
|
|
|
|
lldb::user_id_t type_uid, const lldb_private::ExecutionContext *exe_ctx) {
|
|
|
|
|
return llvm::None;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2018-10-22 16:19:07 +00:00
|
|
|
bool SymbolFileNativePDB::CompleteType(CompilerType &compiler_type) {
|
2018-12-17 19:43:33 +00:00
|
|
|
clang::QualType qt =
|
|
|
|
|
clang::QualType::getFromOpaquePtr(compiler_type.GetOpaqueQualType());
|
2018-10-23 16:37:53 +00:00
|
|
|
|
2018-12-17 19:43:33 +00:00
|
|
|
return m_ast->CompleteType(qt);
|
2018-10-22 16:19:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
size_t SymbolFileNativePDB::GetTypes(lldb_private::SymbolContextScope *sc_scope,
|
2018-10-25 20:45:40 +00:00
|
|
|
TypeClass type_mask,
|
2018-10-22 16:19:07 +00:00
|
|
|
lldb_private::TypeList &type_list) {
|
2018-10-12 19:47:13 +00:00
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2018-10-22 16:19:07 +00:00
|
|
|
CompilerDeclContext
|
2019-01-14 22:41:00 +00:00
|
|
|
SymbolFileNativePDB::FindNamespace(const ConstString &name,
|
2018-10-22 16:19:07 +00:00
|
|
|
const CompilerDeclContext *parent_decl_ctx) {
|
2018-10-12 19:47:13 +00:00
|
|
|
return {};
|
|
|
|
|
}
|
|
|
|
|
|
2018-10-22 16:19:07 +00:00
|
|
|
TypeSystem *
|
2018-10-12 19:47:13 +00:00
|
|
|
SymbolFileNativePDB::GetTypeSystemForLanguage(lldb::LanguageType language) {
|
|
|
|
|
auto type_system =
|
|
|
|
|
m_obj_file->GetModule()->GetTypeSystemForLanguage(language);
|
|
|
|
|
if (type_system)
|
|
|
|
|
type_system->SetSymbolFile(this);
|
|
|
|
|
return type_system;
|
|
|
|
|
}
|
|
|
|
|
|
2018-10-22 16:19:07 +00:00
|
|
|
ConstString SymbolFileNativePDB::GetPluginName() {
|
2018-10-12 19:47:13 +00:00
|
|
|
static ConstString g_name("pdb");
|
|
|
|
|
return g_name;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
uint32_t SymbolFileNativePDB::GetPluginVersion() { return 1; }
|