Coverage Report

Created: 2023-06-29 07:03

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