diff options
Diffstat (limited to 'backends')
| -rw-r--r-- | backends/ChangeLog | 32 | ||||
| -rw-r--r-- | backends/Makefile.am | 12 | ||||
| -rw-r--r-- | backends/aarch64_init.c | 1 | ||||
| -rw-r--r-- | backends/aarch64_initreg.c | 4 | ||||
| -rw-r--r-- | backends/aarch64_unwind.c | 83 | ||||
| -rw-r--r-- | backends/arm_initreg.c | 4 | ||||
| -rw-r--r-- | backends/i386_init.c | 3 | ||||
| -rw-r--r-- | backends/i386_unwind.c | 84 | ||||
| -rw-r--r-- | backends/ppc64_init.c | 1 | ||||
| -rw-r--r-- | backends/ppc_attrs.c | 1 | ||||
| -rw-r--r-- | backends/ppc_initreg.c | 4 | ||||
| -rw-r--r-- | backends/s390_initreg.c | 4 | ||||
| -rw-r--r-- | backends/x86_64_init.c | 1 | ||||
| -rw-r--r-- | backends/x86_64_initreg.c | 2 | ||||
| -rw-r--r-- | backends/x86_64_unwind.c | 86 |
15 files changed, 307 insertions, 15 deletions
diff --git a/backends/ChangeLog b/backends/ChangeLog index 1c561b50..1ac5bab3 100644 --- a/backends/ChangeLog +++ b/backends/ChangeLog @@ -1,3 +1,35 @@ +2017-04-06 Mark Wielaard <[email protected]> + + * i386_unwind.c: New file. + * i386_init.c: Hook i386_unwind. + * Makefile.am (i386_SRCS): Add i386_unwind.c + +2017-02-09 Ulf Hermann <[email protected]> + + * aarch64_unwind.c: New file + * Makefile.am (aarch64_SRCS): Add aarch64_unwind.c + * aarch64_init.c (aarch64_init): Hook aarch64_unwind + +2017-02-09 Ulf Hermann <[email protected]> + + * x86_64_unwind.c: New file + * Makefile.am (x86_64_SRCS): Add x86_64_unwind.c + * x86_64_init.c (x86_64_init): Hook x86_64_unwind + +2017-04-20 Ulf Hermann <[email protected]> + + * aarch64_initreg.c: Compile register initialization only on linux. + * arm_initreg.c: Likewise. + * ppc_initreg.c: Likewise. + * s390_initreg.c: Likewise. + * x86_64_initreg.c: Likewise. + +2017-02-15 Mark Wielaard <[email protected]> + + * ppc64_init.c (ppc64_init): Add check_object_attribute HOOK. + * ppc_attrs.c (ppc_check_object_attribute): Add Single-precision hard + float. + 2016-11-02 Mark Wielaard <[email protected]> * i386_regs.c (i386_register_info): Add fallthrough comment. diff --git a/backends/Makefile.am b/backends/Makefile.am index 54ddd78f..96004dcc 100644 --- a/backends/Makefile.am +++ b/backends/Makefile.am @@ -52,14 +52,14 @@ libdw = ../libdw/libdw.so # each others files. static_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_initreg.c \ + i386_initreg.c i386_unwind.c \ x86_64_init.c x86_64_symbol.c x86_64_corenote.c x86_64_cfi.c \ x86_64_retval.c x86_64_regs.c x86_64_syscall.c \ - x86_64_initreg.c x32_corenote.c \ + x86_64_initreg.c x86_64_unwind.c x32_corenote.c \ ia64_init.c ia64_symbol.c ia64_regs.c ia64_retval.c \ aarch64_init.c aarch64_regs.c aarch64_symbol.c \ aarch64_corenote.c aarch64_retval.c aarch64_cfi.c \ - aarch64_initreg.c \ + aarch64_initreg.c aarch64_unwind.c \ 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_initreg.c \ @@ -74,7 +74,7 @@ am_libebl_static_pic_a_OBJECTS = $(static_SRCS:.c=.os) 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_initreg.c + i386_initreg.c i386_unwind.c cpu_i386 = ../libcpu/libcpu_i386.a libebl_i386_pic_a_SOURCES = $(i386_SRCS) am_libebl_i386_pic_a_OBJECTS = $(i386_SRCS:.c=.os) @@ -85,7 +85,7 @@ 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_initreg.c x32_corenote.c + x86_64_initreg.c x86_64_unwind.c x32_corenote.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) @@ -106,7 +106,7 @@ 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 \ - aarch64_initreg.c + aarch64_initreg.c aarch64_unwind.c libebl_aarch64_pic_a_SOURCES = $(aarch64_SRCS) am_libebl_aarch64_pic_a_OBJECTS = $(aarch64_SRCS:.c=.os) diff --git a/backends/aarch64_init.c b/backends/aarch64_init.c index 6395f117..08664943 100644 --- a/backends/aarch64_init.c +++ b/backends/aarch64_init.c @@ -63,6 +63,7 @@ aarch64_init (Elf *elf __attribute__ ((unused)), + ALT_FRAME_RETURN_COLUMN (used when LR isn't used) = 97 DWARF regs. */ eh->frame_nregs = 97; HOOK (eh, set_initial_registers_tid); + HOOK (eh, unwind); return MODVERSION; } diff --git a/backends/aarch64_initreg.c b/backends/aarch64_initreg.c index 9706205e..daf6f375 100644 --- a/backends/aarch64_initreg.c +++ b/backends/aarch64_initreg.c @@ -32,7 +32,7 @@ #include "system.h" #include <assert.h> -#ifdef __aarch64__ +#if defined(__aarch64__) && defined(__linux__) # include <linux/uio.h> # include <sys/user.h> # include <sys/ptrace.h> @@ -51,7 +51,7 @@ aarch64_set_initial_registers_tid (pid_t tid __attribute__ ((unused)), ebl_tid_registers_t *setfunc __attribute__ ((unused)), void *arg __attribute__ ((unused))) { -#ifndef __aarch64__ +#if !defined(__aarch64__) || !defined(__linux__) return false; #else /* __aarch64__ */ diff --git a/backends/aarch64_unwind.c b/backends/aarch64_unwind.c new file mode 100644 index 00000000..e0a7e96e --- /dev/null +++ b/backends/aarch64_unwind.c @@ -0,0 +1,83 @@ +/* Get previous frame state for an existing frame state. + Copyright (C) 2016 The Qt Company Ltd. + 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 FP_REG 29 +#define LR_REG 30 +#define SP_REG 31 +#define FP_OFFSET 0 +#define LR_OFFSET 8 +#define SP_OFFSET 16 + +#include "libebl_CPU.h" + +/* There was no CFI. Maybe we happen to have a frame pointer and can unwind from that? */ + +bool +EBLHOOK(unwind) (Ebl *ebl __attribute__ ((unused)), Dwarf_Addr pc __attribute__ ((unused)), + ebl_tid_registers_t *setfunc, ebl_tid_registers_get_t *getfunc, + ebl_pid_memory_read_t *readfunc, void *arg, + bool *signal_framep __attribute__ ((unused))) +{ + Dwarf_Word fp, lr, sp; + + if (!getfunc(LR_REG, 1, &lr, arg)) + return false; + + if (lr == 0 || !setfunc(-1, 1, &lr, arg)) + return false; + + if (!getfunc(FP_REG, 1, &fp, arg)) + fp = 0; + + if (!getfunc(SP_REG, 1, &sp, arg)) + sp = 0; + + Dwarf_Word newLr, newFp, newSp; + + if (!readfunc(fp + LR_OFFSET, &newLr, arg)) + newLr = 0; + + if (!readfunc(fp + FP_OFFSET, &newFp, arg)) + newFp = 0; + + newSp = fp + SP_OFFSET; + + // These are not fatal if they don't work. They will just prevent unwinding at the next frame. + setfunc(LR_REG, 1, &newLr, arg); + setfunc(FP_REG, 1, &newFp, arg); + setfunc(SP_REG, 1, &newSp, arg); + + // If the fp is invalid, we might still have a valid lr. + // But if the fp is valid, then the stack should be moving in the right direction. + return fp == 0 || newSp > sp; +} diff --git a/backends/arm_initreg.c b/backends/arm_initreg.c index a0a9be94..efcabaf6 100644 --- a/backends/arm_initreg.c +++ b/backends/arm_initreg.c @@ -30,6 +30,7 @@ # include <config.h> #endif +#ifdef __linux__ #if defined __arm__ # include <sys/types.h> # include <sys/user.h> @@ -45,6 +46,7 @@ # define user_regs_struct user_pt_regs # endif #endif +#endif #define BACKEND arm_ #include "libebl_CPU.h" @@ -54,7 +56,7 @@ arm_set_initial_registers_tid (pid_t tid __attribute__ ((unused)), ebl_tid_registers_t *setfunc __attribute__ ((unused)), void *arg __attribute__ ((unused))) { -#if !defined __arm__ && !defined __aarch64__ +#if !defined(__linux__) || (!defined __arm__ && !defined __aarch64__) return false; #else /* __arm__ || __aarch64__ */ #if defined __arm__ diff --git a/backends/i386_init.c b/backends/i386_init.c index 515d5ac0..fc1587a9 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, 2013 Red Hat, Inc. + Copyright (C) 2000-2009, 2013, 2017 Red Hat, Inc. This file is part of elfutils. Written by Ulrich Drepper <[email protected]>, 2000. @@ -65,6 +65,7 @@ i386_init (Elf *elf __attribute__ ((unused)), /* gcc/config/ #define DWARF_FRAME_REGISTERS. For i386 it is 17, why? */ eh->frame_nregs = 9; HOOK (eh, set_initial_registers_tid); + HOOK (eh, unwind); return MODVERSION; } diff --git a/backends/i386_unwind.c b/backends/i386_unwind.c new file mode 100644 index 00000000..5c9a5de0 --- /dev/null +++ b/backends/i386_unwind.c @@ -0,0 +1,84 @@ +/* Get previous frame state for an existing frame state using frame pointers. + Copyright (C) 2017 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 i386_ +#include "libebl_CPU.h" + +/* Register numbers for frame and stack pointers. We take advantage of + them being next to each other when calling getfunc and setfunc. */ +#define ESP 4 +#define EBP (ESP + 1) + +/* Most basic frame pointer chasing with EBP as frame pointer. + PC = *(FP + 4), SP = FP + 8, FP = *FP. */ +bool +i386_unwind (Ebl *ebl __attribute__ ((unused)), + Dwarf_Addr pc __attribute__ ((unused)), + ebl_tid_registers_t *setfunc, ebl_tid_registers_get_t *getfunc, + ebl_pid_memory_read_t *readfunc, void *arg, + bool *signal_framep __attribute__ ((unused))) +{ + /* sp = 0, fp = 1 */ + Dwarf_Word regs[2]; + + /* Get current stack and frame pointers. */ + if (! getfunc (ESP, 2, regs, arg)) + return false; + + Dwarf_Word sp = regs[0]; + Dwarf_Word fp = regs[1]; + + /* Sanity check. We only support traditional stack frames. */ + if (fp == 0 || sp == 0 || fp < sp) + return false; + + /* Get the return address from the stack, it is our new pc. */ + Dwarf_Word ret_addr; + if (! readfunc (fp + 4, &ret_addr, arg) || ret_addr == 0) + return false; + + /* Get new sp and fp. Sanity check again. */ + sp = fp + 8; + if (! readfunc (fp, &fp, arg) || fp == 0 || sp >= fp) + return false; + + /* Set new sp, fp and pc. */ + regs[0] = sp; + regs[1] = fp; + if (! setfunc (ESP, 2, regs, arg) || ! setfunc (-1, 1, &ret_addr, arg)) + return false; + + return true; +} diff --git a/backends/ppc64_init.c b/backends/ppc64_init.c index 2ba82327..11d3a77f 100644 --- a/backends/ppc64_init.c +++ b/backends/ppc64_init.c @@ -67,6 +67,7 @@ ppc64_init (Elf *elf __attribute__ ((unused)), HOOK (eh, syscall_abi); HOOK (eh, core_note); 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; diff --git a/backends/ppc_attrs.c b/backends/ppc_attrs.c index 612c5769..48d7129d 100644 --- a/backends/ppc_attrs.c +++ b/backends/ppc_attrs.c @@ -51,6 +51,7 @@ ppc_check_object_attribute (Ebl *ebl __attribute__ ((unused)), "Hard or soft float", "Hard float", "Soft float", + "Single-precision hard float", }; if (value < sizeof fp_kinds / sizeof fp_kinds[0]) *value_name = fp_kinds[value]; diff --git a/backends/ppc_initreg.c b/backends/ppc_initreg.c index 64f53793..69d623b9 100644 --- a/backends/ppc_initreg.c +++ b/backends/ppc_initreg.c @@ -32,7 +32,7 @@ #include "system.h" #include <stdlib.h> -#ifdef __powerpc__ +#if defined(__powerpc__) && defined(__linux__) # include <sys/user.h> # include <sys/ptrace.h> #endif @@ -70,7 +70,7 @@ ppc_set_initial_registers_tid (pid_t tid __attribute__ ((unused)), ebl_tid_registers_t *setfunc __attribute__ ((unused)), void *arg __attribute__ ((unused))) { -#ifndef __powerpc__ +#if !defined(__powerpc__) || !defined(__linux__) return false; #else /* __powerpc__ */ union diff --git a/backends/s390_initreg.c b/backends/s390_initreg.c index b4c4b67c..011305ce 100644 --- a/backends/s390_initreg.c +++ b/backends/s390_initreg.c @@ -32,7 +32,7 @@ #include "system.h" #include <assert.h> -#ifdef __s390__ +#if defined(__s390__) && defined(__linux__) # include <sys/user.h> # include <asm/ptrace.h> # include <sys/ptrace.h> @@ -46,7 +46,7 @@ s390_set_initial_registers_tid (pid_t tid __attribute__ ((unused)), ebl_tid_registers_t *setfunc __attribute__ ((unused)), void *arg __attribute__ ((unused))) { -#ifndef __s390__ +#if !defined(__s390__) || !defined(__linux__) return false; #else /* __s390__ */ struct user user_regs; diff --git a/backends/x86_64_init.c b/backends/x86_64_init.c index cfd0158c..adfa4791 100644 --- a/backends/x86_64_init.c +++ b/backends/x86_64_init.c @@ -68,6 +68,7 @@ x86_64_init (Elf *elf __attribute__ ((unused)), /* gcc/config/ #define DWARF_FRAME_REGISTERS. */ eh->frame_nregs = 17; HOOK (eh, set_initial_registers_tid); + HOOK (eh, unwind); return MODVERSION; } diff --git a/backends/x86_64_initreg.c b/backends/x86_64_initreg.c index db9216ed..50e90020 100644 --- a/backends/x86_64_initreg.c +++ b/backends/x86_64_initreg.c @@ -31,7 +31,7 @@ #endif #include <stdlib.h> -#ifdef __x86_64__ +#if defined(__x86_64__) && defined(__linux__) # include <sys/user.h> # include <sys/ptrace.h> #endif diff --git a/backends/x86_64_unwind.c b/backends/x86_64_unwind.c new file mode 100644 index 00000000..ade64c01 --- /dev/null +++ b/backends/x86_64_unwind.c @@ -0,0 +1,86 @@ +/* Get previous frame state for an existing frame state. + Copyright (C) 2016 The Qt Company Ltd. + 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 x86_64_ +#include "libebl_CPU.h" + +/* There was no CFI. Maybe we happen to have a frame pointer and can unwind from that? */ + +bool +x86_64_unwind (Ebl *ebl __attribute__ ((unused)), + Dwarf_Addr pc __attribute__ ((unused)), + ebl_tid_registers_t *setfunc, ebl_tid_registers_get_t *getfunc, + ebl_pid_memory_read_t *readfunc, void *arg, + bool *signal_framep __attribute__ ((unused))) +{ + // Register 6 is supposed to be rbp, thus the conventional frame pointer + const int fpReg = 6; + const int spReg = 7; + + Dwarf_Word fp; + if (!getfunc(fpReg, 1, &fp, arg) || fp == 0) + return false; + + // Try to read old sp, so that we can avoid infinite loops below + Dwarf_Word sp; + if (!getfunc(spReg, 1, &sp, arg)) + sp = 0; + + Dwarf_Word prev_fp; + if (!readfunc(fp, &prev_fp, arg)) + prev_fp = 0; + + Dwarf_Word ret; + if (!readfunc(fp + 8, &ret, arg)) + return false; + + if (!setfunc(fpReg, 1, &prev_fp, arg)) + return false; + + fp += 16; // Pop fp and return address and write result to sp + if (!setfunc(spReg, 1, &fp, arg)) + return false; + + if (!setfunc(-1, 1, &ret, arg)) + return false; + + // If the sp didn't move up we don't actually have a new stack + // frame but rather some random data that doesn't include frame + // pointers. Break the unwinding then. + if (sp >= fp) + return false; + + return true; +} |
