Coverage Report

Created: 2023-08-28 06:31

/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_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 exression 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 exression 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
    funtion 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_bp_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 desciptor 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 BP register from CFA.  Neither of the AMD64 or AAPCS64
662
     ABIs have a fixed offset for the BP 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_bp_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 auxilliary header.
677
     When the need does arise to use this field, the appropriate backend
678
     must provide this information.  */
679
0
  out_one (0); /* Auxilliary 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
  sframe_xlate_ctx_init (xlate_ctx);
851
0
}
852
853
/* Transfer the state from the SFrame translation context to the SFrame FDE.  */
854
855
static void
856
sframe_xlate_ctx_finalize (struct sframe_xlate_ctx *xlate_ctx,
857
         struct sframe_func_entry *sframe_fde)
858
0
{
859
0
  sframe_fde->dw_fde = xlate_ctx->dw_fde;
860
0
  sframe_fde->sframe_fres = xlate_ctx->first_fre;
861
0
  sframe_fde->num_fres = xlate_ctx->num_xlate_fres;
862
0
}
863
864
static struct sframe_row_entry*
865
sframe_row_entry_new (void)
866
0
{
867
0
  struct sframe_row_entry *fre = XCNEW (struct sframe_row_entry);
868
  /* Reset cfa_base_reg to -1.  A value of 0 will imply some valid register
869
     for the supported arches.  */
870
0
  fre->cfa_base_reg = -1;
871
0
  fre->merge_candidate = true;
872
  /* Reset the mangled RA status bit to zero by default.  We will initialize it in
873
     sframe_row_entry_initialize () with the sticky bit if set.  */
874
0
  fre->mangled_ra_p = false;
875
876
0
  return fre;
877
0
}
878
879
/* Add the given FRE in the list of frame row entries in the given FDE
880
   translation context.  */
881
882
static void
883
sframe_xlate_ctx_add_fre (struct sframe_xlate_ctx *xlate_ctx,
884
       struct sframe_row_entry *fre)
885
0
{
886
0
  gas_assert (xlate_ctx && fre);
887
888
  /* Add the frame row entry.  */
889
0
  if (!xlate_ctx->first_fre)
890
0
    xlate_ctx->first_fre = fre;
891
0
  else if (xlate_ctx->last_fre)
892
0
    xlate_ctx->last_fre->next = fre;
893
894
0
  xlate_ctx->last_fre = fre;
895
896
  /* Keep track of the total number of SFrame frame row entries.  */
897
0
  xlate_ctx->num_xlate_fres++;
898
0
}
899
900
/* A SFrame Frame Row Entry is self-sufficient in terms of stack tracing info
901
   for a given PC.  It contains information assimilated from multiple CFI
902
   instructions, and hence, a new SFrame FRE is initialized with the data from
903
   the previous known FRE, if any.
904
905
   Understandably, not all information (especially the instruction begin
906
   and end boundaries) needs to be relayed.  Hence, the caller of this API
907
   must set the pc_begin and pc_end as applicable.  */
908
909
static void
910
sframe_row_entry_initialize (struct sframe_row_entry *cur_fre,
911
           struct sframe_row_entry *prev_fre)
912
0
{
913
0
  gas_assert (prev_fre);
914
0
  cur_fre->cfa_base_reg = prev_fre->cfa_base_reg;
915
0
  cur_fre->cfa_offset = prev_fre->cfa_offset;
916
0
  cur_fre->bp_loc = prev_fre->bp_loc;
917
0
  cur_fre->bp_offset = prev_fre->bp_offset;
918
0
  cur_fre->ra_loc = prev_fre->ra_loc;
919
0
  cur_fre->ra_offset = prev_fre->ra_offset;
920
  /* Treat RA mangling as a sticky bit.  It retains its value until another
921
     .cfi_negate_ra_state is seen.  */
922
0
  cur_fre->mangled_ra_p = prev_fre->mangled_ra_p;
923
0
}
924
925
/* Translate DW_CFA_advance_loc into SFrame context.
926
   Return SFRAME_XLATE_OK if success.  */
927
928
static int
929
sframe_xlate_do_advance_loc (struct sframe_xlate_ctx *xlate_ctx,
930
           struct cfi_insn_data *cfi_insn)
931
0
{
932
0
  struct sframe_row_entry *last_fre = xlate_ctx->last_fre;
933
  /* Get the scratchpad FRE currently being updated as the cfi_insn's
934
     get interpreted.  This FRE eventually gets linked in into the
935
     list of FREs for the specific function.  */
936
0
  struct sframe_row_entry *cur_fre = xlate_ctx->cur_fre;
937
938
0
  if (cur_fre)
939
0
    {
940
0
      if (!cur_fre->merge_candidate)
941
0
  {
942
0
    sframe_fre_set_end_addr (cur_fre, cfi_insn->u.ll.lab2);
943
944
0
    sframe_xlate_ctx_add_fre (xlate_ctx, cur_fre);
945
0
    last_fre = xlate_ctx->last_fre;
946
947
0
    xlate_ctx->cur_fre = sframe_row_entry_new ();
948
0
    cur_fre = xlate_ctx->cur_fre;
949
950
0
    if (last_fre)
951
0
      sframe_row_entry_initialize (cur_fre, last_fre);
952
0
  }
953
0
      else
954
0
  {
955
0
    sframe_fre_set_end_addr (last_fre, cfi_insn->u.ll.lab2);
956
0
    gas_assert (last_fre->merge_candidate == false);
957
0
  }
958
0
    }
959
0
  else
960
0
    {
961
0
      xlate_ctx->cur_fre = sframe_row_entry_new ();
962
0
      cur_fre = xlate_ctx->cur_fre;
963
0
    }
964
965
0
  gas_assert (cur_fre);
966
0
  sframe_fre_set_begin_addr (cur_fre, cfi_insn->u.ll.lab2);
967
968
0
  return SFRAME_XLATE_OK;
969
0
}
970
971
/* Translate DW_CFA_def_cfa into SFrame context.
972
   Return SFRAME_XLATE_OK if success.  */
973
974
static int
975
sframe_xlate_do_def_cfa (struct sframe_xlate_ctx *xlate_ctx,
976
       struct cfi_insn_data *cfi_insn)
977
978
0
{
979
  /* Get the scratchpad FRE.  This FRE will eventually get linked in.  */
980
0
  struct sframe_row_entry *cur_fre = xlate_ctx->cur_fre;
981
0
  if (!cur_fre)
982
0
  {
983
0
    xlate_ctx->cur_fre = sframe_row_entry_new ();
984
0
    cur_fre = xlate_ctx->cur_fre;
985
0
    sframe_fre_set_begin_addr (cur_fre,
986
0
             get_dw_fde_start_addrS (xlate_ctx->dw_fde));
987
0
  }
988
  /* Define the current CFA rule to use the provided register and
989
     offset.  */
990
0
  sframe_fre_set_cfa_base_reg (cur_fre, cfi_insn->u.ri.reg);
991
0
  sframe_fre_set_cfa_offset (cur_fre, cfi_insn->u.ri.offset);
992
0
  cur_fre->merge_candidate = false;
993
994
0
  return SFRAME_XLATE_OK;
995
0
}
996
997
/* Translate DW_CFA_def_cfa_register into SFrame context.
998
   Return SFRAME_XLATE_OK if success.  */
999
1000
static int
1001
sframe_xlate_do_def_cfa_register (struct sframe_xlate_ctx *xlate_ctx,
1002
          struct cfi_insn_data *cfi_insn)
1003
0
{
1004
0
  struct sframe_row_entry *last_fre = xlate_ctx->last_fre;
1005
  /* Get the scratchpad FRE.  This FRE will eventually get linked in.  */
1006
0
  struct sframe_row_entry *cur_fre = xlate_ctx->cur_fre;
1007
0
  gas_assert (cur_fre);
1008
  /* Define the current CFA rule to use the provided register (but to
1009
     keep the old offset).  */
1010
0
  sframe_fre_set_cfa_base_reg (cur_fre, cfi_insn->u.ri.reg);
1011
0
  sframe_fre_set_cfa_offset (cur_fre, last_fre->cfa_offset);
1012
0
  cur_fre->merge_candidate = false;
1013
1014
0
  return SFRAME_XLATE_OK;
1015
0
}
1016
1017
/* Translate DW_CFA_def_cfa_offset into SFrame context.
1018
   Return SFRAME_XLATE_OK if success.  */
1019
1020
static int
1021
sframe_xlate_do_def_cfa_offset (struct sframe_xlate_ctx *xlate_ctx,
1022
        struct cfi_insn_data *cfi_insn)
1023
0
{
1024
  /* The scratchpad FRE currently being updated with each cfi_insn
1025
     being interpreted.  This FRE eventually gets linked in into the
1026
     list of FREs for the specific function.  */
1027
0
  struct sframe_row_entry *cur_fre = xlate_ctx->cur_fre;
1028
1029
0
  gas_assert (cur_fre);
1030
  /*  Define the current CFA rule to use the provided offset (but to keep
1031
      the old register).  However, if the old register is not FP/SP,
1032
      skip creating SFrame stack trace info for the function.  */
1033
0
  if ((cur_fre->cfa_base_reg == SFRAME_CFA_FP_REG)
1034
0
      || (cur_fre->cfa_base_reg == SFRAME_CFA_SP_REG))
1035
0
    {
1036
0
      sframe_fre_set_cfa_offset (cur_fre, cfi_insn->u.i);
1037
0
      cur_fre->merge_candidate = false;
1038
0
    }
1039
0
  else
1040
0
    return SFRAME_XLATE_ERR_NOTREPRESENTED;
1041
1042
0
  return SFRAME_XLATE_OK;
1043
0
}
1044
1045
/* Translate DW_CFA_offset into SFrame context.
1046
   Return SFRAME_XLATE_OK if success.  */
1047
1048
static int
1049
sframe_xlate_do_offset (struct sframe_xlate_ctx *xlate_ctx,
1050
      struct cfi_insn_data *cfi_insn)
1051
0
{
1052
  /* The scratchpad FRE currently being updated with each cfi_insn
1053
     being interpreted.  This FRE eventually gets linked in into the
1054
     list of FREs for the specific function.  */
1055
0
  struct sframe_row_entry *cur_fre = xlate_ctx->cur_fre;
1056
1057
0
  gas_assert (cur_fre);
1058
  /* Change the rule for the register indicated by the register number to
1059
     be the specified offset.  */
1060
0
  if (cfi_insn->u.r == SFRAME_CFA_FP_REG)
1061
0
    {
1062
0
      gas_assert (!cur_fre->base_reg);
1063
0
      sframe_fre_set_bp_track (cur_fre, cfi_insn->u.ri.offset);
1064
0
      cur_fre->merge_candidate = false;
1065
0
    }
1066
#ifdef SFRAME_FRE_RA_TRACKING
1067
  else if (sframe_ra_tracking_p ()
1068
     && cfi_insn->u.r == SFRAME_CFA_RA_REG)
1069
    {
1070
      sframe_fre_set_ra_track (cur_fre, cfi_insn->u.ri.offset);
1071
      cur_fre->merge_candidate = false;
1072
    }
1073
#endif
1074
  /* This is used to track changes to non-rsp registers, skip all others
1075
     except FP / RA for now.  */
1076
0
  return SFRAME_XLATE_OK;
1077
0
}
1078
1079
/* Translate DW_CFA_val_offset into SFrame context.
1080
   Return SFRAME_XLATE_OK if success.  */
1081
1082
static int
1083
sframe_xlate_do_val_offset (struct sframe_xlate_ctx *xlate_ctx ATTRIBUTE_UNUSED,
1084
          struct cfi_insn_data *cfi_insn)
1085
0
{
1086
  /* Previous value of register is CFA + offset.  However, if the specified
1087
     register is not interesting (FP or RA reg), the current DW_CFA_val_offset
1088
     instruction can be safely skipped without sacrificing the asynchonicity of
1089
     stack trace information.  */
1090
0
  if (cfi_insn->u.r == SFRAME_CFA_FP_REG)
1091
0
    return SFRAME_XLATE_ERR_NOTREPRESENTED; /* Not represented.  */
1092
#ifdef SFRAME_FRE_RA_TRACKING
1093
  else if (sframe_ra_tracking_p ()
1094
     && cfi_insn->u.r == SFRAME_CFA_RA_REG)
1095
    return SFRAME_XLATE_ERR_NOTREPRESENTED; /* Not represented.  */
1096
#endif
1097
1098
  /* Safe to skip.  */
1099
0
  return SFRAME_XLATE_OK;
1100
0
}
1101
1102
/* Translate DW_CFA_remember_state into SFrame context.
1103
   Return SFRAME_XLATE_OK if success.  */
1104
1105
static int
1106
sframe_xlate_do_remember_state (struct sframe_xlate_ctx *xlate_ctx)
1107
0
{
1108
0
  struct sframe_row_entry *last_fre = xlate_ctx->last_fre;
1109
1110
  /* If there is no FRE state to remember, nothing to do here.  Return
1111
     early with non-zero error code, this will cause no SFrame stack trace
1112
     info for the function involved.  */
1113
0
  if (!last_fre)
1114
0
    return SFRAME_XLATE_ERR_INVAL;
1115
1116
0
  if (!xlate_ctx->remember_fre)
1117
0
    xlate_ctx->remember_fre = sframe_row_entry_new ();
1118
0
  sframe_row_entry_initialize (xlate_ctx->remember_fre, last_fre);
1119
1120
0
  return SFRAME_XLATE_OK;
1121
0
}
1122
1123
/* Translate DW_CFA_restore_state into SFrame context.
1124
   Return SFRAME_XLATE_OK if success.  */
1125
1126
static int
1127
sframe_xlate_do_restore_state (struct sframe_xlate_ctx *xlate_ctx)
1128
0
{
1129
  /* The scratchpad FRE currently being updated with each cfi_insn
1130
     being interpreted.  This FRE eventually gets linked in into the
1131
     list of FREs for the specific function.  */
1132
0
  struct sframe_row_entry *cur_fre = xlate_ctx->cur_fre;
1133
1134
0
  gas_assert (xlate_ctx->remember_fre);
1135
0
  gas_assert (cur_fre && cur_fre->merge_candidate);
1136
1137
  /* Get the CFA state from the DW_CFA_remember_state insn.  */
1138
0
  sframe_row_entry_initialize (cur_fre, xlate_ctx->remember_fre);
1139
  /* The PC boundaries of the current SFrame FRE are updated
1140
     via other machinery.  */
1141
0
  cur_fre->merge_candidate = false;
1142
0
  return SFRAME_XLATE_OK;
1143
0
}
1144
1145
/* Translate DW_CFA_restore into SFrame context.
1146
   Return SFRAME_XLATE_OK if success.  */
1147
1148
static int
1149
sframe_xlate_do_restore (struct sframe_xlate_ctx *xlate_ctx,
1150
       struct cfi_insn_data *cfi_insn)
1151
0
{
1152
0
  struct sframe_row_entry *cie_fre = xlate_ctx->first_fre;
1153
  /* The scratchpad FRE currently being updated with each cfi_insn
1154
     being interpreted.  This FRE eventually gets linked in into the
1155
     list of FREs for the specific function.  */
1156
0
  struct sframe_row_entry *cur_fre = xlate_ctx->cur_fre;
1157
1158
  /* Change the rule for the indicated register to the rule assigned to
1159
     it by the initial_instructions in the CIE.  */
1160
0
  gas_assert (cie_fre);
1161
  /* SFrame FREs track only CFA and FP / RA for backtracing purposes;
1162
     skip the other .cfi_restore directives.  */
1163
0
  if (cfi_insn->u.r == SFRAME_CFA_FP_REG)
1164
0
    {
1165
0
      gas_assert (cur_fre);
1166
0
      cur_fre->bp_loc = cie_fre->bp_loc;
1167
0
      cur_fre->bp_offset = cie_fre->bp_offset;
1168
0
      cur_fre->merge_candidate = false;
1169
0
    }
1170
#ifdef SFRAME_FRE_RA_TRACKING
1171
  else if (sframe_ra_tracking_p ()
1172
     && cfi_insn->u.r == SFRAME_CFA_RA_REG)
1173
    {
1174
      gas_assert (cur_fre);
1175
      cur_fre->ra_loc = cie_fre->ra_loc;
1176
      cur_fre->ra_offset = cie_fre->ra_offset;
1177
      cur_fre->merge_candidate = false;
1178
    }
1179
#endif
1180
0
  return SFRAME_XLATE_OK;
1181
0
}
1182
1183
/* Translate DW_CFA_GNU_window_save into SFrame context.
1184
   Return SFRAME_XLATE_OK if success.  */
1185
1186
static int
1187
sframe_xlate_do_gnu_window_save (struct sframe_xlate_ctx *xlate_ctx,
1188
         struct cfi_insn_data *cfi_insn ATTRIBUTE_UNUSED)
1189
0
{
1190
0
  struct sframe_row_entry *cur_fre = xlate_ctx->cur_fre;
1191
1192
0
  gas_assert (cur_fre);
1193
  /* Toggle the mangled RA status bit.  */
1194
0
  cur_fre->mangled_ra_p = !cur_fre->mangled_ra_p;
1195
0
  cur_fre->merge_candidate = false;
1196
1197
0
  return SFRAME_XLATE_OK;
1198
0
}
1199
1200
/* Process CFI_INSN and update the translation context with the FRE
1201
   information.
1202
1203
   Returns an error code (sframe_xlate_err) if CFI_INSN is not successfully
1204
   processed.  */
1205
1206
static int
1207
sframe_do_cfi_insn (struct sframe_xlate_ctx *xlate_ctx,
1208
        struct cfi_insn_data *cfi_insn)
1209
0
{
1210
0
  int err = 0;
1211
1212
  /* Atleast one cfi_insn per FDE is expected.  */
1213
0
  gas_assert (cfi_insn);
1214
0
  int op = cfi_insn->insn;
1215
1216
0
  switch (op)
1217
0
    {
1218
0
    case DW_CFA_advance_loc:
1219
0
      err = sframe_xlate_do_advance_loc (xlate_ctx, cfi_insn);
1220
0
      break;
1221
0
    case DW_CFA_def_cfa:
1222
0
      err = sframe_xlate_do_def_cfa (xlate_ctx, cfi_insn);
1223
0
      break;
1224
0
    case DW_CFA_def_cfa_register:
1225
0
      err = sframe_xlate_do_def_cfa_register (xlate_ctx, cfi_insn);
1226
0
      break;
1227
0
    case DW_CFA_def_cfa_offset:
1228
0
      err = sframe_xlate_do_def_cfa_offset (xlate_ctx, cfi_insn);
1229
0
      break;
1230
0
    case DW_CFA_offset:
1231
0
      err = sframe_xlate_do_offset (xlate_ctx, cfi_insn);
1232
0
      break;
1233
0
    case DW_CFA_val_offset:
1234
0
      err = sframe_xlate_do_val_offset (xlate_ctx, cfi_insn);
1235
0
      break;
1236
0
    case DW_CFA_remember_state:
1237
0
      err = sframe_xlate_do_remember_state (xlate_ctx);
1238
0
      break;
1239
0
    case DW_CFA_restore_state:
1240
0
      err = sframe_xlate_do_restore_state (xlate_ctx);
1241
0
      break;
1242
0
    case DW_CFA_restore:
1243
0
      err = sframe_xlate_do_restore (xlate_ctx, cfi_insn);
1244
0
      break;
1245
    /* DW_CFA_AARCH64_negate_ra_state is multiplexed with
1246
       DW_CFA_GNU_window_save.  */
1247
0
    case DW_CFA_GNU_window_save:
1248
0
      err = sframe_xlate_do_gnu_window_save (xlate_ctx, cfi_insn);
1249
0
      break;
1250
0
    case DW_CFA_undefined:
1251
0
    case DW_CFA_same_value:
1252
0
      break;
1253
0
    default:
1254
0
      {
1255
  /* Other CFI opcodes are not processed at this time.
1256
     These do not impact the coverage of the basic stack tracing
1257
     information as conveyed in the SFrame format.
1258
      - DW_CFA_register,
1259
      - ...
1260
1261
     Following skipped operations do, however, impact the asynchronicity:
1262
       - CFI_escape  */
1263
1264
0
  err = SFRAME_XLATE_ERR_NOTREPRESENTED;
1265
  // printf (_("SFrame Unsupported or unknown Dwarf CFI number: %#x\n"), op);
1266
0
      }
1267
0
    }
1268
1269
0
  return err;
1270
0
}
1271
1272
1273
static int
1274
sframe_do_fde (struct sframe_xlate_ctx *xlate_ctx,
1275
         const struct fde_entry *dw_fde)
1276
0
{
1277
0
  struct cfi_insn_data *cfi_insn;
1278
0
  int err = SFRAME_XLATE_OK;
1279
1280
0
  xlate_ctx->dw_fde = dw_fde;
1281
1282
  /* If the return column is not RIP, SFrame format cannot represent it.  */
1283
0
  if (xlate_ctx->dw_fde->return_column != DWARF2_DEFAULT_RETURN_COLUMN)
1284
0
    return SFRAME_XLATE_ERR_NOTREPRESENTED;
1285
1286
  /* Iterate over the CFIs and create SFrame FREs.  */
1287
0
  for (cfi_insn = dw_fde->data; cfi_insn; cfi_insn = cfi_insn->next)
1288
0
    {
1289
      /* Translate each CFI, and buffer the state in translation context.  */
1290
0
      err = sframe_do_cfi_insn (xlate_ctx, cfi_insn);
1291
0
      if (err != SFRAME_XLATE_OK)
1292
0
  {
1293
    /* Skip generating SFrame stack trace info for the function if any
1294
       offending CFI is encountered by sframe_do_cfi_insn ().  */
1295
0
    return err; /* Return the error code.  */
1296
0
  }
1297
0
    }
1298
1299
  /* No errors encountered.  */
1300
1301
  /* Link in the scratchpad FRE that the last few CFI insns helped create.  */
1302
0
  if (xlate_ctx->cur_fre)
1303
0
    {
1304
0
      sframe_xlate_ctx_add_fre (xlate_ctx, xlate_ctx->cur_fre);
1305
0
      xlate_ctx->cur_fre = NULL;
1306
0
    }
1307
  /* Designate the end of the last SFrame FRE.  */
1308
0
  if (xlate_ctx->last_fre)
1309
0
    {
1310
0
      xlate_ctx->last_fre->pc_end
1311
0
  = get_dw_fde_end_addrS (xlate_ctx->dw_fde);
1312
0
    }
1313
1314
0
  return SFRAME_XLATE_OK;
1315
0
}
1316
1317
/* Create SFrame stack trace info for all functions.
1318
1319
   This function consumes the already generated DWARF FDEs (by dw2gencfi) and
1320
   generates data which is later emitted as stack trace information encoded in
1321
   the SFrame format.  */
1322
1323
static void
1324
create_sframe_all (void)
1325
0
{
1326
0
  struct fde_entry *dw_fde = NULL;
1327
0
  struct sframe_func_entry *sframe_fde = NULL;
1328
1329
0
  struct sframe_xlate_ctx *xlate_ctx = sframe_xlate_ctx_alloc ();
1330
1331
0
  for (dw_fde = all_fde_data; dw_fde ; dw_fde = dw_fde->next)
1332
0
    {
1333
0
      sframe_fde = sframe_fde_alloc ();
1334
      /* Initialize the translation context with information anew.  */
1335
0
      sframe_xlate_ctx_init (xlate_ctx);
1336
1337
      /* Process and link SFrame FDEs if no error.  Also skip adding an SFrame
1338
   FDE if it does not contain any SFrame FREs.  There is little use of an
1339
   SFrame FDE if there is no stack tracing information for the
1340
   function.  */
1341
0
      int err = sframe_do_fde (xlate_ctx, dw_fde);
1342
0
      if (err || xlate_ctx->num_xlate_fres == 0)
1343
0
  {
1344
0
    sframe_xlate_ctx_cleanup (xlate_ctx);
1345
0
    sframe_fde_free (sframe_fde);
1346
0
  }
1347
0
      else
1348
0
  {
1349
    /* All done.  Transfer the state from the SFrame translation
1350
       context to the SFrame FDE.  */
1351
0
    sframe_xlate_ctx_finalize (xlate_ctx, sframe_fde);
1352
0
    sframe_fde_link (sframe_fde);
1353
0
  }
1354
0
    }
1355
0
}
1356
1357
void
1358
output_sframe (segT sframe_seg)
1359
0
{
1360
0
  (void) sframe_seg;
1361
1362
  /* Setup the version specific access functions.  */
1363
0
  sframe_set_version (SFRAME_VERSION_2);
1364
1365
  /* Process all fdes and create SFrame stack trace information.  */
1366
0
  create_sframe_all ();
1367
1368
0
  output_sframe_internal ();
1369
0
}
1370
1371
#else  /*  support_sframe_p  */
1372
1373
void
1374
output_sframe (segT sframe_seg ATTRIBUTE_UNUSED)
1375
{
1376
}
1377
1378
#endif /*  support_sframe_p  */