[Lldb-commits] [lldb] r344154 - Create a SymbolFile plugin for cross-platform PDB access.
Zachary Turner via lldb-commits
lldb-commits at lists.llvm.org
Wed Oct 10 09:39:08 PDT 2018
Author: zturner
Date: Wed Oct 10 09:39:07 2018
New Revision: 344154
URL: http://llvm.org/viewvc/llvm-project?rev=344154&view=rev
Log:
Create a SymbolFile plugin for cross-platform PDB access.
The existing SymbolFilePDB only works on Windows, as it is written
against a closed-source Microsoft SDK that ships with their debugging
tools.
There are several reasons we want to bypass this and go straight to the
bits of the PDB, but just to list a few:
More room for optimization. We can't see inside the implementation of
the Microsoft SDK, so we don't always know if we're doing things in the
most efficient way possible. For example, setting a breakpoint on main
of a big program currently takes several seconds. With the
implementation here, the time is unnoticeable.
We want to be able to symbolize Windows minidumps even if not on
Windows. Someone should be able to debug Windows minidumps as if they
were on Windows, given that no running process is necessary.
This patch is a very crude first attempt at filling out some of the
basic pieces.
I've implemented FindFunctions, ParseCompileUnitLineTable, and
ResolveSymbolContext for a limited subset of possible parameter values,
which is just enough to get it to display something nice for the
breakpoint location.
I've added several tests exercising this functionality which are limited
enough to work on all platforms but still exercise this functionality.
I'll try to add as many tests of this nature as I can, but at some
point we'll need a live process.
For now, this plugin is enabled always on non-Windows, and by setting
the environment variable LLDB_USE_NATIVE_PDB_READER=1 on Windows.
Eventually, once it's at parity with the Windows implementation, we'll
delete the Windows DIA-based implementation.
Differential Revision: https://reviews.llvm.org/D53002
Added:
lldb/trunk/lit/SymbolFile/NativePDB/
lldb/trunk/lit/SymbolFile/NativePDB/Inputs/
lldb/trunk/lit/SymbolFile/NativePDB/Inputs/breakpoints.lldbinit
lldb/trunk/lit/SymbolFile/NativePDB/Inputs/disassembly.lldbinit
lldb/trunk/lit/SymbolFile/NativePDB/Inputs/source-list.lldbinit
lldb/trunk/lit/SymbolFile/NativePDB/disassembly.cpp
lldb/trunk/lit/SymbolFile/NativePDB/lit.local.cfg
lldb/trunk/lit/SymbolFile/NativePDB/simple-breakpoints.cpp
lldb/trunk/lit/SymbolFile/NativePDB/source-list.cpp
lldb/trunk/source/Plugins/SymbolFile/NativePDB/
lldb/trunk/source/Plugins/SymbolFile/NativePDB/CMakeLists.txt
lldb/trunk/source/Plugins/SymbolFile/NativePDB/CompileUnitIndex.cpp
lldb/trunk/source/Plugins/SymbolFile/NativePDB/CompileUnitIndex.h
lldb/trunk/source/Plugins/SymbolFile/NativePDB/PdbIndex.cpp
lldb/trunk/source/Plugins/SymbolFile/NativePDB/PdbIndex.h
lldb/trunk/source/Plugins/SymbolFile/NativePDB/PdbSymUid.h
lldb/trunk/source/Plugins/SymbolFile/NativePDB/PdbUtil.cpp
lldb/trunk/source/Plugins/SymbolFile/NativePDB/PdbUtil.h
lldb/trunk/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp
lldb/trunk/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.h
Modified:
lldb/trunk/include/lldb/Utility/LLDBAssert.h
lldb/trunk/lit/lit.cfg
lldb/trunk/source/Plugins/SymbolFile/CMakeLists.txt
lldb/trunk/source/Plugins/SymbolFile/PDB/CMakeLists.txt
lldb/trunk/source/Plugins/SymbolFile/PDB/SymbolFilePDB.cpp
Modified: lldb/trunk/include/lldb/Utility/LLDBAssert.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Utility/LLDBAssert.h?rev=344154&r1=344153&r2=344154&view=diff
==============================================================================
--- lldb/trunk/include/lldb/Utility/LLDBAssert.h (original)
+++ lldb/trunk/include/lldb/Utility/LLDBAssert.h Wed Oct 10 09:39:07 2018
@@ -14,7 +14,8 @@
#define lldbassert(x) assert(x)
#else
#define lldbassert(x) \
- lldb_private::lldb_assert(x, #x, __FUNCTION__, __FILE__, __LINE__)
+ lldb_private::lldb_assert(static_cast<bool>(x), #x, __FUNCTION__, __FILE__, \
+ __LINE__)
#endif
namespace lldb_private {
Added: lldb/trunk/lit/SymbolFile/NativePDB/Inputs/breakpoints.lldbinit
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/lit/SymbolFile/NativePDB/Inputs/breakpoints.lldbinit?rev=344154&view=auto
==============================================================================
--- lldb/trunk/lit/SymbolFile/NativePDB/Inputs/breakpoints.lldbinit (added)
+++ lldb/trunk/lit/SymbolFile/NativePDB/Inputs/breakpoints.lldbinit Wed Oct 10 09:39:07 2018
@@ -0,0 +1,6 @@
+break set -n main
+break set -n OvlGlobalFn
+break set -n StaticFn
+break set -n DoesntExist
+break list
+quit
Added: lldb/trunk/lit/SymbolFile/NativePDB/Inputs/disassembly.lldbinit
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/lit/SymbolFile/NativePDB/Inputs/disassembly.lldbinit?rev=344154&view=auto
==============================================================================
--- lldb/trunk/lit/SymbolFile/NativePDB/Inputs/disassembly.lldbinit (added)
+++ lldb/trunk/lit/SymbolFile/NativePDB/Inputs/disassembly.lldbinit Wed Oct 10 09:39:07 2018
@@ -0,0 +1,2 @@
+disassemble --flavor=intel -m -n main
+quit
Added: lldb/trunk/lit/SymbolFile/NativePDB/Inputs/source-list.lldbinit
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/lit/SymbolFile/NativePDB/Inputs/source-list.lldbinit?rev=344154&view=auto
==============================================================================
--- lldb/trunk/lit/SymbolFile/NativePDB/Inputs/source-list.lldbinit (added)
+++ lldb/trunk/lit/SymbolFile/NativePDB/Inputs/source-list.lldbinit Wed Oct 10 09:39:07 2018
@@ -0,0 +1,3 @@
+source list -n main
+source list -n OvlGlobalFn
+quit
Added: lldb/trunk/lit/SymbolFile/NativePDB/disassembly.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/lit/SymbolFile/NativePDB/disassembly.cpp?rev=344154&view=auto
==============================================================================
--- lldb/trunk/lit/SymbolFile/NativePDB/disassembly.cpp (added)
+++ lldb/trunk/lit/SymbolFile/NativePDB/disassembly.cpp Wed Oct 10 09:39:07 2018
@@ -0,0 +1,38 @@
+// 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
Added: lldb/trunk/lit/SymbolFile/NativePDB/lit.local.cfg
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/lit/SymbolFile/NativePDB/lit.local.cfg?rev=344154&view=auto
==============================================================================
--- lldb/trunk/lit/SymbolFile/NativePDB/lit.local.cfg (added)
+++ lldb/trunk/lit/SymbolFile/NativePDB/lit.local.cfg Wed Oct 10 09:39:07 2018
@@ -0,0 +1 @@
+config.suffixes = ['.test', '.cpp']
Added: lldb/trunk/lit/SymbolFile/NativePDB/simple-breakpoints.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/lit/SymbolFile/NativePDB/simple-breakpoints.cpp?rev=344154&view=auto
==============================================================================
--- lldb/trunk/lit/SymbolFile/NativePDB/simple-breakpoints.cpp (added)
+++ lldb/trunk/lit/SymbolFile/NativePDB/simple-breakpoints.cpp Wed Oct 10 09:39:07 2018
@@ -0,0 +1,63 @@
+// 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)
Added: lldb/trunk/lit/SymbolFile/NativePDB/source-list.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/lit/SymbolFile/NativePDB/source-list.cpp?rev=344154&view=auto
==============================================================================
--- lldb/trunk/lit/SymbolFile/NativePDB/source-list.cpp (added)
+++ lldb/trunk/lit/SymbolFile/NativePDB/source-list.cpp Wed Oct 10 09:39:07 2018
@@ -0,0 +1,42 @@
+// 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: D:\src\llvm-mono\lldb\lit\SymbolFile\NativePDB\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
Modified: lldb/trunk/lit/lit.cfg
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/lit/lit.cfg?rev=344154&r1=344153&r2=344154&view=diff
==============================================================================
--- lldb/trunk/lit/lit.cfg (original)
+++ lldb/trunk/lit/lit.cfg Wed Oct 10 09:39:07 2018
@@ -64,6 +64,8 @@ lldb = "%s -S %s/lit-lldb-init" % (lit.u
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'])
@@ -90,7 +92,8 @@ if platform.system() in ['OpenBSD']:
config.substitutions.append(('%cc', config.cc))
config.substitutions.append(('%cxx', config.cxx))
-config.substitutions.append(('%lldbmi', lldbmi + " --synchronous"))
+if lldbmi:
+ config.substitutions.append(('%lldbmi', lldbmi + " --synchronous"))
config.substitutions.append(('%lldb', lldb))
if debugserver is not None:
Modified: lldb/trunk/source/Plugins/SymbolFile/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/SymbolFile/CMakeLists.txt?rev=344154&r1=344153&r2=344154&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/SymbolFile/CMakeLists.txt (original)
+++ lldb/trunk/source/Plugins/SymbolFile/CMakeLists.txt Wed Oct 10 09:39:07 2018
@@ -1,3 +1,4 @@
add_subdirectory(DWARF)
add_subdirectory(Symtab)
+add_subdirectory(NativePDB)
add_subdirectory(PDB)
Added: lldb/trunk/source/Plugins/SymbolFile/NativePDB/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/SymbolFile/NativePDB/CMakeLists.txt?rev=344154&view=auto
==============================================================================
--- lldb/trunk/source/Plugins/SymbolFile/NativePDB/CMakeLists.txt (added)
+++ lldb/trunk/source/Plugins/SymbolFile/NativePDB/CMakeLists.txt Wed Oct 10 09:39:07 2018
@@ -0,0 +1,16 @@
+add_lldb_library(lldbPluginSymbolFileNativePDB PLUGIN
+ CompileUnitIndex.cpp
+ PdbIndex.cpp
+ PdbUtil.cpp
+ SymbolFileNativePDB.cpp
+
+ LINK_LIBS
+ clangAST
+ clangLex
+ lldbCore
+ lldbSymbol
+ lldbUtility
+ LINK_COMPONENTS
+ DebugInfoPDB
+ Support
+ )
Added: lldb/trunk/source/Plugins/SymbolFile/NativePDB/CompileUnitIndex.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/SymbolFile/NativePDB/CompileUnitIndex.cpp?rev=344154&view=auto
==============================================================================
--- lldb/trunk/source/Plugins/SymbolFile/NativePDB/CompileUnitIndex.cpp (added)
+++ lldb/trunk/source/Plugins/SymbolFile/NativePDB/CompileUnitIndex.cpp Wed Oct 10 09:39:07 2018
@@ -0,0 +1,229 @@
+//===-- 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;
+
+ // FIXME: If we ever want to support PDB debug info for non-Windows systems
+ // the following check will be wrong, but we need a way to store the host
+ // information in the PDB.
+ llvm::SmallString<64> normalized(other);
+ llvm::sys::path::native(normalized, llvm::sys::path::Style::windows);
+ 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);
+ llvm::sys::path::native(main_file, llvm::sys::path::Style::windows);
+
+ 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;
+}
Added: lldb/trunk/source/Plugins/SymbolFile/NativePDB/CompileUnitIndex.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/SymbolFile/NativePDB/CompileUnitIndex.h?rev=344154&view=auto
==============================================================================
--- lldb/trunk/source/Plugins/SymbolFile/NativePDB/CompileUnitIndex.h (added)
+++ lldb/trunk/source/Plugins/SymbolFile/NativePDB/CompileUnitIndex.h Wed Oct 10 09:39:07 2018
@@ -0,0 +1,99 @@
+//===-- 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
Added: lldb/trunk/source/Plugins/SymbolFile/NativePDB/PdbIndex.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/SymbolFile/NativePDB/PdbIndex.cpp?rev=344154&view=auto
==============================================================================
--- lldb/trunk/source/Plugins/SymbolFile/NativePDB/PdbIndex.cpp (added)
+++ lldb/trunk/source/Plugins/SymbolFile/NativePDB/PdbIndex.cpp Wed Oct 10 09:39:07 2018
@@ -0,0 +1,202 @@
+//===-- 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 emplace_result = cci.m_symbols_by_va.try_emplace(va, cu_sym_uid);
+ (void)emplace_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(emplace_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;
+}
Added: lldb/trunk/source/Plugins/SymbolFile/NativePDB/PdbIndex.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/SymbolFile/NativePDB/PdbIndex.h?rev=344154&view=auto
==============================================================================
--- lldb/trunk/source/Plugins/SymbolFile/NativePDB/PdbIndex.h (added)
+++ lldb/trunk/source/Plugins/SymbolFile/NativePDB/PdbIndex.h Wed Oct 10 09:39:07 2018
@@ -0,0 +1,161 @@
+//===-- 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
Added: lldb/trunk/source/Plugins/SymbolFile/NativePDB/PdbSymUid.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/SymbolFile/NativePDB/PdbSymUid.h?rev=344154&view=auto
==============================================================================
--- lldb/trunk/source/Plugins/SymbolFile/NativePDB/PdbSymUid.h (added)
+++ lldb/trunk/source/Plugins/SymbolFile/NativePDB/PdbSymUid.h Wed Oct 10 09:39:07 2018
@@ -0,0 +1,202 @@
+//===-- 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
Added: lldb/trunk/source/Plugins/SymbolFile/NativePDB/PdbUtil.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/SymbolFile/NativePDB/PdbUtil.cpp?rev=344154&view=auto
==============================================================================
--- lldb/trunk/source/Plugins/SymbolFile/NativePDB/PdbUtil.cpp (added)
+++ lldb/trunk/source/Plugins/SymbolFile/NativePDB/PdbUtil.cpp Wed Oct 10 09:39:07 2018
@@ -0,0 +1,258 @@
+//===-- 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 {record.Segment, record.Offset, record.Length};
+}
+
+template <>
+SegmentOffsetLength
+GetSegmentOffsetAndLength<CoffGroupSym>(const CVSymbol &sym) {
+ CoffGroupSym record = createRecord<CoffGroupSym>(sym);
+ return {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};
+}
Added: lldb/trunk/source/Plugins/SymbolFile/NativePDB/PdbUtil.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/SymbolFile/NativePDB/PdbUtil.h?rev=344154&view=auto
==============================================================================
--- lldb/trunk/source/Plugins/SymbolFile/NativePDB/PdbUtil.h (added)
+++ lldb/trunk/source/Plugins/SymbolFile/NativePDB/PdbUtil.h Wed Oct 10 09:39:07 2018
@@ -0,0 +1,53 @@
+//===-- 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 {
+ uint16_t segment = 0;
+ uint32_t offset = 0;
+};
+
+struct SegmentOffsetLength {
+ 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
Added: lldb/trunk/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp?rev=344154&view=auto
==============================================================================
--- lldb/trunk/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp (added)
+++ lldb/trunk/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp Wed Oct 10 09:39:07 2018
@@ -0,0 +1,619 @@
+//===-- 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 std::move(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 std::move(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.
+ llvm::StringRef file_name = *efn;
+ 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 spec(f, false, FileSpec::Style::windows);
+ 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; }
Added: lldb/trunk/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.h?rev=344154&view=auto
==============================================================================
--- lldb/trunk/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.h (added)
+++ lldb/trunk/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.h Wed Oct 10 09:39:07 2018
@@ -0,0 +1,181 @@
+//===-- 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_
Modified: lldb/trunk/source/Plugins/SymbolFile/PDB/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/SymbolFile/PDB/CMakeLists.txt?rev=344154&r1=344153&r2=344154&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/SymbolFile/PDB/CMakeLists.txt (original)
+++ lldb/trunk/source/Plugins/SymbolFile/PDB/CMakeLists.txt Wed Oct 10 09:39:07 2018
@@ -9,6 +9,7 @@ add_lldb_library(lldbPluginSymbolFilePDB
lldbCore
lldbSymbol
lldbUtility
+ lldbPluginSymbolFileNativePDB
LINK_COMPONENTS
DebugInfoPDB
Support
Modified: lldb/trunk/source/Plugins/SymbolFile/PDB/SymbolFilePDB.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/SymbolFile/PDB/SymbolFilePDB.cpp?rev=344154&r1=344153&r2=344154&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/SymbolFile/PDB/SymbolFilePDB.cpp (original)
+++ lldb/trunk/source/Plugins/SymbolFile/PDB/SymbolFilePDB.cpp Wed Oct 10 09:39:07 2018
@@ -46,6 +46,7 @@
#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"
@@ -74,14 +75,31 @@ bool ShouldAddLine(uint32_t requested_li
}
} // 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() {
- PluginManager::RegisterPlugin(GetPluginNameStatic(),
- GetPluginDescriptionStatic(), CreateInstance,
- DebuggerInitialize);
+ if (ShouldUseNativeReader()) {
+ npdb::SymbolFileNativePDB::Initialize();
+ } else {
+ PluginManager::RegisterPlugin(GetPluginNameStatic(),
+ GetPluginDescriptionStatic(), CreateInstance,
+ DebuggerInitialize);
+ }
}
void SymbolFilePDB::Terminate() {
- PluginManager::UnregisterPlugin(CreateInstance);
+ if (ShouldUseNativeReader()) {
+ npdb::SymbolFileNativePDB::Terminate();
+ } else {
+ PluginManager::UnregisterPlugin(CreateInstance);
+ }
}
void SymbolFilePDB::DebuggerInitialize(lldb_private::Debugger &debugger) {}
More information about the lldb-commits
mailing list