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