diff options
Diffstat (limited to 'libsframe')
-rw-r--r-- | libsframe/Makefile.in | 42 | ||||
-rw-r--r-- | libsframe/doc/sframe-spec.texi | 157 | ||||
-rw-r--r-- | libsframe/libsframe.ver | 7 | ||||
-rw-r--r-- | libsframe/libtool-version | 2 | ||||
-rw-r--r-- | libsframe/sframe-dump.c | 101 | ||||
-rw-r--r-- | libsframe/sframe.c | 253 | ||||
-rw-r--r-- | libsframe/testsuite/libsframe.decode/DATA2 | bin | 98 -> 98 bytes | |||
-rw-r--r-- | libsframe/testsuite/libsframe.encode/encode-1.c | 7 | ||||
-rw-r--r-- | libsframe/testsuite/libsframe.find/find.exp | 5 | ||||
-rw-r--r-- | libsframe/testsuite/libsframe.find/findfre-1.c | 124 | ||||
-rw-r--r-- | libsframe/testsuite/libsframe.find/findfunc-1.c | 159 | ||||
-rw-r--r-- | libsframe/testsuite/libsframe.find/local.mk | 5 | ||||
-rw-r--r-- | libsframe/testsuite/libsframe.find/plt-findfre-1.c | 89 | ||||
-rw-r--r-- | libsframe/testsuite/libsframe.find/plt-findfre-2.c | 201 |
14 files changed, 898 insertions, 254 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 ae11570..7307789 100644 --- a/libsframe/doc/sframe-spec.texi +++ b/libsframe/doc/sframe-spec.texi @@ -21,6 +21,8 @@ License''. @titlepage @title The SFrame Format @subtitle Version 2 +@sp 15 +@center @today{} @author Indu Bhagat @page @@ -75,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 @@ -126,6 +129,42 @@ the data structure. @item The above two imply that each SFrame function descriptor entry has a fixed size of 20 bytes instead of its size of 17 bytes in SFrame format version 1. +@item +Add a new flag SFRAME_F_FDE_FUNC_START_PCREL, as an erratum to SFrame +Version 2, to indicate the encoding of the SFrame FDE function start address +field: + @itemize @minus + @item if set, @code{sfde_func_start_address} field contains the offset in +bytes to the start PC of the associated function from the field itself. + @item if unset, @code{sfde_func_start_address} field contains the offset in +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. @@ -232,21 +271,28 @@ describe various section-wide properties. The following flags are currently defined. -@multitable {@code{SFRAME_F_FRAME_POINTER}} {Versions} {Value} {Function Descriptor Entries} -@headitem Flag @tab Versions @tab Value @tab Meaning +@multitable {@code{SFRAME_F_FRAME_POINTER}} {Version} {Value} {Function Descriptor Entries are sorted} +@headitem Flag @tab Version @tab Value @tab Meaning @tindex SFRAME_F_FDE_SORTED @item @code{SFRAME_F_FDE_SORTED} @tab All @tab 0x1 @tab Function Descriptor Entries are sorted on PC. @tindex SFRAME_F_FRAME_POINTER @item @code{SFRAME_F_FRAME_POINTER} @tab All @tab 0x2 @tab All functions in the object file preserve frame pointer. +@tindex SFRAME_F_FDE_FUNC_START_PCREL +@item @code{SFRAME_F_FDE_FUNC_START_PCREL} @tab 2 @tab 0x4 +@tab The @code{sfde_func_start_address} field in the SFrame FDE is an offset in +bytes to the function's start address, from the field itself. If unset, the +@code{sfde_func_start_address} field in the SFrame FDE is an offset in bytes to +the function's start address, from the start of the SFrame section. @end multitable The purpose of SFRAME_F_FRAME_POINTER flag is to facilitate stack tracers to reliably fallback on the frame pointer based stack tracing method, if SFrame information is not present for some function in the SFrame section. -Further flags may be added in future. +Further flags may be added in future. Bits corresponding to the currently +undefined flags must be set to zero. @node SFrame Header @section SFrame Header @@ -401,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 @@ -459,9 +509,11 @@ Following table describes each component of the SFrame FDE structure: @tab @code{int32_t} @tab @code{sfde_func_start_address} @tab Signed 32-bit integral field denoting the virtual memory address of the -described function, for which the SFrame FDE applies. The value encoded in -the @code{sfde_func_start_address} field is the offset in bytes of the -function's start address, from the SFrame section. +described function, for which the SFrame FDE applies. If the flag +@code{SFRAME_F_FDE_FUNC_START_PCREL}, @xref{SFrame Flags}, in the SFrame +header is set, the value encoded in the @code{sfde_func_start_address} field is +the offset in bytes to the function's start address, from the SFrame +@code{sfde_func_start_address} field. @item 0x04 @tab @code{uint32_t} @@ -758,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 @@ -772,6 +825,7 @@ auxiliary SFrame header, etc., if used, must also be outlined here. @menu * AMD64:: * AArch64:: +* s390x:: @end menu @node AMD64 @@ -828,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 @@ -891,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 57f5fb6..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; 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 1fa508d..d55d384 100644 --- a/libsframe/sframe-dump.c +++ b/libsframe/sframe-dump.c @@ -23,8 +23,6 @@ #include <inttypes.h> #include "sframe-impl.h" -#define SFRAME_HEADER_FLAGS_STR_MAX_LEN 50 - /* Return TRUE if the SFrame section is associated with the aarch64 ABIs. */ static bool @@ -40,12 +38,49 @@ 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) +{ + uint8_t flags; + const char *prefix = "Flags: "; + + flags = sframe_decoder_get_flags (sfd_ctx); + if (!flags) + { + printf ("%11sNONE\n", prefix); + return; + } + +#define PRINT_FLAG(x) \ + if (flags & (x)) \ + { flags = (flags & ~(x)); \ + printf ("%11s%s%s\n", prefix, #x, flags ? "," : ""); \ + prefix = " "; \ + } + + PRINT_FLAG (SFRAME_F_FDE_SORTED); + PRINT_FLAG (SFRAME_F_FRAME_POINTER); + PRINT_FLAG (SFRAME_F_FDE_FUNC_START_PCREL); +#undef PRINT_FLAG + + /* Print any residual flags, should this implementation be out of sync when + new flags are added. */ + if (flags) + printf ("%11s%d\n", prefix, flags); +} + static void dump_sframe_header (sframe_decoder_ctx *sfd_ctx) { uint8_t ver; - uint8_t flags; - char *flags_str; const char *ver_str = NULL; int8_t cfa_fixed_fp_offset; int8_t cfa_fixed_ra_offset; @@ -57,33 +92,10 @@ dump_sframe_header (sframe_decoder_ctx *sfd_ctx) "SFRAME_VERSION_1", "SFRAME_VERSION_2" }; - /* PS: Keep SFRAME_HEADER_FLAGS_STR_MAX_LEN in sync if adding more members to - this array. */ - const char *flag_names[] - = { "SFRAME_F_FDE_SORTED", - "SFRAME_F_FRAME_POINTER" }; - ver = sframe_decoder_get_version (sfd_ctx); if (ver <= SFRAME_VERSION) ver_str = version_names[ver]; - /* Prepare SFrame section flags string. */ - flags = header->sfh_preamble.sfp_flags; - flags_str = (char*) calloc (SFRAME_HEADER_FLAGS_STR_MAX_LEN, sizeof (char)); - if (flags) - { - if (flags & SFRAME_F_FDE_SORTED) - strcpy (flags_str, flag_names[0]); - if (flags & SFRAME_F_FRAME_POINTER) - { - if (strlen (flags_str) > 0) - strcpy (flags_str, ","); - strcpy (flags_str, flag_names[1]); - } - } - else - strcpy (flags_str, "NONE"); - /* CFA fixed FP and RA offsets. */ cfa_fixed_fp_offset = header->sfh_cfa_fixed_fp_offset; cfa_fixed_ra_offset = header->sfh_cfa_fixed_ra_offset; @@ -93,15 +105,15 @@ dump_sframe_header (sframe_decoder_ctx *sfd_ctx) printf (" %s :\n", subsec_name); printf ("\n"); printf (" Version: %s\n", ver_str); - printf (" Flags: %s\n", flags_str); + + dump_sframe_header_flags (sfd_ctx); + if (cfa_fixed_fp_offset != SFRAME_CFA_FIXED_FP_INVALID) printf (" CFA fixed FP offset: %d\n", cfa_fixed_fp_offset); if (cfa_fixed_ra_offset != SFRAME_CFA_FIXED_RA_INVALID) printf (" CFA fixed RA offset: %d\n", cfa_fixed_ra_offset); printf (" Num FDEs: %d\n", sframe_decoder_get_num_fidx (sfd_ctx)); printf (" Num FREs: %d\n", header->sfh_num_fres); - - free (flags_str); } static void @@ -129,8 +141,15 @@ dump_sframe_func_with_fres (sframe_decoder_ctx *sfd_ctx, /* Get the SFrame function descriptor. */ sframe_decoder_get_funcdesc (sfd_ctx, funcidx, &num_fres, &func_size, &func_start_address, &func_info); - /* Calculate the virtual memory address for function start pc. */ +/* Calculate the virtual memory address for function start pc. Some older + SFrame V2 sections in ET_DYN or ET_EXEC may still have the + SFRAME_F_FDE_FUNC_START_PCREL flag unset, and hence may be using the + old encoding. Continue to support dumping the sections at least. */ func_start_pc_vma = func_start_address + sec_addr; + if (sframe_decoder_get_flags (sfd_ctx) & SFRAME_F_FDE_FUNC_START_PCREL) + func_start_pc_vma += sframe_decoder_get_offsetof_fde_start_addr (sfd_ctx, + funcidx, + NULL); /* Mark FDEs with [m] where the FRE start address is interpreted as a mask. */ @@ -175,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); @@ -186,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 c2693b9..7357fc1 100644 --- a/libsframe/sframe.c +++ b/libsframe/sframe.c @@ -22,6 +22,7 @@ #include <stdlib.h> #include <stdarg.h> #include <string.h> +#include <stddef.h> #include "sframe-impl.h" #include "swap.h" @@ -165,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; @@ -204,12 +206,11 @@ flip_fde (sframe_func_desc_entry *fdep) static bool sframe_header_sanity_check_p (sframe_header *hp) { - unsigned char all_flags = SFRAME_F_FDE_SORTED | SFRAME_F_FRAME_POINTER; /* Check preamble is valid. */ if (hp->sfh_preamble.sfp_magic != SFRAME_MAGIC || (hp->sfh_preamble.sfp_version != SFRAME_VERSION_1 && hp->sfh_preamble.sfp_version != SFRAME_VERSION_2) - || (hp->sfh_preamble.sfp_flags | all_flags) != all_flags) + || (hp->sfh_preamble.sfp_flags & ~SFRAME_V2_F_ALL_FLAGS)) return false; /* Check offsets are valid. */ @@ -363,49 +364,62 @@ sframe_decoder_get_funcdesc_at_index (sframe_decoder_ctx *ctx, return fdep; } +/* Get the offset of the start PC of the SFrame FDE at FUNC_IDX from the start + of the SFrame section. This section-relative offset is used within + libsframe for sorting the SFrame FDEs, and also information lookup routines + like sframe_find_fre. + + If FUNC_IDX is not a valid index in the given decoder object, returns 0. */ + +static int32_t +sframe_decoder_get_secrel_func_start_addr (sframe_decoder_ctx *dctx, + uint32_t func_idx) +{ + int err = 0; + int32_t offsetof_fde_in_sec + = sframe_decoder_get_offsetof_fde_start_addr (dctx, func_idx, &err); + /* If func_idx is not a valid index, return 0. */ + if (err) + return 0; + + int32_t func_start_addr = dctx->sfd_funcdesc[func_idx].sfde_func_start_address; + + return func_start_addr + offsetof_fde_in_sec; +} + /* Check whether for the given FDEP, the SFrame Frame Row Entry identified via the START_IP_OFFSET and the END_IP_OFFSET, provides the stack trace information for the PC. */ static bool -sframe_fre_check_range_p (sframe_func_desc_entry *fdep, - int32_t start_ip_offset, int32_t end_ip_offset, +sframe_fre_check_range_p (sframe_decoder_ctx *dctx, uint32_t func_idx, + uint32_t start_ip_offset, uint32_t end_ip_offset, int32_t pc) { - int32_t start_ip, end_ip; + sframe_func_desc_entry *fdep; int32_t func_start_addr; uint8_t rep_block_size; uint32_t fde_type; - int32_t masked_pc; + uint32_t pc_offset; bool mask_p; - bool ret; - ret = false; - - if (!fdep) - return ret; - - func_start_addr = fdep->sfde_func_start_address; + fdep = &dctx->sfd_funcdesc[func_idx]; + func_start_addr = sframe_decoder_get_secrel_func_start_addr (dctx, func_idx); fde_type = sframe_get_fde_type (fdep); mask_p = (fde_type == SFRAME_FDE_TYPE_PCMASK); rep_block_size = fdep->sfde_func_rep_size; - if (!mask_p) - { - start_ip = start_ip_offset + func_start_addr; - end_ip = end_ip_offset + func_start_addr; - ret = ((start_ip <= pc) && (end_ip >= pc)); - } - else - { - /* For FDEs for repetitive pattern of insns, we need to return the FRE - where pc % rep_block_size is between start_ip_offset and - end_ip_offset. */ - masked_pc = pc % rep_block_size; - ret = ((start_ip_offset <= masked_pc) && (end_ip_offset >= masked_pc)); - } + if (func_start_addr > pc) + return false; + + /* Given func_start_addr <= pc, pc - func_start_addr must be positive. */ + pc_offset = pc - func_start_addr; + /* For SFrame FDEs encoding information for repetitive pattern of insns, + masking with the rep_block_size is necessary to find the matching FRE. */ + if (mask_p) + pc_offset = pc_offset % rep_block_size; - return ret; + return (start_ip_offset <= pc_offset) && (end_ip_offset >= pc_offset); } static int @@ -507,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++) { @@ -522,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; @@ -677,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, @@ -710,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, @@ -844,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 @@ -922,7 +954,7 @@ sframe_decode (const char *sf_buf, size_t sf_size, int *errp) sfheaderp = &dctx->sfd_header; if (!sframe_header_sanity_check_p (sfheaderp)) { - sframe_ret_set_errno (errp, SFRAME_ERR_NOMEM); + sframe_ret_set_errno (errp, SFRAME_ERR_BUF_INVAL); goto decode_fail_free; } hdrsz = sframe_get_hdr_size (sfheaderp); @@ -997,6 +1029,15 @@ sframe_decoder_get_version (sframe_decoder_ctx *dctx) return dhp->sfh_preamble.sfp_version; } +/* Get the section flags from the SFrame decoder context DCTX. */ + +uint8_t +sframe_decoder_get_flags (sframe_decoder_ctx *dctx) +{ + const sframe_header *dhp = sframe_decoder_get_header (dctx); + return dhp->sfh_preamble.sfp_flags; +} + /* Get the SFrame's fixed FP offset given the decoder context CTX. */ int8_t sframe_decoder_get_fixed_fp_offset (sframe_decoder_ctx *ctx) @@ -1015,16 +1056,27 @@ sframe_decoder_get_fixed_ra_offset (sframe_decoder_ctx *ctx) return dhp->sfh_cfa_fixed_ra_offset; } -/* Find the function descriptor entry which contains the specified address - ADDR. - This function is deprecated and will be removed from libsframe.so.2. */ +/* Get the offset of the sfde_func_start_address field (from the start of the + on-disk layout of the SFrame section) of the FDE at FUNC_IDX in the decoder + context DCTX. -void * -sframe_get_funcdesc_with_addr (sframe_decoder_ctx *ctx __attribute__ ((unused)), - int32_t addr __attribute__ ((unused)), - int *errp) + If FUNC_IDX is more than the number of SFrame FDEs in the section, sets + error code in ERRP, but returns the (hypothetical) offset. This is useful + for the linker when arranging input FDEs into the output section to be + emitted. */ + +uint32_t +sframe_decoder_get_offsetof_fde_start_addr (sframe_decoder_ctx *dctx, + uint32_t func_idx, int *errp) { - return sframe_ret_set_errno (errp, SFRAME_ERR_INVAL); + if (func_idx >= sframe_decoder_get_num_fidx (dctx)) + sframe_ret_set_errno (errp, SFRAME_ERR_FDE_NOTFOUND); + else if (errp) + *errp = 0; + + return (sframe_decoder_get_hdr_size (dctx) + + func_idx * sizeof (sframe_func_desc_entry) + + offsetof (sframe_func_desc_entry, sfde_func_start_address)); } /* Find the function descriptor entry starting which contains the specified @@ -1032,11 +1084,11 @@ sframe_get_funcdesc_with_addr (sframe_decoder_ctx *ctx __attribute__ ((unused)), static sframe_func_desc_entry * sframe_get_funcdesc_with_addr_internal (sframe_decoder_ctx *ctx, int32_t addr, - int *errp) + int *errp, uint32_t *func_idx) { sframe_header *dhp; sframe_func_desc_entry *fdp; - int low, high, cnt; + int low, high; if (ctx == NULL) return sframe_ret_set_errno (errp, SFRAME_ERR_INVAL); @@ -1047,29 +1099,30 @@ sframe_get_funcdesc_with_addr_internal (sframe_decoder_ctx *ctx, int32_t addr, return sframe_ret_set_errno (errp, SFRAME_ERR_DCTX_INVAL); /* If the FDE sub-section is not sorted on PCs, skip the lookup because binary search cannot be used. */ - if ((dhp->sfh_preamble.sfp_flags & SFRAME_F_FDE_SORTED) == 0) + if ((sframe_decoder_get_flags (ctx) & SFRAME_F_FDE_SORTED) == 0) return sframe_ret_set_errno (errp, SFRAME_ERR_FDE_NOTSORTED); /* Do the binary search. */ fdp = (sframe_func_desc_entry *) ctx->sfd_funcdesc; low = 0; - high = dhp->sfh_num_fdes; - cnt = high; + high = dhp->sfh_num_fdes - 1; while (low <= high) { int mid = low + (high - low) / 2; - if (fdp[mid].sfde_func_start_address == addr) - return fdp + mid; - - if (fdp[mid].sfde_func_start_address < addr) + /* Given sfde_func_start_address <= addr, + addr - sfde_func_start_address must be positive. */ + if (sframe_decoder_get_secrel_func_start_addr (ctx, mid) <= addr + && ((uint32_t)(addr - sframe_decoder_get_secrel_func_start_addr (ctx, + mid)) + < fdp[mid].sfde_func_size)) { - if (mid == (cnt - 1)) /* Check if it's the last one. */ - return fdp + (cnt - 1); - else if (fdp[mid+1].sfde_func_start_address > addr) - return fdp + mid; - low = mid + 1; + *func_idx = mid; + return fdp + mid; } + + if (sframe_decoder_get_secrel_func_start_addr (ctx, mid) < addr) + low = mid + 1; else high = mid - 1; } @@ -1112,29 +1165,26 @@ sframe_find_fre (sframe_decoder_ctx *ctx, int32_t pc, { sframe_frame_row_entry cur_fre; sframe_func_desc_entry *fdep; - uint32_t fre_type, fde_type, i; - int32_t start_ip_offset; + uint32_t func_idx; + uint32_t fre_type, i; int32_t func_start_addr; - int32_t end_ip_offset; + uint32_t start_ip_offset, end_ip_offset; const char *fres; size_t size = 0; int err = 0; - bool mask_p; if ((ctx == NULL) || (frep == NULL)) return sframe_set_errno (&err, SFRAME_ERR_INVAL); /* Find the FDE which contains the PC, then scan its fre entries. */ - fdep = sframe_get_funcdesc_with_addr_internal (ctx, pc, &err); + fdep = sframe_get_funcdesc_with_addr_internal (ctx, pc, &err, &func_idx); if (fdep == NULL || ctx->sfd_fres == NULL) return sframe_set_errno (&err, SFRAME_ERR_DCTX_INVAL); fre_type = sframe_get_fre_type (fdep); - fde_type = sframe_get_fde_type (fdep); - mask_p = (fde_type == SFRAME_FDE_TYPE_PCMASK); fres = ctx->sfd_fres + fdep->sfde_func_start_fre_off; - func_start_addr = fdep->sfde_func_start_address; + func_start_addr = sframe_decoder_get_secrel_func_start_addr (ctx, func_idx); for (i = 0; i < fdep->sfde_func_num_fres; i++) { @@ -1145,11 +1195,13 @@ sframe_find_fre (sframe_decoder_ctx *ctx, int32_t pc, start_ip_offset = cur_fre.fre_start_addr; end_ip_offset = sframe_fre_get_end_ip_offset (fdep, i, fres + size); - /* First FRE's start_ip must be more than pc for regular SFrame FDEs. */ - if (i == 0 && !mask_p && (start_ip_offset + func_start_addr) > pc) + /* Stop search if FRE's start_ip is greater than pc. Given + func_start_addr <= pc, pc - func_start_addr must be positive. */ + if (start_ip_offset > (uint32_t)(pc - func_start_addr)) return sframe_set_errno (&err, SFRAME_ERR_FRE_INVAL); - if (sframe_fre_check_range_p (fdep, start_ip_offset, end_ip_offset, pc)) + if (sframe_fre_check_range_p (ctx, func_idx, start_ip_offset, + end_ip_offset, pc)) { sframe_frame_row_entry_copy (frep, &cur_fre); return 0; @@ -1345,6 +1397,12 @@ sframe_encode (uint8_t ver, uint8_t flags, uint8_t abi_arch, hp->sfh_preamble.sfp_magic = SFRAME_MAGIC; hp->sfh_preamble.sfp_flags = flags; + /* Implementation in the SFrame encoder APIs, e.g., + sframe_encoder_write_sframe assume flag SFRAME_F_FDE_FUNC_START_PCREL + set. */ + if (!(flags & SFRAME_F_FDE_FUNC_START_PCREL)) + return sframe_ret_set_errno (errp, SFRAME_ERR_ECTX_INVAL); + hp->sfh_abi_arch = abi_arch; hp->sfh_cfa_fixed_fp_offset = fixed_fp_offset; hp->sfh_cfa_fixed_ra_offset = fixed_ra_offset; @@ -1417,6 +1475,15 @@ sframe_encoder_get_version (sframe_encoder_ctx *encoder) return ehp->sfh_preamble.sfp_version; } +/* Get the section flags from the SFrame encoder context ENCODER. */ + +uint8_t +sframe_encoder_get_flags (sframe_encoder_ctx *encoder) +{ + const sframe_header *ehp = sframe_encoder_get_header (encoder); + return ehp->sfh_preamble.sfp_flags; +} + /* Return the number of function descriptor entries in the SFrame encoder ENCODER. */ @@ -1431,6 +1498,29 @@ sframe_encoder_get_num_fidx (sframe_encoder_ctx *encoder) return num_fdes; } +/* Get the offset of the sfde_func_start_address field (from the start of the + on-disk layout of the SFrame section) of the FDE at FUNC_IDX in the encoder + context ENCODER. + + If FUNC_IDX is more than the number of SFrame FDEs in the section, sets + error code in ERRP, but returns the (hypothetical) offset. This is useful + for the linker when arranging input FDEs into the output section to be + emitted. */ + +uint32_t +sframe_encoder_get_offsetof_fde_start_addr (sframe_encoder_ctx *encoder, + uint32_t func_idx, int *errp) +{ + if (func_idx >= sframe_encoder_get_num_fidx (encoder)) + sframe_ret_set_errno (errp, SFRAME_ERR_FDE_INVAL); + else if (errp) + *errp = 0; + + return (sframe_encoder_get_hdr_size (encoder) + + func_idx * sizeof (sframe_func_desc_entry) + + offsetof (sframe_func_desc_entry, sfde_func_start_address)); +} + /* Add an FRE to function at FUNC_IDX'th function descriptor entry in the encoder context. */ @@ -1537,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; @@ -1619,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; @@ -1642,15 +1732,28 @@ sframe_encoder_add_funcdesc_v2 (sframe_encoder_ctx *encoder, static int sframe_sort_funcdesc (sframe_encoder_ctx *encoder) { - sframe_header *ehp; + sframe_header *ehp = sframe_encoder_get_header (encoder); - ehp = sframe_encoder_get_header (encoder); /* Sort and write out the FDE table. */ sf_fde_tbl *fd_info = encoder->sfe_funcdesc; if (fd_info) { + /* The new encoding of sfde_func_start_address means the distances are + not from the same anchor, so cannot be sorted directly. At the moment + we adress this by manual value adjustments before and after sorting. + FIXME - qsort_r may be more optimal. */ + + for (unsigned int i = 0; i < fd_info->count; i++) + fd_info->entry[i].sfde_func_start_address + += sframe_encoder_get_offsetof_fde_start_addr (encoder, i, NULL); + qsort (fd_info->entry, fd_info->count, sizeof (sframe_func_desc_entry), fde_func); + + for (unsigned int i = 0; i < fd_info->count; i++) + fd_info->entry[i].sfde_func_start_address + -= sframe_encoder_get_offsetof_fde_start_addr (encoder, i, NULL); + /* Update preamble's flags. */ ehp->sfh_preamble.sfp_flags |= SFRAME_F_FDE_SORTED; } @@ -1751,7 +1854,6 @@ sframe_encoder_write_sframe (sframe_encoder_ctx *encoder) size_t fre_size; size_t esz = 0; sframe_header *ehp; - unsigned char flags; sf_fde_tbl *fd_info; sf_fre_tbl *fr_info; uint32_t i, num_fdes; @@ -1821,8 +1923,7 @@ sframe_encoder_write_sframe (sframe_encoder_ctx *encoder) /* Sanity checks: - the FDE section must have been sorted by now on the start address of each function. */ - flags = ehp->sfh_preamble.sfp_flags; - if (!(flags & SFRAME_F_FDE_SORTED) + if (!(sframe_encoder_get_flags (encoder) & SFRAME_F_FDE_SORTED) || (fd_info == NULL)) return sframe_set_errno (&err, SFRAME_ERR_FDE_INVAL); diff --git a/libsframe/testsuite/libsframe.decode/DATA2 b/libsframe/testsuite/libsframe.decode/DATA2 Binary files differindex 472f736..90649e2 100644 --- a/libsframe/testsuite/libsframe.decode/DATA2 +++ b/libsframe/testsuite/libsframe.decode/DATA2 diff --git a/libsframe/testsuite/libsframe.encode/encode-1.c b/libsframe/testsuite/libsframe.encode/encode-1.c index 3c2df76..1ba75d7 100644 --- a/libsframe/testsuite/libsframe.encode/encode-1.c +++ b/libsframe/testsuite/libsframe.encode/encode-1.c @@ -41,7 +41,7 @@ add_fde1 (sframe_encoder_ctx *encode, int idx) unsigned char finfo = sframe_fde_create_func_info (SFRAME_FRE_TYPE_ADDR1, SFRAME_FDE_TYPE_PCINC); - err = sframe_encoder_add_funcdesc (encode, 0xfffff03e, 0x1b, finfo, 4); + err = sframe_encoder_add_funcdesc (encode, 0xfffff022, 0x1b, finfo, 4); if (err == -1) return err; @@ -66,7 +66,7 @@ add_fde2 (sframe_encoder_ctx *encode, int idx) unsigned char finfo = sframe_fde_create_func_info (SFRAME_FRE_TYPE_ADDR1, SFRAME_FDE_TYPE_PCINC); - err = sframe_encoder_add_funcdesc (encode, 0xfffff059, 0x10, finfo, 4); + err = sframe_encoder_add_funcdesc (encode, 0xfffff029, 0x10, finfo, 4); if (err == -1) return err; @@ -145,7 +145,8 @@ int main (void) } \ while (0) - encode = sframe_encode (SFRAME_VERSION, 0, + encode = sframe_encode (SFRAME_VERSION, + SFRAME_F_FDE_FUNC_START_PCREL, SFRAME_ABI_AMD64_ENDIAN_LITTLE, SFRAME_CFA_FIXED_FP_INVALID, -8, /* Fixed RA offset for AMD64. */ 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/findfre-1.c b/libsframe/testsuite/libsframe.find/findfre-1.c index 5b1da05..7c7c947 100644 --- a/libsframe/testsuite/libsframe.find/findfre-1.c +++ b/libsframe/testsuite/libsframe.find/findfre-1.c @@ -28,64 +28,88 @@ #include <dejagnu.h> static int -add_fde1 (sframe_encoder_ctx *encode, int idx) +add_fde1 (sframe_encoder_ctx *encode, uint32_t start_pc_vaddr, + uint32_t sframe_vaddr, int idx, uint32_t *func_size) { - int i, err; /* A contiguous block containing 4 FREs. */ - sframe_frame_row_entry fres[] +#define FDE1_NUM_FRES 4 + sframe_frame_row_entry fres[FDE1_NUM_FRES] = { {0x0, {0x1, 0, 0}, 0x3}, {0x1, {0x2, 0xf0, 0}, 0x5}, {0x10, {0x3, 0xf0, 0}, 0x4}, {0x38, {0x8, 0xf0, 0}, 0x5} }; - + /* Function size in bytes. P.S. Must be a value greater than the + fre_start_addr of the last FRE above (0x38). */ + *func_size = 0x40; + + uint32_t offsetof_fde_in_sec + = sframe_encoder_get_offsetof_fde_start_addr (encode, idx, NULL); + int32_t func1_start_addr = (start_pc_vaddr + - (sframe_vaddr + offsetof_fde_in_sec)); unsigned char finfo = sframe_fde_create_func_info (SFRAME_FRE_TYPE_ADDR1, SFRAME_FDE_TYPE_PCINC); - err = sframe_encoder_add_funcdesc (encode, 0xfffff03e, 0x40, finfo, 4); + int err = sframe_encoder_add_funcdesc (encode, func1_start_addr, *func_size, + finfo, FDE1_NUM_FRES); if (err == -1) return err; - for (i = 0; i < 4; i++) - if (sframe_encoder_add_fre (encode, idx,fres+i) == SFRAME_ERR) + for (unsigned int i = 0; i < FDE1_NUM_FRES; i++) + if (sframe_encoder_add_fre (encode, idx, fres + i) == SFRAME_ERR) return -1; return 0; } static int -add_fde2 (sframe_encoder_ctx *encode, int idx) +add_fde2 (sframe_encoder_ctx *encode, uint32_t start_pc_vaddr, + uint32_t sframe_vaddr, int idx, uint32_t *func_size) { - int i, err; /* A contiguous block containing 4 FREs. */ - sframe_frame_row_entry fres[] +#define FDE2_NUM_FRES 4 + sframe_frame_row_entry fres[FDE2_NUM_FRES] = { {0x0, {0x10, 0, 0}, 0x3}, {0x10, {0x12, 0xf0, 0}, 0x5}, {0x14, {0x14, 0xf0, 0}, 0x4}, {0x20, {0x15, 0xf0, 0}, 0x5} }; - + /* Function size in bytes. P.S. Must be a value greater than the + fre_start_addr of the last FRE above (0x20). */ + *func_size = 0x60; + + uint32_t offsetof_fde_in_sec + = sframe_encoder_get_offsetof_fde_start_addr (encode, idx, NULL); + int32_t func2_start_addr = (start_pc_vaddr + - (sframe_vaddr + offsetof_fde_in_sec)); unsigned char finfo = sframe_fde_create_func_info (SFRAME_FRE_TYPE_ADDR1, SFRAME_FDE_TYPE_PCINC); - err = sframe_encoder_add_funcdesc (encode, 0xfffff08e, 0x60, finfo, 4); + int err = sframe_encoder_add_funcdesc (encode, func2_start_addr, *func_size, + finfo, FDE2_NUM_FRES); if (err == -1) return err; - for (i = 0; i < 4; i++) - if (sframe_encoder_add_fre (encode, idx, fres+i) == SFRAME_ERR) + for (unsigned int i = 0; i < FDE2_NUM_FRES; i++) + if (sframe_encoder_add_fre (encode, idx, fres + i) == SFRAME_ERR) return -1; return 0; } -int main (void) +static +void test_text_findfre (uint32_t text_vaddr, uint32_t sframe_vaddr) { sframe_encoder_ctx *encode; sframe_decoder_ctx *dctx; sframe_frame_row_entry frep; + uint32_t func1_start_vaddr; + uint32_t func2_start_vaddr; + uint32_t func1_size = 0; + uint32_t func2_size = 0; + uint32_t fde_cnt = 0; + int32_t lookup_pc; char *sframe_buf; size_t sf_size; int err = 0; - unsigned int fde_cnt = 0; #define TEST(name, cond) \ do \ @@ -97,16 +121,20 @@ int main (void) } \ while (0) - encode = sframe_encode (SFRAME_VERSION, 0, + encode = sframe_encode (SFRAME_VERSION, + SFRAME_F_FDE_FUNC_START_PCREL, SFRAME_ABI_AMD64_ENDIAN_LITTLE, SFRAME_CFA_FIXED_FP_INVALID, -8, /* Fixed RA offset for AMD64. */ &err); - err = add_fde1 (encode, 0); + func1_start_vaddr = text_vaddr; + err = add_fde1 (encode, func1_start_vaddr, sframe_vaddr, 0, &func1_size); TEST ("findfre-1: Adding FDE1", err == 0); - err = add_fde2 (encode, 1); + /* Function 2 is placed after 0x10 bytes from the end of Function 1. */ + func2_start_vaddr = func1_start_vaddr + func1_size + 0x10; + err = add_fde2 (encode, func2_start_vaddr, sframe_vaddr, 1, &func2_size); TEST ("findfre-1: Adding FDE2", err == 0); fde_cnt = sframe_encoder_get_num_fidx (encode); @@ -116,40 +144,58 @@ int main (void) TEST ("findfre-1: Encoder write", err == 0); dctx = sframe_decode (sframe_buf, sf_size, &err); - TEST("findfre-1: Decoder setup", dctx != NULL); + TEST ("findfre-1: Decoder setup", dctx != NULL); /* Find the third FRE in first FDE. */ - err = sframe_find_fre (dctx, (0xfffff03e + 0x15), &frep); - TEST("findfre-1: Find third FRE", - ((err == 0) && (sframe_fre_get_cfa_offset(dctx, &frep, &err) == 0x3))); + lookup_pc = func1_start_vaddr + 0x15 - sframe_vaddr; + err = sframe_find_fre (dctx, lookup_pc, &frep); + TEST ("findfre-1: Find third FRE", + (err == 0 && sframe_fre_get_cfa_offset (dctx, &frep, &err) == 0x3)); /* Find an FRE for PC at the end of range covered by FRE. */ - err = sframe_find_fre (dctx, (0xfffff03e + 0x9), &frep); - TEST("findfre-1: Find FRE for last PC covered by FRE", - ((err == 0) && (sframe_fre_get_cfa_offset(dctx, &frep, &err) == 0x2))); + lookup_pc = func1_start_vaddr + 0x9 - sframe_vaddr; + err = sframe_find_fre (dctx, lookup_pc, &frep); + TEST ("findfre-1: Find FRE for last PC covered by FRE", + (err == 0 && sframe_fre_get_cfa_offset (dctx, &frep, &err) == 0x2)); /* Find the last FRE in first FDE. */ - err = sframe_find_fre (dctx, (0xfffff03e + 0x39), &frep); - TEST("findfre-1: Find last FRE", - ((err == 0) && (sframe_fre_get_cfa_offset(dctx, &frep, &err) == 0x8))); + lookup_pc = func1_start_vaddr + 0x39 - sframe_vaddr; + err = sframe_find_fre (dctx, lookup_pc, &frep); + TEST ("findfre-1: Find last FRE", + (err == 0 && sframe_fre_get_cfa_offset (dctx, &frep, &err) == 0x8)); /* Find the second FRE in second FDE. */ - err = sframe_find_fre (dctx, (0xfffff08e + 0x11), &frep); - TEST("findfre-1: Find second FRE", - ((err == 0) && (sframe_fre_get_cfa_offset(dctx, &frep, &err) == 0x12))); + lookup_pc = func2_start_vaddr + 0x11 - sframe_vaddr; + err = sframe_find_fre (dctx, lookup_pc, &frep); + TEST ("findfre-1: Find second FRE", + (err == 0 && sframe_fre_get_cfa_offset (dctx, &frep, &err) == 0x12)); /* Find the first FRE in second FDE. */ - err = sframe_find_fre (dctx, (0xfffff08e + 0x0), &frep); - TEST("findfre-1: Find first FRE", - ((err == 0) && (sframe_fre_get_cfa_offset(dctx, &frep, &err) == 0x10))); + lookup_pc = func2_start_vaddr + 0x0 - sframe_vaddr; + err = sframe_find_fre (dctx, lookup_pc, &frep); + TEST ("findfre-1: Find first FRE", + (err == 0 && sframe_fre_get_cfa_offset (dctx, &frep, &err) == 0x10)); /* Find FRE for PC out of range. Expect error code. */ - err = sframe_find_fre (dctx, (0xfffff03e + 0x40), &frep); - TEST("findfre-1: Find FRE for out of range PC", - (err == SFRAME_ERR)); + lookup_pc = func1_start_vaddr + func1_size - sframe_vaddr; + err = sframe_find_fre (dctx, lookup_pc, &frep); + TEST ("findfre-1: Find FRE for out of range PC", err == SFRAME_ERR); sframe_encoder_free (&encode); sframe_decoder_free (&dctx); +} - return 0; +int main (void) +{ + uint32_t sframe_vaddr = 0x402220; + uint32_t text_vaddr = 0x401020; + printf ("Testing with text_vaddr = %#x; sframe_vaddr = %#x\n", text_vaddr, + sframe_vaddr); + test_text_findfre (text_vaddr, sframe_vaddr); + + sframe_vaddr = 0x401020; + text_vaddr = 0x402220; + printf ("Testing with text_vaddr = %#x; sframe_vaddr = %#x\n", text_vaddr, + sframe_vaddr); + test_text_findfre (text_vaddr, sframe_vaddr); } diff --git a/libsframe/testsuite/libsframe.find/findfunc-1.c b/libsframe/testsuite/libsframe.find/findfunc-1.c index 8671f5d..00b9e8d 100644 --- a/libsframe/testsuite/libsframe.find/findfunc-1.c +++ b/libsframe/testsuite/libsframe.find/findfunc-1.c @@ -35,89 +35,124 @@ #include <dejagnu.h> static int -add_fde1 (sframe_encoder_ctx *encode, int idx) +add_fde1 (sframe_encoder_ctx *encode, uint32_t start_pc_vaddr, + uint32_t sframe_vaddr, int idx, uint32_t *func_size) { - int i, err; /* A contiguous block containing 4 FREs. */ - sframe_frame_row_entry fres[] +#define FDE1_NUM_FRES 4 + sframe_frame_row_entry fres[FDE1_NUM_FRES] = { {0x0, {0x1, 0, 0}, 0x3}, {0x1, {0x2, 0xf0, 0}, 0x5}, {0x10, {0x3, 0xf0, 0}, 0x4}, {0x38, {0x8, 0xf0, 0}, 0x5} }; - + /* Function size in bytes. P.S. Must be a value greater than the + fre_start_addr of the last FRE above (0x38). */ + *func_size = 0x40; + + uint32_t offsetof_fde_in_sec + = sframe_encoder_get_offsetof_fde_start_addr (encode, idx, NULL); + int32_t func1_start_addr = (start_pc_vaddr + - (sframe_vaddr + offsetof_fde_in_sec)); unsigned char finfo = sframe_fde_create_func_info (SFRAME_FRE_TYPE_ADDR1, SFRAME_FDE_TYPE_PCINC); - err = sframe_encoder_add_funcdesc (encode, 0xfffff03e, 0x40, finfo, 4); + int err = sframe_encoder_add_funcdesc (encode, func1_start_addr, *func_size, + finfo, FDE1_NUM_FRES); if (err == -1) return err; - for (i = 0; i < 4; i++) - if (sframe_encoder_add_fre (encode, idx,fres+i) == SFRAME_ERR) + for (unsigned int i = 0; i < FDE1_NUM_FRES; i++) + if (sframe_encoder_add_fre (encode, idx, fres + i) == SFRAME_ERR) return -1; return 0; } static int -add_fde2 (sframe_encoder_ctx *encode, int idx) +add_fde2 (sframe_encoder_ctx *encode, uint32_t start_pc_vaddr, + uint32_t sframe_vaddr, int idx, uint32_t *func_size) { - int i, err; /* A contiguous block containing 4 FREs. */ - sframe_frame_row_entry fres[] +#define FDE2_NUM_FRES 4 + sframe_frame_row_entry fres[FDE2_NUM_FRES] = { {0x0, {0x10, 0, 0}, 0x3}, {0x10, {0x12, 0xf0, 0}, 0x5}, {0x14, {0x14, 0xf0, 0}, 0x4}, {0x20, {0x15, 0xf0, 0}, 0x5} }; - + /* Function size in bytes. P.S. Must be a value greater than the + fre_start_addr of the last FRE above (0x20). */ + *func_size = 0x60; + + uint32_t offsetof_fde_in_sec + = sframe_encoder_get_offsetof_fde_start_addr (encode, idx, NULL); + int32_t func2_start_addr = (start_pc_vaddr + - (sframe_vaddr + offsetof_fde_in_sec)); unsigned char finfo = sframe_fde_create_func_info (SFRAME_FRE_TYPE_ADDR1, SFRAME_FDE_TYPE_PCINC); - err = sframe_encoder_add_funcdesc (encode, 0xfffff08e, 0x60, finfo, 4); + int err = sframe_encoder_add_funcdesc (encode, func2_start_addr, *func_size, + finfo, FDE2_NUM_FRES); if (err == -1) return err; - for (i = 0; i < 4; i++) - if (sframe_encoder_add_fre (encode, idx, fres+i) == SFRAME_ERR) + for (unsigned int i = 0; i < FDE2_NUM_FRES; i++) + if (sframe_encoder_add_fre (encode, idx, fres + i) == SFRAME_ERR) return -1; return 0; } static int -add_fde3 (sframe_encoder_ctx *encode, int idx) +add_fde3 (sframe_encoder_ctx *encode, uint32_t start_pc_vaddr, + uint32_t sframe_vaddr, int idx, uint32_t *func_size) { - int i, err; /* A contiguous block containing 4 FREs. */ - sframe_frame_row_entry fres[] +#define FDE3_NUM_FRES 4 + sframe_frame_row_entry fres[FDE3_NUM_FRES] = { {0x0, {0x16, 0, 0}, 0x3}, {0x1, {0x17, 0xf0, 0}, 0x5}, {0x10, {0x18, 0xf0, 0}, 0x4}, {0x38, {0x19, 0xf0, 0}, 0x5} }; - + /* Function size in bytes. P.S. Must be a value greater than the + fre_start_addr of the last FRE above (0x38). */ + *func_size = 0x40; + + uint32_t offsetof_fde_in_sec + = sframe_encoder_get_offsetof_fde_start_addr (encode, idx, NULL); + int32_t func3_start_addr = (start_pc_vaddr + - (sframe_vaddr + offsetof_fde_in_sec)); unsigned char finfo = sframe_fde_create_func_info (SFRAME_FRE_TYPE_ADDR1, SFRAME_FDE_TYPE_PCINC); - err = sframe_encoder_add_funcdesc (encode, 0xfffff10e, 0x40, finfo, 4); + int err = sframe_encoder_add_funcdesc (encode, func3_start_addr, *func_size, + finfo, FDE3_NUM_FRES); if (err == -1) return err; - for (i = 0; i < 4; i++) - if (sframe_encoder_add_fre (encode, idx,fres+i) == SFRAME_ERR) + for (unsigned int i = 0; i < FDE3_NUM_FRES; i++) + if (sframe_encoder_add_fre (encode, idx, fres + i) == SFRAME_ERR) return -1; return 0; } -int main (void) +static +void test_text_findfre (uint32_t text_vaddr, uint32_t sframe_vaddr) { sframe_encoder_ctx *encode; sframe_decoder_ctx *dctx; sframe_frame_row_entry frep; + uint32_t func1_start_vaddr; + uint32_t func2_start_vaddr; + uint32_t func3_start_vaddr; + uint32_t func1_size = 0; + uint32_t func2_size = 0; + uint32_t func3_size = 0; + uint32_t fde_cnt = 0; + int32_t lookup_pc = 0; char *sframe_buf; size_t sf_size; int err = 0; - unsigned int fde_cnt = 0; #define TEST(name, cond) \ do \ @@ -129,22 +164,26 @@ int main (void) } \ while (0) - encode = sframe_encode (SFRAME_VERSION, 0, + encode = sframe_encode (SFRAME_VERSION, + SFRAME_F_FDE_FUNC_START_PCREL, SFRAME_ABI_AMD64_ENDIAN_LITTLE, SFRAME_CFA_FIXED_FP_INVALID, -8, /* Fixed RA offset for AMD64. */ &err); /* Add FDE at index 0. */ - err = add_fde1 (encode, 0); + func1_start_vaddr = text_vaddr; + err = add_fde1 (encode, func1_start_vaddr, sframe_vaddr, 0, &func1_size); TEST ("findfunc-1: Adding FDE1", err == 0); /* Add FDE at index 1. */ - err = add_fde2 (encode, 1); + func2_start_vaddr = func1_start_vaddr + func1_size + 0x10; + err = add_fde2 (encode, func2_start_vaddr, sframe_vaddr, 1, &func2_size); TEST ("findfunc-1: Adding FDE2", err == 0); /* Add FDE at index 2. */ - err = add_fde3 (encode, 2); + func3_start_vaddr = func2_start_vaddr + func2_size + 0x10; + err = add_fde3 (encode, func3_start_vaddr, sframe_vaddr, 2, &func3_size); TEST ("findfunc-1: Adding FDE3", err == 0); fde_cnt = sframe_encoder_get_num_fidx (encode); @@ -154,51 +193,71 @@ int main (void) TEST ("findfunc-1: Encoder write", err == 0); dctx = sframe_decode (sframe_buf, sf_size, &err); - TEST("findfunc-1: Decoder setup", dctx != NULL); + TEST ("findfunc-1: Decoder setup", dctx != NULL); /* Following negative tests check that libsframe APIs (sframe_get_funcdesc_with_addr, sframe_find_fre) work well for PCs not covered by the FDEs. */ /* Search with PC less than the first FDE's start addr. */ - err = sframe_find_fre (dctx, (0xfffff03e - 0x15), &frep); - TEST("findfunc-1: test-1: Find FRE for PC not in range", - (err == SFRAME_ERR)); + lookup_pc = func1_start_vaddr - 0x15 - sframe_vaddr; + err = sframe_find_fre (dctx, lookup_pc, &frep); + TEST ("findfunc-1: test-1: Find FRE for PC not in range", + err == SFRAME_ERR); /* Search with a PC between func1's last PC and func2's first PC. */ - err = sframe_find_fre (dctx, (0xfffff03e + 0x40 + 0x1), &frep); - TEST("findfunc-1: test-2: Find FRE for PC not in range", - (err == SFRAME_ERR)); + lookup_pc = func1_start_vaddr + func1_size + 0x1 - sframe_vaddr, + err = sframe_find_fre (dctx, lookup_pc, &frep); + TEST ("findfunc-1: test-2: Find FRE for PC not in range", + err == SFRAME_ERR); /* Search for a PC between func2's last PC and func3's first PC. */ - err = sframe_find_fre (dctx, (0xfffff08e + 0x60 + 0x3), &frep); - TEST("findfunc-1: test-3: Find FRE for PC not in range", - (err == SFRAME_ERR)); + lookup_pc = func2_start_vaddr + func2_size + 0x3 - sframe_vaddr; + err = sframe_find_fre (dctx, lookup_pc, &frep); + TEST ("findfunc-1: test-3: Find FRE for PC not in range", + err == SFRAME_ERR); /* Search for a PC beyond the last func, i.e., > func3's last PC. */ - err = sframe_find_fre (dctx, (0xfffff10e + 0x40 + 0x10), &frep); - TEST("findfunc-1: test-4: Find FRE for PC not in range", - (err == SFRAME_ERR)); + lookup_pc = func3_start_vaddr + func3_size + 0x10 - sframe_vaddr; + err = sframe_find_fre (dctx, lookup_pc, &frep); + TEST ("findfunc-1: test-4: Find FRE for PC not in range", + err == SFRAME_ERR); /* And some positive tests... */ /* Find an FRE for PC in FDE1. */ - err = sframe_find_fre (dctx, (0xfffff03e + 0x9), &frep); - TEST("findfunc-1: Find FRE in FDE1", - ((err == 0) && (sframe_fre_get_cfa_offset(dctx, &frep, &err) == 0x2))); + lookup_pc = func1_start_vaddr + 0x9 - sframe_vaddr; + err = sframe_find_fre (dctx, lookup_pc, &frep); + TEST ("findfunc-1: Find FRE in FDE1", + (err == 0 && sframe_fre_get_cfa_offset (dctx, &frep, &err) == 0x2)); /* Find an FRE for PC in FDE2. */ - err = sframe_find_fre (dctx, (0xfffff08e + 0x11), &frep); - TEST("findfunc-1: Find FRE in FDE2", - ((err == 0) && (sframe_fre_get_cfa_offset(dctx, &frep, &err) == 0x12))); + lookup_pc = func2_start_vaddr + 0x11 - sframe_vaddr; + err = sframe_find_fre (dctx, lookup_pc, &frep); + TEST ("findfunc-1: Find FRE in FDE2", + (err == 0 && sframe_fre_get_cfa_offset (dctx, &frep, &err) == 0x12)); /* Find an FRE for PC in FDE3. */ - err = sframe_find_fre (dctx, (0xfffff10e + 0x10), &frep); - TEST("findfunc-1: Find FRE in FDE3", - ((err == 0) && (sframe_fre_get_cfa_offset(dctx, &frep, &err) == 0x18))); + lookup_pc = func3_start_vaddr + 0x10 - sframe_vaddr; + err = sframe_find_fre (dctx, lookup_pc, &frep); + TEST ("findfunc-1: Find FRE in FDE3", + (err == 0 && sframe_fre_get_cfa_offset (dctx, &frep, &err) == 0x18)); sframe_encoder_free (&encode); sframe_decoder_free (&dctx); +} - return 0; +int main (void) +{ + uint32_t sframe_vaddr = 0x4b5620; + uint32_t text_vaddr = 0x4038b0; + printf ("Testing with text_vaddr = %#x; sframe_vaddr = %#x\n", text_vaddr, + sframe_vaddr); + test_text_findfre (text_vaddr, sframe_vaddr); + + sframe_vaddr = 0x4038b0; + text_vaddr = 0x4b5620; + printf ("Testing with text_vaddr = %#x; sframe_vaddr = %#x\n", text_vaddr, + sframe_vaddr); + test_text_findfre (text_vaddr, sframe_vaddr); } 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-1.c b/libsframe/testsuite/libsframe.find/plt-findfre-1.c index c84b46f..91da4bc 100644 --- a/libsframe/testsuite/libsframe.find/plt-findfre-1.c +++ b/libsframe/testsuite/libsframe.find/plt-findfre-1.c @@ -28,12 +28,13 @@ #include <dejagnu.h> static int -add_plt_fde1 (sframe_encoder_ctx *ectx, int idx) +add_plt_fde1 (sframe_encoder_ctx *ectx, uint32_t plt_vaddr, + uint32_t sframe_vaddr, int idx) { - int i, err; /* A contiguous block containing 3 FREs. The start_ip_offset must remain less than 16 bytes. */ - sframe_frame_row_entry fres[] +#define PLT1_NUM_FRES 3 + sframe_frame_row_entry fres[PLT1_NUM_FRES] = { {0x0, {0x1, 0, 0}, 0x3}, {0x6, {0x2, 0xf0, 0}, 0x5}, {0xc, {0x3, 0xf0, 0}, 0x4} @@ -41,19 +42,29 @@ add_plt_fde1 (sframe_encoder_ctx *ectx, int idx) 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)); + /* 5 pltN entries of 16 bytes each. */ - err = sframe_encoder_add_funcdesc_v2 (ectx, 0x1000, 16*5, finfo, 16, 3); + int err = sframe_encoder_add_funcdesc_v2 (ectx, func_start_addr, + 16 * 5 /* func size in bytes. */, + finfo, + 16 /* rep block size in bytes. */, + PLT1_NUM_FRES); if (err == -1) return err; - for (i = 0; i < 3; i++) - if (sframe_encoder_add_fre (ectx, idx, fres+i) == SFRAME_ERR) + for (unsigned i = 0; i < PLT1_NUM_FRES; i++) + if (sframe_encoder_add_fre (ectx, idx, fres + i) == SFRAME_ERR) return -1; return 0; } -int main (void) +static +void test_plt_findfre (uint32_t plt_vaddr, uint32_t sframe_vaddr) { sframe_encoder_ctx *ectx; sframe_decoder_ctx *dctx; @@ -61,7 +72,7 @@ int main (void) char *sframe_buf; size_t sf_size; int err = 0; - unsigned int fde_cnt = 0; + uint32_t fde_cnt = 0; #define TEST(name, cond) \ do \ @@ -73,12 +84,13 @@ int main (void) } \ while (0) - ectx = sframe_encode (SFRAME_VERSION, 0, SFRAME_ABI_AMD64_ENDIAN_LITTLE, + ectx = sframe_encode (SFRAME_VERSION, SFRAME_F_FDE_FUNC_START_PCREL, + SFRAME_ABI_AMD64_ENDIAN_LITTLE, SFRAME_CFA_FIXED_FP_INVALID, -8, /* Fixed RA offset for AMD64. */ &err); - err = add_plt_fde1 (ectx, 0); + err = add_plt_fde1 (ectx, plt_vaddr, sframe_vaddr, 0); TEST ("plt-findfre-1: Adding FDE1 for plt", err == 0); fde_cnt = sframe_encoder_get_num_fidx (ectx); @@ -88,40 +100,57 @@ int main (void) TEST ("plt-findfre-1: Encoder write", err == 0); dctx = sframe_decode (sframe_buf, sf_size, &err); - TEST("plt-findfre-1: Decoder setup", dctx != NULL); + TEST ("plt-findfre-1: Decoder setup", dctx != NULL); /* Find the first FRE in PLT1. */ - err = sframe_find_fre (dctx, (0x1000 + 0x0), &frep); - TEST("plt-findfre-1: Find first FRE in PLT1", - ((err == 0) && (sframe_fre_get_cfa_offset (dctx, &frep, &err) == 0x1))); + err = sframe_find_fre (dctx, (plt_vaddr + 0x0 - sframe_vaddr), &frep); + TEST ("plt-findfre-1: Find first FRE in PLT1", + (err == 0 && sframe_fre_get_cfa_offset (dctx, &frep, &err) == 0x1)); /* Find the second FRE. */ - err = sframe_find_fre (dctx, (0x1000 + 0x6), &frep); - TEST("plt-findfre-1: Find second FRE in PLT1", - ((err == 0) && (sframe_fre_get_cfa_offset (dctx, &frep, &err) == 0x2))); + err = sframe_find_fre (dctx, (plt_vaddr + 0x6 - sframe_vaddr), &frep); + TEST ("plt-findfre-1: Find second FRE in PLT1", + (err == 0 && sframe_fre_get_cfa_offset (dctx, &frep, &err) == 0x2)); /* Find the last FRE. */ - err = sframe_find_fre (dctx, (0x1000 + 0xc), &frep); - TEST("plt-findfre-1: Find last FRE in PLT1", - ((err == 0) && (sframe_fre_get_cfa_offset (dctx, &frep, &err) == 0x3))); + err = sframe_find_fre (dctx, (plt_vaddr + 0xc - sframe_vaddr), &frep); + TEST ("plt-findfre-1: Find last FRE in PLT1", + (err == 0 && sframe_fre_get_cfa_offset (dctx, &frep, &err) == 0x3)); /* Find the first FRE in PLT4. */ - err = sframe_find_fre (dctx, (0x1000 + 16*3 + 0x0), &frep); - TEST("plt-findfre-1: Find first FRE in PLT4", - ((err == 0) && (sframe_fre_get_cfa_offset (dctx, &frep, &err) == 0x1))); + err = sframe_find_fre (dctx, (plt_vaddr + 16*3 + 0x0 - sframe_vaddr), &frep); + TEST ("plt-findfre-1: Find first FRE in PLT4", + (err == 0 && sframe_fre_get_cfa_offset (dctx, &frep, &err) == 0x1)); /* Find the second FRE in PLT4. */ - err = sframe_find_fre (dctx, (0x1000 + 16*3 + 0x6), &frep); - TEST("plt-findfre-1: Find second FRE in PLT4", - ((err == 0) && (sframe_fre_get_cfa_offset (dctx, &frep, &err) == 0x2))); + err = sframe_find_fre (dctx, (plt_vaddr + 16*3 + 0x6 - sframe_vaddr), &frep); + TEST ("plt-findfre-1: Find second FRE in PLT4", + (err == 0 && sframe_fre_get_cfa_offset (dctx, &frep, &err) == 0x2)); /* Find the last FRE in PLT4. */ - err = sframe_find_fre (dctx, (0x1000 + 16*3 + 0xc), &frep); - TEST("plt-findfre-1: Find last FRE in PLT4", - ((err == 0) && (sframe_fre_get_cfa_offset (dctx, &frep, &err) == 0x3))); + err = sframe_find_fre (dctx, (plt_vaddr + 16*3 + 0xc - sframe_vaddr), &frep); + TEST ("plt-findfre-1: Find last FRE in PLT4", + (err == 0 && sframe_fre_get_cfa_offset (dctx, &frep, &err) == 0x3)); + + /* Find no FRE for out of range PLT6. */ + err = sframe_find_fre (dctx, (plt_vaddr + 16*5 + 0x0 - sframe_vaddr), &frep); + TEST ("plt-findfre-1: Find no FRE for out of range PLT6", err != 0); sframe_encoder_free (&ectx); sframe_decoder_free (&dctx); +} - return 0; +int main (void) +{ + uint32_t sframe_vaddr = 0x402220; + uint32_t plt_vaddr = 0x401020; + printf ("Testing with plt_vaddr = %#x; sframe_vaddr = %#x\n", plt_vaddr, + sframe_vaddr); + test_plt_findfre (plt_vaddr, sframe_vaddr); + + sframe_vaddr = 0x401020; + plt_vaddr = 0x402220; + printf ("Testing with plt_vaddr = %#x; sframe_vaddr = %#x\n", plt_vaddr, + sframe_vaddr); + test_plt_findfre (plt_vaddr, sframe_vaddr); } 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; +} |