linux-crisv32-low.c [plain text]
#include "server.h"
#include "linux-low.h"
#include <sys/ptrace.h>
#define cris_num_regs 49
static int cris_regmap[] = {
1*4, 2*4, 3*4, 4*4,
5*4, 6*4, 7*4, 8*4,
9*4, 10*4, 11*4, 12*4,
13*4, 14*4, 24*4, 15*4,
-1, -1, -1, 16*4,
-1, 22*4, 23*4, 17*4,
-1, -1, 21*4, 20*4,
-1, 19*4, -1, 18*4,
25*4,
26*4, -1, -1, 29*4,
30*4, 31*4, 32*4, 33*4,
34*4, 35*4, 36*4, 37*4,
38*4, 39*4, 40*4, -1
};
extern int debug_threads;
static CORE_ADDR
cris_get_pc (void)
{
unsigned long pc;
collect_register_by_name ("pc", &pc);
if (debug_threads)
fprintf (stderr, "stop pc is %08lx\n", pc);
return pc;
}
static void
cris_set_pc (CORE_ADDR pc)
{
unsigned long newpc = pc;
supply_register_by_name ("pc", &newpc);
}
static const unsigned short cris_breakpoint = 0xe938;
#define cris_breakpoint_len 2
static int
cris_breakpoint_at (CORE_ADDR where)
{
unsigned short insn;
(*the_target->read_memory) (where, (unsigned char *) &insn,
cris_breakpoint_len);
if (insn == cris_breakpoint)
return 1;
return 0;
}
static CORE_ADDR
cris_reinsert_addr (void)
{
unsigned long pc;
collect_register_by_name ("srp", &pc);
return pc;
}
static void
cris_write_data_breakpoint (int bp, unsigned long start, unsigned long end)
{
switch (bp)
{
case 0:
supply_register_by_name ("s3", &start);
supply_register_by_name ("s4", &end);
break;
case 1:
supply_register_by_name ("s5", &start);
supply_register_by_name ("s6", &end);
break;
case 2:
supply_register_by_name ("s7", &start);
supply_register_by_name ("s8", &end);
break;
case 3:
supply_register_by_name ("s9", &start);
supply_register_by_name ("s10", &end);
break;
case 4:
supply_register_by_name ("s11", &start);
supply_register_by_name ("s12", &end);
break;
case 5:
supply_register_by_name ("s13", &start);
supply_register_by_name ("s14", &end);
break;
}
}
static int
cris_insert_watchpoint (char type, CORE_ADDR addr, int len)
{
int bp;
unsigned long bp_ctrl;
unsigned long start, end;
unsigned long ccs;
if (type < '2' || type > '4')
{
return 1;
}
if (type == '3')
type = '4';
collect_register_by_name ("s0", &bp_ctrl);
for (bp = 0; bp < 6; bp++)
{
if (!(bp_ctrl & (0x3 << (2 + (bp * 4)))))
break;
}
if (bp > 5)
{
return -1;
}
if (type == '3' || type == '4')
{
bp_ctrl |= (1 << (2 + bp * 4));
}
if (type == '2' || type == '4')
{
bp_ctrl |= (2 << (2 + bp * 4));
}
supply_register_by_name ("s0", &bp_ctrl);
start = addr;
end = addr + len - 1;
cris_write_data_breakpoint (bp, start, end);
collect_register_by_name ("ccs", &ccs);
ccs |= (1 << 19);
supply_register_by_name ("ccs", &ccs);
return 0;
}
static int
cris_remove_watchpoint (char type, CORE_ADDR addr, int len)
{
int bp;
unsigned long bp_ctrl;
unsigned long start, end;
if (type < '2' || type > '4')
return -1;
if (type == '3')
type = '4';
collect_register_by_name ("s0", &bp_ctrl);
unsigned long bp_d_regs[12];
collect_register_by_name ("s3", &bp_d_regs[0]);
collect_register_by_name ("s4", &bp_d_regs[1]);
collect_register_by_name ("s5", &bp_d_regs[2]);
collect_register_by_name ("s6", &bp_d_regs[3]);
collect_register_by_name ("s7", &bp_d_regs[4]);
collect_register_by_name ("s8", &bp_d_regs[5]);
collect_register_by_name ("s9", &bp_d_regs[6]);
collect_register_by_name ("s10", &bp_d_regs[7]);
collect_register_by_name ("s11", &bp_d_regs[8]);
collect_register_by_name ("s12", &bp_d_regs[9]);
collect_register_by_name ("s13", &bp_d_regs[10]);
collect_register_by_name ("s14", &bp_d_regs[11]);
for (bp = 0; bp < 6; bp++)
{
if (bp_d_regs[bp * 2] == addr
&& bp_d_regs[bp * 2 + 1] == (addr + len - 1)) {
int bitpos = 2 + bp * 4;
int rw_bits;
rw_bits = (bp_ctrl & (0x3 << bitpos)) >> bitpos;
if ((type == '3' && rw_bits == 0x1)
|| (type == '2' && rw_bits == 0x2)
|| (type == '4' && rw_bits == 0x3))
{
break;
}
}
}
if (bp > 5)
{
return -1;
}
bp_ctrl &= ~(3 << (2 + (bp * 4)));
supply_register_by_name ("s0", &bp_ctrl);
start = end = 0;
cris_write_data_breakpoint (bp, start, end);
return 0;
}
static int
cris_stopped_by_watchpoint (void)
{
unsigned long exs;
collect_register_by_name ("exs", &exs);
return (((exs & 0xff00) >> 8) == 0xc);
}
static CORE_ADDR
cris_stopped_data_address (void)
{
unsigned long eda;
collect_register_by_name ("eda", &eda);
return eda;
}
static void
cris_fill_gregset (void *buf)
{
int i;
for (i = 0; i < cris_num_regs; i++)
{
if (cris_regmap[i] != -1)
collect_register (i, ((char *) buf) + cris_regmap[i]);
}
}
static void
cris_store_gregset (const void *buf)
{
int i;
for (i = 0; i < cris_num_regs; i++)
{
if (cris_regmap[i] != -1)
supply_register (i, ((char *) buf) + cris_regmap[i]);
}
}
typedef unsigned long elf_gregset_t[cris_num_regs];
struct regset_info target_regsets[] = {
{ PTRACE_GETREGS, PTRACE_SETREGS, sizeof (elf_gregset_t),
GENERAL_REGS, cris_fill_gregset, cris_store_gregset },
{ 0, 0, -1, -1, NULL, NULL }
};
struct linux_target_ops the_low_target = {
-1,
NULL,
NULL,
NULL,
cris_get_pc,
cris_set_pc,
(const unsigned char *) &cris_breakpoint,
cris_breakpoint_len,
cris_reinsert_addr,
0,
cris_breakpoint_at,
cris_insert_watchpoint,
cris_remove_watchpoint,
cris_stopped_by_watchpoint,
cris_stopped_data_address,
};