#include "defs.h"
#include "inferior.h"
#include "regcache.h"
#include <stdio.h>
#include <mach.h>
#include <mach/message.h>
#include <mach/exception.h>
#include <mach_error.h>
#if 1
#define REG_OFFSET(reg) (int)(&((struct mips_thread_state *)0)->reg)
#define CREG_OFFSET(reg) (int)(&((struct mips_float_state *)0)->reg)
#define EREG_OFFSET(reg) (int)(&((struct mips_exc_state *)0)->reg)
static int reg_offset[] =
{
-1, REG_OFFSET (r1), REG_OFFSET (r2), REG_OFFSET (r3),
REG_OFFSET (r4), REG_OFFSET (r5), REG_OFFSET (r6), REG_OFFSET (r7),
REG_OFFSET (r8), REG_OFFSET (r9), REG_OFFSET (r10), REG_OFFSET (r11),
REG_OFFSET (r12), REG_OFFSET (r13), REG_OFFSET (r14), REG_OFFSET (r15),
REG_OFFSET (r16), REG_OFFSET (r17), REG_OFFSET (r18), REG_OFFSET (r19),
REG_OFFSET (r20), REG_OFFSET (r21), REG_OFFSET (r22), REG_OFFSET (r23),
REG_OFFSET (r24), REG_OFFSET (r25), REG_OFFSET (r26), REG_OFFSET (r27),
REG_OFFSET (r28), REG_OFFSET (r29), REG_OFFSET (r30), REG_OFFSET (r31),
EREG_OFFSET (coproc_state),
REG_OFFSET (mdlo), REG_OFFSET (mdhi),
EREG_OFFSET (address), EREG_OFFSET (cause), REG_OFFSET (pc),
CREG_OFFSET (r0), CREG_OFFSET (r1), CREG_OFFSET (r2), CREG_OFFSET (r3),
CREG_OFFSET (r4), CREG_OFFSET (r5), CREG_OFFSET (r6), CREG_OFFSET (r7),
CREG_OFFSET (r8), CREG_OFFSET (r9), CREG_OFFSET (r10), CREG_OFFSET (r11),
CREG_OFFSET (r12), CREG_OFFSET (r13), CREG_OFFSET (r14), CREG_OFFSET (r15),
CREG_OFFSET (r16), CREG_OFFSET (r17), CREG_OFFSET (r18), CREG_OFFSET (r19),
CREG_OFFSET (r20), CREG_OFFSET (r21), CREG_OFFSET (r22), CREG_OFFSET (r23),
CREG_OFFSET (r24), CREG_OFFSET (r25), CREG_OFFSET (r26), CREG_OFFSET (r27),
CREG_OFFSET (r28), CREG_OFFSET (r29), CREG_OFFSET (r30), CREG_OFFSET (r31),
CREG_OFFSET (csr), CREG_OFFSET (esr), REG_OFFSET (r30)
};
#else
static int reg_offset[] =
{
-1, 0, 4, 8, 12, 16, 20, 24, 28, 32, 36, 40, 44, 48, 52, 56,
60, 64, 68, 72, 76, 80, 84, 88, 92, 96, 100, 104, 108, 112, 116, 120,
8, 124, 128, 4, 0, 132,
0, 4, 8, 12, 16, 20, 24, 28, 32, 36, 40, 44, 48, 52, 56, 60,
64, 68, 72, 76, 80, 84, 88, 92, 96, 100, 104, 108, 112, 116, 120, 124,
128, 132,
116
};
#endif
#define FETCH_REGS(state, regnum, count) \
memcpy (®isters[REGISTER_BYTE (regnum)], \
(char *)state+reg_offset[ regnum ], \
count*REGISTER_SIZE)
#define STORE_REGS(state, regnum, count) \
memcpy ((char *)state+reg_offset[ regnum ], \
®isters[REGISTER_BYTE (regnum)], \
count*REGISTER_SIZE)
#define REGS_ALL -1
#define REGS_NORMAL 1
#define REGS_EXC 2
#define REGS_COP1 4
#define MACH_FP_REGNUM 30
void
fetch_inferior_registers (int regno)
{
kern_return_t ret;
thread_state_data_t state;
struct mips_exc_state exc_state;
int stateCnt = MIPS_THREAD_STATE_COUNT;
int which_regs = 0;
if (!MACH_PORT_VALID (current_thread))
error ("fetch inferior registers: Invalid thread");
if (regno < -1 || regno >= NUM_REGS)
error ("invalid register %d supplied to fetch_inferior_registers", regno);
if (regno == -1)
which_regs = REGS_ALL;
else if (regno == ZERO_REGNUM)
{
int zero = 0;
supply_register (ZERO_REGNUM, &zero);
return;
}
else if ((ZERO_REGNUM < regno && regno < PS_REGNUM)
|| regno == FP_REGNUM
|| regno == LO_REGNUM
|| regno == HI_REGNUM
|| regno == PC_REGNUM)
which_regs = REGS_NORMAL;
else if (FP0_REGNUM <= regno && regno <= FCRIR_REGNUM)
which_regs = REGS_COP1 | REGS_EXC;
else
which_regs = REGS_EXC;
if (which_regs & REGS_NORMAL)
{
ret = thread_get_state (current_thread,
MIPS_THREAD_STATE,
state,
&stateCnt);
CHK ("fetch inferior registers: thread_get_state", ret);
if (which_regs == REGS_NORMAL)
{
if (regno == MACH_FP_REGNUM || regno == FP_REGNUM)
{
supply_register (FP_REGNUM,
(char *) state + reg_offset[MACH_FP_REGNUM]);
supply_register (MACH_FP_REGNUM,
(char *) state + reg_offset[MACH_FP_REGNUM]);
}
else
supply_register (regno,
(char *) state + reg_offset[regno]);
return;
}
*(int *) registers = 0;
FETCH_REGS (state, 1, 31);
FETCH_REGS (state, LO_REGNUM, 2);
FETCH_REGS (state, PC_REGNUM, 1);
FETCH_REGS (state, FP_REGNUM, 1);
}
if (which_regs & REGS_EXC)
{
stateCnt = MIPS_EXC_STATE_COUNT;
ret = thread_get_state (current_thread,
MIPS_EXC_STATE,
(thread_state_t) & exc_state,
&stateCnt);
CHK ("fetch inferior regs (exc): thread_get_state", ret);
supply_register (PS_REGNUM,
(char *) &exc_state + reg_offset[PS_REGNUM]);
if (which_regs == REGS_EXC || which_regs == REGS_ALL)
{
supply_register (BADVADDR_REGNUM,
(char *) &exc_state + reg_offset[BADVADDR_REGNUM]);
supply_register (CAUSE_REGNUM,
(char *) &exc_state + reg_offset[CAUSE_REGNUM]);
if (which_regs == REGS_EXC)
return;
}
}
if (which_regs & REGS_COP1)
{
if (!(exc_state.coproc_state & MIPS_STATUS_USE_COP1))
bzero (®isters[REGISTER_BYTE (FP0_REGNUM)],
sizeof (struct mips_float_state));
else
{
stateCnt = MIPS_FLOAT_STATE_COUNT;
ret = thread_get_state (current_thread,
MIPS_FLOAT_STATE,
state,
&stateCnt);
CHK ("fetch inferior regs (floats): thread_get_state", ret);
if (regno != -1)
{
supply_register (regno,
(char *) state + reg_offset[regno]);
return;
}
FETCH_REGS (state, FP0_REGNUM, 34);
}
}
registers_fetched ();
}
void
store_inferior_registers (register int regno)
{
thread_state_data_t state;
kern_return_t ret;
if (!MACH_PORT_VALID (current_thread))
error ("store inferior registers: Invalid thread");
if (regno == ZERO_REGNUM ||
regno == PS_REGNUM ||
regno == BADVADDR_REGNUM ||
regno == CAUSE_REGNUM ||
regno == FCRIR_REGNUM)
{
message ("You can not alter read-only register `%s'",
REGISTER_NAME (regno));
fetch_inferior_registers (regno);
return;
}
if (regno == -1)
{
*(int *) registers = 0;
fetch_inferior_registers (PS_REGNUM);
fetch_inferior_registers (BADVADDR_REGNUM);
fetch_inferior_registers (CAUSE_REGNUM);
fetch_inferior_registers (FCRIR_REGNUM);
}
if (regno == -1 || (ZERO_REGNUM < regno && regno <= PC_REGNUM))
{
#if 1
memcpy (®isters[REGISTER_BYTE (MACH_FP_REGNUM)],
®isters[REGISTER_BYTE (FP_REGNUM)],
REGISTER_RAW_SIZE (FP_REGNUM));
#endif
STORE_REGS (state, 1, 31);
STORE_REGS (state, LO_REGNUM, 2);
STORE_REGS (state, PC_REGNUM, 1);
ret = thread_set_state (current_thread,
MIPS_THREAD_STATE,
state,
MIPS_FLOAT_STATE_COUNT);
CHK ("store inferior regs : thread_set_state", ret);
}
if (regno == -1 || regno >= FP0_REGNUM)
{
if (read_register (PS_REGNUM) & MIPS_STATUS_USE_COP1)
{
STORE_REGS (state, FP0_REGNUM, 33);
ret = thread_set_state (current_thread,
MIPS_FLOAT_STATE,
state,
MIPS_FLOAT_STATE_COUNT);
CHK ("store inferior registers (floats): thread_set_state", ret);
}
else if (regno != -1)
message
("Thread does not use floating point unit, floating regs not saved");
}
}