xref: /llvm-project/llvm/lib/DebugInfo/PDB/Native/NativeSession.cpp (revision a13dce1d90cba6c55252dee0a2600eab37ffbc44)
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 (auto EC = ObjFile->getDebugPDBInfo(PdbInfo, PdbPath))
136     return make_error<RawError>(EC);
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 PdbName = sys::path::filename(PathOrErr.get());
169 
170   // Check if pdb exists in the executable directory.
171   SmallString<128> PdbPath = StringRef(Opts.ExePath);
172   sys::path::remove_filename(PdbPath);
173   sys::path::append(PdbPath, PdbName);
174 
175   auto Allocator = std::make_unique<BumpPtrAllocator>();
176   if (loadPdbFile(PdbPath, Allocator))
177     return std::string(PdbPath);
178 
179   return make_error<RawError>("PDB not found");
180 }
181 
182 uint64_t NativeSession::getLoadAddress() const { return LoadAddress; }
183 
184 bool NativeSession::setLoadAddress(uint64_t Address) {
185   LoadAddress = Address;
186   return true;
187 }
188 
189 std::unique_ptr<PDBSymbolExe> NativeSession::getGlobalScope() {
190   return PDBSymbol::createAs<PDBSymbolExe>(*this, getNativeGlobalScope());
191 }
192 
193 std::unique_ptr<PDBSymbol>
194 NativeSession::getSymbolById(SymIndexId SymbolId) const {
195   return Cache.getSymbolById(SymbolId);
196 }
197 
198 bool NativeSession::addressForVA(uint64_t VA, uint32_t &Section,
199                                  uint32_t &Offset) const {
200   uint32_t RVA = VA - getLoadAddress();
201   return addressForRVA(RVA, Section, Offset);
202 }
203 
204 bool NativeSession::addressForRVA(uint32_t RVA, uint32_t &Section,
205                                   uint32_t &Offset) const {
206   auto Dbi = Pdb->getPDBDbiStream();
207   if (!Dbi)
208     return false;
209 
210   Section = 0;
211   Offset = 0;
212 
213   if ((int32_t)RVA < 0)
214     return true;
215 
216   Offset = RVA;
217   for (; Section < Dbi->getSectionHeaders().size(); ++Section) {
218     auto &Sec = Dbi->getSectionHeaders()[Section];
219     if (RVA < Sec.VirtualAddress)
220       return true;
221     Offset = RVA - Sec.VirtualAddress;
222   }
223   return true;
224 }
225 
226 std::unique_ptr<PDBSymbol>
227 NativeSession::findSymbolByAddress(uint64_t Address, PDB_SymType Type) const {
228   return nullptr;
229 }
230 
231 std::unique_ptr<PDBSymbol>
232 NativeSession::findSymbolByRVA(uint32_t RVA, PDB_SymType Type) const {
233   return nullptr;
234 }
235 
236 std::unique_ptr<PDBSymbol>
237 NativeSession::findSymbolBySectOffset(uint32_t Sect, uint32_t Offset,
238                                       PDB_SymType Type) const {
239   return nullptr;
240 }
241 
242 std::unique_ptr<IPDBEnumLineNumbers>
243 NativeSession::findLineNumbers(const PDBSymbolCompiland &Compiland,
244                                const IPDBSourceFile &File) const {
245   return nullptr;
246 }
247 
248 std::unique_ptr<IPDBEnumLineNumbers>
249 NativeSession::findLineNumbersByAddress(uint64_t Address,
250                                         uint32_t Length) const {
251   return nullptr;
252 }
253 
254 std::unique_ptr<IPDBEnumLineNumbers>
255 NativeSession::findLineNumbersByRVA(uint32_t RVA, uint32_t Length) const {
256   return nullptr;
257 }
258 
259 std::unique_ptr<IPDBEnumLineNumbers>
260 NativeSession::findLineNumbersBySectOffset(uint32_t Section, uint32_t Offset,
261                                            uint32_t Length) const {
262   return nullptr;
263 }
264 
265 std::unique_ptr<IPDBEnumSourceFiles>
266 NativeSession::findSourceFiles(const PDBSymbolCompiland *Compiland,
267                                StringRef Pattern,
268                                PDB_NameSearchFlags Flags) const {
269   return nullptr;
270 }
271 
272 std::unique_ptr<IPDBSourceFile>
273 NativeSession::findOneSourceFile(const PDBSymbolCompiland *Compiland,
274                                  StringRef Pattern,
275                                  PDB_NameSearchFlags Flags) const {
276   return nullptr;
277 }
278 
279 std::unique_ptr<IPDBEnumChildren<PDBSymbolCompiland>>
280 NativeSession::findCompilandsForSourceFile(StringRef Pattern,
281                                            PDB_NameSearchFlags Flags) const {
282   return nullptr;
283 }
284 
285 std::unique_ptr<PDBSymbolCompiland>
286 NativeSession::findOneCompilandForSourceFile(StringRef Pattern,
287                                              PDB_NameSearchFlags Flags) const {
288   return nullptr;
289 }
290 
291 std::unique_ptr<IPDBEnumSourceFiles> NativeSession::getAllSourceFiles() const {
292   return nullptr;
293 }
294 
295 std::unique_ptr<IPDBEnumSourceFiles> NativeSession::getSourceFilesForCompiland(
296     const PDBSymbolCompiland &Compiland) const {
297   return nullptr;
298 }
299 
300 std::unique_ptr<IPDBSourceFile>
301 NativeSession::getSourceFileById(uint32_t FileId) const {
302   return nullptr;
303 }
304 
305 std::unique_ptr<IPDBEnumDataStreams> NativeSession::getDebugStreams() const {
306   return nullptr;
307 }
308 
309 std::unique_ptr<IPDBEnumTables> NativeSession::getEnumTables() const {
310   return nullptr;
311 }
312 
313 std::unique_ptr<IPDBEnumInjectedSources>
314 NativeSession::getInjectedSources() const {
315   auto ISS = Pdb->getInjectedSourceStream();
316   if (!ISS) {
317     consumeError(ISS.takeError());
318     return nullptr;
319   }
320   auto Strings = Pdb->getStringTable();
321   if (!Strings) {
322     consumeError(Strings.takeError());
323     return nullptr;
324   }
325   return std::make_unique<NativeEnumInjectedSources>(*Pdb, *ISS, *Strings);
326 }
327 
328 std::unique_ptr<IPDBEnumSectionContribs>
329 NativeSession::getSectionContribs() const {
330   return nullptr;
331 }
332 
333 std::unique_ptr<IPDBEnumFrameData>
334 NativeSession::getFrameData() const {
335   return nullptr;
336 }
337 
338 void NativeSession::initializeExeSymbol() {
339   if (ExeSymbol == 0)
340     ExeSymbol = Cache.createSymbol<NativeExeSymbol>();
341 }
342 
343 NativeExeSymbol &NativeSession::getNativeGlobalScope() const {
344   const_cast<NativeSession &>(*this).initializeExeSymbol();
345 
346   return Cache.getNativeSymbolById<NativeExeSymbol>(ExeSymbol);
347 }
348