1 /* sframe.c - SFrame decoder/encoder.
3 Copyright (C) 2022-2023 Free Software Foundation, Inc.
5 This file is part of libsframe.
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program. If not, see <http://www.gnu.org/licenses/>. */
25 #include "sframe-impl.h"
28 typedef struct sf_funidx_tbl
32 sframe_func_desc_entry entry
[1];
35 typedef struct sf_fre_tbl
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 unsigned int 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 unsigned int 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
)
211 || ((hp
->sfh_preamble
.sfp_flags
| all_flags
) != all_flags
))
214 /* Check offsets are valid. */
215 if (hp
->sfh_fdeoff
> hp
->sfh_freoff
)
221 /* Flip the start address pointed to by FP. */
224 flip_fre_start_address (char *fp
, unsigned int fre_type
)
226 void *start
= (void*)fp
;
227 if (fre_type
== SFRAME_FRE_TYPE_ADDR2
)
229 unsigned short *start_addr
= (unsigned short *)(start
);
230 swap_thing (*start_addr
);
232 else if (fre_type
== SFRAME_FRE_TYPE_ADDR4
)
234 uint32_t *start_addr
= (uint32_t *)(start
);
235 swap_thing (*start_addr
);
240 flip_fre_stack_offsets (char *fp
, uint8_t offset_size
, uint8_t offset_cnt
)
243 void *offsets
= (void *)fp
;
245 if (offset_size
== SFRAME_FRE_OFFSET_2B
)
247 unsigned short *ust
= (unsigned short *)offsets
;
248 for (j
= offset_cnt
; j
> 0; ust
++, j
--)
251 else if (offset_size
== SFRAME_FRE_OFFSET_4B
)
253 uint32_t *uit
= (uint32_t *)offsets
;
254 for (j
= offset_cnt
; j
> 0; uit
++, j
--)
259 /* Get the FRE start address size, given the FRE_TYPE. */
262 sframe_fre_start_addr_size (unsigned int fre_type
)
264 size_t addr_size
= 0;
267 case SFRAME_FRE_TYPE_ADDR1
:
270 case SFRAME_FRE_TYPE_ADDR2
:
273 case SFRAME_FRE_TYPE_ADDR4
:
277 /* No other value is expected. */
284 /* Check if the FREP has valid data. */
287 sframe_fre_sanity_check_p (sframe_frame_row_entry
*frep
)
289 uint8_t offset_size
, offset_cnt
;
295 fre_info
= frep
->fre_info
;
296 offset_size
= sframe_fre_get_offset_size (fre_info
);
298 if (offset_size
!= SFRAME_FRE_OFFSET_1B
299 && offset_size
!= SFRAME_FRE_OFFSET_2B
300 && offset_size
!= SFRAME_FRE_OFFSET_4B
)
303 offset_cnt
= sframe_fre_get_offset_count (fre_info
);
310 /* Get FRE_INFO's offset size in bytes. */
313 sframe_fre_offset_bytes_size (uint8_t fre_info
)
315 uint8_t offset_size
, offset_cnt
;
317 offset_size
= sframe_fre_get_offset_size (fre_info
);
319 debug_printf ("offset_size = %u\n", offset_size
);
321 offset_cnt
= sframe_fre_get_offset_count (fre_info
);
323 if (offset_size
== SFRAME_FRE_OFFSET_2B
324 || offset_size
== SFRAME_FRE_OFFSET_4B
) /* 2 or 4 bytes. */
325 return (offset_cnt
* (offset_size
* 2));
330 /* Get total size in bytes to represent FREP in the binary format. This
331 includes the starting address, FRE info, and all the offsets. */
334 sframe_fre_entry_size (sframe_frame_row_entry
*frep
, unsigned int fre_type
)
339 uint8_t fre_info
= frep
->fre_info
;
340 size_t addr_size
= sframe_fre_start_addr_size (fre_type
);
342 return (addr_size
+ sizeof (frep
->fre_info
)
343 + sframe_fre_offset_bytes_size (fre_info
));
347 flip_fre (char *fp
, unsigned int fre_type
, size_t *fre_size
)
350 uint8_t offset_size
, offset_cnt
;
351 size_t addr_size
, fre_info_size
= 0;
354 if (fre_size
== NULL
)
355 return sframe_set_errno (&err
, SFRAME_ERR_INVAL
);
357 flip_fre_start_address (fp
, fre_type
);
359 /* Advance the buffer pointer to where the FRE info is. */
360 addr_size
= sframe_fre_start_addr_size (fre_type
);
363 /* FRE info is uint8_t. No need to flip. */
364 fre_info
= *(uint8_t*)fp
;
365 offset_size
= sframe_fre_get_offset_size (fre_info
);
366 offset_cnt
= sframe_fre_get_offset_count (fre_info
);
368 /* Advance the buffer pointer to where the stack offsets are. */
369 fre_info_size
= sizeof (uint8_t);
371 flip_fre_stack_offsets (fp
, offset_size
, offset_cnt
);
374 = addr_size
+ fre_info_size
+ sframe_fre_offset_bytes_size (fre_info
);
379 /* Endian flip the contents of FRAME_BUF of size BUF_SIZE.
380 The SFrame header in the FRAME_BUF must be endian flipped prior to
383 Endian flipping at decode time vs encode time have different needs. At
384 encode time, the frame_buf is in host endianness, and hence, values should
385 be read up before the buffer is changed to foreign endianness. This change
386 of behaviour is specified via TO_FOREIGN arg.
388 If an error code is returned, the buffer should not be used. */
391 flip_sframe (char *frame_buf
, size_t buf_size
, uint32_t to_foreign
)
393 unsigned int i
, j
, prev_frep_index
;
397 sframe_func_desc_entry
*fdep
;
398 unsigned int num_fdes
= 0;
399 unsigned int num_fres
= 0;
400 unsigned int fre_type
= 0;
401 uint32_t fre_offset
= 0;
405 /* For error checking. */
406 size_t bytes_flipped
= 0;
408 /* Header must be in host endianness at this time. */
409 ihp
= (sframe_header
*)frame_buf
;
411 if (!sframe_header_sanity_check_p (ihp
))
412 return sframe_set_errno (&err
, SFRAME_ERR_BUF_INVAL
);
414 /* The contents of the SFrame header are safe to read. Get the number of
415 FDEs and the first FDE in the buffer. */
416 hdrsz
= sframe_get_hdr_size (ihp
);
417 num_fdes
= ihp
->sfh_num_fdes
;
418 fdes
= frame_buf
+ hdrsz
+ ihp
->sfh_fdeoff
;
419 fdep
= (sframe_func_desc_entry
*)fdes
;
423 for (i
= 0; i
< num_fdes
; fdep
++, i
++)
425 if ((char*)fdep
>= (frame_buf
+ buf_size
))
430 num_fres
= fdep
->sfde_func_num_fres
;
431 fre_type
= sframe_get_fre_type (fdep
);
432 fre_offset
= fdep
->sfde_func_start_fre_off
;
436 bytes_flipped
+= sizeof (sframe_func_desc_entry
);
440 num_fres
= fdep
->sfde_func_num_fres
;
441 fre_type
= sframe_get_fre_type (fdep
);
442 fre_offset
= fdep
->sfde_func_start_fre_off
;
445 fp
= frame_buf
+ sframe_get_hdr_size (ihp
) + ihp
->sfh_freoff
;
447 for (; j
< prev_frep_index
+ num_fres
; j
++)
449 if (flip_fre (fp
, fre_type
, &esz
))
451 bytes_flipped
+= esz
;
453 if (esz
== 0 || esz
> buf_size
)
459 /* All FDEs and FREs must have been endian flipped by now. */
460 if ((j
!= ihp
->sfh_num_fres
) || (bytes_flipped
!= (buf_size
- hdrsz
)))
469 /* The SFrame Decoder. */
471 /* Get SFrame header from the given decoder context DCTX. */
473 static sframe_header
*
474 sframe_decoder_get_header (sframe_decoder_ctx
*dctx
)
476 sframe_header
*hp
= NULL
;
478 hp
= &dctx
->sfd_header
;
482 /* Compare function for qsort'ing the FDE table. */
485 fde_func (const void *p1
, const void *p2
)
487 const sframe_func_desc_entry
*aa
= p1
;
488 const sframe_func_desc_entry
*bb
= p2
;
490 if (aa
->sfde_func_start_address
< bb
->sfde_func_start_address
)
492 else if (aa
->sfde_func_start_address
> bb
->sfde_func_start_address
)
497 /* Get IDX'th offset from FRE. Set errp as applicable. */
500 sframe_get_fre_offset (sframe_frame_row_entry
*fre
, int idx
, int *errp
)
502 uint8_t offset_cnt
, offset_size
;
504 if (fre
== NULL
|| !sframe_fre_sanity_check_p (fre
))
505 return sframe_set_errno (errp
, SFRAME_ERR_FRE_INVAL
);
507 offset_cnt
= sframe_fre_get_offset_count (fre
->fre_info
);
508 offset_size
= sframe_fre_get_offset_size (fre
->fre_info
);
510 if (offset_cnt
< idx
+ 1)
511 return sframe_set_errno (errp
, SFRAME_ERR_FREOFFSET_NOPRESENT
);
514 *errp
= 0; /* Offset Valid. */
516 if (offset_size
== SFRAME_FRE_OFFSET_1B
)
518 int8_t *sp
= (int8_t *)fre
->fre_offsets
;
521 else if (offset_size
== SFRAME_FRE_OFFSET_2B
)
523 int16_t *sp
= (int16_t *)fre
->fre_offsets
;
528 int32_t *ip
= (int32_t *)fre
->fre_offsets
;
533 /* Free the decoder context. */
536 sframe_decoder_free (sframe_decoder_ctx
**dctxp
)
540 sframe_decoder_ctx
*dctx
= *dctxp
;
544 if (dctx
->sfd_funcdesc
!= NULL
)
546 free (dctx
->sfd_funcdesc
);
547 dctx
->sfd_funcdesc
= NULL
;
549 if (dctx
->sfd_fres
!= NULL
)
551 free (dctx
->sfd_fres
);
552 dctx
->sfd_fres
= NULL
;
554 if (dctx
->sfd_buf
!= NULL
)
556 free (dctx
->sfd_buf
);
557 dctx
->sfd_buf
= NULL
;
565 /* Create an FDE function info byte given an FRE_TYPE and an FDE_TYPE. */
566 /* FIXME API for linker. Revisit if its better placed somewhere else? */
569 sframe_fde_create_func_info (unsigned int fre_type
,
570 unsigned int fde_type
)
572 unsigned char func_info
;
573 sframe_assert (fre_type
== SFRAME_FRE_TYPE_ADDR1
574 || fre_type
== SFRAME_FRE_TYPE_ADDR2
575 || fre_type
== SFRAME_FRE_TYPE_ADDR4
);
576 sframe_assert (fde_type
== SFRAME_FDE_TYPE_PCINC
577 || fde_type
== SFRAME_FDE_TYPE_PCMASK
);
578 func_info
= SFRAME_V1_FUNC_INFO (fde_type
, fre_type
);
582 /* Get the FRE type given the function size. */
583 /* FIXME API for linker. Revisit if its better placed somewhere else? */
586 sframe_calc_fre_type (size_t func_size
)
588 unsigned int fre_type
= 0;
589 if (func_size
< SFRAME_FRE_TYPE_ADDR1_LIMIT
)
590 fre_type
= SFRAME_FRE_TYPE_ADDR1
;
591 else if (func_size
< SFRAME_FRE_TYPE_ADDR2_LIMIT
)
592 fre_type
= SFRAME_FRE_TYPE_ADDR2
;
593 /* Adjust the check a bit so that it remains warning-free but meaningful
594 on 32-bit systems. */
595 else if (func_size
<= (size_t) (SFRAME_FRE_TYPE_ADDR4_LIMIT
- 1))
596 fre_type
= SFRAME_FRE_TYPE_ADDR4
;
600 /* Get the base reg id from the FRE info. Set errp if failure. */
603 sframe_fre_get_base_reg_id (sframe_frame_row_entry
*fre
, int *errp
)
606 return sframe_set_errno (errp
, SFRAME_ERR_FRE_INVAL
);
608 uint8_t fre_info
= fre
->fre_info
;
609 return SFRAME_V1_FRE_CFA_BASE_REG_ID (fre_info
);
612 /* Get the CFA offset from the FRE. If the offset is invalid, sets errp. */
615 sframe_fre_get_cfa_offset (sframe_decoder_ctx
*dctx ATTRIBUTE_UNUSED
,
616 sframe_frame_row_entry
*fre
, int *errp
)
618 return sframe_get_fre_offset (fre
, SFRAME_FRE_CFA_OFFSET_IDX
, errp
);
621 /* Get the FP offset from the FRE. If the offset is invalid, sets errp. */
624 sframe_fre_get_fp_offset (sframe_decoder_ctx
*dctx
,
625 sframe_frame_row_entry
*fre
, int *errp
)
627 uint32_t fp_offset_idx
= 0;
628 sframe_header
*dhp
= sframe_decoder_get_header (dctx
);
629 /* If the FP offset is not being tracked, return an error code so the caller
630 can gather the fixed FP offset from the SFrame header. */
631 if (dhp
->sfh_cfa_fixed_fp_offset
!= SFRAME_CFA_FIXED_FP_INVALID
)
632 return sframe_set_errno (errp
, SFRAME_ERR_FREOFFSET_NOPRESENT
);
634 /* In some ABIs, the stack offset to recover RA (using the CFA) from is
635 fixed (like AMD64). In such cases, the stack offset to recover FP will
636 appear at the second index. */
637 fp_offset_idx
= ((dhp
->sfh_cfa_fixed_ra_offset
!= SFRAME_CFA_FIXED_RA_INVALID
)
638 ? SFRAME_FRE_RA_OFFSET_IDX
639 : SFRAME_FRE_FP_OFFSET_IDX
);
640 return sframe_get_fre_offset (fre
, fp_offset_idx
, errp
);
643 /* Get the RA offset from the FRE. If the offset is invalid, sets errp. */
646 sframe_fre_get_ra_offset (sframe_decoder_ctx
*dctx
,
647 sframe_frame_row_entry
*fre
, int *errp
)
649 sframe_header
*dhp
= sframe_decoder_get_header (dctx
);
650 /* If the RA offset was not being tracked, return an error code so the caller
651 can gather the fixed RA offset from the SFrame header. */
652 if (dhp
->sfh_cfa_fixed_ra_offset
!= SFRAME_CFA_FIXED_RA_INVALID
)
653 return sframe_set_errno (errp
, SFRAME_ERR_FREOFFSET_NOPRESENT
);
655 /* Otherwise, get the RA offset from the FRE. */
656 return sframe_get_fre_offset (fre
, SFRAME_FRE_RA_OFFSET_IDX
, errp
);
659 /* Get whether the RA is mangled. */
662 sframe_fre_get_ra_mangled_p (sframe_decoder_ctx
*dctx ATTRIBUTE_UNUSED
,
663 sframe_frame_row_entry
*fre
, int *errp
)
665 if (fre
== NULL
|| !sframe_fre_sanity_check_p (fre
))
666 return sframe_set_errno (errp
, SFRAME_ERR_FRE_INVAL
);
668 return sframe_get_fre_ra_mangled_p (fre
->fre_info
);
672 sframe_frame_row_entry_copy (sframe_frame_row_entry
*dst
, sframe_frame_row_entry
*src
)
676 if (dst
== NULL
|| src
== NULL
)
677 return sframe_set_errno (&err
, SFRAME_ERR_INVAL
);
679 memcpy (dst
, src
, sizeof (sframe_frame_row_entry
));
683 /* Decode the SFrame FRE start address offset value from FRE_BUF in on-disk
684 binary format, given the FRE_TYPE. Updates the FRE_START_ADDR.
686 Returns 0 on success, SFRAME_ERR otherwise. */
689 sframe_decode_fre_start_address (const char *fre_buf
,
690 uint32_t *fre_start_addr
,
691 unsigned int fre_type
)
695 size_t addr_size
= 0;
697 addr_size
= sframe_fre_start_addr_size (fre_type
);
699 if (fre_type
== SFRAME_FRE_TYPE_ADDR1
)
701 uint8_t *uc
= (uint8_t *)fre_buf
;
702 saddr
= (uint32_t)*uc
;
704 else if (fre_type
== SFRAME_FRE_TYPE_ADDR2
)
706 uint16_t *ust
= (uint16_t *)fre_buf
;
707 /* SFrame is an unaligned on-disk format. Using memcpy helps avoid the
708 use of undesirable unaligned loads. See PR libsframe/29856. */
710 memcpy (&tmp
, ust
, addr_size
);
711 saddr
= (uint32_t)tmp
;
713 else if (fre_type
== SFRAME_FRE_TYPE_ADDR4
)
715 uint32_t *uit
= (uint32_t *)fre_buf
;
717 memcpy (&tmp
, uit
, addr_size
);
718 saddr
= (uint32_t)tmp
;
721 return sframe_set_errno (&err
, SFRAME_ERR_INVAL
);
723 *fre_start_addr
= saddr
;
727 /* Decode a frame row entry FRE which starts at location FRE_BUF. The function
728 updates ESZ to the size of the FRE as stored in the binary format.
730 This function works closely with the SFrame binary format.
732 Returns SFRAME_ERR if failure. */
735 sframe_decode_fre (const char *fre_buf
, sframe_frame_row_entry
*fre
,
736 unsigned int fre_type
,
740 void *stack_offsets
= NULL
;
741 size_t stack_offsets_sz
;
745 if (fre_buf
== NULL
|| fre
== NULL
|| esz
== NULL
)
746 return sframe_set_errno (&err
, SFRAME_ERR_INVAL
);
748 /* Copy over the FRE start address. */
749 sframe_decode_fre_start_address (fre_buf
, &fre
->fre_start_addr
, fre_type
);
751 addr_size
= sframe_fre_start_addr_size (fre_type
);
752 fre
->fre_info
= *(uint8_t *)(fre_buf
+ addr_size
);
753 /* Sanity check as the API works closely with the binary format. */
754 sframe_assert (sizeof (fre
->fre_info
) == sizeof (uint8_t));
756 /* Cleanup the space for fre_offsets first, then copy over the valid
758 memset (fre
->fre_offsets
, 0, MAX_OFFSET_BYTES
);
759 /* Get offsets size. */
760 stack_offsets_sz
= sframe_fre_offset_bytes_size (fre
->fre_info
);
761 stack_offsets
= (unsigned char *)fre_buf
+ addr_size
+ sizeof (fre
->fre_info
);
762 memcpy (fre
->fre_offsets
, stack_offsets
, stack_offsets_sz
);
764 /* The FRE has been decoded. Use it to perform one last sanity check. */
765 fre_size
= sframe_fre_entry_size (fre
, fre_type
);
766 sframe_assert (fre_size
== (addr_size
+ sizeof (fre
->fre_info
)
767 + stack_offsets_sz
));
773 /* Decode the specified SFrame buffer CF_BUF of size CF_SIZE and return the
774 new SFrame decoder context.
776 Sets ERRP for the caller if any error. Frees up the allocated memory in
780 sframe_decode (const char *sf_buf
, size_t sf_size
, int *errp
)
782 const sframe_preamble
*sfp
;
784 sframe_header
*sfheaderp
;
785 sframe_decoder_ctx
*dctx
;
787 char *tempbuf
= NULL
;
791 int foreign_endian
= 0;
793 sframe_init_debug ();
795 if ((sf_buf
== NULL
) || (!sf_size
))
796 return sframe_ret_set_errno (errp
, SFRAME_ERR_INVAL
);
797 else if (sf_size
< sizeof (sframe_header
))
798 return sframe_ret_set_errno (errp
, SFRAME_ERR_BUF_INVAL
);
800 sfp
= (const sframe_preamble
*) sf_buf
;
802 debug_printf ("sframe_decode: magic=0x%x version=%u flags=%u\n",
803 sfp
->sfp_magic
, sfp
->sfp_version
, sfp
->sfp_flags
);
805 /* Check for foreign endianness. */
806 if (sfp
->sfp_magic
!= SFRAME_MAGIC
)
808 if (sfp
->sfp_magic
== bswap_16 (SFRAME_MAGIC
))
811 return sframe_ret_set_errno (errp
, SFRAME_ERR_BUF_INVAL
);
814 /* Initialize a new decoder context. */
815 if ((dctx
= malloc (sizeof (sframe_decoder_ctx
))) == NULL
)
816 return sframe_ret_set_errno (errp
, SFRAME_ERR_NOMEM
);
817 memset (dctx
, 0, sizeof (sframe_decoder_ctx
));
821 /* Allocate a new buffer and initialize it. */
822 tempbuf
= (char *) malloc (sf_size
* sizeof (char));
824 return sframe_ret_set_errno (errp
, SFRAME_ERR_NOMEM
);
825 memcpy (tempbuf
, sf_buf
, sf_size
);
827 /* Flip the header. */
828 sframe_header
*ihp
= (sframe_header
*) tempbuf
;
830 /* Flip the rest of the SFrame section data buffer. */
831 if (flip_sframe (tempbuf
, sf_size
, 0))
834 return sframe_ret_set_errno (errp
, SFRAME_ERR_BUF_INVAL
);
837 /* This buffer is malloc'd when endian flipping the contents of the input
838 buffer are needed. Keep a reference to it so it can be free'd up
839 later in sframe_decoder_free (). */
840 dctx
->sfd_buf
= tempbuf
;
843 frame_buf
= (char *)sf_buf
;
845 /* Handle the SFrame header. */
846 dctx
->sfd_header
= *(sframe_header
*) frame_buf
;
847 /* Validate the contents of SFrame header. */
848 sfheaderp
= &dctx
->sfd_header
;
849 if (!sframe_header_sanity_check_p (sfheaderp
))
851 sframe_ret_set_errno (errp
, SFRAME_ERR_NOMEM
);
852 goto decode_fail_free
;
854 hdrsz
= sframe_get_hdr_size (sfheaderp
);
857 /* Handle the SFrame Function Descriptor Entry section. */
859 = sfheaderp
->sfh_num_fdes
* sizeof (sframe_func_desc_entry
);
860 dctx
->sfd_funcdesc
= malloc (fidx_size
);
861 if (dctx
->sfd_funcdesc
== NULL
)
863 sframe_ret_set_errno (errp
, SFRAME_ERR_NOMEM
);
864 goto decode_fail_free
;
866 memcpy (dctx
->sfd_funcdesc
, frame_buf
, fidx_size
);
868 debug_printf ("%u total fidx size\n", fidx_size
);
870 frame_buf
+= (fidx_size
);
872 /* Handle the SFrame Frame Row Entry section. */
873 dctx
->sfd_fres
= malloc (sfheaderp
->sfh_fre_len
);
874 if (dctx
->sfd_fres
== NULL
)
876 sframe_ret_set_errno (errp
, SFRAME_ERR_NOMEM
);
877 goto decode_fail_free
;
879 memcpy (dctx
->sfd_fres
, frame_buf
, sfheaderp
->sfh_fre_len
);
881 fre_bytes
= sfheaderp
->sfh_fre_len
;
882 dctx
->sfd_fre_nbytes
= fre_bytes
;
884 debug_printf ("%u total fre bytes\n", fre_bytes
);
889 if (foreign_endian
&& tempbuf
!= NULL
)
891 sframe_decoder_free (&dctx
);
896 /* Get the size of the SFrame header from the decoder context CTX. */
899 sframe_decoder_get_hdr_size (sframe_decoder_ctx
*ctx
)
902 dhp
= sframe_decoder_get_header (ctx
);
903 return sframe_get_hdr_size (dhp
);
906 /* Get the SFrame's abi/arch info given the decoder context CTX. */
909 sframe_decoder_get_abi_arch (sframe_decoder_ctx
*ctx
)
911 sframe_header
*sframe_header
;
912 sframe_header
= sframe_decoder_get_header (ctx
);
913 return sframe_header
->sfh_abi_arch
;
916 /* Get the SFrame's fixed FP offset given the decoder context CTX. */
918 sframe_decoder_get_fixed_fp_offset (sframe_decoder_ctx
*ctx
)
921 dhp
= sframe_decoder_get_header (ctx
);
922 return dhp
->sfh_cfa_fixed_fp_offset
;
925 /* Get the SFrame's fixed RA offset given the decoder context CTX. */
927 sframe_decoder_get_fixed_ra_offset (sframe_decoder_ctx
*ctx
)
930 dhp
= sframe_decoder_get_header (ctx
);
931 return dhp
->sfh_cfa_fixed_ra_offset
;
934 /* Find the function descriptor entry starting which contains the specified
937 sframe_func_desc_entry
*
938 sframe_get_funcdesc_with_addr (sframe_decoder_ctx
*ctx
,
939 int32_t addr
, int *errp
)
942 sframe_func_desc_entry
*fdp
;
946 return sframe_ret_set_errno (errp
, SFRAME_ERR_INVAL
);
948 dhp
= sframe_decoder_get_header (ctx
);
950 if (dhp
== NULL
|| dhp
->sfh_num_fdes
== 0 || ctx
->sfd_funcdesc
== NULL
)
951 return sframe_ret_set_errno (errp
, SFRAME_ERR_DCTX_INVAL
);
952 /* If the FDE sub-section is not sorted on PCs, skip the lookup because
953 binary search cannot be used. */
954 if ((dhp
->sfh_preamble
.sfp_flags
& SFRAME_F_FDE_SORTED
) == 0)
955 return sframe_ret_set_errno (errp
, SFRAME_ERR_FDE_NOTSORTED
);
957 /* Do the binary search. */
958 fdp
= (sframe_func_desc_entry
*) ctx
->sfd_funcdesc
;
960 high
= dhp
->sfh_num_fdes
;
964 int mid
= low
+ (high
- low
) / 2;
966 if (fdp
[mid
].sfde_func_start_address
== addr
)
969 if (fdp
[mid
].sfde_func_start_address
< addr
)
971 if (mid
== (cnt
- 1)) /* Check if it's the last one. */
972 return fdp
+ (cnt
- 1);
973 else if (fdp
[mid
+1].sfde_func_start_address
> addr
)
981 return sframe_ret_set_errno (errp
, SFRAME_ERR_FDE_NOTFOUND
);
984 /* Find the SFrame Row Entry which contains the PC. Returns
985 SFRAME_ERR if failure. */
988 sframe_find_fre (sframe_decoder_ctx
*ctx
, int32_t pc
,
989 sframe_frame_row_entry
*frep
)
991 sframe_func_desc_entry
*fdep
;
992 uint32_t start_address
, i
;
993 sframe_frame_row_entry cur_fre
, next_fre
;
995 unsigned int fre_type
, fde_type
;
999 /* For regular FDEs (i.e. fde_type SFRAME_FDE_TYPE_PCINC),
1000 where the start address in the FRE is an offset from start pc,
1001 use a bitmask with all bits set so that none of the address bits are
1002 ignored. In this case, we need to return the FRE where
1003 (PC >= FRE_START_ADDR) */
1004 uint64_t bitmask
= 0xffffffff;
1006 if ((ctx
== NULL
) || (frep
== NULL
))
1007 return sframe_set_errno (&err
, SFRAME_ERR_INVAL
);
1009 /* Find the FDE which contains the PC, then scan its fre entries. */
1010 fdep
= sframe_get_funcdesc_with_addr (ctx
, pc
, &err
);
1011 if (fdep
== NULL
|| ctx
->sfd_fres
== NULL
)
1012 return sframe_set_errno (&err
, SFRAME_ERR_DCTX_INVAL
);
1014 fre_type
= sframe_get_fre_type (fdep
);
1015 fde_type
= sframe_get_fde_type (fdep
);
1017 /* For FDEs for repetitive pattern of insns, we need to return the FRE
1018 such that (PC & FRE_START_ADDR_AS_MASK >= FRE_START_ADDR_AS_MASK).
1019 so, update the bitmask to the start address. */
1020 /* FIXME - the bitmask should be picked per ABI or encoded in the format
1021 somehow. For AMD64, the pltN entry stub is 16 bytes. */
1022 if (fde_type
== SFRAME_FDE_TYPE_PCMASK
)
1025 sp
= (unsigned char *) ctx
->sfd_fres
+ fdep
->sfde_func_start_fre_off
;
1026 for (i
= 0; i
< fdep
->sfde_func_num_fres
; i
++)
1028 err
= sframe_decode_fre ((const char *)sp
, &next_fre
, fre_type
, &esz
);
1029 start_address
= next_fre
.fre_start_addr
;
1031 if (((fdep
->sfde_func_start_address
1032 + (int32_t) start_address
) & bitmask
) <= (pc
& bitmask
))
1034 sframe_frame_row_entry_copy (&cur_fre
, &next_fre
);
1036 /* Get the next FRE in sequence. */
1037 if (i
< fdep
->sfde_func_num_fres
- 1)
1040 err
= sframe_decode_fre ((const char*)sp
, &next_fre
,
1043 /* Sanity check the next FRE. */
1044 if (!sframe_fre_sanity_check_p (&next_fre
))
1045 return sframe_set_errno (&err
, SFRAME_ERR_FRE_INVAL
);
1047 size
= next_fre
.fre_start_addr
;
1049 else size
= fdep
->sfde_func_size
;
1051 /* If the cur FRE is the one that contains the PC, return it. */
1052 if (((fdep
->sfde_func_start_address
1053 + (int32_t)size
) & bitmask
) > (pc
& bitmask
))
1055 sframe_frame_row_entry_copy (frep
, &cur_fre
);
1060 return sframe_set_errno (&err
, SFRAME_ERR_FRE_INVAL
);
1062 return sframe_set_errno (&err
, SFRAME_ERR_FDE_INVAL
);
1065 /* Return the number of function descriptor entries in the SFrame decoder
1069 sframe_decoder_get_num_fidx (sframe_decoder_ctx
*ctx
)
1071 unsigned int num_fdes
= 0;
1072 sframe_header
*dhp
= NULL
;
1073 dhp
= sframe_decoder_get_header (ctx
);
1075 num_fdes
= dhp
->sfh_num_fdes
;
1079 /* Get the data (NUM_FRES, FUNC_START_ADDRESS) from the function
1080 descriptor entry at index I'th in the decoder CTX. If failed,
1081 return error code. */
1082 /* FIXME - consolidate the args and return a
1083 sframe_func_desc_index_elem rather? */
1086 sframe_decoder_get_funcdesc (sframe_decoder_ctx
*ctx
,
1089 uint32_t *func_size
,
1090 int32_t *func_start_address
,
1091 unsigned char *func_info
)
1093 sframe_func_desc_entry
*fdp
;
1094 unsigned int num_fdes
;
1097 if (ctx
== NULL
|| func_start_address
== NULL
|| num_fres
== NULL
1098 || func_size
== NULL
)
1099 return sframe_set_errno (&err
, SFRAME_ERR_INVAL
);
1101 num_fdes
= sframe_decoder_get_num_fidx (ctx
);
1104 || ctx
->sfd_funcdesc
== NULL
)
1105 return sframe_set_errno (&err
, SFRAME_ERR_DCTX_INVAL
);
1107 fdp
= (sframe_func_desc_entry
*) ctx
->sfd_funcdesc
+ i
;
1108 *num_fres
= fdp
->sfde_func_num_fres
;
1109 *func_start_address
= fdp
->sfde_func_start_address
;
1110 *func_size
= fdp
->sfde_func_size
;
1111 *func_info
= fdp
->sfde_func_info
;
1116 /* Get the function descriptor entry at index FUNC_IDX in the decoder
1119 static sframe_func_desc_entry
*
1120 sframe_decoder_get_funcdesc_at_index (sframe_decoder_ctx
*ctx
,
1123 /* Invalid argument. No FDE will be found. */
1124 if (func_idx
>= sframe_decoder_get_num_fidx (ctx
))
1127 sframe_func_desc_entry
*fdep
;
1128 fdep
= (sframe_func_desc_entry
*) ctx
->sfd_funcdesc
;
1129 return fdep
+ func_idx
;
1132 /* Get the FRE_IDX'th FRE of the function at FUNC_IDX'th function
1133 descriptor entry in the SFrame decoder CTX. Returns error code as
1137 sframe_decoder_get_fre (sframe_decoder_ctx
*ctx
,
1138 unsigned int func_idx
,
1139 unsigned int fre_idx
,
1140 sframe_frame_row_entry
*fre
)
1142 sframe_func_desc_entry
*fdep
;
1143 sframe_frame_row_entry ifre
;
1146 unsigned int fre_type
;
1150 if (ctx
== NULL
|| fre
== NULL
)
1151 return sframe_set_errno (&err
, SFRAME_ERR_INVAL
);
1153 /* Get function descriptor entry at index func_idx. */
1154 fdep
= sframe_decoder_get_funcdesc_at_index (ctx
, func_idx
);
1157 return sframe_set_errno (&err
, SFRAME_ERR_FDE_NOTFOUND
);
1159 fre_type
= sframe_get_fre_type (fdep
);
1160 /* Now scan the FRE entries. */
1161 sp
= (unsigned char *) ctx
->sfd_fres
+ fdep
->sfde_func_start_fre_off
;
1162 for (i
= 0; i
< fdep
->sfde_func_num_fres
; i
++)
1164 /* Decode the FRE at the current position. Return it if valid. */
1165 err
= sframe_decode_fre ((const char *)sp
, &ifre
, fre_type
, &esz
);
1168 if (!sframe_fre_sanity_check_p (&ifre
))
1169 return sframe_set_errno (&err
, SFRAME_ERR_FRE_INVAL
);
1171 sframe_frame_row_entry_copy (fre
, &ifre
);
1173 if (fdep
->sfde_func_size
)
1174 sframe_assert (fre
->fre_start_addr
< fdep
->sfde_func_size
);
1176 /* A SFrame FDE with func size equal to zero is possible. */
1177 sframe_assert (fre
->fre_start_addr
== fdep
->sfde_func_size
);
1185 return sframe_set_errno (&err
, SFRAME_ERR_FDE_NOTFOUND
);
1189 /* SFrame Encoder. */
1191 /* Get a reference to the ENCODER's SFrame header. */
1193 static sframe_header
*
1194 sframe_encoder_get_header (sframe_encoder_ctx
*encoder
)
1196 sframe_header
*hp
= NULL
;
1198 hp
= &encoder
->sfe_header
;
1202 static sframe_func_desc_entry
*
1203 sframe_encoder_get_funcdesc_at_index (sframe_encoder_ctx
*encoder
,
1206 sframe_func_desc_entry
*fde
= NULL
;
1207 if (func_idx
< sframe_encoder_get_num_fidx (encoder
))
1209 sf_funidx_tbl
*func_tbl
= (sf_funidx_tbl
*) encoder
->sfe_funcdesc
;
1210 fde
= func_tbl
->entry
+ func_idx
;
1215 /* Create an encoder context with the given SFrame format version VER, FLAGS
1216 and ABI information. Sets errp if failure. */
1218 sframe_encoder_ctx
*
1219 sframe_encode (unsigned char ver
, unsigned char flags
, int abi_arch
,
1220 int8_t fixed_fp_offset
, int8_t fixed_ra_offset
, int *errp
)
1223 sframe_encoder_ctx
*encoder
;
1225 if (ver
!= SFRAME_VERSION
)
1226 return sframe_ret_set_errno (errp
, SFRAME_ERR_VERSION_INVAL
);
1228 if ((encoder
= malloc (sizeof (sframe_encoder_ctx
))) == NULL
)
1229 return sframe_ret_set_errno (errp
, SFRAME_ERR_NOMEM
);
1231 memset (encoder
, 0, sizeof (sframe_encoder_ctx
));
1233 /* Get the SFrame header and update it. */
1234 hp
= sframe_encoder_get_header (encoder
);
1235 hp
->sfh_preamble
.sfp_version
= ver
;
1236 hp
->sfh_preamble
.sfp_magic
= SFRAME_MAGIC
;
1237 hp
->sfh_preamble
.sfp_flags
= flags
;
1239 hp
->sfh_abi_arch
= abi_arch
;
1240 hp
->sfh_cfa_fixed_fp_offset
= fixed_fp_offset
;
1241 hp
->sfh_cfa_fixed_ra_offset
= fixed_ra_offset
;
1246 /* Free the encoder context. */
1249 sframe_encoder_free (sframe_encoder_ctx
**encoder
)
1251 if (encoder
!= NULL
)
1253 sframe_encoder_ctx
*ectx
= *encoder
;
1257 if (ectx
->sfe_funcdesc
!= NULL
)
1259 free (ectx
->sfe_funcdesc
);
1260 ectx
->sfe_funcdesc
= NULL
;
1262 if (ectx
->sfe_fres
!= NULL
)
1264 free (ectx
->sfe_fres
);
1265 ectx
->sfe_fres
= NULL
;
1267 if (ectx
->sfe_data
!= NULL
)
1269 free (ectx
->sfe_data
);
1270 ectx
->sfe_data
= NULL
;
1278 /* Get the size of the SFrame header from the encoder ctx ENCODER. */
1281 sframe_encoder_get_hdr_size (sframe_encoder_ctx
*encoder
)
1284 ehp
= sframe_encoder_get_header (encoder
);
1285 return sframe_get_hdr_size (ehp
);
1288 /* Get the abi/arch info from the SFrame encoder context ENCODER. */
1291 sframe_encoder_get_abi_arch (sframe_encoder_ctx
*encoder
)
1293 unsigned char abi_arch
= 0;
1295 ehp
= sframe_encoder_get_header (encoder
);
1297 abi_arch
= ehp
->sfh_abi_arch
;
1301 /* Return the number of function descriptor entries in the SFrame encoder
1305 sframe_encoder_get_num_fidx (sframe_encoder_ctx
*encoder
)
1307 unsigned int num_fdes
= 0;
1308 sframe_header
*ehp
= NULL
;
1309 ehp
= sframe_encoder_get_header (encoder
);
1311 num_fdes
= ehp
->sfh_num_fdes
;
1315 /* Add an FRE to function at FUNC_IDX'th function descriptor entry in
1316 the encoder context. */
1319 sframe_encoder_add_fre (sframe_encoder_ctx
*encoder
,
1320 unsigned int func_idx
,
1321 sframe_frame_row_entry
*frep
)
1324 sframe_func_desc_entry
*fdep
;
1325 sframe_frame_row_entry
*ectx_frep
;
1326 size_t offsets_sz
, esz
;
1327 unsigned int fre_type
;
1331 if (encoder
== NULL
|| frep
== NULL
)
1332 return sframe_set_errno (&err
, SFRAME_ERR_INVAL
);
1333 if (!sframe_fre_sanity_check_p (frep
))
1334 return sframe_set_errno (&err
, SFRAME_ERR_FRE_INVAL
);
1336 /* Use func_idx to gather the function descriptor entry. */
1337 fdep
= sframe_encoder_get_funcdesc_at_index (encoder
, func_idx
);
1340 return sframe_set_errno (&err
, SFRAME_ERR_FDE_NOTFOUND
);
1342 fre_type
= sframe_get_fre_type (fdep
);
1343 sf_fre_tbl
*fre_tbl
= (sf_fre_tbl
*) encoder
->sfe_fres
;
1345 if (fre_tbl
== NULL
)
1347 fre_tbl_sz
= (sizeof (sf_fre_tbl
)
1348 + (number_of_entries
* sizeof (sframe_frame_row_entry
)));
1349 fre_tbl
= malloc (fre_tbl_sz
);
1351 if (fre_tbl
== NULL
)
1353 sframe_set_errno (&err
, SFRAME_ERR_NOMEM
);
1354 goto bad
; /* OOM. */
1356 memset (fre_tbl
, 0, fre_tbl_sz
);
1357 fre_tbl
->alloced
= number_of_entries
;
1359 else if (fre_tbl
->count
== fre_tbl
->alloced
)
1361 fre_tbl_sz
= (sizeof (sf_fre_tbl
)
1362 + ((fre_tbl
->alloced
+ number_of_entries
)
1363 * sizeof (sframe_frame_row_entry
)));
1364 fre_tbl
= realloc (fre_tbl
, fre_tbl_sz
);
1365 if (fre_tbl
== NULL
)
1367 sframe_set_errno (&err
, SFRAME_ERR_NOMEM
);
1368 goto bad
; /* OOM. */
1371 memset (&fre_tbl
->entry
[fre_tbl
->alloced
], 0,
1372 number_of_entries
* sizeof (sframe_frame_row_entry
));
1373 fre_tbl
->alloced
+= number_of_entries
;
1376 ectx_frep
= &fre_tbl
->entry
[fre_tbl
->count
];
1377 ectx_frep
->fre_start_addr
1378 = frep
->fre_start_addr
;
1379 ectx_frep
->fre_info
= frep
->fre_info
;
1381 if (fdep
->sfde_func_size
)
1382 sframe_assert (frep
->fre_start_addr
< fdep
->sfde_func_size
);
1384 /* A SFrame FDE with func size equal to zero is possible. */
1385 sframe_assert (frep
->fre_start_addr
== fdep
->sfde_func_size
);
1387 /* frep has already been sanity check'd. Get offsets size. */
1388 offsets_sz
= sframe_fre_offset_bytes_size (frep
->fre_info
);
1389 memcpy (&ectx_frep
->fre_offsets
, &frep
->fre_offsets
, offsets_sz
);
1391 esz
= sframe_fre_entry_size (frep
, fre_type
);
1394 encoder
->sfe_fres
= (void *) fre_tbl
;
1395 encoder
->sfe_fre_nbytes
+= esz
;
1397 ehp
= sframe_encoder_get_header (encoder
);
1398 ehp
->sfh_num_fres
= fre_tbl
->count
;
1400 /* Update the value of the number of FREs for the function. */
1401 fdep
->sfde_func_num_fres
++;
1406 if (fre_tbl
!= NULL
)
1408 encoder
->sfe_fres
= NULL
;
1409 encoder
->sfe_fre_nbytes
= 0;
1413 /* Add a new function descriptor entry with START_ADDR, FUNC_SIZE and NUM_FRES
1417 sframe_encoder_add_funcdesc (sframe_encoder_ctx
*encoder
,
1420 unsigned char func_info
,
1421 uint32_t num_fres
__attribute__ ((unused
)))
1424 sf_funidx_tbl
*fd_info
;
1428 /* FIXME book-keep num_fres for error checking. */
1429 if (encoder
== NULL
)
1430 return sframe_set_errno (&err
, SFRAME_ERR_INVAL
);
1432 fd_info
= (sf_funidx_tbl
*) encoder
->sfe_funcdesc
;
1433 ehp
= sframe_encoder_get_header (encoder
);
1435 if (fd_info
== NULL
)
1437 fd_tbl_sz
= (sizeof (sf_funidx_tbl
)
1438 + (number_of_entries
* sizeof (sframe_func_desc_entry
)));
1439 fd_info
= malloc (fd_tbl_sz
);
1440 if (fd_info
== NULL
)
1442 sframe_set_errno (&err
, SFRAME_ERR_NOMEM
);
1443 goto bad
; /* OOM. */
1445 memset (fd_info
, 0, fd_tbl_sz
);
1446 fd_info
->alloced
= number_of_entries
;
1448 else if (fd_info
->count
== fd_info
->alloced
)
1450 fd_tbl_sz
= (sizeof (sf_funidx_tbl
)
1451 + ((fd_info
->alloced
+ number_of_entries
)
1452 * sizeof (sframe_func_desc_entry
)));
1453 fd_info
= realloc (fd_info
, fd_tbl_sz
);
1454 if (fd_info
== NULL
)
1456 sframe_set_errno (&err
, SFRAME_ERR_NOMEM
);
1457 goto bad
; /* OOM. */
1460 memset (&fd_info
->entry
[fd_info
->alloced
], 0,
1461 number_of_entries
* sizeof (sframe_func_desc_entry
));
1462 fd_info
->alloced
+= number_of_entries
;
1465 fd_info
->entry
[fd_info
->count
].sfde_func_start_address
= start_addr
;
1466 /* Num FREs is updated as FREs are added for the function later via
1467 sframe_encoder_add_fre. */
1468 fd_info
->entry
[fd_info
->count
].sfde_func_size
= func_size
;
1469 fd_info
->entry
[fd_info
->count
].sfde_func_start_fre_off
1470 = encoder
->sfe_fre_nbytes
;
1472 // Linker optimization test code cleanup later ibhagat TODO FIXME
1473 unsigned int fre_type
= sframe_calc_fre_type (func_size
);
1475 fd_info
->entry
[fd_info
->count
].sfde_func_info
1476 = sframe_fde_func_info (fre_type
);
1478 fd_info
->entry
[fd_info
->count
].sfde_func_info
= func_info
;
1480 encoder
->sfe_funcdesc
= (void *) fd_info
;
1481 ehp
->sfh_num_fdes
++;
1485 if (fd_info
!= NULL
)
1487 encoder
->sfe_funcdesc
= NULL
;
1488 ehp
->sfh_num_fdes
= 0;
1493 sframe_sort_funcdesc (sframe_encoder_ctx
*encoder
)
1497 ehp
= sframe_encoder_get_header (encoder
);
1498 /* Sort and write out the FDE table. */
1499 sf_funidx_tbl
*fd_info
= (sf_funidx_tbl
*) encoder
->sfe_funcdesc
;
1502 qsort (fd_info
->entry
, fd_info
->count
,
1503 sizeof (sframe_func_desc_entry
), fde_func
);
1504 /* Update preamble's flags. */
1505 ehp
->sfh_preamble
.sfp_flags
|= SFRAME_F_FDE_SORTED
;
1510 /* Write the SFrame FRE start address from the in-memory FRE_START_ADDR
1511 to the buffer CONTENTS (on-disk format), given the FRE_TYPE and
1512 FRE_START_ADDR_SZ. */
1515 sframe_encoder_write_fre_start_addr (char *contents
,
1516 uint32_t fre_start_addr
,
1517 unsigned int fre_type
,
1518 size_t fre_start_addr_sz
)
1522 if (fre_type
== SFRAME_FRE_TYPE_ADDR1
)
1524 uint8_t uc
= fre_start_addr
;
1525 memcpy (contents
, &uc
, fre_start_addr_sz
);
1527 else if (fre_type
== SFRAME_FRE_TYPE_ADDR2
)
1529 uint16_t ust
= fre_start_addr
;
1530 memcpy (contents
, &ust
, fre_start_addr_sz
);
1532 else if (fre_type
== SFRAME_FRE_TYPE_ADDR4
)
1534 uint32_t uit
= fre_start_addr
;
1535 memcpy (contents
, &uit
, fre_start_addr_sz
);
1538 return sframe_set_errno (&err
, SFRAME_ERR_INVAL
);
1543 /* Write a frame row entry pointed to by FREP into the buffer CONTENTS. The
1544 size in bytes written out are updated in ESZ.
1546 This function works closely with the SFrame binary format.
1548 Returns SFRAME_ERR if failure. */
1551 sframe_encoder_write_fre (char *contents
, sframe_frame_row_entry
*frep
,
1552 unsigned int fre_type
, size_t *esz
)
1555 size_t fre_start_addr_sz
;
1556 size_t fre_stack_offsets_sz
;
1559 if (!sframe_fre_sanity_check_p (frep
))
1560 return sframe_set_errno (&err
, SFRAME_ERR_FRE_INVAL
);
1562 fre_start_addr_sz
= sframe_fre_start_addr_size (fre_type
);
1563 fre_stack_offsets_sz
= sframe_fre_offset_bytes_size (frep
->fre_info
);
1565 /* The FRE start address must be encodable in the available number of
1567 uint64_t bitmask
= SFRAME_BITMASK_OF_SIZE (fre_start_addr_sz
);
1568 sframe_assert ((uint64_t)frep
->fre_start_addr
<= bitmask
);
1570 sframe_encoder_write_fre_start_addr (contents
, frep
->fre_start_addr
,
1571 fre_type
, fre_start_addr_sz
);
1572 contents
+= fre_start_addr_sz
;
1574 memcpy (contents
, &frep
->fre_info
, sizeof (frep
->fre_info
));
1575 contents
+= sizeof (frep
->fre_info
);
1577 memcpy (contents
, frep
->fre_offsets
, fre_stack_offsets_sz
);
1578 contents
+= fre_stack_offsets_sz
;
1580 fre_sz
= sframe_fre_entry_size (frep
, fre_type
);
1581 /* Sanity checking. */
1582 sframe_assert ((fre_start_addr_sz
1583 + sizeof (frep
->fre_info
)
1584 + fre_stack_offsets_sz
) == fre_sz
);
1591 /* Serialize the core contents of the SFrame section and write out to the
1592 output buffer held in the ENCODER. Return SFRAME_ERR if failure. */
1595 sframe_encoder_write_sframe (sframe_encoder_ctx
*encoder
)
1600 size_t all_fdes_size
;
1604 unsigned char flags
;
1605 sf_funidx_tbl
*fd_info
;
1606 sf_fre_tbl
*fr_info
;
1607 uint32_t i
, num_fdes
;
1608 uint32_t j
, num_fres
;
1609 sframe_func_desc_entry
*fdep
;
1610 sframe_frame_row_entry
*frep
;
1612 unsigned int fre_type
;
1615 contents
= encoder
->sfe_data
;
1616 buf_size
= encoder
->sfe_data_size
;
1617 num_fdes
= sframe_encoder_get_num_fidx (encoder
);
1618 all_fdes_size
= num_fdes
* sizeof (sframe_func_desc_entry
);
1619 ehp
= sframe_encoder_get_header (encoder
);
1620 hdr_size
= sframe_get_hdr_size (ehp
);
1622 fd_info
= (sf_funidx_tbl
*) encoder
->sfe_funcdesc
;
1623 fr_info
= (sf_fre_tbl
*) encoder
->sfe_fres
;
1626 - buffers must be malloc'd by the caller. */
1627 if ((contents
== NULL
) || (buf_size
< hdr_size
))
1628 return sframe_set_errno (&err
, SFRAME_ERR_BUF_INVAL
);
1629 if (fr_info
== NULL
)
1630 return sframe_set_errno (&err
, SFRAME_ERR_FRE_INVAL
);
1632 /* Write out the FRE table first.
1634 Recall that read/write of FREs needs information from the corresponding
1635 FDE; the latter stores the information about the FRE type record used for
1636 the function. Also note that sorting of FDEs does NOT impact the order
1637 in which FREs are stored in the SFrame's FRE sub-section. This means
1638 that writing out FREs after sorting of FDEs will need some additional
1639 book-keeping. At this time, we can afford to avoid it by writing out
1640 the FREs first to the output buffer. */
1642 uint32_t global
= 0;
1643 uint32_t fre_index
= 0;
1645 contents
+= hdr_size
+ all_fdes_size
;
1646 for (i
= 0; i
< num_fdes
; i
++)
1648 fdep
= &fd_info
->entry
[i
];
1649 fre_type
= sframe_get_fre_type (fdep
);
1650 num_fres
= fdep
->sfde_func_num_fres
;
1652 for (j
= 0; j
< num_fres
; j
++)
1654 fre_index
= global
+ j
;
1655 frep
= &fr_info
->entry
[fre_index
];
1657 sframe_encoder_write_fre (contents
, frep
, fre_type
, &esz
);
1659 fre_size
+= esz
; /* For debugging only. */
1664 sframe_assert (fre_size
== ehp
->sfh_fre_len
);
1665 sframe_assert (global
== ehp
->sfh_num_fres
);
1666 sframe_assert ((size_t)(contents
- encoder
->sfe_data
) == buf_size
);
1668 /* Sort the FDE table */
1669 sframe_sort_funcdesc (encoder
);
1672 - the FDE section must have been sorted by now on the start address
1673 of each function. */
1674 flags
= ehp
->sfh_preamble
.sfp_flags
;
1675 if (!(flags
& SFRAME_F_FDE_SORTED
)
1676 || (fd_info
== NULL
))
1677 return sframe_set_errno (&err
, SFRAME_ERR_FDE_INVAL
);
1679 contents
= encoder
->sfe_data
;
1680 /* Write out the SFrame header. The SFrame header in the encoder
1681 object has already been updated with correct offsets by the caller. */
1682 memcpy (contents
, ehp
, hdr_size
);
1683 contents
+= hdr_size
;
1685 /* Write out the FDE table sorted on funtion start address. */
1686 memcpy (contents
, fd_info
->entry
, all_fdes_size
);
1687 contents
+= all_fdes_size
;
1692 /* Serialize the contents of the encoder and return the buffer. ENCODED_SIZE
1693 is updated to the size of the buffer. */
1696 sframe_encoder_write (sframe_encoder_ctx
*encoder
,
1697 size_t *encoded_size
, int *errp
)
1700 size_t hdrsize
, fsz
, fresz
, bufsize
;
1703 /* Initialize the encoded_size to zero. This makes it simpler to just
1704 return from the function in case of failure. Free'ing up of
1705 encoder->sfe_data is the responsibility of the caller. */
1708 if (encoder
== NULL
|| encoded_size
== NULL
|| errp
== NULL
)
1709 return sframe_ret_set_errno (errp
, SFRAME_ERR_INVAL
);
1711 ehp
= sframe_encoder_get_header (encoder
);
1712 hdrsize
= sframe_get_hdr_size (ehp
);
1713 fsz
= sframe_encoder_get_num_fidx (encoder
)
1714 * sizeof (sframe_func_desc_entry
);
1715 fresz
= encoder
->sfe_fre_nbytes
;
1717 /* The total size of buffer is the sum of header, SFrame Function Descriptor
1718 Entries section and the FRE section. */
1719 bufsize
= hdrsize
+ fsz
+ fresz
;
1720 encoder
->sfe_data
= (char *) malloc (bufsize
);
1721 if (encoder
->sfe_data
== NULL
)
1722 return sframe_ret_set_errno (errp
, SFRAME_ERR_NOMEM
);
1723 encoder
->sfe_data_size
= bufsize
;
1725 /* Update the information in the SFrame header. */
1726 /* SFrame FDE section follows immediately after the header. */
1727 ehp
->sfh_fdeoff
= 0;
1728 /* SFrame FRE section follows immediately after the SFrame FDE section. */
1729 ehp
->sfh_freoff
= fsz
;
1730 ehp
->sfh_fre_len
= fresz
;
1732 foreign_endian
= need_swapping (ehp
->sfh_abi_arch
);
1734 /* Write out the FDE Index and the FRE table in the sfe_data. */
1735 if (sframe_encoder_write_sframe (encoder
))
1736 return sframe_ret_set_errno (errp
, SFRAME_ERR_BUF_INVAL
);
1738 /* Endian flip the contents if necessary. */
1741 if (flip_sframe (encoder
->sfe_data
, bufsize
, 1))
1742 return sframe_ret_set_errno (errp
, SFRAME_ERR_BUF_INVAL
);
1743 flip_header ((sframe_header
*)encoder
->sfe_data
);
1746 *encoded_size
= bufsize
;
1747 return encoder
->sfe_data
;