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 struct CVInfoPdb70 { 31 // 16-byte GUID 32 struct _Guid { 33 llvm::support::ulittle32_t Data1; 34 llvm::support::ulittle16_t Data2; 35 llvm::support::ulittle16_t Data3; 36 uint8_t Data4[8]; 37 } Guid; 38 39 llvm::support::ulittle32_t Age; 40 }; 41 42 static UUID GetPDBUUID(InfoStream &IS) { 43 // This part is similar with what has done in ObjectFilePECOFF. 44 using llvm::support::endian::read16be; 45 using llvm::support::endian::read32; 46 using llvm::support::endian::read32be; 47 48 GUID guid = IS.getGuid(); 49 const uint8_t *guid_p = guid.Guid; 50 struct CVInfoPdb70 info; 51 info.Guid.Data1 = read32be(guid_p); 52 guid_p += 4; 53 info.Guid.Data2 = read16be(guid_p); 54 guid_p += 2; 55 info.Guid.Data3 = read16be(guid_p); 56 guid_p += 2; 57 memcpy(info.Guid.Data4, guid_p, 8); 58 59 // Return 20-byte UUID if the Age is not zero 60 uint32_t age = IS.getAge(); 61 if (age) { 62 info.Age = read32(&age, llvm::support::big); 63 return UUID::fromOptionalData(&info, sizeof(info)); 64 } 65 // Otherwise return 16-byte GUID 66 return UUID::fromOptionalData(&info.Guid, sizeof(info.Guid)); 67 } 68 69 char ObjectFilePDB::ID; 70 71 void ObjectFilePDB::Initialize() { 72 PluginManager::RegisterPlugin(GetPluginNameStatic(), 73 GetPluginDescriptionStatic(), CreateInstance, 74 CreateMemoryInstance, GetModuleSpecifications); 75 } 76 77 void ObjectFilePDB::Terminate() { 78 PluginManager::UnregisterPlugin(CreateInstance); 79 } 80 81 ConstString ObjectFilePDB::GetPluginNameStatic() { 82 static ConstString g_name("pdb"); 83 return g_name; 84 } 85 86 ArchSpec ObjectFilePDB::GetArchitecture() { 87 auto dbi_stream = m_file_up->getPDBDbiStream(); 88 if (!dbi_stream) { 89 llvm::consumeError(dbi_stream.takeError()); 90 return ArchSpec(); 91 } 92 93 PDB_Machine machine = dbi_stream->getMachineType(); 94 switch (machine) { 95 default: 96 break; 97 case PDB_Machine::Amd64: 98 case PDB_Machine::x86: 99 case PDB_Machine::PowerPC: 100 case PDB_Machine::PowerPCFP: 101 case PDB_Machine::Arm: 102 case PDB_Machine::ArmNT: 103 case PDB_Machine::Thumb: 104 case PDB_Machine::Arm64: 105 ArchSpec arch; 106 arch.SetArchitecture(eArchTypeCOFF, static_cast<int>(machine), 107 LLDB_INVALID_CPUTYPE); 108 return arch; 109 } 110 return ArchSpec(); 111 } 112 113 bool ObjectFilePDB::initPDBFile() { 114 m_file_up = loadPDBFile(m_file.GetPath(), m_allocator); 115 if (!m_file_up) 116 return false; 117 auto info_stream = m_file_up->getPDBInfoStream(); 118 if (!info_stream) { 119 llvm::consumeError(info_stream.takeError()); 120 return false; 121 } 122 m_uuid = GetPDBUUID(*info_stream); 123 return true; 124 } 125 126 ObjectFile * 127 ObjectFilePDB::CreateInstance(const ModuleSP &module_sp, DataBufferSP &data_sp, 128 offset_t data_offset, const FileSpec *file, 129 offset_t file_offset, offset_t length) { 130 auto objfile_up = std::make_unique<ObjectFilePDB>( 131 module_sp, data_sp, data_offset, file, file_offset, length); 132 if (!objfile_up->initPDBFile()) 133 return nullptr; 134 return objfile_up.release(); 135 } 136 137 ObjectFile *ObjectFilePDB::CreateMemoryInstance(const ModuleSP &module_sp, 138 DataBufferSP &data_sp, 139 const ProcessSP &process_sp, 140 addr_t header_addr) { 141 return nullptr; 142 } 143 144 size_t ObjectFilePDB::GetModuleSpecifications( 145 const FileSpec &file, DataBufferSP &data_sp, offset_t data_offset, 146 offset_t file_offset, offset_t length, ModuleSpecList &specs) { 147 const size_t initial_count = specs.GetSize(); 148 ModuleSpec module_spec(file); 149 llvm::BumpPtrAllocator allocator; 150 std::unique_ptr<PDBFile> pdb_file = loadPDBFile(file.GetPath(), allocator); 151 if (!pdb_file) 152 return initial_count; 153 154 auto info_stream = pdb_file->getPDBInfoStream(); 155 if (!info_stream) { 156 llvm::consumeError(info_stream.takeError()); 157 return initial_count; 158 } 159 auto dbi_stream = pdb_file->getPDBDbiStream(); 160 if (!dbi_stream) { 161 llvm::consumeError(dbi_stream.takeError()); 162 return initial_count; 163 } 164 165 lldb_private::UUID &uuid = module_spec.GetUUID(); 166 uuid = GetPDBUUID(*info_stream); 167 168 ArchSpec &module_arch = module_spec.GetArchitecture(); 169 switch (dbi_stream->getMachineType()) { 170 case PDB_Machine::Amd64: 171 module_arch.SetTriple("x86_64-pc-windows"); 172 specs.Append(module_spec); 173 break; 174 case PDB_Machine::x86: 175 module_arch.SetTriple("i386-pc-windows"); 176 specs.Append(module_spec); 177 module_arch.SetTriple("i686-pc-windows"); 178 specs.Append(module_spec); 179 break; 180 case PDB_Machine::ArmNT: 181 module_arch.SetTriple("armv7-pc-windows"); 182 specs.Append(module_spec); 183 break; 184 case PDB_Machine::Arm64: 185 module_arch.SetTriple("aarch64-pc-windows"); 186 specs.Append(module_spec); 187 break; 188 default: 189 break; 190 } 191 192 return specs.GetSize() - initial_count; 193 } 194 195 ObjectFilePDB::ObjectFilePDB(const ModuleSP &module_sp, DataBufferSP &data_sp, 196 offset_t data_offset, const FileSpec *file, 197 offset_t offset, offset_t length) 198 : ObjectFile(module_sp, file, offset, length, data_sp, data_offset) {} 199 200 std::unique_ptr<PDBFile> 201 ObjectFilePDB::loadPDBFile(std::string PdbPath, 202 llvm::BumpPtrAllocator &Allocator) { 203 llvm::file_magic magic; 204 auto ec = llvm::identify_magic(PdbPath, magic); 205 if (ec || magic != llvm::file_magic::pdb) 206 return nullptr; 207 llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> ErrorOrBuffer = 208 llvm::MemoryBuffer::getFile(PdbPath, /*FileSize=*/-1, 209 /*RequiresNullTerminator=*/false); 210 if (!ErrorOrBuffer) 211 return nullptr; 212 std::unique_ptr<llvm::MemoryBuffer> Buffer = std::move(*ErrorOrBuffer); 213 214 llvm::StringRef Path = Buffer->getBufferIdentifier(); 215 auto Stream = std::make_unique<llvm::MemoryBufferByteStream>( 216 std::move(Buffer), llvm::support::little); 217 218 auto File = std::make_unique<PDBFile>(Path, std::move(Stream), Allocator); 219 if (auto EC = File->parseFileHeaders()) { 220 llvm::consumeError(std::move(EC)); 221 return nullptr; 222 } 223 if (auto EC = File->parseStreamData()) { 224 llvm::consumeError(std::move(EC)); 225 return nullptr; 226 } 227 228 return File; 229 } 230