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