summaryrefslogtreecommitdiffstats
path: root/backends
diff options
context:
space:
mode:
Diffstat (limited to 'backends')
-rw-r--r--backends/ChangeLog6
-rw-r--r--backends/Makefile.am2
-rw-r--r--backends/x86_64_init.c1
-rw-r--r--backends/x86_64_unwind.c86
4 files changed, 94 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;
+}