Coverage Report

Created: 2023-06-29 07:09

/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-2023 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
/* By default, use 32-bit relocations from .sframe into .text.  */
30
#ifndef SFRAME_RELOC_SIZE
31
0
# define SFRAME_RELOC_SIZE 4
32
#endif
33
34
/* Whether frame row entries track RA.
35
36
   A target may not need return address tracking for stack tracing.  If it
37
   does need the same, SFRAME_CFA_RA_REG must be defined with the return
38
   address register number.  */
39
40
#if defined (sframe_ra_tracking_p) && defined (SFRAME_CFA_RA_REG)
41
# ifndef SFRAME_FRE_RA_TRACKING
42
# define SFRAME_FRE_RA_TRACKING 1
43
# endif
44
#endif
45
46
/* SFrame FRE type selection optimization is an optimization for size.
47
48
   There are three flavors of SFrame FRE representation in the binary format:
49
     - sframe_frame_row_entry_addr1 where the FRE start address is 1 byte.
50
     - sframe_frame_row_entry_addr2 where the FRE start address is 2 bytes.
51
     - sframe_frame_row_entry_addr4 where the FRE start address is 4 bytes.
52
53
   Note that in the SFrame format, all SFrame FREs of a function use one
54
   single representation.  The SFrame FRE type itself is identified via the
55
   information in the SFrame FDE function info.
56
57
   Now, to select the minimum required one from the list above, one needs to
58
   make a decision based on the size (in bytes) of the function.
59
60
   As a result, for this optimization, some fragments (generated with a new
61
   type rs_sframe) for the SFrame section are fixed up later.
62
63
   This optimization (for size) is enabled by default.  */
64
65
#ifndef SFRAME_FRE_TYPE_SELECTION_OPT
66
# define SFRAME_FRE_TYPE_SELECTION_OPT 1
67
#endif
68
69
/* Emit a single byte into the current segment.  */
70
71
static inline void
72
out_one (int byte)
73
0
{
74
0
  FRAG_APPEND_1_CHAR (byte);
75
0
}
76
77
/* Emit a two-byte word into the current segment.  */
78
79
static inline void
80
out_two (int data)
81
0
{
82
0
  md_number_to_chars (frag_more (2), data, 2);
83
0
}
84
85
/* Emit a four byte word into the current segment.  */
86
87
static inline void
88
out_four (int data)
89
0
{
90
0
  md_number_to_chars (frag_more (4), data, 4);
91
0
}
92
93
/* Get the start address symbol from the DWARF FDE.  */
94
95
static symbolS*
96
get_dw_fde_start_addrS (const struct fde_entry *dw_fde)
97
0
{
98
0
  return dw_fde->start_address;
99
0
}
100
101
/* Get the start address symbol from the DWARF FDE.  */
102
103
static symbolS*
104
get_dw_fde_end_addrS (const struct fde_entry *dw_fde)
105
0
{
106
0
  return dw_fde->end_address;
107
0
}
108
109
/* Get whether PAUTH B key is used.  */
110
static bool
111
get_dw_fde_pauth_b_key_p (const struct fde_entry *dw_fde ATTRIBUTE_UNUSED)
112
0
{
113
#ifdef tc_fde_entry_extras
114
  return (dw_fde->pauth_key == AARCH64_PAUTH_KEY_B);
115
#else
116
0
  return false;
117
0
#endif
118
0
}
119
120
/* SFrame Frame Row Entry (FRE) related functions.  */
121
122
static void
123
sframe_fre_set_begin_addr (struct sframe_row_entry *fre, symbolS *beginS)
124
0
{
125
0
  fre->pc_begin = beginS;
126
0
}
127
128
static void
129
sframe_fre_set_end_addr (struct sframe_row_entry *fre, symbolS *endS)
130
0
{
131
0
  fre->pc_end = endS;
132
0
}
133
134
static void
135
sframe_fre_set_cfa_base_reg (struct sframe_row_entry *fre,
136
           unsigned int cfa_base_reg)
137
0
{
138
0
  fre->cfa_base_reg = cfa_base_reg;
139
0
  fre->merge_candidate = false;
140
0
}
141
142
static void
143
sframe_fre_set_cfa_offset (struct sframe_row_entry *fre,
144
         offsetT cfa_offset)
145
0
{
146
0
  fre->cfa_offset = cfa_offset;
147
0
  fre->merge_candidate = false;
148
0
}
149
150
#ifdef SFRAME_FRE_RA_TRACKING
151
static void
152
sframe_fre_set_ra_track (struct sframe_row_entry *fre, offsetT ra_offset)
153
{
154
  fre->ra_loc = SFRAME_FRE_ELEM_LOC_STACK;
155
  fre->ra_offset = ra_offset;
156
  fre->merge_candidate = false;
157
}
158
#endif
159
160
static void
161
sframe_fre_set_bp_track (struct sframe_row_entry *fre, offsetT bp_offset)
162
0
{
163
0
  fre->bp_loc = SFRAME_FRE_ELEM_LOC_STACK;
164
0
  fre->bp_offset = bp_offset;
165
0
  fre->merge_candidate = false;
166
0
}
167
168
/* All stack offset values within an FRE are uniformly encoded in the same
169
   number of bytes.  The size of the stack offset values will, however, vary
170
   across FREs.  */
171
172
0
#define VALUE_8BIT  0x7f
173
0
#define VALUE_16BIT 0x7fff
174
0
#define VALUE_32BIT 0x7fffffff
175
0
#define VALUE_64BIT 0x7fffffffffffffff
176
177
/* Given a signed offset, return the size in bytes needed to represent it.  */
178
179
static unsigned int
180
get_offset_size_in_bytes (offsetT value)
181
0
{
182
0
  unsigned int size = 0;
183
184
0
  if (value <= VALUE_8BIT && value >= (offsetT) -VALUE_8BIT)
185
0
    size = 1;
186
0
  else if (value <= VALUE_16BIT && value >= (offsetT) -VALUE_16BIT)
187
0
    size = 2;
188
0
  else if (value <= VALUE_32BIT && value >= (offsetT) -VALUE_32BIT)
189
0
    size = 4;
190
0
  else if ((sizeof (offsetT) > 4) && (value <= (offsetT) VALUE_64BIT
191
0
              && value >= (offsetT) -VALUE_64BIT))
192
0
    size = 8;
193
194
0
  return size;
195
0
}
196
197
0
#define SFRAME_FRE_OFFSET_FUNC_MAP_INDEX_1B  0 /* SFRAME_FRE_OFFSET_1B.  */
198
0
#define SFRAME_FRE_OFFSET_FUNC_MAP_INDEX_2B  1 /* SFRAME_FRE_OFFSET_2B.  */
199
0
#define SFRAME_FRE_OFFSET_FUNC_MAP_INDEX_4B  2 /* SFRAME_FRE_OFFSET_4B.  */
200
0
#define SFRAME_FRE_OFFSET_FUNC_MAP_INDEX_8B  3 /* Not supported in SFrame.  */
201
0
#define SFRAME_FRE_OFFSET_FUNC_MAP_INDEX_MAX SFRAME_FRE_OFFSET_FUNC_MAP_INDEX_8B
202
203
/* Helper struct for mapping offset size to output functions.  */
204
205
struct sframe_fre_offset_func_map
206
{
207
  unsigned int offset_size;
208
  void (*out_func)(int);
209
};
210
211
/* Given an OFFSET_SIZE, return the size in bytes needed to represent it.  */
212
213
static unsigned int
214
sframe_fre_offset_func_map_index (unsigned int offset_size)
215
0
{
216
0
  unsigned int idx = SFRAME_FRE_OFFSET_FUNC_MAP_INDEX_MAX;
217
218
0
  switch (offset_size)
219
0
    {
220
0
      case SFRAME_FRE_OFFSET_1B:
221
0
  idx = SFRAME_FRE_OFFSET_FUNC_MAP_INDEX_1B;
222
0
  break;
223
0
      case SFRAME_FRE_OFFSET_2B:
224
0
  idx = SFRAME_FRE_OFFSET_FUNC_MAP_INDEX_2B;
225
0
  break;
226
0
      case SFRAME_FRE_OFFSET_4B:
227
0
  idx = SFRAME_FRE_OFFSET_FUNC_MAP_INDEX_4B;
228
0
  break;
229
0
      default:
230
  /* Not supported in SFrame.  */
231
0
  break;
232
0
    }
233
234
0
  return idx;
235
0
}
236
237
/* Mapping from offset size to the output function to emit the value.  */
238
239
static const
240
struct sframe_fre_offset_func_map
241
fre_offset_func_map[SFRAME_FRE_OFFSET_FUNC_MAP_INDEX_MAX+1] =
242
{
243
  { SFRAME_FRE_OFFSET_1B, out_one },
244
  { SFRAME_FRE_OFFSET_2B, out_two },
245
  { SFRAME_FRE_OFFSET_4B, out_four },
246
  { -1, NULL } /* Not Supported in SFrame.  */
247
};
248
249
/* SFrame version specific operations access.  */
250
251
static struct sframe_version_ops sframe_ver_ops;
252
253
/* SFrame (SFRAME_VERSION_1) set FRE info.  */
254
255
static unsigned char
256
sframe_v1_set_fre_info (unsigned int base_reg, unsigned int num_offsets,
257
      unsigned int offset_size, bool mangled_ra_p)
258
0
{
259
0
  unsigned char fre_info;
260
0
  fre_info = SFRAME_V1_FRE_INFO (base_reg, num_offsets, offset_size);
261
0
  fre_info = SFRAME_V1_FRE_INFO_UPDATE_MANGLED_RA_P (mangled_ra_p, fre_info);
262
0
  return fre_info;
263
0
}
264
265
/* SFrame (SFRAME_VERSION_1) set function info.  */
266
static unsigned char
267
sframe_v1_set_func_info (unsigned int fde_type, unsigned int fre_type,
268
       unsigned int pauth_key)
269
0
{
270
0
  unsigned char func_info;
271
0
  func_info = SFRAME_V1_FUNC_INFO (fde_type, fre_type);
272
0
  func_info = SFRAME_V1_FUNC_INFO_UPDATE_PAUTH_KEY (pauth_key, func_info);
273
0
  return func_info;
274
0
}
275
276
/* SFrame version specific operations setup.  */
277
278
static void
279
sframe_set_version (uint32_t sframe_version ATTRIBUTE_UNUSED)
280
0
{
281
0
  sframe_ver_ops.format_version = SFRAME_VERSION_1;
282
283
0
  sframe_ver_ops.set_fre_info = sframe_v1_set_fre_info;
284
285
0
  sframe_ver_ops.set_func_info = sframe_v1_set_func_info;
286
0
}
287
288
/* SFrame set FRE info.  */
289
290
static unsigned char
291
sframe_set_fre_info (unsigned int base_reg, unsigned int num_offsets,
292
         unsigned int offset_size, bool mangled_ra_p)
293
0
{
294
0
  return sframe_ver_ops.set_fre_info (base_reg, num_offsets,
295
0
              offset_size, mangled_ra_p);
296
0
}
297
298
/* SFrame set func info. */
299
300
static unsigned char
301
sframe_set_func_info (unsigned int fde_type, unsigned int fre_type,
302
          unsigned int pauth_key)
303
0
{
304
0
  return sframe_ver_ops.set_func_info (fde_type, fre_type, pauth_key);
305
0
}
306
307
/* Get the number of SFrame FDEs for the current file.  */
308
309
static unsigned int
310
get_num_sframe_fdes (void);
311
312
/* Get the number of SFrame frame row entries for the current file.  */
313
314
static unsigned int
315
get_num_sframe_fres (void);
316
317
/* Get CFA base register ID as represented in SFrame Frame Row Entry.  */
318
319
static unsigned int
320
get_fre_base_reg_id (struct sframe_row_entry *sframe_fre)
321
0
{
322
0
  unsigned int cfi_insn_cfa_base_reg = sframe_fre->cfa_base_reg;
323
0
  unsigned fre_base_reg = SFRAME_BASE_REG_SP;
324
325
0
  if (cfi_insn_cfa_base_reg == SFRAME_CFA_FP_REG)
326
0
    fre_base_reg = SFRAME_BASE_REG_FP;
327
328
  /* Only one bit is reserved in SFRAME_VERSION_1.  */
329
0
  gas_assert (fre_base_reg == SFRAME_BASE_REG_SP
330
0
        || fre_base_reg == SFRAME_BASE_REG_FP);
331
332
0
  return fre_base_reg;
333
0
}
334
335
/* Get number of offsets necessary for the SFrame Frame Row Entry.  */
336
337
static unsigned int
338
get_fre_num_offsets (struct sframe_row_entry *sframe_fre)
339
0
{
340
  /* Atleast 1 must always be present (to recover CFA).  */
341
0
  unsigned int fre_num_offsets = 1;
342
343
0
  if (sframe_fre->bp_loc == SFRAME_FRE_ELEM_LOC_STACK)
344
0
    fre_num_offsets++;
345
#ifdef SFRAME_FRE_RA_TRACKING
346
  if (sframe_fre->ra_loc == SFRAME_FRE_ELEM_LOC_STACK)
347
    fre_num_offsets++;
348
#endif
349
0
  return fre_num_offsets;
350
0
}
351
352
/* Get the minimum necessary offset size (in bytes) for this
353
   SFrame frame row entry.  */
354
355
static unsigned int
356
sframe_get_fre_offset_size (struct sframe_row_entry *sframe_fre)
357
0
{
358
0
  unsigned int max_offset_size = 0;
359
0
  unsigned int cfa_offset_size = 0;
360
0
  unsigned int bp_offset_size = 0;
361
0
  unsigned int ra_offset_size = 0;
362
363
0
  unsigned int fre_offset_size = 0;
364
365
  /* What size of offsets appear in this frame row entry.  */
366
0
  cfa_offset_size = get_offset_size_in_bytes (sframe_fre->cfa_offset);
367
0
  if (sframe_fre->bp_loc == SFRAME_FRE_ELEM_LOC_STACK)
368
0
    bp_offset_size = get_offset_size_in_bytes (sframe_fre->bp_offset);
369
#ifdef SFRAME_FRE_RA_TRACKING
370
  if (sframe_ra_tracking_p ()
371
      && sframe_fre->ra_loc == SFRAME_FRE_ELEM_LOC_STACK)
372
    ra_offset_size = get_offset_size_in_bytes (sframe_fre->ra_offset);
373
#endif
374
375
  /* Get the maximum size needed to represent the offsets.  */
376
0
  max_offset_size = cfa_offset_size;
377
0
  if (bp_offset_size > max_offset_size)
378
0
    max_offset_size = bp_offset_size;
379
0
  if (ra_offset_size > max_offset_size)
380
0
    max_offset_size = ra_offset_size;
381
382
0
  gas_assert (max_offset_size);
383
384
0
  switch (max_offset_size)
385
0
    {
386
0
    case 1:
387
0
      fre_offset_size = SFRAME_FRE_OFFSET_1B;
388
0
      break;
389
0
    case 2:
390
0
      fre_offset_size = SFRAME_FRE_OFFSET_2B;
391
0
      break;
392
0
    case 4:
393
0
      fre_offset_size = SFRAME_FRE_OFFSET_4B;
394
0
      break;
395
0
    default:
396
      /* Offset of size 8 bytes is not supported in SFrame format
397
   version 1.  */
398
0
      as_fatal (_("SFrame unsupported offset value\n"));
399
0
      break;
400
0
    }
401
402
0
  return fre_offset_size;
403
0
}
404
405
#if SFRAME_FRE_TYPE_SELECTION_OPT
406
407
/* Create a composite exression CEXP (for SFrame FRE start address) such that:
408
409
      exp = <val> OP_absent <width>, where,
410
411
    - <val> and <width> are themselves expressionS.
412
    - <val> stores the expression which when evaluated gives the value of the
413
      start address offset of the FRE.
414
    - <width> stores the expression when evaluated gives the number of bytes
415
      needed to encode the start address offset of the FRE.
416
417
   The use of OP_absent as the X_op_symbol helps identify this expression
418
   later when fragments are fixed up.  */
419
420
static void
421
create_fre_start_addr_exp (expressionS *cexp, symbolS *fre_pc_begin,
422
         symbolS *fde_start_address,
423
         symbolS *fde_end_address)
424
0
{
425
0
  expressionS val;
426
0
  expressionS width;
427
428
  /* val expression stores the FDE start address offset from the start PC
429
     of function.  */
430
0
  val.X_op = O_subtract;
431
0
  val.X_add_symbol = fre_pc_begin;
432
0
  val.X_op_symbol = fde_start_address;
433
0
  val.X_add_number = 0;
434
435
  /* width expressions stores the size of the function.  This is used later
436
     to determine the number of bytes to be used to encode the FRE start
437
     address of each FRE of the function.  */
438
0
  width.X_op = O_subtract;
439
0
  width.X_add_symbol = fde_end_address;
440
0
  width.X_op_symbol = fde_start_address;
441
0
  width.X_add_number = 0;
442
443
0
  cexp->X_op = O_absent;
444
0
  cexp->X_add_symbol = make_expr_symbol (&val);
445
0
  cexp->X_op_symbol = make_expr_symbol (&width);
446
0
  cexp->X_add_number = 0;
447
0
}
448
449
/* Create a composite exression CEXP (for SFrame FDE function info) such that:
450
451
      exp = <rest_of_func_info> OP_modulus <width>, where,
452
453
    - <rest_of_func_info> and <width> are themselves expressionS.
454
    - <rest_of_func_info> stores a constant expression where X_add_number is
455
    used to stash away the func_info.  The upper 4-bits of the func_info are copied
456
    back to the resulting byte by the fragment fixup logic.
457
    - <width> stores the expression when evaluated gives the size of the
458
    funtion in number of bytes.
459
460
   The use of OP_modulus as the X_op_symbol helps identify this expression
461
   later when fragments are fixed up.  */
462
463
static void
464
create_func_info_exp (expressionS *cexp, symbolS *dw_fde_end_addrS,
465
          symbolS *dw_fde_start_addrS, uint8_t func_info)
466
0
{
467
0
  expressionS width;
468
0
  expressionS rest_of_func_info;
469
470
0
  width.X_op = O_subtract;
471
0
  width.X_add_symbol = dw_fde_end_addrS;
472
0
  width.X_op_symbol = dw_fde_start_addrS;
473
0
  width.X_add_number = 0;
474
475
0
  rest_of_func_info.X_op = O_constant;
476
0
  rest_of_func_info.X_add_number = func_info;
477
478
0
  cexp->X_op = O_modulus;
479
0
  cexp->X_add_symbol = make_expr_symbol (&rest_of_func_info);
480
0
  cexp->X_op_symbol = make_expr_symbol (&width);
481
0
  cexp->X_add_number = 0;
482
0
}
483
484
#endif
485
486
static void
487
output_sframe_row_entry (symbolS *fde_start_addr,
488
       symbolS *fde_end_addr,
489
       struct sframe_row_entry *sframe_fre)
490
0
{
491
0
  unsigned char fre_info;
492
0
  unsigned int fre_num_offsets;
493
0
  unsigned int fre_offset_size;
494
0
  unsigned int fre_base_reg;
495
0
  expressionS exp;
496
0
  unsigned int fre_addr_size;
497
498
0
  unsigned int idx = 0;
499
0
  unsigned int fre_write_offsets = 0;
500
501
0
  fre_addr_size = 4; /* 4 bytes by default.   FIXME tie it to fre_type? */
502
503
  /* SFrame FRE Start Address.  */
504
0
#if SFRAME_FRE_TYPE_SELECTION_OPT
505
0
  create_fre_start_addr_exp (&exp, sframe_fre->pc_begin, fde_start_addr,
506
0
           fde_end_addr);
507
0
  frag_grow (fre_addr_size);
508
0
  frag_var (rs_sframe, fre_addr_size, 0, (relax_substateT) 0,
509
0
      make_expr_symbol (&exp), 0, (char *) frag_now);
510
#else
511
  gas_assert (fde_end_addr);
512
  exp.X_op = O_subtract;
513
  exp.X_add_symbol = sframe_fre->pc_begin; /* to.  */
514
  exp.X_op_symbol = fde_start_addr; /* from.  */
515
  exp.X_add_number = 0;
516
  emit_expr (&exp, fre_addr_size);
517
#endif
518
519
  /* Create the fre_info using the CFA base register, number of offsets and max
520
     size of offset in this frame row entry.  */
521
0
  fre_base_reg = get_fre_base_reg_id (sframe_fre);
522
0
  fre_num_offsets = get_fre_num_offsets (sframe_fre);
523
0
  fre_offset_size = sframe_get_fre_offset_size (sframe_fre);
524
0
  fre_info = sframe_set_fre_info (fre_base_reg, fre_num_offsets,
525
0
          fre_offset_size, sframe_fre->mangled_ra_p);
526
0
  out_one (fre_info);
527
528
0
  idx = sframe_fre_offset_func_map_index (fre_offset_size);
529
0
  gas_assert (idx < SFRAME_FRE_OFFSET_FUNC_MAP_INDEX_MAX);
530
531
  /* Write out the offsets in order - cfa, bp, ra.  */
532
0
  fre_offset_func_map[idx].out_func (sframe_fre->cfa_offset);
533
0
  fre_write_offsets++;
534
535
#ifdef SFRAME_FRE_RA_TRACKING
536
  if (sframe_fre->ra_loc == SFRAME_FRE_ELEM_LOC_STACK)
537
    {
538
      fre_offset_func_map[idx].out_func (sframe_fre->ra_offset);
539
      fre_write_offsets++;
540
    }
541
#endif
542
0
  if (sframe_fre->bp_loc == SFRAME_FRE_ELEM_LOC_STACK)
543
0
    {
544
0
      fre_offset_func_map[idx].out_func (sframe_fre->bp_offset);
545
0
      fre_write_offsets++;
546
0
    }
547
548
  /* Check if the expected number offsets have been written out
549
     in this FRE.  */
550
0
  gas_assert (fre_write_offsets == fre_num_offsets);
551
0
}
552
553
static void
554
output_sframe_funcdesc (symbolS *start_of_fre_section,
555
      symbolS *fre_symbol,
556
      struct sframe_func_entry *sframe_fde)
557
0
{
558
0
  expressionS exp;
559
0
  unsigned int addr_size;
560
0
  symbolS *dw_fde_start_addrS, *dw_fde_end_addrS;
561
0
  unsigned int pauth_key;
562
563
0
  addr_size = SFRAME_RELOC_SIZE;
564
0
  dw_fde_start_addrS = get_dw_fde_start_addrS (sframe_fde->dw_fde);
565
0
  dw_fde_end_addrS = get_dw_fde_end_addrS (sframe_fde->dw_fde);
566
567
  /* Start address of the function.  */
568
0
  exp.X_op = O_subtract;
569
0
  exp.X_add_symbol = dw_fde_start_addrS; /* to location.  */
570
0
  exp.X_op_symbol = symbol_temp_new_now (); /* from location.  */
571
0
  exp.X_add_number = 0;
572
0
  emit_expr (&exp, addr_size);
573
574
  /* Size of the function in bytes.  */
575
0
  exp.X_op = O_subtract;
576
0
  exp.X_add_symbol = dw_fde_end_addrS;
577
0
  exp.X_op_symbol = dw_fde_start_addrS;
578
0
  exp.X_add_number = 0;
579
0
  emit_expr (&exp, addr_size);
580
581
  /* Offset to the first frame row entry.  */
582
0
  exp.X_op = O_subtract;
583
0
  exp.X_add_symbol = fre_symbol; /* Minuend.  */
584
0
  exp.X_op_symbol = start_of_fre_section; /* Subtrahend.  */
585
0
  exp.X_add_number = 0;
586
0
  emit_expr (&exp, addr_size);
587
588
  /* Number of FREs.  */
589
0
  out_four (sframe_fde->num_fres);
590
591
  /* SFrame FDE function info.  */
592
0
  unsigned char func_info;
593
0
  pauth_key = (get_dw_fde_pauth_b_key_p (sframe_fde->dw_fde)
594
0
         ? SFRAME_AARCH64_PAUTH_KEY_B : SFRAME_AARCH64_PAUTH_KEY_A);
595
0
  func_info = sframe_set_func_info (SFRAME_FDE_TYPE_PCINC,
596
0
            SFRAME_FRE_TYPE_ADDR4,
597
0
            pauth_key);
598
0
#if SFRAME_FRE_TYPE_SELECTION_OPT
599
0
  expressionS cexp;
600
0
  create_func_info_exp (&cexp, dw_fde_end_addrS, dw_fde_start_addrS,
601
0
      func_info);
602
0
  frag_grow (1); /* Size of func info is unsigned char.  */
603
0
  frag_var (rs_sframe, 1, 0, (relax_substateT) 0,
604
0
      make_expr_symbol (&cexp), 0, (char *) frag_now);
605
#else
606
  out_one (func_info);
607
#endif
608
0
}
609
610
static void
611
output_sframe_internal (void)
612
0
{
613
0
  expressionS exp;
614
0
  unsigned int i = 0;
615
616
0
  symbolS *end_of_frame_hdr;
617
0
  symbolS *end_of_frame_section;
618
0
  symbolS *start_of_func_desc_section;
619
0
  symbolS *start_of_fre_section;
620
0
  struct sframe_func_entry *sframe_fde;
621
0
  struct sframe_row_entry *sframe_fre;
622
0
  unsigned char abi_arch = 0;
623
0
  int fixed_bp_offset = SFRAME_CFA_FIXED_FP_INVALID;
624
0
  int fixed_ra_offset = SFRAME_CFA_FIXED_RA_INVALID;
625
0
  unsigned int addr_size;
626
627
0
  addr_size = SFRAME_RELOC_SIZE;
628
629
  /* The function desciptor entries as dumped by the assembler are not
630
     sorted on PCs.  */
631
0
  unsigned char sframe_flags = 0;
632
0
  sframe_flags |= !SFRAME_F_FDE_SORTED;
633
634
0
  unsigned int num_fdes = get_num_sframe_fdes ();
635
0
  unsigned int num_fres = get_num_sframe_fres ();
636
0
  symbolS **fre_symbols = XNEWVEC (symbolS *, num_fres);
637
0
  for (i = 0; i < num_fres; i++)
638
0
    fre_symbols[i] = symbol_temp_make ();
639
640
0
  end_of_frame_hdr = symbol_temp_make ();
641
0
  start_of_fre_section = symbol_temp_make ();
642
0
  start_of_func_desc_section = symbol_temp_make ();
643
0
  end_of_frame_section = symbol_temp_make ();
644
645
  /* Output the preamble of SFrame section.  */
646
0
  out_two (SFRAME_MAGIC);
647
0
  out_one (SFRAME_VERSION);
648
0
  out_one (sframe_flags);
649
  /* abi/arch.  */
650
0
#ifdef sframe_get_abi_arch
651
0
  abi_arch = sframe_get_abi_arch ();
652
0
#endif
653
0
  gas_assert (abi_arch);
654
0
  out_one (abi_arch);
655
656
  /* Offset for the BP register from CFA.  Neither of the AMD64 or AAPCS64
657
     ABIs have a fixed offset for the BP register from the CFA.  This may be
658
     useful in future (but not without additional support in the toolchain)
659
     for specialized handling/encoding for cases where, for example,
660
     -fno-omit-frame-pointer is used.  */
661
0
  out_one (fixed_bp_offset);
662
663
  /* Offset for the return address from CFA is fixed for some ABIs
664
     (e.g., AMD64), output a SFRAME_CFA_FIXED_RA_INVALID otherwise.  */
665
0
#ifdef sframe_ra_tracking_p
666
0
  if (!sframe_ra_tracking_p ())
667
0
    fixed_ra_offset = sframe_cfa_ra_offset ();
668
0
#endif
669
0
  out_one (fixed_ra_offset);
670
671
  /* None of the AMD64, or AARCH64 ABIs need the auxilliary header.
672
     When the need does arise to use this field, the appropriate backend
673
     must provide this information.  */
674
0
  out_one (0); /* Auxilliary SFrame header length.  */
675
676
0
  out_four (num_fdes); /* Number of FDEs.  */
677
0
  out_four (num_fres); /* Number of FREs.  */
678
679
  /* FRE sub-section len.  */
680
0
  exp.X_op = O_subtract;
681
0
  exp.X_add_symbol = end_of_frame_section;
682
0
  exp.X_op_symbol = start_of_fre_section;
683
0
  exp.X_add_number = 0;
684
0
  emit_expr (&exp, addr_size);
685
686
  /* Offset of Function Index sub-section.  */
687
0
  exp.X_op = O_subtract;
688
0
  exp.X_add_symbol = end_of_frame_hdr;
689
0
  exp.X_op_symbol = start_of_func_desc_section;
690
0
  exp.X_add_number = 0;
691
0
  emit_expr (&exp, addr_size);
692
693
  /* Offset of FRE sub-section.  */
694
0
  exp.X_op = O_subtract;
695
0
  exp.X_add_symbol = start_of_fre_section;
696
0
  exp.X_op_symbol = end_of_frame_hdr;
697
0
  exp.X_add_number = 0;
698
0
  emit_expr (&exp, addr_size);
699
700
0
  symbol_set_value_now (end_of_frame_hdr);
701
0
  symbol_set_value_now (start_of_func_desc_section);
702
703
  /* Output the SFrame function descriptor entries.  */
704
0
  i = 0;
705
0
  for (sframe_fde = all_sframe_fdes; sframe_fde; sframe_fde = sframe_fde->next)
706
0
    {
707
0
      output_sframe_funcdesc (start_of_fre_section,
708
0
            fre_symbols[i], sframe_fde);
709
0
      i += sframe_fde->num_fres;
710
0
    }
711
712
0
  symbol_set_value_now (start_of_fre_section);
713
714
  /* Output the SFrame FREs.  */
715
0
  i = 0;
716
0
  sframe_fde = all_sframe_fdes;
717
718
0
  for (sframe_fde = all_sframe_fdes; sframe_fde; sframe_fde = sframe_fde->next)
719
0
    {
720
0
      for (sframe_fre = sframe_fde->sframe_fres;
721
0
     sframe_fre;
722
0
     sframe_fre = sframe_fre->next)
723
0
  {
724
0
    symbol_set_value_now (fre_symbols[i]);
725
0
    output_sframe_row_entry (get_dw_fde_start_addrS (sframe_fde->dw_fde),
726
0
           get_dw_fde_end_addrS (sframe_fde->dw_fde),
727
0
           sframe_fre);
728
0
    i++;
729
0
  }
730
0
    }
731
732
0
  symbol_set_value_now (end_of_frame_section);
733
734
0
  gas_assert (i == num_fres);
735
736
0
  free (fre_symbols);
737
0
  fre_symbols = NULL;
738
0
}
739
740
/* List of SFrame FDE entries.  */
741
742
struct sframe_func_entry *all_sframe_fdes;
743
744
/* Tail of the list to add to.  */
745
746
static struct sframe_func_entry **last_sframe_fde = &all_sframe_fdes;
747
748
static unsigned int
749
get_num_sframe_fdes (void)
750
0
{
751
0
  struct sframe_func_entry *sframe_fde;
752
0
  unsigned int total_fdes = 0;
753
754
0
  for (sframe_fde = all_sframe_fdes; sframe_fde ; sframe_fde = sframe_fde->next)
755
0
    total_fdes++;
756
757
0
  return total_fdes;
758
0
}
759
760
/* Get the total number of SFrame row entries across the FDEs.  */
761
762
static unsigned int
763
get_num_sframe_fres (void)
764
0
{
765
0
  struct sframe_func_entry *sframe_fde;
766
0
  unsigned int total_fres = 0;
767
768
0
  for (sframe_fde = all_sframe_fdes; sframe_fde ; sframe_fde = sframe_fde->next)
769
0
    total_fres += sframe_fde->num_fres;
770
771
0
  return total_fres;
772
0
}
773
774
/* Allocate an SFrame FDE.  */
775
776
static struct sframe_func_entry*
777
sframe_fde_alloc (void)
778
0
{
779
0
  struct sframe_func_entry *sframe_fde = XCNEW (struct sframe_func_entry);
780
0
  return sframe_fde;
781
0
}
782
783
/* Link the SFrame FDE in.  */
784
785
static int
786
sframe_fde_link (struct sframe_func_entry *sframe_fde)
787
0
{
788
0
  *last_sframe_fde = sframe_fde;
789
0
  last_sframe_fde = &sframe_fde->next;
790
791
0
  return 0;
792
0
}
793
794
/* Free up the SFrame FDE.  */
795
796
static void
797
sframe_fde_free (struct sframe_func_entry *sframe_fde)
798
0
{
799
0
  XDELETE (sframe_fde);
800
0
  sframe_fde = NULL;
801
0
}
802
803
/* SFrame translation context functions.  */
804
805
/* Allocate a new SFrame translation context.  */
806
807
static struct sframe_xlate_ctx*
808
sframe_xlate_ctx_alloc (void)
809
0
{
810
0
  struct sframe_xlate_ctx* xlate_ctx = XCNEW (struct sframe_xlate_ctx);
811
0
  return xlate_ctx;
812
0
}
813
814
/* Initialize the given SFrame translation context.  */
815
816
static void
817
sframe_xlate_ctx_init (struct sframe_xlate_ctx *xlate_ctx)
818
0
{
819
0
  xlate_ctx->dw_fde = NULL;
820
0
  xlate_ctx->first_fre = NULL;
821
0
  xlate_ctx->last_fre = NULL;
822
0
  xlate_ctx->cur_fre = NULL;
823
0
  xlate_ctx->remember_fre = NULL;
824
0
  xlate_ctx->num_xlate_fres = 0;
825
0
}
826
827
/* Cleanup the given SFrame translation context.  */
828
829
static void
830
sframe_xlate_ctx_cleanup (struct sframe_xlate_ctx *xlate_ctx)
831
0
{
832
0
  struct sframe_row_entry *fre, *fre_next;
833
834
0
  if (xlate_ctx->num_xlate_fres)
835
0
    {
836
0
      fre = xlate_ctx->first_fre;
837
0
      while (fre)
838
0
  {
839
0
    fre_next = fre->next;
840
0
    XDELETE (fre);
841
0
    fre = fre_next;
842
0
  }
843
0
    }
844
845
0
  sframe_xlate_ctx_init (xlate_ctx);
846
0
}
847
848
/* Transfer the state from the SFrame translation context to the SFrame FDE.  */
849
850
static void
851
sframe_xlate_ctx_finalize (struct sframe_xlate_ctx *xlate_ctx,
852
         struct sframe_func_entry *sframe_fde)
853
0
{
854
0
  sframe_fde->dw_fde = xlate_ctx->dw_fde;
855
0
  sframe_fde->sframe_fres = xlate_ctx->first_fre;
856
0
  sframe_fde->num_fres = xlate_ctx->num_xlate_fres;
857
0
}
858
859
static struct sframe_row_entry*
860
sframe_row_entry_new (void)
861
0
{
862
0
  struct sframe_row_entry *fre = XCNEW (struct sframe_row_entry);
863
  /* Reset cfa_base_reg to -1.  A value of 0 will imply some valid register
864
     for the supported arches.  */
865
0
  fre->cfa_base_reg = -1;
866
0
  fre->merge_candidate = true;
867
  /* Reset the mangled RA status bit to zero by default.  We will initialize it in
868
     sframe_row_entry_initialize () with the sticky bit if set.  */
869
0
  fre->mangled_ra_p = false;
870
871
0
  return fre;
872
0
}
873
874
/* Add the given FRE in the list of frame row entries in the given FDE
875
   translation context.  */
876
877
static void
878
sframe_xlate_ctx_add_fre (struct sframe_xlate_ctx *xlate_ctx,
879
       struct sframe_row_entry *fre)
880
0
{
881
0
  gas_assert (xlate_ctx && fre);
882
883
  /* Add the frame row entry.  */
884
0
  if (!xlate_ctx->first_fre)
885
0
    xlate_ctx->first_fre = fre;
886
0
  else if (xlate_ctx->last_fre)
887
0
    xlate_ctx->last_fre->next = fre;
888
889
0
  xlate_ctx->last_fre = fre;
890
891
  /* Keep track of the total number of SFrame frame row entries.  */
892
0
  xlate_ctx->num_xlate_fres++;
893
0
}
894
895
/* A SFrame Frame Row Entry is self-sufficient in terms of stack tracing info
896
   for a given PC.  It contains information assimilated from multiple CFI
897
   instructions, and hence, a new SFrame FRE is initialized with the data from
898
   the previous known FRE, if any.
899
900
   Understandably, not all information (especially the instruction begin
901
   and end boundaries) needs to be relayed.  Hence, the caller of this API
902
   must set the pc_begin and pc_end as applicable.  */
903
904
static void
905
sframe_row_entry_initialize (struct sframe_row_entry *cur_fre,
906
           struct sframe_row_entry *prev_fre)
907
0
{
908
0
  gas_assert (prev_fre);
909
0
  cur_fre->cfa_base_reg = prev_fre->cfa_base_reg;
910
0
  cur_fre->cfa_offset = prev_fre->cfa_offset;
911
0
  cur_fre->bp_loc = prev_fre->bp_loc;
912
0
  cur_fre->bp_offset = prev_fre->bp_offset;
913
0
  cur_fre->ra_loc = prev_fre->ra_loc;
914
0
  cur_fre->ra_offset = prev_fre->ra_offset;
915
  /* Treat RA mangling as a sticky bit.  It retains its value until another
916
     .cfi_negate_ra_state is seen.  */
917
0
  cur_fre->mangled_ra_p = prev_fre->mangled_ra_p;
918
0
}
919
920
/* Translate DW_CFA_advance_loc into SFrame context.
921
   Return SFRAME_XLATE_OK if success.  */
922
923
static int
924
sframe_xlate_do_advance_loc (struct sframe_xlate_ctx *xlate_ctx,
925
           struct cfi_insn_data *cfi_insn)
926
0
{
927
0
  struct sframe_row_entry *last_fre = xlate_ctx->last_fre;
928
  /* Get the scratchpad FRE currently being updated as the cfi_insn's
929
     get interpreted.  This FRE eventually gets linked in into the
930
     list of FREs for the specific function.  */
931
0
  struct sframe_row_entry *cur_fre = xlate_ctx->cur_fre;
932
933
0
  if (cur_fre)
934
0
    {
935
0
      if (!cur_fre->merge_candidate)
936
0
  {
937
0
    sframe_fre_set_end_addr (cur_fre, cfi_insn->u.ll.lab2);
938
939
0
    sframe_xlate_ctx_add_fre (xlate_ctx, cur_fre);
940
0
    last_fre = xlate_ctx->last_fre;
941
942
0
    xlate_ctx->cur_fre = sframe_row_entry_new ();
943
0
    cur_fre = xlate_ctx->cur_fre;
944
945
0
    if (last_fre)
946
0
      sframe_row_entry_initialize (cur_fre, last_fre);
947
0
  }
948
0
      else
949
0
  {
950
0
    sframe_fre_set_end_addr (last_fre, cfi_insn->u.ll.lab2);
951
0
    gas_assert (last_fre->merge_candidate == false);
952
0
  }
953
0
    }
954
0
  else
955
0
    {
956
0
      xlate_ctx->cur_fre = sframe_row_entry_new ();
957
0
      cur_fre = xlate_ctx->cur_fre;
958
0
    }
959
960
0
  gas_assert (cur_fre);
961
0
  sframe_fre_set_begin_addr (cur_fre, cfi_insn->u.ll.lab2);
962
963
0
  return SFRAME_XLATE_OK;
964
0
}
965
966
/* Translate DW_CFA_def_cfa into SFrame context.
967
   Return SFRAME_XLATE_OK if success.  */
968
969
static int
970
sframe_xlate_do_def_cfa (struct sframe_xlate_ctx *xlate_ctx,
971
       struct cfi_insn_data *cfi_insn)
972
973
0
{
974
  /* Get the scratchpad FRE.  This FRE will eventually get linked in.  */
975
0
  struct sframe_row_entry *cur_fre = xlate_ctx->cur_fre;
976
0
  if (!cur_fre)
977
0
  {
978
0
    xlate_ctx->cur_fre = sframe_row_entry_new ();
979
0
    cur_fre = xlate_ctx->cur_fre;
980
0
    sframe_fre_set_begin_addr (cur_fre,
981
0
             get_dw_fde_start_addrS (xlate_ctx->dw_fde));
982
0
  }
983
  /* Define the current CFA rule to use the provided register and
984
     offset.  */
985
0
  sframe_fre_set_cfa_base_reg (cur_fre, cfi_insn->u.ri.reg);
986
0
  sframe_fre_set_cfa_offset (cur_fre, cfi_insn->u.ri.offset);
987
0
  cur_fre->merge_candidate = false;
988
989
0
  return SFRAME_XLATE_OK;
990
0
}
991
992
/* Translate DW_CFA_def_cfa_register into SFrame context.
993
   Return SFRAME_XLATE_OK if success.  */
994
995
static int
996
sframe_xlate_do_def_cfa_register (struct sframe_xlate_ctx *xlate_ctx,
997
          struct cfi_insn_data *cfi_insn)
998
0
{
999
0
  struct sframe_row_entry *last_fre = xlate_ctx->last_fre;
1000
  /* Get the scratchpad FRE.  This FRE will eventually get linked in.  */
1001
0
  struct sframe_row_entry *cur_fre = xlate_ctx->cur_fre;
1002
0
  gas_assert (cur_fre);
1003
  /* Define the current CFA rule to use the provided register (but to
1004
     keep the old offset).  */
1005
0
  sframe_fre_set_cfa_base_reg (cur_fre, cfi_insn->u.ri.reg);
1006
0
  sframe_fre_set_cfa_offset (cur_fre, last_fre->cfa_offset);
1007
0
  cur_fre->merge_candidate = false;
1008
1009
0
  return SFRAME_XLATE_OK;
1010
0
}
1011
1012
/* Translate DW_CFA_def_cfa_offset into SFrame context.
1013
   Return SFRAME_XLATE_OK if success.  */
1014
1015
static int
1016
sframe_xlate_do_def_cfa_offset (struct sframe_xlate_ctx *xlate_ctx,
1017
        struct cfi_insn_data *cfi_insn)
1018
0
{
1019
  /* The scratchpad FRE currently being updated with each cfi_insn
1020
     being interpreted.  This FRE eventually gets linked in into the
1021
     list of FREs for the specific function.  */
1022
0
  struct sframe_row_entry *cur_fre = xlate_ctx->cur_fre;
1023
1024
0
  gas_assert (cur_fre);
1025
  /*  Define the current CFA rule to use the provided offset (but to keep
1026
      the old register).  However, if the old register is not FP/SP,
1027
      skip creating SFrame stack trace info for the function.  */
1028
0
  if ((cur_fre->cfa_base_reg == SFRAME_CFA_FP_REG)
1029
0
      || (cur_fre->cfa_base_reg == SFRAME_CFA_SP_REG))
1030
0
    {
1031
0
      sframe_fre_set_cfa_offset (cur_fre, cfi_insn->u.i);
1032
0
      cur_fre->merge_candidate = false;
1033
0
    }
1034
0
  else
1035
0
    return SFRAME_XLATE_ERR_NOTREPRESENTED;
1036
1037
0
  return SFRAME_XLATE_OK;
1038
0
}
1039
1040
/* Translate DW_CFA_offset into SFrame context.
1041
   Return SFRAME_XLATE_OK if success.  */
1042
1043
static int
1044
sframe_xlate_do_offset (struct sframe_xlate_ctx *xlate_ctx,
1045
      struct cfi_insn_data *cfi_insn)
1046
0
{
1047
  /* The scratchpad FRE currently being updated with each cfi_insn
1048
     being interpreted.  This FRE eventually gets linked in into the
1049
     list of FREs for the specific function.  */
1050
0
  struct sframe_row_entry *cur_fre = xlate_ctx->cur_fre;
1051
1052
0
  gas_assert (cur_fre);
1053
  /* Change the rule for the register indicated by the register number to
1054
     be the specified offset.  */
1055
0
  if (cfi_insn->u.r == SFRAME_CFA_FP_REG)
1056
0
    {
1057
0
      gas_assert (!cur_fre->base_reg);
1058
0
      sframe_fre_set_bp_track (cur_fre, cfi_insn->u.ri.offset);
1059
0
      cur_fre->merge_candidate = false;
1060
0
    }
1061
#ifdef SFRAME_FRE_RA_TRACKING
1062
  else if (sframe_ra_tracking_p ()
1063
     && cfi_insn->u.r == SFRAME_CFA_RA_REG)
1064
    {
1065
      sframe_fre_set_ra_track (cur_fre, cfi_insn->u.ri.offset);
1066
      cur_fre->merge_candidate = false;
1067
    }
1068
#endif
1069
  /* This is used to track changes to non-rsp registers, skip all others
1070
     except FP / RA for now.  */
1071
0
  return SFRAME_XLATE_OK;
1072
0
}
1073
1074
/* Translate DW_CFA_val_offset into SFrame context.
1075
   Return SFRAME_XLATE_OK if success.  */
1076
1077
static int
1078
sframe_xlate_do_val_offset (struct sframe_xlate_ctx *xlate_ctx ATTRIBUTE_UNUSED,
1079
          struct cfi_insn_data *cfi_insn)
1080
0
{
1081
  /* Previous value of register is CFA + offset.  However, if the specified
1082
     register is not interesting (FP or RA reg), the current DW_CFA_val_offset
1083
     instruction can be safely skipped without sacrificing the asynchonicity of
1084
     stack trace information.  */
1085
0
  if (cfi_insn->u.r == SFRAME_CFA_FP_REG)
1086
0
    return SFRAME_XLATE_ERR_NOTREPRESENTED; /* Not represented.  */
1087
#ifdef SFRAME_FRE_RA_TRACKING
1088
  else if (sframe_ra_tracking_p ()
1089
     && cfi_insn->u.r == SFRAME_CFA_RA_REG)
1090
    return SFRAME_XLATE_ERR_NOTREPRESENTED; /* Not represented.  */
1091
#endif
1092
1093
  /* Safe to skip.  */
1094
0
  return SFRAME_XLATE_OK;
1095
0
}
1096
1097
/* Translate DW_CFA_remember_state into SFrame context.
1098
   Return SFRAME_XLATE_OK if success.  */
1099
1100
static int
1101
sframe_xlate_do_remember_state (struct sframe_xlate_ctx *xlate_ctx)
1102
0
{
1103
0
  struct sframe_row_entry *last_fre = xlate_ctx->last_fre;
1104
1105
  /* If there is no FRE state to remember, nothing to do here.  Return
1106
     early with non-zero error code, this will cause no SFrame stack trace
1107
     info for the function involved.  */
1108
0
  if (!last_fre)
1109
0
    return SFRAME_XLATE_ERR_INVAL;
1110
1111
0
  if (!xlate_ctx->remember_fre)
1112
0
    xlate_ctx->remember_fre = sframe_row_entry_new ();
1113
0
  sframe_row_entry_initialize (xlate_ctx->remember_fre, last_fre);
1114
1115
0
  return SFRAME_XLATE_OK;
1116
0
}
1117
1118
/* Translate DW_CFA_restore_state into SFrame context.
1119
   Return SFRAME_XLATE_OK if success.  */
1120
1121
static int
1122
sframe_xlate_do_restore_state (struct sframe_xlate_ctx *xlate_ctx)
1123
0
{
1124
  /* The scratchpad FRE currently being updated with each cfi_insn
1125
     being interpreted.  This FRE eventually gets linked in into the
1126
     list of FREs for the specific function.  */
1127
0
  struct sframe_row_entry *cur_fre = xlate_ctx->cur_fre;
1128
1129
0
  gas_assert (xlate_ctx->remember_fre);
1130
0
  gas_assert (cur_fre && cur_fre->merge_candidate);
1131
1132
  /* Get the CFA state from the DW_CFA_remember_state insn.  */
1133
0
  sframe_row_entry_initialize (cur_fre, xlate_ctx->remember_fre);
1134
  /* The PC boundaries of the current SFrame FRE are updated
1135
     via other machinery.  */
1136
0
  cur_fre->merge_candidate = false;
1137
0
  return SFRAME_XLATE_OK;
1138
0
}
1139
1140
/* Translate DW_CFA_restore into SFrame context.
1141
   Return SFRAME_XLATE_OK if success.  */
1142
1143
static int
1144
sframe_xlate_do_restore (struct sframe_xlate_ctx *xlate_ctx,
1145
       struct cfi_insn_data *cfi_insn)
1146
0
{
1147
0
  struct sframe_row_entry *cie_fre = xlate_ctx->first_fre;
1148
  /* The scratchpad FRE currently being updated with each cfi_insn
1149
     being interpreted.  This FRE eventually gets linked in into the
1150
     list of FREs for the specific function.  */
1151
0
  struct sframe_row_entry *cur_fre = xlate_ctx->cur_fre;
1152
1153
  /* Change the rule for the indicated register to the rule assigned to
1154
     it by the initial_instructions in the CIE.  */
1155
0
  gas_assert (cie_fre);
1156
  /* SFrame FREs track only CFA and FP / RA for backtracing purposes;
1157
     skip the other .cfi_restore directives.  */
1158
0
  if (cfi_insn->u.r == SFRAME_CFA_FP_REG)
1159
0
    {
1160
0
      gas_assert (cur_fre);
1161
0
      cur_fre->bp_loc = cie_fre->bp_loc;
1162
0
      cur_fre->bp_offset = cie_fre->bp_offset;
1163
0
      cur_fre->merge_candidate = false;
1164
0
    }
1165
#ifdef SFRAME_FRE_RA_TRACKING
1166
  else if (sframe_ra_tracking_p ()
1167
     && cfi_insn->u.r == SFRAME_CFA_RA_REG)
1168
    {
1169
      gas_assert (cur_fre);
1170
      cur_fre->ra_loc = cie_fre->ra_loc;
1171
      cur_fre->ra_offset = cie_fre->ra_offset;
1172
      cur_fre->merge_candidate = false;
1173
    }
1174
#endif
1175
0
  return SFRAME_XLATE_OK;
1176
0
}
1177
1178
/* Translate DW_CFA_GNU_window_save into SFrame context.
1179
   Return SFRAME_XLATE_OK if success.  */
1180
1181
static int
1182
sframe_xlate_do_gnu_window_save (struct sframe_xlate_ctx *xlate_ctx,
1183
         struct cfi_insn_data *cfi_insn ATTRIBUTE_UNUSED)
1184
0
{
1185
0
  struct sframe_row_entry *cur_fre = xlate_ctx->cur_fre;
1186
1187
0
  gas_assert (cur_fre);
1188
  /* Toggle the mangled RA status bit.  */
1189
0
  cur_fre->mangled_ra_p = !cur_fre->mangled_ra_p;
1190
0
  cur_fre->merge_candidate = false;
1191
1192
0
  return SFRAME_XLATE_OK;
1193
0
}
1194
1195
/* Process CFI_INSN and update the translation context with the FRE
1196
   information.
1197
1198
   Returns an error code (sframe_xlate_err) if CFI_INSN is not successfully
1199
   processed.  */
1200
1201
static int
1202
sframe_do_cfi_insn (struct sframe_xlate_ctx *xlate_ctx,
1203
        struct cfi_insn_data *cfi_insn)
1204
0
{
1205
0
  int err = 0;
1206
1207
  /* Atleast one cfi_insn per FDE is expected.  */
1208
0
  gas_assert (cfi_insn);
1209
0
  int op = cfi_insn->insn;
1210
1211
0
  switch (op)
1212
0
    {
1213
0
    case DW_CFA_advance_loc:
1214
0
      err = sframe_xlate_do_advance_loc (xlate_ctx, cfi_insn);
1215
0
      break;
1216
0
    case DW_CFA_def_cfa:
1217
0
      err = sframe_xlate_do_def_cfa (xlate_ctx, cfi_insn);
1218
0
      break;
1219
0
    case DW_CFA_def_cfa_register:
1220
0
      err = sframe_xlate_do_def_cfa_register (xlate_ctx, cfi_insn);
1221
0
      break;
1222
0
    case DW_CFA_def_cfa_offset:
1223
0
      err = sframe_xlate_do_def_cfa_offset (xlate_ctx, cfi_insn);
1224
0
      break;
1225
0
    case DW_CFA_offset:
1226
0
      err = sframe_xlate_do_offset (xlate_ctx, cfi_insn);
1227
0
      break;
1228
0
    case DW_CFA_val_offset:
1229
0
      err = sframe_xlate_do_val_offset (xlate_ctx, cfi_insn);
1230
0
      break;
1231
0
    case DW_CFA_remember_state:
1232
0
      err = sframe_xlate_do_remember_state (xlate_ctx);
1233
0
      break;
1234
0
    case DW_CFA_restore_state:
1235
0
      err = sframe_xlate_do_restore_state (xlate_ctx);
1236
0
      break;
1237
0
    case DW_CFA_restore:
1238
0
      err = sframe_xlate_do_restore (xlate_ctx, cfi_insn);
1239
0
      break;
1240
    /* DW_CFA_AARCH64_negate_ra_state is multiplexed with
1241
       DW_CFA_GNU_window_save.  */
1242
0
    case DW_CFA_GNU_window_save:
1243
0
      err = sframe_xlate_do_gnu_window_save (xlate_ctx, cfi_insn);
1244
0
      break;
1245
0
    case DW_CFA_undefined:
1246
0
    case DW_CFA_same_value:
1247
0
      break;
1248
0
    default:
1249
0
      {
1250
  /* Other CFI opcodes are not processed at this time.
1251
     These do not impact the coverage of the basic stack tracing
1252
     information as conveyed in the SFrame format.
1253
      - DW_CFA_register,
1254
      - ...
1255
1256
     Following skipped operations do, however, impact the asynchronicity:
1257
       - CFI_escape  */
1258
1259
0
  err = SFRAME_XLATE_ERR_NOTREPRESENTED;
1260
  // printf (_("SFrame Unsupported or unknown Dwarf CFI number: %#x\n"), op);
1261
0
      }
1262
0
    }
1263
1264
0
  return err;
1265
0
}
1266
1267
1268
static int
1269
sframe_do_fde (struct sframe_xlate_ctx *xlate_ctx,
1270
         const struct fde_entry *dw_fde)
1271
0
{
1272
0
  struct cfi_insn_data *cfi_insn;
1273
0
  int err = SFRAME_XLATE_OK;
1274
1275
0
  xlate_ctx->dw_fde = dw_fde;
1276
1277
  /* If the return column is not RIP, SFrame format cannot represent it.  */
1278
0
  if (xlate_ctx->dw_fde->return_column != DWARF2_DEFAULT_RETURN_COLUMN)
1279
0
    return SFRAME_XLATE_ERR_NOTREPRESENTED;
1280
1281
  /* Iterate over the CFIs and create SFrame FREs.  */
1282
0
  for (cfi_insn = dw_fde->data; cfi_insn; cfi_insn = cfi_insn->next)
1283
0
    {
1284
      /* Translate each CFI, and buffer the state in translation context.  */
1285
0
      err = sframe_do_cfi_insn (xlate_ctx, cfi_insn);
1286
0
      if (err != SFRAME_XLATE_OK)
1287
0
  {
1288
    /* Skip generating SFrame stack trace info for the function if any
1289
       offending CFI is encountered by sframe_do_cfi_insn ().  */
1290
0
    return err; /* Return the error code.  */
1291
0
  }
1292
0
    }
1293
1294
  /* No errors encountered.  */
1295
1296
  /* Link in the scratchpad FRE that the last few CFI insns helped create.  */
1297
0
  if (xlate_ctx->cur_fre)
1298
0
    {
1299
0
      sframe_xlate_ctx_add_fre (xlate_ctx, xlate_ctx->cur_fre);
1300
0
      xlate_ctx->cur_fre = NULL;
1301
0
    }
1302
  /* Designate the end of the last SFrame FRE.  */
1303
0
  if (xlate_ctx->last_fre)
1304
0
    {
1305
0
      xlate_ctx->last_fre->pc_end
1306
0
  = get_dw_fde_end_addrS (xlate_ctx->dw_fde);
1307
0
    }
1308
1309
0
  return SFRAME_XLATE_OK;
1310
0
}
1311
1312
/* Create SFrame stack trace info for all functions.
1313
1314
   This function consumes the already generated DWARF FDEs (by dw2gencfi) and
1315
   generates data which is later emitted as stack trace information encoded in
1316
   the SFrame format.  */
1317
1318
static void
1319
create_sframe_all (void)
1320
0
{
1321
0
  struct fde_entry *dw_fde = NULL;
1322
0
  struct sframe_func_entry *sframe_fde = NULL;
1323
1324
0
  struct sframe_xlate_ctx *xlate_ctx = sframe_xlate_ctx_alloc ();
1325
1326
0
  for (dw_fde = all_fde_data; dw_fde ; dw_fde = dw_fde->next)
1327
0
    {
1328
0
      sframe_fde = sframe_fde_alloc ();
1329
      /* Initialize the translation context with information anew.  */
1330
0
      sframe_xlate_ctx_init (xlate_ctx);
1331
1332
      /* Process and link SFrame FDEs if no error.  Also skip adding an SFrame
1333
   FDE if it does not contain any SFrame FREs.  There is little use of an
1334
   SFrame FDE if there is no stack tracing information for the
1335
   function.  */
1336
0
      int err = sframe_do_fde (xlate_ctx, dw_fde);
1337
0
      if (err || xlate_ctx->num_xlate_fres == 0)
1338
0
  {
1339
0
    sframe_xlate_ctx_cleanup (xlate_ctx);
1340
0
    sframe_fde_free (sframe_fde);
1341
0
  }
1342
0
      else
1343
0
  {
1344
    /* All done.  Transfer the state from the SFrame translation
1345
       context to the SFrame FDE.  */
1346
0
    sframe_xlate_ctx_finalize (xlate_ctx, sframe_fde);
1347
0
    sframe_fde_link (sframe_fde);
1348
0
  }
1349
0
    }
1350
0
}
1351
1352
void
1353
output_sframe (segT sframe_seg)
1354
0
{
1355
0
  (void) sframe_seg;
1356
1357
  /* Setup the version specific access functions.  */
1358
0
  sframe_set_version (SFRAME_VERSION_1);
1359
1360
  /* Process all fdes and create SFrame stack trace information.  */
1361
0
  create_sframe_all ();
1362
1363
0
  output_sframe_internal ();
1364
0
}
1365
1366
#else  /*  support_sframe_p  */
1367
1368
void
1369
output_sframe (segT sframe_seg ATTRIBUTE_UNUSED)
1370
{
1371
}
1372
1373
#endif /*  support_sframe_p  */