This is the mail archive of the libc-ports@sources.redhat.com mailing list for the libc-ports project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Fix unwinding for Thumb-2 libraries


I discovered that the backtrace() function would not work correctly if
GLIBC was built as Thumb-2.  You can see the reason why in the deleted
portion of the patch below: to avoid conflicts with GCC, which thinks
that r7 is the frame pointer with -mthumb, the inline syscall assembly
had to save r7 to the stack.  There was already a nasty workaround in
place to avoid pushing and popping.  That made backtrace appear to
work, but if r7 really was the frame pointer for something further up
the stack, unwinding would break down at that point.

This patch moves the "inline" syscalls to a special out-of-line helper
that takes the syscall number in ip instead of r7.

Tested on arm-none-linux-gnueabi.  Is this OK to commit?

[I'm not sure if I still have write access.]

-- 
Daniel Jacobowitz
CodeSourcery

2010-04-01  Daniel Jacobowitz  <dan@codesourcery.com>

	* sysdeps/unix/sysv/linux/arm/eabi/libc-do-syscall.S: New file.
	* sysdeps/unix/sysv/linux/arm/eabi/sysdep.h [__thumb__]
	(INTERNAL_SYSCALL_RAW): Rewrite to use __libc_do_syscall.
	* sysdeps/unix/sysv/linux/arm/eabi/Makefile: Add libc-do-syscall
	to libraries and tests that require it.

Index: sysdeps/unix/sysv/linux/arm/eabi/libc-do-syscall.S
===================================================================
--- sysdeps/unix/sysv/linux/arm/eabi/libc-do-syscall.S	(revision 0)
+++ sysdeps/unix/sysv/linux/arm/eabi/libc-do-syscall.S	(revision 0)
@@ -0,0 +1,43 @@
+/* Copyright (C) 2010 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
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <sysdep.h>
+
+/* Out-of-line syscall stub.  We expect the system call number in ip
+   and return the raw result in r0.  No registers are clobbered.
+   We could avoid using the stack for this, but the goal is accurate
+   unwind information - and while there is a reserved prefix in the
+   ARM unwind tables for register to register moves, the actual opcodes
+   are not defined.  */
+
+	.thumb
+	.syntax unified
+	.hidden __libc_do_syscall
+
+ENTRY (__libc_do_syscall)
+	.fnstart
+	push	{r7, lr}
+	.save	{r7, lr}
+	cfi_adjust_cfa_offset (8)
+	cfi_rel_offset (r7, 0)
+	cfi_rel_offset (lr, 4)
+	mov	r7, ip
+	swi	0x0
+	pop	{r7, pc}
+	.fnend
+END (__libc_do_syscall)
Index: sysdeps/unix/sysv/linux/arm/eabi/sysdep.h
===================================================================
--- sysdeps/unix/sysv/linux/arm/eabi/sysdep.h	(revision 10159)
+++ sysdeps/unix/sysv/linux/arm/eabi/sysdep.h	(working copy)
@@ -44,30 +44,34 @@
    argument; otherwise the (optional) compatibility code for APCS binaries
    may be invoked.  */
 
-#ifdef __thumb__
-/* Hide the use of r7 from the compiler, this would be a lot
-   easier but for the fact that the syscalls can exceed 255.
-   For the moment the LOAD_ARGS_7 is sacrificed.
+#if defined(__thumb__)
+/* We can not expose the use of r7 to the compiler.  GCC (as
+   of 4.5) uses r7 as the hard frame pointer for Thumb - although
+   for Thumb-2 it isn't obviously a better choice than r11.
+   And GCC does not support asms that conflict with the frame
+   pointer.
+
+   This would be easier if syscall numbers never exceeded 255,
+   but they do.  For the moment the LOAD_ARGS_7 is sacrificed.
    We can't use push/pop inside the asm because that breaks
-   unwinding (ie. thread cancellation).  */
-/* FIXME: the str / ldr of r7 are not covered by CFI information.  */
+   unwinding (i.e. thread cancellation) for this frame.  We can't
+   locally save and restore r7, because we do not know if this
+   function uses r7 or if it is our caller's r7; if it is our caller's,
+   then unwinding will fail higher up the stack.  So we move the
+   syscall out of line and provide its own unwind information.  */
 #undef LOAD_ARGS_7
 #undef INTERNAL_SYSCALL_RAW
 #define INTERNAL_SYSCALL_RAW(name, err, nr, args...)		\
   ({								\
-      int _sys_buf[2];						\
       register int _a1 asm ("a1");				\
-      register int *_r6 asm ("r6") = _sys_buf;			\
-      *_r6 = name;						\
+      int _nametmp = name;					\
       LOAD_ARGS_##nr (args)					\
-      asm volatile ("str        r7, [r6, #4]\n\t"		\
-                    "ldr      r7, [r6]\n\t"			\
-                    "swi      0       @ syscall " #name "\n\t"	\
-                    "ldr      r7, [r6, #4]"			\
-                   : "=r" (_a1)					\
-                    : "r" (_r6) ASM_ARGS_##nr			\
-                    : "memory");				\
-       _a1; })
+      register int _name asm ("ip") = _nametmp;			\
+      asm volatile ("bl      __libc_do_syscall"			\
+                    : "=r" (_a1)				\
+                    : "r" (_name) ASM_ARGS_##nr			\
+                    : "memory", "lr");				\
+      _a1; })
 #else /* ARM */
 #undef INTERNAL_SYSCALL_RAW
 #define INTERNAL_SYSCALL_RAW(name, err, nr, args...)		\
Index: sysdeps/unix/sysv/linux/arm/eabi/Makefile
===================================================================
--- sysdeps/unix/sysv/linux/arm/eabi/Makefile	(revision 10159)
+++ sysdeps/unix/sysv/linux/arm/eabi/Makefile	(working copy)
@@ -7,3 +7,34 @@ ifeq ($(subdir),csu)
 # unwind tables for __libc_start_main.
 CFLAGS-libc-start.c += -fexceptions
 endif
+
+# Add a syscall function to each library that needs one.
+
+ifeq ($(subdir),rt)
+librt-sysdep_routines += libc-do-syscall
+librt-shared-only-routines += libc-do-syscall
+endif
+
+ifeq ($(subdir),nptl)
+libpthread-sysdep_routines += libc-do-syscall
+libpthread-shared-only-routines += libc-do-syscall
+endif
+
+ifeq ($(subdir),resolv)
+libanl-sysdep_routines += libc-do-syscall
+libanl-shared-only-routines += libc-do-syscall
+endif
+
+ifeq ($(subdir),csu)
+sysdep_routines += libc-do-syscall
+endif
+
+ifeq ($(subdir),nscd)
+nscd-modules += libc-do-syscall
+endif
+
+ifeq ($(subdir),posix)
+LDFLAGS-tst-rfc3484 += $(common-objpfx)csu/libc-do-syscall.o
+LDFLAGS-tst-rfc3484-2 += $(common-objpfx)csu/libc-do-syscall.o
+LDFLAGS-tst-rfc3484-3 += $(common-objpfx)csu/libc-do-syscall.o
+endif


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]