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