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