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