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/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"
40
41 #include <algorithm>
42 #include <cassert>
43 #include <memory>
44 #include <utility>
45
46 using namespace llvm;
47 using namespace llvm::msf;
48 using namespace llvm::pdb;
49
50 namespace llvm {
51 namespace codeview {
52 union DebugInfo;
53 }
54 } // namespace llvm
55
getDbiStreamPtr(PDBFile & File)56 static DbiStream *getDbiStreamPtr(PDBFile &File) {
57 Expected<DbiStream &> DbiS = File.getPDBDbiStream();
58 if (DbiS)
59 return &DbiS.get();
60
61 consumeError(DbiS.takeError());
62 return nullptr;
63 }
64
NativeSession(std::unique_ptr<PDBFile> PdbFile,std::unique_ptr<BumpPtrAllocator> Allocator)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) {}
69
70 NativeSession::~NativeSession() = default;
71
createFromPdb(std::unique_ptr<MemoryBuffer> Buffer,std::unique_ptr<IPDBSession> & Session)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);
77
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())
81 return EC;
82 if (auto EC = File->parseStreamData())
83 return EC;
84
85 Session =
86 std::make_unique<NativeSession>(std::move(File), std::move(Allocator));
87
88 return Error::success();
89 }
90
91 static Expected<std::unique_ptr<PDBFile>>
loadPdbFile(StringRef PdbPath,std::unique_ptr<BumpPtrAllocator> & Allocator)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);
96 if (!ErrorOrBuffer)
97 return make_error<RawError>(ErrorOrBuffer.getError());
98 std::unique_ptr<llvm::MemoryBuffer> Buffer = std::move(*ErrorOrBuffer);
99
100 PdbPath = Buffer->getBufferIdentifier();
101 file_magic Magic;
102 auto EC = identify_magic(PdbPath, Magic);
103 if (EC || Magic != file_magic::pdb)
104 return make_error<RawError>(EC);
105
106 auto Stream = std::make_unique<MemoryBufferByteStream>(std::move(Buffer),
107 llvm::support::little);
108
109 auto File = std::make_unique<PDBFile>(PdbPath, std::move(Stream), *Allocator);
110 if (auto EC = File->parseFileHeaders())
111 return std::move(EC);
112
113 if (auto EC = File->parseStreamData())
114 return std::move(EC);
115
116 return std::move(File);
117 }
118
createFromPdbPath(StringRef PdbPath,std::unique_ptr<IPDBSession> & Session)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);
123 if (!PdbFile)
124 return PdbFile.takeError();
125
126 Session = std::make_unique<NativeSession>(std::move(PdbFile.get()),
127 std::move(Allocator));
128 return Error::success();
129 }
130
getPdbPathFromExe(StringRef ExePath)131 static Expected<std::string> getPdbPathFromExe(StringRef ExePath) {
132 Expected<object::OwningBinary<object::Binary>> BinaryFile =
133 object::createBinary(ExePath);
134 if (!BinaryFile)
135 return BinaryFile.takeError();
136
137 const object::COFFObjectFile *ObjFile =
138 dyn_cast<object::COFFObjectFile>(BinaryFile->getBinary());
139 if (!ObjFile)
140 return make_error<RawError>(raw_error_code::invalid_format);
141
142 StringRef PdbPath;
143 const llvm::codeview::DebugInfo *PdbInfo = nullptr;
144 if (Error E = ObjFile->getDebugPDBInfo(PdbInfo, PdbPath))
145 return std::move(E);
146
147 return std::string(PdbPath);
148 }
149
createFromExe(StringRef ExePath,std::unique_ptr<IPDBSession> & Session)150 Error NativeSession::createFromExe(StringRef ExePath,
151 std::unique_ptr<IPDBSession> &Session) {
152 Expected<std::string> PdbPath = getPdbPathFromExe(ExePath);
153 if (!PdbPath)
154 return PdbPath.takeError();
155
156 file_magic Magic;
157 auto EC = identify_magic(PdbPath.get(), Magic);
158 if (EC || Magic != file_magic::pdb)
159 return make_error<RawError>(EC);
160
161 auto Allocator = std::make_unique<BumpPtrAllocator>();
162 auto File = loadPdbFile(PdbPath.get(), Allocator);
163 if (!File)
164 return File.takeError();
165
166 Session = std::make_unique<NativeSession>(std::move(File.get()),
167 std::move(Allocator));
168
169 return Error::success();
170 }
171
172 Expected<std::string>
searchForPdb(const PdbSearchOptions & Opts)173 NativeSession::searchForPdb(const PdbSearchOptions &Opts) {
174 Expected<std::string> PathOrErr = getPdbPathFromExe(Opts.ExePath);
175 if (!PathOrErr)
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);
182
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);
187
188 auto Allocator = std::make_unique<BumpPtrAllocator>();
189
190 if (auto File = loadPdbFile(PdbPath, Allocator))
191 return std::string(PdbPath);
192 else
193 consumeError(File.takeError());
194
195 // Check path that was in the executable.
196 if (auto File = loadPdbFile(PathFromExe, Allocator))
197 return std::string(PathFromExe);
198 else
199 return File.takeError();
200
201 return make_error<RawError>("PDB not found");
202 }
203
getLoadAddress() const204 uint64_t NativeSession::getLoadAddress() const { return LoadAddress; }
205
setLoadAddress(uint64_t Address)206 bool NativeSession::setLoadAddress(uint64_t Address) {
207 LoadAddress = Address;
208 return true;
209 }
210
getGlobalScope()211 std::unique_ptr<PDBSymbolExe> NativeSession::getGlobalScope() {
212 return PDBSymbol::createAs<PDBSymbolExe>(*this, getNativeGlobalScope());
213 }
214
215 std::unique_ptr<PDBSymbol>
getSymbolById(SymIndexId SymbolId) const216 NativeSession::getSymbolById(SymIndexId SymbolId) const {
217 return Cache.getSymbolById(SymbolId);
218 }
219
addressForVA(uint64_t VA,uint32_t & Section,uint32_t & Offset) const220 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);
224 }
225
addressForRVA(uint32_t RVA,uint32_t & Section,uint32_t & Offset) const226 bool NativeSession::addressForRVA(uint32_t RVA, uint32_t &Section,
227 uint32_t &Offset) const {
228 Section = 0;
229 Offset = 0;
230
231 auto Dbi = Pdb->getPDBDbiStream();
232 if (!Dbi)
233 return false;
234
235 if ((int32_t)RVA < 0)
236 return true;
237
238 Offset = RVA;
239 for (; Section < Dbi->getSectionHeaders().size(); ++Section) {
240 auto &Sec = Dbi->getSectionHeaders()[Section];
241 if (RVA < Sec.VirtualAddress)
242 return true;
243 Offset = RVA - Sec.VirtualAddress;
244 }
245 return true;
246 }
247
248 std::unique_ptr<PDBSymbol>
findSymbolByAddress(uint64_t Address,PDB_SymType Type)249 NativeSession::findSymbolByAddress(uint64_t Address, PDB_SymType Type) {
250 uint32_t Section;
251 uint32_t Offset;
252 addressForVA(Address, Section, Offset);
253 return findSymbolBySectOffset(Section, Offset, Type);
254 }
255
findSymbolByRVA(uint32_t RVA,PDB_SymType Type)256 std::unique_ptr<PDBSymbol> NativeSession::findSymbolByRVA(uint32_t RVA,
257 PDB_SymType Type) {
258 uint32_t Section;
259 uint32_t Offset;
260 addressForRVA(RVA, Section, Offset);
261 return findSymbolBySectOffset(Section, Offset, Type);
262 }
263
264 std::unique_ptr<PDBSymbol>
findSymbolBySectOffset(uint32_t Sect,uint32_t Offset,PDB_SymType Type)265 NativeSession::findSymbolBySectOffset(uint32_t Sect, uint32_t Offset,
266 PDB_SymType Type) {
267 if (AddrToModuleIndex.empty())
268 parseSectionContribs();
269
270 return Cache.findSymbolBySectOffset(Sect, Offset, Type);
271 }
272
273 std::unique_ptr<IPDBEnumLineNumbers>
findLineNumbers(const PDBSymbolCompiland & Compiland,const IPDBSourceFile & File) const274 NativeSession::findLineNumbers(const PDBSymbolCompiland &Compiland,
275 const IPDBSourceFile &File) const {
276 return nullptr;
277 }
278
279 std::unique_ptr<IPDBEnumLineNumbers>
findLineNumbersByAddress(uint64_t Address,uint32_t Length) const280 NativeSession::findLineNumbersByAddress(uint64_t Address,
281 uint32_t Length) const {
282 return Cache.findLineNumbersByVA(Address, Length);
283 }
284
285 std::unique_ptr<IPDBEnumLineNumbers>
findLineNumbersByRVA(uint32_t RVA,uint32_t Length) const286 NativeSession::findLineNumbersByRVA(uint32_t RVA, uint32_t Length) const {
287 return Cache.findLineNumbersByVA(getLoadAddress() + RVA, Length);
288 }
289
290 std::unique_ptr<IPDBEnumLineNumbers>
findLineNumbersBySectOffset(uint32_t Section,uint32_t Offset,uint32_t Length) const291 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);
295 }
296
297 std::unique_ptr<IPDBEnumSourceFiles>
findSourceFiles(const PDBSymbolCompiland * Compiland,StringRef Pattern,PDB_NameSearchFlags Flags) const298 NativeSession::findSourceFiles(const PDBSymbolCompiland *Compiland,
299 StringRef Pattern,
300 PDB_NameSearchFlags Flags) const {
301 return nullptr;
302 }
303
304 std::unique_ptr<IPDBSourceFile>
findOneSourceFile(const PDBSymbolCompiland * Compiland,StringRef Pattern,PDB_NameSearchFlags Flags) const305 NativeSession::findOneSourceFile(const PDBSymbolCompiland *Compiland,
306 StringRef Pattern,
307 PDB_NameSearchFlags Flags) const {
308 return nullptr;
309 }
310
311 std::unique_ptr<IPDBEnumChildren<PDBSymbolCompiland>>
findCompilandsForSourceFile(StringRef Pattern,PDB_NameSearchFlags Flags) const312 NativeSession::findCompilandsForSourceFile(StringRef Pattern,
313 PDB_NameSearchFlags Flags) const {
314 return nullptr;
315 }
316
317 std::unique_ptr<PDBSymbolCompiland>
findOneCompilandForSourceFile(StringRef Pattern,PDB_NameSearchFlags Flags) const318 NativeSession::findOneCompilandForSourceFile(StringRef Pattern,
319 PDB_NameSearchFlags Flags) const {
320 return nullptr;
321 }
322
getAllSourceFiles() const323 std::unique_ptr<IPDBEnumSourceFiles> NativeSession::getAllSourceFiles() const {
324 return nullptr;
325 }
326
getSourceFilesForCompiland(const PDBSymbolCompiland & Compiland) const327 std::unique_ptr<IPDBEnumSourceFiles> NativeSession::getSourceFilesForCompiland(
328 const PDBSymbolCompiland &Compiland) const {
329 return nullptr;
330 }
331
332 std::unique_ptr<IPDBSourceFile>
getSourceFileById(uint32_t FileId) const333 NativeSession::getSourceFileById(uint32_t FileId) const {
334 return Cache.getSourceFileById(FileId);
335 }
336
getDebugStreams() const337 std::unique_ptr<IPDBEnumDataStreams> NativeSession::getDebugStreams() const {
338 return nullptr;
339 }
340
getEnumTables() const341 std::unique_ptr<IPDBEnumTables> NativeSession::getEnumTables() const {
342 return nullptr;
343 }
344
345 std::unique_ptr<IPDBEnumInjectedSources>
getInjectedSources() const346 NativeSession::getInjectedSources() const {
347 auto ISS = Pdb->getInjectedSourceStream();
348 if (!ISS) {
349 consumeError(ISS.takeError());
350 return nullptr;
351 }
352 auto Strings = Pdb->getStringTable();
353 if (!Strings) {
354 consumeError(Strings.takeError());
355 return nullptr;
356 }
357 return std::make_unique<NativeEnumInjectedSources>(*Pdb, *ISS, *Strings);
358 }
359
360 std::unique_ptr<IPDBEnumSectionContribs>
getSectionContribs() const361 NativeSession::getSectionContribs() const {
362 return nullptr;
363 }
364
365 std::unique_ptr<IPDBEnumFrameData>
getFrameData() const366 NativeSession::getFrameData() const {
367 return nullptr;
368 }
369
initializeExeSymbol()370 void NativeSession::initializeExeSymbol() {
371 if (ExeSymbol == 0)
372 ExeSymbol = Cache.createSymbol<NativeExeSymbol>();
373 }
374
getNativeGlobalScope() const375 NativeExeSymbol &NativeSession::getNativeGlobalScope() const {
376 const_cast<NativeSession &>(*this).initializeExeSymbol();
377
378 return Cache.getNativeSymbolById<NativeExeSymbol>(ExeSymbol);
379 }
380
getRVAFromSectOffset(uint32_t Section,uint32_t Offset) const381 uint32_t NativeSession::getRVAFromSectOffset(uint32_t Section,
382 uint32_t Offset) const {
383 if (Section <= 0)
384 return 0;
385
386 auto Dbi = getDbiStreamPtr(*Pdb);
387 if (!Dbi)
388 return 0;
389
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;
395 }
396
getVAFromSectOffset(uint32_t Section,uint32_t Offset) const397 uint64_t NativeSession::getVAFromSectOffset(uint32_t Section,
398 uint32_t Offset) const {
399 return LoadAddress + getRVAFromSectOffset(Section, Offset);
400 }
401
moduleIndexForVA(uint64_t VA,uint16_t & ModuleIndex) const402 bool NativeSession::moduleIndexForVA(uint64_t VA, uint16_t &ModuleIndex) const {
403 ModuleIndex = 0;
404 auto Iter = AddrToModuleIndex.find(VA);
405 if (Iter == AddrToModuleIndex.end())
406 return false;
407 ModuleIndex = Iter.value();
408 return true;
409 }
410
moduleIndexForSectOffset(uint32_t Sect,uint32_t Offset,uint16_t & ModuleIndex) const411 bool NativeSession::moduleIndexForSectOffset(uint32_t Sect, uint32_t Offset,
412 uint16_t &ModuleIndex) const {
413 ModuleIndex = 0;
414 auto Iter = AddrToModuleIndex.find(getVAFromSectOffset(Sect, Offset));
415 if (Iter == AddrToModuleIndex.end())
416 return false;
417 ModuleIndex = Iter.value();
418 return true;
419 }
420
parseSectionContribs()421 void NativeSession::parseSectionContribs() {
422 auto Dbi = Pdb->getPDBDbiStream();
423 if (!Dbi)
424 return;
425
426 class Visitor : public ISectionContribVisitor {
427 NativeSession &Session;
428 IMap &AddrMap;
429
430 public:
431 Visitor(NativeSession &Session, IMap &AddrMap)
432 : Session(Session), AddrMap(AddrMap) {}
433 void visit(const SectionContrib &C) override {
434 if (C.Size == 0)
435 return;
436
437 uint64_t VA = Session.getVAFromSectOffset(C.ISect, C.Off);
438 uint64_t End = VA + C.Size;
439
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);
444 }
445 void visit(const SectionContrib2 &C) override { visit(C.Base); }
446 };
447
448 Visitor V(*this, AddrToModuleIndex);
449 Dbi->visitSectionContributions(V);
450 }
451
452 Expected<ModuleDebugStreamRef>
getModuleDebugStream(uint32_t Index) const453 NativeSession::getModuleDebugStream(uint32_t Index) const {
454 auto *Dbi = getDbiStreamPtr(*Pdb);
455 assert(Dbi && "Dbi stream not present");
456
457 DbiModuleDescriptor Modi = Dbi->modules().getModuleDescriptor(Index);
458
459 uint16_t ModiStream = Modi.getModuleStreamIndex();
460 if (ModiStream == kInvalidStreamIndex)
461 return make_error<RawError>("Module stream not present");
462
463 std::unique_ptr<msf::MappedBlockStream> ModStreamData =
464 Pdb->createIndexedStream(ModiStream);
465
466 ModuleDebugStreamRef ModS(Modi, std::move(ModStreamData));
467 if (auto EC = ModS.reload())
468 return std::move(EC);
469
470 return std::move(ModS);
471 }
472