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