• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
getDbiStreamPtr(PDBFile & File)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 
NativeSession(std::unique_ptr<PDBFile> PdbFile,std::unique_ptr<BumpPtrAllocator> Allocator)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 
createFromPdb(std::unique_ptr<MemoryBuffer> Buffer,std::unique_ptr<IPDBSession> & Session)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>>
loadPdbFile(StringRef PdbPath,std::unique_ptr<BumpPtrAllocator> & Allocator)84 loadPdbFile(StringRef PdbPath, std::unique_ptr<BumpPtrAllocator> &Allocator) {
85   ErrorOr<std::unique_ptr<MemoryBuffer>> ErrorOrBuffer =
86       MemoryBuffer::getFile(PdbPath, /*FileSize=*/-1,
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 
createFromPdbPath(StringRef PdbPath,std::unique_ptr<IPDBSession> & Session)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 
getPdbPathFromExe(StringRef ExePath)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 
createFromExe(StringRef ExePath,std::unique_ptr<IPDBSession> & Session)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>
searchForPdb(const PdbSearchOptions & Opts)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 
getLoadAddress() const196 uint64_t NativeSession::getLoadAddress() const { return LoadAddress; }
197 
setLoadAddress(uint64_t Address)198 bool NativeSession::setLoadAddress(uint64_t Address) {
199   LoadAddress = Address;
200   return true;
201 }
202 
getGlobalScope()203 std::unique_ptr<PDBSymbolExe> NativeSession::getGlobalScope() {
204   return PDBSymbol::createAs<PDBSymbolExe>(*this, getNativeGlobalScope());
205 }
206 
207 std::unique_ptr<PDBSymbol>
getSymbolById(SymIndexId SymbolId) const208 NativeSession::getSymbolById(SymIndexId SymbolId) const {
209   return Cache.getSymbolById(SymbolId);
210 }
211 
addressForVA(uint64_t VA,uint32_t & Section,uint32_t & Offset) const212 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 
addressForRVA(uint32_t RVA,uint32_t & Section,uint32_t & Offset) const218 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>
findSymbolByAddress(uint64_t Address,PDB_SymType Type)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 
findSymbolByRVA(uint32_t RVA,PDB_SymType Type)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>
findSymbolBySectOffset(uint32_t Sect,uint32_t Offset,PDB_SymType Type)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>
findLineNumbers(const PDBSymbolCompiland & Compiland,const IPDBSourceFile & File) const266 NativeSession::findLineNumbers(const PDBSymbolCompiland &Compiland,
267                                const IPDBSourceFile &File) const {
268   return nullptr;
269 }
270 
271 std::unique_ptr<IPDBEnumLineNumbers>
findLineNumbersByAddress(uint64_t Address,uint32_t Length) const272 NativeSession::findLineNumbersByAddress(uint64_t Address,
273                                         uint32_t Length) const {
274   return Cache.findLineNumbersByVA(Address, Length);
275 }
276 
277 std::unique_ptr<IPDBEnumLineNumbers>
findLineNumbersByRVA(uint32_t RVA,uint32_t Length) const278 NativeSession::findLineNumbersByRVA(uint32_t RVA, uint32_t Length) const {
279   return Cache.findLineNumbersByVA(getLoadAddress() + RVA, Length);
280 }
281 
282 std::unique_ptr<IPDBEnumLineNumbers>
findLineNumbersBySectOffset(uint32_t Section,uint32_t Offset,uint32_t Length) const283 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>
findSourceFiles(const PDBSymbolCompiland * Compiland,StringRef Pattern,PDB_NameSearchFlags Flags) const290 NativeSession::findSourceFiles(const PDBSymbolCompiland *Compiland,
291                                StringRef Pattern,
292                                PDB_NameSearchFlags Flags) const {
293   return nullptr;
294 }
295 
296 std::unique_ptr<IPDBSourceFile>
findOneSourceFile(const PDBSymbolCompiland * Compiland,StringRef Pattern,PDB_NameSearchFlags Flags) const297 NativeSession::findOneSourceFile(const PDBSymbolCompiland *Compiland,
298                                  StringRef Pattern,
299                                  PDB_NameSearchFlags Flags) const {
300   return nullptr;
301 }
302 
303 std::unique_ptr<IPDBEnumChildren<PDBSymbolCompiland>>
findCompilandsForSourceFile(StringRef Pattern,PDB_NameSearchFlags Flags) const304 NativeSession::findCompilandsForSourceFile(StringRef Pattern,
305                                            PDB_NameSearchFlags Flags) const {
306   return nullptr;
307 }
308 
309 std::unique_ptr<PDBSymbolCompiland>
findOneCompilandForSourceFile(StringRef Pattern,PDB_NameSearchFlags Flags) const310 NativeSession::findOneCompilandForSourceFile(StringRef Pattern,
311                                              PDB_NameSearchFlags Flags) const {
312   return nullptr;
313 }
314 
getAllSourceFiles() const315 std::unique_ptr<IPDBEnumSourceFiles> NativeSession::getAllSourceFiles() const {
316   return nullptr;
317 }
318 
getSourceFilesForCompiland(const PDBSymbolCompiland & Compiland) const319 std::unique_ptr<IPDBEnumSourceFiles> NativeSession::getSourceFilesForCompiland(
320     const PDBSymbolCompiland &Compiland) const {
321   return nullptr;
322 }
323 
324 std::unique_ptr<IPDBSourceFile>
getSourceFileById(uint32_t FileId) const325 NativeSession::getSourceFileById(uint32_t FileId) const {
326   return Cache.getSourceFileById(FileId);
327 }
328 
getDebugStreams() const329 std::unique_ptr<IPDBEnumDataStreams> NativeSession::getDebugStreams() const {
330   return nullptr;
331 }
332 
getEnumTables() const333 std::unique_ptr<IPDBEnumTables> NativeSession::getEnumTables() const {
334   return nullptr;
335 }
336 
337 std::unique_ptr<IPDBEnumInjectedSources>
getInjectedSources() const338 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>
getSectionContribs() const353 NativeSession::getSectionContribs() const {
354   return nullptr;
355 }
356 
357 std::unique_ptr<IPDBEnumFrameData>
getFrameData() const358 NativeSession::getFrameData() const {
359   return nullptr;
360 }
361 
initializeExeSymbol()362 void NativeSession::initializeExeSymbol() {
363   if (ExeSymbol == 0)
364     ExeSymbol = Cache.createSymbol<NativeExeSymbol>();
365 }
366 
getNativeGlobalScope() const367 NativeExeSymbol &NativeSession::getNativeGlobalScope() const {
368   const_cast<NativeSession &>(*this).initializeExeSymbol();
369 
370   return Cache.getNativeSymbolById<NativeExeSymbol>(ExeSymbol);
371 }
372 
getRVAFromSectOffset(uint32_t Section,uint32_t Offset) const373 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 
getVAFromSectOffset(uint32_t Section,uint32_t Offset) const389 uint64_t NativeSession::getVAFromSectOffset(uint32_t Section,
390                                             uint32_t Offset) const {
391   return LoadAddress + getRVAFromSectOffset(Section, Offset);
392 }
393 
moduleIndexForVA(uint64_t VA,uint16_t & ModuleIndex) const394 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 
moduleIndexForSectOffset(uint32_t Sect,uint32_t Offset,uint16_t & ModuleIndex) const403 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 
parseSectionContribs()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>
getModuleDebugStream(uint32_t Index) const445 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