Coverage Report

Created: 2024-05-21 06:29

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