summaryrefslogtreecommitdiffstats
path: root/backends
diff options
context:
space:
mode:
Diffstat (limited to 'backends')
-rw-r--r--backends/ChangeLog77
-rw-r--r--backends/Makefile.am30
-rw-r--r--backends/aarch64_cfi.c82
-rw-r--r--backends/aarch64_corenote.c162
-rw-r--r--backends/aarch64_init.c63
-rw-r--r--backends/aarch64_regs.c95
-rw-r--r--backends/aarch64_reloc.def157
-rw-r--r--backends/aarch64_retval.c375
-rw-r--r--backends/aarch64_symbol.c84
-rw-r--r--backends/i386_init.c5
-rw-r--r--backends/i386_initreg.c79
-rw-r--r--backends/libebl_CPU.h37
-rw-r--r--backends/ppc64_init.c34
-rw-r--r--backends/ppc64_resolve_sym.c63
-rw-r--r--backends/ppc_cfi.c2
-rw-r--r--backends/ppc_corenote.c2
-rw-r--r--backends/ppc_init.c4
-rw-r--r--backends/ppc_initreg.c114
-rw-r--r--backends/s390_corenote.c10
-rw-r--r--backends/s390_init.c9
-rw-r--r--backends/s390_initreg.c95
-rw-r--r--backends/s390_unwind.c139
-rw-r--r--backends/x86_64_init.c5
-rw-r--r--backends/x86_64_initreg.c73
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__ */
+}