Re: [CRIS] dwarf2 frame sniffer problem?

Daniel Jacobowitz
2004-03-12T15:38:28Z

On Fri, Mar 12, 2004 at 11:22:34AM +0100, Orjan Friberg wrote:
> Daniel Jacobowitz wrote:
> >
> >The beauty of using the CFI data is that it _is_ supposed to work in
> >the prologue. It sounds like the CFI is wrong. Could you post both
> >assembly and CFI data for the same testcase? I don't know CRIS
> >assembly but I imagine I can interpret it well enough to see what's
> >going on.
>
> I have attached the test program, dissassembly (objdump -d -S) and the
> dwarf2 info (readelf -w). (Crash course in CRIS assembly, if at all
> needed: r8 holds the frame pointer and srp holds the return address,
> pushed only in non-leaf functions.)

OK, let's see what we have. I can see that your unwind information is
definitely wrong. Take a look at this:

00080080 <foo>:
void foo(void)
{
80080: fce1 7ebe push $srp
80084: fce1 ee8f push $r8
80088: 6e86 move.d $sp,$r8
bar();
8008a: 3fbd 7400 0800 jsr 80074 <bar>
}
80090: 68e6 move.d $r8,$sp
80092: 6e8e pop $r8
80094: 3e0d jump [$sp+]

00000028 00000014 00000000 FDE cie=00000000 pc=00080080..00080096
DW_CFA_advance_loc: 0 to 00080080
DW_CFA_def_cfa: r8 ofs 8
DW_CFA_offset: r16 at cfa-4
DW_CFA_offset: r8 at cfa-8

That says, at 0x80080, CFA is r8 + 8 and both r16 and r8 are saved.
Which is obviously untrue.

I see that your GCC port uses textual prologues. As it happens, I just
implemented dwarf generation for that mechanism (for Thumb), so I know
how it's supposed to work. Here's your problem. First you have:

/* FIXME: Slightly redundant calculation, as we do the same in
pieces below. This offset must be the total adjustment of the
stack-pointer. We can then def_cfa call at the end of this
function with the current implementation of execute_cfa_insn, but
that wouldn't really be clean. */

cfa_label = dwarf2out_cfi_label ();
dwarf2out_def_cfa (cfa_label, cfa_reg, cfa_offset);

but that label is at the beginning of the function, so this is
incorrect. That's not what the CFA is at the beginning of the
function.

What it really ought to be, if I'm reading this right, is (I'll use the
gas CFI pseudo-ops to write this, but you'd use GCC's internal
mechanism to emit it...)

00080080 <foo>:
.cfi_startproc
.cfi_def_cfa $sp, 0 # Set the CFA to $sp + 0
80080: fce1 7ebe push $srp
.cfi_def_cfa_offset 4
.cfi_offset $srp, -4
80084: fce1 ee8f push $r8
.cfi_def_cfa_offset 8
.cfi_offset $r8, -8
80088: 6e86 move.d $sp,$r8
.cfi_def_cfa $r8, 0

With that sequence, assuming that I didn't make any silly mistakes, the
CFI is correct at every instruction.

>
> >It also sounds like your DWARF2_REG_TO_REGNUM may need work, if the
> >unwinder thinks r16 is the return address column and GDB thinks it's an
> >8-bit register.
>
> Ugh, I had totally missed that (i.e. I don't even have a CRIS-specific
> DWARF2_REG_TO_REGNUM). Looking at the other targets' implementations I
> don't understand where they got the dwarf2 register mapping from (though
> amd64-tdep.c mentions System V psABI), and the dwarf2 spec says in
> "2.4.2 Register Name Operators" it should be in the architecture's ABI
> spec. I'll go bug my compiler guy, or go look in gcc myself.
>
> --
> Orjan Friberg
> Axis Communications
>

>
> test: file format elf32-cris
>
> Disassembly of section .text:
>
> 00080074 <bar>:
> void bar(void) {}
> 80074: fce1 ee8f push $r8
> 80078: 6e86 move.d $sp,$r8
> 8007a: 68e6 move.d $r8,$sp
> 8007c: 7fb6 ret
> 8007e: 6e8e pop $r8
>
> 00080080 <foo>:
> void foo(void)
> {
> 80080: fce1 7ebe push $srp
> 80084: fce1 ee8f push $r8
> 80088: 6e86 move.d $sp,$r8
> bar();
> 8008a: 3fbd 7400 0800 jsr 80074 <bar>
> }
> 80090: 68e6 move.d $r8,$sp
> 80092: 6e8e pop $r8
> 80094: 3e0d jump [$sp+]
>
> 00080096 :
> int main ()
> {
> 80096: fce1 7ebe push $srp
> 8009a: fce1 ee8f push $r8
> 8009e: 6e86 move.d $sp,$r8
> foo();
> 800a0: 3fbd 8000 0800 jsr 80080 <foo>
> return 0;
> 800a6: 7986 clear.d $r9
> }
> 800a8: 69a6 move.d $r9,$r10
> 800aa: 68e6 move.d $r8,$sp
> 800ac: 6e8e pop $r8
> 800ae: 3e0d jump [$sp+]

> The section .debug_aranges contains:
>
> Length: 28
> Version: 2
> Offset into .debug_info: 0
> Pointer Size: 4
> Segment Size: 0
>
> Address Length
> 00080074 60
>
> Contents of the .debug_pubnames section:
>
> Length: 39
> Version: 2
> Offset into .debug_info section: 0
> Size of area in .debug_info section: 105
>
> Offset Name
> 37 bar
> 56 foo
> 75 main
>
> The section .debug_info contains:
>
> Compilation Unit @ 0:
> Length: 101
> Version: 2
> Abbrev Offset: 0
> Pointer Size: 4
> <0>: Abbrev Number: 1 (DW_TAG_compile_unit)
> DW_AT_stmt_list : 0
> DW_AT_high_pc : 0x800b0 524464
> DW_AT_low_pc : 0x80074 524404
> DW_AT_name : (indirect string, offset: 0x34): test.c
> DW_AT_comp_dir : (indirect string, offset: 0x0): /home/orjanf
> DW_AT_producer : (indirect string, offset: 0xd): GNU C 3.2.1 Axis release R55/1.55
> DW_AT_language : 1 (ANSI C)
> <1><25>: Abbrev Number: 2 (DW_TAG_subprogram)
> DW_AT_external : 1
> DW_AT_name : bar
> DW_AT_decl_file : 1
> DW_AT_decl_line : 1
> DW_AT_prototyped : 1
> DW_AT_low_pc : 0x80074 524404
> DW_AT_high_pc : 0x80080 524416
> DW_AT_frame_base : 1 byte block: 58 (DW_OP_reg8; )
> <1><38>: Abbrev Number: 2 (DW_TAG_subprogram)
> DW_AT_external : 1
> DW_AT_name : foo
> DW_AT_decl_file : 1
> DW_AT_decl_line : 3
> DW_AT_prototyped : 1
> DW_AT_low_pc : 0x80080 524416
> DW_AT_high_pc : 0x80096 524438
> DW_AT_frame_base : 1 byte block: 58 (DW_OP_reg8; )
> <1><4b>: Abbrev Number: 3 (DW_TAG_subprogram)
> DW_AT_external : 1
> DW_AT_name : (indirect string, offset: 0x2f): main
> DW_AT_decl_file : 1
> DW_AT_decl_line : 7
> DW_AT_type : <61>
> DW_AT_low_pc : 0x80096 524438
> DW_AT_high_pc : 0x800b0 524464
> DW_AT_frame_base : 1 byte block: 58 (DW_OP_reg8; )
> <1><61>: Abbrev Number: 4 (DW_TAG_base_type)
> DW_AT_name : int
> DW_AT_byte_size : 4
> DW_AT_encoding : 5 (signed)
>
> Contents of the .debug_abbrev section:
>
> Number TAG
> 1 DW_TAG_compile_unit [has children]
> DW_AT_stmt_list DW_FORM_data4
> DW_AT_high_pc DW_FORM_addr
> DW_AT_low_pc DW_FORM_addr
> DW_AT_name DW_FORM_strp
> DW_AT_comp_dir DW_FORM_strp
> DW_AT_producer DW_FORM_strp
> DW_AT_language DW_FORM_data1
> 2 DW_TAG_subprogram [no children]
> DW_AT_external DW_FORM_flag
> DW_AT_name DW_FORM_string
> DW_AT_decl_file DW_FORM_data1
> DW_AT_decl_line DW_FORM_data1
> DW_AT_prototyped DW_FORM_flag
> DW_AT_low_pc DW_FORM_addr
> DW_AT_high_pc DW_FORM_addr
> DW_AT_frame_base DW_FORM_block1
> 3 DW_TAG_subprogram [no children]
> DW_AT_external DW_FORM_flag
> DW_AT_name DW_FORM_strp
> DW_AT_decl_file DW_FORM_data1
> DW_AT_decl_line DW_FORM_data1
> DW_AT_type DW_FORM_ref4
> DW_AT_low_pc DW_FORM_addr
> DW_AT_high_pc DW_FORM_addr
> DW_AT_frame_base DW_FORM_block1
> 4 DW_TAG_base_type [no children]
> DW_AT_name DW_FORM_string
> DW_AT_byte_size DW_FORM_data1
> DW_AT_encoding DW_FORM_data1
>
>
> Dump of debug contents of section .debug_line:
>
> Length: 52
> DWARF Version: 2
> Prologue Length: 26
> Minimum Instruction Length: 2
> Initial value of 'is_stmt': 1
> Line Base: -5
> Line Range: 14
> Opcode Base: 10
>
> Opcodes:
> Opcode 1 has 0 args
> Opcode 2 has 1 args
> Opcode 3 has 1 args
> Opcode 4 has 1 args
> Opcode 5 has 1 args
> Opcode 6 has 0 args
> Opcode 7 has 0 args
> Opcode 8 has 0 args
> Opcode 9 has 1 args
>
> The Directory Table is empty.
>
> The File Name Table:
> Entry Dir Time Size Name
> 1 0 0 0 test.c
>
> Line Number Statements:
> Extended opcode 2: set Address to 0x80074
> Special opcode 5: advance Address by 0 to 0x80074 and Line by 0 to 1
> Special opcode 91: advance Address by 12 to 0x80080 and Line by 2 to 3
> Special opcode 76: advance Address by 10 to 0x8008a and Line by 1 to 4
> Special opcode 48: advance Address by 6 to 0x80090 and Line by 1 to 5
> Special opcode 49: advance Address by 6 to 0x80096 and Line by 2 to 7
> Special opcode 76: advance Address by 10 to 0x800a0 and Line by 1 to 8
> Special opcode 48: advance Address by 6 to 0x800a6 and Line by 1 to 9
> Special opcode 20: advance Address by 2 to 0x800a8 and Line by 1 to 10
> Advance PC by 8 to 800b0
> Extended opcode 1: End of Sequence
>
>
> The section .debug_frame contains:
>
> 00000000 0000000c ffffffff CIE
> Version: 1
> Augmentation: ""
> Code alignment factor: 1
> Data alignment factor: -1
> Return address column: 16
>
> DW_CFA_def_cfa: r14 ofs 0
>
> 00000010 00000014 00000000 FDE cie=00000000 pc=00080074..00080080
> DW_CFA_advance_loc: 0 to 00080074
> DW_CFA_def_cfa: r8 ofs 4
> DW_CFA_offset: r8 at cfa-4
> DW_CFA_nop
> DW_CFA_nop
>
> 00000028 00000014 00000000 FDE cie=00000000 pc=00080080..00080096
> DW_CFA_advance_loc: 0 to 00080080
> DW_CFA_def_cfa: r8 ofs 8
> DW_CFA_offset: r16 at cfa-4
> DW_CFA_offset: r8 at cfa-8
>
> 00000040 00000014 00000000 FDE cie=00000000 pc=00080096..000800b0
> DW_CFA_advance_loc: 0 to 00080096
> DW_CFA_def_cfa: r8 ofs 8
> DW_CFA_offset: r16 at cfa-4
> DW_CFA_offset: r8 at cfa-8
>
> Contents of the .debug_str section:
>
> 0x00000000 2f686f6d 652f6f72 6a616e66 00474e55 /home/orjanf.GNU
> 0x00000010 20432033 2e322e31 20417869 73207265 C 3.2.1 Axis re
> 0x00000020 6c656173 65205235 352f312e 3535006d lease R55/1.55.m
> 0x00000030 61696e00 74657374 2e6300 ain.test.c.

--
Daniel Jacobowitz
MontaVista Software Debian GNU/Linux Developer