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