diff options
Diffstat (limited to 'libsframe')
-rw-r--r-- | libsframe/Makefile.in | 42 | ||||
-rw-r--r-- | libsframe/doc/sframe-spec.texi | 123 | ||||
-rw-r--r-- | libsframe/libsframe.ver | 14 | ||||
-rw-r--r-- | libsframe/libtool-version | 2 | ||||
-rw-r--r-- | libsframe/sframe-dump.c | 28 | ||||
-rw-r--r-- | libsframe/sframe.c | 49 | ||||
-rw-r--r-- | libsframe/testsuite/libsframe.find/find.exp | 5 | ||||
-rw-r--r-- | libsframe/testsuite/libsframe.find/local.mk | 5 | ||||
-rw-r--r-- | libsframe/testsuite/libsframe.find/plt-findfre-2.c | 201 |
9 files changed, 422 insertions, 47 deletions
diff --git a/libsframe/Makefile.in b/libsframe/Makefile.in index 13f4c26..fa705dd 100644 --- a/libsframe/Makefile.in +++ b/libsframe/Makefile.in @@ -118,7 +118,8 @@ check_PROGRAMS = $(am__EXEEXT_1) @HAVE_COMPAT_DEJAGNU_TRUE@ testsuite/libsframe.encode/encode-1 \ @HAVE_COMPAT_DEJAGNU_TRUE@ testsuite/libsframe.find/findfre-1 \ @HAVE_COMPAT_DEJAGNU_TRUE@ testsuite/libsframe.find/findfunc-1 \ -@HAVE_COMPAT_DEJAGNU_TRUE@ testsuite/libsframe.find/plt-findfre-1 +@HAVE_COMPAT_DEJAGNU_TRUE@ testsuite/libsframe.find/plt-findfre-1 \ +@HAVE_COMPAT_DEJAGNU_TRUE@ testsuite/libsframe.find/plt-findfre-2 subdir = . ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/../bfd/acinclude.m4 \ @@ -193,7 +194,8 @@ libsframe_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ @HAVE_COMPAT_DEJAGNU_TRUE@ testsuite/libsframe.encode/encode-1$(EXEEXT) \ @HAVE_COMPAT_DEJAGNU_TRUE@ testsuite/libsframe.find/findfre-1$(EXEEXT) \ @HAVE_COMPAT_DEJAGNU_TRUE@ testsuite/libsframe.find/findfunc-1$(EXEEXT) \ -@HAVE_COMPAT_DEJAGNU_TRUE@ testsuite/libsframe.find/plt-findfre-1$(EXEEXT) +@HAVE_COMPAT_DEJAGNU_TRUE@ testsuite/libsframe.find/plt-findfre-1$(EXEEXT) \ +@HAVE_COMPAT_DEJAGNU_TRUE@ testsuite/libsframe.find/plt-findfre-2$(EXEEXT) am__dirstamp = $(am__leading_dot)dirstamp am_testsuite_libsframe_decode_be_flipping_OBJECTS = testsuite/libsframe.decode/testsuite_libsframe_decode_be_flipping-be-flipping.$(OBJEXT) testsuite_libsframe_decode_be_flipping_OBJECTS = \ @@ -230,6 +232,11 @@ testsuite_libsframe_find_plt_findfre_1_OBJECTS = \ $(am_testsuite_libsframe_find_plt_findfre_1_OBJECTS) testsuite_libsframe_find_plt_findfre_1_DEPENDENCIES = \ ${top_builddir}/libsframe.la +am_testsuite_libsframe_find_plt_findfre_2_OBJECTS = testsuite/libsframe.find/testsuite_libsframe_find_plt_findfre_2-plt-findfre-2.$(OBJEXT) +testsuite_libsframe_find_plt_findfre_2_OBJECTS = \ + $(am_testsuite_libsframe_find_plt_findfre_2_OBJECTS) +testsuite_libsframe_find_plt_findfre_2_DEPENDENCIES = \ + ${top_builddir}/libsframe.la AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false @@ -271,7 +278,8 @@ SOURCES = $(libsframe_la_SOURCES) \ $(testsuite_libsframe_encode_encode_1_SOURCES) \ $(testsuite_libsframe_find_findfre_1_SOURCES) \ $(testsuite_libsframe_find_findfunc_1_SOURCES) \ - $(testsuite_libsframe_find_plt_findfre_1_SOURCES) + $(testsuite_libsframe_find_plt_findfre_1_SOURCES) \ + $(testsuite_libsframe_find_plt_findfre_2_SOURCES) DIST_SOURCES = $(libsframe_la_SOURCES) \ $(testsuite_libsframe_decode_be_flipping_SOURCES) \ $(testsuite_libsframe_decode_frecnt_1_SOURCES) \ @@ -279,7 +287,8 @@ DIST_SOURCES = $(libsframe_la_SOURCES) \ $(testsuite_libsframe_encode_encode_1_SOURCES) \ $(testsuite_libsframe_find_findfre_1_SOURCES) \ $(testsuite_libsframe_find_findfunc_1_SOURCES) \ - $(testsuite_libsframe_find_plt_findfre_1_SOURCES) + $(testsuite_libsframe_find_plt_findfre_1_SOURCES) \ + $(testsuite_libsframe_find_plt_findfre_2_SOURCES) AM_V_DVIPS = $(am__v_DVIPS_@AM_V@) am__v_DVIPS_ = $(am__v_DVIPS_@AM_DEFAULT_V@) am__v_DVIPS_0 = @echo " DVIPS " $@; @@ -569,6 +578,9 @@ testsuite_libsframe_find_findfunc_1_CPPFLAGS = -I${top_srcdir}/../include -Wall testsuite_libsframe_find_plt_findfre_1_SOURCES = testsuite/libsframe.find/plt-findfre-1.c testsuite_libsframe_find_plt_findfre_1_LDADD = ${top_builddir}/libsframe.la testsuite_libsframe_find_plt_findfre_1_CPPFLAGS = -I${top_srcdir}/../include -Wall +testsuite_libsframe_find_plt_findfre_2_SOURCES = testsuite/libsframe.find/plt-findfre-2.c +testsuite_libsframe_find_plt_findfre_2_LDADD = ${top_builddir}/libsframe.la +testsuite_libsframe_find_plt_findfre_2_CPPFLAGS = -I${top_srcdir}/../include -Wall all: config.h $(MAKE) $(AM_MAKEFLAGS) all-am @@ -748,6 +760,13 @@ testsuite/libsframe.find/testsuite_libsframe_find_plt_findfre_1-plt-findfre-1.$( testsuite/libsframe.find/plt-findfre-1$(EXEEXT): $(testsuite_libsframe_find_plt_findfre_1_OBJECTS) $(testsuite_libsframe_find_plt_findfre_1_DEPENDENCIES) $(EXTRA_testsuite_libsframe_find_plt_findfre_1_DEPENDENCIES) testsuite/libsframe.find/$(am__dirstamp) @rm -f testsuite/libsframe.find/plt-findfre-1$(EXEEXT) $(AM_V_CCLD)$(LINK) $(testsuite_libsframe_find_plt_findfre_1_OBJECTS) $(testsuite_libsframe_find_plt_findfre_1_LDADD) $(LIBS) +testsuite/libsframe.find/testsuite_libsframe_find_plt_findfre_2-plt-findfre-2.$(OBJEXT): \ + testsuite/libsframe.find/$(am__dirstamp) \ + testsuite/libsframe.find/$(DEPDIR)/$(am__dirstamp) + +testsuite/libsframe.find/plt-findfre-2$(EXEEXT): $(testsuite_libsframe_find_plt_findfre_2_OBJECTS) $(testsuite_libsframe_find_plt_findfre_2_DEPENDENCIES) $(EXTRA_testsuite_libsframe_find_plt_findfre_2_DEPENDENCIES) testsuite/libsframe.find/$(am__dirstamp) + @rm -f testsuite/libsframe.find/plt-findfre-2$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(testsuite_libsframe_find_plt_findfre_2_OBJECTS) $(testsuite_libsframe_find_plt_findfre_2_LDADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) @@ -768,6 +787,7 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@testsuite/libsframe.find/$(DEPDIR)/testsuite_libsframe_find_findfre_1-findfre-1.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@testsuite/libsframe.find/$(DEPDIR)/testsuite_libsframe_find_findfunc_1-findfunc-1.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@testsuite/libsframe.find/$(DEPDIR)/testsuite_libsframe_find_plt_findfre_1-plt-findfre-1.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@testsuite/libsframe.find/$(DEPDIR)/testsuite_libsframe_find_plt_findfre_2-plt-findfre-2.Po@am__quote@ .c.o: @am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\ @@ -912,6 +932,20 @@ testsuite/libsframe.find/testsuite_libsframe_find_plt_findfre_1-plt-findfre-1.ob @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(testsuite_libsframe_find_plt_findfre_1_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o testsuite/libsframe.find/testsuite_libsframe_find_plt_findfre_1-plt-findfre-1.obj `if test -f 'testsuite/libsframe.find/plt-findfre-1.c'; then $(CYGPATH_W) 'testsuite/libsframe.find/plt-findfre-1.c'; else $(CYGPATH_W) '$(srcdir)/testsuite/libsframe.find/plt-findfre-1.c'; fi` +testsuite/libsframe.find/testsuite_libsframe_find_plt_findfre_2-plt-findfre-2.o: testsuite/libsframe.find/plt-findfre-2.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(testsuite_libsframe_find_plt_findfre_2_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT testsuite/libsframe.find/testsuite_libsframe_find_plt_findfre_2-plt-findfre-2.o -MD -MP -MF testsuite/libsframe.find/$(DEPDIR)/testsuite_libsframe_find_plt_findfre_2-plt-findfre-2.Tpo -c -o testsuite/libsframe.find/testsuite_libsframe_find_plt_findfre_2-plt-findfre-2.o `test -f 'testsuite/libsframe.find/plt-findfre-2.c' || echo '$(srcdir)/'`testsuite/libsframe.find/plt-findfre-2.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) testsuite/libsframe.find/$(DEPDIR)/testsuite_libsframe_find_plt_findfre_2-plt-findfre-2.Tpo testsuite/libsframe.find/$(DEPDIR)/testsuite_libsframe_find_plt_findfre_2-plt-findfre-2.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='testsuite/libsframe.find/plt-findfre-2.c' object='testsuite/libsframe.find/testsuite_libsframe_find_plt_findfre_2-plt-findfre-2.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(testsuite_libsframe_find_plt_findfre_2_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o testsuite/libsframe.find/testsuite_libsframe_find_plt_findfre_2-plt-findfre-2.o `test -f 'testsuite/libsframe.find/plt-findfre-2.c' || echo '$(srcdir)/'`testsuite/libsframe.find/plt-findfre-2.c + +testsuite/libsframe.find/testsuite_libsframe_find_plt_findfre_2-plt-findfre-2.obj: testsuite/libsframe.find/plt-findfre-2.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(testsuite_libsframe_find_plt_findfre_2_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT testsuite/libsframe.find/testsuite_libsframe_find_plt_findfre_2-plt-findfre-2.obj -MD -MP -MF testsuite/libsframe.find/$(DEPDIR)/testsuite_libsframe_find_plt_findfre_2-plt-findfre-2.Tpo -c -o testsuite/libsframe.find/testsuite_libsframe_find_plt_findfre_2-plt-findfre-2.obj `if test -f 'testsuite/libsframe.find/plt-findfre-2.c'; then $(CYGPATH_W) 'testsuite/libsframe.find/plt-findfre-2.c'; else $(CYGPATH_W) '$(srcdir)/testsuite/libsframe.find/plt-findfre-2.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) testsuite/libsframe.find/$(DEPDIR)/testsuite_libsframe_find_plt_findfre_2-plt-findfre-2.Tpo testsuite/libsframe.find/$(DEPDIR)/testsuite_libsframe_find_plt_findfre_2-plt-findfre-2.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='testsuite/libsframe.find/plt-findfre-2.c' object='testsuite/libsframe.find/testsuite_libsframe_find_plt_findfre_2-plt-findfre-2.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(testsuite_libsframe_find_plt_findfre_2_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o testsuite/libsframe.find/testsuite_libsframe_find_plt_findfre_2-plt-findfre-2.obj `if test -f 'testsuite/libsframe.find/plt-findfre-2.c'; then $(CYGPATH_W) 'testsuite/libsframe.find/plt-findfre-2.c'; else $(CYGPATH_W) '$(srcdir)/testsuite/libsframe.find/plt-findfre-2.c'; fi` + mostlyclean-libtool: -rm -f *.lo diff --git a/libsframe/doc/sframe-spec.texi b/libsframe/doc/sframe-spec.texi index 69fe873..7307789 100644 --- a/libsframe/doc/sframe-spec.texi +++ b/libsframe/doc/sframe-spec.texi @@ -77,12 +77,13 @@ Appendices @section Overview @cindex Overview -The SFrame stack trace information is provided in a loaded section, known as the -@code{.sframe} section. When available, the @code{.sframe} section appears in -a new segment of its own, PT_GNU_SFRAME. +The SFrame stack trace information is provided in a loaded section, known as +the @code{.sframe} section. When available, the @code{.sframe} section appears +in segment of type PT_GNU_SFRAME. An ELF SFrame section will have the type +SHT_GNU_SFRAME. -The SFrame format is currently supported only for select ABIs, namely, AMD64 -and AAPCS64. +The SFrame format is currently supported only for select ABIs, namely, AMD64, +AAPCS64, and s390x. A portion of the SFrame format follows an unaligned on-disk representation. Some data structures, however, (namely the SFrame header and the SFrame @@ -139,6 +140,31 @@ bytes to the start PC of the associated function from the field itself. bytes to the start PC of the associated function from the start of the SFrame section. @end itemize +@item +Add a new ABI/arch identifier SFRAME_ABI_S390X_ENDIAN_BIG for the s390 +architecture (64-bit) s390x ABI. Other s390x-specific backward compatible +changes including the following helper definitions have been incrementally +added to SFrame version 2 only: + @itemize @minus + @item SFRAME_S390X_SP_VAL_OFFSET: SP value offset from CFA. + @item SFRAME_V2_S390X_OFFSET_IS_REGNUM: Test whether FP/RA offset is an encoded +DWARF register number. + @item SFRAME_V2_S390X_OFFSET_ENCODE_REGNUM: Encode a DWARF register number as an +FP/RA offset. + @item SFRAME_V2_S390X_OFFSET_DECODE_REGNUM: Decode a DWARF register number from +an FP/RA offset. + @item SFRAME_FRE_RA_OFFSET_INVALID: Invalid RA offset value (like +SFRAME_CFA_FIXED_RA_INVALID). Used on s390x as padding offset to represent +FP without RA saved. + @item SFRAME_S390X_CFA_OFFSET_ADJUSTMENT: CFA offset (from CFA base register) +adjustment value. Used to enable use of 8-bit SFrame offsets on s390x. + @item SFRAME_S390X_CFA_OFFSET_ALIGNMENT_FACTOR: CFA offset alignment factor. +Used to scale down the CFA offset to improve the use of 8-bit SFrame offsets. + @item SFRAME_V2_S390X_CFA_OFFSET_ENCODE: Encode CFA offset (i.e., apply +CFA offset adjustment and then scale down by CFA offset alignment factor). + @item SFRAME_V2_S390X_CFA_OFFSET_DECODE: Decode CFA offset (i.e., scale up +by CFA offset alignment factor and then revert CFA offset adjustment). + @end itemize @end itemize SFrame version 1 is now obsolete and should not be used. @@ -421,6 +447,10 @@ in the format. @item @code{SFRAME_ABI_AMD64_ENDIAN_LITTLE} @tab 3 @tab AMD64 little-endian +@tindex SFRAME_ABI_S390X_ENDIAN_BIG +@item @code{SFRAME_ABI_S390X_ENDIAN_BIG} +@tab 4 @tab s390x big-endian + @end multitable The presence of an explicit identification of ABI/arch in SFrame may allow @@ -780,10 +810,11 @@ This section covers the ABI/arch-specific definition of the SFrame file format. Currently, the only part of the SFrame file format definition that is ABI/arch-specific is the interpretation of the variable number of bytes at the -tail end of each SFrame FRE. Currently, these bytes are only used for -representing stack offsets (for all the currently supported ABIs). It is -recommended to peruse this section along with @xref{SFrame Frame Row Entries} -for clarity of context. +tail end of each SFrame FRE. Currently, these bytes are used for representing +stack offsets (for AMD64 and AARCH64 ABIs). For s390x ABI, the interpretation +of these bytes may be stack offsets or even register numbers. It is recommended +to peruse this section along with @xref{SFrame Frame Row Entries} for clarity of +context. Future ABIs must specify the algorithm for identifying the appropriate SFrame FRE stack offsets in this chapter. This should inevitably include the @@ -794,6 +825,7 @@ auxiliary SFrame header, etc., if used, must also be outlined here. @menu * AMD64:: * AArch64:: +* s390x:: @end menu @node AMD64 @@ -850,6 +882,77 @@ Hence, in summary: @item 3 @tab FP = CFA + offset3 @end multitable +@node s390x +@section s390x + +A stack tracer implementation must initialize the SP to the designated SP +register value, the FP to the preferred FP register value, and the RA to the +designated RA register value in the topmost stack frame of the callchain. This +is required, as either the SP or FP is used as CFA base register and as the FP +and/or RA are not necessarily saved on the stack. For RA this may only be the +case in the topmost stack frame of the callchain. For FP this may be the case +in any stack frame. + +Irrespective of the ABI, the first stack offset is always used to locate the +CFA. On s390x the value of the offset is stored adjusted by the s390x-specific +@code{SFRAME_S390X_CFA_OFFSET_ADJUSTMENT} and scaled down by the s390x-specific +@code{SFRAME_S390X_CFA_OFFSET_ALIGNMENT_FACTOR}, to enable and improve the use +of signed 8-bit offsets on s390x. +s390x-specific helpers @code{SFRAME_V2_S390X_CFA_OFFSET_ENCODE} and +@code{SFRAME_V2_S390X_CFA_OFFSET_DECODE} are provided to perform or undo +the adjustment and scaling. The CFA offset can therefore be interpreted as: +CFA = @code{BASE_REG} + offset1 - @code{SFRAME_S390X_CFA_OFFSET_ADJUSTMENT} +or +CFA = @code{BASE_REG} + + (offset1 * @code{SFRAME_S390X_CFA_OFFSET_ALIGNMENT_FACTOR}) + - @code{SFRAME_S390X_CFA_OFFSET_ADJUSTMENT}. +The identification of the @code{BASE_REG} is done by using the +@code{fre_cfa_base_reg_id} field in the SFrame FRE info word. + +The (64-bit) s390x ELF ABI does not mandate the precise location in a function +where the return address (RA) and frame pointer (FP) are saved, if at all. +Hence the need to track RA in the SFrame stack trace format. As RA is being +tracked in this ABI, the second stack offset is always used to locate the RA +stack slot, by interpreting it as: RA = CFA + offset2, unless the offset has a +value of @code{SFRAME_FRE_RA_OFFSET_INVALID}. RA remains unchanged, if the +offset is not available or has a value of @code{SFRAME_FRE_RA_OFFSET_INVALID}. +Stack tracers are recommended to validate that the "unchanged RA" pattern, when +present, is seen only for the topmost stack frame. The third stack offset is +used to locate the FP stack slot, by interpreting it as: FP = CFA + offset3. +FP remains unchanged, if the offset is not available. + +In leaf functions the RA and FP may be saved in other registers, such as +floating-point registers (FPRs), instead of on the stack. To represent this +in the SFrame stack trace format the DWARF register number is encoded as +RA/FP offset using the least-significant bit (LSB) as indication: +offset = (regnum << 1) | 1. A LSB of zero indicates a stack slot offset. +A LSB of one indicates a DWARF register number, which is interpreted as: +regnum = offset >> 1. Given the nature of leaf functions, this can only occur +in the topmost frame during stack tracing. It is recommended that a stack +tracer implementation performs the required checks to ensure that restoring +FP and RA from the said register locations is done only for topmost stack +frame in the callchain. + +Given the nature of things, the number of stack offsets and/or register numbers +seen on s390x per SFrame FRE is either 1, 2, or 3. + +Hence, in summary: + +@multitable @columnfractions .15 .85 +@headitem Offset ID @tab Interpretation in s390x +@item 1 @tab CFA = @code{BASE_REG} + offset1 +@item 2 @tab RA stack slot = CFA + offset2, if (offset2 & 1 == 0) + @*RA register number = offset2 >> 1, if (offset2 & 1 == 1) + @*RA not saved if (offset2 == @code{SFRAME_FRE_RA_OFFSET_INVALID}) +@item 3 @tab FP stack slot = CFA + offset3, if (offset3 & 1 == 0) + @*FP register number = offset3 >> 1, if (offset3 & 1 == 1) +@end multitable + +The s390x ELF ABI defines the CFA as stack pointer (SP) at call site +160. The +SP can therefore be obtained using the SP value offset from CFA +@code{SFRAME_S390X_SP_VAL_OFFSET} of -160 as follows: +SP = CFA + @code{SFRAME_S390X_SP_VAL_OFFSET} + @node Generating Stack Traces using SFrame @appendix Generating Stack Traces using SFrame @@ -913,7 +1016,7 @@ SFrame section. fp_offset = sframe_fre_get_fp_offset (fre); cfa = base_reg_val + cfa_offset; - next_frame->sp = cfa; + next_frame->sp = cfa [+ SFRAME_S390X_SP_VAL_OFFSET on s390x]; ra_stack_loc = cfa + ra_offset; // Get the address stored in the stack location. diff --git a/libsframe/libsframe.ver b/libsframe/libsframe.ver index 06324ee..8cc80da 100644 --- a/libsframe/libsframe.ver +++ b/libsframe/libsframe.ver @@ -1,6 +1,6 @@ LIBSFRAME_0.0 { }; -LIBSFRAME_1.0 { +LIBSFRAME_2.0 { global: sframe_decoder_free; sframe_fde_create_func_info; @@ -11,12 +11,13 @@ LIBSFRAME_1.0 { sframe_fre_get_ra_offset; sframe_fre_get_ra_mangled_p; sframe_decode; + sframe_decoder_get_flags; sframe_decoder_get_hdr_size; sframe_decoder_get_abi_arch; sframe_decoder_get_version; + sframe_decoder_get_offsetof_fde_start_addr; sframe_decoder_get_fixed_fp_offset; sframe_decoder_get_fixed_ra_offset; - sframe_get_funcdesc_with_addr; sframe_find_fre; sframe_decoder_get_num_fidx; sframe_decoder_get_funcdesc; @@ -24,9 +25,11 @@ LIBSFRAME_1.0 { sframe_decoder_get_fre; sframe_encode; sframe_encoder_free; + sframe_encoder_get_flags; sframe_encoder_get_hdr_size; sframe_encoder_get_abi_arch; sframe_encoder_get_version; + sframe_encoder_get_offsetof_fde_start_addr; sframe_encoder_get_num_fidx; sframe_encoder_add_fre; sframe_encoder_add_funcdesc; @@ -38,10 +41,3 @@ LIBSFRAME_1.0 { local: *; } LIBSFRAME_0.0; - -LIBSFRAME_1.1 { - sframe_decoder_get_flags; - sframe_decoder_get_offsetof_fde_start_addr; - sframe_encoder_get_flags; - sframe_encoder_get_offsetof_fde_start_addr; -} LIBSFRAME_1.0; diff --git a/libsframe/libtool-version b/libsframe/libtool-version index 9dcbe48..e06835d 100644 --- a/libsframe/libtool-version +++ b/libsframe/libtool-version @@ -27,4 +27,4 @@ # then set age to 0. # # CURRENT:REVISION:AGE -1:0:0 +2:0:0 diff --git a/libsframe/sframe-dump.c b/libsframe/sframe-dump.c index 47ac00e..d55d384 100644 --- a/libsframe/sframe-dump.c +++ b/libsframe/sframe-dump.c @@ -38,6 +38,14 @@ is_sframe_abi_arch_aarch64 (sframe_decoder_ctx *sfd_ctx) return aarch64_p; } +/* Return TRUE if the SFrame section is associated with the s390x ABI. */ + +static bool +is_sframe_abi_arch_s390x (sframe_decoder_ctx *sfd_ctx) +{ + return sframe_decoder_get_abi_arch (sfd_ctx) == SFRAME_ABI_S390X_ENDIAN_BIG; +} + static void dump_sframe_header_flags (sframe_decoder_ctx *sfd_ctx) { @@ -186,7 +194,13 @@ dump_sframe_func_with_fres (sframe_decoder_ctx *sfd_ctx, /* Dump SP/FP info. */ if (err[1] == 0) - sprintf (temp, "c%+d", fp_offset); + { + if (is_sframe_abi_arch_s390x (sfd_ctx) + && SFRAME_V2_S390X_OFFSET_IS_REGNUM (fp_offset)) + sprintf (temp, "r%d", SFRAME_V2_S390X_OFFSET_DECODE_REGNUM (fp_offset)); + else + sprintf (temp, "c%+d", fp_offset); + } else strcpy (temp, "u"); printf ("%-10s", temp); @@ -197,8 +211,18 @@ dump_sframe_func_with_fres (sframe_decoder_ctx *sfd_ctx, if (sframe_decoder_get_fixed_ra_offset (sfd_ctx) != SFRAME_CFA_FIXED_RA_INVALID) strcpy (temp, "f"); + /* If an ABI does track RA offset, e.g. s390x, it can be a padding + to represent FP without RA being saved on stack. */ + else if (err[2] == 0 && ra_offset == SFRAME_FRE_RA_OFFSET_INVALID) + sprintf (temp, "U"); else if (err[2] == 0) - sprintf (temp, "c%+d", ra_offset); + { + if (is_sframe_abi_arch_s390x (sfd_ctx) + && SFRAME_V2_S390X_OFFSET_IS_REGNUM (ra_offset)) + sprintf (temp, "r%d", SFRAME_V2_S390X_OFFSET_DECODE_REGNUM (ra_offset)); + else + sprintf (temp, "c%+d", ra_offset); + } else strcpy (temp, "u"); diff --git a/libsframe/sframe.c b/libsframe/sframe.c index ea0e1c7..7357fc1 100644 --- a/libsframe/sframe.c +++ b/libsframe/sframe.c @@ -166,6 +166,7 @@ need_swapping (int endian) case SFRAME_ABI_AMD64_ENDIAN_LITTLE: return !is_little; case SFRAME_ABI_AARCH64_ENDIAN_BIG: + case SFRAME_ABI_S390X_ENDIAN_BIG: return is_little; default: break; @@ -520,7 +521,7 @@ flip_sframe (char *frame_buf, size_t buf_size, uint32_t to_foreign) fre_offset = fdep->sfde_func_start_fre_off; } - fp = frame_buf + sframe_get_hdr_size (ihp) + ihp->sfh_freoff; + fp = frame_buf + hdrsz + ihp->sfh_freoff; fp += fre_offset; for (; j < prev_frep_index + num_fres; j++) { @@ -535,8 +536,12 @@ flip_sframe (char *frame_buf, size_t buf_size, uint32_t to_foreign) prev_frep_index = j; } /* All FDEs and FREs must have been endian flipped by now. */ - if ((j != ihp->sfh_num_fres) || (bytes_flipped != (buf_size - hdrsz))) + if ((j != ihp->sfh_num_fres) || (bytes_flipped > (buf_size - hdrsz))) goto bad; + /* Optional trailing section padding. */ + for (fp = frame_buf + hdrsz + bytes_flipped; fp < frame_buf + buf_size; fp++) + if (*fp != '\0') + goto bad; /* Success. */ return 0; @@ -690,13 +695,22 @@ sframe_fre_get_base_reg_id (sframe_frame_row_entry *fre, int *errp) /* Get the CFA offset from the FRE. If the offset is invalid, sets errp. */ int32_t -sframe_fre_get_cfa_offset (sframe_decoder_ctx *dctx ATTRIBUTE_UNUSED, +sframe_fre_get_cfa_offset (sframe_decoder_ctx *dctx, sframe_frame_row_entry *fre, int *errp) { - return sframe_get_fre_offset (fre, SFRAME_FRE_CFA_OFFSET_IDX, errp); + int32_t offset = sframe_get_fre_offset (fre, SFRAME_FRE_CFA_OFFSET_IDX, errp); + + /* For s390x undo adjustment of CFA offset (to enable 8-bit offsets). */ + if (sframe_decoder_get_abi_arch (dctx) == SFRAME_ABI_S390X_ENDIAN_BIG) + offset = SFRAME_V2_S390X_CFA_OFFSET_DECODE (offset); + + return offset; } -/* Get the FP offset from the FRE. If the offset is invalid, sets errp. */ +/* Get the FP offset from the FRE. If the offset is invalid, sets errp. + + For s390x the offset may be an encoded register number, indicated by + LSB set to one, which is only valid in the topmost frame. */ int32_t sframe_fre_get_fp_offset (sframe_decoder_ctx *dctx, @@ -723,7 +737,12 @@ sframe_fre_get_fp_offset (sframe_decoder_ctx *dctx, return sframe_get_fre_offset (fre, fp_offset_idx, errp); } -/* Get the RA offset from the FRE. If the offset is invalid, sets errp. */ +/* Get the RA offset from the FRE. If the offset is invalid, sets errp. + + For s390x an RA offset value of SFRAME_FRE_RA_OFFSET_INVALID indicates + that the RA is not saved, which is only valid in the topmost frame. + For s390x the offset may be an encoded register number, indicated by + LSB set to one, which is only valid in the topmost frame. */ int32_t sframe_fre_get_ra_offset (sframe_decoder_ctx *dctx, @@ -857,7 +876,7 @@ sframe_decode_fre (const char *fre_buf, sframe_frame_row_entry *fre, return 0; } -/* Decode the specified SFrame buffer CF_BUF of size CF_SIZE and return the +/* Decode the specified SFrame buffer SF_BUF of size SF_SIZE and return the new SFrame decoder context. Sets ERRP for the caller if any error. Frees up the allocated memory in @@ -1060,18 +1079,6 @@ sframe_decoder_get_offsetof_fde_start_addr (sframe_decoder_ctx *dctx, + offsetof (sframe_func_desc_entry, sfde_func_start_address)); } -/* Find the function descriptor entry which contains the specified address - ADDR. - This function is deprecated and will be removed from libsframe.so.2. */ - -void * -sframe_get_funcdesc_with_addr (sframe_decoder_ctx *ctx __attribute__ ((unused)), - int32_t addr __attribute__ ((unused)), - int *errp) -{ - return sframe_ret_set_errno (errp, SFRAME_ERR_INVAL); -} - /* Find the function descriptor entry starting which contains the specified address ADDR. */ @@ -1620,7 +1627,7 @@ sframe_encoder_add_funcdesc (sframe_encoder_ctx *encoder, int32_t start_addr, uint32_t func_size, unsigned char func_info, - uint32_t num_fres __attribute__ ((unused))) + uint32_t num_fres ATTRIBUTE_UNUSED) { sframe_header *ehp; sf_fde_tbl *fd_info; @@ -1702,7 +1709,7 @@ sframe_encoder_add_funcdesc_v2 (sframe_encoder_ctx *encoder, uint32_t func_size, unsigned char func_info, uint8_t rep_block_size, - uint32_t num_fres __attribute__ ((unused))) + uint32_t num_fres ATTRIBUTE_UNUSED) { sf_fde_tbl *fd_info; int err; diff --git a/libsframe/testsuite/libsframe.find/find.exp b/libsframe/testsuite/libsframe.find/find.exp index d1be070..62471a3 100644 --- a/libsframe/testsuite/libsframe.find/find.exp +++ b/libsframe/testsuite/libsframe.find/find.exp @@ -26,6 +26,7 @@ if [string equal $COMPAT_DEJAGNU "no"] { unsupported findfre-1 unsupported findfunc-1 unsupported plt-findfre-1 + unsupported plt-findfre-2 return; } @@ -40,3 +41,7 @@ if { [host_execute "testsuite/libsframe.find/findfunc-1"] ne "" } { if { [host_execute "testsuite/libsframe.find/plt-findfre-1"] ne "" } { fail "plt-findfre-1" } + +if { [host_execute "testsuite/libsframe.find/plt-findfre-2"] ne "" } { + fail "plt-findfre-2" +} diff --git a/libsframe/testsuite/libsframe.find/local.mk b/libsframe/testsuite/libsframe.find/local.mk index 03206b1..52741e8 100644 --- a/libsframe/testsuite/libsframe.find/local.mk +++ b/libsframe/testsuite/libsframe.find/local.mk @@ -1,5 +1,6 @@ if HAVE_COMPAT_DEJAGNU check_PROGRAMS += %D%/findfre-1 %D%/findfunc-1 %D%/plt-findfre-1 + check_PROGRAMS += %D%/plt-findfre-2 endif %C%_findfre_1_SOURCES = %D%/findfre-1.c @@ -13,3 +14,7 @@ endif %C%_plt_findfre_1_SOURCES = %D%/plt-findfre-1.c %C%_plt_findfre_1_LDADD = ${top_builddir}/libsframe.la %C%_plt_findfre_1_CPPFLAGS = -I${top_srcdir}/../include -Wall + +%C%_plt_findfre_2_SOURCES = %D%/plt-findfre-2.c +%C%_plt_findfre_2_LDADD = ${top_builddir}/libsframe.la +%C%_plt_findfre_2_CPPFLAGS = -I${top_srcdir}/../include -Wall diff --git a/libsframe/testsuite/libsframe.find/plt-findfre-2.c b/libsframe/testsuite/libsframe.find/plt-findfre-2.c new file mode 100644 index 0000000..00a5b2a --- /dev/null +++ b/libsframe/testsuite/libsframe.find/plt-findfre-2.c @@ -0,0 +1,201 @@ +/* plt-findfre-2.c -- Test for sframe_find_fre for SFrame FDE of type + PCMASK with with one SFrame FRE only. + + Copyright (C) 2025 Free Software Foundation, Inc. + + This program 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 of the License, or + (at your option) any later version. + + This program 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 this program. If not, see <http://www.gnu.org/licenses/>. */ + +#include "config.h" + +#include <stdlib.h> +#include <string.h> +#include <sys/stat.h> + +#include "sframe-api.h" + +/* DejaGnu should not use gnulib's vsnprintf replacement here. */ +#undef vsnprintf +#include <dejagnu.h> + +/* s390x-specific size in bytes of plt0 and pltN. */ +#define PLT_SIZE 32 + +/* Magic values added to CFA offsets to make them distingishable. Must + be multiple of 8 due to s390x-specific CFA alignment factor. */ +#define PLT0_CFA_OFFSET_MAGIC 0 +#define PLTN_CFA_OFFSET_MAGIC 8 + +static int +add_plt0_fde (sframe_encoder_ctx *ectx, uint32_t plt_vaddr, + uint32_t sframe_vaddr, int idx) +{ + /* 1 single FRE. */ + sframe_frame_row_entry fre + = { 0x0, + { SFRAME_V2_S390X_CFA_OFFSET_ENCODE (160 + PLT0_CFA_OFFSET_MAGIC) }, + SFRAME_V1_FRE_INFO (SFRAME_BASE_REG_SP, 1, SFRAME_FRE_OFFSET_1B) }; + + unsigned char finfo = sframe_fde_create_func_info (SFRAME_FRE_TYPE_ADDR1, + SFRAME_FDE_TYPE_PCINC); + uint32_t offsetof_fde_in_sec + = sframe_encoder_get_offsetof_fde_start_addr (ectx, idx, NULL); + + int32_t func_start_addr = (plt_vaddr + - (sframe_vaddr + offsetof_fde_in_sec)); + + /* 1 PCINC-type FDE for 1 plt0 entry of 32 bytes. */ + int err = sframe_encoder_add_funcdesc_v2 (ectx, func_start_addr, + PLT_SIZE /* func size. */, + finfo, + 0 /* rep block size. */, + 1 /* num FREs. */); + if (err == -1) + return err; + + if (sframe_encoder_add_fre (ectx, idx, &fre) == SFRAME_ERR) + return -1; + + return 0; +} + +static int +add_pltn_fde (sframe_encoder_ctx *ectx, uint32_t plt_vaddr, + uint32_t sframe_vaddr, int idx) +{ + /* 1 single FRE. */ + sframe_frame_row_entry fre + = { 0x0, + { SFRAME_V2_S390X_CFA_OFFSET_ENCODE (160 + PLTN_CFA_OFFSET_MAGIC) }, + SFRAME_V1_FRE_INFO (SFRAME_BASE_REG_SP, 1, SFRAME_FRE_OFFSET_1B) }; + + unsigned char finfo = sframe_fde_create_func_info (SFRAME_FRE_TYPE_ADDR1, + SFRAME_FDE_TYPE_PCMASK); + uint32_t offsetof_fde_in_sec + = sframe_encoder_get_offsetof_fde_start_addr (ectx, idx, NULL); + + int32_t func_start_addr = (plt_vaddr + - (sframe_vaddr + offsetof_fde_in_sec)); + + /* 1 PCMASK-type FDE for 5 pltN entries of 32 bytes each. */ + int err = sframe_encoder_add_funcdesc_v2 (ectx, func_start_addr, + 5 * PLT_SIZE /* func size. */, + finfo, + PLT_SIZE /* rep block size. */, + 1 /* num FREs. */); + if (err == -1) + return err; + + if (sframe_encoder_add_fre (ectx, idx, &fre) == SFRAME_ERR) + return -1; + + return 0; +} + +static +void test_plt_findfre (const char suffix, const uint32_t plt_vaddr, + const uint32_t sframe_vaddr) +{ + sframe_encoder_ctx *ectx; + sframe_decoder_ctx *dctx; + sframe_frame_row_entry frep; + char *sframe_buf; + size_t sf_size; + int err = 0; + unsigned int fde_cnt = 0; + int i; + +#define TEST(cond, ...) \ + do \ + { \ + if (cond) \ + pass (__VA_ARGS__); \ + else \ + fail (__VA_ARGS__); \ + } \ + while (0) + + ectx = sframe_encode (SFRAME_VERSION, SFRAME_F_FDE_FUNC_START_PCREL, + SFRAME_ABI_S390X_ENDIAN_BIG, + SFRAME_CFA_FIXED_FP_INVALID, + SFRAME_CFA_FIXED_RA_INVALID, + &err); + TEST (ectx != NULL && err == 0, "plt-findfre-2%c: Creating SFrame encoder", suffix); + + err = add_plt0_fde (ectx, plt_vaddr, sframe_vaddr, 0); + TEST (err == 0, "plt-findfre-2%c: Adding FDE for plt0", suffix); + + fde_cnt = sframe_encoder_get_num_fidx (ectx); + TEST (fde_cnt == 1, "plt-findfre-2%c: Test FDE count after adding FDE for plt0", suffix); + + err = add_pltn_fde (ectx, plt_vaddr + PLT_SIZE, sframe_vaddr, 1); + TEST (err == 0, "plt-findfre-2%c: Adding FDE for pltN", suffix); + + fde_cnt = sframe_encoder_get_num_fidx (ectx); + TEST (fde_cnt == 2, "plt-findfre-2%c: Test FDE count after adding FDE for pltN", suffix); + + sframe_buf = sframe_encoder_write (ectx, &sf_size, &err); + TEST (err == 0, "plt-findfre-2%c: Encoder write", suffix); + + dctx = sframe_decode (sframe_buf, sf_size, &err); + TEST (dctx != NULL, "plt-findfre-2%c: Decoder setup", suffix); + + /* Find the only FRE in PLT0 at offset 0. */ + err = sframe_find_fre (dctx, (plt_vaddr + 0 - sframe_vaddr), &frep); + TEST (err == 0 && sframe_fre_get_cfa_offset (dctx, &frep, &err) == 160 + PLT0_CFA_OFFSET_MAGIC, + "plt-findfre-2%c: Find only FRE in PLT0 at offset 0", suffix); + + /* Find the only FRE in PLT0 at offset PLT_SIZE-1. */ + err = sframe_find_fre (dctx, (plt_vaddr + (PLT_SIZE-1) - sframe_vaddr), &frep); + TEST (err == 0 && sframe_fre_get_cfa_offset (dctx, &frep, &err) == 160 + PLT0_CFA_OFFSET_MAGIC, + "plt-findfre-2%c: Find only FRE in PLT0 at offset PLT_SIZE-1", suffix); + + /* Find the only FRE in PLT1-5 at offset 0 and PLT_SIZE-1. */ + for (i = 1; i < 5; i++) + { + /* Find the only FRE in PLTN at offset 0. */ + err = sframe_find_fre (dctx, (plt_vaddr + i * PLT_SIZE + 0 - sframe_vaddr), &frep); + TEST (err == 0 && sframe_fre_get_cfa_offset (dctx, &frep, &err) == 160 + PLTN_CFA_OFFSET_MAGIC, + "plt-findfre-2%c: Find only FRE in PLT%d at offset 0", suffix, i); + + /* Find the only FRE in PLTN at offset 31. */ + err = sframe_find_fre (dctx, (plt_vaddr + i * PLT_SIZE + (PLT_SIZE-1) - sframe_vaddr), &frep); + TEST (err == 0 && sframe_fre_get_cfa_offset (dctx, &frep, &err) == 160 + PLTN_CFA_OFFSET_MAGIC, + "plt-findfre-2%c: Find only FRE in PLT%d at offset PLT_SIZE-1", suffix, i); + } + + /* Find no FRE in non-existing PLT6 at offset 0. */ + err = sframe_find_fre (dctx, (plt_vaddr + 6 * PLT_SIZE + 0 - sframe_vaddr), &frep); + TEST (err != 0, "plt-findfre-2%c: Find no FRE in out of range PLT6 at offset 0", suffix); + + sframe_encoder_free (&ectx); + sframe_decoder_free (&dctx); +} + +int +main (void) +{ + uint32_t sframe_vaddr = 0x402220; + uint32_t plt_vaddr = 0x401020; + printf ("plt-findfre-2a: Testing with plt_vaddr = %#x; sframe_vaddr = %#x\n", + plt_vaddr, sframe_vaddr); + test_plt_findfre ('a', plt_vaddr, sframe_vaddr); + + sframe_vaddr = 0x401020; + plt_vaddr = 0x402220; + printf ("plt-findfre-2b: Testing with plt_vaddr = %#x; sframe_vaddr = %#x\n", + plt_vaddr, sframe_vaddr); + test_plt_findfre ('b', plt_vaddr, sframe_vaddr); + + return 0; +} |