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)
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. */
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
++;
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
)
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
)
68 reg
= DWARF_REG_TO_UNWIND_COLUMN (reg
);
69 if (UNWIND_COLUMN_IN_RANGE (reg
))
70 fs
->regs
.how
[reg
] = REG_UNSAVED
;
78 insn_ptr
= read_encoded_value (context
, fs
->fde_encoding
,
84 case DW_CFA_advance_loc1
:
85 fs
->pc
+= read_1u (insn_ptr
) * CODE_ALIGN
;
88 case DW_CFA_advance_loc2
:
89 fs
->pc
+= read_2u (insn_ptr
) * CODE_ALIGN
;
92 case DW_CFA_advance_loc4
:
93 fs
->pc
+= read_4u (insn_ptr
) * CODE_ALIGN
;
97 case DW_CFA_offset_extended
:
98 insn_ptr
= read_uleb128 (insn_ptr
, ®
);
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
;
109 case DW_CFA_restore_extended
:
110 insn_ptr
= read_uleb128 (insn_ptr
, ®
);
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
;
118 case DW_CFA_same_value
:
119 insn_ptr
= read_uleb128 (insn_ptr
, ®
);
120 reg
= DWARF_REG_TO_UNWIND_COLUMN (reg
);
121 if (UNWIND_COLUMN_IN_RANGE (reg
))
122 fs
->regs
.how
[reg
] = REG_UNSAVED
;
125 case DW_CFA_undefined
:
126 insn_ptr
= read_uleb128 (insn_ptr
, ®
);
127 reg
= DWARF_REG_TO_UNWIND_COLUMN (reg
);
128 if (UNWIND_COLUMN_IN_RANGE (reg
))
129 fs
->regs
.how
[reg
] = REG_UNDEFINED
;
135 case DW_CFA_register
:
138 insn_ptr
= read_uleb128 (insn_ptr
, ®
);
139 insn_ptr
= read_uleb128 (insn_ptr
, ®2
);
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
;
149 case DW_CFA_remember_state
:
151 struct frame_state_reg_info
*new_rs
;
155 unused_rs
= unused_rs
->prev
;
158 new_rs
= alloca (sizeof (struct frame_state_reg_info
));
161 fs
->regs
.prev
= new_rs
;
165 case DW_CFA_restore_state
:
167 struct frame_state_reg_info
*old_rs
= fs
->regs
.prev
;
169 old_rs
->prev
= unused_rs
;
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
;
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
;
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. */
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
);
201 case DW_CFA_expression
:
202 insn_ptr
= read_uleb128 (insn_ptr
, ®
);
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
);
214 case DW_CFA_offset_extended_sf
:
215 insn_ptr
= read_uleb128 (insn_ptr
, ®
);
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
;
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
;
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. */
242 case DW_CFA_val_offset
:
243 insn_ptr
= read_uleb128 (insn_ptr
, ®
);
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
;
254 case DW_CFA_val_offset_sf
:
255 insn_ptr
= read_uleb128 (insn_ptr
, ®
);
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
;
266 case DW_CFA_val_expression
:
267 insn_ptr
= read_uleb128 (insn_ptr
, ®
);
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 insn_ptr
= read_uleb128 (insn_ptr
, &utmp
);
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
281 return address signing status. REG_UNSAVED/REG_UNSAVED_ARCHEXT
282 mean RA signing is disabled/enabled. */
283 reg
= DWARF_REGNUM_AARCH64_RA_STATE
;
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
;
289 fs
->regs
.how
[reg
] = REG_UNSAVED
;
291 /* ??? Hardcoded for SPARC register window configuration. */
292 if (__LIBGCC_DWARF_FRAME_REGISTERS__
>= 32)
293 for (reg
= 16; reg
< 32; ++reg
)
295 fs
->regs
.how
[reg
] = REG_SAVED_OFFSET
;
296 fs
->regs
.reg
[reg
].loc
.offset
= (reg
- 16) * sizeof (void *);
301 case DW_CFA_GNU_args_size
:
302 insn_ptr
= read_uleb128 (insn_ptr
, &utmp
);
303 context
->args_size
= (_Unwind_Word
)utmp
;
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
, ®
);
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
))
315 fs
->regs
.how
[reg
] = REG_SAVED_OFFSET
;
316 fs
->regs
.reg
[reg
].loc
.offset
= -offset
;