summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTimo Teräs <timo.teras@iki.fi>2011-11-10 09:36:44 +0200
committerNatanael Copa <ncopa@alpinelinux.org>2011-12-23 15:49:02 +0100
commit9d28002b230eb01a5db7aecab263d38bf0d6d6c7 (patch)
treef17505b5757bfe08cc8e55f31731f36b6647cdd1
parenteb5d129b641c644d82089c3ded3d36288c66123c (diff)
downloaduClibc-alpine-9d28002b230eb01a5db7aecab263d38bf0d6d6c7.tar.bz2
uClibc-alpine-9d28002b230eb01a5db7aecab263d38bf0d6d6c7.tar.xz
libc/x86: fix stack unwinding and backtrace information
When compiled without framepointer, the DWARF-2 CFI data is required for proper stack unwinding. This patch adds the CFI information to: * syscalls (so we get proper backtrace even for release builds) the ebx hack was removed as it would complicate the CFI generation * new thread stub function (so the backtrace is clean for user created threads) Also pads the signal return trampolines separate from other functions. If CFI info was found for signal return code (which seems to happen if it's located right next a valid function), it will not be recognized as signal trampoline (gcc unwinder and gdb check first CFI info, and only if it does not exists it compares the exact opcode sequence to see if we are at signal return code block). This fixes a real crash if thread is cancelled and the cancellation handler fails to detect the signal return frame. Signed-off-by: Timo Teräs <timo.teras@iki.fi> Signed-off-by: Natanael Copa <ncopa@alpinelinux.org>
-rw-r--r--libc/sysdeps/linux/i386/bits/syscalls.h82
-rw-r--r--libc/sysdeps/linux/i386/clone.S17
-rw-r--r--libc/sysdeps/linux/i386/sigaction.c4
3 files changed, 28 insertions, 75 deletions
diff --git a/libc/sysdeps/linux/i386/bits/syscalls.h b/libc/sysdeps/linux/i386/bits/syscalls.h
index eeafb3a48..1f60a4493 100644
--- a/libc/sysdeps/linux/i386/bits/syscalls.h
+++ b/libc/sysdeps/linux/i386/bits/syscalls.h
@@ -13,6 +13,7 @@
#ifndef __ASSEMBLER__
#include <errno.h>
+#include <common/sysdep.h>
#define INTERNAL_SYSCALL_NCS(name, err, nr, args...) \
({ \
@@ -31,90 +32,21 @@
#if 1 /* defined __PIC__ || defined __pic__ */
-/* This code avoids pushing/popping ebx as much as possible.
- * I think the main reason was that older GCCs had problems
- * with proper saving/restoring of ebx if "b" constraint was used,
- * which was breaking -fPIC code really badly.
- * At least gcc 4.2.x seems to not need these tricks anymore,
- * but this code is still useful because it often avoids
- * using stack for saving ebx.
- * Keeping it unconditionally enabled for now.
- */
-
-/* We need some help from the assembler to generate optimal code.
- * We define some macros here which later will be used. */
-/* gcc>=4.6 with LTO need the same guards as IMA (a.k.a --combine) did.
- * See gcc.gnu.org/PR47577 */
-/* FIXME: drop these b* macros! */
-
-__asm__ (
-#if defined __DOMULTI__ || __GNUC_PREREQ (4, 6)
- /* Protect against asm macro redefinition (happens in __DOMULTI__ mode).
- * Unfortunately, it ends up visible in .o files. */
- ".ifndef _BITS_SYSCALLS_ASM\n\t"
- ".set _BITS_SYSCALLS_ASM,1\n\t"
-#endif
- ".L__X'%ebx = 1\n\t"
- ".L__X'%ecx = 2\n\t"
- ".L__X'%edx = 2\n\t"
- ".L__X'%eax = 3\n\t"
- ".L__X'%esi = 3\n\t"
- ".L__X'%edi = 3\n\t"
- ".L__X'%ebp = 3\n\t"
- ".L__X'%esp = 3\n\t"
-
- /* Loading param #1 (ebx) is done by loading it into
- * another register, and then performing bpushl+bmovl,
- * since we must preserve ebx */
-
- ".macro bpushl name reg\n\t"
- ".if 1 - \\name\n\t" /* if reg!=ebx... */
- ".if 2 - \\name\n\t" /* if reg can't be clobbered... */
- "pushl %ebx\n\t" /* save ebx on stack */
- ".else\n\t"
- "xchgl \\reg, %ebx\n\t" /* else save ebx in reg, and load reg to ebx */
- ".endif\n\t"
- ".endif\n\t"
- ".endm\n\t"
-
- ".macro bmovl name reg\n\t"
- ".if 1 - \\name\n\t"
- ".if 2 - \\name\n\t" /* if reg can't be clobbered... */
- "movl \\reg, %ebx\n\t" /* load reg to ebx */
- ".endif\n\t"
- ".endif\n\t"
- ".endm\n\t"
-
- ".macro bpopl name reg\n\t"
- ".if 1 - \\name\n\t"
- ".if 2 - \\name\n\t" /* if reg can't be clobbered... */
- "popl %ebx\n\t" /* restore ebx from stack */
- ".else\n\t"
- "xchgl \\reg, %ebx\n\t" /* else restore ebx from reg */
- ".endif\n\t"
- ".endif\n\t"
- ".endm\n\t"
-
-#if defined __DOMULTI__ || __GNUC_PREREQ (4, 6)
- ".endif\n\t" /* _BITS_SYSCALLS_ASM */
-#endif
-);
-
#define LOADARGS_0
-#define LOADARGS_1 "bpushl .L__X'%k2, %k2\n\t" "bmovl .L__X'%k2, %k2\n\t"
+#define LOADARGS_1 "push %%ebx\n\t" CFI_ADJUST_CFA_OFFSET(4) "\n\t" CFI_REL_OFFSET(ebx, 0) "\n\t" "movl %k2, %%ebx\n\t"
#define LOADARGS_2 LOADARGS_1
#define LOADARGS_3 LOADARGS_1
#define LOADARGS_4 LOADARGS_1
#define LOADARGS_5 LOADARGS_1
-#define LOADARGS_6 LOADARGS_1 "push %%ebp\n\t" "movl %7, %%ebp\n\t"
+#define LOADARGS_6 LOADARGS_1 "push %%ebp\n\t" CFI_ADJUST_CFA_OFFSET(4) "\n\t" CFI_REL_OFFSET(ebp, 0) "\n\t" "movl %7, %%ebp\n\t"
#define RESTOREARGS_0
-#define RESTOREARGS_1 "bpopl .L__X'%k2, %k2\n\t"
+#define RESTOREARGS_1 "pop %%ebx\n\t" CFI_ADJUST_CFA_OFFSET(-4) "\n\t" CFI_RESTORE(ebx) "\n\t" RESTOREARGS_0
#define RESTOREARGS_2 RESTOREARGS_1
#define RESTOREARGS_3 RESTOREARGS_1
#define RESTOREARGS_4 RESTOREARGS_1
#define RESTOREARGS_5 RESTOREARGS_1
-#define RESTOREARGS_6 "pop %%ebp\n\t" RESTOREARGS_1
+#define RESTOREARGS_6 "pop %%ebp\n\t" CFI_ADJUST_CFA_OFFSET(-4) "\n\t" CFI_RESTORE(ebp) "\n\t" RESTOREARGS_1
#define ASMFMT_0()
/* "acdSD" constraint would work too, but "SD" would use esi/edi and cause
@@ -162,7 +94,7 @@ __asm__ (
#define LOADARGS_3
#define LOADARGS_4
#define LOADARGS_5
-#define LOADARGS_6 "push %%ebp\n\t" "movl %7, %%ebp\n\t"
+#define LOADARGS_6 "push %%ebp\n\t" CFI_ADJUST_CFA_OFFSET(4) "\n\t" CFI_REL_OFFSET(ebp, 0) "\n\t" "movl %7, %%ebp\n\t"
#define RESTOREARGS_0
#define RESTOREARGS_1
@@ -170,7 +102,7 @@ __asm__ (
#define RESTOREARGS_3
#define RESTOREARGS_4
#define RESTOREARGS_5
-#define RESTOREARGS_6 "pop %%ebp\n\t"
+#define RESTOREARGS_6 "pop %%ebp\n\t" CFI_ADJUST_CFA_OFFSET(-4) "\n\t" CFI_RESTORE(ebp) "\n\t"
#define ASMFMT_0()
#define ASMFMT_1(arg1) \
diff --git a/libc/sysdeps/linux/i386/clone.S b/libc/sysdeps/linux/i386/clone.S
index a7de3fe27..cf6cd35ec 100644
--- a/libc/sysdeps/linux/i386/clone.S
+++ b/libc/sysdeps/linux/i386/clone.S
@@ -25,6 +25,7 @@
#define _ERRNO_H 1
#include <bits/errno.h>
+#include <sysdep.h>
#include <sys/syscall.h>
/* int clone(int (*fn)(void *arg), void *child_stack, int flags, void *arg,
@@ -45,6 +46,7 @@
.global clone
.type clone,%function
clone:
+ cfi_startproc;
/* Sanity check arguments. */
movl $-EINVAL,%eax
@@ -86,17 +88,28 @@ clone:
/* Do the system call */
pushl %ebx
+ cfi_adjust_cfa_offset (4)
pushl %esi
+ cfi_adjust_cfa_offset (4)
pushl %edi
+ cfi_adjust_cfa_offset (4)
+
movl TLS+12(%esp),%esi
+ cfi_rel_offset (esi, 4)
movl PTID+12(%esp),%edx
movl FLAGS+12(%esp),%ebx
+ cfi_rel_offset (ebx, 8)
movl CTID+12(%esp),%edi
+ cfi_rel_offset (edi, 0)
movl $__NR_clone,%eax
#ifdef RESET_PID
/* Remember the flag value. */
movl %ebx, (%ecx)
#endif
+ /* End FDE now, because in the child the unwind info will be
+ wrong. */
+ cfi_endproc
+
int $0x80
popl %edi
popl %esi
@@ -108,6 +121,9 @@ clone:
ret
.Lthread_start:
+ cfi_startproc;
+ /* Clearing frame pointer is insufficient, use CFI. */
+ cfi_undefined (eip);
/* Note: %esi is zero. */
movl %esi,%ebp /* terminate the stack frame */
call *%ebx
@@ -120,6 +136,7 @@ clone:
movl %eax, %ebx
movl $__NR_exit, %eax
int $0x80
+ cfi_endproc;
/* Need to indirect jump to syscall error
* or we end up with TEXTREL's
diff --git a/libc/sysdeps/linux/i386/sigaction.c b/libc/sysdeps/linux/i386/sigaction.c
index de0c75ded..f9af3f748 100644
--- a/libc/sysdeps/linux/i386/sigaction.c
+++ b/libc/sysdeps/linux/i386/sigaction.c
@@ -112,6 +112,9 @@ libc_hidden_weak(sigaction)
#define RESTORE2(name, syscall) \
__asm__ ( \
".text\n" \
+ ".align 8\n" \
+ " nop\n" \
+ ".align 16\n" \
"__" #name ":\n" \
" movl $" #syscall ", %eax\n" \
" int $0x80\n" \
@@ -128,6 +131,7 @@ RESTORE(restore_rt, __NR_rt_sigreturn)
# define RESTORE2(name, syscall) \
__asm__ ( \
".text\n" \
+ ".align 8\n" \
"__" #name ":\n" \
" popl %eax\n" \
" movl $" #syscall ", %eax\n" \