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
28typedef 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
35typedef 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
45static void debug_printf (const char *, ...);
46
47static int _sframe_debug;	/* Control for printing out debug info.  */
48static int number_of_entries = 64;
49
50static void
51sframe_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)
63static 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
86static int
87sframe_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
97static void *
98sframe_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
107static uint32_t
108sframe_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
115static unsigned int
116sframe_fre_get_offset_count (unsigned char fre_info)
117{
118  return SFRAME_V1_FRE_OFFSET_COUNT (fre_info);
119}
120
121static unsigned int
122sframe_fre_get_offset_size (unsigned char fre_info)
123{
124  return SFRAME_V1_FRE_OFFSET_SIZE (fre_info);
125}
126
127static bool
128sframe_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
135static unsigned int
136sframe_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
144static unsigned int
145sframe_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
155static int
156need_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
178static void
179flip_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
193static void
194flip_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
204static int
205sframe_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
223static void
224flip_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
239static void
240flip_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
262static size_t
263sframe_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
287static int
288sframe_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
313static size_t
314sframe_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
334static size_t
335sframe_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
347static int
348flip_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
391static int
392flip_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;
462bad:
463  return SFRAME_ERR;
464}
465
466/* The SFrame Decoder.  */
467
468/* Get DECODER's SFrame header.  */
469
470static sframe_header *
471sframe_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
481static int
482fde_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
496static int32_t
497sframe_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
532void
533sframe_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
560unsigned char
561sframe_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
577unsigned int
578sframe_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
592unsigned int
593sframe_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
604int32_t
605sframe_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
613int32_t
614sframe_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
635int32_t
636sframe_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
651bool
652sframe_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
661static int
662sframe_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
678static int
679sframe_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
724static int
725sframe_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
769sframe_decoder_ctx *
770sframe_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
874decode_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
884unsigned int
885sframe_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
894unsigned char
895sframe_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.  */
903int8_t
904sframe_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.  */
912int8_t
913sframe_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
923sframe_func_desc_entry *
924sframe_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
973int
974sframe_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
1054unsigned int
1055sframe_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
1071int
1072sframe_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
1105static sframe_func_desc_entry *
1106sframe_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
1122int
1123sframe_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
1179static sframe_header *
1180sframe_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
1188static sframe_func_desc_entry *
1189sframe_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
1204sframe_encoder_ctx *
1205sframe_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
1234void
1235sframe_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
1266unsigned int
1267sframe_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
1276unsigned char
1277sframe_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
1290unsigned int
1291sframe_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
1304int
1305sframe_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
1391bad:
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
1402int
1403sframe_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
1470bad:
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
1478static int
1479sframe_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
1503static int
1504sframe_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
1552static int
1553sframe_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
1653char *
1654sframe_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