1  /* sframe-dump.c - Textual dump of .sframe.
       2  
       3     Copyright (C) 2022-2023 Free Software Foundation, Inc.
       4  
       5     This file is part of libsframe.
       6  
       7     This program is free software; you can redistribute it and/or modify
       8     it under the terms of the GNU General Public License as published by
       9     the Free Software Foundation; either version 3 of the License, or
      10     (at your option) any later version.
      11  
      12     This program is distributed in the hope that it will be useful,
      13     but WITHOUT ANY WARRANTY; without even the implied warranty of
      14     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      15     GNU General Public License for more details.
      16  
      17     You should have received a copy of the GNU General Public License
      18     along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
      19  
      20  #include <string.h>
      21  #include <stdio.h>
      22  #include <stdlib.h>
      23  #include <inttypes.h>
      24  #include "sframe-impl.h"
      25  
      26  #define SFRAME_HEADER_FLAGS_STR_MAX_LEN 50
      27  
      28  /* Return TRUE if the SFrame section is associated with the aarch64 ABIs.  */
      29  
      30  static bool
      31  is_sframe_abi_arch_aarch64 (sframe_decoder_ctx *sfd_ctx)
      32  {
      33    bool aarch64_p = false;
      34  
      35    uint8_t abi_arch = sframe_decoder_get_abi_arch (sfd_ctx);
      36    if (abi_arch == SFRAME_ABI_AARCH64_ENDIAN_BIG
      37        || abi_arch == SFRAME_ABI_AARCH64_ENDIAN_LITTLE)
      38      aarch64_p = true;
      39  
      40    return aarch64_p;
      41  }
      42  
      43  static void
      44  dump_sframe_header (sframe_decoder_ctx *sfd_ctx)
      45  {
      46    uint8_t ver;
      47    uint8_t flags;
      48    char *flags_str;
      49    const char *ver_str = NULL;
      50    const sframe_header *header = &(sfd_ctx->sfd_header);
      51  
      52    /* Prepare SFrame section version string.  */
      53    const char *version_names[]
      54      = { "NULL",
      55  	"SFRAME_VERSION_1",
      56  	"SFRAME_VERSION_2" };
      57  
      58    /* PS: Keep SFRAME_HEADER_FLAGS_STR_MAX_LEN in sync if adding more members to
      59       this array.  */
      60    const char *flag_names[]
      61      = { "SFRAME_F_FDE_SORTED",
      62  	"SFRAME_F_FRAME_POINTER" };
      63  
      64    ver = sframe_decoder_get_version (sfd_ctx);
      65    if (ver <= SFRAME_VERSION)
      66      ver_str = version_names[ver];
      67  
      68    /* Prepare SFrame section flags string.  */
      69    flags = header->sfh_preamble.sfp_flags;
      70    flags_str = (char*) calloc (sizeof (char), SFRAME_HEADER_FLAGS_STR_MAX_LEN);
      71    if (flags)
      72      {
      73        if (flags & SFRAME_F_FDE_SORTED)
      74  	strcpy (flags_str, flag_names[0]);
      75        if (flags & SFRAME_F_FRAME_POINTER)
      76  	{
      77  	  if (strlen (flags_str) > 0)
      78  	    strcpy (flags_str, ",");
      79  	  strcpy (flags_str, flag_names[1]);
      80  	}
      81      }
      82    else
      83      strcpy (flags_str, "NONE");
      84  
      85    const char* subsec_name = "Header";
      86    printf ("\n");
      87    printf ("  %s :\n", subsec_name);
      88    printf ("\n");
      89    printf ("    Version: %s\n", ver_str);
      90    printf ("    Flags: %s\n", flags_str);
      91    printf ("    Num FDEs: %d\n", sframe_decoder_get_num_fidx (sfd_ctx));
      92    printf ("    Num FREs: %d\n", header->sfh_num_fres);
      93  
      94    free (flags_str);
      95  }
      96  
      97  static void
      98  dump_sframe_func_with_fres (sframe_decoder_ctx *sfd_ctx,
      99  			    unsigned int funcidx,
     100  			    uint64_t sec_addr)
     101  {
     102    uint32_t j = 0;
     103    uint32_t num_fres = 0;
     104    uint32_t func_size = 0;
     105    int32_t func_start_address = 0;
     106    unsigned char func_info = 0;
     107  
     108    uint64_t func_start_pc_vma = 0;
     109    uint64_t fre_start_pc_vma = 0;
     110    const char *base_reg_str[] = {"fp", "sp"};
     111    int32_t cfa_offset = 0;
     112    int32_t fp_offset = 0;
     113    int32_t ra_offset = 0;
     114    uint8_t base_reg_id = 0;
     115    int err[3] = {0, 0, 0};
     116  
     117    sframe_frame_row_entry fre;
     118  
     119    /* Get the SFrame function descriptor.  */
     120    sframe_decoder_get_funcdesc (sfd_ctx, funcidx, &num_fres,
     121  			       &func_size, &func_start_address, &func_info);
     122    /* Calculate the virtual memory address for function start pc.  */
     123    func_start_pc_vma = func_start_address + sec_addr;
     124  
     125    /* Mark FDEs with [m] where the FRE start address is interpreted as a
     126       mask.  */
     127    int fde_type_addrmask_p = (SFRAME_V1_FUNC_FDE_TYPE (func_info)
     128  			     == SFRAME_FDE_TYPE_PCMASK);
     129    const char *fde_type_marker
     130      = (fde_type_addrmask_p ? "[m]" : "   ");
     131  
     132    printf ("\n    func idx [%d]: pc = 0x%"PRIx64 ", size = %d bytes",
     133  	  funcidx,
     134  	  func_start_pc_vma,
     135  	  func_size);
     136  
     137    if (is_sframe_abi_arch_aarch64 (sfd_ctx)
     138        && (SFRAME_V1_FUNC_PAUTH_KEY (func_info) == SFRAME_AARCH64_PAUTH_KEY_B))
     139      printf (", pauth = B key");
     140  
     141    char temp[100];
     142  
     143    printf ("\n    %-7s%-8s %-10s%-10s%-13s",
     144  	  "STARTPC", fde_type_marker, "CFA", "FP", "RA");
     145    for (j = 0; j < num_fres; j++)
     146      {
     147        sframe_decoder_get_fre (sfd_ctx, funcidx, j, &fre);
     148  
     149        fre_start_pc_vma = (fde_type_addrmask_p
     150  			  ? fre.fre_start_addr
     151  			  : func_start_pc_vma + fre.fre_start_addr);
     152  
     153        /* FIXME - fixup the err caching in array.
     154  	 assert no error for base reg id.  */
     155        base_reg_id = sframe_fre_get_base_reg_id (&fre, &err[0]);
     156        cfa_offset = sframe_fre_get_cfa_offset (sfd_ctx, &fre, &err[0]);
     157        fp_offset = sframe_fre_get_fp_offset (sfd_ctx, &fre, &err[1]);
     158        ra_offset = sframe_fre_get_ra_offset (sfd_ctx, &fre, &err[2]);
     159  
     160        /* Dump CFA info.  */
     161        printf ("\n");
     162        printf ("    %016"PRIx64, fre_start_pc_vma);
     163        sprintf (temp, "%s+%d", base_reg_str[base_reg_id], cfa_offset);
     164        printf ("  %-10s", temp);
     165  
     166        /* Dump SP/FP info.  */
     167        if (err[1] == 0)
     168  	sprintf (temp, "c%+d", fp_offset);
     169        else
     170  	strcpy (temp, "u");
     171        printf ("%-10s", temp);
     172  
     173        /* Dump RA info.
     174  	 If an ABI does not track RA offset, e.g., AMD64, display a 'u',
     175  	 else display the offset d as 'c+-d'.  */
     176        if (sframe_decoder_get_fixed_ra_offset(sfd_ctx)
     177  	  != SFRAME_CFA_FIXED_RA_INVALID)
     178  	strcpy (temp, "u");
     179        else if (err[2] == 0)
     180  	sprintf (temp, "c%+d", ra_offset);
     181  
     182        /* Mark SFrame FRE's RA information with "[s]" if the RA is mangled
     183  	 with signature bits.  */
     184        const char *ra_mangled_p_str
     185  	= ((sframe_fre_get_ra_mangled_p (sfd_ctx, &fre, &err[2]))
     186  	   ? "[s]" : "   ");
     187        strcat (temp, ra_mangled_p_str);
     188        printf ("%-13s", temp);
     189      }
     190  }
     191  
     192  static void
     193  dump_sframe_functions (sframe_decoder_ctx *sfd_ctx, uint64_t sec_addr)
     194  {
     195    uint32_t i;
     196    uint32_t num_fdes;
     197  
     198    const char* subsec_name = "Function Index";
     199    printf ("\n  %s :\n", subsec_name);
     200  
     201    num_fdes = sframe_decoder_get_num_fidx (sfd_ctx);
     202    for (i = 0; i < num_fdes; i++)
     203      {
     204        dump_sframe_func_with_fres (sfd_ctx, i, sec_addr);
     205        printf ("\n");
     206      }
     207  }
     208  
     209  void
     210  dump_sframe (sframe_decoder_ctx *sfd_ctx, uint64_t sec_addr)
     211  {
     212    uint8_t ver;
     213  
     214    dump_sframe_header (sfd_ctx);
     215  
     216    ver = sframe_decoder_get_version (sfd_ctx);
     217    if (ver == SFRAME_VERSION)
     218      dump_sframe_functions (sfd_ctx, sec_addr);
     219    else
     220      printf ("\n No further information can be displayed.  %s",
     221  	    "SFrame version not supported\n");
     222  }