1/* sframe-dump.c - Textual dump of .sframe.
2
3   Copyright (C) 2022 Free Software Foundation, Inc.
4
5   his 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
28static void
29dump_sframe_header (sframe_decoder_ctx *sfd_ctx)
30{
31  const char *verstr = NULL;
32  const sframe_header *header = &(sfd_ctx->sfd_header);
33
34  /* Prepare SFrame section version string.  */
35  const char *version_names[]
36    = { "NULL",
37	"SFRAME_VERSION_1" };
38  unsigned char ver = header->sfh_preamble.sfp_version;
39  if (ver <= SFRAME_VERSION)
40    verstr = version_names[ver];
41
42  /* Prepare SFrame section flags string.  */
43  unsigned char flags = header->sfh_preamble.sfp_flags;
44  char *flags_str
45    = (char*) calloc (sizeof (char), SFRAME_HEADER_FLAGS_STR_MAX_LEN);
46  if (flags)
47    {
48      const char *flag_names[]
49	= { "SFRAME_F_FDE_SORTED",
50	    "SFRAME_F_FRAME_POINTER" };
51      unsigned char flags = header->sfh_preamble.sfp_flags;
52      if (flags & SFRAME_F_FDE_SORTED)
53	strcpy (flags_str, flag_names[0]);
54      if (flags & SFRAME_F_FRAME_POINTER)
55	{
56	  if (strlen (flags_str) > 0)
57	    strcpy (flags_str, ",");
58	  strcpy (flags_str, flag_names[1]);
59	}
60    }
61  else
62    strcpy (flags_str, "NONE");
63
64  const char* subsec_name = "Header";
65  printf ("\n");
66  printf ("  %s :\n", subsec_name);
67  printf ("\n");
68  printf ("    Version: %s\n", verstr);
69  printf ("    Flags: %s\n", flags_str);
70  printf ("    Num FDEs: %d\n", header->sfh_num_fdes);
71  printf ("    Num FREs: %d\n", header->sfh_num_fres);
72
73  free (flags_str);
74}
75
76static void
77dump_sframe_func_with_fres (sframe_decoder_ctx *sfd_ctx,
78			    unsigned int funcidx,
79			    uint64_t sec_addr)
80{
81  uint32_t j = 0;
82  uint32_t num_fres = 0;
83  uint32_t func_size = 0;
84  int32_t func_start_address = 0;
85  unsigned char func_info = 0;
86
87  uint64_t func_start_pc_vma = 0;
88  uint64_t fre_start_pc_vma = 0;
89  const char *base_reg_str[] = {"fp", "sp"};
90  int32_t cfa_offset = 0;
91  int32_t fp_offset = 0;
92  int32_t ra_offset = 0;
93  unsigned int base_reg_id = 0;
94  int err[3] = {0, 0, 0};
95
96  sframe_frame_row_entry fre;
97
98  /* Get the SFrame function descriptor.  */
99  sframe_decoder_get_funcdesc (sfd_ctx, funcidx, &num_fres,
100			       &func_size, &func_start_address, &func_info);
101  /* Calculate the virtual memory address for function start pc.  */
102  func_start_pc_vma = func_start_address + sec_addr;
103
104  /* Mark FDEs with [m] where the FRE start address is interpreted as a
105     mask.  */
106  int fde_type_addrmask_p = (SFRAME_V1_FUNC_FDE_TYPE (func_info)
107			     == SFRAME_FDE_TYPE_PCMASK);
108  const char *fde_type_marker
109    = (fde_type_addrmask_p ? "[m]" : "   ");
110
111  printf ("\n    func idx [%d]: pc = 0x%"PRIx64 ", size = %d bytes",
112	  funcidx,
113	  func_start_pc_vma,
114	  func_size);
115
116  char temp[100];
117  memset (temp, 0, 100);
118
119  printf ("\n    %-7s%-8s %-10s%-10s%-13s", "STARTPC", fde_type_marker, "CFA", "FP", "RA");
120  for (j = 0; j < num_fres; j++)
121    {
122      sframe_decoder_get_fre (sfd_ctx, funcidx, j, &fre);
123
124      fre_start_pc_vma = (fde_type_addrmask_p
125			  ? fre.fre_start_addr
126			  : func_start_pc_vma + fre.fre_start_addr);
127
128      /* FIXME - fixup the err caching in array.
129	 assert no error for base reg id.  */
130      base_reg_id = sframe_fre_get_base_reg_id (&fre, &err[0]);
131      cfa_offset = sframe_fre_get_cfa_offset (sfd_ctx, &fre, &err[0]);
132      fp_offset = sframe_fre_get_fp_offset (sfd_ctx, &fre, &err[1]);
133      ra_offset = sframe_fre_get_ra_offset (sfd_ctx, &fre, &err[2]);
134
135      /* Dump CFA info.  */
136      printf ("\n");
137      printf ("    %016"PRIx64, fre_start_pc_vma);
138      sprintf (temp, "%s+%d", base_reg_str[base_reg_id], cfa_offset);
139      printf ("  %-10s", temp);
140
141      /* Dump SP/FP info.  */
142      memset (temp, 0, 100);
143      if (err[1] == 0)
144	sprintf (temp, "c%+d", fp_offset);
145      else
146	strcpy (temp, "u");
147      printf ("%-10s", temp);
148
149      /* Dump RA info.  */
150      memset (temp, 0, 100);
151      if (err[2] == 0)
152	sprintf (temp, "c%+d", ra_offset);
153      else
154	strcpy (temp, "u");
155      /* Mark SFrame FRE's RA information with "[s]" if the RA is mangled
156	 with signature bits.  */
157      const char *ra_mangled_p_str
158	= ((sframe_fre_get_ra_mangled_p (sfd_ctx, &fre, &err[2]))
159	   ? "[s]" : "   ");
160      size_t ra_mangled_p_str_size = strlen (ra_mangled_p_str);
161      strncat (temp, ra_mangled_p_str, ra_mangled_p_str_size);
162      printf ("%-13s", temp);
163    }
164}
165
166static void
167dump_sframe_functions (sframe_decoder_ctx *sfd_ctx, uint64_t sec_addr)
168{
169  uint32_t i;
170  uint32_t num_fdes;
171
172  const char* subsec_name = "Function Index";
173  printf ("\n  %s :\n", subsec_name);
174
175  num_fdes = sframe_decoder_get_num_fidx (sfd_ctx);
176  for (i = 0; i < num_fdes; i++)
177    {
178      dump_sframe_func_with_fres (sfd_ctx, i, sec_addr);
179      printf ("\n");
180    }
181}
182
183void
184dump_sframe (sframe_decoder_ctx *sfd_ctx, uint64_t sec_addr)
185{
186  dump_sframe_header (sfd_ctx);
187  dump_sframe_functions (sfd_ctx, sec_addr);
188}
189