Path: blob/main/contrib/llvm-project/lldb/source/Plugins/ObjectFile/ELF/ELFHeader.cpp
39642 views
//===-- ELFHeader.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 <cstring>910#include "lldb/Core/Section.h"11#include "lldb/Utility/DataExtractor.h"12#include "lldb/Utility/Stream.h"1314#include "ELFHeader.h"1516using namespace elf;17using namespace lldb;18using namespace llvm::ELF;1920// Static utility functions.21//22// GetMaxU64 and GetMaxS64 wrap the similarly named methods from DataExtractor23// with error handling code and provide for parsing a sequence of values.24static bool GetMaxU64(const lldb_private::DataExtractor &data,25lldb::offset_t *offset, uint64_t *value,26uint32_t byte_size) {27const lldb::offset_t saved_offset = *offset;28*value = data.GetMaxU64(offset, byte_size);29return *offset != saved_offset;30}3132static bool GetMaxU64(const lldb_private::DataExtractor &data,33lldb::offset_t *offset, uint64_t *value,34uint32_t byte_size, uint32_t count) {35lldb::offset_t saved_offset = *offset;3637for (uint32_t i = 0; i < count; ++i, ++value) {38if (!GetMaxU64(data, offset, value, byte_size)) {39*offset = saved_offset;40return false;41}42}43return true;44}4546static bool GetMaxS64(const lldb_private::DataExtractor &data,47lldb::offset_t *offset, int64_t *value,48uint32_t byte_size) {49const lldb::offset_t saved_offset = *offset;50*value = data.GetMaxS64(offset, byte_size);51return *offset != saved_offset;52}5354static bool GetMaxS64(const lldb_private::DataExtractor &data,55lldb::offset_t *offset, int64_t *value,56uint32_t byte_size, uint32_t count) {57lldb::offset_t saved_offset = *offset;5859for (uint32_t i = 0; i < count; ++i, ++value) {60if (!GetMaxS64(data, offset, value, byte_size)) {61*offset = saved_offset;62return false;63}64}65return true;66}6768// ELFHeader6970ELFHeader::ELFHeader() { memset(this, 0, sizeof(ELFHeader)); }7172ByteOrder ELFHeader::GetByteOrder() const {73if (e_ident[EI_DATA] == ELFDATA2MSB)74return eByteOrderBig;75if (e_ident[EI_DATA] == ELFDATA2LSB)76return eByteOrderLittle;77return eByteOrderInvalid;78}7980bool ELFHeader::HasHeaderExtension() const {81bool result = false;8283// Check if any of these values looks like sentinel.84result |= e_phnum_hdr == 0xFFFF; // PN_XNUM85result |= e_shnum_hdr == SHN_UNDEF;86result |= e_shstrndx_hdr == SHN_XINDEX;8788// If header extension is present, the section offset cannot be null.89result &= e_shoff != 0;9091// Done.92return result;93}9495void ELFHeader::ParseHeaderExtension(lldb_private::DataExtractor &data) {96// Extract section #0 header.97ELFSectionHeader section_zero;98lldb::offset_t offset = 0;99lldb_private::DataExtractor sh_data(data, e_shoff, e_shentsize);100bool ok = section_zero.Parse(sh_data, &offset);101102// If we succeeded, fix the header.103if (ok) {104if (e_phnum_hdr == 0xFFFF) // PN_XNUM105e_phnum = section_zero.sh_info;106if (e_shnum_hdr == SHN_UNDEF)107e_shnum = section_zero.sh_size;108if (e_shstrndx_hdr == SHN_XINDEX)109e_shstrndx = section_zero.sh_link;110}111}112113bool ELFHeader::Parse(lldb_private::DataExtractor &data,114lldb::offset_t *offset) {115// Read e_ident. This provides byte order and address size info.116if (data.GetU8(offset, &e_ident, EI_NIDENT) == nullptr)117return false;118119const unsigned byte_size = Is32Bit() ? 4 : 8;120data.SetByteOrder(GetByteOrder());121data.SetAddressByteSize(byte_size);122123// Read e_type and e_machine.124if (data.GetU16(offset, &e_type, 2) == nullptr)125return false;126127// Read e_version.128if (data.GetU32(offset, &e_version, 1) == nullptr)129return false;130131// Read e_entry, e_phoff and e_shoff.132if (!GetMaxU64(data, offset, &e_entry, byte_size, 3))133return false;134135// Read e_flags.136if (data.GetU32(offset, &e_flags, 1) == nullptr)137return false;138139// Read e_ehsize, e_phentsize, e_phnum, e_shentsize, e_shnum and e_shstrndx.140if (data.GetU16(offset, &e_ehsize, 6) == nullptr)141return false;142143// Initialize e_phnum, e_shnum, and e_shstrndx with the values read from the144// header.145e_phnum = e_phnum_hdr;146e_shnum = e_shnum_hdr;147e_shstrndx = e_shstrndx_hdr;148149// See if we have extended header in section #0.150if (HasHeaderExtension())151ParseHeaderExtension(data);152153return true;154}155156bool ELFHeader::MagicBytesMatch(const uint8_t *magic) {157return memcmp(magic, ElfMagic, strlen(ElfMagic)) == 0;158}159160unsigned ELFHeader::AddressSizeInBytes(const uint8_t *magic) {161unsigned address_size = 0;162163switch (magic[EI_CLASS]) {164case ELFCLASS32:165address_size = 4;166break;167168case ELFCLASS64:169address_size = 8;170break;171}172return address_size;173}174175unsigned ELFHeader::GetRelocationJumpSlotType() const {176unsigned slot = 0;177178switch (e_machine) {179default:180assert(false && "architecture not supported");181break;182case EM_PPC:183slot = R_PPC_JMP_SLOT;184break;185case EM_PPC64:186slot = R_PPC64_JMP_SLOT;187break;188case EM_386:189case EM_IAMCU: // FIXME: is this correct?190slot = R_386_JUMP_SLOT;191break;192case EM_X86_64:193slot = R_X86_64_JUMP_SLOT;194break;195case EM_ARM:196slot = R_ARM_JUMP_SLOT;197break;198case EM_HEXAGON:199slot = R_HEX_JMP_SLOT;200break;201case EM_AARCH64:202slot = R_AARCH64_JUMP_SLOT;203break;204case EM_MIPS:205slot = R_MIPS_JUMP_SLOT;206break;207case EM_S390:208slot = R_390_JMP_SLOT;209break;210case EM_RISCV:211slot = R_RISCV_JUMP_SLOT;212break;213case EM_LOONGARCH:214slot = R_LARCH_JUMP_SLOT;215break;216}217218return slot;219}220221// ELFSectionHeader222223ELFSectionHeader::ELFSectionHeader() {224memset(this, 0, sizeof(ELFSectionHeader));225}226227bool ELFSectionHeader::Parse(const lldb_private::DataExtractor &data,228lldb::offset_t *offset) {229const unsigned byte_size = data.GetAddressByteSize();230231// Read sh_name and sh_type.232if (data.GetU32(offset, &sh_name, 2) == nullptr)233return false;234235// Read sh_flags.236if (!GetMaxU64(data, offset, &sh_flags, byte_size))237return false;238239// Read sh_addr, sh_off and sh_size.240if (!GetMaxU64(data, offset, &sh_addr, byte_size, 3))241return false;242243// Read sh_link and sh_info.244if (data.GetU32(offset, &sh_link, 2) == nullptr)245return false;246247// Read sh_addralign and sh_entsize.248if (!GetMaxU64(data, offset, &sh_addralign, byte_size, 2))249return false;250251return true;252}253254// ELFSymbol255256ELFSymbol::ELFSymbol() { memset(this, 0, sizeof(ELFSymbol)); }257258#define ENUM_TO_CSTR(e) \259case e: \260return #e261262const char *ELFSymbol::bindingToCString(unsigned char binding) {263switch (binding) {264ENUM_TO_CSTR(STB_LOCAL);265ENUM_TO_CSTR(STB_GLOBAL);266ENUM_TO_CSTR(STB_WEAK);267ENUM_TO_CSTR(STB_LOOS);268ENUM_TO_CSTR(STB_HIOS);269ENUM_TO_CSTR(STB_LOPROC);270ENUM_TO_CSTR(STB_HIPROC);271}272return "";273}274275const char *ELFSymbol::typeToCString(unsigned char type) {276switch (type) {277ENUM_TO_CSTR(STT_NOTYPE);278ENUM_TO_CSTR(STT_OBJECT);279ENUM_TO_CSTR(STT_FUNC);280ENUM_TO_CSTR(STT_SECTION);281ENUM_TO_CSTR(STT_FILE);282ENUM_TO_CSTR(STT_COMMON);283ENUM_TO_CSTR(STT_TLS);284ENUM_TO_CSTR(STT_GNU_IFUNC);285ENUM_TO_CSTR(STT_HIOS);286ENUM_TO_CSTR(STT_LOPROC);287ENUM_TO_CSTR(STT_HIPROC);288}289return "";290}291292const char *ELFSymbol::sectionIndexToCString(293elf_half shndx, const lldb_private::SectionList *section_list) {294switch (shndx) {295ENUM_TO_CSTR(SHN_UNDEF);296ENUM_TO_CSTR(SHN_LOPROC);297ENUM_TO_CSTR(SHN_HIPROC);298ENUM_TO_CSTR(SHN_LOOS);299ENUM_TO_CSTR(SHN_HIOS);300ENUM_TO_CSTR(SHN_ABS);301ENUM_TO_CSTR(SHN_COMMON);302ENUM_TO_CSTR(SHN_XINDEX);303default: {304const lldb_private::Section *section =305section_list->GetSectionAtIndex(shndx).get();306if (section)307return section->GetName().AsCString("");308} break;309}310return "";311}312313void ELFSymbol::Dump(lldb_private::Stream *s, uint32_t idx,314const lldb_private::DataExtractor *strtab_data,315const lldb_private::SectionList *section_list) {316s->Printf("[%3u] 0x%16.16" PRIx64 " 0x%16.16" PRIx64317" 0x%8.8x 0x%2.2x (%-10s %-13s) 0x%2.2x 0x%4.4x (%-10s) %s\n",318idx, st_value, st_size, st_name, st_info,319bindingToCString(getBinding()), typeToCString(getType()), st_other,320st_shndx, sectionIndexToCString(st_shndx, section_list),321strtab_data ? strtab_data->PeekCStr(st_name) : "");322}323324bool ELFSymbol::Parse(const lldb_private::DataExtractor &data,325lldb::offset_t *offset) {326const unsigned byte_size = data.GetAddressByteSize();327const bool parsing_32 = byte_size == 4;328329// Read st_name.330if (data.GetU32(offset, &st_name, 1) == nullptr)331return false;332333if (parsing_32) {334// Read st_value and st_size.335if (!GetMaxU64(data, offset, &st_value, byte_size, 2))336return false;337338// Read st_info and st_other.339if (data.GetU8(offset, &st_info, 2) == nullptr)340return false;341342// Read st_shndx.343if (data.GetU16(offset, &st_shndx, 1) == nullptr)344return false;345} else {346// Read st_info and st_other.347if (data.GetU8(offset, &st_info, 2) == nullptr)348return false;349350// Read st_shndx.351if (data.GetU16(offset, &st_shndx, 1) == nullptr)352return false;353354// Read st_value and st_size.355if (data.GetU64(offset, &st_value, 2) == nullptr)356return false;357}358return true;359}360361// ELFProgramHeader362363ELFProgramHeader::ELFProgramHeader() {364memset(this, 0, sizeof(ELFProgramHeader));365}366367bool ELFProgramHeader::Parse(const lldb_private::DataExtractor &data,368lldb::offset_t *offset) {369const uint32_t byte_size = data.GetAddressByteSize();370const bool parsing_32 = byte_size == 4;371372// Read p_type;373if (data.GetU32(offset, &p_type, 1) == nullptr)374return false;375376if (parsing_32) {377// Read p_offset, p_vaddr, p_paddr, p_filesz and p_memsz.378if (!GetMaxU64(data, offset, &p_offset, byte_size, 5))379return false;380381// Read p_flags.382if (data.GetU32(offset, &p_flags, 1) == nullptr)383return false;384385// Read p_align.386if (!GetMaxU64(data, offset, &p_align, byte_size))387return false;388} else {389// Read p_flags.390if (data.GetU32(offset, &p_flags, 1) == nullptr)391return false;392393// Read p_offset, p_vaddr, p_paddr, p_filesz, p_memsz and p_align.394if (!GetMaxU64(data, offset, &p_offset, byte_size, 6))395return false;396}397398return true;399}400401// ELFDynamic402403ELFDynamic::ELFDynamic() { memset(this, 0, sizeof(ELFDynamic)); }404405bool ELFDynamic::Parse(const lldb_private::DataExtractor &data,406lldb::offset_t *offset) {407const unsigned byte_size = data.GetAddressByteSize();408return GetMaxS64(data, offset, &d_tag, byte_size, 2);409}410411// ELFRel412413ELFRel::ELFRel() { memset(this, 0, sizeof(ELFRel)); }414415bool ELFRel::Parse(const lldb_private::DataExtractor &data,416lldb::offset_t *offset) {417const unsigned byte_size = data.GetAddressByteSize();418419// Read r_offset and r_info.420return GetMaxU64(data, offset, &r_offset, byte_size, 2) != false;421}422423// ELFRela424425ELFRela::ELFRela() { memset(this, 0, sizeof(ELFRela)); }426427bool ELFRela::Parse(const lldb_private::DataExtractor &data,428lldb::offset_t *offset) {429const unsigned byte_size = data.GetAddressByteSize();430431// Read r_offset and r_info.432if (!GetMaxU64(data, offset, &r_offset, byte_size, 2))433return false;434435// Read r_addend;436if (!GetMaxS64(data, offset, &r_addend, byte_size))437return false;438439return true;440}441442443