ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/Unix/sigsegv.cpp
Revision: 1.86
Committed: 2009-02-11T19:23:53Z (15 years, 9 months ago) by asvitkine
Branch: MAIN
Changes since 1.85: +14 -5 lines
Log Message:
[Patch from Mike Sliczniak]

This first patch gets B2 and SS to build under Leopard and Tiger.

I tested this on a 32-bit intel 10.5.6 mac like so:

B2
./autogen.sh --disable-standalone-gui --enable-vosf --enable-sdl-video --enable-sdl-audio --enable-addressing=real --without-esd --without-gtk --without-mon --without-x

SS
./autogen.sh --disable-standalone-gui --enable-vosf -enable-sdl-video --disable-sdl-audio --enable-addressing=real --without-esd --without-gtk --without-mon --without-x --enable-jit

There is also a little tweak so that you can use sdl audio in SheepShaver when building for Mac OS X.

File Contents

# Content
1 /*
2 * sigsegv.cpp - SIGSEGV signals support
3 *
4 * Derived from Bruno Haible's work on his SIGSEGV library for clisp
5 * <http://clisp.sourceforge.net/>
6 *
7 * MacOS X support derived from the post by Timothy J. Wood to the
8 * omnigroup macosx-dev list:
9 * Mach Exception Handlers 101 (Was Re: ptrace, gdb)
10 * tjw@omnigroup.com Sun, 4 Jun 2000
11 * www.omnigroup.com/mailman/archive/macosx-dev/2000-June/002030.html
12 *
13 * Basilisk II (C) 1997-2008 Christian Bauer
14 *
15 * This program is free software; you can redistribute it and/or modify
16 * it under the terms of the GNU General Public License as published by
17 * the Free Software Foundation; either version 2 of the License, or
18 * (at your option) any later version.
19 *
20 * This program is distributed in the hope that it will be useful,
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 * GNU General Public License for more details.
24 *
25 * You should have received a copy of the GNU General Public License
26 * along with this program; if not, write to the Free Software
27 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
28 */
29
30 #ifdef HAVE_UNISTD_H
31 #include <unistd.h>
32 #endif
33
34 #ifdef HAVE_CONFIG_H
35 #include "config.h"
36 #endif
37
38 #include <list>
39 #include <stdio.h>
40 #include <signal.h>
41 #include "sigsegv.h"
42
43 #ifndef NO_STD_NAMESPACE
44 using std::list;
45 #endif
46
47 // Return value type of a signal handler (standard type if not defined)
48 #ifndef RETSIGTYPE
49 #define RETSIGTYPE void
50 #endif
51
52 // Size of an unsigned integer large enough to hold all bits of a pointer
53 // NOTE: this can be different than SIGSEGV_REGISTER_TYPE. In
54 // particular, on ILP32 systems with a 64-bit kernel (HP-UX/ia64?)
55 #ifdef HAVE_WIN32_VM
56 // Windows is either ILP32 or LLP64
57 typedef UINT_PTR sigsegv_uintptr_t;
58 #else
59 // Other systems are sane enough to follow ILP32 or LP64 models
60 typedef unsigned long sigsegv_uintptr_t;
61 #endif
62
63 // Type of the system signal handler
64 typedef RETSIGTYPE (*signal_handler)(int);
65
66 // User's SIGSEGV handler
67 static sigsegv_fault_handler_t sigsegv_fault_handler = 0;
68
69 // Function called to dump state if we can't handle the fault
70 static sigsegv_state_dumper_t sigsegv_state_dumper = 0;
71
72 // Actual SIGSEGV handler installer
73 static bool sigsegv_do_install_handler(int sig);
74
75
76 /*
77 * Instruction decoding aids
78 */
79
80 // Transfer type
81 enum transfer_type_t {
82 SIGSEGV_TRANSFER_UNKNOWN = 0,
83 SIGSEGV_TRANSFER_LOAD = 1,
84 SIGSEGV_TRANSFER_STORE = 2
85 };
86
87 // Transfer size
88 enum transfer_size_t {
89 SIZE_UNKNOWN,
90 SIZE_BYTE,
91 SIZE_WORD, // 2 bytes
92 SIZE_LONG, // 4 bytes
93 SIZE_QUAD // 8 bytes
94 };
95
96 #if (defined(powerpc) || defined(__powerpc__) || defined(__ppc__) || defined(__ppc64__))
97 // Addressing mode
98 enum addressing_mode_t {
99 MODE_UNKNOWN,
100 MODE_NORM,
101 MODE_U,
102 MODE_X,
103 MODE_UX
104 };
105
106 // Decoded instruction
107 struct instruction_t {
108 transfer_type_t transfer_type;
109 transfer_size_t transfer_size;
110 addressing_mode_t addr_mode;
111 unsigned int addr;
112 char ra, rd;
113 };
114
115 static void powerpc_decode_instruction(instruction_t *instruction, unsigned int nip, unsigned long * gpr)
116 {
117 // Get opcode and divide into fields
118 unsigned int opcode = *((unsigned int *)(unsigned long)nip);
119 unsigned int primop = opcode >> 26;
120 unsigned int exop = (opcode >> 1) & 0x3ff;
121 unsigned int ra = (opcode >> 16) & 0x1f;
122 unsigned int rb = (opcode >> 11) & 0x1f;
123 unsigned int rd = (opcode >> 21) & 0x1f;
124 signed int imm = (signed short)(opcode & 0xffff);
125
126 // Analyze opcode
127 transfer_type_t transfer_type = SIGSEGV_TRANSFER_UNKNOWN;
128 transfer_size_t transfer_size = SIZE_UNKNOWN;
129 addressing_mode_t addr_mode = MODE_UNKNOWN;
130 switch (primop) {
131 case 31:
132 switch (exop) {
133 case 23: // lwzx
134 transfer_type = SIGSEGV_TRANSFER_LOAD; transfer_size = SIZE_LONG; addr_mode = MODE_X; break;
135 case 55: // lwzux
136 transfer_type = SIGSEGV_TRANSFER_LOAD; transfer_size = SIZE_LONG; addr_mode = MODE_UX; break;
137 case 87: // lbzx
138 transfer_type = SIGSEGV_TRANSFER_LOAD; transfer_size = SIZE_BYTE; addr_mode = MODE_X; break;
139 case 119: // lbzux
140 transfer_type = SIGSEGV_TRANSFER_LOAD; transfer_size = SIZE_BYTE; addr_mode = MODE_UX; break;
141 case 151: // stwx
142 transfer_type = SIGSEGV_TRANSFER_STORE; transfer_size = SIZE_LONG; addr_mode = MODE_X; break;
143 case 183: // stwux
144 transfer_type = SIGSEGV_TRANSFER_STORE; transfer_size = SIZE_LONG; addr_mode = MODE_UX; break;
145 case 215: // stbx
146 transfer_type = SIGSEGV_TRANSFER_STORE; transfer_size = SIZE_BYTE; addr_mode = MODE_X; break;
147 case 247: // stbux
148 transfer_type = SIGSEGV_TRANSFER_STORE; transfer_size = SIZE_BYTE; addr_mode = MODE_UX; break;
149 case 279: // lhzx
150 transfer_type = SIGSEGV_TRANSFER_LOAD; transfer_size = SIZE_WORD; addr_mode = MODE_X; break;
151 case 311: // lhzux
152 transfer_type = SIGSEGV_TRANSFER_LOAD; transfer_size = SIZE_WORD; addr_mode = MODE_UX; break;
153 case 343: // lhax
154 transfer_type = SIGSEGV_TRANSFER_LOAD; transfer_size = SIZE_WORD; addr_mode = MODE_X; break;
155 case 375: // lhaux
156 transfer_type = SIGSEGV_TRANSFER_LOAD; transfer_size = SIZE_WORD; addr_mode = MODE_UX; break;
157 case 407: // sthx
158 transfer_type = SIGSEGV_TRANSFER_STORE; transfer_size = SIZE_WORD; addr_mode = MODE_X; break;
159 case 439: // sthux
160 transfer_type = SIGSEGV_TRANSFER_STORE; transfer_size = SIZE_WORD; addr_mode = MODE_UX; break;
161 }
162 break;
163
164 case 32: // lwz
165 transfer_type = SIGSEGV_TRANSFER_LOAD; transfer_size = SIZE_LONG; addr_mode = MODE_NORM; break;
166 case 33: // lwzu
167 transfer_type = SIGSEGV_TRANSFER_LOAD; transfer_size = SIZE_LONG; addr_mode = MODE_U; break;
168 case 34: // lbz
169 transfer_type = SIGSEGV_TRANSFER_LOAD; transfer_size = SIZE_BYTE; addr_mode = MODE_NORM; break;
170 case 35: // lbzu
171 transfer_type = SIGSEGV_TRANSFER_LOAD; transfer_size = SIZE_BYTE; addr_mode = MODE_U; break;
172 case 36: // stw
173 transfer_type = SIGSEGV_TRANSFER_STORE; transfer_size = SIZE_LONG; addr_mode = MODE_NORM; break;
174 case 37: // stwu
175 transfer_type = SIGSEGV_TRANSFER_STORE; transfer_size = SIZE_LONG; addr_mode = MODE_U; break;
176 case 38: // stb
177 transfer_type = SIGSEGV_TRANSFER_STORE; transfer_size = SIZE_BYTE; addr_mode = MODE_NORM; break;
178 case 39: // stbu
179 transfer_type = SIGSEGV_TRANSFER_STORE; transfer_size = SIZE_BYTE; addr_mode = MODE_U; break;
180 case 40: // lhz
181 transfer_type = SIGSEGV_TRANSFER_LOAD; transfer_size = SIZE_WORD; addr_mode = MODE_NORM; break;
182 case 41: // lhzu
183 transfer_type = SIGSEGV_TRANSFER_LOAD; transfer_size = SIZE_WORD; addr_mode = MODE_U; break;
184 case 42: // lha
185 transfer_type = SIGSEGV_TRANSFER_LOAD; transfer_size = SIZE_WORD; addr_mode = MODE_NORM; break;
186 case 43: // lhau
187 transfer_type = SIGSEGV_TRANSFER_LOAD; transfer_size = SIZE_WORD; addr_mode = MODE_U; break;
188 case 44: // sth
189 transfer_type = SIGSEGV_TRANSFER_STORE; transfer_size = SIZE_WORD; addr_mode = MODE_NORM; break;
190 case 45: // sthu
191 transfer_type = SIGSEGV_TRANSFER_STORE; transfer_size = SIZE_WORD; addr_mode = MODE_U; break;
192 case 58: // ld, ldu, lwa
193 transfer_type = SIGSEGV_TRANSFER_LOAD;
194 transfer_size = SIZE_QUAD;
195 addr_mode = ((opcode & 3) == 1) ? MODE_U : MODE_NORM;
196 imm &= ~3;
197 break;
198 case 62: // std, stdu, stq
199 transfer_type = SIGSEGV_TRANSFER_STORE;
200 transfer_size = SIZE_QUAD;
201 addr_mode = ((opcode & 3) == 1) ? MODE_U : MODE_NORM;
202 imm &= ~3;
203 break;
204 }
205
206 // Calculate effective address
207 unsigned int addr = 0;
208 switch (addr_mode) {
209 case MODE_X:
210 case MODE_UX:
211 if (ra == 0)
212 addr = gpr[rb];
213 else
214 addr = gpr[ra] + gpr[rb];
215 break;
216 case MODE_NORM:
217 case MODE_U:
218 if (ra == 0)
219 addr = (signed int)(signed short)imm;
220 else
221 addr = gpr[ra] + (signed int)(signed short)imm;
222 break;
223 default:
224 break;
225 }
226
227 // Commit decoded instruction
228 instruction->addr = addr;
229 instruction->addr_mode = addr_mode;
230 instruction->transfer_type = transfer_type;
231 instruction->transfer_size = transfer_size;
232 instruction->ra = ra;
233 instruction->rd = rd;
234 }
235 #endif
236
237
238 /*
239 * OS-dependant SIGSEGV signals support section
240 */
241
242 #if HAVE_SIGINFO_T
243 // Generic extended signal handler
244 #if defined(__FreeBSD__)
245 #define SIGSEGV_ALL_SIGNALS FAULT_HANDLER(SIGBUS)
246 #elif defined(__hpux)
247 #define SIGSEGV_ALL_SIGNALS FAULT_HANDLER(SIGSEGV) FAULT_HANDLER(SIGBUS)
248 #else
249 #define SIGSEGV_ALL_SIGNALS FAULT_HANDLER(SIGSEGV)
250 #endif
251 #define SIGSEGV_FAULT_HANDLER_ARGLIST int sig, siginfo_t *sip, void *scp
252 #define SIGSEGV_FAULT_HANDLER_ARGLIST_1 siginfo_t *sip, void *scp
253 #define SIGSEGV_FAULT_HANDLER_ARGS sip, scp
254 #define SIGSEGV_FAULT_ADDRESS sip->si_addr
255 #if (defined(sgi) || defined(__sgi))
256 #include <ucontext.h>
257 #define SIGSEGV_CONTEXT_REGS (((ucontext_t *)scp)->uc_mcontext.gregs)
258 #define SIGSEGV_FAULT_INSTRUCTION (unsigned long)SIGSEGV_CONTEXT_REGS[CTX_EPC]
259 #if (defined(mips) || defined(__mips))
260 #define SIGSEGV_REGISTER_FILE &SIGSEGV_CONTEXT_REGS[CTX_EPC], &SIGSEGV_CONTEXT_REGS[CTX_R0]
261 #define SIGSEGV_SKIP_INSTRUCTION mips_skip_instruction
262 #endif
263 #endif
264 #if defined(__sun__)
265 #if (defined(sparc) || defined(__sparc__))
266 #include <sys/stack.h>
267 #include <sys/regset.h>
268 #include <sys/ucontext.h>
269 #define SIGSEGV_CONTEXT_REGS (((ucontext_t *)scp)->uc_mcontext.gregs)
270 #define SIGSEGV_FAULT_INSTRUCTION SIGSEGV_CONTEXT_REGS[REG_PC]
271 #define SIGSEGV_SPARC_GWINDOWS (((ucontext_t *)scp)->uc_mcontext.gwins)
272 #define SIGSEGV_SPARC_RWINDOW (struct rwindow *)((char *)SIGSEGV_CONTEXT_REGS[REG_SP] + STACK_BIAS)
273 #define SIGSEGV_REGISTER_FILE ((unsigned long *)SIGSEGV_CONTEXT_REGS), SIGSEGV_SPARC_GWINDOWS, SIGSEGV_SPARC_RWINDOW
274 #define SIGSEGV_SKIP_INSTRUCTION sparc_skip_instruction
275 #endif
276 #if defined(__i386__)
277 #include <sys/regset.h>
278 #define SIGSEGV_CONTEXT_REGS (((ucontext_t *)scp)->uc_mcontext.gregs)
279 #define SIGSEGV_FAULT_INSTRUCTION SIGSEGV_CONTEXT_REGS[EIP]
280 #define SIGSEGV_REGISTER_FILE (SIGSEGV_REGISTER_TYPE *)SIGSEGV_CONTEXT_REGS
281 #define SIGSEGV_SKIP_INSTRUCTION ix86_skip_instruction
282 #endif
283 #endif
284 #if defined(__FreeBSD__) || defined(__OpenBSD__)
285 #if (defined(i386) || defined(__i386__))
286 #define SIGSEGV_FAULT_INSTRUCTION (((struct sigcontext *)scp)->sc_eip)
287 #define SIGSEGV_REGISTER_FILE ((SIGSEGV_REGISTER_TYPE *)&(((struct sigcontext *)scp)->sc_edi)) /* EDI is the first GPR (even below EIP) in sigcontext */
288 #define SIGSEGV_SKIP_INSTRUCTION ix86_skip_instruction
289 #endif
290 #endif
291 #if defined(__NetBSD__)
292 #if (defined(i386) || defined(__i386__))
293 #include <sys/ucontext.h>
294 #define SIGSEGV_CONTEXT_REGS (((ucontext_t *)scp)->uc_mcontext.__gregs)
295 #define SIGSEGV_FAULT_INSTRUCTION SIGSEGV_CONTEXT_REGS[_REG_EIP]
296 #define SIGSEGV_REGISTER_FILE (SIGSEGV_REGISTER_TYPE *)SIGSEGV_CONTEXT_REGS
297 #define SIGSEGV_SKIP_INSTRUCTION ix86_skip_instruction
298 #endif
299 #if (defined(powerpc) || defined(__powerpc__))
300 #include <sys/ucontext.h>
301 #define SIGSEGV_CONTEXT_REGS (((ucontext_t *)scp)->uc_mcontext.__gregs)
302 #define SIGSEGV_FAULT_INSTRUCTION SIGSEGV_CONTEXT_REGS[_REG_PC]
303 #define SIGSEGV_REGISTER_FILE (unsigned long *)&SIGSEGV_CONTEXT_REGS[_REG_PC], (unsigned long *)&SIGSEGV_CONTEXT_REGS[_REG_R0]
304 #define SIGSEGV_SKIP_INSTRUCTION powerpc_skip_instruction
305 #endif
306 #endif
307 #if defined(__linux__)
308 #if (defined(i386) || defined(__i386__))
309 #include <sys/ucontext.h>
310 #define SIGSEGV_CONTEXT_REGS (((ucontext_t *)scp)->uc_mcontext.gregs)
311 #define SIGSEGV_FAULT_INSTRUCTION SIGSEGV_CONTEXT_REGS[14] /* should use REG_EIP instead */
312 #define SIGSEGV_REGISTER_FILE (SIGSEGV_REGISTER_TYPE *)SIGSEGV_CONTEXT_REGS
313 #define SIGSEGV_SKIP_INSTRUCTION ix86_skip_instruction
314 #endif
315 #if (defined(x86_64) || defined(__x86_64__))
316 #include <sys/ucontext.h>
317 #define SIGSEGV_CONTEXT_REGS (((ucontext_t *)scp)->uc_mcontext.gregs)
318 #define SIGSEGV_FAULT_INSTRUCTION SIGSEGV_CONTEXT_REGS[16] /* should use REG_RIP instead */
319 #define SIGSEGV_REGISTER_FILE (SIGSEGV_REGISTER_TYPE *)SIGSEGV_CONTEXT_REGS
320 #define SIGSEGV_SKIP_INSTRUCTION ix86_skip_instruction
321 #endif
322 #if (defined(ia64) || defined(__ia64__))
323 #define SIGSEGV_CONTEXT_REGS ((struct sigcontext *)scp)
324 #define SIGSEGV_FAULT_INSTRUCTION (SIGSEGV_CONTEXT_REGS->sc_ip & ~0x3ULL) /* slot number is in bits 0 and 1 */
325 #define SIGSEGV_REGISTER_FILE SIGSEGV_CONTEXT_REGS
326 #define SIGSEGV_SKIP_INSTRUCTION ia64_skip_instruction
327 #endif
328 #if (defined(powerpc) || defined(__powerpc__))
329 #include <sys/ucontext.h>
330 #define SIGSEGV_CONTEXT_REGS (((ucontext_t *)scp)->uc_mcontext.regs)
331 #define SIGSEGV_FAULT_INSTRUCTION (SIGSEGV_CONTEXT_REGS->nip)
332 #define SIGSEGV_REGISTER_FILE (unsigned long *)&SIGSEGV_CONTEXT_REGS->nip, (unsigned long *)(SIGSEGV_CONTEXT_REGS->gpr)
333 #define SIGSEGV_SKIP_INSTRUCTION powerpc_skip_instruction
334 #endif
335 #if (defined(hppa) || defined(__hppa__))
336 #undef SIGSEGV_FAULT_ADDRESS
337 #define SIGSEGV_FAULT_ADDRESS sip->si_ptr
338 #endif
339 #if (defined(arm) || defined(__arm__))
340 #include <asm/ucontext.h> /* use kernel structure, glibc may not be in sync */
341 #define SIGSEGV_CONTEXT_REGS (((struct ucontext *)scp)->uc_mcontext)
342 #define SIGSEGV_FAULT_INSTRUCTION (SIGSEGV_CONTEXT_REGS.arm_pc)
343 #define SIGSEGV_REGISTER_FILE (&SIGSEGV_CONTEXT_REGS.arm_r0)
344 #define SIGSEGV_SKIP_INSTRUCTION arm_skip_instruction
345 #endif
346 #if (defined(mips) || defined(__mips__))
347 #include <sys/ucontext.h>
348 #define SIGSEGV_CONTEXT_REGS (((struct ucontext *)scp)->uc_mcontext)
349 #define SIGSEGV_FAULT_INSTRUCTION (SIGSEGV_CONTEXT_REGS.pc)
350 #define SIGSEGV_REGISTER_FILE &SIGSEGV_CONTEXT_REGS.pc, &SIGSEGV_CONTEXT_REGS.gregs[0]
351 #define SIGSEGV_SKIP_INSTRUCTION mips_skip_instruction
352 #endif
353 #endif
354 #if (defined(__hpux) || defined(__hpux__))
355 #if (defined(__hppa) || defined(__hppa__))
356 #define SIGSEGV_CONTEXT_REGS (&((ucontext_t *)scp)->uc_mcontext)
357 #define SIGSEGV_FAULT_INSTRUCTION_32 (SIGSEGV_CONTEXT_REGS->ss_narrow.ss_pcoq_head & ~3ul)
358 #define SIGSEGV_FAULT_INSTRUCTION_64 (SIGSEGV_CONTEXT_REGS->ss_wide.ss_64.ss_pcoq_head & ~3ull)
359 #if defined(__LP64__)
360 #define SIGSEGV_FAULT_INSTRUCTION SIGSEGV_FAULT_INSTRUCTION_64
361 #else
362 #define SIGSEGV_FAULT_INSTRUCTION ((SIGSEGV_CONTEXT_REGS->ss_flags & SS_WIDEREGS) ? \
363 (uint32_t)SIGSEGV_FAULT_INSTRUCTION_64 : \
364 SIGSEGV_FAULT_INSTRUCTION_32)
365 #endif
366 #endif
367 #if (defined(__ia64) || defined(__ia64__))
368 #include <sys/ucontext.h>
369 #define SIGSEGV_CONTEXT_REGS ((ucontext_t *)scp)
370 #define SIGSEGV_FAULT_INSTRUCTION get_fault_instruction(SIGSEGV_CONTEXT_REGS)
371 #define SIGSEGV_REGISTER_FILE SIGSEGV_CONTEXT_REGS
372 #define SIGSEGV_SKIP_INSTRUCTION ia64_skip_instruction
373
374 #include <sys/uc_access.h>
375 static inline sigsegv_address_t get_fault_instruction(const ucontext_t *ucp)
376 {
377 uint64_t ip;
378 if (__uc_get_ip(ucp, &ip) != 0)
379 return SIGSEGV_INVALID_ADDRESS;
380 return (sigsegv_address_t)(ip & ~3ULL);
381 }
382 #endif
383 #endif
384 #endif
385
386 #if HAVE_SIGCONTEXT_SUBTERFUGE
387 // Linux kernels prior to 2.4 ?
388 #if defined(__linux__)
389 #define SIGSEGV_ALL_SIGNALS FAULT_HANDLER(SIGSEGV)
390 #if (defined(i386) || defined(__i386__))
391 #include <asm/sigcontext.h>
392 #define SIGSEGV_FAULT_HANDLER_ARGLIST int sig, struct sigcontext scs
393 #define SIGSEGV_FAULT_HANDLER_ARGLIST_1 struct sigcontext *scp
394 #define SIGSEGV_FAULT_HANDLER_ARGS &scs
395 #define SIGSEGV_FAULT_ADDRESS scp->cr2
396 #define SIGSEGV_FAULT_INSTRUCTION scp->eip
397 #define SIGSEGV_REGISTER_FILE (SIGSEGV_REGISTER_TYPE *)scp
398 #define SIGSEGV_SKIP_INSTRUCTION ix86_skip_instruction
399 #endif
400 #if (defined(sparc) || defined(__sparc__))
401 #include <asm/sigcontext.h>
402 #define SIGSEGV_FAULT_HANDLER_ARGLIST int sig, int code, struct sigcontext *scp, char *addr
403 #define SIGSEGV_FAULT_HANDLER_ARGS sig, code, scp, addr
404 #define SIGSEGV_FAULT_ADDRESS addr
405 #endif
406 #if (defined(powerpc) || defined(__powerpc__))
407 #include <asm/sigcontext.h>
408 #define SIGSEGV_FAULT_HANDLER_ARGLIST int sig, struct sigcontext *scp
409 #define SIGSEGV_FAULT_HANDLER_ARGS sig, scp
410 #define SIGSEGV_FAULT_ADDRESS scp->regs->dar
411 #define SIGSEGV_FAULT_INSTRUCTION scp->regs->nip
412 #define SIGSEGV_REGISTER_FILE (unsigned long *)&scp->regs->nip, (unsigned long *)(scp->regs->gpr)
413 #define SIGSEGV_SKIP_INSTRUCTION powerpc_skip_instruction
414 #endif
415 #if (defined(alpha) || defined(__alpha__))
416 #include <asm/sigcontext.h>
417 #define SIGSEGV_FAULT_HANDLER_ARGLIST int sig, int code, struct sigcontext *scp
418 #define SIGSEGV_FAULT_HANDLER_ARGS sig, code, scp
419 #define SIGSEGV_FAULT_ADDRESS get_fault_address(scp)
420 #define SIGSEGV_FAULT_INSTRUCTION scp->sc_pc
421 #endif
422 #if (defined(arm) || defined(__arm__))
423 #define SIGSEGV_FAULT_HANDLER_ARGLIST int sig, int r1, int r2, int r3, struct sigcontext sc
424 #define SIGSEGV_FAULT_HANDLER_ARGLIST_1 struct sigcontext *scp
425 #define SIGSEGV_FAULT_HANDLER_ARGS &sc
426 #define SIGSEGV_FAULT_ADDRESS scp->fault_address
427 #define SIGSEGV_FAULT_INSTRUCTION scp->arm_pc
428 #define SIGSEGV_REGISTER_FILE &scp->arm_r0
429 #define SIGSEGV_SKIP_INSTRUCTION arm_skip_instruction
430 #endif
431 #endif
432
433 // Irix 5 or 6 on MIPS
434 #if (defined(sgi) || defined(__sgi)) && (defined(SYSTYPE_SVR4) || defined(_SYSTYPE_SVR4))
435 #include <ucontext.h>
436 #define SIGSEGV_FAULT_HANDLER_ARGLIST int sig, int code, struct sigcontext *scp
437 #define SIGSEGV_FAULT_HANDLER_ARGS sig, code, scp
438 #define SIGSEGV_FAULT_ADDRESS (unsigned long)scp->sc_badvaddr
439 #define SIGSEGV_FAULT_INSTRUCTION (unsigned long)scp->sc_pc
440 #define SIGSEGV_ALL_SIGNALS FAULT_HANDLER(SIGSEGV)
441 #endif
442
443 // HP-UX
444 #if (defined(hpux) || defined(__hpux__))
445 #define SIGSEGV_FAULT_HANDLER_ARGLIST int sig, int code, struct sigcontext *scp
446 #define SIGSEGV_FAULT_HANDLER_ARGS sig, code, scp
447 #define SIGSEGV_FAULT_ADDRESS scp->sc_sl.sl_ss.ss_narrow.ss_cr21
448 #define SIGSEGV_ALL_SIGNALS FAULT_HANDLER(SIGSEGV) FAULT_HANDLER(SIGBUS)
449 #endif
450
451 // OSF/1 on Alpha
452 #if defined(__osf__)
453 #include <ucontext.h>
454 #define SIGSEGV_FAULT_HANDLER_ARGLIST int sig, int code, struct sigcontext *scp
455 #define SIGSEGV_FAULT_HANDLER_ARGS sig, code, scp
456 #define SIGSEGV_FAULT_ADDRESS scp->sc_traparg_a0
457 #define SIGSEGV_ALL_SIGNALS FAULT_HANDLER(SIGSEGV)
458 #endif
459
460 // AIX
461 #if defined(_AIX)
462 #define SIGSEGV_FAULT_HANDLER_ARGLIST int sig, int code, struct sigcontext *scp
463 #define SIGSEGV_FAULT_HANDLER_ARGS sig, code, scp
464 #define SIGSEGV_FAULT_ADDRESS scp->sc_jmpbuf.jmp_context.o_vaddr
465 #define SIGSEGV_ALL_SIGNALS FAULT_HANDLER(SIGSEGV)
466 #endif
467
468 // NetBSD
469 #if defined(__NetBSD__)
470 #if (defined(m68k) || defined(__m68k__))
471 #include <m68k/frame.h>
472 #define SIGSEGV_FAULT_HANDLER_ARGLIST int sig, int code, struct sigcontext *scp
473 #define SIGSEGV_FAULT_HANDLER_ARGS sig, code, scp
474 #define SIGSEGV_FAULT_ADDRESS get_fault_address(scp)
475 #define SIGSEGV_ALL_SIGNALS FAULT_HANDLER(SIGSEGV)
476
477 // Use decoding scheme from BasiliskII/m68k native
478 static sigsegv_address_t get_fault_address(struct sigcontext *scp)
479 {
480 struct sigstate {
481 int ss_flags;
482 struct frame ss_frame;
483 };
484 struct sigstate *state = (struct sigstate *)scp->sc_ap;
485 char *fault_addr;
486 switch (state->ss_frame.f_format) {
487 case 7: /* 68040 access error */
488 /* "code" is sometimes unreliable (i.e. contains NULL or a bogus address), reason unknown */
489 fault_addr = state->ss_frame.f_fmt7.f_fa;
490 break;
491 default:
492 fault_addr = (char *)code;
493 break;
494 }
495 return (sigsegv_address_t)fault_addr;
496 }
497 #endif
498 #if (defined(alpha) || defined(__alpha__))
499 #define SIGSEGV_FAULT_HANDLER_ARGLIST int sig, int code, struct sigcontext *scp
500 #define SIGSEGV_FAULT_HANDLER_ARGS sig, code, scp
501 #define SIGSEGV_FAULT_ADDRESS get_fault_address(scp)
502 #define SIGSEGV_ALL_SIGNALS FAULT_HANDLER(SIGBUS)
503 #endif
504 #if (defined(i386) || defined(__i386__))
505 #error "FIXME: need to decode instruction and compute EA"
506 #define SIGSEGV_FAULT_HANDLER_ARGLIST int sig, int code, struct sigcontext *scp
507 #define SIGSEGV_FAULT_HANDLER_ARGS sig, code, scp
508 #define SIGSEGV_ALL_SIGNALS FAULT_HANDLER(SIGSEGV)
509 #endif
510 #endif
511 #if defined(__FreeBSD__)
512 #if (defined(i386) || defined(__i386__))
513 #define SIGSEGV_ALL_SIGNALS FAULT_HANDLER(SIGBUS)
514 #define SIGSEGV_FAULT_HANDLER_ARGLIST int sig, int code, struct sigcontext *scp, char *addr
515 #define SIGSEGV_FAULT_HANDLER_ARGS sig, code, scp, addr
516 #define SIGSEGV_FAULT_ADDRESS addr
517 #define SIGSEGV_FAULT_INSTRUCTION scp->sc_eip
518 #define SIGSEGV_REGISTER_FILE ((SIGSEGV_REGISTER_TYPE *)&scp->sc_edi)
519 #define SIGSEGV_SKIP_INSTRUCTION ix86_skip_instruction
520 #endif
521 #if (defined(alpha) || defined(__alpha__))
522 #define SIGSEGV_ALL_SIGNALS FAULT_HANDLER(SIGSEGV)
523 #define SIGSEGV_FAULT_HANDLER_ARGLIST int sig, char *addr, struct sigcontext *scp
524 #define SIGSEGV_FAULT_HANDLER_ARGS sig, addr, scp
525 #define SIGSEGV_FAULT_ADDRESS addr
526 #define SIGSEGV_FAULT_INSTRUCTION scp->sc_pc
527 #endif
528 #endif
529
530 // Extract fault address out of a sigcontext
531 #if (defined(alpha) || defined(__alpha__))
532 // From Boehm's GC 6.0alpha8
533 static sigsegv_address_t get_fault_address(struct sigcontext *scp)
534 {
535 unsigned int instruction = *((unsigned int *)(scp->sc_pc));
536 unsigned long fault_address = scp->sc_regs[(instruction >> 16) & 0x1f];
537 fault_address += (signed long)(signed short)(instruction & 0xffff);
538 return (sigsegv_address_t)fault_address;
539 }
540 #endif
541
542
543 // MacOS X, not sure which version this works in. Under 10.1
544 // vm_protect does not appear to work from a signal handler. Under
545 // 10.2 signal handlers get siginfo type arguments but the si_addr
546 // field is the address of the faulting instruction and not the
547 // address that caused the SIGBUS. Maybe this works in 10.0? In any
548 // case with Mach exception handlers there is a way to do what this
549 // was meant to do.
550 #ifndef HAVE_MACH_EXCEPTIONS
551 #if defined(__APPLE__) && defined(__MACH__)
552 #if (defined(ppc) || defined(__ppc__))
553 #define SIGSEGV_FAULT_HANDLER_ARGLIST int sig, int code, struct __darwin_sigcontext *scp
554 #define SIGSEGV_FAULT_HANDLER_ARGS sig, code, scp
555 #define SIGSEGV_FAULT_ADDRESS get_fault_address(scp)
556 #define SIGSEGV_FAULT_INSTRUCTION scp->MACH_FIELD_NAME(sc_ir)
557 #define SIGSEGV_ALL_SIGNALS FAULT_HANDLER(SIGBUS)
558 #define SIGSEGV_REGISTER_FILE (unsigned int *)&scp->sc_ir, &((unsigned int *) scp->sc_regs)[2]
559 #define SIGSEGV_SKIP_INSTRUCTION powerpc_skip_instruction
560
561 // Use decoding scheme from SheepShaver
562 static sigsegv_address_t get_fault_address(struct sigcontext *scp)
563 {
564 unsigned int nip = (unsigned int) scp->MACH_FIELD_NAME(sc_ir);
565 unsigned int * gpr = &((unsigned int *) scp->MACH_FIELD_NAME(sc_regs))[2];
566 instruction_t instr;
567
568 powerpc_decode_instruction(&instr, nip, (long unsigned int*)gpr);
569 return (sigsegv_address_t)instr.addr;
570 }
571 #endif
572 #endif
573 #endif
574 #endif
575
576 #if HAVE_WIN32_EXCEPTIONS
577 #define WIN32_LEAN_AND_MEAN /* avoid including junk */
578 #include <windows.h>
579 #include <winerror.h>
580
581 #define SIGSEGV_FAULT_HANDLER_ARGLIST EXCEPTION_POINTERS *ExceptionInfo
582 #define SIGSEGV_FAULT_HANDLER_ARGS ExceptionInfo
583 #define SIGSEGV_FAULT_ADDRESS ExceptionInfo->ExceptionRecord->ExceptionInformation[1]
584 #define SIGSEGV_CONTEXT_REGS ExceptionInfo->ContextRecord
585 #if defined(_M_IX86)
586 #define SIGSEGV_FAULT_INSTRUCTION SIGSEGV_CONTEXT_REGS->Eip
587 #define SIGSEGV_REGISTER_FILE ((SIGSEGV_REGISTER_TYPE *)&SIGSEGV_CONTEXT_REGS->Edi)
588 #define SIGSEGV_SKIP_INSTRUCTION ix86_skip_instruction
589 #endif
590 #if defined(_M_X64)
591 #define SIGSEGV_FAULT_INSTRUCTION SIGSEGV_CONTEXT_REGS->Rip
592 #define SIGSEGV_REGISTER_FILE ((SIGSEGV_REGISTER_TYPE *)&SIGSEGV_CONTEXT_REGS->Rax)
593 #define SIGSEGV_SKIP_INSTRUCTION ix86_skip_instruction
594 #endif
595 #if defined(_M_IA64)
596 #define SIGSEGV_FAULT_INSTRUCTION SIGSEGV_CONTEXT_REGS->StIIP
597 #endif
598 #endif
599
600 #if HAVE_MACH_EXCEPTIONS
601
602 // This can easily be extended to other Mach systems, but really who
603 // uses HURD (oops GNU/HURD), Darwin/x86, NextStep, Rhapsody, or CMU
604 // Mach 2.5/3.0?
605 #if defined(__APPLE__) && defined(__MACH__)
606
607 #include <sys/types.h>
608 #include <stdlib.h>
609 #include <stdio.h>
610 #include <pthread.h>
611
612 /*
613 * If you are familiar with MIG then you will understand the frustration
614 * that was necessary to get these embedded into C++ code by hand.
615 */
616 extern "C" {
617 #include <mach/mach.h>
618 #include <mach/mach_error.h>
619
620 #ifndef HAVE_MACH64_VM
621
622 // Undefine this to prevent a preprocessor warning when compiling on a
623 // 32-bit machine with Mac OS X 10.5.
624 #undef MACH_EXCEPTION_CODES
625
626 #define MACH_EXCEPTION_CODES 0
627 #define mach_exception_data_t exception_data_t
628 #define mach_exception_data_type_t exception_data_type_t
629 #define mach_exc_server exc_server
630 #define catch_mach_exception_raise catch_exception_raise
631 #define mach_exception_raise exception_raise
632 #define mach_exception_raise_state exception_raise_state
633 #define mach_exception_raise_state_identity exception_raise_state_identity
634 #endif
635
636 extern boolean_t mach_exc_server(mach_msg_header_t *, mach_msg_header_t *);
637 extern kern_return_t catch_mach_exception_raise(mach_port_t, mach_port_t,
638 mach_port_t, exception_type_t, mach_exception_data_t, mach_msg_type_number_t);
639 extern kern_return_t catch_mach_exception_raise_state(mach_port_t exception_port,
640 exception_type_t exception, mach_exception_data_t code, mach_msg_type_number_t code_count,
641 int *flavor,
642 thread_state_t old_state, mach_msg_type_number_t old_state_count,
643 thread_state_t new_state, mach_msg_type_number_t *new_state_count);
644 extern kern_return_t catch_mach_exception_raise_state_identity(mach_port_t exception_port,
645 mach_port_t thread_port, mach_port_t task_port, exception_type_t exception,
646 mach_exception_data_t code, mach_msg_type_number_t code_count,
647 int *flavor,
648 thread_state_t old_state, mach_msg_type_number_t old_state_count,
649 thread_state_t new_state, mach_msg_type_number_t *new_state_count);
650 extern kern_return_t mach_exception_raise(mach_port_t, mach_port_t, mach_port_t,
651 exception_type_t, mach_exception_data_t, mach_msg_type_number_t);
652 extern kern_return_t mach_exception_raise_state(mach_port_t, exception_type_t,
653 mach_exception_data_t, mach_msg_type_number_t, thread_state_flavor_t *,
654 thread_state_t, mach_msg_type_number_t, thread_state_t, mach_msg_type_number_t *);
655 extern kern_return_t mach_exception_raise_state_identity(mach_port_t, mach_port_t, mach_port_t,
656 exception_type_t, mach_exception_data_t, mach_msg_type_number_t, thread_state_flavor_t *,
657 thread_state_t, mach_msg_type_number_t, thread_state_t, mach_msg_type_number_t *);
658 }
659
660 // Could make this dynamic by looking for a result of MIG_ARRAY_TOO_LARGE
661 #define HANDLER_COUNT 64
662
663 // structure to tuck away existing exception handlers
664 typedef struct _ExceptionPorts {
665 mach_msg_type_number_t maskCount;
666 exception_mask_t masks[HANDLER_COUNT];
667 exception_handler_t handlers[HANDLER_COUNT];
668 exception_behavior_t behaviors[HANDLER_COUNT];
669 thread_state_flavor_t flavors[HANDLER_COUNT];
670 } ExceptionPorts;
671
672 // exception handler thread
673 static pthread_t exc_thread;
674
675 // place where old exception handler info is stored
676 static ExceptionPorts ports;
677
678 // our exception port
679 static mach_port_t _exceptionPort = MACH_PORT_NULL;
680
681 #define MACH_CHECK_ERROR(name,ret) \
682 if (ret != KERN_SUCCESS) { \
683 mach_error(#name, ret); \
684 exit (1); \
685 }
686
687 #ifdef __ppc__
688 #if __DARWIN_UNIX03 && defined _STRUCT_PPC_THREAD_STATE
689 #define MACH_FIELD_NAME(X) __CONCAT(__,X)
690 #endif
691 #define SIGSEGV_EXCEPTION_STATE_TYPE ppc_exception_state_t
692 #define SIGSEGV_EXCEPTION_STATE_FLAVOR PPC_EXCEPTION_STATE
693 #define SIGSEGV_EXCEPTION_STATE_COUNT PPC_EXCEPTION_STATE_COUNT
694 #define SIGSEGV_FAULT_ADDRESS SIP->exc_state.MACH_FIELD_NAME(dar)
695 #define SIGSEGV_THREAD_STATE_TYPE ppc_thread_state_t
696 #define SIGSEGV_THREAD_STATE_FLAVOR PPC_THREAD_STATE
697 #define SIGSEGV_THREAD_STATE_COUNT PPC_THREAD_STATE_COUNT
698 #define SIGSEGV_FAULT_INSTRUCTION SIP->thr_state.MACH_FIELD_NAME(srr0)
699 #define SIGSEGV_SKIP_INSTRUCTION powerpc_skip_instruction
700 #define SIGSEGV_REGISTER_FILE (unsigned long *)&SIP->thr_state.MACH_FIELD_NAME(srr0), (unsigned long *)&SIP->thr_state.MACH_FIELD_NAME(r0)
701 #endif
702 #ifdef __ppc64__
703 #if __DARWIN_UNIX03 && defined _STRUCT_PPC_THREAD_STATE64
704 #define MACH_FIELD_NAME(X) __CONCAT(__,X)
705 #endif
706 #define SIGSEGV_EXCEPTION_STATE_TYPE ppc_exception_state64_t
707 #define SIGSEGV_EXCEPTION_STATE_FLAVOR PPC_EXCEPTION_STATE64
708 #define SIGSEGV_EXCEPTION_STATE_COUNT PPC_EXCEPTION_STATE64_COUNT
709 #define SIGSEGV_FAULT_ADDRESS SIP->exc_state.MACH_FIELD_NAME(dar)
710 #define SIGSEGV_THREAD_STATE_TYPE ppc_thread_state64_t
711 #define SIGSEGV_THREAD_STATE_FLAVOR PPC_THREAD_STATE64
712 #define SIGSEGV_THREAD_STATE_COUNT PPC_THREAD_STATE64_COUNT
713 #define SIGSEGV_FAULT_INSTRUCTION SIP->thr_state.MACH_FIELD_NAME(srr0)
714 #define SIGSEGV_SKIP_INSTRUCTION powerpc_skip_instruction
715 #define SIGSEGV_REGISTER_FILE (unsigned long *)&SIP->thr_state.MACH_FIELD_NAME(srr0), (unsigned long *)&SIP->thr_state.MACH_FIELD_NAME(r0)
716 #endif
717 #ifdef __i386__
718 #if __DARWIN_UNIX03 && defined _STRUCT_X86_THREAD_STATE32
719 #define MACH_FIELD_NAME(X) __CONCAT(__,X)
720 #endif
721 #define SIGSEGV_EXCEPTION_STATE_TYPE i386_exception_state_t
722 #define SIGSEGV_EXCEPTION_STATE_FLAVOR i386_EXCEPTION_STATE
723 #define SIGSEGV_EXCEPTION_STATE_COUNT i386_EXCEPTION_STATE_COUNT
724 #define SIGSEGV_FAULT_ADDRESS SIP->exc_state.MACH_FIELD_NAME(faultvaddr)
725 #define SIGSEGV_THREAD_STATE_TYPE i386_thread_state_t
726 #define SIGSEGV_THREAD_STATE_FLAVOR i386_THREAD_STATE
727 #define SIGSEGV_THREAD_STATE_COUNT i386_THREAD_STATE_COUNT
728 #define SIGSEGV_FAULT_INSTRUCTION SIP->thr_state.MACH_FIELD_NAME(eip)
729 #define SIGSEGV_SKIP_INSTRUCTION ix86_skip_instruction
730 #define SIGSEGV_REGISTER_FILE ((SIGSEGV_REGISTER_TYPE *)&SIP->thr_state.MACH_FIELD_NAME(eax)) /* EAX is the first GPR we consider */
731 #endif
732 #ifdef __x86_64__
733 #if __DARWIN_UNIX03 && defined _STRUCT_X86_THREAD_STATE64
734 #define MACH_FIELD_NAME(X) __CONCAT(__,X)
735 #endif
736 #define SIGSEGV_EXCEPTION_STATE_TYPE x86_exception_state64_t
737 #define SIGSEGV_EXCEPTION_STATE_FLAVOR x86_EXCEPTION_STATE64
738 #define SIGSEGV_EXCEPTION_STATE_COUNT x86_EXCEPTION_STATE64_COUNT
739 #define SIGSEGV_FAULT_ADDRESS SIP->exc_state.MACH_FIELD_NAME(faultvaddr)
740 #define SIGSEGV_THREAD_STATE_TYPE x86_thread_state64_t
741 #define SIGSEGV_THREAD_STATE_FLAVOR x86_THREAD_STATE64
742 #define SIGSEGV_THREAD_STATE_COUNT x86_THREAD_STATE64_COUNT
743 #define SIGSEGV_FAULT_INSTRUCTION SIP->thr_state.MACH_FIELD_NAME(rip)
744 #define SIGSEGV_SKIP_INSTRUCTION ix86_skip_instruction
745 #define SIGSEGV_REGISTER_FILE ((SIGSEGV_REGISTER_TYPE *)&SIP->thr_state.MACH_FIELD_NAME(rax)) /* RAX is the first GPR we consider */
746 #endif
747 #define SIGSEGV_FAULT_ADDRESS_FAST code[1]
748 #define SIGSEGV_FAULT_INSTRUCTION_FAST SIGSEGV_INVALID_ADDRESS
749 #define SIGSEGV_FAULT_HANDLER_ARGLIST mach_port_t thread, mach_exception_data_t code
750 #define SIGSEGV_FAULT_HANDLER_ARGS thread, code
751
752 #ifndef MACH_FIELD_NAME
753 #define MACH_FIELD_NAME(X) X
754 #endif
755
756 // Since there can only be one exception thread running at any time
757 // this is not a problem.
758 #define MSG_SIZE 512
759 static char msgbuf[MSG_SIZE];
760 static char replybuf[MSG_SIZE];
761
762 /*
763 * This is the entry point for the exception handler thread. The job
764 * of this thread is to wait for exception messages on the exception
765 * port that was setup beforehand and to pass them on to exc_server.
766 * exc_server is a MIG generated function that is a part of Mach.
767 * Its job is to decide what to do with the exception message. In our
768 * case exc_server calls catch_exception_raise on our behalf. After
769 * exc_server returns, it is our responsibility to send the reply.
770 */
771 static void *
772 handleExceptions(void *priv)
773 {
774 mach_msg_header_t *msg, *reply;
775 kern_return_t krc;
776
777 msg = (mach_msg_header_t *)msgbuf;
778 reply = (mach_msg_header_t *)replybuf;
779
780 for (;;) {
781 krc = mach_msg(msg, MACH_RCV_MSG, MSG_SIZE, MSG_SIZE,
782 _exceptionPort, 0, MACH_PORT_NULL);
783 MACH_CHECK_ERROR(mach_msg, krc);
784
785 if (!mach_exc_server(msg, reply)) {
786 fprintf(stderr, "exc_server hated the message\n");
787 exit(1);
788 }
789
790 krc = mach_msg(reply, MACH_SEND_MSG, reply->msgh_size, 0,
791 msg->msgh_local_port, 0, MACH_PORT_NULL);
792 if (krc != KERN_SUCCESS) {
793 fprintf(stderr, "Error sending message to original reply port, krc = %d, %s",
794 krc, mach_error_string(krc));
795 exit(1);
796 }
797 }
798 }
799 #endif
800 #endif
801
802
803 /*
804 * Instruction skipping
805 */
806
807 #ifndef SIGSEGV_REGISTER_TYPE
808 #define SIGSEGV_REGISTER_TYPE sigsegv_uintptr_t
809 #endif
810
811 #ifdef HAVE_SIGSEGV_SKIP_INSTRUCTION
812 // Decode and skip X86 instruction
813 #if (defined(i386) || defined(__i386__)) || (defined(__x86_64__) || defined(_M_X64))
814 #if defined(__linux__)
815 enum {
816 #if (defined(i386) || defined(__i386__))
817 X86_REG_EIP = 14,
818 X86_REG_EAX = 11,
819 X86_REG_ECX = 10,
820 X86_REG_EDX = 9,
821 X86_REG_EBX = 8,
822 X86_REG_ESP = 7,
823 X86_REG_EBP = 6,
824 X86_REG_ESI = 5,
825 X86_REG_EDI = 4
826 #endif
827 #if defined(__x86_64__)
828 X86_REG_R8 = 0,
829 X86_REG_R9 = 1,
830 X86_REG_R10 = 2,
831 X86_REG_R11 = 3,
832 X86_REG_R12 = 4,
833 X86_REG_R13 = 5,
834 X86_REG_R14 = 6,
835 X86_REG_R15 = 7,
836 X86_REG_EDI = 8,
837 X86_REG_ESI = 9,
838 X86_REG_EBP = 10,
839 X86_REG_EBX = 11,
840 X86_REG_EDX = 12,
841 X86_REG_EAX = 13,
842 X86_REG_ECX = 14,
843 X86_REG_ESP = 15,
844 X86_REG_EIP = 16
845 #endif
846 };
847 #endif
848 #if defined(__NetBSD__)
849 enum {
850 #if (defined(i386) || defined(__i386__))
851 X86_REG_EIP = _REG_EIP,
852 X86_REG_EAX = _REG_EAX,
853 X86_REG_ECX = _REG_ECX,
854 X86_REG_EDX = _REG_EDX,
855 X86_REG_EBX = _REG_EBX,
856 X86_REG_ESP = _REG_ESP,
857 X86_REG_EBP = _REG_EBP,
858 X86_REG_ESI = _REG_ESI,
859 X86_REG_EDI = _REG_EDI
860 #endif
861 };
862 #endif
863 #if defined(__FreeBSD__)
864 enum {
865 #if (defined(i386) || defined(__i386__))
866 X86_REG_EIP = 10,
867 X86_REG_EAX = 7,
868 X86_REG_ECX = 6,
869 X86_REG_EDX = 5,
870 X86_REG_EBX = 4,
871 X86_REG_ESP = 13,
872 X86_REG_EBP = 2,
873 X86_REG_ESI = 1,
874 X86_REG_EDI = 0
875 #endif
876 };
877 #endif
878 #if defined(__OpenBSD__)
879 enum {
880 #if defined(__i386__)
881 // EDI is the first register we consider
882 #define OREG(REG) offsetof(struct sigcontext, sc_##REG)
883 #define DREG(REG) ((OREG(REG) - OREG(edi)) / 4)
884 X86_REG_EIP = DREG(eip), // 7
885 X86_REG_EAX = DREG(eax), // 6
886 X86_REG_ECX = DREG(ecx), // 5
887 X86_REG_EDX = DREG(edx), // 4
888 X86_REG_EBX = DREG(ebx), // 3
889 X86_REG_ESP = DREG(esp), // 10
890 X86_REG_EBP = DREG(ebp), // 2
891 X86_REG_ESI = DREG(esi), // 1
892 X86_REG_EDI = DREG(edi) // 0
893 #undef DREG
894 #undef OREG
895 #endif
896 };
897 #endif
898 #if defined(__sun__)
899 // Same as for Linux, need to check for x86-64
900 enum {
901 #if defined(__i386__)
902 X86_REG_EIP = EIP,
903 X86_REG_EAX = EAX,
904 X86_REG_ECX = ECX,
905 X86_REG_EDX = EDX,
906 X86_REG_EBX = EBX,
907 X86_REG_ESP = ESP,
908 X86_REG_EBP = EBP,
909 X86_REG_ESI = ESI,
910 X86_REG_EDI = EDI
911 #endif
912 };
913 #endif
914 #if defined(__APPLE__) && defined(__MACH__)
915 enum {
916 #if (defined(i386) || defined(__i386__))
917 #ifdef i386_SAVED_STATE
918 // same as FreeBSD (in Open Darwin 8.0.1)
919 X86_REG_EIP = 10,
920 X86_REG_EAX = 7,
921 X86_REG_ECX = 6,
922 X86_REG_EDX = 5,
923 X86_REG_EBX = 4,
924 X86_REG_ESP = 13,
925 X86_REG_EBP = 2,
926 X86_REG_ESI = 1,
927 X86_REG_EDI = 0
928 #else
929 // new layout (MacOS X 10.4.4 for x86)
930 X86_REG_EIP = 10,
931 X86_REG_EAX = 0,
932 X86_REG_ECX = 2,
933 X86_REG_EDX = 3,
934 X86_REG_EBX = 1,
935 X86_REG_ESP = 7,
936 X86_REG_EBP = 6,
937 X86_REG_ESI = 5,
938 X86_REG_EDI = 4
939 #endif
940 #endif
941 #if defined(__x86_64__)
942 X86_REG_R8 = 8,
943 X86_REG_R9 = 9,
944 X86_REG_R10 = 10,
945 X86_REG_R11 = 11,
946 X86_REG_R12 = 12,
947 X86_REG_R13 = 13,
948 X86_REG_R14 = 14,
949 X86_REG_R15 = 15,
950 X86_REG_EDI = 4,
951 X86_REG_ESI = 5,
952 X86_REG_EBP = 6,
953 X86_REG_EBX = 1,
954 X86_REG_EDX = 3,
955 X86_REG_EAX = 0,
956 X86_REG_ECX = 2,
957 X86_REG_ESP = 7,
958 X86_REG_EIP = 16
959 #endif
960 };
961 #endif
962 #if defined(_WIN32)
963 enum {
964 #if defined(_M_IX86)
965 X86_REG_EIP = 7,
966 X86_REG_EAX = 5,
967 X86_REG_ECX = 4,
968 X86_REG_EDX = 3,
969 X86_REG_EBX = 2,
970 X86_REG_ESP = 10,
971 X86_REG_EBP = 6,
972 X86_REG_ESI = 1,
973 X86_REG_EDI = 0
974 #endif
975 #if defined(_M_X64)
976 X86_REG_EAX = 0,
977 X86_REG_ECX = 1,
978 X86_REG_EDX = 2,
979 X86_REG_EBX = 3,
980 X86_REG_ESP = 4,
981 X86_REG_EBP = 5,
982 X86_REG_ESI = 6,
983 X86_REG_EDI = 7,
984 X86_REG_R8 = 8,
985 X86_REG_R9 = 9,
986 X86_REG_R10 = 10,
987 X86_REG_R11 = 11,
988 X86_REG_R12 = 12,
989 X86_REG_R13 = 13,
990 X86_REG_R14 = 14,
991 X86_REG_R15 = 15,
992 X86_REG_EIP = 16
993 #endif
994 };
995 #endif
996 // FIXME: this is partly redundant with the instruction decoding phase
997 // to discover transfer type and register number
998 static inline int ix86_step_over_modrm(unsigned char * p)
999 {
1000 int mod = (p[0] >> 6) & 3;
1001 int rm = p[0] & 7;
1002 int offset = 0;
1003
1004 // ModR/M Byte
1005 switch (mod) {
1006 case 0: // [reg]
1007 if (rm == 5) return 4; // disp32
1008 break;
1009 case 1: // disp8[reg]
1010 offset = 1;
1011 break;
1012 case 2: // disp32[reg]
1013 offset = 4;
1014 break;
1015 case 3: // register
1016 return 0;
1017 }
1018
1019 // SIB Byte
1020 if (rm == 4) {
1021 if (mod == 0 && (p[1] & 7) == 5)
1022 offset = 5; // disp32[index]
1023 else
1024 offset++;
1025 }
1026
1027 return offset;
1028 }
1029
1030 static bool ix86_skip_instruction(SIGSEGV_REGISTER_TYPE * regs)
1031 {
1032 unsigned char * eip = (unsigned char *)regs[X86_REG_EIP];
1033
1034 if (eip == 0)
1035 return false;
1036 #ifdef _WIN32
1037 if (IsBadCodePtr((FARPROC)eip))
1038 return false;
1039 #endif
1040
1041 enum instruction_type_t {
1042 i_MOV,
1043 i_ADD
1044 };
1045
1046 transfer_type_t transfer_type = SIGSEGV_TRANSFER_UNKNOWN;
1047 transfer_size_t transfer_size = SIZE_LONG;
1048 instruction_type_t instruction_type = i_MOV;
1049
1050 int reg = -1;
1051 int len = 0;
1052
1053 #if DEBUG
1054 printf("IP: %p [%02x %02x %02x %02x...]\n",
1055 eip, eip[0], eip[1], eip[2], eip[3]);
1056 #endif
1057
1058 // Operand size prefix
1059 if (*eip == 0x66) {
1060 eip++;
1061 len++;
1062 transfer_size = SIZE_WORD;
1063 }
1064
1065 // REX prefix
1066 #if defined(__x86_64__) || defined(_M_X64)
1067 struct rex_t {
1068 unsigned char W;
1069 unsigned char R;
1070 unsigned char X;
1071 unsigned char B;
1072 };
1073 rex_t rex = { 0, 0, 0, 0 };
1074 bool has_rex = false;
1075 if ((*eip & 0xf0) == 0x40) {
1076 has_rex = true;
1077 const unsigned char b = *eip;
1078 rex.W = b & (1 << 3);
1079 rex.R = b & (1 << 2);
1080 rex.X = b & (1 << 1);
1081 rex.B = b & (1 << 0);
1082 #if DEBUG
1083 printf("REX: %c,%c,%c,%c\n",
1084 rex.W ? 'W' : '_',
1085 rex.R ? 'R' : '_',
1086 rex.X ? 'X' : '_',
1087 rex.B ? 'B' : '_');
1088 #endif
1089 eip++;
1090 len++;
1091 if (rex.W)
1092 transfer_size = SIZE_QUAD;
1093 }
1094 #else
1095 const bool has_rex = false;
1096 #endif
1097
1098 // Decode instruction
1099 int op_len = 1;
1100 int target_size = SIZE_UNKNOWN;
1101 switch (eip[0]) {
1102 case 0x0f:
1103 target_size = transfer_size;
1104 switch (eip[1]) {
1105 case 0xbe: // MOVSX r32, r/m8
1106 case 0xb6: // MOVZX r32, r/m8
1107 transfer_size = SIZE_BYTE;
1108 goto do_mov_extend;
1109 case 0xbf: // MOVSX r32, r/m16
1110 case 0xb7: // MOVZX r32, r/m16
1111 transfer_size = SIZE_WORD;
1112 goto do_mov_extend;
1113 do_mov_extend:
1114 op_len = 2;
1115 goto do_transfer_load;
1116 }
1117 break;
1118 #if defined(__x86_64__) || defined(_M_X64)
1119 case 0x63: // MOVSXD r64, r/m32
1120 if (has_rex && rex.W) {
1121 transfer_size = SIZE_LONG;
1122 target_size = SIZE_QUAD;
1123 }
1124 else if (transfer_size != SIZE_WORD) {
1125 transfer_size = SIZE_LONG;
1126 target_size = SIZE_QUAD;
1127 }
1128 goto do_transfer_load;
1129 #endif
1130 case 0x02: // ADD r8, r/m8
1131 transfer_size = SIZE_BYTE;
1132 case 0x03: // ADD r32, r/m32
1133 instruction_type = i_ADD;
1134 goto do_transfer_load;
1135 case 0x8a: // MOV r8, r/m8
1136 transfer_size = SIZE_BYTE;
1137 case 0x8b: // MOV r32, r/m32 (or 16-bit operation)
1138 do_transfer_load:
1139 switch (eip[op_len] & 0xc0) {
1140 case 0x80:
1141 reg = (eip[op_len] >> 3) & 7;
1142 transfer_type = SIGSEGV_TRANSFER_LOAD;
1143 break;
1144 case 0x40:
1145 reg = (eip[op_len] >> 3) & 7;
1146 transfer_type = SIGSEGV_TRANSFER_LOAD;
1147 break;
1148 case 0x00:
1149 reg = (eip[op_len] >> 3) & 7;
1150 transfer_type = SIGSEGV_TRANSFER_LOAD;
1151 break;
1152 }
1153 len += 1 + op_len + ix86_step_over_modrm(eip + op_len);
1154 break;
1155 case 0x00: // ADD r/m8, r8
1156 transfer_size = SIZE_BYTE;
1157 case 0x01: // ADD r/m32, r32
1158 instruction_type = i_ADD;
1159 goto do_transfer_store;
1160 case 0x88: // MOV r/m8, r8
1161 transfer_size = SIZE_BYTE;
1162 case 0x89: // MOV r/m32, r32 (or 16-bit operation)
1163 do_transfer_store:
1164 switch (eip[op_len] & 0xc0) {
1165 case 0x80:
1166 reg = (eip[op_len] >> 3) & 7;
1167 transfer_type = SIGSEGV_TRANSFER_STORE;
1168 break;
1169 case 0x40:
1170 reg = (eip[op_len] >> 3) & 7;
1171 transfer_type = SIGSEGV_TRANSFER_STORE;
1172 break;
1173 case 0x00:
1174 reg = (eip[op_len] >> 3) & 7;
1175 transfer_type = SIGSEGV_TRANSFER_STORE;
1176 break;
1177 }
1178 len += 1 + op_len + ix86_step_over_modrm(eip + op_len);
1179 break;
1180 }
1181 if (target_size == SIZE_UNKNOWN)
1182 target_size = transfer_size;
1183
1184 if (transfer_type == SIGSEGV_TRANSFER_UNKNOWN) {
1185 // Unknown machine code, let it crash. Then patch the decoder
1186 return false;
1187 }
1188
1189 #if defined(__x86_64__) || defined(_M_X64)
1190 if (rex.R)
1191 reg += 8;
1192 #endif
1193
1194 if (instruction_type == i_MOV && transfer_type == SIGSEGV_TRANSFER_LOAD && reg != -1) {
1195 static const int x86_reg_map[] = {
1196 X86_REG_EAX, X86_REG_ECX, X86_REG_EDX, X86_REG_EBX,
1197 X86_REG_ESP, X86_REG_EBP, X86_REG_ESI, X86_REG_EDI,
1198 #if defined(__x86_64__) || defined(_M_X64)
1199 X86_REG_R8, X86_REG_R9, X86_REG_R10, X86_REG_R11,
1200 X86_REG_R12, X86_REG_R13, X86_REG_R14, X86_REG_R15,
1201 #endif
1202 };
1203
1204 if (reg < 0 || reg >= (sizeof(x86_reg_map)/sizeof(x86_reg_map[0]) - 1))
1205 return false;
1206
1207 // Set 0 to the relevant register part
1208 // NOTE: this is only valid for MOV alike instructions
1209 int rloc = x86_reg_map[reg];
1210 switch (target_size) {
1211 case SIZE_BYTE:
1212 if (has_rex || reg < 4)
1213 regs[rloc] = (regs[rloc] & ~0x00ffL);
1214 else {
1215 rloc = x86_reg_map[reg - 4];
1216 regs[rloc] = (regs[rloc] & ~0xff00L);
1217 }
1218 break;
1219 case SIZE_WORD:
1220 regs[rloc] = (regs[rloc] & ~0xffffL);
1221 break;
1222 case SIZE_LONG:
1223 case SIZE_QUAD: // zero-extension
1224 regs[rloc] = 0;
1225 break;
1226 }
1227 }
1228
1229 #if DEBUG
1230 printf("%p: %s %s access", (void *)regs[X86_REG_EIP],
1231 transfer_size == SIZE_BYTE ? "byte" :
1232 transfer_size == SIZE_WORD ? "word" :
1233 transfer_size == SIZE_LONG ? "long" :
1234 transfer_size == SIZE_QUAD ? "quad" : "unknown",
1235 transfer_type == SIGSEGV_TRANSFER_LOAD ? "read" : "write");
1236
1237 if (reg != -1) {
1238 static const char * x86_byte_reg_str_map[] = {
1239 "al", "cl", "dl", "bl",
1240 "spl", "bpl", "sil", "dil",
1241 "r8b", "r9b", "r10b", "r11b",
1242 "r12b", "r13b", "r14b", "r15b",
1243 "ah", "ch", "dh", "bh",
1244 };
1245 static const char * x86_word_reg_str_map[] = {
1246 "ax", "cx", "dx", "bx",
1247 "sp", "bp", "si", "di",
1248 "r8w", "r9w", "r10w", "r11w",
1249 "r12w", "r13w", "r14w", "r15w",
1250 };
1251 static const char *x86_long_reg_str_map[] = {
1252 "eax", "ecx", "edx", "ebx",
1253 "esp", "ebp", "esi", "edi",
1254 "r8d", "r9d", "r10d", "r11d",
1255 "r12d", "r13d", "r14d", "r15d",
1256 };
1257 static const char *x86_quad_reg_str_map[] = {
1258 "rax", "rcx", "rdx", "rbx",
1259 "rsp", "rbp", "rsi", "rdi",
1260 "r8", "r9", "r10", "r11",
1261 "r12", "r13", "r14", "r15",
1262 };
1263 const char * reg_str = NULL;
1264 switch (target_size) {
1265 case SIZE_BYTE:
1266 reg_str = x86_byte_reg_str_map[(!has_rex && reg >= 4 ? 12 : 0) + reg];
1267 break;
1268 case SIZE_WORD: reg_str = x86_word_reg_str_map[reg]; break;
1269 case SIZE_LONG: reg_str = x86_long_reg_str_map[reg]; break;
1270 case SIZE_QUAD: reg_str = x86_quad_reg_str_map[reg]; break;
1271 }
1272 if (reg_str)
1273 printf(" %s register %%%s",
1274 transfer_type == SIGSEGV_TRANSFER_LOAD ? "to" : "from",
1275 reg_str);
1276 }
1277 printf(", %d bytes instruction\n", len);
1278 #endif
1279
1280 regs[X86_REG_EIP] += len;
1281 return true;
1282 }
1283 #endif
1284
1285 // Decode and skip IA-64 instruction
1286 #if defined(__ia64) || defined(__ia64__)
1287 typedef uint64_t ia64_bundle_t[2];
1288 #if defined(__linux__)
1289 // We can directly patch the slot number
1290 #define IA64_CAN_PATCH_IP_SLOT 1
1291 // Helper macros to access the machine context
1292 #define IA64_CONTEXT_TYPE struct sigcontext *
1293 #define IA64_CONTEXT scp
1294 #define IA64_GET_IP() (IA64_CONTEXT->sc_ip)
1295 #define IA64_SET_IP(V) (IA64_CONTEXT->sc_ip = (V))
1296 #define IA64_GET_PR(P) ((IA64_CONTEXT->sc_pr >> (P)) & 1)
1297 #define IA64_GET_NAT(I) ((IA64_CONTEXT->sc_nat >> (I)) & 1)
1298 #define IA64_GET_GR(R) (IA64_CONTEXT->sc_gr[(R)])
1299 #define _IA64_SET_GR(R,V) (IA64_CONTEXT->sc_gr[(R)] = (V))
1300 #define _IA64_SET_NAT(I,V) (IA64_CONTEXT->sc_nat = (IA64_CONTEXT->sc_nat & ~(1ull << (I))) | (((uint64_t)!!(V)) << (I)))
1301 #define IA64_SET_GR(R,V,N) (_IA64_SET_GR(R,V), _IA64_SET_NAT(R,N))
1302
1303 // Load bundle (in little-endian)
1304 static inline void ia64_load_bundle(ia64_bundle_t bundle, uint64_t raw_ip)
1305 {
1306 uint64_t *ip = (uint64_t *)(raw_ip & ~3ull);
1307 bundle[0] = ip[0];
1308 bundle[1] = ip[1];
1309 }
1310 #endif
1311 #if defined(__hpux) || defined(__hpux__)
1312 // We can directly patch the slot number
1313 #define IA64_CAN_PATCH_IP_SLOT 1
1314 // Helper macros to access the machine context
1315 #define IA64_CONTEXT_TYPE ucontext_t *
1316 #define IA64_CONTEXT ucp
1317 #define IA64_GET_IP() ia64_get_ip(IA64_CONTEXT)
1318 #define IA64_SET_IP(V) ia64_set_ip(IA64_CONTEXT, V)
1319 #define IA64_GET_PR(P) ia64_get_pr(IA64_CONTEXT, P)
1320 #define IA64_GET_NAT(I) ia64_get_nat(IA64_CONTEXT, I)
1321 #define IA64_GET_GR(R) ia64_get_gr(IA64_CONTEXT, R)
1322 #define IA64_SET_GR(R,V,N) ia64_set_gr(IA64_CONTEXT, R, V, N)
1323 #define UC_ACCESS(FUNC,ARGS) do { if (__uc_##FUNC ARGS != 0) abort(); } while (0)
1324
1325 static inline uint64_t ia64_get_ip(IA64_CONTEXT_TYPE IA64_CONTEXT)
1326 { uint64_t v; UC_ACCESS(get_ip,(IA64_CONTEXT, &v)); return v; }
1327 static inline void ia64_set_ip(IA64_CONTEXT_TYPE IA64_CONTEXT, uint64_t v)
1328 { UC_ACCESS(set_ip,(IA64_CONTEXT, v)); }
1329 static inline unsigned int ia64_get_pr(IA64_CONTEXT_TYPE IA64_CONTEXT, int pr)
1330 { uint64_t v; UC_ACCESS(get_prs,(IA64_CONTEXT, &v)); return (v >> pr) & 1; }
1331 static inline unsigned int ia64_get_nat(IA64_CONTEXT_TYPE IA64_CONTEXT, int r)
1332 { uint64_t v; unsigned int nat; UC_ACCESS(get_grs,(IA64_CONTEXT, r, 1, &v, &nat)); return (nat >> r) & 1; }
1333 static inline uint64_t ia64_get_gr(IA64_CONTEXT_TYPE IA64_CONTEXT, int r)
1334 { uint64_t v; unsigned int nat; UC_ACCESS(get_grs,(IA64_CONTEXT, r, 1, &v, &nat)); return v; }
1335
1336 static void ia64_set_gr(IA64_CONTEXT_TYPE IA64_CONTEXT, int r, uint64_t v, unsigned int nat)
1337 {
1338 if (r == 0)
1339 return;
1340 if (r > 0 && r < 32)
1341 UC_ACCESS(set_grs,(IA64_CONTEXT, r, 1, &v, (!!nat) << r));
1342 else {
1343 uint64_t bsp, bspstore;
1344 UC_ACCESS(get_ar_bsp,(IA64_CONTEXT, &bsp));
1345 UC_ACCESS(get_ar_bspstore,(IA64_CONTEXT, &bspstore));
1346 abort(); /* XXX: use libunwind, this is not fun... */
1347 }
1348 }
1349
1350 // Byte-swapping
1351 #if defined(__GNUC__)
1352 #define BSWAP64(V) ({ uint64_t r; __asm__ __volatile__("mux1 %0=%1,@rev;;" : "=r" (r) : "r" (V)); r; })
1353 #elif defined (__HP_aCC)
1354 #define BSWAP64(V) _Asm_mux1(_MBTYPE_REV, V)
1355 #else
1356 #error "Define byte-swap instruction"
1357 #endif
1358
1359 // Load bundle (in little-endian)
1360 static inline void ia64_load_bundle(ia64_bundle_t bundle, uint64_t raw_ip)
1361 {
1362 uint64_t *ip = (uint64_t *)(raw_ip & ~3ull);
1363 bundle[0] = BSWAP64(ip[0]);
1364 bundle[1] = BSWAP64(ip[1]);
1365 }
1366 #endif
1367
1368 // Instruction operations
1369 enum {
1370 IA64_INST_UNKNOWN = 0,
1371 IA64_INST_LD1, // ld1 op0=[op1]
1372 IA64_INST_LD1_UPDATE, // ld1 op0=[op1],op2
1373 IA64_INST_LD2, // ld2 op0=[op1]
1374 IA64_INST_LD2_UPDATE, // ld2 op0=[op1],op2
1375 IA64_INST_LD4, // ld4 op0=[op1]
1376 IA64_INST_LD4_UPDATE, // ld4 op0=[op1],op2
1377 IA64_INST_LD8, // ld8 op0=[op1]
1378 IA64_INST_LD8_UPDATE, // ld8 op0=[op1],op2
1379 IA64_INST_ST1, // st1 [op0]=op1
1380 IA64_INST_ST1_UPDATE, // st1 [op0]=op1,op2
1381 IA64_INST_ST2, // st2 [op0]=op1
1382 IA64_INST_ST2_UPDATE, // st2 [op0]=op1,op2
1383 IA64_INST_ST4, // st4 [op0]=op1
1384 IA64_INST_ST4_UPDATE, // st4 [op0]=op1,op2
1385 IA64_INST_ST8, // st8 [op0]=op1
1386 IA64_INST_ST8_UPDATE, // st8 [op0]=op1,op2
1387 IA64_INST_ADD, // add op0=op1,op2,op3
1388 IA64_INST_SUB, // sub op0=op1,op2,op3
1389 IA64_INST_SHLADD, // shladd op0=op1,op3,op2
1390 IA64_INST_AND, // and op0=op1,op2
1391 IA64_INST_ANDCM, // andcm op0=op1,op2
1392 IA64_INST_OR, // or op0=op1,op2
1393 IA64_INST_XOR, // xor op0=op1,op2
1394 IA64_INST_SXT1, // sxt1 op0=op1
1395 IA64_INST_SXT2, // sxt2 op0=op1
1396 IA64_INST_SXT4, // sxt4 op0=op1
1397 IA64_INST_ZXT1, // zxt1 op0=op1
1398 IA64_INST_ZXT2, // zxt2 op0=op1
1399 IA64_INST_ZXT4, // zxt4 op0=op1
1400 IA64_INST_NOP // nop op0
1401 };
1402
1403 const int IA64_N_OPERANDS = 4;
1404
1405 // Decoded operand type
1406 struct ia64_operand_t {
1407 uint8_t commit; // commit result of operation to register file?
1408 uint8_t valid; // XXX: not really used, can be removed (debug)
1409 int8_t index; // index of GPR, or -1 if immediate value
1410 uint8_t nat; // NaT state before operation
1411 uint64_t value; // register contents or immediate value
1412 };
1413
1414 // Decoded instruction type
1415 struct ia64_instruction_t {
1416 uint8_t mnemo; // operation to perform
1417 uint8_t pred; // predicate register to check
1418 uint8_t no_memory; // used to emulated main fault instruction
1419 uint64_t inst; // the raw instruction bits (41-bit wide)
1420 ia64_operand_t operands[IA64_N_OPERANDS];
1421 };
1422
1423 // Get immediate sign-bit
1424 static inline int ia64_inst_get_sbit(uint64_t inst)
1425 {
1426 return (inst >> 36) & 1;
1427 }
1428
1429 // Get 8-bit immediate value (A3, A8, I27, M30)
1430 static inline uint64_t ia64_inst_get_imm8(uint64_t inst)
1431 {
1432 uint64_t value = (inst >> 13) & 0x7full;
1433 if (ia64_inst_get_sbit(inst))
1434 value |= ~0x7full;
1435 return value;
1436 }
1437
1438 // Get 9-bit immediate value (M3)
1439 static inline uint64_t ia64_inst_get_imm9b(uint64_t inst)
1440 {
1441 uint64_t value = (((inst >> 27) & 1) << 7) | ((inst >> 13) & 0x7f);
1442 if (ia64_inst_get_sbit(inst))
1443 value |= ~0xffull;
1444 return value;
1445 }
1446
1447 // Get 9-bit immediate value (M5)
1448 static inline uint64_t ia64_inst_get_imm9a(uint64_t inst)
1449 {
1450 uint64_t value = (((inst >> 27) & 1) << 7) | ((inst >> 6) & 0x7f);
1451 if (ia64_inst_get_sbit(inst))
1452 value |= ~0xffull;
1453 return value;
1454 }
1455
1456 // Get 14-bit immediate value (A4)
1457 static inline uint64_t ia64_inst_get_imm14(uint64_t inst)
1458 {
1459 uint64_t value = (((inst >> 27) & 0x3f) << 7) | (inst & 0x7f);
1460 if (ia64_inst_get_sbit(inst))
1461 value |= ~0x1ffull;
1462 return value;
1463 }
1464
1465 // Get 22-bit immediate value (A5)
1466 static inline uint64_t ia64_inst_get_imm22(uint64_t inst)
1467 {
1468 uint64_t value = ((((inst >> 22) & 0x1f) << 16) |
1469 (((inst >> 27) & 0x1ff) << 7) |
1470 (inst & 0x7f));
1471 if (ia64_inst_get_sbit(inst))
1472 value |= ~0x1fffffull;
1473 return value;
1474 }
1475
1476 // Get 21-bit immediate value (I19)
1477 static inline uint64_t ia64_inst_get_imm21(uint64_t inst)
1478 {
1479 return (((inst >> 36) & 1) << 20) | ((inst >> 6) & 0xfffff);
1480 }
1481
1482 // Get 2-bit count value (A2)
1483 static inline int ia64_inst_get_count2(uint64_t inst)
1484 {
1485 return (inst >> 27) & 0x3;
1486 }
1487
1488 // Get bundle template
1489 static inline unsigned int ia64_get_template(uint64_t ip)
1490 {
1491 ia64_bundle_t bundle;
1492 ia64_load_bundle(bundle, ip);
1493 return bundle[0] & 0x1f;
1494 }
1495
1496 // Get specified instruction in bundle
1497 static uint64_t ia64_get_instruction(uint64_t ip, int slot)
1498 {
1499 uint64_t inst;
1500 ia64_bundle_t bundle;
1501 ia64_load_bundle(bundle, ip);
1502 #if DEBUG
1503 printf("Bundle: %016llx%016llx\n", bundle[1], bundle[0]);
1504 #endif
1505
1506 switch (slot) {
1507 case 0:
1508 inst = (bundle[0] >> 5) & 0x1ffffffffffull;
1509 break;
1510 case 1:
1511 inst = ((bundle[1] & 0x7fffffull) << 18) | ((bundle[0] >> 46) & 0x3ffffull);
1512 break;
1513 case 2:
1514 inst = (bundle[1] >> 23) & 0x1ffffffffffull;
1515 break;
1516 case 3:
1517 fprintf(stderr, "ERROR: ia64_get_instruction(), invalid slot number %d\n", slot);
1518 abort();
1519 break;
1520 }
1521
1522 #if DEBUG
1523 printf(" Instruction %d: 0x%016llx\n", slot, inst);
1524 #endif
1525 return inst;
1526 }
1527
1528 // Decode group 0 instructions
1529 static bool ia64_decode_instruction_0(ia64_instruction_t *inst, IA64_CONTEXT_TYPE IA64_CONTEXT)
1530 {
1531 const int r1 = (inst->inst >> 6) & 0x7f;
1532 const int r3 = (inst->inst >> 20) & 0x7f;
1533
1534 const int x3 = (inst->inst >> 33) & 0x07;
1535 const int x6 = (inst->inst >> 27) & 0x3f;
1536 const int x2 = (inst->inst >> 31) & 0x03;
1537 const int x4 = (inst->inst >> 27) & 0x0f;
1538
1539 if (x3 == 0) {
1540 switch (x6) {
1541 case 0x01: // nop.i (I19)
1542 inst->mnemo = IA64_INST_NOP;
1543 inst->operands[0].valid = true;
1544 inst->operands[0].index = -1;
1545 inst->operands[0].value = ia64_inst_get_imm21(inst->inst);
1546 return true;
1547 case 0x14: // sxt1 (I29)
1548 case 0x15: // sxt2 (I29)
1549 case 0x16: // sxt4 (I29)
1550 case 0x10: // zxt1 (I29)
1551 case 0x11: // zxt2 (I29)
1552 case 0x12: // zxt4 (I29)
1553 switch (x6) {
1554 case 0x14: inst->mnemo = IA64_INST_SXT1; break;
1555 case 0x15: inst->mnemo = IA64_INST_SXT2; break;
1556 case 0x16: inst->mnemo = IA64_INST_SXT4; break;
1557 case 0x10: inst->mnemo = IA64_INST_ZXT1; break;
1558 case 0x11: inst->mnemo = IA64_INST_ZXT2; break;
1559 case 0x12: inst->mnemo = IA64_INST_ZXT4; break;
1560 default: abort();
1561 }
1562 inst->operands[0].valid = true;
1563 inst->operands[0].index = r1;
1564 inst->operands[1].valid = true;
1565 inst->operands[1].index = r3;
1566 inst->operands[1].value = IA64_GET_GR(r3);
1567 inst->operands[1].nat = IA64_GET_NAT(r3);
1568 return true;
1569 }
1570 }
1571 return false;
1572 }
1573
1574 // Decode group 4 instructions (load/store instructions)
1575 static bool ia64_decode_instruction_4(ia64_instruction_t *inst, IA64_CONTEXT_TYPE IA64_CONTEXT)
1576 {
1577 const int r1 = (inst->inst >> 6) & 0x7f;
1578 const int r2 = (inst->inst >> 13) & 0x7f;
1579 const int r3 = (inst->inst >> 20) & 0x7f;
1580
1581 const int m = (inst->inst >> 36) & 1;
1582 const int x = (inst->inst >> 27) & 1;
1583 const int x6 = (inst->inst >> 30) & 0x3f;
1584
1585 switch (x6) {
1586 case 0x00:
1587 case 0x01:
1588 case 0x02:
1589 case 0x03:
1590 if (x == 0) {
1591 inst->operands[0].valid = true;
1592 inst->operands[0].index = r1;
1593 inst->operands[1].valid = true;
1594 inst->operands[1].index = r3;
1595 inst->operands[1].value = IA64_GET_GR(r3);
1596 inst->operands[1].nat = IA64_GET_NAT(r3);
1597 if (m == 0) {
1598 switch (x6) {
1599 case 0x00: inst->mnemo = IA64_INST_LD1; break;
1600 case 0x01: inst->mnemo = IA64_INST_LD2; break;
1601 case 0x02: inst->mnemo = IA64_INST_LD4; break;
1602 case 0x03: inst->mnemo = IA64_INST_LD8; break;
1603 }
1604 }
1605 else {
1606 inst->operands[2].valid = true;
1607 inst->operands[2].index = r2;
1608 inst->operands[2].value = IA64_GET_GR(r2);
1609 inst->operands[2].nat = IA64_GET_NAT(r2);
1610 switch (x6) {
1611 case 0x00: inst->mnemo = IA64_INST_LD1_UPDATE; break;
1612 case 0x01: inst->mnemo = IA64_INST_LD2_UPDATE; break;
1613 case 0x02: inst->mnemo = IA64_INST_LD4_UPDATE; break;
1614 case 0x03: inst->mnemo = IA64_INST_LD8_UPDATE; break;
1615 }
1616 }
1617 return true;
1618 }
1619 break;
1620 case 0x30:
1621 case 0x31:
1622 case 0x32:
1623 case 0x33:
1624 if (m == 0 && x == 0) {
1625 inst->operands[0].valid = true;
1626 inst->operands[0].index = r3;
1627 inst->operands[0].value = IA64_GET_GR(r3);
1628 inst->operands[0].nat = IA64_GET_NAT(r3);
1629 inst->operands[1].valid = true;
1630 inst->operands[1].index = r2;
1631 inst->operands[1].value = IA64_GET_GR(r2);
1632 inst->operands[1].nat = IA64_GET_NAT(r2);
1633 switch (x6) {
1634 case 0x30: inst->mnemo = IA64_INST_ST1; break;
1635 case 0x31: inst->mnemo = IA64_INST_ST2; break;
1636 case 0x32: inst->mnemo = IA64_INST_ST4; break;
1637 case 0x33: inst->mnemo = IA64_INST_ST8; break;
1638 }
1639 return true;
1640 }
1641 break;
1642 }
1643 return false;
1644 }
1645
1646 // Decode group 5 instructions (load/store instructions)
1647 static bool ia64_decode_instruction_5(ia64_instruction_t *inst, IA64_CONTEXT_TYPE IA64_CONTEXT)
1648 {
1649 const int r1 = (inst->inst >> 6) & 0x7f;
1650 const int r2 = (inst->inst >> 13) & 0x7f;
1651 const int r3 = (inst->inst >> 20) & 0x7f;
1652
1653 const int x6 = (inst->inst >> 30) & 0x3f;
1654
1655 switch (x6) {
1656 case 0x00:
1657 case 0x01:
1658 case 0x02:
1659 case 0x03:
1660 inst->operands[0].valid = true;
1661 inst->operands[0].index = r1;
1662 inst->operands[1].valid = true;
1663 inst->operands[1].index = r3;
1664 inst->operands[1].value = IA64_GET_GR(r3);
1665 inst->operands[1].nat = IA64_GET_NAT(r3);
1666 inst->operands[2].valid = true;
1667 inst->operands[2].index = -1;
1668 inst->operands[2].value = ia64_inst_get_imm9b(inst->inst);
1669 inst->operands[2].nat = 0;
1670 switch (x6) {
1671 case 0x00: inst->mnemo = IA64_INST_LD1_UPDATE; break;
1672 case 0x01: inst->mnemo = IA64_INST_LD2_UPDATE; break;
1673 case 0x02: inst->mnemo = IA64_INST_LD4_UPDATE; break;
1674 case 0x03: inst->mnemo = IA64_INST_LD8_UPDATE; break;
1675 }
1676 return true;
1677 case 0x30:
1678 case 0x31:
1679 case 0x32:
1680 case 0x33:
1681 inst->operands[0].valid = true;
1682 inst->operands[0].index = r3;
1683 inst->operands[0].value = IA64_GET_GR(r3);
1684 inst->operands[0].nat = IA64_GET_NAT(r3);
1685 inst->operands[1].valid = true;
1686 inst->operands[1].index = r2;
1687 inst->operands[1].value = IA64_GET_GR(r2);
1688 inst->operands[1].nat = IA64_GET_NAT(r2);
1689 inst->operands[2].valid = true;
1690 inst->operands[2].index = -1;
1691 inst->operands[2].value = ia64_inst_get_imm9a(inst->inst);
1692 inst->operands[2].nat = 0;
1693 switch (x6) {
1694 case 0x30: inst->mnemo = IA64_INST_ST1_UPDATE; break;
1695 case 0x31: inst->mnemo = IA64_INST_ST2_UPDATE; break;
1696 case 0x32: inst->mnemo = IA64_INST_ST4_UPDATE; break;
1697 case 0x33: inst->mnemo = IA64_INST_ST8_UPDATE; break;
1698 }
1699 return true;
1700 }
1701 return false;
1702 }
1703
1704 // Decode group 8 instructions (ALU integer)
1705 static bool ia64_decode_instruction_8(ia64_instruction_t *inst, IA64_CONTEXT_TYPE IA64_CONTEXT)
1706 {
1707 const int r1 = (inst->inst >> 6) & 0x7f;
1708 const int r2 = (inst->inst >> 13) & 0x7f;
1709 const int r3 = (inst->inst >> 20) & 0x7f;
1710
1711 const int x2a = (inst->inst >> 34) & 0x3;
1712 const int x2b = (inst->inst >> 27) & 0x3;
1713 const int x4 = (inst->inst >> 29) & 0xf;
1714 const int ve = (inst->inst >> 33) & 0x1;
1715
1716 // destination register (r1) is always valid in this group
1717 inst->operands[0].valid = true;
1718 inst->operands[0].index = r1;
1719
1720 // source register (r3) is always valid in this group
1721 inst->operands[2].valid = true;
1722 inst->operands[2].index = r3;
1723 inst->operands[2].value = IA64_GET_GR(r3);
1724 inst->operands[2].nat = IA64_GET_NAT(r3);
1725
1726 if (x2a == 0 && ve == 0) {
1727 inst->operands[1].valid = true;
1728 inst->operands[1].index = r2;
1729 inst->operands[1].value = IA64_GET_GR(r2);
1730 inst->operands[1].nat = IA64_GET_NAT(r2);
1731 switch (x4) {
1732 case 0x0: // add (A1)
1733 inst->mnemo = IA64_INST_ADD;
1734 inst->operands[3].valid = true;
1735 inst->operands[3].index = -1;
1736 inst->operands[3].value = x2b == 1;
1737 return true;
1738 case 0x1: // add (A1)
1739 inst->mnemo = IA64_INST_SUB;
1740 inst->operands[3].valid = true;
1741 inst->operands[3].index = -1;
1742 inst->operands[3].value = x2b == 0;
1743 return true;
1744 case 0x4: // shladd (A2)
1745 inst->mnemo = IA64_INST_SHLADD;
1746 inst->operands[3].valid = true;
1747 inst->operands[3].index = -1;
1748 inst->operands[3].value = ia64_inst_get_count2(inst->inst);
1749 return true;
1750 case 0x9:
1751 if (x2b == 1) {
1752 inst->mnemo = IA64_INST_SUB;
1753 inst->operands[1].index = -1;
1754 inst->operands[1].value = ia64_inst_get_imm8(inst->inst);
1755 inst->operands[1].nat = 0;
1756 return true;
1757 }
1758 break;
1759 case 0xb:
1760 inst->operands[1].index = -1;
1761 inst->operands[1].value = ia64_inst_get_imm8(inst->inst);
1762 inst->operands[1].nat = 0;
1763 // fall-through
1764 case 0x3:
1765 switch (x2b) {
1766 case 0: inst->mnemo = IA64_INST_AND; break;
1767 case 1: inst->mnemo = IA64_INST_ANDCM; break;
1768 case 2: inst->mnemo = IA64_INST_OR; break;
1769 case 3: inst->mnemo = IA64_INST_XOR; break;
1770 }
1771 return true;
1772 }
1773 }
1774 return false;
1775 }
1776
1777 // Decode instruction
1778 static bool ia64_decode_instruction(ia64_instruction_t *inst, IA64_CONTEXT_TYPE IA64_CONTEXT)
1779 {
1780 const int major = (inst->inst >> 37) & 0xf;
1781
1782 inst->mnemo = IA64_INST_UNKNOWN;
1783 inst->pred = inst->inst & 0x3f;
1784 memset(&inst->operands[0], 0, sizeof(inst->operands));
1785
1786 switch (major) {
1787 case 0x0: return ia64_decode_instruction_0(inst, IA64_CONTEXT);
1788 case 0x4: return ia64_decode_instruction_4(inst, IA64_CONTEXT);
1789 case 0x5: return ia64_decode_instruction_5(inst, IA64_CONTEXT);
1790 case 0x8: return ia64_decode_instruction_8(inst, IA64_CONTEXT);
1791 }
1792 return false;
1793 }
1794
1795 static bool ia64_emulate_instruction(ia64_instruction_t *inst, IA64_CONTEXT_TYPE IA64_CONTEXT)
1796 {
1797 // XXX: handle Register NaT Consumption fault?
1798 // XXX: this simple emulator assumes instructions in a bundle
1799 // don't depend on effects of other instructions in the same
1800 // bundle. It probably would be simpler to JIT-generate code to be
1801 // executed natively but probably more costly (inject/extract CPU state)
1802 if (inst->mnemo == IA64_INST_UNKNOWN)
1803 return false;
1804 if (inst->pred && !IA64_GET_PR(inst->pred))
1805 return true;
1806
1807 uint8_t nat, nat2;
1808 uint64_t dst, dst2, src1, src2, src3;
1809
1810 switch (inst->mnemo) {
1811 case IA64_INST_NOP:
1812 break;
1813 case IA64_INST_ADD:
1814 case IA64_INST_SUB:
1815 case IA64_INST_SHLADD:
1816 src3 = inst->operands[3].value;
1817 // fall-through
1818 case IA64_INST_AND:
1819 case IA64_INST_ANDCM:
1820 case IA64_INST_OR:
1821 case IA64_INST_XOR:
1822 src1 = inst->operands[1].value;
1823 src2 = inst->operands[2].value;
1824 switch (inst->mnemo) {
1825 case IA64_INST_ADD: dst = src1 + src2 + src3; break;
1826 case IA64_INST_SUB: dst = src1 - src2 - src3; break;
1827 case IA64_INST_SHLADD: dst = (src1 << src3) + src2; break;
1828 case IA64_INST_AND: dst = src1 & src2; break;
1829 case IA64_INST_ANDCM: dst = src1 &~ src2; break;
1830 case IA64_INST_OR: dst = src1 | src2; break;
1831 case IA64_INST_XOR: dst = src1 ^ src2; break;
1832 }
1833 inst->operands[0].commit = true;
1834 inst->operands[0].value = dst;
1835 inst->operands[0].nat = inst->operands[1].nat | inst->operands[2].nat;
1836 break;
1837 case IA64_INST_SXT1:
1838 case IA64_INST_SXT2:
1839 case IA64_INST_SXT4:
1840 case IA64_INST_ZXT1:
1841 case IA64_INST_ZXT2:
1842 case IA64_INST_ZXT4:
1843 src1 = inst->operands[1].value;
1844 switch (inst->mnemo) {
1845 case IA64_INST_SXT1: dst = (int64_t)(int8_t)src1; break;
1846 case IA64_INST_SXT2: dst = (int64_t)(int16_t)src1; break;
1847 case IA64_INST_SXT4: dst = (int64_t)(int32_t)src1; break;
1848 case IA64_INST_ZXT1: dst = (uint8_t)src1; break;
1849 case IA64_INST_ZXT2: dst = (uint16_t)src1; break;
1850 case IA64_INST_ZXT4: dst = (uint32_t)src1; break;
1851 }
1852 inst->operands[0].commit = true;
1853 inst->operands[0].value = dst;
1854 inst->operands[0].nat = inst->operands[1].nat;
1855 break;
1856 case IA64_INST_LD1_UPDATE:
1857 case IA64_INST_LD2_UPDATE:
1858 case IA64_INST_LD4_UPDATE:
1859 case IA64_INST_LD8_UPDATE:
1860 inst->operands[1].commit = true;
1861 dst2 = inst->operands[1].value + inst->operands[2].value;
1862 nat2 = inst->operands[2].nat ? inst->operands[2].nat : 0;
1863 // fall-through
1864 case IA64_INST_LD1:
1865 case IA64_INST_LD2:
1866 case IA64_INST_LD4:
1867 case IA64_INST_LD8:
1868 src1 = inst->operands[1].value;
1869 if (inst->no_memory)
1870 dst = 0;
1871 else {
1872 switch (inst->mnemo) {
1873 case IA64_INST_LD1: case IA64_INST_LD1_UPDATE: dst = *((uint8_t *)src1); break;
1874 case IA64_INST_LD2: case IA64_INST_LD2_UPDATE: dst = *((uint16_t *)src1); break;
1875 case IA64_INST_LD4: case IA64_INST_LD4_UPDATE: dst = *((uint32_t *)src1); break;
1876 case IA64_INST_LD8: case IA64_INST_LD8_UPDATE: dst = *((uint64_t *)src1); break;
1877 }
1878 }
1879 inst->operands[0].commit = true;
1880 inst->operands[0].value = dst;
1881 inst->operands[0].nat = 0;
1882 inst->operands[1].value = dst2;
1883 inst->operands[1].nat = nat2;
1884 break;
1885 case IA64_INST_ST1_UPDATE:
1886 case IA64_INST_ST2_UPDATE:
1887 case IA64_INST_ST4_UPDATE:
1888 case IA64_INST_ST8_UPDATE:
1889 inst->operands[0].commit = 0;
1890 dst2 = inst->operands[0].value + inst->operands[2].value;
1891 nat2 = inst->operands[2].nat ? inst->operands[2].nat : 0;
1892 // fall-through
1893 case IA64_INST_ST1:
1894 case IA64_INST_ST2:
1895 case IA64_INST_ST4:
1896 case IA64_INST_ST8:
1897 dst = inst->operands[0].value;
1898 src1 = inst->operands[1].value;
1899 if (!inst->no_memory) {
1900 switch (inst->mnemo) {
1901 case IA64_INST_ST1: case IA64_INST_ST1_UPDATE: *((uint8_t *)dst) = src1; break;
1902 case IA64_INST_ST2: case IA64_INST_ST2_UPDATE: *((uint16_t *)dst) = src1; break;
1903 case IA64_INST_ST4: case IA64_INST_ST4_UPDATE: *((uint32_t *)dst) = src1; break;
1904 case IA64_INST_ST8: case IA64_INST_ST8_UPDATE: *((uint64_t *)dst) = src1; break;
1905 }
1906 }
1907 inst->operands[0].value = dst2;
1908 inst->operands[0].nat = nat2;
1909 break;
1910 default:
1911 return false;
1912 }
1913
1914 for (int i = 0; i < IA64_N_OPERANDS; i++) {
1915 ia64_operand_t const & op = inst->operands[i];
1916 if (!op.commit)
1917 continue;
1918 if (op.index == -1)
1919 return false; // XXX: internal error
1920 IA64_SET_GR(op.index, op.value, op.nat);
1921 }
1922 return true;
1923 }
1924
1925 static bool ia64_emulate_instruction(uint64_t raw_inst, IA64_CONTEXT_TYPE IA64_CONTEXT)
1926 {
1927 ia64_instruction_t inst;
1928 memset(&inst, 0, sizeof(inst));
1929 inst.inst = raw_inst;
1930 if (!ia64_decode_instruction(&inst, IA64_CONTEXT))
1931 return false;
1932 return ia64_emulate_instruction(&inst, IA64_CONTEXT);
1933 }
1934
1935 static bool ia64_skip_instruction(IA64_CONTEXT_TYPE IA64_CONTEXT)
1936 {
1937 uint64_t ip = IA64_GET_IP();
1938 #if DEBUG
1939 printf("IP: 0x%016llx\n", ip);
1940 #if 0
1941 printf(" Template 0x%02x\n", ia64_get_template(ip));
1942 ia64_get_instruction(ip, 0);
1943 ia64_get_instruction(ip, 1);
1944 ia64_get_instruction(ip, 2);
1945 #endif
1946 #endif
1947
1948 // Select which decode switch to use
1949 ia64_instruction_t inst;
1950 inst.inst = ia64_get_instruction(ip, ip & 3);
1951 if (!ia64_decode_instruction(&inst, IA64_CONTEXT)) {
1952 fprintf(stderr, "ERROR: ia64_skip_instruction(): could not decode instruction\n");
1953 return false;
1954 }
1955
1956 transfer_type_t transfer_type = SIGSEGV_TRANSFER_UNKNOWN;
1957 transfer_size_t transfer_size = SIZE_UNKNOWN;
1958
1959 switch (inst.mnemo) {
1960 case IA64_INST_LD1:
1961 case IA64_INST_LD2:
1962 case IA64_INST_LD4:
1963 case IA64_INST_LD8:
1964 case IA64_INST_LD1_UPDATE:
1965 case IA64_INST_LD2_UPDATE:
1966 case IA64_INST_LD4_UPDATE:
1967 case IA64_INST_LD8_UPDATE:
1968 transfer_type = SIGSEGV_TRANSFER_LOAD;
1969 break;
1970 case IA64_INST_ST1:
1971 case IA64_INST_ST2:
1972 case IA64_INST_ST4:
1973 case IA64_INST_ST8:
1974 case IA64_INST_ST1_UPDATE:
1975 case IA64_INST_ST2_UPDATE:
1976 case IA64_INST_ST4_UPDATE:
1977 case IA64_INST_ST8_UPDATE:
1978 transfer_type = SIGSEGV_TRANSFER_STORE;
1979 break;
1980 }
1981
1982 if (transfer_type == SIGSEGV_TRANSFER_UNKNOWN) {
1983 // Unknown machine code, let it crash. Then patch the decoder
1984 fprintf(stderr, "ERROR: ia64_skip_instruction(): not a load/store instruction\n");
1985 return false;
1986 }
1987
1988 switch (inst.mnemo) {
1989 case IA64_INST_LD1:
1990 case IA64_INST_LD1_UPDATE:
1991 case IA64_INST_ST1:
1992 case IA64_INST_ST1_UPDATE:
1993 transfer_size = SIZE_BYTE;
1994 break;
1995 case IA64_INST_LD2:
1996 case IA64_INST_LD2_UPDATE:
1997 case IA64_INST_ST2:
1998 case IA64_INST_ST2_UPDATE:
1999 transfer_size = SIZE_WORD;
2000 break;
2001 case IA64_INST_LD4:
2002 case IA64_INST_LD4_UPDATE:
2003 case IA64_INST_ST4:
2004 case IA64_INST_ST4_UPDATE:
2005 transfer_size = SIZE_LONG;
2006 break;
2007 case IA64_INST_LD8:
2008 case IA64_INST_LD8_UPDATE:
2009 case IA64_INST_ST8:
2010 case IA64_INST_ST8_UPDATE:
2011 transfer_size = SIZE_QUAD;
2012 break;
2013 }
2014
2015 if (transfer_size == SIZE_UNKNOWN) {
2016 // Unknown machine code, let it crash. Then patch the decoder
2017 fprintf(stderr, "ERROR: ia64_skip_instruction(): unknown transfer size\n");
2018 return false;
2019 }
2020
2021 inst.no_memory = true;
2022 if (!ia64_emulate_instruction(&inst, IA64_CONTEXT)) {
2023 fprintf(stderr, "ERROR: ia64_skip_instruction(): could not emulate fault instruction\n");
2024 return false;
2025 }
2026
2027 int slot = ip & 3;
2028 bool emulate_next = false;
2029 switch (slot) {
2030 case 0:
2031 switch (ia64_get_template(ip)) {
2032 case 0x2: // MI;I
2033 case 0x3: // MI;I;
2034 emulate_next = true;
2035 slot = 2;
2036 break;
2037 case 0xa: // M;MI
2038 case 0xb: // M;MI;
2039 emulate_next = true;
2040 slot = 1;
2041 break;
2042 }
2043 break;
2044 }
2045 if (emulate_next && !IA64_CAN_PATCH_IP_SLOT) {
2046 while (slot < 3) {
2047 if (!ia64_emulate_instruction(ia64_get_instruction(ip, slot), IA64_CONTEXT)) {
2048 fprintf(stderr, "ERROR: ia64_skip_instruction(): could not emulate instruction\n");
2049 return false;
2050 }
2051 ++slot;
2052 }
2053 }
2054
2055 #if IA64_CAN_PATCH_IP_SLOT
2056 if ((slot = ip & 3) < 2)
2057 IA64_SET_IP((ip & ~3ull) + (slot + 1));
2058 else
2059 #endif
2060 IA64_SET_IP((ip & ~3ull) + 16);
2061 #if DEBUG
2062 printf("IP: 0x%016llx\n", IA64_GET_IP());
2063 #endif
2064 return true;
2065 }
2066 #endif
2067
2068 // Decode and skip PPC instruction
2069 #if (defined(powerpc) || defined(__powerpc__) || defined(__ppc__) || defined(__ppc64__))
2070 static bool powerpc_skip_instruction(unsigned long * nip_p, unsigned long * regs)
2071 {
2072 instruction_t instr;
2073 powerpc_decode_instruction(&instr, *nip_p, regs);
2074
2075 if (instr.transfer_type == SIGSEGV_TRANSFER_UNKNOWN) {
2076 // Unknown machine code, let it crash. Then patch the decoder
2077 return false;
2078 }
2079
2080 #if DEBUG
2081 printf("%08x: %s %s access", *nip_p,
2082 instr.transfer_size == SIZE_BYTE ? "byte" :
2083 instr.transfer_size == SIZE_WORD ? "word" :
2084 instr.transfer_size == SIZE_LONG ? "long" : "quad",
2085 instr.transfer_type == SIGSEGV_TRANSFER_LOAD ? "read" : "write");
2086
2087 if (instr.addr_mode == MODE_U || instr.addr_mode == MODE_UX)
2088 printf(" r%d (ra = %08x)\n", instr.ra, instr.addr);
2089 if (instr.transfer_type == SIGSEGV_TRANSFER_LOAD)
2090 printf(" r%d (rd = 0)\n", instr.rd);
2091 #endif
2092
2093 if (instr.addr_mode == MODE_U || instr.addr_mode == MODE_UX)
2094 regs[instr.ra] = instr.addr;
2095 if (instr.transfer_type == SIGSEGV_TRANSFER_LOAD)
2096 regs[instr.rd] = 0;
2097
2098 *nip_p += 4;
2099 return true;
2100 }
2101 #endif
2102
2103 // Decode and skip MIPS instruction
2104 #if (defined(mips) || defined(__mips))
2105 static bool mips_skip_instruction(greg_t * pc_p, greg_t * regs)
2106 {
2107 unsigned int * epc = (unsigned int *)(unsigned long)*pc_p;
2108
2109 if (epc == 0)
2110 return false;
2111
2112 #if DEBUG
2113 printf("IP: %p [%08x]\n", epc, epc[0]);
2114 #endif
2115
2116 transfer_type_t transfer_type = SIGSEGV_TRANSFER_UNKNOWN;
2117 transfer_size_t transfer_size = SIZE_LONG;
2118 int direction = 0;
2119
2120 const unsigned int opcode = epc[0];
2121 switch (opcode >> 26) {
2122 case 32: // Load Byte
2123 case 36: // Load Byte Unsigned
2124 transfer_type = SIGSEGV_TRANSFER_LOAD;
2125 transfer_size = SIZE_BYTE;
2126 break;
2127 case 33: // Load Halfword
2128 case 37: // Load Halfword Unsigned
2129 transfer_type = SIGSEGV_TRANSFER_LOAD;
2130 transfer_size = SIZE_WORD;
2131 break;
2132 case 35: // Load Word
2133 case 39: // Load Word Unsigned
2134 transfer_type = SIGSEGV_TRANSFER_LOAD;
2135 transfer_size = SIZE_LONG;
2136 break;
2137 case 34: // Load Word Left
2138 transfer_type = SIGSEGV_TRANSFER_LOAD;
2139 transfer_size = SIZE_LONG;
2140 direction = -1;
2141 break;
2142 case 38: // Load Word Right
2143 transfer_type = SIGSEGV_TRANSFER_LOAD;
2144 transfer_size = SIZE_LONG;
2145 direction = 1;
2146 break;
2147 case 55: // Load Doubleword
2148 transfer_type = SIGSEGV_TRANSFER_LOAD;
2149 transfer_size = SIZE_QUAD;
2150 break;
2151 case 26: // Load Doubleword Left
2152 transfer_type = SIGSEGV_TRANSFER_LOAD;
2153 transfer_size = SIZE_QUAD;
2154 direction = -1;
2155 break;
2156 case 27: // Load Doubleword Right
2157 transfer_type = SIGSEGV_TRANSFER_LOAD;
2158 transfer_size = SIZE_QUAD;
2159 direction = 1;
2160 break;
2161 case 40: // Store Byte
2162 transfer_type = SIGSEGV_TRANSFER_STORE;
2163 transfer_size = SIZE_BYTE;
2164 break;
2165 case 41: // Store Halfword
2166 transfer_type = SIGSEGV_TRANSFER_STORE;
2167 transfer_size = SIZE_WORD;
2168 break;
2169 case 43: // Store Word
2170 case 42: // Store Word Left
2171 case 46: // Store Word Right
2172 transfer_type = SIGSEGV_TRANSFER_STORE;
2173 transfer_size = SIZE_LONG;
2174 break;
2175 case 63: // Store Doubleword
2176 case 44: // Store Doubleword Left
2177 case 45: // Store Doubleword Right
2178 transfer_type = SIGSEGV_TRANSFER_STORE;
2179 transfer_size = SIZE_QUAD;
2180 break;
2181 /* Misc instructions unlikely to be used within CPU emulators */
2182 case 48: // Load Linked Word
2183 transfer_type = SIGSEGV_TRANSFER_LOAD;
2184 transfer_size = SIZE_LONG;
2185 break;
2186 case 52: // Load Linked Doubleword
2187 transfer_type = SIGSEGV_TRANSFER_LOAD;
2188 transfer_size = SIZE_QUAD;
2189 break;
2190 case 56: // Store Conditional Word
2191 transfer_type = SIGSEGV_TRANSFER_STORE;
2192 transfer_size = SIZE_LONG;
2193 break;
2194 case 60: // Store Conditional Doubleword
2195 transfer_type = SIGSEGV_TRANSFER_STORE;
2196 transfer_size = SIZE_QUAD;
2197 break;
2198 }
2199
2200 if (transfer_type == SIGSEGV_TRANSFER_UNKNOWN) {
2201 // Unknown machine code, let it crash. Then patch the decoder
2202 return false;
2203 }
2204
2205 // Zero target register in case of a load operation
2206 const int reg = (opcode >> 16) & 0x1f;
2207 if (transfer_type == SIGSEGV_TRANSFER_LOAD) {
2208 if (direction == 0)
2209 regs[reg] = 0;
2210 else {
2211 // FIXME: untested code
2212 unsigned long ea = regs[(opcode >> 21) & 0x1f];
2213 ea += (signed long)(signed int)(signed short)(opcode & 0xffff);
2214 const int offset = ea & (transfer_size == SIZE_LONG ? 3 : 7);
2215 unsigned long value;
2216 if (direction > 0) {
2217 const unsigned long rmask = ~((1L << ((offset + 1) * 8)) - 1);
2218 value = regs[reg] & rmask;
2219 }
2220 else {
2221 const unsigned long lmask = (1L << (offset * 8)) - 1;
2222 value = regs[reg] & lmask;
2223 }
2224 // restore most significant bits
2225 if (transfer_size == SIZE_LONG)
2226 value = (signed long)(signed int)value;
2227 regs[reg] = value;
2228 }
2229 }
2230
2231 #if DEBUG
2232 #if (defined(_ABIN32) || defined(_ABI64))
2233 static const char * mips_gpr_names[32] = {
2234 "zero", "at", "v0", "v1", "a0", "a1", "a2", "a3",
2235 "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7",
2236 "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7",
2237 "t8", "t9", "k0", "k1", "gp", "sp", "s8", "ra"
2238 };
2239 #else
2240 static const char * mips_gpr_names[32] = {
2241 "zero", "at", "v0", "v1", "a0", "a1", "a2", "a3",
2242 "a4", "a5", "a6", "a7", "t0", "t1", "t2", "t3",
2243 "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7",
2244 "t8", "t9", "k0", "k1", "gp", "sp", "s8", "ra"
2245 };
2246 #endif
2247 printf("%s %s register %s\n",
2248 transfer_size == SIZE_BYTE ? "byte" :
2249 transfer_size == SIZE_WORD ? "word" :
2250 transfer_size == SIZE_LONG ? "long" :
2251 transfer_size == SIZE_QUAD ? "quad" : "unknown",
2252 transfer_type == SIGSEGV_TRANSFER_LOAD ? "load to" : "store from",
2253 mips_gpr_names[reg]);
2254 #endif
2255
2256 *pc_p += 4;
2257 return true;
2258 }
2259 #endif
2260
2261 // Decode and skip SPARC instruction
2262 #if (defined(sparc) || defined(__sparc__))
2263 enum {
2264 #if (defined(__sun__))
2265 SPARC_REG_G1 = REG_G1,
2266 SPARC_REG_O0 = REG_O0,
2267 SPARC_REG_PC = REG_PC,
2268 SPARC_REG_nPC = REG_nPC
2269 #endif
2270 };
2271 static bool sparc_skip_instruction(unsigned long * regs, gwindows_t * gwins, struct rwindow * rwin)
2272 {
2273 unsigned int * pc = (unsigned int *)regs[SPARC_REG_PC];
2274
2275 if (pc == 0)
2276 return false;
2277
2278 #if DEBUG
2279 printf("IP: %p [%08x]\n", pc, pc[0]);
2280 #endif
2281
2282 transfer_type_t transfer_type = SIGSEGV_TRANSFER_UNKNOWN;
2283 transfer_size_t transfer_size = SIZE_LONG;
2284 bool register_pair = false;
2285
2286 const unsigned int opcode = pc[0];
2287 if ((opcode >> 30) != 3)
2288 return false;
2289 switch ((opcode >> 19) & 0x3f) {
2290 case 9: // Load Signed Byte
2291 case 1: // Load Unsigned Byte
2292 transfer_type = SIGSEGV_TRANSFER_LOAD;
2293 transfer_size = SIZE_BYTE;
2294 break;
2295 case 10:// Load Signed Halfword
2296 case 2: // Load Unsigned Word
2297 transfer_type = SIGSEGV_TRANSFER_LOAD;
2298 transfer_size = SIZE_WORD;
2299 break;
2300 case 8: // Load Word
2301 case 0: // Load Unsigned Word
2302 transfer_type = SIGSEGV_TRANSFER_LOAD;
2303 transfer_size = SIZE_LONG;
2304 break;
2305 case 11:// Load Extended Word
2306 transfer_type = SIGSEGV_TRANSFER_LOAD;
2307 transfer_size = SIZE_QUAD;
2308 break;
2309 case 3: // Load Doubleword
2310 transfer_type = SIGSEGV_TRANSFER_LOAD;
2311 transfer_size = SIZE_LONG;
2312 register_pair = true;
2313 break;
2314 case 5: // Store Byte
2315 transfer_type = SIGSEGV_TRANSFER_STORE;
2316 transfer_size = SIZE_BYTE;
2317 break;
2318 case 6: // Store Halfword
2319 transfer_type = SIGSEGV_TRANSFER_STORE;
2320 transfer_size = SIZE_WORD;
2321 break;
2322 case 4: // Store Word
2323 transfer_type = SIGSEGV_TRANSFER_STORE;
2324 transfer_size = SIZE_LONG;
2325 break;
2326 case 14:// Store Extended Word
2327 transfer_type = SIGSEGV_TRANSFER_STORE;
2328 transfer_size = SIZE_QUAD;
2329 break;
2330 case 7: // Store Doubleword
2331 transfer_type = SIGSEGV_TRANSFER_STORE;
2332 transfer_size = SIZE_LONG;
2333 register_pair = true;
2334 break;
2335 }
2336
2337 if (transfer_type == SIGSEGV_TRANSFER_UNKNOWN) {
2338 // Unknown machine code, let it crash. Then patch the decoder
2339 return false;
2340 }
2341
2342 const int reg = (opcode >> 25) & 0x1f;
2343
2344 #if DEBUG
2345 static const char * reg_names[] = {
2346 "g0", "g1", "g2", "g3", "g4", "g5", "g6", "g7",
2347 "o0", "o1", "o2", "o3", "o4", "o5", "sp", "o7",
2348 "l0", "l1", "l2", "l3", "l4", "l5", "l6", "l7",
2349 "i0", "i1", "i2", "i3", "i4", "i5", "fp", "i7"
2350 };
2351 printf("%s %s register %s\n",
2352 transfer_size == SIZE_BYTE ? "byte" :
2353 transfer_size == SIZE_WORD ? "word" :
2354 transfer_size == SIZE_LONG ? "long" :
2355 transfer_size == SIZE_QUAD ? "quad" : "unknown",
2356 transfer_type == SIGSEGV_TRANSFER_LOAD ? "load to" : "store from",
2357 reg_names[reg]);
2358 #endif
2359
2360 // Zero target register in case of a load operation
2361 if (transfer_type == SIGSEGV_TRANSFER_LOAD && reg != 0) {
2362 // FIXME: code to handle local & input registers is not tested
2363 if (reg >= 1 && reg < 8) {
2364 // global registers
2365 regs[reg - 1 + SPARC_REG_G1] = 0;
2366 }
2367 else if (reg >= 8 && reg < 16) {
2368 // output registers
2369 regs[reg - 8 + SPARC_REG_O0] = 0;
2370 }
2371 else if (reg >= 16 && reg < 24) {
2372 // local registers (in register windows)
2373 if (gwins)
2374 gwins->wbuf->rw_local[reg - 16] = 0;
2375 else
2376 rwin->rw_local[reg - 16] = 0;
2377 }
2378 else {
2379 // input registers (in register windows)
2380 if (gwins)
2381 gwins->wbuf->rw_in[reg - 24] = 0;
2382 else
2383 rwin->rw_in[reg - 24] = 0;
2384 }
2385 }
2386
2387 regs[SPARC_REG_PC] += 4;
2388 regs[SPARC_REG_nPC] += 4;
2389 return true;
2390 }
2391 #endif
2392 #endif
2393
2394 // Decode and skip ARM instruction
2395 #if (defined(arm) || defined(__arm__))
2396 enum {
2397 #if (defined(__linux__))
2398 ARM_REG_PC = 15,
2399 ARM_REG_CPSR = 16
2400 #endif
2401 };
2402 static bool arm_skip_instruction(unsigned long * regs)
2403 {
2404 unsigned int * pc = (unsigned int *)regs[ARM_REG_PC];
2405
2406 if (pc == 0)
2407 return false;
2408
2409 #if DEBUG
2410 printf("IP: %p [%08x]\n", pc, pc[0]);
2411 #endif
2412
2413 transfer_type_t transfer_type = SIGSEGV_TRANSFER_UNKNOWN;
2414 transfer_size_t transfer_size = SIZE_UNKNOWN;
2415 enum { op_sdt = 1, op_sdth = 2 };
2416 int op = 0;
2417
2418 // Handle load/store instructions only
2419 const unsigned int opcode = pc[0];
2420 switch ((opcode >> 25) & 7) {
2421 case 0: // Halfword and Signed Data Transfer (LDRH, STRH, LDRSB, LDRSH)
2422 op = op_sdth;
2423 // Determine transfer size (S/H bits)
2424 switch ((opcode >> 5) & 3) {
2425 case 0: // SWP instruction
2426 break;
2427 case 1: // Unsigned halfwords
2428 case 3: // Signed halfwords
2429 transfer_size = SIZE_WORD;
2430 break;
2431 case 2: // Signed byte
2432 transfer_size = SIZE_BYTE;
2433 break;
2434 }
2435 break;
2436 case 2:
2437 case 3: // Single Data Transfer (LDR, STR)
2438 op = op_sdt;
2439 // Determine transfer size (B bit)
2440 if (((opcode >> 22) & 1) == 1)
2441 transfer_size = SIZE_BYTE;
2442 else
2443 transfer_size = SIZE_LONG;
2444 break;
2445 default:
2446 // FIXME: support load/store mutliple?
2447 return false;
2448 }
2449
2450 // Check for invalid transfer size (SWP instruction?)
2451 if (transfer_size == SIZE_UNKNOWN)
2452 return false;
2453
2454 // Determine transfer type (L bit)
2455 if (((opcode >> 20) & 1) == 1)
2456 transfer_type = SIGSEGV_TRANSFER_LOAD;
2457 else
2458 transfer_type = SIGSEGV_TRANSFER_STORE;
2459
2460 // Compute offset
2461 int offset;
2462 if (((opcode >> 25) & 1) == 0) {
2463 if (op == op_sdt)
2464 offset = opcode & 0xfff;
2465 else if (op == op_sdth) {
2466 int rm = opcode & 0xf;
2467 if (((opcode >> 22) & 1) == 0) {
2468 // register offset
2469 offset = regs[rm];
2470 }
2471 else {
2472 // immediate offset
2473 offset = ((opcode >> 4) & 0xf0) | (opcode & 0x0f);
2474 }
2475 }
2476 }
2477 else {
2478 const int rm = opcode & 0xf;
2479 const int sh = (opcode >> 7) & 0x1f;
2480 if (((opcode >> 4) & 1) == 1) {
2481 // we expect only legal load/store instructions
2482 printf("FATAL: invalid shift operand\n");
2483 return false;
2484 }
2485 const unsigned int v = regs[rm];
2486 switch ((opcode >> 5) & 3) {
2487 case 0: // logical shift left
2488 offset = sh ? v << sh : v;
2489 break;
2490 case 1: // logical shift right
2491 offset = sh ? v >> sh : 0;
2492 break;
2493 case 2: // arithmetic shift right
2494 if (sh)
2495 offset = ((signed int)v) >> sh;
2496 else
2497 offset = (v & 0x80000000) ? 0xffffffff : 0;
2498 break;
2499 case 3: // rotate right
2500 if (sh)
2501 offset = (v >> sh) | (v << (32 - sh));
2502 else
2503 offset = (v >> 1) | ((regs[ARM_REG_CPSR] << 2) & 0x80000000);
2504 break;
2505 }
2506 }
2507 if (((opcode >> 23) & 1) == 0)
2508 offset = -offset;
2509
2510 int rd = (opcode >> 12) & 0xf;
2511 int rn = (opcode >> 16) & 0xf;
2512 #if DEBUG
2513 static const char * reg_names[] = {
2514 "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
2515 "r9", "r9", "sl", "fp", "ip", "sp", "lr", "pc"
2516 };
2517 printf("%s %s register %s\n",
2518 transfer_size == SIZE_BYTE ? "byte" :
2519 transfer_size == SIZE_WORD ? "word" :
2520 transfer_size == SIZE_LONG ? "long" : "unknown",
2521 transfer_type == SIGSEGV_TRANSFER_LOAD ? "load to" : "store from",
2522 reg_names[rd]);
2523 #endif
2524
2525 unsigned int base = regs[rn];
2526 if (((opcode >> 24) & 1) == 1)
2527 base += offset;
2528
2529 if (transfer_type == SIGSEGV_TRANSFER_LOAD)
2530 regs[rd] = 0;
2531
2532 if (((opcode >> 24) & 1) == 0) // post-index addressing
2533 regs[rn] += offset;
2534 else if (((opcode >> 21) & 1) == 1) // write-back address into base
2535 regs[rn] = base;
2536
2537 regs[ARM_REG_PC] += 4;
2538 return true;
2539 }
2540 #endif
2541
2542
2543 // Fallbacks
2544 #ifndef SIGSEGV_FAULT_ADDRESS_FAST
2545 #define SIGSEGV_FAULT_ADDRESS_FAST SIGSEGV_FAULT_ADDRESS
2546 #endif
2547 #ifndef SIGSEGV_FAULT_INSTRUCTION_FAST
2548 #define SIGSEGV_FAULT_INSTRUCTION_FAST SIGSEGV_FAULT_INSTRUCTION
2549 #endif
2550 #ifndef SIGSEGV_FAULT_INSTRUCTION
2551 #define SIGSEGV_FAULT_INSTRUCTION SIGSEGV_INVALID_ADDRESS
2552 #endif
2553 #ifndef SIGSEGV_FAULT_HANDLER_ARGLIST_1
2554 #define SIGSEGV_FAULT_HANDLER_ARGLIST_1 SIGSEGV_FAULT_HANDLER_ARGLIST
2555 #endif
2556 #ifndef SIGSEGV_FAULT_HANDLER_INVOKE
2557 #define SIGSEGV_FAULT_HANDLER_INVOKE(P) sigsegv_fault_handler(P)
2558 #endif
2559
2560 // SIGSEGV recovery supported ?
2561 #if defined(SIGSEGV_ALL_SIGNALS) && defined(SIGSEGV_FAULT_HANDLER_ARGLIST) && defined(SIGSEGV_FAULT_ADDRESS)
2562 #define HAVE_SIGSEGV_RECOVERY
2563 #endif
2564
2565
2566 /*
2567 * SIGSEGV global handler
2568 */
2569
2570 struct sigsegv_info_t {
2571 sigsegv_address_t addr;
2572 sigsegv_address_t pc;
2573 #ifdef HAVE_MACH_EXCEPTIONS
2574 mach_port_t thread;
2575 bool has_exc_state;
2576 SIGSEGV_EXCEPTION_STATE_TYPE exc_state;
2577 mach_msg_type_number_t exc_state_count;
2578 bool has_thr_state;
2579 SIGSEGV_THREAD_STATE_TYPE thr_state;
2580 mach_msg_type_number_t thr_state_count;
2581 #endif
2582 };
2583
2584 #ifdef HAVE_MACH_EXCEPTIONS
2585 static void mach_get_exception_state(sigsegv_info_t *SIP)
2586 {
2587 SIP->exc_state_count = SIGSEGV_EXCEPTION_STATE_COUNT;
2588 kern_return_t krc = thread_get_state(SIP->thread,
2589 SIGSEGV_EXCEPTION_STATE_FLAVOR,
2590 (natural_t *)&SIP->exc_state,
2591 &SIP->exc_state_count);
2592 MACH_CHECK_ERROR(thread_get_state, krc);
2593 SIP->has_exc_state = true;
2594 }
2595
2596 static void mach_get_thread_state(sigsegv_info_t *SIP)
2597 {
2598 SIP->thr_state_count = SIGSEGV_THREAD_STATE_COUNT;
2599 kern_return_t krc = thread_get_state(SIP->thread,
2600 SIGSEGV_THREAD_STATE_FLAVOR,
2601 (natural_t *)&SIP->thr_state,
2602 &SIP->thr_state_count);
2603 MACH_CHECK_ERROR(thread_get_state, krc);
2604 SIP->has_thr_state = true;
2605 }
2606
2607 static void mach_set_thread_state(sigsegv_info_t *SIP)
2608 {
2609 kern_return_t krc = thread_set_state(SIP->thread,
2610 SIGSEGV_THREAD_STATE_FLAVOR,
2611 (natural_t *)&SIP->thr_state,
2612 SIP->thr_state_count);
2613 MACH_CHECK_ERROR(thread_set_state, krc);
2614 }
2615 #endif
2616
2617 // Return the address of the invalid memory reference
2618 sigsegv_address_t sigsegv_get_fault_address(sigsegv_info_t *SIP)
2619 {
2620 #ifdef HAVE_MACH_EXCEPTIONS
2621 #ifdef EMULATED_PPC
2622 static int use_fast_path = -1;
2623 if (use_fast_path != 1 && !SIP->has_exc_state) {
2624 mach_get_exception_state(SIP);
2625
2626 sigsegv_address_t addr = (sigsegv_address_t)SIGSEGV_FAULT_ADDRESS;
2627 if (use_fast_path < 0) {
2628 const char *machfault = getenv("SIGSEGV_MACH_FAULT");
2629 if (machfault) {
2630 if (strcmp(machfault, "fast") == 0)
2631 use_fast_path = 1;
2632 else if (strcmp(machfault, "slow") == 0)
2633 use_fast_path = 0;
2634 }
2635 if (use_fast_path < 0)
2636 use_fast_path = addr == SIP->addr;
2637 }
2638 SIP->addr = addr;
2639 }
2640 #endif
2641 #endif
2642 return SIP->addr;
2643 }
2644
2645 // Return the address of the instruction that caused the fault, or
2646 // SIGSEGV_INVALID_ADDRESS if we could not retrieve this information
2647 sigsegv_address_t sigsegv_get_fault_instruction_address(sigsegv_info_t *SIP)
2648 {
2649 #ifdef HAVE_MACH_EXCEPTIONS
2650 #ifdef EMULATED_PPC
2651 if (!SIP->has_thr_state) {
2652 mach_get_thread_state(SIP);
2653
2654 SIP->pc = (sigsegv_address_t)SIGSEGV_FAULT_INSTRUCTION;
2655 }
2656 #endif
2657 #endif
2658 return SIP->pc;
2659 }
2660
2661 // This function handles the badaccess to memory.
2662 // It is called from the signal handler or the exception handler.
2663 static bool handle_badaccess(SIGSEGV_FAULT_HANDLER_ARGLIST_1)
2664 {
2665 sigsegv_info_t SI;
2666 SI.addr = (sigsegv_address_t)SIGSEGV_FAULT_ADDRESS_FAST;
2667 SI.pc = (sigsegv_address_t)SIGSEGV_FAULT_INSTRUCTION_FAST;
2668 #ifdef HAVE_MACH_EXCEPTIONS
2669 SI.thread = thread;
2670 SI.has_exc_state = false;
2671 SI.has_thr_state = false;
2672 #endif
2673 sigsegv_info_t * const SIP = &SI;
2674
2675 // Call user's handler and reinstall the global handler, if required
2676 switch (SIGSEGV_FAULT_HANDLER_INVOKE(SIP)) {
2677 case SIGSEGV_RETURN_SUCCESS:
2678 return true;
2679
2680 #if HAVE_SIGSEGV_SKIP_INSTRUCTION
2681 case SIGSEGV_RETURN_SKIP_INSTRUCTION:
2682 // Call the instruction skipper with the register file
2683 // available
2684 #ifdef HAVE_MACH_EXCEPTIONS
2685 if (!SIP->has_thr_state)
2686 mach_get_thread_state(SIP);
2687 #endif
2688 if (SIGSEGV_SKIP_INSTRUCTION(SIGSEGV_REGISTER_FILE)) {
2689 #ifdef HAVE_MACH_EXCEPTIONS
2690 // Unlike UNIX signals where the thread state
2691 // is modified off of the stack, in Mach we
2692 // need to actually call thread_set_state to
2693 // have the register values updated.
2694 mach_set_thread_state(SIP);
2695 #endif
2696 return true;
2697 }
2698 break;
2699 #endif
2700 case SIGSEGV_RETURN_FAILURE:
2701 // We can't do anything with the fault_address, dump state?
2702 if (sigsegv_state_dumper != 0)
2703 sigsegv_state_dumper(SIP);
2704 break;
2705 }
2706
2707 return false;
2708 }
2709
2710
2711 /*
2712 * There are two mechanisms for handling a bad memory access,
2713 * Mach exceptions and UNIX signals. The implementation specific
2714 * code appears below. Its reponsibility is to call handle_badaccess
2715 * which is the routine that handles the fault in an implementation
2716 * agnostic manner. The implementation specific code below is then
2717 * reponsible for checking whether handle_badaccess was able
2718 * to handle the memory access error and perform any implementation
2719 * specific tasks necessary afterwards.
2720 */
2721
2722 #ifdef HAVE_MACH_EXCEPTIONS
2723 /*
2724 * We need to forward all exceptions that we do not handle.
2725 * This is important, there are many exceptions that may be
2726 * handled by other exception handlers. For example debuggers
2727 * use exceptions and the exception hander is in another
2728 * process in such a case. (Timothy J. Wood states in his
2729 * message to the list that he based this code on that from
2730 * gdb for Darwin.)
2731 */
2732 static inline kern_return_t
2733 forward_exception(mach_port_t thread_port,
2734 mach_port_t task_port,
2735 exception_type_t exception_type,
2736 mach_exception_data_t exception_data,
2737 mach_msg_type_number_t data_count,
2738 ExceptionPorts *oldExceptionPorts)
2739 {
2740 kern_return_t kret;
2741 unsigned int portIndex;
2742 mach_port_t port;
2743 exception_behavior_t behavior;
2744 thread_state_flavor_t flavor;
2745 thread_state_data_t thread_state;
2746 mach_msg_type_number_t thread_state_count;
2747
2748 for (portIndex = 0; portIndex < oldExceptionPorts->maskCount; portIndex++) {
2749 if (oldExceptionPorts->masks[portIndex] & (1 << exception_type)) {
2750 // This handler wants the exception
2751 break;
2752 }
2753 }
2754
2755 if (portIndex >= oldExceptionPorts->maskCount) {
2756 fprintf(stderr, "No handler for exception_type = %d. Not fowarding\n", exception_type);
2757 return KERN_FAILURE;
2758 }
2759
2760 port = oldExceptionPorts->handlers[portIndex];
2761 behavior = oldExceptionPorts->behaviors[portIndex];
2762 flavor = oldExceptionPorts->flavors[portIndex];
2763
2764 if (!VALID_THREAD_STATE_FLAVOR(flavor)) {
2765 fprintf(stderr, "Invalid thread_state flavor = %d. Not forwarding\n", flavor);
2766 return KERN_FAILURE;
2767 }
2768
2769 /*
2770 fprintf(stderr, "forwarding exception, port = 0x%x, behaviour = %d, flavor = %d\n", port, behavior, flavor);
2771 */
2772
2773 if (behavior != EXCEPTION_DEFAULT) {
2774 thread_state_count = THREAD_STATE_MAX;
2775 kret = thread_get_state (thread_port, flavor, (natural_t *)&thread_state,
2776 &thread_state_count);
2777 MACH_CHECK_ERROR (thread_get_state, kret);
2778 }
2779
2780 switch (behavior) {
2781 case EXCEPTION_DEFAULT:
2782 // fprintf(stderr, "forwarding to exception_raise\n");
2783 kret = mach_exception_raise(port, thread_port, task_port, exception_type,
2784 exception_data, data_count);
2785 MACH_CHECK_ERROR (mach_exception_raise, kret);
2786 break;
2787 case EXCEPTION_STATE:
2788 // fprintf(stderr, "forwarding to exception_raise_state\n");
2789 kret = mach_exception_raise_state(port, exception_type, exception_data,
2790 data_count, &flavor,
2791 (natural_t *)&thread_state, thread_state_count,
2792 (natural_t *)&thread_state, &thread_state_count);
2793 MACH_CHECK_ERROR (mach_exception_raise_state, kret);
2794 break;
2795 case EXCEPTION_STATE_IDENTITY:
2796 // fprintf(stderr, "forwarding to exception_raise_state_identity\n");
2797 kret = mach_exception_raise_state_identity(port, thread_port, task_port,
2798 exception_type, exception_data,
2799 data_count, &flavor,
2800 (natural_t *)&thread_state, thread_state_count,
2801 (natural_t *)&thread_state, &thread_state_count);
2802 MACH_CHECK_ERROR (mach_exception_raise_state_identity, kret);
2803 break;
2804 default:
2805 fprintf(stderr, "forward_exception got unknown behavior\n");
2806 kret = KERN_FAILURE;
2807 break;
2808 }
2809
2810 if (behavior != EXCEPTION_DEFAULT) {
2811 kret = thread_set_state (thread_port, flavor, (natural_t *)&thread_state,
2812 thread_state_count);
2813 MACH_CHECK_ERROR (thread_set_state, kret);
2814 }
2815
2816 return kret;
2817 }
2818
2819 /*
2820 * This is the code that actually handles the exception.
2821 * It is called by exc_server. For Darwin 5 Apple changed
2822 * this a bit from how this family of functions worked in
2823 * Mach. If you are familiar with that it is a little
2824 * different. The main variation that concerns us here is
2825 * that code is an array of exception specific codes and
2826 * codeCount is a count of the number of codes in the code
2827 * array. In typical Mach all exceptions have a code
2828 * and sub-code. It happens to be the case that for a
2829 * EXC_BAD_ACCESS exception the first entry is the type of
2830 * bad access that occurred and the second entry is the
2831 * faulting address so these entries correspond exactly to
2832 * how the code and sub-code are used on Mach.
2833 *
2834 * This is a MIG interface. No code in Basilisk II should
2835 * call this directley. This has to have external C
2836 * linkage because that is what exc_server expects.
2837 */
2838 kern_return_t
2839 catch_mach_exception_raise(mach_port_t exception_port,
2840 mach_port_t thread,
2841 mach_port_t task,
2842 exception_type_t exception,
2843 mach_exception_data_t code,
2844 mach_msg_type_number_t code_count)
2845 {
2846 kern_return_t krc;
2847
2848 if (exception == EXC_BAD_ACCESS) {
2849 switch (code[0]) {
2850 case KERN_PROTECTION_FAILURE:
2851 case KERN_INVALID_ADDRESS:
2852 if (handle_badaccess(SIGSEGV_FAULT_HANDLER_ARGS))
2853 return KERN_SUCCESS;
2854 break;
2855 }
2856 }
2857
2858 // In Mach we do not need to remove the exception handler.
2859 // If we forward the exception, eventually some exception handler
2860 // will take care of this exception.
2861 krc = forward_exception(thread, task, exception, code, code_count, &ports);
2862
2863 return krc;
2864 }
2865
2866 /* XXX: borrowed from launchd and gdb */
2867 kern_return_t
2868 catch_mach_exception_raise_state(mach_port_t exception_port,
2869 exception_type_t exception,
2870 mach_exception_data_t code,
2871 mach_msg_type_number_t code_count,
2872 int *flavor,
2873 thread_state_t old_state,
2874 mach_msg_type_number_t old_state_count,
2875 thread_state_t new_state,
2876 mach_msg_type_number_t *new_state_count)
2877 {
2878 memcpy(new_state, old_state, old_state_count * sizeof(old_state[0]));
2879 *new_state_count = old_state_count;
2880 return KERN_SUCCESS;
2881 }
2882
2883 /* XXX: borrowed from launchd and gdb */
2884 kern_return_t
2885 catch_mach_exception_raise_state_identity(mach_port_t exception_port,
2886 mach_port_t thread_port,
2887 mach_port_t task_port,
2888 exception_type_t exception,
2889 mach_exception_data_t code,
2890 mach_msg_type_number_t code_count,
2891 int *flavor,
2892 thread_state_t old_state,
2893 mach_msg_type_number_t old_state_count,
2894 thread_state_t new_state,
2895 mach_msg_type_number_t *new_state_count)
2896 {
2897 kern_return_t kret;
2898
2899 memcpy(new_state, old_state, old_state_count * sizeof(old_state[0]));
2900 *new_state_count = old_state_count;
2901
2902 kret = mach_port_deallocate(mach_task_self(), task_port);
2903 MACH_CHECK_ERROR(mach_port_deallocate, kret);
2904 kret = mach_port_deallocate(mach_task_self(), thread_port);
2905 MACH_CHECK_ERROR(mach_port_deallocate, kret);
2906
2907 return KERN_SUCCESS;
2908 }
2909 #endif
2910
2911 #ifdef HAVE_SIGSEGV_RECOVERY
2912 // Handle bad memory accesses with signal handler
2913 static void sigsegv_handler(SIGSEGV_FAULT_HANDLER_ARGLIST)
2914 {
2915 // Call handler and reinstall the global handler, if required
2916 if (handle_badaccess(SIGSEGV_FAULT_HANDLER_ARGS)) {
2917 #if (defined(HAVE_SIGACTION) ? defined(SIGACTION_NEED_REINSTALL) : defined(SIGNAL_NEED_REINSTALL))
2918 sigsegv_do_install_handler(sig);
2919 #endif
2920 return;
2921 }
2922
2923 // Failure: reinstall default handler for "safe" crash
2924 #define FAULT_HANDLER(sig) signal(sig, SIG_DFL);
2925 SIGSEGV_ALL_SIGNALS
2926 #undef FAULT_HANDLER
2927 }
2928 #endif
2929
2930
2931 /*
2932 * SIGSEGV handler initialization
2933 */
2934
2935 #if defined(HAVE_SIGINFO_T)
2936 static bool sigsegv_do_install_handler(int sig)
2937 {
2938 // Setup SIGSEGV handler to process writes to frame buffer
2939 #ifdef HAVE_SIGACTION
2940 struct sigaction sigsegv_sa;
2941 sigemptyset(&sigsegv_sa.sa_mask);
2942 sigsegv_sa.sa_sigaction = sigsegv_handler;
2943 sigsegv_sa.sa_flags = SA_SIGINFO;
2944 return (sigaction(sig, &sigsegv_sa, 0) == 0);
2945 #else
2946 return (signal(sig, (signal_handler)sigsegv_handler) != SIG_ERR);
2947 #endif
2948 }
2949 #endif
2950
2951 #if defined(HAVE_SIGCONTEXT_SUBTERFUGE)
2952 static bool sigsegv_do_install_handler(int sig)
2953 {
2954 // Setup SIGSEGV handler to process writes to frame buffer
2955 #ifdef HAVE_SIGACTION
2956 struct sigaction sigsegv_sa;
2957 sigemptyset(&sigsegv_sa.sa_mask);
2958 sigsegv_sa.sa_handler = (signal_handler)sigsegv_handler;
2959 sigsegv_sa.sa_flags = 0;
2960 #if !EMULATED_68K && defined(__NetBSD__)
2961 sigaddset(&sigsegv_sa.sa_mask, SIGALRM);
2962 sigsegv_sa.sa_flags |= SA_ONSTACK;
2963 #endif
2964 return (sigaction(sig, &sigsegv_sa, 0) == 0);
2965 #else
2966 return (signal(sig, (signal_handler)sigsegv_handler) != SIG_ERR);
2967 #endif
2968 }
2969 #endif
2970
2971 #if defined(HAVE_MACH_EXCEPTIONS)
2972 static bool sigsegv_do_install_handler(sigsegv_fault_handler_t handler)
2973 {
2974 /*
2975 * Except for the exception port functions, this should be
2976 * pretty much stock Mach. If later you choose to support
2977 * other Mach's besides Darwin, just check for __MACH__
2978 * here and __APPLE__ where the actual differences are.
2979 */
2980 #if defined(__APPLE__) && defined(__MACH__)
2981 if (sigsegv_fault_handler != NULL) {
2982 sigsegv_fault_handler = handler;
2983 return true;
2984 }
2985
2986 kern_return_t krc;
2987
2988 // create the the exception port
2989 krc = mach_port_allocate(mach_task_self(),
2990 MACH_PORT_RIGHT_RECEIVE, &_exceptionPort);
2991 if (krc != KERN_SUCCESS) {
2992 mach_error("mach_port_allocate", krc);
2993 return false;
2994 }
2995
2996 // add a port send right
2997 krc = mach_port_insert_right(mach_task_self(),
2998 _exceptionPort, _exceptionPort,
2999 MACH_MSG_TYPE_MAKE_SEND);
3000 if (krc != KERN_SUCCESS) {
3001 mach_error("mach_port_insert_right", krc);
3002 return false;
3003 }
3004
3005 // get the old exception ports
3006 ports.maskCount = sizeof (ports.masks) / sizeof (ports.masks[0]);
3007 krc = thread_get_exception_ports(mach_thread_self(), EXC_MASK_BAD_ACCESS, ports.masks,
3008 &ports.maskCount, ports.handlers, ports.behaviors, ports.flavors);
3009 if (krc != KERN_SUCCESS) {
3010 mach_error("thread_get_exception_ports", krc);
3011 return false;
3012 }
3013
3014 // set the new exception port
3015 //
3016 // We could have used EXCEPTION_STATE_IDENTITY instead of
3017 // EXCEPTION_DEFAULT to get the thread state in the initial
3018 // message, but it turns out that in the common case this is not
3019 // neccessary. If we need it we can later ask for it from the
3020 // suspended thread.
3021 //
3022 // Even with THREAD_STATE_NONE, Darwin provides the program
3023 // counter in the thread state. The comments in the header file
3024 // seem to imply that you can count on the GPR's on an exception
3025 // as well but just to be safe I use MACHINE_THREAD_STATE because
3026 // you have to ask for all of the GPR's anyway just to get the
3027 // program counter. In any case because of update effective
3028 // address from immediate and update address from effective
3029 // addresses of ra and rb modes (as good an name as any for these
3030 // addressing modes) used in PPC instructions, you will need the
3031 // GPR state anyway.
3032 krc = thread_set_exception_ports(mach_thread_self(), EXC_MASK_BAD_ACCESS, _exceptionPort,
3033 EXCEPTION_DEFAULT | MACH_EXCEPTION_CODES, SIGSEGV_THREAD_STATE_FLAVOR);
3034 if (krc != KERN_SUCCESS) {
3035 mach_error("thread_set_exception_ports", krc);
3036 return false;
3037 }
3038
3039 // create the exception handler thread
3040 if (pthread_create(&exc_thread, NULL, &handleExceptions, NULL) != 0) {
3041 (void)fprintf(stderr, "creation of exception thread failed\n");
3042 return false;
3043 }
3044
3045 // do not care about the exception thread any longer, let is run standalone
3046 (void)pthread_detach(exc_thread);
3047
3048 sigsegv_fault_handler = handler;
3049 return true;
3050 #else
3051 return false;
3052 #endif
3053 }
3054 #endif
3055
3056 #ifdef HAVE_WIN32_EXCEPTIONS
3057 static LONG WINAPI main_exception_filter(EXCEPTION_POINTERS *ExceptionInfo)
3058 {
3059 if (sigsegv_fault_handler != NULL
3060 && ExceptionInfo->ExceptionRecord->ExceptionCode == EXCEPTION_ACCESS_VIOLATION
3061 && ExceptionInfo->ExceptionRecord->NumberParameters >= 2
3062 && handle_badaccess(ExceptionInfo))
3063 return EXCEPTION_CONTINUE_EXECUTION;
3064
3065 return EXCEPTION_CONTINUE_SEARCH;
3066 }
3067
3068 #if defined __CYGWIN__ && defined __i386__
3069 /* In Cygwin programs, SetUnhandledExceptionFilter has no effect because Cygwin
3070 installs a global exception handler. We have to dig deep in order to install
3071 our main_exception_filter. */
3072
3073 /* Data structures for the current thread's exception handler chain.
3074 On the x86 Windows uses register fs, offset 0 to point to the current
3075 exception handler; Cygwin mucks with it, so we must do the same... :-/ */
3076
3077 /* Magic taken from winsup/cygwin/include/exceptions.h. */
3078
3079 struct exception_list {
3080 struct exception_list *prev;
3081 int (*handler) (EXCEPTION_RECORD *, void *, CONTEXT *, void *);
3082 };
3083 typedef struct exception_list exception_list;
3084
3085 /* Magic taken from winsup/cygwin/exceptions.cc. */
3086
3087 __asm__ (".equ __except_list,0");
3088
3089 extern exception_list *_except_list __asm__ ("%fs:__except_list");
3090
3091 /* For debugging. _except_list is not otherwise accessible from gdb. */
3092 static exception_list *
3093 debug_get_except_list ()
3094 {
3095 return _except_list;
3096 }
3097
3098 /* Cygwin's original exception handler. */
3099 static int (*cygwin_exception_handler) (EXCEPTION_RECORD *, void *, CONTEXT *, void *);
3100
3101 /* Our exception handler. */
3102 static int
3103 libsigsegv_exception_handler (EXCEPTION_RECORD *exception, void *frame, CONTEXT *context, void *dispatch)
3104 {
3105 EXCEPTION_POINTERS ExceptionInfo;
3106 ExceptionInfo.ExceptionRecord = exception;
3107 ExceptionInfo.ContextRecord = context;
3108 if (main_exception_filter (&ExceptionInfo) == EXCEPTION_CONTINUE_SEARCH)
3109 return cygwin_exception_handler (exception, frame, context, dispatch);
3110 else
3111 return 0;
3112 }
3113
3114 static void
3115 do_install_main_exception_filter ()
3116 {
3117 /* We cannot insert any handler into the chain, because such handlers
3118 must lie on the stack (?). Instead, we have to replace(!) Cygwin's
3119 global exception handler. */
3120 cygwin_exception_handler = _except_list->handler;
3121 _except_list->handler = libsigsegv_exception_handler;
3122 }
3123
3124 #else
3125
3126 static void
3127 do_install_main_exception_filter ()
3128 {
3129 SetUnhandledExceptionFilter ((LPTOP_LEVEL_EXCEPTION_FILTER) &main_exception_filter);
3130 }
3131 #endif
3132
3133 static bool sigsegv_do_install_handler(sigsegv_fault_handler_t handler)
3134 {
3135 static bool main_exception_filter_installed = false;
3136 if (!main_exception_filter_installed) {
3137 do_install_main_exception_filter();
3138 main_exception_filter_installed = true;
3139 }
3140 sigsegv_fault_handler = handler;
3141 return true;
3142 }
3143 #endif
3144
3145 bool sigsegv_install_handler(sigsegv_fault_handler_t handler)
3146 {
3147 #if defined(HAVE_SIGSEGV_RECOVERY)
3148 bool success = true;
3149 #define FAULT_HANDLER(sig) success = success && sigsegv_do_install_handler(sig);
3150 SIGSEGV_ALL_SIGNALS
3151 #undef FAULT_HANDLER
3152 if (success)
3153 sigsegv_fault_handler = handler;
3154 return success;
3155 #elif defined(HAVE_MACH_EXCEPTIONS) || defined(HAVE_WIN32_EXCEPTIONS)
3156 return sigsegv_do_install_handler(handler);
3157 #else
3158 // FAIL: no siginfo_t nor sigcontext subterfuge is available
3159 return false;
3160 #endif
3161 }
3162
3163
3164 /*
3165 * SIGSEGV handler deinitialization
3166 */
3167
3168 void sigsegv_deinstall_handler(void)
3169 {
3170 // We do nothing for Mach exceptions, the thread would need to be
3171 // suspended if not already so, and we might mess with other
3172 // exception handlers that came after we registered ours. There is
3173 // no need to remove the exception handler, in fact this function is
3174 // not called anywhere in Basilisk II.
3175 #ifdef HAVE_SIGSEGV_RECOVERY
3176 sigsegv_fault_handler = 0;
3177 #define FAULT_HANDLER(sig) signal(sig, SIG_DFL);
3178 SIGSEGV_ALL_SIGNALS
3179 #undef FAULT_HANDLER
3180 #endif
3181 #ifdef HAVE_WIN32_EXCEPTIONS
3182 sigsegv_fault_handler = NULL;
3183 #endif
3184 }
3185
3186
3187 /*
3188 * Set callback function when we cannot handle the fault
3189 */
3190
3191 void sigsegv_set_dump_state(sigsegv_state_dumper_t handler)
3192 {
3193 sigsegv_state_dumper = handler;
3194 }
3195
3196
3197 /*
3198 * Test program used for configure/test
3199 */
3200
3201 #ifdef CONFIGURE_TEST_SIGSEGV_RECOVERY
3202 #include <stdio.h>
3203 #include <stdlib.h>
3204 #include <fcntl.h>
3205 #ifdef HAVE_SYS_MMAN_H
3206 #include <sys/mman.h>
3207 #endif
3208 #include "vm_alloc.h"
3209
3210 const int REF_INDEX = 123;
3211 const int REF_VALUE = 45;
3212
3213 static sigsegv_uintptr_t page_size;
3214 static volatile char * page = 0;
3215 static volatile int handler_called = 0;
3216
3217 /* Barriers */
3218 #ifdef __GNUC__
3219 #define BARRIER() asm volatile ("" : : : "memory")
3220 #else
3221 #define BARRIER() /* nothing */
3222 #endif
3223
3224 #ifdef __GNUC__
3225 // Code range where we expect the fault to come from
3226 static void *b_region, *e_region;
3227 #endif
3228
3229 static sigsegv_return_t sigsegv_test_handler(sigsegv_info_t *sip)
3230 {
3231 const sigsegv_address_t fault_address = sigsegv_get_fault_address(sip);
3232 const sigsegv_address_t instruction_address = sigsegv_get_fault_instruction_address(sip);
3233 #if DEBUG
3234 printf("sigsegv_test_handler(%p, %p)\n", fault_address, instruction_address);
3235 printf("expected fault at %p\n", page + REF_INDEX);
3236 #ifdef __GNUC__
3237 printf("expected instruction address range: %p-%p\n", b_region, e_region);
3238 #endif
3239 #endif
3240 handler_called++;
3241 if ((fault_address - REF_INDEX) != page)
3242 exit(10);
3243 #ifdef __GNUC__
3244 // Make sure reported fault instruction address falls into
3245 // expected code range
3246 if (instruction_address != SIGSEGV_INVALID_ADDRESS
3247 && ((instruction_address < (sigsegv_address_t)b_region) ||
3248 (instruction_address >= (sigsegv_address_t)e_region)))
3249 exit(11);
3250 #endif
3251 if (vm_protect((char *)((sigsegv_uintptr_t)fault_address & -page_size), page_size, VM_PAGE_READ | VM_PAGE_WRITE) != 0)
3252 exit(12);
3253 return SIGSEGV_RETURN_SUCCESS;
3254 }
3255
3256 #ifdef HAVE_SIGSEGV_SKIP_INSTRUCTION
3257 static sigsegv_return_t sigsegv_insn_handler(sigsegv_info_t *sip)
3258 {
3259 const sigsegv_address_t fault_address = sigsegv_get_fault_address(sip);
3260 const sigsegv_address_t instruction_address = sigsegv_get_fault_instruction_address(sip);
3261 #if DEBUG
3262 printf("sigsegv_insn_handler(%p, %p)\n", fault_address, instruction_address);
3263 #endif
3264 if (((sigsegv_uintptr_t)fault_address - (sigsegv_uintptr_t)page) < page_size) {
3265 #ifdef __GNUC__
3266 // Make sure reported fault instruction address falls into
3267 // expected code range
3268 if (instruction_address != SIGSEGV_INVALID_ADDRESS
3269 && ((instruction_address < (sigsegv_address_t)b_region) ||
3270 (instruction_address >= (sigsegv_address_t)e_region)))
3271 return SIGSEGV_RETURN_FAILURE;
3272 #endif
3273 return SIGSEGV_RETURN_SKIP_INSTRUCTION;
3274 }
3275
3276 return SIGSEGV_RETURN_FAILURE;
3277 }
3278
3279 // More sophisticated tests for instruction skipper
3280 static bool arch_insn_skipper_tests()
3281 {
3282 #if (defined(i386) || defined(__i386__)) || (defined(__x86_64__) || defined(_M_X64))
3283 static const unsigned char code[] = {
3284 0x8a, 0x00, // mov (%eax),%al
3285 0x8a, 0x2c, 0x18, // mov (%eax,%ebx,1),%ch
3286 0x88, 0x20, // mov %ah,(%eax)
3287 0x88, 0x08, // mov %cl,(%eax)
3288 0x66, 0x8b, 0x00, // mov (%eax),%ax
3289 0x66, 0x8b, 0x0c, 0x18, // mov (%eax,%ebx,1),%cx
3290 0x66, 0x89, 0x00, // mov %ax,(%eax)
3291 0x66, 0x89, 0x0c, 0x18, // mov %cx,(%eax,%ebx,1)
3292 0x8b, 0x00, // mov (%eax),%eax
3293 0x8b, 0x0c, 0x18, // mov (%eax,%ebx,1),%ecx
3294 0x89, 0x00, // mov %eax,(%eax)
3295 0x89, 0x0c, 0x18, // mov %ecx,(%eax,%ebx,1)
3296 #if defined(__x86_64__) || defined(_M_X64)
3297 0x44, 0x8a, 0x00, // mov (%rax),%r8b
3298 0x44, 0x8a, 0x20, // mov (%rax),%r12b
3299 0x42, 0x8a, 0x3c, 0x10, // mov (%rax,%r10,1),%dil
3300 0x44, 0x88, 0x00, // mov %r8b,(%rax)
3301 0x44, 0x88, 0x20, // mov %r12b,(%rax)
3302 0x42, 0x88, 0x3c, 0x10, // mov %dil,(%rax,%r10,1)
3303 0x66, 0x44, 0x8b, 0x00, // mov (%rax),%r8w
3304 0x66, 0x42, 0x8b, 0x0c, 0x10, // mov (%rax,%r10,1),%cx
3305 0x66, 0x44, 0x89, 0x00, // mov %r8w,(%rax)
3306 0x66, 0x42, 0x89, 0x0c, 0x10, // mov %cx,(%rax,%r10,1)
3307 0x44, 0x8b, 0x00, // mov (%rax),%r8d
3308 0x42, 0x8b, 0x0c, 0x10, // mov (%rax,%r10,1),%ecx
3309 0x44, 0x89, 0x00, // mov %r8d,(%rax)
3310 0x42, 0x89, 0x0c, 0x10, // mov %ecx,(%rax,%r10,1)
3311 0x48, 0x8b, 0x08, // mov (%rax),%rcx
3312 0x4c, 0x8b, 0x18, // mov (%rax),%r11
3313 0x4a, 0x8b, 0x0c, 0x10, // mov (%rax,%r10,1),%rcx
3314 0x4e, 0x8b, 0x1c, 0x10, // mov (%rax,%r10,1),%r11
3315 0x48, 0x89, 0x08, // mov %rcx,(%rax)
3316 0x4c, 0x89, 0x18, // mov %r11,(%rax)
3317 0x4a, 0x89, 0x0c, 0x10, // mov %rcx,(%rax,%r10,1)
3318 0x4e, 0x89, 0x1c, 0x10, // mov %r11,(%rax,%r10,1)
3319 0x63, 0x47, 0x04, // movslq 4(%rdi),%eax
3320 0x48, 0x63, 0x47, 0x04, // movslq 4(%rdi),%rax
3321 #endif
3322 0 // end
3323 };
3324 const int N_REGS = 20;
3325 SIGSEGV_REGISTER_TYPE regs[N_REGS];
3326 for (int i = 0; i < N_REGS; i++)
3327 regs[i] = i;
3328 const sigsegv_uintptr_t start_code = (sigsegv_uintptr_t)&code;
3329 regs[X86_REG_EIP] = start_code;
3330 while ((regs[X86_REG_EIP] - start_code) < (sizeof(code) - 1)
3331 && ix86_skip_instruction(regs))
3332 ; /* simply iterate */
3333 return (regs[X86_REG_EIP] - start_code) == (sizeof(code) - 1);
3334 #endif
3335 return true;
3336 }
3337 #endif
3338
3339 int main(void)
3340 {
3341 if (vm_init() < 0)
3342 return 1;
3343
3344 page_size = vm_get_page_size();
3345 if ((page = (char *)vm_acquire(page_size)) == VM_MAP_FAILED)
3346 return 2;
3347
3348 memset((void *)page, 0, page_size);
3349 if (vm_protect((char *)page, page_size, VM_PAGE_READ) < 0)
3350 return 3;
3351
3352 if (!sigsegv_install_handler(sigsegv_test_handler))
3353 return 4;
3354
3355 #ifdef __GNUC__
3356 b_region = &&L_b_region1;
3357 e_region = &&L_e_region1;
3358 #endif
3359 /* This is a really awful hack but otherwise gcc is smart enough
3360 * (or bug'ous enough?) to optimize the labels and place them
3361 * e.g. at the "main" entry point, which is wrong.
3362 */
3363 volatile int label_hack = 1;
3364 switch (label_hack) {
3365 case 1:
3366 L_b_region1:
3367 page[REF_INDEX] = REF_VALUE;
3368 if (page[REF_INDEX] != REF_VALUE)
3369 exit(20);
3370 page[REF_INDEX] = REF_VALUE;
3371 BARRIER();
3372 // fall-through
3373 case 2:
3374 L_e_region1:
3375 BARRIER();
3376 break;
3377 }
3378
3379 if (handler_called != 1)
3380 return 5;
3381
3382 #ifdef HAVE_SIGSEGV_SKIP_INSTRUCTION
3383 if (!sigsegv_install_handler(sigsegv_insn_handler))
3384 return 6;
3385
3386 if (vm_protect((char *)page, page_size, VM_PAGE_READ | VM_PAGE_WRITE) < 0)
3387 return 7;
3388
3389 for (int i = 0; i < page_size; i++)
3390 page[i] = (i + 1) % page_size;
3391
3392 if (vm_protect((char *)page, page_size, VM_PAGE_NOACCESS) < 0)
3393 return 8;
3394
3395 #define TEST_SKIP_INSTRUCTION(TYPE) do { \
3396 const unsigned long TAG = 0x12345678 | \
3397 (sizeof(long) == 8 ? 0x9abcdef0UL << 31 : 0); \
3398 TYPE data = *((TYPE *)(page + sizeof(TYPE))); \
3399 volatile unsigned long effect = data + TAG; \
3400 if (effect != TAG) \
3401 return 9; \
3402 } while (0)
3403
3404 #ifdef __GNUC__
3405 b_region = &&L_b_region2;
3406 e_region = &&L_e_region2;
3407 #endif
3408 switch (label_hack) {
3409 case 1:
3410 L_b_region2:
3411 TEST_SKIP_INSTRUCTION(unsigned char);
3412 TEST_SKIP_INSTRUCTION(unsigned short);
3413 TEST_SKIP_INSTRUCTION(unsigned int);
3414 TEST_SKIP_INSTRUCTION(unsigned long);
3415 TEST_SKIP_INSTRUCTION(signed char);
3416 TEST_SKIP_INSTRUCTION(signed short);
3417 TEST_SKIP_INSTRUCTION(signed int);
3418 TEST_SKIP_INSTRUCTION(signed long);
3419 BARRIER();
3420 // fall-through
3421 case 2:
3422 L_e_region2:
3423 BARRIER();
3424 break;
3425 }
3426 if (!arch_insn_skipper_tests())
3427 return 20;
3428 #endif
3429
3430 vm_exit();
3431 return 0;
3432 }
3433 #endif