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
, size_t *esz
)
739 const char *stack_offsets
= NULL
;
740 size_t stack_offsets_sz
;
744 if (fre_buf
== NULL
|| fre
== NULL
|| esz
== NULL
)
745 return sframe_set_errno (&err
, SFRAME_ERR_INVAL
);
747 /* Copy over the FRE start address. */
748 sframe_decode_fre_start_address (fre_buf
, &fre
->fre_start_addr
, fre_type
);
750 addr_size
= sframe_fre_start_addr_size (fre_type
);
751 fre
->fre_info
= *(uint8_t *)(fre_buf
+ addr_size
);
752 /* Sanity check as the API works closely with the binary format. */
753 sframe_assert (sizeof (fre
->fre_info
) == sizeof (uint8_t));
755 /* Cleanup the space for fre_offsets first, then copy over the valid
757 memset (fre
->fre_offsets
, 0, MAX_OFFSET_BYTES
);
758 /* Get offsets size. */
759 stack_offsets_sz
= sframe_fre_offset_bytes_size (fre
->fre_info
);
760 stack_offsets
= fre_buf
+ addr_size
+ sizeof (fre
->fre_info
);
761 memcpy (fre
->fre_offsets
, stack_offsets
, stack_offsets_sz
);
763 /* The FRE has been decoded. Use it to perform one last sanity check. */
764 fre_size
= sframe_fre_entry_size (fre
, fre_type
);
765 sframe_assert (fre_size
== (addr_size
+ sizeof (fre
->fre_info
)
766 + stack_offsets_sz
));
772 /* Decode the specified SFrame buffer CF_BUF of size CF_SIZE and return the
773 new SFrame decoder context.
775 Sets ERRP for the caller if any error. Frees up the allocated memory in
779 sframe_decode (const char *sf_buf
, size_t sf_size
, int *errp
)
781 const sframe_preamble
*sfp
;
783 sframe_header
*sfheaderp
;
784 sframe_decoder_ctx
*dctx
;
786 char *tempbuf
= NULL
;
790 int foreign_endian
= 0;
792 sframe_init_debug ();
794 if ((sf_buf
== NULL
) || (!sf_size
))
795 return sframe_ret_set_errno (errp
, SFRAME_ERR_INVAL
);
796 else if (sf_size
< sizeof (sframe_header
))
797 return sframe_ret_set_errno (errp
, SFRAME_ERR_BUF_INVAL
);
799 sfp
= (const sframe_preamble
*) sf_buf
;
801 debug_printf ("sframe_decode: magic=0x%x version=%u flags=%u\n",
802 sfp
->sfp_magic
, sfp
->sfp_version
, sfp
->sfp_flags
);
804 /* Check for foreign endianness. */
805 if (sfp
->sfp_magic
!= SFRAME_MAGIC
)
807 if (sfp
->sfp_magic
== bswap_16 (SFRAME_MAGIC
))
810 return sframe_ret_set_errno (errp
, SFRAME_ERR_BUF_INVAL
);
813 /* Initialize a new decoder context. */
814 if ((dctx
= malloc (sizeof (sframe_decoder_ctx
))) == NULL
)
815 return sframe_ret_set_errno (errp
, SFRAME_ERR_NOMEM
);
816 memset (dctx
, 0, sizeof (sframe_decoder_ctx
));
820 /* Allocate a new buffer and initialize it. */
821 tempbuf
= (char *) malloc (sf_size
* sizeof (char));
823 return sframe_ret_set_errno (errp
, SFRAME_ERR_NOMEM
);
824 memcpy (tempbuf
, sf_buf
, sf_size
);
826 /* Flip the header. */
827 sframe_header
*ihp
= (sframe_header
*) tempbuf
;
829 /* Flip the rest of the SFrame section data buffer. */
830 if (flip_sframe (tempbuf
, sf_size
, 0))
833 return sframe_ret_set_errno (errp
, SFRAME_ERR_BUF_INVAL
);
836 /* This buffer is malloc'd when endian flipping the contents of the input
837 buffer are needed. Keep a reference to it so it can be free'd up
838 later in sframe_decoder_free (). */
839 dctx
->sfd_buf
= tempbuf
;
842 frame_buf
= (char *)sf_buf
;
844 /* Handle the SFrame header. */
845 dctx
->sfd_header
= *(sframe_header
*) frame_buf
;
846 /* Validate the contents of SFrame header. */
847 sfheaderp
= &dctx
->sfd_header
;
848 if (!sframe_header_sanity_check_p (sfheaderp
))
850 sframe_ret_set_errno (errp
, SFRAME_ERR_NOMEM
);
851 goto decode_fail_free
;
853 hdrsz
= sframe_get_hdr_size (sfheaderp
);
856 /* Handle the SFrame Function Descriptor Entry section. */
858 = sfheaderp
->sfh_num_fdes
* sizeof (sframe_func_desc_entry
);
859 dctx
->sfd_funcdesc
= malloc (fidx_size
);
860 if (dctx
->sfd_funcdesc
== NULL
)
862 sframe_ret_set_errno (errp
, SFRAME_ERR_NOMEM
);
863 goto decode_fail_free
;
865 memcpy (dctx
->sfd_funcdesc
, frame_buf
, fidx_size
);
867 debug_printf ("%u total fidx size\n", fidx_size
);
869 frame_buf
+= (fidx_size
);
871 /* Handle the SFrame Frame Row Entry section. */
872 dctx
->sfd_fres
= malloc (sfheaderp
->sfh_fre_len
);
873 if (dctx
->sfd_fres
== NULL
)
875 sframe_ret_set_errno (errp
, SFRAME_ERR_NOMEM
);
876 goto decode_fail_free
;
878 memcpy (dctx
->sfd_fres
, frame_buf
, sfheaderp
->sfh_fre_len
);
880 fre_bytes
= sfheaderp
->sfh_fre_len
;
881 dctx
->sfd_fre_nbytes
= fre_bytes
;
883 debug_printf ("%u total fre bytes\n", fre_bytes
);
888 if (foreign_endian
&& tempbuf
!= NULL
)
890 sframe_decoder_free (&dctx
);
895 /* Get the size of the SFrame header from the decoder context CTX. */
898 sframe_decoder_get_hdr_size (sframe_decoder_ctx
*ctx
)
901 dhp
= sframe_decoder_get_header (ctx
);
902 return sframe_get_hdr_size (dhp
);
905 /* Get the SFrame's abi/arch info given the decoder context CTX. */
908 sframe_decoder_get_abi_arch (sframe_decoder_ctx
*ctx
)
910 sframe_header
*sframe_header
;
911 sframe_header
= sframe_decoder_get_header (ctx
);
912 return sframe_header
->sfh_abi_arch
;
915 /* Get the SFrame's fixed FP offset given the decoder context CTX. */
917 sframe_decoder_get_fixed_fp_offset (sframe_decoder_ctx
*ctx
)
920 dhp
= sframe_decoder_get_header (ctx
);
921 return dhp
->sfh_cfa_fixed_fp_offset
;
924 /* Get the SFrame's fixed RA offset given the decoder context CTX. */
926 sframe_decoder_get_fixed_ra_offset (sframe_decoder_ctx
*ctx
)
929 dhp
= sframe_decoder_get_header (ctx
);
930 return dhp
->sfh_cfa_fixed_ra_offset
;
933 /* Find the function descriptor entry starting which contains the specified
936 sframe_func_desc_entry
*
937 sframe_get_funcdesc_with_addr (sframe_decoder_ctx
*ctx
,
938 int32_t addr
, int *errp
)
941 sframe_func_desc_entry
*fdp
;
945 return sframe_ret_set_errno (errp
, SFRAME_ERR_INVAL
);
947 dhp
= sframe_decoder_get_header (ctx
);
949 if (dhp
== NULL
|| dhp
->sfh_num_fdes
== 0 || ctx
->sfd_funcdesc
== NULL
)
950 return sframe_ret_set_errno (errp
, SFRAME_ERR_DCTX_INVAL
);
951 /* If the FDE sub-section is not sorted on PCs, skip the lookup because
952 binary search cannot be used. */
953 if ((dhp
->sfh_preamble
.sfp_flags
& SFRAME_F_FDE_SORTED
) == 0)
954 return sframe_ret_set_errno (errp
, SFRAME_ERR_FDE_NOTSORTED
);
956 /* Do the binary search. */
957 fdp
= (sframe_func_desc_entry
*) ctx
->sfd_funcdesc
;
959 high
= dhp
->sfh_num_fdes
;
963 int mid
= low
+ (high
- low
) / 2;
965 if (fdp
[mid
].sfde_func_start_address
== addr
)
968 if (fdp
[mid
].sfde_func_start_address
< addr
)
970 if (mid
== (cnt
- 1)) /* Check if it's the last one. */
971 return fdp
+ (cnt
- 1);
972 else if (fdp
[mid
+1].sfde_func_start_address
> addr
)
980 return sframe_ret_set_errno (errp
, SFRAME_ERR_FDE_NOTFOUND
);
983 /* Get the end IP offset for the FRE at index i in the FDEP. The buffer FRES
984 is the starting location for the FRE. */
987 sframe_fre_get_end_ip_offset (sframe_func_desc_entry
*fdep
, unsigned int i
,
990 uint32_t end_ip_offset
;
993 fre_type
= sframe_get_fre_type (fdep
);
995 /* Get the start address of the next FRE in sequence. */
996 if (i
< fdep
->sfde_func_num_fres
- 1)
998 sframe_decode_fre_start_address (fres
, &end_ip_offset
, fre_type
);
1002 /* The end IP offset for the FRE needs to be deduced from the function
1004 end_ip_offset
= fdep
->sfde_func_size
- 1;
1006 return end_ip_offset
;
1009 /* Find the SFrame Row Entry which contains the PC. Returns
1010 SFRAME_ERR if failure. */
1013 sframe_find_fre (sframe_decoder_ctx
*ctx
, int32_t pc
,
1014 sframe_frame_row_entry
*frep
)
1016 sframe_frame_row_entry cur_fre
;
1017 sframe_func_desc_entry
*fdep
;
1018 unsigned int fre_type
, fde_type
;
1019 uint32_t end_ip_offset
, i
;
1020 int32_t start_ip
, end_ip
;
1021 int32_t func_start_addr
;
1025 /* For regular FDEs (i.e. fde_type SFRAME_FDE_TYPE_PCINC),
1026 where the start address in the FRE is an offset from start pc,
1027 use a bitmask with all bits set so that none of the address bits are
1028 ignored. In this case, we need to return the FRE where
1029 (PC >= FRE_START_ADDR) */
1030 uint64_t bitmask
= 0xffffffff;
1032 if ((ctx
== NULL
) || (frep
== NULL
))
1033 return sframe_set_errno (&err
, SFRAME_ERR_INVAL
);
1035 /* Find the FDE which contains the PC, then scan its fre entries. */
1036 fdep
= sframe_get_funcdesc_with_addr (ctx
, pc
, &err
);
1037 if (fdep
== NULL
|| ctx
->sfd_fres
== NULL
)
1038 return sframe_set_errno (&err
, SFRAME_ERR_DCTX_INVAL
);
1040 fre_type
= sframe_get_fre_type (fdep
);
1041 fde_type
= sframe_get_fde_type (fdep
);
1043 /* For FDEs for repetitive pattern of insns, we need to return the FRE
1044 such that (PC & FRE_START_ADDR_AS_MASK >= FRE_START_ADDR_AS_MASK).
1045 so, update the bitmask to the start address. */
1046 /* FIXME - the bitmask should be picked per ABI or encoded in the format
1047 somehow. For AMD64, the pltN entry stub is 16 bytes. */
1048 if (fde_type
== SFRAME_FDE_TYPE_PCMASK
)
1051 fres
= ctx
->sfd_fres
+ fdep
->sfde_func_start_fre_off
;
1052 func_start_addr
= fdep
->sfde_func_start_address
;
1054 for (i
= 0; i
< fdep
->sfde_func_num_fres
; i
++)
1056 err
= sframe_decode_fre (fres
, &cur_fre
, fre_type
, &size
);
1058 return sframe_set_errno (&err
, SFRAME_ERR_FRE_INVAL
);
1060 start_ip
= func_start_addr
+ cur_fre
.fre_start_addr
;
1061 end_ip_offset
= sframe_fre_get_end_ip_offset (fdep
, i
, fres
+ size
);
1062 end_ip
= func_start_addr
+ end_ip_offset
;
1064 if ((start_ip
& bitmask
) > (pc
& bitmask
))
1065 return sframe_set_errno (&err
, SFRAME_ERR_FRE_INVAL
);
1067 if (((start_ip
& bitmask
) <= (pc
& bitmask
))
1068 && (end_ip
& bitmask
) >= (pc
& bitmask
))
1070 sframe_frame_row_entry_copy (frep
, &cur_fre
);
1075 return sframe_set_errno (&err
, SFRAME_ERR_FDE_INVAL
);
1078 /* Return the number of function descriptor entries in the SFrame decoder
1082 sframe_decoder_get_num_fidx (sframe_decoder_ctx
*ctx
)
1084 unsigned int num_fdes
= 0;
1085 sframe_header
*dhp
= NULL
;
1086 dhp
= sframe_decoder_get_header (ctx
);
1088 num_fdes
= dhp
->sfh_num_fdes
;
1092 /* Get the data (NUM_FRES, FUNC_START_ADDRESS) from the function
1093 descriptor entry at index I'th in the decoder CTX. If failed,
1094 return error code. */
1095 /* FIXME - consolidate the args and return a
1096 sframe_func_desc_index_elem rather? */
1099 sframe_decoder_get_funcdesc (sframe_decoder_ctx
*ctx
,
1102 uint32_t *func_size
,
1103 int32_t *func_start_address
,
1104 unsigned char *func_info
)
1106 sframe_func_desc_entry
*fdp
;
1107 unsigned int num_fdes
;
1110 if (ctx
== NULL
|| func_start_address
== NULL
|| num_fres
== NULL
1111 || func_size
== NULL
)
1112 return sframe_set_errno (&err
, SFRAME_ERR_INVAL
);
1114 num_fdes
= sframe_decoder_get_num_fidx (ctx
);
1117 || ctx
->sfd_funcdesc
== NULL
)
1118 return sframe_set_errno (&err
, SFRAME_ERR_DCTX_INVAL
);
1120 fdp
= (sframe_func_desc_entry
*) ctx
->sfd_funcdesc
+ i
;
1121 *num_fres
= fdp
->sfde_func_num_fres
;
1122 *func_start_address
= fdp
->sfde_func_start_address
;
1123 *func_size
= fdp
->sfde_func_size
;
1124 *func_info
= fdp
->sfde_func_info
;
1129 /* Get the function descriptor entry at index FUNC_IDX in the decoder
1132 static sframe_func_desc_entry
*
1133 sframe_decoder_get_funcdesc_at_index (sframe_decoder_ctx
*ctx
,
1136 /* Invalid argument. No FDE will be found. */
1137 if (func_idx
>= sframe_decoder_get_num_fidx (ctx
))
1140 sframe_func_desc_entry
*fdep
;
1141 fdep
= (sframe_func_desc_entry
*) ctx
->sfd_funcdesc
;
1142 return fdep
+ func_idx
;
1145 /* Get the FRE_IDX'th FRE of the function at FUNC_IDX'th function
1146 descriptor entry in the SFrame decoder CTX. Returns error code as
1150 sframe_decoder_get_fre (sframe_decoder_ctx
*ctx
,
1151 unsigned int func_idx
,
1152 unsigned int fre_idx
,
1153 sframe_frame_row_entry
*fre
)
1155 sframe_func_desc_entry
*fdep
;
1156 sframe_frame_row_entry ifre
;
1159 unsigned int fre_type
;
1163 if (ctx
== NULL
|| fre
== NULL
)
1164 return sframe_set_errno (&err
, SFRAME_ERR_INVAL
);
1166 /* Get function descriptor entry at index func_idx. */
1167 fdep
= sframe_decoder_get_funcdesc_at_index (ctx
, func_idx
);
1170 return sframe_set_errno (&err
, SFRAME_ERR_FDE_NOTFOUND
);
1172 fre_type
= sframe_get_fre_type (fdep
);
1173 /* Now scan the FRE entries. */
1174 fres
= ctx
->sfd_fres
+ fdep
->sfde_func_start_fre_off
;
1175 for (i
= 0; i
< fdep
->sfde_func_num_fres
; i
++)
1177 /* Decode the FRE at the current position. Return it if valid. */
1178 err
= sframe_decode_fre (fres
, &ifre
, fre_type
, &esz
);
1181 if (!sframe_fre_sanity_check_p (&ifre
))
1182 return sframe_set_errno (&err
, SFRAME_ERR_FRE_INVAL
);
1184 sframe_frame_row_entry_copy (fre
, &ifre
);
1186 if (fdep
->sfde_func_size
)
1187 sframe_assert (fre
->fre_start_addr
< fdep
->sfde_func_size
);
1189 /* A SFrame FDE with func size equal to zero is possible. */
1190 sframe_assert (fre
->fre_start_addr
== fdep
->sfde_func_size
);
1198 return sframe_set_errno (&err
, SFRAME_ERR_FDE_NOTFOUND
);
1202 /* SFrame Encoder. */
1204 /* Get a reference to the ENCODER's SFrame header. */
1206 static sframe_header
*
1207 sframe_encoder_get_header (sframe_encoder_ctx
*encoder
)
1209 sframe_header
*hp
= NULL
;
1211 hp
= &encoder
->sfe_header
;
1215 static sframe_func_desc_entry
*
1216 sframe_encoder_get_funcdesc_at_index (sframe_encoder_ctx
*encoder
,
1219 sframe_func_desc_entry
*fde
= NULL
;
1220 if (func_idx
< sframe_encoder_get_num_fidx (encoder
))
1222 sf_funidx_tbl
*func_tbl
= (sf_funidx_tbl
*) encoder
->sfe_funcdesc
;
1223 fde
= func_tbl
->entry
+ func_idx
;
1228 /* Create an encoder context with the given SFrame format version VER, FLAGS
1229 and ABI information. Sets errp if failure. */
1231 sframe_encoder_ctx
*
1232 sframe_encode (unsigned char ver
, unsigned char flags
, int abi_arch
,
1233 int8_t fixed_fp_offset
, int8_t fixed_ra_offset
, int *errp
)
1236 sframe_encoder_ctx
*encoder
;
1238 if (ver
!= SFRAME_VERSION
)
1239 return sframe_ret_set_errno (errp
, SFRAME_ERR_VERSION_INVAL
);
1241 if ((encoder
= malloc (sizeof (sframe_encoder_ctx
))) == NULL
)
1242 return sframe_ret_set_errno (errp
, SFRAME_ERR_NOMEM
);
1244 memset (encoder
, 0, sizeof (sframe_encoder_ctx
));
1246 /* Get the SFrame header and update it. */
1247 hp
= sframe_encoder_get_header (encoder
);
1248 hp
->sfh_preamble
.sfp_version
= ver
;
1249 hp
->sfh_preamble
.sfp_magic
= SFRAME_MAGIC
;
1250 hp
->sfh_preamble
.sfp_flags
= flags
;
1252 hp
->sfh_abi_arch
= abi_arch
;
1253 hp
->sfh_cfa_fixed_fp_offset
= fixed_fp_offset
;
1254 hp
->sfh_cfa_fixed_ra_offset
= fixed_ra_offset
;
1259 /* Free the encoder context. */
1262 sframe_encoder_free (sframe_encoder_ctx
**encoder
)
1264 if (encoder
!= NULL
)
1266 sframe_encoder_ctx
*ectx
= *encoder
;
1270 if (ectx
->sfe_funcdesc
!= NULL
)
1272 free (ectx
->sfe_funcdesc
);
1273 ectx
->sfe_funcdesc
= NULL
;
1275 if (ectx
->sfe_fres
!= NULL
)
1277 free (ectx
->sfe_fres
);
1278 ectx
->sfe_fres
= NULL
;
1280 if (ectx
->sfe_data
!= NULL
)
1282 free (ectx
->sfe_data
);
1283 ectx
->sfe_data
= NULL
;
1291 /* Get the size of the SFrame header from the encoder ctx ENCODER. */
1294 sframe_encoder_get_hdr_size (sframe_encoder_ctx
*encoder
)
1297 ehp
= sframe_encoder_get_header (encoder
);
1298 return sframe_get_hdr_size (ehp
);
1301 /* Get the abi/arch info from the SFrame encoder context ENCODER. */
1304 sframe_encoder_get_abi_arch (sframe_encoder_ctx
*encoder
)
1306 unsigned char abi_arch
= 0;
1308 ehp
= sframe_encoder_get_header (encoder
);
1310 abi_arch
= ehp
->sfh_abi_arch
;
1314 /* Return the number of function descriptor entries in the SFrame encoder
1318 sframe_encoder_get_num_fidx (sframe_encoder_ctx
*encoder
)
1320 unsigned int num_fdes
= 0;
1321 sframe_header
*ehp
= NULL
;
1322 ehp
= sframe_encoder_get_header (encoder
);
1324 num_fdes
= ehp
->sfh_num_fdes
;
1328 /* Add an FRE to function at FUNC_IDX'th function descriptor entry in
1329 the encoder context. */
1332 sframe_encoder_add_fre (sframe_encoder_ctx
*encoder
,
1333 unsigned int func_idx
,
1334 sframe_frame_row_entry
*frep
)
1337 sframe_func_desc_entry
*fdep
;
1338 sframe_frame_row_entry
*ectx_frep
;
1339 size_t offsets_sz
, esz
;
1340 unsigned int fre_type
;
1344 if (encoder
== NULL
|| frep
== NULL
)
1345 return sframe_set_errno (&err
, SFRAME_ERR_INVAL
);
1346 if (!sframe_fre_sanity_check_p (frep
))
1347 return sframe_set_errno (&err
, SFRAME_ERR_FRE_INVAL
);
1349 /* Use func_idx to gather the function descriptor entry. */
1350 fdep
= sframe_encoder_get_funcdesc_at_index (encoder
, func_idx
);
1353 return sframe_set_errno (&err
, SFRAME_ERR_FDE_NOTFOUND
);
1355 fre_type
= sframe_get_fre_type (fdep
);
1356 sf_fre_tbl
*fre_tbl
= (sf_fre_tbl
*) encoder
->sfe_fres
;
1358 if (fre_tbl
== NULL
)
1360 fre_tbl_sz
= (sizeof (sf_fre_tbl
)
1361 + (number_of_entries
* sizeof (sframe_frame_row_entry
)));
1362 fre_tbl
= malloc (fre_tbl_sz
);
1364 if (fre_tbl
== NULL
)
1366 sframe_set_errno (&err
, SFRAME_ERR_NOMEM
);
1367 goto bad
; /* OOM. */
1369 memset (fre_tbl
, 0, fre_tbl_sz
);
1370 fre_tbl
->alloced
= number_of_entries
;
1372 else if (fre_tbl
->count
== fre_tbl
->alloced
)
1374 fre_tbl_sz
= (sizeof (sf_fre_tbl
)
1375 + ((fre_tbl
->alloced
+ number_of_entries
)
1376 * sizeof (sframe_frame_row_entry
)));
1377 fre_tbl
= realloc (fre_tbl
, fre_tbl_sz
);
1378 if (fre_tbl
== NULL
)
1380 sframe_set_errno (&err
, SFRAME_ERR_NOMEM
);
1381 goto bad
; /* OOM. */
1384 memset (&fre_tbl
->entry
[fre_tbl
->alloced
], 0,
1385 number_of_entries
* sizeof (sframe_frame_row_entry
));
1386 fre_tbl
->alloced
+= number_of_entries
;
1389 ectx_frep
= &fre_tbl
->entry
[fre_tbl
->count
];
1390 ectx_frep
->fre_start_addr
1391 = frep
->fre_start_addr
;
1392 ectx_frep
->fre_info
= frep
->fre_info
;
1394 if (fdep
->sfde_func_size
)
1395 sframe_assert (frep
->fre_start_addr
< fdep
->sfde_func_size
);
1397 /* A SFrame FDE with func size equal to zero is possible. */
1398 sframe_assert (frep
->fre_start_addr
== fdep
->sfde_func_size
);
1400 /* frep has already been sanity check'd. Get offsets size. */
1401 offsets_sz
= sframe_fre_offset_bytes_size (frep
->fre_info
);
1402 memcpy (&ectx_frep
->fre_offsets
, &frep
->fre_offsets
, offsets_sz
);
1404 esz
= sframe_fre_entry_size (frep
, fre_type
);
1407 encoder
->sfe_fres
= (void *) fre_tbl
;
1408 encoder
->sfe_fre_nbytes
+= esz
;
1410 ehp
= sframe_encoder_get_header (encoder
);
1411 ehp
->sfh_num_fres
= fre_tbl
->count
;
1413 /* Update the value of the number of FREs for the function. */
1414 fdep
->sfde_func_num_fres
++;
1419 if (fre_tbl
!= NULL
)
1421 encoder
->sfe_fres
= NULL
;
1422 encoder
->sfe_fre_nbytes
= 0;
1426 /* Add a new function descriptor entry with START_ADDR, FUNC_SIZE and NUM_FRES
1430 sframe_encoder_add_funcdesc (sframe_encoder_ctx
*encoder
,
1433 unsigned char func_info
,
1434 uint32_t num_fres
__attribute__ ((unused
)))
1437 sf_funidx_tbl
*fd_info
;
1441 /* FIXME book-keep num_fres for error checking. */
1442 if (encoder
== NULL
)
1443 return sframe_set_errno (&err
, SFRAME_ERR_INVAL
);
1445 fd_info
= (sf_funidx_tbl
*) encoder
->sfe_funcdesc
;
1446 ehp
= sframe_encoder_get_header (encoder
);
1448 if (fd_info
== NULL
)
1450 fd_tbl_sz
= (sizeof (sf_funidx_tbl
)
1451 + (number_of_entries
* sizeof (sframe_func_desc_entry
)));
1452 fd_info
= malloc (fd_tbl_sz
);
1453 if (fd_info
== NULL
)
1455 sframe_set_errno (&err
, SFRAME_ERR_NOMEM
);
1456 goto bad
; /* OOM. */
1458 memset (fd_info
, 0, fd_tbl_sz
);
1459 fd_info
->alloced
= number_of_entries
;
1461 else if (fd_info
->count
== fd_info
->alloced
)
1463 fd_tbl_sz
= (sizeof (sf_funidx_tbl
)
1464 + ((fd_info
->alloced
+ number_of_entries
)
1465 * sizeof (sframe_func_desc_entry
)));
1466 fd_info
= realloc (fd_info
, fd_tbl_sz
);
1467 if (fd_info
== NULL
)
1469 sframe_set_errno (&err
, SFRAME_ERR_NOMEM
);
1470 goto bad
; /* OOM. */
1473 memset (&fd_info
->entry
[fd_info
->alloced
], 0,
1474 number_of_entries
* sizeof (sframe_func_desc_entry
));
1475 fd_info
->alloced
+= number_of_entries
;
1478 fd_info
->entry
[fd_info
->count
].sfde_func_start_address
= start_addr
;
1479 /* Num FREs is updated as FREs are added for the function later via
1480 sframe_encoder_add_fre. */
1481 fd_info
->entry
[fd_info
->count
].sfde_func_size
= func_size
;
1482 fd_info
->entry
[fd_info
->count
].sfde_func_start_fre_off
1483 = encoder
->sfe_fre_nbytes
;
1485 // Linker optimization test code cleanup later ibhagat TODO FIXME
1486 unsigned int fre_type
= sframe_calc_fre_type (func_size
);
1488 fd_info
->entry
[fd_info
->count
].sfde_func_info
1489 = sframe_fde_func_info (fre_type
);
1491 fd_info
->entry
[fd_info
->count
].sfde_func_info
= func_info
;
1493 encoder
->sfe_funcdesc
= (void *) fd_info
;
1494 ehp
->sfh_num_fdes
++;
1498 if (fd_info
!= NULL
)
1500 encoder
->sfe_funcdesc
= NULL
;
1501 ehp
->sfh_num_fdes
= 0;
1506 sframe_sort_funcdesc (sframe_encoder_ctx
*encoder
)
1510 ehp
= sframe_encoder_get_header (encoder
);
1511 /* Sort and write out the FDE table. */
1512 sf_funidx_tbl
*fd_info
= (sf_funidx_tbl
*) encoder
->sfe_funcdesc
;
1515 qsort (fd_info
->entry
, fd_info
->count
,
1516 sizeof (sframe_func_desc_entry
), fde_func
);
1517 /* Update preamble's flags. */
1518 ehp
->sfh_preamble
.sfp_flags
|= SFRAME_F_FDE_SORTED
;
1523 /* Write the SFrame FRE start address from the in-memory FRE_START_ADDR
1524 to the buffer CONTENTS (on-disk format), given the FRE_TYPE and
1525 FRE_START_ADDR_SZ. */
1528 sframe_encoder_write_fre_start_addr (char *contents
,
1529 uint32_t fre_start_addr
,
1530 unsigned int fre_type
,
1531 size_t fre_start_addr_sz
)
1535 if (fre_type
== SFRAME_FRE_TYPE_ADDR1
)
1537 uint8_t uc
= fre_start_addr
;
1538 memcpy (contents
, &uc
, fre_start_addr_sz
);
1540 else if (fre_type
== SFRAME_FRE_TYPE_ADDR2
)
1542 uint16_t ust
= fre_start_addr
;
1543 memcpy (contents
, &ust
, fre_start_addr_sz
);
1545 else if (fre_type
== SFRAME_FRE_TYPE_ADDR4
)
1547 uint32_t uit
= fre_start_addr
;
1548 memcpy (contents
, &uit
, fre_start_addr_sz
);
1551 return sframe_set_errno (&err
, SFRAME_ERR_INVAL
);
1556 /* Write a frame row entry pointed to by FREP into the buffer CONTENTS. The
1557 size in bytes written out are updated in ESZ.
1559 This function works closely with the SFrame binary format.
1561 Returns SFRAME_ERR if failure. */
1564 sframe_encoder_write_fre (char *contents
, sframe_frame_row_entry
*frep
,
1565 unsigned int fre_type
, size_t *esz
)
1568 size_t fre_start_addr_sz
;
1569 size_t fre_stack_offsets_sz
;
1572 if (!sframe_fre_sanity_check_p (frep
))
1573 return sframe_set_errno (&err
, SFRAME_ERR_FRE_INVAL
);
1575 fre_start_addr_sz
= sframe_fre_start_addr_size (fre_type
);
1576 fre_stack_offsets_sz
= sframe_fre_offset_bytes_size (frep
->fre_info
);
1578 /* The FRE start address must be encodable in the available number of
1580 uint64_t bitmask
= SFRAME_BITMASK_OF_SIZE (fre_start_addr_sz
);
1581 sframe_assert ((uint64_t)frep
->fre_start_addr
<= bitmask
);
1583 sframe_encoder_write_fre_start_addr (contents
, frep
->fre_start_addr
,
1584 fre_type
, fre_start_addr_sz
);
1585 contents
+= fre_start_addr_sz
;
1587 memcpy (contents
, &frep
->fre_info
, sizeof (frep
->fre_info
));
1588 contents
+= sizeof (frep
->fre_info
);
1590 memcpy (contents
, frep
->fre_offsets
, fre_stack_offsets_sz
);
1591 contents
+= fre_stack_offsets_sz
;
1593 fre_sz
= sframe_fre_entry_size (frep
, fre_type
);
1594 /* Sanity checking. */
1595 sframe_assert ((fre_start_addr_sz
1596 + sizeof (frep
->fre_info
)
1597 + fre_stack_offsets_sz
) == fre_sz
);
1604 /* Serialize the core contents of the SFrame section and write out to the
1605 output buffer held in the ENCODER. Return SFRAME_ERR if failure. */
1608 sframe_encoder_write_sframe (sframe_encoder_ctx
*encoder
)
1613 size_t all_fdes_size
;
1617 unsigned char flags
;
1618 sf_funidx_tbl
*fd_info
;
1619 sf_fre_tbl
*fr_info
;
1620 uint32_t i
, num_fdes
;
1621 uint32_t j
, num_fres
;
1622 sframe_func_desc_entry
*fdep
;
1623 sframe_frame_row_entry
*frep
;
1625 unsigned int fre_type
;
1628 contents
= encoder
->sfe_data
;
1629 buf_size
= encoder
->sfe_data_size
;
1630 num_fdes
= sframe_encoder_get_num_fidx (encoder
);
1631 all_fdes_size
= num_fdes
* sizeof (sframe_func_desc_entry
);
1632 ehp
= sframe_encoder_get_header (encoder
);
1633 hdr_size
= sframe_get_hdr_size (ehp
);
1635 fd_info
= (sf_funidx_tbl
*) encoder
->sfe_funcdesc
;
1636 fr_info
= (sf_fre_tbl
*) encoder
->sfe_fres
;
1639 - buffers must be malloc'd by the caller. */
1640 if ((contents
== NULL
) || (buf_size
< hdr_size
))
1641 return sframe_set_errno (&err
, SFRAME_ERR_BUF_INVAL
);
1642 if (fr_info
== NULL
)
1643 return sframe_set_errno (&err
, SFRAME_ERR_FRE_INVAL
);
1645 /* Write out the FRE table first.
1647 Recall that read/write of FREs needs information from the corresponding
1648 FDE; the latter stores the information about the FRE type record used for
1649 the function. Also note that sorting of FDEs does NOT impact the order
1650 in which FREs are stored in the SFrame's FRE sub-section. This means
1651 that writing out FREs after sorting of FDEs will need some additional
1652 book-keeping. At this time, we can afford to avoid it by writing out
1653 the FREs first to the output buffer. */
1655 uint32_t global
= 0;
1656 uint32_t fre_index
= 0;
1658 contents
+= hdr_size
+ all_fdes_size
;
1659 for (i
= 0; i
< num_fdes
; i
++)
1661 fdep
= &fd_info
->entry
[i
];
1662 fre_type
= sframe_get_fre_type (fdep
);
1663 num_fres
= fdep
->sfde_func_num_fres
;
1665 for (j
= 0; j
< num_fres
; j
++)
1667 fre_index
= global
+ j
;
1668 frep
= &fr_info
->entry
[fre_index
];
1670 sframe_encoder_write_fre (contents
, frep
, fre_type
, &esz
);
1672 fre_size
+= esz
; /* For debugging only. */
1677 sframe_assert (fre_size
== ehp
->sfh_fre_len
);
1678 sframe_assert (global
== ehp
->sfh_num_fres
);
1679 sframe_assert ((size_t)(contents
- encoder
->sfe_data
) == buf_size
);
1681 /* Sort the FDE table */
1682 sframe_sort_funcdesc (encoder
);
1685 - the FDE section must have been sorted by now on the start address
1686 of each function. */
1687 flags
= ehp
->sfh_preamble
.sfp_flags
;
1688 if (!(flags
& SFRAME_F_FDE_SORTED
)
1689 || (fd_info
== NULL
))
1690 return sframe_set_errno (&err
, SFRAME_ERR_FDE_INVAL
);
1692 contents
= encoder
->sfe_data
;
1693 /* Write out the SFrame header. The SFrame header in the encoder
1694 object has already been updated with correct offsets by the caller. */
1695 memcpy (contents
, ehp
, hdr_size
);
1696 contents
+= hdr_size
;
1698 /* Write out the FDE table sorted on funtion start address. */
1699 memcpy (contents
, fd_info
->entry
, all_fdes_size
);
1700 contents
+= all_fdes_size
;
1705 /* Serialize the contents of the encoder and return the buffer. ENCODED_SIZE
1706 is updated to the size of the buffer. */
1709 sframe_encoder_write (sframe_encoder_ctx
*encoder
,
1710 size_t *encoded_size
, int *errp
)
1713 size_t hdrsize
, fsz
, fresz
, bufsize
;
1716 /* Initialize the encoded_size to zero. This makes it simpler to just
1717 return from the function in case of failure. Free'ing up of
1718 encoder->sfe_data is the responsibility of the caller. */
1721 if (encoder
== NULL
|| encoded_size
== NULL
|| errp
== NULL
)
1722 return sframe_ret_set_errno (errp
, SFRAME_ERR_INVAL
);
1724 ehp
= sframe_encoder_get_header (encoder
);
1725 hdrsize
= sframe_get_hdr_size (ehp
);
1726 fsz
= sframe_encoder_get_num_fidx (encoder
)
1727 * sizeof (sframe_func_desc_entry
);
1728 fresz
= encoder
->sfe_fre_nbytes
;
1730 /* The total size of buffer is the sum of header, SFrame Function Descriptor
1731 Entries section and the FRE section. */
1732 bufsize
= hdrsize
+ fsz
+ fresz
;
1733 encoder
->sfe_data
= (char *) malloc (bufsize
);
1734 if (encoder
->sfe_data
== NULL
)
1735 return sframe_ret_set_errno (errp
, SFRAME_ERR_NOMEM
);
1736 encoder
->sfe_data_size
= bufsize
;
1738 /* Update the information in the SFrame header. */
1739 /* SFrame FDE section follows immediately after the header. */
1740 ehp
->sfh_fdeoff
= 0;
1741 /* SFrame FRE section follows immediately after the SFrame FDE section. */
1742 ehp
->sfh_freoff
= fsz
;
1743 ehp
->sfh_fre_len
= fresz
;
1745 foreign_endian
= need_swapping (ehp
->sfh_abi_arch
);
1747 /* Write out the FDE Index and the FRE table in the sfe_data. */
1748 if (sframe_encoder_write_sframe (encoder
))
1749 return sframe_ret_set_errno (errp
, SFRAME_ERR_BUF_INVAL
);
1751 /* Endian flip the contents if necessary. */
1754 if (flip_sframe (encoder
->sfe_data
, bufsize
, 1))
1755 return sframe_ret_set_errno (errp
, SFRAME_ERR_BUF_INVAL
);
1756 flip_header ((sframe_header
*)encoder
->sfe_data
);
1759 *encoded_size
= bufsize
;
1760 return encoder
->sfe_data
;