Coverage Report

Created: 2025-07-08 11:15

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