#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
};
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,
P0_REGNUM = 16,
VR_REGNUM = 17,
P2_REGNUM = 18,
P3_REGNUM = 19,
P4_REGNUM = 20,
CCR_REGNUM = 21,
MOF_REGNUM = 23,
P8_REGNUM = 24,
IBR_REGNUM = 25,
IRP_REGNUM = 26,
SRP_REGNUM = 27,
BAR_REGNUM = 28,
DCCR_REGNUM = 29,
BRP_REGNUM = 30,
USP_REGNUM = 31
};
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 *usr_cmd_cris_mode;
static int usr_cmd_cris_mode_valid = 0;
static const char CRIS_MODE_USER[] = "CRIS_MODE_USER";
static const char CRIS_MODE_SUPERVISOR[] = "CRIS_MODE_SUPERVISOR";
static const char *cris_mode_enums[] =
{
CRIS_MODE_USER,
CRIS_MODE_SUPERVISOR,
0
};
struct gdbarch_tdep
{
int cris_version;
const char *cris_mode;
};
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);
}
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;
};
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 cris_version_update (char *ignore_args, int from_tty,
struct cmd_list_element *c);
static void cris_mode_update (char *ignore_args, int from_tty,
struct cmd_list_element *c);
static CORE_ADDR bfd_lookup_symbol (bfd *, const char *);
static CORE_ADDR cris_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;
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, int *optimizedp,
enum lval_type *lvalp, CORE_ADDR *addrp,
int *realnump, void *bufferp)
{
struct cris_unwind_cache *info
= cris_frame_unwind_cache (next_frame, this_prologue_cache);
trad_frame_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, CORE_ADDR func_addr,
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 < 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 == 0x866E)
{
if (info)
{
info->uses_frame = 1;
info->r8_offset = info->sp_offset;
}
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->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;
}
info->saved_regs[CRIS_FP_REGNUM].addr = info->base;
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)
{
info->saved_regs[SRP_REGNUM].addr = info->base + 4;
}
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;
}
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 break_insn[] = {0x38, 0xe9};
*lenptr = 2;
return break_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_sim:
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_v10p:
return (version >= 10);
default:
return 0;
}
}
static int
cris_register_size (int regno)
{
int i;
int spec_regno;
if (regno >= 0 && regno < NUM_GENREGS)
{
return 4;
}
else if (regno >= NUM_GENREGS && regno < NUM_REGS)
{
spec_regno = regno - NUM_GENREGS;
for (i = spec_regno; 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
{
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;
else if (cris_mode () == CRIS_MODE_USER)
{
if (regno == IBR_REGNUM || regno == BAR_REGNUM || regno == BRP_REGNUM
|| regno == IRP_REGNUM)
return 1;
}
return 0;
}
static int
cris_register_offset (int regno)
{
int i;
int reg_size;
int offset = 0;
if (regno >= 0 && regno < NUM_REGS)
{
for (i = 0; i < regno; i++)
offset += cris_register_size (i);
return offset;
}
else
{
return -1;
}
}
static struct type *
cris_register_virtual_type (int regno)
{
if (regno == SP_REGNUM || regno == PC_REGNUM
|| (regno > P8_REGNUM && regno < USP_REGNUM))
{
return lookup_pointer_type (builtin_type_void);
}
else if (regno == P8_REGNUM || regno == USP_REGNUM
|| (regno >= 0 && regno < SP_REGNUM))
{
return builtin_type_unsigned_long;
}
else if (regno > P3_REGNUM && regno < P8_REGNUM)
{
return builtin_type_unsigned_short;
}
else if (regno > PC_REGNUM && regno < P4_REGNUM)
{
return builtin_type_unsigned_char;
}
else
{
return builtin_type_void;
}
}
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_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" };
int i;
int spec_regno;
if (regno >= 0 && regno < NUM_GENREGS)
{
return cris_genreg_names[regno];
}
else if (regno >= NUM_GENREGS && regno < NUM_REGS)
{
spec_regno = regno - NUM_GENREGS;
for (i = spec_regno; 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;
}
else
{
return NULL;
}
}
static int
cris_register_bytes_ok (long bytes)
{
return (bytes == DEPRECATED_REGISTER_BYTES);
}
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 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))
{
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)
{
}
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;
typedef elf_greg_t elf_gregset_t[35];
static void
supply_gregset (elf_gregset_t *gregsetp)
{
int i;
elf_greg_t *regp = *gregsetp;
static char zerobuf[4] = {0};
for (i = 0; i < NUM_GENREGS + NUM_SPECREGS; i++)
{
supply_register (i, (char *)®p[i]);
}
}
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 (gregset))
{
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;
}
static void
cris_fpless_backtrace (char *noargs, int from_tty)
{
CORE_ADDR pc = 0;
CORE_ADDR tmp_pc = 0;
CORE_ADDR sp = 0;
struct symtab_and_line sal;
char* func_name;
unsigned short insn;
unsigned short insn_next;
int sp_add_later = 0;
int push_srp_found = 0;
int val = 0;
int frame = 0;
int innermost_frame = 1;
deprecated_read_register_gen (PC_REGNUM, (char *) &pc);
deprecated_read_register_gen (SP_REGNUM, (char *) &sp);
while (1)
{
sal = find_pc_line (pc, 0);
find_pc_partial_function (pc, &func_name, (CORE_ADDR *) NULL,
(CORE_ADDR *) NULL);
printf_unfiltered ("#%i 0x%08lx in %s", frame++, pc, func_name);
if (sal.symtab)
{
printf_unfiltered (" at %s:%i", sal.symtab->filename, sal.line);
}
printf_unfiltered ("\n");
tmp_pc = get_pc_function_start (pc);
while (tmp_pc < pc)
{
insn = read_memory_unsigned_integer (tmp_pc, sizeof (short));
tmp_pc += sizeof (short);
if (insn == 0xE1FC)
{
insn_next = read_memory_unsigned_integer (tmp_pc,
sizeof (short));
tmp_pc += sizeof (short);
if (insn_next == 0xBE7E)
{
push_srp_found = 1;
sp_add_later += 4;
}
else
{
if (push_srp_found)
{
sp += 4;
}
else
{
sp_add_later += 4;
}
}
}
else if (cris_get_operand2 (insn) == SP_REGNUM
&& cris_get_mode (insn) == 0x0000
&& cris_get_opcode (insn) == 0x000A)
{
val = cris_get_quick_value (insn);
if (push_srp_found)
{
sp += val;
}
else
{
sp_add_later += val;
}
}
else if (cris_get_operand2 (insn) == SP_REGNUM
&& cris_get_mode (insn) == 0x0003
&& ((insn) & 0x03E0) >> 5 == 0x0004)
{
val = get_data_from_address (&insn, tmp_pc);
if (push_srp_found)
{
sp += val;
}
else
{
sp_add_later += val;
}
}
else if (cris_get_operand2 (insn) == SP_REGNUM
&& ((insn & 0x0F00) >> 8) == 0x0001
&& (cris_get_signed_offset (insn) < 0))
{
val = -cris_get_signed_offset (insn);
insn_next = read_memory_unsigned_integer (tmp_pc,
sizeof (short));
tmp_pc += sizeof (short);
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)
{
if (push_srp_found)
{
sp += val;
}
else
{
sp_add_later += val;
}
}
}
}
if (push_srp_found)
{
push_srp_found = 0;
pc = read_memory_unsigned_integer (sp, 4);
}
else if (innermost_frame)
{
deprecated_read_register_gen (SRP_REGNUM, (char *) &pc);
}
else
{
return;
}
innermost_frame = 0;
sp += sp_add_later;
sp_add_later = 0;
}
}
extern initialize_file_ftype _initialize_cris_tdep;
void
_initialize_cris_tdep (void)
{
struct cmd_list_element *c;
gdbarch_register (bfd_arch_cris, cris_gdbarch_init, cris_dump_tdep);
c = add_set_cmd ("cris-version", class_support, var_integer,
(char *) &usr_cmd_cris_version,
"Set the current CRIS version.", &setlist);
set_cmd_sfunc (c, cris_version_update);
add_show_from_set (c, &showlist);
c = add_set_enum_cmd ("cris-mode", class_support, cris_mode_enums,
&usr_cmd_cris_mode,
"Set the current CRIS mode.", &setlist);
set_cmd_sfunc (c, cris_mode_update);
add_show_from_set (c, &showlist);
c = add_cmd ("cris-fpless-backtrace", class_support, cris_fpless_backtrace,
"Display call chain using the subroutine return pointer.\n"
"Note that this displays the address after the jump to the "
"subroutine.", &cmdlist);
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);
}
}
static void
cris_version_update (char *ignore_args, int from_tty,
struct cmd_list_element *c)
{
struct gdbarch_info info;
if (cmd_type (c) == set_cmd)
{
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
cris_mode_update (char *ignore_args, int from_tty,
struct cmd_list_element *c)
{
struct gdbarch_info info;
if (cmd_type (c) == set_cmd)
{
usr_cmd_cris_mode_valid = 1;
gdbarch_info_init (&info);
if (!gdbarch_update_p (info))
internal_error (__FILE__, __LINE__, "cris_gdbarch_update: failed to update architecture.");
}
}
static CORE_ADDR
bfd_lookup_symbol (bfd *abfd, const char *symname)
{
unsigned int storage_needed;
asymbol *sym;
asymbol **symbol_table;
unsigned int number_of_symbols;
unsigned int i;
struct cleanup *back_to;
CORE_ADDR symaddr = 0;
storage_needed = bfd_get_symtab_upper_bound (abfd);
if (storage_needed > 0)
{
symbol_table = (asymbol **) xmalloc (storage_needed);
back_to = make_cleanup (free, symbol_table);
number_of_symbols = bfd_canonicalize_symtab (abfd, symbol_table);
for (i = 0; i < number_of_symbols; i++)
{
sym = *symbol_table++;
if (!strcmp (sym->name, symname))
{
symaddr = sym->value + sym->section->vma;
break;
}
}
do_cleanups (back_to);
}
return (symaddr);
}
static struct gdbarch *
cris_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
{
struct gdbarch *gdbarch;
struct gdbarch_tdep *tdep;
int cris_version;
const char *cris_mode;
int register_bytes;
if (usr_cmd_cris_version_valid)
{
cris_version = usr_cmd_cris_version;
}
else
{
cris_version = 10;
}
if (usr_cmd_cris_mode_valid)
{
cris_mode = usr_cmd_cris_mode;
}
else if (cris_version == 10)
{
cris_mode = CRIS_MODE_USER;
}
else
{
cris_mode = CRIS_MODE_SUPERVISOR;
}
usr_cmd_cris_version = cris_version;
usr_cmd_cris_mode = cris_mode;
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 == cris_version)
&& (gdbarch_tdep (arches->gdbarch)->cris_mode == cris_mode))
return arches->gdbarch;
}
tdep = (struct gdbarch_tdep *) xmalloc (sizeof (struct gdbarch_tdep));
gdbarch = gdbarch_alloc (&info, tdep);
tdep->cris_version = cris_version;
tdep->cris_mode = cris_mode;
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_store_return_value (gdbarch, cris_store_return_value);
set_gdbarch_extract_return_value (gdbarch, cris_extract_return_value);
set_gdbarch_deprecated_reg_struct_has_addr (gdbarch,
cris_reg_struct_has_addr);
set_gdbarch_use_struct_convention (gdbarch, always_use_struct_convention);
set_gdbarch_num_regs (gdbarch, 32);
set_gdbarch_sp_regnum (gdbarch, 14);
set_gdbarch_pc_regnum (gdbarch, 15);
set_gdbarch_register_name (gdbarch, cris_register_name);
set_gdbarch_deprecated_register_size (gdbarch, 4);
set_gdbarch_double_bit (gdbarch, 64);
set_gdbarch_long_double_bit (gdbarch, 64);
set_gdbarch_register_bytes_ok (gdbarch, cris_register_bytes_ok);
set_gdbarch_cannot_store_register (gdbarch, cris_cannot_store_register);
set_gdbarch_cannot_fetch_register (gdbarch, cris_cannot_fetch_register);
switch (tdep->cris_version)
{
case 0:
case 1:
case 2:
case 3:
internal_error (__FILE__, __LINE__, "cris_gdbarch_init: unsupported CRIS version");
break;
case 8:
case 9:
register_bytes = (16 * 4) + (2 * 1) + (2 * 2) + (7 * 4);
break;
case 10:
case 11:
register_bytes = (16 * 4) + (2 * 1) + (2 * 2) + (9 * 4);
break;
default:
internal_error (__FILE__, __LINE__, "cris_gdbarch_init: unknown CRIS version");
}
set_gdbarch_deprecated_register_bytes (gdbarch, register_bytes);
set_gdbarch_deprecated_register_byte (gdbarch, cris_register_offset);
set_gdbarch_deprecated_register_raw_size (gdbarch, cris_register_size);
set_gdbarch_deprecated_max_register_raw_size (gdbarch, 32);
set_gdbarch_deprecated_register_virtual_size (gdbarch, cris_register_size);
set_gdbarch_deprecated_max_register_virtual_size (gdbarch, 32);
set_gdbarch_deprecated_register_virtual_type (gdbarch, cris_register_virtual_type);
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_software_single_step (gdbarch, cris_software_single_step);
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);
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;
}