#include "defs.h"
#include "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 "symfile.h"
#include "solib.h"
#include "solib-svr4.h"
enum cris_num_regs
{
NUM_FREGS = 0,
NUM_GENREGS = 16,
NUM_SPECREGS = 16
};
enum cris_regnums
{
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
};
static const char *usr_cmd_cris_abi;
static int usr_cmd_cris_abi_valid = 0;
static const char CRIS_ABI_ORIGINAL[] = "CRIS_ABI_ORIGINAL";
static const char CRIS_ABI_V2[] = "CRIS_ABI_V2";
static const char CRIS_ABI_SYMBOL[] = ".$CRIS_ABI_V2";
static const char *cris_abi_enums[] =
{
CRIS_ABI_ORIGINAL,
CRIS_ABI_V2,
0
};
struct gdbarch_tdep
{
int cris_version;
const char *cris_mode;
const char *cris_abi;
};
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);
}
static const char *
cris_abi (void)
{
return (gdbarch_tdep (current_gdbarch)->cris_abi);
}
static CORE_ADDR struct_return_address;
struct frame_extra_info
{
CORE_ADDR return_pc;
int leaf_function;
};
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_wide_opcode (unsigned short insn)
{
return ((insn & 0x03E0) >> 5);
}
static int
cris_get_short_size (unsigned short insn)
{
return ((insn & 0x0010) >> 4);
}
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_asr_quick_shift_steps (unsigned short insn)
{
return (insn & 0x1F);
}
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 CORE_ADDR cris_skip_prologue_main (CORE_ADDR pc, int frameless_p);
static struct gdbarch *cris_gdbarch_init (struct gdbarch_info,
struct gdbarch_list *);
static int cris_delayed_get_disassembler (bfd_vma, disassemble_info *);
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 void cris_abi_update (char *ignore_args, int from_tty,
struct cmd_list_element *c);
static CORE_ADDR bfd_lookup_symbol (bfd *, const char *);
CORE_ADDR
cris_examine (CORE_ADDR ip, CORE_ADDR limit, struct frame_info *fi,
int frameless_p)
{
unsigned short insn;
unsigned short insn_next;
int regno;
int have_fp;
int val;
int regsave;
short source_register;
fi->extra_info->leaf_function = 1;
have_fp = 0;
val = 0;
regsave = -1;
if (fi->saved_regs)
{
for (regno = 0; regno < NUM_REGS; regno++)
fi->saved_regs[regno] = 0;
}
do
{
insn = read_memory_unsigned_integer (ip, sizeof (short));
ip += sizeof (short);
if (insn == 0xE1FC)
{
insn_next = read_memory_unsigned_integer (ip, sizeof (short));
ip += sizeof (short);
regno = cris_get_operand2 (insn_next);
if (insn_next == 0xBE7E)
{
if (frameless_p)
{
return ip;
}
fi->extra_info->leaf_function = 0;
}
else if (regno == FP_REGNUM)
{
have_fp = 1;
}
}
else if (insn == 0x866E)
{
if (frameless_p)
{
return ip;
}
continue;
}
else if (cris_get_operand2 (insn) == SP_REGNUM
&& cris_get_mode (insn) == 0x0000
&& cris_get_opcode (insn) == 0x000A)
{
val = 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)
{
if (frameless_p)
{
return ip;
}
regsave = cris_get_operand2 (insn);
}
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 (ip, sizeof (short));
ip += 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 (frameless_p)
{
return ip;
}
regsave = cris_get_operand2 (insn_next);
}
else
{
ip -= 2 * sizeof (short);
break;
}
}
else if (cris_get_mode (insn) == 0x0001
&& cris_get_opcode (insn) == 0x0009
&& cris_get_size (insn) == 0x0002)
{
if (frameless_p)
{
return ip;
}
source_register = cris_get_operand1 (insn);
if (source_register < ARG1_REGNUM || source_register > ARG4_REGNUM)
{
ip -= sizeof (short);
break;
}
}
else if (cris_get_operand2 (insn) == FP_REGNUM
&& ((insn & 0x0F00) >> 8) == 0x0001
&& (cris_get_signed_offset (insn) < 0))
{
insn_next = read_memory_unsigned_integer (ip, sizeof (short));
ip += sizeof (short);
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
{
ip -= 2 * sizeof (short);
break;
}
}
else if (cris_get_operand2 (insn) == FP_REGNUM
&& ((insn & 0x0F00) >> 8) == 0x0001
&& (cris_get_signed_offset (insn) > 0))
{
insn_next = read_memory_unsigned_integer (ip, sizeof (short));
ip += sizeof (short);
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
{
ip -= 2 * sizeof (short);
break;
}
}
else
{
ip -= sizeof (short);
break;
}
}
while (ip < limit);
if (!fi->saved_regs)
return ip;
if (have_fp)
{
fi->saved_regs[FP_REGNUM] = FRAME_FP (fi);
for (regno = regsave; regno >= 0; regno--)
{
fi->saved_regs[regno] = FRAME_FP (fi) - val;
val -= 4;
}
if (fi->extra_info->leaf_function)
{
fi->saved_regs[SP_REGNUM] = FRAME_FP (fi) + 4;
}
else
{
fi->saved_regs[SP_REGNUM] = FRAME_FP (fi) + 8;
fi->saved_regs[SRP_REGNUM] = FRAME_FP (fi) + 4;
}
}
return ip;
}
CORE_ADDR
cris_skip_prologue (CORE_ADDR pc)
{
return cris_skip_prologue_main (pc, 0);
}
CORE_ADDR
cris_skip_prologue_frameless_p (CORE_ADDR pc)
{
return cris_skip_prologue_main (pc, 1);
}
CORE_ADDR
cris_skip_prologue_main (CORE_ADDR pc, int frameless_p)
{
struct frame_info fi;
static struct frame_extra_info fei;
struct symtab_and_line sal = find_pc_line (pc, 0);
int best_limit;
CORE_ADDR pc_after_prologue;
fi.saved_regs = 0;
fi.extra_info = &fei;
if (sal.end > 0)
best_limit = sal.end;
else
best_limit = pc + 100;
pc_after_prologue = cris_examine (pc, best_limit, &fi, frameless_p);
return pc_after_prologue;
}
unsigned char *
cris_breakpoint_from_pc (CORE_ADDR *pcptr, int *lenptr)
{
static unsigned char break_insn[] = {0x38, 0xe9};
*lenptr = 2;
return break_insn;
}
CORE_ADDR
cris_saved_pc_after_call ()
{
return read_register (SRP_REGNUM);
}
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;
}
}
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;
}
}
int
cris_cannot_fetch_register (int regno)
{
return ((regno < 0 || regno >= NUM_REGS)
|| (cris_register_size (regno) == 0));
}
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;
}
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;
}
}
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;
}
}
void
cris_abi_original_store_return_value (struct type *type, char *valbuf)
{
int len = TYPE_LENGTH (type);
if (len <= REGISTER_SIZE)
write_register_bytes (REGISTER_BYTE (RET_REGNUM), valbuf, len);
else
internal_error (__FILE__, __LINE__, "cris_abi_original_store_return_value: type length too large.");
}
void
cris_abi_v2_store_return_value (struct type *type, char *valbuf)
{
int len = TYPE_LENGTH (type);
if (len <= 2 * REGISTER_SIZE)
{
write_register_bytes (REGISTER_BYTE (RET_REGNUM), valbuf, len);
}
else
internal_error (__FILE__, __LINE__, "cris_abi_v2_store_return_value: type length too large.");
}
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;
}
}
int
cris_register_bytes_ok (long bytes)
{
return (bytes == REGISTER_BYTES);
}
void
cris_abi_original_extract_return_value (struct type *type, char *regbuf,
char *valbuf)
{
int len = TYPE_LENGTH (type);
if (len <= REGISTER_SIZE)
memcpy (valbuf, regbuf + REGISTER_BYTE (RET_REGNUM), len);
else
internal_error (__FILE__, __LINE__, "cris_abi_original_extract_return_value: type length too large");
}
void
cris_abi_v2_extract_return_value (struct type *type, char *regbuf,
char *valbuf)
{
int len = TYPE_LENGTH (type);
if (len <= 2 * REGISTER_SIZE)
memcpy (valbuf, regbuf + REGISTER_BYTE (RET_REGNUM), len);
else
internal_error (__FILE__, __LINE__, "cris_abi_v2_extract_return_value: type length too large");
}
void
cris_store_struct_return (CORE_ADDR addr, CORE_ADDR sp)
{
write_register (STR_REGNUM, addr);
struct_return_address = addr;
}
CORE_ADDR
cris_extract_struct_value_address (char *regbuf)
{
return struct_return_address;
}
int
cris_use_struct_convention (int gcc_p, struct type *type)
{
return 1;
}
int
cris_abi_original_reg_struct_has_addr (int gcc_p, struct type *type)
{
return (TYPE_LENGTH (type) > 4);
}
int
cris_abi_v2_reg_struct_has_addr (int gcc_p, struct type *type)
{
return (TYPE_LENGTH (type) > 8);
}
int
cris_frameless_function_invocation (struct frame_info *fi)
{
if (fi->signal_handler_caller)
return 0;
else
return frameless_look_for_prologue (fi);
}
void
cris_frame_init_saved_regs (struct frame_info *fi)
{
CORE_ADDR ip;
struct symtab_and_line sal;
int best_limit;
char *dummy_regs = generic_find_dummy_frame (fi->pc, fi->frame);
register int frameless_p = 0;
if (fi->saved_regs)
return;
frame_saved_regs_zalloc (fi);
if (dummy_regs)
{
memcpy (&fi->saved_regs, dummy_regs, sizeof (fi->saved_regs));
}
else
{
ip = get_pc_function_start (fi->pc);
sal = find_pc_line (ip, 0);
if (sal.end > 0)
best_limit = sal.end;
else
best_limit = ip + 100;
cris_examine (ip, best_limit, fi, frameless_p);
}
}
void
cris_init_extra_frame_info (int fromleaf, struct frame_info *fi)
{
if (fi->next)
{
fi->pc = FRAME_SAVED_PC (fi->next);
}
fi->extra_info = (struct frame_extra_info *)
frame_obstack_alloc (sizeof (struct frame_extra_info));
fi->extra_info->return_pc = 0;
fi->extra_info->leaf_function = 0;
if (PC_IN_CALL_DUMMY (fi->pc, fi->frame, fi->frame))
{
fi->frame = generic_read_register_dummy (fi->pc, fi->frame, SP_REGNUM);
fi->extra_info->return_pc =
generic_read_register_dummy (fi->pc, fi->frame, PC_REGNUM);
fi->extra_info->leaf_function = 0;
}
else
{
cris_frame_init_saved_regs (fi);
if (fi->saved_regs[SRP_REGNUM] != 0)
{
fi->extra_info->return_pc =
read_memory_integer (fi->saved_regs[SRP_REGNUM],
REGISTER_RAW_SIZE (SRP_REGNUM));
}
else
{
fi->extra_info->return_pc = read_register (SRP_REGNUM);
fi->extra_info->leaf_function = 1;
}
}
}
CORE_ADDR
cris_frame_chain (struct frame_info *fi)
{
if (PC_IN_CALL_DUMMY (fi->pc, fi->frame, fi->frame))
{
return fi->frame;
}
else if (!inside_entry_file (fi->pc))
{
return read_memory_unsigned_integer (FRAME_FP (fi), 4);
}
else
{
return 0;
}
}
CORE_ADDR
cris_frame_saved_pc (struct frame_info *fi)
{
return fi->extra_info->return_pc;
}
CORE_ADDR
cris_frame_args_address (struct frame_info *fi)
{
return FRAME_FP (fi);
}
CORE_ADDR
cris_frame_locals_address (struct frame_info *fi)
{
return FRAME_FP (fi);
}
CORE_ADDR
cris_abi_original_push_arguments (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;
struct type *type;
int len;
CORE_ADDR regval;
char *val;
CORE_ADDR fp_params;
CORE_ADDR fp_data;
if (struct_return)
{
write_register (STR_REGNUM, struct_addr);
}
for (argnum = 0, stack_alloc = 0; argnum < nargs; argnum++)
stack_alloc += (TYPE_LENGTH (VALUE_TYPE (args[argnum])) + REGISTER_SIZE);
sp -= stack_alloc;
fp_params = sp;
fp_data = sp + (nargs * REGISTER_SIZE);
argreg = ARG1_REGNUM;
stack_offset = 0;
for (argnum = 0; argnum < nargs; argnum++)
{
type = VALUE_TYPE (args[argnum]);
len = TYPE_LENGTH (type);
val = (char *) VALUE_CONTENTS (args[argnum]);
if (len <= REGISTER_SIZE && argreg <= ARG4_REGNUM)
{
write_register (argreg, *(unsigned long *) val);
argreg++;
}
else if (len > REGISTER_SIZE && argreg <= ARG4_REGNUM)
{
write_memory (fp_data, val, len);
write_register (argreg, fp_data);
fp_data += len;
argreg++;
}
else if (len > REGISTER_SIZE)
{
write_memory (fp_data, val, len);
write_memory (fp_params, (char *) (&fp_data), REGISTER_SIZE);
fp_data += len;
fp_params += REGISTER_SIZE;
}
else
{
write_memory (fp_params, val, REGISTER_SIZE);
fp_params += REGISTER_SIZE;
}
}
return sp;
}
CORE_ADDR
cris_abi_v2_push_arguments (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;
if (struct_return)
{
write_register (STR_REGNUM, struct_addr);
}
stack_alloc = 0;
for (argnum = 0; argnum < nargs; argnum++)
{
int len;
int reg_demand;
len = TYPE_LENGTH (VALUE_TYPE (args[argnum]));
reg_demand = (len / REGISTER_SIZE) + (len % REGISTER_SIZE != 0 ? 1 : 0);
stack_alloc += (reg_demand * REGISTER_SIZE + 2 * REGISTER_SIZE);
}
sp -= stack_alloc;
fp_arg = sp;
fp_mem = sp + (nargs * (2 * REGISTER_SIZE));
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 / REGISTER_SIZE) + (len % REGISTER_SIZE != 0 ? 1 : 0);
if (len <= (2 * REGISTER_SIZE)
&& (argreg + reg_demand - 1 <= ARG4_REGNUM))
{
for (i = 0; i < reg_demand; i++)
{
write_register (argreg, *(unsigned long *) val);
argreg++;
val += REGISTER_SIZE;
}
}
else if (len <= (2 * REGISTER_SIZE) && argreg <= ARG4_REGNUM)
{
for (i = 0; i < reg_demand; i++)
{
if (argreg <= ARG4_REGNUM)
{
write_register (argreg, *(unsigned long *) val);
argreg++;
val += REGISTER_SIZE;
}
else
{
write_memory (fp_arg, val, REGISTER_SIZE);
fp_arg += REGISTER_SIZE;
val += REGISTER_SIZE;
}
}
}
else if (len > (2 * REGISTER_SIZE))
{
write_memory (fp_mem, val, len);
write_memory (fp_arg, (char *) (&fp_mem), REGISTER_SIZE);
fp_mem += reg_demand * REGISTER_SIZE;
fp_arg += REGISTER_SIZE;
}
else
{
write_memory (fp_arg, val, len);
fp_arg += reg_demand * REGISTER_SIZE;
}
}
return sp;
}
CORE_ADDR
cris_push_return_address (CORE_ADDR pc, CORE_ADDR sp)
{
write_register (SRP_REGNUM, CALL_DUMMY_ADDRESS ());
return sp;
}
void
cris_pop_frame ()
{
register struct frame_info *fi = get_current_frame ();
register int regno;
register int stack_offset = 0;
if (PC_IN_CALL_DUMMY (fi->pc, fi->frame, fi->frame))
{
generic_pop_dummy_frame ();
}
else
{
cris_frame_init_saved_regs (fi);
for (regno = 0; regno < FP_REGNUM; regno++)
{
if (fi->saved_regs[regno])
{
write_register (regno,
read_memory_integer (fi->saved_regs[regno], 4));
}
}
if (fi->saved_regs[FP_REGNUM])
{
write_register (FP_REGNUM,
read_memory_integer (fi->saved_regs[FP_REGNUM], 4));
stack_offset += 4;
if (fi->saved_regs[SRP_REGNUM])
{
stack_offset += 4;
}
write_register (SP_REGNUM, fi->saved_regs[FP_REGNUM] + stack_offset);
}
else
{
}
write_register (PC_REGNUM, fi->extra_info->return_pc);
}
flush_cached_frames ();
}
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;
}
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;
}
}
}
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;
}
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;
}
}
unsigned long
get_data_from_address (unsigned short *inst, CORE_ADDR address);
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;
}
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;
}
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;
}
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;
}
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;
}
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;
}
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;
}
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;
}
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;
}
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;
}
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;
}
}
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;
}
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;
}
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;
}
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;
}
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;
}
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;
}
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;
}
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;
}
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;
}
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;
}
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;
}
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;
}
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;
}
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;
}
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;
}
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;
}
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;
}
void
reg_pop_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] =
read_memory_unsigned_integer (inst_env->reg[REG_SP], 4);
}
inst_env->slot_needed = 0;
inst_env->prefix_found = 0;
inst_env->xflag_found = 0;
inst_env->disable_interrupt = 0;
}
void
move_reg_to_mem_index_inc_op (unsigned short inst, inst_env_type *inst_env)
{
if (inst_env->prefix_found)
{
check_assign (inst, inst_env);
}
else if ((cris_get_operand1 (inst) == REG_PC)
&& (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;
}
void
not_implemented_op (unsigned short inst, inst_env_type *inst_env)
{
inst_env->invalid = 1;
}
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;
}
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;
}
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;
}
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;
}
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;
}
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;
}
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;
}
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;
}
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;
}
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;
}
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;
}
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);
}
}
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;
}
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, disassemble_info *info)
{
tm_print_insn = cris_get_disassembler (exec_bfd);
return TARGET_PRINT_INSN (addr, info);
}
typedef unsigned long elf_greg_t;
typedef elf_greg_t elf_gregset_t[35];
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
};
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;
read_register_gen (PC_REGNUM, (char *) &pc);
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)
{
read_register_gen (SRP_REGNUM, (char *) &pc);
}
else
{
return;
}
innermost_frame = 0;
sp += sp_add_later;
sp_add_later = 0;
}
}
void
_initialize_cris_tdep (void)
{
struct cmd_list_element *c;
gdbarch_register (bfd_arch_cris, cris_gdbarch_init, cris_dump_tdep);
tm_print_insn = cris_delayed_get_disassembler;
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_set_enum_cmd ("cris-abi", class_support, cris_abi_enums,
&usr_cmd_cris_abi,
"Set the current CRIS ABI version.", &setlist);
set_cmd_sfunc (c, cris_abi_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);
fprintf_unfiltered (file, "cris_dump_tdep: tdep->cris_abi = %s\n",
tdep->cris_abi);
}
}
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 void
cris_abi_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_abi_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, (PTR) 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;
const char *cris_abi;
CORE_ADDR cris_abi_sym = 0;
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;
}
if (usr_cmd_cris_abi_valid)
{
cris_abi = usr_cmd_cris_abi;
}
else if (info.abfd)
{
if (bfd_get_flavour (info.abfd) == bfd_target_elf_flavour)
{
cris_abi = CRIS_ABI_V2;
}
else if (bfd_get_flavour (info.abfd) == bfd_target_aout_flavour)
{
cris_abi_sym = bfd_lookup_symbol (info.abfd, CRIS_ABI_SYMBOL);
cris_abi = cris_abi_sym ? CRIS_ABI_V2 : CRIS_ABI_ORIGINAL;
}
else
{
cris_abi = CRIS_ABI_V2;
}
}
else if (gdbarch_tdep (current_gdbarch))
{
cris_abi = gdbarch_tdep (current_gdbarch)->cris_abi;
}
else
{
cris_abi = CRIS_ABI_V2;
}
usr_cmd_cris_version = cris_version;
usr_cmd_cris_mode = cris_mode;
usr_cmd_cris_abi = cris_abi;
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)
&& (gdbarch_tdep (arches->gdbarch)->cris_abi == cris_abi))
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;
tdep->cris_abi = cris_abi;
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");
}
if (tdep->cris_abi == CRIS_ABI_ORIGINAL)
{
set_gdbarch_double_bit (gdbarch, 32);
set_gdbarch_push_arguments (gdbarch, cris_abi_original_push_arguments);
set_gdbarch_store_return_value (gdbarch,
cris_abi_original_store_return_value);
set_gdbarch_extract_return_value
(gdbarch, cris_abi_original_extract_return_value);
set_gdbarch_reg_struct_has_addr
(gdbarch, cris_abi_original_reg_struct_has_addr);
}
else if (tdep->cris_abi == CRIS_ABI_V2)
{
set_gdbarch_double_bit (gdbarch, 64);
set_gdbarch_push_arguments (gdbarch, cris_abi_v2_push_arguments);
set_gdbarch_store_return_value (gdbarch, cris_abi_v2_store_return_value);
set_gdbarch_extract_return_value (gdbarch,
cris_abi_v2_extract_return_value);
set_gdbarch_reg_struct_has_addr (gdbarch,
cris_abi_v2_reg_struct_has_addr);
}
else
internal_error (__FILE__, __LINE__, "cris_gdbarch_init: unknown CRIS ABI");
set_gdbarch_long_double_bit (gdbarch, 64);
set_gdbarch_num_regs (gdbarch, 32);
set_gdbarch_sp_regnum (gdbarch, 14);
set_gdbarch_fp_regnum (gdbarch, 8);
set_gdbarch_pc_regnum (gdbarch, 15);
set_gdbarch_register_name (gdbarch, cris_register_name);
set_gdbarch_register_size (gdbarch, 4);
set_gdbarch_register_bytes_ok (gdbarch, cris_register_bytes_ok);
set_gdbarch_software_single_step (gdbarch, cris_software_single_step);
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_register_bytes (gdbarch, register_bytes);
set_gdbarch_register_byte (gdbarch, cris_register_offset);
set_gdbarch_register_raw_size (gdbarch, cris_register_size);
set_gdbarch_max_register_raw_size (gdbarch, 32);
set_gdbarch_register_virtual_size (gdbarch, cris_register_size);
set_gdbarch_max_register_virtual_size (gdbarch, 32);
set_gdbarch_register_virtual_type (gdbarch, cris_register_virtual_type);
set_gdbarch_use_generic_dummy_frames (gdbarch, 1);
set_gdbarch_call_dummy_location (gdbarch, AT_ENTRY_POINT);
set_gdbarch_call_dummy_address (gdbarch, entry_point_address);
set_gdbarch_call_dummy_start_offset (gdbarch, 0);
set_gdbarch_call_dummy_breakpoint_offset (gdbarch, 0);
set_gdbarch_call_dummy_breakpoint_offset_p (gdbarch, 1);
set_gdbarch_call_dummy_length (gdbarch, 0);
set_gdbarch_pc_in_call_dummy (gdbarch, pc_in_call_dummy_at_entry_point);
set_gdbarch_call_dummy_p (gdbarch, 1);
set_gdbarch_call_dummy_words (gdbarch, 0);
set_gdbarch_sizeof_call_dummy_words (gdbarch, 0);
set_gdbarch_call_dummy_stack_adjust_p (gdbarch, 0);
set_gdbarch_fix_call_dummy (gdbarch, generic_fix_call_dummy);
set_gdbarch_get_saved_register (gdbarch, generic_get_saved_register);
set_gdbarch_register_convertible (gdbarch, generic_register_convertible_not);
set_gdbarch_push_dummy_frame (gdbarch, generic_push_dummy_frame);
set_gdbarch_push_return_address (gdbarch, cris_push_return_address);
set_gdbarch_pop_frame (gdbarch, cris_pop_frame);
set_gdbarch_store_struct_return (gdbarch, cris_store_struct_return);
set_gdbarch_extract_struct_value_address (gdbarch,
cris_extract_struct_value_address);
set_gdbarch_use_struct_convention (gdbarch, cris_use_struct_convention);
set_gdbarch_frame_init_saved_regs (gdbarch, cris_frame_init_saved_regs);
set_gdbarch_init_extra_frame_info (gdbarch, cris_init_extra_frame_info);
set_gdbarch_skip_prologue (gdbarch, cris_skip_prologue);
set_gdbarch_prologue_frameless_p (gdbarch, generic_prologue_frameless_p);
set_gdbarch_inner_than (gdbarch, core_addr_lessthan);
set_gdbarch_breakpoint_from_pc (gdbarch, cris_breakpoint_from_pc);
set_gdbarch_decr_pc_after_break (gdbarch, 0);
set_gdbarch_function_start_offset (gdbarch, 0);
set_gdbarch_frame_args_skip (gdbarch, 0);
set_gdbarch_frameless_function_invocation
(gdbarch, cris_frameless_function_invocation);
set_gdbarch_frame_chain (gdbarch, cris_frame_chain);
set_gdbarch_frame_chain_valid (gdbarch, generic_file_frame_chain_valid);
set_gdbarch_frame_saved_pc (gdbarch, cris_frame_saved_pc);
set_gdbarch_frame_args_address (gdbarch, cris_frame_args_address);
set_gdbarch_frame_locals_address (gdbarch, cris_frame_locals_address);
set_gdbarch_saved_pc_after_call (gdbarch, cris_saved_pc_after_call);
set_gdbarch_frame_num_args (gdbarch, frame_num_args_unknown);
set_gdbarch_extra_stack_alignment_needed (gdbarch, 0);
set_gdbarch_save_dummy_frame_tos (gdbarch, generic_save_dummy_frame_tos);
set_solib_svr4_fetch_link_map_offsets
(gdbarch, cris_linux_svr4_fetch_link_map_offsets);
return gdbarch;
}