brintos

brintos / llvm-project-archived public Read only

0
0
Text · 11.7 KiB · a6e385f Raw
442 lines · cpp
1//===-- ELFHeader.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 <cstring>10 11#include "lldb/Core/Section.h"12#include "lldb/Utility/DataExtractor.h"13#include "lldb/Utility/Stream.h"14 15#include "ELFHeader.h"16 17using namespace elf;18using namespace lldb;19using namespace llvm::ELF;20 21// Static utility functions.22//23// GetMaxU64 and GetMaxS64 wrap the similarly named methods from DataExtractor24// with error handling code and provide for parsing a sequence of values.25static bool GetMaxU64(const lldb_private::DataExtractor &data,26                      lldb::offset_t *offset, uint64_t *value,27                      uint32_t byte_size) {28  const lldb::offset_t saved_offset = *offset;29  *value = data.GetMaxU64(offset, byte_size);30  return *offset != saved_offset;31}32 33static bool GetMaxU64(const lldb_private::DataExtractor &data,34                      lldb::offset_t *offset, uint64_t *value,35                      uint32_t byte_size, uint32_t count) {36  lldb::offset_t saved_offset = *offset;37 38  for (uint32_t i = 0; i < count; ++i, ++value) {39    if (!GetMaxU64(data, offset, value, byte_size)) {40      *offset = saved_offset;41      return false;42    }43  }44  return true;45}46 47static bool GetMaxS64(const lldb_private::DataExtractor &data,48                      lldb::offset_t *offset, int64_t *value,49                      uint32_t byte_size) {50  const lldb::offset_t saved_offset = *offset;51  *value = data.GetMaxS64(offset, byte_size);52  return *offset != saved_offset;53}54 55static bool GetMaxS64(const lldb_private::DataExtractor &data,56                      lldb::offset_t *offset, int64_t *value,57                      uint32_t byte_size, uint32_t count) {58  lldb::offset_t saved_offset = *offset;59 60  for (uint32_t i = 0; i < count; ++i, ++value) {61    if (!GetMaxS64(data, offset, value, byte_size)) {62      *offset = saved_offset;63      return false;64    }65  }66  return true;67}68 69// ELFHeader70 71ELFHeader::ELFHeader() { memset(this, 0, sizeof(ELFHeader)); }72 73ByteOrder ELFHeader::GetByteOrder() const {74  if (e_ident[EI_DATA] == ELFDATA2MSB)75    return eByteOrderBig;76  if (e_ident[EI_DATA] == ELFDATA2LSB)77    return eByteOrderLittle;78  return eByteOrderInvalid;79}80 81bool ELFHeader::HasHeaderExtension() const {82  bool result = false;83 84  // Check if any of these values looks like sentinel.85  result |= e_phnum_hdr == 0xFFFF; // PN_XNUM86  result |= e_shnum_hdr == SHN_UNDEF;87  result |= e_shstrndx_hdr == SHN_XINDEX;88 89  // If header extension is present, the section offset cannot be null.90  result &= e_shoff != 0;91 92  // Done.93  return result;94}95 96void ELFHeader::ParseHeaderExtension(lldb_private::DataExtractor &data) {97  // Extract section #0 header.98  ELFSectionHeader section_zero;99  lldb::offset_t offset = 0;100  lldb_private::DataExtractor sh_data(data, e_shoff, e_shentsize);101  bool ok = section_zero.Parse(sh_data, &offset);102 103  // If we succeeded, fix the header.104  if (ok) {105    if (e_phnum_hdr == 0xFFFF) // PN_XNUM106      e_phnum = section_zero.sh_info;107    if (e_shnum_hdr == SHN_UNDEF)108      e_shnum = section_zero.sh_size;109    if (e_shstrndx_hdr == SHN_XINDEX)110      e_shstrndx = section_zero.sh_link;111  }112}113 114bool ELFHeader::Parse(lldb_private::DataExtractor &data,115                      lldb::offset_t *offset) {116  // Read e_ident.  This provides byte order and address size info.117  if (data.GetU8(offset, &e_ident, EI_NIDENT) == nullptr)118    return false;119 120  const unsigned byte_size = Is32Bit() ? 4 : 8;121  data.SetByteOrder(GetByteOrder());122  data.SetAddressByteSize(byte_size);123 124  // Read e_type and e_machine.125  if (data.GetU16(offset, &e_type, 2) == nullptr)126    return false;127 128  // Read e_version.129  if (data.GetU32(offset, &e_version, 1) == nullptr)130    return false;131 132  // Read e_entry, e_phoff and e_shoff.133  if (!GetMaxU64(data, offset, &e_entry, byte_size, 3))134    return false;135 136  // Read e_flags.137  if (data.GetU32(offset, &e_flags, 1) == nullptr)138    return false;139 140  // Read e_ehsize, e_phentsize, e_phnum, e_shentsize, e_shnum and e_shstrndx.141  if (data.GetU16(offset, &e_ehsize, 6) == nullptr)142    return false;143 144  // Initialize e_phnum, e_shnum, and e_shstrndx with the values read from the145  // header.146  e_phnum = e_phnum_hdr;147  e_shnum = e_shnum_hdr;148  e_shstrndx = e_shstrndx_hdr;149 150  // See if we have extended header in section #0.151  if (HasHeaderExtension())152    ParseHeaderExtension(data);153 154  return true;155}156 157bool ELFHeader::MagicBytesMatch(const uint8_t *magic) {158  return memcmp(magic, ElfMagic, strlen(ElfMagic)) == 0;159}160 161unsigned ELFHeader::AddressSizeInBytes(const uint8_t *magic) {162  unsigned address_size = 0;163 164  switch (magic[EI_CLASS]) {165  case ELFCLASS32:166    address_size = 4;167    break;168 169  case ELFCLASS64:170    address_size = 8;171    break;172  }173  return address_size;174}175 176unsigned ELFHeader::GetRelocationJumpSlotType() const {177  unsigned slot = 0;178 179  switch (e_machine) {180  default:181    assert(false && "architecture not supported");182    break;183  case EM_PPC:184    slot = R_PPC_JMP_SLOT;185    break;186  case EM_PPC64:187    slot = R_PPC64_JMP_SLOT;188    break;189  case EM_386:190  case EM_IAMCU: // FIXME: is this correct?191    slot = R_386_JUMP_SLOT;192    break;193  case EM_X86_64:194    slot = R_X86_64_JUMP_SLOT;195    break;196  case EM_ARM:197    slot = R_ARM_JUMP_SLOT;198    break;199  case EM_HEXAGON:200    slot = R_HEX_JMP_SLOT;201    break;202  case EM_AARCH64:203    slot = R_AARCH64_JUMP_SLOT;204    break;205  case EM_MIPS:206    slot = R_MIPS_JUMP_SLOT;207    break;208  case EM_S390:209    slot = R_390_JMP_SLOT;210    break;211  case EM_RISCV:212    slot = R_RISCV_JUMP_SLOT;213    break;214  case EM_LOONGARCH:215    slot = R_LARCH_JUMP_SLOT;216    break;217  }218 219  return slot;220}221 222// ELFSectionHeader223 224ELFSectionHeader::ELFSectionHeader() {225  memset(this, 0, sizeof(ELFSectionHeader));226}227 228bool ELFSectionHeader::Parse(const lldb_private::DataExtractor &data,229                             lldb::offset_t *offset) {230  const unsigned byte_size = data.GetAddressByteSize();231 232  // Read sh_name and sh_type.233  if (data.GetU32(offset, &sh_name, 2) == nullptr)234    return false;235 236  // Read sh_flags.237  if (!GetMaxU64(data, offset, &sh_flags, byte_size))238    return false;239 240  // Read sh_addr, sh_off and sh_size.241  if (!GetMaxU64(data, offset, &sh_addr, byte_size, 3))242    return false;243 244  // Read sh_link and sh_info.245  if (data.GetU32(offset, &sh_link, 2) == nullptr)246    return false;247 248  // Read sh_addralign and sh_entsize.249  if (!GetMaxU64(data, offset, &sh_addralign, byte_size, 2))250    return false;251 252  return true;253}254 255// ELFSymbol256 257ELFSymbol::ELFSymbol() { memset(this, 0, sizeof(ELFSymbol)); }258 259#define ENUM_TO_CSTR(e)                                                        \260  case e:                                                                      \261    return #e262 263const char *ELFSymbol::bindingToCString(unsigned char binding) {264  switch (binding) {265    ENUM_TO_CSTR(STB_LOCAL);266    ENUM_TO_CSTR(STB_GLOBAL);267    ENUM_TO_CSTR(STB_WEAK);268    ENUM_TO_CSTR(STB_LOOS);269    ENUM_TO_CSTR(STB_HIOS);270    ENUM_TO_CSTR(STB_LOPROC);271    ENUM_TO_CSTR(STB_HIPROC);272  }273  return "";274}275 276const char *ELFSymbol::typeToCString(unsigned char type) {277  switch (type) {278    ENUM_TO_CSTR(STT_NOTYPE);279    ENUM_TO_CSTR(STT_OBJECT);280    ENUM_TO_CSTR(STT_FUNC);281    ENUM_TO_CSTR(STT_SECTION);282    ENUM_TO_CSTR(STT_FILE);283    ENUM_TO_CSTR(STT_COMMON);284    ENUM_TO_CSTR(STT_TLS);285    ENUM_TO_CSTR(STT_GNU_IFUNC);286    ENUM_TO_CSTR(STT_HIOS);287    ENUM_TO_CSTR(STT_LOPROC);288    ENUM_TO_CSTR(STT_HIPROC);289  }290  return "";291}292 293const char *ELFSymbol::sectionIndexToCString(294    elf_half shndx, const lldb_private::SectionList *section_list) {295  switch (shndx) {296    ENUM_TO_CSTR(SHN_UNDEF);297    ENUM_TO_CSTR(SHN_LOPROC);298    ENUM_TO_CSTR(SHN_HIPROC);299    ENUM_TO_CSTR(SHN_LOOS);300    ENUM_TO_CSTR(SHN_HIOS);301    ENUM_TO_CSTR(SHN_ABS);302    ENUM_TO_CSTR(SHN_COMMON);303    ENUM_TO_CSTR(SHN_XINDEX);304  default: {305    const lldb_private::Section *section =306        section_list->GetSectionAtIndex(shndx).get();307    if (section)308      return section->GetName().AsCString("");309  } break;310  }311  return "";312}313 314void ELFSymbol::Dump(lldb_private::Stream *s, uint32_t idx,315                     const lldb_private::DataExtractor *strtab_data,316                     const lldb_private::SectionList *section_list) {317  s->Printf("[%3u] 0x%16.16" PRIx64 " 0x%16.16" PRIx64318            " 0x%8.8x 0x%2.2x (%-10s %-13s) 0x%2.2x 0x%4.4x (%-10s) %s\n",319            idx, st_value, st_size, st_name, st_info,320            bindingToCString(getBinding()), typeToCString(getType()), st_other,321            st_shndx, sectionIndexToCString(st_shndx, section_list),322            strtab_data ? strtab_data->PeekCStr(st_name) : "");323}324 325bool ELFSymbol::Parse(const lldb_private::DataExtractor &data,326                      lldb::offset_t *offset) {327  const unsigned byte_size = data.GetAddressByteSize();328  const bool parsing_32 = byte_size == 4;329 330  // Read st_name.331  if (data.GetU32(offset, &st_name, 1) == nullptr)332    return false;333 334  if (parsing_32) {335    // Read st_value and st_size.336    if (!GetMaxU64(data, offset, &st_value, byte_size, 2))337      return false;338 339    // Read st_info and st_other.340    if (data.GetU8(offset, &st_info, 2) == nullptr)341      return false;342 343    // Read st_shndx.344    if (data.GetU16(offset, &st_shndx, 1) == nullptr)345      return false;346  } else {347    // Read st_info and st_other.348    if (data.GetU8(offset, &st_info, 2) == nullptr)349      return false;350 351    // Read st_shndx.352    if (data.GetU16(offset, &st_shndx, 1) == nullptr)353      return false;354 355    // Read st_value and st_size.356    if (data.GetU64(offset, &st_value, 2) == nullptr)357      return false;358  }359  return true;360}361 362// ELFProgramHeader363 364ELFProgramHeader::ELFProgramHeader() {365  memset(this, 0, sizeof(ELFProgramHeader));366}367 368bool ELFProgramHeader::Parse(const lldb_private::DataExtractor &data,369                             lldb::offset_t *offset) {370  const uint32_t byte_size = data.GetAddressByteSize();371  const bool parsing_32 = byte_size == 4;372 373  // Read p_type;374  if (data.GetU32(offset, &p_type, 1) == nullptr)375    return false;376 377  if (parsing_32) {378    // Read p_offset, p_vaddr, p_paddr, p_filesz and p_memsz.379    if (!GetMaxU64(data, offset, &p_offset, byte_size, 5))380      return false;381 382    // Read p_flags.383    if (data.GetU32(offset, &p_flags, 1) == nullptr)384      return false;385 386    // Read p_align.387    if (!GetMaxU64(data, offset, &p_align, byte_size))388      return false;389  } else {390    // Read p_flags.391    if (data.GetU32(offset, &p_flags, 1) == nullptr)392      return false;393 394    // Read p_offset, p_vaddr, p_paddr, p_filesz, p_memsz and p_align.395    if (!GetMaxU64(data, offset, &p_offset, byte_size, 6))396      return false;397  }398 399  return true;400}401 402// ELFDynamic403 404ELFDynamic::ELFDynamic() { memset(this, 0, sizeof(ELFDynamic)); }405 406bool ELFDynamic::Parse(const lldb_private::DataExtractor &data,407                       lldb::offset_t *offset) {408  const unsigned byte_size = data.GetAddressByteSize();409  return GetMaxS64(data, offset, &d_tag, byte_size, 2);410}411 412// ELFRel413 414ELFRel::ELFRel() { memset(this, 0, sizeof(ELFRel)); }415 416bool ELFRel::Parse(const lldb_private::DataExtractor &data,417                   lldb::offset_t *offset) {418  const unsigned byte_size = data.GetAddressByteSize();419 420  // Read r_offset and r_info.421  return GetMaxU64(data, offset, &r_offset, byte_size, 2) != false;422}423 424// ELFRela425 426ELFRela::ELFRela() { memset(this, 0, sizeof(ELFRela)); }427 428bool ELFRela::Parse(const lldb_private::DataExtractor &data,429                    lldb::offset_t *offset) {430  const unsigned byte_size = data.GetAddressByteSize();431 432  // Read r_offset and r_info.433  if (!GetMaxU64(data, offset, &r_offset, byte_size, 2))434    return false;435 436  // Read r_addend;437  if (!GetMaxS64(data, offset, &r_addend, byte_size))438    return false;439 440  return true;441}442