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