aboutsummaryrefslogtreecommitdiff
path: root/gas/gen-sframe.c
diff options
context:
space:
mode:
Diffstat (limited to 'gas/gen-sframe.c')
-rw-r--r--gas/gen-sframe.c174
1 files changed, 113 insertions, 61 deletions
diff --git a/gas/gen-sframe.c b/gas/gen-sframe.c
index 5b5e7b1..2d1c196 100644
--- a/gas/gen-sframe.c
+++ b/gas/gen-sframe.c
@@ -30,18 +30,6 @@
# define sizeof_member(type, member) (sizeof (((type *)0)->member))
#endif
-/* Whether frame row entries track RA.
-
- A target may not need return address tracking for stack tracing. If it
- does need the same, SFRAME_CFA_RA_REG must be defined with the return
- address register number. */
-
-#if defined (sframe_ra_tracking_p) && defined (SFRAME_CFA_RA_REG)
-# ifndef SFRAME_FRE_RA_TRACKING
-# define SFRAME_FRE_RA_TRACKING 1
-# endif
-#endif
-
/* SFrame FRE type selection optimization is an optimization for size.
There are three flavors of SFrame FRE representation in the binary format:
@@ -154,7 +142,6 @@ sframe_fre_set_cfa_offset (struct sframe_row_entry *fre,
fre->merge_candidate = false;
}
-#ifdef SFRAME_FRE_RA_TRACKING
static void
sframe_fre_set_ra_track (struct sframe_row_entry *fre, offsetT ra_offset)
{
@@ -162,7 +149,6 @@ sframe_fre_set_ra_track (struct sframe_row_entry *fre, offsetT ra_offset)
fre->ra_offset = ra_offset;
fre->merge_candidate = false;
}
-#endif
static void
sframe_fre_set_bp_track (struct sframe_row_entry *fre, offsetT bp_offset)
@@ -352,11 +338,9 @@ get_fre_num_offsets (struct sframe_row_entry *sframe_fre)
if (sframe_fre->bp_loc == SFRAME_FRE_ELEM_LOC_STACK)
fre_num_offsets++;
-#ifdef SFRAME_FRE_RA_TRACKING
if (sframe_ra_tracking_p ()
&& sframe_fre->ra_loc == SFRAME_FRE_ELEM_LOC_STACK)
fre_num_offsets++;
-#endif
return fre_num_offsets;
}
@@ -377,11 +361,9 @@ sframe_get_fre_offset_size (struct sframe_row_entry *sframe_fre)
cfa_offset_size = get_offset_size_in_bytes (sframe_fre->cfa_offset);
if (sframe_fre->bp_loc == SFRAME_FRE_ELEM_LOC_STACK)
bp_offset_size = get_offset_size_in_bytes (sframe_fre->bp_offset);
-#ifdef SFRAME_FRE_RA_TRACKING
if (sframe_ra_tracking_p ()
&& sframe_fre->ra_loc == SFRAME_FRE_ELEM_LOC_STACK)
ra_offset_size = get_offset_size_in_bytes (sframe_fre->ra_offset);
-#endif
/* Get the maximum size needed to represent the offsets. */
max_offset_size = cfa_offset_size;
@@ -587,14 +569,12 @@ output_sframe_row_entry (symbolS *fde_start_addr,
fre_offset_func_map[idx].out_func (sframe_fre->cfa_offset);
fre_write_offsets++;
-#ifdef SFRAME_FRE_RA_TRACKING
if (sframe_ra_tracking_p ()
&& sframe_fre->ra_loc == SFRAME_FRE_ELEM_LOC_STACK)
{
fre_offset_func_map[idx].out_func (sframe_fre->ra_offset);
fre_write_offsets++;
}
-#endif
if (sframe_fre->bp_loc == SFRAME_FRE_ELEM_LOC_STACK)
{
fre_offset_func_map[idx].out_func (sframe_fre->bp_offset);
@@ -688,9 +668,9 @@ output_sframe_internal (void)
unsigned int num_fdes = get_num_sframe_fdes ();
unsigned int num_fres = get_num_sframe_fres ();
- symbolS **fre_symbols = XNEWVEC (symbolS *, num_fres);
- for (i = 0; i < num_fres; i++)
- fre_symbols[i] = symbol_temp_make ();
+ symbolS **fde_fre_symbols = XNEWVEC (symbolS *, num_fdes);
+ for (i = 0; i < num_fdes; i++)
+ fde_fre_symbols[i] = symbol_temp_make ();
end_of_frame_hdr = symbol_temp_make ();
start_of_fre_section = symbol_temp_make ();
@@ -764,8 +744,8 @@ output_sframe_internal (void)
for (sframe_fde = all_sframe_fdes; sframe_fde; sframe_fde = sframe_fde->next)
{
output_sframe_funcdesc (start_of_fre_section,
- fre_symbols[i], sframe_fde);
- i += sframe_fde->num_fres;
+ fde_fre_symbols[i], sframe_fde);
+ i++;
}
symbol_set_value_now (start_of_fre_section);
@@ -776,16 +756,16 @@ output_sframe_internal (void)
for (sframe_fde = all_sframe_fdes; sframe_fde; sframe_fde = sframe_fde_next)
{
+ symbol_set_value_now (fde_fre_symbols[i]);
for (sframe_fre = sframe_fde->sframe_fres;
sframe_fre;
sframe_fre = sframe_fre->next)
{
- symbol_set_value_now (fre_symbols[i]);
output_sframe_row_entry (get_dw_fde_start_addrS (sframe_fde->dw_fde),
get_dw_fde_end_addrS (sframe_fde->dw_fde),
sframe_fre);
- i++;
}
+ i++;
sframe_fde_next = sframe_fde->next;
sframe_fde_free (sframe_fde);
}
@@ -794,10 +774,10 @@ output_sframe_internal (void)
symbol_set_value_now (end_of_frame_section);
- gas_assert (i == num_fres);
+ gas_assert (i == num_fdes);
- free (fre_symbols);
- fre_symbols = NULL;
+ free (fde_fre_symbols);
+ fde_fre_symbols = NULL;
}
static unsigned int
@@ -926,10 +906,8 @@ sframe_register_name (unsigned int reg)
return "SP";
else if (reg == SFRAME_CFA_FP_REG)
return "FP";
-#ifdef SFRAME_FRE_RA_TRACKING
else if (reg == SFRAME_CFA_RA_REG)
return "RA";
-#endif
else
return NULL;
}
@@ -1003,7 +981,8 @@ sframe_xlate_do_def_cfa (struct sframe_xlate_ctx *xlate_ctx,
if (cfi_insn->u.ri.reg != SFRAME_CFA_SP_REG
&& cfi_insn->u.ri.reg != SFRAME_CFA_FP_REG)
{
- as_warn (_("skipping SFrame FDE; non-SP/FP register %u in .cfi_def_cfa"),
+ as_warn (_("no SFrame FDE emitted; "
+ "non-SP/FP register %u in .cfi_def_cfa"),
cfi_insn->u.ri.reg);
return SFRAME_XLATE_ERR_NOTREPRESENTED; /* Not represented. */
}
@@ -1032,13 +1011,15 @@ sframe_xlate_do_def_cfa_register (struct sframe_xlate_ctx *xlate_ctx,
if (cfi_insn->u.r != SFRAME_CFA_SP_REG
&& cfi_insn->u.r != SFRAME_CFA_FP_REG)
{
- as_warn (_("skipping SFrame FDE; "
+ as_warn (_("no SFrame FDE emitted; "
"non-SP/FP register %u in .cfi_def_cfa_register"),
cfi_insn->u.r);
return SFRAME_XLATE_ERR_NOTREPRESENTED; /* Not represented. */
}
sframe_fre_set_cfa_base_reg (cur_fre, cfi_insn->u.r);
- sframe_fre_set_cfa_offset (cur_fre, last_fre->cfa_offset);
+ if (last_fre)
+ sframe_fre_set_cfa_offset (cur_fre, last_fre->cfa_offset);
+
cur_fre->merge_candidate = false;
return SFRAME_XLATE_OK;
@@ -1070,7 +1051,7 @@ sframe_xlate_do_def_cfa_offset (struct sframe_xlate_ctx *xlate_ctx,
{
/* No CFA base register in effect. Non-SP/FP CFA base register should
not occur, as sframe_xlate_do_def_cfa[_register] would detect this. */
- as_warn (_("skipping SFrame FDE; "
+ as_warn (_("no SFrame FDE emitted; "
".cfi_def_cfa_offset without CFA base register in effect"));
return SFRAME_XLATE_ERR_NOTREPRESENTED;
}
@@ -1100,14 +1081,12 @@ sframe_xlate_do_offset (struct sframe_xlate_ctx *xlate_ctx,
sframe_fre_set_bp_track (cur_fre, cfi_insn->u.ri.offset);
cur_fre->merge_candidate = false;
}
-#ifdef SFRAME_FRE_RA_TRACKING
else if (sframe_ra_tracking_p ()
&& cfi_insn->u.ri.reg == SFRAME_CFA_RA_REG)
{
sframe_fre_set_ra_track (cur_fre, cfi_insn->u.ri.offset);
cur_fre->merge_candidate = false;
}
-#endif
/* This is used to track changes to non-rsp registers, skip all others
except FP / RA for now. */
return SFRAME_XLATE_OK;
@@ -1129,13 +1108,11 @@ sframe_xlate_do_val_offset (const struct sframe_xlate_ctx *xlate_ctx ATTRIBUTE_U
DW_CFA_val_offset instruction can be safely skipped without sacrificing
the asynchronicity of stack trace information. */
if (cfi_insn->u.ri.reg == SFRAME_CFA_FP_REG
-#ifdef SFRAME_FRE_RA_TRACKING
|| (sframe_ra_tracking_p () && cfi_insn->u.ri.reg == SFRAME_CFA_RA_REG)
-#endif
/* Ignore SP reg, if offset matches assumed default rule. */
|| (cfi_insn->u.ri.reg == SFRAME_CFA_SP_REG && cfi_insn->u.ri.offset != 0))
{
- as_warn (_("skipping SFrame FDE; %s with %s reg %u"),
+ as_warn (_("no SFrame FDE emitted; %s with %s reg %u"),
cfi_esc_p ? ".cfi_escape DW_CFA_val_offset" : ".cfi_val_offset",
sframe_register_name (cfi_insn->u.ri.reg), cfi_insn->u.ri.reg);
return SFRAME_XLATE_ERR_NOTREPRESENTED; /* Not represented. */
@@ -1157,13 +1134,11 @@ sframe_xlate_do_register (struct sframe_xlate_ctx *xlate_ctx ATTRIBUTE_UNUSED,
instruction can be safely skipped without sacrificing the asynchronicity of
stack trace information. */
if (cfi_insn->u.rr.reg1 == SFRAME_CFA_FP_REG
-#ifdef SFRAME_FRE_RA_TRACKING
|| (sframe_ra_tracking_p () && cfi_insn->u.rr.reg1 == SFRAME_CFA_RA_REG)
-#endif
/* Ignore SP reg, as it can be recovered from the CFA tracking info. */
)
{
- as_warn (_("skipping SFrame FDE; %s register %u in .cfi_register"),
+ as_warn (_("no SFrame FDE emitted; %s register %u in .cfi_register"),
sframe_register_name (cfi_insn->u.rr.reg1), cfi_insn->u.rr.reg1);
return SFRAME_XLATE_ERR_NOTREPRESENTED; /* Not represented. */
}
@@ -1185,7 +1160,7 @@ sframe_xlate_do_remember_state (struct sframe_xlate_ctx *xlate_ctx)
info for the function involved. */
if (!last_fre)
{
- as_warn (_("skipping SFrame FDE; "
+ as_warn (_("no SFrame FDE emitted; "
".cfi_remember_state without prior SFrame FRE state"));
return SFRAME_XLATE_ERR_INVAL;
}
@@ -1244,7 +1219,6 @@ sframe_xlate_do_restore (struct sframe_xlate_ctx *xlate_ctx,
cur_fre->bp_offset = cie_fre->bp_offset;
cur_fre->merge_candidate = false;
}
-#ifdef SFRAME_FRE_RA_TRACKING
else if (sframe_ra_tracking_p ()
&& cfi_insn->u.r == SFRAME_CFA_RA_REG)
{
@@ -1253,7 +1227,6 @@ sframe_xlate_do_restore (struct sframe_xlate_ctx *xlate_ctx,
cur_fre->ra_offset = cie_fre->ra_offset;
cur_fre->merge_candidate = false;
}
-#endif
return SFRAME_XLATE_OK;
}
@@ -1281,7 +1254,7 @@ static int
sframe_xlate_do_aarch64_negate_ra_state_with_pc (struct sframe_xlate_ctx *xlate_ctx ATTRIBUTE_UNUSED,
struct cfi_insn_data *cfi_insn ATTRIBUTE_UNUSED)
{
- as_warn (_("skipping SFrame FDE; .cfi_negate_ra_state_with_pc"));
+ as_warn (_("no SFrame FDE emitted; .cfi_negate_ra_state_with_pc"));
/* The used signing method should be encoded inside the FDE in SFrame v3.
For now, PAuth_LR extension is not supported with SFrame. */
return SFRAME_XLATE_ERR_NOTREPRESENTED; /* Not represented. */
@@ -1308,7 +1281,7 @@ sframe_xlate_do_gnu_window_save (struct sframe_xlate_ctx *xlate_ctx,
|| abi_arch == SFRAME_ABI_AARCH64_ENDIAN_LITTLE)
return sframe_xlate_do_aarch64_negate_ra_state (xlate_ctx, cfi_insn);
- as_warn (_("skipping SFrame FDE; .cfi_window_save"));
+ as_warn (_("no SFrame FDE emitted; .cfi_window_save"));
return SFRAME_XLATE_ERR_NOTREPRESENTED; /* Not represented. */
}
@@ -1363,12 +1336,10 @@ sframe_xlate_do_escape_expr (const struct sframe_xlate_ctx *xlate_ctx,
#undef CFI_ESC_NUM_EXP
if (reg == SFRAME_CFA_SP_REG || reg == SFRAME_CFA_FP_REG
-#ifdef SFRAME_FRE_RA_TRACKING
|| (sframe_ra_tracking_p () && reg == SFRAME_CFA_RA_REG)
-#endif
|| reg == xlate_ctx->cur_fre->cfa_base_reg)
{
- as_warn (_("skipping SFrame FDE; "
+ as_warn (_("no SFrame FDE emitted; "
".cfi_escape DW_CFA_expression with %s reg %u"),
sframe_register_name (reg), reg);
err = SFRAME_XLATE_ERR_NOTREPRESENTED;
@@ -1529,7 +1500,7 @@ sframe_xlate_do_cfi_escape (const struct sframe_xlate_ctx *xlate_ctx,
OS-specific CFI opcodes), skip inspecting the DWARF expression.
This may impact the asynchronicity due to loss of coverage.
Continue to warn the user and bail out. */
- as_warn (_("skipping SFrame FDE; .cfi_escape with op (%#lx)"),
+ as_warn (_("no SFrame FDE emitted; .cfi_escape with op (%#lx)"),
(unsigned long)firstop);
err = SFRAME_XLATE_ERR_NOTREPRESENTED;
}
@@ -1537,6 +1508,89 @@ sframe_xlate_do_cfi_escape (const struct sframe_xlate_ctx *xlate_ctx,
return err;
}
+/* Translate DW_CFA_undefined into SFrame context.
+
+ DW_CFA_undefined op indicates that from now on, the previous value of
+ register can’t be restored anymore. In SFrame stack trace, we cannot
+ represent such a semantic. So, we skip generating an SFrame FDE for this,
+ when a register of interest is used with DW_CFA_undefined.
+
+ Return SFRAME_XLATE_OK if success. */
+
+static int
+sframe_xlate_do_cfi_undefined (const struct sframe_xlate_ctx *xlate_ctx ATTRIBUTE_UNUSED,
+ const struct cfi_insn_data *cfi_insn)
+{
+ if (cfi_insn->u.r == SFRAME_CFA_FP_REG
+ || cfi_insn->u.r == SFRAME_CFA_RA_REG
+ || cfi_insn->u.r == SFRAME_CFA_SP_REG)
+ {
+ as_warn (_("no SFrame FDE emitted; %s reg %u in .cfi_undefined"),
+ sframe_register_name (cfi_insn->u.r), cfi_insn->u.r);
+ return SFRAME_XLATE_ERR_NOTREPRESENTED; /* Not represented. */
+ }
+
+ /* Safe to skip. */
+ return SFRAME_XLATE_OK;
+}
+
+/* Translate DW_CFA_same_value into SFrame context.
+
+ DW_CFA_same_value op indicates that current value of register is the same as
+ in the previous frame, i.e. no restoration needed. In SFrame stack trace
+ format, the handling is done similar to DW_CFA_restore.
+
+ For SFRAME_CFA_RA_REG, if RA-tracking is enabled, reset the SFrame FRE state
+ for REG_RA to indicate that register does not need restoration. P.S.: Even
+ though resetting just REG_RA may be contradicting the AArch64 ABI (as Frame
+ Record contains for FP and LR), sframe_xlate_do_same_value () does not
+ detect the case and assumes the users' DW_CFA_same_value SFRAME_CFA_RA_REG
+ has a sound reason. For ABIs, where RA-tracking is disabled, handle it
+ similar to DW_CFA_restore: ignore the directive, it is safe to skip. The
+ reasoning is similar to that for DW_CFA_restore: if such a restoration was
+ meant to be of any consequence, there must have been the necessary CFI
+ directives for updating the CFA rule too such that the recovered RA from
+ stack is valid.
+
+ SFrame based stacktracers will implement CFA-based SP recovery for all ABIs:
+ SP for previous frame is based on the applicable CFA-rule. There is no
+ representation in SFrame to indicate "no restoration needed" for REG_SP,
+ when going to the previous frame. That said, if DW_CFA_same_value is seen
+ for SFRAME_CFA_SP_REG, handle it similar to DW_CFA_restore: ignore the
+ directive, it is safe to skip. The reasoning is similar to that for
+ DW_CFA_restore: if such a restoration was meant to be of any consequence,
+ there must have been the necessary CFI directives for updating the CFA rule
+ too. The latter will be duly processed by the SFrame generation code, as
+ expected.
+
+ For SFRAME_CFA_FP_REG, reset the state of the current FRE to indicate that
+ the value is the same as previous frame.
+
+ Return SFRAME_XLATE_OK if success. */
+
+static int
+sframe_xlate_do_same_value (const struct sframe_xlate_ctx *xlate_ctx,
+ const struct cfi_insn_data *cfi_insn)
+{
+ struct sframe_row_entry *cur_fre = xlate_ctx->cur_fre;
+
+ if (sframe_ra_tracking_p () && cfi_insn->u.r == SFRAME_CFA_RA_REG)
+ {
+ cur_fre->ra_loc = SFRAME_FRE_ELEM_LOC_REG;
+ cur_fre->ra_offset = 0;
+ cur_fre->merge_candidate = false;
+ }
+ else if (cfi_insn->u.r == SFRAME_CFA_FP_REG)
+ {
+ cur_fre->bp_loc = SFRAME_FRE_ELEM_LOC_REG;
+ cur_fre->bp_offset = 0;
+ cur_fre->merge_candidate = false;
+ }
+
+ /* Safe to skip. */
+ return SFRAME_XLATE_OK;
+}
+
/* Returns the DWARF call frame instruction name or fake CFI name for the
specified CFI opcode, or NULL if the value is not recognized. */
@@ -1636,11 +1690,11 @@ sframe_do_cfi_insn (struct sframe_xlate_ctx *xlate_ctx,
case CFI_escape:
err = sframe_xlate_do_cfi_escape (xlate_ctx, cfi_insn);
break;
- /* Following CFI opcodes are not processed at this time.
- These do not impact the coverage of the basic stack tracing
- information as conveyed in the SFrame format. */
case DW_CFA_undefined:
+ err = sframe_xlate_do_cfi_undefined (xlate_ctx, cfi_insn);
+ break;
case DW_CFA_same_value:
+ err = sframe_xlate_do_same_value (xlate_ctx, cfi_insn);
break;
default:
/* Other skipped operations may, however, impact the asynchronicity. */
@@ -1649,7 +1703,7 @@ sframe_do_cfi_insn (struct sframe_xlate_ctx *xlate_ctx,
if (!cfi_name)
cfi_name = _("(unknown)");
- as_warn (_("skipping SFrame FDE; CFI insn %s (%#x)"),
+ as_warn (_("no SFrame FDE emitted; CFI insn %s (%#x)"),
cfi_name, op);
err = SFRAME_XLATE_ERR_NOTREPRESENTED;
}
@@ -1673,7 +1727,7 @@ sframe_do_fde (struct sframe_xlate_ctx *xlate_ctx,
/* SFrame format cannot represent a non-default DWARF return column reg. */
if (xlate_ctx->dw_fde->return_column != DWARF2_DEFAULT_RETURN_COLUMN)
{
- as_warn (_("skipping SFrame FDE; non-default RA register %u"),
+ as_warn (_("no SFrame FDE emitted; non-default RA register %u"),
xlate_ctx->dw_fde->return_column);
return SFRAME_XLATE_ERR_NOTREPRESENTED;
}
@@ -1705,7 +1759,6 @@ sframe_do_fde (struct sframe_xlate_ctx *xlate_ctx,
= get_dw_fde_end_addrS (xlate_ctx->dw_fde);
}
-#ifdef SFRAME_FRE_RA_TRACKING
if (sframe_ra_tracking_p ())
{
struct sframe_row_entry *fre;
@@ -1717,12 +1770,11 @@ sframe_do_fde (struct sframe_xlate_ctx *xlate_ctx,
if (fre->ra_loc != SFRAME_FRE_ELEM_LOC_STACK
&& fre->bp_loc == SFRAME_FRE_ELEM_LOC_STACK)
{
- as_warn (_("skipping SFrame FDE; FP without RA on stack"));
+ as_warn (_("no SFrame FDE emitted; FP without RA on stack"));
return SFRAME_XLATE_ERR_NOTREPRESENTED;
}
}
}
-#endif /* SFRAME_FRE_RA_TRACKING */
return SFRAME_XLATE_OK;
}