Coverage Report

Created: 2025-06-24 06:45

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