Home | History | Annotate | Line # | Download | only in libsframe
      1 /* sframe.c - SFrame decoder/encoder.
      2 
      3    Copyright (C) 2022-2026 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 /* Representation of SFrame FDE internal to libsframe.  */
     30 typedef struct sframe_func_desc_entry_int
     31 {
     32   int64_t func_start_pc_offset;
     33   uint32_t func_size;
     34   uint32_t func_start_fre_off;
     35   uint32_t func_num_fres;
     36   uint8_t func_info;
     37   uint8_t func_info2;
     38   uint8_t func_rep_size;
     39 } sframe_func_desc_entry_int;
     40 
     41 struct sf_fde_tbl
     42 {
     43   unsigned int count;
     44   unsigned int alloced;
     45   sframe_func_desc_entry_int entry[1];
     46 };
     47 
     48 struct sf_fre_tbl
     49 {
     50   unsigned int count;
     51   unsigned int alloced;
     52   sframe_frame_row_entry entry[1];
     53 };
     54 
     55 #define _sf_printflike_(string_index,first_to_check) \
     56     __attribute__ ((__format__ (__printf__, (string_index), (first_to_check))))
     57 
     58 static void debug_printf (const char *, ...);
     59 
     60 static int _sframe_debug;	/* Control for printing out debug info.  */
     61 
     62 #define SFRAME_FRE_ALLOC_LEN  64
     63 static int number_of_entries = 64;
     64 
     65 static void
     66 sframe_init_debug (void)
     67 {
     68   static int inited;
     69 
     70   if (!inited)
     71     {
     72       _sframe_debug = getenv ("SFRAME_DEBUG") != NULL;
     73       inited = 1;
     74     }
     75 }
     76 
     77 _sf_printflike_ (1, 2)
     78 static void debug_printf (const char *format, ...)
     79 {
     80   if (_sframe_debug)
     81     {
     82       va_list args;
     83 
     84       va_start (args, format);
     85       vfprintf (stderr, format, args);
     86       va_end (args);
     87     }
     88 }
     89 
     90 /* Generate bitmask of given size in bytes.  This is used for
     91    some checks on the FRE start address.
     92    SFRAME_FRE_TYPE_ADDR1 => 1 byte => [ bitmask = 0xff ]
     93    SFRAME_FRE_TYPE_ADDR2 => 2 byte => [ bitmask = 0xffff ]
     94    SFRAME_FRE_TYPE_ADDR4 => 4 byte => [ bitmask = 0xffffffff ].  */
     95 #define SFRAME_BITMASK_OF_SIZE(size_in_bytes) \
     96   (((uint64_t)1 << (size_in_bytes*8)) - 1)
     97 
     98 /* Store the specified error code into errp if it is non-NULL.
     99    Return SFRAME_ERR.  */
    100 
    101 static int
    102 sframe_set_errno (int *errp, int error)
    103 {
    104   if (errp != NULL)
    105     *errp = error;
    106   return SFRAME_ERR;
    107 }
    108 
    109 /* Store the specified error code into errp if it is non-NULL.
    110    Return NULL.  */
    111 
    112 static void *
    113 sframe_ret_set_errno (int *errp, int error)
    114 {
    115   if (errp != NULL)
    116     *errp = error;
    117   return NULL;
    118 }
    119 
    120 /* Allocate space for NUM_FDES number of SFrame FDEs of type
    121    sframe_func_desc_entry_int.  This is version-unaware because this pertains
    122    to libsframe's internal in-memory representation of SFrame FDE.  */
    123 
    124 static int
    125 sframe_fde_tbl_alloc (sf_fde_tbl **fde_tbl, unsigned int num_fdes)
    126 {
    127   size_t fidx_size = num_fdes * sizeof (sframe_func_desc_entry_int);
    128   size_t fd_tbl_sz = (sizeof (sf_fde_tbl) + fidx_size);
    129 
    130   *fde_tbl = malloc (fd_tbl_sz);
    131   if (*fde_tbl == NULL)
    132     return SFRAME_ERR;
    133 
    134   (*fde_tbl)->alloced = num_fdes;
    135 
    136   return 0;
    137 }
    138 
    139 /* Initialize libsframe's internal representation of SFrame FDEs.  */
    140 
    141 static int
    142 sframe_fde_tbl_init (sf_fde_tbl *fde_tbl, const char *fde_buf,
    143 		     const char *fre_buf, size_t *fidx_size,
    144 		     unsigned int num_fdes, uint8_t ver)
    145 {
    146   if (ver == SFRAME_VERSION_3 && SFRAME_VERSION == SFRAME_VERSION_3)
    147     {
    148       *fidx_size = num_fdes * sizeof (sframe_func_desc_idx_v3);
    149       for (unsigned int i = 0; i < num_fdes; i++)
    150 	{
    151 	  const sframe_func_desc_idx_v3 *fdep
    152 	    = (sframe_func_desc_idx_v3 *)fde_buf + i;
    153 	  fde_tbl->entry[i].func_start_pc_offset = fdep->sfdi_func_start_offset;
    154 	  fde_tbl->entry[i].func_size = fdep->sfdi_func_size;
    155 	  fde_tbl->entry[i].func_start_fre_off = fdep->sfdi_func_start_fre_off;
    156 	  /* V3 organizes the following data closer to the SFrame FREs for the
    157 	     function.  Access them via the sfde_func_start_fre_off.  */
    158 	  const sframe_func_desc_attr_v3 *fattr
    159 	    = (sframe_func_desc_attr_v3 *)(fre_buf
    160 					   + fdep->sfdi_func_start_fre_off);
    161 	  fde_tbl->entry[i].func_num_fres = fattr->sfda_func_num_fres;
    162 	  fde_tbl->entry[i].func_info = fattr->sfda_func_info;
    163 	  fde_tbl->entry[i].func_info2 = fattr->sfda_func_info2;
    164 	  fde_tbl->entry[i].func_rep_size = fattr->sfda_func_rep_size;
    165 	}
    166       fde_tbl->count = num_fdes;
    167     }
    168   /* If ver is not the latest, read buffer manually and upgrade from
    169      sframe_func_desc_entry_v2 to populate the sf_fde_tbl entries.  */
    170   else if (ver == SFRAME_VERSION_2 && SFRAME_VERSION == SFRAME_VERSION_3)
    171     {
    172       *fidx_size = num_fdes * sizeof (sframe_func_desc_entry_v2);
    173       for (unsigned int i = 0; i < num_fdes; i++)
    174 	{
    175 	  const sframe_func_desc_entry_v2 *fdep
    176 	    = (sframe_func_desc_entry_v2 *)fde_buf + i;
    177 	  fde_tbl->entry[i].func_start_pc_offset
    178 	    = fdep->sfde_func_start_address;
    179 	  fde_tbl->entry[i].func_size = fdep->sfde_func_size;
    180 	  fde_tbl->entry[i].func_start_fre_off = fdep->sfde_func_start_fre_off;
    181 	  fde_tbl->entry[i].func_num_fres = fdep->sfde_func_num_fres;
    182 	  fde_tbl->entry[i].func_info = fdep->sfde_func_info;
    183 	  fde_tbl->entry[i].func_info2 = 0;
    184 	  fde_tbl->entry[i].func_rep_size = fdep->sfde_func_rep_size;
    185 	}
    186       fde_tbl->count = num_fdes;
    187     }
    188   else
    189     {
    190       /* Not possible ATM.  */
    191       *fidx_size = 0;
    192       return SFRAME_ERR;
    193     }
    194 
    195   return 0;
    196 }
    197 
    198 /* Get the SFrame header size.  */
    199 
    200 static uint32_t
    201 sframe_get_hdr_size (const sframe_header *sfh)
    202 {
    203   return SFRAME_V1_HDR_SIZE (*sfh);
    204 }
    205 
    206 /* Access functions for frame row entry data.  */
    207 
    208 static uint8_t
    209 sframe_fre_get_dataword_count (uint8_t fre_info)
    210 {
    211   return SFRAME_V1_FRE_OFFSET_COUNT (fre_info);
    212 }
    213 
    214 static uint8_t
    215 sframe_fre_get_dataword_size (uint8_t fre_info)
    216 {
    217   return SFRAME_V1_FRE_OFFSET_SIZE (fre_info);
    218 }
    219 
    220 static bool
    221 sframe_get_fre_ra_mangled_p (uint8_t fre_info)
    222 {
    223   return SFRAME_V1_FRE_MANGLED_RA_P (fre_info);
    224 }
    225 
    226 static bool
    227 sframe_get_fre_ra_undefined_p (uint8_t fre_info)
    228 {
    229   return SFRAME_V2_FRE_RA_UNDEFINED_P (fre_info);
    230 }
    231 
    232 /* Access functions for info from function descriptor entry.  */
    233 
    234 static uint32_t
    235 sframe_get_fre_type (sframe_func_desc_entry_int *fdep)
    236 {
    237   uint32_t fre_type = 0;
    238   if (fdep)
    239     fre_type = SFRAME_V2_FUNC_FRE_TYPE (fdep->func_info);
    240   return fre_type;
    241 }
    242 
    243 static uint32_t
    244 sframe_get_fde_pc_type (sframe_func_desc_entry_int *fdep)
    245 {
    246   uint32_t fde_pc_type = 0;
    247   if (fdep)
    248     fde_pc_type = SFRAME_V2_FUNC_PC_TYPE (fdep->func_info);
    249   return fde_pc_type;
    250 }
    251 
    252 /* Check if flipping is needed, based on ENDIAN.  */
    253 
    254 static int
    255 need_swapping (int endian)
    256 {
    257   unsigned int ui = 1;
    258   char *c = (char *)&ui;
    259   int is_little = (int)*c;
    260 
    261   switch (endian)
    262     {
    263       case SFRAME_ABI_AARCH64_ENDIAN_LITTLE:
    264       case SFRAME_ABI_AMD64_ENDIAN_LITTLE:
    265 	return !is_little;
    266       case SFRAME_ABI_AARCH64_ENDIAN_BIG:
    267       case SFRAME_ABI_S390X_ENDIAN_BIG:
    268 	return is_little;
    269       default:
    270 	break;
    271     }
    272 
    273   return 0;
    274 }
    275 
    276 /* Flip the endianness of the SFrame header starting at BUF.
    277    VER is the version of the SFrame data in the buffer.
    278 
    279    Returns SFRAME_ERR if any error.  If error code is returned, the flipped
    280    header should not be used.  */
    281 
    282 static int
    283 flip_header (char *buf, uint8_t ver ATTRIBUTE_UNUSED)
    284 {
    285   /* SFrame header binary format has remained the same in SFRAME_VERSION_1,
    286      SFRAME_VERSION_2.  */
    287   sframe_header *sfh = (sframe_header *) buf;
    288   swap_thing (sfh->sfh_preamble.sfp_magic);
    289   swap_thing (sfh->sfh_preamble.sfp_version);
    290   swap_thing (sfh->sfh_preamble.sfp_flags);
    291   swap_thing (sfh->sfh_abi_arch);
    292   swap_thing (sfh->sfh_cfa_fixed_fp_offset);
    293   swap_thing (sfh->sfh_cfa_fixed_ra_offset);
    294   swap_thing (sfh->sfh_auxhdr_len);
    295   swap_thing (sfh->sfh_num_fdes);
    296   swap_thing (sfh->sfh_num_fres);
    297   swap_thing (sfh->sfh_fre_len);
    298   swap_thing (sfh->sfh_fdeoff);
    299   swap_thing (sfh->sfh_freoff);
    300 
    301   /* Alert for missing functionatlity.  Auxiliary header, if present, needs to
    302      flipped based on per abi/arch semantics.  */
    303   if (sfh->sfh_auxhdr_len)
    304     return SFRAME_ERR;
    305 
    306   return 0;
    307 }
    308 
    309 /* Endian flip the SFrame FDE at BUF (buffer size provided in BUF_SIZE), given
    310    the SFrame version VER.  Update the FDE_SIZE to the size of the SFrame FDE
    311    flipped.
    312 
    313    Return SFRAME_ERR if any error.  If error code is returned, the flipped FDEP
    314    should not be used.  */
    315 
    316 static int
    317 flip_fde_desc (char *buf, size_t buf_size, uint8_t ver)
    318 {
    319   if (ver == SFRAME_VERSION_3)
    320     {
    321       if (buf_size < sizeof (sframe_func_desc_idx_v3))
    322 	return SFRAME_ERR;
    323 
    324       sframe_func_desc_idx_v3 *fdep = (sframe_func_desc_idx_v3 *) buf;
    325       swap_thing (fdep->sfdi_func_start_offset);
    326       swap_thing (fdep->sfdi_func_size);
    327       swap_thing (fdep->sfdi_func_start_fre_off);
    328     }
    329   else if (ver == SFRAME_VERSION_2)
    330     {
    331       if (buf_size < sizeof (sframe_func_desc_entry_v2))
    332 	return SFRAME_ERR;
    333 
    334       sframe_func_desc_entry_v2 *fdep = (sframe_func_desc_entry_v2 *) buf;
    335       swap_thing (fdep->sfde_func_start_address);
    336       swap_thing (fdep->sfde_func_size);
    337       swap_thing (fdep->sfde_func_start_fre_off);
    338       swap_thing (fdep->sfde_func_num_fres);
    339     }
    340   else
    341     return SFRAME_ERR;
    342 
    343   return 0;
    344 }
    345 
    346 static int
    347 flip_fde_attr_v3 (char *buf, size_t buf_size)
    348 {
    349   if (buf_size < sizeof (sframe_func_desc_attr_v3))
    350     return SFRAME_ERR;
    351 
    352   /* sfda_func_num_fres is the first member of sframe_func_desc_attr_v3.  */
    353   struct { uint16_t x; } ATTRIBUTE_PACKED *p = (void*)buf;
    354   swap_thing (p->x);
    355 
    356   return 0;
    357 }
    358 /* Check if SFrame header has valid data.  */
    359 
    360 static bool
    361 sframe_header_sanity_check_p (const sframe_header *hp)
    362 {
    363   /* Check preamble is valid.  */
    364   if (hp->sfh_preamble.sfp_magic != SFRAME_MAGIC
    365       || (hp->sfh_preamble.sfp_version != SFRAME_VERSION_1
    366 	  && hp->sfh_preamble.sfp_version != SFRAME_VERSION_2
    367 	  && hp->sfh_preamble.sfp_version != SFRAME_VERSION_3))
    368     return false;
    369 
    370   /* Check flags (version-aware).
    371      Do not validate V3 headers against V2 flag definitions, as V3 may
    372      introduce new flags.  */
    373   uint8_t valid_flags = SFRAME_V2_F_ALL_FLAGS;
    374   if (hp->sfh_preamble.sfp_version == SFRAME_VERSION_3)
    375     /* Replace with SFRAME_V3_F_ALL_FLAGS.  */
    376     valid_flags = SFRAME_V3_F_ALL_FLAGS;
    377   if (hp->sfh_preamble.sfp_flags & ~valid_flags)
    378     return false;
    379 
    380   /* Check offsets are valid.  */
    381   if (hp->sfh_fdeoff > hp->sfh_freoff)
    382     return false;
    383 
    384   return true;
    385 }
    386 
    387 /* Flip the start address pointed to by FP.  */
    388 
    389 static void
    390 flip_fre_start_address (void *addr, uint32_t fre_type)
    391 {
    392   if (fre_type == SFRAME_FRE_TYPE_ADDR2)
    393     {
    394       struct { uint16_t x; } ATTRIBUTE_PACKED *p = addr;
    395       swap_thing (p->x);
    396     }
    397   else if (fre_type == SFRAME_FRE_TYPE_ADDR4)
    398     {
    399       struct { uint32_t x; } ATTRIBUTE_PACKED *p = addr;
    400       swap_thing (p->x);
    401     }
    402 }
    403 
    404 static void
    405 flip_fre_datawords (void *datawords, uint8_t dataword_size,
    406 		    uint8_t dataword_cnt)
    407 {
    408   int j;
    409 
    410   if (dataword_size == SFRAME_FRE_DATAWORD_2B)
    411     {
    412       struct { uint16_t x; } ATTRIBUTE_PACKED *p = datawords;
    413       for (j = dataword_cnt; j > 0; p++, j--)
    414 	swap_thing (p->x);
    415     }
    416   else if (dataword_size == SFRAME_FRE_DATAWORD_4B)
    417     {
    418       struct { uint32_t x; } ATTRIBUTE_PACKED *p = datawords;
    419       for (j = dataword_cnt; j > 0; p++, j--)
    420 	swap_thing (p->x);
    421     }
    422 }
    423 
    424 /* Get the FRE start address size, given the FRE_TYPE.  */
    425 
    426 static size_t
    427 sframe_fre_start_addr_size (uint32_t fre_type)
    428 {
    429   size_t addr_size = 0;
    430   switch (fre_type)
    431     {
    432     case SFRAME_FRE_TYPE_ADDR1:
    433       addr_size = 1;
    434       break;
    435     case SFRAME_FRE_TYPE_ADDR2:
    436       addr_size = 2;
    437       break;
    438     case SFRAME_FRE_TYPE_ADDR4:
    439       addr_size = 4;
    440       break;
    441     default:
    442       /* No other value is expected.  */
    443       sframe_assert (0);
    444       break;
    445     }
    446   return addr_size;
    447 }
    448 
    449 /* Check if the FREP has valid data.  */
    450 
    451 static bool
    452 sframe_fre_sanity_check_p (const sframe_frame_row_entry *frep)
    453 {
    454   uint8_t dataword_size, dataword_cnt;
    455   uint8_t fre_info;
    456 
    457   if (frep == NULL)
    458     return false;
    459 
    460   fre_info = frep->fre_info;
    461   dataword_size = sframe_fre_get_dataword_size (fre_info);
    462 
    463   if (dataword_size != SFRAME_FRE_DATAWORD_1B
    464       && dataword_size != SFRAME_FRE_DATAWORD_2B
    465       && dataword_size != SFRAME_FRE_DATAWORD_4B)
    466     return false;
    467 
    468   dataword_cnt = sframe_fre_get_dataword_count (fre_info);
    469   if (dataword_cnt > MAX_NUM_DATAWORDS)
    470     return false;
    471 
    472   return true;
    473 }
    474 
    475 /* Get FRE_INFO's data words' size in bytes.  */
    476 
    477 static size_t
    478 sframe_fre_datawords_bytes_size (uint8_t fre_info)
    479 {
    480   uint8_t dataword_size, dataword_cnt;
    481 
    482   dataword_size = sframe_fre_get_dataword_size (fre_info);
    483 
    484   debug_printf ("dataword_size =  %u\n", dataword_size);
    485 
    486   dataword_cnt = sframe_fre_get_dataword_count (fre_info);
    487 
    488   if (dataword_size == SFRAME_FRE_DATAWORD_2B
    489       || dataword_size == SFRAME_FRE_DATAWORD_4B)	/* 2 or 4 bytes.  */
    490     return (dataword_cnt * (dataword_size * 2));
    491 
    492   return dataword_cnt;
    493 }
    494 
    495 /* Get total size in bytes to represent FREP in the binary format.  This
    496    includes the starting address, FRE info, and all the offsets.  */
    497 
    498 static size_t
    499 sframe_fre_entry_size (sframe_frame_row_entry *frep, uint32_t fre_type)
    500 {
    501   if (frep == NULL)
    502     return 0;
    503 
    504   uint8_t fre_info = frep->fre_info;
    505   size_t addr_size = sframe_fre_start_addr_size (fre_type);
    506 
    507   return (addr_size + sizeof (frep->fre_info)
    508 	  + sframe_fre_datawords_bytes_size (fre_info));
    509 }
    510 
    511 /* Get total size in bytes in the SFrame FRE at FRE_BUF location, given the
    512    type of FRE as FRE_TYPE.  */
    513 
    514 static size_t
    515 sframe_buf_fre_entry_size (const char *fre_buf, uint32_t fre_type)
    516 {
    517   if (fre_buf == NULL)
    518     return 0;
    519 
    520   size_t addr_size = sframe_fre_start_addr_size (fre_type);
    521   uint8_t fre_info = *(uint8_t *)(fre_buf + addr_size);
    522 
    523   return (addr_size + sizeof (fre_info)
    524 	  + sframe_fre_datawords_bytes_size (fre_info));
    525 }
    526 /* Get the function descriptor entry at index FUNC_IDX in the decoder
    527    context CTX.  */
    528 
    529 static sframe_func_desc_entry_int *
    530 sframe_decoder_get_funcdesc_at_index (const sframe_decoder_ctx *ctx,
    531 				      uint32_t func_idx)
    532 {
    533   sframe_func_desc_entry_int *fdep;
    534   uint32_t num_fdes;
    535   int err;
    536 
    537   num_fdes = sframe_decoder_get_num_fidx (ctx);
    538   if (num_fdes == 0
    539       || func_idx >= num_fdes
    540       || ctx->sfd_funcdesc == NULL
    541       || ctx->sfd_funcdesc->count <= func_idx)
    542     return sframe_ret_set_errno (&err, SFRAME_ERR_DCTX_INVAL);
    543 
    544   fdep = &ctx->sfd_funcdesc->entry[func_idx];
    545   return fdep;
    546 }
    547 
    548 /* Get the offset of the start PC of the SFrame FDE at FUNC_IDX from the start
    549    of the SFrame section.  This section-relative offset is used within
    550    libsframe for sorting the SFrame FDEs, and also information lookup routines
    551    like sframe_find_fre.
    552 
    553    If FUNC_IDX is not a valid index in the given decoder object, returns 0.  */
    554 
    555 static int64_t
    556 sframe_decoder_get_secrel_func_start_addr (const sframe_decoder_ctx *dctx,
    557 					   uint32_t func_idx)
    558 {
    559   int err = 0;
    560   int32_t offsetof_fde_in_sec
    561     = sframe_decoder_get_offsetof_fde_start_addr (dctx, func_idx, &err);
    562   /* If func_idx is not a valid index, return 0.  */
    563   if (err)
    564     return 0;
    565 
    566   const sframe_func_desc_entry_int *fdep = &dctx->sfd_funcdesc->entry[func_idx];
    567   int64_t func_start_pc_offset = fdep->func_start_pc_offset;
    568 
    569   return func_start_pc_offset + offsetof_fde_in_sec;
    570 }
    571 
    572 /* Check whether for the given FDEP, the SFrame Frame Row Entry identified via
    573    the START_IP_OFFSET and the END_IP_OFFSET, provides the stack trace
    574    information for the PC.  */
    575 
    576 static bool
    577 sframe_fre_check_range_p (const sframe_decoder_ctx *dctx, uint32_t func_idx,
    578 			  uint32_t start_ip_offset, uint32_t end_ip_offset,
    579 			  int64_t pc)
    580 {
    581   sframe_func_desc_entry_int *fdep;
    582   int64_t func_start_pc_offset;
    583   uint8_t rep_block_size;
    584   uint32_t pc_type;
    585   uint32_t pc_offset;
    586   bool mask_p;
    587 
    588   fdep = &dctx->sfd_funcdesc->entry[func_idx];
    589   func_start_pc_offset = sframe_decoder_get_secrel_func_start_addr (dctx,
    590 								    func_idx);
    591   pc_type = sframe_get_fde_pc_type (fdep);
    592   mask_p = (pc_type == SFRAME_V3_FDE_PCTYPE_MASK);
    593   rep_block_size = fdep->func_rep_size;
    594 
    595   if (func_start_pc_offset > pc)
    596     return false;
    597 
    598   /* Given func_start_addr <= pc, pc - func_start_addr must be positive.  */
    599   pc_offset = pc - func_start_pc_offset;
    600   /* For SFrame FDEs encoding information for repetitive pattern of insns,
    601      masking with the rep_block_size is necessary to find the matching FRE.  */
    602   if (mask_p)
    603     pc_offset = pc_offset % rep_block_size;
    604 
    605   return (start_ip_offset <= pc_offset) && (end_ip_offset >= pc_offset);
    606 }
    607 
    608 /* Read the on-disk SFrame FDE from location BUF of size in bytes equal to
    609    BUF_SIZE.
    610 
    611    Return SFRAME_ERR if any error.  If error code is returned, the read values
    612    should not be used.  */
    613 
    614 static int
    615 sframe_decode_fde_desc_v2 (const char *buf, size_t buf_size,
    616 			   uint32_t *num_fres, uint32_t *fre_type,
    617 			   uint32_t *fre_offset)
    618 {
    619   if (buf_size < sizeof (sframe_func_desc_entry_v2))
    620     return SFRAME_ERR;
    621 
    622   sframe_func_desc_entry_v2 *fdep = (sframe_func_desc_entry_v2 *) buf;
    623   *num_fres = fdep->sfde_func_num_fres;
    624   *fre_type = SFRAME_V2_FUNC_FRE_TYPE (fdep->sfde_func_info);
    625   *fre_offset = fdep->sfde_func_start_fre_off;
    626 
    627   return 0;
    628 }
    629 
    630 /* Read the on-disk SFrame FDE from location BUF of size in bytes equal to
    631    BUF_SIZE.
    632 
    633    Return SFRAME_ERR if any error.  If error code is returned, the read values
    634    should not be used.  */
    635 
    636 static int
    637 sframe_decode_fde_idx_v3 (const char *buf, size_t buf_size,
    638 			  uint32_t *fre_offset)
    639 {
    640   if (buf_size < sizeof (sframe_func_desc_idx_v3))
    641     return SFRAME_ERR;
    642 
    643   sframe_func_desc_idx_v3 *fdep = (sframe_func_desc_idx_v3 *) buf;
    644   *fre_offset = fdep->sfdi_func_start_fre_off;
    645 
    646   return 0;
    647 }
    648 
    649 static int
    650 sframe_decode_fde_attr_v3 (const char *buf, size_t buf_size,
    651 			   uint16_t *num_fres, uint32_t *fre_type)
    652 {
    653   if (buf_size < sizeof (sframe_func_desc_attr_v3))
    654     return SFRAME_ERR;
    655 
    656   const sframe_func_desc_attr_v3 *fdap = (sframe_func_desc_attr_v3 *) buf;
    657   *num_fres = fdap->sfda_func_num_fres;
    658   *fre_type = SFRAME_V3_FDE_FRE_TYPE (fdap->sfda_func_info);
    659   return 0;
    660 }
    661 
    662 static int
    663 flip_fre (char *fp, size_t fp_size, uint32_t fre_type, size_t *fre_size)
    664 {
    665   uint8_t fre_info;
    666   uint8_t dataword_size, dataword_cnt;
    667   size_t addr_size, fre_info_size, datawords_bytes_size;
    668   int err = 0;
    669 
    670   if (fre_size == NULL)
    671     return sframe_set_errno (&err, SFRAME_ERR_INVAL);
    672 
    673   addr_size = sframe_fre_start_addr_size (fre_type);
    674   if (addr_size > fp_size)
    675     return SFRAME_ERR;
    676   flip_fre_start_address (fp, fre_type);
    677 
    678   /* Advance the buffer pointer to where the FRE info is.  */
    679   fp += addr_size;
    680   fp_size -= addr_size;
    681 
    682   /* FRE info is uint8_t.  No need to flip.  */
    683   fre_info_size = sizeof (uint8_t);
    684   if (fre_info_size > fp_size)
    685     return SFRAME_ERR;
    686   fre_info = *(uint8_t*)fp;
    687   dataword_size = sframe_fre_get_dataword_size (fre_info);
    688   dataword_cnt = sframe_fre_get_dataword_count (fre_info);
    689 
    690   /* Advance the buffer pointer to where the stack offsets are.  */
    691   fp += fre_info_size;
    692   fp_size -= fre_info_size;
    693   datawords_bytes_size = sframe_fre_datawords_bytes_size (fre_info);
    694   if (datawords_bytes_size > fp_size)
    695     return SFRAME_ERR;
    696   flip_fre_datawords (fp, dataword_size, dataword_cnt);
    697 
    698   *fre_size = addr_size + fre_info_size + datawords_bytes_size;
    699 
    700   return 0;
    701 }
    702 
    703 /* Endian flip the contents of FRAME_BUF of size BUF_SIZE.
    704    The SFrame header in the FRAME_BUF must be endian flipped prior to
    705    calling flip_sframe.
    706 
    707    Endian flipping at decode time vs encode time have different needs.  At
    708    encode time, the frame_buf is in host endianness, and hence, values should
    709    be read up before the buffer is changed to foreign endianness.  This change
    710    of behaviour is specified via TO_FOREIGN arg.
    711 
    712    If an error code is returned, the buffer should not be used.  */
    713 
    714 static int
    715 flip_sframe_fdes_with_fres_v2 (char *frame_buf, size_t buf_size,
    716 			       uint32_t to_foreign)
    717 {
    718   char *fp = NULL;
    719   uint32_t num_fres = 0;
    720   uint32_t fre_type = 0;
    721   uint32_t fre_offset = 0;
    722   size_t esz = 0;
    723   int err = 0;
    724   /* For error checking.  */
    725   size_t fde_bytes_flipped = 0;
    726   size_t fre_bytes_flipped = 0;
    727 
    728   /* Header must be in host endianness at this time.  */
    729   const sframe_header *ihp = (sframe_header *)frame_buf;
    730 
    731   if (!sframe_header_sanity_check_p (ihp))
    732     return sframe_set_errno (&err, SFRAME_ERR_BUF_INVAL);
    733 
    734   /* The contents of the SFrame header are safe to read.  Get the number of
    735      FDEs and the first FDE in the buffer.  */
    736   size_t hdrsz = sframe_get_hdr_size (ihp);
    737   uint32_t num_fdes = ihp->sfh_num_fdes;
    738   uint8_t ver = ihp->sfh_preamble.sfp_version;
    739   char *fdes = frame_buf + hdrsz + ihp->sfh_fdeoff;
    740   char *fres = frame_buf + hdrsz + ihp->sfh_freoff;
    741   const char *buf_end = frame_buf + buf_size;
    742 
    743   unsigned int i = 0, j = 0;
    744   unsigned int prev_frep_index = 0;
    745   size_t fsz = sizeof (sframe_func_desc_entry_v2);
    746   for (i = 0; i < num_fdes; fdes += fsz, i++)
    747     {
    748       if (fdes >= buf_end)
    749 	goto bad;
    750 
    751       /* Handle FDE.  */
    752       if (to_foreign && sframe_decode_fde_desc_v2 (fdes, buf_end - fdes,
    753 						   &num_fres, &fre_type,
    754 						   &fre_offset))
    755 	goto bad;
    756 
    757       if (flip_fde_desc (fdes, buf_end - fdes, ver))
    758 	goto bad;
    759 
    760       if (!to_foreign && sframe_decode_fde_desc_v2 (fdes, buf_end - fdes,
    761 						    &num_fres, &fre_type,
    762 						    &fre_offset))
    763 	goto bad;
    764 
    765       fde_bytes_flipped += fsz;
    766 
    767       /* Handle FREs.  */
    768       fp = fres + fre_offset;
    769       for (; j < prev_frep_index + num_fres; j++)
    770 	{
    771 	  if (flip_fre (fp, buf_end - fp, fre_type, &esz))
    772 	    goto bad;
    773 	  fre_bytes_flipped += esz;
    774 	  fp += esz;
    775 	}
    776       prev_frep_index = j;
    777     }
    778 
    779   /* All FDEs must have been endian flipped by now.  */
    780   if (i != num_fdes || fde_bytes_flipped > ihp->sfh_freoff - ihp->sfh_fdeoff)
    781     goto bad;
    782 
    783   /* All FREs must have been endian flipped by now.  */
    784   if (j != ihp->sfh_num_fres || fre_bytes_flipped > ihp->sfh_fre_len)
    785     goto bad;
    786 
    787   /* Optional trailing section padding.  */
    788   size_t frame_size = hdrsz + ihp->sfh_freoff + fre_bytes_flipped;
    789   for (fp = frame_buf + frame_size; fp < frame_buf + buf_size; fp++)
    790     if (*fp != '\0')
    791       goto bad;
    792 
    793   /* Done.  */
    794   return 0;
    795 bad:
    796   return SFRAME_ERR;
    797 }
    798 
    799 /* Endian flip the contents of FRAME_BUF of size BUF_SIZE.
    800    The SFrame header in the FRAME_BUF must be endian flipped prior to
    801    calling flip_sframe_fdes_with_fres_v3.
    802 
    803    Endian flipping at decode time vs encode time have different needs.  At
    804    encode time, the frame_buf is in host endianness, and hence, values should
    805    be read up before the buffer is changed to foreign endianness.  This change
    806    of behaviour is specified via TO_FOREIGN arg.
    807 
    808    If an error code is returned, the buffer should not be used.  */
    809 
    810 static int
    811 flip_sframe_fdes_with_fres_v3 (char *frame_buf, size_t buf_size,
    812 			       uint32_t to_foreign)
    813 {
    814   char *fp = NULL;
    815   uint16_t num_fres = 0;
    816   uint32_t fre_type = 0;
    817   uint32_t fre_offset = 0;
    818   size_t esz = 0;
    819   int err = 0;
    820   /* For error checking.  */
    821   size_t fde_bytes_flipped = 0;
    822   size_t fre_bytes_flipped = 0;
    823 
    824   /* Header must be in host endianness at this time.  */
    825   const sframe_header *ihp = (sframe_header *)frame_buf;
    826 
    827   if (!sframe_header_sanity_check_p (ihp))
    828     return sframe_set_errno (&err, SFRAME_ERR_BUF_INVAL);
    829 
    830   /* The contents of the SFrame header are safe to read.  Get the number of
    831      FDEs and the first FDE in the buffer.  */
    832   size_t hdrsz = sframe_get_hdr_size (ihp);
    833   uint32_t num_fdes = ihp->sfh_num_fdes;
    834   uint8_t ver = ihp->sfh_preamble.sfp_version;
    835   char *fdes = frame_buf + hdrsz + ihp->sfh_fdeoff;
    836   char *fres = frame_buf + hdrsz + ihp->sfh_freoff;
    837   const char *buf_end = frame_buf + buf_size;
    838 
    839   unsigned int i = 0, j = 0;
    840   unsigned int prev_frep_index = 0;
    841   size_t fsz = sizeof (sframe_func_desc_idx_v3);
    842   for (i = 0; i < num_fdes; fdes += fsz, i++)
    843     {
    844       if (fdes >= buf_end)
    845 	goto bad;
    846 
    847       /* Handle FDE.  */
    848       if (to_foreign && sframe_decode_fde_idx_v3 (fdes, buf_end - fdes,
    849 						  &fre_offset))
    850 	goto bad;
    851 
    852       if (flip_fde_desc (fdes, buf_end - fdes, ver))
    853 	goto bad;
    854 
    855       if (!to_foreign && sframe_decode_fde_idx_v3 (fdes, buf_end - fdes,
    856 						   &fre_offset))
    857 	goto bad;
    858 
    859       fde_bytes_flipped += fsz;
    860 
    861       /* Handle FDE attr (only in V3).  */
    862       fp = fres + fre_offset;
    863       if (to_foreign && sframe_decode_fde_attr_v3 (fp, buf_end - fp,
    864 						   &num_fres, &fre_type))
    865 	goto bad;
    866 
    867       if (flip_fde_attr_v3 (fp, buf_end - fp))
    868 	goto bad;
    869 
    870       fre_bytes_flipped += sizeof (sframe_func_desc_attr_v3);
    871 
    872       if (!to_foreign && sframe_decode_fde_attr_v3 (fp, buf_end - fp,
    873 						    &num_fres, &fre_type))
    874 	goto bad;
    875 
    876       /* Handle FREs.  */
    877       fp += sizeof (sframe_func_desc_attr_v3);
    878       for (; j < prev_frep_index + num_fres; j++)
    879 	{
    880 	  if (flip_fre (fp, buf_end - fp, fre_type, &esz))
    881 	    goto bad;
    882 	  fre_bytes_flipped += esz;
    883 	  fp += esz;
    884 	}
    885       prev_frep_index = j;
    886     }
    887 
    888   /* All FDEs must have been endian flipped by now.  */
    889   if (i != num_fdes || fde_bytes_flipped > ihp->sfh_freoff - ihp->sfh_fdeoff)
    890     goto bad;
    891 
    892   /* All FREs must have been endian flipped by now.  */
    893   if (j != ihp->sfh_num_fres || fre_bytes_flipped > ihp->sfh_fre_len)
    894     goto bad;
    895 
    896   /* Optional trailing section padding.  */
    897   size_t frame_size = hdrsz + ihp->sfh_freoff + fre_bytes_flipped;
    898   for (fp = frame_buf + frame_size; fp < frame_buf + buf_size; fp++)
    899     if (*fp != '\0')
    900       goto bad;
    901 
    902   /* Done.  */
    903   return 0;
    904 bad:
    905   return SFRAME_ERR;
    906 }
    907 
    908 static int
    909 flip_sframe (char *frame_buf, size_t buf_size, uint32_t to_foreign)
    910 {
    911   int err = 0;
    912 
    913   /* Header must be in host endianness at this time.  */
    914   const sframe_header *ihp = (sframe_header *)frame_buf;
    915   if (!sframe_header_sanity_check_p (ihp))
    916     return sframe_set_errno (&err, SFRAME_ERR_BUF_INVAL);
    917   uint8_t ver = ihp->sfh_preamble.sfp_version;
    918 
    919   if (ver == SFRAME_VERSION_3)
    920     err = flip_sframe_fdes_with_fres_v3 (frame_buf, buf_size, to_foreign);
    921   else if (ver == SFRAME_VERSION_2)
    922     err = flip_sframe_fdes_with_fres_v2 (frame_buf, buf_size, to_foreign);
    923   else
    924     return sframe_set_errno (&err, SFRAME_ERR_BUF_INVAL);
    925 
    926   if (err)
    927     return sframe_set_errno (&err, SFRAME_ERR_BUF_INVAL);
    928 
    929   /* Success.  */
    930   return 0;
    931 }
    932 
    933 /* Expands the memory allocated for the SFrame Frame Row Entry (FRE) table
    934    FRE_TBL.  This function is called when the current FRE buffer is
    935    insufficient and more stack trace data in the form of COUNT number of SFrame
    936    FREs need to be added to the SFrame section.
    937 
    938    Updates ERRP with 0 on success, or an SFrame error code on failure (e.g.,
    939    memory allocation error).  */
    940 
    941 static sf_fre_tbl *
    942 sframe_grow_fre_tbl (sf_fre_tbl *fre_tbl, uint32_t count, int *errp)
    943 {
    944   size_t fre_tbl_sz = 0;
    945   /* Ensure buffer for at least COUNT number of elements.  */
    946   uint32_t grow_count = SFRAME_FRE_ALLOC_LEN + count;
    947   sf_fre_tbl *new_tbl = NULL;
    948 
    949   if (fre_tbl == NULL)
    950     {
    951       fre_tbl_sz = (sizeof (sf_fre_tbl)
    952 		    + (grow_count * sizeof (sframe_frame_row_entry)));
    953       new_tbl = malloc (fre_tbl_sz);
    954       if (new_tbl == NULL)
    955 	{
    956 	  sframe_set_errno (errp, SFRAME_ERR_NOMEM);
    957 	  goto bad;
    958 	}
    959 
    960       memset (new_tbl, 0, fre_tbl_sz);
    961       new_tbl->alloced = grow_count;
    962     }
    963   else if (fre_tbl->count + count >= fre_tbl->alloced)
    964     {
    965       uint32_t new_len = fre_tbl->alloced + grow_count;
    966       fre_tbl_sz = (sizeof (sf_fre_tbl)
    967 		    + (new_len * sizeof (sframe_frame_row_entry)));
    968       void *tmp = realloc (fre_tbl, fre_tbl_sz);
    969       if (tmp == NULL)
    970 	{
    971 	  sframe_set_errno (errp, SFRAME_ERR_NOMEM);
    972 	  goto bad;
    973 	}
    974       new_tbl = tmp;
    975 
    976       memset (&new_tbl->entry[new_tbl->alloced], 0,
    977 	      grow_count * sizeof (sframe_frame_row_entry));
    978       new_tbl->alloced += grow_count;
    979     }
    980 
    981 bad:
    982   return new_tbl;
    983 }
    984 
    985 /* The SFrame Decoder.  */
    986 
    987 /* Get SFrame header from the given decoder context DCTX.  */
    988 
    989 static const sframe_header *
    990 sframe_decoder_get_header (const sframe_decoder_ctx *dctx)
    991 {
    992   const sframe_header *hp = NULL;
    993   if (dctx != NULL)
    994     hp = &dctx->sfd_header;
    995   return hp;
    996 }
    997 
    998 /* Compare function for qsort'ing the FDE table.  */
    999 
   1000 static int
   1001 fde_func (const void *p1, const void *p2)
   1002 {
   1003   const sframe_func_desc_entry_int *aa = p1;
   1004   const sframe_func_desc_entry_int *bb = p2;
   1005 
   1006   if (aa->func_start_pc_offset < bb->func_start_pc_offset)
   1007     return -1;
   1008   else if (aa->func_start_pc_offset > bb->func_start_pc_offset)
   1009     return 1;
   1010   return 0;
   1011 }
   1012 
   1013 /* Get IDX'th offset from FRE.  Set errp as applicable.  */
   1014 
   1015 static int32_t
   1016 sframe_get_fre_offset (const sframe_frame_row_entry *fre, int idx, int *errp)
   1017 {
   1018   uint8_t dataword_cnt, dataword_size;
   1019 
   1020   if (fre == NULL || !sframe_fre_sanity_check_p (fre))
   1021     return sframe_set_errno (errp, SFRAME_ERR_FRE_INVAL);
   1022 
   1023   dataword_cnt = sframe_fre_get_dataword_count (fre->fre_info);
   1024   dataword_size = sframe_fre_get_dataword_size (fre->fre_info);
   1025 
   1026   if (dataword_cnt < idx + 1)
   1027     return sframe_set_errno (errp, SFRAME_ERR_FREOFFSET_NOPRESENT);
   1028 
   1029   if (errp)
   1030     *errp = 0; /* Offset Valid.  */
   1031 
   1032   if (dataword_size == SFRAME_FRE_DATAWORD_1B)
   1033     {
   1034       int8_t *offsets = (int8_t *)fre->fre_datawords;
   1035       return offsets[idx];
   1036     }
   1037   else if (dataword_size == SFRAME_FRE_DATAWORD_2B)
   1038     {
   1039       int16_t *offsets = (int16_t *)fre->fre_datawords;
   1040       return offsets[idx];
   1041     }
   1042   else
   1043     {
   1044       int32_t *offsets = (int32_t *)fre->fre_datawords;
   1045       return offsets[idx];
   1046     }
   1047 }
   1048 
   1049 /* Get IDX'th data word as unsigned data from FRE.  Set errp as applicable.  */
   1050 
   1051 uint32_t
   1052 sframe_get_fre_udata (const sframe_frame_row_entry *fre, int idx, int *errp)
   1053 {
   1054   uint8_t dataword_cnt, dataword_size;
   1055 
   1056   if (fre == NULL || !sframe_fre_sanity_check_p (fre))
   1057     return sframe_set_errno (errp, SFRAME_ERR_FRE_INVAL);
   1058 
   1059   dataword_cnt = sframe_fre_get_dataword_count (fre->fre_info);
   1060   dataword_size = sframe_fre_get_dataword_size (fre->fre_info);
   1061 
   1062   if (dataword_cnt < idx + 1)
   1063     return sframe_set_errno (errp, SFRAME_ERR_FREOFFSET_NOPRESENT);
   1064 
   1065   if (errp)
   1066     *errp = 0; /* Offset Valid.  */
   1067 
   1068   if (dataword_size == SFRAME_FRE_DATAWORD_1B)
   1069     {
   1070       uint8_t *datawords = (uint8_t *)fre->fre_datawords;
   1071       return datawords[idx];
   1072     }
   1073   else if (dataword_size == SFRAME_FRE_DATAWORD_2B)
   1074     {
   1075       uint16_t *datawords = (uint16_t *)fre->fre_datawords;
   1076       return datawords[idx];
   1077     }
   1078   else
   1079     {
   1080       uint32_t *datawords = (uint32_t *)fre->fre_datawords;
   1081       return datawords[idx];
   1082     }
   1083 }
   1084 
   1085 /* Free the decoder context.  */
   1086 
   1087 void
   1088 sframe_decoder_free (sframe_decoder_ctx **dctxp)
   1089 {
   1090   if (dctxp != NULL)
   1091     {
   1092       sframe_decoder_ctx *dctx = *dctxp;
   1093       if (dctx == NULL)
   1094 	return;
   1095 
   1096       if (dctx->sfd_funcdesc != NULL)
   1097 	{
   1098 	  free (dctx->sfd_funcdesc);
   1099 	  dctx->sfd_funcdesc = NULL;
   1100 	}
   1101       if (dctx->sfd_fres != NULL)
   1102 	{
   1103 	  free (dctx->sfd_fres);
   1104 	  dctx->sfd_fres = NULL;
   1105 	}
   1106       if (dctx->sfd_buf != NULL)
   1107 	{
   1108 	  free (dctx->sfd_buf);
   1109 	  dctx->sfd_buf = NULL;
   1110 	}
   1111 
   1112       free (*dctxp);
   1113       *dctxp = NULL;
   1114     }
   1115 }
   1116 
   1117 /* Create an FDE function info byte given an FRE_TYPE and an FDE_TYPE.  */
   1118 /* FIXME API for linker.  Revisit if its better placed somewhere else?  */
   1119 
   1120 unsigned char
   1121 sframe_fde_create_func_info (uint32_t fre_type,
   1122 			     uint32_t fde_type)
   1123 {
   1124   unsigned char func_info;
   1125   sframe_assert (fre_type == SFRAME_FRE_TYPE_ADDR1
   1126 		   || fre_type == SFRAME_FRE_TYPE_ADDR2
   1127 		   || fre_type == SFRAME_FRE_TYPE_ADDR4);
   1128   sframe_assert (fde_type == SFRAME_V3_FDE_PCTYPE_INC
   1129 		 || fde_type == SFRAME_V3_FDE_PCTYPE_MASK);
   1130   func_info = SFRAME_V2_FUNC_INFO (fde_type, fre_type);
   1131   return func_info;
   1132 }
   1133 
   1134 /* Get the FRE type given the function size.  */
   1135 /* FIXME API for linker.  Revisit if its better placed somewhere else?  */
   1136 
   1137 uint32_t
   1138 sframe_calc_fre_type (size_t func_size)
   1139 {
   1140   uint32_t fre_type = 0;
   1141   if (func_size < SFRAME_FRE_TYPE_ADDR1_LIMIT)
   1142     fre_type = SFRAME_FRE_TYPE_ADDR1;
   1143   else if (func_size < SFRAME_FRE_TYPE_ADDR2_LIMIT)
   1144     fre_type = SFRAME_FRE_TYPE_ADDR2;
   1145   /* Adjust the check a bit so that it remains warning-free but meaningful
   1146      on 32-bit systems.  */
   1147   else if (func_size <= (size_t) (SFRAME_FRE_TYPE_ADDR4_LIMIT - 1))
   1148     fre_type = SFRAME_FRE_TYPE_ADDR4;
   1149   return fre_type;
   1150 }
   1151 
   1152 /* Get the base reg id from the FRE info.  Set errp if failure.  */
   1153 
   1154 uint8_t
   1155 sframe_fre_get_base_reg_id (const sframe_frame_row_entry *fre, int *errp)
   1156 {
   1157   if (fre == NULL)
   1158     return sframe_set_errno (errp, SFRAME_ERR_FRE_INVAL);
   1159 
   1160   uint8_t fre_info = fre->fre_info;
   1161   return SFRAME_V1_FRE_CFA_BASE_REG_ID (fre_info);
   1162 }
   1163 
   1164 /* Get the CFA offset from the FRE.  If the offset is invalid, sets errp.  */
   1165 
   1166 int32_t
   1167 sframe_fre_get_cfa_offset (const sframe_decoder_ctx *dctx,
   1168 			   const sframe_frame_row_entry *fre,
   1169 			   uint32_t fde_type,
   1170 			   int *errp)
   1171 {
   1172   int err;
   1173   bool flex_p = (fde_type == SFRAME_FDE_TYPE_FLEX);
   1174   uint32_t idx = flex_p ? 1 : 0;
   1175   int32_t offset = sframe_get_fre_offset (fre, idx, &err);
   1176 
   1177   /* For s390x undo adjustment of CFA offset (to enable 8-bit offsets).  */
   1178   if (!err
   1179       && sframe_decoder_get_abi_arch (dctx) == SFRAME_ABI_S390X_ENDIAN_BIG)
   1180     offset = SFRAME_V2_S390X_CFA_OFFSET_DECODE (offset);
   1181 
   1182   if (errp)
   1183     *errp = err;
   1184   return offset;
   1185 }
   1186 
   1187 /* Get the FP offset from the FRE.  If the offset is invalid, sets errp.  */
   1188 
   1189 int32_t
   1190 sframe_fre_get_fp_offset (const sframe_decoder_ctx *dctx,
   1191 			  const sframe_frame_row_entry *fre,
   1192 			  uint32_t fde_type,
   1193 			  int *errp)
   1194 {
   1195   int fp_err = 0;
   1196   int8_t fixed_fp_offset = sframe_decoder_get_fixed_fp_offset (dctx);
   1197   bool flex_p = (fde_type == SFRAME_FDE_TYPE_FLEX);
   1198 
   1199   /* Initialize fp_offset_idx for default FDEs.  In some ABIs, the stack offset
   1200      to recover RA (using the CFA) from is fixed (like AMD64).  In such cases,
   1201      the stack offset to recover FP will appear at the second index.  */
   1202   uint32_t fp_offset_idx = ((sframe_decoder_get_fixed_ra_offset (dctx)
   1203 			     != SFRAME_CFA_FIXED_RA_INVALID)
   1204 			    ? SFRAME_FRE_RA_OFFSET_IDX
   1205 			    : SFRAME_FRE_FP_OFFSET_IDX);
   1206   if (flex_p)
   1207     {
   1208       uint32_t flex_ra_reg_data
   1209 	= sframe_get_fre_udata (fre, SFRAME_FRE_RA_OFFSET_IDX * 2, errp);
   1210       /* In presence of RA padding SFRAME_FRE_RA_OFFSET_INVALID (instead of RA
   1211 	 offsets), adjust the expected index of the FP offset.  */
   1212       if (errp && *errp == 0
   1213 	  && flex_ra_reg_data == SFRAME_FRE_RA_OFFSET_INVALID)
   1214 	fp_offset_idx = SFRAME_FRE_FP_OFFSET_IDX * 2;
   1215       else
   1216 	fp_offset_idx = SFRAME_FRE_FP_OFFSET_IDX * 2 + 1;
   1217     }
   1218 
   1219   /* NB: This errp must be retained if returning fp_offset.  */
   1220   int32_t fp_offset = sframe_get_fre_offset (fre, fp_offset_idx, &fp_err);
   1221 
   1222   /* If the FP offset is not being tracked, return the fixed FP offset from the
   1223      SFrame header:
   1224        - For default FDEs (!flex_p)
   1225        - For flex FDEs, if there were no FP offsets found.  */
   1226   if ((!flex_p || (flex_p && fp_err))
   1227       && fixed_fp_offset != SFRAME_CFA_FIXED_FP_INVALID
   1228       && !sframe_get_fre_ra_undefined_p (fre->fre_info))
   1229     {
   1230       if (errp)
   1231 	*errp = 0;
   1232       return fixed_fp_offset;
   1233     }
   1234 
   1235   if (errp)
   1236     *errp = fp_err;
   1237   return fp_offset;
   1238 }
   1239 
   1240 /* Get the RA offset from the FRE.  If the offset is invalid, sets errp.  */
   1241 
   1242 int32_t
   1243 sframe_fre_get_ra_offset (const sframe_decoder_ctx *dctx,
   1244 			  const sframe_frame_row_entry *fre,
   1245 			  uint32_t fde_type,
   1246 			  int *errp)
   1247 {
   1248   int ra_err = 0;
   1249   int8_t fixed_ra_offset = sframe_decoder_get_fixed_ra_offset (dctx);
   1250   bool flex_p = (fde_type == SFRAME_FDE_TYPE_FLEX);
   1251 
   1252   uint32_t ra_offset_idx = (flex_p
   1253 			    ? SFRAME_FRE_RA_OFFSET_IDX * 2 + 1
   1254 			    : SFRAME_FRE_RA_OFFSET_IDX);
   1255   /* NB: This errp must be retained if returning ra_offset.  */
   1256   int32_t ra_offset = sframe_get_fre_offset (fre, ra_offset_idx, &ra_err);
   1257 
   1258   /* For ABIs where RA offset is not being tracked, return the fixed RA offset
   1259      specified in the the SFrame header, when:
   1260        - for default FDEs (!flex_p)
   1261        - for flex FDEs, if RA offset is solely padding or not present.  */
   1262   if ((!flex_p || (flex_p && ra_err))
   1263       && fixed_ra_offset != SFRAME_CFA_FIXED_RA_INVALID
   1264       && !sframe_get_fre_ra_undefined_p (fre->fre_info))
   1265     {
   1266       if (errp)
   1267 	*errp = 0;
   1268       return fixed_ra_offset;
   1269     }
   1270 
   1271   /* Otherwise, return the RA offset from the FRE.  The corresponding errp was
   1272      set earlier.  */
   1273   if (errp)
   1274     *errp = ra_err;
   1275   return ra_offset;
   1276 }
   1277 
   1278 /* Get whether the RA is mangled.  */
   1279 
   1280 bool
   1281 sframe_fre_get_ra_mangled_p (const sframe_decoder_ctx *dctx ATTRIBUTE_UNUSED,
   1282 			     const sframe_frame_row_entry *fre, int *errp)
   1283 {
   1284   if (fre == NULL || !sframe_fre_sanity_check_p (fre))
   1285     return sframe_set_errno (errp, SFRAME_ERR_FRE_INVAL);
   1286 
   1287   return sframe_get_fre_ra_mangled_p (fre->fre_info);
   1288 }
   1289 
   1290 /* Get whether the RA is undefined (i.e. outermost frame).  */
   1291 
   1292 bool
   1293 sframe_fre_get_ra_undefined_p (const sframe_decoder_ctx *dctx ATTRIBUTE_UNUSED,
   1294 			       const sframe_frame_row_entry *fre, int *errp)
   1295 {
   1296   if (fre == NULL || !sframe_fre_sanity_check_p (fre))
   1297     return sframe_set_errno (errp, SFRAME_ERR_FRE_INVAL);
   1298 
   1299   return sframe_get_fre_ra_undefined_p (fre->fre_info);
   1300 }
   1301 
   1302 static int
   1303 sframe_frame_row_entry_copy (sframe_frame_row_entry *dst,
   1304 			     sframe_frame_row_entry *src)
   1305 {
   1306   int err = 0;
   1307 
   1308   if (dst == NULL || src == NULL)
   1309     return sframe_set_errno (&err, SFRAME_ERR_INVAL);
   1310 
   1311   memcpy (dst, src, sizeof (sframe_frame_row_entry));
   1312   return 0;
   1313 }
   1314 
   1315 /* Decode the SFrame FRE start address offset value from FRE_BUF in on-disk
   1316    binary format, given the FRE_TYPE.  Updates the FRE_START_ADDR.
   1317 
   1318    Returns 0 on success, SFRAME_ERR otherwise.  */
   1319 
   1320 static int
   1321 sframe_decode_fre_start_address (const void *fre_buf,
   1322 				 uint32_t *fre_start_addr,
   1323 				 uint32_t fre_type)
   1324 {
   1325   uint32_t saddr = 0;
   1326   int err = 0;
   1327 
   1328   if (fre_type == SFRAME_FRE_TYPE_ADDR1)
   1329     {
   1330       const uint8_t *uc = fre_buf;
   1331       saddr = *uc;
   1332     }
   1333   else if (fre_type == SFRAME_FRE_TYPE_ADDR2)
   1334     {
   1335       /* SFrame is an unaligned on-disk format.  See PR libsframe/29856.  */
   1336       const struct { uint16_t x; } ATTRIBUTE_PACKED *p = fre_buf;
   1337       saddr = p->x;
   1338     }
   1339   else if (fre_type == SFRAME_FRE_TYPE_ADDR4)
   1340     {
   1341       const struct { uint32_t x; } ATTRIBUTE_PACKED *p = fre_buf;
   1342       saddr = p->x;
   1343     }
   1344   else
   1345     sframe_set_errno (&err, SFRAME_ERR_INVAL);
   1346 
   1347   *fre_start_addr = saddr;
   1348   return err;
   1349 }
   1350 
   1351 /* Decode a frame row entry FRE which starts at location FRE_BUF.  The function
   1352    updates ESZ to the size of the FRE as stored in the binary format.
   1353 
   1354    This function works closely with the SFrame binary format.
   1355 
   1356    Returns SFRAME_ERR if failure.  */
   1357 
   1358 static int
   1359 sframe_decode_fre (const char *fre_buf, sframe_frame_row_entry *fre,
   1360 		   uint32_t fre_type, size_t *esz)
   1361 {
   1362   int err = 0;
   1363   const char *datawords = NULL;
   1364   size_t datawords_sz;
   1365   size_t addr_size;
   1366   size_t fre_size;
   1367 
   1368   if (fre_buf == NULL || fre == NULL || esz == NULL)
   1369     return sframe_set_errno (&err, SFRAME_ERR_INVAL);
   1370 
   1371   /* Copy over the FRE start address.  */
   1372   sframe_decode_fre_start_address (fre_buf, &fre->fre_start_addr, fre_type);
   1373 
   1374   addr_size = sframe_fre_start_addr_size (fre_type);
   1375   fre->fre_info = *(uint8_t *)(fre_buf + addr_size);
   1376   /* Sanity check as the API works closely with the binary format.  */
   1377   sframe_assert (sizeof (fre->fre_info) == sizeof (uint8_t));
   1378 
   1379   /* Cleanup the space for fre_datawords first, then copy over the valid
   1380      bytes.  */
   1381   memset (fre->fre_datawords, 0, MAX_DATAWORD_BYTES);
   1382   /* Get offsets size.  */
   1383   datawords_sz = sframe_fre_datawords_bytes_size (fre->fre_info);
   1384   datawords = fre_buf + addr_size + sizeof (fre->fre_info);
   1385   memcpy (fre->fre_datawords, datawords, datawords_sz);
   1386 
   1387   /* The FRE has been decoded.  Use it to perform one last sanity check.  */
   1388   fre_size = sframe_fre_entry_size (fre, fre_type);
   1389   sframe_assert (fre_size == (addr_size + sizeof (fre->fre_info)
   1390 			      + datawords_sz));
   1391   *esz = fre_size;
   1392 
   1393   return 0;
   1394 }
   1395 
   1396 /* Decode the specified SFrame buffer SF_BUF of size SF_SIZE and return the
   1397    new SFrame decoder context.
   1398 
   1399    Sets ERRP for the caller if any error.  Frees up the allocated memory in
   1400    case of error.  */
   1401 
   1402 sframe_decoder_ctx *
   1403 sframe_decode (const char *sf_buf, size_t sf_size, int *errp)
   1404 {
   1405   const sframe_preamble *sfp;
   1406   size_t hdrsz;
   1407   const sframe_header *dhp;
   1408   sframe_decoder_ctx *dctx;
   1409   char *frame_buf;
   1410   char *tempbuf = NULL;
   1411 
   1412   size_t fidx_size;
   1413   uint32_t fre_bytes;
   1414   int foreign_endian = 0;
   1415 
   1416   sframe_init_debug ();
   1417 
   1418   if ((sf_buf == NULL) || (!sf_size))
   1419     return sframe_ret_set_errno (errp, SFRAME_ERR_INVAL);
   1420   else if (sf_size < sizeof (sframe_header))
   1421     return sframe_ret_set_errno (errp, SFRAME_ERR_BUF_INVAL);
   1422 
   1423   sfp = (const sframe_preamble *) sf_buf;
   1424 
   1425   debug_printf ("sframe_decode: magic=0x%x version=%u flags=%u\n",
   1426 		sfp->sfp_magic, sfp->sfp_version, sfp->sfp_flags);
   1427 
   1428   /* Check for foreign endianness.  */
   1429   if (sfp->sfp_magic != SFRAME_MAGIC)
   1430     {
   1431       if (sfp->sfp_magic == bswap_16 (SFRAME_MAGIC))
   1432 	foreign_endian = 1;
   1433       else
   1434 	return sframe_ret_set_errno (errp, SFRAME_ERR_BUF_INVAL);
   1435     }
   1436 
   1437   /* Initialize a new decoder context.  */
   1438   if ((dctx = malloc (sizeof (sframe_decoder_ctx))) == NULL)
   1439     return sframe_ret_set_errno (errp, SFRAME_ERR_NOMEM);
   1440   memset (dctx, 0, sizeof (sframe_decoder_ctx));
   1441 
   1442   if (foreign_endian)
   1443     {
   1444       /* Allocate a new buffer and initialize it.  */
   1445       tempbuf = (char *) malloc (sf_size * sizeof (char));
   1446       if (tempbuf == NULL)
   1447 	return sframe_ret_set_errno (errp, SFRAME_ERR_NOMEM);
   1448       memcpy (tempbuf, sf_buf, sf_size);
   1449 
   1450       /* Flip the header first.  */
   1451       if (flip_header (tempbuf, sfp->sfp_version))
   1452 	{
   1453 	  sframe_ret_set_errno (errp, SFRAME_ERR_BUF_INVAL);
   1454 	  goto decode_fail_free;
   1455 	}
   1456       /* Flip the rest of the SFrame section data buffer.  */
   1457       if (flip_sframe (tempbuf, sf_size, 0))
   1458 	{
   1459 	  sframe_ret_set_errno (errp, SFRAME_ERR_BUF_INVAL);
   1460 	  goto decode_fail_free;
   1461 	}
   1462 
   1463       frame_buf = tempbuf;
   1464       /* This buffer is malloc'd when endian flipping the contents of the input
   1465 	 buffer are needed.  Keep a reference to it so it can be free'd up
   1466 	 later in sframe_decoder_free ().  */
   1467       dctx->sfd_buf = tempbuf;
   1468     }
   1469   else
   1470     frame_buf = (char *)sf_buf;
   1471 
   1472   /* Handle the SFrame header.  */
   1473   dctx->sfd_header = *(sframe_header *) frame_buf;
   1474   /* Validate the contents of SFrame header.  */
   1475   dhp = &dctx->sfd_header;
   1476   if (!sframe_header_sanity_check_p (dhp))
   1477     {
   1478       sframe_ret_set_errno (errp, SFRAME_ERR_BUF_INVAL);
   1479       goto decode_fail_free;
   1480     }
   1481   hdrsz = sframe_get_hdr_size (dhp);
   1482   frame_buf += hdrsz;
   1483 
   1484   /* Handle the SFrame Function Descriptor Entry section.  */
   1485   if (sframe_fde_tbl_alloc (&dctx->sfd_funcdesc, dhp->sfh_num_fdes))
   1486     {
   1487       sframe_ret_set_errno (errp, SFRAME_ERR_NOMEM);
   1488       goto decode_fail_free;
   1489     }
   1490 
   1491   /* SFrame FDEs are at an offset of sfh_fdeoff from SFrame header end.  */
   1492   if (sframe_fde_tbl_init (dctx->sfd_funcdesc, frame_buf + dhp->sfh_fdeoff,
   1493 			   frame_buf + dhp->sfh_freoff,
   1494 			   &fidx_size, dhp->sfh_num_fdes, sfp->sfp_version))
   1495     {
   1496       sframe_ret_set_errno (errp, SFRAME_ERR_BUF_INVAL);
   1497       goto decode_fail_free;
   1498     }
   1499 
   1500   debug_printf ("%zu total fidx size\n", fidx_size);
   1501 
   1502   /* Handle the SFrame Frame Row Entry section.  */
   1503   dctx->sfd_fres = (char *) malloc (dhp->sfh_fre_len);
   1504   if (dctx->sfd_fres == NULL)
   1505     {
   1506       sframe_ret_set_errno (errp, SFRAME_ERR_NOMEM);
   1507       goto decode_fail_free;
   1508     }
   1509   /* SFrame FREs are at an offset of sfh_freoff from SFrame header end.  */
   1510   memcpy (dctx->sfd_fres, frame_buf + dhp->sfh_freoff, dhp->sfh_fre_len);
   1511 
   1512   fre_bytes = dhp->sfh_fre_len;
   1513   dctx->sfd_fre_nbytes = fre_bytes;
   1514 
   1515   debug_printf ("%u total fre bytes\n", fre_bytes);
   1516 
   1517   return dctx;
   1518 
   1519 decode_fail_free:
   1520   if (foreign_endian && tempbuf != NULL)
   1521     free (tempbuf);
   1522   sframe_decoder_free (&dctx);
   1523   dctx = NULL;
   1524   return dctx;
   1525 }
   1526 
   1527 /* Get the size of the SFrame header from the decoder context CTX.  */
   1528 
   1529 unsigned int
   1530 sframe_decoder_get_hdr_size (const sframe_decoder_ctx *ctx)
   1531 {
   1532   const sframe_header *dhp = sframe_decoder_get_header (ctx);
   1533   return sframe_get_hdr_size (dhp);
   1534 }
   1535 
   1536 /* Get the SFrame's abi/arch info given the decoder context DCTX.  */
   1537 
   1538 uint8_t
   1539 sframe_decoder_get_abi_arch (const sframe_decoder_ctx *dctx)
   1540 {
   1541   const sframe_header *dhp = sframe_decoder_get_header (dctx);
   1542   return dhp->sfh_abi_arch;
   1543 }
   1544 
   1545 /* Get the format version from the SFrame decoder context DCTX.  */
   1546 
   1547 uint8_t
   1548 sframe_decoder_get_version (const sframe_decoder_ctx *dctx)
   1549 {
   1550   const sframe_header *dhp = sframe_decoder_get_header (dctx);
   1551   return dhp->sfh_preamble.sfp_version;
   1552 }
   1553 
   1554 /* Get the section flags from the SFrame decoder context DCTX.  */
   1555 
   1556 uint8_t
   1557 sframe_decoder_get_flags (const sframe_decoder_ctx *dctx)
   1558 {
   1559   const sframe_header *dhp = sframe_decoder_get_header (dctx);
   1560   return dhp->sfh_preamble.sfp_flags;
   1561 }
   1562 
   1563 /* Get the SFrame's fixed FP offset given the decoder context CTX.  */
   1564 int8_t
   1565 sframe_decoder_get_fixed_fp_offset (const sframe_decoder_ctx *ctx)
   1566 {
   1567   const sframe_header *dhp = sframe_decoder_get_header (ctx);
   1568   return dhp->sfh_cfa_fixed_fp_offset;
   1569 }
   1570 
   1571 /* Get the SFrame's fixed RA offset given the decoder context CTX.  */
   1572 int8_t
   1573 sframe_decoder_get_fixed_ra_offset (const sframe_decoder_ctx *ctx)
   1574 {
   1575   const sframe_header *dhp = sframe_decoder_get_header (ctx);
   1576   return dhp->sfh_cfa_fixed_ra_offset;
   1577 }
   1578 
   1579 /* Get the offset of the sfde_func_start_address field (from the start of the
   1580    on-disk layout of the SFrame section) of the FDE at FUNC_IDX in the decoder
   1581    context DCTX.
   1582 
   1583    If FUNC_IDX is more than the number of SFrame FDEs in the section, sets
   1584    error code in ERRP, but returns the (hypothetical) offset.  This is useful
   1585    for the linker when arranging input FDEs into the output section to be
   1586    emitted.  */
   1587 
   1588 uint32_t
   1589 sframe_decoder_get_offsetof_fde_start_addr (const sframe_decoder_ctx *dctx,
   1590 					    uint32_t func_idx, int *errp)
   1591 {
   1592   if (func_idx >= sframe_decoder_get_num_fidx (dctx))
   1593     sframe_ret_set_errno (errp, SFRAME_ERR_FDE_NOTFOUND);
   1594   else if (errp)
   1595     *errp = 0;
   1596 
   1597   if (sframe_decoder_get_version (dctx) == SFRAME_VERSION_3)
   1598     return (sframe_decoder_get_hdr_size (dctx)
   1599 	    + func_idx * sizeof (sframe_func_desc_idx_v3)
   1600 	    + offsetof (sframe_func_desc_idx_v3, sfdi_func_start_offset));
   1601   else if (sframe_decoder_get_version (dctx) == SFRAME_VERSION_2)
   1602     return (sframe_decoder_get_hdr_size (dctx)
   1603 	    + func_idx * sizeof (sframe_func_desc_entry_v2)
   1604 	    + offsetof (sframe_func_desc_entry_v2, sfde_func_start_address));
   1605   else
   1606     sframe_ret_set_errno (errp, SFRAME_ERR_INVAL);
   1607 
   1608   return 0;
   1609 }
   1610 
   1611 /* Find the function descriptor entry starting which contains the specified
   1612    address ADDR.  */
   1613 
   1614 static sframe_func_desc_entry_int *
   1615 sframe_get_funcdesc_with_addr_internal (const sframe_decoder_ctx *ctx,
   1616 					int64_t addr, int *errp,
   1617 					uint32_t *func_idx)
   1618 {
   1619   sframe_func_desc_entry_int *fdp;
   1620   int low, high;
   1621 
   1622   if (ctx == NULL)
   1623     return sframe_ret_set_errno (errp, SFRAME_ERR_INVAL);
   1624 
   1625   const sframe_header *dhp = sframe_decoder_get_header (ctx);
   1626 
   1627   if (dhp == NULL || dhp->sfh_num_fdes == 0 || ctx->sfd_funcdesc == NULL)
   1628     return sframe_ret_set_errno (errp, SFRAME_ERR_DCTX_INVAL);
   1629   /* If the FDE sub-section is not sorted on PCs, skip the lookup because
   1630      binary search cannot be used.  */
   1631   if ((sframe_decoder_get_flags (ctx) & SFRAME_F_FDE_SORTED) == 0)
   1632     return sframe_ret_set_errno (errp, SFRAME_ERR_FDE_NOTSORTED);
   1633 
   1634   /* Do the binary search.  */
   1635   fdp = (sframe_func_desc_entry_int *) ctx->sfd_funcdesc->entry;
   1636   low = 0;
   1637   high = dhp->sfh_num_fdes - 1;
   1638   while (low <= high)
   1639     {
   1640       int mid = low + (high - low) / 2;
   1641 
   1642       /* Given func_start_addr <= addr,
   1643 	 addr - func_start_addr must be positive.  */
   1644       if (sframe_decoder_get_secrel_func_start_addr (ctx, mid) <= addr
   1645 	  && ((uint32_t)(addr - sframe_decoder_get_secrel_func_start_addr (ctx,
   1646 									   mid))
   1647 	      < fdp[mid].func_size))
   1648 	{
   1649 	  *func_idx = mid;
   1650 	  return fdp + mid;
   1651 	}
   1652 
   1653       if (sframe_decoder_get_secrel_func_start_addr (ctx, mid) < addr)
   1654 	low = mid + 1;
   1655       else
   1656 	high = mid - 1;
   1657     }
   1658 
   1659   return sframe_ret_set_errno (errp, SFRAME_ERR_FDE_NOTFOUND);
   1660 }
   1661 
   1662 /* Get the end IP offset for the FRE at index i in the FDEP.  The buffer FRES
   1663    is the starting location for the FRE.  */
   1664 
   1665 static uint32_t
   1666 sframe_fre_get_end_ip_offset (sframe_func_desc_entry_int *fdep, unsigned int i,
   1667 			      const char *fres)
   1668 {
   1669   uint32_t end_ip_offset;
   1670   uint32_t fre_type;
   1671 
   1672   fre_type = sframe_get_fre_type (fdep);
   1673 
   1674   /* Get the start address of the next FRE in sequence.  */
   1675   if (i < fdep->func_num_fres - 1)
   1676     {
   1677       sframe_decode_fre_start_address (fres, &end_ip_offset, fre_type);
   1678       end_ip_offset -= 1;
   1679     }
   1680   else
   1681     /* The end IP offset for the FRE needs to be deduced from the function
   1682        size.  */
   1683     end_ip_offset = fdep->func_size - 1;
   1684 
   1685   return end_ip_offset;
   1686 }
   1687 
   1688 /* Find the SFrame Row Entry which contains the PC.  Returns
   1689    SFRAME_ERR if failure.  */
   1690 
   1691 int
   1692 sframe_find_fre (const sframe_decoder_ctx *ctx, int64_t pc,
   1693 		 sframe_frame_row_entry *frep)
   1694 {
   1695   sframe_frame_row_entry cur_fre;
   1696   sframe_func_desc_entry_int *fdep;
   1697   uint32_t func_idx;
   1698   uint32_t fre_type, i;
   1699   int64_t func_start_pc_offset;
   1700   uint32_t start_ip_offset, end_ip_offset;
   1701   const char *fres;
   1702   size_t size = 0;
   1703   int err = 0;
   1704 
   1705   if ((ctx == NULL) || (frep == NULL))
   1706     return sframe_set_errno (&err, SFRAME_ERR_INVAL);
   1707 
   1708   uint8_t ver = sframe_decoder_get_version (ctx);
   1709   /* Find the FDE which contains the PC, then scan its fre entries.  */
   1710   fdep = sframe_get_funcdesc_with_addr_internal (ctx, pc, &err, &func_idx);
   1711   if (fdep == NULL || ctx->sfd_fres == NULL)
   1712     return sframe_set_errno (&err, SFRAME_ERR_DCTX_INVAL);
   1713 
   1714   fre_type = sframe_get_fre_type (fdep);
   1715 
   1716   fres = ctx->sfd_fres + fdep->func_start_fre_off;
   1717   if (ver == SFRAME_VERSION_3)
   1718     fres += sizeof (sframe_func_desc_attr_v3);
   1719   func_start_pc_offset = sframe_decoder_get_secrel_func_start_addr (ctx,
   1720 								    func_idx);
   1721 
   1722   for (i = 0; i < fdep->func_num_fres; i++)
   1723    {
   1724      err = sframe_decode_fre (fres, &cur_fre, fre_type, &size);
   1725      if (err)
   1726        return sframe_set_errno (&err, SFRAME_ERR_FRE_INVAL);
   1727 
   1728      start_ip_offset = cur_fre.fre_start_addr;
   1729      end_ip_offset = sframe_fre_get_end_ip_offset (fdep, i, fres + size);
   1730 
   1731      /* Stop search if FRE's start_ip is greater than pc.  Given
   1732 	func_start_addr <= pc, pc - func_start_addr must be positive.  */
   1733      if (start_ip_offset > (uint32_t)(pc - func_start_pc_offset))
   1734        return sframe_set_errno (&err, SFRAME_ERR_FRE_INVAL);
   1735 
   1736      if (sframe_fre_check_range_p (ctx, func_idx, start_ip_offset,
   1737 				   end_ip_offset, pc))
   1738        {
   1739 	 sframe_frame_row_entry_copy (frep, &cur_fre);
   1740 	 return 0;
   1741        }
   1742      fres += size;
   1743    }
   1744   return sframe_set_errno (&err, SFRAME_ERR_FDE_INVAL);
   1745 }
   1746 
   1747 /* Return the number of function descriptor entries in the SFrame decoder
   1748    DCTX.  */
   1749 
   1750 uint32_t
   1751 sframe_decoder_get_num_fidx (const sframe_decoder_ctx *ctx)
   1752 {
   1753   uint32_t num_fdes = 0;
   1754   const sframe_header *dhp = sframe_decoder_get_header (ctx);
   1755   if (dhp)
   1756     num_fdes = dhp->sfh_num_fdes;
   1757   return num_fdes;
   1758 }
   1759 
   1760 int
   1761 sframe_decoder_get_funcdesc_v2 (const sframe_decoder_ctx *dctx,
   1762 				unsigned int i,
   1763 				uint32_t *num_fres,
   1764 				uint32_t *func_size,
   1765 				int32_t *func_start_address,
   1766 				unsigned char *func_info,
   1767 				uint8_t *rep_block_size)
   1768 {
   1769   sframe_func_desc_entry_int *fdp;
   1770   int err = 0;
   1771 
   1772   if (dctx == NULL || func_start_address == NULL
   1773       || num_fres == NULL || func_size == NULL
   1774       || sframe_decoder_get_version (dctx) == SFRAME_VERSION_1)
   1775     return sframe_set_errno (&err, SFRAME_ERR_INVAL);
   1776 
   1777   fdp = sframe_decoder_get_funcdesc_at_index (dctx, i);
   1778 
   1779   if (fdp == NULL)
   1780     return sframe_set_errno (&err, SFRAME_ERR_FDE_NOTFOUND);
   1781 
   1782   *num_fres = fdp->func_num_fres;
   1783   *func_start_address = (int32_t) fdp->func_start_pc_offset;
   1784   *func_size = fdp->func_size;
   1785   *func_info = fdp->func_info;
   1786   *rep_block_size = fdp->func_rep_size;
   1787 
   1788   return 0;
   1789 }
   1790 
   1791 /* Get the data (NUM_FRES, FUNC_SIZE, START_PC_OFFSET, FUNC_INFO,
   1792    REP_BLOCK_SIZE) from the SFrame function descriptor entry at the I'th index
   1793    in the decoder object DCTX.  Return SFRAME_ERR on failure.  */
   1794 
   1795 int
   1796 sframe_decoder_get_funcdesc_v3 (const sframe_decoder_ctx *dctx,
   1797 				unsigned int i,
   1798 				uint32_t *num_fres,
   1799 				uint32_t *func_size,
   1800 				int64_t *start_pc_offset,
   1801 				unsigned char *func_info,
   1802 				unsigned char *func_info2,
   1803 				uint8_t *rep_block_size)
   1804 {
   1805   int err = 0;
   1806   if (dctx == NULL || sframe_decoder_get_version (dctx) != SFRAME_VERSION_3)
   1807     return sframe_set_errno (&err, SFRAME_ERR_INVAL);
   1808 
   1809   sframe_func_desc_entry_int *fdp
   1810     = sframe_decoder_get_funcdesc_at_index (dctx, i);
   1811   if (fdp == NULL)
   1812     return sframe_set_errno (&err, SFRAME_ERR_FDE_NOTFOUND);
   1813 
   1814   if (num_fres)
   1815     *num_fres = fdp->func_num_fres;
   1816   if (start_pc_offset)
   1817     *start_pc_offset = fdp->func_start_pc_offset;
   1818   if (func_size)
   1819     *func_size = fdp->func_size;
   1820   if (func_info)
   1821     *func_info = fdp->func_info;
   1822   if (func_info2)
   1823     *func_info2 = fdp->func_info2;
   1824   if (rep_block_size)
   1825     *rep_block_size = fdp->func_rep_size;
   1826 
   1827   return 0;
   1828 }
   1829 
   1830 /* Get the FRE_IDX'th FRE of the function at FUNC_IDX'th function
   1831    descriptor entry in the SFrame decoder CTX.  Returns error code as
   1832    applicable.  */
   1833 
   1834 int
   1835 sframe_decoder_get_fre (const sframe_decoder_ctx *ctx,
   1836 			unsigned int func_idx,
   1837 			unsigned int fre_idx,
   1838 			sframe_frame_row_entry *fre)
   1839 {
   1840   sframe_func_desc_entry_int *fdep;
   1841   sframe_frame_row_entry ifre;
   1842   const char *fres;
   1843   uint32_t i;
   1844   uint32_t fre_type;
   1845   size_t esz = 0;
   1846   int err = 0;
   1847 
   1848   if (ctx == NULL || fre == NULL)
   1849     return sframe_set_errno (&err, SFRAME_ERR_INVAL);
   1850 
   1851   uint8_t ver = sframe_decoder_get_version (ctx);
   1852 
   1853   /* Get function descriptor entry at index func_idx.  */
   1854   fdep = sframe_decoder_get_funcdesc_at_index (ctx, func_idx);
   1855   if (fdep == NULL)
   1856     return sframe_set_errno (&err, SFRAME_ERR_FDE_NOTFOUND);
   1857 
   1858   fre_type = sframe_get_fre_type (fdep);
   1859   /* Now scan the FRE entries.  */
   1860   fres = ctx->sfd_fres + fdep->func_start_fre_off;
   1861   if (ver == SFRAME_VERSION_3)
   1862     fres += sizeof (sframe_func_desc_attr_v3);
   1863 
   1864   for (i = 0; i < fdep->func_num_fres; i++)
   1865    {
   1866      /* Decode the FRE at the current position.  Return it if valid.  */
   1867      err = sframe_decode_fre (fres, &ifre, fre_type, &esz);
   1868      if (i == fre_idx)
   1869        {
   1870 	 if (!sframe_fre_sanity_check_p (&ifre))
   1871 	   return sframe_set_errno (&err, SFRAME_ERR_FRE_INVAL);
   1872 
   1873 	  /* Although a stricter sanity check on fre_start_addr like:
   1874 	       if (fdep->func_size)
   1875 		 sframe_assert (frep->fre_start_addr < fdep->func_size);
   1876 	     is more suitable, some code has been seen to not abide by it.  See
   1877 	     PR libsframe/33131.  */
   1878 	  sframe_assert (ifre.fre_start_addr <= fdep->func_size);
   1879 
   1880 	 sframe_frame_row_entry_copy (fre, &ifre);
   1881 
   1882 	 return 0;
   1883        }
   1884      /* Next FRE.  */
   1885      fres += esz;
   1886    }
   1887 
   1888   return sframe_set_errno (&err, SFRAME_ERR_FDE_NOTFOUND);
   1889 }
   1890 
   1891 /* Get the SFrame FRE data of the function at FUNC_IDX'th function index entry
   1892    in the SFrame decoder DCTX.  The reference to the buffer is returned in
   1893    FRES_BUF with FRES_BUF_SIZE indicating the size of the buffer.  The number
   1894    of FREs in the buffer are NUM_FRES.  In SFrame V3, this buffer also contains
   1895    the FDE attr data before the actual SFrame FREs.  Returns SFRAME_ERR in case
   1896    of error.  */
   1897 
   1898 int
   1899 sframe_decoder_get_fres_buf (const sframe_decoder_ctx *dctx,
   1900 			     const uint32_t func_idx,
   1901 			     char **fres_buf,
   1902 			     size_t *fres_buf_size,
   1903 			     uint32_t *num_fres)
   1904 {
   1905   sframe_func_desc_entry_int *fdep;
   1906   uint32_t i = 0;
   1907   uint32_t fre_type;
   1908   size_t esz;
   1909   int err = 0;
   1910 
   1911   if (dctx == NULL || fres_buf == NULL)
   1912     return sframe_set_errno (&err, SFRAME_ERR_INVAL);
   1913 
   1914   /* Get function descriptor entry at index func_idx.  */
   1915   fdep = sframe_decoder_get_funcdesc_at_index (dctx, func_idx);
   1916   *num_fres = fdep->func_num_fres;
   1917 
   1918   if (fdep == NULL)
   1919     return sframe_set_errno (&err, SFRAME_ERR_FDE_NOTFOUND);
   1920 
   1921   fre_type = sframe_get_fre_type (fdep);
   1922   /* Update the pointer to (and total size of) the FRE entries.  */
   1923   *fres_buf = dctx->sfd_fres + fdep->func_start_fre_off;
   1924   const char *tmp_buf = *fres_buf + sizeof (sframe_func_desc_attr_v3);
   1925   *fres_buf_size = sizeof (sframe_func_desc_attr_v3);
   1926   while (i < *num_fres)
   1927     {
   1928       /* Avoid cost of full decoding at this time.  */
   1929       esz = sframe_buf_fre_entry_size (tmp_buf, fre_type);
   1930       tmp_buf += esz;
   1931       *fres_buf_size += esz;
   1932       i++;
   1933     }
   1934 
   1935   return 0;
   1936 }
   1937 
   1938 
   1939 /* SFrame Encoder.  */
   1940 
   1941 /* Get a reference to the SFrame header, given the encoder context ECTX.  */
   1942 
   1943 static sframe_header *
   1944 sframe_encoder_get_header (sframe_encoder_ctx *ectx)
   1945 {
   1946   sframe_header *hp = NULL;
   1947   if (ectx)
   1948     hp = &ectx->sfe_header;
   1949   return hp;
   1950 }
   1951 
   1952 static sframe_func_desc_entry_int *
   1953 sframe_encoder_get_funcdesc_at_index (sframe_encoder_ctx *ectx,
   1954 				      uint32_t func_idx)
   1955 {
   1956   sframe_func_desc_entry_int *fde = NULL;
   1957   if (func_idx < sframe_encoder_get_num_fidx (ectx))
   1958     {
   1959       sf_fde_tbl *func_tbl = ectx->sfe_funcdesc;
   1960       fde = func_tbl->entry + func_idx;
   1961     }
   1962   return fde;
   1963 }
   1964 
   1965 /* Create an encoder context with the given SFrame format version VER, FLAGS
   1966    and ABI information.  Uses the ABI specific FIXED_FP_OFFSET and
   1967    FIXED_RA_OFFSET values as provided.  Sets errp if failure.  */
   1968 
   1969 sframe_encoder_ctx *
   1970 sframe_encode (uint8_t ver, uint8_t flags, uint8_t abi_arch,
   1971 	       int8_t fixed_fp_offset, int8_t fixed_ra_offset, int *errp)
   1972 {
   1973   sframe_header *hp;
   1974   sframe_encoder_ctx *ectx;
   1975 
   1976   if (ver != SFRAME_VERSION)
   1977     return sframe_ret_set_errno (errp, SFRAME_ERR_VERSION_INVAL);
   1978 
   1979   if ((ectx = malloc (sizeof (sframe_encoder_ctx))) == NULL)
   1980     return sframe_ret_set_errno (errp, SFRAME_ERR_NOMEM);
   1981 
   1982   memset (ectx, 0, sizeof (sframe_encoder_ctx));
   1983 
   1984   /* Get the SFrame header and update it.  */
   1985   hp = sframe_encoder_get_header (ectx);
   1986   hp->sfh_preamble.sfp_version = ver;
   1987   hp->sfh_preamble.sfp_magic = SFRAME_MAGIC;
   1988   hp->sfh_preamble.sfp_flags = flags;
   1989 
   1990   /* Implementation in the SFrame encoder APIs, e.g.,
   1991      sframe_encoder_write_sframe assume flag SFRAME_F_FDE_FUNC_START_PCREL
   1992      set.  */
   1993   if (!(flags & SFRAME_F_FDE_FUNC_START_PCREL))
   1994    return sframe_ret_set_errno (errp, SFRAME_ERR_ECTX_INVAL);
   1995 
   1996   hp->sfh_abi_arch = abi_arch;
   1997   hp->sfh_cfa_fixed_fp_offset = fixed_fp_offset;
   1998   hp->sfh_cfa_fixed_ra_offset = fixed_ra_offset;
   1999 
   2000   return ectx;
   2001 }
   2002 
   2003 /* Free the encoder context ECTXP.  */
   2004 
   2005 void
   2006 sframe_encoder_free (sframe_encoder_ctx **ectxp)
   2007 {
   2008   if (ectxp != NULL)
   2009     {
   2010       sframe_encoder_ctx *ectx = *ectxp;
   2011       if (ectx == NULL)
   2012 	return;
   2013 
   2014       if (ectx->sfe_funcdesc != NULL)
   2015 	{
   2016 	  free (ectx->sfe_funcdesc);
   2017 	  ectx->sfe_funcdesc = NULL;
   2018 	}
   2019       if (ectx->sfe_fres != NULL)
   2020 	{
   2021 	  free (ectx->sfe_fres);
   2022 	  ectx->sfe_fres = NULL;
   2023 	}
   2024       if (ectx->sfe_data != NULL)
   2025 	{
   2026 	  free (ectx->sfe_data);
   2027 	  ectx->sfe_data = NULL;
   2028 	}
   2029 
   2030       free (*ectxp);
   2031       *ectxp = NULL;
   2032     }
   2033 }
   2034 
   2035 /* Get the size of the SFrame header from the encoder context ECTX.  */
   2036 
   2037 unsigned int
   2038 sframe_encoder_get_hdr_size (sframe_encoder_ctx *ectx)
   2039 {
   2040   const sframe_header *ehp = sframe_encoder_get_header (ectx);
   2041   return sframe_get_hdr_size (ehp);
   2042 }
   2043 
   2044 /* Get the SFrame abi/arch info from the encoder context ECTX.  */
   2045 
   2046 uint8_t
   2047 sframe_encoder_get_abi_arch (sframe_encoder_ctx *ectx)
   2048 {
   2049   uint8_t abi_arch = 0;
   2050   const sframe_header *ehp = sframe_encoder_get_header (ectx);
   2051   if (ehp)
   2052     abi_arch = ehp->sfh_abi_arch;
   2053   return abi_arch;
   2054 }
   2055 
   2056 /* Get the SFrame format version from the encoder context ECTX.  */
   2057 
   2058 uint8_t
   2059 sframe_encoder_get_version (sframe_encoder_ctx *ectx)
   2060 {
   2061   const sframe_header *ehp = sframe_encoder_get_header (ectx);
   2062   return ehp->sfh_preamble.sfp_version;
   2063 }
   2064 
   2065 /* Get the SFrame flags from the encoder context ECTX.  */
   2066 
   2067 uint8_t
   2068 sframe_encoder_get_flags (sframe_encoder_ctx *ectx)
   2069 {
   2070   const sframe_header *ehp = sframe_encoder_get_header (ectx);
   2071   return ehp->sfh_preamble.sfp_flags;
   2072 }
   2073 
   2074 /* Return the number of SFrame function descriptor entries in the encoder
   2075    context ECTX.  */
   2076 
   2077 uint32_t
   2078 sframe_encoder_get_num_fidx (sframe_encoder_ctx *ectx)
   2079 {
   2080   uint32_t num_fdes = 0;
   2081   const sframe_header *ehp = sframe_encoder_get_header (ectx);
   2082   if (ehp)
   2083     num_fdes = ehp->sfh_num_fdes;
   2084   return num_fdes;
   2085 }
   2086 
   2087 /* Get the offset of the sfde_func_start_address field (from the start of the
   2088    on-disk layout of the SFrame section) of the FDE at FUNC_IDX in the encoder
   2089    context ECTX.
   2090 
   2091    If FUNC_IDX is more than the number of SFrame FDEs in the section, sets
   2092    error code in ERRP, but returns the (hypothetical) offset.  This is useful
   2093    for the linker when arranging input FDEs into the output section to be
   2094    emitted.  */
   2095 
   2096 uint32_t
   2097 sframe_encoder_get_offsetof_fde_start_addr (sframe_encoder_ctx *ectx,
   2098 					    uint32_t func_idx, int *errp)
   2099 {
   2100   if (func_idx >= sframe_encoder_get_num_fidx (ectx))
   2101     sframe_ret_set_errno (errp, SFRAME_ERR_FDE_INVAL);
   2102   else if (errp)
   2103     *errp = 0;
   2104 
   2105   return (sframe_encoder_get_hdr_size (ectx)
   2106 	  + func_idx * sizeof (sframe_func_desc_idx_v3)
   2107 	  + offsetof (sframe_func_desc_idx_v3, sfdi_func_start_offset));
   2108 }
   2109 
   2110 /* Add an SFrame FRE to function at FUNC_IDX'th function descriptor entry in
   2111    the encoder context ECTX.  */
   2112 
   2113 int
   2114 sframe_encoder_add_fre (sframe_encoder_ctx *ectx,
   2115 			unsigned int func_idx,
   2116 			sframe_frame_row_entry *frep)
   2117 {
   2118   sframe_header *ehp;
   2119   sframe_func_desc_entry_int *fdep;
   2120   sframe_frame_row_entry *ectx_frep;
   2121   size_t datawords_sz, esz;
   2122   uint32_t fre_type;
   2123   int err = 0;
   2124 
   2125   if (ectx == NULL || frep == NULL)
   2126     return sframe_set_errno (&err, SFRAME_ERR_INVAL);
   2127   if (!sframe_fre_sanity_check_p (frep))
   2128     return sframe_set_errno (&err, SFRAME_ERR_FRE_INVAL);
   2129 
   2130   /* Use func_idx to gather the function descriptor entry.  */
   2131   fdep = sframe_encoder_get_funcdesc_at_index (ectx, func_idx);
   2132 
   2133   if (fdep == NULL)
   2134     return sframe_set_errno (&err, SFRAME_ERR_FDE_NOTFOUND);
   2135 
   2136   fre_type = sframe_get_fre_type (fdep);
   2137   sf_fre_tbl *fre_tbl = ectx->sfe_fres;
   2138 
   2139   if (fre_tbl == NULL || fre_tbl->count == fre_tbl->alloced)
   2140     {
   2141       sf_fre_tbl *tmp = sframe_grow_fre_tbl (fre_tbl, 1, &err);
   2142       if (err)
   2143 	{
   2144 	  sframe_set_errno (&err, SFRAME_ERR_NOMEM);
   2145 	  goto bad;
   2146 	}
   2147       fre_tbl = tmp;
   2148     }
   2149 
   2150   ectx_frep = &fre_tbl->entry[fre_tbl->count];
   2151   ectx_frep->fre_start_addr
   2152     = frep->fre_start_addr;
   2153   ectx_frep->fre_info = frep->fre_info;
   2154 
   2155   /* Although a stricter sanity check on fre_start_addr like:
   2156        if (fdep->func_size)
   2157 	 sframe_assert (frep->fre_start_addr < fdep->func_size);
   2158      is more suitable, some code has been seen to not abide by it.  See PR
   2159      libsframe/33131.  */
   2160   sframe_assert (frep->fre_start_addr <= fdep->func_size);
   2161 
   2162   /* frep has already been sanity check'd.  Get offsets size.  */
   2163   datawords_sz = sframe_fre_datawords_bytes_size (frep->fre_info);
   2164   memcpy (&ectx_frep->fre_datawords, &frep->fre_datawords, datawords_sz);
   2165 
   2166   esz = sframe_fre_entry_size (frep, fre_type);
   2167   fre_tbl->count++;
   2168 
   2169   ectx->sfe_fres = fre_tbl;
   2170   ectx->sfe_fre_nbytes += esz;
   2171 
   2172   if (!fdep->func_num_fres)
   2173     ectx->sfe_fre_nbytes += sizeof (sframe_func_desc_attr_v3);
   2174 
   2175   ehp = sframe_encoder_get_header (ectx);
   2176   ehp->sfh_num_fres = fre_tbl->count;
   2177 
   2178   /* Update the value of the number of FREs for the function.  */
   2179   fdep->func_num_fres++;
   2180 
   2181   return 0;
   2182 
   2183 bad:
   2184   if (fre_tbl != NULL)
   2185     free (fre_tbl);
   2186   ectx->sfe_fres = NULL;
   2187   ectx->sfe_fre_nbytes = 0;
   2188   return -1;
   2189 }
   2190 
   2191 /* Add SFrame FRE data given in the buffer FRES_BUF of size FRES_BUF_SIZE (for
   2192    function at index FUNC_IDX) to the encoder context ECTX.  The number of FREs
   2193    in the buffer are NUM_FRES.  Returns SFRAME_ERR if failure.  */
   2194 
   2195 int
   2196 sframe_encoder_add_fres_buf (sframe_encoder_ctx *ectx,
   2197 			     unsigned int func_idx,
   2198 			     uint32_t num_fres,
   2199 			     const char *fres_buf,
   2200 			     size_t fres_buf_size)
   2201 {
   2202   sframe_frame_row_entry *ectx_frep;
   2203   size_t esz = 0;
   2204 
   2205   int err = 0;
   2206   if (ectx == NULL || ((fres_buf == NULL) != (fres_buf_size == 0)))
   2207     return sframe_set_errno (&err, SFRAME_ERR_INVAL);
   2208 
   2209   /* Use func_idx to gather the function descriptor entry.  */
   2210   sframe_func_desc_entry_int *fdep
   2211     = sframe_encoder_get_funcdesc_at_index (ectx, func_idx);
   2212   if (fdep == NULL)
   2213     return sframe_set_errno (&err, SFRAME_ERR_FDE_NOTFOUND);
   2214 
   2215   sf_fre_tbl *fre_tbl = ectx->sfe_fres;
   2216   if (fre_tbl == NULL || fre_tbl->count + num_fres >= fre_tbl->alloced)
   2217     {
   2218       sf_fre_tbl *tmp = sframe_grow_fre_tbl (fre_tbl, num_fres, &err);
   2219       if (err)
   2220 	{
   2221 	  sframe_set_errno (&err, SFRAME_ERR_NOMEM);
   2222 	  goto bad;		/* OOM.  */
   2223 	}
   2224       fre_tbl = tmp;
   2225     }
   2226 
   2227   /* Update the SFrame func attr values.  */
   2228   fdep->func_num_fres = num_fres;
   2229   const char *fres = fres_buf + sizeof (uint16_t);
   2230   fdep->func_info = *(uint8_t *)fres;
   2231   fres += sizeof (uint8_t);
   2232   fdep->func_info2 = *(uint8_t *)fres;
   2233   fres += sizeof (uint8_t);
   2234   fdep->func_rep_size = *(uint8_t *)fres;
   2235   fres += sizeof (uint8_t);
   2236 
   2237   uint32_t fre_type = sframe_get_fre_type (fdep);
   2238   uint32_t remaining = num_fres;
   2239   size_t buf_size = sizeof (sframe_func_desc_attr_v3);
   2240   while (remaining)
   2241     {
   2242       ectx_frep = &fre_tbl->entry[fre_tbl->count];
   2243       /* Copy the SFrame FRE data over to the encoder object's fre_tbl.  */
   2244       sframe_decode_fre (fres, ectx_frep, fre_type, &esz);
   2245 
   2246       if (!sframe_fre_sanity_check_p (ectx_frep))
   2247 	return sframe_set_errno (&err, SFRAME_ERR_FRE_INVAL);
   2248 
   2249       /* Although a stricter sanity check on fre_start_addr like:
   2250 	   if (fdep->func_size)
   2251 	     sframe_assert (frep->fre_start_addr < fdep->func_size);
   2252 	 is more suitable, some code has been seen to not abide by it.  See PR
   2253 	 libsframe/33131.  */
   2254       sframe_assert (ectx_frep->fre_start_addr <= fdep->func_size);
   2255 
   2256       fre_tbl->count++;
   2257       fres += esz;
   2258       buf_size += esz;
   2259       remaining--;
   2260     }
   2261 
   2262   sframe_assert (fres_buf_size == buf_size);
   2263   ectx->sfe_fres = fre_tbl;
   2264   ectx->sfe_fre_nbytes += buf_size;
   2265 
   2266   sframe_header *ehp = sframe_encoder_get_header (ectx);
   2267   ehp->sfh_num_fres = fre_tbl->count;
   2268 
   2269   return 0;
   2270 
   2271 bad:
   2272   if (fre_tbl != NULL)
   2273     free (fre_tbl);
   2274   ectx->sfe_fres = NULL;
   2275   ectx->sfe_fre_nbytes = 0;
   2276   return -1;
   2277 }
   2278 
   2279 /* Add a new SFrame function descriptor entry with START_ADDR, FUNC_SIZE and
   2280    FUNC_INFO to the encoder context ECTX.  Caller must make sure that ECTX
   2281    exists.  */
   2282 
   2283 static int
   2284 sframe_encoder_add_funcdesc_internal (sframe_encoder_ctx *ectx,
   2285 				      int64_t start_addr,
   2286 				      uint32_t func_size)
   2287 {
   2288   sframe_header *ehp;
   2289   sf_fde_tbl *fd_info;
   2290   size_t fd_tbl_sz;
   2291   int err = 0;
   2292 
   2293   fd_info = ectx->sfe_funcdesc;
   2294   ehp = sframe_encoder_get_header (ectx);
   2295 
   2296   if (fd_info == NULL)
   2297     {
   2298       fd_tbl_sz = (sizeof (sf_fde_tbl)
   2299 		   + (number_of_entries * sizeof (sframe_func_desc_entry_int)));
   2300       fd_info = malloc (fd_tbl_sz);
   2301       if (fd_info == NULL)
   2302 	{
   2303 	  sframe_set_errno (&err, SFRAME_ERR_NOMEM);
   2304 	  goto bad;		/* OOM.  */
   2305 	}
   2306       memset (fd_info, 0, fd_tbl_sz);
   2307       fd_info->alloced = number_of_entries;
   2308     }
   2309   else if (fd_info->count == fd_info->alloced)
   2310     {
   2311       fd_tbl_sz = (sizeof (sf_fde_tbl)
   2312 		   + ((fd_info->alloced + number_of_entries)
   2313 		      * sizeof (sframe_func_desc_entry_int)));
   2314       sf_fde_tbl *tmp = realloc (fd_info, fd_tbl_sz);
   2315       if (tmp == NULL)
   2316 	{
   2317 	  sframe_set_errno (&err, SFRAME_ERR_NOMEM);
   2318 	  goto bad;		/* OOM.  */
   2319 	}
   2320       fd_info = tmp;
   2321 
   2322       memset (&fd_info->entry[fd_info->alloced], 0,
   2323 	      number_of_entries * sizeof (sframe_func_desc_entry_int));
   2324       fd_info->alloced += number_of_entries;
   2325     }
   2326 
   2327   fd_info->entry[fd_info->count].func_start_pc_offset = start_addr;
   2328   /* Num FREs is updated as FREs are added for the function later via
   2329      sframe_encoder_add_fre.  */
   2330   fd_info->entry[fd_info->count].func_size = func_size;
   2331   fd_info->entry[fd_info->count].func_start_fre_off = ectx->sfe_fre_nbytes;
   2332 #if 0
   2333   // Linker optimization test code cleanup later ibhagat TODO FIXME
   2334   uint32_t fre_type = sframe_calc_fre_type (func_size);
   2335 
   2336   fd_info->entry[fd_info->count].sfde_func_info
   2337     = sframe_fde_func_info (fre_type);
   2338 #endif
   2339   fd_info->count++;
   2340   ectx->sfe_funcdesc = fd_info;
   2341   ehp->sfh_num_fdes++;
   2342   return 0;
   2343 
   2344 bad:
   2345   if (fd_info != NULL)
   2346     free (fd_info);
   2347   ectx->sfe_funcdesc = NULL;
   2348   ehp->sfh_num_fdes = 0;
   2349   return err;
   2350 }
   2351 
   2352 /* Add a new SFrame function descriptor entry with START_PC_OFFSET and
   2353    FUNC_SIZE to the encoder context ECTX.  */
   2354 
   2355 int
   2356 sframe_encoder_add_funcdesc (sframe_encoder_ctx *ectx, int64_t start_pc_offset,
   2357 			     uint32_t func_size)
   2358 {
   2359   int err = 0;
   2360   if (ectx == NULL || sframe_encoder_get_version (ectx) == SFRAME_VERSION_1)
   2361     return sframe_set_errno (&err, SFRAME_ERR_INVAL);
   2362 
   2363   err = sframe_encoder_add_funcdesc_internal (ectx, start_pc_offset, func_size);
   2364   if (err)
   2365     return err;
   2366 
   2367   return 0;
   2368 }
   2369 
   2370 /* Add a new SFrame function descriptor entry with START_ADDR, FUNC_SIZE,
   2371    FUNC_INFO and REP_BLOCK_SIZE to the encoder context ECTX.  This API is valid
   2372    only for SFrame format version 2.  */
   2373 
   2374 int
   2375 sframe_encoder_add_funcdesc_v2 (sframe_encoder_ctx *ectx,
   2376 				int32_t start_addr,
   2377 				uint32_t func_size,
   2378 				unsigned char func_info,
   2379 				uint8_t rep_block_size,
   2380 				uint32_t num_fres ATTRIBUTE_UNUSED)
   2381 {
   2382   int err = 0;
   2383   if (ectx == NULL || sframe_encoder_get_version (ectx) == SFRAME_VERSION_1)
   2384     return sframe_set_errno (&err, SFRAME_ERR_INVAL);
   2385 
   2386   err = sframe_encoder_add_funcdesc_internal (ectx, start_addr, func_size);
   2387   if (err)
   2388     return err;
   2389 
   2390   sf_fde_tbl *fd_info = ectx->sfe_funcdesc;
   2391   fd_info->entry[fd_info->count-1].func_info = func_info;
   2392   fd_info->entry[fd_info->count-1].func_rep_size = rep_block_size;
   2393 
   2394   return 0;
   2395 }
   2396 
   2397 /* Add a new SFrame function descriptor entry with START_PC_OFFSET, FUNC_SIZE,
   2398    FUNC_INFO, FUNC_INFO2 and REP_BLOCK_SIZE to the encoder context ECTX.
   2399    Return error code on failure.  */
   2400 
   2401 int
   2402 sframe_encoder_add_funcdesc_v3 (sframe_encoder_ctx *ectx,
   2403 				int64_t start_pc_offset,
   2404 				uint32_t func_size,
   2405 				unsigned char func_info,
   2406 				unsigned char func_info2,
   2407 				uint8_t rep_block_size,
   2408 				uint32_t num_fres ATTRIBUTE_UNUSED)
   2409 {
   2410   int err = 0;
   2411   if (ectx == NULL || sframe_encoder_get_version (ectx) != SFRAME_VERSION_3)
   2412     {
   2413       sframe_set_errno (&err, SFRAME_ERR_INVAL);
   2414       return err;
   2415     }
   2416 
   2417   err = sframe_encoder_add_funcdesc_internal (ectx, start_pc_offset,
   2418 					      func_size);
   2419   if (err)
   2420     return err;
   2421 
   2422   sf_fde_tbl *fd_info = ectx->sfe_funcdesc;
   2423   fd_info->entry[fd_info->count-1].func_info = func_info;
   2424   fd_info->entry[fd_info->count-1].func_info2 = func_info2;
   2425   fd_info->entry[fd_info->count-1].func_rep_size = rep_block_size;
   2426 
   2427   return 0;
   2428 }
   2429 
   2430 static int
   2431 sframe_sort_funcdesc (sframe_encoder_ctx *ectx)
   2432 {
   2433   sframe_header *ehp = sframe_encoder_get_header (ectx);
   2434 
   2435   /* Sort and write out the FDE table.  */
   2436   sf_fde_tbl *fd_info = ectx->sfe_funcdesc;
   2437   if (fd_info)
   2438     {
   2439       /* The new encoding of sfde_func_start_address means the distances are
   2440 	 not from the same anchor, so cannot be sorted directly.  At the moment
   2441 	 we adress this by manual value adjustments before and after sorting.
   2442 	 FIXME - qsort_r may be more optimal.  */
   2443 
   2444       for (unsigned int i = 0; i < fd_info->count; i++)
   2445 	fd_info->entry[i].func_start_pc_offset
   2446 	  += sframe_encoder_get_offsetof_fde_start_addr (ectx, i, NULL);
   2447 
   2448       qsort (fd_info->entry, fd_info->count,
   2449 	     sizeof (sframe_func_desc_entry_int), fde_func);
   2450 
   2451       for (unsigned int i = 0; i < fd_info->count; i++)
   2452 	fd_info->entry[i].func_start_pc_offset
   2453 	  -= sframe_encoder_get_offsetof_fde_start_addr (ectx, i, NULL);
   2454 
   2455       /* Update preamble's flags.  */
   2456       ehp->sfh_preamble.sfp_flags |= SFRAME_F_FDE_SORTED;
   2457     }
   2458   return 0;
   2459 }
   2460 
   2461 /* Write the SFrame FRE start address from the in-memory FRE_START_ADDR
   2462    to the buffer CONTENTS (on-disk format), given the FRE_TYPE and
   2463    FRE_START_ADDR_SZ.  */
   2464 
   2465 static int
   2466 sframe_encoder_write_fre_start_addr (char *contents,
   2467 				     uint32_t fre_start_addr,
   2468 				     uint32_t fre_type,
   2469 				     size_t fre_start_addr_sz)
   2470 {
   2471   int err = 0;
   2472 
   2473   if (fre_type == SFRAME_FRE_TYPE_ADDR1)
   2474     {
   2475       uint8_t uc = fre_start_addr;
   2476       memcpy (contents, &uc, fre_start_addr_sz);
   2477     }
   2478   else if (fre_type == SFRAME_FRE_TYPE_ADDR2)
   2479     {
   2480       uint16_t ust = fre_start_addr;
   2481       memcpy (contents, &ust, fre_start_addr_sz);
   2482     }
   2483   else if (fre_type == SFRAME_FRE_TYPE_ADDR4)
   2484     {
   2485       uint32_t uit = fre_start_addr;
   2486       memcpy (contents, &uit, fre_start_addr_sz);
   2487     }
   2488   else
   2489     return sframe_set_errno (&err, SFRAME_ERR_INVAL);
   2490 
   2491   return 0;
   2492 }
   2493 
   2494 /* Write a frame row entry pointed to by FREP into the buffer CONTENTS.  The
   2495    size in bytes written out are updated in ESZ.
   2496 
   2497    This function works closely with the SFrame binary format.
   2498 
   2499    Returns SFRAME_ERR if failure.  */
   2500 
   2501 static int
   2502 sframe_encoder_write_fre (char *contents, sframe_frame_row_entry *frep,
   2503 			  uint32_t fre_type, size_t *esz)
   2504 {
   2505   size_t fre_sz;
   2506   size_t fre_start_addr_sz;
   2507   size_t fre_datawords_sz;
   2508   int err = 0;
   2509 
   2510   if (!sframe_fre_sanity_check_p (frep))
   2511     return sframe_set_errno (&err, SFRAME_ERR_FRE_INVAL);
   2512 
   2513   fre_start_addr_sz = sframe_fre_start_addr_size (fre_type);
   2514   fre_datawords_sz = sframe_fre_datawords_bytes_size (frep->fre_info);
   2515 
   2516   /* The FRE start address must be encodable in the available number of
   2517      bytes.  */
   2518   uint64_t bitmask = SFRAME_BITMASK_OF_SIZE (fre_start_addr_sz);
   2519   sframe_assert ((uint64_t)frep->fre_start_addr <= bitmask);
   2520 
   2521   sframe_encoder_write_fre_start_addr (contents, frep->fre_start_addr,
   2522 				       fre_type, fre_start_addr_sz);
   2523   contents += fre_start_addr_sz;
   2524 
   2525   memcpy (contents, &frep->fre_info, sizeof (frep->fre_info));
   2526   contents += sizeof (frep->fre_info);
   2527 
   2528   memcpy (contents, frep->fre_datawords, fre_datawords_sz);
   2529   contents+= fre_datawords_sz;
   2530 
   2531   fre_sz = sframe_fre_entry_size (frep, fre_type);
   2532   /* Sanity checking.  */
   2533   sframe_assert ((fre_start_addr_sz
   2534 		  + sizeof (frep->fre_info)
   2535 		  + fre_datawords_sz) == fre_sz);
   2536 
   2537   *esz = fre_sz;
   2538 
   2539   return 0;
   2540 }
   2541 
   2542 /* Write an SFrame FDE Index element for SFrame V3 into the provided buffer at
   2543    CONTENTS.  Update FDE_WRITE_SIZE with the number of bytes written to the
   2544    buffer.  Return 0 on success, SFRAME_ERR otherwise.  */
   2545 
   2546 static int
   2547 sframe_encoder_write_fde_idx (const sframe_header *sfhp ATTRIBUTE_UNUSED,
   2548 			      char *contents,
   2549 			      const sframe_func_desc_entry_int *fde,
   2550 			      size_t *fde_write_size)
   2551 {
   2552   sframe_func_desc_idx_v3 *fdep = (sframe_func_desc_idx_v3 *)contents;
   2553 
   2554   fdep->sfdi_func_start_offset = fde->func_start_pc_offset;
   2555   fdep->sfdi_func_size = fde->func_size;
   2556   fdep->sfdi_func_start_fre_off = fde->func_start_fre_off;
   2557 
   2558   *fde_write_size = sizeof (sframe_func_desc_idx_v3);
   2559 
   2560   return 0;
   2561 }
   2562 
   2563 /* Write the SFrame FDE Attribute element for SFrame V3 into the provided
   2564    buffer at CONTENTS.  Return 0 on success, SFRAME_ERR otherwise.  */
   2565 
   2566 static int
   2567 sframe_encoder_write_fde_attr (char *contents,
   2568 			       const sframe_func_desc_entry_int *fde)
   2569 {
   2570   sframe_func_desc_attr_v3 *fattr = (sframe_func_desc_attr_v3 *)contents;
   2571 
   2572   /* Access to num_fres may be unaligned.  */
   2573   uint16_t num_fres = (uint16_t)fde->func_num_fres;
   2574   memcpy (fattr, &num_fres, sizeof (uint16_t));
   2575 
   2576   fattr->sfda_func_info = fde->func_info;
   2577   fattr->sfda_func_info2 = fde->func_info2;
   2578   fattr->sfda_func_rep_size = fde->func_rep_size;
   2579 
   2580   return 0;
   2581 }
   2582 /* Serialize the core contents of the SFrame section and write out to the
   2583    output buffer held in the encoder context ECTX.  Sort the SFrame FDEs on
   2584    start PC if SORT_FDE_P is true.  Return SFRAME_ERR if failure.  */
   2585 
   2586 static int
   2587 sframe_encoder_write_sframe (sframe_encoder_ctx *ectx, bool sort_fde_p)
   2588 {
   2589   char *contents;
   2590   size_t buf_size;
   2591   size_t hdr_size;
   2592   size_t fde_write_size, all_fdes_size;
   2593   size_t fre_size;
   2594   size_t esz = 0;
   2595   sframe_header *ehp;
   2596   sf_fde_tbl *fd_info;
   2597   sf_fre_tbl *fr_info;
   2598   uint32_t i, num_fdes;
   2599   uint32_t j, num_fres;
   2600   sframe_func_desc_entry_int *fdep;
   2601   sframe_frame_row_entry *frep;
   2602 
   2603   uint32_t fre_type;
   2604   int err = 0;
   2605 
   2606   contents = ectx->sfe_data;
   2607   buf_size = ectx->sfe_data_size;
   2608   num_fdes = sframe_encoder_get_num_fidx (ectx);
   2609   all_fdes_size = num_fdes * sizeof (sframe_func_desc_idx_v3);
   2610   ehp = sframe_encoder_get_header (ectx);
   2611   hdr_size = sframe_get_hdr_size (ehp);
   2612 
   2613   fd_info = ectx->sfe_funcdesc;
   2614   fr_info = ectx->sfe_fres;
   2615 
   2616   /* Sanity checks:
   2617      - buffers must be malloc'd by the caller.  */
   2618   if ((contents == NULL) || (buf_size < hdr_size))
   2619     return sframe_set_errno (&err, SFRAME_ERR_BUF_INVAL);
   2620   if (ehp->sfh_num_fres > 0 && fr_info == NULL)
   2621     return sframe_set_errno (&err, SFRAME_ERR_FRE_INVAL);
   2622 
   2623   /* Write out the FRE table first.
   2624 
   2625      Recall that read/write of FREs needs information from the corresponding
   2626      FDE; the latter stores the information about the FRE type record used for
   2627      the function.  Also note that sorting of FDEs does NOT impact the order
   2628      in which FREs are stored in the SFrame's FRE sub-section.  This means
   2629      that writing out FREs after sorting of FDEs will need some additional
   2630      book-keeping.  At this time, we can afford to avoid it by writing out
   2631      the FREs first to the output buffer.  */
   2632   fre_size = 0;
   2633   uint32_t global = 0;
   2634   uint32_t fre_index = 0;
   2635 
   2636   contents += hdr_size + all_fdes_size;
   2637   for (i = 0; i < num_fdes; i++)
   2638     {
   2639       fdep = &fd_info->entry[i];
   2640       fre_type = sframe_get_fre_type (fdep);
   2641       num_fres = fdep->func_num_fres;
   2642 
   2643       if (num_fres > 0 && fr_info == NULL)
   2644 	return sframe_set_errno (&err, SFRAME_ERR_FRE_INVAL);
   2645 
   2646       sframe_encoder_write_fde_attr (contents, fdep);
   2647       contents += sizeof (sframe_func_desc_attr_v3);
   2648       fre_size += sizeof (sframe_func_desc_attr_v3);
   2649 
   2650       for (j = 0; j < num_fres; j++)
   2651 	{
   2652 	  fre_index = global + j;
   2653 	  frep = &fr_info->entry[fre_index];
   2654 
   2655 	  sframe_encoder_write_fre (contents, frep, fre_type, &esz);
   2656 	  contents += esz;
   2657 	  fre_size += esz; /* For debugging only.  */
   2658 	}
   2659       global += j;
   2660     }
   2661 
   2662   sframe_assert (fre_size == ehp->sfh_fre_len);
   2663   sframe_assert (global == ehp->sfh_num_fres);
   2664   sframe_assert ((size_t)(contents - ectx->sfe_data) == buf_size);
   2665 
   2666   /* Sort the FDE table */
   2667   if (sort_fde_p)
   2668     sframe_sort_funcdesc (ectx);
   2669 
   2670   /* Sanity checks:
   2671      - the FDE section must have been sorted by now on the start address
   2672      of each function, if sorting was needed.  */
   2673   if ((sort_fde_p != (sframe_encoder_get_flags (ectx) & SFRAME_F_FDE_SORTED))
   2674       || (fd_info == NULL))
   2675     return sframe_set_errno (&err, SFRAME_ERR_FDE_INVAL);
   2676 
   2677   contents = ectx->sfe_data;
   2678   /* Write out the SFrame header.  The SFrame header in the encoder
   2679      object has already been updated with correct offsets by the caller.  */
   2680   memcpy (contents, ehp, hdr_size);
   2681   contents += hdr_size;
   2682 
   2683   /* Write out the FDE table sorted on funtion start address.  */
   2684   for (i = 0; i < num_fdes; i++)
   2685     {
   2686       sframe_encoder_write_fde_idx (ehp, contents, &fd_info->entry[i],
   2687 				    &fde_write_size);
   2688       contents += fde_write_size;
   2689     }
   2690 
   2691   return 0;
   2692 }
   2693 
   2694 /* Serialize the contents of the encoder context ECTX and return the buffer.
   2695    Sort the SFrame FDEs on start PC if SORT_FDE_P is true.  ENCODED_SIZE is
   2696    updated to the size of the buffer.  Sets ERRP if failure.  */
   2697 
   2698 char *
   2699 sframe_encoder_write (sframe_encoder_ctx *ectx, size_t *encoded_size,
   2700 		      bool sort_fde_p, int *errp)
   2701 {
   2702   sframe_header *ehp;
   2703   size_t hdrsize, fsz, fresz, bufsize;
   2704   int foreign_endian;
   2705 
   2706   /* Initialize the encoded_size to zero.  This makes it simpler to just
   2707      return from the function in case of failure.  Free'ing up of
   2708      ectx->sfe_data is the responsibility of the caller.  */
   2709   *encoded_size = 0;
   2710 
   2711   if (ectx == NULL || encoded_size == NULL || errp == NULL)
   2712     return sframe_ret_set_errno (errp, SFRAME_ERR_INVAL);
   2713 
   2714   ehp = sframe_encoder_get_header (ectx);
   2715   hdrsize = sframe_get_hdr_size (ehp);
   2716   fsz = sframe_encoder_get_num_fidx (ectx) * sizeof (sframe_func_desc_idx_v3);
   2717   fresz = ectx->sfe_fre_nbytes;
   2718 
   2719   /* Encoder writes out data in the latest SFrame format version.  */
   2720   if (sframe_encoder_get_version (ectx) != SFRAME_VERSION)
   2721     return sframe_ret_set_errno (errp, SFRAME_ERR_VERSION_INVAL);
   2722 
   2723   /* The total size of buffer is the sum of header, SFrame Function Descriptor
   2724      Entries section and the FRE section.  */
   2725   bufsize = hdrsize + fsz + fresz;
   2726   ectx->sfe_data = (char *) malloc (bufsize);
   2727   if (ectx->sfe_data == NULL)
   2728     return sframe_ret_set_errno (errp, SFRAME_ERR_NOMEM);
   2729   ectx->sfe_data_size = bufsize;
   2730 
   2731   /* Update the information in the SFrame header.  */
   2732   /* SFrame FDE section follows immediately after the header.  */
   2733   ehp->sfh_fdeoff = 0;
   2734   /* SFrame FRE section follows immediately after the SFrame FDE section.  */
   2735   ehp->sfh_freoff = fsz;
   2736   ehp->sfh_fre_len = fresz;
   2737 
   2738   foreign_endian = need_swapping (ehp->sfh_abi_arch);
   2739 
   2740   /* Write out the FDE Index and the FRE table in the sfe_data. */
   2741   if (sframe_encoder_write_sframe (ectx, sort_fde_p))
   2742     return sframe_ret_set_errno (errp, SFRAME_ERR_BUF_INVAL);
   2743 
   2744   /* Endian flip the contents if necessary.  */
   2745   if (foreign_endian)
   2746     {
   2747       if (flip_sframe (ectx->sfe_data, bufsize, 1))
   2748 	return sframe_ret_set_errno (errp, SFRAME_ERR_BUF_INVAL);
   2749       if (flip_header (ectx->sfe_data, SFRAME_VERSION))
   2750 	return sframe_ret_set_errno (errp, SFRAME_ERR_BUF_INVAL);
   2751     }
   2752 
   2753   *encoded_size = bufsize;
   2754   return ectx->sfe_data;
   2755 }
   2756