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