196 lines · cpp
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-exception6//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 23using namespace lldb;24using namespace lldb_private;25using namespace llvm::pdb;26using namespace llvm::codeview;27 28LLDB_PLUGIN_DEFINE(ObjectFilePDB)29 30static 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 37char ObjectFilePDB::ID;38 39void ObjectFilePDB::Initialize() {40 PluginManager::RegisterPlugin(GetPluginNameStatic(),41 GetPluginDescriptionStatic(), CreateInstance,42 CreateMemoryInstance, GetModuleSpecifications);43}44 45void ObjectFilePDB::Terminate() {46 PluginManager::UnregisterPlugin(CreateInstance);47}48 49ArchSpec 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 76bool 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 94ObjectFile *95ObjectFilePDB::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 105ObjectFile *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 112size_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 161ObjectFilePDB::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 166std::unique_ptr<PDBFile>167ObjectFilePDB::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