Path: blob/main/contrib/llvm-project/lldb/source/Plugins/ObjectFile/COFF/ObjectFileCOFF.cpp
39644 views
//===-- ObjectFileCOFF.cpp ------------------------------------------------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//78#include "ObjectFileCOFF.h"910#include "lldb/Core/Module.h"11#include "lldb/Core/ModuleSpec.h"12#include "lldb/Core/PluginManager.h"13#include "lldb/Utility/LLDBLog.h"1415#include "llvm/Support/Error.h"16#include "llvm/Support/FormatAdapters.h"1718using namespace lldb;19using namespace lldb_private;2021using namespace llvm;22using namespace llvm::object;2324static bool IsCOFFObjectFile(const DataBufferSP &data) {25return identify_magic(toStringRef(data->GetData())) ==26file_magic::coff_object;27}2829LLDB_PLUGIN_DEFINE(ObjectFileCOFF)3031char ObjectFileCOFF::ID;3233ObjectFileCOFF::~ObjectFileCOFF() = default;3435void ObjectFileCOFF::Initialize() {36PluginManager::RegisterPlugin(GetPluginNameStatic(),37GetPluginDescriptionStatic(), CreateInstance,38CreateMemoryInstance, GetModuleSpecifications);39}4041void ObjectFileCOFF::Terminate() {42PluginManager::UnregisterPlugin(CreateInstance);43}4445lldb_private::ObjectFile *46ObjectFileCOFF::CreateInstance(const ModuleSP &module_sp, DataBufferSP data_sp,47offset_t data_offset, const FileSpec *file,48offset_t file_offset, offset_t length) {49Log *log = GetLog(LLDBLog::Object);5051if (!data_sp) {52data_sp = MapFileData(*file, length, file_offset);53if (!data_sp) {54LLDB_LOG(log,55"Failed to create ObjectFileCOFF instance: cannot read file {0}",56file->GetPath());57return nullptr;58}59data_offset = 0;60}6162assert(data_sp && "must have mapped file at this point");6364if (!IsCOFFObjectFile(data_sp))65return nullptr;6667if (data_sp->GetByteSize() < length) {68data_sp = MapFileData(*file, length, file_offset);69if (!data_sp) {70LLDB_LOG(log,71"Failed to create ObjectFileCOFF instance: cannot read file {0}",72file->GetPath());73return nullptr;74}75data_offset = 0;76}777879MemoryBufferRef buffer{toStringRef(data_sp->GetData()),80file->GetFilename().GetStringRef()};8182Expected<std::unique_ptr<Binary>> binary = createBinary(buffer);83if (!binary) {84LLDB_LOG_ERROR(log, binary.takeError(),85"Failed to create binary for file ({1}): {0}",86file->GetPath());87return nullptr;88}8990LLDB_LOG(log, "ObjectFileCOFF::ObjectFileCOFF module = {1} ({2}), file = {3}",91module_sp.get(), module_sp->GetSpecificationDescription(),92file->GetPath());9394return new ObjectFileCOFF(unique_dyn_cast<COFFObjectFile>(std::move(*binary)),95module_sp, data_sp, data_offset, file, file_offset,96length);97}9899lldb_private::ObjectFile *ObjectFileCOFF::CreateMemoryInstance(100const ModuleSP &module_sp, WritableDataBufferSP data_sp,101const ProcessSP &process_sp, addr_t header) {102// FIXME: do we need to worry about construction from a memory region?103return nullptr;104}105106size_t ObjectFileCOFF::GetModuleSpecifications(107const FileSpec &file, DataBufferSP &data_sp, offset_t data_offset,108offset_t file_offset, offset_t length, ModuleSpecList &specs) {109if (!IsCOFFObjectFile(data_sp))110return 0;111112MemoryBufferRef buffer{toStringRef(data_sp->GetData()),113file.GetFilename().GetStringRef()};114Expected<std::unique_ptr<Binary>> binary = createBinary(buffer);115if (!binary) {116Log *log = GetLog(LLDBLog::Object);117LLDB_LOG_ERROR(log, binary.takeError(),118"Failed to create binary for file ({1}): {0}",119file.GetFilename());120return 0;121}122123std::unique_ptr<COFFObjectFile> object =124unique_dyn_cast<COFFObjectFile>(std::move(*binary));125switch (static_cast<COFF::MachineTypes>(object->getMachine())) {126case COFF::IMAGE_FILE_MACHINE_I386:127specs.Append(ModuleSpec(file, ArchSpec("i686-unknown-windows-msvc")));128return 1;129case COFF::IMAGE_FILE_MACHINE_AMD64:130specs.Append(ModuleSpec(file, ArchSpec("x86_64-unknown-windows-msvc")));131return 1;132case COFF::IMAGE_FILE_MACHINE_ARMNT:133specs.Append(ModuleSpec(file, ArchSpec("armv7-unknown-windows-msvc")));134return 1;135case COFF::IMAGE_FILE_MACHINE_ARM64:136specs.Append(ModuleSpec(file, ArchSpec("aarch64-unknown-windows-msvc")));137return 1;138default:139return 0;140}141}142143void ObjectFileCOFF::Dump(Stream *stream) {144ModuleSP module(GetModule());145if (!module)146return;147148std::lock_guard<std::recursive_mutex> guard(module->GetMutex());149150stream->Printf("%p: ", static_cast<void *>(this));151stream->Indent();152stream->PutCString("ObjectFileCOFF");153*stream << ", file = '" << m_file154<< "', arch = " << GetArchitecture().GetArchitectureName() << '\n';155156if (SectionList *sections = GetSectionList())157sections->Dump(stream->AsRawOstream(), stream->GetIndentLevel(), nullptr,158true, std::numeric_limits<uint32_t>::max());159}160161uint32_t ObjectFileCOFF::GetAddressByteSize() const {162return const_cast<ObjectFileCOFF *>(this)->GetArchitecture().GetAddressByteSize();163}164165ArchSpec ObjectFileCOFF::GetArchitecture() {166switch (static_cast<COFF::MachineTypes>(m_object->getMachine())) {167case COFF::IMAGE_FILE_MACHINE_I386:168return ArchSpec("i686-unknown-windows-msvc");169case COFF::IMAGE_FILE_MACHINE_AMD64:170return ArchSpec("x86_64-unknown-windows-msvc");171case COFF::IMAGE_FILE_MACHINE_ARMNT:172return ArchSpec("armv7-unknown-windows-msvc");173case COFF::IMAGE_FILE_MACHINE_ARM64:174return ArchSpec("aarch64-unknown-windows-msvc");175default:176return ArchSpec();177}178}179180void ObjectFileCOFF::CreateSections(lldb_private::SectionList §ions) {181if (m_sections_up)182return;183184m_sections_up = std::make_unique<SectionList>();185ModuleSP module(GetModule());186if (!module)187return;188189std::lock_guard<std::recursive_mutex> guard(module->GetMutex());190191auto SectionType = [](StringRef Name,192const coff_section *Section) -> lldb::SectionType {193lldb::SectionType type =194StringSwitch<lldb::SectionType>(Name)195// DWARF Debug Sections196.Case(".debug_abbrev", eSectionTypeDWARFDebugAbbrev)197.Case(".debug_info", eSectionTypeDWARFDebugInfo)198.Case(".debug_line", eSectionTypeDWARFDebugLine)199.Case(".debug_pubnames", eSectionTypeDWARFDebugPubNames)200.Case(".debug_pubtypes", eSectionTypeDWARFDebugPubTypes)201.Case(".debug_str", eSectionTypeDWARFDebugStr)202// CodeView Debug Sections: .debug$S, .debug$T203.StartsWith(".debug$", eSectionTypeDebug)204.Case("clangast", eSectionTypeOther)205.Default(eSectionTypeInvalid);206if (type != eSectionTypeInvalid)207return type;208209if (Section->Characteristics & COFF::IMAGE_SCN_CNT_CODE)210return eSectionTypeCode;211if (Section->Characteristics & COFF::IMAGE_SCN_CNT_INITIALIZED_DATA)212return eSectionTypeData;213if (Section->Characteristics & COFF::IMAGE_SCN_CNT_UNINITIALIZED_DATA)214return Section->SizeOfRawData ? eSectionTypeData : eSectionTypeZeroFill;215return eSectionTypeOther;216};217auto Permissions = [](const object::coff_section *Section) -> uint32_t {218uint32_t permissions = 0;219if (Section->Characteristics & COFF::IMAGE_SCN_MEM_EXECUTE)220permissions |= lldb::ePermissionsExecutable;221if (Section->Characteristics & COFF::IMAGE_SCN_MEM_READ)222permissions |= lldb::ePermissionsReadable;223if (Section->Characteristics & COFF::IMAGE_SCN_MEM_WRITE)224permissions |= lldb::ePermissionsWritable;225return permissions;226};227228for (const auto &SecRef : m_object->sections()) {229const auto COFFSection = m_object->getCOFFSection(SecRef);230231llvm::Expected<StringRef> Name = SecRef.getName();232StringRef SectionName = Name ? *Name : COFFSection->Name;233if (!Name)234consumeError(Name.takeError());235236SectionSP section =237std::make_unique<Section>(module, this,238static_cast<user_id_t>(SecRef.getIndex()),239ConstString(SectionName),240SectionType(SectionName, COFFSection),241COFFSection->VirtualAddress,242COFFSection->VirtualSize,243COFFSection->PointerToRawData,244COFFSection->SizeOfRawData,245COFFSection->getAlignment(),2460);247section->SetPermissions(Permissions(COFFSection));248249m_sections_up->AddSection(section);250sections.AddSection(section);251}252}253254void ObjectFileCOFF::ParseSymtab(lldb_private::Symtab &symtab) {255Log *log = GetLog(LLDBLog::Object);256257SectionList *sections = GetSectionList();258symtab.Reserve(symtab.GetNumSymbols() + m_object->getNumberOfSymbols());259260auto SymbolType = [](const COFFSymbolRef &Symbol) -> lldb::SymbolType {261if (Symbol.getComplexType() == COFF::IMAGE_SYM_DTYPE_FUNCTION)262return eSymbolTypeCode;263if (Symbol.getBaseType() == COFF::IMAGE_SYM_TYPE_NULL &&264Symbol.getComplexType() == COFF::IMAGE_SYM_DTYPE_NULL)265return eSymbolTypeData;266return eSymbolTypeInvalid;267};268269for (const auto &SymRef : m_object->symbols()) {270const auto COFFSymRef = m_object->getCOFFSymbol(SymRef);271272Expected<StringRef> NameOrErr = SymRef.getName();273if (!NameOrErr) {274LLDB_LOG_ERROR(log, NameOrErr.takeError(),275"ObjectFileCOFF: failed to get symbol name: {0}");276continue;277}278279Symbol symbol;280symbol.GetMangled().SetValue(ConstString(*NameOrErr));281282int16_t SecIdx = static_cast<int16_t>(COFFSymRef.getSectionNumber());283if (SecIdx == COFF::IMAGE_SYM_ABSOLUTE) {284symbol.GetAddressRef() = Address{COFFSymRef.getValue()};285symbol.SetType(eSymbolTypeAbsolute);286} else if (SecIdx >= 1) {287symbol.GetAddressRef() = Address(sections->GetSectionAtIndex(SecIdx - 1),288COFFSymRef.getValue());289symbol.SetType(SymbolType(COFFSymRef));290}291292symtab.AddSymbol(symbol);293}294295LLDB_LOG(log, "ObjectFileCOFF::ParseSymtab processed {0} symbols",296m_object->getNumberOfSymbols());297}298299bool ObjectFileCOFF::ParseHeader() {300ModuleSP module(GetModule());301if (!module)302return false;303304std::lock_guard<std::recursive_mutex> guard(module->GetMutex());305306m_data.SetByteOrder(eByteOrderLittle);307m_data.SetAddressByteSize(GetAddressByteSize());308309return true;310}311312313