xref: /netbsd-src/external/gpl3/gdb/dist/libsframe/sframe.c (revision 6817db7f6bcc94c9b2ba339c5139981a23c88cf9)
14b169a6bSchristos /* sframe.c - SFrame decoder/encoder.
24b169a6bSchristos 
3*6817db7fSchristos    Copyright (C) 2022-2024 Free Software Foundation, Inc.
44b169a6bSchristos 
54b169a6bSchristos    This file is part of libsframe.
64b169a6bSchristos 
74b169a6bSchristos    This program is free software; you can redistribute it and/or modify
84b169a6bSchristos    it under the terms of the GNU General Public License as published by
94b169a6bSchristos    the Free Software Foundation; either version 3 of the License, or
104b169a6bSchristos    (at your option) any later version.
114b169a6bSchristos 
124b169a6bSchristos    This program is distributed in the hope that it will be useful,
134b169a6bSchristos    but WITHOUT ANY WARRANTY; without even the implied warranty of
144b169a6bSchristos    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
154b169a6bSchristos    GNU General Public License for more details.
164b169a6bSchristos 
174b169a6bSchristos    You should have received a copy of the GNU General Public License
184b169a6bSchristos    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
194b169a6bSchristos 
204b169a6bSchristos #include "config.h"
214b169a6bSchristos #include <stdio.h>
224b169a6bSchristos #include <stdlib.h>
234b169a6bSchristos #include <stdarg.h>
244b169a6bSchristos #include <string.h>
254b169a6bSchristos #include "sframe-impl.h"
264b169a6bSchristos #include "swap.h"
274b169a6bSchristos 
28*6817db7fSchristos struct sf_fde_tbl
294b169a6bSchristos {
304b169a6bSchristos   unsigned int count;
314b169a6bSchristos   unsigned int alloced;
324b169a6bSchristos   sframe_func_desc_entry entry[1];
33*6817db7fSchristos };
344b169a6bSchristos 
35*6817db7fSchristos struct sf_fre_tbl
364b169a6bSchristos {
374b169a6bSchristos   unsigned int count;
384b169a6bSchristos   unsigned int alloced;
394b169a6bSchristos   sframe_frame_row_entry entry[1];
40*6817db7fSchristos };
414b169a6bSchristos 
424b169a6bSchristos #define _sf_printflike_(string_index,first_to_check) \
434b169a6bSchristos     __attribute__ ((__format__ (__printf__, (string_index), (first_to_check))))
444b169a6bSchristos 
454b169a6bSchristos static void debug_printf (const char *, ...);
464b169a6bSchristos 
474b169a6bSchristos static int _sframe_debug;	/* Control for printing out debug info.  */
484b169a6bSchristos static int number_of_entries = 64;
494b169a6bSchristos 
504b169a6bSchristos static void
514b169a6bSchristos sframe_init_debug (void)
524b169a6bSchristos {
534b169a6bSchristos   static int inited;
544b169a6bSchristos 
554b169a6bSchristos   if (!inited)
564b169a6bSchristos     {
574b169a6bSchristos       _sframe_debug = getenv ("SFRAME_DEBUG") != NULL;
584b169a6bSchristos       inited = 1;
594b169a6bSchristos     }
604b169a6bSchristos }
614b169a6bSchristos 
624b169a6bSchristos _sf_printflike_ (1, 2)
634b169a6bSchristos static void debug_printf (const char *format, ...)
644b169a6bSchristos {
654b169a6bSchristos   if (_sframe_debug)
664b169a6bSchristos     {
674b169a6bSchristos       va_list args;
684b169a6bSchristos 
694b169a6bSchristos       va_start (args, format);
704b169a6bSchristos       vfprintf (stderr, format, args);
714b169a6bSchristos       va_end (args);
724b169a6bSchristos     }
734b169a6bSchristos }
744b169a6bSchristos 
754b169a6bSchristos /* Generate bitmask of given size in bytes.  This is used for
764b169a6bSchristos    some checks on the FRE start address.
774b169a6bSchristos    SFRAME_FRE_TYPE_ADDR1 => 1 byte => [ bitmask = 0xff ]
784b169a6bSchristos    SFRAME_FRE_TYPE_ADDR2 => 2 byte => [ bitmask = 0xffff ]
794b169a6bSchristos    SFRAME_FRE_TYPE_ADDR4 => 4 byte => [ bitmask = 0xffffffff ].  */
804b169a6bSchristos #define SFRAME_BITMASK_OF_SIZE(size_in_bytes) \
814b169a6bSchristos   (((uint64_t)1 << (size_in_bytes*8)) - 1)
824b169a6bSchristos 
834b169a6bSchristos /* Store the specified error code into errp if it is non-NULL.
844b169a6bSchristos    Return SFRAME_ERR.  */
854b169a6bSchristos 
864b169a6bSchristos static int
874b169a6bSchristos sframe_set_errno (int *errp, int error)
884b169a6bSchristos {
894b169a6bSchristos   if (errp != NULL)
904b169a6bSchristos     *errp = error;
914b169a6bSchristos   return SFRAME_ERR;
924b169a6bSchristos }
934b169a6bSchristos 
944b169a6bSchristos /* Store the specified error code into errp if it is non-NULL.
954b169a6bSchristos    Return NULL.  */
964b169a6bSchristos 
974b169a6bSchristos static void *
984b169a6bSchristos sframe_ret_set_errno (int *errp, int error)
994b169a6bSchristos {
1004b169a6bSchristos   if (errp != NULL)
1014b169a6bSchristos     *errp = error;
1024b169a6bSchristos   return NULL;
1034b169a6bSchristos }
1044b169a6bSchristos 
1054b169a6bSchristos /* Get the SFrame header size.  */
1064b169a6bSchristos 
1074b169a6bSchristos static uint32_t
1084b169a6bSchristos sframe_get_hdr_size (sframe_header *sfh)
1094b169a6bSchristos {
1104b169a6bSchristos   return SFRAME_V1_HDR_SIZE (*sfh);
1114b169a6bSchristos }
1124b169a6bSchristos 
1134b169a6bSchristos /* Access functions for frame row entry data.  */
1144b169a6bSchristos 
115*6817db7fSchristos static uint8_t
116*6817db7fSchristos sframe_fre_get_offset_count (uint8_t fre_info)
1174b169a6bSchristos {
1184b169a6bSchristos   return SFRAME_V1_FRE_OFFSET_COUNT (fre_info);
1194b169a6bSchristos }
1204b169a6bSchristos 
121*6817db7fSchristos static uint8_t
122*6817db7fSchristos sframe_fre_get_offset_size (uint8_t fre_info)
1234b169a6bSchristos {
1244b169a6bSchristos   return SFRAME_V1_FRE_OFFSET_SIZE (fre_info);
1254b169a6bSchristos }
1264b169a6bSchristos 
1274b169a6bSchristos static bool
128*6817db7fSchristos sframe_get_fre_ra_mangled_p (uint8_t fre_info)
1294b169a6bSchristos {
1304b169a6bSchristos   return SFRAME_V1_FRE_MANGLED_RA_P (fre_info);
1314b169a6bSchristos }
1324b169a6bSchristos 
1334b169a6bSchristos /* Access functions for info from function descriptor entry.  */
1344b169a6bSchristos 
135*6817db7fSchristos static uint32_t
1364b169a6bSchristos sframe_get_fre_type (sframe_func_desc_entry *fdep)
1374b169a6bSchristos {
138*6817db7fSchristos   uint32_t fre_type = 0;
1394b169a6bSchristos   if (fdep)
1404b169a6bSchristos     fre_type = SFRAME_V1_FUNC_FRE_TYPE (fdep->sfde_func_info);
1414b169a6bSchristos   return fre_type;
1424b169a6bSchristos }
1434b169a6bSchristos 
144*6817db7fSchristos static uint32_t
1454b169a6bSchristos sframe_get_fde_type (sframe_func_desc_entry *fdep)
1464b169a6bSchristos {
147*6817db7fSchristos   uint32_t fde_type = 0;
1484b169a6bSchristos   if (fdep)
1494b169a6bSchristos     fde_type = SFRAME_V1_FUNC_FDE_TYPE (fdep->sfde_func_info);
1504b169a6bSchristos   return fde_type;
1514b169a6bSchristos }
1524b169a6bSchristos 
1534b169a6bSchristos /* Check if flipping is needed, based on ENDIAN.  */
1544b169a6bSchristos 
1554b169a6bSchristos static int
1564b169a6bSchristos need_swapping (int endian)
1574b169a6bSchristos {
1584b169a6bSchristos   unsigned int ui = 1;
1594b169a6bSchristos   char *c = (char *)&ui;
1604b169a6bSchristos   int is_little = (int)*c;
1614b169a6bSchristos 
1624b169a6bSchristos   switch (endian)
1634b169a6bSchristos     {
1644b169a6bSchristos       case SFRAME_ABI_AARCH64_ENDIAN_LITTLE:
1654b169a6bSchristos       case SFRAME_ABI_AMD64_ENDIAN_LITTLE:
1664b169a6bSchristos 	return !is_little;
1674b169a6bSchristos       case SFRAME_ABI_AARCH64_ENDIAN_BIG:
1684b169a6bSchristos 	return is_little;
1694b169a6bSchristos       default:
1704b169a6bSchristos 	break;
1714b169a6bSchristos     }
1724b169a6bSchristos 
1734b169a6bSchristos   return 0;
1744b169a6bSchristos }
1754b169a6bSchristos 
1764b169a6bSchristos /* Flip the endianness of the SFrame header.  */
1774b169a6bSchristos 
1784b169a6bSchristos static void
1794b169a6bSchristos flip_header (sframe_header *sfheader)
1804b169a6bSchristos {
1814b169a6bSchristos   swap_thing (sfheader->sfh_preamble.sfp_magic);
1824b169a6bSchristos   swap_thing (sfheader->sfh_preamble.sfp_version);
1834b169a6bSchristos   swap_thing (sfheader->sfh_preamble.sfp_flags);
1844b169a6bSchristos   swap_thing (sfheader->sfh_cfa_fixed_fp_offset);
1854b169a6bSchristos   swap_thing (sfheader->sfh_cfa_fixed_ra_offset);
1864b169a6bSchristos   swap_thing (sfheader->sfh_num_fdes);
1874b169a6bSchristos   swap_thing (sfheader->sfh_num_fres);
1884b169a6bSchristos   swap_thing (sfheader->sfh_fre_len);
1894b169a6bSchristos   swap_thing (sfheader->sfh_fdeoff);
1904b169a6bSchristos   swap_thing (sfheader->sfh_freoff);
1914b169a6bSchristos }
1924b169a6bSchristos 
1934b169a6bSchristos static void
1944b169a6bSchristos flip_fde (sframe_func_desc_entry *fdep)
1954b169a6bSchristos {
1964b169a6bSchristos   swap_thing (fdep->sfde_func_start_address);
1974b169a6bSchristos   swap_thing (fdep->sfde_func_size);
1984b169a6bSchristos   swap_thing (fdep->sfde_func_start_fre_off);
1994b169a6bSchristos   swap_thing (fdep->sfde_func_num_fres);
2004b169a6bSchristos }
2014b169a6bSchristos 
2024b169a6bSchristos /* Check if SFrame header has valid data.  */
2034b169a6bSchristos 
204*6817db7fSchristos static bool
2054b169a6bSchristos sframe_header_sanity_check_p (sframe_header *hp)
2064b169a6bSchristos {
2074b169a6bSchristos   unsigned char all_flags = SFRAME_F_FDE_SORTED | SFRAME_F_FRAME_POINTER;
2084b169a6bSchristos   /* Check preamble is valid.  */
209*6817db7fSchristos   if (hp->sfh_preamble.sfp_magic != SFRAME_MAGIC
210*6817db7fSchristos       || (hp->sfh_preamble.sfp_version != SFRAME_VERSION_1
211*6817db7fSchristos 	  && hp->sfh_preamble.sfp_version != SFRAME_VERSION_2)
212*6817db7fSchristos       || (hp->sfh_preamble.sfp_flags | all_flags) != all_flags)
213*6817db7fSchristos     return false;
2144b169a6bSchristos 
2154b169a6bSchristos   /* Check offsets are valid.  */
2164b169a6bSchristos   if (hp->sfh_fdeoff > hp->sfh_freoff)
217*6817db7fSchristos     return false;
2184b169a6bSchristos 
219*6817db7fSchristos   return true;
2204b169a6bSchristos }
2214b169a6bSchristos 
2224b169a6bSchristos /* Flip the start address pointed to by FP.  */
2234b169a6bSchristos 
2244b169a6bSchristos static void
225*6817db7fSchristos flip_fre_start_address (char *addr, uint32_t fre_type)
2264b169a6bSchristos {
2274b169a6bSchristos   if (fre_type == SFRAME_FRE_TYPE_ADDR2)
2284b169a6bSchristos     {
229*6817db7fSchristos       uint16_t *start_addr = (uint16_t *)addr;
2304b169a6bSchristos       swap_thing (*start_addr);
2314b169a6bSchristos     }
2324b169a6bSchristos   else if (fre_type == SFRAME_FRE_TYPE_ADDR4)
2334b169a6bSchristos     {
234*6817db7fSchristos       uint32_t *start_addr = (uint32_t *)addr;
2354b169a6bSchristos       swap_thing (*start_addr);
2364b169a6bSchristos     }
2374b169a6bSchristos }
2384b169a6bSchristos 
2394b169a6bSchristos static void
240*6817db7fSchristos flip_fre_stack_offsets (char *offsets, uint8_t offset_size, uint8_t offset_cnt)
2414b169a6bSchristos {
2424b169a6bSchristos   int j;
2434b169a6bSchristos 
2444b169a6bSchristos   if (offset_size == SFRAME_FRE_OFFSET_2B)
2454b169a6bSchristos     {
246*6817db7fSchristos       uint16_t *ust = (uint16_t *)offsets;
2474b169a6bSchristos       for (j = offset_cnt; j > 0; ust++, j--)
2484b169a6bSchristos 	swap_thing (*ust);
2494b169a6bSchristos     }
2504b169a6bSchristos   else if (offset_size == SFRAME_FRE_OFFSET_4B)
2514b169a6bSchristos     {
2524b169a6bSchristos       uint32_t *uit = (uint32_t *)offsets;
2534b169a6bSchristos       for (j = offset_cnt; j > 0; uit++, j--)
2544b169a6bSchristos 	swap_thing (*uit);
2554b169a6bSchristos     }
2564b169a6bSchristos }
2574b169a6bSchristos 
2584b169a6bSchristos /* Get the FRE start address size, given the FRE_TYPE.  */
2594b169a6bSchristos 
2604b169a6bSchristos static size_t
261*6817db7fSchristos sframe_fre_start_addr_size (uint32_t fre_type)
2624b169a6bSchristos {
2634b169a6bSchristos   size_t addr_size = 0;
2644b169a6bSchristos   switch (fre_type)
2654b169a6bSchristos     {
2664b169a6bSchristos     case SFRAME_FRE_TYPE_ADDR1:
2674b169a6bSchristos       addr_size = 1;
2684b169a6bSchristos       break;
2694b169a6bSchristos     case SFRAME_FRE_TYPE_ADDR2:
2704b169a6bSchristos       addr_size = 2;
2714b169a6bSchristos       break;
2724b169a6bSchristos     case SFRAME_FRE_TYPE_ADDR4:
2734b169a6bSchristos       addr_size = 4;
2744b169a6bSchristos       break;
2754b169a6bSchristos     default:
2764b169a6bSchristos       /* No other value is expected.  */
2774b169a6bSchristos       sframe_assert (0);
2784b169a6bSchristos       break;
2794b169a6bSchristos     }
2804b169a6bSchristos   return addr_size;
2814b169a6bSchristos }
2824b169a6bSchristos 
2834b169a6bSchristos /* Check if the FREP has valid data.  */
2844b169a6bSchristos 
285*6817db7fSchristos static bool
2864b169a6bSchristos sframe_fre_sanity_check_p (sframe_frame_row_entry *frep)
2874b169a6bSchristos {
288*6817db7fSchristos   uint8_t offset_size, offset_cnt;
289*6817db7fSchristos   uint8_t fre_info;
2904b169a6bSchristos 
2914b169a6bSchristos   if (frep == NULL)
292*6817db7fSchristos     return false;
2934b169a6bSchristos 
2944b169a6bSchristos   fre_info = frep->fre_info;
2954b169a6bSchristos   offset_size = sframe_fre_get_offset_size (fre_info);
2964b169a6bSchristos 
2974b169a6bSchristos   if (offset_size != SFRAME_FRE_OFFSET_1B
2984b169a6bSchristos       && offset_size != SFRAME_FRE_OFFSET_2B
2994b169a6bSchristos       && offset_size != SFRAME_FRE_OFFSET_4B)
300*6817db7fSchristos     return false;
3014b169a6bSchristos 
3024b169a6bSchristos   offset_cnt = sframe_fre_get_offset_count (fre_info);
303*6817db7fSchristos   if (offset_cnt > MAX_NUM_STACK_OFFSETS)
304*6817db7fSchristos     return false;
3054b169a6bSchristos 
306*6817db7fSchristos   return true;
3074b169a6bSchristos }
3084b169a6bSchristos 
3094b169a6bSchristos /* Get FRE_INFO's offset size in bytes.  */
3104b169a6bSchristos 
3114b169a6bSchristos static size_t
312*6817db7fSchristos sframe_fre_offset_bytes_size (uint8_t fre_info)
3134b169a6bSchristos {
314*6817db7fSchristos   uint8_t offset_size, offset_cnt;
3154b169a6bSchristos 
3164b169a6bSchristos   offset_size = sframe_fre_get_offset_size (fre_info);
3174b169a6bSchristos 
3184b169a6bSchristos   debug_printf ("offset_size =  %u\n", offset_size);
3194b169a6bSchristos 
3204b169a6bSchristos   offset_cnt = sframe_fre_get_offset_count (fre_info);
3214b169a6bSchristos 
3224b169a6bSchristos   if (offset_size == SFRAME_FRE_OFFSET_2B
3234b169a6bSchristos       || offset_size == SFRAME_FRE_OFFSET_4B)	/* 2 or 4 bytes.  */
3244b169a6bSchristos     return (offset_cnt * (offset_size * 2));
3254b169a6bSchristos 
3264b169a6bSchristos   return (offset_cnt);
3274b169a6bSchristos }
3284b169a6bSchristos 
3294b169a6bSchristos /* Get total size in bytes to represent FREP in the binary format.  This
3304b169a6bSchristos    includes the starting address, FRE info, and all the offsets.  */
3314b169a6bSchristos 
3324b169a6bSchristos static size_t
333*6817db7fSchristos sframe_fre_entry_size (sframe_frame_row_entry *frep, uint32_t fre_type)
3344b169a6bSchristos {
3354b169a6bSchristos   if (frep == NULL)
3364b169a6bSchristos     return 0;
3374b169a6bSchristos 
338*6817db7fSchristos   uint8_t fre_info = frep->fre_info;
3394b169a6bSchristos   size_t addr_size = sframe_fre_start_addr_size (fre_type);
3404b169a6bSchristos 
3414b169a6bSchristos   return (addr_size + sizeof (frep->fre_info)
3424b169a6bSchristos 	  + sframe_fre_offset_bytes_size (fre_info));
3434b169a6bSchristos }
3444b169a6bSchristos 
345*6817db7fSchristos /* Get the function descriptor entry at index FUNC_IDX in the decoder
346*6817db7fSchristos    context CTX.  */
347*6817db7fSchristos 
348*6817db7fSchristos static sframe_func_desc_entry *
349*6817db7fSchristos sframe_decoder_get_funcdesc_at_index (sframe_decoder_ctx *ctx,
350*6817db7fSchristos 				      uint32_t func_idx)
3514b169a6bSchristos {
352*6817db7fSchristos   sframe_func_desc_entry *fdep;
353*6817db7fSchristos   uint32_t num_fdes;
354*6817db7fSchristos   int err;
355*6817db7fSchristos 
356*6817db7fSchristos   num_fdes = sframe_decoder_get_num_fidx (ctx);
357*6817db7fSchristos   if (num_fdes == 0
358*6817db7fSchristos       || func_idx >= num_fdes
359*6817db7fSchristos       || ctx->sfd_funcdesc == NULL)
360*6817db7fSchristos     return sframe_ret_set_errno (&err, SFRAME_ERR_DCTX_INVAL);
361*6817db7fSchristos 
362*6817db7fSchristos   fdep = &ctx->sfd_funcdesc[func_idx];
363*6817db7fSchristos   return fdep;
364*6817db7fSchristos }
365*6817db7fSchristos 
366*6817db7fSchristos /* Check whether for the given FDEP, the SFrame Frame Row Entry identified via
367*6817db7fSchristos    the START_IP_OFFSET and the END_IP_OFFSET, provides the stack trace
368*6817db7fSchristos    information for the PC.  */
369*6817db7fSchristos 
370*6817db7fSchristos static bool
371*6817db7fSchristos sframe_fre_check_range_p (sframe_func_desc_entry *fdep,
372*6817db7fSchristos 			  int32_t start_ip_offset, int32_t end_ip_offset,
373*6817db7fSchristos 			  int32_t pc)
374*6817db7fSchristos {
375*6817db7fSchristos   int32_t start_ip, end_ip;
376*6817db7fSchristos   int32_t func_start_addr;
377*6817db7fSchristos   uint8_t rep_block_size;
378*6817db7fSchristos   uint32_t fde_type;
379*6817db7fSchristos   int32_t masked_pc;
380*6817db7fSchristos   bool mask_p;
381*6817db7fSchristos   bool ret;
382*6817db7fSchristos 
383*6817db7fSchristos   ret = false;
384*6817db7fSchristos 
385*6817db7fSchristos   if (!fdep)
386*6817db7fSchristos     return ret;
387*6817db7fSchristos 
388*6817db7fSchristos   func_start_addr = fdep->sfde_func_start_address;
389*6817db7fSchristos   fde_type = sframe_get_fde_type (fdep);
390*6817db7fSchristos   mask_p = (fde_type == SFRAME_FDE_TYPE_PCMASK);
391*6817db7fSchristos   rep_block_size = fdep->sfde_func_rep_size;
392*6817db7fSchristos 
393*6817db7fSchristos   if (!mask_p)
394*6817db7fSchristos     {
395*6817db7fSchristos       start_ip = start_ip_offset + func_start_addr;
396*6817db7fSchristos       end_ip = end_ip_offset + func_start_addr;
397*6817db7fSchristos       ret = ((start_ip <= pc) && (end_ip >= pc));
398*6817db7fSchristos     }
399*6817db7fSchristos   else
400*6817db7fSchristos     {
401*6817db7fSchristos       /* For FDEs for repetitive pattern of insns, we need to return the FRE
402*6817db7fSchristos 	 where pc % rep_block_size is between start_ip_offset and
403*6817db7fSchristos 	 end_ip_offset.  */
404*6817db7fSchristos       masked_pc = pc % rep_block_size;
405*6817db7fSchristos       ret = ((start_ip_offset <= masked_pc) && (end_ip_offset >= masked_pc));
406*6817db7fSchristos     }
407*6817db7fSchristos 
408*6817db7fSchristos   return ret;
409*6817db7fSchristos }
410*6817db7fSchristos 
411*6817db7fSchristos static int
412*6817db7fSchristos flip_fre (char *fp, uint32_t fre_type, size_t *fre_size)
413*6817db7fSchristos {
414*6817db7fSchristos   uint8_t fre_info;
415*6817db7fSchristos   uint8_t offset_size, offset_cnt;
4164b169a6bSchristos   size_t addr_size, fre_info_size = 0;
4174b169a6bSchristos   int err = 0;
4184b169a6bSchristos 
4194b169a6bSchristos   if (fre_size == NULL)
4204b169a6bSchristos     return sframe_set_errno (&err, SFRAME_ERR_INVAL);
4214b169a6bSchristos 
4224b169a6bSchristos   flip_fre_start_address (fp, fre_type);
4234b169a6bSchristos 
4244b169a6bSchristos   /* Advance the buffer pointer to where the FRE info is.  */
4254b169a6bSchristos   addr_size = sframe_fre_start_addr_size (fre_type);
4264b169a6bSchristos   fp += addr_size;
4274b169a6bSchristos 
428*6817db7fSchristos   /* FRE info is uint8_t.  No need to flip.  */
429*6817db7fSchristos   fre_info = *(uint8_t*)fp;
4304b169a6bSchristos   offset_size = sframe_fre_get_offset_size (fre_info);
4314b169a6bSchristos   offset_cnt = sframe_fre_get_offset_count (fre_info);
4324b169a6bSchristos 
4334b169a6bSchristos   /* Advance the buffer pointer to where the stack offsets are.  */
434*6817db7fSchristos   fre_info_size = sizeof (uint8_t);
4354b169a6bSchristos   fp += fre_info_size;
4364b169a6bSchristos   flip_fre_stack_offsets (fp, offset_size, offset_cnt);
4374b169a6bSchristos 
4384b169a6bSchristos   *fre_size
4394b169a6bSchristos     = addr_size + fre_info_size + sframe_fre_offset_bytes_size (fre_info);
4404b169a6bSchristos 
4414b169a6bSchristos   return 0;
4424b169a6bSchristos }
4434b169a6bSchristos 
4444b169a6bSchristos /* Endian flip the contents of FRAME_BUF of size BUF_SIZE.
4454b169a6bSchristos    The SFrame header in the FRAME_BUF must be endian flipped prior to
4464b169a6bSchristos    calling flip_sframe.
4474b169a6bSchristos 
4484b169a6bSchristos    Endian flipping at decode time vs encode time have different needs.  At
4494b169a6bSchristos    encode time, the frame_buf is in host endianness, and hence, values should
4504b169a6bSchristos    be read up before the buffer is changed to foreign endianness.  This change
4514b169a6bSchristos    of behaviour is specified via TO_FOREIGN arg.
4524b169a6bSchristos 
4534b169a6bSchristos    If an error code is returned, the buffer should not be used.  */
4544b169a6bSchristos 
4554b169a6bSchristos static int
4564b169a6bSchristos flip_sframe (char *frame_buf, size_t buf_size, uint32_t to_foreign)
4574b169a6bSchristos {
4584b169a6bSchristos   unsigned int i, j, prev_frep_index;
4594b169a6bSchristos   sframe_header *ihp;
4604b169a6bSchristos   char *fdes;
4614b169a6bSchristos   char *fp = NULL;
4624b169a6bSchristos   sframe_func_desc_entry *fdep;
4634b169a6bSchristos   unsigned int num_fdes = 0;
4644b169a6bSchristos   unsigned int num_fres = 0;
465*6817db7fSchristos   uint32_t fre_type = 0;
4664b169a6bSchristos   uint32_t fre_offset = 0;
4674b169a6bSchristos   size_t esz = 0;
468*6817db7fSchristos   size_t hdrsz = 0;
4694b169a6bSchristos   int err = 0;
470*6817db7fSchristos   /* For error checking.  */
471*6817db7fSchristos   size_t bytes_flipped = 0;
4724b169a6bSchristos 
4734b169a6bSchristos   /* Header must be in host endianness at this time.  */
4744b169a6bSchristos   ihp = (sframe_header *)frame_buf;
4754b169a6bSchristos 
4764b169a6bSchristos   if (!sframe_header_sanity_check_p (ihp))
4774b169a6bSchristos     return sframe_set_errno (&err, SFRAME_ERR_BUF_INVAL);
4784b169a6bSchristos 
4794b169a6bSchristos   /* The contents of the SFrame header are safe to read.  Get the number of
4804b169a6bSchristos      FDEs and the first FDE in the buffer.  */
481*6817db7fSchristos   hdrsz = sframe_get_hdr_size (ihp);
4824b169a6bSchristos   num_fdes = ihp->sfh_num_fdes;
483*6817db7fSchristos   fdes = frame_buf + hdrsz + ihp->sfh_fdeoff;
4844b169a6bSchristos   fdep = (sframe_func_desc_entry *)fdes;
4854b169a6bSchristos 
4864b169a6bSchristos   j = 0;
4874b169a6bSchristos   prev_frep_index = 0;
4884b169a6bSchristos   for (i = 0; i < num_fdes; fdep++, i++)
4894b169a6bSchristos     {
490*6817db7fSchristos       if ((char*)fdep >= (frame_buf + buf_size))
491*6817db7fSchristos 	goto bad;
492*6817db7fSchristos 
4934b169a6bSchristos       if (to_foreign)
4944b169a6bSchristos 	{
4954b169a6bSchristos 	  num_fres = fdep->sfde_func_num_fres;
4964b169a6bSchristos 	  fre_type = sframe_get_fre_type (fdep);
4974b169a6bSchristos 	  fre_offset = fdep->sfde_func_start_fre_off;
4984b169a6bSchristos 	}
4994b169a6bSchristos 
5004b169a6bSchristos       flip_fde (fdep);
501*6817db7fSchristos       bytes_flipped += sizeof (sframe_func_desc_entry);
5024b169a6bSchristos 
5034b169a6bSchristos       if (!to_foreign)
5044b169a6bSchristos 	{
5054b169a6bSchristos 	  num_fres = fdep->sfde_func_num_fres;
5064b169a6bSchristos 	  fre_type = sframe_get_fre_type (fdep);
5074b169a6bSchristos 	  fre_offset = fdep->sfde_func_start_fre_off;
5084b169a6bSchristos 	}
5094b169a6bSchristos 
5104b169a6bSchristos       fp = frame_buf + sframe_get_hdr_size (ihp) + ihp->sfh_freoff;
5114b169a6bSchristos       fp += fre_offset;
5124b169a6bSchristos       for (; j < prev_frep_index + num_fres; j++)
5134b169a6bSchristos 	{
5144b169a6bSchristos 	  if (flip_fre (fp, fre_type, &esz))
5154b169a6bSchristos 	    goto bad;
516*6817db7fSchristos 	  bytes_flipped += esz;
5174b169a6bSchristos 
518*6817db7fSchristos 	  if (esz == 0 || esz > buf_size)
5194b169a6bSchristos 	    goto bad;
5204b169a6bSchristos 	  fp += esz;
5214b169a6bSchristos 	}
5224b169a6bSchristos       prev_frep_index = j;
5234b169a6bSchristos     }
524*6817db7fSchristos   /* All FDEs and FREs must have been endian flipped by now.  */
525*6817db7fSchristos   if ((j != ihp->sfh_num_fres) || (bytes_flipped != (buf_size - hdrsz)))
5264b169a6bSchristos     goto bad;
5274b169a6bSchristos 
5284b169a6bSchristos   /* Success.  */
5294b169a6bSchristos   return 0;
5304b169a6bSchristos bad:
5314b169a6bSchristos   return SFRAME_ERR;
5324b169a6bSchristos }
5334b169a6bSchristos 
5344b169a6bSchristos /* The SFrame Decoder.  */
5354b169a6bSchristos 
536*6817db7fSchristos /* Get SFrame header from the given decoder context DCTX.  */
5374b169a6bSchristos 
5384b169a6bSchristos static sframe_header *
539*6817db7fSchristos sframe_decoder_get_header (sframe_decoder_ctx *dctx)
5404b169a6bSchristos {
5414b169a6bSchristos   sframe_header *hp = NULL;
542*6817db7fSchristos   if (dctx != NULL)
543*6817db7fSchristos     hp = &dctx->sfd_header;
5444b169a6bSchristos   return hp;
5454b169a6bSchristos }
5464b169a6bSchristos 
5474b169a6bSchristos /* Compare function for qsort'ing the FDE table.  */
5484b169a6bSchristos 
5494b169a6bSchristos static int
5504b169a6bSchristos fde_func (const void *p1, const void *p2)
5514b169a6bSchristos {
5524b169a6bSchristos   const sframe_func_desc_entry *aa = p1;
5534b169a6bSchristos   const sframe_func_desc_entry *bb = p2;
5544b169a6bSchristos 
5554b169a6bSchristos   if (aa->sfde_func_start_address < bb->sfde_func_start_address)
5564b169a6bSchristos     return -1;
5574b169a6bSchristos   else if (aa->sfde_func_start_address > bb->sfde_func_start_address)
5584b169a6bSchristos     return 1;
5594b169a6bSchristos   return 0;
5604b169a6bSchristos }
5614b169a6bSchristos 
5624b169a6bSchristos /* Get IDX'th offset from FRE.  Set errp as applicable.  */
5634b169a6bSchristos 
5644b169a6bSchristos static int32_t
5654b169a6bSchristos sframe_get_fre_offset (sframe_frame_row_entry *fre, int idx, int *errp)
5664b169a6bSchristos {
567*6817db7fSchristos   uint8_t offset_cnt, offset_size;
5684b169a6bSchristos 
5694b169a6bSchristos   if (fre == NULL || !sframe_fre_sanity_check_p (fre))
5704b169a6bSchristos     return sframe_set_errno (errp, SFRAME_ERR_FRE_INVAL);
5714b169a6bSchristos 
5724b169a6bSchristos   offset_cnt = sframe_fre_get_offset_count (fre->fre_info);
5734b169a6bSchristos   offset_size = sframe_fre_get_offset_size (fre->fre_info);
5744b169a6bSchristos 
5754b169a6bSchristos   if (offset_cnt < idx + 1)
5764b169a6bSchristos     return sframe_set_errno (errp, SFRAME_ERR_FREOFFSET_NOPRESENT);
5774b169a6bSchristos 
5784b169a6bSchristos   if (errp)
5794b169a6bSchristos     *errp = 0; /* Offset Valid.  */
5804b169a6bSchristos 
5814b169a6bSchristos   if (offset_size == SFRAME_FRE_OFFSET_1B)
5824b169a6bSchristos     {
5834b169a6bSchristos       int8_t *sp = (int8_t *)fre->fre_offsets;
5844b169a6bSchristos       return sp[idx];
5854b169a6bSchristos     }
5864b169a6bSchristos   else if (offset_size == SFRAME_FRE_OFFSET_2B)
5874b169a6bSchristos     {
5884b169a6bSchristos       int16_t *sp = (int16_t *)fre->fre_offsets;
5894b169a6bSchristos       return sp[idx];
5904b169a6bSchristos     }
5914b169a6bSchristos   else
5924b169a6bSchristos     {
5934b169a6bSchristos       int32_t *ip = (int32_t *)fre->fre_offsets;
5944b169a6bSchristos       return ip[idx];
5954b169a6bSchristos     }
5964b169a6bSchristos }
5974b169a6bSchristos 
5984b169a6bSchristos /* Free the decoder context.  */
5994b169a6bSchristos 
6004b169a6bSchristos void
601*6817db7fSchristos sframe_decoder_free (sframe_decoder_ctx **dctxp)
6024b169a6bSchristos {
603*6817db7fSchristos   if (dctxp != NULL)
6044b169a6bSchristos     {
605*6817db7fSchristos       sframe_decoder_ctx *dctx = *dctxp;
6064b169a6bSchristos       if (dctx == NULL)
6074b169a6bSchristos 	return;
6084b169a6bSchristos 
6094b169a6bSchristos       if (dctx->sfd_funcdesc != NULL)
6104b169a6bSchristos 	{
6114b169a6bSchristos 	  free (dctx->sfd_funcdesc);
6124b169a6bSchristos 	  dctx->sfd_funcdesc = NULL;
6134b169a6bSchristos 	}
6144b169a6bSchristos       if (dctx->sfd_fres != NULL)
6154b169a6bSchristos 	{
6164b169a6bSchristos 	  free (dctx->sfd_fres);
6174b169a6bSchristos 	  dctx->sfd_fres = NULL;
6184b169a6bSchristos 	}
619*6817db7fSchristos       if (dctx->sfd_buf != NULL)
620*6817db7fSchristos 	{
621*6817db7fSchristos 	  free (dctx->sfd_buf);
622*6817db7fSchristos 	  dctx->sfd_buf = NULL;
623*6817db7fSchristos 	}
6244b169a6bSchristos 
625*6817db7fSchristos       free (*dctxp);
626*6817db7fSchristos       *dctxp = NULL;
6274b169a6bSchristos     }
6284b169a6bSchristos }
6294b169a6bSchristos 
6304b169a6bSchristos /* Create an FDE function info byte given an FRE_TYPE and an FDE_TYPE.  */
6314b169a6bSchristos /* FIXME API for linker.  Revisit if its better placed somewhere else?  */
6324b169a6bSchristos 
6334b169a6bSchristos unsigned char
634*6817db7fSchristos sframe_fde_create_func_info (uint32_t fre_type,
635*6817db7fSchristos 			     uint32_t fde_type)
6364b169a6bSchristos {
6374b169a6bSchristos   unsigned char func_info;
6384b169a6bSchristos   sframe_assert (fre_type == SFRAME_FRE_TYPE_ADDR1
6394b169a6bSchristos 		   || fre_type == SFRAME_FRE_TYPE_ADDR2
6404b169a6bSchristos 		   || fre_type == SFRAME_FRE_TYPE_ADDR4);
6414b169a6bSchristos   sframe_assert (fde_type == SFRAME_FDE_TYPE_PCINC
6424b169a6bSchristos 		    || fde_type == SFRAME_FDE_TYPE_PCMASK);
6434b169a6bSchristos   func_info = SFRAME_V1_FUNC_INFO (fde_type, fre_type);
6444b169a6bSchristos   return func_info;
6454b169a6bSchristos }
6464b169a6bSchristos 
6474b169a6bSchristos /* Get the FRE type given the function size.  */
6484b169a6bSchristos /* FIXME API for linker.  Revisit if its better placed somewhere else?  */
6494b169a6bSchristos 
650*6817db7fSchristos uint32_t
651*6817db7fSchristos sframe_calc_fre_type (size_t func_size)
6524b169a6bSchristos {
653*6817db7fSchristos   uint32_t fre_type = 0;
6544b169a6bSchristos   if (func_size < SFRAME_FRE_TYPE_ADDR1_LIMIT)
6554b169a6bSchristos     fre_type = SFRAME_FRE_TYPE_ADDR1;
6564b169a6bSchristos   else if (func_size < SFRAME_FRE_TYPE_ADDR2_LIMIT)
6574b169a6bSchristos     fre_type = SFRAME_FRE_TYPE_ADDR2;
658*6817db7fSchristos   /* Adjust the check a bit so that it remains warning-free but meaningful
659*6817db7fSchristos      on 32-bit systems.  */
660*6817db7fSchristos   else if (func_size <= (size_t) (SFRAME_FRE_TYPE_ADDR4_LIMIT - 1))
6614b169a6bSchristos     fre_type = SFRAME_FRE_TYPE_ADDR4;
6624b169a6bSchristos   return fre_type;
6634b169a6bSchristos }
6644b169a6bSchristos 
6654b169a6bSchristos /* Get the base reg id from the FRE info.  Set errp if failure.  */
6664b169a6bSchristos 
667*6817db7fSchristos uint8_t
6684b169a6bSchristos sframe_fre_get_base_reg_id (sframe_frame_row_entry *fre, int *errp)
6694b169a6bSchristos {
6704b169a6bSchristos   if (fre == NULL)
6714b169a6bSchristos     return sframe_set_errno (errp, SFRAME_ERR_FRE_INVAL);
6724b169a6bSchristos 
673*6817db7fSchristos   uint8_t fre_info = fre->fre_info;
6744b169a6bSchristos   return SFRAME_V1_FRE_CFA_BASE_REG_ID (fre_info);
6754b169a6bSchristos }
6764b169a6bSchristos 
6774b169a6bSchristos /* Get the CFA offset from the FRE.  If the offset is invalid, sets errp.  */
6784b169a6bSchristos 
6794b169a6bSchristos int32_t
6804b169a6bSchristos sframe_fre_get_cfa_offset (sframe_decoder_ctx *dctx ATTRIBUTE_UNUSED,
6814b169a6bSchristos 			   sframe_frame_row_entry *fre, int *errp)
6824b169a6bSchristos {
6834b169a6bSchristos   return sframe_get_fre_offset (fre, SFRAME_FRE_CFA_OFFSET_IDX, errp);
6844b169a6bSchristos }
6854b169a6bSchristos 
6864b169a6bSchristos /* Get the FP offset from the FRE.  If the offset is invalid, sets errp.  */
6874b169a6bSchristos 
6884b169a6bSchristos int32_t
6894b169a6bSchristos sframe_fre_get_fp_offset (sframe_decoder_ctx *dctx,
6904b169a6bSchristos 			  sframe_frame_row_entry *fre, int *errp)
6914b169a6bSchristos {
6924b169a6bSchristos   uint32_t fp_offset_idx = 0;
693*6817db7fSchristos   int8_t fp_offset = sframe_decoder_get_fixed_fp_offset (dctx);
694*6817db7fSchristos   /* If the FP offset is not being tracked, return the fixed FP offset
695*6817db7fSchristos      from the SFrame header.  */
696*6817db7fSchristos   if (fp_offset != SFRAME_CFA_FIXED_FP_INVALID)
697*6817db7fSchristos     {
698*6817db7fSchristos       if (errp)
699*6817db7fSchristos 	*errp = 0;
700*6817db7fSchristos       return fp_offset;
701*6817db7fSchristos     }
7024b169a6bSchristos 
7034b169a6bSchristos   /* In some ABIs, the stack offset to recover RA (using the CFA) from is
7044b169a6bSchristos      fixed (like AMD64).  In such cases, the stack offset to recover FP will
7054b169a6bSchristos      appear at the second index.  */
706*6817db7fSchristos   fp_offset_idx = ((sframe_decoder_get_fixed_ra_offset (dctx)
707*6817db7fSchristos 		    != SFRAME_CFA_FIXED_RA_INVALID)
7084b169a6bSchristos 		   ? SFRAME_FRE_RA_OFFSET_IDX
7094b169a6bSchristos 		   : SFRAME_FRE_FP_OFFSET_IDX);
7104b169a6bSchristos   return sframe_get_fre_offset (fre, fp_offset_idx, errp);
7114b169a6bSchristos }
7124b169a6bSchristos 
7134b169a6bSchristos /* Get the RA offset from the FRE.  If the offset is invalid, sets errp.  */
7144b169a6bSchristos 
7154b169a6bSchristos int32_t
7164b169a6bSchristos sframe_fre_get_ra_offset (sframe_decoder_ctx *dctx,
7174b169a6bSchristos 			  sframe_frame_row_entry *fre, int *errp)
7184b169a6bSchristos {
719*6817db7fSchristos   int8_t ra_offset = sframe_decoder_get_fixed_ra_offset (dctx);
720*6817db7fSchristos   /* If the RA offset was not being tracked, return the fixed RA offset
721*6817db7fSchristos      from the SFrame header.  */
722*6817db7fSchristos   if (ra_offset != SFRAME_CFA_FIXED_RA_INVALID)
723*6817db7fSchristos     {
724*6817db7fSchristos       if (errp)
725*6817db7fSchristos 	*errp = 0;
726*6817db7fSchristos       return ra_offset;
727*6817db7fSchristos     }
7284b169a6bSchristos 
7294b169a6bSchristos   /* Otherwise, get the RA offset from the FRE.  */
7304b169a6bSchristos   return sframe_get_fre_offset (fre, SFRAME_FRE_RA_OFFSET_IDX, errp);
7314b169a6bSchristos }
7324b169a6bSchristos 
7334b169a6bSchristos /* Get whether the RA is mangled.  */
7344b169a6bSchristos 
7354b169a6bSchristos bool
7364b169a6bSchristos sframe_fre_get_ra_mangled_p (sframe_decoder_ctx *dctx ATTRIBUTE_UNUSED,
7374b169a6bSchristos 			     sframe_frame_row_entry *fre, int *errp)
7384b169a6bSchristos {
7394b169a6bSchristos   if (fre == NULL || !sframe_fre_sanity_check_p (fre))
7404b169a6bSchristos     return sframe_set_errno (errp, SFRAME_ERR_FRE_INVAL);
7414b169a6bSchristos 
7424b169a6bSchristos   return sframe_get_fre_ra_mangled_p (fre->fre_info);
7434b169a6bSchristos }
7444b169a6bSchristos 
7454b169a6bSchristos static int
746*6817db7fSchristos sframe_frame_row_entry_copy (sframe_frame_row_entry *dst,
747*6817db7fSchristos 			     sframe_frame_row_entry *src)
7484b169a6bSchristos {
7494b169a6bSchristos   int err = 0;
7504b169a6bSchristos 
7514b169a6bSchristos   if (dst == NULL || src == NULL)
7524b169a6bSchristos     return sframe_set_errno (&err, SFRAME_ERR_INVAL);
7534b169a6bSchristos 
7544b169a6bSchristos   memcpy (dst, src, sizeof (sframe_frame_row_entry));
7554b169a6bSchristos   return 0;
7564b169a6bSchristos }
7574b169a6bSchristos 
7584b169a6bSchristos /* Decode the SFrame FRE start address offset value from FRE_BUF in on-disk
7594b169a6bSchristos    binary format, given the FRE_TYPE.  Updates the FRE_START_ADDR.
7604b169a6bSchristos 
7614b169a6bSchristos    Returns 0 on success, SFRAME_ERR otherwise.  */
7624b169a6bSchristos 
7634b169a6bSchristos static int
7644b169a6bSchristos sframe_decode_fre_start_address (const char *fre_buf,
7654b169a6bSchristos 				 uint32_t *fre_start_addr,
766*6817db7fSchristos 				 uint32_t fre_type)
7674b169a6bSchristos {
7684b169a6bSchristos   uint32_t saddr = 0;
7694b169a6bSchristos   int err = 0;
7704b169a6bSchristos   size_t addr_size = 0;
7714b169a6bSchristos 
7724b169a6bSchristos   addr_size = sframe_fre_start_addr_size (fre_type);
7734b169a6bSchristos 
7744b169a6bSchristos   if (fre_type == SFRAME_FRE_TYPE_ADDR1)
7754b169a6bSchristos     {
7764b169a6bSchristos       uint8_t *uc = (uint8_t *)fre_buf;
7774b169a6bSchristos       saddr = (uint32_t)*uc;
7784b169a6bSchristos     }
7794b169a6bSchristos   else if (fre_type == SFRAME_FRE_TYPE_ADDR2)
7804b169a6bSchristos     {
7814b169a6bSchristos       uint16_t *ust = (uint16_t *)fre_buf;
7824b169a6bSchristos       /* SFrame is an unaligned on-disk format.  Using memcpy helps avoid the
7834b169a6bSchristos 	 use of undesirable unaligned loads.  See PR libsframe/29856.  */
7844b169a6bSchristos       uint16_t tmp = 0;
7854b169a6bSchristos       memcpy (&tmp, ust, addr_size);
7864b169a6bSchristos       saddr = (uint32_t)tmp;
7874b169a6bSchristos     }
7884b169a6bSchristos   else if (fre_type == SFRAME_FRE_TYPE_ADDR4)
7894b169a6bSchristos     {
7904b169a6bSchristos       uint32_t *uit = (uint32_t *)fre_buf;
791*6817db7fSchristos       uint32_t tmp = 0;
7924b169a6bSchristos       memcpy (&tmp, uit, addr_size);
7934b169a6bSchristos       saddr = (uint32_t)tmp;
7944b169a6bSchristos     }
7954b169a6bSchristos   else
7964b169a6bSchristos     return sframe_set_errno (&err, SFRAME_ERR_INVAL);
7974b169a6bSchristos 
7984b169a6bSchristos   *fre_start_addr = saddr;
7994b169a6bSchristos   return 0;
8004b169a6bSchristos }
8014b169a6bSchristos 
8024b169a6bSchristos /* Decode a frame row entry FRE which starts at location FRE_BUF.  The function
8034b169a6bSchristos    updates ESZ to the size of the FRE as stored in the binary format.
8044b169a6bSchristos 
8054b169a6bSchristos    This function works closely with the SFrame binary format.
8064b169a6bSchristos 
8074b169a6bSchristos    Returns SFRAME_ERR if failure.  */
8084b169a6bSchristos 
8094b169a6bSchristos static int
8104b169a6bSchristos sframe_decode_fre (const char *fre_buf, sframe_frame_row_entry *fre,
811*6817db7fSchristos 		   uint32_t fre_type, size_t *esz)
8124b169a6bSchristos {
8134b169a6bSchristos   int err = 0;
814*6817db7fSchristos   const char *stack_offsets = NULL;
8154b169a6bSchristos   size_t stack_offsets_sz;
8164b169a6bSchristos   size_t addr_size;
8174b169a6bSchristos   size_t fre_size;
8184b169a6bSchristos 
8194b169a6bSchristos   if (fre_buf == NULL || fre == NULL || esz == NULL)
8204b169a6bSchristos     return sframe_set_errno (&err, SFRAME_ERR_INVAL);
8214b169a6bSchristos 
8224b169a6bSchristos   /* Copy over the FRE start address.  */
8234b169a6bSchristos   sframe_decode_fre_start_address (fre_buf, &fre->fre_start_addr, fre_type);
8244b169a6bSchristos 
8254b169a6bSchristos   addr_size = sframe_fre_start_addr_size (fre_type);
826*6817db7fSchristos   fre->fre_info = *(uint8_t *)(fre_buf + addr_size);
8274b169a6bSchristos   /* Sanity check as the API works closely with the binary format.  */
828*6817db7fSchristos   sframe_assert (sizeof (fre->fre_info) == sizeof (uint8_t));
8294b169a6bSchristos 
8304b169a6bSchristos   /* Cleanup the space for fre_offsets first, then copy over the valid
8314b169a6bSchristos      bytes.  */
8324b169a6bSchristos   memset (fre->fre_offsets, 0, MAX_OFFSET_BYTES);
8334b169a6bSchristos   /* Get offsets size.  */
8344b169a6bSchristos   stack_offsets_sz = sframe_fre_offset_bytes_size (fre->fre_info);
835*6817db7fSchristos   stack_offsets = fre_buf + addr_size + sizeof (fre->fre_info);
8364b169a6bSchristos   memcpy (fre->fre_offsets, stack_offsets, stack_offsets_sz);
8374b169a6bSchristos 
8384b169a6bSchristos   /* The FRE has been decoded.  Use it to perform one last sanity check.  */
8394b169a6bSchristos   fre_size = sframe_fre_entry_size (fre, fre_type);
8404b169a6bSchristos   sframe_assert (fre_size == (addr_size + sizeof (fre->fre_info)
8414b169a6bSchristos 			      + stack_offsets_sz));
8424b169a6bSchristos   *esz = fre_size;
8434b169a6bSchristos 
8444b169a6bSchristos   return 0;
8454b169a6bSchristos }
8464b169a6bSchristos 
8474b169a6bSchristos /* Decode the specified SFrame buffer CF_BUF of size CF_SIZE and return the
8484b169a6bSchristos    new SFrame decoder context.
8494b169a6bSchristos 
8504b169a6bSchristos    Sets ERRP for the caller if any error.  Frees up the allocated memory in
8514b169a6bSchristos    case of error.  */
8524b169a6bSchristos 
8534b169a6bSchristos sframe_decoder_ctx *
8544b169a6bSchristos sframe_decode (const char *sf_buf, size_t sf_size, int *errp)
8554b169a6bSchristos {
8564b169a6bSchristos   const sframe_preamble *sfp;
8574b169a6bSchristos   size_t hdrsz;
8584b169a6bSchristos   sframe_header *sfheaderp;
8594b169a6bSchristos   sframe_decoder_ctx *dctx;
8604b169a6bSchristos   char *frame_buf;
8614b169a6bSchristos   char *tempbuf = NULL;
8624b169a6bSchristos 
8634b169a6bSchristos   int fidx_size;
8644b169a6bSchristos   uint32_t fre_bytes;
8654b169a6bSchristos   int foreign_endian = 0;
8664b169a6bSchristos 
8674b169a6bSchristos   sframe_init_debug ();
8684b169a6bSchristos 
8694b169a6bSchristos   if ((sf_buf == NULL) || (!sf_size))
8704b169a6bSchristos     return sframe_ret_set_errno (errp, SFRAME_ERR_INVAL);
8714b169a6bSchristos   else if (sf_size < sizeof (sframe_header))
8724b169a6bSchristos     return sframe_ret_set_errno (errp, SFRAME_ERR_BUF_INVAL);
8734b169a6bSchristos 
8744b169a6bSchristos   sfp = (const sframe_preamble *) sf_buf;
8754b169a6bSchristos 
8764b169a6bSchristos   debug_printf ("sframe_decode: magic=0x%x version=%u flags=%u\n",
8774b169a6bSchristos 		sfp->sfp_magic, sfp->sfp_version, sfp->sfp_flags);
8784b169a6bSchristos 
8794b169a6bSchristos   /* Check for foreign endianness.  */
8804b169a6bSchristos   if (sfp->sfp_magic != SFRAME_MAGIC)
8814b169a6bSchristos     {
8824b169a6bSchristos       if (sfp->sfp_magic == bswap_16 (SFRAME_MAGIC))
8834b169a6bSchristos 	foreign_endian = 1;
8844b169a6bSchristos       else
8854b169a6bSchristos 	return sframe_ret_set_errno (errp, SFRAME_ERR_BUF_INVAL);
8864b169a6bSchristos     }
8874b169a6bSchristos 
8884b169a6bSchristos   /* Initialize a new decoder context.  */
8894b169a6bSchristos   if ((dctx = malloc (sizeof (sframe_decoder_ctx))) == NULL)
8904b169a6bSchristos     return sframe_ret_set_errno (errp, SFRAME_ERR_NOMEM);
8914b169a6bSchristos   memset (dctx, 0, sizeof (sframe_decoder_ctx));
8924b169a6bSchristos 
8934b169a6bSchristos   if (foreign_endian)
8944b169a6bSchristos     {
8954b169a6bSchristos       /* Allocate a new buffer and initialize it.  */
8964b169a6bSchristos       tempbuf = (char *) malloc (sf_size * sizeof (char));
8974b169a6bSchristos       if (tempbuf == NULL)
8984b169a6bSchristos 	return sframe_ret_set_errno (errp, SFRAME_ERR_NOMEM);
8994b169a6bSchristos       memcpy (tempbuf, sf_buf, sf_size);
9004b169a6bSchristos 
9014b169a6bSchristos       /* Flip the header.  */
9024b169a6bSchristos       sframe_header *ihp = (sframe_header *) tempbuf;
9034b169a6bSchristos       flip_header (ihp);
9044b169a6bSchristos       /* Flip the rest of the SFrame section data buffer.  */
9054b169a6bSchristos       if (flip_sframe (tempbuf, sf_size, 0))
9064b169a6bSchristos 	{
9074b169a6bSchristos 	  free (tempbuf);
9084b169a6bSchristos 	  return sframe_ret_set_errno (errp, SFRAME_ERR_BUF_INVAL);
9094b169a6bSchristos 	}
9104b169a6bSchristos       frame_buf = tempbuf;
911*6817db7fSchristos       /* This buffer is malloc'd when endian flipping the contents of the input
912*6817db7fSchristos 	 buffer are needed.  Keep a reference to it so it can be free'd up
913*6817db7fSchristos 	 later in sframe_decoder_free ().  */
914*6817db7fSchristos       dctx->sfd_buf = tempbuf;
9154b169a6bSchristos     }
9164b169a6bSchristos   else
9174b169a6bSchristos     frame_buf = (char *)sf_buf;
9184b169a6bSchristos 
9194b169a6bSchristos   /* Handle the SFrame header.  */
9204b169a6bSchristos   dctx->sfd_header = *(sframe_header *) frame_buf;
9214b169a6bSchristos   /* Validate the contents of SFrame header.  */
9224b169a6bSchristos   sfheaderp = &dctx->sfd_header;
9234b169a6bSchristos   if (!sframe_header_sanity_check_p (sfheaderp))
9244b169a6bSchristos     {
9254b169a6bSchristos       sframe_ret_set_errno (errp, SFRAME_ERR_NOMEM);
9264b169a6bSchristos       goto decode_fail_free;
9274b169a6bSchristos     }
9284b169a6bSchristos   hdrsz = sframe_get_hdr_size (sfheaderp);
9294b169a6bSchristos   frame_buf += hdrsz;
9304b169a6bSchristos 
9314b169a6bSchristos   /* Handle the SFrame Function Descriptor Entry section.  */
9324b169a6bSchristos   fidx_size
9334b169a6bSchristos     = sfheaderp->sfh_num_fdes * sizeof (sframe_func_desc_entry);
9344b169a6bSchristos   dctx->sfd_funcdesc = malloc (fidx_size);
9354b169a6bSchristos   if (dctx->sfd_funcdesc == NULL)
9364b169a6bSchristos     {
9374b169a6bSchristos       sframe_ret_set_errno (errp, SFRAME_ERR_NOMEM);
9384b169a6bSchristos       goto decode_fail_free;
9394b169a6bSchristos     }
9404b169a6bSchristos   memcpy (dctx->sfd_funcdesc, frame_buf, fidx_size);
9414b169a6bSchristos 
9424b169a6bSchristos   debug_printf ("%u total fidx size\n", fidx_size);
9434b169a6bSchristos 
9444b169a6bSchristos   frame_buf += (fidx_size);
9454b169a6bSchristos 
9464b169a6bSchristos   /* Handle the SFrame Frame Row Entry section.  */
947*6817db7fSchristos   dctx->sfd_fres = (char *) malloc (sfheaderp->sfh_fre_len);
9484b169a6bSchristos   if (dctx->sfd_fres == NULL)
9494b169a6bSchristos     {
9504b169a6bSchristos       sframe_ret_set_errno (errp, SFRAME_ERR_NOMEM);
9514b169a6bSchristos       goto decode_fail_free;
9524b169a6bSchristos     }
9534b169a6bSchristos   memcpy (dctx->sfd_fres, frame_buf, sfheaderp->sfh_fre_len);
9544b169a6bSchristos 
9554b169a6bSchristos   fre_bytes = sfheaderp->sfh_fre_len;
9564b169a6bSchristos   dctx->sfd_fre_nbytes = fre_bytes;
9574b169a6bSchristos 
9584b169a6bSchristos   debug_printf ("%u total fre bytes\n", fre_bytes);
9594b169a6bSchristos 
9604b169a6bSchristos   return dctx;
9614b169a6bSchristos 
9624b169a6bSchristos decode_fail_free:
9634b169a6bSchristos   if (foreign_endian && tempbuf != NULL)
9644b169a6bSchristos     free (tempbuf);
9654b169a6bSchristos   sframe_decoder_free (&dctx);
9664b169a6bSchristos   dctx = NULL;
9674b169a6bSchristos   return dctx;
9684b169a6bSchristos }
9694b169a6bSchristos 
9704b169a6bSchristos /* Get the size of the SFrame header from the decoder context CTX.  */
9714b169a6bSchristos 
9724b169a6bSchristos unsigned int
9734b169a6bSchristos sframe_decoder_get_hdr_size (sframe_decoder_ctx *ctx)
9744b169a6bSchristos {
9754b169a6bSchristos   sframe_header *dhp;
9764b169a6bSchristos   dhp = sframe_decoder_get_header (ctx);
9774b169a6bSchristos   return sframe_get_hdr_size (dhp);
9784b169a6bSchristos }
9794b169a6bSchristos 
980*6817db7fSchristos /* Get the SFrame's abi/arch info given the decoder context DCTX.  */
9814b169a6bSchristos 
982*6817db7fSchristos uint8_t
983*6817db7fSchristos sframe_decoder_get_abi_arch (sframe_decoder_ctx *dctx)
9844b169a6bSchristos {
9854b169a6bSchristos   sframe_header *sframe_header;
986*6817db7fSchristos   sframe_header = sframe_decoder_get_header (dctx);
9874b169a6bSchristos   return sframe_header->sfh_abi_arch;
9884b169a6bSchristos }
9894b169a6bSchristos 
990*6817db7fSchristos /* Get the format version from the SFrame decoder context DCTX.  */
991*6817db7fSchristos 
992*6817db7fSchristos uint8_t
993*6817db7fSchristos sframe_decoder_get_version (sframe_decoder_ctx *dctx)
994*6817db7fSchristos {
995*6817db7fSchristos   sframe_header *dhp;
996*6817db7fSchristos   dhp = sframe_decoder_get_header (dctx);
997*6817db7fSchristos   return dhp->sfh_preamble.sfp_version;
998*6817db7fSchristos }
999*6817db7fSchristos 
10004b169a6bSchristos /* Get the SFrame's fixed FP offset given the decoder context CTX.  */
10014b169a6bSchristos int8_t
10024b169a6bSchristos sframe_decoder_get_fixed_fp_offset (sframe_decoder_ctx *ctx)
10034b169a6bSchristos {
10044b169a6bSchristos   sframe_header *dhp;
10054b169a6bSchristos   dhp = sframe_decoder_get_header (ctx);
10064b169a6bSchristos   return dhp->sfh_cfa_fixed_fp_offset;
10074b169a6bSchristos }
10084b169a6bSchristos 
10094b169a6bSchristos /* Get the SFrame's fixed RA offset given the decoder context CTX.  */
10104b169a6bSchristos int8_t
10114b169a6bSchristos sframe_decoder_get_fixed_ra_offset (sframe_decoder_ctx *ctx)
10124b169a6bSchristos {
10134b169a6bSchristos   sframe_header *dhp;
10144b169a6bSchristos   dhp = sframe_decoder_get_header (ctx);
10154b169a6bSchristos   return dhp->sfh_cfa_fixed_ra_offset;
10164b169a6bSchristos }
10174b169a6bSchristos 
1018*6817db7fSchristos /* Find the function descriptor entry which contains the specified address
1019*6817db7fSchristos    ADDR.
1020*6817db7fSchristos    This function is deprecated and will be removed from libsframe.so.2.  */
1021*6817db7fSchristos 
1022*6817db7fSchristos void *
1023*6817db7fSchristos sframe_get_funcdesc_with_addr (sframe_decoder_ctx *ctx __attribute__ ((unused)),
1024*6817db7fSchristos 			       int32_t addr __attribute__ ((unused)),
1025*6817db7fSchristos 			       int *errp)
1026*6817db7fSchristos {
1027*6817db7fSchristos   return sframe_ret_set_errno (errp, SFRAME_ERR_INVAL);
1028*6817db7fSchristos }
1029*6817db7fSchristos 
10304b169a6bSchristos /* Find the function descriptor entry starting which contains the specified
10314b169a6bSchristos    address ADDR.  */
10324b169a6bSchristos 
1033*6817db7fSchristos static sframe_func_desc_entry *
1034*6817db7fSchristos sframe_get_funcdesc_with_addr_internal (sframe_decoder_ctx *ctx, int32_t addr,
1035*6817db7fSchristos 					int *errp)
10364b169a6bSchristos {
10374b169a6bSchristos   sframe_header *dhp;
10384b169a6bSchristos   sframe_func_desc_entry *fdp;
10394b169a6bSchristos   int low, high, cnt;
10404b169a6bSchristos 
10414b169a6bSchristos   if (ctx == NULL)
10424b169a6bSchristos     return sframe_ret_set_errno (errp, SFRAME_ERR_INVAL);
10434b169a6bSchristos 
10444b169a6bSchristos   dhp = sframe_decoder_get_header (ctx);
10454b169a6bSchristos 
10464b169a6bSchristos   if (dhp == NULL || dhp->sfh_num_fdes == 0 || ctx->sfd_funcdesc == NULL)
10474b169a6bSchristos     return sframe_ret_set_errno (errp, SFRAME_ERR_DCTX_INVAL);
10484b169a6bSchristos   /* If the FDE sub-section is not sorted on PCs, skip the lookup because
10494b169a6bSchristos      binary search cannot be used.  */
10504b169a6bSchristos   if ((dhp->sfh_preamble.sfp_flags & SFRAME_F_FDE_SORTED) == 0)
10514b169a6bSchristos     return sframe_ret_set_errno (errp, SFRAME_ERR_FDE_NOTSORTED);
10524b169a6bSchristos 
10534b169a6bSchristos   /* Do the binary search.  */
10544b169a6bSchristos   fdp = (sframe_func_desc_entry *) ctx->sfd_funcdesc;
10554b169a6bSchristos   low = 0;
10564b169a6bSchristos   high = dhp->sfh_num_fdes;
10574b169a6bSchristos   cnt = high;
10584b169a6bSchristos   while (low <= high)
10594b169a6bSchristos     {
10604b169a6bSchristos       int mid = low + (high - low) / 2;
10614b169a6bSchristos 
10624b169a6bSchristos       if (fdp[mid].sfde_func_start_address == addr)
10634b169a6bSchristos 	return fdp + mid;
10644b169a6bSchristos 
10654b169a6bSchristos       if (fdp[mid].sfde_func_start_address < addr)
10664b169a6bSchristos 	{
10674b169a6bSchristos 	  if (mid == (cnt - 1)) 	/* Check if it's the last one.  */
10684b169a6bSchristos 	    return fdp + (cnt - 1);
10694b169a6bSchristos 	  else if (fdp[mid+1].sfde_func_start_address > addr)
10704b169a6bSchristos 	    return fdp + mid;
10714b169a6bSchristos 	  low = mid + 1;
10724b169a6bSchristos 	}
10734b169a6bSchristos       else
10744b169a6bSchristos 	high = mid - 1;
10754b169a6bSchristos     }
10764b169a6bSchristos 
10774b169a6bSchristos   return sframe_ret_set_errno (errp, SFRAME_ERR_FDE_NOTFOUND);
10784b169a6bSchristos }
10794b169a6bSchristos 
1080*6817db7fSchristos /* Get the end IP offset for the FRE at index i in the FDEP.  The buffer FRES
1081*6817db7fSchristos    is the starting location for the FRE.  */
1082*6817db7fSchristos 
1083*6817db7fSchristos static uint32_t
1084*6817db7fSchristos sframe_fre_get_end_ip_offset (sframe_func_desc_entry *fdep, unsigned int i,
1085*6817db7fSchristos 			      const char *fres)
1086*6817db7fSchristos {
1087*6817db7fSchristos   uint32_t end_ip_offset;
1088*6817db7fSchristos   uint32_t fre_type;
1089*6817db7fSchristos 
1090*6817db7fSchristos   fre_type = sframe_get_fre_type (fdep);
1091*6817db7fSchristos 
1092*6817db7fSchristos   /* Get the start address of the next FRE in sequence.  */
1093*6817db7fSchristos   if (i < fdep->sfde_func_num_fres - 1)
1094*6817db7fSchristos     {
1095*6817db7fSchristos       sframe_decode_fre_start_address (fres, &end_ip_offset, fre_type);
1096*6817db7fSchristos       end_ip_offset -= 1;
1097*6817db7fSchristos     }
1098*6817db7fSchristos   else
1099*6817db7fSchristos     /* The end IP offset for the FRE needs to be deduced from the function
1100*6817db7fSchristos        size.  */
1101*6817db7fSchristos     end_ip_offset = fdep->sfde_func_size - 1;
1102*6817db7fSchristos 
1103*6817db7fSchristos   return end_ip_offset;
1104*6817db7fSchristos }
1105*6817db7fSchristos 
11064b169a6bSchristos /* Find the SFrame Row Entry which contains the PC.  Returns
11074b169a6bSchristos    SFRAME_ERR if failure.  */
11084b169a6bSchristos 
11094b169a6bSchristos int
11104b169a6bSchristos sframe_find_fre (sframe_decoder_ctx *ctx, int32_t pc,
11114b169a6bSchristos 		 sframe_frame_row_entry *frep)
11124b169a6bSchristos {
1113*6817db7fSchristos   sframe_frame_row_entry cur_fre;
11144b169a6bSchristos   sframe_func_desc_entry *fdep;
1115*6817db7fSchristos   uint32_t fre_type, fde_type, i;
1116*6817db7fSchristos   int32_t start_ip_offset;
1117*6817db7fSchristos   int32_t func_start_addr;
1118*6817db7fSchristos   int32_t end_ip_offset;
1119*6817db7fSchristos   const char *fres;
11204b169a6bSchristos   size_t size = 0;
1121*6817db7fSchristos   int err = 0;
1122*6817db7fSchristos   bool mask_p;
11234b169a6bSchristos 
11244b169a6bSchristos   if ((ctx == NULL) || (frep == NULL))
11254b169a6bSchristos     return sframe_set_errno (&err, SFRAME_ERR_INVAL);
11264b169a6bSchristos 
11274b169a6bSchristos   /* Find the FDE which contains the PC, then scan its fre entries.  */
1128*6817db7fSchristos   fdep = sframe_get_funcdesc_with_addr_internal (ctx, pc, &err);
11294b169a6bSchristos   if (fdep == NULL || ctx->sfd_fres == NULL)
11304b169a6bSchristos     return sframe_set_errno (&err, SFRAME_ERR_DCTX_INVAL);
11314b169a6bSchristos 
11324b169a6bSchristos   fre_type = sframe_get_fre_type (fdep);
11334b169a6bSchristos   fde_type = sframe_get_fde_type (fdep);
1134*6817db7fSchristos   mask_p = (fde_type == SFRAME_FDE_TYPE_PCMASK);
11354b169a6bSchristos 
1136*6817db7fSchristos   fres = ctx->sfd_fres + fdep->sfde_func_start_fre_off;
1137*6817db7fSchristos   func_start_addr = fdep->sfde_func_start_address;
11384b169a6bSchristos 
11394b169a6bSchristos   for (i = 0; i < fdep->sfde_func_num_fres; i++)
11404b169a6bSchristos    {
1141*6817db7fSchristos      err = sframe_decode_fre (fres, &cur_fre, fre_type, &size);
1142*6817db7fSchristos      if (err)
11434b169a6bSchristos        return sframe_set_errno (&err, SFRAME_ERR_FRE_INVAL);
11444b169a6bSchristos 
1145*6817db7fSchristos      start_ip_offset = cur_fre.fre_start_addr;
1146*6817db7fSchristos      end_ip_offset = sframe_fre_get_end_ip_offset (fdep, i, fres + size);
11474b169a6bSchristos 
1148*6817db7fSchristos      /* First FRE's start_ip must be more than pc for regular SFrame FDEs.  */
1149*6817db7fSchristos      if (i == 0 && !mask_p && (start_ip_offset + func_start_addr) > pc)
1150*6817db7fSchristos        return sframe_set_errno (&err, SFRAME_ERR_FRE_INVAL);
1151*6817db7fSchristos 
1152*6817db7fSchristos      if (sframe_fre_check_range_p (fdep, start_ip_offset, end_ip_offset, pc))
11534b169a6bSchristos        {
11544b169a6bSchristos 	 sframe_frame_row_entry_copy (frep, &cur_fre);
11554b169a6bSchristos 	 return 0;
11564b169a6bSchristos        }
1157*6817db7fSchristos      fres += size;
11584b169a6bSchristos    }
11594b169a6bSchristos   return sframe_set_errno (&err, SFRAME_ERR_FDE_INVAL);
11604b169a6bSchristos }
11614b169a6bSchristos 
11624b169a6bSchristos /* Return the number of function descriptor entries in the SFrame decoder
11634b169a6bSchristos    DCTX.  */
11644b169a6bSchristos 
1165*6817db7fSchristos uint32_t
11664b169a6bSchristos sframe_decoder_get_num_fidx (sframe_decoder_ctx *ctx)
11674b169a6bSchristos {
1168*6817db7fSchristos   uint32_t num_fdes = 0;
11694b169a6bSchristos   sframe_header *dhp = NULL;
11704b169a6bSchristos   dhp = sframe_decoder_get_header (ctx);
11714b169a6bSchristos   if (dhp)
11724b169a6bSchristos     num_fdes = dhp->sfh_num_fdes;
11734b169a6bSchristos   return num_fdes;
11744b169a6bSchristos }
11754b169a6bSchristos 
11764b169a6bSchristos /* Get the data (NUM_FRES, FUNC_START_ADDRESS) from the function
11774b169a6bSchristos    descriptor entry at index I'th in the decoder CTX.  If failed,
11784b169a6bSchristos    return error code.  */
11794b169a6bSchristos /* FIXME - consolidate the args and return a
11804b169a6bSchristos    sframe_func_desc_index_elem rather?  */
11814b169a6bSchristos 
11824b169a6bSchristos int
11834b169a6bSchristos sframe_decoder_get_funcdesc (sframe_decoder_ctx *ctx,
11844b169a6bSchristos 			     unsigned int i,
11854b169a6bSchristos 			     uint32_t *num_fres,
11864b169a6bSchristos 			     uint32_t *func_size,
11874b169a6bSchristos 			     int32_t *func_start_address,
11884b169a6bSchristos 			     unsigned char *func_info)
11894b169a6bSchristos {
11904b169a6bSchristos   sframe_func_desc_entry *fdp;
11914b169a6bSchristos   int err = 0;
11924b169a6bSchristos 
11934b169a6bSchristos   if (ctx == NULL || func_start_address == NULL || num_fres == NULL
11944b169a6bSchristos       || func_size == NULL)
11954b169a6bSchristos     return sframe_set_errno (&err, SFRAME_ERR_INVAL);
11964b169a6bSchristos 
1197*6817db7fSchristos   fdp = sframe_decoder_get_funcdesc_at_index (ctx, i);
11984b169a6bSchristos 
1199*6817db7fSchristos   if (fdp == NULL)
1200*6817db7fSchristos     return sframe_set_errno (&err, SFRAME_ERR_FDE_NOTFOUND);
1201*6817db7fSchristos 
12024b169a6bSchristos   *num_fres = fdp->sfde_func_num_fres;
12034b169a6bSchristos   *func_start_address = fdp->sfde_func_start_address;
12044b169a6bSchristos   *func_size = fdp->sfde_func_size;
12054b169a6bSchristos   *func_info = fdp->sfde_func_info;
12064b169a6bSchristos 
12074b169a6bSchristos   return 0;
12084b169a6bSchristos }
12094b169a6bSchristos 
1210*6817db7fSchristos int
1211*6817db7fSchristos sframe_decoder_get_funcdesc_v2 (sframe_decoder_ctx *dctx,
1212*6817db7fSchristos 				unsigned int i,
1213*6817db7fSchristos 				uint32_t *num_fres,
1214*6817db7fSchristos 				uint32_t *func_size,
1215*6817db7fSchristos 				int32_t *func_start_address,
1216*6817db7fSchristos 				unsigned char *func_info,
1217*6817db7fSchristos 				uint8_t *rep_block_size)
12184b169a6bSchristos {
1219*6817db7fSchristos   sframe_func_desc_entry *fdp;
1220*6817db7fSchristos   int err = 0;
12214b169a6bSchristos 
1222*6817db7fSchristos   if (dctx == NULL || func_start_address == NULL
1223*6817db7fSchristos       || num_fres == NULL || func_size == NULL
1224*6817db7fSchristos       || sframe_decoder_get_version (dctx) == SFRAME_VERSION_1)
1225*6817db7fSchristos     return sframe_set_errno (&err, SFRAME_ERR_INVAL);
1226*6817db7fSchristos 
1227*6817db7fSchristos   fdp = sframe_decoder_get_funcdesc_at_index (dctx, i);
1228*6817db7fSchristos 
1229*6817db7fSchristos   if (fdp == NULL)
1230*6817db7fSchristos     return sframe_set_errno (&err, SFRAME_ERR_FDE_NOTFOUND);
1231*6817db7fSchristos 
1232*6817db7fSchristos   *num_fres = fdp->sfde_func_num_fres;
1233*6817db7fSchristos   *func_start_address = fdp->sfde_func_start_address;
1234*6817db7fSchristos   *func_size = fdp->sfde_func_size;
1235*6817db7fSchristos   *func_info = fdp->sfde_func_info;
1236*6817db7fSchristos   *rep_block_size = fdp->sfde_func_rep_size;
1237*6817db7fSchristos 
1238*6817db7fSchristos   return 0;
12394b169a6bSchristos }
12404b169a6bSchristos /* Get the FRE_IDX'th FRE of the function at FUNC_IDX'th function
12414b169a6bSchristos    descriptor entry in the SFrame decoder CTX.  Returns error code as
12424b169a6bSchristos    applicable.  */
12434b169a6bSchristos 
12444b169a6bSchristos int
12454b169a6bSchristos sframe_decoder_get_fre (sframe_decoder_ctx *ctx,
12464b169a6bSchristos 			unsigned int func_idx,
12474b169a6bSchristos 			unsigned int fre_idx,
12484b169a6bSchristos 			sframe_frame_row_entry *fre)
12494b169a6bSchristos {
12504b169a6bSchristos   sframe_func_desc_entry *fdep;
12514b169a6bSchristos   sframe_frame_row_entry ifre;
1252*6817db7fSchristos   const char *fres;
12534b169a6bSchristos   uint32_t i;
1254*6817db7fSchristos   uint32_t fre_type;
12554b169a6bSchristos   size_t esz = 0;
12564b169a6bSchristos   int err = 0;
12574b169a6bSchristos 
12584b169a6bSchristos   if (ctx == NULL || fre == NULL)
12594b169a6bSchristos     return sframe_set_errno (&err, SFRAME_ERR_INVAL);
12604b169a6bSchristos 
12614b169a6bSchristos   /* Get function descriptor entry at index func_idx.  */
12624b169a6bSchristos   fdep = sframe_decoder_get_funcdesc_at_index (ctx, func_idx);
12634b169a6bSchristos 
12644b169a6bSchristos   if (fdep == NULL)
12654b169a6bSchristos     return sframe_set_errno (&err, SFRAME_ERR_FDE_NOTFOUND);
12664b169a6bSchristos 
12674b169a6bSchristos   fre_type = sframe_get_fre_type (fdep);
12684b169a6bSchristos   /* Now scan the FRE entries.  */
1269*6817db7fSchristos   fres = ctx->sfd_fres + fdep->sfde_func_start_fre_off;
12704b169a6bSchristos   for (i = 0; i < fdep->sfde_func_num_fres; i++)
12714b169a6bSchristos    {
12724b169a6bSchristos      /* Decode the FRE at the current position.  Return it if valid.  */
1273*6817db7fSchristos      err = sframe_decode_fre (fres, &ifre, fre_type, &esz);
12744b169a6bSchristos      if (i == fre_idx)
12754b169a6bSchristos        {
12764b169a6bSchristos 	 if (!sframe_fre_sanity_check_p (&ifre))
12774b169a6bSchristos 	   return sframe_set_errno (&err, SFRAME_ERR_FRE_INVAL);
12784b169a6bSchristos 
12794b169a6bSchristos 	 sframe_frame_row_entry_copy (fre, &ifre);
12804b169a6bSchristos 
12814b169a6bSchristos 	 if (fdep->sfde_func_size)
12824b169a6bSchristos 	   sframe_assert (fre->fre_start_addr < fdep->sfde_func_size);
12834b169a6bSchristos 	 else
12844b169a6bSchristos 	   /* A SFrame FDE with func size equal to zero is possible.  */
12854b169a6bSchristos 	   sframe_assert (fre->fre_start_addr == fdep->sfde_func_size);
12864b169a6bSchristos 
12874b169a6bSchristos 	 return 0;
12884b169a6bSchristos        }
12894b169a6bSchristos      /* Next FRE.  */
1290*6817db7fSchristos      fres += esz;
12914b169a6bSchristos    }
12924b169a6bSchristos 
12934b169a6bSchristos   return sframe_set_errno (&err, SFRAME_ERR_FDE_NOTFOUND);
12944b169a6bSchristos }
12954b169a6bSchristos 
12964b169a6bSchristos 
12974b169a6bSchristos /* SFrame Encoder.  */
12984b169a6bSchristos 
12994b169a6bSchristos /* Get a reference to the ENCODER's SFrame header.  */
13004b169a6bSchristos 
13014b169a6bSchristos static sframe_header *
13024b169a6bSchristos sframe_encoder_get_header (sframe_encoder_ctx *encoder)
13034b169a6bSchristos {
13044b169a6bSchristos   sframe_header *hp = NULL;
13054b169a6bSchristos   if (encoder)
13064b169a6bSchristos     hp = &encoder->sfe_header;
13074b169a6bSchristos   return hp;
13084b169a6bSchristos }
13094b169a6bSchristos 
13104b169a6bSchristos static sframe_func_desc_entry *
13114b169a6bSchristos sframe_encoder_get_funcdesc_at_index (sframe_encoder_ctx *encoder,
13124b169a6bSchristos 				      uint32_t func_idx)
13134b169a6bSchristos {
13144b169a6bSchristos   sframe_func_desc_entry *fde = NULL;
13154b169a6bSchristos   if (func_idx < sframe_encoder_get_num_fidx (encoder))
13164b169a6bSchristos     {
1317*6817db7fSchristos       sf_fde_tbl *func_tbl = encoder->sfe_funcdesc;
13184b169a6bSchristos       fde = func_tbl->entry + func_idx;
13194b169a6bSchristos     }
13204b169a6bSchristos   return fde;
13214b169a6bSchristos }
13224b169a6bSchristos 
13234b169a6bSchristos /* Create an encoder context with the given SFrame format version VER, FLAGS
1324*6817db7fSchristos    and ABI information.  Uses the ABI specific FIXED_FP_OFFSET and
1325*6817db7fSchristos    FIXED_RA_OFFSET values as provided.  Sets errp if failure.  */
13264b169a6bSchristos 
13274b169a6bSchristos sframe_encoder_ctx *
1328*6817db7fSchristos sframe_encode (uint8_t ver, uint8_t flags, uint8_t abi_arch,
13294b169a6bSchristos 	       int8_t fixed_fp_offset, int8_t fixed_ra_offset, int *errp)
13304b169a6bSchristos {
13314b169a6bSchristos   sframe_header *hp;
1332*6817db7fSchristos   sframe_encoder_ctx *encoder;
13334b169a6bSchristos 
13344b169a6bSchristos   if (ver != SFRAME_VERSION)
13354b169a6bSchristos     return sframe_ret_set_errno (errp, SFRAME_ERR_VERSION_INVAL);
13364b169a6bSchristos 
1337*6817db7fSchristos   if ((encoder = malloc (sizeof (sframe_encoder_ctx))) == NULL)
13384b169a6bSchristos     return sframe_ret_set_errno (errp, SFRAME_ERR_NOMEM);
13394b169a6bSchristos 
1340*6817db7fSchristos   memset (encoder, 0, sizeof (sframe_encoder_ctx));
13414b169a6bSchristos 
13424b169a6bSchristos   /* Get the SFrame header and update it.  */
1343*6817db7fSchristos   hp = sframe_encoder_get_header (encoder);
13444b169a6bSchristos   hp->sfh_preamble.sfp_version = ver;
13454b169a6bSchristos   hp->sfh_preamble.sfp_magic = SFRAME_MAGIC;
13464b169a6bSchristos   hp->sfh_preamble.sfp_flags = flags;
13474b169a6bSchristos 
13484b169a6bSchristos   hp->sfh_abi_arch = abi_arch;
13494b169a6bSchristos   hp->sfh_cfa_fixed_fp_offset = fixed_fp_offset;
13504b169a6bSchristos   hp->sfh_cfa_fixed_ra_offset = fixed_ra_offset;
13514b169a6bSchristos 
1352*6817db7fSchristos   return encoder;
13534b169a6bSchristos }
13544b169a6bSchristos 
13554b169a6bSchristos /* Free the encoder context.  */
13564b169a6bSchristos 
13574b169a6bSchristos void
13584b169a6bSchristos sframe_encoder_free (sframe_encoder_ctx **encoder)
13594b169a6bSchristos {
13604b169a6bSchristos   if (encoder != NULL)
13614b169a6bSchristos     {
13624b169a6bSchristos       sframe_encoder_ctx *ectx = *encoder;
13634b169a6bSchristos       if (ectx == NULL)
13644b169a6bSchristos 	return;
13654b169a6bSchristos 
13664b169a6bSchristos       if (ectx->sfe_funcdesc != NULL)
13674b169a6bSchristos 	{
13684b169a6bSchristos 	  free (ectx->sfe_funcdesc);
13694b169a6bSchristos 	  ectx->sfe_funcdesc = NULL;
13704b169a6bSchristos 	}
13714b169a6bSchristos       if (ectx->sfe_fres != NULL)
13724b169a6bSchristos 	{
13734b169a6bSchristos 	  free (ectx->sfe_fres);
13744b169a6bSchristos 	  ectx->sfe_fres = NULL;
13754b169a6bSchristos 	}
13764b169a6bSchristos       if (ectx->sfe_data != NULL)
13774b169a6bSchristos 	{
13784b169a6bSchristos 	  free (ectx->sfe_data);
13794b169a6bSchristos 	  ectx->sfe_data = NULL;
13804b169a6bSchristos 	}
13814b169a6bSchristos 
13824b169a6bSchristos       free (*encoder);
13834b169a6bSchristos       *encoder = NULL;
13844b169a6bSchristos     }
13854b169a6bSchristos }
13864b169a6bSchristos 
13874b169a6bSchristos /* Get the size of the SFrame header from the encoder ctx ENCODER.  */
13884b169a6bSchristos 
13894b169a6bSchristos unsigned int
13904b169a6bSchristos sframe_encoder_get_hdr_size (sframe_encoder_ctx *encoder)
13914b169a6bSchristos {
13924b169a6bSchristos   sframe_header *ehp;
13934b169a6bSchristos   ehp = sframe_encoder_get_header (encoder);
13944b169a6bSchristos   return sframe_get_hdr_size (ehp);
13954b169a6bSchristos }
13964b169a6bSchristos 
13974b169a6bSchristos /* Get the abi/arch info from the SFrame encoder context ENCODER.  */
13984b169a6bSchristos 
1399*6817db7fSchristos uint8_t
14004b169a6bSchristos sframe_encoder_get_abi_arch (sframe_encoder_ctx *encoder)
14014b169a6bSchristos {
1402*6817db7fSchristos   uint8_t abi_arch = 0;
14034b169a6bSchristos   sframe_header *ehp;
14044b169a6bSchristos   ehp = sframe_encoder_get_header (encoder);
14054b169a6bSchristos   if (ehp)
14064b169a6bSchristos     abi_arch = ehp->sfh_abi_arch;
14074b169a6bSchristos   return abi_arch;
14084b169a6bSchristos }
14094b169a6bSchristos 
1410*6817db7fSchristos /* Get the format version from the SFrame encoder context ENCODER.  */
1411*6817db7fSchristos 
1412*6817db7fSchristos uint8_t
1413*6817db7fSchristos sframe_encoder_get_version (sframe_encoder_ctx *encoder)
1414*6817db7fSchristos {
1415*6817db7fSchristos   sframe_header *ehp;
1416*6817db7fSchristos   ehp = sframe_encoder_get_header (encoder);
1417*6817db7fSchristos   return ehp->sfh_preamble.sfp_version;
1418*6817db7fSchristos }
1419*6817db7fSchristos 
14204b169a6bSchristos /* Return the number of function descriptor entries in the SFrame encoder
14214b169a6bSchristos    ENCODER.  */
14224b169a6bSchristos 
1423*6817db7fSchristos uint32_t
14244b169a6bSchristos sframe_encoder_get_num_fidx (sframe_encoder_ctx *encoder)
14254b169a6bSchristos {
1426*6817db7fSchristos   uint32_t num_fdes = 0;
14274b169a6bSchristos   sframe_header *ehp = NULL;
14284b169a6bSchristos   ehp = sframe_encoder_get_header (encoder);
14294b169a6bSchristos   if (ehp)
14304b169a6bSchristos     num_fdes = ehp->sfh_num_fdes;
14314b169a6bSchristos   return num_fdes;
14324b169a6bSchristos }
14334b169a6bSchristos 
14344b169a6bSchristos /* Add an FRE to function at FUNC_IDX'th function descriptor entry in
14354b169a6bSchristos    the encoder context.  */
14364b169a6bSchristos 
14374b169a6bSchristos int
14384b169a6bSchristos sframe_encoder_add_fre (sframe_encoder_ctx *encoder,
14394b169a6bSchristos 			unsigned int func_idx,
14404b169a6bSchristos 			sframe_frame_row_entry *frep)
14414b169a6bSchristos {
14424b169a6bSchristos   sframe_header *ehp;
14434b169a6bSchristos   sframe_func_desc_entry *fdep;
14444b169a6bSchristos   sframe_frame_row_entry *ectx_frep;
14454b169a6bSchristos   size_t offsets_sz, esz;
1446*6817db7fSchristos   uint32_t fre_type;
14474b169a6bSchristos   size_t fre_tbl_sz;
14484b169a6bSchristos   int err = 0;
14494b169a6bSchristos 
14504b169a6bSchristos   if (encoder == NULL || frep == NULL)
14514b169a6bSchristos     return sframe_set_errno (&err, SFRAME_ERR_INVAL);
14524b169a6bSchristos   if (!sframe_fre_sanity_check_p (frep))
14534b169a6bSchristos     return sframe_set_errno (&err, SFRAME_ERR_FRE_INVAL);
14544b169a6bSchristos 
14554b169a6bSchristos   /* Use func_idx to gather the function descriptor entry.  */
14564b169a6bSchristos   fdep = sframe_encoder_get_funcdesc_at_index (encoder, func_idx);
14574b169a6bSchristos 
14584b169a6bSchristos   if (fdep == NULL)
14594b169a6bSchristos     return sframe_set_errno (&err, SFRAME_ERR_FDE_NOTFOUND);
14604b169a6bSchristos 
14614b169a6bSchristos   fre_type = sframe_get_fre_type (fdep);
1462*6817db7fSchristos   sf_fre_tbl *fre_tbl = encoder->sfe_fres;
14634b169a6bSchristos 
14644b169a6bSchristos   if (fre_tbl == NULL)
14654b169a6bSchristos     {
14664b169a6bSchristos       fre_tbl_sz = (sizeof (sf_fre_tbl)
14674b169a6bSchristos 		    + (number_of_entries * sizeof (sframe_frame_row_entry)));
14684b169a6bSchristos       fre_tbl = malloc (fre_tbl_sz);
14694b169a6bSchristos 
14704b169a6bSchristos       if (fre_tbl == NULL)
14714b169a6bSchristos 	{
14724b169a6bSchristos 	  sframe_set_errno (&err, SFRAME_ERR_NOMEM);
14734b169a6bSchristos 	  goto bad;		/* OOM.  */
14744b169a6bSchristos 	}
14754b169a6bSchristos       memset (fre_tbl, 0, fre_tbl_sz);
14764b169a6bSchristos       fre_tbl->alloced = number_of_entries;
14774b169a6bSchristos     }
14784b169a6bSchristos   else if (fre_tbl->count == fre_tbl->alloced)
14794b169a6bSchristos     {
14804b169a6bSchristos       fre_tbl_sz = (sizeof (sf_fre_tbl)
14814b169a6bSchristos 		    + ((fre_tbl->alloced + number_of_entries)
14824b169a6bSchristos 		       * sizeof (sframe_frame_row_entry)));
14834b169a6bSchristos       fre_tbl = realloc (fre_tbl, fre_tbl_sz);
14844b169a6bSchristos       if (fre_tbl == NULL)
14854b169a6bSchristos 	{
14864b169a6bSchristos 	  sframe_set_errno (&err, SFRAME_ERR_NOMEM);
14874b169a6bSchristos 	  goto bad;		/* OOM.  */
14884b169a6bSchristos 	}
14894b169a6bSchristos 
14904b169a6bSchristos       memset (&fre_tbl->entry[fre_tbl->alloced], 0,
14914b169a6bSchristos 	      number_of_entries * sizeof (sframe_frame_row_entry));
14924b169a6bSchristos       fre_tbl->alloced += number_of_entries;
14934b169a6bSchristos     }
14944b169a6bSchristos 
14954b169a6bSchristos   ectx_frep = &fre_tbl->entry[fre_tbl->count];
14964b169a6bSchristos   ectx_frep->fre_start_addr
14974b169a6bSchristos     = frep->fre_start_addr;
14984b169a6bSchristos   ectx_frep->fre_info = frep->fre_info;
14994b169a6bSchristos 
15004b169a6bSchristos   if (fdep->sfde_func_size)
15014b169a6bSchristos     sframe_assert (frep->fre_start_addr < fdep->sfde_func_size);
15024b169a6bSchristos   else
15034b169a6bSchristos     /* A SFrame FDE with func size equal to zero is possible.  */
15044b169a6bSchristos     sframe_assert (frep->fre_start_addr == fdep->sfde_func_size);
15054b169a6bSchristos 
15064b169a6bSchristos   /* frep has already been sanity check'd.  Get offsets size.  */
15074b169a6bSchristos   offsets_sz = sframe_fre_offset_bytes_size (frep->fre_info);
15084b169a6bSchristos   memcpy (&ectx_frep->fre_offsets, &frep->fre_offsets, offsets_sz);
15094b169a6bSchristos 
15104b169a6bSchristos   esz = sframe_fre_entry_size (frep, fre_type);
15114b169a6bSchristos   fre_tbl->count++;
15124b169a6bSchristos 
1513*6817db7fSchristos   encoder->sfe_fres = fre_tbl;
15144b169a6bSchristos   encoder->sfe_fre_nbytes += esz;
15154b169a6bSchristos 
15164b169a6bSchristos   ehp = sframe_encoder_get_header (encoder);
15174b169a6bSchristos   ehp->sfh_num_fres = fre_tbl->count;
15184b169a6bSchristos 
15194b169a6bSchristos   /* Update the value of the number of FREs for the function.  */
15204b169a6bSchristos   fdep->sfde_func_num_fres++;
15214b169a6bSchristos 
15224b169a6bSchristos   return 0;
15234b169a6bSchristos 
15244b169a6bSchristos bad:
15254b169a6bSchristos   if (fre_tbl != NULL)
15264b169a6bSchristos     free (fre_tbl);
15274b169a6bSchristos   encoder->sfe_fres = NULL;
15284b169a6bSchristos   encoder->sfe_fre_nbytes = 0;
15294b169a6bSchristos   return -1;
15304b169a6bSchristos }
15314b169a6bSchristos 
15324b169a6bSchristos /* Add a new function descriptor entry with START_ADDR, FUNC_SIZE and NUM_FRES
15334b169a6bSchristos    to the encoder.  */
15344b169a6bSchristos 
15354b169a6bSchristos int
15364b169a6bSchristos sframe_encoder_add_funcdesc (sframe_encoder_ctx *encoder,
15374b169a6bSchristos 			     int32_t start_addr,
15384b169a6bSchristos 			     uint32_t func_size,
15394b169a6bSchristos 			     unsigned char func_info,
15404b169a6bSchristos 			     uint32_t num_fres __attribute__ ((unused)))
15414b169a6bSchristos {
15424b169a6bSchristos   sframe_header *ehp;
1543*6817db7fSchristos   sf_fde_tbl *fd_info;
15444b169a6bSchristos   size_t fd_tbl_sz;
15454b169a6bSchristos   int err = 0;
15464b169a6bSchristos 
15474b169a6bSchristos   /* FIXME book-keep num_fres for error checking.  */
15484b169a6bSchristos   if (encoder == NULL)
15494b169a6bSchristos     return sframe_set_errno (&err, SFRAME_ERR_INVAL);
15504b169a6bSchristos 
1551*6817db7fSchristos   fd_info = encoder->sfe_funcdesc;
15524b169a6bSchristos   ehp = sframe_encoder_get_header (encoder);
15534b169a6bSchristos 
15544b169a6bSchristos   if (fd_info == NULL)
15554b169a6bSchristos     {
1556*6817db7fSchristos       fd_tbl_sz = (sizeof (sf_fde_tbl)
15574b169a6bSchristos 		   + (number_of_entries * sizeof (sframe_func_desc_entry)));
15584b169a6bSchristos       fd_info = malloc (fd_tbl_sz);
15594b169a6bSchristos       if (fd_info == NULL)
15604b169a6bSchristos 	{
15614b169a6bSchristos 	  sframe_set_errno (&err, SFRAME_ERR_NOMEM);
15624b169a6bSchristos 	  goto bad;		/* OOM.  */
15634b169a6bSchristos 	}
15644b169a6bSchristos       memset (fd_info, 0, fd_tbl_sz);
15654b169a6bSchristos       fd_info->alloced = number_of_entries;
15664b169a6bSchristos     }
15674b169a6bSchristos   else if (fd_info->count == fd_info->alloced)
15684b169a6bSchristos     {
1569*6817db7fSchristos       fd_tbl_sz = (sizeof (sf_fde_tbl)
15704b169a6bSchristos 		   + ((fd_info->alloced + number_of_entries)
15714b169a6bSchristos 		      * sizeof (sframe_func_desc_entry)));
15724b169a6bSchristos       fd_info = realloc (fd_info, fd_tbl_sz);
15734b169a6bSchristos       if (fd_info == NULL)
15744b169a6bSchristos 	{
15754b169a6bSchristos 	  sframe_set_errno (&err, SFRAME_ERR_NOMEM);
15764b169a6bSchristos 	  goto bad;		/* OOM.  */
15774b169a6bSchristos 	}
15784b169a6bSchristos 
15794b169a6bSchristos       memset (&fd_info->entry[fd_info->alloced], 0,
15804b169a6bSchristos 	      number_of_entries * sizeof (sframe_func_desc_entry));
15814b169a6bSchristos       fd_info->alloced += number_of_entries;
15824b169a6bSchristos     }
15834b169a6bSchristos 
15844b169a6bSchristos   fd_info->entry[fd_info->count].sfde_func_start_address = start_addr;
15854b169a6bSchristos   /* Num FREs is updated as FREs are added for the function later via
15864b169a6bSchristos      sframe_encoder_add_fre.  */
15874b169a6bSchristos   fd_info->entry[fd_info->count].sfde_func_size = func_size;
15884b169a6bSchristos   fd_info->entry[fd_info->count].sfde_func_start_fre_off
15894b169a6bSchristos     = encoder->sfe_fre_nbytes;
15904b169a6bSchristos #if 0
15914b169a6bSchristos   // Linker optimization test code cleanup later ibhagat TODO FIXME
1592*6817db7fSchristos   uint32_t fre_type = sframe_calc_fre_type (func_size);
15934b169a6bSchristos 
15944b169a6bSchristos   fd_info->entry[fd_info->count].sfde_func_info
15954b169a6bSchristos     = sframe_fde_func_info (fre_type);
15964b169a6bSchristos #endif
15974b169a6bSchristos   fd_info->entry[fd_info->count].sfde_func_info = func_info;
15984b169a6bSchristos   fd_info->count++;
1599*6817db7fSchristos   encoder->sfe_funcdesc = fd_info;
16004b169a6bSchristos   ehp->sfh_num_fdes++;
16014b169a6bSchristos   return 0;
16024b169a6bSchristos 
16034b169a6bSchristos bad:
16044b169a6bSchristos   if (fd_info != NULL)
16054b169a6bSchristos     free (fd_info);
16064b169a6bSchristos   encoder->sfe_funcdesc = NULL;
16074b169a6bSchristos   ehp->sfh_num_fdes = 0;
16084b169a6bSchristos   return -1;
16094b169a6bSchristos }
16104b169a6bSchristos 
1611*6817db7fSchristos /* Add a new function descriptor entry with START_ADDR, FUNC_SIZE, FUNC_INFO
1612*6817db7fSchristos    and REP_BLOCK_SIZE to the encoder.
1613*6817db7fSchristos 
1614*6817db7fSchristos    This API is valid only for SFrame format version 2.  */
1615*6817db7fSchristos 
1616*6817db7fSchristos int
1617*6817db7fSchristos sframe_encoder_add_funcdesc_v2 (sframe_encoder_ctx *encoder,
1618*6817db7fSchristos 				int32_t start_addr,
1619*6817db7fSchristos 				uint32_t func_size,
1620*6817db7fSchristos 				unsigned char func_info,
1621*6817db7fSchristos 				uint8_t rep_block_size,
1622*6817db7fSchristos 				uint32_t num_fres __attribute__ ((unused)))
1623*6817db7fSchristos {
1624*6817db7fSchristos   sf_fde_tbl *fd_info;
1625*6817db7fSchristos   int err;
1626*6817db7fSchristos 
1627*6817db7fSchristos   if (encoder == NULL
1628*6817db7fSchristos       || sframe_encoder_get_version (encoder) == SFRAME_VERSION_1)
1629*6817db7fSchristos     return sframe_set_errno (&err, SFRAME_ERR_INVAL);
1630*6817db7fSchristos 
1631*6817db7fSchristos   err = sframe_encoder_add_funcdesc (encoder, start_addr, func_size, func_info,
1632*6817db7fSchristos 				     num_fres);
1633*6817db7fSchristos   if (err)
1634*6817db7fSchristos     return SFRAME_ERR;
1635*6817db7fSchristos 
1636*6817db7fSchristos   fd_info = encoder->sfe_funcdesc;
1637*6817db7fSchristos   fd_info->entry[fd_info->count-1].sfde_func_rep_size = rep_block_size;
1638*6817db7fSchristos 
1639*6817db7fSchristos   return 0;
1640*6817db7fSchristos }
1641*6817db7fSchristos 
16424b169a6bSchristos static int
16434b169a6bSchristos sframe_sort_funcdesc (sframe_encoder_ctx *encoder)
16444b169a6bSchristos {
16454b169a6bSchristos   sframe_header *ehp;
16464b169a6bSchristos 
16474b169a6bSchristos   ehp = sframe_encoder_get_header (encoder);
16484b169a6bSchristos   /* Sort and write out the FDE table.  */
1649*6817db7fSchristos   sf_fde_tbl *fd_info = encoder->sfe_funcdesc;
16504b169a6bSchristos   if (fd_info)
16514b169a6bSchristos     {
16524b169a6bSchristos       qsort (fd_info->entry, fd_info->count,
16534b169a6bSchristos 	     sizeof (sframe_func_desc_entry), fde_func);
16544b169a6bSchristos       /* Update preamble's flags.  */
16554b169a6bSchristos       ehp->sfh_preamble.sfp_flags |= SFRAME_F_FDE_SORTED;
16564b169a6bSchristos     }
16574b169a6bSchristos   return 0;
16584b169a6bSchristos }
16594b169a6bSchristos 
1660*6817db7fSchristos /* Write the SFrame FRE start address from the in-memory FRE_START_ADDR
1661*6817db7fSchristos    to the buffer CONTENTS (on-disk format), given the FRE_TYPE and
1662*6817db7fSchristos    FRE_START_ADDR_SZ.  */
1663*6817db7fSchristos 
1664*6817db7fSchristos static int
1665*6817db7fSchristos sframe_encoder_write_fre_start_addr (char *contents,
1666*6817db7fSchristos 				     uint32_t fre_start_addr,
1667*6817db7fSchristos 				     uint32_t fre_type,
1668*6817db7fSchristos 				     size_t fre_start_addr_sz)
1669*6817db7fSchristos {
1670*6817db7fSchristos   int err = 0;
1671*6817db7fSchristos 
1672*6817db7fSchristos   if (fre_type == SFRAME_FRE_TYPE_ADDR1)
1673*6817db7fSchristos     {
1674*6817db7fSchristos       uint8_t uc = fre_start_addr;
1675*6817db7fSchristos       memcpy (contents, &uc, fre_start_addr_sz);
1676*6817db7fSchristos     }
1677*6817db7fSchristos   else if (fre_type == SFRAME_FRE_TYPE_ADDR2)
1678*6817db7fSchristos     {
1679*6817db7fSchristos       uint16_t ust = fre_start_addr;
1680*6817db7fSchristos       memcpy (contents, &ust, fre_start_addr_sz);
1681*6817db7fSchristos     }
1682*6817db7fSchristos   else if (fre_type == SFRAME_FRE_TYPE_ADDR4)
1683*6817db7fSchristos     {
1684*6817db7fSchristos       uint32_t uit = fre_start_addr;
1685*6817db7fSchristos       memcpy (contents, &uit, fre_start_addr_sz);
1686*6817db7fSchristos     }
1687*6817db7fSchristos   else
1688*6817db7fSchristos     return sframe_set_errno (&err, SFRAME_ERR_INVAL);
1689*6817db7fSchristos 
1690*6817db7fSchristos   return 0;
1691*6817db7fSchristos }
1692*6817db7fSchristos 
16934b169a6bSchristos /* Write a frame row entry pointed to by FREP into the buffer CONTENTS.  The
16944b169a6bSchristos    size in bytes written out are updated in ESZ.
16954b169a6bSchristos 
16964b169a6bSchristos    This function works closely with the SFrame binary format.
16974b169a6bSchristos 
16984b169a6bSchristos    Returns SFRAME_ERR if failure.  */
16994b169a6bSchristos 
17004b169a6bSchristos static int
17014b169a6bSchristos sframe_encoder_write_fre (char *contents, sframe_frame_row_entry *frep,
1702*6817db7fSchristos 			  uint32_t fre_type, size_t *esz)
17034b169a6bSchristos {
1704*6817db7fSchristos   size_t fre_sz;
17054b169a6bSchristos   size_t fre_start_addr_sz;
17064b169a6bSchristos   size_t fre_stack_offsets_sz;
17074b169a6bSchristos   int err = 0;
17084b169a6bSchristos 
17094b169a6bSchristos   if (!sframe_fre_sanity_check_p (frep))
17104b169a6bSchristos     return sframe_set_errno (&err, SFRAME_ERR_FRE_INVAL);
17114b169a6bSchristos 
17124b169a6bSchristos   fre_start_addr_sz = sframe_fre_start_addr_size (fre_type);
17134b169a6bSchristos   fre_stack_offsets_sz = sframe_fre_offset_bytes_size (frep->fre_info);
17144b169a6bSchristos 
17154b169a6bSchristos   /* The FRE start address must be encodable in the available number of
17164b169a6bSchristos      bytes.  */
17174b169a6bSchristos   uint64_t bitmask = SFRAME_BITMASK_OF_SIZE (fre_start_addr_sz);
17184b169a6bSchristos   sframe_assert ((uint64_t)frep->fre_start_addr <= bitmask);
17194b169a6bSchristos 
1720*6817db7fSchristos   sframe_encoder_write_fre_start_addr (contents, frep->fre_start_addr,
1721*6817db7fSchristos 				       fre_type, fre_start_addr_sz);
17224b169a6bSchristos   contents += fre_start_addr_sz;
17234b169a6bSchristos 
1724*6817db7fSchristos   memcpy (contents, &frep->fre_info, sizeof (frep->fre_info));
17254b169a6bSchristos   contents += sizeof (frep->fre_info);
17264b169a6bSchristos 
1727*6817db7fSchristos   memcpy (contents, frep->fre_offsets, fre_stack_offsets_sz);
17284b169a6bSchristos   contents+= fre_stack_offsets_sz;
17294b169a6bSchristos 
1730*6817db7fSchristos   fre_sz = sframe_fre_entry_size (frep, fre_type);
17314b169a6bSchristos   /* Sanity checking.  */
17324b169a6bSchristos   sframe_assert ((fre_start_addr_sz
17334b169a6bSchristos 		  + sizeof (frep->fre_info)
1734*6817db7fSchristos 		  + fre_stack_offsets_sz) == fre_sz);
17354b169a6bSchristos 
1736*6817db7fSchristos   *esz = fre_sz;
17374b169a6bSchristos 
17384b169a6bSchristos   return 0;
17394b169a6bSchristos }
17404b169a6bSchristos 
17414b169a6bSchristos /* Serialize the core contents of the SFrame section and write out to the
17424b169a6bSchristos    output buffer held in the ENCODER.  Return SFRAME_ERR if failure.  */
17434b169a6bSchristos 
17444b169a6bSchristos static int
17454b169a6bSchristos sframe_encoder_write_sframe (sframe_encoder_ctx *encoder)
17464b169a6bSchristos {
17474b169a6bSchristos   char *contents;
17484b169a6bSchristos   size_t buf_size;
17494b169a6bSchristos   size_t hdr_size;
17504b169a6bSchristos   size_t all_fdes_size;
17514b169a6bSchristos   size_t fre_size;
17524b169a6bSchristos   size_t esz = 0;
17534b169a6bSchristos   sframe_header *ehp;
17544b169a6bSchristos   unsigned char flags;
1755*6817db7fSchristos   sf_fde_tbl *fd_info;
17564b169a6bSchristos   sf_fre_tbl *fr_info;
17574b169a6bSchristos   uint32_t i, num_fdes;
17584b169a6bSchristos   uint32_t j, num_fres;
17594b169a6bSchristos   sframe_func_desc_entry *fdep;
17604b169a6bSchristos   sframe_frame_row_entry *frep;
17614b169a6bSchristos 
1762*6817db7fSchristos   uint32_t fre_type;
17634b169a6bSchristos   int err = 0;
17644b169a6bSchristos 
17654b169a6bSchristos   contents = encoder->sfe_data;
17664b169a6bSchristos   buf_size = encoder->sfe_data_size;
17674b169a6bSchristos   num_fdes = sframe_encoder_get_num_fidx (encoder);
17684b169a6bSchristos   all_fdes_size = num_fdes * sizeof (sframe_func_desc_entry);
17694b169a6bSchristos   ehp = sframe_encoder_get_header (encoder);
17704b169a6bSchristos   hdr_size = sframe_get_hdr_size (ehp);
17714b169a6bSchristos 
1772*6817db7fSchristos   fd_info = encoder->sfe_funcdesc;
1773*6817db7fSchristos   fr_info = encoder->sfe_fres;
17744b169a6bSchristos 
17754b169a6bSchristos   /* Sanity checks:
17764b169a6bSchristos      - buffers must be malloc'd by the caller.  */
17774b169a6bSchristos   if ((contents == NULL) || (buf_size < hdr_size))
17784b169a6bSchristos     return sframe_set_errno (&err, SFRAME_ERR_BUF_INVAL);
17794b169a6bSchristos   if (fr_info == NULL)
17804b169a6bSchristos     return sframe_set_errno (&err, SFRAME_ERR_FRE_INVAL);
17814b169a6bSchristos 
17824b169a6bSchristos   /* Write out the FRE table first.
17834b169a6bSchristos 
17844b169a6bSchristos      Recall that read/write of FREs needs information from the corresponding
17854b169a6bSchristos      FDE; the latter stores the information about the FRE type record used for
17864b169a6bSchristos      the function.  Also note that sorting of FDEs does NOT impact the order
17874b169a6bSchristos      in which FREs are stored in the SFrame's FRE sub-section.  This means
17884b169a6bSchristos      that writing out FREs after sorting of FDEs will need some additional
17894b169a6bSchristos      book-keeping.  At this time, we can afford to avoid it by writing out
17904b169a6bSchristos      the FREs first to the output buffer.  */
17914b169a6bSchristos   fre_size = 0;
17924b169a6bSchristos   uint32_t global = 0;
17934b169a6bSchristos   uint32_t fre_index = 0;
17944b169a6bSchristos 
17954b169a6bSchristos   contents += hdr_size + all_fdes_size;
17964b169a6bSchristos   for (i = 0; i < num_fdes; i++)
17974b169a6bSchristos     {
17984b169a6bSchristos       fdep = &fd_info->entry[i];
17994b169a6bSchristos       fre_type = sframe_get_fre_type (fdep);
18004b169a6bSchristos       num_fres = fdep->sfde_func_num_fres;
18014b169a6bSchristos 
18024b169a6bSchristos       for (j = 0; j < num_fres; j++)
18034b169a6bSchristos 	{
18044b169a6bSchristos 	  fre_index = global + j;
18054b169a6bSchristos 	  frep = &fr_info->entry[fre_index];
18064b169a6bSchristos 
18074b169a6bSchristos 	  sframe_encoder_write_fre (contents, frep, fre_type, &esz);
18084b169a6bSchristos 	  contents += esz;
18094b169a6bSchristos 	  fre_size += esz; /* For debugging only.  */
18104b169a6bSchristos 	}
18114b169a6bSchristos       global += j;
18124b169a6bSchristos     }
18134b169a6bSchristos 
18144b169a6bSchristos   sframe_assert (fre_size == ehp->sfh_fre_len);
18154b169a6bSchristos   sframe_assert (global == ehp->sfh_num_fres);
18164b169a6bSchristos   sframe_assert ((size_t)(contents - encoder->sfe_data) == buf_size);
18174b169a6bSchristos 
18184b169a6bSchristos   /* Sort the FDE table */
18194b169a6bSchristos   sframe_sort_funcdesc (encoder);
18204b169a6bSchristos 
18214b169a6bSchristos   /* Sanity checks:
18224b169a6bSchristos      - the FDE section must have been sorted by now on the start address
18234b169a6bSchristos      of each function.  */
18244b169a6bSchristos   flags = ehp->sfh_preamble.sfp_flags;
18254b169a6bSchristos   if (!(flags & SFRAME_F_FDE_SORTED)
18264b169a6bSchristos       || (fd_info == NULL))
18274b169a6bSchristos     return sframe_set_errno (&err, SFRAME_ERR_FDE_INVAL);
18284b169a6bSchristos 
18294b169a6bSchristos   contents = encoder->sfe_data;
18304b169a6bSchristos   /* Write out the SFrame header.  The SFrame header in the encoder
18314b169a6bSchristos      object has already been updated with correct offsets by the caller.  */
18324b169a6bSchristos   memcpy (contents, ehp, hdr_size);
18334b169a6bSchristos   contents += hdr_size;
18344b169a6bSchristos 
18354b169a6bSchristos   /* Write out the FDE table sorted on funtion start address.  */
18364b169a6bSchristos   memcpy (contents, fd_info->entry, all_fdes_size);
18374b169a6bSchristos   contents += all_fdes_size;
18384b169a6bSchristos 
18394b169a6bSchristos   return 0;
18404b169a6bSchristos }
18414b169a6bSchristos 
18424b169a6bSchristos /* Serialize the contents of the encoder and return the buffer.  ENCODED_SIZE
18434b169a6bSchristos    is updated to the size of the buffer.  */
18444b169a6bSchristos 
18454b169a6bSchristos char *
18464b169a6bSchristos sframe_encoder_write (sframe_encoder_ctx *encoder,
18474b169a6bSchristos 		      size_t *encoded_size, int *errp)
18484b169a6bSchristos {
18494b169a6bSchristos   sframe_header *ehp;
18504b169a6bSchristos   size_t hdrsize, fsz, fresz, bufsize;
18514b169a6bSchristos   int foreign_endian;
18524b169a6bSchristos 
18534b169a6bSchristos   /* Initialize the encoded_size to zero.  This makes it simpler to just
18544b169a6bSchristos      return from the function in case of failure.  Free'ing up of
18554b169a6bSchristos      encoder->sfe_data is the responsibility of the caller.  */
18564b169a6bSchristos   *encoded_size = 0;
18574b169a6bSchristos 
18584b169a6bSchristos   if (encoder == NULL || encoded_size == NULL || errp == NULL)
18594b169a6bSchristos     return sframe_ret_set_errno (errp, SFRAME_ERR_INVAL);
18604b169a6bSchristos 
18614b169a6bSchristos   ehp = sframe_encoder_get_header (encoder);
18624b169a6bSchristos   hdrsize = sframe_get_hdr_size (ehp);
18634b169a6bSchristos   fsz = sframe_encoder_get_num_fidx (encoder)
18644b169a6bSchristos     * sizeof (sframe_func_desc_entry);
18654b169a6bSchristos   fresz = encoder->sfe_fre_nbytes;
18664b169a6bSchristos 
18674b169a6bSchristos   /* The total size of buffer is the sum of header, SFrame Function Descriptor
18684b169a6bSchristos      Entries section and the FRE section.  */
18694b169a6bSchristos   bufsize = hdrsize + fsz + fresz;
18704b169a6bSchristos   encoder->sfe_data = (char *) malloc (bufsize);
18714b169a6bSchristos   if (encoder->sfe_data == NULL)
18724b169a6bSchristos     return sframe_ret_set_errno (errp, SFRAME_ERR_NOMEM);
18734b169a6bSchristos   encoder->sfe_data_size = bufsize;
18744b169a6bSchristos 
18754b169a6bSchristos   /* Update the information in the SFrame header.  */
18764b169a6bSchristos   /* SFrame FDE section follows immediately after the header.  */
18774b169a6bSchristos   ehp->sfh_fdeoff = 0;
18784b169a6bSchristos   /* SFrame FRE section follows immediately after the SFrame FDE section.  */
18794b169a6bSchristos   ehp->sfh_freoff = fsz;
18804b169a6bSchristos   ehp->sfh_fre_len = fresz;
18814b169a6bSchristos 
18824b169a6bSchristos   foreign_endian = need_swapping (ehp->sfh_abi_arch);
18834b169a6bSchristos 
18844b169a6bSchristos   /* Write out the FDE Index and the FRE table in the sfe_data. */
18854b169a6bSchristos   if (sframe_encoder_write_sframe (encoder))
18864b169a6bSchristos     return sframe_ret_set_errno (errp, SFRAME_ERR_BUF_INVAL);
18874b169a6bSchristos 
18884b169a6bSchristos   /* Endian flip the contents if necessary.  */
18894b169a6bSchristos   if (foreign_endian)
18904b169a6bSchristos     {
18914b169a6bSchristos       if (flip_sframe (encoder->sfe_data, bufsize, 1))
18924b169a6bSchristos 	return sframe_ret_set_errno (errp, SFRAME_ERR_BUF_INVAL);
18934b169a6bSchristos       flip_header ((sframe_header*)encoder->sfe_data);
18944b169a6bSchristos     }
18954b169a6bSchristos 
18964b169a6bSchristos   *encoded_size = bufsize;
18974b169a6bSchristos   return encoder->sfe_data;
18984b169a6bSchristos }
1899