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# 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
71static inline void
72out_one (int byte)
73{
74  FRAG_APPEND_1_CHAR (byte);
75}
76
77/* Emit a two-byte word into the current segment.  */
78
79static inline void
80out_two (int data)
81{
82  md_number_to_chars (frag_more (2), data, 2);
83}
84
85/* Emit a four byte word into the current segment.  */
86
87static inline void
88out_four (int data)
89{
90  md_number_to_chars (frag_more (4), data, 4);
91}
92
93/* Get the start address symbol from the DWARF FDE.  */
94
95static symbolS*
96get_dw_fde_start_addrS (const struct fde_entry *dw_fde)
97{
98  return dw_fde->start_address;
99}
100
101/* Get the start address symbol from the DWARF FDE.  */
102
103static symbolS*
104get_dw_fde_end_addrS (const struct fde_entry *dw_fde)
105{
106  return dw_fde->end_address;
107}
108
109/* Get whether PAUTH B key is used.  */
110static bool
111get_dw_fde_pauth_b_key_p (const struct fde_entry *dw_fde ATTRIBUTE_UNUSED)
112{
113#ifdef tc_fde_entry_extras
114  return (dw_fde->pauth_key == AARCH64_PAUTH_KEY_B);
115#else
116  return false;
117#endif
118}
119
120/* SFrame Frame Row Entry (FRE) related functions.  */
121
122static void
123sframe_fre_set_begin_addr (struct sframe_row_entry *fre, symbolS *beginS)
124{
125  fre->pc_begin = beginS;
126}
127
128static void
129sframe_fre_set_end_addr (struct sframe_row_entry *fre, symbolS *endS)
130{
131  fre->pc_end = endS;
132}
133
134static void
135sframe_fre_set_cfa_base_reg (struct sframe_row_entry *fre,
136			     unsigned int cfa_base_reg)
137{
138  fre->cfa_base_reg = cfa_base_reg;
139  fre->merge_candidate = false;
140}
141
142static void
143sframe_fre_set_cfa_offset (struct sframe_row_entry *fre,
144			   offsetT cfa_offset)
145{
146  fre->cfa_offset = cfa_offset;
147  fre->merge_candidate = false;
148}
149
150#ifdef SFRAME_FRE_RA_TRACKING
151static void
152sframe_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
160static void
161sframe_fre_set_bp_track (struct sframe_row_entry *fre, offsetT bp_offset)
162{
163  fre->bp_loc = SFRAME_FRE_ELEM_LOC_STACK;
164  fre->bp_offset = bp_offset;
165  fre->merge_candidate = false;
166}
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#define VALUE_8BIT  0x7f
173#define VALUE_16BIT 0x7fff
174#define VALUE_32BIT 0x7fffffff
175#define VALUE_64BIT 0x7fffffffffffffff
176
177/* Given a signed offset, return the size in bytes needed to represent it.  */
178
179static unsigned int
180get_offset_size_in_bytes (offsetT value)
181{
182  unsigned int size = 0;
183
184  if (value <= VALUE_8BIT && value >= (offsetT) -VALUE_8BIT)
185    size = 1;
186  else if (value <= VALUE_16BIT && value >= (offsetT) -VALUE_16BIT)
187    size = 2;
188  else if (value <= VALUE_32BIT && value >= (offsetT) -VALUE_32BIT)
189    size = 4;
190  else if ((sizeof (offsetT) > 4) && (value <= (offsetT) VALUE_64BIT
191				      && value >= (offsetT) -VALUE_64BIT))
192    size = 8;
193
194  return size;
195}
196
197#define SFRAME_FRE_OFFSET_FUNC_MAP_INDEX_1B  0 /* SFRAME_FRE_OFFSET_1B.  */
198#define SFRAME_FRE_OFFSET_FUNC_MAP_INDEX_2B  1 /* SFRAME_FRE_OFFSET_2B.  */
199#define SFRAME_FRE_OFFSET_FUNC_MAP_INDEX_4B  2 /* SFRAME_FRE_OFFSET_4B.  */
200#define SFRAME_FRE_OFFSET_FUNC_MAP_INDEX_8B  3 /* Not supported in SFrame.  */
201#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
205struct 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
213static unsigned int
214sframe_fre_offset_func_map_index (unsigned int offset_size)
215{
216  unsigned int idx = SFRAME_FRE_OFFSET_FUNC_MAP_INDEX_MAX;
217
218  switch (offset_size)
219    {
220      case SFRAME_FRE_OFFSET_1B:
221	idx = SFRAME_FRE_OFFSET_FUNC_MAP_INDEX_1B;
222	break;
223      case SFRAME_FRE_OFFSET_2B:
224	idx = SFRAME_FRE_OFFSET_FUNC_MAP_INDEX_2B;
225	break;
226      case SFRAME_FRE_OFFSET_4B:
227	idx = SFRAME_FRE_OFFSET_FUNC_MAP_INDEX_4B;
228	break;
229      default:
230	/* Not supported in SFrame.  */
231	break;
232    }
233
234  return idx;
235}
236
237/* Mapping from offset size to the output function to emit the value.  */
238
239static const
240struct sframe_fre_offset_func_map
241fre_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
251static struct sframe_version_ops sframe_ver_ops;
252
253/* SFrame (SFRAME_VERSION_1) set FRE info.  */
254
255static unsigned char
256sframe_v1_set_fre_info (unsigned int base_reg, unsigned int num_offsets,
257			unsigned int offset_size, bool mangled_ra_p)
258{
259  unsigned char fre_info;
260  fre_info = SFRAME_V1_FRE_INFO (base_reg, num_offsets, offset_size);
261  fre_info = SFRAME_V1_FRE_INFO_UPDATE_MANGLED_RA_P (mangled_ra_p, fre_info);
262  return fre_info;
263}
264
265/* SFrame (SFRAME_VERSION_1) set function info.  */
266static unsigned char
267sframe_v1_set_func_info (unsigned int fde_type, unsigned int fre_type,
268			 unsigned int pauth_key)
269{
270  unsigned char func_info;
271  func_info = SFRAME_V1_FUNC_INFO (fde_type, fre_type);
272  func_info = SFRAME_V1_FUNC_INFO_UPDATE_PAUTH_KEY (pauth_key, func_info);
273  return func_info;
274}
275
276/* SFrame version specific operations setup.  */
277
278static void
279sframe_set_version (uint32_t sframe_version ATTRIBUTE_UNUSED)
280{
281  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  sframe_ver_ops.set_fre_info = sframe_v1_set_fre_info;
287
288  sframe_ver_ops.set_func_info = sframe_v1_set_func_info;
289}
290
291/* SFrame set FRE info.  */
292
293static unsigned char
294sframe_set_fre_info (unsigned int base_reg, unsigned int num_offsets,
295		     unsigned int offset_size, bool mangled_ra_p)
296{
297  return sframe_ver_ops.set_fre_info (base_reg, num_offsets,
298				      offset_size, mangled_ra_p);
299}
300
301/* SFrame set func info. */
302
303static unsigned char
304sframe_set_func_info (unsigned int fde_type, unsigned int fre_type,
305		      unsigned int pauth_key)
306{
307  return sframe_ver_ops.set_func_info (fde_type, fre_type, pauth_key);
308}
309
310/* Get the number of SFrame FDEs for the current file.  */
311
312static unsigned int
313get_num_sframe_fdes (void);
314
315/* Get the number of SFrame frame row entries for the current file.  */
316
317static unsigned int
318get_num_sframe_fres (void);
319
320/* Get CFA base register ID as represented in SFrame Frame Row Entry.  */
321
322static unsigned int
323get_fre_base_reg_id (struct sframe_row_entry *sframe_fre)
324{
325  unsigned int cfi_insn_cfa_base_reg = sframe_fre->cfa_base_reg;
326  unsigned fre_base_reg = SFRAME_BASE_REG_SP;
327
328  if (cfi_insn_cfa_base_reg == SFRAME_CFA_FP_REG)
329    fre_base_reg = SFRAME_BASE_REG_FP;
330
331  /* Only one bit is reserved in SFRAME_VERSION_1.  */
332  gas_assert (fre_base_reg == SFRAME_BASE_REG_SP
333	      || fre_base_reg == SFRAME_BASE_REG_FP);
334
335  return fre_base_reg;
336}
337
338/* Get number of offsets necessary for the SFrame Frame Row Entry.  */
339
340static unsigned int
341get_fre_num_offsets (struct sframe_row_entry *sframe_fre)
342{
343  /* Atleast 1 must always be present (to recover CFA).  */
344  unsigned int fre_num_offsets = 1;
345
346  if (sframe_fre->bp_loc == SFRAME_FRE_ELEM_LOC_STACK)
347    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  return fre_num_offsets;
353}
354
355/* Get the minimum necessary offset size (in bytes) for this
356   SFrame frame row entry.  */
357
358static unsigned int
359sframe_get_fre_offset_size (struct sframe_row_entry *sframe_fre)
360{
361  unsigned int max_offset_size = 0;
362  unsigned int cfa_offset_size = 0;
363  unsigned int bp_offset_size = 0;
364  unsigned int ra_offset_size = 0;
365
366  unsigned int fre_offset_size = 0;
367
368  /* What size of offsets appear in this frame row entry.  */
369  cfa_offset_size = get_offset_size_in_bytes (sframe_fre->cfa_offset);
370  if (sframe_fre->bp_loc == SFRAME_FRE_ELEM_LOC_STACK)
371    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  max_offset_size = cfa_offset_size;
380  if (bp_offset_size > max_offset_size)
381    max_offset_size = bp_offset_size;
382  if (ra_offset_size > max_offset_size)
383    max_offset_size = ra_offset_size;
384
385  gas_assert (max_offset_size);
386
387  switch (max_offset_size)
388    {
389    case 1:
390      fre_offset_size = SFRAME_FRE_OFFSET_1B;
391      break;
392    case 2:
393      fre_offset_size = SFRAME_FRE_OFFSET_2B;
394      break;
395    case 4:
396      fre_offset_size = SFRAME_FRE_OFFSET_4B;
397      break;
398    default:
399      /* Offset of size 8 bytes is not supported in SFrame format
400	 version 1.  */
401      as_fatal (_("SFrame unsupported offset value\n"));
402      break;
403    }
404
405  return fre_offset_size;
406}
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
423static void
424create_fre_start_addr_exp (expressionS *cexp, symbolS *fre_pc_begin,
425			   symbolS *fde_start_address,
426			   symbolS *fde_end_address)
427{
428  expressionS val;
429  expressionS width;
430
431  /* val expression stores the FDE start address offset from the start PC
432     of function.  */
433  val.X_op = O_subtract;
434  val.X_add_symbol = fre_pc_begin;
435  val.X_op_symbol = fde_start_address;
436  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  width.X_op = O_subtract;
442  width.X_add_symbol = fde_end_address;
443  width.X_op_symbol = fde_start_address;
444  width.X_add_number = 0;
445
446  cexp->X_op = O_absent;
447  cexp->X_add_symbol = make_expr_symbol (&val);
448  cexp->X_op_symbol = make_expr_symbol (&width);
449  cexp->X_add_number = 0;
450}
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
466static void
467create_func_info_exp (expressionS *cexp, symbolS *dw_fde_end_addrS,
468		      symbolS *dw_fde_start_addrS, uint8_t func_info)
469{
470  expressionS width;
471  expressionS rest_of_func_info;
472
473  width.X_op = O_subtract;
474  width.X_add_symbol = dw_fde_end_addrS;
475  width.X_op_symbol = dw_fde_start_addrS;
476  width.X_add_number = 0;
477
478  rest_of_func_info.X_op = O_constant;
479  rest_of_func_info.X_add_number = func_info;
480
481  cexp->X_op = O_modulus;
482  cexp->X_add_symbol = make_expr_symbol (&rest_of_func_info);
483  cexp->X_op_symbol = make_expr_symbol (&width);
484  cexp->X_add_number = 0;
485}
486
487#endif
488
489static void
490output_sframe_row_entry (symbolS *fde_start_addr,
491			 symbolS *fde_end_addr,
492			 struct sframe_row_entry *sframe_fre)
493{
494  unsigned char fre_info;
495  unsigned int fre_num_offsets;
496  unsigned int fre_offset_size;
497  unsigned int fre_base_reg;
498  expressionS exp;
499  unsigned int fre_addr_size;
500
501  unsigned int idx = 0;
502  unsigned int fre_write_offsets = 0;
503
504  fre_addr_size = 4; /* 4 bytes by default.   FIXME tie it to fre_type? */
505
506  /* SFrame FRE Start Address.  */
507#if SFRAME_FRE_TYPE_SELECTION_OPT
508  create_fre_start_addr_exp (&exp, sframe_fre->pc_begin, fde_start_addr,
509			     fde_end_addr);
510  frag_grow (fre_addr_size);
511  frag_var (rs_sframe, fre_addr_size, 0, (relax_substateT) 0,
512	    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  fre_base_reg = get_fre_base_reg_id (sframe_fre);
525  fre_num_offsets = get_fre_num_offsets (sframe_fre);
526  fre_offset_size = sframe_get_fre_offset_size (sframe_fre);
527  fre_info = sframe_set_fre_info (fre_base_reg, fre_num_offsets,
528				  fre_offset_size, sframe_fre->mangled_ra_p);
529  out_one (fre_info);
530
531  idx = sframe_fre_offset_func_map_index (fre_offset_size);
532  gas_assert (idx < SFRAME_FRE_OFFSET_FUNC_MAP_INDEX_MAX);
533
534  /* Write out the offsets in order - cfa, bp, ra.  */
535  fre_offset_func_map[idx].out_func (sframe_fre->cfa_offset);
536  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  if (sframe_fre->bp_loc == SFRAME_FRE_ELEM_LOC_STACK)
546    {
547      fre_offset_func_map[idx].out_func (sframe_fre->bp_offset);
548      fre_write_offsets++;
549    }
550
551  /* Check if the expected number offsets have been written out
552     in this FRE.  */
553  gas_assert (fre_write_offsets == fre_num_offsets);
554}
555
556static void
557output_sframe_funcdesc (symbolS *start_of_fre_section,
558			symbolS *fre_symbol,
559			struct sframe_func_entry *sframe_fde)
560{
561  expressionS exp;
562  unsigned int addr_size;
563  symbolS *dw_fde_start_addrS, *dw_fde_end_addrS;
564  unsigned int pauth_key;
565
566  addr_size = SFRAME_RELOC_SIZE;
567  dw_fde_start_addrS = get_dw_fde_start_addrS (sframe_fde->dw_fde);
568  dw_fde_end_addrS = get_dw_fde_end_addrS (sframe_fde->dw_fde);
569
570  /* Start address of the function.  */
571  exp.X_op = O_subtract;
572  exp.X_add_symbol = dw_fde_start_addrS; /* to location.  */
573  exp.X_op_symbol = symbol_temp_new_now (); /* from location.  */
574  exp.X_add_number = 0;
575  emit_expr (&exp, addr_size);
576
577  /* Size of the function in bytes.  */
578  exp.X_op = O_subtract;
579  exp.X_add_symbol = dw_fde_end_addrS;
580  exp.X_op_symbol = dw_fde_start_addrS;
581  exp.X_add_number = 0;
582  emit_expr (&exp, addr_size);
583
584  /* Offset to the first frame row entry.  */
585  exp.X_op = O_subtract;
586  exp.X_add_symbol = fre_symbol; /* Minuend.  */
587  exp.X_op_symbol = start_of_fre_section; /* Subtrahend.  */
588  exp.X_add_number = 0;
589  emit_expr (&exp, addr_size);
590
591  /* Number of FREs.  */
592  out_four (sframe_fde->num_fres);
593
594  /* SFrame FDE function info.  */
595  unsigned char func_info;
596  pauth_key = (get_dw_fde_pauth_b_key_p (sframe_fde->dw_fde)
597	       ? SFRAME_AARCH64_PAUTH_KEY_B : SFRAME_AARCH64_PAUTH_KEY_A);
598  func_info = sframe_set_func_info (SFRAME_FDE_TYPE_PCINC,
599				    SFRAME_FRE_TYPE_ADDR4,
600				    pauth_key);
601#if SFRAME_FRE_TYPE_SELECTION_OPT
602  expressionS cexp;
603  create_func_info_exp (&cexp, dw_fde_end_addrS, dw_fde_start_addrS,
604			func_info);
605  frag_grow (1); /* Size of func info is unsigned char.  */
606  frag_var (rs_sframe, 1, 0, (relax_substateT) 0,
607	    make_expr_symbol (&cexp), 0, (char *) frag_now);
608#else
609  out_one (func_info);
610#endif
611  out_one (0);
612  out_two (0);
613}
614
615static void
616output_sframe_internal (void)
617{
618  expressionS exp;
619  unsigned int i = 0;
620
621  symbolS *end_of_frame_hdr;
622  symbolS *end_of_frame_section;
623  symbolS *start_of_func_desc_section;
624  symbolS *start_of_fre_section;
625  struct sframe_func_entry *sframe_fde;
626  struct sframe_row_entry *sframe_fre;
627  unsigned char abi_arch = 0;
628  int fixed_bp_offset = SFRAME_CFA_FIXED_FP_INVALID;
629  int fixed_ra_offset = SFRAME_CFA_FIXED_RA_INVALID;
630  unsigned int addr_size;
631
632  addr_size = SFRAME_RELOC_SIZE;
633
634  /* The function descriptor entries as dumped by the assembler are not
635     sorted on PCs.  */
636  unsigned char sframe_flags = 0;
637  sframe_flags |= !SFRAME_F_FDE_SORTED;
638
639  unsigned int num_fdes = get_num_sframe_fdes ();
640  unsigned int num_fres = get_num_sframe_fres ();
641  symbolS **fre_symbols = XNEWVEC (symbolS *, num_fres);
642  for (i = 0; i < num_fres; i++)
643    fre_symbols[i] = symbol_temp_make ();
644
645  end_of_frame_hdr = symbol_temp_make ();
646  start_of_fre_section = symbol_temp_make ();
647  start_of_func_desc_section = symbol_temp_make ();
648  end_of_frame_section = symbol_temp_make ();
649
650  /* Output the preamble of SFrame section.  */
651  out_two (SFRAME_MAGIC);
652  out_one (SFRAME_VERSION);
653  out_one (sframe_flags);
654  /* abi/arch.  */
655#ifdef sframe_get_abi_arch
656  abi_arch = sframe_get_abi_arch ();
657#endif
658  gas_assert (abi_arch);
659  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  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#ifdef sframe_ra_tracking_p
671  if (!sframe_ra_tracking_p ())
672    fixed_ra_offset = sframe_cfa_ra_offset ();
673#endif
674  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  out_one (0); /* Auxiliary SFrame header length.  */
680
681  out_four (num_fdes); /* Number of FDEs.  */
682  out_four (num_fres); /* Number of FREs.  */
683
684  /* FRE sub-section len.  */
685  exp.X_op = O_subtract;
686  exp.X_add_symbol = end_of_frame_section;
687  exp.X_op_symbol = start_of_fre_section;
688  exp.X_add_number = 0;
689  emit_expr (&exp, addr_size);
690
691  /* Offset of Function Index sub-section.  */
692  exp.X_op = O_subtract;
693  exp.X_add_symbol = end_of_frame_hdr;
694  exp.X_op_symbol = start_of_func_desc_section;
695  exp.X_add_number = 0;
696  emit_expr (&exp, addr_size);
697
698  /* Offset of FRE sub-section.  */
699  exp.X_op = O_subtract;
700  exp.X_add_symbol = start_of_fre_section;
701  exp.X_op_symbol = end_of_frame_hdr;
702  exp.X_add_number = 0;
703  emit_expr (&exp, addr_size);
704
705  symbol_set_value_now (end_of_frame_hdr);
706  symbol_set_value_now (start_of_func_desc_section);
707
708  /* Output the SFrame function descriptor entries.  */
709  i = 0;
710  for (sframe_fde = all_sframe_fdes; sframe_fde; sframe_fde = sframe_fde->next)
711    {
712      output_sframe_funcdesc (start_of_fre_section,
713			      fre_symbols[i], sframe_fde);
714      i += sframe_fde->num_fres;
715    }
716
717  symbol_set_value_now (start_of_fre_section);
718
719  /* Output the SFrame FREs.  */
720  i = 0;
721  sframe_fde = all_sframe_fdes;
722
723  for (sframe_fde = all_sframe_fdes; sframe_fde; sframe_fde = sframe_fde->next)
724    {
725      for (sframe_fre = sframe_fde->sframe_fres;
726	   sframe_fre;
727	   sframe_fre = sframe_fre->next)
728	{
729	  symbol_set_value_now (fre_symbols[i]);
730	  output_sframe_row_entry (get_dw_fde_start_addrS (sframe_fde->dw_fde),
731				   get_dw_fde_end_addrS (sframe_fde->dw_fde),
732				   sframe_fre);
733	  i++;
734	}
735    }
736
737  symbol_set_value_now (end_of_frame_section);
738
739  gas_assert (i == num_fres);
740
741  free (fre_symbols);
742  fre_symbols = NULL;
743}
744
745/* List of SFrame FDE entries.  */
746
747struct sframe_func_entry *all_sframe_fdes;
748
749/* Tail of the list to add to.  */
750
751static struct sframe_func_entry **last_sframe_fde = &all_sframe_fdes;
752
753static unsigned int
754get_num_sframe_fdes (void)
755{
756  struct sframe_func_entry *sframe_fde;
757  unsigned int total_fdes = 0;
758
759  for (sframe_fde = all_sframe_fdes; sframe_fde ; sframe_fde = sframe_fde->next)
760    total_fdes++;
761
762  return total_fdes;
763}
764
765/* Get the total number of SFrame row entries across the FDEs.  */
766
767static unsigned int
768get_num_sframe_fres (void)
769{
770  struct sframe_func_entry *sframe_fde;
771  unsigned int total_fres = 0;
772
773  for (sframe_fde = all_sframe_fdes; sframe_fde ; sframe_fde = sframe_fde->next)
774    total_fres += sframe_fde->num_fres;
775
776  return total_fres;
777}
778
779/* Allocate an SFrame FDE.  */
780
781static struct sframe_func_entry*
782sframe_fde_alloc (void)
783{
784  struct sframe_func_entry *sframe_fde = XCNEW (struct sframe_func_entry);
785  return sframe_fde;
786}
787
788/* Link the SFrame FDE in.  */
789
790static int
791sframe_fde_link (struct sframe_func_entry *sframe_fde)
792{
793  *last_sframe_fde = sframe_fde;
794  last_sframe_fde = &sframe_fde->next;
795
796  return 0;
797}
798
799/* Free up the SFrame FDE.  */
800
801static void
802sframe_fde_free (struct sframe_func_entry *sframe_fde)
803{
804  XDELETE (sframe_fde);
805  sframe_fde = NULL;
806}
807
808/* SFrame translation context functions.  */
809
810/* Allocate a new SFrame translation context.  */
811
812static struct sframe_xlate_ctx*
813sframe_xlate_ctx_alloc (void)
814{
815  struct sframe_xlate_ctx* xlate_ctx = XCNEW (struct sframe_xlate_ctx);
816  return xlate_ctx;
817}
818
819/* Initialize the given SFrame translation context.  */
820
821static void
822sframe_xlate_ctx_init (struct sframe_xlate_ctx *xlate_ctx)
823{
824  xlate_ctx->dw_fde = NULL;
825  xlate_ctx->first_fre = NULL;
826  xlate_ctx->last_fre = NULL;
827  xlate_ctx->cur_fre = NULL;
828  xlate_ctx->remember_fre = NULL;
829  xlate_ctx->num_xlate_fres = 0;
830}
831
832/* Cleanup the given SFrame translation context.  */
833
834static void
835sframe_xlate_ctx_cleanup (struct sframe_xlate_ctx *xlate_ctx)
836{
837  struct sframe_row_entry *fre, *fre_next;
838
839  if (xlate_ctx->num_xlate_fres)
840    {
841      fre = xlate_ctx->first_fre;
842      while (fre)
843	{
844	  fre_next = fre->next;
845	  XDELETE (fre);
846	  fre = fre_next;
847	}
848    }
849
850  sframe_xlate_ctx_init (xlate_ctx);
851}
852
853/* Transfer the state from the SFrame translation context to the SFrame FDE.  */
854
855static void
856sframe_xlate_ctx_finalize (struct sframe_xlate_ctx *xlate_ctx,
857			   struct sframe_func_entry *sframe_fde)
858{
859  sframe_fde->dw_fde = xlate_ctx->dw_fde;
860  sframe_fde->sframe_fres = xlate_ctx->first_fre;
861  sframe_fde->num_fres = xlate_ctx->num_xlate_fres;
862}
863
864static struct sframe_row_entry*
865sframe_row_entry_new (void)
866{
867  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  fre->cfa_base_reg = -1;
871  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  fre->mangled_ra_p = false;
875
876  return fre;
877}
878
879/* Add the given FRE in the list of frame row entries in the given FDE
880   translation context.  */
881
882static void
883sframe_xlate_ctx_add_fre (struct sframe_xlate_ctx *xlate_ctx,
884			 struct sframe_row_entry *fre)
885{
886  gas_assert (xlate_ctx && fre);
887
888  /* Add the frame row entry.  */
889  if (!xlate_ctx->first_fre)
890    xlate_ctx->first_fre = fre;
891  else if (xlate_ctx->last_fre)
892    xlate_ctx->last_fre->next = fre;
893
894  xlate_ctx->last_fre = fre;
895
896  /* Keep track of the total number of SFrame frame row entries.  */
897  xlate_ctx->num_xlate_fres++;
898}
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
909static void
910sframe_row_entry_initialize (struct sframe_row_entry *cur_fre,
911			     struct sframe_row_entry *prev_fre)
912{
913  gas_assert (prev_fre);
914  cur_fre->cfa_base_reg = prev_fre->cfa_base_reg;
915  cur_fre->cfa_offset = prev_fre->cfa_offset;
916  cur_fre->bp_loc = prev_fre->bp_loc;
917  cur_fre->bp_offset = prev_fre->bp_offset;
918  cur_fre->ra_loc = prev_fre->ra_loc;
919  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  cur_fre->mangled_ra_p = prev_fre->mangled_ra_p;
923}
924
925/* Translate DW_CFA_advance_loc into SFrame context.
926   Return SFRAME_XLATE_OK if success.  */
927
928static int
929sframe_xlate_do_advance_loc (struct sframe_xlate_ctx *xlate_ctx,
930			     struct cfi_insn_data *cfi_insn)
931{
932  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  struct sframe_row_entry *cur_fre = xlate_ctx->cur_fre;
937
938  if (cur_fre)
939    {
940      if (!cur_fre->merge_candidate)
941	{
942	  sframe_fre_set_end_addr (cur_fre, cfi_insn->u.ll.lab2);
943
944	  sframe_xlate_ctx_add_fre (xlate_ctx, cur_fre);
945	  last_fre = xlate_ctx->last_fre;
946
947	  xlate_ctx->cur_fre = sframe_row_entry_new ();
948	  cur_fre = xlate_ctx->cur_fre;
949
950	  if (last_fre)
951	    sframe_row_entry_initialize (cur_fre, last_fre);
952	}
953      else
954	{
955	  sframe_fre_set_end_addr (last_fre, cfi_insn->u.ll.lab2);
956	  gas_assert (last_fre->merge_candidate == false);
957	}
958    }
959  else
960    {
961      xlate_ctx->cur_fre = sframe_row_entry_new ();
962      cur_fre = xlate_ctx->cur_fre;
963    }
964
965  gas_assert (cur_fre);
966  sframe_fre_set_begin_addr (cur_fre, cfi_insn->u.ll.lab2);
967
968  return SFRAME_XLATE_OK;
969}
970
971/* Translate DW_CFA_def_cfa into SFrame context.
972   Return SFRAME_XLATE_OK if success.  */
973
974static int
975sframe_xlate_do_def_cfa (struct sframe_xlate_ctx *xlate_ctx,
976			 struct cfi_insn_data *cfi_insn)
977
978{
979  /* Get the scratchpad FRE.  This FRE will eventually get linked in.  */
980  struct sframe_row_entry *cur_fre = xlate_ctx->cur_fre;
981  if (!cur_fre)
982  {
983    xlate_ctx->cur_fre = sframe_row_entry_new ();
984    cur_fre = xlate_ctx->cur_fre;
985    sframe_fre_set_begin_addr (cur_fre,
986			       get_dw_fde_start_addrS (xlate_ctx->dw_fde));
987  }
988  /* Define the current CFA rule to use the provided register and
989     offset.  */
990  sframe_fre_set_cfa_base_reg (cur_fre, cfi_insn->u.ri.reg);
991  sframe_fre_set_cfa_offset (cur_fre, cfi_insn->u.ri.offset);
992  cur_fre->merge_candidate = false;
993
994  return SFRAME_XLATE_OK;
995}
996
997/* Translate DW_CFA_def_cfa_register into SFrame context.
998   Return SFRAME_XLATE_OK if success.  */
999
1000static int
1001sframe_xlate_do_def_cfa_register (struct sframe_xlate_ctx *xlate_ctx,
1002				  struct cfi_insn_data *cfi_insn)
1003{
1004  struct sframe_row_entry *last_fre = xlate_ctx->last_fre;
1005  /* Get the scratchpad FRE.  This FRE will eventually get linked in.  */
1006  struct sframe_row_entry *cur_fre = xlate_ctx->cur_fre;
1007  gas_assert (cur_fre);
1008  /* Define the current CFA rule to use the provided register (but to
1009     keep the old offset).  */
1010  sframe_fre_set_cfa_base_reg (cur_fre, cfi_insn->u.ri.reg);
1011  sframe_fre_set_cfa_offset (cur_fre, last_fre->cfa_offset);
1012  cur_fre->merge_candidate = false;
1013
1014  return SFRAME_XLATE_OK;
1015}
1016
1017/* Translate DW_CFA_def_cfa_offset into SFrame context.
1018   Return SFRAME_XLATE_OK if success.  */
1019
1020static int
1021sframe_xlate_do_def_cfa_offset (struct sframe_xlate_ctx *xlate_ctx,
1022				struct cfi_insn_data *cfi_insn)
1023{
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  struct sframe_row_entry *cur_fre = xlate_ctx->cur_fre;
1028
1029  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  if ((cur_fre->cfa_base_reg == SFRAME_CFA_FP_REG)
1034      || (cur_fre->cfa_base_reg == SFRAME_CFA_SP_REG))
1035    {
1036      sframe_fre_set_cfa_offset (cur_fre, cfi_insn->u.i);
1037      cur_fre->merge_candidate = false;
1038    }
1039  else
1040    return SFRAME_XLATE_ERR_NOTREPRESENTED;
1041
1042  return SFRAME_XLATE_OK;
1043}
1044
1045/* Translate DW_CFA_offset into SFrame context.
1046   Return SFRAME_XLATE_OK if success.  */
1047
1048static int
1049sframe_xlate_do_offset (struct sframe_xlate_ctx *xlate_ctx,
1050			struct cfi_insn_data *cfi_insn)
1051{
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  struct sframe_row_entry *cur_fre = xlate_ctx->cur_fre;
1056
1057  gas_assert (cur_fre);
1058  /* Change the rule for the register indicated by the register number to
1059     be the specified offset.  */
1060  if (cfi_insn->u.r == SFRAME_CFA_FP_REG)
1061    {
1062      gas_assert (!cur_fre->base_reg);
1063      sframe_fre_set_bp_track (cur_fre, cfi_insn->u.ri.offset);
1064      cur_fre->merge_candidate = false;
1065    }
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  return SFRAME_XLATE_OK;
1077}
1078
1079/* Translate DW_CFA_val_offset into SFrame context.
1080   Return SFRAME_XLATE_OK if success.  */
1081
1082static int
1083sframe_xlate_do_val_offset (struct sframe_xlate_ctx *xlate_ctx ATTRIBUTE_UNUSED,
1084			    struct cfi_insn_data *cfi_insn)
1085{
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 asynchronicity of
1089     stack trace information.  */
1090  if (cfi_insn->u.r == SFRAME_CFA_FP_REG)
1091    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  return SFRAME_XLATE_OK;
1100}
1101
1102/* Translate DW_CFA_remember_state into SFrame context.
1103   Return SFRAME_XLATE_OK if success.  */
1104
1105static int
1106sframe_xlate_do_remember_state (struct sframe_xlate_ctx *xlate_ctx)
1107{
1108  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  if (!last_fre)
1114    return SFRAME_XLATE_ERR_INVAL;
1115
1116  if (!xlate_ctx->remember_fre)
1117    xlate_ctx->remember_fre = sframe_row_entry_new ();
1118  sframe_row_entry_initialize (xlate_ctx->remember_fre, last_fre);
1119
1120  return SFRAME_XLATE_OK;
1121}
1122
1123/* Translate DW_CFA_restore_state into SFrame context.
1124   Return SFRAME_XLATE_OK if success.  */
1125
1126static int
1127sframe_xlate_do_restore_state (struct sframe_xlate_ctx *xlate_ctx)
1128{
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  struct sframe_row_entry *cur_fre = xlate_ctx->cur_fre;
1133
1134  gas_assert (xlate_ctx->remember_fre);
1135  gas_assert (cur_fre && cur_fre->merge_candidate);
1136
1137  /* Get the CFA state from the DW_CFA_remember_state insn.  */
1138  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  cur_fre->merge_candidate = false;
1142  return SFRAME_XLATE_OK;
1143}
1144
1145/* Translate DW_CFA_restore into SFrame context.
1146   Return SFRAME_XLATE_OK if success.  */
1147
1148static int
1149sframe_xlate_do_restore (struct sframe_xlate_ctx *xlate_ctx,
1150			 struct cfi_insn_data *cfi_insn)
1151{
1152  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  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  gas_assert (cie_fre);
1161  /* SFrame FREs track only CFA and FP / RA for backtracing purposes;
1162     skip the other .cfi_restore directives.  */
1163  if (cfi_insn->u.r == SFRAME_CFA_FP_REG)
1164    {
1165      gas_assert (cur_fre);
1166      cur_fre->bp_loc = cie_fre->bp_loc;
1167      cur_fre->bp_offset = cie_fre->bp_offset;
1168      cur_fre->merge_candidate = false;
1169    }
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  return SFRAME_XLATE_OK;
1181}
1182
1183/* Translate DW_CFA_GNU_window_save into SFrame context.
1184   Return SFRAME_XLATE_OK if success.  */
1185
1186static int
1187sframe_xlate_do_gnu_window_save (struct sframe_xlate_ctx *xlate_ctx,
1188				 struct cfi_insn_data *cfi_insn ATTRIBUTE_UNUSED)
1189{
1190  struct sframe_row_entry *cur_fre = xlate_ctx->cur_fre;
1191
1192  gas_assert (cur_fre);
1193  /* Toggle the mangled RA status bit.  */
1194  cur_fre->mangled_ra_p = !cur_fre->mangled_ra_p;
1195  cur_fre->merge_candidate = false;
1196
1197  return SFRAME_XLATE_OK;
1198}
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
1206static int
1207sframe_do_cfi_insn (struct sframe_xlate_ctx *xlate_ctx,
1208		    struct cfi_insn_data *cfi_insn)
1209{
1210  int err = 0;
1211
1212  /* Atleast one cfi_insn per FDE is expected.  */
1213  gas_assert (cfi_insn);
1214  int op = cfi_insn->insn;
1215
1216  switch (op)
1217    {
1218    case DW_CFA_advance_loc:
1219      err = sframe_xlate_do_advance_loc (xlate_ctx, cfi_insn);
1220      break;
1221    case DW_CFA_def_cfa:
1222      err = sframe_xlate_do_def_cfa (xlate_ctx, cfi_insn);
1223      break;
1224    case DW_CFA_def_cfa_register:
1225      err = sframe_xlate_do_def_cfa_register (xlate_ctx, cfi_insn);
1226      break;
1227    case DW_CFA_def_cfa_offset:
1228      err = sframe_xlate_do_def_cfa_offset (xlate_ctx, cfi_insn);
1229      break;
1230    case DW_CFA_offset:
1231      err = sframe_xlate_do_offset (xlate_ctx, cfi_insn);
1232      break;
1233    case DW_CFA_val_offset:
1234      err = sframe_xlate_do_val_offset (xlate_ctx, cfi_insn);
1235      break;
1236    case DW_CFA_remember_state:
1237      err = sframe_xlate_do_remember_state (xlate_ctx);
1238      break;
1239    case DW_CFA_restore_state:
1240      err = sframe_xlate_do_restore_state (xlate_ctx);
1241      break;
1242    case DW_CFA_restore:
1243      err = sframe_xlate_do_restore (xlate_ctx, cfi_insn);
1244      break;
1245    /* DW_CFA_AARCH64_negate_ra_state is multiplexed with
1246       DW_CFA_GNU_window_save.  */
1247    case DW_CFA_GNU_window_save:
1248      err = sframe_xlate_do_gnu_window_save (xlate_ctx, cfi_insn);
1249      break;
1250    /* Other CFI opcodes are not processed at this time.
1251       These do not impact the coverage of the basic stack tracing
1252       information as conveyed in the SFrame format.
1253	- DW_CFA_register,
1254	- etc.  */
1255    case DW_CFA_register:
1256      if (cfi_insn->u.rr.reg1 == SFRAME_CFA_SP_REG
1257#ifdef SFRAME_FRE_RA_TRACKING
1258	  || cfi_insn->u.rr.reg1 == SFRAME_CFA_RA_REG
1259#endif
1260	  || cfi_insn->u.rr.reg1 == SFRAME_CFA_FP_REG)
1261	err = SFRAME_XLATE_ERR_NOTREPRESENTED;
1262      break;
1263    case DW_CFA_undefined:
1264    case DW_CFA_same_value:
1265      break;
1266    default:
1267      /* Following skipped operations do, however, impact the asynchronicity:
1268	  - CFI_escape.  */
1269      err = SFRAME_XLATE_ERR_NOTREPRESENTED;
1270    }
1271
1272  /* An error here will cause no SFrame FDE later.  Warn the user because this
1273     will affect the overall coverage and hence, asynchronicity.  */
1274  if (err)
1275    as_warn (_("skipping SFrame FDE due to DWARF CFI op %#x"), op);
1276
1277  return err;
1278}
1279
1280
1281static int
1282sframe_do_fde (struct sframe_xlate_ctx *xlate_ctx,
1283	       const struct fde_entry *dw_fde)
1284{
1285  struct cfi_insn_data *cfi_insn;
1286  int err = SFRAME_XLATE_OK;
1287
1288  xlate_ctx->dw_fde = dw_fde;
1289
1290  /* If the return column is not RIP, SFrame format cannot represent it.  */
1291  if (xlate_ctx->dw_fde->return_column != DWARF2_DEFAULT_RETURN_COLUMN)
1292    return SFRAME_XLATE_ERR_NOTREPRESENTED;
1293
1294  /* Iterate over the CFIs and create SFrame FREs.  */
1295  for (cfi_insn = dw_fde->data; cfi_insn; cfi_insn = cfi_insn->next)
1296    {
1297      /* Translate each CFI, and buffer the state in translation context.  */
1298      err = sframe_do_cfi_insn (xlate_ctx, cfi_insn);
1299      if (err != SFRAME_XLATE_OK)
1300	{
1301	  /* Skip generating SFrame stack trace info for the function if any
1302	     offending CFI is encountered by sframe_do_cfi_insn ().  */
1303	  return err; /* Return the error code.  */
1304	}
1305    }
1306
1307  /* No errors encountered.  */
1308
1309  /* Link in the scratchpad FRE that the last few CFI insns helped create.  */
1310  if (xlate_ctx->cur_fre)
1311    {
1312      sframe_xlate_ctx_add_fre (xlate_ctx, xlate_ctx->cur_fre);
1313      xlate_ctx->cur_fre = NULL;
1314    }
1315  /* Designate the end of the last SFrame FRE.  */
1316  if (xlate_ctx->last_fre)
1317    {
1318      xlate_ctx->last_fre->pc_end
1319	= get_dw_fde_end_addrS (xlate_ctx->dw_fde);
1320    }
1321
1322  return SFRAME_XLATE_OK;
1323}
1324
1325/* Create SFrame stack trace info for all functions.
1326
1327   This function consumes the already generated DWARF FDEs (by dw2gencfi) and
1328   generates data which is later emitted as stack trace information encoded in
1329   the SFrame format.  */
1330
1331static void
1332create_sframe_all (void)
1333{
1334  struct fde_entry *dw_fde = NULL;
1335  struct sframe_func_entry *sframe_fde = NULL;
1336
1337  struct sframe_xlate_ctx *xlate_ctx = sframe_xlate_ctx_alloc ();
1338
1339  for (dw_fde = all_fde_data; dw_fde ; dw_fde = dw_fde->next)
1340    {
1341      sframe_fde = sframe_fde_alloc ();
1342      /* Initialize the translation context with information anew.  */
1343      sframe_xlate_ctx_init (xlate_ctx);
1344
1345      /* Process and link SFrame FDEs if no error.  Also skip adding an SFrame
1346	 FDE if it does not contain any SFrame FREs.  There is little use of an
1347	 SFrame FDE if there is no stack tracing information for the
1348	 function.  */
1349      int err = sframe_do_fde (xlate_ctx, dw_fde);
1350      if (err || xlate_ctx->num_xlate_fres == 0)
1351	{
1352	  sframe_xlate_ctx_cleanup (xlate_ctx);
1353	  sframe_fde_free (sframe_fde);
1354	}
1355      else
1356	{
1357	  /* All done.  Transfer the state from the SFrame translation
1358	     context to the SFrame FDE.  */
1359	  sframe_xlate_ctx_finalize (xlate_ctx, sframe_fde);
1360	  sframe_fde_link (sframe_fde);
1361	}
1362    }
1363}
1364
1365void
1366output_sframe (segT sframe_seg)
1367{
1368  (void) sframe_seg;
1369
1370  /* Setup the version specific access functions.  */
1371  sframe_set_version (SFRAME_VERSION_2);
1372
1373  /* Process all fdes and create SFrame stack trace information.  */
1374  create_sframe_all ();
1375
1376  output_sframe_internal ();
1377}
1378
1379#else  /*  support_sframe_p  */
1380
1381void
1382output_sframe (segT sframe_seg ATTRIBUTE_UNUSED)
1383{
1384}
1385
1386#endif /*  support_sframe_p  */
1387