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