mirror of
https://github.com/capstone-engine/llvm-capstone.git
synced 2024-12-01 01:31:26 +00:00
Revert SymbolFileNativePDB plugin.
This was originally causing some test failures on non-Windows platforms, which required fixes in the compiler and linker. After those fixes, however, other tests started failing. Reverting temporarily until I can address everything. llvm-svn: 344279
This commit is contained in:
parent
2ce1d6faf8
commit
e8a6c3eb96
@ -222,22 +222,26 @@ public:
|
||||
// PDB to work without additional configuration:
|
||||
// https://docs.microsoft.com/en-us/visualstudio/debugger/debug-source-files-common-properties-solution-property-pages-dialog-box
|
||||
static void pdbMakeAbsolute(SmallVectorImpl<char> &FileName) {
|
||||
// The default behavior is to produce paths that are valid within the context
|
||||
// of the machine that you perform the link on. If the linker is running on
|
||||
// a POSIX system, we will output absolute POSIX paths. If the linker is
|
||||
// running on a Windows system, we will output absolute Windows paths. If the
|
||||
// user desires any other kind of behavior, they should explicitly pass
|
||||
// /pdbsourcepath and/or /pdbaltpath.
|
||||
if (sys::path::is_absolute(FileName))
|
||||
if (sys::path::is_absolute(FileName, sys::path::Style::windows))
|
||||
return;
|
||||
if (Config->PDBSourcePath.empty()) {
|
||||
// Debuggers generally want that PDB files contain absolute, Windows-style
|
||||
// paths. On POSIX hosts, this here will produce an absolute POSIX-style
|
||||
// path, which is weird -- but it's not clear what else to do.
|
||||
// People doing cross builds should probably just always pass
|
||||
// /pbdsourcepath: and make sure paths to input obj files and to lld-link
|
||||
// itself are relative.
|
||||
sys::fs::make_absolute(FileName);
|
||||
return;
|
||||
}
|
||||
// Using /pdbsourcepath: with absolute POSIX paths will prepend
|
||||
// PDBSourcePath to the absolute POSIX path. Since absolute POSIX paths
|
||||
// don't make sense in PDB files anyways, this is gargabe-in-garbage-out.
|
||||
SmallString<128> AbsoluteFileName = Config->PDBSourcePath;
|
||||
sys::path::append(AbsoluteFileName, FileName);
|
||||
sys::path::native(AbsoluteFileName);
|
||||
sys::path::remove_dots(AbsoluteFileName, /*remove_dot_dots=*/true);
|
||||
sys::path::append(AbsoluteFileName, sys::path::Style::windows, FileName);
|
||||
sys::path::native(AbsoluteFileName, sys::path::Style::windows);
|
||||
sys::path::remove_dots(AbsoluteFileName, /*remove_dot_dots=*/true,
|
||||
sys::path::Style::windows);
|
||||
FileName = std::move(AbsoluteFileName);
|
||||
}
|
||||
|
||||
@ -440,7 +444,8 @@ PDBLinker::maybeMergeTypeServerPDB(ObjFile *File, TypeServer2Record &TS) {
|
||||
StringRef LocalPath =
|
||||
!File->ParentName.empty() ? File->ParentName : File->getName();
|
||||
SmallString<128> Path = sys::path::parent_path(LocalPath);
|
||||
sys::path::append(Path, sys::path::filename(TSPath));
|
||||
sys::path::append(
|
||||
Path, sys::path::filename(TSPath, sys::path::Style::windows));
|
||||
return tryToLoadPDB(TSId, Path);
|
||||
},
|
||||
[&](std::unique_ptr<ECError> EC) -> Error {
|
||||
@ -1022,7 +1027,7 @@ void PDBLinker::addObjFile(ObjFile *File) {
|
||||
bool InArchive = !File->ParentName.empty();
|
||||
SmallString<128> Path = InArchive ? File->ParentName : File->getName();
|
||||
pdbMakeAbsolute(Path);
|
||||
sys::path::native(Path);
|
||||
sys::path::native(Path, sys::path::Style::windows);
|
||||
StringRef Name = InArchive ? File->getName() : StringRef(Path);
|
||||
|
||||
pdb::DbiStreamBuilder &DbiBuilder = Builder.getDbiBuilder();
|
||||
@ -1307,7 +1312,7 @@ void PDBLinker::addSections(ArrayRef<OutputSection *> OutputSections,
|
||||
pdb::DbiStreamBuilder &DbiBuilder = Builder.getDbiBuilder();
|
||||
NativePath = Config->PDBPath;
|
||||
pdbMakeAbsolute(NativePath);
|
||||
sys::path::native(NativePath);
|
||||
sys::path::native(NativePath, sys::path::Style::windows);
|
||||
uint32_t PdbFilePathNI = DbiBuilder.addECName(NativePath);
|
||||
auto &LinkerModule = ExitOnErr(DbiBuilder.addModuleInfo("* Linker *"));
|
||||
LinkerModule.setPdbFilePathNI(PdbFilePathNI);
|
||||
|
@ -14,8 +14,7 @@
|
||||
#define lldbassert(x) assert(x)
|
||||
#else
|
||||
#define lldbassert(x) \
|
||||
lldb_private::lldb_assert(static_cast<bool>(x), #x, __FUNCTION__, __FILE__, \
|
||||
__LINE__)
|
||||
lldb_private::lldb_assert(x, #x, __FUNCTION__, __FILE__, __LINE__)
|
||||
#endif
|
||||
|
||||
namespace lldb_private {
|
||||
|
@ -1,6 +0,0 @@
|
||||
break set -n main
|
||||
break set -n OvlGlobalFn
|
||||
break set -n StaticFn
|
||||
break set -n DoesntExist
|
||||
break list
|
||||
quit
|
@ -1,2 +0,0 @@
|
||||
disassemble --flavor=intel -m -n main
|
||||
quit
|
@ -1,3 +0,0 @@
|
||||
source list -n main
|
||||
source list -n OvlGlobalFn
|
||||
quit
|
@ -1,38 +0,0 @@
|
||||
// clang-format off
|
||||
|
||||
// Test that we can show disassembly and source.
|
||||
// RUN: clang-cl /Z7 /GS- /GR- /c %s /Fo%t.obj
|
||||
// RUN: lld-link /DEBUG /nodefaultlib /entry:main /OUT:%t.exe /PDB:%t.pdb %t.obj
|
||||
// RUN: env LLDB_USE_NATIVE_PDB_READER=1 lldb -f %t.exe -s \
|
||||
// RUN: %p/Inputs/disassembly.lldbinit | FileCheck %s
|
||||
|
||||
// Some context lines before
|
||||
// the function.
|
||||
|
||||
int foo() { return 42; }
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
foo();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
// CHECK: (lldb) disassemble --flavor=intel -m -n main
|
||||
// CHECK: 12 int foo() { return 42; }
|
||||
// CHECK-NEXT: 13
|
||||
// CHECK-NEXT: ** 14 int main(int argc, char **argv) {
|
||||
// CHECK: disassembly.cpp.tmp.exe`main:
|
||||
// CHECK-NEXT: disassembly.cpp.tmp.exe[{{.*}}] <+0>: sub rsp, 0x38
|
||||
// CHECK-NEXT: disassembly.cpp.tmp.exe[{{.*}}] <+4>: mov dword ptr [rsp + 0x34], 0x0
|
||||
// CHECK-NEXT: disassembly.cpp.tmp.exe[{{.*}}] <+12>: mov qword ptr [rsp + 0x28], rdx
|
||||
// CHECK-NEXT: disassembly.cpp.tmp.exe[{{.*}}] <+17>: mov dword ptr [rsp + 0x24], ecx
|
||||
// CHECK: ** 15 foo();
|
||||
// CHECK: disassembly.cpp.tmp.exe[{{.*}}] <+21>: call {{.*}} ; foo at disassembly.cpp:12
|
||||
// CHECK-NEXT: disassembly.cpp.tmp.exe[{{.*}}] <+26>: xor ecx, ecx
|
||||
// CHECK-NEXT: disassembly.cpp.tmp.exe[{{.*}}] <+28>: mov dword ptr [rsp + 0x20], eax
|
||||
// CHECK: ** 16 return 0;
|
||||
// CHECK-NEXT: 17 }
|
||||
// CHECK-NEXT: 18
|
||||
// CHECK: disassembly.cpp.tmp.exe[{{.*}}] <+32>: mov eax, ecx
|
||||
// CHECK-NEXT: disassembly.cpp.tmp.exe[{{.*}}] <+34>: add rsp, 0x38
|
||||
// CHECK-NEXT: disassembly.cpp.tmp.exe[{{.*}}] <+38>: ret
|
@ -1 +0,0 @@
|
||||
config.suffixes = ['.test', '.cpp']
|
@ -1,63 +0,0 @@
|
||||
// clang-format off
|
||||
|
||||
// Test that we can set simple breakpoints using PDB on any platform.
|
||||
// RUN: clang-cl /Z7 /GS- /GR- /c %s /Fo%t.obj
|
||||
// RUN: lld-link /DEBUG /nodefaultlib /entry:main /OUT:%t.exe /PDB:%t.pdb %t.obj
|
||||
// RUN: env LLDB_USE_NATIVE_PDB_READER=1 lldb -f %t.exe -s \
|
||||
// RUN: %p/Inputs/breakpoints.lldbinit | FileCheck %s
|
||||
|
||||
// Use different indentation style for each overload so that the starting
|
||||
// line is in a different place.
|
||||
int OvlGlobalFn(int X) {
|
||||
return X + 42;
|
||||
}
|
||||
|
||||
int OvlGlobalFn(int X, int Y) { return X + Y + 42; }
|
||||
|
||||
int OvlGlobalFn(int X, int Y, int Z)
|
||||
{
|
||||
return X + Y + Z + 42;
|
||||
}
|
||||
|
||||
static int StaticFn(int X) {
|
||||
return X + 42;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
// Make sure they don't get optimized out.
|
||||
// Note the comments here, we want to make sure the line number reported
|
||||
// for the breakpoint is the first actual line of code.
|
||||
int Result = OvlGlobalFn(argc) + OvlGlobalFn(argc, argc)
|
||||
+ OvlGlobalFn(argc, argc, argc) + StaticFn(argc);
|
||||
return Result;
|
||||
}
|
||||
|
||||
|
||||
// CHECK: (lldb) target create "{{.*}}simple-breakpoints.cpp.tmp.exe"
|
||||
// CHECK: Current executable set to '{{.*}}simple-breakpoints.cpp.tmp.exe' (x86_64).
|
||||
// CHECK: (lldb) break set -n main
|
||||
// CHECK: Breakpoint 1: where = simple-breakpoints.cpp.tmp.exe`main + 21
|
||||
// CHECK-SAME: at simple-breakpoints.cpp:30
|
||||
// CHECK: (lldb) break set -n OvlGlobalFn
|
||||
// CHECK: Breakpoint 2: 3 locations.
|
||||
// CHECK: (lldb) break set -n StaticFn
|
||||
// CHECK: Breakpoint 3: where = simple-breakpoints.cpp.tmp.exe`StaticFn + 5
|
||||
// CHECK-SAME: at simple-breakpoints.cpp:23
|
||||
// CHECK: (lldb) break set -n DoesntExist
|
||||
// CHECK: Breakpoint 4: no locations (pending).
|
||||
// CHECK: (lldb) break list
|
||||
// CHECK: Current breakpoints:
|
||||
// CHECK: 1: name = 'main', locations = 1
|
||||
// CHECK: 1.1: where = simple-breakpoints.cpp.tmp.exe`main + 21
|
||||
// CHECK-SAME: at simple-breakpoints.cpp:30
|
||||
// CHECK: 2: name = 'OvlGlobalFn', locations = 3
|
||||
// CHECK: 2.1: where = simple-breakpoints.cpp.tmp.exe`OvlGlobalFn + 5
|
||||
// CHECK-SAME: at simple-breakpoints.cpp:12
|
||||
// CHECK: 2.2: where = simple-breakpoints.cpp.tmp.exe`OvlGlobalFn
|
||||
// CHECK-SAME: at simple-breakpoints.cpp:15
|
||||
// CHECK: 2.3: where = simple-breakpoints.cpp.tmp.exe`OvlGlobalFn + 17
|
||||
// CHECK-SAME: at simple-breakpoints.cpp:19
|
||||
// CHECK: 3: name = 'StaticFn', locations = 1
|
||||
// CHECK: 3.1: where = simple-breakpoints.cpp.tmp.exe`StaticFn + 5
|
||||
// CHECK-SAME: at simple-breakpoints.cpp:23
|
||||
// CHECK: 4: name = 'DoesntExist', locations = 0 (pending)
|
@ -1,42 +0,0 @@
|
||||
// clang-format off
|
||||
|
||||
// Test that we can set display source of functions.
|
||||
// RUN: clang-cl /Z7 /GS- /GR- /c %s /Fo%t.obj
|
||||
// RUN: lld-link /DEBUG /nodefaultlib /entry:main /OUT:%t.exe /PDB:%t.pdb %t.obj
|
||||
// RUN: env LLDB_USE_NATIVE_PDB_READER=1 lldb -f %t.exe -s \
|
||||
// RUN: %p/Inputs/source-list.lldbinit | FileCheck %s
|
||||
|
||||
|
||||
|
||||
// Some context lines before
|
||||
// the function.
|
||||
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
// Here are some comments.
|
||||
// That we should print when listing source.
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Some context lines after
|
||||
// the function.
|
||||
|
||||
// check lines go at the end so that line numbers stay stable when
|
||||
// changing this file.
|
||||
|
||||
// CHECK: (lldb) source list -n main
|
||||
// CHECK: File: {{.*}}source-list.cpp
|
||||
// CHECK: 10
|
||||
// CHECK: 11 // Some context lines before
|
||||
// CHECK: 12 // the function.
|
||||
// CHECK: 13
|
||||
// CHECK: 14
|
||||
// CHECK: 15 int main(int argc, char **argv) {
|
||||
// CHECK: 16 // Here are some comments.
|
||||
// CHECK: 17 // That we should print when listing source.
|
||||
// CHECK: 18 return 0;
|
||||
// CHECK: 19 }
|
||||
// CHECK: 20
|
||||
// CHECK: 21 // Some context lines after
|
||||
// CHECK: 22 // the function.
|
||||
// CHECK: 23
|
@ -64,8 +64,6 @@ lldb = "%s -S %s/lit-lldb-init" % (lit.util.which('lldb', lldb_tools_dir),
|
||||
config.test_source_root)
|
||||
|
||||
lldbmi = lit.util.which('lldb-mi', lldb_tools_dir)
|
||||
if lldbmi:
|
||||
config.available_features.add('lldb-mi')
|
||||
|
||||
if not os.path.exists(config.cc):
|
||||
config.cc = lit.util.which(config.cc, config.environment['PATH'])
|
||||
@ -92,8 +90,7 @@ if platform.system() in ['OpenBSD']:
|
||||
config.substitutions.append(('%cc', config.cc))
|
||||
config.substitutions.append(('%cxx', config.cxx))
|
||||
|
||||
if lldbmi:
|
||||
config.substitutions.append(('%lldbmi', lldbmi + " --synchronous"))
|
||||
config.substitutions.append(('%lldbmi', lldbmi + " --synchronous"))
|
||||
config.substitutions.append(('%lldb', lldb))
|
||||
|
||||
if debugserver is not None:
|
||||
|
@ -1,4 +1,3 @@
|
||||
add_subdirectory(DWARF)
|
||||
add_subdirectory(Symtab)
|
||||
add_subdirectory(NativePDB)
|
||||
add_subdirectory(PDB)
|
||||
|
@ -1,16 +0,0 @@
|
||||
add_lldb_library(lldbPluginSymbolFileNativePDB PLUGIN
|
||||
CompileUnitIndex.cpp
|
||||
PdbIndex.cpp
|
||||
PdbUtil.cpp
|
||||
SymbolFileNativePDB.cpp
|
||||
|
||||
LINK_LIBS
|
||||
clangAST
|
||||
clangLex
|
||||
lldbCore
|
||||
lldbSymbol
|
||||
lldbUtility
|
||||
LINK_COMPONENTS
|
||||
DebugInfoPDB
|
||||
Support
|
||||
)
|
@ -1,227 +0,0 @@
|
||||
//===-- CompileUnitIndex.cpp ------------------------------------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "CompileUnitIndex.h"
|
||||
|
||||
#include "PdbIndex.h"
|
||||
#include "PdbUtil.h"
|
||||
|
||||
#include "llvm/DebugInfo/CodeView/LazyRandomTypeCollection.h"
|
||||
#include "llvm/DebugInfo/CodeView/SymbolDeserializer.h"
|
||||
#include "llvm/DebugInfo/CodeView/TypeDeserializer.h"
|
||||
#include "llvm/DebugInfo/MSF/MappedBlockStream.h"
|
||||
#include "llvm/DebugInfo/PDB/Native/DbiModuleDescriptor.h"
|
||||
#include "llvm/DebugInfo/PDB/Native/DbiStream.h"
|
||||
#include "llvm/DebugInfo/PDB/Native/InfoStream.h"
|
||||
#include "llvm/DebugInfo/PDB/Native/ModuleDebugStream.h"
|
||||
#include "llvm/DebugInfo/PDB/Native/NamedStreamMap.h"
|
||||
#include "llvm/DebugInfo/PDB/Native/TpiStream.h"
|
||||
#include "llvm/Support/Path.h"
|
||||
|
||||
#include "lldb/Utility/LLDBAssert.h"
|
||||
|
||||
using namespace lldb;
|
||||
using namespace lldb_private;
|
||||
using namespace lldb_private::npdb;
|
||||
using namespace llvm::codeview;
|
||||
using namespace llvm::pdb;
|
||||
|
||||
static bool IsMainFile(llvm::StringRef main, llvm::StringRef other) {
|
||||
if (main == other)
|
||||
return true;
|
||||
|
||||
// If the files refer to the local file system, we can just ask the file
|
||||
// system if they're equivalent. But if the source isn't present on disk
|
||||
// then we still want to try.
|
||||
if (llvm::sys::fs::equivalent(main, other))
|
||||
return true;
|
||||
|
||||
llvm::SmallString<64> normalized(other);
|
||||
llvm::sys::path::native(normalized);
|
||||
return main.equals_lower(normalized);
|
||||
}
|
||||
|
||||
static void ParseCompile3(const CVSymbol &sym, CompilandIndexItem &cci) {
|
||||
cci.m_compile_opts.emplace();
|
||||
llvm::cantFail(
|
||||
SymbolDeserializer::deserializeAs<Compile3Sym>(sym, *cci.m_compile_opts));
|
||||
}
|
||||
|
||||
static void ParseObjname(const CVSymbol &sym, CompilandIndexItem &cci) {
|
||||
cci.m_obj_name.emplace();
|
||||
llvm::cantFail(
|
||||
SymbolDeserializer::deserializeAs<ObjNameSym>(sym, *cci.m_obj_name));
|
||||
}
|
||||
|
||||
static void ParseBuildInfo(PdbIndex &index, const CVSymbol &sym,
|
||||
CompilandIndexItem &cci) {
|
||||
BuildInfoSym bis(SymbolRecordKind::BuildInfoSym);
|
||||
llvm::cantFail(SymbolDeserializer::deserializeAs<BuildInfoSym>(sym, bis));
|
||||
|
||||
// S_BUILDINFO just points to an LF_BUILDINFO in the IPI stream. Let's do
|
||||
// a little extra work to pull out the LF_BUILDINFO.
|
||||
LazyRandomTypeCollection &types = index.ipi().typeCollection();
|
||||
llvm::Optional<CVType> cvt = types.tryGetType(bis.BuildId);
|
||||
|
||||
if (!cvt || cvt->kind() != LF_BUILDINFO)
|
||||
return;
|
||||
|
||||
BuildInfoRecord bir;
|
||||
llvm::cantFail(TypeDeserializer::deserializeAs<BuildInfoRecord>(*cvt, bir));
|
||||
cci.m_build_info.assign(bir.ArgIndices.begin(), bir.ArgIndices.end());
|
||||
}
|
||||
|
||||
static void ParseExtendedInfo(PdbIndex &index, CompilandIndexItem &item) {
|
||||
const CVSymbolArray &syms = item.m_debug_stream.getSymbolArray();
|
||||
|
||||
// This is a private function, it shouldn't be called if the information
|
||||
// has already been parsed.
|
||||
lldbassert(!item.m_obj_name);
|
||||
lldbassert(!item.m_compile_opts);
|
||||
lldbassert(item.m_build_info.empty());
|
||||
|
||||
// We're looking for 3 things. S_COMPILE3, S_OBJNAME, and S_BUILDINFO.
|
||||
int found = 0;
|
||||
for (const CVSymbol &sym : syms) {
|
||||
switch (sym.kind()) {
|
||||
case S_COMPILE3:
|
||||
ParseCompile3(sym, item);
|
||||
break;
|
||||
case S_OBJNAME:
|
||||
ParseObjname(sym, item);
|
||||
break;
|
||||
case S_BUILDINFO:
|
||||
ParseBuildInfo(index, sym, item);
|
||||
break;
|
||||
default:
|
||||
continue;
|
||||
}
|
||||
if (++found >= 3)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
CompilandIndexItem::CompilandIndexItem(
|
||||
PdbSymUid uid, llvm::pdb::ModuleDebugStreamRef debug_stream,
|
||||
llvm::pdb::DbiModuleDescriptor descriptor)
|
||||
: m_uid(uid), m_debug_stream(std::move(debug_stream)),
|
||||
m_module_descriptor(std::move(descriptor)) {}
|
||||
|
||||
CompilandIndexItem &CompileUnitIndex::GetOrCreateCompiland(uint16_t modi) {
|
||||
PdbSymUid uid = PdbSymUid::makeCompilandId(modi);
|
||||
return GetOrCreateCompiland(uid);
|
||||
}
|
||||
|
||||
CompilandIndexItem &
|
||||
CompileUnitIndex::GetOrCreateCompiland(PdbSymUid compiland_uid) {
|
||||
auto result = m_comp_units.try_emplace(compiland_uid.toOpaqueId(), nullptr);
|
||||
if (!result.second)
|
||||
return *result.first->second;
|
||||
|
||||
// Find the module list and load its debug information stream and cache it
|
||||
// since we need to use it for almost all interesting operations.
|
||||
const DbiModuleList &modules = m_index.dbi().modules();
|
||||
uint16_t modi = compiland_uid.asCompiland().modi;
|
||||
llvm::pdb::DbiModuleDescriptor descriptor = modules.getModuleDescriptor(modi);
|
||||
uint16_t stream = descriptor.getModuleStreamIndex();
|
||||
std::unique_ptr<llvm::msf::MappedBlockStream> stream_data =
|
||||
m_index.pdb().createIndexedStream(stream);
|
||||
llvm::pdb::ModuleDebugStreamRef debug_stream(descriptor,
|
||||
std::move(stream_data));
|
||||
cantFail(debug_stream.reload());
|
||||
|
||||
std::unique_ptr<CompilandIndexItem> &cci = result.first->second;
|
||||
|
||||
cci = llvm::make_unique<CompilandIndexItem>(
|
||||
compiland_uid, std::move(debug_stream), std::move(descriptor));
|
||||
ParseExtendedInfo(m_index, *cci);
|
||||
|
||||
cci->m_strings.initialize(debug_stream.getSubsectionsArray());
|
||||
PDBStringTable &strings = cantFail(m_index.pdb().getStringTable());
|
||||
cci->m_strings.setStrings(strings.getStringTable());
|
||||
|
||||
// We want the main source file to always comes first. Note that we can't
|
||||
// just push_back the main file onto the front because `GetMainSourceFile`
|
||||
// computes it in such a way that it doesn't own the resulting memory. So we
|
||||
// have to iterate the module file list comparing each one to the main file
|
||||
// name until we find it, and we can cache that one since the memory is backed
|
||||
// by a contiguous chunk inside the mapped PDB.
|
||||
llvm::SmallString<64> main_file = GetMainSourceFile(*cci);
|
||||
std::string s = main_file.str();
|
||||
llvm::sys::path::native(main_file);
|
||||
|
||||
uint32_t file_count = modules.getSourceFileCount(modi);
|
||||
cci->m_file_list.reserve(file_count);
|
||||
bool found_main_file = false;
|
||||
for (llvm::StringRef file : modules.source_files(modi)) {
|
||||
if (!found_main_file && IsMainFile(main_file, file)) {
|
||||
cci->m_file_list.insert(cci->m_file_list.begin(), file);
|
||||
found_main_file = true;
|
||||
continue;
|
||||
}
|
||||
cci->m_file_list.push_back(file);
|
||||
}
|
||||
|
||||
return *cci;
|
||||
}
|
||||
|
||||
const CompilandIndexItem *CompileUnitIndex::GetCompiland(uint16_t modi) const {
|
||||
return GetCompiland(PdbSymUid::makeCompilandId(modi));
|
||||
}
|
||||
|
||||
const CompilandIndexItem *
|
||||
CompileUnitIndex::GetCompiland(PdbSymUid compiland_uid) const {
|
||||
auto iter = m_comp_units.find(compiland_uid.toOpaqueId());
|
||||
if (iter == m_comp_units.end())
|
||||
return nullptr;
|
||||
return iter->second.get();
|
||||
}
|
||||
|
||||
CompilandIndexItem *CompileUnitIndex::GetCompiland(uint16_t modi) {
|
||||
return GetCompiland(PdbSymUid::makeCompilandId(modi));
|
||||
}
|
||||
|
||||
CompilandIndexItem *CompileUnitIndex::GetCompiland(PdbSymUid compiland_uid) {
|
||||
auto iter = m_comp_units.find(compiland_uid.toOpaqueId());
|
||||
if (iter == m_comp_units.end())
|
||||
return nullptr;
|
||||
return iter->second.get();
|
||||
}
|
||||
|
||||
llvm::SmallString<64>
|
||||
CompileUnitIndex::GetMainSourceFile(const CompilandIndexItem &item) const {
|
||||
// LF_BUILDINFO contains a list of arg indices which point to LF_STRING_ID
|
||||
// records in the IPI stream. The order of the arg indices is as follows:
|
||||
// [0] - working directory where compiler was invoked.
|
||||
// [1] - absolute path to compiler binary
|
||||
// [2] - source file name
|
||||
// [3] - path to compiler generated PDB (the /Zi PDB, although this entry gets
|
||||
// added even when using /Z7)
|
||||
// [4] - full command line invocation.
|
||||
//
|
||||
// We need to form the path [0]\[2] to generate the full path to the main
|
||||
// file.source
|
||||
if (item.m_build_info.size() < 3)
|
||||
return {""};
|
||||
|
||||
LazyRandomTypeCollection &types = m_index.ipi().typeCollection();
|
||||
|
||||
StringIdRecord working_dir;
|
||||
StringIdRecord file_name;
|
||||
CVType dir_cvt = types.getType(item.m_build_info[0]);
|
||||
CVType file_cvt = types.getType(item.m_build_info[2]);
|
||||
llvm::cantFail(
|
||||
TypeDeserializer::deserializeAs<StringIdRecord>(dir_cvt, working_dir));
|
||||
llvm::cantFail(
|
||||
TypeDeserializer::deserializeAs<StringIdRecord>(file_cvt, file_name));
|
||||
|
||||
llvm::SmallString<64> absolute_path = working_dir.String;
|
||||
llvm::sys::path::append(absolute_path, file_name.String);
|
||||
return absolute_path;
|
||||
}
|
@ -1,99 +0,0 @@
|
||||
//===-- CompileUnitIndex.h --------------------------------------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLDB_PLUGINS_SYMBOLFILENATIVEPDB_COMPILEUNITINDEX_H
|
||||
#define LLDB_PLUGINS_SYMBOLFILENATIVEPDB_COMPILEUNITINDEX_H
|
||||
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "llvm/ADT/DenseSet.h"
|
||||
#include "llvm/ADT/IntervalMap.h"
|
||||
#include "llvm/ADT/Optional.h"
|
||||
#include "llvm/DebugInfo/CodeView/StringsAndChecksums.h"
|
||||
#include "llvm/DebugInfo/CodeView/SymbolRecord.h"
|
||||
#include "llvm/DebugInfo/CodeView/TypeIndex.h"
|
||||
#include "llvm/DebugInfo/PDB/Native/DbiModuleDescriptor.h"
|
||||
#include "llvm/DebugInfo/PDB/Native/ModuleDebugStream.h"
|
||||
#include "llvm/DebugInfo/PDB/PDBTypes.h"
|
||||
|
||||
#include "PdbSymUid.h"
|
||||
|
||||
#include <map>
|
||||
#include <memory>
|
||||
|
||||
namespace lldb_private {
|
||||
|
||||
namespace npdb {
|
||||
class PdbIndex;
|
||||
|
||||
/// Represents a single compile unit. This class is useful for collecting the
|
||||
/// important accessors and information about a compile unit from disparate
|
||||
/// parts of the PDB into a single place, simplifying acess to compile unit
|
||||
/// information for the callers.
|
||||
struct CompilandIndexItem {
|
||||
CompilandIndexItem(PdbSymUid uid,
|
||||
llvm::pdb::ModuleDebugStreamRef debug_stream,
|
||||
llvm::pdb::DbiModuleDescriptor descriptor);
|
||||
|
||||
// uid of this compile unit.
|
||||
PdbSymUid m_uid;
|
||||
|
||||
// debug stream.
|
||||
llvm::pdb::ModuleDebugStreamRef m_debug_stream;
|
||||
|
||||
// dbi module descriptor.
|
||||
llvm::pdb::DbiModuleDescriptor m_module_descriptor;
|
||||
|
||||
llvm::codeview::StringsAndChecksumsRef m_strings;
|
||||
|
||||
// List of files which contribute to this compiland.
|
||||
std::vector<llvm::StringRef> m_file_list;
|
||||
|
||||
// Maps virtual address to global symbol id, which can then be used to
|
||||
// locate the exact compile unit and offset of the symbol. Note that this
|
||||
// is intentionally an ordered map so that we can find all symbols up to a
|
||||
// given starting address.
|
||||
std::map<lldb::addr_t, PdbSymUid> m_symbols_by_va;
|
||||
|
||||
// S_COMPILE3 sym describing compilation settings for the module.
|
||||
llvm::Optional<llvm::codeview::Compile3Sym> m_compile_opts;
|
||||
|
||||
// S_OBJNAME sym describing object name.
|
||||
llvm::Optional<llvm::codeview::ObjNameSym> m_obj_name;
|
||||
|
||||
// LF_BUILDINFO sym describing source file name, working directory,
|
||||
// command line, etc. This usually contains exactly 5 items which
|
||||
// are references to other strings.
|
||||
llvm::SmallVector<llvm::codeview::TypeIndex, 5> m_build_info;
|
||||
};
|
||||
|
||||
/// Indexes information about all compile units. This is really just a map of
|
||||
/// global compile unit index to |CompilandIndexItem| structures.
|
||||
class CompileUnitIndex {
|
||||
PdbIndex &m_index;
|
||||
llvm::DenseMap<lldb::user_id_t, std::unique_ptr<CompilandIndexItem>>
|
||||
m_comp_units;
|
||||
|
||||
public:
|
||||
explicit CompileUnitIndex(PdbIndex &index) : m_index(index) {}
|
||||
|
||||
CompilandIndexItem &GetOrCreateCompiland(uint16_t modi);
|
||||
CompilandIndexItem &GetOrCreateCompiland(PdbSymUid compiland_uid);
|
||||
|
||||
const CompilandIndexItem *GetCompiland(uint16_t modi) const;
|
||||
const CompilandIndexItem *GetCompiland(PdbSymUid compiland_uid) const;
|
||||
|
||||
CompilandIndexItem *GetCompiland(uint16_t modi);
|
||||
CompilandIndexItem *GetCompiland(PdbSymUid compiland_uid);
|
||||
|
||||
llvm::SmallString<64> GetMainSourceFile(const CompilandIndexItem &item) const;
|
||||
};
|
||||
} // namespace npdb
|
||||
} // namespace lldb_private
|
||||
|
||||
#endif
|
@ -1,203 +0,0 @@
|
||||
//===-- PdbIndex.cpp --------------------------------------------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "PdbIndex.h"
|
||||
#include "PdbUtil.h"
|
||||
|
||||
#include "llvm/DebugInfo/CodeView/SymbolDeserializer.h"
|
||||
#include "llvm/DebugInfo/PDB/Native/DbiStream.h"
|
||||
#include "llvm/DebugInfo/PDB/Native/GlobalsStream.h"
|
||||
#include "llvm/DebugInfo/PDB/Native/ISectionContribVisitor.h"
|
||||
#include "llvm/DebugInfo/PDB/Native/PDBFile.h"
|
||||
#include "llvm/DebugInfo/PDB/Native/PublicsStream.h"
|
||||
#include "llvm/DebugInfo/PDB/Native/SymbolStream.h"
|
||||
#include "llvm/Object/COFF.h"
|
||||
#include "llvm/Support/Error.h"
|
||||
|
||||
#include "lldb/Utility/LLDBAssert.h"
|
||||
#include "lldb/lldb-defines.h"
|
||||
|
||||
using namespace lldb_private;
|
||||
using namespace lldb_private::npdb;
|
||||
using namespace llvm::codeview;
|
||||
using namespace llvm::pdb;
|
||||
|
||||
PdbIndex::PdbIndex() : m_cus(*this), m_va_to_modi(m_allocator) {}
|
||||
|
||||
#define ASSIGN_PTR_OR_RETURN(result_ptr, expr) \
|
||||
{ \
|
||||
auto expected_result = expr; \
|
||||
if (!expected_result) \
|
||||
return expected_result.takeError(); \
|
||||
result_ptr = &expected_result.get(); \
|
||||
}
|
||||
|
||||
llvm::Expected<std::unique_ptr<PdbIndex>>
|
||||
PdbIndex::create(std::unique_ptr<llvm::pdb::PDBFile> file) {
|
||||
lldbassert(file);
|
||||
|
||||
std::unique_ptr<PdbIndex> result(new PdbIndex());
|
||||
ASSIGN_PTR_OR_RETURN(result->m_dbi, file->getPDBDbiStream());
|
||||
ASSIGN_PTR_OR_RETURN(result->m_tpi, file->getPDBTpiStream());
|
||||
ASSIGN_PTR_OR_RETURN(result->m_ipi, file->getPDBIpiStream());
|
||||
ASSIGN_PTR_OR_RETURN(result->m_info, file->getPDBInfoStream());
|
||||
ASSIGN_PTR_OR_RETURN(result->m_publics, file->getPDBPublicsStream());
|
||||
ASSIGN_PTR_OR_RETURN(result->m_globals, file->getPDBGlobalsStream());
|
||||
ASSIGN_PTR_OR_RETURN(result->m_symrecords, file->getPDBSymbolStream());
|
||||
|
||||
result->m_file = std::move(file);
|
||||
|
||||
return std::move(result);
|
||||
}
|
||||
|
||||
lldb::addr_t PdbIndex::MakeVirtualAddress(uint16_t segment,
|
||||
uint32_t offset) const {
|
||||
// Segment indices are 1-based.
|
||||
lldbassert(segment > 0);
|
||||
|
||||
uint32_t max_section = dbi().getSectionHeaders().size();
|
||||
lldbassert(segment <= max_section + 1);
|
||||
|
||||
// If this is an absolute symbol, it's indicated by the magic section index
|
||||
// |max_section+1|. In this case, the offset is meaningless, so just return.
|
||||
if (segment == max_section + 1)
|
||||
return LLDB_INVALID_ADDRESS;
|
||||
|
||||
const llvm::object::coff_section &cs = dbi().getSectionHeaders()[segment - 1];
|
||||
return m_load_address + static_cast<lldb::addr_t>(cs.VirtualAddress) +
|
||||
static_cast<lldb::addr_t>(offset);
|
||||
}
|
||||
|
||||
lldb::addr_t PdbIndex::MakeVirtualAddress(const SegmentOffset &so) const {
|
||||
return MakeVirtualAddress(so.segment, so.offset);
|
||||
}
|
||||
|
||||
llvm::Optional<uint16_t>
|
||||
PdbIndex::GetModuleIndexForAddr(uint16_t segment, uint32_t offset) const {
|
||||
return GetModuleIndexForVa(MakeVirtualAddress(segment, offset));
|
||||
}
|
||||
|
||||
llvm::Optional<uint16_t> PdbIndex::GetModuleIndexForVa(lldb::addr_t va) const {
|
||||
auto iter = m_va_to_modi.find(va);
|
||||
if (iter == m_va_to_modi.end())
|
||||
return llvm::None;
|
||||
|
||||
return iter.value();
|
||||
}
|
||||
|
||||
void PdbIndex::ParseSectionContribs() {
|
||||
class Visitor : public ISectionContribVisitor {
|
||||
PdbIndex &m_ctx;
|
||||
llvm::IntervalMap<uint64_t, uint16_t> &m_imap;
|
||||
|
||||
public:
|
||||
Visitor(PdbIndex &ctx, llvm::IntervalMap<uint64_t, uint16_t> &imap)
|
||||
: m_ctx(ctx), m_imap(imap) {}
|
||||
|
||||
void visit(const SectionContrib &C) override {
|
||||
uint64_t va = m_ctx.MakeVirtualAddress(C.ISect, C.Off);
|
||||
uint64_t end = va + C.Size;
|
||||
// IntervalMap's start and end represent a closed range, not a half-open
|
||||
// range, so we have to subtract 1.
|
||||
m_imap.insert(va, end - 1, C.Imod);
|
||||
}
|
||||
void visit(const SectionContrib2 &C) override { visit(C.Base); }
|
||||
};
|
||||
Visitor v(*this, m_va_to_modi);
|
||||
dbi().visitSectionContributions(v);
|
||||
}
|
||||
|
||||
void PdbIndex::BuildAddrToSymbolMap(CompilandIndexItem &cci) {
|
||||
lldbassert(cci.m_symbols_by_va.empty() &&
|
||||
"Addr to symbol map is already built!");
|
||||
uint16_t modi = cci.m_uid.asCompiland().modi;
|
||||
const CVSymbolArray &syms = cci.m_debug_stream.getSymbolArray();
|
||||
for (auto iter = syms.begin(); iter != syms.end(); ++iter) {
|
||||
if (!SymbolHasAddress(*iter))
|
||||
continue;
|
||||
|
||||
SegmentOffset so = GetSegmentAndOffset(*iter);
|
||||
lldb::addr_t va = MakeVirtualAddress(so);
|
||||
|
||||
// We need to add 4 here to adjust for the codeview debug magic
|
||||
// at the beginning of the debug info stream.
|
||||
uint32_t sym_offset = iter.offset() + 4;
|
||||
PdbSymUid cu_sym_uid =
|
||||
PdbSymUid::makeCuSymId(CVSymToPDBSym(iter->kind()), modi, sym_offset);
|
||||
|
||||
// If the debug info is incorrect, we could have multiple symbols with the
|
||||
// same address. So use try_emplace instead of insert, and the first one
|
||||
// will win.
|
||||
auto insert_result =
|
||||
cci.m_symbols_by_va.insert(std::make_pair(va, cu_sym_uid));
|
||||
(void)insert_result;
|
||||
|
||||
// The odds of an error in some function such as GetSegmentAndOffset or
|
||||
// MakeVirtualAddress are much higher than the odds of encountering bad
|
||||
// debug info, so assert that this item was inserted in the map as opposed
|
||||
// to having already been there.
|
||||
lldbassert(insert_result.second);
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<SymbolAndUid> PdbIndex::FindSymbolsByVa(lldb::addr_t va) {
|
||||
std::vector<SymbolAndUid> result;
|
||||
|
||||
llvm::Optional<uint16_t> modi = GetModuleIndexForVa(va);
|
||||
if (!modi)
|
||||
return result;
|
||||
|
||||
CompilandIndexItem &cci = compilands().GetOrCreateCompiland(*modi);
|
||||
if (cci.m_symbols_by_va.empty())
|
||||
BuildAddrToSymbolMap(cci);
|
||||
|
||||
// The map is sorted by starting address of the symbol. So for example
|
||||
// we could (in theory) have this situation
|
||||
//
|
||||
// [------------------]
|
||||
// [----------]
|
||||
// [-----------]
|
||||
// [-------------]
|
||||
// [----]
|
||||
// [-----]
|
||||
// ^ Address we're searching for
|
||||
// In order to find this, we use the upper_bound of the key value which would
|
||||
// be the first symbol whose starting address is higher than the element we're
|
||||
// searching for.
|
||||
|
||||
auto ub = cci.m_symbols_by_va.upper_bound(va);
|
||||
|
||||
for (auto iter = cci.m_symbols_by_va.begin(); iter != ub; ++iter) {
|
||||
const PdbCuSymId &cu_sym_id = iter->second.asCuSym();
|
||||
CVSymbol sym = ReadSymbolRecord(cu_sym_id);
|
||||
|
||||
SegmentOffsetLength sol;
|
||||
if (SymbolIsCode(sym))
|
||||
sol = GetSegmentOffsetAndLength(sym);
|
||||
else
|
||||
sol.so = GetSegmentAndOffset(sym);
|
||||
|
||||
lldb::addr_t start = MakeVirtualAddress(sol.so);
|
||||
lldb::addr_t end = start + sol.length;
|
||||
if (va >= start && va < end)
|
||||
result.push_back({std::move(sym), iter->second});
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
CVSymbol PdbIndex::ReadSymbolRecord(PdbCuSymId cu_sym) const {
|
||||
// We need to subtract 4 here to adjust for the codeview debug magic
|
||||
// at the beginning of the debug info stream.
|
||||
PdbSymUid cuid = PdbSymUid::makeCompilandId(cu_sym.modi);
|
||||
const CompilandIndexItem *cci = compilands().GetCompiland(cuid);
|
||||
auto iter = cci->m_debug_stream.getSymbolArray().at(cu_sym.offset - 4);
|
||||
lldbassert(iter != cci->m_debug_stream.getSymbolArray().end());
|
||||
return *iter;
|
||||
}
|
@ -1,161 +0,0 @@
|
||||
//===-- PdbIndex.h ----------------------------------------------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLDB_PLUGINS_SYMBOLFILENATIVEPDB_PDBINDEX_H
|
||||
#define LLDB_PLUGINS_SYMBOLFILENATIVEPDB_PDBINDEX_H
|
||||
|
||||
#include "lldb/lldb-types.h"
|
||||
#include "llvm/ADT/IntervalMap.h"
|
||||
#include "llvm/ADT/Optional.h"
|
||||
#include "llvm/DebugInfo/PDB/Native/PDBFile.h"
|
||||
#include "llvm/DebugInfo/PDB/PDBTypes.h"
|
||||
|
||||
#include "CompileUnitIndex.h"
|
||||
#include "PdbSymUid.h"
|
||||
|
||||
#include <map>
|
||||
#include <memory>
|
||||
|
||||
namespace llvm {
|
||||
namespace pdb {
|
||||
class DbiStream;
|
||||
class TpiStream;
|
||||
class TpiStream;
|
||||
class InfoStream;
|
||||
class PublicsStream;
|
||||
class GlobalsStream;
|
||||
class SymbolStream;
|
||||
} // namespace pdb
|
||||
} // namespace llvm
|
||||
|
||||
namespace lldb_private {
|
||||
namespace npdb {
|
||||
struct SegmentOffset;
|
||||
|
||||
/// PdbIndex - Lazy access to the important parts of a PDB file.
|
||||
///
|
||||
/// This is a layer on top of LLVM's native PDB support libraries which cache
|
||||
/// certain data when it is accessed the first time. The entire PDB file is
|
||||
/// mapped into memory, and the underlying support libraries vend out memory
|
||||
/// that is always backed by the file, so it is safe to hold StringRefs and
|
||||
/// ArrayRefs into the backing memory as long as the PdbIndex instance is
|
||||
/// alive.
|
||||
class PdbIndex {
|
||||
|
||||
/// The underlying PDB file.
|
||||
std::unique_ptr<llvm::pdb::PDBFile> m_file;
|
||||
|
||||
/// The DBI stream. This contains general high level information about the
|
||||
/// features present in the PDB file, compile units (such as the information
|
||||
/// necessary to locate full symbol information for each compile unit),
|
||||
/// section contributions, and other data which is not specifically symbol or
|
||||
/// type records.
|
||||
llvm::pdb::DbiStream *m_dbi = nullptr;
|
||||
|
||||
/// TPI (types) and IPI (indices) streams. These are both in the exact same
|
||||
/// format with different data. Most type records are stored in the TPI
|
||||
/// stream but certain specific types of records are stored in the IPI stream.
|
||||
/// The IPI stream records can refer to the records in the TPI stream, but not
|
||||
/// the other way around.
|
||||
llvm::pdb::TpiStream *m_tpi = nullptr;
|
||||
llvm::pdb::TpiStream *m_ipi = nullptr;
|
||||
|
||||
/// This is called the "PDB Stream" in the Microsoft reference implementation.
|
||||
/// It contains information about the structure of the file, as well as fields
|
||||
/// used to match EXE and PDB.
|
||||
llvm::pdb::InfoStream *m_info = nullptr;
|
||||
|
||||
/// Publics stream. Is actually a serialized hash table where the keys are
|
||||
/// addresses of symbols in the executable, and values are a record containing
|
||||
/// mangled names and an index which can be used to locate more detailed info
|
||||
/// about the symbol in the Symbol Records stream. The publics stream only
|
||||
/// contains info about externally visible symbols.
|
||||
llvm::pdb::PublicsStream *m_publics = nullptr;
|
||||
|
||||
/// Globals stream. Contrary to its name, this does not contain information
|
||||
/// about all "global variables" or "global functions". Rather, it is the
|
||||
/// "global symbol table", i.e. it contains information about *every* symbol
|
||||
/// in the executable. It is a hash table keyed on name, whose values are
|
||||
/// indices into the symbol records stream to find the full record.
|
||||
llvm::pdb::GlobalsStream *m_globals = nullptr;
|
||||
|
||||
/// Symbol records stream. The publics and globals stream refer to records
|
||||
/// in this stream. For some records, like constants and typedefs, the
|
||||
/// complete record lives in this stream. For other symbol types, such as
|
||||
/// functions, data, and other things that have been materialied into a
|
||||
/// specific compile unit, the records here simply provide a reference
|
||||
/// necessary to locate the full information.
|
||||
llvm::pdb::SymbolStream *m_symrecords = nullptr;
|
||||
|
||||
/// Index of all compile units, mapping identifier to |CompilandIndexItem|
|
||||
/// instance.
|
||||
CompileUnitIndex m_cus;
|
||||
|
||||
/// An allocator for the interval maps
|
||||
llvm::IntervalMap<lldb::addr_t, uint32_t>::Allocator m_allocator;
|
||||
|
||||
/// Maps virtual address to module index
|
||||
llvm::IntervalMap<lldb::addr_t, uint16_t> m_va_to_modi;
|
||||
|
||||
/// The address at which the program has been loaded into memory.
|
||||
lldb::addr_t m_load_address = 0;
|
||||
|
||||
PdbIndex();
|
||||
|
||||
void BuildAddrToSymbolMap(CompilandIndexItem &cci);
|
||||
|
||||
public:
|
||||
static llvm::Expected<std::unique_ptr<PdbIndex>>
|
||||
create(std::unique_ptr<llvm::pdb::PDBFile>);
|
||||
|
||||
void SetLoadAddress(lldb::addr_t addr) { m_load_address = addr; }
|
||||
void ParseSectionContribs();
|
||||
|
||||
llvm::pdb::PDBFile &pdb() { return *m_file; }
|
||||
const llvm::pdb::PDBFile &pdb() const { return *m_file; }
|
||||
|
||||
llvm::pdb::DbiStream &dbi() { return *m_dbi; }
|
||||
const llvm::pdb::DbiStream &dbi() const { return *m_dbi; }
|
||||
|
||||
llvm::pdb::TpiStream &tpi() { return *m_tpi; }
|
||||
const llvm::pdb::TpiStream &tpi() const { return *m_tpi; }
|
||||
|
||||
llvm::pdb::TpiStream &ipi() { return *m_ipi; }
|
||||
const llvm::pdb::TpiStream &ipi() const { return *m_ipi; }
|
||||
|
||||
llvm::pdb::InfoStream &info() { return *m_info; }
|
||||
const llvm::pdb::InfoStream &info() const { return *m_info; }
|
||||
|
||||
llvm::pdb::PublicsStream &publics() { return *m_publics; }
|
||||
const llvm::pdb::PublicsStream &publics() const { return *m_publics; }
|
||||
|
||||
llvm::pdb::GlobalsStream &globals() { return *m_globals; }
|
||||
const llvm::pdb::GlobalsStream &globals() const { return *m_globals; }
|
||||
|
||||
llvm::pdb::SymbolStream &symrecords() { return *m_symrecords; }
|
||||
const llvm::pdb::SymbolStream &symrecords() const { return *m_symrecords; }
|
||||
|
||||
CompileUnitIndex &compilands() { return m_cus; }
|
||||
const CompileUnitIndex &compilands() const { return m_cus; }
|
||||
|
||||
lldb::addr_t MakeVirtualAddress(uint16_t segment, uint32_t offset) const;
|
||||
lldb::addr_t MakeVirtualAddress(const SegmentOffset &so) const;
|
||||
|
||||
std::vector<SymbolAndUid> FindSymbolsByVa(lldb::addr_t va);
|
||||
|
||||
llvm::codeview::CVSymbol ReadSymbolRecord(PdbCuSymId cu_sym) const;
|
||||
|
||||
llvm::Optional<uint16_t> GetModuleIndexForAddr(uint16_t segment,
|
||||
uint32_t offset) const;
|
||||
llvm::Optional<uint16_t> GetModuleIndexForVa(lldb::addr_t va) const;
|
||||
};
|
||||
} // namespace npdb
|
||||
} // namespace lldb_private
|
||||
|
||||
#endif
|
@ -1,202 +0,0 @@
|
||||
//===-- PdbSymUid.h ---------------------------------------------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
// A unique identification scheme for Pdb records.
|
||||
// The scheme is to partition a 64-bit integer into an 8-bit tag field, which
|
||||
// will contain some value from the PDB_SymType enumeration. The format of the
|
||||
// other 48-bits depend on the tag, but must be sufficient to locate the
|
||||
// corresponding entry in the underlying PDB file quickly. For example, for
|
||||
// a compile unit, we use 2 bytes to represent the index, which allows fast
|
||||
// access to the compile unit's information.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLDB_PLUGINS_SYMBOLFILENATIVEPDB_PDBSYMUID_H
|
||||
#define LLDB_PLUGINS_SYMBOLFILENATIVEPDB_PDBSYMUID_H
|
||||
|
||||
#include "llvm/DebugInfo/PDB/PDBTypes.h"
|
||||
#include "llvm/Support/Compiler.h"
|
||||
|
||||
#include "lldb/Utility/LLDBAssert.h"
|
||||
#include "lldb/lldb-types.h"
|
||||
|
||||
namespace lldb_private {
|
||||
namespace npdb {
|
||||
|
||||
// **important** - All concrete id types must have the 1-byte tag field at
|
||||
// the beginning so that the types are all layout-compatible with each
|
||||
// other, which is necessary in order to be able to safely access the tag
|
||||
// member through any union member.
|
||||
|
||||
struct PdbCompilandId {
|
||||
uint64_t tag : 8; // PDB_SymType::Compiland
|
||||
uint64_t modi : 16; // 0-based index of module in PDB
|
||||
uint64_t unused : 32;
|
||||
};
|
||||
struct PdbCuSymId {
|
||||
uint64_t tag : 8; // PDB_SymType::Data, Function, Block, etc.
|
||||
uint64_t
|
||||
offset : 32; // Offset of symbol's record in module stream. This is
|
||||
// offset by 4 from the CVSymbolArray's notion of offset
|
||||
// due to the debug magic at the beginning of the stream.
|
||||
uint64_t modi : 16; // 0-based index of module in PDB
|
||||
};
|
||||
struct PdbTypeSymId {
|
||||
uint64_t tag : 8; // PDB_SymType::FunctionSig, Enum, PointerType, etc.
|
||||
uint64_t is_ipi : 8; // 1 if this value is from the IPI stream, 0 for TPI.
|
||||
uint64_t unused : 16;
|
||||
uint64_t index : 32; // codeview::TypeIndex
|
||||
};
|
||||
|
||||
static_assert(sizeof(PdbCompilandId) == 8, "invalid uid size");
|
||||
static_assert(sizeof(PdbCuSymId) == 8, "invalid uid size");
|
||||
static_assert(std::is_standard_layout<PdbCompilandId>::value,
|
||||
"type is not standard layout!");
|
||||
static_assert(std::is_standard_layout<PdbCuSymId>::value,
|
||||
"type is not standard layout!");
|
||||
|
||||
class PdbSymUid {
|
||||
union {
|
||||
PdbCompilandId comp_id;
|
||||
PdbCuSymId cu_sym;
|
||||
PdbTypeSymId type_sym;
|
||||
} m_uid;
|
||||
|
||||
PdbSymUid() { ::memset(&m_uid, 0, sizeof(m_uid)); }
|
||||
|
||||
public:
|
||||
static bool isTypeSym(llvm::pdb::PDB_SymType tag) {
|
||||
switch (tag) {
|
||||
case llvm::pdb::PDB_SymType::ArrayType:
|
||||
case llvm::pdb::PDB_SymType::BaseClass:
|
||||
case llvm::pdb::PDB_SymType::BaseInterface:
|
||||
case llvm::pdb::PDB_SymType::BuiltinType:
|
||||
case llvm::pdb::PDB_SymType::CustomType:
|
||||
case llvm::pdb::PDB_SymType::Enum:
|
||||
case llvm::pdb::PDB_SymType::FunctionArg:
|
||||
case llvm::pdb::PDB_SymType::FunctionSig:
|
||||
case llvm::pdb::PDB_SymType::Typedef:
|
||||
case llvm::pdb::PDB_SymType::VectorType:
|
||||
case llvm::pdb::PDB_SymType::VTableShape:
|
||||
case llvm::pdb::PDB_SymType::PointerType:
|
||||
case llvm::pdb::PDB_SymType::UDT:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static bool isCuSym(llvm::pdb::PDB_SymType tag) {
|
||||
switch (tag) {
|
||||
case llvm::pdb::PDB_SymType::Block:
|
||||
case llvm::pdb::PDB_SymType::Callee:
|
||||
case llvm::pdb::PDB_SymType::Caller:
|
||||
case llvm::pdb::PDB_SymType::CallSite:
|
||||
case llvm::pdb::PDB_SymType::CoffGroup:
|
||||
case llvm::pdb::PDB_SymType::CompilandDetails:
|
||||
case llvm::pdb::PDB_SymType::CompilandEnv:
|
||||
case llvm::pdb::PDB_SymType::Custom:
|
||||
case llvm::pdb::PDB_SymType::Data:
|
||||
case llvm::pdb::PDB_SymType::Function:
|
||||
case llvm::pdb::PDB_SymType::Inlinee:
|
||||
case llvm::pdb::PDB_SymType::InlineSite:
|
||||
case llvm::pdb::PDB_SymType::Label:
|
||||
case llvm::pdb::PDB_SymType::Thunk:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static PdbSymUid makeCuSymId(llvm::codeview::ProcRefSym sym) {
|
||||
return makeCuSymId(llvm::pdb::PDB_SymType::Function, sym.Module - 1,
|
||||
sym.SymOffset);
|
||||
}
|
||||
|
||||
static PdbSymUid makeCuSymId(llvm::pdb::PDB_SymType type, uint16_t modi,
|
||||
uint32_t offset) {
|
||||
lldbassert(isCuSym(type));
|
||||
|
||||
PdbSymUid uid;
|
||||
uid.m_uid.cu_sym.modi = modi;
|
||||
uid.m_uid.cu_sym.offset = offset;
|
||||
uid.m_uid.cu_sym.tag = static_cast<uint8_t>(type);
|
||||
return uid;
|
||||
}
|
||||
|
||||
static PdbSymUid makeCompilandId(llvm::codeview::ProcRefSym sym) {
|
||||
// S_PROCREF symbols are 1-based
|
||||
lldbassert(sym.Module > 0);
|
||||
return makeCompilandId(sym.Module - 1);
|
||||
}
|
||||
|
||||
static PdbSymUid makeCompilandId(uint16_t modi) {
|
||||
PdbSymUid uid;
|
||||
uid.m_uid.comp_id.modi = modi;
|
||||
uid.m_uid.cu_sym.tag =
|
||||
static_cast<uint8_t>(llvm::pdb::PDB_SymType::Compiland);
|
||||
return uid;
|
||||
}
|
||||
|
||||
static PdbSymUid makeTypeSymId(llvm::pdb::PDB_SymType type,
|
||||
llvm::codeview::TypeIndex index, bool is_ipi) {
|
||||
lldbassert(isTypeSym(type));
|
||||
|
||||
PdbSymUid uid;
|
||||
uid.m_uid.type_sym.tag = static_cast<uint8_t>(type);
|
||||
uid.m_uid.type_sym.index = index.getIndex();
|
||||
uid.m_uid.type_sym.is_ipi = static_cast<uint8_t>(is_ipi);
|
||||
return uid;
|
||||
}
|
||||
|
||||
static PdbSymUid fromOpaqueId(uint64_t value) {
|
||||
PdbSymUid result;
|
||||
::memcpy(&result.m_uid, &value, sizeof(value));
|
||||
return result;
|
||||
}
|
||||
|
||||
uint64_t toOpaqueId() const {
|
||||
uint64_t result;
|
||||
::memcpy(&result, &m_uid, sizeof(m_uid));
|
||||
return result;
|
||||
}
|
||||
|
||||
bool isPubSym() const {
|
||||
return tag() == llvm::pdb::PDB_SymType::PublicSymbol;
|
||||
}
|
||||
bool isCompiland() const {
|
||||
return tag() == llvm::pdb::PDB_SymType::Compiland;
|
||||
}
|
||||
|
||||
llvm::pdb::PDB_SymType tag() const {
|
||||
return static_cast<llvm::pdb::PDB_SymType>(m_uid.comp_id.tag);
|
||||
}
|
||||
|
||||
const PdbCompilandId &asCompiland() const {
|
||||
lldbassert(tag() == llvm::pdb::PDB_SymType::Compiland);
|
||||
return m_uid.comp_id;
|
||||
}
|
||||
|
||||
const PdbCuSymId &asCuSym() const {
|
||||
lldbassert(isCuSym(tag()));
|
||||
return m_uid.cu_sym;
|
||||
}
|
||||
|
||||
const PdbTypeSymId &asTypeSym() const {
|
||||
lldbassert(isTypeSym(tag()));
|
||||
return m_uid.type_sym;
|
||||
}
|
||||
};
|
||||
|
||||
struct SymbolAndUid {
|
||||
llvm::codeview::CVSymbol sym;
|
||||
PdbSymUid uid;
|
||||
};
|
||||
} // namespace npdb
|
||||
} // namespace lldb_private
|
||||
|
||||
#endif
|
@ -1,258 +0,0 @@
|
||||
//===-- PdbUtil.cpp ---------------------------------------------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "PdbUtil.h"
|
||||
|
||||
#include "llvm/DebugInfo/CodeView/SymbolDeserializer.h"
|
||||
|
||||
#include "lldb/Utility/LLDBAssert.h"
|
||||
|
||||
using namespace lldb_private;
|
||||
using namespace lldb_private::npdb;
|
||||
using namespace llvm::codeview;
|
||||
using namespace llvm::pdb;
|
||||
|
||||
llvm::pdb::PDB_SymType
|
||||
lldb_private::npdb::CVSymToPDBSym(llvm::codeview::SymbolKind kind) {
|
||||
switch (kind) {
|
||||
case S_COMPILE3:
|
||||
case S_OBJNAME:
|
||||
return PDB_SymType::CompilandDetails;
|
||||
case S_ENVBLOCK:
|
||||
return PDB_SymType::CompilandEnv;
|
||||
case S_THUNK32:
|
||||
case S_TRAMPOLINE:
|
||||
return PDB_SymType::Thunk;
|
||||
case S_COFFGROUP:
|
||||
return PDB_SymType::CoffGroup;
|
||||
case S_EXPORT:
|
||||
return PDB_SymType::Export;
|
||||
case S_LPROC32:
|
||||
case S_GPROC32:
|
||||
case S_LPROC32_DPC:
|
||||
return PDB_SymType::Function;
|
||||
case S_PUB32:
|
||||
return PDB_SymType::PublicSymbol;
|
||||
case S_INLINESITE:
|
||||
return PDB_SymType::InlineSite;
|
||||
case S_LOCAL:
|
||||
case S_BPREL32:
|
||||
case S_REGREL32:
|
||||
case S_MANCONSTANT:
|
||||
case S_CONSTANT:
|
||||
case S_LDATA32:
|
||||
case S_GDATA32:
|
||||
case S_LMANDATA:
|
||||
case S_GMANDATA:
|
||||
case S_LTHREAD32:
|
||||
case S_GTHREAD32:
|
||||
return PDB_SymType::Data;
|
||||
case S_BLOCK32:
|
||||
return PDB_SymType::Block;
|
||||
case S_LABEL32:
|
||||
return PDB_SymType::Label;
|
||||
case S_CALLSITEINFO:
|
||||
return PDB_SymType::CallSite;
|
||||
case S_HEAPALLOCSITE:
|
||||
return PDB_SymType::HeapAllocationSite;
|
||||
case S_CALLEES:
|
||||
return PDB_SymType::Callee;
|
||||
case S_CALLERS:
|
||||
return PDB_SymType::Caller;
|
||||
default:
|
||||
lldbassert(false && "Invalid symbol record kind!");
|
||||
}
|
||||
return PDB_SymType::None;
|
||||
}
|
||||
|
||||
bool lldb_private::npdb::SymbolHasAddress(const llvm::codeview::CVSymbol &sym) {
|
||||
switch (sym.kind()) {
|
||||
case S_GPROC32:
|
||||
case S_LPROC32:
|
||||
case S_GPROC32_ID:
|
||||
case S_LPROC32_ID:
|
||||
case S_LPROC32_DPC:
|
||||
case S_LPROC32_DPC_ID:
|
||||
case S_THUNK32:
|
||||
case S_TRAMPOLINE:
|
||||
case S_COFFGROUP:
|
||||
case S_BLOCK32:
|
||||
case S_LABEL32:
|
||||
case S_CALLSITEINFO:
|
||||
case S_HEAPALLOCSITE:
|
||||
case S_LDATA32:
|
||||
case S_GDATA32:
|
||||
case S_LMANDATA:
|
||||
case S_GMANDATA:
|
||||
case S_LTHREAD32:
|
||||
case S_GTHREAD32:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool lldb_private::npdb::SymbolIsCode(const llvm::codeview::CVSymbol &sym) {
|
||||
switch (sym.kind()) {
|
||||
case S_GPROC32:
|
||||
case S_LPROC32:
|
||||
case S_GPROC32_ID:
|
||||
case S_LPROC32_ID:
|
||||
case S_LPROC32_DPC:
|
||||
case S_LPROC32_DPC_ID:
|
||||
case S_THUNK32:
|
||||
case S_TRAMPOLINE:
|
||||
case S_COFFGROUP:
|
||||
case S_BLOCK32:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename RecordT> RecordT createRecord(const CVSymbol &sym) {
|
||||
RecordT record(static_cast<SymbolRecordKind>(sym.kind()));
|
||||
cantFail(SymbolDeserializer::deserializeAs<RecordT>(sym, record));
|
||||
return record;
|
||||
}
|
||||
|
||||
template <typename RecordT>
|
||||
static SegmentOffset GetSegmentAndOffset(const CVSymbol &sym) {
|
||||
RecordT record = createRecord<RecordT>(sym);
|
||||
return {record.Segment, record.CodeOffset};
|
||||
}
|
||||
|
||||
template <>
|
||||
SegmentOffset GetSegmentAndOffset<TrampolineSym>(const CVSymbol &sym) {
|
||||
TrampolineSym record = createRecord<TrampolineSym>(sym);
|
||||
return {record.ThunkSection, record.ThunkOffset};
|
||||
}
|
||||
|
||||
template <> SegmentOffset GetSegmentAndOffset<Thunk32Sym>(const CVSymbol &sym) {
|
||||
Thunk32Sym record = createRecord<Thunk32Sym>(sym);
|
||||
return {record.Segment, record.Offset};
|
||||
}
|
||||
|
||||
template <>
|
||||
SegmentOffset GetSegmentAndOffset<CoffGroupSym>(const CVSymbol &sym) {
|
||||
CoffGroupSym record = createRecord<CoffGroupSym>(sym);
|
||||
return {record.Segment, record.Offset};
|
||||
}
|
||||
|
||||
template <> SegmentOffset GetSegmentAndOffset<DataSym>(const CVSymbol &sym) {
|
||||
DataSym record = createRecord<DataSym>(sym);
|
||||
return {record.Segment, record.DataOffset};
|
||||
}
|
||||
|
||||
template <>
|
||||
SegmentOffset GetSegmentAndOffset<ThreadLocalDataSym>(const CVSymbol &sym) {
|
||||
ThreadLocalDataSym record = createRecord<ThreadLocalDataSym>(sym);
|
||||
return {record.Segment, record.DataOffset};
|
||||
}
|
||||
|
||||
SegmentOffset
|
||||
lldb_private::npdb::GetSegmentAndOffset(const llvm::codeview::CVSymbol &sym) {
|
||||
switch (sym.kind()) {
|
||||
case S_GPROC32:
|
||||
case S_LPROC32:
|
||||
case S_GPROC32_ID:
|
||||
case S_LPROC32_ID:
|
||||
case S_LPROC32_DPC:
|
||||
case S_LPROC32_DPC_ID:
|
||||
return ::GetSegmentAndOffset<ProcSym>(sym);
|
||||
case S_THUNK32:
|
||||
return ::GetSegmentAndOffset<Thunk32Sym>(sym);
|
||||
break;
|
||||
case S_TRAMPOLINE:
|
||||
return ::GetSegmentAndOffset<TrampolineSym>(sym);
|
||||
break;
|
||||
case S_COFFGROUP:
|
||||
return ::GetSegmentAndOffset<CoffGroupSym>(sym);
|
||||
break;
|
||||
case S_BLOCK32:
|
||||
return ::GetSegmentAndOffset<BlockSym>(sym);
|
||||
break;
|
||||
case S_LABEL32:
|
||||
return ::GetSegmentAndOffset<LabelSym>(sym);
|
||||
break;
|
||||
case S_CALLSITEINFO:
|
||||
return ::GetSegmentAndOffset<CallSiteInfoSym>(sym);
|
||||
break;
|
||||
case S_HEAPALLOCSITE:
|
||||
return ::GetSegmentAndOffset<HeapAllocationSiteSym>(sym);
|
||||
break;
|
||||
case S_LDATA32:
|
||||
case S_GDATA32:
|
||||
case S_LMANDATA:
|
||||
case S_GMANDATA:
|
||||
return ::GetSegmentAndOffset<DataSym>(sym);
|
||||
break;
|
||||
case S_LTHREAD32:
|
||||
case S_GTHREAD32:
|
||||
return ::GetSegmentAndOffset<ThreadLocalDataSym>(sym);
|
||||
break;
|
||||
default:
|
||||
lldbassert(false && "Record does not have a segment/offset!");
|
||||
}
|
||||
return {0, 0};
|
||||
}
|
||||
|
||||
template <typename RecordT>
|
||||
SegmentOffsetLength GetSegmentOffsetAndLength(const CVSymbol &sym) {
|
||||
RecordT record = createRecord<RecordT>(sym);
|
||||
return {record.Segment, record.CodeOffset, record.CodeSize};
|
||||
}
|
||||
|
||||
template <>
|
||||
SegmentOffsetLength
|
||||
GetSegmentOffsetAndLength<TrampolineSym>(const CVSymbol &sym) {
|
||||
TrampolineSym record = createRecord<TrampolineSym>(sym);
|
||||
return {record.ThunkSection, record.ThunkOffset, record.Size};
|
||||
}
|
||||
|
||||
template <>
|
||||
SegmentOffsetLength GetSegmentOffsetAndLength<Thunk32Sym>(const CVSymbol &sym) {
|
||||
Thunk32Sym record = createRecord<Thunk32Sym>(sym);
|
||||
return SegmentOffsetLength{record.Segment, record.Offset, record.Length};
|
||||
}
|
||||
|
||||
template <>
|
||||
SegmentOffsetLength
|
||||
GetSegmentOffsetAndLength<CoffGroupSym>(const CVSymbol &sym) {
|
||||
CoffGroupSym record = createRecord<CoffGroupSym>(sym);
|
||||
return SegmentOffsetLength{record.Segment, record.Offset, record.Size};
|
||||
}
|
||||
|
||||
SegmentOffsetLength lldb_private::npdb::GetSegmentOffsetAndLength(
|
||||
const llvm::codeview::CVSymbol &sym) {
|
||||
switch (sym.kind()) {
|
||||
case S_GPROC32:
|
||||
case S_LPROC32:
|
||||
case S_GPROC32_ID:
|
||||
case S_LPROC32_ID:
|
||||
case S_LPROC32_DPC:
|
||||
case S_LPROC32_DPC_ID:
|
||||
return ::GetSegmentOffsetAndLength<ProcSym>(sym);
|
||||
case S_THUNK32:
|
||||
return ::GetSegmentOffsetAndLength<Thunk32Sym>(sym);
|
||||
break;
|
||||
case S_TRAMPOLINE:
|
||||
return ::GetSegmentOffsetAndLength<TrampolineSym>(sym);
|
||||
break;
|
||||
case S_COFFGROUP:
|
||||
return ::GetSegmentOffsetAndLength<CoffGroupSym>(sym);
|
||||
break;
|
||||
case S_BLOCK32:
|
||||
return ::GetSegmentOffsetAndLength<BlockSym>(sym);
|
||||
break;
|
||||
default:
|
||||
lldbassert(false && "Record does not have a segment/offset/length triple!");
|
||||
}
|
||||
return {0, 0, 0};
|
||||
}
|
@ -1,58 +0,0 @@
|
||||
//===-- PdbUtil.h -----------------------------------------------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLDB_PLUGINS_SYMBOLFILENATIVEPDB_PDBUTIL_H
|
||||
#define LLDB_PLUGINS_SYMBOLFILENATIVEPDB_PDBUTIL_H
|
||||
|
||||
#include "llvm/DebugInfo/CodeView/SymbolRecord.h"
|
||||
#include "llvm/DebugInfo/PDB/PDBTypes.h"
|
||||
|
||||
#include <tuple>
|
||||
#include <utility>
|
||||
|
||||
namespace lldb_private {
|
||||
namespace npdb {
|
||||
|
||||
struct SegmentOffset {
|
||||
SegmentOffset() = default;
|
||||
SegmentOffset(uint16_t s, uint32_t o) : segment(s), offset(o) {}
|
||||
uint16_t segment = 0;
|
||||
uint32_t offset = 0;
|
||||
};
|
||||
|
||||
struct SegmentOffsetLength {
|
||||
SegmentOffsetLength() = default;
|
||||
SegmentOffsetLength(uint16_t s, uint32_t o, uint32_t l)
|
||||
: so(s, o), length(l) {}
|
||||
SegmentOffset so;
|
||||
uint32_t length = 0;
|
||||
};
|
||||
|
||||
llvm::pdb::PDB_SymType CVSymToPDBSym(llvm::codeview::SymbolKind kind);
|
||||
|
||||
bool SymbolHasAddress(const llvm::codeview::CVSymbol &sym);
|
||||
bool SymbolIsCode(const llvm::codeview::CVSymbol &sym);
|
||||
|
||||
SegmentOffset GetSegmentAndOffset(const llvm::codeview::CVSymbol &sym);
|
||||
SegmentOffsetLength
|
||||
GetSegmentOffsetAndLength(const llvm::codeview::CVSymbol &sym);
|
||||
|
||||
template <typename RecordT> bool IsValidRecord(const RecordT &sym) {
|
||||
return true;
|
||||
}
|
||||
|
||||
inline bool IsValidRecord(const llvm::codeview::ProcRefSym &sym) {
|
||||
// S_PROCREF symbols have 1-based module indices.
|
||||
return sym.Module > 0;
|
||||
}
|
||||
|
||||
} // namespace npdb
|
||||
} // namespace lldb_private
|
||||
|
||||
#endif
|
@ -1,620 +0,0 @@
|
||||
//===-- SymbolFileNativePDB.cpp ---------------------------------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "SymbolFileNativePDB.h"
|
||||
|
||||
#include "clang/Lex/Lexer.h"
|
||||
|
||||
#include "lldb/Core/Module.h"
|
||||
#include "lldb/Core/PluginManager.h"
|
||||
#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"
|
||||
|
||||
#include "llvm/DebugInfo/CodeView/CVRecord.h"
|
||||
#include "llvm/DebugInfo/CodeView/DebugLinesSubsection.h"
|
||||
#include "llvm/DebugInfo/CodeView/RecordName.h"
|
||||
#include "llvm/DebugInfo/CodeView/SymbolDeserializer.h"
|
||||
#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"
|
||||
#include "llvm/DebugInfo/PDB/PDBTypes.h"
|
||||
#include "llvm/Object/COFF.h"
|
||||
#include "llvm/Support/Allocator.h"
|
||||
#include "llvm/Support/BinaryStreamReader.h"
|
||||
#include "llvm/Support/ErrorOr.h"
|
||||
#include "llvm/Support/MemoryBuffer.h"
|
||||
|
||||
#include "PdbSymUid.h"
|
||||
#include "PdbUtil.h"
|
||||
|
||||
using namespace lldb;
|
||||
using namespace lldb_private;
|
||||
using namespace lldb_private::npdb;
|
||||
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);
|
||||
if (auto EC = File->parseFileHeaders())
|
||||
return nullptr;
|
||||
if (auto EC = File->parseStreamData())
|
||||
return nullptr;
|
||||
|
||||
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);
|
||||
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;
|
||||
}
|
||||
|
||||
void SymbolFileNativePDB::Initialize() {
|
||||
PluginManager::RegisterPlugin(GetPluginNameStatic(),
|
||||
GetPluginDescriptionStatic(), CreateInstance,
|
||||
DebuggerInitialize);
|
||||
}
|
||||
|
||||
void SymbolFileNativePDB::Terminate() {
|
||||
PluginManager::UnregisterPlugin(CreateInstance);
|
||||
}
|
||||
|
||||
void SymbolFileNativePDB::DebuggerInitialize(lldb_private::Debugger &debugger) {
|
||||
}
|
||||
|
||||
lldb_private::ConstString SymbolFileNativePDB::GetPluginNameStatic() {
|
||||
static ConstString g_name("native-pdb");
|
||||
return g_name;
|
||||
}
|
||||
|
||||
const char *SymbolFileNativePDB::GetPluginDescriptionStatic() {
|
||||
return "Microsoft PDB debug symbol cross-platform file reader.";
|
||||
}
|
||||
|
||||
lldb_private::SymbolFile *
|
||||
SymbolFileNativePDB::CreateInstance(lldb_private::ObjectFile *obj_file) {
|
||||
return new SymbolFileNativePDB(obj_file);
|
||||
}
|
||||
|
||||
SymbolFileNativePDB::SymbolFileNativePDB(lldb_private::ObjectFile *object_file)
|
||||
: 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() {
|
||||
m_obj_load_address = m_obj_file->GetFileOffset();
|
||||
m_index->SetLoadAddress(m_obj_load_address);
|
||||
m_index->ParseSectionContribs();
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
lldb::FunctionSP SymbolFileNativePDB::CreateFunction(PdbSymUid func_uid,
|
||||
const SymbolContext &sc) {
|
||||
lldbassert(func_uid.tag() == PDB_SymType::Function);
|
||||
|
||||
PdbSymUid cuid = PdbSymUid::makeCompilandId(func_uid.asCuSym().modi);
|
||||
|
||||
const CompilandIndexItem *cci = m_index->compilands().GetCompiland(cuid);
|
||||
lldbassert(cci);
|
||||
CVSymbol sym_record =
|
||||
cci->m_debug_stream.readSymbolAtOffset(func_uid.asCuSym().offset);
|
||||
|
||||
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,
|
||||
sc.module_sp->GetSectionList());
|
||||
if (!func_range.GetBaseAddress().IsValid())
|
||||
return nullptr;
|
||||
|
||||
lldb_private::Type *func_type = nullptr;
|
||||
|
||||
// FIXME: Resolve types and mangled names.
|
||||
PdbSymUid sig_uid =
|
||||
PdbSymUid::makeTypeSymId(PDB_SymType::FunctionSig, TypeIndex{0}, false);
|
||||
Mangled mangled(getSymbolName(sym_record));
|
||||
|
||||
FunctionSP func_sp = std::make_shared<Function>(
|
||||
sc.comp_unit, func_uid.toOpaqueId(), sig_uid.toOpaqueId(), mangled,
|
||||
func_type, func_range);
|
||||
|
||||
sc.comp_unit->AddFunction(func_sp);
|
||||
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;
|
||||
|
||||
llvm::StringRef source_file_name =
|
||||
m_index->compilands().GetMainSourceFile(cci);
|
||||
lldb_private::FileSpec fs(source_file_name, false);
|
||||
|
||||
CompUnitSP cu_sp =
|
||||
std::make_shared<CompileUnit>(m_obj_file->GetModule(), nullptr, fs,
|
||||
cci.m_uid.toOpaqueId(), lang, optimized);
|
||||
|
||||
const PdbCompilandId &cuid = cci.m_uid.asCompiland();
|
||||
m_obj_file->GetModule()->GetSymbolVendor()->SetCompileUnitAtIndex(cuid.modi,
|
||||
cu_sp);
|
||||
return cu_sp;
|
||||
}
|
||||
|
||||
FunctionSP SymbolFileNativePDB::GetOrCreateFunction(PdbSymUid func_uid,
|
||||
const SymbolContext &sc) {
|
||||
lldbassert(func_uid.tag() == PDB_SymType::Function);
|
||||
auto emplace_result = m_functions.try_emplace(func_uid.toOpaqueId(), nullptr);
|
||||
if (emplace_result.second)
|
||||
emplace_result.first->second = CreateFunction(func_uid, sc);
|
||||
|
||||
lldbassert(emplace_result.first->second);
|
||||
return emplace_result.first->second;
|
||||
}
|
||||
|
||||
CompUnitSP
|
||||
SymbolFileNativePDB::GetOrCreateCompileUnit(const CompilandIndexItem &cci) {
|
||||
auto emplace_result =
|
||||
m_compilands.try_emplace(cci.m_uid.toOpaqueId(), nullptr);
|
||||
if (emplace_result.second)
|
||||
emplace_result.first->second = CreateCompileUnit(cci);
|
||||
|
||||
lldbassert(emplace_result.first->second);
|
||||
return emplace_result.first->second;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
lldb::LanguageType SymbolFileNativePDB::ParseCompileUnitLanguage(
|
||||
const lldb_private::SymbolContext &sc) {
|
||||
// What fields should I expect to be filled out on the SymbolContext? Is it
|
||||
// safe to assume that `sc.comp_unit` is valid?
|
||||
if (!sc.comp_unit)
|
||||
return lldb::eLanguageTypeUnknown;
|
||||
PdbSymUid uid = PdbSymUid::fromOpaqueId(sc.comp_unit->GetID());
|
||||
lldbassert(uid.tag() == PDB_SymType::Compiland);
|
||||
|
||||
CompilandIndexItem *item = m_index->compilands().GetCompiland(uid);
|
||||
lldbassert(item);
|
||||
if (!item->m_compile_opts)
|
||||
return lldb::eLanguageTypeUnknown;
|
||||
|
||||
return TranslateLanguage(item->m_compile_opts->getLanguage());
|
||||
}
|
||||
|
||||
size_t SymbolFileNativePDB::ParseCompileUnitFunctions(
|
||||
const lldb_private::SymbolContext &sc) {
|
||||
lldbassert(sc.comp_unit);
|
||||
return false;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
SymbolFileNativePDB::ResolveSymbolContext(const lldb_private::Address &addr,
|
||||
uint32_t resolve_scope,
|
||||
lldb_private::SymbolContext &sc) {
|
||||
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;
|
||||
PdbSymUid cuid = PdbSymUid::makeCompilandId(*modi);
|
||||
CompilandIndexItem *cci = m_index->compilands().GetCompiland(cuid);
|
||||
if (!cci)
|
||||
return 0;
|
||||
|
||||
sc.comp_unit = GetOrCreateCompileUnit(*cci).get();
|
||||
resolved_flags |= eSymbolContextCompUnit;
|
||||
}
|
||||
|
||||
if (resolve_scope & eSymbolContextFunction) {
|
||||
lldbassert(sc.comp_unit);
|
||||
std::vector<SymbolAndUid> matches = m_index->FindSymbolsByVa(file_addr);
|
||||
for (const auto &match : matches) {
|
||||
if (match.uid.tag() != PDB_SymType::Function)
|
||||
continue;
|
||||
sc.function = GetOrCreateFunction(match.uid, sc).get();
|
||||
}
|
||||
resolved_flags |= eSymbolContextFunction;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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());
|
||||
}
|
||||
|
||||
bool SymbolFileNativePDB::ParseCompileUnitLineTable(
|
||||
const lldb_private::SymbolContext &sc) {
|
||||
// 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.
|
||||
lldbassert(sc.comp_unit);
|
||||
PdbSymUid cu_id = PdbSymUid::fromOpaqueId(sc.comp_unit->GetID());
|
||||
lldbassert(cu_id.isCompiland());
|
||||
CompilandIndexItem *cci = m_index->compilands().GetCompiland(cu_id);
|
||||
lldbassert(cci);
|
||||
auto line_table = llvm::make_unique<LineTable>(sc.comp_unit);
|
||||
|
||||
// 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());
|
||||
uint32_t file_index = std::distance(cci->m_file_list.begin(), fn_iter);
|
||||
|
||||
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;
|
||||
|
||||
sc.comp_unit->SetLineTable(line_table.release());
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SymbolFileNativePDB::ParseCompileUnitDebugMacros(
|
||||
const lldb_private::SymbolContext &sc) {
|
||||
// PDB doesn't contain information about macros
|
||||
return false;
|
||||
}
|
||||
|
||||
bool SymbolFileNativePDB::ParseCompileUnitSupportFiles(
|
||||
const lldb_private::SymbolContext &sc,
|
||||
lldb_private::FileSpecList &support_files) {
|
||||
lldbassert(sc.comp_unit);
|
||||
|
||||
PdbSymUid comp_uid = PdbSymUid::fromOpaqueId(sc.comp_unit->GetID());
|
||||
lldbassert(comp_uid.tag() == PDB_SymType::Compiland);
|
||||
|
||||
const CompilandIndexItem *cci = m_index->compilands().GetCompiland(comp_uid);
|
||||
lldbassert(cci);
|
||||
|
||||
for (llvm::StringRef f : cci->m_file_list) {
|
||||
FileSpec::Style style =
|
||||
f.startswith("/") ? FileSpec::Style::posix : FileSpec::Style::windows;
|
||||
FileSpec spec(f, false, style);
|
||||
support_files.Append(spec);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SymbolFileNativePDB::ParseImportedModules(
|
||||
const lldb_private::SymbolContext &sc,
|
||||
std::vector<lldb_private::ConstString> &imported_modules) {
|
||||
// PDB does not yet support module debug info
|
||||
return false;
|
||||
}
|
||||
|
||||
size_t SymbolFileNativePDB::ParseFunctionBlocks(
|
||||
const lldb_private::SymbolContext &sc) {
|
||||
lldbassert(sc.comp_unit && sc.function);
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32_t SymbolFileNativePDB::FindFunctions(
|
||||
const lldb_private::ConstString &name,
|
||||
const lldb_private::CompilerDeclContext *parent_decl_ctx,
|
||||
uint32_t name_type_mask, bool include_inlines, bool append,
|
||||
lldb_private::SymbolContextList &sc_list) {
|
||||
// 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;
|
||||
|
||||
PdbSymUid cuid = PdbSymUid::makeCompilandId(proc);
|
||||
CompilandIndexItem &cci = m_index->compilands().GetOrCreateCompiland(cuid);
|
||||
lldb_private::SymbolContext sc;
|
||||
|
||||
sc.comp_unit = GetOrCreateCompileUnit(cci).get();
|
||||
sc.module_sp = sc.comp_unit->GetModule();
|
||||
PdbSymUid func_uid = PdbSymUid::makeCuSymId(proc);
|
||||
sc.function = GetOrCreateFunction(func_uid, sc).get();
|
||||
|
||||
sc_list.Append(sc);
|
||||
}
|
||||
|
||||
return sc_list.GetSize();
|
||||
}
|
||||
|
||||
uint32_t
|
||||
SymbolFileNativePDB::FindFunctions(const lldb_private::RegularExpression ®ex,
|
||||
bool include_inlines, bool append,
|
||||
lldb_private::SymbolContextList &sc_list) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
lldb_private::CompilerDeclContext SymbolFileNativePDB::FindNamespace(
|
||||
const lldb_private::SymbolContext &sc,
|
||||
const lldb_private::ConstString &name,
|
||||
const lldb_private::CompilerDeclContext *parent_decl_ctx) {
|
||||
return {};
|
||||
}
|
||||
|
||||
lldb_private::TypeSystem *
|
||||
SymbolFileNativePDB::GetTypeSystemForLanguage(lldb::LanguageType language) {
|
||||
auto type_system =
|
||||
m_obj_file->GetModule()->GetTypeSystemForLanguage(language);
|
||||
if (type_system)
|
||||
type_system->SetSymbolFile(this);
|
||||
return type_system;
|
||||
}
|
||||
|
||||
lldb_private::ConstString SymbolFileNativePDB::GetPluginName() {
|
||||
static ConstString g_name("pdb");
|
||||
return g_name;
|
||||
}
|
||||
|
||||
uint32_t SymbolFileNativePDB::GetPluginVersion() { return 1; }
|
@ -1,181 +0,0 @@
|
||||
//===-- SymbolFileNativePDB.h -----------------------------------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef lldb_Plugins_SymbolFile_PDB_SymbolFileNativePDB_h_
|
||||
#define lldb_Plugins_SymbolFile_PDB_SymbolFileNativePDB_h_
|
||||
|
||||
#include "lldb/Core/UniqueCStringMap.h"
|
||||
#include "lldb/Symbol/SymbolFile.h"
|
||||
#include "lldb/Symbol/VariableList.h"
|
||||
#include "lldb/Utility/UserID.h"
|
||||
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "llvm/ADT/Optional.h"
|
||||
#include "llvm/DebugInfo/CodeView/CVRecord.h"
|
||||
#include "llvm/DebugInfo/CodeView/StringsAndChecksums.h"
|
||||
#include "llvm/DebugInfo/CodeView/SymbolRecord.h"
|
||||
#include "llvm/DebugInfo/PDB/Native/ModuleDebugStream.h"
|
||||
#include "llvm/DebugInfo/PDB/PDBTypes.h"
|
||||
|
||||
#include "CompileUnitIndex.h"
|
||||
#include "PdbIndex.h"
|
||||
|
||||
#include <unordered_map>
|
||||
|
||||
namespace llvm {
|
||||
namespace pdb {
|
||||
class PDBFile;
|
||||
class PDBSymbol;
|
||||
class PDBSymbolCompiland;
|
||||
class PDBSymbolData;
|
||||
class PDBSymbolFunc;
|
||||
|
||||
class DbiStream;
|
||||
class TpiStream;
|
||||
class TpiStream;
|
||||
class InfoStream;
|
||||
class PublicsStream;
|
||||
class GlobalsStream;
|
||||
class SymbolStream;
|
||||
class ModuleDebugStreamRef;
|
||||
} // namespace pdb
|
||||
} // namespace llvm
|
||||
|
||||
namespace lldb_private {
|
||||
namespace npdb {
|
||||
|
||||
class SymbolFileNativePDB : public lldb_private::SymbolFile {
|
||||
public:
|
||||
//------------------------------------------------------------------
|
||||
// Static Functions
|
||||
//------------------------------------------------------------------
|
||||
static void Initialize();
|
||||
|
||||
static void Terminate();
|
||||
|
||||
static void DebuggerInitialize(lldb_private::Debugger &debugger);
|
||||
|
||||
static lldb_private::ConstString GetPluginNameStatic();
|
||||
|
||||
static const char *GetPluginDescriptionStatic();
|
||||
|
||||
static lldb_private::SymbolFile *
|
||||
CreateInstance(lldb_private::ObjectFile *obj_file);
|
||||
|
||||
//------------------------------------------------------------------
|
||||
// Constructors and Destructors
|
||||
//------------------------------------------------------------------
|
||||
SymbolFileNativePDB(lldb_private::ObjectFile *ofile);
|
||||
|
||||
~SymbolFileNativePDB() override;
|
||||
|
||||
uint32_t CalculateAbilities() override;
|
||||
|
||||
void InitializeObject() override;
|
||||
|
||||
//------------------------------------------------------------------
|
||||
// Compile Unit function calls
|
||||
//------------------------------------------------------------------
|
||||
|
||||
uint32_t GetNumCompileUnits() override;
|
||||
|
||||
lldb::CompUnitSP ParseCompileUnitAtIndex(uint32_t index) override;
|
||||
|
||||
lldb::LanguageType
|
||||
ParseCompileUnitLanguage(const lldb_private::SymbolContext &sc) override;
|
||||
|
||||
size_t
|
||||
ParseCompileUnitFunctions(const lldb_private::SymbolContext &sc) override;
|
||||
|
||||
bool
|
||||
ParseCompileUnitLineTable(const lldb_private::SymbolContext &sc) override;
|
||||
|
||||
bool
|
||||
ParseCompileUnitDebugMacros(const lldb_private::SymbolContext &sc) override;
|
||||
|
||||
bool ParseCompileUnitSupportFiles(
|
||||
const lldb_private::SymbolContext &sc,
|
||||
lldb_private::FileSpecList &support_files) override;
|
||||
|
||||
bool ParseImportedModules(
|
||||
const lldb_private::SymbolContext &sc,
|
||||
std::vector<lldb_private::ConstString> &imported_modules) override;
|
||||
|
||||
size_t ParseFunctionBlocks(const lldb_private::SymbolContext &sc) override;
|
||||
|
||||
size_t ParseTypes(const lldb_private::SymbolContext &sc) override {
|
||||
return 0;
|
||||
}
|
||||
size_t
|
||||
ParseVariablesForContext(const lldb_private::SymbolContext &sc) override {
|
||||
return 0;
|
||||
}
|
||||
lldb_private::Type *ResolveTypeUID(lldb::user_id_t type_uid) override {
|
||||
return nullptr;
|
||||
}
|
||||
bool CompleteType(lldb_private::CompilerType &compiler_type) override {
|
||||
return false;
|
||||
}
|
||||
uint32_t ResolveSymbolContext(const lldb_private::Address &so_addr,
|
||||
uint32_t resolve_scope,
|
||||
lldb_private::SymbolContext &sc) override;
|
||||
|
||||
virtual size_t GetTypes(lldb_private::SymbolContextScope *sc_scope,
|
||||
uint32_t type_mask,
|
||||
lldb_private::TypeList &type_list) override {
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
FindFunctions(const lldb_private::ConstString &name,
|
||||
const lldb_private::CompilerDeclContext *parent_decl_ctx,
|
||||
uint32_t name_type_mask, bool include_inlines, bool append,
|
||||
lldb_private::SymbolContextList &sc_list) override;
|
||||
|
||||
uint32_t FindFunctions(const lldb_private::RegularExpression ®ex,
|
||||
bool include_inlines, bool append,
|
||||
lldb_private::SymbolContextList &sc_list) override;
|
||||
|
||||
lldb_private::TypeSystem *
|
||||
GetTypeSystemForLanguage(lldb::LanguageType language) override;
|
||||
|
||||
lldb_private::CompilerDeclContext FindNamespace(
|
||||
const lldb_private::SymbolContext &sc,
|
||||
const lldb_private::ConstString &name,
|
||||
const lldb_private::CompilerDeclContext *parent_decl_ctx) override;
|
||||
|
||||
lldb_private::ConstString GetPluginName() override;
|
||||
|
||||
uint32_t GetPluginVersion() override;
|
||||
|
||||
llvm::pdb::PDBFile &GetPDBFile() { return m_index->pdb(); }
|
||||
const llvm::pdb::PDBFile &GetPDBFile() const { return m_index->pdb(); }
|
||||
|
||||
private:
|
||||
lldb::FunctionSP GetOrCreateFunction(PdbSymUid func_uid,
|
||||
const SymbolContext &sc);
|
||||
lldb::CompUnitSP GetOrCreateCompileUnit(const CompilandIndexItem &cci);
|
||||
|
||||
lldb::FunctionSP CreateFunction(PdbSymUid func_uid, const SymbolContext &sc);
|
||||
lldb::CompUnitSP CreateCompileUnit(const CompilandIndexItem &cci);
|
||||
|
||||
llvm::BumpPtrAllocator m_allocator;
|
||||
|
||||
lldb::addr_t m_obj_load_address = 0;
|
||||
|
||||
std::unique_ptr<PdbIndex> m_index;
|
||||
|
||||
llvm::DenseMap<lldb::user_id_t, lldb::FunctionSP> m_functions;
|
||||
llvm::DenseMap<lldb::user_id_t, lldb::CompUnitSP> m_compilands;
|
||||
};
|
||||
|
||||
} // namespace npdb
|
||||
} // namespace lldb_private
|
||||
|
||||
#endif // lldb_Plugins_SymbolFile_PDB_SymbolFilePDB_h_
|
@ -9,7 +9,6 @@ add_lldb_library(lldbPluginSymbolFilePDB PLUGIN
|
||||
lldbCore
|
||||
lldbSymbol
|
||||
lldbUtility
|
||||
lldbPluginSymbolFileNativePDB
|
||||
LINK_COMPONENTS
|
||||
DebugInfoPDB
|
||||
Support
|
||||
|
@ -46,7 +46,6 @@
|
||||
#include "llvm/DebugInfo/PDB/PDBSymbolTypeUDT.h"
|
||||
|
||||
#include "Plugins/Language/CPlusPlus/CPlusPlusLanguage.h" // For IsCPPMangledName
|
||||
#include "Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.h"
|
||||
#include "Plugins/SymbolFile/PDB/PDBASTParser.h"
|
||||
#include "Plugins/SymbolFile/PDB/PDBLocationToDWARFExpression.h"
|
||||
|
||||
@ -75,31 +74,14 @@ bool ShouldAddLine(uint32_t requested_line, uint32_t actual_line,
|
||||
}
|
||||
} // namespace
|
||||
|
||||
static bool ShouldUseNativeReader() {
|
||||
#if !defined(_WIN32)
|
||||
return true;
|
||||
#endif
|
||||
llvm::StringRef use_native = ::getenv("LLDB_USE_NATIVE_PDB_READER");
|
||||
return use_native.equals_lower("on") || use_native.equals_lower("yes") ||
|
||||
use_native.equals_lower("1") || use_native.equals_lower("true");
|
||||
}
|
||||
|
||||
void SymbolFilePDB::Initialize() {
|
||||
if (ShouldUseNativeReader()) {
|
||||
npdb::SymbolFileNativePDB::Initialize();
|
||||
} else {
|
||||
PluginManager::RegisterPlugin(GetPluginNameStatic(),
|
||||
GetPluginDescriptionStatic(), CreateInstance,
|
||||
DebuggerInitialize);
|
||||
}
|
||||
}
|
||||
|
||||
void SymbolFilePDB::Terminate() {
|
||||
if (ShouldUseNativeReader()) {
|
||||
npdb::SymbolFileNativePDB::Terminate();
|
||||
} else {
|
||||
PluginManager::UnregisterPlugin(CreateInstance);
|
||||
}
|
||||
}
|
||||
|
||||
void SymbolFilePDB::DebuggerInitialize(lldb_private::Debugger &debugger) {}
|
||||
|
@ -73,7 +73,6 @@
|
||||
#include "llvm/Support/Error.h"
|
||||
#include "llvm/Support/ErrorHandling.h"
|
||||
#include "llvm/Support/FormatVariadic.h"
|
||||
#include "llvm/Support/Path.h"
|
||||
#include "llvm/Support/SMLoc.h"
|
||||
#include "llvm/Support/ScopedPrinter.h"
|
||||
#include "llvm/Target/TargetLoweringObjectFile.h"
|
||||
@ -135,9 +134,7 @@ StringRef CodeViewDebug::getFullFilepath(const DIFile *File) {
|
||||
|
||||
// If this is a Unix-style path, just use it as is. Don't try to canonicalize
|
||||
// it textually because one of the path components could be a symlink.
|
||||
if (Dir.startswith("/") || Filename.startswith("/")) {
|
||||
if (llvm::sys::path::is_absolute(Filename, llvm::sys::path::Style::posix))
|
||||
return Filename;
|
||||
if (!Dir.empty() && Dir[0] == '/') {
|
||||
Filepath = Dir;
|
||||
if (Dir.back() != '/')
|
||||
Filepath += '/';
|
||||
|
Loading…
Reference in New Issue
Block a user