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