#include "defs.h"
#include "frame.h"
#include "frame-unwind.h"
#include "frame-base.h"
#include "trad-frame.h"
#include "dwarf2-frame.h"
#include "symtab.h"
#include "inferior.h"
#include "gdbtypes.h"
#include "gdbcore.h"
#include "gdbcmd.h"
#include "target.h"
#include "value.h"
#include "opcode/cris.h"
#include "arch-utils.h"
#include "regcache.h"
#include "gdb_assert.h"
#include "objfiles.h"
#include "solib.h"
#include "solib-svr4.h"
#include "gdb_string.h"
#include "dis-asm.h"
enum cris_num_regs
{
NUM_FREGS = 0,
NUM_GENREGS = 16,
NUM_SPECREGS = 16,
NUM_SUPPREGS = 16
};
enum cris_regnums
{
CRIS_FP_REGNUM = 8,
STR_REGNUM = 9,
RET_REGNUM = 10,
ARG1_REGNUM = 10,
ARG2_REGNUM = 11,
ARG3_REGNUM = 12,
ARG4_REGNUM = 13,
VR_REGNUM = 17,
MOF_REGNUM = 23,
SRP_REGNUM = 27,
P0_REGNUM = 16,
P4_REGNUM = 20,
CCR_REGNUM = 21,
P8_REGNUM = 24,
IBR_REGNUM = 25,
IRP_REGNUM = 26,
BAR_REGNUM = 28,
DCCR_REGNUM = 29,
BRP_REGNUM = 30,
USP_REGNUM = 31,
ACR_REGNUM = 15,
BZ_REGNUM = 16,
PID_REGNUM = 18,
SRS_REGNUM = 19,
WZ_REGNUM = 20,
EXS_REGNUM = 21,
EDA_REGNUM = 22,
DZ_REGNUM = 24,
EBP_REGNUM = 25,
ERP_REGNUM = 26,
NRP_REGNUM = 28,
CCS_REGNUM = 29,
CRISV32USP_REGNUM = 30,
SPC_REGNUM = 31,
CRISV32PC_REGNUM = 32,
S0_REGNUM = 33,
S1_REGNUM = 34,
S2_REGNUM = 35,
S3_REGNUM = 36,
S4_REGNUM = 37,
S5_REGNUM = 38,
S6_REGNUM = 39,
S7_REGNUM = 40,
S8_REGNUM = 41,
S9_REGNUM = 42,
S10_REGNUM = 43,
S11_REGNUM = 44,
S12_REGNUM = 45,
S13_REGNUM = 46,
S14_REGNUM = 47,
S15_REGNUM = 48,
};
extern const struct cris_spec_reg cris_spec_regs[];
static int usr_cmd_cris_version;
static int usr_cmd_cris_version_valid = 0;
static const char cris_mode_normal[] = "normal";
static const char cris_mode_guru[] = "guru";
static const char *cris_modes[] = {
cris_mode_normal,
cris_mode_guru,
0
};
static const char *usr_cmd_cris_mode = cris_mode_normal;
static int usr_cmd_cris_dwarf2_cfi = 1;
struct gdbarch_tdep
{
int cris_version;
const char *cris_mode;
int cris_dwarf2_cfi;
};
static int
cris_version (void)
{
return (gdbarch_tdep (current_gdbarch)->cris_version);
}
static const char *
cris_mode (void)
{
return (gdbarch_tdep (current_gdbarch)->cris_mode);
}
#define SIGTRAMP_INSN0 0x9c5f
#define SIGTRAMP_OFFSET0 0
#define SIGTRAMP_INSN1 0xe93d
#define SIGTRAMP_OFFSET1 4
static const unsigned short sigtramp_code[] =
{
SIGTRAMP_INSN0, 0x0077,
SIGTRAMP_INSN1
};
#define SIGTRAMP_LEN (sizeof sigtramp_code)
static const unsigned short rt_sigtramp_code[] =
{
SIGTRAMP_INSN0, 0x00ad,
SIGTRAMP_INSN1
};
static CORE_ADDR
cris_sigtramp_start (struct frame_info *next_frame)
{
CORE_ADDR pc = frame_pc_unwind (next_frame);
gdb_byte buf[SIGTRAMP_LEN];
if (!safe_frame_unwind_memory (next_frame, pc, buf, SIGTRAMP_LEN))
return 0;
if (((buf[1] << 8) + buf[0]) != SIGTRAMP_INSN0)
{
if (((buf[1] << 8) + buf[0]) != SIGTRAMP_INSN1)
return 0;
pc -= SIGTRAMP_OFFSET1;
if (!safe_frame_unwind_memory (next_frame, pc, buf, SIGTRAMP_LEN))
return 0;
}
if (memcmp (buf, sigtramp_code, SIGTRAMP_LEN) != 0)
return 0;
return pc;
}
static CORE_ADDR
cris_rt_sigtramp_start (struct frame_info *next_frame)
{
CORE_ADDR pc = frame_pc_unwind (next_frame);
gdb_byte buf[SIGTRAMP_LEN];
if (!safe_frame_unwind_memory (next_frame, pc, buf, SIGTRAMP_LEN))
return 0;
if (((buf[1] << 8) + buf[0]) != SIGTRAMP_INSN0)
{
if (((buf[1] << 8) + buf[0]) != SIGTRAMP_INSN1)
return 0;
pc -= SIGTRAMP_OFFSET1;
if (!safe_frame_unwind_memory (next_frame, pc, buf, SIGTRAMP_LEN))
return 0;
}
if (memcmp (buf, rt_sigtramp_code, SIGTRAMP_LEN) != 0)
return 0;
return pc;
}
static CORE_ADDR
cris_sigcontext_addr (struct frame_info *next_frame)
{
CORE_ADDR pc;
CORE_ADDR sp;
char buf[4];
frame_unwind_register (next_frame, SP_REGNUM, buf);
sp = extract_unsigned_integer (buf, 4);
pc = cris_sigtramp_start (next_frame);
if (pc)
{
return sp;
}
pc = cris_rt_sigtramp_start (next_frame);
if (pc)
{
return (sp + 156);
}
error (_("Couldn't recognize signal trampoline."));
return 0;
}
struct cris_unwind_cache
{
CORE_ADDR prev_sp;
CORE_ADDR base;
int size;
LONGEST sp_offset;
LONGEST r8_offset;
int uses_frame;
CORE_ADDR return_pc;
int leaf_function;
struct trad_frame_saved_reg *saved_regs;
};
static struct cris_unwind_cache *
cris_sigtramp_frame_unwind_cache (struct frame_info *next_frame,
void **this_cache)
{
struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
struct cris_unwind_cache *info;
CORE_ADDR pc;
CORE_ADDR sp;
CORE_ADDR addr;
char buf[4];
int i;
if ((*this_cache))
return (*this_cache);
info = FRAME_OBSTACK_ZALLOC (struct cris_unwind_cache);
(*this_cache) = info;
info->saved_regs = trad_frame_alloc_saved_regs (next_frame);
info->prev_sp = 0;
info->base = 0;
info->size = 0;
info->sp_offset = 0;
info->r8_offset = 0;
info->uses_frame = 0;
info->return_pc = 0;
info->leaf_function = 0;
frame_unwind_register (next_frame, SP_REGNUM, buf);
info->base = extract_unsigned_integer (buf, 4);
addr = cris_sigcontext_addr (next_frame);
if (tdep->cris_version == 10)
{
for (i = 0; i <= 13; i++)
info->saved_regs[i].addr = addr + ((15 - i) * 4);
info->saved_regs[MOF_REGNUM].addr = addr + (16 * 4);
info->saved_regs[DCCR_REGNUM].addr = addr + (17 * 4);
info->saved_regs[SRP_REGNUM].addr = addr + (18 * 4);
info->saved_regs[IRP_REGNUM].addr = addr + (19 * 4);
info->saved_regs[PC_REGNUM] = info->saved_regs[IRP_REGNUM];
info->saved_regs[SP_REGNUM].addr = addr + (24 * 4);
}
else
{
for (i = 0; i <= 13; i++)
info->saved_regs[i].addr = addr + ((i + 1) * 4);
info->saved_regs[ACR_REGNUM].addr = addr + (15 * 4);
info->saved_regs[SRS_REGNUM].addr = addr + (16 * 4);
info->saved_regs[MOF_REGNUM].addr = addr + (17 * 4);
info->saved_regs[SPC_REGNUM].addr = addr + (18 * 4);
info->saved_regs[CCS_REGNUM].addr = addr + (19 * 4);
info->saved_regs[SRP_REGNUM].addr = addr + (20 * 4);
info->saved_regs[ERP_REGNUM].addr = addr + (21 * 4);
info->saved_regs[EXS_REGNUM].addr = addr + (22 * 4);
info->saved_regs[EDA_REGNUM].addr = addr + (23 * 4);
info->saved_regs[PC_REGNUM] = info->saved_regs[ERP_REGNUM];
info->saved_regs[SP_REGNUM].addr = addr + (25 * 4);
}
return info;
}
static void
cris_sigtramp_frame_this_id (struct frame_info *next_frame, void **this_cache,
struct frame_id *this_id)
{
struct cris_unwind_cache *cache =
cris_sigtramp_frame_unwind_cache (next_frame, this_cache);
(*this_id) = frame_id_build (cache->base, frame_pc_unwind (next_frame));
}
static void cris_frame_prev_register (struct frame_info *next_frame,
void **this_prologue_cache,
int regnum, enum opt_state *optimizedp,
enum lval_type *lvalp, CORE_ADDR *addrp,
int *realnump, gdb_byte *bufferp);
static void
cris_sigtramp_frame_prev_register (struct frame_info *next_frame,
void **this_cache,
int regnum, enum opt_state *optimizedp,
enum lval_type *lvalp, CORE_ADDR *addrp,
int *realnump, gdb_byte *valuep)
{
cris_sigtramp_frame_unwind_cache (next_frame, this_cache);
cris_frame_prev_register (next_frame, this_cache, regnum,
optimizedp, lvalp, addrp, realnump, valuep);
}
static const struct frame_unwind cris_sigtramp_frame_unwind =
{
SIGTRAMP_FRAME,
cris_sigtramp_frame_this_id,
cris_sigtramp_frame_prev_register
};
static const struct frame_unwind *
cris_sigtramp_frame_sniffer (struct frame_info *next_frame)
{
if (cris_sigtramp_start (next_frame)
|| cris_rt_sigtramp_start (next_frame))
return &cris_sigtramp_frame_unwind;
return NULL;
}
int
crisv32_single_step_through_delay (struct gdbarch *gdbarch,
struct frame_info *this_frame)
{
struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
ULONGEST erp;
int ret = 0;
char buf[4];
if (cris_mode () == cris_mode_guru)
{
frame_unwind_register (this_frame, NRP_REGNUM, buf);
}
else
{
frame_unwind_register (this_frame, ERP_REGNUM, buf);
}
erp = extract_unsigned_integer (buf, 4);
if (erp & 0x1)
{
if (breakpoint_here_p (erp & ~0x1))
ret = 1;
}
return ret;
}
int
cris_can_use_hardware_watchpoint (int type, int count, int other)
{
struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
if (tdep->cris_version != 32)
return 0;
else
return (((type == bp_read_watchpoint || type == bp_access_watchpoint
|| type == bp_hardware_watchpoint) && count <= 6)
|| (type == bp_hardware_breakpoint && count <= 1));
}
int
cris_region_ok_for_watchpoint (CORE_ADDR addr, int len)
{
return 1;
}
CORE_ADDR
cris_stopped_data_address (void)
{
CORE_ADDR eda;
eda = read_register (EDA_REGNUM);
return eda;
}
typedef
struct instruction_environment
{
unsigned long reg[NUM_GENREGS];
unsigned long preg[NUM_SPECREGS];
unsigned long branch_break_address;
unsigned long delay_slot_pc;
unsigned long prefix_value;
int branch_found;
int prefix_found;
int invalid;
int slot_needed;
int delay_slot_pc_active;
int xflag_found;
int disable_interrupt;
} inst_env_type;
typedef
char binsn_quantum[BREAKPOINT_MAX];
static binsn_quantum break_mem[2];
static CORE_ADDR next_pc = 0;
static CORE_ADDR branch_target_address = 0;
static unsigned char branch_break_inserted = 0;
enum cris_instruction_sizes
{
INST_BYTE_SIZE = 0,
INST_WORD_SIZE = 1,
INST_DWORD_SIZE = 2
};
enum cris_addressing_modes
{
REGISTER_MODE = 1,
INDIRECT_MODE = 2,
AUTOINC_MODE = 3
};
enum cris_prefix_addressing_modes
{
PREFIX_INDEX_MODE = 2,
PREFIX_ASSIGN_MODE = 3,
PREFIX_OFFSET_MODE = 2
};
enum cris_opcode_masks
{
BRANCH_SIGNED_SHORT_OFFSET_MASK = 0x1,
SIGNED_EXTEND_BIT_MASK = 0x2,
SIGNED_BYTE_MASK = 0x80,
SIGNED_BYTE_EXTEND_MASK = 0xFFFFFF00,
SIGNED_WORD_MASK = 0x8000,
SIGNED_WORD_EXTEND_MASK = 0xFFFF0000,
SIGNED_DWORD_MASK = 0x80000000,
SIGNED_QUICK_VALUE_MASK = 0x20,
SIGNED_QUICK_VALUE_EXTEND_MASK = 0xFFFFFFC0
};
static int
cris_get_operand2 (unsigned short insn)
{
return ((insn & 0xF000) >> 12);
}
static int
cris_get_mode (unsigned short insn)
{
return ((insn & 0x0C00) >> 10);
}
static int
cris_get_opcode (unsigned short insn)
{
return ((insn & 0x03C0) >> 6);
}
static int
cris_get_size (unsigned short insn)
{
return ((insn & 0x0030) >> 4);
}
static int
cris_get_operand1 (unsigned short insn)
{
return (insn & 0x000F);
}
static int
cris_get_quick_value (unsigned short insn)
{
return (insn & 0x003F);
}
static int
cris_get_bdap_quick_offset (unsigned short insn)
{
return (insn & 0x00FF);
}
static int
cris_get_branch_short_offset (unsigned short insn)
{
return (insn & 0x00FF);
}
static int
cris_get_asr_shift_steps (unsigned long value)
{
return (value & 0x3F);
}
static int
cris_get_clear_size (unsigned short insn)
{
return ((insn) & 0xC000);
}
static int
cris_is_signed_extend_bit_on (unsigned short insn)
{
return (((insn) & 0x20) == 0x20);
}
static int
cris_is_xflag_bit_on (unsigned short insn)
{
return (((insn) & 0x1000) == 0x1000);
}
static void
cris_set_size_to_dword (unsigned short *insn)
{
*insn &= 0xFFCF;
*insn |= 0x20;
}
static signed char
cris_get_signed_offset (unsigned short insn)
{
return ((signed char) (insn & 0x00FF));
}
static void cris_gdb_func (enum cris_op_type, unsigned short, inst_env_type *);
static struct gdbarch *cris_gdbarch_init (struct gdbarch_info,
struct gdbarch_list *);
static void cris_dump_tdep (struct gdbarch *, struct ui_file *);
static void set_cris_version (char *ignore_args, int from_tty,
struct cmd_list_element *c);
static void set_cris_mode (char *ignore_args, int from_tty,
struct cmd_list_element *c);
static void set_cris_dwarf2_cfi (char *ignore_args, int from_tty,
struct cmd_list_element *c);
static CORE_ADDR cris_scan_prologue (CORE_ADDR pc,
struct frame_info *next_frame,
struct cris_unwind_cache *info);
static CORE_ADDR crisv32_scan_prologue (CORE_ADDR pc,
struct frame_info *next_frame,
struct cris_unwind_cache *info);
static CORE_ADDR cris_unwind_pc (struct gdbarch *gdbarch,
struct frame_info *next_frame);
static CORE_ADDR cris_unwind_sp (struct gdbarch *gdbarch,
struct frame_info *next_frame);
struct stack_item
{
int len;
struct stack_item *prev;
void *data;
};
static struct stack_item *
push_stack_item (struct stack_item *prev, void *contents, int len)
{
struct stack_item *si;
si = xmalloc (sizeof (struct stack_item));
si->data = xmalloc (len);
si->len = len;
si->prev = prev;
memcpy (si->data, contents, len);
return si;
}
static struct stack_item *
pop_stack_item (struct stack_item *si)
{
struct stack_item *dead = si;
si = si->prev;
xfree (dead->data);
xfree (dead);
return si;
}
struct cris_unwind_cache *
cris_frame_unwind_cache (struct frame_info *next_frame,
void **this_prologue_cache)
{
CORE_ADDR pc;
struct cris_unwind_cache *info;
int i;
if ((*this_prologue_cache))
return (*this_prologue_cache);
info = FRAME_OBSTACK_ZALLOC (struct cris_unwind_cache);
(*this_prologue_cache) = info;
info->saved_regs = trad_frame_alloc_saved_regs (next_frame);
info->prev_sp = 0;
info->base = 0;
info->size = 0;
info->sp_offset = 0;
info->r8_offset = 0;
info->uses_frame = 0;
info->return_pc = 0;
info->leaf_function = 0;
if (cris_version () == 32)
crisv32_scan_prologue (frame_func_unwind (next_frame), next_frame, info);
else
cris_scan_prologue (frame_func_unwind (next_frame), next_frame, info);
return info;
}
static void
cris_frame_this_id (struct frame_info *next_frame,
void **this_prologue_cache,
struct frame_id *this_id)
{
struct cris_unwind_cache *info
= cris_frame_unwind_cache (next_frame, this_prologue_cache);
CORE_ADDR base;
CORE_ADDR func;
struct frame_id id;
func = frame_func_unwind (next_frame);
base = info->prev_sp;
if (base == 0)
return;
id = frame_id_build (base, func);
(*this_id) = id;
}
static void
cris_frame_prev_register (struct frame_info *next_frame,
void **this_prologue_cache,
int regnum, enum opt_state *optimizedp,
enum lval_type *lvalp, CORE_ADDR *addrp,
int *realnump, gdb_byte *bufferp)
{
struct cris_unwind_cache *info
= cris_frame_unwind_cache (next_frame, this_prologue_cache);
trad_frame_get_prev_register (next_frame, info->saved_regs, regnum,
optimizedp, lvalp, addrp, realnump, bufferp);
}
static struct frame_id
cris_unwind_dummy_id (struct gdbarch *gdbarch, struct frame_info *next_frame)
{
return frame_id_build (cris_unwind_sp (gdbarch, next_frame),
frame_pc_unwind (next_frame));
}
static CORE_ADDR
cris_frame_align (struct gdbarch *gdbarch, CORE_ADDR sp)
{
return sp & ~3;
}
static CORE_ADDR
cris_push_dummy_code (struct gdbarch *gdbarch,
CORE_ADDR sp, CORE_ADDR funaddr, int using_gcc,
struct value **args, int nargs,
struct type *value_type,
CORE_ADDR *real_pc, CORE_ADDR *bp_addr)
{
sp = (sp - 4) & ~3;
*bp_addr = sp;
*real_pc = funaddr;
return sp;
}
static CORE_ADDR
cris_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
struct regcache *regcache, CORE_ADDR bp_addr,
int nargs, struct value **args, CORE_ADDR sp,
int struct_return, CORE_ADDR struct_addr)
{
int stack_alloc;
int stack_offset;
int argreg;
int argnum;
CORE_ADDR regval;
CORE_ADDR fp_arg;
CORE_ADDR fp_mem;
struct stack_item *si = NULL;
regcache_cooked_write_unsigned (regcache, SRP_REGNUM, bp_addr);
if (struct_return)
{
regcache_cooked_write_unsigned (regcache, STR_REGNUM, struct_addr);
}
argreg = ARG1_REGNUM;
stack_offset = 0;
for (argnum = 0; argnum < nargs; argnum++)
{
int len;
char *val;
int reg_demand;
int i;
len = TYPE_LENGTH (value_type (args[argnum]));
val = (char *) value_contents (args[argnum]);
reg_demand = (len / 4) + (len % 4 != 0 ? 1 : 0);
if (len <= (2 * 4) && (argreg + reg_demand - 1 <= ARG4_REGNUM))
{
for (i = 0; i < reg_demand; i++)
{
regcache_cooked_write_unsigned (regcache, argreg,
*(unsigned long *) val);
argreg++;
val += 4;
}
}
else if (len <= (2 * 4) && argreg <= ARG4_REGNUM)
{
for (i = 0; i < reg_demand; i++)
{
if (argreg <= ARG4_REGNUM)
{
regcache_cooked_write_unsigned (regcache, argreg,
*(unsigned long *) val);
argreg++;
val += 4;
}
else
{
si = push_stack_item (si, val, 4);
val += 4;
}
}
}
else if (len > (2 * 4))
{
internal_error (__FILE__, __LINE__, _("We don't do this"));
}
else
{
si = push_stack_item (si, val, len);
}
}
while (si)
{
sp = (sp - si->len) & ~3;
write_memory (sp, si->data, si->len);
si = pop_stack_item (si);
}
regcache_cooked_write_unsigned (regcache, SP_REGNUM, sp);
return sp;
}
static const struct frame_unwind cris_frame_unwind =
{
NORMAL_FRAME,
cris_frame_this_id,
cris_frame_prev_register
};
const struct frame_unwind *
cris_frame_sniffer (struct frame_info *next_frame)
{
return &cris_frame_unwind;
}
static CORE_ADDR
cris_frame_base_address (struct frame_info *next_frame, void **this_cache)
{
struct cris_unwind_cache *info
= cris_frame_unwind_cache (next_frame, this_cache);
return info->base;
}
static const struct frame_base cris_frame_base =
{
&cris_frame_unwind,
cris_frame_base_address,
cris_frame_base_address,
cris_frame_base_address
};
static CORE_ADDR
cris_scan_prologue (CORE_ADDR pc, struct frame_info *next_frame,
struct cris_unwind_cache *info)
{
unsigned short insn;
unsigned short insn_next;
int regno;
int have_fp;
int val;
int regsave;
short source_register;
int limit;
if (info)
{
info->leaf_function = 1;
}
val = 0;
regsave = -1;
limit = next_frame ? frame_pc_unwind (next_frame) : pc + 64;
while (pc > 0 && pc < limit)
{
insn = read_memory_unsigned_integer (pc, 2);
pc += 2;
if (insn == 0xE1FC)
{
insn_next = read_memory_unsigned_integer (pc, 2);
pc += 2;
regno = cris_get_operand2 (insn_next);
if (info)
{
info->sp_offset += 4;
}
if (insn_next == 0xBE7E)
{
if (info)
{
info->leaf_function = 0;
}
}
else if (insn_next == 0x8FEE)
{
if (info)
{
info->r8_offset = info->sp_offset;
}
}
}
else if (insn == 0x866E)
{
if (info)
{
info->uses_frame = 1;
}
continue;
}
else if (cris_get_operand2 (insn) == SP_REGNUM
&& cris_get_mode (insn) == 0x0000
&& cris_get_opcode (insn) == 0x000A)
{
if (info)
{
info->sp_offset += cris_get_quick_value (insn);
}
}
else if (cris_get_mode (insn) == 0x0002
&& cris_get_opcode (insn) == 0x000F
&& cris_get_size (insn) == 0x0003
&& cris_get_operand1 (insn) == SP_REGNUM)
{
regsave = cris_get_operand2 (insn);
}
else if (cris_get_operand2 (insn) == SP_REGNUM
&& ((insn & 0x0F00) >> 8) == 0x0001
&& (cris_get_signed_offset (insn) < 0))
{
if (info)
{
info->sp_offset += -cris_get_signed_offset (insn);
}
insn_next = read_memory_unsigned_integer (pc, 2);
pc += 2;
if (cris_get_mode (insn_next) == PREFIX_ASSIGN_MODE
&& cris_get_opcode (insn_next) == 0x000F
&& cris_get_size (insn_next) == 0x0003
&& cris_get_operand1 (insn_next) == SP_REGNUM)
{
regsave = cris_get_operand2 (insn_next);
}
else
{
pc -= 4;
break;
}
}
else if (cris_get_mode (insn) == 0x0001
&& cris_get_opcode (insn) == 0x0009
&& cris_get_size (insn) == 0x0002)
{
source_register = cris_get_operand1 (insn);
if (source_register < ARG1_REGNUM || source_register > ARG4_REGNUM)
{
pc -= 2;
break;
}
}
else if (cris_get_operand2 (insn) == CRIS_FP_REGNUM
&& ((insn & 0x0F00) >> 8) == 0x0001
&& (cris_get_signed_offset (insn) < 0))
{
insn_next = read_memory_unsigned_integer (pc, 2);
pc += 2;
regno = cris_get_operand2 (insn_next);
if ((regno >= 0 && regno < SP_REGNUM)
&& cris_get_mode (insn_next) == PREFIX_OFFSET_MODE
&& cris_get_opcode (insn_next) == 0x000F)
{
continue;
}
else
{
pc -= 4;
break;
}
}
else if (cris_get_operand2 (insn) == CRIS_FP_REGNUM
&& ((insn & 0x0F00) >> 8) == 0x0001
&& (cris_get_signed_offset (insn) > 0))
{
insn_next = read_memory_unsigned_integer (pc, 2);
pc += 2;
regno = cris_get_operand2 (insn_next);
if ((regno >= 0 && regno < SP_REGNUM)
&& cris_get_mode (insn_next) == PREFIX_OFFSET_MODE
&& cris_get_opcode (insn_next) == 0x0009
&& cris_get_operand1 (insn_next) == regno)
{
continue;
}
else
{
pc -= 4;
break;
}
}
else
{
pc -= 2;
break;
}
}
if (next_frame == NULL && info == NULL)
{
return pc;
}
info->size = info->sp_offset;
if (info->uses_frame)
{
ULONGEST this_base;
frame_unwind_unsigned_register (next_frame, CRIS_FP_REGNUM,
&this_base);
info->base = this_base;
info->saved_regs[CRIS_FP_REGNUM].addr = info->base;
info->prev_sp = info->base + info->r8_offset;
}
else
{
ULONGEST this_base;
frame_unwind_unsigned_register (next_frame, SP_REGNUM, &this_base);
info->base = this_base;
info->prev_sp = info->base + info->size;
}
val = info->sp_offset;
for (regno = regsave; regno >= 0; regno--)
{
info->saved_regs[regno].addr = info->base + info->r8_offset - val;
val -= 4;
}
trad_frame_set_value (info->saved_regs, SP_REGNUM, info->prev_sp);
if (!info->leaf_function)
{
if (info->r8_offset == 0)
{
info->saved_regs[SRP_REGNUM].addr = info->base;
}
else
{
info->saved_regs[SRP_REGNUM].addr = info->base + 4;
}
}
info->saved_regs[PC_REGNUM] = info->saved_regs[SRP_REGNUM];
return pc;
}
static CORE_ADDR
crisv32_scan_prologue (CORE_ADDR pc, struct frame_info *next_frame,
struct cris_unwind_cache *info)
{
ULONGEST this_base;
if (next_frame == NULL && info == NULL)
{
return pc;
}
frame_unwind_unsigned_register (next_frame, SP_REGNUM, &this_base);
info->base = this_base;
info->prev_sp = this_base;
info->saved_regs[PC_REGNUM] = info->saved_regs[SRP_REGNUM];
return pc;
}
static CORE_ADDR
cris_skip_prologue (CORE_ADDR pc)
{
CORE_ADDR func_addr, func_end;
struct symtab_and_line sal;
CORE_ADDR pc_after_prologue;
if (find_pc_partial_function (pc, NULL, &func_addr, &func_end))
{
sal = find_pc_line (func_addr, 0);
if (sal.end > 0 && sal.end < func_end)
return sal.end;
}
if (cris_version () == 32)
pc_after_prologue = crisv32_scan_prologue (pc, NULL, NULL);
else
pc_after_prologue = cris_scan_prologue (pc, NULL, NULL);
return pc_after_prologue;
}
static CORE_ADDR
cris_unwind_pc (struct gdbarch *gdbarch, struct frame_info *next_frame)
{
ULONGEST pc;
frame_unwind_unsigned_register (next_frame, PC_REGNUM, &pc);
return pc;
}
static CORE_ADDR
cris_unwind_sp (struct gdbarch *gdbarch, struct frame_info *next_frame)
{
ULONGEST sp;
frame_unwind_unsigned_register (next_frame, SP_REGNUM, &sp);
return sp;
}
static const unsigned char *
cris_breakpoint_from_pc (CORE_ADDR *pcptr, int *lenptr)
{
static unsigned char break8_insn[] = {0x38, 0xe9};
static unsigned char break15_insn[] = {0x3f, 0xe9};
*lenptr = 2;
if (cris_mode () == cris_mode_guru)
return break15_insn;
else
return break8_insn;
}
static int
cris_spec_reg_applicable (struct cris_spec_reg spec_reg)
{
int version = cris_version ();
switch (spec_reg.applicable_version)
{
case cris_ver_version_all:
return 1;
case cris_ver_warning:
return 0;
case cris_ver_v0_3:
return (version >= 0 && version <= 3);
case cris_ver_v3p:
return (version >= 3);
case cris_ver_v8:
return (version == 8 || version == 9);
case cris_ver_v8p:
return (version >= 8);
case cris_ver_v0_10:
return (version >= 0 && version <= 10);
case cris_ver_v3_10:
return (version >= 3 && version <= 10);
case cris_ver_v8_10:
return (version >= 8 && version <= 10);
case cris_ver_v10:
return (version == 10);
case cris_ver_v10p:
return (version >= 10);
case cris_ver_v32p:
return (version >= 32);
default:
return 0;
}
}
static int
cris_register_size (int regno)
{
struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
int i;
int spec_regno;
if (regno >= 0 && regno < NUM_GENREGS)
{
return 4;
}
else if (regno >= NUM_GENREGS && regno < (NUM_GENREGS + NUM_SPECREGS))
{
spec_regno = regno - NUM_GENREGS;
for (i = 0; cris_spec_regs[i].name != NULL; i++)
{
if (cris_spec_regs[i].number == spec_regno
&& cris_spec_reg_applicable (cris_spec_regs[i]))
return cris_spec_regs[i].reg_size;
}
return 0;
}
else if (regno >= PC_REGNUM && regno < NUM_REGS)
{
return 4;
}
return -1;
}
static int
cris_cannot_fetch_register (int regno)
{
return ((regno < 0 || regno >= NUM_REGS)
|| (cris_register_size (regno) == 0));
}
static int
cris_cannot_store_register (int regno)
{
if (regno < 0 || regno >= NUM_REGS || cris_register_size (regno) == 0)
return 1;
else if (regno == VR_REGNUM)
return 1;
else if (regno == P0_REGNUM || regno == P4_REGNUM || regno == P8_REGNUM)
return 1;
return 0;
}
static int
crisv32_cannot_fetch_register (int regno)
{
return ((regno < 0 || regno >= NUM_REGS)
|| (cris_register_size (regno) == 0));
}
static int
crisv32_cannot_store_register (int regno)
{
if (regno < 0 || regno >= NUM_REGS || cris_register_size (regno) == 0)
return 1;
else if (regno == VR_REGNUM)
return 1;
else if (regno == BZ_REGNUM || regno == WZ_REGNUM || regno == DZ_REGNUM)
return 1;
return 0;
}
static struct type *
cris_register_type (struct gdbarch *gdbarch, int regno)
{
if (regno == PC_REGNUM)
return builtin_type_void_func_ptr;
else if (regno == SP_REGNUM || regno == CRIS_FP_REGNUM)
return builtin_type_void_data_ptr;
else if ((regno >= 0 && regno < SP_REGNUM)
|| (regno >= MOF_REGNUM && regno <= USP_REGNUM))
return builtin_type_uint32;
else if (regno >= P4_REGNUM && regno <= CCR_REGNUM)
return builtin_type_uint16;
else if (regno >= P0_REGNUM && regno <= VR_REGNUM)
return builtin_type_uint8;
else
return builtin_type_int0;
}
static struct type *
crisv32_register_type (struct gdbarch *gdbarch, int regno)
{
if (regno == PC_REGNUM)
return builtin_type_void_func_ptr;
else if (regno == SP_REGNUM || regno == CRIS_FP_REGNUM)
return builtin_type_void_data_ptr;
else if ((regno >= 0 && regno <= ACR_REGNUM)
|| (regno >= EXS_REGNUM && regno <= SPC_REGNUM)
|| (regno == PID_REGNUM)
|| (regno >= S0_REGNUM && regno <= S15_REGNUM))
return builtin_type_uint32;
else if (regno == WZ_REGNUM)
return builtin_type_uint16;
else if (regno == BZ_REGNUM || regno == VR_REGNUM || regno == SRS_REGNUM)
return builtin_type_uint8;
else
{
warning (_("crisv32_register_type: unknown regno %d"), regno);
return builtin_type_int0;
}
}
static void
cris_store_return_value (struct type *type, struct regcache *regcache,
const void *valbuf)
{
ULONGEST val;
int len = TYPE_LENGTH (type);
if (len <= 4)
{
val = extract_unsigned_integer (valbuf, len);
regcache_cooked_write_unsigned (regcache, ARG1_REGNUM, val);
}
else if (len <= 8)
{
val = extract_unsigned_integer (valbuf, 4);
regcache_cooked_write_unsigned (regcache, ARG1_REGNUM, val);
val = extract_unsigned_integer ((char *)valbuf + 4, len - 4);
regcache_cooked_write_unsigned (regcache, ARG2_REGNUM, val);
}
else
error (_("cris_store_return_value: type length too large."));
}
static const char *
cris_special_register_name (int regno)
{
int spec_regno;
int i;
spec_regno = regno - NUM_GENREGS;
for (i = 0; cris_spec_regs[i].name != NULL; i++)
{
if (cris_spec_regs[i].number == spec_regno
&& cris_spec_reg_applicable (cris_spec_regs[i]))
return cris_spec_regs[i].name;
}
return NULL;
}
static const char *
cris_register_name (int regno)
{
static char *cris_genreg_names[] =
{ "r0", "r1", "r2", "r3", \
"r4", "r5", "r6", "r7", \
"r8", "r9", "r10", "r11", \
"r12", "r13", "sp", "pc" };
if (regno >= 0 && regno < NUM_GENREGS)
{
return cris_genreg_names[regno];
}
else if (regno >= NUM_GENREGS && regno < NUM_REGS)
{
return cris_special_register_name (regno);
}
else
{
return NULL;
}
}
static const char *
crisv32_register_name (int regno)
{
static char *crisv32_genreg_names[] =
{ "r0", "r1", "r2", "r3", \
"r4", "r5", "r6", "r7", \
"r8", "r9", "r10", "r11", \
"r12", "r13", "sp", "acr"
};
static char *crisv32_sreg_names[] =
{ "s0", "s1", "s2", "s3", \
"s4", "s5", "s6", "s7", \
"s8", "s9", "s10", "s11", \
"s12", "s13", "s14", "s15"
};
if (regno >= 0 && regno < NUM_GENREGS)
{
return crisv32_genreg_names[regno];
}
else if (regno >= NUM_GENREGS && regno < (NUM_GENREGS + NUM_SPECREGS))
{
return cris_special_register_name (regno);
}
else if (regno == PC_REGNUM)
{
return "pc";
}
else if (regno >= S0_REGNUM && regno <= S15_REGNUM)
{
return crisv32_sreg_names[regno - S0_REGNUM];
}
else
{
return NULL;
}
}
static int
cris_dwarf2_reg_to_regnum (int reg)
{
static int cris_dwarf_regmap[] = {
0, 1, 2, 3,
4, 5, 6, 7,
8, 9, 10, 11,
12, 13, 14, 15,
27, -1, -1, -1,
-1, -1, -1, 23,
-1, -1, -1, 27,
-1, -1, -1, -1
};
int regnum = -1;
if (reg >= 0 && reg < ARRAY_SIZE (cris_dwarf_regmap))
regnum = cris_dwarf_regmap[reg];
if (regnum == -1)
warning (_("Unmapped DWARF Register #%d encountered."), reg);
return regnum;
}
static void
cris_dwarf2_frame_init_reg (struct gdbarch *gdbarch, int regnum,
struct dwarf2_frame_state_reg *reg)
{
if (regnum == PC_REGNUM)
reg->how = DWARF2_FRAME_REG_RA;
else if (regnum == SP_REGNUM)
reg->how = DWARF2_FRAME_REG_CFA;
}
static void
cris_extract_return_value (struct type *type, struct regcache *regcache,
void *valbuf)
{
ULONGEST val;
int len = TYPE_LENGTH (type);
if (len <= 4)
{
regcache_cooked_read_unsigned (regcache, ARG1_REGNUM, &val);
store_unsigned_integer (valbuf, len, val);
}
else if (len <= 8)
{
regcache_cooked_read_unsigned (regcache, ARG1_REGNUM, &val);
store_unsigned_integer (valbuf, 4, val);
regcache_cooked_read_unsigned (regcache, ARG2_REGNUM, &val);
store_unsigned_integer ((char *)valbuf + 4, len - 4, val);
}
else
error (_("cris_extract_return_value: type length too large"));
}
static enum return_value_convention
cris_return_value (struct gdbarch *gdbarch, struct type *type,
struct regcache *regcache, gdb_byte *readbuf,
const gdb_byte *writebuf)
{
if (TYPE_CODE (type) == TYPE_CODE_STRUCT
|| TYPE_CODE (type) == TYPE_CODE_UNION
|| TYPE_LENGTH (type) > 8)
return RETURN_VALUE_STRUCT_CONVENTION;
if (readbuf)
cris_extract_return_value (type, regcache, readbuf);
if (writebuf)
cris_store_return_value (type, regcache, writebuf);
return RETURN_VALUE_REGISTER_CONVENTION;
}
static int
cris_reg_struct_has_addr (int gcc_p, struct type *type)
{
return (TYPE_LENGTH (type) > 8);
}
static int
constraint (unsigned int insn, const signed char *inst_args,
inst_env_type *inst_env)
{
int retval = 0;
int tmp, i;
const char *s = inst_args;
for (; *s; s++)
switch (*s)
{
case 'm':
if ((insn & 0x30) == 0x30)
return -1;
break;
case 'S':
if (inst_env->prefix_found)
break;
else
return -1;
case 'B':
if (inst_env->prefix_found)
break;
else
return -1;
case 'D':
retval = (((insn >> 0xC) & 0xF) == (insn & 0xF));
if (!retval)
return -1;
else
retval += 4;
break;
case 'P':
tmp = (insn >> 0xC) & 0xF;
for (i = 0; cris_spec_regs[i].name != NULL; i++)
{
if (tmp == cris_spec_regs[i].number)
{
retval += 3;
break;
}
}
if (cris_spec_regs[i].name == NULL)
return -1;
break;
}
return retval;
}
static int
number_of_bits (unsigned int value)
{
int number_of_bits = 0;
while (value != 0)
{
number_of_bits += 1;
value &= (value - 1);
}
return number_of_bits;
}
static int
find_cris_op (unsigned short insn, inst_env_type *inst_env)
{
int i;
int max_level_of_match = -1;
int max_matched = -1;
int level_of_match;
for (i = 0; cris_opcodes[i].name != NULL; i++)
{
if (((cris_opcodes[i].match & insn) == cris_opcodes[i].match)
&& ((cris_opcodes[i].lose & insn) == 0)
&& (cris_opcodes[i].applicable_version != cris_ver_v32p))
{
level_of_match = constraint (insn, cris_opcodes[i].args, inst_env);
if (level_of_match >= 0)
{
level_of_match +=
number_of_bits (cris_opcodes[i].match | cris_opcodes[i].lose);
if (level_of_match > max_level_of_match)
{
max_matched = i;
max_level_of_match = level_of_match;
if (level_of_match == 16)
{
break;
}
}
}
}
}
return max_matched;
}
static int
find_step_target (inst_env_type *inst_env)
{
int i;
int offset;
unsigned short insn;
for (i = 0; i < NUM_GENREGS; i++)
{
inst_env->reg[i] = (unsigned long) read_register (i);
}
offset = NUM_GENREGS;
for (i = 0; i < NUM_SPECREGS; i++)
{
inst_env->preg[i] = (unsigned long) read_register (offset + i);
}
inst_env->branch_found = 0;
inst_env->slot_needed = 0;
inst_env->delay_slot_pc_active = 0;
inst_env->prefix_found = 0;
inst_env->invalid = 0;
inst_env->xflag_found = 0;
inst_env->disable_interrupt = 0;
do
{
insn = read_memory_unsigned_integer (inst_env->reg[PC_REGNUM], 2);
if (!inst_env->delay_slot_pc_active)
{
inst_env->reg[PC_REGNUM] += 2;
}
else
{
inst_env->delay_slot_pc_active = 0;
inst_env->reg[PC_REGNUM] = inst_env->delay_slot_pc;
}
i = find_cris_op (insn, inst_env);
if (i == -1)
{
inst_env->invalid = 1;
}
else
{
cris_gdb_func (cris_opcodes[i].op, insn, inst_env);
}
} while (!inst_env->invalid
&& (inst_env->prefix_found || inst_env->xflag_found
|| inst_env->slot_needed));
return i;
}
static void
cris_software_single_step (enum target_signal ignore, int insert_breakpoints)
{
inst_env_type inst_env;
if (insert_breakpoints)
{
int status = find_step_target (&inst_env);
if (status == -1)
{
warning (_("CRIS software single step could not find a step target."));
}
else
{
next_pc = (CORE_ADDR) inst_env.reg[PC_REGNUM];
target_insert_breakpoint (next_pc, break_mem[0]);
if (inst_env.branch_found
&& (CORE_ADDR) inst_env.branch_break_address != next_pc)
{
branch_target_address =
(CORE_ADDR) inst_env.branch_break_address;
target_insert_breakpoint (branch_target_address, break_mem[1]);
branch_break_inserted = 1;
}
}
}
else
{
target_remove_breakpoint (next_pc, break_mem[0]);
if (branch_break_inserted)
{
target_remove_breakpoint (branch_target_address, break_mem[1]);
branch_break_inserted = 0;
}
}
}
static void
quick_mode_bdap_prefix (unsigned short inst, inst_env_type *inst_env)
{
if (inst_env->slot_needed || inst_env->prefix_found)
{
inst_env->invalid = 1;
return;
}
inst_env->prefix_value = inst_env->reg[cris_get_operand2 (inst)];
inst_env->prefix_value += cris_get_bdap_quick_offset (inst);
inst_env->slot_needed = 0;
inst_env->prefix_found = 1;
}
static void
process_autoincrement (int size, unsigned short inst, inst_env_type *inst_env)
{
if (size == INST_BYTE_SIZE)
{
inst_env->reg[cris_get_operand1 (inst)] += 1;
if (cris_get_operand1 (inst) == REG_PC)
{
inst_env->reg[REG_PC] += 1;
}
}
else if (size == INST_WORD_SIZE)
{
inst_env->reg[cris_get_operand1 (inst)] += 2;
}
else if (size == INST_DWORD_SIZE)
{
inst_env->reg[cris_get_operand1 (inst)] += 4;
}
else
{
inst_env->invalid = 1;
}
}
static unsigned long get_data_from_address (unsigned short *inst,
CORE_ADDR address);
static void
bdap_prefix (unsigned short inst, inst_env_type *inst_env)
{
long offset;
if (inst_env->slot_needed || inst_env->prefix_found)
{
inst_env->invalid = 1;
return;
}
inst_env->prefix_value = inst_env->reg[cris_get_operand2 (inst)];
inst_env->prefix_value +=
get_data_from_address (&inst, inst_env->reg[cris_get_operand1 (inst)]);
if (cris_get_mode (inst) == AUTOINC_MODE)
{
process_autoincrement (cris_get_size (inst), inst, inst_env);
}
inst_env->slot_needed = 0;
inst_env->prefix_found = 1;
}
static void
biap_prefix (unsigned short inst, inst_env_type *inst_env)
{
if (inst_env->slot_needed || inst_env->prefix_found)
{
inst_env->invalid = 1;
return;
}
inst_env->prefix_value = inst_env->reg[cris_get_operand1 (inst)];
inst_env->prefix_value +=
inst_env->reg[cris_get_operand2 (inst)] << cris_get_size (inst);
if (cris_get_operand1 (inst) == REG_PC)
{
inst_env->prefix_value += 2;
}
inst_env->slot_needed = 0;
inst_env->xflag_found = 0;
inst_env->prefix_found = 1;
}
static void
dip_prefix (unsigned short inst, inst_env_type *inst_env)
{
CORE_ADDR address;
if (inst_env->slot_needed || inst_env->prefix_found)
{
inst_env->invalid = 1;
return;
}
address = (CORE_ADDR) inst_env->reg[cris_get_operand1 (inst)];
inst_env->prefix_value = read_memory_unsigned_integer (address, 4);
if (cris_get_mode (inst) == AUTOINC_MODE)
{
inst_env->reg[cris_get_operand1 (inst)] += 4;
}
inst_env->slot_needed = 0;
inst_env->xflag_found = 0;
inst_env->prefix_found = 1;
}
static void
eight_bit_offset_branch_op (unsigned short inst, inst_env_type *inst_env)
{
short offset;
if (inst_env->slot_needed || inst_env->prefix_found)
{
inst_env->invalid = 1;
return;
}
offset = cris_get_branch_short_offset (inst);
if (offset & BRANCH_SIGNED_SHORT_OFFSET_MASK)
{
offset |= 0xFF00;
}
offset &= ~BRANCH_SIGNED_SHORT_OFFSET_MASK;
inst_env->branch_found = 1;
inst_env->branch_break_address = inst_env->reg[REG_PC] + offset;
inst_env->slot_needed = 1;
inst_env->prefix_found = 0;
inst_env->xflag_found = 0;
inst_env->disable_interrupt = 1;
}
static void
sixteen_bit_offset_branch_op (unsigned short inst, inst_env_type *inst_env)
{
short offset;
if (inst_env->slot_needed || inst_env->prefix_found)
{
inst_env->invalid = 1;
return;
}
offset = read_memory_integer (inst_env->reg[REG_PC], 2);
inst_env->reg[REG_PC] += 2;
inst_env->branch_found = 1;
inst_env->branch_break_address = inst_env->reg[REG_PC] + offset;
inst_env->slot_needed = 1;
inst_env->prefix_found = 0;
inst_env->xflag_found = 0;
inst_env->disable_interrupt = 1;
}
static void
abs_op (unsigned short inst, inst_env_type *inst_env)
{
long value;
if (inst_env->prefix_found)
{
inst_env->invalid = 1;
return;
}
if (cris_get_operand2 (inst) == REG_PC)
{
if (inst_env->slot_needed)
{
inst_env->invalid = 1;
return;
}
value = (long) inst_env->reg[REG_PC];
if (value != SIGNED_DWORD_MASK)
{
value = -value;
inst_env->reg[REG_PC] = (long) value;
}
}
inst_env->slot_needed = 0;
inst_env->prefix_found = 0;
inst_env->xflag_found = 0;
inst_env->disable_interrupt = 0;
}
static void
addi_op (unsigned short inst, inst_env_type *inst_env)
{
if (inst_env->prefix_found || (cris_get_operand1 (inst) == REG_PC))
{
inst_env->invalid = 1;
return;
}
inst_env->slot_needed = 0;
inst_env->prefix_found = 0;
inst_env->xflag_found = 0;
inst_env->disable_interrupt = 0;
}
static void
asr_op (unsigned short inst, inst_env_type *inst_env)
{
int shift_steps;
unsigned long value;
unsigned long signed_extend_mask = 0;
if (inst_env->prefix_found)
{
inst_env->invalid = 1;
return;
}
if (cris_get_operand2 (inst) == REG_PC)
{
if (inst_env->slot_needed)
{
inst_env->invalid = 1;
return;
}
shift_steps = cris_get_asr_shift_steps (inst_env->reg[cris_get_operand1 (inst)]);
value = inst_env->reg[REG_PC];
if (cris_get_size (inst) == INST_BYTE_SIZE)
{
if (value & SIGNED_BYTE_MASK)
{
signed_extend_mask = 0xFF;
signed_extend_mask = signed_extend_mask >> shift_steps;
signed_extend_mask = ~signed_extend_mask;
}
value = value >> shift_steps;
value |= signed_extend_mask;
value &= 0xFF;
inst_env->reg[REG_PC] &= 0xFFFFFF00;
inst_env->reg[REG_PC] |= value;
}
else if (cris_get_size (inst) == INST_WORD_SIZE)
{
if (value & SIGNED_WORD_MASK)
{
signed_extend_mask = 0xFFFF;
signed_extend_mask = signed_extend_mask >> shift_steps;
signed_extend_mask = ~signed_extend_mask;
}
value = value >> shift_steps;
value |= signed_extend_mask;
value &= 0xFFFF;
inst_env->reg[REG_PC] &= 0xFFFF0000;
inst_env->reg[REG_PC] |= value;
}
else if (cris_get_size (inst) == INST_DWORD_SIZE)
{
if (value & SIGNED_DWORD_MASK)
{
signed_extend_mask = 0xFFFFFFFF;
signed_extend_mask = signed_extend_mask >> shift_steps;
signed_extend_mask = ~signed_extend_mask;
}
value = value >> shift_steps;
value |= signed_extend_mask;
inst_env->reg[REG_PC] = value;
}
}
inst_env->slot_needed = 0;
inst_env->prefix_found = 0;
inst_env->xflag_found = 0;
inst_env->disable_interrupt = 0;
}
static void
asrq_op (unsigned short inst, inst_env_type *inst_env)
{
int shift_steps;
unsigned long value;
unsigned long signed_extend_mask = 0;
if (inst_env->prefix_found)
{
inst_env->invalid = 1;
return;
}
if (cris_get_operand2 (inst) == REG_PC)
{
if (inst_env->slot_needed)
{
inst_env->invalid = 1;
return;
}
shift_steps = cris_get_asr_shift_steps (inst);
value = inst_env->reg[REG_PC];
if (value & SIGNED_DWORD_MASK)
{
signed_extend_mask = 0xFFFFFFFF;
signed_extend_mask = signed_extend_mask >> shift_steps;
signed_extend_mask = ~signed_extend_mask;
}
value = value >> shift_steps;
value |= signed_extend_mask;
inst_env->reg[REG_PC] = value;
}
inst_env->slot_needed = 0;
inst_env->prefix_found = 0;
inst_env->xflag_found = 0;
inst_env->disable_interrupt = 0;
}
static void
ax_ei_setf_op (unsigned short inst, inst_env_type *inst_env)
{
if (inst_env->prefix_found)
{
inst_env->invalid = 1;
return;
}
if (cris_is_xflag_bit_on (inst))
{
inst_env->xflag_found = 1;
}
else
{
inst_env->xflag_found = 0;
}
inst_env->slot_needed = 0;
inst_env->prefix_found = 0;
inst_env->disable_interrupt = 1;
}
static void
check_assign (unsigned short inst, inst_env_type *inst_env)
{
if (cris_get_mode (inst) == PREFIX_ASSIGN_MODE)
{
inst_env->reg[cris_get_operand1 (inst)] = inst_env->prefix_value;
}
}
static void
two_operand_bound_op (unsigned short inst, inst_env_type *inst_env)
{
if (cris_get_operand2 (inst) == REG_PC)
{
inst_env->invalid = 1;
return;
}
if (inst_env->prefix_found)
{
check_assign (inst, inst_env);
}
else if (cris_get_mode (inst) == AUTOINC_MODE)
{
if (inst_env->slot_needed)
{
inst_env->invalid = 1;
return;
}
process_autoincrement (cris_get_size (inst), inst, inst_env);
}
inst_env->slot_needed = 0;
inst_env->prefix_found = 0;
inst_env->xflag_found = 0;
inst_env->disable_interrupt = 0;
}
static void
three_operand_bound_op (unsigned short inst, inst_env_type *inst_env)
{
if ((!inst_env->prefix_found) || (cris_get_operand1 (inst) == REG_PC))
{
inst_env->invalid = 1;
return;
}
inst_env->slot_needed = 0;
inst_env->prefix_found = 0;
inst_env->xflag_found = 0;
inst_env->disable_interrupt = 0;
}
static void
btst_nop_op (unsigned short inst, inst_env_type *inst_env)
{
if (inst_env->prefix_found)
{
inst_env->invalid = 1;
return;
}
inst_env->slot_needed = 0;
inst_env->prefix_found = 0;
inst_env->xflag_found = 0;
inst_env->disable_interrupt = 0;
}
static void
clearf_di_op (unsigned short inst, inst_env_type *inst_env)
{
if (inst_env->prefix_found)
{
inst_env->invalid = 1;
return;
}
inst_env->slot_needed = 0;
inst_env->prefix_found = 0;
inst_env->xflag_found = 0;
inst_env->disable_interrupt = 1;
}
static void
reg_mode_clear_op (unsigned short inst, inst_env_type *inst_env)
{
if (cris_get_operand2 (inst) == REG_PC)
{
int clear_size = cris_get_clear_size (inst);
if (clear_size == INST_BYTE_SIZE)
{
inst_env->delay_slot_pc = inst_env->reg[REG_PC] & 0xFFFFFF00;
}
if (clear_size == INST_WORD_SIZE)
{
inst_env->delay_slot_pc = inst_env->reg[REG_PC] & 0xFFFF0000;
}
if (clear_size == INST_DWORD_SIZE)
{
inst_env->delay_slot_pc = 0x0;
}
inst_env->slot_needed = 1;
inst_env->delay_slot_pc_active = 1;
}
else
{
inst_env->slot_needed = 0;
}
inst_env->prefix_found = 0;
inst_env->xflag_found = 0;
inst_env->disable_interrupt = 0;
}
static void
reg_mode_test_op (unsigned short inst, inst_env_type *inst_env)
{
if (inst_env->prefix_found)
{
inst_env->invalid = 1;
return;
}
inst_env->slot_needed = 0;
inst_env->prefix_found = 0;
inst_env->xflag_found = 0;
inst_env->disable_interrupt = 0;
}
static void
none_reg_mode_clear_test_op (unsigned short inst, inst_env_type *inst_env)
{
if (inst_env->prefix_found)
{
check_assign (inst, inst_env);
}
else if (cris_get_mode (inst) == AUTOINC_MODE)
{
process_autoincrement (cris_get_size (inst), inst, inst_env);
}
inst_env->slot_needed = 0;
inst_env->prefix_found = 0;
inst_env->xflag_found = 0;
inst_env->disable_interrupt = 0;
}
static void
dstep_logshift_mstep_neg_not_op (unsigned short inst, inst_env_type *inst_env)
{
if ((cris_get_operand2 (inst) == REG_PC) || inst_env->prefix_found)
{
inst_env->invalid = 1;
return;
}
inst_env->slot_needed = 0;
inst_env->prefix_found = 0;
inst_env->xflag_found = 0;
inst_env->disable_interrupt = 0;
}
static void
break_op (unsigned short inst, inst_env_type *inst_env)
{
if (inst_env->prefix_found)
{
inst_env->invalid = 1;
return;
}
inst_env->slot_needed = 0;
inst_env->prefix_found = 0;
inst_env->xflag_found = 0;
inst_env->disable_interrupt = 1;
}
static void
scc_op (unsigned short inst, inst_env_type *inst_env)
{
if ((cris_get_operand2 (inst) == REG_PC) || inst_env->prefix_found)
{
inst_env->invalid = 1;
return;
}
inst_env->slot_needed = 0;
inst_env->prefix_found = 0;
inst_env->xflag_found = 0;
inst_env->disable_interrupt = 1;
}
static void
reg_mode_jump_op (unsigned short inst, inst_env_type *inst_env)
{
if ((inst_env->slot_needed) || (inst_env->prefix_found))
{
inst_env->invalid = 1;
return;
}
inst_env->reg[REG_PC] = inst_env->reg[cris_get_operand1 (inst)];
inst_env->slot_needed = 0;
inst_env->prefix_found = 0;
inst_env->xflag_found = 0;
inst_env->disable_interrupt = 1;
}
static void
none_reg_mode_jump_op (unsigned short inst, inst_env_type *inst_env)
{
unsigned long newpc;
CORE_ADDR address;
if (inst_env->slot_needed)
{
inst_env->invalid = 1;
}
else
{
if (inst_env->prefix_found)
{
check_assign (inst, inst_env);
newpc =
read_memory_unsigned_integer ((CORE_ADDR) inst_env->prefix_value,
4);
}
else
{
address = (CORE_ADDR) inst_env->reg[cris_get_operand1 (inst)];
newpc = read_memory_unsigned_integer (address, 4);
if (cris_get_mode (inst) == AUTOINC_MODE)
{
inst_env->reg[cris_get_operand1 (inst)] += 4;
}
}
inst_env->reg[REG_PC] = newpc;
}
inst_env->slot_needed = 0;
inst_env->prefix_found = 0;
inst_env->xflag_found = 0;
inst_env->disable_interrupt = 1;
}
static void
move_to_preg_op (unsigned short inst, inst_env_type *inst_env)
{
if (inst_env->prefix_found)
{
if (cris_get_mode (inst) == PREFIX_ASSIGN_MODE)
{
if (cris_get_operand1 (inst) == REG_PC)
{
check_assign (inst, inst_env);
}
}
}
else if (cris_get_mode (inst) == AUTOINC_MODE)
{
if (cris_get_operand1 (inst) == REG_PC)
{
if (inst_env->slot_needed)
{
inst_env->invalid = 1;
return;
}
if (cris_register_size (cris_get_operand2 (inst)) == 1)
{
process_autoincrement (INST_BYTE_SIZE, inst, inst_env);
}
else if (cris_register_size (cris_get_operand2 (inst)) == 2)
{
process_autoincrement (INST_WORD_SIZE, inst, inst_env);
}
else
{
process_autoincrement (INST_DWORD_SIZE, inst, inst_env);
}
}
}
inst_env->slot_needed = 0;
inst_env->prefix_found = 0;
inst_env->xflag_found = 0;
inst_env->disable_interrupt = 1;
}
static void
none_reg_mode_move_from_preg_op (unsigned short inst, inst_env_type *inst_env)
{
if (inst_env->prefix_found)
{
if (cris_get_mode (inst) == PREFIX_ASSIGN_MODE)
{
if (cris_get_operand1 (inst) == REG_PC)
{
check_assign (inst, inst_env);
}
}
}
else if (cris_get_mode (inst) == AUTOINC_MODE)
{
if (cris_get_operand1 (inst) == REG_PC)
{
if (inst_env->slot_needed)
{
inst_env->invalid = 1;
return;
}
if (cris_register_size (cris_get_operand2 (inst)) == 1)
{
process_autoincrement (INST_BYTE_SIZE, inst, inst_env);
}
else if (cris_register_size (cris_get_operand2 (inst)) == 2)
{
process_autoincrement (INST_WORD_SIZE, inst, inst_env);
}
else
{
process_autoincrement (INST_DWORD_SIZE, inst, inst_env);
}
}
}
inst_env->slot_needed = 0;
inst_env->prefix_found = 0;
inst_env->xflag_found = 0;
inst_env->disable_interrupt = 1;
}
static void
reg_mode_move_from_preg_op (unsigned short inst, inst_env_type *inst_env)
{
if (inst_env->prefix_found)
{
inst_env->invalid = 1;
return;
}
if (cris_get_operand1 (inst) == REG_PC)
{
if (inst_env->slot_needed)
{
inst_env->invalid = 1;
return;
}
inst_env->delay_slot_pc = inst_env->preg[cris_get_operand2 (inst)];
inst_env->slot_needed = 1;
inst_env->delay_slot_pc_active = 1;
}
else
{
inst_env->slot_needed = 0;
}
inst_env->prefix_found = 0;
inst_env->xflag_found = 0;
inst_env->disable_interrupt = 1;
}
static void
move_mem_to_reg_movem_op (unsigned short inst, inst_env_type *inst_env)
{
if (inst_env->prefix_found)
{
if (cris_get_operand2 (inst) >= REG_PC)
{
inst_env->reg[REG_PC] =
read_memory_unsigned_integer (inst_env->prefix_value, 4);
}
if ((cris_get_operand1 (inst) == REG_PC)
&& (cris_get_mode (inst) == PREFIX_ASSIGN_MODE))
{
inst_env->reg[REG_PC] = inst_env->prefix_value;
inst_env->reg[REG_PC] += 4 * (cris_get_operand2 (inst) + 1);
}
}
else
{
if (cris_get_operand2 (inst) == REG_PC)
{
if (inst_env->slot_needed)
{
inst_env->invalid = 1;
return;
}
inst_env->reg[REG_PC] =
read_memory_unsigned_integer (inst_env->reg[cris_get_operand1 (inst)],
4);
}
if ((cris_get_operand1 (inst) == REG_PC) && (cris_get_mode (inst) == AUTOINC_MODE))
{
if (inst_env->slot_needed)
{
inst_env->invalid = 1;
return;
}
inst_env->reg[REG_PC] += 4 * (cris_get_operand2 (inst) + 1);
}
}
inst_env->slot_needed = 0;
inst_env->prefix_found = 0;
inst_env->xflag_found = 0;
inst_env->disable_interrupt = 0;
}
static void
move_reg_to_mem_movem_op (unsigned short inst, inst_env_type *inst_env)
{
if (inst_env->prefix_found)
{
if ((cris_get_operand1 (inst) == REG_PC) &&
(cris_get_mode (inst) == PREFIX_ASSIGN_MODE))
{
inst_env->reg[REG_PC] = inst_env->prefix_value;
inst_env->reg[REG_PC] += 4 * (cris_get_operand2 (inst) + 1);
}
}
else
{
if ((cris_get_operand1 (inst) == REG_PC) && (cris_get_mode (inst) == AUTOINC_MODE))
{
if (inst_env->slot_needed)
{
inst_env->invalid = 1;
return;
}
inst_env->reg[REG_PC] += 4 * (cris_get_operand2 (inst) + 1);
}
}
inst_env->slot_needed = 0;
inst_env->prefix_found = 0;
inst_env->xflag_found = 0;
inst_env->disable_interrupt = 0;
}
static void
not_implemented_op (unsigned short inst, inst_env_type *inst_env)
{
inst_env->invalid = 1;
}
static void
xor_op (unsigned short inst, inst_env_type *inst_env)
{
if (inst_env->prefix_found)
{
inst_env->invalid = 1;
return;
}
if (cris_get_operand2 (inst) == REG_PC)
{
if (inst_env->slot_needed)
{
inst_env->invalid = 1;
return;
}
inst_env->reg[REG_PC] ^= inst_env->reg[cris_get_operand1 (inst)];
}
inst_env->slot_needed = 0;
inst_env->prefix_found = 0;
inst_env->xflag_found = 0;
inst_env->disable_interrupt = 0;
}
static void
muls_op (unsigned short inst, inst_env_type *inst_env)
{
if (inst_env->prefix_found)
{
inst_env->invalid = 1;
return;
}
if (cris_get_operand2 (inst) == REG_PC)
{
inst_env->invalid = 1;
return;
}
inst_env->slot_needed = 0;
inst_env->prefix_found = 0;
inst_env->xflag_found = 0;
inst_env->disable_interrupt = 0;
}
static void
mulu_op (unsigned short inst, inst_env_type *inst_env)
{
if (inst_env->prefix_found)
{
inst_env->invalid = 1;
return;
}
if (cris_get_operand2 (inst) == REG_PC)
{
inst_env->invalid = 1;
return;
}
inst_env->slot_needed = 0;
inst_env->prefix_found = 0;
inst_env->xflag_found = 0;
inst_env->disable_interrupt = 0;
}
static void
add_sub_cmp_and_or_move_action (unsigned short inst, inst_env_type *inst_env,
unsigned long source1, unsigned long source2)
{
unsigned long pc_mask;
unsigned long operation_mask;
if (cris_get_size (inst) == INST_BYTE_SIZE)
{
pc_mask = 0xFFFFFF00;
operation_mask = 0xFF;
}
else if (cris_get_size (inst) == INST_WORD_SIZE)
{
pc_mask = 0xFFFF0000;
operation_mask = 0xFFFF;
}
else if (cris_get_size (inst) == INST_DWORD_SIZE)
{
pc_mask = 0x0;
operation_mask = 0xFFFFFFFF;
}
else
{
inst_env->invalid = 1;
return;
}
source2 &= operation_mask;
source1 &= operation_mask;
switch (cris_get_opcode (inst) & 7)
{
case 0:
source1 += source2;
break;
case 1:
source1 = source2;
break;
case 2:
source1 -= source2;
break;
case 3:
break;
case 4:
source1 &= source2;
break;
case 5:
source1 |= source2;
break;
default:
inst_env->invalid = 1;
return;
break;
}
source2 &= operation_mask;
inst_env->reg[REG_PC] &= pc_mask;
inst_env->reg[REG_PC] |= source1;
}
static unsigned long
do_sign_or_zero_extend (unsigned long value, unsigned short *inst)
{
if (cris_get_size (*inst) & INST_WORD_SIZE)
{
value &= 0xFFFF;
if (cris_is_signed_extend_bit_on (*inst) && (value & SIGNED_WORD_MASK))
{
value |= SIGNED_WORD_EXTEND_MASK;
}
}
else
{
value &= 0xFF;
if (cris_is_signed_extend_bit_on (*inst) && (value & SIGNED_BYTE_MASK))
{
value |= SIGNED_BYTE_EXTEND_MASK;
}
}
cris_set_size_to_dword (inst);
return value;
}
static void
reg_mode_add_sub_cmp_and_or_move_op (unsigned short inst,
inst_env_type *inst_env)
{
unsigned long operand1;
unsigned long operand2;
if (inst_env->prefix_found)
{
inst_env->invalid = 1;
return;
}
if (cris_get_operand2 (inst) == REG_PC)
{
if (inst_env->slot_needed)
{
inst_env->invalid = 1;
return;
}
operand1 = inst_env->reg[cris_get_operand1 (inst)];
operand2 = inst_env->reg[REG_PC];
if (cris_get_opcode (inst) < 4)
{
operand1 = do_sign_or_zero_extend (operand1, &inst);
}
add_sub_cmp_and_or_move_action (inst, inst_env, operand2, operand1);
}
inst_env->slot_needed = 0;
inst_env->prefix_found = 0;
inst_env->xflag_found = 0;
inst_env->disable_interrupt = 0;
}
static unsigned long
get_data_from_address (unsigned short *inst, CORE_ADDR address)
{
int size = cris_get_size (*inst);
unsigned long value;
if (cris_get_opcode (*inst) < 4)
{
size &= ~SIGNED_EXTEND_BIT_MASK;
}
size = 1 << size;
value = read_memory_unsigned_integer (address, size);
if (cris_get_opcode (*inst) < 4)
{
value = do_sign_or_zero_extend (value, inst);
}
return value;
}
static void
handle_prefix_assign_mode_for_aritm_op (unsigned short inst,
inst_env_type *inst_env)
{
unsigned long operand2;
unsigned long operand3;
check_assign (inst, inst_env);
if (cris_get_operand2 (inst) == REG_PC)
{
operand2 = inst_env->reg[REG_PC];
operand3 = get_data_from_address (&inst, inst_env->prefix_value);
add_sub_cmp_and_or_move_action (inst, inst_env, operand2, operand3);
}
inst_env->slot_needed = 0;
inst_env->prefix_found = 0;
inst_env->xflag_found = 0;
inst_env->disable_interrupt = 0;
}
static void
three_operand_add_sub_cmp_and_or_op (unsigned short inst,
inst_env_type *inst_env)
{
unsigned long operand2;
unsigned long operand3;
if (cris_get_operand1 (inst) == REG_PC)
{
operand2 = inst_env->reg[cris_get_operand2 (inst)];
operand3 = get_data_from_address (&inst, inst_env->prefix_value);
add_sub_cmp_and_or_move_action (inst, inst_env, operand2, operand3);
}
inst_env->slot_needed = 0;
inst_env->prefix_found = 0;
inst_env->xflag_found = 0;
inst_env->disable_interrupt = 0;
}
static void
handle_prefix_index_mode_for_aritm_op (unsigned short inst,
inst_env_type *inst_env)
{
if (cris_get_operand1 (inst) != cris_get_operand2 (inst))
{
inst_env->invalid = 1;
return;
}
else
{
three_operand_add_sub_cmp_and_or_op (inst, inst_env);
}
inst_env->slot_needed = 0;
inst_env->prefix_found = 0;
inst_env->xflag_found = 0;
inst_env->disable_interrupt = 0;
}
static void
handle_inc_and_index_mode_for_aritm_op (unsigned short inst,
inst_env_type *inst_env)
{
unsigned long operand1;
unsigned long operand2;
unsigned long operand3;
int size;
if (cris_get_operand2 (inst) == REG_PC)
{
size = cris_get_size (inst);
operand2 = inst_env->reg[REG_PC];
operand1 = inst_env->reg[cris_get_operand1 (inst)];
operand3 = get_data_from_address (&inst, operand1);
add_sub_cmp_and_or_move_action (inst, inst_env, operand2, operand3);
}
if ((cris_get_operand1 (inst) == REG_PC) && (cris_get_mode (inst) == AUTOINC_MODE))
{
size = cris_get_size (inst);
if (cris_get_opcode (inst) < 4)
{
size &= ~SIGNED_EXTEND_BIT_MASK;
}
process_autoincrement (size, inst, inst_env);
}
inst_env->slot_needed = 0;
inst_env->prefix_found = 0;
inst_env->xflag_found = 0;
inst_env->disable_interrupt = 0;
}
static void
none_reg_mode_add_sub_cmp_and_or_move_op (unsigned short inst,
inst_env_type *inst_env)
{
if (inst_env->prefix_found)
{
if (cris_get_mode (inst) == PREFIX_INDEX_MODE)
{
handle_prefix_index_mode_for_aritm_op (inst, inst_env);
}
else if (cris_get_mode (inst) == PREFIX_ASSIGN_MODE)
{
handle_prefix_assign_mode_for_aritm_op (inst, inst_env);
}
else
{
inst_env->invalid = 1;
return;
}
}
else
{
handle_inc_and_index_mode_for_aritm_op (inst, inst_env);
}
}
static void
quick_mode_add_sub_op (unsigned short inst, inst_env_type *inst_env)
{
unsigned long operand1;
unsigned long operand2;
if (inst_env->prefix_found)
{
inst_env->invalid = 1;
return;
}
if (cris_get_operand2 (inst) == REG_PC)
{
if (inst_env->slot_needed)
{
inst_env->invalid = 1;
return;
}
operand1 = cris_get_quick_value (inst);
operand2 = inst_env->reg[REG_PC];
cris_set_size_to_dword (&inst);
add_sub_cmp_and_or_move_action (inst, inst_env, operand2, operand1);
}
inst_env->slot_needed = 0;
inst_env->prefix_found = 0;
inst_env->xflag_found = 0;
inst_env->disable_interrupt = 0;
}
static void
quick_mode_and_cmp_move_or_op (unsigned short inst, inst_env_type *inst_env)
{
unsigned long operand1;
unsigned long operand2;
if (inst_env->prefix_found)
{
inst_env->invalid = 1;
return;
}
if (cris_get_operand2 (inst) == REG_PC)
{
if (inst_env->slot_needed)
{
inst_env->invalid = 1;
return;
}
operand1 = cris_get_quick_value (inst);
operand2 = inst_env->reg[REG_PC];
if (operand1 & SIGNED_QUICK_VALUE_MASK)
{
operand1 |= SIGNED_QUICK_VALUE_EXTEND_MASK;
}
cris_set_size_to_dword (&inst);
add_sub_cmp_and_or_move_action (inst, inst_env, operand2, operand1);
}
inst_env->slot_needed = 0;
inst_env->prefix_found = 0;
inst_env->xflag_found = 0;
inst_env->disable_interrupt = 0;
}
static void
cris_gdb_func (enum cris_op_type op_type, unsigned short inst,
inst_env_type *inst_env)
{
switch (op_type)
{
case cris_not_implemented_op:
not_implemented_op (inst, inst_env);
break;
case cris_abs_op:
abs_op (inst, inst_env);
break;
case cris_addi_op:
addi_op (inst, inst_env);
break;
case cris_asr_op:
asr_op (inst, inst_env);
break;
case cris_asrq_op:
asrq_op (inst, inst_env);
break;
case cris_ax_ei_setf_op:
ax_ei_setf_op (inst, inst_env);
break;
case cris_bdap_prefix:
bdap_prefix (inst, inst_env);
break;
case cris_biap_prefix:
biap_prefix (inst, inst_env);
break;
case cris_break_op:
break_op (inst, inst_env);
break;
case cris_btst_nop_op:
btst_nop_op (inst, inst_env);
break;
case cris_clearf_di_op:
clearf_di_op (inst, inst_env);
break;
case cris_dip_prefix:
dip_prefix (inst, inst_env);
break;
case cris_dstep_logshift_mstep_neg_not_op:
dstep_logshift_mstep_neg_not_op (inst, inst_env);
break;
case cris_eight_bit_offset_branch_op:
eight_bit_offset_branch_op (inst, inst_env);
break;
case cris_move_mem_to_reg_movem_op:
move_mem_to_reg_movem_op (inst, inst_env);
break;
case cris_move_reg_to_mem_movem_op:
move_reg_to_mem_movem_op (inst, inst_env);
break;
case cris_move_to_preg_op:
move_to_preg_op (inst, inst_env);
break;
case cris_muls_op:
muls_op (inst, inst_env);
break;
case cris_mulu_op:
mulu_op (inst, inst_env);
break;
case cris_none_reg_mode_add_sub_cmp_and_or_move_op:
none_reg_mode_add_sub_cmp_and_or_move_op (inst, inst_env);
break;
case cris_none_reg_mode_clear_test_op:
none_reg_mode_clear_test_op (inst, inst_env);
break;
case cris_none_reg_mode_jump_op:
none_reg_mode_jump_op (inst, inst_env);
break;
case cris_none_reg_mode_move_from_preg_op:
none_reg_mode_move_from_preg_op (inst, inst_env);
break;
case cris_quick_mode_add_sub_op:
quick_mode_add_sub_op (inst, inst_env);
break;
case cris_quick_mode_and_cmp_move_or_op:
quick_mode_and_cmp_move_or_op (inst, inst_env);
break;
case cris_quick_mode_bdap_prefix:
quick_mode_bdap_prefix (inst, inst_env);
break;
case cris_reg_mode_add_sub_cmp_and_or_move_op:
reg_mode_add_sub_cmp_and_or_move_op (inst, inst_env);
break;
case cris_reg_mode_clear_op:
reg_mode_clear_op (inst, inst_env);
break;
case cris_reg_mode_jump_op:
reg_mode_jump_op (inst, inst_env);
break;
case cris_reg_mode_move_from_preg_op:
reg_mode_move_from_preg_op (inst, inst_env);
break;
case cris_reg_mode_test_op:
reg_mode_test_op (inst, inst_env);
break;
case cris_scc_op:
scc_op (inst, inst_env);
break;
case cris_sixteen_bit_offset_branch_op:
sixteen_bit_offset_branch_op (inst, inst_env);
break;
case cris_three_operand_add_sub_cmp_and_or_op:
three_operand_add_sub_cmp_and_or_op (inst, inst_env);
break;
case cris_three_operand_bound_op:
three_operand_bound_op (inst, inst_env);
break;
case cris_two_operand_bound_op:
two_operand_bound_op (inst, inst_env);
break;
case cris_xor_op:
xor_op (inst, inst_env);
break;
}
}
static int
cris_delayed_get_disassembler (bfd_vma addr, struct disassemble_info *info)
{
int (*print_insn) (bfd_vma addr, struct disassemble_info *info);
gdb_assert (exec_bfd != NULL);
print_insn = cris_get_disassembler (exec_bfd);
gdb_assert (print_insn != NULL);
return print_insn (addr, info);
}
typedef unsigned long elf_greg_t;
#define CRISV10_ELF_NGREG 35
typedef elf_greg_t elf_gregset_t[CRISV10_ELF_NGREG];
#define CRISV32_ELF_NGREG 32
typedef elf_greg_t crisv32_elf_gregset_t[CRISV32_ELF_NGREG];
static void
supply_gregset (elf_gregset_t *gregsetp)
{
struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
int i;
elf_greg_t *regp = *gregsetp;
static char zerobuf[4] = {0};
for (i = 0; i < NUM_GENREGS + NUM_SPECREGS; i++)
{
regcache_raw_supply (current_regcache, i, (char *)®p[i]);
}
if (tdep->cris_version == 32)
{
regcache_raw_supply (current_regcache, PC_REGNUM,
(char *)®p[ERP_REGNUM]);
if (*(char *)®p[ERP_REGNUM] & 0x1)
fprintf_unfiltered (gdb_stderr, "Warning: PC in delay slot\n");
}
}
static void
fetch_core_registers (char *core_reg_sect, unsigned core_reg_size,
int which, CORE_ADDR reg_addr)
{
elf_gregset_t gregset;
switch (which)
{
case 0:
if (core_reg_size != sizeof (elf_gregset_t)
&& core_reg_size != sizeof (crisv32_elf_gregset_t))
{
warning (_("wrong size gregset struct in core file"));
}
else
{
memcpy (&gregset, core_reg_sect, sizeof (gregset));
supply_gregset (&gregset);
}
default:
break;
}
}
static struct core_fns cris_elf_core_fns =
{
bfd_target_elf_flavour,
default_check_format,
default_core_sniffer,
fetch_core_registers,
NULL
};
static struct link_map_offsets *
cris_linux_svr4_fetch_link_map_offsets (void)
{
static struct link_map_offsets lmo;
static struct link_map_offsets *lmp = NULL;
if (lmp == NULL)
{
lmp = &lmo;
lmo.r_debug_size = 8;
lmo.r_map_offset = 4;
lmo.r_map_size = 4;
lmo.link_map_size = 20;
lmo.l_addr_offset = 0;
lmo.l_addr_size = 4;
lmo.l_name_offset = 4;
lmo.l_name_size = 4;
lmo.l_next_offset = 12;
lmo.l_next_size = 4;
lmo.l_prev_offset = 16;
lmo.l_prev_size = 4;
}
return lmp;
}
extern initialize_file_ftype _initialize_cris_tdep;
void
_initialize_cris_tdep (void)
{
static struct cmd_list_element *cris_set_cmdlist;
static struct cmd_list_element *cris_show_cmdlist;
struct cmd_list_element *c;
gdbarch_register (bfd_arch_cris, cris_gdbarch_init, cris_dump_tdep);
add_setshow_uinteger_cmd ("cris-version", class_support,
&usr_cmd_cris_version,
_("Set the current CRIS version."),
_("Show the current CRIS version."),
_("\
Set to 10 for CRISv10 or 32 for CRISv32 if autodetection fails.\n\
Defaults to 10. "),
set_cris_version,
NULL,
&setlist, &showlist);
add_setshow_enum_cmd ("cris-mode", class_support,
cris_modes, &usr_cmd_cris_mode,
_("Set the current CRIS mode."),
_("Show the current CRIS mode."),
_("\
Set to CRIS_MODE_GURU when debugging in guru mode.\n\
Makes GDB use the NRP register instead of the ERP register in certain cases."),
set_cris_mode,
NULL,
&setlist, &showlist);
add_setshow_boolean_cmd ("cris-dwarf2-cfi", class_support,
&usr_cmd_cris_dwarf2_cfi,
_("Set the usage of Dwarf-2 CFI for CRIS."),
_("Show the usage of Dwarf-2 CFI for CRIS."),
_("Set this to \"off\" if using gcc-cris < R59."),
set_cris_dwarf2_cfi,
NULL,
&setlist, &showlist);
deprecated_add_core_fns (&cris_elf_core_fns);
}
static void
cris_dump_tdep (struct gdbarch *gdbarch, struct ui_file *file)
{
struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
if (tdep != NULL)
{
fprintf_unfiltered (file, "cris_dump_tdep: tdep->cris_version = %i\n",
tdep->cris_version);
fprintf_unfiltered (file, "cris_dump_tdep: tdep->cris_mode = %s\n",
tdep->cris_mode);
fprintf_unfiltered (file, "cris_dump_tdep: tdep->cris_dwarf2_cfi = %i\n",
tdep->cris_dwarf2_cfi);
}
}
static void
set_cris_version (char *ignore_args, int from_tty,
struct cmd_list_element *c)
{
struct gdbarch_info info;
usr_cmd_cris_version_valid = 1;
gdbarch_info_init (&info);
if (!gdbarch_update_p (info))
internal_error (__FILE__, __LINE__,
_("cris_gdbarch_update: failed to update architecture."));
}
static void
set_cris_mode (char *ignore_args, int from_tty,
struct cmd_list_element *c)
{
struct gdbarch_info info;
gdbarch_info_init (&info);
if (!gdbarch_update_p (info))
internal_error (__FILE__, __LINE__,
"cris_gdbarch_update: failed to update architecture.");
}
static void
set_cris_dwarf2_cfi (char *ignore_args, int from_tty,
struct cmd_list_element *c)
{
struct gdbarch_info info;
gdbarch_info_init (&info);
if (!gdbarch_update_p (info))
internal_error (__FILE__, __LINE__,
_("cris_gdbarch_update: failed to update architecture."));
}
static struct gdbarch *
cris_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
{
struct gdbarch *gdbarch;
struct gdbarch_tdep *tdep;
int cris_version;
if (usr_cmd_cris_version_valid)
{
cris_version = usr_cmd_cris_version;
}
else if (info.abfd && bfd_get_mach (info.abfd) == bfd_mach_cris_v32)
{
cris_version = 32;
}
else
{
cris_version = 10;
}
usr_cmd_cris_version = cris_version;
for (arches = gdbarch_list_lookup_by_info (arches, &info);
arches != NULL;
arches = gdbarch_list_lookup_by_info (arches->next, &info))
{
if ((gdbarch_tdep (arches->gdbarch)->cris_version
== usr_cmd_cris_version)
&& (gdbarch_tdep (arches->gdbarch)->cris_mode
== usr_cmd_cris_mode)
&& (gdbarch_tdep (arches->gdbarch)->cris_dwarf2_cfi
== usr_cmd_cris_dwarf2_cfi))
return arches->gdbarch;
}
tdep = (struct gdbarch_tdep *) xmalloc (sizeof (struct gdbarch_tdep));
gdbarch = gdbarch_alloc (&info, tdep);
tdep->cris_version = usr_cmd_cris_version;
tdep->cris_mode = usr_cmd_cris_mode;
tdep->cris_dwarf2_cfi = usr_cmd_cris_dwarf2_cfi;
switch (info.byte_order)
{
case BFD_ENDIAN_LITTLE:
break;
case BFD_ENDIAN_BIG:
internal_error (__FILE__, __LINE__, _("cris_gdbarch_init: big endian byte order in info"));
break;
default:
internal_error (__FILE__, __LINE__, _("cris_gdbarch_init: unknown byte order in info"));
}
set_gdbarch_return_value (gdbarch, cris_return_value);
set_gdbarch_deprecated_reg_struct_has_addr (gdbarch,
cris_reg_struct_has_addr);
set_gdbarch_deprecated_use_struct_convention (gdbarch, always_use_struct_convention);
set_gdbarch_sp_regnum (gdbarch, 14);
set_gdbarch_double_bit (gdbarch, 64);
set_gdbarch_long_double_bit (gdbarch, 64);
switch (tdep->cris_version)
{
case 0:
case 1:
case 2:
case 3:
case 8:
case 9:
internal_error (__FILE__, __LINE__,
_("cris_gdbarch_init: unsupported CRIS version"));
break;
case 10:
case 11:
set_gdbarch_pc_regnum (gdbarch, 15);
set_gdbarch_register_type (gdbarch, cris_register_type);
set_gdbarch_num_regs (gdbarch, 32);
set_gdbarch_register_name (gdbarch, cris_register_name);
set_gdbarch_cannot_store_register (gdbarch, cris_cannot_store_register);
set_gdbarch_cannot_fetch_register (gdbarch, cris_cannot_fetch_register);
set_gdbarch_software_single_step (gdbarch, cris_software_single_step);
break;
case 32:
set_gdbarch_pc_regnum (gdbarch, 32);
set_gdbarch_register_type (gdbarch, crisv32_register_type);
set_gdbarch_num_regs (gdbarch, 32 + 1 + 16);
set_gdbarch_register_name (gdbarch, crisv32_register_name);
set_gdbarch_cannot_store_register
(gdbarch, crisv32_cannot_store_register);
set_gdbarch_cannot_fetch_register
(gdbarch, crisv32_cannot_fetch_register);
set_gdbarch_have_nonsteppable_watchpoint (gdbarch, 1);
set_gdbarch_single_step_through_delay
(gdbarch, crisv32_single_step_through_delay);
break;
default:
internal_error (__FILE__, __LINE__,
_("cris_gdbarch_init: unknown CRIS version"));
}
set_gdbarch_push_dummy_code (gdbarch, cris_push_dummy_code);
set_gdbarch_push_dummy_call (gdbarch, cris_push_dummy_call);
set_gdbarch_frame_align (gdbarch, cris_frame_align);
set_gdbarch_skip_prologue (gdbarch, cris_skip_prologue);
set_gdbarch_inner_than (gdbarch, core_addr_lessthan);
set_gdbarch_breakpoint_from_pc (gdbarch, cris_breakpoint_from_pc);
set_gdbarch_unwind_pc (gdbarch, cris_unwind_pc);
set_gdbarch_unwind_sp (gdbarch, cris_unwind_sp);
set_gdbarch_unwind_dummy_id (gdbarch, cris_unwind_dummy_id);
if (tdep->cris_dwarf2_cfi == 1)
{
set_gdbarch_dwarf2_reg_to_regnum (gdbarch, cris_dwarf2_reg_to_regnum);
dwarf2_frame_set_init_reg (gdbarch, cris_dwarf2_frame_init_reg);
frame_unwind_append_sniffer (gdbarch, dwarf2_frame_sniffer);
}
if (tdep->cris_mode != cris_mode_guru)
{
frame_unwind_append_sniffer (gdbarch, cris_sigtramp_frame_sniffer);
}
frame_unwind_append_sniffer (gdbarch, cris_frame_sniffer);
frame_base_set_default (gdbarch, &cris_frame_base);
set_solib_svr4_fetch_link_map_offsets
(gdbarch, cris_linux_svr4_fetch_link_map_offsets);
set_gdbarch_print_insn (gdbarch, cris_delayed_get_disassembler);
return gdbarch;
}