#include "genesis/constants.h"
+#define INSN_LEN 4
+
void
arch_init()
{
os_context_insn(os_context_t *context)
{
if (os_context_bd_cause(context))
- return *(unsigned int *)(os_context_pc(context) + 4);
+ 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
correct target address without attempting to execute the delay slot.
For other instructions it just increments the returned PC value. */
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. */
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;
/* 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)));
+ *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);
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);
}