diff options
Diffstat (limited to 'gas/gen-sframe.c')
-rw-r--r-- | gas/gen-sframe.c | 170 |
1 files changed, 110 insertions, 60 deletions
diff --git a/gas/gen-sframe.c b/gas/gen-sframe.c index 5c8c7eb..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,7 +1011,7 @@ 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. */ @@ -1072,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; } @@ -1102,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; @@ -1131,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. */ @@ -1159,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. */ } @@ -1187,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; } @@ -1246,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) { @@ -1255,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; } @@ -1283,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. */ @@ -1310,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. */ } @@ -1365,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; @@ -1531,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; } @@ -1539,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. */ @@ -1638,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. */ @@ -1651,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; } @@ -1675,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; } @@ -1707,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; @@ -1719,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; } |