Match: Refactor the unsigned SAT_ADD match pattern [NFC]
[gcc.git] / libgcc / unwind-dw2-execute_cfa.h
blob5d73e0420b1f86bfcaea1af7a9bd88af0d3e7f7b
1 /* DWARF2 exception handling CFA execution engine.
2 Copyright (C) 1997-2024 Free Software Foundation, Inc.
4 This file is part of GCC.
6 GCC is free software; you can redistribute it and/or modify it
7 under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 3, or (at your option)
9 any later version.
11 GCC is distributed in the hope that it will be useful, but WITHOUT
12 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13 or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
14 License for more details.
16 Under Section 7 of GPL version 3, you are granted additional
17 permissions described in the GCC Runtime Library Exception, version
18 3.1, as published by the Free Software Foundation.
20 You should have received a copy of the GNU General Public License and
21 a copy of the GCC Runtime Library Exception along with this program;
22 see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
23 <http://www.gnu.org/licenses/>. */
25 /* This file is included from unwind-dw2.c to specialize the code for certain
26 values of DATA_ALIGN and CODE_ALIGN. These macros must be defined prior to
27 including this file. */
30 struct frame_state_reg_info *unused_rs = NULL;
32 /* Don't allow remember/restore between CIE and FDE programs. */
33 fs->regs.prev = NULL;
35 /* The comparison with the return address uses < rather than <= because
36 we are only interested in the effects of code before the call; for a
37 noreturn function, the return address may point to unrelated code with
38 a different stack configuration that we are not interested in. We
39 assume that the call itself is unwind info-neutral; if not, or if
40 there are delay instructions that adjust the stack, these must be
41 reflected at the point immediately before the call insn.
42 In signal frames, return address is after last completed instruction,
43 so we add 1 to return address to make the comparison <=. */
44 while (insn_ptr < insn_end
45 && fs->pc < context->ra + _Unwind_IsSignalFrame (context))
47 unsigned char insn = *insn_ptr++;
48 _uleb128_t reg, utmp;
49 _sleb128_t offset, stmp;
51 if ((insn & 0xc0) == DW_CFA_advance_loc)
52 fs->pc += (insn & 0x3f) * CODE_ALIGN;
53 else if ((insn & 0xc0) == DW_CFA_offset)
55 reg = insn & 0x3f;
56 insn_ptr = read_uleb128 (insn_ptr, &utmp);
57 offset = (_Unwind_Sword) utmp * DATA_ALIGN;
58 reg = DWARF_REG_TO_UNWIND_COLUMN (reg);
59 if (UNWIND_COLUMN_IN_RANGE (reg))
61 fs->regs.how[reg] = REG_SAVED_OFFSET;
62 fs->regs.reg[reg].loc.offset = offset;
65 else if ((insn & 0xc0) == DW_CFA_restore)
67 reg = insn & 0x3f;
68 reg = DWARF_REG_TO_UNWIND_COLUMN (reg);
69 if (UNWIND_COLUMN_IN_RANGE (reg))
70 fs->regs.how[reg] = REG_UNSAVED;
72 else switch (insn)
74 case DW_CFA_set_loc:
76 _Unwind_Ptr pc;
78 insn_ptr = read_encoded_value (context, fs->fde_encoding,
79 insn_ptr, &pc);
80 fs->pc = (void *) pc;
82 break;
84 case DW_CFA_advance_loc1:
85 fs->pc += read_1u (insn_ptr) * CODE_ALIGN;
86 insn_ptr += 1;
87 break;
88 case DW_CFA_advance_loc2:
89 fs->pc += read_2u (insn_ptr) * CODE_ALIGN;
90 insn_ptr += 2;
91 break;
92 case DW_CFA_advance_loc4:
93 fs->pc += read_4u (insn_ptr) * CODE_ALIGN;
94 insn_ptr += 4;
95 break;
97 case DW_CFA_offset_extended:
98 insn_ptr = read_uleb128 (insn_ptr, &reg);
99 insn_ptr = read_uleb128 (insn_ptr, &utmp);
100 offset = (_Unwind_Sword) utmp * DATA_ALIGN;
101 reg = DWARF_REG_TO_UNWIND_COLUMN (reg);
102 if (UNWIND_COLUMN_IN_RANGE (reg))
104 fs->regs.how[reg] = REG_SAVED_OFFSET;
105 fs->regs.reg[reg].loc.offset = offset;
107 break;
109 case DW_CFA_restore_extended:
110 insn_ptr = read_uleb128 (insn_ptr, &reg);
111 /* FIXME, this is wrong; the CIE might have said that the
112 register was saved somewhere. */
113 reg = DWARF_REG_TO_UNWIND_COLUMN (reg);
114 if (UNWIND_COLUMN_IN_RANGE (reg))
115 fs->regs.how[reg] = REG_UNSAVED;
116 break;
118 case DW_CFA_same_value:
119 insn_ptr = read_uleb128 (insn_ptr, &reg);
120 reg = DWARF_REG_TO_UNWIND_COLUMN (reg);
121 if (UNWIND_COLUMN_IN_RANGE (reg))
122 fs->regs.how[reg] = REG_UNSAVED;
123 break;
125 case DW_CFA_undefined:
126 insn_ptr = read_uleb128 (insn_ptr, &reg);
127 reg = DWARF_REG_TO_UNWIND_COLUMN (reg);
128 if (UNWIND_COLUMN_IN_RANGE (reg))
129 fs->regs.how[reg] = REG_UNDEFINED;
130 break;
132 case DW_CFA_nop:
133 break;
135 case DW_CFA_register:
137 _uleb128_t reg2;
138 insn_ptr = read_uleb128 (insn_ptr, &reg);
139 insn_ptr = read_uleb128 (insn_ptr, &reg2);
140 reg = DWARF_REG_TO_UNWIND_COLUMN (reg);
141 if (UNWIND_COLUMN_IN_RANGE (reg))
143 fs->regs.how[reg] = REG_SAVED_REG;
144 fs->regs.reg[reg].loc.reg = (_Unwind_Word)reg2;
147 break;
149 case DW_CFA_remember_state:
151 struct frame_state_reg_info *new_rs;
152 if (unused_rs)
154 new_rs = unused_rs;
155 unused_rs = unused_rs->prev;
157 else
158 new_rs = alloca (sizeof (struct frame_state_reg_info));
160 *new_rs = fs->regs;
161 fs->regs.prev = new_rs;
163 break;
165 case DW_CFA_restore_state:
167 struct frame_state_reg_info *old_rs = fs->regs.prev;
168 fs->regs = *old_rs;
169 old_rs->prev = unused_rs;
170 unused_rs = old_rs;
172 break;
174 case DW_CFA_def_cfa:
175 insn_ptr = read_uleb128 (insn_ptr, &utmp);
176 fs->regs.cfa_reg = (_Unwind_Word)utmp;
177 insn_ptr = read_uleb128 (insn_ptr, &utmp);
178 fs->regs.cfa_offset = (_Unwind_Word)utmp;
179 fs->regs.cfa_how = CFA_REG_OFFSET;
180 break;
182 case DW_CFA_def_cfa_register:
183 insn_ptr = read_uleb128 (insn_ptr, &utmp);
184 fs->regs.cfa_reg = (_Unwind_Word)utmp;
185 fs->regs.cfa_how = CFA_REG_OFFSET;
186 break;
188 case DW_CFA_def_cfa_offset:
189 insn_ptr = read_uleb128 (insn_ptr, &utmp);
190 fs->regs.cfa_offset = utmp;
191 /* cfa_how deliberately not set. */
192 break;
194 case DW_CFA_def_cfa_expression:
195 fs->regs.cfa_exp = insn_ptr;
196 fs->regs.cfa_how = CFA_EXP;
197 insn_ptr = read_uleb128 (insn_ptr, &utmp);
198 insn_ptr += utmp;
199 break;
201 case DW_CFA_expression:
202 insn_ptr = read_uleb128 (insn_ptr, &reg);
203 reg = DWARF_REG_TO_UNWIND_COLUMN (reg);
204 if (UNWIND_COLUMN_IN_RANGE (reg))
206 fs->regs.how[reg] = REG_SAVED_EXP;
207 fs->regs.reg[reg].loc.exp = insn_ptr;
209 insn_ptr = read_uleb128 (insn_ptr, &utmp);
210 insn_ptr += utmp;
211 break;
213 /* Dwarf3. */
214 case DW_CFA_offset_extended_sf:
215 insn_ptr = read_uleb128 (insn_ptr, &reg);
216 insn_ptr = read_sleb128 (insn_ptr, &stmp);
217 offset = stmp * DATA_ALIGN;
218 reg = DWARF_REG_TO_UNWIND_COLUMN (reg);
219 if (UNWIND_COLUMN_IN_RANGE (reg))
221 fs->regs.how[reg] = REG_SAVED_OFFSET;
222 fs->regs.reg[reg].loc.offset = offset;
224 break;
226 case DW_CFA_def_cfa_sf:
227 insn_ptr = read_uleb128 (insn_ptr, &utmp);
228 fs->regs.cfa_reg = (_Unwind_Word)utmp;
229 insn_ptr = read_sleb128 (insn_ptr, &stmp);
230 fs->regs.cfa_offset = (_Unwind_Sword)stmp;
231 fs->regs.cfa_how = CFA_REG_OFFSET;
232 fs->regs.cfa_offset *= DATA_ALIGN;
233 break;
235 case DW_CFA_def_cfa_offset_sf:
236 insn_ptr = read_sleb128 (insn_ptr, &stmp);
237 fs->regs.cfa_offset = (_Unwind_Sword)stmp;
238 fs->regs.cfa_offset *= DATA_ALIGN;
239 /* cfa_how deliberately not set. */
240 break;
242 case DW_CFA_val_offset:
243 insn_ptr = read_uleb128 (insn_ptr, &reg);
244 insn_ptr = read_uleb128 (insn_ptr, &utmp);
245 offset = (_Unwind_Sword) utmp * DATA_ALIGN;
246 reg = DWARF_REG_TO_UNWIND_COLUMN (reg);
247 if (UNWIND_COLUMN_IN_RANGE (reg))
249 fs->regs.how[reg] = REG_SAVED_VAL_OFFSET;
250 fs->regs.reg[reg].loc.offset = offset;
252 break;
254 case DW_CFA_val_offset_sf:
255 insn_ptr = read_uleb128 (insn_ptr, &reg);
256 insn_ptr = read_sleb128 (insn_ptr, &stmp);
257 offset = stmp * DATA_ALIGN;
258 reg = DWARF_REG_TO_UNWIND_COLUMN (reg);
259 if (UNWIND_COLUMN_IN_RANGE (reg))
261 fs->regs.how[reg] = REG_SAVED_VAL_OFFSET;
262 fs->regs.reg[reg].loc.offset = offset;
264 break;
266 case DW_CFA_val_expression:
267 insn_ptr = read_uleb128 (insn_ptr, &reg);
268 reg = DWARF_REG_TO_UNWIND_COLUMN (reg);
269 if (UNWIND_COLUMN_IN_RANGE (reg))
271 fs->regs.how[reg] = REG_SAVED_VAL_EXP;
272 fs->regs.reg[reg].loc.exp = insn_ptr;
274 /* Don't execute the expression, but jump over it by adding
275 DW_FORM_block's size to insn_ptr. */
276 insn_ptr = read_uleb128 (insn_ptr, &utmp);
277 insn_ptr += utmp;
278 break;
280 #if defined (__aarch64__) && !defined (__ILP32__)
281 case DW_CFA_AARCH64_negate_ra_state:
282 /* This CFA is multiplexed with SPARC.
283 On AArch64 it's used to toggle the status of return address signing
284 with SP as a diversifier.
285 - REG_ARCHEXT means that the RA state register in FS contains a
286 valid value, and that no other DWARF directive has changed the
287 value of this register.
288 - any other value is not compatible with negating the RA state. */
289 aarch64_fs_ra_state_toggle (fs);
290 break;
291 #else
292 case DW_CFA_GNU_window_save:
293 /* ??? Hardcoded for SPARC register window configuration. */
294 if (__LIBGCC_DWARF_FRAME_REGISTERS__ >= 32)
295 for (reg = 16; reg < 32; ++reg)
297 fs->regs.how[reg] = REG_SAVED_OFFSET;
298 fs->regs.reg[reg].loc.offset = (reg - 16) * sizeof (void *);
300 break;
301 #endif
303 case DW_CFA_GNU_args_size:
304 insn_ptr = read_uleb128 (insn_ptr, &utmp);
305 context->args_size = (_Unwind_Word)utmp;
306 break;
308 case DW_CFA_GNU_negative_offset_extended:
309 /* Obsoleted by DW_CFA_offset_extended_sf, but used by
310 older PowerPC code. */
311 insn_ptr = read_uleb128 (insn_ptr, &reg);
312 insn_ptr = read_uleb128 (insn_ptr, &utmp);
313 offset = (_Unwind_Word) utmp * DATA_ALIGN;
314 reg = DWARF_REG_TO_UNWIND_COLUMN (reg);
315 if (UNWIND_COLUMN_IN_RANGE (reg))
317 fs->regs.how[reg] = REG_SAVED_OFFSET;
318 fs->regs.reg[reg].loc.offset = -offset;
320 break;
322 default:
323 gcc_unreachable ();
328 #undef DATA_ALIGN
329 #undef CODE_ALIGN