From patchwork Tue Mar 5 09:51:17 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ying Huang X-Patchwork-Id: 86784 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 5386C3858299 for ; Tue, 5 Mar 2024 09:52:09 +0000 (GMT) X-Original-To: elfutils-devel@sourceware.org Delivered-To: elfutils-devel@sourceware.org Received: from va-1-19.ptr.blmpb.com (va-1-19.ptr.blmpb.com [209.127.230.19]) by sourceware.org (Postfix) with ESMTPS id 459693858C41 for ; Tue, 5 Mar 2024 09:51:49 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 459693858C41 Authentication-Results: sourceware.org; dmarc=none (p=none dis=none) header.from=oss.cipunited.com Authentication-Results: sourceware.org; spf=none smtp.mailfrom=oss.cipunited.com ARC-Filter: OpenARC Filter v1.0.0 sourceware.org 459693858C41 Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=209.127.230.19 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1709632315; cv=none; b=quGA2J/JtqdAJjBvMzcwfS/hksz5T7xRSp3h9ZGiAsourjUBoHnuG/nn/wyjVuqRrQmtefl8iFdzJHdfmj0N1BV9zBcyiAFBlnMnAOKZrTFiJ0KBxuXspoo6CFqW41qPbUAGXf+1YgFss+MPrpLBCPd0IOv6xi/lT8gWuhQ0s6w= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1709632315; c=relaxed/simple; bh=hhWzr14UB+dMFSo43cRwaMStdFjsOWeOplfA636W37s=; h=DKIM-Signature:Date:Subject:Mime-Version:Message-Id:To:From; b=Nd0/4rrr7xLlys9eCXiCI4iRV1pzgrj7bWbE0Iuc9v1HxOh6ySPS5wtCsQSUneHm0JOjv4atDmGdCy3xjVZmL3SJwbeFgqZZ9maJXFEPehdzrpuSksyo1o4U+VPF2Vs28p1wZVi7r0aroJnUYJvFiK1pXQXJ9AQyS0mFiCezmxw= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; s=feishu2303200042; d=oss.cipunited.com; t=1709632303; h=from:subject:mime-version:from:date:message-id:subject:to:cc: reply-to:content-type:mime-version:in-reply-to:message-id; bh=8hcokPj81BgKpTOqIkpO8m8lzwne2IocBZiHRUtgtS0=; b=xCNCeYHiIPozNXaQYiis7x7erj4dDxZtKBfJjmey43UEZ6nhnwKAQCx+nSYirtgpLTOL2d ZRPQIr3HfDmtEVjtHVbFx7g+p61aOZ/MjuTWyGku16Ozd0TmGdBe2ruDep/Eao+SK+59a9 SxPgsCjLTdUBL7/t6lsWMYCXYLvbG/XEYi7h4N3w0kIK5aHiSNDDAlanSKAitrp4+TcqDi s2/AAExwaDWqTOK2LOzmSXTpKKfQ5aBP+G5jyoHc+T4GSAhn/hmOZ0hTbpmMhb6IFSuuZT 0+vDL6/qa2XwjPi6DPjgTPORhcUlPYFnJrwOCIvQ1Rr42iR1Pq+OvIMOptNQgw== Cc: "Ying Huang" Date: Tue, 5 Mar 2024 17:51:17 +0800 X-Original-From: Ying Huang Received: from localhost.localdomain ([123.161.203.50]) by smtp.feishu.cn with ESMTPS; Tue, 05 Mar 2024 17:51:41 +0800 Subject: [PATCH v3 1/6] Support Mips architecture Mime-Version: 1.0 Message-Id: <20240305095122.889077-2-ying.huang@oss.cipunited.com> To: From: "Ying Huang" X-Lms-Return-Path: X-Mailer: git-send-email 2.39.2 X-Spam-Status: No, score=-11.6 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, GIT_PATCH_0, KAM_SHORT, SPF_HELO_NONE, SPF_PASS, TXREP, T_SCC_BODY_TEXT_LINE autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org X-BeenThere: elfutils-devel@sourceware.org X-Mailman-Version: 2.1.30 Precedence: list List-Id: Elfutils-devel mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: elfutils-devel-bounces+patchwork=sourceware.org@sourceware.org From: Ying Huang Signed-off-by: Ying Huang 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 + tests/libelf.h | 541 ++++++++++++++++++++++++++++++++++++++++ 7 files changed, 758 insertions(+), 2 deletions(-) create mode 100644 backends/mips_init.c create mode 100644 backends/mips_reloc.def create mode 100644 backends/mips_symbol.c create mode 100644 tests/libelf.h diff --git a/backends/Makefile.am b/backends/Makefile.am index bbb2aac7..b946fd30 100644 --- a/backends/Makefile.am +++ b/backends/Makefile.am @@ -37,7 +37,7 @@ AM_CPPFLAGS += -I$(top_srcdir)/libebl -I$(top_srcdir)/libasm \ 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,14 @@ loongarch_SRCS = loongarch_init.c loongarch_symbol.c loongarch_cfi.c \ arc_SRCS = arc_init.c arc_symbol.c +mips_SRCS = mips_init.c mips_symbol.c + libebl_backends_a_SOURCES = $(i386_SRCS) $(sh_SRCS) $(x86_64_SRCS) \ $(ia64_SRCS) $(alpha_SRCS) $(arm_SRCS) \ $(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) diff --git a/backends/mips_init.c b/backends/mips_init.c new file mode 100644 index 00000000..cedd08ca --- /dev/null +++ b/backends/mips_init.c @@ -0,0 +1,52 @@ +/* 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" + +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); + return eh; +} diff --git a/backends/mips_reloc.def b/backends/mips_reloc.def new file mode 100644 index 00000000..5120980c --- /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) diff --git a/backends/mips_symbol.c b/backends/mips_symbol.c new file mode 100644 index 00000000..f2a46495 --- /dev/null +++ b/backends/mips_symbol.c @@ -0,0 +1,63 @@ +/* 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; + } +} diff --git a/libebl/eblopenbackend.c b/libebl/eblopenbackend.c index 084a1544..a5f7467a 100644 --- 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])) diff --git a/libelf/libelfP.h b/libelf/libelfP.h index ed061abb..bdd2cc6a 100644 --- a/libelf/libelfP.h +++ b/libelf/libelfP.h @@ -617,4 +617,7 @@ extern void __libelf_reset_rawdata (Elf_Scn *scn, void *buf, size_t size, #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) #endif /* libelfP.h */ diff --git a/tests/libelf.h b/tests/libelf.h new file mode 100644 index 00000000..d3f057b4 --- /dev/null +++ b/tests/libelf.h @@ -0,0 +1,541 @@ +/* Interface for libelf. + Copyright (C) 1998-2010, 2015 Red Hat, 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 . */ + +#ifndef _LIBELF_H +#define _LIBELF_H 1 + +#include +#include + +/* Get the ELF types. */ +#include + +#ifndef SHF_COMPRESSED + /* Older glibc elf.h might not yet define the ELF compression types. */ + #define SHF_COMPRESSED (1 << 11) /* Section with compressed data. */ + + /* Section compression header. Used when SHF_COMPRESSED is set. */ + + typedef struct + { + Elf32_Word ch_type; /* Compression format. */ + Elf32_Word ch_size; /* Uncompressed data size. */ + Elf32_Word ch_addralign; /* Uncompressed data alignment. */ + } Elf32_Chdr; + + typedef struct + { + Elf64_Word ch_type; /* Compression format. */ + Elf64_Word ch_reserved; + Elf64_Xword ch_size; /* Uncompressed data size. */ + Elf64_Xword ch_addralign; /* Uncompressed data alignment. */ + } Elf64_Chdr; + + /* Legal values for ch_type (compression algorithm). */ + #define ELFCOMPRESS_ZLIB 1 /* ZLIB/DEFLATE algorithm. */ + #define ELFCOMPRESS_LOOS 0x60000000 /* Start of OS-specific. */ + #define ELFCOMPRESS_HIOS 0x6fffffff /* End of OS-specific. */ + #define ELFCOMPRESS_LOPROC 0x70000000 /* Start of processor-specific. */ + #define ELFCOMPRESS_HIPROC 0x7fffffff /* End of processor-specific. */ +#endif + +#ifndef ELFCOMPRESS_ZSTD + /* So ZSTD compression can be used even with an old system elf.h. */ + #define ELFCOMPRESS_ZSTD 2 /* Zstandard algorithm. */ +#endif + +#ifndef SHT_RELR + /* So RELR defines/typedefs can be used even with an old system elf.h. */ + #define SHT_RELR 19 /* RELR relative relocations */ + + /* RELR relocation table entry */ + typedef Elf32_Word Elf32_Relr; + typedef Elf64_Xword Elf64_Relr; + + #define DT_RELRSZ 35 /* Total size of RELR relative relocations */ + #define DT_RELR 36 /* Address of RELR relative relocations */ + #define DT_RELRENT 37 /* Size of one RELR relative relocaction */ +#endif + +#if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 3) +# define __nonnull_attribute__(...) __attribute__ ((__nonnull__ (__VA_ARGS__))) +# define __deprecated_attribute__ __attribute__ ((__deprecated__)) +# define __pure_attribute__ __attribute__ ((__pure__)) +# define __const_attribute__ __attribute__ ((__const__)) +#else +# define __nonnull_attribute__(...) +# define __deprecated_attribute__ +# define __pure_attribute__ +# define __const_attribute__ +#endif + +#if __GNUC__ < 4 +#define __noreturn_attribute__ +#else +#define __noreturn_attribute__ __attribute__ ((noreturn)) +#endif + +#ifdef __GNUC_STDC_INLINE__ +# define __libdw_extern_inline extern __inline __attribute__ ((__gnu_inline__)) +#else +# define __libdw_extern_inline extern __inline +#endif + +/* Known translation types. */ +typedef enum +{ + ELF_T_BYTE, /* unsigned char */ + ELF_T_ADDR, /* Elf32_Addr, Elf64_Addr, ... */ + ELF_T_DYN, /* Dynamic section record. */ + ELF_T_EHDR, /* ELF header. */ + ELF_T_HALF, /* Elf32_Half, Elf64_Half, ... */ + ELF_T_OFF, /* Elf32_Off, Elf64_Off, ... */ + ELF_T_PHDR, /* Program header. */ + ELF_T_RELA, /* Relocation entry with addend. */ + ELF_T_REL, /* Relocation entry. */ + ELF_T_SHDR, /* Section header. */ + ELF_T_SWORD, /* Elf32_Sword, Elf64_Sword, ... */ + ELF_T_SYM, /* Symbol record. */ + ELF_T_WORD, /* Elf32_Word, Elf64_Word, ... */ + ELF_T_XWORD, /* Elf32_Xword, Elf64_Xword, ... */ + ELF_T_SXWORD, /* Elf32_Sxword, Elf64_Sxword, ... */ + ELF_T_VDEF, /* Elf32_Verdef, Elf64_Verdef, ... */ + ELF_T_VDAUX, /* Elf32_Verdaux, Elf64_Verdaux, ... */ + ELF_T_VNEED, /* Elf32_Verneed, Elf64_Verneed, ... */ + ELF_T_VNAUX, /* Elf32_Vernaux, Elf64_Vernaux, ... */ + ELF_T_NHDR, /* Elf32_Nhdr, Elf64_Nhdr, ... */ + ELF_T_SYMINFO, /* Elf32_Syminfo, Elf64_Syminfo, ... */ + ELF_T_MOVE, /* Elf32_Move, Elf64_Move, ... */ + ELF_T_LIB, /* Elf32_Lib, Elf64_Lib, ... */ + ELF_T_GNUHASH, /* GNU-style hash section. */ + ELF_T_AUXV, /* Elf32_auxv_t, Elf64_auxv_t, ... */ + ELF_T_CHDR, /* Compressed, Elf32_Chdr, Elf64_Chdr, ... */ + ELF_T_NHDR8, /* Special GNU Properties note. Same as Nhdr, + except padding. */ + ELF_T_RELR, /* Relative relocation entry. */ + /* Keep this the last entry. */ + ELF_T_NUM +} Elf_Type; + +/* Descriptor for data to be converted to or from memory format. */ +typedef struct +{ + void *d_buf; /* Pointer to the actual data. */ + Elf_Type d_type; /* Type of this piece of data. */ + unsigned int d_version; /* ELF version. */ + size_t d_size; /* Size in bytes. */ + int64_t d_off; /* Offset into section. */ + size_t d_align; /* Alignment in section. */ +} Elf_Data; + + +/* Commands for `...'. */ +typedef enum +{ + ELF_C_NULL, /* Nothing, terminate, or compute only. */ + ELF_C_READ, /* Read .. */ + ELF_C_RDWR, /* Read and write .. */ + ELF_C_WRITE, /* Write .. */ + ELF_C_CLR, /* Clear flag. */ + ELF_C_SET, /* Set flag. */ + ELF_C_FDDONE, /* Signal that file descriptor will not be + used anymore. */ + ELF_C_FDREAD, /* Read rest of data so that file descriptor + is not used anymore. */ + /* The following are extensions. */ + ELF_C_READ_MMAP, /* Read, but mmap the file if possible. */ + ELF_C_RDWR_MMAP, /* Read and write, with mmap. */ + ELF_C_WRITE_MMAP, /* Write, with mmap. */ + ELF_C_READ_MMAP_PRIVATE, /* Read, but memory is writable, results are + not written to the file. */ + ELF_C_EMPTY, /* Copy basic file data but not the content. */ + /* Keep this the last entry. */ + ELF_C_NUM +} Elf_Cmd; + + +/* Flags for the ELF structures. */ +enum +{ + ELF_F_DIRTY = 0x1, +#define ELF_F_DIRTY ELF_F_DIRTY + ELF_F_LAYOUT = 0x4, +#define ELF_F_LAYOUT ELF_F_LAYOUT + ELF_F_PERMISSIVE = 0x8 +#define ELF_F_PERMISSIVE ELF_F_PERMISSIVE +}; + +/* Flags for elf_compress[_gnu]. */ +enum +{ + ELF_CHF_FORCE = 0x1 +#define ELF_CHF_FORCE ELF_CHF_FORCE +}; + +/* Identification values for recognized object files. */ +typedef enum +{ + ELF_K_NONE, /* Unknown. */ + ELF_K_AR, /* Archive. */ + ELF_K_COFF, /* Stupid old COFF. */ + ELF_K_ELF, /* ELF file. */ + /* Keep this the last entry. */ + ELF_K_NUM +} Elf_Kind; + + +/* Archive member header. */ +typedef struct +{ + char *ar_name; /* Name of archive member. */ + time_t ar_date; /* File date. */ + uid_t ar_uid; /* User ID. */ + gid_t ar_gid; /* Group ID. */ + mode_t ar_mode; /* File mode. */ + int64_t ar_size; /* File size. */ + char *ar_rawname; /* Original name of archive member. */ +} Elf_Arhdr; + + +/* Archive symbol table entry. */ +typedef struct +{ + char *as_name; /* Symbol name. */ + size_t as_off; /* Offset for this file in the archive. */ + unsigned long int as_hash; /* Hash value of the name. */ +} Elf_Arsym; + + +/* Descriptor for the ELF file. */ +typedef struct Elf Elf; + +/* Descriptor for ELF file section. */ +typedef struct Elf_Scn Elf_Scn; + + +#ifdef __cplusplus +extern "C" { +#endif + +/* Return descriptor for ELF file to work according to CMD. */ +extern Elf *elf_begin (int __fildes, Elf_Cmd __cmd, Elf *__ref); + +/* Create a clone of an existing ELF descriptor. */ + extern Elf *elf_clone (Elf *__elf, Elf_Cmd __cmd); + +/* Create descriptor for memory region. */ +extern Elf *elf_memory (char *__image, size_t __size); + +/* Advance archive descriptor to next element. */ +extern Elf_Cmd elf_next (Elf *__elf); + +/* Free resources allocated for ELF. */ +extern int elf_end (Elf *__elf); + +/* Update ELF descriptor and write file to disk. */ +extern int64_t elf_update (Elf *__elf, Elf_Cmd __cmd); + +/* Determine what kind of file is associated with ELF. */ +extern Elf_Kind elf_kind (Elf *__elf) __pure_attribute__; + +/* Get the base offset for an object file. */ +extern int64_t elf_getbase (Elf *__elf); + + +/* Retrieve file identification data. */ +extern char *elf_getident (Elf *__elf, size_t *__nbytes); + +/* Retrieve class-dependent object file header. */ +extern Elf32_Ehdr *elf32_getehdr (Elf *__elf); +/* Similar but this time the binary calls is ELFCLASS64. */ +extern Elf64_Ehdr *elf64_getehdr (Elf *__elf); + +/* Create ELF header if none exists. */ +extern Elf32_Ehdr *elf32_newehdr (Elf *__elf); +/* Similar but this time the binary calls is ELFCLASS64. */ +extern Elf64_Ehdr *elf64_newehdr (Elf *__elf); + +/* Get the number of program headers in the ELF file. If the file uses + more headers than can be represented in the e_phnum field of the ELF + header the information from the sh_info field in the zeroth section + header is used. */ +extern int elf_getphdrnum (Elf *__elf, size_t *__dst); + +/* Retrieve class-dependent program header table. */ +extern Elf32_Phdr *elf32_getphdr (Elf *__elf); +/* Similar but this time the binary calls is ELFCLASS64. */ +extern Elf64_Phdr *elf64_getphdr (Elf *__elf); + +/* Create ELF program header. */ +extern Elf32_Phdr *elf32_newphdr (Elf *__elf, size_t __cnt); +/* Similar but this time the binary calls is ELFCLASS64. */ +extern Elf64_Phdr *elf64_newphdr (Elf *__elf, size_t __cnt); + + +/* Get section at INDEX. */ +extern Elf_Scn *elf_getscn (Elf *__elf, size_t __index); + +/* Get section at OFFSET. */ +extern Elf_Scn *elf32_offscn (Elf *__elf, Elf32_Off __offset); +/* Similar but this time the binary calls is ELFCLASS64. */ +extern Elf_Scn *elf64_offscn (Elf *__elf, Elf64_Off __offset); + +/* Get index of section. */ +extern size_t elf_ndxscn (Elf_Scn *__scn); + +/* Get section with next section index. */ +extern Elf_Scn *elf_nextscn (Elf *__elf, Elf_Scn *__scn); + +/* Create a new section and append it at the end of the table. */ +extern Elf_Scn *elf_newscn (Elf *__elf); + +/* Get the section index of the extended section index table for the + given symbol table. */ +extern int elf_scnshndx (Elf_Scn *__scn); + +/* Get the number of sections in the ELF file. If the file uses more + sections than can be represented in the e_shnum field of the ELF + header the information from the sh_size field in the zeroth section + header is used. */ +extern int elf_getshdrnum (Elf *__elf, size_t *__dst); +/* Sun messed up the implementation of 'elf_getshnum' in their implementation. + It was agreed to make the same functionality available under a different + name and obsolete the old name. */ +extern int elf_getshnum (Elf *__elf, size_t *__dst) + __deprecated_attribute__; + + +/* Get the section index of the section header string table in the ELF + file. If the index cannot be represented in the e_shstrndx field of + the ELF header the information from the sh_link field in the zeroth + section header is used. */ +extern int elf_getshdrstrndx (Elf *__elf, size_t *__dst); +/* Sun messed up the implementation of 'elf_getshstrndx' in their + implementation. It was agreed to make the same functionality available + under a different name and obsolete the old name. */ +extern int elf_getshstrndx (Elf *__elf, size_t *__dst) + __deprecated_attribute__; + + +/* Retrieve section header of ELFCLASS32 binary. */ +extern Elf32_Shdr *elf32_getshdr (Elf_Scn *__scn); +/* Similar for ELFCLASS64. */ +extern Elf64_Shdr *elf64_getshdr (Elf_Scn *__scn); + +/* Returns compression header for a section if section data is + compressed. Returns NULL and sets elf_errno if the section isn't + compressed or an error occurred. */ +extern Elf32_Chdr *elf32_getchdr (Elf_Scn *__scn); +extern Elf64_Chdr *elf64_getchdr (Elf_Scn *__scn); + +/* Compress or decompress the data of a section and adjust the section + header. + + elf_compress works by setting or clearing the SHF_COMPRESS flag + from the section Shdr and will encode or decode a Elf32_Chdr or + Elf64_Chdr at the start of the section data. elf_compress_gnu will + encode or decode any section, but is traditionally only used for + sections that have a name starting with ".debug" when + uncompressed or ".zdebug" when compressed and stores just the + uncompressed size. The GNU compression method is deprecated and + should only be used for legacy support. + + elf_compress takes a compression type that should be either zero to + decompress or an ELFCOMPRESS algorithm to use for compression. + Currently ELFCOMPRESS_ZLIB and ELFCOMPRESS_ZSTD are supported. + elf_compress_gnu will compress in the traditional GNU compression + format when compress is one and decompress the section data when + compress is zero. + + The FLAGS argument can be zero or ELF_CHF_FORCE. If FLAGS contains + ELF_CHF_FORCE then it will always compress the section, even if + that would not reduce the size of the data section (including the + header). Otherwise elf_compress and elf_compress_gnu will compress + the section only if the total data size is reduced. + + On successful compression or decompression the function returns + one. If (not forced) compression is requested and the data section + would not actually reduce in size, the section is not actually + compressed and zero is returned. Otherwise -1 is returned and + elf_errno is set. + + It is an error to request compression for a section that already + has SHF_COMPRESSED set, or (for elf_compress) to request + decompression for an section that doesn't have SHF_COMPRESSED set. + If a section has SHF_COMPRESSED set then calling elf_compress_gnu + will result in an error. The section has to be decompressed first + using elf_compress. Calling elf_compress on a section compressed + with elf_compress_gnu is fine, but probably useless. + + It is always an error to call these functions on SHT_NOBITS + sections or if the section has the SHF_ALLOC flag set. + elf_compress_gnu will not check whether the section name starts + with ".debug" or .zdebug". It is the responsibility of the caller + to make sure the deprecated GNU compression method is only called + on correctly named sections (and to change the name of the section + when using elf_compress_gnu). + + All previous returned Shdrs and Elf_Data buffers are invalidated by + this call and should no longer be accessed. + + Note that although this changes the header and data returned it + doesn't mark the section as dirty. To keep the changes when + calling elf_update the section has to be flagged ELF_F_DIRTY. */ +extern int elf_compress (Elf_Scn *scn, int type, unsigned int flags); +extern int elf_compress_gnu (Elf_Scn *scn, int compress, unsigned int flags); + +/* Set or clear flags for ELF file. */ +extern unsigned int elf_flagelf (Elf *__elf, Elf_Cmd __cmd, + unsigned int __flags); +/* Similarly for the ELF header. */ +extern unsigned int elf_flagehdr (Elf *__elf, Elf_Cmd __cmd, + unsigned int __flags); +/* Similarly for the ELF program header. */ +extern unsigned int elf_flagphdr (Elf *__elf, Elf_Cmd __cmd, + unsigned int __flags); +/* Similarly for the given ELF section. */ +extern unsigned int elf_flagscn (Elf_Scn *__scn, Elf_Cmd __cmd, + unsigned int __flags); +/* Similarly for the given ELF data. */ +extern unsigned int elf_flagdata (Elf_Data *__data, Elf_Cmd __cmd, + unsigned int __flags); +/* Similarly for the given ELF section header. */ +extern unsigned int elf_flagshdr (Elf_Scn *__scn, Elf_Cmd __cmd, + unsigned int __flags); + + +/* Get data from section while translating from file representation to + memory representation. The Elf_Data d_type is set based on the + section type if known. Otherwise d_type is set to ELF_T_BYTE. If + the section contains compressed data then d_type is always set to + ELF_T_CHDR. */ +extern Elf_Data *elf_getdata (Elf_Scn *__scn, Elf_Data *__data); + +/* Get uninterpreted section content. */ +extern Elf_Data *elf_rawdata (Elf_Scn *__scn, Elf_Data *__data); + +/* Create new data descriptor for section SCN. */ +extern Elf_Data *elf_newdata (Elf_Scn *__scn); + +/* Get data translated from a chunk of the file contents as section data + would be for TYPE. The resulting Elf_Data pointer is valid until + elf_end (ELF) is called. */ +extern Elf_Data *elf_getdata_rawchunk (Elf *__elf, + int64_t __offset, size_t __size, + Elf_Type __type); + + +/* Return pointer to string at OFFSET in section INDEX. */ +extern char *elf_strptr (Elf *__elf, size_t __index, size_t __offset); + + +/* Return header of archive. */ +extern Elf_Arhdr *elf_getarhdr (Elf *__elf); + +/* Return offset in archive for current file ELF. */ +extern int64_t elf_getaroff (Elf *__elf); + +/* Select archive element at OFFSET. */ +extern size_t elf_rand (Elf *__elf, size_t __offset); + +/* Get symbol table of archive. */ +extern Elf_Arsym *elf_getarsym (Elf *__elf, size_t *__narsyms); + + +/* Control ELF descriptor. */ +extern int elf_cntl (Elf *__elf, Elf_Cmd __cmd); + +/* Retrieve uninterpreted file contents. */ +extern char *elf_rawfile (Elf *__elf, size_t *__nbytes); + + +/* Return size of array of COUNT elements of the type denoted by TYPE + in the external representation. The binary class is taken from ELF. + The result is based on version VERSION of the ELF standard. */ +extern size_t elf32_fsize (Elf_Type __type, size_t __count, + unsigned int __version) + __const_attribute__; +/* Similar but this time the binary calls is ELFCLASS64. */ +extern size_t elf64_fsize (Elf_Type __type, size_t __count, + unsigned int __version) + __const_attribute__; + + +/* Convert data structure from the representation in the file represented + by ELF to their memory representation. */ +extern Elf_Data *elf32_xlatetom (Elf_Data *__dest, const Elf_Data *__src, + unsigned int __encode); +/* Same for 64 bit class. */ +extern Elf_Data *elf64_xlatetom (Elf_Data *__dest, const Elf_Data *__src, + unsigned int __encode); + +/* Convert data structure from to the representation in memory + represented by ELF file representation. */ +extern Elf_Data *elf32_xlatetof (Elf_Data *__dest, const Elf_Data *__src, + unsigned int __encode); +/* Same for 64 bit class. */ +extern Elf_Data *elf64_xlatetof (Elf_Data *__dest, const Elf_Data *__src, + unsigned int __encode); + + +/* Return error code of last failing function call. This value is kept + separately for each thread. */ +extern int elf_errno (void); + +/* Return error string for ERROR. If ERROR is zero, return error string + for most recent error or NULL is none occurred. If ERROR is -1 the + behaviour is similar to the last case except that not NULL but a legal + string is returned. */ +extern const char *elf_errmsg (int __error); + + +/* Coordinate ELF library and application versions. */ +extern unsigned int elf_version (unsigned int __version); + +/* Set fill bytes used to fill holes in data structures. */ +extern void elf_fill (int __fill); + +/* Compute hash value. */ +extern unsigned long int elf_hash (const char *__string) + __pure_attribute__; + +/* Compute hash value using the GNU-specific hash function. */ +extern unsigned long int elf_gnu_hash (const char *__string) + __pure_attribute__; + + +/* Compute simple checksum from permanent parts of the ELF file. */ +extern long int elf32_checksum (Elf *__elf); +/* Similar but this time the binary calls is ELFCLASS64. */ +extern long int elf64_checksum (Elf *__elf); + +#ifdef __cplusplus +} +#endif + +#endif /* libelf.h */ From patchwork Tue Mar 5 09:51:18 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ying Huang X-Patchwork-Id: 86785 X-Patchwork-Delegate: mark@klomp.org Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id BBC4F3858285 for ; Tue, 5 Mar 2024 09:52:18 +0000 (GMT) X-Original-To: elfutils-devel@sourceware.org Delivered-To: elfutils-devel@sourceware.org Received: from va-2-34.ptr.blmpb.com (va-2-34.ptr.blmpb.com [209.127.231.34]) by sourceware.org (Postfix) with ESMTPS id 633093858C54 for ; Tue, 5 Mar 2024 09:51:51 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 633093858C54 Authentication-Results: sourceware.org; dmarc=none (p=none dis=none) header.from=oss.cipunited.com Authentication-Results: sourceware.org; spf=none smtp.mailfrom=oss.cipunited.com ARC-Filter: OpenARC Filter v1.0.0 sourceware.org 633093858C54 Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=209.127.231.34 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1709632314; cv=none; b=CxvSu3ftK0niZIdf+79/mxZPZiMN9vxywfGsrYLP2p3pjTN8TgLvD1vZk5rhS5PC04d5gaSmgZQczV5Ox4NhNK4JrUQkh/5kg/xYEsK5u2mOhihyu4gUnp+Nv3Mb83n8D8xKbwxtg1CmAzJCOX2IAM2YXQm55ccwf50fuHd7Yp0= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1709632314; c=relaxed/simple; bh=azXgBlpFRBmyBTVyTfrCIe9tgvhitsz4ATrdBwJeDYY=; h=DKIM-Signature:Subject:Date:Message-Id:Mime-Version:From:To; b=J63EbQXonVCz+L7AxVBN9JOCXhJC13KT3sm/unYGlJa1wRIth5xCJSvDqVKJ7FoX0YwISD/XIM6CXt1PTMDGWikFzdd4wWtBjWh/w8WlFO1s1fjhgO15DLOk7JMsvRqsIFrfX42W/Bkxfg1CXsVLQ3dheAAd61rWt2ggttdLAdc= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; s=feishu2303200042; d=oss.cipunited.com; t=1709632306; h=from:subject:mime-version:from:date:message-id:subject:to:cc: reply-to:content-type:mime-version:in-reply-to:message-id; bh=6doPh6vz3GcUKSxiQmb5v8juz+rheIXzqfipxBrsJio=; b=mtGfN60srz0biFVl62ioym+QlnCdEL8P+yo3ITUp7IIEoT2c9u7232kzlPf/1AHsGeMuYp t9dMglVuh2/u7RKwH1pXm/JE7adAQC3c/k9ONvBy/xNUAIyRJFEqfes2XtLQjo8ycdEgg6 uaHNpc12BOdX6E4gTWil74Oq2Ego+BMabFpZRvQLZmiWdY/FG0jA++Zzhu9iOqiIQWVkgM Nh+ZcZ2olBRTVL3OSO+7IjvM5Qg7sl7Gh7HxauuerD/JFS60qrXAKUbllQFvOvXQOtGwEG 4H7dDd+6xmdiWKTGd+IhuFGs/seLL97FLu8TCmCHThHTOxfKKZaMqVcLu5+dwg== X-Lms-Return-Path: Received: from localhost.localdomain ([123.161.203.50]) by smtp.feishu.cn with ESMTPS; Tue, 05 Mar 2024 17:51:44 +0800 Subject: [PATCH v3 2/6] strip: Adapt src/strip -o -f on mips Date: Tue, 5 Mar 2024 17:51:18 +0800 Message-Id: <20240305095122.889077-3-ying.huang@oss.cipunited.com> Cc: "Ying Huang" Mime-Version: 1.0 X-Mailer: git-send-email 2.39.2 From: "Ying Huang" X-Original-From: Ying Huang To: X-Spam-Status: No, score=-11.3 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, GIT_PATCH_0, SPF_HELO_NONE, SPF_PASS, TXREP, T_SCC_BODY_TEXT_LINE autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org X-BeenThere: elfutils-devel@sourceware.org X-Mailman-Version: 2.1.30 Precedence: list List-Id: Elfutils-devel mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: elfutils-devel-bounces+patchwork=sourceware.org@sourceware.org From: Ying Huang In mips64 little-endian, r_info consists of four byte fields(contains three reloc types) and a 32-bit symbol index. In order to adapt GELF_R_SYM and GELF_R_TYPE, need convert raw data to get correct symbol index and type. libelf/elf_getdata.c: Some eu-utils use read-mmap method to map file, so we need to malloc and memcpy raw data to avoid segment fault. After modification, the correct value are saved in the malloced memory not in process address space. libelf/elf_updata.c: Because we converted the relocation info in mips order when we call elf_getdata.c, so we need to convert the modified data in original order bits before writing the data to the file. Signed-off-by: Ying Huang --- libelf/elf_getdata.c | 132 ++++++++++++++++++++++++++++++++++++++++++- libelf/elf_update.c | 53 +++++++++++++++++ 2 files changed, 183 insertions(+), 2 deletions(-) diff --git a/libelf/elf_getdata.c b/libelf/elf_getdata.c index 7c3ac043..942ba536 100644 --- a/libelf/elf_getdata.c +++ b/libelf/elf_getdata.c @@ -133,6 +133,119 @@ __libelf_data_type (GElf_Ehdr *ehdr, int sh_type, GElf_Xword align) } } +/* 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, @@ -451,8 +564,23 @@ __libelf_set_data_list_rdlock (Elf_Scn *scn, int wrlocked) 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)) diff --git a/libelf/elf_update.c b/libelf/elf_update.c index 56af3a1c..aec19b7c 100644 --- 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: From patchwork Tue Mar 5 09:51:19 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ying Huang X-Patchwork-Id: 86786 X-Patchwork-Delegate: mark@klomp.org Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id CDBBD3858282 for ; Tue, 5 Mar 2024 09:52:19 +0000 (GMT) X-Original-To: elfutils-devel@sourceware.org Delivered-To: elfutils-devel@sourceware.org Received: from va-1-19.ptr.blmpb.com (va-1-19.ptr.blmpb.com [209.127.230.19]) by sourceware.org (Postfix) with ESMTPS id 343853858C56 for ; Tue, 5 Mar 2024 09:51:54 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 343853858C56 Authentication-Results: sourceware.org; dmarc=none (p=none dis=none) header.from=oss.cipunited.com Authentication-Results: sourceware.org; spf=none smtp.mailfrom=oss.cipunited.com ARC-Filter: OpenARC Filter v1.0.0 sourceware.org 343853858C56 Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=209.127.230.19 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1709632318; cv=none; b=IueJ/rXUvMcZwl9bWIx+vMW5aDPywU1/d6PbybntVnVhEAlm0q49ugoxR9KPYNGPNerKiOioTK1EasSIMAc8YfcEtBx6N1AfqEnEx65djy4eLsmn7rr22+M7RAZlNShWzHBwqwTj4MfObqAUIXNmeh5m8f6uSp2njchurSQ/UCg= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1709632318; c=relaxed/simple; bh=Sqw8wc/Mw2HkRAW1Tl0J6Ui2A5SVNCDSaWMzmII9Drs=; h=DKIM-Signature:From:Subject:Mime-Version:To:Date:Message-Id; b=Z+NXBlRL0A6n7c7AotDa1fP/WdQNuEvkBeUMIMeJQPg5ktbaSZw4GK3gk3PmcVVjqCcM2MNApW2hQbIBON8oTBwxrI+y1Qud0fdOL1ex4liMHp+zfMbUYndw7kU5yfQ9nawiB8v1Dv14YqhPanyGVaOUlLgNjQVPzGq7uMnAjj8= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; s=feishu2303200042; d=oss.cipunited.com; t=1709632309; h=from:subject:mime-version:from:date:message-id:subject:to:cc: reply-to:content-type:mime-version:in-reply-to:message-id; bh=Z0qOL6v3D73BgWVNj/Evbe6h+EXZBd2ioXRtnkbPPAs=; b=Yprgvmlw0yMmMCs0JboQH5fhZfybS66MDEgauGrGtrKcCl6tWq0aJW0DsGN0JEQnf+apF/ zimCAIUgRGpnnzZMxikLOG28+5iXOf7KWSohWCYcatZOO91J5+TBYW2n/5Sey4J+BXWdCx MS3yTFN7iN5jdVRawAhDsFfodBSXQdRRbTbJWd/amI923RTTtztm6ksk7WtBh/L7cTsm4R OLoRM8e4KEDscmXZHklnFPiM8sPhsHVCov4COFl1OY0t8NvjbI5tCYCryDIqZsQPq/Zany UPBi1wrq4UV3zwUHTbslPhfY15an4TbUXoj3LCbez+dvHHuPE6dgz+CMreCXaQ== Cc: "Ying Huang" From: "Ying Huang" Subject: [PATCH v3 3/6] readelf: Adapt src/readelf -h/-S/-r/-w/-l/-d/-a on mips Mime-Version: 1.0 X-Original-From: Ying Huang To: Date: Tue, 5 Mar 2024 17:51:19 +0800 X-Mailer: git-send-email 2.39.2 Received: from localhost.localdomain ([123.161.203.50]) by smtp.feishu.cn with ESMTPS; Tue, 05 Mar 2024 17:51:47 +0800 Message-Id: <20240305095122.889077-4-ying.huang@oss.cipunited.com> X-Lms-Return-Path: X-Spam-Status: No, score=-11.9 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, GIT_PATCH_0, KAM_SHORT, NO_DNS_FOR_FROM, SPF_HELO_NONE, SPF_NONE, TXREP, T_SCC_BODY_TEXT_LINE autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org X-BeenThere: elfutils-devel@sourceware.org X-Mailman-Version: 2.1.30 Precedence: list List-Id: Elfutils-devel mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: elfutils-devel-bounces+patchwork=sourceware.org@sourceware.org From: Ying Huang -h: support show Flags name -S: support show mips related section type -r: support show type of Relocation section -w: can work and can show correct "strp" contents -l: support show mips related program header entry type -d: can show mips related Dynamic type name -a: support show complete Object attribute section ".gnu.attributes" Also add test/run-readelf-reloc.sh file to test new type2/type3 of src/readelf -r. Signed-off-by: Ying Huang --- backends/Makefile.am | 2 +- backends/mips_attrs.c | 140 +++++++++ backends/mips_init.c | 7 + backends/mips_symbol.c | 571 +++++++++++++++++++++++++++++++++++++ libelf/libelfP.h | 1 + src/readelf.c | 188 +++++++++--- tests/Makefile.am | 5 +- tests/run-readelf-reloc.sh | 42 +++ 8 files changed, 907 insertions(+), 49 deletions(-) create mode 100644 backends/mips_attrs.c create mode 100755 tests/run-readelf-reloc.sh diff --git a/backends/Makefile.am b/backends/Makefile.am index b946fd30..ad95526e 100644 --- a/backends/Makefile.am +++ b/backends/Makefile.am @@ -102,7 +102,7 @@ loongarch_SRCS = loongarch_init.c loongarch_symbol.c loongarch_cfi.c \ arc_SRCS = arc_init.c arc_symbol.c -mips_SRCS = mips_init.c mips_symbol.c +mips_SRCS = mips_init.c mips_symbol.c mips_attrs.c libebl_backends_a_SOURCES = $(i386_SRCS) $(sh_SRCS) $(x86_64_SRCS) \ $(ia64_SRCS) $(alpha_SRCS) $(arm_SRCS) \ diff --git a/backends/mips_attrs.c b/backends/mips_attrs.c new file mode 100644 index 00000000..54fd3ce3 --- /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; +} diff --git a/backends/mips_init.c b/backends/mips_init.c index cedd08ca..6b9bd4c8 100644 --- a/backends/mips_init.c +++ b/backends/mips_init.c @@ -48,5 +48,12 @@ mips_init (Elf *elf __attribute__ ((unused)), /* We handle it. */ mips_init_reloc (eh); HOOK (eh, reloc_simple_type); + HOOK (eh, section_type_name); + HOOK (eh, machine_flag_check); + HOOK (eh, machine_flag_name); + HOOK (eh, segment_type_name); + HOOK (eh, dynamic_tag_check); + HOOK (eh, dynamic_tag_name); + HOOK (eh, check_object_attribute); return eh; } diff --git a/backends/mips_symbol.c b/backends/mips_symbol.c index f2a46495..1545fc4b 100644 --- a/backends/mips_symbol.c +++ b/backends/mips_symbol.c @@ -61,3 +61,574 @@ mips_reloc_simple_type (Ebl *ebl, int type, 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; +} diff --git a/libelf/libelfP.h b/libelf/libelfP.h index bdd2cc6a..6565ee02 100644 --- a/libelf/libelfP.h +++ b/libelf/libelfP.h @@ -620,4 +620,5 @@ extern void __libelf_reset_rawdata (Elf_Scn *scn, void *buf, size_t size, #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 */ diff --git a/src/readelf.c b/src/readelf.c index 0e931184..e88cf67c 100644 --- a/src/readelf.c +++ b/src/readelf.c @@ -2219,17 +2219,41 @@ handle_relocs_rel (Ebl *ebl, GElf_Ehdr *ehdr, Elf_Scn *scn, GElf_Shdr *shdr) (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 *ehdr, Elf_Scn *scn, GElf_Shdr *shdr) (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 *ehdr, Elf_Scn *scn, GElf_Shdr *shdr) (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 *ehdr, Elf_Scn *scn, GElf_Shdr *shdr) (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 *ebl, GElf_Ehdr *ehdr) 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 *ebl, GElf_Ehdr *ehdr) 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 { diff --git a/tests/Makefile.am b/tests/Makefile.am index 9141074f..18db4047 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -214,7 +214,7 @@ TESTS = run-arextract.sh run-arsymtest.sh run-ar.sh newfile test-nlist \ 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-arsymtest.sh run-ar.sh \ 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 diff --git a/tests/run-readelf-reloc.sh b/tests/run-readelf-reloc.sh new file mode 100755 index 00000000..c1a081dd --- /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 From patchwork Tue Mar 5 09:51:20 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ying Huang X-Patchwork-Id: 86787 X-Patchwork-Delegate: mark@klomp.org Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 203323858C54 for ; Tue, 5 Mar 2024 09:52:32 +0000 (GMT) X-Original-To: elfutils-devel@sourceware.org Delivered-To: elfutils-devel@sourceware.org Received: from va-1-16.ptr.blmpb.com (va-1-16.ptr.blmpb.com [209.127.230.16]) by sourceware.org (Postfix) with ESMTPS id 528A4385842F for ; Tue, 5 Mar 2024 09:52:03 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 528A4385842F Authentication-Results: sourceware.org; dmarc=none (p=none dis=none) header.from=oss.cipunited.com Authentication-Results: sourceware.org; spf=none smtp.mailfrom=oss.cipunited.com ARC-Filter: OpenARC Filter v1.0.0 sourceware.org 528A4385842F Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=209.127.230.16 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1709632326; cv=none; b=Hy7dPzDVfahwDJ//ChtuyztlKVPKKVWEkxnhiw1L17X1U32sZN6xEMvUctTsJjpiTRVP481jVnQzV7GZEbJUQBEifsoku5df4KSKYU4EU4Ix/orxH8kpei+fzAVwVhvQOfsL3pWhgKtUuavXFuKJIqVYOPu7/Ats8ucEISWVvoQ= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1709632326; c=relaxed/simple; bh=8OdMzWx0paCdHJh7f00wHoa2yz5FvbI6BCIhMx1Yz4A=; h=DKIM-Signature:From:Subject:Date:To:Mime-Version:Message-Id; b=Ow9dWAL+Y2KxiihFftZTdhkupAKxFKw6hDEOjQfarIkU9SUjg8CpIY8ZnEO7cOlFJSyEOfQtKHpkDMDfk3B80MD33RB+ZrrdU7MsifKiMxxKbyrwVNTPodKHWOqxflSBP5GoGWa064bLDxLg6vCsEWIcGNeSvyV4phPnev/GZHg= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; s=feishu2303200042; d=oss.cipunited.com; t=1709632312; h=from:subject:mime-version:from:date:message-id:subject:to:cc: reply-to:content-type:mime-version:in-reply-to:message-id; bh=AoZivuAetnfeGhSGiCftzE23H/nZwjJZeoO8Df9uqaU=; b=RnX7NJqeGLJ8HBHZyKUm1XjT/GE1h5aYPtwvtUQdCgVcNijTAZ6CUZNXcePjZIlM1joRUv e/Dzj7q1Cf6AE/4lC7i+wTlpFW1RaoMdcy1dCSYFpifRLl7Z2GyPo0fsIuGvZetqDQaWyr tVky5mCedezIgUg3xQZiZ47IQlROJAQPUkVy5r+ak79u2WHrnElm8VzkV3UVVzWoHlnTbk IrfSIVm45yvtHyjXaaT4nEyPfXcHFytKWNjKvqluhfrWK6E/Iw3fePlWCftOzpclph5tvC r+Koh+b0TKVde67IT3LrCvt3zUwhMOmKLx6Yz/ECUO04UccbTE6p28WCmNAnbQ== From: "Ying Huang" Subject: [PATCH v3 4/6] elflint: adapt src/elflint --gnu src/nm on mips Date: Tue, 5 Mar 2024 17:51:20 +0800 X-Original-From: Ying Huang To: Mime-Version: 1.0 Received: from localhost.localdomain ([123.161.203.50]) by smtp.feishu.cn with ESMTPS; Tue, 05 Mar 2024 17:51:50 +0800 X-Mailer: git-send-email 2.39.2 Message-Id: <20240305095122.889077-5-ying.huang@oss.cipunited.com> X-Lms-Return-Path: Cc: "Ying Huang" X-Spam-Status: No, score=-12.0 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, GIT_PATCH_0, NO_DNS_FOR_FROM, SPF_HELO_NONE, SPF_NONE, TXREP, T_SCC_BODY_TEXT_LINE autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org X-BeenThere: elfutils-devel@sourceware.org X-Mailman-Version: 2.1.30 Precedence: list List-Id: Elfutils-devel mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: elfutils-devel-bounces+patchwork=sourceware.org@sourceware.org From: Ying Huang The errors were: $ src/elflint --gnu src/nm section [ 2] '.MIPS.options' contains unknown flag(s) 0x8000000 section [ 7] '.dynsym': symbol 165 (_DYNAMIC_LINKING): non-local section symbol section [24] '.got' contains invalid processor-specific flag(s) 0x10000000 section [25] '.sdata' contains invalid processor-specific flag(s) 0x10000000 section [29] '.debug_aranges' has wrong type: expected PROGBITS, is MIPS_DWARF section [30] '.debug_info' has wrong type: expected PROGBITS, is MIPS_DWARF section [31] '.debug_abbrev' has wrong type: expected PROGBITS, is MIPS_DWARF section [32] '.debug_line' has wrong type: expected PROGBITS, is MIPS_DWARF section [33] '.debug_frame' has wrong type: expected PROGBITS, is MIPS_DWARF section [34] '.debug_str' has wrong type: expected PROGBITS, is MIPS_DWARF section [35] '.debug_loc' has wrong type: expected PROGBITS, is MIPS_DWARF section [36] '.debug_ranges' has wrong type: expected PROGBITS, is MIPS_DWARF section [38] '.symtab': symbol 785 (_gp): st_value out of bounds section [38] '.symtab': symbol 910 (_fbss): st_value out of bounds section [38] '.symtab': symbol 1051 (_DYNAMIC_LINKING): non-local section symbol After fixing: $ src/elflint --gnu src/nm No errors Signed-off-by: Ying Huang --- backends/mips_init.c | 3 +++ backends/mips_symbol.c | 37 +++++++++++++++++++++++++++++++++++++ src/elflint.c | 26 +++++++++++++++++++++----- 3 files changed, 61 insertions(+), 5 deletions(-) diff --git a/backends/mips_init.c b/backends/mips_init.c index 6b9bd4c8..521e6e51 100644 --- a/backends/mips_init.c +++ b/backends/mips_init.c @@ -51,9 +51,12 @@ mips_init (Elf *elf __attribute__ ((unused)), HOOK (eh, section_type_name); HOOK (eh, machine_flag_check); HOOK (eh, machine_flag_name); + HOOK (eh, machine_section_flag_check); HOOK (eh, segment_type_name); HOOK (eh, dynamic_tag_check); HOOK (eh, dynamic_tag_name); HOOK (eh, check_object_attribute); + HOOK (eh, check_special_symbol); + HOOK (eh, check_reloc_target_type); return eh; } diff --git a/backends/mips_symbol.c b/backends/mips_symbol.c index 1545fc4b..af4b6e45 100644 --- a/backends/mips_symbol.c +++ b/backends/mips_symbol.c @@ -158,6 +158,43 @@ mips_section_type_name (int type, return NULL; } +bool +mips_check_reloc_target_type (Ebl *ebl __attribute__ ((unused)), Elf64_Word sh_type) +{ + return (sh_type == SHT_MIPS_DWARF); +} + +/* Check whether given symbol's st_value and st_size are OK despite failing + normal checks. */ +bool +mips_check_special_symbol (Elf *elf, + const GElf_Sym *sym __attribute__ ((unused)), + const char *name __attribute__ ((unused)), + const GElf_Shdr *destshdr) +{ + size_t shstrndx; + if (elf_getshdrstrndx (elf, &shstrndx) != 0) + return false; + const char *sname = elf_strptr (elf, shstrndx, destshdr->sh_name); + if (sname == NULL) + return false; + return (strcmp (sname, ".got") == 0 || strcmp (sname, ".bss") == 0); +} + +/* Check whether SHF_MASKPROC flags are valid. */ +bool +mips_machine_section_flag_check (GElf_Xword sh_flags) +{ + return ((sh_flags &~ (SHF_MIPS_GPREL | + SHF_MIPS_MERGE | + SHF_MIPS_ADDR | + SHF_MIPS_STRINGS | + SHF_MIPS_NOSTRIP | + SHF_MIPS_LOCAL | + SHF_MIPS_NAMES | + SHF_MIPS_NODUPE)) == 0); +} + /* Check whether machine flags are valid. */ bool mips_machine_flag_check (GElf_Word flags) diff --git a/src/elflint.c b/src/elflint.c index 864de710..092409a2 100644 --- a/src/elflint.c +++ b/src/elflint.c @@ -936,7 +936,9 @@ section [%2d] '%s': symbol %zu (%s): non-local symbol outside range described in } 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 [%2zu] '%s': %s\n"), && 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 of entry size\n"), 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 entry size is zero\n"), 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 PHDR entry do not match")); 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", From patchwork Tue Mar 5 09:51:21 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ying Huang X-Patchwork-Id: 86788 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 46E3E385843B for ; Tue, 5 Mar 2024 09:52:45 +0000 (GMT) X-Original-To: elfutils-devel@sourceware.org Delivered-To: elfutils-devel@sourceware.org Received: from va-1-17.ptr.blmpb.com (va-1-17.ptr.blmpb.com [209.127.230.17]) by sourceware.org (Postfix) with ESMTPS id 444A43858428 for ; Tue, 5 Mar 2024 09:52:03 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 444A43858428 Authentication-Results: sourceware.org; dmarc=none (p=none dis=none) header.from=oss.cipunited.com Authentication-Results: sourceware.org; spf=none smtp.mailfrom=oss.cipunited.com ARC-Filter: OpenARC Filter v1.0.0 sourceware.org 444A43858428 Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=209.127.230.17 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1709632327; cv=none; b=L8Zq0uw2GrshCj0Umlj2Ct5PVq9P48uX3kP7TcXKJBj8RJnyxinUWInMxjj9EaIdzCOP9aLKwWpErC0VIfnoVZq4gNdeqa2QLUoHfDLw7C4ZfC1+aCZRAwvhKDTTSoWpAhb739iqUKVGaphV8ZX8NN8WUpmYiYOSPz8ZYOvkf9w= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1709632327; c=relaxed/simple; bh=QgjxaVMsln5PpqyUakuyv6SlivHY3Qono3xOfsQUFPI=; h=DKIM-Signature:To:From:Message-Id:Mime-Version:Subject:Date; b=W8ICro6PPbnufoZDsb3aUt5b/d8cb0C9lpEqOy79InyuJf5BWvYWOM/s59exTr5L3QRkJBbTjrx9PYy+asHHtmYfngo7Mqj8o/7zLhGBNP5FX2+BiLpbJcPukRAreRgZ95lHYdd2PKD2c/bC2PGc8xfAuVtvhU5GHmcLF3Lznjk= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; s=feishu2303200042; d=oss.cipunited.com; t=1709632315; h=from:subject:mime-version:from:date:message-id:subject:to:cc: reply-to:content-type:mime-version:in-reply-to:message-id; bh=qdmbziX7jRtI/VLEIfCFr1rbiBgaun0R4Fls2eWssTU=; b=oKW+VMMP+giln/WPirhzOSq5Sa0xYm6t6BekYF8DQ0vLszGovuj9S57mmTRIE/IigV/ose WSRELuyG8kKUzvyZtnoiGGdRneIPA4UAavOkX+61ugz93qzhMInIZ7b9aRZfRkRioYsyOu N4a69JW+MywVk+A5H+wvWxjMw1U6PMSpUjPRDVoHLM+hI0Qz/ECYdJOM/kkMqK8CTw4anC 5emLk93ooNP1vtaL1bGZtGGyipRbzZclMGnVNZd0/s/Kj0ConlbOgoBxh0BBZmthSpkqJx II4amgzCAtoL5aWl/GYo5ytJM0XreovL6j70zXxPrHPSNhjX6M7KK0m3M3B9og== To: From: "Ying Huang" Message-Id: <20240305095122.889077-6-ying.huang@oss.cipunited.com> Mime-Version: 1.0 X-Mailer: git-send-email 2.39.2 Cc: "Ying Huang" X-Original-From: Ying Huang Subject: [PATCH v3 5/6] stack: Fix stack unwind failure on mips Date: Tue, 5 Mar 2024 17:51:21 +0800 Received: from localhost.localdomain ([123.161.203.50]) by smtp.feishu.cn with ESMTPS; Tue, 05 Mar 2024 17:51:53 +0800 X-Lms-Return-Path: X-Spam-Status: No, score=-12.1 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, GIT_PATCH_0, KAM_SHORT, MSGID_FROM_MTA_HEADER, NO_DNS_FOR_FROM, SPF_HELO_NONE, SPF_NONE, TXREP, T_SCC_BODY_TEXT_LINE autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org X-BeenThere: elfutils-devel@sourceware.org X-Mailman-Version: 2.1.30 Precedence: list List-Id: Elfutils-devel mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: elfutils-devel-bounces+patchwork=sourceware.org@sourceware.org From: Ying Huang Add abi_cfi, set_initial_registers_tid, unwind on mips. Signed-off-by: Ying Huang --- backends/Makefile.am | 3 +- backends/mips_cfi.c | 68 +++++++++++++++++++++++++++++++++ backends/mips_init.c | 4 ++ backends/mips_initreg.c | 61 ++++++++++++++++++++++++++++++ backends/mips_unwind.c | 84 +++++++++++++++++++++++++++++++++++++++++ 5 files changed, 219 insertions(+), 1 deletion(-) create mode 100644 backends/mips_cfi.c create mode 100644 backends/mips_initreg.c create mode 100644 backends/mips_unwind.c diff --git a/backends/Makefile.am b/backends/Makefile.am index ad95526e..5e7b7f21 100644 --- a/backends/Makefile.am +++ b/backends/Makefile.am @@ -102,7 +102,8 @@ loongarch_SRCS = loongarch_init.c loongarch_symbol.c loongarch_cfi.c \ arc_SRCS = arc_init.c arc_symbol.c -mips_SRCS = mips_init.c mips_symbol.c mips_attrs.c +mips_SRCS = mips_init.c mips_symbol.c mips_attrs.c mips_initreg.c \ + mips_cfi.c mips_unwind.c libebl_backends_a_SOURCES = $(i386_SRCS) $(sh_SRCS) $(x86_64_SRCS) \ $(ia64_SRCS) $(alpha_SRCS) $(arm_SRCS) \ diff --git a/backends/mips_cfi.c b/backends/mips_cfi.c new file mode 100644 index 00000000..60cf8111 --- /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; +} diff --git a/backends/mips_init.c b/backends/mips_init.c index 521e6e51..1a2456b1 100644 --- a/backends/mips_init.c +++ b/backends/mips_init.c @@ -58,5 +58,9 @@ mips_init (Elf *elf __attribute__ ((unused)), HOOK (eh, check_object_attribute); HOOK (eh, check_special_symbol); HOOK (eh, check_reloc_target_type); + HOOK (eh, set_initial_registers_tid); + HOOK (eh, abi_cfi); + HOOK (eh, unwind); + eh->frame_nregs = 71; return eh; } diff --git a/backends/mips_initreg.c b/backends/mips_initreg.c new file mode 100644 index 00000000..21e7dedb --- /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__ */ +} diff --git a/backends/mips_unwind.c b/backends/mips_unwind.c new file mode 100644 index 00000000..9acf87a7 --- /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; +} From patchwork Tue Mar 5 09:51:22 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ying Huang X-Patchwork-Id: 86789 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id B34083858437 for ; Tue, 5 Mar 2024 09:52:51 +0000 (GMT) X-Original-To: elfutils-devel@sourceware.org Delivered-To: elfutils-devel@sourceware.org Received: from va-2-32.ptr.blmpb.com (va-2-32.ptr.blmpb.com [209.127.231.32]) by sourceware.org (Postfix) with ESMTPS id 66ECE3858439 for ; Tue, 5 Mar 2024 09:52:03 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 66ECE3858439 Authentication-Results: sourceware.org; dmarc=none (p=none dis=none) header.from=oss.cipunited.com Authentication-Results: sourceware.org; spf=none smtp.mailfrom=oss.cipunited.com ARC-Filter: OpenARC Filter v1.0.0 sourceware.org 66ECE3858439 Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=209.127.231.32 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1709632328; cv=none; b=lsgXsyN4Hu8ewLH3k6/8ziKQl636pTNwAnVn5ee8R1GgUsKAoPklQkT7YIzkj9SmVpRlNs/tOG9jKep4/ocqwmdrtGe4V8IcEuF18NuQprGqOm7a5jFnbOSfmpvRMQzD9AG5bi53n3D53yf9D51ETQeH1yEzav4TdB0t4Uf/glM= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1709632328; c=relaxed/simple; bh=aRTCs4mT5jHW2kzJZO1TPDaNvXL5y1/xD9S1row+XIo=; h=DKIM-Signature:Mime-Version:From:Message-Id:Subject:Date:To; b=P8rhTp00hfPF6MPsI+e7PhfagoZOEHYAnhaEMQkDjIWOgHoHe1ujafWMc6Dmgix93GdgBEfWiZ54GsyiOWxuxMywJ7GT3X0eCD2Sq8FLd8bNOUPJBt8DPQHrByvBx6pEQgS1WjlxDo7MhpIna+uxq28sV5UlMEQQhuRdLYHh3VI= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; s=feishu2303200042; d=oss.cipunited.com; t=1709632318; h=from:subject:mime-version:from:date:message-id:subject:to:cc: reply-to:content-type:mime-version:in-reply-to:message-id; bh=ftFkF7rNY7TEPIJjYqhTIk7qBkxaRWipeir8Ak+vGO8=; b=pmmrC43lF6GAc5kjMHTB/al9nkuZ2rHP9NgHAmMXh/m5lKrUGqlZNtWp+vm/I7AGwvwfhY h60OE/412Knb9glK085vU+7dNjRmabH8+sVL3lw4UjDuFjbFEfDmZhcm6UGDXP0S6olt+a BFzht8N5uLMt/v+zUf9TmIfTqyuOMSMf0jlEyaiddxPlkKihHCHjWbBTMk5L+S5UArvz/Z iYYbnfwtfj/ODRCzHCk2ZtLLf+eg4akUL1r98QftzxSNGJr3pDpcpltnKVjyK2pItVBLai qY7NGJ6oKNJ2VayP77JE8WSf+gBy/lvKO8dFDUIF5KwiHRZ8Qzaz9iizoyIGPQ== Mime-Version: 1.0 Received: from localhost.localdomain ([123.161.203.50]) by smtp.feishu.cn with ESMTPS; Tue, 05 Mar 2024 17:51:56 +0800 From: "Ying Huang" Message-Id: <20240305095122.889077-7-ying.huang@oss.cipunited.com> X-Original-From: Ying Huang X-Mailer: git-send-email 2.39.2 Subject: [PATCH v3 6/6] backends: Add register_info, return_value_location, core_note function on mips Date: Tue, 5 Mar 2024 17:51:22 +0800 X-Lms-Return-Path: To: Cc: "Ying Huang" X-Spam-Status: No, score=-12.2 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, GIT_PATCH_0, KAM_SHORT, NO_DNS_FOR_FROM, SPF_HELO_NONE, SPF_NONE, TXREP, T_SCC_BODY_TEXT_LINE autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org X-BeenThere: elfutils-devel@sourceware.org X-Mailman-Version: 2.1.30 Precedence: list List-Id: Elfutils-devel mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: elfutils-devel-bounces+patchwork=sourceware.org@sourceware.org From: Ying Huang Signed-off-by: Ying Huang --- backends/Makefile.am | 3 +- backends/mips_corenote.c | 85 +++++++++++++++++ backends/mips_init.c | 3 + backends/mips_regs.c | 135 +++++++++++++++++++++++++++ backends/mips_retval.c | 196 +++++++++++++++++++++++++++++++++++++++ 5 files changed, 421 insertions(+), 1 deletion(-) create mode 100644 backends/mips_corenote.c create mode 100644 backends/mips_regs.c create mode 100644 backends/mips_retval.c diff --git a/backends/Makefile.am b/backends/Makefile.am index 5e7b7f21..7c7f3351 100644 --- a/backends/Makefile.am +++ b/backends/Makefile.am @@ -103,7 +103,8 @@ loongarch_SRCS = loongarch_init.c loongarch_symbol.c loongarch_cfi.c \ arc_SRCS = arc_init.c arc_symbol.c mips_SRCS = mips_init.c mips_symbol.c mips_attrs.c mips_initreg.c \ - mips_cfi.c mips_unwind.c + mips_cfi.c mips_unwind.c mips_regs.c mips_retval.c \ + mips_corenote.c libebl_backends_a_SOURCES = $(i386_SRCS) $(sh_SRCS) $(x86_64_SRCS) \ $(ia64_SRCS) $(alpha_SRCS) $(arm_SRCS) \ diff --git a/backends/mips_corenote.c b/backends/mips_corenote.c new file mode 100644 index 00000000..aeadeb17 --- /dev/null +++ b/backends/mips_corenote.c @@ -0,0 +1,85 @@ +/* MIPS specific core note handling. + Copyright (C) 2024 CIP United Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see . */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include +#include +#include + +#define BACKEND mips_ +#include "libebl_CPU.h" + +#define BITS 64 +#ifndef BITS +# define BITS 32 +#else +# define BITS 64 +#endif + +#define PRSTATUS_REGS_SIZE (45 * (BITS / 8)) +static const Ebl_Register_Location prstatus_regs[] = + { + { .offset = 0, .regno = 0, .count = (BITS == 32 ? 40 : 34), .bits = BITS }, + { .offset = BITS/8 * (BITS == 32 ? 41 : 35), .regno = (BITS == 32 ? 41 : 35), .count = (BITS == 32 ? 4 : 10), .bits = BITS }, + }; + +#define PRSTATUS_REGSET_ITEMS \ + { \ + .name = "pc", .type = ELF_T_ADDR, .format = 'x', \ + .offset = offsetof (struct EBLHOOK(prstatus), pr_reg) + ((BITS/8) * (BITS == 32 ? 40 : 34)), \ + .group = "register", \ + .pc_register = true \ + } + +#if BITS == 32 +# define ULONG uint32_t +# define ALIGN_ULONG 4 +# define TYPE_ULONG ELF_T_WORD +#define TYPE_LONG ELF_T_SWORD +#else +#define ULONG uint64_t +#define ALIGN_ULONG 8 +#define TYPE_ULONG ELF_T_XWORD +#define TYPE_LONG ELF_T_SXWORD +#endif +#define PID_T int32_t +#define UID_T uint32_t +#define GID_T uint32_t +#define ALIGN_PID_T 4 +#define ALIGN_UID_T 4 +#define ALIGN_GID_T 4 +#define TYPE_PID_T ELF_T_SWORD +#define TYPE_UID_T ELF_T_WORD +#define TYPE_GID_T ELF_T_WORD + +#include "linux-core-note.c" diff --git a/backends/mips_init.c b/backends/mips_init.c index 1a2456b1..711a934e 100644 --- a/backends/mips_init.c +++ b/backends/mips_init.c @@ -61,6 +61,9 @@ mips_init (Elf *elf __attribute__ ((unused)), HOOK (eh, set_initial_registers_tid); HOOK (eh, abi_cfi); HOOK (eh, unwind); + HOOK (eh, register_info); + HOOK (eh, return_value_location); + HOOK (eh, core_note); eh->frame_nregs = 71; return eh; } diff --git a/backends/mips_regs.c b/backends/mips_regs.c new file mode 100644 index 00000000..4a1f8c50 --- /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; +} diff --git a/backends/mips_retval.c b/backends/mips_retval.c new file mode 100644 index 00000000..2b697c08 --- /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; +}