Allow the use of SOURCE_DATE_EPOCH in the timestamps for members of static archives.
[binutils-gdb.git] / libsframe / sframe.c
blob95da010f823b5ac76341ec1cafe2462b2b7afa34
1 /* sframe.c - SFrame decoder/encoder.
3 Copyright (C) 2022-2023 Free Software Foundation, Inc.
5 This file is part of libsframe.
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.
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.
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/>. */
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"
28 struct sf_fde_tbl
30 unsigned int count;
31 unsigned int alloced;
32 sframe_func_desc_entry entry[1];
35 struct sf_fre_tbl
37 unsigned int count;
38 unsigned int alloced;
39 sframe_frame_row_entry entry[1];
42 #define _sf_printflike_(string_index,first_to_check) \
43 __attribute__ ((__format__ (__printf__, (string_index), (first_to_check))))
45 static void debug_printf (const char *, ...);
47 static int _sframe_debug; /* Control for printing out debug info. */
48 static int number_of_entries = 64;
50 static void
51 sframe_init_debug (void)
53 static int inited;
55 if (!inited)
57 _sframe_debug = getenv ("SFRAME_DEBUG") != NULL;
58 inited = 1;
62 _sf_printflike_ (1, 2)
63 static void debug_printf (const char *format, ...)
65 if (_sframe_debug)
67 va_list args;
69 va_start (args, format);
70 vfprintf (stderr, format, args);
71 va_end (args);
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)
83 /* Store the specified error code into errp if it is non-NULL.
84 Return SFRAME_ERR. */
86 static int
87 sframe_set_errno (int *errp, int error)
89 if (errp != NULL)
90 *errp = error;
91 return SFRAME_ERR;
94 /* Store the specified error code into errp if it is non-NULL.
95 Return NULL. */
97 static void *
98 sframe_ret_set_errno (int *errp, int error)
100 if (errp != NULL)
101 *errp = error;
102 return NULL;
105 /* Get the SFrame header size. */
107 static uint32_t
108 sframe_get_hdr_size (sframe_header *sfh)
110 return SFRAME_V1_HDR_SIZE (*sfh);
113 /* Access functions for frame row entry data. */
115 static uint8_t
116 sframe_fre_get_offset_count (uint8_t fre_info)
118 return SFRAME_V1_FRE_OFFSET_COUNT (fre_info);
121 static uint8_t
122 sframe_fre_get_offset_size (uint8_t fre_info)
124 return SFRAME_V1_FRE_OFFSET_SIZE (fre_info);
127 static bool
128 sframe_get_fre_ra_mangled_p (uint8_t fre_info)
130 return SFRAME_V1_FRE_MANGLED_RA_P (fre_info);
133 /* Access functions for info from function descriptor entry. */
135 static uint32_t
136 sframe_get_fre_type (sframe_func_desc_entry *fdep)
138 uint32_t fre_type = 0;
139 if (fdep)
140 fre_type = SFRAME_V1_FUNC_FRE_TYPE (fdep->sfde_func_info);
141 return fre_type;
144 static uint32_t
145 sframe_get_fde_type (sframe_func_desc_entry *fdep)
147 uint32_t fde_type = 0;
148 if (fdep)
149 fde_type = SFRAME_V1_FUNC_FDE_TYPE (fdep->sfde_func_info);
150 return fde_type;
153 /* Check if flipping is needed, based on ENDIAN. */
155 static int
156 need_swapping (int endian)
158 unsigned int ui = 1;
159 char *c = (char *)&ui;
160 int is_little = (int)*c;
162 switch (endian)
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;
173 return 0;
176 /* Flip the endianness of the SFrame header. */
178 static void
179 flip_header (sframe_header *sfheader)
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);
193 static void
194 flip_fde (sframe_func_desc_entry *fdep)
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);
202 /* Check if SFrame header has valid data. */
204 static bool
205 sframe_header_sanity_check_p (sframe_header *hp)
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_1
211 && hp->sfh_preamble.sfp_version != SFRAME_VERSION_2)
212 || (hp->sfh_preamble.sfp_flags | all_flags) != all_flags)
213 return false;
215 /* Check offsets are valid. */
216 if (hp->sfh_fdeoff > hp->sfh_freoff)
217 return false;
219 return true;
222 /* Flip the start address pointed to by FP. */
224 static void
225 flip_fre_start_address (char *addr, uint32_t fre_type)
227 if (fre_type == SFRAME_FRE_TYPE_ADDR2)
229 uint16_t *start_addr = (uint16_t *)addr;
230 swap_thing (*start_addr);
232 else if (fre_type == SFRAME_FRE_TYPE_ADDR4)
234 uint32_t *start_addr = (uint32_t *)addr;
235 swap_thing (*start_addr);
239 static void
240 flip_fre_stack_offsets (char *offsets, uint8_t offset_size, uint8_t offset_cnt)
242 int j;
244 if (offset_size == SFRAME_FRE_OFFSET_2B)
246 uint16_t *ust = (uint16_t *)offsets;
247 for (j = offset_cnt; j > 0; ust++, j--)
248 swap_thing (*ust);
250 else if (offset_size == SFRAME_FRE_OFFSET_4B)
252 uint32_t *uit = (uint32_t *)offsets;
253 for (j = offset_cnt; j > 0; uit++, j--)
254 swap_thing (*uit);
258 /* Get the FRE start address size, given the FRE_TYPE. */
260 static size_t
261 sframe_fre_start_addr_size (uint32_t fre_type)
263 size_t addr_size = 0;
264 switch (fre_type)
266 case SFRAME_FRE_TYPE_ADDR1:
267 addr_size = 1;
268 break;
269 case SFRAME_FRE_TYPE_ADDR2:
270 addr_size = 2;
271 break;
272 case SFRAME_FRE_TYPE_ADDR4:
273 addr_size = 4;
274 break;
275 default:
276 /* No other value is expected. */
277 sframe_assert (0);
278 break;
280 return addr_size;
283 /* Check if the FREP has valid data. */
285 static bool
286 sframe_fre_sanity_check_p (sframe_frame_row_entry *frep)
288 uint8_t offset_size, offset_cnt;
289 uint8_t fre_info;
291 if (frep == NULL)
292 return false;
294 fre_info = frep->fre_info;
295 offset_size = sframe_fre_get_offset_size (fre_info);
297 if (offset_size != SFRAME_FRE_OFFSET_1B
298 && offset_size != SFRAME_FRE_OFFSET_2B
299 && offset_size != SFRAME_FRE_OFFSET_4B)
300 return false;
302 offset_cnt = sframe_fre_get_offset_count (fre_info);
303 if (offset_cnt > MAX_NUM_STACK_OFFSETS)
304 return false;
306 return true;
309 /* Get FRE_INFO's offset size in bytes. */
311 static size_t
312 sframe_fre_offset_bytes_size (uint8_t fre_info)
314 uint8_t offset_size, offset_cnt;
316 offset_size = sframe_fre_get_offset_size (fre_info);
318 debug_printf ("offset_size = %u\n", offset_size);
320 offset_cnt = sframe_fre_get_offset_count (fre_info);
322 if (offset_size == SFRAME_FRE_OFFSET_2B
323 || offset_size == SFRAME_FRE_OFFSET_4B) /* 2 or 4 bytes. */
324 return (offset_cnt * (offset_size * 2));
326 return (offset_cnt);
329 /* Get total size in bytes to represent FREP in the binary format. This
330 includes the starting address, FRE info, and all the offsets. */
332 static size_t
333 sframe_fre_entry_size (sframe_frame_row_entry *frep, uint32_t fre_type)
335 if (frep == NULL)
336 return 0;
338 uint8_t fre_info = frep->fre_info;
339 size_t addr_size = sframe_fre_start_addr_size (fre_type);
341 return (addr_size + sizeof (frep->fre_info)
342 + sframe_fre_offset_bytes_size (fre_info));
345 /* Get the function descriptor entry at index FUNC_IDX in the decoder
346 context CTX. */
348 static sframe_func_desc_entry *
349 sframe_decoder_get_funcdesc_at_index (sframe_decoder_ctx *ctx,
350 uint32_t func_idx)
352 sframe_func_desc_entry *fdep;
353 uint32_t num_fdes;
354 int err;
356 num_fdes = sframe_decoder_get_num_fidx (ctx);
357 if (num_fdes == 0
358 || func_idx >= num_fdes
359 || ctx->sfd_funcdesc == NULL)
360 return sframe_ret_set_errno (&err, SFRAME_ERR_DCTX_INVAL);
362 fdep = &ctx->sfd_funcdesc[func_idx];
363 return fdep;
366 /* Check whether for the given FDEP, the SFrame Frame Row Entry identified via
367 the START_IP_OFFSET and the END_IP_OFFSET, provides the stack trace
368 information for the PC. */
370 static bool
371 sframe_fre_check_range_p (sframe_func_desc_entry *fdep,
372 int32_t start_ip_offset, int32_t end_ip_offset,
373 int32_t pc)
375 int32_t start_ip, end_ip;
376 int32_t func_start_addr;
377 uint8_t rep_block_size;
378 uint32_t fde_type;
379 int32_t masked_pc;
380 bool mask_p;
381 bool ret;
383 ret = false;
385 if (!fdep)
386 return ret;
388 func_start_addr = fdep->sfde_func_start_address;
389 fde_type = sframe_get_fde_type (fdep);
390 mask_p = (fde_type == SFRAME_FDE_TYPE_PCMASK);
391 rep_block_size = fdep->sfde_func_rep_size;
393 if (!mask_p)
395 start_ip = start_ip_offset + func_start_addr;
396 end_ip = end_ip_offset + func_start_addr;
397 ret = ((start_ip <= pc) && (end_ip >= pc));
399 else
401 /* For FDEs for repetitive pattern of insns, we need to return the FRE
402 where pc % rep_block_size is between start_ip_offset and
403 end_ip_offset. */
404 masked_pc = pc % rep_block_size;
405 ret = ((start_ip_offset <= masked_pc) && (end_ip_offset >= masked_pc));
408 return ret;
411 static int
412 flip_fre (char *fp, uint32_t fre_type, size_t *fre_size)
414 uint8_t fre_info;
415 uint8_t offset_size, offset_cnt;
416 size_t addr_size, fre_info_size = 0;
417 int err = 0;
419 if (fre_size == NULL)
420 return sframe_set_errno (&err, SFRAME_ERR_INVAL);
422 flip_fre_start_address (fp, fre_type);
424 /* Advance the buffer pointer to where the FRE info is. */
425 addr_size = sframe_fre_start_addr_size (fre_type);
426 fp += addr_size;
428 /* FRE info is uint8_t. No need to flip. */
429 fre_info = *(uint8_t*)fp;
430 offset_size = sframe_fre_get_offset_size (fre_info);
431 offset_cnt = sframe_fre_get_offset_count (fre_info);
433 /* Advance the buffer pointer to where the stack offsets are. */
434 fre_info_size = sizeof (uint8_t);
435 fp += fre_info_size;
436 flip_fre_stack_offsets (fp, offset_size, offset_cnt);
438 *fre_size
439 = addr_size + fre_info_size + sframe_fre_offset_bytes_size (fre_info);
441 return 0;
444 /* Endian flip the contents of FRAME_BUF of size BUF_SIZE.
445 The SFrame header in the FRAME_BUF must be endian flipped prior to
446 calling flip_sframe.
448 Endian flipping at decode time vs encode time have different needs. At
449 encode time, the frame_buf is in host endianness, and hence, values should
450 be read up before the buffer is changed to foreign endianness. This change
451 of behaviour is specified via TO_FOREIGN arg.
453 If an error code is returned, the buffer should not be used. */
455 static int
456 flip_sframe (char *frame_buf, size_t buf_size, uint32_t to_foreign)
458 unsigned int i, j, prev_frep_index;
459 sframe_header *ihp;
460 char *fdes;
461 char *fp = NULL;
462 sframe_func_desc_entry *fdep;
463 unsigned int num_fdes = 0;
464 unsigned int num_fres = 0;
465 uint32_t fre_type = 0;
466 uint32_t fre_offset = 0;
467 size_t esz = 0;
468 size_t hdrsz = 0;
469 int err = 0;
470 /* For error checking. */
471 size_t bytes_flipped = 0;
473 /* Header must be in host endianness at this time. */
474 ihp = (sframe_header *)frame_buf;
476 if (!sframe_header_sanity_check_p (ihp))
477 return sframe_set_errno (&err, SFRAME_ERR_BUF_INVAL);
479 /* The contents of the SFrame header are safe to read. Get the number of
480 FDEs and the first FDE in the buffer. */
481 hdrsz = sframe_get_hdr_size (ihp);
482 num_fdes = ihp->sfh_num_fdes;
483 fdes = frame_buf + hdrsz + ihp->sfh_fdeoff;
484 fdep = (sframe_func_desc_entry *)fdes;
486 j = 0;
487 prev_frep_index = 0;
488 for (i = 0; i < num_fdes; fdep++, i++)
490 if ((char*)fdep >= (frame_buf + buf_size))
491 goto bad;
493 if (to_foreign)
495 num_fres = fdep->sfde_func_num_fres;
496 fre_type = sframe_get_fre_type (fdep);
497 fre_offset = fdep->sfde_func_start_fre_off;
500 flip_fde (fdep);
501 bytes_flipped += sizeof (sframe_func_desc_entry);
503 if (!to_foreign)
505 num_fres = fdep->sfde_func_num_fres;
506 fre_type = sframe_get_fre_type (fdep);
507 fre_offset = fdep->sfde_func_start_fre_off;
510 fp = frame_buf + sframe_get_hdr_size (ihp) + ihp->sfh_freoff;
511 fp += fre_offset;
512 for (; j < prev_frep_index + num_fres; j++)
514 if (flip_fre (fp, fre_type, &esz))
515 goto bad;
516 bytes_flipped += esz;
518 if (esz == 0 || esz > buf_size)
519 goto bad;
520 fp += esz;
522 prev_frep_index = j;
524 /* All FDEs and FREs must have been endian flipped by now. */
525 if ((j != ihp->sfh_num_fres) || (bytes_flipped != (buf_size - hdrsz)))
526 goto bad;
528 /* Success. */
529 return 0;
530 bad:
531 return SFRAME_ERR;
534 /* The SFrame Decoder. */
536 /* Get SFrame header from the given decoder context DCTX. */
538 static sframe_header *
539 sframe_decoder_get_header (sframe_decoder_ctx *dctx)
541 sframe_header *hp = NULL;
542 if (dctx != NULL)
543 hp = &dctx->sfd_header;
544 return hp;
547 /* Compare function for qsort'ing the FDE table. */
549 static int
550 fde_func (const void *p1, const void *p2)
552 const sframe_func_desc_entry *aa = p1;
553 const sframe_func_desc_entry *bb = p2;
555 if (aa->sfde_func_start_address < bb->sfde_func_start_address)
556 return -1;
557 else if (aa->sfde_func_start_address > bb->sfde_func_start_address)
558 return 1;
559 return 0;
562 /* Get IDX'th offset from FRE. Set errp as applicable. */
564 static int32_t
565 sframe_get_fre_offset (sframe_frame_row_entry *fre, int idx, int *errp)
567 uint8_t offset_cnt, offset_size;
569 if (fre == NULL || !sframe_fre_sanity_check_p (fre))
570 return sframe_set_errno (errp, SFRAME_ERR_FRE_INVAL);
572 offset_cnt = sframe_fre_get_offset_count (fre->fre_info);
573 offset_size = sframe_fre_get_offset_size (fre->fre_info);
575 if (offset_cnt < idx + 1)
576 return sframe_set_errno (errp, SFRAME_ERR_FREOFFSET_NOPRESENT);
578 if (errp)
579 *errp = 0; /* Offset Valid. */
581 if (offset_size == SFRAME_FRE_OFFSET_1B)
583 int8_t *sp = (int8_t *)fre->fre_offsets;
584 return sp[idx];
586 else if (offset_size == SFRAME_FRE_OFFSET_2B)
588 int16_t *sp = (int16_t *)fre->fre_offsets;
589 return sp[idx];
591 else
593 int32_t *ip = (int32_t *)fre->fre_offsets;
594 return ip[idx];
598 /* Free the decoder context. */
600 void
601 sframe_decoder_free (sframe_decoder_ctx **dctxp)
603 if (dctxp != NULL)
605 sframe_decoder_ctx *dctx = *dctxp;
606 if (dctx == NULL)
607 return;
609 if (dctx->sfd_funcdesc != NULL)
611 free (dctx->sfd_funcdesc);
612 dctx->sfd_funcdesc = NULL;
614 if (dctx->sfd_fres != NULL)
616 free (dctx->sfd_fres);
617 dctx->sfd_fres = NULL;
619 if (dctx->sfd_buf != NULL)
621 free (dctx->sfd_buf);
622 dctx->sfd_buf = NULL;
625 free (*dctxp);
626 *dctxp = NULL;
630 /* Create an FDE function info byte given an FRE_TYPE and an FDE_TYPE. */
631 /* FIXME API for linker. Revisit if its better placed somewhere else? */
633 unsigned char
634 sframe_fde_create_func_info (uint32_t fre_type,
635 uint32_t fde_type)
637 unsigned char func_info;
638 sframe_assert (fre_type == SFRAME_FRE_TYPE_ADDR1
639 || fre_type == SFRAME_FRE_TYPE_ADDR2
640 || fre_type == SFRAME_FRE_TYPE_ADDR4);
641 sframe_assert (fde_type == SFRAME_FDE_TYPE_PCINC
642 || fde_type == SFRAME_FDE_TYPE_PCMASK);
643 func_info = SFRAME_V1_FUNC_INFO (fde_type, fre_type);
644 return func_info;
647 /* Get the FRE type given the function size. */
648 /* FIXME API for linker. Revisit if its better placed somewhere else? */
650 uint32_t
651 sframe_calc_fre_type (size_t func_size)
653 uint32_t fre_type = 0;
654 if (func_size < SFRAME_FRE_TYPE_ADDR1_LIMIT)
655 fre_type = SFRAME_FRE_TYPE_ADDR1;
656 else if (func_size < SFRAME_FRE_TYPE_ADDR2_LIMIT)
657 fre_type = SFRAME_FRE_TYPE_ADDR2;
658 /* Adjust the check a bit so that it remains warning-free but meaningful
659 on 32-bit systems. */
660 else if (func_size <= (size_t) (SFRAME_FRE_TYPE_ADDR4_LIMIT - 1))
661 fre_type = SFRAME_FRE_TYPE_ADDR4;
662 return fre_type;
665 /* Get the base reg id from the FRE info. Set errp if failure. */
667 uint8_t
668 sframe_fre_get_base_reg_id (sframe_frame_row_entry *fre, int *errp)
670 if (fre == NULL)
671 return sframe_set_errno (errp, SFRAME_ERR_FRE_INVAL);
673 uint8_t fre_info = fre->fre_info;
674 return SFRAME_V1_FRE_CFA_BASE_REG_ID (fre_info);
677 /* Get the CFA offset from the FRE. If the offset is invalid, sets errp. */
679 int32_t
680 sframe_fre_get_cfa_offset (sframe_decoder_ctx *dctx ATTRIBUTE_UNUSED,
681 sframe_frame_row_entry *fre, int *errp)
683 return sframe_get_fre_offset (fre, SFRAME_FRE_CFA_OFFSET_IDX, errp);
686 /* Get the FP offset from the FRE. If the offset is invalid, sets errp. */
688 int32_t
689 sframe_fre_get_fp_offset (sframe_decoder_ctx *dctx,
690 sframe_frame_row_entry *fre, int *errp)
692 uint32_t fp_offset_idx = 0;
693 int8_t fp_offset = sframe_decoder_get_fixed_fp_offset (dctx);
694 /* If the FP offset is not being tracked, return the fixed FP offset
695 from the SFrame header. */
696 if (fp_offset != SFRAME_CFA_FIXED_FP_INVALID)
698 if (errp)
699 *errp = 0;
700 return fp_offset;
703 /* In some ABIs, the stack offset to recover RA (using the CFA) from is
704 fixed (like AMD64). In such cases, the stack offset to recover FP will
705 appear at the second index. */
706 fp_offset_idx = ((sframe_decoder_get_fixed_ra_offset (dctx)
707 != SFRAME_CFA_FIXED_RA_INVALID)
708 ? SFRAME_FRE_RA_OFFSET_IDX
709 : SFRAME_FRE_FP_OFFSET_IDX);
710 return sframe_get_fre_offset (fre, fp_offset_idx, errp);
713 /* Get the RA offset from the FRE. If the offset is invalid, sets errp. */
715 int32_t
716 sframe_fre_get_ra_offset (sframe_decoder_ctx *dctx,
717 sframe_frame_row_entry *fre, int *errp)
719 int8_t ra_offset = sframe_decoder_get_fixed_ra_offset (dctx);
720 /* If the RA offset was not being tracked, return the fixed RA offset
721 from the SFrame header. */
722 if (ra_offset != SFRAME_CFA_FIXED_RA_INVALID)
724 if (errp)
725 *errp = 0;
726 return ra_offset;
729 /* Otherwise, get the RA offset from the FRE. */
730 return sframe_get_fre_offset (fre, SFRAME_FRE_RA_OFFSET_IDX, errp);
733 /* Get whether the RA is mangled. */
735 bool
736 sframe_fre_get_ra_mangled_p (sframe_decoder_ctx *dctx ATTRIBUTE_UNUSED,
737 sframe_frame_row_entry *fre, int *errp)
739 if (fre == NULL || !sframe_fre_sanity_check_p (fre))
740 return sframe_set_errno (errp, SFRAME_ERR_FRE_INVAL);
742 return sframe_get_fre_ra_mangled_p (fre->fre_info);
745 static int
746 sframe_frame_row_entry_copy (sframe_frame_row_entry *dst,
747 sframe_frame_row_entry *src)
749 int err = 0;
751 if (dst == NULL || src == NULL)
752 return sframe_set_errno (&err, SFRAME_ERR_INVAL);
754 memcpy (dst, src, sizeof (sframe_frame_row_entry));
755 return 0;
758 /* Decode the SFrame FRE start address offset value from FRE_BUF in on-disk
759 binary format, given the FRE_TYPE. Updates the FRE_START_ADDR.
761 Returns 0 on success, SFRAME_ERR otherwise. */
763 static int
764 sframe_decode_fre_start_address (const char *fre_buf,
765 uint32_t *fre_start_addr,
766 uint32_t fre_type)
768 uint32_t saddr = 0;
769 int err = 0;
770 size_t addr_size = 0;
772 addr_size = sframe_fre_start_addr_size (fre_type);
774 if (fre_type == SFRAME_FRE_TYPE_ADDR1)
776 uint8_t *uc = (uint8_t *)fre_buf;
777 saddr = (uint32_t)*uc;
779 else if (fre_type == SFRAME_FRE_TYPE_ADDR2)
781 uint16_t *ust = (uint16_t *)fre_buf;
782 /* SFrame is an unaligned on-disk format. Using memcpy helps avoid the
783 use of undesirable unaligned loads. See PR libsframe/29856. */
784 uint16_t tmp = 0;
785 memcpy (&tmp, ust, addr_size);
786 saddr = (uint32_t)tmp;
788 else if (fre_type == SFRAME_FRE_TYPE_ADDR4)
790 uint32_t *uit = (uint32_t *)fre_buf;
791 uint32_t tmp = 0;
792 memcpy (&tmp, uit, addr_size);
793 saddr = (uint32_t)tmp;
795 else
796 return sframe_set_errno (&err, SFRAME_ERR_INVAL);
798 *fre_start_addr = saddr;
799 return 0;
802 /* Decode a frame row entry FRE which starts at location FRE_BUF. The function
803 updates ESZ to the size of the FRE as stored in the binary format.
805 This function works closely with the SFrame binary format.
807 Returns SFRAME_ERR if failure. */
809 static int
810 sframe_decode_fre (const char *fre_buf, sframe_frame_row_entry *fre,
811 uint32_t fre_type, size_t *esz)
813 int err = 0;
814 const char *stack_offsets = NULL;
815 size_t stack_offsets_sz;
816 size_t addr_size;
817 size_t fre_size;
819 if (fre_buf == NULL || fre == NULL || esz == NULL)
820 return sframe_set_errno (&err, SFRAME_ERR_INVAL);
822 /* Copy over the FRE start address. */
823 sframe_decode_fre_start_address (fre_buf, &fre->fre_start_addr, fre_type);
825 addr_size = sframe_fre_start_addr_size (fre_type);
826 fre->fre_info = *(uint8_t *)(fre_buf + addr_size);
827 /* Sanity check as the API works closely with the binary format. */
828 sframe_assert (sizeof (fre->fre_info) == sizeof (uint8_t));
830 /* Cleanup the space for fre_offsets first, then copy over the valid
831 bytes. */
832 memset (fre->fre_offsets, 0, MAX_OFFSET_BYTES);
833 /* Get offsets size. */
834 stack_offsets_sz = sframe_fre_offset_bytes_size (fre->fre_info);
835 stack_offsets = fre_buf + addr_size + sizeof (fre->fre_info);
836 memcpy (fre->fre_offsets, stack_offsets, stack_offsets_sz);
838 /* The FRE has been decoded. Use it to perform one last sanity check. */
839 fre_size = sframe_fre_entry_size (fre, fre_type);
840 sframe_assert (fre_size == (addr_size + sizeof (fre->fre_info)
841 + stack_offsets_sz));
842 *esz = fre_size;
844 return 0;
847 /* Decode the specified SFrame buffer CF_BUF of size CF_SIZE and return the
848 new SFrame decoder context.
850 Sets ERRP for the caller if any error. Frees up the allocated memory in
851 case of error. */
853 sframe_decoder_ctx *
854 sframe_decode (const char *sf_buf, size_t sf_size, int *errp)
856 const sframe_preamble *sfp;
857 size_t hdrsz;
858 sframe_header *sfheaderp;
859 sframe_decoder_ctx *dctx;
860 char *frame_buf;
861 char *tempbuf = NULL;
863 int fidx_size;
864 uint32_t fre_bytes;
865 int foreign_endian = 0;
867 sframe_init_debug ();
869 if ((sf_buf == NULL) || (!sf_size))
870 return sframe_ret_set_errno (errp, SFRAME_ERR_INVAL);
871 else if (sf_size < sizeof (sframe_header))
872 return sframe_ret_set_errno (errp, SFRAME_ERR_BUF_INVAL);
874 sfp = (const sframe_preamble *) sf_buf;
876 debug_printf ("sframe_decode: magic=0x%x version=%u flags=%u\n",
877 sfp->sfp_magic, sfp->sfp_version, sfp->sfp_flags);
879 /* Check for foreign endianness. */
880 if (sfp->sfp_magic != SFRAME_MAGIC)
882 if (sfp->sfp_magic == bswap_16 (SFRAME_MAGIC))
883 foreign_endian = 1;
884 else
885 return sframe_ret_set_errno (errp, SFRAME_ERR_BUF_INVAL);
888 /* Initialize a new decoder context. */
889 if ((dctx = malloc (sizeof (sframe_decoder_ctx))) == NULL)
890 return sframe_ret_set_errno (errp, SFRAME_ERR_NOMEM);
891 memset (dctx, 0, sizeof (sframe_decoder_ctx));
893 if (foreign_endian)
895 /* Allocate a new buffer and initialize it. */
896 tempbuf = (char *) malloc (sf_size * sizeof (char));
897 if (tempbuf == NULL)
898 return sframe_ret_set_errno (errp, SFRAME_ERR_NOMEM);
899 memcpy (tempbuf, sf_buf, sf_size);
901 /* Flip the header. */
902 sframe_header *ihp = (sframe_header *) tempbuf;
903 flip_header (ihp);
904 /* Flip the rest of the SFrame section data buffer. */
905 if (flip_sframe (tempbuf, sf_size, 0))
907 free (tempbuf);
908 return sframe_ret_set_errno (errp, SFRAME_ERR_BUF_INVAL);
910 frame_buf = tempbuf;
911 /* This buffer is malloc'd when endian flipping the contents of the input
912 buffer are needed. Keep a reference to it so it can be free'd up
913 later in sframe_decoder_free (). */
914 dctx->sfd_buf = tempbuf;
916 else
917 frame_buf = (char *)sf_buf;
919 /* Handle the SFrame header. */
920 dctx->sfd_header = *(sframe_header *) frame_buf;
921 /* Validate the contents of SFrame header. */
922 sfheaderp = &dctx->sfd_header;
923 if (!sframe_header_sanity_check_p (sfheaderp))
925 sframe_ret_set_errno (errp, SFRAME_ERR_NOMEM);
926 goto decode_fail_free;
928 hdrsz = sframe_get_hdr_size (sfheaderp);
929 frame_buf += hdrsz;
931 /* Handle the SFrame Function Descriptor Entry section. */
932 fidx_size
933 = sfheaderp->sfh_num_fdes * sizeof (sframe_func_desc_entry);
934 dctx->sfd_funcdesc = malloc (fidx_size);
935 if (dctx->sfd_funcdesc == NULL)
937 sframe_ret_set_errno (errp, SFRAME_ERR_NOMEM);
938 goto decode_fail_free;
940 memcpy (dctx->sfd_funcdesc, frame_buf, fidx_size);
942 debug_printf ("%u total fidx size\n", fidx_size);
944 frame_buf += (fidx_size);
946 /* Handle the SFrame Frame Row Entry section. */
947 dctx->sfd_fres = (char *) malloc (sfheaderp->sfh_fre_len);
948 if (dctx->sfd_fres == NULL)
950 sframe_ret_set_errno (errp, SFRAME_ERR_NOMEM);
951 goto decode_fail_free;
953 memcpy (dctx->sfd_fres, frame_buf, sfheaderp->sfh_fre_len);
955 fre_bytes = sfheaderp->sfh_fre_len;
956 dctx->sfd_fre_nbytes = fre_bytes;
958 debug_printf ("%u total fre bytes\n", fre_bytes);
960 return dctx;
962 decode_fail_free:
963 if (foreign_endian && tempbuf != NULL)
964 free (tempbuf);
965 sframe_decoder_free (&dctx);
966 dctx = NULL;
967 return dctx;
970 /* Get the size of the SFrame header from the decoder context CTX. */
972 unsigned int
973 sframe_decoder_get_hdr_size (sframe_decoder_ctx *ctx)
975 sframe_header *dhp;
976 dhp = sframe_decoder_get_header (ctx);
977 return sframe_get_hdr_size (dhp);
980 /* Get the SFrame's abi/arch info given the decoder context DCTX. */
982 uint8_t
983 sframe_decoder_get_abi_arch (sframe_decoder_ctx *dctx)
985 sframe_header *sframe_header;
986 sframe_header = sframe_decoder_get_header (dctx);
987 return sframe_header->sfh_abi_arch;
990 /* Get the format version from the SFrame decoder context DCTX. */
992 uint8_t
993 sframe_decoder_get_version (sframe_decoder_ctx *dctx)
995 sframe_header *dhp;
996 dhp = sframe_decoder_get_header (dctx);
997 return dhp->sfh_preamble.sfp_version;
1000 /* Get the SFrame's fixed FP offset given the decoder context CTX. */
1001 int8_t
1002 sframe_decoder_get_fixed_fp_offset (sframe_decoder_ctx *ctx)
1004 sframe_header *dhp;
1005 dhp = sframe_decoder_get_header (ctx);
1006 return dhp->sfh_cfa_fixed_fp_offset;
1009 /* Get the SFrame's fixed RA offset given the decoder context CTX. */
1010 int8_t
1011 sframe_decoder_get_fixed_ra_offset (sframe_decoder_ctx *ctx)
1013 sframe_header *dhp;
1014 dhp = sframe_decoder_get_header (ctx);
1015 return dhp->sfh_cfa_fixed_ra_offset;
1018 /* Find the function descriptor entry which contains the specified address
1019 ADDR.
1020 This function is deprecated and will be removed from libsframe.so.2. */
1022 void *
1023 sframe_get_funcdesc_with_addr (sframe_decoder_ctx *ctx __attribute__ ((unused)),
1024 int32_t addr __attribute__ ((unused)),
1025 int *errp)
1027 return sframe_ret_set_errno (errp, SFRAME_ERR_INVAL);
1030 /* Find the function descriptor entry starting which contains the specified
1031 address ADDR. */
1033 static sframe_func_desc_entry *
1034 sframe_get_funcdesc_with_addr_internal (sframe_decoder_ctx *ctx, int32_t addr,
1035 int *errp)
1037 sframe_header *dhp;
1038 sframe_func_desc_entry *fdp;
1039 int low, high, cnt;
1041 if (ctx == NULL)
1042 return sframe_ret_set_errno (errp, SFRAME_ERR_INVAL);
1044 dhp = sframe_decoder_get_header (ctx);
1046 if (dhp == NULL || dhp->sfh_num_fdes == 0 || ctx->sfd_funcdesc == NULL)
1047 return sframe_ret_set_errno (errp, SFRAME_ERR_DCTX_INVAL);
1048 /* If the FDE sub-section is not sorted on PCs, skip the lookup because
1049 binary search cannot be used. */
1050 if ((dhp->sfh_preamble.sfp_flags & SFRAME_F_FDE_SORTED) == 0)
1051 return sframe_ret_set_errno (errp, SFRAME_ERR_FDE_NOTSORTED);
1053 /* Do the binary search. */
1054 fdp = (sframe_func_desc_entry *) ctx->sfd_funcdesc;
1055 low = 0;
1056 high = dhp->sfh_num_fdes;
1057 cnt = high;
1058 while (low <= high)
1060 int mid = low + (high - low) / 2;
1062 if (fdp[mid].sfde_func_start_address == addr)
1063 return fdp + mid;
1065 if (fdp[mid].sfde_func_start_address < addr)
1067 if (mid == (cnt - 1)) /* Check if it's the last one. */
1068 return fdp + (cnt - 1);
1069 else if (fdp[mid+1].sfde_func_start_address > addr)
1070 return fdp + mid;
1071 low = mid + 1;
1073 else
1074 high = mid - 1;
1077 return sframe_ret_set_errno (errp, SFRAME_ERR_FDE_NOTFOUND);
1080 /* Get the end IP offset for the FRE at index i in the FDEP. The buffer FRES
1081 is the starting location for the FRE. */
1083 static uint32_t
1084 sframe_fre_get_end_ip_offset (sframe_func_desc_entry *fdep, unsigned int i,
1085 const char *fres)
1087 uint32_t end_ip_offset;
1088 uint32_t fre_type;
1090 fre_type = sframe_get_fre_type (fdep);
1092 /* Get the start address of the next FRE in sequence. */
1093 if (i < fdep->sfde_func_num_fres - 1)
1095 sframe_decode_fre_start_address (fres, &end_ip_offset, fre_type);
1096 end_ip_offset -= 1;
1098 else
1099 /* The end IP offset for the FRE needs to be deduced from the function
1100 size. */
1101 end_ip_offset = fdep->sfde_func_size - 1;
1103 return end_ip_offset;
1106 /* Find the SFrame Row Entry which contains the PC. Returns
1107 SFRAME_ERR if failure. */
1110 sframe_find_fre (sframe_decoder_ctx *ctx, int32_t pc,
1111 sframe_frame_row_entry *frep)
1113 sframe_frame_row_entry cur_fre;
1114 sframe_func_desc_entry *fdep;
1115 uint32_t fre_type, fde_type, i;
1116 int32_t start_ip_offset;
1117 int32_t func_start_addr;
1118 int32_t end_ip_offset;
1119 const char *fres;
1120 size_t size = 0;
1121 int err = 0;
1122 bool mask_p;
1124 if ((ctx == NULL) || (frep == NULL))
1125 return sframe_set_errno (&err, SFRAME_ERR_INVAL);
1127 /* Find the FDE which contains the PC, then scan its fre entries. */
1128 fdep = sframe_get_funcdesc_with_addr_internal (ctx, pc, &err);
1129 if (fdep == NULL || ctx->sfd_fres == NULL)
1130 return sframe_set_errno (&err, SFRAME_ERR_DCTX_INVAL);
1132 fre_type = sframe_get_fre_type (fdep);
1133 fde_type = sframe_get_fde_type (fdep);
1134 mask_p = (fde_type == SFRAME_FDE_TYPE_PCMASK);
1136 fres = ctx->sfd_fres + fdep->sfde_func_start_fre_off;
1137 func_start_addr = fdep->sfde_func_start_address;
1139 for (i = 0; i < fdep->sfde_func_num_fres; i++)
1141 err = sframe_decode_fre (fres, &cur_fre, fre_type, &size);
1142 if (err)
1143 return sframe_set_errno (&err, SFRAME_ERR_FRE_INVAL);
1145 start_ip_offset = cur_fre.fre_start_addr;
1146 end_ip_offset = sframe_fre_get_end_ip_offset (fdep, i, fres + size);
1148 /* First FRE's start_ip must be more than pc for regular SFrame FDEs. */
1149 if (i == 0 && !mask_p && (start_ip_offset + func_start_addr) > pc)
1150 return sframe_set_errno (&err, SFRAME_ERR_FRE_INVAL);
1152 if (sframe_fre_check_range_p (fdep, start_ip_offset, end_ip_offset, pc))
1154 sframe_frame_row_entry_copy (frep, &cur_fre);
1155 return 0;
1157 fres += size;
1159 return sframe_set_errno (&err, SFRAME_ERR_FDE_INVAL);
1162 /* Return the number of function descriptor entries in the SFrame decoder
1163 DCTX. */
1165 uint32_t
1166 sframe_decoder_get_num_fidx (sframe_decoder_ctx *ctx)
1168 uint32_t num_fdes = 0;
1169 sframe_header *dhp = NULL;
1170 dhp = sframe_decoder_get_header (ctx);
1171 if (dhp)
1172 num_fdes = dhp->sfh_num_fdes;
1173 return num_fdes;
1176 /* Get the data (NUM_FRES, FUNC_START_ADDRESS) from the function
1177 descriptor entry at index I'th in the decoder CTX. If failed,
1178 return error code. */
1179 /* FIXME - consolidate the args and return a
1180 sframe_func_desc_index_elem rather? */
1183 sframe_decoder_get_funcdesc (sframe_decoder_ctx *ctx,
1184 unsigned int i,
1185 uint32_t *num_fres,
1186 uint32_t *func_size,
1187 int32_t *func_start_address,
1188 unsigned char *func_info)
1190 sframe_func_desc_entry *fdp;
1191 int err = 0;
1193 if (ctx == NULL || func_start_address == NULL || num_fres == NULL
1194 || func_size == NULL)
1195 return sframe_set_errno (&err, SFRAME_ERR_INVAL);
1197 fdp = sframe_decoder_get_funcdesc_at_index (ctx, i);
1199 if (fdp == NULL)
1200 return sframe_set_errno (&err, SFRAME_ERR_FDE_NOTFOUND);
1202 *num_fres = fdp->sfde_func_num_fres;
1203 *func_start_address = fdp->sfde_func_start_address;
1204 *func_size = fdp->sfde_func_size;
1205 *func_info = fdp->sfde_func_info;
1207 return 0;
1211 sframe_decoder_get_funcdesc_v2 (sframe_decoder_ctx *dctx,
1212 unsigned int i,
1213 uint32_t *num_fres,
1214 uint32_t *func_size,
1215 int32_t *func_start_address,
1216 unsigned char *func_info,
1217 uint8_t *rep_block_size)
1219 sframe_func_desc_entry *fdp;
1220 int err = 0;
1222 if (dctx == NULL || func_start_address == NULL
1223 || num_fres == NULL || func_size == NULL
1224 || sframe_decoder_get_version (dctx) == SFRAME_VERSION_1)
1225 return sframe_set_errno (&err, SFRAME_ERR_INVAL);
1227 fdp = sframe_decoder_get_funcdesc_at_index (dctx, i);
1229 if (fdp == NULL)
1230 return sframe_set_errno (&err, SFRAME_ERR_FDE_NOTFOUND);
1232 *num_fres = fdp->sfde_func_num_fres;
1233 *func_start_address = fdp->sfde_func_start_address;
1234 *func_size = fdp->sfde_func_size;
1235 *func_info = fdp->sfde_func_info;
1236 *rep_block_size = fdp->sfde_func_rep_size;
1238 return 0;
1240 /* Get the FRE_IDX'th FRE of the function at FUNC_IDX'th function
1241 descriptor entry in the SFrame decoder CTX. Returns error code as
1242 applicable. */
1245 sframe_decoder_get_fre (sframe_decoder_ctx *ctx,
1246 unsigned int func_idx,
1247 unsigned int fre_idx,
1248 sframe_frame_row_entry *fre)
1250 sframe_func_desc_entry *fdep;
1251 sframe_frame_row_entry ifre;
1252 const char *fres;
1253 uint32_t i;
1254 uint32_t fre_type;
1255 size_t esz = 0;
1256 int err = 0;
1258 if (ctx == NULL || fre == NULL)
1259 return sframe_set_errno (&err, SFRAME_ERR_INVAL);
1261 /* Get function descriptor entry at index func_idx. */
1262 fdep = sframe_decoder_get_funcdesc_at_index (ctx, func_idx);
1264 if (fdep == NULL)
1265 return sframe_set_errno (&err, SFRAME_ERR_FDE_NOTFOUND);
1267 fre_type = sframe_get_fre_type (fdep);
1268 /* Now scan the FRE entries. */
1269 fres = ctx->sfd_fres + fdep->sfde_func_start_fre_off;
1270 for (i = 0; i < fdep->sfde_func_num_fres; i++)
1272 /* Decode the FRE at the current position. Return it if valid. */
1273 err = sframe_decode_fre (fres, &ifre, fre_type, &esz);
1274 if (i == fre_idx)
1276 if (!sframe_fre_sanity_check_p (&ifre))
1277 return sframe_set_errno (&err, SFRAME_ERR_FRE_INVAL);
1279 sframe_frame_row_entry_copy (fre, &ifre);
1281 if (fdep->sfde_func_size)
1282 sframe_assert (fre->fre_start_addr < fdep->sfde_func_size);
1283 else
1284 /* A SFrame FDE with func size equal to zero is possible. */
1285 sframe_assert (fre->fre_start_addr == fdep->sfde_func_size);
1287 return 0;
1289 /* Next FRE. */
1290 fres += esz;
1293 return sframe_set_errno (&err, SFRAME_ERR_FDE_NOTFOUND);
1297 /* SFrame Encoder. */
1299 /* Get a reference to the ENCODER's SFrame header. */
1301 static sframe_header *
1302 sframe_encoder_get_header (sframe_encoder_ctx *encoder)
1304 sframe_header *hp = NULL;
1305 if (encoder)
1306 hp = &encoder->sfe_header;
1307 return hp;
1310 static sframe_func_desc_entry *
1311 sframe_encoder_get_funcdesc_at_index (sframe_encoder_ctx *encoder,
1312 uint32_t func_idx)
1314 sframe_func_desc_entry *fde = NULL;
1315 if (func_idx < sframe_encoder_get_num_fidx (encoder))
1317 sf_fde_tbl *func_tbl = encoder->sfe_funcdesc;
1318 fde = func_tbl->entry + func_idx;
1320 return fde;
1323 /* Create an encoder context with the given SFrame format version VER, FLAGS
1324 and ABI information. Uses the ABI specific FIXED_FP_OFFSET and
1325 FIXED_RA_OFFSET values as provided. Sets errp if failure. */
1327 sframe_encoder_ctx *
1328 sframe_encode (uint8_t ver, uint8_t flags, uint8_t abi_arch,
1329 int8_t fixed_fp_offset, int8_t fixed_ra_offset, int *errp)
1331 sframe_header *hp;
1332 sframe_encoder_ctx *encoder;
1334 if (ver != SFRAME_VERSION)
1335 return sframe_ret_set_errno (errp, SFRAME_ERR_VERSION_INVAL);
1337 if ((encoder = malloc (sizeof (sframe_encoder_ctx))) == NULL)
1338 return sframe_ret_set_errno (errp, SFRAME_ERR_NOMEM);
1340 memset (encoder, 0, sizeof (sframe_encoder_ctx));
1342 /* Get the SFrame header and update it. */
1343 hp = sframe_encoder_get_header (encoder);
1344 hp->sfh_preamble.sfp_version = ver;
1345 hp->sfh_preamble.sfp_magic = SFRAME_MAGIC;
1346 hp->sfh_preamble.sfp_flags = flags;
1348 hp->sfh_abi_arch = abi_arch;
1349 hp->sfh_cfa_fixed_fp_offset = fixed_fp_offset;
1350 hp->sfh_cfa_fixed_ra_offset = fixed_ra_offset;
1352 return encoder;
1355 /* Free the encoder context. */
1357 void
1358 sframe_encoder_free (sframe_encoder_ctx **encoder)
1360 if (encoder != NULL)
1362 sframe_encoder_ctx *ectx = *encoder;
1363 if (ectx == NULL)
1364 return;
1366 if (ectx->sfe_funcdesc != NULL)
1368 free (ectx->sfe_funcdesc);
1369 ectx->sfe_funcdesc = NULL;
1371 if (ectx->sfe_fres != NULL)
1373 free (ectx->sfe_fres);
1374 ectx->sfe_fres = NULL;
1376 if (ectx->sfe_data != NULL)
1378 free (ectx->sfe_data);
1379 ectx->sfe_data = NULL;
1382 free (*encoder);
1383 *encoder = NULL;
1387 /* Get the size of the SFrame header from the encoder ctx ENCODER. */
1389 unsigned int
1390 sframe_encoder_get_hdr_size (sframe_encoder_ctx *encoder)
1392 sframe_header *ehp;
1393 ehp = sframe_encoder_get_header (encoder);
1394 return sframe_get_hdr_size (ehp);
1397 /* Get the abi/arch info from the SFrame encoder context ENCODER. */
1399 uint8_t
1400 sframe_encoder_get_abi_arch (sframe_encoder_ctx *encoder)
1402 uint8_t abi_arch = 0;
1403 sframe_header *ehp;
1404 ehp = sframe_encoder_get_header (encoder);
1405 if (ehp)
1406 abi_arch = ehp->sfh_abi_arch;
1407 return abi_arch;
1410 /* Get the format version from the SFrame encoder context ENCODER. */
1412 uint8_t
1413 sframe_encoder_get_version (sframe_encoder_ctx *encoder)
1415 sframe_header *ehp;
1416 ehp = sframe_encoder_get_header (encoder);
1417 return ehp->sfh_preamble.sfp_version;
1420 /* Return the number of function descriptor entries in the SFrame encoder
1421 ENCODER. */
1423 uint32_t
1424 sframe_encoder_get_num_fidx (sframe_encoder_ctx *encoder)
1426 uint32_t num_fdes = 0;
1427 sframe_header *ehp = NULL;
1428 ehp = sframe_encoder_get_header (encoder);
1429 if (ehp)
1430 num_fdes = ehp->sfh_num_fdes;
1431 return num_fdes;
1434 /* Add an FRE to function at FUNC_IDX'th function descriptor entry in
1435 the encoder context. */
1438 sframe_encoder_add_fre (sframe_encoder_ctx *encoder,
1439 unsigned int func_idx,
1440 sframe_frame_row_entry *frep)
1442 sframe_header *ehp;
1443 sframe_func_desc_entry *fdep;
1444 sframe_frame_row_entry *ectx_frep;
1445 size_t offsets_sz, esz;
1446 uint32_t fre_type;
1447 size_t fre_tbl_sz;
1448 int err = 0;
1450 if (encoder == NULL || frep == NULL)
1451 return sframe_set_errno (&err, SFRAME_ERR_INVAL);
1452 if (!sframe_fre_sanity_check_p (frep))
1453 return sframe_set_errno (&err, SFRAME_ERR_FRE_INVAL);
1455 /* Use func_idx to gather the function descriptor entry. */
1456 fdep = sframe_encoder_get_funcdesc_at_index (encoder, func_idx);
1458 if (fdep == NULL)
1459 return sframe_set_errno (&err, SFRAME_ERR_FDE_NOTFOUND);
1461 fre_type = sframe_get_fre_type (fdep);
1462 sf_fre_tbl *fre_tbl = encoder->sfe_fres;
1464 if (fre_tbl == NULL)
1466 fre_tbl_sz = (sizeof (sf_fre_tbl)
1467 + (number_of_entries * sizeof (sframe_frame_row_entry)));
1468 fre_tbl = malloc (fre_tbl_sz);
1470 if (fre_tbl == NULL)
1472 sframe_set_errno (&err, SFRAME_ERR_NOMEM);
1473 goto bad; /* OOM. */
1475 memset (fre_tbl, 0, fre_tbl_sz);
1476 fre_tbl->alloced = number_of_entries;
1478 else if (fre_tbl->count == fre_tbl->alloced)
1480 fre_tbl_sz = (sizeof (sf_fre_tbl)
1481 + ((fre_tbl->alloced + number_of_entries)
1482 * sizeof (sframe_frame_row_entry)));
1483 fre_tbl = realloc (fre_tbl, fre_tbl_sz);
1484 if (fre_tbl == NULL)
1486 sframe_set_errno (&err, SFRAME_ERR_NOMEM);
1487 goto bad; /* OOM. */
1490 memset (&fre_tbl->entry[fre_tbl->alloced], 0,
1491 number_of_entries * sizeof (sframe_frame_row_entry));
1492 fre_tbl->alloced += number_of_entries;
1495 ectx_frep = &fre_tbl->entry[fre_tbl->count];
1496 ectx_frep->fre_start_addr
1497 = frep->fre_start_addr;
1498 ectx_frep->fre_info = frep->fre_info;
1500 if (fdep->sfde_func_size)
1501 sframe_assert (frep->fre_start_addr < fdep->sfde_func_size);
1502 else
1503 /* A SFrame FDE with func size equal to zero is possible. */
1504 sframe_assert (frep->fre_start_addr == fdep->sfde_func_size);
1506 /* frep has already been sanity check'd. Get offsets size. */
1507 offsets_sz = sframe_fre_offset_bytes_size (frep->fre_info);
1508 memcpy (&ectx_frep->fre_offsets, &frep->fre_offsets, offsets_sz);
1510 esz = sframe_fre_entry_size (frep, fre_type);
1511 fre_tbl->count++;
1513 encoder->sfe_fres = fre_tbl;
1514 encoder->sfe_fre_nbytes += esz;
1516 ehp = sframe_encoder_get_header (encoder);
1517 ehp->sfh_num_fres = fre_tbl->count;
1519 /* Update the value of the number of FREs for the function. */
1520 fdep->sfde_func_num_fres++;
1522 return 0;
1524 bad:
1525 if (fre_tbl != NULL)
1526 free (fre_tbl);
1527 encoder->sfe_fres = NULL;
1528 encoder->sfe_fre_nbytes = 0;
1529 return -1;
1532 /* Add a new function descriptor entry with START_ADDR, FUNC_SIZE and NUM_FRES
1533 to the encoder. */
1536 sframe_encoder_add_funcdesc (sframe_encoder_ctx *encoder,
1537 int32_t start_addr,
1538 uint32_t func_size,
1539 unsigned char func_info,
1540 uint32_t num_fres __attribute__ ((unused)))
1542 sframe_header *ehp;
1543 sf_fde_tbl *fd_info;
1544 size_t fd_tbl_sz;
1545 int err = 0;
1547 /* FIXME book-keep num_fres for error checking. */
1548 if (encoder == NULL)
1549 return sframe_set_errno (&err, SFRAME_ERR_INVAL);
1551 fd_info = encoder->sfe_funcdesc;
1552 ehp = sframe_encoder_get_header (encoder);
1554 if (fd_info == NULL)
1556 fd_tbl_sz = (sizeof (sf_fde_tbl)
1557 + (number_of_entries * sizeof (sframe_func_desc_entry)));
1558 fd_info = malloc (fd_tbl_sz);
1559 if (fd_info == NULL)
1561 sframe_set_errno (&err, SFRAME_ERR_NOMEM);
1562 goto bad; /* OOM. */
1564 memset (fd_info, 0, fd_tbl_sz);
1565 fd_info->alloced = number_of_entries;
1567 else if (fd_info->count == fd_info->alloced)
1569 fd_tbl_sz = (sizeof (sf_fde_tbl)
1570 + ((fd_info->alloced + number_of_entries)
1571 * sizeof (sframe_func_desc_entry)));
1572 fd_info = realloc (fd_info, fd_tbl_sz);
1573 if (fd_info == NULL)
1575 sframe_set_errno (&err, SFRAME_ERR_NOMEM);
1576 goto bad; /* OOM. */
1579 memset (&fd_info->entry[fd_info->alloced], 0,
1580 number_of_entries * sizeof (sframe_func_desc_entry));
1581 fd_info->alloced += number_of_entries;
1584 fd_info->entry[fd_info->count].sfde_func_start_address = start_addr;
1585 /* Num FREs is updated as FREs are added for the function later via
1586 sframe_encoder_add_fre. */
1587 fd_info->entry[fd_info->count].sfde_func_size = func_size;
1588 fd_info->entry[fd_info->count].sfde_func_start_fre_off
1589 = encoder->sfe_fre_nbytes;
1590 #if 0
1591 // Linker optimization test code cleanup later ibhagat TODO FIXME
1592 uint32_t fre_type = sframe_calc_fre_type (func_size);
1594 fd_info->entry[fd_info->count].sfde_func_info
1595 = sframe_fde_func_info (fre_type);
1596 #endif
1597 fd_info->entry[fd_info->count].sfde_func_info = func_info;
1598 fd_info->count++;
1599 encoder->sfe_funcdesc = fd_info;
1600 ehp->sfh_num_fdes++;
1601 return 0;
1603 bad:
1604 if (fd_info != NULL)
1605 free (fd_info);
1606 encoder->sfe_funcdesc = NULL;
1607 ehp->sfh_num_fdes = 0;
1608 return -1;
1611 /* Add a new function descriptor entry with START_ADDR, FUNC_SIZE, FUNC_INFO
1612 and REP_BLOCK_SIZE to the encoder.
1614 This API is valid only for SFrame format version 2. */
1617 sframe_encoder_add_funcdesc_v2 (sframe_encoder_ctx *encoder,
1618 int32_t start_addr,
1619 uint32_t func_size,
1620 unsigned char func_info,
1621 uint8_t rep_block_size,
1622 uint32_t num_fres __attribute__ ((unused)))
1624 sf_fde_tbl *fd_info;
1625 int err;
1627 if (encoder == NULL
1628 || sframe_encoder_get_version (encoder) == SFRAME_VERSION_1)
1629 return sframe_set_errno (&err, SFRAME_ERR_INVAL);
1631 err = sframe_encoder_add_funcdesc (encoder, start_addr, func_size, func_info,
1632 num_fres);
1633 if (err)
1634 return SFRAME_ERR;
1636 fd_info = encoder->sfe_funcdesc;
1637 fd_info->entry[fd_info->count-1].sfde_func_rep_size = rep_block_size;
1639 return 0;
1642 static int
1643 sframe_sort_funcdesc (sframe_encoder_ctx *encoder)
1645 sframe_header *ehp;
1647 ehp = sframe_encoder_get_header (encoder);
1648 /* Sort and write out the FDE table. */
1649 sf_fde_tbl *fd_info = encoder->sfe_funcdesc;
1650 if (fd_info)
1652 qsort (fd_info->entry, fd_info->count,
1653 sizeof (sframe_func_desc_entry), fde_func);
1654 /* Update preamble's flags. */
1655 ehp->sfh_preamble.sfp_flags |= SFRAME_F_FDE_SORTED;
1657 return 0;
1660 /* Write the SFrame FRE start address from the in-memory FRE_START_ADDR
1661 to the buffer CONTENTS (on-disk format), given the FRE_TYPE and
1662 FRE_START_ADDR_SZ. */
1664 static int
1665 sframe_encoder_write_fre_start_addr (char *contents,
1666 uint32_t fre_start_addr,
1667 uint32_t fre_type,
1668 size_t fre_start_addr_sz)
1670 int err = 0;
1672 if (fre_type == SFRAME_FRE_TYPE_ADDR1)
1674 uint8_t uc = fre_start_addr;
1675 memcpy (contents, &uc, fre_start_addr_sz);
1677 else if (fre_type == SFRAME_FRE_TYPE_ADDR2)
1679 uint16_t ust = fre_start_addr;
1680 memcpy (contents, &ust, fre_start_addr_sz);
1682 else if (fre_type == SFRAME_FRE_TYPE_ADDR4)
1684 uint32_t uit = fre_start_addr;
1685 memcpy (contents, &uit, fre_start_addr_sz);
1687 else
1688 return sframe_set_errno (&err, SFRAME_ERR_INVAL);
1690 return 0;
1693 /* Write a frame row entry pointed to by FREP into the buffer CONTENTS. The
1694 size in bytes written out are updated in ESZ.
1696 This function works closely with the SFrame binary format.
1698 Returns SFRAME_ERR if failure. */
1700 static int
1701 sframe_encoder_write_fre (char *contents, sframe_frame_row_entry *frep,
1702 uint32_t fre_type, size_t *esz)
1704 size_t fre_sz;
1705 size_t fre_start_addr_sz;
1706 size_t fre_stack_offsets_sz;
1707 int err = 0;
1709 if (!sframe_fre_sanity_check_p (frep))
1710 return sframe_set_errno (&err, SFRAME_ERR_FRE_INVAL);
1712 fre_start_addr_sz = sframe_fre_start_addr_size (fre_type);
1713 fre_stack_offsets_sz = sframe_fre_offset_bytes_size (frep->fre_info);
1715 /* The FRE start address must be encodable in the available number of
1716 bytes. */
1717 uint64_t bitmask = SFRAME_BITMASK_OF_SIZE (fre_start_addr_sz);
1718 sframe_assert ((uint64_t)frep->fre_start_addr <= bitmask);
1720 sframe_encoder_write_fre_start_addr (contents, frep->fre_start_addr,
1721 fre_type, fre_start_addr_sz);
1722 contents += fre_start_addr_sz;
1724 memcpy (contents, &frep->fre_info, sizeof (frep->fre_info));
1725 contents += sizeof (frep->fre_info);
1727 memcpy (contents, frep->fre_offsets, fre_stack_offsets_sz);
1728 contents+= fre_stack_offsets_sz;
1730 fre_sz = sframe_fre_entry_size (frep, fre_type);
1731 /* Sanity checking. */
1732 sframe_assert ((fre_start_addr_sz
1733 + sizeof (frep->fre_info)
1734 + fre_stack_offsets_sz) == fre_sz);
1736 *esz = fre_sz;
1738 return 0;
1741 /* Serialize the core contents of the SFrame section and write out to the
1742 output buffer held in the ENCODER. Return SFRAME_ERR if failure. */
1744 static int
1745 sframe_encoder_write_sframe (sframe_encoder_ctx *encoder)
1747 char *contents;
1748 size_t buf_size;
1749 size_t hdr_size;
1750 size_t all_fdes_size;
1751 size_t fre_size;
1752 size_t esz = 0;
1753 sframe_header *ehp;
1754 unsigned char flags;
1755 sf_fde_tbl *fd_info;
1756 sf_fre_tbl *fr_info;
1757 uint32_t i, num_fdes;
1758 uint32_t j, num_fres;
1759 sframe_func_desc_entry *fdep;
1760 sframe_frame_row_entry *frep;
1762 uint32_t fre_type;
1763 int err = 0;
1765 contents = encoder->sfe_data;
1766 buf_size = encoder->sfe_data_size;
1767 num_fdes = sframe_encoder_get_num_fidx (encoder);
1768 all_fdes_size = num_fdes * sizeof (sframe_func_desc_entry);
1769 ehp = sframe_encoder_get_header (encoder);
1770 hdr_size = sframe_get_hdr_size (ehp);
1772 fd_info = encoder->sfe_funcdesc;
1773 fr_info = encoder->sfe_fres;
1775 /* Sanity checks:
1776 - buffers must be malloc'd by the caller. */
1777 if ((contents == NULL) || (buf_size < hdr_size))
1778 return sframe_set_errno (&err, SFRAME_ERR_BUF_INVAL);
1779 if (fr_info == NULL)
1780 return sframe_set_errno (&err, SFRAME_ERR_FRE_INVAL);
1782 /* Write out the FRE table first.
1784 Recall that read/write of FREs needs information from the corresponding
1785 FDE; the latter stores the information about the FRE type record used for
1786 the function. Also note that sorting of FDEs does NOT impact the order
1787 in which FREs are stored in the SFrame's FRE sub-section. This means
1788 that writing out FREs after sorting of FDEs will need some additional
1789 book-keeping. At this time, we can afford to avoid it by writing out
1790 the FREs first to the output buffer. */
1791 fre_size = 0;
1792 uint32_t global = 0;
1793 uint32_t fre_index = 0;
1795 contents += hdr_size + all_fdes_size;
1796 for (i = 0; i < num_fdes; i++)
1798 fdep = &fd_info->entry[i];
1799 fre_type = sframe_get_fre_type (fdep);
1800 num_fres = fdep->sfde_func_num_fres;
1802 for (j = 0; j < num_fres; j++)
1804 fre_index = global + j;
1805 frep = &fr_info->entry[fre_index];
1807 sframe_encoder_write_fre (contents, frep, fre_type, &esz);
1808 contents += esz;
1809 fre_size += esz; /* For debugging only. */
1811 global += j;
1814 sframe_assert (fre_size == ehp->sfh_fre_len);
1815 sframe_assert (global == ehp->sfh_num_fres);
1816 sframe_assert ((size_t)(contents - encoder->sfe_data) == buf_size);
1818 /* Sort the FDE table */
1819 sframe_sort_funcdesc (encoder);
1821 /* Sanity checks:
1822 - the FDE section must have been sorted by now on the start address
1823 of each function. */
1824 flags = ehp->sfh_preamble.sfp_flags;
1825 if (!(flags & SFRAME_F_FDE_SORTED)
1826 || (fd_info == NULL))
1827 return sframe_set_errno (&err, SFRAME_ERR_FDE_INVAL);
1829 contents = encoder->sfe_data;
1830 /* Write out the SFrame header. The SFrame header in the encoder
1831 object has already been updated with correct offsets by the caller. */
1832 memcpy (contents, ehp, hdr_size);
1833 contents += hdr_size;
1835 /* Write out the FDE table sorted on funtion start address. */
1836 memcpy (contents, fd_info->entry, all_fdes_size);
1837 contents += all_fdes_size;
1839 return 0;
1842 /* Serialize the contents of the encoder and return the buffer. ENCODED_SIZE
1843 is updated to the size of the buffer. */
1845 char *
1846 sframe_encoder_write (sframe_encoder_ctx *encoder,
1847 size_t *encoded_size, int *errp)
1849 sframe_header *ehp;
1850 size_t hdrsize, fsz, fresz, bufsize;
1851 int foreign_endian;
1853 /* Initialize the encoded_size to zero. This makes it simpler to just
1854 return from the function in case of failure. Free'ing up of
1855 encoder->sfe_data is the responsibility of the caller. */
1856 *encoded_size = 0;
1858 if (encoder == NULL || encoded_size == NULL || errp == NULL)
1859 return sframe_ret_set_errno (errp, SFRAME_ERR_INVAL);
1861 ehp = sframe_encoder_get_header (encoder);
1862 hdrsize = sframe_get_hdr_size (ehp);
1863 fsz = sframe_encoder_get_num_fidx (encoder)
1864 * sizeof (sframe_func_desc_entry);
1865 fresz = encoder->sfe_fre_nbytes;
1867 /* The total size of buffer is the sum of header, SFrame Function Descriptor
1868 Entries section and the FRE section. */
1869 bufsize = hdrsize + fsz + fresz;
1870 encoder->sfe_data = (char *) malloc (bufsize);
1871 if (encoder->sfe_data == NULL)
1872 return sframe_ret_set_errno (errp, SFRAME_ERR_NOMEM);
1873 encoder->sfe_data_size = bufsize;
1875 /* Update the information in the SFrame header. */
1876 /* SFrame FDE section follows immediately after the header. */
1877 ehp->sfh_fdeoff = 0;
1878 /* SFrame FRE section follows immediately after the SFrame FDE section. */
1879 ehp->sfh_freoff = fsz;
1880 ehp->sfh_fre_len = fresz;
1882 foreign_endian = need_swapping (ehp->sfh_abi_arch);
1884 /* Write out the FDE Index and the FRE table in the sfe_data. */
1885 if (sframe_encoder_write_sframe (encoder))
1886 return sframe_ret_set_errno (errp, SFRAME_ERR_BUF_INVAL);
1888 /* Endian flip the contents if necessary. */
1889 if (foreign_endian)
1891 if (flip_sframe (encoder->sfe_data, bufsize, 1))
1892 return sframe_ret_set_errno (errp, SFRAME_ERR_BUF_INVAL);
1893 flip_header ((sframe_header*)encoder->sfe_data);
1896 *encoded_size = bufsize;
1897 return encoder->sfe_data;