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

Jason Molenda jmolenda at apple.com
Tue Aug 3 17:00:58 PDT 2010


(you may ask why the prologue instructions are described at all if this is only for exception handling ... these are usually the most critical for debuggers.  If the FDE were genuinely only for exception handling, the prologue could be described as one single location once the stack frame was set up, instead of describing the changes at each instruction location.)

On Aug 3, 2010, at 4:55 PM, Jason Molenda wrote:

> 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
> 
> _______________________________________________
> 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