aboutsummaryrefslogtreecommitdiff
path: root/tools/elfutils/patches/012-backport-mips-support-readelf.patch
diff options
context:
space:
mode:
Diffstat (limited to 'tools/elfutils/patches/012-backport-mips-support-readelf.patch')
-rw-r--r--tools/elfutils/patches/012-backport-mips-support-readelf.patch1079
1 files changed, 1079 insertions, 0 deletions
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..3a61acde6e
--- /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 <ying.huang@oss.cipunited.com>
+---
+ 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_initreg.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
+
+--- /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 <http://www.gnu.org/licenses/>. */
++
++#ifdef HAVE_CONFIG_H
++# include <config.h>
++#endif
++
++#include <string.h>
++#include <dwarf.h>
++
++#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,6 +48,13 @@ 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);
+ HOOK (eh, set_initial_registers_tid);
+ HOOK (eh, abi_cfi);
+ HOOK (eh, unwind);
+--- 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
+@@ -624,4 +624,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
+- : _("<INVALID RELOC>"),
+- 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
++ : _("<INVALID RELOC>"),
++ 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
+- : _("<INVALID RELOC>"),
+- 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
++ : _("<INVALID RELOC>"),
++ 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
+- : _("<INVALID RELOC>"),
+- 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
++ : _("<INVALID RELOC>"),
++ 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
+- : _("<INVALID RELOC>"),
+- 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
++ : _("<INVALID RELOC>"),
++ 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");
++ }
++ }
+ }
+ }
+ }
+@@ -12037,7 +12133,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);
+@@ -12067,7 +12163,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
+@@ -216,7 +216,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 \
+ run-sysroot.sh
+
+ if !BIARCH
+@@ -684,7 +684,7 @@ EXTRA_DIST = run-arextract.sh run-arsymt
+ testfile-dwp-4-cu-index-overflow.bz2 \
+ testfile-dwp-4-cu-index-overflow.dwp.bz2 \
+ testfile-dwp-cu-index-overflow.source \
+- testfile-define-file.bz2 \
++ run-readelf-reloc.sh testfile-define-file.bz2 \
+ testfile-sysroot.tar.bz2 run-sysroot.sh run-debuginfod-seekable.sh
+
+
+--- /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 <http://www.gnu.org/licenses/>.
++
++. $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