diff options
Diffstat (limited to 'backends')
| -rw-r--r-- | backends/ChangeLog | 77 | ||||
| -rw-r--r-- | backends/Makefile.am | 30 | ||||
| -rw-r--r-- | backends/aarch64_cfi.c | 82 | ||||
| -rw-r--r-- | backends/aarch64_corenote.c | 162 | ||||
| -rw-r--r-- | backends/aarch64_init.c | 63 | ||||
| -rw-r--r-- | backends/aarch64_regs.c | 95 | ||||
| -rw-r--r-- | backends/aarch64_reloc.def | 157 | ||||
| -rw-r--r-- | backends/aarch64_retval.c | 375 | ||||
| -rw-r--r-- | backends/aarch64_symbol.c | 84 | ||||
| -rw-r--r-- | backends/i386_init.c | 5 | ||||
| -rw-r--r-- | backends/i386_initreg.c | 79 | ||||
| -rw-r--r-- | backends/libebl_CPU.h | 37 | ||||
| -rw-r--r-- | backends/ppc64_init.c | 34 | ||||
| -rw-r--r-- | backends/ppc64_resolve_sym.c | 63 | ||||
| -rw-r--r-- | backends/ppc_cfi.c | 2 | ||||
| -rw-r--r-- | backends/ppc_corenote.c | 2 | ||||
| -rw-r--r-- | backends/ppc_init.c | 4 | ||||
| -rw-r--r-- | backends/ppc_initreg.c | 114 | ||||
| -rw-r--r-- | backends/s390_corenote.c | 10 | ||||
| -rw-r--r-- | backends/s390_init.c | 9 | ||||
| -rw-r--r-- | backends/s390_initreg.c | 95 | ||||
| -rw-r--r-- | backends/s390_unwind.c | 139 | ||||
| -rw-r--r-- | backends/x86_64_init.c | 5 | ||||
| -rw-r--r-- | backends/x86_64_initreg.c | 73 |
24 files changed, 1776 insertions, 20 deletions
diff --git a/backends/ChangeLog b/backends/ChangeLog index 3409010d..2074cff3 100644 --- a/backends/ChangeLog +++ b/backends/ChangeLog @@ -1,3 +1,80 @@ +2014-01-03 Mark Wielaard <[email protected]> + + * Makefile.am (aarch64_SRCS): Add aarch64_cfi.c. + * aarch64_cfi.c: New file. + * aarch64_init.c (aarch64_init): Hook abi_cfi. + * aarch64_regs.c (aarch64_register_info): Set *prefix to "". + +2013-12-19 Mark Wielaard <[email protected]> + + * aarch64_init.c (aarch64_init): Hook check_special_symbol. + * aarch64_symbol.c (aarch64_check_special_symbol): New function. + +2013-12-18 Mark Wielaard <[email protected]> + + * Makefile.am (ppc64_SRCS): Add ppc64_resolve_sym.c. + * ppc64_resolve_sym.c: New file. + * ppc64_init.c: Hook resolve_sym_value and find function descriptor + table. + +2013-12-18 Mark Wielaard <[email protected]> + + * s390_initreg.c (s390_set_initial_registers_tid): Use union + to avoid type-punning when assigning a double to a Dwarf_Word. + +2013-12-18 Jan Kratochvil <[email protected]> + + unwinder: s390 and s390x + * Makefile.am (s390_SRCS): Add s390_initreg.c and s390_unwind.c. + * s390_corenote.c (prstatus_regs): Set PC_REGISTER. Reindent all the + entries. + * s390_init.c (s390_init): Initialize frame_nregs, + set_initial_registers_tid, normalize_pc and unwind. + * s390_initreg.c: New file. + * s390_unwind.c: New file. + +2013-12-15 Jan Kratochvil <[email protected]> + + unwinder: ppc and ppc64 + * Makefile.am (ppc_SRCS, ppc64_SRCS): Add ppc_initreg.c. + * ppc64_init.c (ppc64_init): Initialize also frame_nregs, + set_initial_registers_tid and dwarf_to_regno. + * ppc_corenote.c (PRSTATUS_REGSET_ITEMS) <nip>: Set PC_REGISTER. + * ppc_init.c (ppc64_init): Initialize also frame_nregs, + set_initial_registers_tid and dwarf_to_regno. + * ppc_initreg.c: New file. + +2013-11-25 Petr Machata <[email protected]> + + * Makefile.am (modules): Add aarch64. + (libebl_pic): Add libebl_aarch64_pic.a. + (aarch64_SRCS): New variable. + (libebl_aarch64_pic_a_SOURCES): Likewise. + (am_libebl_aarch64_pic_a_OBJECTS): Likewise. + (aarch64_regs_no_Wformat): Likewise. + * aarch64_corenote.c, aarch64_init.c: New files. + * aarch64_regs.c, aarch64_reloc.def: Likewise. + * aarch64_retval.c, aarch64_symbol.c: Likewise. + * libebl_CPU.h (dwarf_peel_type): New function. + (dwarf_peeled_die_type): Likewise. + +2013-11-07 Jan Kratochvil <[email protected]> + Mark Wielaard <[email protected]> + + * Makefile.am (i386_SRCS): Add i386_initreg.c. + (x86_64_SRCS): Add x86_64_initreg.c. + * i386_initreg.c: New file. + * i386_init.c (i386_init): Initialize frame_nregs and + set_initial_registers_tid. + * x86_64_initreg.c: New file. + * x86_64_init.c (x86_64_init): Initialize frame_nregs and + set_initial_registers_tid. + +2013-10-06 Mark Wielaard <[email protected]> + + * ppc_cfi.c (ppc_abi_cfi): Use DW_CFA_val_offset for reg1, not + DW_CFA_val_expression. + 2013-08-29 Mark Wielaard <[email protected]> * Makefile.am (arm_SRCS): Add arm_cfi.c. diff --git a/backends/Makefile.am b/backends/Makefile.am index 557ed879..b8bea36b 100644 --- a/backends/Makefile.am +++ b/backends/Makefile.am @@ -32,11 +32,12 @@ AM_CPPFLAGS += -I$(top_srcdir)/libebl -I$(top_srcdir)/libasm \ -I$(top_srcdir)/libelf -I$(top_srcdir)/libdw -modules = i386 sh x86_64 ia64 alpha arm sparc ppc ppc64 s390 tilegx -libebl_pic = libebl_i386_pic.a libebl_sh_pic.a libebl_x86_64_pic.a \ - libebl_ia64_pic.a libebl_alpha_pic.a libebl_arm_pic.a \ - libebl_sparc_pic.a libebl_ppc_pic.a libebl_ppc64_pic.a \ - libebl_s390_pic.a libebl_tilegx_pic.a +modules = i386 sh x86_64 ia64 alpha arm aarch64 sparc ppc ppc64 s390 \ + tilegx +libebl_pic = libebl_i386_pic.a libebl_sh_pic.a libebl_x86_64_pic.a \ + libebl_ia64_pic.a libebl_alpha_pic.a libebl_arm_pic.a \ + libebl_aarch64_pic.a libebl_sparc_pic.a libebl_ppc_pic.a \ + libebl_ppc64_pic.a libebl_s390_pic.a libebl_tilegx_pic.a noinst_LIBRARIES = $(libebl_pic) noinst_DATA = $(libebl_pic:_pic.a=.so) @@ -50,7 +51,8 @@ libdw = ../libdw/libdw.so endif i386_SRCS = i386_init.c i386_symbol.c i386_corenote.c i386_cfi.c \ - i386_retval.c i386_regs.c i386_auxv.c i386_syscall.c + i386_retval.c i386_regs.c i386_auxv.c i386_syscall.c \ + i386_initreg.c cpu_i386 = ../libcpu/libcpu_i386.a libebl_i386_pic_a_SOURCES = $(i386_SRCS) am_libebl_i386_pic_a_OBJECTS = $(i386_SRCS:.c=.os) @@ -60,7 +62,8 @@ libebl_sh_pic_a_SOURCES = $(sh_SRCS) am_libebl_sh_pic_a_OBJECTS = $(sh_SRCS:.c=.os) x86_64_SRCS = x86_64_init.c x86_64_symbol.c x86_64_corenote.c x86_64_cfi.c \ - x86_64_retval.c x86_64_regs.c i386_auxv.c x86_64_syscall.c + x86_64_retval.c x86_64_regs.c i386_auxv.c x86_64_syscall.c \ + x86_64_initreg.c cpu_x86_64 = ../libcpu/libcpu_x86_64.a libebl_x86_64_pic_a_SOURCES = $(x86_64_SRCS) am_libebl_x86_64_pic_a_OBJECTS = $(x86_64_SRCS:.c=.os) @@ -79,6 +82,12 @@ arm_SRCS = arm_init.c arm_symbol.c arm_regs.c arm_corenote.c \ libebl_arm_pic_a_SOURCES = $(arm_SRCS) am_libebl_arm_pic_a_OBJECTS = $(arm_SRCS:.c=.os) +aarch64_SRCS = aarch64_init.c aarch64_regs.c aarch64_symbol.c \ + aarch64_corenote.c aarch64_retval.c aarch64_cfi.c +libebl_aarch64_pic_a_SOURCES = $(aarch64_SRCS) +am_libebl_aarch64_pic_a_OBJECTS = $(aarch64_SRCS:.c=.os) +aarch64_regs_no_Wformat = yes + sparc_SRCS = sparc_init.c sparc_symbol.c sparc_regs.c sparc_retval.c \ sparc_corenote.c sparc64_corenote.c sparc_auxv.c libebl_sparc_pic_a_SOURCES = $(sparc_SRCS) @@ -86,18 +95,19 @@ am_libebl_sparc_pic_a_OBJECTS = $(sparc_SRCS:.c=.os) ppc_SRCS = ppc_init.c ppc_symbol.c ppc_retval.c ppc_regs.c \ ppc_corenote.c ppc_auxv.c ppc_attrs.c ppc_syscall.c \ - ppc_cfi.c + ppc_cfi.c ppc_initreg.c libebl_ppc_pic_a_SOURCES = $(ppc_SRCS) am_libebl_ppc_pic_a_OBJECTS = $(ppc_SRCS:.c=.os) ppc64_SRCS = ppc64_init.c ppc64_symbol.c ppc64_retval.c \ ppc64_corenote.c ppc_regs.c ppc_auxv.c ppc_attrs.c ppc_syscall.c \ - ppc_cfi.c + ppc_cfi.c ppc_initreg.c ppc64_resolve_sym.c libebl_ppc64_pic_a_SOURCES = $(ppc64_SRCS) am_libebl_ppc64_pic_a_OBJECTS = $(ppc64_SRCS:.c=.os) s390_SRCS = s390_init.c s390_symbol.c s390_regs.c s390_retval.c \ - s390_corenote.c s390x_corenote.c s390_cfi.c + s390_corenote.c s390x_corenote.c s390_cfi.c s390_initreg.c \ + s390_unwind.c libebl_s390_pic_a_SOURCES = $(s390_SRCS) am_libebl_s390_pic_a_OBJECTS = $(s390_SRCS:.c=.os) diff --git a/backends/aarch64_cfi.c b/backends/aarch64_cfi.c new file mode 100644 index 00000000..acbb9b69 --- /dev/null +++ b/backends/aarch64_cfi.c @@ -0,0 +1,82 @@ +/* arm ABI-specified defaults for DWARF CFI. + Copyright (C) 2013 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 <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <dwarf.h> + +#define BACKEND aarch64_ +#include "libebl_CPU.h" + + +/* ABI-specified state of DWARF CFI based on: + + "DWARF for the ARM 64 bit architecture (AArch64) 1.0" +http://infocenter.arm.com/help/topic/com.arm.doc.ihi0057b/IHI0057B_aadwarf64.pdf + + "Procedure Call Standard for the ARM 64 bit Architecture 1.0" +http://infocenter.arm.com/help/topic/com.arm.doc.ihi0055b/IHI0055B_aapcs64.pdf +*/ + +int +aarch64_abi_cfi (Ebl *ebl __attribute__ ((unused)), Dwarf_CIE *abi_info) +{ + static const uint8_t abi_cfi[] = + { + /* The initial Canonical Frame Address is the value of the + Stack Pointer (r31) as setup in the previous frame. */ + DW_CFA_def_cfa, ULEB128_7 (30), ULEB128_7 (0), + +#define SV(n) DW_CFA_same_value, ULEB128_7 (n) + /* Callee-saved regs r19-r28. */ + SV (19), SV (20), SV (21), SV (22), SV (23), + SV (24), SV (25), SV (26), SV (27), SV (28), + + /* The Frame Pointer (FP, r29) and Link Register (LR, r30). */ + SV (29), SV (30), + + /* Callee-saved fpregs v8-v15. v0 == 64. */ + SV (72), SV (73), SV (74), SV (75), + SV (76), SV (77), SV (78), SV (79), +#undef SV + + /* XXX Note: registers intentionally unused by the program, + for example as a consequence of the procedure call standard + should be initialized as if by DW_CFA_same_value. */ + }; + + abi_info->initial_instructions = abi_cfi; + abi_info->initial_instructions_end = &abi_cfi[sizeof abi_cfi]; + abi_info->data_alignment_factor = -4; + + abi_info->return_address_register = 30; /* lr. */ + + return 0; +} diff --git a/backends/aarch64_corenote.c b/backends/aarch64_corenote.c new file mode 100644 index 00000000..8f5b9d5d --- /dev/null +++ b/backends/aarch64_corenote.c @@ -0,0 +1,162 @@ +/* AArch64 specific core note handling. + Copyright (C) 2013 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 <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <elf.h> +#include <inttypes.h> +#include <stddef.h> +#include <stdio.h> +#include <sys/time.h> + +#define BACKEND aarch64_ +#include "libebl_CPU.h" + +#define ULONG uint64_t +#define PID_T int32_t +#define UID_T uint32_t +#define GID_T uint32_t +#define ALIGN_ULONG 8 +#define ALIGN_PID_T 4 +#define ALIGN_UID_T 4 +#define ALIGN_GID_T 4 +#define TYPE_ULONG ELF_T_XWORD +#define TYPE_PID_T ELF_T_SWORD +#define TYPE_UID_T ELF_T_WORD +#define TYPE_GID_T ELF_T_WORD + +#define PRSTATUS_REGS_SIZE (34 * 8) + +static const Ebl_Register_Location prstatus_regs[] = + { + { .offset = 0, .regno = 0, .count = 32, .bits = 64 }, /* x0..x30, sp */ + }; + +#define PRSTATUS_REGSET_ITEMS \ + { \ + .name = "pc", .type = ELF_T_XWORD, .format = 'x', \ + .offset = (offsetof (struct EBLHOOK(prstatus), pr_reg) \ + + PRSTATUS_REGS_SIZE - 16), \ + .group = "register" \ + }, \ + { \ + .name = "pstate", .type = ELF_T_XWORD, .format = 'x', \ + .offset = (offsetof (struct EBLHOOK(prstatus), pr_reg) \ + + PRSTATUS_REGS_SIZE - 8), \ + .group = "register" \ + } + +static const Ebl_Register_Location aarch64_fpregset_regs[] = + { + { .offset = 0, .regno = 64, .count = 32, .bits = 128 }, /* v0..v31 */ + }; + +static const Ebl_Core_Item aarch64_fpregset_items[] = + { + { + .name = "fpsr", .type = ELF_T_WORD, .format = 'x', + .offset = 512, .group = "register" + }, + { + .name = "fpcr", .type = ELF_T_WORD, .format = 'x', + .offset = 516, .group = "register" + } + }; + +static const Ebl_Core_Item aarch64_tls_items[] = + { + { + .name = "tls", .type = ELF_T_XWORD, .format = 'x', + .offset = 0, .group = "register" + } + }; + +#define AARCH64_HWBP_REG(KIND, N) \ + { \ + .name = "DBG" KIND "VR" #N "_EL1", .type = ELF_T_XWORD, .format = 'x', \ + .offset = 8 + N * 16, .group = "register" \ + }, \ + { \ + .name = "DBG" KIND "CR" #N "_EL1", .type = ELF_T_WORD, .format = 'x', \ + .offset = 16 + N * 16, .group = "register" \ + } + +#define AARCH64_BP_WP_GROUP(KIND, NAME) \ + static const Ebl_Core_Item NAME[] = \ + { \ + { \ + .name = "dbg_info", .type = ELF_T_WORD, .format = 'x', \ + .offset = 0, .group = "control" \ + }, \ + /* N.B.: 4 bytes of padding here. */ \ + \ + AARCH64_HWBP_REG(KIND, 0), \ + AARCH64_HWBP_REG(KIND, 1), \ + AARCH64_HWBP_REG(KIND, 2), \ + AARCH64_HWBP_REG(KIND, 3), \ + AARCH64_HWBP_REG(KIND, 4), \ + AARCH64_HWBP_REG(KIND, 5), \ + AARCH64_HWBP_REG(KIND, 6), \ + AARCH64_HWBP_REG(KIND, 7), \ + AARCH64_HWBP_REG(KIND, 8), \ + AARCH64_HWBP_REG(KIND, 9), \ + AARCH64_HWBP_REG(KIND, 10), \ + AARCH64_HWBP_REG(KIND, 11), \ + AARCH64_HWBP_REG(KIND, 12), \ + AARCH64_HWBP_REG(KIND, 13), \ + AARCH64_HWBP_REG(KIND, 14), \ + AARCH64_HWBP_REG(KIND, 15), \ + \ + /* The DBGBVR+DBGBCR pair only takes 12 bytes. There are 4 bytes \ + of padding at the end of each pair. The item formatter in \ + readelf can skip those, but the missing 4 bytes at the end of \ + the whole block cause it to assume the whole item bunch \ + repeats, so it loops around to read more. Insert an explicit \ + (but invisible) padding word. */ \ + { \ + .name = "", .type = ELF_T_WORD, .format = 'h', \ + .offset = 260, .group = "register" \ + } \ + } + +AARCH64_BP_WP_GROUP ("B", aarch64_hw_bp_items); +AARCH64_BP_WP_GROUP ("W", aarch64_hw_wp_items); + +#undef AARCH64_BP_WP_GROUP +#undef AARCH64_HWBP_REG + +#define EXTRA_NOTES \ + EXTRA_REGSET_ITEMS (NT_FPREGSET, 528, \ + aarch64_fpregset_regs, aarch64_fpregset_items) \ + EXTRA_ITEMS (NT_ARM_TLS, 8, aarch64_tls_items) \ + EXTRA_ITEMS (NT_ARM_HW_BREAK, 264, aarch64_hw_bp_items) \ + EXTRA_ITEMS (NT_ARM_HW_WATCH, 264, aarch64_hw_wp_items) + +#include "linux-core-note.c" diff --git a/backends/aarch64_init.c b/backends/aarch64_init.c new file mode 100644 index 00000000..a1a70606 --- /dev/null +++ b/backends/aarch64_init.c @@ -0,0 +1,63 @@ +/* Initialization of AArch64 specific backend library. + Copyright (C) 2013 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 <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#define BACKEND aarch64_ +#define RELOC_PREFIX R_AARCH64_ +#include "libebl_CPU.h" + +/* This defines the common reloc hooks based on aarch64_reloc.def. */ +#include "common-reloc.c" + + +const char * +aarch64_init (elf, machine, eh, ehlen) + Elf *elf __attribute__ ((unused)); + GElf_Half machine __attribute__ ((unused)); + Ebl *eh; + size_t ehlen; +{ + /* Check whether the Elf_BH object has a sufficent size. */ + if (ehlen < sizeof (Ebl)) + return NULL; + + /* We handle it. */ + eh->name = "AARCH64"; + aarch64_init_reloc (eh); + HOOK (eh, register_info); + HOOK (eh, core_note); + HOOK (eh, reloc_simple_type); + HOOK (eh, return_value_location); + HOOK (eh, check_special_symbol); + HOOK (eh, abi_cfi); + + return MODVERSION; +} diff --git a/backends/aarch64_regs.c b/backends/aarch64_regs.c new file mode 100644 index 00000000..aec201f3 --- /dev/null +++ b/backends/aarch64_regs.c @@ -0,0 +1,95 @@ +/* Register names and numbers for AArch64 DWARF. + Copyright (C) 2013 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 <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <stdio.h> +#include <string.h> +#include <dwarf.h> + +#define BACKEND aarch64_ +#include "libebl_CPU.h" + +ssize_t +aarch64_register_info (Ebl *ebl __attribute__ ((unused)), + int regno, char *name, size_t namelen, + const char **prefix, const char **setnamep, + int *bits, int *typep) +{ + if (name == NULL) + return 128; + + ssize_t + regtype (const char *setname, int type, const char *fmt, int arg) + { + *setnamep = setname; + *typep = type; + int s = snprintf (name, namelen, fmt, arg); + if (s < 0 || (unsigned) s >= namelen) + return -1; + return s + 1; + } + + *prefix = ""; + *bits = 64; + + switch (regno) + { + case 0 ... 30: + return regtype ("integer", DW_ATE_signed, "x%d", regno); + + case 31: + return regtype ("integer", DW_ATE_address, "sp", 0); + + case 32: + return 0; + + case 33: + return regtype ("integer", DW_ATE_address, "elr", 0); + + case 34 ... 63: + return 0; + + case 64 ... 95: + /* FP/SIMD register file supports a variety of data types--it + can be thought of as a register holding a single integer or + floating-point value, or a vector of 8-, 16-, 32- or 64-bit + integers. 128-bit quad-word is the only singular value that + covers the whole register, so mark the register thus. */ + *bits = 128; + return regtype ("FP/SIMD", DW_ATE_unsigned, "v%d", regno - 64); + + case 96 ... 127: + return 0; + + default: + return -1; + } +} diff --git a/backends/aarch64_reloc.def b/backends/aarch64_reloc.def new file mode 100644 index 00000000..f6331573 --- /dev/null +++ b/backends/aarch64_reloc.def @@ -0,0 +1,157 @@ +/* List the relocation types for AArch64. -*- C -*- + Copyright (C) 2013 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 <http://www.gnu.org/licenses/>. */ + +/* NAME, REL|EXEC|DYN */ + +RELOC_TYPE (ABS64, EXEC|DYN) +RELOC_TYPE (ABS32, EXEC|DYN) +RELOC_TYPE (COPY, EXEC) +RELOC_TYPE (GLOB_DAT, EXEC|DYN) +RELOC_TYPE (JUMP_SLOT, EXEC|DYN) +RELOC_TYPE (RELATIVE, EXEC|DYN) +RELOC_TYPE (TLS_DTPMOD64, EXEC|DYN) +RELOC_TYPE (TLS_DTPREL64, EXEC|DYN) +RELOC_TYPE (TLS_TPREL64, EXEC|DYN) +RELOC_TYPE (TLSDESC, EXEC|DYN) + +/* R_AARCH64_NONE records that the section containing the place to be + relocated depends on the section defining the symbol mentioned in + the relocation directive[.] (ARM IHI 0056B). */ +RELOC_TYPE (NONE, REL) + +RELOC_TYPE (ABS16, REL) +RELOC_TYPE (PREL64, REL) +RELOC_TYPE (PREL32, REL) +RELOC_TYPE (PREL16, REL) +RELOC_TYPE (MOVW_UABS_G0, REL) +RELOC_TYPE (MOVW_UABS_G0_NC, REL) +RELOC_TYPE (MOVW_UABS_G1, REL) +RELOC_TYPE (MOVW_UABS_G1_NC, REL) +RELOC_TYPE (MOVW_UABS_G2, REL) +RELOC_TYPE (MOVW_UABS_G2_NC, REL) +RELOC_TYPE (MOVW_UABS_G3, REL) +RELOC_TYPE (MOVW_SABS_G0, REL) +RELOC_TYPE (MOVW_SABS_G1, REL) +RELOC_TYPE (MOVW_SABS_G2, REL) +RELOC_TYPE (LD_PREL_LO19, REL) +RELOC_TYPE (ADR_PREL_LO21, REL) +RELOC_TYPE (ADR_PREL_PG_HI21, REL) +RELOC_TYPE (ADR_PREL_PG_HI21_NC, REL) +RELOC_TYPE (ADD_ABS_LO12_NC, REL) +RELOC_TYPE (LDST8_ABS_LO12_NC, REL) +RELOC_TYPE (LDST16_ABS_LO12_NC, REL) +RELOC_TYPE (LDST32_ABS_LO12_NC, REL) +RELOC_TYPE (LDST64_ABS_LO12_NC, REL) +RELOC_TYPE (LDST128_ABS_LO12_NC, REL) +RELOC_TYPE (TSTBR14, REL) +RELOC_TYPE (CONDBR19, REL) +RELOC_TYPE (JUMP26, REL) +RELOC_TYPE (CALL26, REL) +RELOC_TYPE (MOVW_PREL_G0, REL) +RELOC_TYPE (MOVW_PREL_G0_NC, REL) +RELOC_TYPE (MOVW_PREL_G1, REL) +RELOC_TYPE (MOVW_PREL_G1_NC, REL) +RELOC_TYPE (MOVW_PREL_G2, REL) +RELOC_TYPE (MOVW_PREL_G2_NC, REL) +RELOC_TYPE (MOVW_PREL_G3, REL) +RELOC_TYPE (MOVW_GOTOFF_G0, REL) +RELOC_TYPE (MOVW_GOTOFF_G0_NC, REL) +RELOC_TYPE (MOVW_GOTOFF_G1, REL) +RELOC_TYPE (MOVW_GOTOFF_G1_NC, REL) +RELOC_TYPE (MOVW_GOTOFF_G2, REL) +RELOC_TYPE (MOVW_GOTOFF_G2_NC, REL) +RELOC_TYPE (MOVW_GOTOFF_G3, REL) +RELOC_TYPE (GOTREL64, REL) +RELOC_TYPE (GOTREL32, REL) +RELOC_TYPE (GOT_LD_PREL19, REL) +RELOC_TYPE (LD64_GOTOFF_LO15, REL) +RELOC_TYPE (ADR_GOT_PAGE, REL) +RELOC_TYPE (LD64_GOT_LO12_NC, REL) +RELOC_TYPE (LD64_GOTPAGE_LO15, REL) +RELOC_TYPE (TLSGD_ADR_PREL21, REL) +RELOC_TYPE (TLSGD_ADR_PAGE21, REL) +RELOC_TYPE (TLSGD_ADD_LO12_NC, REL) +RELOC_TYPE (TLSGD_MOVW_G1, REL) +RELOC_TYPE (TLSGD_MOVW_G0_NC, REL) +RELOC_TYPE (TLSLD_ADR_PREL21, REL) +RELOC_TYPE (TLSLD_ADR_PAGE21, REL) +RELOC_TYPE (TLSLD_ADD_LO12_NC, REL) +RELOC_TYPE (TLSLD_MOVW_G1, REL) +RELOC_TYPE (TLSLD_MOVW_G0_NC, REL) +RELOC_TYPE (TLSLD_LD_PREL19, REL) +RELOC_TYPE (TLSLD_MOVW_DTPREL_G2, REL) +RELOC_TYPE (TLSLD_MOVW_DTPREL_G1, REL) +RELOC_TYPE (TLSLD_MOVW_DTPREL_G1_NC, REL) +RELOC_TYPE (TLSLD_MOVW_DTPREL_G0, REL) +RELOC_TYPE (TLSLD_MOVW_DTPREL_G0_NC, REL) +RELOC_TYPE (TLSLD_ADD_DTPREL_HI12, REL) +RELOC_TYPE (TLSLD_ADD_DTPREL_LO12, REL) +RELOC_TYPE (TLSLD_ADD_DTPREL_LO12_NC, REL) +RELOC_TYPE (TLSLD_LDST8_DTPREL_LO12, REL) +RELOC_TYPE (TLSLD_LDST8_DTPREL_LO12_NC, REL) +RELOC_TYPE (TLSLD_LDST16_DTPREL_LO12, REL) +RELOC_TYPE (TLSLD_LDST16_DTPREL_LO12_NC, REL) +RELOC_TYPE (TLSLD_LDST32_DTPREL_LO12, REL) +RELOC_TYPE (TLSLD_LDST32_DTPREL_LO12_NC, REL) +RELOC_TYPE (TLSLD_LDST64_DTPREL_LO12, REL) +RELOC_TYPE (TLSLD_LDST64_DTPREL_LO12_NC, REL) +RELOC_TYPE (TLSLD_LDST128_DTPREL_LO12, REL) +RELOC_TYPE (TLSLD_LDST128_DTPREL_LO12_NC, REL) +RELOC_TYPE (TLSIE_MOVW_GOTTPREL_G1, REL) +RELOC_TYPE (TLSIE_MOVW_GOTTPREL_G0_NC, REL) +RELOC_TYPE (TLSIE_ADR_GOTTPREL_PAGE21, REL) +RELOC_TYPE (TLSIE_LD64_GOTTPREL_LO12_NC, REL) +RELOC_TYPE (TLSIE_LD_GOTTPREL_PREL19, REL) +RELOC_TYPE (TLSLE_MOVW_TPREL_G2, REL) +RELOC_TYPE (TLSLE_MOVW_TPREL_G1, REL) +RELOC_TYPE (TLSLE_MOVW_TPREL_G1_NC, REL) +RELOC_TYPE (TLSLE_MOVW_TPREL_G0, REL) +RELOC_TYPE (TLSLE_MOVW_TPREL_G0_NC, REL) +RELOC_TYPE (TLSLE_ADD_TPREL_HI12, REL) +RELOC_TYPE (TLSLE_ADD_TPREL_LO12, REL) +RELOC_TYPE (TLSLE_ADD_TPREL_LO12_NC, REL) +RELOC_TYPE (TLSLE_LDST8_TPREL_LO12, REL) +RELOC_TYPE (TLSLE_LDST8_TPREL_LO12_NC, REL) +RELOC_TYPE (TLSLE_LDST16_TPREL_LO12, REL) +RELOC_TYPE (TLSLE_LDST16_TPREL_LO12_NC, REL) +RELOC_TYPE (TLSLE_LDST32_TPREL_LO12, REL) +RELOC_TYPE (TLSLE_LDST32_TPREL_LO12_NC, REL) +RELOC_TYPE (TLSLE_LDST64_TPREL_LO12, REL) +RELOC_TYPE (TLSLE_LDST64_TPREL_LO12_NC, REL) +RELOC_TYPE (TLSLE_LDST128_TPREL_LO12, REL) +RELOC_TYPE (TLSLE_LDST128_TPREL_LO12_NC, REL) +RELOC_TYPE (TLSDESC_LD_PREL19, REL) +RELOC_TYPE (TLSDESC_ADR_PREL21, REL) +RELOC_TYPE (TLSDESC_ADR_PAGE21, REL) +RELOC_TYPE (TLSDESC_LD64_LO12, REL) +RELOC_TYPE (TLSDESC_ADD_LO12, REL) +RELOC_TYPE (TLSDESC_OFF_G1, REL) +RELOC_TYPE (TLSDESC_OFF_G0_NC, REL) +RELOC_TYPE (TLSDESC_LDR, REL) +RELOC_TYPE (TLSDESC_ADD, REL) +RELOC_TYPE (TLSDESC_CALL, REL) diff --git a/backends/aarch64_retval.c b/backends/aarch64_retval.c new file mode 100644 index 00000000..0ed7d561 --- /dev/null +++ b/backends/aarch64_retval.c @@ -0,0 +1,375 @@ +/* Function return value location for Linux/AArch64 ABI. + Copyright (C) 2013 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 <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <stdio.h> +#include <inttypes.h> + +#include <assert.h> +#include <dwarf.h> + +#define BACKEND aarch64_ +#include "libebl_CPU.h" + +static int +skip_until (Dwarf_Die *child, int tag) +{ + int i; + while (DWARF_TAG_OR_RETURN (child) != tag) + if ((i = dwarf_siblingof (child, child)) != 0) + /* If there are no members, then this is not a HFA. Errors + are propagated. */ + return i; + return 0; +} + +static int +dwarf_bytesize_aux (Dwarf_Die *die, Dwarf_Word *sizep) +{ + int bits; + if (((bits = 8 * dwarf_bytesize (die)) < 0 + && (bits = dwarf_bitsize (die)) < 0) + || bits % 8 != 0) + return -1; + + *sizep = bits / 8; + return 0; +} + +/* HFA (Homogeneous Floating-point Aggregate) is an aggregate type + whose members are all of the same floating-point type, which is + then base type of this HFA. Instead of being floating-point types + directly, members can instead themselves be HFA. Such HFA fields + are handled as if their type were HFA base type. + + This function returns 0 if TYPEDIE is HFA, 1 if it is not, or -1 if + there were errors. In the former case, *SIZEP contains byte size + of the base type (e.g. 8 for IEEE double). *COUNT is set to the + number of leaf members of the HFA. */ +static int hfa_type (Dwarf_Die *ftypedie, int tag, + Dwarf_Word *sizep, Dwarf_Word *countp); + +/* Return 0 if MEMBDIE refers to a member with a floating-point or HFA + type, or 1 if it's not. Return -1 for errors. The meaning of the + remaining arguments is as documented at hfa_type. */ +static int +member_is_fp (Dwarf_Die *membdie, Dwarf_Word *sizep, Dwarf_Word *countp) +{ + Dwarf_Die typedie; + int tag = dwarf_peeled_die_type (membdie, &typedie); + switch (tag) + { + case DW_TAG_base_type:; + Dwarf_Word encoding; + Dwarf_Attribute attr_mem; + if (dwarf_attr_integrate (&typedie, DW_AT_encoding, &attr_mem) == NULL + || dwarf_formudata (&attr_mem, &encoding) != 0) + return -1; + + switch (encoding) + { + case DW_ATE_complex_float: + *countp = 2; + break; + + case DW_ATE_float: + *countp = 1; + break; + + default: + return 1; + } + + if (dwarf_bytesize_aux (&typedie, sizep) < 0) + return -1; + + *sizep /= *countp; + return 0; + + case DW_TAG_structure_type: + case DW_TAG_union_type: + case DW_TAG_array_type: + return hfa_type (&typedie, tag, sizep, countp); + } + + return 1; +} + +static int +hfa_type (Dwarf_Die *ftypedie, int tag, Dwarf_Word *sizep, Dwarf_Word *countp) +{ + assert (tag == DW_TAG_structure_type || tag == DW_TAG_class_type + || tag == DW_TAG_union_type || tag == DW_TAG_array_type); + + int i; + if (tag == DW_TAG_array_type) + { + Dwarf_Word tot_size; + if (dwarf_aggregate_size (ftypedie, &tot_size) < 0) + return -1; + + /* For vector types, we don't care about the underlying + type, but only about the vector type itself. */ + bool vec; + Dwarf_Attribute attr_mem; + if (dwarf_formflag (dwarf_attr_integrate (ftypedie, DW_AT_GNU_vector, + &attr_mem), &vec) == 0 + && vec) + { + *sizep = tot_size; + *countp = 1; + + return 0; + } + + if ((i = member_is_fp (ftypedie, sizep, countp)) == 0) + { + *countp = tot_size / *sizep; + return 0; + } + + return i; + } + + /* Find first DW_TAG_member and determine its type. */ + Dwarf_Die member; + if ((i = dwarf_child (ftypedie, &member) != 0)) + return i; + + if ((i = skip_until (&member, DW_TAG_member)) != 0) + return i; + + *countp = 0; + if ((i = member_is_fp (&member, sizep, countp)) != 0) + return i; + + while ((i = dwarf_siblingof (&member, &member)) == 0 + && (i = skip_until (&member, DW_TAG_member)) == 0) + { + Dwarf_Word size, count; + if ((i = member_is_fp (&member, &size, &count)) != 0) + return i; + + if (*sizep != size) + return 1; + + *countp += count; + } + + /* At this point we already have at least one FP member, which means + FTYPEDIE is an HFA. So either return 0, or propagate error. */ + return i < 0 ? i : 0; +} + +static int +pass_in_gpr (const Dwarf_Op **locp, Dwarf_Word size) +{ + static const Dwarf_Op loc[] = + { + { .atom = DW_OP_reg0 }, { .atom = DW_OP_piece, .number = 8 }, + { .atom = DW_OP_reg1 }, { .atom = DW_OP_piece, .number = 8 } + }; + + *locp = loc; + return size <= 8 ? 1 : 4; +} + +static int +pass_by_ref (const Dwarf_Op **locp) +{ + static const Dwarf_Op loc[] = { { .atom = DW_OP_breg0 } }; + + *locp = loc; + return 1; +} + +static int +pass_hfa (const Dwarf_Op **locp, Dwarf_Word size, Dwarf_Word count) +{ + assert (count >= 1 && count <= 4); + assert (size == 2 || size == 4 || size == 8 || size == 16); + +#define DEFINE_FPREG(NAME, SIZE) \ + static const Dwarf_Op NAME[] = { \ + { .atom = DW_OP_regx, .number = 64 }, \ + { .atom = DW_OP_piece, .number = SIZE }, \ + { .atom = DW_OP_regx, .number = 65 }, \ + { .atom = DW_OP_piece, .number = SIZE }, \ + { .atom = DW_OP_regx, .number = 66 }, \ + { .atom = DW_OP_piece, .number = SIZE }, \ + { .atom = DW_OP_regx, .number = 67 }, \ + { .atom = DW_OP_piece, .number = SIZE } \ + } + + switch (size) + { + case 2:; + DEFINE_FPREG (loc_hfa_2, 2); + *locp = loc_hfa_2; + break; + + case 4:; + DEFINE_FPREG (loc_hfa_4, 4); + *locp = loc_hfa_4; + break; + + case 8:; + DEFINE_FPREG (loc_hfa_8, 8); + *locp = loc_hfa_8; + break; + + case 16:; + DEFINE_FPREG (loc_hfa_16, 16); + *locp = loc_hfa_16; + break; + } +#undef DEFINE_FPREG + + return count == 1 ? 1 : 2 * count; +} + +static int +pass_in_simd (const Dwarf_Op **locp) +{ + /* This is like passing single-element HFA. Size doesn't matter, so + pretend it's for example double. */ + return pass_hfa (locp, 8, 1); +} + +int +aarch64_return_value_location (Dwarf_Die *functypedie, const Dwarf_Op **locp) +{ + /* Start with the function's type, and get the DW_AT_type attribute, + which is the type of the return value. */ + Dwarf_Die typedie; + int tag = dwarf_peeled_die_type (functypedie, &typedie); + if (tag <= 0) + return tag; + + Dwarf_Word size = (Dwarf_Word)-1; + + /* If the argument type is a Composite Type that is larger than 16 + bytes, then the argument is copied to memory allocated by the + caller and the argument is replaced by a pointer to the copy. */ + if (tag == DW_TAG_structure_type || tag == DW_TAG_union_type + || tag == DW_TAG_class_type || tag == DW_TAG_array_type) + { + Dwarf_Word base_size, count; + switch (hfa_type (&typedie, tag, &base_size, &count)) + { + default: + return -1; + + case 0: + assert (count > 0); + if (count <= 4) + return pass_hfa (locp, base_size, count); + /* Fall through. */ + + case 1: + /* Not a HFA. */ + if (dwarf_aggregate_size (&typedie, &size) < 0) + return -1; + if (size > 16) + return pass_by_ref (locp); + } + } + + if (tag == DW_TAG_base_type + || tag == DW_TAG_pointer_type || tag == DW_TAG_ptr_to_member_type) + { + if (dwarf_bytesize_aux (&typedie, &size) < 0) + { + if (tag == DW_TAG_pointer_type || tag == DW_TAG_ptr_to_member_type) + size = 8; + else + return -1; + } + + Dwarf_Attribute attr_mem; + 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; + + switch (encoding) + { + /* If the argument is a Half-, Single-, Double- or Quad- + precision Floating-point [...] the argument is allocated + to the least significant bits of register v[NSRN]. */ + case DW_ATE_float: + switch (size) + { + case 2: /* half */ + case 4: /* sigle */ + case 8: /* double */ + case 16: /* quad */ + return pass_in_simd (locp); + + default: + return -2; + } + + case DW_ATE_complex_float: + switch (size) + { + case 8: /* float _Complex */ + case 16: /* double _Complex */ + case 32: /* long double _Complex */ + return pass_hfa (locp, size / 2, 2); + + default: + return -2; + } + + /* If the argument is an Integral or Pointer Type, the + size of the argument is less than or equal to 8 bytes + [...] the argument is copied to the least significant + bits in x[NGRN]. */ + case DW_ATE_signed: + case DW_ATE_unsigned: + case DW_ATE_unsigned_char: + case DW_ATE_signed_char: + return pass_in_gpr (locp, size); + } + + return -2; + } + else + return pass_in_gpr (locp, size); + } + + *locp = NULL; + return 0; +} diff --git a/backends/aarch64_symbol.c b/backends/aarch64_symbol.c new file mode 100644 index 00000000..e41a7a7d --- /dev/null +++ b/backends/aarch64_symbol.c @@ -0,0 +1,84 @@ +/* AArch64 specific symbolic name handling. + Copyright (C) 2013 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 <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <elf.h> +#include <stddef.h> +#include <string.h> + +#define BACKEND aarch64_ +#include "libebl_CPU.h" + + +/* Check for the simple reloc types. */ +Elf_Type +aarch64_reloc_simple_type (Ebl *ebl __attribute__ ((unused)), int type) +{ + switch (type) + { + case R_AARCH64_ABS64: + return ELF_T_XWORD; + case R_AARCH64_ABS32: + return ELF_T_WORD; + case R_AARCH64_ABS16: + return ELF_T_HALF; + + default: + return ELF_T_NUM; + } +} + +/* If this is the _GLOBAL_OFFSET_TABLE_ symbol, then it should point to + .got[0] even if there is a .got.plt section. */ +bool +aarch64_check_special_symbol (Elf *elf, GElf_Ehdr *ehdr, const GElf_Sym *sym, + const char *name, const GElf_Shdr *destshdr) +{ + if (name != NULL + && strcmp (name, "_GLOBAL_OFFSET_TABLE_") == 0) + { + const char *sname = elf_strptr (elf, ehdr->e_shstrndx, destshdr->sh_name); + if (sname != NULL && strcmp (sname, ".got.plt") == 0) + { + Elf_Scn *scn = NULL; + while ((scn = elf_nextscn (elf, scn)) != NULL) + { + GElf_Shdr shdr_mem; + GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem); + sname = elf_strptr (elf, ehdr->e_shstrndx, shdr->sh_name); + if (sname != NULL && strcmp (sname, ".got") == 0) + return sym->st_value == shdr->sh_addr; + } + } + } + + return false; +} diff --git a/backends/i386_init.c b/backends/i386_init.c index cc9b2d7f..1e0b4863 100644 --- a/backends/i386_init.c +++ b/backends/i386_init.c @@ -1,5 +1,5 @@ /* Initialization of i386 specific backend library. - Copyright (C) 2000-2009 Red Hat, Inc. + Copyright (C) 2000-2009, 2013 Red Hat, Inc. This file is part of elfutils. Written by Ulrich Drepper <[email protected]>, 2000. @@ -63,6 +63,9 @@ i386_init (elf, machine, eh, ehlen) HOOK (eh, auxv_info); HOOK (eh, disasm); HOOK (eh, abi_cfi); + /* gcc/config/ #define DWARF_FRAME_REGISTERS. For i386 it is 17, why? */ + eh->frame_nregs = 9; + HOOK (eh, set_initial_registers_tid); return MODVERSION; } diff --git a/backends/i386_initreg.c b/backends/i386_initreg.c new file mode 100644 index 00000000..9e819a47 --- /dev/null +++ b/backends/i386_initreg.c @@ -0,0 +1,79 @@ +/* Fetch live process registers from TID. + Copyright (C) 2013 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 <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#if defined __i386__ || defined __x86_64__ +# include <sys/types.h> +# include <sys/user.h> +# include <sys/ptrace.h> +#endif + +#define BACKEND i386_ +#include "libebl_CPU.h" + +bool +i386_set_initial_registers_tid (pid_t tid __attribute__ ((unused)), + ebl_tid_registers_t *setfunc __attribute__ ((unused)), + void *arg __attribute__ ((unused))) +{ +#if !defined __i386__ && !defined __x86_64__ + return false; +#else /* __i386__ || __x86_64__ */ + struct user_regs_struct user_regs; + if (ptrace (PTRACE_GETREGS, tid, NULL, &user_regs) != 0) + return false; + Dwarf_Word dwarf_regs[9]; +# if defined __i386__ + dwarf_regs[0] = user_regs.eax; + dwarf_regs[1] = user_regs.ecx; + dwarf_regs[2] = user_regs.edx; + dwarf_regs[3] = user_regs.ebx; + dwarf_regs[4] = user_regs.esp; + dwarf_regs[5] = user_regs.ebp; + dwarf_regs[6] = user_regs.esi; + dwarf_regs[7] = user_regs.edi; + dwarf_regs[8] = user_regs.eip; +# elif defined __x86_64__ + dwarf_regs[0] = user_regs.rax; + dwarf_regs[1] = user_regs.rcx; + dwarf_regs[2] = user_regs.rdx; + dwarf_regs[3] = user_regs.rbx; + dwarf_regs[4] = user_regs.rsp; + dwarf_regs[5] = user_regs.rbp; + dwarf_regs[6] = user_regs.rsi; + dwarf_regs[7] = user_regs.rdi; + dwarf_regs[8] = user_regs.rip; +# else /* (__i386__ || __x86_64__) && (!__i386__ && !__x86_64__) */ +# error "source file error, it cannot happen" +# endif /* (__i386__ || __x86_64__) && (!__i386__ && !__x86_64__) */ + return setfunc (0, 9, dwarf_regs, arg); +#endif /* __i386__ || __x86_64__ */ +} diff --git a/backends/libebl_CPU.h b/backends/libebl_CPU.h index 09c8cd10..3ad92588 100644 --- a/backends/libebl_CPU.h +++ b/backends/libebl_CPU.h @@ -1,5 +1,5 @@ /* Common interface for libebl modules. - Copyright (C) 2000, 2001, 2002, 2003, 2005 Red Hat, Inc. + Copyright (C) 2000, 2001, 2002, 2003, 2005, 2013 Red Hat, Inc. This file is part of elfutils. This file is free software; you can redistribute it and/or modify @@ -29,6 +29,7 @@ #ifndef _LIBEBL_CPU_H #define _LIBEBL_CPU_H 1 +#include <dwarf.h> #include <libeblP.h> #define EBLHOOK(name) EBLHOOK_1(BACKEND, name) @@ -52,4 +53,38 @@ extern bool (*generic_debugscn_p) (const char *) attribute_hidden; if (_die == NULL) return -1; \ dwarf_tag (_die); }) +/* Follow typedefs and qualifiers to get to the actual type. */ +static inline int +dwarf_peel_type (Dwarf_Die *typediep, Dwarf_Attribute *attrp) +{ + int tag = DWARF_TAG_OR_RETURN (typediep); + while (tag == DW_TAG_typedef + || tag == DW_TAG_const_type || tag == DW_TAG_volatile_type + || tag == DW_TAG_restrict_type || tag == DW_TAG_mutable_type) + { + attrp = dwarf_attr_integrate (typediep, DW_AT_type, attrp); + typediep = dwarf_formref_die (attrp, typediep); + tag = DWARF_TAG_OR_RETURN (typediep); + } + + return tag; +} + +/* Get a type die corresponding to DIE. Peel CV qualifiers off + it. */ +static inline int +dwarf_peeled_die_type (Dwarf_Die *die, Dwarf_Die *result) +{ + Dwarf_Attribute attr_mem; + Dwarf_Attribute *attr = dwarf_attr_integrate (die, DW_AT_type, &attr_mem); + if (attr == NULL) + /* The function has no return value, like a `void' function in C. */ + return 0; + + if (dwarf_formref_die (attr, result) == NULL) + return -1; + + return dwarf_peel_type (result, attr); +} + #endif /* libebl_CPU.h */ diff --git a/backends/ppc64_init.c b/backends/ppc64_init.c index 14358754..d8f1417e 100644 --- a/backends/ppc64_init.c +++ b/backends/ppc64_init.c @@ -31,6 +31,8 @@ # include <config.h> #endif +#include <string.h> + #define BACKEND ppc64_ #define RELOC_PREFIX R_PPC64_ #include "libebl_CPU.h" @@ -65,6 +67,38 @@ ppc64_init (elf, machine, eh, ehlen) HOOK (eh, core_note); HOOK (eh, auxv_info); HOOK (eh, abi_cfi); + /* gcc/config/ #define DWARF_FRAME_REGISTERS. */ + eh->frame_nregs = (114 - 1) + 32; + HOOK (eh, set_initial_registers_tid); + HOOK (eh, dwarf_to_regno); + HOOK (eh, resolve_sym_value); + + /* Find the function descriptor .opd table for resolve_sym_value. */ + if (elf != NULL) + { + GElf_Ehdr ehdr_mem, *ehdr = gelf_getehdr (elf, &ehdr_mem); + if (ehdr != NULL && ehdr->e_type != ET_REL) + { + /* We could also try through DT_PPC64_OPD and DT_PPC64_OPDSZ. */ + GElf_Shdr opd_shdr_mem, *opd_shdr; + Elf_Scn *scn = NULL; + while ((scn = elf_nextscn (elf, scn)) != NULL) + { + opd_shdr = gelf_getshdr (scn, &opd_shdr_mem); + if (opd_shdr != NULL + && (opd_shdr->sh_flags & SHF_ALLOC) != 0 + && opd_shdr->sh_type == SHT_PROGBITS + && opd_shdr->sh_size > 0 + && strcmp (elf_strptr (elf, ehdr->e_shstrndx, + opd_shdr->sh_name), ".opd") == 0) + { + eh->fd_addr = opd_shdr->sh_addr; + eh->fd_data = elf_getdata (scn, NULL); + break; + } + } + } + } return MODVERSION; } diff --git a/backends/ppc64_resolve_sym.c b/backends/ppc64_resolve_sym.c new file mode 100644 index 00000000..03f65584 --- /dev/null +++ b/backends/ppc64_resolve_sym.c @@ -0,0 +1,63 @@ +/* Resolve symbol values through .opd function descriptors. + Copyright (C) 2013 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 <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#define BACKEND ppc64_ +#include "libebl_CPU.h" + +/* Resolve a function descriptor if addr points into the .opd section. + The .opd section contains function descriptors consisting of 3 addresses. + function, toc and chain. We are just interested in the first. + http://refspecs.linuxfoundation.org/ELF/ppc64/PPC-elf64abi-1.9.html#FUNC-DES + + Returns true if the given address could be resolved, false otherwise. +*/ +bool +ppc64_resolve_sym_value (Ebl *ebl, GElf_Addr *addr) +{ + if (ebl->fd_data != NULL && *addr >= ebl->fd_addr + && *addr + sizeof (Elf64_Addr) <= ebl->fd_addr + ebl->fd_data->d_size) + { + GElf_Ehdr ehdr_mem, *ehdr = gelf_getehdr (ebl->elf, &ehdr_mem); + if (ehdr != NULL) + { + Elf_Data opd_in, opd_out; + opd_in.d_buf = ebl->fd_data->d_buf + (*addr - ebl->fd_addr); + opd_out.d_buf = addr; + opd_out.d_size = opd_in.d_size = sizeof (Elf64_Addr); + opd_out.d_type = opd_in.d_type = ELF_T_ADDR; + if (elf64_xlatetom (&opd_out, &opd_in, + ehdr->e_ident[EI_DATA]) != NULL) + return true; + } + } + return false; +} diff --git a/backends/ppc_cfi.c b/backends/ppc_cfi.c index 6a4f4619..55169aef 100644 --- a/backends/ppc_cfi.c +++ b/backends/ppc_cfi.c @@ -44,7 +44,7 @@ ppc_abi_cfi (Ebl *ebl __attribute__ ((unused)), Dwarf_CIE *abi_info) DW_CFA_def_cfa, ULEB128_7 (1), ULEB128_7 (0) */ /* r1 is assumed to be restored from cfa adress, r1 acts as a stack frame pointer. */ - DW_CFA_val_expression, ULEB128_7 (1), ULEB128_7 (1), DW_OP_nop, + DW_CFA_val_offset, ULEB128_7 (1), ULEB128_7 (0), /* lr is not callee-saved but it needs to be preserved as it is pre-set by the caller. */ DW_CFA_same_value, ULEB128_7 (65), /* lr */ diff --git a/backends/ppc_corenote.c b/backends/ppc_corenote.c index 707a3954..9ac88712 100644 --- a/backends/ppc_corenote.c +++ b/backends/ppc_corenote.c @@ -123,7 +123,7 @@ static const Ebl_Register_Location spe_regs[] = { \ .name = "nip", .type = ELF_T_ADDR, .format = 'x', \ .offset = offsetof (struct EBLHOOK(prstatus), pr_reg[32]), \ - .group = "register" \ + .group = "register", .pc_register = true \ }, \ { \ .name = "orig_gpr3", .type = TYPE_LONG, .format = 'd', \ diff --git a/backends/ppc_init.c b/backends/ppc_init.c index 004c6016..ad92765c 100644 --- a/backends/ppc_init.c +++ b/backends/ppc_init.c @@ -65,6 +65,10 @@ ppc_init (elf, machine, eh, ehlen) HOOK (eh, auxv_info); HOOK (eh, check_object_attribute); HOOK (eh, abi_cfi); + /* gcc/config/ #define DWARF_FRAME_REGISTERS. */ + eh->frame_nregs = (114 - 1) + 32; + HOOK (eh, set_initial_registers_tid); + HOOK (eh, dwarf_to_regno); return MODVERSION; } diff --git a/backends/ppc_initreg.c b/backends/ppc_initreg.c new file mode 100644 index 00000000..64f53793 --- /dev/null +++ b/backends/ppc_initreg.c @@ -0,0 +1,114 @@ +/* Fetch live process registers from TID. + Copyright (C) 2013 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 <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include "system.h" +#include <stdlib.h> +#ifdef __powerpc__ +# include <sys/user.h> +# include <sys/ptrace.h> +#endif + +#define BACKEND ppc_ +#include "libebl_CPU.h" + +bool +ppc_dwarf_to_regno (Ebl *ebl __attribute__ ((unused)), unsigned *regno) +{ + switch (*regno) + { + case 108: + // LR uses both 65 and 108 numbers, there is no consistency for it. + *regno = 65; + return true; + case 0 ... 107: + case 109 ... (114 - 1) -1: + return true; + case 1200 ... 1231: + *regno = *regno - 1200 + (114 - 1); + return true; + default: + return false; + } + abort (); +} + +__typeof (ppc_dwarf_to_regno) + ppc64_dwarf_to_regno + __attribute__ ((alias ("ppc_dwarf_to_regno"))); + +bool +ppc_set_initial_registers_tid (pid_t tid __attribute__ ((unused)), + ebl_tid_registers_t *setfunc __attribute__ ((unused)), + void *arg __attribute__ ((unused))) +{ +#ifndef __powerpc__ + return false; +#else /* __powerpc__ */ + union + { + struct pt_regs r; + long l[sizeof (struct pt_regs) / sizeof (long)]; + } + user_regs; + eu_static_assert (sizeof (struct pt_regs) % sizeof (long) == 0); + /* PTRACE_GETREGS is EIO on kernel-2.6.18-308.el5.ppc64. */ + errno = 0; + for (unsigned regno = 0; regno < sizeof (user_regs) / sizeof (long); + regno++) + { + user_regs.l[regno] = ptrace (PTRACE_PEEKUSER, tid, + (void *) (uintptr_t) (regno + * sizeof (long)), + NULL); + if (errno != 0) + return false; + } + const size_t gprs = sizeof (user_regs.r.gpr) / sizeof (*user_regs.r.gpr); + Dwarf_Word dwarf_regs[gprs]; + for (unsigned gpr = 0; gpr < gprs; gpr++) + dwarf_regs[gpr] = user_regs.r.gpr[gpr]; + if (! setfunc (0, gprs, dwarf_regs, arg)) + return false; + dwarf_regs[0] = user_regs.r.link; + // LR uses both 65 and 108 numbers, there is no consistency for it. + if (! setfunc (65, 1, dwarf_regs, arg)) + return false; + /* Registers like msr, ctr, xer, dar, dsisr etc. are probably irrelevant + for CFI. */ + dwarf_regs[0] = user_regs.r.nip; + return setfunc (-1, 1, dwarf_regs, arg); +#endif /* __powerpc__ */ +} + +__typeof (ppc_set_initial_registers_tid) + ppc64_set_initial_registers_tid + __attribute__ ((alias ("ppc_set_initial_registers_tid"))); diff --git a/backends/s390_corenote.c b/backends/s390_corenote.c index b88c05cf..7ca35168 100644 --- a/backends/s390_corenote.c +++ b/backends/s390_corenote.c @@ -47,13 +47,13 @@ static const Ebl_Register_Location prstatus_regs[] = { -#define GR(at, n, dwreg, b) \ +#define GR(at, n, dwreg, b...) \ { .offset = at * BITS/8, .regno = dwreg, .count = n, .bits = b } - GR ( 0, 1, 64, BITS), /* pswm */ - GR ( 1, 1, 65, BITS), /* pswa */ - GR ( 2, 16, 0, BITS), /* r0-r15 */ - GR (18, 16, 48, 32), /* ar0-ar15 */ + GR ( 0, 1, 64, BITS), /* pswm */ + GR ( 1, 1, 65, BITS, .pc_register = true ), /* pswa */ + GR ( 2, 16, 0, BITS), /* r0-r15 */ + GR (18, 16, 48, 32), /* ar0-ar15 */ #undef GR }; diff --git a/backends/s390_init.c b/backends/s390_init.c index 630a2ee3..26b20b49 100644 --- a/backends/s390_init.c +++ b/backends/s390_init.c @@ -62,6 +62,15 @@ s390_init (elf, machine, eh, ehlen) else HOOK (eh, core_note); HOOK (eh, abi_cfi); + /* gcc/config/ #define DWARF_FRAME_REGISTERS 34. + But from the gcc/config/s390/s390.h "Register usage." comment it looks as + if #32 (Argument pointer) and #33 (Condition code) are not used for + unwinding. */ + eh->frame_nregs = 32; + HOOK (eh, set_initial_registers_tid); + if (eh->class == ELFCLASS32) + HOOK (eh, normalize_pc); + HOOK (eh, unwind); /* Only the 64-bit format uses the incorrect hash table entry size. */ if (eh->class == ELFCLASS64) diff --git a/backends/s390_initreg.c b/backends/s390_initreg.c new file mode 100644 index 00000000..b4c4b67c --- /dev/null +++ b/backends/s390_initreg.c @@ -0,0 +1,95 @@ +/* Fetch live process registers from TID. + Copyright (C) 2013 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 <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include "system.h" +#include <assert.h> +#ifdef __s390__ +# include <sys/user.h> +# include <asm/ptrace.h> +# include <sys/ptrace.h> +#endif + +#define BACKEND s390_ +#include "libebl_CPU.h" + +bool +s390_set_initial_registers_tid (pid_t tid __attribute__ ((unused)), + ebl_tid_registers_t *setfunc __attribute__ ((unused)), + void *arg __attribute__ ((unused))) +{ +#ifndef __s390__ + return false; +#else /* __s390__ */ + struct user user_regs; + ptrace_area parea; + parea.process_addr = (uintptr_t) &user_regs; + parea.kernel_addr = 0; + parea.len = sizeof (user_regs); + if (ptrace (PTRACE_PEEKUSR_AREA, tid, &parea, NULL) != 0) + return false; + /* If we run as s390x we get the 64-bit registers of tid. + But -m31 executable seems to use only the 32-bit parts of its + registers so we ignore the upper half. */ + Dwarf_Word dwarf_regs[16]; + for (unsigned u = 0; u < 16; u++) + dwarf_regs[u] = user_regs.regs.gprs[u]; + if (! setfunc (0, 16, dwarf_regs, arg)) + return false; + /* Avoid conversion double -> integer. */ + eu_static_assert (sizeof user_regs.regs.fp_regs.fprs[0] + == sizeof dwarf_regs[0]); + for (unsigned u = 0; u < 16; u++) + { + // Store the double bits as is in the Dwarf_Word without conversion. + union + { + double d; + Dwarf_Word w; + } fpr = { .d = user_regs.regs.fp_regs.fprs[u] }; + dwarf_regs[u] = fpr.w; + } + + if (! setfunc (16, 16, dwarf_regs, arg)) + return false; + dwarf_regs[0] = user_regs.regs.psw.addr; + return setfunc (-1, 1, dwarf_regs, arg); +#endif /* __s390__ */ +} + +void +s390_normalize_pc (Ebl *ebl __attribute__ ((unused)), Dwarf_Addr *pc) +{ + assert (ebl->class == ELFCLASS32); + + /* Clear S390 bit 31. */ + *pc &= (1U << 31) - 1; +} diff --git a/backends/s390_unwind.c b/backends/s390_unwind.c new file mode 100644 index 00000000..752bc287 --- /dev/null +++ b/backends/s390_unwind.c @@ -0,0 +1,139 @@ +/* Get previous frame state for an existing frame state. + Copyright (C) 2013 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 <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <stdlib.h> +#include <assert.h> + +#define BACKEND s390_ +#include "libebl_CPU.h" + +/* s390/s390x do not annotate signal handler frame by CFI. It would be also + difficult as PC points into a stub built on stack. Function below is called + only if unwinder could not find CFI. Function then verifies the register + state for this frame really belongs to a signal frame. In such case it + fetches original registers saved by the signal frame. */ + +bool +s390_unwind (Ebl *ebl, Dwarf_Addr pc, ebl_tid_registers_t *setfunc, + ebl_tid_registers_get_t *getfunc, ebl_pid_memory_read_t *readfunc, + void *arg, bool *signal_framep) +{ + /* Caller already assumed caller adjustment but S390 instructions are 4 bytes + long. Undo it. */ + if ((pc & 0x3) != 0x3) + return false; + pc++; + /* We can assume big-endian read here. */ + Dwarf_Word instr; + if (! readfunc (pc, &instr, arg)) + return false; + /* Fetch only the very first two bytes. */ + instr = (instr >> (ebl->class == ELFCLASS64 ? 48 : 16)) & 0xffff; + /* See GDB s390_sigtramp_frame_sniffer. */ + /* Check for 'svc' as the first instruction. */ + if (((instr >> 8) & 0xff) != 0x0a) + return false; + /* Check for 'sigreturn' or 'rt_sigreturn' as the second instruction. */ + if ((instr & 0xff) != 119 && (instr & 0xff) != 173) + return false; + /* See GDB s390_sigtramp_frame_unwind_cache. */ + Dwarf_Word this_sp; + if (! getfunc (0 + 15, 1, &this_sp, arg)) + return false; + unsigned word_size = ebl->class == ELFCLASS64 ? 8 : 4; + Dwarf_Addr next_cfa = this_sp + 16 * word_size + 32; + /* "New-style RT frame" is not supported, + assuming "Old-style RT frame and all non-RT frames". + Pointer to the array of saved registers is at NEXT_CFA + 8. */ + Dwarf_Word sigreg_ptr; + if (! readfunc (next_cfa + 8, &sigreg_ptr, arg)) + return false; + /* Skip PSW mask. */ + sigreg_ptr += word_size; + /* Read PSW address. */ + Dwarf_Word val; + if (! readfunc (sigreg_ptr, &val, arg)) + return false; + if (! setfunc (-1, 1, &val, arg)) + return false; + sigreg_ptr += word_size; + /* Then the GPRs. */ + Dwarf_Word gprs[16]; + for (int i = 0; i < 16; i++) + { + if (! readfunc (sigreg_ptr, &gprs[i], arg)) + return false; + sigreg_ptr += word_size; + } + /* Then the ACRs. Skip them, they are not used in CFI. */ + for (int i = 0; i < 16; i++) + sigreg_ptr += 4; + /* The floating-point control word. */ + sigreg_ptr += 8; + /* And finally the FPRs. */ + Dwarf_Word fprs[16]; + for (int i = 0; i < 16; i++) + { + if (! readfunc (sigreg_ptr, &val, arg)) + return false; + if (ebl->class == ELFCLASS32) + { + Dwarf_Addr val_low; + if (! readfunc (sigreg_ptr + 4, &val_low, arg)) + return false; + val = (val << 32) | val_low; + } + fprs[i] = val; + sigreg_ptr += 8; + } + /* If we have them, the GPR upper halves are appended at the end. */ + if (ebl->class == ELFCLASS32) + { + /* Skip signal number. */ + sigreg_ptr += 4; + for (int i = 0; i < 16; i++) + { + if (! readfunc (sigreg_ptr, &val, arg)) + return false; + Dwarf_Word val_low = gprs[i]; + val = (val << 32) | val_low; + gprs[i] = val; + sigreg_ptr += 4; + } + } + if (! setfunc (0, 16, gprs, arg)) + return false; + if (! setfunc (16, 16, fprs, arg)) + return false; + *signal_framep = true; + return true; +} diff --git a/backends/x86_64_init.c b/backends/x86_64_init.c index 67a58804..b885558b 100644 --- a/backends/x86_64_init.c +++ b/backends/x86_64_init.c @@ -1,5 +1,5 @@ /* Initialization of x86-64 specific backend library. - Copyright (C) 2002-2009 Red Hat, Inc. + Copyright (C) 2002-2009, 2013 Red Hat, Inc. This file is part of elfutils. Written by Ulrich Drepper <[email protected]>, 2002. @@ -60,6 +60,9 @@ x86_64_init (elf, machine, eh, ehlen) HOOK (eh, auxv_info); HOOK (eh, disasm); HOOK (eh, abi_cfi); + /* gcc/config/ #define DWARF_FRAME_REGISTERS. */ + eh->frame_nregs = 17; + HOOK (eh, set_initial_registers_tid); return MODVERSION; } diff --git a/backends/x86_64_initreg.c b/backends/x86_64_initreg.c new file mode 100644 index 00000000..0c493640 --- /dev/null +++ b/backends/x86_64_initreg.c @@ -0,0 +1,73 @@ +/* Fetch live process registers from TID. + Copyright (C) 2013 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 <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <stdlib.h> +#ifdef __x86_64__ +# include <sys/user.h> +# include <sys/ptrace.h> +#endif + +#define BACKEND x86_64_ +#include "libebl_CPU.h" + +bool +x86_64_set_initial_registers_tid (pid_t tid __attribute__ ((unused)), + ebl_tid_registers_t *setfunc __attribute__ ((unused)), + void *arg __attribute__ ((unused))) +{ +#ifndef __x86_64__ + return false; +#else /* __x86_64__ */ + struct user_regs_struct user_regs; + if (ptrace (PTRACE_GETREGS, tid, NULL, &user_regs) != 0) + return false; + Dwarf_Word dwarf_regs[17]; + dwarf_regs[0] = user_regs.rax; + dwarf_regs[1] = user_regs.rdx; + dwarf_regs[2] = user_regs.rcx; + dwarf_regs[3] = user_regs.rbx; + dwarf_regs[4] = user_regs.rsi; + dwarf_regs[5] = user_regs.rdi; + dwarf_regs[6] = user_regs.rbp; + dwarf_regs[7] = user_regs.rsp; + dwarf_regs[8] = user_regs.r8; + dwarf_regs[9] = user_regs.r9; + dwarf_regs[10] = user_regs.r10; + dwarf_regs[11] = user_regs.r11; + dwarf_regs[12] = user_regs.r12; + dwarf_regs[13] = user_regs.r13; + dwarf_regs[14] = user_regs.r14; + dwarf_regs[15] = user_regs.r15; + dwarf_regs[16] = user_regs.rip; + return setfunc (0, 17, dwarf_regs, arg); +#endif /* __x86_64__ */ +} |
