brintos

brintos / llvm-project-archived public Read only

0
0
Text · 14.0 KiB · d2c46ed Raw
412 lines · cpp
1//===-- ObjectFileXCOFF.cpp2//-------------------------------------------------===//3//4// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.5// See https://llvm.org/LICENSE.txt for license information.6// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception7//8//===----------------------------------------------------------------------===//9 10#include "ObjectFileXCOFF.h"11#include "lldb/Core/Module.h"12#include "lldb/Core/ModuleSpec.h"13#include "lldb/Core/PluginManager.h"14#include "lldb/Core/Progress.h"15#include "lldb/Core/Section.h"16#include "lldb/Host/FileSystem.h"17#include "lldb/Symbol/SymbolContext.h"18#include "lldb/Target/Process.h"19#include "lldb/Target/Target.h"20#include "lldb/Utility/ArchSpec.h"21#include "lldb/Utility/DataBufferHeap.h"22#include "lldb/Utility/FileSpecList.h"23#include "lldb/Utility/LLDBLog.h"24#include "lldb/Utility/Log.h"25#include "lldb/Utility/RangeMap.h"26#include "lldb/Utility/Status.h"27#include "lldb/Utility/Stream.h"28#include "llvm/ADT/StringRef.h"29#include "llvm/BinaryFormat/XCOFF.h"30#include "llvm/Object/XCOFFObjectFile.h"31#include "llvm/Support/MemoryBuffer.h"32#include <algorithm>33#include <cassert>34#include <cstring>35#include <unordered_map>36 37using namespace llvm;38using namespace lldb;39using namespace lldb_private;40 41LLDB_PLUGIN_DEFINE(ObjectFileXCOFF)42// FIXME: target 64bit at this moment.43 44// Static methods.45void ObjectFileXCOFF::Initialize() {46  PluginManager::RegisterPlugin(GetPluginNameStatic(),47                                GetPluginDescriptionStatic(), CreateInstance,48                                CreateMemoryInstance, GetModuleSpecifications);49}50 51void ObjectFileXCOFF::Terminate() {52  PluginManager::UnregisterPlugin(CreateInstance);53}54 55ObjectFile *ObjectFileXCOFF::CreateInstance(const lldb::ModuleSP &module_sp,56                                            DataBufferSP data_sp,57                                            lldb::offset_t data_offset,58                                            const lldb_private::FileSpec *file,59                                            lldb::offset_t file_offset,60                                            lldb::offset_t length) {61  if (!data_sp) {62    data_sp = MapFileData(*file, length, file_offset);63    if (!data_sp)64      return nullptr;65    data_offset = 0;66  }67  if (!ObjectFileXCOFF::MagicBytesMatch(data_sp, data_offset, length))68    return nullptr;69  // Update the data to contain the entire file if it doesn't already70  if (data_sp->GetByteSize() < length) {71    data_sp = MapFileData(*file, length, file_offset);72    if (!data_sp)73      return nullptr;74    data_offset = 0;75  }76  auto objfile_up = std::make_unique<ObjectFileXCOFF>(77      module_sp, data_sp, data_offset, file, file_offset, length);78  if (!objfile_up)79    return nullptr;80 81  // Cache xcoff binary.82  if (!objfile_up->CreateBinary())83    return nullptr;84 85  if (!objfile_up->ParseHeader())86    return nullptr;87 88  return objfile_up.release();89}90 91bool ObjectFileXCOFF::CreateBinary() {92  if (m_binary)93    return true;94 95  Log *log = GetLog(LLDBLog::Object);96 97  auto memory_ref = llvm::MemoryBufferRef(toStringRef(m_data.GetData()),98                                          m_file.GetFilename().GetStringRef());99  llvm::file_magic magic = llvm::identify_magic(memory_ref.getBuffer());100 101  auto binary = llvm::object::ObjectFile::createObjectFile(memory_ref, magic);102  if (!binary) {103    LLDB_LOG_ERROR(log, binary.takeError(),104                   "Failed to create binary for file ({1}): {0}", m_file);105    return false;106  }107  // Make sure we only handle XCOFF format.108  m_binary =109      llvm::unique_dyn_cast<llvm::object::XCOFFObjectFile>(std::move(*binary));110  if (!m_binary)111    return false;112 113  LLDB_LOG(log, "this = {0}, module = {1} ({2}), file = {3}, binary = {4}",114           this, GetModule().get(), GetModule()->GetSpecificationDescription(),115           m_file.GetPath(), m_binary.get());116 117  return true;118}119 120ObjectFile *ObjectFileXCOFF::CreateMemoryInstance(121    const lldb::ModuleSP &module_sp, WritableDataBufferSP data_sp,122    const lldb::ProcessSP &process_sp, lldb::addr_t header_addr) {123  return nullptr;124}125 126size_t ObjectFileXCOFF::GetModuleSpecifications(127    const lldb_private::FileSpec &file, lldb::DataBufferSP &data_sp,128    lldb::offset_t data_offset, lldb::offset_t file_offset,129    lldb::offset_t length, lldb_private::ModuleSpecList &specs) {130  const size_t initial_count = specs.GetSize();131 132  if (ObjectFileXCOFF::MagicBytesMatch(data_sp, 0, data_sp->GetByteSize())) {133    ArchSpec arch_spec =134        ArchSpec(eArchTypeXCOFF, XCOFF::TCPU_PPC64, LLDB_INVALID_CPUTYPE);135    ModuleSpec spec(file, arch_spec);136    spec.GetArchitecture().SetArchitecture(eArchTypeXCOFF, XCOFF::TCPU_PPC64,137                                           LLDB_INVALID_CPUTYPE,138                                           llvm::Triple::AIX);139    specs.Append(spec);140  }141  return specs.GetSize() - initial_count;142}143 144static uint32_t XCOFFHeaderSizeFromMagic(uint32_t magic) {145  switch (magic) {146  case XCOFF::XCOFF32:147    return sizeof(struct llvm::object::XCOFFFileHeader32);148    break;149  case XCOFF::XCOFF64:150    return sizeof(struct llvm::object::XCOFFFileHeader64);151    break;152 153  default:154    break;155  }156  return 0;157}158 159bool ObjectFileXCOFF::MagicBytesMatch(DataBufferSP &data_sp,160                                      lldb::addr_t data_offset,161                                      lldb::addr_t data_length) {162  lldb_private::DataExtractor data;163  data.SetData(data_sp, data_offset, data_length);164  // Need to set this as XCOFF is only compatible with Big Endian165  data.SetByteOrder(eByteOrderBig);166  lldb::offset_t offset = 0;167  uint16_t magic = data.GetU16(&offset);168  return XCOFFHeaderSizeFromMagic(magic) != 0;169}170 171bool ObjectFileXCOFF::ParseHeader() {172  if (m_binary->is64Bit())173    return m_binary->fileHeader64()->Magic == XCOFF::XCOFF64;174  return m_binary->fileHeader32()->Magic == XCOFF::XCOFF32;175}176 177ByteOrder ObjectFileXCOFF::GetByteOrder() const { return eByteOrderBig; }178 179bool ObjectFileXCOFF::IsExecutable() const { return true; }180 181uint32_t ObjectFileXCOFF::GetAddressByteSize() const {182  if (m_binary->is64Bit())183    return 8;184  return 4;185}186 187AddressClass ObjectFileXCOFF::GetAddressClass(addr_t file_addr) {188  return AddressClass::eUnknown;189}190 191static lldb::SymbolType MapSymbolType(llvm::object::SymbolRef::Type sym_type) {192  switch (sym_type) {193  case llvm::object::SymbolRef::ST_Function:194    return lldb::eSymbolTypeCode;195  case llvm::object::SymbolRef::ST_Data:196    return lldb::eSymbolTypeData;197  case llvm::object::SymbolRef::ST_File:198    return lldb::eSymbolTypeSourceFile;199  default:200    return lldb::eSymbolTypeInvalid;201  }202}203 204void ObjectFileXCOFF::ParseSymtab(Symtab &lldb_symtab) {205  Log *log = GetLog(LLDBLog::Object);206  SectionList *sectionList = GetSectionList();207 208  for (const auto &symbol_ref : m_binary->symbols()) {209    llvm::object::XCOFFSymbolRef xcoff_sym_ref(symbol_ref);210 211    llvm::Expected<llvm::StringRef> name_or_err = xcoff_sym_ref.getName();212    if (!name_or_err) {213      LLDB_LOG_ERROR(log, name_or_err.takeError(),214                     "Unable to extract name from the xcoff symbol ref object");215      continue;216    }217 218    llvm::StringRef symbolName = name_or_err.get();219    // Remove the . prefix added during compilation. This prefix is usually220    // added to differentiate between reference to the code and function221    // descriptor. For instance, Adding .func will only allow user to put bp on222    // .func, which is not known to the user, instead of func.223    llvm::StringRef name_no_dot =224        symbolName.starts_with(".") ? symbolName.drop_front() : symbolName;225    auto storageClass = xcoff_sym_ref.getStorageClass();226    // C_HIDEXT symbols are not needed to be exposed, with the exception of TOC227    // which is responsible for storing references to global data228    if (storageClass == XCOFF::C_HIDEXT && symbolName != "TOC") {229 230      // Zero or muliple aux entries may suggest ambiguous data231      if (xcoff_sym_ref.getNumberOfAuxEntries() != 1)232        continue;233 234      auto aux_csect_or_err = xcoff_sym_ref.getXCOFFCsectAuxRef();235      if (!aux_csect_or_err) {236        LLDB_LOG_ERROR(log, aux_csect_or_err.takeError(),237                       "Unable to access xcoff csect aux ref object");238        continue;239      }240 241      const llvm::object::XCOFFCsectAuxRef csect_aux = aux_csect_or_err.get();242 243      // Only add hidden ext entries which come under Program Code, skip others244      // as they are not useful as debugging data.245      if (csect_aux.getStorageMappingClass() != XCOFF::XMC_PR)246        continue;247 248      // This does not apply to 32-bit,249      // Only add csect symbols identified by the aux entry, as they are250      // needed to reference section information. Skip others251      if (m_binary->is64Bit())252        if (csect_aux.getAuxType64() != XCOFF::AUX_CSECT)253          continue;254    }255 256    Symbol symbol;257    symbol.GetMangled().SetValue(ConstString(name_no_dot));258 259    int16_t sectionNumber = xcoff_sym_ref.getSectionNumber();260    // Note that XCOFF section headers are numbered from 1 and not 0.261    size_t sectionIndex = static_cast<size_t>(sectionNumber - 1);262    if (sectionNumber > 0) {263      if (sectionIndex < sectionList->GetSize()) {264 265        lldb::SectionSP section_sp =266            sectionList->GetSectionAtIndex(sectionIndex);267        if (!section_sp || section_sp->GetFileAddress() == LLDB_INVALID_ADDRESS)268          continue;269 270        lldb::addr_t file_addr = section_sp->GetFileAddress();271        lldb::addr_t symbolValue = xcoff_sym_ref.getValue();272        if (symbolValue < file_addr)273          continue;274 275        symbol.GetAddressRef() = Address(section_sp, symbolValue - file_addr);276      }277    }278 279    Expected<llvm::object::SymbolRef::Type> sym_type_or_err =280        symbol_ref.getType();281    if (!sym_type_or_err) {282      LLDB_LOG_ERROR(log, sym_type_or_err.takeError(),283                     "Unable to access xcoff symbol type");284      continue;285    }286 287    symbol.SetType(MapSymbolType(sym_type_or_err.get()));288 289    lldb_symtab.AddSymbol(symbol);290  }291}292 293bool ObjectFileXCOFF::IsStripped() { return false; }294 295void ObjectFileXCOFF::CreateSections(SectionList &unified_section_list) {296 297  if (m_sections_up)298    return;299 300  m_sections_up = std::make_unique<SectionList>();301  if (m_binary->is64Bit())302    CreateSectionsWithBitness<XCOFF64>(unified_section_list);303  else304    CreateSectionsWithBitness<XCOFF32>(unified_section_list);305}306 307template <typename T>308static auto GetSections(llvm::object::XCOFFObjectFile *binary) {309  if constexpr (T::Is64Bit)310    return binary->sections64();311  else312    return binary->sections32();313}314 315template <typename T>316void ObjectFileXCOFF::CreateSectionsWithBitness(317    SectionList &unified_section_list) {318  ModuleSP module_sp(GetModule());319  if (!module_sp)320    return;321 322  std::lock_guard<std::recursive_mutex> guard(module_sp->GetMutex());323 324  int idx = 0;325  for (const typename T::SectionHeader &section :326       GetSections<T>(m_binary.get())) {327 328    ConstString const_sect_name(section.Name);329 330    SectionType section_type = lldb::eSectionTypeOther;331    if (section.Flags & XCOFF::STYP_TEXT)332      section_type = eSectionTypeCode;333    else if (section.Flags & XCOFF::STYP_DATA)334      section_type = eSectionTypeData;335    else if (section.Flags & XCOFF::STYP_BSS)336      section_type = eSectionTypeZeroFill;337    else if (section.Flags & XCOFF::STYP_DWARF) {338      section_type = llvm::StringSwitch<SectionType>(section.Name)339                         .Case(".dwinfo", eSectionTypeDWARFDebugInfo)340                         .Case(".dwline", eSectionTypeDWARFDebugLine)341                         .Case(".dwabrev", eSectionTypeDWARFDebugAbbrev)342                         .Case(".dwrnges", eSectionTypeDWARFDebugRanges)343                         .Default(eSectionTypeInvalid);344    }345 346    SectionSP section_sp(new Section(347        module_sp, this, ++idx, const_sect_name, section_type,348        section.VirtualAddress, section.SectionSize,349        section.FileOffsetToRawData, section.SectionSize, 0, section.Flags));350 351    uint32_t permissions = ePermissionsReadable;352    if (section.Flags & (XCOFF::STYP_DATA | XCOFF::STYP_BSS))353      permissions |= ePermissionsWritable;354    if (section.Flags & XCOFF::STYP_TEXT)355      permissions |= ePermissionsExecutable;356 357    section_sp->SetPermissions(permissions);358    m_sections_up->AddSection(section_sp);359    unified_section_list.AddSection(section_sp);360  }361}362 363void ObjectFileXCOFF::Dump(Stream *s) {}364 365ArchSpec ObjectFileXCOFF::GetArchitecture() {366  ArchSpec arch_spec =367      ArchSpec(eArchTypeXCOFF, XCOFF::TCPU_PPC64, LLDB_INVALID_CPUTYPE);368  return arch_spec;369}370 371UUID ObjectFileXCOFF::GetUUID() { return UUID(); }372 373uint32_t ObjectFileXCOFF::GetDependentModules(FileSpecList &files) { return 0; }374 375ObjectFile::Type ObjectFileXCOFF::CalculateType() {376 377  const auto flags = m_binary->is64Bit() ? m_binary->fileHeader64()->Flags378                                         : m_binary->fileHeader32()->Flags;379 380  if (flags & XCOFF::F_EXEC)381    return eTypeExecutable;382  else if (flags & XCOFF::F_SHROBJ)383    return eTypeSharedLibrary;384  return eTypeUnknown;385}386 387ObjectFile::Strata ObjectFileXCOFF::CalculateStrata() { return eStrataUnknown; }388 389lldb::WritableDataBufferSP390ObjectFileXCOFF::MapFileDataWritable(const FileSpec &file, uint64_t Size,391                                     uint64_t Offset) {392  return FileSystem::Instance().CreateWritableDataBuffer(file.GetPath(), Size,393                                                         Offset);394}395 396ObjectFileXCOFF::ObjectFileXCOFF(const lldb::ModuleSP &module_sp,397                                 DataBufferSP data_sp,398                                 lldb::offset_t data_offset,399                                 const FileSpec *file,400                                 lldb::offset_t file_offset,401                                 lldb::offset_t length)402    : ObjectFile(module_sp, file, file_offset, length, data_sp, data_offset) {403  if (file)404    m_file = *file;405}406 407ObjectFileXCOFF::ObjectFileXCOFF(const lldb::ModuleSP &module_sp,408                                 DataBufferSP header_data_sp,409                                 const lldb::ProcessSP &process_sp,410                                 addr_t header_addr)411    : ObjectFile(module_sp, process_sp, header_addr, header_data_sp) {}412