brintos

brintos / llvm-project-archived public Read only

0
0
Text · 14.9 KiB · 49674b4 Raw
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