xref: /netbsd-src/external/gpl3/gdb/dist/libsframe/sframe-dump.c (revision 6817db7f6bcc94c9b2ba339c5139981a23c88cf9)
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