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