1 //===- NativeSession.cpp - Native implementation of IPDBSession -*- C++ -*-===//
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
7 //===----------------------------------------------------------------------===//
9 #include "llvm/DebugInfo/PDB/Native/NativeSession.h"
11 #include "llvm/BinaryFormat/Magic.h"
12 #include "llvm/DebugInfo/MSF/MSFCommon.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"
47 using namespace llvm::msf
;
48 using namespace llvm::pdb
;
56 static DbiStream
*getDbiStreamPtr(PDBFile
&File
) {
57 Expected
<DbiStream
&> DbiS
= File
.getPDBDbiStream();
61 consumeError(DbiS
.takeError());
65 NativeSession::NativeSession(std::unique_ptr
<PDBFile
> PdbFile
,
66 std::unique_ptr
<BumpPtrAllocator
> Allocator
)
67 : Pdb(std::move(PdbFile
)), Allocator(std::move(Allocator
)),
68 Cache(*this, getDbiStreamPtr(*Pdb
)), AddrToModuleIndex(IMapAllocator
) {}
70 NativeSession::~NativeSession() = default;
72 Error
NativeSession::createFromPdb(std::unique_ptr
<MemoryBuffer
> Buffer
,
73 std::unique_ptr
<IPDBSession
> &Session
) {
74 StringRef Path
= Buffer
->getBufferIdentifier();
75 auto Stream
= std::make_unique
<MemoryBufferByteStream
>(
76 std::move(Buffer
), llvm::support::little
);
78 auto Allocator
= std::make_unique
<BumpPtrAllocator
>();
79 auto File
= std::make_unique
<PDBFile
>(Path
, std::move(Stream
), *Allocator
);
80 if (auto EC
= File
->parseFileHeaders())
82 if (auto EC
= File
->parseStreamData())
86 std::make_unique
<NativeSession
>(std::move(File
), std::move(Allocator
));
88 return Error::success();
91 static Expected
<std::unique_ptr
<PDBFile
>>
92 loadPdbFile(StringRef PdbPath
, std::unique_ptr
<BumpPtrAllocator
> &Allocator
) {
93 ErrorOr
<std::unique_ptr
<MemoryBuffer
>> ErrorOrBuffer
=
94 MemoryBuffer::getFile(PdbPath
, /*IsText=*/false,
95 /*RequiresNullTerminator=*/false);
97 return make_error
<RawError
>(ErrorOrBuffer
.getError());
98 std::unique_ptr
<llvm::MemoryBuffer
> Buffer
= std::move(*ErrorOrBuffer
);
100 PdbPath
= Buffer
->getBufferIdentifier();
102 auto EC
= identify_magic(PdbPath
, Magic
);
103 if (EC
|| Magic
!= file_magic::pdb
)
104 return make_error
<RawError
>(EC
);
106 auto Stream
= std::make_unique
<MemoryBufferByteStream
>(std::move(Buffer
),
107 llvm::support::little
);
109 auto File
= std::make_unique
<PDBFile
>(PdbPath
, std::move(Stream
), *Allocator
);
110 if (auto EC
= File
->parseFileHeaders())
111 return std::move(EC
);
113 if (auto EC
= File
->parseStreamData())
114 return std::move(EC
);
116 return std::move(File
);
119 Error
NativeSession::createFromPdbPath(StringRef PdbPath
,
120 std::unique_ptr
<IPDBSession
> &Session
) {
121 auto Allocator
= std::make_unique
<BumpPtrAllocator
>();
122 auto PdbFile
= loadPdbFile(PdbPath
, Allocator
);
124 return PdbFile
.takeError();
126 Session
= std::make_unique
<NativeSession
>(std::move(PdbFile
.get()),
127 std::move(Allocator
));
128 return Error::success();
131 static Expected
<std::string
> getPdbPathFromExe(StringRef ExePath
) {
132 Expected
<object::OwningBinary
<object::Binary
>> BinaryFile
=
133 object::createBinary(ExePath
);
135 return BinaryFile
.takeError();
137 const object::COFFObjectFile
*ObjFile
=
138 dyn_cast
<object::COFFObjectFile
>(BinaryFile
->getBinary());
140 return make_error
<RawError
>(raw_error_code::invalid_format
);
143 const llvm::codeview::DebugInfo
*PdbInfo
= nullptr;
144 if (Error E
= ObjFile
->getDebugPDBInfo(PdbInfo
, PdbPath
))
147 return std::string(PdbPath
);
150 Error
NativeSession::createFromExe(StringRef ExePath
,
151 std::unique_ptr
<IPDBSession
> &Session
) {
152 Expected
<std::string
> PdbPath
= getPdbPathFromExe(ExePath
);
154 return PdbPath
.takeError();
157 auto EC
= identify_magic(PdbPath
.get(), Magic
);
158 if (EC
|| Magic
!= file_magic::pdb
)
159 return make_error
<RawError
>(EC
);
161 auto Allocator
= std::make_unique
<BumpPtrAllocator
>();
162 auto File
= loadPdbFile(PdbPath
.get(), Allocator
);
164 return File
.takeError();
166 Session
= std::make_unique
<NativeSession
>(std::move(File
.get()),
167 std::move(Allocator
));
169 return Error::success();
172 Expected
<std::string
>
173 NativeSession::searchForPdb(const PdbSearchOptions
&Opts
) {
174 Expected
<std::string
> PathOrErr
= getPdbPathFromExe(Opts
.ExePath
);
176 return PathOrErr
.takeError();
177 StringRef PathFromExe
= PathOrErr
.get();
178 sys::path::Style Style
= PathFromExe
.startswith("/")
179 ? sys::path::Style::posix
180 : sys::path::Style::windows
;
181 StringRef PdbName
= sys::path::filename(PathFromExe
, Style
);
183 // Check if pdb exists in the executable directory.
184 SmallString
<128> PdbPath
= StringRef(Opts
.ExePath
);
185 sys::path::remove_filename(PdbPath
);
186 sys::path::append(PdbPath
, PdbName
);
188 auto Allocator
= std::make_unique
<BumpPtrAllocator
>();
190 if (auto File
= loadPdbFile(PdbPath
, Allocator
))
191 return std::string(PdbPath
);
193 consumeError(File
.takeError());
195 // Check path that was in the executable.
196 if (auto File
= loadPdbFile(PathFromExe
, Allocator
))
197 return std::string(PathFromExe
);
199 return File
.takeError();
201 return make_error
<RawError
>("PDB not found");
204 uint64_t NativeSession::getLoadAddress() const { return LoadAddress
; }
206 bool NativeSession::setLoadAddress(uint64_t Address
) {
207 LoadAddress
= Address
;
211 std::unique_ptr
<PDBSymbolExe
> NativeSession::getGlobalScope() {
212 return PDBSymbol::createAs
<PDBSymbolExe
>(*this, getNativeGlobalScope());
215 std::unique_ptr
<PDBSymbol
>
216 NativeSession::getSymbolById(SymIndexId SymbolId
) const {
217 return Cache
.getSymbolById(SymbolId
);
220 bool NativeSession::addressForVA(uint64_t VA
, uint32_t &Section
,
221 uint32_t &Offset
) const {
222 uint32_t RVA
= VA
- getLoadAddress();
223 return addressForRVA(RVA
, Section
, Offset
);
226 bool NativeSession::addressForRVA(uint32_t RVA
, uint32_t &Section
,
227 uint32_t &Offset
) const {
231 auto Dbi
= Pdb
->getPDBDbiStream();
235 if ((int32_t)RVA
< 0)
239 for (; Section
< Dbi
->getSectionHeaders().size(); ++Section
) {
240 auto &Sec
= Dbi
->getSectionHeaders()[Section
];
241 if (RVA
< Sec
.VirtualAddress
)
243 Offset
= RVA
- Sec
.VirtualAddress
;
248 std::unique_ptr
<PDBSymbol
>
249 NativeSession::findSymbolByAddress(uint64_t Address
, PDB_SymType Type
) {
252 addressForVA(Address
, Section
, Offset
);
253 return findSymbolBySectOffset(Section
, Offset
, Type
);
256 std::unique_ptr
<PDBSymbol
> NativeSession::findSymbolByRVA(uint32_t RVA
,
260 addressForRVA(RVA
, Section
, Offset
);
261 return findSymbolBySectOffset(Section
, Offset
, Type
);
264 std::unique_ptr
<PDBSymbol
>
265 NativeSession::findSymbolBySectOffset(uint32_t Sect
, uint32_t Offset
,
267 if (AddrToModuleIndex
.empty())
268 parseSectionContribs();
270 return Cache
.findSymbolBySectOffset(Sect
, Offset
, Type
);
273 std::unique_ptr
<IPDBEnumLineNumbers
>
274 NativeSession::findLineNumbers(const PDBSymbolCompiland
&Compiland
,
275 const IPDBSourceFile
&File
) const {
279 std::unique_ptr
<IPDBEnumLineNumbers
>
280 NativeSession::findLineNumbersByAddress(uint64_t Address
,
281 uint32_t Length
) const {
282 return Cache
.findLineNumbersByVA(Address
, Length
);
285 std::unique_ptr
<IPDBEnumLineNumbers
>
286 NativeSession::findLineNumbersByRVA(uint32_t RVA
, uint32_t Length
) const {
287 return Cache
.findLineNumbersByVA(getLoadAddress() + RVA
, Length
);
290 std::unique_ptr
<IPDBEnumLineNumbers
>
291 NativeSession::findLineNumbersBySectOffset(uint32_t Section
, uint32_t Offset
,
292 uint32_t Length
) const {
293 uint64_t VA
= getVAFromSectOffset(Section
, Offset
);
294 return Cache
.findLineNumbersByVA(VA
, Length
);
297 std::unique_ptr
<IPDBEnumSourceFiles
>
298 NativeSession::findSourceFiles(const PDBSymbolCompiland
*Compiland
,
300 PDB_NameSearchFlags Flags
) const {
304 std::unique_ptr
<IPDBSourceFile
>
305 NativeSession::findOneSourceFile(const PDBSymbolCompiland
*Compiland
,
307 PDB_NameSearchFlags Flags
) const {
311 std::unique_ptr
<IPDBEnumChildren
<PDBSymbolCompiland
>>
312 NativeSession::findCompilandsForSourceFile(StringRef Pattern
,
313 PDB_NameSearchFlags Flags
) const {
317 std::unique_ptr
<PDBSymbolCompiland
>
318 NativeSession::findOneCompilandForSourceFile(StringRef Pattern
,
319 PDB_NameSearchFlags Flags
) const {
323 std::unique_ptr
<IPDBEnumSourceFiles
> NativeSession::getAllSourceFiles() const {
327 std::unique_ptr
<IPDBEnumSourceFiles
> NativeSession::getSourceFilesForCompiland(
328 const PDBSymbolCompiland
&Compiland
) const {
332 std::unique_ptr
<IPDBSourceFile
>
333 NativeSession::getSourceFileById(uint32_t FileId
) const {
334 return Cache
.getSourceFileById(FileId
);
337 std::unique_ptr
<IPDBEnumDataStreams
> NativeSession::getDebugStreams() const {
341 std::unique_ptr
<IPDBEnumTables
> NativeSession::getEnumTables() const {
345 std::unique_ptr
<IPDBEnumInjectedSources
>
346 NativeSession::getInjectedSources() const {
347 auto ISS
= Pdb
->getInjectedSourceStream();
349 consumeError(ISS
.takeError());
352 auto Strings
= Pdb
->getStringTable();
354 consumeError(Strings
.takeError());
357 return std::make_unique
<NativeEnumInjectedSources
>(*Pdb
, *ISS
, *Strings
);
360 std::unique_ptr
<IPDBEnumSectionContribs
>
361 NativeSession::getSectionContribs() const {
365 std::unique_ptr
<IPDBEnumFrameData
>
366 NativeSession::getFrameData() const {
370 void NativeSession::initializeExeSymbol() {
372 ExeSymbol
= Cache
.createSymbol
<NativeExeSymbol
>();
375 NativeExeSymbol
&NativeSession::getNativeGlobalScope() const {
376 const_cast<NativeSession
&>(*this).initializeExeSymbol();
378 return Cache
.getNativeSymbolById
<NativeExeSymbol
>(ExeSymbol
);
381 uint32_t NativeSession::getRVAFromSectOffset(uint32_t Section
,
382 uint32_t Offset
) const {
386 auto Dbi
= getDbiStreamPtr(*Pdb
);
390 uint32_t MaxSection
= Dbi
->getSectionHeaders().size();
391 if (Section
> MaxSection
+ 1)
392 Section
= MaxSection
+ 1;
393 auto &Sec
= Dbi
->getSectionHeaders()[Section
- 1];
394 return Sec
.VirtualAddress
+ Offset
;
397 uint64_t NativeSession::getVAFromSectOffset(uint32_t Section
,
398 uint32_t Offset
) const {
399 return LoadAddress
+ getRVAFromSectOffset(Section
, Offset
);
402 bool NativeSession::moduleIndexForVA(uint64_t VA
, uint16_t &ModuleIndex
) const {
404 auto Iter
= AddrToModuleIndex
.find(VA
);
405 if (Iter
== AddrToModuleIndex
.end())
407 ModuleIndex
= Iter
.value();
411 bool NativeSession::moduleIndexForSectOffset(uint32_t Sect
, uint32_t Offset
,
412 uint16_t &ModuleIndex
) const {
414 auto Iter
= AddrToModuleIndex
.find(getVAFromSectOffset(Sect
, Offset
));
415 if (Iter
== AddrToModuleIndex
.end())
417 ModuleIndex
= Iter
.value();
421 void NativeSession::parseSectionContribs() {
422 auto Dbi
= Pdb
->getPDBDbiStream();
426 class Visitor
: public ISectionContribVisitor
{
427 NativeSession
&Session
;
431 Visitor(NativeSession
&Session
, IMap
&AddrMap
)
432 : Session(Session
), AddrMap(AddrMap
) {}
433 void visit(const SectionContrib
&C
) override
{
437 uint64_t VA
= Session
.getVAFromSectOffset(C
.ISect
, C
.Off
);
438 uint64_t End
= VA
+ C
.Size
;
440 // Ignore overlapping sections based on the assumption that a valid
441 // PDB file should not have overlaps.
442 if (!AddrMap
.overlaps(VA
, End
))
443 AddrMap
.insert(VA
, End
, C
.Imod
);
445 void visit(const SectionContrib2
&C
) override
{ visit(C
.Base
); }
448 Visitor
V(*this, AddrToModuleIndex
);
449 Dbi
->visitSectionContributions(V
);
452 Expected
<ModuleDebugStreamRef
>
453 NativeSession::getModuleDebugStream(uint32_t Index
) const {
454 auto *Dbi
= getDbiStreamPtr(*Pdb
);
455 assert(Dbi
&& "Dbi stream not present");
457 DbiModuleDescriptor Modi
= Dbi
->modules().getModuleDescriptor(Index
);
459 uint16_t ModiStream
= Modi
.getModuleStreamIndex();
460 if (ModiStream
== kInvalidStreamIndex
)
461 return make_error
<RawError
>("Module stream not present");
463 std::unique_ptr
<msf::MappedBlockStream
> ModStreamData
=
464 Pdb
->createIndexedStream(ModiStream
);
466 ModuleDebugStreamRef
ModS(Modi
, std::move(ModStreamData
));
467 if (auto EC
= ModS
.reload())
468 return std::move(EC
);
470 return std::move(ModS
);