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