xref: /netbsd-src/external/gpl3/binutils/dist/libsframe/sframe.c (revision cb63e24e8d6aae7ddac1859a9015f48b1d8bd90e)
1 /* sframe.c - SFrame decoder/encoder.
2 
3    Copyright (C) 2022-2024 Free Software Foundation, Inc.
4 
5    This file is part of libsframe.
6 
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.
11 
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.
16 
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/>.  */
19 
20 #include "config.h"
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <stdarg.h>
24 #include <string.h>
25 #include "sframe-impl.h"
26 #include "swap.h"
27 
28 struct sf_fde_tbl
29 {
30   unsigned int count;
31   unsigned int alloced;
32   sframe_func_desc_entry entry[1];
33 };
34 
35 struct sf_fre_tbl
36 {
37   unsigned int count;
38   unsigned int alloced;
39   sframe_frame_row_entry entry[1];
40 };
41 
42 #define _sf_printflike_(string_index,first_to_check) \
43     __attribute__ ((__format__ (__printf__, (string_index), (first_to_check))))
44 
45 static void debug_printf (const char *, ...);
46 
47 static int _sframe_debug;	/* Control for printing out debug info.  */
48 static int number_of_entries = 64;
49 
50 static void
sframe_init_debug(void)51 sframe_init_debug (void)
52 {
53   static int inited;
54 
55   if (!inited)
56     {
57       _sframe_debug = getenv ("SFRAME_DEBUG") != NULL;
58       inited = 1;
59     }
60 }
61 
62 _sf_printflike_ (1, 2)
debug_printf(const char * format,...)63 static void debug_printf (const char *format, ...)
64 {
65   if (_sframe_debug)
66     {
67       va_list args;
68 
69       va_start (args, format);
70       vfprintf (stderr, format, args);
71       va_end (args);
72     }
73 }
74 
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)
82 
83 /* Store the specified error code into errp if it is non-NULL.
84    Return SFRAME_ERR.  */
85 
86 static int
sframe_set_errno(int * errp,int error)87 sframe_set_errno (int *errp, int error)
88 {
89   if (errp != NULL)
90     *errp = error;
91   return SFRAME_ERR;
92 }
93 
94 /* Store the specified error code into errp if it is non-NULL.
95    Return NULL.  */
96 
97 static void *
sframe_ret_set_errno(int * errp,int error)98 sframe_ret_set_errno (int *errp, int error)
99 {
100   if (errp != NULL)
101     *errp = error;
102   return NULL;
103 }
104 
105 /* Get the SFrame header size.  */
106 
107 static uint32_t
sframe_get_hdr_size(sframe_header * sfh)108 sframe_get_hdr_size (sframe_header *sfh)
109 {
110   return SFRAME_V1_HDR_SIZE (*sfh);
111 }
112 
113 /* Access functions for frame row entry data.  */
114 
115 static uint8_t
sframe_fre_get_offset_count(uint8_t fre_info)116 sframe_fre_get_offset_count (uint8_t fre_info)
117 {
118   return SFRAME_V1_FRE_OFFSET_COUNT (fre_info);
119 }
120 
121 static uint8_t
sframe_fre_get_offset_size(uint8_t fre_info)122 sframe_fre_get_offset_size (uint8_t fre_info)
123 {
124   return SFRAME_V1_FRE_OFFSET_SIZE (fre_info);
125 }
126 
127 static bool
sframe_get_fre_ra_mangled_p(uint8_t fre_info)128 sframe_get_fre_ra_mangled_p (uint8_t fre_info)
129 {
130   return SFRAME_V1_FRE_MANGLED_RA_P (fre_info);
131 }
132 
133 /* Access functions for info from function descriptor entry.  */
134 
135 static uint32_t
sframe_get_fre_type(sframe_func_desc_entry * fdep)136 sframe_get_fre_type (sframe_func_desc_entry *fdep)
137 {
138   uint32_t fre_type = 0;
139   if (fdep)
140     fre_type = SFRAME_V1_FUNC_FRE_TYPE (fdep->sfde_func_info);
141   return fre_type;
142 }
143 
144 static uint32_t
sframe_get_fde_type(sframe_func_desc_entry * fdep)145 sframe_get_fde_type (sframe_func_desc_entry *fdep)
146 {
147   uint32_t fde_type = 0;
148   if (fdep)
149     fde_type = SFRAME_V1_FUNC_FDE_TYPE (fdep->sfde_func_info);
150   return fde_type;
151 }
152 
153 /* Check if flipping is needed, based on ENDIAN.  */
154 
155 static int
need_swapping(int endian)156 need_swapping (int endian)
157 {
158   unsigned int ui = 1;
159   char *c = (char *)&ui;
160   int is_little = (int)*c;
161 
162   switch (endian)
163     {
164       case SFRAME_ABI_AARCH64_ENDIAN_LITTLE:
165       case SFRAME_ABI_AMD64_ENDIAN_LITTLE:
166 	return !is_little;
167       case SFRAME_ABI_AARCH64_ENDIAN_BIG:
168 	return is_little;
169       default:
170 	break;
171     }
172 
173   return 0;
174 }
175 
176 /* Flip the endianness of the SFrame header.  */
177 
178 static void
flip_header(sframe_header * sfheader)179 flip_header (sframe_header *sfheader)
180 {
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);
191 }
192 
193 static void
flip_fde(sframe_func_desc_entry * fdep)194 flip_fde (sframe_func_desc_entry *fdep)
195 {
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);
200 }
201 
202 /* Check if SFrame header has valid data.  */
203 
204 static bool
sframe_header_sanity_check_p(sframe_header * hp)205 sframe_header_sanity_check_p (sframe_header *hp)
206 {
207   unsigned char all_flags = SFRAME_F_FDE_SORTED | SFRAME_F_FRAME_POINTER;
208   /* Check preamble is valid.  */
209   if (hp->sfh_preamble.sfp_magic != SFRAME_MAGIC
210       || (hp->sfh_preamble.sfp_version != SFRAME_VERSION_1
211 	  && hp->sfh_preamble.sfp_version != SFRAME_VERSION_2)
212       || (hp->sfh_preamble.sfp_flags | all_flags) != all_flags)
213     return false;
214 
215   /* Check offsets are valid.  */
216   if (hp->sfh_fdeoff > hp->sfh_freoff)
217     return false;
218 
219   return true;
220 }
221 
222 /* Flip the start address pointed to by FP.  */
223 
224 static void
flip_fre_start_address(char * addr,uint32_t fre_type)225 flip_fre_start_address (char *addr, uint32_t fre_type)
226 {
227   if (fre_type == SFRAME_FRE_TYPE_ADDR2)
228     {
229       uint16_t *start_addr = (uint16_t *)addr;
230       swap_thing (*start_addr);
231     }
232   else if (fre_type == SFRAME_FRE_TYPE_ADDR4)
233     {
234       uint32_t *start_addr = (uint32_t *)addr;
235       swap_thing (*start_addr);
236     }
237 }
238 
239 static void
flip_fre_stack_offsets(char * offsets,uint8_t offset_size,uint8_t offset_cnt)240 flip_fre_stack_offsets (char *offsets, uint8_t offset_size, uint8_t offset_cnt)
241 {
242   int j;
243 
244   if (offset_size == SFRAME_FRE_OFFSET_2B)
245     {
246       uint16_t *ust = (uint16_t *)offsets;
247       for (j = offset_cnt; j > 0; ust++, j--)
248 	swap_thing (*ust);
249     }
250   else if (offset_size == SFRAME_FRE_OFFSET_4B)
251     {
252       uint32_t *uit = (uint32_t *)offsets;
253       for (j = offset_cnt; j > 0; uit++, j--)
254 	swap_thing (*uit);
255     }
256 }
257 
258 /* Get the FRE start address size, given the FRE_TYPE.  */
259 
260 static size_t
sframe_fre_start_addr_size(uint32_t fre_type)261 sframe_fre_start_addr_size (uint32_t fre_type)
262 {
263   size_t addr_size = 0;
264   switch (fre_type)
265     {
266     case SFRAME_FRE_TYPE_ADDR1:
267       addr_size = 1;
268       break;
269     case SFRAME_FRE_TYPE_ADDR2:
270       addr_size = 2;
271       break;
272     case SFRAME_FRE_TYPE_ADDR4:
273       addr_size = 4;
274       break;
275     default:
276       /* No other value is expected.  */
277       sframe_assert (0);
278       break;
279     }
280   return addr_size;
281 }
282 
283 /* Check if the FREP has valid data.  */
284 
285 static bool
sframe_fre_sanity_check_p(sframe_frame_row_entry * frep)286 sframe_fre_sanity_check_p (sframe_frame_row_entry *frep)
287 {
288   uint8_t offset_size, offset_cnt;
289   uint8_t fre_info;
290 
291   if (frep == NULL)
292     return false;
293 
294   fre_info = frep->fre_info;
295   offset_size = sframe_fre_get_offset_size (fre_info);
296 
297   if (offset_size != SFRAME_FRE_OFFSET_1B
298       && offset_size != SFRAME_FRE_OFFSET_2B
299       && offset_size != SFRAME_FRE_OFFSET_4B)
300     return false;
301 
302   offset_cnt = sframe_fre_get_offset_count (fre_info);
303   if (offset_cnt > MAX_NUM_STACK_OFFSETS)
304     return false;
305 
306   return true;
307 }
308 
309 /* Get FRE_INFO's offset size in bytes.  */
310 
311 static size_t
sframe_fre_offset_bytes_size(uint8_t fre_info)312 sframe_fre_offset_bytes_size (uint8_t fre_info)
313 {
314   uint8_t offset_size, offset_cnt;
315 
316   offset_size = sframe_fre_get_offset_size (fre_info);
317 
318   debug_printf ("offset_size =  %u\n", offset_size);
319 
320   offset_cnt = sframe_fre_get_offset_count (fre_info);
321 
322   if (offset_size == SFRAME_FRE_OFFSET_2B
323       || offset_size == SFRAME_FRE_OFFSET_4B)	/* 2 or 4 bytes.  */
324     return (offset_cnt * (offset_size * 2));
325 
326   return (offset_cnt);
327 }
328 
329 /* Get total size in bytes to represent FREP in the binary format.  This
330    includes the starting address, FRE info, and all the offsets.  */
331 
332 static size_t
sframe_fre_entry_size(sframe_frame_row_entry * frep,uint32_t fre_type)333 sframe_fre_entry_size (sframe_frame_row_entry *frep, uint32_t fre_type)
334 {
335   if (frep == NULL)
336     return 0;
337 
338   uint8_t fre_info = frep->fre_info;
339   size_t addr_size = sframe_fre_start_addr_size (fre_type);
340 
341   return (addr_size + sizeof (frep->fre_info)
342 	  + sframe_fre_offset_bytes_size (fre_info));
343 }
344 
345 /* Get the function descriptor entry at index FUNC_IDX in the decoder
346    context CTX.  */
347 
348 static sframe_func_desc_entry *
sframe_decoder_get_funcdesc_at_index(sframe_decoder_ctx * ctx,uint32_t func_idx)349 sframe_decoder_get_funcdesc_at_index (sframe_decoder_ctx *ctx,
350 				      uint32_t func_idx)
351 {
352   sframe_func_desc_entry *fdep;
353   uint32_t num_fdes;
354   int err;
355 
356   num_fdes = sframe_decoder_get_num_fidx (ctx);
357   if (num_fdes == 0
358       || func_idx >= num_fdes
359       || ctx->sfd_funcdesc == NULL)
360     return sframe_ret_set_errno (&err, SFRAME_ERR_DCTX_INVAL);
361 
362   fdep = &ctx->sfd_funcdesc[func_idx];
363   return fdep;
364 }
365 
366 /* Check whether for the given FDEP, the SFrame Frame Row Entry identified via
367    the START_IP_OFFSET and the END_IP_OFFSET, provides the stack trace
368    information for the PC.  */
369 
370 static bool
sframe_fre_check_range_p(sframe_func_desc_entry * fdep,int32_t start_ip_offset,int32_t end_ip_offset,int32_t pc)371 sframe_fre_check_range_p (sframe_func_desc_entry *fdep,
372 			  int32_t start_ip_offset, int32_t end_ip_offset,
373 			  int32_t pc)
374 {
375   int32_t start_ip, end_ip;
376   int32_t func_start_addr;
377   uint8_t rep_block_size;
378   uint32_t fde_type;
379   int32_t masked_pc;
380   bool mask_p;
381   bool ret;
382 
383   ret = false;
384 
385   if (!fdep)
386     return ret;
387 
388   func_start_addr = fdep->sfde_func_start_address;
389   fde_type = sframe_get_fde_type (fdep);
390   mask_p = (fde_type == SFRAME_FDE_TYPE_PCMASK);
391   rep_block_size = fdep->sfde_func_rep_size;
392 
393   if (!mask_p)
394     {
395       start_ip = start_ip_offset + func_start_addr;
396       end_ip = end_ip_offset + func_start_addr;
397       ret = ((start_ip <= pc) && (end_ip >= pc));
398     }
399   else
400     {
401       /* For FDEs for repetitive pattern of insns, we need to return the FRE
402 	 where pc % rep_block_size is between start_ip_offset and
403 	 end_ip_offset.  */
404       masked_pc = pc % rep_block_size;
405       ret = ((start_ip_offset <= masked_pc) && (end_ip_offset >= masked_pc));
406     }
407 
408   return ret;
409 }
410 
411 static int
flip_fre(char * fp,uint32_t fre_type,size_t * fre_size)412 flip_fre (char *fp, uint32_t fre_type, size_t *fre_size)
413 {
414   uint8_t fre_info;
415   uint8_t offset_size, offset_cnt;
416   size_t addr_size, fre_info_size = 0;
417   int err = 0;
418 
419   if (fre_size == NULL)
420     return sframe_set_errno (&err, SFRAME_ERR_INVAL);
421 
422   flip_fre_start_address (fp, fre_type);
423 
424   /* Advance the buffer pointer to where the FRE info is.  */
425   addr_size = sframe_fre_start_addr_size (fre_type);
426   fp += addr_size;
427 
428   /* FRE info is uint8_t.  No need to flip.  */
429   fre_info = *(uint8_t*)fp;
430   offset_size = sframe_fre_get_offset_size (fre_info);
431   offset_cnt = sframe_fre_get_offset_count (fre_info);
432 
433   /* Advance the buffer pointer to where the stack offsets are.  */
434   fre_info_size = sizeof (uint8_t);
435   fp += fre_info_size;
436   flip_fre_stack_offsets (fp, offset_size, offset_cnt);
437 
438   *fre_size
439     = addr_size + fre_info_size + sframe_fre_offset_bytes_size (fre_info);
440 
441   return 0;
442 }
443 
444 /* Endian flip the contents of FRAME_BUF of size BUF_SIZE.
445    The SFrame header in the FRAME_BUF must be endian flipped prior to
446    calling flip_sframe.
447 
448    Endian flipping at decode time vs encode time have different needs.  At
449    encode time, the frame_buf is in host endianness, and hence, values should
450    be read up before the buffer is changed to foreign endianness.  This change
451    of behaviour is specified via TO_FOREIGN arg.
452 
453    If an error code is returned, the buffer should not be used.  */
454 
455 static int
flip_sframe(char * frame_buf,size_t buf_size,uint32_t to_foreign)456 flip_sframe (char *frame_buf, size_t buf_size, uint32_t to_foreign)
457 {
458   unsigned int i, j, prev_frep_index;
459   sframe_header *ihp;
460   char *fdes;
461   char *fp = NULL;
462   sframe_func_desc_entry *fdep;
463   unsigned int num_fdes = 0;
464   unsigned int num_fres = 0;
465   uint32_t fre_type = 0;
466   uint32_t fre_offset = 0;
467   size_t esz = 0;
468   size_t hdrsz = 0;
469   int err = 0;
470   /* For error checking.  */
471   size_t bytes_flipped = 0;
472 
473   /* Header must be in host endianness at this time.  */
474   ihp = (sframe_header *)frame_buf;
475 
476   if (!sframe_header_sanity_check_p (ihp))
477     return sframe_set_errno (&err, SFRAME_ERR_BUF_INVAL);
478 
479   /* The contents of the SFrame header are safe to read.  Get the number of
480      FDEs and the first FDE in the buffer.  */
481   hdrsz = sframe_get_hdr_size (ihp);
482   num_fdes = ihp->sfh_num_fdes;
483   fdes = frame_buf + hdrsz + ihp->sfh_fdeoff;
484   fdep = (sframe_func_desc_entry *)fdes;
485 
486   j = 0;
487   prev_frep_index = 0;
488   for (i = 0; i < num_fdes; fdep++, i++)
489     {
490       if ((char*)fdep >= (frame_buf + buf_size))
491 	goto bad;
492 
493       if (to_foreign)
494 	{
495 	  num_fres = fdep->sfde_func_num_fres;
496 	  fre_type = sframe_get_fre_type (fdep);
497 	  fre_offset = fdep->sfde_func_start_fre_off;
498 	}
499 
500       flip_fde (fdep);
501       bytes_flipped += sizeof (sframe_func_desc_entry);
502 
503       if (!to_foreign)
504 	{
505 	  num_fres = fdep->sfde_func_num_fres;
506 	  fre_type = sframe_get_fre_type (fdep);
507 	  fre_offset = fdep->sfde_func_start_fre_off;
508 	}
509 
510       fp = frame_buf + sframe_get_hdr_size (ihp) + ihp->sfh_freoff;
511       fp += fre_offset;
512       for (; j < prev_frep_index + num_fres; j++)
513 	{
514 	  if (flip_fre (fp, fre_type, &esz))
515 	    goto bad;
516 	  bytes_flipped += esz;
517 
518 	  if (esz == 0 || esz > buf_size)
519 	    goto bad;
520 	  fp += esz;
521 	}
522       prev_frep_index = j;
523     }
524   /* All FDEs and FREs must have been endian flipped by now.  */
525   if ((j != ihp->sfh_num_fres) || (bytes_flipped != (buf_size - hdrsz)))
526     goto bad;
527 
528   /* Success.  */
529   return 0;
530 bad:
531   return SFRAME_ERR;
532 }
533 
534 /* The SFrame Decoder.  */
535 
536 /* Get SFrame header from the given decoder context DCTX.  */
537 
538 static sframe_header *
sframe_decoder_get_header(sframe_decoder_ctx * dctx)539 sframe_decoder_get_header (sframe_decoder_ctx *dctx)
540 {
541   sframe_header *hp = NULL;
542   if (dctx != NULL)
543     hp = &dctx->sfd_header;
544   return hp;
545 }
546 
547 /* Compare function for qsort'ing the FDE table.  */
548 
549 static int
fde_func(const void * p1,const void * p2)550 fde_func (const void *p1, const void *p2)
551 {
552   const sframe_func_desc_entry *aa = p1;
553   const sframe_func_desc_entry *bb = p2;
554 
555   if (aa->sfde_func_start_address < bb->sfde_func_start_address)
556     return -1;
557   else if (aa->sfde_func_start_address > bb->sfde_func_start_address)
558     return 1;
559   return 0;
560 }
561 
562 /* Get IDX'th offset from FRE.  Set errp as applicable.  */
563 
564 static int32_t
sframe_get_fre_offset(sframe_frame_row_entry * fre,int idx,int * errp)565 sframe_get_fre_offset (sframe_frame_row_entry *fre, int idx, int *errp)
566 {
567   uint8_t offset_cnt, offset_size;
568 
569   if (fre == NULL || !sframe_fre_sanity_check_p (fre))
570     return sframe_set_errno (errp, SFRAME_ERR_FRE_INVAL);
571 
572   offset_cnt = sframe_fre_get_offset_count (fre->fre_info);
573   offset_size = sframe_fre_get_offset_size (fre->fre_info);
574 
575   if (offset_cnt < idx + 1)
576     return sframe_set_errno (errp, SFRAME_ERR_FREOFFSET_NOPRESENT);
577 
578   if (errp)
579     *errp = 0; /* Offset Valid.  */
580 
581   if (offset_size == SFRAME_FRE_OFFSET_1B)
582     {
583       int8_t *sp = (int8_t *)fre->fre_offsets;
584       return sp[idx];
585     }
586   else if (offset_size == SFRAME_FRE_OFFSET_2B)
587     {
588       int16_t *sp = (int16_t *)fre->fre_offsets;
589       return sp[idx];
590     }
591   else
592     {
593       int32_t *ip = (int32_t *)fre->fre_offsets;
594       return ip[idx];
595     }
596 }
597 
598 /* Free the decoder context.  */
599 
600 void
sframe_decoder_free(sframe_decoder_ctx ** dctxp)601 sframe_decoder_free (sframe_decoder_ctx **dctxp)
602 {
603   if (dctxp != NULL)
604     {
605       sframe_decoder_ctx *dctx = *dctxp;
606       if (dctx == NULL)
607 	return;
608 
609       if (dctx->sfd_funcdesc != NULL)
610 	{
611 	  free (dctx->sfd_funcdesc);
612 	  dctx->sfd_funcdesc = NULL;
613 	}
614       if (dctx->sfd_fres != NULL)
615 	{
616 	  free (dctx->sfd_fres);
617 	  dctx->sfd_fres = NULL;
618 	}
619       if (dctx->sfd_buf != NULL)
620 	{
621 	  free (dctx->sfd_buf);
622 	  dctx->sfd_buf = NULL;
623 	}
624 
625       free (*dctxp);
626       *dctxp = NULL;
627     }
628 }
629 
630 /* Create an FDE function info byte given an FRE_TYPE and an FDE_TYPE.  */
631 /* FIXME API for linker.  Revisit if its better placed somewhere else?  */
632 
633 unsigned char
sframe_fde_create_func_info(uint32_t fre_type,uint32_t fde_type)634 sframe_fde_create_func_info (uint32_t fre_type,
635 			     uint32_t fde_type)
636 {
637   unsigned char func_info;
638   sframe_assert (fre_type == SFRAME_FRE_TYPE_ADDR1
639 		   || fre_type == SFRAME_FRE_TYPE_ADDR2
640 		   || fre_type == SFRAME_FRE_TYPE_ADDR4);
641   sframe_assert (fde_type == SFRAME_FDE_TYPE_PCINC
642 		    || fde_type == SFRAME_FDE_TYPE_PCMASK);
643   func_info = SFRAME_V1_FUNC_INFO (fde_type, fre_type);
644   return func_info;
645 }
646 
647 /* Get the FRE type given the function size.  */
648 /* FIXME API for linker.  Revisit if its better placed somewhere else?  */
649 
650 uint32_t
sframe_calc_fre_type(size_t func_size)651 sframe_calc_fre_type (size_t func_size)
652 {
653   uint32_t fre_type = 0;
654   if (func_size < SFRAME_FRE_TYPE_ADDR1_LIMIT)
655     fre_type = SFRAME_FRE_TYPE_ADDR1;
656   else if (func_size < SFRAME_FRE_TYPE_ADDR2_LIMIT)
657     fre_type = SFRAME_FRE_TYPE_ADDR2;
658   /* Adjust the check a bit so that it remains warning-free but meaningful
659      on 32-bit systems.  */
660   else if (func_size <= (size_t) (SFRAME_FRE_TYPE_ADDR4_LIMIT - 1))
661     fre_type = SFRAME_FRE_TYPE_ADDR4;
662   return fre_type;
663 }
664 
665 /* Get the base reg id from the FRE info.  Set errp if failure.  */
666 
667 uint8_t
sframe_fre_get_base_reg_id(sframe_frame_row_entry * fre,int * errp)668 sframe_fre_get_base_reg_id (sframe_frame_row_entry *fre, int *errp)
669 {
670   if (fre == NULL)
671     return sframe_set_errno (errp, SFRAME_ERR_FRE_INVAL);
672 
673   uint8_t fre_info = fre->fre_info;
674   return SFRAME_V1_FRE_CFA_BASE_REG_ID (fre_info);
675 }
676 
677 /* Get the CFA offset from the FRE.  If the offset is invalid, sets errp.  */
678 
679 int32_t
sframe_fre_get_cfa_offset(sframe_decoder_ctx * dctx ATTRIBUTE_UNUSED,sframe_frame_row_entry * fre,int * errp)680 sframe_fre_get_cfa_offset (sframe_decoder_ctx *dctx ATTRIBUTE_UNUSED,
681 			   sframe_frame_row_entry *fre, int *errp)
682 {
683   return sframe_get_fre_offset (fre, SFRAME_FRE_CFA_OFFSET_IDX, errp);
684 }
685 
686 /* Get the FP offset from the FRE.  If the offset is invalid, sets errp.  */
687 
688 int32_t
sframe_fre_get_fp_offset(sframe_decoder_ctx * dctx,sframe_frame_row_entry * fre,int * errp)689 sframe_fre_get_fp_offset (sframe_decoder_ctx *dctx,
690 			  sframe_frame_row_entry *fre, int *errp)
691 {
692   uint32_t fp_offset_idx = 0;
693   int8_t fp_offset = sframe_decoder_get_fixed_fp_offset (dctx);
694   /* If the FP offset is not being tracked, return the fixed FP offset
695      from the SFrame header.  */
696   if (fp_offset != SFRAME_CFA_FIXED_FP_INVALID)
697     {
698       if (errp)
699 	*errp = 0;
700       return fp_offset;
701     }
702 
703   /* In some ABIs, the stack offset to recover RA (using the CFA) from is
704      fixed (like AMD64).  In such cases, the stack offset to recover FP will
705      appear at the second index.  */
706   fp_offset_idx = ((sframe_decoder_get_fixed_ra_offset (dctx)
707 		    != SFRAME_CFA_FIXED_RA_INVALID)
708 		   ? SFRAME_FRE_RA_OFFSET_IDX
709 		   : SFRAME_FRE_FP_OFFSET_IDX);
710   return sframe_get_fre_offset (fre, fp_offset_idx, errp);
711 }
712 
713 /* Get the RA offset from the FRE.  If the offset is invalid, sets errp.  */
714 
715 int32_t
sframe_fre_get_ra_offset(sframe_decoder_ctx * dctx,sframe_frame_row_entry * fre,int * errp)716 sframe_fre_get_ra_offset (sframe_decoder_ctx *dctx,
717 			  sframe_frame_row_entry *fre, int *errp)
718 {
719   int8_t ra_offset = sframe_decoder_get_fixed_ra_offset (dctx);
720   /* If the RA offset was not being tracked, return the fixed RA offset
721      from the SFrame header.  */
722   if (ra_offset != SFRAME_CFA_FIXED_RA_INVALID)
723     {
724       if (errp)
725 	*errp = 0;
726       return ra_offset;
727     }
728 
729   /* Otherwise, get the RA offset from the FRE.  */
730   return sframe_get_fre_offset (fre, SFRAME_FRE_RA_OFFSET_IDX, errp);
731 }
732 
733 /* Get whether the RA is mangled.  */
734 
735 bool
sframe_fre_get_ra_mangled_p(sframe_decoder_ctx * dctx ATTRIBUTE_UNUSED,sframe_frame_row_entry * fre,int * errp)736 sframe_fre_get_ra_mangled_p (sframe_decoder_ctx *dctx ATTRIBUTE_UNUSED,
737 			     sframe_frame_row_entry *fre, int *errp)
738 {
739   if (fre == NULL || !sframe_fre_sanity_check_p (fre))
740     return sframe_set_errno (errp, SFRAME_ERR_FRE_INVAL);
741 
742   return sframe_get_fre_ra_mangled_p (fre->fre_info);
743 }
744 
745 static int
sframe_frame_row_entry_copy(sframe_frame_row_entry * dst,sframe_frame_row_entry * src)746 sframe_frame_row_entry_copy (sframe_frame_row_entry *dst,
747 			     sframe_frame_row_entry *src)
748 {
749   int err = 0;
750 
751   if (dst == NULL || src == NULL)
752     return sframe_set_errno (&err, SFRAME_ERR_INVAL);
753 
754   memcpy (dst, src, sizeof (sframe_frame_row_entry));
755   return 0;
756 }
757 
758 /* Decode the SFrame FRE start address offset value from FRE_BUF in on-disk
759    binary format, given the FRE_TYPE.  Updates the FRE_START_ADDR.
760 
761    Returns 0 on success, SFRAME_ERR otherwise.  */
762 
763 static int
sframe_decode_fre_start_address(const char * fre_buf,uint32_t * fre_start_addr,uint32_t fre_type)764 sframe_decode_fre_start_address (const char *fre_buf,
765 				 uint32_t *fre_start_addr,
766 				 uint32_t fre_type)
767 {
768   uint32_t saddr = 0;
769   int err = 0;
770   size_t addr_size = 0;
771 
772   addr_size = sframe_fre_start_addr_size (fre_type);
773 
774   if (fre_type == SFRAME_FRE_TYPE_ADDR1)
775     {
776       uint8_t *uc = (uint8_t *)fre_buf;
777       saddr = (uint32_t)*uc;
778     }
779   else if (fre_type == SFRAME_FRE_TYPE_ADDR2)
780     {
781       uint16_t *ust = (uint16_t *)fre_buf;
782       /* SFrame is an unaligned on-disk format.  Using memcpy helps avoid the
783 	 use of undesirable unaligned loads.  See PR libsframe/29856.  */
784       uint16_t tmp = 0;
785       memcpy (&tmp, ust, addr_size);
786       saddr = (uint32_t)tmp;
787     }
788   else if (fre_type == SFRAME_FRE_TYPE_ADDR4)
789     {
790       uint32_t *uit = (uint32_t *)fre_buf;
791       uint32_t tmp = 0;
792       memcpy (&tmp, uit, addr_size);
793       saddr = (uint32_t)tmp;
794     }
795   else
796     return sframe_set_errno (&err, SFRAME_ERR_INVAL);
797 
798   *fre_start_addr = saddr;
799   return 0;
800 }
801 
802 /* Decode a frame row entry FRE which starts at location FRE_BUF.  The function
803    updates ESZ to the size of the FRE as stored in the binary format.
804 
805    This function works closely with the SFrame binary format.
806 
807    Returns SFRAME_ERR if failure.  */
808 
809 static int
sframe_decode_fre(const char * fre_buf,sframe_frame_row_entry * fre,uint32_t fre_type,size_t * esz)810 sframe_decode_fre (const char *fre_buf, sframe_frame_row_entry *fre,
811 		   uint32_t fre_type, size_t *esz)
812 {
813   int err = 0;
814   const char *stack_offsets = NULL;
815   size_t stack_offsets_sz;
816   size_t addr_size;
817   size_t fre_size;
818 
819   if (fre_buf == NULL || fre == NULL || esz == NULL)
820     return sframe_set_errno (&err, SFRAME_ERR_INVAL);
821 
822   /* Copy over the FRE start address.  */
823   sframe_decode_fre_start_address (fre_buf, &fre->fre_start_addr, fre_type);
824 
825   addr_size = sframe_fre_start_addr_size (fre_type);
826   fre->fre_info = *(uint8_t *)(fre_buf + addr_size);
827   /* Sanity check as the API works closely with the binary format.  */
828   sframe_assert (sizeof (fre->fre_info) == sizeof (uint8_t));
829 
830   /* Cleanup the space for fre_offsets first, then copy over the valid
831      bytes.  */
832   memset (fre->fre_offsets, 0, MAX_OFFSET_BYTES);
833   /* Get offsets size.  */
834   stack_offsets_sz = sframe_fre_offset_bytes_size (fre->fre_info);
835   stack_offsets = fre_buf + addr_size + sizeof (fre->fre_info);
836   memcpy (fre->fre_offsets, stack_offsets, stack_offsets_sz);
837 
838   /* The FRE has been decoded.  Use it to perform one last sanity check.  */
839   fre_size = sframe_fre_entry_size (fre, fre_type);
840   sframe_assert (fre_size == (addr_size + sizeof (fre->fre_info)
841 			      + stack_offsets_sz));
842   *esz = fre_size;
843 
844   return 0;
845 }
846 
847 /* Decode the specified SFrame buffer CF_BUF of size CF_SIZE and return the
848    new SFrame decoder context.
849 
850    Sets ERRP for the caller if any error.  Frees up the allocated memory in
851    case of error.  */
852 
853 sframe_decoder_ctx *
sframe_decode(const char * sf_buf,size_t sf_size,int * errp)854 sframe_decode (const char *sf_buf, size_t sf_size, int *errp)
855 {
856   const sframe_preamble *sfp;
857   size_t hdrsz;
858   sframe_header *sfheaderp;
859   sframe_decoder_ctx *dctx;
860   char *frame_buf;
861   char *tempbuf = NULL;
862 
863   int fidx_size;
864   uint32_t fre_bytes;
865   int foreign_endian = 0;
866 
867   sframe_init_debug ();
868 
869   if ((sf_buf == NULL) || (!sf_size))
870     return sframe_ret_set_errno (errp, SFRAME_ERR_INVAL);
871   else if (sf_size < sizeof (sframe_header))
872     return sframe_ret_set_errno (errp, SFRAME_ERR_BUF_INVAL);
873 
874   sfp = (const sframe_preamble *) sf_buf;
875 
876   debug_printf ("sframe_decode: magic=0x%x version=%u flags=%u\n",
877 		sfp->sfp_magic, sfp->sfp_version, sfp->sfp_flags);
878 
879   /* Check for foreign endianness.  */
880   if (sfp->sfp_magic != SFRAME_MAGIC)
881     {
882       if (sfp->sfp_magic == bswap_16 (SFRAME_MAGIC))
883 	foreign_endian = 1;
884       else
885 	return sframe_ret_set_errno (errp, SFRAME_ERR_BUF_INVAL);
886     }
887 
888   /* Initialize a new decoder context.  */
889   if ((dctx = malloc (sizeof (sframe_decoder_ctx))) == NULL)
890     return sframe_ret_set_errno (errp, SFRAME_ERR_NOMEM);
891   memset (dctx, 0, sizeof (sframe_decoder_ctx));
892 
893   if (foreign_endian)
894     {
895       /* Allocate a new buffer and initialize it.  */
896       tempbuf = (char *) malloc (sf_size * sizeof (char));
897       if (tempbuf == NULL)
898 	return sframe_ret_set_errno (errp, SFRAME_ERR_NOMEM);
899       memcpy (tempbuf, sf_buf, sf_size);
900 
901       /* Flip the header.  */
902       sframe_header *ihp = (sframe_header *) tempbuf;
903       flip_header (ihp);
904       /* Flip the rest of the SFrame section data buffer.  */
905       if (flip_sframe (tempbuf, sf_size, 0))
906 	{
907 	  free (tempbuf);
908 	  return sframe_ret_set_errno (errp, SFRAME_ERR_BUF_INVAL);
909 	}
910       frame_buf = tempbuf;
911       /* This buffer is malloc'd when endian flipping the contents of the input
912 	 buffer are needed.  Keep a reference to it so it can be free'd up
913 	 later in sframe_decoder_free ().  */
914       dctx->sfd_buf = tempbuf;
915     }
916   else
917     frame_buf = (char *)sf_buf;
918 
919   /* Handle the SFrame header.  */
920   dctx->sfd_header = *(sframe_header *) frame_buf;
921   /* Validate the contents of SFrame header.  */
922   sfheaderp = &dctx->sfd_header;
923   if (!sframe_header_sanity_check_p (sfheaderp))
924     {
925       sframe_ret_set_errno (errp, SFRAME_ERR_NOMEM);
926       goto decode_fail_free;
927     }
928   hdrsz = sframe_get_hdr_size (sfheaderp);
929   frame_buf += hdrsz;
930 
931   /* Handle the SFrame Function Descriptor Entry section.  */
932   fidx_size
933     = sfheaderp->sfh_num_fdes * sizeof (sframe_func_desc_entry);
934   dctx->sfd_funcdesc = malloc (fidx_size);
935   if (dctx->sfd_funcdesc == NULL)
936     {
937       sframe_ret_set_errno (errp, SFRAME_ERR_NOMEM);
938       goto decode_fail_free;
939     }
940   memcpy (dctx->sfd_funcdesc, frame_buf, fidx_size);
941 
942   debug_printf ("%u total fidx size\n", fidx_size);
943 
944   frame_buf += (fidx_size);
945 
946   /* Handle the SFrame Frame Row Entry section.  */
947   dctx->sfd_fres = (char *) malloc (sfheaderp->sfh_fre_len);
948   if (dctx->sfd_fres == NULL)
949     {
950       sframe_ret_set_errno (errp, SFRAME_ERR_NOMEM);
951       goto decode_fail_free;
952     }
953   memcpy (dctx->sfd_fres, frame_buf, sfheaderp->sfh_fre_len);
954 
955   fre_bytes = sfheaderp->sfh_fre_len;
956   dctx->sfd_fre_nbytes = fre_bytes;
957 
958   debug_printf ("%u total fre bytes\n", fre_bytes);
959 
960   return dctx;
961 
962 decode_fail_free:
963   if (foreign_endian && tempbuf != NULL)
964     free (tempbuf);
965   sframe_decoder_free (&dctx);
966   dctx = NULL;
967   return dctx;
968 }
969 
970 /* Get the size of the SFrame header from the decoder context CTX.  */
971 
972 unsigned int
sframe_decoder_get_hdr_size(sframe_decoder_ctx * ctx)973 sframe_decoder_get_hdr_size (sframe_decoder_ctx *ctx)
974 {
975   sframe_header *dhp;
976   dhp = sframe_decoder_get_header (ctx);
977   return sframe_get_hdr_size (dhp);
978 }
979 
980 /* Get the SFrame's abi/arch info given the decoder context DCTX.  */
981 
982 uint8_t
sframe_decoder_get_abi_arch(sframe_decoder_ctx * dctx)983 sframe_decoder_get_abi_arch (sframe_decoder_ctx *dctx)
984 {
985   sframe_header *sframe_header;
986   sframe_header = sframe_decoder_get_header (dctx);
987   return sframe_header->sfh_abi_arch;
988 }
989 
990 /* Get the format version from the SFrame decoder context DCTX.  */
991 
992 uint8_t
sframe_decoder_get_version(sframe_decoder_ctx * dctx)993 sframe_decoder_get_version (sframe_decoder_ctx *dctx)
994 {
995   sframe_header *dhp;
996   dhp = sframe_decoder_get_header (dctx);
997   return dhp->sfh_preamble.sfp_version;
998 }
999 
1000 /* Get the SFrame's fixed FP offset given the decoder context CTX.  */
1001 int8_t
sframe_decoder_get_fixed_fp_offset(sframe_decoder_ctx * ctx)1002 sframe_decoder_get_fixed_fp_offset (sframe_decoder_ctx *ctx)
1003 {
1004   sframe_header *dhp;
1005   dhp = sframe_decoder_get_header (ctx);
1006   return dhp->sfh_cfa_fixed_fp_offset;
1007 }
1008 
1009 /* Get the SFrame's fixed RA offset given the decoder context CTX.  */
1010 int8_t
sframe_decoder_get_fixed_ra_offset(sframe_decoder_ctx * ctx)1011 sframe_decoder_get_fixed_ra_offset (sframe_decoder_ctx *ctx)
1012 {
1013   sframe_header *dhp;
1014   dhp = sframe_decoder_get_header (ctx);
1015   return dhp->sfh_cfa_fixed_ra_offset;
1016 }
1017 
1018 /* Find the function descriptor entry which contains the specified address
1019    ADDR.
1020    This function is deprecated and will be removed from libsframe.so.2.  */
1021 
1022 void *
sframe_get_funcdesc_with_addr(sframe_decoder_ctx * ctx,int32_t addr,int * errp)1023 sframe_get_funcdesc_with_addr (sframe_decoder_ctx *ctx __attribute__ ((unused)),
1024 			       int32_t addr __attribute__ ((unused)),
1025 			       int *errp)
1026 {
1027   return sframe_ret_set_errno (errp, SFRAME_ERR_INVAL);
1028 }
1029 
1030 /* Find the function descriptor entry starting which contains the specified
1031    address ADDR.  */
1032 
1033 static sframe_func_desc_entry *
sframe_get_funcdesc_with_addr_internal(sframe_decoder_ctx * ctx,int32_t addr,int * errp)1034 sframe_get_funcdesc_with_addr_internal (sframe_decoder_ctx *ctx, int32_t addr,
1035 					int *errp)
1036 {
1037   sframe_header *dhp;
1038   sframe_func_desc_entry *fdp;
1039   int low, high, cnt;
1040 
1041   if (ctx == NULL)
1042     return sframe_ret_set_errno (errp, SFRAME_ERR_INVAL);
1043 
1044   dhp = sframe_decoder_get_header (ctx);
1045 
1046   if (dhp == NULL || dhp->sfh_num_fdes == 0 || ctx->sfd_funcdesc == NULL)
1047     return sframe_ret_set_errno (errp, SFRAME_ERR_DCTX_INVAL);
1048   /* If the FDE sub-section is not sorted on PCs, skip the lookup because
1049      binary search cannot be used.  */
1050   if ((dhp->sfh_preamble.sfp_flags & SFRAME_F_FDE_SORTED) == 0)
1051     return sframe_ret_set_errno (errp, SFRAME_ERR_FDE_NOTSORTED);
1052 
1053   /* Do the binary search.  */
1054   fdp = (sframe_func_desc_entry *) ctx->sfd_funcdesc;
1055   low = 0;
1056   high = dhp->sfh_num_fdes;
1057   cnt = high;
1058   while (low <= high)
1059     {
1060       int mid = low + (high - low) / 2;
1061 
1062       if (fdp[mid].sfde_func_start_address == addr)
1063 	return fdp + mid;
1064 
1065       if (fdp[mid].sfde_func_start_address < addr)
1066 	{
1067 	  if (mid == (cnt - 1)) 	/* Check if it's the last one.  */
1068 	    return fdp + (cnt - 1);
1069 	  else if (fdp[mid+1].sfde_func_start_address > addr)
1070 	    return fdp + mid;
1071 	  low = mid + 1;
1072 	}
1073       else
1074 	high = mid - 1;
1075     }
1076 
1077   return sframe_ret_set_errno (errp, SFRAME_ERR_FDE_NOTFOUND);
1078 }
1079 
1080 /* Get the end IP offset for the FRE at index i in the FDEP.  The buffer FRES
1081    is the starting location for the FRE.  */
1082 
1083 static uint32_t
sframe_fre_get_end_ip_offset(sframe_func_desc_entry * fdep,unsigned int i,const char * fres)1084 sframe_fre_get_end_ip_offset (sframe_func_desc_entry *fdep, unsigned int i,
1085 			      const char *fres)
1086 {
1087   uint32_t end_ip_offset;
1088   uint32_t fre_type;
1089 
1090   fre_type = sframe_get_fre_type (fdep);
1091 
1092   /* Get the start address of the next FRE in sequence.  */
1093   if (i < fdep->sfde_func_num_fres - 1)
1094     {
1095       sframe_decode_fre_start_address (fres, &end_ip_offset, fre_type);
1096       end_ip_offset -= 1;
1097     }
1098   else
1099     /* The end IP offset for the FRE needs to be deduced from the function
1100        size.  */
1101     end_ip_offset = fdep->sfde_func_size - 1;
1102 
1103   return end_ip_offset;
1104 }
1105 
1106 /* Find the SFrame Row Entry which contains the PC.  Returns
1107    SFRAME_ERR if failure.  */
1108 
1109 int
sframe_find_fre(sframe_decoder_ctx * ctx,int32_t pc,sframe_frame_row_entry * frep)1110 sframe_find_fre (sframe_decoder_ctx *ctx, int32_t pc,
1111 		 sframe_frame_row_entry *frep)
1112 {
1113   sframe_frame_row_entry cur_fre;
1114   sframe_func_desc_entry *fdep;
1115   uint32_t fre_type, fde_type, i;
1116   int32_t start_ip_offset;
1117   int32_t func_start_addr;
1118   int32_t end_ip_offset;
1119   const char *fres;
1120   size_t size = 0;
1121   int err = 0;
1122   bool mask_p;
1123 
1124   if ((ctx == NULL) || (frep == NULL))
1125     return sframe_set_errno (&err, SFRAME_ERR_INVAL);
1126 
1127   /* Find the FDE which contains the PC, then scan its fre entries.  */
1128   fdep = sframe_get_funcdesc_with_addr_internal (ctx, pc, &err);
1129   if (fdep == NULL || ctx->sfd_fres == NULL)
1130     return sframe_set_errno (&err, SFRAME_ERR_DCTX_INVAL);
1131 
1132   fre_type = sframe_get_fre_type (fdep);
1133   fde_type = sframe_get_fde_type (fdep);
1134   mask_p = (fde_type == SFRAME_FDE_TYPE_PCMASK);
1135 
1136   fres = ctx->sfd_fres + fdep->sfde_func_start_fre_off;
1137   func_start_addr = fdep->sfde_func_start_address;
1138 
1139   for (i = 0; i < fdep->sfde_func_num_fres; i++)
1140    {
1141      err = sframe_decode_fre (fres, &cur_fre, fre_type, &size);
1142      if (err)
1143        return sframe_set_errno (&err, SFRAME_ERR_FRE_INVAL);
1144 
1145      start_ip_offset = cur_fre.fre_start_addr;
1146      end_ip_offset = sframe_fre_get_end_ip_offset (fdep, i, fres + size);
1147 
1148      /* First FRE's start_ip must be more than pc for regular SFrame FDEs.  */
1149      if (i == 0 && !mask_p && (start_ip_offset + func_start_addr) > pc)
1150        return sframe_set_errno (&err, SFRAME_ERR_FRE_INVAL);
1151 
1152      if (sframe_fre_check_range_p (fdep, start_ip_offset, end_ip_offset, pc))
1153        {
1154 	 sframe_frame_row_entry_copy (frep, &cur_fre);
1155 	 return 0;
1156        }
1157      fres += size;
1158    }
1159   return sframe_set_errno (&err, SFRAME_ERR_FDE_INVAL);
1160 }
1161 
1162 /* Return the number of function descriptor entries in the SFrame decoder
1163    DCTX.  */
1164 
1165 uint32_t
sframe_decoder_get_num_fidx(sframe_decoder_ctx * ctx)1166 sframe_decoder_get_num_fidx (sframe_decoder_ctx *ctx)
1167 {
1168   uint32_t num_fdes = 0;
1169   sframe_header *dhp = NULL;
1170   dhp = sframe_decoder_get_header (ctx);
1171   if (dhp)
1172     num_fdes = dhp->sfh_num_fdes;
1173   return num_fdes;
1174 }
1175 
1176 /* Get the data (NUM_FRES, FUNC_START_ADDRESS) from the function
1177    descriptor entry at index I'th in the decoder CTX.  If failed,
1178    return error code.  */
1179 /* FIXME - consolidate the args and return a
1180    sframe_func_desc_index_elem rather?  */
1181 
1182 int
sframe_decoder_get_funcdesc(sframe_decoder_ctx * ctx,unsigned int i,uint32_t * num_fres,uint32_t * func_size,int32_t * func_start_address,unsigned char * func_info)1183 sframe_decoder_get_funcdesc (sframe_decoder_ctx *ctx,
1184 			     unsigned int i,
1185 			     uint32_t *num_fres,
1186 			     uint32_t *func_size,
1187 			     int32_t *func_start_address,
1188 			     unsigned char *func_info)
1189 {
1190   sframe_func_desc_entry *fdp;
1191   int err = 0;
1192 
1193   if (ctx == NULL || func_start_address == NULL || num_fres == NULL
1194       || func_size == NULL)
1195     return sframe_set_errno (&err, SFRAME_ERR_INVAL);
1196 
1197   fdp = sframe_decoder_get_funcdesc_at_index (ctx, i);
1198 
1199   if (fdp == NULL)
1200     return sframe_set_errno (&err, SFRAME_ERR_FDE_NOTFOUND);
1201 
1202   *num_fres = fdp->sfde_func_num_fres;
1203   *func_start_address = fdp->sfde_func_start_address;
1204   *func_size = fdp->sfde_func_size;
1205   *func_info = fdp->sfde_func_info;
1206 
1207   return 0;
1208 }
1209 
1210 int
sframe_decoder_get_funcdesc_v2(sframe_decoder_ctx * dctx,unsigned int i,uint32_t * num_fres,uint32_t * func_size,int32_t * func_start_address,unsigned char * func_info,uint8_t * rep_block_size)1211 sframe_decoder_get_funcdesc_v2 (sframe_decoder_ctx *dctx,
1212 				unsigned int i,
1213 				uint32_t *num_fres,
1214 				uint32_t *func_size,
1215 				int32_t *func_start_address,
1216 				unsigned char *func_info,
1217 				uint8_t *rep_block_size)
1218 {
1219   sframe_func_desc_entry *fdp;
1220   int err = 0;
1221 
1222   if (dctx == NULL || func_start_address == NULL
1223       || num_fres == NULL || func_size == NULL
1224       || sframe_decoder_get_version (dctx) == SFRAME_VERSION_1)
1225     return sframe_set_errno (&err, SFRAME_ERR_INVAL);
1226 
1227   fdp = sframe_decoder_get_funcdesc_at_index (dctx, i);
1228 
1229   if (fdp == NULL)
1230     return sframe_set_errno (&err, SFRAME_ERR_FDE_NOTFOUND);
1231 
1232   *num_fres = fdp->sfde_func_num_fres;
1233   *func_start_address = fdp->sfde_func_start_address;
1234   *func_size = fdp->sfde_func_size;
1235   *func_info = fdp->sfde_func_info;
1236   *rep_block_size = fdp->sfde_func_rep_size;
1237 
1238   return 0;
1239 }
1240 /* Get the FRE_IDX'th FRE of the function at FUNC_IDX'th function
1241    descriptor entry in the SFrame decoder CTX.  Returns error code as
1242    applicable.  */
1243 
1244 int
sframe_decoder_get_fre(sframe_decoder_ctx * ctx,unsigned int func_idx,unsigned int fre_idx,sframe_frame_row_entry * fre)1245 sframe_decoder_get_fre (sframe_decoder_ctx *ctx,
1246 			unsigned int func_idx,
1247 			unsigned int fre_idx,
1248 			sframe_frame_row_entry *fre)
1249 {
1250   sframe_func_desc_entry *fdep;
1251   sframe_frame_row_entry ifre;
1252   const char *fres;
1253   uint32_t i;
1254   uint32_t fre_type;
1255   size_t esz = 0;
1256   int err = 0;
1257 
1258   if (ctx == NULL || fre == NULL)
1259     return sframe_set_errno (&err, SFRAME_ERR_INVAL);
1260 
1261   /* Get function descriptor entry at index func_idx.  */
1262   fdep = sframe_decoder_get_funcdesc_at_index (ctx, func_idx);
1263 
1264   if (fdep == NULL)
1265     return sframe_set_errno (&err, SFRAME_ERR_FDE_NOTFOUND);
1266 
1267   fre_type = sframe_get_fre_type (fdep);
1268   /* Now scan the FRE entries.  */
1269   fres = ctx->sfd_fres + fdep->sfde_func_start_fre_off;
1270   for (i = 0; i < fdep->sfde_func_num_fres; i++)
1271    {
1272      /* Decode the FRE at the current position.  Return it if valid.  */
1273      err = sframe_decode_fre (fres, &ifre, fre_type, &esz);
1274      if (i == fre_idx)
1275        {
1276 	 if (!sframe_fre_sanity_check_p (&ifre))
1277 	   return sframe_set_errno (&err, SFRAME_ERR_FRE_INVAL);
1278 
1279 	 sframe_frame_row_entry_copy (fre, &ifre);
1280 
1281 	 if (fdep->sfde_func_size)
1282 	   sframe_assert (fre->fre_start_addr < fdep->sfde_func_size);
1283 	 else
1284 	   /* A SFrame FDE with func size equal to zero is possible.  */
1285 	   sframe_assert (fre->fre_start_addr == fdep->sfde_func_size);
1286 
1287 	 return 0;
1288        }
1289      /* Next FRE.  */
1290      fres += esz;
1291    }
1292 
1293   return sframe_set_errno (&err, SFRAME_ERR_FDE_NOTFOUND);
1294 }
1295 
1296 
1297 /* SFrame Encoder.  */
1298 
1299 /* Get a reference to the ENCODER's SFrame header.  */
1300 
1301 static sframe_header *
sframe_encoder_get_header(sframe_encoder_ctx * encoder)1302 sframe_encoder_get_header (sframe_encoder_ctx *encoder)
1303 {
1304   sframe_header *hp = NULL;
1305   if (encoder)
1306     hp = &encoder->sfe_header;
1307   return hp;
1308 }
1309 
1310 static sframe_func_desc_entry *
sframe_encoder_get_funcdesc_at_index(sframe_encoder_ctx * encoder,uint32_t func_idx)1311 sframe_encoder_get_funcdesc_at_index (sframe_encoder_ctx *encoder,
1312 				      uint32_t func_idx)
1313 {
1314   sframe_func_desc_entry *fde = NULL;
1315   if (func_idx < sframe_encoder_get_num_fidx (encoder))
1316     {
1317       sf_fde_tbl *func_tbl = encoder->sfe_funcdesc;
1318       fde = func_tbl->entry + func_idx;
1319     }
1320   return fde;
1321 }
1322 
1323 /* Create an encoder context with the given SFrame format version VER, FLAGS
1324    and ABI information.  Uses the ABI specific FIXED_FP_OFFSET and
1325    FIXED_RA_OFFSET values as provided.  Sets errp if failure.  */
1326 
1327 sframe_encoder_ctx *
sframe_encode(uint8_t ver,uint8_t flags,uint8_t abi_arch,int8_t fixed_fp_offset,int8_t fixed_ra_offset,int * errp)1328 sframe_encode (uint8_t ver, uint8_t flags, uint8_t abi_arch,
1329 	       int8_t fixed_fp_offset, int8_t fixed_ra_offset, int *errp)
1330 {
1331   sframe_header *hp;
1332   sframe_encoder_ctx *encoder;
1333 
1334   if (ver != SFRAME_VERSION)
1335     return sframe_ret_set_errno (errp, SFRAME_ERR_VERSION_INVAL);
1336 
1337   if ((encoder = malloc (sizeof (sframe_encoder_ctx))) == NULL)
1338     return sframe_ret_set_errno (errp, SFRAME_ERR_NOMEM);
1339 
1340   memset (encoder, 0, sizeof (sframe_encoder_ctx));
1341 
1342   /* Get the SFrame header and update it.  */
1343   hp = sframe_encoder_get_header (encoder);
1344   hp->sfh_preamble.sfp_version = ver;
1345   hp->sfh_preamble.sfp_magic = SFRAME_MAGIC;
1346   hp->sfh_preamble.sfp_flags = flags;
1347 
1348   hp->sfh_abi_arch = abi_arch;
1349   hp->sfh_cfa_fixed_fp_offset = fixed_fp_offset;
1350   hp->sfh_cfa_fixed_ra_offset = fixed_ra_offset;
1351 
1352   return encoder;
1353 }
1354 
1355 /* Free the encoder context.  */
1356 
1357 void
sframe_encoder_free(sframe_encoder_ctx ** encoder)1358 sframe_encoder_free (sframe_encoder_ctx **encoder)
1359 {
1360   if (encoder != NULL)
1361     {
1362       sframe_encoder_ctx *ectx = *encoder;
1363       if (ectx == NULL)
1364 	return;
1365 
1366       if (ectx->sfe_funcdesc != NULL)
1367 	{
1368 	  free (ectx->sfe_funcdesc);
1369 	  ectx->sfe_funcdesc = NULL;
1370 	}
1371       if (ectx->sfe_fres != NULL)
1372 	{
1373 	  free (ectx->sfe_fres);
1374 	  ectx->sfe_fres = NULL;
1375 	}
1376       if (ectx->sfe_data != NULL)
1377 	{
1378 	  free (ectx->sfe_data);
1379 	  ectx->sfe_data = NULL;
1380 	}
1381 
1382       free (*encoder);
1383       *encoder = NULL;
1384     }
1385 }
1386 
1387 /* Get the size of the SFrame header from the encoder ctx ENCODER.  */
1388 
1389 unsigned int
sframe_encoder_get_hdr_size(sframe_encoder_ctx * encoder)1390 sframe_encoder_get_hdr_size (sframe_encoder_ctx *encoder)
1391 {
1392   sframe_header *ehp;
1393   ehp = sframe_encoder_get_header (encoder);
1394   return sframe_get_hdr_size (ehp);
1395 }
1396 
1397 /* Get the abi/arch info from the SFrame encoder context ENCODER.  */
1398 
1399 uint8_t
sframe_encoder_get_abi_arch(sframe_encoder_ctx * encoder)1400 sframe_encoder_get_abi_arch (sframe_encoder_ctx *encoder)
1401 {
1402   uint8_t abi_arch = 0;
1403   sframe_header *ehp;
1404   ehp = sframe_encoder_get_header (encoder);
1405   if (ehp)
1406     abi_arch = ehp->sfh_abi_arch;
1407   return abi_arch;
1408 }
1409 
1410 /* Get the format version from the SFrame encoder context ENCODER.  */
1411 
1412 uint8_t
sframe_encoder_get_version(sframe_encoder_ctx * encoder)1413 sframe_encoder_get_version (sframe_encoder_ctx *encoder)
1414 {
1415   sframe_header *ehp;
1416   ehp = sframe_encoder_get_header (encoder);
1417   return ehp->sfh_preamble.sfp_version;
1418 }
1419 
1420 /* Return the number of function descriptor entries in the SFrame encoder
1421    ENCODER.  */
1422 
1423 uint32_t
sframe_encoder_get_num_fidx(sframe_encoder_ctx * encoder)1424 sframe_encoder_get_num_fidx (sframe_encoder_ctx *encoder)
1425 {
1426   uint32_t num_fdes = 0;
1427   sframe_header *ehp = NULL;
1428   ehp = sframe_encoder_get_header (encoder);
1429   if (ehp)
1430     num_fdes = ehp->sfh_num_fdes;
1431   return num_fdes;
1432 }
1433 
1434 /* Add an FRE to function at FUNC_IDX'th function descriptor entry in
1435    the encoder context.  */
1436 
1437 int
sframe_encoder_add_fre(sframe_encoder_ctx * encoder,unsigned int func_idx,sframe_frame_row_entry * frep)1438 sframe_encoder_add_fre (sframe_encoder_ctx *encoder,
1439 			unsigned int func_idx,
1440 			sframe_frame_row_entry *frep)
1441 {
1442   sframe_header *ehp;
1443   sframe_func_desc_entry *fdep;
1444   sframe_frame_row_entry *ectx_frep;
1445   size_t offsets_sz, esz;
1446   uint32_t fre_type;
1447   size_t fre_tbl_sz;
1448   int err = 0;
1449 
1450   if (encoder == NULL || frep == NULL)
1451     return sframe_set_errno (&err, SFRAME_ERR_INVAL);
1452   if (!sframe_fre_sanity_check_p (frep))
1453     return sframe_set_errno (&err, SFRAME_ERR_FRE_INVAL);
1454 
1455   /* Use func_idx to gather the function descriptor entry.  */
1456   fdep = sframe_encoder_get_funcdesc_at_index (encoder, func_idx);
1457 
1458   if (fdep == NULL)
1459     return sframe_set_errno (&err, SFRAME_ERR_FDE_NOTFOUND);
1460 
1461   fre_type = sframe_get_fre_type (fdep);
1462   sf_fre_tbl *fre_tbl = encoder->sfe_fres;
1463 
1464   if (fre_tbl == NULL)
1465     {
1466       fre_tbl_sz = (sizeof (sf_fre_tbl)
1467 		    + (number_of_entries * sizeof (sframe_frame_row_entry)));
1468       fre_tbl = malloc (fre_tbl_sz);
1469 
1470       if (fre_tbl == NULL)
1471 	{
1472 	  sframe_set_errno (&err, SFRAME_ERR_NOMEM);
1473 	  goto bad;		/* OOM.  */
1474 	}
1475       memset (fre_tbl, 0, fre_tbl_sz);
1476       fre_tbl->alloced = number_of_entries;
1477     }
1478   else if (fre_tbl->count == fre_tbl->alloced)
1479     {
1480       fre_tbl_sz = (sizeof (sf_fre_tbl)
1481 		    + ((fre_tbl->alloced + number_of_entries)
1482 		       * sizeof (sframe_frame_row_entry)));
1483       fre_tbl = realloc (fre_tbl, fre_tbl_sz);
1484       if (fre_tbl == NULL)
1485 	{
1486 	  sframe_set_errno (&err, SFRAME_ERR_NOMEM);
1487 	  goto bad;		/* OOM.  */
1488 	}
1489 
1490       memset (&fre_tbl->entry[fre_tbl->alloced], 0,
1491 	      number_of_entries * sizeof (sframe_frame_row_entry));
1492       fre_tbl->alloced += number_of_entries;
1493     }
1494 
1495   ectx_frep = &fre_tbl->entry[fre_tbl->count];
1496   ectx_frep->fre_start_addr
1497     = frep->fre_start_addr;
1498   ectx_frep->fre_info = frep->fre_info;
1499 
1500   if (fdep->sfde_func_size)
1501     sframe_assert (frep->fre_start_addr < fdep->sfde_func_size);
1502   else
1503     /* A SFrame FDE with func size equal to zero is possible.  */
1504     sframe_assert (frep->fre_start_addr == fdep->sfde_func_size);
1505 
1506   /* frep has already been sanity check'd.  Get offsets size.  */
1507   offsets_sz = sframe_fre_offset_bytes_size (frep->fre_info);
1508   memcpy (&ectx_frep->fre_offsets, &frep->fre_offsets, offsets_sz);
1509 
1510   esz = sframe_fre_entry_size (frep, fre_type);
1511   fre_tbl->count++;
1512 
1513   encoder->sfe_fres = fre_tbl;
1514   encoder->sfe_fre_nbytes += esz;
1515 
1516   ehp = sframe_encoder_get_header (encoder);
1517   ehp->sfh_num_fres = fre_tbl->count;
1518 
1519   /* Update the value of the number of FREs for the function.  */
1520   fdep->sfde_func_num_fres++;
1521 
1522   return 0;
1523 
1524 bad:
1525   if (fre_tbl != NULL)
1526     free (fre_tbl);
1527   encoder->sfe_fres = NULL;
1528   encoder->sfe_fre_nbytes = 0;
1529   return -1;
1530 }
1531 
1532 /* Add a new function descriptor entry with START_ADDR, FUNC_SIZE and NUM_FRES
1533    to the encoder.  */
1534 
1535 int
sframe_encoder_add_funcdesc(sframe_encoder_ctx * encoder,int32_t start_addr,uint32_t func_size,unsigned char func_info,uint32_t num_fres)1536 sframe_encoder_add_funcdesc (sframe_encoder_ctx *encoder,
1537 			     int32_t start_addr,
1538 			     uint32_t func_size,
1539 			     unsigned char func_info,
1540 			     uint32_t num_fres __attribute__ ((unused)))
1541 {
1542   sframe_header *ehp;
1543   sf_fde_tbl *fd_info;
1544   size_t fd_tbl_sz;
1545   int err = 0;
1546 
1547   /* FIXME book-keep num_fres for error checking.  */
1548   if (encoder == NULL)
1549     return sframe_set_errno (&err, SFRAME_ERR_INVAL);
1550 
1551   fd_info = encoder->sfe_funcdesc;
1552   ehp = sframe_encoder_get_header (encoder);
1553 
1554   if (fd_info == NULL)
1555     {
1556       fd_tbl_sz = (sizeof (sf_fde_tbl)
1557 		   + (number_of_entries * sizeof (sframe_func_desc_entry)));
1558       fd_info = malloc (fd_tbl_sz);
1559       if (fd_info == NULL)
1560 	{
1561 	  sframe_set_errno (&err, SFRAME_ERR_NOMEM);
1562 	  goto bad;		/* OOM.  */
1563 	}
1564       memset (fd_info, 0, fd_tbl_sz);
1565       fd_info->alloced = number_of_entries;
1566     }
1567   else if (fd_info->count == fd_info->alloced)
1568     {
1569       fd_tbl_sz = (sizeof (sf_fde_tbl)
1570 		   + ((fd_info->alloced + number_of_entries)
1571 		      * sizeof (sframe_func_desc_entry)));
1572       fd_info = realloc (fd_info, fd_tbl_sz);
1573       if (fd_info == NULL)
1574 	{
1575 	  sframe_set_errno (&err, SFRAME_ERR_NOMEM);
1576 	  goto bad;		/* OOM.  */
1577 	}
1578 
1579       memset (&fd_info->entry[fd_info->alloced], 0,
1580 	      number_of_entries * sizeof (sframe_func_desc_entry));
1581       fd_info->alloced += number_of_entries;
1582     }
1583 
1584   fd_info->entry[fd_info->count].sfde_func_start_address = start_addr;
1585   /* Num FREs is updated as FREs are added for the function later via
1586      sframe_encoder_add_fre.  */
1587   fd_info->entry[fd_info->count].sfde_func_size = func_size;
1588   fd_info->entry[fd_info->count].sfde_func_start_fre_off
1589     = encoder->sfe_fre_nbytes;
1590 #if 0
1591   // Linker optimization test code cleanup later ibhagat TODO FIXME
1592   uint32_t fre_type = sframe_calc_fre_type (func_size);
1593 
1594   fd_info->entry[fd_info->count].sfde_func_info
1595     = sframe_fde_func_info (fre_type);
1596 #endif
1597   fd_info->entry[fd_info->count].sfde_func_info = func_info;
1598   fd_info->count++;
1599   encoder->sfe_funcdesc = fd_info;
1600   ehp->sfh_num_fdes++;
1601   return 0;
1602 
1603 bad:
1604   if (fd_info != NULL)
1605     free (fd_info);
1606   encoder->sfe_funcdesc = NULL;
1607   ehp->sfh_num_fdes = 0;
1608   return -1;
1609 }
1610 
1611 /* Add a new function descriptor entry with START_ADDR, FUNC_SIZE, FUNC_INFO
1612    and REP_BLOCK_SIZE to the encoder.
1613 
1614    This API is valid only for SFrame format version 2.  */
1615 
1616 int
sframe_encoder_add_funcdesc_v2(sframe_encoder_ctx * encoder,int32_t start_addr,uint32_t func_size,unsigned char func_info,uint8_t rep_block_size,uint32_t num_fres)1617 sframe_encoder_add_funcdesc_v2 (sframe_encoder_ctx *encoder,
1618 				int32_t start_addr,
1619 				uint32_t func_size,
1620 				unsigned char func_info,
1621 				uint8_t rep_block_size,
1622 				uint32_t num_fres __attribute__ ((unused)))
1623 {
1624   sf_fde_tbl *fd_info;
1625   int err;
1626 
1627   if (encoder == NULL
1628       || sframe_encoder_get_version (encoder) == SFRAME_VERSION_1)
1629     return sframe_set_errno (&err, SFRAME_ERR_INVAL);
1630 
1631   err = sframe_encoder_add_funcdesc (encoder, start_addr, func_size, func_info,
1632 				     num_fres);
1633   if (err)
1634     return SFRAME_ERR;
1635 
1636   fd_info = encoder->sfe_funcdesc;
1637   fd_info->entry[fd_info->count-1].sfde_func_rep_size = rep_block_size;
1638 
1639   return 0;
1640 }
1641 
1642 static int
sframe_sort_funcdesc(sframe_encoder_ctx * encoder)1643 sframe_sort_funcdesc (sframe_encoder_ctx *encoder)
1644 {
1645   sframe_header *ehp;
1646 
1647   ehp = sframe_encoder_get_header (encoder);
1648   /* Sort and write out the FDE table.  */
1649   sf_fde_tbl *fd_info = encoder->sfe_funcdesc;
1650   if (fd_info)
1651     {
1652       qsort (fd_info->entry, fd_info->count,
1653 	     sizeof (sframe_func_desc_entry), fde_func);
1654       /* Update preamble's flags.  */
1655       ehp->sfh_preamble.sfp_flags |= SFRAME_F_FDE_SORTED;
1656     }
1657   return 0;
1658 }
1659 
1660 /* Write the SFrame FRE start address from the in-memory FRE_START_ADDR
1661    to the buffer CONTENTS (on-disk format), given the FRE_TYPE and
1662    FRE_START_ADDR_SZ.  */
1663 
1664 static int
sframe_encoder_write_fre_start_addr(char * contents,uint32_t fre_start_addr,uint32_t fre_type,size_t fre_start_addr_sz)1665 sframe_encoder_write_fre_start_addr (char *contents,
1666 				     uint32_t fre_start_addr,
1667 				     uint32_t fre_type,
1668 				     size_t fre_start_addr_sz)
1669 {
1670   int err = 0;
1671 
1672   if (fre_type == SFRAME_FRE_TYPE_ADDR1)
1673     {
1674       uint8_t uc = fre_start_addr;
1675       memcpy (contents, &uc, fre_start_addr_sz);
1676     }
1677   else if (fre_type == SFRAME_FRE_TYPE_ADDR2)
1678     {
1679       uint16_t ust = fre_start_addr;
1680       memcpy (contents, &ust, fre_start_addr_sz);
1681     }
1682   else if (fre_type == SFRAME_FRE_TYPE_ADDR4)
1683     {
1684       uint32_t uit = fre_start_addr;
1685       memcpy (contents, &uit, fre_start_addr_sz);
1686     }
1687   else
1688     return sframe_set_errno (&err, SFRAME_ERR_INVAL);
1689 
1690   return 0;
1691 }
1692 
1693 /* Write a frame row entry pointed to by FREP into the buffer CONTENTS.  The
1694    size in bytes written out are updated in ESZ.
1695 
1696    This function works closely with the SFrame binary format.
1697 
1698    Returns SFRAME_ERR if failure.  */
1699 
1700 static int
sframe_encoder_write_fre(char * contents,sframe_frame_row_entry * frep,uint32_t fre_type,size_t * esz)1701 sframe_encoder_write_fre (char *contents, sframe_frame_row_entry *frep,
1702 			  uint32_t fre_type, size_t *esz)
1703 {
1704   size_t fre_sz;
1705   size_t fre_start_addr_sz;
1706   size_t fre_stack_offsets_sz;
1707   int err = 0;
1708 
1709   if (!sframe_fre_sanity_check_p (frep))
1710     return sframe_set_errno (&err, SFRAME_ERR_FRE_INVAL);
1711 
1712   fre_start_addr_sz = sframe_fre_start_addr_size (fre_type);
1713   fre_stack_offsets_sz = sframe_fre_offset_bytes_size (frep->fre_info);
1714 
1715   /* The FRE start address must be encodable in the available number of
1716      bytes.  */
1717   uint64_t bitmask = SFRAME_BITMASK_OF_SIZE (fre_start_addr_sz);
1718   sframe_assert ((uint64_t)frep->fre_start_addr <= bitmask);
1719 
1720   sframe_encoder_write_fre_start_addr (contents, frep->fre_start_addr,
1721 				       fre_type, fre_start_addr_sz);
1722   contents += fre_start_addr_sz;
1723 
1724   memcpy (contents, &frep->fre_info, sizeof (frep->fre_info));
1725   contents += sizeof (frep->fre_info);
1726 
1727   memcpy (contents, frep->fre_offsets, fre_stack_offsets_sz);
1728   contents+= fre_stack_offsets_sz;
1729 
1730   fre_sz = sframe_fre_entry_size (frep, fre_type);
1731   /* Sanity checking.  */
1732   sframe_assert ((fre_start_addr_sz
1733 		  + sizeof (frep->fre_info)
1734 		  + fre_stack_offsets_sz) == fre_sz);
1735 
1736   *esz = fre_sz;
1737 
1738   return 0;
1739 }
1740 
1741 /* Serialize the core contents of the SFrame section and write out to the
1742    output buffer held in the ENCODER.  Return SFRAME_ERR if failure.  */
1743 
1744 static int
sframe_encoder_write_sframe(sframe_encoder_ctx * encoder)1745 sframe_encoder_write_sframe (sframe_encoder_ctx *encoder)
1746 {
1747   char *contents;
1748   size_t buf_size;
1749   size_t hdr_size;
1750   size_t all_fdes_size;
1751   size_t fre_size;
1752   size_t esz = 0;
1753   sframe_header *ehp;
1754   unsigned char flags;
1755   sf_fde_tbl *fd_info;
1756   sf_fre_tbl *fr_info;
1757   uint32_t i, num_fdes;
1758   uint32_t j, num_fres;
1759   sframe_func_desc_entry *fdep;
1760   sframe_frame_row_entry *frep;
1761 
1762   uint32_t fre_type;
1763   int err = 0;
1764 
1765   contents = encoder->sfe_data;
1766   buf_size = encoder->sfe_data_size;
1767   num_fdes = sframe_encoder_get_num_fidx (encoder);
1768   all_fdes_size = num_fdes * sizeof (sframe_func_desc_entry);
1769   ehp = sframe_encoder_get_header (encoder);
1770   hdr_size = sframe_get_hdr_size (ehp);
1771 
1772   fd_info = encoder->sfe_funcdesc;
1773   fr_info = encoder->sfe_fres;
1774 
1775   /* Sanity checks:
1776      - buffers must be malloc'd by the caller.  */
1777   if ((contents == NULL) || (buf_size < hdr_size))
1778     return sframe_set_errno (&err, SFRAME_ERR_BUF_INVAL);
1779   if (fr_info == NULL)
1780     return sframe_set_errno (&err, SFRAME_ERR_FRE_INVAL);
1781 
1782   /* Write out the FRE table first.
1783 
1784      Recall that read/write of FREs needs information from the corresponding
1785      FDE; the latter stores the information about the FRE type record used for
1786      the function.  Also note that sorting of FDEs does NOT impact the order
1787      in which FREs are stored in the SFrame's FRE sub-section.  This means
1788      that writing out FREs after sorting of FDEs will need some additional
1789      book-keeping.  At this time, we can afford to avoid it by writing out
1790      the FREs first to the output buffer.  */
1791   fre_size = 0;
1792   uint32_t global = 0;
1793   uint32_t fre_index = 0;
1794 
1795   contents += hdr_size + all_fdes_size;
1796   for (i = 0; i < num_fdes; i++)
1797     {
1798       fdep = &fd_info->entry[i];
1799       fre_type = sframe_get_fre_type (fdep);
1800       num_fres = fdep->sfde_func_num_fres;
1801 
1802       for (j = 0; j < num_fres; j++)
1803 	{
1804 	  fre_index = global + j;
1805 	  frep = &fr_info->entry[fre_index];
1806 
1807 	  sframe_encoder_write_fre (contents, frep, fre_type, &esz);
1808 	  contents += esz;
1809 	  fre_size += esz; /* For debugging only.  */
1810 	}
1811       global += j;
1812     }
1813 
1814   sframe_assert (fre_size == ehp->sfh_fre_len);
1815   sframe_assert (global == ehp->sfh_num_fres);
1816   sframe_assert ((size_t)(contents - encoder->sfe_data) == buf_size);
1817 
1818   /* Sort the FDE table */
1819   sframe_sort_funcdesc (encoder);
1820 
1821   /* Sanity checks:
1822      - the FDE section must have been sorted by now on the start address
1823      of each function.  */
1824   flags = ehp->sfh_preamble.sfp_flags;
1825   if (!(flags & SFRAME_F_FDE_SORTED)
1826       || (fd_info == NULL))
1827     return sframe_set_errno (&err, SFRAME_ERR_FDE_INVAL);
1828 
1829   contents = encoder->sfe_data;
1830   /* Write out the SFrame header.  The SFrame header in the encoder
1831      object has already been updated with correct offsets by the caller.  */
1832   memcpy (contents, ehp, hdr_size);
1833   contents += hdr_size;
1834 
1835   /* Write out the FDE table sorted on funtion start address.  */
1836   memcpy (contents, fd_info->entry, all_fdes_size);
1837   contents += all_fdes_size;
1838 
1839   return 0;
1840 }
1841 
1842 /* Serialize the contents of the encoder and return the buffer.  ENCODED_SIZE
1843    is updated to the size of the buffer.  */
1844 
1845 char *
sframe_encoder_write(sframe_encoder_ctx * encoder,size_t * encoded_size,int * errp)1846 sframe_encoder_write (sframe_encoder_ctx *encoder,
1847 		      size_t *encoded_size, int *errp)
1848 {
1849   sframe_header *ehp;
1850   size_t hdrsize, fsz, fresz, bufsize;
1851   int foreign_endian;
1852 
1853   /* Initialize the encoded_size to zero.  This makes it simpler to just
1854      return from the function in case of failure.  Free'ing up of
1855      encoder->sfe_data is the responsibility of the caller.  */
1856   *encoded_size = 0;
1857 
1858   if (encoder == NULL || encoded_size == NULL || errp == NULL)
1859     return sframe_ret_set_errno (errp, SFRAME_ERR_INVAL);
1860 
1861   ehp = sframe_encoder_get_header (encoder);
1862   hdrsize = sframe_get_hdr_size (ehp);
1863   fsz = sframe_encoder_get_num_fidx (encoder)
1864     * sizeof (sframe_func_desc_entry);
1865   fresz = encoder->sfe_fre_nbytes;
1866 
1867   /* The total size of buffer is the sum of header, SFrame Function Descriptor
1868      Entries section and the FRE section.  */
1869   bufsize = hdrsize + fsz + fresz;
1870   encoder->sfe_data = (char *) malloc (bufsize);
1871   if (encoder->sfe_data == NULL)
1872     return sframe_ret_set_errno (errp, SFRAME_ERR_NOMEM);
1873   encoder->sfe_data_size = bufsize;
1874 
1875   /* Update the information in the SFrame header.  */
1876   /* SFrame FDE section follows immediately after the header.  */
1877   ehp->sfh_fdeoff = 0;
1878   /* SFrame FRE section follows immediately after the SFrame FDE section.  */
1879   ehp->sfh_freoff = fsz;
1880   ehp->sfh_fre_len = fresz;
1881 
1882   foreign_endian = need_swapping (ehp->sfh_abi_arch);
1883 
1884   /* Write out the FDE Index and the FRE table in the sfe_data. */
1885   if (sframe_encoder_write_sframe (encoder))
1886     return sframe_ret_set_errno (errp, SFRAME_ERR_BUF_INVAL);
1887 
1888   /* Endian flip the contents if necessary.  */
1889   if (foreign_endian)
1890     {
1891       if (flip_sframe (encoder->sfe_data, bufsize, 1))
1892 	return sframe_ret_set_errno (errp, SFRAME_ERR_BUF_INVAL);
1893       flip_header ((sframe_header*)encoder->sfe_data);
1894     }
1895 
1896   *encoded_size = bufsize;
1897   return encoder->sfe_data;
1898 }
1899