/src/binutils-gdb/libsframe/sframe-dump.c
Line | Count | Source |
1 | | /* sframe-dump.c - Textual dump of .sframe. |
2 | | |
3 | | Copyright (C) 2022-2026 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 | | typedef struct |
27 | | { |
28 | | unsigned int reg_num; |
29 | | const char *reg_name; |
30 | | } sframe_reg_map_entry; |
31 | | |
32 | | typedef struct |
33 | | { |
34 | | const sframe_reg_map_entry *reg_map; |
35 | | size_t map_size; |
36 | | } sframe_abi_reg_map; |
37 | | |
38 | | /* Register number - Register name pair. |
39 | | Stack pointer (sp) and Frame pointer (fp) pairs. */ |
40 | | #define SFRAME_SP(num) { num, "sp" } |
41 | | #define SFRAME_FP(num) { num, "fp" } |
42 | | |
43 | | #define SFRAME_ABI_REG_MAP(abi_str, ...) \ |
44 | | const sframe_reg_map_entry abi_str##_reg_map_entries[] = { __VA_ARGS__ }; \ |
45 | | const sframe_abi_reg_map abi_str##_sframe_abi_reg_map = { \ |
46 | | abi_str##_reg_map_entries, \ |
47 | | (sizeof (abi_str##_reg_map_entries) \ |
48 | | / sizeof (abi_str##_reg_map_entries[0])) \ |
49 | | }; |
50 | | |
51 | | /* Create a map for each supported arch specifying DWARF register numbers for |
52 | | stack pointer and frame pointer. */ |
53 | | SFRAME_ABI_REG_MAP (amd64, SFRAME_SP (7), SFRAME_FP (6)); |
54 | | SFRAME_ABI_REG_MAP (aarch64, SFRAME_SP (31), SFRAME_FP (29)); |
55 | | SFRAME_ABI_REG_MAP (s390x, SFRAME_SP (15), SFRAME_FP (11)); |
56 | | |
57 | | static const char * |
58 | | sframe_get_reg_name (uint8_t abi_arch, unsigned int reg_num, char *buf, |
59 | | size_t buf_size) |
60 | 0 | { |
61 | 0 | const char *reg_name = NULL; |
62 | 0 | const sframe_abi_reg_map *abi_reg_map = NULL; |
63 | |
|
64 | 0 | switch (abi_arch) |
65 | 0 | { |
66 | 0 | case SFRAME_ABI_AARCH64_ENDIAN_BIG: |
67 | 0 | case SFRAME_ABI_AARCH64_ENDIAN_LITTLE: |
68 | 0 | abi_reg_map = &aarch64_sframe_abi_reg_map; |
69 | 0 | break; |
70 | 0 | case SFRAME_ABI_AMD64_ENDIAN_LITTLE: |
71 | 0 | abi_reg_map = &amd64_sframe_abi_reg_map; |
72 | 0 | break; |
73 | 0 | case SFRAME_ABI_S390X_ENDIAN_BIG: |
74 | 0 | abi_reg_map = &s390x_sframe_abi_reg_map; |
75 | 0 | break; |
76 | 0 | default: |
77 | 0 | sframe_assert (false); |
78 | 0 | break; |
79 | 0 | } |
80 | | |
81 | 0 | if (abi_reg_map->reg_map[0].reg_num == reg_num) |
82 | 0 | reg_name = abi_reg_map->reg_map[0].reg_name; |
83 | 0 | else if (abi_reg_map->reg_map[1].reg_num == reg_num) |
84 | 0 | reg_name = abi_reg_map->reg_map[1].reg_name; |
85 | | |
86 | | /* Handle fallback if name is missing or reg num is non-SP/FP. */ |
87 | 0 | if (reg_name == NULL) |
88 | 0 | { |
89 | 0 | snprintf (buf, buf_size, "r%u", reg_num); |
90 | 0 | reg_name = buf; |
91 | 0 | } |
92 | |
|
93 | 0 | return reg_name; |
94 | 0 | } |
95 | | |
96 | | /* Return TRUE if the SFrame section is associated with the aarch64 ABIs. */ |
97 | | |
98 | | static bool |
99 | | is_sframe_abi_arch_aarch64 (const sframe_decoder_ctx *sfd_ctx) |
100 | 0 | { |
101 | 0 | bool aarch64_p = false; |
102 | |
|
103 | 0 | uint8_t abi_arch = sframe_decoder_get_abi_arch (sfd_ctx); |
104 | 0 | if (abi_arch == SFRAME_ABI_AARCH64_ENDIAN_BIG |
105 | 0 | || abi_arch == SFRAME_ABI_AARCH64_ENDIAN_LITTLE) |
106 | 0 | aarch64_p = true; |
107 | |
|
108 | 0 | return aarch64_p; |
109 | 0 | } |
110 | | |
111 | | /* Return TRUE if the SFrame section is associated with the s390x ABI. */ |
112 | | |
113 | | static bool |
114 | | is_sframe_abi_arch_s390x (const sframe_decoder_ctx *sfd_ctx) |
115 | 0 | { |
116 | 0 | return sframe_decoder_get_abi_arch (sfd_ctx) == SFRAME_ABI_S390X_ENDIAN_BIG; |
117 | 0 | } |
118 | | |
119 | | static bool |
120 | | sframe_s390x_offset_regnum_p (int32_t offset, uint8_t ver) |
121 | 0 | { |
122 | 0 | if (ver == SFRAME_VERSION_2) |
123 | 0 | return SFRAME_V2_S390X_OFFSET_IS_REGNUM (offset); |
124 | 0 | else if (ver == SFRAME_VERSION_3) |
125 | 0 | return false; |
126 | 0 | else |
127 | | /* No other version is supported yet. */ |
128 | 0 | sframe_assert (false); |
129 | 0 | } |
130 | | |
131 | | static int |
132 | | sframe_s390x_offset_decode_regnum (int32_t offset, uint8_t ver) |
133 | 0 | { |
134 | 0 | if (ver == SFRAME_VERSION_2) |
135 | 0 | return SFRAME_V2_S390X_OFFSET_DECODE_REGNUM (offset); |
136 | 0 | else |
137 | | /* No other version is supported yet. */ |
138 | 0 | sframe_assert (false); |
139 | 0 | } |
140 | | |
141 | | static void |
142 | | dump_sframe_header_flags (const sframe_decoder_ctx *sfd_ctx) |
143 | 0 | { |
144 | 0 | const char *prefix = "Flags: "; |
145 | |
|
146 | 0 | uint8_t ver = sframe_decoder_get_version (sfd_ctx); |
147 | 0 | uint8_t flags = sframe_decoder_get_flags (sfd_ctx); |
148 | |
|
149 | 0 | if (!flags) |
150 | 0 | { |
151 | 0 | printf ("%11sNONE\n", prefix); |
152 | 0 | return; |
153 | 0 | } |
154 | | |
155 | 0 | #define PRINT_FLAG(x) \ |
156 | 0 | if (flags & (x)) \ |
157 | 0 | { flags = (flags & ~(x)); \ |
158 | 0 | printf ("%11s%s%s\n", prefix, #x, flags ? "," : ""); \ |
159 | 0 | prefix = " "; \ |
160 | 0 | } |
161 | | |
162 | 0 | PRINT_FLAG (SFRAME_F_FDE_SORTED); |
163 | | /* SFRAME_F_FRAME_POINTER has been removed from SFrame V3 and beyond. */ |
164 | 0 | if (ver == SFRAME_VERSION_2) |
165 | 0 | PRINT_FLAG (SFRAME_F_FRAME_POINTER); |
166 | 0 | PRINT_FLAG (SFRAME_F_FDE_FUNC_START_PCREL); |
167 | 0 | #undef PRINT_FLAG |
168 | | |
169 | | /* Print any residual flags, should this implementation be out of sync when |
170 | | new flags are added. */ |
171 | 0 | if (flags) |
172 | 0 | printf ("%11s%d\n", prefix, flags); |
173 | 0 | } |
174 | | |
175 | | static void |
176 | | dump_sframe_header (const sframe_decoder_ctx *sfd_ctx) |
177 | 0 | { |
178 | 0 | uint8_t ver; |
179 | 0 | const char *ver_str = NULL; |
180 | 0 | int8_t cfa_fixed_fp_offset; |
181 | 0 | int8_t cfa_fixed_ra_offset; |
182 | 0 | const sframe_header *header = &(sfd_ctx->sfd_header); |
183 | | |
184 | | /* Prepare SFrame section version string. */ |
185 | 0 | const char *version_names[] |
186 | 0 | = { "NULL", |
187 | 0 | "SFRAME_VERSION_1", |
188 | 0 | "SFRAME_VERSION_2", |
189 | 0 | "SFRAME_VERSION_3" }; |
190 | |
|
191 | 0 | ver = sframe_decoder_get_version (sfd_ctx); |
192 | 0 | if (ver <= SFRAME_VERSION) |
193 | 0 | ver_str = version_names[ver]; |
194 | | |
195 | | /* CFA fixed FP and RA offsets. */ |
196 | 0 | cfa_fixed_fp_offset = header->sfh_cfa_fixed_fp_offset; |
197 | 0 | cfa_fixed_ra_offset = header->sfh_cfa_fixed_ra_offset; |
198 | |
|
199 | 0 | const char* subsec_name = "Header"; |
200 | 0 | printf ("\n"); |
201 | 0 | printf (" %s :\n", subsec_name); |
202 | 0 | printf ("\n"); |
203 | 0 | printf (" Version: %s\n", ver_str); |
204 | |
|
205 | 0 | dump_sframe_header_flags (sfd_ctx); |
206 | |
|
207 | 0 | if (cfa_fixed_fp_offset != SFRAME_CFA_FIXED_FP_INVALID) |
208 | 0 | printf (" CFA fixed FP offset: %d\n", cfa_fixed_fp_offset); |
209 | 0 | if (cfa_fixed_ra_offset != SFRAME_CFA_FIXED_RA_INVALID) |
210 | 0 | printf (" CFA fixed RA offset: %d\n", cfa_fixed_ra_offset); |
211 | 0 | printf (" Num FDEs: %d\n", sframe_decoder_get_num_fidx (sfd_ctx)); |
212 | 0 | printf (" Num FREs: %d\n", header->sfh_num_fres); |
213 | 0 | } |
214 | | |
215 | | static void |
216 | | dump_sframe_func_fres_simple (const sframe_decoder_ctx *sfd_ctx, |
217 | | unsigned int funcidx, |
218 | | uint32_t num_fres, |
219 | | int64_t func_start_pc_vma, |
220 | | bool pc_mask_p) |
221 | 0 | { |
222 | 0 | uint32_t j = 0; |
223 | 0 | const char *base_reg_str[] = {"fp", "sp"}; |
224 | 0 | bool ra_undefined_p = false; |
225 | 0 | int32_t cfa_offset = 0; |
226 | 0 | int32_t fp_offset = 0; |
227 | 0 | int32_t ra_offset = 0; |
228 | 0 | uint8_t base_reg_id = 0; |
229 | 0 | int err[3] = {0, 0, 0}; |
230 | |
|
231 | 0 | sframe_frame_row_entry fre; |
232 | |
|
233 | 0 | uint8_t ver = sframe_decoder_get_version (sfd_ctx); |
234 | 0 | char temp[100] = {0}; |
235 | 0 | for (j = 0; j < num_fres; j++) |
236 | 0 | { |
237 | 0 | sframe_decoder_get_fre (sfd_ctx, funcidx, j, &fre); |
238 | |
|
239 | 0 | int64_t fre_start_pc_vma = (pc_mask_p |
240 | 0 | ? fre.fre_start_addr |
241 | 0 | : func_start_pc_vma + fre.fre_start_addr); |
242 | | |
243 | | /* FIXME - fixup the err caching in array. |
244 | | assert no error for base reg id and RA undefined. */ |
245 | 0 | base_reg_id = sframe_fre_get_base_reg_id (&fre, &err[0]); |
246 | 0 | ra_undefined_p = sframe_fre_get_ra_undefined_p (sfd_ctx, &fre, &err[0]); |
247 | 0 | cfa_offset = sframe_fre_get_cfa_offset (sfd_ctx, &fre, |
248 | 0 | SFRAME_FDE_TYPE_DEFAULT, |
249 | 0 | &err[0]); |
250 | 0 | fp_offset = sframe_fre_get_fp_offset (sfd_ctx, &fre, |
251 | 0 | SFRAME_FDE_TYPE_DEFAULT, &err[1]); |
252 | 0 | ra_offset = sframe_fre_get_ra_offset (sfd_ctx, &fre, |
253 | 0 | SFRAME_FDE_TYPE_DEFAULT, &err[2]); |
254 | | |
255 | | /* Dump VMA. */ |
256 | 0 | printf ("\n"); |
257 | 0 | printf (" %016"PRIx64, fre_start_pc_vma); |
258 | | |
259 | | /* Dump RA undefined (FRE without any offsets). */ |
260 | 0 | if (ra_undefined_p) |
261 | 0 | { |
262 | 0 | printf (" RA undefined"); |
263 | 0 | continue; |
264 | 0 | } |
265 | | |
266 | | /* Dump CFA info. */ |
267 | 0 | sprintf (temp, "%s+%d", base_reg_str[base_reg_id], cfa_offset); |
268 | 0 | printf (" %-10s", temp); |
269 | | |
270 | | /* Dump SP/FP info. */ |
271 | 0 | if (err[1] == 0) |
272 | 0 | { |
273 | 0 | if (is_sframe_abi_arch_s390x (sfd_ctx) |
274 | 0 | && sframe_s390x_offset_regnum_p (fp_offset, ver)) |
275 | 0 | sprintf (temp, "r%d", |
276 | 0 | sframe_s390x_offset_decode_regnum (fp_offset, ver)); |
277 | 0 | else |
278 | 0 | sprintf (temp, "c%+d", fp_offset); |
279 | 0 | } |
280 | 0 | else |
281 | 0 | strcpy (temp, "u"); |
282 | 0 | printf ("%-10s", temp); |
283 | | |
284 | | /* Dump RA info. |
285 | | If an ABI does not track RA offset, e.g., AMD64, display 'f', |
286 | | else display the offset d as 'c+-d'. */ |
287 | 0 | if (sframe_decoder_get_fixed_ra_offset (sfd_ctx) |
288 | 0 | != SFRAME_CFA_FIXED_RA_INVALID) |
289 | 0 | strcpy (temp, "f"); |
290 | | /* If an ABI does track RA offset, e.g. s390x, it can be a padding |
291 | | to represent FP without RA being saved on stack. */ |
292 | 0 | else if (err[2] == 0 && ra_offset == SFRAME_FRE_RA_OFFSET_INVALID) |
293 | 0 | sprintf (temp, "U"); |
294 | 0 | else if (err[2] == 0) |
295 | 0 | { |
296 | 0 | if (is_sframe_abi_arch_s390x (sfd_ctx) |
297 | 0 | && sframe_s390x_offset_regnum_p (ra_offset, ver)) |
298 | 0 | sprintf (temp, "r%d", |
299 | 0 | sframe_s390x_offset_decode_regnum (ra_offset, ver)); |
300 | 0 | else |
301 | 0 | sprintf (temp, "c%+d", ra_offset); |
302 | 0 | } |
303 | 0 | else |
304 | 0 | strcpy (temp, "u"); |
305 | | |
306 | | /* Mark SFrame FRE's RA information with "[s]" if the RA is mangled |
307 | | with signature bits. */ |
308 | 0 | const char *ra_mangled_p_str |
309 | 0 | = ((sframe_fre_get_ra_mangled_p (sfd_ctx, &fre, &err[2])) |
310 | 0 | ? "[s]" : " "); |
311 | 0 | strcat (temp, ra_mangled_p_str); |
312 | 0 | printf ("%-13s", temp); |
313 | 0 | } |
314 | 0 | } |
315 | | |
316 | | /* Helper to safely format "reg+offset" or "(reg+offset)". */ |
317 | | |
318 | | static void |
319 | | sframe_format_fre_disp (char *buf, size_t size, uint8_t abi_arch, |
320 | | unsigned int reg_num, bool reg_p, int32_t offset, |
321 | | bool deref_p) |
322 | 0 | { |
323 | | /* Initialize to string for CFA-based. */ |
324 | 0 | const char *reg_name = "c"; |
325 | | |
326 | | /* Allocate space for the potential fallback name (e.g., "r12") */ |
327 | 0 | char temp_reg_name[32] = {0}; |
328 | 0 | if (reg_p) |
329 | 0 | reg_name = sframe_get_reg_name (abi_arch, reg_num, temp_reg_name, |
330 | 0 | sizeof (temp_reg_name)); |
331 | |
|
332 | 0 | if (deref_p) |
333 | 0 | snprintf (buf, size, "(%s%+d)", reg_name, offset); |
334 | 0 | else |
335 | 0 | snprintf (buf, size, "%s%+d", reg_name, offset); |
336 | 0 | } |
337 | | |
338 | | static void |
339 | | dump_sframe_func_fres_flex (const sframe_decoder_ctx *sfd_ctx, |
340 | | unsigned int funcidx, |
341 | | uint32_t num_fres, |
342 | | int64_t func_start_pc_vma, |
343 | | bool pc_mask_p) |
344 | 0 | { |
345 | 0 | uint32_t j = 0; |
346 | 0 | bool ra_undefined_p = false; |
347 | 0 | int64_t fre_start_pc_vma = 0; |
348 | 0 | uint32_t fde_type = SFRAME_FDE_TYPE_FLEX; |
349 | |
|
350 | 0 | sframe_frame_row_entry fre; |
351 | 0 | char temp[100] = {0}; |
352 | |
|
353 | 0 | for (j = 0; j < num_fres; j++) |
354 | 0 | { |
355 | 0 | sframe_decoder_get_fre (sfd_ctx, funcidx, j, &fre); |
356 | |
|
357 | 0 | fre_start_pc_vma = (pc_mask_p |
358 | 0 | ? fre.fre_start_addr |
359 | 0 | : func_start_pc_vma + fre.fre_start_addr); |
360 | | |
361 | | /* Dump VMA. */ |
362 | 0 | printf ("\n"); |
363 | 0 | printf (" %016"PRIx64, fre_start_pc_vma); |
364 | |
|
365 | 0 | int err_ra_offset = 0; |
366 | | /* Dump RA undefined (FRE without any offsets). */ |
367 | 0 | ra_undefined_p = sframe_fre_get_ra_undefined_p (sfd_ctx, &fre, |
368 | 0 | &err_ra_offset); |
369 | 0 | sframe_assert (!err_ra_offset); |
370 | 0 | if (ra_undefined_p) |
371 | 0 | { |
372 | 0 | printf (" RA undefined"); |
373 | 0 | continue; |
374 | 0 | } |
375 | | |
376 | 0 | unsigned int cfa_reg = 0, ra_reg = 0, fp_reg = 0; |
377 | 0 | bool cfa_deref_p = 0, ra_deref_p = 0, fp_deref_p = 0; |
378 | |
|
379 | 0 | int err_cfa_reg = 0; |
380 | 0 | int err_cfa_offset = 0; |
381 | | /* Read the Register/Control Data as unsigned. */ |
382 | 0 | uint32_t cfa_reg_data |
383 | 0 | = sframe_get_fre_udata (&fre, SFRAME_FRE_CFA_OFFSET_IDX, |
384 | 0 | &err_cfa_reg); |
385 | 0 | int32_t cfa_offset = sframe_fre_get_cfa_offset (sfd_ctx, &fre, fde_type, |
386 | 0 | &err_cfa_offset); |
387 | 0 | sframe_assert (!err_cfa_reg && !err_cfa_offset); |
388 | 0 | bool cfa_reg_p = SFRAME_V3_FLEX_FDE_CTRLWORD_REG_P (cfa_reg_data); |
389 | 0 | if (cfa_reg_p) |
390 | 0 | { |
391 | 0 | cfa_reg = SFRAME_V3_FLEX_FDE_CTRLWORD_REGNUM (cfa_reg_data); |
392 | 0 | cfa_deref_p = SFRAME_V3_FLEX_FDE_CTRLWORD_DEREF_P (cfa_reg_data); |
393 | 0 | } |
394 | |
|
395 | 0 | int err_ra_reg = 0; |
396 | | /* Read the Register/Control Data as unsigned. */ |
397 | 0 | uint32_t ra_reg_data |
398 | 0 | = sframe_get_fre_udata (&fre, SFRAME_FRE_RA_OFFSET_IDX * 2, |
399 | 0 | &err_ra_reg); |
400 | 0 | int32_t ra_offset = sframe_fre_get_ra_offset (sfd_ctx, &fre, fde_type, |
401 | 0 | &err_ra_offset); |
402 | 0 | bool ra_reg_p = SFRAME_V3_FLEX_FDE_CTRLWORD_REG_P (ra_reg_data); |
403 | 0 | if (ra_reg_p) |
404 | 0 | { |
405 | 0 | ra_reg = SFRAME_V3_FLEX_FDE_CTRLWORD_REGNUM (ra_reg_data); |
406 | 0 | ra_deref_p = SFRAME_V3_FLEX_FDE_CTRLWORD_DEREF_P (ra_reg_data); |
407 | 0 | } |
408 | |
|
409 | 0 | int err_fp_reg = 0; |
410 | 0 | int err_fp_offset = 0; |
411 | 0 | int fp_idx = SFRAME_FRE_FP_OFFSET_IDX * 2; |
412 | 0 | if (!err_ra_reg && ra_reg_data == SFRAME_FRE_RA_OFFSET_INVALID) |
413 | 0 | fp_idx -= 1; |
414 | | |
415 | | /* Read the Register/Control Data as unsigned. */ |
416 | 0 | uint32_t fp_reg_data = sframe_get_fre_udata (&fre, fp_idx, &err_fp_reg); |
417 | 0 | int32_t fp_offset = sframe_fre_get_fp_offset (sfd_ctx, &fre, fde_type, |
418 | 0 | &err_fp_offset); |
419 | 0 | bool fp_reg_p = SFRAME_V3_FLEX_FDE_CTRLWORD_REG_P (fp_reg_data); |
420 | 0 | if (fp_reg_p) |
421 | 0 | { |
422 | 0 | fp_reg = SFRAME_V3_FLEX_FDE_CTRLWORD_REGNUM (fp_reg_data); |
423 | 0 | fp_deref_p = SFRAME_V3_FLEX_FDE_CTRLWORD_DEREF_P (fp_reg_data); |
424 | 0 | } |
425 | | |
426 | | /* Dump CFA info. */ |
427 | 0 | uint8_t abi_arch = sframe_decoder_get_abi_arch (sfd_ctx); |
428 | 0 | sframe_format_fre_disp (temp, sizeof (temp), abi_arch, cfa_reg, |
429 | 0 | cfa_reg_p, cfa_offset, cfa_deref_p); |
430 | 0 | printf (" %-10s", temp); |
431 | | |
432 | | /* Dump FP info. */ |
433 | 0 | if (!err_fp_reg && !err_fp_offset) |
434 | 0 | sframe_format_fre_disp (temp, sizeof (temp), abi_arch, fp_reg, |
435 | 0 | fp_reg_p, fp_offset, fp_deref_p); |
436 | 0 | else |
437 | 0 | strcpy (temp, "u"); |
438 | 0 | printf ("%-10s", temp); |
439 | | |
440 | | /* Dump RA info. |
441 | | Even if an ABI does not track RA offset, e.g., AMD64, for flex |
442 | | frame, it may have RA recovery from register. Else, display 'f'. */ |
443 | 0 | if (err_ra_reg) |
444 | 0 | { |
445 | 0 | if (sframe_decoder_get_fixed_ra_offset (sfd_ctx) |
446 | 0 | != SFRAME_CFA_FIXED_RA_INVALID) |
447 | 0 | strcpy (temp, "f"); |
448 | 0 | else |
449 | 0 | strcpy (temp, "u"); |
450 | 0 | } |
451 | 0 | else if (ra_reg_data == SFRAME_FRE_RA_OFFSET_INVALID) |
452 | 0 | strcpy (temp, "U"); |
453 | 0 | else |
454 | 0 | sframe_format_fre_disp (temp, sizeof (temp), abi_arch, ra_reg, |
455 | 0 | ra_reg_p, ra_offset, ra_deref_p); |
456 | | |
457 | | /* Mark SFrame FRE's RA information with "[s]" if the RA is mangled |
458 | | with signature bits. */ |
459 | 0 | err_ra_offset = 0; |
460 | 0 | const char *ra_mangled_p_str |
461 | 0 | = ((sframe_fre_get_ra_mangled_p (sfd_ctx, &fre, &err_ra_offset)) |
462 | 0 | ? "[s]" : " "); |
463 | 0 | sframe_assert (!err_ra_offset); |
464 | 0 | strcat (temp, ra_mangled_p_str); |
465 | 0 | printf ("%-13s", temp); |
466 | 0 | } |
467 | 0 | } |
468 | | |
469 | | static void |
470 | | dump_sframe_func_with_fres (const sframe_decoder_ctx *sfd_ctx, |
471 | | unsigned int funcidx, |
472 | | uint64_t sec_addr) |
473 | 0 | { |
474 | 0 | uint32_t num_fres = 0; |
475 | 0 | uint32_t func_size = 0; |
476 | 0 | uint64_t func_start_pc_vma = 0; |
477 | 0 | unsigned char func_info = 0; |
478 | 0 | unsigned char func_info2 = 0; |
479 | 0 | uint8_t rep_block_size = 0; |
480 | |
|
481 | 0 | uint8_t ver = sframe_decoder_get_version (sfd_ctx); |
482 | 0 | sframe_assert (ver == SFRAME_VERSION_3 || ver == SFRAME_VERSION_2); |
483 | | /* Get the SFrame function descriptor - all data including the index and |
484 | | attributes. */ |
485 | 0 | if (ver == SFRAME_VERSION_3) |
486 | 0 | { |
487 | 0 | int64_t func_start_addr = 0; |
488 | 0 | sframe_decoder_get_funcdesc_v3 (sfd_ctx, funcidx, &num_fres, &func_size, |
489 | 0 | &func_start_addr, &func_info, |
490 | 0 | &func_info2, &rep_block_size); |
491 | 0 | func_start_pc_vma = func_start_addr + sec_addr; |
492 | 0 | } |
493 | 0 | else |
494 | 0 | { |
495 | 0 | int32_t func_start_addr = 0; |
496 | 0 | sframe_decoder_get_funcdesc_v2 (sfd_ctx, funcidx, &num_fres, &func_size, |
497 | 0 | &func_start_addr, &func_info, |
498 | 0 | &rep_block_size); |
499 | 0 | func_start_pc_vma = func_start_addr + sec_addr; |
500 | 0 | } |
501 | | |
502 | | /* Calculate the virtual memory address for function start pc. Some older |
503 | | SFrame V2 sections in ET_DYN or ET_EXEC may still have the |
504 | | SFRAME_F_FDE_FUNC_START_PCREL flag unset, and hence may be using the old |
505 | | encoding. Continue to support dumping the sections at least. */ |
506 | 0 | if (sframe_decoder_get_flags (sfd_ctx) & SFRAME_F_FDE_FUNC_START_PCREL) |
507 | 0 | func_start_pc_vma += sframe_decoder_get_offsetof_fde_start_addr (sfd_ctx, |
508 | 0 | funcidx, |
509 | 0 | NULL); |
510 | | |
511 | | /* Gather all FDE attributes. Use a single snprintf to: |
512 | | - Include 'S', if fde_signal_p is true |
513 | | - Include 'F', if flex_p is true. */ |
514 | 0 | char attrs[16] = {0}; |
515 | 0 | bool fde_signal_p = SFRAME_V3_FDE_SIGNAL_P (func_info); |
516 | 0 | bool flex_p = (SFRAME_V3_FDE_TYPE (func_info2) == SFRAME_FDE_TYPE_FLEX); |
517 | 0 | snprintf (attrs, sizeof (attrs), "%s%s", |
518 | 0 | fde_signal_p ? "S" : "", |
519 | 0 | flex_p ? "F" : ""); |
520 | |
|
521 | 0 | printf ("\n func idx [%d]: pc = 0x%"PRIx64 ", size = %d bytes", |
522 | 0 | funcidx, |
523 | 0 | func_start_pc_vma, |
524 | 0 | func_size); |
525 | | /* Print attributes if they exist. */ |
526 | 0 | if (attrs[0]) |
527 | 0 | printf (", attr = \"%s\"", attrs); |
528 | |
|
529 | 0 | if (is_sframe_abi_arch_aarch64 (sfd_ctx) |
530 | 0 | && (SFRAME_V2_FUNC_PAUTH_KEY (func_info) == SFRAME_AARCH64_PAUTH_KEY_B)) |
531 | 0 | printf (", pauth = B key"); |
532 | | |
533 | | /* Mark FDEs with [m] where the FRE start address is interpreted as a |
534 | | mask. */ |
535 | 0 | bool pc_mask_p |
536 | 0 | = (SFRAME_V2_FUNC_PC_TYPE (func_info) == SFRAME_V3_FDE_PCTYPE_MASK); |
537 | 0 | const char *pc_mask_marker = (pc_mask_p ? "[m]" : " "); |
538 | 0 | printf ("\n %-7s%-8s %-10s%-10s%-13s", |
539 | 0 | "STARTPC", pc_mask_marker, "CFA", "FP", "RA"); |
540 | |
|
541 | 0 | if (!flex_p) |
542 | 0 | dump_sframe_func_fres_simple (sfd_ctx, funcidx, num_fres, |
543 | 0 | func_start_pc_vma, pc_mask_p); |
544 | 0 | else |
545 | 0 | dump_sframe_func_fres_flex (sfd_ctx, funcidx, num_fres, func_start_pc_vma, |
546 | 0 | pc_mask_p); |
547 | 0 | } |
548 | | |
549 | | static void |
550 | | dump_sframe_functions (const sframe_decoder_ctx *sfd_ctx, uint64_t sec_addr) |
551 | 0 | { |
552 | 0 | uint32_t i; |
553 | 0 | uint32_t num_fdes; |
554 | |
|
555 | 0 | const char* subsec_name = "Function Index"; |
556 | 0 | printf ("\n %s :\n", subsec_name); |
557 | |
|
558 | 0 | num_fdes = sframe_decoder_get_num_fidx (sfd_ctx); |
559 | 0 | for (i = 0; i < num_fdes; i++) |
560 | 0 | { |
561 | 0 | dump_sframe_func_with_fres (sfd_ctx, i, sec_addr); |
562 | 0 | printf ("\n"); |
563 | 0 | } |
564 | 0 | } |
565 | | |
566 | | void |
567 | | dump_sframe (const sframe_decoder_ctx *sfd_ctx, uint64_t sec_addr) |
568 | 0 | { |
569 | 0 | dump_sframe_header (sfd_ctx); |
570 | |
|
571 | 0 | uint8_t ver = sframe_decoder_get_version (sfd_ctx); |
572 | | /* Although newer gas and ld do not generate SFrame V2, continue to support |
573 | | textual dump of SFrame V2 sections ATM. */ |
574 | 0 | if (ver == SFRAME_VERSION_3 || ver == SFRAME_VERSION_2) |
575 | 0 | dump_sframe_functions (sfd_ctx, sec_addr); |
576 | 0 | else |
577 | 0 | printf ("\n No further information can be displayed. %s", |
578 | 0 | "SFrame version not supported\n"); |
579 | 0 | } |