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/MSFCommon.h"
14 #include "llvm/DebugInfo/MSF/MappedBlockStream.h"
15 #include "llvm/DebugInfo/PDB/IPDBEnumChildren.h"
16 #include "llvm/DebugInfo/PDB/IPDBSourceFile.h"
17 #include "llvm/DebugInfo/PDB/Native/DbiModuleDescriptor.h"
18 #include "llvm/DebugInfo/PDB/Native/DbiModuleList.h"
19 #include "llvm/DebugInfo/PDB/Native/DbiStream.h"
20 #include "llvm/DebugInfo/PDB/Native/ISectionContribVisitor.h"
21 #include "llvm/DebugInfo/PDB/Native/ModuleDebugStream.h"
22 #include "llvm/DebugInfo/PDB/Native/NativeEnumInjectedSources.h"
23 #include "llvm/DebugInfo/PDB/Native/NativeExeSymbol.h"
24 #include "llvm/DebugInfo/PDB/Native/PDBFile.h"
25 #include "llvm/DebugInfo/PDB/Native/RawConstants.h"
26 #include "llvm/DebugInfo/PDB/Native/RawError.h"
27 #include "llvm/DebugInfo/PDB/Native/RawTypes.h"
28 #include "llvm/DebugInfo/PDB/Native/SymbolCache.h"
29 #include "llvm/DebugInfo/PDB/PDBSymbol.h"
30 #include "llvm/DebugInfo/PDB/PDBSymbolCompiland.h"
31 #include "llvm/DebugInfo/PDB/PDBSymbolExe.h"
32 #include "llvm/Object/Binary.h"
33 #include "llvm/Object/COFF.h"
34 #include "llvm/Support/Allocator.h"
35 #include "llvm/Support/BinaryByteStream.h"
36 #include "llvm/Support/BinaryStreamArray.h"
37 #include "llvm/Support/Error.h"
38 #include "llvm/Support/ErrorOr.h"
39 #include "llvm/Support/MemoryBuffer.h"
40 #include "llvm/Support/Path.h"
41
42 #include <algorithm>
43 #include <cassert>
44 #include <memory>
45 #include <utility>
46
47 using namespace llvm;
48 using namespace llvm::msf;
49 using namespace llvm::pdb;
50
51 namespace llvm {
52 namespace codeview {
53 union DebugInfo;
54 }
55 } // namespace llvm
56
getDbiStreamPtr(PDBFile & File)57 static DbiStream *getDbiStreamPtr(PDBFile &File) {
58 Expected<DbiStream &> DbiS = File.getPDBDbiStream();
59 if (DbiS)
60 return &DbiS.get();
61
62 consumeError(DbiS.takeError());
63 return nullptr;
64 }
65
NativeSession(std::unique_ptr<PDBFile> PdbFile,std::unique_ptr<BumpPtrAllocator> Allocator)66 NativeSession::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
71 NativeSession::~NativeSession() = default;
72
createFromPdb(std::unique_ptr<MemoryBuffer> Buffer,std::unique_ptr<IPDBSession> & Session)73 Error 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
92 static Expected<std::unique_ptr<PDBFile>>
loadPdbFile(StringRef PdbPath,std::unique_ptr<BumpPtrAllocator> & Allocator)93 loadPdbFile(StringRef PdbPath, std::unique_ptr<BumpPtrAllocator> &Allocator) {
94 ErrorOr<std::unique_ptr<MemoryBuffer>> ErrorOrBuffer =
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();
102 file_magic Magic;
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
createFromPdbPath(StringRef PdbPath,std::unique_ptr<IPDBSession> & Session)120 Error NativeSession::createFromPdbPath(StringRef PdbPath,
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
getPdbPathFromExe(StringRef ExePath)132 static Expected<std::string> getPdbPathFromExe(StringRef ExePath) {
133 Expected<object::OwningBinary<object::Binary>> BinaryFile =
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
createFromExe(StringRef ExePath,std::unique_ptr<IPDBSession> & Session)151 Error NativeSession::createFromExe(StringRef ExePath,
152 std::unique_ptr<IPDBSession> &Session) {
153 Expected<std::string> PdbPath = getPdbPathFromExe(ExePath);
154 if (!PdbPath)
155 return PdbPath.takeError();
156
157 file_magic Magic;
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
173 Expected<std::string>
searchForPdb(const PdbSearchOptions & Opts)174 NativeSession::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("/")
180 ? sys::path::Style::posix
181 : sys::path::Style::windows;
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);
186 sys::path::remove_filename(PdbPath);
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
getLoadAddress() const205 uint64_t NativeSession::getLoadAddress() const { return LoadAddress; }
206
setLoadAddress(uint64_t Address)207 bool NativeSession::setLoadAddress(uint64_t Address) {
208 LoadAddress = Address;
209 return true;
210 }
211
getGlobalScope()212 std::unique_ptr<PDBSymbolExe> NativeSession::getGlobalScope() {
213 return PDBSymbol::createAs<PDBSymbolExe>(*this, getNativeGlobalScope());
214 }
215
216 std::unique_ptr<PDBSymbol>
getSymbolById(SymIndexId SymbolId) const217 NativeSession::getSymbolById(SymIndexId SymbolId) const {
218 return Cache.getSymbolById(SymbolId);
219 }
220
addressForVA(uint64_t VA,uint32_t & Section,uint32_t & Offset) const221 bool NativeSession::addressForVA(uint64_t VA, uint32_t &Section,
222 uint32_t &Offset) const {
223 uint32_t RVA = VA - getLoadAddress();
224 return addressForRVA(RVA, Section, Offset);
225 }
226
addressForRVA(uint32_t RVA,uint32_t & Section,uint32_t & Offset) const227 bool NativeSession::addressForRVA(uint32_t RVA, uint32_t &Section,
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
249 std::unique_ptr<PDBSymbol>
findSymbolByAddress(uint64_t Address,PDB_SymType Type)250 NativeSession::findSymbolByAddress(uint64_t Address, PDB_SymType Type) {
251 uint32_t Section;
252 uint32_t Offset;
253 addressForVA(Address, Section, Offset);
254 return findSymbolBySectOffset(Section, Offset, Type);
255 }
256
findSymbolByRVA(uint32_t RVA,PDB_SymType Type)257 std::unique_ptr<PDBSymbol> NativeSession::findSymbolByRVA(uint32_t RVA,
258 PDB_SymType Type) {
259 uint32_t Section;
260 uint32_t Offset;
261 addressForRVA(RVA, Section, Offset);
262 return findSymbolBySectOffset(Section, Offset, Type);
263 }
264
265 std::unique_ptr<PDBSymbol>
findSymbolBySectOffset(uint32_t Sect,uint32_t Offset,PDB_SymType Type)266 NativeSession::findSymbolBySectOffset(uint32_t Sect, uint32_t Offset,
267 PDB_SymType Type) {
268 if (AddrToModuleIndex.empty())
269 parseSectionContribs();
270
271 return Cache.findSymbolBySectOffset(Sect, Offset, Type);
272 }
273
274 std::unique_ptr<IPDBEnumLineNumbers>
findLineNumbers(const PDBSymbolCompiland & Compiland,const IPDBSourceFile & File) const275 NativeSession::findLineNumbers(const PDBSymbolCompiland &Compiland,
276 const IPDBSourceFile &File) const {
277 return nullptr;
278 }
279
280 std::unique_ptr<IPDBEnumLineNumbers>
findLineNumbersByAddress(uint64_t Address,uint32_t Length) const281 NativeSession::findLineNumbersByAddress(uint64_t Address,
282 uint32_t Length) const {
283 return Cache.findLineNumbersByVA(Address, Length);
284 }
285
286 std::unique_ptr<IPDBEnumLineNumbers>
findLineNumbersByRVA(uint32_t RVA,uint32_t Length) const287 NativeSession::findLineNumbersByRVA(uint32_t RVA, uint32_t Length) const {
288 return Cache.findLineNumbersByVA(getLoadAddress() + RVA, Length);
289 }
290
291 std::unique_ptr<IPDBEnumLineNumbers>
findLineNumbersBySectOffset(uint32_t Section,uint32_t Offset,uint32_t Length) const292 NativeSession::findLineNumbersBySectOffset(uint32_t Section, uint32_t Offset,
293 uint32_t Length) const {
294 uint64_t VA = getVAFromSectOffset(Section, Offset);
295 return Cache.findLineNumbersByVA(VA, Length);
296 }
297
298 std::unique_ptr<IPDBEnumSourceFiles>
findSourceFiles(const PDBSymbolCompiland * Compiland,StringRef Pattern,PDB_NameSearchFlags Flags) const299 NativeSession::findSourceFiles(const PDBSymbolCompiland *Compiland,
300 StringRef Pattern,
301 PDB_NameSearchFlags Flags) const {
302 return nullptr;
303 }
304
305 std::unique_ptr<IPDBSourceFile>
findOneSourceFile(const PDBSymbolCompiland * Compiland,StringRef Pattern,PDB_NameSearchFlags Flags) const306 NativeSession::findOneSourceFile(const PDBSymbolCompiland *Compiland,
307 StringRef Pattern,
308 PDB_NameSearchFlags Flags) const {
309 return nullptr;
310 }
311
312 std::unique_ptr<IPDBEnumChildren<PDBSymbolCompiland>>
findCompilandsForSourceFile(StringRef Pattern,PDB_NameSearchFlags Flags) const313 NativeSession::findCompilandsForSourceFile(StringRef Pattern,
314 PDB_NameSearchFlags Flags) const {
315 return nullptr;
316 }
317
318 std::unique_ptr<PDBSymbolCompiland>
findOneCompilandForSourceFile(StringRef Pattern,PDB_NameSearchFlags Flags) const319 NativeSession::findOneCompilandForSourceFile(StringRef Pattern,
320 PDB_NameSearchFlags Flags) const {
321 return nullptr;
322 }
323
getAllSourceFiles() const324 std::unique_ptr<IPDBEnumSourceFiles> NativeSession::getAllSourceFiles() const {
325 return nullptr;
326 }
327
getSourceFilesForCompiland(const PDBSymbolCompiland & Compiland) const328 std::unique_ptr<IPDBEnumSourceFiles> NativeSession::getSourceFilesForCompiland(
329 const PDBSymbolCompiland &Compiland) const {
330 return nullptr;
331 }
332
333 std::unique_ptr<IPDBSourceFile>
getSourceFileById(uint32_t FileId) const334 NativeSession::getSourceFileById(uint32_t FileId) const {
335 return Cache.getSourceFileById(FileId);
336 }
337
getDebugStreams() const338 std::unique_ptr<IPDBEnumDataStreams> NativeSession::getDebugStreams() const {
339 return nullptr;
340 }
341
getEnumTables() const342 std::unique_ptr<IPDBEnumTables> NativeSession::getEnumTables() const {
343 return nullptr;
344 }
345
346 std::unique_ptr<IPDBEnumInjectedSources>
getInjectedSources() const347 NativeSession::getInjectedSources() const {
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
361 std::unique_ptr<IPDBEnumSectionContribs>
getSectionContribs() const362 NativeSession::getSectionContribs() const {
363 return nullptr;
364 }
365
366 std::unique_ptr<IPDBEnumFrameData>
getFrameData() const367 NativeSession::getFrameData() const {
368 return nullptr;
369 }
370
initializeExeSymbol()371 void NativeSession::initializeExeSymbol() {
372 if (ExeSymbol == 0)
373 ExeSymbol = Cache.createSymbol<NativeExeSymbol>();
374 }
375
getNativeGlobalScope() const376 NativeExeSymbol &NativeSession::getNativeGlobalScope() const {
377 const_cast<NativeSession &>(*this).initializeExeSymbol();
378
379 return Cache.getNativeSymbolById<NativeExeSymbol>(ExeSymbol);
380 }
381
getRVAFromSectOffset(uint32_t Section,uint32_t Offset) const382 uint32_t NativeSession::getRVAFromSectOffset(uint32_t Section,
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
getVAFromSectOffset(uint32_t Section,uint32_t Offset) const398 uint64_t NativeSession::getVAFromSectOffset(uint32_t Section,
399 uint32_t Offset) const {
400 return LoadAddress + getRVAFromSectOffset(Section, Offset);
401 }
402
moduleIndexForVA(uint64_t VA,uint16_t & ModuleIndex) const403 bool NativeSession::moduleIndexForVA(uint64_t VA, uint16_t &ModuleIndex) const {
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
moduleIndexForSectOffset(uint32_t Sect,uint32_t Offset,uint16_t & ModuleIndex) const412 bool NativeSession::moduleIndexForSectOffset(uint32_t Sect, uint32_t Offset,
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
parseSectionContribs()422 void 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
453 Expected<ModuleDebugStreamRef>
getModuleDebugStream(uint32_t Index) const454 NativeSession::getModuleDebugStream(uint32_t Index) const {
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 }
473