diff options
| -rw-r--r-- | backends/ChangeLog | 6 | ||||
| -rw-r--r-- | backends/Makefile.am | 2 | ||||
| -rw-r--r-- | backends/x86_64_init.c | 1 | ||||
| -rw-r--r-- | backends/x86_64_unwind.c | 86 | ||||
| -rw-r--r-- | tests/ChangeLog | 7 | ||||
| -rw-r--r-- | tests/Makefile.am | 3 | ||||
| -rw-r--r-- | tests/backtrace.x86_64.fp.core.bz2 | bin | 0 -> 11072 bytes | |||
| -rw-r--r-- | tests/backtrace.x86_64.fp.exec.bz2 | bin | 0 -> 434645 bytes | |||
| -rwxr-xr-x | tests/run-backtrace-fp-core-x86_64.sh | 29 |
9 files changed, 133 insertions, 1 deletions
diff --git a/backends/ChangeLog b/backends/ChangeLog index c6e0e08b..04f579da 100644 --- a/backends/ChangeLog +++ b/backends/ChangeLog @@ -1,3 +1,9 @@ +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. diff --git a/backends/Makefile.am b/backends/Makefile.am index b553ec34..60917b92 100644 --- a/backends/Makefile.am +++ b/backends/Makefile.am @@ -59,7 +59,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) 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_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; +} diff --git a/tests/ChangeLog b/tests/ChangeLog index 73485458..db71f8e3 100644 --- a/tests/ChangeLog +++ b/tests/ChangeLog @@ -1,3 +1,10 @@ +2017-02-09 Ulf Hermann <[email protected]> + + * Makefile.am: Add test for unwinding with frame pointers on x86_64 + * backtrace.x86_64.fp.core.bz2: New file + * backtrace.x86_64.fp.exec.bz2: New file + * run-backtrace-fp-core-x86_64.sh: New file + 2017-04-25 Mark Wielaard <[email protected]> * backtrace-subr.sh (check_backtracegen): New function. diff --git a/tests/Makefile.am b/tests/Makefile.am index f6d8b0d8..b0db19f0 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -115,6 +115,7 @@ TESTS = run-arextract.sh run-arsymtest.sh newfile test-nlist \ run-backtrace-native.sh run-backtrace-data.sh run-backtrace-dwarf.sh \ run-backtrace-native-biarch.sh run-backtrace-native-core.sh \ run-backtrace-native-core-biarch.sh run-backtrace-core-x86_64.sh \ + run-backtrace-fp-core-x86_64.sh \ run-backtrace-core-x32.sh \ run-backtrace-core-i386.sh run-backtrace-core-ppc.sh \ run-backtrace-core-s390x.sh run-backtrace-core-s390.sh \ @@ -293,9 +294,11 @@ EXTRA_DIST = run-arextract.sh run-arsymtest.sh \ run-backtrace-native.sh run-backtrace-native-biarch.sh \ run-backtrace-native-core.sh run-backtrace-native-core-biarch.sh \ run-backtrace-core-x86_64.sh run-backtrace-core-i386.sh \ + run-backtrace-fp-core-x86_64.sh \ run-backtrace-core-x32.sh \ backtrace-subr.sh backtrace.i386.core.bz2 backtrace.i386.exec.bz2 \ backtrace.x86_64.core.bz2 backtrace.x86_64.exec.bz2 \ + backtrace.x86_64.fp.core.bz2 backtrace.x86_64.fp.exec.bz2 \ backtrace.ppc.core.bz2 backtrace.ppc.exec.bz2 \ run-backtrace-core-ppc.sh testfile66.bz2 testfile66.core.bz2 \ backtrace.s390x.core.bz2 backtrace.s390x.exec.bz2 \ diff --git a/tests/backtrace.x86_64.fp.core.bz2 b/tests/backtrace.x86_64.fp.core.bz2 Binary files differnew file mode 100644 index 00000000..e773ca21 --- /dev/null +++ b/tests/backtrace.x86_64.fp.core.bz2 diff --git a/tests/backtrace.x86_64.fp.exec.bz2 b/tests/backtrace.x86_64.fp.exec.bz2 Binary files differnew file mode 100644 index 00000000..06958452 --- /dev/null +++ b/tests/backtrace.x86_64.fp.exec.bz2 diff --git a/tests/run-backtrace-fp-core-x86_64.sh b/tests/run-backtrace-fp-core-x86_64.sh new file mode 100755 index 00000000..348eb183 --- /dev/null +++ b/tests/run-backtrace-fp-core-x86_64.sh @@ -0,0 +1,29 @@ +#! /bin/bash +# Copyright (C) 2017 The Qt Company +# This file is part of elfutils. +# +# This file is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# elfutils is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +. $srcdir/backtrace-subr.sh + +# The binary is generated by compiling with eh_frame CFI, but with frame +# pointers. +# +# gcc -static -O2 -fno-omit-frame-pointer -fno-asynchronous-unwind-tables \ +# -D_GNU_SOURCE -pthread -o tests/backtrace.x86_64.fp.exec -I. -Ilib \ +# tests/backtrace-child.c +# +# The core is generated by calling the binary with --gencore + +check_core x86_64.fp |
