LLVM 20.0.0git
NativeSession.cpp
Go to the documentation of this file.
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
10
32#include "llvm/Object/Binary.h"
33#include "llvm/Object/COFF.h"
37#include "llvm/Support/Error.h"
40#include "llvm/Support/Path.h"
41
42#include <algorithm>
43#include <cassert>
44#include <memory>
45#include <utility>
46
47using namespace llvm;
48using namespace llvm::msf;
49using namespace llvm::pdb;
50
51namespace llvm {
52namespace codeview {
53union DebugInfo;
54}
55} // namespace llvm
56
58 Expected<DbiStream &> DbiS = File.getPDBDbiStream();
59 if (DbiS)
60 return &DbiS.get();
61
62 consumeError(DbiS.takeError());
63 return nullptr;
64}
65
66NativeSession::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
72
73Error 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
93loadPdbFile(StringRef PdbPath, std::unique_ptr<BumpPtrAllocator> &Allocator) {
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();
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
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
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
152 std::unique_ptr<IPDBSession> &Session) {
153 Expected<std::string> PdbPath = getPdbPathFromExe(ExePath);
154 if (!PdbPath)
155 return PdbPath.takeError();
156
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
174NativeSession::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("/")
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);
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
205uint64_t NativeSession::getLoadAddress() const { return LoadAddress; }
206
208 LoadAddress = Address;
209 return true;
210}
211
212std::unique_ptr<PDBSymbolExe> NativeSession::getGlobalScope() {
213 return PDBSymbol::createAs<PDBSymbolExe>(*this, getNativeGlobalScope());
214}
215
216std::unique_ptr<PDBSymbol>
218 return Cache.getSymbolById(SymbolId);
219}
220
222 uint32_t &Offset) const {
223 uint32_t RVA = VA - getLoadAddress();
224 return addressForRVA(RVA, Section, Offset);
225}
226
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
249std::unique_ptr<PDBSymbol>
251 uint32_t Section;
253 addressForVA(Address, Section, Offset);
254 return findSymbolBySectOffset(Section, Offset, Type);
255}
256
257std::unique_ptr<PDBSymbol> NativeSession::findSymbolByRVA(uint32_t RVA,
259 uint32_t Section;
261 addressForRVA(RVA, Section, Offset);
262 return findSymbolBySectOffset(Section, Offset, Type);
263}
264
265std::unique_ptr<PDBSymbol>
268 if (AddrToModuleIndex.empty())
269 parseSectionContribs();
270
271 return Cache.findSymbolBySectOffset(Sect, Offset, Type);
272}
273
274std::unique_ptr<IPDBEnumLineNumbers>
276 const IPDBSourceFile &File) const {
277 return nullptr;
278}
279
280std::unique_ptr<IPDBEnumLineNumbers>
282 uint32_t Length) const {
283 return Cache.findLineNumbersByVA(Address, Length);
284}
285
286std::unique_ptr<IPDBEnumLineNumbers>
288 return Cache.findLineNumbersByVA(getLoadAddress() + RVA, Length);
289}
290
291std::unique_ptr<IPDBEnumLineNumbers>
293 uint32_t Length) const {
294 uint64_t VA = getVAFromSectOffset(Section, Offset);
295 return Cache.findLineNumbersByVA(VA, Length);
296}
297
298std::unique_ptr<IPDBEnumSourceFiles>
301 PDB_NameSearchFlags Flags) const {
302 return nullptr;
303}
304
305std::unique_ptr<IPDBSourceFile>
308 PDB_NameSearchFlags Flags) const {
309 return nullptr;
310}
311
312std::unique_ptr<IPDBEnumChildren<PDBSymbolCompiland>>
314 PDB_NameSearchFlags Flags) const {
315 return nullptr;
316}
317
318std::unique_ptr<PDBSymbolCompiland>
320 PDB_NameSearchFlags Flags) const {
321 return nullptr;
322}
323
324std::unique_ptr<IPDBEnumSourceFiles> NativeSession::getAllSourceFiles() const {
325 return nullptr;
326}
327
328std::unique_ptr<IPDBEnumSourceFiles> NativeSession::getSourceFilesForCompiland(
329 const PDBSymbolCompiland &Compiland) const {
330 return nullptr;
331}
332
333std::unique_ptr<IPDBSourceFile>
335 return Cache.getSourceFileById(FileId);
336}
337
338std::unique_ptr<IPDBEnumDataStreams> NativeSession::getDebugStreams() const {
339 return nullptr;
340}
341
342std::unique_ptr<IPDBEnumTables> NativeSession::getEnumTables() const {
343 return nullptr;
344}
345
346std::unique_ptr<IPDBEnumInjectedSources>
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
361std::unique_ptr<IPDBEnumSectionContribs>
363 return nullptr;
364}
365
366std::unique_ptr<IPDBEnumFrameData>
368 return nullptr;
369}
370
371void NativeSession::initializeExeSymbol() {
372 if (ExeSymbol == 0)
373 ExeSymbol = Cache.createSymbol<NativeExeSymbol>();
374}
375
377 const_cast<NativeSession &>(*this).initializeExeSymbol();
378
379 return Cache.getNativeSymbolById<NativeExeSymbol>(ExeSymbol);
380}
381
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
399 uint32_t Offset) const {
400 return LoadAddress + getRVAFromSectOffset(Section, Offset);
401}
402
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
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
422void 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
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}
This file defines the BumpPtrAllocator interface.
Lightweight arrays that are backed by an arbitrary BinaryStream.
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
bool End
Definition: ELF_riscv.cpp:480
Provides ErrorOr<T> smart pointer.
static DbiStream * getDbiStreamPtr(NativeSession &Session)
static DbiStream * getDbiStreamPtr(PDBFile &File)
static Expected< std::string > getPdbPathFromExe(StringRef ExePath)
static Expected< std::unique_ptr< PDBFile > > loadPdbFile(StringRef PdbPath, std::unique_ptr< BumpPtrAllocator > &Allocator)
Basic Register Allocator
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
This file defines the SmallString class.
Represents either an error or a value T.
Definition: ErrorOr.h:56
std::error_code getError() const
Definition: ErrorOr.h:152
Lightweight error class with error context and mandatory checking.
Definition: Error.h:160
static ErrorSuccess success()
Create a success value.
Definition: Error.h:337
Tagged union holding either a T or a Error.
Definition: Error.h:481
Error takeError()
Take ownership of the stored error.
Definition: Error.h:608
reference get()
Returns a reference to the stored T value.
Definition: Error.h:578
const_iterator find(KeyT x) const
find - Return an iterator pointing to the first interval ending at or after x, or end().
Definition: IntervalMap.h:1172
bool empty() const
empty - Return true when no intervals are mapped.
Definition: IntervalMap.h:1101
const_iterator end() const
Definition: IntervalMap.h:1158
static ErrorOr< std::unique_ptr< MemoryBuffer > > getFile(const Twine &Filename, bool IsText=false, bool RequiresNullTerminator=true, bool IsVolatile=false, std::optional< Align > Alignment=std::nullopt)
Open the specified file as a MemoryBuffer, returning a new MemoryBuffer if successful,...
SmallString - A SmallString is just a SmallVector with methods and accessors that make it work better...
Definition: SmallString.h:26
StringRef - Represent a constant reference to a string, i.e.
Definition: StringRef.h:50
bool starts_with(StringRef Prefix) const
Check if this string starts with the given Prefix.
Definition: StringRef.h:250
The instances of the Type class are immutable: once they are created, they are never changed.
Definition: Type.h:45
Error getDebugPDBInfo(const debug_directory *DebugDir, const codeview::DebugInfo *&Info, StringRef &PDBFileName) const
Get PDB information out of a codeview debug directory entry.
IPDBSourceFile defines an interface used to represent source files whose information are stored in th...
std::unique_ptr< IPDBEnumFrameData > getFrameData() const override
std::unique_ptr< IPDBEnumSourceFiles > getSourceFilesForCompiland(const PDBSymbolCompiland &Compiland) const override
static Expected< std::string > searchForPdb(const PdbSearchOptions &Opts)
std::unique_ptr< PDBSymbolExe > getGlobalScope() override
bool addressForVA(uint64_t VA, uint32_t &Section, uint32_t &Offset) const override
std::unique_ptr< IPDBEnumSourceFiles > findSourceFiles(const PDBSymbolCompiland *Compiland, llvm::StringRef Pattern, PDB_NameSearchFlags Flags) const override
bool addressForRVA(uint32_t RVA, uint32_t &Section, uint32_t &Offset) const override
std::unique_ptr< IPDBEnumLineNumbers > findLineNumbersByRVA(uint32_t RVA, uint32_t Length) const override
bool moduleIndexForSectOffset(uint32_t Sect, uint32_t Offset, uint16_t &ModuleIndex) const
uint64_t getVAFromSectOffset(uint32_t Section, uint32_t Offset) const
std::unique_ptr< IPDBEnumLineNumbers > findLineNumbersBySectOffset(uint32_t Section, uint32_t Offset, uint32_t Length) const override
static Error createFromPdb(std::unique_ptr< MemoryBuffer > MB, std::unique_ptr< IPDBSession > &Session)
static Error createFromExe(StringRef Path, std::unique_ptr< IPDBSession > &Session)
std::unique_ptr< PDBSymbol > findSymbolBySectOffset(uint32_t Sect, uint32_t Offset, PDB_SymType Type) override
std::unique_ptr< PDBSymbolCompiland > findOneCompilandForSourceFile(llvm::StringRef Pattern, PDB_NameSearchFlags Flags) const override
uint32_t getRVAFromSectOffset(uint32_t Section, uint32_t Offset) const
std::unique_ptr< IPDBEnumInjectedSources > getInjectedSources() const override
std::unique_ptr< IPDBEnumTables > getEnumTables() const override
static Error createFromPdbPath(StringRef PdbPath, std::unique_ptr< IPDBSession > &Session)
bool setLoadAddress(uint64_t Address) override
std::unique_ptr< IPDBSourceFile > getSourceFileById(uint32_t FileId) const override
std::unique_ptr< IPDBEnumSectionContribs > getSectionContribs() const override
NativeSession(std::unique_ptr< PDBFile > PdbFile, std::unique_ptr< BumpPtrAllocator > Allocator)
NativeExeSymbol & getNativeGlobalScope() const
std::unique_ptr< IPDBEnumChildren< PDBSymbolCompiland > > findCompilandsForSourceFile(llvm::StringRef Pattern, PDB_NameSearchFlags Flags) const override
std::unique_ptr< IPDBEnumLineNumbers > findLineNumbersByAddress(uint64_t Address, uint32_t Length) const override
std::unique_ptr< PDBSymbol > findSymbolByAddress(uint64_t Address, PDB_SymType Type) override
Expected< ModuleDebugStreamRef > getModuleDebugStream(uint32_t Index) const
std::unique_ptr< IPDBEnumSourceFiles > getAllSourceFiles() const override
bool moduleIndexForVA(uint64_t VA, uint16_t &ModuleIndex) const
std::unique_ptr< IPDBEnumDataStreams > getDebugStreams() const override
std::unique_ptr< IPDBEnumLineNumbers > findLineNumbers(const PDBSymbolCompiland &Compiland, const IPDBSourceFile &File) const override
std::unique_ptr< PDBSymbol > getSymbolById(SymIndexId SymbolId) const override
std::unique_ptr< IPDBSourceFile > findOneSourceFile(const PDBSymbolCompiland *Compiland, llvm::StringRef Pattern, PDB_NameSearchFlags Flags) const override
std::unique_ptr< PDBSymbol > findSymbolByRVA(uint32_t RVA, PDB_SymType Type) override
uint64_t getLoadAddress() const override
std::unique_ptr< PDBSymbol > getSymbolById(SymIndexId SymbolId) const
NativeRawSymbol & getNativeSymbolById(SymIndexId SymbolId) const
std::unique_ptr< IPDBSourceFile > getSourceFileById(SymIndexId FileId) const
std::unique_ptr< IPDBEnumLineNumbers > findLineNumbersByVA(uint64_t VA, uint32_t Length) const
SymIndexId createSymbol(Args &&...ConstructorArgs) const
Definition: SymbolCache.h:127
std::unique_ptr< PDBSymbol > findSymbolBySectOffset(uint32_t Sect, uint32_t Offset, PDB_SymType Type)
@ C
The default llvm calling convention, compatible with C.
Definition: CallingConv.h:34
static const char Magic[]
Definition: MSFCommon.h:23
Expected< std::unique_ptr< Binary > > createBinary(MemoryBufferRef Source, LLVMContext *Context=nullptr, bool InitContent=true)
Create a Binary from Source, autodetecting the file type.
Definition: Binary.cpp:45
const uint16_t kInvalidStreamIndex
Definition: RawConstants.h:19
PDB_NameSearchFlags
Defines flags used for enumerating child symbols.
Definition: PDBTypes.h:102
PDB_SymType
These values correspond to the SymTagEnum enumeration, and are documented here: https://msdn....
Definition: PDBTypes.h:243
void remove_filename(SmallVectorImpl< char > &path, Style style=Style::native)
Remove the last component from path unless it is the root dir.
Definition: Path.cpp:475
StringRef filename(StringRef path, Style style=Style::native)
Get filename.
Definition: Path.cpp:578
void append(SmallVectorImpl< char > &path, const Twine &a, const Twine &b="", const Twine &c="", const Twine &d="")
Append to path.
Definition: Path.cpp:457
This is an optimization pass for GlobalISel generic memory operations.
Definition: AddressRanges.h:18
file_magic identify_magic(StringRef magic)
Identify the type of a binary file based on how magical it is.
Definition: Magic.cpp:33
@ Length
Definition: DWP.cpp:480
auto size(R &&Range, std::enable_if_t< std::is_base_of< std::random_access_iterator_tag, typename std::iterator_traits< decltype(Range.begin())>::iterator_category >::value, void > *=nullptr)
Get the size of a range.
Definition: STLExtras.h:1680
OutputIt move(R &&Range, OutputIt Out)
Provide wrappers to std::move which take ranges instead of having to pass begin/end explicitly.
Definition: STLExtras.h:1856
void consumeError(Error Err)
Consume a Error without doing anything.
Definition: Error.h:1069
Implement std::hash so that hash_code can be used in STL containers.
Definition: BitVector.h:858
file_magic - An "enum class" enumeration of file types based on magic (the first N bytes of the file)...
Definition: Magic.h:20
@ pdb
Windows PDB debug info file.
Definition: Magic.h:54