Coverage Report

Created: 2025-07-08 11:15

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