xref: /netbsd-src/external/gpl3/binutils/dist/gas/gen-sframe.c (revision cb63e24e8d6aae7ddac1859a9015f48b1d8bd90e)
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 
71 static inline void
out_one(int byte)72 out_one (int byte)
73 {
74   FRAG_APPEND_1_CHAR (byte);
75 }
76 
77 /* Emit a two-byte word into the current segment.  */
78 
79 static inline void
out_two(int data)80 out_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 
87 static inline void
out_four(int data)88 out_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 
95 static symbolS*
get_dw_fde_start_addrS(const struct fde_entry * dw_fde)96 get_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 
103 static symbolS*
get_dw_fde_end_addrS(const struct fde_entry * dw_fde)104 get_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.  */
110 static bool
get_dw_fde_pauth_b_key_p(const struct fde_entry * dw_fde ATTRIBUTE_UNUSED)111 get_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 
122 static void
sframe_fre_set_begin_addr(struct sframe_row_entry * fre,symbolS * beginS)123 sframe_fre_set_begin_addr (struct sframe_row_entry *fre, symbolS *beginS)
124 {
125   fre->pc_begin = beginS;
126 }
127 
128 static void
sframe_fre_set_end_addr(struct sframe_row_entry * fre,symbolS * endS)129 sframe_fre_set_end_addr (struct sframe_row_entry *fre, symbolS *endS)
130 {
131   fre->pc_end = endS;
132 }
133 
134 static void
sframe_fre_set_cfa_base_reg(struct sframe_row_entry * fre,unsigned int cfa_base_reg)135 sframe_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 
142 static void
sframe_fre_set_cfa_offset(struct sframe_row_entry * fre,offsetT cfa_offset)143 sframe_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
151 static void
sframe_fre_set_ra_track(struct sframe_row_entry * fre,offsetT ra_offset)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
sframe_fre_set_bp_track(struct sframe_row_entry * fre,offsetT bp_offset)161 sframe_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 
179 static unsigned int
get_offset_size_in_bytes(offsetT value)180 get_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 
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
sframe_fre_offset_func_map_index(unsigned int offset_size)214 sframe_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 
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
sframe_v1_set_fre_info(unsigned int base_reg,unsigned int num_offsets,unsigned int offset_size,bool mangled_ra_p)256 sframe_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.  */
266 static unsigned char
sframe_v1_set_func_info(unsigned int fde_type,unsigned int fre_type,unsigned int pauth_key)267 sframe_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 
278 static void
sframe_set_version(uint32_t sframe_version ATTRIBUTE_UNUSED)279 sframe_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 
293 static unsigned char
sframe_set_fre_info(unsigned int base_reg,unsigned int num_offsets,unsigned int offset_size,bool mangled_ra_p)294 sframe_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 
303 static unsigned char
sframe_set_func_info(unsigned int fde_type,unsigned int fre_type,unsigned int pauth_key)304 sframe_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 
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
get_fre_base_reg_id(struct sframe_row_entry * sframe_fre)323 get_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 
340 static unsigned int
get_fre_num_offsets(struct sframe_row_entry * sframe_fre)341 get_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 
358 static unsigned int
sframe_get_fre_offset_size(struct sframe_row_entry * sframe_fre)359 sframe_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 
423 static void
create_fre_start_addr_exp(expressionS * cexp,symbolS * fre_pc_begin,symbolS * fde_start_address,symbolS * fde_end_address)424 create_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 
466 static void
create_func_info_exp(expressionS * cexp,symbolS * dw_fde_end_addrS,symbolS * dw_fde_start_addrS,uint8_t func_info)467 create_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 
489 static void
output_sframe_row_entry(symbolS * fde_start_addr,symbolS * fde_end_addr,struct sframe_row_entry * sframe_fre)490 output_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 
556 static void
output_sframe_funcdesc(symbolS * start_of_fre_section,symbolS * fre_symbol,struct sframe_func_entry * sframe_fde)557 output_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 
615 static void
output_sframe_internal(void)616 output_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 
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
get_num_sframe_fdes(void)754 get_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 
767 static unsigned int
get_num_sframe_fres(void)768 get_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 
781 static struct sframe_func_entry*
sframe_fde_alloc(void)782 sframe_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 
790 static int
sframe_fde_link(struct sframe_func_entry * sframe_fde)791 sframe_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 
801 static void
sframe_fde_free(struct sframe_func_entry * sframe_fde)802 sframe_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 
812 static struct sframe_xlate_ctx*
sframe_xlate_ctx_alloc(void)813 sframe_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 
821 static void
sframe_xlate_ctx_init(struct sframe_xlate_ctx * xlate_ctx)822 sframe_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 
834 static void
sframe_xlate_ctx_cleanup(struct sframe_xlate_ctx * xlate_ctx)835 sframe_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 
855 static void
sframe_xlate_ctx_finalize(struct sframe_xlate_ctx * xlate_ctx,struct sframe_func_entry * sframe_fde)856 sframe_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 
864 static struct sframe_row_entry*
sframe_row_entry_new(void)865 sframe_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 
882 static void
sframe_xlate_ctx_add_fre(struct sframe_xlate_ctx * xlate_ctx,struct sframe_row_entry * fre)883 sframe_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 
909 static void
sframe_row_entry_initialize(struct sframe_row_entry * cur_fre,struct sframe_row_entry * prev_fre)910 sframe_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 
928 static int
sframe_xlate_do_advance_loc(struct sframe_xlate_ctx * xlate_ctx,struct cfi_insn_data * cfi_insn)929 sframe_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 
974 static int
sframe_xlate_do_def_cfa(struct sframe_xlate_ctx * xlate_ctx,struct cfi_insn_data * cfi_insn)975 sframe_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 
1000 static int
sframe_xlate_do_def_cfa_register(struct sframe_xlate_ctx * xlate_ctx,struct cfi_insn_data * cfi_insn)1001 sframe_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 
1020 static int
sframe_xlate_do_def_cfa_offset(struct sframe_xlate_ctx * xlate_ctx,struct cfi_insn_data * cfi_insn)1021 sframe_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 
1048 static int
sframe_xlate_do_offset(struct sframe_xlate_ctx * xlate_ctx,struct cfi_insn_data * cfi_insn)1049 sframe_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 
1082 static int
sframe_xlate_do_val_offset(struct sframe_xlate_ctx * xlate_ctx ATTRIBUTE_UNUSED,struct cfi_insn_data * cfi_insn)1083 sframe_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 
1105 static int
sframe_xlate_do_remember_state(struct sframe_xlate_ctx * xlate_ctx)1106 sframe_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 
1126 static int
sframe_xlate_do_restore_state(struct sframe_xlate_ctx * xlate_ctx)1127 sframe_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 
1148 static int
sframe_xlate_do_restore(struct sframe_xlate_ctx * xlate_ctx,struct cfi_insn_data * cfi_insn)1149 sframe_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 
1186 static int
sframe_xlate_do_gnu_window_save(struct sframe_xlate_ctx * xlate_ctx,struct cfi_insn_data * cfi_insn ATTRIBUTE_UNUSED)1187 sframe_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 
1206 static int
sframe_do_cfi_insn(struct sframe_xlate_ctx * xlate_ctx,struct cfi_insn_data * cfi_insn)1207 sframe_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 
1281 static int
sframe_do_fde(struct sframe_xlate_ctx * xlate_ctx,const struct fde_entry * dw_fde)1282 sframe_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 
1331 static void
create_sframe_all(void)1332 create_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 
1365 void
output_sframe(segT sframe_seg)1366 output_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 
1381 void
output_sframe(segT sframe_seg ATTRIBUTE_UNUSED)1382 output_sframe (segT sframe_seg ATTRIBUTE_UNUSED)
1383 {
1384 }
1385 
1386 #endif /*  support_sframe_p  */
1387