mirror of
https://github.com/kanjitalk755/macemu.git
synced 2024-10-14 02:24:02 +00:00
New API to ignore a SIGSEGV fault. This should help on SheepShaver/x86 for now
since I still don't know why MacOS would like to write to ROM on a particular test.
This commit is contained in:
parent
94ec8c82ca
commit
deb3da2e9f
@ -357,10 +357,10 @@ int main(int argc, char **argv)
|
|||||||
if (!PrefsEditor())
|
if (!PrefsEditor())
|
||||||
QuitEmulator();
|
QuitEmulator();
|
||||||
|
|
||||||
// Register request to ignore segmentation faults
|
// Register request to ignore all segmentation faults
|
||||||
#ifdef HAVE_SIGSEGV_SKIP_INSTRUCTION
|
#ifdef HAVE_SIGSEGV_SKIP_INSTRUCTION
|
||||||
if (PrefsFindBool("ignoresegv"))
|
if (PrefsFindBool("ignoresegv"))
|
||||||
sigsegv_set_ignore_state(true);
|
sigsegv_add_ignore_range(0, ~(0UL), SIGSEGV_TRANSFER_LOAD | SIGSEGV_TRANSFER_STORE);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Register dump state function when we got mad after a segfault
|
// Register dump state function when we got mad after a segfault
|
||||||
|
@ -29,9 +29,14 @@
|
|||||||
#include "config.h"
|
#include "config.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include <list>
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
#include "sigsegv.h"
|
#include "sigsegv.h"
|
||||||
|
|
||||||
|
#ifndef NO_STD_NAMESPACE
|
||||||
|
using std::list;
|
||||||
|
#endif
|
||||||
|
|
||||||
// Return value type of a signal handler (standard type if not defined)
|
// Return value type of a signal handler (standard type if not defined)
|
||||||
#ifndef RETSIGTYPE
|
#ifndef RETSIGTYPE
|
||||||
#define RETSIGTYPE void
|
#define RETSIGTYPE void
|
||||||
@ -40,8 +45,15 @@
|
|||||||
// Type of the system signal handler
|
// Type of the system signal handler
|
||||||
typedef RETSIGTYPE (*signal_handler)(int);
|
typedef RETSIGTYPE (*signal_handler)(int);
|
||||||
|
|
||||||
// Is the fault to be ignored?
|
// Ignore range chain
|
||||||
static bool sigsegv_ignore_fault = false;
|
struct ignore_range_t {
|
||||||
|
sigsegv_address_t start;
|
||||||
|
unsigned long length;
|
||||||
|
int transfer_type;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef list<ignore_range_t> ignore_range_list_t;
|
||||||
|
ignore_range_list_t sigsegv_ignore_ranges;
|
||||||
|
|
||||||
// User's SIGSEGV handler
|
// User's SIGSEGV handler
|
||||||
static sigsegv_fault_handler_t sigsegv_fault_handler = 0;
|
static sigsegv_fault_handler_t sigsegv_fault_handler = 0;
|
||||||
@ -52,18 +64,21 @@ static sigsegv_state_dumper_t sigsegv_state_dumper = 0;
|
|||||||
// Actual SIGSEGV handler installer
|
// Actual SIGSEGV handler installer
|
||||||
static bool sigsegv_do_install_handler(int sig);
|
static bool sigsegv_do_install_handler(int sig);
|
||||||
|
|
||||||
|
// Find ignore range matching address
|
||||||
|
static inline ignore_range_list_t::iterator sigsegv_find_ignore_range(sigsegv_address_t address)
|
||||||
|
{
|
||||||
|
ignore_range_list_t::iterator it;
|
||||||
|
for (it = sigsegv_ignore_ranges.begin(); it != sigsegv_ignore_ranges.end(); it++)
|
||||||
|
if (address >= it->start && address < it->start + it->length)
|
||||||
|
break;
|
||||||
|
return it;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Instruction decoding aids
|
* Instruction decoding aids
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// Transfer type
|
|
||||||
enum transfer_type_t {
|
|
||||||
TYPE_UNKNOWN,
|
|
||||||
TYPE_LOAD,
|
|
||||||
TYPE_STORE
|
|
||||||
};
|
|
||||||
|
|
||||||
// Transfer size
|
// Transfer size
|
||||||
enum transfer_size_t {
|
enum transfer_size_t {
|
||||||
SIZE_UNKNOWN,
|
SIZE_UNKNOWN,
|
||||||
@ -83,6 +98,7 @@ enum addressing_mode_t {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Decoded instruction
|
// Decoded instruction
|
||||||
|
typedef sigsegv_transfer_type_t transfer_type_t;
|
||||||
struct instruction_t {
|
struct instruction_t {
|
||||||
transfer_type_t transfer_type;
|
transfer_type_t transfer_type;
|
||||||
transfer_size_t transfer_size;
|
transfer_size_t transfer_size;
|
||||||
@ -103,71 +119,71 @@ static void powerpc_decode_instruction(instruction_t *instruction, unsigned int
|
|||||||
signed int imm = (signed short)(opcode & 0xffff);
|
signed int imm = (signed short)(opcode & 0xffff);
|
||||||
|
|
||||||
// Analyze opcode
|
// Analyze opcode
|
||||||
transfer_type_t transfer_type = TYPE_UNKNOWN;
|
transfer_type_t transfer_type = SIGSEGV_TRANSFER_UNKNOWN;
|
||||||
transfer_size_t transfer_size = SIZE_UNKNOWN;
|
transfer_size_t transfer_size = SIZE_UNKNOWN;
|
||||||
addressing_mode_t addr_mode = MODE_UNKNOWN;
|
addressing_mode_t addr_mode = MODE_UNKNOWN;
|
||||||
switch (primop) {
|
switch (primop) {
|
||||||
case 31:
|
case 31:
|
||||||
switch (exop) {
|
switch (exop) {
|
||||||
case 23: // lwzx
|
case 23: // lwzx
|
||||||
transfer_type = TYPE_LOAD; transfer_size = SIZE_LONG; addr_mode = MODE_X; break;
|
transfer_type = SIGSEGV_TRANSFER_LOAD; transfer_size = SIZE_LONG; addr_mode = MODE_X; break;
|
||||||
case 55: // lwzux
|
case 55: // lwzux
|
||||||
transfer_type = TYPE_LOAD; transfer_size = SIZE_LONG; addr_mode = MODE_UX; break;
|
transfer_type = SIGSEGV_TRANSFER_LOAD; transfer_size = SIZE_LONG; addr_mode = MODE_UX; break;
|
||||||
case 87: // lbzx
|
case 87: // lbzx
|
||||||
transfer_type = TYPE_LOAD; transfer_size = SIZE_BYTE; addr_mode = MODE_X; break;
|
transfer_type = SIGSEGV_TRANSFER_LOAD; transfer_size = SIZE_BYTE; addr_mode = MODE_X; break;
|
||||||
case 119: // lbzux
|
case 119: // lbzux
|
||||||
transfer_type = TYPE_LOAD; transfer_size = SIZE_BYTE; addr_mode = MODE_UX; break;
|
transfer_type = SIGSEGV_TRANSFER_LOAD; transfer_size = SIZE_BYTE; addr_mode = MODE_UX; break;
|
||||||
case 151: // stwx
|
case 151: // stwx
|
||||||
transfer_type = TYPE_STORE; transfer_size = SIZE_LONG; addr_mode = MODE_X; break;
|
transfer_type = SIGSEGV_TRANSFER_STORE; transfer_size = SIZE_LONG; addr_mode = MODE_X; break;
|
||||||
case 183: // stwux
|
case 183: // stwux
|
||||||
transfer_type = TYPE_STORE; transfer_size = SIZE_LONG; addr_mode = MODE_UX; break;
|
transfer_type = SIGSEGV_TRANSFER_STORE; transfer_size = SIZE_LONG; addr_mode = MODE_UX; break;
|
||||||
case 215: // stbx
|
case 215: // stbx
|
||||||
transfer_type = TYPE_STORE; transfer_size = SIZE_BYTE; addr_mode = MODE_X; break;
|
transfer_type = SIGSEGV_TRANSFER_STORE; transfer_size = SIZE_BYTE; addr_mode = MODE_X; break;
|
||||||
case 247: // stbux
|
case 247: // stbux
|
||||||
transfer_type = TYPE_STORE; transfer_size = SIZE_BYTE; addr_mode = MODE_UX; break;
|
transfer_type = SIGSEGV_TRANSFER_STORE; transfer_size = SIZE_BYTE; addr_mode = MODE_UX; break;
|
||||||
case 279: // lhzx
|
case 279: // lhzx
|
||||||
transfer_type = TYPE_LOAD; transfer_size = SIZE_WORD; addr_mode = MODE_X; break;
|
transfer_type = SIGSEGV_TRANSFER_LOAD; transfer_size = SIZE_WORD; addr_mode = MODE_X; break;
|
||||||
case 311: // lhzux
|
case 311: // lhzux
|
||||||
transfer_type = TYPE_LOAD; transfer_size = SIZE_WORD; addr_mode = MODE_UX; break;
|
transfer_type = SIGSEGV_TRANSFER_LOAD; transfer_size = SIZE_WORD; addr_mode = MODE_UX; break;
|
||||||
case 343: // lhax
|
case 343: // lhax
|
||||||
transfer_type = TYPE_LOAD; transfer_size = SIZE_WORD; addr_mode = MODE_X; break;
|
transfer_type = SIGSEGV_TRANSFER_LOAD; transfer_size = SIZE_WORD; addr_mode = MODE_X; break;
|
||||||
case 375: // lhaux
|
case 375: // lhaux
|
||||||
transfer_type = TYPE_LOAD; transfer_size = SIZE_WORD; addr_mode = MODE_UX; break;
|
transfer_type = SIGSEGV_TRANSFER_LOAD; transfer_size = SIZE_WORD; addr_mode = MODE_UX; break;
|
||||||
case 407: // sthx
|
case 407: // sthx
|
||||||
transfer_type = TYPE_STORE; transfer_size = SIZE_WORD; addr_mode = MODE_X; break;
|
transfer_type = SIGSEGV_TRANSFER_STORE; transfer_size = SIZE_WORD; addr_mode = MODE_X; break;
|
||||||
case 439: // sthux
|
case 439: // sthux
|
||||||
transfer_type = TYPE_STORE; transfer_size = SIZE_WORD; addr_mode = MODE_UX; break;
|
transfer_type = SIGSEGV_TRANSFER_STORE; transfer_size = SIZE_WORD; addr_mode = MODE_UX; break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 32: // lwz
|
case 32: // lwz
|
||||||
transfer_type = TYPE_LOAD; transfer_size = SIZE_LONG; addr_mode = MODE_NORM; break;
|
transfer_type = SIGSEGV_TRANSFER_LOAD; transfer_size = SIZE_LONG; addr_mode = MODE_NORM; break;
|
||||||
case 33: // lwzu
|
case 33: // lwzu
|
||||||
transfer_type = TYPE_LOAD; transfer_size = SIZE_LONG; addr_mode = MODE_U; break;
|
transfer_type = SIGSEGV_TRANSFER_LOAD; transfer_size = SIZE_LONG; addr_mode = MODE_U; break;
|
||||||
case 34: // lbz
|
case 34: // lbz
|
||||||
transfer_type = TYPE_LOAD; transfer_size = SIZE_BYTE; addr_mode = MODE_NORM; break;
|
transfer_type = SIGSEGV_TRANSFER_LOAD; transfer_size = SIZE_BYTE; addr_mode = MODE_NORM; break;
|
||||||
case 35: // lbzu
|
case 35: // lbzu
|
||||||
transfer_type = TYPE_LOAD; transfer_size = SIZE_BYTE; addr_mode = MODE_U; break;
|
transfer_type = SIGSEGV_TRANSFER_LOAD; transfer_size = SIZE_BYTE; addr_mode = MODE_U; break;
|
||||||
case 36: // stw
|
case 36: // stw
|
||||||
transfer_type = TYPE_STORE; transfer_size = SIZE_LONG; addr_mode = MODE_NORM; break;
|
transfer_type = SIGSEGV_TRANSFER_STORE; transfer_size = SIZE_LONG; addr_mode = MODE_NORM; break;
|
||||||
case 37: // stwu
|
case 37: // stwu
|
||||||
transfer_type = TYPE_STORE; transfer_size = SIZE_LONG; addr_mode = MODE_U; break;
|
transfer_type = SIGSEGV_TRANSFER_STORE; transfer_size = SIZE_LONG; addr_mode = MODE_U; break;
|
||||||
case 38: // stb
|
case 38: // stb
|
||||||
transfer_type = TYPE_STORE; transfer_size = SIZE_BYTE; addr_mode = MODE_NORM; break;
|
transfer_type = SIGSEGV_TRANSFER_STORE; transfer_size = SIZE_BYTE; addr_mode = MODE_NORM; break;
|
||||||
case 39: // stbu
|
case 39: // stbu
|
||||||
transfer_type = TYPE_STORE; transfer_size = SIZE_BYTE; addr_mode = MODE_U; break;
|
transfer_type = SIGSEGV_TRANSFER_STORE; transfer_size = SIZE_BYTE; addr_mode = MODE_U; break;
|
||||||
case 40: // lhz
|
case 40: // lhz
|
||||||
transfer_type = TYPE_LOAD; transfer_size = SIZE_WORD; addr_mode = MODE_NORM; break;
|
transfer_type = SIGSEGV_TRANSFER_LOAD; transfer_size = SIZE_WORD; addr_mode = MODE_NORM; break;
|
||||||
case 41: // lhzu
|
case 41: // lhzu
|
||||||
transfer_type = TYPE_LOAD; transfer_size = SIZE_WORD; addr_mode = MODE_U; break;
|
transfer_type = SIGSEGV_TRANSFER_LOAD; transfer_size = SIZE_WORD; addr_mode = MODE_U; break;
|
||||||
case 42: // lha
|
case 42: // lha
|
||||||
transfer_type = TYPE_LOAD; transfer_size = SIZE_WORD; addr_mode = MODE_NORM; break;
|
transfer_type = SIGSEGV_TRANSFER_LOAD; transfer_size = SIZE_WORD; addr_mode = MODE_NORM; break;
|
||||||
case 43: // lhau
|
case 43: // lhau
|
||||||
transfer_type = TYPE_LOAD; transfer_size = SIZE_WORD; addr_mode = MODE_U; break;
|
transfer_type = SIGSEGV_TRANSFER_LOAD; transfer_size = SIZE_WORD; addr_mode = MODE_U; break;
|
||||||
case 44: // sth
|
case 44: // sth
|
||||||
transfer_type = TYPE_STORE; transfer_size = SIZE_WORD; addr_mode = MODE_NORM; break;
|
transfer_type = SIGSEGV_TRANSFER_STORE; transfer_size = SIZE_WORD; addr_mode = MODE_NORM; break;
|
||||||
case 45: // sthu
|
case 45: // sthu
|
||||||
transfer_type = TYPE_STORE; transfer_size = SIZE_WORD; addr_mode = MODE_U; break;
|
transfer_type = SIGSEGV_TRANSFER_STORE; transfer_size = SIZE_WORD; addr_mode = MODE_U; break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Calculate effective address
|
// Calculate effective address
|
||||||
@ -455,7 +471,7 @@ static bool ix86_skip_instruction(unsigned int * regs)
|
|||||||
if (eip == 0)
|
if (eip == 0)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
transfer_type_t transfer_type = TYPE_UNKNOWN;
|
transfer_type_t transfer_type = SIGSEGV_TRANSFER_UNKNOWN;
|
||||||
transfer_size_t transfer_size = SIZE_LONG;
|
transfer_size_t transfer_size = SIZE_LONG;
|
||||||
|
|
||||||
int reg = -1;
|
int reg = -1;
|
||||||
@ -477,15 +493,15 @@ static bool ix86_skip_instruction(unsigned int * regs)
|
|||||||
switch (eip[2] & 0xc0) {
|
switch (eip[2] & 0xc0) {
|
||||||
case 0x80:
|
case 0x80:
|
||||||
reg = (eip[2] >> 3) & 7;
|
reg = (eip[2] >> 3) & 7;
|
||||||
transfer_type = TYPE_LOAD;
|
transfer_type = SIGSEGV_TRANSFER_LOAD;
|
||||||
break;
|
break;
|
||||||
case 0x40:
|
case 0x40:
|
||||||
reg = (eip[2] >> 3) & 7;
|
reg = (eip[2] >> 3) & 7;
|
||||||
transfer_type = TYPE_LOAD;
|
transfer_type = SIGSEGV_TRANSFER_LOAD;
|
||||||
break;
|
break;
|
||||||
case 0x00:
|
case 0x00:
|
||||||
reg = (eip[2] >> 3) & 7;
|
reg = (eip[2] >> 3) & 7;
|
||||||
transfer_type = TYPE_LOAD;
|
transfer_type = SIGSEGV_TRANSFER_LOAD;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
len += 3 + ix86_step_over_modrm(eip + 2);
|
len += 3 + ix86_step_over_modrm(eip + 2);
|
||||||
@ -498,15 +514,15 @@ static bool ix86_skip_instruction(unsigned int * regs)
|
|||||||
switch (eip[1] & 0xc0) {
|
switch (eip[1] & 0xc0) {
|
||||||
case 0x80:
|
case 0x80:
|
||||||
reg = (eip[1] >> 3) & 7;
|
reg = (eip[1] >> 3) & 7;
|
||||||
transfer_type = TYPE_LOAD;
|
transfer_type = SIGSEGV_TRANSFER_LOAD;
|
||||||
break;
|
break;
|
||||||
case 0x40:
|
case 0x40:
|
||||||
reg = (eip[1] >> 3) & 7;
|
reg = (eip[1] >> 3) & 7;
|
||||||
transfer_type = TYPE_LOAD;
|
transfer_type = SIGSEGV_TRANSFER_LOAD;
|
||||||
break;
|
break;
|
||||||
case 0x00:
|
case 0x00:
|
||||||
reg = (eip[1] >> 3) & 7;
|
reg = (eip[1] >> 3) & 7;
|
||||||
transfer_type = TYPE_LOAD;
|
transfer_type = SIGSEGV_TRANSFER_LOAD;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
len += 2 + ix86_step_over_modrm(eip + 1);
|
len += 2 + ix86_step_over_modrm(eip + 1);
|
||||||
@ -517,27 +533,27 @@ static bool ix86_skip_instruction(unsigned int * regs)
|
|||||||
switch (eip[1] & 0xc0) {
|
switch (eip[1] & 0xc0) {
|
||||||
case 0x80:
|
case 0x80:
|
||||||
reg = (eip[1] >> 3) & 7;
|
reg = (eip[1] >> 3) & 7;
|
||||||
transfer_type = TYPE_STORE;
|
transfer_type = SIGSEGV_TRANSFER_STORE;
|
||||||
break;
|
break;
|
||||||
case 0x40:
|
case 0x40:
|
||||||
reg = (eip[1] >> 3) & 7;
|
reg = (eip[1] >> 3) & 7;
|
||||||
transfer_type = TYPE_STORE;
|
transfer_type = SIGSEGV_TRANSFER_STORE;
|
||||||
break;
|
break;
|
||||||
case 0x00:
|
case 0x00:
|
||||||
reg = (eip[1] >> 3) & 7;
|
reg = (eip[1] >> 3) & 7;
|
||||||
transfer_type = TYPE_STORE;
|
transfer_type = SIGSEGV_TRANSFER_STORE;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
len += 2 + ix86_step_over_modrm(eip + 1);
|
len += 2 + ix86_step_over_modrm(eip + 1);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (transfer_type == TYPE_UNKNOWN) {
|
if (transfer_type == SIGSEGV_TRANSFER_UNKNOWN) {
|
||||||
// Unknown machine code, let it crash. Then patch the decoder
|
// Unknown machine code, let it crash. Then patch the decoder
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (transfer_type == TYPE_LOAD && reg != -1) {
|
if (transfer_type == SIGSEGV_TRANSFER_LOAD && reg != -1) {
|
||||||
static const int x86_reg_map[8] = {
|
static const int x86_reg_map[8] = {
|
||||||
X86_REG_EAX, X86_REG_ECX, X86_REG_EDX, X86_REG_EBX,
|
X86_REG_EAX, X86_REG_ECX, X86_REG_EDX, X86_REG_EBX,
|
||||||
X86_REG_ESP, X86_REG_EBP, X86_REG_ESI, X86_REG_EDI
|
X86_REG_ESP, X86_REG_EBP, X86_REG_ESI, X86_REG_EDI
|
||||||
@ -563,14 +579,14 @@ static bool ix86_skip_instruction(unsigned int * regs)
|
|||||||
#if DEBUG
|
#if DEBUG
|
||||||
printf("%08x: %s %s access", regs[X86_REG_EIP],
|
printf("%08x: %s %s access", regs[X86_REG_EIP],
|
||||||
transfer_size == SIZE_BYTE ? "byte" : transfer_size == SIZE_WORD ? "word" : "long",
|
transfer_size == SIZE_BYTE ? "byte" : transfer_size == SIZE_WORD ? "word" : "long",
|
||||||
transfer_type == TYPE_LOAD ? "read" : "write");
|
transfer_type == SIGSEGV_TRANSFER_LOAD ? "read" : "write");
|
||||||
|
|
||||||
if (reg != -1) {
|
if (reg != -1) {
|
||||||
static const char * x86_reg_str_map[8] = {
|
static const char * x86_reg_str_map[8] = {
|
||||||
"eax", "ecx", "edx", "ebx",
|
"eax", "ecx", "edx", "ebx",
|
||||||
"esp", "ebp", "esi", "edi"
|
"esp", "ebp", "esi", "edi"
|
||||||
};
|
};
|
||||||
printf(" %s register %%%s", transfer_type == TYPE_LOAD ? "to" : "from", x86_reg_str_map[reg]);
|
printf(" %s register %%%s", transfer_type == SIGSEGV_TRANSFER_LOAD ? "to" : "from", x86_reg_str_map[reg]);
|
||||||
}
|
}
|
||||||
printf(", %d bytes instruction\n", len);
|
printf(", %d bytes instruction\n", len);
|
||||||
#endif
|
#endif
|
||||||
@ -587,25 +603,31 @@ static bool powerpc_skip_instruction(unsigned int * nip_p, unsigned int * regs)
|
|||||||
instruction_t instr;
|
instruction_t instr;
|
||||||
powerpc_decode_instruction(&instr, *nip_p, regs);
|
powerpc_decode_instruction(&instr, *nip_p, regs);
|
||||||
|
|
||||||
if (instr.transfer_type == TYPE_UNKNOWN) {
|
if (instr.transfer_type == SIGSEGV_TRANSFER_UNKNOWN) {
|
||||||
// Unknown machine code, let it crash. Then patch the decoder
|
// Unknown machine code, let it crash. Then patch the decoder
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ignore_range_list_t::iterator it = sigsegv_find_ignore_range((sigsegv_address_t)instr.addr);
|
||||||
|
if (it == sigsegv_ignore_ranges.end() || ((it->transfer_type & instr.transfer_type) != instr.transfer_type)) {
|
||||||
|
// Address doesn't fall into ignore ranges list, let it crash.
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
printf("%08x: %s %s access", *nip_p,
|
printf("%08x: %s %s access", *nip_p,
|
||||||
instr.transfer_size == SIZE_BYTE ? "byte" : instr.transfer_size == SIZE_WORD ? "word" : "long",
|
instr.transfer_size == SIZE_BYTE ? "byte" : instr.transfer_size == SIZE_WORD ? "word" : "long",
|
||||||
instr.transfer_type == TYPE_LOAD ? "read" : "write");
|
instr.transfer_type == SIGSEGV_TRANSFER_LOAD ? "read" : "write");
|
||||||
|
|
||||||
if (instr.addr_mode == MODE_U || instr.addr_mode == MODE_UX)
|
if (instr.addr_mode == MODE_U || instr.addr_mode == MODE_UX)
|
||||||
printf(" r%d (ra = %08x)\n", instr.ra, instr.addr);
|
printf(" r%d (ra = %08x)\n", instr.ra, instr.addr);
|
||||||
if (instr.transfer_type == TYPE_LOAD)
|
if (instr.transfer_type == SIGSEGV_TRANSFER_LOAD)
|
||||||
printf(" r%d (rd = 0)\n", instr.rd);
|
printf(" r%d (rd = 0)\n", instr.rd);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (instr.addr_mode == MODE_U || instr.addr_mode == MODE_UX)
|
if (instr.addr_mode == MODE_U || instr.addr_mode == MODE_UX)
|
||||||
regs[instr.ra] = instr.addr;
|
regs[instr.ra] = instr.addr;
|
||||||
if (instr.transfer_type == TYPE_LOAD)
|
if (instr.transfer_type == SIGSEGV_TRANSFER_LOAD)
|
||||||
regs[instr.rd] = 0;
|
regs[instr.rd] = 0;
|
||||||
|
|
||||||
*nip_p += 4;
|
*nip_p += 4;
|
||||||
@ -644,7 +666,7 @@ static void sigsegv_handler(SIGSEGV_FAULT_HANDLER_ARGLIST)
|
|||||||
fault_recovered = true;
|
fault_recovered = true;
|
||||||
}
|
}
|
||||||
#if HAVE_SIGSEGV_SKIP_INSTRUCTION
|
#if HAVE_SIGSEGV_SKIP_INSTRUCTION
|
||||||
else if (sigsegv_ignore_fault) {
|
else if (sigsegv_ignore_ranges.size() > 0) {
|
||||||
// Call the instruction skipper with the register file available
|
// Call the instruction skipper with the register file available
|
||||||
if (SIGSEGV_SKIP_INSTRUCTION(SIGSEGV_REGISTER_FILE))
|
if (SIGSEGV_SKIP_INSTRUCTION(SIGSEGV_REGISTER_FILE))
|
||||||
fault_recovered = true;
|
fault_recovered = true;
|
||||||
@ -674,11 +696,11 @@ static bool sigsegv_do_install_handler(int sig)
|
|||||||
{
|
{
|
||||||
// Setup SIGSEGV handler to process writes to frame buffer
|
// Setup SIGSEGV handler to process writes to frame buffer
|
||||||
#ifdef HAVE_SIGACTION
|
#ifdef HAVE_SIGACTION
|
||||||
struct sigaction vosf_sa;
|
struct sigaction sigsegv_sa;
|
||||||
sigemptyset(&vosf_sa.sa_mask);
|
sigemptyset(&sigsegv_sa.sa_mask);
|
||||||
vosf_sa.sa_sigaction = sigsegv_handler;
|
sigsegv_sa.sa_sigaction = sigsegv_handler;
|
||||||
vosf_sa.sa_flags = SA_SIGINFO;
|
sigsegv_sa.sa_flags = SA_SIGINFO;
|
||||||
return (sigaction(sig, &vosf_sa, 0) == 0);
|
return (sigaction(sig, &sigsegv_sa, 0) == 0);
|
||||||
#else
|
#else
|
||||||
return (signal(sig, (signal_handler)sigsegv_handler) != SIG_ERR);
|
return (signal(sig, (signal_handler)sigsegv_handler) != SIG_ERR);
|
||||||
#endif
|
#endif
|
||||||
@ -690,16 +712,15 @@ static bool sigsegv_do_install_handler(int sig)
|
|||||||
{
|
{
|
||||||
// Setup SIGSEGV handler to process writes to frame buffer
|
// Setup SIGSEGV handler to process writes to frame buffer
|
||||||
#ifdef HAVE_SIGACTION
|
#ifdef HAVE_SIGACTION
|
||||||
struct sigaction vosf_sa;
|
struct sigaction sigsegv_sa;
|
||||||
sigemptyset(&vosf_sa.sa_mask);
|
sigemptyset(&sigsegv_sa.sa_mask);
|
||||||
vosf_sa.sa_handler = (signal_handler)sigsegv_handler;
|
sigsegv_sa.sa_handler = (signal_handler)sigsegv_handler;
|
||||||
|
sigsegv_sa.sa_flags = 0;
|
||||||
#if !EMULATED_68K && defined(__NetBSD__)
|
#if !EMULATED_68K && defined(__NetBSD__)
|
||||||
sigaddset(&vosf_sa.sa_mask, SIGALRM);
|
sigaddset(&sigsegv_sa.sa_mask, SIGALRM);
|
||||||
vosf_sa.sa_flags = SA_ONSTACK;
|
sigsegv_sa.sa_flags |= SA_ONSTACK;
|
||||||
#else
|
|
||||||
vosf_sa.sa_flags = 0;
|
|
||||||
#endif
|
#endif
|
||||||
return (sigaction(sig, &vosf_sa, 0) == 0);
|
return (sigaction(sig, &sigsegv_sa, 0) == 0);
|
||||||
#else
|
#else
|
||||||
return (signal(sig, (signal_handler)sigsegv_handler) != SIG_ERR);
|
return (signal(sig, (signal_handler)sigsegv_handler) != SIG_ERR);
|
||||||
#endif
|
#endif
|
||||||
@ -738,12 +759,39 @@ void sigsegv_deinstall_handler(void)
|
|||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* SIGSEGV ignore state modifier
|
* Add SIGSEGV ignore range
|
||||||
*/
|
*/
|
||||||
|
|
||||||
void sigsegv_set_ignore_state(bool ignore_fault)
|
void sigsegv_add_ignore_range(sigsegv_address_t address, unsigned long length, int transfer_type)
|
||||||
{
|
{
|
||||||
sigsegv_ignore_fault = ignore_fault;
|
ignore_range_t ignore_range;
|
||||||
|
ignore_range.start = address;
|
||||||
|
ignore_range.length = length;
|
||||||
|
ignore_range.transfer_type = transfer_type;
|
||||||
|
sigsegv_ignore_ranges.push_front(ignore_range);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Remove SIGSEGV ignore range. Range must match installed one, otherwise FALSE is returned.
|
||||||
|
*/
|
||||||
|
|
||||||
|
bool sigsegv_remove_ignore_range(sigsegv_address_t address, unsigned long length, int transfer_type)
|
||||||
|
{
|
||||||
|
ignore_range_list_t::iterator it;
|
||||||
|
for (it = sigsegv_ignore_ranges.begin(); it != sigsegv_ignore_ranges.end(); it++)
|
||||||
|
if (it->start == address && it->length == length && ((it->transfer_type & transfer_type) == transfer_type))
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (it != sigsegv_ignore_ranges.end()) {
|
||||||
|
if (it->transfer_type != transfer_type)
|
||||||
|
it->transfer_type &= ~transfer_type;
|
||||||
|
else
|
||||||
|
sigsegv_ignore_ranges.erase(it);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -823,7 +871,7 @@ int main(void)
|
|||||||
if (vm_protect((char *)page, page_size, VM_PAGE_NOACCESS) < 0)
|
if (vm_protect((char *)page, page_size, VM_PAGE_NOACCESS) < 0)
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
sigsegv_set_ignore_state(true);
|
sigsegv_add_ignore_range((char *)page, page_size, SIGSEGV_TRANSFER_LOAD | SIGSEGV_TRANSFER_STORE);
|
||||||
|
|
||||||
#define TEST_SKIP_INSTRUCTION(TYPE) do { \
|
#define TEST_SKIP_INSTRUCTION(TYPE) do { \
|
||||||
const unsigned int TAG = 0x12345678; \
|
const unsigned int TAG = 0x12345678; \
|
||||||
|
@ -27,6 +27,13 @@
|
|||||||
// Address type
|
// Address type
|
||||||
typedef char * sigsegv_address_t;
|
typedef char * sigsegv_address_t;
|
||||||
|
|
||||||
|
// Transfer type (intended to be used a mask for sigsegv_*_ignore_range())
|
||||||
|
enum sigsegv_transfer_type_t {
|
||||||
|
SIGSEGV_TRANSFER_UNKNOWN = 0,
|
||||||
|
SIGSEGV_TRANSFER_LOAD = 1,
|
||||||
|
SIGSEGV_TRANSFER_STORE = 2,
|
||||||
|
};
|
||||||
|
|
||||||
// Type of a SIGSEGV handler. Returns boolean expressing successful operation
|
// Type of a SIGSEGV handler. Returns boolean expressing successful operation
|
||||||
typedef bool (*sigsegv_fault_handler_t)(sigsegv_address_t fault_address, sigsegv_address_t instruction_address);
|
typedef bool (*sigsegv_fault_handler_t)(sigsegv_address_t fault_address, sigsegv_address_t instruction_address);
|
||||||
|
|
||||||
@ -39,8 +46,11 @@ extern bool sigsegv_install_handler(sigsegv_fault_handler_t handler);
|
|||||||
// Remove the user SIGSEGV handler, revert to default behavior
|
// Remove the user SIGSEGV handler, revert to default behavior
|
||||||
extern void sigsegv_uninstall_handler(void);
|
extern void sigsegv_uninstall_handler(void);
|
||||||
|
|
||||||
// Set SIGSEGV ignore state
|
// Add SIGSEGV ignore range
|
||||||
extern void sigsegv_set_ignore_state(bool ignore_fault);
|
extern void sigsegv_add_ignore_range(sigsegv_address_t address, unsigned long length, int transfer_type);
|
||||||
|
|
||||||
|
// Remove SIGSEGV ignore range. Range must match installed one, otherwise FALSE is returned.
|
||||||
|
extern bool sigsegv_remove_ignore_range(sigsegv_address_t address, unsigned long length, int transfer_type);
|
||||||
|
|
||||||
// Set callback function when we cannot handle the fault
|
// Set callback function when we cannot handle the fault
|
||||||
extern void sigsegv_set_dump_state(sigsegv_state_dumper_t handler);
|
extern void sigsegv_set_dump_state(sigsegv_state_dumper_t handler);
|
||||||
|
Loading…
Reference in New Issue
Block a user