]> git.ipfire.org Git - thirdparty/gcc.git/blame - libgcc/unwind-dw2-execute_cfa.h
Update copyright years.
[thirdparty/gcc.git] / libgcc / unwind-dw2-execute_cfa.h
CommitLineData
8fdef16c 1/* DWARF2 exception handling CFA execution engine.
a945c346 2 Copyright (C) 1997-2024 Free Software Foundation, Inc.
8fdef16c
FW
3
4 This file is part of GCC.
5
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.
10
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.
15
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.
19
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/>. */
24
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. */
28
29{
30 struct frame_state_reg_info *unused_rs = NULL;
31
32 /* Don't allow remember/restore between CIE and FDE programs. */
33 fs->regs.prev = NULL;
34
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))
46 {
47 unsigned char insn = *insn_ptr++;
48 _uleb128_t reg, utmp;
49 _sleb128_t offset, stmp;
50
51 if ((insn & 0xc0) == DW_CFA_advance_loc)
52 fs->pc += (insn & 0x3f) * CODE_ALIGN;
53 else if ((insn & 0xc0) == DW_CFA_offset)
54 {
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))
60 {
61 fs->regs.how[reg] = REG_SAVED_OFFSET;
62 fs->regs.reg[reg].loc.offset = offset;
63 }
64 }
65 else if ((insn & 0xc0) == DW_CFA_restore)
66 {
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;
71 }
72 else switch (insn)
73 {
74 case DW_CFA_set_loc:
75 {
76 _Unwind_Ptr pc;
77
78 insn_ptr = read_encoded_value (context, fs->fde_encoding,
79 insn_ptr, &pc);
80 fs->pc = (void *) pc;
81 }
82 break;
83
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;
96
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))
103 {
104 fs->regs.how[reg] = REG_SAVED_OFFSET;
105 fs->regs.reg[reg].loc.offset = offset;
106 }
107 break;
108
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;
117
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;
124
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;
131
132 case DW_CFA_nop:
133 break;
134
135 case DW_CFA_register:
136 {
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))
142 {
143 fs->regs.how[reg] = REG_SAVED_REG;
144 fs->regs.reg[reg].loc.reg = (_Unwind_Word)reg2;
145 }
146 }
147 break;
148
149 case DW_CFA_remember_state:
150 {
151 struct frame_state_reg_info *new_rs;
152 if (unused_rs)
153 {
154 new_rs = unused_rs;
155 unused_rs = unused_rs->prev;
156 }
157 else
158 new_rs = alloca (sizeof (struct frame_state_reg_info));
159
160 *new_rs = fs->regs;
161 fs->regs.prev = new_rs;
162 }
163 break;
164
165 case DW_CFA_restore_state:
166 {
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;
171 }
172 break;
173
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;
181
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;
187
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;
193
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;
200
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))
205 {
206 fs->regs.how[reg] = REG_SAVED_EXP;
207 fs->regs.reg[reg].loc.exp = insn_ptr;
208 }
209 insn_ptr = read_uleb128 (insn_ptr, &utmp);
210 insn_ptr += utmp;
211 break;
212
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))
220 {
221 fs->regs.how[reg] = REG_SAVED_OFFSET;
222 fs->regs.reg[reg].loc.offset = offset;
223 }
224 break;
225
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;
234
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;
241
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))
248 {
249 fs->regs.how[reg] = REG_SAVED_VAL_OFFSET;
250 fs->regs.reg[reg].loc.offset = offset;
251 }
252 break;
253
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))
260 {
261 fs->regs.how[reg] = REG_SAVED_VAL_OFFSET;
262 fs->regs.reg[reg].loc.offset = offset;
263 }
264 break;
265
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))
270 {
271 fs->regs.how[reg] = REG_SAVED_VAL_EXP;
272 fs->regs.reg[reg].loc.exp = insn_ptr;
273 }
274 insn_ptr = read_uleb128 (insn_ptr, &utmp);
275 insn_ptr += utmp;
276 break;
277
278 case DW_CFA_GNU_window_save:
279#if defined (__aarch64__) && !defined (__ILP32__)
280 /* This CFA is multiplexed with Sparc. On AArch64 it's used to toggle
c98cd1df
WD
281 return address signing status. REG_UNSAVED/REG_UNSAVED_ARCHEXT
282 mean RA signing is disabled/enabled. */
8fdef16c 283 reg = DWARF_REGNUM_AARCH64_RA_STATE;
c98cd1df
WD
284 gcc_assert (fs->regs.how[reg] == REG_UNSAVED
285 || fs->regs.how[reg] == REG_UNSAVED_ARCHEXT);
286 if (fs->regs.how[reg] == REG_UNSAVED)
287 fs->regs.how[reg] = REG_UNSAVED_ARCHEXT;
288 else
289 fs->regs.how[reg] = REG_UNSAVED;
8fdef16c
FW
290#else
291 /* ??? Hardcoded for SPARC register window configuration. */
292 if (__LIBGCC_DWARF_FRAME_REGISTERS__ >= 32)
293 for (reg = 16; reg < 32; ++reg)
294 {
295 fs->regs.how[reg] = REG_SAVED_OFFSET;
296 fs->regs.reg[reg].loc.offset = (reg - 16) * sizeof (void *);
297 }
298#endif
299 break;
300
301 case DW_CFA_GNU_args_size:
302 insn_ptr = read_uleb128 (insn_ptr, &utmp);
303 context->args_size = (_Unwind_Word)utmp;
304 break;
305
306 case DW_CFA_GNU_negative_offset_extended:
307 /* Obsoleted by DW_CFA_offset_extended_sf, but used by
308 older PowerPC code. */
309 insn_ptr = read_uleb128 (insn_ptr, &reg);
310 insn_ptr = read_uleb128 (insn_ptr, &utmp);
311 offset = (_Unwind_Word) utmp * DATA_ALIGN;
312 reg = DWARF_REG_TO_UNWIND_COLUMN (reg);
313 if (UNWIND_COLUMN_IN_RANGE (reg))
314 {
315 fs->regs.how[reg] = REG_SAVED_OFFSET;
316 fs->regs.reg[reg].loc.offset = -offset;
317 }
318 break;
319
320 default:
321 gcc_unreachable ();
322 }
323 }
324}
325
326#undef DATA_ALIGN
327#undef CODE_ALIGN