From 8d3bb7db9d6f07decfc59d83988cda54e5a8b0cd 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 * backends/Makefile.am (modules): Add mips. (mips_SRCS): New var for mips_init.c mips_symbol.c. (libebl_backends_a_SOURCES): Add mips_SRCS. * backends/mips_init.c: New file. * backends/mips_reloc.def: Likewise. * backends/mips_symbol.c: Likewise. * libebl/eblopenbackend.c (mips_init): Declare. (machines): Add mips. * libelf/libelfP.h: Add ELF64_MIPS_R_TYPE{1,2,3} Signed-off-by: Ying Huang --- backends/Makefile.am | 6 ++- backends/mips_init.c | 52 +++++++++++++++++++++++ backends/mips_reloc.def | 93 +++++++++++++++++++++++++++++++++++++++++ backends/mips_symbol.c | 63 ++++++++++++++++++++++++++++ libebl/eblopenbackend.c | 2 + libelf/libelfP.h | 3 ++ 6 files changed, 217 insertions(+), 2 deletions(-) create mode 100644 backends/mips_init.c create mode 100644 backends/mips_reloc.def create mode 100644 backends/mips_symbol.c --- a/backends/Makefile.am +++ b/backends/Makefile.am @@ -37,7 +37,7 @@ AM_CPPFLAGS += -I$(top_srcdir)/libebl -I noinst_LIBRARIES = libebl_backends.a libebl_backends_pic.a modules = i386 sh x86_64 ia64 alpha arm aarch64 sparc ppc ppc64 s390 \ - m68k bpf riscv csky loongarch arc + m68k bpf riscv csky loongarch arc mips 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 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 + libebl_backends_a_SOURCES = $(i386_SRCS) $(sh_SRCS) $(x86_64_SRCS) \ $(ia64_SRCS) $(alpha_SRCS) $(arm_SRCS) \ $(aarch64_SRCS) $(sparc_SRCS) $(ppc_SRCS) \ $(ppc64_SRCS) $(s390_SRCS) \ $(m68k_SRCS) $(bpf_SRCS) $(riscv_SRCS) $(csky_SRCS) \ - $(loongarch_SRCS) $(arc_SRCS) + $(loongarch_SRCS) $(arc_SRCS) $(mips_SRCS) libebl_backends_pic_a_SOURCES = am_libebl_backends_pic_a_OBJECTS = $(libebl_backends_a_SOURCES:.c=.os) --- /dev/null +++ b/backends/mips_init.c @@ -0,0 +1,74 @@ +/* Initialization of MIPS specific backend library. + 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 RELOC_PREFIX R_MIPS_ +#include "libebl_CPU.h" +#include "libelfP.h" + +#define RELOC_TYPE_ID(type) ((type) & 0xff) + +/* 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)), + Ebl *eh) +{ + /* 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 +++ b/backends/mips_reloc.def @@ -0,0 +1,93 @@ +/* List the relocation types for MIPS. -*- C -*- + 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 . */ + +/* NAME, REL|EXEC|DYN */ + + +RELOC_TYPE (NONE, REL|EXEC|DYN) +RELOC_TYPE (16, REL|EXEC|DYN) +RELOC_TYPE (32, REL) +RELOC_TYPE (REL32, REL|EXEC|DYN) +RELOC_TYPE (26, REL|DYN) +RELOC_TYPE (HI16, REL) +RELOC_TYPE (LO16, REL|EXEC|DYN) +RELOC_TYPE (GPREL16, REL|EXEC|DYN) +RELOC_TYPE (LITERAL, REL|EXEC|DYN) +RELOC_TYPE (GOT16, REL|EXEC|DYN) +RELOC_TYPE (PC16, REL) +RELOC_TYPE (CALL16, REL) +RELOC_TYPE (GPREL32, REL) +RELOC_TYPE (SHIFT5, REL) +RELOC_TYPE (SHIFT6, REL) +RELOC_TYPE (64, REL) +RELOC_TYPE (GOT_DISP, REL) +RELOC_TYPE (GOT_PAGE, REL) +RELOC_TYPE (GOT_OFST, REL) +RELOC_TYPE (GOT_HI16, REL) +RELOC_TYPE (GOT_LO16, REL) +RELOC_TYPE (SUB, REL) +RELOC_TYPE (INSERT_A, REL) +RELOC_TYPE (INSERT_B, REL) +RELOC_TYPE (DELETE, REL) +RELOC_TYPE (HIGHER, REL) +RELOC_TYPE (HIGHEST, REL) +RELOC_TYPE (CALL_HI16, REL) +RELOC_TYPE (CALL_LO16, REL) +RELOC_TYPE (SCN_DISP, REL) +RELOC_TYPE (REL16, REL) +RELOC_TYPE (ADD_IMMEDIATE, REL) +RELOC_TYPE (PJUMP, REL) +RELOC_TYPE (RELGOT, REL) +RELOC_TYPE (JALR, REL) +RELOC_TYPE (TLS_DTPMOD32, DYN) +RELOC_TYPE (TLS_DTPREL32, REL) +RELOC_TYPE (TLS_DTPMOD64, DYN) +RELOC_TYPE (TLS_DTPREL64, REL) +RELOC_TYPE (TLS_GD, REL) +RELOC_TYPE (TLS_LDM, REL) +RELOC_TYPE (TLS_DTPREL_HI16, REL) +RELOC_TYPE (TLS_DTPREL_LO16, REL) +RELOC_TYPE (TLS_GOTTPREL, REL) +RELOC_TYPE (TLS_TPREL32, REL) +RELOC_TYPE (TLS_TPREL64, REL) +RELOC_TYPE (TLS_TPREL_HI16, REL) +RELOC_TYPE (TLS_TPREL_LO16, REL) +RELOC_TYPE (GLOB_DAT, REL) +RELOC_TYPE (PC21_S2, REL) +RELOC_TYPE (PC26_S2, REL) +RELOC_TYPE (PC18_S3, REL) +RELOC_TYPE (PC19_S2, REL) +RELOC_TYPE (PCHI16, REL) +RELOC_TYPE (PCLO16, REL) +RELOC_TYPE (COPY, REL) +RELOC_TYPE (JUMP_SLOT, REL) +RELOC_TYPE (PC32, REL) +RELOC_TYPE (EH, REL) +RELOC_TYPE (GNU_REL16_S2, REL) +RELOC_TYPE (GNU_VTINHERIT, REL) +RELOC_TYPE (GNU_VTENTRY, REL) --- /dev/null +++ b/backends/mips_symbol.c @@ -0,0 +1,671 @@ +/* MIPS specific symbolic name 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" +#include "libelfP.h" + +/* Check for the simple reloc types. */ +Elf_Type +mips_reloc_simple_type (Ebl *ebl, int type, + int *addsub __attribute__ ((unused))) +{ + int typeNew = type; + if(ebl->elf->class == ELFCLASS64) + typeNew = ELF64_MIPS_R_TYPE1(type); + switch (typeNew) + { + case R_MIPS_64: + return ELF_T_XWORD; + case R_MIPS_32: + return ELF_T_WORD; + case R_MIPS_16: + return ELF_T_HALF; + + default: + 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 * Ebl *csky_init (Elf *, GElf_Half, Ebl *); Ebl *loongarch_init (Elf *, GElf_Half, Ebl *); Ebl *arc_init (Elf *, GElf_Half, Ebl *); +Ebl *mips_init (Elf *, GElf_Half, Ebl *); /* This table should contain the complete list of architectures as far as the ELF specification is concerned. */ @@ -154,6 +155,7 @@ static const struct { csky_init, "elf_csky", "csky", 4, EM_CSKY, ELFCLASS32, ELFDATA2LSB }, { loongarch_init, "elf_loongarch", "loongarch", 9, EM_LOONGARCH, ELFCLASS64, ELFDATA2LSB }, { arc_init, "elf_arc", "arc", 3, EM_ARCV2, ELFCLASS32, ELFDATA2LSB }, + { mips_init, "elf_mips", "mips", 4, EM_MIPS, 0, 0 }, }; #define nmachines (sizeof (machines) / sizeof (machines[0])) --- a/libelf/libelfP.h +++ b/libelf/libelfP.h @@ -617,4 +617,8 @@ 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