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/SmallString.h" 12 #include "llvm/BinaryFormat/Magic.h" 13 #include "llvm/DebugInfo/MSF/MappedBlockStream.h" 14 #include "llvm/DebugInfo/PDB/IPDBEnumChildren.h" 15 #include "llvm/DebugInfo/PDB/IPDBSourceFile.h" 16 #include "llvm/DebugInfo/PDB/Native/DbiModuleDescriptor.h" 17 #include "llvm/DebugInfo/PDB/Native/DbiModuleList.h" 18 #include "llvm/DebugInfo/PDB/Native/DbiStream.h" 19 #include "llvm/DebugInfo/PDB/Native/ISectionContribVisitor.h" 20 #include "llvm/DebugInfo/PDB/Native/ModuleDebugStream.h" 21 #include "llvm/DebugInfo/PDB/Native/NativeEnumInjectedSources.h" 22 #include "llvm/DebugInfo/PDB/Native/NativeExeSymbol.h" 23 #include "llvm/DebugInfo/PDB/Native/PDBFile.h" 24 #include "llvm/DebugInfo/PDB/Native/RawConstants.h" 25 #include "llvm/DebugInfo/PDB/Native/RawError.h" 26 #include "llvm/DebugInfo/PDB/Native/RawTypes.h" 27 #include "llvm/DebugInfo/PDB/Native/SymbolCache.h" 28 #include "llvm/DebugInfo/PDB/PDBSymbol.h" 29 #include "llvm/DebugInfo/PDB/PDBSymbolCompiland.h" 30 #include "llvm/DebugInfo/PDB/PDBSymbolExe.h" 31 #include "llvm/Object/Binary.h" 32 #include "llvm/Object/COFF.h" 33 #include "llvm/Support/Allocator.h" 34 #include "llvm/Support/BinaryByteStream.h" 35 #include "llvm/Support/BinaryStreamArray.h" 36 #include "llvm/Support/Error.h" 37 #include "llvm/Support/ErrorOr.h" 38 #include "llvm/Support/MemoryBuffer.h" 39 #include "llvm/Support/Path.h" 40 41 #include <cassert> 42 #include <memory> 43 #include <utility> 44 45 using namespace llvm; 46 using namespace llvm::msf; 47 using namespace llvm::pdb; 48 49 namespace llvm { 50 namespace codeview { 51 union DebugInfo; 52 } 53 } // namespace llvm 54 55 static DbiStream *getDbiStreamPtr(PDBFile &File) { 56 Expected<DbiStream &> DbiS = File.getPDBDbiStream(); 57 if (DbiS) 58 return &DbiS.get(); 59 60 consumeError(DbiS.takeError()); 61 return nullptr; 62 } 63 64 NativeSession::NativeSession(std::unique_ptr<PDBFile> PdbFile, 65 std::unique_ptr<BumpPtrAllocator> Allocator) 66 : Pdb(std::move(PdbFile)), Allocator(std::move(Allocator)), 67 Cache(*this, getDbiStreamPtr(*Pdb)), AddrToModuleIndex(IMapAllocator) {} 68 69 NativeSession::~NativeSession() = default; 70 71 Error NativeSession::createFromPdb(std::unique_ptr<MemoryBuffer> Buffer, 72 std::unique_ptr<IPDBSession> &Session) { 73 StringRef Path = Buffer->getBufferIdentifier(); 74 auto Stream = std::make_unique<MemoryBufferByteStream>( 75 std::move(Buffer), llvm::endianness::little); 76 77 auto Allocator = std::make_unique<BumpPtrAllocator>(); 78 auto File = std::make_unique<PDBFile>(Path, std::move(Stream), *Allocator); 79 if (auto EC = File->parseFileHeaders()) 80 return EC; 81 if (auto EC = File->parseStreamData()) 82 return EC; 83 84 Session = 85 std::make_unique<NativeSession>(std::move(File), std::move(Allocator)); 86 87 return Error::success(); 88 } 89 90 static Expected<std::unique_ptr<PDBFile>> 91 loadPdbFile(StringRef PdbPath, std::unique_ptr<BumpPtrAllocator> &Allocator) { 92 ErrorOr<std::unique_ptr<MemoryBuffer>> ErrorOrBuffer = 93 MemoryBuffer::getFile(PdbPath, /*IsText=*/false, 94 /*RequiresNullTerminator=*/false); 95 if (!ErrorOrBuffer) 96 return make_error<RawError>(ErrorOrBuffer.getError()); 97 std::unique_ptr<llvm::MemoryBuffer> Buffer = std::move(*ErrorOrBuffer); 98 99 PdbPath = Buffer->getBufferIdentifier(); 100 file_magic Magic; 101 auto EC = identify_magic(PdbPath, Magic); 102 if (EC || Magic != file_magic::pdb) 103 return make_error<RawError>(EC); 104 105 auto Stream = std::make_unique<MemoryBufferByteStream>( 106 std::move(Buffer), llvm::endianness::little); 107 108 auto File = std::make_unique<PDBFile>(PdbPath, std::move(Stream), *Allocator); 109 if (auto EC = File->parseFileHeaders()) 110 return std::move(EC); 111 112 if (auto EC = File->parseStreamData()) 113 return std::move(EC); 114 115 return std::move(File); 116 } 117 118 Error NativeSession::createFromPdbPath(StringRef PdbPath, 119 std::unique_ptr<IPDBSession> &Session) { 120 auto Allocator = std::make_unique<BumpPtrAllocator>(); 121 auto PdbFile = loadPdbFile(PdbPath, Allocator); 122 if (!PdbFile) 123 return PdbFile.takeError(); 124 125 Session = std::make_unique<NativeSession>(std::move(PdbFile.get()), 126 std::move(Allocator)); 127 return Error::success(); 128 } 129 130 static Expected<std::string> getPdbPathFromExe(StringRef ExePath) { 131 Expected<object::OwningBinary<object::Binary>> BinaryFile = 132 object::createBinary(ExePath); 133 if (!BinaryFile) 134 return BinaryFile.takeError(); 135 136 const object::COFFObjectFile *ObjFile = 137 dyn_cast<object::COFFObjectFile>(BinaryFile->getBinary()); 138 if (!ObjFile) 139 return make_error<RawError>(raw_error_code::invalid_format); 140 141 StringRef PdbPath; 142 const llvm::codeview::DebugInfo *PdbInfo = nullptr; 143 if (Error E = ObjFile->getDebugPDBInfo(PdbInfo, PdbPath)) 144 return std::move(E); 145 146 return std::string(PdbPath); 147 } 148 149 Error NativeSession::createFromExe(StringRef ExePath, 150 std::unique_ptr<IPDBSession> &Session) { 151 Expected<std::string> PdbPath = getPdbPathFromExe(ExePath); 152 if (!PdbPath) 153 return PdbPath.takeError(); 154 155 file_magic Magic; 156 auto EC = identify_magic(PdbPath.get(), Magic); 157 if (EC || Magic != file_magic::pdb) 158 return make_error<RawError>(EC); 159 160 auto Allocator = std::make_unique<BumpPtrAllocator>(); 161 auto File = loadPdbFile(PdbPath.get(), Allocator); 162 if (!File) 163 return File.takeError(); 164 165 Session = std::make_unique<NativeSession>(std::move(File.get()), 166 std::move(Allocator)); 167 168 return Error::success(); 169 } 170 171 Expected<std::string> 172 NativeSession::searchForPdb(const PdbSearchOptions &Opts) { 173 Expected<std::string> PathOrErr = getPdbPathFromExe(Opts.ExePath); 174 if (!PathOrErr) 175 return PathOrErr.takeError(); 176 StringRef PathFromExe = PathOrErr.get(); 177 sys::path::Style Style = PathFromExe.starts_with("/") 178 ? sys::path::Style::posix 179 : sys::path::Style::windows; 180 StringRef PdbName = sys::path::filename(PathFromExe, Style); 181 182 // Check if pdb exists in the executable directory. 183 SmallString<128> PdbPath = StringRef(Opts.ExePath); 184 sys::path::remove_filename(PdbPath); 185 sys::path::append(PdbPath, PdbName); 186 187 auto Allocator = std::make_unique<BumpPtrAllocator>(); 188 189 if (auto File = loadPdbFile(PdbPath, Allocator)) 190 return std::string(PdbPath); 191 else 192 consumeError(File.takeError()); 193 194 // Check path that was in the executable. 195 if (auto File = loadPdbFile(PathFromExe, Allocator)) 196 return std::string(PathFromExe); 197 else 198 return File.takeError(); 199 200 return make_error<RawError>("PDB not found"); 201 } 202 203 uint64_t NativeSession::getLoadAddress() const { return LoadAddress; } 204 205 bool NativeSession::setLoadAddress(uint64_t Address) { 206 LoadAddress = Address; 207 return true; 208 } 209 210 std::unique_ptr<PDBSymbolExe> NativeSession::getGlobalScope() { 211 return PDBSymbol::createAs<PDBSymbolExe>(*this, getNativeGlobalScope()); 212 } 213 214 std::unique_ptr<PDBSymbol> 215 NativeSession::getSymbolById(SymIndexId SymbolId) const { 216 return Cache.getSymbolById(SymbolId); 217 } 218 219 bool NativeSession::addressForVA(uint64_t VA, uint32_t &Section, 220 uint32_t &Offset) const { 221 uint32_t RVA = VA - getLoadAddress(); 222 return addressForRVA(RVA, Section, Offset); 223 } 224 225 bool NativeSession::addressForRVA(uint32_t RVA, uint32_t &Section, 226 uint32_t &Offset) const { 227 Section = 0; 228 Offset = 0; 229 230 auto Dbi = Pdb->getPDBDbiStream(); 231 if (!Dbi) 232 return false; 233 234 if ((int32_t)RVA < 0) 235 return true; 236 237 Offset = RVA; 238 for (; Section < Dbi->getSectionHeaders().size(); ++Section) { 239 auto &Sec = Dbi->getSectionHeaders()[Section]; 240 if (RVA < Sec.VirtualAddress) 241 return true; 242 Offset = RVA - Sec.VirtualAddress; 243 } 244 return true; 245 } 246 247 std::unique_ptr<PDBSymbol> 248 NativeSession::findSymbolByAddress(uint64_t Address, PDB_SymType Type) { 249 uint32_t Section; 250 uint32_t Offset; 251 addressForVA(Address, Section, Offset); 252 return findSymbolBySectOffset(Section, Offset, Type); 253 } 254 255 std::unique_ptr<PDBSymbol> NativeSession::findSymbolByRVA(uint32_t RVA, 256 PDB_SymType Type) { 257 uint32_t Section; 258 uint32_t Offset; 259 addressForRVA(RVA, Section, Offset); 260 return findSymbolBySectOffset(Section, Offset, Type); 261 } 262 263 std::unique_ptr<PDBSymbol> 264 NativeSession::findSymbolBySectOffset(uint32_t Sect, uint32_t Offset, 265 PDB_SymType Type) { 266 if (AddrToModuleIndex.empty()) 267 parseSectionContribs(); 268 269 return Cache.findSymbolBySectOffset(Sect, Offset, Type); 270 } 271 272 std::unique_ptr<IPDBEnumLineNumbers> 273 NativeSession::findLineNumbers(const PDBSymbolCompiland &Compiland, 274 const IPDBSourceFile &File) const { 275 return nullptr; 276 } 277 278 std::unique_ptr<IPDBEnumLineNumbers> 279 NativeSession::findLineNumbersByAddress(uint64_t Address, 280 uint32_t Length) const { 281 return Cache.findLineNumbersByVA(Address, Length); 282 } 283 284 std::unique_ptr<IPDBEnumLineNumbers> 285 NativeSession::findLineNumbersByRVA(uint32_t RVA, uint32_t Length) const { 286 return Cache.findLineNumbersByVA(getLoadAddress() + RVA, Length); 287 } 288 289 std::unique_ptr<IPDBEnumLineNumbers> 290 NativeSession::findLineNumbersBySectOffset(uint32_t Section, uint32_t Offset, 291 uint32_t Length) const { 292 uint64_t VA = getVAFromSectOffset(Section, Offset); 293 return Cache.findLineNumbersByVA(VA, Length); 294 } 295 296 std::unique_ptr<IPDBEnumSourceFiles> 297 NativeSession::findSourceFiles(const PDBSymbolCompiland *Compiland, 298 StringRef Pattern, 299 PDB_NameSearchFlags Flags) const { 300 return nullptr; 301 } 302 303 std::unique_ptr<IPDBSourceFile> 304 NativeSession::findOneSourceFile(const PDBSymbolCompiland *Compiland, 305 StringRef Pattern, 306 PDB_NameSearchFlags Flags) const { 307 return nullptr; 308 } 309 310 std::unique_ptr<IPDBEnumChildren<PDBSymbolCompiland>> 311 NativeSession::findCompilandsForSourceFile(StringRef Pattern, 312 PDB_NameSearchFlags Flags) const { 313 return nullptr; 314 } 315 316 std::unique_ptr<PDBSymbolCompiland> 317 NativeSession::findOneCompilandForSourceFile(StringRef Pattern, 318 PDB_NameSearchFlags Flags) const { 319 return nullptr; 320 } 321 322 std::unique_ptr<IPDBEnumSourceFiles> NativeSession::getAllSourceFiles() const { 323 return nullptr; 324 } 325 326 std::unique_ptr<IPDBEnumSourceFiles> NativeSession::getSourceFilesForCompiland( 327 const PDBSymbolCompiland &Compiland) const { 328 return nullptr; 329 } 330 331 std::unique_ptr<IPDBSourceFile> 332 NativeSession::getSourceFileById(uint32_t FileId) const { 333 return Cache.getSourceFileById(FileId); 334 } 335 336 std::unique_ptr<IPDBEnumDataStreams> NativeSession::getDebugStreams() const { 337 return nullptr; 338 } 339 340 std::unique_ptr<IPDBEnumTables> NativeSession::getEnumTables() const { 341 return nullptr; 342 } 343 344 std::unique_ptr<IPDBEnumInjectedSources> 345 NativeSession::getInjectedSources() const { 346 auto ISS = Pdb->getInjectedSourceStream(); 347 if (!ISS) { 348 consumeError(ISS.takeError()); 349 return nullptr; 350 } 351 auto Strings = Pdb->getStringTable(); 352 if (!Strings) { 353 consumeError(Strings.takeError()); 354 return nullptr; 355 } 356 return std::make_unique<NativeEnumInjectedSources>(*Pdb, *ISS, *Strings); 357 } 358 359 std::unique_ptr<IPDBEnumSectionContribs> 360 NativeSession::getSectionContribs() const { 361 return nullptr; 362 } 363 364 std::unique_ptr<IPDBEnumFrameData> 365 NativeSession::getFrameData() const { 366 return nullptr; 367 } 368 369 void NativeSession::initializeExeSymbol() { 370 if (ExeSymbol == 0) 371 ExeSymbol = Cache.createSymbol<NativeExeSymbol>(); 372 } 373 374 NativeExeSymbol &NativeSession::getNativeGlobalScope() const { 375 const_cast<NativeSession &>(*this).initializeExeSymbol(); 376 377 return Cache.getNativeSymbolById<NativeExeSymbol>(ExeSymbol); 378 } 379 380 uint32_t NativeSession::getRVAFromSectOffset(uint32_t Section, 381 uint32_t Offset) const { 382 if (Section <= 0) 383 return 0; 384 385 auto Dbi = getDbiStreamPtr(*Pdb); 386 if (!Dbi) 387 return 0; 388 389 uint32_t MaxSection = Dbi->getSectionHeaders().size(); 390 if (Section > MaxSection + 1) 391 Section = MaxSection + 1; 392 auto &Sec = Dbi->getSectionHeaders()[Section - 1]; 393 return Sec.VirtualAddress + Offset; 394 } 395 396 uint64_t NativeSession::getVAFromSectOffset(uint32_t Section, 397 uint32_t Offset) const { 398 return LoadAddress + getRVAFromSectOffset(Section, Offset); 399 } 400 401 bool NativeSession::moduleIndexForVA(uint64_t VA, uint16_t &ModuleIndex) const { 402 ModuleIndex = 0; 403 auto Iter = AddrToModuleIndex.find(VA); 404 if (Iter == AddrToModuleIndex.end()) 405 return false; 406 ModuleIndex = Iter.value(); 407 return true; 408 } 409 410 bool NativeSession::moduleIndexForSectOffset(uint32_t Sect, uint32_t Offset, 411 uint16_t &ModuleIndex) const { 412 ModuleIndex = 0; 413 auto Iter = AddrToModuleIndex.find(getVAFromSectOffset(Sect, Offset)); 414 if (Iter == AddrToModuleIndex.end()) 415 return false; 416 ModuleIndex = Iter.value(); 417 return true; 418 } 419 420 void NativeSession::parseSectionContribs() { 421 auto Dbi = Pdb->getPDBDbiStream(); 422 if (!Dbi) 423 return; 424 425 class Visitor : public ISectionContribVisitor { 426 NativeSession &Session; 427 IMap &AddrMap; 428 429 public: 430 Visitor(NativeSession &Session, IMap &AddrMap) 431 : Session(Session), AddrMap(AddrMap) {} 432 void visit(const SectionContrib &C) override { 433 if (C.Size == 0) 434 return; 435 436 uint64_t VA = Session.getVAFromSectOffset(C.ISect, C.Off); 437 uint64_t End = VA + C.Size; 438 439 // Ignore overlapping sections based on the assumption that a valid 440 // PDB file should not have overlaps. 441 if (!AddrMap.overlaps(VA, End)) 442 AddrMap.insert(VA, End, C.Imod); 443 } 444 void visit(const SectionContrib2 &C) override { visit(C.Base); } 445 }; 446 447 Visitor V(*this, AddrToModuleIndex); 448 Dbi->visitSectionContributions(V); 449 } 450 451 Expected<ModuleDebugStreamRef> 452 NativeSession::getModuleDebugStream(uint32_t Index) const { 453 auto *Dbi = getDbiStreamPtr(*Pdb); 454 assert(Dbi && "Dbi stream not present"); 455 456 DbiModuleDescriptor Modi = Dbi->modules().getModuleDescriptor(Index); 457 458 uint16_t ModiStream = Modi.getModuleStreamIndex(); 459 if (ModiStream == kInvalidStreamIndex) 460 return make_error<RawError>("Module stream not present"); 461 462 std::unique_ptr<msf::MappedBlockStream> ModStreamData = 463 Pdb->createIndexedStream(ModiStream); 464 465 ModuleDebugStreamRef ModS(Modi, std::move(ModStreamData)); 466 if (auto EC = ModS.reload()) 467 return std::move(EC); 468 469 return std::move(ModS); 470 } 471