bug-gnulib
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[PATCH][gnulib] Add the Sframe package


From: Weimin Pan
Subject: [PATCH][gnulib] Add the Sframe package
Date: Tue, 15 Nov 2022 12:09:51 -0800

This patch adds two new modules to gnulib, related to the Simple Frame
format (SFrame) recently introduced in binutils [1].

The SFrame format (Simple Frame format) represents the minimal necessary
information for stack backtrace and it is stored in the .sframe section.
The format's detailed definition is in lib/sframe.h.  The main design
goals after the format are 1) to be simple and easy to decode and
implement and 2) to be compact.  The main use-case for this format are
"online" debugging tools like stack tracers (as opposed to full-fledged
"offline" debugging tools like source debuggers.)

The first module, sframe-header, provides a header file sframe.h with
the data structures comprising the format.

The second module, `sframe', provides a flexible and convenient
implementation of SFrame encoding and decoding.  This code is based on
the libsframe submitted to binutils, which is in turn used by
BFD/linker, and the plan is to switch the later to use this gnulib
module instead in order to minimize external dependencies.

[1] https://sourceware.org/pipermail/binutils/2022-October/123641.html

---
 ChangeLog                       |    3 +
 MODULES.html.sh                 |    2 +
 lib/sframe-api.h                |  229 ++++
 lib/sframe-internal.h           |   53 +
 lib/sframe.c                    | 1853 +++++++++++++++++++++++++++++++
 lib/sframe.h                    |  287 +++++
 modules/sframe                  |   30 +
 modules/sframe-header           |   23 +
 modules/sframe-tests            |   16 +
 tests/DATA-BE                   |  Bin 0 -> 64 bytes
 tests/DATA1                     |  Bin 0 -> 60 bytes
 tests/DATA2                     |  Bin 0 -> 92 bytes
 tests/sframe-api.h              |  229 ++++
 tests/test-sframe-be-flipping.c |  115 ++
 tests/test-sframe-encode1.c     |  187 ++++
 tests/test-sframe-frecnt1.c     |   99 ++
 tests/test-sframe-frecnt2.c     |  103 ++
 17 files changed, 3229 insertions(+)
 create mode 100644 lib/sframe-api.h
 create mode 100644 lib/sframe-internal.h
 create mode 100644 lib/sframe.c
 create mode 100644 lib/sframe.h
 create mode 100644 modules/sframe
 create mode 100644 modules/sframe-header
 create mode 100644 modules/sframe-tests
 create mode 100644 tests/DATA-BE
 create mode 100644 tests/DATA1
 create mode 100644 tests/DATA2
 create mode 100644 tests/sframe-api.h
 create mode 100644 tests/test-sframe-be-flipping.c
 create mode 100644 tests/test-sframe-encode1.c
 create mode 100644 tests/test-sframe-frecnt1.c
 create mode 100644 tests/test-sframe-frecnt2.c

diff --git a/ChangeLog b/ChangeLog
index 76a56c78f..0f16f24b2 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,6 @@
+2022-11-09  Weimin Pan  <weimin.pan@oracle.com>
+       Add the SFrame package.
+
 2022-10-16  Bruno Haible  <bruno@clisp.org>
 
        getdelim: Work around buggy implementation on macOS 10.13.
diff --git a/MODULES.html.sh b/MODULES.html.sh
index d48912b13..38a203d19 100755
--- a/MODULES.html.sh
+++ b/MODULES.html.sh
@@ -1935,6 +1935,8 @@ func_all_modules ()
   func_module linkedhash-list
   func_module avltreehash-list
   func_module rbtreehash-list
+  func_module sframe
+  func_module sframe-header
   func_module sublist
   func_module xsublist
   func_module oset
diff --git a/lib/sframe-api.h b/lib/sframe-api.h
new file mode 100644
index 000000000..254e9149e
--- /dev/null
+++ b/lib/sframe-api.h
@@ -0,0 +1,229 @@
+/* Public API to SFrame.
+
+   Copyright (C) 2022 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/>.  */
+
+#ifndef        _SFRAME_API_H
+#define        _SFRAME_API_H
+
+#include <sframe.h>
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+typedef struct sframe_decoder_ctx sframe_decoder_ctx;
+typedef struct sframe_encoder_ctx sframe_encoder_ctx;
+
+#define MAX_OFFSET_BYTES (SFRAME_FRE_OFFSET_4B * 2 * 3)
+
+/* User interfacing SFrame Row Entry.
+   An abstraction provided by SFrame so the consumer is decoupled from
+   the binary format representation of the same.  */
+
+typedef struct sframe_frame_row_entry
+{
+  uint32_t fre_start_addr;
+  unsigned char fre_info;
+  unsigned char fre_offsets[MAX_OFFSET_BYTES];
+} sframe_frame_row_entry;
+
+#define SFRAME_ERR ((int) -1)
+
+/* This macro holds information about all the available SFrame
+   errors.  It is used to form both an enum holding all the error
+   constants, and also the error strings themselves.  To use, define
+   _SFRAME_FIRST and _SFRAME_ITEM to expand as you like, then
+   mention the macro name.  See the enum after this for an example.  */
+#define _SFRAME_ERRORS \
+  _SFRAME_FIRST (SFRAME_ERR_VERSION_INVAL, "SFrame version not supported.") \
+  _SFRAME_ITEM (SFRAME_ERR_NOMEM, "Out of Memory.") \
+  _SFRAME_ITEM (SFRAME_ERR_INVAL, "Corrupt SFrame.") \
+  _SFRAME_ITEM (SFRAME_ERR_BUF_INVAL, "Buffer does not contain SFrame data.") \
+  _SFRAME_ITEM (SFRAME_ERR_DCTX_INVAL, "Corrupt SFrame decoder.") \
+  _SFRAME_ITEM (SFRAME_ERR_ECTX_INVAL, "Corrupt SFrame encoder.") \
+  _SFRAME_ITEM (SFRAME_ERR_FDE_INVAL, "Corrput FDE.") \
+  _SFRAME_ITEM (SFRAME_ERR_FRE_INVAL, "Corrupt FRE.") \
+  _SFRAME_ITEM (SFRAME_ERR_FDE_NOTFOUND,"FDE not found.") \
+  _SFRAME_ITEM (SFRAME_ERR_FDE_NOTSORTED, "FDEs not sorted.") \
+  _SFRAME_ITEM (SFRAME_ERR_FRE_NOTFOUND,"FRE not found.") \
+  _SFRAME_ITEM (SFRAME_ERR_FREOFFSET_NOPRESENT,"FRE offset not present.")
+
+#define        SFRAME_ERR_BASE 2000    /* Base value for SFrame errnos.  */
+
+enum
+  {
+#define _SFRAME_FIRST(NAME, STR) NAME = SFRAME_ERR_BASE
+#define _SFRAME_ITEM(NAME, STR) , NAME
+_SFRAME_ERRORS
+#undef _SFRAME_ITEM
+#undef _SFRAME_FIRST
+  };
+
+/* Count of SFrame errors.  */
+#define SFRAME_ERR_NERR (SFRAME_ERR_FREOFFSET_NOPRESENT - SFRAME_ERR_BASE + 1)
+
+/* Get the error message string.  */
+
+extern const char *
+sframe_errmsg (int error);
+
+/* Get FDE function info given a FRE_TYPE.  */
+
+extern unsigned char
+sframe_fde_func_info (unsigned int fre_type, unsigned int fde_type);
+
+/* Gather the FRE type given the function size.  */
+
+extern unsigned int
+sframe_calc_fre_type (unsigned int func_size);
+
+/* The SFrame Decoder.  */
+
+/* Decode the specified SFrame buffer CF_BUF of size CF_SIZE and return the
+   new SFrame decoder context.  Sets ERRP for the caller if any error.  */
+extern sframe_decoder_ctx *
+sframe_decode (const char *cf_buf, size_t cf_size, int *errp);
+
+/* Free the decoder context.  */
+extern void
+sframe_decoder_free (sframe_decoder_ctx **dctx);
+
+/* Get the size of the SFrame header from the decoder context DCTX.  */
+extern unsigned int
+sframe_decoder_get_hdr_size (sframe_decoder_ctx *dctx);
+
+/* Get the SFrame's abi/arch info.  */
+extern unsigned char
+sframe_decoder_get_abi_arch (sframe_decoder_ctx *dctx);
+
+/* Return the number of function descriptor entries in the SFrame decoder
+   DCTX.  */
+unsigned int
+sframe_decoder_get_num_fidx (sframe_decoder_ctx *dctx);
+
+/* Get the fixed FP offset from the decoder context DCTX.  */
+extern int8_t
+sframe_decoder_get_fixed_fp_offset (sframe_decoder_ctx *dctx);
+
+/* Get the fixed RA offset from the decoder context DCTX.  */
+extern int8_t
+sframe_decoder_get_fixed_ra_offset (sframe_decoder_ctx *dctx);
+
+/* Find the function descriptor entry which contains the specified address.  */
+extern sframe_func_desc_entry *
+sframe_get_funcdesc_with_addr (sframe_decoder_ctx *dctx,
+                              int32_t addr, int *errp);
+
+/* Find the SFrame Frame Row Entry which contains the PC.  Returns
+   SFRAME_ERR if failure.  */
+
+extern int
+sframe_find_fre (sframe_decoder_ctx *ctx, int32_t pc,
+                sframe_frame_row_entry *frep);
+
+/* Get the FRE_IDX'th FRE of the function at FUNC_IDX'th function
+   index entry in the SFrame decoder CTX.  Returns error code as
+   applicable.  */
+extern int
+sframe_decoder_get_fre (sframe_decoder_ctx *ctx,
+                       unsigned int func_idx,
+                       unsigned int fre_idx,
+                       sframe_frame_row_entry *fre);
+
+/* Get the data (NUM_FRES, FUNC_START_ADDRESS) from the function
+   descriptor entry at index I'th in the decoder CTX.  If failed,
+   return error code.  */
+extern int
+sframe_decoder_get_funcdesc (sframe_decoder_ctx *ctx,
+                            unsigned int i,
+                            uint32_t *num_fres,
+                            uint32_t *func_size,
+                            int32_t *func_start_address,
+                            unsigned char *func_info);
+
+/* SFrame textual dump.  */
+extern void
+dump_sframe (sframe_decoder_ctx *decoder, uint64_t addr);
+
+/* Get the base reg id from the FRE info.  Sets errp if fails.  */
+extern unsigned int
+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.  */
+extern int32_t
+sframe_fre_get_cfa_offset (sframe_frame_row_entry *fre, int *errp);
+
+/* Get the FP offset from the FRE.  If the offset is invalid, sets errp.  */
+extern int32_t
+sframe_fre_get_fp_offset (sframe_frame_row_entry *fre, int *errp);
+
+/* Get the RA offset from the FRE.  If the offset is invalid, sets errp.  */
+extern int32_t
+sframe_fre_get_ra_offset (sframe_frame_row_entry *fre, int *errp);
+
+/* The SFrame Encoder.  */
+
+/* Create an encoder context with the given SFrame format version VER, FLAGS
+   and ABI information.  Sets errp if failure.  */
+extern sframe_encoder_ctx *
+sframe_encode (unsigned char ver, unsigned char flags, int abi,
+              int8_t fixed_fp_offset, int8_t fixed_ra_offset, int *errp);
+
+/* Free the encoder context.  */
+extern void
+sframe_encoder_free (sframe_encoder_ctx **encoder);
+
+/* Get the size of the SFrame header from the encoder ctx ENCODER.  */
+extern unsigned int
+sframe_encoder_get_hdr_size (sframe_encoder_ctx *encoder);
+
+/* Get the abi/arch info from the SFrame encoder context CTX.  */
+extern unsigned char
+sframe_encoder_get_abi_arch (sframe_encoder_ctx *encoder);
+
+/* Return the number of function descriptor entries in the SFrame encoder
+   ENCODER.  */
+extern unsigned int
+sframe_encoder_get_num_fidx (sframe_encoder_ctx *encoder);
+
+/* Add an FRE to function at FUNC_IDX'th function descriptor index entry in
+   the encoder context.  */
+extern int
+sframe_encoder_add_fre (sframe_encoder_ctx *encoder,
+                       unsigned int func_idx,
+                       sframe_frame_row_entry *frep);
+
+/* Add a new function descriptor entry with START_ADDR, FUNC_SIZE and NUM_FRES
+   to the encoder.  */
+extern int
+sframe_encoder_add_funcdesc (sframe_encoder_ctx *encoder,
+                            int32_t start_addr,
+                            uint32_t func_size,
+                            unsigned char func_info,
+                            uint32_t num_fres);
+
+/* Serialize the contents of the encoder and return the buffer.  ENCODED_SIZE
+   is updated to the size of the buffer.  Sets ERRP if failure.  */
+extern char  *
+sframe_encoder_write (sframe_encoder_ctx *encoder,
+                     size_t *encoded_size, int *errp);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif                         /* _SFRAME_API_H */
diff --git a/lib/sframe-internal.h b/lib/sframe-internal.h
new file mode 100644
index 000000000..af4939ebc
--- /dev/null
+++ b/lib/sframe-internal.h
@@ -0,0 +1,53 @@
+/* Implementation header.
+
+   Copyright (C) 2022 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/>.  */
+
+#ifndef _SFRAME_IMPL_H
+#define _SFRAME_IMPL_H
+
+#include "sframe-api.h"
+
+#ifdef  __cplusplus
+extern "C"
+{
+#endif
+
+#include <assert.h>
+#define sframe_assert(expr) (assert (expr))
+
+struct sframe_decoder_ctx
+{
+  sframe_header sfd_header;          /* SFrame header.  */
+  uint32_t *sfd_funcdesc;            /* SFrame function desc entries table.  */
+  void *sfd_fres;                    /* SFrame FRE table.  */
+  int sfd_fre_nbytes;                /* Number of bytes needed for SFrame 
FREs.  */
+};
+
+struct sframe_encoder_ctx
+{
+  sframe_header sfe_header;            /* SFrame header.  */
+  uint32_t *sfe_funcdesc;              /* SFrame function desc entries table.  
*/
+  sframe_frame_row_entry *sfe_fres;    /* SFrame FRE table.  */
+  uint32_t sfe_fre_nbytes;             /* Number of bytes needed for SFrame 
FREs.  */
+  char *sfe_data;                      /* SFrame data buffer.  */
+  size_t sfe_data_size;                        /* Size of the SFrame data 
buffer.  */
+};
+
+#ifdef  __cplusplus
+}
+#endif
+
+#endif /* _SFRAME_IMPL_H */
diff --git a/lib/sframe.c b/lib/sframe.c
new file mode 100644
index 000000000..74990dc7d
--- /dev/null
+++ b/lib/sframe.c
@@ -0,0 +1,1853 @@
+/* sframe.c - SFrame decoder/encoder.
+
+   Copyright (C) 2022 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 <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include "sframe-internal.h"
+#include <byteswap.h>
+
+/* Textual dump of .sframe.  */
+
+#define SFRAME_HEADER_FLAGS_STR_MAX_LEN 50
+
+static void
+dump_sframe_header (sframe_decoder_ctx *sfd_ctx)
+{
+  const char *verstr = NULL;
+  const sframe_header *header = &(sfd_ctx->sfd_header);
+
+  /* Prepare SFrame section version string.  */
+  const char *version_names[]
+    = { "NULL",
+       "SFRAME_VERSION_1" };
+  unsigned char ver = header->sfh_preamble.sfp_version;
+  if (ver <= SFRAME_VERSION)
+    verstr = version_names[ver];
+
+  /* Prepare SFrame section flags string.  */
+  unsigned char flags = header->sfh_preamble.sfp_flags;
+  char *flags_str
+    = (char*) calloc (sizeof (char), SFRAME_HEADER_FLAGS_STR_MAX_LEN);
+  if (flags)
+    {
+      const char *flag_names[]
+       = { "SFRAME_F_FDE_SORTED",
+           "SFRAME_F_FRAME_POINTER" };
+      unsigned char flags = header->sfh_preamble.sfp_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");
+
+  const char* subsec_name = "Header";
+  printf ("\n");
+  printf ("  %s :\n", subsec_name);
+  printf ("\n");
+  printf ("    Version: %s\n", verstr);
+  printf ("    Flags: %s\n", flags_str);
+  printf ("    Num FDEs: %d\n", header->sfh_num_fdes);
+  printf ("    Num FREs: %d\n", header->sfh_num_fres);
+
+  free (flags_str);
+}
+
+static void
+dump_sframe_func_with_fres (sframe_decoder_ctx *sfd_ctx,
+                           unsigned int funcidx,
+                           uint64_t sec_addr)
+{
+  uint32_t j = 0;
+  uint32_t num_fres = 0;
+  uint32_t func_size = 0;
+  int32_t func_start_address = 0;
+  unsigned char func_info = 0;
+
+  uint64_t func_start_pc_vma = 0;
+  uint64_t fre_start_pc_vma = 0;
+  const char *base_reg_str[] = {"fp", "sp"};
+  int32_t cfa_offset = 0;
+  int32_t fp_offset = 0;
+  int32_t ra_offset = 0;
+  unsigned int base_reg_id = 0;
+  int err[3] = {0, 0, 0};
+
+  sframe_frame_row_entry fre;
+
+  /* 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.  */
+  func_start_pc_vma = func_start_address + sec_addr;
+
+  /* Mark FDEs with [m] where the FRE start address is interpreted as a
+     mask.  */
+  int fde_type_addrmask_p = (SFRAME_V1_FUNC_FDE_TYPE (func_info)
+                            == SFRAME_FDE_TYPE_PCMASK);
+  const char *fde_type_marker
+    = (fde_type_addrmask_p ? "[m]" : "   ");
+
+  printf ("\n    func idx [%d]: pc = 0x%lx, size = %d bytes",
+         funcidx,
+         func_start_pc_vma,
+         func_size);
+
+  char temp[100];
+  memset (temp, 0, 100);
+
+  printf ("\n    %-7s%-8s %-10s%-10s%-10s", "STARTPC", fde_type_marker, "CFA", 
"FP", "RA");
+  for (j = 0; j < num_fres; j++)
+    {
+      sframe_decoder_get_fre (sfd_ctx, funcidx, j, &fre);
+
+      fre_start_pc_vma = (fde_type_addrmask_p
+                         ? fre.fre_start_addr
+                         : func_start_pc_vma + fre.fre_start_addr);
+
+      /* FIXME - fixup the err caching in array.
+        assert no error for base reg id.  */
+      base_reg_id = sframe_fre_get_base_reg_id (&fre, &err[0]);
+      cfa_offset = sframe_fre_get_cfa_offset (&fre, &err[0]);
+      fp_offset = sframe_fre_get_fp_offset (&fre, &err[1]);
+      ra_offset = sframe_fre_get_ra_offset (&fre, &err[2]);
+
+      /* Dump CFA info.  */
+      printf ("\n");
+      printf ("    %016lx", fre_start_pc_vma);
+      sprintf (temp, "%s+%d", base_reg_str[base_reg_id], cfa_offset);
+      printf ("  %-10s", temp);
+
+      /* Dump SP/FP info.  */
+      memset (temp, 0, 100);
+      if (err[1] == 0)
+       sprintf (temp, "c%+d", fp_offset);
+      else
+       strcpy (temp, "u");
+      printf ("%-10s", temp);
+
+      /* Dump RA info.  */
+      memset (temp, 0, 100);
+      if (err[2] == 0)
+       sprintf (temp, "c%+d", ra_offset);
+      else
+       strcpy (temp, "u");
+      printf ("%-10s", temp);
+    }
+}
+
+static void
+dump_sframe_functions (sframe_decoder_ctx *sfd_ctx, uint64_t sec_addr)
+{
+  uint32_t i;
+  uint32_t num_fdes;
+
+  const char* subsec_name = "Function Index";
+  printf ("\n  %s :\n", subsec_name);
+
+  num_fdes = sframe_decoder_get_num_fidx (sfd_ctx);
+  for (i = 0; i < num_fdes; i++)
+    {
+      dump_sframe_func_with_fres (sfd_ctx, i, sec_addr);
+      printf ("\n");
+    }
+}
+
+void
+dump_sframe (sframe_decoder_ctx *sfd_ctx, uint64_t sec_addr)
+{
+  dump_sframe_header (sfd_ctx);
+  dump_sframe_functions (sfd_ctx, sec_addr);
+}
+
+/* We want to treat the first item of the SFrame error macro
+   like subsequent items.  */
+#define _SFRAME_FIRST(NAME, VALUE) _SFRAME_ITEM(NAME, VALUE)
+
+/* The error message strings, each in a unique structure member precisely big
+   enough for that error, plus a str member to access them all as a string
+   table.  */
+
+static const char *const _sframe_errlist[] = {
+#define _SFRAME_ITEM(n, s) s,
+_SFRAME_ERRORS
+#undef _SFRAME_ITEM
+};
+
+const char *
+sframe_errmsg (int error)
+{
+  const char *str;
+
+  if (error >= SFRAME_ERR_BASE && (error - SFRAME_ERR_BASE) < SFRAME_ERR_NERR)
+    str = _sframe_errlist[error - SFRAME_ERR_BASE];
+  else
+    str = (const char *) strerror (error);
+
+  return (str ? str : "Unknown error");
+}
+
+/* Swap the endianness of something.  */
+
+#define swap_thing(x)                                                  \
+  do                                                                   \
+    {                                                                  \
+      _Static_assert (sizeof (x) == 1 || (sizeof (x) % 2 == 0          \
+                                         && sizeof (x) <= 8),          \
+                     "Invalid size, update endianness code");          \
+      switch (sizeof (x)) {                                            \
+      case 2: x = bswap_16 (x); break;                                 \
+      case 4: x = bswap_32 (x); break;                                 \
+      case 8: x = bswap_64 (x); break;                                 \
+      case 1: /* Nothing needs doing */                                        
\
+       break;                                                          \
+      }                                                                        
\
+    }                                                                  \
+  while (0);
+
+typedef struct sf_funidx_tbl
+{
+  unsigned int count;
+  unsigned int alloced;
+  sframe_func_desc_entry entry[1];
+} sf_funidx_tbl;
+
+typedef struct sf_fre_tbl
+{
+  unsigned int count;
+  unsigned int alloced;
+  sframe_frame_row_entry entry[1];
+} sf_fre_tbl;
+
+#define _sf_printflike_(string_index,first_to_check) \
+    __attribute__ ((__format__ (__printf__, (string_index), (first_to_check))))
+
+static void debug_printf (const char *, ...);
+
+static int _sframe_debug;      /* Control for printing out debug info.  */
+static int number_of_entries = 64;
+
+static void
+sframe_init_debug (void)
+{
+  static int inited;
+
+  if (!inited)
+    {
+      _sframe_debug = getenv ("SFRAME_DEBUG") != NULL;
+      inited = 1;
+    }
+}
+
+_sf_printflike_ (1, 2)
+static void debug_printf (const char *format, ...)
+{
+  if (_sframe_debug)
+    {
+      va_list args;
+
+      va_start (args, format);
+      vfprintf (stderr, format, args);
+      va_end (args);
+    }
+}
+
+/* Generate bitmask of given size in bytes.  This is used for
+   some checks on the FRE start address.
+   SFRAME_FRE_TYPE_ADDR1 => 1 byte => [ bitmask = 0xff ]
+   SFRAME_FRE_TYPE_ADDR2 => 2 byte => [ bitmask = 0xffff ]
+   SFRAME_FRE_TYPE_ADDR4 => 4 byte => [ bitmask = 0xffffffff ].  */
+#define SFRAME_BITMASK_OF_SIZE(size_in_bytes) \
+  (((uint64_t)1 << (size_in_bytes*8)) - 1)
+
+/* Store the specified error code into errp if it is non-NULL.
+   Return SFRAME_ERR.  */
+
+static int
+sframe_set_errno (int *errp, int error)
+{
+  if (errp != NULL)
+    *errp = error;
+  return SFRAME_ERR;
+}
+
+/* Store the specified error code into errp if it is non-NULL.
+   Return NULL.  */
+
+static void *
+sframe_ret_set_errno (int *errp, int error)
+{
+  if (errp != NULL)
+    *errp = error;
+  return NULL;
+}
+
+/* Get the SFrame header size.  */
+
+static uint32_t
+sframe_get_hdr_size (sframe_header *sfh)
+{
+  return SFRAME_V1_HDR_SIZE (*sfh);
+}
+
+/* Access functions for frame row entry data.  */
+
+static unsigned int
+sframe_fre_get_offset_count (unsigned char fre_info)
+{
+  return SFRAME_V1_FRE_OFFSET_COUNT (fre_info);
+}
+
+static unsigned int
+sframe_fre_get_offset_size (unsigned char fre_info)
+{
+  return SFRAME_V1_FRE_OFFSET_SIZE (fre_info);
+}
+
+/* Access functions for info from function descriptor entry.  */
+
+static unsigned int
+sframe_get_fre_type (sframe_func_desc_entry *fdep)
+{
+  unsigned int fre_type = 0;
+  if (fdep)
+    fre_type = SFRAME_V1_FUNC_FRE_TYPE (fdep->sfde_func_info);
+  return fre_type;
+}
+
+static unsigned int
+sframe_get_fde_type (sframe_func_desc_entry *fdep)
+{
+  unsigned int fde_type = 0;
+  if (fdep)
+    fde_type = SFRAME_V1_FUNC_FDE_TYPE (fdep->sfde_func_info);
+  return fde_type;
+}
+
+/* Check if flipping is needed, based on ENDIAN.  */
+
+static int
+need_swapping (int endian)
+{
+  unsigned int ui = 1;
+  char *c = (char *)&ui;
+  int is_little = (int)*c;
+
+  switch (endian)
+    {
+      case SFRAME_ABI_AARCH64_ENDIAN_LITTLE:
+      case SFRAME_ABI_AMD64_ENDIAN_LITTLE:
+       return !is_little;
+      case SFRAME_ABI_AARCH64_ENDIAN_BIG:
+       return is_little;
+      default:
+       break;
+    }
+
+  return 0;
+}
+
+/* Flip the endianness of the SFrame header.  */
+
+static void
+flip_header (sframe_header *sfheader)
+{
+  swap_thing (sfheader->sfh_preamble.sfp_magic);
+  swap_thing (sfheader->sfh_preamble.sfp_version);
+  swap_thing (sfheader->sfh_preamble.sfp_flags);
+  swap_thing (sfheader->sfh_cfa_fixed_fp_offset);
+  swap_thing (sfheader->sfh_cfa_fixed_ra_offset);
+  swap_thing (sfheader->sfh_num_fdes);
+  swap_thing (sfheader->sfh_num_fres);
+  swap_thing (sfheader->sfh_fre_len);
+  swap_thing (sfheader->sfh_fdeoff);
+  swap_thing (sfheader->sfh_freoff);
+}
+
+static void
+flip_fde (sframe_func_desc_entry *fdep)
+{
+  swap_thing (fdep->sfde_func_start_address);
+  swap_thing (fdep->sfde_func_size);
+  swap_thing (fdep->sfde_func_start_fre_off);
+  swap_thing (fdep->sfde_func_num_fres);
+}
+
+/* Check if SFrame header has valid data.  */
+
+static int
+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)
+      || ((hp->sfh_preamble.sfp_flags | all_flags)
+         != all_flags))
+    return 0;
+
+  /* Check offsets are valid.  */
+  if (hp->sfh_fdeoff > hp->sfh_freoff)
+    return 0;
+
+  return 1;
+}
+
+/* Flip the start address pointed to by FP.  */
+
+static void
+flip_fre_start_address (char *fp, unsigned int fre_type)
+{
+  void *start = (void*)fp;
+  if (fre_type == SFRAME_FRE_TYPE_ADDR2)
+    {
+      unsigned short *start_addr = (unsigned short *)(start);
+      swap_thing (*start_addr);
+    }
+  else if (fre_type == SFRAME_FRE_TYPE_ADDR4)
+    {
+      uint32_t *start_addr = (uint32_t *)(start);
+      swap_thing (*start_addr);
+    }
+}
+
+static void
+flip_fre_stack_offsets (char *fp, unsigned char offset_size,
+                       unsigned char offset_cnt)
+{
+  int j;
+  void *offsets = (void *)fp;
+
+  if (offset_size == SFRAME_FRE_OFFSET_2B)
+    {
+      unsigned short *ust = (unsigned short *)offsets;
+      for (j = offset_cnt; j > 0; ust++, j--)
+       swap_thing (*ust);
+    }
+  else if (offset_size == SFRAME_FRE_OFFSET_4B)
+    {
+      uint32_t *uit = (uint32_t *)offsets;
+      for (j = offset_cnt; j > 0; uit++, j--)
+       swap_thing (*uit);
+    }
+}
+
+/* Get the FRE start address size, given the FRE_TYPE.  */
+
+static size_t
+sframe_fre_start_addr_size (unsigned int fre_type)
+{
+  size_t addr_size = 0;
+  switch (fre_type)
+    {
+    case SFRAME_FRE_TYPE_ADDR1:
+      addr_size = 1;
+      break;
+    case SFRAME_FRE_TYPE_ADDR2:
+      addr_size = 2;
+      break;
+    case SFRAME_FRE_TYPE_ADDR4:
+      addr_size = 4;
+      break;
+    default:
+      /* No other value is expected.  */
+      sframe_assert (0);
+      break;
+    }
+  return addr_size;
+}
+
+/* Check if the FREP has valid data.  */
+
+static int
+sframe_fre_sanity_check_p (sframe_frame_row_entry *frep)
+{
+  unsigned int offset_size, offset_cnt;
+  unsigned int fre_info;
+
+  if (frep == NULL)
+    return 0;
+
+  fre_info = frep->fre_info;
+  offset_size = sframe_fre_get_offset_size (fre_info);
+
+  if (offset_size != SFRAME_FRE_OFFSET_1B
+      && offset_size != SFRAME_FRE_OFFSET_2B
+      && offset_size != SFRAME_FRE_OFFSET_4B)
+    return 0;
+
+  offset_cnt = sframe_fre_get_offset_count (fre_info);
+  if (offset_cnt > 3)
+    return 0;
+
+  return 1;
+}
+
+/* Get FRE_INFO's offset size in bytes.  */
+
+static size_t
+sframe_fre_offset_bytes_size (unsigned char fre_info)
+{
+  unsigned int offset_size, offset_cnt;
+
+  offset_size = sframe_fre_get_offset_size (fre_info);
+
+  debug_printf ("offset_size =  %u\n", offset_size);
+
+  offset_cnt = sframe_fre_get_offset_count (fre_info);
+
+  if (offset_size == SFRAME_FRE_OFFSET_2B
+      || offset_size == SFRAME_FRE_OFFSET_4B)  /* 2 or 4 bytes.  */
+    return (offset_cnt * (offset_size * 2));
+
+  return (offset_cnt);
+}
+
+/* Get total size in bytes to represent FREP in the binary format.  This
+   includes the starting address, FRE info, and all the offsets.  */
+
+static size_t
+sframe_fre_entry_size (sframe_frame_row_entry *frep, unsigned int fre_type)
+{
+  if (frep == NULL)
+    return 0;
+
+  unsigned char fre_info = frep->fre_info;
+  size_t addr_size = sframe_fre_start_addr_size (fre_type);
+
+  return (addr_size + sizeof (frep->fre_info)
+         + sframe_fre_offset_bytes_size (fre_info));
+}
+
+static int
+flip_fre (char *fp, unsigned int fre_type, size_t *fre_size)
+{
+  unsigned char fre_info;
+  unsigned int offset_size, offset_cnt;
+  size_t addr_size, fre_info_size = 0;
+  int err = 0;
+
+  if (fre_size == NULL)
+    return sframe_set_errno (&err, SFRAME_ERR_INVAL);
+
+  flip_fre_start_address (fp, fre_type);
+
+  /* Advance the buffer pointer to where the FRE info is.  */
+  addr_size = sframe_fre_start_addr_size (fre_type);
+  fp += addr_size;
+
+  /* FRE info is unsigned char.  No need to flip.  */
+  fre_info = *(unsigned char*)fp;
+  offset_size = sframe_fre_get_offset_size (fre_info);
+  offset_cnt = sframe_fre_get_offset_count (fre_info);
+
+  /* Advance the buffer pointer to where the stack offsets are.  */
+  fre_info_size = sizeof (unsigned char);
+  fp += fre_info_size;
+  flip_fre_stack_offsets (fp, offset_size, offset_cnt);
+
+  *fre_size
+    = addr_size + fre_info_size + sframe_fre_offset_bytes_size (fre_info);
+
+  return 0;
+}
+
+/* Endian flip the contents of FRAME_BUF of size BUF_SIZE.
+   The SFrame header in the FRAME_BUF must be endian flipped prior to
+   calling flip_sframe.
+
+   Endian flipping at decode time vs encode time have different needs.  At
+   encode time, the frame_buf is in host endianness, and hence, values should
+   be read up before the buffer is changed to foreign endianness.  This change
+   of behaviour is specified via TO_FOREIGN arg.
+
+   If an error code is returned, the buffer should not be used.  */
+
+static int
+flip_sframe (char *frame_buf, size_t buf_size, uint32_t to_foreign)
+{
+  unsigned int i, j, prev_frep_index;
+  sframe_header *ihp;
+  char *fdes;
+  char *fp = NULL;
+  sframe_func_desc_entry *fdep;
+  unsigned int num_fdes, num_fres;
+  unsigned int fre_type;
+  uint32_t fre_offset;
+  size_t esz;
+  int err = 0;
+
+  /* Header must be in host endianness at this time.  */
+  ihp = (sframe_header *)frame_buf;
+
+  if (!sframe_header_sanity_check_p (ihp))
+    return sframe_set_errno (&err, SFRAME_ERR_BUF_INVAL);
+
+  /* The contents of the SFrame header are safe to read.  Get the number of
+     FDEs and the first FDE in the buffer.  */
+  num_fdes = ihp->sfh_num_fdes;
+  fdes = frame_buf + sframe_get_hdr_size (ihp) + ihp->sfh_fdeoff;
+  fdep = (sframe_func_desc_entry *)fdes;
+
+  j = 0;
+  prev_frep_index = 0;
+  for (i = 0; i < num_fdes; fdep++, i++)
+    {
+      if (to_foreign)
+       {
+         num_fres = fdep->sfde_func_num_fres;
+         fre_type = sframe_get_fre_type (fdep);
+         fre_offset = fdep->sfde_func_start_fre_off;
+       }
+
+      flip_fde (fdep);
+
+      if (!to_foreign)
+       {
+         num_fres = fdep->sfde_func_num_fres;
+         fre_type = sframe_get_fre_type (fdep);
+         fre_offset = fdep->sfde_func_start_fre_off;
+       }
+
+      fp = frame_buf + sframe_get_hdr_size (ihp) + ihp->sfh_freoff;
+      fp += fre_offset;
+      for (; j < prev_frep_index + num_fres; j++)
+       {
+         if (flip_fre (fp, fre_type, &esz))
+           goto bad;
+
+         if (esz == 0)
+           goto bad;
+         fp += esz;
+       }
+      prev_frep_index = j;
+    }
+  /* All FREs must have been endian flipped by now.  */
+  if (j != ihp->sfh_num_fres)
+    goto bad;
+  /* Contents, if any, must have been processed by now.
+     Recall that .sframe section with just a SFrame header may be generated by
+     GAS if no SFrame FDEs were found for the input file.  */
+  if (ihp->sfh_num_fres && ((frame_buf + buf_size) != (void*)fp))
+    goto bad;
+
+  /* Success.  */
+  return 0;
+bad:
+  return SFRAME_ERR;
+}
+
+/* The SFrame Decoder.  */
+
+/* Compare function for qsort'ing the FDE table.  */
+
+static int
+fde_func (const void *p1, const void *p2)
+{
+  const sframe_func_desc_entry *aa = p1;
+  const sframe_func_desc_entry *bb = p2;
+
+  if (aa->sfde_func_start_address < bb->sfde_func_start_address)
+    return -1;
+  else if (aa->sfde_func_start_address > bb->sfde_func_start_address)
+    return 1;
+  return 0;
+}
+
+/* Get IDX'th offset from FRE.  Set errp as applicable.  */
+
+static int32_t
+sframe_get_fre_offset (sframe_frame_row_entry *fre, int idx, int *errp)
+{
+  int offset_cnt, offset_size;
+
+  if (fre == NULL || !sframe_fre_sanity_check_p (fre))
+    return sframe_set_errno (errp, SFRAME_ERR_FRE_INVAL);
+
+  offset_cnt = sframe_fre_get_offset_count (fre->fre_info);
+  offset_size = sframe_fre_get_offset_size (fre->fre_info);
+
+  if (offset_cnt < idx + 1)
+    return sframe_set_errno (errp, SFRAME_ERR_FREOFFSET_NOPRESENT);
+
+  if (errp)
+    *errp = 0; /* Offset Valid.  */
+
+  if (offset_size == SFRAME_FRE_OFFSET_1B)
+    {
+      int8_t *sp = (int8_t *)fre->fre_offsets;
+      return sp[idx];
+    }
+  else if (offset_size == SFRAME_FRE_OFFSET_2B)
+    {
+      int16_t *sp = (int16_t *)fre->fre_offsets;
+      return sp[idx];
+    }
+  else
+    {
+      int32_t *ip = (int32_t *)fre->fre_offsets;
+      return ip[idx];
+    }
+}
+
+/* Free the decoder context.  */
+
+void
+sframe_decoder_free (sframe_decoder_ctx **decoder)
+{
+  if (decoder != NULL)
+    {
+      sframe_decoder_ctx *dctx = *decoder;
+      if (dctx == NULL)
+       return;
+
+      if (dctx->sfd_funcdesc != NULL)
+       {
+         free (dctx->sfd_funcdesc);
+         dctx->sfd_funcdesc = NULL;
+       }
+      if (dctx->sfd_fres != NULL)
+       {
+         free (dctx->sfd_fres);
+         dctx->sfd_fres = NULL;
+       }
+
+      free (*decoder);
+      *decoder = NULL;
+    }
+}
+
+/* Create a FDE function info byte given an FRE_TYPE and an FDE_TYPE.  */
+/* FIXME API for linker.  Revisit if its better placed somewhere else?  */
+
+unsigned char
+sframe_fde_func_info (unsigned int fre_type,
+                     unsigned int fde_type)
+{
+  unsigned char func_info;
+  sframe_assert (fre_type == SFRAME_FRE_TYPE_ADDR1
+                  || fre_type == SFRAME_FRE_TYPE_ADDR2
+                  || fre_type == SFRAME_FRE_TYPE_ADDR4);
+  sframe_assert (fde_type == SFRAME_FDE_TYPE_PCINC
+                   || fde_type == SFRAME_FDE_TYPE_PCMASK);
+  func_info = SFRAME_V1_FUNC_INFO (fde_type, fre_type);
+  return func_info;
+}
+
+/* Get the FRE type given the function size.  */
+/* FIXME API for linker.  Revisit if its better placed somewhere else?  */
+
+unsigned int
+sframe_calc_fre_type (unsigned int func_size)
+{
+  unsigned int fre_type = 0;
+  if (func_size <= 0xff)
+    fre_type = SFRAME_FRE_TYPE_ADDR1;
+  else if (func_size <= 0xffff)
+    fre_type = SFRAME_FRE_TYPE_ADDR2;
+  else if (func_size <= 0xffffffff)
+    fre_type = SFRAME_FRE_TYPE_ADDR4;
+  return fre_type;
+}
+
+/* Get the base reg id from the FRE info.  Set errp if failure.  */
+
+unsigned int
+sframe_fre_get_base_reg_id (sframe_frame_row_entry *fre, int *errp)
+{
+  if (fre == NULL)
+    return sframe_set_errno (errp, SFRAME_ERR_FRE_INVAL);
+
+  unsigned int fre_info = fre->fre_info;
+  return SFRAME_V1_FRE_CFA_BASE_REG_ID (fre_info);
+}
+
+/* Get the CFA offset from the FRE.  If the offset is invalid, sets errp.  */
+
+int32_t
+sframe_fre_get_cfa_offset (sframe_frame_row_entry *fre, int *errp)
+{
+  return sframe_get_fre_offset (fre, SFRAME_FRE_CFA_OFFSET_IDX, errp);
+}
+
+/* Get the FP offset from the FRE.  If the offset is invalid, sets errp.  */
+
+int32_t
+sframe_fre_get_fp_offset (sframe_frame_row_entry *fre, int *errp)
+{
+  return sframe_get_fre_offset (fre, SFRAME_FRE_FP_OFFSET_IDX, errp);
+}
+
+/* Get the RA offset from the FRE.  If the offset is invalid, sets errp.  */
+
+int32_t
+sframe_fre_get_ra_offset (sframe_frame_row_entry *fre, int *errp)
+{
+  return sframe_get_fre_offset (fre, SFRAME_FRE_RA_OFFSET_IDX, errp);
+}
+
+static int
+sframe_frame_row_entry_copy (sframe_frame_row_entry *dst, 
sframe_frame_row_entry *src)
+{
+  int err = 0;
+
+  if (dst == NULL || src == NULL)
+    return sframe_set_errno (&err, SFRAME_ERR_INVAL);
+
+  memcpy (dst, src, sizeof (sframe_frame_row_entry));
+  return 0;
+}
+
+static int
+sframe_decode_fre_start_address (const char *fre_buf,
+                                uint32_t *fre_start_addr,
+                                unsigned int fre_type)
+{
+  uint32_t saddr = 0;
+  int err = 0;
+
+  if (fre_type == SFRAME_FRE_TYPE_ADDR1)
+    {
+      uint8_t *uc = (uint8_t *)fre_buf;
+      saddr = (uint32_t)*uc;
+    }
+  else if (fre_type == SFRAME_FRE_TYPE_ADDR2)
+    {
+      uint16_t *ust = (uint16_t *)fre_buf;
+      saddr = (uint32_t)*ust;
+    }
+  else if (fre_type == SFRAME_FRE_TYPE_ADDR4)
+    {
+      uint32_t *uit = (uint32_t *)fre_buf;
+      saddr = (uint32_t)*uit;
+    }
+  else
+    return sframe_set_errno (&err, SFRAME_ERR_INVAL);
+
+  *fre_start_addr = saddr;
+  return 0;
+}
+
+/* Decode a frame row entry FRE which starts at location FRE_BUF.  The function
+   updates ESZ to the size of the FRE as stored in the binary format.
+
+   This function works closely with the SFrame binary format.
+
+   Returns SFRAME_ERR if failure.  */
+
+static int
+sframe_decode_fre (const char *fre_buf, sframe_frame_row_entry *fre,
+                  unsigned int fre_type,
+                  size_t *esz)
+{
+  int err = 0;
+  void *stack_offsets = NULL;
+  size_t stack_offsets_sz;
+  size_t addr_size;
+  size_t fre_size;
+
+  if (fre_buf == NULL || fre == NULL || esz == NULL)
+    return sframe_set_errno (&err, SFRAME_ERR_INVAL);
+
+  /* Copy over the FRE start address.  */
+  sframe_decode_fre_start_address (fre_buf, &fre->fre_start_addr, fre_type);
+
+  addr_size = sframe_fre_start_addr_size (fre_type);
+  fre->fre_info = *(unsigned char *)(fre_buf + addr_size);
+  /* Sanity check as the API works closely with the binary format.  */
+  sframe_assert (sizeof (fre->fre_info) == sizeof (unsigned char));
+
+  /* Cleanup the space for fre_offsets first, then copy over the valid
+     bytes.  */
+  memset (fre->fre_offsets, 0, MAX_OFFSET_BYTES);
+  /* Get offsets size.  */
+  stack_offsets_sz = sframe_fre_offset_bytes_size (fre->fre_info);
+  stack_offsets = (unsigned char *)fre_buf + addr_size + sizeof 
(fre->fre_info);
+  memcpy (fre->fre_offsets, stack_offsets, stack_offsets_sz);
+
+  /* The FRE has been decoded.  Use it to perform one last sanity check.  */
+  fre_size = sframe_fre_entry_size (fre, fre_type);
+  sframe_assert (fre_size == (addr_size + sizeof (fre->fre_info)
+                                + stack_offsets_sz));
+  *esz = fre_size;
+
+  return 0;
+}
+
+/* Decode the specified SFrame buffer CF_BUF of size CF_SIZE and return the
+   new SFrame decoder context.
+
+   Sets ERRP for the caller if any error.  Frees up the allocated memory in
+   case of error.  */
+
+sframe_decoder_ctx *
+sframe_decode (const char *sf_buf, size_t sf_size, int *errp)
+{
+  const sframe_preamble *sfp;
+  size_t hdrsz;
+  sframe_header *sfheaderp;
+  sframe_decoder_ctx *dctx;
+  char *frame_buf;
+  char *tempbuf = NULL;
+
+  int fidx_size;
+  uint32_t fre_bytes;
+  int foreign_endian = 0;
+
+  sframe_init_debug ();
+
+  if ((sf_buf == NULL) || (!sf_size))
+    return sframe_ret_set_errno (errp, SFRAME_ERR_INVAL);
+  else if (sf_size < sizeof (sframe_header))
+    return sframe_ret_set_errno (errp, SFRAME_ERR_BUF_INVAL);
+
+  sfp = (const sframe_preamble *) sf_buf;
+
+  debug_printf ("sframe_decode: magic=0x%x version=%u flags=%u\n",
+               sfp->sfp_magic, sfp->sfp_version, sfp->sfp_flags);
+
+  /* Check for foreign endianness.  */
+  if (sfp->sfp_magic != SFRAME_MAGIC)
+    {
+      if (sfp->sfp_magic == bswap_16 (SFRAME_MAGIC))
+       foreign_endian = 1;
+      else
+       return sframe_ret_set_errno (errp, SFRAME_ERR_BUF_INVAL);
+    }
+
+  /* Initialize a new decoder context.  */
+  if ((dctx = malloc (sizeof (sframe_decoder_ctx))) == NULL)
+    return sframe_ret_set_errno (errp, SFRAME_ERR_NOMEM);
+  memset (dctx, 0, sizeof (sframe_decoder_ctx));
+
+  if (foreign_endian)
+    {
+      /* Allocate a new buffer and initialize it.  */
+      tempbuf = (char *) malloc (sf_size * sizeof (char));
+      if (tempbuf == NULL)
+       return sframe_ret_set_errno (errp, SFRAME_ERR_NOMEM);
+      memcpy (tempbuf, sf_buf, sf_size);
+
+      /* Flip the header.  */
+      sframe_header *ihp = (sframe_header *) tempbuf;
+      flip_header (ihp);
+      /* Flip the rest of the SFrame section data buffer.  */
+      if (flip_sframe (tempbuf, sf_size, 0))
+       {
+         free (tempbuf);
+         return sframe_ret_set_errno (errp, SFRAME_ERR_BUF_INVAL);
+       }
+      frame_buf = tempbuf;
+    }
+  else
+    frame_buf = (char *)sf_buf;
+
+  /* Handle the SFrame header.  */
+  dctx->sfd_header = *(sframe_header *) frame_buf;
+  /* Validate the contents of SFrame header.  */
+  sfheaderp = &dctx->sfd_header;
+  if (!sframe_header_sanity_check_p (sfheaderp))
+    {
+      sframe_ret_set_errno (errp, SFRAME_ERR_NOMEM);
+      goto decode_fail_free;
+    }
+  hdrsz = sframe_get_hdr_size (sfheaderp);
+  frame_buf += hdrsz;
+
+  /* Handle the SFrame Function Descriptor Entry section.  */
+  fidx_size
+    = sfheaderp->sfh_num_fdes * sizeof (sframe_func_desc_entry);
+  dctx->sfd_funcdesc = malloc (fidx_size);
+  if (dctx->sfd_funcdesc == NULL)
+    {
+      sframe_ret_set_errno (errp, SFRAME_ERR_NOMEM);
+      goto decode_fail_free;
+    }
+  memcpy (dctx->sfd_funcdesc, frame_buf, fidx_size);
+
+  debug_printf ("%u total fidx size\n", fidx_size);
+
+  frame_buf += (fidx_size);
+
+  /* Handle the SFrame Frame Row Entry section.  */
+  dctx->sfd_fres = malloc (sfheaderp->sfh_fre_len);
+  if (dctx->sfd_fres == NULL)
+    {
+      sframe_ret_set_errno (errp, SFRAME_ERR_NOMEM);
+      goto decode_fail_free;
+    }
+  memcpy (dctx->sfd_fres, frame_buf, sfheaderp->sfh_fre_len);
+
+  fre_bytes = sfheaderp->sfh_fre_len;
+  dctx->sfd_fre_nbytes = fre_bytes;
+
+  debug_printf ("%u total fre bytes\n", fre_bytes);
+
+  return dctx;
+
+decode_fail_free:
+  if (foreign_endian && tempbuf != NULL)
+    free (tempbuf);
+  sframe_decoder_free (&dctx);
+  dctx = NULL;
+  return dctx;
+}
+
+/* Get DECODER's SFrame header.  */
+
+static sframe_header *
+sframe_decoder_get_header (sframe_decoder_ctx *decoder)
+{
+  sframe_header *hp = NULL;
+  if (decoder != NULL)
+    hp = &decoder->sfd_header;
+  return hp;
+}
+
+/* Get the size of the SFrame header from the decoder context CTX.  */
+
+unsigned int
+sframe_decoder_get_hdr_size (sframe_decoder_ctx *ctx)
+{
+  sframe_header *dhp;
+  dhp = sframe_decoder_get_header (ctx);
+  return sframe_get_hdr_size (dhp);
+}
+
+/* Get the SFrame's abi/arch info given the decoder context CTX.  */
+
+unsigned char
+sframe_decoder_get_abi_arch (sframe_decoder_ctx *ctx)
+{
+  sframe_header *sframe_header;
+  sframe_header = sframe_decoder_get_header (ctx);
+  return sframe_header->sfh_abi_arch;
+}
+
+/* Get the SFrame's fixed FP offset given the decoder context CTX.  */
+int8_t
+sframe_decoder_get_fixed_fp_offset (sframe_decoder_ctx *ctx)
+{
+  sframe_header *dhp;
+  dhp = sframe_decoder_get_header (ctx);
+  return dhp->sfh_cfa_fixed_fp_offset;
+}
+
+/* Get the SFrame's fixed RA offset given the decoder context CTX.  */
+int8_t
+sframe_decoder_get_fixed_ra_offset (sframe_decoder_ctx *ctx)
+{
+  sframe_header *dhp;
+  dhp = sframe_decoder_get_header (ctx);
+  return dhp->sfh_cfa_fixed_ra_offset;
+}
+
+/* Find the function descriptor entry starting which contains the specified
+   address ADDR.  */
+
+sframe_func_desc_entry *
+sframe_get_funcdesc_with_addr (sframe_decoder_ctx *ctx,
+                              int32_t addr, int *errp)
+{
+  sframe_header *dhp;
+  sframe_func_desc_entry *fdp;
+  int low, high, cnt;
+
+  if (ctx == NULL)
+    return sframe_ret_set_errno (errp, SFRAME_ERR_INVAL);
+
+  dhp = sframe_decoder_get_header (ctx);
+
+  if (dhp == NULL || dhp->sfh_num_fdes == 0 || ctx->sfd_funcdesc == NULL)
+    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)
+    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;
+  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)
+       {
+         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;
+       }
+      else
+       high = mid - 1;
+    }
+
+  return sframe_ret_set_errno (errp, SFRAME_ERR_FDE_NOTFOUND);
+}
+
+/* Find the SFrame Row Entry which contains the PC.  Returns
+   SFRAME_ERR if failure.  */
+
+int
+sframe_find_fre (sframe_decoder_ctx *ctx, int32_t pc,
+                sframe_frame_row_entry *frep)
+{
+  sframe_func_desc_entry *fdep;
+  uint32_t start_address, i;
+  sframe_frame_row_entry cur_fre, next_fre;
+  unsigned char *sp;
+  unsigned int fre_type, fde_type;
+  size_t esz;
+  int err = 0;
+  size_t size = 0;
+  /* For regular FDEs (i.e. fde_type SFRAME_FDE_TYPE_PCINC),
+     where the start address in the FRE is an offset from start pc,
+     use a bitmask with all bits set so that none of the address bits are
+     ignored.  In this case, we need to return the FRE where
+     (PC >= FRE_START_ADDR) */
+  uint64_t bitmask = 0xffffffff;
+
+  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 (ctx, pc, &err);
+  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);
+
+  /* For FDEs for repetitive pattern of insns, we need to return the FRE
+     such that (PC & FRE_START_ADDR_AS_MASK >= FRE_START_ADDR_AS_MASK).
+     so, update the bitmask to the start address.  */
+  /* FIXME - the bitmask should be picked per ABI or encoded in the format
+     somehow. For AMD64, the pltN entry stub is 16 bytes. */
+  if (fde_type == SFRAME_FDE_TYPE_PCMASK)
+    bitmask = 0xff;
+
+  sp = (unsigned char *) ctx->sfd_fres + fdep->sfde_func_start_fre_off;
+  for (i = 0; i < fdep->sfde_func_num_fres; i++)
+   {
+     err = sframe_decode_fre ((const char *)sp, &next_fre,
+                                fre_type, &esz);
+     start_address = next_fre.fre_start_addr;
+
+     if (((fdep->sfde_func_start_address
+          + (int32_t) start_address) & bitmask) <= (pc & bitmask))
+       {
+        sframe_frame_row_entry_copy (&cur_fre, &next_fre);
+
+        /* Get the next FRE in sequence.  */
+        if (i < fdep->sfde_func_num_fres - 1)
+          {
+            sp += esz;
+            err = sframe_decode_fre ((const char*)sp, &next_fre,
+                                        fre_type, &esz);
+
+            /* Sanity check the next FRE.  */
+            if (!sframe_fre_sanity_check_p (&next_fre))
+              return sframe_set_errno (&err, SFRAME_ERR_FRE_INVAL);
+
+            size = next_fre.fre_start_addr;
+          }
+        else size = fdep->sfde_func_size;
+
+        /* If the cur FRE is the one that contains the PC, return it.  */
+        if (((fdep->sfde_func_start_address
+              + (int32_t)size) & bitmask) > (pc & bitmask))
+          {
+            sframe_frame_row_entry_copy (frep, &cur_fre);
+            return 0;
+          }
+       }
+     else
+       return sframe_set_errno (&err, SFRAME_ERR_FRE_INVAL);
+   }
+  return sframe_set_errno (&err, SFRAME_ERR_FDE_INVAL);
+}
+
+/* Return the number of function descriptor entries in the SFrame decoder
+   DCTX.  */
+
+unsigned int
+sframe_decoder_get_num_fidx (sframe_decoder_ctx *ctx)
+{
+  unsigned int num_fdes = 0;
+  sframe_header *dhp = NULL;
+  dhp = sframe_decoder_get_header (ctx);
+  if (dhp)
+    num_fdes = dhp->sfh_num_fdes;
+  return num_fdes;
+}
+
+/* Get the data (NUM_FRES, FUNC_START_ADDRESS) from the function
+   descriptor entry at index I'th in the decoder CTX.  If failed,
+   return error code.  */
+/* FIXME - consolidate the args and return a
+   sframe_func_desc_index_elem rather?  */
+
+int
+sframe_decoder_get_funcdesc (sframe_decoder_ctx *ctx,
+                            unsigned int i,
+                            uint32_t *num_fres,
+                            uint32_t *func_size,
+                            int32_t *func_start_address,
+                            unsigned char *func_info)
+{
+  sframe_func_desc_entry *fdp;
+  unsigned int num_fdes;
+  int err = 0;
+
+  if (ctx == NULL || func_start_address == NULL || num_fres == NULL
+      || func_size == NULL)
+    return sframe_set_errno (&err, SFRAME_ERR_INVAL);
+
+  num_fdes = sframe_decoder_get_num_fidx (ctx);
+  if (num_fdes == 0
+      || i >= num_fdes
+      || ctx->sfd_funcdesc == NULL)
+    return sframe_set_errno (&err, SFRAME_ERR_DCTX_INVAL);
+
+  fdp = (sframe_func_desc_entry *) ctx->sfd_funcdesc + i;
+  *num_fres = fdp->sfde_func_num_fres;
+  *func_start_address = fdp->sfde_func_start_address;
+  *func_size = fdp->sfde_func_size;
+  *func_info = fdp->sfde_func_info;
+
+  return 0;
+}
+
+/* Get the function descriptor entry at index FUNC_IDX in the decoder
+   context CTX.  */
+
+static sframe_func_desc_entry *
+sframe_decoder_get_funcdesc_at_index (sframe_decoder_ctx *ctx,
+                                        uint32_t func_idx)
+{
+  /* Invalid argument.  No FDE will be found.  */
+  if (func_idx >= sframe_decoder_get_num_fidx (ctx))
+    return NULL;
+
+  sframe_func_desc_entry *fdep;
+  fdep = (sframe_func_desc_entry *) ctx->sfd_funcdesc;
+  return fdep + func_idx;
+}
+
+/* Get the FRE_IDX'th FRE of the function at FUNC_IDX'th function
+   descriptor entry in the SFrame decoder CTX.  Returns error code as
+   applicable.  */
+
+int
+sframe_decoder_get_fre (sframe_decoder_ctx *ctx,
+                          unsigned int func_idx,
+                          unsigned int fre_idx,
+                          sframe_frame_row_entry *fre)
+{
+  sframe_func_desc_entry *fdep;
+  sframe_frame_row_entry ifre;
+  unsigned char *sp;
+  uint32_t i;
+  unsigned int fre_type;
+  size_t esz = 0;
+  int err = 0;
+
+  if (ctx == NULL || fre == NULL)
+    return sframe_set_errno (&err, SFRAME_ERR_INVAL);
+
+  /* Get function descriptor entry at index func_idx.  */
+  fdep = sframe_decoder_get_funcdesc_at_index (ctx, func_idx);
+
+  if (fdep == NULL)
+    return sframe_set_errno (&err, SFRAME_ERR_FDE_NOTFOUND);
+
+  fre_type = sframe_get_fre_type (fdep);
+  /* Now scan the FRE entries.  */
+  sp = (unsigned char *) ctx->sfd_fres + fdep->sfde_func_start_fre_off;
+  for (i = 0; i < fdep->sfde_func_num_fres; i++)
+   {
+     /* Decode the FRE at the current position.  Return it if valid.  */
+     err = sframe_decode_fre ((const char *)sp, &ifre, fre_type, &esz);
+     if (i == fre_idx)
+       {
+        if (!sframe_fre_sanity_check_p (&ifre))
+          return sframe_set_errno (&err, SFRAME_ERR_FRE_INVAL);
+
+        sframe_frame_row_entry_copy (fre, &ifre);
+
+        if (fdep->sfde_func_size)
+          sframe_assert (fre->fre_start_addr < fdep->sfde_func_size);
+        else
+          /* A SFrame FDE with func size equal to zero is possible.  */
+          sframe_assert (fre->fre_start_addr == fdep->sfde_func_size);
+
+        return 0;
+       }
+     /* Next FRE.  */
+     sp += esz;
+   }
+
+  return sframe_set_errno (&err, SFRAME_ERR_FDE_NOTFOUND);
+}
+
+
+/* SFrame Encoder.  */
+
+/* Get a reference to the ENCODER's SFrame header.  */
+
+static sframe_header *
+sframe_encoder_get_header (sframe_encoder_ctx *encoder)
+{
+  sframe_header *hp = NULL;
+  if (encoder)
+    hp = &encoder->sfe_header;
+  return hp;
+}
+
+static sframe_func_desc_entry *
+sframe_encoder_get_funcdesc_at_index (sframe_encoder_ctx *encoder,
+                                        uint32_t func_idx)
+{
+  sframe_func_desc_entry *fde = NULL;
+  if (func_idx < sframe_encoder_get_num_fidx (encoder))
+    {
+      sf_funidx_tbl *func_tbl = (sf_funidx_tbl *) encoder->sfe_funcdesc;
+      fde = func_tbl->entry + func_idx;
+    }
+  return fde;
+}
+
+/* Create an encoder context with the given SFrame format version VER, FLAGS
+   and ABI information.  Sets errp if failure.  */
+
+sframe_encoder_ctx *
+sframe_encode (unsigned char ver, unsigned char flags, int abi_arch,
+              int8_t fixed_fp_offset, int8_t fixed_ra_offset, int *errp)
+{
+  sframe_header *hp;
+  sframe_encoder_ctx *fp;
+
+  if (ver != SFRAME_VERSION)
+    return sframe_ret_set_errno (errp, SFRAME_ERR_VERSION_INVAL);
+
+  if ((fp = malloc (sizeof (sframe_encoder_ctx))) == NULL)
+    return sframe_ret_set_errno (errp, SFRAME_ERR_NOMEM);
+
+  memset (fp, 0, sizeof (sframe_encoder_ctx));
+
+  /* Get the SFrame header and update it.  */
+  hp = sframe_encoder_get_header (fp);
+  hp->sfh_preamble.sfp_version = ver;
+  hp->sfh_preamble.sfp_magic = SFRAME_MAGIC;
+  hp->sfh_preamble.sfp_flags = flags;
+
+  hp->sfh_abi_arch = abi_arch;
+  hp->sfh_cfa_fixed_fp_offset = fixed_fp_offset;
+  hp->sfh_cfa_fixed_ra_offset = fixed_ra_offset;
+
+  return fp;
+}
+
+/* Free the encoder context.  */
+
+void
+sframe_encoder_free (sframe_encoder_ctx **encoder)
+{
+  if (encoder != NULL)
+    {
+      sframe_encoder_ctx *ectx = *encoder;
+      if (ectx == NULL)
+       return;
+
+      if (ectx->sfe_funcdesc != NULL)
+       {
+         free (ectx->sfe_funcdesc);
+         ectx->sfe_funcdesc = NULL;
+       }
+      if (ectx->sfe_fres != NULL)
+       {
+         free (ectx->sfe_fres);
+         ectx->sfe_fres = NULL;
+       }
+      if (ectx->sfe_data != NULL)
+       {
+         free (ectx->sfe_data);
+         ectx->sfe_data = NULL;
+       }
+
+      free (*encoder);
+      *encoder = NULL;
+    }
+}
+
+/* Get the size of the SFrame header from the encoder ctx ENCODER.  */
+
+unsigned int
+sframe_encoder_get_hdr_size (sframe_encoder_ctx *encoder)
+{
+  sframe_header *ehp;
+  ehp = sframe_encoder_get_header (encoder);
+  return sframe_get_hdr_size (ehp);
+}
+
+/* Get the abi/arch info from the SFrame encoder context ENCODER.  */
+
+unsigned char
+sframe_encoder_get_abi_arch (sframe_encoder_ctx *encoder)
+{
+  unsigned char abi_arch = 0;
+  sframe_header *ehp;
+  ehp = sframe_encoder_get_header (encoder);
+  if (ehp)
+    abi_arch = ehp->sfh_abi_arch;
+  return abi_arch;
+}
+
+/* Return the number of function descriptor entries in the SFrame encoder
+   ENCODER.  */
+
+unsigned int
+sframe_encoder_get_num_fidx (sframe_encoder_ctx *encoder)
+{
+  unsigned int num_fdes = 0;
+  sframe_header *ehp = NULL;
+  ehp = sframe_encoder_get_header (encoder);
+  if (ehp)
+    num_fdes = ehp->sfh_num_fdes;
+  return num_fdes;
+}
+
+/* Add an FRE to function at FUNC_IDX'th function descriptor entry in
+   the encoder context.  */
+
+int
+sframe_encoder_add_fre (sframe_encoder_ctx *encoder,
+                          unsigned int func_idx,
+                          sframe_frame_row_entry *frep)
+{
+  sframe_header *ehp;
+  sframe_func_desc_entry *fdep;
+  sframe_frame_row_entry *ectx_frep;
+  size_t offsets_sz, esz;
+  unsigned int fre_type;
+  size_t fre_tbl_sz;
+  int err = 0;
+
+  if (encoder == NULL || frep == NULL)
+    return sframe_set_errno (&err, SFRAME_ERR_INVAL);
+  if (!sframe_fre_sanity_check_p (frep))
+    return sframe_set_errno (&err, SFRAME_ERR_FRE_INVAL);
+
+  /* Use func_idx to gather the function descriptor entry.  */
+  fdep = sframe_encoder_get_funcdesc_at_index (encoder, func_idx);
+
+  if (fdep == NULL)
+    return sframe_set_errno (&err, SFRAME_ERR_FDE_NOTFOUND);
+
+  fre_type = sframe_get_fre_type (fdep);
+  sf_fre_tbl *fre_tbl = (sf_fre_tbl *) encoder->sfe_fres;
+
+  if (fre_tbl == NULL)
+    {
+      fre_tbl_sz = (sizeof (sf_fre_tbl)
+                   + (number_of_entries * sizeof (sframe_frame_row_entry)));
+      fre_tbl = malloc (fre_tbl_sz);
+
+      if (fre_tbl == NULL)
+       {
+         sframe_set_errno (&err, SFRAME_ERR_NOMEM);
+         goto bad;             /* OOM.  */
+       }
+      memset (fre_tbl, 0, fre_tbl_sz);
+      fre_tbl->alloced = number_of_entries;
+    }
+  else if (fre_tbl->count == fre_tbl->alloced)
+    {
+      fre_tbl_sz = (sizeof (sf_fre_tbl)
+                   + ((fre_tbl->alloced + number_of_entries)
+                      * sizeof (sframe_frame_row_entry)));
+      fre_tbl = realloc (fre_tbl, fre_tbl_sz);
+      if (fre_tbl == NULL)
+       {
+         sframe_set_errno (&err, SFRAME_ERR_NOMEM);
+         goto bad;             /* OOM.  */
+       }
+
+      memset (&fre_tbl->entry[fre_tbl->alloced], 0,
+             number_of_entries * sizeof (sframe_frame_row_entry));
+      fre_tbl->alloced += number_of_entries;
+    }
+
+  ectx_frep = &fre_tbl->entry[fre_tbl->count];
+  ectx_frep->fre_start_addr
+    = frep->fre_start_addr;
+  ectx_frep->fre_info = frep->fre_info;
+
+  if (fdep->sfde_func_size)
+    sframe_assert (frep->fre_start_addr < fdep->sfde_func_size);
+  else
+    /* A SFrame FDE with func size equal to zero is possible.  */
+    sframe_assert (frep->fre_start_addr == fdep->sfde_func_size);
+
+  /* frep has already been sanity check'd.  Get offsets size.  */
+  offsets_sz = sframe_fre_offset_bytes_size (frep->fre_info);
+  memcpy (&ectx_frep->fre_offsets, &frep->fre_offsets, offsets_sz);
+
+  esz = sframe_fre_entry_size (frep, fre_type);
+  fre_tbl->count++;
+
+  encoder->sfe_fres = (void *) fre_tbl;
+  encoder->sfe_fre_nbytes += esz;
+
+  ehp = sframe_encoder_get_header (encoder);
+  ehp->sfh_num_fres = fre_tbl->count;
+
+  /* Update the value of the number of FREs for the function.  */
+  fdep->sfde_func_num_fres++;
+
+  return 0;
+
+bad:
+  if (fre_tbl != NULL)
+    free (fre_tbl);
+  encoder->sfe_fres = NULL;
+  encoder->sfe_fre_nbytes = 0;
+  return -1;
+}
+
+/* Add a new function descriptor entry with START_ADDR, FUNC_SIZE and NUM_FRES
+   to the encoder.  */
+
+int
+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)))
+{
+  sframe_header *ehp;
+  sf_funidx_tbl *fd_info;
+  size_t fd_tbl_sz;
+  int err = 0;
+
+  /* FIXME book-keep num_fres for error checking.  */
+  if (encoder == NULL)
+    return sframe_set_errno (&err, SFRAME_ERR_INVAL);
+
+  fd_info = (sf_funidx_tbl *) encoder->sfe_funcdesc;
+  ehp = sframe_encoder_get_header (encoder);
+
+  if (fd_info == NULL)
+    {
+      fd_tbl_sz = (sizeof (sf_funidx_tbl)
+                  + (number_of_entries * sizeof (sframe_func_desc_entry)));
+      fd_info = malloc (fd_tbl_sz);
+      if (fd_info == NULL)
+       {
+         sframe_set_errno (&err, SFRAME_ERR_NOMEM);
+         goto bad;             /* OOM.  */
+       }
+      memset (fd_info, 0, fd_tbl_sz);
+      fd_info->alloced = number_of_entries;
+    }
+  else if (fd_info->count == fd_info->alloced)
+    {
+      fd_tbl_sz = (sizeof (sf_funidx_tbl)
+                  + ((fd_info->alloced + number_of_entries)
+                     * sizeof (sframe_func_desc_entry)));
+      fd_info = realloc (fd_info, fd_tbl_sz);
+      if (fd_info == NULL)
+       {
+         sframe_set_errno (&err, SFRAME_ERR_NOMEM);
+         goto bad;             /* OOM.  */
+       }
+
+      memset (&fd_info->entry[fd_info->alloced], 0,
+             number_of_entries * sizeof (sframe_func_desc_entry));
+      fd_info->alloced += number_of_entries;
+    }
+
+  fd_info->entry[fd_info->count].sfde_func_start_address = start_addr;
+  /* Num FREs is updated as FREs are added for the function later via
+     sframe_encoder_add_fre.  */
+  fd_info->entry[fd_info->count].sfde_func_size = func_size;
+  fd_info->entry[fd_info->count].sfde_func_start_fre_off
+    = encoder->sfe_fre_nbytes;
+#if 0
+  // Linker optimization test code cleanup later ibhagat TODO FIXME
+  unsigned int fre_type = sframe_calc_fre_type (func_size);
+
+  fd_info->entry[fd_info->count].sfde_func_info
+    = sframe_fde_func_info (fre_type);
+#endif
+  fd_info->entry[fd_info->count].sfde_func_info = func_info;
+  fd_info->count++;
+  encoder->sfe_funcdesc = (void *) fd_info;
+  ehp->sfh_num_fdes++;
+  return 0;
+
+bad:
+  if (fd_info != NULL)
+    free (fd_info);
+  encoder->sfe_funcdesc = NULL;
+  ehp->sfh_num_fdes = 0;
+  return -1;
+}
+
+static int
+sframe_sort_funcdesc (sframe_encoder_ctx *encoder)
+{
+  sframe_header *ehp;
+
+  ehp = sframe_encoder_get_header (encoder);
+  /* Sort and write out the FDE table.  */
+  sf_funidx_tbl *fd_info = (sf_funidx_tbl *) encoder->sfe_funcdesc;
+  if (fd_info)
+    {
+      qsort (fd_info->entry, fd_info->count,
+            sizeof (sframe_func_desc_entry), fde_func);
+      /* Update preamble's flags.  */
+      ehp->sfh_preamble.sfp_flags |= SFRAME_F_FDE_SORTED;
+    }
+  return 0;
+}
+
+/* Write a frame row entry pointed to by FREP into the buffer CONTENTS.  The
+   size in bytes written out are updated in ESZ.
+
+   This function works closely with the SFrame binary format.
+
+   Returns SFRAME_ERR if failure.  */
+
+static int
+sframe_encoder_write_fre (char *contents, sframe_frame_row_entry *frep,
+                         unsigned int fre_type, size_t *esz)
+{
+  size_t fre_size;
+  size_t fre_start_addr_sz;
+  size_t fre_stack_offsets_sz;
+  int err = 0;
+
+  if (!sframe_fre_sanity_check_p (frep))
+    return sframe_set_errno (&err, SFRAME_ERR_FRE_INVAL);
+
+  fre_start_addr_sz = sframe_fre_start_addr_size (fre_type);
+  fre_stack_offsets_sz = sframe_fre_offset_bytes_size (frep->fre_info);
+
+  /* The FRE start address must be encodable in the available number of
+     bytes.  */
+  uint64_t bitmask = SFRAME_BITMASK_OF_SIZE (fre_start_addr_sz);
+  sframe_assert ((uint64_t)frep->fre_start_addr <= bitmask);
+
+  memcpy (contents,
+         &frep->fre_start_addr,
+         fre_start_addr_sz);
+  contents += fre_start_addr_sz;
+
+  memcpy (contents,
+         &frep->fre_info,
+         sizeof (frep->fre_info));
+  contents += sizeof (frep->fre_info);
+
+  memcpy (contents,
+         frep->fre_offsets,
+         fre_stack_offsets_sz);
+  contents+= fre_stack_offsets_sz;
+
+  fre_size = sframe_fre_entry_size (frep, fre_type);
+  /* Sanity checking.  */
+  sframe_assert ((fre_start_addr_sz
+                    + sizeof (frep->fre_info)
+                    + fre_stack_offsets_sz) == fre_size);
+
+  *esz = fre_size;
+
+  return 0;
+}
+
+/* Serialize the core contents of the SFrame section and write out to the
+   output buffer held in the ENCODER.  Return SFRAME_ERR if failure.  */
+
+static int
+sframe_encoder_write_sframe (sframe_encoder_ctx *encoder)
+{
+  char *contents;
+  size_t buf_size;
+  size_t hdr_size;
+  size_t all_fdes_size;
+  size_t fre_size;
+  size_t esz = 0;
+  sframe_header *ehp;
+  unsigned char flags;
+  sf_funidx_tbl *fd_info;
+  sf_fre_tbl *fr_info;
+  uint32_t i, num_fdes;
+  uint32_t j, num_fres;
+  sframe_func_desc_entry *fdep;
+  sframe_frame_row_entry *frep;
+
+  unsigned int fre_type;
+  int err = 0;
+
+  contents = encoder->sfe_data;
+  buf_size = encoder->sfe_data_size;
+  num_fdes = sframe_encoder_get_num_fidx (encoder);
+  all_fdes_size = num_fdes * sizeof (sframe_func_desc_entry);
+  ehp = sframe_encoder_get_header (encoder);
+  hdr_size = sframe_get_hdr_size (ehp);
+
+  fd_info = (sf_funidx_tbl *) encoder->sfe_funcdesc;
+  fr_info = (sf_fre_tbl *) encoder->sfe_fres;
+
+  /* Sanity checks:
+     - buffers must be malloc'd by the caller.  */
+  if ((contents == NULL) || (buf_size < hdr_size))
+    return sframe_set_errno (&err, SFRAME_ERR_BUF_INVAL);
+  if (fr_info == NULL)
+    return sframe_set_errno (&err, SFRAME_ERR_FRE_INVAL);
+
+  /* Write out the FRE table first.
+
+     Recall that read/write of FREs needs information from the corresponding
+     FDE; the latter stores the information about the FRE type record used for
+     the function.  Also note that sorting of FDEs does NOT impact the order
+     in which FREs are stored in the SFrame's FRE sub-section.  This means
+     that writing out FREs after sorting of FDEs will need some additional
+     book-keeping.  At this time, we can afford to avoid it by writing out
+     the FREs first to the output buffer.  */
+  fre_size = 0;
+  uint32_t global = 0;
+  uint32_t fre_index = 0;
+
+  contents += hdr_size + all_fdes_size;
+  for (i = 0; i < num_fdes; i++)
+    {
+      fdep = &fd_info->entry[i];
+      fre_type = sframe_get_fre_type (fdep);
+      num_fres = fdep->sfde_func_num_fres;
+
+      for (j = 0; j < num_fres; j++)
+       {
+         fre_index = global + j;
+         frep = &fr_info->entry[fre_index];
+
+         sframe_encoder_write_fre (contents, frep, fre_type, &esz);
+         contents += esz;
+         fre_size += esz; /* For debugging only.  */
+       }
+      global += j;
+    }
+
+  sframe_assert (fre_size == ehp->sfh_fre_len);
+  sframe_assert (global == ehp->sfh_num_fres);
+  sframe_assert ((size_t)(contents - encoder->sfe_data) == buf_size);
+
+  /* Sort the FDE table */
+  sframe_sort_funcdesc (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)
+      || (fd_info == NULL))
+    return sframe_set_errno (&err, SFRAME_ERR_FDE_INVAL);
+
+  contents = encoder->sfe_data;
+  /* Write out the SFrame header.  The SFrame header in the encoder
+     object has already been updated with correct offsets by the caller.  */
+  memcpy (contents, ehp, hdr_size);
+  contents += hdr_size;
+
+  /* Write out the FDE table sorted on funtion start address.  */
+  memcpy (contents, fd_info->entry, all_fdes_size);
+  contents += all_fdes_size;
+
+  return 0;
+}
+
+/* Serialize the contents of the encoder and return the buffer.  ENCODED_SIZE
+   is updated to the size of the buffer.  */
+
+char *
+sframe_encoder_write (sframe_encoder_ctx *encoder,
+                     size_t *encoded_size, int *errp)
+{
+  sframe_header *ehp;
+  size_t hdrsize, fsz, fresz, bufsize;
+  int foreign_endian;
+
+  /* Initialize the encoded_size to zero.  This makes it simpler to just
+     return from the function in case of failure.  Free'ing up of
+     encoder->sfe_data is the responsibility of the caller.  */
+  *encoded_size = 0;
+
+  if (encoder == NULL || encoded_size == NULL || errp == NULL)
+    return sframe_ret_set_errno (errp, SFRAME_ERR_INVAL);
+
+  ehp = sframe_encoder_get_header (encoder);
+  hdrsize = sframe_get_hdr_size (ehp);
+  fsz = sframe_encoder_get_num_fidx (encoder)
+    * sizeof (sframe_func_desc_entry);
+  fresz = encoder->sfe_fre_nbytes;
+
+  /* The total size of buffer is the sum of header, SFrame Function Descriptor
+     Entries section and the FRE section.  */
+  bufsize = hdrsize + fsz + fresz;
+  encoder->sfe_data = (char *) malloc (bufsize);
+  if (encoder->sfe_data == NULL)
+    return sframe_ret_set_errno (errp, SFRAME_ERR_NOMEM);
+  encoder->sfe_data_size = bufsize;
+
+  /* Update the information in the SFrame header.  */
+  /* SFrame FDE section follows immediately after the header.  */
+  ehp->sfh_fdeoff = 0;
+  /* SFrame FRE section follows immediately after the SFrame FDE section.  */
+  ehp->sfh_freoff = fsz;
+  ehp->sfh_fre_len = fresz;
+
+  foreign_endian = need_swapping (ehp->sfh_abi_arch);
+
+  /* Write out the FDE Index and the FRE table in the sfe_data. */
+  if (sframe_encoder_write_sframe (encoder))
+    return sframe_ret_set_errno (errp, SFRAME_ERR_BUF_INVAL);
+
+  /* Endian flip the contents if necessary.  */
+  if (foreign_endian)
+    {
+      if (flip_sframe (encoder->sfe_data, bufsize, 1))
+       return sframe_ret_set_errno (errp, SFRAME_ERR_BUF_INVAL);
+      flip_header ((sframe_header*)encoder->sfe_data);
+    }
+
+  *encoded_size = bufsize;
+  return encoder->sfe_data;
+}
diff --git a/lib/sframe.h b/lib/sframe.h
new file mode 100644
index 000000000..dd9b49eac
--- /dev/null
+++ b/lib/sframe.h
@@ -0,0 +1,287 @@
+/* SFrame format description.
+   Copyright (C) 2022 Free Software Foundation, Inc.
+
+   SFrame is free software; you can redistribute it and/or modify it
+   under the terms of the GNU General Public License as published by the Free
+   Software Foundation; either version 3, or (at your option) any later
+   version.
+
+   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; see the file COPYING.  If not see
+   <http://www.gnu.org/licenses/>.  */
+
+#ifndef        _SFRAME_H
+#define        _SFRAME_H
+
+#include <sys/types.h>
+#include <limits.h>
+#include <stdint.h>
+
+#include "ansidecl.h"
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/* SFrame format.
+
+   SFrame format is a simple format to represent the information needed
+   for vanilla virtual stack unwinding.  SFrame format keeps track of the
+   minimal necessary information needed for stack unwinding:
+     - Canonical Frame Address (CFA)
+     - Frame Pointer (FP)
+     - Return Address (RA)
+
+   The SFrame section itself has the following structure:
+
+       +--------+------------+---------+
+       |  file  |  function  | frame   |
+       | header | descriptor |  row    |
+       |        |   entries  | entries |
+       +--------+------------+---------+
+
+   The file header stores a magic number and version information, flags, and
+   the byte offset of each of the sections relative to the end of the header
+   itself.  The file header also specifies the total number of Function
+   Descriptor Entries, Frame Row Entries and length of the FRE sub-section.
+
+   Following the header is a list of Function Descriptor Entries (FDEs).
+   This list may be sorted if the flags in the file header indicate it to be
+   so.  The sort order, if applicable, is the order of functions in the
+   .text.* sections in the resulting binary artifact.  Each Function
+   Descriptor Entry specifies the start PC of a function, the size in bytes
+   of the function and an offset to its first Frame Row Entry (FRE).  Each FDE
+   additionally also specifies the type of FRE it uses to encode the unwind
+   information.
+
+   Next, the Frame Row Entry section is a list of variable size records,
+   each of which represent SFrame unwind information for a set of PCs.  A
+   singular Frame Row Entry is a self-sufficient record with information on
+   how to virtually unwind the stack for the applicable set of PCs.
+
+   */
+
+
+/* SFrame format versions.  */
+#define SFRAME_VERSION_1       1
+/* SFrame magic number.  */
+#define SFRAME_MAGIC           0xdee2
+/* Current version of SFrame format.  */
+#define SFRAME_VERSION SFRAME_VERSION_1
+
+/* Various flags for SFrame.  */
+
+/* Function Descriptor Entries are sorted on PC.  */
+#define SFRAME_F_FDE_SORTED    0x1
+/* Frame-pointer based unwinding.  */
+#define SFRAME_F_FRAME_POINTER 0x2
+
+#define SFRAME_CFA_FIXED_FP_INVALID 0
+#define SFRAME_CFA_FIXED_RA_INVALID 0
+
+/* Supported ABIs/Arch.  */
+#define SFRAME_ABI_AARCH64_ENDIAN_BIG      1 /* AARCH64 big endian.  */
+#define SFRAME_ABI_AARCH64_ENDIAN_LITTLE   2 /* AARCH64 little endian.  */
+#define SFRAME_ABI_AMD64_ENDIAN_LITTLE     3 /* AMD64 little endian.  */
+
+/* SFrame FRE types.  */
+#define SFRAME_FRE_TYPE_ADDR1  0
+#define SFRAME_FRE_TYPE_ADDR2  1
+#define SFRAME_FRE_TYPE_ADDR4  2
+
+/* SFrame Function Descriptor Entry types.
+
+   The SFrame format has two possible representations for functions.  The
+   choice of which type to use is made according to the instruction patterns
+   in the relevant program stub.
+
+   An SFrame FDE of type SFRAME_FDE_TYPE_PCINC is an indication
+   that the PCs in the FREs should be treated as increments in bytes.  This is
+   used for a bulk of the executable code of a program, which contains
+   instructions with no specific pattern.
+
+   An SFrame FDE of type SFRAME_FDE_TYPE_PCMASK is an indication
+   that the PCs in the FREs should be treated as masks.  This type is useful
+   for the cases when a small pattern of instructions in a program stub is
+   repeatedly to cover a specific functionality.  Typical usescases are pltN
+   entries, trampolines etc.  */
+
+/* Unwinders perform a (PC >= FRE_START_ADDR) to look up a matching FRE.  */
+#define SFRAME_FDE_TYPE_PCINC   0
+/* Unwinders perform a (PC & FRE_START_ADDR_AS_MASK >= FRE_START_ADDR_AS_MASK)
+   to look up a matching FRE.  */
+#define SFRAME_FDE_TYPE_PCMASK  1
+
+typedef struct sframe_preamble
+{
+  uint16_t sfp_magic;  /* Magic number (SFRAME_MAGIC).  */
+  uint8_t sfp_version; /* Data format version number (SFRAME_VERSION).  */
+  uint8_t sfp_flags;   /* Flags.  */
+} ATTRIBUTE_PACKED sframe_preamble;
+
+typedef struct sframe_header
+{
+  sframe_preamble sfh_preamble;
+  /* Information about the arch (endianness) and ABI.  */
+  uint8_t sfh_abi_arch;
+  /* Offset for the Frame Pointer (FP) from CFA may be fixed for some
+     ABIs (e.g, in AMD64 when -fno-omit-frame-pointer is used).  When fixed,
+     this field specifies the fixed stack frame offset and the individual
+     FREs do not need to track it.  When not fixed, it is set to
+     SFRAME_CFA_FIXED_FP_INVALID, and the individual FREs may provide
+     the applicable stack frame offset, if any.  */
+  int8_t sfh_cfa_fixed_fp_offset;
+  /* Offset for the Return Address from CFA is fixed for some ABIs
+     (e.g., AMD64 has it as CFA-8).  When fixed, the header specifies the
+     fixed stack frame offset and the individual FREs do not track it.  When
+     not fixed, it is set to SFRAME_CFA_FIXED_RA_INVALID, and individual
+     FREs provide the applicable stack frame offset, if any.  */
+  int8_t sfh_cfa_fixed_ra_offset;
+  /* Number of bytes making up the auxilliary header, if any.
+     Some ABI/arch, in the future, may use this space for extending the
+     information in SFrame header.  Auxilliary header is contained in
+     bytes sequentially following the sframe_header.  */
+  uint8_t sfh_auxhdr_len;
+  /* Number of SFrame FDEs in this SFrame section.  */
+  uint32_t sfh_num_fdes;
+  /* Number of SFrame Frame Row Entries.  */
+  uint32_t sfh_num_fres;
+  /* Number of bytes in the SFrame Frame Row Entry section. */
+  uint32_t sfh_fre_len;
+  /* Offset of SFrame Function Descriptor Entry section.  */
+  uint32_t sfh_fdeoff;
+  /* Offset of SFrame Frame Row Entry section.  */
+  uint32_t sfh_freoff;
+} ATTRIBUTE_PACKED sframe_header;
+
+#define SFRAME_V1_HDR_SIZE(sframe_hdr) \
+  ((sizeof (sframe_header) + (sframe_hdr).sfh_auxhdr_len))
+
+typedef struct sframe_func_desc_entry
+{
+  /* Function start address.  Encoded as a signed offset, relative to the
+     beginning of the current FDE.  */
+  int32_t sfde_func_start_address;
+  /* Size of the function in bytes.  */
+  uint32_t sfde_func_size;
+  /* Offset of the first SFrame Frame Row Entry of the function, relative to 
the
+     beginning of the SFrame Frame Row Entry sub-section.  */
+  uint32_t sfde_func_start_fre_off;
+  /* Number of frame row entries for the function.  */
+  uint32_t sfde_func_num_fres;
+  /* Additional information for deciphering the unwind information for the
+     function.
+     - 4-bits: Identify the FRE type used for the function.
+     - 1-bit: Identify the FDE type of the function - mask or inc.
+     - 3-bits: Unused.
+     --------------------------------------------
+     |     Unused    |  FDE type |   FRE type   |
+     --------------------------------------------
+     8               5           4              0     */
+  uint8_t sfde_func_info;
+} ATTRIBUTE_PACKED sframe_func_desc_entry;
+
+/* Macros to compose and decompose function info in FDE.  */
+
+#define SFRAME_V1_FUNC_INFO(fde_type, fre_enc_type) \
+  (((fde_type) & 0x1) << 4 | (fre_enc_type))
+
+#define SFRAME_V1_FUNC_FRE_TYPE(data)    ((data) & 0xf)
+#define SFRAME_V1_FUNC_FDE_TYPE(data)    ((data >> 4) & 0x1)
+
+/* Size of stack frame offsets in an SFrame Frame Row Entry.  A single
+   SFrame FRE has all offsets of the same size.  Offset size may vary
+   across frame row entries.  */
+#define SFRAME_FRE_OFFSET_1B     0
+#define SFRAME_FRE_OFFSET_2B     1
+#define SFRAME_FRE_OFFSET_4B     2
+
+/* An SFrame Frame Row Entry can be SP or FP based.  */
+#define SFRAME_BASE_REG_FP     0
+#define SFRAME_BASE_REG_SP     1
+
+/* The index at which a specific offset is presented in the variable length
+   bytes of an FRE.  */
+#define SFRAME_FRE_CFA_OFFSET_IDX  0
+#define SFRAME_FRE_FP_OFFSET_IDX   1
+#define SFRAME_FRE_RA_OFFSET_IDX   2
+
+typedef struct sframe_fre_info
+{
+  /* Information about
+     - 1 bit: base reg for CFA
+     - 4 bits: Number of offsets (N).  A value of upto 3 is allowed to track
+     all three of CFA, FP and RA (fixed implicit order).
+     - 2 bits: information about size of the offsets (S) in bytes.
+     Valid values are SFRAME_FRE_OFFSET_1B, SFRAME_FRE_OFFSET_2B,
+     SFRAME_FRE_OFFSET_4B
+     - 1 bit: Unused.
+     -----------------------------------------------------------------------
+     |  Unused  |  Size of offsets   |   Number of offsets    |   base_reg |
+     -----------------------------------------------------------------------
+     8          7                    5                        1            0
+
+     */
+  uint8_t fre_info;
+} sframe_fre_info;
+
+/* Macros to compose and decompose FRE info.  */
+
+#define SFRAME_V1_FRE_INFO(base_reg_id, offset_num, offset_size) \
+  ((offset_size << 5) | (offset_num << 1) | (base_reg_id))
+
+#define SFRAME_V1_FRE_CFA_BASE_REG_ID(data)      ((data) & 0x1)
+#define SFRAME_V1_FRE_OFFSET_COUNT(data)         (((data) >> 1) & 0xf)
+#define SFRAME_V1_FRE_OFFSET_SIZE(data)          (((data) >> 5) & 0x3)
+
+/* SFrame Frame Row Entry definitions.
+
+   Used for both AMD64 and AARCH64.
+
+   An SFrame Frame Row Entry is a self-sufficient record containing SFrame
+   unwind info for a range of addresses, starting at the specified offset in
+   the function.  Each SFrame Frame Row Entry is followed by S*N bytes, where:
+     S is the size of the stack frame offset for the FRE, and
+     N is the number of stack frame offsets in the FRE
+
+   The offsets are interpreted in order as follows:
+   offset1 (interpreted as CFA = BASE_REG + offset1)
+   offset2 (interpreted as FP = CFA + offset2)
+   offset3 (interpreted as RA = CFA + offset3)
+*/
+
+typedef struct sframe_frame_row_entry_addr1
+{
+  /* Start address of the frame row entry.  Encoded as an 1-byte unsigned
+     offset, relative to the start address of the function.  */
+  uint8_t sfre_start_address;
+  sframe_fre_info sfre_info;
+} ATTRIBUTE_PACKED sframe_frame_row_entry_addr1;
+
+typedef struct sframe_frame_row_entry_addr2
+{
+  /* Start address of the frame row entry.  Encoded as an 2-byte unsigned
+     offset, relative to the start address of the function.  */
+  uint16_t sfre_start_address;
+  sframe_fre_info sfre_info;
+} ATTRIBUTE_PACKED sframe_frame_row_entry_addr2;
+
+typedef struct sframe_frame_row_entry_addr4
+{
+  /* Start address of the frame row entry.  Encoded as a 4-byte unsigned
+     offset, relative to the start address of the function.  */
+  uint32_t sfre_start_address;
+  sframe_fre_info sfre_info;
+} ATTRIBUTE_PACKED sframe_frame_row_entry_addr4;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif                         /* _SFRAME_H */
diff --git a/modules/sframe b/modules/sframe
new file mode 100644
index 000000000..f5eb78200
--- /dev/null
+++ b/modules/sframe
@@ -0,0 +1,30 @@
+Description:
+Sframe's encoder and decoder.
+
+Files:
+lib/sframe-api.h
+lib/sframe-internal.h
+lib/sframe.h
+lib/sframe.c
+
+Depends-on:
+stdio
+stdlib
+stdarg
+string
+
+configure.ac:
+
+Makefile.am:
+lib_SOURCES += sframe-api.h sframe-internal.h sframe.h sframe.c
+
+Include:
+"sframe-api.h"
+"sframe-internal.h"
+"sframe.h"
+
+License:
+LGPLv2+
+
+Maintainer:
+all
diff --git a/modules/sframe-header b/modules/sframe-header
new file mode 100644
index 000000000..e098991a5
--- /dev/null
+++ b/modules/sframe-header
@@ -0,0 +1,23 @@
+Description:
+Define the SFrame format.
+
+Files:
+lib/sframe.h
+
+Depends-on:
+
+configure.ac:
+
+Makefile.am:
+lib_SOURCES += sframe.h
+
+Include:
+<sys/types.h>
+<limits.h>
+<stdint.h>
+
+License:
+LGPLv2+
+
+Maintainer:
+all
diff --git a/modules/sframe-tests b/modules/sframe-tests
new file mode 100644
index 000000000..80a2a39c5
--- /dev/null
+++ b/modules/sframe-tests
@@ -0,0 +1,16 @@
+Files:
+tests/test-sframe-frecnt1.c
+tests/test-sframe-frecnt2.c
+tests/test-sframe-encode1.c
+tests/test-sframe-be-flipping.c
+tests/DATA1
+tests/DATA2
+tests/DATA-BE
+
+Depends-on:
+
+configure.ac:
+
+Makefile.am:
+TESTS += test-sframe-frecnt1 test-sframe-frecnt2 test-sframe-encode1 
test-sframe-be-flipping
+check_PROGRAMS += test-sframe-frecnt1 test-sframe-frecnt2 test-sframe-encode1 
test-sframe-be-flipping
diff --git a/tests/DATA-BE b/tests/DATA-BE
new file mode 100644
index 
0000000000000000000000000000000000000000..3e19ff48e9c67f30645a9d8bdca0af834dd345f4
GIT binary patch
literal 64
tcmccjh>?Mj0SrJCD-a7qxD0|&+677j<(L^**cBeU&|zjU0MQQ23;?AA2E70P

literal 0
HcmV?d00001

diff --git a/tests/DATA1 b/tests/DATA1
new file mode 100644
index 
0000000000000000000000000000000000000000..22ed40e5751caf8edd06d0a28f2cb9ea6824febc
GIT binary patch
literal 60
zcmaEKkCBm?fq{V$h*^M`ABaIf5Qx)0{QoZv=0W5b7??R2Sp`0@un2sRV&(V%0O#fi
AjsO4v

literal 0
HcmV?d00001

diff --git a/tests/DATA2 b/tests/DATA2
new file mode 100644
index 
0000000000000000000000000000000000000000..68fc2d240cd34878747f552d1b12bbc0e59a5217
GIT binary patch
literal 92
zcmaEKkCBm?;Rgc~0|NsG5X%8E2q*!u-G~4GrNKM~1{M$<2^0_j()>US7GPlJU}P2e
Sz``Q%L5h{*0}_`X$OQnwj}Q_7

literal 0
HcmV?d00001

diff --git a/tests/sframe-api.h b/tests/sframe-api.h
new file mode 100644
index 000000000..254e9149e
--- /dev/null
+++ b/tests/sframe-api.h
@@ -0,0 +1,229 @@
+/* Public API to SFrame.
+
+   Copyright (C) 2022 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/>.  */
+
+#ifndef        _SFRAME_API_H
+#define        _SFRAME_API_H
+
+#include <sframe.h>
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+typedef struct sframe_decoder_ctx sframe_decoder_ctx;
+typedef struct sframe_encoder_ctx sframe_encoder_ctx;
+
+#define MAX_OFFSET_BYTES (SFRAME_FRE_OFFSET_4B * 2 * 3)
+
+/* User interfacing SFrame Row Entry.
+   An abstraction provided by SFrame so the consumer is decoupled from
+   the binary format representation of the same.  */
+
+typedef struct sframe_frame_row_entry
+{
+  uint32_t fre_start_addr;
+  unsigned char fre_info;
+  unsigned char fre_offsets[MAX_OFFSET_BYTES];
+} sframe_frame_row_entry;
+
+#define SFRAME_ERR ((int) -1)
+
+/* This macro holds information about all the available SFrame
+   errors.  It is used to form both an enum holding all the error
+   constants, and also the error strings themselves.  To use, define
+   _SFRAME_FIRST and _SFRAME_ITEM to expand as you like, then
+   mention the macro name.  See the enum after this for an example.  */
+#define _SFRAME_ERRORS \
+  _SFRAME_FIRST (SFRAME_ERR_VERSION_INVAL, "SFrame version not supported.") \
+  _SFRAME_ITEM (SFRAME_ERR_NOMEM, "Out of Memory.") \
+  _SFRAME_ITEM (SFRAME_ERR_INVAL, "Corrupt SFrame.") \
+  _SFRAME_ITEM (SFRAME_ERR_BUF_INVAL, "Buffer does not contain SFrame data.") \
+  _SFRAME_ITEM (SFRAME_ERR_DCTX_INVAL, "Corrupt SFrame decoder.") \
+  _SFRAME_ITEM (SFRAME_ERR_ECTX_INVAL, "Corrupt SFrame encoder.") \
+  _SFRAME_ITEM (SFRAME_ERR_FDE_INVAL, "Corrput FDE.") \
+  _SFRAME_ITEM (SFRAME_ERR_FRE_INVAL, "Corrupt FRE.") \
+  _SFRAME_ITEM (SFRAME_ERR_FDE_NOTFOUND,"FDE not found.") \
+  _SFRAME_ITEM (SFRAME_ERR_FDE_NOTSORTED, "FDEs not sorted.") \
+  _SFRAME_ITEM (SFRAME_ERR_FRE_NOTFOUND,"FRE not found.") \
+  _SFRAME_ITEM (SFRAME_ERR_FREOFFSET_NOPRESENT,"FRE offset not present.")
+
+#define        SFRAME_ERR_BASE 2000    /* Base value for SFrame errnos.  */
+
+enum
+  {
+#define _SFRAME_FIRST(NAME, STR) NAME = SFRAME_ERR_BASE
+#define _SFRAME_ITEM(NAME, STR) , NAME
+_SFRAME_ERRORS
+#undef _SFRAME_ITEM
+#undef _SFRAME_FIRST
+  };
+
+/* Count of SFrame errors.  */
+#define SFRAME_ERR_NERR (SFRAME_ERR_FREOFFSET_NOPRESENT - SFRAME_ERR_BASE + 1)
+
+/* Get the error message string.  */
+
+extern const char *
+sframe_errmsg (int error);
+
+/* Get FDE function info given a FRE_TYPE.  */
+
+extern unsigned char
+sframe_fde_func_info (unsigned int fre_type, unsigned int fde_type);
+
+/* Gather the FRE type given the function size.  */
+
+extern unsigned int
+sframe_calc_fre_type (unsigned int func_size);
+
+/* The SFrame Decoder.  */
+
+/* Decode the specified SFrame buffer CF_BUF of size CF_SIZE and return the
+   new SFrame decoder context.  Sets ERRP for the caller if any error.  */
+extern sframe_decoder_ctx *
+sframe_decode (const char *cf_buf, size_t cf_size, int *errp);
+
+/* Free the decoder context.  */
+extern void
+sframe_decoder_free (sframe_decoder_ctx **dctx);
+
+/* Get the size of the SFrame header from the decoder context DCTX.  */
+extern unsigned int
+sframe_decoder_get_hdr_size (sframe_decoder_ctx *dctx);
+
+/* Get the SFrame's abi/arch info.  */
+extern unsigned char
+sframe_decoder_get_abi_arch (sframe_decoder_ctx *dctx);
+
+/* Return the number of function descriptor entries in the SFrame decoder
+   DCTX.  */
+unsigned int
+sframe_decoder_get_num_fidx (sframe_decoder_ctx *dctx);
+
+/* Get the fixed FP offset from the decoder context DCTX.  */
+extern int8_t
+sframe_decoder_get_fixed_fp_offset (sframe_decoder_ctx *dctx);
+
+/* Get the fixed RA offset from the decoder context DCTX.  */
+extern int8_t
+sframe_decoder_get_fixed_ra_offset (sframe_decoder_ctx *dctx);
+
+/* Find the function descriptor entry which contains the specified address.  */
+extern sframe_func_desc_entry *
+sframe_get_funcdesc_with_addr (sframe_decoder_ctx *dctx,
+                              int32_t addr, int *errp);
+
+/* Find the SFrame Frame Row Entry which contains the PC.  Returns
+   SFRAME_ERR if failure.  */
+
+extern int
+sframe_find_fre (sframe_decoder_ctx *ctx, int32_t pc,
+                sframe_frame_row_entry *frep);
+
+/* Get the FRE_IDX'th FRE of the function at FUNC_IDX'th function
+   index entry in the SFrame decoder CTX.  Returns error code as
+   applicable.  */
+extern int
+sframe_decoder_get_fre (sframe_decoder_ctx *ctx,
+                       unsigned int func_idx,
+                       unsigned int fre_idx,
+                       sframe_frame_row_entry *fre);
+
+/* Get the data (NUM_FRES, FUNC_START_ADDRESS) from the function
+   descriptor entry at index I'th in the decoder CTX.  If failed,
+   return error code.  */
+extern int
+sframe_decoder_get_funcdesc (sframe_decoder_ctx *ctx,
+                            unsigned int i,
+                            uint32_t *num_fres,
+                            uint32_t *func_size,
+                            int32_t *func_start_address,
+                            unsigned char *func_info);
+
+/* SFrame textual dump.  */
+extern void
+dump_sframe (sframe_decoder_ctx *decoder, uint64_t addr);
+
+/* Get the base reg id from the FRE info.  Sets errp if fails.  */
+extern unsigned int
+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.  */
+extern int32_t
+sframe_fre_get_cfa_offset (sframe_frame_row_entry *fre, int *errp);
+
+/* Get the FP offset from the FRE.  If the offset is invalid, sets errp.  */
+extern int32_t
+sframe_fre_get_fp_offset (sframe_frame_row_entry *fre, int *errp);
+
+/* Get the RA offset from the FRE.  If the offset is invalid, sets errp.  */
+extern int32_t
+sframe_fre_get_ra_offset (sframe_frame_row_entry *fre, int *errp);
+
+/* The SFrame Encoder.  */
+
+/* Create an encoder context with the given SFrame format version VER, FLAGS
+   and ABI information.  Sets errp if failure.  */
+extern sframe_encoder_ctx *
+sframe_encode (unsigned char ver, unsigned char flags, int abi,
+              int8_t fixed_fp_offset, int8_t fixed_ra_offset, int *errp);
+
+/* Free the encoder context.  */
+extern void
+sframe_encoder_free (sframe_encoder_ctx **encoder);
+
+/* Get the size of the SFrame header from the encoder ctx ENCODER.  */
+extern unsigned int
+sframe_encoder_get_hdr_size (sframe_encoder_ctx *encoder);
+
+/* Get the abi/arch info from the SFrame encoder context CTX.  */
+extern unsigned char
+sframe_encoder_get_abi_arch (sframe_encoder_ctx *encoder);
+
+/* Return the number of function descriptor entries in the SFrame encoder
+   ENCODER.  */
+extern unsigned int
+sframe_encoder_get_num_fidx (sframe_encoder_ctx *encoder);
+
+/* Add an FRE to function at FUNC_IDX'th function descriptor index entry in
+   the encoder context.  */
+extern int
+sframe_encoder_add_fre (sframe_encoder_ctx *encoder,
+                       unsigned int func_idx,
+                       sframe_frame_row_entry *frep);
+
+/* Add a new function descriptor entry with START_ADDR, FUNC_SIZE and NUM_FRES
+   to the encoder.  */
+extern int
+sframe_encoder_add_funcdesc (sframe_encoder_ctx *encoder,
+                            int32_t start_addr,
+                            uint32_t func_size,
+                            unsigned char func_info,
+                            uint32_t num_fres);
+
+/* Serialize the contents of the encoder and return the buffer.  ENCODED_SIZE
+   is updated to the size of the buffer.  Sets ERRP if failure.  */
+extern char  *
+sframe_encoder_write (sframe_encoder_ctx *encoder,
+                     size_t *encoded_size, int *errp);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif                         /* _SFRAME_API_H */
diff --git a/tests/test-sframe-be-flipping.c b/tests/test-sframe-be-flipping.c
new file mode 100644
index 000000000..89c3fa8a6
--- /dev/null
+++ b/tests/test-sframe-be-flipping.c
@@ -0,0 +1,115 @@
+/* test-sframe-be-flipping.c -- Test for handling different endianness in 
Sframe.
+
+   Copyright (C) 2022 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 <stdio.h>
+#include <stdlib.h>
+#include <sys/stat.h>
+
+#include "sframe-api.h"
+
+/* DejaGnu should not use gnulib's vsnprintf replacement here.  */
+#undef vsnprintf
+#include <dejagnu.h>
+
+/* SFrame info from the following source (1 fde 5 fres):
+   static int cnt;
+   extern void foo (void);
+
+   int bar()
+   {
+     cnt++;
+     if (cnt == 3)
+       foo();
+    return (cnt);
+  }
+  gcc -mbig-endian -Wa,--gsframe -c -O3 t.c
+  objcopy --dump-section .sframe=DATA-BE t.o
+ */
+#define DATA   "DATA-BE"
+
+int
+main ()
+{
+  sframe_decoder_ctx *dctx = NULL;
+  uint32_t nfres, fsize;
+  int32_t fstart;
+  unsigned char finfo;
+  int err = 0;
+  FILE *fp;
+  struct stat st;
+  char *sf_buf;
+  size_t sf_size;
+
+#define TEST(name, cond)                                                      \
+  do                                                                          \
+    {                                                                         \
+      if (cond)                                                               \
+       pass (name);                                                          \
+      else                                                                    \
+       fail (name);                                                          \
+    }                                                                         \
+    while (0)
+
+  /* Test setup.  */
+  fp = fopen (DATA, "r");
+  if (fp == NULL)
+    goto setup_fail;
+  if (fstat (fileno (fp), &st) < 0)
+    {
+      perror ("fstat");
+      fclose (fp);
+      goto setup_fail;
+    }
+  sf_buf = malloc (st.st_size);
+  if (sf_buf == NULL)
+    {
+      perror ("malloc");
+      goto setup_fail;
+    }
+  sf_size = fread (sf_buf, 1, st.st_size, fp);
+  fclose (fp);
+  if (sf_size == 0)
+    {
+      fprintf (stderr, "Decode: Read buffer failed\n");
+      goto setup_fail;
+    }
+
+  /* Execute tests.  */
+
+  /* Call to sframe_decode will endian flip the input buffer (big-endian) if
+     the host running the test is a little-endian system.  This endian-flipped
+     copy of the buffer is kept internally in dctx.  */
+  dctx = sframe_decode (sf_buf, sf_size, &err);
+  TEST ("be-flipping: Decoder setup", dctx != NULL);
+
+  unsigned int fde_cnt = sframe_decoder_get_num_fidx (dctx);
+  TEST ("be-flipping: Decoder FDE count", fde_cnt == 1);
+
+  err = sframe_decoder_get_funcdesc (dctx, 0, &nfres, &fsize, &fstart, &finfo);
+  TEST ("be-flipping: Decoder get FDE", err == 0);
+  TEST ("be-flipping: Decoder FRE count", nfres == 5);
+      
+  sframe_decoder_free (&dctx);
+  return 0;
+
+setup_fail:
+  sframe_decoder_free (&dctx);
+  fail ("be-flipping: Test setup");
+  return 1;
+}
diff --git a/tests/test-sframe-encode1.c b/tests/test-sframe-encode1.c
new file mode 100644
index 000000000..29a6942d9
--- /dev/null
+++ b/tests/test-sframe-encode1.c
@@ -0,0 +1,187 @@
+/* test-sframe-encode1.c -- Test for encoder in SFrame.
+
+   Copyright (C) 2022 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 <stdio.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>
+
+static int
+add_fde1 (sframe_encoder_ctx *encode, int idx)
+{
+  int i, err;
+  /* A contiguous block containing 4 FREs.  */
+  sframe_frame_row_entry fres[]
+    = { {0x0, 0x3, {0x8, 0, 0}},
+       {0x1, 0x5, {0x10, 0xf0, 0}},
+       {0x4, 0x4, {0x10, 0xf0, 0}},
+       {0x1a, 0x5, {0x8, 0xf0, 0}}
+      };
+
+  unsigned char finfo = sframe_fde_func_info (SFRAME_FRE_TYPE_ADDR1,
+                                             SFRAME_FDE_TYPE_PCINC);
+  err = sframe_encoder_add_funcdesc (encode, 0xfffff03e, 0x1b, finfo, 4);
+  if (err == -1)
+    return err;
+
+  for (i = 0; i < 4; 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)
+{
+  int i, err;
+  /* A contiguous block containing 4 FREs.  */
+  sframe_frame_row_entry fres[]
+    = { {0x0, 0x3, {0x8, 0, 0}},
+       {0x1, 0x5, {0x10, 0xf0, 0}},
+       {0x4, 0x4, {0x10, 0xf0, 0}},
+       {0xf, 0x5, {0x8, 0xf0, 0}}
+      };
+
+  unsigned char finfo = sframe_fde_func_info (SFRAME_FRE_TYPE_ADDR1,
+                                             SFRAME_FDE_TYPE_PCINC);
+  err = sframe_encoder_add_funcdesc (encode, 0xfffff059, 0x10, finfo, 4);
+  if (err == -1)
+    return err;
+
+  for (i = 0; i < 4; i++)
+    if (sframe_encoder_add_fre (encode, idx, fres+i) == SFRAME_ERR)
+      return -1;
+
+  return 0;
+}
+
+/*
+ * SFrame info from the following source (2 fdes, 4 fres in each fde):
+ * static int cnt;
+ * int foo() { return ++cnt; }
+ * int main() { return foo(); }
+ */
+#define DATA    "DATA2"
+
+static int
+data_match (char *sframe_buf, size_t sz)
+{
+  FILE *fp;
+  struct stat st;
+  char *sf_buf;
+  size_t sf_size;
+  int diffs;
+
+  fp = fopen (DATA, "r");
+  if (fp == NULL)
+    return 0;
+  if (fstat (fileno (fp), &st) < 0)
+    {
+      perror ("fstat");
+      fclose (fp);
+      return 0;
+    }
+  sf_buf = malloc (st.st_size);
+  if (sf_buf == NULL)
+    {
+      perror ("malloc");
+      return 0;
+    }
+  sf_size = fread (sf_buf, 1, st.st_size, fp);
+  fclose (fp);
+  if (sf_size == 0 || sf_buf == NULL)
+    {
+      fprintf (stderr, "Encode: Read section failed\n");
+      return 0;
+    }
+  if (sf_size != sz)
+    return 0;
+
+  diffs = memcmp (sf_buf, sframe_buf, sz);
+
+  free (sf_buf);
+  return diffs == 0;
+}
+
+int main ()
+{
+  sframe_encoder_ctx *encode;
+  sframe_frame_row_entry frep;
+  char *sframe_buf;
+  size_t sf_size;
+  int err = 0;
+
+  encode = sframe_encode (SFRAME_VERSION, 0,
+                         SFRAME_ABI_AMD64_ENDIAN_LITTLE, 0, -8, &err);
+
+  if (sframe_encoder_get_num_fidx (encode) != 0)
+    {
+      fprintf (stderr, "Encode: incorrect FDEs count\n");
+      goto fail;
+    }
+
+  /* Error test.  */
+  if (sframe_encoder_add_fre (encode, 1, &frep) != SFRAME_ERR)
+    {
+      fprintf (stderr, "Encode: Adding FRE befoer FDE does\n");
+      goto fail;
+    }
+
+  if (add_fde1 (encode, 0) == -1)
+    {
+      fprintf (stderr, "Encode: Adding FDE1\n");
+      goto fail;
+    }
+  if (add_fde2 (encode, 1) == -1)
+    {
+      fprintf (stderr, "Encode: Adding FDE2\n");
+      goto fail;
+    }
+
+  if (sframe_encoder_get_num_fidx (encode) != 2)
+    {
+      fprintf (stderr, "Encode: Wrong FDE count\n");
+      goto fail;
+    }
+
+  sframe_buf = sframe_encoder_write (encode, &sf_size, &err);
+  if (err)
+    {
+      fprintf (stderr, "Encode: Write failed\n");
+      goto fail;
+    }
+  if (data_match (sframe_buf, sf_size))
+    {
+      sframe_encoder_free (&encode);
+      pass ("encode test");
+      return 0;
+    }
+
+fail:
+  sframe_encoder_free (&encode);
+  fail ("encode test");
+  return 1;
+}
diff --git a/tests/test-sframe-frecnt1.c b/tests/test-sframe-frecnt1.c
new file mode 100644
index 000000000..ecee0842a
--- /dev/null
+++ b/tests/test-sframe-frecnt1.c
@@ -0,0 +1,99 @@
+/* test-sframe-frecnt1.c -- Test for decoder in SFrame.
+
+   Copyright (C) 2022 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 <stdio.h>
+#include <stdlib.h>
+#include <sys/stat.h>
+
+#include "sframe-api.h"
+
+/* DejaGnu should not use gnulib's vsnprintf replacement here.  */
+#undef vsnprintf
+#include <dejagnu.h>
+
+/*
+ * SFrame info from the following source (1 fde 4 fres):
+ * static int cnt;
+ * int main() { cnt++; return (cnt); }
+ */
+#define DATA   "DATA1"
+
+int
+main ()
+{
+  sframe_decoder_ctx *dctx = NULL;
+  uint32_t nfres, fsize;
+  int32_t fstart;
+  unsigned char finfo;
+  int err = 0;
+  FILE *fp;
+  struct stat st;
+  char *sf_buf;
+  size_t sf_size;
+
+#define TEST(name, cond)                                                      \
+  do                                                                          \
+    {                                                                         \
+      if (cond)                                                               \
+       pass (name);                                                          \
+      else                                                                    \
+       fail (name);                                                          \
+    }                                                                         \
+    while (0)
+
+  /* Test Setup.  */
+  fp = fopen (DATA, "r");
+  if (fp == NULL)
+    goto setup_fail;
+  if (fstat (fileno (fp), &st) < 0)
+    {
+      perror ("fstat");
+      fclose (fp);
+      goto setup_fail;
+    }
+  sf_buf = malloc (st.st_size);
+  if (sf_buf == NULL)
+    {
+      perror ("malloc");
+      goto setup_fail;
+    }
+
+  /* Execute tests.  */
+  sf_size = fread (sf_buf, 1, st.st_size, fp);
+  fclose (fp);
+  TEST ("frecnt-1: Read section", sf_size != 0);
+
+  dctx = sframe_decode (sf_buf, sf_size, &err);
+  TEST ("frecnt-1: Decoder setup", dctx != NULL);
+
+  unsigned int fde_cnt = sframe_decoder_get_num_fidx (dctx);
+  TEST ("frecnt-1: Decoder FDE count", fde_cnt == 1);
+
+  err = sframe_decoder_get_funcdesc (dctx, 0, &nfres, &fsize, &fstart, &finfo);
+  TEST ("frecnt-1: Decoder get FDE", err == 0);
+  TEST ("frecnt-1: Decoder FRE count", nfres == 4);
+
+  sframe_decoder_free (&dctx);
+  return 0;
+
+setup_fail:
+  sframe_decoder_free (&dctx);
+  fail ("frecnt-1: Test setup");
+  return 1;
+}
diff --git a/tests/test-sframe-frecnt2.c b/tests/test-sframe-frecnt2.c
new file mode 100644
index 000000000..6479a70e4
--- /dev/null
+++ b/tests/test-sframe-frecnt2.c
@@ -0,0 +1,103 @@
+/* test-sframe-frecnt2.c -- Test for decoder in SFrame.
+
+   Copyright (C) 2022 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 <stdio.h>
+#include <stdlib.h>
+#include <sys/stat.h>
+
+#include "sframe-api.h"
+
+/* DejaGnu should not use gnulib's vsnprintf replacement here.  */
+#undef vsnprintf
+#include <dejagnu.h>
+
+/*
+ * SFrame info from the following source (2 fde 8 fres):
+ * static int cnt;
+ * int foo() { return ++cnt; }
+ * int main() { return foo(); }
+ */
+#define DATA   "DATA2"
+
+int
+main ()
+{
+  sframe_decoder_ctx *dctx = NULL;
+  uint32_t nfres, fsize;
+  int32_t fstart;
+  unsigned char finfo;
+  int i, err = 0;
+  FILE *fp;
+  struct stat st;
+  char *sf_buf;
+  size_t sf_size;
+
+#define TEST(name, cond)                                                      \
+  do                                                                          \
+    {                                                                         \
+      if (cond)                                                               \
+       pass (name);                                                          \
+      else                                                                    \
+       fail (name);                                                          \
+    }                                                                         \
+    while (0)
+
+  fp = fopen (DATA, "r");
+  if (fp == NULL)
+    goto setup_fail;
+  if (fstat (fileno (fp), &st) < 0)
+    {
+      perror ("fstat");
+      fclose (fp);
+      goto setup_fail;
+    }
+  sf_buf = malloc (st.st_size);
+  if (sf_buf == NULL)
+    {
+      perror ("malloc");
+      goto setup_fail;
+    }
+
+  /* Execute tests.  */
+  sf_size = fread (sf_buf, 1, st.st_size, fp);
+  fclose (fp);
+  TEST ("frecnt-2: Read section", sf_size != 0);
+
+  dctx = sframe_decode (sf_buf, sf_size, &err);
+  TEST ("frecnt-2: Decode setup", dctx != NULL);
+
+  unsigned int fde_cnt = sframe_decoder_get_num_fidx (dctx);
+  TEST ("frecnt-2: Decode FDE count", fde_cnt == 2);
+
+  for (i = 0; i < fde_cnt; ++i)
+    {
+      err = sframe_decoder_get_funcdesc (dctx, i, &nfres, &fsize, &fstart,
+                                        &finfo);
+      TEST ("frecnt-2: Decode get FDE", err == 0);
+      TEST ("frecnt-2: Decode get FRE", nfres == 4);
+    }
+
+  sframe_decoder_free (&dctx);
+  return 0;
+
+setup_fail:
+  sframe_decoder_free (&dctx);
+  fail ("frecnt-2: Test setup");
+  return 1;
+}
-- 
2.18.2




reply via email to

[Prev in Thread] Current Thread [Next in Thread]