1 /*
2  * sigsegv_linux_x86.cpp - x86/x86_64 Linux SIGSEGV handler
3  *
4  * Copyright (c) 2001-2005 Milan Jurik of ARAnyM dev team (see AUTHORS)
5  *
6  * Inspired by Bernie Meyer's UAE-JIT and Gwenole Beauchesne's Basilisk II-JIT
7  *
8  * This file is part of the ARAnyM project which builds a new and powerful
9  * TOS/FreeMiNT compatible virtual machine running on almost any hardware.
10  *
11  * ARAnyM is free software; you can redistribute it and/or modify
12  * it under the terms of the GNU General Public License as published by
13  * the Free Software Foundation; either version 2 of the License, or
14  * (at your option) any later version.
15  *
16  * ARAnyM is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with ARAnyM; if not, write to the Free Software
23  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
24  *
25  * 2013-06-16 : Adapted to 64 Bit Linux - Jens Heitmann
26  * 2014-07-05 : Merged with 64bit version,
27  *              lots of fixes - Thorsten Otto
28  *
29  */
30 
31 #include "sysdeps.h"
32 #include "cpu_emulation.h"
33 #define DEBUG 0
34 #include "debug.h"
35 
36 #include <csignal>
37 
38 #ifdef CPU_i386
39 #define REG_RIP REG_EIP
40 #define REG_RAX REG_EAX
41 #define REG_RBX REG_EBX
42 #define REG_RCX REG_ECX
43 #define REG_RDX REG_EDX
44 #define REG_RBP REG_EBP
45 #define REG_RSI REG_ESI
46 #define REG_RDI REG_EDI
47 #define REG_RSP REG_ESP
48 #endif
49 #if defined(CPU_i386) || defined(CPU_x86_64)
50 #define CONTEXT_NAME	ucp
51 #define CONTEXT_TYPE	volatile ucontext_t
52 #define CONTEXT_ATYPE	CONTEXT_TYPE *
53 #define CONTEXT_REGS    CONTEXT_NAME->uc_mcontext.gregs
54 #define CONTEXT_AEFLAGS	CONTEXT_REGS[REG_EFL]
55 #define CONTEXT_AEIP	CONTEXT_REGS[REG_RIP]
56 #define CONTEXT_AEAX	CONTEXT_REGS[REG_RAX]
57 #define CONTEXT_AEBX	CONTEXT_REGS[REG_RBX]
58 #define CONTEXT_AECX	CONTEXT_REGS[REG_RCX]
59 #define CONTEXT_AEDX	CONTEXT_REGS[REG_RDX]
60 #define CONTEXT_AEBP	CONTEXT_REGS[REG_RBP]
61 #define CONTEXT_AESI	CONTEXT_REGS[REG_RSI]
62 #define CONTEXT_AEDI	CONTEXT_REGS[REG_RDI]
63 #endif
64 
65 
66 #include "sigsegv_common_x86.h"
67 
segfault_vec(int,siginfo_t * sip,void * _ucp)68 static void segfault_vec(int /* sig */, siginfo_t *sip, void *_ucp)
69 {
70 	CONTEXT_ATYPE CONTEXT_NAME = (CONTEXT_ATYPE) _ucp;
71 	uintptr faultaddr = (uintptr)sip->si_addr;	/* CONTEXT_REGS[REG_CR2] */
72 	memptr addr = (memptr)(faultaddr - fixed_memory_offset);
73 #if DEBUG
74 	if (addr >= 0xff000000)
75 		addr &= 0x00ffffff;
76 	if (addr < 0x00f00000 || addr > 0x00ffffff) // YYY
77 		bug("\nsegfault: pc=%08x, " REG_RIP_NAME " =%p, addr=%p (0x%08x)", m68k_getpc(), (void *)CONTEXT_AEIP, sip->si_addr, addr);
78 	if (faultaddr < (uintptr)(fixed_memory_offset - 0x1000000UL)
79 #ifdef CPU_x86_64
80 		|| faultaddr >= ((uintptr)fixed_memory_offset + 0x100000000UL)
81 #endif
82 		)
83 	{
84 #ifdef HAVE_DISASM_X86
85 		if (CONTEXT_AEIP != 0)
86 		{
87 			char buf[256];
88 
89 			x86_disasm((const uint8 *)CONTEXT_AEIP, buf, 1);
90 			panicbug("%s", buf);
91 		}
92 #endif
93 		// raise(SIGBUS);
94 	}
95 #endif
96 	if (faultaddr == 0 || CONTEXT_AEIP == 0)
97 	{
98 		real_segmentationfault();
99 		/* not reached (hopefully) */
100 		return;
101 	}
102 	handle_access_fault(CONTEXT_NAME, addr);
103 }
104 
install_sigsegv()105 void install_sigsegv() {
106 	struct sigaction act;
107 	memset(&act, 0, sizeof(act));
108 	sigemptyset(&act.sa_mask);
109 	act.sa_sigaction = segfault_vec;
110 	act.sa_flags = SA_SIGINFO;
111 	sigaction(SIGSEGV, &act, NULL);
112 #if defined(CPU_x86_64) /* XXX is this really neccessary? */
113 	sigaction(SIGILL, &act, NULL);
114 #endif
115 }
116 
uninstall_sigsegv()117 void uninstall_sigsegv()
118 {
119 	signal(SIGSEGV, SIG_DFL);
120 #ifdef HW_SIGSEGV_STATISTICS
121 	for (unsigned int i = 0; i < 256; i++)
122 		if (x86_opcodes[i] != 0)
123 			bug("opcodes: %02x = %lu", i, x86_opcodes[i]);
124 #endif
125 }
126