1 /* sframe.c - SFrame decoder/encoder.
3 Copyright (C) 2022-2025 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/>. */
26 #include "sframe-impl.h"
33 sframe_func_desc_entry entry
[1];
40 sframe_frame_row_entry entry
[1];
43 #define _sf_printflike_(string_index,first_to_check) \
44 __attribute__ ((__format__ (__printf__, (string_index), (first_to_check))))
46 static void debug_printf (const char *, ...);
48 static int _sframe_debug
; /* Control for printing out debug info. */
49 static int number_of_entries
= 64;
52 sframe_init_debug (void)
58 _sframe_debug
= getenv ("SFRAME_DEBUG") != NULL
;
63 _sf_printflike_ (1, 2)
64 static void debug_printf (const char *format
, ...)
70 va_start (args
, format
);
71 vfprintf (stderr
, format
, args
);
76 /* Generate bitmask of given size in bytes. This is used for
77 some checks on the FRE start address.
78 SFRAME_FRE_TYPE_ADDR1 => 1 byte => [ bitmask = 0xff ]
79 SFRAME_FRE_TYPE_ADDR2 => 2 byte => [ bitmask = 0xffff ]
80 SFRAME_FRE_TYPE_ADDR4 => 4 byte => [ bitmask = 0xffffffff ]. */
81 #define SFRAME_BITMASK_OF_SIZE(size_in_bytes) \
82 (((uint64_t)1 << (size_in_bytes*8)) - 1)
84 /* Store the specified error code into errp if it is non-NULL.
88 sframe_set_errno (int *errp
, int error
)
95 /* Store the specified error code into errp if it is non-NULL.
99 sframe_ret_set_errno (int *errp
, int error
)
106 /* Get the SFrame header size. */
109 sframe_get_hdr_size (sframe_header
*sfh
)
111 return SFRAME_V1_HDR_SIZE (*sfh
);
114 /* Access functions for frame row entry data. */
117 sframe_fre_get_offset_count (uint8_t fre_info
)
119 return SFRAME_V1_FRE_OFFSET_COUNT (fre_info
);
123 sframe_fre_get_offset_size (uint8_t fre_info
)
125 return SFRAME_V1_FRE_OFFSET_SIZE (fre_info
);
129 sframe_get_fre_ra_mangled_p (uint8_t fre_info
)
131 return SFRAME_V1_FRE_MANGLED_RA_P (fre_info
);
134 /* Access functions for info from function descriptor entry. */
137 sframe_get_fre_type (sframe_func_desc_entry
*fdep
)
139 uint32_t fre_type
= 0;
141 fre_type
= SFRAME_V1_FUNC_FRE_TYPE (fdep
->sfde_func_info
);
146 sframe_get_fde_type (sframe_func_desc_entry
*fdep
)
148 uint32_t fde_type
= 0;
150 fde_type
= SFRAME_V1_FUNC_FDE_TYPE (fdep
->sfde_func_info
);
154 /* Check if flipping is needed, based on ENDIAN. */
157 need_swapping (int endian
)
160 char *c
= (char *)&ui
;
161 int is_little
= (int)*c
;
165 case SFRAME_ABI_AARCH64_ENDIAN_LITTLE
:
166 case SFRAME_ABI_AMD64_ENDIAN_LITTLE
:
168 case SFRAME_ABI_AARCH64_ENDIAN_BIG
:
177 /* Flip the endianness of the SFrame header. */
180 flip_header (sframe_header
*sfheader
)
182 swap_thing (sfheader
->sfh_preamble
.sfp_magic
);
183 swap_thing (sfheader
->sfh_preamble
.sfp_version
);
184 swap_thing (sfheader
->sfh_preamble
.sfp_flags
);
185 swap_thing (sfheader
->sfh_cfa_fixed_fp_offset
);
186 swap_thing (sfheader
->sfh_cfa_fixed_ra_offset
);
187 swap_thing (sfheader
->sfh_num_fdes
);
188 swap_thing (sfheader
->sfh_num_fres
);
189 swap_thing (sfheader
->sfh_fre_len
);
190 swap_thing (sfheader
->sfh_fdeoff
);
191 swap_thing (sfheader
->sfh_freoff
);
195 flip_fde (sframe_func_desc_entry
*fdep
)
197 swap_thing (fdep
->sfde_func_start_address
);
198 swap_thing (fdep
->sfde_func_size
);
199 swap_thing (fdep
->sfde_func_start_fre_off
);
200 swap_thing (fdep
->sfde_func_num_fres
);
203 /* Check if SFrame header has valid data. */
206 sframe_header_sanity_check_p (sframe_header
*hp
)
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
& ~SFRAME_V2_F_ALL_FLAGS
))
215 /* Check offsets are valid. */
216 if (hp
->sfh_fdeoff
> hp
->sfh_freoff
)
222 /* Flip the start address pointed to by FP. */
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
);
240 flip_fre_stack_offsets (char *offsets
, uint8_t offset_size
, uint8_t offset_cnt
)
244 if (offset_size
== SFRAME_FRE_OFFSET_2B
)
246 uint16_t *ust
= (uint16_t *)offsets
;
247 for (j
= offset_cnt
; j
> 0; ust
++, j
--)
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
--)
258 /* Get the FRE start address size, given the FRE_TYPE. */
261 sframe_fre_start_addr_size (uint32_t fre_type
)
263 size_t addr_size
= 0;
266 case SFRAME_FRE_TYPE_ADDR1
:
269 case SFRAME_FRE_TYPE_ADDR2
:
272 case SFRAME_FRE_TYPE_ADDR4
:
276 /* No other value is expected. */
283 /* Check if the FREP has valid data. */
286 sframe_fre_sanity_check_p (sframe_frame_row_entry
*frep
)
288 uint8_t offset_size
, offset_cnt
;
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
)
302 offset_cnt
= sframe_fre_get_offset_count (fre_info
);
303 if (offset_cnt
> MAX_NUM_STACK_OFFSETS
)
309 /* Get FRE_INFO's offset size in bytes. */
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));
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. */
333 sframe_fre_entry_size (sframe_frame_row_entry
*frep
, uint32_t fre_type
)
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
348 static sframe_func_desc_entry
*
349 sframe_decoder_get_funcdesc_at_index (sframe_decoder_ctx
*ctx
,
352 sframe_func_desc_entry
*fdep
;
356 num_fdes
= sframe_decoder_get_num_fidx (ctx
);
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
];
366 /* Get the offset of the start PC of the SFrame FDE at FUNC_IDX from the start
367 of the SFrame section. This section-relative offset is used within
368 libsframe for sorting the SFrame FDEs, and also information lookup routines
369 like sframe_find_fre.
371 If FUNC_IDX is not a valid index in the given decoder object, returns 0. */
374 sframe_decoder_get_secrel_func_start_addr (sframe_decoder_ctx
*dctx
,
378 int32_t offsetof_fde_in_sec
379 = sframe_decoder_get_offsetof_fde_start_addr (dctx
, func_idx
, &err
);
380 /* If func_idx is not a valid index, return 0. */
384 int32_t func_start_addr
= dctx
->sfd_funcdesc
[func_idx
].sfde_func_start_address
;
386 return func_start_addr
+ offsetof_fde_in_sec
;
389 /* Check whether for the given FDEP, the SFrame Frame Row Entry identified via
390 the START_IP_OFFSET and the END_IP_OFFSET, provides the stack trace
391 information for the PC. */
394 sframe_fre_check_range_p (sframe_decoder_ctx
*dctx
, uint32_t func_idx
,
395 uint32_t start_ip_offset
, uint32_t end_ip_offset
,
398 sframe_func_desc_entry
*fdep
;
399 int32_t func_start_addr
;
400 uint8_t rep_block_size
;
405 fdep
= &dctx
->sfd_funcdesc
[func_idx
];
406 func_start_addr
= sframe_decoder_get_secrel_func_start_addr (dctx
, func_idx
);
407 fde_type
= sframe_get_fde_type (fdep
);
408 mask_p
= (fde_type
== SFRAME_FDE_TYPE_PCMASK
);
409 rep_block_size
= fdep
->sfde_func_rep_size
;
411 if (func_start_addr
> pc
)
414 /* Given func_start_addr <= pc, pc - func_start_addr must be positive. */
415 pc_offset
= pc
- func_start_addr
;
416 /* For SFrame FDEs encoding information for repetitive pattern of insns,
417 masking with the rep_block_size is necessary to find the matching FRE. */
419 pc_offset
= pc_offset
% rep_block_size
;
421 return (start_ip_offset
<= pc_offset
) && (end_ip_offset
>= pc_offset
);
425 flip_fre (char *fp
, uint32_t fre_type
, size_t *fre_size
)
428 uint8_t offset_size
, offset_cnt
;
429 size_t addr_size
, fre_info_size
= 0;
432 if (fre_size
== NULL
)
433 return sframe_set_errno (&err
, SFRAME_ERR_INVAL
);
435 flip_fre_start_address (fp
, fre_type
);
437 /* Advance the buffer pointer to where the FRE info is. */
438 addr_size
= sframe_fre_start_addr_size (fre_type
);
441 /* FRE info is uint8_t. No need to flip. */
442 fre_info
= *(uint8_t*)fp
;
443 offset_size
= sframe_fre_get_offset_size (fre_info
);
444 offset_cnt
= sframe_fre_get_offset_count (fre_info
);
446 /* Advance the buffer pointer to where the stack offsets are. */
447 fre_info_size
= sizeof (uint8_t);
449 flip_fre_stack_offsets (fp
, offset_size
, offset_cnt
);
452 = addr_size
+ fre_info_size
+ sframe_fre_offset_bytes_size (fre_info
);
457 /* Endian flip the contents of FRAME_BUF of size BUF_SIZE.
458 The SFrame header in the FRAME_BUF must be endian flipped prior to
461 Endian flipping at decode time vs encode time have different needs. At
462 encode time, the frame_buf is in host endianness, and hence, values should
463 be read up before the buffer is changed to foreign endianness. This change
464 of behaviour is specified via TO_FOREIGN arg.
466 If an error code is returned, the buffer should not be used. */
469 flip_sframe (char *frame_buf
, size_t buf_size
, uint32_t to_foreign
)
471 unsigned int i
, j
, prev_frep_index
;
475 sframe_func_desc_entry
*fdep
;
476 unsigned int num_fdes
= 0;
477 unsigned int num_fres
= 0;
478 uint32_t fre_type
= 0;
479 uint32_t fre_offset
= 0;
483 /* For error checking. */
484 size_t bytes_flipped
= 0;
486 /* Header must be in host endianness at this time. */
487 ihp
= (sframe_header
*)frame_buf
;
489 if (!sframe_header_sanity_check_p (ihp
))
490 return sframe_set_errno (&err
, SFRAME_ERR_BUF_INVAL
);
492 /* The contents of the SFrame header are safe to read. Get the number of
493 FDEs and the first FDE in the buffer. */
494 hdrsz
= sframe_get_hdr_size (ihp
);
495 num_fdes
= ihp
->sfh_num_fdes
;
496 fdes
= frame_buf
+ hdrsz
+ ihp
->sfh_fdeoff
;
497 fdep
= (sframe_func_desc_entry
*)fdes
;
501 for (i
= 0; i
< num_fdes
; fdep
++, i
++)
503 if ((char*)fdep
>= (frame_buf
+ buf_size
))
508 num_fres
= fdep
->sfde_func_num_fres
;
509 fre_type
= sframe_get_fre_type (fdep
);
510 fre_offset
= fdep
->sfde_func_start_fre_off
;
514 bytes_flipped
+= sizeof (sframe_func_desc_entry
);
518 num_fres
= fdep
->sfde_func_num_fres
;
519 fre_type
= sframe_get_fre_type (fdep
);
520 fre_offset
= fdep
->sfde_func_start_fre_off
;
523 fp
= frame_buf
+ sframe_get_hdr_size (ihp
) + ihp
->sfh_freoff
;
525 for (; j
< prev_frep_index
+ num_fres
; j
++)
527 if (flip_fre (fp
, fre_type
, &esz
))
529 bytes_flipped
+= esz
;
531 if (esz
== 0 || esz
> buf_size
)
537 /* All FDEs and FREs must have been endian flipped by now. */
538 if ((j
!= ihp
->sfh_num_fres
) || (bytes_flipped
!= (buf_size
- hdrsz
)))
547 /* The SFrame Decoder. */
549 /* Get SFrame header from the given decoder context DCTX. */
551 static sframe_header
*
552 sframe_decoder_get_header (sframe_decoder_ctx
*dctx
)
554 sframe_header
*hp
= NULL
;
556 hp
= &dctx
->sfd_header
;
560 /* Compare function for qsort'ing the FDE table. */
563 fde_func (const void *p1
, const void *p2
)
565 const sframe_func_desc_entry
*aa
= p1
;
566 const sframe_func_desc_entry
*bb
= p2
;
568 if (aa
->sfde_func_start_address
< bb
->sfde_func_start_address
)
570 else if (aa
->sfde_func_start_address
> bb
->sfde_func_start_address
)
575 /* Get IDX'th offset from FRE. Set errp as applicable. */
578 sframe_get_fre_offset (sframe_frame_row_entry
*fre
, int idx
, int *errp
)
580 uint8_t offset_cnt
, offset_size
;
582 if (fre
== NULL
|| !sframe_fre_sanity_check_p (fre
))
583 return sframe_set_errno (errp
, SFRAME_ERR_FRE_INVAL
);
585 offset_cnt
= sframe_fre_get_offset_count (fre
->fre_info
);
586 offset_size
= sframe_fre_get_offset_size (fre
->fre_info
);
588 if (offset_cnt
< idx
+ 1)
589 return sframe_set_errno (errp
, SFRAME_ERR_FREOFFSET_NOPRESENT
);
592 *errp
= 0; /* Offset Valid. */
594 if (offset_size
== SFRAME_FRE_OFFSET_1B
)
596 int8_t *sp
= (int8_t *)fre
->fre_offsets
;
599 else if (offset_size
== SFRAME_FRE_OFFSET_2B
)
601 int16_t *sp
= (int16_t *)fre
->fre_offsets
;
606 int32_t *ip
= (int32_t *)fre
->fre_offsets
;
611 /* Free the decoder context. */
614 sframe_decoder_free (sframe_decoder_ctx
**dctxp
)
618 sframe_decoder_ctx
*dctx
= *dctxp
;
622 if (dctx
->sfd_funcdesc
!= NULL
)
624 free (dctx
->sfd_funcdesc
);
625 dctx
->sfd_funcdesc
= NULL
;
627 if (dctx
->sfd_fres
!= NULL
)
629 free (dctx
->sfd_fres
);
630 dctx
->sfd_fres
= NULL
;
632 if (dctx
->sfd_buf
!= NULL
)
634 free (dctx
->sfd_buf
);
635 dctx
->sfd_buf
= NULL
;
643 /* Create an FDE function info byte given an FRE_TYPE and an FDE_TYPE. */
644 /* FIXME API for linker. Revisit if its better placed somewhere else? */
647 sframe_fde_create_func_info (uint32_t fre_type
,
650 unsigned char func_info
;
651 sframe_assert (fre_type
== SFRAME_FRE_TYPE_ADDR1
652 || fre_type
== SFRAME_FRE_TYPE_ADDR2
653 || fre_type
== SFRAME_FRE_TYPE_ADDR4
);
654 sframe_assert (fde_type
== SFRAME_FDE_TYPE_PCINC
655 || fde_type
== SFRAME_FDE_TYPE_PCMASK
);
656 func_info
= SFRAME_V1_FUNC_INFO (fde_type
, fre_type
);
660 /* Get the FRE type given the function size. */
661 /* FIXME API for linker. Revisit if its better placed somewhere else? */
664 sframe_calc_fre_type (size_t func_size
)
666 uint32_t fre_type
= 0;
667 if (func_size
< SFRAME_FRE_TYPE_ADDR1_LIMIT
)
668 fre_type
= SFRAME_FRE_TYPE_ADDR1
;
669 else if (func_size
< SFRAME_FRE_TYPE_ADDR2_LIMIT
)
670 fre_type
= SFRAME_FRE_TYPE_ADDR2
;
671 /* Adjust the check a bit so that it remains warning-free but meaningful
672 on 32-bit systems. */
673 else if (func_size
<= (size_t) (SFRAME_FRE_TYPE_ADDR4_LIMIT
- 1))
674 fre_type
= SFRAME_FRE_TYPE_ADDR4
;
678 /* Get the base reg id from the FRE info. Set errp if failure. */
681 sframe_fre_get_base_reg_id (sframe_frame_row_entry
*fre
, int *errp
)
684 return sframe_set_errno (errp
, SFRAME_ERR_FRE_INVAL
);
686 uint8_t fre_info
= fre
->fre_info
;
687 return SFRAME_V1_FRE_CFA_BASE_REG_ID (fre_info
);
690 /* Get the CFA offset from the FRE. If the offset is invalid, sets errp. */
693 sframe_fre_get_cfa_offset (sframe_decoder_ctx
*dctx ATTRIBUTE_UNUSED
,
694 sframe_frame_row_entry
*fre
, int *errp
)
696 return sframe_get_fre_offset (fre
, SFRAME_FRE_CFA_OFFSET_IDX
, errp
);
699 /* Get the FP offset from the FRE. If the offset is invalid, sets errp. */
702 sframe_fre_get_fp_offset (sframe_decoder_ctx
*dctx
,
703 sframe_frame_row_entry
*fre
, int *errp
)
705 uint32_t fp_offset_idx
= 0;
706 int8_t fp_offset
= sframe_decoder_get_fixed_fp_offset (dctx
);
707 /* If the FP offset is not being tracked, return the fixed FP offset
708 from the SFrame header. */
709 if (fp_offset
!= SFRAME_CFA_FIXED_FP_INVALID
)
716 /* In some ABIs, the stack offset to recover RA (using the CFA) from is
717 fixed (like AMD64). In such cases, the stack offset to recover FP will
718 appear at the second index. */
719 fp_offset_idx
= ((sframe_decoder_get_fixed_ra_offset (dctx
)
720 != SFRAME_CFA_FIXED_RA_INVALID
)
721 ? SFRAME_FRE_RA_OFFSET_IDX
722 : SFRAME_FRE_FP_OFFSET_IDX
);
723 return sframe_get_fre_offset (fre
, fp_offset_idx
, errp
);
726 /* Get the RA offset from the FRE. If the offset is invalid, sets errp. */
729 sframe_fre_get_ra_offset (sframe_decoder_ctx
*dctx
,
730 sframe_frame_row_entry
*fre
, int *errp
)
732 int8_t ra_offset
= sframe_decoder_get_fixed_ra_offset (dctx
);
733 /* If the RA offset was not being tracked, return the fixed RA offset
734 from the SFrame header. */
735 if (ra_offset
!= SFRAME_CFA_FIXED_RA_INVALID
)
742 /* Otherwise, get the RA offset from the FRE. */
743 return sframe_get_fre_offset (fre
, SFRAME_FRE_RA_OFFSET_IDX
, errp
);
746 /* Get whether the RA is mangled. */
749 sframe_fre_get_ra_mangled_p (sframe_decoder_ctx
*dctx ATTRIBUTE_UNUSED
,
750 sframe_frame_row_entry
*fre
, int *errp
)
752 if (fre
== NULL
|| !sframe_fre_sanity_check_p (fre
))
753 return sframe_set_errno (errp
, SFRAME_ERR_FRE_INVAL
);
755 return sframe_get_fre_ra_mangled_p (fre
->fre_info
);
759 sframe_frame_row_entry_copy (sframe_frame_row_entry
*dst
,
760 sframe_frame_row_entry
*src
)
764 if (dst
== NULL
|| src
== NULL
)
765 return sframe_set_errno (&err
, SFRAME_ERR_INVAL
);
767 memcpy (dst
, src
, sizeof (sframe_frame_row_entry
));
771 /* Decode the SFrame FRE start address offset value from FRE_BUF in on-disk
772 binary format, given the FRE_TYPE. Updates the FRE_START_ADDR.
774 Returns 0 on success, SFRAME_ERR otherwise. */
777 sframe_decode_fre_start_address (const char *fre_buf
,
778 uint32_t *fre_start_addr
,
783 size_t addr_size
= 0;
785 addr_size
= sframe_fre_start_addr_size (fre_type
);
787 if (fre_type
== SFRAME_FRE_TYPE_ADDR1
)
789 uint8_t *uc
= (uint8_t *)fre_buf
;
790 saddr
= (uint32_t)*uc
;
792 else if (fre_type
== SFRAME_FRE_TYPE_ADDR2
)
794 uint16_t *ust
= (uint16_t *)fre_buf
;
795 /* SFrame is an unaligned on-disk format. Using memcpy helps avoid the
796 use of undesirable unaligned loads. See PR libsframe/29856. */
798 memcpy (&tmp
, ust
, addr_size
);
799 saddr
= (uint32_t)tmp
;
801 else if (fre_type
== SFRAME_FRE_TYPE_ADDR4
)
803 uint32_t *uit
= (uint32_t *)fre_buf
;
805 memcpy (&tmp
, uit
, addr_size
);
806 saddr
= (uint32_t)tmp
;
809 return sframe_set_errno (&err
, SFRAME_ERR_INVAL
);
811 *fre_start_addr
= saddr
;
815 /* Decode a frame row entry FRE which starts at location FRE_BUF. The function
816 updates ESZ to the size of the FRE as stored in the binary format.
818 This function works closely with the SFrame binary format.
820 Returns SFRAME_ERR if failure. */
823 sframe_decode_fre (const char *fre_buf
, sframe_frame_row_entry
*fre
,
824 uint32_t fre_type
, size_t *esz
)
827 const char *stack_offsets
= NULL
;
828 size_t stack_offsets_sz
;
832 if (fre_buf
== NULL
|| fre
== NULL
|| esz
== NULL
)
833 return sframe_set_errno (&err
, SFRAME_ERR_INVAL
);
835 /* Copy over the FRE start address. */
836 sframe_decode_fre_start_address (fre_buf
, &fre
->fre_start_addr
, fre_type
);
838 addr_size
= sframe_fre_start_addr_size (fre_type
);
839 fre
->fre_info
= *(uint8_t *)(fre_buf
+ addr_size
);
840 /* Sanity check as the API works closely with the binary format. */
841 sframe_assert (sizeof (fre
->fre_info
) == sizeof (uint8_t));
843 /* Cleanup the space for fre_offsets first, then copy over the valid
845 memset (fre
->fre_offsets
, 0, MAX_OFFSET_BYTES
);
846 /* Get offsets size. */
847 stack_offsets_sz
= sframe_fre_offset_bytes_size (fre
->fre_info
);
848 stack_offsets
= fre_buf
+ addr_size
+ sizeof (fre
->fre_info
);
849 memcpy (fre
->fre_offsets
, stack_offsets
, stack_offsets_sz
);
851 /* The FRE has been decoded. Use it to perform one last sanity check. */
852 fre_size
= sframe_fre_entry_size (fre
, fre_type
);
853 sframe_assert (fre_size
== (addr_size
+ sizeof (fre
->fre_info
)
854 + stack_offsets_sz
));
860 /* Decode the specified SFrame buffer CF_BUF of size CF_SIZE and return the
861 new SFrame decoder context.
863 Sets ERRP for the caller if any error. Frees up the allocated memory in
867 sframe_decode (const char *sf_buf
, size_t sf_size
, int *errp
)
869 const sframe_preamble
*sfp
;
871 sframe_header
*sfheaderp
;
872 sframe_decoder_ctx
*dctx
;
874 char *tempbuf
= NULL
;
878 int foreign_endian
= 0;
880 sframe_init_debug ();
882 if ((sf_buf
== NULL
) || (!sf_size
))
883 return sframe_ret_set_errno (errp
, SFRAME_ERR_INVAL
);
884 else if (sf_size
< sizeof (sframe_header
))
885 return sframe_ret_set_errno (errp
, SFRAME_ERR_BUF_INVAL
);
887 sfp
= (const sframe_preamble
*) sf_buf
;
889 debug_printf ("sframe_decode: magic=0x%x version=%u flags=%u\n",
890 sfp
->sfp_magic
, sfp
->sfp_version
, sfp
->sfp_flags
);
892 /* Check for foreign endianness. */
893 if (sfp
->sfp_magic
!= SFRAME_MAGIC
)
895 if (sfp
->sfp_magic
== bswap_16 (SFRAME_MAGIC
))
898 return sframe_ret_set_errno (errp
, SFRAME_ERR_BUF_INVAL
);
901 /* Initialize a new decoder context. */
902 if ((dctx
= malloc (sizeof (sframe_decoder_ctx
))) == NULL
)
903 return sframe_ret_set_errno (errp
, SFRAME_ERR_NOMEM
);
904 memset (dctx
, 0, sizeof (sframe_decoder_ctx
));
908 /* Allocate a new buffer and initialize it. */
909 tempbuf
= (char *) malloc (sf_size
* sizeof (char));
911 return sframe_ret_set_errno (errp
, SFRAME_ERR_NOMEM
);
912 memcpy (tempbuf
, sf_buf
, sf_size
);
914 /* Flip the header. */
915 sframe_header
*ihp
= (sframe_header
*) tempbuf
;
917 /* Flip the rest of the SFrame section data buffer. */
918 if (flip_sframe (tempbuf
, sf_size
, 0))
921 return sframe_ret_set_errno (errp
, SFRAME_ERR_BUF_INVAL
);
924 /* This buffer is malloc'd when endian flipping the contents of the input
925 buffer are needed. Keep a reference to it so it can be free'd up
926 later in sframe_decoder_free (). */
927 dctx
->sfd_buf
= tempbuf
;
930 frame_buf
= (char *)sf_buf
;
932 /* Handle the SFrame header. */
933 dctx
->sfd_header
= *(sframe_header
*) frame_buf
;
934 /* Validate the contents of SFrame header. */
935 sfheaderp
= &dctx
->sfd_header
;
936 if (!sframe_header_sanity_check_p (sfheaderp
))
938 sframe_ret_set_errno (errp
, SFRAME_ERR_BUF_INVAL
);
939 goto decode_fail_free
;
941 hdrsz
= sframe_get_hdr_size (sfheaderp
);
944 /* Handle the SFrame Function Descriptor Entry section. */
946 = sfheaderp
->sfh_num_fdes
* sizeof (sframe_func_desc_entry
);
947 dctx
->sfd_funcdesc
= malloc (fidx_size
);
948 if (dctx
->sfd_funcdesc
== NULL
)
950 sframe_ret_set_errno (errp
, SFRAME_ERR_NOMEM
);
951 goto decode_fail_free
;
953 memcpy (dctx
->sfd_funcdesc
, frame_buf
, fidx_size
);
955 debug_printf ("%u total fidx size\n", fidx_size
);
957 frame_buf
+= (fidx_size
);
959 /* Handle the SFrame Frame Row Entry section. */
960 dctx
->sfd_fres
= (char *) malloc (sfheaderp
->sfh_fre_len
);
961 if (dctx
->sfd_fres
== NULL
)
963 sframe_ret_set_errno (errp
, SFRAME_ERR_NOMEM
);
964 goto decode_fail_free
;
966 memcpy (dctx
->sfd_fres
, frame_buf
, sfheaderp
->sfh_fre_len
);
968 fre_bytes
= sfheaderp
->sfh_fre_len
;
969 dctx
->sfd_fre_nbytes
= fre_bytes
;
971 debug_printf ("%u total fre bytes\n", fre_bytes
);
976 if (foreign_endian
&& tempbuf
!= NULL
)
978 sframe_decoder_free (&dctx
);
983 /* Get the size of the SFrame header from the decoder context CTX. */
986 sframe_decoder_get_hdr_size (sframe_decoder_ctx
*ctx
)
989 dhp
= sframe_decoder_get_header (ctx
);
990 return sframe_get_hdr_size (dhp
);
993 /* Get the SFrame's abi/arch info given the decoder context DCTX. */
996 sframe_decoder_get_abi_arch (sframe_decoder_ctx
*dctx
)
998 sframe_header
*sframe_header
;
999 sframe_header
= sframe_decoder_get_header (dctx
);
1000 return sframe_header
->sfh_abi_arch
;
1003 /* Get the format version from the SFrame decoder context DCTX. */
1006 sframe_decoder_get_version (sframe_decoder_ctx
*dctx
)
1009 dhp
= sframe_decoder_get_header (dctx
);
1010 return dhp
->sfh_preamble
.sfp_version
;
1013 /* Get the section flags from the SFrame decoder context DCTX. */
1016 sframe_decoder_get_flags (sframe_decoder_ctx
*dctx
)
1018 const sframe_header
*dhp
= sframe_decoder_get_header (dctx
);
1019 return dhp
->sfh_preamble
.sfp_flags
;
1022 /* Get the SFrame's fixed FP offset given the decoder context CTX. */
1024 sframe_decoder_get_fixed_fp_offset (sframe_decoder_ctx
*ctx
)
1027 dhp
= sframe_decoder_get_header (ctx
);
1028 return dhp
->sfh_cfa_fixed_fp_offset
;
1031 /* Get the SFrame's fixed RA offset given the decoder context CTX. */
1033 sframe_decoder_get_fixed_ra_offset (sframe_decoder_ctx
*ctx
)
1036 dhp
= sframe_decoder_get_header (ctx
);
1037 return dhp
->sfh_cfa_fixed_ra_offset
;
1040 /* Get the offset of the sfde_func_start_address field (from the start of the
1041 on-disk layout of the SFrame section) of the FDE at FUNC_IDX in the decoder
1044 If FUNC_IDX is more than the number of SFrame FDEs in the section, sets
1045 error code in ERRP, but returns the (hypothetical) offset. This is useful
1046 for the linker when arranging input FDEs into the output section to be
1050 sframe_decoder_get_offsetof_fde_start_addr (sframe_decoder_ctx
*dctx
,
1051 uint32_t func_idx
, int *errp
)
1053 if (func_idx
>= sframe_decoder_get_num_fidx (dctx
))
1054 sframe_ret_set_errno (errp
, SFRAME_ERR_FDE_NOTFOUND
);
1058 return (sframe_decoder_get_hdr_size (dctx
)
1059 + func_idx
* sizeof (sframe_func_desc_entry
)
1060 + offsetof (sframe_func_desc_entry
, sfde_func_start_address
));
1063 /* Find the function descriptor entry which contains the specified address
1065 This function is deprecated and will be removed from libsframe.so.2. */
1068 sframe_get_funcdesc_with_addr (sframe_decoder_ctx
*ctx
__attribute__ ((unused
)),
1069 int32_t addr
__attribute__ ((unused
)),
1072 return sframe_ret_set_errno (errp
, SFRAME_ERR_INVAL
);
1075 /* Find the function descriptor entry starting which contains the specified
1078 static sframe_func_desc_entry
*
1079 sframe_get_funcdesc_with_addr_internal (sframe_decoder_ctx
*ctx
, int32_t addr
,
1080 int *errp
, uint32_t *func_idx
)
1083 sframe_func_desc_entry
*fdp
;
1087 return sframe_ret_set_errno (errp
, SFRAME_ERR_INVAL
);
1089 dhp
= sframe_decoder_get_header (ctx
);
1091 if (dhp
== NULL
|| dhp
->sfh_num_fdes
== 0 || ctx
->sfd_funcdesc
== NULL
)
1092 return sframe_ret_set_errno (errp
, SFRAME_ERR_DCTX_INVAL
);
1093 /* If the FDE sub-section is not sorted on PCs, skip the lookup because
1094 binary search cannot be used. */
1095 if ((sframe_decoder_get_flags (ctx
) & SFRAME_F_FDE_SORTED
) == 0)
1096 return sframe_ret_set_errno (errp
, SFRAME_ERR_FDE_NOTSORTED
);
1098 /* Do the binary search. */
1099 fdp
= (sframe_func_desc_entry
*) ctx
->sfd_funcdesc
;
1101 high
= dhp
->sfh_num_fdes
- 1;
1104 int mid
= low
+ (high
- low
) / 2;
1106 /* Given sfde_func_start_address <= addr,
1107 addr - sfde_func_start_address must be positive. */
1108 if (sframe_decoder_get_secrel_func_start_addr (ctx
, mid
) <= addr
1109 && ((uint32_t)(addr
- sframe_decoder_get_secrel_func_start_addr (ctx
,
1111 < fdp
[mid
].sfde_func_size
))
1117 if (sframe_decoder_get_secrel_func_start_addr (ctx
, mid
) < addr
)
1123 return sframe_ret_set_errno (errp
, SFRAME_ERR_FDE_NOTFOUND
);
1126 /* Get the end IP offset for the FRE at index i in the FDEP. The buffer FRES
1127 is the starting location for the FRE. */
1130 sframe_fre_get_end_ip_offset (sframe_func_desc_entry
*fdep
, unsigned int i
,
1133 uint32_t end_ip_offset
;
1136 fre_type
= sframe_get_fre_type (fdep
);
1138 /* Get the start address of the next FRE in sequence. */
1139 if (i
< fdep
->sfde_func_num_fres
- 1)
1141 sframe_decode_fre_start_address (fres
, &end_ip_offset
, fre_type
);
1145 /* The end IP offset for the FRE needs to be deduced from the function
1147 end_ip_offset
= fdep
->sfde_func_size
- 1;
1149 return end_ip_offset
;
1152 /* Find the SFrame Row Entry which contains the PC. Returns
1153 SFRAME_ERR if failure. */
1156 sframe_find_fre (sframe_decoder_ctx
*ctx
, int32_t pc
,
1157 sframe_frame_row_entry
*frep
)
1159 sframe_frame_row_entry cur_fre
;
1160 sframe_func_desc_entry
*fdep
;
1162 uint32_t fre_type
, i
;
1163 int32_t func_start_addr
;
1164 uint32_t start_ip_offset
, end_ip_offset
;
1169 if ((ctx
== NULL
) || (frep
== NULL
))
1170 return sframe_set_errno (&err
, SFRAME_ERR_INVAL
);
1172 /* Find the FDE which contains the PC, then scan its fre entries. */
1173 fdep
= sframe_get_funcdesc_with_addr_internal (ctx
, pc
, &err
, &func_idx
);
1174 if (fdep
== NULL
|| ctx
->sfd_fres
== NULL
)
1175 return sframe_set_errno (&err
, SFRAME_ERR_DCTX_INVAL
);
1177 fre_type
= sframe_get_fre_type (fdep
);
1179 fres
= ctx
->sfd_fres
+ fdep
->sfde_func_start_fre_off
;
1180 func_start_addr
= sframe_decoder_get_secrel_func_start_addr (ctx
, func_idx
);
1182 for (i
= 0; i
< fdep
->sfde_func_num_fres
; i
++)
1184 err
= sframe_decode_fre (fres
, &cur_fre
, fre_type
, &size
);
1186 return sframe_set_errno (&err
, SFRAME_ERR_FRE_INVAL
);
1188 start_ip_offset
= cur_fre
.fre_start_addr
;
1189 end_ip_offset
= sframe_fre_get_end_ip_offset (fdep
, i
, fres
+ size
);
1191 /* Stop search if FRE's start_ip is greater than pc. Given
1192 func_start_addr <= pc, pc - func_start_addr must be positive. */
1193 if (start_ip_offset
> (uint32_t)(pc
- func_start_addr
))
1194 return sframe_set_errno (&err
, SFRAME_ERR_FRE_INVAL
);
1196 if (sframe_fre_check_range_p (ctx
, func_idx
, start_ip_offset
,
1199 sframe_frame_row_entry_copy (frep
, &cur_fre
);
1204 return sframe_set_errno (&err
, SFRAME_ERR_FDE_INVAL
);
1207 /* Return the number of function descriptor entries in the SFrame decoder
1211 sframe_decoder_get_num_fidx (sframe_decoder_ctx
*ctx
)
1213 uint32_t num_fdes
= 0;
1214 sframe_header
*dhp
= NULL
;
1215 dhp
= sframe_decoder_get_header (ctx
);
1217 num_fdes
= dhp
->sfh_num_fdes
;
1221 /* Get the data (NUM_FRES, FUNC_START_ADDRESS) from the function
1222 descriptor entry at index I'th in the decoder CTX. If failed,
1223 return error code. */
1224 /* FIXME - consolidate the args and return a
1225 sframe_func_desc_index_elem rather? */
1228 sframe_decoder_get_funcdesc (sframe_decoder_ctx
*ctx
,
1231 uint32_t *func_size
,
1232 int32_t *func_start_address
,
1233 unsigned char *func_info
)
1235 sframe_func_desc_entry
*fdp
;
1238 if (ctx
== NULL
|| func_start_address
== NULL
|| num_fres
== NULL
1239 || func_size
== NULL
)
1240 return sframe_set_errno (&err
, SFRAME_ERR_INVAL
);
1242 fdp
= sframe_decoder_get_funcdesc_at_index (ctx
, i
);
1245 return sframe_set_errno (&err
, SFRAME_ERR_FDE_NOTFOUND
);
1247 *num_fres
= fdp
->sfde_func_num_fres
;
1248 *func_start_address
= fdp
->sfde_func_start_address
;
1249 *func_size
= fdp
->sfde_func_size
;
1250 *func_info
= fdp
->sfde_func_info
;
1256 sframe_decoder_get_funcdesc_v2 (sframe_decoder_ctx
*dctx
,
1259 uint32_t *func_size
,
1260 int32_t *func_start_address
,
1261 unsigned char *func_info
,
1262 uint8_t *rep_block_size
)
1264 sframe_func_desc_entry
*fdp
;
1267 if (dctx
== NULL
|| func_start_address
== NULL
1268 || num_fres
== NULL
|| func_size
== NULL
1269 || sframe_decoder_get_version (dctx
) == SFRAME_VERSION_1
)
1270 return sframe_set_errno (&err
, SFRAME_ERR_INVAL
);
1272 fdp
= sframe_decoder_get_funcdesc_at_index (dctx
, i
);
1275 return sframe_set_errno (&err
, SFRAME_ERR_FDE_NOTFOUND
);
1277 *num_fres
= fdp
->sfde_func_num_fres
;
1278 *func_start_address
= fdp
->sfde_func_start_address
;
1279 *func_size
= fdp
->sfde_func_size
;
1280 *func_info
= fdp
->sfde_func_info
;
1281 *rep_block_size
= fdp
->sfde_func_rep_size
;
1285 /* Get the FRE_IDX'th FRE of the function at FUNC_IDX'th function
1286 descriptor entry in the SFrame decoder CTX. Returns error code as
1290 sframe_decoder_get_fre (sframe_decoder_ctx
*ctx
,
1291 unsigned int func_idx
,
1292 unsigned int fre_idx
,
1293 sframe_frame_row_entry
*fre
)
1295 sframe_func_desc_entry
*fdep
;
1296 sframe_frame_row_entry ifre
;
1303 if (ctx
== NULL
|| fre
== NULL
)
1304 return sframe_set_errno (&err
, SFRAME_ERR_INVAL
);
1306 /* Get function descriptor entry at index func_idx. */
1307 fdep
= sframe_decoder_get_funcdesc_at_index (ctx
, func_idx
);
1310 return sframe_set_errno (&err
, SFRAME_ERR_FDE_NOTFOUND
);
1312 fre_type
= sframe_get_fre_type (fdep
);
1313 /* Now scan the FRE entries. */
1314 fres
= ctx
->sfd_fres
+ fdep
->sfde_func_start_fre_off
;
1315 for (i
= 0; i
< fdep
->sfde_func_num_fres
; i
++)
1317 /* Decode the FRE at the current position. Return it if valid. */
1318 err
= sframe_decode_fre (fres
, &ifre
, fre_type
, &esz
);
1321 if (!sframe_fre_sanity_check_p (&ifre
))
1322 return sframe_set_errno (&err
, SFRAME_ERR_FRE_INVAL
);
1324 sframe_frame_row_entry_copy (fre
, &ifre
);
1326 if (fdep
->sfde_func_size
)
1327 sframe_assert (fre
->fre_start_addr
< fdep
->sfde_func_size
);
1329 /* A SFrame FDE with func size equal to zero is possible. */
1330 sframe_assert (fre
->fre_start_addr
== fdep
->sfde_func_size
);
1338 return sframe_set_errno (&err
, SFRAME_ERR_FDE_NOTFOUND
);
1342 /* SFrame Encoder. */
1344 /* Get a reference to the ENCODER's SFrame header. */
1346 static sframe_header
*
1347 sframe_encoder_get_header (sframe_encoder_ctx
*encoder
)
1349 sframe_header
*hp
= NULL
;
1351 hp
= &encoder
->sfe_header
;
1355 static sframe_func_desc_entry
*
1356 sframe_encoder_get_funcdesc_at_index (sframe_encoder_ctx
*encoder
,
1359 sframe_func_desc_entry
*fde
= NULL
;
1360 if (func_idx
< sframe_encoder_get_num_fidx (encoder
))
1362 sf_fde_tbl
*func_tbl
= encoder
->sfe_funcdesc
;
1363 fde
= func_tbl
->entry
+ func_idx
;
1368 /* Create an encoder context with the given SFrame format version VER, FLAGS
1369 and ABI information. Uses the ABI specific FIXED_FP_OFFSET and
1370 FIXED_RA_OFFSET values as provided. Sets errp if failure. */
1372 sframe_encoder_ctx
*
1373 sframe_encode (uint8_t ver
, uint8_t flags
, uint8_t abi_arch
,
1374 int8_t fixed_fp_offset
, int8_t fixed_ra_offset
, int *errp
)
1377 sframe_encoder_ctx
*encoder
;
1379 if (ver
!= SFRAME_VERSION
)
1380 return sframe_ret_set_errno (errp
, SFRAME_ERR_VERSION_INVAL
);
1382 if ((encoder
= malloc (sizeof (sframe_encoder_ctx
))) == NULL
)
1383 return sframe_ret_set_errno (errp
, SFRAME_ERR_NOMEM
);
1385 memset (encoder
, 0, sizeof (sframe_encoder_ctx
));
1387 /* Get the SFrame header and update it. */
1388 hp
= sframe_encoder_get_header (encoder
);
1389 hp
->sfh_preamble
.sfp_version
= ver
;
1390 hp
->sfh_preamble
.sfp_magic
= SFRAME_MAGIC
;
1391 hp
->sfh_preamble
.sfp_flags
= flags
;
1393 /* Implementation in the SFrame encoder APIs, e.g.,
1394 sframe_encoder_write_sframe assume flag SFRAME_F_FDE_FUNC_START_PCREL
1396 if (!(flags
& SFRAME_F_FDE_FUNC_START_PCREL
))
1397 return sframe_ret_set_errno (errp
, SFRAME_ERR_ECTX_INVAL
);
1399 hp
->sfh_abi_arch
= abi_arch
;
1400 hp
->sfh_cfa_fixed_fp_offset
= fixed_fp_offset
;
1401 hp
->sfh_cfa_fixed_ra_offset
= fixed_ra_offset
;
1406 /* Free the encoder context. */
1409 sframe_encoder_free (sframe_encoder_ctx
**encoder
)
1411 if (encoder
!= NULL
)
1413 sframe_encoder_ctx
*ectx
= *encoder
;
1417 if (ectx
->sfe_funcdesc
!= NULL
)
1419 free (ectx
->sfe_funcdesc
);
1420 ectx
->sfe_funcdesc
= NULL
;
1422 if (ectx
->sfe_fres
!= NULL
)
1424 free (ectx
->sfe_fres
);
1425 ectx
->sfe_fres
= NULL
;
1427 if (ectx
->sfe_data
!= NULL
)
1429 free (ectx
->sfe_data
);
1430 ectx
->sfe_data
= NULL
;
1438 /* Get the size of the SFrame header from the encoder ctx ENCODER. */
1441 sframe_encoder_get_hdr_size (sframe_encoder_ctx
*encoder
)
1444 ehp
= sframe_encoder_get_header (encoder
);
1445 return sframe_get_hdr_size (ehp
);
1448 /* Get the abi/arch info from the SFrame encoder context ENCODER. */
1451 sframe_encoder_get_abi_arch (sframe_encoder_ctx
*encoder
)
1453 uint8_t abi_arch
= 0;
1455 ehp
= sframe_encoder_get_header (encoder
);
1457 abi_arch
= ehp
->sfh_abi_arch
;
1461 /* Get the format version from the SFrame encoder context ENCODER. */
1464 sframe_encoder_get_version (sframe_encoder_ctx
*encoder
)
1467 ehp
= sframe_encoder_get_header (encoder
);
1468 return ehp
->sfh_preamble
.sfp_version
;
1471 /* Get the section flags from the SFrame encoder context ENCODER. */
1474 sframe_encoder_get_flags (sframe_encoder_ctx
*encoder
)
1476 const sframe_header
*ehp
= sframe_encoder_get_header (encoder
);
1477 return ehp
->sfh_preamble
.sfp_flags
;
1480 /* Return the number of function descriptor entries in the SFrame encoder
1484 sframe_encoder_get_num_fidx (sframe_encoder_ctx
*encoder
)
1486 uint32_t num_fdes
= 0;
1487 sframe_header
*ehp
= NULL
;
1488 ehp
= sframe_encoder_get_header (encoder
);
1490 num_fdes
= ehp
->sfh_num_fdes
;
1494 /* Get the offset of the sfde_func_start_address field (from the start of the
1495 on-disk layout of the SFrame section) of the FDE at FUNC_IDX in the encoder
1498 If FUNC_IDX is more than the number of SFrame FDEs in the section, sets
1499 error code in ERRP, but returns the (hypothetical) offset. This is useful
1500 for the linker when arranging input FDEs into the output section to be
1504 sframe_encoder_get_offsetof_fde_start_addr (sframe_encoder_ctx
*encoder
,
1505 uint32_t func_idx
, int *errp
)
1507 if (func_idx
>= sframe_encoder_get_num_fidx (encoder
))
1508 sframe_ret_set_errno (errp
, SFRAME_ERR_FDE_INVAL
);
1512 return (sframe_encoder_get_hdr_size (encoder
)
1513 + func_idx
* sizeof (sframe_func_desc_entry
)
1514 + offsetof (sframe_func_desc_entry
, sfde_func_start_address
));
1517 /* Add an FRE to function at FUNC_IDX'th function descriptor entry in
1518 the encoder context. */
1521 sframe_encoder_add_fre (sframe_encoder_ctx
*encoder
,
1522 unsigned int func_idx
,
1523 sframe_frame_row_entry
*frep
)
1526 sframe_func_desc_entry
*fdep
;
1527 sframe_frame_row_entry
*ectx_frep
;
1528 size_t offsets_sz
, esz
;
1533 if (encoder
== NULL
|| frep
== NULL
)
1534 return sframe_set_errno (&err
, SFRAME_ERR_INVAL
);
1535 if (!sframe_fre_sanity_check_p (frep
))
1536 return sframe_set_errno (&err
, SFRAME_ERR_FRE_INVAL
);
1538 /* Use func_idx to gather the function descriptor entry. */
1539 fdep
= sframe_encoder_get_funcdesc_at_index (encoder
, func_idx
);
1542 return sframe_set_errno (&err
, SFRAME_ERR_FDE_NOTFOUND
);
1544 fre_type
= sframe_get_fre_type (fdep
);
1545 sf_fre_tbl
*fre_tbl
= encoder
->sfe_fres
;
1547 if (fre_tbl
== NULL
)
1549 fre_tbl_sz
= (sizeof (sf_fre_tbl
)
1550 + (number_of_entries
* sizeof (sframe_frame_row_entry
)));
1551 fre_tbl
= malloc (fre_tbl_sz
);
1553 if (fre_tbl
== NULL
)
1555 sframe_set_errno (&err
, SFRAME_ERR_NOMEM
);
1556 goto bad
; /* OOM. */
1558 memset (fre_tbl
, 0, fre_tbl_sz
);
1559 fre_tbl
->alloced
= number_of_entries
;
1561 else if (fre_tbl
->count
== fre_tbl
->alloced
)
1563 fre_tbl_sz
= (sizeof (sf_fre_tbl
)
1564 + ((fre_tbl
->alloced
+ number_of_entries
)
1565 * sizeof (sframe_frame_row_entry
)));
1566 fre_tbl
= realloc (fre_tbl
, fre_tbl_sz
);
1567 if (fre_tbl
== NULL
)
1569 sframe_set_errno (&err
, SFRAME_ERR_NOMEM
);
1570 goto bad
; /* OOM. */
1573 memset (&fre_tbl
->entry
[fre_tbl
->alloced
], 0,
1574 number_of_entries
* sizeof (sframe_frame_row_entry
));
1575 fre_tbl
->alloced
+= number_of_entries
;
1578 ectx_frep
= &fre_tbl
->entry
[fre_tbl
->count
];
1579 ectx_frep
->fre_start_addr
1580 = frep
->fre_start_addr
;
1581 ectx_frep
->fre_info
= frep
->fre_info
;
1583 if (fdep
->sfde_func_size
)
1584 sframe_assert (frep
->fre_start_addr
< fdep
->sfde_func_size
);
1586 /* A SFrame FDE with func size equal to zero is possible. */
1587 sframe_assert (frep
->fre_start_addr
== fdep
->sfde_func_size
);
1589 /* frep has already been sanity check'd. Get offsets size. */
1590 offsets_sz
= sframe_fre_offset_bytes_size (frep
->fre_info
);
1591 memcpy (&ectx_frep
->fre_offsets
, &frep
->fre_offsets
, offsets_sz
);
1593 esz
= sframe_fre_entry_size (frep
, fre_type
);
1596 encoder
->sfe_fres
= fre_tbl
;
1597 encoder
->sfe_fre_nbytes
+= esz
;
1599 ehp
= sframe_encoder_get_header (encoder
);
1600 ehp
->sfh_num_fres
= fre_tbl
->count
;
1602 /* Update the value of the number of FREs for the function. */
1603 fdep
->sfde_func_num_fres
++;
1608 if (fre_tbl
!= NULL
)
1610 encoder
->sfe_fres
= NULL
;
1611 encoder
->sfe_fre_nbytes
= 0;
1615 /* Add a new function descriptor entry with START_ADDR, FUNC_SIZE and NUM_FRES
1619 sframe_encoder_add_funcdesc (sframe_encoder_ctx
*encoder
,
1622 unsigned char func_info
,
1623 uint32_t num_fres
__attribute__ ((unused
)))
1626 sf_fde_tbl
*fd_info
;
1630 /* FIXME book-keep num_fres for error checking. */
1631 if (encoder
== NULL
)
1632 return sframe_set_errno (&err
, SFRAME_ERR_INVAL
);
1634 fd_info
= encoder
->sfe_funcdesc
;
1635 ehp
= sframe_encoder_get_header (encoder
);
1637 if (fd_info
== NULL
)
1639 fd_tbl_sz
= (sizeof (sf_fde_tbl
)
1640 + (number_of_entries
* sizeof (sframe_func_desc_entry
)));
1641 fd_info
= malloc (fd_tbl_sz
);
1642 if (fd_info
== NULL
)
1644 sframe_set_errno (&err
, SFRAME_ERR_NOMEM
);
1645 goto bad
; /* OOM. */
1647 memset (fd_info
, 0, fd_tbl_sz
);
1648 fd_info
->alloced
= number_of_entries
;
1650 else if (fd_info
->count
== fd_info
->alloced
)
1652 fd_tbl_sz
= (sizeof (sf_fde_tbl
)
1653 + ((fd_info
->alloced
+ number_of_entries
)
1654 * sizeof (sframe_func_desc_entry
)));
1655 fd_info
= realloc (fd_info
, fd_tbl_sz
);
1656 if (fd_info
== NULL
)
1658 sframe_set_errno (&err
, SFRAME_ERR_NOMEM
);
1659 goto bad
; /* OOM. */
1662 memset (&fd_info
->entry
[fd_info
->alloced
], 0,
1663 number_of_entries
* sizeof (sframe_func_desc_entry
));
1664 fd_info
->alloced
+= number_of_entries
;
1667 fd_info
->entry
[fd_info
->count
].sfde_func_start_address
= start_addr
;
1668 /* Num FREs is updated as FREs are added for the function later via
1669 sframe_encoder_add_fre. */
1670 fd_info
->entry
[fd_info
->count
].sfde_func_size
= func_size
;
1671 fd_info
->entry
[fd_info
->count
].sfde_func_start_fre_off
1672 = encoder
->sfe_fre_nbytes
;
1674 // Linker optimization test code cleanup later ibhagat TODO FIXME
1675 uint32_t fre_type
= sframe_calc_fre_type (func_size
);
1677 fd_info
->entry
[fd_info
->count
].sfde_func_info
1678 = sframe_fde_func_info (fre_type
);
1680 fd_info
->entry
[fd_info
->count
].sfde_func_info
= func_info
;
1682 encoder
->sfe_funcdesc
= fd_info
;
1683 ehp
->sfh_num_fdes
++;
1687 if (fd_info
!= NULL
)
1689 encoder
->sfe_funcdesc
= NULL
;
1690 ehp
->sfh_num_fdes
= 0;
1694 /* Add a new function descriptor entry with START_ADDR, FUNC_SIZE, FUNC_INFO
1695 and REP_BLOCK_SIZE to the encoder.
1697 This API is valid only for SFrame format version 2. */
1700 sframe_encoder_add_funcdesc_v2 (sframe_encoder_ctx
*encoder
,
1703 unsigned char func_info
,
1704 uint8_t rep_block_size
,
1705 uint32_t num_fres
__attribute__ ((unused
)))
1707 sf_fde_tbl
*fd_info
;
1711 || sframe_encoder_get_version (encoder
) == SFRAME_VERSION_1
)
1712 return sframe_set_errno (&err
, SFRAME_ERR_INVAL
);
1714 err
= sframe_encoder_add_funcdesc (encoder
, start_addr
, func_size
, func_info
,
1719 fd_info
= encoder
->sfe_funcdesc
;
1720 fd_info
->entry
[fd_info
->count
-1].sfde_func_rep_size
= rep_block_size
;
1726 sframe_sort_funcdesc (sframe_encoder_ctx
*encoder
)
1728 sframe_header
*ehp
= sframe_encoder_get_header (encoder
);
1730 /* Sort and write out the FDE table. */
1731 sf_fde_tbl
*fd_info
= encoder
->sfe_funcdesc
;
1734 /* The new encoding of sfde_func_start_address means the distances are
1735 not from the same anchor, so cannot be sorted directly. At the moment
1736 we adress this by manual value adjustments before and after sorting.
1737 FIXME - qsort_r may be more optimal. */
1739 for (unsigned int i
= 0; i
< fd_info
->count
; i
++)
1740 fd_info
->entry
[i
].sfde_func_start_address
1741 += sframe_encoder_get_offsetof_fde_start_addr (encoder
, i
, NULL
);
1743 qsort (fd_info
->entry
, fd_info
->count
,
1744 sizeof (sframe_func_desc_entry
), fde_func
);
1746 for (unsigned int i
= 0; i
< fd_info
->count
; i
++)
1747 fd_info
->entry
[i
].sfde_func_start_address
1748 -= sframe_encoder_get_offsetof_fde_start_addr (encoder
, i
, NULL
);
1750 /* Update preamble's flags. */
1751 ehp
->sfh_preamble
.sfp_flags
|= SFRAME_F_FDE_SORTED
;
1756 /* Write the SFrame FRE start address from the in-memory FRE_START_ADDR
1757 to the buffer CONTENTS (on-disk format), given the FRE_TYPE and
1758 FRE_START_ADDR_SZ. */
1761 sframe_encoder_write_fre_start_addr (char *contents
,
1762 uint32_t fre_start_addr
,
1764 size_t fre_start_addr_sz
)
1768 if (fre_type
== SFRAME_FRE_TYPE_ADDR1
)
1770 uint8_t uc
= fre_start_addr
;
1771 memcpy (contents
, &uc
, fre_start_addr_sz
);
1773 else if (fre_type
== SFRAME_FRE_TYPE_ADDR2
)
1775 uint16_t ust
= fre_start_addr
;
1776 memcpy (contents
, &ust
, fre_start_addr_sz
);
1778 else if (fre_type
== SFRAME_FRE_TYPE_ADDR4
)
1780 uint32_t uit
= fre_start_addr
;
1781 memcpy (contents
, &uit
, fre_start_addr_sz
);
1784 return sframe_set_errno (&err
, SFRAME_ERR_INVAL
);
1789 /* Write a frame row entry pointed to by FREP into the buffer CONTENTS. The
1790 size in bytes written out are updated in ESZ.
1792 This function works closely with the SFrame binary format.
1794 Returns SFRAME_ERR if failure. */
1797 sframe_encoder_write_fre (char *contents
, sframe_frame_row_entry
*frep
,
1798 uint32_t fre_type
, size_t *esz
)
1801 size_t fre_start_addr_sz
;
1802 size_t fre_stack_offsets_sz
;
1805 if (!sframe_fre_sanity_check_p (frep
))
1806 return sframe_set_errno (&err
, SFRAME_ERR_FRE_INVAL
);
1808 fre_start_addr_sz
= sframe_fre_start_addr_size (fre_type
);
1809 fre_stack_offsets_sz
= sframe_fre_offset_bytes_size (frep
->fre_info
);
1811 /* The FRE start address must be encodable in the available number of
1813 uint64_t bitmask
= SFRAME_BITMASK_OF_SIZE (fre_start_addr_sz
);
1814 sframe_assert ((uint64_t)frep
->fre_start_addr
<= bitmask
);
1816 sframe_encoder_write_fre_start_addr (contents
, frep
->fre_start_addr
,
1817 fre_type
, fre_start_addr_sz
);
1818 contents
+= fre_start_addr_sz
;
1820 memcpy (contents
, &frep
->fre_info
, sizeof (frep
->fre_info
));
1821 contents
+= sizeof (frep
->fre_info
);
1823 memcpy (contents
, frep
->fre_offsets
, fre_stack_offsets_sz
);
1824 contents
+= fre_stack_offsets_sz
;
1826 fre_sz
= sframe_fre_entry_size (frep
, fre_type
);
1827 /* Sanity checking. */
1828 sframe_assert ((fre_start_addr_sz
1829 + sizeof (frep
->fre_info
)
1830 + fre_stack_offsets_sz
) == fre_sz
);
1837 /* Serialize the core contents of the SFrame section and write out to the
1838 output buffer held in the ENCODER. Return SFRAME_ERR if failure. */
1841 sframe_encoder_write_sframe (sframe_encoder_ctx
*encoder
)
1846 size_t all_fdes_size
;
1850 sf_fde_tbl
*fd_info
;
1851 sf_fre_tbl
*fr_info
;
1852 uint32_t i
, num_fdes
;
1853 uint32_t j
, num_fres
;
1854 sframe_func_desc_entry
*fdep
;
1855 sframe_frame_row_entry
*frep
;
1860 contents
= encoder
->sfe_data
;
1861 buf_size
= encoder
->sfe_data_size
;
1862 num_fdes
= sframe_encoder_get_num_fidx (encoder
);
1863 all_fdes_size
= num_fdes
* sizeof (sframe_func_desc_entry
);
1864 ehp
= sframe_encoder_get_header (encoder
);
1865 hdr_size
= sframe_get_hdr_size (ehp
);
1867 fd_info
= encoder
->sfe_funcdesc
;
1868 fr_info
= encoder
->sfe_fres
;
1871 - buffers must be malloc'd by the caller. */
1872 if ((contents
== NULL
) || (buf_size
< hdr_size
))
1873 return sframe_set_errno (&err
, SFRAME_ERR_BUF_INVAL
);
1874 if (fr_info
== NULL
)
1875 return sframe_set_errno (&err
, SFRAME_ERR_FRE_INVAL
);
1877 /* Write out the FRE table first.
1879 Recall that read/write of FREs needs information from the corresponding
1880 FDE; the latter stores the information about the FRE type record used for
1881 the function. Also note that sorting of FDEs does NOT impact the order
1882 in which FREs are stored in the SFrame's FRE sub-section. This means
1883 that writing out FREs after sorting of FDEs will need some additional
1884 book-keeping. At this time, we can afford to avoid it by writing out
1885 the FREs first to the output buffer. */
1887 uint32_t global
= 0;
1888 uint32_t fre_index
= 0;
1890 contents
+= hdr_size
+ all_fdes_size
;
1891 for (i
= 0; i
< num_fdes
; i
++)
1893 fdep
= &fd_info
->entry
[i
];
1894 fre_type
= sframe_get_fre_type (fdep
);
1895 num_fres
= fdep
->sfde_func_num_fres
;
1897 for (j
= 0; j
< num_fres
; j
++)
1899 fre_index
= global
+ j
;
1900 frep
= &fr_info
->entry
[fre_index
];
1902 sframe_encoder_write_fre (contents
, frep
, fre_type
, &esz
);
1904 fre_size
+= esz
; /* For debugging only. */
1909 sframe_assert (fre_size
== ehp
->sfh_fre_len
);
1910 sframe_assert (global
== ehp
->sfh_num_fres
);
1911 sframe_assert ((size_t)(contents
- encoder
->sfe_data
) == buf_size
);
1913 /* Sort the FDE table */
1914 sframe_sort_funcdesc (encoder
);
1917 - the FDE section must have been sorted by now on the start address
1918 of each function. */
1919 if (!(sframe_encoder_get_flags (encoder
) & SFRAME_F_FDE_SORTED
)
1920 || (fd_info
== NULL
))
1921 return sframe_set_errno (&err
, SFRAME_ERR_FDE_INVAL
);
1923 contents
= encoder
->sfe_data
;
1924 /* Write out the SFrame header. The SFrame header in the encoder
1925 object has already been updated with correct offsets by the caller. */
1926 memcpy (contents
, ehp
, hdr_size
);
1927 contents
+= hdr_size
;
1929 /* Write out the FDE table sorted on funtion start address. */
1930 memcpy (contents
, fd_info
->entry
, all_fdes_size
);
1931 contents
+= all_fdes_size
;
1936 /* Serialize the contents of the encoder and return the buffer. ENCODED_SIZE
1937 is updated to the size of the buffer. */
1940 sframe_encoder_write (sframe_encoder_ctx
*encoder
,
1941 size_t *encoded_size
, int *errp
)
1944 size_t hdrsize
, fsz
, fresz
, bufsize
;
1947 /* Initialize the encoded_size to zero. This makes it simpler to just
1948 return from the function in case of failure. Free'ing up of
1949 encoder->sfe_data is the responsibility of the caller. */
1952 if (encoder
== NULL
|| encoded_size
== NULL
|| errp
== NULL
)
1953 return sframe_ret_set_errno (errp
, SFRAME_ERR_INVAL
);
1955 ehp
= sframe_encoder_get_header (encoder
);
1956 hdrsize
= sframe_get_hdr_size (ehp
);
1957 fsz
= sframe_encoder_get_num_fidx (encoder
)
1958 * sizeof (sframe_func_desc_entry
);
1959 fresz
= encoder
->sfe_fre_nbytes
;
1961 /* The total size of buffer is the sum of header, SFrame Function Descriptor
1962 Entries section and the FRE section. */
1963 bufsize
= hdrsize
+ fsz
+ fresz
;
1964 encoder
->sfe_data
= (char *) malloc (bufsize
);
1965 if (encoder
->sfe_data
== NULL
)
1966 return sframe_ret_set_errno (errp
, SFRAME_ERR_NOMEM
);
1967 encoder
->sfe_data_size
= bufsize
;
1969 /* Update the information in the SFrame header. */
1970 /* SFrame FDE section follows immediately after the header. */
1971 ehp
->sfh_fdeoff
= 0;
1972 /* SFrame FRE section follows immediately after the SFrame FDE section. */
1973 ehp
->sfh_freoff
= fsz
;
1974 ehp
->sfh_fre_len
= fresz
;
1976 foreign_endian
= need_swapping (ehp
->sfh_abi_arch
);
1978 /* Write out the FDE Index and the FRE table in the sfe_data. */
1979 if (sframe_encoder_write_sframe (encoder
))
1980 return sframe_ret_set_errno (errp
, SFRAME_ERR_BUF_INVAL
);
1982 /* Endian flip the contents if necessary. */
1985 if (flip_sframe (encoder
->sfe_data
, bufsize
, 1))
1986 return sframe_ret_set_errno (errp
, SFRAME_ERR_BUF_INVAL
);
1987 flip_header ((sframe_header
*)encoder
->sfe_data
);
1990 *encoded_size
= bufsize
;
1991 return encoder
->sfe_data
;