| /* Target dependent code for CRIS, for GDB, the GNU debugger. |
| |
| Copyright (C) 2001-2024 Free Software Foundation, Inc. |
| |
| Contributed by Axis Communications AB. |
| Written by Hendrik Ruijter, Stefan Andersson, and Orjan Friberg. |
| |
| This file is part of GDB. |
| |
| This program is free software; you can redistribute it and/or modify |
| it under the terms of the GNU General Public License as published by |
| the Free Software Foundation; either version 3 of the License, or |
| (at your option) any later version. |
| |
| This program is distributed in the hope that it will be useful, |
| but WITHOUT ANY WARRANTY; without even the implied warranty of |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| GNU General Public License for more details. |
| |
| You should have received a copy of the GNU General Public License |
| along with this program. If not, see <http://www.gnu.org/licenses/>. */ |
| |
| #include "extract-store-integer.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 "cli/cli-cmds.h" |
| #include "target.h" |
| #include "value.h" |
| #include "opcode/cris.h" |
| #include "osabi.h" |
| #include "arch-utils.h" |
| #include "regcache.h" |
| #include "regset.h" |
| |
| #include "objfiles.h" |
| |
| #include "solib.h" |
| #include "solib-svr4.h" |
| #include "dis-asm.h" |
| |
| #include "cris-tdep.h" |
| |
| enum cris_num_regs |
| { |
| /* There are no floating point registers. Used in gdbserver low-linux.c. */ |
| NUM_FREGS = 0, |
| |
| /* There are 16 general registers. */ |
| NUM_GENREGS = 16, |
| |
| /* There are 16 special registers. */ |
| NUM_SPECREGS = 16, |
| |
| /* CRISv32 has a pseudo PC register, not noted here. */ |
| |
| /* CRISv32 has 16 support registers. */ |
| NUM_SUPPREGS = 16 |
| }; |
| |
| /* Register numbers of various important registers. |
| CRIS_FP_REGNUM Contains address of executing stack frame. |
| STR_REGNUM Contains the address of structure return values. |
| RET_REGNUM Contains the return value when shorter than or equal to 32 bits |
| ARG1_REGNUM Contains the first parameter to a function. |
| ARG2_REGNUM Contains the second parameter to a function. |
| ARG3_REGNUM Contains the third parameter to a function. |
| ARG4_REGNUM Contains the fourth parameter to a function. Rest on stack. |
| gdbarch_sp_regnum Contains address of top of stack. |
| gdbarch_pc_regnum Contains address of next instruction. |
| SRP_REGNUM Subroutine return pointer register. |
| BRP_REGNUM Breakpoint return pointer register. */ |
| |
| enum cris_regnums |
| { |
| /* Enums with respect to the general registers, valid for all |
| CRIS versions. The frame pointer is always in R8. */ |
| CRIS_FP_REGNUM = 8, |
| /* ABI related registers. */ |
| STR_REGNUM = 9, |
| RET_REGNUM = 10, |
| ARG1_REGNUM = 10, |
| ARG2_REGNUM = 11, |
| ARG3_REGNUM = 12, |
| ARG4_REGNUM = 13, |
| |
| /* Registers which happen to be common. */ |
| VR_REGNUM = 17, |
| MOF_REGNUM = 23, |
| SRP_REGNUM = 27, |
| |
| /* CRISv10 et al. specific registers. */ |
| P0_REGNUM = 16, |
| P4_REGNUM = 20, |
| CCR_REGNUM = 21, |
| P8_REGNUM = 24, |
| IBR_REGNUM = 25, |
| IRP_REGNUM = 26, |
| BAR_REGNUM = 28, |
| DCCR_REGNUM = 29, |
| BRP_REGNUM = 30, |
| USP_REGNUM = 31, |
| |
| /* CRISv32 specific registers. */ |
| ACR_REGNUM = 15, |
| BZ_REGNUM = 16, |
| PID_REGNUM = 18, |
| SRS_REGNUM = 19, |
| WZ_REGNUM = 20, |
| EXS_REGNUM = 21, |
| EDA_REGNUM = 22, |
| DZ_REGNUM = 24, |
| EBP_REGNUM = 25, |
| ERP_REGNUM = 26, |
| NRP_REGNUM = 28, |
| CCS_REGNUM = 29, |
| CRISV32USP_REGNUM = 30, /* Shares name but not number with CRISv10. */ |
| SPC_REGNUM = 31, |
| CRISV32PC_REGNUM = 32, /* Shares name but not number with CRISv10. */ |
| |
| S0_REGNUM = 33, |
| S1_REGNUM = 34, |
| S2_REGNUM = 35, |
| S3_REGNUM = 36, |
| S4_REGNUM = 37, |
| S5_REGNUM = 38, |
| S6_REGNUM = 39, |
| S7_REGNUM = 40, |
| S8_REGNUM = 41, |
| S9_REGNUM = 42, |
| S10_REGNUM = 43, |
| S11_REGNUM = 44, |
| S12_REGNUM = 45, |
| S13_REGNUM = 46, |
| S14_REGNUM = 47, |
| S15_REGNUM = 48, |
| }; |
| |
| extern const struct cris_spec_reg cris_spec_regs[]; |
| |
| /* CRIS version, set via the user command 'set cris-version'. Affects |
| register names and sizes. */ |
| static unsigned int usr_cmd_cris_version; |
| |
| /* Indicates whether to trust the above variable. */ |
| static bool usr_cmd_cris_version_valid = false; |
| |
| static const char cris_mode_normal[] = "normal"; |
| static const char cris_mode_guru[] = "guru"; |
| static const char *const cris_modes[] = { |
| cris_mode_normal, |
| cris_mode_guru, |
| 0 |
| }; |
| |
| /* CRIS mode, set via the user command 'set cris-mode'. Affects |
| type of break instruction among other things. */ |
| static const char *usr_cmd_cris_mode = cris_mode_normal; |
| |
| /* Whether to make use of Dwarf-2 CFI (default on). */ |
| static bool usr_cmd_cris_dwarf2_cfi = true; |
| |
| /* Sigtramp identification code copied from i386-linux-tdep.c. */ |
| |
| #define SIGTRAMP_INSN0 0x9c5f /* movu.w 0xXX, $r9 */ |
| #define SIGTRAMP_OFFSET0 0 |
| #define SIGTRAMP_INSN1 0xe93d /* break 13 */ |
| #define SIGTRAMP_OFFSET1 4 |
| |
| static const unsigned short sigtramp_code[] = |
| { |
| SIGTRAMP_INSN0, 0x0077, /* movu.w $0x77, $r9 */ |
| SIGTRAMP_INSN1 /* break 13 */ |
| }; |
| |
| #define SIGTRAMP_LEN (sizeof sigtramp_code) |
| |
| /* Note: same length as normal sigtramp code. */ |
| |
| static const unsigned short rt_sigtramp_code[] = |
| { |
| SIGTRAMP_INSN0, 0x00ad, /* movu.w $0xad, $r9 */ |
| SIGTRAMP_INSN1 /* break 13 */ |
| }; |
| |
| /* If PC is in a sigtramp routine, return the address of the start of |
| the routine. Otherwise, return 0. */ |
| |
| static CORE_ADDR |
| cris_sigtramp_start (const frame_info_ptr &this_frame) |
| { |
| CORE_ADDR pc = get_frame_pc (this_frame); |
| gdb_byte buf[SIGTRAMP_LEN]; |
| |
| if (!safe_frame_unwind_memory (this_frame, pc, buf)) |
| return 0; |
| |
| if (((buf[1] << 8) + buf[0]) != SIGTRAMP_INSN0) |
| { |
| if (((buf[1] << 8) + buf[0]) != SIGTRAMP_INSN1) |
| return 0; |
| |
| pc -= SIGTRAMP_OFFSET1; |
| if (!safe_frame_unwind_memory (this_frame, pc, buf)) |
| return 0; |
| } |
| |
| if (memcmp (buf, sigtramp_code, SIGTRAMP_LEN) != 0) |
| return 0; |
| |
| return pc; |
| } |
| |
| /* If PC is in a RT sigtramp routine, return the address of the start of |
| the routine. Otherwise, return 0. */ |
| |
| static CORE_ADDR |
| cris_rt_sigtramp_start (const frame_info_ptr &this_frame) |
| { |
| CORE_ADDR pc = get_frame_pc (this_frame); |
| gdb_byte buf[SIGTRAMP_LEN]; |
| |
| if (!safe_frame_unwind_memory (this_frame, pc, buf)) |
| return 0; |
| |
| if (((buf[1] << 8) + buf[0]) != SIGTRAMP_INSN0) |
| { |
| if (((buf[1] << 8) + buf[0]) != SIGTRAMP_INSN1) |
| return 0; |
| |
| pc -= SIGTRAMP_OFFSET1; |
| if (!safe_frame_unwind_memory (this_frame, pc, buf)) |
| return 0; |
| } |
| |
| if (memcmp (buf, rt_sigtramp_code, SIGTRAMP_LEN) != 0) |
| return 0; |
| |
| return pc; |
| } |
| |
| /* Assuming THIS_FRAME is a frame for a GNU/Linux sigtramp routine, |
| return the address of the associated sigcontext structure. */ |
| |
| static CORE_ADDR |
| cris_sigcontext_addr (const frame_info_ptr &this_frame) |
| { |
| struct gdbarch *gdbarch = get_frame_arch (this_frame); |
| enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); |
| CORE_ADDR pc; |
| CORE_ADDR sp; |
| gdb_byte buf[4]; |
| |
| get_frame_register (this_frame, gdbarch_sp_regnum (gdbarch), buf); |
| sp = extract_unsigned_integer (buf, 4, byte_order); |
| |
| /* Look for normal sigtramp frame first. */ |
| pc = cris_sigtramp_start (this_frame); |
| if (pc) |
| { |
| /* struct signal_frame (arch/cris/kernel/signal.c) contains |
| struct sigcontext as its first member, meaning the SP points to |
| it already. */ |
| return sp; |
| } |
| |
| pc = cris_rt_sigtramp_start (this_frame); |
| if (pc) |
| { |
| /* struct rt_signal_frame (arch/cris/kernel/signal.c) contains |
| a struct ucontext, which in turn contains a struct sigcontext. |
| Magic digging: |
| 4 + 4 + 128 to struct ucontext, then |
| 4 + 4 + 12 to struct sigcontext. */ |
| return (sp + 156); |
| } |
| |
| error (_("Couldn't recognize signal trampoline.")); |
| return 0; |
| } |
| |
| struct cris_unwind_cache |
| { |
| /* The previous frame's inner most stack address. Used as this |
| frame ID's stack_addr. */ |
| CORE_ADDR prev_sp; |
| /* The frame's base, optionally used by the high-level debug info. */ |
| CORE_ADDR base; |
| int size; |
| /* How far the SP and r8 (FP) have been offset from the start of |
| the stack frame (as defined by the previous frame's stack |
| pointer). */ |
| LONGEST sp_offset; |
| LONGEST r8_offset; |
| int uses_frame; |
| |
| /* From old frame_extra_info struct. */ |
| CORE_ADDR return_pc; |
| int leaf_function; |
| |
| /* Table indicating the location of each and every register. */ |
| trad_frame_saved_reg *saved_regs; |
| }; |
| |
| static struct cris_unwind_cache * |
| cris_sigtramp_frame_unwind_cache (const frame_info_ptr &this_frame, |
| void **this_cache) |
| { |
| struct gdbarch *gdbarch = get_frame_arch (this_frame); |
| cris_gdbarch_tdep *tdep = gdbarch_tdep<cris_gdbarch_tdep> (gdbarch); |
| enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); |
| struct cris_unwind_cache *info; |
| CORE_ADDR addr; |
| gdb_byte buf[4]; |
| int i; |
| |
| if ((*this_cache)) |
| return (struct cris_unwind_cache *) (*this_cache); |
| |
| info = FRAME_OBSTACK_ZALLOC (struct cris_unwind_cache); |
| (*this_cache) = info; |
| info->saved_regs = trad_frame_alloc_saved_regs (this_frame); |
| |
| /* Zero all fields. */ |
| 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; |
| |
| get_frame_register (this_frame, gdbarch_sp_regnum (gdbarch), buf); |
| info->base = extract_unsigned_integer (buf, 4, byte_order); |
| |
| addr = cris_sigcontext_addr (this_frame); |
| |
| /* Layout of the sigcontext struct: |
| struct sigcontext { |
| struct pt_regs regs; |
| unsigned long oldmask; |
| unsigned long usp; |
| }; */ |
| |
| if (tdep->cris_version == 10) |
| { |
| /* R0 to R13 are stored in reverse order at offset (2 * 4) in |
| struct pt_regs. */ |
| for (i = 0; i <= 13; i++) |
| info->saved_regs[i].set_addr (addr + ((15 - i) * 4)); |
| |
| info->saved_regs[MOF_REGNUM].set_addr (addr + (16 * 4)); |
| info->saved_regs[DCCR_REGNUM].set_addr (addr + (17 * 4)); |
| info->saved_regs[SRP_REGNUM].set_addr (addr + (18 * 4)); |
| /* Note: IRP is off by 2 at this point. There's no point in correcting |
| it though since that will mean that the backtrace will show a PC |
| different from what is shown when stopped. */ |
| info->saved_regs[IRP_REGNUM].set_addr (addr + (19 * 4)); |
| info->saved_regs[gdbarch_pc_regnum (gdbarch)] |
| = info->saved_regs[IRP_REGNUM]; |
| info->saved_regs[gdbarch_sp_regnum (gdbarch)].set_addr (addr + (24 * 4)); |
| } |
| else |
| { |
| /* CRISv32. */ |
| /* R0 to R13 are stored in order at offset (1 * 4) in |
| struct pt_regs. */ |
| for (i = 0; i <= 13; i++) |
| info->saved_regs[i].set_addr (addr + ((i + 1) * 4)); |
| |
| info->saved_regs[ACR_REGNUM].set_addr (addr + (15 * 4)); |
| info->saved_regs[SRS_REGNUM].set_addr (addr + (16 * 4)); |
| info->saved_regs[MOF_REGNUM].set_addr (addr + (17 * 4)); |
| info->saved_regs[SPC_REGNUM].set_addr (addr + (18 * 4)); |
| info->saved_regs[CCS_REGNUM].set_addr (addr + (19 * 4)); |
| info->saved_regs[SRP_REGNUM].set_addr (addr + (20 * 4)); |
| info->saved_regs[ERP_REGNUM].set_addr (addr + (21 * 4)); |
| info->saved_regs[EXS_REGNUM].set_addr (addr + (22 * 4)); |
| info->saved_regs[EDA_REGNUM].set_addr (addr + (23 * 4)); |
| |
| /* FIXME: If ERP is in a delay slot at this point then the PC will |
| be wrong at this point. This problem manifests itself in the |
| sigaltstack.exp test case, which occasionally generates FAILs when |
| the signal is received while in a delay slot. |
| |
| This could be solved by a couple of read_memory_unsigned_integer and a |
| trad_frame_set_value. */ |
| info->saved_regs[gdbarch_pc_regnum (gdbarch)] |
| = info->saved_regs[ERP_REGNUM]; |
| |
| info->saved_regs[gdbarch_sp_regnum (gdbarch)].set_addr (addr + (25 * 4)); |
| } |
| |
| return info; |
| } |
| |
| static void |
| cris_sigtramp_frame_this_id (const frame_info_ptr &this_frame, void **this_cache, |
| struct frame_id *this_id) |
| { |
| struct cris_unwind_cache *cache = |
| cris_sigtramp_frame_unwind_cache (this_frame, this_cache); |
| (*this_id) = frame_id_build (cache->base, get_frame_pc (this_frame)); |
| } |
| |
| /* Forward declaration. */ |
| |
| static struct value *cris_frame_prev_register (const frame_info_ptr &this_frame, |
| void **this_cache, int regnum); |
| static struct value * |
| cris_sigtramp_frame_prev_register (const frame_info_ptr &this_frame, |
| void **this_cache, int regnum) |
| { |
| /* Make sure we've initialized the cache. */ |
| cris_sigtramp_frame_unwind_cache (this_frame, this_cache); |
| return cris_frame_prev_register (this_frame, this_cache, regnum); |
| } |
| |
| static int |
| cris_sigtramp_frame_sniffer (const struct frame_unwind *self, |
| const frame_info_ptr &this_frame, |
| void **this_cache) |
| { |
| if (cris_sigtramp_start (this_frame) |
| || cris_rt_sigtramp_start (this_frame)) |
| return 1; |
| |
| return 0; |
| } |
| |
| static const struct frame_unwind cris_sigtramp_frame_unwind = |
| { |
| "cris sigtramp", |
| SIGTRAMP_FRAME, |
| default_frame_unwind_stop_reason, |
| cris_sigtramp_frame_this_id, |
| cris_sigtramp_frame_prev_register, |
| NULL, |
| cris_sigtramp_frame_sniffer |
| }; |
| |
| static int |
| crisv32_single_step_through_delay (struct gdbarch *gdbarch, |
| const frame_info_ptr &this_frame) |
| { |
| cris_gdbarch_tdep *tdep = gdbarch_tdep<cris_gdbarch_tdep> (gdbarch); |
| ULONGEST erp; |
| int ret = 0; |
| |
| if (tdep->cris_mode == cris_mode_guru) |
| erp = get_frame_register_unsigned (this_frame, NRP_REGNUM); |
| else |
| erp = get_frame_register_unsigned (this_frame, ERP_REGNUM); |
| |
| if (erp & 0x1) |
| { |
| /* In delay slot - check if there's a breakpoint at the preceding |
| instruction. */ |
| if (breakpoint_here_p (get_frame_address_space (this_frame), erp & ~0x1)) |
| ret = 1; |
| } |
| return ret; |
| } |
| |
| /* The instruction environment needed to find single-step breakpoints. */ |
| |
| 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; |
| enum bfd_endian byte_order; |
| } inst_env_type; |
| |
| /* Machine-dependencies in CRIS for opcodes. */ |
| |
| /* Instruction sizes. */ |
| enum cris_instruction_sizes |
| { |
| INST_BYTE_SIZE = 0, |
| INST_WORD_SIZE = 1, |
| INST_DWORD_SIZE = 2 |
| }; |
| |
| /* Addressing modes. */ |
| enum cris_addressing_modes |
| { |
| REGISTER_MODE = 1, |
| INDIRECT_MODE = 2, |
| AUTOINC_MODE = 3 |
| }; |
| |
| /* Prefix addressing modes. */ |
| enum cris_prefix_addressing_modes |
| { |
| PREFIX_INDEX_MODE = 2, |
| PREFIX_ASSIGN_MODE = 3, |
| |
| /* Handle immediate byte offset addressing mode prefix format. */ |
| PREFIX_OFFSET_MODE = 2 |
| }; |
| |
| /* Masks for opcodes. */ |
| 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 |
| }; |
| |
| /* Functions for opcodes. The general form of the ETRAX 16-bit instruction: |
| Bit 15 - 12 Operand2 |
| 11 - 10 Mode |
| 9 - 6 Opcode |
| 5 - 4 Size |
| 3 - 0 Operand1 */ |
| |
| 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); |
| } |
| |
| /* Additional functions in order to handle opcodes. */ |
| |
| 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)); |
| } |
| |
| /* Calls an op function given the op-type, working on the insn and the |
| inst_env. */ |
| static void cris_gdb_func (struct gdbarch *, enum cris_op_type, unsigned short, |
| inst_env_type *); |
| |
| static struct gdbarch *cris_gdbarch_init (struct gdbarch_info, |
| struct gdbarch_list *); |
| |
| static void cris_dump_tdep (struct gdbarch *, struct ui_file *); |
| |
| static void set_cris_version (const char *ignore_args, int from_tty, |
| struct cmd_list_element *c); |
| |
| static void set_cris_mode (const char *ignore_args, int from_tty, |
| struct cmd_list_element *c); |
| |
| static void set_cris_dwarf2_cfi (const char *ignore_args, int from_tty, |
| struct cmd_list_element *c); |
| |
| static CORE_ADDR cris_scan_prologue (CORE_ADDR pc, |
| const frame_info_ptr &this_frame, |
| struct cris_unwind_cache *info); |
| |
| static CORE_ADDR crisv32_scan_prologue (CORE_ADDR pc, |
| const frame_info_ptr &this_frame, |
| struct cris_unwind_cache *info); |
| |
| /* When arguments must be pushed onto the stack, they go on in reverse |
| order. The below implements a FILO (stack) to do this. |
| Copied from d10v-tdep.c. */ |
| |
| struct cris_stack_item |
| { |
| int len; |
| struct cris_stack_item *prev; |
| gdb_byte *data; |
| }; |
| |
| static struct cris_stack_item * |
| push_stack_item (struct cris_stack_item *prev, const gdb_byte *contents, |
| int len) |
| { |
| struct cris_stack_item *si = XNEW (struct cris_stack_item); |
| si->data = (gdb_byte *) xmalloc (len); |
| si->len = len; |
| si->prev = prev; |
| memcpy (si->data, contents, len); |
| return si; |
| } |
| |
| static struct cris_stack_item * |
| pop_stack_item (struct cris_stack_item *si) |
| { |
| struct cris_stack_item *dead = si; |
| si = si->prev; |
| xfree (dead->data); |
| xfree (dead); |
| return si; |
| } |
| |
| /* Put here the code to store, into fi->saved_regs, the addresses of |
| the saved registers of frame described by FRAME_INFO. This |
| includes special registers such as pc and fp saved in special ways |
| in the stack frame. sp is even more special: the address we return |
| for it IS the sp for the next frame. */ |
| |
| static struct cris_unwind_cache * |
| cris_frame_unwind_cache (const frame_info_ptr &this_frame, |
| void **this_prologue_cache) |
| { |
| struct gdbarch *gdbarch = get_frame_arch (this_frame); |
| cris_gdbarch_tdep *tdep = gdbarch_tdep<cris_gdbarch_tdep> (gdbarch); |
| struct cris_unwind_cache *info; |
| |
| if ((*this_prologue_cache)) |
| return (struct cris_unwind_cache *) (*this_prologue_cache); |
| |
| info = FRAME_OBSTACK_ZALLOC (struct cris_unwind_cache); |
| (*this_prologue_cache) = info; |
| info->saved_regs = trad_frame_alloc_saved_regs (this_frame); |
| |
| /* Zero all fields. */ |
| 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; |
| |
| /* Prologue analysis does the rest... */ |
| if (tdep->cris_version == 32) |
| crisv32_scan_prologue (get_frame_func (this_frame), this_frame, info); |
| else |
| cris_scan_prologue (get_frame_func (this_frame), this_frame, info); |
| |
| return info; |
| } |
| |
| /* Given a GDB frame, determine the address of the calling function's |
| frame. This will be used to create a new GDB frame struct. */ |
| |
| static void |
| cris_frame_this_id (const frame_info_ptr &this_frame, |
| void **this_prologue_cache, |
| struct frame_id *this_id) |
| { |
| struct cris_unwind_cache *info |
| = cris_frame_unwind_cache (this_frame, this_prologue_cache); |
| CORE_ADDR base; |
| CORE_ADDR func; |
| struct frame_id id; |
| |
| /* The FUNC is easy. */ |
| func = get_frame_func (this_frame); |
| |
| /* Hopefully the prologue analysis either correctly determined the |
| frame's base (which is the SP from the previous frame), or set |
| that base to "NULL". */ |
| base = info->prev_sp; |
| if (base == 0) |
| return; |
| |
| id = frame_id_build (base, func); |
| |
| (*this_id) = id; |
| } |
| |
| static struct value * |
| cris_frame_prev_register (const frame_info_ptr &this_frame, |
| void **this_prologue_cache, int regnum) |
| { |
| struct cris_unwind_cache *info |
| = cris_frame_unwind_cache (this_frame, this_prologue_cache); |
| return trad_frame_get_prev_register (this_frame, info->saved_regs, regnum); |
| } |
| |
| static CORE_ADDR |
| cris_frame_align (struct gdbarch *gdbarch, CORE_ADDR sp) |
| { |
| /* Align to the size of an instruction (so that they can safely be |
| pushed onto the stack). */ |
| return sp & ~3; |
| } |
| |
| static CORE_ADDR |
| cris_push_dummy_code (struct gdbarch *gdbarch, |
| CORE_ADDR sp, CORE_ADDR funaddr, |
| struct value **args, int nargs, |
| struct type *value_type, |
| CORE_ADDR *real_pc, CORE_ADDR *bp_addr, |
| struct regcache *regcache) |
| { |
| /* Allocate space sufficient for a breakpoint. */ |
| sp = (sp - 4) & ~3; |
| /* Store the address of that breakpoint */ |
| *bp_addr = sp; |
| /* CRIS always starts the call at the callee's entry point. */ |
| *real_pc = funaddr; |
| return sp; |
| } |
| |
| static CORE_ADDR |
| cris_push_dummy_call (struct gdbarch *gdbarch, struct value *function, |
| struct regcache *regcache, CORE_ADDR bp_addr, |
| int nargs, struct value **args, CORE_ADDR sp, |
| function_call_return_method return_method, |
| CORE_ADDR struct_addr) |
| { |
| enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); |
| int argreg; |
| int argnum; |
| |
| struct cris_stack_item *si = NULL; |
| |
| /* Push the return address. */ |
| regcache_cooked_write_unsigned (regcache, SRP_REGNUM, bp_addr); |
| |
| /* Are we returning a value using a structure return or a normal value |
| return? struct_addr is the address of the reserved space for the return |
| structure to be written on the stack. */ |
| if (return_method == return_method_struct) |
| regcache_cooked_write_unsigned (regcache, STR_REGNUM, struct_addr); |
| |
| /* Now load as many as possible of the first arguments into registers, |
| and push the rest onto the stack. */ |
| argreg = ARG1_REGNUM; |
| |
| for (argnum = 0; argnum < nargs; argnum++) |
| { |
| int len; |
| const gdb_byte *val; |
| int reg_demand; |
| int i; |
| |
| len = args[argnum]->type ()->length (); |
| val = args[argnum]->contents ().data (); |
| |
| /* How may registers worth of storage do we need for this argument? */ |
| reg_demand = (len / 4) + (len % 4 != 0 ? 1 : 0); |
| |
| if (len <= (2 * 4) && (argreg + reg_demand - 1 <= ARG4_REGNUM)) |
| { |
| /* Data passed by value. Fits in available register(s). */ |
| for (i = 0; i < reg_demand; i++) |
| { |
| regcache->cooked_write (argreg, val); |
| argreg++; |
| val += 4; |
| } |
| } |
| else if (len <= (2 * 4) && argreg <= ARG4_REGNUM) |
| { |
| /* Data passed by value. Does not fit in available register(s). |
| Use the register(s) first, then the stack. */ |
| for (i = 0; i < reg_demand; i++) |
| { |
| if (argreg <= ARG4_REGNUM) |
| { |
| regcache->cooked_write (argreg, val); |
| argreg++; |
| val += 4; |
| } |
| else |
| { |
| /* Push item for later so that pushed arguments |
| come in the right order. */ |
| si = push_stack_item (si, val, 4); |
| val += 4; |
| } |
| } |
| } |
| else if (len > (2 * 4)) |
| { |
| /* Data passed by reference. Push copy of data onto stack |
| and pass pointer to this copy as argument. */ |
| sp = (sp - len) & ~3; |
| write_memory (sp, val, len); |
| |
| if (argreg <= ARG4_REGNUM) |
| { |
| regcache_cooked_write_unsigned (regcache, argreg, sp); |
| argreg++; |
| } |
| else |
| { |
| gdb_byte buf[4]; |
| store_unsigned_integer (buf, 4, byte_order, sp); |
| si = push_stack_item (si, buf, 4); |
| } |
| } |
| else |
| { |
| /* Data passed by value. No available registers. Put it on |
| the stack. */ |
| si = push_stack_item (si, val, len); |
| } |
| } |
| |
| while (si) |
| { |
| /* fp_arg must be word-aligned (i.e., don't += len) to match |
| the function prologue. */ |
| sp = (sp - si->len) & ~3; |
| write_memory (sp, si->data, si->len); |
| si = pop_stack_item (si); |
| } |
| |
| /* Finally, update the SP register. */ |
| regcache_cooked_write_unsigned (regcache, gdbarch_sp_regnum (gdbarch), sp); |
| |
| return sp; |
| } |
| |
| static const struct frame_unwind cris_frame_unwind = |
| { |
| "cris prologue", |
| NORMAL_FRAME, |
| default_frame_unwind_stop_reason, |
| cris_frame_this_id, |
| cris_frame_prev_register, |
| NULL, |
| default_frame_sniffer |
| }; |
| |
| static CORE_ADDR |
| cris_frame_base_address (const frame_info_ptr &this_frame, void **this_cache) |
| { |
| struct cris_unwind_cache *info |
| = cris_frame_unwind_cache (this_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 |
| }; |
| |
| /* Frames information. The definition of the struct frame_info is |
| |
| CORE_ADDR frame |
| CORE_ADDR pc |
| enum frame_type type; |
| CORE_ADDR return_pc |
| int leaf_function |
| |
| If the compilation option -fno-omit-frame-pointer is present the |
| variable frame will be set to the content of R8 which is the frame |
| pointer register. |
| |
| The variable pc contains the address where execution is performed |
| in the present frame. The innermost frame contains the current content |
| of the register PC. All other frames contain the content of the |
| register PC in the next frame. |
| |
| The variable `type' indicates the frame's type: normal, SIGTRAMP |
| (associated with a signal handler), dummy (associated with a dummy |
| frame). |
| |
| The variable return_pc contains the address where execution should be |
| resumed when the present frame has finished, the return address. |
| |
| The variable leaf_function is 1 if the return address is in the register |
| SRP, and 0 if it is on the stack. |
| |
| Prologue instructions C-code. |
| The prologue may consist of (-fno-omit-frame-pointer) |
| 1) 2) |
| push srp |
| push r8 push r8 |
| move.d sp,r8 move.d sp,r8 |
| subq X,sp subq X,sp |
| movem rY,[sp] movem rY,[sp] |
| move.S rZ,[r8-U] move.S rZ,[r8-U] |
| |
| where 1 is a non-terminal function, and 2 is a leaf-function. |
| |
| Note that this assumption is extremely brittle, and will break at the |
| slightest change in GCC's prologue. |
| |
| If local variables are declared or register contents are saved on stack |
| the subq-instruction will be present with X as the number of bytes |
| needed for storage. The reshuffle with respect to r8 may be performed |
| with any size S (b, w, d) and any of the general registers Z={0..13}. |
| The offset U should be representable by a signed 8-bit value in all cases. |
| Thus, the prefix word is assumed to be immediate byte offset mode followed |
| by another word containing the instruction. |
| |
| Degenerate cases: |
| 3) |
| push r8 |
| move.d sp,r8 |
| move.d r8,sp |
| pop r8 |
| |
| Prologue instructions C++-code. |
| Case 1) and 2) in the C-code may be followed by |
| |
| move.d r10,rS ; this |
| move.d r11,rT ; P1 |
| move.d r12,rU ; P2 |
| move.d r13,rV ; P3 |
| move.S [r8+U],rZ ; P4 |
| |
| if any of the call parameters are stored. The host expects these |
| instructions to be executed in order to get the call parameters right. */ |
| |
| /* Examine the prologue of a function. The variable ip is the address of |
| the first instruction of the prologue. The variable limit is the address |
| of the first instruction after the prologue. The variable fi contains the |
| information in struct frame_info. The variable frameless_p controls whether |
| the entire prologue is examined (0) or just enough instructions to |
| determine that it is a prologue (1). */ |
| |
| static CORE_ADDR |
| cris_scan_prologue (CORE_ADDR pc, const frame_info_ptr &this_frame, |
| struct cris_unwind_cache *info) |
| { |
| struct gdbarch *gdbarch = get_frame_arch (this_frame); |
| enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); |
| |
| /* Present instruction. */ |
| unsigned short insn; |
| |
| /* Next instruction, lookahead. */ |
| unsigned short insn_next; |
| int regno; |
| |
| /* Number of byte on stack used for local variables and movem. */ |
| int val; |
| |
| /* Highest register number in a movem. */ |
| int regsave; |
| |
| /* move.d r<source_register>,rS */ |
| short source_register; |
| |
| /* Scan limit. */ |
| int limit; |
| |
| /* This frame is with respect to a leaf until a push srp is found. */ |
| if (info) |
| { |
| info->leaf_function = 1; |
| } |
| |
| /* Assume nothing on stack. */ |
| val = 0; |
| regsave = -1; |
| |
| /* If we were called without a this_frame, that means we were called |
| from cris_skip_prologue which already tried to find the end of the |
| prologue through the symbol information. 64 instructions past current |
| pc is arbitrarily chosen, but at least it means we'll stop eventually. */ |
| limit = this_frame ? get_frame_pc (this_frame) : pc + 64; |
| |
| /* Find the prologue instructions. */ |
| while (pc > 0 && pc < limit) |
| { |
| insn = read_memory_unsigned_integer (pc, 2, byte_order); |
| pc += 2; |
| if (insn == 0xE1FC) |
| { |
| /* push <reg> 32 bit instruction. */ |
| insn_next = read_memory_unsigned_integer (pc, 2, byte_order); |
| pc += 2; |
| regno = cris_get_operand2 (insn_next); |
| if (info) |
| { |
| info->sp_offset += 4; |
| } |
| /* This check, meant to recognize srp, used to be regno == |
| (SRP_REGNUM - NUM_GENREGS), but that covers r11 also. */ |
| if (insn_next == 0xBE7E) |
| { |
| if (info) |
| { |
| info->leaf_function = 0; |
| } |
| } |
| else if (insn_next == 0x8FEE) |
| { |
| /* push $r8 */ |
| if (info) |
| { |
| info->r8_offset = info->sp_offset; |
| } |
| } |
| } |
| else if (insn == 0x866E) |
| { |
| /* move.d sp,r8 */ |
| if (info) |
| { |
| info->uses_frame = 1; |
| } |
| continue; |
| } |
| else if (cris_get_operand2 (insn) == gdbarch_sp_regnum (gdbarch) |
| && cris_get_mode (insn) == 0x0000 |
| && cris_get_opcode (insn) == 0x000A) |
| { |
| /* subq <val>,sp */ |
| 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) == gdbarch_sp_regnum (gdbarch)) |
| { |
| /* movem r<regsave>,[sp] */ |
| regsave = cris_get_operand2 (insn); |
| } |
| else if (cris_get_operand2 (insn) == gdbarch_sp_regnum (gdbarch) |
| && ((insn & 0x0F00) >> 8) == 0x0001 |
| && (cris_get_signed_offset (insn) < 0)) |
| { |
| /* Immediate byte offset addressing prefix word with sp as base |
| register. Used for CRIS v8 i.e. ETRAX 100 and newer if <val> |
| is between 64 and 128. |
| movem r<regsave>,[sp=sp-<val>] */ |
| if (info) |
| { |
| info->sp_offset += -cris_get_signed_offset (insn); |
| } |
| insn_next = read_memory_unsigned_integer (pc, 2, byte_order); |
| 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) == gdbarch_sp_regnum |
| (gdbarch)) |
| { |
| regsave = cris_get_operand2 (insn_next); |
| } |
| else |
| { |
| /* The prologue ended before the limit was reached. */ |
| pc -= 4; |
| break; |
| } |
| } |
| else if (cris_get_mode (insn) == 0x0001 |
| && cris_get_opcode (insn) == 0x0009 |
| && cris_get_size (insn) == 0x0002) |
| { |
| /* move.d r<10..13>,r<0..15> */ |
| source_register = cris_get_operand1 (insn); |
| |
| /* FIXME? In the glibc solibs, the prologue might contain something |
| like (this example taken from relocate_doit): |
| move.d $pc,$r0 |
| sub.d 0xfffef426,$r0 |
| which isn't covered by the source_register check below. Question |
| is whether to add a check for this combo, or make better use of |
| the limit variable instead. */ |
| if (source_register < ARG1_REGNUM || source_register > ARG4_REGNUM) |
| { |
| /* The prologue ended before the limit was reached. */ |
| pc -= 2; |
| break; |
| } |
| } |
| else if (cris_get_operand2 (insn) == CRIS_FP_REGNUM |
| /* The size is a fixed-size. */ |
| && ((insn & 0x0F00) >> 8) == 0x0001 |
| /* A negative offset. */ |
| && (cris_get_signed_offset (insn) < 0)) |
| { |
| /* move.S rZ,[r8-U] (?) */ |
| insn_next = read_memory_unsigned_integer (pc, 2, byte_order); |
| pc += 2; |
| regno = cris_get_operand2 (insn_next); |
| if ((regno >= 0 && regno < gdbarch_sp_regnum (gdbarch)) |
| && cris_get_mode (insn_next) == PREFIX_OFFSET_MODE |
| && cris_get_opcode (insn_next) == 0x000F) |
| { |
| /* move.S rZ,[r8-U] */ |
| continue; |
| } |
| else |
| { |
| /* The prologue ended before the limit was reached. */ |
| pc -= 4; |
| break; |
| } |
| } |
| else if (cris_get_operand2 (insn) == CRIS_FP_REGNUM |
| /* The size is a fixed-size. */ |
| && ((insn & 0x0F00) >> 8) == 0x0001 |
| /* A positive offset. */ |
| && (cris_get_signed_offset (insn) > 0)) |
| { |
| /* move.S [r8+U],rZ (?) */ |
| insn_next = read_memory_unsigned_integer (pc, 2, byte_order); |
| pc += 2; |
| regno = cris_get_operand2 (insn_next); |
| if ((regno >= 0 && regno < gdbarch_sp_regnum (gdbarch)) |
| && cris_get_mode (insn_next) == PREFIX_OFFSET_MODE |
| && cris_get_opcode (insn_next) == 0x0009 |
| && cris_get_operand1 (insn_next) == regno) |
| { |
| /* move.S [r8+U],rZ */ |
| continue; |
| } |
| else |
| { |
| /* The prologue ended before the limit was reached. */ |
| pc -= 4; |
| break; |
| } |
| } |
| else |
| { |
| /* The prologue ended before the limit was reached. */ |
| pc -= 2; |
| break; |
| } |
| } |
| |
| /* We only want to know the end of the prologue when this_frame and info |
| are NULL (called from cris_skip_prologue i.e.). */ |
| if (this_frame == NULL && info == NULL) |
| { |
| return pc; |
| } |
| |
| info->size = info->sp_offset; |
| |
| /* Compute the previous frame's stack pointer (which is also the |
| frame's ID's stack address), and this frame's base pointer. */ |
| if (info->uses_frame) |
| { |
| ULONGEST this_base; |
| /* The SP was moved to the FP. This indicates that a new frame |
| was created. Get THIS frame's FP value by unwinding it from |
| the next frame. */ |
| this_base = get_frame_register_unsigned (this_frame, CRIS_FP_REGNUM); |
| info->base = this_base; |
| info->saved_regs[CRIS_FP_REGNUM].set_addr (info->base); |
| |
| /* The FP points at the last saved register. Adjust the FP back |
| to before the first saved register giving the SP. */ |
| info->prev_sp = info->base + info->r8_offset; |
| } |
| else |
| { |
| ULONGEST this_base; |
| /* Assume that the FP is this frame's SP but with that pushed |
| stack space added back. */ |
| this_base = get_frame_register_unsigned (this_frame, |
| gdbarch_sp_regnum (gdbarch)); |
| info->base = this_base; |
| info->prev_sp = info->base + info->size; |
| } |
| |
| /* Calculate the addresses for the saved registers on the stack. */ |
| /* FIXME: The address calculation should really be done on the fly while |
| we're analyzing the prologue (we only hold one regsave value as it is |
| now). */ |
| val = info->sp_offset; |
| |
| for (regno = regsave; regno >= 0; regno--) |
| { |
| info->saved_regs[regno].set_addr (info->base + info->r8_offset - val); |
| val -= 4; |
| } |
| |
| /* The previous frame's SP needed to be computed. Save the computed |
| value. */ |
| info->saved_regs[gdbarch_sp_regnum (gdbarch)].set_value (info->prev_sp); |
| |
| if (!info->leaf_function) |
| { |
| /* SRP saved on the stack. But where? */ |
| if (info->r8_offset == 0) |
| { |
| /* R8 not pushed yet. */ |
| info->saved_regs[SRP_REGNUM].set_addr (info->base); |
| } |
| else |
| { |
| /* R8 pushed, but SP may or may not be moved to R8 yet. */ |
| info->saved_regs[SRP_REGNUM].set_addr (info->base + 4); |
| } |
| } |
| |
| /* The PC is found in SRP (the actual register or located on the stack). */ |
| info->saved_regs[gdbarch_pc_regnum (gdbarch)] |
| = info->saved_regs[SRP_REGNUM]; |
| |
| return pc; |
| } |
| |
| static CORE_ADDR |
| crisv32_scan_prologue (CORE_ADDR pc, const frame_info_ptr &this_frame, |
| struct cris_unwind_cache *info) |
| { |
| struct gdbarch *gdbarch = get_frame_arch (this_frame); |
| ULONGEST this_base; |
| |
| /* Unlike the CRISv10 prologue scanner (cris_scan_prologue), this is not |
| meant to be a full-fledged prologue scanner. It is only needed for |
| the cases where we end up in code always lacking DWARF-2 CFI, notably: |
| |
| * PLT stubs (library calls) |
| * call dummys |
| * signal trampolines |
| |
| For those cases, it is assumed that there is no actual prologue; that |
| the stack pointer is not adjusted, and (as a consequence) the return |
| address is not pushed onto the stack. */ |
| |
| /* We only want to know the end of the prologue when this_frame and info |
| are NULL (called from cris_skip_prologue i.e.). */ |
| if (this_frame == NULL && info == NULL) |
| { |
| return pc; |
| } |
| |
| /* The SP is assumed to be unaltered. */ |
| this_base = get_frame_register_unsigned (this_frame, |
| gdbarch_sp_regnum (gdbarch)); |
| info->base = this_base; |
| info->prev_sp = this_base; |
| |
| /* The PC is assumed to be found in SRP. */ |
| info->saved_regs[gdbarch_pc_regnum (gdbarch)] |
| = info->saved_regs[SRP_REGNUM]; |
| |
| return pc; |
| } |
| |
| /* Advance pc beyond any function entry prologue instructions at pc |
| to reach some "real" code. */ |
| |
| /* Given a PC value corresponding to the start of a function, return the PC |
| of the first instruction after the function prologue. */ |
| |
| static CORE_ADDR |
| cris_skip_prologue (struct gdbarch *gdbarch, CORE_ADDR pc) |
| { |
| cris_gdbarch_tdep *tdep = gdbarch_tdep<cris_gdbarch_tdep> (gdbarch); |
| CORE_ADDR func_addr, func_end; |
| struct symtab_and_line sal; |
| CORE_ADDR pc_after_prologue; |
| |
| /* If we have line debugging information, then the end of the prologue |
| should the first assembly instruction of the first source line. */ |
| if (find_pc_partial_function (pc, NULL, &func_addr, &func_end)) |
| { |
| sal = find_pc_line (func_addr, 0); |
| if (sal.end > 0 && sal.end < func_end) |
| return sal.end; |
| } |
| |
| if (tdep->cris_version == 32) |
| pc_after_prologue = crisv32_scan_prologue (pc, NULL, NULL); |
| else |
| pc_after_prologue = cris_scan_prologue (pc, NULL, NULL); |
| |
| return pc_after_prologue; |
| } |
| |
| /* Implement the breakpoint_kind_from_pc gdbarch method. */ |
| |
| static int |
| cris_breakpoint_kind_from_pc (struct gdbarch *gdbarch, CORE_ADDR *pcptr) |
| { |
| return 2; |
| } |
| |
| /* Implement the sw_breakpoint_from_kind gdbarch method. */ |
| |
| static const gdb_byte * |
| cris_sw_breakpoint_from_kind (struct gdbarch *gdbarch, int kind, int *size) |
| { |
| cris_gdbarch_tdep *tdep = gdbarch_tdep<cris_gdbarch_tdep> (gdbarch); |
| static unsigned char break8_insn[] = {0x38, 0xe9}; |
| static unsigned char break15_insn[] = {0x3f, 0xe9}; |
| |
| *size = kind; |
| |
| if (tdep->cris_mode == cris_mode_guru) |
| return break15_insn; |
| else |
| return break8_insn; |
| } |
| |
| /* Returns 1 if spec_reg is applicable to the current gdbarch's CRIS version, |
| 0 otherwise. */ |
| |
| static int |
| cris_spec_reg_applicable (struct gdbarch *gdbarch, |
| struct cris_spec_reg spec_reg) |
| { |
| cris_gdbarch_tdep *tdep = gdbarch_tdep<cris_gdbarch_tdep> (gdbarch); |
| unsigned int version = tdep->cris_version; |
| |
| switch (spec_reg.applicable_version) |
| { |
| case cris_ver_version_all: |
| return 1; |
| case cris_ver_warning: |
| /* Indeterminate/obsolete. */ |
| return 0; |
| case cris_ver_v0_3: |
| return in_inclusive_range (version, 0U, 3U); |
| case cris_ver_v3p: |
| return (version >= 3); |
| case cris_ver_v8: |
| return in_inclusive_range (version, 8U, 9U); |
| case cris_ver_v8p: |
| return (version >= 8); |
| case cris_ver_v0_10: |
| return in_inclusive_range (version, 0U, 10U); |
| case cris_ver_v3_10: |
| return in_inclusive_range (version, 3U, 10U); |
| case cris_ver_v8_10: |
| return in_inclusive_range (version, 8U, 10U); |
| case cris_ver_v10: |
| return (version == 10); |
| case cris_ver_v10p: |
| return (version >= 10); |
| case cris_ver_v32p: |
| return (version >= 32); |
| default: |
| /* Invalid cris version. */ |
| return 0; |
| } |
| } |
| |
| /* Returns the register size in unit byte. Returns 0 for an unimplemented |
| register, -1 for an invalid register. */ |
| |
| static int |
| cris_register_size (struct gdbarch *gdbarch, int regno) |
| { |
| int i; |
| int spec_regno; |
| |
| if (regno >= 0 && regno < NUM_GENREGS) |
| { |
| /* General registers (R0 - R15) are 32 bits. */ |
| return 4; |
| } |
| else if (regno >= NUM_GENREGS && regno < (NUM_GENREGS + NUM_SPECREGS)) |
| { |
| /* Special register (R16 - R31). cris_spec_regs is zero-based. |
| Adjust regno accordingly. */ |
| spec_regno = regno - NUM_GENREGS; |
| |
| for (i = 0; cris_spec_regs[i].name != NULL; i++) |
| { |
| if (cris_spec_regs[i].number == spec_regno |
| && cris_spec_reg_applicable (gdbarch, cris_spec_regs[i])) |
| /* Go with the first applicable register. */ |
| return cris_spec_regs[i].reg_size; |
| } |
| /* Special register not applicable to this CRIS version. */ |
| return 0; |
| } |
| else if (regno >= gdbarch_pc_regnum (gdbarch) |
| && regno < gdbarch_num_regs (gdbarch)) |
| { |
| /* This will apply to CRISv32 only where there are additional registers |
| after the special registers (pseudo PC and support registers). */ |
| return 4; |
| } |
| |
| |
| return -1; |
| } |
| |
| /* Nonzero if regno should not be fetched from the target. This is the case |
| for unimplemented (size 0) and non-existant registers. */ |
| |
| static int |
| cris_cannot_fetch_register (struct gdbarch *gdbarch, int regno) |
| { |
| return ((regno < 0 || regno >= gdbarch_num_regs (gdbarch)) |
| || (cris_register_size (gdbarch, regno) == 0)); |
| } |
| |
| /* Nonzero if regno should not be written to the target, for various |
| reasons. */ |
| |
| static int |
| cris_cannot_store_register (struct gdbarch *gdbarch, int regno) |
| { |
| /* There are three kinds of registers we refuse to write to. |
| 1. Those that not implemented. |
| 2. Those that are read-only (depends on the processor mode). |
| 3. Those registers to which a write has no effect. */ |
| |
| if (regno < 0 |
| || regno >= gdbarch_num_regs (gdbarch) |
| || cris_register_size (gdbarch, regno) == 0) |
| /* Not implemented. */ |
| return 1; |
| |
| else if (regno == VR_REGNUM) |
| /* Read-only. */ |
| return 1; |
| |
| else if (regno == P0_REGNUM || regno == P4_REGNUM || regno == P8_REGNUM) |
| /* Writing has no effect. */ |
| return 1; |
| |
| /* IBR, BAR, BRP and IRP are read-only in user mode. Let the debug |
| agent decide whether they are writable. */ |
| |
| return 0; |
| } |
| |
| /* Nonzero if regno should not be fetched from the target. This is the case |
| for unimplemented (size 0) and non-existant registers. */ |
| |
| static int |
| crisv32_cannot_fetch_register (struct gdbarch *gdbarch, int regno) |
| { |
| return ((regno < 0 || regno >= gdbarch_num_regs (gdbarch)) |
| || (cris_register_size (gdbarch, regno) == 0)); |
| } |
| |
| /* Nonzero if regno should not be written to the target, for various |
| reasons. */ |
| |
| static int |
| crisv32_cannot_store_register (struct gdbarch *gdbarch, int regno) |
| { |
| /* There are three kinds of registers we refuse to write to. |
| 1. Those that not implemented. |
| 2. Those that are read-only (depends on the processor mode). |
| 3. Those registers to which a write has no effect. */ |
| |
| if (regno < 0 |
| || regno >= gdbarch_num_regs (gdbarch) |
| || cris_register_size (gdbarch, regno) == 0) |
| /* Not implemented. */ |
| return 1; |
| |
| else if (regno == VR_REGNUM) |
| /* Read-only. */ |
| return 1; |
| |
| else if (regno == BZ_REGNUM || regno == WZ_REGNUM || regno == DZ_REGNUM) |
| /* Writing has no effect. */ |
| return 1; |
| |
| /* Many special registers are read-only in user mode. Let the debug |
| agent decide whether they are writable. */ |
| |
| return 0; |
| } |
| |
| /* Return the GDB type (defined in gdbtypes.c) for the "standard" data type |
| of data in register regno. */ |
| |
| static struct type * |
| cris_register_type (struct gdbarch *gdbarch, int regno) |
| { |
| if (regno == gdbarch_pc_regnum (gdbarch)) |
| return builtin_type (gdbarch)->builtin_func_ptr; |
| else if (regno == gdbarch_sp_regnum (gdbarch) |
| || regno == CRIS_FP_REGNUM) |
| return builtin_type (gdbarch)->builtin_data_ptr; |
| else if ((regno >= 0 && regno < gdbarch_sp_regnum (gdbarch)) |
| || (regno >= MOF_REGNUM && regno <= USP_REGNUM)) |
| /* Note: R8 taken care of previous clause. */ |
| return builtin_type (gdbarch)->builtin_uint32; |
| else if (regno >= P4_REGNUM && regno <= CCR_REGNUM) |
| return builtin_type (gdbarch)->builtin_uint16; |
| else if (regno >= P0_REGNUM && regno <= VR_REGNUM) |
| return builtin_type (gdbarch)->builtin_uint8; |
| else |
| /* Invalid (unimplemented) register. */ |
| return builtin_type (gdbarch)->builtin_int0; |
| } |
| |
| static struct type * |
| crisv32_register_type (struct gdbarch *gdbarch, int regno) |
| { |
| if (regno == gdbarch_pc_regnum (gdbarch)) |
| return builtin_type (gdbarch)->builtin_func_ptr; |
| else if (regno == gdbarch_sp_regnum (gdbarch) |
| || regno == CRIS_FP_REGNUM) |
| return builtin_type (gdbarch)->builtin_data_ptr; |
| else if ((regno >= 0 && regno <= ACR_REGNUM) |
| || (regno >= EXS_REGNUM && regno <= SPC_REGNUM) |
| || (regno == PID_REGNUM) |
| || (regno >= S0_REGNUM && regno <= S15_REGNUM)) |
| /* Note: R8 and SP taken care of by previous clause. */ |
| return builtin_type (gdbarch)->builtin_uint32; |
| else if (regno == WZ_REGNUM) |
| return builtin_type (gdbarch)->builtin_uint16; |
| else if (regno == BZ_REGNUM || regno == VR_REGNUM || regno == SRS_REGNUM) |
| return builtin_type (gdbarch)->builtin_uint8; |
| else |
| { |
| /* Invalid (unimplemented) register. Should not happen as there are |
| no unimplemented CRISv32 registers. */ |
| warning (_("crisv32_register_type: unknown regno %d"), regno); |
| return builtin_type (gdbarch)->builtin_int0; |
| } |
| } |
| |
| /* Stores a function return value of type type, where valbuf is the address |
| of the value to be stored. */ |
| |
| /* In the CRIS ABI, R10 and R11 are used to store return values. */ |
| |
| static void |
| cris_store_return_value (struct type *type, struct regcache *regcache, |
| const gdb_byte *valbuf) |
| { |
| struct gdbarch *gdbarch = regcache->arch (); |
| enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); |
| ULONGEST val; |
| int len = type->length (); |
| |
| if (len <= 4) |
| { |
| /* Put the return value in R10. */ |
| val = extract_unsigned_integer (valbuf, len, byte_order); |
| regcache_cooked_write_unsigned (regcache, ARG1_REGNUM, val); |
| } |
| else if (len <= 8) |
| { |
| /* Put the return value in R10 and R11. */ |
| val = extract_unsigned_integer (valbuf, 4, byte_order); |
| regcache_cooked_write_unsigned (regcache, ARG1_REGNUM, val); |
| val = extract_unsigned_integer (valbuf + 4, len - 4, byte_order); |
| regcache_cooked_write_unsigned (regcache, ARG2_REGNUM, val); |
| } |
| else |
| error (_("cris_store_return_value: type length too large.")); |
| } |
| |
| /* Return the name of register regno as a string. Return NULL for an |
| invalid or unimplemented register. */ |
| |
| static const char * |
| cris_special_register_name (struct gdbarch *gdbarch, int regno) |
| { |
| int spec_regno; |
| int i; |
| |
| /* Special register (R16 - R31). cris_spec_regs is zero-based. |
| Adjust regno accordingly. */ |
| spec_regno = regno - NUM_GENREGS; |
| |
| /* Assume nothing about the layout of the cris_spec_regs struct |
| when searching. */ |
| for (i = 0; cris_spec_regs[i].name != NULL; i++) |
| { |
| if (cris_spec_regs[i].number == spec_regno |
| && cris_spec_reg_applicable (gdbarch, cris_spec_regs[i])) |
| /* Go with the first applicable register. */ |
| return cris_spec_regs[i].name; |
| } |
| /* Special register not applicable to this CRIS version. */ |
| return ""; |
| } |
| |
| static const char * |
| cris_register_name (struct gdbarch *gdbarch, int regno) |
| { |
| static const char *cris_genreg_names[] = |
| { "r0", "r1", "r2", "r3", \ |
| "r4", "r5", "r6", "r7", \ |
| "r8", "r9", "r10", "r11", \ |
| "r12", "r13", "sp", "pc" }; |
| |
| if (regno < NUM_GENREGS) |
| { |
| /* General register. */ |
| static_assert (ARRAY_SIZE (cris_genreg_names) == NUM_GENREGS); |
| return cris_genreg_names[regno]; |
| } |
| else if (regno >= NUM_GENREGS && regno < gdbarch_num_regs (gdbarch)) |
| { |
| return cris_special_register_name (gdbarch, regno); |
| } |
| else |
| { |
| /* Invalid register. */ |
| return ""; |
| } |
| } |
| |
| static const char * |
| crisv32_register_name (struct gdbarch *gdbarch, int regno) |
| { |
| static const char *crisv32_genreg_names[] = |
| { "r0", "r1", "r2", "r3", \ |
| "r4", "r5", "r6", "r7", \ |
| "r8", "r9", "r10", "r11", \ |
| "r12", "r13", "sp", "acr" |
| }; |
| |
| static const char *crisv32_sreg_names[] = |
| { "s0", "s1", "s2", "s3", \ |
| "s4", "s5", "s6", "s7", \ |
| "s8", "s9", "s10", "s11", \ |
| "s12", "s13", "s14", "s15" |
| }; |
| |
| if (regno >= 0 && regno < NUM_GENREGS) |
| { |
| /* General register. */ |
| return crisv32_genreg_names[regno]; |
| } |
| else if (regno >= NUM_GENREGS && regno < (NUM_GENREGS + NUM_SPECREGS)) |
| { |
| return cris_special_register_name (gdbarch, regno); |
| } |
| else if (regno == gdbarch_pc_regnum (gdbarch)) |
| { |
| return "pc"; |
| } |
| else if (regno >= S0_REGNUM && regno <= S15_REGNUM) |
| { |
| return crisv32_sreg_names[regno - S0_REGNUM]; |
| } |
| else |
| { |
| /* Invalid register. */ |
| return NULL; |
| } |
| } |
| |
| /* Convert DWARF register number REG to the appropriate register |
| number used by GDB. */ |
| |
| static int |
| cris_dwarf2_reg_to_regnum (struct gdbarch *gdbarch, int reg) |
| { |
| /* We need to re-map a couple of registers (SRP is 16 in Dwarf-2 register |
| numbering, MOF is 18). |
| Adapted from gcc/config/cris/cris.h. */ |
| static int cris_dwarf_regmap[] = { |
| 0, 1, 2, 3, |
| 4, 5, 6, 7, |
| 8, 9, 10, 11, |
| 12, 13, 14, 15, |
| 27, -1, -1, -1, |
| -1, -1, -1, 23, |
| -1, -1, -1, 27, |
| -1, -1, -1, -1 |
| }; |
| int regnum = -1; |
| |
| if (reg >= 0 && reg < ARRAY_SIZE (cris_dwarf_regmap)) |
| regnum = cris_dwarf_regmap[reg]; |
| |
| return regnum; |
| } |
| |
| /* DWARF-2 frame support. */ |
| |
| static void |
| cris_dwarf2_frame_init_reg (struct gdbarch *gdbarch, int regnum, |
| struct dwarf2_frame_state_reg *reg, |
| const frame_info_ptr &this_frame) |
| { |
| /* The return address column. */ |
| if (regnum == gdbarch_pc_regnum (gdbarch)) |
| reg->how = DWARF2_FRAME_REG_RA; |
| |
| /* The call frame address. */ |
| else if (regnum == gdbarch_sp_regnum (gdbarch)) |
| reg->how = DWARF2_FRAME_REG_CFA; |
| } |
| |
| /* Extract from an array regbuf containing the raw register state a function |
| return value of type type, and copy that, in virtual format, into |
| valbuf. */ |
| |
| /* In the CRIS ABI, R10 and R11 are used to store return values. */ |
| |
| static void |
| cris_extract_return_value (struct type *type, struct regcache *regcache, |
| gdb_byte *valbuf) |
| { |
| struct gdbarch *gdbarch = regcache->arch (); |
| enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); |
| ULONGEST val; |
| int len = type->length (); |
| |
| if (len <= 4) |
| { |
| /* Get the return value from R10. */ |
| regcache_cooked_read_unsigned (regcache, ARG1_REGNUM, &val); |
| store_unsigned_integer (valbuf, len, byte_order, val); |
| } |
| else if (len <= 8) |
| { |
| /* Get the return value from R10 and R11. */ |
| regcache_cooked_read_unsigned (regcache, ARG1_REGNUM, &val); |
| store_unsigned_integer (valbuf, 4, byte_order, val); |
| regcache_cooked_read_unsigned (regcache, ARG2_REGNUM, &val); |
| store_unsigned_integer (valbuf + 4, len - 4, byte_order, val); |
| } |
| else |
| error (_("cris_extract_return_value: type length too large")); |
| } |
| |
| /* Handle the CRIS return value convention. */ |
| |
| static enum return_value_convention |
| cris_return_value (struct gdbarch *gdbarch, struct value *function, |
| struct type *type, struct regcache *regcache, |
| gdb_byte *readbuf, const gdb_byte *writebuf) |
| { |
| if (type->code () == TYPE_CODE_STRUCT |
| || type->code () == TYPE_CODE_UNION |
| || type->length () > 8) |
| /* Structs, unions, and anything larger than 8 bytes (2 registers) |
| goes on the stack. */ |
| return RETURN_VALUE_STRUCT_CONVENTION; |
| |
| if (readbuf) |
| cris_extract_return_value (type, regcache, readbuf); |
| if (writebuf) |
| cris_store_return_value (type, regcache, writebuf); |
| |
| return RETURN_VALUE_REGISTER_CONVENTION; |
| } |
| |
| /* Calculates a value that measures how good inst_args constraints an |
| instruction. It stems from cris_constraint, found in cris-dis.c. */ |
| |
| static int |
| constraint (unsigned int insn, const char *inst_args, |
| inst_env_type *inst_env) |
| { |
| int retval = 0; |
| int tmp, i; |
| |
| const gdb_byte *s = (const gdb_byte *) inst_args; |
| |
| for (; *s; s++) |
| switch (*s) |
| { |
| case 'm': |
| if ((insn & 0x30) == 0x30) |
| return -1; |
| break; |
| |
| case 'S': |
| /* A prefix operand. */ |
| if (inst_env->prefix_found) |
| break; |
| else |
| return -1; |
| |
| case 'B': |
| /* A "push" prefix. (This check was REMOVED by san 970921.) Check for |
| valid "push" size. In case of special register, it may be != 4. */ |
| 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++) |
| { |
| /* Since we match four bits, we will give a value of |
| 4 - 1 = 3 in a match. If there is a corresponding |
| exact match of a special register in another pattern, it |
| will get a value of 4, which will be higher. This should |
| be correct in that an exact pattern would match better that |
| a general pattern. |
| Note that there is a reason for not returning zero; the |
| pattern for "clear" is partly matched in the bit-pattern |
| (the two lower bits must be zero), while the bit-pattern |
| for a move from a special register is matched in the |
| register constraint. |
| This also means we will will have a race condition if |
| there is a partly match in three bits in the bit pattern. */ |
| if (tmp == cris_spec_regs[i].number) |
| { |
| retval += 3; |
| break; |
| } |
| } |
| |
| if (cris_spec_regs[i].name == NULL) |
| return -1; |
| break; |
| } |
| return retval; |
| } |
| |
| /* Returns the number of bits set in the variable value. */ |
| |
| 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; |
| } |
| |
| /* Finds the address that should contain the single step breakpoint(s). |
| It stems from code in cris-dis.c. */ |
| |
| 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) |
| /* Only CRISv10 instructions, please. */ |
| && (cris_opcodes[i].applicable_version != cris_ver_v32p)) |
| { |
| level_of_match = constraint (insn, cris_opcodes[i].args, inst_env); |
| if (level_of_match >= 0) |
| { |
| level_of_match += |
| number_of_bits (cris_opcodes[i].match | cris_opcodes[i].lose); |
| if (level_of_match > max_level_of_match) |
| { |
| max_matched = i; |
| max_level_of_match = level_of_match; |
| if (level_of_match == 16) |
| { |
| /* All bits matched, cannot find better. */ |
| break; |
| } |
| } |
| } |
| } |
| } |
| return max_matched; |
| } |
| |
| /* Attempts to find single-step breakpoints. Returns -1 on failure which is |
| actually an internal error. */ |
| |
| static int |
| find_step_target (struct regcache *regcache, inst_env_type *inst_env) |
| { |
| int i; |
| int offset; |
| unsigned short insn; |
| struct gdbarch *gdbarch = regcache->arch (); |
| enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); |
| |
| /* Create a local register image and set the initial state. */ |
| for (i = 0; i < NUM_GENREGS; i++) |
| { |
| inst_env->reg[i] = |
| (unsigned long) regcache_raw_get_unsigned (regcache, i); |
| } |
| offset = NUM_GENREGS; |
| for (i = 0; i < NUM_SPECREGS; i++) |
| { |
| inst_env->preg[i] = |
| (unsigned long) regcache_raw_get_unsigned (regcache, 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; |
| inst_env->byte_order = byte_order; |
| |
| /* Look for a step target. */ |
| do |
| { |
| /* Read an instruction from the client. */ |
| insn = read_memory_unsigned_integer |
| (inst_env->reg[gdbarch_pc_regnum (gdbarch)], 2, byte_order); |
| |
| /* If the instruction is not in a delay slot the new content of the |
| PC is [PC] + 2. If the instruction is in a delay slot it is not |
| that simple. Since a instruction in a delay slot cannot change |
| the content of the PC, it does not matter what value PC will have. |
| Just make sure it is a valid instruction. */ |
| if (!inst_env->delay_slot_pc_active) |
| { |
| inst_env->reg[gdbarch_pc_regnum (gdbarch)] += 2; |
| } |
| else |
| { |
| inst_env->delay_slot_pc_active = 0; |
| inst_env->reg[gdbarch_pc_regnum (gdbarch)] |
| = inst_env->delay_slot_pc; |
| } |
| /* Analyse the present instruction. */ |
| i = find_cris_op (insn, inst_env); |
| if (i == -1) |
| { |
| inst_env->invalid = 1; |
| } |
| else |
| { |
| cris_gdb_func (gdbarch, 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; |
| } |
| |
| /* There is no hardware single-step support. The function find_step_target |
| digs through the opcodes in order to find all possible targets. |
| Either one ordinary target or two targets for branches may be found. */ |
| |
| static std::vector<CORE_ADDR> |
| cris_software_single_step (struct regcache *regcache) |
| { |
| struct gdbarch *gdbarch = regcache->arch (); |
| inst_env_type inst_env; |
| std::vector<CORE_ADDR> next_pcs; |
| |
| /* Analyse the present instruction environment and insert |
| breakpoints. */ |
| int status = find_step_target (regcache, &inst_env); |
| if (status == -1) |
| { |
| /* Could not find a target. Things are likely to go downhill |
| from here. */ |
| warning (_("CRIS software single step could not find a step target.")); |
| } |
| else |
| { |
| /* Insert at most two breakpoints. One for the next PC content |
| and possibly another one for a branch, jump, etc. */ |
| CORE_ADDR next_pc |
| = (CORE_ADDR) inst_env.reg[gdbarch_pc_regnum (gdbarch)]; |
| |
| next_pcs.push_back (next_pc); |
| if (inst_env.branch_found |
| && (CORE_ADDR) inst_env.branch_break_address != next_pc) |
| { |
| CORE_ADDR branch_target_address |
| = (CORE_ADDR) inst_env.branch_break_address; |
| |
| next_pcs.push_back (branch_target_address); |
| } |
| } |
| |
| return next_pcs; |
| } |
| |
| /* Calculates the prefix value for quick offset addressing mode. */ |
| |
| static void |
| quick_mode_bdap_prefix (unsigned short inst, inst_env_type *inst_env) |
| { |
| /* It's invalid to be in a delay slot. You can't have a prefix to this |
| instruction (not 100% sure). */ |
| 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); |
| |
| /* A prefix doesn't change the xflag_found. But the rest of the flags |
| need updating. */ |
| inst_env->slot_needed = 0; |
| inst_env->prefix_found = 1; |
| } |
| |
| /* Updates the autoincrement register. The size of the increment is derived |
| from the size of the operation. The PC is always kept aligned on even |
| word addresses. */ |
| |
| 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; |
| |
| /* The PC must be word aligned, so increase the PC with one |
| word even if the size is byte. */ |
| 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 |
| { |
| /* Invalid size. */ |
| inst_env->invalid = 1; |
| } |
| } |
| |
| /* Just a forward declaration. */ |
| |
| static unsigned long get_data_from_address (unsigned short *inst, |
| CORE_ADDR address, |
| enum bfd_endian byte_order); |
| |
| /* Calculates the prefix value for the general case of offset addressing |
| mode. */ |
| |
| static void |
| bdap_prefix (unsigned short inst, inst_env_type *inst_env) |
| { |
| /* It's invalid to be in a delay slot. */ |
| if (inst_env->slot_needed || inst_env->prefix_found) |
| { |
| inst_env->invalid = 1; |
| return; |
| } |
| |
| /* The calculation of prefix_value used to be after process_autoincrement, |
| but that fails for an instruction such as jsr [$r0+12] which is encoded |
| as 5f0d 0c00 30b9 when compiled with -fpic. Since PC is operand1 it |
| mustn't be incremented until we have read it and what it points at. */ |
| inst_env->prefix_value = inst_env->reg[cris_get_operand2 (inst)]; |
| |
| /* The offset is an indirection of the contents of the operand1 register. */ |
| inst_env->prefix_value += |
| get_data_from_address (&inst, inst_env->reg[cris_get_operand1 (inst)], |
| inst_env->byte_order); |
| |
| if (cris_get_mode (inst) == AUTOINC_MODE) |
| { |
| process_autoincrement (cris_get_size (inst), inst, inst_env); |
| } |
| |
| /* A prefix doesn't change the xflag_found. But the rest of the flags |
| need updating. */ |
| inst_env->slot_needed = 0; |
| inst_env->prefix_found = 1; |
| } |
| |
| /* Calculates the prefix value for the index addressing mode. */ |
| |
| static void |
| biap_prefix (unsigned short inst, inst_env_type *inst_env) |
| { |
| /* It's invalid to be in a delay slot. I can't see that it's possible to |
| have a prefix to this instruction. So I will treat this as invalid. */ |
| 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)]; |
| |
| /* The offset is the operand2 value shifted the size of the instruction |
| to the left. */ |
| inst_env->prefix_value += |
| inst_env->reg[cris_get_operand2 (inst)] << cris_get_size (inst); |
| |
| /* If the PC is operand1 (base) the address used is the address after |
| the main instruction, i.e. address + 2 (the PC is already compensated |
| for the prefix operation). */ |
| if (cris_get_operand1 (inst) == REG_PC) |
| { |
| inst_env->prefix_value += 2; |
| } |
| |
| /* A prefix doesn't change the xflag_found. But the rest of the flags |
| need updating. */ |
| inst_env->slot_needed = 0; |
| inst_env->xflag_found = 0; |
| inst_env->prefix_found = 1; |
| } |
| |
| /* Calculates the prefix value for the double indirect addressing mode. */ |
| |
| static void |
| dip_prefix (unsigned short inst, inst_env_type *inst_env) |
| { |
| |
| CORE_ADDR address; |
| |
| /* It's invalid to be in a delay slot. */ |
| if (inst_env->slot_needed || inst_env->prefix_found) |
| { |
| inst_env->invalid = 1; |
| return; |
| } |
| |
| /* The prefix value is one dereference of the contents of the operand1 |
| register. */ |
| address = (CORE_ADDR) inst_env->reg[cris_get_operand1 (inst)]; |
| inst_env->prefix_value |
| = read_memory_unsigned_integer (address, 4, inst_env->byte_order); |
| |
| /* Check if the mode is autoincrement. */ |
| if (cris_get_mode (inst) == AUTOINC_MODE) |
| { |
| inst_env->reg[cris_get_operand1 (inst)] += 4; |
| } |
| |
| /* A prefix doesn't change the xflag_found. But the rest of the flags |
| need updating. */ |
| inst_env->slot_needed = 0; |
| inst_env->xflag_found = 0; |
| inst_env->prefix_found = 1; |
| } |
| |
| /* Finds the destination for a branch with 8-bits offset. */ |
| |
| static void |
| eight_bit_offset_branch_op (unsigned short inst, inst_env_type *inst_env) |
| { |
| |
| short offset; |
| |
| /* If we have a prefix or are in a delay slot it's bad. */ |
| if (inst_env->slot_needed || inst_env->prefix_found) |
| { |
| inst_env->invalid = 1; |
| return; |
| } |
| |
| /* We have a branch, find out where the branch will land. */ |
| offset = cris_get_branch_short_offset (inst); |
| |
| /* Check if the offset is signed. */ |
| if (offset & BRANCH_SIGNED_SHORT_OFFSET_MASK) |
| { |
| offset |= 0xFF00; |
| } |
| |
| /* The offset ends with the sign bit, set it to zero. The address |
| should always be word aligned. */ |
| 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; |
| } |
| |
| /* Finds the destination for a branch with 16-bits offset. */ |
| |
| static void |
| sixteen_bit_offset_branch_op (unsigned short inst, inst_env_type *inst_env) |
| { |
| short offset; |
| |
| /* If we have a prefix or is in a delay slot it's bad. */ |
| if (inst_env->slot_needed || inst_env->prefix_found) |
| { |
| inst_env->invalid = 1; |
| return; |
| } |
| |
| /* We have a branch, find out the offset for the branch. */ |
| offset = read_memory_integer (inst_env->reg[REG_PC], 2, |
| inst_env->byte_order); |
| |
| /* The instruction is one word longer than normal, so add one word |
| to the PC. */ |
| 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; |
| } |
| |
| /* Handles the ABS instruction. */ |
| |
| static void |
| abs_op (unsigned short inst, inst_env_type *inst_env) |
| { |
| |
| long value; |
| |
| /* ABS can't have a prefix, so it's bad if it does. */ |
| if (inst_env->prefix_found) |
| { |
| inst_env->invalid = 1; |
| return; |
| } |
| |
| /* Check if the operation affects the PC. */ |
| if (cris_get_operand2 (inst) == REG_PC) |
| { |
| |
| /* It's invalid to change to the PC if we are in a delay slot. */ |
| if (inst_env->slot_needed) |
| { |
| inst_env->invalid = 1; |
| return; |
| } |
| |
| value = (long) inst_env->reg[REG_PC]; |
| |
| /* The value of abs (SIGNED_DWORD_MASK) is SIGNED_DWORD_MASK. */ |
| 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; |
| } |
| |
| /* Handles the ADDI instruction. */ |
| |
| static void |
| addi_op (unsigned short inst, inst_env_type *inst_env) |
| { |
| /* It's invalid to have the PC as base register. And ADDI can't have |
| a prefix. */ |
| 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; |
| } |
| |
| /* Handles the ASR instruction. */ |
| |
| static void |
| asr_op (unsigned short inst, inst_env_type *inst_env) |
| { |
| int shift_steps; |
| unsigned long value; |
| unsigned long signed_extend_mask = 0; |
| |
| /* ASR can't have a prefix, so check that it doesn't. */ |
| if (inst_env->prefix_found) |
| { |
| inst_env->invalid = 1; |
| return; |
| } |
| |
| /* Check if the PC is the target register. */ |
| if (cris_get_operand2 (inst) == REG_PC) |
| { |
| /* It's invalid to change the PC in a delay slot. */ |
| if (inst_env->slot_needed) |
| { |
| inst_env->invalid = 1; |
| return; |
| } |
| /* Get the number of bits to shift. */ |
| shift_steps |
| = cris_get_asr_shift_steps (inst_env->reg[cris_get_operand1 (inst)]); |
| value = inst_env->reg[REG_PC]; |
| |
| /* Find out how many bits the operation should apply to. */ |
| 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; |
| } |
| |
| /* Handles the ASRQ instruction. */ |
| |
| static void |
| asrq_op (unsigned short inst, inst_env_type *inst_env) |
| { |
| |
| int shift_steps; |
| unsigned long value; |
| unsigned long signed_extend_mask = 0; |
| |
| /* ASRQ can't have a prefix, so check that it doesn't. */ |
| if (inst_env->prefix_found) |
| { |
| inst_env->invalid = 1; |
| return; |
| } |
| |
| /* Check if the PC is the target register. */ |
| if (cris_get_operand2 (inst) == REG_PC) |
| { |
| |
| /* It's invalid to change the PC in a delay slot. */ |
| if (inst_env->slot_needed) |
| { |
| inst_env->invalid = 1; |
| return; |
| } |
| /* The shift size is given as a 5 bit quick value, i.e. we don't |
| want the sign bit of the quick value. */ |
| 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; |
| } |
| |
| /* Handles the AX, EI and SETF instruction. */ |
| |
| static void |
| ax_ei_setf_op (unsigned short inst, inst_env_type *inst_env) |
| { |
| if (inst_env->prefix_found) |
| { |
| inst_env->invalid = 1; |
| return; |
| } |
| /* Check if the instruction is setting the X flag. */ |
| 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; |
| } |
| |
| /* Checks if the instruction is in assign mode. If so, it updates the assign |
| register. Note that check_assign assumes that the caller has checked that |
| there is a prefix to this instruction. The mode check depends on this. */ |
| |
| static void |
| check_assign (unsigned short inst, inst_env_type *inst_env) |
| { |
| /* Check if it's an assign addressing mode. */ |
| if (cris_get_mode (inst) == PREFIX_ASSIGN_MODE) |
| { |
| /* Assign the prefix value to operand 1. */ |
| inst_env->reg[cris_get_operand1 (inst)] = inst_env->prefix_value; |
| } |
| } |
| |
| /* Handles the 2-operand BOUND instruction. */ |
| |
| static void |
| two_operand_bound_op (unsigned short inst, inst_env_type *inst_env) |
| { |
| /* It's invalid to have the PC as the index operand. */ |
| if (cris_get_operand2 (inst) == REG_PC) |
| { |
| inst_env->invalid = 1; |
| return; |
| } |
| /* Check if we have a prefix. */ |
| if (inst_env->prefix_found) |
| { |
| check_assign (inst, inst_env); |
| } |
| /* Check if this is an autoincrement mode. */ |
| else if (cris_get_mode (inst) == AUTOINC_MODE) |
| { |
| /* It's invalid to change the PC in a delay slot. */ |
| 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; |
| } |
| |
| /* Handles the 3-operand BOUND instruction. */ |
| |
| static void |
| three_operand_bound_op (unsigned short inst, inst_env_type *inst_env) |
| { |
| /* It's an error if we haven't got a prefix. And it's also an error |
| if the PC is the destination register. */ |
| 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; |
| } |
| |
| /* Clears the status flags in inst_env. */ |
| |
| static void |
| btst_nop_op (unsigned short inst, inst_env_type *inst_env) |
| { |
| /* It's an error if we have got a prefix. */ |
| 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; |
| } |
| |
| /* Clears the status flags in inst_env. */ |
| |
| static void |
| clearf_di_op (unsigned short inst, inst_env_type *inst_env) |
| { |
| /* It's an error if we have got a prefix. */ |
| 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; |
| } |
| |
| /* Handles the CLEAR instruction if it's in register mode. */ |
| |
| static void |
| reg_mode_clear_op (unsigned short inst, inst_env_type *inst_env) |
| { |
| /* Check if the target is the PC. */ |
| if (cris_get_operand2 (inst) == REG_PC) |
| { |
| /* The instruction will clear the instruction's size bits. */ |
| 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; |
| } |
| /* The jump will be delayed with one delay slot. So we need a delay |
| slot. */ |
| inst_env->slot_needed = 1; |
| inst_env->delay_slot_pc_active = 1; |
| } |
| else |
| { |
| /* The PC will not change => no delay slot. */ |
| inst_env->slot_needed = 0; |
| } |
| inst_env->prefix_found = 0; |
| inst_env->xflag_found = 0; |
| inst_env->disable_interrupt = 0; |
| } |
| |
| /* Handles the TEST instruction if it's in register mode. */ |
| |
| static void |
| reg_mode_test_op (unsigned short inst, inst_env_type *inst_env) |
| { |
| /* It's an error if we have got a prefix. */ |
| 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; |
| |
| } |
| |
| /* Handles the CLEAR and TEST instruction if the instruction isn't |
| in register mode. */ |
| |
| static void |
| none_reg_mode_clear_test_op (unsigned short inst, inst_env_type *inst_env) |
| { |
| /* Check if we are in a prefix mode. */ |
| if (inst_env->prefix_found) |
| { |
| /* The only way the PC can change is if this instruction is in |
| assign addressing mode. */ |
| check_assign (inst, inst_env); |
| } |
| /* Indirect mode can't change the PC so just check if the mode is |
| autoincrement. */ |
| 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; |
| } |
| |
| /* Checks that the PC isn't the destination register or the instructions has |
| a prefix. */ |
| |
| static void |
| dstep_logshift_mstep_neg_not_op (unsigned short inst, inst_env_type *inst_env) |
| { |
| /* It's invalid to have the PC as the destination. The instruction can't |
| have a prefix. */ |
| 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; |
| } |
| |
| /* Checks that the instruction doesn't have a prefix. */ |
| |
| static void |
| break_op (unsigned short inst, inst_env_type *inst_env) |
| { |
| /* The instruction can't have a prefix. */ |
| 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; |
| } |
| |
| /* Checks that the PC isn't the destination register and that the instruction |
| doesn't have a prefix. */ |
| |
| static void |
| scc_op (unsigned short inst, inst_env_type *inst_env) |
| { |
| /* It's invalid to have the PC as the destination. The instruction can't |
| have a prefix. */ |
| 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; |
| } |
| |
| /* Handles the register mode JUMP instruction. */ |
| |
| static void |
| reg_mode_jump_op (unsigned short inst, inst_env_type *inst_env) |
| { |
| /* It's invalid to do a JUMP in a delay slot. The mode is register, so |
| you can't have a prefix. */ |
| if ((inst_env->slot_needed) || (inst_env->prefix_found)) |
| { |
| inst_env->invalid = 1; |
| return; |
| } |
| |
| /* Just change the PC. */ |
| 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; |
| } |
| |
| /* Handles the JUMP instruction for all modes except register. */ |
| |
| static void |
| none_reg_mode_jump_op (unsigned short inst, inst_env_type *inst_env) |
| { |
| unsigned long newpc; |
| CORE_ADDR address; |
| |
| /* It's invalid to do a JUMP in a delay slot. */ |
| if (inst_env->slot_needed) |
| { |
| inst_env->invalid = 1; |
| } |
| else |
| { |
| /* Check if we have a prefix. */ |
| if (inst_env->prefix_found) |
| { |
| check_assign (inst, inst_env); |
| |
| /* Get the new value for the PC. */ |
| newpc = |
| read_memory_unsigned_integer ((CORE_ADDR) inst_env->prefix_value, |
| 4, inst_env->byte_order); |
| } |
| else |
| { |
| /* Get the new value for the PC. */ |
| address = (CORE_ADDR) inst_env->reg[cris_get_operand1 (inst)]; |
| newpc = read_memory_unsigned_integer (address, |
| 4, inst_env->byte_order); |
| |
| /* Check if we should increment a register. */ |
| 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; |
| } |
| |
| /* Handles moves to special registers (aka P-register) for all modes. */ |
| |
| static void |
| move_to_preg_op (struct gdbarch *gdbarch, unsigned short inst, |
| inst_env_type *inst_env) |
| { |
| if (inst_env->prefix_found) |
| { |
| /* The instruction has a prefix that means we are only interested if |
| the instruction is in assign mode. */ |
| if (cris_get_mode (inst) == PREFIX_ASSIGN_MODE) |
| { |
| /* The prefix handles the problem if we are in a delay slot. */ |
| if (cris_get_operand1 (inst) == REG_PC) |
| { |
| /* Just take care of the assign. */ |
| check_assign (inst, inst_env); |
| } |
| } |
| } |
| else if (cris_get_mode (inst) == AUTOINC_MODE) |
| { |
| /* The instruction doesn't have a prefix, the only case left that we |
| are interested in is the autoincrement mode. */ |
| if (cris_get_operand1 (inst) == REG_PC) |
| { |
| /* If the PC is to be incremented it's invalid to be in a |
| delay slot. */ |
| if (inst_env->slot_needed) |
| { |
| inst_env->invalid = 1; |
| return; |
| } |
| |
| /* The increment depends on the size of the special register. */ |
| if (cris_register_size (gdbarch, cris_get_operand2 (inst)) == 1) |
| { |
| process_autoincrement (INST_BYTE_SIZE, inst, inst_env); |
| } |
| else if (cris_register_size (gdbarch, 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; |
| } |
| |
| /* Handles moves from special registers (aka P-register) for all modes |
| except register. */ |
| |
| static void |
| none_reg_mode_move_from_preg_op (struct gdbarch *gdbarch, unsigned short inst, |
| inst_env_type *inst_env) |
| { |
| if (inst_env->prefix_found) |
| { |
| /* The instruction has a prefix that means we are only interested if |
| the instruction is in assign mode. */ |
| if (cris_get_mode (inst) == PREFIX_ASSIGN_MODE) |
| { |
| /* The prefix handles the problem if we are in a delay slot. */ |
| if (cris_get_operand1 (inst) == REG_PC) |
| { |
| /* Just take care of the assign. */ |
| check_assign (inst, inst_env); |
| } |
| } |
| } |
| /* The instruction doesn't have a prefix, the only case left that we |
| are interested in is the autoincrement mode. */ |
| else if (cris_get_mode (inst) == AUTOINC_MODE) |
| { |
| if (cris_get_operand1 (inst) == REG_PC) |
| { |
| /* If the PC is to be incremented it's invalid to be in a |
| delay slot. */ |
| if (inst_env->slot_needed) |
| { |
| inst_env->invalid = 1; |
| return; |
| } |
| |
| /* The increment depends on the size of the special register. */ |
| if (cris_register_size (gdbarch, cris_get_operand2 (inst)) == 1) |
| { |
| process_autoincrement (INST_BYTE_SIZE, inst, inst_env); |
| } |
| else if (cris_register_size (gdbarch, 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; |
| } |
| |
| /* Handles moves from special registers (aka P-register) when the mode |
| is register. */ |
| |
| static void |
| reg_mode_move_from_preg_op (unsigned short inst, inst_env_type *inst_env) |
| { |
| /* Register mode move from special register can't have a prefix. */ |
| if (inst_env->prefix_found) |
| { |
| inst_env->invalid = 1; |
| return; |
| } |
| |
| if (cris_get_operand1 (inst) == REG_PC) |
| { |
| /* It's invalid to change the PC in a delay slot. */ |
| if (inst_env->slot_needed) |
| { |
| inst_env->invalid = 1; |
| return; |
| } |
| /* The destination is the PC, the jump will have a delay slot. */ |
| 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 |
| { |
| /* If the destination isn't PC, there will be no jump. */ |
| inst_env->slot_needed = 0; |
| } |
| inst_env->prefix_found = 0; |
| inst_env->xflag_found = 0; |
| inst_env->disable_interrupt = 1; |
| } |
| |
| /* Handles the MOVEM from memory to general register instruction. */ |
| |
| static void |
| move_mem_to_reg_movem_op (unsigned short inst, inst_env_type *inst_env) |
| { |
| if (inst_env->prefix_found) |
| { |
| /* The prefix handles the problem if we are in a delay slot. Is the |
| MOVEM instruction going to change the PC? */ |
| if (cris_get_operand2 (inst) >= REG_PC) |
| { |
| inst_env->reg[REG_PC] = |
| read_memory_unsigned_integer (inst_env->prefix_value, |
| 4, inst_env->byte_order); |
| } |
| /* The assign value is the value after the increment. Normally, the |
| assign value is the value before the increment. */ |
| 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 |
| { |
| /* Is the MOVEM instruction going to change the PC? */ |
| if (cris_get_operand2 (inst) == REG_PC) |
| { |
| /* It's invalid to change the PC in a delay slot. */ |
| 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, inst_env->byte_order); |
| } |
| /* The increment is not depending on the size, instead it's depending |
| on the number of registers loaded from memory. */ |
| if ((cris_get_operand1 (inst) == REG_PC) |
| && (cris_get_mode (inst) == AUTOINC_MODE)) |
| { |
| /* It's invalid to change the PC in a delay slot. */ |
| 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; |
| } |
| |
| /* Handles the MOVEM to memory from general register instruction. */ |
| |
| static void |
| move_reg_to_mem_movem_op (unsigned short inst, inst_env_type *inst_env) |
| { |
| if (inst_env->prefix_found) |
| { |
| /* The assign value is the value after the increment. Normally, the |
| assign value is the value before the increment. */ |
| if ((cris_get_operand1 (inst) == REG_PC) |
| && (cris_get_mode (inst) == PREFIX_ASSIGN_MODE)) |
| { |
| /* The prefix handles the problem if we are in a delay slot. */ |
| inst_env->reg[REG_PC] = inst_env->prefix_value; |
| inst_env->reg[REG_PC] += 4 * (cris_get_operand2 (inst) + 1); |
| } |
| } |
| else |
| { |
| /* The increment is not depending on the size, instead it's depending |
| on the number of registers loaded to memory. */ |
| if ((cris_get_operand1 (inst) == REG_PC) |
| && (cris_get_mode (inst) == AUTOINC_MODE)) |
| { |
| /* It's invalid to change the PC in a delay slot. */ |
| 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; |
| } |
| |
| /* Handles the instructions that's not yet implemented, by setting |
| inst_env->invalid to true. */ |
| |
| static void |
| not_implemented_op (unsigned short inst, inst_env_type *inst_env) |
| { |
| inst_env->invalid = 1; |
| } |
| |
| /* Handles the XOR instruction. */ |
| |
| static void |
| xor_op (unsigned short inst, inst_env_type *inst_env) |
| { |
| /* XOR can't have a prefix. */ |
| if (inst_env->prefix_found) |
| { |
| inst_env->invalid = 1; |
| return; |
| } |
| |
| /* Check if the PC is the target. */ |
| if (cris_get_operand2 (inst) == REG_PC) |
| { |
| /* It's invalid to change the PC in a delay slot. */ |
| 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; |
| } |
| |
| /* Handles the MULS instruction. */ |
| |
| static void |
| muls_op (unsigned short inst, inst_env_type *inst_env) |
| { |
| /* MULS/U can't have a prefix. */ |
| if (inst_env->prefix_found) |
| { |
| inst_env->invalid = 1; |
| return; |
| } |
| |
| /* Consider it invalid if the PC is the target. */ |
| 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; |
| } |
| |
| /* Handles the MULU instruction. */ |
| |
| static void |
| mulu_op (unsigned short inst, inst_env_type *inst_env) |
| { |
| /* MULS/U can't have a prefix. */ |
| if (inst_env->prefix_found) |
| { |
| inst_env->invalid = 1; |
| return; |
| } |
| |
| /* Consider it invalid if the PC is the target. */ |
| 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; |
| } |
| |
| /* Calculate the result of the instruction for ADD, SUB, CMP AND, OR and MOVE. |
| The MOVE instruction is the move from source to register. */ |
| |
| 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; |
| |
| /* Find out how many bits the operation should apply to. */ |
| 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 |
| { |
| /* The size is out of range. */ |
| inst_env->invalid = 1; |
| return; |
| } |
| |
| /* The instruction just works on uw_operation_mask bits. */ |
| source2 &= operation_mask; |
| source1 &= operation_mask; |
| |
| /* Now calculate the result. The opcode's 3 first bits separates |
| the different actions. */ |
| switch (cris_get_opcode (inst) & 7) |
| { |
| case 0: /* add */ |
| source1 += source2; |
| break; |
| |
| case 1: /* move */ |
| source1 = source2; |
| break; |
| |
| case 2: /* subtract */ |
| source1 -= source2; |
| break; |
| |
| case 3: /* compare */ |
| break; |
| |
| case 4: /* and */ |
| source1 &= source2; |
| break; |
| |
| case 5: /* or */ |
| source1 |= source2; |
| break; |
| |
| default: |
| inst_env->invalid = 1; |
| return; |
| |
| break; |
| } |
| |
| /* Make sure that the result doesn't contain more than the instruction |
| size bits. */ |
| source2 &= operation_mask; |
| |
| /* Calculate the new breakpoint address. */ |
| inst_env->reg[REG_PC] &= pc_mask; |
| inst_env->reg[REG_PC] |= source1; |
| |
| } |
| |
| /* Extends the value from either byte or word size to a dword. If the mode |
| is zero extend then the value is extended with zero. If instead the mode |
| is signed extend the sign bit of the value is taken into consideration. */ |
| |
| static unsigned |