]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blob - libsframe/sframe.c
libsframe: use uint8_t data type for FRE info related stubs
[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,
737 size_t *esz)
738 {
739 int err = 0;
740 void *stack_offsets = NULL;
741 size_t stack_offsets_sz;
742 size_t addr_size;
743 size_t fre_size;
744
745 if (fre_buf == NULL || fre == NULL || esz == NULL)
746 return sframe_set_errno (&err, SFRAME_ERR_INVAL);
747
748 /* Copy over the FRE start address. */
749 sframe_decode_fre_start_address (fre_buf, &fre->fre_start_addr, fre_type);
750
751 addr_size = sframe_fre_start_addr_size (fre_type);
752 fre->fre_info = *(uint8_t *)(fre_buf + addr_size);
753 /* Sanity check as the API works closely with the binary format. */
754 sframe_assert (sizeof (fre->fre_info) == sizeof (uint8_t));
755
756 /* Cleanup the space for fre_offsets first, then copy over the valid
757 bytes. */
758 memset (fre->fre_offsets, 0, MAX_OFFSET_BYTES);
759 /* Get offsets size. */
760 stack_offsets_sz = sframe_fre_offset_bytes_size (fre->fre_info);
761 stack_offsets = (unsigned char *)fre_buf + addr_size + sizeof (fre->fre_info);
762 memcpy (fre->fre_offsets, stack_offsets, stack_offsets_sz);
763
764 /* The FRE has been decoded. Use it to perform one last sanity check. */
765 fre_size = sframe_fre_entry_size (fre, fre_type);
766 sframe_assert (fre_size == (addr_size + sizeof (fre->fre_info)
767 + stack_offsets_sz));
768 *esz = fre_size;
769
770 return 0;
771 }
772
773 /* Decode the specified SFrame buffer CF_BUF of size CF_SIZE and return the
774 new SFrame decoder context.
775
776 Sets ERRP for the caller if any error. Frees up the allocated memory in
777 case of error. */
778
779 sframe_decoder_ctx *
780 sframe_decode (const char *sf_buf, size_t sf_size, int *errp)
781 {
782 const sframe_preamble *sfp;
783 size_t hdrsz;
784 sframe_header *sfheaderp;
785 sframe_decoder_ctx *dctx;
786 char *frame_buf;
787 char *tempbuf = NULL;
788
789 int fidx_size;
790 uint32_t fre_bytes;
791 int foreign_endian = 0;
792
793 sframe_init_debug ();
794
795 if ((sf_buf == NULL) || (!sf_size))
796 return sframe_ret_set_errno (errp, SFRAME_ERR_INVAL);
797 else if (sf_size < sizeof (sframe_header))
798 return sframe_ret_set_errno (errp, SFRAME_ERR_BUF_INVAL);
799
800 sfp = (const sframe_preamble *) sf_buf;
801
802 debug_printf ("sframe_decode: magic=0x%x version=%u flags=%u\n",
803 sfp->sfp_magic, sfp->sfp_version, sfp->sfp_flags);
804
805 /* Check for foreign endianness. */
806 if (sfp->sfp_magic != SFRAME_MAGIC)
807 {
808 if (sfp->sfp_magic == bswap_16 (SFRAME_MAGIC))
809 foreign_endian = 1;
810 else
811 return sframe_ret_set_errno (errp, SFRAME_ERR_BUF_INVAL);
812 }
813
814 /* Initialize a new decoder context. */
815 if ((dctx = malloc (sizeof (sframe_decoder_ctx))) == NULL)
816 return sframe_ret_set_errno (errp, SFRAME_ERR_NOMEM);
817 memset (dctx, 0, sizeof (sframe_decoder_ctx));
818
819 if (foreign_endian)
820 {
821 /* Allocate a new buffer and initialize it. */
822 tempbuf = (char *) malloc (sf_size * sizeof (char));
823 if (tempbuf == NULL)
824 return sframe_ret_set_errno (errp, SFRAME_ERR_NOMEM);
825 memcpy (tempbuf, sf_buf, sf_size);
826
827 /* Flip the header. */
828 sframe_header *ihp = (sframe_header *) tempbuf;
829 flip_header (ihp);
830 /* Flip the rest of the SFrame section data buffer. */
831 if (flip_sframe (tempbuf, sf_size, 0))
832 {
833 free (tempbuf);
834 return sframe_ret_set_errno (errp, SFRAME_ERR_BUF_INVAL);
835 }
836 frame_buf = tempbuf;
837 /* This buffer is malloc'd when endian flipping the contents of the input
838 buffer are needed. Keep a reference to it so it can be free'd up
839 later in sframe_decoder_free (). */
840 dctx->sfd_buf = tempbuf;
841 }
842 else
843 frame_buf = (char *)sf_buf;
844
845 /* Handle the SFrame header. */
846 dctx->sfd_header = *(sframe_header *) frame_buf;
847 /* Validate the contents of SFrame header. */
848 sfheaderp = &dctx->sfd_header;
849 if (!sframe_header_sanity_check_p (sfheaderp))
850 {
851 sframe_ret_set_errno (errp, SFRAME_ERR_NOMEM);
852 goto decode_fail_free;
853 }
854 hdrsz = sframe_get_hdr_size (sfheaderp);
855 frame_buf += hdrsz;
856
857 /* Handle the SFrame Function Descriptor Entry section. */
858 fidx_size
859 = sfheaderp->sfh_num_fdes * sizeof (sframe_func_desc_entry);
860 dctx->sfd_funcdesc = malloc (fidx_size);
861 if (dctx->sfd_funcdesc == NULL)
862 {
863 sframe_ret_set_errno (errp, SFRAME_ERR_NOMEM);
864 goto decode_fail_free;
865 }
866 memcpy (dctx->sfd_funcdesc, frame_buf, fidx_size);
867
868 debug_printf ("%u total fidx size\n", fidx_size);
869
870 frame_buf += (fidx_size);
871
872 /* Handle the SFrame Frame Row Entry section. */
873 dctx->sfd_fres = malloc (sfheaderp->sfh_fre_len);
874 if (dctx->sfd_fres == NULL)
875 {
876 sframe_ret_set_errno (errp, SFRAME_ERR_NOMEM);
877 goto decode_fail_free;
878 }
879 memcpy (dctx->sfd_fres, frame_buf, sfheaderp->sfh_fre_len);
880
881 fre_bytes = sfheaderp->sfh_fre_len;
882 dctx->sfd_fre_nbytes = fre_bytes;
883
884 debug_printf ("%u total fre bytes\n", fre_bytes);
885
886 return dctx;
887
888 decode_fail_free:
889 if (foreign_endian && tempbuf != NULL)
890 free (tempbuf);
891 sframe_decoder_free (&dctx);
892 dctx = NULL;
893 return dctx;
894 }
895
896 /* Get the size of the SFrame header from the decoder context CTX. */
897
898 unsigned int
899 sframe_decoder_get_hdr_size (sframe_decoder_ctx *ctx)
900 {
901 sframe_header *dhp;
902 dhp = sframe_decoder_get_header (ctx);
903 return sframe_get_hdr_size (dhp);
904 }
905
906 /* Get the SFrame's abi/arch info given the decoder context CTX. */
907
908 unsigned char
909 sframe_decoder_get_abi_arch (sframe_decoder_ctx *ctx)
910 {
911 sframe_header *sframe_header;
912 sframe_header = sframe_decoder_get_header (ctx);
913 return sframe_header->sfh_abi_arch;
914 }
915
916 /* Get the SFrame's fixed FP offset given the decoder context CTX. */
917 int8_t
918 sframe_decoder_get_fixed_fp_offset (sframe_decoder_ctx *ctx)
919 {
920 sframe_header *dhp;
921 dhp = sframe_decoder_get_header (ctx);
922 return dhp->sfh_cfa_fixed_fp_offset;
923 }
924
925 /* Get the SFrame's fixed RA offset given the decoder context CTX. */
926 int8_t
927 sframe_decoder_get_fixed_ra_offset (sframe_decoder_ctx *ctx)
928 {
929 sframe_header *dhp;
930 dhp = sframe_decoder_get_header (ctx);
931 return dhp->sfh_cfa_fixed_ra_offset;
932 }
933
934 /* Find the function descriptor entry starting which contains the specified
935 address ADDR. */
936
937 sframe_func_desc_entry *
938 sframe_get_funcdesc_with_addr (sframe_decoder_ctx *ctx,
939 int32_t addr, int *errp)
940 {
941 sframe_header *dhp;
942 sframe_func_desc_entry *fdp;
943 int low, high, cnt;
944
945 if (ctx == NULL)
946 return sframe_ret_set_errno (errp, SFRAME_ERR_INVAL);
947
948 dhp = sframe_decoder_get_header (ctx);
949
950 if (dhp == NULL || dhp->sfh_num_fdes == 0 || ctx->sfd_funcdesc == NULL)
951 return sframe_ret_set_errno (errp, SFRAME_ERR_DCTX_INVAL);
952 /* If the FDE sub-section is not sorted on PCs, skip the lookup because
953 binary search cannot be used. */
954 if ((dhp->sfh_preamble.sfp_flags & SFRAME_F_FDE_SORTED) == 0)
955 return sframe_ret_set_errno (errp, SFRAME_ERR_FDE_NOTSORTED);
956
957 /* Do the binary search. */
958 fdp = (sframe_func_desc_entry *) ctx->sfd_funcdesc;
959 low = 0;
960 high = dhp->sfh_num_fdes;
961 cnt = high;
962 while (low <= high)
963 {
964 int mid = low + (high - low) / 2;
965
966 if (fdp[mid].sfde_func_start_address == addr)
967 return fdp + mid;
968
969 if (fdp[mid].sfde_func_start_address < addr)
970 {
971 if (mid == (cnt - 1)) /* Check if it's the last one. */
972 return fdp + (cnt - 1);
973 else if (fdp[mid+1].sfde_func_start_address > addr)
974 return fdp + mid;
975 low = mid + 1;
976 }
977 else
978 high = mid - 1;
979 }
980
981 return sframe_ret_set_errno (errp, SFRAME_ERR_FDE_NOTFOUND);
982 }
983
984 /* Find the SFrame Row Entry which contains the PC. Returns
985 SFRAME_ERR if failure. */
986
987 int
988 sframe_find_fre (sframe_decoder_ctx *ctx, int32_t pc,
989 sframe_frame_row_entry *frep)
990 {
991 sframe_func_desc_entry *fdep;
992 uint32_t start_address, i;
993 sframe_frame_row_entry cur_fre, next_fre;
994 unsigned char *sp;
995 unsigned int fre_type, fde_type;
996 size_t esz;
997 int err = 0;
998 size_t size = 0;
999 /* For regular FDEs (i.e. fde_type SFRAME_FDE_TYPE_PCINC),
1000 where the start address in the FRE is an offset from start pc,
1001 use a bitmask with all bits set so that none of the address bits are
1002 ignored. In this case, we need to return the FRE where
1003 (PC >= FRE_START_ADDR) */
1004 uint64_t bitmask = 0xffffffff;
1005
1006 if ((ctx == NULL) || (frep == NULL))
1007 return sframe_set_errno (&err, SFRAME_ERR_INVAL);
1008
1009 /* Find the FDE which contains the PC, then scan its fre entries. */
1010 fdep = sframe_get_funcdesc_with_addr (ctx, pc, &err);
1011 if (fdep == NULL || ctx->sfd_fres == NULL)
1012 return sframe_set_errno (&err, SFRAME_ERR_DCTX_INVAL);
1013
1014 fre_type = sframe_get_fre_type (fdep);
1015 fde_type = sframe_get_fde_type (fdep);
1016
1017 /* For FDEs for repetitive pattern of insns, we need to return the FRE
1018 such that (PC & FRE_START_ADDR_AS_MASK >= FRE_START_ADDR_AS_MASK).
1019 so, update the bitmask to the start address. */
1020 /* FIXME - the bitmask should be picked per ABI or encoded in the format
1021 somehow. For AMD64, the pltN entry stub is 16 bytes. */
1022 if (fde_type == SFRAME_FDE_TYPE_PCMASK)
1023 bitmask = 0xff;
1024
1025 sp = (unsigned char *) ctx->sfd_fres + fdep->sfde_func_start_fre_off;
1026 for (i = 0; i < fdep->sfde_func_num_fres; i++)
1027 {
1028 err = sframe_decode_fre ((const char *)sp, &next_fre, fre_type, &esz);
1029 start_address = next_fre.fre_start_addr;
1030
1031 if (((fdep->sfde_func_start_address
1032 + (int32_t) start_address) & bitmask) <= (pc & bitmask))
1033 {
1034 sframe_frame_row_entry_copy (&cur_fre, &next_fre);
1035
1036 /* Get the next FRE in sequence. */
1037 if (i < fdep->sfde_func_num_fres - 1)
1038 {
1039 sp += esz;
1040 err = sframe_decode_fre ((const char*)sp, &next_fre,
1041 fre_type, &esz);
1042
1043 /* Sanity check the next FRE. */
1044 if (!sframe_fre_sanity_check_p (&next_fre))
1045 return sframe_set_errno (&err, SFRAME_ERR_FRE_INVAL);
1046
1047 size = next_fre.fre_start_addr;
1048 }
1049 else size = fdep->sfde_func_size;
1050
1051 /* If the cur FRE is the one that contains the PC, return it. */
1052 if (((fdep->sfde_func_start_address
1053 + (int32_t)size) & bitmask) > (pc & bitmask))
1054 {
1055 sframe_frame_row_entry_copy (frep, &cur_fre);
1056 return 0;
1057 }
1058 }
1059 else
1060 return sframe_set_errno (&err, SFRAME_ERR_FRE_INVAL);
1061 }
1062 return sframe_set_errno (&err, SFRAME_ERR_FDE_INVAL);
1063 }
1064
1065 /* Return the number of function descriptor entries in the SFrame decoder
1066 DCTX. */
1067
1068 unsigned int
1069 sframe_decoder_get_num_fidx (sframe_decoder_ctx *ctx)
1070 {
1071 unsigned int num_fdes = 0;
1072 sframe_header *dhp = NULL;
1073 dhp = sframe_decoder_get_header (ctx);
1074 if (dhp)
1075 num_fdes = dhp->sfh_num_fdes;
1076 return num_fdes;
1077 }
1078
1079 /* Get the data (NUM_FRES, FUNC_START_ADDRESS) from the function
1080 descriptor entry at index I'th in the decoder CTX. If failed,
1081 return error code. */
1082 /* FIXME - consolidate the args and return a
1083 sframe_func_desc_index_elem rather? */
1084
1085 int
1086 sframe_decoder_get_funcdesc (sframe_decoder_ctx *ctx,
1087 unsigned int i,
1088 uint32_t *num_fres,
1089 uint32_t *func_size,
1090 int32_t *func_start_address,
1091 unsigned char *func_info)
1092 {
1093 sframe_func_desc_entry *fdp;
1094 unsigned int num_fdes;
1095 int err = 0;
1096
1097 if (ctx == NULL || func_start_address == NULL || num_fres == NULL
1098 || func_size == NULL)
1099 return sframe_set_errno (&err, SFRAME_ERR_INVAL);
1100
1101 num_fdes = sframe_decoder_get_num_fidx (ctx);
1102 if (num_fdes == 0
1103 || i >= num_fdes
1104 || ctx->sfd_funcdesc == NULL)
1105 return sframe_set_errno (&err, SFRAME_ERR_DCTX_INVAL);
1106
1107 fdp = (sframe_func_desc_entry *) ctx->sfd_funcdesc + i;
1108 *num_fres = fdp->sfde_func_num_fres;
1109 *func_start_address = fdp->sfde_func_start_address;
1110 *func_size = fdp->sfde_func_size;
1111 *func_info = fdp->sfde_func_info;
1112
1113 return 0;
1114 }
1115
1116 /* Get the function descriptor entry at index FUNC_IDX in the decoder
1117 context CTX. */
1118
1119 static sframe_func_desc_entry *
1120 sframe_decoder_get_funcdesc_at_index (sframe_decoder_ctx *ctx,
1121 uint32_t func_idx)
1122 {
1123 /* Invalid argument. No FDE will be found. */
1124 if (func_idx >= sframe_decoder_get_num_fidx (ctx))
1125 return NULL;
1126
1127 sframe_func_desc_entry *fdep;
1128 fdep = (sframe_func_desc_entry *) ctx->sfd_funcdesc;
1129 return fdep + func_idx;
1130 }
1131
1132 /* Get the FRE_IDX'th FRE of the function at FUNC_IDX'th function
1133 descriptor entry in the SFrame decoder CTX. Returns error code as
1134 applicable. */
1135
1136 int
1137 sframe_decoder_get_fre (sframe_decoder_ctx *ctx,
1138 unsigned int func_idx,
1139 unsigned int fre_idx,
1140 sframe_frame_row_entry *fre)
1141 {
1142 sframe_func_desc_entry *fdep;
1143 sframe_frame_row_entry ifre;
1144 unsigned char *sp;
1145 uint32_t i;
1146 unsigned int fre_type;
1147 size_t esz = 0;
1148 int err = 0;
1149
1150 if (ctx == NULL || fre == NULL)
1151 return sframe_set_errno (&err, SFRAME_ERR_INVAL);
1152
1153 /* Get function descriptor entry at index func_idx. */
1154 fdep = sframe_decoder_get_funcdesc_at_index (ctx, func_idx);
1155
1156 if (fdep == NULL)
1157 return sframe_set_errno (&err, SFRAME_ERR_FDE_NOTFOUND);
1158
1159 fre_type = sframe_get_fre_type (fdep);
1160 /* Now scan the FRE entries. */
1161 sp = (unsigned char *) ctx->sfd_fres + fdep->sfde_func_start_fre_off;
1162 for (i = 0; i < fdep->sfde_func_num_fres; i++)
1163 {
1164 /* Decode the FRE at the current position. Return it if valid. */
1165 err = sframe_decode_fre ((const char *)sp, &ifre, fre_type, &esz);
1166 if (i == fre_idx)
1167 {
1168 if (!sframe_fre_sanity_check_p (&ifre))
1169 return sframe_set_errno (&err, SFRAME_ERR_FRE_INVAL);
1170
1171 sframe_frame_row_entry_copy (fre, &ifre);
1172
1173 if (fdep->sfde_func_size)
1174 sframe_assert (fre->fre_start_addr < fdep->sfde_func_size);
1175 else
1176 /* A SFrame FDE with func size equal to zero is possible. */
1177 sframe_assert (fre->fre_start_addr == fdep->sfde_func_size);
1178
1179 return 0;
1180 }
1181 /* Next FRE. */
1182 sp += esz;
1183 }
1184
1185 return sframe_set_errno (&err, SFRAME_ERR_FDE_NOTFOUND);
1186 }
1187
1188
1189 /* SFrame Encoder. */
1190
1191 /* Get a reference to the ENCODER's SFrame header. */
1192
1193 static sframe_header *
1194 sframe_encoder_get_header (sframe_encoder_ctx *encoder)
1195 {
1196 sframe_header *hp = NULL;
1197 if (encoder)
1198 hp = &encoder->sfe_header;
1199 return hp;
1200 }
1201
1202 static sframe_func_desc_entry *
1203 sframe_encoder_get_funcdesc_at_index (sframe_encoder_ctx *encoder,
1204 uint32_t func_idx)
1205 {
1206 sframe_func_desc_entry *fde = NULL;
1207 if (func_idx < sframe_encoder_get_num_fidx (encoder))
1208 {
1209 sf_funidx_tbl *func_tbl = (sf_funidx_tbl *) encoder->sfe_funcdesc;
1210 fde = func_tbl->entry + func_idx;
1211 }
1212 return fde;
1213 }
1214
1215 /* Create an encoder context with the given SFrame format version VER, FLAGS
1216 and ABI information. Sets errp if failure. */
1217
1218 sframe_encoder_ctx *
1219 sframe_encode (unsigned char ver, unsigned char flags, int abi_arch,
1220 int8_t fixed_fp_offset, int8_t fixed_ra_offset, int *errp)
1221 {
1222 sframe_header *hp;
1223 sframe_encoder_ctx *encoder;
1224
1225 if (ver != SFRAME_VERSION)
1226 return sframe_ret_set_errno (errp, SFRAME_ERR_VERSION_INVAL);
1227
1228 if ((encoder = malloc (sizeof (sframe_encoder_ctx))) == NULL)
1229 return sframe_ret_set_errno (errp, SFRAME_ERR_NOMEM);
1230
1231 memset (encoder, 0, sizeof (sframe_encoder_ctx));
1232
1233 /* Get the SFrame header and update it. */
1234 hp = sframe_encoder_get_header (encoder);
1235 hp->sfh_preamble.sfp_version = ver;
1236 hp->sfh_preamble.sfp_magic = SFRAME_MAGIC;
1237 hp->sfh_preamble.sfp_flags = flags;
1238
1239 hp->sfh_abi_arch = abi_arch;
1240 hp->sfh_cfa_fixed_fp_offset = fixed_fp_offset;
1241 hp->sfh_cfa_fixed_ra_offset = fixed_ra_offset;
1242
1243 return encoder;
1244 }
1245
1246 /* Free the encoder context. */
1247
1248 void
1249 sframe_encoder_free (sframe_encoder_ctx **encoder)
1250 {
1251 if (encoder != NULL)
1252 {
1253 sframe_encoder_ctx *ectx = *encoder;
1254 if (ectx == NULL)
1255 return;
1256
1257 if (ectx->sfe_funcdesc != NULL)
1258 {
1259 free (ectx->sfe_funcdesc);
1260 ectx->sfe_funcdesc = NULL;
1261 }
1262 if (ectx->sfe_fres != NULL)
1263 {
1264 free (ectx->sfe_fres);
1265 ectx->sfe_fres = NULL;
1266 }
1267 if (ectx->sfe_data != NULL)
1268 {
1269 free (ectx->sfe_data);
1270 ectx->sfe_data = NULL;
1271 }
1272
1273 free (*encoder);
1274 *encoder = NULL;
1275 }
1276 }
1277
1278 /* Get the size of the SFrame header from the encoder ctx ENCODER. */
1279
1280 unsigned int
1281 sframe_encoder_get_hdr_size (sframe_encoder_ctx *encoder)
1282 {
1283 sframe_header *ehp;
1284 ehp = sframe_encoder_get_header (encoder);
1285 return sframe_get_hdr_size (ehp);
1286 }
1287
1288 /* Get the abi/arch info from the SFrame encoder context ENCODER. */
1289
1290 unsigned char
1291 sframe_encoder_get_abi_arch (sframe_encoder_ctx *encoder)
1292 {
1293 unsigned char abi_arch = 0;
1294 sframe_header *ehp;
1295 ehp = sframe_encoder_get_header (encoder);
1296 if (ehp)
1297 abi_arch = ehp->sfh_abi_arch;
1298 return abi_arch;
1299 }
1300
1301 /* Return the number of function descriptor entries in the SFrame encoder
1302 ENCODER. */
1303
1304 unsigned int
1305 sframe_encoder_get_num_fidx (sframe_encoder_ctx *encoder)
1306 {
1307 unsigned int num_fdes = 0;
1308 sframe_header *ehp = NULL;
1309 ehp = sframe_encoder_get_header (encoder);
1310 if (ehp)
1311 num_fdes = ehp->sfh_num_fdes;
1312 return num_fdes;
1313 }
1314
1315 /* Add an FRE to function at FUNC_IDX'th function descriptor entry in
1316 the encoder context. */
1317
1318 int
1319 sframe_encoder_add_fre (sframe_encoder_ctx *encoder,
1320 unsigned int func_idx,
1321 sframe_frame_row_entry *frep)
1322 {
1323 sframe_header *ehp;
1324 sframe_func_desc_entry *fdep;
1325 sframe_frame_row_entry *ectx_frep;
1326 size_t offsets_sz, esz;
1327 unsigned int fre_type;
1328 size_t fre_tbl_sz;
1329 int err = 0;
1330
1331 if (encoder == NULL || frep == NULL)
1332 return sframe_set_errno (&err, SFRAME_ERR_INVAL);
1333 if (!sframe_fre_sanity_check_p (frep))
1334 return sframe_set_errno (&err, SFRAME_ERR_FRE_INVAL);
1335
1336 /* Use func_idx to gather the function descriptor entry. */
1337 fdep = sframe_encoder_get_funcdesc_at_index (encoder, func_idx);
1338
1339 if (fdep == NULL)
1340 return sframe_set_errno (&err, SFRAME_ERR_FDE_NOTFOUND);
1341
1342 fre_type = sframe_get_fre_type (fdep);
1343 sf_fre_tbl *fre_tbl = (sf_fre_tbl *) encoder->sfe_fres;
1344
1345 if (fre_tbl == NULL)
1346 {
1347 fre_tbl_sz = (sizeof (sf_fre_tbl)
1348 + (number_of_entries * sizeof (sframe_frame_row_entry)));
1349 fre_tbl = malloc (fre_tbl_sz);
1350
1351 if (fre_tbl == NULL)
1352 {
1353 sframe_set_errno (&err, SFRAME_ERR_NOMEM);
1354 goto bad; /* OOM. */
1355 }
1356 memset (fre_tbl, 0, fre_tbl_sz);
1357 fre_tbl->alloced = number_of_entries;
1358 }
1359 else if (fre_tbl->count == fre_tbl->alloced)
1360 {
1361 fre_tbl_sz = (sizeof (sf_fre_tbl)
1362 + ((fre_tbl->alloced + number_of_entries)
1363 * sizeof (sframe_frame_row_entry)));
1364 fre_tbl = realloc (fre_tbl, fre_tbl_sz);
1365 if (fre_tbl == NULL)
1366 {
1367 sframe_set_errno (&err, SFRAME_ERR_NOMEM);
1368 goto bad; /* OOM. */
1369 }
1370
1371 memset (&fre_tbl->entry[fre_tbl->alloced], 0,
1372 number_of_entries * sizeof (sframe_frame_row_entry));
1373 fre_tbl->alloced += number_of_entries;
1374 }
1375
1376 ectx_frep = &fre_tbl->entry[fre_tbl->count];
1377 ectx_frep->fre_start_addr
1378 = frep->fre_start_addr;
1379 ectx_frep->fre_info = frep->fre_info;
1380
1381 if (fdep->sfde_func_size)
1382 sframe_assert (frep->fre_start_addr < fdep->sfde_func_size);
1383 else
1384 /* A SFrame FDE with func size equal to zero is possible. */
1385 sframe_assert (frep->fre_start_addr == fdep->sfde_func_size);
1386
1387 /* frep has already been sanity check'd. Get offsets size. */
1388 offsets_sz = sframe_fre_offset_bytes_size (frep->fre_info);
1389 memcpy (&ectx_frep->fre_offsets, &frep->fre_offsets, offsets_sz);
1390
1391 esz = sframe_fre_entry_size (frep, fre_type);
1392 fre_tbl->count++;
1393
1394 encoder->sfe_fres = (void *) fre_tbl;
1395 encoder->sfe_fre_nbytes += esz;
1396
1397 ehp = sframe_encoder_get_header (encoder);
1398 ehp->sfh_num_fres = fre_tbl->count;
1399
1400 /* Update the value of the number of FREs for the function. */
1401 fdep->sfde_func_num_fres++;
1402
1403 return 0;
1404
1405 bad:
1406 if (fre_tbl != NULL)
1407 free (fre_tbl);
1408 encoder->sfe_fres = NULL;
1409 encoder->sfe_fre_nbytes = 0;
1410 return -1;
1411 }
1412
1413 /* Add a new function descriptor entry with START_ADDR, FUNC_SIZE and NUM_FRES
1414 to the encoder. */
1415
1416 int
1417 sframe_encoder_add_funcdesc (sframe_encoder_ctx *encoder,
1418 int32_t start_addr,
1419 uint32_t func_size,
1420 unsigned char func_info,
1421 uint32_t num_fres __attribute__ ((unused)))
1422 {
1423 sframe_header *ehp;
1424 sf_funidx_tbl *fd_info;
1425 size_t fd_tbl_sz;
1426 int err = 0;
1427
1428 /* FIXME book-keep num_fres for error checking. */
1429 if (encoder == NULL)
1430 return sframe_set_errno (&err, SFRAME_ERR_INVAL);
1431
1432 fd_info = (sf_funidx_tbl *) encoder->sfe_funcdesc;
1433 ehp = sframe_encoder_get_header (encoder);
1434
1435 if (fd_info == NULL)
1436 {
1437 fd_tbl_sz = (sizeof (sf_funidx_tbl)
1438 + (number_of_entries * sizeof (sframe_func_desc_entry)));
1439 fd_info = malloc (fd_tbl_sz);
1440 if (fd_info == NULL)
1441 {
1442 sframe_set_errno (&err, SFRAME_ERR_NOMEM);
1443 goto bad; /* OOM. */
1444 }
1445 memset (fd_info, 0, fd_tbl_sz);
1446 fd_info->alloced = number_of_entries;
1447 }
1448 else if (fd_info->count == fd_info->alloced)
1449 {
1450 fd_tbl_sz = (sizeof (sf_funidx_tbl)
1451 + ((fd_info->alloced + number_of_entries)
1452 * sizeof (sframe_func_desc_entry)));
1453 fd_info = realloc (fd_info, fd_tbl_sz);
1454 if (fd_info == NULL)
1455 {
1456 sframe_set_errno (&err, SFRAME_ERR_NOMEM);
1457 goto bad; /* OOM. */
1458 }
1459
1460 memset (&fd_info->entry[fd_info->alloced], 0,
1461 number_of_entries * sizeof (sframe_func_desc_entry));
1462 fd_info->alloced += number_of_entries;
1463 }
1464
1465 fd_info->entry[fd_info->count].sfde_func_start_address = start_addr;
1466 /* Num FREs is updated as FREs are added for the function later via
1467 sframe_encoder_add_fre. */
1468 fd_info->entry[fd_info->count].sfde_func_size = func_size;
1469 fd_info->entry[fd_info->count].sfde_func_start_fre_off
1470 = encoder->sfe_fre_nbytes;
1471 #if 0
1472 // Linker optimization test code cleanup later ibhagat TODO FIXME
1473 unsigned int fre_type = sframe_calc_fre_type (func_size);
1474
1475 fd_info->entry[fd_info->count].sfde_func_info
1476 = sframe_fde_func_info (fre_type);
1477 #endif
1478 fd_info->entry[fd_info->count].sfde_func_info = func_info;
1479 fd_info->count++;
1480 encoder->sfe_funcdesc = (void *) fd_info;
1481 ehp->sfh_num_fdes++;
1482 return 0;
1483
1484 bad:
1485 if (fd_info != NULL)
1486 free (fd_info);
1487 encoder->sfe_funcdesc = NULL;
1488 ehp->sfh_num_fdes = 0;
1489 return -1;
1490 }
1491
1492 static int
1493 sframe_sort_funcdesc (sframe_encoder_ctx *encoder)
1494 {
1495 sframe_header *ehp;
1496
1497 ehp = sframe_encoder_get_header (encoder);
1498 /* Sort and write out the FDE table. */
1499 sf_funidx_tbl *fd_info = (sf_funidx_tbl *) encoder->sfe_funcdesc;
1500 if (fd_info)
1501 {
1502 qsort (fd_info->entry, fd_info->count,
1503 sizeof (sframe_func_desc_entry), fde_func);
1504 /* Update preamble's flags. */
1505 ehp->sfh_preamble.sfp_flags |= SFRAME_F_FDE_SORTED;
1506 }
1507 return 0;
1508 }
1509
1510 /* Write the SFrame FRE start address from the in-memory FRE_START_ADDR
1511 to the buffer CONTENTS (on-disk format), given the FRE_TYPE and
1512 FRE_START_ADDR_SZ. */
1513
1514 static int
1515 sframe_encoder_write_fre_start_addr (char *contents,
1516 uint32_t fre_start_addr,
1517 unsigned int fre_type,
1518 size_t fre_start_addr_sz)
1519 {
1520 int err = 0;
1521
1522 if (fre_type == SFRAME_FRE_TYPE_ADDR1)
1523 {
1524 uint8_t uc = fre_start_addr;
1525 memcpy (contents, &uc, fre_start_addr_sz);
1526 }
1527 else if (fre_type == SFRAME_FRE_TYPE_ADDR2)
1528 {
1529 uint16_t ust = fre_start_addr;
1530 memcpy (contents, &ust, fre_start_addr_sz);
1531 }
1532 else if (fre_type == SFRAME_FRE_TYPE_ADDR4)
1533 {
1534 uint32_t uit = fre_start_addr;
1535 memcpy (contents, &uit, fre_start_addr_sz);
1536 }
1537 else
1538 return sframe_set_errno (&err, SFRAME_ERR_INVAL);
1539
1540 return 0;
1541 }
1542
1543 /* Write a frame row entry pointed to by FREP into the buffer CONTENTS. The
1544 size in bytes written out are updated in ESZ.
1545
1546 This function works closely with the SFrame binary format.
1547
1548 Returns SFRAME_ERR if failure. */
1549
1550 static int
1551 sframe_encoder_write_fre (char *contents, sframe_frame_row_entry *frep,
1552 unsigned int fre_type, size_t *esz)
1553 {
1554 size_t fre_sz;
1555 size_t fre_start_addr_sz;
1556 size_t fre_stack_offsets_sz;
1557 int err = 0;
1558
1559 if (!sframe_fre_sanity_check_p (frep))
1560 return sframe_set_errno (&err, SFRAME_ERR_FRE_INVAL);
1561
1562 fre_start_addr_sz = sframe_fre_start_addr_size (fre_type);
1563 fre_stack_offsets_sz = sframe_fre_offset_bytes_size (frep->fre_info);
1564
1565 /* The FRE start address must be encodable in the available number of
1566 bytes. */
1567 uint64_t bitmask = SFRAME_BITMASK_OF_SIZE (fre_start_addr_sz);
1568 sframe_assert ((uint64_t)frep->fre_start_addr <= bitmask);
1569
1570 sframe_encoder_write_fre_start_addr (contents, frep->fre_start_addr,
1571 fre_type, fre_start_addr_sz);
1572 contents += fre_start_addr_sz;
1573
1574 memcpy (contents, &frep->fre_info, sizeof (frep->fre_info));
1575 contents += sizeof (frep->fre_info);
1576
1577 memcpy (contents, frep->fre_offsets, fre_stack_offsets_sz);
1578 contents+= fre_stack_offsets_sz;
1579
1580 fre_sz = sframe_fre_entry_size (frep, fre_type);
1581 /* Sanity checking. */
1582 sframe_assert ((fre_start_addr_sz
1583 + sizeof (frep->fre_info)
1584 + fre_stack_offsets_sz) == fre_sz);
1585
1586 *esz = fre_sz;
1587
1588 return 0;
1589 }
1590
1591 /* Serialize the core contents of the SFrame section and write out to the
1592 output buffer held in the ENCODER. Return SFRAME_ERR if failure. */
1593
1594 static int
1595 sframe_encoder_write_sframe (sframe_encoder_ctx *encoder)
1596 {
1597 char *contents;
1598 size_t buf_size;
1599 size_t hdr_size;
1600 size_t all_fdes_size;
1601 size_t fre_size;
1602 size_t esz = 0;
1603 sframe_header *ehp;
1604 unsigned char flags;
1605 sf_funidx_tbl *fd_info;
1606 sf_fre_tbl *fr_info;
1607 uint32_t i, num_fdes;
1608 uint32_t j, num_fres;
1609 sframe_func_desc_entry *fdep;
1610 sframe_frame_row_entry *frep;
1611
1612 unsigned int fre_type;
1613 int err = 0;
1614
1615 contents = encoder->sfe_data;
1616 buf_size = encoder->sfe_data_size;
1617 num_fdes = sframe_encoder_get_num_fidx (encoder);
1618 all_fdes_size = num_fdes * sizeof (sframe_func_desc_entry);
1619 ehp = sframe_encoder_get_header (encoder);
1620 hdr_size = sframe_get_hdr_size (ehp);
1621
1622 fd_info = (sf_funidx_tbl *) encoder->sfe_funcdesc;
1623 fr_info = (sf_fre_tbl *) encoder->sfe_fres;
1624
1625 /* Sanity checks:
1626 - buffers must be malloc'd by the caller. */
1627 if ((contents == NULL) || (buf_size < hdr_size))
1628 return sframe_set_errno (&err, SFRAME_ERR_BUF_INVAL);
1629 if (fr_info == NULL)
1630 return sframe_set_errno (&err, SFRAME_ERR_FRE_INVAL);
1631
1632 /* Write out the FRE table first.
1633
1634 Recall that read/write of FREs needs information from the corresponding
1635 FDE; the latter stores the information about the FRE type record used for
1636 the function. Also note that sorting of FDEs does NOT impact the order
1637 in which FREs are stored in the SFrame's FRE sub-section. This means
1638 that writing out FREs after sorting of FDEs will need some additional
1639 book-keeping. At this time, we can afford to avoid it by writing out
1640 the FREs first to the output buffer. */
1641 fre_size = 0;
1642 uint32_t global = 0;
1643 uint32_t fre_index = 0;
1644
1645 contents += hdr_size + all_fdes_size;
1646 for (i = 0; i < num_fdes; i++)
1647 {
1648 fdep = &fd_info->entry[i];
1649 fre_type = sframe_get_fre_type (fdep);
1650 num_fres = fdep->sfde_func_num_fres;
1651
1652 for (j = 0; j < num_fres; j++)
1653 {
1654 fre_index = global + j;
1655 frep = &fr_info->entry[fre_index];
1656
1657 sframe_encoder_write_fre (contents, frep, fre_type, &esz);
1658 contents += esz;
1659 fre_size += esz; /* For debugging only. */
1660 }
1661 global += j;
1662 }
1663
1664 sframe_assert (fre_size == ehp->sfh_fre_len);
1665 sframe_assert (global == ehp->sfh_num_fres);
1666 sframe_assert ((size_t)(contents - encoder->sfe_data) == buf_size);
1667
1668 /* Sort the FDE table */
1669 sframe_sort_funcdesc (encoder);
1670
1671 /* Sanity checks:
1672 - the FDE section must have been sorted by now on the start address
1673 of each function. */
1674 flags = ehp->sfh_preamble.sfp_flags;
1675 if (!(flags & SFRAME_F_FDE_SORTED)
1676 || (fd_info == NULL))
1677 return sframe_set_errno (&err, SFRAME_ERR_FDE_INVAL);
1678
1679 contents = encoder->sfe_data;
1680 /* Write out the SFrame header. The SFrame header in the encoder
1681 object has already been updated with correct offsets by the caller. */
1682 memcpy (contents, ehp, hdr_size);
1683 contents += hdr_size;
1684
1685 /* Write out the FDE table sorted on funtion start address. */
1686 memcpy (contents, fd_info->entry, all_fdes_size);
1687 contents += all_fdes_size;
1688
1689 return 0;
1690 }
1691
1692 /* Serialize the contents of the encoder and return the buffer. ENCODED_SIZE
1693 is updated to the size of the buffer. */
1694
1695 char *
1696 sframe_encoder_write (sframe_encoder_ctx *encoder,
1697 size_t *encoded_size, int *errp)
1698 {
1699 sframe_header *ehp;
1700 size_t hdrsize, fsz, fresz, bufsize;
1701 int foreign_endian;
1702
1703 /* Initialize the encoded_size to zero. This makes it simpler to just
1704 return from the function in case of failure. Free'ing up of
1705 encoder->sfe_data is the responsibility of the caller. */
1706 *encoded_size = 0;
1707
1708 if (encoder == NULL || encoded_size == NULL || errp == NULL)
1709 return sframe_ret_set_errno (errp, SFRAME_ERR_INVAL);
1710
1711 ehp = sframe_encoder_get_header (encoder);
1712 hdrsize = sframe_get_hdr_size (ehp);
1713 fsz = sframe_encoder_get_num_fidx (encoder)
1714 * sizeof (sframe_func_desc_entry);
1715 fresz = encoder->sfe_fre_nbytes;
1716
1717 /* The total size of buffer is the sum of header, SFrame Function Descriptor
1718 Entries section and the FRE section. */
1719 bufsize = hdrsize + fsz + fresz;
1720 encoder->sfe_data = (char *) malloc (bufsize);
1721 if (encoder->sfe_data == NULL)
1722 return sframe_ret_set_errno (errp, SFRAME_ERR_NOMEM);
1723 encoder->sfe_data_size = bufsize;
1724
1725 /* Update the information in the SFrame header. */
1726 /* SFrame FDE section follows immediately after the header. */
1727 ehp->sfh_fdeoff = 0;
1728 /* SFrame FRE section follows immediately after the SFrame FDE section. */
1729 ehp->sfh_freoff = fsz;
1730 ehp->sfh_fre_len = fresz;
1731
1732 foreign_endian = need_swapping (ehp->sfh_abi_arch);
1733
1734 /* Write out the FDE Index and the FRE table in the sfe_data. */
1735 if (sframe_encoder_write_sframe (encoder))
1736 return sframe_ret_set_errno (errp, SFRAME_ERR_BUF_INVAL);
1737
1738 /* Endian flip the contents if necessary. */
1739 if (foreign_endian)
1740 {
1741 if (flip_sframe (encoder->sfe_data, bufsize, 1))
1742 return sframe_ret_set_errno (errp, SFRAME_ERR_BUF_INVAL);
1743 flip_header ((sframe_header*)encoder->sfe_data);
1744 }
1745
1746 *encoded_size = bufsize;
1747 return encoder->sfe_data;
1748 }