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