Coverage Report

Created: 2026-03-10 08:46

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/binutils-gdb/libsframe/sframe.c
Line
Count
Source
1
/* sframe.c - SFrame decoder/encoder.
2
3
   Copyright (C) 2022-2026 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
/* Representation of SFrame FDE internal to libsframe.  */
30
typedef struct sframe_func_desc_entry_int
31
{
32
  int64_t func_start_pc_offset;
33
  uint32_t func_size;
34
  uint32_t func_start_fre_off;
35
  uint32_t func_num_fres;
36
  uint8_t func_info;
37
  uint8_t func_info2;
38
  uint8_t func_rep_size;
39
} sframe_func_desc_entry_int;
40
41
struct sf_fde_tbl
42
{
43
  unsigned int count;
44
  unsigned int alloced;
45
  sframe_func_desc_entry_int entry[1];
46
};
47
48
struct sf_fre_tbl
49
{
50
  unsigned int count;
51
  unsigned int alloced;
52
  sframe_frame_row_entry entry[1];
53
};
54
55
#define _sf_printflike_(string_index,first_to_check) \
56
    __attribute__ ((__format__ (__printf__, (string_index), (first_to_check))))
57
58
static void debug_printf (const char *, ...);
59
60
static int _sframe_debug; /* Control for printing out debug info.  */
61
62
0
#define SFRAME_FRE_ALLOC_LEN  64
63
static int number_of_entries = 64;
64
65
static void
66
sframe_init_debug (void)
67
0
{
68
0
  static int inited;
69
70
0
  if (!inited)
71
0
    {
72
0
      _sframe_debug = getenv ("SFRAME_DEBUG") != NULL;
73
0
      inited = 1;
74
0
    }
75
0
}
76
77
_sf_printflike_ (1, 2)
78
static void debug_printf (const char *format, ...)
79
0
{
80
0
  if (_sframe_debug)
81
0
    {
82
0
      va_list args;
83
84
0
      va_start (args, format);
85
0
      vfprintf (stderr, format, args);
86
0
      va_end (args);
87
0
    }
88
0
}
89
90
/* Generate bitmask of given size in bytes.  This is used for
91
   some checks on the FRE start address.
92
   SFRAME_FRE_TYPE_ADDR1 => 1 byte => [ bitmask = 0xff ]
93
   SFRAME_FRE_TYPE_ADDR2 => 2 byte => [ bitmask = 0xffff ]
94
   SFRAME_FRE_TYPE_ADDR4 => 4 byte => [ bitmask = 0xffffffff ].  */
95
#define SFRAME_BITMASK_OF_SIZE(size_in_bytes) \
96
0
  (((uint64_t)1 << (size_in_bytes*8)) - 1)
97
98
/* Store the specified error code into errp if it is non-NULL.
99
   Return SFRAME_ERR.  */
100
101
static int
102
sframe_set_errno (int *errp, int error)
103
0
{
104
0
  if (errp != NULL)
105
0
    *errp = error;
106
0
  return SFRAME_ERR;
107
0
}
108
109
/* Store the specified error code into errp if it is non-NULL.
110
   Return NULL.  */
111
112
static void *
113
sframe_ret_set_errno (int *errp, int error)
114
0
{
115
0
  if (errp != NULL)
116
0
    *errp = error;
117
0
  return NULL;
118
0
}
119
120
/* Allocate space for NUM_FDES number of SFrame FDEs of type
121
   sframe_func_desc_entry_int.  This is version-unaware because this pertains
122
   to libsframe's internal in-memory representation of SFrame FDE.  */
123
124
static int
125
sframe_fde_tbl_alloc (sf_fde_tbl **fde_tbl, unsigned int num_fdes)
126
0
{
127
0
  size_t fidx_size = num_fdes * sizeof (sframe_func_desc_entry_int);
128
0
  size_t fd_tbl_sz = (sizeof (sf_fde_tbl) + fidx_size);
129
130
0
  *fde_tbl = malloc (fd_tbl_sz);
131
0
  if (*fde_tbl == NULL)
132
0
    return SFRAME_ERR;
133
134
0
  (*fde_tbl)->alloced = num_fdes;
135
136
0
  return 0;
137
0
}
138
139
/* Initialize libsframe's internal representation of SFrame FDEs.  */
140
141
static int
142
sframe_fde_tbl_init (sf_fde_tbl *fde_tbl, const char *fde_buf,
143
         const char *fre_buf, size_t *fidx_size,
144
         unsigned int num_fdes, uint8_t ver)
145
0
{
146
0
  if (ver == SFRAME_VERSION_3 && SFRAME_VERSION == SFRAME_VERSION_3)
147
0
    {
148
0
      *fidx_size = num_fdes * sizeof (sframe_func_desc_idx_v3);
149
0
      for (unsigned int i = 0; i < num_fdes; i++)
150
0
  {
151
0
    const sframe_func_desc_idx_v3 *fdep
152
0
      = (sframe_func_desc_idx_v3 *)fde_buf + i;
153
0
    fde_tbl->entry[i].func_start_pc_offset = fdep->sfdi_func_start_offset;
154
0
    fde_tbl->entry[i].func_size = fdep->sfdi_func_size;
155
0
    fde_tbl->entry[i].func_start_fre_off = fdep->sfdi_func_start_fre_off;
156
    /* V3 organizes the following data closer to the SFrame FREs for the
157
       function.  Access them via the sfde_func_start_fre_off.  */
158
0
    const sframe_func_desc_attr_v3 *fattr
159
0
      = (sframe_func_desc_attr_v3 *)(fre_buf
160
0
             + fdep->sfdi_func_start_fre_off);
161
0
    fde_tbl->entry[i].func_num_fres = fattr->sfda_func_num_fres;
162
0
    fde_tbl->entry[i].func_info = fattr->sfda_func_info;
163
0
    fde_tbl->entry[i].func_info2 = fattr->sfda_func_info2;
164
0
    fde_tbl->entry[i].func_rep_size = fattr->sfda_func_rep_size;
165
0
  }
166
0
      fde_tbl->count = num_fdes;
167
0
    }
168
  /* If ver is not the latest, read buffer manually and upgrade from
169
     sframe_func_desc_entry_v2 to populate the sf_fde_tbl entries.  */
170
0
  else if (ver == SFRAME_VERSION_2 && SFRAME_VERSION == SFRAME_VERSION_3)
171
0
    {
172
0
      *fidx_size = num_fdes * sizeof (sframe_func_desc_entry_v2);
173
0
      for (unsigned int i = 0; i < num_fdes; i++)
174
0
  {
175
0
    const sframe_func_desc_entry_v2 *fdep
176
0
      = (sframe_func_desc_entry_v2 *)fde_buf + i;
177
0
    fde_tbl->entry[i].func_start_pc_offset
178
0
      = fdep->sfde_func_start_address;
179
0
    fde_tbl->entry[i].func_size = fdep->sfde_func_size;
180
0
    fde_tbl->entry[i].func_start_fre_off = fdep->sfde_func_start_fre_off;
181
0
    fde_tbl->entry[i].func_num_fres = fdep->sfde_func_num_fres;
182
0
    fde_tbl->entry[i].func_info = fdep->sfde_func_info;
183
0
    fde_tbl->entry[i].func_info2 = 0;
184
0
    fde_tbl->entry[i].func_rep_size = fdep->sfde_func_rep_size;
185
0
  }
186
0
      fde_tbl->count = num_fdes;
187
0
    }
188
0
  else
189
0
    {
190
      /* Not possible ATM.  */
191
0
      *fidx_size = 0;
192
0
      return SFRAME_ERR;
193
0
    }
194
195
0
  return 0;
196
0
}
197
198
/* Get the SFrame header size.  */
199
200
static uint32_t
201
sframe_get_hdr_size (const sframe_header *sfh)
202
0
{
203
0
  return SFRAME_V1_HDR_SIZE (*sfh);
204
0
}
205
206
/* Access functions for frame row entry data.  */
207
208
static uint8_t
209
sframe_fre_get_dataword_count (uint8_t fre_info)
210
0
{
211
0
  return SFRAME_V1_FRE_OFFSET_COUNT (fre_info);
212
0
}
213
214
static uint8_t
215
sframe_fre_get_dataword_size (uint8_t fre_info)
216
0
{
217
0
  return SFRAME_V1_FRE_OFFSET_SIZE (fre_info);
218
0
}
219
220
static bool
221
sframe_get_fre_ra_mangled_p (uint8_t fre_info)
222
0
{
223
0
  return SFRAME_V1_FRE_MANGLED_RA_P (fre_info);
224
0
}
225
226
static bool
227
sframe_get_fre_ra_undefined_p (uint8_t fre_info)
228
0
{
229
0
  return SFRAME_V2_FRE_RA_UNDEFINED_P (fre_info);
230
0
}
231
232
/* Access functions for info from function descriptor entry.  */
233
234
static uint32_t
235
sframe_get_fre_type (sframe_func_desc_entry_int *fdep)
236
0
{
237
0
  uint32_t fre_type = 0;
238
0
  if (fdep)
239
0
    fre_type = SFRAME_V2_FUNC_FRE_TYPE (fdep->func_info);
240
0
  return fre_type;
241
0
}
242
243
static uint32_t
244
sframe_get_fde_pc_type (sframe_func_desc_entry_int *fdep)
245
0
{
246
0
  uint32_t fde_pc_type = 0;
247
0
  if (fdep)
248
0
    fde_pc_type = SFRAME_V2_FUNC_PC_TYPE (fdep->func_info);
249
0
  return fde_pc_type;
250
0
}
251
252
/* Check if flipping is needed, based on ENDIAN.  */
253
254
static int
255
need_swapping (int endian)
256
0
{
257
0
  unsigned int ui = 1;
258
0
  char *c = (char *)&ui;
259
0
  int is_little = (int)*c;
260
261
0
  switch (endian)
262
0
    {
263
0
      case SFRAME_ABI_AARCH64_ENDIAN_LITTLE:
264
0
      case SFRAME_ABI_AMD64_ENDIAN_LITTLE:
265
0
  return !is_little;
266
0
      case SFRAME_ABI_AARCH64_ENDIAN_BIG:
267
0
      case SFRAME_ABI_S390X_ENDIAN_BIG:
268
0
  return is_little;
269
0
      default:
270
0
  break;
271
0
    }
272
273
0
  return 0;
274
0
}
275
276
/* Flip the endianness of the SFrame header starting at BUF.
277
   VER is the version of the SFrame data in the buffer.
278
279
   Returns SFRAME_ERR if any error.  If error code is returned, the flipped
280
   header should not be used.  */
281
282
static int
283
flip_header (char *buf, uint8_t ver ATTRIBUTE_UNUSED)
284
0
{
285
  /* SFrame header binary format has remained the same in SFRAME_VERSION_1,
286
     SFRAME_VERSION_2.  */
287
0
  sframe_header *sfh = (sframe_header *) buf;
288
0
  swap_thing (sfh->sfh_preamble.sfp_magic);
289
0
  swap_thing (sfh->sfh_preamble.sfp_version);
290
0
  swap_thing (sfh->sfh_preamble.sfp_flags);
291
0
  swap_thing (sfh->sfh_abi_arch);
292
0
  swap_thing (sfh->sfh_cfa_fixed_fp_offset);
293
0
  swap_thing (sfh->sfh_cfa_fixed_ra_offset);
294
0
  swap_thing (sfh->sfh_auxhdr_len);
295
0
  swap_thing (sfh->sfh_num_fdes);
296
0
  swap_thing (sfh->sfh_num_fres);
297
0
  swap_thing (sfh->sfh_fre_len);
298
0
  swap_thing (sfh->sfh_fdeoff);
299
0
  swap_thing (sfh->sfh_freoff);
300
301
  /* Alert for missing functionatlity.  Auxiliary header, if present, needs to
302
     flipped based on per abi/arch semantics.  */
303
0
  if (sfh->sfh_auxhdr_len)
304
0
    return SFRAME_ERR;
305
306
0
  return 0;
307
0
}
308
309
/* Endian flip the SFrame FDE at BUF (buffer size provided in BUF_SIZE), given
310
   the SFrame version VER.  Update the FDE_SIZE to the size of the SFrame FDE
311
   flipped.
312
313
   Return SFRAME_ERR if any error.  If error code is returned, the flipped FDEP
314
   should not be used.  */
315
316
static int
317
flip_fde_desc (char *buf, size_t buf_size, uint8_t ver)
318
0
{
319
0
  if (ver == SFRAME_VERSION_3)
320
0
    {
321
0
      if (buf_size < sizeof (sframe_func_desc_idx_v3))
322
0
  return SFRAME_ERR;
323
324
0
      sframe_func_desc_idx_v3 *fdep = (sframe_func_desc_idx_v3 *) buf;
325
0
      swap_thing (fdep->sfdi_func_start_offset);
326
0
      swap_thing (fdep->sfdi_func_size);
327
0
      swap_thing (fdep->sfdi_func_start_fre_off);
328
0
    }
329
0
  else if (ver == SFRAME_VERSION_2)
330
0
    {
331
0
      if (buf_size < sizeof (sframe_func_desc_entry_v2))
332
0
  return SFRAME_ERR;
333
334
0
      sframe_func_desc_entry_v2 *fdep = (sframe_func_desc_entry_v2 *) buf;
335
0
      swap_thing (fdep->sfde_func_start_address);
336
0
      swap_thing (fdep->sfde_func_size);
337
0
      swap_thing (fdep->sfde_func_start_fre_off);
338
0
      swap_thing (fdep->sfde_func_num_fres);
339
0
    }
340
0
  else
341
0
    return SFRAME_ERR;
342
343
0
  return 0;
344
0
}
345
346
static int
347
flip_fde_attr_v3 (char *buf, size_t buf_size)
348
0
{
349
0
  if (buf_size < sizeof (sframe_func_desc_attr_v3))
350
0
    return SFRAME_ERR;
351
352
  /* sfda_func_num_fres is the first member of sframe_func_desc_attr_v3.  */
353
0
  struct { uint16_t x; } ATTRIBUTE_PACKED *p = (void*)buf;
354
0
  swap_thing (p->x);
355
356
0
  return 0;
357
0
}
358
/* Check if SFrame header has valid data.  */
359
360
static bool
361
sframe_header_sanity_check_p (const sframe_header *hp)
362
0
{
363
  /* Check preamble is valid.  */
364
0
  if (hp->sfh_preamble.sfp_magic != SFRAME_MAGIC
365
0
      || (hp->sfh_preamble.sfp_version != SFRAME_VERSION_1
366
0
    && hp->sfh_preamble.sfp_version != SFRAME_VERSION_2
367
0
    && hp->sfh_preamble.sfp_version != SFRAME_VERSION_3))
368
0
    return false;
369
370
  /* Check flags (version-aware).
371
     Do not validate V3 headers against V2 flag definitions, as V3 may
372
     introduce new flags.  */
373
0
  uint8_t valid_flags = SFRAME_V2_F_ALL_FLAGS;
374
0
  if (hp->sfh_preamble.sfp_version == SFRAME_VERSION_3)
375
    /* Replace with SFRAME_V3_F_ALL_FLAGS.  */
376
0
    valid_flags = SFRAME_V3_F_ALL_FLAGS;
377
0
  if (hp->sfh_preamble.sfp_flags & ~valid_flags)
378
0
    return false;
379
380
  /* Check offsets are valid.  */
381
0
  if (hp->sfh_fdeoff > hp->sfh_freoff)
382
0
    return false;
383
384
0
  return true;
385
0
}
386
387
/* Flip the start address pointed to by FP.  */
388
389
static void
390
flip_fre_start_address (void *addr, uint32_t fre_type)
391
0
{
392
0
  if (fre_type == SFRAME_FRE_TYPE_ADDR2)
393
0
    {
394
0
      struct { uint16_t x; } ATTRIBUTE_PACKED *p = addr;
395
0
      swap_thing (p->x);
396
0
    }
397
0
  else if (fre_type == SFRAME_FRE_TYPE_ADDR4)
398
0
    {
399
0
      struct { uint32_t x; } ATTRIBUTE_PACKED *p = addr;
400
0
      swap_thing (p->x);
401
0
    }
402
0
}
403
404
static void
405
flip_fre_datawords (void *datawords, uint8_t dataword_size,
406
        uint8_t dataword_cnt)
407
0
{
408
0
  int j;
409
410
0
  if (dataword_size == SFRAME_FRE_DATAWORD_2B)
411
0
    {
412
0
      struct { uint16_t x; } ATTRIBUTE_PACKED *p = datawords;
413
0
      for (j = dataword_cnt; j > 0; p++, j--)
414
0
  swap_thing (p->x);
415
0
    }
416
0
  else if (dataword_size == SFRAME_FRE_DATAWORD_4B)
417
0
    {
418
0
      struct { uint32_t x; } ATTRIBUTE_PACKED *p = datawords;
419
0
      for (j = dataword_cnt; j > 0; p++, j--)
420
0
  swap_thing (p->x);
421
0
    }
422
0
}
423
424
/* Get the FRE start address size, given the FRE_TYPE.  */
425
426
static size_t
427
sframe_fre_start_addr_size (uint32_t fre_type)
428
0
{
429
0
  size_t addr_size = 0;
430
0
  switch (fre_type)
431
0
    {
432
0
    case SFRAME_FRE_TYPE_ADDR1:
433
0
      addr_size = 1;
434
0
      break;
435
0
    case SFRAME_FRE_TYPE_ADDR2:
436
0
      addr_size = 2;
437
0
      break;
438
0
    case SFRAME_FRE_TYPE_ADDR4:
439
0
      addr_size = 4;
440
0
      break;
441
0
    default:
442
      /* No other value is expected.  */
443
0
      sframe_assert (0);
444
0
      break;
445
0
    }
446
0
  return addr_size;
447
0
}
448
449
/* Check if the FREP has valid data.  */
450
451
static bool
452
sframe_fre_sanity_check_p (const sframe_frame_row_entry *frep)
453
0
{
454
0
  uint8_t dataword_size, dataword_cnt;
455
0
  uint8_t fre_info;
456
457
0
  if (frep == NULL)
458
0
    return false;
459
460
0
  fre_info = frep->fre_info;
461
0
  dataword_size = sframe_fre_get_dataword_size (fre_info);
462
463
0
  if (dataword_size != SFRAME_FRE_DATAWORD_1B
464
0
      && dataword_size != SFRAME_FRE_DATAWORD_2B
465
0
      && dataword_size != SFRAME_FRE_DATAWORD_4B)
466
0
    return false;
467
468
0
  dataword_cnt = sframe_fre_get_dataword_count (fre_info);
469
0
  if (dataword_cnt > MAX_NUM_DATAWORDS)
470
0
    return false;
471
472
0
  return true;
473
0
}
474
475
/* Get FRE_INFO's data words' size in bytes.  */
476
477
static size_t
478
sframe_fre_datawords_bytes_size (uint8_t fre_info)
479
0
{
480
0
  uint8_t dataword_size, dataword_cnt;
481
482
0
  dataword_size = sframe_fre_get_dataword_size (fre_info);
483
484
0
  debug_printf ("dataword_size =  %u\n", dataword_size);
485
486
0
  dataword_cnt = sframe_fre_get_dataword_count (fre_info);
487
488
0
  if (dataword_size == SFRAME_FRE_DATAWORD_2B
489
0
      || dataword_size == SFRAME_FRE_DATAWORD_4B) /* 2 or 4 bytes.  */
490
0
    return (dataword_cnt * (dataword_size * 2));
491
492
0
  return dataword_cnt;
493
0
}
494
495
/* Get total size in bytes to represent FREP in the binary format.  This
496
   includes the starting address, FRE info, and all the offsets.  */
497
498
static size_t
499
sframe_fre_entry_size (sframe_frame_row_entry *frep, uint32_t fre_type)
500
0
{
501
0
  if (frep == NULL)
502
0
    return 0;
503
504
0
  uint8_t fre_info = frep->fre_info;
505
0
  size_t addr_size = sframe_fre_start_addr_size (fre_type);
506
507
0
  return (addr_size + sizeof (frep->fre_info)
508
0
    + sframe_fre_datawords_bytes_size (fre_info));
509
0
}
510
511
/* Get total size in bytes in the SFrame FRE at FRE_BUF location, given the
512
   type of FRE as FRE_TYPE.  */
513
514
static size_t
515
sframe_buf_fre_entry_size (const char *fre_buf, uint32_t fre_type)
516
0
{
517
0
  if (fre_buf == NULL)
518
0
    return 0;
519
520
0
  size_t addr_size = sframe_fre_start_addr_size (fre_type);
521
0
  uint8_t fre_info = *(uint8_t *)(fre_buf + addr_size);
522
523
0
  return (addr_size + sizeof (fre_info)
524
0
    + sframe_fre_datawords_bytes_size (fre_info));
525
0
}
526
/* Get the function descriptor entry at index FUNC_IDX in the decoder
527
   context CTX.  */
528
529
static sframe_func_desc_entry_int *
530
sframe_decoder_get_funcdesc_at_index (const sframe_decoder_ctx *ctx,
531
              uint32_t func_idx)
532
0
{
533
0
  sframe_func_desc_entry_int *fdep;
534
0
  uint32_t num_fdes;
535
0
  int err;
536
537
0
  num_fdes = sframe_decoder_get_num_fidx (ctx);
538
0
  if (num_fdes == 0
539
0
      || func_idx >= num_fdes
540
0
      || ctx->sfd_funcdesc == NULL
541
0
      || ctx->sfd_funcdesc->count <= func_idx)
542
0
    return sframe_ret_set_errno (&err, SFRAME_ERR_DCTX_INVAL);
543
544
0
  fdep = &ctx->sfd_funcdesc->entry[func_idx];
545
0
  return fdep;
546
0
}
547
548
/* Get the offset of the start PC of the SFrame FDE at FUNC_IDX from the start
549
   of the SFrame section.  This section-relative offset is used within
550
   libsframe for sorting the SFrame FDEs, and also information lookup routines
551
   like sframe_find_fre.
552
553
   If FUNC_IDX is not a valid index in the given decoder object, returns 0.  */
554
555
static int64_t
556
sframe_decoder_get_secrel_func_start_addr (const sframe_decoder_ctx *dctx,
557
             uint32_t func_idx)
558
0
{
559
0
  int err = 0;
560
0
  int32_t offsetof_fde_in_sec
561
0
    = sframe_decoder_get_offsetof_fde_start_addr (dctx, func_idx, &err);
562
  /* If func_idx is not a valid index, return 0.  */
563
0
  if (err)
564
0
    return 0;
565
566
0
  const sframe_func_desc_entry_int *fdep = &dctx->sfd_funcdesc->entry[func_idx];
567
0
  int64_t func_start_pc_offset = fdep->func_start_pc_offset;
568
569
0
  return func_start_pc_offset + offsetof_fde_in_sec;
570
0
}
571
572
/* Check whether for the given FDEP, the SFrame Frame Row Entry identified via
573
   the START_IP_OFFSET and the END_IP_OFFSET, provides the stack trace
574
   information for the PC.  */
575
576
static bool
577
sframe_fre_check_range_p (const sframe_decoder_ctx *dctx, uint32_t func_idx,
578
        uint32_t start_ip_offset, uint32_t end_ip_offset,
579
        int64_t pc)
580
0
{
581
0
  sframe_func_desc_entry_int *fdep;
582
0
  int64_t func_start_pc_offset;
583
0
  uint8_t rep_block_size;
584
0
  uint32_t pc_type;
585
0
  uint32_t pc_offset;
586
0
  bool mask_p;
587
588
0
  fdep = &dctx->sfd_funcdesc->entry[func_idx];
589
0
  func_start_pc_offset = sframe_decoder_get_secrel_func_start_addr (dctx,
590
0
                    func_idx);
591
0
  pc_type = sframe_get_fde_pc_type (fdep);
592
0
  mask_p = (pc_type == SFRAME_V3_FDE_PCTYPE_MASK);
593
0
  rep_block_size = fdep->func_rep_size;
594
595
0
  if (func_start_pc_offset > pc)
596
0
    return false;
597
598
  /* Given func_start_addr <= pc, pc - func_start_addr must be positive.  */
599
0
  pc_offset = pc - func_start_pc_offset;
600
  /* For SFrame FDEs encoding information for repetitive pattern of insns,
601
     masking with the rep_block_size is necessary to find the matching FRE.  */
602
0
  if (mask_p)
603
0
    pc_offset = pc_offset % rep_block_size;
604
605
0
  return (start_ip_offset <= pc_offset) && (end_ip_offset >= pc_offset);
606
0
}
607
608
/* Read the on-disk SFrame FDE from location BUF of size in bytes equal to
609
   BUF_SIZE.
610
611
   Return SFRAME_ERR if any error.  If error code is returned, the read values
612
   should not be used.  */
613
614
static int
615
sframe_decode_fde_desc_v2 (const char *buf, size_t buf_size,
616
         uint32_t *num_fres, uint32_t *fre_type,
617
         uint32_t *fre_offset)
618
0
{
619
0
  if (buf_size < sizeof (sframe_func_desc_entry_v2))
620
0
    return SFRAME_ERR;
621
622
0
  sframe_func_desc_entry_v2 *fdep = (sframe_func_desc_entry_v2 *) buf;
623
0
  *num_fres = fdep->sfde_func_num_fres;
624
0
  *fre_type = SFRAME_V2_FUNC_FRE_TYPE (fdep->sfde_func_info);
625
0
  *fre_offset = fdep->sfde_func_start_fre_off;
626
627
0
  return 0;
628
0
}
629
630
/* Read the on-disk SFrame FDE from location BUF of size in bytes equal to
631
   BUF_SIZE.
632
633
   Return SFRAME_ERR if any error.  If error code is returned, the read values
634
   should not be used.  */
635
636
static int
637
sframe_decode_fde_idx_v3 (const char *buf, size_t buf_size,
638
        uint32_t *fre_offset)
639
0
{
640
0
  if (buf_size < sizeof (sframe_func_desc_idx_v3))
641
0
    return SFRAME_ERR;
642
643
0
  sframe_func_desc_idx_v3 *fdep = (sframe_func_desc_idx_v3 *) buf;
644
0
  *fre_offset = fdep->sfdi_func_start_fre_off;
645
646
0
  return 0;
647
0
}
648
649
static int
650
sframe_decode_fde_attr_v3 (const char *buf, size_t buf_size,
651
         uint16_t *num_fres, uint32_t *fre_type)
652
0
{
653
0
  if (buf_size < sizeof (sframe_func_desc_attr_v3))
654
0
    return SFRAME_ERR;
655
656
0
  const sframe_func_desc_attr_v3 *fdap = (sframe_func_desc_attr_v3 *) buf;
657
0
  *num_fres = fdap->sfda_func_num_fres;
658
0
  *fre_type = SFRAME_V3_FDE_FRE_TYPE (fdap->sfda_func_info);
659
0
  return 0;
660
0
}
661
662
static int
663
flip_fre (char *fp, size_t fp_size, uint32_t fre_type, size_t *fre_size)
664
0
{
665
0
  uint8_t fre_info;
666
0
  uint8_t dataword_size, dataword_cnt;
667
0
  size_t addr_size, fre_info_size, datawords_bytes_size;
668
0
  int err = 0;
669
670
0
  if (fre_size == NULL)
671
0
    return sframe_set_errno (&err, SFRAME_ERR_INVAL);
672
673
0
  addr_size = sframe_fre_start_addr_size (fre_type);
674
0
  if (addr_size > fp_size)
675
0
    return SFRAME_ERR;
676
0
  flip_fre_start_address (fp, fre_type);
677
678
  /* Advance the buffer pointer to where the FRE info is.  */
679
0
  fp += addr_size;
680
0
  fp_size -= addr_size;
681
682
  /* FRE info is uint8_t.  No need to flip.  */
683
0
  fre_info_size = sizeof (uint8_t);
684
0
  if (fre_info_size > fp_size)
685
0
    return SFRAME_ERR;
686
0
  fre_info = *(uint8_t*)fp;
687
0
  dataword_size = sframe_fre_get_dataword_size (fre_info);
688
0
  dataword_cnt = sframe_fre_get_dataword_count (fre_info);
689
690
  /* Advance the buffer pointer to where the stack offsets are.  */
691
0
  fp += fre_info_size;
692
0
  fp_size -= fre_info_size;
693
0
  datawords_bytes_size = sframe_fre_datawords_bytes_size (fre_info);
694
0
  if (datawords_bytes_size > fp_size)
695
0
    return SFRAME_ERR;
696
0
  flip_fre_datawords (fp, dataword_size, dataword_cnt);
697
698
0
  *fre_size = addr_size + fre_info_size + datawords_bytes_size;
699
700
0
  return 0;
701
0
}
702
703
/* Endian flip the contents of FRAME_BUF of size BUF_SIZE.
704
   The SFrame header in the FRAME_BUF must be endian flipped prior to
705
   calling flip_sframe.
706
707
   Endian flipping at decode time vs encode time have different needs.  At
708
   encode time, the frame_buf is in host endianness, and hence, values should
709
   be read up before the buffer is changed to foreign endianness.  This change
710
   of behaviour is specified via TO_FOREIGN arg.
711
712
   If an error code is returned, the buffer should not be used.  */
713
714
static int
715
flip_sframe_fdes_with_fres_v2 (char *frame_buf, size_t buf_size,
716
             uint32_t to_foreign)
717
0
{
718
0
  char *fp = NULL;
719
0
  uint32_t num_fres = 0;
720
0
  uint32_t fre_type = 0;
721
0
  uint32_t fre_offset = 0;
722
0
  size_t esz = 0;
723
0
  int err = 0;
724
  /* For error checking.  */
725
0
  size_t fde_bytes_flipped = 0;
726
0
  size_t fre_bytes_flipped = 0;
727
728
  /* Header must be in host endianness at this time.  */
729
0
  const sframe_header *ihp = (sframe_header *)frame_buf;
730
731
0
  if (!sframe_header_sanity_check_p (ihp))
732
0
    return sframe_set_errno (&err, SFRAME_ERR_BUF_INVAL);
733
734
  /* The contents of the SFrame header are safe to read.  Get the number of
735
     FDEs and the first FDE in the buffer.  */
736
0
  size_t hdrsz = sframe_get_hdr_size (ihp);
737
0
  uint32_t num_fdes = ihp->sfh_num_fdes;
738
0
  uint8_t ver = ihp->sfh_preamble.sfp_version;
739
0
  char *fdes = frame_buf + hdrsz + ihp->sfh_fdeoff;
740
0
  char *fres = frame_buf + hdrsz + ihp->sfh_freoff;
741
0
  const char *buf_end = frame_buf + buf_size;
742
743
0
  unsigned int i = 0, j = 0;
744
0
  unsigned int prev_frep_index = 0;
745
0
  size_t fsz = sizeof (sframe_func_desc_entry_v2);
746
0
  for (i = 0; i < num_fdes; fdes += fsz, i++)
747
0
    {
748
0
      if (fdes >= buf_end)
749
0
  goto bad;
750
751
      /* Handle FDE.  */
752
0
      if (to_foreign && sframe_decode_fde_desc_v2 (fdes, buf_end - fdes,
753
0
               &num_fres, &fre_type,
754
0
               &fre_offset))
755
0
  goto bad;
756
757
0
      if (flip_fde_desc (fdes, buf_end - fdes, ver))
758
0
  goto bad;
759
760
0
      if (!to_foreign && sframe_decode_fde_desc_v2 (fdes, buf_end - fdes,
761
0
                &num_fres, &fre_type,
762
0
                &fre_offset))
763
0
  goto bad;
764
765
0
      fde_bytes_flipped += fsz;
766
767
      /* Handle FREs.  */
768
0
      fp = fres + fre_offset;
769
0
      for (; j < prev_frep_index + num_fres; j++)
770
0
  {
771
0
    if (flip_fre (fp, buf_end - fp, fre_type, &esz))
772
0
      goto bad;
773
0
    fre_bytes_flipped += esz;
774
0
    fp += esz;
775
0
  }
776
0
      prev_frep_index = j;
777
0
    }
778
779
  /* All FDEs must have been endian flipped by now.  */
780
0
  if (i != num_fdes || fde_bytes_flipped > ihp->sfh_freoff - ihp->sfh_fdeoff)
781
0
    goto bad;
782
783
  /* All FREs must have been endian flipped by now.  */
784
0
  if (j != ihp->sfh_num_fres || fre_bytes_flipped > ihp->sfh_fre_len)
785
0
    goto bad;
786
787
  /* Optional trailing section padding.  */
788
0
  size_t frame_size = hdrsz + ihp->sfh_freoff + fre_bytes_flipped;
789
0
  for (fp = frame_buf + frame_size; fp < frame_buf + buf_size; fp++)
790
0
    if (*fp != '\0')
791
0
      goto bad;
792
793
  /* Done.  */
794
0
  return 0;
795
0
bad:
796
0
  return SFRAME_ERR;
797
0
}
798
799
/* Endian flip the contents of FRAME_BUF of size BUF_SIZE.
800
   The SFrame header in the FRAME_BUF must be endian flipped prior to
801
   calling flip_sframe_fdes_with_fres_v3.
802
803
   Endian flipping at decode time vs encode time have different needs.  At
804
   encode time, the frame_buf is in host endianness, and hence, values should
805
   be read up before the buffer is changed to foreign endianness.  This change
806
   of behaviour is specified via TO_FOREIGN arg.
807
808
   If an error code is returned, the buffer should not be used.  */
809
810
static int
811
flip_sframe_fdes_with_fres_v3 (char *frame_buf, size_t buf_size,
812
             uint32_t to_foreign)
813
0
{
814
0
  char *fp = NULL;
815
0
  uint16_t num_fres = 0;
816
0
  uint32_t fre_type = 0;
817
0
  uint32_t fre_offset = 0;
818
0
  size_t esz = 0;
819
0
  int err = 0;
820
  /* For error checking.  */
821
0
  size_t fde_bytes_flipped = 0;
822
0
  size_t fre_bytes_flipped = 0;
823
824
  /* Header must be in host endianness at this time.  */
825
0
  const sframe_header *ihp = (sframe_header *)frame_buf;
826
827
0
  if (!sframe_header_sanity_check_p (ihp))
828
0
    return sframe_set_errno (&err, SFRAME_ERR_BUF_INVAL);
829
830
  /* The contents of the SFrame header are safe to read.  Get the number of
831
     FDEs and the first FDE in the buffer.  */
832
0
  size_t hdrsz = sframe_get_hdr_size (ihp);
833
0
  uint32_t num_fdes = ihp->sfh_num_fdes;
834
0
  uint8_t ver = ihp->sfh_preamble.sfp_version;
835
0
  char *fdes = frame_buf + hdrsz + ihp->sfh_fdeoff;
836
0
  char *fres = frame_buf + hdrsz + ihp->sfh_freoff;
837
0
  const char *buf_end = frame_buf + buf_size;
838
839
0
  unsigned int i = 0, j = 0;
840
0
  unsigned int prev_frep_index = 0;
841
0
  size_t fsz = sizeof (sframe_func_desc_idx_v3);
842
0
  for (i = 0; i < num_fdes; fdes += fsz, i++)
843
0
    {
844
0
      if (fdes >= buf_end)
845
0
  goto bad;
846
847
      /* Handle FDE.  */
848
0
      if (to_foreign && sframe_decode_fde_idx_v3 (fdes, buf_end - fdes,
849
0
              &fre_offset))
850
0
  goto bad;
851
852
0
      if (flip_fde_desc (fdes, buf_end - fdes, ver))
853
0
  goto bad;
854
855
0
      if (!to_foreign && sframe_decode_fde_idx_v3 (fdes, buf_end - fdes,
856
0
               &fre_offset))
857
0
  goto bad;
858
859
0
      fde_bytes_flipped += fsz;
860
861
      /* Handle FDE attr (only in V3).  */
862
0
      fp = fres + fre_offset;
863
0
      if (to_foreign && sframe_decode_fde_attr_v3 (fp, buf_end - fp,
864
0
               &num_fres, &fre_type))
865
0
  goto bad;
866
867
0
      if (flip_fde_attr_v3 (fp, buf_end - fp))
868
0
  goto bad;
869
870
0
      fre_bytes_flipped += sizeof (sframe_func_desc_attr_v3);
871
872
0
      if (!to_foreign && sframe_decode_fde_attr_v3 (fp, buf_end - fp,
873
0
                &num_fres, &fre_type))
874
0
  goto bad;
875
876
      /* Handle FREs.  */
877
0
      fp += sizeof (sframe_func_desc_attr_v3);
878
0
      for (; j < prev_frep_index + num_fres; j++)
879
0
  {
880
0
    if (flip_fre (fp, buf_end - fp, fre_type, &esz))
881
0
      goto bad;
882
0
    fre_bytes_flipped += esz;
883
0
    fp += esz;
884
0
  }
885
0
      prev_frep_index = j;
886
0
    }
887
888
  /* All FDEs must have been endian flipped by now.  */
889
0
  if (i != num_fdes || fde_bytes_flipped > ihp->sfh_freoff - ihp->sfh_fdeoff)
890
0
    goto bad;
891
892
  /* All FREs must have been endian flipped by now.  */
893
0
  if (j != ihp->sfh_num_fres || fre_bytes_flipped > ihp->sfh_fre_len)
894
0
    goto bad;
895
896
  /* Optional trailing section padding.  */
897
0
  size_t frame_size = hdrsz + ihp->sfh_freoff + fre_bytes_flipped;
898
0
  for (fp = frame_buf + frame_size; fp < frame_buf + buf_size; fp++)
899
0
    if (*fp != '\0')
900
0
      goto bad;
901
902
  /* Done.  */
903
0
  return 0;
904
0
bad:
905
0
  return SFRAME_ERR;
906
0
}
907
908
static int
909
flip_sframe (char *frame_buf, size_t buf_size, uint32_t to_foreign)
910
0
{
911
0
  int err = 0;
912
913
  /* Header must be in host endianness at this time.  */
914
0
  const sframe_header *ihp = (sframe_header *)frame_buf;
915
0
  if (!sframe_header_sanity_check_p (ihp))
916
0
    return sframe_set_errno (&err, SFRAME_ERR_BUF_INVAL);
917
0
  uint8_t ver = ihp->sfh_preamble.sfp_version;
918
919
0
  if (ver == SFRAME_VERSION_3)
920
0
    err = flip_sframe_fdes_with_fres_v3 (frame_buf, buf_size, to_foreign);
921
0
  else if (ver == SFRAME_VERSION_2)
922
0
    err = flip_sframe_fdes_with_fres_v2 (frame_buf, buf_size, to_foreign);
923
0
  else
924
0
    return sframe_set_errno (&err, SFRAME_ERR_BUF_INVAL);
925
926
0
  if (err)
927
0
    return sframe_set_errno (&err, SFRAME_ERR_BUF_INVAL);
928
929
  /* Success.  */
930
0
  return 0;
931
0
}
932
933
/* Expands the memory allocated for the SFrame Frame Row Entry (FRE) table
934
   FRE_TBL.  This function is called when the current FRE buffer is
935
   insufficient and more stack trace data in the form of COUNT number of SFrame
936
   FREs need to be added to the SFrame section.
937
938
   Updates ERRP with 0 on success, or an SFrame error code on failure (e.g.,
939
   memory allocation error).  */
940
941
static sf_fre_tbl *
942
sframe_grow_fre_tbl (sf_fre_tbl *fre_tbl, uint32_t count, int *errp)
943
0
{
944
0
  size_t fre_tbl_sz = 0;
945
  /* Ensure buffer for at least COUNT number of elements.  */
946
0
  uint32_t grow_count = SFRAME_FRE_ALLOC_LEN + count;
947
0
  sf_fre_tbl *new_tbl = NULL;
948
949
0
  if (fre_tbl == NULL)
950
0
    {
951
0
      fre_tbl_sz = (sizeof (sf_fre_tbl)
952
0
        + (grow_count * sizeof (sframe_frame_row_entry)));
953
0
      new_tbl = malloc (fre_tbl_sz);
954
0
      if (new_tbl == NULL)
955
0
  {
956
0
    sframe_set_errno (errp, SFRAME_ERR_NOMEM);
957
0
    goto bad;
958
0
  }
959
960
0
      memset (new_tbl, 0, fre_tbl_sz);
961
0
      new_tbl->alloced = grow_count;
962
0
    }
963
0
  else if (fre_tbl->count + count >= fre_tbl->alloced)
964
0
    {
965
0
      uint32_t new_len = fre_tbl->alloced + grow_count;
966
0
      fre_tbl_sz = (sizeof (sf_fre_tbl)
967
0
        + (new_len * sizeof (sframe_frame_row_entry)));
968
0
      void *tmp = realloc (fre_tbl, fre_tbl_sz);
969
0
      if (tmp == NULL)
970
0
  {
971
0
    sframe_set_errno (errp, SFRAME_ERR_NOMEM);
972
0
    goto bad;
973
0
  }
974
0
      new_tbl = tmp;
975
976
0
      memset (&new_tbl->entry[new_tbl->alloced], 0,
977
0
        grow_count * sizeof (sframe_frame_row_entry));
978
0
      new_tbl->alloced += grow_count;
979
0
    }
980
981
0
bad:
982
0
  return new_tbl;
983
0
}
984
985
/* The SFrame Decoder.  */
986
987
/* Get SFrame header from the given decoder context DCTX.  */
988
989
static const sframe_header *
990
sframe_decoder_get_header (const sframe_decoder_ctx *dctx)
991
0
{
992
0
  const sframe_header *hp = NULL;
993
0
  if (dctx != NULL)
994
0
    hp = &dctx->sfd_header;
995
0
  return hp;
996
0
}
997
998
/* Compare function for qsort'ing the FDE table.  */
999
1000
static int
1001
fde_func (const void *p1, const void *p2)
1002
0
{
1003
0
  const sframe_func_desc_entry_int *aa = p1;
1004
0
  const sframe_func_desc_entry_int *bb = p2;
1005
1006
0
  if (aa->func_start_pc_offset < bb->func_start_pc_offset)
1007
0
    return -1;
1008
0
  else if (aa->func_start_pc_offset > bb->func_start_pc_offset)
1009
0
    return 1;
1010
0
  return 0;
1011
0
}
1012
1013
/* Get IDX'th offset from FRE.  Set errp as applicable.  */
1014
1015
static int32_t
1016
sframe_get_fre_offset (const sframe_frame_row_entry *fre, int idx, int *errp)
1017
0
{
1018
0
  uint8_t dataword_cnt, dataword_size;
1019
1020
0
  if (fre == NULL || !sframe_fre_sanity_check_p (fre))
1021
0
    return sframe_set_errno (errp, SFRAME_ERR_FRE_INVAL);
1022
1023
0
  dataword_cnt = sframe_fre_get_dataword_count (fre->fre_info);
1024
0
  dataword_size = sframe_fre_get_dataword_size (fre->fre_info);
1025
1026
0
  if (dataword_cnt < idx + 1)
1027
0
    return sframe_set_errno (errp, SFRAME_ERR_FREOFFSET_NOPRESENT);
1028
1029
0
  if (errp)
1030
0
    *errp = 0; /* Offset Valid.  */
1031
1032
0
  if (dataword_size == SFRAME_FRE_DATAWORD_1B)
1033
0
    {
1034
0
      int8_t *offsets = (int8_t *)fre->fre_datawords;
1035
0
      return offsets[idx];
1036
0
    }
1037
0
  else if (dataword_size == SFRAME_FRE_DATAWORD_2B)
1038
0
    {
1039
0
      int16_t *offsets = (int16_t *)fre->fre_datawords;
1040
0
      return offsets[idx];
1041
0
    }
1042
0
  else
1043
0
    {
1044
0
      int32_t *offsets = (int32_t *)fre->fre_datawords;
1045
0
      return offsets[idx];
1046
0
    }
1047
0
}
1048
1049
/* Get IDX'th data word as unsigned data from FRE.  Set errp as applicable.  */
1050
1051
uint32_t
1052
sframe_get_fre_udata (const sframe_frame_row_entry *fre, int idx, int *errp)
1053
0
{
1054
0
  uint8_t dataword_cnt, dataword_size;
1055
1056
0
  if (fre == NULL || !sframe_fre_sanity_check_p (fre))
1057
0
    return sframe_set_errno (errp, SFRAME_ERR_FRE_INVAL);
1058
1059
0
  dataword_cnt = sframe_fre_get_dataword_count (fre->fre_info);
1060
0
  dataword_size = sframe_fre_get_dataword_size (fre->fre_info);
1061
1062
0
  if (dataword_cnt < idx + 1)
1063
0
    return sframe_set_errno (errp, SFRAME_ERR_FREOFFSET_NOPRESENT);
1064
1065
0
  if (errp)
1066
0
    *errp = 0; /* Offset Valid.  */
1067
1068
0
  if (dataword_size == SFRAME_FRE_DATAWORD_1B)
1069
0
    {
1070
0
      uint8_t *datawords = (uint8_t *)fre->fre_datawords;
1071
0
      return datawords[idx];
1072
0
    }
1073
0
  else if (dataword_size == SFRAME_FRE_DATAWORD_2B)
1074
0
    {
1075
0
      uint16_t *datawords = (uint16_t *)fre->fre_datawords;
1076
0
      return datawords[idx];
1077
0
    }
1078
0
  else
1079
0
    {
1080
0
      uint32_t *datawords = (uint32_t *)fre->fre_datawords;
1081
0
      return datawords[idx];
1082
0
    }
1083
0
}
1084
1085
/* Free the decoder context.  */
1086
1087
void
1088
sframe_decoder_free (sframe_decoder_ctx **dctxp)
1089
0
{
1090
0
  if (dctxp != NULL)
1091
0
    {
1092
0
      sframe_decoder_ctx *dctx = *dctxp;
1093
0
      if (dctx == NULL)
1094
0
  return;
1095
1096
0
      if (dctx->sfd_funcdesc != NULL)
1097
0
  {
1098
0
    free (dctx->sfd_funcdesc);
1099
0
    dctx->sfd_funcdesc = NULL;
1100
0
  }
1101
0
      if (dctx->sfd_fres != NULL)
1102
0
  {
1103
0
    free (dctx->sfd_fres);
1104
0
    dctx->sfd_fres = NULL;
1105
0
  }
1106
0
      if (dctx->sfd_buf != NULL)
1107
0
  {
1108
0
    free (dctx->sfd_buf);
1109
0
    dctx->sfd_buf = NULL;
1110
0
  }
1111
1112
0
      free (*dctxp);
1113
0
      *dctxp = NULL;
1114
0
    }
1115
0
}
1116
1117
/* Create an FDE function info byte given an FRE_TYPE and an FDE_TYPE.  */
1118
/* FIXME API for linker.  Revisit if its better placed somewhere else?  */
1119
1120
unsigned char
1121
sframe_fde_create_func_info (uint32_t fre_type,
1122
           uint32_t fde_type)
1123
0
{
1124
0
  unsigned char func_info;
1125
0
  sframe_assert (fre_type == SFRAME_FRE_TYPE_ADDR1
1126
0
       || fre_type == SFRAME_FRE_TYPE_ADDR2
1127
0
       || fre_type == SFRAME_FRE_TYPE_ADDR4);
1128
0
  sframe_assert (fde_type == SFRAME_V3_FDE_PCTYPE_INC
1129
0
     || fde_type == SFRAME_V3_FDE_PCTYPE_MASK);
1130
0
  func_info = SFRAME_V2_FUNC_INFO (fde_type, fre_type);
1131
0
  return func_info;
1132
0
}
1133
1134
/* Get the FRE type given the function size.  */
1135
/* FIXME API for linker.  Revisit if its better placed somewhere else?  */
1136
1137
uint32_t
1138
sframe_calc_fre_type (size_t func_size)
1139
0
{
1140
0
  uint32_t fre_type = 0;
1141
0
  if (func_size < SFRAME_FRE_TYPE_ADDR1_LIMIT)
1142
0
    fre_type = SFRAME_FRE_TYPE_ADDR1;
1143
0
  else if (func_size < SFRAME_FRE_TYPE_ADDR2_LIMIT)
1144
0
    fre_type = SFRAME_FRE_TYPE_ADDR2;
1145
  /* Adjust the check a bit so that it remains warning-free but meaningful
1146
     on 32-bit systems.  */
1147
0
  else if (func_size <= (size_t) (SFRAME_FRE_TYPE_ADDR4_LIMIT - 1))
1148
0
    fre_type = SFRAME_FRE_TYPE_ADDR4;
1149
0
  return fre_type;
1150
0
}
1151
1152
/* Get the base reg id from the FRE info.  Set errp if failure.  */
1153
1154
uint8_t
1155
sframe_fre_get_base_reg_id (const sframe_frame_row_entry *fre, int *errp)
1156
0
{
1157
0
  if (fre == NULL)
1158
0
    return sframe_set_errno (errp, SFRAME_ERR_FRE_INVAL);
1159
1160
0
  uint8_t fre_info = fre->fre_info;
1161
0
  return SFRAME_V1_FRE_CFA_BASE_REG_ID (fre_info);
1162
0
}
1163
1164
/* Get the CFA offset from the FRE.  If the offset is invalid, sets errp.  */
1165
1166
int32_t
1167
sframe_fre_get_cfa_offset (const sframe_decoder_ctx *dctx,
1168
         const sframe_frame_row_entry *fre,
1169
         uint32_t fde_type,
1170
         int *errp)
1171
0
{
1172
0
  int err;
1173
0
  bool flex_p = (fde_type == SFRAME_FDE_TYPE_FLEX);
1174
0
  uint32_t idx = flex_p ? 1 : 0;
1175
0
  int32_t offset = sframe_get_fre_offset (fre, idx, &err);
1176
1177
  /* For s390x undo adjustment of CFA offset (to enable 8-bit offsets).  */
1178
0
  if (!err
1179
0
      && sframe_decoder_get_abi_arch (dctx) == SFRAME_ABI_S390X_ENDIAN_BIG)
1180
0
    offset = SFRAME_V2_S390X_CFA_OFFSET_DECODE (offset);
1181
1182
0
  if (errp)
1183
0
    *errp = err;
1184
0
  return offset;
1185
0
}
1186
1187
/* Get the FP offset from the FRE.  If the offset is invalid, sets errp.  */
1188
1189
int32_t
1190
sframe_fre_get_fp_offset (const sframe_decoder_ctx *dctx,
1191
        const sframe_frame_row_entry *fre,
1192
        uint32_t fde_type,
1193
        int *errp)
1194
0
{
1195
0
  int fp_err = 0;
1196
0
  int8_t fixed_fp_offset = sframe_decoder_get_fixed_fp_offset (dctx);
1197
0
  bool flex_p = (fde_type == SFRAME_FDE_TYPE_FLEX);
1198
1199
  /* Initialize fp_offset_idx for default FDEs.  In some ABIs, the stack offset
1200
     to recover RA (using the CFA) from is fixed (like AMD64).  In such cases,
1201
     the stack offset to recover FP will appear at the second index.  */
1202
0
  uint32_t fp_offset_idx = ((sframe_decoder_get_fixed_ra_offset (dctx)
1203
0
           != SFRAME_CFA_FIXED_RA_INVALID)
1204
0
          ? SFRAME_FRE_RA_OFFSET_IDX
1205
0
          : SFRAME_FRE_FP_OFFSET_IDX);
1206
0
  if (flex_p)
1207
0
    {
1208
0
      uint32_t flex_ra_reg_data
1209
0
  = sframe_get_fre_udata (fre, SFRAME_FRE_RA_OFFSET_IDX * 2, errp);
1210
      /* In presence of RA padding SFRAME_FRE_RA_OFFSET_INVALID (instead of RA
1211
   offsets), adjust the expected index of the FP offset.  */
1212
0
      if (errp && *errp == 0
1213
0
    && flex_ra_reg_data == SFRAME_FRE_RA_OFFSET_INVALID)
1214
0
  fp_offset_idx = SFRAME_FRE_FP_OFFSET_IDX * 2;
1215
0
      else
1216
0
  fp_offset_idx = SFRAME_FRE_FP_OFFSET_IDX * 2 + 1;
1217
0
    }
1218
1219
  /* NB: This errp must be retained if returning fp_offset.  */
1220
0
  int32_t fp_offset = sframe_get_fre_offset (fre, fp_offset_idx, &fp_err);
1221
1222
  /* If the FP offset is not being tracked, return the fixed FP offset from the
1223
     SFrame header:
1224
       - For default FDEs (!flex_p)
1225
       - For flex FDEs, if there were no FP offsets found.  */
1226
0
  if ((!flex_p || (flex_p && fp_err))
1227
0
      && fixed_fp_offset != SFRAME_CFA_FIXED_FP_INVALID
1228
0
      && !sframe_get_fre_ra_undefined_p (fre->fre_info))
1229
0
    {
1230
0
      if (errp)
1231
0
  *errp = 0;
1232
0
      return fixed_fp_offset;
1233
0
    }
1234
1235
0
  if (errp)
1236
0
    *errp = fp_err;
1237
0
  return fp_offset;
1238
0
}
1239
1240
/* Get the RA offset from the FRE.  If the offset is invalid, sets errp.  */
1241
1242
int32_t
1243
sframe_fre_get_ra_offset (const sframe_decoder_ctx *dctx,
1244
        const sframe_frame_row_entry *fre,
1245
        uint32_t fde_type,
1246
        int *errp)
1247
0
{
1248
0
  int ra_err = 0;
1249
0
  int8_t fixed_ra_offset = sframe_decoder_get_fixed_ra_offset (dctx);
1250
0
  bool flex_p = (fde_type == SFRAME_FDE_TYPE_FLEX);
1251
1252
0
  uint32_t ra_offset_idx = (flex_p
1253
0
          ? SFRAME_FRE_RA_OFFSET_IDX * 2 + 1
1254
0
          : SFRAME_FRE_RA_OFFSET_IDX);
1255
  /* NB: This errp must be retained if returning ra_offset.  */
1256
0
  int32_t ra_offset = sframe_get_fre_offset (fre, ra_offset_idx, &ra_err);
1257
1258
  /* For ABIs where RA offset is not being tracked, return the fixed RA offset
1259
     specified in the the SFrame header, when:
1260
       - for default FDEs (!flex_p)
1261
       - for flex FDEs, if RA offset is solely padding or not present.  */
1262
0
  if ((!flex_p || (flex_p && ra_err))
1263
0
      && fixed_ra_offset != SFRAME_CFA_FIXED_RA_INVALID
1264
0
      && !sframe_get_fre_ra_undefined_p (fre->fre_info))
1265
0
    {
1266
0
      if (errp)
1267
0
  *errp = 0;
1268
0
      return fixed_ra_offset;
1269
0
    }
1270
1271
  /* Otherwise, return the RA offset from the FRE.  The corresponding errp was
1272
     set earlier.  */
1273
0
  if (errp)
1274
0
    *errp = ra_err;
1275
0
  return ra_offset;
1276
0
}
1277
1278
/* Get whether the RA is mangled.  */
1279
1280
bool
1281
sframe_fre_get_ra_mangled_p (const sframe_decoder_ctx *dctx ATTRIBUTE_UNUSED,
1282
           const sframe_frame_row_entry *fre, int *errp)
1283
0
{
1284
0
  if (fre == NULL || !sframe_fre_sanity_check_p (fre))
1285
0
    return sframe_set_errno (errp, SFRAME_ERR_FRE_INVAL);
1286
1287
0
  return sframe_get_fre_ra_mangled_p (fre->fre_info);
1288
0
}
1289
1290
/* Get whether the RA is undefined (i.e. outermost frame).  */
1291
1292
bool
1293
sframe_fre_get_ra_undefined_p (const sframe_decoder_ctx *dctx ATTRIBUTE_UNUSED,
1294
             const sframe_frame_row_entry *fre, int *errp)
1295
0
{
1296
0
  if (fre == NULL || !sframe_fre_sanity_check_p (fre))
1297
0
    return sframe_set_errno (errp, SFRAME_ERR_FRE_INVAL);
1298
1299
0
  return sframe_get_fre_ra_undefined_p (fre->fre_info);
1300
0
}
1301
1302
static int
1303
sframe_frame_row_entry_copy (sframe_frame_row_entry *dst,
1304
           sframe_frame_row_entry *src)
1305
0
{
1306
0
  int err = 0;
1307
1308
0
  if (dst == NULL || src == NULL)
1309
0
    return sframe_set_errno (&err, SFRAME_ERR_INVAL);
1310
1311
0
  memcpy (dst, src, sizeof (sframe_frame_row_entry));
1312
0
  return 0;
1313
0
}
1314
1315
/* Decode the SFrame FRE start address offset value from FRE_BUF in on-disk
1316
   binary format, given the FRE_TYPE.  Updates the FRE_START_ADDR.
1317
1318
   Returns 0 on success, SFRAME_ERR otherwise.  */
1319
1320
static int
1321
sframe_decode_fre_start_address (const void *fre_buf,
1322
         uint32_t *fre_start_addr,
1323
         uint32_t fre_type)
1324
0
{
1325
0
  uint32_t saddr = 0;
1326
0
  int err = 0;
1327
1328
0
  if (fre_type == SFRAME_FRE_TYPE_ADDR1)
1329
0
    {
1330
0
      const uint8_t *uc = fre_buf;
1331
0
      saddr = *uc;
1332
0
    }
1333
0
  else if (fre_type == SFRAME_FRE_TYPE_ADDR2)
1334
0
    {
1335
      /* SFrame is an unaligned on-disk format.  See PR libsframe/29856.  */
1336
0
      const struct { uint16_t x; } ATTRIBUTE_PACKED *p = fre_buf;
1337
0
      saddr = p->x;
1338
0
    }
1339
0
  else if (fre_type == SFRAME_FRE_TYPE_ADDR4)
1340
0
    {
1341
0
      const struct { uint32_t x; } ATTRIBUTE_PACKED *p = fre_buf;
1342
0
      saddr = p->x;
1343
0
    }
1344
0
  else
1345
0
    sframe_set_errno (&err, SFRAME_ERR_INVAL);
1346
1347
0
  *fre_start_addr = saddr;
1348
0
  return err;
1349
0
}
1350
1351
/* Decode a frame row entry FRE which starts at location FRE_BUF.  The function
1352
   updates ESZ to the size of the FRE as stored in the binary format.
1353
1354
   This function works closely with the SFrame binary format.
1355
1356
   Returns SFRAME_ERR if failure.  */
1357
1358
static int
1359
sframe_decode_fre (const char *fre_buf, sframe_frame_row_entry *fre,
1360
       uint32_t fre_type, size_t *esz)
1361
0
{
1362
0
  int err = 0;
1363
0
  const char *datawords = NULL;
1364
0
  size_t datawords_sz;
1365
0
  size_t addr_size;
1366
0
  size_t fre_size;
1367
1368
0
  if (fre_buf == NULL || fre == NULL || esz == NULL)
1369
0
    return sframe_set_errno (&err, SFRAME_ERR_INVAL);
1370
1371
  /* Copy over the FRE start address.  */
1372
0
  sframe_decode_fre_start_address (fre_buf, &fre->fre_start_addr, fre_type);
1373
1374
0
  addr_size = sframe_fre_start_addr_size (fre_type);
1375
0
  fre->fre_info = *(uint8_t *)(fre_buf + addr_size);
1376
  /* Sanity check as the API works closely with the binary format.  */
1377
0
  sframe_assert (sizeof (fre->fre_info) == sizeof (uint8_t));
1378
1379
  /* Cleanup the space for fre_datawords first, then copy over the valid
1380
     bytes.  */
1381
0
  memset (fre->fre_datawords, 0, MAX_DATAWORD_BYTES);
1382
  /* Get offsets size.  */
1383
0
  datawords_sz = sframe_fre_datawords_bytes_size (fre->fre_info);
1384
0
  datawords = fre_buf + addr_size + sizeof (fre->fre_info);
1385
0
  memcpy (fre->fre_datawords, datawords, datawords_sz);
1386
1387
  /* The FRE has been decoded.  Use it to perform one last sanity check.  */
1388
0
  fre_size = sframe_fre_entry_size (fre, fre_type);
1389
0
  sframe_assert (fre_size == (addr_size + sizeof (fre->fre_info)
1390
0
            + datawords_sz));
1391
0
  *esz = fre_size;
1392
1393
0
  return 0;
1394
0
}
1395
1396
/* Decode the specified SFrame buffer SF_BUF of size SF_SIZE and return the
1397
   new SFrame decoder context.
1398
1399
   Sets ERRP for the caller if any error.  Frees up the allocated memory in
1400
   case of error.  */
1401
1402
sframe_decoder_ctx *
1403
sframe_decode (const char *sf_buf, size_t sf_size, int *errp)
1404
0
{
1405
0
  const sframe_preamble *sfp;
1406
0
  size_t hdrsz;
1407
0
  const sframe_header *dhp;
1408
0
  sframe_decoder_ctx *dctx;
1409
0
  char *frame_buf;
1410
1411
0
  size_t fidx_size;
1412
0
  uint32_t fre_bytes;
1413
0
  int foreign_endian = 0;
1414
1415
0
  sframe_init_debug ();
1416
1417
0
  if ((sf_buf == NULL) || (!sf_size))
1418
0
    return sframe_ret_set_errno (errp, SFRAME_ERR_INVAL);
1419
0
  else if (sf_size < sizeof (sframe_header))
1420
0
    return sframe_ret_set_errno (errp, SFRAME_ERR_BUF_INVAL);
1421
1422
0
  sfp = (const sframe_preamble *) sf_buf;
1423
1424
0
  debug_printf ("sframe_decode: magic=0x%x version=%u flags=%u\n",
1425
0
    sfp->sfp_magic, sfp->sfp_version, sfp->sfp_flags);
1426
1427
  /* Check for foreign endianness.  */
1428
0
  if (sfp->sfp_magic != SFRAME_MAGIC)
1429
0
    {
1430
0
      if (sfp->sfp_magic == bswap_16 (SFRAME_MAGIC))
1431
0
  foreign_endian = 1;
1432
0
      else
1433
0
  return sframe_ret_set_errno (errp, SFRAME_ERR_BUF_INVAL);
1434
0
    }
1435
1436
  /* Initialize a new decoder context.  */
1437
0
  if ((dctx = malloc (sizeof (sframe_decoder_ctx))) == NULL)
1438
0
    return sframe_ret_set_errno (errp, SFRAME_ERR_NOMEM);
1439
0
  memset (dctx, 0, sizeof (sframe_decoder_ctx));
1440
1441
0
  if (foreign_endian)
1442
0
    {
1443
      /* Allocate a new buffer and initialize it.  */
1444
0
      char *tempbuf = malloc (sf_size * sizeof (char));
1445
0
      if (tempbuf == NULL)
1446
0
  return sframe_ret_set_errno (errp, SFRAME_ERR_NOMEM);
1447
0
      memcpy (tempbuf, sf_buf, sf_size);
1448
1449
      /* Flip the header first.  */
1450
0
      if (flip_header (tempbuf, sfp->sfp_version))
1451
0
  {
1452
0
    sframe_ret_set_errno (errp, SFRAME_ERR_BUF_INVAL);
1453
0
    free (tempbuf);
1454
0
    goto decode_fail_free;
1455
0
  }
1456
      /* Flip the rest of the SFrame section data buffer.  */
1457
0
      if (flip_sframe (tempbuf, sf_size, 0))
1458
0
  {
1459
0
    sframe_ret_set_errno (errp, SFRAME_ERR_BUF_INVAL);
1460
0
    free (tempbuf);
1461
0
    goto decode_fail_free;
1462
0
  }
1463
1464
0
      frame_buf = tempbuf;
1465
      /* This buffer is malloc'd when endian flipping the contents of the input
1466
   buffer are needed.  Keep a reference to it so it can be free'd up
1467
   later in sframe_decoder_free ().  */
1468
0
      dctx->sfd_buf = tempbuf;
1469
0
    }
1470
0
  else
1471
0
    frame_buf = (char *)sf_buf;
1472
1473
  /* Handle the SFrame header.  */
1474
0
  dctx->sfd_header = *(sframe_header *) frame_buf;
1475
  /* Validate the contents of SFrame header.  */
1476
0
  dhp = &dctx->sfd_header;
1477
0
  if (!sframe_header_sanity_check_p (dhp))
1478
0
    {
1479
0
      sframe_ret_set_errno (errp, SFRAME_ERR_BUF_INVAL);
1480
0
      goto decode_fail_free;
1481
0
    }
1482
0
  hdrsz = sframe_get_hdr_size (dhp);
1483
0
  frame_buf += hdrsz;
1484
1485
  /* Handle the SFrame Function Descriptor Entry section.  */
1486
0
  if (sframe_fde_tbl_alloc (&dctx->sfd_funcdesc, dhp->sfh_num_fdes))
1487
0
    {
1488
0
      sframe_ret_set_errno (errp, SFRAME_ERR_NOMEM);
1489
0
      goto decode_fail_free;
1490
0
    }
1491
1492
  /* SFrame FDEs are at an offset of sfh_fdeoff from SFrame header end.  */
1493
0
  if (sframe_fde_tbl_init (dctx->sfd_funcdesc, frame_buf + dhp->sfh_fdeoff,
1494
0
         frame_buf + dhp->sfh_freoff,
1495
0
         &fidx_size, dhp->sfh_num_fdes, sfp->sfp_version))
1496
0
    {
1497
0
      sframe_ret_set_errno (errp, SFRAME_ERR_BUF_INVAL);
1498
0
      goto decode_fail_free;
1499
0
    }
1500
1501
0
  debug_printf ("%zu total fidx size\n", fidx_size);
1502
1503
  /* Handle the SFrame Frame Row Entry section.  */
1504
0
  dctx->sfd_fres = (char *) malloc (dhp->sfh_fre_len);
1505
0
  if (dctx->sfd_fres == NULL)
1506
0
    {
1507
0
      sframe_ret_set_errno (errp, SFRAME_ERR_NOMEM);
1508
0
      goto decode_fail_free;
1509
0
    }
1510
  /* SFrame FREs are at an offset of sfh_freoff from SFrame header end.  */
1511
0
  memcpy (dctx->sfd_fres, frame_buf + dhp->sfh_freoff, dhp->sfh_fre_len);
1512
1513
0
  fre_bytes = dhp->sfh_fre_len;
1514
0
  dctx->sfd_fre_nbytes = fre_bytes;
1515
1516
0
  debug_printf ("%u total fre bytes\n", fre_bytes);
1517
1518
0
  return dctx;
1519
1520
0
decode_fail_free:
1521
0
  sframe_decoder_free (&dctx);
1522
0
  dctx = NULL;
1523
0
  return dctx;
1524
0
}
1525
1526
/* Get the size of the SFrame header from the decoder context CTX.  */
1527
1528
unsigned int
1529
sframe_decoder_get_hdr_size (const sframe_decoder_ctx *ctx)
1530
0
{
1531
0
  const sframe_header *dhp = sframe_decoder_get_header (ctx);
1532
0
  return sframe_get_hdr_size (dhp);
1533
0
}
1534
1535
/* Get the SFrame's abi/arch info given the decoder context DCTX.  */
1536
1537
uint8_t
1538
sframe_decoder_get_abi_arch (const sframe_decoder_ctx *dctx)
1539
0
{
1540
0
  const sframe_header *dhp = sframe_decoder_get_header (dctx);
1541
0
  return dhp->sfh_abi_arch;
1542
0
}
1543
1544
/* Get the format version from the SFrame decoder context DCTX.  */
1545
1546
uint8_t
1547
sframe_decoder_get_version (const sframe_decoder_ctx *dctx)
1548
0
{
1549
0
  const sframe_header *dhp = sframe_decoder_get_header (dctx);
1550
0
  return dhp->sfh_preamble.sfp_version;
1551
0
}
1552
1553
/* Get the section flags from the SFrame decoder context DCTX.  */
1554
1555
uint8_t
1556
sframe_decoder_get_flags (const sframe_decoder_ctx *dctx)
1557
0
{
1558
0
  const sframe_header *dhp = sframe_decoder_get_header (dctx);
1559
0
  return dhp->sfh_preamble.sfp_flags;
1560
0
}
1561
1562
/* Get the SFrame's fixed FP offset given the decoder context CTX.  */
1563
int8_t
1564
sframe_decoder_get_fixed_fp_offset (const sframe_decoder_ctx *ctx)
1565
0
{
1566
0
  const sframe_header *dhp = sframe_decoder_get_header (ctx);
1567
0
  return dhp->sfh_cfa_fixed_fp_offset;
1568
0
}
1569
1570
/* Get the SFrame's fixed RA offset given the decoder context CTX.  */
1571
int8_t
1572
sframe_decoder_get_fixed_ra_offset (const sframe_decoder_ctx *ctx)
1573
0
{
1574
0
  const sframe_header *dhp = sframe_decoder_get_header (ctx);
1575
0
  return dhp->sfh_cfa_fixed_ra_offset;
1576
0
}
1577
1578
/* Get the offset of the sfde_func_start_address field (from the start of the
1579
   on-disk layout of the SFrame section) of the FDE at FUNC_IDX in the decoder
1580
   context DCTX.
1581
1582
   If FUNC_IDX is more than the number of SFrame FDEs in the section, sets
1583
   error code in ERRP, but returns the (hypothetical) offset.  This is useful
1584
   for the linker when arranging input FDEs into the output section to be
1585
   emitted.  */
1586
1587
uint32_t
1588
sframe_decoder_get_offsetof_fde_start_addr (const sframe_decoder_ctx *dctx,
1589
              uint32_t func_idx, int *errp)
1590
0
{
1591
0
  if (func_idx >= sframe_decoder_get_num_fidx (dctx))
1592
0
    sframe_ret_set_errno (errp, SFRAME_ERR_FDE_NOTFOUND);
1593
0
  else if (errp)
1594
0
    *errp = 0;
1595
1596
0
  if (sframe_decoder_get_version (dctx) == SFRAME_VERSION_3)
1597
0
    return (sframe_decoder_get_hdr_size (dctx)
1598
0
      + func_idx * sizeof (sframe_func_desc_idx_v3)
1599
0
      + offsetof (sframe_func_desc_idx_v3, sfdi_func_start_offset));
1600
0
  else if (sframe_decoder_get_version (dctx) == SFRAME_VERSION_2)
1601
0
    return (sframe_decoder_get_hdr_size (dctx)
1602
0
      + func_idx * sizeof (sframe_func_desc_entry_v2)
1603
0
      + offsetof (sframe_func_desc_entry_v2, sfde_func_start_address));
1604
0
  else
1605
0
    sframe_ret_set_errno (errp, SFRAME_ERR_INVAL);
1606
1607
0
  return 0;
1608
0
}
1609
1610
/* Find the function descriptor entry starting which contains the specified
1611
   address ADDR.  */
1612
1613
static sframe_func_desc_entry_int *
1614
sframe_get_funcdesc_with_addr_internal (const sframe_decoder_ctx *ctx,
1615
          int64_t addr, int *errp,
1616
          uint32_t *func_idx)
1617
0
{
1618
0
  sframe_func_desc_entry_int *fdp;
1619
0
  int low, high;
1620
1621
0
  if (ctx == NULL)
1622
0
    return sframe_ret_set_errno (errp, SFRAME_ERR_INVAL);
1623
1624
0
  const sframe_header *dhp = sframe_decoder_get_header (ctx);
1625
1626
0
  if (dhp == NULL || dhp->sfh_num_fdes == 0 || ctx->sfd_funcdesc == NULL)
1627
0
    return sframe_ret_set_errno (errp, SFRAME_ERR_DCTX_INVAL);
1628
  /* If the FDE sub-section is not sorted on PCs, skip the lookup because
1629
     binary search cannot be used.  */
1630
0
  if ((sframe_decoder_get_flags (ctx) & SFRAME_F_FDE_SORTED) == 0)
1631
0
    return sframe_ret_set_errno (errp, SFRAME_ERR_FDE_NOTSORTED);
1632
1633
  /* Do the binary search.  */
1634
0
  fdp = (sframe_func_desc_entry_int *) ctx->sfd_funcdesc->entry;
1635
0
  low = 0;
1636
0
  high = dhp->sfh_num_fdes - 1;
1637
0
  while (low <= high)
1638
0
    {
1639
0
      int mid = low + (high - low) / 2;
1640
1641
      /* Given func_start_addr <= addr,
1642
   addr - func_start_addr must be positive.  */
1643
0
      if (sframe_decoder_get_secrel_func_start_addr (ctx, mid) <= addr
1644
0
    && ((uint32_t)(addr - sframe_decoder_get_secrel_func_start_addr (ctx,
1645
0
                     mid))
1646
0
        < fdp[mid].func_size))
1647
0
  {
1648
0
    *func_idx = mid;
1649
0
    return fdp + mid;
1650
0
  }
1651
1652
0
      if (sframe_decoder_get_secrel_func_start_addr (ctx, mid) < addr)
1653
0
  low = mid + 1;
1654
0
      else
1655
0
  high = mid - 1;
1656
0
    }
1657
1658
0
  return sframe_ret_set_errno (errp, SFRAME_ERR_FDE_NOTFOUND);
1659
0
}
1660
1661
/* Get the end IP offset for the FRE at index i in the FDEP.  The buffer FRES
1662
   is the starting location for the FRE.  */
1663
1664
static uint32_t
1665
sframe_fre_get_end_ip_offset (sframe_func_desc_entry_int *fdep, unsigned int i,
1666
            const char *fres)
1667
0
{
1668
0
  uint32_t end_ip_offset;
1669
0
  uint32_t fre_type;
1670
1671
0
  fre_type = sframe_get_fre_type (fdep);
1672
1673
  /* Get the start address of the next FRE in sequence.  */
1674
0
  if (i < fdep->func_num_fres - 1)
1675
0
    {
1676
0
      sframe_decode_fre_start_address (fres, &end_ip_offset, fre_type);
1677
0
      end_ip_offset -= 1;
1678
0
    }
1679
0
  else
1680
    /* The end IP offset for the FRE needs to be deduced from the function
1681
       size.  */
1682
0
    end_ip_offset = fdep->func_size - 1;
1683
1684
0
  return end_ip_offset;
1685
0
}
1686
1687
/* Find the SFrame Row Entry which contains the PC.  Returns
1688
   SFRAME_ERR if failure.  */
1689
1690
int
1691
sframe_find_fre (const sframe_decoder_ctx *ctx, int64_t pc,
1692
     sframe_frame_row_entry *frep)
1693
0
{
1694
0
  sframe_frame_row_entry cur_fre;
1695
0
  sframe_func_desc_entry_int *fdep;
1696
0
  uint32_t func_idx;
1697
0
  uint32_t fre_type, i;
1698
0
  int64_t func_start_pc_offset;
1699
0
  uint32_t start_ip_offset, end_ip_offset;
1700
0
  const char *fres;
1701
0
  size_t size = 0;
1702
0
  int err = 0;
1703
1704
0
  if ((ctx == NULL) || (frep == NULL))
1705
0
    return sframe_set_errno (&err, SFRAME_ERR_INVAL);
1706
1707
0
  uint8_t ver = sframe_decoder_get_version (ctx);
1708
  /* Find the FDE which contains the PC, then scan its fre entries.  */
1709
0
  fdep = sframe_get_funcdesc_with_addr_internal (ctx, pc, &err, &func_idx);
1710
0
  if (fdep == NULL || ctx->sfd_fres == NULL)
1711
0
    return sframe_set_errno (&err, SFRAME_ERR_DCTX_INVAL);
1712
1713
0
  fre_type = sframe_get_fre_type (fdep);
1714
1715
0
  fres = ctx->sfd_fres + fdep->func_start_fre_off;
1716
0
  if (ver == SFRAME_VERSION_3)
1717
0
    fres += sizeof (sframe_func_desc_attr_v3);
1718
0
  func_start_pc_offset = sframe_decoder_get_secrel_func_start_addr (ctx,
1719
0
                    func_idx);
1720
1721
0
  for (i = 0; i < fdep->func_num_fres; i++)
1722
0
   {
1723
0
     err = sframe_decode_fre (fres, &cur_fre, fre_type, &size);
1724
0
     if (err)
1725
0
       return sframe_set_errno (&err, SFRAME_ERR_FRE_INVAL);
1726
1727
0
     start_ip_offset = cur_fre.fre_start_addr;
1728
0
     end_ip_offset = sframe_fre_get_end_ip_offset (fdep, i, fres + size);
1729
1730
     /* Stop search if FRE's start_ip is greater than pc.  Given
1731
  func_start_addr <= pc, pc - func_start_addr must be positive.  */
1732
0
     if (start_ip_offset > (uint32_t)(pc - func_start_pc_offset))
1733
0
       return sframe_set_errno (&err, SFRAME_ERR_FRE_INVAL);
1734
1735
0
     if (sframe_fre_check_range_p (ctx, func_idx, start_ip_offset,
1736
0
           end_ip_offset, pc))
1737
0
       {
1738
0
   sframe_frame_row_entry_copy (frep, &cur_fre);
1739
0
   return 0;
1740
0
       }
1741
0
     fres += size;
1742
0
   }
1743
0
  return sframe_set_errno (&err, SFRAME_ERR_FDE_INVAL);
1744
0
}
1745
1746
/* Return the number of function descriptor entries in the SFrame decoder
1747
   DCTX.  */
1748
1749
uint32_t
1750
sframe_decoder_get_num_fidx (const sframe_decoder_ctx *ctx)
1751
0
{
1752
0
  uint32_t num_fdes = 0;
1753
0
  const sframe_header *dhp = sframe_decoder_get_header (ctx);
1754
0
  if (dhp)
1755
0
    num_fdes = dhp->sfh_num_fdes;
1756
0
  return num_fdes;
1757
0
}
1758
1759
int
1760
sframe_decoder_get_funcdesc_v2 (const sframe_decoder_ctx *dctx,
1761
        unsigned int i,
1762
        uint32_t *num_fres,
1763
        uint32_t *func_size,
1764
        int32_t *func_start_address,
1765
        unsigned char *func_info,
1766
        uint8_t *rep_block_size)
1767
0
{
1768
0
  sframe_func_desc_entry_int *fdp;
1769
0
  int err = 0;
1770
1771
0
  if (dctx == NULL || func_start_address == NULL
1772
0
      || num_fres == NULL || func_size == NULL
1773
0
      || sframe_decoder_get_version (dctx) == SFRAME_VERSION_1)
1774
0
    return sframe_set_errno (&err, SFRAME_ERR_INVAL);
1775
1776
0
  fdp = sframe_decoder_get_funcdesc_at_index (dctx, i);
1777
1778
0
  if (fdp == NULL)
1779
0
    return sframe_set_errno (&err, SFRAME_ERR_FDE_NOTFOUND);
1780
1781
0
  *num_fres = fdp->func_num_fres;
1782
0
  *func_start_address = (int32_t) fdp->func_start_pc_offset;
1783
0
  *func_size = fdp->func_size;
1784
0
  *func_info = fdp->func_info;
1785
0
  *rep_block_size = fdp->func_rep_size;
1786
1787
0
  return 0;
1788
0
}
1789
1790
/* Get the data (NUM_FRES, FUNC_SIZE, START_PC_OFFSET, FUNC_INFO,
1791
   REP_BLOCK_SIZE) from the SFrame function descriptor entry at the I'th index
1792
   in the decoder object DCTX.  Return SFRAME_ERR on failure.  */
1793
1794
int
1795
sframe_decoder_get_funcdesc_v3 (const sframe_decoder_ctx *dctx,
1796
        unsigned int i,
1797
        uint32_t *num_fres,
1798
        uint32_t *func_size,
1799
        int64_t *start_pc_offset,
1800
        unsigned char *func_info,
1801
        unsigned char *func_info2,
1802
        uint8_t *rep_block_size)
1803
0
{
1804
0
  int err = 0;
1805
0
  if (dctx == NULL || sframe_decoder_get_version (dctx) != SFRAME_VERSION_3)
1806
0
    return sframe_set_errno (&err, SFRAME_ERR_INVAL);
1807
1808
0
  sframe_func_desc_entry_int *fdp
1809
0
    = sframe_decoder_get_funcdesc_at_index (dctx, i);
1810
0
  if (fdp == NULL)
1811
0
    return sframe_set_errno (&err, SFRAME_ERR_FDE_NOTFOUND);
1812
1813
0
  if (num_fres)
1814
0
    *num_fres = fdp->func_num_fres;
1815
0
  if (start_pc_offset)
1816
0
    *start_pc_offset = fdp->func_start_pc_offset;
1817
0
  if (func_size)
1818
0
    *func_size = fdp->func_size;
1819
0
  if (func_info)
1820
0
    *func_info = fdp->func_info;
1821
0
  if (func_info2)
1822
0
    *func_info2 = fdp->func_info2;
1823
0
  if (rep_block_size)
1824
0
    *rep_block_size = fdp->func_rep_size;
1825
1826
0
  return 0;
1827
0
}
1828
1829
/* Get the FRE_IDX'th FRE of the function at FUNC_IDX'th function
1830
   descriptor entry in the SFrame decoder CTX.  Returns error code as
1831
   applicable.  */
1832
1833
int
1834
sframe_decoder_get_fre (const sframe_decoder_ctx *ctx,
1835
      unsigned int func_idx,
1836
      unsigned int fre_idx,
1837
      sframe_frame_row_entry *fre)
1838
0
{
1839
0
  sframe_func_desc_entry_int *fdep;
1840
0
  sframe_frame_row_entry ifre;
1841
0
  const char *fres;
1842
0
  uint32_t i;
1843
0
  uint32_t fre_type;
1844
0
  size_t esz = 0;
1845
0
  int err = 0;
1846
1847
0
  if (ctx == NULL || fre == NULL)
1848
0
    return sframe_set_errno (&err, SFRAME_ERR_INVAL);
1849
1850
0
  uint8_t ver = sframe_decoder_get_version (ctx);
1851
1852
  /* Get function descriptor entry at index func_idx.  */
1853
0
  fdep = sframe_decoder_get_funcdesc_at_index (ctx, func_idx);
1854
0
  if (fdep == NULL)
1855
0
    return sframe_set_errno (&err, SFRAME_ERR_FDE_NOTFOUND);
1856
1857
0
  fre_type = sframe_get_fre_type (fdep);
1858
  /* Now scan the FRE entries.  */
1859
0
  fres = ctx->sfd_fres + fdep->func_start_fre_off;
1860
0
  if (ver == SFRAME_VERSION_3)
1861
0
    fres += sizeof (sframe_func_desc_attr_v3);
1862
1863
0
  for (i = 0; i < fdep->func_num_fres; i++)
1864
0
   {
1865
     /* Decode the FRE at the current position.  Return it if valid.  */
1866
0
     err = sframe_decode_fre (fres, &ifre, fre_type, &esz);
1867
0
     if (i == fre_idx)
1868
0
       {
1869
0
   if (!sframe_fre_sanity_check_p (&ifre))
1870
0
     return sframe_set_errno (&err, SFRAME_ERR_FRE_INVAL);
1871
1872
    /* Although a stricter sanity check on fre_start_addr like:
1873
         if (fdep->func_size)
1874
     sframe_assert (frep->fre_start_addr < fdep->func_size);
1875
       is more suitable, some code has been seen to not abide by it.  See
1876
       PR libsframe/33131.  */
1877
0
    sframe_assert (ifre.fre_start_addr <= fdep->func_size);
1878
1879
0
   sframe_frame_row_entry_copy (fre, &ifre);
1880
1881
0
   return 0;
1882
0
       }
1883
     /* Next FRE.  */
1884
0
     fres += esz;
1885
0
   }
1886
1887
0
  return sframe_set_errno (&err, SFRAME_ERR_FDE_NOTFOUND);
1888
0
}
1889
1890
/* Get the SFrame FRE data of the function at FUNC_IDX'th function index entry
1891
   in the SFrame decoder DCTX.  The reference to the buffer is returned in
1892
   FRES_BUF with FRES_BUF_SIZE indicating the size of the buffer.  The number
1893
   of FREs in the buffer are NUM_FRES.  In SFrame V3, this buffer also contains
1894
   the FDE attr data before the actual SFrame FREs.  Returns SFRAME_ERR in case
1895
   of error.  */
1896
1897
int
1898
sframe_decoder_get_fres_buf (const sframe_decoder_ctx *dctx,
1899
           const uint32_t func_idx,
1900
           char **fres_buf,
1901
           size_t *fres_buf_size,
1902
           uint32_t *num_fres)
1903
0
{
1904
0
  sframe_func_desc_entry_int *fdep;
1905
0
  uint32_t i = 0;
1906
0
  uint32_t fre_type;
1907
0
  size_t esz;
1908
0
  int err = 0;
1909
1910
0
  if (dctx == NULL || fres_buf == NULL)
1911
0
    return sframe_set_errno (&err, SFRAME_ERR_INVAL);
1912
1913
  /* Get function descriptor entry at index func_idx.  */
1914
0
  fdep = sframe_decoder_get_funcdesc_at_index (dctx, func_idx);
1915
0
  *num_fres = fdep->func_num_fres;
1916
1917
0
  if (fdep == NULL)
1918
0
    return sframe_set_errno (&err, SFRAME_ERR_FDE_NOTFOUND);
1919
1920
0
  fre_type = sframe_get_fre_type (fdep);
1921
  /* Update the pointer to (and total size of) the FRE entries.  */
1922
0
  *fres_buf = dctx->sfd_fres + fdep->func_start_fre_off;
1923
0
  const char *tmp_buf = *fres_buf + sizeof (sframe_func_desc_attr_v3);
1924
0
  *fres_buf_size = sizeof (sframe_func_desc_attr_v3);
1925
0
  while (i < *num_fres)
1926
0
    {
1927
      /* Avoid cost of full decoding at this time.  */
1928
0
      esz = sframe_buf_fre_entry_size (tmp_buf, fre_type);
1929
0
      tmp_buf += esz;
1930
0
      *fres_buf_size += esz;
1931
0
      i++;
1932
0
    }
1933
1934
0
  return 0;
1935
0
}
1936
1937
1938
/* SFrame Encoder.  */
1939
1940
/* Get a reference to the SFrame header, given the encoder context ECTX.  */
1941
1942
static sframe_header *
1943
sframe_encoder_get_header (sframe_encoder_ctx *ectx)
1944
0
{
1945
0
  sframe_header *hp = NULL;
1946
0
  if (ectx)
1947
0
    hp = &ectx->sfe_header;
1948
0
  return hp;
1949
0
}
1950
1951
static sframe_func_desc_entry_int *
1952
sframe_encoder_get_funcdesc_at_index (sframe_encoder_ctx *ectx,
1953
              uint32_t func_idx)
1954
0
{
1955
0
  sframe_func_desc_entry_int *fde = NULL;
1956
0
  if (func_idx < sframe_encoder_get_num_fidx (ectx))
1957
0
    {
1958
0
      sf_fde_tbl *func_tbl = ectx->sfe_funcdesc;
1959
0
      fde = func_tbl->entry + func_idx;
1960
0
    }
1961
0
  return fde;
1962
0
}
1963
1964
/* Create an encoder context with the given SFrame format version VER, FLAGS
1965
   and ABI information.  Uses the ABI specific FIXED_FP_OFFSET and
1966
   FIXED_RA_OFFSET values as provided.  Sets errp if failure.  */
1967
1968
sframe_encoder_ctx *
1969
sframe_encode (uint8_t ver, uint8_t flags, uint8_t abi_arch,
1970
         int8_t fixed_fp_offset, int8_t fixed_ra_offset, int *errp)
1971
0
{
1972
0
  sframe_header *hp;
1973
0
  sframe_encoder_ctx *ectx;
1974
1975
0
  if (ver != SFRAME_VERSION)
1976
0
    return sframe_ret_set_errno (errp, SFRAME_ERR_VERSION_INVAL);
1977
1978
0
  if ((ectx = malloc (sizeof (sframe_encoder_ctx))) == NULL)
1979
0
    return sframe_ret_set_errno (errp, SFRAME_ERR_NOMEM);
1980
1981
0
  memset (ectx, 0, sizeof (sframe_encoder_ctx));
1982
1983
  /* Get the SFrame header and update it.  */
1984
0
  hp = sframe_encoder_get_header (ectx);
1985
0
  hp->sfh_preamble.sfp_version = ver;
1986
0
  hp->sfh_preamble.sfp_magic = SFRAME_MAGIC;
1987
0
  hp->sfh_preamble.sfp_flags = flags;
1988
1989
  /* Implementation in the SFrame encoder APIs, e.g.,
1990
     sframe_encoder_write_sframe assume flag SFRAME_F_FDE_FUNC_START_PCREL
1991
     set.  */
1992
0
  if (!(flags & SFRAME_F_FDE_FUNC_START_PCREL))
1993
0
    {
1994
0
      free (ectx);
1995
0
      return sframe_ret_set_errno (errp, SFRAME_ERR_ECTX_INVAL);
1996
0
    }
1997
1998
0
  hp->sfh_abi_arch = abi_arch;
1999
0
  hp->sfh_cfa_fixed_fp_offset = fixed_fp_offset;
2000
0
  hp->sfh_cfa_fixed_ra_offset = fixed_ra_offset;
2001
2002
0
  return ectx;
2003
0
}
2004
2005
/* Free the encoder context ECTXP.  */
2006
2007
void
2008
sframe_encoder_free (sframe_encoder_ctx **ectxp)
2009
0
{
2010
0
  if (ectxp != NULL)
2011
0
    {
2012
0
      sframe_encoder_ctx *ectx = *ectxp;
2013
0
      if (ectx == NULL)
2014
0
  return;
2015
2016
0
      if (ectx->sfe_funcdesc != NULL)
2017
0
  {
2018
0
    free (ectx->sfe_funcdesc);
2019
0
    ectx->sfe_funcdesc = NULL;
2020
0
  }
2021
0
      if (ectx->sfe_fres != NULL)
2022
0
  {
2023
0
    free (ectx->sfe_fres);
2024
0
    ectx->sfe_fres = NULL;
2025
0
  }
2026
0
      if (ectx->sfe_data != NULL)
2027
0
  {
2028
0
    free (ectx->sfe_data);
2029
0
    ectx->sfe_data = NULL;
2030
0
  }
2031
2032
0
      free (*ectxp);
2033
0
      *ectxp = NULL;
2034
0
    }
2035
0
}
2036
2037
/* Get the size of the SFrame header from the encoder context ECTX.  */
2038
2039
unsigned int
2040
sframe_encoder_get_hdr_size (sframe_encoder_ctx *ectx)
2041
0
{
2042
0
  const sframe_header *ehp = sframe_encoder_get_header (ectx);
2043
0
  return sframe_get_hdr_size (ehp);
2044
0
}
2045
2046
/* Get the SFrame abi/arch info from the encoder context ECTX.  */
2047
2048
uint8_t
2049
sframe_encoder_get_abi_arch (sframe_encoder_ctx *ectx)
2050
0
{
2051
0
  uint8_t abi_arch = 0;
2052
0
  const sframe_header *ehp = sframe_encoder_get_header (ectx);
2053
0
  if (ehp)
2054
0
    abi_arch = ehp->sfh_abi_arch;
2055
0
  return abi_arch;
2056
0
}
2057
2058
/* Get the SFrame format version from the encoder context ECTX.  */
2059
2060
uint8_t
2061
sframe_encoder_get_version (sframe_encoder_ctx *ectx)
2062
0
{
2063
0
  const sframe_header *ehp = sframe_encoder_get_header (ectx);
2064
0
  return ehp->sfh_preamble.sfp_version;
2065
0
}
2066
2067
/* Get the SFrame flags from the encoder context ECTX.  */
2068
2069
uint8_t
2070
sframe_encoder_get_flags (sframe_encoder_ctx *ectx)
2071
0
{
2072
0
  const sframe_header *ehp = sframe_encoder_get_header (ectx);
2073
0
  return ehp->sfh_preamble.sfp_flags;
2074
0
}
2075
2076
/* Return the number of SFrame function descriptor entries in the encoder
2077
   context ECTX.  */
2078
2079
uint32_t
2080
sframe_encoder_get_num_fidx (sframe_encoder_ctx *ectx)
2081
0
{
2082
0
  uint32_t num_fdes = 0;
2083
0
  const sframe_header *ehp = sframe_encoder_get_header (ectx);
2084
0
  if (ehp)
2085
0
    num_fdes = ehp->sfh_num_fdes;
2086
0
  return num_fdes;
2087
0
}
2088
2089
/* Get the offset of the sfde_func_start_address field (from the start of the
2090
   on-disk layout of the SFrame section) of the FDE at FUNC_IDX in the encoder
2091
   context ECTX.
2092
2093
   If FUNC_IDX is more than the number of SFrame FDEs in the section, sets
2094
   error code in ERRP, but returns the (hypothetical) offset.  This is useful
2095
   for the linker when arranging input FDEs into the output section to be
2096
   emitted.  */
2097
2098
uint32_t
2099
sframe_encoder_get_offsetof_fde_start_addr (sframe_encoder_ctx *ectx,
2100
              uint32_t func_idx, int *errp)
2101
0
{
2102
0
  if (func_idx >= sframe_encoder_get_num_fidx (ectx))
2103
0
    sframe_ret_set_errno (errp, SFRAME_ERR_FDE_INVAL);
2104
0
  else if (errp)
2105
0
    *errp = 0;
2106
2107
0
  return (sframe_encoder_get_hdr_size (ectx)
2108
0
    + func_idx * sizeof (sframe_func_desc_idx_v3)
2109
0
    + offsetof (sframe_func_desc_idx_v3, sfdi_func_start_offset));
2110
0
}
2111
2112
/* Add an SFrame FRE to function at FUNC_IDX'th function descriptor entry in
2113
   the encoder context ECTX.  */
2114
2115
int
2116
sframe_encoder_add_fre (sframe_encoder_ctx *ectx,
2117
      unsigned int func_idx,
2118
      sframe_frame_row_entry *frep)
2119
0
{
2120
0
  sframe_header *ehp;
2121
0
  sframe_func_desc_entry_int *fdep;
2122
0
  sframe_frame_row_entry *ectx_frep;
2123
0
  size_t datawords_sz, esz;
2124
0
  uint32_t fre_type;
2125
0
  int err = 0;
2126
2127
0
  if (ectx == NULL || frep == NULL)
2128
0
    return sframe_set_errno (&err, SFRAME_ERR_INVAL);
2129
0
  if (!sframe_fre_sanity_check_p (frep))
2130
0
    return sframe_set_errno (&err, SFRAME_ERR_FRE_INVAL);
2131
2132
  /* Use func_idx to gather the function descriptor entry.  */
2133
0
  fdep = sframe_encoder_get_funcdesc_at_index (ectx, func_idx);
2134
2135
0
  if (fdep == NULL)
2136
0
    return sframe_set_errno (&err, SFRAME_ERR_FDE_NOTFOUND);
2137
2138
0
  fre_type = sframe_get_fre_type (fdep);
2139
0
  sf_fre_tbl *fre_tbl = ectx->sfe_fres;
2140
2141
0
  if (fre_tbl == NULL || fre_tbl->count == fre_tbl->alloced)
2142
0
    {
2143
0
      sf_fre_tbl *tmp = sframe_grow_fre_tbl (fre_tbl, 1, &err);
2144
0
      if (err)
2145
0
  {
2146
0
    sframe_set_errno (&err, SFRAME_ERR_NOMEM);
2147
0
    goto bad;
2148
0
  }
2149
0
      fre_tbl = tmp;
2150
0
    }
2151
2152
0
  ectx_frep = &fre_tbl->entry[fre_tbl->count];
2153
0
  ectx_frep->fre_start_addr
2154
0
    = frep->fre_start_addr;
2155
0
  ectx_frep->fre_info = frep->fre_info;
2156
2157
  /* Although a stricter sanity check on fre_start_addr like:
2158
       if (fdep->func_size)
2159
   sframe_assert (frep->fre_start_addr < fdep->func_size);
2160
     is more suitable, some code has been seen to not abide by it.  See PR
2161
     libsframe/33131.  */
2162
0
  sframe_assert (frep->fre_start_addr <= fdep->func_size);
2163
2164
  /* frep has already been sanity check'd.  Get offsets size.  */
2165
0
  datawords_sz = sframe_fre_datawords_bytes_size (frep->fre_info);
2166
0
  memcpy (&ectx_frep->fre_datawords, &frep->fre_datawords, datawords_sz);
2167
2168
0
  esz = sframe_fre_entry_size (frep, fre_type);
2169
0
  fre_tbl->count++;
2170
2171
0
  ectx->sfe_fres = fre_tbl;
2172
0
  ectx->sfe_fre_nbytes += esz;
2173
2174
0
  if (!fdep->func_num_fres)
2175
0
    ectx->sfe_fre_nbytes += sizeof (sframe_func_desc_attr_v3);
2176
2177
0
  ehp = sframe_encoder_get_header (ectx);
2178
0
  ehp->sfh_num_fres = fre_tbl->count;
2179
2180
  /* Update the value of the number of FREs for the function.  */
2181
0
  fdep->func_num_fres++;
2182
2183
0
  return 0;
2184
2185
0
bad:
2186
0
  if (fre_tbl != NULL)
2187
0
    free (fre_tbl);
2188
0
  ectx->sfe_fres = NULL;
2189
0
  ectx->sfe_fre_nbytes = 0;
2190
0
  return -1;
2191
0
}
2192
2193
/* Add SFrame FRE data given in the buffer FRES_BUF of size FRES_BUF_SIZE (for
2194
   function at index FUNC_IDX) to the encoder context ECTX.  The number of FREs
2195
   in the buffer are NUM_FRES.  Returns SFRAME_ERR if failure.  */
2196
2197
int
2198
sframe_encoder_add_fres_buf (sframe_encoder_ctx *ectx,
2199
           unsigned int func_idx,
2200
           uint32_t num_fres,
2201
           const char *fres_buf,
2202
           size_t fres_buf_size)
2203
0
{
2204
0
  sframe_frame_row_entry *ectx_frep;
2205
0
  size_t esz = 0;
2206
2207
0
  int err = 0;
2208
0
  if (ectx == NULL || ((fres_buf == NULL) != (fres_buf_size == 0)))
2209
0
    return sframe_set_errno (&err, SFRAME_ERR_INVAL);
2210
2211
  /* Use func_idx to gather the function descriptor entry.  */
2212
0
  sframe_func_desc_entry_int *fdep
2213
0
    = sframe_encoder_get_funcdesc_at_index (ectx, func_idx);
2214
0
  if (fdep == NULL)
2215
0
    return sframe_set_errno (&err, SFRAME_ERR_FDE_NOTFOUND);
2216
2217
0
  sf_fre_tbl *fre_tbl = ectx->sfe_fres;
2218
0
  if (fre_tbl == NULL || fre_tbl->count + num_fres >= fre_tbl->alloced)
2219
0
    {
2220
0
      sf_fre_tbl *tmp = sframe_grow_fre_tbl (fre_tbl, num_fres, &err);
2221
0
      if (err)
2222
0
  {
2223
0
    sframe_set_errno (&err, SFRAME_ERR_NOMEM);
2224
0
    goto bad;   /* OOM.  */
2225
0
  }
2226
0
      fre_tbl = tmp;
2227
0
    }
2228
2229
  /* Update the SFrame func attr values.  */
2230
0
  fdep->func_num_fres = num_fres;
2231
0
  const char *fres = fres_buf + sizeof (uint16_t);
2232
0
  fdep->func_info = *(uint8_t *)fres;
2233
0
  fres += sizeof (uint8_t);
2234
0
  fdep->func_info2 = *(uint8_t *)fres;
2235
0
  fres += sizeof (uint8_t);
2236
0
  fdep->func_rep_size = *(uint8_t *)fres;
2237
0
  fres += sizeof (uint8_t);
2238
2239
0
  uint32_t fre_type = sframe_get_fre_type (fdep);
2240
0
  uint32_t remaining = num_fres;
2241
0
  size_t buf_size = sizeof (sframe_func_desc_attr_v3);
2242
0
  while (remaining)
2243
0
    {
2244
0
      ectx_frep = &fre_tbl->entry[fre_tbl->count];
2245
      /* Copy the SFrame FRE data over to the encoder object's fre_tbl.  */
2246
0
      sframe_decode_fre (fres, ectx_frep, fre_type, &esz);
2247
2248
0
      if (!sframe_fre_sanity_check_p (ectx_frep))
2249
0
  return sframe_set_errno (&err, SFRAME_ERR_FRE_INVAL);
2250
2251
      /* Although a stricter sanity check on fre_start_addr like:
2252
     if (fdep->func_size)
2253
       sframe_assert (frep->fre_start_addr < fdep->func_size);
2254
   is more suitable, some code has been seen to not abide by it.  See PR
2255
   libsframe/33131.  */
2256
0
      sframe_assert (ectx_frep->fre_start_addr <= fdep->func_size);
2257
2258
0
      fre_tbl->count++;
2259
0
      fres += esz;
2260
0
      buf_size += esz;
2261
0
      remaining--;
2262
0
    }
2263
2264
0
  sframe_assert (fres_buf_size == buf_size);
2265
0
  ectx->sfe_fres = fre_tbl;
2266
0
  ectx->sfe_fre_nbytes += buf_size;
2267
2268
0
  sframe_header *ehp = sframe_encoder_get_header (ectx);
2269
0
  ehp->sfh_num_fres = fre_tbl->count;
2270
2271
0
  return 0;
2272
2273
0
bad:
2274
0
  if (fre_tbl != NULL)
2275
0
    free (fre_tbl);
2276
0
  ectx->sfe_fres = NULL;
2277
0
  ectx->sfe_fre_nbytes = 0;
2278
0
  return -1;
2279
0
}
2280
2281
/* Add a new SFrame function descriptor entry with START_ADDR, FUNC_SIZE and
2282
   FUNC_INFO to the encoder context ECTX.  Caller must make sure that ECTX
2283
   exists.  */
2284
2285
static int
2286
sframe_encoder_add_funcdesc_internal (sframe_encoder_ctx *ectx,
2287
              int64_t start_addr,
2288
              uint32_t func_size)
2289
0
{
2290
0
  sframe_header *ehp;
2291
0
  sf_fde_tbl *fd_info;
2292
0
  size_t fd_tbl_sz;
2293
0
  int err = 0;
2294
2295
0
  fd_info = ectx->sfe_funcdesc;
2296
0
  ehp = sframe_encoder_get_header (ectx);
2297
2298
0
  if (fd_info == NULL)
2299
0
    {
2300
0
      fd_tbl_sz = (sizeof (sf_fde_tbl)
2301
0
       + (number_of_entries * sizeof (sframe_func_desc_entry_int)));
2302
0
      fd_info = malloc (fd_tbl_sz);
2303
0
      if (fd_info == NULL)
2304
0
  {
2305
0
    sframe_set_errno (&err, SFRAME_ERR_NOMEM);
2306
0
    goto bad;   /* OOM.  */
2307
0
  }
2308
0
      memset (fd_info, 0, fd_tbl_sz);
2309
0
      fd_info->alloced = number_of_entries;
2310
0
    }
2311
0
  else if (fd_info->count == fd_info->alloced)
2312
0
    {
2313
0
      fd_tbl_sz = (sizeof (sf_fde_tbl)
2314
0
       + ((fd_info->alloced + number_of_entries)
2315
0
          * sizeof (sframe_func_desc_entry_int)));
2316
0
      sf_fde_tbl *tmp = realloc (fd_info, fd_tbl_sz);
2317
0
      if (tmp == NULL)
2318
0
  {
2319
0
    sframe_set_errno (&err, SFRAME_ERR_NOMEM);
2320
0
    goto bad;   /* OOM.  */
2321
0
  }
2322
0
      fd_info = tmp;
2323
2324
0
      memset (&fd_info->entry[fd_info->alloced], 0,
2325
0
        number_of_entries * sizeof (sframe_func_desc_entry_int));
2326
0
      fd_info->alloced += number_of_entries;
2327
0
    }
2328
2329
0
  fd_info->entry[fd_info->count].func_start_pc_offset = start_addr;
2330
  /* Num FREs is updated as FREs are added for the function later via
2331
     sframe_encoder_add_fre.  */
2332
0
  fd_info->entry[fd_info->count].func_size = func_size;
2333
0
  fd_info->entry[fd_info->count].func_start_fre_off = ectx->sfe_fre_nbytes;
2334
#if 0
2335
  // Linker optimization test code cleanup later ibhagat TODO FIXME
2336
  uint32_t fre_type = sframe_calc_fre_type (func_size);
2337
2338
  fd_info->entry[fd_info->count].sfde_func_info
2339
    = sframe_fde_func_info (fre_type);
2340
#endif
2341
0
  fd_info->count++;
2342
0
  ectx->sfe_funcdesc = fd_info;
2343
0
  ehp->sfh_num_fdes++;
2344
0
  return 0;
2345
2346
0
bad:
2347
0
  if (fd_info != NULL)
2348
0
    free (fd_info);
2349
0
  ectx->sfe_funcdesc = NULL;
2350
0
  ehp->sfh_num_fdes = 0;
2351
0
  return err;
2352
0
}
2353
2354
/* Add a new SFrame function descriptor entry with START_PC_OFFSET and
2355
   FUNC_SIZE to the encoder context ECTX.  */
2356
2357
int
2358
sframe_encoder_add_funcdesc (sframe_encoder_ctx *ectx, int64_t start_pc_offset,
2359
           uint32_t func_size)
2360
0
{
2361
0
  int err = 0;
2362
0
  if (ectx == NULL || sframe_encoder_get_version (ectx) == SFRAME_VERSION_1)
2363
0
    return sframe_set_errno (&err, SFRAME_ERR_INVAL);
2364
2365
0
  err = sframe_encoder_add_funcdesc_internal (ectx, start_pc_offset, func_size);
2366
0
  if (err)
2367
0
    return err;
2368
2369
0
  return 0;
2370
0
}
2371
2372
/* Add a new SFrame function descriptor entry with START_ADDR, FUNC_SIZE,
2373
   FUNC_INFO and REP_BLOCK_SIZE to the encoder context ECTX.  This API is valid
2374
   only for SFrame format version 2.  */
2375
2376
int
2377
sframe_encoder_add_funcdesc_v2 (sframe_encoder_ctx *ectx,
2378
        int32_t start_addr,
2379
        uint32_t func_size,
2380
        unsigned char func_info,
2381
        uint8_t rep_block_size,
2382
        uint32_t num_fres ATTRIBUTE_UNUSED)
2383
0
{
2384
0
  int err = 0;
2385
0
  if (ectx == NULL || sframe_encoder_get_version (ectx) == SFRAME_VERSION_1)
2386
0
    return sframe_set_errno (&err, SFRAME_ERR_INVAL);
2387
2388
0
  err = sframe_encoder_add_funcdesc_internal (ectx, start_addr, func_size);
2389
0
  if (err)
2390
0
    return err;
2391
2392
0
  sf_fde_tbl *fd_info = ectx->sfe_funcdesc;
2393
0
  fd_info->entry[fd_info->count-1].func_info = func_info;
2394
0
  fd_info->entry[fd_info->count-1].func_rep_size = rep_block_size;
2395
2396
0
  return 0;
2397
0
}
2398
2399
/* Add a new SFrame function descriptor entry with START_PC_OFFSET, FUNC_SIZE,
2400
   FUNC_INFO, FUNC_INFO2 and REP_BLOCK_SIZE to the encoder context ECTX.
2401
   Return error code on failure.  */
2402
2403
int
2404
sframe_encoder_add_funcdesc_v3 (sframe_encoder_ctx *ectx,
2405
        int64_t start_pc_offset,
2406
        uint32_t func_size,
2407
        unsigned char func_info,
2408
        unsigned char func_info2,
2409
        uint8_t rep_block_size,
2410
        uint32_t num_fres ATTRIBUTE_UNUSED)
2411
0
{
2412
0
  int err = 0;
2413
0
  if (ectx == NULL || sframe_encoder_get_version (ectx) != SFRAME_VERSION_3)
2414
0
    {
2415
0
      sframe_set_errno (&err, SFRAME_ERR_INVAL);
2416
0
      return err;
2417
0
    }
2418
2419
0
  err = sframe_encoder_add_funcdesc_internal (ectx, start_pc_offset,
2420
0
                func_size);
2421
0
  if (err)
2422
0
    return err;
2423
2424
0
  sf_fde_tbl *fd_info = ectx->sfe_funcdesc;
2425
0
  fd_info->entry[fd_info->count-1].func_info = func_info;
2426
0
  fd_info->entry[fd_info->count-1].func_info2 = func_info2;
2427
0
  fd_info->entry[fd_info->count-1].func_rep_size = rep_block_size;
2428
2429
0
  return 0;
2430
0
}
2431
2432
static int
2433
sframe_sort_funcdesc (sframe_encoder_ctx *ectx)
2434
0
{
2435
0
  sframe_header *ehp = sframe_encoder_get_header (ectx);
2436
2437
  /* Sort and write out the FDE table.  */
2438
0
  sf_fde_tbl *fd_info = ectx->sfe_funcdesc;
2439
0
  if (fd_info)
2440
0
    {
2441
      /* The new encoding of sfde_func_start_address means the distances are
2442
   not from the same anchor, so cannot be sorted directly.  At the moment
2443
   we adress this by manual value adjustments before and after sorting.
2444
   FIXME - qsort_r may be more optimal.  */
2445
2446
0
      for (unsigned int i = 0; i < fd_info->count; i++)
2447
0
  fd_info->entry[i].func_start_pc_offset
2448
0
    += sframe_encoder_get_offsetof_fde_start_addr (ectx, i, NULL);
2449
2450
0
      qsort (fd_info->entry, fd_info->count,
2451
0
       sizeof (sframe_func_desc_entry_int), fde_func);
2452
2453
0
      for (unsigned int i = 0; i < fd_info->count; i++)
2454
0
  fd_info->entry[i].func_start_pc_offset
2455
0
    -= sframe_encoder_get_offsetof_fde_start_addr (ectx, i, NULL);
2456
2457
      /* Update preamble's flags.  */
2458
0
      ehp->sfh_preamble.sfp_flags |= SFRAME_F_FDE_SORTED;
2459
0
    }
2460
0
  return 0;
2461
0
}
2462
2463
/* Write the SFrame FRE start address from the in-memory FRE_START_ADDR
2464
   to the buffer CONTENTS (on-disk format), given the FRE_TYPE and
2465
   FRE_START_ADDR_SZ.  */
2466
2467
static int
2468
sframe_encoder_write_fre_start_addr (char *contents,
2469
             uint32_t fre_start_addr,
2470
             uint32_t fre_type,
2471
             size_t fre_start_addr_sz)
2472
0
{
2473
0
  int err = 0;
2474
2475
0
  if (fre_type == SFRAME_FRE_TYPE_ADDR1)
2476
0
    {
2477
0
      uint8_t uc = fre_start_addr;
2478
0
      memcpy (contents, &uc, fre_start_addr_sz);
2479
0
    }
2480
0
  else if (fre_type == SFRAME_FRE_TYPE_ADDR2)
2481
0
    {
2482
0
      uint16_t ust = fre_start_addr;
2483
0
      memcpy (contents, &ust, fre_start_addr_sz);
2484
0
    }
2485
0
  else if (fre_type == SFRAME_FRE_TYPE_ADDR4)
2486
0
    {
2487
0
      uint32_t uit = fre_start_addr;
2488
0
      memcpy (contents, &uit, fre_start_addr_sz);
2489
0
    }
2490
0
  else
2491
0
    return sframe_set_errno (&err, SFRAME_ERR_INVAL);
2492
2493
0
  return 0;
2494
0
}
2495
2496
/* Write a frame row entry pointed to by FREP into the buffer CONTENTS.  The
2497
   size in bytes written out are updated in ESZ.
2498
2499
   This function works closely with the SFrame binary format.
2500
2501
   Returns SFRAME_ERR if failure.  */
2502
2503
static int
2504
sframe_encoder_write_fre (char *contents, sframe_frame_row_entry *frep,
2505
        uint32_t fre_type, size_t *esz)
2506
0
{
2507
0
  size_t fre_sz;
2508
0
  size_t fre_start_addr_sz;
2509
0
  size_t fre_datawords_sz;
2510
0
  int err = 0;
2511
2512
0
  if (!sframe_fre_sanity_check_p (frep))
2513
0
    return sframe_set_errno (&err, SFRAME_ERR_FRE_INVAL);
2514
2515
0
  fre_start_addr_sz = sframe_fre_start_addr_size (fre_type);
2516
0
  fre_datawords_sz = sframe_fre_datawords_bytes_size (frep->fre_info);
2517
2518
  /* The FRE start address must be encodable in the available number of
2519
     bytes.  */
2520
0
  uint64_t bitmask = SFRAME_BITMASK_OF_SIZE (fre_start_addr_sz);
2521
0
  sframe_assert ((uint64_t)frep->fre_start_addr <= bitmask);
2522
2523
0
  sframe_encoder_write_fre_start_addr (contents, frep->fre_start_addr,
2524
0
               fre_type, fre_start_addr_sz);
2525
0
  contents += fre_start_addr_sz;
2526
2527
0
  memcpy (contents, &frep->fre_info, sizeof (frep->fre_info));
2528
0
  contents += sizeof (frep->fre_info);
2529
2530
0
  memcpy (contents, frep->fre_datawords, fre_datawords_sz);
2531
0
  contents+= fre_datawords_sz;
2532
2533
0
  fre_sz = sframe_fre_entry_size (frep, fre_type);
2534
  /* Sanity checking.  */
2535
0
  sframe_assert ((fre_start_addr_sz
2536
0
      + sizeof (frep->fre_info)
2537
0
      + fre_datawords_sz) == fre_sz);
2538
2539
0
  *esz = fre_sz;
2540
2541
0
  return 0;
2542
0
}
2543
2544
/* Write an SFrame FDE Index element for SFrame V3 into the provided buffer at
2545
   CONTENTS.  Update FDE_WRITE_SIZE with the number of bytes written to the
2546
   buffer.  Return 0 on success, SFRAME_ERR otherwise.  */
2547
2548
static int
2549
sframe_encoder_write_fde_idx (const sframe_header *sfhp ATTRIBUTE_UNUSED,
2550
            char *contents,
2551
            const sframe_func_desc_entry_int *fde,
2552
            size_t *fde_write_size)
2553
0
{
2554
0
  sframe_func_desc_idx_v3 *fdep = (sframe_func_desc_idx_v3 *)contents;
2555
2556
0
  fdep->sfdi_func_start_offset = fde->func_start_pc_offset;
2557
0
  fdep->sfdi_func_size = fde->func_size;
2558
0
  fdep->sfdi_func_start_fre_off = fde->func_start_fre_off;
2559
2560
0
  *fde_write_size = sizeof (sframe_func_desc_idx_v3);
2561
2562
0
  return 0;
2563
0
}
2564
2565
/* Write the SFrame FDE Attribute element for SFrame V3 into the provided
2566
   buffer at CONTENTS.  Return 0 on success, SFRAME_ERR otherwise.  */
2567
2568
static int
2569
sframe_encoder_write_fde_attr (char *contents,
2570
             const sframe_func_desc_entry_int *fde)
2571
0
{
2572
0
  sframe_func_desc_attr_v3 *fattr = (sframe_func_desc_attr_v3 *)contents;
2573
2574
  /* Access to num_fres may be unaligned.  */
2575
0
  uint16_t num_fres = (uint16_t)fde->func_num_fres;
2576
0
  memcpy (fattr, &num_fres, sizeof (uint16_t));
2577
2578
0
  fattr->sfda_func_info = fde->func_info;
2579
0
  fattr->sfda_func_info2 = fde->func_info2;
2580
0
  fattr->sfda_func_rep_size = fde->func_rep_size;
2581
2582
0
  return 0;
2583
0
}
2584
/* Serialize the core contents of the SFrame section and write out to the
2585
   output buffer held in the encoder context ECTX.  Sort the SFrame FDEs on
2586
   start PC if SORT_FDE_P is true.  Return SFRAME_ERR if failure.  */
2587
2588
static int
2589
sframe_encoder_write_sframe (sframe_encoder_ctx *ectx, bool sort_fde_p)
2590
0
{
2591
0
  char *contents;
2592
0
  size_t buf_size;
2593
0
  size_t hdr_size;
2594
0
  size_t fde_write_size, all_fdes_size;
2595
0
  size_t fre_size;
2596
0
  size_t esz = 0;
2597
0
  sframe_header *ehp;
2598
0
  sf_fde_tbl *fd_info;
2599
0
  sf_fre_tbl *fr_info;
2600
0
  uint32_t i, num_fdes;
2601
0
  uint32_t j, num_fres;
2602
0
  sframe_func_desc_entry_int *fdep;
2603
0
  sframe_frame_row_entry *frep;
2604
2605
0
  uint32_t fre_type;
2606
0
  int err = 0;
2607
2608
0
  contents = ectx->sfe_data;
2609
0
  buf_size = ectx->sfe_data_size;
2610
0
  num_fdes = sframe_encoder_get_num_fidx (ectx);
2611
0
  all_fdes_size = num_fdes * sizeof (sframe_func_desc_idx_v3);
2612
0
  ehp = sframe_encoder_get_header (ectx);
2613
0
  hdr_size = sframe_get_hdr_size (ehp);
2614
2615
0
  fd_info = ectx->sfe_funcdesc;
2616
0
  fr_info = ectx->sfe_fres;
2617
2618
  /* Sanity checks:
2619
     - buffers must be malloc'd by the caller.  */
2620
0
  if ((contents == NULL) || (buf_size < hdr_size))
2621
0
    return sframe_set_errno (&err, SFRAME_ERR_BUF_INVAL);
2622
0
  if (ehp->sfh_num_fres > 0 && fr_info == NULL)
2623
0
    return sframe_set_errno (&err, SFRAME_ERR_FRE_INVAL);
2624
2625
  /* Write out the FRE table first.
2626
2627
     Recall that read/write of FREs needs information from the corresponding
2628
     FDE; the latter stores the information about the FRE type record used for
2629
     the function.  Also note that sorting of FDEs does NOT impact the order
2630
     in which FREs are stored in the SFrame's FRE sub-section.  This means
2631
     that writing out FREs after sorting of FDEs will need some additional
2632
     book-keeping.  At this time, we can afford to avoid it by writing out
2633
     the FREs first to the output buffer.  */
2634
0
  fre_size = 0;
2635
0
  uint32_t global = 0;
2636
0
  uint32_t fre_index = 0;
2637
2638
0
  contents += hdr_size + all_fdes_size;
2639
0
  for (i = 0; i < num_fdes; i++)
2640
0
    {
2641
0
      fdep = &fd_info->entry[i];
2642
0
      fre_type = sframe_get_fre_type (fdep);
2643
0
      num_fres = fdep->func_num_fres;
2644
2645
0
      if (num_fres > 0 && fr_info == NULL)
2646
0
  return sframe_set_errno (&err, SFRAME_ERR_FRE_INVAL);
2647
2648
0
      sframe_encoder_write_fde_attr (contents, fdep);
2649
0
      contents += sizeof (sframe_func_desc_attr_v3);
2650
0
      fre_size += sizeof (sframe_func_desc_attr_v3);
2651
2652
0
      for (j = 0; j < num_fres; j++)
2653
0
  {
2654
0
    fre_index = global + j;
2655
0
    frep = &fr_info->entry[fre_index];
2656
2657
0
    sframe_encoder_write_fre (contents, frep, fre_type, &esz);
2658
0
    contents += esz;
2659
0
    fre_size += esz; /* For debugging only.  */
2660
0
  }
2661
0
      global += j;
2662
0
    }
2663
2664
0
  sframe_assert (fre_size == ehp->sfh_fre_len);
2665
0
  sframe_assert (global == ehp->sfh_num_fres);
2666
0
  sframe_assert ((size_t)(contents - ectx->sfe_data) == buf_size);
2667
2668
  /* Sort the FDE table */
2669
0
  if (sort_fde_p)
2670
0
    sframe_sort_funcdesc (ectx);
2671
2672
  /* Sanity checks:
2673
     - the FDE section must have been sorted by now on the start address
2674
     of each function, if sorting was needed.  */
2675
0
  if ((sort_fde_p != (sframe_encoder_get_flags (ectx) & SFRAME_F_FDE_SORTED))
2676
0
      || (fd_info == NULL))
2677
0
    return sframe_set_errno (&err, SFRAME_ERR_FDE_INVAL);
2678
2679
0
  contents = ectx->sfe_data;
2680
  /* Write out the SFrame header.  The SFrame header in the encoder
2681
     object has already been updated with correct offsets by the caller.  */
2682
0
  memcpy (contents, ehp, hdr_size);
2683
0
  contents += hdr_size;
2684
2685
  /* Write out the FDE table sorted on funtion start address.  */
2686
0
  for (i = 0; i < num_fdes; i++)
2687
0
    {
2688
0
      sframe_encoder_write_fde_idx (ehp, contents, &fd_info->entry[i],
2689
0
            &fde_write_size);
2690
0
      contents += fde_write_size;
2691
0
    }
2692
2693
0
  return 0;
2694
0
}
2695
2696
/* Serialize the contents of the encoder context ECTX and return the buffer.
2697
   Sort the SFrame FDEs on start PC if SORT_FDE_P is true.  ENCODED_SIZE is
2698
   updated to the size of the buffer.  Sets ERRP if failure.  */
2699
2700
char *
2701
sframe_encoder_write (sframe_encoder_ctx *ectx, size_t *encoded_size,
2702
          bool sort_fde_p, int *errp)
2703
0
{
2704
0
  sframe_header *ehp;
2705
0
  size_t hdrsize, fsz, fresz, bufsize;
2706
0
  int foreign_endian;
2707
2708
  /* Initialize the encoded_size to zero.  This makes it simpler to just
2709
     return from the function in case of failure.  Free'ing up of
2710
     ectx->sfe_data is the responsibility of the caller.  */
2711
0
  *encoded_size = 0;
2712
2713
0
  if (ectx == NULL || encoded_size == NULL || errp == NULL)
2714
0
    return sframe_ret_set_errno (errp, SFRAME_ERR_INVAL);
2715
2716
0
  ehp = sframe_encoder_get_header (ectx);
2717
0
  hdrsize = sframe_get_hdr_size (ehp);
2718
0
  fsz = sframe_encoder_get_num_fidx (ectx) * sizeof (sframe_func_desc_idx_v3);
2719
0
  fresz = ectx->sfe_fre_nbytes;
2720
2721
  /* Encoder writes out data in the latest SFrame format version.  */
2722
0
  if (sframe_encoder_get_version (ectx) != SFRAME_VERSION)
2723
0
    return sframe_ret_set_errno (errp, SFRAME_ERR_VERSION_INVAL);
2724
2725
  /* The total size of buffer is the sum of header, SFrame Function Descriptor
2726
     Entries section and the FRE section.  */
2727
0
  bufsize = hdrsize + fsz + fresz;
2728
0
  ectx->sfe_data = (char *) malloc (bufsize);
2729
0
  if (ectx->sfe_data == NULL)
2730
0
    return sframe_ret_set_errno (errp, SFRAME_ERR_NOMEM);
2731
0
  ectx->sfe_data_size = bufsize;
2732
2733
  /* Update the information in the SFrame header.  */
2734
  /* SFrame FDE section follows immediately after the header.  */
2735
0
  ehp->sfh_fdeoff = 0;
2736
  /* SFrame FRE section follows immediately after the SFrame FDE section.  */
2737
0
  ehp->sfh_freoff = fsz;
2738
0
  ehp->sfh_fre_len = fresz;
2739
2740
0
  foreign_endian = need_swapping (ehp->sfh_abi_arch);
2741
2742
  /* Write out the FDE Index and the FRE table in the sfe_data. */
2743
0
  if (sframe_encoder_write_sframe (ectx, sort_fde_p))
2744
0
    return sframe_ret_set_errno (errp, SFRAME_ERR_BUF_INVAL);
2745
2746
  /* Endian flip the contents if necessary.  */
2747
0
  if (foreign_endian)
2748
0
    {
2749
0
      if (flip_sframe (ectx->sfe_data, bufsize, 1))
2750
0
  return sframe_ret_set_errno (errp, SFRAME_ERR_BUF_INVAL);
2751
0
      if (flip_header (ectx->sfe_data, SFRAME_VERSION))
2752
0
  return sframe_ret_set_errno (errp, SFRAME_ERR_BUF_INVAL);
2753
0
    }
2754
2755
0
  *encoded_size = bufsize;
2756
0
  return ectx->sfe_data;
2757
0
}