/src/binutils-gdb/libsframe/sframe-dump.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* sframe-dump.c - Textual dump of .sframe. |
2 | | |
3 | | Copyright (C) 2022-2025 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 | | /* Return TRUE if the SFrame section is associated with the aarch64 ABIs. */ |
27 | | |
28 | | static bool |
29 | | is_sframe_abi_arch_aarch64 (sframe_decoder_ctx *sfd_ctx) |
30 | 0 | { |
31 | 0 | bool aarch64_p = false; |
32 | |
|
33 | 0 | uint8_t abi_arch = sframe_decoder_get_abi_arch (sfd_ctx); |
34 | 0 | if (abi_arch == SFRAME_ABI_AARCH64_ENDIAN_BIG |
35 | 0 | || abi_arch == SFRAME_ABI_AARCH64_ENDIAN_LITTLE) |
36 | 0 | aarch64_p = true; |
37 | |
|
38 | 0 | return aarch64_p; |
39 | 0 | } |
40 | | |
41 | | static void |
42 | | dump_sframe_header_flags (sframe_decoder_ctx *sfd_ctx) |
43 | 0 | { |
44 | 0 | uint8_t flags; |
45 | 0 | const char *prefix = "Flags: "; |
46 | |
|
47 | 0 | flags = sframe_decoder_get_flags (sfd_ctx); |
48 | 0 | if (!flags) |
49 | 0 | { |
50 | 0 | printf ("%11sNONE\n", prefix); |
51 | 0 | return; |
52 | 0 | } |
53 | | |
54 | 0 | #define PRINT_FLAG(x) \ |
55 | 0 | if (flags & (x)) \ |
56 | 0 | { flags = (flags & ~(x)); \ |
57 | 0 | printf ("%11s%s%s\n", prefix, #x, flags ? "," : ""); \ |
58 | 0 | prefix = " "; \ |
59 | 0 | } |
60 | | |
61 | 0 | PRINT_FLAG (SFRAME_F_FDE_SORTED); |
62 | 0 | PRINT_FLAG (SFRAME_F_FRAME_POINTER); |
63 | 0 | PRINT_FLAG (SFRAME_F_FDE_FUNC_START_PCREL); |
64 | 0 | #undef PRINT_FLAG |
65 | | |
66 | | /* Print any residual flags, should this implementation be out of sync when |
67 | | new flags are added. */ |
68 | 0 | if (flags) |
69 | 0 | printf ("%11s%d\n", prefix, flags); |
70 | 0 | } |
71 | | |
72 | | static void |
73 | | dump_sframe_header (sframe_decoder_ctx *sfd_ctx) |
74 | 0 | { |
75 | 0 | uint8_t ver; |
76 | 0 | const char *ver_str = NULL; |
77 | 0 | int8_t cfa_fixed_fp_offset; |
78 | 0 | int8_t cfa_fixed_ra_offset; |
79 | 0 | const sframe_header *header = &(sfd_ctx->sfd_header); |
80 | | |
81 | | /* Prepare SFrame section version string. */ |
82 | 0 | const char *version_names[] |
83 | 0 | = { "NULL", |
84 | 0 | "SFRAME_VERSION_1", |
85 | 0 | "SFRAME_VERSION_2" }; |
86 | |
|
87 | 0 | ver = sframe_decoder_get_version (sfd_ctx); |
88 | 0 | if (ver <= SFRAME_VERSION) |
89 | 0 | ver_str = version_names[ver]; |
90 | | |
91 | | /* CFA fixed FP and RA offsets. */ |
92 | 0 | cfa_fixed_fp_offset = header->sfh_cfa_fixed_fp_offset; |
93 | 0 | cfa_fixed_ra_offset = header->sfh_cfa_fixed_ra_offset; |
94 | |
|
95 | 0 | const char* subsec_name = "Header"; |
96 | 0 | printf ("\n"); |
97 | 0 | printf (" %s :\n", subsec_name); |
98 | 0 | printf ("\n"); |
99 | 0 | printf (" Version: %s\n", ver_str); |
100 | |
|
101 | 0 | dump_sframe_header_flags (sfd_ctx); |
102 | |
|
103 | 0 | if (cfa_fixed_fp_offset != SFRAME_CFA_FIXED_FP_INVALID) |
104 | 0 | printf (" CFA fixed FP offset: %d\n", cfa_fixed_fp_offset); |
105 | 0 | if (cfa_fixed_ra_offset != SFRAME_CFA_FIXED_RA_INVALID) |
106 | 0 | printf (" CFA fixed RA offset: %d\n", cfa_fixed_ra_offset); |
107 | 0 | printf (" Num FDEs: %d\n", sframe_decoder_get_num_fidx (sfd_ctx)); |
108 | 0 | printf (" Num FREs: %d\n", header->sfh_num_fres); |
109 | 0 | } |
110 | | |
111 | | static void |
112 | | dump_sframe_func_with_fres (sframe_decoder_ctx *sfd_ctx, |
113 | | unsigned int funcidx, |
114 | | uint64_t sec_addr) |
115 | 0 | { |
116 | 0 | uint32_t j = 0; |
117 | 0 | uint32_t num_fres = 0; |
118 | 0 | uint32_t func_size = 0; |
119 | 0 | int32_t func_start_address = 0; |
120 | 0 | unsigned char func_info = 0; |
121 | |
|
122 | 0 | uint64_t func_start_pc_vma = 0; |
123 | 0 | uint64_t fre_start_pc_vma = 0; |
124 | 0 | const char *base_reg_str[] = {"fp", "sp"}; |
125 | 0 | int32_t cfa_offset = 0; |
126 | 0 | int32_t fp_offset = 0; |
127 | 0 | int32_t ra_offset = 0; |
128 | 0 | uint8_t base_reg_id = 0; |
129 | 0 | int err[3] = {0, 0, 0}; |
130 | |
|
131 | 0 | sframe_frame_row_entry fre; |
132 | | |
133 | | /* Get the SFrame function descriptor. */ |
134 | 0 | sframe_decoder_get_funcdesc (sfd_ctx, funcidx, &num_fres, |
135 | 0 | &func_size, &func_start_address, &func_info); |
136 | | /* Calculate the virtual memory address for function start pc. Some older |
137 | | SFrame V2 sections in ET_DYN or ET_EXEC may still have the |
138 | | SFRAME_F_FDE_FUNC_START_PCREL flag unset, and hence may be using the |
139 | | old encoding. Continue to support dumping the sections at least. */ |
140 | 0 | func_start_pc_vma = func_start_address + sec_addr; |
141 | 0 | if (sframe_decoder_get_flags (sfd_ctx) & SFRAME_F_FDE_FUNC_START_PCREL) |
142 | 0 | func_start_pc_vma += sframe_decoder_get_offsetof_fde_start_addr (sfd_ctx, |
143 | 0 | funcidx, |
144 | 0 | NULL); |
145 | | |
146 | | /* Mark FDEs with [m] where the FRE start address is interpreted as a |
147 | | mask. */ |
148 | 0 | int fde_type_addrmask_p = (SFRAME_V1_FUNC_FDE_TYPE (func_info) |
149 | 0 | == SFRAME_FDE_TYPE_PCMASK); |
150 | 0 | const char *fde_type_marker |
151 | 0 | = (fde_type_addrmask_p ? "[m]" : " "); |
152 | |
|
153 | 0 | printf ("\n func idx [%d]: pc = 0x%"PRIx64 ", size = %d bytes", |
154 | 0 | funcidx, |
155 | 0 | func_start_pc_vma, |
156 | 0 | func_size); |
157 | |
|
158 | 0 | if (is_sframe_abi_arch_aarch64 (sfd_ctx) |
159 | 0 | && (SFRAME_V1_FUNC_PAUTH_KEY (func_info) == SFRAME_AARCH64_PAUTH_KEY_B)) |
160 | 0 | printf (", pauth = B key"); |
161 | |
|
162 | 0 | char temp[100]; |
163 | |
|
164 | 0 | printf ("\n %-7s%-8s %-10s%-10s%-13s", |
165 | 0 | "STARTPC", fde_type_marker, "CFA", "FP", "RA"); |
166 | 0 | for (j = 0; j < num_fres; j++) |
167 | 0 | { |
168 | 0 | sframe_decoder_get_fre (sfd_ctx, funcidx, j, &fre); |
169 | |
|
170 | 0 | fre_start_pc_vma = (fde_type_addrmask_p |
171 | 0 | ? fre.fre_start_addr |
172 | 0 | : func_start_pc_vma + fre.fre_start_addr); |
173 | | |
174 | | /* FIXME - fixup the err caching in array. |
175 | | assert no error for base reg id. */ |
176 | 0 | base_reg_id = sframe_fre_get_base_reg_id (&fre, &err[0]); |
177 | 0 | cfa_offset = sframe_fre_get_cfa_offset (sfd_ctx, &fre, &err[0]); |
178 | 0 | fp_offset = sframe_fre_get_fp_offset (sfd_ctx, &fre, &err[1]); |
179 | 0 | ra_offset = sframe_fre_get_ra_offset (sfd_ctx, &fre, &err[2]); |
180 | | |
181 | | /* Dump CFA info. */ |
182 | 0 | printf ("\n"); |
183 | 0 | printf (" %016"PRIx64, fre_start_pc_vma); |
184 | 0 | sprintf (temp, "%s+%d", base_reg_str[base_reg_id], cfa_offset); |
185 | 0 | printf (" %-10s", temp); |
186 | | |
187 | | /* Dump SP/FP info. */ |
188 | 0 | if (err[1] == 0) |
189 | 0 | sprintf (temp, "c%+d", fp_offset); |
190 | 0 | else |
191 | 0 | strcpy (temp, "u"); |
192 | 0 | printf ("%-10s", temp); |
193 | | |
194 | | /* Dump RA info. |
195 | | If an ABI does not track RA offset, e.g., AMD64, display 'f', |
196 | | else display the offset d as 'c+-d'. */ |
197 | 0 | if (sframe_decoder_get_fixed_ra_offset (sfd_ctx) |
198 | 0 | != SFRAME_CFA_FIXED_RA_INVALID) |
199 | 0 | strcpy (temp, "f"); |
200 | 0 | else if (err[2] == 0) |
201 | 0 | sprintf (temp, "c%+d", ra_offset); |
202 | 0 | else |
203 | 0 | strcpy (temp, "u"); |
204 | | |
205 | | /* Mark SFrame FRE's RA information with "[s]" if the RA is mangled |
206 | | with signature bits. */ |
207 | 0 | const char *ra_mangled_p_str |
208 | 0 | = ((sframe_fre_get_ra_mangled_p (sfd_ctx, &fre, &err[2])) |
209 | 0 | ? "[s]" : " "); |
210 | 0 | strcat (temp, ra_mangled_p_str); |
211 | 0 | printf ("%-13s", temp); |
212 | 0 | } |
213 | 0 | } |
214 | | |
215 | | static void |
216 | | dump_sframe_functions (sframe_decoder_ctx *sfd_ctx, uint64_t sec_addr) |
217 | 0 | { |
218 | 0 | uint32_t i; |
219 | 0 | uint32_t num_fdes; |
220 | |
|
221 | 0 | const char* subsec_name = "Function Index"; |
222 | 0 | printf ("\n %s :\n", subsec_name); |
223 | |
|
224 | 0 | num_fdes = sframe_decoder_get_num_fidx (sfd_ctx); |
225 | 0 | for (i = 0; i < num_fdes; i++) |
226 | 0 | { |
227 | 0 | dump_sframe_func_with_fres (sfd_ctx, i, sec_addr); |
228 | 0 | printf ("\n"); |
229 | 0 | } |
230 | 0 | } |
231 | | |
232 | | void |
233 | | dump_sframe (sframe_decoder_ctx *sfd_ctx, uint64_t sec_addr) |
234 | 0 | { |
235 | 0 | uint8_t ver; |
236 | |
|
237 | 0 | dump_sframe_header (sfd_ctx); |
238 | |
|
239 | 0 | ver = sframe_decoder_get_version (sfd_ctx); |
240 | 0 | if (ver == SFRAME_VERSION) |
241 | 0 | dump_sframe_functions (sfd_ctx, sec_addr); |
242 | 0 | else |
243 | 0 | printf ("\n No further information can be displayed. %s", |
244 | 0 | "SFrame version not supported\n"); |
245 | 0 | } |