Coverage Report

Created: 2023-08-28 06:30

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