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