Coverage Report

Created: 2025-06-24 06:45

/src/binutils-gdb/gas/gen-sframe.c
Line
Count
Source (jump to first uncovered line)
1
/* gen-sframe.c - Support for generating SFrame section.
2
   Copyright (C) 2022-2025 Free Software Foundation, Inc.
3
4
   This file is part of GAS, the GNU Assembler.
5
6
   GAS is free software; you can redistribute it and/or modify
7
   it under the terms of the GNU General Public License as published by
8
   the Free Software Foundation; either version 3, or (at your option)
9
   any later version.
10
11
   GAS is distributed in the hope that it will be useful,
12
   but WITHOUT ANY WARRANTY; without even the implied warranty of
13
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
   GNU General Public License for more details.
15
16
   You should have received a copy of the GNU General Public License
17
   along with GAS; see the file COPYING.  If not, write to the Free
18
   Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA
19
   02110-1301, USA.  */
20
21
#include "as.h"
22
#include "subsegs.h"
23
#include "sframe.h"
24
#include "gen-sframe.h"
25
#include "dw2gencfi.h"
26
27
#ifdef support_sframe_p
28
29
#ifndef sizeof_member
30
6
# define sizeof_member(type, member)  (sizeof (((type *)0)->member))
31
#endif
32
33
/* SFrame FRE type selection optimization is an optimization for size.
34
35
   There are three flavors of SFrame FRE representation in the binary format:
36
     - sframe_frame_row_entry_addr1 where the FRE start address is 1 byte.
37
     - sframe_frame_row_entry_addr2 where the FRE start address is 2 bytes.
38
     - sframe_frame_row_entry_addr4 where the FRE start address is 4 bytes.
39
40
   Note that in the SFrame format, all SFrame FREs of a function use one
41
   single representation.  The SFrame FRE type itself is identified via the
42
   information in the SFrame FDE function info.
43
44
   Now, to select the minimum required one from the list above, one needs to
45
   make a decision based on the size (in bytes) of the function.
46
47
   As a result, for this optimization, some fragments (generated with a new
48
   type rs_sframe) for the SFrame section are fixed up later.
49
50
   This optimization (for size) is enabled by default.  */
51
52
#ifndef SFRAME_FRE_TYPE_SELECTION_OPT
53
# define SFRAME_FRE_TYPE_SELECTION_OPT 1
54
#endif
55
56
/* List of SFrame FDE entries.  */
57
58
static struct sframe_func_entry *all_sframe_fdes = NULL;
59
60
/* Tail of the list to add to.  */
61
62
static struct sframe_func_entry **last_sframe_fde = &all_sframe_fdes;
63
64
/* Emit a single byte into the current segment.  */
65
66
static inline void
67
out_one (int byte)
68
9
{
69
9
  FRAG_APPEND_1_CHAR (byte);
70
9
}
71
72
/* Emit a two-byte word into the current segment.  */
73
74
static inline void
75
out_two (int data)
76
2
{
77
2
  md_number_to_chars (frag_more (2), data, 2);
78
2
}
79
80
/* Emit a four byte word into the current segment.  */
81
82
static inline void
83
out_four (int data)
84
3
{
85
3
  md_number_to_chars (frag_more (4), data, 4);
86
3
}
87
88
/* Get the start address symbol from the DWARF FDE.  */
89
90
static symbolS*
91
get_dw_fde_start_addrS (const struct fde_entry *dw_fde)
92
6
{
93
6
  return dw_fde->start_address;
94
6
}
95
96
/* Get the start address symbol from the DWARF FDE.  */
97
98
static symbolS*
99
get_dw_fde_end_addrS (const struct fde_entry *dw_fde)
100
3
{
101
3
  return dw_fde->end_address;
102
3
}
103
104
/* Get whether PAUTH B key is used.  */
105
static bool
106
get_dw_fde_pauth_b_key_p (const struct fde_entry *dw_fde ATTRIBUTE_UNUSED)
107
1
{
108
#ifdef tc_fde_entry_extras
109
  return (dw_fde->pauth_key == AARCH64_PAUTH_KEY_B);
110
#else
111
1
  return false;
112
1
#endif
113
1
}
114
115
/* SFrame Frame Row Entry (FRE) related functions.  */
116
117
static void
118
sframe_fre_set_begin_addr (struct sframe_row_entry *fre, symbolS *beginS)
119
8
{
120
8
  fre->pc_begin = beginS;
121
8
}
122
123
static void
124
sframe_fre_set_end_addr (struct sframe_row_entry *fre, symbolS *endS)
125
4
{
126
4
  fre->pc_end = endS;
127
4
}
128
129
static void
130
sframe_fre_set_cfa_base_reg (struct sframe_row_entry *fre,
131
           unsigned int cfa_base_reg)
132
4
{
133
4
  fre->cfa_base_reg = cfa_base_reg;
134
4
  fre->merge_candidate = false;
135
4
}
136
137
static void
138
sframe_fre_set_cfa_offset (struct sframe_row_entry *fre,
139
         offsetT cfa_offset)
140
4
{
141
4
  fre->cfa_offset = cfa_offset;
142
4
  fre->merge_candidate = false;
143
4
}
144
145
static void
146
sframe_fre_set_ra_track (struct sframe_row_entry *fre, offsetT ra_offset)
147
0
{
148
0
  fre->ra_loc = SFRAME_FRE_ELEM_LOC_STACK;
149
0
  fre->ra_offset = ra_offset;
150
0
  fre->merge_candidate = false;
151
0
}
152
153
static void
154
sframe_fre_set_bp_track (struct sframe_row_entry *fre, offsetT bp_offset)
155
0
{
156
0
  fre->bp_loc = SFRAME_FRE_ELEM_LOC_STACK;
157
0
  fre->bp_offset = bp_offset;
158
0
  fre->merge_candidate = false;
159
0
}
160
161
/* All stack offset values within an FRE are uniformly encoded in the same
162
   number of bytes.  The size of the stack offset values will, however, vary
163
   across FREs.  */
164
165
3
#define VALUE_8BIT  0x7f
166
0
#define VALUE_16BIT 0x7fff
167
0
#define VALUE_32BIT 0x7fffffff
168
0
#define VALUE_64BIT 0x7fffffffffffffff
169
170
/* Given a signed offset, return the size in bytes needed to represent it.  */
171
172
static unsigned int
173
get_offset_size_in_bytes (offsetT value)
174
1
{
175
1
  unsigned int size = 0;
176
177
1
  if (value <= VALUE_8BIT && value >= (offsetT) -VALUE_8BIT)
178
1
    size = 1;
179
0
  else if (value <= VALUE_16BIT && value >= (offsetT) -VALUE_16BIT)
180
0
    size = 2;
181
0
  else if (value <= VALUE_32BIT && value >= (offsetT) -VALUE_32BIT)
182
0
    size = 4;
183
0
  else if ((sizeof (offsetT) > 4) && (value <= (offsetT) VALUE_64BIT
184
0
              && value >= (offsetT) -VALUE_64BIT))
185
0
    size = 8;
186
187
1
  return size;
188
1
}
189
190
1
#define SFRAME_FRE_OFFSET_FUNC_MAP_INDEX_1B  0 /* SFRAME_FRE_OFFSET_1B.  */
191
0
#define SFRAME_FRE_OFFSET_FUNC_MAP_INDEX_2B  1 /* SFRAME_FRE_OFFSET_2B.  */
192
0
#define SFRAME_FRE_OFFSET_FUNC_MAP_INDEX_4B  2 /* SFRAME_FRE_OFFSET_4B.  */
193
1
#define SFRAME_FRE_OFFSET_FUNC_MAP_INDEX_8B  3 /* Not supported in SFrame.  */
194
1
#define SFRAME_FRE_OFFSET_FUNC_MAP_INDEX_MAX SFRAME_FRE_OFFSET_FUNC_MAP_INDEX_8B
195
196
/* Helper struct for mapping offset size to output functions.  */
197
198
struct sframe_fre_offset_func_map
199
{
200
  unsigned int offset_size;
201
  void (*out_func)(int);
202
};
203
204
/* Given an OFFSET_SIZE, return the size in bytes needed to represent it.  */
205
206
static unsigned int
207
sframe_fre_offset_func_map_index (unsigned int offset_size)
208
1
{
209
1
  unsigned int idx = SFRAME_FRE_OFFSET_FUNC_MAP_INDEX_MAX;
210
211
1
  switch (offset_size)
212
1
    {
213
1
      case SFRAME_FRE_OFFSET_1B:
214
1
  idx = SFRAME_FRE_OFFSET_FUNC_MAP_INDEX_1B;
215
1
  break;
216
0
      case SFRAME_FRE_OFFSET_2B:
217
0
  idx = SFRAME_FRE_OFFSET_FUNC_MAP_INDEX_2B;
218
0
  break;
219
0
      case SFRAME_FRE_OFFSET_4B:
220
0
  idx = SFRAME_FRE_OFFSET_FUNC_MAP_INDEX_4B;
221
0
  break;
222
0
      default:
223
  /* Not supported in SFrame.  */
224
0
  break;
225
1
    }
226
227
1
  return idx;
228
1
}
229
230
/* Mapping from offset size to the output function to emit the value.  */
231
232
static const
233
struct sframe_fre_offset_func_map
234
fre_offset_func_map[SFRAME_FRE_OFFSET_FUNC_MAP_INDEX_MAX+1] =
235
{
236
  { SFRAME_FRE_OFFSET_1B, out_one },
237
  { SFRAME_FRE_OFFSET_2B, out_two },
238
  { SFRAME_FRE_OFFSET_4B, out_four },
239
  { -1, NULL } /* Not Supported in SFrame.  */
240
};
241
242
/* SFrame version specific operations access.  */
243
244
static struct sframe_version_ops sframe_ver_ops;
245
246
/* SFrame (SFRAME_VERSION_1) set FRE info.  */
247
248
static unsigned char
249
sframe_v1_set_fre_info (unsigned int base_reg, unsigned int num_offsets,
250
      unsigned int offset_size, bool mangled_ra_p)
251
1
{
252
1
  unsigned char fre_info;
253
1
  fre_info = SFRAME_V1_FRE_INFO (base_reg, num_offsets, offset_size);
254
1
  fre_info = SFRAME_V1_FRE_INFO_UPDATE_MANGLED_RA_P (mangled_ra_p, fre_info);
255
1
  return fre_info;
256
1
}
257
258
/* SFrame (SFRAME_VERSION_1) set function info.  */
259
static unsigned char
260
sframe_v1_set_func_info (unsigned int fde_type, unsigned int fre_type,
261
       unsigned int pauth_key)
262
1
{
263
1
  unsigned char func_info;
264
1
  func_info = SFRAME_V1_FUNC_INFO (fde_type, fre_type);
265
1
  func_info = SFRAME_V1_FUNC_INFO_UPDATE_PAUTH_KEY (pauth_key, func_info);
266
1
  return func_info;
267
1
}
268
269
/* SFrame version specific operations setup.  */
270
271
static void
272
sframe_set_version (uint32_t sframe_version ATTRIBUTE_UNUSED)
273
1
{
274
1
  sframe_ver_ops.format_version = SFRAME_VERSION_2;
275
276
  /* These operations remain the same for SFRAME_VERSION_2 as fre_info and
277
     func_info have not changed from SFRAME_VERSION_1.  */
278
279
1
  sframe_ver_ops.set_fre_info = sframe_v1_set_fre_info;
280
281
1
  sframe_ver_ops.set_func_info = sframe_v1_set_func_info;
282
1
}
283
284
/* SFrame set FRE info.  */
285
286
static unsigned char
287
sframe_set_fre_info (unsigned int base_reg, unsigned int num_offsets,
288
         unsigned int offset_size, bool mangled_ra_p)
289
1
{
290
1
  return sframe_ver_ops.set_fre_info (base_reg, num_offsets,
291
1
              offset_size, mangled_ra_p);
292
1
}
293
294
/* SFrame set func info. */
295
296
static unsigned char
297
sframe_set_func_info (unsigned int fde_type, unsigned int fre_type,
298
          unsigned int pauth_key)
299
1
{
300
1
  return sframe_ver_ops.set_func_info (fde_type, fre_type, pauth_key);
301
1
}
302
303
/* Get the number of SFrame FDEs for the current file.  */
304
305
static unsigned int
306
get_num_sframe_fdes (void);
307
308
/* Get the number of SFrame frame row entries for the current file.  */
309
310
static unsigned int
311
get_num_sframe_fres (void);
312
313
/* Get CFA base register ID as represented in SFrame Frame Row Entry.  */
314
315
static unsigned int
316
get_fre_base_reg_id (struct sframe_row_entry *sframe_fre)
317
1
{
318
1
  unsigned int cfi_insn_cfa_base_reg = sframe_fre->cfa_base_reg;
319
1
  unsigned fre_base_reg = SFRAME_BASE_REG_SP;
320
321
1
  if (cfi_insn_cfa_base_reg == SFRAME_CFA_FP_REG)
322
0
    fre_base_reg = SFRAME_BASE_REG_FP;
323
324
  /* Only one bit is reserved in SFRAME_VERSION_1.  */
325
1
  gas_assert (fre_base_reg == SFRAME_BASE_REG_SP
326
1
        || fre_base_reg == SFRAME_BASE_REG_FP);
327
328
1
  return fre_base_reg;
329
1
}
330
331
/* Get number of offsets necessary for the SFrame Frame Row Entry.  */
332
333
static unsigned int
334
get_fre_num_offsets (struct sframe_row_entry *sframe_fre)
335
1
{
336
  /* Atleast 1 must always be present (to recover CFA).  */
337
1
  unsigned int fre_num_offsets = 1;
338
339
1
  if (sframe_fre->bp_loc == SFRAME_FRE_ELEM_LOC_STACK)
340
0
    fre_num_offsets++;
341
1
  if (sframe_ra_tracking_p ()
342
1
      && sframe_fre->ra_loc == SFRAME_FRE_ELEM_LOC_STACK)
343
0
    fre_num_offsets++;
344
1
  return fre_num_offsets;
345
1
}
346
347
/* Get the minimum necessary offset size (in bytes) for this
348
   SFrame frame row entry.  */
349
350
static unsigned int
351
sframe_get_fre_offset_size (struct sframe_row_entry *sframe_fre)
352
1
{
353
1
  unsigned int max_offset_size = 0;
354
1
  unsigned int cfa_offset_size = 0;
355
1
  unsigned int bp_offset_size = 0;
356
1
  unsigned int ra_offset_size = 0;
357
358
1
  unsigned int fre_offset_size = 0;
359
360
  /* What size of offsets appear in this frame row entry.  */
361
1
  cfa_offset_size = get_offset_size_in_bytes (sframe_fre->cfa_offset);
362
1
  if (sframe_fre->bp_loc == SFRAME_FRE_ELEM_LOC_STACK)
363
0
    bp_offset_size = get_offset_size_in_bytes (sframe_fre->bp_offset);
364
1
  if (sframe_ra_tracking_p ()
365
1
      && sframe_fre->ra_loc == SFRAME_FRE_ELEM_LOC_STACK)
366
0
    ra_offset_size = get_offset_size_in_bytes (sframe_fre->ra_offset);
367
368
  /* Get the maximum size needed to represent the offsets.  */
369
1
  max_offset_size = cfa_offset_size;
370
1
  if (bp_offset_size > max_offset_size)
371
0
    max_offset_size = bp_offset_size;
372
1
  if (ra_offset_size > max_offset_size)
373
0
    max_offset_size = ra_offset_size;
374
375
1
  gas_assert (max_offset_size);
376
377
1
  switch (max_offset_size)
378
1
    {
379
1
    case 1:
380
1
      fre_offset_size = SFRAME_FRE_OFFSET_1B;
381
1
      break;
382
0
    case 2:
383
0
      fre_offset_size = SFRAME_FRE_OFFSET_2B;
384
0
      break;
385
0
    case 4:
386
0
      fre_offset_size = SFRAME_FRE_OFFSET_4B;
387
0
      break;
388
0
    default:
389
      /* Offset of size 8 bytes is not supported in SFrame format
390
   version 1.  */
391
0
      as_fatal (_("SFrame unsupported offset value\n"));
392
0
      break;
393
1
    }
394
395
1
  return fre_offset_size;
396
1
}
397
398
#if SFRAME_FRE_TYPE_SELECTION_OPT
399
400
/* Create a composite expression CEXP (for SFrame FRE start address) such that:
401
402
      exp = <val> OP_absent <width>, where,
403
404
    - <val> and <width> are themselves expressionS.
405
    - <val> stores the expression which when evaluated gives the value of the
406
      start address offset of the FRE.
407
    - <width> stores the expression when evaluated gives the number of bytes
408
      needed to encode the start address offset of the FRE.
409
410
   The use of OP_absent as the X_op_symbol helps identify this expression
411
   later when fragments are fixed up.  */
412
413
static void
414
create_fre_start_addr_exp (expressionS *cexp, symbolS *fre_pc_begin,
415
         symbolS *fde_start_address,
416
         symbolS *fde_end_address)
417
1
{
418
1
  expressionS val;
419
1
  expressionS width;
420
421
  /* val expression stores the FDE start address offset from the start PC
422
     of function.  */
423
1
  val.X_op = O_subtract;
424
1
  val.X_add_symbol = fre_pc_begin;
425
1
  val.X_op_symbol = fde_start_address;
426
1
  val.X_add_number = 0;
427
428
  /* width expressions stores the size of the function.  This is used later
429
     to determine the number of bytes to be used to encode the FRE start
430
     address of each FRE of the function.  */
431
1
  width.X_op = O_subtract;
432
1
  width.X_add_symbol = fde_end_address;
433
1
  width.X_op_symbol = fde_start_address;
434
1
  width.X_add_number = 0;
435
436
1
  cexp->X_op = O_absent;
437
1
  cexp->X_add_symbol = make_expr_symbol (&val);
438
1
  cexp->X_op_symbol = make_expr_symbol (&width);
439
1
  cexp->X_add_number = 0;
440
1
}
441
442
/* Create a composite expression CEXP (for SFrame FDE function info) such that:
443
444
      exp = <rest_of_func_info> OP_modulus <width>, where,
445
446
    - <rest_of_func_info> and <width> are themselves expressionS.
447
    - <rest_of_func_info> stores a constant expression where X_add_number is
448
    used to stash away the func_info.  The upper 4-bits of the func_info are copied
449
    back to the resulting byte by the fragment fixup logic.
450
    - <width> stores the expression when evaluated gives the size of the
451
    function in number of bytes.
452
453
   The use of OP_modulus as the X_op_symbol helps identify this expression
454
   later when fragments are fixed up.  */
455
456
static void
457
create_func_info_exp (expressionS *cexp, symbolS *dw_fde_end_addrS,
458
          symbolS *dw_fde_start_addrS, uint8_t func_info)
459
1
{
460
1
  expressionS width;
461
1
  expressionS rest_of_func_info;
462
463
1
  width.X_op = O_subtract;
464
1
  width.X_add_symbol = dw_fde_end_addrS;
465
1
  width.X_op_symbol = dw_fde_start_addrS;
466
1
  width.X_add_number = 0;
467
468
1
  rest_of_func_info.X_op = O_constant;
469
1
  rest_of_func_info.X_add_number = func_info;
470
471
1
  cexp->X_op = O_modulus;
472
1
  cexp->X_add_symbol = make_expr_symbol (&rest_of_func_info);
473
1
  cexp->X_op_symbol = make_expr_symbol (&width);
474
1
  cexp->X_add_number = 0;
475
1
}
476
477
#endif
478
479
static struct sframe_row_entry*
480
sframe_row_entry_new (void)
481
7
{
482
7
  struct sframe_row_entry *fre = XCNEW (struct sframe_row_entry);
483
  /* Reset cfa_base_reg to -1.  A value of 0 will imply some valid register
484
     for the supported arches.  */
485
7
  fre->cfa_base_reg = SFRAME_FRE_BASE_REG_INVAL;
486
7
  fre->merge_candidate = true;
487
  /* Reset the mangled RA status bit to zero by default.  We will
488
     initialize it in sframe_row_entry_initialize () with the sticky
489
     bit if set.  */
490
7
  fre->mangled_ra_p = false;
491
492
7
  return fre;
493
7
}
494
495
static void
496
sframe_row_entry_free (struct sframe_row_entry *fre)
497
7
{
498
11
  while (fre)
499
4
    {
500
4
      struct sframe_row_entry *fre_next = fre->next;
501
4
      XDELETE (fre);
502
4
      fre = fre_next;
503
4
    }
504
7
}
505
506
/* Allocate an SFrame FDE.  */
507
508
static struct sframe_func_entry*
509
sframe_fde_alloc (void)
510
4
{
511
4
  return XCNEW (struct sframe_func_entry);
512
4
}
513
514
/* Free up the SFrame FDE.  */
515
516
static void
517
sframe_fde_free (struct sframe_func_entry *sframe_fde)
518
4
{
519
4
  sframe_row_entry_free (sframe_fde->sframe_fres);
520
4
  XDELETE (sframe_fde);
521
4
}
522
523
static void
524
output_sframe_row_entry (symbolS *fde_start_addr,
525
       symbolS *fde_end_addr,
526
       struct sframe_row_entry *sframe_fre)
527
1
{
528
1
  unsigned char fre_info;
529
1
  unsigned int fre_num_offsets;
530
1
  unsigned int fre_offset_size;
531
1
  unsigned int fre_base_reg;
532
1
  expressionS exp;
533
1
  unsigned int fre_addr_size;
534
535
1
  unsigned int idx = 0;
536
1
  unsigned int fre_write_offsets = 0;
537
538
1
  fre_addr_size = 4; /* 4 bytes by default.   FIXME tie it to fre_type? */
539
540
  /* SFrame FRE Start Address.  */
541
1
#if SFRAME_FRE_TYPE_SELECTION_OPT
542
1
  create_fre_start_addr_exp (&exp, sframe_fre->pc_begin, fde_start_addr,
543
1
           fde_end_addr);
544
1
  frag_grow (fre_addr_size);
545
1
  frag_var (rs_sframe, fre_addr_size, 0, (relax_substateT) 0,
546
1
      make_expr_symbol (&exp), 0, (char *) frag_now);
547
#else
548
  gas_assert (fde_end_addr);
549
  exp.X_op = O_subtract;
550
  exp.X_add_symbol = sframe_fre->pc_begin; /* to.  */
551
  exp.X_op_symbol = fde_start_addr; /* from.  */
552
  exp.X_add_number = 0;
553
  emit_expr (&exp, fre_addr_size);
554
#endif
555
556
  /* Create the fre_info using the CFA base register, number of offsets and max
557
     size of offset in this frame row entry.  */
558
1
  fre_base_reg = get_fre_base_reg_id (sframe_fre);
559
1
  fre_num_offsets = get_fre_num_offsets (sframe_fre);
560
1
  fre_offset_size = sframe_get_fre_offset_size (sframe_fre);
561
1
  fre_info = sframe_set_fre_info (fre_base_reg, fre_num_offsets,
562
1
          fre_offset_size, sframe_fre->mangled_ra_p);
563
1
  out_one (fre_info);
564
565
1
  idx = sframe_fre_offset_func_map_index (fre_offset_size);
566
1
  gas_assert (idx < SFRAME_FRE_OFFSET_FUNC_MAP_INDEX_MAX);
567
568
  /* Write out the offsets in order - cfa, bp, ra.  */
569
1
  fre_offset_func_map[idx].out_func (sframe_fre->cfa_offset);
570
1
  fre_write_offsets++;
571
572
1
  if (sframe_ra_tracking_p ()
573
1
      && sframe_fre->ra_loc == SFRAME_FRE_ELEM_LOC_STACK)
574
0
    {
575
0
      fre_offset_func_map[idx].out_func (sframe_fre->ra_offset);
576
0
      fre_write_offsets++;
577
0
    }
578
1
  if (sframe_fre->bp_loc == SFRAME_FRE_ELEM_LOC_STACK)
579
0
    {
580
0
      fre_offset_func_map[idx].out_func (sframe_fre->bp_offset);
581
0
      fre_write_offsets++;
582
0
    }
583
584
  /* Check if the expected number offsets have been written out
585
     in this FRE.  */
586
1
  gas_assert (fre_write_offsets == fre_num_offsets);
587
1
}
588
589
static void
590
output_sframe_funcdesc (symbolS *start_of_fre_section,
591
      symbolS *fre_symbol,
592
      struct sframe_func_entry *sframe_fde)
593
1
{
594
1
  expressionS exp;
595
1
  symbolS *dw_fde_start_addrS, *dw_fde_end_addrS;
596
1
  unsigned int pauth_key;
597
598
1
  dw_fde_start_addrS = get_dw_fde_start_addrS (sframe_fde->dw_fde);
599
1
  dw_fde_end_addrS = get_dw_fde_end_addrS (sframe_fde->dw_fde);
600
601
  /* Start address of the function.  */
602
1
  exp.X_op = O_subtract;
603
1
  exp.X_add_symbol = dw_fde_start_addrS; /* to location.  */
604
1
  exp.X_op_symbol = symbol_temp_new_now (); /* from location.  */
605
1
  exp.X_add_number = 0;
606
1
  emit_expr (&exp, sizeof_member (sframe_func_desc_entry,
607
1
          sfde_func_start_address));
608
609
  /* Size of the function in bytes.  */
610
1
  exp.X_op = O_subtract;
611
1
  exp.X_add_symbol = dw_fde_end_addrS;
612
1
  exp.X_op_symbol = dw_fde_start_addrS;
613
1
  exp.X_add_number = 0;
614
1
  emit_expr (&exp, sizeof_member (sframe_func_desc_entry,
615
1
          sfde_func_size));
616
617
  /* Offset to the first frame row entry.  */
618
1
  exp.X_op = O_subtract;
619
1
  exp.X_add_symbol = fre_symbol; /* Minuend.  */
620
1
  exp.X_op_symbol = start_of_fre_section; /* Subtrahend.  */
621
1
  exp.X_add_number = 0;
622
1
  emit_expr (&exp, sizeof_member (sframe_func_desc_entry,
623
1
          sfde_func_start_fre_off));
624
625
  /* Number of FREs.  */
626
1
  out_four (sframe_fde->num_fres);
627
628
  /* SFrame FDE function info.  */
629
1
  unsigned char func_info;
630
1
  pauth_key = (get_dw_fde_pauth_b_key_p (sframe_fde->dw_fde)
631
1
         ? SFRAME_AARCH64_PAUTH_KEY_B : SFRAME_AARCH64_PAUTH_KEY_A);
632
1
  func_info = sframe_set_func_info (SFRAME_FDE_TYPE_PCINC,
633
1
            SFRAME_FRE_TYPE_ADDR4,
634
1
            pauth_key);
635
1
#if SFRAME_FRE_TYPE_SELECTION_OPT
636
1
  expressionS cexp;
637
1
  create_func_info_exp (&cexp, dw_fde_end_addrS, dw_fde_start_addrS,
638
1
      func_info);
639
1
  frag_grow (1); /* Size of func info is unsigned char.  */
640
1
  frag_var (rs_sframe, 1, 0, (relax_substateT) 0,
641
1
      make_expr_symbol (&cexp), 0, (char *) frag_now);
642
#else
643
  out_one (func_info);
644
#endif
645
1
  out_one (0);
646
1
  out_two (0);
647
1
}
648
649
static void
650
output_sframe_internal (void)
651
1
{
652
1
  expressionS exp;
653
1
  unsigned int i = 0;
654
655
1
  symbolS *end_of_frame_hdr;
656
1
  symbolS *end_of_frame_section;
657
1
  symbolS *start_of_func_desc_section;
658
1
  symbolS *start_of_fre_section;
659
1
  struct sframe_func_entry *sframe_fde, *sframe_fde_next;
660
1
  struct sframe_row_entry *sframe_fre;
661
1
  unsigned char abi_arch = 0;
662
1
  int fixed_fp_offset = SFRAME_CFA_FIXED_FP_INVALID;
663
1
  int fixed_ra_offset = SFRAME_CFA_FIXED_RA_INVALID;
664
665
  /* The function descriptor entries as dumped by the assembler are not
666
     sorted on PCs.  */
667
1
  unsigned char sframe_flags = 0;
668
669
1
  unsigned int num_fdes = get_num_sframe_fdes ();
670
1
  unsigned int num_fres = get_num_sframe_fres ();
671
1
  symbolS **fde_fre_symbols = XNEWVEC (symbolS *, num_fdes);
672
2
  for (i = 0; i < num_fdes; i++)
673
1
    fde_fre_symbols[i] = symbol_temp_make ();
674
675
1
  end_of_frame_hdr = symbol_temp_make ();
676
1
  start_of_fre_section = symbol_temp_make ();
677
1
  start_of_func_desc_section = symbol_temp_make ();
678
1
  end_of_frame_section = symbol_temp_make ();
679
680
  /* Output the preamble of SFrame section.  */
681
1
  out_two (SFRAME_MAGIC);
682
1
  out_one (SFRAME_VERSION);
683
1
  out_one (sframe_flags);
684
  /* abi/arch.  */
685
1
#ifdef sframe_get_abi_arch
686
1
  abi_arch = sframe_get_abi_arch ();
687
1
#endif
688
1
  gas_assert (abi_arch);
689
1
  out_one (abi_arch);
690
691
  /* Offset for the FP register from CFA.  Neither of the AMD64 or AAPCS64
692
     ABIs have a fixed offset for the FP register from the CFA.  This may be
693
     useful in future (but not without additional support in the toolchain)
694
     for specialized handling/encoding for cases where, for example,
695
     -fno-omit-frame-pointer is used.  */
696
1
  out_one (fixed_fp_offset);
697
698
  /* All ABIs participating in SFrame generation must define
699
     sframe_ra_tracking_p.
700
     When RA tracking (in FREs) is not needed (e.g., AMD64), SFrame assumes
701
     the RA is going to be at a fixed offset from CFA.  Check that the fixed RA
702
     offset is appropriately defined in all cases.  */
703
1
  if (!sframe_ra_tracking_p ())
704
1
    {
705
1
      fixed_ra_offset = sframe_cfa_ra_offset ();
706
1
      gas_assert (fixed_ra_offset != SFRAME_CFA_FIXED_RA_INVALID);
707
1
    }
708
1
  out_one (fixed_ra_offset);
709
710
  /* None of the AMD64, or AARCH64 ABIs need the auxiliary header.
711
     When the need does arise to use this field, the appropriate backend
712
     must provide this information.  */
713
1
  out_one (0); /* Auxiliary SFrame header length.  */
714
715
1
  out_four (num_fdes); /* Number of FDEs.  */
716
1
  out_four (num_fres); /* Number of FREs.  */
717
718
  /* Size of FRE sub-section.  */
719
1
  exp.X_op = O_subtract;
720
1
  exp.X_add_symbol = end_of_frame_section;
721
1
  exp.X_op_symbol = start_of_fre_section;
722
1
  exp.X_add_number = 0;
723
1
  emit_expr (&exp, sizeof_member (sframe_header, sfh_fre_len));
724
725
  /* Offset of FDE sub-section.  */
726
1
  exp.X_op = O_subtract;
727
1
  exp.X_add_symbol = end_of_frame_hdr;
728
1
  exp.X_op_symbol = start_of_func_desc_section;
729
1
  exp.X_add_number = 0;
730
1
  emit_expr (&exp, sizeof_member (sframe_header, sfh_fdeoff));
731
732
  /* Offset of FRE sub-section.  */
733
1
  exp.X_op = O_subtract;
734
1
  exp.X_add_symbol = start_of_fre_section;
735
1
  exp.X_op_symbol = end_of_frame_hdr;
736
1
  exp.X_add_number = 0;
737
1
  emit_expr (&exp, sizeof_member (sframe_header, sfh_freoff));
738
739
1
  symbol_set_value_now (end_of_frame_hdr);
740
1
  symbol_set_value_now (start_of_func_desc_section);
741
742
  /* Output the SFrame function descriptor entries.  */
743
1
  i = 0;
744
2
  for (sframe_fde = all_sframe_fdes; sframe_fde; sframe_fde = sframe_fde->next)
745
1
    {
746
1
      output_sframe_funcdesc (start_of_fre_section,
747
1
            fde_fre_symbols[i], sframe_fde);
748
1
      i++;
749
1
    }
750
751
1
  symbol_set_value_now (start_of_fre_section);
752
753
  /* Output the SFrame FREs.  */
754
1
  i = 0;
755
1
  sframe_fde = all_sframe_fdes;
756
757
2
  for (sframe_fde = all_sframe_fdes; sframe_fde; sframe_fde = sframe_fde_next)
758
1
    {
759
1
      symbol_set_value_now (fde_fre_symbols[i]);
760
1
      for (sframe_fre = sframe_fde->sframe_fres;
761
2
     sframe_fre;
762
1
     sframe_fre = sframe_fre->next)
763
1
  {
764
1
    output_sframe_row_entry (get_dw_fde_start_addrS (sframe_fde->dw_fde),
765
1
           get_dw_fde_end_addrS (sframe_fde->dw_fde),
766
1
           sframe_fre);
767
1
  }
768
1
      i++;
769
1
      sframe_fde_next = sframe_fde->next;
770
1
      sframe_fde_free (sframe_fde);
771
1
    }
772
1
  all_sframe_fdes = NULL;
773
1
  last_sframe_fde = &all_sframe_fdes;
774
775
1
  symbol_set_value_now (end_of_frame_section);
776
777
1
  gas_assert (i == num_fdes);
778
779
1
  free (fde_fre_symbols);
780
1
  fde_fre_symbols = NULL;
781
1
}
782
783
static unsigned int
784
get_num_sframe_fdes (void)
785
1
{
786
1
  struct sframe_func_entry *sframe_fde;
787
1
  unsigned int total_fdes = 0;
788
789
2
  for (sframe_fde = all_sframe_fdes; sframe_fde ; sframe_fde = sframe_fde->next)
790
1
    total_fdes++;
791
792
1
  return total_fdes;
793
1
}
794
795
/* Get the total number of SFrame row entries across the FDEs.  */
796
797
static unsigned int
798
get_num_sframe_fres (void)
799
1
{
800
1
  struct sframe_func_entry *sframe_fde;
801
1
  unsigned int total_fres = 0;
802
803
2
  for (sframe_fde = all_sframe_fdes; sframe_fde ; sframe_fde = sframe_fde->next)
804
1
    total_fres += sframe_fde->num_fres;
805
806
1
  return total_fres;
807
1
}
808
809
/* SFrame translation context functions.  */
810
811
/* Allocate a new SFrame translation context.  */
812
813
static struct sframe_xlate_ctx*
814
sframe_xlate_ctx_alloc (void)
815
1
{
816
1
  struct sframe_xlate_ctx* xlate_ctx = XCNEW (struct sframe_xlate_ctx);
817
1
  return xlate_ctx;
818
1
}
819
820
/* Initialize the given SFrame translation context.  */
821
822
static void
823
sframe_xlate_ctx_init (struct sframe_xlate_ctx *xlate_ctx)
824
4
{
825
4
  xlate_ctx->dw_fde = NULL;
826
4
  xlate_ctx->first_fre = NULL;
827
4
  xlate_ctx->last_fre = NULL;
828
4
  xlate_ctx->cur_fre = NULL;
829
4
  xlate_ctx->remember_fre = NULL;
830
4
  xlate_ctx->num_xlate_fres = 0;
831
4
}
832
833
/* Cleanup the given SFrame translation context.  */
834
835
static void
836
sframe_xlate_ctx_cleanup (struct sframe_xlate_ctx *xlate_ctx)
837
3
{
838
3
  sframe_row_entry_free (xlate_ctx->first_fre);
839
3
  XDELETE (xlate_ctx->remember_fre);
840
3
  XDELETE (xlate_ctx->cur_fre);
841
3
}
842
843
/* Transfer the state from the SFrame translation context to the SFrame FDE.  */
844
845
static void
846
sframe_xlate_ctx_finalize (struct sframe_xlate_ctx *xlate_ctx,
847
         struct sframe_func_entry *sframe_fde)
848
1
{
849
1
  sframe_fde->dw_fde = xlate_ctx->dw_fde;
850
1
  sframe_fde->sframe_fres = xlate_ctx->first_fre;
851
1
  sframe_fde->num_fres = xlate_ctx->num_xlate_fres;
852
1
}
853
854
/* Add the given FRE in the list of frame row entries in the given FDE
855
   translation context.  */
856
857
static void
858
sframe_xlate_ctx_add_fre (struct sframe_xlate_ctx *xlate_ctx,
859
       struct sframe_row_entry *fre)
860
4
{
861
4
  gas_assert (xlate_ctx && fre);
862
863
  /* Add the frame row entry.  */
864
4
  if (!xlate_ctx->first_fre)
865
4
    xlate_ctx->first_fre = fre;
866
0
  else if (xlate_ctx->last_fre)
867
0
    xlate_ctx->last_fre->next = fre;
868
869
4
  xlate_ctx->last_fre = fre;
870
871
  /* Keep track of the total number of SFrame frame row entries.  */
872
4
  xlate_ctx->num_xlate_fres++;
873
4
}
874
875
/* A SFrame Frame Row Entry is self-sufficient in terms of stack tracing info
876
   for a given PC.  It contains information assimilated from multiple CFI
877
   instructions, and hence, a new SFrame FRE is initialized with the data from
878
   the previous known FRE, if any.
879
880
   Understandably, not all information (especially the instruction begin
881
   and end boundaries) needs to be relayed.  Hence, the caller of this API
882
   must set the pc_begin and pc_end as applicable.  */
883
884
static void
885
sframe_row_entry_initialize (struct sframe_row_entry *cur_fre,
886
           struct sframe_row_entry *prev_fre)
887
3
{
888
3
  gas_assert (prev_fre);
889
3
  cur_fre->cfa_base_reg = prev_fre->cfa_base_reg;
890
3
  cur_fre->cfa_offset = prev_fre->cfa_offset;
891
3
  cur_fre->bp_loc = prev_fre->bp_loc;
892
3
  cur_fre->bp_offset = prev_fre->bp_offset;
893
3
  cur_fre->ra_loc = prev_fre->ra_loc;
894
3
  cur_fre->ra_offset = prev_fre->ra_offset;
895
  /* Treat RA mangling as a sticky bit.  It retains its value until another
896
     .cfi_negate_ra_state is seen.  */
897
3
  cur_fre->mangled_ra_p = prev_fre->mangled_ra_p;
898
3
}
899
900
/* Return SFrame register name for SP, FP, and RA, or NULL if other.  */
901
902
static const char *
903
sframe_register_name (unsigned int reg)
904
0
{
905
0
  if (reg == SFRAME_CFA_SP_REG)
906
0
    return "SP";
907
0
  else if (reg == SFRAME_CFA_FP_REG)
908
0
    return "FP";
909
0
  else if (reg == SFRAME_CFA_RA_REG)
910
0
    return "RA";
911
0
  else
912
0
    return NULL;
913
0
}
914
915
/* Translate DW_CFA_advance_loc into SFrame context.
916
   Return SFRAME_XLATE_OK if success.  */
917
918
static int
919
sframe_xlate_do_advance_loc (struct sframe_xlate_ctx *xlate_ctx,
920
           struct cfi_insn_data *cfi_insn)
921
4
{
922
4
  struct sframe_row_entry *last_fre = xlate_ctx->last_fre;
923
  /* Get the scratchpad FRE currently being updated as the cfi_insn's
924
     get interpreted.  This FRE eventually gets linked in into the
925
     list of FREs for the specific function.  */
926
4
  struct sframe_row_entry *cur_fre = xlate_ctx->cur_fre;
927
928
4
  if (cur_fre)
929
4
    {
930
4
      if (!cur_fre->merge_candidate)
931
3
  {
932
3
    sframe_fre_set_end_addr (cur_fre, cfi_insn->u.ll.lab2);
933
934
3
    sframe_xlate_ctx_add_fre (xlate_ctx, cur_fre);
935
3
    last_fre = xlate_ctx->last_fre;
936
937
3
    xlate_ctx->cur_fre = sframe_row_entry_new ();
938
3
    cur_fre = xlate_ctx->cur_fre;
939
940
3
    if (last_fre)
941
3
      sframe_row_entry_initialize (cur_fre, last_fre);
942
3
  }
943
1
      else
944
1
  {
945
1
    sframe_fre_set_end_addr (last_fre, cfi_insn->u.ll.lab2);
946
1
    gas_assert (last_fre->merge_candidate == false);
947
1
  }
948
4
    }
949
0
  else
950
0
    {
951
0
      xlate_ctx->cur_fre = sframe_row_entry_new ();
952
0
      cur_fre = xlate_ctx->cur_fre;
953
0
    }
954
955
4
  gas_assert (cur_fre);
956
4
  sframe_fre_set_begin_addr (cur_fre, cfi_insn->u.ll.lab2);
957
958
4
  return SFRAME_XLATE_OK;
959
4
}
960
961
/* Translate DW_CFA_def_cfa into SFrame context.
962
   Return SFRAME_XLATE_OK if success.  */
963
964
static int
965
sframe_xlate_do_def_cfa (struct sframe_xlate_ctx *xlate_ctx,
966
       struct cfi_insn_data *cfi_insn)
967
968
4
{
969
  /* Get the scratchpad FRE.  This FRE will eventually get linked in.  */
970
4
  struct sframe_row_entry *cur_fre = xlate_ctx->cur_fre;
971
4
  if (!cur_fre)
972
4
  {
973
4
    xlate_ctx->cur_fre = sframe_row_entry_new ();
974
4
    cur_fre = xlate_ctx->cur_fre;
975
4
    sframe_fre_set_begin_addr (cur_fre,
976
4
             get_dw_fde_start_addrS (xlate_ctx->dw_fde));
977
4
  }
978
  /* Define the current CFA rule to use the provided register and
979
     offset.  However, if the register is not FP/SP, skip creating
980
     SFrame stack trace info for the function.  */
981
4
  if (cfi_insn->u.ri.reg != SFRAME_CFA_SP_REG
982
4
      && cfi_insn->u.ri.reg != SFRAME_CFA_FP_REG)
983
0
    {
984
0
      as_warn (_("no SFrame FDE emitted; "
985
0
     "non-SP/FP register %u in .cfi_def_cfa"),
986
0
         cfi_insn->u.ri.reg);
987
0
      return SFRAME_XLATE_ERR_NOTREPRESENTED; /* Not represented.  */
988
0
    }
989
4
  sframe_fre_set_cfa_base_reg (cur_fre, cfi_insn->u.ri.reg);
990
4
  sframe_fre_set_cfa_offset (cur_fre, cfi_insn->u.ri.offset);
991
4
  cur_fre->merge_candidate = false;
992
993
4
  return SFRAME_XLATE_OK;
994
4
}
995
996
/* Translate DW_CFA_def_cfa_register into SFrame context.
997
   Return SFRAME_XLATE_OK if success.  */
998
999
static int
1000
sframe_xlate_do_def_cfa_register (struct sframe_xlate_ctx *xlate_ctx,
1001
          struct cfi_insn_data *cfi_insn)
1002
0
{
1003
0
  struct sframe_row_entry *last_fre = xlate_ctx->last_fre;
1004
  /* Get the scratchpad FRE.  This FRE will eventually get linked in.  */
1005
0
  struct sframe_row_entry *cur_fre = xlate_ctx->cur_fre;
1006
1007
0
  gas_assert (cur_fre);
1008
  /* Define the current CFA rule to use the provided register (but to
1009
     keep the old offset).  However, if the register is not FP/SP,
1010
     skip creating SFrame stack trace info for the function.  */
1011
0
  if (cfi_insn->u.r != SFRAME_CFA_SP_REG
1012
0
      && cfi_insn->u.r != SFRAME_CFA_FP_REG)
1013
0
    {
1014
0
      as_warn (_("no SFrame FDE emitted; "
1015
0
     "non-SP/FP register %u in .cfi_def_cfa_register"),
1016
0
         cfi_insn->u.r);
1017
0
      return SFRAME_XLATE_ERR_NOTREPRESENTED; /* Not represented.  */
1018
0
    }
1019
0
  sframe_fre_set_cfa_base_reg (cur_fre, cfi_insn->u.r);
1020
0
  if (last_fre)
1021
0
    sframe_fre_set_cfa_offset (cur_fre, last_fre->cfa_offset);
1022
1023
0
  cur_fre->merge_candidate = false;
1024
1025
0
  return SFRAME_XLATE_OK;
1026
0
}
1027
1028
/* Translate DW_CFA_def_cfa_offset into SFrame context.
1029
   Return SFRAME_XLATE_OK if success.  */
1030
1031
static int
1032
sframe_xlate_do_def_cfa_offset (struct sframe_xlate_ctx *xlate_ctx,
1033
        struct cfi_insn_data *cfi_insn)
1034
0
{
1035
  /* The scratchpad FRE currently being updated with each cfi_insn
1036
     being interpreted.  This FRE eventually gets linked in into the
1037
     list of FREs for the specific function.  */
1038
0
  struct sframe_row_entry *cur_fre = xlate_ctx->cur_fre;
1039
1040
0
  gas_assert (cur_fre);
1041
  /*  Define the current CFA rule to use the provided offset (but to keep
1042
      the old register).  However, if the old register is not FP/SP,
1043
      skip creating SFrame stack trace info for the function.  */
1044
0
  if ((cur_fre->cfa_base_reg == SFRAME_CFA_FP_REG)
1045
0
      || (cur_fre->cfa_base_reg == SFRAME_CFA_SP_REG))
1046
0
    {
1047
0
      sframe_fre_set_cfa_offset (cur_fre, cfi_insn->u.i);
1048
0
      cur_fre->merge_candidate = false;
1049
0
    }
1050
0
  else
1051
0
    {
1052
      /* No CFA base register in effect.  Non-SP/FP CFA base register should
1053
   not occur, as sframe_xlate_do_def_cfa[_register] would detect this.  */
1054
0
      as_warn (_("no SFrame FDE emitted; "
1055
0
     ".cfi_def_cfa_offset without CFA base register in effect"));
1056
0
      return SFRAME_XLATE_ERR_NOTREPRESENTED;
1057
0
    }
1058
1059
0
  return SFRAME_XLATE_OK;
1060
0
}
1061
1062
/* Translate DW_CFA_offset into SFrame context.
1063
   Return SFRAME_XLATE_OK if success.  */
1064
1065
static int
1066
sframe_xlate_do_offset (struct sframe_xlate_ctx *xlate_ctx,
1067
      struct cfi_insn_data *cfi_insn)
1068
4
{
1069
  /* The scratchpad FRE currently being updated with each cfi_insn
1070
     being interpreted.  This FRE eventually gets linked in into the
1071
     list of FREs for the specific function.  */
1072
4
  struct sframe_row_entry *cur_fre = xlate_ctx->cur_fre;
1073
1074
4
  gas_assert (cur_fre);
1075
  /* Change the rule for the register indicated by the register number to
1076
     be the specified offset.  */
1077
  /* Ignore SP reg, as it can be recovered from the CFA tracking info.  */
1078
4
  if (cfi_insn->u.ri.reg == SFRAME_CFA_FP_REG)
1079
0
    {
1080
0
      gas_assert (!cur_fre->base_reg);
1081
0
      sframe_fre_set_bp_track (cur_fre, cfi_insn->u.ri.offset);
1082
0
      cur_fre->merge_candidate = false;
1083
0
    }
1084
4
  else if (sframe_ra_tracking_p ()
1085
4
     && cfi_insn->u.ri.reg == SFRAME_CFA_RA_REG)
1086
0
    {
1087
0
      sframe_fre_set_ra_track (cur_fre, cfi_insn->u.ri.offset);
1088
0
      cur_fre->merge_candidate = false;
1089
0
    }
1090
  /* This is used to track changes to non-rsp registers, skip all others
1091
     except FP / RA for now.  */
1092
4
  return SFRAME_XLATE_OK;
1093
4
}
1094
1095
/* Translate DW_CFA_val_offset into SFrame context.
1096
   Return SFRAME_XLATE_OK if success.
1097
1098
   When CFI_ESC_P is true, the CFI_INSN is hand-crafted using CFI_escape
1099
   data.  See sframe_xlate_do_escape_val_offset.  */
1100
1101
static int
1102
sframe_xlate_do_val_offset (const struct sframe_xlate_ctx *xlate_ctx ATTRIBUTE_UNUSED,
1103
          const struct cfi_insn_data *cfi_insn,
1104
          bool cfi_esc_p)
1105
0
{
1106
  /* Previous value of register is CFA + offset.  However, if the specified
1107
     register is not interesting (SP, FP, or RA reg), the current
1108
     DW_CFA_val_offset instruction can be safely skipped without sacrificing
1109
     the asynchronicity of stack trace information.  */
1110
0
  if (cfi_insn->u.ri.reg == SFRAME_CFA_FP_REG
1111
0
      || (sframe_ra_tracking_p () && cfi_insn->u.ri.reg == SFRAME_CFA_RA_REG)
1112
      /* Ignore SP reg, if offset matches assumed default rule.  */
1113
0
      || (cfi_insn->u.ri.reg == SFRAME_CFA_SP_REG && cfi_insn->u.ri.offset != 0))
1114
0
    {
1115
0
      as_warn (_("no SFrame FDE emitted; %s with %s reg %u"),
1116
0
         cfi_esc_p ? ".cfi_escape DW_CFA_val_offset" : ".cfi_val_offset",
1117
0
         sframe_register_name (cfi_insn->u.ri.reg), cfi_insn->u.ri.reg);
1118
0
      return SFRAME_XLATE_ERR_NOTREPRESENTED; /* Not represented.  */
1119
0
    }
1120
1121
  /* Safe to skip.  */
1122
0
  return SFRAME_XLATE_OK;
1123
0
}
1124
1125
/* Translate DW_CFA_register into SFrame context.
1126
   Return SFRAME_XLATE_OK if success.  */
1127
1128
static int
1129
sframe_xlate_do_register (struct sframe_xlate_ctx *xlate_ctx ATTRIBUTE_UNUSED,
1130
        struct cfi_insn_data *cfi_insn)
1131
0
{
1132
  /* Previous value of register1 is register2.  However, if the specified
1133
     register1 is not interesting (FP or RA reg), the current DW_CFA_register
1134
     instruction can be safely skipped without sacrificing the asynchronicity of
1135
     stack trace information.  */
1136
0
  if (cfi_insn->u.rr.reg1 == SFRAME_CFA_FP_REG
1137
0
      || (sframe_ra_tracking_p () && cfi_insn->u.rr.reg1 == SFRAME_CFA_RA_REG)
1138
      /* Ignore SP reg, as it can be recovered from the CFA tracking info.  */
1139
0
      )
1140
0
    {
1141
0
      as_warn (_("no SFrame FDE emitted; %s register %u in .cfi_register"),
1142
0
         sframe_register_name (cfi_insn->u.rr.reg1), cfi_insn->u.rr.reg1);
1143
0
      return SFRAME_XLATE_ERR_NOTREPRESENTED;  /* Not represented.  */
1144
0
    }
1145
1146
  /* Safe to skip.  */
1147
0
  return SFRAME_XLATE_OK;
1148
0
}
1149
1150
/* Translate DW_CFA_remember_state into SFrame context.
1151
   Return SFRAME_XLATE_OK if success.  */
1152
1153
static int
1154
sframe_xlate_do_remember_state (struct sframe_xlate_ctx *xlate_ctx)
1155
0
{
1156
0
  struct sframe_row_entry *last_fre = xlate_ctx->last_fre;
1157
1158
  /* If there is no FRE state to remember, nothing to do here.  Return
1159
     early with non-zero error code, this will cause no SFrame stack trace
1160
     info for the function involved.  */
1161
0
  if (!last_fre)
1162
0
    {
1163
0
      as_warn (_("no SFrame FDE emitted; "
1164
0
     ".cfi_remember_state without prior SFrame FRE state"));
1165
0
      return SFRAME_XLATE_ERR_INVAL;
1166
0
    }
1167
1168
0
  if (!xlate_ctx->remember_fre)
1169
0
    xlate_ctx->remember_fre = sframe_row_entry_new ();
1170
0
  sframe_row_entry_initialize (xlate_ctx->remember_fre, last_fre);
1171
1172
0
  return SFRAME_XLATE_OK;
1173
0
}
1174
1175
/* Translate DW_CFA_restore_state into SFrame context.
1176
   Return SFRAME_XLATE_OK if success.  */
1177
1178
static int
1179
sframe_xlate_do_restore_state (struct sframe_xlate_ctx *xlate_ctx)
1180
0
{
1181
  /* The scratchpad FRE currently being updated with each cfi_insn
1182
     being interpreted.  This FRE eventually gets linked in into the
1183
     list of FREs for the specific function.  */
1184
0
  struct sframe_row_entry *cur_fre = xlate_ctx->cur_fre;
1185
1186
0
  gas_assert (xlate_ctx->remember_fre);
1187
0
  gas_assert (cur_fre && cur_fre->merge_candidate);
1188
1189
  /* Get the CFA state from the DW_CFA_remember_state insn.  */
1190
0
  sframe_row_entry_initialize (cur_fre, xlate_ctx->remember_fre);
1191
  /* The PC boundaries of the current SFrame FRE are updated
1192
     via other machinery.  */
1193
0
  cur_fre->merge_candidate = false;
1194
0
  return SFRAME_XLATE_OK;
1195
0
}
1196
1197
/* Translate DW_CFA_restore into SFrame context.
1198
   Return SFRAME_XLATE_OK if success.  */
1199
1200
static int
1201
sframe_xlate_do_restore (struct sframe_xlate_ctx *xlate_ctx,
1202
       struct cfi_insn_data *cfi_insn)
1203
0
{
1204
0
  struct sframe_row_entry *cie_fre = xlate_ctx->first_fre;
1205
  /* The scratchpad FRE currently being updated with each cfi_insn
1206
     being interpreted.  This FRE eventually gets linked in into the
1207
     list of FREs for the specific function.  */
1208
0
  struct sframe_row_entry *cur_fre = xlate_ctx->cur_fre;
1209
1210
  /* Change the rule for the indicated register to the rule assigned to
1211
     it by the initial_instructions in the CIE.  */
1212
0
  gas_assert (cie_fre);
1213
  /* SFrame FREs track only CFA and FP / RA for backtracing purposes;
1214
     skip the other .cfi_restore directives.  */
1215
0
  if (cfi_insn->u.r == SFRAME_CFA_FP_REG)
1216
0
    {
1217
0
      gas_assert (cur_fre);
1218
0
      cur_fre->bp_loc = cie_fre->bp_loc;
1219
0
      cur_fre->bp_offset = cie_fre->bp_offset;
1220
0
      cur_fre->merge_candidate = false;
1221
0
    }
1222
0
  else if (sframe_ra_tracking_p ()
1223
0
     && cfi_insn->u.r == SFRAME_CFA_RA_REG)
1224
0
    {
1225
0
      gas_assert (cur_fre);
1226
0
      cur_fre->ra_loc = cie_fre->ra_loc;
1227
0
      cur_fre->ra_offset = cie_fre->ra_offset;
1228
0
      cur_fre->merge_candidate = false;
1229
0
    }
1230
0
  return SFRAME_XLATE_OK;
1231
0
}
1232
1233
/* Translate DW_CFA_AARCH64_negate_ra_state into SFrame context.
1234
   Return SFRAME_XLATE_OK if success.  */
1235
1236
static int
1237
sframe_xlate_do_aarch64_negate_ra_state (struct sframe_xlate_ctx *xlate_ctx,
1238
           struct cfi_insn_data *cfi_insn ATTRIBUTE_UNUSED)
1239
0
{
1240
0
  struct sframe_row_entry *cur_fre = xlate_ctx->cur_fre;
1241
1242
0
  gas_assert (cur_fre);
1243
  /* Toggle the mangled RA status bit.  */
1244
0
  cur_fre->mangled_ra_p = !cur_fre->mangled_ra_p;
1245
0
  cur_fre->merge_candidate = false;
1246
1247
0
  return SFRAME_XLATE_OK;
1248
0
}
1249
1250
/* Translate DW_CFA_AARCH64_negate_ra_state_with_pc into SFrame context.
1251
   Return SFRAME_XLATE_OK if success.  */
1252
1253
static int
1254
sframe_xlate_do_aarch64_negate_ra_state_with_pc (struct sframe_xlate_ctx *xlate_ctx ATTRIBUTE_UNUSED,
1255
             struct cfi_insn_data *cfi_insn ATTRIBUTE_UNUSED)
1256
0
{
1257
0
  as_warn (_("no SFrame FDE emitted; .cfi_negate_ra_state_with_pc"));
1258
  /* The used signing method should be encoded inside the FDE in SFrame v3.
1259
     For now, PAuth_LR extension is not supported with SFrame.  */
1260
0
  return SFRAME_XLATE_ERR_NOTREPRESENTED;  /* Not represented.  */
1261
0
}
1262
1263
/* Translate DW_CFA_GNU_window_save into SFrame context.
1264
   DW_CFA_GNU_window_save is a DWARF Sparc extension, but is multiplexed with a
1265
   directive of DWARF AArch64 extension: DW_CFA_AARCH64_negate_ra_state.
1266
   The AArch64 backend of GCC 14 and older versions was emitting mistakenly the
1267
   Sparc CFI directive (.cfi_window_save).  From GCC 15, the AArch64 backend
1268
   only emits .cfi_negate_ra_state.  For backward compatibility, the handler for
1269
   .cfi_window_save needs to check whether the directive was used in a AArch64
1270
   ABI context or not.
1271
   Return SFRAME_XLATE_OK if success.  */
1272
1273
static int
1274
sframe_xlate_do_gnu_window_save (struct sframe_xlate_ctx *xlate_ctx,
1275
         struct cfi_insn_data *cfi_insn)
1276
3
{
1277
3
  unsigned char abi_arch = sframe_get_abi_arch ();
1278
1279
  /* Translate DW_CFA_AARCH64_negate_ra_state into SFrame context.  */
1280
3
  if (abi_arch == SFRAME_ABI_AARCH64_ENDIAN_BIG
1281
3
      || abi_arch == SFRAME_ABI_AARCH64_ENDIAN_LITTLE)
1282
0
    return sframe_xlate_do_aarch64_negate_ra_state (xlate_ctx, cfi_insn);
1283
1284
3
  as_warn (_("no SFrame FDE emitted; .cfi_window_save"));
1285
3
  return SFRAME_XLATE_ERR_NOTREPRESENTED;  /* Not represented.  */
1286
3
}
1287
1288
/* Handle DW_CFA_expression in .cfi_escape.
1289
1290
   As with sframe_xlate_do_cfi_escape, the intent of this function is to detect
1291
   only the simple-to-process but common cases, where skipping over the escape
1292
   expr data does not affect correctness of the SFrame stack trace data.
1293
1294
   Sets CALLER_WARN_P for skipped cases (and returns SFRAME_XLATE_OK) where the
1295
   caller must warn.  The caller then must also set
1296
   SFRAME_XLATE_ERR_NOTREPRESENTED for their callers.  */
1297
1298
static int
1299
sframe_xlate_do_escape_expr (const struct sframe_xlate_ctx *xlate_ctx,
1300
           const struct cfi_insn_data *cfi_insn,
1301
           bool *caller_warn_p)
1302
0
{
1303
0
  const struct cfi_escape_data *e = cfi_insn->u.esc;
1304
0
  int err = SFRAME_XLATE_OK;
1305
0
  unsigned int reg = 0;
1306
0
  unsigned int i = 0;
1307
1308
  /* Check roughly for an expression
1309
     DW_CFA_expression: r1 (rdx) (DW_OP_bregN (reg): OFFSET).  */
1310
0
#define CFI_ESC_NUM_EXP 4
1311
0
  offsetT items[CFI_ESC_NUM_EXP] = {0};
1312
0
  while (e->next)
1313
0
    {
1314
0
      e = e->next;
1315
0
      if ((i == 2 && (items[1] != 2)) /* Expected len of 2 in DWARF expr.  */
1316
    /* We do not care for the exact values of items[2] and items[3],
1317
       so an explicit check for O_constant isnt necessary either.  */
1318
0
    || i >= CFI_ESC_NUM_EXP
1319
0
    || (i < 2
1320
0
        && (e->exp.X_op != O_constant
1321
0
      || e->type != CFI_ESC_byte
1322
0
      || e->reloc != TC_PARSE_CONS_RETURN_NONE)))
1323
0
  goto warn_and_exit;
1324
0
      items[i] = e->exp.X_add_number;
1325
0
      i++;
1326
0
    }
1327
1328
0
  if (i <= CFI_ESC_NUM_EXP - 1)
1329
0
    goto warn_and_exit;
1330
1331
  /* reg operand to DW_CFA_expression is ULEB128.  For the purpose at hand,
1332
     however, the register value will be less than 128 (CFI_ESC_NUM_EXP set
1333
     to 4).  See an extended comment in sframe_xlate_do_escape_expr for why
1334
     reading ULEB is okay to skip without sacrificing correctness.  */
1335
0
  reg = items[0];
1336
0
#undef CFI_ESC_NUM_EXP
1337
1338
0
  if (reg == SFRAME_CFA_SP_REG || reg == SFRAME_CFA_FP_REG
1339
0
      || (sframe_ra_tracking_p () && reg == SFRAME_CFA_RA_REG)
1340
0
      || reg == xlate_ctx->cur_fre->cfa_base_reg)
1341
0
    {
1342
0
      as_warn (_("no SFrame FDE emitted; "
1343
0
     ".cfi_escape DW_CFA_expression with %s reg %u"),
1344
0
         sframe_register_name (reg), reg);
1345
0
      err = SFRAME_XLATE_ERR_NOTREPRESENTED;
1346
0
    }
1347
  /* else safe to skip, so continue to return SFRAME_XLATE_OK.  */
1348
1349
0
  return err;
1350
1351
0
warn_and_exit:
1352
0
  *caller_warn_p = true;
1353
0
  return err;
1354
0
}
1355
1356
/* Handle DW_CFA_val_offset in .cfi_escape.
1357
1358
   As with sframe_xlate_do_cfi_escape, the intent of this function is to detect
1359
   only the simple-to-process but common cases, where skipping over the escape
1360
   expr data does not affect correctness of the SFrame stack trace data.
1361
1362
   Sets CALLER_WARN_P for skipped cases (and returns SFRAME_XLATE_OK) where the
1363
   caller must warn.  The caller then must also set
1364
   SFRAME_XLATE_ERR_NOTREPRESENTED for their callers.  */
1365
1366
static int
1367
sframe_xlate_do_escape_val_offset (const struct sframe_xlate_ctx *xlate_ctx,
1368
           const struct cfi_insn_data *cfi_insn,
1369
           bool *caller_warn_p)
1370
0
{
1371
0
  const struct cfi_escape_data *e = cfi_insn->u.esc;
1372
0
  int err = SFRAME_XLATE_OK;
1373
0
  unsigned int i = 0;
1374
0
  unsigned int reg;
1375
0
  offsetT offset;
1376
1377
  /* Check for (DW_CFA_val_offset reg scaled_offset) sequence.  */
1378
0
#define CFI_ESC_NUM_EXP 2
1379
0
  offsetT items[CFI_ESC_NUM_EXP] = {0};
1380
0
  while (e->next)
1381
0
    {
1382
0
      e = e->next;
1383
0
      if (i >= CFI_ESC_NUM_EXP || e->exp.X_op != O_constant
1384
0
    || e->type != CFI_ESC_byte
1385
0
    || e->reloc != TC_PARSE_CONS_RETURN_NONE)
1386
0
  goto warn_and_exit;
1387
0
      items[i] = e->exp.X_add_number;
1388
0
      i++;
1389
0
    }
1390
0
  if (i <= CFI_ESC_NUM_EXP - 1)
1391
0
    goto warn_and_exit;
1392
1393
  /* Both arguments to DW_CFA_val_offset are ULEB128.  Especially with APX (on
1394
     x86) we're going to see DWARF register numbers above 127, for the extended
1395
     GPRs.  And large enough stack frames would also require multi-byte offset
1396
     representation.  However, since we limit our focus on cases when
1397
     CFI_ESC_NUM_EXP is 2, reading ULEB can be skipped.  IOW, although not
1398
     ideal, SFrame FDE generation in case of an APX register in
1399
     DW_CFA_val_offset is being skipped (PS: this does _not_ mean incorrect
1400
     SFrame stack trace data).
1401
1402
     Recall that the intent here is to check for simple and prevalent cases,
1403
     when feasible.  */
1404
1405
0
  reg = items[0];
1406
0
  offset = items[1];
1407
0
#undef CFI_ESC_NUM_EXP
1408
1409
  /* Invoke sframe_xlate_do_val_offset itself for checking.  */
1410
0
  struct cfi_insn_data temp = {
1411
0
    .insn = DW_CFA_val_offset,
1412
0
    .u = {
1413
0
      .ri = {
1414
0
  .reg = reg,
1415
0
  .offset = offset * DWARF2_CIE_DATA_ALIGNMENT
1416
0
      }
1417
0
    }
1418
0
  };
1419
0
  err = sframe_xlate_do_val_offset (xlate_ctx, &temp, true);
1420
0
  return err;
1421
1422
0
warn_and_exit:
1423
0
  *caller_warn_p = true;
1424
0
  return err;
1425
0
}
1426
1427
/* Handle CFI_escape in SFrame context.
1428
1429
   .cfi_escape CFI directive allows the user to add arbitrary data to the
1430
   unwind info.  DWARF expressions commonly follow after CFI_escape (fake CFI)
1431
   DWARF opcode.  One might also use CFI_escape to add OS-specific CFI opcodes
1432
   even.
1433
1434
   Complex unwind info added using .cfi_escape directive _may_ be of no
1435
   consequence for SFrame when the affected registers are not SP, FP, RA or
1436
   CFA.  The challenge in confirming the afore-mentioned is that it needs full
1437
   parsing (and validation) of the data presented after .cfi_escape.  Here we
1438
   take a case-by-case approach towards skipping _some_ instances of
1439
   .cfi_escape: skip those that can be *easily* determined to be harmless in
1440
   the context of SFrame stack trace information.
1441
1442
   This function partially processes data following .cfi_escape and returns
1443
   SFRAME_XLATE_OK if OK to skip.  */
1444
1445
static int
1446
sframe_xlate_do_cfi_escape (const struct sframe_xlate_ctx *xlate_ctx,
1447
          const struct cfi_insn_data *cfi_insn)
1448
0
{
1449
0
  const struct cfi_escape_data *e;
1450
0
  bool warn_p = false;
1451
0
  int err = SFRAME_XLATE_OK;
1452
0
  offsetT firstop;
1453
1454
0
  e = cfi_insn->u.esc;
1455
1456
0
  if (!e)
1457
0
    return SFRAME_XLATE_ERR_INVAL;
1458
1459
0
  if (e->exp.X_op != O_constant
1460
0
      || e->type != CFI_ESC_byte
1461
0
      || e->reloc != TC_PARSE_CONS_RETURN_NONE)
1462
0
    return SFRAME_XLATE_ERR_NOTREPRESENTED;
1463
1464
0
  firstop = e->exp.X_add_number;
1465
0
  switch (firstop)
1466
0
    {
1467
0
    case DW_CFA_nop:
1468
      /* One or more nops together are harmless for SFrame.  */
1469
0
      while (e->next)
1470
0
  {
1471
0
    e = e->next;
1472
0
    if (e->exp.X_op != O_constant || e->exp.X_add_number != DW_CFA_nop
1473
0
        || e->type != CFI_ESC_byte
1474
0
        || e->reloc != TC_PARSE_CONS_RETURN_NONE)
1475
0
      {
1476
0
        warn_p = true;
1477
0
        break;
1478
0
      }
1479
0
  }
1480
0
      break;
1481
1482
0
    case DW_CFA_expression:
1483
0
      err = sframe_xlate_do_escape_expr (xlate_ctx, cfi_insn, &warn_p);
1484
0
      break;
1485
1486
0
    case DW_CFA_val_offset:
1487
0
      err = sframe_xlate_do_escape_val_offset (xlate_ctx, cfi_insn, &warn_p);
1488
0
      break;
1489
1490
    /* FIXME - Also add processing for DW_CFA_GNU_args_size in future?  */
1491
1492
0
    default:
1493
0
      warn_p = true;
1494
0
      break;
1495
0
    }
1496
1497
0
  if (warn_p)
1498
0
    {
1499
      /* In all other cases (e.g., DW_CFA_def_cfa_expression or other
1500
   OS-specific CFI opcodes), skip inspecting the DWARF expression.
1501
   This may impact the asynchronicity due to loss of coverage.
1502
   Continue to warn the user and bail out.  */
1503
0
      as_warn (_("no SFrame FDE emitted; .cfi_escape with op (%#lx)"),
1504
0
         (unsigned long)firstop);
1505
0
      err = SFRAME_XLATE_ERR_NOTREPRESENTED;
1506
0
    }
1507
1508
0
  return err;
1509
0
}
1510
1511
/* Translate DW_CFA_undefined into SFrame context.
1512
1513
   DW_CFA_undefined op indicates that from now on, the previous value of
1514
   register can’t be restored anymore.  In SFrame stack trace, we cannot
1515
   represent such a semantic.  So, we skip generating an SFrame FDE for this,
1516
   when a register of interest is used with DW_CFA_undefined.
1517
1518
   Return SFRAME_XLATE_OK if success.  */
1519
1520
static int
1521
sframe_xlate_do_cfi_undefined (const struct sframe_xlate_ctx *xlate_ctx ATTRIBUTE_UNUSED,
1522
             const struct cfi_insn_data *cfi_insn)
1523
2
{
1524
2
  if (cfi_insn->u.r == SFRAME_CFA_FP_REG
1525
2
      || cfi_insn->u.r == SFRAME_CFA_RA_REG
1526
2
      || cfi_insn->u.r == SFRAME_CFA_SP_REG)
1527
0
    {
1528
0
      as_warn (_("no SFrame FDE emitted; %s reg %u in .cfi_undefined"),
1529
0
         sframe_register_name (cfi_insn->u.r), cfi_insn->u.r);
1530
0
      return SFRAME_XLATE_ERR_NOTREPRESENTED; /* Not represented.  */
1531
0
    }
1532
1533
  /* Safe to skip.  */
1534
2
  return SFRAME_XLATE_OK;
1535
2
}
1536
1537
/* Translate DW_CFA_same_value into SFrame context.
1538
1539
   DW_CFA_same_value op indicates that current value of register is the same as
1540
   in the previous frame, i.e. no restoration needed.  In SFrame stack trace
1541
   format, the handling is done similar to DW_CFA_restore.
1542
1543
   For SFRAME_CFA_RA_REG, if RA-tracking is enabled, reset the SFrame FRE state
1544
   for REG_RA to indicate that register does not need restoration.  P.S.: Even
1545
   though resetting just REG_RA may be contradicting the AArch64 ABI (as Frame
1546
   Record contains for FP and LR), sframe_xlate_do_same_value () does not
1547
   detect the case and assumes the users' DW_CFA_same_value SFRAME_CFA_RA_REG
1548
   has a sound reason.  For ABIs, where RA-tracking is disabled, handle it
1549
   similar to DW_CFA_restore: ignore the directive, it is safe to skip.  The
1550
   reasoning is similar to that for DW_CFA_restore: if such a restoration was
1551
   meant to be of any consequence, there must have been the necessary CFI
1552
   directives for updating the CFA rule too such that the recovered RA from
1553
   stack is valid.
1554
1555
   SFrame based stacktracers will implement CFA-based SP recovery for all ABIs:
1556
   SP for previous frame is based on the applicable CFA-rule.  There is no
1557
   representation in SFrame to indicate "no restoration needed" for REG_SP,
1558
   when going to the previous frame.  That said, if DW_CFA_same_value is seen
1559
   for SFRAME_CFA_SP_REG, handle it similar to DW_CFA_restore: ignore the
1560
   directive, it is safe to skip.  The reasoning is similar to that for
1561
   DW_CFA_restore: if such a restoration was meant to be of any consequence,
1562
   there must have been the necessary CFI directives for updating the CFA rule
1563
   too.  The latter will be duly processed by the SFrame generation code, as
1564
   expected.
1565
1566
   For SFRAME_CFA_FP_REG, reset the state of the current FRE to indicate that
1567
   the value is the same as previous frame.
1568
1569
   Return SFRAME_XLATE_OK if success.  */
1570
1571
static int
1572
sframe_xlate_do_same_value (const struct sframe_xlate_ctx *xlate_ctx,
1573
          const struct cfi_insn_data *cfi_insn)
1574
0
{
1575
0
  struct sframe_row_entry *cur_fre = xlate_ctx->cur_fre;
1576
1577
0
  if (sframe_ra_tracking_p () && cfi_insn->u.r == SFRAME_CFA_RA_REG)
1578
0
    {
1579
0
      cur_fre->ra_loc = SFRAME_FRE_ELEM_LOC_REG;
1580
0
      cur_fre->ra_offset = 0;
1581
0
      cur_fre->merge_candidate = false;
1582
0
    }
1583
0
  else if (cfi_insn->u.r == SFRAME_CFA_FP_REG)
1584
0
    {
1585
0
      cur_fre->bp_loc = SFRAME_FRE_ELEM_LOC_REG;
1586
0
      cur_fre->bp_offset = 0;
1587
0
      cur_fre->merge_candidate = false;
1588
0
    }
1589
1590
  /* Safe to skip.  */
1591
0
  return SFRAME_XLATE_OK;
1592
0
}
1593
1594
/* Returns the DWARF call frame instruction name or fake CFI name for the
1595
   specified CFI opcode, or NULL if the value is not recognized.  */
1596
1597
static const char *
1598
sframe_get_cfi_name (int cfi_opc)
1599
0
{
1600
0
  const char *cfi_name;
1601
1602
0
  switch (cfi_opc)
1603
0
    {
1604
      /* Fake CFI type; outside the byte range of any real CFI insn.  */
1605
      /* See gas/dw2gencfi.h.  */
1606
0
      case CFI_adjust_cfa_offset:
1607
0
  cfi_name = "CFI_adjust_cfa_offset";
1608
0
  break;
1609
0
      case CFI_return_column:
1610
0
  cfi_name = "CFI_return_column";
1611
0
  break;
1612
0
      case CFI_rel_offset:
1613
0
  cfi_name = "CFI_rel_offset";
1614
0
  break;
1615
0
      case CFI_escape:
1616
0
  cfi_name = "CFI_escape";
1617
0
  break;
1618
0
      case CFI_signal_frame:
1619
0
  cfi_name = "CFI_signal_frame";
1620
0
  break;
1621
0
      case CFI_val_encoded_addr:
1622
0
  cfi_name = "CFI_val_encoded_addr";
1623
0
  break;
1624
0
      case CFI_label:
1625
0
  cfi_name = "CFI_label";
1626
0
  break;
1627
0
      default:
1628
0
  cfi_name = get_DW_CFA_name (cfi_opc);
1629
0
    }
1630
1631
0
  return cfi_name;
1632
0
}
1633
1634
/* Process CFI_INSN and update the translation context with the FRE
1635
   information.
1636
1637
   Returns an error code (sframe_xlate_err) if CFI_INSN is not successfully
1638
   processed.  */
1639
1640
static int
1641
sframe_do_cfi_insn (struct sframe_xlate_ctx *xlate_ctx,
1642
        struct cfi_insn_data *cfi_insn)
1643
17
{
1644
17
  int err = 0;
1645
1646
  /* Atleast one cfi_insn per FDE is expected.  */
1647
17
  gas_assert (cfi_insn);
1648
17
  int op = cfi_insn->insn;
1649
1650
17
  switch (op)
1651
17
    {
1652
4
    case DW_CFA_advance_loc:
1653
4
      err = sframe_xlate_do_advance_loc (xlate_ctx, cfi_insn);
1654
4
      break;
1655
4
    case DW_CFA_def_cfa:
1656
4
      err = sframe_xlate_do_def_cfa (xlate_ctx, cfi_insn);
1657
4
      break;
1658
0
    case DW_CFA_def_cfa_register:
1659
0
      err = sframe_xlate_do_def_cfa_register (xlate_ctx, cfi_insn);
1660
0
      break;
1661
0
    case DW_CFA_def_cfa_offset:
1662
0
      err = sframe_xlate_do_def_cfa_offset (xlate_ctx, cfi_insn);
1663
0
      break;
1664
4
    case DW_CFA_offset:
1665
4
      err = sframe_xlate_do_offset (xlate_ctx, cfi_insn);
1666
4
      break;
1667
0
    case DW_CFA_val_offset:
1668
0
      err = sframe_xlate_do_val_offset (xlate_ctx, cfi_insn, false);
1669
0
      break;
1670
0
    case DW_CFA_remember_state:
1671
0
      err = sframe_xlate_do_remember_state (xlate_ctx);
1672
0
      break;
1673
0
    case DW_CFA_restore_state:
1674
0
      err = sframe_xlate_do_restore_state (xlate_ctx);
1675
0
      break;
1676
0
    case DW_CFA_restore:
1677
0
      err = sframe_xlate_do_restore (xlate_ctx, cfi_insn);
1678
0
      break;
1679
    /* DW_CFA_AARCH64_negate_ra_state is multiplexed with
1680
       DW_CFA_GNU_window_save.  */
1681
3
    case DW_CFA_GNU_window_save:
1682
3
      err = sframe_xlate_do_gnu_window_save (xlate_ctx, cfi_insn);
1683
3
      break;
1684
0
    case DW_CFA_AARCH64_negate_ra_state_with_pc:
1685
0
      err = sframe_xlate_do_aarch64_negate_ra_state_with_pc (xlate_ctx, cfi_insn);
1686
0
      break;
1687
0
    case DW_CFA_register:
1688
0
      err = sframe_xlate_do_register (xlate_ctx, cfi_insn);
1689
0
      break;
1690
0
    case CFI_escape:
1691
0
      err = sframe_xlate_do_cfi_escape (xlate_ctx, cfi_insn);
1692
0
      break;
1693
2
    case DW_CFA_undefined:
1694
2
      err = sframe_xlate_do_cfi_undefined (xlate_ctx, cfi_insn);
1695
2
      break;
1696
0
    case DW_CFA_same_value:
1697
0
      err = sframe_xlate_do_same_value (xlate_ctx, cfi_insn);
1698
0
      break;
1699
0
    default:
1700
      /* Other skipped operations may, however, impact the asynchronicity.  */
1701
0
      {
1702
0
  const char *cfi_name = sframe_get_cfi_name (op);
1703
1704
0
  if (!cfi_name)
1705
0
    cfi_name = _("(unknown)");
1706
0
  as_warn (_("no SFrame FDE emitted; CFI insn %s (%#x)"),
1707
0
     cfi_name, op);
1708
0
  err = SFRAME_XLATE_ERR_NOTREPRESENTED;
1709
0
      }
1710
17
    }
1711
1712
  /* Any error will cause no SFrame FDE later.  The user has already been
1713
     warned.  */
1714
17
  return err;
1715
17
}
1716
1717
1718
static int
1719
sframe_do_fde (struct sframe_xlate_ctx *xlate_ctx,
1720
         const struct fde_entry *dw_fde)
1721
4
{
1722
4
  struct cfi_insn_data *cfi_insn;
1723
4
  int err = SFRAME_XLATE_OK;
1724
1725
4
  xlate_ctx->dw_fde = dw_fde;
1726
1727
  /* SFrame format cannot represent a non-default DWARF return column reg.  */
1728
4
  if (xlate_ctx->dw_fde->return_column != DWARF2_DEFAULT_RETURN_COLUMN)
1729
0
    {
1730
0
      as_warn (_("no SFrame FDE emitted; non-default RA register %u"),
1731
0
         xlate_ctx->dw_fde->return_column);
1732
0
      return SFRAME_XLATE_ERR_NOTREPRESENTED;
1733
0
    }
1734
1735
  /* Iterate over the CFIs and create SFrame FREs.  */
1736
18
  for (cfi_insn = dw_fde->data; cfi_insn; cfi_insn = cfi_insn->next)
1737
17
    {
1738
      /* Translate each CFI, and buffer the state in translation context.  */
1739
17
      err = sframe_do_cfi_insn (xlate_ctx, cfi_insn);
1740
17
      if (err != SFRAME_XLATE_OK)
1741
3
  {
1742
    /* Skip generating SFrame stack trace info for the function if any
1743
       offending CFI is encountered by sframe_do_cfi_insn ().  Warning
1744
       message already printed by sframe_do_cfi_insn ().  */
1745
3
    return err; /* Return the error code.  */
1746
3
  }
1747
17
    }
1748
1749
  /* Link in the scratchpad FRE that the last few CFI insns helped create.  */
1750
1
  if (xlate_ctx->cur_fre)
1751
1
    {
1752
1
      sframe_xlate_ctx_add_fre (xlate_ctx, xlate_ctx->cur_fre);
1753
1
      xlate_ctx->cur_fre = NULL;
1754
1
    }
1755
  /* Designate the end of the last SFrame FRE.  */
1756
1
  if (xlate_ctx->last_fre)
1757
1
    {
1758
1
      xlate_ctx->last_fre->pc_end
1759
1
  = get_dw_fde_end_addrS (xlate_ctx->dw_fde);
1760
1
    }
1761
1762
1
  if (sframe_ra_tracking_p ())
1763
0
    {
1764
0
      struct sframe_row_entry *fre;
1765
1766
      /* Iterate over the scratchpad FREs and validate them.  */
1767
0
      for (fre = xlate_ctx->first_fre; fre; fre = fre->next)
1768
0
  {
1769
    /* SFrame format cannot represent FP on stack without RA on stack.  */
1770
0
    if (fre->ra_loc != SFRAME_FRE_ELEM_LOC_STACK
1771
0
        && fre->bp_loc == SFRAME_FRE_ELEM_LOC_STACK)
1772
0
      {
1773
0
        as_warn (_("no SFrame FDE emitted; FP without RA on stack"));
1774
0
        return SFRAME_XLATE_ERR_NOTREPRESENTED;
1775
0
      }
1776
0
  }
1777
0
    }
1778
1779
1
  return SFRAME_XLATE_OK;
1780
1
}
1781
1782
/* Create SFrame stack trace info for all functions.
1783
1784
   This function consumes the already generated DWARF FDEs (by dw2gencfi) and
1785
   generates data which is later emitted as stack trace information encoded in
1786
   the SFrame format.  */
1787
1788
static void
1789
create_sframe_all (void)
1790
1
{
1791
1
  struct fde_entry *dw_fde = NULL;
1792
1
  struct sframe_func_entry *sframe_fde = NULL;
1793
1794
1
  struct sframe_xlate_ctx *xlate_ctx = sframe_xlate_ctx_alloc ();
1795
1796
5
  for (dw_fde = all_fde_data; dw_fde ; dw_fde = dw_fde->next)
1797
4
    {
1798
4
      sframe_fde = sframe_fde_alloc ();
1799
      /* Initialize the translation context with information anew.  */
1800
4
      sframe_xlate_ctx_init (xlate_ctx);
1801
1802
      /* Process and link SFrame FDEs if no error.  Also skip adding an SFrame
1803
   FDE if it does not contain any SFrame FREs.  There is little use of an
1804
   SFrame FDE if there is no stack tracing information for the
1805
   function.  */
1806
4
      int err = sframe_do_fde (xlate_ctx, dw_fde);
1807
4
      if (err || xlate_ctx->num_xlate_fres == 0)
1808
3
  {
1809
3
    sframe_xlate_ctx_cleanup (xlate_ctx);
1810
3
    sframe_fde_free (sframe_fde);
1811
3
  }
1812
1
      else
1813
1
  {
1814
    /* All done.  Transfer the state from the SFrame translation
1815
       context to the SFrame FDE.  */
1816
1
    sframe_xlate_ctx_finalize (xlate_ctx, sframe_fde);
1817
1
    *last_sframe_fde = sframe_fde;
1818
1
    last_sframe_fde = &sframe_fde->next;
1819
1
  }
1820
4
    }
1821
1822
1
  XDELETE (xlate_ctx);
1823
1
}
1824
1825
void
1826
output_sframe (segT sframe_seg)
1827
1
{
1828
1
  (void) sframe_seg;
1829
1830
  /* Setup the version specific access functions.  */
1831
1
  sframe_set_version (SFRAME_VERSION_2);
1832
1833
  /* Process all fdes and create SFrame stack trace information.  */
1834
1
  create_sframe_all ();
1835
1836
1
  output_sframe_internal ();
1837
1
}
1838
1839
#else  /*  support_sframe_p  */
1840
1841
void
1842
output_sframe (segT sframe_seg ATTRIBUTE_UNUSED)
1843
{
1844
}
1845
1846
#endif /*  support_sframe_p  */