Implement "ignoresegv" feature on Darwin/ppc (tested on MacOS X)

- Unix/sigsegv.cpp (powerpc_decode_instruction): New.
  (get_fault_instruction [MacOS X]): Factorize code.
  (get_fault_instruction [Linux/m68k]): Don't use expression statement.
- README (ignoresegv): Add Darwin/ppc to list of supported platforms.
This commit is contained in:
gbeauche 2002-05-20 15:56:13 +00:00
parent c47819020c
commit e81b9ace6d
2 changed files with 215 additions and 266 deletions

View File

@ -578,7 +578,7 @@ Unix:
Set this to "true" to ignore illegal memory accesses. The default Set this to "true" to ignore illegal memory accesses. The default
is "false". This feature is only implemented on the following is "false". This feature is only implemented on the following
platforms: Linux/x86, Linux/ppc. platforms: Linux/x86, Linux/ppc, Darwin/ppc.
AmigaOS: AmigaOS:

View File

@ -53,6 +53,155 @@ static sigsegv_state_dumper_t sigsegv_state_dumper = 0;
static bool sigsegv_do_install_handler(int sig); static bool sigsegv_do_install_handler(int sig);
/*
* Instruction decoding aids
*/
// Transfer type
enum transfer_type_t {
TYPE_UNKNOWN,
TYPE_LOAD,
TYPE_STORE
};
// Transfer size
enum transfer_size_t {
SIZE_UNKNOWN,
SIZE_BYTE,
SIZE_WORD,
SIZE_LONG
};
#if (defined(powerpc) || defined(__powerpc__) || defined(__ppc__))
// Addressing mode
enum addressing_mode_t {
MODE_UNKNOWN,
MODE_NORM,
MODE_U,
MODE_X,
MODE_UX
};
// Decoded instruction
struct instruction_t {
transfer_type_t transfer_type;
transfer_size_t transfer_size;
addressing_mode_t addr_mode;
unsigned int addr;
char ra, rd;
};
static void powerpc_decode_instruction(instruction_t *instruction, unsigned int nip, unsigned int * gpr)
{
// Get opcode and divide into fields
unsigned int opcode = *((unsigned int *)nip);
unsigned int primop = opcode >> 26;
unsigned int exop = (opcode >> 1) & 0x3ff;
unsigned int ra = (opcode >> 16) & 0x1f;
unsigned int rb = (opcode >> 11) & 0x1f;
unsigned int rd = (opcode >> 21) & 0x1f;
signed int imm = (signed short)(opcode & 0xffff);
// Analyze opcode
transfer_type_t transfer_type = TYPE_UNKNOWN;
transfer_size_t transfer_size = SIZE_UNKNOWN;
addressing_mode_t addr_mode = MODE_UNKNOWN;
switch (primop) {
case 31:
switch (exop) {
case 23: // lwzx
transfer_type = TYPE_LOAD; transfer_size = SIZE_LONG; addr_mode = MODE_X; break;
case 55: // lwzux
transfer_type = TYPE_LOAD; transfer_size = SIZE_LONG; addr_mode = MODE_UX; break;
case 87: // lbzx
transfer_type = TYPE_LOAD; transfer_size = SIZE_BYTE; addr_mode = MODE_X; break;
case 119: // lbzux
transfer_type = TYPE_LOAD; transfer_size = SIZE_BYTE; addr_mode = MODE_UX; break;
case 151: // stwx
transfer_type = TYPE_STORE; transfer_size = SIZE_LONG; addr_mode = MODE_X; break;
case 183: // stwux
transfer_type = TYPE_STORE; transfer_size = SIZE_LONG; addr_mode = MODE_UX; break;
case 215: // stbx
transfer_type = TYPE_STORE; transfer_size = SIZE_BYTE; addr_mode = MODE_X; break;
case 247: // stbux
transfer_type = TYPE_STORE; transfer_size = SIZE_BYTE; addr_mode = MODE_UX; break;
case 279: // lhzx
transfer_type = TYPE_LOAD; transfer_size = SIZE_WORD; addr_mode = MODE_X; break;
case 311: // lhzux
transfer_type = TYPE_LOAD; transfer_size = SIZE_WORD; addr_mode = MODE_UX; break;
case 343: // lhax
transfer_type = TYPE_LOAD; transfer_size = SIZE_WORD; addr_mode = MODE_X; break;
case 375: // lhaux
transfer_type = TYPE_LOAD; transfer_size = SIZE_WORD; addr_mode = MODE_UX; break;
case 407: // sthx
transfer_type = TYPE_STORE; transfer_size = SIZE_WORD; addr_mode = MODE_X; break;
case 439: // sthux
transfer_type = TYPE_STORE; transfer_size = SIZE_WORD; addr_mode = MODE_UX; break;
}
break;
case 32: // lwz
transfer_type = TYPE_LOAD; transfer_size = SIZE_LONG; addr_mode = MODE_NORM; break;
case 33: // lwzu
transfer_type = TYPE_LOAD; transfer_size = SIZE_LONG; addr_mode = MODE_U; break;
case 34: // lbz
transfer_type = TYPE_LOAD; transfer_size = SIZE_BYTE; addr_mode = MODE_NORM; break;
case 35: // lbzu
transfer_type = TYPE_LOAD; transfer_size = SIZE_BYTE; addr_mode = MODE_U; break;
case 36: // stw
transfer_type = TYPE_STORE; transfer_size = SIZE_LONG; addr_mode = MODE_NORM; break;
case 37: // stwu
transfer_type = TYPE_STORE; transfer_size = SIZE_LONG; addr_mode = MODE_U; break;
case 38: // stb
transfer_type = TYPE_STORE; transfer_size = SIZE_BYTE; addr_mode = MODE_NORM; break;
case 39: // stbu
transfer_type = TYPE_STORE; transfer_size = SIZE_BYTE; addr_mode = MODE_U; break;
case 40: // lhz
transfer_type = TYPE_LOAD; transfer_size = SIZE_WORD; addr_mode = MODE_NORM; break;
case 41: // lhzu
transfer_type = TYPE_LOAD; transfer_size = SIZE_WORD; addr_mode = MODE_U; break;
case 42: // lha
transfer_type = TYPE_LOAD; transfer_size = SIZE_WORD; addr_mode = MODE_NORM; break;
case 43: // lhau
transfer_type = TYPE_LOAD; transfer_size = SIZE_WORD; addr_mode = MODE_U; break;
case 44: // sth
transfer_type = TYPE_STORE; transfer_size = SIZE_WORD; addr_mode = MODE_NORM; break;
case 45: // sthu
transfer_type = TYPE_STORE; transfer_size = SIZE_WORD; addr_mode = MODE_U; break;
}
// Calculate effective address
unsigned int addr = 0;
switch (addr_mode) {
case MODE_X:
case MODE_UX:
if (ra == 0)
addr = gpr[rb];
else
addr = gpr[ra] + gpr[rb];
break;
case MODE_NORM:
case MODE_U:
if (ra == 0)
addr = (signed int)(signed short)imm;
else
addr = gpr[ra] + (signed int)(signed short)imm;
break;
default:
break;
}
// Commit decoded instruction
instruction->addr = addr;
instruction->addr_mode = addr_mode;
instruction->transfer_type = transfer_type;
instruction->transfer_size = transfer_size;
instruction->ra = ra;
instruction->rd = rd;
}
#endif
/* /*
* OS-dependant SIGSEGV signals support section * OS-dependant SIGSEGV signals support section
*/ */
@ -69,8 +218,9 @@ static bool sigsegv_do_install_handler(int sig);
#if defined(__linux__) #if defined(__linux__)
#if (defined(i386) || defined(__i386__)) #if (defined(i386) || defined(__i386__))
#include <sys/ucontext.h> #include <sys/ucontext.h>
#define SIGSEGV_FAULT_INSTRUCTION (((ucontext_t *)scp)->uc_mcontext.gregs[14]) /* should use REG_EIP instead */ #define SIGSEGV_CONTEXT_REGS (((ucontext_t *)scp)->uc_mcontext.gregs)
#define SIGSEGV_REGISTER_FILE (unsigned long *)(((ucontext_t *)scp)->uc_mcontext.gregs) #define SIGSEGV_FAULT_INSTRUCTION SIGSEGV_CONTEXT_REGS[14] /* should use REG_EIP instead */
#define SIGSEGV_REGISTER_FILE (unsigned int *)SIGSEGV_CONTEXT_REGS
#define SIGSEGV_SKIP_INSTRUCTION ix86_skip_instruction #define SIGSEGV_SKIP_INSTRUCTION ix86_skip_instruction
#endif #endif
#if (defined(ia64) || defined(__ia64__)) #if (defined(ia64) || defined(__ia64__))
@ -78,8 +228,9 @@ static bool sigsegv_do_install_handler(int sig);
#endif #endif
#if (defined(powerpc) || defined(__powerpc__)) #if (defined(powerpc) || defined(__powerpc__))
#include <sys/ucontext.h> #include <sys/ucontext.h>
#define SIGSEGV_FAULT_INSTRUCTION (((ucontext_t *)scp)->uc_mcontext.regs->nip) #define SIGSEGV_CONTEXT_REGS (((ucontext_t *)scp)->uc_mcontext.regs)
#define SIGSEGV_REGISTER_FILE (unsigned long *)(((ucontext_t *)scp)->uc_mcontext.regs) #define SIGSEGV_FAULT_INSTRUCTION (SIGSEGV_CONTEXT_REGS->nip)
#define SIGSEGV_REGISTER_FILE (unsigned int *)&SIGSEGV_CONTEXT_REGS->nip, (unsigned int *)(SIGSEGV_CONTEXT_REGS->gpr)
#define SIGSEGV_SKIP_INSTRUCTION powerpc_skip_instruction #define SIGSEGV_SKIP_INSTRUCTION powerpc_skip_instruction
#endif #endif
#endif #endif
@ -107,7 +258,7 @@ static bool sigsegv_do_install_handler(int sig);
#define SIGSEGV_FAULT_HANDLER_ARGLIST int sig, struct sigcontext *scp #define SIGSEGV_FAULT_HANDLER_ARGLIST int sig, struct sigcontext *scp
#define SIGSEGV_FAULT_ADDRESS scp->regs->dar #define SIGSEGV_FAULT_ADDRESS scp->regs->dar
#define SIGSEGV_FAULT_INSTRUCTION scp->regs->nip #define SIGSEGV_FAULT_INSTRUCTION scp->regs->nip
#define SIGSEGV_REGISTER_FILE (unsigned long *)(scp->regs) #define SIGSEGV_REGISTER_FILE (unsigned int *)&scp->regs->nip, (unsigned int *)(scp->regs->gpr)
#define SIGSEGV_SKIP_INSTRUCTION powerpc_skip_instruction #define SIGSEGV_SKIP_INSTRUCTION powerpc_skip_instruction
#endif #endif
#if (defined(alpha) || defined(__alpha__)) #if (defined(alpha) || defined(__alpha__))
@ -162,25 +313,29 @@ static sigsegv_address_t get_fault_address(struct sigcontext *scp)
#if (defined(m68k) || defined(__m68k__)) #if (defined(m68k) || defined(__m68k__))
#include <m68k/frame.h> #include <m68k/frame.h>
#define SIGSEGV_FAULT_HANDLER_ARGLIST int sig, int code, struct sigcontext *scp #define SIGSEGV_FAULT_HANDLER_ARGLIST int sig, int code, struct sigcontext *scp
#define SIGSEGV_FAULT_ADDRESS ({ \ #define SIGSEGV_FAULT_ADDRESS get_fault_address(scp)
struct sigstate { \
int ss_flags; \
struct frame ss_frame; \
}; \
struct sigstate *state = (struct sigstate *)scp->sc_ap; \
char *fault_addr; \
switch (state->ss_frame.f_format) { \
case 7: /* 68040 access error */ \
/* "code" is sometimes unreliable (i.e. contains NULL or a bogus address), reason unknown */ \
fault_addr = state->ss_frame.f_fmt7.f_fa; \
break; \
default: \
fault_addr = (char *)code; \
break; \
} \
fault_addr; \
})
#define SIGSEGV_ALL_SIGNALS FAULT_HANDLER(SIGSEGV) #define SIGSEGV_ALL_SIGNALS FAULT_HANDLER(SIGSEGV)
// Use decoding scheme from BasiliskII/m68k native
static sigsegv_address_t get_fault_address(struct sigcontext *scp)
{
struct sigstate {
int ss_flags;
struct frame ss_frame;
};
struct sigstate *state = (struct sigstate *)scp->sc_ap;
char *fault_addr;
switch (state->ss_frame.f_format) {
case 7: /* 68040 access error */
/* "code" is sometimes unreliable (i.e. contains NULL or a bogus address), reason unknown */
fault_addr = state->ss_frame.f_fmt7.f_fa;
break;
default:
fault_addr = (char *)code;
break;
}
return (sigsegv_address_t)fault_addr;
}
#else #else
#define SIGSEGV_FAULT_HANDLER_ARGLIST int sig, int code, void *scp, char *addr #define SIGSEGV_FAULT_HANDLER_ARGLIST int sig, int code, void *scp, char *addr
#define SIGSEGV_FAULT_ADDRESS addr #define SIGSEGV_FAULT_ADDRESS addr
@ -195,108 +350,28 @@ static sigsegv_address_t get_fault_address(struct sigcontext *scp)
#define SIGSEGV_FAULT_ADDRESS get_fault_address(scp) #define SIGSEGV_FAULT_ADDRESS get_fault_address(scp)
#define SIGSEGV_FAULT_INSTRUCTION scp->sc_ir #define SIGSEGV_FAULT_INSTRUCTION scp->sc_ir
#define SIGSEGV_ALL_SIGNALS FAULT_HANDLER(SIGBUS) #define SIGSEGV_ALL_SIGNALS FAULT_HANDLER(SIGBUS)
#define SIGSEGV_REGISTER_FILE (unsigned int *)&scp->sc_ir, &((unsigned int *) scp->sc_regs)[2]
#define SIGSEGV_SKIP_INSTRUCTION powerpc_skip_instruction
// From Boehm's GC 6.0alpha8 // Use decoding scheme from SheepShaver
#define EXTRACT_OP1(iw) (((iw) & 0xFC000000) >> 26)
#define EXTRACT_OP2(iw) (((iw) & 0x000007FE) >> 1)
#define EXTRACT_REGA(iw) (((iw) & 0x001F0000) >> 16)
#define EXTRACT_REGB(iw) (((iw) & 0x03E00000) >> 21)
#define EXTRACT_REGC(iw) (((iw) & 0x0000F800) >> 11)
#define EXTRACT_DISP(iw) ((short *) &(iw))[1]
static sigsegv_address_t get_fault_address(struct sigcontext *scp) static sigsegv_address_t get_fault_address(struct sigcontext *scp)
{ {
unsigned int instr = *((unsigned int *) scp->sc_ir); unsigned int nip = (unsigned int) scp->sc_ir;
unsigned int * regs = &((unsigned int *) scp->sc_regs)[2]; unsigned int * gpr = &((unsigned int *) scp->sc_regs)[2];
int disp = 0, tmp; instruction_t instr;
unsigned int baseA = 0, baseB = 0;
unsigned int addr, alignmask = 0xFFFFFFFF;
switch(EXTRACT_OP1(instr)) { powerpc_decode_instruction(&instr, nip, gpr);
case 38: /* stb */ return (sigsegv_address_t)instr.addr;
case 39: /* stbu */
case 54: /* stfd */
case 55: /* stfdu */
case 52: /* stfs */
case 53: /* stfsu */
case 44: /* sth */
case 45: /* sthu */
case 47: /* stmw */
case 36: /* stw */
case 37: /* stwu */
tmp = EXTRACT_REGA(instr);
if(tmp > 0)
baseA = regs[tmp];
disp = EXTRACT_DISP(instr);
break;
case 31:
switch(EXTRACT_OP2(instr)) {
case 86: /* dcbf */
case 54: /* dcbst */
case 1014: /* dcbz */
case 247: /* stbux */
case 215: /* stbx */
case 759: /* stfdux */
case 727: /* stfdx */
case 983: /* stfiwx */
case 695: /* stfsux */
case 663: /* stfsx */
case 918: /* sthbrx */
case 439: /* sthux */
case 407: /* sthx */
case 661: /* stswx */
case 662: /* stwbrx */
case 150: /* stwcx. */
case 183: /* stwux */
case 151: /* stwx */
case 135: /* stvebx */
case 167: /* stvehx */
case 199: /* stvewx */
case 231: /* stvx */
case 487: /* stvxl */
tmp = EXTRACT_REGA(instr);
if(tmp > 0)
baseA = regs[tmp];
baseB = regs[EXTRACT_REGC(instr)];
/* determine Altivec alignment mask */
switch(EXTRACT_OP2(instr)) {
case 167: /* stvehx */
alignmask = 0xFFFFFFFE;
break;
case 199: /* stvewx */
alignmask = 0xFFFFFFFC;
break;
case 231: /* stvx */
alignmask = 0xFFFFFFF0;
break;
case 487: /* stvxl */
alignmask = 0xFFFFFFF0;
break;
}
break;
case 725: /* stswi */
tmp = EXTRACT_REGA(instr);
if(tmp > 0)
baseA = regs[tmp];
break;
default: /* ignore instruction */
return 0;
break;
}
break;
default: /* ignore instruction */
return 0;
break;
}
addr = (baseA + baseB) + disp;
addr &= alignmask;
return (sigsegv_address_t)addr;
} }
#endif #endif
#endif #endif
#endif #endif
/*
* Instruction skipping
*/
#ifdef HAVE_SIGSEGV_SKIP_INSTRUCTION #ifdef HAVE_SIGSEGV_SKIP_INSTRUCTION
// Decode and skip X86 instruction // Decode and skip X86 instruction
#if (defined(i386) || defined(__i386__)) #if (defined(i386) || defined(__i386__))
@ -347,26 +422,15 @@ static inline int ix86_step_over_modrm(unsigned char * p)
return offset; return offset;
} }
static bool ix86_skip_instruction(sigsegv_address_t fault_instruction, unsigned long * regs) static bool ix86_skip_instruction(unsigned int * regs)
{ {
unsigned char * eip = (unsigned char *)fault_instruction; unsigned char * eip = (unsigned char *)regs[X86_REG_EIP];
if (eip == 0) if (eip == 0)
return false; return false;
// Transfer type transfer_type_t transfer_type = TYPE_UNKNOWN;
enum { transfer_size_t transfer_size = SIZE_LONG;
TYPE_UNKNOWN,
TYPE_LOAD,
TYPE_STORE
} transfer_type = TYPE_UNKNOWN;
// Transfer size
enum {
SIZE_BYTE,
SIZE_WORD,
SIZE_LONG
} transfer_size = SIZE_LONG;
int reg = -1; int reg = -1;
int len = 0; int len = 0;
@ -467,151 +531,36 @@ static bool ix86_skip_instruction(sigsegv_address_t fault_instruction, unsigned
return true; return true;
} }
#endif #endif
// Decode and skip PPC instruction // Decode and skip PPC instruction
#if (defined(powerpc) || defined(__powerpc__)) #if (defined(powerpc) || defined(__powerpc__) || defined(__ppc__))
#if defined(__linux__) static bool powerpc_skip_instruction(unsigned int * nip_p, unsigned int * regs)
enum {
POWERPC_REG_GPR = 0,
POWERPC_REG_NIP = 32
};
#endif
static bool powerpc_skip_instruction(sigsegv_address_t fault_instruction, unsigned long * regs)
{ {
// Get opcode and divide into fields instruction_t instr;
unsigned int opcode = *((unsigned int *)fault_instruction); powerpc_decode_instruction(&instr, *nip_p, regs);
unsigned int primop = opcode >> 26;
unsigned int exop = (opcode >> 1) & 0x3ff;
unsigned int ra = (opcode >> 16) & 0x1f;
unsigned int rb = (opcode >> 11) & 0x1f;
unsigned int rd = (opcode >> 21) & 0x1f;
signed int imm = (signed short)(opcode & 0xffff);
// Analyze opcode if (instr.transfer_type == TYPE_UNKNOWN) {
enum {
TYPE_UNKNOWN,
TYPE_LOAD,
TYPE_STORE
} transfer_type = TYPE_UNKNOWN;
enum {
SIZE_UNKNOWN,
SIZE_BYTE,
SIZE_HALFWORD,
SIZE_WORD
} transfer_size = SIZE_UNKNOWN;
enum {
MODE_UNKNOWN,
MODE_NORM,
MODE_U,
MODE_X,
MODE_UX
} addr_mode = MODE_UNKNOWN;
switch (primop) {
case 31:
switch (exop) {
case 23: // lwzx
transfer_type = TYPE_LOAD; transfer_size = SIZE_WORD; addr_mode = MODE_X; break;
case 55: // lwzux
transfer_type = TYPE_LOAD; transfer_size = SIZE_WORD; addr_mode = MODE_UX; break;
case 87: // lbzx
transfer_type = TYPE_LOAD; transfer_size = SIZE_BYTE; addr_mode = MODE_X; break;
case 119: // lbzux
transfer_type = TYPE_LOAD; transfer_size = SIZE_BYTE; addr_mode = MODE_UX; break;
case 151: // stwx
transfer_type = TYPE_STORE; transfer_size = SIZE_WORD; addr_mode = MODE_X; break;
case 183: // stwux
transfer_type = TYPE_STORE; transfer_size = SIZE_WORD; addr_mode = MODE_UX; break;
case 215: // stbx
transfer_type = TYPE_STORE; transfer_size = SIZE_BYTE; addr_mode = MODE_X; break;
case 247: // stbux
transfer_type = TYPE_STORE; transfer_size = SIZE_BYTE; addr_mode = MODE_UX; break;
case 279: // lhzx
transfer_type = TYPE_LOAD; transfer_size = SIZE_HALFWORD; addr_mode = MODE_X; break;
case 311: // lhzux
transfer_type = TYPE_LOAD; transfer_size = SIZE_HALFWORD; addr_mode = MODE_UX; break;
case 343: // lhax
transfer_type = TYPE_LOAD; transfer_size = SIZE_HALFWORD; addr_mode = MODE_X; break;
case 375: // lhaux
transfer_type = TYPE_LOAD; transfer_size = SIZE_HALFWORD; addr_mode = MODE_UX; break;
case 407: // sthx
transfer_type = TYPE_STORE; transfer_size = SIZE_HALFWORD; addr_mode = MODE_X; break;
case 439: // sthux
transfer_type = TYPE_STORE; transfer_size = SIZE_HALFWORD; addr_mode = MODE_UX; break;
}
break;
case 32: // lwz
transfer_type = TYPE_LOAD; transfer_size = SIZE_WORD; addr_mode = MODE_NORM; break;
case 33: // lwzu
transfer_type = TYPE_LOAD; transfer_size = SIZE_WORD; addr_mode = MODE_U; break;
case 34: // lbz
transfer_type = TYPE_LOAD; transfer_size = SIZE_BYTE; addr_mode = MODE_NORM; break;
case 35: // lbzu
transfer_type = TYPE_LOAD; transfer_size = SIZE_BYTE; addr_mode = MODE_U; break;
case 36: // stw
transfer_type = TYPE_STORE; transfer_size = SIZE_WORD; addr_mode = MODE_NORM; break;
case 37: // stwu
transfer_type = TYPE_STORE; transfer_size = SIZE_WORD; addr_mode = MODE_U; break;
case 38: // stb
transfer_type = TYPE_STORE; transfer_size = SIZE_BYTE; addr_mode = MODE_NORM; break;
case 39: // stbu
transfer_type = TYPE_STORE; transfer_size = SIZE_BYTE; addr_mode = MODE_U; break;
case 40: // lhz
transfer_type = TYPE_LOAD; transfer_size = SIZE_HALFWORD; addr_mode = MODE_NORM; break;
case 41: // lhzu
transfer_type = TYPE_LOAD; transfer_size = SIZE_HALFWORD; addr_mode = MODE_U; break;
case 42: // lha
transfer_type = TYPE_LOAD; transfer_size = SIZE_HALFWORD; addr_mode = MODE_NORM; break;
case 43: // lhau
transfer_type = TYPE_LOAD; transfer_size = SIZE_HALFWORD; addr_mode = MODE_U; break;
case 44: // sth
transfer_type = TYPE_STORE; transfer_size = SIZE_HALFWORD; addr_mode = MODE_NORM; break;
case 45: // sthu
transfer_type = TYPE_STORE; transfer_size = SIZE_HALFWORD; addr_mode = MODE_U; break;
}
// Calculate effective address
unsigned int addr = 0;
switch (addr_mode) {
case MODE_X:
case MODE_UX:
if (ra == 0)
addr = regs[POWERPC_REG_GPR + rb];
else
addr = regs[POWERPC_REG_GPR + ra] + regs[POWERPC_REG_GPR + rb];
break;
case MODE_NORM:
case MODE_U:
if (ra == 0)
addr = (signed int)(signed short)imm;
else
addr = regs[POWERPC_REG_GPR + ra] + (signed int)(signed short)imm;
break;
default:
break;
}
if (transfer_type == TYPE_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 DEBUG #if DEBUG
printf("%08x: %s %s access", fault_instruction, printf("%08x: %s %s access", *nip_p,
transfer_size == SIZE_BYTE ? "byte" : transfer_size == SIZE_HALFWORD ? "word" : "long", instr.transfer_size == SIZE_BYTE ? "byte" : instr.transfer_size == SIZE_WORD ? "word" : "long",
transfer_type == TYPE_LOAD ? "read" : "write"); instr.transfer_type == TYPE_LOAD ? "read" : "write");
if (addr_mode == MODE_U || addr_mode == MODE_UX) if (instr.addr_mode == MODE_U || instr.addr_mode == MODE_UX)
printf(" r%d (ra = %08x)\n", ra, addr); printf(" r%d (ra = %08x)\n", instr.ra, instr.addr);
if (transfer_type == TYPE_LOAD) if (instr.transfer_type == TYPE_LOAD)
printf(" r%d (rd = 0)\n", rd); printf(" r%d (rd = 0)\n", instr.rd);
#endif #endif
if (addr_mode == MODE_U || addr_mode == MODE_UX) if (instr.addr_mode == MODE_U || instr.addr_mode == MODE_UX)
regs[POWERPC_REG_GPR + ra] = addr; regs[instr.ra] = instr.addr;
if (transfer_type == TYPE_LOAD) if (instr.transfer_type == TYPE_LOAD)
regs[POWERPC_REG_GPR + rd] = 0; regs[instr.rd] = 0;
regs[POWERPC_REG_NIP] += 4; *nip_p += 4;
return true; return true;
} }
#endif #endif
@ -649,7 +598,7 @@ static void sigsegv_handler(SIGSEGV_FAULT_HANDLER_ARGLIST)
#if HAVE_SIGSEGV_SKIP_INSTRUCTION #if HAVE_SIGSEGV_SKIP_INSTRUCTION
else if (sigsegv_ignore_fault) { else if (sigsegv_ignore_fault) {
// Call the instruction skipper with the register file available // Call the instruction skipper with the register file available
if (SIGSEGV_SKIP_INSTRUCTION(fault_instruction, SIGSEGV_REGISTER_FILE)) if (SIGSEGV_SKIP_INSTRUCTION(SIGSEGV_REGISTER_FILE))
fault_recovered = true; fault_recovered = true;
} }
#endif #endif