1 /* sframe.c - SFrame decoder/encoder.
3 Copyright (C) 2022-2024 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/>. */
25 #include "sframe-impl.h"
32 sframe_func_desc_entry entry
[1];
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;
51 sframe_init_debug (void)
57 _sframe_debug
= getenv ("SFRAME_DEBUG") != NULL
;
62 _sf_printflike_ (1, 2)
63 static void debug_printf (const char *format
, ...)
69 va_start (args
, format
);
70 vfprintf (stderr
, format
, 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.
87 sframe_set_errno (int *errp
, int error
)
94 /* Store the specified error code into errp if it is non-NULL.
98 sframe_ret_set_errno (int *errp
, int error
)
105 /* Get the SFrame header size. */
108 sframe_get_hdr_size (sframe_header
*sfh
)
110 return SFRAME_V1_HDR_SIZE (*sfh
);
113 /* Access functions for frame row entry data. */
116 sframe_fre_get_offset_count (uint8_t fre_info
)
118 return SFRAME_V1_FRE_OFFSET_COUNT (fre_info
);
122 sframe_fre_get_offset_size (uint8_t fre_info
)
124 return SFRAME_V1_FRE_OFFSET_SIZE (fre_info
);
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. */
136 sframe_get_fre_type (sframe_func_desc_entry
*fdep
)
138 uint32_t fre_type
= 0;
140 fre_type
= SFRAME_V1_FUNC_FRE_TYPE (fdep
->sfde_func_info
);
145 sframe_get_fde_type (sframe_func_desc_entry
*fdep
)
147 uint32_t fde_type
= 0;
149 fde_type
= SFRAME_V1_FUNC_FDE_TYPE (fdep
->sfde_func_info
);
153 /* Check if flipping is needed, based on ENDIAN. */
156 need_swapping (int endian
)
159 char *c
= (char *)&ui
;
160 int is_little
= (int)*c
;
164 case SFRAME_ABI_AARCH64_ENDIAN_LITTLE
:
165 case SFRAME_ABI_AMD64_ENDIAN_LITTLE
:
167 case SFRAME_ABI_AARCH64_ENDIAN_BIG
:
176 /* Flip the endianness of the SFrame header. */
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
);
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. */
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
)
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 /* 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. */
371 sframe_fre_check_range_p (sframe_func_desc_entry
*fdep
,
372 int32_t start_ip_offset
, int32_t end_ip_offset
,
375 int32_t start_ip
, end_ip
;
376 int32_t func_start_addr
;
377 uint8_t rep_block_size
;
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
;
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
));
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
404 masked_pc
= pc
% rep_block_size
;
405 ret
= ((start_ip_offset
<= masked_pc
) && (end_ip_offset
>= masked_pc
));
412 flip_fre (char *fp
, uint32_t fre_type
, size_t *fre_size
)
415 uint8_t offset_size
, offset_cnt
;
416 size_t addr_size
, fre_info_size
= 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
);
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);
436 flip_fre_stack_offsets (fp
, offset_size
, offset_cnt
);
439 = addr_size
+ fre_info_size
+ sframe_fre_offset_bytes_size (fre_info
);
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
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. */
456 flip_sframe (char *frame_buf
, size_t buf_size
, uint32_t to_foreign
)
458 unsigned int i
, j
, prev_frep_index
;
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;
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
;
488 for (i
= 0; i
< num_fdes
; fdep
++, i
++)
490 if ((char*)fdep
>= (frame_buf
+ buf_size
))
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
;
501 bytes_flipped
+= sizeof (sframe_func_desc_entry
);
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
;
512 for (; j
< prev_frep_index
+ num_fres
; j
++)
514 if (flip_fre (fp
, fre_type
, &esz
))
516 bytes_flipped
+= esz
;
518 if (esz
== 0 || esz
> buf_size
)
524 /* All FDEs and FREs must have been endian flipped by now. */
525 if ((j
!= ihp
->sfh_num_fres
) || (bytes_flipped
!= (buf_size
- hdrsz
)))
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
;
543 hp
= &dctx
->sfd_header
;
547 /* Compare function for qsort'ing the FDE table. */
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
)
557 else if (aa
->sfde_func_start_address
> bb
->sfde_func_start_address
)
562 /* Get IDX'th offset from FRE. Set errp as applicable. */
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
);
579 *errp
= 0; /* Offset Valid. */
581 if (offset_size
== SFRAME_FRE_OFFSET_1B
)
583 int8_t *sp
= (int8_t *)fre
->fre_offsets
;
586 else if (offset_size
== SFRAME_FRE_OFFSET_2B
)
588 int16_t *sp
= (int16_t *)fre
->fre_offsets
;
593 int32_t *ip
= (int32_t *)fre
->fre_offsets
;
598 /* Free the decoder context. */
601 sframe_decoder_free (sframe_decoder_ctx
**dctxp
)
605 sframe_decoder_ctx
*dctx
= *dctxp
;
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
;
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? */
634 sframe_fde_create_func_info (uint32_t fre_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
);
647 /* Get the FRE type given the function size. */
648 /* FIXME API for linker. Revisit if its better placed somewhere else? */
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
;
665 /* Get the base reg id from the FRE info. Set errp if failure. */
668 sframe_fre_get_base_reg_id (sframe_frame_row_entry
*fre
, int *errp
)
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. */
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. */
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
)
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. */
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
)
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. */
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
);
746 sframe_frame_row_entry_copy (sframe_frame_row_entry
*dst
,
747 sframe_frame_row_entry
*src
)
751 if (dst
== NULL
|| src
== NULL
)
752 return sframe_set_errno (&err
, SFRAME_ERR_INVAL
);
754 memcpy (dst
, src
, sizeof (sframe_frame_row_entry
));
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. */
764 sframe_decode_fre_start_address (const char *fre_buf
,
765 uint32_t *fre_start_addr
,
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. */
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
;
792 memcpy (&tmp
, uit
, addr_size
);
793 saddr
= (uint32_t)tmp
;
796 return sframe_set_errno (&err
, SFRAME_ERR_INVAL
);
798 *fre_start_addr
= saddr
;
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. */
810 sframe_decode_fre (const char *fre_buf
, sframe_frame_row_entry
*fre
,
811 uint32_t fre_type
, size_t *esz
)
814 const char *stack_offsets
= NULL
;
815 size_t stack_offsets_sz
;
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
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
));
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
854 sframe_decode (const char *sf_buf
, size_t sf_size
, int *errp
)
856 const sframe_preamble
*sfp
;
858 sframe_header
*sfheaderp
;
859 sframe_decoder_ctx
*dctx
;
861 char *tempbuf
= NULL
;
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
))
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
));
895 /* Allocate a new buffer and initialize it. */
896 tempbuf
= (char *) malloc (sf_size
* sizeof (char));
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
;
904 /* Flip the rest of the SFrame section data buffer. */
905 if (flip_sframe (tempbuf
, sf_size
, 0))
908 return sframe_ret_set_errno (errp
, SFRAME_ERR_BUF_INVAL
);
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
;
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
);
931 /* Handle the SFrame Function Descriptor Entry section. */
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
);
963 if (foreign_endian
&& tempbuf
!= NULL
)
965 sframe_decoder_free (&dctx
);
970 /* Get the size of the SFrame header from the decoder context CTX. */
973 sframe_decoder_get_hdr_size (sframe_decoder_ctx
*ctx
)
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. */
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. */
993 sframe_decoder_get_version (sframe_decoder_ctx
*dctx
)
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. */
1002 sframe_decoder_get_fixed_fp_offset (sframe_decoder_ctx
*ctx
)
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. */
1011 sframe_decoder_get_fixed_ra_offset (sframe_decoder_ctx
*ctx
)
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
1020 This function is deprecated and will be removed from libsframe.so.2. */
1023 sframe_get_funcdesc_with_addr (sframe_decoder_ctx
*ctx
__attribute__ ((unused
)),
1024 int32_t addr
__attribute__ ((unused
)),
1027 return sframe_ret_set_errno (errp
, SFRAME_ERR_INVAL
);
1030 /* Find the function descriptor entry starting which contains the specified
1033 static sframe_func_desc_entry
*
1034 sframe_get_funcdesc_with_addr_internal (sframe_decoder_ctx
*ctx
, int32_t addr
,
1038 sframe_func_desc_entry
*fdp
;
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
;
1056 high
= dhp
->sfh_num_fdes
;
1060 int mid
= low
+ (high
- low
) / 2;
1062 if (fdp
[mid
].sfde_func_start_address
== addr
)
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
)
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. */
1084 sframe_fre_get_end_ip_offset (sframe_func_desc_entry
*fdep
, unsigned int i
,
1087 uint32_t end_ip_offset
;
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
);
1099 /* The end IP offset for the FRE needs to be deduced from the function
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
;
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
);
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
);
1159 return sframe_set_errno (&err
, SFRAME_ERR_FDE_INVAL
);
1162 /* Return the number of function descriptor entries in the SFrame decoder
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
);
1172 num_fdes
= dhp
->sfh_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
,
1186 uint32_t *func_size
,
1187 int32_t *func_start_address
,
1188 unsigned char *func_info
)
1190 sframe_func_desc_entry
*fdp
;
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
);
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
;
1211 sframe_decoder_get_funcdesc_v2 (sframe_decoder_ctx
*dctx
,
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
;
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
);
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
;
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
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
;
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
);
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
);
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
);
1284 /* A SFrame FDE with func size equal to zero is possible. */
1285 sframe_assert (fre
->fre_start_addr
== fdep
->sfde_func_size
);
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
;
1306 hp
= &encoder
->sfe_header
;
1310 static sframe_func_desc_entry
*
1311 sframe_encoder_get_funcdesc_at_index (sframe_encoder_ctx
*encoder
,
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
;
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
)
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
;
1355 /* Free the encoder context. */
1358 sframe_encoder_free (sframe_encoder_ctx
**encoder
)
1360 if (encoder
!= NULL
)
1362 sframe_encoder_ctx
*ectx
= *encoder
;
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
;
1387 /* Get the size of the SFrame header from the encoder ctx ENCODER. */
1390 sframe_encoder_get_hdr_size (sframe_encoder_ctx
*encoder
)
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. */
1400 sframe_encoder_get_abi_arch (sframe_encoder_ctx
*encoder
)
1402 uint8_t abi_arch
= 0;
1404 ehp
= sframe_encoder_get_header (encoder
);
1406 abi_arch
= ehp
->sfh_abi_arch
;
1410 /* Get the format version from the SFrame encoder context ENCODER. */
1413 sframe_encoder_get_version (sframe_encoder_ctx
*encoder
)
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
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
);
1430 num_fdes
= ehp
->sfh_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
)
1443 sframe_func_desc_entry
*fdep
;
1444 sframe_frame_row_entry
*ectx_frep
;
1445 size_t offsets_sz
, esz
;
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
);
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
);
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
);
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
++;
1525 if (fre_tbl
!= NULL
)
1527 encoder
->sfe_fres
= NULL
;
1528 encoder
->sfe_fre_nbytes
= 0;
1532 /* Add a new function descriptor entry with START_ADDR, FUNC_SIZE and NUM_FRES
1536 sframe_encoder_add_funcdesc (sframe_encoder_ctx
*encoder
,
1539 unsigned char func_info
,
1540 uint32_t num_fres
__attribute__ ((unused
)))
1543 sf_fde_tbl
*fd_info
;
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
;
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
);
1597 fd_info
->entry
[fd_info
->count
].sfde_func_info
= func_info
;
1599 encoder
->sfe_funcdesc
= fd_info
;
1600 ehp
->sfh_num_fdes
++;
1604 if (fd_info
!= NULL
)
1606 encoder
->sfe_funcdesc
= NULL
;
1607 ehp
->sfh_num_fdes
= 0;
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
,
1620 unsigned char func_info
,
1621 uint8_t rep_block_size
,
1622 uint32_t num_fres
__attribute__ ((unused
)))
1624 sf_fde_tbl
*fd_info
;
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
,
1636 fd_info
= encoder
->sfe_funcdesc
;
1637 fd_info
->entry
[fd_info
->count
-1].sfde_func_rep_size
= rep_block_size
;
1643 sframe_sort_funcdesc (sframe_encoder_ctx
*encoder
)
1647 ehp
= sframe_encoder_get_header (encoder
);
1648 /* Sort and write out the FDE table. */
1649 sf_fde_tbl
*fd_info
= encoder
->sfe_funcdesc
;
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
;
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. */
1665 sframe_encoder_write_fre_start_addr (char *contents
,
1666 uint32_t fre_start_addr
,
1668 size_t fre_start_addr_sz
)
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
);
1688 return sframe_set_errno (&err
, SFRAME_ERR_INVAL
);
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. */
1701 sframe_encoder_write_fre (char *contents
, sframe_frame_row_entry
*frep
,
1702 uint32_t fre_type
, size_t *esz
)
1705 size_t fre_start_addr_sz
;
1706 size_t fre_stack_offsets_sz
;
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
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
);
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. */
1745 sframe_encoder_write_sframe (sframe_encoder_ctx
*encoder
)
1750 size_t all_fdes_size
;
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
;
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
;
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. */
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
);
1809 fre_size
+= esz
; /* For debugging only. */
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
);
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
;
1842 /* Serialize the contents of the encoder and return the buffer. ENCODED_SIZE
1843 is updated to the size of the buffer. */
1846 sframe_encoder_write (sframe_encoder_ctx
*encoder
,
1847 size_t *encoded_size
, int *errp
)
1850 size_t hdrsize
, fsz
, fresz
, bufsize
;
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. */
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. */
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
;