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:
gbeauche 2003-05-14 06:50:05 +00:00
parent 94ec8c82ca
commit deb3da2e9f
3 changed files with 136 additions and 78 deletions

View File

@ -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

View File

@ -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; \

View File

@ -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);