From: Indu Bhagat Date: Fri, 28 Nov 2025 19:50:14 +0000 (-0800) Subject: [SFrame-V3] sframe: gas: libsframe: use uint16_t for num_fres of FDE X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=e7825af0df880b84a6162957aec22bfc6519d38b;p=thirdparty%2Fbinutils-gdb.git [SFrame-V3] sframe: gas: libsframe: use uint16_t for num_fres of FDE Reduce the size of the num_fres field in the Function Descriptor Entry (FDE) from 32 bits to 16 bits. The number of Frame Row Entries (FREs) for a single function is extremely unlikely to exceed 65,535 in real-world scenarios. Reducing this field saves 2 bytes per FDE, contributing to a smaller overall SFrame section size. (BTW, these savings will be eaten up by a later commit which adds support for text > 2 GiB by increasing an offset from int32_t to int64_t). Safety checks are added to the assembler to warn and skip SFrame FDE generation if a function's FRE count exceeds UINT16_MAX. include/ * sframe.h (sframe_func_desc_entry_v3): Change sfde_func_num_fres type to uint16_t. gas/ * gen-sframe.c (output_sframe_funcdesc): Write 2 bytes for num_fres and assert it fits in uint16_t. (sframe_do_fde): Add check to skip FDE emission if num_fres exceeds UINT16_MAX. libsframe/ * sframe.c (sframe_fde_tbl_init): Cast num_fres to uint16_t. (sframe_decode_fde): Likewise. (sframe_encoder_write_fde): Likewise. * testsuite/libsframe.decode/DATA2: Update binary test data. --- diff --git a/gas/gen-sframe.c b/gas/gen-sframe.c index 46e5fa2c92a..56c0c95c940 100644 --- a/gas/gen-sframe.c +++ b/gas/gen-sframe.c @@ -724,8 +724,9 @@ output_sframe_funcdesc (symbolS *start_of_fre_section, sfde_func_start_fre_off)); } - /* Number of FREs. */ - out_four (sframe_fde->num_fres); + /* Number of FREs must fit uint16_t. */ + gas_assert (sframe_fde->num_fres <= UINT16_MAX); + out_two (sframe_fde->num_fres); /* SFrame FDE function info. */ unsigned char func_info; @@ -2032,6 +2033,20 @@ sframe_do_fde (struct sframe_xlate_ctx *xlate_ctx, = get_dw_fde_end_addrS (xlate_ctx->dw_fde); } + /* Number of FREs must fit uint16_t. Check now, and do not emit the SFrame + FDE if it doesnt fit (although, it is not expected to happen for + real-world, useful programs). The approach of truncating the FDE and + emitting multiple SFrame FDEs instead, is not a clearly preferable + handling either. Its a divergence from the model where an SFrame FDE + encodes stack trace data between a .cfi_startproc and .cfi_endproc pair. + Further, some components (linkers, stack tracers) want to associate the + Start PC of a function to a known symbol in the file? */ + if (xlate_ctx->num_xlate_fres > UINT16_MAX) + { + as_warn (_("no SFrame FDE emitted; Number of FREs exceeds UINT16_MAX")); + return SFRAME_XLATE_ERR_NOTREPRESENTED; + } + /* ABI/arch except s390x cannot represent FP without RA saved. */ if (sframe_ra_tracking_p () && sframe_get_abi_arch () != SFRAME_ABI_S390X_ENDIAN_BIG) diff --git a/include/sframe.h b/include/sframe.h index 8d08aefcc04..50dee8ebb96 100644 --- a/include/sframe.h +++ b/include/sframe.h @@ -251,7 +251,7 @@ typedef struct sframe_func_desc_entry_v3 beginning of the SFrame Frame Row Entry sub-section. */ uint32_t sfde_func_start_fre_off; /* Number of frame row entries for the function. */ - uint32_t sfde_func_num_fres; + uint16_t sfde_func_num_fres; /* Additional information for stack tracing from the function: - 4-bits: Identify the FRE type used for the function. - 1-bit: Identify the FDE type of the function - mask or inc. diff --git a/libsframe/sframe.c b/libsframe/sframe.c index afa8923b733..b0da92afb6b 100644 --- a/libsframe/sframe.c +++ b/libsframe/sframe.c @@ -151,7 +151,7 @@ sframe_fde_tbl_init (sf_fde_tbl *fde_tbl, const char *fde_buf, fde_tbl->entry[i].func_start_addr = fdep->sfde_func_start_address; fde_tbl->entry[i].func_size = fdep->sfde_func_size; fde_tbl->entry[i].func_start_fre_off = fdep->sfde_func_start_fre_off; - fde_tbl->entry[i].func_num_fres = fdep->sfde_func_num_fres; + fde_tbl->entry[i].func_num_fres = (uint16_t)fdep->sfde_func_num_fres; fde_tbl->entry[i].func_info = fdep->sfde_func_info; fde_tbl->entry[i].func_rep_size = fdep->sfde_func_rep_size; } @@ -576,7 +576,7 @@ sframe_decode_fde (const char *buf, size_t buf_size, uint8_t ver, return SFRAME_ERR; sframe_func_desc_entry_v3 *fdep = (sframe_func_desc_entry_v3 *) buf; - *num_fres = fdep->sfde_func_num_fres; + *num_fres = (uint16_t)fdep->sfde_func_num_fres; *fre_type = SFRAME_V1_FUNC_FRE_TYPE (fdep->sfde_func_info); *fre_offset = fdep->sfde_func_start_fre_off; @@ -2131,7 +2131,7 @@ sframe_encoder_write_fde (const sframe_header *sfhp ATTRIBUTE_UNUSED, fdep->sfde_func_start_address = (int32_t)fde->func_start_addr; fdep->sfde_func_size = fde->func_size; fdep->sfde_func_start_fre_off = fde->func_start_fre_off; - fdep->sfde_func_num_fres = fde->func_num_fres; + fdep->sfde_func_num_fres = (uint16_t)fde->func_num_fres; fdep->sfde_func_info = fde->func_info; fdep->sfde_func_rep_size = fde->func_rep_size; fdep->sfde_func_padding2 = 0; diff --git a/libsframe/testsuite/libsframe.decode/DATA2 b/libsframe/testsuite/libsframe.decode/DATA2 index aa62398b2ca..7a218f86bcc 100644 Binary files a/libsframe/testsuite/libsframe.decode/DATA2 and b/libsframe/testsuite/libsframe.decode/DATA2 differ