Patchwork [gccgo] Use a cleanup to restore the stack guard when unwinding

login
register
mail settings
Submitter Ian Taylor
Date June 24, 2010, 7:47 p.m.
Message ID <mcr7hlociwt.fsf@dhcp-172-17-9-151.mtv.corp.google.com>
Download mbox | patch
Permalink /patch/56828/
State New
Headers show

Comments

Ian Taylor - June 24, 2010, 7:47 p.m.
When using split stacks, and unwinding the stack due to an exception,
we need to not only restore the stack pointer across a stack split, we
need to also restore the stack guard.  This patch implements that by
using a cleanup in the split stack code.  Committed to gccgo branch.

Ian

Patch

Index: generic-morestack.c
===================================================================
--- generic-morestack.c	(revision 161235)
+++ generic-morestack.c	(working copy)
@@ -62,6 +62,10 @@  extern void *
 __generic_releasestack (size_t *pavailable)
   __attribute__ ((no_split_stack, flatten, visibility ("hidden")));
 
+extern size_t
+__generic_findstack (void *stack)
+  __attribute__ ((no_split_stack, flatten, visibility ("hidden")));
+
 extern void
 __morestack_load_mmap (void)
   __attribute__ ((no_split_stack));
@@ -362,6 +366,33 @@  __generic_releasestack (size_t *pavailab
   return old_stack;
 }
 
+/* Find the stack segment for STACK and return the amount of space
+   available.  This is used when unwinding the stack because of an
+   exception, in order to reset the stack guard correctly.  */
+
+size_t
+__generic_findstack (void *stack)
+{
+  struct stack_segment *pss;
+
+  for (pss = __morestack_current_segment; pss != NULL; pss = pss->prev)
+    {
+      if ((char *) pss < (char *) stack
+	  && (char *) pss + pss->size > (char *) stack)
+	{
+	  __morestack_current_segment = pss;
+#ifdef STACK_GROWS_DOWNWARD
+	  return (char *) stack - (char *) (pss + 1);
+#else
+	  return (char *) (pss + 1) + pss->size - (char *) stack;
+#endif
+	}
+    }
+
+  // We don't know where we are on the stack.
+  return 512;
+}
+
 /* This function is called at program startup time to make sure that
    mmap and munmap are resolved if linking dynamically.  We want to
    resolve them while we have enough stack for them, rather than
Index: config/i386/morestack.S
===================================================================
--- config/i386/morestack.S	(revision 161235)
+++ config/i386/morestack.S	(working copy)
@@ -103,10 +103,21 @@  __morestack_non_split:
 #endif
 
 __morestack:
+.LFB1:
 	.cfi_startproc
 
 #ifndef __x86_64__
 
+	# We use a cleanup to restore the stack guard if an exception
+	# is thrown through this code.
+#ifndef __PIC__
+	.cfi_personality 0,__gcc_personality_v0
+	.cfi_lsda 0,.LLSDA1
+#else
+	.cfi_personality 0x9b,DW.ref.__gcc_personality_v0
+	.cfi_lsda 0x1b,.LLSDA1
+#endif
+
 	# Set up a normal backtrace.
 	pushl	%ebp
 	.cfi_def_cfa_offset 8
@@ -152,6 +163,7 @@  __morestack:
 	# FIXME: The offset must match
 	# TARGET_THREAD_SPLIT_STACK_OFFSET in
 	# gcc/config/i386/linux.h.
+.LEHB0:
 	movl	%eax,%gs:0x30		# Save the new stack boundary.
 
 	movl	-8(%ebp),%edx		# Restore registers.
@@ -186,6 +198,7 @@  __morestack:
 
 	subl	4(%esp),%eax		# Subtract available space.
 	addl	$512,%eax		# Back off 512 bytes.
+.LEHE0:
 	movl	%eax,%gs:0x30		# Save the new stack boundary.
 
 	addl	$8,%esp			# Remove values from stack.
@@ -195,14 +208,42 @@  __morestack:
 
 	# Switch back to the old stack via copy back from %ebp.
 	leave
+	.cfi_remember_state
 	.cfi_restore %ebp
 	.cfi_def_cfa %esp, 12
 	ret	$8			# Return to caller, which will
 					# immediately return.  Pop
 					# arguments as we go.
 
+# This is the cleanup code called by the stack unwinder when unwinding
+# through the code between .LEHB0 and .LEHE0 above.
+	
+.L1:
+	.cfi_restore_state
+	subl	$16,%esp		# Maintain 16 byte alignment.
+	movl	%eax,4(%esp)		# Save exception header.
+	movl	%ebp,(%esp)		# Stack pointer after resume.
+	call	__generic_findstack
+	movl	%esp,%ecx		# Get the stack pointer.
+	subl	%eax,%ecx		# Subtract available space.
+	addl	$512,%ecx		# Back off 512 bytes.
+	movl	%ecx,%gs:0x30		# Save new stack boundary.
+	movl	4(%esp),%eax		# Function argument.
+	movl	%eax,(%esp)
+	call	_Unwind_Resume		# Resume unwinding.
+
 #else /* defined(__x86_64__) */
 
+	# We use a cleanup to restore the stack guard if an exception
+	# is thrown through this code.
+#ifndef __PIC__
+	.cfi_personality 0x3,__gcc_personality_v0
+	.cfi_lsda 0x3,.LLSDA1
+#else
+	.cfi_personality 0x9b,DW.ref.__gcc_personality_v0
+	.cfi_lsda 0x1b,.LLSDA1
+#endif
+
 	# Set up a normal backtrace.
 	pushq	%rbp
 	.cfi_def_cfa_offset 16
@@ -251,6 +292,7 @@  __morestack:
 	# FIXME: The offset must match
 	# TARGET_THREAD_SPLIT_STACK_OFFSET in
 	# gcc/config/i386/linux64.h.
+.LEHB0:
 	movq	%rax,%fs:0x70		# Save the new stack boundary.
 
 	movq	8(%rbp),%r10		# Increment the return address
@@ -276,6 +318,7 @@  __morestack:
 
 	subq	0(%rsp),%rax		# Subtract available space.
 	addq	$512,%rax		# Back off 512 bytes.
+.LEHE0:
 	movq	%rax,%fs:0x70		# Save the new stack boundary.
 
 	addq	$8,%rsp			# Remove value from stack.
@@ -284,12 +327,30 @@  __morestack:
 	popq	%rax
 
 	# Switch back to the old stack via copy back from %rbp.
+	.cfi_remember_state
 	leave
 	.cfi_restore %rbp
 	.cfi_def_cfa %rsp, 8
 	ret				# Return to caller, which will
 					# immediately return.
 
+# This is the cleanup code called by the stack unwinder when unwinding
+# through the code between .LEHB0 and .LEHE0 above.
+	
+.L1:
+	.cfi_restore_state
+	movl	%edx,%ebx		# Save exception data
+	movq	%rax,%r12
+	movl	%rbp,%rdi		# Stack pointer after resume.
+	call	__generic_findstack
+	movq	%rsp,%rcx		# Get the stack pointer.
+	subq	%rax,%rcx		# Subtract available space.
+	addq	$512,%rcx		# Back off 512 bytes.
+	movq	%rcx,%fs:0x70		# Save new stack boundary.
+	movq	%r12,%rdi		# Restore exception data for call.
+	movslq	%ebx,%rdx
+	call	_Unwind_Resume		# Resume unwinding.
+
 #endif /* defined(__x86_64__) */
 
 	.cfi_endproc
@@ -297,6 +358,40 @@  __morestack:
 	.size	__morestack, . - __morestack
 #endif
 
+	.globl __gcc_personality_v0
+	.section	.gcc_except_table,"a",@progbits
+	.align	4
+.LLSDA1:
+	.byte	0xff	# @LPStart format (omit)
+	.byte	0xff	# @TType format (omit)
+	.byte	0x1	# call-site format (uleb128)
+	.uleb128 .LLSDACSE1-.LLSDACSB1	# Call-site table length
+.LLSDACSB1:
+	.uleb128 .LEHB0-.LFB1	# region 0 start
+	.uleb128 .LEHE0-.LEHB0	# length
+	.uleb128 .L1-.LFB1	# landing pad
+	.uleb128 0		# action
+.LLSDACSE1:
+
+#ifdef __PIC__
+	# Build a position independent reference to the basic
+        # personality function.
+	.hidden DW.ref.__gcc_personality_v0
+	.weak   DW.ref.__gcc_personality_v0
+	.section .data.DW.ref.__gcc_personality_v0,"awG",@progbits,DW.ref.__gcc_personality_v0,comdat
+	.type	DW.ref.__gcc_personality_v0, @object
+DW.ref.__gcc_personality_v0:
+#ifndef __x86_64
+	.align 4
+	.size	DW.ref.__gcc_personality_v0, 4
+	.long	__gcc_personality_v0
+#else
+	.align 8
+	.size	DW.ref.__gcc_personality_v0, 8
+	.quad	__gcc_personality_v0
+#endif
+#endif
+
 # Initialize the stack test value when the program starts or when a
 # new thread starts.  We don't know how large the main stack is, so we
 # guess conservatively.  We might be able to use getrlimit here.