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) { 31 UUID::CvRecordPdb70 debug_info; 32 memcpy(&debug_info.Uuid, IS.getGuid().Guid, sizeof(debug_info.Uuid)); 33 debug_info.Age = IS.getAge(); 34 return UUID::fromCvRecord(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 ConstString ObjectFilePDB::GetPluginNameStatic() { 50 static ConstString g_name("pdb"); 51 return g_name; 52 } 53 54 ArchSpec ObjectFilePDB::GetArchitecture() { 55 auto dbi_stream = m_file_up->getPDBDbiStream(); 56 if (!dbi_stream) { 57 llvm::consumeError(dbi_stream.takeError()); 58 return ArchSpec(); 59 } 60 61 PDB_Machine machine = dbi_stream->getMachineType(); 62 switch (machine) { 63 default: 64 break; 65 case PDB_Machine::Amd64: 66 case PDB_Machine::x86: 67 case PDB_Machine::PowerPC: 68 case PDB_Machine::PowerPCFP: 69 case PDB_Machine::Arm: 70 case PDB_Machine::ArmNT: 71 case PDB_Machine::Thumb: 72 case PDB_Machine::Arm64: 73 ArchSpec arch; 74 arch.SetArchitecture(eArchTypeCOFF, static_cast<int>(machine), 75 LLDB_INVALID_CPUTYPE); 76 return arch; 77 } 78 return ArchSpec(); 79 } 80 81 bool ObjectFilePDB::initPDBFile() { 82 m_file_up = loadPDBFile(m_file.GetPath(), m_allocator); 83 if (!m_file_up) 84 return false; 85 auto info_stream = m_file_up->getPDBInfoStream(); 86 if (!info_stream) { 87 llvm::consumeError(info_stream.takeError()); 88 return false; 89 } 90 m_uuid = GetPDBUUID(*info_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 DataBufferSP &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); 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 module_arch.SetTriple("i686-pc-windows"); 146 specs.Append(module_spec); 147 break; 148 case PDB_Machine::ArmNT: 149 module_arch.SetTriple("armv7-pc-windows"); 150 specs.Append(module_spec); 151 break; 152 case PDB_Machine::Arm64: 153 module_arch.SetTriple("aarch64-pc-windows"); 154 specs.Append(module_spec); 155 break; 156 default: 157 break; 158 } 159 160 return specs.GetSize() - initial_count; 161 } 162 163 ObjectFilePDB::ObjectFilePDB(const ModuleSP &module_sp, DataBufferSP &data_sp, 164 offset_t data_offset, const FileSpec *file, 165 offset_t offset, offset_t length) 166 : ObjectFile(module_sp, file, offset, length, data_sp, data_offset) {} 167 168 std::unique_ptr<PDBFile> 169 ObjectFilePDB::loadPDBFile(std::string PdbPath, 170 llvm::BumpPtrAllocator &Allocator) { 171 llvm::file_magic magic; 172 auto ec = llvm::identify_magic(PdbPath, magic); 173 if (ec || magic != llvm::file_magic::pdb) 174 return nullptr; 175 llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> ErrorOrBuffer = 176 llvm::MemoryBuffer::getFile(PdbPath, /*IsText=*/false, 177 /*RequiresNullTerminator=*/false); 178 if (!ErrorOrBuffer) 179 return nullptr; 180 std::unique_ptr<llvm::MemoryBuffer> Buffer = std::move(*ErrorOrBuffer); 181 182 llvm::StringRef Path = Buffer->getBufferIdentifier(); 183 auto Stream = std::make_unique<llvm::MemoryBufferByteStream>( 184 std::move(Buffer), llvm::support::little); 185 186 auto File = std::make_unique<PDBFile>(Path, std::move(Stream), Allocator); 187 if (auto EC = File->parseFileHeaders()) { 188 llvm::consumeError(std::move(EC)); 189 return nullptr; 190 } 191 if (auto EC = File->parseStreamData()) { 192 llvm::consumeError(std::move(EC)); 193 return nullptr; 194 } 195 196 return File; 197 } 198