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