Path: blob/main/contrib/llvm-project/lldb/source/Plugins/SymbolFile/NativePDB/PdbIndex.cpp
39644 views
//===-- PdbIndex.cpp ------------------------------------------------------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//78#include "PdbIndex.h"9#include "PdbUtil.h"1011#include "llvm/DebugInfo/CodeView/SymbolDeserializer.h"12#include "llvm/DebugInfo/PDB/Native/DbiStream.h"13#include "llvm/DebugInfo/PDB/Native/GlobalsStream.h"14#include "llvm/DebugInfo/PDB/Native/ISectionContribVisitor.h"15#include "llvm/DebugInfo/PDB/Native/PDBFile.h"16#include "llvm/DebugInfo/PDB/Native/PublicsStream.h"17#include "llvm/DebugInfo/PDB/Native/SymbolStream.h"18#include "llvm/DebugInfo/PDB/Native/TpiStream.h"19#include "llvm/Object/COFF.h"20#include "llvm/Support/Error.h"2122#include "lldb/Utility/LLDBAssert.h"23#include "lldb/lldb-defines.h"24#include <optional>2526using namespace lldb_private;27using namespace lldb_private::npdb;28using namespace llvm::codeview;29using namespace llvm::pdb;3031PdbIndex::PdbIndex() : m_cus(*this), m_va_to_modi(m_allocator) {}3233#define ASSIGN_PTR_OR_RETURN(result_ptr, expr) \34{ \35auto expected_result = expr; \36if (!expected_result) \37return expected_result.takeError(); \38result_ptr = &expected_result.get(); \39}4041llvm::Expected<std::unique_ptr<PdbIndex>>42PdbIndex::create(llvm::pdb::PDBFile *file) {43lldbassert(file);4445std::unique_ptr<PdbIndex> result(new PdbIndex());46ASSIGN_PTR_OR_RETURN(result->m_dbi, file->getPDBDbiStream());47ASSIGN_PTR_OR_RETURN(result->m_tpi, file->getPDBTpiStream());48ASSIGN_PTR_OR_RETURN(result->m_ipi, file->getPDBIpiStream());49ASSIGN_PTR_OR_RETURN(result->m_info, file->getPDBInfoStream());50ASSIGN_PTR_OR_RETURN(result->m_publics, file->getPDBPublicsStream());51ASSIGN_PTR_OR_RETURN(result->m_globals, file->getPDBGlobalsStream());52ASSIGN_PTR_OR_RETURN(result->m_symrecords, file->getPDBSymbolStream());5354result->m_tpi->buildHashMap();5556result->m_file = file;5758return std::move(result);59}6061lldb::addr_t PdbIndex::MakeVirtualAddress(uint16_t segment,62uint32_t offset) const {63uint32_t max_section = dbi().getSectionHeaders().size();64// Segment indices are 1-based.65// If this is an absolute symbol, it's indicated by the magic section index66// |max_section+1|. In this case, the offset is meaningless, so just return.67if (segment == 0 || segment > max_section)68return LLDB_INVALID_ADDRESS;6970const llvm::object::coff_section &cs = dbi().getSectionHeaders()[segment - 1];71return m_load_address + static_cast<lldb::addr_t>(cs.VirtualAddress) +72static_cast<lldb::addr_t>(offset);73}7475std::optional<uint16_t> PdbIndex::GetModuleIndexForAddr(uint16_t segment,76uint32_t offset) const {77return GetModuleIndexForVa(MakeVirtualAddress(segment, offset));78}7980std::optional<uint16_t> PdbIndex::GetModuleIndexForVa(lldb::addr_t va) const {81auto iter = m_va_to_modi.find(va);82if (iter == m_va_to_modi.end())83return std::nullopt;8485return iter.value();86}8788void PdbIndex::ParseSectionContribs() {89class Visitor : public ISectionContribVisitor {90PdbIndex &m_ctx;91llvm::IntervalMap<uint64_t, uint16_t> &m_imap;9293public:94Visitor(PdbIndex &ctx, llvm::IntervalMap<uint64_t, uint16_t> &imap)95: m_ctx(ctx), m_imap(imap) {}9697void visit(const SectionContrib &C) override {98if (C.Size == 0)99return;100101uint64_t va = m_ctx.MakeVirtualAddress(C.ISect, C.Off);102if (va == LLDB_INVALID_ADDRESS)103return;104uint64_t end = va + C.Size;105// IntervalMap's start and end represent a closed range, not a half-open106// range, so we have to subtract 1.107m_imap.insert(va, end - 1, C.Imod);108}109void visit(const SectionContrib2 &C) override { visit(C.Base); }110};111Visitor v(*this, m_va_to_modi);112dbi().visitSectionContributions(v);113}114115void PdbIndex::BuildAddrToSymbolMap(CompilandIndexItem &cci) {116lldbassert(cci.m_symbols_by_va.empty() &&117"Addr to symbol map is already built!");118uint16_t modi = cci.m_id.modi;119const CVSymbolArray &syms = cci.m_debug_stream.getSymbolArray();120for (auto iter = syms.begin(); iter != syms.end(); ++iter) {121if (!SymbolHasAddress(*iter))122continue;123124SegmentOffset so = GetSegmentAndOffset(*iter);125lldb::addr_t va = MakeVirtualAddress(so.segment, so.offset);126if (va == LLDB_INVALID_ADDRESS)127continue;128129PdbCompilandSymId cu_sym_id(modi, iter.offset());130131// It's rare, but we could have multiple symbols with the same address132// because of identical comdat folding. Right now, the first one will win.133cci.m_symbols_by_va.insert(std::make_pair(va, PdbSymUid(cu_sym_id)));134}135}136137std::vector<SymbolAndUid> PdbIndex::FindSymbolsByVa(lldb::addr_t va) {138std::vector<SymbolAndUid> result;139140std::optional<uint16_t> modi = GetModuleIndexForVa(va);141if (!modi)142return result;143144CompilandIndexItem &cci = compilands().GetOrCreateCompiland(*modi);145if (cci.m_symbols_by_va.empty())146BuildAddrToSymbolMap(cci);147148// The map is sorted by starting address of the symbol. So for example149// we could (in theory) have this situation150//151// [------------------]152// [----------]153// [-----------]154// [-------------]155// [----]156// [-----]157// ^ Address we're searching for158// In order to find this, we use the upper_bound of the key value which would159// be the first symbol whose starting address is higher than the element we're160// searching for.161162auto ub = cci.m_symbols_by_va.upper_bound(va);163164for (auto iter = cci.m_symbols_by_va.begin(); iter != ub; ++iter) {165PdbCompilandSymId cu_sym_id = iter->second.asCompilandSym();166CVSymbol sym = ReadSymbolRecord(cu_sym_id);167168SegmentOffsetLength sol;169if (SymbolIsCode(sym))170sol = GetSegmentOffsetAndLength(sym);171else172sol.so = GetSegmentAndOffset(sym);173174lldb::addr_t start = MakeVirtualAddress(sol.so.segment, sol.so.offset);175if (start == LLDB_INVALID_ADDRESS)176continue;177178lldb::addr_t end = start + sol.length;179if (va >= start && va < end)180result.push_back({std::move(sym), iter->second});181}182183return result;184}185186CVSymbol PdbIndex::ReadSymbolRecord(PdbCompilandSymId cu_sym) const {187const CompilandIndexItem *cci = compilands().GetCompiland(cu_sym.modi);188auto iter = cci->m_debug_stream.getSymbolArray().at(cu_sym.offset);189lldbassert(iter != cci->m_debug_stream.getSymbolArray().end());190return *iter;191}192193CVSymbol PdbIndex::ReadSymbolRecord(PdbGlobalSymId global) const {194return symrecords().readRecord(global.offset);195}196197198