From patchwork Mon Mar 21 18:28:54 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ulrich Weigand X-Patchwork-Id: 707 Return-Path: Delivered-To: unknown Received: from imap.gmail.com (74.125.159.109) by localhost6.localdomain6 with IMAP4-SSL; 08 Jun 2011 14:45:03 -0000 Delivered-To: patches@linaro.org Received: by 10.220.28.198 with SMTP id n6cs147780vcc; Mon, 21 Mar 2011 11:28:57 -0700 (PDT) Received: by 10.14.119.4 with SMTP id m4mr1427550eeh.116.1300732136736; Mon, 21 Mar 2011 11:28:56 -0700 (PDT) Received: from mtagate3.uk.ibm.com (mtagate3.uk.ibm.com [194.196.100.163]) by mx.google.com with ESMTPS id u13si6661206eeh.3.2011.03.21.11.28.55 (version=TLSv1/SSLv3 cipher=OTHER); Mon, 21 Mar 2011 11:28:56 -0700 (PDT) Received-SPF: softfail (google.com: domain of transitioning uweigand@de.ibm.com does not designate 194.196.100.163 as permitted sender) client-ip=194.196.100.163; Authentication-Results: mx.google.com; spf=softfail (google.com: domain of transitioning uweigand@de.ibm.com does not designate 194.196.100.163 as permitted sender) smtp.mail=uweigand@de.ibm.com Received: from d06nrmr1307.portsmouth.uk.ibm.com (d06nrmr1307.portsmouth.uk.ibm.com [9.149.38.129]) by mtagate3.uk.ibm.com (8.13.1/8.13.1) with ESMTP id p2LISt3Q014380 for ; Mon, 21 Mar 2011 18:28:55 GMT Received: from d06av02.portsmouth.uk.ibm.com (d06av02.portsmouth.uk.ibm.com [9.149.37.228]) by d06nrmr1307.portsmouth.uk.ibm.com (8.13.8/8.13.8/NCO v10.0) with ESMTP id p2LITLvd1269870 for ; Mon, 21 Mar 2011 18:29:21 GMT Received: from d06av02.portsmouth.uk.ibm.com (loopback [127.0.0.1]) by d06av02.portsmouth.uk.ibm.com (8.14.4/8.13.1/NCO v10.0 AVout) with ESMTP id p2LISt4B017230 for ; Mon, 21 Mar 2011 12:28:55 -0600 Received: from tuxmaker.boeblingen.de.ibm.com (tuxmaker.boeblingen.de.ibm.com [9.152.85.9]) by d06av02.portsmouth.uk.ibm.com (8.14.4/8.13.1/NCO v10.0 AVin) with SMTP id p2LISsix017221; Mon, 21 Mar 2011 12:28:54 -0600 Message-Id: <201103211828.p2LISsix017221@d06av02.portsmouth.uk.ibm.com> Received: by tuxmaker.boeblingen.de.ibm.com (sSMTP sendmail emulation); Mon, 21 Mar 2011 19:28:54 +0100 Subject: [PATCH][arm] Create ARM unwind records for system call stubs To: libc-ports@sourceware.org Date: Mon, 21 Mar 2011 19:28:54 +0100 (CET) From: "Ulrich Weigand" Cc: patches@linaro.org X-Mailer: ELM [version 2.5 PL2] MIME-Version: 1.0 Hello, ARM EABI system call stubs currently save r7 into IP (r12). However, while the stubs contain DWARF CFI that records this fact, there are no ARM unwind records. This is suboptimal for debugging with GDB, since the DWARF CFI is often stripped, while unwind records would be always available. The problem is that it is not actually possible to represent saving of a register into a different one with an ARM unwind record; those only support saving a register onto the stack. However, there is no real reason why the ARM system call stubs cannot just do so: that is, save r7 to the stack instead of IP. (In fact, the variants for NPTL cancellable system calls already do so.) See also the following thread on gdb-patches for further disussion: http://sourceware.org/ml/gdb-patches/2011-03/msg00616.html The patch below implements this change. It consists of three parts: - eabi/sysdep.h: DO_CALL / DOARGS_xxx / UNDOARGS_xxx This is main change to save/restore r7 onto the stack and create an ARM unwind record. - eabi/nptl/sysdel-cancel.h: This needs to be adapted to the above changes; the code already saves r7 to the stack, which is now unnecesary since it is done by the base DOARGS_xxx / UNDOARGS_xxx macros already. Also, handling of ARM unwind records needs to be adapted to cope for the pre-existing actions of the DOARGS macros. - vfork.S This is a bit of a special case. In the vfork system call stub, we cannot restore from the stack (in the parent), because the child -which shared the parent's address space until exec- will have already clobbered stack contents. Therefore I'm saving r7 both to IP (from which the value will actually be restored) *and* to the stack (which gets recorded into the ARM unwind info). This enables proper unwinding at least at the point of the system call (which is important since GDB sets an implicit breakpoint there to track vforks). I've tested this by running the glibc testsuite on armv7l-linux-gnueabi with no regressions. I've also rebuild an Ubuntu Natty libc with this patch applied; using this as system library, I've ran the GDB test suite with no regressions, and a couple of failures were fixed (in the absence of DWARF debug info for libc). Bye, Ulrich ChangeLog.arm: 2011-03-21 Ulrich Weigand * sysdeps/unix/sysv/arm/eabi/sysdep.h (DO_CALL): Do not save/restore r7 into IP. (DOARGS_0, UNDOARGS_0): Redefine to save/restore r7 to the stack. Create appropriate ARM unwind record. (DOARGS_1, UNDOARGS_1): Likewise. (DOARGS_2, UNDOARGS_2): Likewise. (DOARGS_3, UNDOARGS_3): Likewise. (DOARGS_4, UNDOARGS_4): Likewise. (DOARGS_5, UNDOARGS_5): Likewise. (DOARGS_6, UNDOARGS_6): Likewise. (DOARGS_7, UNDOARGS_7): Likewise. * sysdeps/unix/sysv/arm/eabi/nptl/sysdep-cancel.h (PSEUDO): Adapt to DO_CALL/DOARGS_xxx/UNDOARGS_xxx changes. (RESTART_UNWIND): Likewise. (DOCARGS_0, RESTORE_LR_0): Likewise. (DOCARGS_1): Likewise. (DOCARGS_2): Likewise. (DOCARGS_3): Likewise. (DOCARGS_4): Likewise. (DOCARGS_5, UNDOCARGS_5, RESTORE_LR_5): Likewise. (DOCARGS_6, UNDOCARGS_6): Likewise. * sysdeps/unix/sysv/linux/arm/vfork.S (__vfork): Do no use DO_CALL to call vfork. In the __ARM_EABI__ case, save r7 both to IP (to restore from) and the stack (to create an ARM unwind record). diff --git a/sysdeps/unix/sysv/linux/arm/eabi/nptl/sysdep-cancel.h b/sysdeps/unix/sysv/linux/arm/eabi/nptl/sysdep-cancel.h index 458558b..f4a8af4 100644 --- a/sysdeps/unix/sysv/linux/arm/eabi/nptl/sysdep-cancel.h +++ b/sysdeps/unix/sysv/linux/arm/eabi/nptl/sysdep-cancel.h @@ -47,20 +47,20 @@ DOARGS_##args; \ bne .Lpseudo_cancel; \ cfi_remember_state; \ - DO_CALL (syscall_name, 0); \ + ldr r7, =SYS_ify (syscall_name); \ + swi 0x0; \ UNDOARGS_##args; \ cmn r0, $4096; \ PSEUDO_RET; \ cfi_restore_state; \ .Lpseudo_cancel: \ - .fnstart; \ + .fnstart; /* matched by the .fnend in UNDOARGS below. */ \ DOCARGS_##args; /* save syscall args etc. around CENABLE. */ \ CENABLE; \ mov ip, r0; /* put mask in safe place. */ \ UNDOCARGS_##args; /* restore syscall args. */ \ ldr r7, =SYS_ify (syscall_name); \ swi 0x0; /* do the call. */ \ - .fnend; /* Past here we can't easily unwind. */ \ mov r7, r0; /* save syscall return value. */ \ mov r0, ip; /* get mask back. */ \ CDISABLE; \ @@ -69,34 +69,34 @@ UNDOARGS_##args; \ cmn r0, $4096 -/* DOARGS pushes four bytes on the stack for five arguments, eight bytes for - six arguments, and nothing for fewer. In order to preserve doubleword +/* DOARGS pushes eight bytes on the stack for five arguments, twelve bytes for + six arguments, and four bytes for fewer. In order to preserve doubleword alignment, sometimes we must save an extra register. */ # define RESTART_UNWIND \ .fnend; \ .fnstart; \ - .save {r7, lr} + .save {r7}; \ + .save {lr} # define DOCARGS_0 \ - stmfd sp!, {r7, lr}; \ - cfi_adjust_cfa_offset (8); \ - cfi_rel_offset (r7, 0); \ - cfi_rel_offset (lr, 4); \ - .save {r7, lr} + .save {r7}; \ + str lr, [sp, #-4]!; \ + cfi_adjust_cfa_offset (4); \ + cfi_rel_offset (lr, 0); \ + .save {lr} # define UNDOCARGS_0 # define RESTORE_LR_0 \ - ldmfd sp!, {r7, lr}; \ - cfi_adjust_cfa_offset (-8); \ - cfi_restore (r7); \ + ldr lr, [sp], #4; \ + cfi_adjust_cfa_offset (-4); \ cfi_restore (lr) # define DOCARGS_1 \ - stmfd sp!, {r0, r1, r7, lr}; \ - cfi_adjust_cfa_offset (16); \ - cfi_rel_offset (r7, 8); \ - cfi_rel_offset (lr, 12); \ - .save {r7, lr}; \ + .save {r7}; \ + stmfd sp!, {r0, r1, lr}; \ + cfi_adjust_cfa_offset (12); \ + cfi_rel_offset (lr, 8); \ + .save {lr}; \ .pad #8 # define UNDOCARGS_1 \ ldr r0, [sp], #8; \ @@ -106,11 +106,11 @@ RESTORE_LR_0 # define DOCARGS_2 \ - stmfd sp!, {r0, r1, r7, lr}; \ - cfi_adjust_cfa_offset (16); \ - cfi_rel_offset (r7, 8); \ - cfi_rel_offset (lr, 12); \ - .save {r7, lr}; \ + .save {r7}; \ + stmfd sp!, {r0, r1, lr}; \ + cfi_adjust_cfa_offset (12); \ + cfi_rel_offset (lr, 8); \ + .save {lr}; \ .pad #8 # define UNDOCARGS_2 \ ldmfd sp!, {r0, r1}; \ @@ -120,11 +120,11 @@ RESTORE_LR_0 # define DOCARGS_3 \ - stmfd sp!, {r0, r1, r2, r3, r7, lr}; \ - cfi_adjust_cfa_offset (24); \ - cfi_rel_offset (r7, 16); \ - cfi_rel_offset (lr, 20); \ - .save {r7, lr}; \ + .save {r7}; \ + stmfd sp!, {r0, r1, r2, r3, lr}; \ + cfi_adjust_cfa_offset (20); \ + cfi_rel_offset (lr, 16); \ + .save {lr}; \ .pad #16 # define UNDOCARGS_3 \ ldmfd sp!, {r0, r1, r2, r3}; \ @@ -134,11 +134,11 @@ RESTORE_LR_0 # define DOCARGS_4 \ - stmfd sp!, {r0, r1, r2, r3, r7, lr}; \ - cfi_adjust_cfa_offset (24); \ - cfi_rel_offset (r7, 16); \ - cfi_rel_offset (lr, 20); \ - .save {r7, lr}; \ + .save {r7}; \ + stmfd sp!, {r0, r1, r2, r3, lr}; \ + cfi_adjust_cfa_offset (20); \ + cfi_rel_offset (lr, 16); \ + .save {lr}; \ .pad #16 # define UNDOCARGS_4 \ ldmfd sp!, {r0, r1, r2, r3}; \ @@ -149,43 +149,40 @@ /* r4 is only stmfd'ed for correct stack alignment. */ # define DOCARGS_5 \ - .save {r4}; \ - stmfd sp!, {r0, r1, r2, r3, r4, r7, lr}; \ - cfi_adjust_cfa_offset (28); \ - cfi_rel_offset (r7, 20); \ - cfi_rel_offset (lr, 24); \ - .save {r7, lr}; \ + .save {r4, r7}; \ + stmfd sp!, {r0, r1, r2, r3, r4, lr}; \ + cfi_adjust_cfa_offset (24); \ + cfi_rel_offset (lr, 20); \ + .save {lr}; \ .pad #20 # define UNDOCARGS_5 \ ldmfd sp!, {r0, r1, r2, r3}; \ cfi_adjust_cfa_offset (-16); \ .fnend; \ .fnstart; \ - .save {r4}; \ - .save {r7, lr}; \ + .save {r4, r7}; \ + .save {lr}; \ .pad #4 # define RESTORE_LR_5 \ - ldmfd sp!, {r4, r7, lr}; \ - cfi_adjust_cfa_offset (-12); \ + ldmfd sp!, {r4, lr}; \ + cfi_adjust_cfa_offset (-8); \ /* r4 will be marked as restored later. */ \ - cfi_restore (r7); \ cfi_restore (lr) # define DOCARGS_6 \ - .save {r4, r5}; \ - stmfd sp!, {r0, r1, r2, r3, r7, lr}; \ - cfi_adjust_cfa_offset (24); \ - cfi_rel_offset (r7, 16); \ - cfi_rel_offset (lr, 20); \ - .save {r7, lr}; \ + .save {r4, r5, r7}; \ + stmfd sp!, {r0, r1, r2, r3, lr}; \ + cfi_adjust_cfa_offset (20); \ + cfi_rel_offset (lr, 16); \ + .save {lr}; \ .pad #16 # define UNDOCARGS_6 \ ldmfd sp!, {r0, r1, r2, r3}; \ cfi_adjust_cfa_offset (-16); \ .fnend; \ .fnstart; \ - .save {r4, r5}; \ - .save {r7, lr} + .save {r4, r5, r7}; \ + .save {lr}; # define RESTORE_LR_6 \ RESTORE_LR_0 diff --git a/sysdeps/unix/sysv/linux/arm/eabi/sysdep.h b/sysdeps/unix/sysv/linux/arm/eabi/sysdep.h index b7815ba..a80621e 100644 --- a/sysdeps/unix/sysv/linux/arm/eabi/sysdep.h +++ b/sysdeps/unix/sysv/linux/arm/eabi/sysdep.h @@ -106,12 +106,95 @@ #undef DO_CALL #define DO_CALL(syscall_name, args) \ DOARGS_##args; \ - mov ip, r7; \ - cfi_register (r7, ip); \ ldr r7, =SYS_ify (syscall_name); \ swi 0x0; \ - mov r7, ip; \ - cfi_restore (r7); \ UNDOARGS_##args +#undef DOARGS_0 +#define DOARGS_0 \ + .fnstart; \ + str r7, [sp, #-4]!; \ + cfi_adjust_cfa_offset (4); \ + cfi_rel_offset (r7, 0); \ + .save { r7 } +#undef DOARGS_1 +#define DOARGS_1 DOARGS_0 +#undef DOARGS_2 +#define DOARGS_2 DOARGS_0 +#undef DOARGS_3 +#define DOARGS_3 DOARGS_0 +#undef DOARGS_4 +#define DOARGS_4 DOARGS_0 +#undef DOARGS_5 +#define DOARGS_5 \ + .fnstart; \ + stmfd sp!, {r4, r7}; \ + cfi_adjust_cfa_offset (8); \ + cfi_rel_offset (r4, 0); \ + cfi_rel_offset (r7, 4); \ + .save { r4, r7 }; \ + ldr r4, [sp, #8] +#undef DOARGS_6 +#define DOARGS_6 \ + .fnstart; \ + mov ip, sp; \ + stmfd sp!, {r4, r5, r7}; \ + cfi_adjust_cfa_offset (12); \ + cfi_rel_offset (r4, 0); \ + cfi_rel_offset (r5, 4); \ + cfi_rel_offset (r7, 8); \ + .save { r4, r5, r7 }; \ + ldmia ip, {r4, r5} +#undef DOARGS_7 +#define DOARGS_7 \ + .fnstart; \ + mov ip, sp; \ + stmfd sp!, {r4, r5, r6, r7}; \ + cfi_adjust_cfa_offset (16); \ + cfi_rel_offset (r4, 0); \ + cfi_rel_offset (r5, 4); \ + cfi_rel_offset (r6, 8); \ + cfi_rel_offset (r7, 12); \ + .save { r4, r5, r6, r7 }; \ + ldmia ip, {r4, r5, r6} + +#undef UNDOARGS_0 +#define UNDOARGS_0 \ + ldr r7, [sp], #4; \ + cfi_adjust_cfa_offset (-4); \ + cfi_restore (r7); \ + .fnend +#undef UNDOARGS_1 +#define UNDOARGS_1 UNDOARGS_0 +#undef UNDOARGS_2 +#define UNDOARGS_2 UNDOARGS_0 +#undef UNDOARGS_3 +#define UNDOARGS_3 UNDOARGS_0 +#undef UNDOARGS_4 +#define UNDOARGS_4 UNDOARGS_0 +#undef UNDOARGS_5 +#define UNDOARGS_5 \ + ldmfd sp!, {r4, r7}; \ + cfi_adjust_cfa_offset (-8); \ + cfi_restore (r4); \ + cfi_restore (r7); \ + .fnend +#undef UNDOARGS_6 +#define UNDOARGS_6 \ + ldmfd sp!, {r4, r5, r7}; \ + cfi_adjust_cfa_offset (-12); \ + cfi_restore (r4); \ + cfi_restore (r5); \ + cfi_restore (r7); \ + .fnend +#undef UNDOARGS_7 +#define UNDOARGS_7 \ + ldmfd sp!, {r4, r5, r6, r7}; \ + cfi_adjust_cfa_offset (-16); \ + cfi_restore (r4); \ + cfi_restore (r5); \ + cfi_restore (r6); \ + cfi_restore (r7); \ + .fnend + #endif /* _LINUX_ARM_EABI_SYSDEP_H */ diff --git a/sysdeps/unix/sysv/linux/arm/vfork.S b/sysdeps/unix/sysv/linux/arm/vfork.S index a020658..e63690e 100644 --- a/sysdeps/unix/sysv/linux/arm/vfork.S +++ b/sysdeps/unix/sysv/linux/arm/vfork.S @@ -33,7 +33,28 @@ ENTRY (__vfork) #ifdef SAVE_PID SAVE_PID #endif - DO_CALL (vfork, 0) +#ifdef __ARM_EABI__ + /* The DO_CALL macro saves r7 on the stack, to enable generation + of ARM unwind info. Since the stack is initially shared between + parent and child of vfork, that saved value could be corrupted. + To avoid this problem, we save r7 into ip as well, and restore + from there. */ + mov ip, r7 + cfi_register (r7, ip) + .fnstart + str r7, [sp, #-4]! + cfi_adjust_cfa_offset (4) + .save { r7 } + ldr r7, =SYS_ify (vfork) + swi 0x0 + .fnend + add sp, sp, #4 + cfi_adjust_cfa_offset (-4) + mov r7, ip + cfi_restore (r7); +#else + swi SYS_ify(vfork) +#endif #ifdef RESTORE_PID RESTORE_PID #endif