summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--libpthread/nptl/sysdeps/unix/sysv/linux/arm/sysdep-cancel.h167
1 files changed, 142 insertions, 25 deletions
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/arm/sysdep-cancel.h b/libpthread/nptl/sysdeps/unix/sysv/linux/arm/sysdep-cancel.h
index 423c23195..7ac9ca1e9 100644
--- a/libpthread/nptl/sysdeps/unix/sysv/linux/arm/sysdep-cancel.h
+++ b/libpthread/nptl/sysdeps/unix/sysv/linux/arm/sysdep-cancel.h
@@ -1,4 +1,4 @@
-/* Copyright (C) 2003, 2004, 2005 Free Software Foundation, Inc.
+/* Copyright (C) 2003, 2004, 2005, 2009 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
@@ -24,6 +24,11 @@
#if !defined NOT_IN_libc || defined IS_IN_libpthread || defined IS_IN_librt
+/* NOTE: We do mark syscalls with unwind annotations, for the benefit of
+ cancellation; but they're really only accurate at the point of the
+ syscall. The ARM unwind directives are not rich enough without adding
+ a custom personality function. */
+
# undef PSEUDO
# define PSEUDO(name, syscall_name, args) \
.section ".text"; \
@@ -31,50 +36,158 @@
.type __##syscall_name##_nocancel,%function; \
.globl __##syscall_name##_nocancel; \
__##syscall_name##_nocancel: \
+ .cfi_sections .debug_frame; \
+ cfi_startproc; \
DO_CALL (syscall_name, args); \
PSEUDO_RET; \
+ cfi_endproc; \
.size __##syscall_name##_nocancel,.-__##syscall_name##_nocancel; \
ENTRY (name); \
SINGLE_THREAD_P; \
DOARGS_##args; \
bne .Lpseudo_cancel; \
+ cfi_remember_state; \
DO_CALL (syscall_name, 0); \
UNDOARGS_##args; \
cmn r0, $4096; \
PSEUDO_RET; \
+ cfi_restore_state; \
.Lpseudo_cancel: \
+ .fnstart; \
DOCARGS_##args; /* save syscall args etc. around CENABLE. */ \
CENABLE; \
mov ip, r0; /* put mask in safe place. */ \
UNDOCARGS_##args; /* restore syscall args. */ \
- swi SYS_ify (syscall_name); /* do the call. */ \
- str r0, [sp, $-4]!; /* save syscall return value. */ \
+ 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; \
- ldmfd sp!, {r0, lr}; /* retrieve return value and address. */ \
+ mov r0, r7; /* retrieve return value. */ \
+ RESTORE_LR_##args; \
UNDOARGS_##args; \
- cmn r0, $4096;
-
-# define DOCARGS_0 str lr, [sp, #-4]!;
+ 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
+ alignment, sometimes we must save an extra register. */
+
+# define RESTART_UNWIND \
+ .fnend; \
+ .fnstart; \
+ .save {r7, 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}
# define UNDOCARGS_0
-
-# define DOCARGS_1 stmfd sp!, {r0, lr};
-# define UNDOCARGS_1 ldr r0, [sp], #4;
-
-# define DOCARGS_2 stmfd sp!, {r0, r1, lr};
-# define UNDOCARGS_2 ldmfd sp!, {r0, r1};
-
-# define DOCARGS_3 stmfd sp!, {r0, r1, r2, lr};
-# define UNDOCARGS_3 ldmfd sp!, {r0, r1, r2};
-
-# define DOCARGS_4 stmfd sp!, {r0, r1, r2, r3, lr};
-# define UNDOCARGS_4 ldmfd sp!, {r0, r1, r2, r3};
-
-# define DOCARGS_5 DOCARGS_4
-# define UNDOCARGS_5 UNDOCARGS_4
-
-# define DOCARGS_6 DOCARGS_5
-# define UNDOCARGS_6 UNDOCARGS_5
+# define RESTORE_LR_0 \
+ ldmfd sp!, {r7, lr}; \
+ cfi_adjust_cfa_offset (-8); \
+ cfi_restore (r7); \
+ 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}; \
+ .pad #8
+# define UNDOCARGS_1 \
+ ldr r0, [sp], #8; \
+ cfi_adjust_cfa_offset (-8); \
+ RESTART_UNWIND
+# define RESTORE_LR_1 \
+ 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}; \
+ .pad #8
+# define UNDOCARGS_2 \
+ ldmfd sp!, {r0, r1}; \
+ cfi_adjust_cfa_offset (-8); \
+ RESTART_UNWIND
+# define RESTORE_LR_2 \
+ 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}; \
+ .pad #16
+# define UNDOCARGS_3 \
+ ldmfd sp!, {r0, r1, r2, r3}; \
+ cfi_adjust_cfa_offset (-16); \
+ RESTART_UNWIND
+# define RESTORE_LR_3 \
+ 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}; \
+ .pad #16
+# define UNDOCARGS_4 \
+ ldmfd sp!, {r0, r1, r2, r3}; \
+ cfi_adjust_cfa_offset (-16); \
+ RESTART_UNWIND
+# define RESTORE_LR_4 \
+ RESTORE_LR_0
+
+/* 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}; \
+ .pad #20
+# define UNDOCARGS_5 \
+ ldmfd sp!, {r0, r1, r2, r3}; \
+ cfi_adjust_cfa_offset (-16); \
+ .fnend; \
+ .fnstart; \
+ .save {r4}; \
+ .save {r7, lr}; \
+ .pad #4
+# define RESTORE_LR_5 \
+ ldmfd sp!, {r4, r7, lr}; \
+ cfi_adjust_cfa_offset (-12); \
+ /* 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}; \
+ .pad #16
+# define UNDOCARGS_6 \
+ ldmfd sp!, {r0, r1, r2, r3}; \
+ cfi_adjust_cfa_offset (-16); \
+ .fnend; \
+ .fnstart; \
+ .save {r4, r5}; \
+ .save {r7, lr}
+# define RESTORE_LR_6 \
+ RESTORE_LR_0
# ifdef IS_IN_libpthread
# define CENABLE bl PLTJMP(__pthread_enable_asynccancel)
@@ -114,9 +227,13 @@ extern int __local_multiple_threads attribute_hidden;
# define PSEUDO_PROLOGUE
# define SINGLE_THREAD_P \
stmfd sp!, {r0, lr}; \
+ cfi_adjust_cfa_offset (8); \
+ cfi_rel_offset (lr, 4); \
bl __aeabi_read_tp; \
ldr ip, [r0, #MULTIPLE_THREADS_OFFSET]; \
ldmfd sp!, {r0, lr}; \
+ cfi_adjust_cfa_offset (-8); \
+ cfi_restore (lr); \
teq ip, #0
# define SINGLE_THREAD_P_PIC(x) SINGLE_THREAD_P
# endif