This patch adds support for .cfi_val_offset GAS pseudo command which
maps to DW_CFA_val_offset and DW_CFA_val_offset_sf.
gas/ChangeLog:
2016-09-29 Andreas Krebbel <krebbel@linux.vnet.ibm.com>
* doc/as.texinfo: Add docu for .cfi_val_offset.
* dw2gencfi.c (cfi_add_CFA_val_offset): New function.
(dot_cfi): Add case for DW_CFA_val_offset.
(output_cfi_insn): Likewise.
(cfi_pseudo_table): Add entry for cfi_val_offset.
* dw2gencfi.h: Add prototype for cfi_add_CFA_val_offset.
* testsuite/gas/cfi/cfi-common-8.d: New test.
* testsuite/gas/cfi/cfi-common-8.s: New test.
* testsuite/gas/cfi/cfi.exp: Run cfi-common-8 testcase.
binutils/ChangeLog:
2016-09-29 Andreas Krebbel <krebbel@linux.vnet.ibm.com>
* dwarf.c (display_debug_frames): Adjust output line.
if (reg >= (unsigned int) fc->ncols)
reg_prefix = bad_reg;
if (! do_debug_frames_interp || *reg_prefix != '\0')
if (reg >= (unsigned int) fc->ncols)
reg_prefix = bad_reg;
if (! do_debug_frames_interp || *reg_prefix != '\0')
- printf (" DW_CFA_val_offset: %s%s at cfa%+ld\n",
+ printf (" DW_CFA_val_offset: %s%s is cfa%+ld\n",
reg_prefix, regname (reg, 0),
roffs * fc->data_factor);
if (*reg_prefix == '\0')
reg_prefix, regname (reg, 0),
roffs * fc->data_factor);
if (*reg_prefix == '\0')
if (frame_need_space (fc, reg) < 0)
reg_prefix = bad_reg;
if (! do_debug_frames_interp || *reg_prefix != '\0')
if (frame_need_space (fc, reg) < 0)
reg_prefix = bad_reg;
if (! do_debug_frames_interp || *reg_prefix != '\0')
- printf (" DW_CFA_val_offset_sf: %s%s at cfa%+ld\n",
+ printf (" DW_CFA_val_offset_sf: %s%s is cfa%+ld\n",
reg_prefix, regname (reg, 0),
(long)(l * fc->data_factor));
if (*reg_prefix == '\0')
reg_prefix, regname (reg, 0),
(long)(l * fc->data_factor));
if (*reg_prefix == '\0')
Previous value of @var{register} is saved at offset @var{offset} from
CFA.
Previous value of @var{register} is saved at offset @var{offset} from
CFA.
+@subsection @code{.cfi_val_offset @var{register}, @var{offset}}
+Previous value of @var{register} is CFA + @var{offset}.
+
@subsection @code{.cfi_rel_offset @var{register}, @var{offset}}
Previous value of @var{register} is saved at offset @var{offset} from
the current CFA register. This is transformed to @code{.cfi_offset}
@subsection @code{.cfi_rel_offset @var{register}, @var{offset}}
Previous value of @var{register} is saved at offset @var{offset} from
the current CFA register. This is transformed to @code{.cfi_offset}
as_bad (_("register save offset not a multiple of %u"), abs_data_align);
}
as_bad (_("register save offset not a multiple of %u"), abs_data_align);
}
+/* Add a DW_CFA_val_offset record to the CFI data. */
+
+void
+cfi_add_CFA_val_offset (unsigned regno, offsetT offset)
+{
+ unsigned int abs_data_align;
+
+ gas_assert (DWARF2_CIE_DATA_ALIGNMENT != 0);
+ cfi_add_CFA_insn_reg_offset (DW_CFA_val_offset, regno, offset);
+
+ abs_data_align = (DWARF2_CIE_DATA_ALIGNMENT < 0
+ ? -DWARF2_CIE_DATA_ALIGNMENT : DWARF2_CIE_DATA_ALIGNMENT);
+ if (offset % abs_data_align)
+ as_bad (_("register save offset not a multiple of %u"), abs_data_align);
+}
+
/* Add a DW_CFA_def_cfa record to the CFI data. */
void
/* Add a DW_CFA_def_cfa record to the CFI data. */
void
{ "cfi_val_encoded_addr", dot_cfi_val_encoded_addr, 0 },
{ "cfi_inline_lsda", dot_cfi_inline_lsda, 0 },
{ "cfi_label", dot_cfi_label, 0 },
{ "cfi_val_encoded_addr", dot_cfi_val_encoded_addr, 0 },
{ "cfi_inline_lsda", dot_cfi_inline_lsda, 0 },
{ "cfi_label", dot_cfi_label, 0 },
+ { "cfi_val_offset", dot_cfi, DW_CFA_val_offset },
cfi_add_CFA_offset (reg1, offset);
break;
cfi_add_CFA_offset (reg1, offset);
break;
+ case DW_CFA_val_offset:
+ reg1 = cfi_parse_reg ();
+ cfi_parse_separator ();
+ offset = cfi_parse_const ();
+ cfi_add_CFA_val_offset (reg1, offset);
+ break;
+
case CFI_rel_offset:
reg1 = cfi_parse_reg ();
cfi_parse_separator ();
case CFI_rel_offset:
reg1 = cfi_parse_reg ();
cfi_parse_separator ();
+ case DW_CFA_val_offset:
+ regno = insn->u.ri.reg;
+ offset = insn->u.ri.offset / DWARF2_CIE_DATA_ALIGNMENT;
+ if (offset < 0)
+ {
+ out_one (DW_CFA_val_offset_sf);
+ out_uleb128 (regno);
+ out_sleb128 (offset);
+ }
+ else
+ {
+ out_one (DW_CFA_val_offset);
+ out_uleb128 (regno);
+ out_uleb128 (offset);
+ }
+ break;
+
case DW_CFA_register:
out_one (DW_CFA_register);
out_uleb128 (insn->u.rr.reg1);
case DW_CFA_register:
out_one (DW_CFA_register);
out_uleb128 (insn->u.rr.reg1);
{ "cfi_val_encoded_addr", dot_cfi_dummy, 0 },
{ "cfi_label", dot_cfi_dummy, 0 },
{ "cfi_inline_lsda", dot_cfi_dummy, 0 },
{ "cfi_val_encoded_addr", dot_cfi_dummy, 0 },
{ "cfi_label", dot_cfi_dummy, 0 },
{ "cfi_inline_lsda", dot_cfi_dummy, 0 },
+ { "cfi_val_offset", dot_cfi_dummy, 0 },
extern void cfi_add_label (const char *);
extern void cfi_add_CFA_offset (unsigned, offsetT);
extern void cfi_add_label (const char *);
extern void cfi_add_CFA_offset (unsigned, offsetT);
+extern void cfi_add_CFA_val_offset (unsigned, offsetT);
extern void cfi_add_CFA_def_cfa (unsigned, offsetT);
extern void cfi_add_CFA_register (unsigned, unsigned);
extern void cfi_add_CFA_def_cfa_register (unsigned);
extern void cfi_add_CFA_def_cfa (unsigned, offsetT);
extern void cfi_add_CFA_register (unsigned, unsigned);
extern void cfi_add_CFA_def_cfa_register (unsigned);
--- /dev/null
+#objdump: -Wf
+#name: CFI common 8
+#...
+Contents of the .eh_frame section:
+
+00000000 0+0010 0+0000 CIE
+ Version: 1
+ Augmentation: "zR"
+ Code alignment factor: .*
+ Data alignment factor: .*
+ Return address column: .*
+ Augmentation data: [01]b
+
+ DW_CFA_nop
+ DW_CFA_nop
+ DW_CFA_nop
+
+00000014 0+00(18|1c|20) 0+0018 FDE cie=0+0000 pc=.*
+ DW_CFA_advance_loc: 4 to .*
+ DW_CFA_def_cfa: r0( \([er]ax\)|) ofs 16
+ DW_CFA_val_offset(_sf|): r1( \((rdx|ecx)\)|) is cfa\+8
+ DW_CFA_val_offset(_sf|): r2( \((rcx|edx)\)|) is cfa-32
+#...
--- /dev/null
+ .cfi_startproc simple
+ .long 0
+ .cfi_def_cfa 0, 16
+ .cfi_val_offset 1, 8
+ .cfi_val_offset 2, -32
+ .cfi_endproc
run_dump_test "cfi-common-6"
}
run_dump_test "cfi-common-7"
run_dump_test "cfi-common-6"
}
run_dump_test "cfi-common-7"
+ run_dump_test "cfi-common-8"