11638Srgrimes/* sframe-dump.c - Textual dump of .sframe. 21638Srgrimes 31638Srgrimes Copyright (C) 2022-2024 Free Software Foundation, Inc. 41638Srgrimes 51638Srgrimes This file is part of libsframe. 61638Srgrimes 71638Srgrimes This program is free software; you can redistribute it and/or modify 81638Srgrimes it under the terms of the GNU General Public License as published by 91638Srgrimes the Free Software Foundation; either version 3 of the License, or 101638Srgrimes (at your option) any later version. 111638Srgrimes 121638Srgrimes 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 30static bool 31is_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 43static void 44dump_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 97static void 98dump_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 192static void 193dump_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 209void 210dump_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} 223