LLVM 22.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
31#include "llvm/Object/Binary.h"
32#include "llvm/Object/COFF.h"
36#include "llvm/Support/Error.h"
39#include "llvm/Support/Path.h"
40
41#include <cassert>
42#include <memory>
43#include <utility>
44
45using namespace llvm;
46using namespace llvm::msf;
47using namespace llvm::pdb;
48
49namespace llvm {
50namespace codeview {
51union DebugInfo;
52}
53} // namespace llvm
54
56 Expected<DbiStream &> DbiS = File.getPDBDbiStream();
57 if (DbiS)
58 return &DbiS.get();
59
60 consumeError(DbiS.takeError());
61 return nullptr;
62}
63
64NativeSession::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
70
71Error 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
92 if (auto EC = identify_magic(PdbPath, Magic))
93 return make_error<RawError>(EC);
94
98 "The input file did not contain the pdb file magic.");
99
100 return Error::success();
101}
102
103static Expected<std::unique_ptr<PDBFile>>
104loadPdbFile(StringRef PdbPath, std::unique_ptr<BumpPtrAllocator> &Allocator) {
106 MemoryBuffer::getFile(PdbPath, /*IsText=*/false,
107 /*RequiresNullTerminator=*/false);
108 if (!ErrorOrBuffer)
109 return make_error<RawError>(ErrorOrBuffer.getError());
110 std::unique_ptr<llvm::MemoryBuffer> Buffer = std::move(*ErrorOrBuffer);
111
112 PdbPath = Buffer->getBufferIdentifier();
113 if (auto EC = validatePdbMagic(PdbPath))
114 return std::move(EC);
115
116 auto Stream = std::make_unique<MemoryBufferByteStream>(
117 std::move(Buffer), llvm::endianness::little);
118
119 auto File = std::make_unique<PDBFile>(PdbPath, std::move(Stream), *Allocator);
120 if (auto EC = File->parseFileHeaders())
121 return std::move(EC);
122
123 if (auto EC = File->parseStreamData())
124 return std::move(EC);
125
126 return std::move(File);
127}
128
130 std::unique_ptr<IPDBSession> &Session) {
131 auto Allocator = std::make_unique<BumpPtrAllocator>();
132 auto PdbFile = loadPdbFile(PdbPath, Allocator);
133 if (!PdbFile)
134 return PdbFile.takeError();
135
136 Session = std::make_unique<NativeSession>(std::move(PdbFile.get()),
137 std::move(Allocator));
138 return Error::success();
139}
140
143 object::createBinary(ExePath);
144 if (!BinaryFile)
145 return BinaryFile.takeError();
146
147 const object::COFFObjectFile *ObjFile =
148 dyn_cast<object::COFFObjectFile>(BinaryFile->getBinary());
149 if (!ObjFile)
151
152 StringRef PdbPath;
153 const llvm::codeview::DebugInfo *PdbInfo = nullptr;
154 if (Error E = ObjFile->getDebugPDBInfo(PdbInfo, PdbPath))
155 return std::move(E);
156
157 return std::string(PdbPath);
158}
159
161 std::unique_ptr<IPDBSession> &Session) {
162 Expected<std::string> PdbPath = getPdbPathFromExe(ExePath);
163 if (!PdbPath)
164 return PdbPath.takeError();
165
166 if (auto EC = validatePdbMagic(PdbPath.get()))
167 return EC;
168
169 auto Allocator = std::make_unique<BumpPtrAllocator>();
170 auto File = loadPdbFile(PdbPath.get(), Allocator);
171 if (!File)
172 return File.takeError();
173
174 Session = std::make_unique<NativeSession>(std::move(File.get()),
175 std::move(Allocator));
176
177 return Error::success();
178}
179
181NativeSession::searchForPdb(const PdbSearchOptions &Opts) {
182 Expected<std::string> PathOrErr = getPdbPathFromExe(Opts.ExePath);
183 if (!PathOrErr)
184 return PathOrErr.takeError();
185 StringRef PathFromExe = PathOrErr.get();
186 sys::path::Style Style = PathFromExe.starts_with("/")
189 StringRef PdbName = sys::path::filename(PathFromExe, Style);
190
191 // Check if pdb exists in the executable directory.
192 SmallString<128> PdbPath = StringRef(Opts.ExePath);
194 sys::path::append(PdbPath, PdbName);
195
196 auto Allocator = std::make_unique<BumpPtrAllocator>();
197
198 if (auto File = loadPdbFile(PdbPath, Allocator))
199 return std::string(PdbPath);
200 else
201 consumeError(File.takeError());
202
203 // Check path that was in the executable.
204 if (auto File = loadPdbFile(PathFromExe, Allocator))
205 return std::string(PathFromExe);
206 else
207 return File.takeError();
208
209 return make_error<RawError>("PDB not found");
210}
211
212uint64_t NativeSession::getLoadAddress() const { return LoadAddress; }
213
215 LoadAddress = Address;
216 return true;
217}
218
219std::unique_ptr<PDBSymbolExe> NativeSession::getGlobalScope() {
221}
222
223std::unique_ptr<PDBSymbol>
225 return Cache.getSymbolById(SymbolId);
226}
227
229 uint32_t &Offset) const {
230 uint32_t RVA = VA - getLoadAddress();
231 return addressForRVA(RVA, Section, Offset);
232}
233
235 uint32_t &Offset) const {
236 Section = 0;
237 Offset = 0;
238
239 auto Dbi = Pdb->getPDBDbiStream();
240 if (!Dbi)
241 return false;
242
243 if ((int32_t)RVA < 0)
244 return true;
245
246 Offset = RVA;
247 for (; Section < Dbi->getSectionHeaders().size(); ++Section) {
248 auto &Sec = Dbi->getSectionHeaders()[Section];
249 if (RVA < Sec.VirtualAddress)
250 return true;
251 Offset = RVA - Sec.VirtualAddress;
252 }
253 return true;
254}
255
256std::unique_ptr<PDBSymbol>
263
264std::unique_ptr<PDBSymbol> NativeSession::findSymbolByRVA(uint32_t RVA,
266 uint32_t Section;
268 addressForRVA(RVA, Section, Offset);
269 return findSymbolBySectOffset(Section, Offset, Type);
270}
271
272std::unique_ptr<PDBSymbol>
275 if (AddrToModuleIndex.empty())
276 parseSectionContribs();
277
278 return Cache.findSymbolBySectOffset(Sect, Offset, Type);
279}
280
281std::unique_ptr<IPDBEnumLineNumbers>
283 const IPDBSourceFile &File) const {
284 return nullptr;
285}
286
287std::unique_ptr<IPDBEnumLineNumbers>
289 uint32_t Length) const {
290 return Cache.findLineNumbersByVA(Address, Length);
291}
292
293std::unique_ptr<IPDBEnumLineNumbers>
295 return Cache.findLineNumbersByVA(getLoadAddress() + RVA, Length);
296}
297
298std::unique_ptr<IPDBEnumLineNumbers>
300 uint32_t Length) const {
301 uint64_t VA = getVAFromSectOffset(Section, Offset);
302 return Cache.findLineNumbersByVA(VA, Length);
303}
304
305std::unique_ptr<IPDBEnumSourceFiles>
311
312std::unique_ptr<IPDBSourceFile>
318
319std::unique_ptr<IPDBEnumChildren<PDBSymbolCompiland>>
324
325std::unique_ptr<PDBSymbolCompiland>
330
331std::unique_ptr<IPDBEnumSourceFiles> NativeSession::getAllSourceFiles() const {
332 return nullptr;
333}
334
335std::unique_ptr<IPDBEnumSourceFiles> NativeSession::getSourceFilesForCompiland(
336 const PDBSymbolCompiland &Compiland) const {
337 return nullptr;
338}
339
340std::unique_ptr<IPDBSourceFile>
342 return Cache.getSourceFileById(FileId);
343}
344
345std::unique_ptr<IPDBEnumDataStreams> NativeSession::getDebugStreams() const {
346 return nullptr;
347}
348
349std::unique_ptr<IPDBEnumTables> NativeSession::getEnumTables() const {
350 return nullptr;
351}
352
353std::unique_ptr<IPDBEnumInjectedSources>
355 auto ISS = Pdb->getInjectedSourceStream();
356 if (!ISS) {
357 consumeError(ISS.takeError());
358 return nullptr;
359 }
360 auto Strings = Pdb->getStringTable();
361 if (!Strings) {
362 consumeError(Strings.takeError());
363 return nullptr;
364 }
365 return std::make_unique<NativeEnumInjectedSources>(*Pdb, *ISS, *Strings);
366}
367
368std::unique_ptr<IPDBEnumSectionContribs>
370 return nullptr;
371}
372
373std::unique_ptr<IPDBEnumFrameData>
375 return nullptr;
376}
377
378void NativeSession::initializeExeSymbol() {
379 if (ExeSymbol == 0)
380 ExeSymbol = Cache.createSymbol<NativeExeSymbol>();
381}
382
384 const_cast<NativeSession &>(*this).initializeExeSymbol();
385
386 return Cache.getNativeSymbolById<NativeExeSymbol>(ExeSymbol);
387}
388
390 uint32_t Offset) const {
391 if (Section <= 0)
392 return 0;
393
394 auto Dbi = getDbiStreamPtr(*Pdb);
395 if (!Dbi)
396 return 0;
397
398 uint32_t MaxSection = Dbi->getSectionHeaders().size();
399 if (Section > MaxSection + 1)
400 Section = MaxSection + 1;
401 auto &Sec = Dbi->getSectionHeaders()[Section - 1];
402 return Sec.VirtualAddress + Offset;
403}
404
406 uint32_t Offset) const {
407 return LoadAddress + getRVAFromSectOffset(Section, Offset);
408}
409
411 ModuleIndex = 0;
412 auto Iter = AddrToModuleIndex.find(VA);
413 if (Iter == AddrToModuleIndex.end())
414 return false;
415 ModuleIndex = Iter.value();
416 return true;
417}
418
420 uint16_t &ModuleIndex) const {
421 ModuleIndex = 0;
422 auto Iter = AddrToModuleIndex.find(getVAFromSectOffset(Sect, Offset));
423 if (Iter == AddrToModuleIndex.end())
424 return false;
425 ModuleIndex = Iter.value();
426 return true;
427}
428
429void NativeSession::parseSectionContribs() {
430 auto Dbi = Pdb->getPDBDbiStream();
431 if (!Dbi)
432 return;
433
434 class Visitor : public ISectionContribVisitor {
435 NativeSession &Session;
436 IMap &AddrMap;
437
438 public:
439 Visitor(NativeSession &Session, IMap &AddrMap)
440 : Session(Session), AddrMap(AddrMap) {}
441 void visit(const SectionContrib &C) override {
442 if (C.Size == 0)
443 return;
444
445 uint64_t VA = Session.getVAFromSectOffset(C.ISect, C.Off);
446 uint64_t End = VA + C.Size;
447
448 // Ignore overlapping sections based on the assumption that a valid
449 // PDB file should not have overlaps.
450 if (!AddrMap.overlaps(VA, End))
451 AddrMap.insert(VA, End, C.Imod);
452 }
453 void visit(const SectionContrib2 &C) override { visit(C.Base); }
454 };
455
456 Visitor V(*this, AddrToModuleIndex);
457 Dbi->visitSectionContributions(V);
458}
459
460Expected<ModuleDebugStreamRef>
462 auto *Dbi = getDbiStreamPtr(*Pdb);
463 assert(Dbi && "Dbi stream not present");
464
465 DbiModuleDescriptor Modi = Dbi->modules().getModuleDescriptor(Index);
466
467 uint16_t ModiStream = Modi.getModuleStreamIndex();
468 if (ModiStream == kInvalidStreamIndex)
469 return make_error<RawError>("Module stream not present");
470
471 std::unique_ptr<msf::MappedBlockStream> ModStreamData =
472 Pdb->createIndexedStream(ModiStream);
473
474 ModuleDebugStreamRef ModS(Modi, std::move(ModStreamData));
475 if (auto EC = ModS.reload())
476 return std::move(EC);
477
478 return std::move(ModS);
479}
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
This file defines the BumpPtrAllocator interface.
Lightweight arrays that are backed by an arbitrary BinaryStream.
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
Provides ErrorOr<T> smart pointer.
static DbiStream * getDbiStreamPtr(NativeSession &Session)
static Error validatePdbMagic(StringRef PdbPath)
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
void visit(MachineFunction &MF, MachineBasicBlock &Start, std::function< void(MachineBasicBlock *)> op)
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:159
static ErrorSuccess success()
Create a success value.
Definition Error.h:336
Tagged union holding either a T or a Error.
Definition Error.h:485
Error takeError()
Take ownership of the stored error.
Definition Error.h:612
reference get()
Returns a reference to the stored T value.
Definition Error.h:582
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:55
bool starts_with(StringRef Prefix) const
Check if this string starts with the given Prefix.
Definition StringRef.h:261
Error getDebugPDBInfo(const debug_directory *DebugDir, const codeview::DebugInfo *&Info, StringRef &PDBFileName) const
Get PDB information out of a codeview debug directory entry.
LLVM_ABI uint16_t getModuleStreamIndex() const
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
static std::unique_ptr< ConcreteT > createAs(const IPDBSession &PDBSession, std::unique_ptr< IPDBRawSymbol > RawSymbol)
Definition PDBSymbol.h:89
@ C
The default llvm calling convention, compatible with C.
Definition CallingConv.h:34
static const char Magic[]
Definition MSFCommon.h:24
LLVM_ABI 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
uint32_t SymIndexId
Definition PDBTypes.h:26
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
LLVM_ABI 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:474
LLVM_ABI StringRef filename(StringRef path LLVM_LIFETIME_BOUND, Style style=Style::native)
Get filename.
Definition Path.cpp:577
LLVM_ABI void append(SmallVectorImpl< char > &path, const Twine &a, const Twine &b="", const Twine &c="", const Twine &d="")
Append to path.
Definition Path.cpp:456
This is an optimization pass for GlobalISel generic memory operations.
LLVM_ABI 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:532
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:1655
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:643
Error make_error(ArgTs &&... Args)
Make a Error instance representing failure using the given error info type.
Definition Error.h:340
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:1867
void consumeError(Error Err)
Consume a Error without doing anything.
Definition Error.h:1083
Implement std::hash so that hash_code can be used in STL containers.
Definition BitVector.h:867
file_magic - An "enum class" enumeration of file types based on magic (the first N bytes of the file)...
Definition Magic.h:21
@ pdb
Windows PDB debug info file.
Definition Magic.h:55