480 lines · cpp
1//===- NativeSession.cpp - Native implementation of IPDBSession -*- C++ -*-===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#include "llvm/DebugInfo/PDB/Native/NativeSession.h"10 11#include "llvm/ADT/SmallString.h"12#include "llvm/BinaryFormat/Magic.h"13#include "llvm/DebugInfo/MSF/MappedBlockStream.h"14#include "llvm/DebugInfo/PDB/IPDBEnumChildren.h"15#include "llvm/DebugInfo/PDB/IPDBSourceFile.h"16#include "llvm/DebugInfo/PDB/Native/DbiModuleDescriptor.h"17#include "llvm/DebugInfo/PDB/Native/DbiModuleList.h"18#include "llvm/DebugInfo/PDB/Native/DbiStream.h"19#include "llvm/DebugInfo/PDB/Native/ISectionContribVisitor.h"20#include "llvm/DebugInfo/PDB/Native/ModuleDebugStream.h"21#include "llvm/DebugInfo/PDB/Native/NativeEnumInjectedSources.h"22#include "llvm/DebugInfo/PDB/Native/NativeExeSymbol.h"23#include "llvm/DebugInfo/PDB/Native/PDBFile.h"24#include "llvm/DebugInfo/PDB/Native/RawConstants.h"25#include "llvm/DebugInfo/PDB/Native/RawError.h"26#include "llvm/DebugInfo/PDB/Native/RawTypes.h"27#include "llvm/DebugInfo/PDB/Native/SymbolCache.h"28#include "llvm/DebugInfo/PDB/PDBSymbol.h"29#include "llvm/DebugInfo/PDB/PDBSymbolCompiland.h"30#include "llvm/DebugInfo/PDB/PDBSymbolExe.h"31#include "llvm/Object/Binary.h"32#include "llvm/Object/COFF.h"33#include "llvm/Support/Allocator.h"34#include "llvm/Support/BinaryByteStream.h"35#include "llvm/Support/BinaryStreamArray.h"36#include "llvm/Support/Error.h"37#include "llvm/Support/ErrorOr.h"38#include "llvm/Support/MemoryBuffer.h"39#include "llvm/Support/Path.h"40 41#include <cassert>42#include <memory>43#include <utility>44 45using namespace llvm;46using namespace llvm::msf;47using namespace llvm::pdb;48 49namespace llvm {50namespace codeview {51union DebugInfo;52}53} // namespace llvm54 55static DbiStream *getDbiStreamPtr(PDBFile &File) {56 Expected<DbiStream &> DbiS = File.getPDBDbiStream();57 if (DbiS)58 return &DbiS.get();59 60 consumeError(DbiS.takeError());61 return nullptr;62}63 64NativeSession::NativeSession(std::unique_ptr<PDBFile> PdbFile,65 std::unique_ptr<BumpPtrAllocator> Allocator)66 : Pdb(std::move(PdbFile)), Allocator(std::move(Allocator)),67 Cache(*this, getDbiStreamPtr(*Pdb)), AddrToModuleIndex(IMapAllocator) {}68 69NativeSession::~NativeSession() = default;70 71Error NativeSession::createFromPdb(std::unique_ptr<MemoryBuffer> Buffer,72 std::unique_ptr<IPDBSession> &Session) {73 StringRef Path = Buffer->getBufferIdentifier();74 auto Stream = std::make_unique<MemoryBufferByteStream>(75 std::move(Buffer), llvm::endianness::little);76 77 auto Allocator = std::make_unique<BumpPtrAllocator>();78 auto File = std::make_unique<PDBFile>(Path, std::move(Stream), *Allocator);79 if (auto EC = File->parseFileHeaders())80 return EC;81 if (auto EC = File->parseStreamData())82 return EC;83 84 Session =85 std::make_unique<NativeSession>(std::move(File), std::move(Allocator));86 87 return Error::success();88}89 90static Error validatePdbMagic(StringRef PdbPath) {91 file_magic Magic;92 if (auto EC = identify_magic(PdbPath, Magic))93 return make_error<RawError>(EC);94 95 if (Magic != file_magic::pdb)96 return make_error<RawError>(97 raw_error_code::invalid_format,98 "The input file did not contain the pdb file magic.");99 100 return Error::success();101}102 103static Expected<std::unique_ptr<PDBFile>>104loadPdbFile(StringRef PdbPath, std::unique_ptr<BumpPtrAllocator> &Allocator) {105 ErrorOr<std::unique_ptr<MemoryBuffer>> ErrorOrBuffer =106 MemoryBuffer::getFile(PdbPath, /*IsText=*/false,107 /*RequiresNullTerminator=*/false);108 if (!ErrorOrBuffer)109 return make_error<RawError>(ErrorOrBuffer.getError());110 std::unique_ptr<llvm::MemoryBuffer> Buffer = std::move(*ErrorOrBuffer);111 112 PdbPath = Buffer->getBufferIdentifier();113 if (auto EC = validatePdbMagic(PdbPath))114 return std::move(EC);115 116 auto Stream = std::make_unique<MemoryBufferByteStream>(117 std::move(Buffer), llvm::endianness::little);118 119 auto File = std::make_unique<PDBFile>(PdbPath, std::move(Stream), *Allocator);120 if (auto EC = File->parseFileHeaders())121 return std::move(EC);122 123 if (auto EC = File->parseStreamData())124 return std::move(EC);125 126 return std::move(File);127}128 129Error NativeSession::createFromPdbPath(StringRef PdbPath,130 std::unique_ptr<IPDBSession> &Session) {131 auto Allocator = std::make_unique<BumpPtrAllocator>();132 auto PdbFile = loadPdbFile(PdbPath, Allocator);133 if (!PdbFile)134 return PdbFile.takeError();135 136 Session = std::make_unique<NativeSession>(std::move(PdbFile.get()),137 std::move(Allocator));138 return Error::success();139}140 141static Expected<std::string> getPdbPathFromExe(StringRef ExePath) {142 Expected<object::OwningBinary<object::Binary>> BinaryFile =143 object::createBinary(ExePath);144 if (!BinaryFile)145 return BinaryFile.takeError();146 147 const object::COFFObjectFile *ObjFile =148 dyn_cast<object::COFFObjectFile>(BinaryFile->getBinary());149 if (!ObjFile)150 return make_error<RawError>(raw_error_code::invalid_format);151 152 StringRef PdbPath;153 const llvm::codeview::DebugInfo *PdbInfo = nullptr;154 if (Error E = ObjFile->getDebugPDBInfo(PdbInfo, PdbPath))155 return std::move(E);156 157 return std::string(PdbPath);158}159 160Error NativeSession::createFromExe(StringRef ExePath,161 std::unique_ptr<IPDBSession> &Session) {162 Expected<std::string> PdbPath = getPdbPathFromExe(ExePath);163 if (!PdbPath)164 return PdbPath.takeError();165 166 if (auto EC = validatePdbMagic(PdbPath.get()))167 return EC;168 169 auto Allocator = std::make_unique<BumpPtrAllocator>();170 auto File = loadPdbFile(PdbPath.get(), Allocator);171 if (!File)172 return File.takeError();173 174 Session = std::make_unique<NativeSession>(std::move(File.get()),175 std::move(Allocator));176 177 return Error::success();178}179 180Expected<std::string>181NativeSession::searchForPdb(const PdbSearchOptions &Opts) {182 Expected<std::string> PathOrErr = getPdbPathFromExe(Opts.ExePath);183 if (!PathOrErr)184 return PathOrErr.takeError();185 StringRef PathFromExe = PathOrErr.get();186 sys::path::Style Style = PathFromExe.starts_with("/")187 ? sys::path::Style::posix188 : sys::path::Style::windows;189 StringRef PdbName = sys::path::filename(PathFromExe, Style);190 191 // Check if pdb exists in the executable directory.192 SmallString<128> PdbPath = StringRef(Opts.ExePath);193 sys::path::remove_filename(PdbPath);194 sys::path::append(PdbPath, PdbName);195 196 auto Allocator = std::make_unique<BumpPtrAllocator>();197 198 if (auto File = loadPdbFile(PdbPath, Allocator))199 return std::string(PdbPath);200 else201 consumeError(File.takeError());202 203 // Check path that was in the executable.204 if (auto File = loadPdbFile(PathFromExe, Allocator))205 return std::string(PathFromExe);206 else207 return File.takeError();208 209 return make_error<RawError>("PDB not found");210}211 212uint64_t NativeSession::getLoadAddress() const { return LoadAddress; }213 214bool NativeSession::setLoadAddress(uint64_t Address) {215 LoadAddress = Address;216 return true;217}218 219std::unique_ptr<PDBSymbolExe> NativeSession::getGlobalScope() {220 return PDBSymbol::createAs<PDBSymbolExe>(*this, getNativeGlobalScope());221}222 223std::unique_ptr<PDBSymbol>224NativeSession::getSymbolById(SymIndexId SymbolId) const {225 return Cache.getSymbolById(SymbolId);226}227 228bool NativeSession::addressForVA(uint64_t VA, uint32_t &Section,229 uint32_t &Offset) const {230 uint32_t RVA = VA - getLoadAddress();231 return addressForRVA(RVA, Section, Offset);232}233 234bool NativeSession::addressForRVA(uint32_t RVA, uint32_t &Section,235 uint32_t &Offset) const {236 Section = 0;237 Offset = 0;238 239 auto Dbi = Pdb->getPDBDbiStream();240 if (!Dbi)241 return false;242 243 if ((int32_t)RVA < 0)244 return true;245 246 Offset = RVA;247 for (; Section < Dbi->getSectionHeaders().size(); ++Section) {248 auto &Sec = Dbi->getSectionHeaders()[Section];249 if (RVA < Sec.VirtualAddress)250 return true;251 Offset = RVA - Sec.VirtualAddress;252 }253 return true;254}255 256std::unique_ptr<PDBSymbol>257NativeSession::findSymbolByAddress(uint64_t Address, PDB_SymType Type) {258 uint32_t Section;259 uint32_t Offset;260 addressForVA(Address, Section, Offset);261 return findSymbolBySectOffset(Section, Offset, Type);262}263 264std::unique_ptr<PDBSymbol> NativeSession::findSymbolByRVA(uint32_t RVA,265 PDB_SymType Type) {266 uint32_t Section;267 uint32_t Offset;268 addressForRVA(RVA, Section, Offset);269 return findSymbolBySectOffset(Section, Offset, Type);270}271 272std::unique_ptr<PDBSymbol>273NativeSession::findSymbolBySectOffset(uint32_t Sect, uint32_t Offset,274 PDB_SymType Type) {275 if (AddrToModuleIndex.empty())276 parseSectionContribs();277 278 return Cache.findSymbolBySectOffset(Sect, Offset, Type);279}280 281std::unique_ptr<IPDBEnumLineNumbers>282NativeSession::findLineNumbers(const PDBSymbolCompiland &Compiland,283 const IPDBSourceFile &File) const {284 return nullptr;285}286 287std::unique_ptr<IPDBEnumLineNumbers>288NativeSession::findLineNumbersByAddress(uint64_t Address,289 uint32_t Length) const {290 return Cache.findLineNumbersByVA(Address, Length);291}292 293std::unique_ptr<IPDBEnumLineNumbers>294NativeSession::findLineNumbersByRVA(uint32_t RVA, uint32_t Length) const {295 return Cache.findLineNumbersByVA(getLoadAddress() + RVA, Length);296}297 298std::unique_ptr<IPDBEnumLineNumbers>299NativeSession::findLineNumbersBySectOffset(uint32_t Section, uint32_t Offset,300 uint32_t Length) const {301 uint64_t VA = getVAFromSectOffset(Section, Offset);302 return Cache.findLineNumbersByVA(VA, Length);303}304 305std::unique_ptr<IPDBEnumSourceFiles>306NativeSession::findSourceFiles(const PDBSymbolCompiland *Compiland,307 StringRef Pattern,308 PDB_NameSearchFlags Flags) const {309 return nullptr;310}311 312std::unique_ptr<IPDBSourceFile>313NativeSession::findOneSourceFile(const PDBSymbolCompiland *Compiland,314 StringRef Pattern,315 PDB_NameSearchFlags Flags) const {316 return nullptr;317}318 319std::unique_ptr<IPDBEnumChildren<PDBSymbolCompiland>>320NativeSession::findCompilandsForSourceFile(StringRef Pattern,321 PDB_NameSearchFlags Flags) const {322 return nullptr;323}324 325std::unique_ptr<PDBSymbolCompiland>326NativeSession::findOneCompilandForSourceFile(StringRef Pattern,327 PDB_NameSearchFlags Flags) const {328 return nullptr;329}330 331std::unique_ptr<IPDBEnumSourceFiles> NativeSession::getAllSourceFiles() const {332 return nullptr;333}334 335std::unique_ptr<IPDBEnumSourceFiles> NativeSession::getSourceFilesForCompiland(336 const PDBSymbolCompiland &Compiland) const {337 return nullptr;338}339 340std::unique_ptr<IPDBSourceFile>341NativeSession::getSourceFileById(uint32_t FileId) const {342 return Cache.getSourceFileById(FileId);343}344 345std::unique_ptr<IPDBEnumDataStreams> NativeSession::getDebugStreams() const {346 return nullptr;347}348 349std::unique_ptr<IPDBEnumTables> NativeSession::getEnumTables() const {350 return nullptr;351}352 353std::unique_ptr<IPDBEnumInjectedSources>354NativeSession::getInjectedSources() const {355 auto ISS = Pdb->getInjectedSourceStream();356 if (!ISS) {357 consumeError(ISS.takeError());358 return nullptr;359 }360 auto Strings = Pdb->getStringTable();361 if (!Strings) {362 consumeError(Strings.takeError());363 return nullptr;364 }365 return std::make_unique<NativeEnumInjectedSources>(*Pdb, *ISS, *Strings);366}367 368std::unique_ptr<IPDBEnumSectionContribs>369NativeSession::getSectionContribs() const {370 return nullptr;371}372 373std::unique_ptr<IPDBEnumFrameData>374NativeSession::getFrameData() const {375 return nullptr;376}377 378void NativeSession::initializeExeSymbol() {379 if (ExeSymbol == 0)380 ExeSymbol = Cache.createSymbol<NativeExeSymbol>();381}382 383NativeExeSymbol &NativeSession::getNativeGlobalScope() const {384 const_cast<NativeSession &>(*this).initializeExeSymbol();385 386 return Cache.getNativeSymbolById<NativeExeSymbol>(ExeSymbol);387}388 389uint32_t NativeSession::getRVAFromSectOffset(uint32_t Section,390 uint32_t Offset) const {391 if (Section <= 0)392 return 0;393 394 auto Dbi = getDbiStreamPtr(*Pdb);395 if (!Dbi)396 return 0;397 398 uint32_t MaxSection = Dbi->getSectionHeaders().size();399 if (Section > MaxSection + 1)400 Section = MaxSection + 1;401 auto &Sec = Dbi->getSectionHeaders()[Section - 1];402 return Sec.VirtualAddress + Offset;403}404 405uint64_t NativeSession::getVAFromSectOffset(uint32_t Section,406 uint32_t Offset) const {407 return LoadAddress + getRVAFromSectOffset(Section, Offset);408}409 410bool NativeSession::moduleIndexForVA(uint64_t VA, uint16_t &ModuleIndex) const {411 ModuleIndex = 0;412 auto Iter = AddrToModuleIndex.find(VA);413 if (Iter == AddrToModuleIndex.end())414 return false;415 ModuleIndex = Iter.value();416 return true;417}418 419bool NativeSession::moduleIndexForSectOffset(uint32_t Sect, uint32_t Offset,420 uint16_t &ModuleIndex) const {421 ModuleIndex = 0;422 auto Iter = AddrToModuleIndex.find(getVAFromSectOffset(Sect, Offset));423 if (Iter == AddrToModuleIndex.end())424 return false;425 ModuleIndex = Iter.value();426 return true;427}428 429void NativeSession::parseSectionContribs() {430 auto Dbi = Pdb->getPDBDbiStream();431 if (!Dbi)432 return;433 434 class Visitor : public ISectionContribVisitor {435 NativeSession &Session;436 IMap &AddrMap;437 438 public:439 Visitor(NativeSession &Session, IMap &AddrMap)440 : Session(Session), AddrMap(AddrMap) {}441 void visit(const SectionContrib &C) override {442 if (C.Size == 0)443 return;444 445 uint64_t VA = Session.getVAFromSectOffset(C.ISect, C.Off);446 uint64_t End = VA + C.Size;447 448 // Ignore overlapping sections based on the assumption that a valid449 // PDB file should not have overlaps.450 if (!AddrMap.overlaps(VA, End))451 AddrMap.insert(VA, End, C.Imod);452 }453 void visit(const SectionContrib2 &C) override { visit(C.Base); }454 };455 456 Visitor V(*this, AddrToModuleIndex);457 Dbi->visitSectionContributions(V);458}459 460Expected<ModuleDebugStreamRef>461NativeSession::getModuleDebugStream(uint32_t Index) const {462 auto *Dbi = getDbiStreamPtr(*Pdb);463 assert(Dbi && "Dbi stream not present");464 465 DbiModuleDescriptor Modi = Dbi->modules().getModuleDescriptor(Index);466 467 uint16_t ModiStream = Modi.getModuleStreamIndex();468 if (ModiStream == kInvalidStreamIndex)469 return make_error<RawError>("Module stream not present");470 471 std::unique_ptr<msf::MappedBlockStream> ModStreamData =472 Pdb->createIndexedStream(ModiStream);473 474 ModuleDebugStreamRef ModS(Modi, std::move(ModStreamData));475 if (auto EC = ModS.reload())476 return std::move(EC);477 478 return std::move(ModS);479}480