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/NativeCompilandSymbol.h"
17 #include "llvm/DebugInfo/PDB/Native/NativeEnumInjectedSources.h"
18 #include "llvm/DebugInfo/PDB/Native/NativeEnumTypes.h"
19 #include "llvm/DebugInfo/PDB/Native/NativeExeSymbol.h"
20 #include "llvm/DebugInfo/PDB/Native/NativeTypeBuiltin.h"
21 #include "llvm/DebugInfo/PDB/Native/NativeTypeEnum.h"
22 #include "llvm/DebugInfo/PDB/Native/PDBFile.h"
23 #include "llvm/DebugInfo/PDB/Native/RawError.h"
24 #include "llvm/DebugInfo/PDB/Native/SymbolCache.h"
25 #include "llvm/DebugInfo/PDB/Native/TpiStream.h"
26 #include "llvm/DebugInfo/PDB/PDBSymbolCompiland.h"
27 #include "llvm/DebugInfo/PDB/PDBSymbolExe.h"
28 #include "llvm/DebugInfo/PDB/PDBSymbolTypeEnum.h"
29 #include "llvm/Object/COFF.h"
30 #include "llvm/Support/Allocator.h"
31 #include "llvm/Support/BinaryByteStream.h"
32 #include "llvm/Support/Error.h"
33 #include "llvm/Support/ErrorOr.h"
34 #include "llvm/Support/FileSystem.h"
35 #include "llvm/Support/MemoryBuffer.h"
36 #include "llvm/Support/Path.h"
37
38 #include <algorithm>
39 #include <cassert>
40 #include <memory>
41 #include <utility>
42
43 using namespace llvm;
44 using namespace llvm::msf;
45 using namespace llvm::pdb;
46
getDbiStreamPtr(PDBFile & File)47 static DbiStream *getDbiStreamPtr(PDBFile &File) {
48 Expected<DbiStream &> DbiS = File.getPDBDbiStream();
49 if (DbiS)
50 return &DbiS.get();
51
52 consumeError(DbiS.takeError());
53 return nullptr;
54 }
55
NativeSession(std::unique_ptr<PDBFile> PdbFile,std::unique_ptr<BumpPtrAllocator> Allocator)56 NativeSession::NativeSession(std::unique_ptr<PDBFile> PdbFile,
57 std::unique_ptr<BumpPtrAllocator> Allocator)
58 : Pdb(std::move(PdbFile)), Allocator(std::move(Allocator)),
59 Cache(*this, getDbiStreamPtr(*Pdb)) {}
60
61 NativeSession::~NativeSession() = default;
62
createFromPdb(std::unique_ptr<MemoryBuffer> Buffer,std::unique_ptr<IPDBSession> & Session)63 Error NativeSession::createFromPdb(std::unique_ptr<MemoryBuffer> Buffer,
64 std::unique_ptr<IPDBSession> &Session) {
65 StringRef Path = Buffer->getBufferIdentifier();
66 auto Stream = std::make_unique<MemoryBufferByteStream>(
67 std::move(Buffer), llvm::support::little);
68
69 auto Allocator = std::make_unique<BumpPtrAllocator>();
70 auto File = std::make_unique<PDBFile>(Path, std::move(Stream), *Allocator);
71 if (auto EC = File->parseFileHeaders())
72 return EC;
73 if (auto EC = File->parseStreamData())
74 return EC;
75
76 Session =
77 std::make_unique<NativeSession>(std::move(File), std::move(Allocator));
78
79 return Error::success();
80 }
81
82 static Expected<std::unique_ptr<PDBFile>>
loadPdbFile(StringRef PdbPath,std::unique_ptr<BumpPtrAllocator> & Allocator)83 loadPdbFile(StringRef PdbPath, std::unique_ptr<BumpPtrAllocator> &Allocator) {
84 ErrorOr<std::unique_ptr<MemoryBuffer>> ErrorOrBuffer =
85 MemoryBuffer::getFile(PdbPath, /*FileSize=*/-1,
86 /*RequiresNullTerminator=*/false);
87 if (!ErrorOrBuffer)
88 return make_error<RawError>(ErrorOrBuffer.getError());
89 std::unique_ptr<llvm::MemoryBuffer> Buffer = std::move(*ErrorOrBuffer);
90
91 PdbPath = Buffer->getBufferIdentifier();
92 file_magic Magic;
93 auto EC = identify_magic(PdbPath, Magic);
94 if (EC || Magic != file_magic::pdb)
95 return make_error<RawError>(EC);
96
97 auto Stream = std::make_unique<MemoryBufferByteStream>(std::move(Buffer),
98 llvm::support::little);
99
100 auto File = std::make_unique<PDBFile>(PdbPath, std::move(Stream), *Allocator);
101 if (auto EC = File->parseFileHeaders())
102 return std::move(EC);
103
104 if (auto EC = File->parseStreamData())
105 return std::move(EC);
106
107 return std::move(File);
108 }
109
createFromPdbPath(StringRef PdbPath,std::unique_ptr<IPDBSession> & Session)110 Error NativeSession::createFromPdbPath(StringRef PdbPath,
111 std::unique_ptr<IPDBSession> &Session) {
112 auto Allocator = std::make_unique<BumpPtrAllocator>();
113 auto PdbFile = loadPdbFile(PdbPath, Allocator);
114 if (!PdbFile)
115 return PdbFile.takeError();
116
117 Session = std::make_unique<NativeSession>(std::move(PdbFile.get()),
118 std::move(Allocator));
119 return Error::success();
120 }
121
getPdbPathFromExe(StringRef ExePath)122 static Expected<std::string> getPdbPathFromExe(StringRef ExePath) {
123 Expected<object::OwningBinary<object::Binary>> BinaryFile =
124 object::createBinary(ExePath);
125 if (!BinaryFile)
126 return BinaryFile.takeError();
127
128 const object::COFFObjectFile *ObjFile =
129 dyn_cast<object::COFFObjectFile>(BinaryFile->getBinary());
130 if (!ObjFile)
131 return make_error<RawError>(raw_error_code::invalid_format);
132
133 StringRef PdbPath;
134 const llvm::codeview::DebugInfo *PdbInfo = nullptr;
135 if (Error E = ObjFile->getDebugPDBInfo(PdbInfo, PdbPath))
136 return std::move(E);
137
138 return std::string(PdbPath);
139 }
140
createFromExe(StringRef ExePath,std::unique_ptr<IPDBSession> & Session)141 Error NativeSession::createFromExe(StringRef ExePath,
142 std::unique_ptr<IPDBSession> &Session) {
143 Expected<std::string> PdbPath = getPdbPathFromExe(ExePath);
144 if (!PdbPath)
145 return PdbPath.takeError();
146
147 file_magic Magic;
148 auto EC = identify_magic(PdbPath.get(), Magic);
149 if (EC || Magic != file_magic::pdb)
150 return make_error<RawError>(EC);
151
152 auto Allocator = std::make_unique<BumpPtrAllocator>();
153 auto File = loadPdbFile(PdbPath.get(), Allocator);
154 if (!File)
155 return File.takeError();
156
157 Session = std::make_unique<NativeSession>(std::move(File.get()),
158 std::move(Allocator));
159
160 return Error::success();
161 }
162
163 Expected<std::string>
searchForPdb(const PdbSearchOptions & Opts)164 NativeSession::searchForPdb(const PdbSearchOptions &Opts) {
165 Expected<std::string> PathOrErr = getPdbPathFromExe(Opts.ExePath);
166 if (!PathOrErr)
167 return PathOrErr.takeError();
168 StringRef PathFromExe = PathOrErr.get();
169 sys::path::Style Style = PathFromExe.startswith("/")
170 ? sys::path::Style::posix
171 : sys::path::Style::windows;
172 StringRef PdbName = sys::path::filename(PathFromExe, Style);
173
174 // Check if pdb exists in the executable directory.
175 SmallString<128> PdbPath = StringRef(Opts.ExePath);
176 sys::path::remove_filename(PdbPath);
177 sys::path::append(PdbPath, PdbName);
178
179 auto Allocator = std::make_unique<BumpPtrAllocator>();
180
181 if (auto File = loadPdbFile(PdbPath, Allocator))
182 return std::string(PdbPath);
183 else
184 consumeError(File.takeError());
185
186 // Check path that was in the executable.
187 if (auto File = loadPdbFile(PathFromExe, Allocator))
188 return std::string(PathFromExe);
189 else
190 return File.takeError();
191
192 return make_error<RawError>("PDB not found");
193 }
194
getLoadAddress() const195 uint64_t NativeSession::getLoadAddress() const { return LoadAddress; }
196
setLoadAddress(uint64_t Address)197 bool NativeSession::setLoadAddress(uint64_t Address) {
198 LoadAddress = Address;
199 return true;
200 }
201
getGlobalScope()202 std::unique_ptr<PDBSymbolExe> NativeSession::getGlobalScope() {
203 return PDBSymbol::createAs<PDBSymbolExe>(*this, getNativeGlobalScope());
204 }
205
206 std::unique_ptr<PDBSymbol>
getSymbolById(SymIndexId SymbolId) const207 NativeSession::getSymbolById(SymIndexId SymbolId) const {
208 return Cache.getSymbolById(SymbolId);
209 }
210
addressForVA(uint64_t VA,uint32_t & Section,uint32_t & Offset) const211 bool NativeSession::addressForVA(uint64_t VA, uint32_t &Section,
212 uint32_t &Offset) const {
213 uint32_t RVA = VA - getLoadAddress();
214 return addressForRVA(RVA, Section, Offset);
215 }
216
addressForRVA(uint32_t RVA,uint32_t & Section,uint32_t & Offset) const217 bool NativeSession::addressForRVA(uint32_t RVA, uint32_t &Section,
218 uint32_t &Offset) const {
219 Section = 0;
220 Offset = 0;
221
222 auto Dbi = Pdb->getPDBDbiStream();
223 if (!Dbi)
224 return false;
225
226 if ((int32_t)RVA < 0)
227 return true;
228
229 Offset = RVA;
230 for (; Section < Dbi->getSectionHeaders().size(); ++Section) {
231 auto &Sec = Dbi->getSectionHeaders()[Section];
232 if (RVA < Sec.VirtualAddress)
233 return true;
234 Offset = RVA - Sec.VirtualAddress;
235 }
236 return true;
237 }
238
239 std::unique_ptr<PDBSymbol>
findSymbolByAddress(uint64_t Address,PDB_SymType Type)240 NativeSession::findSymbolByAddress(uint64_t Address, PDB_SymType Type) {
241 uint32_t Section;
242 uint32_t Offset;
243 addressForVA(Address, Section, Offset);
244 return findSymbolBySectOffset(Section, Offset, Type);
245 }
246
findSymbolByRVA(uint32_t RVA,PDB_SymType Type)247 std::unique_ptr<PDBSymbol> NativeSession::findSymbolByRVA(uint32_t RVA,
248 PDB_SymType Type) {
249 uint32_t Section;
250 uint32_t Offset;
251 addressForRVA(RVA, Section, Offset);
252 return findSymbolBySectOffset(Section, Offset, Type);
253 }
254
255 std::unique_ptr<PDBSymbol>
findSymbolBySectOffset(uint32_t Sect,uint32_t Offset,PDB_SymType Type)256 NativeSession::findSymbolBySectOffset(uint32_t Sect, uint32_t Offset,
257 PDB_SymType Type) {
258 return Cache.findSymbolBySectOffset(Sect, Offset, Type);
259 }
260
261 std::unique_ptr<IPDBEnumLineNumbers>
findLineNumbers(const PDBSymbolCompiland & Compiland,const IPDBSourceFile & File) const262 NativeSession::findLineNumbers(const PDBSymbolCompiland &Compiland,
263 const IPDBSourceFile &File) const {
264 return nullptr;
265 }
266
267 std::unique_ptr<IPDBEnumLineNumbers>
findLineNumbersByAddress(uint64_t Address,uint32_t Length) const268 NativeSession::findLineNumbersByAddress(uint64_t Address,
269 uint32_t Length) const {
270 return Cache.findLineNumbersByVA(Address, Length);
271 }
272
273 std::unique_ptr<IPDBEnumLineNumbers>
findLineNumbersByRVA(uint32_t RVA,uint32_t Length) const274 NativeSession::findLineNumbersByRVA(uint32_t RVA, uint32_t Length) const {
275 return findLineNumbersByAddress(getLoadAddress() + RVA, Length);
276 }
277
278 std::unique_ptr<IPDBEnumLineNumbers>
findLineNumbersBySectOffset(uint32_t Section,uint32_t Offset,uint32_t Length) const279 NativeSession::findLineNumbersBySectOffset(uint32_t Section, uint32_t Offset,
280 uint32_t Length) const {
281 uint64_t VA = getVAFromSectOffset(Section, Offset);
282 return findLineNumbersByAddress(VA, Length);
283 }
284
285 std::unique_ptr<IPDBEnumSourceFiles>
findSourceFiles(const PDBSymbolCompiland * Compiland,StringRef Pattern,PDB_NameSearchFlags Flags) const286 NativeSession::findSourceFiles(const PDBSymbolCompiland *Compiland,
287 StringRef Pattern,
288 PDB_NameSearchFlags Flags) const {
289 return nullptr;
290 }
291
292 std::unique_ptr<IPDBSourceFile>
findOneSourceFile(const PDBSymbolCompiland * Compiland,StringRef Pattern,PDB_NameSearchFlags Flags) const293 NativeSession::findOneSourceFile(const PDBSymbolCompiland *Compiland,
294 StringRef Pattern,
295 PDB_NameSearchFlags Flags) const {
296 return nullptr;
297 }
298
299 std::unique_ptr<IPDBEnumChildren<PDBSymbolCompiland>>
findCompilandsForSourceFile(StringRef Pattern,PDB_NameSearchFlags Flags) const300 NativeSession::findCompilandsForSourceFile(StringRef Pattern,
301 PDB_NameSearchFlags Flags) const {
302 return nullptr;
303 }
304
305 std::unique_ptr<PDBSymbolCompiland>
findOneCompilandForSourceFile(StringRef Pattern,PDB_NameSearchFlags Flags) const306 NativeSession::findOneCompilandForSourceFile(StringRef Pattern,
307 PDB_NameSearchFlags Flags) const {
308 return nullptr;
309 }
310
getAllSourceFiles() const311 std::unique_ptr<IPDBEnumSourceFiles> NativeSession::getAllSourceFiles() const {
312 return nullptr;
313 }
314
getSourceFilesForCompiland(const PDBSymbolCompiland & Compiland) const315 std::unique_ptr<IPDBEnumSourceFiles> NativeSession::getSourceFilesForCompiland(
316 const PDBSymbolCompiland &Compiland) const {
317 return nullptr;
318 }
319
320 std::unique_ptr<IPDBSourceFile>
getSourceFileById(uint32_t FileId) const321 NativeSession::getSourceFileById(uint32_t FileId) const {
322 return Cache.getSourceFileById(FileId);
323 }
324
getDebugStreams() const325 std::unique_ptr<IPDBEnumDataStreams> NativeSession::getDebugStreams() const {
326 return nullptr;
327 }
328
getEnumTables() const329 std::unique_ptr<IPDBEnumTables> NativeSession::getEnumTables() const {
330 return nullptr;
331 }
332
333 std::unique_ptr<IPDBEnumInjectedSources>
getInjectedSources() const334 NativeSession::getInjectedSources() const {
335 auto ISS = Pdb->getInjectedSourceStream();
336 if (!ISS) {
337 consumeError(ISS.takeError());
338 return nullptr;
339 }
340 auto Strings = Pdb->getStringTable();
341 if (!Strings) {
342 consumeError(Strings.takeError());
343 return nullptr;
344 }
345 return std::make_unique<NativeEnumInjectedSources>(*Pdb, *ISS, *Strings);
346 }
347
348 std::unique_ptr<IPDBEnumSectionContribs>
getSectionContribs() const349 NativeSession::getSectionContribs() const {
350 return nullptr;
351 }
352
353 std::unique_ptr<IPDBEnumFrameData>
getFrameData() const354 NativeSession::getFrameData() const {
355 return nullptr;
356 }
357
initializeExeSymbol()358 void NativeSession::initializeExeSymbol() {
359 if (ExeSymbol == 0)
360 ExeSymbol = Cache.createSymbol<NativeExeSymbol>();
361 }
362
getNativeGlobalScope() const363 NativeExeSymbol &NativeSession::getNativeGlobalScope() const {
364 const_cast<NativeSession &>(*this).initializeExeSymbol();
365
366 return Cache.getNativeSymbolById<NativeExeSymbol>(ExeSymbol);
367 }
368
getRVAFromSectOffset(uint32_t Section,uint32_t Offset) const369 uint32_t NativeSession::getRVAFromSectOffset(uint32_t Section,
370 uint32_t Offset) const {
371 if (Section <= 0)
372 return 0;
373
374 auto Dbi = getDbiStreamPtr(*Pdb);
375 if (!Dbi)
376 return 0;
377
378 uint32_t MaxSection = Dbi->getSectionHeaders().size();
379 if (Section > MaxSection + 1)
380 Section = MaxSection + 1;
381 auto &Sec = Dbi->getSectionHeaders()[Section - 1];
382 return Sec.VirtualAddress + Offset;
383 }
384
getVAFromSectOffset(uint32_t Section,uint32_t Offset) const385 uint64_t NativeSession::getVAFromSectOffset(uint32_t Section,
386 uint32_t Offset) const {
387 return LoadAddress + getRVAFromSectOffset(Section, Offset);
388 }
389