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