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 30*06c3fb27SDimitry Andric static UUID GetPDBUUID(InfoStream &IS, DbiStream &DS) { 31e8d8bef9SDimitry Andric UUID::CvRecordPdb70 debug_info; 32e8d8bef9SDimitry Andric memcpy(&debug_info.Uuid, IS.getGuid().Guid, sizeof(debug_info.Uuid)); 33*06c3fb27SDimitry Andric debug_info.Age = DS.getAge(); 34bdd1243dSDimitry 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 } 85*06c3fb27SDimitry Andric auto dbi_stream = m_file_up->getPDBDbiStream(); 86*06c3fb27SDimitry Andric if (!dbi_stream) { 87*06c3fb27SDimitry Andric llvm::consumeError(dbi_stream.takeError()); 88*06c3fb27SDimitry Andric return false; 89*06c3fb27SDimitry Andric } 90*06c3fb27SDimitry Andric m_uuid = GetPDBUUID(*info_stream, *dbi_stream); 91e8d8bef9SDimitry Andric return true; 92e8d8bef9SDimitry Andric } 93e8d8bef9SDimitry Andric 94e8d8bef9SDimitry Andric ObjectFile * 9581ad6265SDimitry Andric ObjectFilePDB::CreateInstance(const ModuleSP &module_sp, DataBufferSP data_sp, 96e8d8bef9SDimitry Andric offset_t data_offset, const FileSpec *file, 97e8d8bef9SDimitry Andric offset_t file_offset, offset_t length) { 98e8d8bef9SDimitry Andric auto objfile_up = std::make_unique<ObjectFilePDB>( 99e8d8bef9SDimitry Andric module_sp, data_sp, data_offset, file, file_offset, length); 100e8d8bef9SDimitry Andric if (!objfile_up->initPDBFile()) 101e8d8bef9SDimitry Andric return nullptr; 102e8d8bef9SDimitry Andric return objfile_up.release(); 103e8d8bef9SDimitry Andric } 104e8d8bef9SDimitry Andric 105e8d8bef9SDimitry Andric ObjectFile *ObjectFilePDB::CreateMemoryInstance(const ModuleSP &module_sp, 10681ad6265SDimitry Andric WritableDataBufferSP data_sp, 107e8d8bef9SDimitry Andric const ProcessSP &process_sp, 108e8d8bef9SDimitry Andric addr_t header_addr) { 109e8d8bef9SDimitry Andric return nullptr; 110e8d8bef9SDimitry Andric } 111e8d8bef9SDimitry Andric 112e8d8bef9SDimitry Andric size_t ObjectFilePDB::GetModuleSpecifications( 113e8d8bef9SDimitry Andric const FileSpec &file, DataBufferSP &data_sp, offset_t data_offset, 114e8d8bef9SDimitry Andric offset_t file_offset, offset_t length, ModuleSpecList &specs) { 115e8d8bef9SDimitry Andric const size_t initial_count = specs.GetSize(); 116e8d8bef9SDimitry Andric ModuleSpec module_spec(file); 117e8d8bef9SDimitry Andric llvm::BumpPtrAllocator allocator; 118e8d8bef9SDimitry Andric std::unique_ptr<PDBFile> pdb_file = loadPDBFile(file.GetPath(), allocator); 119e8d8bef9SDimitry Andric if (!pdb_file) 120e8d8bef9SDimitry Andric return initial_count; 121e8d8bef9SDimitry Andric 122e8d8bef9SDimitry Andric auto info_stream = pdb_file->getPDBInfoStream(); 123e8d8bef9SDimitry Andric if (!info_stream) { 124e8d8bef9SDimitry Andric llvm::consumeError(info_stream.takeError()); 125e8d8bef9SDimitry Andric return initial_count; 126e8d8bef9SDimitry Andric } 127e8d8bef9SDimitry Andric auto dbi_stream = pdb_file->getPDBDbiStream(); 128e8d8bef9SDimitry Andric if (!dbi_stream) { 129e8d8bef9SDimitry Andric llvm::consumeError(dbi_stream.takeError()); 130e8d8bef9SDimitry Andric return initial_count; 131e8d8bef9SDimitry Andric } 132e8d8bef9SDimitry Andric 133e8d8bef9SDimitry Andric lldb_private::UUID &uuid = module_spec.GetUUID(); 134*06c3fb27SDimitry Andric uuid = GetPDBUUID(*info_stream, *dbi_stream); 135e8d8bef9SDimitry Andric 136e8d8bef9SDimitry Andric ArchSpec &module_arch = module_spec.GetArchitecture(); 137e8d8bef9SDimitry Andric switch (dbi_stream->getMachineType()) { 138e8d8bef9SDimitry Andric case PDB_Machine::Amd64: 139e8d8bef9SDimitry Andric module_arch.SetTriple("x86_64-pc-windows"); 140e8d8bef9SDimitry Andric specs.Append(module_spec); 141e8d8bef9SDimitry Andric break; 142e8d8bef9SDimitry Andric case PDB_Machine::x86: 143e8d8bef9SDimitry Andric module_arch.SetTriple("i386-pc-windows"); 144e8d8bef9SDimitry Andric specs.Append(module_spec); 145e8d8bef9SDimitry Andric break; 146e8d8bef9SDimitry Andric case PDB_Machine::ArmNT: 147e8d8bef9SDimitry Andric module_arch.SetTriple("armv7-pc-windows"); 148e8d8bef9SDimitry Andric specs.Append(module_spec); 149e8d8bef9SDimitry Andric break; 150e8d8bef9SDimitry Andric case PDB_Machine::Arm64: 151e8d8bef9SDimitry Andric module_arch.SetTriple("aarch64-pc-windows"); 152e8d8bef9SDimitry Andric specs.Append(module_spec); 153e8d8bef9SDimitry Andric break; 154e8d8bef9SDimitry Andric default: 155e8d8bef9SDimitry Andric break; 156e8d8bef9SDimitry Andric } 157e8d8bef9SDimitry Andric 158e8d8bef9SDimitry Andric return specs.GetSize() - initial_count; 159e8d8bef9SDimitry Andric } 160e8d8bef9SDimitry Andric 161e8d8bef9SDimitry Andric ObjectFilePDB::ObjectFilePDB(const ModuleSP &module_sp, DataBufferSP &data_sp, 162e8d8bef9SDimitry Andric offset_t data_offset, const FileSpec *file, 163e8d8bef9SDimitry Andric offset_t offset, offset_t length) 164e8d8bef9SDimitry Andric : ObjectFile(module_sp, file, offset, length, data_sp, data_offset) {} 165e8d8bef9SDimitry Andric 166e8d8bef9SDimitry Andric std::unique_ptr<PDBFile> 167e8d8bef9SDimitry Andric ObjectFilePDB::loadPDBFile(std::string PdbPath, 168e8d8bef9SDimitry Andric llvm::BumpPtrAllocator &Allocator) { 169e8d8bef9SDimitry Andric llvm::file_magic magic; 170e8d8bef9SDimitry Andric auto ec = llvm::identify_magic(PdbPath, magic); 171e8d8bef9SDimitry Andric if (ec || magic != llvm::file_magic::pdb) 172e8d8bef9SDimitry Andric return nullptr; 173e8d8bef9SDimitry Andric llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> ErrorOrBuffer = 174fe6060f1SDimitry Andric llvm::MemoryBuffer::getFile(PdbPath, /*IsText=*/false, 175e8d8bef9SDimitry Andric /*RequiresNullTerminator=*/false); 176e8d8bef9SDimitry Andric if (!ErrorOrBuffer) 177e8d8bef9SDimitry Andric return nullptr; 178e8d8bef9SDimitry Andric std::unique_ptr<llvm::MemoryBuffer> Buffer = std::move(*ErrorOrBuffer); 179e8d8bef9SDimitry Andric 180e8d8bef9SDimitry Andric llvm::StringRef Path = Buffer->getBufferIdentifier(); 181e8d8bef9SDimitry Andric auto Stream = std::make_unique<llvm::MemoryBufferByteStream>( 182e8d8bef9SDimitry Andric std::move(Buffer), llvm::support::little); 183e8d8bef9SDimitry Andric 184e8d8bef9SDimitry Andric auto File = std::make_unique<PDBFile>(Path, std::move(Stream), Allocator); 185e8d8bef9SDimitry Andric if (auto EC = File->parseFileHeaders()) { 186e8d8bef9SDimitry Andric llvm::consumeError(std::move(EC)); 187e8d8bef9SDimitry Andric return nullptr; 188e8d8bef9SDimitry Andric } 189e8d8bef9SDimitry Andric if (auto EC = File->parseStreamData()) { 190e8d8bef9SDimitry Andric llvm::consumeError(std::move(EC)); 191e8d8bef9SDimitry Andric return nullptr; 192e8d8bef9SDimitry Andric } 193e8d8bef9SDimitry Andric 194e8d8bef9SDimitry Andric return File; 195e8d8bef9SDimitry Andric } 196