]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blob - libsframe/sframe.c
libsframe: minor fixups in flip_fre related functions
[thirdparty/binutils-gdb.git] / libsframe / sframe.c
1 /* sframe.c - SFrame decoder/encoder.
2
3 Copyright (C) 2022-2023 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 "config.h"
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <stdarg.h>
24 #include <string.h>
25 #include "sframe-impl.h"
26 #include "swap.h"
27
28 typedef struct sf_funidx_tbl
29 {
30 unsigned int count;
31 unsigned int alloced;
32 sframe_func_desc_entry entry[1];
33 } sf_funidx_tbl;
34
35 typedef struct sf_fre_tbl
36 {
37 unsigned int count;
38 unsigned int alloced;
39 sframe_frame_row_entry entry[1];
40 } sf_fre_tbl;
41
42 #define _sf_printflike_(string_index,first_to_check) \
43 __attribute__ ((__format__ (__printf__, (string_index), (first_to_check))))
44
45 static void debug_printf (const char *, ...);
46
47 static int _sframe_debug; /* Control for printing out debug info. */
48 static int number_of_entries = 64;
49
50 static void
51 sframe_init_debug (void)
52 {
53 static int inited;
54
55 if (!inited)
56 {
57 _sframe_debug = getenv ("SFRAME_DEBUG") != NULL;
58 inited = 1;
59 }
60 }
61
62 _sf_printflike_ (1, 2)
63 static void debug_printf (const char *format, ...)
64 {
65 if (_sframe_debug)
66 {
67 va_list args;
68
69 va_start (args, format);
70 vfprintf (stderr, format, args);
71 va_end (args);
72 }
73 }
74
75 /* Generate bitmask of given size in bytes. This is used for
76 some checks on the FRE start address.
77 SFRAME_FRE_TYPE_ADDR1 => 1 byte => [ bitmask = 0xff ]
78 SFRAME_FRE_TYPE_ADDR2 => 2 byte => [ bitmask = 0xffff ]
79 SFRAME_FRE_TYPE_ADDR4 => 4 byte => [ bitmask = 0xffffffff ]. */
80 #define SFRAME_BITMASK_OF_SIZE(size_in_bytes) \
81 (((uint64_t)1 << (size_in_bytes*8)) - 1)
82
83 /* Store the specified error code into errp if it is non-NULL.
84 Return SFRAME_ERR. */
85
86 static int
87 sframe_set_errno (int *errp, int error)
88 {
89 if (errp != NULL)
90 *errp = error;
91 return SFRAME_ERR;
92 }
93
94 /* Store the specified error code into errp if it is non-NULL.
95 Return NULL. */
96
97 static void *
98 sframe_ret_set_errno (int *errp, int error)
99 {
100 if (errp != NULL)
101 *errp = error;
102 return NULL;
103 }
104
105 /* Get the SFrame header size. */
106
107 static uint32_t
108 sframe_get_hdr_size (sframe_header *sfh)
109 {
110 return SFRAME_V1_HDR_SIZE (*sfh);
111 }
112
113 /* Access functions for frame row entry data. */
114
115 static uint8_t
116 sframe_fre_get_offset_count (uint8_t fre_info)
117 {
118 return SFRAME_V1_FRE_OFFSET_COUNT (fre_info);
119 }
120
121 static uint8_t
122 sframe_fre_get_offset_size (uint8_t fre_info)
123 {
124 return SFRAME_V1_FRE_OFFSET_SIZE (fre_info);
125 }
126
127 static bool
128 sframe_get_fre_ra_mangled_p (uint8_t fre_info)
129 {
130 return SFRAME_V1_FRE_MANGLED_RA_P (fre_info);
131 }
132
133 /* Access functions for info from function descriptor entry. */
134
135 static unsigned int
136 sframe_get_fre_type (sframe_func_desc_entry *fdep)
137 {
138 unsigned int fre_type = 0;
139 if (fdep)
140 fre_type = SFRAME_V1_FUNC_FRE_TYPE (fdep->sfde_func_info);
141 return fre_type;
142 }
143
144 static unsigned int
145 sframe_get_fde_type (sframe_func_desc_entry *fdep)
146 {
147 unsigned int fde_type = 0;
148 if (fdep)
149 fde_type = SFRAME_V1_FUNC_FDE_TYPE (fdep->sfde_func_info);
150 return fde_type;
151 }
152
153 /* Check if flipping is needed, based on ENDIAN. */
154
155 static int
156 need_swapping (int endian)
157 {
158 unsigned int ui = 1;
159 char *c = (char *)&ui;
160 int is_little = (int)*c;
161
162 switch (endian)
163 {
164 case SFRAME_ABI_AARCH64_ENDIAN_LITTLE:
165 case SFRAME_ABI_AMD64_ENDIAN_LITTLE:
166 return !is_little;
167 case SFRAME_ABI_AARCH64_ENDIAN_BIG:
168 return is_little;
169 default:
170 break;
171 }
172
173 return 0;
174 }
175
176 /* Flip the endianness of the SFrame header. */
177
178 static void
179 flip_header (sframe_header *sfheader)
180 {
181 swap_thing (sfheader->sfh_preamble.sfp_magic);
182 swap_thing (sfheader->sfh_preamble.sfp_version);
183 swap_thing (sfheader->sfh_preamble.sfp_flags);
184 swap_thing (sfheader->sfh_cfa_fixed_fp_offset);
185 swap_thing (sfheader->sfh_cfa_fixed_ra_offset);
186 swap_thing (sfheader->sfh_num_fdes);
187 swap_thing (sfheader->sfh_num_fres);
188 swap_thing (sfheader->sfh_fre_len);
189 swap_thing (sfheader->sfh_fdeoff);
190 swap_thing (sfheader->sfh_freoff);
191 }
192
193 static void
194 flip_fde (sframe_func_desc_entry *fdep)
195 {
196 swap_thing (fdep->sfde_func_start_address);
197 swap_thing (fdep->sfde_func_size);
198 swap_thing (fdep->sfde_func_start_fre_off);
199 swap_thing (fdep->sfde_func_num_fres);
200 }
201
202 /* Check if SFrame header has valid data. */
203
204 static bool
205 sframe_header_sanity_check_p (sframe_header *hp)
206 {
207 unsigned char all_flags = SFRAME_F_FDE_SORTED | SFRAME_F_FRAME_POINTER;
208 /* Check preamble is valid. */
209 if ((hp->sfh_preamble.sfp_magic != SFRAME_MAGIC)
210 || (hp->sfh_preamble.sfp_version != SFRAME_VERSION)
211 || ((hp->sfh_preamble.sfp_flags | all_flags) != all_flags))
212 return false;
213
214 /* Check offsets are valid. */
215 if (hp->sfh_fdeoff > hp->sfh_freoff)
216 return false;
217
218 return true;
219 }
220
221 /* Flip the start address pointed to by FP. */
222
223 static void
224 flip_fre_start_address (char *addr, unsigned int fre_type)
225 {
226 if (fre_type == SFRAME_FRE_TYPE_ADDR2)
227 {
228 uint16_t *start_addr = (uint16_t *)addr;
229 swap_thing (*start_addr);
230 }
231 else if (fre_type == SFRAME_FRE_TYPE_ADDR4)
232 {
233 uint32_t *start_addr = (uint32_t *)addr;
234 swap_thing (*start_addr);
235 }
236 }
237
238 static void
239 flip_fre_stack_offsets (char *offsets, uint8_t offset_size, uint8_t offset_cnt)
240 {
241 int j;
242
243 if (offset_size == SFRAME_FRE_OFFSET_2B)
244 {
245 uint16_t *ust = (uint16_t *)offsets;
246 for (j = offset_cnt; j > 0; ust++, j--)
247 swap_thing (*ust);
248 }
249 else if (offset_size == SFRAME_FRE_OFFSET_4B)
250 {
251 uint32_t *uit = (uint32_t *)offsets;
252 for (j = offset_cnt; j > 0; uit++, j--)
253 swap_thing (*uit);
254 }
255 }
256
257 /* Get the FRE start address size, given the FRE_TYPE. */
258
259 static size_t
260 sframe_fre_start_addr_size (unsigned int fre_type)
261 {
262 size_t addr_size = 0;
263 switch (fre_type)
264 {
265 case SFRAME_FRE_TYPE_ADDR1:
266 addr_size = 1;
267 break;
268 case SFRAME_FRE_TYPE_ADDR2:
269 addr_size = 2;
270 break;
271 case SFRAME_FRE_TYPE_ADDR4:
272 addr_size = 4;
273 break;
274 default:
275 /* No other value is expected. */
276 sframe_assert (0);
277 break;
278 }
279 return addr_size;
280 }
281
282 /* Check if the FREP has valid data. */
283
284 static bool
285 sframe_fre_sanity_check_p (sframe_frame_row_entry *frep)
286 {
287 uint8_t offset_size, offset_cnt;
288 uint8_t fre_info;
289
290 if (frep == NULL)
291 return false;
292
293 fre_info = frep->fre_info;
294 offset_size = sframe_fre_get_offset_size (fre_info);
295
296 if (offset_size != SFRAME_FRE_OFFSET_1B
297 && offset_size != SFRAME_FRE_OFFSET_2B
298 && offset_size != SFRAME_FRE_OFFSET_4B)
299 return false;
300
301 offset_cnt = sframe_fre_get_offset_count (fre_info);
302 if (offset_cnt > 3)
303 return false;
304
305 return true;
306 }
307
308 /* Get FRE_INFO's offset size in bytes. */
309
310 static size_t
311 sframe_fre_offset_bytes_size (uint8_t fre_info)
312 {
313 uint8_t offset_size, offset_cnt;
314
315 offset_size = sframe_fre_get_offset_size (fre_info);
316
317 debug_printf ("offset_size = %u\n", offset_size);
318
319 offset_cnt = sframe_fre_get_offset_count (fre_info);
320
321 if (offset_size == SFRAME_FRE_OFFSET_2B
322 || offset_size == SFRAME_FRE_OFFSET_4B) /* 2 or 4 bytes. */
323 return (offset_cnt * (offset_size * 2));
324
325 return (offset_cnt);
326 }
327
328 /* Get total size in bytes to represent FREP in the binary format. This
329 includes the starting address, FRE info, and all the offsets. */
330
331 static size_t
332 sframe_fre_entry_size (sframe_frame_row_entry *frep, unsigned int fre_type)
333 {
334 if (frep == NULL)
335 return 0;
336
337 uint8_t fre_info = frep->fre_info;
338 size_t addr_size = sframe_fre_start_addr_size (fre_type);
339
340 return (addr_size + sizeof (frep->fre_info)
341 + sframe_fre_offset_bytes_size (fre_info));
342 }
343
344 static int
345 flip_fre (char *fp, unsigned int fre_type, size_t *fre_size)
346 {
347 uint8_t fre_info;
348 uint8_t offset_size, offset_cnt;
349 size_t addr_size, fre_info_size = 0;
350 int err = 0;
351
352 if (fre_size == NULL)
353 return sframe_set_errno (&err, SFRAME_ERR_INVAL);
354
355 flip_fre_start_address (fp, fre_type);
356
357 /* Advance the buffer pointer to where the FRE info is. */
358 addr_size = sframe_fre_start_addr_size (fre_type);
359 fp += addr_size;
360
361 /* FRE info is uint8_t. No need to flip. */
362 fre_info = *(uint8_t*)fp;
363 offset_size = sframe_fre_get_offset_size (fre_info);
364 offset_cnt = sframe_fre_get_offset_count (fre_info);
365
366 /* Advance the buffer pointer to where the stack offsets are. */
367 fre_info_size = sizeof (uint8_t);
368 fp += fre_info_size;
369 flip_fre_stack_offsets (fp, offset_size, offset_cnt);
370
371 *fre_size
372 = addr_size + fre_info_size + sframe_fre_offset_bytes_size (fre_info);
373
374 return 0;
375 }
376
377 /* Endian flip the contents of FRAME_BUF of size BUF_SIZE.
378 The SFrame header in the FRAME_BUF must be endian flipped prior to
379 calling flip_sframe.
380
381 Endian flipping at decode time vs encode time have different needs. At
382 encode time, the frame_buf is in host endianness, and hence, values should
383 be read up before the buffer is changed to foreign endianness. This change
384 of behaviour is specified via TO_FOREIGN arg.
385
386 If an error code is returned, the buffer should not be used. */
387
388 static int
389 flip_sframe (char *frame_buf, size_t buf_size, uint32_t to_foreign)
390 {
391 unsigned int i, j, prev_frep_index;
392 sframe_header *ihp;
393 char *fdes;
394 char *fp = NULL;
395 sframe_func_desc_entry *fdep;
396 unsigned int num_fdes = 0;
397 unsigned int num_fres = 0;
398 unsigned int fre_type = 0;
399 uint32_t fre_offset = 0;
400 size_t esz = 0;
401 size_t hdrsz = 0;
402 int err = 0;
403 /* For error checking. */
404 size_t bytes_flipped = 0;
405
406 /* Header must be in host endianness at this time. */
407 ihp = (sframe_header *)frame_buf;
408
409 if (!sframe_header_sanity_check_p (ihp))
410 return sframe_set_errno (&err, SFRAME_ERR_BUF_INVAL);
411
412 /* The contents of the SFrame header are safe to read. Get the number of
413 FDEs and the first FDE in the buffer. */
414 hdrsz = sframe_get_hdr_size (ihp);
415 num_fdes = ihp->sfh_num_fdes;
416 fdes = frame_buf + hdrsz + ihp->sfh_fdeoff;
417 fdep = (sframe_func_desc_entry *)fdes;
418
419 j = 0;
420 prev_frep_index = 0;
421 for (i = 0; i < num_fdes; fdep++, i++)
422 {
423 if ((char*)fdep >= (frame_buf + buf_size))
424 goto bad;
425
426 if (to_foreign)
427 {
428 num_fres = fdep->sfde_func_num_fres;
429 fre_type = sframe_get_fre_type (fdep);
430 fre_offset = fdep->sfde_func_start_fre_off;
431 }
432
433 flip_fde (fdep);
434 bytes_flipped += sizeof (sframe_func_desc_entry);
435
436 if (!to_foreign)
437 {
438 num_fres = fdep->sfde_func_num_fres;
439 fre_type = sframe_get_fre_type (fdep);
440 fre_offset = fdep->sfde_func_start_fre_off;
441 }
442
443 fp = frame_buf + sframe_get_hdr_size (ihp) + ihp->sfh_freoff;
444 fp += fre_offset;
445 for (; j < prev_frep_index + num_fres; j++)
446 {
447 if (flip_fre (fp, fre_type, &esz))
448 goto bad;
449 bytes_flipped += esz;
450
451 if (esz == 0 || esz > buf_size)
452 goto bad;
453 fp += esz;
454 }
455 prev_frep_index = j;
456 }
457 /* All FDEs and FREs must have been endian flipped by now. */
458 if ((j != ihp->sfh_num_fres) || (bytes_flipped != (buf_size - hdrsz)))
459 goto bad;
460
461 /* Success. */
462 return 0;
463 bad:
464 return SFRAME_ERR;
465 }
466
467 /* The SFrame Decoder. */
468
469 /* Get SFrame header from the given decoder context DCTX. */
470
471 static sframe_header *
472 sframe_decoder_get_header (sframe_decoder_ctx *dctx)
473 {
474 sframe_header *hp = NULL;
475 if (dctx != NULL)
476 hp = &dctx->sfd_header;
477 return hp;
478 }
479
480 /* Compare function for qsort'ing the FDE table. */
481
482 static int
483 fde_func (const void *p1, const void *p2)
484 {
485 const sframe_func_desc_entry *aa = p1;
486 const sframe_func_desc_entry *bb = p2;
487
488 if (aa->sfde_func_start_address < bb->sfde_func_start_address)
489 return -1;
490 else if (aa->sfde_func_start_address > bb->sfde_func_start_address)
491 return 1;
492 return 0;
493 }
494
495 /* Get IDX'th offset from FRE. Set errp as applicable. */
496
497 static int32_t
498 sframe_get_fre_offset (sframe_frame_row_entry *fre, int idx, int *errp)
499 {
500 uint8_t offset_cnt, offset_size;
501
502 if (fre == NULL || !sframe_fre_sanity_check_p (fre))
503 return sframe_set_errno (errp, SFRAME_ERR_FRE_INVAL);
504
505 offset_cnt = sframe_fre_get_offset_count (fre->fre_info);
506 offset_size = sframe_fre_get_offset_size (fre->fre_info);
507
508 if (offset_cnt < idx + 1)
509 return sframe_set_errno (errp, SFRAME_ERR_FREOFFSET_NOPRESENT);
510
511 if (errp)
512 *errp = 0; /* Offset Valid. */
513
514 if (offset_size == SFRAME_FRE_OFFSET_1B)
515 {
516 int8_t *sp = (int8_t *)fre->fre_offsets;
517 return sp[idx];
518 }
519 else if (offset_size == SFRAME_FRE_OFFSET_2B)
520 {
521 int16_t *sp = (int16_t *)fre->fre_offsets;
522 return sp[idx];
523 }
524 else
525 {
526 int32_t *ip = (int32_t *)fre->fre_offsets;
527 return ip[idx];
528 }
529 }
530
531 /* Free the decoder context. */
532
533 void
534 sframe_decoder_free (sframe_decoder_ctx **dctxp)
535 {
536 if (dctxp != NULL)
537 {
538 sframe_decoder_ctx *dctx = *dctxp;
539 if (dctx == NULL)
540 return;
541
542 if (dctx->sfd_funcdesc != NULL)
543 {
544 free (dctx->sfd_funcdesc);
545 dctx->sfd_funcdesc = NULL;
546 }
547 if (dctx->sfd_fres != NULL)
548 {
549 free (dctx->sfd_fres);
550 dctx->sfd_fres = NULL;
551 }
552 if (dctx->sfd_buf != NULL)
553 {
554 free (dctx->sfd_buf);
555 dctx->sfd_buf = NULL;
556 }
557
558 free (*dctxp);
559 *dctxp = NULL;
560 }
561 }
562
563 /* Create an FDE function info byte given an FRE_TYPE and an FDE_TYPE. */
564 /* FIXME API for linker. Revisit if its better placed somewhere else? */
565
566 unsigned char
567 sframe_fde_create_func_info (unsigned int fre_type,
568 unsigned int fde_type)
569 {
570 unsigned char func_info;
571 sframe_assert (fre_type == SFRAME_FRE_TYPE_ADDR1
572 || fre_type == SFRAME_FRE_TYPE_ADDR2
573 || fre_type == SFRAME_FRE_TYPE_ADDR4);
574 sframe_assert (fde_type == SFRAME_FDE_TYPE_PCINC
575 || fde_type == SFRAME_FDE_TYPE_PCMASK);
576 func_info = SFRAME_V1_FUNC_INFO (fde_type, fre_type);
577 return func_info;
578 }
579
580 /* Get the FRE type given the function size. */
581 /* FIXME API for linker. Revisit if its better placed somewhere else? */
582
583 unsigned int
584 sframe_calc_fre_type (size_t func_size)
585 {
586 unsigned int fre_type = 0;
587 if (func_size < SFRAME_FRE_TYPE_ADDR1_LIMIT)
588 fre_type = SFRAME_FRE_TYPE_ADDR1;
589 else if (func_size < SFRAME_FRE_TYPE_ADDR2_LIMIT)
590 fre_type = SFRAME_FRE_TYPE_ADDR2;
591 /* Adjust the check a bit so that it remains warning-free but meaningful
592 on 32-bit systems. */
593 else if (func_size <= (size_t) (SFRAME_FRE_TYPE_ADDR4_LIMIT - 1))
594 fre_type = SFRAME_FRE_TYPE_ADDR4;
595 return fre_type;
596 }
597
598 /* Get the base reg id from the FRE info. Set errp if failure. */
599
600 unsigned int
601 sframe_fre_get_base_reg_id (sframe_frame_row_entry *fre, int *errp)
602 {
603 if (fre == NULL)
604 return sframe_set_errno (errp, SFRAME_ERR_FRE_INVAL);
605
606 uint8_t fre_info = fre->fre_info;
607 return SFRAME_V1_FRE_CFA_BASE_REG_ID (fre_info);
608 }
609
610 /* Get the CFA offset from the FRE. If the offset is invalid, sets errp. */
611
612 int32_t
613 sframe_fre_get_cfa_offset (sframe_decoder_ctx *dctx ATTRIBUTE_UNUSED,
614 sframe_frame_row_entry *fre, int *errp)
615 {
616 return sframe_get_fre_offset (fre, SFRAME_FRE_CFA_OFFSET_IDX, errp);
617 }
618
619 /* Get the FP offset from the FRE. If the offset is invalid, sets errp. */
620
621 int32_t
622 sframe_fre_get_fp_offset (sframe_decoder_ctx *dctx,
623 sframe_frame_row_entry *fre, int *errp)
624 {
625 uint32_t fp_offset_idx = 0;
626 sframe_header *dhp = sframe_decoder_get_header (dctx);
627 /* If the FP offset is not being tracked, return an error code so the caller
628 can gather the fixed FP offset from the SFrame header. */
629 if (dhp->sfh_cfa_fixed_fp_offset != SFRAME_CFA_FIXED_FP_INVALID)
630 return sframe_set_errno (errp, SFRAME_ERR_FREOFFSET_NOPRESENT);
631
632 /* In some ABIs, the stack offset to recover RA (using the CFA) from is
633 fixed (like AMD64). In such cases, the stack offset to recover FP will
634 appear at the second index. */
635 fp_offset_idx = ((dhp->sfh_cfa_fixed_ra_offset != SFRAME_CFA_FIXED_RA_INVALID)
636 ? SFRAME_FRE_RA_OFFSET_IDX
637 : SFRAME_FRE_FP_OFFSET_IDX);
638 return sframe_get_fre_offset (fre, fp_offset_idx, errp);
639 }
640
641 /* Get the RA offset from the FRE. If the offset is invalid, sets errp. */
642
643 int32_t
644 sframe_fre_get_ra_offset (sframe_decoder_ctx *dctx,
645 sframe_frame_row_entry *fre, int *errp)
646 {
647 sframe_header *dhp = sframe_decoder_get_header (dctx);
648 /* If the RA offset was not being tracked, return an error code so the caller
649 can gather the fixed RA offset from the SFrame header. */
650 if (dhp->sfh_cfa_fixed_ra_offset != SFRAME_CFA_FIXED_RA_INVALID)
651 return sframe_set_errno (errp, SFRAME_ERR_FREOFFSET_NOPRESENT);
652
653 /* Otherwise, get the RA offset from the FRE. */
654 return sframe_get_fre_offset (fre, SFRAME_FRE_RA_OFFSET_IDX, errp);
655 }
656
657 /* Get whether the RA is mangled. */
658
659 bool
660 sframe_fre_get_ra_mangled_p (sframe_decoder_ctx *dctx ATTRIBUTE_UNUSED,
661 sframe_frame_row_entry *fre, int *errp)
662 {
663 if (fre == NULL || !sframe_fre_sanity_check_p (fre))
664 return sframe_set_errno (errp, SFRAME_ERR_FRE_INVAL);
665
666 return sframe_get_fre_ra_mangled_p (fre->fre_info);
667 }
668
669 static int
670 sframe_frame_row_entry_copy (sframe_frame_row_entry *dst, sframe_frame_row_entry *src)
671 {
672 int err = 0;
673
674 if (dst == NULL || src == NULL)
675 return sframe_set_errno (&err, SFRAME_ERR_INVAL);
676
677 memcpy (dst, src, sizeof (sframe_frame_row_entry));
678 return 0;
679 }
680
681 /* Decode the SFrame FRE start address offset value from FRE_BUF in on-disk
682 binary format, given the FRE_TYPE. Updates the FRE_START_ADDR.
683
684 Returns 0 on success, SFRAME_ERR otherwise. */
685
686 static int
687 sframe_decode_fre_start_address (const char *fre_buf,
688 uint32_t *fre_start_addr,
689 unsigned int fre_type)
690 {
691 uint32_t saddr = 0;
692 int err = 0;
693 size_t addr_size = 0;
694
695 addr_size = sframe_fre_start_addr_size (fre_type);
696
697 if (fre_type == SFRAME_FRE_TYPE_ADDR1)
698 {
699 uint8_t *uc = (uint8_t *)fre_buf;
700 saddr = (uint32_t)*uc;
701 }
702 else if (fre_type == SFRAME_FRE_TYPE_ADDR2)
703 {
704 uint16_t *ust = (uint16_t *)fre_buf;
705 /* SFrame is an unaligned on-disk format. Using memcpy helps avoid the
706 use of undesirable unaligned loads. See PR libsframe/29856. */
707 uint16_t tmp = 0;
708 memcpy (&tmp, ust, addr_size);
709 saddr = (uint32_t)tmp;
710 }
711 else if (fre_type == SFRAME_FRE_TYPE_ADDR4)
712 {
713 uint32_t *uit = (uint32_t *)fre_buf;
714 int32_t tmp = 0;
715 memcpy (&tmp, uit, addr_size);
716 saddr = (uint32_t)tmp;
717 }
718 else
719 return sframe_set_errno (&err, SFRAME_ERR_INVAL);
720
721 *fre_start_addr = saddr;
722 return 0;
723 }
724
725 /* Decode a frame row entry FRE which starts at location FRE_BUF. The function
726 updates ESZ to the size of the FRE as stored in the binary format.
727
728 This function works closely with the SFrame binary format.
729
730 Returns SFRAME_ERR if failure. */
731
732 static int
733 sframe_decode_fre (const char *fre_buf, sframe_frame_row_entry *fre,
734 unsigned int fre_type, size_t *esz)
735 {
736 int err = 0;
737 const char *stack_offsets = NULL;
738 size_t stack_offsets_sz;
739 size_t addr_size;
740 size_t fre_size;
741
742 if (fre_buf == NULL || fre == NULL || esz == NULL)
743 return sframe_set_errno (&err, SFRAME_ERR_INVAL);
744
745 /* Copy over the FRE start address. */
746 sframe_decode_fre_start_address (fre_buf, &fre->fre_start_addr, fre_type);
747
748 addr_size = sframe_fre_start_addr_size (fre_type);
749 fre->fre_info = *(uint8_t *)(fre_buf + addr_size);
750 /* Sanity check as the API works closely with the binary format. */
751 sframe_assert (sizeof (fre->fre_info) == sizeof (uint8_t));
752
753 /* Cleanup the space for fre_offsets first, then copy over the valid
754 bytes. */
755 memset (fre->fre_offsets, 0, MAX_OFFSET_BYTES);
756 /* Get offsets size. */
757 stack_offsets_sz = sframe_fre_offset_bytes_size (fre->fre_info);
758 stack_offsets = fre_buf + addr_size + sizeof (fre->fre_info);
759 memcpy (fre->fre_offsets, stack_offsets, stack_offsets_sz);
760
761 /* The FRE has been decoded. Use it to perform one last sanity check. */
762 fre_size = sframe_fre_entry_size (fre, fre_type);
763 sframe_assert (fre_size == (addr_size + sizeof (fre->fre_info)
764 + stack_offsets_sz));
765 *esz = fre_size;
766
767 return 0;
768 }
769
770 /* Decode the specified SFrame buffer CF_BUF of size CF_SIZE and return the
771 new SFrame decoder context.
772
773 Sets ERRP for the caller if any error. Frees up the allocated memory in
774 case of error. */
775
776 sframe_decoder_ctx *
777 sframe_decode (const char *sf_buf, size_t sf_size, int *errp)
778 {
779 const sframe_preamble *sfp;
780 size_t hdrsz;
781 sframe_header *sfheaderp;
782 sframe_decoder_ctx *dctx;
783 char *frame_buf;
784 char *tempbuf = NULL;
785
786 int fidx_size;
787 uint32_t fre_bytes;
788 int foreign_endian = 0;
789
790 sframe_init_debug ();
791
792 if ((sf_buf == NULL) || (!sf_size))
793 return sframe_ret_set_errno (errp, SFRAME_ERR_INVAL);
794 else if (sf_size < sizeof (sframe_header))
795 return sframe_ret_set_errno (errp, SFRAME_ERR_BUF_INVAL);
796
797 sfp = (const sframe_preamble *) sf_buf;
798
799 debug_printf ("sframe_decode: magic=0x%x version=%u flags=%u\n",
800 sfp->sfp_magic, sfp->sfp_version, sfp->sfp_flags);
801
802 /* Check for foreign endianness. */
803 if (sfp->sfp_magic != SFRAME_MAGIC)
804 {
805 if (sfp->sfp_magic == bswap_16 (SFRAME_MAGIC))
806 foreign_endian = 1;
807 else
808 return sframe_ret_set_errno (errp, SFRAME_ERR_BUF_INVAL);
809 }
810
811 /* Initialize a new decoder context. */
812 if ((dctx = malloc (sizeof (sframe_decoder_ctx))) == NULL)
813 return sframe_ret_set_errno (errp, SFRAME_ERR_NOMEM);
814 memset (dctx, 0, sizeof (sframe_decoder_ctx));
815
816 if (foreign_endian)
817 {
818 /* Allocate a new buffer and initialize it. */
819 tempbuf = (char *) malloc (sf_size * sizeof (char));
820 if (tempbuf == NULL)
821 return sframe_ret_set_errno (errp, SFRAME_ERR_NOMEM);
822 memcpy (tempbuf, sf_buf, sf_size);
823
824 /* Flip the header. */
825 sframe_header *ihp = (sframe_header *) tempbuf;
826 flip_header (ihp);
827 /* Flip the rest of the SFrame section data buffer. */
828 if (flip_sframe (tempbuf, sf_size, 0))
829 {
830 free (tempbuf);
831 return sframe_ret_set_errno (errp, SFRAME_ERR_BUF_INVAL);
832 }
833 frame_buf = tempbuf;
834 /* This buffer is malloc'd when endian flipping the contents of the input
835 buffer are needed. Keep a reference to it so it can be free'd up
836 later in sframe_decoder_free (). */
837 dctx->sfd_buf = tempbuf;
838 }
839 else
840 frame_buf = (char *)sf_buf;
841
842 /* Handle the SFrame header. */
843 dctx->sfd_header = *(sframe_header *) frame_buf;
844 /* Validate the contents of SFrame header. */
845 sfheaderp = &dctx->sfd_header;
846 if (!sframe_header_sanity_check_p (sfheaderp))
847 {
848 sframe_ret_set_errno (errp, SFRAME_ERR_NOMEM);
849 goto decode_fail_free;
850 }
851 hdrsz = sframe_get_hdr_size (sfheaderp);
852 frame_buf += hdrsz;
853
854 /* Handle the SFrame Function Descriptor Entry section. */
855 fidx_size
856 = sfheaderp->sfh_num_fdes * sizeof (sframe_func_desc_entry);
857 dctx->sfd_funcdesc = malloc (fidx_size);
858 if (dctx->sfd_funcdesc == NULL)
859 {
860 sframe_ret_set_errno (errp, SFRAME_ERR_NOMEM);
861 goto decode_fail_free;
862 }
863 memcpy (dctx->sfd_funcdesc, frame_buf, fidx_size);
864
865 debug_printf ("%u total fidx size\n", fidx_size);
866
867 frame_buf += (fidx_size);
868
869 /* Handle the SFrame Frame Row Entry section. */
870 dctx->sfd_fres = malloc (sfheaderp->sfh_fre_len);
871 if (dctx->sfd_fres == NULL)
872 {
873 sframe_ret_set_errno (errp, SFRAME_ERR_NOMEM);
874 goto decode_fail_free;
875 }
876 memcpy (dctx->sfd_fres, frame_buf, sfheaderp->sfh_fre_len);
877
878 fre_bytes = sfheaderp->sfh_fre_len;
879 dctx->sfd_fre_nbytes = fre_bytes;
880
881 debug_printf ("%u total fre bytes\n", fre_bytes);
882
883 return dctx;
884
885 decode_fail_free:
886 if (foreign_endian && tempbuf != NULL)
887 free (tempbuf);
888 sframe_decoder_free (&dctx);
889 dctx = NULL;
890 return dctx;
891 }
892
893 /* Get the size of the SFrame header from the decoder context CTX. */
894
895 unsigned int
896 sframe_decoder_get_hdr_size (sframe_decoder_ctx *ctx)
897 {
898 sframe_header *dhp;
899 dhp = sframe_decoder_get_header (ctx);
900 return sframe_get_hdr_size (dhp);
901 }
902
903 /* Get the SFrame's abi/arch info given the decoder context CTX. */
904
905 unsigned char
906 sframe_decoder_get_abi_arch (sframe_decoder_ctx *ctx)
907 {
908 sframe_header *sframe_header;
909 sframe_header = sframe_decoder_get_header (ctx);
910 return sframe_header->sfh_abi_arch;
911 }
912
913 /* Get the SFrame's fixed FP offset given the decoder context CTX. */
914 int8_t
915 sframe_decoder_get_fixed_fp_offset (sframe_decoder_ctx *ctx)
916 {
917 sframe_header *dhp;
918 dhp = sframe_decoder_get_header (ctx);
919 return dhp->sfh_cfa_fixed_fp_offset;
920 }
921
922 /* Get the SFrame's fixed RA offset given the decoder context CTX. */
923 int8_t
924 sframe_decoder_get_fixed_ra_offset (sframe_decoder_ctx *ctx)
925 {
926 sframe_header *dhp;
927 dhp = sframe_decoder_get_header (ctx);
928 return dhp->sfh_cfa_fixed_ra_offset;
929 }
930
931 /* Find the function descriptor entry starting which contains the specified
932 address ADDR. */
933
934 sframe_func_desc_entry *
935 sframe_get_funcdesc_with_addr (sframe_decoder_ctx *ctx,
936 int32_t addr, int *errp)
937 {
938 sframe_header *dhp;
939 sframe_func_desc_entry *fdp;
940 int low, high, cnt;
941
942 if (ctx == NULL)
943 return sframe_ret_set_errno (errp, SFRAME_ERR_INVAL);
944
945 dhp = sframe_decoder_get_header (ctx);
946
947 if (dhp == NULL || dhp->sfh_num_fdes == 0 || ctx->sfd_funcdesc == NULL)
948 return sframe_ret_set_errno (errp, SFRAME_ERR_DCTX_INVAL);
949 /* If the FDE sub-section is not sorted on PCs, skip the lookup because
950 binary search cannot be used. */
951 if ((dhp->sfh_preamble.sfp_flags & SFRAME_F_FDE_SORTED) == 0)
952 return sframe_ret_set_errno (errp, SFRAME_ERR_FDE_NOTSORTED);
953
954 /* Do the binary search. */
955 fdp = (sframe_func_desc_entry *) ctx->sfd_funcdesc;
956 low = 0;
957 high = dhp->sfh_num_fdes;
958 cnt = high;
959 while (low <= high)
960 {
961 int mid = low + (high - low) / 2;
962
963 if (fdp[mid].sfde_func_start_address == addr)
964 return fdp + mid;
965
966 if (fdp[mid].sfde_func_start_address < addr)
967 {
968 if (mid == (cnt - 1)) /* Check if it's the last one. */
969 return fdp + (cnt - 1);
970 else if (fdp[mid+1].sfde_func_start_address > addr)
971 return fdp + mid;
972 low = mid + 1;
973 }
974 else
975 high = mid - 1;
976 }
977
978 return sframe_ret_set_errno (errp, SFRAME_ERR_FDE_NOTFOUND);
979 }
980
981 /* Get the end IP offset for the FRE at index i in the FDEP. The buffer FRES
982 is the starting location for the FRE. */
983
984 static uint32_t
985 sframe_fre_get_end_ip_offset (sframe_func_desc_entry *fdep, unsigned int i,
986 const char *fres)
987 {
988 uint32_t end_ip_offset;
989 uint32_t fre_type;
990
991 fre_type = sframe_get_fre_type (fdep);
992
993 /* Get the start address of the next FRE in sequence. */
994 if (i < fdep->sfde_func_num_fres - 1)
995 {
996 sframe_decode_fre_start_address (fres, &end_ip_offset, fre_type);
997 end_ip_offset -= 1;
998 }
999 else
1000 /* The end IP offset for the FRE needs to be deduced from the function
1001 size. */
1002 end_ip_offset = fdep->sfde_func_size - 1;
1003
1004 return end_ip_offset;
1005 }
1006
1007 /* Find the SFrame Row Entry which contains the PC. Returns
1008 SFRAME_ERR if failure. */
1009
1010 int
1011 sframe_find_fre (sframe_decoder_ctx *ctx, int32_t pc,
1012 sframe_frame_row_entry *frep)
1013 {
1014 sframe_frame_row_entry cur_fre;
1015 sframe_func_desc_entry *fdep;
1016 unsigned int fre_type, fde_type;
1017 uint32_t end_ip_offset, i;
1018 int32_t start_ip, end_ip;
1019 int32_t func_start_addr;
1020 const char *fres;
1021 size_t size = 0;
1022 int err = 0;
1023 /* For regular FDEs (i.e. fde_type SFRAME_FDE_TYPE_PCINC),
1024 where the start address in the FRE is an offset from start pc,
1025 use a bitmask with all bits set so that none of the address bits are
1026 ignored. In this case, we need to return the FRE where
1027 (PC >= FRE_START_ADDR) */
1028 uint64_t bitmask = 0xffffffff;
1029
1030 if ((ctx == NULL) || (frep == NULL))
1031 return sframe_set_errno (&err, SFRAME_ERR_INVAL);
1032
1033 /* Find the FDE which contains the PC, then scan its fre entries. */
1034 fdep = sframe_get_funcdesc_with_addr (ctx, pc, &err);
1035 if (fdep == NULL || ctx->sfd_fres == NULL)
1036 return sframe_set_errno (&err, SFRAME_ERR_DCTX_INVAL);
1037
1038 fre_type = sframe_get_fre_type (fdep);
1039 fde_type = sframe_get_fde_type (fdep);
1040
1041 /* For FDEs for repetitive pattern of insns, we need to return the FRE
1042 such that (PC & FRE_START_ADDR_AS_MASK >= FRE_START_ADDR_AS_MASK).
1043 so, update the bitmask to the start address. */
1044 /* FIXME - the bitmask should be picked per ABI or encoded in the format
1045 somehow. For AMD64, the pltN entry stub is 16 bytes. */
1046 if (fde_type == SFRAME_FDE_TYPE_PCMASK)
1047 bitmask = 0xff;
1048
1049 fres = ctx->sfd_fres + fdep->sfde_func_start_fre_off;
1050 func_start_addr = fdep->sfde_func_start_address;
1051
1052 for (i = 0; i < fdep->sfde_func_num_fres; i++)
1053 {
1054 err = sframe_decode_fre (fres, &cur_fre, fre_type, &size);
1055 if (err)
1056 return sframe_set_errno (&err, SFRAME_ERR_FRE_INVAL);
1057
1058 start_ip = func_start_addr + cur_fre.fre_start_addr;
1059 end_ip_offset = sframe_fre_get_end_ip_offset (fdep, i, fres + size);
1060 end_ip = func_start_addr + end_ip_offset;
1061
1062 if ((start_ip & bitmask) > (pc & bitmask))
1063 return sframe_set_errno (&err, SFRAME_ERR_FRE_INVAL);
1064
1065 if (((start_ip & bitmask) <= (pc & bitmask))
1066 && (end_ip & bitmask) >= (pc & bitmask))
1067 {
1068 sframe_frame_row_entry_copy (frep, &cur_fre);
1069 return 0;
1070 }
1071 fres += size;
1072 }
1073 return sframe_set_errno (&err, SFRAME_ERR_FDE_INVAL);
1074 }
1075
1076 /* Return the number of function descriptor entries in the SFrame decoder
1077 DCTX. */
1078
1079 unsigned int
1080 sframe_decoder_get_num_fidx (sframe_decoder_ctx *ctx)
1081 {
1082 unsigned int num_fdes = 0;
1083 sframe_header *dhp = NULL;
1084 dhp = sframe_decoder_get_header (ctx);
1085 if (dhp)
1086 num_fdes = dhp->sfh_num_fdes;
1087 return num_fdes;
1088 }
1089
1090 /* Get the data (NUM_FRES, FUNC_START_ADDRESS) from the function
1091 descriptor entry at index I'th in the decoder CTX. If failed,
1092 return error code. */
1093 /* FIXME - consolidate the args and return a
1094 sframe_func_desc_index_elem rather? */
1095
1096 int
1097 sframe_decoder_get_funcdesc (sframe_decoder_ctx *ctx,
1098 unsigned int i,
1099 uint32_t *num_fres,
1100 uint32_t *func_size,
1101 int32_t *func_start_address,
1102 unsigned char *func_info)
1103 {
1104 sframe_func_desc_entry *fdp;
1105 unsigned int num_fdes;
1106 int err = 0;
1107
1108 if (ctx == NULL || func_start_address == NULL || num_fres == NULL
1109 || func_size == NULL)
1110 return sframe_set_errno (&err, SFRAME_ERR_INVAL);
1111
1112 num_fdes = sframe_decoder_get_num_fidx (ctx);
1113 if (num_fdes == 0
1114 || i >= num_fdes
1115 || ctx->sfd_funcdesc == NULL)
1116 return sframe_set_errno (&err, SFRAME_ERR_DCTX_INVAL);
1117
1118 fdp = (sframe_func_desc_entry *) ctx->sfd_funcdesc + i;
1119 *num_fres = fdp->sfde_func_num_fres;
1120 *func_start_address = fdp->sfde_func_start_address;
1121 *func_size = fdp->sfde_func_size;
1122 *func_info = fdp->sfde_func_info;
1123
1124 return 0;
1125 }
1126
1127 /* Get the function descriptor entry at index FUNC_IDX in the decoder
1128 context CTX. */
1129
1130 static sframe_func_desc_entry *
1131 sframe_decoder_get_funcdesc_at_index (sframe_decoder_ctx *ctx,
1132 uint32_t func_idx)
1133 {
1134 /* Invalid argument. No FDE will be found. */
1135 if (func_idx >= sframe_decoder_get_num_fidx (ctx))
1136 return NULL;
1137
1138 sframe_func_desc_entry *fdep;
1139 fdep = (sframe_func_desc_entry *) ctx->sfd_funcdesc;
1140 return fdep + func_idx;
1141 }
1142
1143 /* Get the FRE_IDX'th FRE of the function at FUNC_IDX'th function
1144 descriptor entry in the SFrame decoder CTX. Returns error code as
1145 applicable. */
1146
1147 int
1148 sframe_decoder_get_fre (sframe_decoder_ctx *ctx,
1149 unsigned int func_idx,
1150 unsigned int fre_idx,
1151 sframe_frame_row_entry *fre)
1152 {
1153 sframe_func_desc_entry *fdep;
1154 sframe_frame_row_entry ifre;
1155 const char *fres;
1156 uint32_t i;
1157 unsigned int fre_type;
1158 size_t esz = 0;
1159 int err = 0;
1160
1161 if (ctx == NULL || fre == NULL)
1162 return sframe_set_errno (&err, SFRAME_ERR_INVAL);
1163
1164 /* Get function descriptor entry at index func_idx. */
1165 fdep = sframe_decoder_get_funcdesc_at_index (ctx, func_idx);
1166
1167 if (fdep == NULL)
1168 return sframe_set_errno (&err, SFRAME_ERR_FDE_NOTFOUND);
1169
1170 fre_type = sframe_get_fre_type (fdep);
1171 /* Now scan the FRE entries. */
1172 fres = ctx->sfd_fres + fdep->sfde_func_start_fre_off;
1173 for (i = 0; i < fdep->sfde_func_num_fres; i++)
1174 {
1175 /* Decode the FRE at the current position. Return it if valid. */
1176 err = sframe_decode_fre (fres, &ifre, fre_type, &esz);
1177 if (i == fre_idx)
1178 {
1179 if (!sframe_fre_sanity_check_p (&ifre))
1180 return sframe_set_errno (&err, SFRAME_ERR_FRE_INVAL);
1181
1182 sframe_frame_row_entry_copy (fre, &ifre);
1183
1184 if (fdep->sfde_func_size)
1185 sframe_assert (fre->fre_start_addr < fdep->sfde_func_size);
1186 else
1187 /* A SFrame FDE with func size equal to zero is possible. */
1188 sframe_assert (fre->fre_start_addr == fdep->sfde_func_size);
1189
1190 return 0;
1191 }
1192 /* Next FRE. */
1193 fres += esz;
1194 }
1195
1196 return sframe_set_errno (&err, SFRAME_ERR_FDE_NOTFOUND);
1197 }
1198
1199
1200 /* SFrame Encoder. */
1201
1202 /* Get a reference to the ENCODER's SFrame header. */
1203
1204 static sframe_header *
1205 sframe_encoder_get_header (sframe_encoder_ctx *encoder)
1206 {
1207 sframe_header *hp = NULL;
1208 if (encoder)
1209 hp = &encoder->sfe_header;
1210 return hp;
1211 }
1212
1213 static sframe_func_desc_entry *
1214 sframe_encoder_get_funcdesc_at_index (sframe_encoder_ctx *encoder,
1215 uint32_t func_idx)
1216 {
1217 sframe_func_desc_entry *fde = NULL;
1218 if (func_idx < sframe_encoder_get_num_fidx (encoder))
1219 {
1220 sf_funidx_tbl *func_tbl = (sf_funidx_tbl *) encoder->sfe_funcdesc;
1221 fde = func_tbl->entry + func_idx;
1222 }
1223 return fde;
1224 }
1225
1226 /* Create an encoder context with the given SFrame format version VER, FLAGS
1227 and ABI information. Sets errp if failure. */
1228
1229 sframe_encoder_ctx *
1230 sframe_encode (unsigned char ver, unsigned char flags, int abi_arch,
1231 int8_t fixed_fp_offset, int8_t fixed_ra_offset, int *errp)
1232 {
1233 sframe_header *hp;
1234 sframe_encoder_ctx *encoder;
1235
1236 if (ver != SFRAME_VERSION)
1237 return sframe_ret_set_errno (errp, SFRAME_ERR_VERSION_INVAL);
1238
1239 if ((encoder = malloc (sizeof (sframe_encoder_ctx))) == NULL)
1240 return sframe_ret_set_errno (errp, SFRAME_ERR_NOMEM);
1241
1242 memset (encoder, 0, sizeof (sframe_encoder_ctx));
1243
1244 /* Get the SFrame header and update it. */
1245 hp = sframe_encoder_get_header (encoder);
1246 hp->sfh_preamble.sfp_version = ver;
1247 hp->sfh_preamble.sfp_magic = SFRAME_MAGIC;
1248 hp->sfh_preamble.sfp_flags = flags;
1249
1250 hp->sfh_abi_arch = abi_arch;
1251 hp->sfh_cfa_fixed_fp_offset = fixed_fp_offset;
1252 hp->sfh_cfa_fixed_ra_offset = fixed_ra_offset;
1253
1254 return encoder;
1255 }
1256
1257 /* Free the encoder context. */
1258
1259 void
1260 sframe_encoder_free (sframe_encoder_ctx **encoder)
1261 {
1262 if (encoder != NULL)
1263 {
1264 sframe_encoder_ctx *ectx = *encoder;
1265 if (ectx == NULL)
1266 return;
1267
1268 if (ectx->sfe_funcdesc != NULL)
1269 {
1270 free (ectx->sfe_funcdesc);
1271 ectx->sfe_funcdesc = NULL;
1272 }
1273 if (ectx->sfe_fres != NULL)
1274 {
1275 free (ectx->sfe_fres);
1276 ectx->sfe_fres = NULL;
1277 }
1278 if (ectx->sfe_data != NULL)
1279 {
1280 free (ectx->sfe_data);
1281 ectx->sfe_data = NULL;
1282 }
1283
1284 free (*encoder);
1285 *encoder = NULL;
1286 }
1287 }
1288
1289 /* Get the size of the SFrame header from the encoder ctx ENCODER. */
1290
1291 unsigned int
1292 sframe_encoder_get_hdr_size (sframe_encoder_ctx *encoder)
1293 {
1294 sframe_header *ehp;
1295 ehp = sframe_encoder_get_header (encoder);
1296 return sframe_get_hdr_size (ehp);
1297 }
1298
1299 /* Get the abi/arch info from the SFrame encoder context ENCODER. */
1300
1301 unsigned char
1302 sframe_encoder_get_abi_arch (sframe_encoder_ctx *encoder)
1303 {
1304 unsigned char abi_arch = 0;
1305 sframe_header *ehp;
1306 ehp = sframe_encoder_get_header (encoder);
1307 if (ehp)
1308 abi_arch = ehp->sfh_abi_arch;
1309 return abi_arch;
1310 }
1311
1312 /* Return the number of function descriptor entries in the SFrame encoder
1313 ENCODER. */
1314
1315 unsigned int
1316 sframe_encoder_get_num_fidx (sframe_encoder_ctx *encoder)
1317 {
1318 unsigned int num_fdes = 0;
1319 sframe_header *ehp = NULL;
1320 ehp = sframe_encoder_get_header (encoder);
1321 if (ehp)
1322 num_fdes = ehp->sfh_num_fdes;
1323 return num_fdes;
1324 }
1325
1326 /* Add an FRE to function at FUNC_IDX'th function descriptor entry in
1327 the encoder context. */
1328
1329 int
1330 sframe_encoder_add_fre (sframe_encoder_ctx *encoder,
1331 unsigned int func_idx,
1332 sframe_frame_row_entry *frep)
1333 {
1334 sframe_header *ehp;
1335 sframe_func_desc_entry *fdep;
1336 sframe_frame_row_entry *ectx_frep;
1337 size_t offsets_sz, esz;
1338 unsigned int fre_type;
1339 size_t fre_tbl_sz;
1340 int err = 0;
1341
1342 if (encoder == NULL || frep == NULL)
1343 return sframe_set_errno (&err, SFRAME_ERR_INVAL);
1344 if (!sframe_fre_sanity_check_p (frep))
1345 return sframe_set_errno (&err, SFRAME_ERR_FRE_INVAL);
1346
1347 /* Use func_idx to gather the function descriptor entry. */
1348 fdep = sframe_encoder_get_funcdesc_at_index (encoder, func_idx);
1349
1350 if (fdep == NULL)
1351 return sframe_set_errno (&err, SFRAME_ERR_FDE_NOTFOUND);
1352
1353 fre_type = sframe_get_fre_type (fdep);
1354 sf_fre_tbl *fre_tbl = (sf_fre_tbl *) encoder->sfe_fres;
1355
1356 if (fre_tbl == NULL)
1357 {
1358 fre_tbl_sz = (sizeof (sf_fre_tbl)
1359 + (number_of_entries * sizeof (sframe_frame_row_entry)));
1360 fre_tbl = malloc (fre_tbl_sz);
1361
1362 if (fre_tbl == NULL)
1363 {
1364 sframe_set_errno (&err, SFRAME_ERR_NOMEM);
1365 goto bad; /* OOM. */
1366 }
1367 memset (fre_tbl, 0, fre_tbl_sz);
1368 fre_tbl->alloced = number_of_entries;
1369 }
1370 else if (fre_tbl->count == fre_tbl->alloced)
1371 {
1372 fre_tbl_sz = (sizeof (sf_fre_tbl)
1373 + ((fre_tbl->alloced + number_of_entries)
1374 * sizeof (sframe_frame_row_entry)));
1375 fre_tbl = realloc (fre_tbl, fre_tbl_sz);
1376 if (fre_tbl == NULL)
1377 {
1378 sframe_set_errno (&err, SFRAME_ERR_NOMEM);
1379 goto bad; /* OOM. */
1380 }
1381
1382 memset (&fre_tbl->entry[fre_tbl->alloced], 0,
1383 number_of_entries * sizeof (sframe_frame_row_entry));
1384 fre_tbl->alloced += number_of_entries;
1385 }
1386
1387 ectx_frep = &fre_tbl->entry[fre_tbl->count];
1388 ectx_frep->fre_start_addr
1389 = frep->fre_start_addr;
1390 ectx_frep->fre_info = frep->fre_info;
1391
1392 if (fdep->sfde_func_size)
1393 sframe_assert (frep->fre_start_addr < fdep->sfde_func_size);
1394 else
1395 /* A SFrame FDE with func size equal to zero is possible. */
1396 sframe_assert (frep->fre_start_addr == fdep->sfde_func_size);
1397
1398 /* frep has already been sanity check'd. Get offsets size. */
1399 offsets_sz = sframe_fre_offset_bytes_size (frep->fre_info);
1400 memcpy (&ectx_frep->fre_offsets, &frep->fre_offsets, offsets_sz);
1401
1402 esz = sframe_fre_entry_size (frep, fre_type);
1403 fre_tbl->count++;
1404
1405 encoder->sfe_fres = (void *) fre_tbl;
1406 encoder->sfe_fre_nbytes += esz;
1407
1408 ehp = sframe_encoder_get_header (encoder);
1409 ehp->sfh_num_fres = fre_tbl->count;
1410
1411 /* Update the value of the number of FREs for the function. */
1412 fdep->sfde_func_num_fres++;
1413
1414 return 0;
1415
1416 bad:
1417 if (fre_tbl != NULL)
1418 free (fre_tbl);
1419 encoder->sfe_fres = NULL;
1420 encoder->sfe_fre_nbytes = 0;
1421 return -1;
1422 }
1423
1424 /* Add a new function descriptor entry with START_ADDR, FUNC_SIZE and NUM_FRES
1425 to the encoder. */
1426
1427 int
1428 sframe_encoder_add_funcdesc (sframe_encoder_ctx *encoder,
1429 int32_t start_addr,
1430 uint32_t func_size,
1431 unsigned char func_info,
1432 uint32_t num_fres __attribute__ ((unused)))
1433 {
1434 sframe_header *ehp;
1435 sf_funidx_tbl *fd_info;
1436 size_t fd_tbl_sz;
1437 int err = 0;
1438
1439 /* FIXME book-keep num_fres for error checking. */
1440 if (encoder == NULL)
1441 return sframe_set_errno (&err, SFRAME_ERR_INVAL);
1442
1443 fd_info = (sf_funidx_tbl *) encoder->sfe_funcdesc;
1444 ehp = sframe_encoder_get_header (encoder);
1445
1446 if (fd_info == NULL)
1447 {
1448 fd_tbl_sz = (sizeof (sf_funidx_tbl)
1449 + (number_of_entries * sizeof (sframe_func_desc_entry)));
1450 fd_info = malloc (fd_tbl_sz);
1451 if (fd_info == NULL)
1452 {
1453 sframe_set_errno (&err, SFRAME_ERR_NOMEM);
1454 goto bad; /* OOM. */
1455 }
1456 memset (fd_info, 0, fd_tbl_sz);
1457 fd_info->alloced = number_of_entries;
1458 }
1459 else if (fd_info->count == fd_info->alloced)
1460 {
1461 fd_tbl_sz = (sizeof (sf_funidx_tbl)
1462 + ((fd_info->alloced + number_of_entries)
1463 * sizeof (sframe_func_desc_entry)));
1464 fd_info = realloc (fd_info, fd_tbl_sz);
1465 if (fd_info == NULL)
1466 {
1467 sframe_set_errno (&err, SFRAME_ERR_NOMEM);
1468 goto bad; /* OOM. */
1469 }
1470
1471 memset (&fd_info->entry[fd_info->alloced], 0,
1472 number_of_entries * sizeof (sframe_func_desc_entry));
1473 fd_info->alloced += number_of_entries;
1474 }
1475
1476 fd_info->entry[fd_info->count].sfde_func_start_address = start_addr;
1477 /* Num FREs is updated as FREs are added for the function later via
1478 sframe_encoder_add_fre. */
1479 fd_info->entry[fd_info->count].sfde_func_size = func_size;
1480 fd_info->entry[fd_info->count].sfde_func_start_fre_off
1481 = encoder->sfe_fre_nbytes;
1482 #if 0
1483 // Linker optimization test code cleanup later ibhagat TODO FIXME
1484 unsigned int fre_type = sframe_calc_fre_type (func_size);
1485
1486 fd_info->entry[fd_info->count].sfde_func_info
1487 = sframe_fde_func_info (fre_type);
1488 #endif
1489 fd_info->entry[fd_info->count].sfde_func_info = func_info;
1490 fd_info->count++;
1491 encoder->sfe_funcdesc = (void *) fd_info;
1492 ehp->sfh_num_fdes++;
1493 return 0;
1494
1495 bad:
1496 if (fd_info != NULL)
1497 free (fd_info);
1498 encoder->sfe_funcdesc = NULL;
1499 ehp->sfh_num_fdes = 0;
1500 return -1;
1501 }
1502
1503 static int
1504 sframe_sort_funcdesc (sframe_encoder_ctx *encoder)
1505 {
1506 sframe_header *ehp;
1507
1508 ehp = sframe_encoder_get_header (encoder);
1509 /* Sort and write out the FDE table. */
1510 sf_funidx_tbl *fd_info = (sf_funidx_tbl *) encoder->sfe_funcdesc;
1511 if (fd_info)
1512 {
1513 qsort (fd_info->entry, fd_info->count,
1514 sizeof (sframe_func_desc_entry), fde_func);
1515 /* Update preamble's flags. */
1516 ehp->sfh_preamble.sfp_flags |= SFRAME_F_FDE_SORTED;
1517 }
1518 return 0;
1519 }
1520
1521 /* Write the SFrame FRE start address from the in-memory FRE_START_ADDR
1522 to the buffer CONTENTS (on-disk format), given the FRE_TYPE and
1523 FRE_START_ADDR_SZ. */
1524
1525 static int
1526 sframe_encoder_write_fre_start_addr (char *contents,
1527 uint32_t fre_start_addr,
1528 unsigned int fre_type,
1529 size_t fre_start_addr_sz)
1530 {
1531 int err = 0;
1532
1533 if (fre_type == SFRAME_FRE_TYPE_ADDR1)
1534 {
1535 uint8_t uc = fre_start_addr;
1536 memcpy (contents, &uc, fre_start_addr_sz);
1537 }
1538 else if (fre_type == SFRAME_FRE_TYPE_ADDR2)
1539 {
1540 uint16_t ust = fre_start_addr;
1541 memcpy (contents, &ust, fre_start_addr_sz);
1542 }
1543 else if (fre_type == SFRAME_FRE_TYPE_ADDR4)
1544 {
1545 uint32_t uit = fre_start_addr;
1546 memcpy (contents, &uit, fre_start_addr_sz);
1547 }
1548 else
1549 return sframe_set_errno (&err, SFRAME_ERR_INVAL);
1550
1551 return 0;
1552 }
1553
1554 /* Write a frame row entry pointed to by FREP into the buffer CONTENTS. The
1555 size in bytes written out are updated in ESZ.
1556
1557 This function works closely with the SFrame binary format.
1558
1559 Returns SFRAME_ERR if failure. */
1560
1561 static int
1562 sframe_encoder_write_fre (char *contents, sframe_frame_row_entry *frep,
1563 unsigned int fre_type, size_t *esz)
1564 {
1565 size_t fre_sz;
1566 size_t fre_start_addr_sz;
1567 size_t fre_stack_offsets_sz;
1568 int err = 0;
1569
1570 if (!sframe_fre_sanity_check_p (frep))
1571 return sframe_set_errno (&err, SFRAME_ERR_FRE_INVAL);
1572
1573 fre_start_addr_sz = sframe_fre_start_addr_size (fre_type);
1574 fre_stack_offsets_sz = sframe_fre_offset_bytes_size (frep->fre_info);
1575
1576 /* The FRE start address must be encodable in the available number of
1577 bytes. */
1578 uint64_t bitmask = SFRAME_BITMASK_OF_SIZE (fre_start_addr_sz);
1579 sframe_assert ((uint64_t)frep->fre_start_addr <= bitmask);
1580
1581 sframe_encoder_write_fre_start_addr (contents, frep->fre_start_addr,
1582 fre_type, fre_start_addr_sz);
1583 contents += fre_start_addr_sz;
1584
1585 memcpy (contents, &frep->fre_info, sizeof (frep->fre_info));
1586 contents += sizeof (frep->fre_info);
1587
1588 memcpy (contents, frep->fre_offsets, fre_stack_offsets_sz);
1589 contents+= fre_stack_offsets_sz;
1590
1591 fre_sz = sframe_fre_entry_size (frep, fre_type);
1592 /* Sanity checking. */
1593 sframe_assert ((fre_start_addr_sz
1594 + sizeof (frep->fre_info)
1595 + fre_stack_offsets_sz) == fre_sz);
1596
1597 *esz = fre_sz;
1598
1599 return 0;
1600 }
1601
1602 /* Serialize the core contents of the SFrame section and write out to the
1603 output buffer held in the ENCODER. Return SFRAME_ERR if failure. */
1604
1605 static int
1606 sframe_encoder_write_sframe (sframe_encoder_ctx *encoder)
1607 {
1608 char *contents;
1609 size_t buf_size;
1610 size_t hdr_size;
1611 size_t all_fdes_size;
1612 size_t fre_size;
1613 size_t esz = 0;
1614 sframe_header *ehp;
1615 unsigned char flags;
1616 sf_funidx_tbl *fd_info;
1617 sf_fre_tbl *fr_info;
1618 uint32_t i, num_fdes;
1619 uint32_t j, num_fres;
1620 sframe_func_desc_entry *fdep;
1621 sframe_frame_row_entry *frep;
1622
1623 unsigned int fre_type;
1624 int err = 0;
1625
1626 contents = encoder->sfe_data;
1627 buf_size = encoder->sfe_data_size;
1628 num_fdes = sframe_encoder_get_num_fidx (encoder);
1629 all_fdes_size = num_fdes * sizeof (sframe_func_desc_entry);
1630 ehp = sframe_encoder_get_header (encoder);
1631 hdr_size = sframe_get_hdr_size (ehp);
1632
1633 fd_info = (sf_funidx_tbl *) encoder->sfe_funcdesc;
1634 fr_info = (sf_fre_tbl *) encoder->sfe_fres;
1635
1636 /* Sanity checks:
1637 - buffers must be malloc'd by the caller. */
1638 if ((contents == NULL) || (buf_size < hdr_size))
1639 return sframe_set_errno (&err, SFRAME_ERR_BUF_INVAL);
1640 if (fr_info == NULL)
1641 return sframe_set_errno (&err, SFRAME_ERR_FRE_INVAL);
1642
1643 /* Write out the FRE table first.
1644
1645 Recall that read/write of FREs needs information from the corresponding
1646 FDE; the latter stores the information about the FRE type record used for
1647 the function. Also note that sorting of FDEs does NOT impact the order
1648 in which FREs are stored in the SFrame's FRE sub-section. This means
1649 that writing out FREs after sorting of FDEs will need some additional
1650 book-keeping. At this time, we can afford to avoid it by writing out
1651 the FREs first to the output buffer. */
1652 fre_size = 0;
1653 uint32_t global = 0;
1654 uint32_t fre_index = 0;
1655
1656 contents += hdr_size + all_fdes_size;
1657 for (i = 0; i < num_fdes; i++)
1658 {
1659 fdep = &fd_info->entry[i];
1660 fre_type = sframe_get_fre_type (fdep);
1661 num_fres = fdep->sfde_func_num_fres;
1662
1663 for (j = 0; j < num_fres; j++)
1664 {
1665 fre_index = global + j;
1666 frep = &fr_info->entry[fre_index];
1667
1668 sframe_encoder_write_fre (contents, frep, fre_type, &esz);
1669 contents += esz;
1670 fre_size += esz; /* For debugging only. */
1671 }
1672 global += j;
1673 }
1674
1675 sframe_assert (fre_size == ehp->sfh_fre_len);
1676 sframe_assert (global == ehp->sfh_num_fres);
1677 sframe_assert ((size_t)(contents - encoder->sfe_data) == buf_size);
1678
1679 /* Sort the FDE table */
1680 sframe_sort_funcdesc (encoder);
1681
1682 /* Sanity checks:
1683 - the FDE section must have been sorted by now on the start address
1684 of each function. */
1685 flags = ehp->sfh_preamble.sfp_flags;
1686 if (!(flags & SFRAME_F_FDE_SORTED)
1687 || (fd_info == NULL))
1688 return sframe_set_errno (&err, SFRAME_ERR_FDE_INVAL);
1689
1690 contents = encoder->sfe_data;
1691 /* Write out the SFrame header. The SFrame header in the encoder
1692 object has already been updated with correct offsets by the caller. */
1693 memcpy (contents, ehp, hdr_size);
1694 contents += hdr_size;
1695
1696 /* Write out the FDE table sorted on funtion start address. */
1697 memcpy (contents, fd_info->entry, all_fdes_size);
1698 contents += all_fdes_size;
1699
1700 return 0;
1701 }
1702
1703 /* Serialize the contents of the encoder and return the buffer. ENCODED_SIZE
1704 is updated to the size of the buffer. */
1705
1706 char *
1707 sframe_encoder_write (sframe_encoder_ctx *encoder,
1708 size_t *encoded_size, int *errp)
1709 {
1710 sframe_header *ehp;
1711 size_t hdrsize, fsz, fresz, bufsize;
1712 int foreign_endian;
1713
1714 /* Initialize the encoded_size to zero. This makes it simpler to just
1715 return from the function in case of failure. Free'ing up of
1716 encoder->sfe_data is the responsibility of the caller. */
1717 *encoded_size = 0;
1718
1719 if (encoder == NULL || encoded_size == NULL || errp == NULL)
1720 return sframe_ret_set_errno (errp, SFRAME_ERR_INVAL);
1721
1722 ehp = sframe_encoder_get_header (encoder);
1723 hdrsize = sframe_get_hdr_size (ehp);
1724 fsz = sframe_encoder_get_num_fidx (encoder)
1725 * sizeof (sframe_func_desc_entry);
1726 fresz = encoder->sfe_fre_nbytes;
1727
1728 /* The total size of buffer is the sum of header, SFrame Function Descriptor
1729 Entries section and the FRE section. */
1730 bufsize = hdrsize + fsz + fresz;
1731 encoder->sfe_data = (char *) malloc (bufsize);
1732 if (encoder->sfe_data == NULL)
1733 return sframe_ret_set_errno (errp, SFRAME_ERR_NOMEM);
1734 encoder->sfe_data_size = bufsize;
1735
1736 /* Update the information in the SFrame header. */
1737 /* SFrame FDE section follows immediately after the header. */
1738 ehp->sfh_fdeoff = 0;
1739 /* SFrame FRE section follows immediately after the SFrame FDE section. */
1740 ehp->sfh_freoff = fsz;
1741 ehp->sfh_fre_len = fresz;
1742
1743 foreign_endian = need_swapping (ehp->sfh_abi_arch);
1744
1745 /* Write out the FDE Index and the FRE table in the sfe_data. */
1746 if (sframe_encoder_write_sframe (encoder))
1747 return sframe_ret_set_errno (errp, SFRAME_ERR_BUF_INVAL);
1748
1749 /* Endian flip the contents if necessary. */
1750 if (foreign_endian)
1751 {
1752 if (flip_sframe (encoder->sfe_data, bufsize, 1))
1753 return sframe_ret_set_errno (errp, SFRAME_ERR_BUF_INVAL);
1754 flip_header ((sframe_header*)encoder->sfe_data);
1755 }
1756
1757 *encoded_size = bufsize;
1758 return encoder->sfe_data;
1759 }