mirror of
https://github.com/bminor/binutils-gdb.git
synced 2025-11-16 12:34:43 +00:00
In DWARF CFI an "undefined" register rule for the return address (RA) register indicates that there is no return address and the stack trace is complete. Represent DW_CFA_undefined as SFrame FRE without any offsets, so that a stack tracer implementation can use this as indication that an outermost frame has been reached and the stack trace is complete. This representation is backward compatible, as existing stack tracers should already deal with the case, that an SFrame FRE a so far invalid offset count of zero and stop the trace. include/ * sframe.h (SFRAME_V2_FRE_RA_UNDEFINED_P): New macro to test FRE info word for RA undefined (FRE without any offsets). binutils/ * NEWS: Mention SFrame can represent an undefined RA as FRE without any offsets. gas/ * gen-sframe.h (struct sframe_row_entry): Add ra_undefined_p flag. * gen-sframe.c (sframe_row_entry_new): Initialize ra_undefined_p flag to not set. (sframe_row_entry_initialize): Treat ra_undefined_p flag as sticky. (sframe_fre_set_ra_track): Reset ra_undefined_p flag. (sframe_xlate_do_restore): Reset ra_undefined_p flag to saved state. (sframe_xlate_do_same_value): Reset ra_undefined_p flag. (sframe_xlate_do_cfi_undefined): For RA set ra_undefined_p flag. (output_sframe_row_entry): Represent RA undefined as SFrame FRE without any offsets and FRE info word fields zeroed. * NEWS: Mention assembler represents .cfi_undefined RA in SFrame as FRE without any offsets. libsframe/ * doc/sframe-spec.texi (Changes from Version 1 to Version 2): Mention that a SFrame FRE without any offsets flag indicates an outermost frame with an undefined RA. (fre_offset_count): Document that a FRE offset count of zero indicates an outermost frame with an undefined RA. * sframe.c (sframe_get_fre_ra_undefined_p): Use macro SFRAME_V2_FRE_RA_UNDEFINED_P. (sframe_fre_get_fp_offset, sframe_fre_get_ra_offset): Do not return fixed FP/RA offset if RA undefined. * sframe-dump.c (dump_sframe_func_with_fres): Show FRE without any offsets as "RA undefined". gas/testsuite/ * gas/cfi-sframe/cfi-sframe.exp: Run tests for .cfi_undefined RA on AArch64, s390x, and x86-64. * gas/cfi-sframe/cfi-sframe-aarch64-ra-undefined-1.d: Add test for .cfi_undefined RA on AArch64. * gas/cfi-sframe/cfi-sframe-aarch64-ra-undefined-1.s: Likewise. * as/cfi-sframe/cfi-sframe-s390x-ra-undefined-1.d: Add test for .cfi_undefined RA on s390x. * gas/cfi-sframe/cfi-sframe-s390x-ra-undefined-1.s: Likewise. * gas/cfi-sframe/cfi-sframe-x86_64-ra-undefined-1.d: Add test for .cfi_undefined RA on x86-64. * gas/cfi-sframe/cfi-sframe-x86_64-ra-undefined-1.s: Likewise. Signed-off-by: Jens Remus <jremus@linux.ibm.com>
169 lines
5.2 KiB
C
169 lines
5.2 KiB
C
/* gen-sframe.h - Support for generating SFrame.
|
|
Copyright (C) 2022-2025 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
|
|
|
|
/* Errors shouldn't be emitted either if SFrames are default-enabled, as
|
|
we interpret default-enabled as "opportunistic SFrames". Users don't
|
|
want to be bothered by something preventing emission of SFrames in
|
|
such a case. */
|
|
#define sframe_as_bad(format, ...) \
|
|
do { \
|
|
if (flag_gen_sframe == GEN_SFRAME_ENABLED) \
|
|
as_bad (format, ##__VA_ARGS__); \
|
|
} while (0)
|
|
|
|
#define SFRAME_FRE_ELEM_LOC_REG 0
|
|
#define SFRAME_FRE_ELEM_LOC_STACK 1
|
|
|
|
#define SFRAME_FRE_BASE_REG_INVAL ((unsigned int)-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;
|
|
|
|
/* Whether the return address is mangled with pauth code. */
|
|
bool mangled_ra_p;
|
|
|
|
/* Whether RA is undefined. */
|
|
bool ra_undefined_p;
|
|
|
|
/* 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);
|
|
|
|
/* 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,
|
|
bool);
|
|
/* set SFrame Func info. */
|
|
unsigned char (*set_func_info) (unsigned int, unsigned int, unsigned int);
|
|
};
|
|
|
|
/* Generate SFrame stack trace 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 */
|