summaryrefslogtreecommitdiffstats
path: root/main/libc0.9.32/0007-libc-x86-fix-stack-unwinding-and-backtrace-informati.patch
blob: ba3681f334abe5c007a47d30bde77bbb2c82a3ea (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
From caed9d8dbc7e7b1e39a3e666d691d844da3ab12d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Timo=20Ter=C3=A4s?= <timo.teras@iki.fi>
Date: Thu, 10 Nov 2011 09:36:44 +0200
Subject: [PATCH 7/8] libc/x86: fix stack unwinding and backtrace information
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

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>
---
 libc/sysdeps/linux/i386/bits/syscalls.h |   82 +++----------------------------
 libc/sysdeps/linux/i386/clone.S         |   17 ++++++
 libc/sysdeps/linux/i386/sigaction.c     |    4 ++
 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 9fb4f35..35b09bb 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...) \
 (__extension__ \
@@ -32,90 +33,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
@@ -163,7 +95,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
@@ -171,7 +103,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 a7de3fe..cf6cd35 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 a6a22de..1b787a6 100644
--- a/libc/sysdeps/linux/i386/sigaction.c
+++ b/libc/sysdeps/linux/i386/sigaction.c
@@ -120,6 +120,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"			\
@@ -133,6 +136,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"		\
-- 
1.7.8.4