[PATCH] Unwinding CFI for x86_64 signal frame (__restore_rt)
Jan Kratochvil
jan.kratochvil@redhat.com
Tue Nov 28 23:05:00 GMT 2006
Hi Jakub,
On Tue, 28 Nov 2006 11:47:56 +0100, Jakub Jelinek wrote:
> On Mon, Nov 27, 2006 at 04:46:22PM -0500, Daniel Jacobowitz wrote:
...
> > http://sourceware.org/ml/gdb/2006-07/msg00131.html
...
> I actually think your patch above is (almost) fine, all you should change
> is 1) use oR* macros from ucontext_i.h 2) use .uleb128 resp. .sleb128
> directives as opposed to .byte when the argument is leb128, that way you
> can get rid e.g. of the do_expr_2 macro and can have just one, do_expr.
> 3) I'd put the nop before .align 16 and use
> " .long .LSTART_" #name "-1-.\n" /* PC-relative start address */ \
> for the start address, so that movq/syscall isn't unnecessarily unaligned.
>
> Really .cfi_* directives don't buy us anything here.
while I strongly disagree we still should code assembly instructions by hand
even in the 21st century the attached patch refactored the Daniel's one
following your guidelines.
It has been tested with the frysk's forked libunwind.
Thanks,
Jan
-------------- next part --------------
2006-11-28 Daniel Jacobowitz <dan@codesourcery.com>
Jakub Jelinek <jakub@redhat.com>
Jan Kratochvil <jan.kratochvil@redhat.com>
* sysdeps/unix/sysv/linux/x86_64/sigaction.c (restore_rt): Add correct
unwind information.
* sysdeps/unix/sysv/linux/x86_64/Makefile: Prvide symbols for
`restore_rt' even in the `signal' directory.
* sysdeps/unix/sysv/linux/x86_64/ucontext_i.sym: Extend the regs list.
diff -u -rup glibc-20061120T1000-orig/sysdeps/unix/sysv/linux/x86_64/Makefile glibc-20061120T1000/sysdeps/unix/sysv/linux/x86_64/Makefile
--- glibc-20061120T1000-orig/sysdeps/unix/sysv/linux/x86_64/Makefile 2005-12-22 05:57:36.000000000 +0100
+++ glibc-20061120T1000/sysdeps/unix/sysv/linux/x86_64/Makefile 2006-11-28 23:47:15.000000000 +0100
@@ -8,8 +8,9 @@ endif
ifeq ($(subdir),stdlib)
sysdep_routines += __start_context
+gen-as-const-headers += ucontext_i.sym
endif
-ifeq ($(subdir),stdlib)
+ifeq ($(subdir),signal)
gen-as-const-headers += ucontext_i.sym
endif
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-28 23:45:04.000000000 +0100
@@ -33,6 +33,8 @@
translate it here. */
#include <kernel_sigaction.h>
+#include "ucontext_i.h"
+
/* We do not globally define the SA_RESTORER flag so do it here. */
#define SA_RESTORER 0x04000000
@@ -90,18 +92,94 @@ weak_alias (__libc_sigaction, sigaction)
signal handlers work right. Important are both the names
(__restore_rt) and the exact instruction sequence.
If you ever feel the need to make any changes, please notify the
- appropriate GDB maintainer. */
+ appropriate GDB maintainer.
+
+ The unwind information starts a byte before __restore_rt, so that
+ it is found when unwinding, to get an address the unwinder assumes
+ will be in the middle of a call instruction. See the Linux kernel
+ (the i386 vsyscall, in particular) for an explanation of the complex
+ unwind information used here in order to get the traditional CFA.
+ We do not restore cs - it's only stored as two bytes here so that's
+ a bit tricky. We don't use the gas cfi directives, so that we can
+ reliably add .cfi_signal_frame. */
+
+#define do_cfa_expr \
+ " .byte 0x0f\n" /* DW_CFA_def_cfa_expression */ \
+ " .uleb128 2f-1f\n" /* length */ \
+ "1: .byte 0x77\n" /* DW_OP_breg8 */ \
+ " .sleb128 " CFI_STRINGIFY(oRSP) "\n" \
+ " .byte 0x06\n" /* DW_OP_deref */ \
+ "2:"
+
+#define do_expr(regno, offset) \
+ " .byte 0x10\n" /* DW_CFA_expression */ \
+ " .uleb128 " CFI_STRINGIFY(regno) "\n" \
+ " .uleb128 2f-1f\n" /* length */ \
+ "1: .byte 0x77\n" /* DW_OP_breg8 */ \
+ " .sleb128 " CFI_STRINGIFY(offset) "\n" \
+ "2:"
#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 \
+ ( \
+ /* `nop' for debuggers assuming `call' should not disalign the code. */ \
+ " nop\n" \
+ ".align 16\n" \
+ ".LSTART_" #name ":\n" \
+ " nop\n" \
+ " .type __" #name ",@function\n" \
+ "__" #name ":\n" \
+ " movq $" #syscall ", %rax\n" \
+ " syscall\n" \
+ ".LEND_" #name ":\n" \
+ ".section .eh_frame,\"a\",@progbits\n" \
+ ".LSTARTFRAME_" #name ":\n" \
+ " .long .LENDCIE_" #name "-.LSTARTCIE_" #name "\n" \
+ ".LSTARTCIE_" #name ":\n" \
+ " .long 0\n" /* CIE ID */ \
+ " .byte 1\n" /* Version number */ \
+ " .string \"zRS\"\n" /* NUL-terminated augmentation string */ \
+ " .uleb128 1\n" /* Code alignment factor */ \
+ " .sleb128 -8\n" /* Data alignment factor */ \
+ " .byte 0x10\n" /* Return address register column */ \
+ " .uleb128 1\n" /* Augmentation value length */ \
+ " .byte 0x1b\n" /* DW_EH_PE_pcrel|DW_EH_PE_sdata4. */ \
+ " .byte 0\n" /* DW_CFA_nop */ \
+ " .align 8\n" \
+ ".LENDCIE_" #name ":\n" \
+ " .long .LENDFDE_" #name "-.LSTARTFDE_" #name "\n" /* FDE len */ \
+ ".LSTARTFDE_" #name ":\n" \
+ " .long .LSTARTFDE_" #name "-.LSTARTFRAME_" #name "\n" /* CIE */ \
+ /* `LSTART_' is subtracted 1 as debuggers assume a `call' here. */ \
+ " .long (.LSTART_" #name "-1)-.\n" /* PC-relative start addr. */ \
+ " .long .LEND_" #name "-(.LSTART_" #name "-1)\n" \
+ " .uleb128 0\n" /* Augmentation */ \
+ do_cfa_expr \
+ do_expr (8 /* r8 */, oR8) \
+ do_expr (9 /* r9 */, oR9) \
+ do_expr (10 /* r10 */, oR10) \
+ do_expr (11 /* r11 */, oR11) \
+ do_expr (12 /* r12 */, oR12) \
+ do_expr (13 /* r13 */, oR13) \
+ do_expr (14 /* r14 */, oR14) \
+ do_expr (15 /* r15 */, oR15) \
+ do_expr (5 /* rdi */, oRDI) \
+ do_expr (4 /* rsi */, oRSI) \
+ do_expr (6 /* rbp */, oRBP) \
+ do_expr (3 /* rbx */, oRBX) \
+ do_expr (1 /* rdx */, oRDX) \
+ do_expr (0 /* rax */, oRAX) \
+ do_expr (2 /* rcx */, oRCX) \
+ do_expr (7 /* rsp */, oRSP) \
+ do_expr (16 /* rip */, oRIP) \
+ /* Older gas(1) does not support `rflags'. */ \
+ do_expr (49 /* rflags */, oEFL) \
+ /* `cs'/`ds'/`fs' are unaligned and a different size. */ \
+ /* gas: Error: register save offset not a multiple of 8 */ \
+ " .align 4\n" \
+ " .LENDFDE_" #name ":\n" \
+ " .previous\n" \
);
/* The return code for realtime-signals. */
RESTORE (restore_rt, __NR_rt_sigreturn)
diff -u -rup glibc-20061120T1000-orig/sysdeps/unix/sysv/linux/x86_64/ucontext_i.sym glibc-20061120T1000/sysdeps/unix/sysv/linux/x86_64/ucontext_i.sym
--- glibc-20061120T1000-orig/sysdeps/unix/sysv/linux/x86_64/ucontext_i.sym 2005-12-22 05:57:36.000000000 +0100
+++ glibc-20061120T1000/sysdeps/unix/sysv/linux/x86_64/ucontext_i.sym 2006-11-28 23:12:37.000000000 +0100
@@ -18,6 +18,8 @@ oRSP mreg (RSP)
oRBX mreg (RBX)
oR8 mreg (R8)
oR9 mreg (R9)
+oR10 mreg (R10)
+oR11 mreg (R11)
oR12 mreg (R12)
oR13 mreg (R13)
oR14 mreg (R14)
@@ -28,6 +30,7 @@ oRDX mreg (RDX)
oRAX mreg (RAX)
oRCX mreg (RCX)
oRIP mreg (RIP)
+oEFL mreg (EFL)
oFPREGS mcontext (fpregs)
oSIGMASK ucontext (uc_sigmask)
oFPREGSMEM ucontext (__fpregs_mem)
More information about the Libc-alpha
mailing list