gen-sframe.c revision 1.1.1.2 1 1.1 christos /* gen-sframe.c - Support for generating SFrame section.
2 1.1.1.2 christos Copyright (C) 2022-2025 Free Software Foundation, Inc.
3 1.1 christos
4 1.1 christos This file is part of GAS, the GNU Assembler.
5 1.1 christos
6 1.1 christos GAS is free software; you can redistribute it and/or modify
7 1.1 christos it under the terms of the GNU General Public License as published by
8 1.1 christos the Free Software Foundation; either version 3, or (at your option)
9 1.1 christos any later version.
10 1.1 christos
11 1.1 christos GAS is distributed in the hope that it will be useful,
12 1.1 christos but WITHOUT ANY WARRANTY; without even the implied warranty of
13 1.1 christos MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 1.1 christos GNU General Public License for more details.
15 1.1 christos
16 1.1 christos You should have received a copy of the GNU General Public License
17 1.1 christos along with GAS; see the file COPYING. If not, write to the Free
18 1.1 christos Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA
19 1.1 christos 02110-1301, USA. */
20 1.1 christos
21 1.1 christos #include "as.h"
22 1.1 christos #include "subsegs.h"
23 1.1 christos #include "sframe.h"
24 1.1.1.2 christos #include "sframe-internal.h"
25 1.1 christos #include "gen-sframe.h"
26 1.1 christos #include "dw2gencfi.h"
27 1.1 christos
28 1.1 christos #ifdef support_sframe_p
29 1.1 christos
30 1.1.1.2 christos #ifndef sizeof_member
31 1.1.1.2 christos # define sizeof_member(type, member) (sizeof (((type *)0)->member))
32 1.1 christos #endif
33 1.1 christos
34 1.1 christos /* SFrame FRE type selection optimization is an optimization for size.
35 1.1 christos
36 1.1 christos There are three flavors of SFrame FRE representation in the binary format:
37 1.1 christos - sframe_frame_row_entry_addr1 where the FRE start address is 1 byte.
38 1.1 christos - sframe_frame_row_entry_addr2 where the FRE start address is 2 bytes.
39 1.1 christos - sframe_frame_row_entry_addr4 where the FRE start address is 4 bytes.
40 1.1 christos
41 1.1 christos Note that in the SFrame format, all SFrame FREs of a function use one
42 1.1 christos single representation. The SFrame FRE type itself is identified via the
43 1.1 christos information in the SFrame FDE function info.
44 1.1 christos
45 1.1 christos Now, to select the minimum required one from the list above, one needs to
46 1.1 christos make a decision based on the size (in bytes) of the function.
47 1.1 christos
48 1.1 christos As a result, for this optimization, some fragments (generated with a new
49 1.1 christos type rs_sframe) for the SFrame section are fixed up later.
50 1.1 christos
51 1.1 christos This optimization (for size) is enabled by default. */
52 1.1 christos
53 1.1 christos #ifndef SFRAME_FRE_TYPE_SELECTION_OPT
54 1.1 christos # define SFRAME_FRE_TYPE_SELECTION_OPT 1
55 1.1 christos #endif
56 1.1 christos
57 1.1.1.2 christos /* List of SFrame FDE entries. */
58 1.1.1.2 christos
59 1.1.1.2 christos static struct sframe_func_entry *all_sframe_fdes = NULL;
60 1.1.1.2 christos
61 1.1.1.2 christos /* Tail of the list to add to. */
62 1.1.1.2 christos
63 1.1.1.2 christos static struct sframe_func_entry **last_sframe_fde = &all_sframe_fdes;
64 1.1.1.2 christos
65 1.1 christos /* Emit a single byte into the current segment. */
66 1.1 christos
67 1.1 christos static inline void
68 1.1 christos out_one (int byte)
69 1.1 christos {
70 1.1 christos FRAG_APPEND_1_CHAR (byte);
71 1.1 christos }
72 1.1 christos
73 1.1 christos /* Emit a two-byte word into the current segment. */
74 1.1 christos
75 1.1 christos static inline void
76 1.1 christos out_two (int data)
77 1.1 christos {
78 1.1 christos md_number_to_chars (frag_more (2), data, 2);
79 1.1 christos }
80 1.1 christos
81 1.1 christos /* Emit a four byte word into the current segment. */
82 1.1 christos
83 1.1 christos static inline void
84 1.1 christos out_four (int data)
85 1.1 christos {
86 1.1 christos md_number_to_chars (frag_more (4), data, 4);
87 1.1 christos }
88 1.1 christos
89 1.1 christos /* Get the start address symbol from the DWARF FDE. */
90 1.1 christos
91 1.1 christos static symbolS*
92 1.1 christos get_dw_fde_start_addrS (const struct fde_entry *dw_fde)
93 1.1 christos {
94 1.1 christos return dw_fde->start_address;
95 1.1 christos }
96 1.1 christos
97 1.1 christos /* Get the start address symbol from the DWARF FDE. */
98 1.1 christos
99 1.1 christos static symbolS*
100 1.1 christos get_dw_fde_end_addrS (const struct fde_entry *dw_fde)
101 1.1 christos {
102 1.1 christos return dw_fde->end_address;
103 1.1 christos }
104 1.1 christos
105 1.1 christos /* Get whether PAUTH B key is used. */
106 1.1 christos static bool
107 1.1 christos get_dw_fde_pauth_b_key_p (const struct fde_entry *dw_fde ATTRIBUTE_UNUSED)
108 1.1 christos {
109 1.1 christos #ifdef tc_fde_entry_extras
110 1.1 christos return (dw_fde->pauth_key == AARCH64_PAUTH_KEY_B);
111 1.1 christos #else
112 1.1 christos return false;
113 1.1 christos #endif
114 1.1 christos }
115 1.1 christos
116 1.1 christos /* SFrame Frame Row Entry (FRE) related functions. */
117 1.1 christos
118 1.1 christos static void
119 1.1 christos sframe_fre_set_begin_addr (struct sframe_row_entry *fre, symbolS *beginS)
120 1.1 christos {
121 1.1 christos fre->pc_begin = beginS;
122 1.1 christos }
123 1.1 christos
124 1.1 christos static void
125 1.1 christos sframe_fre_set_end_addr (struct sframe_row_entry *fre, symbolS *endS)
126 1.1 christos {
127 1.1 christos fre->pc_end = endS;
128 1.1 christos }
129 1.1 christos
130 1.1 christos static void
131 1.1 christos sframe_fre_set_cfa_base_reg (struct sframe_row_entry *fre,
132 1.1 christos unsigned int cfa_base_reg)
133 1.1 christos {
134 1.1 christos fre->cfa_base_reg = cfa_base_reg;
135 1.1 christos fre->merge_candidate = false;
136 1.1 christos }
137 1.1 christos
138 1.1.1.2 christos static offsetT
139 1.1.1.2 christos sframe_fre_get_cfa_offset (const struct sframe_row_entry * fre)
140 1.1.1.2 christos {
141 1.1.1.2 christos offsetT offset = fre->cfa_offset;
142 1.1.1.2 christos
143 1.1.1.2 christos /* For s390x undo adjustment of CFA offset (to enable 8-bit offsets). */
144 1.1.1.2 christos if (sframe_get_abi_arch () == SFRAME_ABI_S390X_ENDIAN_BIG)
145 1.1.1.2 christos offset = SFRAME_V2_S390X_CFA_OFFSET_DECODE (offset);
146 1.1.1.2 christos
147 1.1.1.2 christos return offset;
148 1.1.1.2 christos }
149 1.1.1.2 christos
150 1.1 christos static void
151 1.1 christos sframe_fre_set_cfa_offset (struct sframe_row_entry *fre,
152 1.1 christos offsetT cfa_offset)
153 1.1 christos {
154 1.1.1.2 christos /* For s390x adjust CFA offset to enable 8-bit offsets. */
155 1.1.1.2 christos if (sframe_get_abi_arch () == SFRAME_ABI_S390X_ENDIAN_BIG)
156 1.1.1.2 christos cfa_offset = SFRAME_V2_S390X_CFA_OFFSET_ENCODE (cfa_offset);
157 1.1.1.2 christos
158 1.1 christos fre->cfa_offset = cfa_offset;
159 1.1 christos fre->merge_candidate = false;
160 1.1 christos }
161 1.1 christos
162 1.1 christos static void
163 1.1 christos sframe_fre_set_ra_track (struct sframe_row_entry *fre, offsetT ra_offset)
164 1.1 christos {
165 1.1 christos fre->ra_loc = SFRAME_FRE_ELEM_LOC_STACK;
166 1.1 christos fre->ra_offset = ra_offset;
167 1.1 christos fre->merge_candidate = false;
168 1.1 christos }
169 1.1 christos
170 1.1 christos static void
171 1.1 christos sframe_fre_set_bp_track (struct sframe_row_entry *fre, offsetT bp_offset)
172 1.1 christos {
173 1.1 christos fre->bp_loc = SFRAME_FRE_ELEM_LOC_STACK;
174 1.1 christos fre->bp_offset = bp_offset;
175 1.1 christos fre->merge_candidate = false;
176 1.1 christos }
177 1.1 christos
178 1.1 christos /* All stack offset values within an FRE are uniformly encoded in the same
179 1.1 christos number of bytes. The size of the stack offset values will, however, vary
180 1.1 christos across FREs. */
181 1.1 christos
182 1.1 christos #define VALUE_8BIT 0x7f
183 1.1 christos #define VALUE_16BIT 0x7fff
184 1.1 christos #define VALUE_32BIT 0x7fffffff
185 1.1 christos #define VALUE_64BIT 0x7fffffffffffffff
186 1.1 christos
187 1.1 christos /* Given a signed offset, return the size in bytes needed to represent it. */
188 1.1 christos
189 1.1 christos static unsigned int
190 1.1 christos get_offset_size_in_bytes (offsetT value)
191 1.1 christos {
192 1.1 christos unsigned int size = 0;
193 1.1 christos
194 1.1 christos if (value <= VALUE_8BIT && value >= (offsetT) -VALUE_8BIT)
195 1.1 christos size = 1;
196 1.1 christos else if (value <= VALUE_16BIT && value >= (offsetT) -VALUE_16BIT)
197 1.1 christos size = 2;
198 1.1 christos else if (value <= VALUE_32BIT && value >= (offsetT) -VALUE_32BIT)
199 1.1 christos size = 4;
200 1.1 christos else if ((sizeof (offsetT) > 4) && (value <= (offsetT) VALUE_64BIT
201 1.1 christos && value >= (offsetT) -VALUE_64BIT))
202 1.1 christos size = 8;
203 1.1 christos
204 1.1 christos return size;
205 1.1 christos }
206 1.1 christos
207 1.1 christos #define SFRAME_FRE_OFFSET_FUNC_MAP_INDEX_1B 0 /* SFRAME_FRE_OFFSET_1B. */
208 1.1 christos #define SFRAME_FRE_OFFSET_FUNC_MAP_INDEX_2B 1 /* SFRAME_FRE_OFFSET_2B. */
209 1.1 christos #define SFRAME_FRE_OFFSET_FUNC_MAP_INDEX_4B 2 /* SFRAME_FRE_OFFSET_4B. */
210 1.1 christos #define SFRAME_FRE_OFFSET_FUNC_MAP_INDEX_8B 3 /* Not supported in SFrame. */
211 1.1 christos #define SFRAME_FRE_OFFSET_FUNC_MAP_INDEX_MAX SFRAME_FRE_OFFSET_FUNC_MAP_INDEX_8B
212 1.1 christos
213 1.1 christos /* Helper struct for mapping offset size to output functions. */
214 1.1 christos
215 1.1 christos struct sframe_fre_offset_func_map
216 1.1 christos {
217 1.1 christos unsigned int offset_size;
218 1.1 christos void (*out_func)(int);
219 1.1 christos };
220 1.1 christos
221 1.1 christos /* Given an OFFSET_SIZE, return the size in bytes needed to represent it. */
222 1.1 christos
223 1.1 christos static unsigned int
224 1.1 christos sframe_fre_offset_func_map_index (unsigned int offset_size)
225 1.1 christos {
226 1.1 christos unsigned int idx = SFRAME_FRE_OFFSET_FUNC_MAP_INDEX_MAX;
227 1.1 christos
228 1.1 christos switch (offset_size)
229 1.1 christos {
230 1.1 christos case SFRAME_FRE_OFFSET_1B:
231 1.1 christos idx = SFRAME_FRE_OFFSET_FUNC_MAP_INDEX_1B;
232 1.1 christos break;
233 1.1 christos case SFRAME_FRE_OFFSET_2B:
234 1.1 christos idx = SFRAME_FRE_OFFSET_FUNC_MAP_INDEX_2B;
235 1.1 christos break;
236 1.1 christos case SFRAME_FRE_OFFSET_4B:
237 1.1 christos idx = SFRAME_FRE_OFFSET_FUNC_MAP_INDEX_4B;
238 1.1 christos break;
239 1.1 christos default:
240 1.1 christos /* Not supported in SFrame. */
241 1.1 christos break;
242 1.1 christos }
243 1.1 christos
244 1.1 christos return idx;
245 1.1 christos }
246 1.1 christos
247 1.1 christos /* Mapping from offset size to the output function to emit the value. */
248 1.1 christos
249 1.1 christos static const
250 1.1 christos struct sframe_fre_offset_func_map
251 1.1 christos fre_offset_func_map[SFRAME_FRE_OFFSET_FUNC_MAP_INDEX_MAX+1] =
252 1.1 christos {
253 1.1 christos { SFRAME_FRE_OFFSET_1B, out_one },
254 1.1 christos { SFRAME_FRE_OFFSET_2B, out_two },
255 1.1 christos { SFRAME_FRE_OFFSET_4B, out_four },
256 1.1 christos { -1, NULL } /* Not Supported in SFrame. */
257 1.1 christos };
258 1.1 christos
259 1.1 christos /* SFrame version specific operations access. */
260 1.1 christos
261 1.1 christos static struct sframe_version_ops sframe_ver_ops;
262 1.1 christos
263 1.1 christos /* SFrame (SFRAME_VERSION_1) set FRE info. */
264 1.1 christos
265 1.1 christos static unsigned char
266 1.1 christos sframe_v1_set_fre_info (unsigned int base_reg, unsigned int num_offsets,
267 1.1 christos unsigned int offset_size, bool mangled_ra_p)
268 1.1 christos {
269 1.1 christos unsigned char fre_info;
270 1.1 christos fre_info = SFRAME_V1_FRE_INFO (base_reg, num_offsets, offset_size);
271 1.1 christos fre_info = SFRAME_V1_FRE_INFO_UPDATE_MANGLED_RA_P (mangled_ra_p, fre_info);
272 1.1 christos return fre_info;
273 1.1 christos }
274 1.1 christos
275 1.1 christos /* SFrame (SFRAME_VERSION_1) set function info. */
276 1.1 christos static unsigned char
277 1.1 christos sframe_v1_set_func_info (unsigned int fde_type, unsigned int fre_type,
278 1.1 christos unsigned int pauth_key)
279 1.1 christos {
280 1.1 christos unsigned char func_info;
281 1.1 christos func_info = SFRAME_V1_FUNC_INFO (fde_type, fre_type);
282 1.1 christos func_info = SFRAME_V1_FUNC_INFO_UPDATE_PAUTH_KEY (pauth_key, func_info);
283 1.1 christos return func_info;
284 1.1 christos }
285 1.1 christos
286 1.1 christos /* SFrame version specific operations setup. */
287 1.1 christos
288 1.1 christos static void
289 1.1 christos sframe_set_version (uint32_t sframe_version ATTRIBUTE_UNUSED)
290 1.1 christos {
291 1.1 christos sframe_ver_ops.format_version = SFRAME_VERSION_2;
292 1.1 christos
293 1.1 christos /* These operations remain the same for SFRAME_VERSION_2 as fre_info and
294 1.1 christos func_info have not changed from SFRAME_VERSION_1. */
295 1.1 christos
296 1.1 christos sframe_ver_ops.set_fre_info = sframe_v1_set_fre_info;
297 1.1 christos
298 1.1 christos sframe_ver_ops.set_func_info = sframe_v1_set_func_info;
299 1.1 christos }
300 1.1 christos
301 1.1 christos /* SFrame set FRE info. */
302 1.1 christos
303 1.1 christos static unsigned char
304 1.1 christos sframe_set_fre_info (unsigned int base_reg, unsigned int num_offsets,
305 1.1 christos unsigned int offset_size, bool mangled_ra_p)
306 1.1 christos {
307 1.1 christos return sframe_ver_ops.set_fre_info (base_reg, num_offsets,
308 1.1 christos offset_size, mangled_ra_p);
309 1.1 christos }
310 1.1 christos
311 1.1 christos /* SFrame set func info. */
312 1.1 christos
313 1.1 christos static unsigned char
314 1.1 christos sframe_set_func_info (unsigned int fde_type, unsigned int fre_type,
315 1.1 christos unsigned int pauth_key)
316 1.1 christos {
317 1.1 christos return sframe_ver_ops.set_func_info (fde_type, fre_type, pauth_key);
318 1.1 christos }
319 1.1 christos
320 1.1 christos /* Get the number of SFrame FDEs for the current file. */
321 1.1 christos
322 1.1 christos static unsigned int
323 1.1 christos get_num_sframe_fdes (void);
324 1.1 christos
325 1.1 christos /* Get the number of SFrame frame row entries for the current file. */
326 1.1 christos
327 1.1 christos static unsigned int
328 1.1 christos get_num_sframe_fres (void);
329 1.1 christos
330 1.1 christos /* Get CFA base register ID as represented in SFrame Frame Row Entry. */
331 1.1 christos
332 1.1 christos static unsigned int
333 1.1 christos get_fre_base_reg_id (struct sframe_row_entry *sframe_fre)
334 1.1 christos {
335 1.1 christos unsigned int cfi_insn_cfa_base_reg = sframe_fre->cfa_base_reg;
336 1.1 christos unsigned fre_base_reg = SFRAME_BASE_REG_SP;
337 1.1 christos
338 1.1 christos if (cfi_insn_cfa_base_reg == SFRAME_CFA_FP_REG)
339 1.1 christos fre_base_reg = SFRAME_BASE_REG_FP;
340 1.1 christos
341 1.1 christos /* Only one bit is reserved in SFRAME_VERSION_1. */
342 1.1 christos gas_assert (fre_base_reg == SFRAME_BASE_REG_SP
343 1.1 christos || fre_base_reg == SFRAME_BASE_REG_FP);
344 1.1 christos
345 1.1 christos return fre_base_reg;
346 1.1 christos }
347 1.1 christos
348 1.1 christos /* Get number of offsets necessary for the SFrame Frame Row Entry. */
349 1.1 christos
350 1.1 christos static unsigned int
351 1.1 christos get_fre_num_offsets (struct sframe_row_entry *sframe_fre)
352 1.1 christos {
353 1.1 christos /* Atleast 1 must always be present (to recover CFA). */
354 1.1 christos unsigned int fre_num_offsets = 1;
355 1.1 christos
356 1.1 christos if (sframe_fre->bp_loc == SFRAME_FRE_ELEM_LOC_STACK)
357 1.1 christos fre_num_offsets++;
358 1.1.1.2 christos if (sframe_ra_tracking_p ()
359 1.1.1.2 christos && (sframe_fre->ra_loc == SFRAME_FRE_ELEM_LOC_STACK
360 1.1.1.2 christos /* For s390x account padding RA offset, if FP without RA saved. */
361 1.1.1.2 christos || (sframe_get_abi_arch () == SFRAME_ABI_S390X_ENDIAN_BIG
362 1.1.1.2 christos && sframe_fre->bp_loc == SFRAME_FRE_ELEM_LOC_STACK)))
363 1.1 christos fre_num_offsets++;
364 1.1 christos return fre_num_offsets;
365 1.1 christos }
366 1.1 christos
367 1.1 christos /* Get the minimum necessary offset size (in bytes) for this
368 1.1 christos SFrame frame row entry. */
369 1.1 christos
370 1.1 christos static unsigned int
371 1.1 christos sframe_get_fre_offset_size (struct sframe_row_entry *sframe_fre)
372 1.1 christos {
373 1.1 christos unsigned int max_offset_size = 0;
374 1.1 christos unsigned int cfa_offset_size = 0;
375 1.1 christos unsigned int bp_offset_size = 0;
376 1.1 christos unsigned int ra_offset_size = 0;
377 1.1 christos
378 1.1 christos unsigned int fre_offset_size = 0;
379 1.1 christos
380 1.1 christos /* What size of offsets appear in this frame row entry. */
381 1.1 christos cfa_offset_size = get_offset_size_in_bytes (sframe_fre->cfa_offset);
382 1.1 christos if (sframe_fre->bp_loc == SFRAME_FRE_ELEM_LOC_STACK)
383 1.1 christos bp_offset_size = get_offset_size_in_bytes (sframe_fre->bp_offset);
384 1.1.1.2 christos if (sframe_ra_tracking_p ())
385 1.1.1.2 christos {
386 1.1.1.2 christos if (sframe_fre->ra_loc == SFRAME_FRE_ELEM_LOC_STACK)
387 1.1.1.2 christos ra_offset_size = get_offset_size_in_bytes (sframe_fre->ra_offset);
388 1.1.1.2 christos /* For s390x account padding RA offset, if FP without RA saved. */
389 1.1.1.2 christos else if (sframe_get_abi_arch () == SFRAME_ABI_S390X_ENDIAN_BIG
390 1.1.1.2 christos && sframe_fre->bp_loc == SFRAME_FRE_ELEM_LOC_STACK)
391 1.1.1.2 christos ra_offset_size = get_offset_size_in_bytes (SFRAME_FRE_RA_OFFSET_INVALID);
392 1.1.1.2 christos }
393 1.1 christos
394 1.1 christos /* Get the maximum size needed to represent the offsets. */
395 1.1 christos max_offset_size = cfa_offset_size;
396 1.1 christos if (bp_offset_size > max_offset_size)
397 1.1 christos max_offset_size = bp_offset_size;
398 1.1 christos if (ra_offset_size > max_offset_size)
399 1.1 christos max_offset_size = ra_offset_size;
400 1.1 christos
401 1.1 christos gas_assert (max_offset_size);
402 1.1 christos
403 1.1 christos switch (max_offset_size)
404 1.1 christos {
405 1.1 christos case 1:
406 1.1 christos fre_offset_size = SFRAME_FRE_OFFSET_1B;
407 1.1 christos break;
408 1.1 christos case 2:
409 1.1 christos fre_offset_size = SFRAME_FRE_OFFSET_2B;
410 1.1 christos break;
411 1.1 christos case 4:
412 1.1 christos fre_offset_size = SFRAME_FRE_OFFSET_4B;
413 1.1 christos break;
414 1.1 christos default:
415 1.1 christos /* Offset of size 8 bytes is not supported in SFrame format
416 1.1 christos version 1. */
417 1.1 christos as_fatal (_("SFrame unsupported offset value\n"));
418 1.1 christos break;
419 1.1 christos }
420 1.1 christos
421 1.1 christos return fre_offset_size;
422 1.1 christos }
423 1.1 christos
424 1.1 christos #if SFRAME_FRE_TYPE_SELECTION_OPT
425 1.1 christos
426 1.1 christos /* Create a composite expression CEXP (for SFrame FRE start address) such that:
427 1.1 christos
428 1.1 christos exp = <val> OP_absent <width>, where,
429 1.1 christos
430 1.1 christos - <val> and <width> are themselves expressionS.
431 1.1 christos - <val> stores the expression which when evaluated gives the value of the
432 1.1 christos start address offset of the FRE.
433 1.1 christos - <width> stores the expression when evaluated gives the number of bytes
434 1.1 christos needed to encode the start address offset of the FRE.
435 1.1 christos
436 1.1 christos The use of OP_absent as the X_op_symbol helps identify this expression
437 1.1 christos later when fragments are fixed up. */
438 1.1 christos
439 1.1 christos static void
440 1.1 christos create_fre_start_addr_exp (expressionS *cexp, symbolS *fre_pc_begin,
441 1.1 christos symbolS *fde_start_address,
442 1.1 christos symbolS *fde_end_address)
443 1.1 christos {
444 1.1 christos expressionS val;
445 1.1 christos expressionS width;
446 1.1 christos
447 1.1 christos /* val expression stores the FDE start address offset from the start PC
448 1.1 christos of function. */
449 1.1 christos val.X_op = O_subtract;
450 1.1 christos val.X_add_symbol = fre_pc_begin;
451 1.1 christos val.X_op_symbol = fde_start_address;
452 1.1 christos val.X_add_number = 0;
453 1.1 christos
454 1.1 christos /* width expressions stores the size of the function. This is used later
455 1.1 christos to determine the number of bytes to be used to encode the FRE start
456 1.1 christos address of each FRE of the function. */
457 1.1 christos width.X_op = O_subtract;
458 1.1 christos width.X_add_symbol = fde_end_address;
459 1.1 christos width.X_op_symbol = fde_start_address;
460 1.1 christos width.X_add_number = 0;
461 1.1 christos
462 1.1 christos cexp->X_op = O_absent;
463 1.1 christos cexp->X_add_symbol = make_expr_symbol (&val);
464 1.1 christos cexp->X_op_symbol = make_expr_symbol (&width);
465 1.1 christos cexp->X_add_number = 0;
466 1.1 christos }
467 1.1 christos
468 1.1 christos /* Create a composite expression CEXP (for SFrame FDE function info) such that:
469 1.1 christos
470 1.1 christos exp = <rest_of_func_info> OP_modulus <width>, where,
471 1.1 christos
472 1.1 christos - <rest_of_func_info> and <width> are themselves expressionS.
473 1.1 christos - <rest_of_func_info> stores a constant expression where X_add_number is
474 1.1 christos used to stash away the func_info. The upper 4-bits of the func_info are copied
475 1.1 christos back to the resulting byte by the fragment fixup logic.
476 1.1 christos - <width> stores the expression when evaluated gives the size of the
477 1.1 christos function in number of bytes.
478 1.1 christos
479 1.1 christos The use of OP_modulus as the X_op_symbol helps identify this expression
480 1.1 christos later when fragments are fixed up. */
481 1.1 christos
482 1.1 christos static void
483 1.1 christos create_func_info_exp (expressionS *cexp, symbolS *dw_fde_end_addrS,
484 1.1 christos symbolS *dw_fde_start_addrS, uint8_t func_info)
485 1.1 christos {
486 1.1 christos expressionS width;
487 1.1 christos expressionS rest_of_func_info;
488 1.1 christos
489 1.1 christos width.X_op = O_subtract;
490 1.1 christos width.X_add_symbol = dw_fde_end_addrS;
491 1.1 christos width.X_op_symbol = dw_fde_start_addrS;
492 1.1 christos width.X_add_number = 0;
493 1.1 christos
494 1.1 christos rest_of_func_info.X_op = O_constant;
495 1.1 christos rest_of_func_info.X_add_number = func_info;
496 1.1 christos
497 1.1 christos cexp->X_op = O_modulus;
498 1.1 christos cexp->X_add_symbol = make_expr_symbol (&rest_of_func_info);
499 1.1 christos cexp->X_op_symbol = make_expr_symbol (&width);
500 1.1 christos cexp->X_add_number = 0;
501 1.1 christos }
502 1.1 christos
503 1.1 christos #endif
504 1.1 christos
505 1.1.1.2 christos static struct sframe_row_entry*
506 1.1.1.2 christos sframe_row_entry_new (void)
507 1.1.1.2 christos {
508 1.1.1.2 christos struct sframe_row_entry *fre = XCNEW (struct sframe_row_entry);
509 1.1.1.2 christos /* Reset cfa_base_reg to -1. A value of 0 will imply some valid register
510 1.1.1.2 christos for the supported arches. */
511 1.1.1.2 christos fre->cfa_base_reg = SFRAME_FRE_BASE_REG_INVAL;
512 1.1.1.2 christos fre->merge_candidate = true;
513 1.1.1.2 christos /* Reset the mangled RA status bit to zero by default. We will
514 1.1.1.2 christos initialize it in sframe_row_entry_initialize () with the sticky
515 1.1.1.2 christos bit if set. */
516 1.1.1.2 christos fre->mangled_ra_p = false;
517 1.1.1.2 christos
518 1.1.1.2 christos return fre;
519 1.1.1.2 christos }
520 1.1.1.2 christos
521 1.1.1.2 christos static void
522 1.1.1.2 christos sframe_row_entry_free (struct sframe_row_entry *fre)
523 1.1.1.2 christos {
524 1.1.1.2 christos while (fre)
525 1.1.1.2 christos {
526 1.1.1.2 christos struct sframe_row_entry *fre_next = fre->next;
527 1.1.1.2 christos XDELETE (fre);
528 1.1.1.2 christos fre = fre_next;
529 1.1.1.2 christos }
530 1.1.1.2 christos }
531 1.1.1.2 christos
532 1.1.1.2 christos /* Allocate an SFrame FDE. */
533 1.1.1.2 christos
534 1.1.1.2 christos static struct sframe_func_entry*
535 1.1.1.2 christos sframe_fde_alloc (void)
536 1.1.1.2 christos {
537 1.1.1.2 christos return XCNEW (struct sframe_func_entry);
538 1.1.1.2 christos }
539 1.1.1.2 christos
540 1.1.1.2 christos /* Free up the SFrame FDE. */
541 1.1.1.2 christos
542 1.1.1.2 christos static void
543 1.1.1.2 christos sframe_fde_free (struct sframe_func_entry *sframe_fde)
544 1.1.1.2 christos {
545 1.1.1.2 christos sframe_row_entry_free (sframe_fde->sframe_fres);
546 1.1.1.2 christos XDELETE (sframe_fde);
547 1.1.1.2 christos }
548 1.1.1.2 christos
549 1.1 christos static void
550 1.1 christos output_sframe_row_entry (symbolS *fde_start_addr,
551 1.1 christos symbolS *fde_end_addr,
552 1.1 christos struct sframe_row_entry *sframe_fre)
553 1.1 christos {
554 1.1 christos unsigned char fre_info;
555 1.1 christos unsigned int fre_num_offsets;
556 1.1 christos unsigned int fre_offset_size;
557 1.1 christos unsigned int fre_base_reg;
558 1.1 christos expressionS exp;
559 1.1 christos unsigned int fre_addr_size;
560 1.1 christos
561 1.1 christos unsigned int idx = 0;
562 1.1 christos unsigned int fre_write_offsets = 0;
563 1.1 christos
564 1.1 christos fre_addr_size = 4; /* 4 bytes by default. FIXME tie it to fre_type? */
565 1.1 christos
566 1.1 christos /* SFrame FRE Start Address. */
567 1.1 christos #if SFRAME_FRE_TYPE_SELECTION_OPT
568 1.1 christos create_fre_start_addr_exp (&exp, sframe_fre->pc_begin, fde_start_addr,
569 1.1 christos fde_end_addr);
570 1.1 christos frag_grow (fre_addr_size);
571 1.1.1.2 christos frag_var (rs_sframe, fre_addr_size, 0, 0,
572 1.1 christos make_expr_symbol (&exp), 0, (char *) frag_now);
573 1.1 christos #else
574 1.1 christos gas_assert (fde_end_addr);
575 1.1 christos exp.X_op = O_subtract;
576 1.1 christos exp.X_add_symbol = sframe_fre->pc_begin; /* to. */
577 1.1 christos exp.X_op_symbol = fde_start_addr; /* from. */
578 1.1 christos exp.X_add_number = 0;
579 1.1 christos emit_expr (&exp, fre_addr_size);
580 1.1 christos #endif
581 1.1 christos
582 1.1 christos /* Create the fre_info using the CFA base register, number of offsets and max
583 1.1 christos size of offset in this frame row entry. */
584 1.1 christos fre_base_reg = get_fre_base_reg_id (sframe_fre);
585 1.1 christos fre_num_offsets = get_fre_num_offsets (sframe_fre);
586 1.1 christos fre_offset_size = sframe_get_fre_offset_size (sframe_fre);
587 1.1 christos fre_info = sframe_set_fre_info (fre_base_reg, fre_num_offsets,
588 1.1 christos fre_offset_size, sframe_fre->mangled_ra_p);
589 1.1 christos out_one (fre_info);
590 1.1 christos
591 1.1 christos idx = sframe_fre_offset_func_map_index (fre_offset_size);
592 1.1 christos gas_assert (idx < SFRAME_FRE_OFFSET_FUNC_MAP_INDEX_MAX);
593 1.1 christos
594 1.1 christos /* Write out the offsets in order - cfa, bp, ra. */
595 1.1 christos fre_offset_func_map[idx].out_func (sframe_fre->cfa_offset);
596 1.1 christos fre_write_offsets++;
597 1.1 christos
598 1.1.1.2 christos if (sframe_ra_tracking_p ())
599 1.1 christos {
600 1.1.1.2 christos if (sframe_fre->ra_loc == SFRAME_FRE_ELEM_LOC_STACK)
601 1.1.1.2 christos {
602 1.1.1.2 christos fre_offset_func_map[idx].out_func (sframe_fre->ra_offset);
603 1.1.1.2 christos fre_write_offsets++;
604 1.1.1.2 christos }
605 1.1.1.2 christos /* For s390x write padding RA offset, if FP without RA saved. */
606 1.1.1.2 christos else if (sframe_get_abi_arch () == SFRAME_ABI_S390X_ENDIAN_BIG
607 1.1.1.2 christos && sframe_fre->bp_loc == SFRAME_FRE_ELEM_LOC_STACK)
608 1.1.1.2 christos {
609 1.1.1.2 christos fre_offset_func_map[idx].out_func (SFRAME_FRE_RA_OFFSET_INVALID);
610 1.1.1.2 christos fre_write_offsets++;
611 1.1.1.2 christos }
612 1.1 christos }
613 1.1 christos if (sframe_fre->bp_loc == SFRAME_FRE_ELEM_LOC_STACK)
614 1.1 christos {
615 1.1 christos fre_offset_func_map[idx].out_func (sframe_fre->bp_offset);
616 1.1 christos fre_write_offsets++;
617 1.1 christos }
618 1.1 christos
619 1.1 christos /* Check if the expected number offsets have been written out
620 1.1 christos in this FRE. */
621 1.1 christos gas_assert (fre_write_offsets == fre_num_offsets);
622 1.1 christos }
623 1.1 christos
624 1.1 christos static void
625 1.1 christos output_sframe_funcdesc (symbolS *start_of_fre_section,
626 1.1 christos symbolS *fre_symbol,
627 1.1 christos struct sframe_func_entry *sframe_fde)
628 1.1 christos {
629 1.1 christos expressionS exp;
630 1.1 christos symbolS *dw_fde_start_addrS, *dw_fde_end_addrS;
631 1.1 christos unsigned int pauth_key;
632 1.1 christos
633 1.1 christos dw_fde_start_addrS = get_dw_fde_start_addrS (sframe_fde->dw_fde);
634 1.1 christos dw_fde_end_addrS = get_dw_fde_end_addrS (sframe_fde->dw_fde);
635 1.1 christos
636 1.1.1.2 christos /* Start address of the function. gas always emits this value with encoding
637 1.1.1.2 christos SFRAME_F_FDE_FUNC_START_PCREL. See PR ld/32666. */
638 1.1 christos exp.X_op = O_subtract;
639 1.1 christos exp.X_add_symbol = dw_fde_start_addrS; /* to location. */
640 1.1 christos exp.X_op_symbol = symbol_temp_new_now (); /* from location. */
641 1.1 christos exp.X_add_number = 0;
642 1.1.1.2 christos emit_expr (&exp, sizeof_member (sframe_func_desc_entry,
643 1.1.1.2 christos sfde_func_start_address));
644 1.1 christos
645 1.1 christos /* Size of the function in bytes. */
646 1.1 christos exp.X_op = O_subtract;
647 1.1 christos exp.X_add_symbol = dw_fde_end_addrS;
648 1.1 christos exp.X_op_symbol = dw_fde_start_addrS;
649 1.1 christos exp.X_add_number = 0;
650 1.1.1.2 christos emit_expr (&exp, sizeof_member (sframe_func_desc_entry,
651 1.1.1.2 christos sfde_func_size));
652 1.1 christos
653 1.1 christos /* Offset to the first frame row entry. */
654 1.1 christos exp.X_op = O_subtract;
655 1.1 christos exp.X_add_symbol = fre_symbol; /* Minuend. */
656 1.1 christos exp.X_op_symbol = start_of_fre_section; /* Subtrahend. */
657 1.1 christos exp.X_add_number = 0;
658 1.1.1.2 christos emit_expr (&exp, sizeof_member (sframe_func_desc_entry,
659 1.1.1.2 christos sfde_func_start_fre_off));
660 1.1 christos
661 1.1 christos /* Number of FREs. */
662 1.1 christos out_four (sframe_fde->num_fres);
663 1.1 christos
664 1.1 christos /* SFrame FDE function info. */
665 1.1 christos unsigned char func_info;
666 1.1 christos pauth_key = (get_dw_fde_pauth_b_key_p (sframe_fde->dw_fde)
667 1.1 christos ? SFRAME_AARCH64_PAUTH_KEY_B : SFRAME_AARCH64_PAUTH_KEY_A);
668 1.1 christos func_info = sframe_set_func_info (SFRAME_FDE_TYPE_PCINC,
669 1.1 christos SFRAME_FRE_TYPE_ADDR4,
670 1.1 christos pauth_key);
671 1.1 christos #if SFRAME_FRE_TYPE_SELECTION_OPT
672 1.1 christos expressionS cexp;
673 1.1 christos create_func_info_exp (&cexp, dw_fde_end_addrS, dw_fde_start_addrS,
674 1.1 christos func_info);
675 1.1 christos frag_grow (1); /* Size of func info is unsigned char. */
676 1.1.1.2 christos frag_var (rs_sframe, 1, 0, 0, make_expr_symbol (&cexp), 0,
677 1.1.1.2 christos (char *) frag_now);
678 1.1 christos #else
679 1.1 christos out_one (func_info);
680 1.1 christos #endif
681 1.1 christos out_one (0);
682 1.1 christos out_two (0);
683 1.1 christos }
684 1.1 christos
685 1.1 christos static void
686 1.1 christos output_sframe_internal (void)
687 1.1 christos {
688 1.1 christos expressionS exp;
689 1.1 christos unsigned int i = 0;
690 1.1 christos
691 1.1 christos symbolS *end_of_frame_hdr;
692 1.1 christos symbolS *end_of_frame_section;
693 1.1 christos symbolS *start_of_func_desc_section;
694 1.1 christos symbolS *start_of_fre_section;
695 1.1.1.2 christos struct sframe_func_entry *sframe_fde, *sframe_fde_next;
696 1.1 christos struct sframe_row_entry *sframe_fre;
697 1.1 christos unsigned char abi_arch = 0;
698 1.1.1.2 christos int fixed_fp_offset = SFRAME_CFA_FIXED_FP_INVALID;
699 1.1 christos int fixed_ra_offset = SFRAME_CFA_FIXED_RA_INVALID;
700 1.1 christos
701 1.1 christos /* The function descriptor entries as dumped by the assembler are not
702 1.1.1.2 christos sorted on PCs. Fix for PR ld/32666 requires setting of an additional
703 1.1.1.2 christos flag in SFrame Version 2. */
704 1.1.1.2 christos unsigned char sframe_flags = SFRAME_F_FDE_FUNC_START_PCREL;
705 1.1 christos
706 1.1 christos unsigned int num_fdes = get_num_sframe_fdes ();
707 1.1 christos unsigned int num_fres = get_num_sframe_fres ();
708 1.1.1.2 christos symbolS **fde_fre_symbols = XNEWVEC (symbolS *, num_fdes);
709 1.1.1.2 christos for (i = 0; i < num_fdes; i++)
710 1.1.1.2 christos fde_fre_symbols[i] = symbol_temp_make ();
711 1.1 christos
712 1.1 christos end_of_frame_hdr = symbol_temp_make ();
713 1.1 christos start_of_fre_section = symbol_temp_make ();
714 1.1 christos start_of_func_desc_section = symbol_temp_make ();
715 1.1 christos end_of_frame_section = symbol_temp_make ();
716 1.1 christos
717 1.1 christos /* Output the preamble of SFrame section. */
718 1.1 christos out_two (SFRAME_MAGIC);
719 1.1 christos out_one (SFRAME_VERSION);
720 1.1.1.2 christos /* gas must ensure emitted SFrame sections have at least the required flags
721 1.1.1.2 christos set. */
722 1.1.1.2 christos gas_assert ((sframe_flags & SFRAME_V2_GNU_AS_LD_ENCODING_FLAGS)
723 1.1.1.2 christos == SFRAME_V2_GNU_AS_LD_ENCODING_FLAGS);
724 1.1 christos out_one (sframe_flags);
725 1.1 christos /* abi/arch. */
726 1.1 christos #ifdef sframe_get_abi_arch
727 1.1 christos abi_arch = sframe_get_abi_arch ();
728 1.1 christos #endif
729 1.1 christos gas_assert (abi_arch);
730 1.1 christos out_one (abi_arch);
731 1.1 christos
732 1.1.1.2 christos /* Offset for the FP register from CFA. Neither of the AMD64 or AAPCS64
733 1.1.1.2 christos ABIs have a fixed offset for the FP register from the CFA. This may be
734 1.1 christos useful in future (but not without additional support in the toolchain)
735 1.1 christos for specialized handling/encoding for cases where, for example,
736 1.1 christos -fno-omit-frame-pointer is used. */
737 1.1.1.2 christos out_one (fixed_fp_offset);
738 1.1 christos
739 1.1.1.2 christos /* All ABIs participating in SFrame generation must define
740 1.1.1.2 christos sframe_ra_tracking_p.
741 1.1.1.2 christos When RA tracking (in FREs) is not needed (e.g., AMD64), SFrame assumes
742 1.1.1.2 christos the RA is going to be at a fixed offset from CFA. Check that the fixed RA
743 1.1.1.2 christos offset is appropriately defined in all cases. */
744 1.1 christos if (!sframe_ra_tracking_p ())
745 1.1.1.2 christos {
746 1.1.1.2 christos fixed_ra_offset = sframe_cfa_ra_offset ();
747 1.1.1.2 christos gas_assert (fixed_ra_offset != SFRAME_CFA_FIXED_RA_INVALID);
748 1.1.1.2 christos }
749 1.1 christos out_one (fixed_ra_offset);
750 1.1 christos
751 1.1.1.2 christos /* None of the AMD64, AARCH64, or s390x ABIs need the auxiliary header.
752 1.1 christos When the need does arise to use this field, the appropriate backend
753 1.1 christos must provide this information. */
754 1.1 christos out_one (0); /* Auxiliary SFrame header length. */
755 1.1 christos
756 1.1 christos out_four (num_fdes); /* Number of FDEs. */
757 1.1 christos out_four (num_fres); /* Number of FREs. */
758 1.1 christos
759 1.1.1.2 christos /* Size of FRE sub-section. */
760 1.1 christos exp.X_op = O_subtract;
761 1.1 christos exp.X_add_symbol = end_of_frame_section;
762 1.1 christos exp.X_op_symbol = start_of_fre_section;
763 1.1 christos exp.X_add_number = 0;
764 1.1.1.2 christos emit_expr (&exp, sizeof_member (sframe_header, sfh_fre_len));
765 1.1 christos
766 1.1.1.2 christos /* Offset of FDE sub-section. */
767 1.1 christos exp.X_op = O_subtract;
768 1.1 christos exp.X_add_symbol = end_of_frame_hdr;
769 1.1 christos exp.X_op_symbol = start_of_func_desc_section;
770 1.1 christos exp.X_add_number = 0;
771 1.1.1.2 christos emit_expr (&exp, sizeof_member (sframe_header, sfh_fdeoff));
772 1.1 christos
773 1.1 christos /* Offset of FRE sub-section. */
774 1.1 christos exp.X_op = O_subtract;
775 1.1 christos exp.X_add_symbol = start_of_fre_section;
776 1.1 christos exp.X_op_symbol = end_of_frame_hdr;
777 1.1 christos exp.X_add_number = 0;
778 1.1.1.2 christos emit_expr (&exp, sizeof_member (sframe_header, sfh_freoff));
779 1.1 christos
780 1.1 christos symbol_set_value_now (end_of_frame_hdr);
781 1.1 christos symbol_set_value_now (start_of_func_desc_section);
782 1.1 christos
783 1.1 christos /* Output the SFrame function descriptor entries. */
784 1.1 christos i = 0;
785 1.1 christos for (sframe_fde = all_sframe_fdes; sframe_fde; sframe_fde = sframe_fde->next)
786 1.1 christos {
787 1.1 christos output_sframe_funcdesc (start_of_fre_section,
788 1.1.1.2 christos fde_fre_symbols[i], sframe_fde);
789 1.1.1.2 christos i++;
790 1.1 christos }
791 1.1 christos
792 1.1 christos symbol_set_value_now (start_of_fre_section);
793 1.1 christos
794 1.1 christos /* Output the SFrame FREs. */
795 1.1 christos i = 0;
796 1.1 christos sframe_fde = all_sframe_fdes;
797 1.1 christos
798 1.1.1.2 christos for (sframe_fde = all_sframe_fdes; sframe_fde; sframe_fde = sframe_fde_next)
799 1.1 christos {
800 1.1.1.2 christos symbol_set_value_now (fde_fre_symbols[i]);
801 1.1 christos for (sframe_fre = sframe_fde->sframe_fres;
802 1.1 christos sframe_fre;
803 1.1 christos sframe_fre = sframe_fre->next)
804 1.1 christos {
805 1.1 christos output_sframe_row_entry (get_dw_fde_start_addrS (sframe_fde->dw_fde),
806 1.1 christos get_dw_fde_end_addrS (sframe_fde->dw_fde),
807 1.1 christos sframe_fre);
808 1.1 christos }
809 1.1.1.2 christos i++;
810 1.1.1.2 christos sframe_fde_next = sframe_fde->next;
811 1.1.1.2 christos sframe_fde_free (sframe_fde);
812 1.1 christos }
813 1.1.1.2 christos all_sframe_fdes = NULL;
814 1.1.1.2 christos last_sframe_fde = &all_sframe_fdes;
815 1.1 christos
816 1.1 christos symbol_set_value_now (end_of_frame_section);
817 1.1 christos
818 1.1.1.2 christos gas_assert (i == num_fdes);
819 1.1 christos
820 1.1.1.2 christos free (fde_fre_symbols);
821 1.1.1.2 christos fde_fre_symbols = NULL;
822 1.1 christos }
823 1.1 christos
824 1.1 christos static unsigned int
825 1.1 christos get_num_sframe_fdes (void)
826 1.1 christos {
827 1.1 christos struct sframe_func_entry *sframe_fde;
828 1.1 christos unsigned int total_fdes = 0;
829 1.1 christos
830 1.1 christos for (sframe_fde = all_sframe_fdes; sframe_fde ; sframe_fde = sframe_fde->next)
831 1.1 christos total_fdes++;
832 1.1 christos
833 1.1 christos return total_fdes;
834 1.1 christos }
835 1.1 christos
836 1.1 christos /* Get the total number of SFrame row entries across the FDEs. */
837 1.1 christos
838 1.1 christos static unsigned int
839 1.1 christos get_num_sframe_fres (void)
840 1.1 christos {
841 1.1 christos struct sframe_func_entry *sframe_fde;
842 1.1 christos unsigned int total_fres = 0;
843 1.1 christos
844 1.1 christos for (sframe_fde = all_sframe_fdes; sframe_fde ; sframe_fde = sframe_fde->next)
845 1.1 christos total_fres += sframe_fde->num_fres;
846 1.1 christos
847 1.1 christos return total_fres;
848 1.1 christos }
849 1.1 christos
850 1.1 christos /* SFrame translation context functions. */
851 1.1 christos
852 1.1 christos /* Allocate a new SFrame translation context. */
853 1.1 christos
854 1.1 christos static struct sframe_xlate_ctx*
855 1.1 christos sframe_xlate_ctx_alloc (void)
856 1.1 christos {
857 1.1 christos struct sframe_xlate_ctx* xlate_ctx = XCNEW (struct sframe_xlate_ctx);
858 1.1 christos return xlate_ctx;
859 1.1 christos }
860 1.1 christos
861 1.1 christos /* Initialize the given SFrame translation context. */
862 1.1 christos
863 1.1 christos static void
864 1.1 christos sframe_xlate_ctx_init (struct sframe_xlate_ctx *xlate_ctx)
865 1.1 christos {
866 1.1 christos xlate_ctx->dw_fde = NULL;
867 1.1 christos xlate_ctx->first_fre = NULL;
868 1.1 christos xlate_ctx->last_fre = NULL;
869 1.1 christos xlate_ctx->cur_fre = NULL;
870 1.1 christos xlate_ctx->remember_fre = NULL;
871 1.1 christos xlate_ctx->num_xlate_fres = 0;
872 1.1 christos }
873 1.1 christos
874 1.1 christos /* Cleanup the given SFrame translation context. */
875 1.1 christos
876 1.1 christos static void
877 1.1 christos sframe_xlate_ctx_cleanup (struct sframe_xlate_ctx *xlate_ctx)
878 1.1 christos {
879 1.1.1.2 christos sframe_row_entry_free (xlate_ctx->first_fre);
880 1.1.1.2 christos XDELETE (xlate_ctx->remember_fre);
881 1.1.1.2 christos XDELETE (xlate_ctx->cur_fre);
882 1.1 christos }
883 1.1 christos
884 1.1 christos /* Transfer the state from the SFrame translation context to the SFrame FDE. */
885 1.1 christos
886 1.1 christos static void
887 1.1 christos sframe_xlate_ctx_finalize (struct sframe_xlate_ctx *xlate_ctx,
888 1.1 christos struct sframe_func_entry *sframe_fde)
889 1.1 christos {
890 1.1 christos sframe_fde->dw_fde = xlate_ctx->dw_fde;
891 1.1 christos sframe_fde->sframe_fres = xlate_ctx->first_fre;
892 1.1 christos sframe_fde->num_fres = xlate_ctx->num_xlate_fres;
893 1.1 christos }
894 1.1 christos
895 1.1 christos /* Add the given FRE in the list of frame row entries in the given FDE
896 1.1 christos translation context. */
897 1.1 christos
898 1.1 christos static void
899 1.1 christos sframe_xlate_ctx_add_fre (struct sframe_xlate_ctx *xlate_ctx,
900 1.1 christos struct sframe_row_entry *fre)
901 1.1 christos {
902 1.1 christos gas_assert (xlate_ctx && fre);
903 1.1 christos
904 1.1 christos /* Add the frame row entry. */
905 1.1 christos if (!xlate_ctx->first_fre)
906 1.1 christos xlate_ctx->first_fre = fre;
907 1.1 christos else if (xlate_ctx->last_fre)
908 1.1 christos xlate_ctx->last_fre->next = fre;
909 1.1 christos
910 1.1 christos xlate_ctx->last_fre = fre;
911 1.1 christos
912 1.1 christos /* Keep track of the total number of SFrame frame row entries. */
913 1.1 christos xlate_ctx->num_xlate_fres++;
914 1.1 christos }
915 1.1 christos
916 1.1 christos /* A SFrame Frame Row Entry is self-sufficient in terms of stack tracing info
917 1.1 christos for a given PC. It contains information assimilated from multiple CFI
918 1.1 christos instructions, and hence, a new SFrame FRE is initialized with the data from
919 1.1 christos the previous known FRE, if any.
920 1.1 christos
921 1.1 christos Understandably, not all information (especially the instruction begin
922 1.1 christos and end boundaries) needs to be relayed. Hence, the caller of this API
923 1.1 christos must set the pc_begin and pc_end as applicable. */
924 1.1 christos
925 1.1 christos static void
926 1.1 christos sframe_row_entry_initialize (struct sframe_row_entry *cur_fre,
927 1.1 christos struct sframe_row_entry *prev_fre)
928 1.1 christos {
929 1.1 christos gas_assert (prev_fre);
930 1.1 christos cur_fre->cfa_base_reg = prev_fre->cfa_base_reg;
931 1.1 christos cur_fre->cfa_offset = prev_fre->cfa_offset;
932 1.1 christos cur_fre->bp_loc = prev_fre->bp_loc;
933 1.1 christos cur_fre->bp_offset = prev_fre->bp_offset;
934 1.1 christos cur_fre->ra_loc = prev_fre->ra_loc;
935 1.1 christos cur_fre->ra_offset = prev_fre->ra_offset;
936 1.1 christos /* Treat RA mangling as a sticky bit. It retains its value until another
937 1.1 christos .cfi_negate_ra_state is seen. */
938 1.1 christos cur_fre->mangled_ra_p = prev_fre->mangled_ra_p;
939 1.1 christos }
940 1.1 christos
941 1.1.1.2 christos /* Return SFrame register name for SP, FP, and RA, or NULL if other. */
942 1.1.1.2 christos
943 1.1.1.2 christos static const char *
944 1.1.1.2 christos sframe_register_name (unsigned int reg)
945 1.1.1.2 christos {
946 1.1.1.2 christos if (reg == SFRAME_CFA_SP_REG)
947 1.1.1.2 christos return "SP";
948 1.1.1.2 christos else if (reg == SFRAME_CFA_FP_REG)
949 1.1.1.2 christos return "FP";
950 1.1.1.2 christos else if (reg == SFRAME_CFA_RA_REG)
951 1.1.1.2 christos return "RA";
952 1.1.1.2 christos else
953 1.1.1.2 christos return NULL;
954 1.1.1.2 christos }
955 1.1.1.2 christos
956 1.1 christos /* Translate DW_CFA_advance_loc into SFrame context.
957 1.1 christos Return SFRAME_XLATE_OK if success. */
958 1.1 christos
959 1.1 christos static int
960 1.1 christos sframe_xlate_do_advance_loc (struct sframe_xlate_ctx *xlate_ctx,
961 1.1 christos struct cfi_insn_data *cfi_insn)
962 1.1 christos {
963 1.1 christos struct sframe_row_entry *last_fre = xlate_ctx->last_fre;
964 1.1 christos /* Get the scratchpad FRE currently being updated as the cfi_insn's
965 1.1 christos get interpreted. This FRE eventually gets linked in into the
966 1.1 christos list of FREs for the specific function. */
967 1.1 christos struct sframe_row_entry *cur_fre = xlate_ctx->cur_fre;
968 1.1 christos
969 1.1 christos if (cur_fre)
970 1.1 christos {
971 1.1 christos if (!cur_fre->merge_candidate)
972 1.1 christos {
973 1.1 christos sframe_fre_set_end_addr (cur_fre, cfi_insn->u.ll.lab2);
974 1.1 christos
975 1.1 christos sframe_xlate_ctx_add_fre (xlate_ctx, cur_fre);
976 1.1 christos last_fre = xlate_ctx->last_fre;
977 1.1 christos
978 1.1 christos xlate_ctx->cur_fre = sframe_row_entry_new ();
979 1.1 christos cur_fre = xlate_ctx->cur_fre;
980 1.1 christos
981 1.1 christos if (last_fre)
982 1.1 christos sframe_row_entry_initialize (cur_fre, last_fre);
983 1.1 christos }
984 1.1 christos else
985 1.1 christos {
986 1.1 christos sframe_fre_set_end_addr (last_fre, cfi_insn->u.ll.lab2);
987 1.1 christos gas_assert (last_fre->merge_candidate == false);
988 1.1 christos }
989 1.1 christos }
990 1.1 christos else
991 1.1 christos {
992 1.1 christos xlate_ctx->cur_fre = sframe_row_entry_new ();
993 1.1 christos cur_fre = xlate_ctx->cur_fre;
994 1.1 christos }
995 1.1 christos
996 1.1 christos gas_assert (cur_fre);
997 1.1 christos sframe_fre_set_begin_addr (cur_fre, cfi_insn->u.ll.lab2);
998 1.1 christos
999 1.1 christos return SFRAME_XLATE_OK;
1000 1.1 christos }
1001 1.1 christos
1002 1.1 christos /* Translate DW_CFA_def_cfa into SFrame context.
1003 1.1 christos Return SFRAME_XLATE_OK if success. */
1004 1.1 christos
1005 1.1 christos static int
1006 1.1 christos sframe_xlate_do_def_cfa (struct sframe_xlate_ctx *xlate_ctx,
1007 1.1 christos struct cfi_insn_data *cfi_insn)
1008 1.1 christos
1009 1.1 christos {
1010 1.1 christos /* Get the scratchpad FRE. This FRE will eventually get linked in. */
1011 1.1 christos struct sframe_row_entry *cur_fre = xlate_ctx->cur_fre;
1012 1.1 christos if (!cur_fre)
1013 1.1 christos {
1014 1.1 christos xlate_ctx->cur_fre = sframe_row_entry_new ();
1015 1.1 christos cur_fre = xlate_ctx->cur_fre;
1016 1.1 christos sframe_fre_set_begin_addr (cur_fre,
1017 1.1 christos get_dw_fde_start_addrS (xlate_ctx->dw_fde));
1018 1.1 christos }
1019 1.1 christos /* Define the current CFA rule to use the provided register and
1020 1.1.1.2 christos offset. However, if the register is not FP/SP, skip creating
1021 1.1.1.2 christos SFrame stack trace info for the function. */
1022 1.1.1.2 christos if (cfi_insn->u.ri.reg != SFRAME_CFA_SP_REG
1023 1.1.1.2 christos && cfi_insn->u.ri.reg != SFRAME_CFA_FP_REG)
1024 1.1.1.2 christos {
1025 1.1.1.2 christos as_warn (_("no SFrame FDE emitted; "
1026 1.1.1.2 christos "non-SP/FP register %u in .cfi_def_cfa"),
1027 1.1.1.2 christos cfi_insn->u.ri.reg);
1028 1.1.1.2 christos return SFRAME_XLATE_ERR_NOTREPRESENTED; /* Not represented. */
1029 1.1.1.2 christos }
1030 1.1 christos sframe_fre_set_cfa_base_reg (cur_fre, cfi_insn->u.ri.reg);
1031 1.1 christos sframe_fre_set_cfa_offset (cur_fre, cfi_insn->u.ri.offset);
1032 1.1 christos cur_fre->merge_candidate = false;
1033 1.1 christos
1034 1.1 christos return SFRAME_XLATE_OK;
1035 1.1 christos }
1036 1.1 christos
1037 1.1 christos /* Translate DW_CFA_def_cfa_register into SFrame context.
1038 1.1 christos Return SFRAME_XLATE_OK if success. */
1039 1.1 christos
1040 1.1 christos static int
1041 1.1 christos sframe_xlate_do_def_cfa_register (struct sframe_xlate_ctx *xlate_ctx,
1042 1.1 christos struct cfi_insn_data *cfi_insn)
1043 1.1 christos {
1044 1.1 christos struct sframe_row_entry *last_fre = xlate_ctx->last_fre;
1045 1.1 christos /* Get the scratchpad FRE. This FRE will eventually get linked in. */
1046 1.1 christos struct sframe_row_entry *cur_fre = xlate_ctx->cur_fre;
1047 1.1.1.2 christos
1048 1.1 christos gas_assert (cur_fre);
1049 1.1 christos /* Define the current CFA rule to use the provided register (but to
1050 1.1.1.2 christos keep the old offset). However, if the register is not FP/SP,
1051 1.1.1.2 christos skip creating SFrame stack trace info for the function. */
1052 1.1.1.2 christos if (cfi_insn->u.r != SFRAME_CFA_SP_REG
1053 1.1.1.2 christos && cfi_insn->u.r != SFRAME_CFA_FP_REG)
1054 1.1.1.2 christos {
1055 1.1.1.2 christos as_warn (_("no SFrame FDE emitted; "
1056 1.1.1.2 christos "non-SP/FP register %u in .cfi_def_cfa_register"),
1057 1.1.1.2 christos cfi_insn->u.r);
1058 1.1.1.2 christos return SFRAME_XLATE_ERR_NOTREPRESENTED; /* Not represented. */
1059 1.1.1.2 christos }
1060 1.1.1.2 christos sframe_fre_set_cfa_base_reg (cur_fre, cfi_insn->u.r);
1061 1.1.1.2 christos if (last_fre)
1062 1.1.1.2 christos sframe_fre_set_cfa_offset (cur_fre, sframe_fre_get_cfa_offset (last_fre));
1063 1.1.1.2 christos
1064 1.1 christos cur_fre->merge_candidate = false;
1065 1.1 christos
1066 1.1 christos return SFRAME_XLATE_OK;
1067 1.1 christos }
1068 1.1 christos
1069 1.1 christos /* Translate DW_CFA_def_cfa_offset into SFrame context.
1070 1.1 christos Return SFRAME_XLATE_OK if success. */
1071 1.1 christos
1072 1.1 christos static int
1073 1.1 christos sframe_xlate_do_def_cfa_offset (struct sframe_xlate_ctx *xlate_ctx,
1074 1.1 christos struct cfi_insn_data *cfi_insn)
1075 1.1 christos {
1076 1.1 christos /* The scratchpad FRE currently being updated with each cfi_insn
1077 1.1 christos being interpreted. This FRE eventually gets linked in into the
1078 1.1 christos list of FREs for the specific function. */
1079 1.1 christos struct sframe_row_entry *cur_fre = xlate_ctx->cur_fre;
1080 1.1 christos
1081 1.1 christos gas_assert (cur_fre);
1082 1.1 christos /* Define the current CFA rule to use the provided offset (but to keep
1083 1.1 christos the old register). However, if the old register is not FP/SP,
1084 1.1 christos skip creating SFrame stack trace info for the function. */
1085 1.1 christos if ((cur_fre->cfa_base_reg == SFRAME_CFA_FP_REG)
1086 1.1 christos || (cur_fre->cfa_base_reg == SFRAME_CFA_SP_REG))
1087 1.1 christos {
1088 1.1 christos sframe_fre_set_cfa_offset (cur_fre, cfi_insn->u.i);
1089 1.1 christos cur_fre->merge_candidate = false;
1090 1.1 christos }
1091 1.1 christos else
1092 1.1.1.2 christos {
1093 1.1.1.2 christos /* No CFA base register in effect. Non-SP/FP CFA base register should
1094 1.1.1.2 christos not occur, as sframe_xlate_do_def_cfa[_register] would detect this. */
1095 1.1.1.2 christos as_warn (_("no SFrame FDE emitted; "
1096 1.1.1.2 christos ".cfi_def_cfa_offset without CFA base register in effect"));
1097 1.1.1.2 christos return SFRAME_XLATE_ERR_NOTREPRESENTED;
1098 1.1.1.2 christos }
1099 1.1 christos
1100 1.1 christos return SFRAME_XLATE_OK;
1101 1.1 christos }
1102 1.1 christos
1103 1.1 christos /* Translate DW_CFA_offset into SFrame context.
1104 1.1 christos Return SFRAME_XLATE_OK if success. */
1105 1.1 christos
1106 1.1 christos static int
1107 1.1 christos sframe_xlate_do_offset (struct sframe_xlate_ctx *xlate_ctx,
1108 1.1 christos struct cfi_insn_data *cfi_insn)
1109 1.1 christos {
1110 1.1 christos /* The scratchpad FRE currently being updated with each cfi_insn
1111 1.1 christos being interpreted. This FRE eventually gets linked in into the
1112 1.1 christos list of FREs for the specific function. */
1113 1.1 christos struct sframe_row_entry *cur_fre = xlate_ctx->cur_fre;
1114 1.1 christos
1115 1.1 christos gas_assert (cur_fre);
1116 1.1 christos /* Change the rule for the register indicated by the register number to
1117 1.1 christos be the specified offset. */
1118 1.1.1.2 christos /* Ignore SP reg, as it can be recovered from the CFA tracking info. */
1119 1.1.1.2 christos if (cfi_insn->u.ri.reg == SFRAME_CFA_FP_REG)
1120 1.1 christos {
1121 1.1 christos gas_assert (!cur_fre->base_reg);
1122 1.1 christos sframe_fre_set_bp_track (cur_fre, cfi_insn->u.ri.offset);
1123 1.1 christos cur_fre->merge_candidate = false;
1124 1.1 christos }
1125 1.1 christos else if (sframe_ra_tracking_p ()
1126 1.1.1.2 christos && cfi_insn->u.ri.reg == SFRAME_CFA_RA_REG)
1127 1.1 christos {
1128 1.1 christos sframe_fre_set_ra_track (cur_fre, cfi_insn->u.ri.offset);
1129 1.1 christos cur_fre->merge_candidate = false;
1130 1.1 christos }
1131 1.1 christos /* This is used to track changes to non-rsp registers, skip all others
1132 1.1 christos except FP / RA for now. */
1133 1.1 christos return SFRAME_XLATE_OK;
1134 1.1 christos }
1135 1.1 christos
1136 1.1 christos /* Translate DW_CFA_val_offset into SFrame context.
1137 1.1.1.2 christos Return SFRAME_XLATE_OK if success.
1138 1.1.1.2 christos
1139 1.1.1.2 christos When CFI_ESC_P is true, the CFI_INSN is hand-crafted using CFI_escape
1140 1.1.1.2 christos data. See sframe_xlate_do_escape_val_offset. */
1141 1.1 christos
1142 1.1 christos static int
1143 1.1.1.2 christos sframe_xlate_do_val_offset (const struct sframe_xlate_ctx *xlate_ctx ATTRIBUTE_UNUSED,
1144 1.1.1.2 christos const struct cfi_insn_data *cfi_insn,
1145 1.1.1.2 christos bool cfi_esc_p)
1146 1.1 christos {
1147 1.1 christos /* Previous value of register is CFA + offset. However, if the specified
1148 1.1.1.2 christos register is not interesting (SP, FP, or RA reg), the current
1149 1.1.1.2 christos DW_CFA_val_offset instruction can be safely skipped without sacrificing
1150 1.1.1.2 christos the asynchronicity of stack trace information. */
1151 1.1.1.2 christos if (cfi_insn->u.ri.reg == SFRAME_CFA_FP_REG
1152 1.1.1.2 christos || (sframe_ra_tracking_p () && cfi_insn->u.ri.reg == SFRAME_CFA_RA_REG)
1153 1.1.1.2 christos /* Ignore SP reg, if offset matches assumed default rule. */
1154 1.1.1.2 christos || (cfi_insn->u.ri.reg == SFRAME_CFA_SP_REG
1155 1.1.1.2 christos && ((sframe_get_abi_arch () != SFRAME_ABI_S390X_ENDIAN_BIG
1156 1.1.1.2 christos && cfi_insn->u.ri.offset != 0)
1157 1.1.1.2 christos || (sframe_get_abi_arch () == SFRAME_ABI_S390X_ENDIAN_BIG
1158 1.1.1.2 christos && cfi_insn->u.ri.offset != SFRAME_S390X_SP_VAL_OFFSET))))
1159 1.1.1.2 christos {
1160 1.1.1.2 christos as_warn (_("no SFrame FDE emitted; %s with %s reg %u"),
1161 1.1.1.2 christos cfi_esc_p ? ".cfi_escape DW_CFA_val_offset" : ".cfi_val_offset",
1162 1.1.1.2 christos sframe_register_name (cfi_insn->u.ri.reg), cfi_insn->u.ri.reg);
1163 1.1.1.2 christos return SFRAME_XLATE_ERR_NOTREPRESENTED; /* Not represented. */
1164 1.1.1.2 christos }
1165 1.1.1.2 christos
1166 1.1.1.2 christos /* Safe to skip. */
1167 1.1.1.2 christos return SFRAME_XLATE_OK;
1168 1.1.1.2 christos }
1169 1.1.1.2 christos
1170 1.1.1.2 christos /* S390-specific translate DW_CFA_register into SFrame context.
1171 1.1.1.2 christos Return SFRAME_XLATE_OK if success. */
1172 1.1.1.2 christos
1173 1.1.1.2 christos static int
1174 1.1.1.2 christos s390_sframe_xlate_do_register (struct sframe_xlate_ctx *xlate_ctx,
1175 1.1.1.2 christos struct cfi_insn_data *cfi_insn)
1176 1.1.1.2 christos {
1177 1.1.1.2 christos /* The scratchpad FRE currently being updated with each cfi_insn
1178 1.1.1.2 christos being interpreted. This FRE eventually gets linked in into the
1179 1.1.1.2 christos list of FREs for the specific function. */
1180 1.1.1.2 christos struct sframe_row_entry *cur_fre = xlate_ctx->cur_fre;
1181 1.1.1.2 christos
1182 1.1.1.2 christos gas_assert (cur_fre);
1183 1.1.1.2 christos
1184 1.1.1.2 christos /* Change the rule for the register indicated by the register number to
1185 1.1.1.2 christos be the specified register. Encode the register number as offset by
1186 1.1.1.2 christos shifting it to the left by one and setting the least-significant bit
1187 1.1.1.2 christos (LSB). The LSB can be used to differentiate offsets from register
1188 1.1.1.2 christos numbers, as offsets from CFA are always a multiple of -8 on s390x. */
1189 1.1.1.2 christos if (cfi_insn->u.rr.reg1 == SFRAME_CFA_FP_REG)
1190 1.1.1.2 christos sframe_fre_set_bp_track (cur_fre,
1191 1.1.1.2 christos SFRAME_V2_S390X_OFFSET_ENCODE_REGNUM (cfi_insn->u.rr.reg2));
1192 1.1.1.2 christos else if (sframe_ra_tracking_p ()
1193 1.1.1.2 christos && cfi_insn->u.rr.reg1 == SFRAME_CFA_RA_REG)
1194 1.1.1.2 christos sframe_fre_set_ra_track (cur_fre,
1195 1.1.1.2 christos SFRAME_V2_S390X_OFFSET_ENCODE_REGNUM (cfi_insn->u.rr.reg2));
1196 1.1.1.2 christos
1197 1.1.1.2 christos return SFRAME_XLATE_OK;
1198 1.1.1.2 christos }
1199 1.1.1.2 christos
1200 1.1.1.2 christos /* Translate DW_CFA_register into SFrame context.
1201 1.1.1.2 christos Return SFRAME_XLATE_OK if success. */
1202 1.1.1.2 christos
1203 1.1.1.2 christos static int
1204 1.1.1.2 christos sframe_xlate_do_register (struct sframe_xlate_ctx *xlate_ctx ATTRIBUTE_UNUSED,
1205 1.1.1.2 christos struct cfi_insn_data *cfi_insn)
1206 1.1.1.2 christos {
1207 1.1.1.2 christos /* Conditionally invoke S390-specific implementation. */
1208 1.1.1.2 christos if (sframe_get_abi_arch () == SFRAME_ABI_S390X_ENDIAN_BIG)
1209 1.1.1.2 christos return s390_sframe_xlate_do_register (xlate_ctx, cfi_insn);
1210 1.1.1.2 christos
1211 1.1.1.2 christos /* Previous value of register1 is register2. However, if the specified
1212 1.1.1.2 christos register1 is not interesting (FP or RA reg), the current DW_CFA_register
1213 1.1 christos instruction can be safely skipped without sacrificing the asynchronicity of
1214 1.1 christos stack trace information. */
1215 1.1.1.2 christos if (cfi_insn->u.rr.reg1 == SFRAME_CFA_FP_REG
1216 1.1.1.2 christos || (sframe_ra_tracking_p () && cfi_insn->u.rr.reg1 == SFRAME_CFA_RA_REG)
1217 1.1.1.2 christos /* Ignore SP reg, as it can be recovered from the CFA tracking info. */
1218 1.1.1.2 christos )
1219 1.1.1.2 christos {
1220 1.1.1.2 christos as_warn (_("no SFrame FDE emitted; %s register %u in .cfi_register"),
1221 1.1.1.2 christos sframe_register_name (cfi_insn->u.rr.reg1), cfi_insn->u.rr.reg1);
1222 1.1.1.2 christos return SFRAME_XLATE_ERR_NOTREPRESENTED; /* Not represented. */
1223 1.1.1.2 christos }
1224 1.1 christos
1225 1.1 christos /* Safe to skip. */
1226 1.1 christos return SFRAME_XLATE_OK;
1227 1.1 christos }
1228 1.1 christos
1229 1.1 christos /* Translate DW_CFA_remember_state into SFrame context.
1230 1.1 christos Return SFRAME_XLATE_OK if success. */
1231 1.1 christos
1232 1.1 christos static int
1233 1.1 christos sframe_xlate_do_remember_state (struct sframe_xlate_ctx *xlate_ctx)
1234 1.1 christos {
1235 1.1 christos struct sframe_row_entry *last_fre = xlate_ctx->last_fre;
1236 1.1 christos
1237 1.1 christos /* If there is no FRE state to remember, nothing to do here. Return
1238 1.1 christos early with non-zero error code, this will cause no SFrame stack trace
1239 1.1 christos info for the function involved. */
1240 1.1 christos if (!last_fre)
1241 1.1.1.2 christos {
1242 1.1.1.2 christos as_warn (_("no SFrame FDE emitted; "
1243 1.1.1.2 christos ".cfi_remember_state without prior SFrame FRE state"));
1244 1.1.1.2 christos return SFRAME_XLATE_ERR_INVAL;
1245 1.1.1.2 christos }
1246 1.1 christos
1247 1.1 christos if (!xlate_ctx->remember_fre)
1248 1.1 christos xlate_ctx->remember_fre = sframe_row_entry_new ();
1249 1.1 christos sframe_row_entry_initialize (xlate_ctx->remember_fre, last_fre);
1250 1.1 christos
1251 1.1 christos return SFRAME_XLATE_OK;
1252 1.1 christos }
1253 1.1 christos
1254 1.1 christos /* Translate DW_CFA_restore_state into SFrame context.
1255 1.1 christos Return SFRAME_XLATE_OK if success. */
1256 1.1 christos
1257 1.1 christos static int
1258 1.1 christos sframe_xlate_do_restore_state (struct sframe_xlate_ctx *xlate_ctx)
1259 1.1 christos {
1260 1.1 christos /* The scratchpad FRE currently being updated with each cfi_insn
1261 1.1 christos being interpreted. This FRE eventually gets linked in into the
1262 1.1 christos list of FREs for the specific function. */
1263 1.1 christos struct sframe_row_entry *cur_fre = xlate_ctx->cur_fre;
1264 1.1 christos
1265 1.1 christos gas_assert (xlate_ctx->remember_fre);
1266 1.1 christos gas_assert (cur_fre && cur_fre->merge_candidate);
1267 1.1 christos
1268 1.1 christos /* Get the CFA state from the DW_CFA_remember_state insn. */
1269 1.1 christos sframe_row_entry_initialize (cur_fre, xlate_ctx->remember_fre);
1270 1.1 christos /* The PC boundaries of the current SFrame FRE are updated
1271 1.1 christos via other machinery. */
1272 1.1 christos cur_fre->merge_candidate = false;
1273 1.1 christos return SFRAME_XLATE_OK;
1274 1.1 christos }
1275 1.1 christos
1276 1.1 christos /* Translate DW_CFA_restore into SFrame context.
1277 1.1 christos Return SFRAME_XLATE_OK if success. */
1278 1.1 christos
1279 1.1 christos static int
1280 1.1 christos sframe_xlate_do_restore (struct sframe_xlate_ctx *xlate_ctx,
1281 1.1 christos struct cfi_insn_data *cfi_insn)
1282 1.1 christos {
1283 1.1 christos struct sframe_row_entry *cie_fre = xlate_ctx->first_fre;
1284 1.1 christos /* The scratchpad FRE currently being updated with each cfi_insn
1285 1.1 christos being interpreted. This FRE eventually gets linked in into the
1286 1.1 christos list of FREs for the specific function. */
1287 1.1 christos struct sframe_row_entry *cur_fre = xlate_ctx->cur_fre;
1288 1.1 christos
1289 1.1.1.2 christos /* PR gas/33170. It is valid to have a:
1290 1.1.1.2 christos .cfi_restore N
1291 1.1.1.2 christos even at the entry of a function; in which case cie_fre is not yet setup.
1292 1.1.1.2 christos Point cie_fre to cur_fre, and let the machinery proceed to update
1293 1.1.1.2 christos merge_candidate as usual. */
1294 1.1.1.2 christos if (cie_fre == NULL)
1295 1.1.1.2 christos cie_fre = cur_fre;
1296 1.1.1.2 christos
1297 1.1 christos /* Change the rule for the indicated register to the rule assigned to
1298 1.1.1.2 christos it by the initial_instructions in the CIE. SFrame FREs track only CFA
1299 1.1.1.2 christos and FP / RA for backtracing purposes; skip the other .cfi_restore
1300 1.1.1.2 christos directives. */
1301 1.1 christos if (cfi_insn->u.r == SFRAME_CFA_FP_REG)
1302 1.1 christos {
1303 1.1 christos gas_assert (cur_fre);
1304 1.1 christos cur_fre->bp_loc = cie_fre->bp_loc;
1305 1.1 christos cur_fre->bp_offset = cie_fre->bp_offset;
1306 1.1 christos cur_fre->merge_candidate = false;
1307 1.1 christos }
1308 1.1 christos else if (sframe_ra_tracking_p ()
1309 1.1 christos && cfi_insn->u.r == SFRAME_CFA_RA_REG)
1310 1.1 christos {
1311 1.1 christos gas_assert (cur_fre);
1312 1.1 christos cur_fre->ra_loc = cie_fre->ra_loc;
1313 1.1 christos cur_fre->ra_offset = cie_fre->ra_offset;
1314 1.1 christos cur_fre->merge_candidate = false;
1315 1.1 christos }
1316 1.1 christos return SFRAME_XLATE_OK;
1317 1.1 christos }
1318 1.1 christos
1319 1.1.1.2 christos /* Translate DW_CFA_AARCH64_negate_ra_state into SFrame context.
1320 1.1 christos Return SFRAME_XLATE_OK if success. */
1321 1.1 christos
1322 1.1 christos static int
1323 1.1.1.2 christos sframe_xlate_do_aarch64_negate_ra_state (struct sframe_xlate_ctx *xlate_ctx,
1324 1.1.1.2 christos struct cfi_insn_data *cfi_insn ATTRIBUTE_UNUSED)
1325 1.1 christos {
1326 1.1 christos struct sframe_row_entry *cur_fre = xlate_ctx->cur_fre;
1327 1.1 christos
1328 1.1 christos gas_assert (cur_fre);
1329 1.1 christos /* Toggle the mangled RA status bit. */
1330 1.1 christos cur_fre->mangled_ra_p = !cur_fre->mangled_ra_p;
1331 1.1 christos cur_fre->merge_candidate = false;
1332 1.1 christos
1333 1.1 christos return SFRAME_XLATE_OK;
1334 1.1 christos }
1335 1.1 christos
1336 1.1.1.2 christos /* Translate DW_CFA_AARCH64_negate_ra_state_with_pc into SFrame context.
1337 1.1.1.2 christos Return SFRAME_XLATE_OK if success. */
1338 1.1.1.2 christos
1339 1.1.1.2 christos static int
1340 1.1.1.2 christos sframe_xlate_do_aarch64_negate_ra_state_with_pc (struct sframe_xlate_ctx *xlate_ctx ATTRIBUTE_UNUSED,
1341 1.1.1.2 christos struct cfi_insn_data *cfi_insn ATTRIBUTE_UNUSED)
1342 1.1.1.2 christos {
1343 1.1.1.2 christos as_warn (_("no SFrame FDE emitted; .cfi_negate_ra_state_with_pc"));
1344 1.1.1.2 christos /* The used signing method should be encoded inside the FDE in SFrame v3.
1345 1.1.1.2 christos For now, PAuth_LR extension is not supported with SFrame. */
1346 1.1.1.2 christos return SFRAME_XLATE_ERR_NOTREPRESENTED; /* Not represented. */
1347 1.1.1.2 christos }
1348 1.1.1.2 christos
1349 1.1.1.2 christos /* Translate DW_CFA_GNU_window_save into SFrame context.
1350 1.1.1.2 christos DW_CFA_GNU_window_save is a DWARF Sparc extension, but is multiplexed with a
1351 1.1.1.2 christos directive of DWARF AArch64 extension: DW_CFA_AARCH64_negate_ra_state.
1352 1.1.1.2 christos The AArch64 backend of GCC 14 and older versions was emitting mistakenly the
1353 1.1.1.2 christos Sparc CFI directive (.cfi_window_save). From GCC 15, the AArch64 backend
1354 1.1.1.2 christos only emits .cfi_negate_ra_state. For backward compatibility, the handler for
1355 1.1.1.2 christos .cfi_window_save needs to check whether the directive was used in a AArch64
1356 1.1.1.2 christos ABI context or not.
1357 1.1.1.2 christos Return SFRAME_XLATE_OK if success. */
1358 1.1.1.2 christos
1359 1.1.1.2 christos static int
1360 1.1.1.2 christos sframe_xlate_do_gnu_window_save (struct sframe_xlate_ctx *xlate_ctx,
1361 1.1.1.2 christos struct cfi_insn_data *cfi_insn)
1362 1.1.1.2 christos {
1363 1.1.1.2 christos unsigned char abi_arch = sframe_get_abi_arch ();
1364 1.1.1.2 christos
1365 1.1.1.2 christos /* Translate DW_CFA_AARCH64_negate_ra_state into SFrame context. */
1366 1.1.1.2 christos if (abi_arch == SFRAME_ABI_AARCH64_ENDIAN_BIG
1367 1.1.1.2 christos || abi_arch == SFRAME_ABI_AARCH64_ENDIAN_LITTLE)
1368 1.1.1.2 christos return sframe_xlate_do_aarch64_negate_ra_state (xlate_ctx, cfi_insn);
1369 1.1.1.2 christos
1370 1.1.1.2 christos as_warn (_("no SFrame FDE emitted; .cfi_window_save"));
1371 1.1.1.2 christos return SFRAME_XLATE_ERR_NOTREPRESENTED; /* Not represented. */
1372 1.1.1.2 christos }
1373 1.1.1.2 christos
1374 1.1.1.2 christos /* Handle DW_CFA_expression in .cfi_escape.
1375 1.1.1.2 christos
1376 1.1.1.2 christos As with sframe_xlate_do_cfi_escape, the intent of this function is to detect
1377 1.1.1.2 christos only the simple-to-process but common cases, where skipping over the escape
1378 1.1.1.2 christos expr data does not affect correctness of the SFrame stack trace data.
1379 1.1.1.2 christos
1380 1.1.1.2 christos Sets CALLER_WARN_P for skipped cases (and returns SFRAME_XLATE_OK) where the
1381 1.1.1.2 christos caller must warn. The caller then must also set
1382 1.1.1.2 christos SFRAME_XLATE_ERR_NOTREPRESENTED for their callers. */
1383 1.1.1.2 christos
1384 1.1.1.2 christos static int
1385 1.1.1.2 christos sframe_xlate_do_escape_expr (const struct sframe_xlate_ctx *xlate_ctx,
1386 1.1.1.2 christos const struct cfi_insn_data *cfi_insn,
1387 1.1.1.2 christos bool *caller_warn_p)
1388 1.1.1.2 christos {
1389 1.1.1.2 christos const struct cfi_escape_data *e = cfi_insn->u.esc;
1390 1.1.1.2 christos int err = SFRAME_XLATE_OK;
1391 1.1.1.2 christos unsigned int reg = 0;
1392 1.1.1.2 christos unsigned int i = 0;
1393 1.1.1.2 christos
1394 1.1.1.2 christos /* Check roughly for an expression
1395 1.1.1.2 christos DW_CFA_expression: r1 (rdx) (DW_OP_bregN (reg): OFFSET). */
1396 1.1.1.2 christos #define CFI_ESC_NUM_EXP 4
1397 1.1.1.2 christos offsetT items[CFI_ESC_NUM_EXP] = {0};
1398 1.1.1.2 christos while (e->next)
1399 1.1.1.2 christos {
1400 1.1.1.2 christos e = e->next;
1401 1.1.1.2 christos if ((i == 2 && (items[1] != 2)) /* Expected len of 2 in DWARF expr. */
1402 1.1.1.2 christos /* We do not care for the exact values of items[2] and items[3],
1403 1.1.1.2 christos so an explicit check for O_constant isnt necessary either. */
1404 1.1.1.2 christos || i >= CFI_ESC_NUM_EXP
1405 1.1.1.2 christos || (i < 2
1406 1.1.1.2 christos && (e->exp.X_op != O_constant
1407 1.1.1.2 christos || e->type != CFI_ESC_byte
1408 1.1.1.2 christos || e->reloc != TC_PARSE_CONS_RETURN_NONE)))
1409 1.1.1.2 christos goto warn_and_exit;
1410 1.1.1.2 christos items[i] = e->exp.X_add_number;
1411 1.1.1.2 christos i++;
1412 1.1.1.2 christos }
1413 1.1.1.2 christos
1414 1.1.1.2 christos if (i <= CFI_ESC_NUM_EXP - 1)
1415 1.1.1.2 christos goto warn_and_exit;
1416 1.1.1.2 christos
1417 1.1.1.2 christos /* reg operand to DW_CFA_expression is ULEB128. For the purpose at hand,
1418 1.1.1.2 christos however, the register value will be less than 128 (CFI_ESC_NUM_EXP set
1419 1.1.1.2 christos to 4). See an extended comment in sframe_xlate_do_escape_expr for why
1420 1.1.1.2 christos reading ULEB is okay to skip without sacrificing correctness. */
1421 1.1.1.2 christos reg = items[0];
1422 1.1.1.2 christos #undef CFI_ESC_NUM_EXP
1423 1.1.1.2 christos
1424 1.1.1.2 christos if (reg == SFRAME_CFA_SP_REG || reg == SFRAME_CFA_FP_REG
1425 1.1.1.2 christos || (sframe_ra_tracking_p () && reg == SFRAME_CFA_RA_REG)
1426 1.1.1.2 christos || reg == xlate_ctx->cur_fre->cfa_base_reg)
1427 1.1.1.2 christos {
1428 1.1.1.2 christos as_warn (_("no SFrame FDE emitted; "
1429 1.1.1.2 christos ".cfi_escape DW_CFA_expression with %s reg %u"),
1430 1.1.1.2 christos sframe_register_name (reg), reg);
1431 1.1.1.2 christos err = SFRAME_XLATE_ERR_NOTREPRESENTED;
1432 1.1.1.2 christos }
1433 1.1.1.2 christos /* else safe to skip, so continue to return SFRAME_XLATE_OK. */
1434 1.1.1.2 christos
1435 1.1.1.2 christos return err;
1436 1.1.1.2 christos
1437 1.1.1.2 christos warn_and_exit:
1438 1.1.1.2 christos *caller_warn_p = true;
1439 1.1.1.2 christos return err;
1440 1.1.1.2 christos }
1441 1.1.1.2 christos
1442 1.1.1.2 christos /* Handle DW_CFA_val_offset in .cfi_escape.
1443 1.1.1.2 christos
1444 1.1.1.2 christos As with sframe_xlate_do_cfi_escape, the intent of this function is to detect
1445 1.1.1.2 christos only the simple-to-process but common cases, where skipping over the escape
1446 1.1.1.2 christos expr data does not affect correctness of the SFrame stack trace data.
1447 1.1.1.2 christos
1448 1.1.1.2 christos Sets CALLER_WARN_P for skipped cases (and returns SFRAME_XLATE_OK) where the
1449 1.1.1.2 christos caller must warn. The caller then must also set
1450 1.1.1.2 christos SFRAME_XLATE_ERR_NOTREPRESENTED for their callers. */
1451 1.1.1.2 christos
1452 1.1.1.2 christos static int
1453 1.1.1.2 christos sframe_xlate_do_escape_val_offset (const struct sframe_xlate_ctx *xlate_ctx,
1454 1.1.1.2 christos const struct cfi_insn_data *cfi_insn,
1455 1.1.1.2 christos bool *caller_warn_p)
1456 1.1.1.2 christos {
1457 1.1.1.2 christos const struct cfi_escape_data *e = cfi_insn->u.esc;
1458 1.1.1.2 christos int err = SFRAME_XLATE_OK;
1459 1.1.1.2 christos unsigned int i = 0;
1460 1.1.1.2 christos unsigned int reg;
1461 1.1.1.2 christos offsetT offset;
1462 1.1.1.2 christos
1463 1.1.1.2 christos /* Check for (DW_CFA_val_offset reg scaled_offset) sequence. */
1464 1.1.1.2 christos #define CFI_ESC_NUM_EXP 2
1465 1.1.1.2 christos offsetT items[CFI_ESC_NUM_EXP] = {0};
1466 1.1.1.2 christos while (e->next)
1467 1.1.1.2 christos {
1468 1.1.1.2 christos e = e->next;
1469 1.1.1.2 christos if (i >= CFI_ESC_NUM_EXP || e->exp.X_op != O_constant
1470 1.1.1.2 christos || e->type != CFI_ESC_byte
1471 1.1.1.2 christos || e->reloc != TC_PARSE_CONS_RETURN_NONE)
1472 1.1.1.2 christos goto warn_and_exit;
1473 1.1.1.2 christos items[i] = e->exp.X_add_number;
1474 1.1.1.2 christos i++;
1475 1.1.1.2 christos }
1476 1.1.1.2 christos if (i <= CFI_ESC_NUM_EXP - 1)
1477 1.1.1.2 christos goto warn_and_exit;
1478 1.1.1.2 christos
1479 1.1.1.2 christos /* Both arguments to DW_CFA_val_offset are ULEB128. Especially with APX (on
1480 1.1.1.2 christos x86) we're going to see DWARF register numbers above 127, for the extended
1481 1.1.1.2 christos GPRs. And large enough stack frames would also require multi-byte offset
1482 1.1.1.2 christos representation. However, since we limit our focus on cases when
1483 1.1.1.2 christos CFI_ESC_NUM_EXP is 2, reading ULEB can be skipped. IOW, although not
1484 1.1.1.2 christos ideal, SFrame FDE generation in case of an APX register in
1485 1.1.1.2 christos DW_CFA_val_offset is being skipped (PS: this does _not_ mean incorrect
1486 1.1.1.2 christos SFrame stack trace data).
1487 1.1.1.2 christos
1488 1.1.1.2 christos Recall that the intent here is to check for simple and prevalent cases,
1489 1.1.1.2 christos when feasible. */
1490 1.1.1.2 christos
1491 1.1.1.2 christos reg = items[0];
1492 1.1.1.2 christos offset = items[1];
1493 1.1.1.2 christos #undef CFI_ESC_NUM_EXP
1494 1.1.1.2 christos
1495 1.1.1.2 christos /* Invoke sframe_xlate_do_val_offset itself for checking. */
1496 1.1.1.2 christos struct cfi_insn_data temp = {
1497 1.1.1.2 christos .insn = DW_CFA_val_offset,
1498 1.1.1.2 christos .u = {
1499 1.1.1.2 christos .ri = {
1500 1.1.1.2 christos .reg = reg,
1501 1.1.1.2 christos .offset = offset * DWARF2_CIE_DATA_ALIGNMENT
1502 1.1.1.2 christos }
1503 1.1.1.2 christos }
1504 1.1.1.2 christos };
1505 1.1.1.2 christos err = sframe_xlate_do_val_offset (xlate_ctx, &temp, true);
1506 1.1.1.2 christos return err;
1507 1.1.1.2 christos
1508 1.1.1.2 christos warn_and_exit:
1509 1.1.1.2 christos *caller_warn_p = true;
1510 1.1.1.2 christos return err;
1511 1.1.1.2 christos }
1512 1.1.1.2 christos
1513 1.1.1.2 christos /* Handle CFI_escape in SFrame context.
1514 1.1.1.2 christos
1515 1.1.1.2 christos .cfi_escape CFI directive allows the user to add arbitrary data to the
1516 1.1.1.2 christos unwind info. DWARF expressions commonly follow after CFI_escape (fake CFI)
1517 1.1.1.2 christos DWARF opcode. One might also use CFI_escape to add OS-specific CFI opcodes
1518 1.1.1.2 christos even.
1519 1.1.1.2 christos
1520 1.1.1.2 christos Complex unwind info added using .cfi_escape directive _may_ be of no
1521 1.1.1.2 christos consequence for SFrame when the affected registers are not SP, FP, RA or
1522 1.1.1.2 christos CFA. The challenge in confirming the afore-mentioned is that it needs full
1523 1.1.1.2 christos parsing (and validation) of the data presented after .cfi_escape. Here we
1524 1.1.1.2 christos take a case-by-case approach towards skipping _some_ instances of
1525 1.1.1.2 christos .cfi_escape: skip those that can be *easily* determined to be harmless in
1526 1.1.1.2 christos the context of SFrame stack trace information.
1527 1.1.1.2 christos
1528 1.1.1.2 christos This function partially processes data following .cfi_escape and returns
1529 1.1.1.2 christos SFRAME_XLATE_OK if OK to skip. */
1530 1.1.1.2 christos
1531 1.1.1.2 christos static int
1532 1.1.1.2 christos sframe_xlate_do_cfi_escape (const struct sframe_xlate_ctx *xlate_ctx,
1533 1.1.1.2 christos const struct cfi_insn_data *cfi_insn)
1534 1.1.1.2 christos {
1535 1.1.1.2 christos const struct cfi_escape_data *e;
1536 1.1.1.2 christos bool warn_p = false;
1537 1.1.1.2 christos int err = SFRAME_XLATE_OK;
1538 1.1.1.2 christos offsetT firstop;
1539 1.1.1.2 christos
1540 1.1.1.2 christos e = cfi_insn->u.esc;
1541 1.1.1.2 christos
1542 1.1.1.2 christos if (!e)
1543 1.1.1.2 christos return SFRAME_XLATE_ERR_INVAL;
1544 1.1.1.2 christos
1545 1.1.1.2 christos if (e->exp.X_op != O_constant
1546 1.1.1.2 christos || e->type != CFI_ESC_byte
1547 1.1.1.2 christos || e->reloc != TC_PARSE_CONS_RETURN_NONE)
1548 1.1.1.2 christos return SFRAME_XLATE_ERR_NOTREPRESENTED;
1549 1.1.1.2 christos
1550 1.1.1.2 christos firstop = e->exp.X_add_number;
1551 1.1.1.2 christos switch (firstop)
1552 1.1.1.2 christos {
1553 1.1.1.2 christos case DW_CFA_nop:
1554 1.1.1.2 christos /* One or more nops together are harmless for SFrame. */
1555 1.1.1.2 christos while (e->next)
1556 1.1.1.2 christos {
1557 1.1.1.2 christos e = e->next;
1558 1.1.1.2 christos if (e->exp.X_op != O_constant || e->exp.X_add_number != DW_CFA_nop
1559 1.1.1.2 christos || e->type != CFI_ESC_byte
1560 1.1.1.2 christos || e->reloc != TC_PARSE_CONS_RETURN_NONE)
1561 1.1.1.2 christos {
1562 1.1.1.2 christos warn_p = true;
1563 1.1.1.2 christos break;
1564 1.1.1.2 christos }
1565 1.1.1.2 christos }
1566 1.1.1.2 christos break;
1567 1.1.1.2 christos
1568 1.1.1.2 christos case DW_CFA_expression:
1569 1.1.1.2 christos err = sframe_xlate_do_escape_expr (xlate_ctx, cfi_insn, &warn_p);
1570 1.1.1.2 christos break;
1571 1.1.1.2 christos
1572 1.1.1.2 christos case DW_CFA_val_offset:
1573 1.1.1.2 christos err = sframe_xlate_do_escape_val_offset (xlate_ctx, cfi_insn, &warn_p);
1574 1.1.1.2 christos break;
1575 1.1.1.2 christos
1576 1.1.1.2 christos /* FIXME - Also add processing for DW_CFA_GNU_args_size in future? */
1577 1.1.1.2 christos
1578 1.1.1.2 christos default:
1579 1.1.1.2 christos warn_p = true;
1580 1.1.1.2 christos break;
1581 1.1.1.2 christos }
1582 1.1.1.2 christos
1583 1.1.1.2 christos if (warn_p)
1584 1.1.1.2 christos {
1585 1.1.1.2 christos /* In all other cases (e.g., DW_CFA_def_cfa_expression or other
1586 1.1.1.2 christos OS-specific CFI opcodes), skip inspecting the DWARF expression.
1587 1.1.1.2 christos This may impact the asynchronicity due to loss of coverage.
1588 1.1.1.2 christos Continue to warn the user and bail out. */
1589 1.1.1.2 christos as_warn (_("no SFrame FDE emitted; .cfi_escape with op (%#lx)"),
1590 1.1.1.2 christos (unsigned long)firstop);
1591 1.1.1.2 christos err = SFRAME_XLATE_ERR_NOTREPRESENTED;
1592 1.1.1.2 christos }
1593 1.1.1.2 christos
1594 1.1.1.2 christos return err;
1595 1.1.1.2 christos }
1596 1.1.1.2 christos
1597 1.1.1.2 christos /* Translate DW_CFA_undefined into SFrame context.
1598 1.1.1.2 christos
1599 1.1.1.2 christos DW_CFA_undefined op indicates that from now on, the previous value of
1600 1.1.1.2 christos register cant be restored anymore. In SFrame stack trace, we cannot
1601 1.1.1.2 christos represent such a semantic. So, we skip generating an SFrame FDE for this,
1602 1.1.1.2 christos when a register of interest is used with DW_CFA_undefined.
1603 1.1.1.2 christos
1604 1.1.1.2 christos Return SFRAME_XLATE_OK if success. */
1605 1.1.1.2 christos
1606 1.1.1.2 christos static int
1607 1.1.1.2 christos sframe_xlate_do_cfi_undefined (const struct sframe_xlate_ctx *xlate_ctx ATTRIBUTE_UNUSED,
1608 1.1.1.2 christos const struct cfi_insn_data *cfi_insn)
1609 1.1.1.2 christos {
1610 1.1.1.2 christos if (cfi_insn->u.r == SFRAME_CFA_FP_REG
1611 1.1.1.2 christos || cfi_insn->u.r == SFRAME_CFA_RA_REG
1612 1.1.1.2 christos || cfi_insn->u.r == SFRAME_CFA_SP_REG)
1613 1.1.1.2 christos {
1614 1.1.1.2 christos as_warn (_("no SFrame FDE emitted; %s reg %u in .cfi_undefined"),
1615 1.1.1.2 christos sframe_register_name (cfi_insn->u.r), cfi_insn->u.r);
1616 1.1.1.2 christos return SFRAME_XLATE_ERR_NOTREPRESENTED; /* Not represented. */
1617 1.1.1.2 christos }
1618 1.1.1.2 christos
1619 1.1.1.2 christos /* Safe to skip. */
1620 1.1.1.2 christos return SFRAME_XLATE_OK;
1621 1.1.1.2 christos }
1622 1.1.1.2 christos
1623 1.1.1.2 christos /* Translate DW_CFA_same_value into SFrame context.
1624 1.1.1.2 christos
1625 1.1.1.2 christos DW_CFA_same_value op indicates that current value of register is the same as
1626 1.1.1.2 christos in the previous frame, i.e. no restoration needed. In SFrame stack trace
1627 1.1.1.2 christos format, the handling is done similar to DW_CFA_restore.
1628 1.1.1.2 christos
1629 1.1.1.2 christos For SFRAME_CFA_RA_REG, if RA-tracking is enabled, reset the SFrame FRE state
1630 1.1.1.2 christos for REG_RA to indicate that register does not need restoration. P.S.: Even
1631 1.1.1.2 christos though resetting just REG_RA may be contradicting the AArch64 ABI (as Frame
1632 1.1.1.2 christos Record contains for FP and LR), sframe_xlate_do_same_value () does not
1633 1.1.1.2 christos detect the case and assumes the users' DW_CFA_same_value SFRAME_CFA_RA_REG
1634 1.1.1.2 christos has a sound reason. For ABIs, where RA-tracking is disabled, handle it
1635 1.1.1.2 christos similar to DW_CFA_restore: ignore the directive, it is safe to skip. The
1636 1.1.1.2 christos reasoning is similar to that for DW_CFA_restore: if such a restoration was
1637 1.1.1.2 christos meant to be of any consequence, there must have been the necessary CFI
1638 1.1.1.2 christos directives for updating the CFA rule too such that the recovered RA from
1639 1.1.1.2 christos stack is valid.
1640 1.1.1.2 christos
1641 1.1.1.2 christos SFrame based stacktracers will implement CFA-based SP recovery for all ABIs:
1642 1.1.1.2 christos SP for previous frame is based on the applicable CFA-rule. There is no
1643 1.1.1.2 christos representation in SFrame to indicate "no restoration needed" for REG_SP,
1644 1.1.1.2 christos when going to the previous frame. That said, if DW_CFA_same_value is seen
1645 1.1.1.2 christos for SFRAME_CFA_SP_REG, handle it similar to DW_CFA_restore: ignore the
1646 1.1.1.2 christos directive, it is safe to skip. The reasoning is similar to that for
1647 1.1.1.2 christos DW_CFA_restore: if such a restoration was meant to be of any consequence,
1648 1.1.1.2 christos there must have been the necessary CFI directives for updating the CFA rule
1649 1.1.1.2 christos too. The latter will be duly processed by the SFrame generation code, as
1650 1.1.1.2 christos expected.
1651 1.1.1.2 christos
1652 1.1.1.2 christos For SFRAME_CFA_FP_REG, reset the state of the current FRE to indicate that
1653 1.1.1.2 christos the value is the same as previous frame.
1654 1.1.1.2 christos
1655 1.1.1.2 christos Return SFRAME_XLATE_OK if success. */
1656 1.1.1.2 christos
1657 1.1.1.2 christos static int
1658 1.1.1.2 christos sframe_xlate_do_same_value (const struct sframe_xlate_ctx *xlate_ctx,
1659 1.1.1.2 christos const struct cfi_insn_data *cfi_insn)
1660 1.1.1.2 christos {
1661 1.1.1.2 christos struct sframe_row_entry *cur_fre = xlate_ctx->cur_fre;
1662 1.1.1.2 christos
1663 1.1.1.2 christos if (sframe_ra_tracking_p () && cfi_insn->u.r == SFRAME_CFA_RA_REG)
1664 1.1.1.2 christos {
1665 1.1.1.2 christos cur_fre->ra_loc = SFRAME_FRE_ELEM_LOC_REG;
1666 1.1.1.2 christos cur_fre->ra_offset = 0;
1667 1.1.1.2 christos cur_fre->merge_candidate = false;
1668 1.1.1.2 christos }
1669 1.1.1.2 christos else if (cfi_insn->u.r == SFRAME_CFA_FP_REG)
1670 1.1.1.2 christos {
1671 1.1.1.2 christos cur_fre->bp_loc = SFRAME_FRE_ELEM_LOC_REG;
1672 1.1.1.2 christos cur_fre->bp_offset = 0;
1673 1.1.1.2 christos cur_fre->merge_candidate = false;
1674 1.1.1.2 christos }
1675 1.1.1.2 christos
1676 1.1.1.2 christos /* Safe to skip. */
1677 1.1.1.2 christos return SFRAME_XLATE_OK;
1678 1.1.1.2 christos }
1679 1.1.1.2 christos
1680 1.1.1.2 christos /* Returns the DWARF call frame instruction name or fake CFI name for the
1681 1.1.1.2 christos specified CFI opcode, or NULL if the value is not recognized. */
1682 1.1.1.2 christos
1683 1.1.1.2 christos static const char *
1684 1.1.1.2 christos sframe_get_cfi_name (int cfi_opc)
1685 1.1.1.2 christos {
1686 1.1.1.2 christos const char *cfi_name;
1687 1.1.1.2 christos
1688 1.1.1.2 christos switch (cfi_opc)
1689 1.1.1.2 christos {
1690 1.1.1.2 christos /* Fake CFI type; outside the byte range of any real CFI insn. */
1691 1.1.1.2 christos /* See gas/dw2gencfi.h. */
1692 1.1.1.2 christos case CFI_adjust_cfa_offset:
1693 1.1.1.2 christos cfi_name = "CFI_adjust_cfa_offset";
1694 1.1.1.2 christos break;
1695 1.1.1.2 christos case CFI_return_column:
1696 1.1.1.2 christos cfi_name = "CFI_return_column";
1697 1.1.1.2 christos break;
1698 1.1.1.2 christos case CFI_rel_offset:
1699 1.1.1.2 christos cfi_name = "CFI_rel_offset";
1700 1.1.1.2 christos break;
1701 1.1.1.2 christos case CFI_escape:
1702 1.1.1.2 christos cfi_name = "CFI_escape";
1703 1.1.1.2 christos break;
1704 1.1.1.2 christos case CFI_signal_frame:
1705 1.1.1.2 christos cfi_name = "CFI_signal_frame";
1706 1.1.1.2 christos break;
1707 1.1.1.2 christos case CFI_val_encoded_addr:
1708 1.1.1.2 christos cfi_name = "CFI_val_encoded_addr";
1709 1.1.1.2 christos break;
1710 1.1.1.2 christos case CFI_label:
1711 1.1.1.2 christos cfi_name = "CFI_label";
1712 1.1.1.2 christos break;
1713 1.1.1.2 christos default:
1714 1.1.1.2 christos cfi_name = get_DW_CFA_name (cfi_opc);
1715 1.1.1.2 christos }
1716 1.1.1.2 christos
1717 1.1.1.2 christos return cfi_name;
1718 1.1.1.2 christos }
1719 1.1.1.2 christos
1720 1.1 christos /* Process CFI_INSN and update the translation context with the FRE
1721 1.1 christos information.
1722 1.1 christos
1723 1.1 christos Returns an error code (sframe_xlate_err) if CFI_INSN is not successfully
1724 1.1 christos processed. */
1725 1.1 christos
1726 1.1 christos static int
1727 1.1 christos sframe_do_cfi_insn (struct sframe_xlate_ctx *xlate_ctx,
1728 1.1 christos struct cfi_insn_data *cfi_insn)
1729 1.1 christos {
1730 1.1 christos int err = 0;
1731 1.1 christos
1732 1.1 christos /* Atleast one cfi_insn per FDE is expected. */
1733 1.1 christos gas_assert (cfi_insn);
1734 1.1 christos int op = cfi_insn->insn;
1735 1.1 christos
1736 1.1 christos switch (op)
1737 1.1 christos {
1738 1.1 christos case DW_CFA_advance_loc:
1739 1.1 christos err = sframe_xlate_do_advance_loc (xlate_ctx, cfi_insn);
1740 1.1 christos break;
1741 1.1 christos case DW_CFA_def_cfa:
1742 1.1 christos err = sframe_xlate_do_def_cfa (xlate_ctx, cfi_insn);
1743 1.1 christos break;
1744 1.1 christos case DW_CFA_def_cfa_register:
1745 1.1 christos err = sframe_xlate_do_def_cfa_register (xlate_ctx, cfi_insn);
1746 1.1 christos break;
1747 1.1 christos case DW_CFA_def_cfa_offset:
1748 1.1 christos err = sframe_xlate_do_def_cfa_offset (xlate_ctx, cfi_insn);
1749 1.1 christos break;
1750 1.1 christos case DW_CFA_offset:
1751 1.1 christos err = sframe_xlate_do_offset (xlate_ctx, cfi_insn);
1752 1.1 christos break;
1753 1.1 christos case DW_CFA_val_offset:
1754 1.1.1.2 christos err = sframe_xlate_do_val_offset (xlate_ctx, cfi_insn, false);
1755 1.1 christos break;
1756 1.1 christos case DW_CFA_remember_state:
1757 1.1 christos err = sframe_xlate_do_remember_state (xlate_ctx);
1758 1.1 christos break;
1759 1.1 christos case DW_CFA_restore_state:
1760 1.1 christos err = sframe_xlate_do_restore_state (xlate_ctx);
1761 1.1 christos break;
1762 1.1 christos case DW_CFA_restore:
1763 1.1 christos err = sframe_xlate_do_restore (xlate_ctx, cfi_insn);
1764 1.1 christos break;
1765 1.1 christos /* DW_CFA_AARCH64_negate_ra_state is multiplexed with
1766 1.1 christos DW_CFA_GNU_window_save. */
1767 1.1 christos case DW_CFA_GNU_window_save:
1768 1.1 christos err = sframe_xlate_do_gnu_window_save (xlate_ctx, cfi_insn);
1769 1.1 christos break;
1770 1.1.1.2 christos case DW_CFA_AARCH64_negate_ra_state_with_pc:
1771 1.1.1.2 christos err = sframe_xlate_do_aarch64_negate_ra_state_with_pc (xlate_ctx, cfi_insn);
1772 1.1.1.2 christos break;
1773 1.1 christos case DW_CFA_register:
1774 1.1.1.2 christos err = sframe_xlate_do_register (xlate_ctx, cfi_insn);
1775 1.1.1.2 christos break;
1776 1.1.1.2 christos case CFI_escape:
1777 1.1.1.2 christos err = sframe_xlate_do_cfi_escape (xlate_ctx, cfi_insn);
1778 1.1 christos break;
1779 1.1 christos case DW_CFA_undefined:
1780 1.1.1.2 christos err = sframe_xlate_do_cfi_undefined (xlate_ctx, cfi_insn);
1781 1.1.1.2 christos break;
1782 1.1 christos case DW_CFA_same_value:
1783 1.1.1.2 christos err = sframe_xlate_do_same_value (xlate_ctx, cfi_insn);
1784 1.1 christos break;
1785 1.1 christos default:
1786 1.1.1.2 christos /* Other skipped operations may, however, impact the asynchronicity. */
1787 1.1.1.2 christos {
1788 1.1.1.2 christos const char *cfi_name = sframe_get_cfi_name (op);
1789 1.1.1.2 christos
1790 1.1.1.2 christos if (!cfi_name)
1791 1.1.1.2 christos cfi_name = _("(unknown)");
1792 1.1.1.2 christos as_warn (_("no SFrame FDE emitted; CFI insn %s (%#x)"),
1793 1.1.1.2 christos cfi_name, op);
1794 1.1.1.2 christos err = SFRAME_XLATE_ERR_NOTREPRESENTED;
1795 1.1.1.2 christos }
1796 1.1 christos }
1797 1.1 christos
1798 1.1.1.2 christos /* Any error will cause no SFrame FDE later. The user has already been
1799 1.1.1.2 christos warned. */
1800 1.1 christos return err;
1801 1.1 christos }
1802 1.1 christos
1803 1.1 christos
1804 1.1 christos static int
1805 1.1 christos sframe_do_fde (struct sframe_xlate_ctx *xlate_ctx,
1806 1.1 christos const struct fde_entry *dw_fde)
1807 1.1 christos {
1808 1.1 christos struct cfi_insn_data *cfi_insn;
1809 1.1 christos int err = SFRAME_XLATE_OK;
1810 1.1 christos
1811 1.1 christos xlate_ctx->dw_fde = dw_fde;
1812 1.1 christos
1813 1.1.1.2 christos /* SFrame format cannot represent a non-default DWARF return column reg. */
1814 1.1 christos if (xlate_ctx->dw_fde->return_column != DWARF2_DEFAULT_RETURN_COLUMN)
1815 1.1.1.2 christos {
1816 1.1.1.2 christos as_warn (_("no SFrame FDE emitted; non-default RA register %u"),
1817 1.1.1.2 christos xlate_ctx->dw_fde->return_column);
1818 1.1.1.2 christos return SFRAME_XLATE_ERR_NOTREPRESENTED;
1819 1.1.1.2 christos }
1820 1.1 christos
1821 1.1 christos /* Iterate over the CFIs and create SFrame FREs. */
1822 1.1 christos for (cfi_insn = dw_fde->data; cfi_insn; cfi_insn = cfi_insn->next)
1823 1.1 christos {
1824 1.1 christos /* Translate each CFI, and buffer the state in translation context. */
1825 1.1 christos err = sframe_do_cfi_insn (xlate_ctx, cfi_insn);
1826 1.1 christos if (err != SFRAME_XLATE_OK)
1827 1.1 christos {
1828 1.1 christos /* Skip generating SFrame stack trace info for the function if any
1829 1.1.1.2 christos offending CFI is encountered by sframe_do_cfi_insn (). Warning
1830 1.1.1.2 christos message already printed by sframe_do_cfi_insn (). */
1831 1.1 christos return err; /* Return the error code. */
1832 1.1 christos }
1833 1.1 christos }
1834 1.1 christos
1835 1.1 christos /* Link in the scratchpad FRE that the last few CFI insns helped create. */
1836 1.1 christos if (xlate_ctx->cur_fre)
1837 1.1 christos {
1838 1.1 christos sframe_xlate_ctx_add_fre (xlate_ctx, xlate_ctx->cur_fre);
1839 1.1 christos xlate_ctx->cur_fre = NULL;
1840 1.1 christos }
1841 1.1 christos /* Designate the end of the last SFrame FRE. */
1842 1.1 christos if (xlate_ctx->last_fre)
1843 1.1 christos {
1844 1.1 christos xlate_ctx->last_fre->pc_end
1845 1.1 christos = get_dw_fde_end_addrS (xlate_ctx->dw_fde);
1846 1.1 christos }
1847 1.1 christos
1848 1.1.1.2 christos /* ABI/arch except s390x cannot represent FP without RA saved. */
1849 1.1.1.2 christos if (sframe_ra_tracking_p ()
1850 1.1.1.2 christos && sframe_get_abi_arch () != SFRAME_ABI_S390X_ENDIAN_BIG)
1851 1.1.1.2 christos {
1852 1.1.1.2 christos struct sframe_row_entry *fre;
1853 1.1.1.2 christos
1854 1.1.1.2 christos /* Iterate over the scratchpad FREs and validate them. */
1855 1.1.1.2 christos for (fre = xlate_ctx->first_fre; fre; fre = fre->next)
1856 1.1.1.2 christos {
1857 1.1.1.2 christos /* SFrame format cannot represent FP on stack without RA on stack. */
1858 1.1.1.2 christos if (fre->ra_loc != SFRAME_FRE_ELEM_LOC_STACK
1859 1.1.1.2 christos && fre->bp_loc == SFRAME_FRE_ELEM_LOC_STACK)
1860 1.1.1.2 christos {
1861 1.1.1.2 christos as_warn (_("no SFrame FDE emitted; FP without RA on stack"));
1862 1.1.1.2 christos return SFRAME_XLATE_ERR_NOTREPRESENTED;
1863 1.1.1.2 christos }
1864 1.1.1.2 christos }
1865 1.1.1.2 christos }
1866 1.1.1.2 christos
1867 1.1 christos return SFRAME_XLATE_OK;
1868 1.1 christos }
1869 1.1 christos
1870 1.1 christos /* Create SFrame stack trace info for all functions.
1871 1.1 christos
1872 1.1 christos This function consumes the already generated DWARF FDEs (by dw2gencfi) and
1873 1.1 christos generates data which is later emitted as stack trace information encoded in
1874 1.1 christos the SFrame format. */
1875 1.1 christos
1876 1.1 christos static void
1877 1.1 christos create_sframe_all (void)
1878 1.1 christos {
1879 1.1 christos struct fde_entry *dw_fde = NULL;
1880 1.1 christos struct sframe_func_entry *sframe_fde = NULL;
1881 1.1 christos
1882 1.1 christos struct sframe_xlate_ctx *xlate_ctx = sframe_xlate_ctx_alloc ();
1883 1.1 christos
1884 1.1 christos for (dw_fde = all_fde_data; dw_fde ; dw_fde = dw_fde->next)
1885 1.1 christos {
1886 1.1 christos sframe_fde = sframe_fde_alloc ();
1887 1.1 christos /* Initialize the translation context with information anew. */
1888 1.1 christos sframe_xlate_ctx_init (xlate_ctx);
1889 1.1 christos
1890 1.1 christos /* Process and link SFrame FDEs if no error. Also skip adding an SFrame
1891 1.1 christos FDE if it does not contain any SFrame FREs. There is little use of an
1892 1.1 christos SFrame FDE if there is no stack tracing information for the
1893 1.1 christos function. */
1894 1.1 christos int err = sframe_do_fde (xlate_ctx, dw_fde);
1895 1.1 christos if (err || xlate_ctx->num_xlate_fres == 0)
1896 1.1 christos {
1897 1.1 christos sframe_xlate_ctx_cleanup (xlate_ctx);
1898 1.1 christos sframe_fde_free (sframe_fde);
1899 1.1 christos }
1900 1.1 christos else
1901 1.1 christos {
1902 1.1 christos /* All done. Transfer the state from the SFrame translation
1903 1.1 christos context to the SFrame FDE. */
1904 1.1 christos sframe_xlate_ctx_finalize (xlate_ctx, sframe_fde);
1905 1.1.1.2 christos *last_sframe_fde = sframe_fde;
1906 1.1.1.2 christos last_sframe_fde = &sframe_fde->next;
1907 1.1 christos }
1908 1.1 christos }
1909 1.1.1.2 christos
1910 1.1.1.2 christos XDELETE (xlate_ctx);
1911 1.1 christos }
1912 1.1 christos
1913 1.1 christos void
1914 1.1 christos output_sframe (segT sframe_seg)
1915 1.1 christos {
1916 1.1 christos (void) sframe_seg;
1917 1.1 christos
1918 1.1 christos /* Setup the version specific access functions. */
1919 1.1 christos sframe_set_version (SFRAME_VERSION_2);
1920 1.1 christos
1921 1.1 christos /* Process all fdes and create SFrame stack trace information. */
1922 1.1 christos create_sframe_all ();
1923 1.1 christos
1924 1.1 christos output_sframe_internal ();
1925 1.1 christos }
1926 1.1 christos
1927 1.1 christos #else /* support_sframe_p */
1928 1.1 christos
1929 1.1 christos void
1930 1.1 christos output_sframe (segT sframe_seg ATTRIBUTE_UNUSED)
1931 1.1 christos {
1932 1.1 christos }
1933 1.1 christos
1934 1.1 christos #endif /* support_sframe_p */
1935