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