(root)/
binutils-2.41/
libsframe/
sframe.c
       1  /* sframe.c - SFrame decoder/encoder.
       2  
       3     Copyright (C) 2022-2023 Free Software Foundation, Inc.
       4  
       5     This file is part of libsframe.
       6  
       7     This program is free software; you can redistribute it and/or modify
       8     it under the terms of the GNU General Public License as published by
       9     the Free Software Foundation; either version 3 of the License, or
      10     (at your option) any later version.
      11  
      12     This program is distributed in the hope that it will be useful,
      13     but WITHOUT ANY WARRANTY; without even the implied warranty of
      14     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      15     GNU General Public License for more details.
      16  
      17     You should have received a copy of the GNU General Public License
      18     along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
      19  
      20  #include "config.h"
      21  #include <stdio.h>
      22  #include <stdlib.h>
      23  #include <stdarg.h>
      24  #include <string.h>
      25  #include "sframe-impl.h"
      26  #include "swap.h"
      27  
      28  struct sf_fde_tbl
      29  {
      30    unsigned int count;
      31    unsigned int alloced;
      32    sframe_func_desc_entry entry[1];
      33  };
      34  
      35  struct sf_fre_tbl
      36  {
      37    unsigned int count;
      38    unsigned int alloced;
      39    sframe_frame_row_entry entry[1];
      40  };
      41  
      42  #define _sf_printflike_(string_index,first_to_check) \
      43      __attribute__ ((__format__ (__printf__, (string_index), (first_to_check))))
      44  
      45  static void debug_printf (const char *, ...);
      46  
      47  static int _sframe_debug;	/* Control for printing out debug info.  */
      48  static int number_of_entries = 64;
      49  
      50  static void
      51  sframe_init_debug (void)
      52  {
      53    static int inited;
      54  
      55    if (!inited)
      56      {
      57        _sframe_debug = getenv ("SFRAME_DEBUG") != NULL;
      58        inited = 1;
      59      }
      60  }
      61  
      62  _sf_printflike_ (1, 2)
      63  static void debug_printf (const char *format, ...)
      64  {
      65    if (_sframe_debug)
      66      {
      67        va_list args;
      68  
      69        va_start (args, format);
      70        vfprintf (stderr, format, args);
      71        va_end (args);
      72      }
      73  }
      74  
      75  /* Generate bitmask of given size in bytes.  This is used for
      76     some checks on the FRE start address.
      77     SFRAME_FRE_TYPE_ADDR1 => 1 byte => [ bitmask = 0xff ]
      78     SFRAME_FRE_TYPE_ADDR2 => 2 byte => [ bitmask = 0xffff ]
      79     SFRAME_FRE_TYPE_ADDR4 => 4 byte => [ bitmask = 0xffffffff ].  */
      80  #define SFRAME_BITMASK_OF_SIZE(size_in_bytes) \
      81    (((uint64_t)1 << (size_in_bytes*8)) - 1)
      82  
      83  /* Store the specified error code into errp if it is non-NULL.
      84     Return SFRAME_ERR.  */
      85  
      86  static int
      87  sframe_set_errno (int *errp, int error)
      88  {
      89    if (errp != NULL)
      90      *errp = error;
      91    return SFRAME_ERR;
      92  }
      93  
      94  /* Store the specified error code into errp if it is non-NULL.
      95     Return NULL.  */
      96  
      97  static void *
      98  sframe_ret_set_errno (int *errp, int error)
      99  {
     100    if (errp != NULL)
     101      *errp = error;
     102    return NULL;
     103  }
     104  
     105  /* Get the SFrame header size.  */
     106  
     107  static uint32_t
     108  sframe_get_hdr_size (sframe_header *sfh)
     109  {
     110    return SFRAME_V1_HDR_SIZE (*sfh);
     111  }
     112  
     113  /* Access functions for frame row entry data.  */
     114  
     115  static uint8_t
     116  sframe_fre_get_offset_count (uint8_t fre_info)
     117  {
     118    return SFRAME_V1_FRE_OFFSET_COUNT (fre_info);
     119  }
     120  
     121  static uint8_t
     122  sframe_fre_get_offset_size (uint8_t fre_info)
     123  {
     124    return SFRAME_V1_FRE_OFFSET_SIZE (fre_info);
     125  }
     126  
     127  static bool
     128  sframe_get_fre_ra_mangled_p (uint8_t fre_info)
     129  {
     130    return SFRAME_V1_FRE_MANGLED_RA_P (fre_info);
     131  }
     132  
     133  /* Access functions for info from function descriptor entry.  */
     134  
     135  static uint32_t
     136  sframe_get_fre_type (sframe_func_desc_entry *fdep)
     137  {
     138    uint32_t fre_type = 0;
     139    if (fdep)
     140      fre_type = SFRAME_V1_FUNC_FRE_TYPE (fdep->sfde_func_info);
     141    return fre_type;
     142  }
     143  
     144  static uint32_t
     145  sframe_get_fde_type (sframe_func_desc_entry *fdep)
     146  {
     147    uint32_t fde_type = 0;
     148    if (fdep)
     149      fde_type = SFRAME_V1_FUNC_FDE_TYPE (fdep->sfde_func_info);
     150    return fde_type;
     151  }
     152  
     153  /* Check if flipping is needed, based on ENDIAN.  */
     154  
     155  static int
     156  need_swapping (int endian)
     157  {
     158    unsigned int ui = 1;
     159    char *c = (char *)&ui;
     160    int is_little = (int)*c;
     161  
     162    switch (endian)
     163      {
     164        case SFRAME_ABI_AARCH64_ENDIAN_LITTLE:
     165        case SFRAME_ABI_AMD64_ENDIAN_LITTLE:
     166  	return !is_little;
     167        case SFRAME_ABI_AARCH64_ENDIAN_BIG:
     168  	return is_little;
     169        default:
     170  	break;
     171      }
     172  
     173    return 0;
     174  }
     175  
     176  /* Flip the endianness of the SFrame header.  */
     177  
     178  static void
     179  flip_header (sframe_header *sfheader)
     180  {
     181    swap_thing (sfheader->sfh_preamble.sfp_magic);
     182    swap_thing (sfheader->sfh_preamble.sfp_version);
     183    swap_thing (sfheader->sfh_preamble.sfp_flags);
     184    swap_thing (sfheader->sfh_cfa_fixed_fp_offset);
     185    swap_thing (sfheader->sfh_cfa_fixed_ra_offset);
     186    swap_thing (sfheader->sfh_num_fdes);
     187    swap_thing (sfheader->sfh_num_fres);
     188    swap_thing (sfheader->sfh_fre_len);
     189    swap_thing (sfheader->sfh_fdeoff);
     190    swap_thing (sfheader->sfh_freoff);
     191  }
     192  
     193  static void
     194  flip_fde (sframe_func_desc_entry *fdep)
     195  {
     196    swap_thing (fdep->sfde_func_start_address);
     197    swap_thing (fdep->sfde_func_size);
     198    swap_thing (fdep->sfde_func_start_fre_off);
     199    swap_thing (fdep->sfde_func_num_fres);
     200  }
     201  
     202  /* Check if SFrame header has valid data.  */
     203  
     204  static bool
     205  sframe_header_sanity_check_p (sframe_header *hp)
     206  {
     207    unsigned char all_flags = SFRAME_F_FDE_SORTED | SFRAME_F_FRAME_POINTER;
     208    /* Check preamble is valid.  */
     209    if (hp->sfh_preamble.sfp_magic != SFRAME_MAGIC
     210        || (hp->sfh_preamble.sfp_version != SFRAME_VERSION_1
     211  	  && hp->sfh_preamble.sfp_version != SFRAME_VERSION_2)
     212        || (hp->sfh_preamble.sfp_flags | all_flags) != all_flags)
     213      return false;
     214  
     215    /* Check offsets are valid.  */
     216    if (hp->sfh_fdeoff > hp->sfh_freoff)
     217      return false;
     218  
     219    return true;
     220  }
     221  
     222  /* Flip the start address pointed to by FP.  */
     223  
     224  static void
     225  flip_fre_start_address (char *addr, uint32_t fre_type)
     226  {
     227    if (fre_type == SFRAME_FRE_TYPE_ADDR2)
     228      {
     229        uint16_t *start_addr = (uint16_t *)addr;
     230        swap_thing (*start_addr);
     231      }
     232    else if (fre_type == SFRAME_FRE_TYPE_ADDR4)
     233      {
     234        uint32_t *start_addr = (uint32_t *)addr;
     235        swap_thing (*start_addr);
     236      }
     237  }
     238  
     239  static void
     240  flip_fre_stack_offsets (char *offsets, uint8_t offset_size, uint8_t offset_cnt)
     241  {
     242    int j;
     243  
     244    if (offset_size == SFRAME_FRE_OFFSET_2B)
     245      {
     246        uint16_t *ust = (uint16_t *)offsets;
     247        for (j = offset_cnt; j > 0; ust++, j--)
     248  	swap_thing (*ust);
     249      }
     250    else if (offset_size == SFRAME_FRE_OFFSET_4B)
     251      {
     252        uint32_t *uit = (uint32_t *)offsets;
     253        for (j = offset_cnt; j > 0; uit++, j--)
     254  	swap_thing (*uit);
     255      }
     256  }
     257  
     258  /* Get the FRE start address size, given the FRE_TYPE.  */
     259  
     260  static size_t
     261  sframe_fre_start_addr_size (uint32_t fre_type)
     262  {
     263    size_t addr_size = 0;
     264    switch (fre_type)
     265      {
     266      case SFRAME_FRE_TYPE_ADDR1:
     267        addr_size = 1;
     268        break;
     269      case SFRAME_FRE_TYPE_ADDR2:
     270        addr_size = 2;
     271        break;
     272      case SFRAME_FRE_TYPE_ADDR4:
     273        addr_size = 4;
     274        break;
     275      default:
     276        /* No other value is expected.  */
     277        sframe_assert (0);
     278        break;
     279      }
     280    return addr_size;
     281  }
     282  
     283  /* Check if the FREP has valid data.  */
     284  
     285  static bool
     286  sframe_fre_sanity_check_p (sframe_frame_row_entry *frep)
     287  {
     288    uint8_t offset_size, offset_cnt;
     289    uint8_t fre_info;
     290  
     291    if (frep == NULL)
     292      return false;
     293  
     294    fre_info = frep->fre_info;
     295    offset_size = sframe_fre_get_offset_size (fre_info);
     296  
     297    if (offset_size != SFRAME_FRE_OFFSET_1B
     298        && offset_size != SFRAME_FRE_OFFSET_2B
     299        && offset_size != SFRAME_FRE_OFFSET_4B)
     300      return false;
     301  
     302    offset_cnt = sframe_fre_get_offset_count (fre_info);
     303    if (offset_cnt > MAX_NUM_STACK_OFFSETS)
     304      return false;
     305  
     306    return true;
     307  }
     308  
     309  /* Get FRE_INFO's offset size in bytes.  */
     310  
     311  static size_t
     312  sframe_fre_offset_bytes_size (uint8_t fre_info)
     313  {
     314    uint8_t offset_size, offset_cnt;
     315  
     316    offset_size = sframe_fre_get_offset_size (fre_info);
     317  
     318    debug_printf ("offset_size =  %u\n", offset_size);
     319  
     320    offset_cnt = sframe_fre_get_offset_count (fre_info);
     321  
     322    if (offset_size == SFRAME_FRE_OFFSET_2B
     323        || offset_size == SFRAME_FRE_OFFSET_4B)	/* 2 or 4 bytes.  */
     324      return (offset_cnt * (offset_size * 2));
     325  
     326    return (offset_cnt);
     327  }
     328  
     329  /* Get total size in bytes to represent FREP in the binary format.  This
     330     includes the starting address, FRE info, and all the offsets.  */
     331  
     332  static size_t
     333  sframe_fre_entry_size (sframe_frame_row_entry *frep, uint32_t fre_type)
     334  {
     335    if (frep == NULL)
     336      return 0;
     337  
     338    uint8_t fre_info = frep->fre_info;
     339    size_t addr_size = sframe_fre_start_addr_size (fre_type);
     340  
     341    return (addr_size + sizeof (frep->fre_info)
     342  	  + sframe_fre_offset_bytes_size (fre_info));
     343  }
     344  
     345  /* Get the function descriptor entry at index FUNC_IDX in the decoder
     346     context CTX.  */
     347  
     348  static sframe_func_desc_entry *
     349  sframe_decoder_get_funcdesc_at_index (sframe_decoder_ctx *ctx,
     350  				      uint32_t func_idx)
     351  {
     352    sframe_func_desc_entry *fdep;
     353    uint32_t num_fdes;
     354    int err;
     355  
     356    num_fdes = sframe_decoder_get_num_fidx (ctx);
     357    if (num_fdes == 0
     358        || func_idx >= num_fdes
     359        || ctx->sfd_funcdesc == NULL)
     360      return sframe_ret_set_errno (&err, SFRAME_ERR_DCTX_INVAL);
     361  
     362    fdep = &ctx->sfd_funcdesc[func_idx];
     363    return fdep;
     364  }
     365  
     366  /* Check whether for the given FDEP, the SFrame Frame Row Entry identified via
     367     the START_IP_OFFSET and the END_IP_OFFSET, provides the stack trace
     368     information for the PC.  */
     369  
     370  static bool
     371  sframe_fre_check_range_p (sframe_func_desc_entry *fdep,
     372  			  int32_t start_ip_offset, int32_t end_ip_offset,
     373  			  int32_t pc)
     374  {
     375    int32_t start_ip, end_ip;
     376    int32_t func_start_addr;
     377    uint8_t rep_block_size;
     378    uint32_t fde_type;
     379    int32_t masked_pc;
     380    bool mask_p;
     381    bool ret;
     382  
     383    ret = false;
     384  
     385    if (!fdep)
     386      return ret;
     387  
     388    func_start_addr = fdep->sfde_func_start_address;
     389    fde_type = sframe_get_fde_type (fdep);
     390    mask_p = (fde_type == SFRAME_FDE_TYPE_PCMASK);
     391    rep_block_size = fdep->sfde_func_rep_size;
     392  
     393    if (!mask_p)
     394      {
     395        start_ip = start_ip_offset + func_start_addr;
     396        end_ip = end_ip_offset + func_start_addr;
     397        ret = ((start_ip <= pc) && (end_ip >= pc));
     398      }
     399    else
     400      {
     401        /* For FDEs for repetitive pattern of insns, we need to return the FRE
     402  	 where pc % rep_block_size is between start_ip_offset and
     403  	 end_ip_offset.  */
     404        masked_pc = pc % rep_block_size;
     405        ret = ((start_ip_offset <= masked_pc) && (end_ip_offset >= masked_pc));
     406      }
     407  
     408    return ret;
     409  }
     410  
     411  static int
     412  flip_fre (char *fp, uint32_t fre_type, size_t *fre_size)
     413  {
     414    uint8_t fre_info;
     415    uint8_t offset_size, offset_cnt;
     416    size_t addr_size, fre_info_size = 0;
     417    int err = 0;
     418  
     419    if (fre_size == NULL)
     420      return sframe_set_errno (&err, SFRAME_ERR_INVAL);
     421  
     422    flip_fre_start_address (fp, fre_type);
     423  
     424    /* Advance the buffer pointer to where the FRE info is.  */
     425    addr_size = sframe_fre_start_addr_size (fre_type);
     426    fp += addr_size;
     427  
     428    /* FRE info is uint8_t.  No need to flip.  */
     429    fre_info = *(uint8_t*)fp;
     430    offset_size = sframe_fre_get_offset_size (fre_info);
     431    offset_cnt = sframe_fre_get_offset_count (fre_info);
     432  
     433    /* Advance the buffer pointer to where the stack offsets are.  */
     434    fre_info_size = sizeof (uint8_t);
     435    fp += fre_info_size;
     436    flip_fre_stack_offsets (fp, offset_size, offset_cnt);
     437  
     438    *fre_size
     439      = addr_size + fre_info_size + sframe_fre_offset_bytes_size (fre_info);
     440  
     441    return 0;
     442  }
     443  
     444  /* Endian flip the contents of FRAME_BUF of size BUF_SIZE.
     445     The SFrame header in the FRAME_BUF must be endian flipped prior to
     446     calling flip_sframe.
     447  
     448     Endian flipping at decode time vs encode time have different needs.  At
     449     encode time, the frame_buf is in host endianness, and hence, values should
     450     be read up before the buffer is changed to foreign endianness.  This change
     451     of behaviour is specified via TO_FOREIGN arg.
     452  
     453     If an error code is returned, the buffer should not be used.  */
     454  
     455  static int
     456  flip_sframe (char *frame_buf, size_t buf_size, uint32_t to_foreign)
     457  {
     458    unsigned int i, j, prev_frep_index;
     459    sframe_header *ihp;
     460    char *fdes;
     461    char *fp = NULL;
     462    sframe_func_desc_entry *fdep;
     463    unsigned int num_fdes = 0;
     464    unsigned int num_fres = 0;
     465    uint32_t fre_type = 0;
     466    uint32_t fre_offset = 0;
     467    size_t esz = 0;
     468    size_t hdrsz = 0;
     469    int err = 0;
     470    /* For error checking.  */
     471    size_t bytes_flipped = 0;
     472  
     473    /* Header must be in host endianness at this time.  */
     474    ihp = (sframe_header *)frame_buf;
     475  
     476    if (!sframe_header_sanity_check_p (ihp))
     477      return sframe_set_errno (&err, SFRAME_ERR_BUF_INVAL);
     478  
     479    /* The contents of the SFrame header are safe to read.  Get the number of
     480       FDEs and the first FDE in the buffer.  */
     481    hdrsz = sframe_get_hdr_size (ihp);
     482    num_fdes = ihp->sfh_num_fdes;
     483    fdes = frame_buf + hdrsz + ihp->sfh_fdeoff;
     484    fdep = (sframe_func_desc_entry *)fdes;
     485  
     486    j = 0;
     487    prev_frep_index = 0;
     488    for (i = 0; i < num_fdes; fdep++, i++)
     489      {
     490        if ((char*)fdep >= (frame_buf + buf_size))
     491  	goto bad;
     492  
     493        if (to_foreign)
     494  	{
     495  	  num_fres = fdep->sfde_func_num_fres;
     496  	  fre_type = sframe_get_fre_type (fdep);
     497  	  fre_offset = fdep->sfde_func_start_fre_off;
     498  	}
     499  
     500        flip_fde (fdep);
     501        bytes_flipped += sizeof (sframe_func_desc_entry);
     502  
     503        if (!to_foreign)
     504  	{
     505  	  num_fres = fdep->sfde_func_num_fres;
     506  	  fre_type = sframe_get_fre_type (fdep);
     507  	  fre_offset = fdep->sfde_func_start_fre_off;
     508  	}
     509  
     510        fp = frame_buf + sframe_get_hdr_size (ihp) + ihp->sfh_freoff;
     511        fp += fre_offset;
     512        for (; j < prev_frep_index + num_fres; j++)
     513  	{
     514  	  if (flip_fre (fp, fre_type, &esz))
     515  	    goto bad;
     516  	  bytes_flipped += esz;
     517  
     518  	  if (esz == 0 || esz > buf_size)
     519  	    goto bad;
     520  	  fp += esz;
     521  	}
     522        prev_frep_index = j;
     523      }
     524    /* All FDEs and FREs must have been endian flipped by now.  */
     525    if ((j != ihp->sfh_num_fres) || (bytes_flipped != (buf_size - hdrsz)))
     526      goto bad;
     527  
     528    /* Success.  */
     529    return 0;
     530  bad:
     531    return SFRAME_ERR;
     532  }
     533  
     534  /* The SFrame Decoder.  */
     535  
     536  /* Get SFrame header from the given decoder context DCTX.  */
     537  
     538  static sframe_header *
     539  sframe_decoder_get_header (sframe_decoder_ctx *dctx)
     540  {
     541    sframe_header *hp = NULL;
     542    if (dctx != NULL)
     543      hp = &dctx->sfd_header;
     544    return hp;
     545  }
     546  
     547  /* Compare function for qsort'ing the FDE table.  */
     548  
     549  static int
     550  fde_func (const void *p1, const void *p2)
     551  {
     552    const sframe_func_desc_entry *aa = p1;
     553    const sframe_func_desc_entry *bb = p2;
     554  
     555    if (aa->sfde_func_start_address < bb->sfde_func_start_address)
     556      return -1;
     557    else if (aa->sfde_func_start_address > bb->sfde_func_start_address)
     558      return 1;
     559    return 0;
     560  }
     561  
     562  /* Get IDX'th offset from FRE.  Set errp as applicable.  */
     563  
     564  static int32_t
     565  sframe_get_fre_offset (sframe_frame_row_entry *fre, int idx, int *errp)
     566  {
     567    uint8_t offset_cnt, offset_size;
     568  
     569    if (fre == NULL || !sframe_fre_sanity_check_p (fre))
     570      return sframe_set_errno (errp, SFRAME_ERR_FRE_INVAL);
     571  
     572    offset_cnt = sframe_fre_get_offset_count (fre->fre_info);
     573    offset_size = sframe_fre_get_offset_size (fre->fre_info);
     574  
     575    if (offset_cnt < idx + 1)
     576      return sframe_set_errno (errp, SFRAME_ERR_FREOFFSET_NOPRESENT);
     577  
     578    if (errp)
     579      *errp = 0; /* Offset Valid.  */
     580  
     581    if (offset_size == SFRAME_FRE_OFFSET_1B)
     582      {
     583        int8_t *sp = (int8_t *)fre->fre_offsets;
     584        return sp[idx];
     585      }
     586    else if (offset_size == SFRAME_FRE_OFFSET_2B)
     587      {
     588        int16_t *sp = (int16_t *)fre->fre_offsets;
     589        return sp[idx];
     590      }
     591    else
     592      {
     593        int32_t *ip = (int32_t *)fre->fre_offsets;
     594        return ip[idx];
     595      }
     596  }
     597  
     598  /* Free the decoder context.  */
     599  
     600  void
     601  sframe_decoder_free (sframe_decoder_ctx **dctxp)
     602  {
     603    if (dctxp != NULL)
     604      {
     605        sframe_decoder_ctx *dctx = *dctxp;
     606        if (dctx == NULL)
     607  	return;
     608  
     609        if (dctx->sfd_funcdesc != NULL)
     610  	{
     611  	  free (dctx->sfd_funcdesc);
     612  	  dctx->sfd_funcdesc = NULL;
     613  	}
     614        if (dctx->sfd_fres != NULL)
     615  	{
     616  	  free (dctx->sfd_fres);
     617  	  dctx->sfd_fres = NULL;
     618  	}
     619        if (dctx->sfd_buf != NULL)
     620  	{
     621  	  free (dctx->sfd_buf);
     622  	  dctx->sfd_buf = NULL;
     623  	}
     624  
     625        free (*dctxp);
     626        *dctxp = NULL;
     627      }
     628  }
     629  
     630  /* Create an FDE function info byte given an FRE_TYPE and an FDE_TYPE.  */
     631  /* FIXME API for linker.  Revisit if its better placed somewhere else?  */
     632  
     633  unsigned char
     634  sframe_fde_create_func_info (uint32_t fre_type,
     635  			     uint32_t fde_type)
     636  {
     637    unsigned char func_info;
     638    sframe_assert (fre_type == SFRAME_FRE_TYPE_ADDR1
     639  		   || fre_type == SFRAME_FRE_TYPE_ADDR2
     640  		   || fre_type == SFRAME_FRE_TYPE_ADDR4);
     641    sframe_assert (fde_type == SFRAME_FDE_TYPE_PCINC
     642  		    || fde_type == SFRAME_FDE_TYPE_PCMASK);
     643    func_info = SFRAME_V1_FUNC_INFO (fde_type, fre_type);
     644    return func_info;
     645  }
     646  
     647  /* Get the FRE type given the function size.  */
     648  /* FIXME API for linker.  Revisit if its better placed somewhere else?  */
     649  
     650  uint32_t
     651  sframe_calc_fre_type (size_t func_size)
     652  {
     653    uint32_t fre_type = 0;
     654    if (func_size < SFRAME_FRE_TYPE_ADDR1_LIMIT)
     655      fre_type = SFRAME_FRE_TYPE_ADDR1;
     656    else if (func_size < SFRAME_FRE_TYPE_ADDR2_LIMIT)
     657      fre_type = SFRAME_FRE_TYPE_ADDR2;
     658    /* Adjust the check a bit so that it remains warning-free but meaningful
     659       on 32-bit systems.  */
     660    else if (func_size <= (size_t) (SFRAME_FRE_TYPE_ADDR4_LIMIT - 1))
     661      fre_type = SFRAME_FRE_TYPE_ADDR4;
     662    return fre_type;
     663  }
     664  
     665  /* Get the base reg id from the FRE info.  Set errp if failure.  */
     666  
     667  uint8_t
     668  sframe_fre_get_base_reg_id (sframe_frame_row_entry *fre, int *errp)
     669  {
     670    if (fre == NULL)
     671      return sframe_set_errno (errp, SFRAME_ERR_FRE_INVAL);
     672  
     673    uint8_t fre_info = fre->fre_info;
     674    return SFRAME_V1_FRE_CFA_BASE_REG_ID (fre_info);
     675  }
     676  
     677  /* Get the CFA offset from the FRE.  If the offset is invalid, sets errp.  */
     678  
     679  int32_t
     680  sframe_fre_get_cfa_offset (sframe_decoder_ctx *dctx ATTRIBUTE_UNUSED,
     681  			   sframe_frame_row_entry *fre, int *errp)
     682  {
     683    return sframe_get_fre_offset (fre, SFRAME_FRE_CFA_OFFSET_IDX, errp);
     684  }
     685  
     686  /* Get the FP offset from the FRE.  If the offset is invalid, sets errp.  */
     687  
     688  int32_t
     689  sframe_fre_get_fp_offset (sframe_decoder_ctx *dctx,
     690  			  sframe_frame_row_entry *fre, int *errp)
     691  {
     692    uint32_t fp_offset_idx = 0;
     693    int8_t fp_offset = sframe_decoder_get_fixed_fp_offset (dctx);
     694    /* If the FP offset is not being tracked, return the fixed FP offset
     695       from the SFrame header.  */
     696    if (fp_offset != SFRAME_CFA_FIXED_FP_INVALID)
     697      {
     698        if (errp)
     699  	*errp = 0;
     700        return fp_offset;
     701      }
     702  
     703    /* In some ABIs, the stack offset to recover RA (using the CFA) from is
     704       fixed (like AMD64).  In such cases, the stack offset to recover FP will
     705       appear at the second index.  */
     706    fp_offset_idx = ((sframe_decoder_get_fixed_ra_offset (dctx)
     707  		    != SFRAME_CFA_FIXED_RA_INVALID)
     708  		   ? SFRAME_FRE_RA_OFFSET_IDX
     709  		   : SFRAME_FRE_FP_OFFSET_IDX);
     710    return sframe_get_fre_offset (fre, fp_offset_idx, errp);
     711  }
     712  
     713  /* Get the RA offset from the FRE.  If the offset is invalid, sets errp.  */
     714  
     715  int32_t
     716  sframe_fre_get_ra_offset (sframe_decoder_ctx *dctx,
     717  			  sframe_frame_row_entry *fre, int *errp)
     718  {
     719    int8_t ra_offset = sframe_decoder_get_fixed_ra_offset (dctx);
     720    /* If the RA offset was not being tracked, return the fixed RA offset
     721       from the SFrame header.  */
     722    if (ra_offset != SFRAME_CFA_FIXED_RA_INVALID)
     723      {
     724        if (errp)
     725  	*errp = 0;
     726        return ra_offset;
     727      }
     728  
     729    /* Otherwise, get the RA offset from the FRE.  */
     730    return sframe_get_fre_offset (fre, SFRAME_FRE_RA_OFFSET_IDX, errp);
     731  }
     732  
     733  /* Get whether the RA is mangled.  */
     734  
     735  bool
     736  sframe_fre_get_ra_mangled_p (sframe_decoder_ctx *dctx ATTRIBUTE_UNUSED,
     737  			     sframe_frame_row_entry *fre, int *errp)
     738  {
     739    if (fre == NULL || !sframe_fre_sanity_check_p (fre))
     740      return sframe_set_errno (errp, SFRAME_ERR_FRE_INVAL);
     741  
     742    return sframe_get_fre_ra_mangled_p (fre->fre_info);
     743  }
     744  
     745  static int
     746  sframe_frame_row_entry_copy (sframe_frame_row_entry *dst,
     747  			     sframe_frame_row_entry *src)
     748  {
     749    int err = 0;
     750  
     751    if (dst == NULL || src == NULL)
     752      return sframe_set_errno (&err, SFRAME_ERR_INVAL);
     753  
     754    memcpy (dst, src, sizeof (sframe_frame_row_entry));
     755    return 0;
     756  }
     757  
     758  /* Decode the SFrame FRE start address offset value from FRE_BUF in on-disk
     759     binary format, given the FRE_TYPE.  Updates the FRE_START_ADDR.
     760  
     761     Returns 0 on success, SFRAME_ERR otherwise.  */
     762  
     763  static int
     764  sframe_decode_fre_start_address (const char *fre_buf,
     765  				 uint32_t *fre_start_addr,
     766  				 uint32_t fre_type)
     767  {
     768    uint32_t saddr = 0;
     769    int err = 0;
     770    size_t addr_size = 0;
     771  
     772    addr_size = sframe_fre_start_addr_size (fre_type);
     773  
     774    if (fre_type == SFRAME_FRE_TYPE_ADDR1)
     775      {
     776        uint8_t *uc = (uint8_t *)fre_buf;
     777        saddr = (uint32_t)*uc;
     778      }
     779    else if (fre_type == SFRAME_FRE_TYPE_ADDR2)
     780      {
     781        uint16_t *ust = (uint16_t *)fre_buf;
     782        /* SFrame is an unaligned on-disk format.  Using memcpy helps avoid the
     783  	 use of undesirable unaligned loads.  See PR libsframe/29856.  */
     784        uint16_t tmp = 0;
     785        memcpy (&tmp, ust, addr_size);
     786        saddr = (uint32_t)tmp;
     787      }
     788    else if (fre_type == SFRAME_FRE_TYPE_ADDR4)
     789      {
     790        uint32_t *uit = (uint32_t *)fre_buf;
     791        uint32_t tmp = 0;
     792        memcpy (&tmp, uit, addr_size);
     793        saddr = (uint32_t)tmp;
     794      }
     795    else
     796      return sframe_set_errno (&err, SFRAME_ERR_INVAL);
     797  
     798    *fre_start_addr = saddr;
     799    return 0;
     800  }
     801  
     802  /* Decode a frame row entry FRE which starts at location FRE_BUF.  The function
     803     updates ESZ to the size of the FRE as stored in the binary format.
     804  
     805     This function works closely with the SFrame binary format.
     806  
     807     Returns SFRAME_ERR if failure.  */
     808  
     809  static int
     810  sframe_decode_fre (const char *fre_buf, sframe_frame_row_entry *fre,
     811  		   uint32_t fre_type, size_t *esz)
     812  {
     813    int err = 0;
     814    const char *stack_offsets = NULL;
     815    size_t stack_offsets_sz;
     816    size_t addr_size;
     817    size_t fre_size;
     818  
     819    if (fre_buf == NULL || fre == NULL || esz == NULL)
     820      return sframe_set_errno (&err, SFRAME_ERR_INVAL);
     821  
     822    /* Copy over the FRE start address.  */
     823    sframe_decode_fre_start_address (fre_buf, &fre->fre_start_addr, fre_type);
     824  
     825    addr_size = sframe_fre_start_addr_size (fre_type);
     826    fre->fre_info = *(uint8_t *)(fre_buf + addr_size);
     827    /* Sanity check as the API works closely with the binary format.  */
     828    sframe_assert (sizeof (fre->fre_info) == sizeof (uint8_t));
     829  
     830    /* Cleanup the space for fre_offsets first, then copy over the valid
     831       bytes.  */
     832    memset (fre->fre_offsets, 0, MAX_OFFSET_BYTES);
     833    /* Get offsets size.  */
     834    stack_offsets_sz = sframe_fre_offset_bytes_size (fre->fre_info);
     835    stack_offsets = fre_buf + addr_size + sizeof (fre->fre_info);
     836    memcpy (fre->fre_offsets, stack_offsets, stack_offsets_sz);
     837  
     838    /* The FRE has been decoded.  Use it to perform one last sanity check.  */
     839    fre_size = sframe_fre_entry_size (fre, fre_type);
     840    sframe_assert (fre_size == (addr_size + sizeof (fre->fre_info)
     841  			      + stack_offsets_sz));
     842    *esz = fre_size;
     843  
     844    return 0;
     845  }
     846  
     847  /* Decode the specified SFrame buffer CF_BUF of size CF_SIZE and return the
     848     new SFrame decoder context.
     849  
     850     Sets ERRP for the caller if any error.  Frees up the allocated memory in
     851     case of error.  */
     852  
     853  sframe_decoder_ctx *
     854  sframe_decode (const char *sf_buf, size_t sf_size, int *errp)
     855  {
     856    const sframe_preamble *sfp;
     857    size_t hdrsz;
     858    sframe_header *sfheaderp;
     859    sframe_decoder_ctx *dctx;
     860    char *frame_buf;
     861    char *tempbuf = NULL;
     862  
     863    int fidx_size;
     864    uint32_t fre_bytes;
     865    int foreign_endian = 0;
     866  
     867    sframe_init_debug ();
     868  
     869    if ((sf_buf == NULL) || (!sf_size))
     870      return sframe_ret_set_errno (errp, SFRAME_ERR_INVAL);
     871    else if (sf_size < sizeof (sframe_header))
     872      return sframe_ret_set_errno (errp, SFRAME_ERR_BUF_INVAL);
     873  
     874    sfp = (const sframe_preamble *) sf_buf;
     875  
     876    debug_printf ("sframe_decode: magic=0x%x version=%u flags=%u\n",
     877  		sfp->sfp_magic, sfp->sfp_version, sfp->sfp_flags);
     878  
     879    /* Check for foreign endianness.  */
     880    if (sfp->sfp_magic != SFRAME_MAGIC)
     881      {
     882        if (sfp->sfp_magic == bswap_16 (SFRAME_MAGIC))
     883  	foreign_endian = 1;
     884        else
     885  	return sframe_ret_set_errno (errp, SFRAME_ERR_BUF_INVAL);
     886      }
     887  
     888    /* Initialize a new decoder context.  */
     889    if ((dctx = malloc (sizeof (sframe_decoder_ctx))) == NULL)
     890      return sframe_ret_set_errno (errp, SFRAME_ERR_NOMEM);
     891    memset (dctx, 0, sizeof (sframe_decoder_ctx));
     892  
     893    if (foreign_endian)
     894      {
     895        /* Allocate a new buffer and initialize it.  */
     896        tempbuf = (char *) malloc (sf_size * sizeof (char));
     897        if (tempbuf == NULL)
     898  	return sframe_ret_set_errno (errp, SFRAME_ERR_NOMEM);
     899        memcpy (tempbuf, sf_buf, sf_size);
     900  
     901        /* Flip the header.  */
     902        sframe_header *ihp = (sframe_header *) tempbuf;
     903        flip_header (ihp);
     904        /* Flip the rest of the SFrame section data buffer.  */
     905        if (flip_sframe (tempbuf, sf_size, 0))
     906  	{
     907  	  free (tempbuf);
     908  	  return sframe_ret_set_errno (errp, SFRAME_ERR_BUF_INVAL);
     909  	}
     910        frame_buf = tempbuf;
     911        /* This buffer is malloc'd when endian flipping the contents of the input
     912  	 buffer are needed.  Keep a reference to it so it can be free'd up
     913  	 later in sframe_decoder_free ().  */
     914        dctx->sfd_buf = tempbuf;
     915      }
     916    else
     917      frame_buf = (char *)sf_buf;
     918  
     919    /* Handle the SFrame header.  */
     920    dctx->sfd_header = *(sframe_header *) frame_buf;
     921    /* Validate the contents of SFrame header.  */
     922    sfheaderp = &dctx->sfd_header;
     923    if (!sframe_header_sanity_check_p (sfheaderp))
     924      {
     925        sframe_ret_set_errno (errp, SFRAME_ERR_NOMEM);
     926        goto decode_fail_free;
     927      }
     928    hdrsz = sframe_get_hdr_size (sfheaderp);
     929    frame_buf += hdrsz;
     930  
     931    /* Handle the SFrame Function Descriptor Entry section.  */
     932    fidx_size
     933      = sfheaderp->sfh_num_fdes * sizeof (sframe_func_desc_entry);
     934    dctx->sfd_funcdesc = malloc (fidx_size);
     935    if (dctx->sfd_funcdesc == NULL)
     936      {
     937        sframe_ret_set_errno (errp, SFRAME_ERR_NOMEM);
     938        goto decode_fail_free;
     939      }
     940    memcpy (dctx->sfd_funcdesc, frame_buf, fidx_size);
     941  
     942    debug_printf ("%u total fidx size\n", fidx_size);
     943  
     944    frame_buf += (fidx_size);
     945  
     946    /* Handle the SFrame Frame Row Entry section.  */
     947    dctx->sfd_fres = (char *) malloc (sfheaderp->sfh_fre_len);
     948    if (dctx->sfd_fres == NULL)
     949      {
     950        sframe_ret_set_errno (errp, SFRAME_ERR_NOMEM);
     951        goto decode_fail_free;
     952      }
     953    memcpy (dctx->sfd_fres, frame_buf, sfheaderp->sfh_fre_len);
     954  
     955    fre_bytes = sfheaderp->sfh_fre_len;
     956    dctx->sfd_fre_nbytes = fre_bytes;
     957  
     958    debug_printf ("%u total fre bytes\n", fre_bytes);
     959  
     960    return dctx;
     961  
     962  decode_fail_free:
     963    if (foreign_endian && tempbuf != NULL)
     964      free (tempbuf);
     965    sframe_decoder_free (&dctx);
     966    dctx = NULL;
     967    return dctx;
     968  }
     969  
     970  /* Get the size of the SFrame header from the decoder context CTX.  */
     971  
     972  unsigned int
     973  sframe_decoder_get_hdr_size (sframe_decoder_ctx *ctx)
     974  {
     975    sframe_header *dhp;
     976    dhp = sframe_decoder_get_header (ctx);
     977    return sframe_get_hdr_size (dhp);
     978  }
     979  
     980  /* Get the SFrame's abi/arch info given the decoder context DCTX.  */
     981  
     982  uint8_t
     983  sframe_decoder_get_abi_arch (sframe_decoder_ctx *dctx)
     984  {
     985    sframe_header *sframe_header;
     986    sframe_header = sframe_decoder_get_header (dctx);
     987    return sframe_header->sfh_abi_arch;
     988  }
     989  
     990  /* Get the format version from the SFrame decoder context DCTX.  */
     991  
     992  uint8_t
     993  sframe_decoder_get_version (sframe_decoder_ctx *dctx)
     994  {
     995    sframe_header *dhp;
     996    dhp = sframe_decoder_get_header (dctx);
     997    return dhp->sfh_preamble.sfp_version;
     998  }
     999  
    1000  /* Get the SFrame's fixed FP offset given the decoder context CTX.  */
    1001  int8_t
    1002  sframe_decoder_get_fixed_fp_offset (sframe_decoder_ctx *ctx)
    1003  {
    1004    sframe_header *dhp;
    1005    dhp = sframe_decoder_get_header (ctx);
    1006    return dhp->sfh_cfa_fixed_fp_offset;
    1007  }
    1008  
    1009  /* Get the SFrame's fixed RA offset given the decoder context CTX.  */
    1010  int8_t
    1011  sframe_decoder_get_fixed_ra_offset (sframe_decoder_ctx *ctx)
    1012  {
    1013    sframe_header *dhp;
    1014    dhp = sframe_decoder_get_header (ctx);
    1015    return dhp->sfh_cfa_fixed_ra_offset;
    1016  }
    1017  
    1018  /* Find the function descriptor entry which contains the specified address
    1019     ADDR.
    1020     This function is deprecated and will be removed from libsframe.so.2.  */
    1021  
    1022  void *
    1023  sframe_get_funcdesc_with_addr (sframe_decoder_ctx *ctx __attribute__ ((unused)),
    1024  			       int32_t addr __attribute__ ((unused)),
    1025  			       int *errp)
    1026  {
    1027    return sframe_ret_set_errno (errp, SFRAME_ERR_INVAL);
    1028  }
    1029  
    1030  /* Find the function descriptor entry starting which contains the specified
    1031     address ADDR.  */
    1032  
    1033  static sframe_func_desc_entry *
    1034  sframe_get_funcdesc_with_addr_internal (sframe_decoder_ctx *ctx, int32_t addr,
    1035  					int *errp)
    1036  {
    1037    sframe_header *dhp;
    1038    sframe_func_desc_entry *fdp;
    1039    int low, high, cnt;
    1040  
    1041    if (ctx == NULL)
    1042      return sframe_ret_set_errno (errp, SFRAME_ERR_INVAL);
    1043  
    1044    dhp = sframe_decoder_get_header (ctx);
    1045  
    1046    if (dhp == NULL || dhp->sfh_num_fdes == 0 || ctx->sfd_funcdesc == NULL)
    1047      return sframe_ret_set_errno (errp, SFRAME_ERR_DCTX_INVAL);
    1048    /* If the FDE sub-section is not sorted on PCs, skip the lookup because
    1049       binary search cannot be used.  */
    1050    if ((dhp->sfh_preamble.sfp_flags & SFRAME_F_FDE_SORTED) == 0)
    1051      return sframe_ret_set_errno (errp, SFRAME_ERR_FDE_NOTSORTED);
    1052  
    1053    /* Do the binary search.  */
    1054    fdp = (sframe_func_desc_entry *) ctx->sfd_funcdesc;
    1055    low = 0;
    1056    high = dhp->sfh_num_fdes;
    1057    cnt = high;
    1058    while (low <= high)
    1059      {
    1060        int mid = low + (high - low) / 2;
    1061  
    1062        if (fdp[mid].sfde_func_start_address == addr)
    1063  	return fdp + mid;
    1064  
    1065        if (fdp[mid].sfde_func_start_address < addr)
    1066  	{
    1067  	  if (mid == (cnt - 1)) 	/* Check if it's the last one.  */
    1068  	    return fdp + (cnt - 1);
    1069  	  else if (fdp[mid+1].sfde_func_start_address > addr)
    1070  	    return fdp + mid;
    1071  	  low = mid + 1;
    1072  	}
    1073        else
    1074  	high = mid - 1;
    1075      }
    1076  
    1077    return sframe_ret_set_errno (errp, SFRAME_ERR_FDE_NOTFOUND);
    1078  }
    1079  
    1080  /* Get the end IP offset for the FRE at index i in the FDEP.  The buffer FRES
    1081     is the starting location for the FRE.  */
    1082  
    1083  static uint32_t
    1084  sframe_fre_get_end_ip_offset (sframe_func_desc_entry *fdep, unsigned int i,
    1085  			      const char *fres)
    1086  {
    1087    uint32_t end_ip_offset;
    1088    uint32_t fre_type;
    1089  
    1090    fre_type = sframe_get_fre_type (fdep);
    1091  
    1092    /* Get the start address of the next FRE in sequence.  */
    1093    if (i < fdep->sfde_func_num_fres - 1)
    1094      {
    1095        sframe_decode_fre_start_address (fres, &end_ip_offset, fre_type);
    1096        end_ip_offset -= 1;
    1097      }
    1098    else
    1099      /* The end IP offset for the FRE needs to be deduced from the function
    1100         size.  */
    1101      end_ip_offset = fdep->sfde_func_size - 1;
    1102  
    1103    return end_ip_offset;
    1104  }
    1105  
    1106  /* Find the SFrame Row Entry which contains the PC.  Returns
    1107     SFRAME_ERR if failure.  */
    1108  
    1109  int
    1110  sframe_find_fre (sframe_decoder_ctx *ctx, int32_t pc,
    1111  		 sframe_frame_row_entry *frep)
    1112  {
    1113    sframe_frame_row_entry cur_fre;
    1114    sframe_func_desc_entry *fdep;
    1115    uint32_t fre_type, fde_type, i;
    1116    int32_t start_ip_offset;
    1117    int32_t func_start_addr;
    1118    int32_t end_ip_offset;
    1119    const char *fres;
    1120    size_t size = 0;
    1121    int err = 0;
    1122    bool mask_p;
    1123  
    1124    if ((ctx == NULL) || (frep == NULL))
    1125      return sframe_set_errno (&err, SFRAME_ERR_INVAL);
    1126  
    1127    /* Find the FDE which contains the PC, then scan its fre entries.  */
    1128    fdep = sframe_get_funcdesc_with_addr_internal (ctx, pc, &err);
    1129    if (fdep == NULL || ctx->sfd_fres == NULL)
    1130      return sframe_set_errno (&err, SFRAME_ERR_DCTX_INVAL);
    1131  
    1132    fre_type = sframe_get_fre_type (fdep);
    1133    fde_type = sframe_get_fde_type (fdep);
    1134    mask_p = (fde_type == SFRAME_FDE_TYPE_PCMASK);
    1135  
    1136    fres = ctx->sfd_fres + fdep->sfde_func_start_fre_off;
    1137    func_start_addr = fdep->sfde_func_start_address;
    1138  
    1139    for (i = 0; i < fdep->sfde_func_num_fres; i++)
    1140     {
    1141       err = sframe_decode_fre (fres, &cur_fre, fre_type, &size);
    1142       if (err)
    1143         return sframe_set_errno (&err, SFRAME_ERR_FRE_INVAL);
    1144  
    1145       start_ip_offset = cur_fre.fre_start_addr;
    1146       end_ip_offset = sframe_fre_get_end_ip_offset (fdep, i, fres + size);
    1147  
    1148       /* First FRE's start_ip must be more than pc for regular SFrame FDEs.  */
    1149       if (i == 0 && !mask_p && (start_ip_offset + func_start_addr) > pc)
    1150         return sframe_set_errno (&err, SFRAME_ERR_FRE_INVAL);
    1151  
    1152       if (sframe_fre_check_range_p (fdep, start_ip_offset, end_ip_offset, pc))
    1153         {
    1154  	 sframe_frame_row_entry_copy (frep, &cur_fre);
    1155  	 return 0;
    1156         }
    1157       fres += size;
    1158     }
    1159    return sframe_set_errno (&err, SFRAME_ERR_FDE_INVAL);
    1160  }
    1161  
    1162  /* Return the number of function descriptor entries in the SFrame decoder
    1163     DCTX.  */
    1164  
    1165  uint32_t
    1166  sframe_decoder_get_num_fidx (sframe_decoder_ctx *ctx)
    1167  {
    1168    uint32_t num_fdes = 0;
    1169    sframe_header *dhp = NULL;
    1170    dhp = sframe_decoder_get_header (ctx);
    1171    if (dhp)
    1172      num_fdes = dhp->sfh_num_fdes;
    1173    return num_fdes;
    1174  }
    1175  
    1176  /* Get the data (NUM_FRES, FUNC_START_ADDRESS) from the function
    1177     descriptor entry at index I'th in the decoder CTX.  If failed,
    1178     return error code.  */
    1179  /* FIXME - consolidate the args and return a
    1180     sframe_func_desc_index_elem rather?  */
    1181  
    1182  int
    1183  sframe_decoder_get_funcdesc (sframe_decoder_ctx *ctx,
    1184  			     unsigned int i,
    1185  			     uint32_t *num_fres,
    1186  			     uint32_t *func_size,
    1187  			     int32_t *func_start_address,
    1188  			     unsigned char *func_info)
    1189  {
    1190    sframe_func_desc_entry *fdp;
    1191    int err = 0;
    1192  
    1193    if (ctx == NULL || func_start_address == NULL || num_fres == NULL
    1194        || func_size == NULL)
    1195      return sframe_set_errno (&err, SFRAME_ERR_INVAL);
    1196  
    1197    fdp = sframe_decoder_get_funcdesc_at_index (ctx, i);
    1198  
    1199    if (fdp == NULL)
    1200      return sframe_set_errno (&err, SFRAME_ERR_FDE_NOTFOUND);
    1201  
    1202    *num_fres = fdp->sfde_func_num_fres;
    1203    *func_start_address = fdp->sfde_func_start_address;
    1204    *func_size = fdp->sfde_func_size;
    1205    *func_info = fdp->sfde_func_info;
    1206  
    1207    return 0;
    1208  }
    1209  
    1210  int
    1211  sframe_decoder_get_funcdesc_v2 (sframe_decoder_ctx *dctx,
    1212  				unsigned int i,
    1213  				uint32_t *num_fres,
    1214  				uint32_t *func_size,
    1215  				int32_t *func_start_address,
    1216  				unsigned char *func_info,
    1217  				uint8_t *rep_block_size)
    1218  {
    1219    sframe_func_desc_entry *fdp;
    1220    int err = 0;
    1221  
    1222    if (dctx == NULL || func_start_address == NULL
    1223        || num_fres == NULL || func_size == NULL
    1224        || sframe_decoder_get_version (dctx) == SFRAME_VERSION_1)
    1225      return sframe_set_errno (&err, SFRAME_ERR_INVAL);
    1226  
    1227    fdp = sframe_decoder_get_funcdesc_at_index (dctx, i);
    1228  
    1229    if (fdp == NULL)
    1230      return sframe_set_errno (&err, SFRAME_ERR_FDE_NOTFOUND);
    1231  
    1232    *num_fres = fdp->sfde_func_num_fres;
    1233    *func_start_address = fdp->sfde_func_start_address;
    1234    *func_size = fdp->sfde_func_size;
    1235    *func_info = fdp->sfde_func_info;
    1236    *rep_block_size = fdp->sfde_func_rep_size;
    1237  
    1238    return 0;
    1239  }
    1240  /* Get the FRE_IDX'th FRE of the function at FUNC_IDX'th function
    1241     descriptor entry in the SFrame decoder CTX.  Returns error code as
    1242     applicable.  */
    1243  
    1244  int
    1245  sframe_decoder_get_fre (sframe_decoder_ctx *ctx,
    1246  			unsigned int func_idx,
    1247  			unsigned int fre_idx,
    1248  			sframe_frame_row_entry *fre)
    1249  {
    1250    sframe_func_desc_entry *fdep;
    1251    sframe_frame_row_entry ifre;
    1252    const char *fres;
    1253    uint32_t i;
    1254    uint32_t fre_type;
    1255    size_t esz = 0;
    1256    int err = 0;
    1257  
    1258    if (ctx == NULL || fre == NULL)
    1259      return sframe_set_errno (&err, SFRAME_ERR_INVAL);
    1260  
    1261    /* Get function descriptor entry at index func_idx.  */
    1262    fdep = sframe_decoder_get_funcdesc_at_index (ctx, func_idx);
    1263  
    1264    if (fdep == NULL)
    1265      return sframe_set_errno (&err, SFRAME_ERR_FDE_NOTFOUND);
    1266  
    1267    fre_type = sframe_get_fre_type (fdep);
    1268    /* Now scan the FRE entries.  */
    1269    fres = ctx->sfd_fres + fdep->sfde_func_start_fre_off;
    1270    for (i = 0; i < fdep->sfde_func_num_fres; i++)
    1271     {
    1272       /* Decode the FRE at the current position.  Return it if valid.  */
    1273       err = sframe_decode_fre (fres, &ifre, fre_type, &esz);
    1274       if (i == fre_idx)
    1275         {
    1276  	 if (!sframe_fre_sanity_check_p (&ifre))
    1277  	   return sframe_set_errno (&err, SFRAME_ERR_FRE_INVAL);
    1278  
    1279  	 sframe_frame_row_entry_copy (fre, &ifre);
    1280  
    1281  	 if (fdep->sfde_func_size)
    1282  	   sframe_assert (fre->fre_start_addr < fdep->sfde_func_size);
    1283  	 else
    1284  	   /* A SFrame FDE with func size equal to zero is possible.  */
    1285  	   sframe_assert (fre->fre_start_addr == fdep->sfde_func_size);
    1286  
    1287  	 return 0;
    1288         }
    1289       /* Next FRE.  */
    1290       fres += esz;
    1291     }
    1292  
    1293    return sframe_set_errno (&err, SFRAME_ERR_FDE_NOTFOUND);
    1294  }
    1295  
    1296  
    1297  /* SFrame Encoder.  */
    1298  
    1299  /* Get a reference to the ENCODER's SFrame header.  */
    1300  
    1301  static sframe_header *
    1302  sframe_encoder_get_header (sframe_encoder_ctx *encoder)
    1303  {
    1304    sframe_header *hp = NULL;
    1305    if (encoder)
    1306      hp = &encoder->sfe_header;
    1307    return hp;
    1308  }
    1309  
    1310  static sframe_func_desc_entry *
    1311  sframe_encoder_get_funcdesc_at_index (sframe_encoder_ctx *encoder,
    1312  				      uint32_t func_idx)
    1313  {
    1314    sframe_func_desc_entry *fde = NULL;
    1315    if (func_idx < sframe_encoder_get_num_fidx (encoder))
    1316      {
    1317        sf_fde_tbl *func_tbl = encoder->sfe_funcdesc;
    1318        fde = func_tbl->entry + func_idx;
    1319      }
    1320    return fde;
    1321  }
    1322  
    1323  /* Create an encoder context with the given SFrame format version VER, FLAGS
    1324     and ABI information.  Uses the ABI specific FIXED_FP_OFFSET and
    1325     FIXED_RA_OFFSET values as provided.  Sets errp if failure.  */
    1326  
    1327  sframe_encoder_ctx *
    1328  sframe_encode (uint8_t ver, uint8_t flags, uint8_t abi_arch,
    1329  	       int8_t fixed_fp_offset, int8_t fixed_ra_offset, int *errp)
    1330  {
    1331    sframe_header *hp;
    1332    sframe_encoder_ctx *encoder;
    1333  
    1334    if (ver != SFRAME_VERSION)
    1335      return sframe_ret_set_errno (errp, SFRAME_ERR_VERSION_INVAL);
    1336  
    1337    if ((encoder = malloc (sizeof (sframe_encoder_ctx))) == NULL)
    1338      return sframe_ret_set_errno (errp, SFRAME_ERR_NOMEM);
    1339  
    1340    memset (encoder, 0, sizeof (sframe_encoder_ctx));
    1341  
    1342    /* Get the SFrame header and update it.  */
    1343    hp = sframe_encoder_get_header (encoder);
    1344    hp->sfh_preamble.sfp_version = ver;
    1345    hp->sfh_preamble.sfp_magic = SFRAME_MAGIC;
    1346    hp->sfh_preamble.sfp_flags = flags;
    1347  
    1348    hp->sfh_abi_arch = abi_arch;
    1349    hp->sfh_cfa_fixed_fp_offset = fixed_fp_offset;
    1350    hp->sfh_cfa_fixed_ra_offset = fixed_ra_offset;
    1351  
    1352    return encoder;
    1353  }
    1354  
    1355  /* Free the encoder context.  */
    1356  
    1357  void
    1358  sframe_encoder_free (sframe_encoder_ctx **encoder)
    1359  {
    1360    if (encoder != NULL)
    1361      {
    1362        sframe_encoder_ctx *ectx = *encoder;
    1363        if (ectx == NULL)
    1364  	return;
    1365  
    1366        if (ectx->sfe_funcdesc != NULL)
    1367  	{
    1368  	  free (ectx->sfe_funcdesc);
    1369  	  ectx->sfe_funcdesc = NULL;
    1370  	}
    1371        if (ectx->sfe_fres != NULL)
    1372  	{
    1373  	  free (ectx->sfe_fres);
    1374  	  ectx->sfe_fres = NULL;
    1375  	}
    1376        if (ectx->sfe_data != NULL)
    1377  	{
    1378  	  free (ectx->sfe_data);
    1379  	  ectx->sfe_data = NULL;
    1380  	}
    1381  
    1382        free (*encoder);
    1383        *encoder = NULL;
    1384      }
    1385  }
    1386  
    1387  /* Get the size of the SFrame header from the encoder ctx ENCODER.  */
    1388  
    1389  unsigned int
    1390  sframe_encoder_get_hdr_size (sframe_encoder_ctx *encoder)
    1391  {
    1392    sframe_header *ehp;
    1393    ehp = sframe_encoder_get_header (encoder);
    1394    return sframe_get_hdr_size (ehp);
    1395  }
    1396  
    1397  /* Get the abi/arch info from the SFrame encoder context ENCODER.  */
    1398  
    1399  uint8_t
    1400  sframe_encoder_get_abi_arch (sframe_encoder_ctx *encoder)
    1401  {
    1402    uint8_t abi_arch = 0;
    1403    sframe_header *ehp;
    1404    ehp = sframe_encoder_get_header (encoder);
    1405    if (ehp)
    1406      abi_arch = ehp->sfh_abi_arch;
    1407    return abi_arch;
    1408  }
    1409  
    1410  /* Get the format version from the SFrame encoder context ENCODER.  */
    1411  
    1412  uint8_t
    1413  sframe_encoder_get_version (sframe_encoder_ctx *encoder)
    1414  {
    1415    sframe_header *ehp;
    1416    ehp = sframe_encoder_get_header (encoder);
    1417    return ehp->sfh_preamble.sfp_version;
    1418  }
    1419  
    1420  /* Return the number of function descriptor entries in the SFrame encoder
    1421     ENCODER.  */
    1422  
    1423  uint32_t
    1424  sframe_encoder_get_num_fidx (sframe_encoder_ctx *encoder)
    1425  {
    1426    uint32_t num_fdes = 0;
    1427    sframe_header *ehp = NULL;
    1428    ehp = sframe_encoder_get_header (encoder);
    1429    if (ehp)
    1430      num_fdes = ehp->sfh_num_fdes;
    1431    return num_fdes;
    1432  }
    1433  
    1434  /* Add an FRE to function at FUNC_IDX'th function descriptor entry in
    1435     the encoder context.  */
    1436  
    1437  int
    1438  sframe_encoder_add_fre (sframe_encoder_ctx *encoder,
    1439  			unsigned int func_idx,
    1440  			sframe_frame_row_entry *frep)
    1441  {
    1442    sframe_header *ehp;
    1443    sframe_func_desc_entry *fdep;
    1444    sframe_frame_row_entry *ectx_frep;
    1445    size_t offsets_sz, esz;
    1446    uint32_t fre_type;
    1447    size_t fre_tbl_sz;
    1448    int err = 0;
    1449  
    1450    if (encoder == NULL || frep == NULL)
    1451      return sframe_set_errno (&err, SFRAME_ERR_INVAL);
    1452    if (!sframe_fre_sanity_check_p (frep))
    1453      return sframe_set_errno (&err, SFRAME_ERR_FRE_INVAL);
    1454  
    1455    /* Use func_idx to gather the function descriptor entry.  */
    1456    fdep = sframe_encoder_get_funcdesc_at_index (encoder, func_idx);
    1457  
    1458    if (fdep == NULL)
    1459      return sframe_set_errno (&err, SFRAME_ERR_FDE_NOTFOUND);
    1460  
    1461    fre_type = sframe_get_fre_type (fdep);
    1462    sf_fre_tbl *fre_tbl = encoder->sfe_fres;
    1463  
    1464    if (fre_tbl == NULL)
    1465      {
    1466        fre_tbl_sz = (sizeof (sf_fre_tbl)
    1467  		    + (number_of_entries * sizeof (sframe_frame_row_entry)));
    1468        fre_tbl = malloc (fre_tbl_sz);
    1469  
    1470        if (fre_tbl == NULL)
    1471  	{
    1472  	  sframe_set_errno (&err, SFRAME_ERR_NOMEM);
    1473  	  goto bad;		/* OOM.  */
    1474  	}
    1475        memset (fre_tbl, 0, fre_tbl_sz);
    1476        fre_tbl->alloced = number_of_entries;
    1477      }
    1478    else if (fre_tbl->count == fre_tbl->alloced)
    1479      {
    1480        fre_tbl_sz = (sizeof (sf_fre_tbl)
    1481  		    + ((fre_tbl->alloced + number_of_entries)
    1482  		       * sizeof (sframe_frame_row_entry)));
    1483        fre_tbl = realloc (fre_tbl, fre_tbl_sz);
    1484        if (fre_tbl == NULL)
    1485  	{
    1486  	  sframe_set_errno (&err, SFRAME_ERR_NOMEM);
    1487  	  goto bad;		/* OOM.  */
    1488  	}
    1489  
    1490        memset (&fre_tbl->entry[fre_tbl->alloced], 0,
    1491  	      number_of_entries * sizeof (sframe_frame_row_entry));
    1492        fre_tbl->alloced += number_of_entries;
    1493      }
    1494  
    1495    ectx_frep = &fre_tbl->entry[fre_tbl->count];
    1496    ectx_frep->fre_start_addr
    1497      = frep->fre_start_addr;
    1498    ectx_frep->fre_info = frep->fre_info;
    1499  
    1500    if (fdep->sfde_func_size)
    1501      sframe_assert (frep->fre_start_addr < fdep->sfde_func_size);
    1502    else
    1503      /* A SFrame FDE with func size equal to zero is possible.  */
    1504      sframe_assert (frep->fre_start_addr == fdep->sfde_func_size);
    1505  
    1506    /* frep has already been sanity check'd.  Get offsets size.  */
    1507    offsets_sz = sframe_fre_offset_bytes_size (frep->fre_info);
    1508    memcpy (&ectx_frep->fre_offsets, &frep->fre_offsets, offsets_sz);
    1509  
    1510    esz = sframe_fre_entry_size (frep, fre_type);
    1511    fre_tbl->count++;
    1512  
    1513    encoder->sfe_fres = fre_tbl;
    1514    encoder->sfe_fre_nbytes += esz;
    1515  
    1516    ehp = sframe_encoder_get_header (encoder);
    1517    ehp->sfh_num_fres = fre_tbl->count;
    1518  
    1519    /* Update the value of the number of FREs for the function.  */
    1520    fdep->sfde_func_num_fres++;
    1521  
    1522    return 0;
    1523  
    1524  bad:
    1525    if (fre_tbl != NULL)
    1526      free (fre_tbl);
    1527    encoder->sfe_fres = NULL;
    1528    encoder->sfe_fre_nbytes = 0;
    1529    return -1;
    1530  }
    1531  
    1532  /* Add a new function descriptor entry with START_ADDR, FUNC_SIZE and NUM_FRES
    1533     to the encoder.  */
    1534  
    1535  int
    1536  sframe_encoder_add_funcdesc (sframe_encoder_ctx *encoder,
    1537  			     int32_t start_addr,
    1538  			     uint32_t func_size,
    1539  			     unsigned char func_info,
    1540  			     uint32_t num_fres __attribute__ ((unused)))
    1541  {
    1542    sframe_header *ehp;
    1543    sf_fde_tbl *fd_info;
    1544    size_t fd_tbl_sz;
    1545    int err = 0;
    1546  
    1547    /* FIXME book-keep num_fres for error checking.  */
    1548    if (encoder == NULL)
    1549      return sframe_set_errno (&err, SFRAME_ERR_INVAL);
    1550  
    1551    fd_info = encoder->sfe_funcdesc;
    1552    ehp = sframe_encoder_get_header (encoder);
    1553  
    1554    if (fd_info == NULL)
    1555      {
    1556        fd_tbl_sz = (sizeof (sf_fde_tbl)
    1557  		   + (number_of_entries * sizeof (sframe_func_desc_entry)));
    1558        fd_info = malloc (fd_tbl_sz);
    1559        if (fd_info == NULL)
    1560  	{
    1561  	  sframe_set_errno (&err, SFRAME_ERR_NOMEM);
    1562  	  goto bad;		/* OOM.  */
    1563  	}
    1564        memset (fd_info, 0, fd_tbl_sz);
    1565        fd_info->alloced = number_of_entries;
    1566      }
    1567    else if (fd_info->count == fd_info->alloced)
    1568      {
    1569        fd_tbl_sz = (sizeof (sf_fde_tbl)
    1570  		   + ((fd_info->alloced + number_of_entries)
    1571  		      * sizeof (sframe_func_desc_entry)));
    1572        fd_info = realloc (fd_info, fd_tbl_sz);
    1573        if (fd_info == NULL)
    1574  	{
    1575  	  sframe_set_errno (&err, SFRAME_ERR_NOMEM);
    1576  	  goto bad;		/* OOM.  */
    1577  	}
    1578  
    1579        memset (&fd_info->entry[fd_info->alloced], 0,
    1580  	      number_of_entries * sizeof (sframe_func_desc_entry));
    1581        fd_info->alloced += number_of_entries;
    1582      }
    1583  
    1584    fd_info->entry[fd_info->count].sfde_func_start_address = start_addr;
    1585    /* Num FREs is updated as FREs are added for the function later via
    1586       sframe_encoder_add_fre.  */
    1587    fd_info->entry[fd_info->count].sfde_func_size = func_size;
    1588    fd_info->entry[fd_info->count].sfde_func_start_fre_off
    1589      = encoder->sfe_fre_nbytes;
    1590  #if 0
    1591    // Linker optimization test code cleanup later ibhagat TODO FIXME
    1592    uint32_t fre_type = sframe_calc_fre_type (func_size);
    1593  
    1594    fd_info->entry[fd_info->count].sfde_func_info
    1595      = sframe_fde_func_info (fre_type);
    1596  #endif
    1597    fd_info->entry[fd_info->count].sfde_func_info = func_info;
    1598    fd_info->count++;
    1599    encoder->sfe_funcdesc = fd_info;
    1600    ehp->sfh_num_fdes++;
    1601    return 0;
    1602  
    1603  bad:
    1604    if (fd_info != NULL)
    1605      free (fd_info);
    1606    encoder->sfe_funcdesc = NULL;
    1607    ehp->sfh_num_fdes = 0;
    1608    return -1;
    1609  }
    1610  
    1611  /* Add a new function descriptor entry with START_ADDR, FUNC_SIZE, FUNC_INFO
    1612     and REP_BLOCK_SIZE to the encoder.
    1613  
    1614     This API is valid only for SFrame format version 2.  */
    1615  
    1616  int
    1617  sframe_encoder_add_funcdesc_v2 (sframe_encoder_ctx *encoder,
    1618  				int32_t start_addr,
    1619  				uint32_t func_size,
    1620  				unsigned char func_info,
    1621  				uint8_t rep_block_size,
    1622  				uint32_t num_fres __attribute__ ((unused)))
    1623  {
    1624    sf_fde_tbl *fd_info;
    1625    int err;
    1626  
    1627    if (encoder == NULL
    1628        || sframe_encoder_get_version (encoder) == SFRAME_VERSION_1)
    1629      return sframe_set_errno (&err, SFRAME_ERR_INVAL);
    1630  
    1631    err = sframe_encoder_add_funcdesc (encoder, start_addr, func_size, func_info,
    1632  				     num_fres);
    1633    if (err)
    1634      return SFRAME_ERR;
    1635  
    1636    fd_info = encoder->sfe_funcdesc;
    1637    fd_info->entry[fd_info->count-1].sfde_func_rep_size = rep_block_size;
    1638  
    1639    return 0;
    1640  }
    1641  
    1642  static int
    1643  sframe_sort_funcdesc (sframe_encoder_ctx *encoder)
    1644  {
    1645    sframe_header *ehp;
    1646  
    1647    ehp = sframe_encoder_get_header (encoder);
    1648    /* Sort and write out the FDE table.  */
    1649    sf_fde_tbl *fd_info = encoder->sfe_funcdesc;
    1650    if (fd_info)
    1651      {
    1652        qsort (fd_info->entry, fd_info->count,
    1653  	     sizeof (sframe_func_desc_entry), fde_func);
    1654        /* Update preamble's flags.  */
    1655        ehp->sfh_preamble.sfp_flags |= SFRAME_F_FDE_SORTED;
    1656      }
    1657    return 0;
    1658  }
    1659  
    1660  /* Write the SFrame FRE start address from the in-memory FRE_START_ADDR
    1661     to the buffer CONTENTS (on-disk format), given the FRE_TYPE and
    1662     FRE_START_ADDR_SZ.  */
    1663  
    1664  static int
    1665  sframe_encoder_write_fre_start_addr (char *contents,
    1666  				     uint32_t fre_start_addr,
    1667  				     uint32_t fre_type,
    1668  				     size_t fre_start_addr_sz)
    1669  {
    1670    int err = 0;
    1671  
    1672    if (fre_type == SFRAME_FRE_TYPE_ADDR1)
    1673      {
    1674        uint8_t uc = fre_start_addr;
    1675        memcpy (contents, &uc, fre_start_addr_sz);
    1676      }
    1677    else if (fre_type == SFRAME_FRE_TYPE_ADDR2)
    1678      {
    1679        uint16_t ust = fre_start_addr;
    1680        memcpy (contents, &ust, fre_start_addr_sz);
    1681      }
    1682    else if (fre_type == SFRAME_FRE_TYPE_ADDR4)
    1683      {
    1684        uint32_t uit = fre_start_addr;
    1685        memcpy (contents, &uit, fre_start_addr_sz);
    1686      }
    1687    else
    1688      return sframe_set_errno (&err, SFRAME_ERR_INVAL);
    1689  
    1690    return 0;
    1691  }
    1692  
    1693  /* Write a frame row entry pointed to by FREP into the buffer CONTENTS.  The
    1694     size in bytes written out are updated in ESZ.
    1695  
    1696     This function works closely with the SFrame binary format.
    1697  
    1698     Returns SFRAME_ERR if failure.  */
    1699  
    1700  static int
    1701  sframe_encoder_write_fre (char *contents, sframe_frame_row_entry *frep,
    1702  			  uint32_t fre_type, size_t *esz)
    1703  {
    1704    size_t fre_sz;
    1705    size_t fre_start_addr_sz;
    1706    size_t fre_stack_offsets_sz;
    1707    int err = 0;
    1708  
    1709    if (!sframe_fre_sanity_check_p (frep))
    1710      return sframe_set_errno (&err, SFRAME_ERR_FRE_INVAL);
    1711  
    1712    fre_start_addr_sz = sframe_fre_start_addr_size (fre_type);
    1713    fre_stack_offsets_sz = sframe_fre_offset_bytes_size (frep->fre_info);
    1714  
    1715    /* The FRE start address must be encodable in the available number of
    1716       bytes.  */
    1717    uint64_t bitmask = SFRAME_BITMASK_OF_SIZE (fre_start_addr_sz);
    1718    sframe_assert ((uint64_t)frep->fre_start_addr <= bitmask);
    1719  
    1720    sframe_encoder_write_fre_start_addr (contents, frep->fre_start_addr,
    1721  				       fre_type, fre_start_addr_sz);
    1722    contents += fre_start_addr_sz;
    1723  
    1724    memcpy (contents, &frep->fre_info, sizeof (frep->fre_info));
    1725    contents += sizeof (frep->fre_info);
    1726  
    1727    memcpy (contents, frep->fre_offsets, fre_stack_offsets_sz);
    1728    contents+= fre_stack_offsets_sz;
    1729  
    1730    fre_sz = sframe_fre_entry_size (frep, fre_type);
    1731    /* Sanity checking.  */
    1732    sframe_assert ((fre_start_addr_sz
    1733  		  + sizeof (frep->fre_info)
    1734  		  + fre_stack_offsets_sz) == fre_sz);
    1735  
    1736    *esz = fre_sz;
    1737  
    1738    return 0;
    1739  }
    1740  
    1741  /* Serialize the core contents of the SFrame section and write out to the
    1742     output buffer held in the ENCODER.  Return SFRAME_ERR if failure.  */
    1743  
    1744  static int
    1745  sframe_encoder_write_sframe (sframe_encoder_ctx *encoder)
    1746  {
    1747    char *contents;
    1748    size_t buf_size;
    1749    size_t hdr_size;
    1750    size_t all_fdes_size;
    1751    size_t fre_size;
    1752    size_t esz = 0;
    1753    sframe_header *ehp;
    1754    unsigned char flags;
    1755    sf_fde_tbl *fd_info;
    1756    sf_fre_tbl *fr_info;
    1757    uint32_t i, num_fdes;
    1758    uint32_t j, num_fres;
    1759    sframe_func_desc_entry *fdep;
    1760    sframe_frame_row_entry *frep;
    1761  
    1762    uint32_t fre_type;
    1763    int err = 0;
    1764  
    1765    contents = encoder->sfe_data;
    1766    buf_size = encoder->sfe_data_size;
    1767    num_fdes = sframe_encoder_get_num_fidx (encoder);
    1768    all_fdes_size = num_fdes * sizeof (sframe_func_desc_entry);
    1769    ehp = sframe_encoder_get_header (encoder);
    1770    hdr_size = sframe_get_hdr_size (ehp);
    1771  
    1772    fd_info = encoder->sfe_funcdesc;
    1773    fr_info = encoder->sfe_fres;
    1774  
    1775    /* Sanity checks:
    1776       - buffers must be malloc'd by the caller.  */
    1777    if ((contents == NULL) || (buf_size < hdr_size))
    1778      return sframe_set_errno (&err, SFRAME_ERR_BUF_INVAL);
    1779    if (fr_info == NULL)
    1780      return sframe_set_errno (&err, SFRAME_ERR_FRE_INVAL);
    1781  
    1782    /* Write out the FRE table first.
    1783  
    1784       Recall that read/write of FREs needs information from the corresponding
    1785       FDE; the latter stores the information about the FRE type record used for
    1786       the function.  Also note that sorting of FDEs does NOT impact the order
    1787       in which FREs are stored in the SFrame's FRE sub-section.  This means
    1788       that writing out FREs after sorting of FDEs will need some additional
    1789       book-keeping.  At this time, we can afford to avoid it by writing out
    1790       the FREs first to the output buffer.  */
    1791    fre_size = 0;
    1792    uint32_t global = 0;
    1793    uint32_t fre_index = 0;
    1794  
    1795    contents += hdr_size + all_fdes_size;
    1796    for (i = 0; i < num_fdes; i++)
    1797      {
    1798        fdep = &fd_info->entry[i];
    1799        fre_type = sframe_get_fre_type (fdep);
    1800        num_fres = fdep->sfde_func_num_fres;
    1801  
    1802        for (j = 0; j < num_fres; j++)
    1803  	{
    1804  	  fre_index = global + j;
    1805  	  frep = &fr_info->entry[fre_index];
    1806  
    1807  	  sframe_encoder_write_fre (contents, frep, fre_type, &esz);
    1808  	  contents += esz;
    1809  	  fre_size += esz; /* For debugging only.  */
    1810  	}
    1811        global += j;
    1812      }
    1813  
    1814    sframe_assert (fre_size == ehp->sfh_fre_len);
    1815    sframe_assert (global == ehp->sfh_num_fres);
    1816    sframe_assert ((size_t)(contents - encoder->sfe_data) == buf_size);
    1817  
    1818    /* Sort the FDE table */
    1819    sframe_sort_funcdesc (encoder);
    1820  
    1821    /* Sanity checks:
    1822       - the FDE section must have been sorted by now on the start address
    1823       of each function.  */
    1824    flags = ehp->sfh_preamble.sfp_flags;
    1825    if (!(flags & SFRAME_F_FDE_SORTED)
    1826        || (fd_info == NULL))
    1827      return sframe_set_errno (&err, SFRAME_ERR_FDE_INVAL);
    1828  
    1829    contents = encoder->sfe_data;
    1830    /* Write out the SFrame header.  The SFrame header in the encoder
    1831       object has already been updated with correct offsets by the caller.  */
    1832    memcpy (contents, ehp, hdr_size);
    1833    contents += hdr_size;
    1834  
    1835    /* Write out the FDE table sorted on funtion start address.  */
    1836    memcpy (contents, fd_info->entry, all_fdes_size);
    1837    contents += all_fdes_size;
    1838  
    1839    return 0;
    1840  }
    1841  
    1842  /* Serialize the contents of the encoder and return the buffer.  ENCODED_SIZE
    1843     is updated to the size of the buffer.  */
    1844  
    1845  char *
    1846  sframe_encoder_write (sframe_encoder_ctx *encoder,
    1847  		      size_t *encoded_size, int *errp)
    1848  {
    1849    sframe_header *ehp;
    1850    size_t hdrsize, fsz, fresz, bufsize;
    1851    int foreign_endian;
    1852  
    1853    /* Initialize the encoded_size to zero.  This makes it simpler to just
    1854       return from the function in case of failure.  Free'ing up of
    1855       encoder->sfe_data is the responsibility of the caller.  */
    1856    *encoded_size = 0;
    1857  
    1858    if (encoder == NULL || encoded_size == NULL || errp == NULL)
    1859      return sframe_ret_set_errno (errp, SFRAME_ERR_INVAL);
    1860  
    1861    ehp = sframe_encoder_get_header (encoder);
    1862    hdrsize = sframe_get_hdr_size (ehp);
    1863    fsz = sframe_encoder_get_num_fidx (encoder)
    1864      * sizeof (sframe_func_desc_entry);
    1865    fresz = encoder->sfe_fre_nbytes;
    1866  
    1867    /* The total size of buffer is the sum of header, SFrame Function Descriptor
    1868       Entries section and the FRE section.  */
    1869    bufsize = hdrsize + fsz + fresz;
    1870    encoder->sfe_data = (char *) malloc (bufsize);
    1871    if (encoder->sfe_data == NULL)
    1872      return sframe_ret_set_errno (errp, SFRAME_ERR_NOMEM);
    1873    encoder->sfe_data_size = bufsize;
    1874  
    1875    /* Update the information in the SFrame header.  */
    1876    /* SFrame FDE section follows immediately after the header.  */
    1877    ehp->sfh_fdeoff = 0;
    1878    /* SFrame FRE section follows immediately after the SFrame FDE section.  */
    1879    ehp->sfh_freoff = fsz;
    1880    ehp->sfh_fre_len = fresz;
    1881  
    1882    foreign_endian = need_swapping (ehp->sfh_abi_arch);
    1883  
    1884    /* Write out the FDE Index and the FRE table in the sfe_data. */
    1885    if (sframe_encoder_write_sframe (encoder))
    1886      return sframe_ret_set_errno (errp, SFRAME_ERR_BUF_INVAL);
    1887  
    1888    /* Endian flip the contents if necessary.  */
    1889    if (foreign_endian)
    1890      {
    1891        if (flip_sframe (encoder->sfe_data, bufsize, 1))
    1892  	return sframe_ret_set_errno (errp, SFRAME_ERR_BUF_INVAL);
    1893        flip_header ((sframe_header*)encoder->sfe_data);
    1894      }
    1895  
    1896    *encoded_size = bufsize;
    1897    return encoder->sfe_data;
    1898  }