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 *addr
, unsigned int fre_type
)
226 if (fre_type
== SFRAME_FRE_TYPE_ADDR2
)
228 uint16_t *start_addr
= (uint16_t *)addr
;
229 swap_thing (*start_addr
);
231 else if (fre_type
== SFRAME_FRE_TYPE_ADDR4
)
233 uint32_t *start_addr
= (uint32_t *)addr
;
234 swap_thing (*start_addr
);
239 flip_fre_stack_offsets (char *offsets
, uint8_t offset_size
, uint8_t offset_cnt
)
243 if (offset_size
== SFRAME_FRE_OFFSET_2B
)
245 uint16_t *ust
= (uint16_t *)offsets
;
246 for (j
= offset_cnt
; j
> 0; ust
++, j
--)
249 else if (offset_size
== SFRAME_FRE_OFFSET_4B
)
251 uint32_t *uit
= (uint32_t *)offsets
;
252 for (j
= offset_cnt
; j
> 0; uit
++, j
--)
257 /* Get the FRE start address size, given the FRE_TYPE. */
260 sframe_fre_start_addr_size (unsigned int fre_type
)
262 size_t addr_size
= 0;
265 case SFRAME_FRE_TYPE_ADDR1
:
268 case SFRAME_FRE_TYPE_ADDR2
:
271 case SFRAME_FRE_TYPE_ADDR4
:
275 /* No other value is expected. */
282 /* Check if the FREP has valid data. */
285 sframe_fre_sanity_check_p (sframe_frame_row_entry
*frep
)
287 uint8_t offset_size
, offset_cnt
;
293 fre_info
= frep
->fre_info
;
294 offset_size
= sframe_fre_get_offset_size (fre_info
);
296 if (offset_size
!= SFRAME_FRE_OFFSET_1B
297 && offset_size
!= SFRAME_FRE_OFFSET_2B
298 && offset_size
!= SFRAME_FRE_OFFSET_4B
)
301 offset_cnt
= sframe_fre_get_offset_count (fre_info
);
308 /* Get FRE_INFO's offset size in bytes. */
311 sframe_fre_offset_bytes_size (uint8_t fre_info
)
313 uint8_t offset_size
, offset_cnt
;
315 offset_size
= sframe_fre_get_offset_size (fre_info
);
317 debug_printf ("offset_size = %u\n", offset_size
);
319 offset_cnt
= sframe_fre_get_offset_count (fre_info
);
321 if (offset_size
== SFRAME_FRE_OFFSET_2B
322 || offset_size
== SFRAME_FRE_OFFSET_4B
) /* 2 or 4 bytes. */
323 return (offset_cnt
* (offset_size
* 2));
328 /* Get total size in bytes to represent FREP in the binary format. This
329 includes the starting address, FRE info, and all the offsets. */
332 sframe_fre_entry_size (sframe_frame_row_entry
*frep
, unsigned int fre_type
)
337 uint8_t fre_info
= frep
->fre_info
;
338 size_t addr_size
= sframe_fre_start_addr_size (fre_type
);
340 return (addr_size
+ sizeof (frep
->fre_info
)
341 + sframe_fre_offset_bytes_size (fre_info
));
345 flip_fre (char *fp
, unsigned int fre_type
, size_t *fre_size
)
348 uint8_t offset_size
, offset_cnt
;
349 size_t addr_size
, fre_info_size
= 0;
352 if (fre_size
== NULL
)
353 return sframe_set_errno (&err
, SFRAME_ERR_INVAL
);
355 flip_fre_start_address (fp
, fre_type
);
357 /* Advance the buffer pointer to where the FRE info is. */
358 addr_size
= sframe_fre_start_addr_size (fre_type
);
361 /* FRE info is uint8_t. No need to flip. */
362 fre_info
= *(uint8_t*)fp
;
363 offset_size
= sframe_fre_get_offset_size (fre_info
);
364 offset_cnt
= sframe_fre_get_offset_count (fre_info
);
366 /* Advance the buffer pointer to where the stack offsets are. */
367 fre_info_size
= sizeof (uint8_t);
369 flip_fre_stack_offsets (fp
, offset_size
, offset_cnt
);
372 = addr_size
+ fre_info_size
+ sframe_fre_offset_bytes_size (fre_info
);
377 /* Endian flip the contents of FRAME_BUF of size BUF_SIZE.
378 The SFrame header in the FRAME_BUF must be endian flipped prior to
381 Endian flipping at decode time vs encode time have different needs. At
382 encode time, the frame_buf is in host endianness, and hence, values should
383 be read up before the buffer is changed to foreign endianness. This change
384 of behaviour is specified via TO_FOREIGN arg.
386 If an error code is returned, the buffer should not be used. */
389 flip_sframe (char *frame_buf
, size_t buf_size
, uint32_t to_foreign
)
391 unsigned int i
, j
, prev_frep_index
;
395 sframe_func_desc_entry
*fdep
;
396 unsigned int num_fdes
= 0;
397 unsigned int num_fres
= 0;
398 unsigned int fre_type
= 0;
399 uint32_t fre_offset
= 0;
403 /* For error checking. */
404 size_t bytes_flipped
= 0;
406 /* Header must be in host endianness at this time. */
407 ihp
= (sframe_header
*)frame_buf
;
409 if (!sframe_header_sanity_check_p (ihp
))
410 return sframe_set_errno (&err
, SFRAME_ERR_BUF_INVAL
);
412 /* The contents of the SFrame header are safe to read. Get the number of
413 FDEs and the first FDE in the buffer. */
414 hdrsz
= sframe_get_hdr_size (ihp
);
415 num_fdes
= ihp
->sfh_num_fdes
;
416 fdes
= frame_buf
+ hdrsz
+ ihp
->sfh_fdeoff
;
417 fdep
= (sframe_func_desc_entry
*)fdes
;
421 for (i
= 0; i
< num_fdes
; fdep
++, i
++)
423 if ((char*)fdep
>= (frame_buf
+ buf_size
))
428 num_fres
= fdep
->sfde_func_num_fres
;
429 fre_type
= sframe_get_fre_type (fdep
);
430 fre_offset
= fdep
->sfde_func_start_fre_off
;
434 bytes_flipped
+= sizeof (sframe_func_desc_entry
);
438 num_fres
= fdep
->sfde_func_num_fres
;
439 fre_type
= sframe_get_fre_type (fdep
);
440 fre_offset
= fdep
->sfde_func_start_fre_off
;
443 fp
= frame_buf
+ sframe_get_hdr_size (ihp
) + ihp
->sfh_freoff
;
445 for (; j
< prev_frep_index
+ num_fres
; j
++)
447 if (flip_fre (fp
, fre_type
, &esz
))
449 bytes_flipped
+= esz
;
451 if (esz
== 0 || esz
> buf_size
)
457 /* All FDEs and FREs must have been endian flipped by now. */
458 if ((j
!= ihp
->sfh_num_fres
) || (bytes_flipped
!= (buf_size
- hdrsz
)))
467 /* The SFrame Decoder. */
469 /* Get SFrame header from the given decoder context DCTX. */
471 static sframe_header
*
472 sframe_decoder_get_header (sframe_decoder_ctx
*dctx
)
474 sframe_header
*hp
= NULL
;
476 hp
= &dctx
->sfd_header
;
480 /* Compare function for qsort'ing the FDE table. */
483 fde_func (const void *p1
, const void *p2
)
485 const sframe_func_desc_entry
*aa
= p1
;
486 const sframe_func_desc_entry
*bb
= p2
;
488 if (aa
->sfde_func_start_address
< bb
->sfde_func_start_address
)
490 else if (aa
->sfde_func_start_address
> bb
->sfde_func_start_address
)
495 /* Get IDX'th offset from FRE. Set errp as applicable. */
498 sframe_get_fre_offset (sframe_frame_row_entry
*fre
, int idx
, int *errp
)
500 uint8_t offset_cnt
, offset_size
;
502 if (fre
== NULL
|| !sframe_fre_sanity_check_p (fre
))
503 return sframe_set_errno (errp
, SFRAME_ERR_FRE_INVAL
);
505 offset_cnt
= sframe_fre_get_offset_count (fre
->fre_info
);
506 offset_size
= sframe_fre_get_offset_size (fre
->fre_info
);
508 if (offset_cnt
< idx
+ 1)
509 return sframe_set_errno (errp
, SFRAME_ERR_FREOFFSET_NOPRESENT
);
512 *errp
= 0; /* Offset Valid. */
514 if (offset_size
== SFRAME_FRE_OFFSET_1B
)
516 int8_t *sp
= (int8_t *)fre
->fre_offsets
;
519 else if (offset_size
== SFRAME_FRE_OFFSET_2B
)
521 int16_t *sp
= (int16_t *)fre
->fre_offsets
;
526 int32_t *ip
= (int32_t *)fre
->fre_offsets
;
531 /* Free the decoder context. */
534 sframe_decoder_free (sframe_decoder_ctx
**dctxp
)
538 sframe_decoder_ctx
*dctx
= *dctxp
;
542 if (dctx
->sfd_funcdesc
!= NULL
)
544 free (dctx
->sfd_funcdesc
);
545 dctx
->sfd_funcdesc
= NULL
;
547 if (dctx
->sfd_fres
!= NULL
)
549 free (dctx
->sfd_fres
);
550 dctx
->sfd_fres
= NULL
;
552 if (dctx
->sfd_buf
!= NULL
)
554 free (dctx
->sfd_buf
);
555 dctx
->sfd_buf
= NULL
;
563 /* Create an FDE function info byte given an FRE_TYPE and an FDE_TYPE. */
564 /* FIXME API for linker. Revisit if its better placed somewhere else? */
567 sframe_fde_create_func_info (unsigned int fre_type
,
568 unsigned int fde_type
)
570 unsigned char func_info
;
571 sframe_assert (fre_type
== SFRAME_FRE_TYPE_ADDR1
572 || fre_type
== SFRAME_FRE_TYPE_ADDR2
573 || fre_type
== SFRAME_FRE_TYPE_ADDR4
);
574 sframe_assert (fde_type
== SFRAME_FDE_TYPE_PCINC
575 || fde_type
== SFRAME_FDE_TYPE_PCMASK
);
576 func_info
= SFRAME_V1_FUNC_INFO (fde_type
, fre_type
);
580 /* Get the FRE type given the function size. */
581 /* FIXME API for linker. Revisit if its better placed somewhere else? */
584 sframe_calc_fre_type (size_t func_size
)
586 unsigned int fre_type
= 0;
587 if (func_size
< SFRAME_FRE_TYPE_ADDR1_LIMIT
)
588 fre_type
= SFRAME_FRE_TYPE_ADDR1
;
589 else if (func_size
< SFRAME_FRE_TYPE_ADDR2_LIMIT
)
590 fre_type
= SFRAME_FRE_TYPE_ADDR2
;
591 /* Adjust the check a bit so that it remains warning-free but meaningful
592 on 32-bit systems. */
593 else if (func_size
<= (size_t) (SFRAME_FRE_TYPE_ADDR4_LIMIT
- 1))
594 fre_type
= SFRAME_FRE_TYPE_ADDR4
;
598 /* Get the base reg id from the FRE info. Set errp if failure. */
601 sframe_fre_get_base_reg_id (sframe_frame_row_entry
*fre
, int *errp
)
604 return sframe_set_errno (errp
, SFRAME_ERR_FRE_INVAL
);
606 uint8_t fre_info
= fre
->fre_info
;
607 return SFRAME_V1_FRE_CFA_BASE_REG_ID (fre_info
);
610 /* Get the CFA offset from the FRE. If the offset is invalid, sets errp. */
613 sframe_fre_get_cfa_offset (sframe_decoder_ctx
*dctx ATTRIBUTE_UNUSED
,
614 sframe_frame_row_entry
*fre
, int *errp
)
616 return sframe_get_fre_offset (fre
, SFRAME_FRE_CFA_OFFSET_IDX
, errp
);
619 /* Get the FP offset from the FRE. If the offset is invalid, sets errp. */
622 sframe_fre_get_fp_offset (sframe_decoder_ctx
*dctx
,
623 sframe_frame_row_entry
*fre
, int *errp
)
625 uint32_t fp_offset_idx
= 0;
626 sframe_header
*dhp
= sframe_decoder_get_header (dctx
);
627 /* If the FP offset is not being tracked, return an error code so the caller
628 can gather the fixed FP offset from the SFrame header. */
629 if (dhp
->sfh_cfa_fixed_fp_offset
!= SFRAME_CFA_FIXED_FP_INVALID
)
630 return sframe_set_errno (errp
, SFRAME_ERR_FREOFFSET_NOPRESENT
);
632 /* In some ABIs, the stack offset to recover RA (using the CFA) from is
633 fixed (like AMD64). In such cases, the stack offset to recover FP will
634 appear at the second index. */
635 fp_offset_idx
= ((dhp
->sfh_cfa_fixed_ra_offset
!= SFRAME_CFA_FIXED_RA_INVALID
)
636 ? SFRAME_FRE_RA_OFFSET_IDX
637 : SFRAME_FRE_FP_OFFSET_IDX
);
638 return sframe_get_fre_offset (fre
, fp_offset_idx
, errp
);
641 /* Get the RA offset from the FRE. If the offset is invalid, sets errp. */
644 sframe_fre_get_ra_offset (sframe_decoder_ctx
*dctx
,
645 sframe_frame_row_entry
*fre
, int *errp
)
647 sframe_header
*dhp
= sframe_decoder_get_header (dctx
);
648 /* If the RA offset was not being tracked, return an error code so the caller
649 can gather the fixed RA offset from the SFrame header. */
650 if (dhp
->sfh_cfa_fixed_ra_offset
!= SFRAME_CFA_FIXED_RA_INVALID
)
651 return sframe_set_errno (errp
, SFRAME_ERR_FREOFFSET_NOPRESENT
);
653 /* Otherwise, get the RA offset from the FRE. */
654 return sframe_get_fre_offset (fre
, SFRAME_FRE_RA_OFFSET_IDX
, errp
);
657 /* Get whether the RA is mangled. */
660 sframe_fre_get_ra_mangled_p (sframe_decoder_ctx
*dctx ATTRIBUTE_UNUSED
,
661 sframe_frame_row_entry
*fre
, int *errp
)
663 if (fre
== NULL
|| !sframe_fre_sanity_check_p (fre
))
664 return sframe_set_errno (errp
, SFRAME_ERR_FRE_INVAL
);
666 return sframe_get_fre_ra_mangled_p (fre
->fre_info
);
670 sframe_frame_row_entry_copy (sframe_frame_row_entry
*dst
, sframe_frame_row_entry
*src
)
674 if (dst
== NULL
|| src
== NULL
)
675 return sframe_set_errno (&err
, SFRAME_ERR_INVAL
);
677 memcpy (dst
, src
, sizeof (sframe_frame_row_entry
));
681 /* Decode the SFrame FRE start address offset value from FRE_BUF in on-disk
682 binary format, given the FRE_TYPE. Updates the FRE_START_ADDR.
684 Returns 0 on success, SFRAME_ERR otherwise. */
687 sframe_decode_fre_start_address (const char *fre_buf
,
688 uint32_t *fre_start_addr
,
689 unsigned int fre_type
)
693 size_t addr_size
= 0;
695 addr_size
= sframe_fre_start_addr_size (fre_type
);
697 if (fre_type
== SFRAME_FRE_TYPE_ADDR1
)
699 uint8_t *uc
= (uint8_t *)fre_buf
;
700 saddr
= (uint32_t)*uc
;
702 else if (fre_type
== SFRAME_FRE_TYPE_ADDR2
)
704 uint16_t *ust
= (uint16_t *)fre_buf
;
705 /* SFrame is an unaligned on-disk format. Using memcpy helps avoid the
706 use of undesirable unaligned loads. See PR libsframe/29856. */
708 memcpy (&tmp
, ust
, addr_size
);
709 saddr
= (uint32_t)tmp
;
711 else if (fre_type
== SFRAME_FRE_TYPE_ADDR4
)
713 uint32_t *uit
= (uint32_t *)fre_buf
;
715 memcpy (&tmp
, uit
, addr_size
);
716 saddr
= (uint32_t)tmp
;
719 return sframe_set_errno (&err
, SFRAME_ERR_INVAL
);
721 *fre_start_addr
= saddr
;
725 /* Decode a frame row entry FRE which starts at location FRE_BUF. The function
726 updates ESZ to the size of the FRE as stored in the binary format.
728 This function works closely with the SFrame binary format.
730 Returns SFRAME_ERR if failure. */
733 sframe_decode_fre (const char *fre_buf
, sframe_frame_row_entry
*fre
,
734 unsigned int fre_type
, size_t *esz
)
737 const char *stack_offsets
= NULL
;
738 size_t stack_offsets_sz
;
742 if (fre_buf
== NULL
|| fre
== NULL
|| esz
== NULL
)
743 return sframe_set_errno (&err
, SFRAME_ERR_INVAL
);
745 /* Copy over the FRE start address. */
746 sframe_decode_fre_start_address (fre_buf
, &fre
->fre_start_addr
, fre_type
);
748 addr_size
= sframe_fre_start_addr_size (fre_type
);
749 fre
->fre_info
= *(uint8_t *)(fre_buf
+ addr_size
);
750 /* Sanity check as the API works closely with the binary format. */
751 sframe_assert (sizeof (fre
->fre_info
) == sizeof (uint8_t));
753 /* Cleanup the space for fre_offsets first, then copy over the valid
755 memset (fre
->fre_offsets
, 0, MAX_OFFSET_BYTES
);
756 /* Get offsets size. */
757 stack_offsets_sz
= sframe_fre_offset_bytes_size (fre
->fre_info
);
758 stack_offsets
= fre_buf
+ addr_size
+ sizeof (fre
->fre_info
);
759 memcpy (fre
->fre_offsets
, stack_offsets
, stack_offsets_sz
);
761 /* The FRE has been decoded. Use it to perform one last sanity check. */
762 fre_size
= sframe_fre_entry_size (fre
, fre_type
);
763 sframe_assert (fre_size
== (addr_size
+ sizeof (fre
->fre_info
)
764 + stack_offsets_sz
));
770 /* Decode the specified SFrame buffer CF_BUF of size CF_SIZE and return the
771 new SFrame decoder context.
773 Sets ERRP for the caller if any error. Frees up the allocated memory in
777 sframe_decode (const char *sf_buf
, size_t sf_size
, int *errp
)
779 const sframe_preamble
*sfp
;
781 sframe_header
*sfheaderp
;
782 sframe_decoder_ctx
*dctx
;
784 char *tempbuf
= NULL
;
788 int foreign_endian
= 0;
790 sframe_init_debug ();
792 if ((sf_buf
== NULL
) || (!sf_size
))
793 return sframe_ret_set_errno (errp
, SFRAME_ERR_INVAL
);
794 else if (sf_size
< sizeof (sframe_header
))
795 return sframe_ret_set_errno (errp
, SFRAME_ERR_BUF_INVAL
);
797 sfp
= (const sframe_preamble
*) sf_buf
;
799 debug_printf ("sframe_decode: magic=0x%x version=%u flags=%u\n",
800 sfp
->sfp_magic
, sfp
->sfp_version
, sfp
->sfp_flags
);
802 /* Check for foreign endianness. */
803 if (sfp
->sfp_magic
!= SFRAME_MAGIC
)
805 if (sfp
->sfp_magic
== bswap_16 (SFRAME_MAGIC
))
808 return sframe_ret_set_errno (errp
, SFRAME_ERR_BUF_INVAL
);
811 /* Initialize a new decoder context. */
812 if ((dctx
= malloc (sizeof (sframe_decoder_ctx
))) == NULL
)
813 return sframe_ret_set_errno (errp
, SFRAME_ERR_NOMEM
);
814 memset (dctx
, 0, sizeof (sframe_decoder_ctx
));
818 /* Allocate a new buffer and initialize it. */
819 tempbuf
= (char *) malloc (sf_size
* sizeof (char));
821 return sframe_ret_set_errno (errp
, SFRAME_ERR_NOMEM
);
822 memcpy (tempbuf
, sf_buf
, sf_size
);
824 /* Flip the header. */
825 sframe_header
*ihp
= (sframe_header
*) tempbuf
;
827 /* Flip the rest of the SFrame section data buffer. */
828 if (flip_sframe (tempbuf
, sf_size
, 0))
831 return sframe_ret_set_errno (errp
, SFRAME_ERR_BUF_INVAL
);
834 /* This buffer is malloc'd when endian flipping the contents of the input
835 buffer are needed. Keep a reference to it so it can be free'd up
836 later in sframe_decoder_free (). */
837 dctx
->sfd_buf
= tempbuf
;
840 frame_buf
= (char *)sf_buf
;
842 /* Handle the SFrame header. */
843 dctx
->sfd_header
= *(sframe_header
*) frame_buf
;
844 /* Validate the contents of SFrame header. */
845 sfheaderp
= &dctx
->sfd_header
;
846 if (!sframe_header_sanity_check_p (sfheaderp
))
848 sframe_ret_set_errno (errp
, SFRAME_ERR_NOMEM
);
849 goto decode_fail_free
;
851 hdrsz
= sframe_get_hdr_size (sfheaderp
);
854 /* Handle the SFrame Function Descriptor Entry section. */
856 = sfheaderp
->sfh_num_fdes
* sizeof (sframe_func_desc_entry
);
857 dctx
->sfd_funcdesc
= malloc (fidx_size
);
858 if (dctx
->sfd_funcdesc
== NULL
)
860 sframe_ret_set_errno (errp
, SFRAME_ERR_NOMEM
);
861 goto decode_fail_free
;
863 memcpy (dctx
->sfd_funcdesc
, frame_buf
, fidx_size
);
865 debug_printf ("%u total fidx size\n", fidx_size
);
867 frame_buf
+= (fidx_size
);
869 /* Handle the SFrame Frame Row Entry section. */
870 dctx
->sfd_fres
= malloc (sfheaderp
->sfh_fre_len
);
871 if (dctx
->sfd_fres
== NULL
)
873 sframe_ret_set_errno (errp
, SFRAME_ERR_NOMEM
);
874 goto decode_fail_free
;
876 memcpy (dctx
->sfd_fres
, frame_buf
, sfheaderp
->sfh_fre_len
);
878 fre_bytes
= sfheaderp
->sfh_fre_len
;
879 dctx
->sfd_fre_nbytes
= fre_bytes
;
881 debug_printf ("%u total fre bytes\n", fre_bytes
);
886 if (foreign_endian
&& tempbuf
!= NULL
)
888 sframe_decoder_free (&dctx
);
893 /* Get the size of the SFrame header from the decoder context CTX. */
896 sframe_decoder_get_hdr_size (sframe_decoder_ctx
*ctx
)
899 dhp
= sframe_decoder_get_header (ctx
);
900 return sframe_get_hdr_size (dhp
);
903 /* Get the SFrame's abi/arch info given the decoder context CTX. */
906 sframe_decoder_get_abi_arch (sframe_decoder_ctx
*ctx
)
908 sframe_header
*sframe_header
;
909 sframe_header
= sframe_decoder_get_header (ctx
);
910 return sframe_header
->sfh_abi_arch
;
913 /* Get the SFrame's fixed FP offset given the decoder context CTX. */
915 sframe_decoder_get_fixed_fp_offset (sframe_decoder_ctx
*ctx
)
918 dhp
= sframe_decoder_get_header (ctx
);
919 return dhp
->sfh_cfa_fixed_fp_offset
;
922 /* Get the SFrame's fixed RA offset given the decoder context CTX. */
924 sframe_decoder_get_fixed_ra_offset (sframe_decoder_ctx
*ctx
)
927 dhp
= sframe_decoder_get_header (ctx
);
928 return dhp
->sfh_cfa_fixed_ra_offset
;
931 /* Find the function descriptor entry starting which contains the specified
934 sframe_func_desc_entry
*
935 sframe_get_funcdesc_with_addr (sframe_decoder_ctx
*ctx
,
936 int32_t addr
, int *errp
)
939 sframe_func_desc_entry
*fdp
;
943 return sframe_ret_set_errno (errp
, SFRAME_ERR_INVAL
);
945 dhp
= sframe_decoder_get_header (ctx
);
947 if (dhp
== NULL
|| dhp
->sfh_num_fdes
== 0 || ctx
->sfd_funcdesc
== NULL
)
948 return sframe_ret_set_errno (errp
, SFRAME_ERR_DCTX_INVAL
);
949 /* If the FDE sub-section is not sorted on PCs, skip the lookup because
950 binary search cannot be used. */
951 if ((dhp
->sfh_preamble
.sfp_flags
& SFRAME_F_FDE_SORTED
) == 0)
952 return sframe_ret_set_errno (errp
, SFRAME_ERR_FDE_NOTSORTED
);
954 /* Do the binary search. */
955 fdp
= (sframe_func_desc_entry
*) ctx
->sfd_funcdesc
;
957 high
= dhp
->sfh_num_fdes
;
961 int mid
= low
+ (high
- low
) / 2;
963 if (fdp
[mid
].sfde_func_start_address
== addr
)
966 if (fdp
[mid
].sfde_func_start_address
< addr
)
968 if (mid
== (cnt
- 1)) /* Check if it's the last one. */
969 return fdp
+ (cnt
- 1);
970 else if (fdp
[mid
+1].sfde_func_start_address
> addr
)
978 return sframe_ret_set_errno (errp
, SFRAME_ERR_FDE_NOTFOUND
);
981 /* Get the end IP offset for the FRE at index i in the FDEP. The buffer FRES
982 is the starting location for the FRE. */
985 sframe_fre_get_end_ip_offset (sframe_func_desc_entry
*fdep
, unsigned int i
,
988 uint32_t end_ip_offset
;
991 fre_type
= sframe_get_fre_type (fdep
);
993 /* Get the start address of the next FRE in sequence. */
994 if (i
< fdep
->sfde_func_num_fres
- 1)
996 sframe_decode_fre_start_address (fres
, &end_ip_offset
, fre_type
);
1000 /* The end IP offset for the FRE needs to be deduced from the function
1002 end_ip_offset
= fdep
->sfde_func_size
- 1;
1004 return end_ip_offset
;
1007 /* Find the SFrame Row Entry which contains the PC. Returns
1008 SFRAME_ERR if failure. */
1011 sframe_find_fre (sframe_decoder_ctx
*ctx
, int32_t pc
,
1012 sframe_frame_row_entry
*frep
)
1014 sframe_frame_row_entry cur_fre
;
1015 sframe_func_desc_entry
*fdep
;
1016 unsigned int fre_type
, fde_type
;
1017 uint32_t end_ip_offset
, i
;
1018 int32_t start_ip
, end_ip
;
1019 int32_t func_start_addr
;
1023 /* For regular FDEs (i.e. fde_type SFRAME_FDE_TYPE_PCINC),
1024 where the start address in the FRE is an offset from start pc,
1025 use a bitmask with all bits set so that none of the address bits are
1026 ignored. In this case, we need to return the FRE where
1027 (PC >= FRE_START_ADDR) */
1028 uint64_t bitmask
= 0xffffffff;
1030 if ((ctx
== NULL
) || (frep
== NULL
))
1031 return sframe_set_errno (&err
, SFRAME_ERR_INVAL
);
1033 /* Find the FDE which contains the PC, then scan its fre entries. */
1034 fdep
= sframe_get_funcdesc_with_addr (ctx
, pc
, &err
);
1035 if (fdep
== NULL
|| ctx
->sfd_fres
== NULL
)
1036 return sframe_set_errno (&err
, SFRAME_ERR_DCTX_INVAL
);
1038 fre_type
= sframe_get_fre_type (fdep
);
1039 fde_type
= sframe_get_fde_type (fdep
);
1041 /* For FDEs for repetitive pattern of insns, we need to return the FRE
1042 such that (PC & FRE_START_ADDR_AS_MASK >= FRE_START_ADDR_AS_MASK).
1043 so, update the bitmask to the start address. */
1044 /* FIXME - the bitmask should be picked per ABI or encoded in the format
1045 somehow. For AMD64, the pltN entry stub is 16 bytes. */
1046 if (fde_type
== SFRAME_FDE_TYPE_PCMASK
)
1049 fres
= ctx
->sfd_fres
+ fdep
->sfde_func_start_fre_off
;
1050 func_start_addr
= fdep
->sfde_func_start_address
;
1052 for (i
= 0; i
< fdep
->sfde_func_num_fres
; i
++)
1054 err
= sframe_decode_fre (fres
, &cur_fre
, fre_type
, &size
);
1056 return sframe_set_errno (&err
, SFRAME_ERR_FRE_INVAL
);
1058 start_ip
= func_start_addr
+ cur_fre
.fre_start_addr
;
1059 end_ip_offset
= sframe_fre_get_end_ip_offset (fdep
, i
, fres
+ size
);
1060 end_ip
= func_start_addr
+ end_ip_offset
;
1062 if ((start_ip
& bitmask
) > (pc
& bitmask
))
1063 return sframe_set_errno (&err
, SFRAME_ERR_FRE_INVAL
);
1065 if (((start_ip
& bitmask
) <= (pc
& bitmask
))
1066 && (end_ip
& bitmask
) >= (pc
& bitmask
))
1068 sframe_frame_row_entry_copy (frep
, &cur_fre
);
1073 return sframe_set_errno (&err
, SFRAME_ERR_FDE_INVAL
);
1076 /* Return the number of function descriptor entries in the SFrame decoder
1080 sframe_decoder_get_num_fidx (sframe_decoder_ctx
*ctx
)
1082 unsigned int num_fdes
= 0;
1083 sframe_header
*dhp
= NULL
;
1084 dhp
= sframe_decoder_get_header (ctx
);
1086 num_fdes
= dhp
->sfh_num_fdes
;
1090 /* Get the data (NUM_FRES, FUNC_START_ADDRESS) from the function
1091 descriptor entry at index I'th in the decoder CTX. If failed,
1092 return error code. */
1093 /* FIXME - consolidate the args and return a
1094 sframe_func_desc_index_elem rather? */
1097 sframe_decoder_get_funcdesc (sframe_decoder_ctx
*ctx
,
1100 uint32_t *func_size
,
1101 int32_t *func_start_address
,
1102 unsigned char *func_info
)
1104 sframe_func_desc_entry
*fdp
;
1105 unsigned int num_fdes
;
1108 if (ctx
== NULL
|| func_start_address
== NULL
|| num_fres
== NULL
1109 || func_size
== NULL
)
1110 return sframe_set_errno (&err
, SFRAME_ERR_INVAL
);
1112 num_fdes
= sframe_decoder_get_num_fidx (ctx
);
1115 || ctx
->sfd_funcdesc
== NULL
)
1116 return sframe_set_errno (&err
, SFRAME_ERR_DCTX_INVAL
);
1118 fdp
= (sframe_func_desc_entry
*) ctx
->sfd_funcdesc
+ i
;
1119 *num_fres
= fdp
->sfde_func_num_fres
;
1120 *func_start_address
= fdp
->sfde_func_start_address
;
1121 *func_size
= fdp
->sfde_func_size
;
1122 *func_info
= fdp
->sfde_func_info
;
1127 /* Get the function descriptor entry at index FUNC_IDX in the decoder
1130 static sframe_func_desc_entry
*
1131 sframe_decoder_get_funcdesc_at_index (sframe_decoder_ctx
*ctx
,
1134 /* Invalid argument. No FDE will be found. */
1135 if (func_idx
>= sframe_decoder_get_num_fidx (ctx
))
1138 sframe_func_desc_entry
*fdep
;
1139 fdep
= (sframe_func_desc_entry
*) ctx
->sfd_funcdesc
;
1140 return fdep
+ func_idx
;
1143 /* Get the FRE_IDX'th FRE of the function at FUNC_IDX'th function
1144 descriptor entry in the SFrame decoder CTX. Returns error code as
1148 sframe_decoder_get_fre (sframe_decoder_ctx
*ctx
,
1149 unsigned int func_idx
,
1150 unsigned int fre_idx
,
1151 sframe_frame_row_entry
*fre
)
1153 sframe_func_desc_entry
*fdep
;
1154 sframe_frame_row_entry ifre
;
1157 unsigned int fre_type
;
1161 if (ctx
== NULL
|| fre
== NULL
)
1162 return sframe_set_errno (&err
, SFRAME_ERR_INVAL
);
1164 /* Get function descriptor entry at index func_idx. */
1165 fdep
= sframe_decoder_get_funcdesc_at_index (ctx
, func_idx
);
1168 return sframe_set_errno (&err
, SFRAME_ERR_FDE_NOTFOUND
);
1170 fre_type
= sframe_get_fre_type (fdep
);
1171 /* Now scan the FRE entries. */
1172 fres
= ctx
->sfd_fres
+ fdep
->sfde_func_start_fre_off
;
1173 for (i
= 0; i
< fdep
->sfde_func_num_fres
; i
++)
1175 /* Decode the FRE at the current position. Return it if valid. */
1176 err
= sframe_decode_fre (fres
, &ifre
, fre_type
, &esz
);
1179 if (!sframe_fre_sanity_check_p (&ifre
))
1180 return sframe_set_errno (&err
, SFRAME_ERR_FRE_INVAL
);
1182 sframe_frame_row_entry_copy (fre
, &ifre
);
1184 if (fdep
->sfde_func_size
)
1185 sframe_assert (fre
->fre_start_addr
< fdep
->sfde_func_size
);
1187 /* A SFrame FDE with func size equal to zero is possible. */
1188 sframe_assert (fre
->fre_start_addr
== fdep
->sfde_func_size
);
1196 return sframe_set_errno (&err
, SFRAME_ERR_FDE_NOTFOUND
);
1200 /* SFrame Encoder. */
1202 /* Get a reference to the ENCODER's SFrame header. */
1204 static sframe_header
*
1205 sframe_encoder_get_header (sframe_encoder_ctx
*encoder
)
1207 sframe_header
*hp
= NULL
;
1209 hp
= &encoder
->sfe_header
;
1213 static sframe_func_desc_entry
*
1214 sframe_encoder_get_funcdesc_at_index (sframe_encoder_ctx
*encoder
,
1217 sframe_func_desc_entry
*fde
= NULL
;
1218 if (func_idx
< sframe_encoder_get_num_fidx (encoder
))
1220 sf_funidx_tbl
*func_tbl
= (sf_funidx_tbl
*) encoder
->sfe_funcdesc
;
1221 fde
= func_tbl
->entry
+ func_idx
;
1226 /* Create an encoder context with the given SFrame format version VER, FLAGS
1227 and ABI information. Sets errp if failure. */
1229 sframe_encoder_ctx
*
1230 sframe_encode (unsigned char ver
, unsigned char flags
, int abi_arch
,
1231 int8_t fixed_fp_offset
, int8_t fixed_ra_offset
, int *errp
)
1234 sframe_encoder_ctx
*encoder
;
1236 if (ver
!= SFRAME_VERSION
)
1237 return sframe_ret_set_errno (errp
, SFRAME_ERR_VERSION_INVAL
);
1239 if ((encoder
= malloc (sizeof (sframe_encoder_ctx
))) == NULL
)
1240 return sframe_ret_set_errno (errp
, SFRAME_ERR_NOMEM
);
1242 memset (encoder
, 0, sizeof (sframe_encoder_ctx
));
1244 /* Get the SFrame header and update it. */
1245 hp
= sframe_encoder_get_header (encoder
);
1246 hp
->sfh_preamble
.sfp_version
= ver
;
1247 hp
->sfh_preamble
.sfp_magic
= SFRAME_MAGIC
;
1248 hp
->sfh_preamble
.sfp_flags
= flags
;
1250 hp
->sfh_abi_arch
= abi_arch
;
1251 hp
->sfh_cfa_fixed_fp_offset
= fixed_fp_offset
;
1252 hp
->sfh_cfa_fixed_ra_offset
= fixed_ra_offset
;
1257 /* Free the encoder context. */
1260 sframe_encoder_free (sframe_encoder_ctx
**encoder
)
1262 if (encoder
!= NULL
)
1264 sframe_encoder_ctx
*ectx
= *encoder
;
1268 if (ectx
->sfe_funcdesc
!= NULL
)
1270 free (ectx
->sfe_funcdesc
);
1271 ectx
->sfe_funcdesc
= NULL
;
1273 if (ectx
->sfe_fres
!= NULL
)
1275 free (ectx
->sfe_fres
);
1276 ectx
->sfe_fres
= NULL
;
1278 if (ectx
->sfe_data
!= NULL
)
1280 free (ectx
->sfe_data
);
1281 ectx
->sfe_data
= NULL
;
1289 /* Get the size of the SFrame header from the encoder ctx ENCODER. */
1292 sframe_encoder_get_hdr_size (sframe_encoder_ctx
*encoder
)
1295 ehp
= sframe_encoder_get_header (encoder
);
1296 return sframe_get_hdr_size (ehp
);
1299 /* Get the abi/arch info from the SFrame encoder context ENCODER. */
1302 sframe_encoder_get_abi_arch (sframe_encoder_ctx
*encoder
)
1304 unsigned char abi_arch
= 0;
1306 ehp
= sframe_encoder_get_header (encoder
);
1308 abi_arch
= ehp
->sfh_abi_arch
;
1312 /* Return the number of function descriptor entries in the SFrame encoder
1316 sframe_encoder_get_num_fidx (sframe_encoder_ctx
*encoder
)
1318 unsigned int num_fdes
= 0;
1319 sframe_header
*ehp
= NULL
;
1320 ehp
= sframe_encoder_get_header (encoder
);
1322 num_fdes
= ehp
->sfh_num_fdes
;
1326 /* Add an FRE to function at FUNC_IDX'th function descriptor entry in
1327 the encoder context. */
1330 sframe_encoder_add_fre (sframe_encoder_ctx
*encoder
,
1331 unsigned int func_idx
,
1332 sframe_frame_row_entry
*frep
)
1335 sframe_func_desc_entry
*fdep
;
1336 sframe_frame_row_entry
*ectx_frep
;
1337 size_t offsets_sz
, esz
;
1338 unsigned int fre_type
;
1342 if (encoder
== NULL
|| frep
== NULL
)
1343 return sframe_set_errno (&err
, SFRAME_ERR_INVAL
);
1344 if (!sframe_fre_sanity_check_p (frep
))
1345 return sframe_set_errno (&err
, SFRAME_ERR_FRE_INVAL
);
1347 /* Use func_idx to gather the function descriptor entry. */
1348 fdep
= sframe_encoder_get_funcdesc_at_index (encoder
, func_idx
);
1351 return sframe_set_errno (&err
, SFRAME_ERR_FDE_NOTFOUND
);
1353 fre_type
= sframe_get_fre_type (fdep
);
1354 sf_fre_tbl
*fre_tbl
= (sf_fre_tbl
*) encoder
->sfe_fres
;
1356 if (fre_tbl
== NULL
)
1358 fre_tbl_sz
= (sizeof (sf_fre_tbl
)
1359 + (number_of_entries
* sizeof (sframe_frame_row_entry
)));
1360 fre_tbl
= malloc (fre_tbl_sz
);
1362 if (fre_tbl
== NULL
)
1364 sframe_set_errno (&err
, SFRAME_ERR_NOMEM
);
1365 goto bad
; /* OOM. */
1367 memset (fre_tbl
, 0, fre_tbl_sz
);
1368 fre_tbl
->alloced
= number_of_entries
;
1370 else if (fre_tbl
->count
== fre_tbl
->alloced
)
1372 fre_tbl_sz
= (sizeof (sf_fre_tbl
)
1373 + ((fre_tbl
->alloced
+ number_of_entries
)
1374 * sizeof (sframe_frame_row_entry
)));
1375 fre_tbl
= realloc (fre_tbl
, fre_tbl_sz
);
1376 if (fre_tbl
== NULL
)
1378 sframe_set_errno (&err
, SFRAME_ERR_NOMEM
);
1379 goto bad
; /* OOM. */
1382 memset (&fre_tbl
->entry
[fre_tbl
->alloced
], 0,
1383 number_of_entries
* sizeof (sframe_frame_row_entry
));
1384 fre_tbl
->alloced
+= number_of_entries
;
1387 ectx_frep
= &fre_tbl
->entry
[fre_tbl
->count
];
1388 ectx_frep
->fre_start_addr
1389 = frep
->fre_start_addr
;
1390 ectx_frep
->fre_info
= frep
->fre_info
;
1392 if (fdep
->sfde_func_size
)
1393 sframe_assert (frep
->fre_start_addr
< fdep
->sfde_func_size
);
1395 /* A SFrame FDE with func size equal to zero is possible. */
1396 sframe_assert (frep
->fre_start_addr
== fdep
->sfde_func_size
);
1398 /* frep has already been sanity check'd. Get offsets size. */
1399 offsets_sz
= sframe_fre_offset_bytes_size (frep
->fre_info
);
1400 memcpy (&ectx_frep
->fre_offsets
, &frep
->fre_offsets
, offsets_sz
);
1402 esz
= sframe_fre_entry_size (frep
, fre_type
);
1405 encoder
->sfe_fres
= (void *) fre_tbl
;
1406 encoder
->sfe_fre_nbytes
+= esz
;
1408 ehp
= sframe_encoder_get_header (encoder
);
1409 ehp
->sfh_num_fres
= fre_tbl
->count
;
1411 /* Update the value of the number of FREs for the function. */
1412 fdep
->sfde_func_num_fres
++;
1417 if (fre_tbl
!= NULL
)
1419 encoder
->sfe_fres
= NULL
;
1420 encoder
->sfe_fre_nbytes
= 0;
1424 /* Add a new function descriptor entry with START_ADDR, FUNC_SIZE and NUM_FRES
1428 sframe_encoder_add_funcdesc (sframe_encoder_ctx
*encoder
,
1431 unsigned char func_info
,
1432 uint32_t num_fres
__attribute__ ((unused
)))
1435 sf_funidx_tbl
*fd_info
;
1439 /* FIXME book-keep num_fres for error checking. */
1440 if (encoder
== NULL
)
1441 return sframe_set_errno (&err
, SFRAME_ERR_INVAL
);
1443 fd_info
= (sf_funidx_tbl
*) encoder
->sfe_funcdesc
;
1444 ehp
= sframe_encoder_get_header (encoder
);
1446 if (fd_info
== NULL
)
1448 fd_tbl_sz
= (sizeof (sf_funidx_tbl
)
1449 + (number_of_entries
* sizeof (sframe_func_desc_entry
)));
1450 fd_info
= malloc (fd_tbl_sz
);
1451 if (fd_info
== NULL
)
1453 sframe_set_errno (&err
, SFRAME_ERR_NOMEM
);
1454 goto bad
; /* OOM. */
1456 memset (fd_info
, 0, fd_tbl_sz
);
1457 fd_info
->alloced
= number_of_entries
;
1459 else if (fd_info
->count
== fd_info
->alloced
)
1461 fd_tbl_sz
= (sizeof (sf_funidx_tbl
)
1462 + ((fd_info
->alloced
+ number_of_entries
)
1463 * sizeof (sframe_func_desc_entry
)));
1464 fd_info
= realloc (fd_info
, fd_tbl_sz
);
1465 if (fd_info
== NULL
)
1467 sframe_set_errno (&err
, SFRAME_ERR_NOMEM
);
1468 goto bad
; /* OOM. */
1471 memset (&fd_info
->entry
[fd_info
->alloced
], 0,
1472 number_of_entries
* sizeof (sframe_func_desc_entry
));
1473 fd_info
->alloced
+= number_of_entries
;
1476 fd_info
->entry
[fd_info
->count
].sfde_func_start_address
= start_addr
;
1477 /* Num FREs is updated as FREs are added for the function later via
1478 sframe_encoder_add_fre. */
1479 fd_info
->entry
[fd_info
->count
].sfde_func_size
= func_size
;
1480 fd_info
->entry
[fd_info
->count
].sfde_func_start_fre_off
1481 = encoder
->sfe_fre_nbytes
;
1483 // Linker optimization test code cleanup later ibhagat TODO FIXME
1484 unsigned int fre_type
= sframe_calc_fre_type (func_size
);
1486 fd_info
->entry
[fd_info
->count
].sfde_func_info
1487 = sframe_fde_func_info (fre_type
);
1489 fd_info
->entry
[fd_info
->count
].sfde_func_info
= func_info
;
1491 encoder
->sfe_funcdesc
= (void *) fd_info
;
1492 ehp
->sfh_num_fdes
++;
1496 if (fd_info
!= NULL
)
1498 encoder
->sfe_funcdesc
= NULL
;
1499 ehp
->sfh_num_fdes
= 0;
1504 sframe_sort_funcdesc (sframe_encoder_ctx
*encoder
)
1508 ehp
= sframe_encoder_get_header (encoder
);
1509 /* Sort and write out the FDE table. */
1510 sf_funidx_tbl
*fd_info
= (sf_funidx_tbl
*) encoder
->sfe_funcdesc
;
1513 qsort (fd_info
->entry
, fd_info
->count
,
1514 sizeof (sframe_func_desc_entry
), fde_func
);
1515 /* Update preamble's flags. */
1516 ehp
->sfh_preamble
.sfp_flags
|= SFRAME_F_FDE_SORTED
;
1521 /* Write the SFrame FRE start address from the in-memory FRE_START_ADDR
1522 to the buffer CONTENTS (on-disk format), given the FRE_TYPE and
1523 FRE_START_ADDR_SZ. */
1526 sframe_encoder_write_fre_start_addr (char *contents
,
1527 uint32_t fre_start_addr
,
1528 unsigned int fre_type
,
1529 size_t fre_start_addr_sz
)
1533 if (fre_type
== SFRAME_FRE_TYPE_ADDR1
)
1535 uint8_t uc
= fre_start_addr
;
1536 memcpy (contents
, &uc
, fre_start_addr_sz
);
1538 else if (fre_type
== SFRAME_FRE_TYPE_ADDR2
)
1540 uint16_t ust
= fre_start_addr
;
1541 memcpy (contents
, &ust
, fre_start_addr_sz
);
1543 else if (fre_type
== SFRAME_FRE_TYPE_ADDR4
)
1545 uint32_t uit
= fre_start_addr
;
1546 memcpy (contents
, &uit
, fre_start_addr_sz
);
1549 return sframe_set_errno (&err
, SFRAME_ERR_INVAL
);
1554 /* Write a frame row entry pointed to by FREP into the buffer CONTENTS. The
1555 size in bytes written out are updated in ESZ.
1557 This function works closely with the SFrame binary format.
1559 Returns SFRAME_ERR if failure. */
1562 sframe_encoder_write_fre (char *contents
, sframe_frame_row_entry
*frep
,
1563 unsigned int fre_type
, size_t *esz
)
1566 size_t fre_start_addr_sz
;
1567 size_t fre_stack_offsets_sz
;
1570 if (!sframe_fre_sanity_check_p (frep
))
1571 return sframe_set_errno (&err
, SFRAME_ERR_FRE_INVAL
);
1573 fre_start_addr_sz
= sframe_fre_start_addr_size (fre_type
);
1574 fre_stack_offsets_sz
= sframe_fre_offset_bytes_size (frep
->fre_info
);
1576 /* The FRE start address must be encodable in the available number of
1578 uint64_t bitmask
= SFRAME_BITMASK_OF_SIZE (fre_start_addr_sz
);
1579 sframe_assert ((uint64_t)frep
->fre_start_addr
<= bitmask
);
1581 sframe_encoder_write_fre_start_addr (contents
, frep
->fre_start_addr
,
1582 fre_type
, fre_start_addr_sz
);
1583 contents
+= fre_start_addr_sz
;
1585 memcpy (contents
, &frep
->fre_info
, sizeof (frep
->fre_info
));
1586 contents
+= sizeof (frep
->fre_info
);
1588 memcpy (contents
, frep
->fre_offsets
, fre_stack_offsets_sz
);
1589 contents
+= fre_stack_offsets_sz
;
1591 fre_sz
= sframe_fre_entry_size (frep
, fre_type
);
1592 /* Sanity checking. */
1593 sframe_assert ((fre_start_addr_sz
1594 + sizeof (frep
->fre_info
)
1595 + fre_stack_offsets_sz
) == fre_sz
);
1602 /* Serialize the core contents of the SFrame section and write out to the
1603 output buffer held in the ENCODER. Return SFRAME_ERR if failure. */
1606 sframe_encoder_write_sframe (sframe_encoder_ctx
*encoder
)
1611 size_t all_fdes_size
;
1615 unsigned char flags
;
1616 sf_funidx_tbl
*fd_info
;
1617 sf_fre_tbl
*fr_info
;
1618 uint32_t i
, num_fdes
;
1619 uint32_t j
, num_fres
;
1620 sframe_func_desc_entry
*fdep
;
1621 sframe_frame_row_entry
*frep
;
1623 unsigned int fre_type
;
1626 contents
= encoder
->sfe_data
;
1627 buf_size
= encoder
->sfe_data_size
;
1628 num_fdes
= sframe_encoder_get_num_fidx (encoder
);
1629 all_fdes_size
= num_fdes
* sizeof (sframe_func_desc_entry
);
1630 ehp
= sframe_encoder_get_header (encoder
);
1631 hdr_size
= sframe_get_hdr_size (ehp
);
1633 fd_info
= (sf_funidx_tbl
*) encoder
->sfe_funcdesc
;
1634 fr_info
= (sf_fre_tbl
*) encoder
->sfe_fres
;
1637 - buffers must be malloc'd by the caller. */
1638 if ((contents
== NULL
) || (buf_size
< hdr_size
))
1639 return sframe_set_errno (&err
, SFRAME_ERR_BUF_INVAL
);
1640 if (fr_info
== NULL
)
1641 return sframe_set_errno (&err
, SFRAME_ERR_FRE_INVAL
);
1643 /* Write out the FRE table first.
1645 Recall that read/write of FREs needs information from the corresponding
1646 FDE; the latter stores the information about the FRE type record used for
1647 the function. Also note that sorting of FDEs does NOT impact the order
1648 in which FREs are stored in the SFrame's FRE sub-section. This means
1649 that writing out FREs after sorting of FDEs will need some additional
1650 book-keeping. At this time, we can afford to avoid it by writing out
1651 the FREs first to the output buffer. */
1653 uint32_t global
= 0;
1654 uint32_t fre_index
= 0;
1656 contents
+= hdr_size
+ all_fdes_size
;
1657 for (i
= 0; i
< num_fdes
; i
++)
1659 fdep
= &fd_info
->entry
[i
];
1660 fre_type
= sframe_get_fre_type (fdep
);
1661 num_fres
= fdep
->sfde_func_num_fres
;
1663 for (j
= 0; j
< num_fres
; j
++)
1665 fre_index
= global
+ j
;
1666 frep
= &fr_info
->entry
[fre_index
];
1668 sframe_encoder_write_fre (contents
, frep
, fre_type
, &esz
);
1670 fre_size
+= esz
; /* For debugging only. */
1675 sframe_assert (fre_size
== ehp
->sfh_fre_len
);
1676 sframe_assert (global
== ehp
->sfh_num_fres
);
1677 sframe_assert ((size_t)(contents
- encoder
->sfe_data
) == buf_size
);
1679 /* Sort the FDE table */
1680 sframe_sort_funcdesc (encoder
);
1683 - the FDE section must have been sorted by now on the start address
1684 of each function. */
1685 flags
= ehp
->sfh_preamble
.sfp_flags
;
1686 if (!(flags
& SFRAME_F_FDE_SORTED
)
1687 || (fd_info
== NULL
))
1688 return sframe_set_errno (&err
, SFRAME_ERR_FDE_INVAL
);
1690 contents
= encoder
->sfe_data
;
1691 /* Write out the SFrame header. The SFrame header in the encoder
1692 object has already been updated with correct offsets by the caller. */
1693 memcpy (contents
, ehp
, hdr_size
);
1694 contents
+= hdr_size
;
1696 /* Write out the FDE table sorted on funtion start address. */
1697 memcpy (contents
, fd_info
->entry
, all_fdes_size
);
1698 contents
+= all_fdes_size
;
1703 /* Serialize the contents of the encoder and return the buffer. ENCODED_SIZE
1704 is updated to the size of the buffer. */
1707 sframe_encoder_write (sframe_encoder_ctx
*encoder
,
1708 size_t *encoded_size
, int *errp
)
1711 size_t hdrsize
, fsz
, fresz
, bufsize
;
1714 /* Initialize the encoded_size to zero. This makes it simpler to just
1715 return from the function in case of failure. Free'ing up of
1716 encoder->sfe_data is the responsibility of the caller. */
1719 if (encoder
== NULL
|| encoded_size
== NULL
|| errp
== NULL
)
1720 return sframe_ret_set_errno (errp
, SFRAME_ERR_INVAL
);
1722 ehp
= sframe_encoder_get_header (encoder
);
1723 hdrsize
= sframe_get_hdr_size (ehp
);
1724 fsz
= sframe_encoder_get_num_fidx (encoder
)
1725 * sizeof (sframe_func_desc_entry
);
1726 fresz
= encoder
->sfe_fre_nbytes
;
1728 /* The total size of buffer is the sum of header, SFrame Function Descriptor
1729 Entries section and the FRE section. */
1730 bufsize
= hdrsize
+ fsz
+ fresz
;
1731 encoder
->sfe_data
= (char *) malloc (bufsize
);
1732 if (encoder
->sfe_data
== NULL
)
1733 return sframe_ret_set_errno (errp
, SFRAME_ERR_NOMEM
);
1734 encoder
->sfe_data_size
= bufsize
;
1736 /* Update the information in the SFrame header. */
1737 /* SFrame FDE section follows immediately after the header. */
1738 ehp
->sfh_fdeoff
= 0;
1739 /* SFrame FRE section follows immediately after the SFrame FDE section. */
1740 ehp
->sfh_freoff
= fsz
;
1741 ehp
->sfh_fre_len
= fresz
;
1743 foreign_endian
= need_swapping (ehp
->sfh_abi_arch
);
1745 /* Write out the FDE Index and the FRE table in the sfe_data. */
1746 if (sframe_encoder_write_sframe (encoder
))
1747 return sframe_ret_set_errno (errp
, SFRAME_ERR_BUF_INVAL
);
1749 /* Endian flip the contents if necessary. */
1752 if (flip_sframe (encoder
->sfe_data
, bufsize
, 1))
1753 return sframe_ret_set_errno (errp
, SFRAME_ERR_BUF_INVAL
);
1754 flip_header ((sframe_header
*)encoder
->sfe_data
);
1757 *encoded_size
= bufsize
;
1758 return encoder
->sfe_data
;