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