Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions lldb/source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1108,6 +1108,27 @@ std::optional<FileSpec> ObjectFilePECOFF::GetDebugLink() {
return std::nullopt;
}

std::optional<FileSpec> ObjectFilePECOFF::GetPDBPath() {
llvm::StringRef pdb_file;
const llvm::codeview::DebugInfo *pdb_info = nullptr;
if (llvm::Error Err = m_binary->getDebugPDBInfo(pdb_info, pdb_file)) {
// DebugInfo section is corrupt.
Log *log = GetLog(LLDBLog::Object);
llvm::StringRef file = m_binary->getFileName();
LLDB_LOG_ERROR(
log, std::move(Err),
"Failed to read Codeview record for PDB debug info file ({1}): {0}",
file);
return std::nullopt;
}
if (pdb_file.empty()) {
// No DebugInfo section present.
return std::nullopt;
}
return FileSpec(pdb_file, FileSpec::GuessPathStyle(pdb_file).value_or(
FileSpec::Style::native));
}

uint32_t ObjectFilePECOFF::ParseDependentModules() {
ModuleSP module_sp(GetModule());
if (!module_sp)
Expand Down
2 changes: 2 additions & 0 deletions lldb/source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.h
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,8 @@ class ObjectFilePECOFF : public lldb_private::ObjectFile {
/// contains it.
std::optional<lldb_private::FileSpec> GetDebugLink();

std::optional<lldb_private::FileSpec> GetPDBPath();

uint32_t GetDependentModules(lldb_private::FileSpecList &files) override;

lldb_private::Address GetEntryPointAddress() override;
Expand Down
233 changes: 213 additions & 20 deletions lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
#include "llvm/DebugInfo/PDB/Native/ModuleDebugStream.h"
#include "llvm/DebugInfo/PDB/Native/NativeSession.h"
#include "llvm/DebugInfo/PDB/Native/PDBFile.h"
#include "llvm/DebugInfo/PDB/Native/PublicsStream.h"
#include "llvm/DebugInfo/PDB/Native/SymbolStream.h"
#include "llvm/DebugInfo/PDB/Native/TpiStream.h"
#include "llvm/DebugInfo/PDB/PDB.h"
Expand Down Expand Up @@ -367,6 +368,11 @@ uint32_t SymbolFileNativePDB::CalculateAbilities() {
if (!pdb_file)
return 0;

LLDB_LOG(
GetLog(LLDBLog::Symbols), "Loading {0} for {1}",
pdb_file->getFilePath(),
m_objfile_sp->GetModule()->GetObjectFile()->GetFileSpec().GetPath());

auto expected_index = PdbIndex::create(pdb_file);
if (!expected_index) {
llvm::consumeError(expected_index.takeError());
Expand Down Expand Up @@ -1163,7 +1169,80 @@ lldb::LanguageType SymbolFileNativePDB::ParseLanguage(CompileUnit &comp_unit) {
return TranslateLanguage(item->m_compile_opts->getLanguage());
}

void SymbolFileNativePDB::AddSymbols(Symtab &symtab) {}
void SymbolFileNativePDB::AddSymbols(Symtab &symtab) {
auto *section_list =
m_objfile_sp->GetModule()->GetObjectFile()->GetSectionList();
if (!section_list)
return;

PublicSym32 last_sym;
size_t last_sym_idx = 0;
lldb::SectionSP section_sp;

// To estimate the size of a symbol, we use the difference to the next symbol.
// If there's no next symbol or the section/segment changed, the symbol will
// take the remaining space. The estimate can be too high in case there's
// padding between symbols. This similar to the algorithm used by the DIA
// SDK.
auto finish_last_symbol = [&](const PublicSym32 *next) {
if (!section_sp)
return;
Symbol *last = symtab.SymbolAtIndex(last_sym_idx);
if (!last)
return;

if (next && last_sym.Segment == next->Segment) {
assert(last_sym.Offset <= next->Offset);
last->SetByteSize(next->Offset - last_sym.Offset);
} else {
// the last symbol was the last in its section
assert(section_sp->GetByteSize() >= last_sym.Offset);
assert(!next || next->Segment > last_sym.Segment);
last->SetByteSize(section_sp->GetByteSize() - last_sym.Offset);
}
};

// The address map is sorted by the address of a symbol.
for (auto pid : m_index->publics().getAddressMap()) {
PdbGlobalSymId global{pid, true};
CVSymbol sym = m_index->ReadSymbolRecord(global);
auto kind = sym.kind();
if (kind != S_PUB32)
continue;
PublicSym32 pub =
llvm::cantFail(SymbolDeserializer::deserializeAs<PublicSym32>(sym));
finish_last_symbol(&pub);

if (!section_sp || last_sym.Segment != pub.Segment)
section_sp = section_list->FindSectionByID(pub.Segment);

if (!section_sp)
continue;

lldb::SymbolType type = eSymbolTypeData;
if ((pub.Flags & PublicSymFlags::Function) != PublicSymFlags::None ||
(pub.Flags & PublicSymFlags::Code) != PublicSymFlags::None)
type = eSymbolTypeCode;

last_sym_idx =
symtab.AddSymbol(Symbol(/*symID=*/pid,
/*name=*/pub.Name,
/*type=*/type,
/*external=*/true,
/*is_debug=*/true,
/*is_trampoline=*/false,
/*is_artificial=*/false,
/*section_sp=*/section_sp,
/*value=*/pub.Offset,
/*size=*/0,
/*size_is_valid=*/false,
/*contains_linker_annotations=*/false,
/*flags=*/0));
last_sym = pub;
}

finish_last_symbol(nullptr);
}

size_t SymbolFileNativePDB::ParseFunctions(CompileUnit &comp_unit) {
std::lock_guard<std::recursive_mutex> guard(GetModuleMutex());
Expand Down Expand Up @@ -1783,6 +1862,94 @@ void SymbolFileNativePDB::DumpClangAST(Stream &s, llvm::StringRef filter) {
ast_builder->Dump(s, filter);
}

void SymbolFileNativePDB::CacheFunctionNames() {
if (!m_func_full_names.IsEmpty())
return;

// (segment, code offset) -> gid
std::map<std::pair<uint16_t, uint32_t>, uint32_t> addr_ids;

// First, find all function references in the globals table.
for (const uint32_t gid : m_index->globals().getGlobalsTable()) {
CVSymbol ref_sym = m_index->symrecords().readRecord(gid);
auto kind = ref_sym.kind();
if (kind != S_PROCREF && kind != S_LPROCREF)
continue;

ProcRefSym ref =
llvm::cantFail(SymbolDeserializer::deserializeAs<ProcRefSym>(ref_sym));
if (ref.Name.empty())
continue;

// Find the function this is referencing.
CompilandIndexItem &cci =
m_index->compilands().GetOrCreateCompiland(ref.modi());
auto iter = cci.m_debug_stream.getSymbolArray().at(ref.SymOffset);
if (iter == cci.m_debug_stream.getSymbolArray().end())
continue;
kind = iter->kind();
if (kind != S_GPROC32 && kind != S_LPROC32)
continue;

ProcSym proc =
llvm::cantFail(SymbolDeserializer::deserializeAs<ProcSym>(*iter));
if ((proc.Flags & ProcSymFlags::IsUnreachable) != ProcSymFlags::None)
continue;
if (proc.Name.empty() || proc.FunctionType.isSimple())
continue;

// The function/procedure symbol only contains the demangled name.
// The mangled names are in the publics table. Save the address of this
// function to lookup the mangled name later.
addr_ids.emplace(std::make_pair(proc.Segment, proc.CodeOffset), gid);

llvm::StringRef basename = MSVCUndecoratedNameParser::DropScope(proc.Name);
if (basename.empty())
basename = proc.Name;

m_func_base_names.Append(ConstString(basename), gid);
m_func_full_names.Append(ConstString(proc.Name), gid);

// To see if this is a member function, check the type.
auto type = m_index->tpi().getType(proc.FunctionType);
if (type.kind() == LF_MFUNCTION) {
MemberFunctionRecord mfr;
llvm::cantFail(
TypeDeserializer::deserializeAs<MemberFunctionRecord>(type, mfr));
if (!mfr.getThisType().isNoneType())
m_func_method_names.Append(ConstString(basename), gid);
}
}

// The publics stream contains all mangled function names and their address.
for (auto pid : m_index->publics().getPublicsTable()) {
PdbGlobalSymId global{pid, true};
CVSymbol sym = m_index->ReadSymbolRecord(global);
auto kind = sym.kind();
if (kind != S_PUB32)
continue;
PublicSym32 pub =
llvm::cantFail(SymbolDeserializer::deserializeAs<PublicSym32>(sym));
// We only care about mangled names - if the name isn't mangled, it's
// already in the full name map.
if (!Mangled::IsMangledName(pub.Name))
continue;

// Check if this symbol is for one of our functions.
auto it = addr_ids.find({pub.Segment, pub.Offset});
if (it != addr_ids.end())
m_func_full_names.Append(ConstString(pub.Name), it->second);
}

// Sort them before value searching is working properly.
m_func_full_names.Sort();
m_func_full_names.SizeToFit();
m_func_method_names.Sort();
m_func_method_names.SizeToFit();
m_func_base_names.Sort();
m_func_base_names.SizeToFit();
}

void SymbolFileNativePDB::FindGlobalVariables(
ConstString name, const CompilerDeclContext &parent_decl_ctx,
uint32_t max_matches, VariableList &variables) {
Expand Down Expand Up @@ -1819,34 +1986,60 @@ void SymbolFileNativePDB::FindFunctions(
if (name_type_mask & eFunctionNameTypeFull)
name = lookup_info.GetName();

// For now we only support lookup by method name or full name.
if (!(name_type_mask & eFunctionNameTypeFull ||
name_type_mask & eFunctionNameTypeBase ||
name_type_mask & eFunctionNameTypeMethod))
return;
CacheFunctionNames();

using SymbolAndOffset = std::pair<uint32_t, llvm::codeview::CVSymbol>;
std::set<uint32_t> resolved_ids; // avoid duplicate lookups
auto resolve_from = [&](UniqueCStringMap<uint32_t> &Names) {
std::vector<uint32_t> ids;
if (!Names.GetValues(name, ids))
return;

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));
for (uint32_t id : ids) {
if (!resolved_ids.insert(id).second)
continue;

if (!IsValidRecord(proc))
continue;
PdbGlobalSymId global{id, false};
if (parent_decl_ctx.IsValid() &&
GetDeclContextContainingUID(toOpaqueUid(global)) != parent_decl_ctx)
continue;

CompilandIndexItem &cci =
m_index->compilands().GetOrCreateCompiland(proc.modi());
SymbolContext sc;
CVSymbol sym = m_index->ReadSymbolRecord(global);
auto kind = sym.kind();
lldbassert(kind == S_PROCREF || kind == S_LPROCREF);

sc.comp_unit = GetOrCreateCompileUnit(cci).get();
PdbCompilandSymId func_id(proc.modi(), proc.SymOffset);
sc.function = GetOrCreateFunction(func_id, *sc.comp_unit).get();
ProcRefSym proc =
cantFail(SymbolDeserializer::deserializeAs<ProcRefSym>(sym));

sc_list.Append(sc);
}
if (!IsValidRecord(proc))
continue;

CompilandIndexItem &cci =
m_index->compilands().GetOrCreateCompiland(proc.modi());
SymbolContext sc;

sc.comp_unit = GetOrCreateCompileUnit(cci).get();
if (!sc.comp_unit)
continue;

PdbCompilandSymId func_id(proc.modi(), proc.SymOffset);
sc.function = GetOrCreateFunction(func_id, *sc.comp_unit).get();
if (!sc.function)
continue;

sc_list.Append(sc);
}
};

if (name_type_mask & eFunctionNameTypeFull)
resolve_from(m_func_full_names);
if (name_type_mask & eFunctionNameTypeBase)
resolve_from(m_func_base_names);
if (name_type_mask & eFunctionNameTypeMethod)
resolve_from(m_func_method_names);
}

void SymbolFileNativePDB::FindFunctions(const RegularExpression &regex,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -259,6 +259,8 @@ class SymbolFileNativePDB : public SymbolFileCommon {
fn);

void ParseInlineSite(PdbCompilandSymId inline_site_id, Address func_addr);

void CacheFunctionNames();

llvm::BumpPtrAllocator m_allocator;

Expand All @@ -280,6 +282,13 @@ class SymbolFileNativePDB : public SymbolFileCommon {
llvm::DenseMap<lldb::user_id_t, std::shared_ptr<InlineSite>> m_inline_sites;
llvm::DenseMap<llvm::codeview::TypeIndex, llvm::codeview::TypeIndex>
m_parent_types;

/// mangled name/full function name -> Global ID(s)
lldb_private::UniqueCStringMap<uint32_t> m_func_full_names;
/// basename -> Global ID(s)
lldb_private::UniqueCStringMap<uint32_t> m_func_base_names;
/// method basename -> Global ID(s)
lldb_private::UniqueCStringMap<uint32_t> m_func_method_names;
};

} // namespace npdb
Expand Down
16 changes: 12 additions & 4 deletions lldb/source/Plugins/SymbolFile/PDB/SymbolFilePDB.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,8 @@ uint32_t SymbolFilePDB::CalculateAbilities() {

if (!m_session_up) {
// Lazily load and match the PDB file, but only do this once.
std::string exePath = m_objfile_sp->GetFileSpec().GetPath();
std::string exePath =
m_objfile_sp->GetModule()->GetObjectFile()->GetFileSpec().GetPath();
auto error = loadDataForEXE(PDB_ReaderType::DIA, llvm::StringRef(exePath),
m_session_up);
if (error) {
Expand All @@ -163,6 +164,10 @@ uint32_t SymbolFilePDB::CalculateAbilities() {
return 0;
// See if any symbol file is specified through `--symfile` option.
FileSpec symfile = module_sp->GetSymbolFileFileSpec();
// If m_objfile_sp is a supplemental ObjectFilePDB (e.g. located via
// SymStore by SymbolVendorPECOFF), its file spec is the PDB path.
if (!symfile && m_objfile_sp.get() != module_sp->GetObjectFile())
symfile = m_objfile_sp->GetFileSpec();
if (!symfile)
return 0;
error = loadDataForPDB(PDB_ReaderType::DIA,
Expand Down Expand Up @@ -201,8 +206,10 @@ uint32_t SymbolFilePDB::CalculateAbilities() {
}

void SymbolFilePDB::InitializeObject() {
lldb::addr_t obj_load_address =
m_objfile_sp->GetBaseAddress().GetFileAddress();
lldb::addr_t obj_load_address = m_objfile_sp->GetModule()
->GetObjectFile()
->GetBaseAddress()
.GetFileAddress();
lldbassert(obj_load_address && obj_load_address != LLDB_INVALID_ADDRESS);
m_session_up->setLoadAddress(obj_load_address);
if (!m_global_scope_up)
Expand Down Expand Up @@ -1392,7 +1399,8 @@ void SymbolFilePDB::AddSymbols(lldb_private::Symtab &symtab) {
if (!results)
return;

auto section_list = m_objfile_sp->GetSectionList();
auto section_list =
m_objfile_sp->GetModule()->GetObjectFile()->GetSectionList();
if (!section_list)
return;

Expand Down
1 change: 1 addition & 0 deletions lldb/source/Plugins/SymbolLocator/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ set_property(DIRECTORY PROPERTY LLDB_PLUGIN_KIND SymbolLocator)
# prevents an unstripped binary from being requested from the Debuginfod
# provider.
add_subdirectory(Debuginfod)
add_subdirectory(SymStore)
add_subdirectory(Default)
if (CMAKE_SYSTEM_NAME MATCHES "Darwin")
add_subdirectory(DebugSymbols)
Expand Down
Loading