[Dwarf-Discuss] unwinding stack (CIE/FDE)

Jason Molenda jmolenda at apple.com
Tue Aug 3 16:55:23 PDT 2010


Some compilers output CFI with the sole purpose of assisting exception handling.  These FDEs may only provide enough information to unwind the frame at valid throw locations (e.g. call sites).  You would expect to see this in an "eh_frame" section but it's been my experience that some compilers put the same information in the dwarf_debug section.  At some instruction locations within the function, the debug_frame instructions may not be sufficient to unwind.

A simple example.  On i386 gcc will do a call instruction to the next instruction, followed by a pop to get the current pc value (x86_64 adds ip-relative addressing so this trick isn't needed) so you'll get a function like this for "main () { puts ("HI"); }"

0x00001f66 <main+0>:	push   %ebp
0x00001f67 <main+1>:	mov    %esp,%ebp
0x00001f69 <main+3>:	push   %ebx
0x00001f6a <main+4>:	sub    $0x14,%esp
0x00001f6d <main+7>:	call   0x1f72 <main+12>
0x00001f72 <main+12>:	pop    %ebx
0x00001f73 <main+13>:	lea    0x42(%ebx),%eax
0x00001f79 <main+19>:	mov    %eax,(%esp)
0x00001f7c <main+22>:	call   0x1f8e <dyld_stub_puts>
0x00001f81 <main+27>:	add    $0x14,%esp
0x00001f84 <main+30>:	pop    %ebx
0x00001f85 <main+31>:	leave  
0x00001f86 <main+32>:	ret    

Notice that at main+12 the CFA has moved one word (and will be moved back on the next instruction).  If you want to unwind at this point in the function, you need information in the CFI to do it.

Looking at the debug_frame that my compiler (gcc-4.2 in this case) outputs,

0x00000014: FDE
        length: 0x00000024
   CIE_pointer: 0x00000000
    start_addr: 0x00001f66 main
    range_size: 0x00000021 (end_addr = 0x00001f87)
  Instructions: 0x00001f66: CFA=esp+4     eip=[esp]
                DW_CFA_advance_loc4 (1)
                DW_CFA_def_cfa_offset (8)
                DW_CFA_offset (ebp, -8)
                0x00001f67: CFA=esp+8     ebp=[esp]  eip=[esp+4]
                DW_CFA_advance_loc4 (2)
                DW_CFA_def_cfa_register (ebp)
                0x00001f69: CFA=ebp+8     ebp=[ebp]  eip=[ebp+4]
                DW_CFA_advance_loc4 (4)
                DW_CFA_offset (ebx, -12)
                DW_CFA_nop
                0x00001f6d: CFA=ebp+8     ebx=[ebp-4]  ebp=[ebp]  eip=[ebp+4]

There's nothing about that stack movement in the FDE.

You can see similar problems if a function uses the "large struct return" calling convention on i386 with the SysV ABI.

When you have debug_frame/eh_frame information like this, you need to augment your unwind algorithm if you want to unwind at any arbitrary instruction location.

J

On Aug 3, 2010, at 4:40 PM, Saurabh wrote:

> Assuming my pc is 0x2010ddc, the FDE below applies
>  
> 00001954 0000001c 0560e358 FDE cie=f6066110 pc=02010d70..02010e06
>   DW_CFA_advance_loc: 0 to 02010d70
>   DW_CFA_same_value: r31
>   DW_CFA_advance_loc: 0 to 02010d70
>   DW_CFA_same_value: r31
>   DW_CFA_advance_loc: 0 to 02010d70
>   DW_CFA_def_cfa_offset: 8
>   DW_CFA_advance_loc: 0 to 02010d70
>   DW_CFA_offset: r27 at cfa+0
>   DW_CFA_advance_loc: 0 to 02010d70
>   DW_CFA_def_cfa_reg: r27
>   DW_CFA_nop
> 00001974 0000001c 0560e358 FDE cie=f6066110 pc=02010e08..02010e8c
> 00001640 0000000c ffffffff CIE
>   Version:               1
>   Augmentation:          ""
>   Code alignment factor: 1
>   Data alignment factor: -4
>   Return address column: 31
>   DW_CFA_def_cfa: r28 ofs 0
>  
> I don't see the "restore operations of epilogue". Is the producer not following the specification?
> If its a bug, can I still find return address by just the prologue?
>  
> Thanks
> 
> From: Paul Pluzhnikov <ppluzhnikov at google.com>
> To: Saurabh <saurabhcv at yahoo.com>
> Cc: dwarf-discuss at lists.dwarfstd.org
> Sent: Tue, August 3, 2010 2:28:15 PM
> Subject: Re: [Dwarf-Discuss] unwinding stack (CIE/FDE)
> 
> On Tue, Aug 3, 2010 at 2:09 PM, Saurabh <saurabhcv at yahoo.com> wrote:
> 
> > I think my understanding is incorrect since these steps don't work as the
> > return register is fixed at 31(blink) in my case.
> 
> You'll need to find where previous value of "blink" register is stored;
> as described you'll only be able to unwind one level.
> 
> You may also want to look at libunwind: http://www.nongnu.org/libunwind
> 
> -- 
> Paul Pluzhnikov
> 
> _______________________________________________
> Dwarf-Discuss mailing list
> Dwarf-Discuss at lists.dwarfstd.org
> http://lists.dwarfstd.org/listinfo.cgi/dwarf-discuss-dwarfstd.org




More information about the Dwarf-Discuss mailing list