[PATCH] Unwinding CFI for x86_64 signal frame (__restore_rt)
Jan Kratochvil
jan.kratochvil@redhat.com
Sat Nov 25 18:06:00 GMT 2006
Hi,
Frysk debugger in development would like to properly unwind signal frames
without any hacks as has been done in the gdb case. Provided patch sets proper
CFI unwind information for `__restore_rt'.
`__restore_rt' CFI is fixed only for x86_64 (tested on Fedora Core
kernel-xen-2.6.18-1.2849.fc6.x86_64) as on i386 (kernel-2.6.18-1.2747.el5.i686)
is in use VDSOed `__kernel_sigreturn' instead (with proper CFI already).
Still i386 should get fixed a similiar way but I do not have an easy testcase.
Currently gdb identifies signal frames using strcmp ("__restore_rt", ...)
(`amd64_linux_sigtramp_p') and gdb has also hardcoded arch-dependent unwind
info (register locations) for the signal frames.
I was told gcc is using `MD_FALLBACK_FRAME_STATE_FOR' (for exceptions
unwinding) but it is not suitable for ptrace(2)ing remote debuggers.
Testcase in glibc is not provided as the whole DWARF/CFI unwinding requires
framework IMO out of the glibc testcases' scope.
Regards,
Jan
Original Bug:
https://bugzilla.redhat.com/bugzilla/show_bug.cgi?id=217087
Testcase provided in libunwind testsuite forked in the Frysk repository:
CVSROOT=:pserver:anoncvs@sources.redhat.com:/cvs/frysk
CVS Repository=frysk-imports/libunwind
testcase: tests/run-ptrace-stepper
Requires patch: http://sourceware.org/bugzilla/show_bug.cgi?id=3590
-------------- next part --------------
2006-11-25 Jan Kratochvil <jan.kratochvil@redhat.com>
* glibc-20061120T1000-orig/configure.in: Test whether gas supports
`.cfi_signal_frame' and `rflags'.
* glibc-20061120T1000-orig/sysdeps/unix/sysv/linux/x86_64/sigaction.c
(__restore_rt): Set CFI as signal-frame and provide the CFI unwind info.
https://bugzilla.redhat.com/bugzilla/show_bug.cgi?id=217087
diff -u -rup glibc-20061120T1000-orig/config.h.in glibc-20061120T1000/config.h.in
--- glibc-20061120T1000-orig/config.h.in 2006-10-28 08:44:04.000000000 +0200
+++ glibc-20061120T1000/config.h.in 2006-11-25 16:59:17.000000000 +0100
@@ -35,6 +35,12 @@
/* Define if CFI directives are available. */
#undef HAVE_ASM_CFI_DIRECTIVES
+/* Define if CFI .cfi_signal_frame directive is available. */
+#undef HAVE_ASM_CFI_SIGNAL_FRAME_DIRECTIVE
+
+/* Define if CFI x86_64 rflags is available. */
+#undef HAVE_ASM_CFI_RFLAGS
+
/* Define to the assembler line separator character for multiple
assembler instructions per line. Default is `;' */
#undef ASM_LINE_SEP
diff -u -rup glibc-20061120T1000-orig/configure.in glibc-20061120T1000/configure.in
--- glibc-20061120T1000-orig/configure.in 2006-11-02 19:34:30.000000000 +0100
+++ glibc-20061120T1000/configure.in 2006-11-25 18:09:45.000000000 +0100
@@ -1793,6 +1793,48 @@ if test $libc_cv_asm_cfi_directives = ye
AC_DEFINE(HAVE_ASM_CFI_DIRECTIVES)
fi
+AC_CACHE_CHECK(whether CFI signal frame directive is supported, libc_cv_asm_cfi_signal_frame_directive, [dnl
+cat > conftest.s <<EOF
+ .text
+ .type func,%function
+func:
+ .cfi_startproc
+ .cfi_signal_frame
+ .cfi_endproc
+EOF
+if AC_TRY_COMMAND(${CC-cc} $ASFLAGS -c conftest.s 1>&AS_MESSAGE_LOG_FD); then
+ libc_cv_asm_cfi_signal_frame_directive=yes
+else
+ libc_cv_asm_cfi_signal_frame_directive=no
+fi
+rm -f conftest*])
+if test $libc_cv_asm_cfi_signal_frame_directive = yes; then
+ AC_DEFINE(HAVE_ASM_CFI_SIGNAL_FRAME_DIRECTIVE)
+fi
+
+case $machine in
+ x86_64)
+ AC_CACHE_CHECK(whether CFI x86_64 rflags is supported, libc_cv_asm_cfi_rflags, [dnl
+ cat > conftest.s <<EOF
+ .text
+ .type func,%function
+func:
+ .cfi_startproc
+ .cfi_offset rflags, 0
+ .cfi_endproc
+EOF
+ if AC_TRY_COMMAND(${CC-cc} $ASFLAGS -c conftest.s 1>&AS_MESSAGE_LOG_FD); then
+ libc_cv_asm_cfi_rflags=yes
+ else
+ libc_cv_asm_cfi_rflags=no
+ fi
+ rm -f conftest*])
+ if test $libc_cv_asm_cfi_rflags = yes; then
+ AC_DEFINE(HAVE_ASM_CFI_RFLAGS)
+ fi
+ ;;
+esac
+
AC_CACHE_CHECK(for ld --no-whole-archive, libc_cv_ld_no_whole_archive, [dnl
cat > conftest.c <<\EOF
_start () {}
diff -u -rup glibc-20061120T1000-orig/sysdeps/generic/sysdep.h glibc-20061120T1000/sysdeps/generic/sysdep.h
--- glibc-20061120T1000-orig/sysdeps/generic/sysdep.h 2006-01-07 04:46:40.000000000 +0100
+++ glibc-20061120T1000/sysdeps/generic/sysdep.h 2006-11-25 16:59:17.000000000 +0100
@@ -84,6 +84,20 @@
# define cfi_window_save
# endif
+/* `.cfi_signal_frame' was introduced later. */
+# ifdef HAVE_ASM_CFI_SIGNAL_FRAME_DIRECTIVE
+# define cfi_signal_frame .cfi_signal_frame
+# else
+# define cfi_signal_frame
+# endif
+
+/* To be used as: cfi_if_rflags (cfi_offset (rflags, xxx * 8)) */
+# ifdef HAVE_ASM_CFI_RFLAGS
+# define cfi_if_rflags(x) x
+# else
+# define cfi_if_rflags(x)
+# endif
+
#else /* ! ASSEMBLER */
# ifdef HAVE_ASM_CFI_DIRECTIVES
# define CFI_STRINGIFY(Name) CFI_STRINGIFY2 (Name)
@@ -134,4 +148,18 @@
# define CFI_WINDOW_SAVE
# endif
+# ifdef HAVE_ASM_CFI_SIGNAL_FRAME_DIRECTIVE
+# define CFI_SIGNAL_FRAME \
+ ".cfi_signal_frame"
+# else
+# define CFI_SIGNAL_FRAME
+# endif
+
+/* To be used as: CFI_IF_RFLAGS (CFI_OFFSET (rflags, xxx * 8)) */
+# ifdef HAVE_ASM_CFI_RFLAGS
+# define CFI_IF_RFLAGS(x) x
+# else
+# define CFI_IF_RFLAGS(x)
+# endif
+
#endif /* __ASSEMBLER__ */
diff -u -rup glibc-20061120T1000-orig/sysdeps/unix/sysv/linux/x86_64/sigaction.c glibc-20061120T1000/sysdeps/unix/sysv/linux/x86_64/sigaction.c
--- glibc-20061120T1000-orig/sysdeps/unix/sysv/linux/x86_64/sigaction.c 2006-10-28 08:44:03.000000000 +0200
+++ glibc-20061120T1000/sysdeps/unix/sysv/linux/x86_64/sigaction.c 2006-11-25 16:59:17.000000000 +0100
@@ -92,16 +92,49 @@ weak_alias (__libc_sigaction, sigaction)
If you ever feel the need to make any changes, please notify the
appropriate GDB maintainer. */
+/* sizeof (struct rt_sigframe) */
+#define FRAME_SIZE 0x238
+/* offsetof (struct rt_sigframe, uc.uc_mcontext) */
+#define SIGCONTEXT_BASE (-FRAME_SIZE + 0x28)
+
#define RESTORE(name, syscall) RESTORE2 (name, syscall)
# define RESTORE2(name, syscall) \
-asm \
- ( \
- ".align 16\n" \
- CFI_STARTPROC "\n" \
- "__" #name ":\n" \
- " movq $" #syscall ", %rax\n" \
- " syscall\n" \
- CFI_ENDPROC "\n" \
+asm \
+ ( \
+ ".align 16\n" \
+ CFI_STARTPROC "\n" \
+ CFI_SIGNAL_FRAME "\n" \
+ CFI_DEF_CFA (rsp, +FRAME_SIZE) "\n" \
+ /* Offsets from: <asm-x86_64/sigcontext.h> */ \
+ CFI_OFFSET (r8, SIGCONTEXT_BASE + 0*8) "\n" \
+ CFI_OFFSET (r9, SIGCONTEXT_BASE + 1*8) "\n" \
+ CFI_OFFSET (r10, SIGCONTEXT_BASE + 2*8) "\n" \
+ CFI_OFFSET (r11, SIGCONTEXT_BASE + 3*8) "\n" \
+ CFI_OFFSET (r12, SIGCONTEXT_BASE + 4*8) "\n" \
+ CFI_OFFSET (r13, SIGCONTEXT_BASE + 5*8) "\n" \
+ CFI_OFFSET (r14, SIGCONTEXT_BASE + 6*8) "\n" \
+ CFI_OFFSET (r15, SIGCONTEXT_BASE + 7*8) "\n" \
+ CFI_OFFSET (rdi, SIGCONTEXT_BASE + 8*8) "\n" \
+ CFI_OFFSET (rsi, SIGCONTEXT_BASE + 9*8) "\n" \
+ CFI_OFFSET (rbp, SIGCONTEXT_BASE + 10*8) "\n" \
+ CFI_OFFSET (rbx, SIGCONTEXT_BASE + 11*8) "\n" \
+ CFI_OFFSET (rdx, SIGCONTEXT_BASE + 12*8) "\n" \
+ CFI_OFFSET (rax, SIGCONTEXT_BASE + 13*8) "\n" \
+ CFI_OFFSET (rcx, SIGCONTEXT_BASE + 14*8) "\n" \
+ CFI_OFFSET (rsp, SIGCONTEXT_BASE + 15*8) "\n" \
+ CFI_OFFSET (rip, SIGCONTEXT_BASE + 16*8) "\n" \
+ CFI_IF_RFLAGS (CFI_OFFSET (rflags, SIGCONTEXT_BASE + 17*8)) "\n" \
+ CFI_OFFSET (cs, SIGCONTEXT_BASE + 18*8 + 0) "\n" \
+ /* gas: Error: register save offset not a multiple of 8 */ \
+ /* CFI_OFFSET (gs, SIGCONTEXT_BASE + 18*8 + 2) "\n" */ \
+ /* CFI_OFFSET (fs, SIGCONTEXT_BASE + 18*8 + 4) "\n" */ \
+ /* Debugger assumes `call' and automatically lookups `ip - 1'. */ \
+ " nop\n" \
+ " .type __" #name ",@function\n" \
+ "__" #name ":\n" \
+ " movq $" #syscall ", %rax\n" \
+ " syscall\n" \
+ CFI_ENDPROC "\n" \
);
/* The return code for realtime-signals. */
RESTORE (restore_rt, __NR_rt_sigreturn)
More information about the Libc-alpha
mailing list