diff mbox

Problem with GDB when debugging IRQ handlers

Message ID BANLkTinvrJ5MAZABDmdmQk6UZHDKJQo1+A@mail.gmail.com
State New
Headers show

Commit Message

Dmitry Baryshkov June 28, 2011, 12:06 p.m. UTC
On 6/28/11, Russell King - ARM Linux <linux@arm.linux.org.uk> wrote:
> On Mon, Jun 27, 2011 at 10:58:59PM +0800, Yao Qi wrote:
>> On 06/27/2011 10:04 PM, Dmitry Eremin-Solenikov wrote:
>> > Hello,
>> >
>> > On 27.06.2011 17:27, Russell King - ARM Linux wrote:
>> >> We _really_ _do_ want to unwind through this so that we can see the
>> >> parent kernel context information in backtraces - and the fact that
>>
>> I am not sure GDB is able to unwind stacks across processes (from child
>> to parent).
>
> It's not about unwinding across processes.  It's still the same process.
>
> Let me give you a recent example.  This may be using frame pointers rather
> than the unwinder, but serves to illustrate what we - as kernel developers -
> absolutely must have from the kernel:
>
> Internal error: Oops: 17 [#1] PREEMPT
> Modules linked in: uinput g_ether cryptomgr aead arc4 crypto_algapi
> rt2800usb rt2800lib rt2x00usb rt2x00lib mac80211 cfg80211 sg pcmciamtd
> mousedev snd_soc_wm8750 snd_soc_pxa2xx_i2s snd_soc_core ohci_hcd usbcore
> pxa27x_udc physmap snd_pcm_oss snd_pcm snd_timer snd_page_alloc
> snd_mixer_oss snd soundcore rfcomm pxaficp_ir ircomm_tty ircomm irda ipv6
> hidp hid bluetooth rfkill crc16
> CPU: 0    Not tainted  (3.0.0-rc4+ #5)
> PC is at complete+0x28/0x7c
> LR is at complete+0x28/0x7c
> pc : [<c0036b6c>]    lr : [<c0036b6c>]    psr: 80000093
> sp : c3897b68  ip : c3897b68  fp : c3897b84
> r10: c4806000  r9 : c381f3e0  r8 : 0000000a
> r7 : c30f0da8  r6 : 00000000  r5 : 00000000  r4 : a0000013
> r3 : c3896000  r2 : 00000000  r1 : 00000103  r0 : 00000004
> Flags: Nzcv  IRQs off  FIQs on  Mode SVC_32  ISA ARM  Segment kernel
> Control: 0000397f  Table: a080c000  DAC: 00000017
> Process kswapd0 (pid: 270, stack limit = 0xc3896278)
> [<c0036b6c>] (complete+0x28/0x7c) from [<c01e9b0c>] (spi_complete+0x10/0x14)
> [<c01e9b0c>] (spi_complete+0x10/0x14) from [<c01eac2c>]
> (giveback+0x114/0x12c)
> [<c01eac2c>] (giveback+0x114/0x12c) from [<c01eb60c>]
> (pump_transfers+0x13c/0x6f8)
> [<c01eb60c>] (pump_transfers+0x13c/0x6f8) from [<c0044924>]
> (tasklet_action+0x90/0xf0)
> [<c0044924>] (tasklet_action+0x90/0xf0) from [<c0044eb8>]
> (__do_softirq+0x98/0x138)
> [<c0044eb8>] (__do_softirq+0x98/0x138) from [<c00453a0>]
> (irq_exit+0x4c/0xa8)
> [<c00453a0>] (irq_exit+0x4c/0xa8) from [<c002406c>] (asm_do_IRQ+0x6c/0x8c)
> [<c002406c>] (asm_do_IRQ+0x6c/0x8c) from [<c0024b84>] (__irq_svc+0x44/0xcc)
> Exception stack(0xc3897c78 to 0xc3897cc0)
> 7c60:                                                       4022d320
> 4022e000
> 7c80: 08000075 00001000 c32273c0 c03ce1c0 c2b49b78 4022d000 c2b420b4
> 00000001
> 7ca0: 00000000 c3897cfc 00000000 c3897cc0 c00afc54 c002edd8 00000013
> ffffffff
> [<c0024b84>] (__irq_svc+0x44/0xcc) from [<c002edd8>]
> (xscale_flush_user_cache_range+0x18/0x3c)
> [<c002edd8>] (xscale_flush_user_cache_range+0x18/0x3c) from [<c00affd8>]
> (try_to_unmap_file+0x98/0x4ec)
> [<c00affd8>] (try_to_unmap_file+0x98/0x4ec) from [<c00b07ac>]
> (try_to_unmap+0x40/0x60)
> [<c00b07ac>] (try_to_unmap+0x40/0x60) from [<c009b940>]
> (shrink_page_list+0x2a8/0x8cc)
> [<c009b940>] (shrink_page_list+0x2a8/0x8cc) from [<c009c448>]
> (shrink_inactive_list+0x218/0x344)
> [<c009c448>] (shrink_inactive_list+0x218/0x344) from [<c009c8f8>]
> (shrink_zone+0x384/0x4ac)
> [<c009c8f8>] (shrink_zone+0x384/0x4ac) from [<c009ceb0>]
> (kswapd+0x490/0x7d0)
> [<c009ceb0>] (kswapd+0x490/0x7d0) from [<c0059be0>] (kthread+0x90/0x98)
> [<c0059be0>] (kthread+0x90/0x98) from [<c00258d8>]
> (kernel_thread_exit+0x0/0x8)
> Code: e3843080 e121f003 e3a00001 ebfff96a (e5953000)
>
> This shows that we've unwound from 'complete' to '__irq_svc'.  That
> may not be the full story though - the problem may relate to where we
> were when we were interrupted (or indeed took the data or prefetch
> abort).  So the unwinding from __irq_svc right back to kthread is
> just as important.

I did some checks. It seems, the problem isn't related to unwinder. At least
it looks like kernel has all necessary unwinding subops. It looks like the
problem is really related to the lack of necessary .cfi information. At least
when i added .cfi_startproc/.cfi_endproc annotations to entry-armv.S code,
gdb stopped decoding backtrace with the "previous frame identical to this frame"
error. Unfortunately I don't have enough knowledge to add .cfi annotations to
irq handlers.

For the reference I'm providing the patch in the attachment.

Russell, will you agree to merge at least this partial solution, so
that gdb chokes,
but doesn't go to indefinite recursion? If you'd agree, I'll submit it
with proper
headers and sign-off.

Comments

Russell King - ARM Linux June 28, 2011, 12:13 p.m. UTC | #1
On Tue, Jun 28, 2011 at 04:06:11PM +0400, Dmitry Eremin-Solenikov wrote:
> For the reference I'm providing the patch in the attachment.
> 
> Russell, will you agree to merge at least this partial solution, so
> that gdb chokes,
> but doesn't go to indefinite recursion? If you'd agree, I'll submit it
> with proper
> headers and sign-off.

It looks like it does the right thing, but I think we need someone who
knows how the debug info is supposed to work comment.

Adding Catalin to the thread to see whether Catalin has any comments;
Catalin added the original unwinder annotations.
Catalin Marinas June 28, 2011, 2:20 p.m. UTC | #2
On Tue, Jun 28, 2011 at 04:06:11PM +0400, Dmitry Eremin-Solenikov wrote:
> On 6/28/11, Russell King - ARM Linux <linux@arm.linux.org.uk> wrote:
> I did some checks. It seems, the problem isn't related to unwinder. At least
> it looks like kernel has all necessary unwinding subops. It looks like the
> problem is really related to the lack of necessary .cfi information. At least
> when i added .cfi_startproc/.cfi_endproc annotations to entry-armv.S code,
> gdb stopped decoding backtrace with the "previous frame identical to this frame"
> error. Unfortunately I don't have enough knowledge to add .cfi annotations to
> irq handlers.

I think it may have stopped decoding because of some information it
reads from the stack doesn't look sane. But I wonder whether we could
get it looping again depending on the register values in the interrupted
context.

> diff --git a/arch/arm/kernel/entry-armv.S b/arch/arm/kernel/entry-armv.S
> index e8d8856..d77f9d7 100644
> --- a/arch/arm/kernel/entry-armv.S
> +++ b/arch/arm/kernel/entry-armv.S
> @@ -28,6 +28,7 @@
>  #include "entry-header.S"
>  #include <asm/entry-macro-multi.S>
>  
> +	.cfi_sections	.debug_frame
>  /*
>   * Interrupt handling.  Preserves r7, r8, r9
>   */
> @@ -113,6 +114,7 @@ ENDPROC(__und_invalid)
>  
>  	.macro	svc_entry, stack_hole=0
>   UNWIND(.fnstart		)
> +	.cfi_startproc
>   UNWIND(.save {r0 - pc}		)
>  	sub	sp, sp, #(S_FRAME_SIZE + \stack_hole - 4)

Could you add some directives like below in the svc_entry macro (after
"sub sp...", not sure if it matters) and check whether gdb behaves
better:

	.cfi_def_cfa_offset S_PC
	.cfi_offset 14, -4

Thanks.
Catalin Marinas June 28, 2011, 2:30 p.m. UTC | #3
On Tue, Jun 28, 2011 at 03:20:45PM +0100, Catalin Marinas wrote:
> On Tue, Jun 28, 2011 at 04:06:11PM +0400, Dmitry Eremin-Solenikov wrote:
> > On 6/28/11, Russell King - ARM Linux <linux@arm.linux.org.uk> wrote:
> > I did some checks. It seems, the problem isn't related to unwinder. At least
> > it looks like kernel has all necessary unwinding subops. It looks like the
> > problem is really related to the lack of necessary .cfi information. At least
> > when i added .cfi_startproc/.cfi_endproc annotations to entry-armv.S code,
> > gdb stopped decoding backtrace with the "previous frame identical to this frame"
> > error. Unfortunately I don't have enough knowledge to add .cfi annotations to
> > irq handlers.
> 
> I think it may have stopped decoding because of some information it
> reads from the stack doesn't look sane. But I wonder whether we could
> get it looping again depending on the register values in the interrupted
> context.
> 
> > diff --git a/arch/arm/kernel/entry-armv.S b/arch/arm/kernel/entry-armv.S
> > index e8d8856..d77f9d7 100644
> > --- a/arch/arm/kernel/entry-armv.S
> > +++ b/arch/arm/kernel/entry-armv.S
> > @@ -28,6 +28,7 @@
> >  #include "entry-header.S"
> >  #include <asm/entry-macro-multi.S>
> >  
> > +	.cfi_sections	.debug_frame
> >  /*
> >   * Interrupt handling.  Preserves r7, r8, r9
> >   */
> > @@ -113,6 +114,7 @@ ENDPROC(__und_invalid)
> >  
> >  	.macro	svc_entry, stack_hole=0
> >   UNWIND(.fnstart		)
> > +	.cfi_startproc
> >   UNWIND(.save {r0 - pc}		)
> >  	sub	sp, sp, #(S_FRAME_SIZE + \stack_hole - 4)
> 
> Could you add some directives like below in the svc_entry macro (after
> "sub sp...", not sure if it matters) and check whether gdb behaves
> better:
> 
> 	.cfi_def_cfa_offset S_PC
> 	.cfi_offset 14, -4

Actually since the return address is in S_PC (which maybe gdb assumes it
would be the saved LR), this is probably not be correct. After SVC
entry, we have he following structure on the stack:

	ORIG_r0
	CPSR
		<--- assuming this is the Call Frame Address (SP+S_PC+4)
	PC	<--- CFA - 4
	LR	<--- don't care
	SP	<--- CFA - 12
	...


So we tell gdb about this with something like below (untested):

	.cfi_def_cfa_offset S_PC + 4
	.cfi_offset 14, -4
	.cfi_offset 13, -12
Russell King - ARM Linux June 28, 2011, 2:37 p.m. UTC | #4
On Tue, Jun 28, 2011 at 03:30:14PM +0100, Catalin Marinas wrote:
> Actually since the return address is in S_PC (which maybe gdb assumes it
> would be the saved LR), this is probably not be correct. After SVC
> entry, we have he following structure on the stack:
> 
> 	ORIG_r0
> 	CPSR
> 		<--- assuming this is the Call Frame Address (SP+S_PC+4)
> 	PC	<--- CFA - 4
> 	LR	<--- don't care
> 	SP	<--- CFA - 12
> 	...

If I'm reading this correctly, it's not correct.

parent SP -->	parent context stack
		[possible empty word]
		ORIG_r0
		parent context CPSR
		parent context PC
		parent context LR
		parent context SP
		...
new SP -->	R0

That empty word may or may not be present if the parent SP is aligned to
a 64-bit boundary.
Catalin Marinas June 28, 2011, 2:42 p.m. UTC | #5
On Tue, Jun 28, 2011 at 03:37:59PM +0100, Russell King - ARM Linux wrote:
> On Tue, Jun 28, 2011 at 03:30:14PM +0100, Catalin Marinas wrote:
> > Actually since the return address is in S_PC (which maybe gdb assumes it
> > would be the saved LR), this is probably not be correct. After SVC
> > entry, we have he following structure on the stack:
> > 
> > 	ORIG_r0
> > 	CPSR
> > 		<--- assuming this is the Call Frame Address (SP+S_PC+4)
> > 	PC	<--- CFA - 4
> > 	LR	<--- don't care
> > 	SP	<--- CFA - 12
> > 	...
> 
> If I'm reading this correctly, it's not correct.
> 
> parent SP -->	parent context stack
> 		[possible empty word]
> 		ORIG_r0
> 		parent context CPSR
> 		parent context PC
> 		parent context LR
> 		parent context SP
> 		...
> new SP -->	R0
> 
> That empty word may or may not be present if the parent SP is aligned to
> a 64-bit boundary.

But it shouldn't matter if we tell gdb that the previous SP (parent) is
stored in the current stack at CFA - 12. It calculates CFA by adding
S_PC+4 to the current SP, in which case the possible empty word doesn't
matter.

But please note that I don't have any gdb experience, so we need someone
else to confirm.
Dmitry Baryshkov June 28, 2011, 2:44 p.m. UTC | #6
On 6/28/11, Catalin Marinas <catalin.marinas@arm.com> wrote:
> On Tue, Jun 28, 2011 at 03:20:45PM +0100, Catalin Marinas wrote:
>> On Tue, Jun 28, 2011 at 04:06:11PM +0400, Dmitry Eremin-Solenikov wrote:
>> > On 6/28/11, Russell King - ARM Linux <linux@arm.linux.org.uk> wrote:
>> > I did some checks. It seems, the problem isn't related to unwinder. At
>> > least
>> > it looks like kernel has all necessary unwinding subops. It looks like
>> > the
>> > problem is really related to the lack of necessary .cfi information. At
>> > least
>> > when i added .cfi_startproc/.cfi_endproc annotations to entry-armv.S
>> > code,
>> > gdb stopped decoding backtrace with the "previous frame identical to
>> > this frame"
>> > error. Unfortunately I don't have enough knowledge to add .cfi
>> > annotations to
>> > irq handlers.
>>
>> I think it may have stopped decoding because of some information it
>> reads from the stack doesn't look sane. But I wonder whether we could
>> get it looping again depending on the register values in the interrupted
>> context.
>>
>> > diff --git a/arch/arm/kernel/entry-armv.S b/arch/arm/kernel/entry-armv.S
>> > index e8d8856..d77f9d7 100644
>> > --- a/arch/arm/kernel/entry-armv.S
>> > +++ b/arch/arm/kernel/entry-armv.S
>> > @@ -28,6 +28,7 @@
>> >  #include "entry-header.S"
>> >  #include <asm/entry-macro-multi.S>
>> >
>> > +	.cfi_sections	.debug_frame
>> >  /*
>> >   * Interrupt handling.  Preserves r7, r8, r9
>> >   */
>> > @@ -113,6 +114,7 @@ ENDPROC(__und_invalid)
>> >
>> >  	.macro	svc_entry, stack_hole=0
>> >   UNWIND(.fnstart		)
>> > +	.cfi_startproc
>> >   UNWIND(.save {r0 - pc}		)
>> >  	sub	sp, sp, #(S_FRAME_SIZE + \stack_hole - 4)
>>
>> Could you add some directives like below in the svc_entry macro (after
>> "sub sp...", not sure if it matters) and check whether gdb behaves
>> better:
>>
>> 	.cfi_def_cfa_offset S_PC
>> 	.cfi_offset 14, -4
>
> Actually since the return address is in S_PC (which maybe gdb assumes it
> would be the saved LR), this is probably not be correct. After SVC
> entry, we have he following structure on the stack:
>
> 	ORIG_r0
> 	CPSR
> 		<--- assuming this is the Call Frame Address (SP+S_PC+4)
> 	PC	<--- CFA - 4
> 	LR	<--- don't care
> 	SP	<--- CFA - 12
> 	...
>
>
> So we tell gdb about this with something like below (untested):
>
> 	.cfi_def_cfa_offset S_PC + 4
> 	.cfi_offset 14, -4
> 	.cfi_offset 13, -12

This brings "unknown CFA rule" gdb exception, but it seems I got your idea.
Dmitry Baryshkov June 28, 2011, 2:54 p.m. UTC | #7
On 6/28/11, Dmitry Eremin-Solenikov <dbaryshkov@gmail.com> wrote:
> On 6/28/11, Catalin Marinas <catalin.marinas@arm.com> wrote:
>> On Tue, Jun 28, 2011 at 03:20:45PM +0100, Catalin Marinas wrote:
>>> On Tue, Jun 28, 2011 at 04:06:11PM +0400, Dmitry Eremin-Solenikov wrote:
>>> > On 6/28/11, Russell King - ARM Linux <linux@arm.linux.org.uk> wrote:
>>> > I did some checks. It seems, the problem isn't related to unwinder. At
>>> > least
>>> > it looks like kernel has all necessary unwinding subops. It looks like
>>> > the
>>> > problem is really related to the lack of necessary .cfi information.
>>> > At
>>> > least
>>> > when i added .cfi_startproc/.cfi_endproc annotations to entry-armv.S
>>> > code,
>>> > gdb stopped decoding backtrace with the "previous frame identical to
>>> > this frame"
>>> > error. Unfortunately I don't have enough knowledge to add .cfi
>>> > annotations to
>>> > irq handlers.
>>>
>>> I think it may have stopped decoding because of some information it
>>> reads from the stack doesn't look sane. But I wonder whether we could
>>> get it looping again depending on the register values in the interrupted
>>> context.
>>>
>>> > diff --git a/arch/arm/kernel/entry-armv.S
>>> > b/arch/arm/kernel/entry-armv.S
>>> > index e8d8856..d77f9d7 100644
>>> > --- a/arch/arm/kernel/entry-armv.S
>>> > +++ b/arch/arm/kernel/entry-armv.S
>>> > @@ -28,6 +28,7 @@
>>> >  #include "entry-header.S"
>>> >  #include <asm/entry-macro-multi.S>
>>> >
>>> > +	.cfi_sections	.debug_frame
>>> >  /*
>>> >   * Interrupt handling.  Preserves r7, r8, r9
>>> >   */
>>> > @@ -113,6 +114,7 @@ ENDPROC(__und_invalid)
>>> >
>>> >  	.macro	svc_entry, stack_hole=0
>>> >   UNWIND(.fnstart		)
>>> > +	.cfi_startproc
>>> >   UNWIND(.save {r0 - pc}		)
>>> >  	sub	sp, sp, #(S_FRAME_SIZE + \stack_hole - 4)
>>>
>>> Could you add some directives like below in the svc_entry macro (after
>>> "sub sp...", not sure if it matters) and check whether gdb behaves
>>> better:
>>>
>>> 	.cfi_def_cfa_offset S_PC
>>> 	.cfi_offset 14, -4
>>
>> Actually since the return address is in S_PC (which maybe gdb assumes it
>> would be the saved LR), this is probably not be correct. After SVC
>> entry, we have he following structure on the stack:
>>
>> 	ORIG_r0
>> 	CPSR
>> 		<--- assuming this is the Call Frame Address (SP+S_PC+4)
>> 	PC	<--- CFA - 4
>> 	LR	<--- don't care
>> 	SP	<--- CFA - 12
>> 	...
>>
>>
>> So we tell gdb about this with something like below (untested):
>>
>> 	.cfi_def_cfa_offset S_PC + 4
>> 	.cfi_offset 14, -4
>> 	.cfi_offset 13, -12
>
> This brings "unknown CFA rule" gdb exception, but it seems I got your idea.

No, this seems to work, it was my fault. I got more or less reasonable
backtrace now.
Catalin Marinas June 28, 2011, 3:06 p.m. UTC | #8
On Tue, Jun 28, 2011 at 03:54:11PM +0100, Dmitry Eremin-Solenikov wrote:
> On 6/28/11, Dmitry Eremin-Solenikov <dbaryshkov@gmail.com> wrote:
> > On 6/28/11, Catalin Marinas <catalin.marinas@arm.com> wrote:
> >> Actually since the return address is in S_PC (which maybe gdb assumes it
> >> would be the saved LR), this is probably not be correct. After SVC
> >> entry, we have he following structure on the stack:
> >>
> >> 	ORIG_r0
> >> 	CPSR
> >> 		<--- assuming this is the Call Frame Address (SP+S_PC+4)
> >> 	PC	<--- CFA - 4
> >> 	LR	<--- don't care
> >> 	SP	<--- CFA - 12
> >> 	...
> >>
> >>
> >> So we tell gdb about this with something like below (untested):
> >>
> >> 	.cfi_def_cfa_offset S_PC + 4
> >> 	.cfi_offset 14, -4
> >> 	.cfi_offset 13, -12
> >
> > This brings "unknown CFA rule" gdb exception, but it seems I got your idea.
> 
> No, this seems to work, it was my fault. I got more or less reasonable
> backtrace now.

Does gdb manage to get into the parent stack frame?

BTW, are you compiling with FRAME_POINTER enabled? In this case you
would need to set some offset for the FP register (11). If you don't
mind missing the first part in the parent context, maybe something like
below:

	.cfi_def_cfa_offset S_PC
	.cfi_offset 14, -4
	.cfi_offset 13, -8
	.cfi_offset 11, -16
diff mbox

Patch

diff --git a/arch/arm/kernel/entry-armv.S b/arch/arm/kernel/entry-armv.S
index e8d8856..d77f9d7 100644
--- a/arch/arm/kernel/entry-armv.S
+++ b/arch/arm/kernel/entry-armv.S
@@ -28,6 +28,7 @@ 
 #include "entry-header.S"
 #include <asm/entry-macro-multi.S>
 
+	.cfi_sections	.debug_frame
 /*
  * Interrupt handling.  Preserves r7, r8, r9
  */
@@ -113,6 +114,7 @@  ENDPROC(__und_invalid)
 
 	.macro	svc_entry, stack_hole=0
  UNWIND(.fnstart		)
+	.cfi_startproc
  UNWIND(.save {r0 - pc}		)
 	sub	sp, sp, #(S_FRAME_SIZE + \stack_hole - 4)
 #ifdef CONFIG_THUMB2_KERNEL
@@ -347,6 +349,7 @@  ENDPROC(__pabt_svc)
 	.macro	usr_entry
  UNWIND(.fnstart	)
  UNWIND(.cantunwind	)	@ don't unwind the user space
+	.cfi_startproc
 	sub	sp, sp, #S_FRAME_SIZE
  ARM(	stmib	sp, {r1 - r12}	)
  THUMB(	stmia	sp, {r0 - r12}	)
@@ -427,6 +430,7 @@  __dabt_usr:
 	mov	r2, sp
 	adr	lr, BSYM(ret_from_exception)
 	b	do_DataAbort
+	.cfi_endproc
  UNWIND(.fnend		)
 ENDPROC(__dabt_usr)
 
@@ -454,6 +458,7 @@  __irq_usr:
 
 	mov	why, #0
 	b	ret_to_user
+	.cfi_endproc
  UNWIND(.fnend		)
 ENDPROC(__irq_usr)
 
@@ -496,6 +501,7 @@  __und_usr:
 #else
 	b	__und_usr_unknown
 #endif
+	.cfi_endproc
  UNWIND(.fnend		)
 ENDPROC(__und_usr)
 
@@ -691,6 +697,7 @@  __pabt_usr:
 	enable_irq				@ Enable interrupts
 	mov	r2, sp				@ regs
 	bl	do_PrefetchAbort		@ call abort handler
+	.cfi_endproc
  UNWIND(.fnend		)
 	/* fall through */
 /*
@@ -699,9 +706,11 @@  __pabt_usr:
 ENTRY(ret_from_exception)
  UNWIND(.fnstart	)
  UNWIND(.cantunwind	)
+	.cfi_startproc
 	get_thread_info tsk
 	mov	why, #0
 	b	ret_to_user
+	.cfi_endproc
  UNWIND(.fnend		)
 ENDPROC(__pabt_usr)
 ENDPROC(ret_from_exception)
diff --git a/arch/arm/kernel/entry-header.S b/arch/arm/kernel/entry-header.S
index 051166c..5ed13ae 100644
--- a/arch/arm/kernel/entry-header.S
+++ b/arch/arm/kernel/entry-header.S
@@ -86,6 +86,7 @@ 
 #else
 	ldmia	sp, {r0 - pc}^			@ load r0 - pc, cpsr
 #endif
+	.cfi_endproc
 	.endm
 
 	.macro	restore_user_regs, fast = 0, offset = 0