[PATCH] Force DW_CFA_def_cfa after DW_CFA_def_cfa_expression if no longer indirect

Jakub Jelinek jakub@redhat.com
Sat Apr 24 09:21:00 GMT 2010


On Fri, Apr 23, 2010 at 05:02:12PM -0700, Roland McGrath wrote:
> > GCC as producer seems to assume the offset in that case is something
> > get_cfa_from_loc_descr computes from the location expression (if
> > there is DW_OP_plus_uconst after deref, then it is the offset),
> > apparently e.g. libgcc unwinder assumes in that case offset is inherited
> > from DW_CFA_def_cfa or DW_CFA_def_cfa_offset{,_sf} valid before
> > the DW_CFA_def_cfa_expression.
> 
> What remains unclear to me is whether the old code in fact only ever
> produces this pattern in ways that are correct given that assumption about
> the consumer processing behavior, or might ever have produced actually
> wrong calculations.  That is, when the old code decides to emit
> DW_CFA_def_cfa_offset or DW_CFA_def_cfa_offset_sf, is the old_cfa.reg (with
> old_cfa.indirect=1) always the correct register for the new offset?  And,
> when the old code decides to emit DW_CFA_def_cfa_register, is
> old_cfa.offset (with old_cfa.indirect=1) always the correct offset for the
> new register?

GCC itself currently emits DW_CFA_def_cfa_expression only for indirect
addressing (guess that's only used for i?86/x86_64 dynamic stack
realignment).

/* This is how we define the location of the CFA. We use to handle it
   as REG + OFFSET all the time,  but now it can be more complex.
   It can now be either REG + CFA_OFFSET or *(REG + BASE_OFFSET) + CFA_OFFSET.
   Instead of passing around REG and OFFSET, we pass a copy
   of this structure.  */
typedef struct GTY(()) cfa_loc {
  HOST_WIDE_INT offset;
  HOST_WIDE_INT base_offset;
  unsigned int reg;
  BOOL_BITFIELD indirect : 1;  /* 1 if CFA is accessed via a dereference. 
  */
  BOOL_BITFIELD in_use : 1;    /* 1 if a saved cfa is stored here.  */
} dw_cfa_location;

So, all DW_CFA_def_cfa_expression expressions GCC ATM generates
should look like:
DW_OP_bregREG <base_offset> DW_OP_deref
DW_OP_bregx <reg> <base_offset> DW_OP_deref
DW_OP_bregREG <base_offset> DW_OP_deref DW_OP_plus_uconst <offset>
DW_OP_bregx <reg> <base_offset> DW_OP_deref DW_OP_plus_uconst <offset>

If GCC generated DW_CFA_def_cfa_expression is followed by GCC generated
DW_CFA_def_cfa_offset{,_sf}, then the assumed register that is
meant to be current is the REG/<reg> from those expressions.
If DW_CFA_def_cfa_register follows that DW_CFA_def_cfa_expression,
then offset is assumed to be 0 for the first two expressions and
<offset> for the last two.

This is just in case you'd want to hardcode the wrong GCC behavior
into your consumer.  Of course GCC's own unwinder doesn't handle that case
this way and other unwinders don't either...

> Everyone agrees that is valid and well-specified DWARF.  The current
> behavior at least one person on the DWARF committee asserts is invalid
> DWARF.

I completely agree that the current behavior is invalid DWARF too.

	Jakub



More information about the Gcc-patches mailing list