1343181Sdim//===-- PdbIndex.cpp --------------------------------------------*- C++ -*-===// 2343181Sdim// 3353358Sdim// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4353358Sdim// See https://llvm.org/LICENSE.txt for license information. 5353358Sdim// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6343181Sdim// 7343181Sdim//===----------------------------------------------------------------------===// 8343181Sdim 9343181Sdim#include "PdbIndex.h" 10343181Sdim#include "PdbUtil.h" 11343181Sdim 12343181Sdim#include "llvm/DebugInfo/CodeView/SymbolDeserializer.h" 13343181Sdim#include "llvm/DebugInfo/PDB/Native/DbiStream.h" 14343181Sdim#include "llvm/DebugInfo/PDB/Native/GlobalsStream.h" 15343181Sdim#include "llvm/DebugInfo/PDB/Native/ISectionContribVisitor.h" 16343181Sdim#include "llvm/DebugInfo/PDB/Native/PDBFile.h" 17343181Sdim#include "llvm/DebugInfo/PDB/Native/PublicsStream.h" 18343181Sdim#include "llvm/DebugInfo/PDB/Native/SymbolStream.h" 19343181Sdim#include "llvm/DebugInfo/PDB/Native/TpiStream.h" 20343181Sdim#include "llvm/Object/COFF.h" 21343181Sdim#include "llvm/Support/Error.h" 22343181Sdim 23343181Sdim#include "lldb/Utility/LLDBAssert.h" 24343181Sdim#include "lldb/lldb-defines.h" 25343181Sdim 26343181Sdimusing namespace lldb_private; 27343181Sdimusing namespace lldb_private::npdb; 28343181Sdimusing namespace llvm::codeview; 29343181Sdimusing namespace llvm::pdb; 30343181Sdim 31343181SdimPdbIndex::PdbIndex() : m_cus(*this), m_va_to_modi(m_allocator) {} 32343181Sdim 33343181Sdim#define ASSIGN_PTR_OR_RETURN(result_ptr, expr) \ 34343181Sdim { \ 35343181Sdim auto expected_result = expr; \ 36343181Sdim if (!expected_result) \ 37343181Sdim return expected_result.takeError(); \ 38343181Sdim result_ptr = &expected_result.get(); \ 39343181Sdim } 40343181Sdim 41343181Sdimllvm::Expected<std::unique_ptr<PdbIndex>> 42343181SdimPdbIndex::create(std::unique_ptr<llvm::pdb::PDBFile> file) { 43343181Sdim lldbassert(file); 44343181Sdim 45343181Sdim std::unique_ptr<PdbIndex> result(new PdbIndex()); 46343181Sdim ASSIGN_PTR_OR_RETURN(result->m_dbi, file->getPDBDbiStream()); 47343181Sdim ASSIGN_PTR_OR_RETURN(result->m_tpi, file->getPDBTpiStream()); 48343181Sdim ASSIGN_PTR_OR_RETURN(result->m_ipi, file->getPDBIpiStream()); 49343181Sdim ASSIGN_PTR_OR_RETURN(result->m_info, file->getPDBInfoStream()); 50343181Sdim ASSIGN_PTR_OR_RETURN(result->m_publics, file->getPDBPublicsStream()); 51343181Sdim ASSIGN_PTR_OR_RETURN(result->m_globals, file->getPDBGlobalsStream()); 52343181Sdim ASSIGN_PTR_OR_RETURN(result->m_symrecords, file->getPDBSymbolStream()); 53343181Sdim 54343181Sdim result->m_tpi->buildHashMap(); 55343181Sdim 56343181Sdim result->m_file = std::move(file); 57343181Sdim 58343181Sdim return std::move(result); 59343181Sdim} 60343181Sdim 61343181Sdimlldb::addr_t PdbIndex::MakeVirtualAddress(uint16_t segment, 62343181Sdim uint32_t offset) const { 63343181Sdim // Segment indices are 1-based. 64343181Sdim lldbassert(segment > 0); 65343181Sdim 66343181Sdim uint32_t max_section = dbi().getSectionHeaders().size(); 67343181Sdim lldbassert(segment <= max_section + 1); 68343181Sdim 69343181Sdim // If this is an absolute symbol, it's indicated by the magic section index 70343181Sdim // |max_section+1|. In this case, the offset is meaningless, so just return. 71343181Sdim if (segment == max_section + 1) 72343181Sdim return LLDB_INVALID_ADDRESS; 73343181Sdim 74343181Sdim const llvm::object::coff_section &cs = dbi().getSectionHeaders()[segment - 1]; 75343181Sdim return m_load_address + static_cast<lldb::addr_t>(cs.VirtualAddress) + 76343181Sdim static_cast<lldb::addr_t>(offset); 77343181Sdim} 78343181Sdim 79343181Sdimlldb::addr_t PdbIndex::MakeVirtualAddress(const SegmentOffset &so) const { 80343181Sdim return MakeVirtualAddress(so.segment, so.offset); 81343181Sdim} 82343181Sdim 83343181Sdimllvm::Optional<uint16_t> 84343181SdimPdbIndex::GetModuleIndexForAddr(uint16_t segment, uint32_t offset) const { 85343181Sdim return GetModuleIndexForVa(MakeVirtualAddress(segment, offset)); 86343181Sdim} 87343181Sdim 88343181Sdimllvm::Optional<uint16_t> PdbIndex::GetModuleIndexForVa(lldb::addr_t va) const { 89343181Sdim auto iter = m_va_to_modi.find(va); 90343181Sdim if (iter == m_va_to_modi.end()) 91343181Sdim return llvm::None; 92343181Sdim 93343181Sdim return iter.value(); 94343181Sdim} 95343181Sdim 96343181Sdimvoid PdbIndex::ParseSectionContribs() { 97343181Sdim class Visitor : public ISectionContribVisitor { 98343181Sdim PdbIndex &m_ctx; 99343181Sdim llvm::IntervalMap<uint64_t, uint16_t> &m_imap; 100343181Sdim 101343181Sdim public: 102343181Sdim Visitor(PdbIndex &ctx, llvm::IntervalMap<uint64_t, uint16_t> &imap) 103343181Sdim : m_ctx(ctx), m_imap(imap) {} 104343181Sdim 105343181Sdim void visit(const SectionContrib &C) override { 106343181Sdim if (C.Size == 0) 107343181Sdim return; 108343181Sdim 109343181Sdim uint64_t va = m_ctx.MakeVirtualAddress(C.ISect, C.Off); 110343181Sdim uint64_t end = va + C.Size; 111343181Sdim // IntervalMap's start and end represent a closed range, not a half-open 112343181Sdim // range, so we have to subtract 1. 113343181Sdim m_imap.insert(va, end - 1, C.Imod); 114343181Sdim } 115343181Sdim void visit(const SectionContrib2 &C) override { visit(C.Base); } 116343181Sdim }; 117343181Sdim Visitor v(*this, m_va_to_modi); 118343181Sdim dbi().visitSectionContributions(v); 119343181Sdim} 120343181Sdim 121343181Sdimvoid PdbIndex::BuildAddrToSymbolMap(CompilandIndexItem &cci) { 122343181Sdim lldbassert(cci.m_symbols_by_va.empty() && 123343181Sdim "Addr to symbol map is already built!"); 124343181Sdim uint16_t modi = cci.m_id.modi; 125343181Sdim const CVSymbolArray &syms = cci.m_debug_stream.getSymbolArray(); 126343181Sdim for (auto iter = syms.begin(); iter != syms.end(); ++iter) { 127343181Sdim if (!SymbolHasAddress(*iter)) 128343181Sdim continue; 129343181Sdim 130343181Sdim SegmentOffset so = GetSegmentAndOffset(*iter); 131343181Sdim lldb::addr_t va = MakeVirtualAddress(so); 132343181Sdim 133343181Sdim PdbCompilandSymId cu_sym_id(modi, iter.offset()); 134343181Sdim 135353358Sdim // It's rare, but we could have multiple symbols with the same address 136353358Sdim // because of identical comdat folding. Right now, the first one will win. 137343181Sdim cci.m_symbols_by_va.insert(std::make_pair(va, PdbSymUid(cu_sym_id))); 138343181Sdim } 139343181Sdim} 140343181Sdim 141343181Sdimstd::vector<SymbolAndUid> PdbIndex::FindSymbolsByVa(lldb::addr_t va) { 142343181Sdim std::vector<SymbolAndUid> result; 143343181Sdim 144343181Sdim llvm::Optional<uint16_t> modi = GetModuleIndexForVa(va); 145343181Sdim if (!modi) 146343181Sdim return result; 147343181Sdim 148343181Sdim CompilandIndexItem &cci = compilands().GetOrCreateCompiland(*modi); 149343181Sdim if (cci.m_symbols_by_va.empty()) 150343181Sdim BuildAddrToSymbolMap(cci); 151343181Sdim 152343181Sdim // The map is sorted by starting address of the symbol. So for example 153343181Sdim // we could (in theory) have this situation 154343181Sdim // 155343181Sdim // [------------------] 156343181Sdim // [----------] 157343181Sdim // [-----------] 158343181Sdim // [-------------] 159343181Sdim // [----] 160343181Sdim // [-----] 161343181Sdim // ^ Address we're searching for 162343181Sdim // In order to find this, we use the upper_bound of the key value which would 163343181Sdim // be the first symbol whose starting address is higher than the element we're 164343181Sdim // searching for. 165343181Sdim 166343181Sdim auto ub = cci.m_symbols_by_va.upper_bound(va); 167343181Sdim 168343181Sdim for (auto iter = cci.m_symbols_by_va.begin(); iter != ub; ++iter) { 169343181Sdim PdbCompilandSymId cu_sym_id = iter->second.asCompilandSym(); 170343181Sdim CVSymbol sym = ReadSymbolRecord(cu_sym_id); 171343181Sdim 172343181Sdim SegmentOffsetLength sol; 173343181Sdim if (SymbolIsCode(sym)) 174343181Sdim sol = GetSegmentOffsetAndLength(sym); 175343181Sdim else 176343181Sdim sol.so = GetSegmentAndOffset(sym); 177343181Sdim 178343181Sdim lldb::addr_t start = MakeVirtualAddress(sol.so); 179343181Sdim lldb::addr_t end = start + sol.length; 180343181Sdim if (va >= start && va < end) 181343181Sdim result.push_back({std::move(sym), iter->second}); 182343181Sdim } 183343181Sdim 184343181Sdim return result; 185343181Sdim} 186343181Sdim 187343181SdimCVSymbol PdbIndex::ReadSymbolRecord(PdbCompilandSymId cu_sym) const { 188343181Sdim const CompilandIndexItem *cci = compilands().GetCompiland(cu_sym.modi); 189343181Sdim auto iter = cci->m_debug_stream.getSymbolArray().at(cu_sym.offset); 190343181Sdim lldbassert(iter != cci->m_debug_stream.getSymbolArray().end()); 191343181Sdim return *iter; 192343181Sdim} 193343181Sdim 194343181SdimCVSymbol PdbIndex::ReadSymbolRecord(PdbGlobalSymId global) const { 195343181Sdim return symrecords().readRecord(global.offset); 196343181Sdim} 197