#include "genesis/constants.h"
+#define INSN_LEN 4
+
void
arch_init()
{
static inline unsigned int
os_context_insn(os_context_t *context)
{
- return *(unsigned int *)(os_context_pc(context));
+ if (os_context_bd_cause(context))
+ return *(unsigned int *)(os_context_pc(context) + INSN_LEN);
+ else
+ return *(unsigned int *)(os_context_pc(context));
+}
+
+boolean
+arch_insn_with_bdelay_p(unsigned int insn)
+{
+ switch (insn >> 26) {
+ case 0x0:
+ switch (insn & 0x3f) {
+ /* register jumps */
+ case 0x08:
+ case 0x09:
+ return 1;
+ }
+ break;
+ /* branches and immediate jumps */
+ case 0x1:
+ switch ((insn >> 16) & 0x1f) {
+ case 0x00:
+ case 0x01:
+ case 0x02:
+ case 0x03:
+ case 0x10:
+ case 0x11:
+ case 0x12:
+ case 0x13:
+ return 1;
+ }
+ break;
+ case 0x2:
+ case 0x3:
+ case 0x4:
+ case 0x5:
+ case 0x6:
+ case 0x7:
+ return 1;
+ case 0x10:
+ case 0x11:
+ case 0x12:
+ switch ((insn >> 21) & 0x1f) {
+ /* CP0/CP1/CP2 branches */
+ case 0x08:
+ return 1;
+ }
+ break;
+ /* branch likely (MIPS II) */
+ case 0x14:
+ case 0x15:
+ case 0x16:
+ case 0x17:
+ return 1;
+ }
+ return 0;
}
/* This function is somewhat misnamed, it actually just jumps to the
case 0x09: /* jalr */
tgt = os_context_register(context, r1);
*os_context_register_addr(context, r3)
- = os_context_pc(context) + 4;
+ = os_context_pc(context) + INSN_LEN;
break;
default:
- tgt += 4;
+ tgt += INSN_LEN;
break;
}
break;
if(os_context_register(context, r1) < 0)
tgt += disp;
*os_context_register_addr(context, 31)
- = os_context_pc(context) + 4;
+ = os_context_pc(context) + INSN_LEN;
break;
case 0x11: /* bgezal */
if(os_context_register(context, r1) >= 0)
tgt += disp;
*os_context_register_addr(context, 31)
- = os_context_pc(context) + 4;
+ = os_context_pc(context) + INSN_LEN;
break;
- default: /* conditional branches/traps for > MIPS I, ignore for now. */
+ default: /* conditional branches/traps for > MIPS I, ignore for now. */
break;
}
break;
case 0x3: /* jal */
tgt = jtgt;
*os_context_register_addr(context, 31)
- = os_context_pc(context) + 4;
+ = os_context_pc(context) + INSN_LEN;
break;
default:
tgt += 4;
void
arch_skip_instruction(os_context_t *context)
{
- /* Skip the offending instruction */
- *os_context_pc_addr(context)
- = emulate_branch(context, os_context_insn(context));
+ /* Skip the offending instruction. Don't use os_context_insn here,
+ since in case of a branch we want the branch insn, not the delay
+ slot. */
+ *os_context_pc_addr(context)
+ = emulate_branch(context,
+ *(unsigned int *)(os_context_pc(context)));
}
unsigned char *
arch_internal_error_arguments(os_context_t *context)
{
if (os_context_bd_cause(context))
- return (unsigned char *)(os_context_pc(context) + 8);
+ return (unsigned char *)(os_context_pc(context) + (INSN_LEN * 2));
else
- return (unsigned char *)(os_context_pc(context) + 4);
+ return (unsigned char *)(os_context_pc(context) + INSN_LEN);
}
boolean
arch_install_breakpoint(void *pc)
{
unsigned int *ptr = (unsigned int *)pc;
+ unsigned int insn = *ptr;
unsigned long result;
- /* Don't install over a branch/jump. */
- switch (*ptr >> 26) {
- case 0x0: /* immediate jumps */
- switch (*ptr & 0x3f) {
- case 0x08:
- case 0x09:
+ /* Don't install over a branch/jump with delay slot. */
+ if (arch_insn_with_bdelay_p(insn))
ptr++;
- }
- break;
- /* branches and register jumps */
- case 0x1:
- case 0x2:
- case 0x3:
- case 0x4:
- case 0x5:
- case 0x6:
- case 0x7:
- ptr++;
- }
- result = (unsigned long) *ptr;
+ result = (unsigned long)insn;
*ptr = (trap_Breakpoint << 16) | 0xd;
- os_flush_icache((os_vm_address_t)ptr, sizeof(unsigned int));
+ os_flush_icache((os_vm_address_t)ptr, INSN_LEN);
return result;
}
unsigned int *ptr = (unsigned int *)pc;
*ptr = (unsigned int) orig_inst;
- os_flush_icache((os_vm_address_t)ptr, sizeof(unsigned int));
+ os_flush_icache((os_vm_address_t)ptr, INSN_LEN);
}
static unsigned int *skipped_break_addr, displaced_after_inst;
}
static void
-sigill_handler(int signal, siginfo_t *info, void *void_context)
-{
- os_context_t *context = arch_os_get_context(&void_context);
-
- fake_foreign_function_call(context);
- monitor_or_something();
-}
-
-static void
sigtrap_handler(int signal, siginfo_t *info, void *void_context)
{
os_context_t *context = arch_os_get_context(&void_context);
static void
sigfpe_handler(int signal, siginfo_t *info, void *void_context)
{
- unsigned int bad_inst;
+ os_context_t *context = arch_os_get_context(&void_context);
+ unsigned int bad_inst = os_context_insn(context);
unsigned int op, rs, rt, rd, funct, dest = 32;
int immed;
int result;
- os_context_t *context = arch_os_get_context(&void_context);
-
- if (os_context_bd_cause(context))
- bad_inst = *(unsigned int *)(os_context_pc(context) + 4);
- else
- bad_inst = os_context_insn(context);
op = (bad_inst >> 26) & 0x3f;
rs = (bad_inst >> 21) & 0x1f;
void
arch_install_interrupt_handlers()
{
- undoably_install_low_level_interrupt_handler(SIGILL,sigill_handler);
undoably_install_low_level_interrupt_handler(SIGTRAP,sigtrap_handler);
undoably_install_low_level_interrupt_handler(SIGFPE,sigfpe_handler);
}