| //===-- ObjectFilePDB.cpp -------------------------------------------------===// | |
| // | |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| // See https://llvm.org/LICENSE.txt for license information. | |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| // | |
| //===----------------------------------------------------------------------===// | |
| #include "ObjectFilePDB.h" | |
| #include "lldb/Core/Module.h" | |
| #include "lldb/Core/ModuleSpec.h" | |
| #include "lldb/Core/PluginManager.h" | |
| #include "lldb/Core/Section.h" | |
| #include "lldb/Utility/StreamString.h" | |
| #include "llvm/BinaryFormat/Magic.h" | |
| #include "llvm/DebugInfo/PDB/Native/DbiStream.h" | |
| #include "llvm/DebugInfo/PDB/Native/InfoStream.h" | |
| #include "llvm/DebugInfo/PDB/Native/NativeSession.h" | |
| #include "llvm/DebugInfo/PDB/Native/PDBFile.h" | |
| #include "llvm/DebugInfo/PDB/PDB.h" | |
| #include "llvm/Support/BinaryByteStream.h" | |
| using namespace lldb; | |
| using namespace lldb_private; | |
| using namespace llvm::pdb; | |
| using namespace llvm::codeview; | |
| LLDB_PLUGIN_DEFINE(ObjectFilePDB) | |
| static UUID GetPDBUUID(InfoStream &IS, DbiStream &DS) { | |
| UUID::CvRecordPdb70 debug_info; | |
| memcpy(&debug_info.Uuid, IS.getGuid().Guid, sizeof(debug_info.Uuid)); | |
| debug_info.Age = DS.getAge(); | |
| return UUID(debug_info); | |
| } | |
| char ObjectFilePDB::ID; | |
| void ObjectFilePDB::Initialize() { | |
| PluginManager::RegisterPlugin(GetPluginNameStatic(), | |
| GetPluginDescriptionStatic(), CreateInstance, | |
| CreateMemoryInstance, GetModuleSpecifications); | |
| } | |
| void ObjectFilePDB::Terminate() { | |
| PluginManager::UnregisterPlugin(CreateInstance); | |
| } | |
| ArchSpec ObjectFilePDB::GetArchitecture() { | |
| auto dbi_stream = m_file_up->getPDBDbiStream(); | |
| if (!dbi_stream) { | |
| llvm::consumeError(dbi_stream.takeError()); | |
| return ArchSpec(); | |
| } | |
| PDB_Machine machine = dbi_stream->getMachineType(); | |
| switch (machine) { | |
| default: | |
| break; | |
| case PDB_Machine::Amd64: | |
| case PDB_Machine::x86: | |
| case PDB_Machine::PowerPC: | |
| case PDB_Machine::PowerPCFP: | |
| case PDB_Machine::Arm: | |
| case PDB_Machine::ArmNT: | |
| case PDB_Machine::Thumb: | |
| case PDB_Machine::Arm64: | |
| ArchSpec arch; | |
| arch.SetArchitecture(eArchTypeCOFF, static_cast<int>(machine), | |
| LLDB_INVALID_CPUTYPE); | |
| return arch; | |
| } | |
| return ArchSpec(); | |
| } | |
| bool ObjectFilePDB::initPDBFile() { | |
| m_file_up = loadPDBFile(m_file.GetPath(), m_allocator); | |
| if (!m_file_up) | |
| return false; | |
| auto info_stream = m_file_up->getPDBInfoStream(); | |
| if (!info_stream) { | |
| llvm::consumeError(info_stream.takeError()); | |
| return false; | |
| } | |
| auto dbi_stream = m_file_up->getPDBDbiStream(); | |
| if (!dbi_stream) { | |
| llvm::consumeError(dbi_stream.takeError()); | |
| return false; | |
| } | |
| m_uuid = GetPDBUUID(*info_stream, *dbi_stream); | |
| return true; | |
| } | |
| ObjectFile *ObjectFilePDB::CreateInstance(const ModuleSP &module_sp, | |
| DataExtractorSP extractor_sp, | |
| offset_t data_offset, | |
| const FileSpec *file, | |
| offset_t file_offset, | |
| offset_t length) { | |
| auto objfile_up = std::make_unique<ObjectFilePDB>( | |
| module_sp, extractor_sp, data_offset, file, file_offset, length); | |
| if (!objfile_up->initPDBFile()) | |
| return nullptr; | |
| return objfile_up.release(); | |
| } | |
| ObjectFile *ObjectFilePDB::CreateMemoryInstance(const ModuleSP &module_sp, | |
| WritableDataBufferSP data_sp, | |
| const ProcessSP &process_sp, | |
| addr_t header_addr) { | |
| return nullptr; | |
| } | |
| ModuleSpecList | |
| ObjectFilePDB::GetModuleSpecifications(const FileSpec &file, | |
| DataExtractorSP &extractor_sp, | |
| offset_t file_offset, offset_t length) { | |
| ModuleSpec module_spec(file); | |
| llvm::BumpPtrAllocator allocator; | |
| std::unique_ptr<PDBFile> pdb_file = loadPDBFile(file.GetPath(), allocator); | |
| if (!pdb_file) | |
| return {}; | |
| auto info_stream = pdb_file->getPDBInfoStream(); | |
| if (!info_stream) { | |
| llvm::consumeError(info_stream.takeError()); | |
| return {}; | |
| } | |
| auto dbi_stream = pdb_file->getPDBDbiStream(); | |
| if (!dbi_stream) { | |
| llvm::consumeError(dbi_stream.takeError()); | |
| return {}; | |
| } | |
| lldb_private::UUID &uuid = module_spec.GetUUID(); | |
| uuid = GetPDBUUID(*info_stream, *dbi_stream); | |
| ModuleSpecList specs; | |
| ArchSpec &module_arch = module_spec.GetArchitecture(); | |
| switch (dbi_stream->getMachineType()) { | |
| case PDB_Machine::Amd64: | |
| module_arch.SetTriple("x86_64-pc-windows"); | |
| specs.Append(module_spec); | |
| break; | |
| case PDB_Machine::x86: | |
| module_arch.SetTriple("i386-pc-windows"); | |
| specs.Append(module_spec); | |
| break; | |
| case PDB_Machine::ArmNT: | |
| module_arch.SetTriple("armv7-pc-windows"); | |
| specs.Append(module_spec); | |
| break; | |
| case PDB_Machine::Arm64: | |
| module_arch.SetTriple("aarch64-pc-windows"); | |
| specs.Append(module_spec); | |
| break; | |
| default: | |
| break; | |
| } | |
| return specs; | |
| } | |
| ObjectFilePDB::ObjectFilePDB(const ModuleSP &module_sp, | |
| DataExtractorSP &extractor_sp, | |
| offset_t data_offset, const FileSpec *file, | |
| offset_t offset, offset_t length) | |
| : ObjectFile(module_sp, file, offset, length, extractor_sp, data_offset) {} | |
| std::unique_ptr<PDBFile> | |
| ObjectFilePDB::loadPDBFile(std::string PdbPath, | |
| llvm::BumpPtrAllocator &Allocator) { | |
| llvm::file_magic magic; | |
| auto ec = llvm::identify_magic(PdbPath, magic); | |
| if (ec || magic != llvm::file_magic::pdb) | |
| return nullptr; | |
| llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> ErrorOrBuffer = | |
| llvm::MemoryBuffer::getFile(PdbPath, /*IsText=*/false, | |
| /*RequiresNullTerminator=*/false); | |
| if (!ErrorOrBuffer) | |
| return nullptr; | |
| std::unique_ptr<llvm::MemoryBuffer> Buffer = std::move(*ErrorOrBuffer); | |
| llvm::StringRef Path = Buffer->getBufferIdentifier(); | |
| auto Stream = std::make_unique<llvm::MemoryBufferByteStream>( | |
| std::move(Buffer), llvm::endianness::little); | |
| auto File = std::make_unique<PDBFile>(Path, std::move(Stream), Allocator); | |
| if (auto EC = File->parseFileHeaders()) { | |
| llvm::consumeError(std::move(EC)); | |
| return nullptr; | |
| } | |
| if (auto EC = File->parseStreamData()) { | |
| llvm::consumeError(std::move(EC)); | |
| return nullptr; | |
| } | |
| return File; | |
| } |