S390: Add cfi information for start routines in order to stop unwinding.

Message ID 7599203b-933e-335b-4ffd-3a97a8679855@linux.vnet.ibm.com
State Committed
Headers

Commit Message

Stefan Liebler Nov. 14, 2017, 9:52 a.m. UTC
  Hi,

GDB failed to detect the outermost frame while showing the backtrace
within a thread:
Backtrace stopped: previous frame identical to this frame (corrupt stack?)

Before this patch, the start routines like thread_start had
no cfi information. GDB is then using the prologue unwinder if
no cfi information is available. This unwinder tries to unwind r15
and stops e.g. if r15 was updated or on some jump-instructions.

On older glibc-versions (before commit "Remove cached PID/TID in clone"
c579f48edba88380635ab98cb612030e3ed8691e), the thread_start function
used such a jump-instruction and GDB did not fail with an error.

This patch adds cfi information for _start, thread_start and
__makecontext_ret and marks r14 as undefined which marks the frame
as outermost frame and GDB stops the backtrace. Also tested
different gcc versions in order to test _Unwind_Backtrace() in libgcc
as this is used by backtrace() in glibc.

Bye
Stefan

ChangeLog:

	* sysdeps/s390/s390-64/start.S (_start):
	Add cfi information for r14.
	* sysdeps/s390/s390-32/start.S: (_start): Likewise
	* sysdeps/unix/sysv/linux/s390/s390-64/clone.S
	(thread_start): Likewise.
	* sysdeps/unix/sysv/linux/s390/s390-32/clone.S
	(thread_start): Likewise.
	* sysdeps/unix/sysv/linux/s390/s390-64/__makecontext_ret.S
	(__makecontext_ret): Likewise.
	* sysdeps/unix/sysv/linux/s390/s390-32/__makecontext_ret.S
	(__makecontext_ret): Likewise.
  

Comments

Stefan Liebler Nov. 21, 2017, 7:48 a.m. UTC | #1
On 11/14/2017 10:52 AM, Stefan Liebler wrote:
> Hi,
> 
> GDB failed to detect the outermost frame while showing the backtrace
> within a thread:
> Backtrace stopped: previous frame identical to this frame (corrupt stack?)
> 
> Before this patch, the start routines like thread_start had
> no cfi information. GDB is then using the prologue unwinder if
> no cfi information is available. This unwinder tries to unwind r15
> and stops e.g. if r15 was updated or on some jump-instructions.
> 
> On older glibc-versions (before commit "Remove cached PID/TID in clone"
> c579f48edba88380635ab98cb612030e3ed8691e), the thread_start function
> used such a jump-instruction and GDB did not fail with an error.
> 
> This patch adds cfi information for _start, thread_start and
> __makecontext_ret and marks r14 as undefined which marks the frame
> as outermost frame and GDB stops the backtrace. Also tested
> different gcc versions in order to test _Unwind_Backtrace() in libgcc
> as this is used by backtrace() in glibc.
> 
> Bye
> Stefan
> 
> ChangeLog:
> 
>      * sysdeps/s390/s390-64/start.S (_start):
>      Add cfi information for r14.
>      * sysdeps/s390/s390-32/start.S: (_start): Likewise
>      * sysdeps/unix/sysv/linux/s390/s390-64/clone.S
>      (thread_start): Likewise.
>      * sysdeps/unix/sysv/linux/s390/s390-32/clone.S
>      (thread_start): Likewise.
>      * sysdeps/unix/sysv/linux/s390/s390-64/__makecontext_ret.S
>      (__makecontext_ret): Likewise.
>      * sysdeps/unix/sysv/linux/s390/s390-32/__makecontext_ret.S
>      (__makecontext_ret): Likewise.

Committed
  

Patch

commit f078ec7c04c5b82b98002946d6d7f388187a2e49
Author: Stefan Liebler <stli@linux.vnet.ibm.com>
Date:   Fri Nov 10 09:40:03 2017 +0100

    S390: Add cfi information for start routines in order to stop unwinding.
    
    GDB failed to detect the outermost frame while showing the backtrace
    within a thread:
    Backtrace stopped: previous frame identical to this frame (corrupt stack?)
    
    Before this patch, the start routines like thread_start had no cfi information.
    GDB is then using the prologue unwinder if no cfi information is available.
    This unwinder tries to unwind r15 and stops e.g. if r15 was updated or
    on some jump-instructions.
    
    On older glibc-versions (before commit "Remove cached PID/TID in clone"
    c579f48edba88380635ab98cb612030e3ed8691e), the thread_start function used
    such a jump-instruction and GDB did not fail with an error.
    
    This patch adds cfi information for _start, thread_start and __makecontext_ret
    and marks r14 as undefined which marks the frame as outermost frame and GDB
    stops the backtrace. Also tested different gcc versions in order to test
    _Unwind_Backtrace() in libgcc as this is used by backtrace() in glibc.
    
    ChangeLog:
    
    	* sysdeps/s390/s390-64/start.S (_start): Add cfi information for r14.
    	* sysdeps/s390/s390-32/start.S: (_start): Likewise
    	* sysdeps/unix/sysv/linux/s390/s390-64/clone.S
    	(thread_start): Likewise.
    	* sysdeps/unix/sysv/linux/s390/s390-32/clone.S
    	(thread_start): Likewise.
    	* sysdeps/unix/sysv/linux/s390/s390-64/__makecontext_ret.S
    	(__makecontext_ret): Likewise.
    	* sysdeps/unix/sysv/linux/s390/s390-32/__makecontext_ret.S
    	(__makecontext_ret): Likewise.

diff --git a/sysdeps/s390/s390-32/start.S b/sysdeps/s390/s390-32/start.S
index 07400f1..66c00f3 100644
--- a/sysdeps/s390/s390-32/start.S
+++ b/sysdeps/s390/s390-32/start.S
@@ -34,6 +34,8 @@ 
    License along with the GNU C Library; if not, see
    <http://www.gnu.org/licenses/>.  */
 
+#include <sysdep.h>
+
 /*
    This is the canonical entry point, usually the first thing in the text
    segment. Most registers' values are unspecified, except for:
@@ -57,6 +59,10 @@ 
 	.globl _start
 	.type _start,@function
 _start:
+	cfi_startproc
+	/* Mark r14 as undefined in order to stop unwinding here!  */
+	cfi_undefined (r14)
+
 	/* Check if the kernel provides highgprs facility if needed by
 	   the binary.  */
 
@@ -188,6 +194,7 @@  _start:
 	/* crash if __libc_start_main returns */
 	.word   0
 
+	cfi_endproc
 .Llit:
 #ifndef PIC
 .L1:    .long  __libc_csu_init
diff --git a/sysdeps/s390/s390-64/start.S b/sysdeps/s390/s390-64/start.S
index d8e6545..d3e62d2 100644
--- a/sysdeps/s390/s390-64/start.S
+++ b/sysdeps/s390/s390-64/start.S
@@ -34,6 +34,8 @@ 
    License along with the GNU C Library; if not, see
    <http://www.gnu.org/licenses/>.  */
 
+#include <sysdep.h>
+
 /*
    This is the canonical entry point, usually the first thing in the text
    segment. Most registers' values are unspecified, except for:
@@ -57,6 +59,9 @@ 
 	.globl _start
 	.type _start,@function
 _start:
+	cfi_startproc
+	/* Mark r14 as undefined in order to stop unwinding here!  */
+	cfi_undefined (r14)
 	/* Load argc and argv from stack.  */
 	la	%r4,8(%r15)		# get argv
 	lg	%r3,0(%r15)		# get argc
@@ -91,6 +96,8 @@  _start:
 	/* Crash if __libc_start_main returns.	*/
 	.word	0
 
+	cfi_endproc
+
 	/* Define a symbol for the first piece of initialized data.  */
 	.data
 	.globl __data_start
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/__makecontext_ret.S b/sysdeps/unix/sysv/linux/s390/s390-32/__makecontext_ret.S
index 887d841..ba38a30 100644
--- a/sysdeps/unix/sysv/linux/s390/s390-32/__makecontext_ret.S
+++ b/sysdeps/unix/sysv/linux/s390/s390-32/__makecontext_ret.S
@@ -17,15 +17,9 @@ 
 
 #include <sysdep.h>
 
-/* We do not want .eh_frame info so that __makecontext_ret stops unwinding
-   if backtrace was called within a context created by makecontext. (There
-   is also no .eh_frame info for _start or thread_start.)  */
-#undef cfi_startproc
-#define cfi_startproc
-#undef cfi_endproc
-#define cfi_endproc
-
 ENTRY(__makecontext_ret)
+	/* Mark r14 as undefined in order to stop unwinding here!  */
+	cfi_undefined (r14)
 	basr  %r14,%r7
 	ltr   %r8,%r8			/* Check whether uc_link is 0.  */
 	jz    1f
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/clone.S b/sysdeps/unix/sysv/linux/s390/s390-32/clone.S
index a8b4dbc..91f8ede 100644
--- a/sysdeps/unix/sysv/linux/s390/s390-32/clone.S
+++ b/sysdeps/unix/sysv/linux/s390/s390-32/clone.S
@@ -54,12 +54,16 @@  error:
 PSEUDO_END (__clone)
 
 thread_start:
+	cfi_startproc
+	/* Mark r14 as undefined in order to stop unwinding here!  */
+	cfi_undefined (r14)
 	/* fn is in gpr 1, arg in gpr 0 */
 	lr      %r2,%r0         /* set first parameter to void *arg */
 	ahi     %r15,-96        /* make room on the stack for the save area */
 	xc	0(4,%r15),0(%r15)
 	basr    %r14,%r1        /* jump to fn */
 	DO_CALL (exit, 1)
+	cfi_endproc
 
 libc_hidden_def (__clone)
 weak_alias (__clone, clone)
diff --git a/sysdeps/unix/sysv/linux/s390/s390-64/__makecontext_ret.S b/sysdeps/unix/sysv/linux/s390/s390-64/__makecontext_ret.S
index 1690163..2dcd43f 100644
--- a/sysdeps/unix/sysv/linux/s390/s390-64/__makecontext_ret.S
+++ b/sysdeps/unix/sysv/linux/s390/s390-64/__makecontext_ret.S
@@ -17,15 +17,9 @@ 
 
 #include <sysdep.h>
 
-/* We do not want .eh_frame info so that __makecontext_ret stops unwinding
-   if backtrace was called within a context created by makecontext. (There
-   is also no .eh_frame info for _start or thread_start.)  */
-#undef cfi_startproc
-#define cfi_startproc
-#undef cfi_endproc
-#define cfi_endproc
-
 ENTRY(__makecontext_ret)
+	/* Mark r14 as undefined in order to stop unwinding here!  */
+	cfi_undefined (r14)
 	basr	%r14,%r7
 	ltgr	%r8,%r8			/* Check whether uc_link is 0.  */
 	jz	1f
diff --git a/sysdeps/unix/sysv/linux/s390/s390-64/clone.S b/sysdeps/unix/sysv/linux/s390/s390-64/clone.S
index daf8a58..8b0cc7e 100644
--- a/sysdeps/unix/sysv/linux/s390/s390-64/clone.S
+++ b/sysdeps/unix/sysv/linux/s390/s390-64/clone.S
@@ -55,12 +55,16 @@  error:
 PSEUDO_END (__clone)
 
 thread_start:
+	cfi_startproc
+	/* Mark r14 as undefined in order to stop unwinding here!  */
+	cfi_undefined (r14)
 	/* fn is in gpr 1, arg in gpr 0 */
 	lgr	%r2,%r0		/* set first parameter to void *arg */
 	aghi	%r15,-160	/* make room on the stack for the save area */
 	xc	0(8,%r15),0(%r15)
 	basr	%r14,%r1	/* jump to fn */
 	DO_CALL	(exit, 1)
+	cfi_endproc
 
 libc_hidden_def (__clone)
 weak_alias (__clone, clone)