14b169a6bSchristos /* sframe-dump.c - Textual dump of .sframe. 24b169a6bSchristos 3*6817db7fSchristos Copyright (C) 2022-2024 Free Software Foundation, Inc. 44b169a6bSchristos 5*6817db7fSchristos 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 <string.h> 214b169a6bSchristos #include <stdio.h> 224b169a6bSchristos #include <stdlib.h> 234b169a6bSchristos #include <inttypes.h> 244b169a6bSchristos #include "sframe-impl.h" 254b169a6bSchristos 264b169a6bSchristos #define SFRAME_HEADER_FLAGS_STR_MAX_LEN 50 274b169a6bSchristos 28*6817db7fSchristos /* Return TRUE if the SFrame section is associated with the aarch64 ABIs. */ 29*6817db7fSchristos 30*6817db7fSchristos static bool 31*6817db7fSchristos is_sframe_abi_arch_aarch64 (sframe_decoder_ctx *sfd_ctx) 32*6817db7fSchristos { 33*6817db7fSchristos bool aarch64_p = false; 34*6817db7fSchristos 35*6817db7fSchristos uint8_t abi_arch = sframe_decoder_get_abi_arch (sfd_ctx); 36*6817db7fSchristos if (abi_arch == SFRAME_ABI_AARCH64_ENDIAN_BIG 37*6817db7fSchristos || abi_arch == SFRAME_ABI_AARCH64_ENDIAN_LITTLE) 38*6817db7fSchristos aarch64_p = true; 39*6817db7fSchristos 40*6817db7fSchristos return aarch64_p; 41*6817db7fSchristos } 42*6817db7fSchristos 434b169a6bSchristos static void 444b169a6bSchristos dump_sframe_header (sframe_decoder_ctx *sfd_ctx) 454b169a6bSchristos { 46*6817db7fSchristos uint8_t ver; 47*6817db7fSchristos uint8_t flags; 48*6817db7fSchristos char *flags_str; 49*6817db7fSchristos const char *ver_str = NULL; 504b169a6bSchristos const sframe_header *header = &(sfd_ctx->sfd_header); 514b169a6bSchristos 524b169a6bSchristos /* Prepare SFrame section version string. */ 534b169a6bSchristos const char *version_names[] 544b169a6bSchristos = { "NULL", 55*6817db7fSchristos "SFRAME_VERSION_1", 56*6817db7fSchristos "SFRAME_VERSION_2" }; 574b169a6bSchristos 58*6817db7fSchristos /* PS: Keep SFRAME_HEADER_FLAGS_STR_MAX_LEN in sync if adding more members to 59*6817db7fSchristos this array. */ 604b169a6bSchristos const char *flag_names[] 614b169a6bSchristos = { "SFRAME_F_FDE_SORTED", 624b169a6bSchristos "SFRAME_F_FRAME_POINTER" }; 63*6817db7fSchristos 64*6817db7fSchristos ver = sframe_decoder_get_version (sfd_ctx); 65*6817db7fSchristos if (ver <= SFRAME_VERSION) 66*6817db7fSchristos ver_str = version_names[ver]; 67*6817db7fSchristos 68*6817db7fSchristos /* Prepare SFrame section flags string. */ 69*6817db7fSchristos flags = header->sfh_preamble.sfp_flags; 70*6817db7fSchristos flags_str = (char*) calloc (SFRAME_HEADER_FLAGS_STR_MAX_LEN, sizeof (char)); 71*6817db7fSchristos if (flags) 72*6817db7fSchristos { 734b169a6bSchristos if (flags & SFRAME_F_FDE_SORTED) 744b169a6bSchristos strcpy (flags_str, flag_names[0]); 754b169a6bSchristos if (flags & SFRAME_F_FRAME_POINTER) 764b169a6bSchristos { 774b169a6bSchristos if (strlen (flags_str) > 0) 784b169a6bSchristos strcpy (flags_str, ","); 794b169a6bSchristos strcpy (flags_str, flag_names[1]); 804b169a6bSchristos } 814b169a6bSchristos } 824b169a6bSchristos else 834b169a6bSchristos strcpy (flags_str, "NONE"); 844b169a6bSchristos 854b169a6bSchristos const char* subsec_name = "Header"; 864b169a6bSchristos printf ("\n"); 874b169a6bSchristos printf (" %s :\n", subsec_name); 884b169a6bSchristos printf ("\n"); 89*6817db7fSchristos printf (" Version: %s\n", ver_str); 904b169a6bSchristos printf (" Flags: %s\n", flags_str); 91*6817db7fSchristos printf (" Num FDEs: %d\n", sframe_decoder_get_num_fidx (sfd_ctx)); 924b169a6bSchristos printf (" Num FREs: %d\n", header->sfh_num_fres); 934b169a6bSchristos 944b169a6bSchristos free (flags_str); 954b169a6bSchristos } 964b169a6bSchristos 974b169a6bSchristos static void 984b169a6bSchristos dump_sframe_func_with_fres (sframe_decoder_ctx *sfd_ctx, 994b169a6bSchristos unsigned int funcidx, 1004b169a6bSchristos uint64_t sec_addr) 1014b169a6bSchristos { 1024b169a6bSchristos uint32_t j = 0; 1034b169a6bSchristos uint32_t num_fres = 0; 1044b169a6bSchristos uint32_t func_size = 0; 1054b169a6bSchristos int32_t func_start_address = 0; 1064b169a6bSchristos unsigned char func_info = 0; 1074b169a6bSchristos 1084b169a6bSchristos uint64_t func_start_pc_vma = 0; 1094b169a6bSchristos uint64_t fre_start_pc_vma = 0; 1104b169a6bSchristos const char *base_reg_str[] = {"fp", "sp"}; 1114b169a6bSchristos int32_t cfa_offset = 0; 1124b169a6bSchristos int32_t fp_offset = 0; 1134b169a6bSchristos int32_t ra_offset = 0; 114*6817db7fSchristos uint8_t base_reg_id = 0; 1154b169a6bSchristos int err[3] = {0, 0, 0}; 1164b169a6bSchristos 1174b169a6bSchristos sframe_frame_row_entry fre; 1184b169a6bSchristos 1194b169a6bSchristos /* Get the SFrame function descriptor. */ 1204b169a6bSchristos sframe_decoder_get_funcdesc (sfd_ctx, funcidx, &num_fres, 1214b169a6bSchristos &func_size, &func_start_address, &func_info); 1224b169a6bSchristos /* Calculate the virtual memory address for function start pc. */ 1234b169a6bSchristos func_start_pc_vma = func_start_address + sec_addr; 1244b169a6bSchristos 1254b169a6bSchristos /* Mark FDEs with [m] where the FRE start address is interpreted as a 1264b169a6bSchristos mask. */ 1274b169a6bSchristos int fde_type_addrmask_p = (SFRAME_V1_FUNC_FDE_TYPE (func_info) 1284b169a6bSchristos == SFRAME_FDE_TYPE_PCMASK); 1294b169a6bSchristos const char *fde_type_marker 1304b169a6bSchristos = (fde_type_addrmask_p ? "[m]" : " "); 1314b169a6bSchristos 1324b169a6bSchristos printf ("\n func idx [%d]: pc = 0x%"PRIx64 ", size = %d bytes", 1334b169a6bSchristos funcidx, 1344b169a6bSchristos func_start_pc_vma, 1354b169a6bSchristos func_size); 1364b169a6bSchristos 137*6817db7fSchristos if (is_sframe_abi_arch_aarch64 (sfd_ctx) 138*6817db7fSchristos && (SFRAME_V1_FUNC_PAUTH_KEY (func_info) == SFRAME_AARCH64_PAUTH_KEY_B)) 139*6817db7fSchristos printf (", pauth = B key"); 1404b169a6bSchristos 141*6817db7fSchristos char temp[100]; 142*6817db7fSchristos 143*6817db7fSchristos printf ("\n %-7s%-8s %-10s%-10s%-13s", 144*6817db7fSchristos "STARTPC", fde_type_marker, "CFA", "FP", "RA"); 1454b169a6bSchristos for (j = 0; j < num_fres; j++) 1464b169a6bSchristos { 1474b169a6bSchristos sframe_decoder_get_fre (sfd_ctx, funcidx, j, &fre); 1484b169a6bSchristos 1494b169a6bSchristos fre_start_pc_vma = (fde_type_addrmask_p 1504b169a6bSchristos ? fre.fre_start_addr 1514b169a6bSchristos : func_start_pc_vma + fre.fre_start_addr); 1524b169a6bSchristos 1534b169a6bSchristos /* FIXME - fixup the err caching in array. 1544b169a6bSchristos assert no error for base reg id. */ 1554b169a6bSchristos base_reg_id = sframe_fre_get_base_reg_id (&fre, &err[0]); 1564b169a6bSchristos cfa_offset = sframe_fre_get_cfa_offset (sfd_ctx, &fre, &err[0]); 1574b169a6bSchristos fp_offset = sframe_fre_get_fp_offset (sfd_ctx, &fre, &err[1]); 1584b169a6bSchristos ra_offset = sframe_fre_get_ra_offset (sfd_ctx, &fre, &err[2]); 1594b169a6bSchristos 1604b169a6bSchristos /* Dump CFA info. */ 1614b169a6bSchristos printf ("\n"); 1624b169a6bSchristos printf (" %016"PRIx64, fre_start_pc_vma); 1634b169a6bSchristos sprintf (temp, "%s+%d", base_reg_str[base_reg_id], cfa_offset); 1644b169a6bSchristos printf (" %-10s", temp); 1654b169a6bSchristos 1664b169a6bSchristos /* Dump SP/FP info. */ 1674b169a6bSchristos if (err[1] == 0) 1684b169a6bSchristos sprintf (temp, "c%+d", fp_offset); 1694b169a6bSchristos else 1704b169a6bSchristos strcpy (temp, "u"); 1714b169a6bSchristos printf ("%-10s", temp); 1724b169a6bSchristos 173*6817db7fSchristos /* Dump RA info. 174*6817db7fSchristos If an ABI does not track RA offset, e.g., AMD64, display a 'u', 175*6817db7fSchristos else display the offset d as 'c+-d'. */ 176*6817db7fSchristos if (sframe_decoder_get_fixed_ra_offset(sfd_ctx) 177*6817db7fSchristos != SFRAME_CFA_FIXED_RA_INVALID) 1784b169a6bSchristos strcpy (temp, "u"); 179*6817db7fSchristos else if (err[2] == 0) 180*6817db7fSchristos sprintf (temp, "c%+d", ra_offset); 181*6817db7fSchristos 1824b169a6bSchristos /* Mark SFrame FRE's RA information with "[s]" if the RA is mangled 1834b169a6bSchristos with signature bits. */ 1844b169a6bSchristos const char *ra_mangled_p_str 1854b169a6bSchristos = ((sframe_fre_get_ra_mangled_p (sfd_ctx, &fre, &err[2])) 1864b169a6bSchristos ? "[s]" : " "); 187*6817db7fSchristos strcat (temp, ra_mangled_p_str); 1884b169a6bSchristos printf ("%-13s", temp); 1894b169a6bSchristos } 1904b169a6bSchristos } 1914b169a6bSchristos 1924b169a6bSchristos static void 1934b169a6bSchristos dump_sframe_functions (sframe_decoder_ctx *sfd_ctx, uint64_t sec_addr) 1944b169a6bSchristos { 1954b169a6bSchristos uint32_t i; 1964b169a6bSchristos uint32_t num_fdes; 1974b169a6bSchristos 1984b169a6bSchristos const char* subsec_name = "Function Index"; 1994b169a6bSchristos printf ("\n %s :\n", subsec_name); 2004b169a6bSchristos 2014b169a6bSchristos num_fdes = sframe_decoder_get_num_fidx (sfd_ctx); 2024b169a6bSchristos for (i = 0; i < num_fdes; i++) 2034b169a6bSchristos { 2044b169a6bSchristos dump_sframe_func_with_fres (sfd_ctx, i, sec_addr); 2054b169a6bSchristos printf ("\n"); 2064b169a6bSchristos } 2074b169a6bSchristos } 2084b169a6bSchristos 2094b169a6bSchristos void 2104b169a6bSchristos dump_sframe (sframe_decoder_ctx *sfd_ctx, uint64_t sec_addr) 2114b169a6bSchristos { 212*6817db7fSchristos uint8_t ver; 213*6817db7fSchristos 2144b169a6bSchristos dump_sframe_header (sfd_ctx); 215*6817db7fSchristos 216*6817db7fSchristos ver = sframe_decoder_get_version (sfd_ctx); 217*6817db7fSchristos if (ver == SFRAME_VERSION) 2184b169a6bSchristos dump_sframe_functions (sfd_ctx, sec_addr); 219*6817db7fSchristos else 220*6817db7fSchristos printf ("\n No further information can be displayed. %s", 221*6817db7fSchristos "SFrame version not supported\n"); 2224b169a6bSchristos } 223