mirror of
https://sourceware.org/git/binutils-gdb.git
synced 2024-12-27 04:52:05 +08:00
b52c4ee466
Currently supported for x86_64 and aarch64 only. [PS: Currently, the compiler has not been adapted to generate ".cfi_sections" with ".sframe" in it. The newly added command line option of --gsframe provides an easy way to try out .sframe support in the toolchain.] gas interprets the CFI directives to generate DWARF-based .eh_frame info. These internal DWARF structures are now consumed by gen-sframe.[ch] sub-system to, in turn, create the SFrame unwind information. These internal DWARF structures are read-only for the purpose of SFrame unwind info generation. SFrame unwind info generation does not impact .eh_frame unwind info generation. Both .eh_frame and .sframe can co-exist in an ELF file, if so desired by the user. Recall that SFrame unwind information only contains the minimal necessary information to generate backtraces and does not provide information to recover all callee-saved registers. The reason being that callee-saved registers other than FP are not needed for stack unwinding, and hence are not included in the .sframe section. Consequently, gen-sframe.[ch] only needs to interpret a subset of DWARF opcodes in gas. More details follow. [Set 1, Interpreted] The following opcodes are interpreted: - DW_CFA_advance_loc - DW_CFA_def_cfa - DW_CFA_def_cfa_register - DW_CFA_def_cfa_offset - DW_CFA_offset - DW_CFA_remember_state - DW_CFA_restore_state - DW_CFA_restore [Set 2, Bypassed] The following opcodes are acknowledged but are not necessary for generating SFrame unwind info: - DW_CFA_undefined - DW_CFA_same_value Anything else apart from the two above-mentioned sets is skipped altogether. This means that any function containing a CFI directive not in Set 1 or Set 2 above, will not have any SFrame unwind information generated for them. Holes in instructions covered by FREs of a single FDE are not representable in the SFrame unwind format. As few examples, following opcodes are not processed for .sframe generation, and are skipped: - .cfi_personality* - .cfi_*lsda - .cfi_escape - .cfi_negate_ra_state - ... Not processing .cfi_escape, .cfi_negate_ra_state will cause SFrame unwind information to be absent for SFrame FDEs that contain these CFI directives, hence affecting the asynchronicity. x86-64 and aarch64 backends need to have a few new definitions and functions for .sframe generation. These provide gas with architecture specific information like the SP/FP/RA register numbers and an SFrame-specific ABI marker. Lastly, the patch also implements an optimization for size, where specific fragments containing SFrame FRE start address and SFrame FDE function are fixed up. This is similar to other similar optimizations in gas, where fragments are sized and fixed up when the associated symbols can be resolved. This optimization is controlled by a #define SFRAME_FRE_TYPE_SELECTION_OPT and should be easy to turn off if needed. The optimization is on by default for both x86_64 and aarch64. ChangeLog: * gas/Makefile.am: Include gen-sframe.c and sframe-opt.c. * gas/Makefile.in: Regenerated. * gas/as.h (enum _relax_state): Add new state rs_sframe. (sframe_estimate_size_before_relax): New function. (sframe_relax_frag): Likewise. (sframe_convert_frag): Likewise. * gas/config/tc-aarch64.c (aarch64_support_sframe_p): New definition. (aarch64_sframe_ra_tracking_p): Likewise. (aarch64_sframe_cfa_ra_offset): Likewise. (aarch64_sframe_get_abi_arch): Likewise. (md_begin): Set values of sp/fp/ra registers. * gas/config/tc-aarch64.h (aarch64_support_sframe_p): New declaration. (support_sframe_p): Likewise. (SFRAME_CFA_SP_REG): Likewise. (SFRAME_CFA_FP_REG): Likewise. (SFRAME_CFA_RA_REG): Likewise. (aarch64_sframe_ra_tracking_p): Likewise. (sframe_ra_tracking_p): Likewise. (aarch64_sframe_cfa_ra_offset): Likewise. (sframe_cfa_ra_offset): Likewise. (aarch64_sframe_get_abi_arch): Likewise. (sframe_get_abi_arch): Likewise. * gas/config/tc-i386.c (x86_support_sframe_p): New definition. (x86_sframe_ra_tracking_p): Likewise. (x86_sframe_cfa_ra_offset): Likewise. (x86_sframe_get_abi_arch): Likewise. * gas/config/tc-i386.h (x86_support_sframe_p): New declaration. (support_sframe_p): Likewise. (SFRAME_CFA_SP_REG): Likewise. (SFRAME_CFA_FP_REG): Likewise. (x86_sframe_ra_tracking_p): Likewise. (sframe_ra_tracking_p): Likewise. (x86_sframe_cfa_ra_offset): Likewise. (sframe_cfa_ra_offset): Likewise. (x86_sframe_get_abi_arch): Likewise. (sframe_get_abi_arch): Likewise. * gas/config/tc-xtensa.c (unrelaxed_frag_max_size): Add case for rs_sframe. * gas/doc/as.texi: Add .sframe to the documentation for .cfi_sections. * gas/dw2gencfi.c (cfi_finish): Create a .sframe section. * gas/dw2gencfi.h (CFI_EMIT_sframe): New definition. * gas/write.c (cvt_frag_to_fill): Handle rs_sframe. (relax_segment): Likewise. * gas/gen-sframe.c: New file. * gas/gen-sframe.h: New file. * gas/sframe-opt.c: New file.
154 lines
4.7 KiB
C
154 lines
4.7 KiB
C
/* gen-sframe.h - Support for generating SFrame.
|
|
Copyright (C) 2022 Free Software Foundation, Inc.
|
|
|
|
This file is part of GAS, the GNU Assembler.
|
|
|
|
GAS is free software; you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation; either version 3, or (at your option)
|
|
any later version.
|
|
|
|
GAS is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with GAS; see the file COPYING. If not, write to the Free
|
|
Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA
|
|
02110-1301, USA. */
|
|
|
|
#ifndef GENSFRAME_H
|
|
#define GENSFRAME_H
|
|
|
|
#define SFRAME_FRE_ELEM_LOC_REG 0
|
|
#define SFRAME_FRE_ELEM_LOC_STACK 1
|
|
|
|
/* SFrame Frame Row Entry (FRE).
|
|
|
|
A frame row entry is a slice of the frame and can be valid for a set of
|
|
program instructions. It keeps all information needed to retrieve the CFA
|
|
and the Return Address (RA) if tracked.
|
|
|
|
A frame row entry effectively stores accumulated information gathered by
|
|
interpreting multiple CFI instructions. More precisely, it is a
|
|
self-sufficient record in its own right. Only the subset of information
|
|
necessary for unwinding is stored: Given a PC, how to retrieve the CFA and
|
|
the RA.
|
|
*/
|
|
|
|
struct sframe_row_entry
|
|
{
|
|
/* A linked list. */
|
|
struct sframe_row_entry *next;
|
|
|
|
/* Start and end of the frame row entry. */
|
|
symbolS *pc_begin;
|
|
symbolS *pc_end;
|
|
|
|
/* A frame row entry is a merge candidate if new information can be updated
|
|
on it. */
|
|
bool merge_candidate;
|
|
|
|
/* Track CFA base (architectural) register ID. */
|
|
unsigned int cfa_base_reg;
|
|
/* Offset from the CFA base register for recovering CFA. */
|
|
offsetT cfa_offset;
|
|
|
|
/* Track the other register used as base register for CFA. Specify whether
|
|
it is in register or memory. */
|
|
unsigned int base_reg;
|
|
unsigned int bp_loc;
|
|
/* If the other register is stashed on stack, note the offset. */
|
|
offsetT bp_offset;
|
|
|
|
/* Track RA location. Specify whether it is in register or memory. */
|
|
unsigned int ra_loc;
|
|
/* If RA is stashed on stack, note the offset. */
|
|
offsetT ra_offset;
|
|
};
|
|
|
|
/* SFrame Function Description Entry. */
|
|
|
|
struct sframe_func_entry
|
|
{
|
|
/* A linked list. */
|
|
struct sframe_func_entry *next;
|
|
|
|
/* Reference to the FDE created from CFI in dw2gencfi. Some information
|
|
like the start_address and the segment is made available via this
|
|
member. */
|
|
const struct fde_entry *dw_fde;
|
|
|
|
/* Reference to the first FRE for this function. */
|
|
struct sframe_row_entry *sframe_fres;
|
|
|
|
unsigned int num_fres;
|
|
};
|
|
|
|
/* SFrame Function Description Entry Translation Context. */
|
|
|
|
struct sframe_xlate_ctx
|
|
{
|
|
/* Reference to the FDE created from CFI in dw2gencfi. Information
|
|
like the FDE start_address, end_address and the cfi insns are
|
|
made available via this member. */
|
|
const struct fde_entry *dw_fde;
|
|
|
|
/* List of FREs in the current FDE translation context, bounded by first_fre
|
|
and last_fre. */
|
|
|
|
/* Keep track of the first FRE for the purpose of restoring state if
|
|
necessary (for DW_CFA_restore). */
|
|
struct sframe_row_entry *first_fre;
|
|
/* The last FRE in the list. */
|
|
struct sframe_row_entry *last_fre;
|
|
|
|
/* The current FRE under construction. */
|
|
struct sframe_row_entry *cur_fre;
|
|
/* Remember FRE for an eventual restore. */
|
|
struct sframe_row_entry *remember_fre;
|
|
|
|
unsigned num_xlate_fres;
|
|
};
|
|
|
|
/* Error codes for SFrame translation context. */
|
|
enum sframe_xlate_err
|
|
{
|
|
/* Success. */
|
|
SFRAME_XLATE_OK = 0,
|
|
/* Error. */
|
|
SFRAME_XLATE_ERROR = 1,
|
|
/* Detailed error codes. */
|
|
SFRAME_XLATE_ERR_INVAL = -1,
|
|
SFRAME_XLATE_ERR_NOTREPRESENTED = -2,
|
|
};
|
|
|
|
/* Callback to create the abi/arch identifier for SFrame section. */
|
|
|
|
unsigned char
|
|
sframe_get_abi_arch_callback (const char *target_arch,
|
|
int big_endian_p);
|
|
|
|
/* The list of all FDEs with data in SFrame internal representation. */
|
|
|
|
extern struct sframe_func_entry *all_sframe_fdes;
|
|
|
|
/* SFrame version specific operations structure. */
|
|
|
|
struct sframe_version_ops
|
|
{
|
|
unsigned char format_version; /* SFrame format version. */
|
|
/* set SFrame FRE info. */
|
|
unsigned char (*set_fre_info) (unsigned int, unsigned int, unsigned int);
|
|
/* set SFrame Func info. */
|
|
unsigned char (*set_func_info) (unsigned int, unsigned int);
|
|
};
|
|
|
|
/* Generate SFrame unwind info and prepare contents for the output.
|
|
outout_sframe () is called at the end of file. */
|
|
|
|
extern void output_sframe (segT sframe_seg);
|
|
|
|
#endif /* GENSFRAME_H */
|