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

Note that libc-hacker is a closed list. You may look at the archives of this list, but subscription and posting are not open.


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

[PATCH] Fix AMD64 backtrace


Hi!

The cfi_startproc hidden in x86_64's ENTRY and cfi_endproc in END macros
causes several routines to have incorrect unwind info.
I went through them and the problems are in at least:
libc/linuxthreads/sysdeps/unix/sysv/linux/x86_64/vfork.S
libc/sysdeps/unix/sysv/linux/x86_64/__start_context.S
libc/sysdeps/unix/sysv/linux/x86_64/clone.S
libc/sysdeps/unix/sysv/linux/x86_64/getcontext.S
libc/sysdeps/unix/sysv/linux/x86_64/setcontext.S
libc/sysdeps/unix/sysv/linux/x86_64/swapcontext.S
libc/sysdeps/unix/sysv/linux/x86_64/sysdep.S
libc/sysdeps/unix/sysv/linux/x86_64/vfork.S
libc/sysdeps/unix/x86_64/sysdep.S
libc/sysdeps/x86_64/__longjmp.S
libc/sysdeps/x86_64/strcspn.S
libc/sysdeps/x86_64/strspn.S
(that's all .S x86_64 files which use ENTRY/END, don't use any cfi_*
directives, and don't maintain constant %rsp over its lifetime or
clobber call saved registers).

The testcase below segfaults on AMD64, because thread_start part of __clone
has incorrect unwind info.
I don't think there is any frame info termination on AMD64
(e.g. when context->ra is 0 libgcc segfaults), so I'd say it is better to
avoid the unwind info in that case altogether, which will cause e.g.
backtrace to stop.  I've terminated the FDE already before syscall,
because then the unwind info would need to differentiate between
%rax == 0 (terminate unwind info chain; how?) and %rax != 0 (the current
DW_CFA_nop should be sufficient).

For the remaining of the above failes, either they should start using
ENTRY_NOCFI/END_NOCFI, or, IMHO better given that GCC defaults to
-fasynchronous-unwind-tables on AMD64, cfi_* directives should be added.

2004-01-08  Jakub Jelinek  <jakub@redhat.com>

	* sysdeps/unix/sysv/linux/x86_64/clone.S (__clone): Add cfi_endproc
	right before syscall and cfi_startproc before PSEUDO_END.
	Clear %rbp in thread_start.
nptl/
	* Makefile (tests): Add tst-backtrace1.
	* tst-backtrace1.c: New test.

--- libc/sysdeps/unix/sysv/linux/x86_64/clone.S.jj	2003-03-04 20:45:35.000000000 +0100
+++ libc/sysdeps/unix/sysv/linux/x86_64/clone.S	2004-01-08 16:20:37.000000000 +0100
@@ -1,4 +1,4 @@
-/* Copyright (C) 2001, 2002, 2003 Free Software Foundation, Inc.
+/* Copyright (C) 2001, 2002, 2003, 2004 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
@@ -72,6 +72,10 @@ ENTRY (BP_SYM (__clone))
 	movq	%r9, %r8
 	movq	8(%rsp), %r10
 	movq	$SYS_ify(clone),%rax
+
+	/* End FDE now, because in the child the unwind info will be
+	   wrong.  */
+	cfi_endproc;
 	syscall
 
 	testq	%rax,%rax
@@ -82,6 +86,10 @@ L(pseudo_end):
 	ret
 
 thread_start:
+	/* Clear the frame pointer.  The ABI suggests this be done, to mark
+	   the outermost frame obviously.  */
+	xorq	%rbp, %rbp
+
 	/* Set up arguments for the function call.  */
 	popq	%rax		/* Function to call.  */
 	popq	%rdi		/* Argument.  */
@@ -90,6 +98,7 @@ thread_start:
 	movq	%rax, %rdi
 	call	HIDDEN_JUMPTARGET (_exit)
 
+	cfi_startproc;
 PSEUDO_END (BP_SYM (__clone))
 
 weak_alias (BP_SYM (__clone), BP_SYM (clone))
--- libc/nptl/Makefile.jj	2003-12-29 15:01:27.000000000 +0100
+++ libc/nptl/Makefile	2004-01-08 16:25:24.000000000 +0100
@@ -1,4 +1,4 @@
-# Copyright (C) 2002, 2003 Free Software Foundation, Inc.
+# Copyright (C) 2002, 2003, 2004 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
@@ -235,6 +235,7 @@ tests = tst-attr1 tst-attr2 tst-attr3 \
 	tst-clock1 tst-clock2 \
 	tst-context1 \
 	tst-sched1 \
+	tst-backtrace1 \
 	tst-oddstacklimit
 
 # This sets the stack resource limit to 1023kb, which is not a multiple
--- libc/nptl/tst-backtrace1.c.jj	2004-01-08 16:24:13.000000000 +0100
+++ libc/nptl/tst-backtrace1.c	2004-01-08 16:24:06.000000000 +0100
@@ -0,0 +1,86 @@
+/* Copyright (C) 2004 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Jakub Jelinek <jakub@redhat.com>, 2004.
+
+   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 <execinfo.h>
+#include <pthread.h>
+#include <stdio.h>
+
+#define BT_SIZE 64
+void *bt_array[BT_SIZE];
+int bt_cnt;
+
+int
+do_bt (void)
+{
+  bt_cnt = backtrace (bt_array, BT_SIZE);
+  return 56;
+}
+
+int
+call_do_bt (void)
+{
+  return do_bt () + 1;
+}
+
+void *
+tf (void *arg)
+{
+  if (call_do_bt () != 57)
+    return (void *) 1L;
+  return NULL;
+}
+
+int
+do_test (void)
+{
+  pthread_t th;
+  if (pthread_create (&th, NULL, tf, NULL))
+    {
+      puts ("create failed");
+      return 1;
+    }
+
+  void *res;
+  if (pthread_join (th, &res))
+    {
+      puts ("join failed");
+      return 1;
+    }
+
+  if (res != NULL)
+    {
+      puts ("thread failed");
+      return 1;
+    }
+
+  char **text = backtrace_symbols (bt_array, bt_cnt);
+  if (text == NULL)
+    {
+      puts ("backtrace_symbols failed");
+      return 1;
+    }
+
+  for (int i = 0; i < bt_cnt; ++i)
+    puts (text[i]);
+
+  return 0;
+}
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"

	Jakub


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