xref: /freebsd/contrib/llvm-project/llvm/lib/DebugInfo/PDB/Native/NativeSession.cpp (revision a521f2116473fbd8c09db395518f060a27d02334)
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 
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 
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 
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>>
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 
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 
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 
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>
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 
195 uint64_t NativeSession::getLoadAddress() const { return LoadAddress; }
196 
197 bool NativeSession::setLoadAddress(uint64_t Address) {
198   LoadAddress = Address;
199   return true;
200 }
201 
202 std::unique_ptr<PDBSymbolExe> NativeSession::getGlobalScope() {
203   return PDBSymbol::createAs<PDBSymbolExe>(*this, getNativeGlobalScope());
204 }
205 
206 std::unique_ptr<PDBSymbol>
207 NativeSession::getSymbolById(SymIndexId SymbolId) const {
208   return Cache.getSymbolById(SymbolId);
209 }
210 
211 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 
217 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>
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 
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>
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>
262 NativeSession::findLineNumbers(const PDBSymbolCompiland &Compiland,
263                                const IPDBSourceFile &File) const {
264   return nullptr;
265 }
266 
267 std::unique_ptr<IPDBEnumLineNumbers>
268 NativeSession::findLineNumbersByAddress(uint64_t Address,
269                                         uint32_t Length) const {
270   return Cache.findLineNumbersByVA(Address, Length);
271 }
272 
273 std::unique_ptr<IPDBEnumLineNumbers>
274 NativeSession::findLineNumbersByRVA(uint32_t RVA, uint32_t Length) const {
275   return findLineNumbersByAddress(getLoadAddress() + RVA, Length);
276 }
277 
278 std::unique_ptr<IPDBEnumLineNumbers>
279 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>
286 NativeSession::findSourceFiles(const PDBSymbolCompiland *Compiland,
287                                StringRef Pattern,
288                                PDB_NameSearchFlags Flags) const {
289   return nullptr;
290 }
291 
292 std::unique_ptr<IPDBSourceFile>
293 NativeSession::findOneSourceFile(const PDBSymbolCompiland *Compiland,
294                                  StringRef Pattern,
295                                  PDB_NameSearchFlags Flags) const {
296   return nullptr;
297 }
298 
299 std::unique_ptr<IPDBEnumChildren<PDBSymbolCompiland>>
300 NativeSession::findCompilandsForSourceFile(StringRef Pattern,
301                                            PDB_NameSearchFlags Flags) const {
302   return nullptr;
303 }
304 
305 std::unique_ptr<PDBSymbolCompiland>
306 NativeSession::findOneCompilandForSourceFile(StringRef Pattern,
307                                              PDB_NameSearchFlags Flags) const {
308   return nullptr;
309 }
310 
311 std::unique_ptr<IPDBEnumSourceFiles> NativeSession::getAllSourceFiles() const {
312   return nullptr;
313 }
314 
315 std::unique_ptr<IPDBEnumSourceFiles> NativeSession::getSourceFilesForCompiland(
316     const PDBSymbolCompiland &Compiland) const {
317   return nullptr;
318 }
319 
320 std::unique_ptr<IPDBSourceFile>
321 NativeSession::getSourceFileById(uint32_t FileId) const {
322   return Cache.getSourceFileById(FileId);
323 }
324 
325 std::unique_ptr<IPDBEnumDataStreams> NativeSession::getDebugStreams() const {
326   return nullptr;
327 }
328 
329 std::unique_ptr<IPDBEnumTables> NativeSession::getEnumTables() const {
330   return nullptr;
331 }
332 
333 std::unique_ptr<IPDBEnumInjectedSources>
334 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>
349 NativeSession::getSectionContribs() const {
350   return nullptr;
351 }
352 
353 std::unique_ptr<IPDBEnumFrameData>
354 NativeSession::getFrameData() const {
355   return nullptr;
356 }
357 
358 void NativeSession::initializeExeSymbol() {
359   if (ExeSymbol == 0)
360     ExeSymbol = Cache.createSymbol<NativeExeSymbol>();
361 }
362 
363 NativeExeSymbol &NativeSession::getNativeGlobalScope() const {
364   const_cast<NativeSession &>(*this).initializeExeSymbol();
365 
366   return Cache.getNativeSymbolById<NativeExeSymbol>(ExeSymbol);
367 }
368 
369 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 
385 uint64_t NativeSession::getVAFromSectOffset(uint32_t Section,
386                                             uint32_t Offset) const {
387   return LoadAddress + getRVAFromSectOffset(Section, Offset);
388 }
389