Wolfgang Thallergcc16 merge934c3885 months agoHistory
2755 lines · 79.2 KB · C
RawDownload
/* sframe.c - SFrame decoder/encoder.    Copyright (C) 2022-2026 Free Software Foundation, Inc.    This file is part of libsframe.    This program is free software; you can redistribute it and/or modify   it under the terms of the GNU General Public License as published by   the Free Software Foundation; either version 3 of the License, or   (at your option) any later version.    This program is distributed in the hope that it will be useful,   but WITHOUT ANY WARRANTY; without even the implied warranty of   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the   GNU General Public License for more details.    You should have received a copy of the GNU General Public License   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */ #include "config.h"#include <stdio.h>#include <stdlib.h>#include <stdarg.h>#include <string.h>#include <stddef.h>#include "sframe-impl.h"#include "swap.h" /* Representation of SFrame FDE internal to libsframe.  */typedef struct sframe_func_desc_entry_int{  int64_t func_start_pc_offset;  uint32_t func_size;  uint32_t func_start_fre_off;  uint32_t func_num_fres;  uint8_t func_info;  uint8_t func_info2;  uint8_t func_rep_size;} sframe_func_desc_entry_int; struct sf_fde_tbl{  unsigned int count;  unsigned int alloced;  sframe_func_desc_entry_int entry[1];}; struct sf_fre_tbl{  unsigned int count;  unsigned int alloced;  sframe_frame_row_entry entry[1];}; #define _sf_printflike_(string_index,first_to_check) \    __attribute__ ((__format__ (__printf__, (string_index), (first_to_check)))) static void debug_printf (const char *, ...); static int _sframe_debug;	/* Control for printing out debug info.  */ #define SFRAME_FRE_ALLOC_LEN  64static int number_of_entries = 64; static voidsframe_init_debug (void){  static int inited;   if (!inited)    {      _sframe_debug = getenv ("SFRAME_DEBUG") != NULL;      inited = 1;    }} _sf_printflike_ (1, 2)static void debug_printf (const char *format, ...){  if (_sframe_debug)    {      va_list args;       va_start (args, format);      vfprintf (stderr, format, args);      va_end (args);    }} /* Generate bitmask of given size in bytes.  This is used for   some checks on the FRE start address.   SFRAME_FRE_TYPE_ADDR1 => 1 byte => [ bitmask = 0xff ]   SFRAME_FRE_TYPE_ADDR2 => 2 byte => [ bitmask = 0xffff ]   SFRAME_FRE_TYPE_ADDR4 => 4 byte => [ bitmask = 0xffffffff ].  */#define SFRAME_BITMASK_OF_SIZE(size_in_bytes) \  (((uint64_t)1 << (size_in_bytes*8)) - 1) /* Store the specified error code into errp if it is non-NULL.   Return SFRAME_ERR.  */ static intsframe_set_errno (int *errp, int error){  if (errp != NULL)    *errp = error;  return SFRAME_ERR;} /* Store the specified error code into errp if it is non-NULL.   Return NULL.  */ static void *sframe_ret_set_errno (int *errp, int error){  if (errp != NULL)    *errp = error;  return NULL;} /* Allocate space for NUM_FDES number of SFrame FDEs of type   sframe_func_desc_entry_int.  This is version-unaware because this pertains   to libsframe's internal in-memory representation of SFrame FDE.  */ static intsframe_fde_tbl_alloc (sf_fde_tbl **fde_tbl, unsigned int num_fdes){  size_t fidx_size = num_fdes * sizeof (sframe_func_desc_entry_int);  size_t fd_tbl_sz = (sizeof (sf_fde_tbl) + fidx_size);   *fde_tbl = malloc (fd_tbl_sz);  if (*fde_tbl == NULL)    return SFRAME_ERR;   (*fde_tbl)->alloced = num_fdes;   return 0;} /* Initialize libsframe's internal representation of SFrame FDEs.  */ static intsframe_fde_tbl_init (sf_fde_tbl *fde_tbl, const char *fde_buf,		     const char *fre_buf, size_t *fidx_size,		     unsigned int num_fdes, uint8_t ver){  if (ver == SFRAME_VERSION_3 && SFRAME_VERSION == SFRAME_VERSION_3)    {      *fidx_size = num_fdes * sizeof (sframe_func_desc_idx_v3);      for (unsigned int i = 0; i < num_fdes; i++)	{	  const sframe_func_desc_idx_v3 *fdep	    = (sframe_func_desc_idx_v3 *)fde_buf + i;	  fde_tbl->entry[i].func_start_pc_offset = fdep->sfdi_func_start_offset;	  fde_tbl->entry[i].func_size = fdep->sfdi_func_size;	  fde_tbl->entry[i].func_start_fre_off = fdep->sfdi_func_start_fre_off;	  /* V3 organizes the following data closer to the SFrame FREs for the	     function.  Access them via the sfde_func_start_fre_off.  */	  const sframe_func_desc_attr_v3 *fattr	    = (sframe_func_desc_attr_v3 *)(fre_buf					   + fdep->sfdi_func_start_fre_off);	  fde_tbl->entry[i].func_num_fres = fattr->sfda_func_num_fres;	  fde_tbl->entry[i].func_info = fattr->sfda_func_info;	  fde_tbl->entry[i].func_info2 = fattr->sfda_func_info2;	  fde_tbl->entry[i].func_rep_size = fattr->sfda_func_rep_size;	}      fde_tbl->count = num_fdes;    }  /* If ver is not the latest, read buffer manually and upgrade from     sframe_func_desc_entry_v2 to populate the sf_fde_tbl entries.  */  else if (ver == SFRAME_VERSION_2 && SFRAME_VERSION == SFRAME_VERSION_3)    {      *fidx_size = num_fdes * sizeof (sframe_func_desc_entry_v2);      for (unsigned int i = 0; i < num_fdes; i++)	{	  const sframe_func_desc_entry_v2 *fdep	    = (sframe_func_desc_entry_v2 *)fde_buf + i;	  fde_tbl->entry[i].func_start_pc_offset	    = fdep->sfde_func_start_address;	  fde_tbl->entry[i].func_size = fdep->sfde_func_size;	  fde_tbl->entry[i].func_start_fre_off = fdep->sfde_func_start_fre_off;	  fde_tbl->entry[i].func_num_fres = fdep->sfde_func_num_fres;	  fde_tbl->entry[i].func_info = fdep->sfde_func_info;	  fde_tbl->entry[i].func_info2 = 0;	  fde_tbl->entry[i].func_rep_size = fdep->sfde_func_rep_size;	}      fde_tbl->count = num_fdes;    }  else    {      /* Not possible ATM.  */      *fidx_size = 0;      return SFRAME_ERR;    }   return 0;} /* Get the SFrame header size.  */ static uint32_tsframe_get_hdr_size (const sframe_header *sfh){  return SFRAME_V1_HDR_SIZE (*sfh);} /* Access functions for frame row entry data.  */ static uint8_tsframe_fre_get_dataword_count (uint8_t fre_info){  return SFRAME_V1_FRE_OFFSET_COUNT (fre_info);} static uint8_tsframe_fre_get_dataword_size (uint8_t fre_info){  return SFRAME_V1_FRE_OFFSET_SIZE (fre_info);} static boolsframe_get_fre_ra_mangled_p (uint8_t fre_info){  return SFRAME_V1_FRE_MANGLED_RA_P (fre_info);} static boolsframe_get_fre_ra_undefined_p (uint8_t fre_info){  return SFRAME_V2_FRE_RA_UNDEFINED_P (fre_info);} /* Access functions for info from function descriptor entry.  */ static uint32_tsframe_get_fre_type (sframe_func_desc_entry_int *fdep){  uint32_t fre_type = 0;  if (fdep)    fre_type = SFRAME_V2_FUNC_FRE_TYPE (fdep->func_info);  return fre_type;} static uint32_tsframe_get_fde_pc_type (sframe_func_desc_entry_int *fdep){  uint32_t fde_pc_type = 0;  if (fdep)    fde_pc_type = SFRAME_V2_FUNC_PC_TYPE (fdep->func_info);  return fde_pc_type;} /* Check if flipping is needed, based on ENDIAN.  */ static intneed_swapping (int endian){  unsigned int ui = 1;  char *c = (char *)&ui;  int is_little = (int)*c;   switch (endian)    {      case SFRAME_ABI_AARCH64_ENDIAN_LITTLE:      case SFRAME_ABI_AMD64_ENDIAN_LITTLE:	return !is_little;      case SFRAME_ABI_AARCH64_ENDIAN_BIG:      case SFRAME_ABI_S390X_ENDIAN_BIG:	return is_little;      default:	break;    }   return 0;} /* Flip the endianness of the SFrame header starting at BUF.   VER is the version of the SFrame data in the buffer.    Returns SFRAME_ERR if any error.  If error code is returned, the flipped   header should not be used.  */ static intflip_header (char *buf, uint8_t ver ATTRIBUTE_UNUSED){  /* SFrame header binary format has remained the same in SFRAME_VERSION_1,     SFRAME_VERSION_2.  */  sframe_header *sfh = (sframe_header *) buf;  swap_thing (sfh->sfh_preamble.sfp_magic);  swap_thing (sfh->sfh_preamble.sfp_version);  swap_thing (sfh->sfh_preamble.sfp_flags);  swap_thing (sfh->sfh_abi_arch);  swap_thing (sfh->sfh_cfa_fixed_fp_offset);  swap_thing (sfh->sfh_cfa_fixed_ra_offset);  swap_thing (sfh->sfh_auxhdr_len);  swap_thing (sfh->sfh_num_fdes);  swap_thing (sfh->sfh_num_fres);  swap_thing (sfh->sfh_fre_len);  swap_thing (sfh->sfh_fdeoff);  swap_thing (sfh->sfh_freoff);   /* Alert for missing functionatlity.  Auxiliary header, if present, needs to     flipped based on per abi/arch semantics.  */  if (sfh->sfh_auxhdr_len)    return SFRAME_ERR;   return 0;} /* Endian flip the SFrame FDE at BUF (buffer size provided in BUF_SIZE), given   the SFrame version VER.  Update the FDE_SIZE to the size of the SFrame FDE   flipped.    Return SFRAME_ERR if any error.  If error code is returned, the flipped FDEP   should not be used.  */ static intflip_fde_desc (char *buf, size_t buf_size, uint8_t ver){  if (ver == SFRAME_VERSION_3)    {      if (buf_size < sizeof (sframe_func_desc_idx_v3))	return SFRAME_ERR;       sframe_func_desc_idx_v3 *fdep = (sframe_func_desc_idx_v3 *) buf;      swap_thing (fdep->sfdi_func_start_offset);      swap_thing (fdep->sfdi_func_size);      swap_thing (fdep->sfdi_func_start_fre_off);    }  else if (ver == SFRAME_VERSION_2)    {      if (buf_size < sizeof (sframe_func_desc_entry_v2))	return SFRAME_ERR;       sframe_func_desc_entry_v2 *fdep = (sframe_func_desc_entry_v2 *) buf;      swap_thing (fdep->sfde_func_start_address);      swap_thing (fdep->sfde_func_size);      swap_thing (fdep->sfde_func_start_fre_off);      swap_thing (fdep->sfde_func_num_fres);    }  else    return SFRAME_ERR;   return 0;} static intflip_fde_attr_v3 (char *buf, size_t buf_size){  if (buf_size < sizeof (sframe_func_desc_attr_v3))    return SFRAME_ERR;   /* sfda_func_num_fres is the first member of sframe_func_desc_attr_v3.  */  struct { uint16_t x; } ATTRIBUTE_PACKED *p = (void*)buf;  swap_thing (p->x);   return 0;}/* Check if SFrame header has valid data.  */ static boolsframe_header_sanity_check_p (const sframe_header *hp){  /* Check preamble is valid.  */  if (hp->sfh_preamble.sfp_magic != SFRAME_MAGIC      || (hp->sfh_preamble.sfp_version != SFRAME_VERSION_1	  && hp->sfh_preamble.sfp_version != SFRAME_VERSION_2	  && hp->sfh_preamble.sfp_version != SFRAME_VERSION_3))    return false;   /* Check flags (version-aware).     Do not validate V3 headers against V2 flag definitions, as V3 may     introduce new flags.  */  uint8_t valid_flags = SFRAME_V2_F_ALL_FLAGS;  if (hp->sfh_preamble.sfp_version == SFRAME_VERSION_3)    /* Replace with SFRAME_V3_F_ALL_FLAGS.  */    valid_flags = SFRAME_V3_F_ALL_FLAGS;  if (hp->sfh_preamble.sfp_flags & ~valid_flags)    return false;   /* Check offsets are valid.  */  if (hp->sfh_fdeoff > hp->sfh_freoff)    return false;   return true;} /* Flip the start address pointed to by FP.  */ static voidflip_fre_start_address (void *addr, uint32_t fre_type){  if (fre_type == SFRAME_FRE_TYPE_ADDR2)    {      struct { uint16_t x; } ATTRIBUTE_PACKED *p = addr;      swap_thing (p->x);    }  else if (fre_type == SFRAME_FRE_TYPE_ADDR4)    {      struct { uint32_t x; } ATTRIBUTE_PACKED *p = addr;      swap_thing (p->x);    }} static voidflip_fre_datawords (void *datawords, uint8_t dataword_size,		    uint8_t dataword_cnt){  int j;   if (dataword_size == SFRAME_FRE_DATAWORD_2B)    {      struct { uint16_t x; } ATTRIBUTE_PACKED *p = datawords;      for (j = dataword_cnt; j > 0; p++, j--)	swap_thing (p->x);    }  else if (dataword_size == SFRAME_FRE_DATAWORD_4B)    {      struct { uint32_t x; } ATTRIBUTE_PACKED *p = datawords;      for (j = dataword_cnt; j > 0; p++, j--)	swap_thing (p->x);    }} /* Get the FRE start address size, given the FRE_TYPE.  */ static size_tsframe_fre_start_addr_size (uint32_t fre_type){  size_t addr_size = 0;  switch (fre_type)    {    case SFRAME_FRE_TYPE_ADDR1:      addr_size = 1;      break;    case SFRAME_FRE_TYPE_ADDR2:      addr_size = 2;      break;    case SFRAME_FRE_TYPE_ADDR4:      addr_size = 4;      break;    default:      /* No other value is expected.  */      sframe_assert (0);      break;    }  return addr_size;} /* Check if the FREP has valid data.  */ static boolsframe_fre_sanity_check_p (const sframe_frame_row_entry *frep){  uint8_t dataword_size, dataword_cnt;  uint8_t fre_info;   if (frep == NULL)    return false;   fre_info = frep->fre_info;  dataword_size = sframe_fre_get_dataword_size (fre_info);   if (dataword_size != SFRAME_FRE_DATAWORD_1B      && dataword_size != SFRAME_FRE_DATAWORD_2B      && dataword_size != SFRAME_FRE_DATAWORD_4B)    return false;   dataword_cnt = sframe_fre_get_dataword_count (fre_info);  if (dataword_cnt > MAX_NUM_DATAWORDS)    return false;   return true;} /* Get FRE_INFO's data words' size in bytes.  */ static size_tsframe_fre_datawords_bytes_size (uint8_t fre_info){  uint8_t dataword_size, dataword_cnt;   dataword_size = sframe_fre_get_dataword_size (fre_info);   debug_printf ("dataword_size =  %u\n", dataword_size);   dataword_cnt = sframe_fre_get_dataword_count (fre_info);   if (dataword_size == SFRAME_FRE_DATAWORD_2B      || dataword_size == SFRAME_FRE_DATAWORD_4B)	/* 2 or 4 bytes.  */    return (dataword_cnt * (dataword_size * 2));   return dataword_cnt;} /* Get total size in bytes to represent FREP in the binary format.  This   includes the starting address, FRE info, and all the offsets.  */ static size_tsframe_fre_entry_size (sframe_frame_row_entry *frep, uint32_t fre_type){

Lines 1–500 of 2755.

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t