diff --git a/tools/elfutils/patches/010-backport-mips-support-reloc.patch b/tools/elfutils/patches/010-backport-mips-support-reloc.patch index 8a65e4e464..e9ef3997d2 100644 --- a/tools/elfutils/patches/010-backport-mips-support-reloc.patch +++ b/tools/elfutils/patches/010-backport-mips-support-reloc.patch @@ -1,7 +1,7 @@ -From 8d3bb7db9d6f07decfc59d83988cda54e5a8b0cd Mon Sep 17 00:00:00 2001 +From e259f126f5077923e415e306915de50ed0f0db56 Mon Sep 17 00:00:00 2001 From: Ying Huang Date: Tue, 5 Mar 2024 17:51:17 +0800 -Subject: [PATCH 1/7] Support Mips architecture +Subject: [PATCH] Support Mips architecture * backends/Makefile.am (modules): Add mips. (mips_SRCS): New var for mips_init.c mips_symbol.c. @@ -37,13 +37,11 @@ Signed-off-by: Ying Huang i386_SRCS = i386_init.c i386_symbol.c i386_corenote.c i386_cfi.c \ i386_retval.c i386_regs.c i386_auxv.c \ -@@ -102,12 +102,16 @@ loongarch_SRCS = loongarch_init.c loonga +@@ -102,12 +102,14 @@ loongarch_SRCS = loongarch_init.c loonga arc_SRCS = arc_init.c arc_symbol.c -+mips_SRCS = mips_init.c mips_symbol.c mips_attrs.c mips_initreg.c \ -+ mips_cfi.c mips_unwind.c mips_regs.c mips_retval.c \ -+ mips_corenote.c mips64_corenote.c ++mips_SRCS = mips_init.c mips_symbol.c + libebl_backends_a_SOURCES = $(i386_SRCS) $(sh_SRCS) $(x86_64_SRCS) \ $(ia64_SRCS) $(alpha_SRCS) $(arm_SRCS) \ @@ -57,7 +55,7 @@ Signed-off-by: Ying Huang am_libebl_backends_pic_a_OBJECTS = $(libebl_backends_a_SOURCES:.c=.os) --- /dev/null +++ b/backends/mips_init.c -@@ -0,0 +1,74 @@ +@@ -0,0 +1,52 @@ +/* Initialization of MIPS specific backend library. + Copyright (C) 2024 CIP United Inc. + This file is part of elfutils. @@ -100,8 +98,6 @@ Signed-off-by: Ying Huang +/* This defines the common reloc hooks based on mips_reloc.def. */ +#include "common-reloc.c" + -+extern __typeof (EBLHOOK (core_note)) mips64_core_note attribute_hidden; -+ +Ebl * +mips_init (Elf *elf __attribute__ ((unused)), + GElf_Half machine __attribute__ ((unused)), @@ -110,26 +106,6 @@ Signed-off-by: Ying Huang + /* We handle it. */ + mips_init_reloc (eh); + HOOK (eh, reloc_simple_type); -+ HOOK (eh, section_type_name); -+ HOOK (eh, machine_flag_check); -+ HOOK (eh, machine_flag_name); -+ HOOK (eh, machine_section_flag_check); -+ HOOK (eh, segment_type_name); -+ HOOK (eh, dynamic_tag_check); -+ HOOK (eh, dynamic_tag_name); -+ HOOK (eh, check_object_attribute); -+ HOOK (eh, check_special_symbol); -+ HOOK (eh, check_reloc_target_type); -+ HOOK (eh, set_initial_registers_tid); -+ HOOK (eh, abi_cfi); -+ HOOK (eh, unwind); -+ HOOK (eh, register_info); -+ HOOK (eh, return_value_location); -+ if (eh->class == ELFCLASS64) -+ eh->core_note = mips64_core_note; -+ else -+ HOOK (eh, core_note); -+ eh->frame_nregs = 71; + return eh; +} --- /dev/null @@ -230,7 +206,7 @@ Signed-off-by: Ying Huang +RELOC_TYPE (GNU_VTENTRY, REL) --- /dev/null +++ b/backends/mips_symbol.c -@@ -0,0 +1,671 @@ +@@ -0,0 +1,63 @@ +/* MIPS specific symbolic name handling. + Copyright (C) 2024 CIP United Inc. + This file is part of elfutils. @@ -294,614 +270,6 @@ Signed-off-by: Ying Huang + return ELF_T_NUM; + } +} -+ -+/* copy binutils-2.34/binutils/readelf.c get_mips_section_type_name */ -+const char * -+mips_section_type_name (int type, -+ char *buf __attribute__ ((unused)), -+ size_t len __attribute__ ((unused))) -+{ -+ switch (type) -+ { -+ case SHT_MIPS_LIBLIST: -+ return "MIPS_LIBLIST"; -+ case SHT_MIPS_MSYM: -+ return "MIPS_MSYM"; -+ case SHT_MIPS_CONFLICT: -+ return "MIPS_CONFLICT"; -+ case SHT_MIPS_GPTAB: -+ return "MIPS_GPTAB"; -+ case SHT_MIPS_UCODE: -+ return "MIPS_UCODE"; -+ case SHT_MIPS_DEBUG: -+ return "MIPS_DEBUG"; -+ case SHT_MIPS_REGINFO: -+ return "MIPS_REGINFO"; -+ case SHT_MIPS_PACKAGE: -+ return "MIPS_PACKAGE"; -+ case SHT_MIPS_PACKSYM: -+ return "MIPS_PACKSYM"; -+ case SHT_MIPS_RELD: -+ return "MIPS_RELD"; -+ case SHT_MIPS_IFACE: -+ return "MIPS_IFACE"; -+ case SHT_MIPS_CONTENT: -+ return "MIPS_CONTENT"; -+ case SHT_MIPS_OPTIONS: -+ return "MIPS_OPTIONS"; -+ case SHT_MIPS_SHDR: -+ return "MIPS_SHDR"; -+ case SHT_MIPS_FDESC: -+ return "MIPS_FDESC"; -+ case SHT_MIPS_EXTSYM: -+ return "MIPS_EXTSYM"; -+ case SHT_MIPS_DENSE: -+ return "MIPS_DENSE"; -+ case SHT_MIPS_PDESC: -+ return "MIPS_PDESC"; -+ case SHT_MIPS_LOCSYM: -+ return "MIPS_LOCSYM"; -+ case SHT_MIPS_AUXSYM: -+ return "MIPS_AUXSYM"; -+ case SHT_MIPS_OPTSYM: -+ return "MIPS_OPTSYM"; -+ case SHT_MIPS_LOCSTR: -+ return "MIPS_LOCSTR"; -+ case SHT_MIPS_LINE: -+ return "MIPS_LINE"; -+ case SHT_MIPS_RFDESC: -+ return "MIPS_RFDESC"; -+ case SHT_MIPS_DELTASYM: -+ return "MIPS_DELTASYM"; -+ case SHT_MIPS_DELTAINST: -+ return "MIPS_DELTAINST"; -+ case SHT_MIPS_DELTACLASS: -+ return "MIPS_DELTACLASS"; -+ case SHT_MIPS_DWARF: -+ return "MIPS_DWARF"; -+ case SHT_MIPS_DELTADECL: -+ return "MIPS_DELTADECL"; -+ case SHT_MIPS_SYMBOL_LIB: -+ return "MIPS_SYMBOL_LIB"; -+ case SHT_MIPS_EVENTS: -+ return "MIPS_EVENTS"; -+ case SHT_MIPS_TRANSLATE: -+ return "MIPS_TRANSLATE"; -+ case SHT_MIPS_PIXIE: -+ return "MIPS_PIXIE"; -+ case SHT_MIPS_XLATE: -+ return "MIPS_XLATE"; -+ case SHT_MIPS_XLATE_DEBUG: -+ return "MIPS_XLATE_DEBUG"; -+ case SHT_MIPS_WHIRL: -+ return "MIPS_WHIRL"; -+ case SHT_MIPS_EH_REGION: -+ return "MIPS_EH_REGION"; -+ case SHT_MIPS_XLATE_OLD: -+ return "MIPS_XLATE_OLD"; -+ case SHT_MIPS_PDR_EXCEPTION: -+ return "MIPS_PDR_EXCEPTION"; -+ case SHT_MIPS_ABIFLAGS: -+ return "MIPS_ABIFLAGS"; -+ case SHT_MIPS_XHASH: -+ return "MIPS_XHASH"; -+ default: -+ break; -+ } -+ return NULL; -+} -+ -+bool -+mips_check_reloc_target_type (Ebl *ebl __attribute__ ((unused)), Elf64_Word sh_type) -+{ -+ return (sh_type == SHT_MIPS_DWARF); -+} -+ -+/* Check whether given symbol's st_value and st_size are OK despite failing -+ normal checks. */ -+bool -+mips_check_special_symbol (Elf *elf, -+ const GElf_Sym *sym __attribute__ ((unused)), -+ const char *name __attribute__ ((unused)), -+ const GElf_Shdr *destshdr) -+{ -+ size_t shstrndx; -+ if (elf_getshdrstrndx (elf, &shstrndx) != 0) -+ return false; -+ const char *sname = elf_strptr (elf, shstrndx, destshdr->sh_name); -+ if (sname == NULL) -+ return false; -+ return (strcmp (sname, ".got") == 0 || strcmp (sname, ".bss") == 0); -+} -+ -+/* Check whether SHF_MASKPROC flags are valid. */ -+bool -+mips_machine_section_flag_check (GElf_Xword sh_flags) -+{ -+ return ((sh_flags &~ (SHF_MIPS_GPREL | -+ SHF_MIPS_MERGE | -+ SHF_MIPS_ADDR | -+ SHF_MIPS_STRINGS | -+ SHF_MIPS_NOSTRIP | -+ SHF_MIPS_LOCAL | -+ SHF_MIPS_NAMES | -+ SHF_MIPS_NODUPE)) == 0); -+} -+ -+/* Check whether machine flags are valid. */ -+bool -+mips_machine_flag_check (GElf_Word flags) -+{ -+ if ((flags &~ (EF_MIPS_NOREORDER | -+ EF_MIPS_PIC | -+ EF_MIPS_CPIC | -+ EF_MIPS_UCODE | -+ EF_MIPS_ABI2 | -+ EF_MIPS_OPTIONS_FIRST | -+ EF_MIPS_32BITMODE | -+ EF_MIPS_NAN2008 | -+ EF_MIPS_FP64 | -+ EF_MIPS_ARCH_ASE_MDMX | -+ EF_MIPS_ARCH_ASE_M16 | -+ EF_MIPS_ARCH_ASE_MICROMIPS)) == 0) -+ return false; -+ -+ switch(flags & EF_MIPS_MACH) -+ { -+ case EF_MIPS_MACH_3900: -+ case EF_MIPS_MACH_4010: -+ case EF_MIPS_MACH_4100: -+ case EF_MIPS_MACH_4111: -+ case EF_MIPS_MACH_4120: -+ case EF_MIPS_MACH_4650: -+ case EF_MIPS_MACH_5400: -+ case EF_MIPS_MACH_5500: -+ case EF_MIPS_MACH_5900: -+ case EF_MIPS_MACH_SB1: -+ case EF_MIPS_MACH_9000: -+ case EF_MIPS_MACH_LS2E: -+ case EF_MIPS_MACH_LS2F: -+ case EF_MIPS_MACH_GS464: -+ case EF_MIPS_MACH_GS464E: -+ case EF_MIPS_MACH_GS264E: -+ case EF_MIPS_MACH_OCTEON: -+ case EF_MIPS_MACH_OCTEON2: -+ case EF_MIPS_MACH_OCTEON3: -+ case EF_MIPS_MACH_XLR: -+ case EF_MIPS_MACH_IAMR2: -+ case 0: -+ break; -+ default: -+ return false; -+ } -+ -+ switch ((flags & EF_MIPS_ABI)) -+ { -+ case EF_MIPS_ABI_O32: -+ case EF_MIPS_ABI_O64: -+ case EF_MIPS_ABI_EABI32: -+ case EF_MIPS_ABI_EABI64: -+ case 0: -+ break; -+ default: -+ return false; -+ } -+ -+ switch ((flags & EF_MIPS_ARCH)) -+ { -+ case EF_MIPS_ARCH_1: -+ case EF_MIPS_ARCH_2: -+ case EF_MIPS_ARCH_3: -+ case EF_MIPS_ARCH_4: -+ case EF_MIPS_ARCH_5: -+ case EF_MIPS_ARCH_32: -+ case EF_MIPS_ARCH_32R2: -+ case EF_MIPS_ARCH_32R6: -+ case EF_MIPS_ARCH_64: -+ case EF_MIPS_ARCH_64R2: -+ case EF_MIPS_ARCH_64R6: -+ return true; -+ default: -+ return false; -+ } -+ return false; -+} -+ -+/* copy binutils-2.34/binutils/readelf.c get_machine_flags */ -+const char * -+mips_machine_flag_name (Elf64_Word orig __attribute__ ((unused)), Elf64_Word *flagref) -+{ -+ if (*flagref & EF_MIPS_NOREORDER) -+ { -+ *flagref &= ~((Elf64_Word) EF_MIPS_NOREORDER); -+ return "noreorder"; -+ } -+ -+ if (*flagref & EF_MIPS_PIC) -+ { -+ *flagref &= ~((Elf64_Word) EF_MIPS_PIC); -+ return "pic"; -+ } -+ -+ if (*flagref & EF_MIPS_CPIC) -+ { -+ *flagref &= ~((Elf64_Word) EF_MIPS_CPIC); -+ return "cpic"; -+ } -+ -+ if (*flagref & EF_MIPS_UCODE) -+ { -+ *flagref &= ~((Elf64_Word) EF_MIPS_UCODE); -+ return "ugen_reserved"; -+ } -+ -+ if (*flagref & EF_MIPS_ABI2) -+ { -+ *flagref &= ~((Elf64_Word) EF_MIPS_ABI2); -+ return "abi2"; -+ } -+ -+ if (*flagref & EF_MIPS_OPTIONS_FIRST) -+ { -+ *flagref &= ~((Elf64_Word) EF_MIPS_OPTIONS_FIRST); -+ return "odk first"; -+ } -+ -+ if (*flagref & EF_MIPS_32BITMODE) -+ { -+ *flagref &= ~((Elf64_Word) EF_MIPS_32BITMODE); -+ return "32bitmode"; -+ } -+ -+ if (*flagref & EF_MIPS_NAN2008) -+ { -+ *flagref &= ~((Elf64_Word) EF_MIPS_NAN2008); -+ return "nan2008"; -+ } -+ -+ if (*flagref & EF_MIPS_FP64) -+ { -+ *flagref &= ~((Elf64_Word) EF_MIPS_FP64); -+ return "fp64"; -+ } -+ -+ switch (*flagref & EF_MIPS_MACH) -+ { -+ case EF_MIPS_MACH_3900: -+ *flagref &= ~((Elf64_Word) EF_MIPS_MACH_3900); -+ return "3900"; -+ case EF_MIPS_MACH_4010: -+ *flagref &= ~((Elf64_Word) EF_MIPS_MACH_4010); -+ return "4010"; -+ case EF_MIPS_MACH_4100: -+ *flagref &= ~((Elf64_Word) EF_MIPS_MACH_4100); -+ return "4100"; -+ case EF_MIPS_MACH_4111: -+ *flagref &= ~((Elf64_Word) EF_MIPS_MACH_4111); -+ return "4111"; -+ case EF_MIPS_MACH_4120: -+ *flagref &= ~((Elf64_Word) EF_MIPS_MACH_4120); -+ return "4120"; -+ case EF_MIPS_MACH_4650: -+ *flagref &= ~((Elf64_Word) EF_MIPS_MACH_4650); -+ return "4650"; -+ case EF_MIPS_MACH_5400: -+ *flagref &= ~((Elf64_Word) EF_MIPS_MACH_5400); -+ return "5400"; -+ case EF_MIPS_MACH_5500: -+ *flagref &= ~((Elf64_Word) EF_MIPS_MACH_5500); -+ return "5500"; -+ case EF_MIPS_MACH_5900: -+ *flagref &= ~((Elf64_Word) EF_MIPS_MACH_5900); -+ return "5900"; -+ case EF_MIPS_MACH_SB1: -+ *flagref &= ~((Elf64_Word) EF_MIPS_MACH_SB1); -+ return "sb1"; -+ case EF_MIPS_MACH_9000: -+ *flagref &= ~((Elf64_Word) EF_MIPS_MACH_9000); -+ return "9000"; -+ case EF_MIPS_MACH_LS2E: -+ *flagref &= ~((Elf64_Word) EF_MIPS_MACH_LS2E); -+ return "loongson-2e"; -+ case EF_MIPS_MACH_LS2F: -+ *flagref &= ~((Elf64_Word) EF_MIPS_MACH_LS2F); -+ return "loongson-2f"; -+ case EF_MIPS_MACH_GS464: -+ *flagref &= ~((Elf64_Word) EF_MIPS_MACH_GS464); -+ return "gs464"; -+ case EF_MIPS_MACH_GS464E: -+ *flagref &= ~((Elf64_Word) EF_MIPS_MACH_GS464E); -+ return "gs464e"; -+ case EF_MIPS_MACH_GS264E: -+ *flagref &= ~((Elf64_Word) EF_MIPS_MACH_GS264E); -+ return "gs264e"; -+ case EF_MIPS_MACH_OCTEON: -+ *flagref &= ~((Elf64_Word) EF_MIPS_MACH_OCTEON); -+ return "octeon"; -+ case EF_MIPS_MACH_OCTEON2: -+ *flagref &= ~((Elf64_Word) EF_MIPS_MACH_OCTEON2); -+ return "octeon2"; -+ case EF_MIPS_MACH_OCTEON3: -+ *flagref &= ~((Elf64_Word) EF_MIPS_MACH_OCTEON3); -+ return "octeon3"; -+ case EF_MIPS_MACH_XLR: -+ *flagref &= ~((Elf64_Word) EF_MIPS_MACH_XLR); -+ return "xlr"; -+ case EF_MIPS_MACH_IAMR2: -+ *flagref &= ~((Elf64_Word) EF_MIPS_MACH_IAMR2); -+ return "interaptiv-mr2"; -+ case 0: -+ /* We simply ignore the field in this case to avoid confusion: -+ MIPS ELF does not specify EF_MIPS_MACH, it is a GNU -+ extension. */ -+ break; -+ default: -+ *flagref &= ~((Elf64_Word) EF_MIPS_MACH); -+ return "unknown CPU"; -+ } -+ switch (*flagref & EF_MIPS_ABI) -+ { -+ case EF_MIPS_ABI_O32: -+ *flagref &= ~((Elf64_Word) EF_MIPS_ABI_O32); -+ return "o32"; -+ case EF_MIPS_ABI_O64: -+ *flagref &= ~((Elf64_Word) EF_MIPS_ABI_O64); -+ return "o64"; -+ case EF_MIPS_ABI_EABI32: -+ *flagref &= ~((Elf64_Word) EF_MIPS_ABI_EABI32); -+ return "eabi32"; -+ case EF_MIPS_ABI_EABI64: -+ *flagref &= ~((Elf64_Word) EF_MIPS_ABI_EABI64); -+ return "eabi64"; -+ case 0: -+ /* We simply ignore the field in this case to avoid confusion: -+ MIPS ELF does not specify EF_MIPS_ABI, it is a GNU extension. -+ This means it is likely to be an o32 file, but not for -+ sure. */ -+ break; -+ default: -+ *flagref &= ~((Elf64_Word) EF_MIPS_ABI); -+ return "unknown ABI"; -+ } -+ -+ if (*flagref & EF_MIPS_ARCH_ASE_MDMX) -+ { -+ *flagref &= ~((Elf64_Word) EF_MIPS_ARCH_ASE_MDMX); -+ return "mdmx"; -+ } -+ -+ if (*flagref & EF_MIPS_ARCH_ASE_M16) -+ { -+ *flagref &= ~((Elf64_Word) EF_MIPS_ARCH_ASE_M16); -+ return "mips16"; -+ } -+ -+ if (*flagref & EF_MIPS_ARCH_ASE_MICROMIPS) -+ { -+ *flagref &= ~((Elf64_Word) EF_MIPS_ARCH_ASE_MICROMIPS); -+ return "micromips"; -+ } -+ -+ switch (*flagref & EF_MIPS_ARCH) -+ { -+ case EF_MIPS_ARCH_1: -+ *flagref &= ~((Elf64_Word) EF_MIPS_ARCH_1); -+ return "mips1"; -+ case EF_MIPS_ARCH_2: -+ *flagref &= ~((Elf64_Word) EF_MIPS_ARCH_2); -+ return "mips2"; -+ case EF_MIPS_ARCH_3: -+ *flagref &= ~((Elf64_Word) EF_MIPS_ARCH_3); -+ return "mips3"; -+ case EF_MIPS_ARCH_4: -+ *flagref &= ~((Elf64_Word) EF_MIPS_ARCH_4); -+ return "mips4"; -+ case EF_MIPS_ARCH_5: -+ *flagref &= ~((Elf64_Word) EF_MIPS_ARCH_5); -+ return "mips5"; -+ case EF_MIPS_ARCH_32: -+ *flagref &= ~((Elf64_Word) EF_MIPS_ARCH_32); -+ return "mips32"; -+ case EF_MIPS_ARCH_32R2: -+ *flagref &= ~((Elf64_Word) EF_MIPS_ARCH_32R2); -+ return "mips32r2"; -+ case EF_MIPS_ARCH_32R6: -+ *flagref &= ~((Elf64_Word) EF_MIPS_ARCH_32R6); -+ return "mips32r6"; -+ case EF_MIPS_ARCH_64: -+ *flagref &= ~((Elf64_Word) EF_MIPS_ARCH_64); -+ return "mips64"; -+ case EF_MIPS_ARCH_64R2: -+ *flagref &= ~((Elf64_Word) EF_MIPS_ARCH_64R2); -+ return "mips64r2"; -+ case EF_MIPS_ARCH_64R6: -+ *flagref &= ~((Elf64_Word) EF_MIPS_ARCH_64R6); -+ return "mips64r6"; -+ default: -+ *flagref &= ~((Elf64_Word) EF_MIPS_ARCH); -+ return "unknown ISA"; -+ } -+ return NULL; -+} -+ -+/* copy binutils-2.34/binutils/readelf.c get_mips_segment_type */ -+const char * -+mips_segment_type_name (int segment, char *buf __attribute__ ((unused)), -+ size_t len __attribute__ ((unused))) -+{ -+ switch (segment) -+ { -+ case PT_MIPS_REGINFO: -+ return "REGINFO"; -+ case PT_MIPS_RTPROC: -+ return "RTPROC"; -+ case PT_MIPS_OPTIONS: -+ return "OPTIONS"; -+ case PT_MIPS_ABIFLAGS: -+ return "ABIFLAGS"; -+ default: -+ return NULL; -+ } -+} -+ -+bool -+mips_dynamic_tag_check (int64_t tag) -+{ -+ return ((tag &~ (DT_MIPS_RLD_VERSION -+ | DT_MIPS_TIME_STAMP -+ | DT_MIPS_ICHECKSUM -+ | DT_MIPS_IVERSION -+ | DT_MIPS_FLAGS -+ | DT_MIPS_BASE_ADDRESS -+ | DT_MIPS_MSYM -+ | DT_MIPS_CONFLICT -+ | DT_MIPS_LIBLIST -+ | DT_MIPS_LOCAL_GOTNO -+ | DT_MIPS_CONFLICTNO -+ | DT_MIPS_LIBLISTNO -+ | DT_MIPS_SYMTABNO -+ | DT_MIPS_UNREFEXTNO -+ | DT_MIPS_GOTSYM -+ | DT_MIPS_HIPAGENO -+ | DT_MIPS_RLD_MAP -+ | DT_MIPS_DELTA_CLASS -+ | DT_MIPS_DELTA_CLASS_NO -+ | DT_MIPS_DELTA_INSTANCE -+ | DT_MIPS_DELTA_INSTANCE_NO -+ | DT_MIPS_DELTA_RELOC -+ | DT_MIPS_DELTA_RELOC_NO -+ | DT_MIPS_DELTA_SYM -+ | DT_MIPS_DELTA_SYM_NO -+ | DT_MIPS_DELTA_CLASSSYM -+ | DT_MIPS_DELTA_CLASSSYM_NO -+ | DT_MIPS_CXX_FLAGS -+ | DT_MIPS_PIXIE_INIT -+ | DT_MIPS_SYMBOL_LIB -+ | DT_MIPS_LOCALPAGE_GOTIDX -+ | DT_MIPS_LOCAL_GOTIDX -+ | DT_MIPS_HIDDEN_GOTIDX -+ | DT_MIPS_PROTECTED_GOTIDX -+ | DT_MIPS_OPTIONS -+ | DT_MIPS_INTERFACE -+ | DT_MIPS_DYNSTR_ALIGN -+ | DT_MIPS_INTERFACE_SIZE -+ | DT_MIPS_RLD_TEXT_RESOLVE_ADDR -+ | DT_MIPS_PERF_SUFFIX -+ | DT_MIPS_COMPACT_SIZE -+ | DT_MIPS_GP_VALUE -+ | DT_MIPS_AUX_DYNAMIC -+ | DT_MIPS_PLTGOT -+ | DT_MIPS_RWPLT -+ | DT_MIPS_RLD_MAP_REL -+ | DT_MIPS_XHASH)) == 0); -+} -+ -+/* copy binutils-2.34/binutils/readelf.c get_mips_dynamic_type*/ -+const char * -+mips_dynamic_tag_name (int64_t tag, char *buf __attribute__ ((unused)), -+ size_t len __attribute__ ((unused))) -+{ -+ switch (tag) -+ { -+ case DT_MIPS_RLD_VERSION: -+ return "MIPS_RLD_VERSION"; -+ case DT_MIPS_TIME_STAMP: -+ return "MIPS_TIME_STAMP"; -+ case DT_MIPS_ICHECKSUM: -+ return "MIPS_ICHECKSUM"; -+ case DT_MIPS_IVERSION: -+ return "MIPS_IVERSION"; -+ case DT_MIPS_FLAGS: -+ return "MIPS_FLAGS"; -+ case DT_MIPS_BASE_ADDRESS: -+ return "MIPS_BASE_ADDRESS"; -+ case DT_MIPS_MSYM: -+ return "MIPS_MSYM"; -+ case DT_MIPS_CONFLICT: -+ return "MIPS_CONFLICT"; -+ case DT_MIPS_LIBLIST: -+ return "MIPS_LIBLIST"; -+ case DT_MIPS_LOCAL_GOTNO: -+ return "MIPS_LOCAL_GOTNO"; -+ case DT_MIPS_CONFLICTNO: -+ return "MIPS_CONFLICTNO"; -+ case DT_MIPS_LIBLISTNO: -+ return "MIPS_LIBLISTNO"; -+ case DT_MIPS_SYMTABNO: -+ return "MIPS_SYMTABNO"; -+ case DT_MIPS_UNREFEXTNO: -+ return "MIPS_UNREFEXTNO"; -+ case DT_MIPS_GOTSYM: -+ return "MIPS_GOTSYM"; -+ case DT_MIPS_HIPAGENO: -+ return "MIPS_HIPAGENO"; -+ case DT_MIPS_RLD_MAP: -+ return "MIPS_RLD_MAP"; -+ case DT_MIPS_RLD_MAP_REL: -+ return "MIPS_RLD_MAP_REL"; -+ case DT_MIPS_DELTA_CLASS: -+ return "MIPS_DELTA_CLASS"; -+ case DT_MIPS_DELTA_CLASS_NO: -+ return "MIPS_DELTA_CLASS_NO"; -+ case DT_MIPS_DELTA_INSTANCE: -+ return "MIPS_DELTA_INSTANCE"; -+ case DT_MIPS_DELTA_INSTANCE_NO: -+ return "MIPS_DELTA_INSTANCE_NO"; -+ case DT_MIPS_DELTA_RELOC: -+ return "MIPS_DELTA_RELOC"; -+ case DT_MIPS_DELTA_RELOC_NO: -+ return "MIPS_DELTA_RELOC_NO"; -+ case DT_MIPS_DELTA_SYM: -+ return "MIPS_DELTA_SYM"; -+ case DT_MIPS_DELTA_SYM_NO: -+ return "MIPS_DELTA_SYM_NO"; -+ case DT_MIPS_DELTA_CLASSSYM: -+ return "MIPS_DELTA_CLASSSYM"; -+ case DT_MIPS_DELTA_CLASSSYM_NO: -+ return "MIPS_DELTA_CLASSSYM_NO"; -+ case DT_MIPS_CXX_FLAGS: -+ return "MIPS_CXX_FLAGS"; -+ case DT_MIPS_PIXIE_INIT: -+ return "MIPS_PIXIE_INIT"; -+ case DT_MIPS_SYMBOL_LIB: -+ return "MIPS_SYMBOL_LIB"; -+ case DT_MIPS_LOCALPAGE_GOTIDX: -+ return "MIPS_LOCALPAGE_GOTIDX"; -+ case DT_MIPS_LOCAL_GOTIDX: -+ return "MIPS_LOCAL_GOTIDX"; -+ case DT_MIPS_HIDDEN_GOTIDX: -+ return "MIPS_HIDDEN_GOTIDX"; -+ case DT_MIPS_PROTECTED_GOTIDX: -+ return "MIPS_PROTECTED_GOTIDX"; -+ case DT_MIPS_OPTIONS: -+ return "MIPS_OPTIONS"; -+ case DT_MIPS_INTERFACE: -+ return "MIPS_INTERFACE"; -+ case DT_MIPS_DYNSTR_ALIGN: -+ return "MIPS_DYNSTR_ALIGN"; -+ case DT_MIPS_INTERFACE_SIZE: -+ return "MIPS_INTERFACE_SIZE"; -+ case DT_MIPS_RLD_TEXT_RESOLVE_ADDR: -+ return "MIPS_RLD_TEXT_RESOLVE_ADDR"; -+ case DT_MIPS_PERF_SUFFIX: -+ return "MIPS_PERF_SUFFIX"; -+ case DT_MIPS_COMPACT_SIZE: -+ return "MIPS_COMPACT_SIZE"; -+ case DT_MIPS_GP_VALUE: -+ return "MIPS_GP_VALUE"; -+ case DT_MIPS_AUX_DYNAMIC: -+ return "MIPS_AUX_DYNAMIC"; -+ case DT_MIPS_PLTGOT: -+ return "MIPS_PLTGOT"; -+ case DT_MIPS_RWPLT: -+ return "MIPS_RWPLT"; -+ case DT_MIPS_XHASH: -+ return "MIPS_XHASH"; -+ default: -+ return NULL; -+ } -+ return NULL; -+} --- a/libebl/eblopenbackend.c +++ b/libebl/eblopenbackend.c @@ -57,6 +57,7 @@ Ebl *riscv_init (Elf *, GElf_Half, Ebl * @@ -922,1604 +290,11 @@ Signed-off-by: Ying Huang --- a/libelf/libelfP.h +++ b/libelf/libelfP.h -@@ -617,4 +617,8 @@ extern void __libelf_reset_rawdata (Elf_ +@@ -617,4 +617,7 @@ extern void __libelf_reset_rawdata (Elf_ #define INVALID_NDX(ndx, type, data) \ unlikely ((data)->d_size / sizeof (type) <= (unsigned int) (ndx)) +#define ELF64_MIPS_R_TYPE1(i) ((i) & 0xff) +#define ELF64_MIPS_R_TYPE2(i) (((i) >> 8) & 0xff) +#define ELF64_MIPS_R_TYPE3(i) (((i) >> 16) & 0xff) -+#define is_debug_section_type(type) (type == SHT_PROGBITS || type == SHT_MIPS_DWARF) #endif /* libelfP.h */ ---- /dev/null -+++ b/backends/mips_cfi.c -@@ -0,0 +1,68 @@ -+/* MIPS ABI-specified defaults for DWARF CFI. -+ Copyright (C) 2009 Red Hat, Inc. -+ Copyright (C) 2024 CIP United Inc. -+ This file is part of elfutils. -+ -+ This file is free software; you can redistribute it and/or modify -+ it under the terms of either -+ -+ * the GNU Lesser General Public License as published by the Free -+ Software Foundation; either version 3 of the License, or (at -+ your option) any later version -+ -+ or -+ -+ * the GNU General Public License as published by the Free -+ Software Foundation; either version 2 of the License, or (at -+ your option) any later version -+ -+ or both in parallel, as here. -+ -+ elfutils is distributed in the hope that it will be useful, but -+ WITHOUT ANY WARRANTY; without even the implied warranty of -+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ General Public License for more details. -+ -+ You should have received copies of the GNU General Public License and -+ the GNU Lesser General Public License along with this program. If -+ not, see . */ -+ -+#ifdef HAVE_CONFIG_H -+# include -+#endif -+ -+#include -+ -+#define BACKEND mips_ -+#include "libebl_CPU.h" -+ -+int -+mips_abi_cfi (Ebl *ebl __attribute__ ((unused)), Dwarf_CIE *abi_info) -+{ -+ static const uint8_t abi_cfi[] = -+ { -+ DW_CFA_def_cfa, ULEB128_7 (31), ULEB128_7 (0), -+ /* Callee-saved regs. */ -+ DW_CFA_same_value, ULEB128_7 (16), /* s0 */ -+ DW_CFA_same_value, ULEB128_7 (17), /* s1 */ -+ DW_CFA_same_value, ULEB128_7 (18), /* s2 */ -+ DW_CFA_same_value, ULEB128_7 (19), /* s3 */ -+ DW_CFA_same_value, ULEB128_7 (20), /* s4 */ -+ DW_CFA_same_value, ULEB128_7 (21), /* s5 */ -+ DW_CFA_same_value, ULEB128_7 (22), /* s6 */ -+ DW_CFA_same_value, ULEB128_7 (23), /* s7 */ -+ DW_CFA_same_value, ULEB128_7 (28), /* gp */ -+ DW_CFA_same_value, ULEB128_7 (29), /* sp */ -+ DW_CFA_same_value, ULEB128_7 (30), /* fp */ -+ -+ DW_CFA_val_offset, ULEB128_7 (29), ULEB128_7 (0), -+ }; -+ -+ abi_info->initial_instructions = abi_cfi; -+ abi_info->initial_instructions_end = &abi_cfi[sizeof abi_cfi]; -+ abi_info->data_alignment_factor = 8; -+ -+ abi_info->return_address_register = 31; /* %ra */ -+ -+ return 0; -+} ---- /dev/null -+++ b/backends/mips_initreg.c -@@ -0,0 +1,61 @@ -+/* Fetch live process registers from TID. -+ Copyright (C) 2024 CIP United Inc. -+ This file is part of elfutils. -+ -+ This file is free software; you can redistribute it and/or modify -+ it under the terms of either -+ -+ * the GNU Lesser General Public License as published by the Free -+ Software Foundation; either version 3 of the License, or (at -+ your option) any later version -+ -+ or -+ -+ * the GNU General Public License as published by the Free -+ Software Foundation; either version 2 of the License, or (at -+ your option) any later version -+ -+ or both in parallel, as here. -+ -+ elfutils is distributed in the hope that it will be useful, but -+ WITHOUT ANY WARRANTY; without even the implied warranty of -+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ General Public License for more details. -+ -+ You should have received copies of the GNU General Public License and -+ the GNU Lesser General Public License along with this program. If -+ not, see . */ -+ -+#ifdef HAVE_CONFIG_H -+# include -+#endif -+ -+#include -+#if (defined(mips) || defined(__mips) || defined(__mips__) || defined(MIPS) || defined(__MIPS__)) && defined(__linux__) -+# include -+# include -+#include -+#endif -+ -+#define BACKEND mips_ -+#include "libebl_CPU.h" -+ -+ -+bool -+mips_set_initial_registers_tid (pid_t tid __attribute__ ((unused)), -+ ebl_tid_registers_t *setfunc __attribute__ ((unused)), -+ void *arg __attribute__ ((unused))) -+{ -+#if (!defined(mips) && !defined(__mips) && !defined(__mips__) && !defined(MIPS) && !defined(__MIPS__)) || !defined(__linux__) -+ return false; -+#else /* __mips__ */ -+/* For PTRACE_GETREGS */ -+ -+ struct pt_regs gregs; -+ if (ptrace (PTRACE_GETREGS, tid, 0, &gregs) != 0) -+ return false; -+ if (! setfunc (-1, 1, (Dwarf_Word *) &gregs.cp0_epc, arg)) -+ return false; -+ return setfunc (0, 32, (Dwarf_Word *) &gregs.regs[0], arg); -+#endif /* __mips__ */ -+} ---- /dev/null -+++ b/backends/mips_unwind.c -@@ -0,0 +1,84 @@ -+/* Get previous frame state for an existing frame state. -+ Copyright (C) 2016 The Qt Company Ltd. -+ Copyright (C) 2024 CIP United Inc. -+ This file is part of elfutils. -+ -+ This file is free software; you can redistribute it and/or modify -+ it under the terms of either -+ -+ * the GNU Lesser General Public License as published by the Free -+ Software Foundation; either version 3 of the License, or (at -+ your option) any later version -+ -+ or -+ -+ * the GNU General Public License as published by the Free -+ Software Foundation; either version 2 of the License, or (at -+ your option) any later version -+ -+ or both in parallel, as here. -+ -+ elfutils is distributed in the hope that it will be useful, but -+ WITHOUT ANY WARRANTY; without even the implied warranty of -+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ General Public License for more details. -+ -+ You should have received copies of the GNU General Public License and -+ the GNU Lesser General Public License along with this program. If -+ not, see . */ -+ -+#ifdef HAVE_CONFIG_H -+# include -+#endif -+ -+#define BACKEND mips_ -+#define SP_REG 29 -+#define FP_REG 30 -+#define LR_REG 31 -+#define FP_OFFSET 0 -+#define LR_OFFSET 8 -+#define SP_OFFSET 16 -+ -+#include "libebl_CPU.h" -+ -+/* There was no CFI. Maybe we happen to have a frame pointer and can unwind from that? */ -+ -+bool -+EBLHOOK(unwind) (Ebl *ebl __attribute__ ((unused)), Dwarf_Addr pc __attribute__ ((unused)), -+ ebl_tid_registers_t *setfunc, ebl_tid_registers_get_t *getfunc, -+ ebl_pid_memory_read_t *readfunc, void *arg, -+ bool *signal_framep __attribute__ ((unused))) -+{ -+ Dwarf_Word fp, lr, sp; -+ -+ if (!getfunc(LR_REG, 1, &lr, arg)) -+ return false; -+ -+ if (lr == 0 || !setfunc(-1, 1, &lr, arg)) -+ return false; -+ -+ if (!getfunc(FP_REG, 1, &fp, arg)) -+ fp = 0; -+ -+ if (!getfunc(SP_REG, 1, &sp, arg)) -+ sp = 0; -+ -+ Dwarf_Word newLr, newFp, newSp; -+ -+ if (!readfunc(fp + LR_OFFSET, &newLr, arg)) -+ newLr = 0; -+ -+ if (!readfunc(fp + FP_OFFSET, &newFp, arg)) -+ newFp = 0; -+ -+ newSp = fp + SP_OFFSET; -+ -+ // These are not fatal if they don't work. They will just prevent unwinding at the next frame. -+ setfunc(LR_REG, 1, &newLr, arg); -+ setfunc(FP_REG, 1, &newFp, arg); -+ setfunc(SP_REG, 1, &newSp, arg); -+ -+ // If the fp is invalid, we might still have a valid lr. -+ // But if the fp is valid, then the stack should be moving in the right direction. -+ return fp == 0 || newSp > sp; -+} ---- /dev/null -+++ b/backends/mips_corenote.c -@@ -0,0 +1,104 @@ -+/* MIPS specific core note handling. -+ Copyright (C) 2024 CIP United Inc. -+ This file is part of elfutils. -+ -+ This file is free software; you can redistribute it and/or modify -+ it under the terms of either -+ -+ * the GNU Lesser General Public License as published by the Free -+ Software Foundation; either version 3 of the License, or (at -+ your option) any later version -+ -+ or -+ -+ * the GNU General Public License as published by the Free -+ Software Foundation; either version 2 of the License, or (at -+ your option) any later version -+ -+ or both in parallel, as here. -+ -+ elfutils is distributed in the hope that it will be useful, but -+ WITHOUT ANY WARRANTY; without even the implied warranty of -+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ General Public License for more details. -+ -+ You should have received copies of the GNU General Public License and -+ the GNU Lesser General Public License along with this program. If -+ not, see . */ -+ -+#ifdef HAVE_CONFIG_H -+# include -+#endif -+ -+#include -+#include -+#include -+#include -+#include -+#include "libebl_CPU.h" -+ -+#ifndef BITS -+# define BITS 32 -+#define BACKEND mips_ -+#else -+# define BITS 64 -+# define BACKEND mips64_ -+#endif -+ -+#define PRSTATUS_REGS_SIZE (45 * (BITS / 8)) -+static const Ebl_Register_Location prstatus_regs[] = -+ { -+ { .offset = 0, .regno = 0, .count = (BITS == 32 ? 40 : 34), .bits = BITS }, -+ { .offset = BITS/8 * (BITS == 32 ? 41 : 35), .regno = (BITS == 32 ? 41 : 35), .count = (BITS == 32 ? 4 : 10), .bits = BITS }, -+ }; -+ -+#define PRSTATUS_REGSET_ITEMS \ -+ { \ -+ .name = "pc", .type = ELF_T_ADDR, .format = 'x', \ -+ .offset = offsetof (struct EBLHOOK(prstatus), pr_reg) + ((BITS/8) * (BITS == 32 ? 40 : 34)), \ -+ .group = "register", \ -+ .pc_register = true \ -+ } -+ -+static const Ebl_Register_Location mips_fpregset_regs[] = -+ { -+ { .offset = 0, .regno = 38, .count = 32, .bits = 64 }, /* fp0-fp31 */ -+ }; -+ -+static const Ebl_Core_Item mips_fpregset_items[] = -+ { -+ { -+ .name = "fcs", .type = ELF_T_WORD, .format = 'x', -+ .offset = 32 * 8, .group = "register" -+ }, -+ { -+ .name = "fir", .type = ELF_T_WORD, .format = 'x', -+ .offset = 32 * 8 + 4, .group = "register" -+ } -+ }; -+ -+#if BITS == 32 -+# define ULONG uint32_t -+# define ALIGN_ULONG 4 -+# define TYPE_ULONG ELF_T_WORD -+#define TYPE_LONG ELF_T_SWORD -+#else -+#define ULONG uint64_t -+#define ALIGN_ULONG 8 -+#define TYPE_ULONG ELF_T_XWORD -+#define TYPE_LONG ELF_T_SXWORD -+#endif -+#define PID_T int32_t -+#define UID_T uint32_t -+#define GID_T uint32_t -+#define ALIGN_PID_T 4 -+#define ALIGN_UID_T 4 -+#define ALIGN_GID_T 4 -+#define TYPE_PID_T ELF_T_SWORD -+#define TYPE_UID_T ELF_T_WORD -+#define TYPE_GID_T ELF_T_WORD -+ -+#define EXTRA_NOTES \ -+ EXTRA_REGSET_ITEMS (NT_FPREGSET, 32 * 8 + 4 * 2, mips_fpregset_regs, mips_fpregset_items) -+ -+#include "linux-core-note.c" ---- /dev/null -+++ b/backends/mips_regs.c -@@ -0,0 +1,135 @@ -+/* Register names and numbers for mips DWARF. -+ Copyright (C) 2006 Red Hat, Inc. -+ Copyright (C) 2024 CIP United Inc. -+ This file is part of elfutils. -+ -+ This file is free software; you can redistribute it and/or modify -+ it under the terms of either -+ -+ * the GNU Lesser General Public License as published by the Free -+ Software Foundation; either version 3 of the License, or (at -+ your option) any later version -+ -+ or -+ -+ * the GNU General Public License as published by the Free -+ Software Foundation; either version 2 of the License, or (at -+ your option) any later version -+ -+ or both in parallel, as here. -+ -+ elfutils is distributed in the hope that it will be useful, but -+ WITHOUT ANY WARRANTY; without even the implied warranty of -+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ General Public License for more details. -+ -+ You should have received copies of the GNU General Public License and -+ the GNU Lesser General Public License along with this program. If -+ not, see . */ -+ -+#ifdef HAVE_CONFIG_H -+# include -+#endif -+ -+#include -+#include -+#include -+ -+#define BACKEND mips_ -+#include "libebl_CPU.h" -+#include -+ssize_t -+mips_register_info (Ebl *ebl __attribute__ ((unused)), -+ int regno, char *name, size_t namelen, -+ const char **prefix, const char **setname, -+ int *bits, int *type) -+{ -+ if (name == NULL) -+ return 72; -+ -+ if (regno < 0 || regno > 71 || namelen < 4) -+ return -1; -+ -+ *prefix = "$"; -+ if (regno < 38) -+ { -+ *setname = "integer"; -+ *type = DW_ATE_signed; -+ *bits = 32; -+ } -+ else -+ { -+ *setname = "FPU"; -+ *type = DW_ATE_float; -+ *bits = 64; -+ } -+ -+ if (regno < 32) -+ { -+ if (regno < 10) -+ { -+ name[0] = regno + '0'; -+ namelen = 1; -+ } -+ else -+ { -+ name[0] = (regno / 10) + '0'; -+ name[1] = (regno % 10) + '0'; -+ namelen = 2; -+ } -+ if (regno == 28 || regno == 29 || regno == 31) -+ *type = DW_ATE_address; -+ } -+ else if (regno == 32) -+ { -+ return stpcpy (name, "lo") + 1 - name; -+ } -+ else if (regno == 33) -+ { -+ return stpcpy (name, "hi") + 1 - name; -+ } -+ else if (regno == 34) -+ { -+ return stpcpy (name, "pc") + 1 - name; -+ } -+ else if (regno == 35) -+ { -+ *type = DW_ATE_address; -+ return stpcpy (name, "bad") + 1 - name; -+ } -+ else if (regno == 36) -+ { -+ return stpcpy (name, "sr") + 1 - name; -+ } -+ else if (regno == 37) -+ { -+ *type = DW_ATE_address; -+ return stpcpy (name, "cause") + 1 - name; -+ } -+ else if (regno < 70) -+ { -+ name[0] = 'f'; -+ if (regno < 38 + 10) -+ { -+ name[1] = (regno - 38) + '0'; -+ namelen = 2; -+ } -+ else -+ { -+ name[1] = (regno - 38) / 10 + '0'; -+ name[2] = (regno - 38) % 10 + '0'; -+ namelen = 3; -+ } -+ } -+ else if (regno == 70) -+ { -+ return stpcpy (name, "fsr") + 1 - name; -+ } -+ else if (regno == 71) -+ { -+ return stpcpy (name, "fir") + 1 - name; -+ } -+ -+ name[namelen++] = '\0'; -+ return namelen; -+} ---- /dev/null -+++ b/backends/mips_retval.c -@@ -0,0 +1,196 @@ -+/* Function return value location for Linux/mips ABI. -+ Copyright (C) 2005 Red Hat, Inc. -+ Copyright (C) 2024 CIP United Inc. -+ This file is part of elfutils. -+ -+ This file is free software; you can redistribute it and/or modify -+ it under the terms of either -+ -+ * the GNU Lesser General Public License as published by the Free -+ Software Foundation; either version 3 of the License, or (at -+ your option) any later version -+ -+ or -+ -+ * the GNU General Public License as published by the Free -+ Software Foundation; either version 2 of the License, or (at -+ your option) any later version -+ -+ or both in parallel, as here. -+ -+ elfutils is distributed in the hope that it will be useful, but -+ WITHOUT ANY WARRANTY; without even the implied warranty of -+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ General Public License for more details. -+ -+ You should have received copies of the GNU General Public License and -+ the GNU Lesser General Public License along with this program. If -+ not, see . */ -+ -+#ifdef HAVE_CONFIG_H -+# include -+#endif -+ -+#include -+#include -+#include -+#include -+#include -+ -+#define BACKEND mips_ -+#include "libebl_CPU.h" -+#include "libdwP.h" -+#include -+ -+/* $v0 or pair $v0, $v1 */ -+static const Dwarf_Op loc_intreg_o32[] = -+ { -+ { .atom = DW_OP_reg2 }, { .atom = DW_OP_piece, .number = 4 }, -+ { .atom = DW_OP_reg3 }, { .atom = DW_OP_piece, .number = 4 }, -+ }; -+ -+static const Dwarf_Op loc_intreg[] = -+ { -+ { .atom = DW_OP_reg2 }, { .atom = DW_OP_piece, .number = 8 }, -+ { .atom = DW_OP_reg3 }, { .atom = DW_OP_piece, .number = 8 }, -+ }; -+#define nloc_intreg 1 -+#define nloc_intregpair 4 -+ -+/* $f0 (float), or pair $f0, $f1 (double). -+ * f2/f3 are used for COMPLEX (= 2 doubles) returns in Fortran */ -+static const Dwarf_Op loc_fpreg_o32[] = -+ { -+ { .atom = DW_OP_regx, .number = 32 }, { .atom = DW_OP_piece, .number = 4 }, -+ { .atom = DW_OP_regx, .number = 33 }, { .atom = DW_OP_piece, .number = 4 }, -+ { .atom = DW_OP_regx, .number = 34 }, { .atom = DW_OP_piece, .number = 4 }, -+ { .atom = DW_OP_regx, .number = 35 }, { .atom = DW_OP_piece, .number = 4 }, -+ }; -+ -+/* $f0, or pair $f0, $f2. */ -+static const Dwarf_Op loc_fpreg[] = -+ { -+ { .atom = DW_OP_regx, .number = 32 }, { .atom = DW_OP_piece, .number = 8 }, -+ { .atom = DW_OP_regx, .number = 34 }, { .atom = DW_OP_piece, .number = 8 }, -+ }; -+#define nloc_fpreg 1 -+#define nloc_fpregpair 4 -+#define nloc_fpregquad 8 -+ -+/* The return value is a structure and is actually stored in stack space -+ passed in a hidden argument by the caller. But, the compiler -+ helpfully returns the address of that space in $v0. */ -+static const Dwarf_Op loc_aggregate[] = -+ { -+ { .atom = DW_OP_breg2, .number = 0 } -+ }; -+#define nloc_aggregate 1 -+ -+int -+mips_return_value_location (Dwarf_Die *functypedie, const Dwarf_Op **locp) -+{ -+ unsigned int regsize = (gelf_getclass (functypedie->cu->dbg->elf) == ELFCLASS32 ) ? 4 : 8; -+ if (!regsize) -+ return -2; -+ -+ /* Start with the function's type, and get the DW_AT_type attribute, -+ which is the type of the return value. */ -+ -+ Dwarf_Attribute attr_mem; -+ Dwarf_Attribute *attr = dwarf_attr_integrate (functypedie, DW_AT_type, &attr_mem); -+ if (attr == NULL) -+ /* The function has no return value, like a `void' function in C. */ -+ return 0; -+ -+ Dwarf_Die die_mem; -+ Dwarf_Die *typedie = dwarf_formref_die (attr, &die_mem); -+ int tag = dwarf_tag (typedie); -+ -+ /* Follow typedefs and qualifiers to get to the actual type. */ -+ while (tag == DW_TAG_typedef -+ || tag == DW_TAG_const_type || tag == DW_TAG_volatile_type -+ || tag == DW_TAG_restrict_type) -+ { -+ attr = dwarf_attr_integrate (typedie, DW_AT_type, &attr_mem); -+ typedie = dwarf_formref_die (attr, &die_mem); -+ tag = dwarf_tag (typedie); -+ } -+ -+ switch (tag) -+ { -+ case -1: -+ return -1; -+ -+ case DW_TAG_subrange_type: -+ if (! dwarf_hasattr_integrate (typedie, DW_AT_byte_size)) -+ { -+ attr = dwarf_attr_integrate (typedie, DW_AT_type, &attr_mem); -+ typedie = dwarf_formref_die (attr, &die_mem); -+ tag = dwarf_tag (typedie); -+ } -+ /* Fall through. */ -+ FALLTHROUGH; -+ -+ case DW_TAG_base_type: -+ case DW_TAG_enumeration_type: -+ CASE_POINTER: -+ { -+ Dwarf_Word size; -+ if (dwarf_formudata (dwarf_attr_integrate (typedie, DW_AT_byte_size, -+ &attr_mem), &size) != 0) -+ { -+ if (dwarf_is_pointer (tag)) -+ size = regsize; -+ else -+ return -1; -+ } -+ if (tag == DW_TAG_base_type) -+ { -+ Dwarf_Word encoding; -+ if (dwarf_formudata (dwarf_attr_integrate (typedie, DW_AT_encoding, -+ &attr_mem), &encoding) != 0) -+ return -1; -+ -+#define ARCH_LOC(loc, regsize) ((regsize) == 4 ? (loc ## _o32) : (loc)) -+ -+ if (encoding == DW_ATE_float) -+ { -+ *locp = ARCH_LOC(loc_fpreg, regsize); -+ if (size <= regsize) -+ return nloc_fpreg; -+ -+ if (size <= 2*regsize) -+ return nloc_fpregpair; -+ -+ if (size <= 4*regsize) -+ return nloc_fpregquad; -+ -+ goto aggregate; -+ } -+ } -+ *locp = ARCH_LOC(loc_intreg, regsize); -+ if (size <= regsize) -+ return nloc_intreg; -+ if (size <= 2*regsize) -+ return nloc_intregpair; -+ -+ /* Else fall through. Shouldn't happen though (at least with gcc) */ -+ } -+ FALLTHROUGH; -+ -+ case DW_TAG_structure_type: -+ case DW_TAG_class_type: -+ case DW_TAG_union_type: -+ case DW_TAG_array_type: -+ aggregate: -+ *locp = loc_aggregate; -+ return nloc_aggregate; -+ case DW_TAG_unspecified_type: -+ return 0; -+ } -+ -+ /* XXX We don't have a good way to return specific errors from ebl calls. -+ This value means we do not understand the type, but it is well-formed -+ DWARF and might be valid. */ -+ return -2; -+} ---- a/libelf/elf_getdata.c -+++ b/libelf/elf_getdata.c -@@ -135,6 +135,119 @@ __libelf_data_type (GElf_Ehdr *ehdr, int - - /* Convert the data in the current section. */ - static void -+convert_data_for_mips64el (Elf_Scn *scn, int eclass, -+ int data, size_t size, Elf_Type type) -+{ -+ /* Do we need to convert the data and/or adjust for alignment? */ -+ if (data == MY_ELFDATA || type == ELF_T_BYTE) -+ { -+ /* In order to adapt macro GELF_R_SYM and GELF_R_TYPE on mips64, need to convert -+ relocation info(raw data). Some eu-utils use read-mmap method to map file, so -+ we need to malloc and memcpy raw data to avoid segment fault. After modification, -+ the correct value are saved in the malloced memory not in process address space. */ -+ scn->data_base = malloc (size); -+ if (scn->data_base == NULL) -+ { -+ __libelf_seterrno (ELF_E_NOMEM); -+ return; -+ } -+ -+ /* The copy will be appropriately aligned for direct access. */ -+ memcpy (scn->data_base, scn->rawdata_base, size); -+ } -+ else -+ { -+ xfct_t fp; -+ -+ scn->data_base = malloc (size); -+ if (scn->data_base == NULL) -+ { -+ __libelf_seterrno (ELF_E_NOMEM); -+ return; -+ } -+ -+ /* Make sure the source is correctly aligned for the conversion -+ function to directly access the data elements. */ -+ char *rawdata_source; -+ /* In order to adapt macro GELF_R_SYM and GELF_R_TYPE on mips64, need to convert -+ relocation info(raw data). Some eu-utils use read-mmap method to map file, so -+ we need to malloc and memcpy raw data to avoid segment fault. After modification, -+ the correct value are saved in the malloced memory not in process address space. */ -+ rawdata_source = malloc (size); -+ if (rawdata_source == NULL) -+ { -+ __libelf_seterrno (ELF_E_NOMEM); -+ return; -+ } -+ -+ /* The copy will be appropriately aligned for direct access. */ -+ memcpy (rawdata_source, scn->rawdata_base, size); -+ -+ /* Get the conversion function. */ -+ fp = __elf_xfctstom[eclass - 1][type]; -+ -+ fp (scn->data_base, rawdata_source, size, 0); -+ -+ if (rawdata_source != scn->rawdata_base) -+ free (rawdata_source); -+ } -+ -+ scn->data_list.data.d.d_buf = scn->data_base; -+ scn->data_list.data.d.d_size = size; -+ scn->data_list.data.d.d_type = type; -+ scn->data_list.data.d.d_off = scn->rawdata.d.d_off; -+ scn->data_list.data.d.d_align = scn->rawdata.d.d_align; -+ scn->data_list.data.d.d_version = scn->rawdata.d.d_version; -+ -+ scn->data_list.data.s = scn; -+ -+ /* In mips64 little-endian, r_info consists of four byte fields(contains -+ three reloc types) and a 32-bit symbol index. In order to adapt -+ GELF_R_SYM and GELF_R_TYPE, need to convert r_info to get correct symbol -+ index and type. */ -+ /* references: -+ https://www.linux-mips.org/pub/linux/mips/doc/ABI/elf64-2.4.pdf -+ Page40 && Page41 */ -+ GElf_Shdr shdr_mem; -+ GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem); -+ if (shdr->sh_type == SHT_REL) -+ { -+ size_t sh_entsize = gelf_fsize (scn->elf, ELF_T_REL, 1, EV_CURRENT); -+ int nentries = shdr->sh_size / sh_entsize; -+ for (int cnt = 0; cnt < nentries; ++cnt) -+ { -+ Elf_Data_Scn *data_scn = (Elf_Data_Scn *) &scn->data_list.data.d; -+ Elf64_Rel *value = &((Elf64_Rel *) data_scn->d.d_buf)[cnt]; -+ Elf64_Xword info = value->r_info; -+ value->r_info = (((info & 0xffffffff) << 32) -+ | ((info >> 56) & 0xff) -+ | ((info >> 40) & 0xff00) -+ | ((info >> 24) & 0xff0000) -+ | ((info >> 8) & 0xff000000)); -+ ((Elf64_Rel *) data_scn->d.d_buf)[cnt] = *value; -+ } -+ } -+ else if (shdr->sh_type == SHT_RELA) -+ { -+ size_t sh_entsize = gelf_fsize (scn->elf, ELF_T_RELA, 1, EV_CURRENT); -+ int nentries = shdr->sh_size / sh_entsize; -+ for (int cnt = 0; cnt < nentries; cnt++) -+ { -+ Elf_Data_Scn *data_scn = (Elf_Data_Scn *) &scn->data_list.data.d; -+ Elf64_Rela *value = &((Elf64_Rela *) data_scn->d.d_buf)[cnt]; -+ Elf64_Xword info = value->r_info; -+ value->r_info = (((info & 0xffffffff) << 32) -+ | ((info >> 56) & 0xff) -+ | ((info >> 40) & 0xff00) -+ | ((info >> 24) & 0xff0000) -+ | ((info >> 8) & 0xff000000)); -+ ((Elf64_Rela *) data_scn->d.d_buf)[cnt] = *value; -+ } -+ } -+} -+ -+/* Convert the data in the current section. */ -+static void - convert_data (Elf_Scn *scn, int eclass, - int data, size_t size, Elf_Type type) - { -@@ -451,8 +564,23 @@ __libelf_set_data_list_rdlock (Elf_Scn * - return; - } - -- /* Convert according to the version and the type. */ -- convert_data (scn, elf->class, -+ GElf_Shdr shdr_mem; -+ GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem); -+ GElf_Ehdr ehdr_mem; -+ GElf_Ehdr *ehdr = gelf_getehdr (scn->elf, &ehdr_mem); -+ if (shdr != NULL && (shdr->sh_type == SHT_RELA || shdr->sh_type == SHT_REL) && -+ scn->elf->class == ELFCLASS64 && ehdr != NULL && -+ ehdr->e_machine == EM_MIPS && ehdr->e_ident[EI_DATA] == ELFDATA2LSB) -+ convert_data_for_mips64el (scn, elf->class, -+ (elf->class == ELFCLASS32 -+ || (offsetof (struct Elf, state.elf32.ehdr) -+ == offsetof (struct Elf, state.elf64.ehdr)) -+ ? elf->state.elf32.ehdr->e_ident[EI_DATA] -+ : elf->state.elf64.ehdr->e_ident[EI_DATA]), -+ scn->rawdata.d.d_size, scn->rawdata.d.d_type); -+ else -+ /* Convert according to the version and the type. */ -+ convert_data (scn, elf->class, - (elf->class == ELFCLASS32 - || (offsetof (struct Elf, state.elf32.ehdr) - == offsetof (struct Elf, state.elf64.ehdr)) ---- a/libelf/elf_update.c -+++ b/libelf/elf_update.c -@@ -228,7 +228,60 @@ elf_update (Elf *elf, Elf_Cmd cmd) - size = -1; - } - else -+ { -+ /* Because we converted the relocation info in mips order when we call elf_getdata.c, -+ so we need to convert the modified data in original order bits before writing the -+ data to the file. */ -+ Elf_Scn *scn = NULL; -+ while ((scn = elf_nextscn (elf, scn)) != NULL) -+ { -+ GElf_Shdr shdr_mem; -+ GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem); -+ GElf_Ehdr ehdr_mem; -+ GElf_Ehdr *ehdr = gelf_getehdr (scn->elf, &ehdr_mem); -+ if (shdr != NULL && (shdr->sh_type == SHT_RELA || shdr->sh_type == SHT_REL) && -+ scn->elf->class == ELFCLASS64 && -+ ehdr != NULL && ehdr->e_machine == EM_MIPS && ehdr->e_ident[EI_DATA] == ELFDATA2LSB) -+ { -+ Elf_Data *d = elf_getdata (scn, NULL); -+ if (shdr->sh_type == SHT_REL) -+ { -+ size_t sh_entsize = gelf_fsize (scn->elf, ELF_T_REL, 1, EV_CURRENT); -+ int nentries = shdr->sh_size / sh_entsize; -+ for (int cnt = 0; cnt < nentries; ++cnt) -+ { -+ Elf_Data_Scn *data_scn = (Elf_Data_Scn *) d; -+ Elf64_Rel *value = &((Elf64_Rel *) data_scn->d.d_buf)[cnt]; -+ Elf64_Xword info = value->r_info; -+ value->r_info = (info >> 32 -+ | ((info << 56) & 0xff00000000000000) -+ | ((info << 40) & 0xff000000000000) -+ | ((info << 24) & 0xff0000000000) -+ | ((info << 8) & 0xff00000000)); -+ ((Elf64_Rel *) data_scn->d.d_buf)[cnt] = *value; -+ } -+ } -+ else if (shdr->sh_type == SHT_RELA) -+ { -+ size_t sh_entsize = gelf_fsize (scn->elf, ELF_T_RELA, 1, EV_CURRENT); -+ int nentries = shdr->sh_size / sh_entsize; -+ for (int cnt = 0; cnt < nentries; cnt++) -+ { -+ Elf_Data_Scn *data_scn = (Elf_Data_Scn *) d; -+ Elf64_Rela *value = &((Elf64_Rela *) data_scn->d.d_buf)[cnt]; -+ Elf64_Xword info = value->r_info; -+ value->r_info = (info >> 32 -+ | ((info << 56) & 0xff00000000000000) -+ | ((info << 40) & 0xff000000000000) -+ | ((info << 24) & 0xff0000000000) -+ | ((info << 8) & 0xff00000000)); -+ ((Elf64_Rela *) data_scn->d.d_buf)[cnt] = *value; -+ } -+ } -+ } -+ } - size = write_file (elf, size, change_bo, shnum); -+ } - } - - out: ---- /dev/null -+++ b/backends/mips_attrs.c -@@ -0,0 +1,140 @@ -+/* Object attribute tags for MIPS. -+ Copyright (C) 2024 CIP United Inc. -+ This file is part of elfutils. -+ -+ This file is free software; you can redistribute it and/or modify -+ it under the terms of either -+ -+ * the GNU Lesser General Public License as published by the Free -+ Software Foundation; either version 3 of the License, or (at -+ your option) any later version -+ -+ or -+ -+ * the GNU General Public License as published by the Free -+ Software Foundation; either version 2 of the License, or (at -+ your option) any later version -+ -+ or both in parallel, as here. -+ -+ elfutils is distributed in the hope that it will be useful, but -+ WITHOUT ANY WARRANTY; without even the implied warranty of -+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ General Public License for more details. -+ -+ You should have received copies of the GNU General Public License and -+ the GNU Lesser General Public License along with this program. If -+ not, see . */ -+ -+#ifdef HAVE_CONFIG_H -+# include -+#endif -+ -+#include -+#include -+ -+#define BACKEND mips_ -+#include "libebl_CPU.h" -+ -+#define KNOWN_VALUES(...) do \ -+ { \ -+ static const char *table[] = { __VA_ARGS__ }; \ -+ if (value < sizeof table / sizeof table[0]) \ -+ *value_name = table[value]; \ -+ } while (0) -+ -+//copy gnu attr tags from binutils-2.34/elfcpp/mips.h -+/* Object attribute tags. */ -+enum -+{ -+ /* 0-3 are generic. */ -+ -+ /* Floating-point ABI used by this object file. */ -+ Tag_GNU_MIPS_ABI_FP = 4, -+ -+ /* MSA ABI used by this object file. */ -+ Tag_GNU_MIPS_ABI_MSA = 8, -+}; -+ -+/* Object attribute values. */ -+enum -+{ -+ /* Values defined for Tag_GNU_MIPS_ABI_MSA. */ -+ -+ /* Not tagged or not using any ABIs affected by the differences. */ -+ Val_GNU_MIPS_ABI_MSA_ANY = 0, -+ -+ /* Using 128-bit MSA. */ -+ Val_GNU_MIPS_ABI_MSA_128 = 1, -+}; -+ -+/* Object attribute values. */ -+enum -+{ -+ /* This is reserved for backward-compatibility with an earlier -+ implementation of the MIPS NaN2008 functionality. */ -+ Val_GNU_MIPS_ABI_FP_NAN2008 = 8, -+}; -+ -+/* copy binutils-2.34/binutils/readelf.c display_mips_gnu_attribute */ -+bool -+mips_check_object_attribute (Ebl *ebl __attribute__ ((unused)), -+ const char *vendor, int tag, uint64_t value, -+ const char **tag_name, const char **value_name) -+{ -+ if (!strcmp (vendor, "gnu")) -+ switch (tag) -+ { -+ case Tag_GNU_MIPS_ABI_FP: -+ *tag_name = "Tag_GNU_MIPS_ABI_FP"; -+ switch (value) -+ { -+ case Val_GNU_MIPS_ABI_FP_ANY: -+ *value_name = "Hard or soft float"; -+ return true; -+ case Val_GNU_MIPS_ABI_FP_DOUBLE: -+ *value_name = "Hard float (double precision)"; -+ return true; -+ case Val_GNU_MIPS_ABI_FP_SINGLE: -+ *value_name = "Hard float (single precision)"; -+ return true; -+ case Val_GNU_MIPS_ABI_FP_SOFT: -+ *value_name = "Soft float"; -+ return true; -+ case Val_GNU_MIPS_ABI_FP_OLD_64: -+ *value_name = "Hard float (MIPS32r2 64-bit FPU 12 callee-saved)"; -+ return true; -+ case Val_GNU_MIPS_ABI_FP_XX: -+ *value_name = "Hard float (32-bit CPU, Any FPU)"; -+ return true; -+ case Val_GNU_MIPS_ABI_FP_64: -+ *value_name = "Hard float (32-bit CPU, 64-bit FPU)"; -+ return true; -+ case Val_GNU_MIPS_ABI_FP_64A: -+ *value_name = "Hard float compat (32-bit CPU, 64-bit FPU)"; -+ return true; -+ case Val_GNU_MIPS_ABI_FP_NAN2008: -+ *value_name = "NaN 2008 compatibility"; -+ return true; -+ default: -+ return true; -+ } -+ return true; -+ case Tag_GNU_MIPS_ABI_MSA: -+ *tag_name = "Tag_GNU_MIPS_ABI_MSA"; -+ switch (value) -+ { -+ case Val_GNU_MIPS_ABI_MSA_ANY: -+ *value_name = "Any MSA or not"; -+ return true; -+ case Val_GNU_MIPS_ABI_MSA_128: -+ *value_name = "128-bit MSA"; -+ return true; -+ default: -+ return true; -+ } -+ return true; -+ } -+ -+ return false; -+} ---- a/src/readelf.c -+++ b/src/readelf.c -@@ -2219,17 +2219,41 @@ handle_relocs_rel (Ebl *ebl, GElf_Ehdr * - (long int) GELF_R_SYM (rel->r_info)); - } - else if (GELF_ST_TYPE (sym->st_info) != STT_SECTION) -- printf (" %#0*" PRIx64 " %-20s %#0*" PRIx64 " %s\n", -- class == ELFCLASS32 ? 10 : 18, rel->r_offset, -- likely (ebl_reloc_type_check (ebl, -- GELF_R_TYPE (rel->r_info))) -- /* Avoid the leading R_ which isn't carrying any -- information. */ -- ? ebl_reloc_type_name (ebl, GELF_R_TYPE (rel->r_info), -- buf, sizeof (buf)) + 2 -- : _(""), -- class == ELFCLASS32 ? 10 : 18, sym->st_value, -- elf_strptr (ebl->elf, symshdr->sh_link, sym->st_name)); -+ { -+ unsigned long inf = rel->r_info; -+ printf (" %#0*" PRIx64 " %-20s %#0*" PRIx64 " %s\n", -+ class == ELFCLASS32 ? 10 : 18, rel->r_offset, -+ likely (ebl_reloc_type_check (ebl, -+ GELF_R_TYPE (rel->r_info))) -+ /* Avoid the leading R_ which isn't carrying any -+ information. */ -+ ? ebl_reloc_type_name (ebl, GELF_R_TYPE (rel->r_info), -+ buf, sizeof (buf)) + 2 -+ : _(""), -+ class == ELFCLASS32 ? 10 : 18, sym->st_value, -+ elf_strptr (ebl->elf, symshdr->sh_link, sym->st_name)); -+ -+ /* copy binutils-2.34/binutils/readelf.c dump_relocations+1753 */ -+ if(ebl->elf->class == ELFCLASS64 && ebl->elf->state.elf64.ehdr->e_machine == EM_MIPS) -+ { -+ unsigned int type2 = ELF64_MIPS_R_TYPE2 (inf); -+ unsigned int type3 = ELF64_MIPS_R_TYPE3 (inf); -+ const char * rtype2 = ebl_reloc_type_name (ebl, type2, buf, sizeof (buf)) + 2; -+ const char * rtype3 = ebl_reloc_type_name (ebl, type3, buf, sizeof (buf)) + 2; -+ printf(" Type2: "); -+ if (rtype2 == NULL) -+ printf (_("unrecognized: %lx"), (unsigned long) type2 & 0xffffffff); -+ else -+ printf ("%s", rtype2); -+ -+ printf ("\n Type3: "); -+ if (rtype3 == NULL) -+ printf (_("unrecognized: %lx"), (unsigned long) type3 & 0xffffffff); -+ else -+ printf ("%s", rtype3); -+ printf("\n"); -+ } -+ } - else - { - /* This is a relocation against a STT_SECTION symbol. */ -@@ -2253,16 +2277,40 @@ handle_relocs_rel (Ebl *ebl, GElf_Ehdr * - (long int) (sym->st_shndx == SHN_XINDEX - ? xndx : sym->st_shndx)); - else -- printf (" %#0*" PRIx64 " %-20s %#0*" PRIx64 " %s\n", -- class == ELFCLASS32 ? 10 : 18, rel->r_offset, -- ebl_reloc_type_check (ebl, GELF_R_TYPE (rel->r_info)) -- /* Avoid the leading R_ which isn't carrying any -- information. */ -- ? ebl_reloc_type_name (ebl, GELF_R_TYPE (rel->r_info), -- buf, sizeof (buf)) + 2 -- : _(""), -- class == ELFCLASS32 ? 10 : 18, sym->st_value, -- elf_strptr (ebl->elf, shstrndx, secshdr->sh_name)); -+ { -+ unsigned long inf = rel->r_info; -+ printf (" %#0*" PRIx64 " %-20s %#0*" PRIx64 " %s\n", -+ class == ELFCLASS32 ? 10 : 18, rel->r_offset, -+ ebl_reloc_type_check (ebl, GELF_R_TYPE (rel->r_info)) -+ /* Avoid the leading R_ which isn't carrying any -+ information. */ -+ ? ebl_reloc_type_name (ebl, GELF_R_TYPE (rel->r_info), -+ buf, sizeof (buf)) + 2 -+ : _(""), -+ class == ELFCLASS32 ? 10 : 18, sym->st_value, -+ elf_strptr (ebl->elf, shstrndx, secshdr->sh_name)); -+ -+ /* copy binutils-2.34/binutils/readelf.c dump_relocations+1753 */ -+ if(ebl->elf->class == ELFCLASS64 && ebl->elf->state.elf64.ehdr->e_machine == EM_MIPS) -+ { -+ unsigned int type2 = ELF64_MIPS_R_TYPE2 (inf); -+ unsigned int type3 = ELF64_MIPS_R_TYPE3 (inf); -+ const char * rtype2 = ebl_reloc_type_name (ebl, type2, buf, sizeof (buf)) + 2; -+ const char * rtype3 = ebl_reloc_type_name (ebl, type3, buf, sizeof (buf)) + 2; -+ printf(" Type2: "); -+ if (rtype2 == NULL) -+ printf (_("unrecognized: %lx"), (unsigned long) type2 & 0xffffffff); -+ else -+ printf ("%s", rtype2); -+ -+ printf ("\n Type3: "); -+ if (rtype3 == NULL) -+ printf (_("unrecognized: %lx"), (unsigned long) type3 & 0xffffffff); -+ else -+ printf ("%s", rtype3); -+ printf("\n"); -+ } -+ } - } - } - } -@@ -2410,19 +2458,43 @@ handle_relocs_rela (Ebl *ebl, GElf_Ehdr - (long int) GELF_R_SYM (rel->r_info)); - } - else if (GELF_ST_TYPE (sym->st_info) != STT_SECTION) -- printf ("\ -+ { -+ unsigned long inf = rel->r_info; -+ printf ("\ - %#0*" PRIx64 " %-15s %#0*" PRIx64 " %+6" PRId64 " %s\n", -- class == ELFCLASS32 ? 10 : 18, rel->r_offset, -- likely (ebl_reloc_type_check (ebl, -- GELF_R_TYPE (rel->r_info))) -- /* Avoid the leading R_ which isn't carrying any -- information. */ -- ? ebl_reloc_type_name (ebl, GELF_R_TYPE (rel->r_info), -- buf, sizeof (buf)) + 2 -- : _(""), -- class == ELFCLASS32 ? 10 : 18, sym->st_value, -- rel->r_addend, -- elf_strptr (ebl->elf, symshdr->sh_link, sym->st_name)); -+ class == ELFCLASS32 ? 10 : 18, rel->r_offset, -+ likely (ebl_reloc_type_check (ebl, -+ GELF_R_TYPE (rel->r_info))) -+ /* Avoid the leading R_ which isn't carrying any -+ information. */ -+ ? ebl_reloc_type_name (ebl, GELF_R_TYPE (rel->r_info), -+ buf, sizeof (buf)) + 2 -+ : _(""), -+ class == ELFCLASS32 ? 10 : 18, sym->st_value, -+ rel->r_addend, -+ elf_strptr (ebl->elf, symshdr->sh_link, sym->st_name)); -+ -+ /* copy binutils-2.34/binutils/readelf.c dump_relocations+1753 */ -+ if(ebl->elf->class == ELFCLASS64 && ebl->elf->state.elf64.ehdr->e_machine == EM_MIPS) -+ { -+ unsigned int type2 = ELF64_MIPS_R_TYPE2 (inf); -+ unsigned int type3 = ELF64_MIPS_R_TYPE3 (inf); -+ const char * rtype2 = ebl_reloc_type_name (ebl, type2, buf, sizeof (buf)) + 2; -+ const char * rtype3 = ebl_reloc_type_name (ebl, type3, buf, sizeof (buf)) + 2; -+ printf(" Type2: "); -+ if (rtype2 == NULL) -+ printf (_("unrecognized: %lx"), (unsigned long) type2 & 0xffffffff); -+ else -+ printf ("%s", rtype2); -+ -+ printf ("\n Type3: "); -+ if (rtype3 == NULL) -+ printf (_("unrecognized: %lx"), (unsigned long) type3 & 0xffffffff); -+ else -+ printf ("%s", rtype3); -+ printf("\n"); -+ } -+ } - else - { - /* This is a relocation against a STT_SECTION symbol. */ -@@ -2446,18 +2518,42 @@ handle_relocs_rela (Ebl *ebl, GElf_Ehdr - (long int) (sym->st_shndx == SHN_XINDEX - ? xndx : sym->st_shndx)); - else -- printf ("\ -+ { -+ unsigned long inf = rel->r_info; -+ printf ("\ - %#0*" PRIx64 " %-15s %#0*" PRIx64 " %+6" PRId64 " %s\n", -- class == ELFCLASS32 ? 10 : 18, rel->r_offset, -- ebl_reloc_type_check (ebl, GELF_R_TYPE (rel->r_info)) -- /* Avoid the leading R_ which isn't carrying any -- information. */ -- ? ebl_reloc_type_name (ebl, GELF_R_TYPE (rel->r_info), -- buf, sizeof (buf)) + 2 -- : _(""), -- class == ELFCLASS32 ? 10 : 18, sym->st_value, -- rel->r_addend, -- elf_strptr (ebl->elf, shstrndx, secshdr->sh_name)); -+ class == ELFCLASS32 ? 10 : 18, rel->r_offset, -+ ebl_reloc_type_check (ebl, GELF_R_TYPE (rel->r_info)) -+ /* Avoid the leading R_ which isn't carrying any -+ information. */ -+ ? ebl_reloc_type_name (ebl, GELF_R_TYPE (rel->r_info), -+ buf, sizeof (buf)) + 2 -+ : _(""), -+ class == ELFCLASS32 ? 10 : 18, sym->st_value, -+ rel->r_addend, -+ elf_strptr (ebl->elf, shstrndx, secshdr->sh_name)); -+ -+ /* copy binutils-2.34/binutils/readelf.c dump_relocations+1753 */ -+ if(ebl->elf->class == ELFCLASS64 && ebl->elf->state.elf64.ehdr->e_machine == EM_MIPS) -+ { -+ unsigned int type2 = ELF64_MIPS_R_TYPE2 (inf); -+ unsigned int type3 = ELF64_MIPS_R_TYPE3 (inf); -+ const char * rtype2 = ebl_reloc_type_name (ebl, type2, buf, sizeof (buf)) + 2; -+ const char * rtype3 = ebl_reloc_type_name (ebl, type3, buf, sizeof (buf)) + 2; -+ printf(" Type2: "); -+ if (rtype2 == NULL) -+ printf (_("unrecognized: %-7lx"), (unsigned long) type2 & 0xffffffff); -+ else -+ printf ("%s", rtype2); -+ -+ printf ("\n Type3: "); -+ if (rtype3 == NULL) -+ printf (_("unrecognized: %lx"), (unsigned long) type3 & 0xffffffff); -+ else -+ printf ("%s", rtype3); -+ printf("\n"); -+ } -+ } - } - } - } -@@ -12043,7 +12139,7 @@ print_debug (Dwfl_Module *dwflmod, Ebl * - GElf_Shdr shdr_mem; - GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem); - -- if (shdr != NULL && shdr->sh_type == SHT_PROGBITS) -+ if (shdr != NULL && is_debug_section_type(shdr->sh_type)) - { - const char *name = elf_strptr (ebl->elf, shstrndx, - shdr->sh_name); -@@ -12073,7 +12169,7 @@ print_debug (Dwfl_Module *dwflmod, Ebl * - GElf_Shdr shdr_mem; - GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem); - -- if (shdr != NULL && shdr->sh_type == SHT_PROGBITS) -+ if (shdr != NULL && is_debug_section_type(shdr->sh_type)) - { - static const struct - { ---- a/tests/Makefile.am -+++ b/tests/Makefile.am -@@ -214,7 +214,7 @@ TESTS = run-arextract.sh run-arsymtest.s - run-nvidia-extended-linemap-libdw.sh run-nvidia-extended-linemap-readelf.sh \ - run-readelf-dw-form-indirect.sh run-strip-largealign.sh \ - run-readelf-Dd.sh run-dwfl-core-noncontig.sh run-cu-dwp-section-info.sh \ -- run-declfiles.sh -+ run-declfiles.sh run-readelf-reloc.sh - - if !BIARCH - export ELFUTILS_DISABLE_BIARCH = 1 -@@ -646,7 +646,8 @@ EXTRA_DIST = run-arextract.sh run-arsymt - testfile-dwp-5-cu-index-overflow.dwp.bz2 \ - testfile-dwp-4-cu-index-overflow.bz2 \ - testfile-dwp-4-cu-index-overflow.dwp.bz2 \ -- testfile-dwp-cu-index-overflow.source -+ testfile-dwp-cu-index-overflow.source \ -+ run-readelf-reloc.sh - - - if USE_VALGRIND ---- /dev/null -+++ b/tests/run-readelf-reloc.sh -@@ -0,0 +1,42 @@ -+#! /bin/bash -+# Copyright (C) 2024 CIP United Inc. -+# This file is part of elfutils. -+# -+# This file is free software; you can redistribute it and/or modify -+# it under the terms of the GNU General Public License as published by -+# the Free Software Foundation; either version 3 of the License, or -+# (at your option) any later version. -+# -+# elfutils is distributed in the hope that it will be useful, but -+# WITHOUT ANY WARRANTY; without even the implied warranty of -+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+# GNU General Public License for more details. -+# -+# You should have received a copy of the GNU General Public License -+# along with this program. If not, see . -+ -+. $srcdir/test-subr.sh -+ -+tempfiles test-readelf-h.txt test-readelf-reloc.txt -+testrun ${abs_top_builddir}/src/readelf -h ${abs_top_builddir}/src/strip.o > test-readelf-h.txt -+machine=`cat test-readelf-h.txt | grep Machine` -+class=`cat test-readelf-h.txt | grep Class` -+endian=`cat test-readelf-h.txt | grep Data` -+if [[ "$machine" == *MIPS* && "$class" == *ELF64 && "$endian" == *little* ]]; then -+testrun ${abs_top_builddir}/src/readelf -r ${abs_top_builddir}/src/strip.o | head -n 12 | tail -n 10 > test-readelf-reloc.txt -+ -+testrun_compare cat test-readelf-reloc.txt << EOF -+ Offset Type Value Addend Name -+ 0x0000000000000008 MIPS_GPREL16 000000000000000000 +0 .text -+ Type2: MIPS_SUB -+ Type3: MIPS_HI16 -+ 0x0000000000000010 MIPS_GPREL16 000000000000000000 +0 .text -+ Type2: MIPS_SUB -+ Type3: MIPS_LO16 -+ 0x0000000000000014 MIPS_CALL16 000000000000000000 +0 gelf_getehdr -+ Type2: MIPS_NONE -+ Type3: MIPS_NONE -+EOF -+fi -+ -+exit 0 ---- a/src/elflint.c -+++ b/src/elflint.c -@@ -936,7 +936,9 @@ section [%2d] '%s': symbol %zu (%s): non - } - - if (GELF_ST_TYPE (sym->st_info) == STT_SECTION -- && GELF_ST_BIND (sym->st_info) != STB_LOCAL) -+ && GELF_ST_BIND (sym->st_info) != STB_LOCAL -+ && ehdr->e_machine != EM_MIPS -+ && strcmp (name, "_DYNAMIC_LINKING") != 0) - ERROR (_("\ - section [%2d] '%s': symbol %zu (%s): non-local section symbol\n"), - idx, section_name (ebl, idx), cnt, name); -@@ -3828,6 +3830,10 @@ cannot get section header for section [% - && ebl_bss_plt_p (ebl)) - good_type = SHT_NOBITS; - -+ if (ehdr->e_machine == EM_MIPS -+ && (strstr(special_sections[s].name, ".debug") != NULL)) -+ good_type = SHT_MIPS_DWARF; -+ - /* In a debuginfo file, any normal section can be SHT_NOBITS. - This is only invalid for DWARF sections and .shstrtab. */ - if (shdr->sh_type != good_type -@@ -3988,12 +3994,21 @@ section [%2zu] '%s': size not multiple o - ERROR (_("section [%2zu] '%s'" - " contains invalid processor-specific flag(s)" - " %#" PRIx64 "\n"), -- cnt, section_name (ebl, cnt), sh_flags & SHF_MASKPROC); -+ cnt, section_name (ebl, cnt), sh_flags & SHF_MASKPROC); - sh_flags &= ~(GElf_Xword) SHF_MASKPROC; - } - if (sh_flags & SHF_MASKOS) -- if (gnuld) -- sh_flags &= ~(GElf_Xword) SHF_GNU_RETAIN; -+ { -+ if (gnuld) -+ sh_flags &= ~(GElf_Xword) SHF_GNU_RETAIN; -+ if (!ebl_machine_section_flag_check (ebl, -+ sh_flags & SHF_MASKOS)) -+ ERROR (_("section [%2zu] '%s'" -+ " contains invalid os-specific flag(s)" -+ " %#" PRIx64 "\n"), -+ cnt, section_name (ebl, cnt), sh_flags & SHF_MASKOS); -+ sh_flags &= ~(GElf_Xword) SHF_MASKOS; -+ } - if (sh_flags != 0) - ERROR (_("section [%2zu] '%s' contains unknown flag(s)" - " %#" PRIx64 "\n"), -@@ -4059,6 +4074,7 @@ section [%2zu] '%s': merge flag set but - switch (shdr->sh_type) - { - case SHT_PROGBITS: -+ case SHT_MIPS_DWARF: - break; - - case SHT_NOBITS: -@@ -4716,7 +4732,7 @@ program header offset in ELF header and - if (shdr != NULL - && ((is_debuginfo && shdr->sh_type == SHT_NOBITS) - || (! is_debuginfo -- && (shdr->sh_type == SHT_PROGBITS -+ && (is_debug_section_type(shdr->sh_type) - || shdr->sh_type == SHT_X86_64_UNWIND))) - && elf_strptr (ebl->elf, shstrndx, shdr->sh_name) != NULL - && ! strcmp (".eh_frame_hdr", ---- /dev/null -+++ b/backends/mips64_corenote.c -@@ -0,0 +1,2 @@ -+#define BITS 64 -+#include "mips_corenote.c" ---- a/libebl/eblcorenotetypename.c -+++ b/libebl/eblcorenotetypename.c -@@ -94,6 +94,8 @@ ebl_core_note_type_name (Ebl *ebl, uint3 - KNOWNSTYPE (ARM_SYSTEM_CALL); - KNOWNSTYPE (SIGINFO); - KNOWNSTYPE (FILE); -+ KNOWNSTYPE (MIPS_FP_MODE); -+ KNOWNSTYPE (MIPS_MSA); - #undef KNOWNSTYPE - - default: ---- a/tests/run-allregs.sh -+++ b/tests/run-allregs.sh -@@ -2904,4 +2904,83 @@ FPU registers: - 62: ft10 (ft10), float 64 bits - 63: ft11 (ft11), float 64 bits - EOF -+ -+# See run-readelf-mixed-corenote.sh for instructions to regenerate -+# this core file. -+regs_test testfile-mips64-core <<\EOF -+integer registers: -+ 0: $0 (0), signed 32 bits -+ 1: $1 (1), signed 32 bits -+ 2: $2 (2), signed 32 bits -+ 3: $3 (3), signed 32 bits -+ 4: $4 (4), signed 32 bits -+ 5: $5 (5), signed 32 bits -+ 6: $6 (6), signed 32 bits -+ 7: $7 (7), signed 32 bits -+ 8: $8 (8), signed 32 bits -+ 9: $9 (9), signed 32 bits -+ 10: $10 (10), signed 32 bits -+ 11: $11 (11), signed 32 bits -+ 12: $12 (12), signed 32 bits -+ 13: $13 (13), signed 32 bits -+ 14: $14 (14), signed 32 bits -+ 15: $15 (15), signed 32 bits -+ 16: $16 (16), signed 32 bits -+ 17: $17 (17), signed 32 bits -+ 18: $18 (18), signed 32 bits -+ 19: $19 (19), signed 32 bits -+ 20: $20 (20), signed 32 bits -+ 21: $21 (21), signed 32 bits -+ 22: $22 (22), signed 32 bits -+ 23: $23 (23), signed 32 bits -+ 24: $24 (24), signed 32 bits -+ 25: $25 (25), signed 32 bits -+ 26: $26 (26), signed 32 bits -+ 27: $27 (27), signed 32 bits -+ 28: $28 (28), address 32 bits -+ 29: $29 (29), address 32 bits -+ 30: $30 (30), signed 32 bits -+ 31: $31 (31), address 32 bits -+ 32: $lo (lo), signed 32 bits -+ 33: $hi (hi), signed 32 bits -+ 34: $pc (pc), signed 32 bits -+ 35: $bad (bad), address 32 bits -+ 36: $sr (sr), signed 32 bits -+ 37: $cause (cause), address 32 bits -+FPU registers: -+ 38: $f0 (f0), float 64 bits -+ 39: $f1 (f1), float 64 bits -+ 40: $f2 (f2), float 64 bits -+ 41: $f3 (f3), float 64 bits -+ 42: $f4 (f4), float 64 bits -+ 43: $f5 (f5), float 64 bits -+ 44: $f6 (f6), float 64 bits -+ 45: $f7 (f7), float 64 bits -+ 46: $f8 (f8), float 64 bits -+ 47: $f9 (f9), float 64 bits -+ 48: $f10 (f10), float 64 bits -+ 49: $f11 (f11), float 64 bits -+ 50: $f12 (f12), float 64 bits -+ 51: $f13 (f13), float 64 bits -+ 52: $f14 (f14), float 64 bits -+ 53: $f15 (f15), float 64 bits -+ 54: $f16 (f16), float 64 bits -+ 55: $f17 (f17), float 64 bits -+ 56: $f18 (f18), float 64 bits -+ 57: $f19 (f19), float 64 bits -+ 58: $f20 (f20), float 64 bits -+ 59: $f21 (f21), float 64 bits -+ 60: $f22 (f22), float 64 bits -+ 61: $f23 (f23), float 64 bits -+ 62: $f24 (f24), float 64 bits -+ 63: $f25 (f25), float 64 bits -+ 64: $f26 (f26), float 64 bits -+ 65: $f27 (f27), float 64 bits -+ 66: $f28 (f28), float 64 bits -+ 67: $f29 (f29), float 64 bits -+ 68: $f30 (f30), float 64 bits -+ 69: $f31 (f31), float 64 bits -+ 70: $fsr (fsr), float 64 bits -+ 71: $fir (fir), float 64 bits -+EOF - exit 0 ---- a/tests/run-readelf-mixed-corenote.sh -+++ b/tests/run-readelf-mixed-corenote.sh -@@ -716,4 +716,101 @@ Note segment of 1408 bytes at offset 0x3 - 2000155000-2000157000 00122000 8192 /lib64/libc-2.27.so - EOF - -+# To reproduce this core dump, do this on a mips machine: -+# $ gcc -x c <(echo 'int main () { return *(int *)0x12345678; }') -+# $ ./a.out -+testfiles testfile-mips64-core -+testrun_compare ${abs_top_builddir}/src/readelf -n testfile-mips64-core <<\EOF -+ -+Note segment of 2572 bytes at offset 0x3c0: -+ Owner Data size Type -+ CORE 480 PRSTATUS -+ info.si_signo: 11, info.si_code: 0, info.si_errno: 0, cursig: 11 -+ sigpend: <> -+ sighold: <> -+ pid: 1660204, ppid: 1457483, pgrp: 1660204, sid: 1457483 -+ utime: 0.000000, stime: 0.012000, cutime: 0.000000, cstime: 0.000000 -+ pc: 0x000000aaacce0a64, fpvalid: 1 -+ bad: 0x12345678 sr: 0 cause: 0x0400ccf3 -+ f0: 0x1000000800000000 f1: 0x0000000000000000 f2: 0x0000000000000000 -+ f3: 0x0000000000000000 f4: 0x0000000000000000 f5: 0x0000000000000000 -+ f6: 0x0000000000000000 -+ 0: 0 1: 0 2: 1 -+ 3: 0 4: 305419896 5: 0 -+ 6: -73593800 7: 255 8: 1 -+ 9: 0 10: -73593464 11: 255 -+ 12: -73593448 13: 255 14: 0 -+ 15: 0 16: -244869184 17: 255 -+ 18: -244886336 19: 255 20: -73593472 -+ 21: 255 22: -1 23: -1 -+ 24: 3 25: 0 26: 3167716 -+ 27: 0 28: 0x00000024 29: 0x00000000 -+ 30: 49495 31: 0x00000000 lo: -73593464 -+ hi: 255 bad: 0x12345678 sr: 0 -+ cause: 0x0400ccf3 f0: 0x1000000800000000 -+ f1: 0x0000000000000000 f2: 0x0000000000000000 -+ f3: 0x0000000000000000 f4: 0x0000000000000000 -+ f5: 0x0000000000000000 f6: 0x0000000000000000 -+ CORE 136 PRPSINFO -+ state: 0, sname: R, zomb: 0, nice: 0, flag: 0x0000000000402600 -+ uid: 1014, gid: 100, pid: 1660204, ppid: 1457483, pgrp: 1660204 -+ sid: 1457483 -+ fname: a.out, psargs: ./a.out -+ CORE 128 SIGINFO -+ si_signo: 11, si_errno: 1, si_code: 0 -+ sender PID: 305419896, sender UID: 0 -+ CORE 320 AUXV -+ SYSINFO_EHDR: 0xffff14c000 -+ HWCAP: 0x7806 -+ PAGESZ: 16384 -+ CLKTCK: 100 -+ PHDR: 0xaaacce0040 -+ PHENT: 56 -+ PHNUM: 9 -+ BASE: 0xfff1694000 -+ FLAGS: 0 -+ ENTRY: 0xaaacce08d0 -+ UID: 1014 -+ EUID: 1014 -+ GID: 100 -+ EGID: 100 -+ SECURE: 0 -+ RANDOM: 0xfffb9d0f9c -+ EXECFN: 0xfffb9d3ff0 -+ PLATFORM: 0xfffb9d0fb5 -+ BASE_PLATFORM: 0xfffb9d0fac -+ NULL -+ CORE 549 FILE -+ 9 files: -+ aaacce0000-aaacce4000 00000000 16384 /tmp/a.out -+ aaaccf0000-aaaccf4000 00000000 16384 /tmp/a.out -+ fff1470000-fff165c000 00000000 2015232 /usr/lib/mips64el-linux-gnuabi64/libc.so.6 -+ fff165c000-fff1668000 001ec000 49152 /usr/lib/mips64el-linux-gnuabi64/libc.so.6 -+ fff1668000-fff1670000 001e8000 32768 /usr/lib/mips64el-linux-gnuabi64/libc.so.6 -+ fff1670000-fff1678000 001f0000 32768 /usr/lib/mips64el-linux-gnuabi64/libc.so.6 -+ fff1694000-fff16c4000 00000000 196608 /usr/lib/mips64el-linux-gnuabi64/ld.so.1 -+ fff16d0000-fff16d4000 0002c000 16384 /usr/lib/mips64el-linux-gnuabi64/ld.so.1 -+ fff16d4000-fff16d8000 00030000 16384 /usr/lib/mips64el-linux-gnuabi64/ld.so.1 -+ CORE 264 FPREGSET -+ fcs: 0x000c0000, fir: 0x00f70501 -+ f0: 0xffffffffffffffff f1: 0xffffffffffffffff -+ f2: 0xffffffffffffffff f3: 0xffffffffffffffff -+ f4: 0xffffffffffffffff f5: 0xffffffffffffffff -+ f6: 0xffffffffffffffff f7: 0xffffffffffffffff -+ f8: 0xffffffffffffffff f9: 0xffffffffffffffff -+ f10: 0xffffffffffffffff f11: 0xffffffffffffffff -+ f12: 0xffffffffffffffff f13: 0xffffffffffffffff -+ f14: 0xffffffffffffffff f15: 0xffffffffffffffff -+ f16: 0xffffffffffffffff f17: 0xffffffffffffffff -+ f18: 0xffffffffffffffff f19: 0xffffffffffffffff -+ f20: 0xffffffffffffffff f21: 0xffffffffffffffff -+ f22: 0xffffffffffffffff f23: 0xffffffffffffffff -+ f24: 0xffffffffffffffff f25: 0xffffffffffffffff -+ f26: 0xffffffffffffffff f27: 0xffffffffffffffff -+ f28: 0xffffffffffffffff f29: 0xffffffffffffffff -+ f30: 0xffffffffffffffff f31: 0xffffffffffffffff -+ LINUX 4 MIPS_FP_MODE -+ LINUX 528 MIPS_MSA -+EOF -+ - exit 0 diff --git a/tools/elfutils/patches/011-backport-mips-support-strip.patch b/tools/elfutils/patches/011-backport-mips-support-strip.patch new file mode 100644 index 0000000000..7ea9bedc1a --- /dev/null +++ b/tools/elfutils/patches/011-backport-mips-support-strip.patch @@ -0,0 +1,230 @@ +In mips64 little-endian, r_info consists of four byte fields(contains +three reloc types) and a 32-bit symbol index. In order to adapt +GELF_R_SYM and GELF_R_TYPE, need convert raw data to get correct symbol +index and type. + + libelf/elf_getdata.c: Some eu-utils use read-mmap method to map file, +so we need to malloc and memcpy raw data to avoid segment fault. After +modification, the correct value are saved in the malloced memory not in +process address space. + libelf/elf_updata.c: Because we converted the relocation info in mips +order when we call elf_getdata.c, so we need to convert the modified data +in original order bits before writing the data to the file. + +Signed-off-by: Ying Huang +--- + libelf/elf_getdata.c | 132 ++++++++++++++++++++++++++++++++++++++++++- + libelf/elf_update.c | 53 +++++++++++++++++ + 2 files changed, 183 insertions(+), 2 deletions(-) + +--- a/libelf/elf_getdata.c ++++ b/libelf/elf_getdata.c +@@ -135,6 +135,119 @@ __libelf_data_type (GElf_Ehdr *ehdr, int + + /* Convert the data in the current section. */ + static void ++convert_data_for_mips64el (Elf_Scn *scn, int eclass, ++ int data, size_t size, Elf_Type type) ++{ ++ /* Do we need to convert the data and/or adjust for alignment? */ ++ if (data == MY_ELFDATA || type == ELF_T_BYTE) ++ { ++ /* In order to adapt macro GELF_R_SYM and GELF_R_TYPE on mips64, need to convert ++ relocation info(raw data). Some eu-utils use read-mmap method to map file, so ++ we need to malloc and memcpy raw data to avoid segment fault. After modification, ++ the correct value are saved in the malloced memory not in process address space. */ ++ scn->data_base = malloc (size); ++ if (scn->data_base == NULL) ++ { ++ __libelf_seterrno (ELF_E_NOMEM); ++ return; ++ } ++ ++ /* The copy will be appropriately aligned for direct access. */ ++ memcpy (scn->data_base, scn->rawdata_base, size); ++ } ++ else ++ { ++ xfct_t fp; ++ ++ scn->data_base = malloc (size); ++ if (scn->data_base == NULL) ++ { ++ __libelf_seterrno (ELF_E_NOMEM); ++ return; ++ } ++ ++ /* Make sure the source is correctly aligned for the conversion ++ function to directly access the data elements. */ ++ char *rawdata_source; ++ /* In order to adapt macro GELF_R_SYM and GELF_R_TYPE on mips64, need to convert ++ relocation info(raw data). Some eu-utils use read-mmap method to map file, so ++ we need to malloc and memcpy raw data to avoid segment fault. After modification, ++ the correct value are saved in the malloced memory not in process address space. */ ++ rawdata_source = malloc (size); ++ if (rawdata_source == NULL) ++ { ++ __libelf_seterrno (ELF_E_NOMEM); ++ return; ++ } ++ ++ /* The copy will be appropriately aligned for direct access. */ ++ memcpy (rawdata_source, scn->rawdata_base, size); ++ ++ /* Get the conversion function. */ ++ fp = __elf_xfctstom[eclass - 1][type]; ++ ++ fp (scn->data_base, rawdata_source, size, 0); ++ ++ if (rawdata_source != scn->rawdata_base) ++ free (rawdata_source); ++ } ++ ++ scn->data_list.data.d.d_buf = scn->data_base; ++ scn->data_list.data.d.d_size = size; ++ scn->data_list.data.d.d_type = type; ++ scn->data_list.data.d.d_off = scn->rawdata.d.d_off; ++ scn->data_list.data.d.d_align = scn->rawdata.d.d_align; ++ scn->data_list.data.d.d_version = scn->rawdata.d.d_version; ++ ++ scn->data_list.data.s = scn; ++ ++ /* In mips64 little-endian, r_info consists of four byte fields(contains ++ three reloc types) and a 32-bit symbol index. In order to adapt ++ GELF_R_SYM and GELF_R_TYPE, need to convert r_info to get correct symbol ++ index and type. */ ++ /* references: ++ https://www.linux-mips.org/pub/linux/mips/doc/ABI/elf64-2.4.pdf ++ Page40 && Page41 */ ++ GElf_Shdr shdr_mem; ++ GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem); ++ if (shdr->sh_type == SHT_REL) ++ { ++ size_t sh_entsize = gelf_fsize (scn->elf, ELF_T_REL, 1, EV_CURRENT); ++ int nentries = shdr->sh_size / sh_entsize; ++ for (int cnt = 0; cnt < nentries; ++cnt) ++ { ++ Elf_Data_Scn *data_scn = (Elf_Data_Scn *) &scn->data_list.data.d; ++ Elf64_Rel *value = &((Elf64_Rel *) data_scn->d.d_buf)[cnt]; ++ Elf64_Xword info = value->r_info; ++ value->r_info = (((info & 0xffffffff) << 32) ++ | ((info >> 56) & 0xff) ++ | ((info >> 40) & 0xff00) ++ | ((info >> 24) & 0xff0000) ++ | ((info >> 8) & 0xff000000)); ++ ((Elf64_Rel *) data_scn->d.d_buf)[cnt] = *value; ++ } ++ } ++ else if (shdr->sh_type == SHT_RELA) ++ { ++ size_t sh_entsize = gelf_fsize (scn->elf, ELF_T_RELA, 1, EV_CURRENT); ++ int nentries = shdr->sh_size / sh_entsize; ++ for (int cnt = 0; cnt < nentries; cnt++) ++ { ++ Elf_Data_Scn *data_scn = (Elf_Data_Scn *) &scn->data_list.data.d; ++ Elf64_Rela *value = &((Elf64_Rela *) data_scn->d.d_buf)[cnt]; ++ Elf64_Xword info = value->r_info; ++ value->r_info = (((info & 0xffffffff) << 32) ++ | ((info >> 56) & 0xff) ++ | ((info >> 40) & 0xff00) ++ | ((info >> 24) & 0xff0000) ++ | ((info >> 8) & 0xff000000)); ++ ((Elf64_Rela *) data_scn->d.d_buf)[cnt] = *value; ++ } ++ } ++} ++ ++/* Convert the data in the current section. */ ++static void + convert_data (Elf_Scn *scn, int eclass, + int data, size_t size, Elf_Type type) + { +@@ -451,8 +564,23 @@ __libelf_set_data_list_rdlock (Elf_Scn * + return; + } + +- /* Convert according to the version and the type. */ +- convert_data (scn, elf->class, ++ GElf_Shdr shdr_mem; ++ GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem); ++ GElf_Ehdr ehdr_mem; ++ GElf_Ehdr *ehdr = gelf_getehdr (scn->elf, &ehdr_mem); ++ if (shdr != NULL && (shdr->sh_type == SHT_RELA || shdr->sh_type == SHT_REL) && ++ scn->elf->class == ELFCLASS64 && ehdr != NULL && ++ ehdr->e_machine == EM_MIPS && ehdr->e_ident[EI_DATA] == ELFDATA2LSB) ++ convert_data_for_mips64el (scn, elf->class, ++ (elf->class == ELFCLASS32 ++ || (offsetof (struct Elf, state.elf32.ehdr) ++ == offsetof (struct Elf, state.elf64.ehdr)) ++ ? elf->state.elf32.ehdr->e_ident[EI_DATA] ++ : elf->state.elf64.ehdr->e_ident[EI_DATA]), ++ scn->rawdata.d.d_size, scn->rawdata.d.d_type); ++ else ++ /* Convert according to the version and the type. */ ++ convert_data (scn, elf->class, + (elf->class == ELFCLASS32 + || (offsetof (struct Elf, state.elf32.ehdr) + == offsetof (struct Elf, state.elf64.ehdr)) +--- a/libelf/elf_update.c ++++ b/libelf/elf_update.c +@@ -228,7 +228,60 @@ elf_update (Elf *elf, Elf_Cmd cmd) + size = -1; + } + else ++ { ++ /* Because we converted the relocation info in mips order when we call elf_getdata.c, ++ so we need to convert the modified data in original order bits before writing the ++ data to the file. */ ++ Elf_Scn *scn = NULL; ++ while ((scn = elf_nextscn (elf, scn)) != NULL) ++ { ++ GElf_Shdr shdr_mem; ++ GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem); ++ GElf_Ehdr ehdr_mem; ++ GElf_Ehdr *ehdr = gelf_getehdr (scn->elf, &ehdr_mem); ++ if (shdr != NULL && (shdr->sh_type == SHT_RELA || shdr->sh_type == SHT_REL) && ++ scn->elf->class == ELFCLASS64 && ++ ehdr != NULL && ehdr->e_machine == EM_MIPS && ehdr->e_ident[EI_DATA] == ELFDATA2LSB) ++ { ++ Elf_Data *d = elf_getdata (scn, NULL); ++ if (shdr->sh_type == SHT_REL) ++ { ++ size_t sh_entsize = gelf_fsize (scn->elf, ELF_T_REL, 1, EV_CURRENT); ++ int nentries = shdr->sh_size / sh_entsize; ++ for (int cnt = 0; cnt < nentries; ++cnt) ++ { ++ Elf_Data_Scn *data_scn = (Elf_Data_Scn *) d; ++ Elf64_Rel *value = &((Elf64_Rel *) data_scn->d.d_buf)[cnt]; ++ Elf64_Xword info = value->r_info; ++ value->r_info = (info >> 32 ++ | ((info << 56) & 0xff00000000000000) ++ | ((info << 40) & 0xff000000000000) ++ | ((info << 24) & 0xff0000000000) ++ | ((info << 8) & 0xff00000000)); ++ ((Elf64_Rel *) data_scn->d.d_buf)[cnt] = *value; ++ } ++ } ++ else if (shdr->sh_type == SHT_RELA) ++ { ++ size_t sh_entsize = gelf_fsize (scn->elf, ELF_T_RELA, 1, EV_CURRENT); ++ int nentries = shdr->sh_size / sh_entsize; ++ for (int cnt = 0; cnt < nentries; cnt++) ++ { ++ Elf_Data_Scn *data_scn = (Elf_Data_Scn *) d; ++ Elf64_Rela *value = &((Elf64_Rela *) data_scn->d.d_buf)[cnt]; ++ Elf64_Xword info = value->r_info; ++ value->r_info = (info >> 32 ++ | ((info << 56) & 0xff00000000000000) ++ | ((info << 40) & 0xff000000000000) ++ | ((info << 24) & 0xff0000000000) ++ | ((info << 8) & 0xff00000000)); ++ ((Elf64_Rela *) data_scn->d.d_buf)[cnt] = *value; ++ } ++ } ++ } ++ } + size = write_file (elf, size, change_bo, shnum); ++ } + } + + out: diff --git a/tools/elfutils/patches/012-backport-mips-support-readelf.patch b/tools/elfutils/patches/012-backport-mips-support-readelf.patch new file mode 100644 index 0000000000..cf2b7c827b --- /dev/null +++ b/tools/elfutils/patches/012-backport-mips-support-readelf.patch @@ -0,0 +1,1079 @@ +-h: support show Flags name +-S: support show mips related section type +-r: support show type of Relocation section +-w: can work and can show correct "strp" contents +-l: support show mips related program header entry type +-d: can show mips related Dynamic type name +-a: support show complete Object attribute section ".gnu.attributes" + +Also add test/run-readelf-reloc.sh file to test new type2/type3 of +src/readelf -r. + +Signed-off-by: Ying Huang +--- + backends/Makefile.am | 2 +- + backends/mips_attrs.c | 140 +++++++++ + backends/mips_init.c | 7 + + backends/mips_symbol.c | 571 +++++++++++++++++++++++++++++++++++++ + libelf/libelfP.h | 1 + + src/readelf.c | 188 +++++++++--- + tests/Makefile.am | 5 +- + tests/run-readelf-reloc.sh | 42 +++ + 8 files changed, 907 insertions(+), 49 deletions(-) + create mode 100644 backends/mips_attrs.c + create mode 100755 tests/run-readelf-reloc.sh + +--- a/backends/Makefile.am ++++ b/backends/Makefile.am +@@ -102,7 +102,7 @@ loongarch_SRCS = loongarch_init.c loonga + + arc_SRCS = arc_init.c arc_symbol.c + +-mips_SRCS = mips_init.c mips_symbol.c ++mips_SRCS = mips_init.c mips_symbol.c mips_attrs.c + + libebl_backends_a_SOURCES = $(i386_SRCS) $(sh_SRCS) $(x86_64_SRCS) \ + $(ia64_SRCS) $(alpha_SRCS) $(arm_SRCS) \ +--- /dev/null ++++ b/backends/mips_attrs.c +@@ -0,0 +1,140 @@ ++/* Object attribute tags for MIPS. ++ Copyright (C) 2024 CIP United Inc. ++ This file is part of elfutils. ++ ++ This file is free software; you can redistribute it and/or modify ++ it under the terms of either ++ ++ * the GNU Lesser General Public License as published by the Free ++ Software Foundation; either version 3 of the License, or (at ++ your option) any later version ++ ++ or ++ ++ * the GNU General Public License as published by the Free ++ Software Foundation; either version 2 of the License, or (at ++ your option) any later version ++ ++ or both in parallel, as here. ++ ++ elfutils is distributed in the hope that it will be useful, but ++ WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ General Public License for more details. ++ ++ You should have received copies of the GNU General Public License and ++ the GNU Lesser General Public License along with this program. If ++ not, see . */ ++ ++#ifdef HAVE_CONFIG_H ++# include ++#endif ++ ++#include ++#include ++ ++#define BACKEND mips_ ++#include "libebl_CPU.h" ++ ++#define KNOWN_VALUES(...) do \ ++ { \ ++ static const char *table[] = { __VA_ARGS__ }; \ ++ if (value < sizeof table / sizeof table[0]) \ ++ *value_name = table[value]; \ ++ } while (0) ++ ++//copy gnu attr tags from binutils-2.34/elfcpp/mips.h ++/* Object attribute tags. */ ++enum ++{ ++ /* 0-3 are generic. */ ++ ++ /* Floating-point ABI used by this object file. */ ++ Tag_GNU_MIPS_ABI_FP = 4, ++ ++ /* MSA ABI used by this object file. */ ++ Tag_GNU_MIPS_ABI_MSA = 8, ++}; ++ ++/* Object attribute values. */ ++enum ++{ ++ /* Values defined for Tag_GNU_MIPS_ABI_MSA. */ ++ ++ /* Not tagged or not using any ABIs affected by the differences. */ ++ Val_GNU_MIPS_ABI_MSA_ANY = 0, ++ ++ /* Using 128-bit MSA. */ ++ Val_GNU_MIPS_ABI_MSA_128 = 1, ++}; ++ ++/* Object attribute values. */ ++enum ++{ ++ /* This is reserved for backward-compatibility with an earlier ++ implementation of the MIPS NaN2008 functionality. */ ++ Val_GNU_MIPS_ABI_FP_NAN2008 = 8, ++}; ++ ++/* copy binutils-2.34/binutils/readelf.c display_mips_gnu_attribute */ ++bool ++mips_check_object_attribute (Ebl *ebl __attribute__ ((unused)), ++ const char *vendor, int tag, uint64_t value, ++ const char **tag_name, const char **value_name) ++{ ++ if (!strcmp (vendor, "gnu")) ++ switch (tag) ++ { ++ case Tag_GNU_MIPS_ABI_FP: ++ *tag_name = "Tag_GNU_MIPS_ABI_FP"; ++ switch (value) ++ { ++ case Val_GNU_MIPS_ABI_FP_ANY: ++ *value_name = "Hard or soft float"; ++ return true; ++ case Val_GNU_MIPS_ABI_FP_DOUBLE: ++ *value_name = "Hard float (double precision)"; ++ return true; ++ case Val_GNU_MIPS_ABI_FP_SINGLE: ++ *value_name = "Hard float (single precision)"; ++ return true; ++ case Val_GNU_MIPS_ABI_FP_SOFT: ++ *value_name = "Soft float"; ++ return true; ++ case Val_GNU_MIPS_ABI_FP_OLD_64: ++ *value_name = "Hard float (MIPS32r2 64-bit FPU 12 callee-saved)"; ++ return true; ++ case Val_GNU_MIPS_ABI_FP_XX: ++ *value_name = "Hard float (32-bit CPU, Any FPU)"; ++ return true; ++ case Val_GNU_MIPS_ABI_FP_64: ++ *value_name = "Hard float (32-bit CPU, 64-bit FPU)"; ++ return true; ++ case Val_GNU_MIPS_ABI_FP_64A: ++ *value_name = "Hard float compat (32-bit CPU, 64-bit FPU)"; ++ return true; ++ case Val_GNU_MIPS_ABI_FP_NAN2008: ++ *value_name = "NaN 2008 compatibility"; ++ return true; ++ default: ++ return true; ++ } ++ return true; ++ case Tag_GNU_MIPS_ABI_MSA: ++ *tag_name = "Tag_GNU_MIPS_ABI_MSA"; ++ switch (value) ++ { ++ case Val_GNU_MIPS_ABI_MSA_ANY: ++ *value_name = "Any MSA or not"; ++ return true; ++ case Val_GNU_MIPS_ABI_MSA_128: ++ *value_name = "128-bit MSA"; ++ return true; ++ default: ++ return true; ++ } ++ return true; ++ } ++ ++ return false; ++} +--- a/backends/mips_init.c ++++ b/backends/mips_init.c +@@ -48,5 +48,12 @@ mips_init (Elf *elf __attribute__ ((unus + /* We handle it. */ + mips_init_reloc (eh); + HOOK (eh, reloc_simple_type); ++ HOOK (eh, section_type_name); ++ HOOK (eh, machine_flag_check); ++ HOOK (eh, machine_flag_name); ++ HOOK (eh, segment_type_name); ++ HOOK (eh, dynamic_tag_check); ++ HOOK (eh, dynamic_tag_name); ++ HOOK (eh, check_object_attribute); + return eh; + } +--- a/backends/mips_symbol.c ++++ b/backends/mips_symbol.c +@@ -61,3 +61,574 @@ mips_reloc_simple_type (Ebl *ebl, int ty + return ELF_T_NUM; + } + } ++ ++/* copy binutils-2.34/binutils/readelf.c get_mips_section_type_name */ ++const char * ++mips_section_type_name (int type, ++ char *buf __attribute__ ((unused)), ++ size_t len __attribute__ ((unused))) ++{ ++ switch (type) ++ { ++ case SHT_MIPS_LIBLIST: ++ return "MIPS_LIBLIST"; ++ case SHT_MIPS_MSYM: ++ return "MIPS_MSYM"; ++ case SHT_MIPS_CONFLICT: ++ return "MIPS_CONFLICT"; ++ case SHT_MIPS_GPTAB: ++ return "MIPS_GPTAB"; ++ case SHT_MIPS_UCODE: ++ return "MIPS_UCODE"; ++ case SHT_MIPS_DEBUG: ++ return "MIPS_DEBUG"; ++ case SHT_MIPS_REGINFO: ++ return "MIPS_REGINFO"; ++ case SHT_MIPS_PACKAGE: ++ return "MIPS_PACKAGE"; ++ case SHT_MIPS_PACKSYM: ++ return "MIPS_PACKSYM"; ++ case SHT_MIPS_RELD: ++ return "MIPS_RELD"; ++ case SHT_MIPS_IFACE: ++ return "MIPS_IFACE"; ++ case SHT_MIPS_CONTENT: ++ return "MIPS_CONTENT"; ++ case SHT_MIPS_OPTIONS: ++ return "MIPS_OPTIONS"; ++ case SHT_MIPS_SHDR: ++ return "MIPS_SHDR"; ++ case SHT_MIPS_FDESC: ++ return "MIPS_FDESC"; ++ case SHT_MIPS_EXTSYM: ++ return "MIPS_EXTSYM"; ++ case SHT_MIPS_DENSE: ++ return "MIPS_DENSE"; ++ case SHT_MIPS_PDESC: ++ return "MIPS_PDESC"; ++ case SHT_MIPS_LOCSYM: ++ return "MIPS_LOCSYM"; ++ case SHT_MIPS_AUXSYM: ++ return "MIPS_AUXSYM"; ++ case SHT_MIPS_OPTSYM: ++ return "MIPS_OPTSYM"; ++ case SHT_MIPS_LOCSTR: ++ return "MIPS_LOCSTR"; ++ case SHT_MIPS_LINE: ++ return "MIPS_LINE"; ++ case SHT_MIPS_RFDESC: ++ return "MIPS_RFDESC"; ++ case SHT_MIPS_DELTASYM: ++ return "MIPS_DELTASYM"; ++ case SHT_MIPS_DELTAINST: ++ return "MIPS_DELTAINST"; ++ case SHT_MIPS_DELTACLASS: ++ return "MIPS_DELTACLASS"; ++ case SHT_MIPS_DWARF: ++ return "MIPS_DWARF"; ++ case SHT_MIPS_DELTADECL: ++ return "MIPS_DELTADECL"; ++ case SHT_MIPS_SYMBOL_LIB: ++ return "MIPS_SYMBOL_LIB"; ++ case SHT_MIPS_EVENTS: ++ return "MIPS_EVENTS"; ++ case SHT_MIPS_TRANSLATE: ++ return "MIPS_TRANSLATE"; ++ case SHT_MIPS_PIXIE: ++ return "MIPS_PIXIE"; ++ case SHT_MIPS_XLATE: ++ return "MIPS_XLATE"; ++ case SHT_MIPS_XLATE_DEBUG: ++ return "MIPS_XLATE_DEBUG"; ++ case SHT_MIPS_WHIRL: ++ return "MIPS_WHIRL"; ++ case SHT_MIPS_EH_REGION: ++ return "MIPS_EH_REGION"; ++ case SHT_MIPS_XLATE_OLD: ++ return "MIPS_XLATE_OLD"; ++ case SHT_MIPS_PDR_EXCEPTION: ++ return "MIPS_PDR_EXCEPTION"; ++ case SHT_MIPS_ABIFLAGS: ++ return "MIPS_ABIFLAGS"; ++ case SHT_MIPS_XHASH: ++ return "MIPS_XHASH"; ++ default: ++ break; ++ } ++ return NULL; ++} ++ ++/* Check whether machine flags are valid. */ ++bool ++mips_machine_flag_check (GElf_Word flags) ++{ ++ if ((flags &~ (EF_MIPS_NOREORDER | ++ EF_MIPS_PIC | ++ EF_MIPS_CPIC | ++ EF_MIPS_UCODE | ++ EF_MIPS_ABI2 | ++ EF_MIPS_OPTIONS_FIRST | ++ EF_MIPS_32BITMODE | ++ EF_MIPS_NAN2008 | ++ EF_MIPS_FP64 | ++ EF_MIPS_ARCH_ASE_MDMX | ++ EF_MIPS_ARCH_ASE_M16 | ++ EF_MIPS_ARCH_ASE_MICROMIPS)) == 0) ++ return false; ++ ++ switch(flags & EF_MIPS_MACH) ++ { ++ case EF_MIPS_MACH_3900: ++ case EF_MIPS_MACH_4010: ++ case EF_MIPS_MACH_4100: ++ case EF_MIPS_MACH_4111: ++ case EF_MIPS_MACH_4120: ++ case EF_MIPS_MACH_4650: ++ case EF_MIPS_MACH_5400: ++ case EF_MIPS_MACH_5500: ++ case EF_MIPS_MACH_5900: ++ case EF_MIPS_MACH_SB1: ++ case EF_MIPS_MACH_9000: ++ case EF_MIPS_MACH_LS2E: ++ case EF_MIPS_MACH_LS2F: ++ case EF_MIPS_MACH_GS464: ++ case EF_MIPS_MACH_GS464E: ++ case EF_MIPS_MACH_GS264E: ++ case EF_MIPS_MACH_OCTEON: ++ case EF_MIPS_MACH_OCTEON2: ++ case EF_MIPS_MACH_OCTEON3: ++ case EF_MIPS_MACH_XLR: ++ case EF_MIPS_MACH_IAMR2: ++ case 0: ++ break; ++ default: ++ return false; ++ } ++ ++ switch ((flags & EF_MIPS_ABI)) ++ { ++ case EF_MIPS_ABI_O32: ++ case EF_MIPS_ABI_O64: ++ case EF_MIPS_ABI_EABI32: ++ case EF_MIPS_ABI_EABI64: ++ case 0: ++ break; ++ default: ++ return false; ++ } ++ ++ switch ((flags & EF_MIPS_ARCH)) ++ { ++ case EF_MIPS_ARCH_1: ++ case EF_MIPS_ARCH_2: ++ case EF_MIPS_ARCH_3: ++ case EF_MIPS_ARCH_4: ++ case EF_MIPS_ARCH_5: ++ case EF_MIPS_ARCH_32: ++ case EF_MIPS_ARCH_32R2: ++ case EF_MIPS_ARCH_32R6: ++ case EF_MIPS_ARCH_64: ++ case EF_MIPS_ARCH_64R2: ++ case EF_MIPS_ARCH_64R6: ++ return true; ++ default: ++ return false; ++ } ++ return false; ++} ++ ++/* copy binutils-2.34/binutils/readelf.c get_machine_flags */ ++const char * ++mips_machine_flag_name (Elf64_Word orig __attribute__ ((unused)), Elf64_Word *flagref) ++{ ++ if (*flagref & EF_MIPS_NOREORDER) ++ { ++ *flagref &= ~((Elf64_Word) EF_MIPS_NOREORDER); ++ return "noreorder"; ++ } ++ ++ if (*flagref & EF_MIPS_PIC) ++ { ++ *flagref &= ~((Elf64_Word) EF_MIPS_PIC); ++ return "pic"; ++ } ++ ++ if (*flagref & EF_MIPS_CPIC) ++ { ++ *flagref &= ~((Elf64_Word) EF_MIPS_CPIC); ++ return "cpic"; ++ } ++ ++ if (*flagref & EF_MIPS_UCODE) ++ { ++ *flagref &= ~((Elf64_Word) EF_MIPS_UCODE); ++ return "ugen_reserved"; ++ } ++ ++ if (*flagref & EF_MIPS_ABI2) ++ { ++ *flagref &= ~((Elf64_Word) EF_MIPS_ABI2); ++ return "abi2"; ++ } ++ ++ if (*flagref & EF_MIPS_OPTIONS_FIRST) ++ { ++ *flagref &= ~((Elf64_Word) EF_MIPS_OPTIONS_FIRST); ++ return "odk first"; ++ } ++ ++ if (*flagref & EF_MIPS_32BITMODE) ++ { ++ *flagref &= ~((Elf64_Word) EF_MIPS_32BITMODE); ++ return "32bitmode"; ++ } ++ ++ if (*flagref & EF_MIPS_NAN2008) ++ { ++ *flagref &= ~((Elf64_Word) EF_MIPS_NAN2008); ++ return "nan2008"; ++ } ++ ++ if (*flagref & EF_MIPS_FP64) ++ { ++ *flagref &= ~((Elf64_Word) EF_MIPS_FP64); ++ return "fp64"; ++ } ++ ++ switch (*flagref & EF_MIPS_MACH) ++ { ++ case EF_MIPS_MACH_3900: ++ *flagref &= ~((Elf64_Word) EF_MIPS_MACH_3900); ++ return "3900"; ++ case EF_MIPS_MACH_4010: ++ *flagref &= ~((Elf64_Word) EF_MIPS_MACH_4010); ++ return "4010"; ++ case EF_MIPS_MACH_4100: ++ *flagref &= ~((Elf64_Word) EF_MIPS_MACH_4100); ++ return "4100"; ++ case EF_MIPS_MACH_4111: ++ *flagref &= ~((Elf64_Word) EF_MIPS_MACH_4111); ++ return "4111"; ++ case EF_MIPS_MACH_4120: ++ *flagref &= ~((Elf64_Word) EF_MIPS_MACH_4120); ++ return "4120"; ++ case EF_MIPS_MACH_4650: ++ *flagref &= ~((Elf64_Word) EF_MIPS_MACH_4650); ++ return "4650"; ++ case EF_MIPS_MACH_5400: ++ *flagref &= ~((Elf64_Word) EF_MIPS_MACH_5400); ++ return "5400"; ++ case EF_MIPS_MACH_5500: ++ *flagref &= ~((Elf64_Word) EF_MIPS_MACH_5500); ++ return "5500"; ++ case EF_MIPS_MACH_5900: ++ *flagref &= ~((Elf64_Word) EF_MIPS_MACH_5900); ++ return "5900"; ++ case EF_MIPS_MACH_SB1: ++ *flagref &= ~((Elf64_Word) EF_MIPS_MACH_SB1); ++ return "sb1"; ++ case EF_MIPS_MACH_9000: ++ *flagref &= ~((Elf64_Word) EF_MIPS_MACH_9000); ++ return "9000"; ++ case EF_MIPS_MACH_LS2E: ++ *flagref &= ~((Elf64_Word) EF_MIPS_MACH_LS2E); ++ return "loongson-2e"; ++ case EF_MIPS_MACH_LS2F: ++ *flagref &= ~((Elf64_Word) EF_MIPS_MACH_LS2F); ++ return "loongson-2f"; ++ case EF_MIPS_MACH_GS464: ++ *flagref &= ~((Elf64_Word) EF_MIPS_MACH_GS464); ++ return "gs464"; ++ case EF_MIPS_MACH_GS464E: ++ *flagref &= ~((Elf64_Word) EF_MIPS_MACH_GS464E); ++ return "gs464e"; ++ case EF_MIPS_MACH_GS264E: ++ *flagref &= ~((Elf64_Word) EF_MIPS_MACH_GS264E); ++ return "gs264e"; ++ case EF_MIPS_MACH_OCTEON: ++ *flagref &= ~((Elf64_Word) EF_MIPS_MACH_OCTEON); ++ return "octeon"; ++ case EF_MIPS_MACH_OCTEON2: ++ *flagref &= ~((Elf64_Word) EF_MIPS_MACH_OCTEON2); ++ return "octeon2"; ++ case EF_MIPS_MACH_OCTEON3: ++ *flagref &= ~((Elf64_Word) EF_MIPS_MACH_OCTEON3); ++ return "octeon3"; ++ case EF_MIPS_MACH_XLR: ++ *flagref &= ~((Elf64_Word) EF_MIPS_MACH_XLR); ++ return "xlr"; ++ case EF_MIPS_MACH_IAMR2: ++ *flagref &= ~((Elf64_Word) EF_MIPS_MACH_IAMR2); ++ return "interaptiv-mr2"; ++ case 0: ++ /* We simply ignore the field in this case to avoid confusion: ++ MIPS ELF does not specify EF_MIPS_MACH, it is a GNU ++ extension. */ ++ break; ++ default: ++ *flagref &= ~((Elf64_Word) EF_MIPS_MACH); ++ return "unknown CPU"; ++ } ++ switch (*flagref & EF_MIPS_ABI) ++ { ++ case EF_MIPS_ABI_O32: ++ *flagref &= ~((Elf64_Word) EF_MIPS_ABI_O32); ++ return "o32"; ++ case EF_MIPS_ABI_O64: ++ *flagref &= ~((Elf64_Word) EF_MIPS_ABI_O64); ++ return "o64"; ++ case EF_MIPS_ABI_EABI32: ++ *flagref &= ~((Elf64_Word) EF_MIPS_ABI_EABI32); ++ return "eabi32"; ++ case EF_MIPS_ABI_EABI64: ++ *flagref &= ~((Elf64_Word) EF_MIPS_ABI_EABI64); ++ return "eabi64"; ++ case 0: ++ /* We simply ignore the field in this case to avoid confusion: ++ MIPS ELF does not specify EF_MIPS_ABI, it is a GNU extension. ++ This means it is likely to be an o32 file, but not for ++ sure. */ ++ break; ++ default: ++ *flagref &= ~((Elf64_Word) EF_MIPS_ABI); ++ return "unknown ABI"; ++ } ++ ++ if (*flagref & EF_MIPS_ARCH_ASE_MDMX) ++ { ++ *flagref &= ~((Elf64_Word) EF_MIPS_ARCH_ASE_MDMX); ++ return "mdmx"; ++ } ++ ++ if (*flagref & EF_MIPS_ARCH_ASE_M16) ++ { ++ *flagref &= ~((Elf64_Word) EF_MIPS_ARCH_ASE_M16); ++ return "mips16"; ++ } ++ ++ if (*flagref & EF_MIPS_ARCH_ASE_MICROMIPS) ++ { ++ *flagref &= ~((Elf64_Word) EF_MIPS_ARCH_ASE_MICROMIPS); ++ return "micromips"; ++ } ++ ++ switch (*flagref & EF_MIPS_ARCH) ++ { ++ case EF_MIPS_ARCH_1: ++ *flagref &= ~((Elf64_Word) EF_MIPS_ARCH_1); ++ return "mips1"; ++ case EF_MIPS_ARCH_2: ++ *flagref &= ~((Elf64_Word) EF_MIPS_ARCH_2); ++ return "mips2"; ++ case EF_MIPS_ARCH_3: ++ *flagref &= ~((Elf64_Word) EF_MIPS_ARCH_3); ++ return "mips3"; ++ case EF_MIPS_ARCH_4: ++ *flagref &= ~((Elf64_Word) EF_MIPS_ARCH_4); ++ return "mips4"; ++ case EF_MIPS_ARCH_5: ++ *flagref &= ~((Elf64_Word) EF_MIPS_ARCH_5); ++ return "mips5"; ++ case EF_MIPS_ARCH_32: ++ *flagref &= ~((Elf64_Word) EF_MIPS_ARCH_32); ++ return "mips32"; ++ case EF_MIPS_ARCH_32R2: ++ *flagref &= ~((Elf64_Word) EF_MIPS_ARCH_32R2); ++ return "mips32r2"; ++ case EF_MIPS_ARCH_32R6: ++ *flagref &= ~((Elf64_Word) EF_MIPS_ARCH_32R6); ++ return "mips32r6"; ++ case EF_MIPS_ARCH_64: ++ *flagref &= ~((Elf64_Word) EF_MIPS_ARCH_64); ++ return "mips64"; ++ case EF_MIPS_ARCH_64R2: ++ *flagref &= ~((Elf64_Word) EF_MIPS_ARCH_64R2); ++ return "mips64r2"; ++ case EF_MIPS_ARCH_64R6: ++ *flagref &= ~((Elf64_Word) EF_MIPS_ARCH_64R6); ++ return "mips64r6"; ++ default: ++ *flagref &= ~((Elf64_Word) EF_MIPS_ARCH); ++ return "unknown ISA"; ++ } ++ return NULL; ++} ++ ++/* copy binutils-2.34/binutils/readelf.c get_mips_segment_type */ ++const char * ++mips_segment_type_name (int segment, char *buf __attribute__ ((unused)), ++ size_t len __attribute__ ((unused))) ++{ ++ switch (segment) ++ { ++ case PT_MIPS_REGINFO: ++ return "REGINFO"; ++ case PT_MIPS_RTPROC: ++ return "RTPROC"; ++ case PT_MIPS_OPTIONS: ++ return "OPTIONS"; ++ case PT_MIPS_ABIFLAGS: ++ return "ABIFLAGS"; ++ default: ++ return NULL; ++ } ++} ++ ++bool ++mips_dynamic_tag_check (int64_t tag) ++{ ++ return ((tag &~ (DT_MIPS_RLD_VERSION ++ | DT_MIPS_TIME_STAMP ++ | DT_MIPS_ICHECKSUM ++ | DT_MIPS_IVERSION ++ | DT_MIPS_FLAGS ++ | DT_MIPS_BASE_ADDRESS ++ | DT_MIPS_MSYM ++ | DT_MIPS_CONFLICT ++ | DT_MIPS_LIBLIST ++ | DT_MIPS_LOCAL_GOTNO ++ | DT_MIPS_CONFLICTNO ++ | DT_MIPS_LIBLISTNO ++ | DT_MIPS_SYMTABNO ++ | DT_MIPS_UNREFEXTNO ++ | DT_MIPS_GOTSYM ++ | DT_MIPS_HIPAGENO ++ | DT_MIPS_RLD_MAP ++ | DT_MIPS_DELTA_CLASS ++ | DT_MIPS_DELTA_CLASS_NO ++ | DT_MIPS_DELTA_INSTANCE ++ | DT_MIPS_DELTA_INSTANCE_NO ++ | DT_MIPS_DELTA_RELOC ++ | DT_MIPS_DELTA_RELOC_NO ++ | DT_MIPS_DELTA_SYM ++ | DT_MIPS_DELTA_SYM_NO ++ | DT_MIPS_DELTA_CLASSSYM ++ | DT_MIPS_DELTA_CLASSSYM_NO ++ | DT_MIPS_CXX_FLAGS ++ | DT_MIPS_PIXIE_INIT ++ | DT_MIPS_SYMBOL_LIB ++ | DT_MIPS_LOCALPAGE_GOTIDX ++ | DT_MIPS_LOCAL_GOTIDX ++ | DT_MIPS_HIDDEN_GOTIDX ++ | DT_MIPS_PROTECTED_GOTIDX ++ | DT_MIPS_OPTIONS ++ | DT_MIPS_INTERFACE ++ | DT_MIPS_DYNSTR_ALIGN ++ | DT_MIPS_INTERFACE_SIZE ++ | DT_MIPS_RLD_TEXT_RESOLVE_ADDR ++ | DT_MIPS_PERF_SUFFIX ++ | DT_MIPS_COMPACT_SIZE ++ | DT_MIPS_GP_VALUE ++ | DT_MIPS_AUX_DYNAMIC ++ | DT_MIPS_PLTGOT ++ | DT_MIPS_RWPLT ++ | DT_MIPS_RLD_MAP_REL ++ | DT_MIPS_XHASH)) == 0); ++} ++ ++/* copy binutils-2.34/binutils/readelf.c get_mips_dynamic_type*/ ++const char * ++mips_dynamic_tag_name (int64_t tag, char *buf __attribute__ ((unused)), ++ size_t len __attribute__ ((unused))) ++{ ++ switch (tag) ++ { ++ case DT_MIPS_RLD_VERSION: ++ return "MIPS_RLD_VERSION"; ++ case DT_MIPS_TIME_STAMP: ++ return "MIPS_TIME_STAMP"; ++ case DT_MIPS_ICHECKSUM: ++ return "MIPS_ICHECKSUM"; ++ case DT_MIPS_IVERSION: ++ return "MIPS_IVERSION"; ++ case DT_MIPS_FLAGS: ++ return "MIPS_FLAGS"; ++ case DT_MIPS_BASE_ADDRESS: ++ return "MIPS_BASE_ADDRESS"; ++ case DT_MIPS_MSYM: ++ return "MIPS_MSYM"; ++ case DT_MIPS_CONFLICT: ++ return "MIPS_CONFLICT"; ++ case DT_MIPS_LIBLIST: ++ return "MIPS_LIBLIST"; ++ case DT_MIPS_LOCAL_GOTNO: ++ return "MIPS_LOCAL_GOTNO"; ++ case DT_MIPS_CONFLICTNO: ++ return "MIPS_CONFLICTNO"; ++ case DT_MIPS_LIBLISTNO: ++ return "MIPS_LIBLISTNO"; ++ case DT_MIPS_SYMTABNO: ++ return "MIPS_SYMTABNO"; ++ case DT_MIPS_UNREFEXTNO: ++ return "MIPS_UNREFEXTNO"; ++ case DT_MIPS_GOTSYM: ++ return "MIPS_GOTSYM"; ++ case DT_MIPS_HIPAGENO: ++ return "MIPS_HIPAGENO"; ++ case DT_MIPS_RLD_MAP: ++ return "MIPS_RLD_MAP"; ++ case DT_MIPS_RLD_MAP_REL: ++ return "MIPS_RLD_MAP_REL"; ++ case DT_MIPS_DELTA_CLASS: ++ return "MIPS_DELTA_CLASS"; ++ case DT_MIPS_DELTA_CLASS_NO: ++ return "MIPS_DELTA_CLASS_NO"; ++ case DT_MIPS_DELTA_INSTANCE: ++ return "MIPS_DELTA_INSTANCE"; ++ case DT_MIPS_DELTA_INSTANCE_NO: ++ return "MIPS_DELTA_INSTANCE_NO"; ++ case DT_MIPS_DELTA_RELOC: ++ return "MIPS_DELTA_RELOC"; ++ case DT_MIPS_DELTA_RELOC_NO: ++ return "MIPS_DELTA_RELOC_NO"; ++ case DT_MIPS_DELTA_SYM: ++ return "MIPS_DELTA_SYM"; ++ case DT_MIPS_DELTA_SYM_NO: ++ return "MIPS_DELTA_SYM_NO"; ++ case DT_MIPS_DELTA_CLASSSYM: ++ return "MIPS_DELTA_CLASSSYM"; ++ case DT_MIPS_DELTA_CLASSSYM_NO: ++ return "MIPS_DELTA_CLASSSYM_NO"; ++ case DT_MIPS_CXX_FLAGS: ++ return "MIPS_CXX_FLAGS"; ++ case DT_MIPS_PIXIE_INIT: ++ return "MIPS_PIXIE_INIT"; ++ case DT_MIPS_SYMBOL_LIB: ++ return "MIPS_SYMBOL_LIB"; ++ case DT_MIPS_LOCALPAGE_GOTIDX: ++ return "MIPS_LOCALPAGE_GOTIDX"; ++ case DT_MIPS_LOCAL_GOTIDX: ++ return "MIPS_LOCAL_GOTIDX"; ++ case DT_MIPS_HIDDEN_GOTIDX: ++ return "MIPS_HIDDEN_GOTIDX"; ++ case DT_MIPS_PROTECTED_GOTIDX: ++ return "MIPS_PROTECTED_GOTIDX"; ++ case DT_MIPS_OPTIONS: ++ return "MIPS_OPTIONS"; ++ case DT_MIPS_INTERFACE: ++ return "MIPS_INTERFACE"; ++ case DT_MIPS_DYNSTR_ALIGN: ++ return "MIPS_DYNSTR_ALIGN"; ++ case DT_MIPS_INTERFACE_SIZE: ++ return "MIPS_INTERFACE_SIZE"; ++ case DT_MIPS_RLD_TEXT_RESOLVE_ADDR: ++ return "MIPS_RLD_TEXT_RESOLVE_ADDR"; ++ case DT_MIPS_PERF_SUFFIX: ++ return "MIPS_PERF_SUFFIX"; ++ case DT_MIPS_COMPACT_SIZE: ++ return "MIPS_COMPACT_SIZE"; ++ case DT_MIPS_GP_VALUE: ++ return "MIPS_GP_VALUE"; ++ case DT_MIPS_AUX_DYNAMIC: ++ return "MIPS_AUX_DYNAMIC"; ++ case DT_MIPS_PLTGOT: ++ return "MIPS_PLTGOT"; ++ case DT_MIPS_RWPLT: ++ return "MIPS_RWPLT"; ++ case DT_MIPS_XHASH: ++ return "MIPS_XHASH"; ++ default: ++ return NULL; ++ } ++ return NULL; ++} +--- a/libelf/libelfP.h ++++ b/libelf/libelfP.h +@@ -620,4 +620,5 @@ extern void __libelf_reset_rawdata (Elf_ + #define ELF64_MIPS_R_TYPE1(i) ((i) & 0xff) + #define ELF64_MIPS_R_TYPE2(i) (((i) >> 8) & 0xff) + #define ELF64_MIPS_R_TYPE3(i) (((i) >> 16) & 0xff) ++#define is_debug_section_type(type) (type == SHT_PROGBITS || type == SHT_MIPS_DWARF) + #endif /* libelfP.h */ +--- a/src/readelf.c ++++ b/src/readelf.c +@@ -2219,17 +2219,41 @@ handle_relocs_rel (Ebl *ebl, GElf_Ehdr * + (long int) GELF_R_SYM (rel->r_info)); + } + else if (GELF_ST_TYPE (sym->st_info) != STT_SECTION) +- printf (" %#0*" PRIx64 " %-20s %#0*" PRIx64 " %s\n", +- class == ELFCLASS32 ? 10 : 18, rel->r_offset, +- likely (ebl_reloc_type_check (ebl, +- GELF_R_TYPE (rel->r_info))) +- /* Avoid the leading R_ which isn't carrying any +- information. */ +- ? ebl_reloc_type_name (ebl, GELF_R_TYPE (rel->r_info), +- buf, sizeof (buf)) + 2 +- : _(""), +- class == ELFCLASS32 ? 10 : 18, sym->st_value, +- elf_strptr (ebl->elf, symshdr->sh_link, sym->st_name)); ++ { ++ unsigned long inf = rel->r_info; ++ printf (" %#0*" PRIx64 " %-20s %#0*" PRIx64 " %s\n", ++ class == ELFCLASS32 ? 10 : 18, rel->r_offset, ++ likely (ebl_reloc_type_check (ebl, ++ GELF_R_TYPE (rel->r_info))) ++ /* Avoid the leading R_ which isn't carrying any ++ information. */ ++ ? ebl_reloc_type_name (ebl, GELF_R_TYPE (rel->r_info), ++ buf, sizeof (buf)) + 2 ++ : _(""), ++ class == ELFCLASS32 ? 10 : 18, sym->st_value, ++ elf_strptr (ebl->elf, symshdr->sh_link, sym->st_name)); ++ ++ /* copy binutils-2.34/binutils/readelf.c dump_relocations+1753 */ ++ if(ebl->elf->class == ELFCLASS64 && ebl->elf->state.elf64.ehdr->e_machine == EM_MIPS) ++ { ++ unsigned int type2 = ELF64_MIPS_R_TYPE2 (inf); ++ unsigned int type3 = ELF64_MIPS_R_TYPE3 (inf); ++ const char * rtype2 = ebl_reloc_type_name (ebl, type2, buf, sizeof (buf)) + 2; ++ const char * rtype3 = ebl_reloc_type_name (ebl, type3, buf, sizeof (buf)) + 2; ++ printf(" Type2: "); ++ if (rtype2 == NULL) ++ printf (_("unrecognized: %lx"), (unsigned long) type2 & 0xffffffff); ++ else ++ printf ("%s", rtype2); ++ ++ printf ("\n Type3: "); ++ if (rtype3 == NULL) ++ printf (_("unrecognized: %lx"), (unsigned long) type3 & 0xffffffff); ++ else ++ printf ("%s", rtype3); ++ printf("\n"); ++ } ++ } + else + { + /* This is a relocation against a STT_SECTION symbol. */ +@@ -2253,16 +2277,40 @@ handle_relocs_rel (Ebl *ebl, GElf_Ehdr * + (long int) (sym->st_shndx == SHN_XINDEX + ? xndx : sym->st_shndx)); + else +- printf (" %#0*" PRIx64 " %-20s %#0*" PRIx64 " %s\n", +- class == ELFCLASS32 ? 10 : 18, rel->r_offset, +- ebl_reloc_type_check (ebl, GELF_R_TYPE (rel->r_info)) +- /* Avoid the leading R_ which isn't carrying any +- information. */ +- ? ebl_reloc_type_name (ebl, GELF_R_TYPE (rel->r_info), +- buf, sizeof (buf)) + 2 +- : _(""), +- class == ELFCLASS32 ? 10 : 18, sym->st_value, +- elf_strptr (ebl->elf, shstrndx, secshdr->sh_name)); ++ { ++ unsigned long inf = rel->r_info; ++ printf (" %#0*" PRIx64 " %-20s %#0*" PRIx64 " %s\n", ++ class == ELFCLASS32 ? 10 : 18, rel->r_offset, ++ ebl_reloc_type_check (ebl, GELF_R_TYPE (rel->r_info)) ++ /* Avoid the leading R_ which isn't carrying any ++ information. */ ++ ? ebl_reloc_type_name (ebl, GELF_R_TYPE (rel->r_info), ++ buf, sizeof (buf)) + 2 ++ : _(""), ++ class == ELFCLASS32 ? 10 : 18, sym->st_value, ++ elf_strptr (ebl->elf, shstrndx, secshdr->sh_name)); ++ ++ /* copy binutils-2.34/binutils/readelf.c dump_relocations+1753 */ ++ if(ebl->elf->class == ELFCLASS64 && ebl->elf->state.elf64.ehdr->e_machine == EM_MIPS) ++ { ++ unsigned int type2 = ELF64_MIPS_R_TYPE2 (inf); ++ unsigned int type3 = ELF64_MIPS_R_TYPE3 (inf); ++ const char * rtype2 = ebl_reloc_type_name (ebl, type2, buf, sizeof (buf)) + 2; ++ const char * rtype3 = ebl_reloc_type_name (ebl, type3, buf, sizeof (buf)) + 2; ++ printf(" Type2: "); ++ if (rtype2 == NULL) ++ printf (_("unrecognized: %lx"), (unsigned long) type2 & 0xffffffff); ++ else ++ printf ("%s", rtype2); ++ ++ printf ("\n Type3: "); ++ if (rtype3 == NULL) ++ printf (_("unrecognized: %lx"), (unsigned long) type3 & 0xffffffff); ++ else ++ printf ("%s", rtype3); ++ printf("\n"); ++ } ++ } + } + } + } +@@ -2410,19 +2458,43 @@ handle_relocs_rela (Ebl *ebl, GElf_Ehdr + (long int) GELF_R_SYM (rel->r_info)); + } + else if (GELF_ST_TYPE (sym->st_info) != STT_SECTION) +- printf ("\ ++ { ++ unsigned long inf = rel->r_info; ++ printf ("\ + %#0*" PRIx64 " %-15s %#0*" PRIx64 " %+6" PRId64 " %s\n", +- class == ELFCLASS32 ? 10 : 18, rel->r_offset, +- likely (ebl_reloc_type_check (ebl, +- GELF_R_TYPE (rel->r_info))) +- /* Avoid the leading R_ which isn't carrying any +- information. */ +- ? ebl_reloc_type_name (ebl, GELF_R_TYPE (rel->r_info), +- buf, sizeof (buf)) + 2 +- : _(""), +- class == ELFCLASS32 ? 10 : 18, sym->st_value, +- rel->r_addend, +- elf_strptr (ebl->elf, symshdr->sh_link, sym->st_name)); ++ class == ELFCLASS32 ? 10 : 18, rel->r_offset, ++ likely (ebl_reloc_type_check (ebl, ++ GELF_R_TYPE (rel->r_info))) ++ /* Avoid the leading R_ which isn't carrying any ++ information. */ ++ ? ebl_reloc_type_name (ebl, GELF_R_TYPE (rel->r_info), ++ buf, sizeof (buf)) + 2 ++ : _(""), ++ class == ELFCLASS32 ? 10 : 18, sym->st_value, ++ rel->r_addend, ++ elf_strptr (ebl->elf, symshdr->sh_link, sym->st_name)); ++ ++ /* copy binutils-2.34/binutils/readelf.c dump_relocations+1753 */ ++ if(ebl->elf->class == ELFCLASS64 && ebl->elf->state.elf64.ehdr->e_machine == EM_MIPS) ++ { ++ unsigned int type2 = ELF64_MIPS_R_TYPE2 (inf); ++ unsigned int type3 = ELF64_MIPS_R_TYPE3 (inf); ++ const char * rtype2 = ebl_reloc_type_name (ebl, type2, buf, sizeof (buf)) + 2; ++ const char * rtype3 = ebl_reloc_type_name (ebl, type3, buf, sizeof (buf)) + 2; ++ printf(" Type2: "); ++ if (rtype2 == NULL) ++ printf (_("unrecognized: %lx"), (unsigned long) type2 & 0xffffffff); ++ else ++ printf ("%s", rtype2); ++ ++ printf ("\n Type3: "); ++ if (rtype3 == NULL) ++ printf (_("unrecognized: %lx"), (unsigned long) type3 & 0xffffffff); ++ else ++ printf ("%s", rtype3); ++ printf("\n"); ++ } ++ } + else + { + /* This is a relocation against a STT_SECTION symbol. */ +@@ -2446,18 +2518,42 @@ handle_relocs_rela (Ebl *ebl, GElf_Ehdr + (long int) (sym->st_shndx == SHN_XINDEX + ? xndx : sym->st_shndx)); + else +- printf ("\ ++ { ++ unsigned long inf = rel->r_info; ++ printf ("\ + %#0*" PRIx64 " %-15s %#0*" PRIx64 " %+6" PRId64 " %s\n", +- class == ELFCLASS32 ? 10 : 18, rel->r_offset, +- ebl_reloc_type_check (ebl, GELF_R_TYPE (rel->r_info)) +- /* Avoid the leading R_ which isn't carrying any +- information. */ +- ? ebl_reloc_type_name (ebl, GELF_R_TYPE (rel->r_info), +- buf, sizeof (buf)) + 2 +- : _(""), +- class == ELFCLASS32 ? 10 : 18, sym->st_value, +- rel->r_addend, +- elf_strptr (ebl->elf, shstrndx, secshdr->sh_name)); ++ class == ELFCLASS32 ? 10 : 18, rel->r_offset, ++ ebl_reloc_type_check (ebl, GELF_R_TYPE (rel->r_info)) ++ /* Avoid the leading R_ which isn't carrying any ++ information. */ ++ ? ebl_reloc_type_name (ebl, GELF_R_TYPE (rel->r_info), ++ buf, sizeof (buf)) + 2 ++ : _(""), ++ class == ELFCLASS32 ? 10 : 18, sym->st_value, ++ rel->r_addend, ++ elf_strptr (ebl->elf, shstrndx, secshdr->sh_name)); ++ ++ /* copy binutils-2.34/binutils/readelf.c dump_relocations+1753 */ ++ if(ebl->elf->class == ELFCLASS64 && ebl->elf->state.elf64.ehdr->e_machine == EM_MIPS) ++ { ++ unsigned int type2 = ELF64_MIPS_R_TYPE2 (inf); ++ unsigned int type3 = ELF64_MIPS_R_TYPE3 (inf); ++ const char * rtype2 = ebl_reloc_type_name (ebl, type2, buf, sizeof (buf)) + 2; ++ const char * rtype3 = ebl_reloc_type_name (ebl, type3, buf, sizeof (buf)) + 2; ++ printf(" Type2: "); ++ if (rtype2 == NULL) ++ printf (_("unrecognized: %-7lx"), (unsigned long) type2 & 0xffffffff); ++ else ++ printf ("%s", rtype2); ++ ++ printf ("\n Type3: "); ++ if (rtype3 == NULL) ++ printf (_("unrecognized: %lx"), (unsigned long) type3 & 0xffffffff); ++ else ++ printf ("%s", rtype3); ++ printf("\n"); ++ } ++ } + } + } + } +@@ -12043,7 +12139,7 @@ print_debug (Dwfl_Module *dwflmod, Ebl * + GElf_Shdr shdr_mem; + GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem); + +- if (shdr != NULL && shdr->sh_type == SHT_PROGBITS) ++ if (shdr != NULL && is_debug_section_type(shdr->sh_type)) + { + const char *name = elf_strptr (ebl->elf, shstrndx, + shdr->sh_name); +@@ -12073,7 +12169,7 @@ print_debug (Dwfl_Module *dwflmod, Ebl * + GElf_Shdr shdr_mem; + GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem); + +- if (shdr != NULL && shdr->sh_type == SHT_PROGBITS) ++ if (shdr != NULL && is_debug_section_type(shdr->sh_type)) + { + static const struct + { +--- a/tests/Makefile.am ++++ b/tests/Makefile.am +@@ -214,7 +214,7 @@ TESTS = run-arextract.sh run-arsymtest.s + run-nvidia-extended-linemap-libdw.sh run-nvidia-extended-linemap-readelf.sh \ + run-readelf-dw-form-indirect.sh run-strip-largealign.sh \ + run-readelf-Dd.sh run-dwfl-core-noncontig.sh run-cu-dwp-section-info.sh \ +- run-declfiles.sh ++ run-declfiles.sh run-readelf-reloc.sh + + if !BIARCH + export ELFUTILS_DISABLE_BIARCH = 1 +@@ -646,7 +646,8 @@ EXTRA_DIST = run-arextract.sh run-arsymt + testfile-dwp-5-cu-index-overflow.dwp.bz2 \ + testfile-dwp-4-cu-index-overflow.bz2 \ + testfile-dwp-4-cu-index-overflow.dwp.bz2 \ +- testfile-dwp-cu-index-overflow.source ++ testfile-dwp-cu-index-overflow.source \ ++ run-readelf-reloc.sh + + + if USE_VALGRIND +--- /dev/null ++++ b/tests/run-readelf-reloc.sh +@@ -0,0 +1,42 @@ ++#! /bin/bash ++# Copyright (C) 2024 CIP United Inc. ++# This file is part of elfutils. ++# ++# This file is free software; you can redistribute it and/or modify ++# it under the terms of the GNU General Public License as published by ++# the Free Software Foundation; either version 3 of the License, or ++# (at your option) any later version. ++# ++# elfutils is distributed in the hope that it will be useful, but ++# WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++# GNU General Public License for more details. ++# ++# You should have received a copy of the GNU General Public License ++# along with this program. If not, see . ++ ++. $srcdir/test-subr.sh ++ ++tempfiles test-readelf-h.txt test-readelf-reloc.txt ++testrun ${abs_top_builddir}/src/readelf -h ${abs_top_builddir}/src/strip.o > test-readelf-h.txt ++machine=`cat test-readelf-h.txt | grep Machine` ++class=`cat test-readelf-h.txt | grep Class` ++endian=`cat test-readelf-h.txt | grep Data` ++if [[ "$machine" == *MIPS* && "$class" == *ELF64 && "$endian" == *little* ]]; then ++testrun ${abs_top_builddir}/src/readelf -r ${abs_top_builddir}/src/strip.o | head -n 12 | tail -n 10 > test-readelf-reloc.txt ++ ++testrun_compare cat test-readelf-reloc.txt << EOF ++ Offset Type Value Addend Name ++ 0x0000000000000008 MIPS_GPREL16 000000000000000000 +0 .text ++ Type2: MIPS_SUB ++ Type3: MIPS_HI16 ++ 0x0000000000000010 MIPS_GPREL16 000000000000000000 +0 .text ++ Type2: MIPS_SUB ++ Type3: MIPS_LO16 ++ 0x0000000000000014 MIPS_CALL16 000000000000000000 +0 gelf_getehdr ++ Type2: MIPS_NONE ++ Type3: MIPS_NONE ++EOF ++fi ++ ++exit 0 diff --git a/tools/elfutils/patches/013-backport-mips-support-elflint.patch b/tools/elfutils/patches/013-backport-mips-support-elflint.patch new file mode 100644 index 0000000000..906a3bf0f2 --- /dev/null +++ b/tools/elfutils/patches/013-backport-mips-support-elflint.patch @@ -0,0 +1,156 @@ +The errors were: +$ src/elflint --gnu src/nm +section [ 2] '.MIPS.options' contains unknown flag(s) 0x8000000 +section [ 7] '.dynsym': symbol 165 (_DYNAMIC_LINKING): non-local section symbol +section [24] '.got' contains invalid processor-specific flag(s) 0x10000000 +section [25] '.sdata' contains invalid processor-specific flag(s) 0x10000000 +section [29] '.debug_aranges' has wrong type: expected PROGBITS, is MIPS_DWARF +section [30] '.debug_info' has wrong type: expected PROGBITS, is MIPS_DWARF +section [31] '.debug_abbrev' has wrong type: expected PROGBITS, is MIPS_DWARF +section [32] '.debug_line' has wrong type: expected PROGBITS, is MIPS_DWARF +section [33] '.debug_frame' has wrong type: expected PROGBITS, is MIPS_DWARF +section [34] '.debug_str' has wrong type: expected PROGBITS, is MIPS_DWARF +section [35] '.debug_loc' has wrong type: expected PROGBITS, is MIPS_DWARF +section [36] '.debug_ranges' has wrong type: expected PROGBITS, is MIPS_DWARF +section [38] '.symtab': symbol 785 (_gp): st_value out of bounds +section [38] '.symtab': symbol 910 (_fbss): st_value out of bounds +section [38] '.symtab': symbol 1051 (_DYNAMIC_LINKING): non-local section symbol + +After fixing: +$ src/elflint --gnu src/nm +No errors + +Signed-off-by: Ying Huang +--- + backends/mips_init.c | 3 +++ + backends/mips_symbol.c | 37 +++++++++++++++++++++++++++++++++++++ + src/elflint.c | 26 +++++++++++++++++++++----- + 3 files changed, 61 insertions(+), 5 deletions(-) + +--- a/backends/mips_init.c ++++ b/backends/mips_init.c +@@ -51,9 +51,12 @@ mips_init (Elf *elf __attribute__ ((unus + HOOK (eh, section_type_name); + HOOK (eh, machine_flag_check); + HOOK (eh, machine_flag_name); ++ HOOK (eh, machine_section_flag_check); + HOOK (eh, segment_type_name); + HOOK (eh, dynamic_tag_check); + HOOK (eh, dynamic_tag_name); + HOOK (eh, check_object_attribute); ++ HOOK (eh, check_special_symbol); ++ HOOK (eh, check_reloc_target_type); + return eh; + } +--- a/backends/mips_symbol.c ++++ b/backends/mips_symbol.c +@@ -158,6 +158,43 @@ mips_section_type_name (int type, + return NULL; + } + ++bool ++mips_check_reloc_target_type (Ebl *ebl __attribute__ ((unused)), Elf64_Word sh_type) ++{ ++ return (sh_type == SHT_MIPS_DWARF); ++} ++ ++/* Check whether given symbol's st_value and st_size are OK despite failing ++ normal checks. */ ++bool ++mips_check_special_symbol (Elf *elf, ++ const GElf_Sym *sym __attribute__ ((unused)), ++ const char *name __attribute__ ((unused)), ++ const GElf_Shdr *destshdr) ++{ ++ size_t shstrndx; ++ if (elf_getshdrstrndx (elf, &shstrndx) != 0) ++ return false; ++ const char *sname = elf_strptr (elf, shstrndx, destshdr->sh_name); ++ if (sname == NULL) ++ return false; ++ return (strcmp (sname, ".got") == 0 || strcmp (sname, ".bss") == 0); ++} ++ ++/* Check whether SHF_MASKPROC flags are valid. */ ++bool ++mips_machine_section_flag_check (GElf_Xword sh_flags) ++{ ++ return ((sh_flags &~ (SHF_MIPS_GPREL | ++ SHF_MIPS_MERGE | ++ SHF_MIPS_ADDR | ++ SHF_MIPS_STRINGS | ++ SHF_MIPS_NOSTRIP | ++ SHF_MIPS_LOCAL | ++ SHF_MIPS_NAMES | ++ SHF_MIPS_NODUPE)) == 0); ++} ++ + /* Check whether machine flags are valid. */ + bool + mips_machine_flag_check (GElf_Word flags) +--- a/src/elflint.c ++++ b/src/elflint.c +@@ -936,7 +936,9 @@ section [%2d] '%s': symbol %zu (%s): non + } + + if (GELF_ST_TYPE (sym->st_info) == STT_SECTION +- && GELF_ST_BIND (sym->st_info) != STB_LOCAL) ++ && GELF_ST_BIND (sym->st_info) != STB_LOCAL ++ && ehdr->e_machine != EM_MIPS ++ && strcmp (name, "_DYNAMIC_LINKING") != 0) + ERROR (_("\ + section [%2d] '%s': symbol %zu (%s): non-local section symbol\n"), + idx, section_name (ebl, idx), cnt, name); +@@ -3828,6 +3830,10 @@ cannot get section header for section [% + && ebl_bss_plt_p (ebl)) + good_type = SHT_NOBITS; + ++ if (ehdr->e_machine == EM_MIPS ++ && (strstr(special_sections[s].name, ".debug") != NULL)) ++ good_type = SHT_MIPS_DWARF; ++ + /* In a debuginfo file, any normal section can be SHT_NOBITS. + This is only invalid for DWARF sections and .shstrtab. */ + if (shdr->sh_type != good_type +@@ -3988,12 +3994,21 @@ section [%2zu] '%s': size not multiple o + ERROR (_("section [%2zu] '%s'" + " contains invalid processor-specific flag(s)" + " %#" PRIx64 "\n"), +- cnt, section_name (ebl, cnt), sh_flags & SHF_MASKPROC); ++ cnt, section_name (ebl, cnt), sh_flags & SHF_MASKPROC); + sh_flags &= ~(GElf_Xword) SHF_MASKPROC; + } + if (sh_flags & SHF_MASKOS) +- if (gnuld) +- sh_flags &= ~(GElf_Xword) SHF_GNU_RETAIN; ++ { ++ if (gnuld) ++ sh_flags &= ~(GElf_Xword) SHF_GNU_RETAIN; ++ if (!ebl_machine_section_flag_check (ebl, ++ sh_flags & SHF_MASKOS)) ++ ERROR (_("section [%2zu] '%s'" ++ " contains invalid os-specific flag(s)" ++ " %#" PRIx64 "\n"), ++ cnt, section_name (ebl, cnt), sh_flags & SHF_MASKOS); ++ sh_flags &= ~(GElf_Xword) SHF_MASKOS; ++ } + if (sh_flags != 0) + ERROR (_("section [%2zu] '%s' contains unknown flag(s)" + " %#" PRIx64 "\n"), +@@ -4059,6 +4074,7 @@ section [%2zu] '%s': merge flag set but + switch (shdr->sh_type) + { + case SHT_PROGBITS: ++ case SHT_MIPS_DWARF: + break; + + case SHT_NOBITS: +@@ -4716,7 +4732,7 @@ program header offset in ELF header and + if (shdr != NULL + && ((is_debuginfo && shdr->sh_type == SHT_NOBITS) + || (! is_debuginfo +- && (shdr->sh_type == SHT_PROGBITS ++ && (is_debug_section_type(shdr->sh_type) + || shdr->sh_type == SHT_X86_64_UNWIND))) + && elf_strptr (ebl->elf, shstrndx, shdr->sh_name) != NULL + && ! strcmp (".eh_frame_hdr", diff --git a/tools/elfutils/patches/014-backport-mips-support-stack.patch b/tools/elfutils/patches/014-backport-mips-support-stack.patch new file mode 100644 index 0000000000..9907a30264 --- /dev/null +++ b/tools/elfutils/patches/014-backport-mips-support-stack.patch @@ -0,0 +1,273 @@ +From f2acb06970522a9563d82490f2f1b8fc0bb5b720 Mon Sep 17 00:00:00 2001 +From: Ying Huang +Date: Tue, 5 Mar 2024 17:51:21 +0800 +Subject: [PATCH] stack: Fix stack unwind failure on mips + +Add abi_cfi, set_initial_registers_tid, unwind on mips. + + * backends/Makefile.am (mips_SRCS): Add mips_initreg.c, + mips_cfi.c and mips_unwind.c. + * backends/mips_init.c (mips_init): HOOK abi_cfi, unwind and + set_initial_registers_tid. Set frame_nregs to 71. + * backends/mips_cfi.c: New file. + * backends/mips_initreg.c: Likewise. + * backends/mips_unwind.c: Likewise. + +Signed-off-by: Ying Huang +--- + backends/Makefile.am | 3 +- + backends/mips_cfi.c | 68 +++++++++++++++++++++++++++++++++ + backends/mips_init.c | 4 ++ + backends/mips_initreg.c | 61 ++++++++++++++++++++++++++++++ + backends/mips_unwind.c | 84 +++++++++++++++++++++++++++++++++++++++++ + 5 files changed, 219 insertions(+), 1 deletion(-) + create mode 100644 backends/mips_cfi.c + create mode 100644 backends/mips_initreg.c + create mode 100644 backends/mips_unwind.c + +--- a/backends/Makefile.am ++++ b/backends/Makefile.am +@@ -102,7 +102,8 @@ loongarch_SRCS = loongarch_init.c loonga + + arc_SRCS = arc_init.c arc_symbol.c + +-mips_SRCS = mips_init.c mips_symbol.c mips_attrs.c ++mips_SRCS = mips_init.c mips_symbol.c mips_attrs.c mips_initreg.c \ ++ mips_cfi.c mips_unwind.c + + libebl_backends_a_SOURCES = $(i386_SRCS) $(sh_SRCS) $(x86_64_SRCS) \ + $(ia64_SRCS) $(alpha_SRCS) $(arm_SRCS) \ +--- /dev/null ++++ b/backends/mips_cfi.c +@@ -0,0 +1,68 @@ ++/* MIPS ABI-specified defaults for DWARF CFI. ++ Copyright (C) 2009 Red Hat, Inc. ++ Copyright (C) 2024 CIP United Inc. ++ This file is part of elfutils. ++ ++ This file is free software; you can redistribute it and/or modify ++ it under the terms of either ++ ++ * the GNU Lesser General Public License as published by the Free ++ Software Foundation; either version 3 of the License, or (at ++ your option) any later version ++ ++ or ++ ++ * the GNU General Public License as published by the Free ++ Software Foundation; either version 2 of the License, or (at ++ your option) any later version ++ ++ or both in parallel, as here. ++ ++ elfutils is distributed in the hope that it will be useful, but ++ WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ General Public License for more details. ++ ++ You should have received copies of the GNU General Public License and ++ the GNU Lesser General Public License along with this program. If ++ not, see . */ ++ ++#ifdef HAVE_CONFIG_H ++# include ++#endif ++ ++#include ++ ++#define BACKEND mips_ ++#include "libebl_CPU.h" ++ ++int ++mips_abi_cfi (Ebl *ebl __attribute__ ((unused)), Dwarf_CIE *abi_info) ++{ ++ static const uint8_t abi_cfi[] = ++ { ++ DW_CFA_def_cfa, ULEB128_7 (31), ULEB128_7 (0), ++ /* Callee-saved regs. */ ++ DW_CFA_same_value, ULEB128_7 (16), /* s0 */ ++ DW_CFA_same_value, ULEB128_7 (17), /* s1 */ ++ DW_CFA_same_value, ULEB128_7 (18), /* s2 */ ++ DW_CFA_same_value, ULEB128_7 (19), /* s3 */ ++ DW_CFA_same_value, ULEB128_7 (20), /* s4 */ ++ DW_CFA_same_value, ULEB128_7 (21), /* s5 */ ++ DW_CFA_same_value, ULEB128_7 (22), /* s6 */ ++ DW_CFA_same_value, ULEB128_7 (23), /* s7 */ ++ DW_CFA_same_value, ULEB128_7 (28), /* gp */ ++ DW_CFA_same_value, ULEB128_7 (29), /* sp */ ++ DW_CFA_same_value, ULEB128_7 (30), /* fp */ ++ ++ DW_CFA_val_offset, ULEB128_7 (29), ULEB128_7 (0), ++ }; ++ ++ abi_info->initial_instructions = abi_cfi; ++ abi_info->initial_instructions_end = &abi_cfi[sizeof abi_cfi]; ++ abi_info->data_alignment_factor = 8; ++ ++ abi_info->return_address_register = 31; /* %ra */ ++ ++ return 0; ++} +--- a/backends/mips_init.c ++++ b/backends/mips_init.c +@@ -58,5 +58,9 @@ mips_init (Elf *elf __attribute__ ((unus + HOOK (eh, check_object_attribute); + HOOK (eh, check_special_symbol); + HOOK (eh, check_reloc_target_type); ++ HOOK (eh, set_initial_registers_tid); ++ HOOK (eh, abi_cfi); ++ HOOK (eh, unwind); ++ eh->frame_nregs = 71; + return eh; + } +--- /dev/null ++++ b/backends/mips_initreg.c +@@ -0,0 +1,61 @@ ++/* Fetch live process registers from TID. ++ Copyright (C) 2024 CIP United Inc. ++ This file is part of elfutils. ++ ++ This file is free software; you can redistribute it and/or modify ++ it under the terms of either ++ ++ * the GNU Lesser General Public License as published by the Free ++ Software Foundation; either version 3 of the License, or (at ++ your option) any later version ++ ++ or ++ ++ * the GNU General Public License as published by the Free ++ Software Foundation; either version 2 of the License, or (at ++ your option) any later version ++ ++ or both in parallel, as here. ++ ++ elfutils is distributed in the hope that it will be useful, but ++ WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ General Public License for more details. ++ ++ You should have received copies of the GNU General Public License and ++ the GNU Lesser General Public License along with this program. If ++ not, see . */ ++ ++#ifdef HAVE_CONFIG_H ++# include ++#endif ++ ++#include ++#if (defined(mips) || defined(__mips) || defined(__mips__) || defined(MIPS) || defined(__MIPS__)) && defined(__linux__) ++# include ++# include ++#include ++#endif ++ ++#define BACKEND mips_ ++#include "libebl_CPU.h" ++ ++ ++bool ++mips_set_initial_registers_tid (pid_t tid __attribute__ ((unused)), ++ ebl_tid_registers_t *setfunc __attribute__ ((unused)), ++ void *arg __attribute__ ((unused))) ++{ ++#if (!defined(mips) && !defined(__mips) && !defined(__mips__) && !defined(MIPS) && !defined(__MIPS__)) || !defined(__linux__) ++ return false; ++#else /* __mips__ */ ++/* For PTRACE_GETREGS */ ++ ++ struct pt_regs gregs; ++ if (ptrace (PTRACE_GETREGS, tid, 0, &gregs) != 0) ++ return false; ++ if (! setfunc (-1, 1, (Dwarf_Word *) &gregs.cp0_epc, arg)) ++ return false; ++ return setfunc (0, 32, (Dwarf_Word *) &gregs.regs[0], arg); ++#endif /* __mips__ */ ++} +--- /dev/null ++++ b/backends/mips_unwind.c +@@ -0,0 +1,84 @@ ++/* Get previous frame state for an existing frame state. ++ Copyright (C) 2016 The Qt Company Ltd. ++ Copyright (C) 2024 CIP United Inc. ++ This file is part of elfutils. ++ ++ This file is free software; you can redistribute it and/or modify ++ it under the terms of either ++ ++ * the GNU Lesser General Public License as published by the Free ++ Software Foundation; either version 3 of the License, or (at ++ your option) any later version ++ ++ or ++ ++ * the GNU General Public License as published by the Free ++ Software Foundation; either version 2 of the License, or (at ++ your option) any later version ++ ++ or both in parallel, as here. ++ ++ elfutils is distributed in the hope that it will be useful, but ++ WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ General Public License for more details. ++ ++ You should have received copies of the GNU General Public License and ++ the GNU Lesser General Public License along with this program. If ++ not, see . */ ++ ++#ifdef HAVE_CONFIG_H ++# include ++#endif ++ ++#define BACKEND mips_ ++#define SP_REG 29 ++#define FP_REG 30 ++#define LR_REG 31 ++#define FP_OFFSET 0 ++#define LR_OFFSET 8 ++#define SP_OFFSET 16 ++ ++#include "libebl_CPU.h" ++ ++/* There was no CFI. Maybe we happen to have a frame pointer and can unwind from that? */ ++ ++bool ++EBLHOOK(unwind) (Ebl *ebl __attribute__ ((unused)), Dwarf_Addr pc __attribute__ ((unused)), ++ ebl_tid_registers_t *setfunc, ebl_tid_registers_get_t *getfunc, ++ ebl_pid_memory_read_t *readfunc, void *arg, ++ bool *signal_framep __attribute__ ((unused))) ++{ ++ Dwarf_Word fp, lr, sp; ++ ++ if (!getfunc(LR_REG, 1, &lr, arg)) ++ return false; ++ ++ if (lr == 0 || !setfunc(-1, 1, &lr, arg)) ++ return false; ++ ++ if (!getfunc(FP_REG, 1, &fp, arg)) ++ fp = 0; ++ ++ if (!getfunc(SP_REG, 1, &sp, arg)) ++ sp = 0; ++ ++ Dwarf_Word newLr, newFp, newSp; ++ ++ if (!readfunc(fp + LR_OFFSET, &newLr, arg)) ++ newLr = 0; ++ ++ if (!readfunc(fp + FP_OFFSET, &newFp, arg)) ++ newFp = 0; ++ ++ newSp = fp + SP_OFFSET; ++ ++ // These are not fatal if they don't work. They will just prevent unwinding at the next frame. ++ setfunc(LR_REG, 1, &newLr, arg); ++ setfunc(FP_REG, 1, &newFp, arg); ++ setfunc(SP_REG, 1, &newSp, arg); ++ ++ // If the fp is invalid, we might still have a valid lr. ++ // But if the fp is valid, then the stack should be moving in the right direction. ++ return fp == 0 || newSp > sp; ++} diff --git a/tools/elfutils/patches/015-backport-mips-support-regs.patch b/tools/elfutils/patches/015-backport-mips-support-regs.patch new file mode 100644 index 0000000000..7547a12140 --- /dev/null +++ b/tools/elfutils/patches/015-backport-mips-support-regs.patch @@ -0,0 +1,475 @@ +From db33cb0cac3253c34881c0377ada51d9803eaae0 Mon Sep 17 00:00:00 2001 +From: Ying Huang +Date: Tue, 5 Mar 2024 17:51:22 +0800 +Subject: [PATCH] backends: Add register_info, return_value_location, core_note + on mips + + * backends/Makefile.am (mips_SRCS): Add mips_regs.c, + mips_retval.c and mips_corenote.c. + * backends/mips_init.c (mips_init): HOOK register_info, + return_value_location and core_note. + * backends/mips_corenote.c: New file. + * backends/mips_regs.c: Likewise. + * backends/mips_retval.c: Likewise. + +Signed-off-by: Ying Huang +--- + backends/Makefile.am | 3 +- + backends/mips_corenote.c | 85 +++++++++++++++++ + backends/mips_init.c | 3 + + backends/mips_regs.c | 135 +++++++++++++++++++++++++++ + backends/mips_retval.c | 196 +++++++++++++++++++++++++++++++++++++++ + 5 files changed, 421 insertions(+), 1 deletion(-) + create mode 100644 backends/mips_corenote.c + create mode 100644 backends/mips_regs.c + create mode 100644 backends/mips_retval.c + +--- a/backends/Makefile.am ++++ b/backends/Makefile.am +@@ -103,7 +103,8 @@ loongarch_SRCS = loongarch_init.c loonga + arc_SRCS = arc_init.c arc_symbol.c + + mips_SRCS = mips_init.c mips_symbol.c mips_attrs.c mips_initreg.c \ +- mips_cfi.c mips_unwind.c ++ mips_cfi.c mips_unwind.c mips_regs.c mips_retval.c \ ++ mips_corenote.c + + libebl_backends_a_SOURCES = $(i386_SRCS) $(sh_SRCS) $(x86_64_SRCS) \ + $(ia64_SRCS) $(alpha_SRCS) $(arm_SRCS) \ +--- /dev/null ++++ b/backends/mips_corenote.c +@@ -0,0 +1,85 @@ ++/* MIPS specific core note handling. ++ Copyright (C) 2024 CIP United Inc. ++ This file is part of elfutils. ++ ++ This file is free software; you can redistribute it and/or modify ++ it under the terms of either ++ ++ * the GNU Lesser General Public License as published by the Free ++ Software Foundation; either version 3 of the License, or (at ++ your option) any later version ++ ++ or ++ ++ * the GNU General Public License as published by the Free ++ Software Foundation; either version 2 of the License, or (at ++ your option) any later version ++ ++ or both in parallel, as here. ++ ++ elfutils is distributed in the hope that it will be useful, but ++ WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ General Public License for more details. ++ ++ You should have received copies of the GNU General Public License and ++ the GNU Lesser General Public License along with this program. If ++ not, see . */ ++ ++#ifdef HAVE_CONFIG_H ++# include ++#endif ++ ++#include ++#include ++#include ++#include ++#include ++ ++#define BACKEND mips_ ++#include "libebl_CPU.h" ++ ++#define BITS 64 ++#ifndef BITS ++# define BITS 32 ++#else ++# define BITS 64 ++#endif ++ ++#define PRSTATUS_REGS_SIZE (45 * (BITS / 8)) ++static const Ebl_Register_Location prstatus_regs[] = ++ { ++ { .offset = 0, .regno = 0, .count = (BITS == 32 ? 40 : 34), .bits = BITS }, ++ { .offset = BITS/8 * (BITS == 32 ? 41 : 35), .regno = (BITS == 32 ? 41 : 35), .count = (BITS == 32 ? 4 : 10), .bits = BITS }, ++ }; ++ ++#define PRSTATUS_REGSET_ITEMS \ ++ { \ ++ .name = "pc", .type = ELF_T_ADDR, .format = 'x', \ ++ .offset = offsetof (struct EBLHOOK(prstatus), pr_reg) + ((BITS/8) * (BITS == 32 ? 40 : 34)), \ ++ .group = "register", \ ++ .pc_register = true \ ++ } ++ ++#if BITS == 32 ++# define ULONG uint32_t ++# define ALIGN_ULONG 4 ++# define TYPE_ULONG ELF_T_WORD ++#define TYPE_LONG ELF_T_SWORD ++#else ++#define ULONG uint64_t ++#define ALIGN_ULONG 8 ++#define TYPE_ULONG ELF_T_XWORD ++#define TYPE_LONG ELF_T_SXWORD ++#endif ++#define PID_T int32_t ++#define UID_T uint32_t ++#define GID_T uint32_t ++#define ALIGN_PID_T 4 ++#define ALIGN_UID_T 4 ++#define ALIGN_GID_T 4 ++#define TYPE_PID_T ELF_T_SWORD ++#define TYPE_UID_T ELF_T_WORD ++#define TYPE_GID_T ELF_T_WORD ++ ++#include "linux-core-note.c" +--- a/backends/mips_init.c ++++ b/backends/mips_init.c +@@ -61,6 +61,9 @@ mips_init (Elf *elf __attribute__ ((unus + HOOK (eh, set_initial_registers_tid); + HOOK (eh, abi_cfi); + HOOK (eh, unwind); ++ HOOK (eh, register_info); ++ HOOK (eh, return_value_location); ++ HOOK (eh, core_note); + eh->frame_nregs = 71; + return eh; + } +--- /dev/null ++++ b/backends/mips_regs.c +@@ -0,0 +1,135 @@ ++/* Register names and numbers for mips DWARF. ++ Copyright (C) 2006 Red Hat, Inc. ++ Copyright (C) 2024 CIP United Inc. ++ This file is part of elfutils. ++ ++ This file is free software; you can redistribute it and/or modify ++ it under the terms of either ++ ++ * the GNU Lesser General Public License as published by the Free ++ Software Foundation; either version 3 of the License, or (at ++ your option) any later version ++ ++ or ++ ++ * the GNU General Public License as published by the Free ++ Software Foundation; either version 2 of the License, or (at ++ your option) any later version ++ ++ or both in parallel, as here. ++ ++ elfutils is distributed in the hope that it will be useful, but ++ WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ General Public License for more details. ++ ++ You should have received copies of the GNU General Public License and ++ the GNU Lesser General Public License along with this program. If ++ not, see . */ ++ ++#ifdef HAVE_CONFIG_H ++# include ++#endif ++ ++#include ++#include ++#include ++ ++#define BACKEND mips_ ++#include "libebl_CPU.h" ++#include ++ssize_t ++mips_register_info (Ebl *ebl __attribute__ ((unused)), ++ int regno, char *name, size_t namelen, ++ const char **prefix, const char **setname, ++ int *bits, int *type) ++{ ++ if (name == NULL) ++ return 72; ++ ++ if (regno < 0 || regno > 71 || namelen < 4) ++ return -1; ++ ++ *prefix = "$"; ++ if (regno < 38) ++ { ++ *setname = "integer"; ++ *type = DW_ATE_signed; ++ *bits = 32; ++ } ++ else ++ { ++ *setname = "FPU"; ++ *type = DW_ATE_float; ++ *bits = 64; ++ } ++ ++ if (regno < 32) ++ { ++ if (regno < 10) ++ { ++ name[0] = regno + '0'; ++ namelen = 1; ++ } ++ else ++ { ++ name[0] = (regno / 10) + '0'; ++ name[1] = (regno % 10) + '0'; ++ namelen = 2; ++ } ++ if (regno == 28 || regno == 29 || regno == 31) ++ *type = DW_ATE_address; ++ } ++ else if (regno == 32) ++ { ++ return stpcpy (name, "lo") + 1 - name; ++ } ++ else if (regno == 33) ++ { ++ return stpcpy (name, "hi") + 1 - name; ++ } ++ else if (regno == 34) ++ { ++ return stpcpy (name, "pc") + 1 - name; ++ } ++ else if (regno == 35) ++ { ++ *type = DW_ATE_address; ++ return stpcpy (name, "bad") + 1 - name; ++ } ++ else if (regno == 36) ++ { ++ return stpcpy (name, "sr") + 1 - name; ++ } ++ else if (regno == 37) ++ { ++ *type = DW_ATE_address; ++ return stpcpy (name, "cause") + 1 - name; ++ } ++ else if (regno < 70) ++ { ++ name[0] = 'f'; ++ if (regno < 38 + 10) ++ { ++ name[1] = (regno - 38) + '0'; ++ namelen = 2; ++ } ++ else ++ { ++ name[1] = (regno - 38) / 10 + '0'; ++ name[2] = (regno - 38) % 10 + '0'; ++ namelen = 3; ++ } ++ } ++ else if (regno == 70) ++ { ++ return stpcpy (name, "fsr") + 1 - name; ++ } ++ else if (regno == 71) ++ { ++ return stpcpy (name, "fir") + 1 - name; ++ } ++ ++ name[namelen++] = '\0'; ++ return namelen; ++} +--- /dev/null ++++ b/backends/mips_retval.c +@@ -0,0 +1,196 @@ ++/* Function return value location for Linux/mips ABI. ++ Copyright (C) 2005 Red Hat, Inc. ++ Copyright (C) 2024 CIP United Inc. ++ This file is part of elfutils. ++ ++ This file is free software; you can redistribute it and/or modify ++ it under the terms of either ++ ++ * the GNU Lesser General Public License as published by the Free ++ Software Foundation; either version 3 of the License, or (at ++ your option) any later version ++ ++ or ++ ++ * the GNU General Public License as published by the Free ++ Software Foundation; either version 2 of the License, or (at ++ your option) any later version ++ ++ or both in parallel, as here. ++ ++ elfutils is distributed in the hope that it will be useful, but ++ WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ General Public License for more details. ++ ++ You should have received copies of the GNU General Public License and ++ the GNU Lesser General Public License along with this program. If ++ not, see . */ ++ ++#ifdef HAVE_CONFIG_H ++# include ++#endif ++ ++#include ++#include ++#include ++#include ++#include ++ ++#define BACKEND mips_ ++#include "libebl_CPU.h" ++#include "libdwP.h" ++#include ++ ++/* $v0 or pair $v0, $v1 */ ++static const Dwarf_Op loc_intreg_o32[] = ++ { ++ { .atom = DW_OP_reg2 }, { .atom = DW_OP_piece, .number = 4 }, ++ { .atom = DW_OP_reg3 }, { .atom = DW_OP_piece, .number = 4 }, ++ }; ++ ++static const Dwarf_Op loc_intreg[] = ++ { ++ { .atom = DW_OP_reg2 }, { .atom = DW_OP_piece, .number = 8 }, ++ { .atom = DW_OP_reg3 }, { .atom = DW_OP_piece, .number = 8 }, ++ }; ++#define nloc_intreg 1 ++#define nloc_intregpair 4 ++ ++/* $f0 (float), or pair $f0, $f1 (double). ++ * f2/f3 are used for COMPLEX (= 2 doubles) returns in Fortran */ ++static const Dwarf_Op loc_fpreg_o32[] = ++ { ++ { .atom = DW_OP_regx, .number = 32 }, { .atom = DW_OP_piece, .number = 4 }, ++ { .atom = DW_OP_regx, .number = 33 }, { .atom = DW_OP_piece, .number = 4 }, ++ { .atom = DW_OP_regx, .number = 34 }, { .atom = DW_OP_piece, .number = 4 }, ++ { .atom = DW_OP_regx, .number = 35 }, { .atom = DW_OP_piece, .number = 4 }, ++ }; ++ ++/* $f0, or pair $f0, $f2. */ ++static const Dwarf_Op loc_fpreg[] = ++ { ++ { .atom = DW_OP_regx, .number = 32 }, { .atom = DW_OP_piece, .number = 8 }, ++ { .atom = DW_OP_regx, .number = 34 }, { .atom = DW_OP_piece, .number = 8 }, ++ }; ++#define nloc_fpreg 1 ++#define nloc_fpregpair 4 ++#define nloc_fpregquad 8 ++ ++/* The return value is a structure and is actually stored in stack space ++ passed in a hidden argument by the caller. But, the compiler ++ helpfully returns the address of that space in $v0. */ ++static const Dwarf_Op loc_aggregate[] = ++ { ++ { .atom = DW_OP_breg2, .number = 0 } ++ }; ++#define nloc_aggregate 1 ++ ++int ++mips_return_value_location (Dwarf_Die *functypedie, const Dwarf_Op **locp) ++{ ++ unsigned int regsize = (gelf_getclass (functypedie->cu->dbg->elf) == ELFCLASS32 ) ? 4 : 8; ++ if (!regsize) ++ return -2; ++ ++ /* Start with the function's type, and get the DW_AT_type attribute, ++ which is the type of the return value. */ ++ ++ Dwarf_Attribute attr_mem; ++ Dwarf_Attribute *attr = dwarf_attr_integrate (functypedie, DW_AT_type, &attr_mem); ++ if (attr == NULL) ++ /* The function has no return value, like a `void' function in C. */ ++ return 0; ++ ++ Dwarf_Die die_mem; ++ Dwarf_Die *typedie = dwarf_formref_die (attr, &die_mem); ++ int tag = dwarf_tag (typedie); ++ ++ /* Follow typedefs and qualifiers to get to the actual type. */ ++ while (tag == DW_TAG_typedef ++ || tag == DW_TAG_const_type || tag == DW_TAG_volatile_type ++ || tag == DW_TAG_restrict_type) ++ { ++ attr = dwarf_attr_integrate (typedie, DW_AT_type, &attr_mem); ++ typedie = dwarf_formref_die (attr, &die_mem); ++ tag = dwarf_tag (typedie); ++ } ++ ++ switch (tag) ++ { ++ case -1: ++ return -1; ++ ++ case DW_TAG_subrange_type: ++ if (! dwarf_hasattr_integrate (typedie, DW_AT_byte_size)) ++ { ++ attr = dwarf_attr_integrate (typedie, DW_AT_type, &attr_mem); ++ typedie = dwarf_formref_die (attr, &die_mem); ++ tag = dwarf_tag (typedie); ++ } ++ /* Fall through. */ ++ FALLTHROUGH; ++ ++ case DW_TAG_base_type: ++ case DW_TAG_enumeration_type: ++ CASE_POINTER: ++ { ++ Dwarf_Word size; ++ if (dwarf_formudata (dwarf_attr_integrate (typedie, DW_AT_byte_size, ++ &attr_mem), &size) != 0) ++ { ++ if (dwarf_is_pointer (tag)) ++ size = regsize; ++ else ++ return -1; ++ } ++ if (tag == DW_TAG_base_type) ++ { ++ Dwarf_Word encoding; ++ if (dwarf_formudata (dwarf_attr_integrate (typedie, DW_AT_encoding, ++ &attr_mem), &encoding) != 0) ++ return -1; ++ ++#define ARCH_LOC(loc, regsize) ((regsize) == 4 ? (loc ## _o32) : (loc)) ++ ++ if (encoding == DW_ATE_float) ++ { ++ *locp = ARCH_LOC(loc_fpreg, regsize); ++ if (size <= regsize) ++ return nloc_fpreg; ++ ++ if (size <= 2*regsize) ++ return nloc_fpregpair; ++ ++ if (size <= 4*regsize) ++ return nloc_fpregquad; ++ ++ goto aggregate; ++ } ++ } ++ *locp = ARCH_LOC(loc_intreg, regsize); ++ if (size <= regsize) ++ return nloc_intreg; ++ if (size <= 2*regsize) ++ return nloc_intregpair; ++ ++ /* Else fall through. Shouldn't happen though (at least with gcc) */ ++ } ++ FALLTHROUGH; ++ ++ case DW_TAG_structure_type: ++ case DW_TAG_class_type: ++ case DW_TAG_union_type: ++ case DW_TAG_array_type: ++ aggregate: ++ *locp = loc_aggregate; ++ return nloc_aggregate; ++ case DW_TAG_unspecified_type: ++ return 0; ++ } ++ ++ /* XXX We don't have a good way to return specific errors from ebl calls. ++ This value means we do not understand the type, but it is well-formed ++ DWARF and might be valid. */ ++ return -2; ++}