This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC 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]

Add unwind information for ARM div0 and interworking stubs


This patch got a little larger than I expected...

The original problem I wanted to solve was that when you divide by zero on
arm-linux, GDB can not backtrace from the point where the signal is raised.
This is because of the stack frame created at the end of __divsi3; the
function is otherwise frameless, so GDB assumes that lr is not on the stack.
The only way to fix this is to provide an appropriate .debug_frame.

The gas cfi directives are not useful for this.  They create a .eh_frame
section, instead of a .debug_frame section; we don't need the extra bytes
in an allocated section on ARM.  It would be nice if gas supported geerating
.debug_frame instead of .eh_frame at some point.

While I was there, I noticed a couple minor problems in this file:
  - The interworking stubs and division routines call out with a
    non-doubleword-aligned stack.
  - The GNU/Linux div0 handler raises a signal by sys_kill, but if
    sys_tkill is available, we should use that.  Otherwise a random
    thread is going to receive the signal (in NPTL).  Ditto gettid
    versus getpid.

Tested on arm-elf simulator, and by hand on arm-linux and arm-elf.  I
checked backtraces from div0 on arm-elf ARM, arm-elf Thumb, and arm-linux. 
I checked backtraces through _arm_return using -mcaller-super-interworking.
I checked behavior of the tkill changes when gettid or tkill returns ENOSYS.

Is this OK?

-- 
Daniel Jacobowitz
CodeSourcery, LLC

2005-05-13  Daniel Jacobowitz  <dan@codesourcery.com>

	* config/arm/lib1funcs.asm (cfi_pop, cfi_push, cfi_start)
	(cfi_end): New macros.
	(RETLDM): Use cfi_pop.  Expect an eight byte stack frame.
	(ARM_LDIV0, THUMB_LDIV0, DIV_FUNC_END): Use CFI macros.  Create
	an eight byte stack frame.
	(__NR_tkill): Define.
	(__div0): Use gettid tkill on GNU/Linux.
	(_arm_return): Add CFI.
	(Lchange_\register, .Lchange_lr): Create an eight byte stack frame.

Index: gcc/gcc/config/arm/lib1funcs.asm
===================================================================
--- gcc.orig/gcc/config/arm/lib1funcs.asm	2005-04-30 15:40:53.000000000 -0400
+++ gcc/gcc/config/arm/lib1funcs.asm	2005-05-13 17:30:34.266612726 -0400
@@ -116,19 +116,82 @@ Boston, MA 02111-1307, USA.  */
 
 #endif
 
+.macro	cfi_pop		advance, reg, cfa_offset
+#ifdef __ELF__
+	.pushsection	.debug_frame
+	.byte	0x4		/* DW_CFA_advance_loc4 */
+	.4byte	\advance
+	.byte	(0xc0 | \reg)	/* DW_CFA_restore */
+	.byte	0xe		/* DW_CFA_def_cfa_offset */
+	.uleb128 \cfa_offset
+	.popsection
+#endif
+.endm
+.macro	cfi_push	advance, reg, offset, cfa_offset
+#ifdef __ELF__
+	.pushsection	.debug_frame
+	.byte	0x4		/* DW_CFA_advance_loc4 */
+	.4byte	\advance
+	.byte	(0x80 | \reg)	/* DW_CFA_offset */
+	.uleb128 (\offset / -4)
+	.byte	0xe		/* DW_CFA_def_cfa_offset */
+	.uleb128 \cfa_offset
+	.popsection
+#endif
+.endm
+.macro cfi_start	start_label, end_label
+#ifdef __ELF__
+	.pushsection	.debug_frame
+LSYM(Lstart_frame):
+	.4byte	LSYM(Lend_cie) - LSYM(Lstart_cie) @ Length of CIE
+LSYM(Lstart_cie):
+        .4byte	0xffffffff	@ CIE Identifier Tag
+        .byte	0x1	@ CIE Version
+        .ascii	"\0"	@ CIE Augmentation
+        .uleb128 0x1	@ CIE Code Alignment Factor
+        .sleb128 -4	@ CIE Data Alignment Factor
+        .byte	0xe	@ CIE RA Column
+        .byte	0xc	@ DW_CFA_def_cfa
+        .uleb128 0xd
+        .uleb128 0x0
+
+	.align 2
+LSYM(Lend_cie):
+	.4byte	LSYM(Lend_fde)-LSYM(Lstart_fde)	@ FDE Length
+LSYM(Lstart_fde):
+	.4byte	LSYM(Lstart_frame)	@ FDE CIE offset
+	.4byte	\start_label	@ FDE initial location
+	.4byte	\end_label-\start_label	@ FDE address range
+	.popsection
+#endif
+.endm
+.macro cfi_end	end_label
+#ifdef __ELF__
+	.pushsection	.debug_frame
+	.align	2
+LSYM(Lend_fde):
+	.popsection
+\end_label:
+#endif
+.endm
+
 /* Don't pass dirn, it's there just to get token pasting right.  */
 
-.macro	RETLDM	regs=, cond=, dirn=ia
+.macro	RETLDM	regs=, cond=, unwind=, dirn=ia
 #if defined (__INTERWORKING__)
 	.ifc "\regs",""
-	ldr\cond	lr, [sp], #4
+	ldr\cond	lr, [sp], #8
 	.else
 	ldm\cond\dirn	sp!, {\regs, lr}
 	.endif
+	.ifnc "\unwind", ""
+	/* Mark LR as restored.  */
+97:	cfi_pop 97b - \unwind, 0xe, 0x0
+	.endif
 	bx\cond	lr
 #else
 	.ifc "\regs",""
-	ldr\cond	pc, [sp], #4
+	ldr\cond	pc, [sp], #8
 	.else
 	ldm\cond\dirn	sp!, {\regs, pc}
 	.endif
@@ -136,25 +199,25 @@ Boston, MA 02111-1307, USA.  */
 .endm
 
 
-.macro ARM_LDIV0
-LSYM(Ldiv0):
-	str	lr, [sp, #-4]!
+.macro ARM_LDIV0 name
+	str	lr, [sp, #-8]!
+98:	cfi_push 98b - __\name, 0xe, -0x8, 0x8
 	bl	SYM (__div0) __PLT__
 	mov	r0, #0			@ About as wrong as it could be.
-	RETLDM
+	RETLDM	unwind=98b
 .endm
 
 
-.macro THUMB_LDIV0
-LSYM(Ldiv0):
-	push	{ lr }
+.macro THUMB_LDIV0 name
+	push	{ r1, lr }
+98:	cfi_push 98b - __\name, 0xe, -0x4, 0x8
 	bl	SYM (__div0)
 	mov	r0, #0			@ About as wrong as it could be.
 #if defined (__INTERWORKING__)
-	pop	{ r1 }
-	bx	r1
+	pop	{ r1, r2 }
+	bx	r2
 #else
-	pop	{ pc }
+	pop	{ r1, pc }
 #endif
 .endm
 
@@ -163,12 +226,14 @@ LSYM(Ldiv0):
 .endm
 
 .macro DIV_FUNC_END name
+	cfi_start	__\name, LSYM(Lend_div0)
 LSYM(Ldiv0):
 #ifdef __thumb__
-	THUMB_LDIV0
+	THUMB_LDIV0 \name
 #else
-	ARM_LDIV0
+	ARM_LDIV0 \name
 #endif
+	cfi_end	LSYM(Lend_div0)
 	FUNC_END \name
 .endm
 
@@ -923,16 +988,24 @@ LSYM(Lover12):
 #define __NR_SYSCALL_BASE	0x900000
 #define __NR_getpid			(__NR_SYSCALL_BASE+ 20)
 #define __NR_kill			(__NR_SYSCALL_BASE+ 37)
+#define __NR_gettid			(__NR_SYSCALL_BASE+ 224)
+#define __NR_tkill			(__NR_SYSCALL_BASE+ 238)
 
 	.code	32
 	FUNC_START div0
 
 	stmfd	sp!, {r1, lr}
-	swi	__NR_getpid
+	swi	__NR_gettid
 	cmn	r0, #1000
+	swihs	__NR_getpid
+	cmnhs	r0, #1000
 	RETLDM	r1 hs
+	mov	ip, r0
 	mov	r1, #SIGFPE
-	swi	__NR_kill
+	swi	__NR_tkill
+	movs	r0, r0
+	movne	r0, ip
+	swine	__NR_kill
 	RETLDM	r1
 
 	FUNC_END div0
@@ -1137,8 +1210,14 @@ LSYM(Lover12):
 
 	.code   32
 	.globl _arm_return
+LSYM(Lstart_arm_return):
+	cfi_start	LSYM(Lstart_arm_return) LSYM(Lend_arm_return)
+	cfi_push	0, 0xe, -0x8, 0x8
+	nop	@ This nop is for the benefit of debuggers, so that
+		@ backtraces will use the correct unwind information.
 _arm_return:
-	RETLDM
+	RETLDM	unwind=LSYM(Lstart_arm_return)
+	cfi_end	LSYM(Lend_arm_return)
 
 	.globl _arm_return_r7
 _arm_return_r7:
@@ -1179,7 +1258,7 @@ _arm_return_r11:
 	.globl LSYM(Lchange_\register)
 LSYM(Lchange_\register):
 	tst	\register, #1
-	streq	lr, [sp, #-4]!
+	streq	lr, [sp, #-8]!
 	adreq	lr, _arm_return
 	bx	\register
 
@@ -1216,7 +1295,7 @@ LSYM(Lchange_\register):
 	.globl .Lchange_lr
 .Lchange_lr:
 	tst	lr, #1
-	stmeqdb	r13!, {lr}
+	stmeqdb	r13!, {lr, pc}
 	mov	ip, lr
 	adreq	lr, _arm_return
 	bx	ip


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