mirror of
https://sourceware.org/git/binutils-gdb.git
synced 2024-12-09 04:21:49 +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.
211 lines
5.5 KiB
C
211 lines
5.5 KiB
C
/* dw2gencfi.h - Support for generating Dwarf2 CFI information.
|
|
Copyright (C) 2003-2022 Free Software Foundation, Inc.
|
|
Contributed by Michal Ludvig <mludvig@suse.cz>
|
|
|
|
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 DW2GENCFI_H
|
|
#define DW2GENCFI_H
|
|
|
|
#include "dwarf2.h"
|
|
|
|
struct symbol;
|
|
|
|
extern const pseudo_typeS cfi_pseudo_table[];
|
|
|
|
/* cfi_finish() is called at the end of file. It will complain if
|
|
the last CFI wasn't properly closed by .cfi_endproc. */
|
|
extern void cfi_finish (void);
|
|
|
|
/* Entry points for backends to add unwind information. */
|
|
extern void cfi_new_fde (struct symbol *);
|
|
extern void cfi_end_fde (struct symbol *);
|
|
extern void cfi_set_return_column (unsigned);
|
|
extern void cfi_set_sections (void);
|
|
extern void cfi_add_advance_loc (struct symbol *);
|
|
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_offset (offsetT);
|
|
extern void cfi_add_CFA_restore (unsigned);
|
|
extern void cfi_add_CFA_undefined (unsigned);
|
|
extern void cfi_add_CFA_same_value (unsigned);
|
|
extern void cfi_add_CFA_remember_state (void);
|
|
extern void cfi_add_CFA_restore_state (void);
|
|
|
|
/* Structures for md_cfi_end. */
|
|
|
|
#if defined (TE_PE) || defined (TE_PEP)
|
|
#define SUPPORT_FRAME_LINKONCE 1
|
|
#else
|
|
#define SUPPORT_FRAME_LINKONCE 0
|
|
#endif
|
|
|
|
#ifdef tc_cfi_reloc_for_encoding
|
|
#define SUPPORT_COMPACT_EH 1
|
|
#else
|
|
#define SUPPORT_COMPACT_EH 0
|
|
#endif
|
|
|
|
#ifndef TARGET_MULTIPLE_EH_FRAME_SECTIONS
|
|
#define TARGET_MULTIPLE_EH_FRAME_SECTIONS 0
|
|
#endif
|
|
|
|
#define MULTIPLE_FRAME_SECTIONS (SUPPORT_FRAME_LINKONCE || SUPPORT_COMPACT_EH \
|
|
|| TARGET_MULTIPLE_EH_FRAME_SECTIONS)
|
|
|
|
struct cfi_insn_data
|
|
{
|
|
struct cfi_insn_data *next;
|
|
#if MULTIPLE_FRAME_SECTIONS
|
|
segT cur_seg;
|
|
#endif
|
|
int insn;
|
|
union
|
|
{
|
|
struct
|
|
{
|
|
unsigned reg;
|
|
offsetT offset;
|
|
} ri;
|
|
|
|
struct
|
|
{
|
|
unsigned reg1;
|
|
unsigned reg2;
|
|
} rr;
|
|
|
|
unsigned r;
|
|
offsetT i;
|
|
|
|
struct
|
|
{
|
|
symbolS *lab1;
|
|
symbolS *lab2;
|
|
} ll;
|
|
|
|
struct cfi_escape_data *esc;
|
|
|
|
struct
|
|
{
|
|
unsigned reg, encoding;
|
|
expressionS exp;
|
|
} ea;
|
|
|
|
const char *sym_name;
|
|
} u;
|
|
};
|
|
|
|
/* An enumeration describing the Compact EH header format. The least
|
|
significant bit is used to distinguish the entries.
|
|
|
|
Inline Compact: Function offset [0]
|
|
Four chars of unwind data.
|
|
Out-of-line Compact: Function offset [1]
|
|
Compact unwind data offset [0]
|
|
Legacy: Function offset [1]
|
|
Unwind data offset [1]
|
|
|
|
The header type is initialized to EH_COMPACT_UNKNOWN until the
|
|
format is discovered by encountering a .fde_data entry.
|
|
Failure to find a .fde_data entry will cause an EH_COMPACT_LEGACY
|
|
header to be generated. */
|
|
|
|
enum {
|
|
EH_COMPACT_UNKNOWN,
|
|
EH_COMPACT_LEGACY,
|
|
EH_COMPACT_INLINE,
|
|
EH_COMPACT_OUTLINE,
|
|
EH_COMPACT_OUTLINE_DONE,
|
|
/* Outline if .cfi_inline_lsda used, otherwise legacy FDE. */
|
|
EH_COMPACT_HAS_LSDA
|
|
};
|
|
|
|
/* Stack of old CFI data, for save/restore. */
|
|
struct cfa_save_data
|
|
{
|
|
struct cfa_save_data *next;
|
|
offsetT cfa_offset;
|
|
};
|
|
|
|
/* Current open FDE entry. */
|
|
struct frch_cfi_data
|
|
{
|
|
struct fde_entry *cur_fde_data;
|
|
symbolS *last_address;
|
|
offsetT cur_cfa_offset;
|
|
struct cfa_save_data *cfa_save_stack;
|
|
};
|
|
|
|
struct fde_entry
|
|
{
|
|
struct fde_entry *next;
|
|
#if MULTIPLE_FRAME_SECTIONS
|
|
segT cur_seg;
|
|
#endif
|
|
symbolS *start_address;
|
|
symbolS *end_address;
|
|
struct cfi_insn_data *data;
|
|
struct cfi_insn_data **last;
|
|
unsigned char per_encoding;
|
|
unsigned char lsda_encoding;
|
|
int personality_id;
|
|
expressionS personality;
|
|
expressionS lsda;
|
|
unsigned int return_column;
|
|
unsigned int signal_frame;
|
|
#if MULTIPLE_FRAME_SECTIONS
|
|
int handled;
|
|
#endif
|
|
int eh_header_type;
|
|
/* Compact unwinding opcodes, not including the PR byte or LSDA. */
|
|
int eh_data_size;
|
|
bfd_byte *eh_data;
|
|
/* For out of line tables and FDEs. */
|
|
symbolS *eh_loc;
|
|
int sections;
|
|
#ifdef tc_fde_entry_extras
|
|
tc_fde_entry_extras
|
|
#endif
|
|
};
|
|
|
|
/* The list of all FDEs that have been collected. */
|
|
extern struct fde_entry *all_fde_data;
|
|
|
|
/* Fake CFI type; outside the byte range of any real CFI insn. */
|
|
#define CFI_adjust_cfa_offset 0x100
|
|
#define CFI_return_column 0x101
|
|
#define CFI_rel_offset 0x102
|
|
#define CFI_escape 0x103
|
|
#define CFI_signal_frame 0x104
|
|
#define CFI_val_encoded_addr 0x105
|
|
#define CFI_label 0x106
|
|
|
|
/* By default emit .eh_frame only, not .debug_frame. */
|
|
#define CFI_EMIT_eh_frame (1 << 0)
|
|
#define CFI_EMIT_debug_frame (1 << 1)
|
|
#define CFI_EMIT_target (1 << 2)
|
|
#define CFI_EMIT_eh_frame_compact (1 << 3)
|
|
#define CFI_EMIT_sframe (1 << 4)
|
|
|
|
#endif /* DW2GENCFI_H */
|