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