1e8d8bef9SDimitry Andric //===-- ObjectFilePDB.cpp -------------------------------------------------===// 2e8d8bef9SDimitry Andric // 3e8d8bef9SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4e8d8bef9SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5e8d8bef9SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6e8d8bef9SDimitry Andric // 7e8d8bef9SDimitry Andric //===----------------------------------------------------------------------===// 8e8d8bef9SDimitry Andric 9e8d8bef9SDimitry Andric #include "ObjectFilePDB.h" 10e8d8bef9SDimitry Andric #include "lldb/Core/Module.h" 11e8d8bef9SDimitry Andric #include "lldb/Core/ModuleSpec.h" 12e8d8bef9SDimitry Andric #include "lldb/Core/PluginManager.h" 13e8d8bef9SDimitry Andric #include "lldb/Core/Section.h" 14e8d8bef9SDimitry Andric #include "lldb/Utility/StreamString.h" 15e8d8bef9SDimitry Andric #include "llvm/BinaryFormat/Magic.h" 16e8d8bef9SDimitry Andric #include "llvm/DebugInfo/PDB/Native/DbiStream.h" 17e8d8bef9SDimitry Andric #include "llvm/DebugInfo/PDB/Native/InfoStream.h" 18e8d8bef9SDimitry Andric #include "llvm/DebugInfo/PDB/Native/NativeSession.h" 19e8d8bef9SDimitry Andric #include "llvm/DebugInfo/PDB/Native/PDBFile.h" 20e8d8bef9SDimitry Andric #include "llvm/DebugInfo/PDB/PDB.h" 21e8d8bef9SDimitry Andric #include "llvm/Support/BinaryByteStream.h" 22e8d8bef9SDimitry Andric 23e8d8bef9SDimitry Andric using namespace lldb; 24e8d8bef9SDimitry Andric using namespace lldb_private; 25e8d8bef9SDimitry Andric using namespace llvm::pdb; 26e8d8bef9SDimitry Andric using namespace llvm::codeview; 27e8d8bef9SDimitry Andric 28e8d8bef9SDimitry Andric LLDB_PLUGIN_DEFINE(ObjectFilePDB) 29e8d8bef9SDimitry Andric 30e8d8bef9SDimitry Andric static UUID GetPDBUUID(InfoStream &IS) { 31e8d8bef9SDimitry Andric UUID::CvRecordPdb70 debug_info; 32e8d8bef9SDimitry Andric memcpy(&debug_info.Uuid, IS.getGuid().Guid, sizeof(debug_info.Uuid)); 33e8d8bef9SDimitry Andric debug_info.Age = IS.getAge(); 34*bdd1243dSDimitry Andric return UUID(debug_info); 35e8d8bef9SDimitry Andric } 36e8d8bef9SDimitry Andric 37e8d8bef9SDimitry Andric char ObjectFilePDB::ID; 38e8d8bef9SDimitry Andric 39e8d8bef9SDimitry Andric void ObjectFilePDB::Initialize() { 40e8d8bef9SDimitry Andric PluginManager::RegisterPlugin(GetPluginNameStatic(), 41e8d8bef9SDimitry Andric GetPluginDescriptionStatic(), CreateInstance, 42e8d8bef9SDimitry Andric CreateMemoryInstance, GetModuleSpecifications); 43e8d8bef9SDimitry Andric } 44e8d8bef9SDimitry Andric 45e8d8bef9SDimitry Andric void ObjectFilePDB::Terminate() { 46e8d8bef9SDimitry Andric PluginManager::UnregisterPlugin(CreateInstance); 47e8d8bef9SDimitry Andric } 48e8d8bef9SDimitry Andric 49e8d8bef9SDimitry Andric ArchSpec ObjectFilePDB::GetArchitecture() { 50e8d8bef9SDimitry Andric auto dbi_stream = m_file_up->getPDBDbiStream(); 51e8d8bef9SDimitry Andric if (!dbi_stream) { 52e8d8bef9SDimitry Andric llvm::consumeError(dbi_stream.takeError()); 53e8d8bef9SDimitry Andric return ArchSpec(); 54e8d8bef9SDimitry Andric } 55e8d8bef9SDimitry Andric 56e8d8bef9SDimitry Andric PDB_Machine machine = dbi_stream->getMachineType(); 57e8d8bef9SDimitry Andric switch (machine) { 58e8d8bef9SDimitry Andric default: 59e8d8bef9SDimitry Andric break; 60e8d8bef9SDimitry Andric case PDB_Machine::Amd64: 61e8d8bef9SDimitry Andric case PDB_Machine::x86: 62e8d8bef9SDimitry Andric case PDB_Machine::PowerPC: 63e8d8bef9SDimitry Andric case PDB_Machine::PowerPCFP: 64e8d8bef9SDimitry Andric case PDB_Machine::Arm: 65e8d8bef9SDimitry Andric case PDB_Machine::ArmNT: 66e8d8bef9SDimitry Andric case PDB_Machine::Thumb: 67e8d8bef9SDimitry Andric case PDB_Machine::Arm64: 68e8d8bef9SDimitry Andric ArchSpec arch; 69e8d8bef9SDimitry Andric arch.SetArchitecture(eArchTypeCOFF, static_cast<int>(machine), 70e8d8bef9SDimitry Andric LLDB_INVALID_CPUTYPE); 71e8d8bef9SDimitry Andric return arch; 72e8d8bef9SDimitry Andric } 73e8d8bef9SDimitry Andric return ArchSpec(); 74e8d8bef9SDimitry Andric } 75e8d8bef9SDimitry Andric 76e8d8bef9SDimitry Andric bool ObjectFilePDB::initPDBFile() { 77e8d8bef9SDimitry Andric m_file_up = loadPDBFile(m_file.GetPath(), m_allocator); 78e8d8bef9SDimitry Andric if (!m_file_up) 79e8d8bef9SDimitry Andric return false; 80e8d8bef9SDimitry Andric auto info_stream = m_file_up->getPDBInfoStream(); 81e8d8bef9SDimitry Andric if (!info_stream) { 82e8d8bef9SDimitry Andric llvm::consumeError(info_stream.takeError()); 83e8d8bef9SDimitry Andric return false; 84e8d8bef9SDimitry Andric } 85e8d8bef9SDimitry Andric m_uuid = GetPDBUUID(*info_stream); 86e8d8bef9SDimitry Andric return true; 87e8d8bef9SDimitry Andric } 88e8d8bef9SDimitry Andric 89e8d8bef9SDimitry Andric ObjectFile * 9081ad6265SDimitry Andric ObjectFilePDB::CreateInstance(const ModuleSP &module_sp, DataBufferSP data_sp, 91e8d8bef9SDimitry Andric offset_t data_offset, const FileSpec *file, 92e8d8bef9SDimitry Andric offset_t file_offset, offset_t length) { 93e8d8bef9SDimitry Andric auto objfile_up = std::make_unique<ObjectFilePDB>( 94e8d8bef9SDimitry Andric module_sp, data_sp, data_offset, file, file_offset, length); 95e8d8bef9SDimitry Andric if (!objfile_up->initPDBFile()) 96e8d8bef9SDimitry Andric return nullptr; 97e8d8bef9SDimitry Andric return objfile_up.release(); 98e8d8bef9SDimitry Andric } 99e8d8bef9SDimitry Andric 100e8d8bef9SDimitry Andric ObjectFile *ObjectFilePDB::CreateMemoryInstance(const ModuleSP &module_sp, 10181ad6265SDimitry Andric WritableDataBufferSP data_sp, 102e8d8bef9SDimitry Andric const ProcessSP &process_sp, 103e8d8bef9SDimitry Andric addr_t header_addr) { 104e8d8bef9SDimitry Andric return nullptr; 105e8d8bef9SDimitry Andric } 106e8d8bef9SDimitry Andric 107e8d8bef9SDimitry Andric size_t ObjectFilePDB::GetModuleSpecifications( 108e8d8bef9SDimitry Andric const FileSpec &file, DataBufferSP &data_sp, offset_t data_offset, 109e8d8bef9SDimitry Andric offset_t file_offset, offset_t length, ModuleSpecList &specs) { 110e8d8bef9SDimitry Andric const size_t initial_count = specs.GetSize(); 111e8d8bef9SDimitry Andric ModuleSpec module_spec(file); 112e8d8bef9SDimitry Andric llvm::BumpPtrAllocator allocator; 113e8d8bef9SDimitry Andric std::unique_ptr<PDBFile> pdb_file = loadPDBFile(file.GetPath(), allocator); 114e8d8bef9SDimitry Andric if (!pdb_file) 115e8d8bef9SDimitry Andric return initial_count; 116e8d8bef9SDimitry Andric 117e8d8bef9SDimitry Andric auto info_stream = pdb_file->getPDBInfoStream(); 118e8d8bef9SDimitry Andric if (!info_stream) { 119e8d8bef9SDimitry Andric llvm::consumeError(info_stream.takeError()); 120e8d8bef9SDimitry Andric return initial_count; 121e8d8bef9SDimitry Andric } 122e8d8bef9SDimitry Andric auto dbi_stream = pdb_file->getPDBDbiStream(); 123e8d8bef9SDimitry Andric if (!dbi_stream) { 124e8d8bef9SDimitry Andric llvm::consumeError(dbi_stream.takeError()); 125e8d8bef9SDimitry Andric return initial_count; 126e8d8bef9SDimitry Andric } 127e8d8bef9SDimitry Andric 128e8d8bef9SDimitry Andric lldb_private::UUID &uuid = module_spec.GetUUID(); 129e8d8bef9SDimitry Andric uuid = GetPDBUUID(*info_stream); 130e8d8bef9SDimitry Andric 131e8d8bef9SDimitry Andric ArchSpec &module_arch = module_spec.GetArchitecture(); 132e8d8bef9SDimitry Andric switch (dbi_stream->getMachineType()) { 133e8d8bef9SDimitry Andric case PDB_Machine::Amd64: 134e8d8bef9SDimitry Andric module_arch.SetTriple("x86_64-pc-windows"); 135e8d8bef9SDimitry Andric specs.Append(module_spec); 136e8d8bef9SDimitry Andric break; 137e8d8bef9SDimitry Andric case PDB_Machine::x86: 138e8d8bef9SDimitry Andric module_arch.SetTriple("i386-pc-windows"); 139e8d8bef9SDimitry Andric specs.Append(module_spec); 140e8d8bef9SDimitry Andric break; 141e8d8bef9SDimitry Andric case PDB_Machine::ArmNT: 142e8d8bef9SDimitry Andric module_arch.SetTriple("armv7-pc-windows"); 143e8d8bef9SDimitry Andric specs.Append(module_spec); 144e8d8bef9SDimitry Andric break; 145e8d8bef9SDimitry Andric case PDB_Machine::Arm64: 146e8d8bef9SDimitry Andric module_arch.SetTriple("aarch64-pc-windows"); 147e8d8bef9SDimitry Andric specs.Append(module_spec); 148e8d8bef9SDimitry Andric break; 149e8d8bef9SDimitry Andric default: 150e8d8bef9SDimitry Andric break; 151e8d8bef9SDimitry Andric } 152e8d8bef9SDimitry Andric 153e8d8bef9SDimitry Andric return specs.GetSize() - initial_count; 154e8d8bef9SDimitry Andric } 155e8d8bef9SDimitry Andric 156e8d8bef9SDimitry Andric ObjectFilePDB::ObjectFilePDB(const ModuleSP &module_sp, DataBufferSP &data_sp, 157e8d8bef9SDimitry Andric offset_t data_offset, const FileSpec *file, 158e8d8bef9SDimitry Andric offset_t offset, offset_t length) 159e8d8bef9SDimitry Andric : ObjectFile(module_sp, file, offset, length, data_sp, data_offset) {} 160e8d8bef9SDimitry Andric 161e8d8bef9SDimitry Andric std::unique_ptr<PDBFile> 162e8d8bef9SDimitry Andric ObjectFilePDB::loadPDBFile(std::string PdbPath, 163e8d8bef9SDimitry Andric llvm::BumpPtrAllocator &Allocator) { 164e8d8bef9SDimitry Andric llvm::file_magic magic; 165e8d8bef9SDimitry Andric auto ec = llvm::identify_magic(PdbPath, magic); 166e8d8bef9SDimitry Andric if (ec || magic != llvm::file_magic::pdb) 167e8d8bef9SDimitry Andric return nullptr; 168e8d8bef9SDimitry Andric llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> ErrorOrBuffer = 169fe6060f1SDimitry Andric llvm::MemoryBuffer::getFile(PdbPath, /*IsText=*/false, 170e8d8bef9SDimitry Andric /*RequiresNullTerminator=*/false); 171e8d8bef9SDimitry Andric if (!ErrorOrBuffer) 172e8d8bef9SDimitry Andric return nullptr; 173e8d8bef9SDimitry Andric std::unique_ptr<llvm::MemoryBuffer> Buffer = std::move(*ErrorOrBuffer); 174e8d8bef9SDimitry Andric 175e8d8bef9SDimitry Andric llvm::StringRef Path = Buffer->getBufferIdentifier(); 176e8d8bef9SDimitry Andric auto Stream = std::make_unique<llvm::MemoryBufferByteStream>( 177e8d8bef9SDimitry Andric std::move(Buffer), llvm::support::little); 178e8d8bef9SDimitry Andric 179e8d8bef9SDimitry Andric auto File = std::make_unique<PDBFile>(Path, std::move(Stream), Allocator); 180e8d8bef9SDimitry Andric if (auto EC = File->parseFileHeaders()) { 181e8d8bef9SDimitry Andric llvm::consumeError(std::move(EC)); 182e8d8bef9SDimitry Andric return nullptr; 183e8d8bef9SDimitry Andric } 184e8d8bef9SDimitry Andric if (auto EC = File->parseStreamData()) { 185e8d8bef9SDimitry Andric llvm::consumeError(std::move(EC)); 186e8d8bef9SDimitry Andric return nullptr; 187e8d8bef9SDimitry Andric } 188e8d8bef9SDimitry Andric 189e8d8bef9SDimitry Andric return File; 190e8d8bef9SDimitry Andric } 191