Path: blob/main/contrib/llvm-project/lldb/source/Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.cpp
213845 views
//===-- ObjectFileXCOFF.cpp1//-------------------------------------------------===//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//===----------------------------------------------------------------------===//89#include "ObjectFileXCOFF.h"10#include "lldb/Core/Module.h"11#include "lldb/Core/ModuleSpec.h"12#include "lldb/Core/PluginManager.h"13#include "lldb/Core/Progress.h"14#include "lldb/Core/Section.h"15#include "lldb/Host/FileSystem.h"16#include "lldb/Symbol/SymbolContext.h"17#include "lldb/Target/Process.h"18#include "lldb/Target/Target.h"19#include "lldb/Utility/ArchSpec.h"20#include "lldb/Utility/DataBufferHeap.h"21#include "lldb/Utility/FileSpecList.h"22#include "lldb/Utility/LLDBLog.h"23#include "lldb/Utility/Log.h"24#include "lldb/Utility/RangeMap.h"25#include "lldb/Utility/Status.h"26#include "lldb/Utility/Stream.h"27#include "llvm/ADT/StringRef.h"28#include "llvm/BinaryFormat/XCOFF.h"29#include "llvm/Object/XCOFFObjectFile.h"30#include "llvm/Support/MemoryBuffer.h"31#include <algorithm>32#include <cassert>33#include <cstring>34#include <unordered_map>3536using namespace llvm;37using namespace lldb;38using namespace lldb_private;3940LLDB_PLUGIN_DEFINE(ObjectFileXCOFF)41// FIXME: target 64bit at this moment.4243// Static methods.44void ObjectFileXCOFF::Initialize() {45PluginManager::RegisterPlugin(GetPluginNameStatic(),46GetPluginDescriptionStatic(), CreateInstance,47CreateMemoryInstance, GetModuleSpecifications);48}4950void ObjectFileXCOFF::Terminate() {51PluginManager::UnregisterPlugin(CreateInstance);52}5354ObjectFile *ObjectFileXCOFF::CreateInstance(const lldb::ModuleSP &module_sp,55DataBufferSP data_sp,56lldb::offset_t data_offset,57const lldb_private::FileSpec *file,58lldb::offset_t file_offset,59lldb::offset_t length) {60if (!data_sp) {61data_sp = MapFileData(*file, length, file_offset);62if (!data_sp)63return nullptr;64data_offset = 0;65}66if (!ObjectFileXCOFF::MagicBytesMatch(data_sp, data_offset, length))67return nullptr;68// Update the data to contain the entire file if it doesn't already69if (data_sp->GetByteSize() < length) {70data_sp = MapFileData(*file, length, file_offset);71if (!data_sp)72return nullptr;73data_offset = 0;74}75auto objfile_up = std::make_unique<ObjectFileXCOFF>(76module_sp, data_sp, data_offset, file, file_offset, length);77if (!objfile_up)78return nullptr;7980// Cache xcoff binary.81if (!objfile_up->CreateBinary())82return nullptr;8384if (!objfile_up->ParseHeader())85return nullptr;8687return objfile_up.release();88}8990bool ObjectFileXCOFF::CreateBinary() {91if (m_binary)92return true;9394Log *log = GetLog(LLDBLog::Object);9596auto memory_ref = llvm::MemoryBufferRef(toStringRef(m_data.GetData()),97m_file.GetFilename().GetStringRef());98llvm::file_magic magic = llvm::identify_magic(memory_ref.getBuffer());99100auto binary = llvm::object::ObjectFile::createObjectFile(memory_ref, magic);101if (!binary) {102LLDB_LOG_ERROR(log, binary.takeError(),103"Failed to create binary for file ({1}): {0}", m_file);104return false;105}106// Make sure we only handle XCOFF format.107m_binary =108llvm::unique_dyn_cast<llvm::object::XCOFFObjectFile>(std::move(*binary));109if (!m_binary)110return false;111112LLDB_LOG(log, "this = {0}, module = {1} ({2}), file = {3}, binary = {4}",113this, GetModule().get(), GetModule()->GetSpecificationDescription(),114m_file.GetPath(), m_binary.get());115116return true;117}118119ObjectFile *ObjectFileXCOFF::CreateMemoryInstance(120const lldb::ModuleSP &module_sp, WritableDataBufferSP data_sp,121const lldb::ProcessSP &process_sp, lldb::addr_t header_addr) {122return nullptr;123}124125size_t ObjectFileXCOFF::GetModuleSpecifications(126const lldb_private::FileSpec &file, lldb::DataBufferSP &data_sp,127lldb::offset_t data_offset, lldb::offset_t file_offset,128lldb::offset_t length, lldb_private::ModuleSpecList &specs) {129const size_t initial_count = specs.GetSize();130131if (ObjectFileXCOFF::MagicBytesMatch(data_sp, 0, data_sp->GetByteSize())) {132ArchSpec arch_spec =133ArchSpec(eArchTypeXCOFF, XCOFF::TCPU_PPC64, LLDB_INVALID_CPUTYPE);134ModuleSpec spec(file, arch_spec);135spec.GetArchitecture().SetArchitecture(eArchTypeXCOFF, XCOFF::TCPU_PPC64,136LLDB_INVALID_CPUTYPE,137llvm::Triple::AIX);138specs.Append(spec);139}140return specs.GetSize() - initial_count;141}142143static uint32_t XCOFFHeaderSizeFromMagic(uint32_t magic) {144switch (magic) {145case XCOFF::XCOFF32:146return sizeof(struct llvm::object::XCOFFFileHeader32);147break;148case XCOFF::XCOFF64:149return sizeof(struct llvm::object::XCOFFFileHeader64);150break;151152default:153break;154}155return 0;156}157158bool ObjectFileXCOFF::MagicBytesMatch(DataBufferSP &data_sp,159lldb::addr_t data_offset,160lldb::addr_t data_length) {161lldb_private::DataExtractor data;162data.SetData(data_sp, data_offset, data_length);163// Need to set this as XCOFF is only compatible with Big Endian164data.SetByteOrder(eByteOrderBig);165lldb::offset_t offset = 0;166uint16_t magic = data.GetU16(&offset);167return XCOFFHeaderSizeFromMagic(magic) != 0;168}169170bool ObjectFileXCOFF::ParseHeader() {171if (m_binary->is64Bit())172return m_binary->fileHeader64()->Magic == XCOFF::XCOFF64;173return m_binary->fileHeader32()->Magic == XCOFF::XCOFF32;174}175176ByteOrder ObjectFileXCOFF::GetByteOrder() const { return eByteOrderBig; }177178bool ObjectFileXCOFF::IsExecutable() const { return true; }179180uint32_t ObjectFileXCOFF::GetAddressByteSize() const {181if (m_binary->is64Bit())182return 8;183return 4;184}185186AddressClass ObjectFileXCOFF::GetAddressClass(addr_t file_addr) {187return AddressClass::eUnknown;188}189190static lldb::SymbolType MapSymbolType(llvm::object::SymbolRef::Type sym_type) {191switch (sym_type) {192case llvm::object::SymbolRef::ST_Function:193return lldb::eSymbolTypeCode;194case llvm::object::SymbolRef::ST_Data:195return lldb::eSymbolTypeData;196case llvm::object::SymbolRef::ST_File:197return lldb::eSymbolTypeSourceFile;198default:199return lldb::eSymbolTypeInvalid;200}201}202203void ObjectFileXCOFF::ParseSymtab(Symtab &lldb_symtab) {204Log *log = GetLog(LLDBLog::Object);205SectionList *sectionList = GetSectionList();206207for (const auto &symbol_ref : m_binary->symbols()) {208llvm::object::XCOFFSymbolRef xcoff_sym_ref(symbol_ref);209210llvm::Expected<llvm::StringRef> name_or_err = xcoff_sym_ref.getName();211if (!name_or_err) {212LLDB_LOG_ERROR(log, name_or_err.takeError(),213"Unable to extract name from the xcoff symbol ref object");214continue;215}216217llvm::StringRef symbolName = name_or_err.get();218// Remove the . prefix added during compilation. This prefix is usually219// added to differentiate between reference to the code and function220// descriptor. For instance, Adding .func will only allow user to put bp on221// .func, which is not known to the user, instead of func.222llvm::StringRef name_no_dot =223symbolName.starts_with(".") ? symbolName.drop_front() : symbolName;224auto storageClass = xcoff_sym_ref.getStorageClass();225// C_HIDEXT symbols are not needed to be exposed, with the exception of TOC226// which is responsible for storing references to global data227if (storageClass == XCOFF::C_HIDEXT && symbolName != "TOC") {228229// Zero or muliple aux entries may suggest ambiguous data230if (xcoff_sym_ref.getNumberOfAuxEntries() != 1)231continue;232233auto aux_csect_or_err = xcoff_sym_ref.getXCOFFCsectAuxRef();234if (!aux_csect_or_err) {235LLDB_LOG_ERROR(log, aux_csect_or_err.takeError(),236"Unable to access xcoff csect aux ref object");237continue;238}239240const llvm::object::XCOFFCsectAuxRef csect_aux = aux_csect_or_err.get();241242// Only add hidden ext entries which come under Program Code, skip others243// as they are not useful as debugging data.244if (csect_aux.getStorageMappingClass() != XCOFF::XMC_PR)245continue;246247// This does not apply to 32-bit,248// Only add csect symbols identified by the aux entry, as they are249// needed to reference section information. Skip others250if (m_binary->is64Bit())251if (csect_aux.getAuxType64() != XCOFF::AUX_CSECT)252continue;253}254255Symbol symbol;256symbol.GetMangled().SetValue(ConstString(name_no_dot));257258int16_t sectionNumber = xcoff_sym_ref.getSectionNumber();259// Note that XCOFF section headers are numbered from 1 and not 0.260size_t sectionIndex = static_cast<size_t>(sectionNumber - 1);261if (sectionNumber > 0) {262if (sectionIndex < sectionList->GetSize()) {263264lldb::SectionSP section_sp =265sectionList->GetSectionAtIndex(sectionIndex);266if (!section_sp || section_sp->GetFileAddress() == LLDB_INVALID_ADDRESS)267continue;268269lldb::addr_t file_addr = section_sp->GetFileAddress();270lldb::addr_t symbolValue = xcoff_sym_ref.getValue();271if (symbolValue < file_addr)272continue;273274symbol.GetAddressRef() = Address(section_sp, symbolValue - file_addr);275}276}277278Expected<llvm::object::SymbolRef::Type> sym_type_or_err =279symbol_ref.getType();280if (!sym_type_or_err) {281LLDB_LOG_ERROR(log, sym_type_or_err.takeError(),282"Unable to access xcoff symbol type");283continue;284}285286symbol.SetType(MapSymbolType(sym_type_or_err.get()));287288lldb_symtab.AddSymbol(symbol);289}290}291292bool ObjectFileXCOFF::IsStripped() { return false; }293294void ObjectFileXCOFF::CreateSections(SectionList &unified_section_list) {295296if (m_sections_up)297return;298299m_sections_up = std::make_unique<SectionList>();300if (m_binary->is64Bit())301CreateSectionsWithBitness<XCOFF64>(unified_section_list);302else303CreateSectionsWithBitness<XCOFF32>(unified_section_list);304}305306template <typename T>307static auto GetSections(llvm::object::XCOFFObjectFile *binary) {308if constexpr (T::Is64Bit)309return binary->sections64();310else311return binary->sections32();312}313314template <typename T>315void ObjectFileXCOFF::CreateSectionsWithBitness(316SectionList &unified_section_list) {317ModuleSP module_sp(GetModule());318if (!module_sp)319return;320321std::lock_guard<std::recursive_mutex> guard(module_sp->GetMutex());322323int idx = 0;324for (const typename T::SectionHeader §ion :325GetSections<T>(m_binary.get())) {326327ConstString const_sect_name(section.Name);328329SectionType section_type = lldb::eSectionTypeOther;330if (section.Flags & XCOFF::STYP_TEXT)331section_type = eSectionTypeCode;332else if (section.Flags & XCOFF::STYP_DATA)333section_type = eSectionTypeData;334else if (section.Flags & XCOFF::STYP_BSS)335section_type = eSectionTypeZeroFill;336else if (section.Flags & XCOFF::STYP_DWARF) {337section_type = llvm::StringSwitch<SectionType>(section.Name)338.Case(".dwinfo", eSectionTypeDWARFDebugInfo)339.Case(".dwline", eSectionTypeDWARFDebugLine)340.Case(".dwabrev", eSectionTypeDWARFDebugAbbrev)341.Case(".dwrnges", eSectionTypeDWARFDebugRanges)342.Default(eSectionTypeInvalid);343}344345SectionSP section_sp(new Section(346module_sp, this, ++idx, const_sect_name, section_type,347section.VirtualAddress, section.SectionSize,348section.FileOffsetToRawData, section.SectionSize, 0, section.Flags));349350uint32_t permissions = ePermissionsReadable;351if (section.Flags & (XCOFF::STYP_DATA | XCOFF::STYP_BSS))352permissions |= ePermissionsWritable;353if (section.Flags & XCOFF::STYP_TEXT)354permissions |= ePermissionsExecutable;355356section_sp->SetPermissions(permissions);357m_sections_up->AddSection(section_sp);358unified_section_list.AddSection(section_sp);359}360}361362void ObjectFileXCOFF::Dump(Stream *s) {}363364ArchSpec ObjectFileXCOFF::GetArchitecture() {365ArchSpec arch_spec =366ArchSpec(eArchTypeXCOFF, XCOFF::TCPU_PPC64, LLDB_INVALID_CPUTYPE);367return arch_spec;368}369370UUID ObjectFileXCOFF::GetUUID() { return UUID(); }371372uint32_t ObjectFileXCOFF::GetDependentModules(FileSpecList &files) { return 0; }373374ObjectFile::Type ObjectFileXCOFF::CalculateType() {375376const auto flags = m_binary->is64Bit() ? m_binary->fileHeader64()->Flags377: m_binary->fileHeader32()->Flags;378379if (flags & XCOFF::F_EXEC)380return eTypeExecutable;381else if (flags & XCOFF::F_SHROBJ)382return eTypeSharedLibrary;383return eTypeUnknown;384}385386ObjectFile::Strata ObjectFileXCOFF::CalculateStrata() { return eStrataUnknown; }387388lldb::WritableDataBufferSP389ObjectFileXCOFF::MapFileDataWritable(const FileSpec &file, uint64_t Size,390uint64_t Offset) {391return FileSystem::Instance().CreateWritableDataBuffer(file.GetPath(), Size,392Offset);393}394395ObjectFileXCOFF::ObjectFileXCOFF(const lldb::ModuleSP &module_sp,396DataBufferSP data_sp,397lldb::offset_t data_offset,398const FileSpec *file,399lldb::offset_t file_offset,400lldb::offset_t length)401: ObjectFile(module_sp, file, file_offset, length, data_sp, data_offset) {402if (file)403m_file = *file;404}405406ObjectFileXCOFF::ObjectFileXCOFF(const lldb::ModuleSP &module_sp,407DataBufferSP header_data_sp,408const lldb::ProcessSP &process_sp,409addr_t header_addr)410: ObjectFile(module_sp, process_sp, header_addr, header_data_sp) {}411412413