229 changes: 229 additions & 0 deletions lldb/source/Plugins/SymbolFile/NativePDB/CompileUnitIndex.cpp
Original file line number Diff line number Diff line change
@@ -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;
}
99 changes: 99 additions & 0 deletions lldb/source/Plugins/SymbolFile/NativePDB/CompileUnitIndex.h
Original file line number Diff line number Diff line change
@@ -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
202 changes: 202 additions & 0 deletions lldb/source/Plugins/SymbolFile/NativePDB/PdbIndex.cpp
Original file line number Diff line number Diff line change
@@ -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;
}
161 changes: 161 additions & 0 deletions lldb/source/Plugins/SymbolFile/NativePDB/PdbIndex.h
Original file line number Diff line number Diff line change
@@ -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
202 changes: 202 additions & 0 deletions lldb/source/Plugins/SymbolFile/NativePDB/PdbSymUid.h
Original file line number Diff line number Diff line change
@@ -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
258 changes: 258 additions & 0 deletions lldb/source/Plugins/SymbolFile/NativePDB/PdbUtil.cpp
Original file line number Diff line number Diff line change
@@ -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};
}
53 changes: 53 additions & 0 deletions lldb/source/Plugins/SymbolFile/NativePDB/PdbUtil.h
Original file line number Diff line number Diff line change
@@ -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
619 changes: 619 additions & 0 deletions lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp

Large diffs are not rendered by default.

181 changes: 181 additions & 0 deletions lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.h
Original file line number Diff line number Diff line change
@@ -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 &regex,
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_
1 change: 1 addition & 0 deletions lldb/source/Plugins/SymbolFile/PDB/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ add_lldb_library(lldbPluginSymbolFilePDB PLUGIN
lldbCore
lldbSymbol
lldbUtility
lldbPluginSymbolFileNativePDB
LINK_COMPONENTS
DebugInfoPDB
Support
Expand Down
26 changes: 22 additions & 4 deletions lldb/source/Plugins/SymbolFile/PDB/SymbolFilePDB.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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"

Expand Down Expand Up @@ -74,14 +75,31 @@ 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() {
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) {}
Expand Down