aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authornobody <>2002-09-17 20:42:02 +0000
committernobody <>2002-09-17 20:42:02 +0000
commitc80c4635cedcdb1cb2efa481eceda2b69cc8cbd7 (patch)
tree4cc86b964e683ac5ff944eae7d5ca48ed02a8014
parent047807b33f6355af51cd2481644d5b9a5757406d (diff)
downloadfsf-binutils-gdb-c80c4635cedcdb1cb2efa481eceda2b69cc8cbd7.zip
fsf-binutils-gdb-c80c4635cedcdb1cb2efa481eceda2b69cc8cbd7.tar.gz
fsf-binutils-gdb-c80c4635cedcdb1cb2efa481eceda2b69cc8cbd7.tar.bz2
This commit was manufactured by cvs2svn to create branch
'carlton_dictionary-branch'. Cherrypick from gdb_5_3-branch 2002-09-03 22:29:15 UTC nobody 'This commit was manufactured by cvs2svn to create branch 'gdb_5_3-branch'.': gdb/ns32k-tdep.c gdb/sh3-rom.c gdb/vax-tdep.c Cherrypick from master 2002-09-17 20:42:01 UTC Andrew Cagney <cagney@redhat.com> '2002-09-17 Andrew Cagney <cagney@redhat.com>': gdb/cris-tdep.c gdb/mcore-tdep.c
-rw-r--r--gdb/cris-tdep.c4348
-rw-r--r--gdb/mcore-tdep.c1180
-rw-r--r--gdb/ns32k-tdep.c626
-rw-r--r--gdb/sh3-rom.c384
-rw-r--r--gdb/vax-tdep.c702
5 files changed, 7240 insertions, 0 deletions
diff --git a/gdb/cris-tdep.c b/gdb/cris-tdep.c
new file mode 100644
index 0000000..0bfb5b3
--- /dev/null
+++ b/gdb/cris-tdep.c
@@ -0,0 +1,4348 @@
+/* Target dependent code for CRIS, for GDB, the GNU debugger.
+ Copyright 2001 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 2 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, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+#include "defs.h"
+#include "frame.h"
+#include "symtab.h"
+#include "inferior.h"
+#include "gdbtypes.h"
+#include "gdbcore.h"
+#include "gdbcmd.h"
+#include "target.h"
+#include "value.h"
+#include "opcode/cris.h"
+#include "arch-utils.h"
+#include "regcache.h"
+
+/* To get entry_point_address. */
+#include "symfile.h"
+
+#include "solib.h" /* Support for shared libraries. */
+#include "solib-svr4.h" /* For struct link_map_offsets. */
+
+
+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
+};
+
+/* Register numbers of various important registers.
+ 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.
+ SP_REGNUM Contains address of top of stack.
+ PC_REGNUM Contains address of next instruction.
+ SRP_REGNUM Subroutine return pointer register.
+ BRP_REGNUM Breakpoint return pointer register. */
+
+/* FP_REGNUM = 8, SP_REGNUM = 14, and PC_REGNUM = 15 have been incorporated
+ into the multi-arch framework. */
+
+enum cris_regnums
+{
+ /* Enums with respect to the general registers, valid for all
+ CRIS versions. */
+ STR_REGNUM = 9,
+ RET_REGNUM = 10,
+ ARG1_REGNUM = 10,
+ ARG2_REGNUM = 11,
+ ARG3_REGNUM = 12,
+ ARG4_REGNUM = 13,
+
+ /* Enums with respect to the special registers, some of which may not be
+ applicable to all CRIS versions. */
+ P0_REGNUM = 16,
+ VR_REGNUM = 17,
+ P2_REGNUM = 18,
+ P3_REGNUM = 19,
+ P4_REGNUM = 20,
+ CCR_REGNUM = 21,
+ MOF_REGNUM = 23,
+ P8_REGNUM = 24,
+ IBR_REGNUM = 25,
+ IRP_REGNUM = 26,
+ SRP_REGNUM = 27,
+ BAR_REGNUM = 28,
+ DCCR_REGNUM = 29,
+ BRP_REGNUM = 30,
+ USP_REGNUM = 31
+};
+
+extern const struct cris_spec_reg cris_spec_regs[];
+
+/* CRIS version, set via the user command 'set cris-version'. Affects
+ register names and sizes.*/
+static int usr_cmd_cris_version;
+
+/* Indicates whether to trust the above variable. */
+static int usr_cmd_cris_version_valid = 0;
+
+/* CRIS mode, set via the user command 'set cris-mode'. Affects availability
+ of some registers. */
+static const char *usr_cmd_cris_mode;
+
+/* Indicates whether to trust the above variable. */
+static int usr_cmd_cris_mode_valid = 0;
+
+static const char CRIS_MODE_USER[] = "CRIS_MODE_USER";
+static const char CRIS_MODE_SUPERVISOR[] = "CRIS_MODE_SUPERVISOR";
+static const char *cris_mode_enums[] =
+{
+ CRIS_MODE_USER,
+ CRIS_MODE_SUPERVISOR,
+ 0
+};
+
+/* CRIS ABI, set via the user command 'set cris-abi'.
+ There are two flavours:
+ 1. Original ABI with 32-bit doubles, where arguments <= 4 bytes are
+ passed by value.
+ 2. New ABI with 64-bit doubles, where arguments <= 8 bytes are passed by
+ value. */
+static const char *usr_cmd_cris_abi;
+
+/* Indicates whether to trust the above variable. */
+static int usr_cmd_cris_abi_valid = 0;
+
+/* These variables are strings instead of enums to make them usable as
+ parameters to add_set_enum_cmd. */
+static const char CRIS_ABI_ORIGINAL[] = "CRIS_ABI_ORIGINAL";
+static const char CRIS_ABI_V2[] = "CRIS_ABI_V2";
+static const char CRIS_ABI_SYMBOL[] = ".$CRIS_ABI_V2";
+static const char *cris_abi_enums[] =
+{
+ CRIS_ABI_ORIGINAL,
+ CRIS_ABI_V2,
+ 0
+};
+
+/* CRIS architecture specific information. */
+struct gdbarch_tdep
+{
+ int cris_version;
+ const char *cris_mode;
+ const char *cris_abi;
+};
+
+/* Functions for accessing target dependent data. */
+
+static int
+cris_version (void)
+{
+ return (gdbarch_tdep (current_gdbarch)->cris_version);
+}
+
+static const char *
+cris_mode (void)
+{
+ return (gdbarch_tdep (current_gdbarch)->cris_mode);
+}
+
+static const char *
+cris_abi (void)
+{
+ return (gdbarch_tdep (current_gdbarch)->cris_abi);
+}
+
+/* For saving call-clobbered contents in R9 when returning structs. */
+static CORE_ADDR struct_return_address;
+
+struct frame_extra_info
+{
+ CORE_ADDR return_pc;
+ int leaf_function;
+};
+
+/* 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;
+} inst_env_type;
+
+/* Save old breakpoints in order to restore the state before a single_step.
+ At most, two breakpoints will have to be remembered. */
+typedef
+char binsn_quantum[BREAKPOINT_MAX];
+static binsn_quantum break_mem[2];
+static CORE_ADDR next_pc = 0;
+static CORE_ADDR branch_target_address = 0;
+static unsigned char branch_break_inserted = 0;
+
+/* 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_wide_opcode (unsigned short insn)
+{
+ return ((insn & 0x03E0) >> 5);
+}
+
+static int
+cris_get_short_size (unsigned short insn)
+{
+ return ((insn & 0x0010) >> 4);
+}
+
+static int
+cris_get_quick_value (unsigned short insn)
+{
+ return (insn & 0x003F);
+}
+
+static int
+cris_get_bdap_quick_offset (unsigned short insn)
+{
+ return (insn & 0x00FF);
+}
+
+static int
+cris_get_branch_short_offset (unsigned short insn)
+{
+ return (insn & 0x00FF);
+}
+
+static int
+cris_get_asr_shift_steps (unsigned long value)
+{
+ return (value & 0x3F);
+}
+
+static int
+cris_get_asr_quick_shift_steps (unsigned short insn)
+{
+ return (insn & 0x1F);
+}
+
+static int
+cris_get_clear_size (unsigned short insn)
+{
+ return ((insn) & 0xC000);
+}
+
+static int
+cris_is_signed_extend_bit_on (unsigned short insn)
+{
+ return (((insn) & 0x20) == 0x20);
+}
+
+static int
+cris_is_xflag_bit_on (unsigned short insn)
+{
+ return (((insn) & 0x1000) == 0x1000);
+}
+
+static void
+cris_set_size_to_dword (unsigned short *insn)
+{
+ *insn &= 0xFFCF;
+ *insn |= 0x20;
+}
+
+static signed char
+cris_get_signed_offset (unsigned short insn)
+{
+ return ((signed char) (insn & 0x00FF));
+}
+
+/* Calls an op function given the op-type, working on the insn and the
+ inst_env. */
+static void cris_gdb_func (enum cris_op_type, unsigned short, inst_env_type *);
+
+static CORE_ADDR cris_skip_prologue_main (CORE_ADDR pc, int frameless_p);
+
+static struct gdbarch *cris_gdbarch_init (struct gdbarch_info,
+ struct gdbarch_list *);
+
+static int cris_delayed_get_disassembler (bfd_vma, disassemble_info *);
+
+static void cris_dump_tdep (struct gdbarch *, struct ui_file *);
+
+static void cris_version_update (char *ignore_args, int from_tty,
+ struct cmd_list_element *c);
+
+static void cris_mode_update (char *ignore_args, int from_tty,
+ struct cmd_list_element *c);
+
+static void cris_abi_update (char *ignore_args, int from_tty,
+ struct cmd_list_element *c);
+
+static CORE_ADDR bfd_lookup_symbol (bfd *, const char *);
+
+/* Frames information. The definition of the struct frame_info is
+
+ CORE_ADDR frame
+ CORE_ADDR pc
+ int signal_handler_caller
+ 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 signal_handler_caller is non-zero when the frame is
+ associated with the call of a signal handler.
+
+ 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). */
+
+CORE_ADDR
+cris_examine (CORE_ADDR ip, CORE_ADDR limit, struct frame_info *fi,
+ int frameless_p)
+{
+ /* Present instruction. */
+ unsigned short insn;
+
+ /* Next instruction, lookahead. */
+ unsigned short insn_next;
+ int regno;
+
+ /* Is there a push fp? */
+ int have_fp;
+
+ /* 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;
+
+ /* This frame is with respect to a leaf until a push srp is found. */
+ fi->extra_info->leaf_function = 1;
+
+ /* This frame is without the FP until a push fp is found. */
+ have_fp = 0;
+
+ /* Assume nothing on stack. */
+ val = 0;
+ regsave = -1;
+
+ /* No information about register contents so far. */
+
+ /* We only want to know the end of the prologue when fi->saved_regs == 0.
+ When the saved registers are allocated full information is required. */
+ if (fi->saved_regs)
+ {
+ for (regno = 0; regno < NUM_REGS; regno++)
+ fi->saved_regs[regno] = 0;
+ }
+
+ /* Find the prologue instructions. */
+ do
+ {
+ insn = read_memory_unsigned_integer (ip, sizeof (short));
+ ip += sizeof (short);
+ if (insn == 0xE1FC)
+ {
+ /* push <reg> 32 bit instruction */
+ insn_next = read_memory_unsigned_integer (ip, sizeof (short));
+ ip += sizeof (short);
+ regno = cris_get_operand2 (insn_next);
+
+ /* This check, meant to recognize srp, used to be regno ==
+ (SRP_REGNUM - NUM_GENREGS), but that covers r11 also. */
+ if (insn_next == 0xBE7E)
+ {
+ if (frameless_p)
+ {
+ return ip;
+ }
+ fi->extra_info->leaf_function = 0;
+ }
+ else if (regno == FP_REGNUM)
+ {
+ have_fp = 1;
+ }
+ }
+ else if (insn == 0x866E)
+ {
+ /* move.d sp,r8 */
+ if (frameless_p)
+ {
+ return ip;
+ }
+ continue;
+ }
+ else if (cris_get_operand2 (insn) == SP_REGNUM
+ && cris_get_mode (insn) == 0x0000
+ && cris_get_opcode (insn) == 0x000A)
+ {
+ /* subq <val>,sp */
+ val = cris_get_quick_value (insn);
+ }
+ else if (cris_get_mode (insn) == 0x0002
+ && cris_get_opcode (insn) == 0x000F
+ && cris_get_size (insn) == 0x0003
+ && cris_get_operand1 (insn) == SP_REGNUM)
+ {
+ /* movem r<regsave>,[sp] */
+ if (frameless_p)
+ {
+ return ip;
+ }
+ regsave = cris_get_operand2 (insn);
+ }
+ else if (cris_get_operand2 (insn) == SP_REGNUM
+ && ((insn & 0x0F00) >> 8) == 0x0001
+ && (cris_get_signed_offset (insn) < 0))
+ {
+ /* 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>] */
+ val = -cris_get_signed_offset (insn);
+ insn_next = read_memory_unsigned_integer (ip, sizeof (short));
+ ip += sizeof (short);
+ if (cris_get_mode (insn_next) == PREFIX_ASSIGN_MODE
+ && cris_get_opcode (insn_next) == 0x000F
+ && cris_get_size (insn_next) == 0x0003
+ && cris_get_operand1 (insn_next) == SP_REGNUM)
+ {
+ if (frameless_p)
+ {
+ return ip;
+ }
+ regsave = cris_get_operand2 (insn_next);
+ }
+ else
+ {
+ /* The prologue ended before the limit was reached. */
+ ip -= 2 * sizeof (short);
+ 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> */
+ if (frameless_p)
+ {
+ return ip;
+ }
+ 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. */
+ ip -= sizeof (short);
+ break;
+ }
+ }
+ else if (cris_get_operand2 (insn) == 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 (ip, sizeof (short));
+ ip += sizeof (short);
+ regno = cris_get_operand2 (insn_next);
+ if ((regno >= 0 && regno < SP_REGNUM)
+ && cris_get_mode (insn_next) == PREFIX_OFFSET_MODE
+ && cris_get_opcode (insn_next) == 0x000F)
+ {
+ /* move.S rZ,[r8-U] */
+ continue;
+ }
+ else
+ {
+ /* The prologue ended before the limit was reached. */
+ ip -= 2 * sizeof (short);
+ break;
+ }
+ }
+ else if (cris_get_operand2 (insn) == 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 (ip, sizeof (short));
+ ip += sizeof (short);
+ regno = cris_get_operand2 (insn_next);
+ if ((regno >= 0 && regno < SP_REGNUM)
+ && cris_get_mode (insn_next) == PREFIX_OFFSET_MODE
+ && cris_get_opcode (insn_next) == 0x0009
+ && cris_get_operand1 (insn_next) == regno)
+ {
+ /* move.S [r8+U],rZ */
+ continue;
+ }
+ else
+ {
+ /* The prologue ended before the limit was reached. */
+ ip -= 2 * sizeof (short);
+ break;
+ }
+ }
+ else
+ {
+ /* The prologue ended before the limit was reached. */
+ ip -= sizeof (short);
+ break;
+ }
+ }
+ while (ip < limit);
+
+ /* We only want to know the end of the prologue when
+ fi->saved_regs == 0. */
+ if (!fi->saved_regs)
+ return ip;
+
+ if (have_fp)
+ {
+ fi->saved_regs[FP_REGNUM] = FRAME_FP (fi);
+
+ /* Calculate the addresses. */
+ for (regno = regsave; regno >= 0; regno--)
+ {
+ fi->saved_regs[regno] = FRAME_FP (fi) - val;
+ val -= 4;
+ }
+ if (fi->extra_info->leaf_function)
+ {
+ /* Set the register SP to contain the stack pointer of
+ the caller. */
+ fi->saved_regs[SP_REGNUM] = FRAME_FP (fi) + 4;
+ }
+ else
+ {
+ /* Set the register SP to contain the stack pointer of
+ the caller. */
+ fi->saved_regs[SP_REGNUM] = FRAME_FP (fi) + 8;
+
+ /* Set the register SRP to contain the return address of
+ the caller. */
+ fi->saved_regs[SRP_REGNUM] = FRAME_FP (fi) + 4;
+ }
+ }
+ return ip;
+}
+
+/* Advance pc beyond any function entry prologue instructions at pc
+ to reach some "real" code. */
+
+CORE_ADDR
+cris_skip_prologue (CORE_ADDR pc)
+{
+ return cris_skip_prologue_main (pc, 0);
+}
+
+/* As cris_skip_prologue, but stops as soon as it knows that the function
+ has a frame. Its result is equal to its input pc if the function is
+ frameless, unequal otherwise. */
+
+CORE_ADDR
+cris_skip_prologue_frameless_p (CORE_ADDR pc)
+{
+ return cris_skip_prologue_main (pc, 1);
+}
+
+/* Given a PC value corresponding to the start of a function, return the PC
+ of the first instruction after the function prologue. */
+
+CORE_ADDR
+cris_skip_prologue_main (CORE_ADDR pc, int frameless_p)
+{
+ struct frame_info fi;
+ static struct frame_extra_info fei;
+ struct symtab_and_line sal = find_pc_line (pc, 0);
+ int best_limit;
+ CORE_ADDR pc_after_prologue;
+
+ /* frame_info now contains dynamic memory. Since fi is a dummy here,
+ I use static memory for extra_info, and don't bother allocating
+ memory for saved_regs. */
+ fi.saved_regs = 0;
+ fi.extra_info = &fei;
+
+ /* If there is no symbol information then sal.end == 0, and we end up
+ examining only the first instruction in the function prologue.
+ Exaggerating the limit seems to be harmless. */
+ if (sal.end > 0)
+ best_limit = sal.end;
+ else
+ best_limit = pc + 100;
+
+ pc_after_prologue = cris_examine (pc, best_limit, &fi, frameless_p);
+ return pc_after_prologue;
+}
+
+/* Use the program counter to determine the contents and size of a breakpoint
+ instruction. It returns a pointer to a string of bytes that encode a
+ breakpoint instruction, stores the length of the string to *lenptr, and
+ adjusts pcptr (if necessary) to point to the actual memory location where
+ the breakpoint should be inserted. */
+
+const unsigned char *
+cris_breakpoint_from_pc (CORE_ADDR *pcptr, int *lenptr)
+{
+ static unsigned char break_insn[] = {0x38, 0xe9};
+ *lenptr = 2;
+
+ return break_insn;
+}
+
+/* Returns the register SRP (subroutine return pointer) which must contain
+ the content of the register PC after a function call. */
+
+static CORE_ADDR
+cris_saved_pc_after_call (struct frame_info *frame)
+{
+ return read_register (SRP_REGNUM);
+}
+
+/* Returns 1 if spec_reg is applicable to the current gdbarch's CRIS version,
+ 0 otherwise. */
+
+int
+cris_spec_reg_applicable (struct cris_spec_reg spec_reg)
+{
+ int version = cris_version ();
+
+ switch (spec_reg.applicable_version)
+ {
+ case cris_ver_version_all:
+ return 1;
+ case cris_ver_warning:
+ /* Indeterminate/obsolete. */
+ return 0;
+ case cris_ver_sim:
+ /* Simulator only. */
+ return 0;
+ case cris_ver_v0_3:
+ return (version >= 0 && version <= 3);
+ case cris_ver_v3p:
+ return (version >= 3);
+ case cris_ver_v8:
+ return (version == 8 || version == 9);
+ case cris_ver_v8p:
+ return (version >= 8);
+ case cris_ver_v10p:
+ return (version >= 10);
+ default:
+ /* Invalid cris version. */
+ return 0;
+ }
+}
+
+/* Returns the register size in unit byte. Returns 0 for an unimplemented
+ register, -1 for an invalid register. */
+
+int
+cris_register_size (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_REGS)
+ {
+ /* Special register (R16 - R31). cris_spec_regs is zero-based.
+ Adjust regno accordingly. */
+ spec_regno = regno - NUM_GENREGS;
+
+ /* The entries in cris_spec_regs are stored in register number order,
+ which means we can shortcut into the array when searching it. */
+ for (i = spec_regno; cris_spec_regs[i].name != NULL; i++)
+ {
+ if (cris_spec_regs[i].number == spec_regno
+ && cris_spec_reg_applicable (cris_spec_regs[i]))
+ /* Go with the first applicable register. */
+ return cris_spec_regs[i].reg_size;
+ }
+ /* Special register not applicable to this CRIS version. */
+ return 0;
+ }
+ else
+ {
+ /* Invalid register. */
+ return -1;
+ }
+}
+
+/* Nonzero if regno should not be fetched from the target. This is the case
+ for unimplemented (size 0) and non-existant registers. */
+
+int
+cris_cannot_fetch_register (int regno)
+{
+ return ((regno < 0 || regno >= NUM_REGS)
+ || (cris_register_size (regno) == 0));
+}
+
+/* Nonzero if regno should not be written to the target, for various
+ reasons. */
+
+int
+cris_cannot_store_register (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 >= NUM_REGS || cris_register_size (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;
+
+ else if (cris_mode () == CRIS_MODE_USER)
+ {
+ if (regno == IBR_REGNUM || regno == BAR_REGNUM || regno == BRP_REGNUM
+ || regno == IRP_REGNUM)
+ /* Read-only in user mode. */
+ return 1;
+ }
+
+ return 0;
+}
+
+/* Returns the register offset for the first byte of register regno's space
+ in the saved register state. Returns -1 for an invalid or unimplemented
+ register. */
+
+int
+cris_register_offset (int regno)
+{
+ int i;
+ int reg_size;
+ int offset = 0;
+
+ if (regno >= 0 && regno < NUM_REGS)
+ {
+ /* FIXME: The offsets should be cached and calculated only once,
+ when the architecture being debugged has changed. */
+ for (i = 0; i < regno; i++)
+ offset += cris_register_size (i);
+
+ return offset;
+ }
+ else
+ {
+ /* Invalid register. */
+ return -1;
+ }
+}
+
+/* Return the GDB type (defined in gdbtypes.c) for the "standard" data type
+ of data in register regno. */
+
+struct type *
+cris_register_virtual_type (int regno)
+{
+ if (regno == SP_REGNUM || regno == PC_REGNUM
+ || (regno > P8_REGNUM && regno < USP_REGNUM))
+ {
+ /* SP, PC, IBR, IRP, SRP, BAR, DCCR, BRP */
+ return lookup_pointer_type (builtin_type_void);
+ }
+ else if (regno == P8_REGNUM || regno == USP_REGNUM
+ || (regno >= 0 && regno < SP_REGNUM))
+ {
+ /* R0 - R13, P8, P15 */
+ return builtin_type_unsigned_long;
+ }
+ else if (regno > P3_REGNUM && regno < P8_REGNUM)
+ {
+ /* P4, CCR, DCR0, DCR1 */
+ return builtin_type_unsigned_short;
+ }
+ else if (regno > PC_REGNUM && regno < P4_REGNUM)
+ {
+ /* P0, P1, P2, P3 */
+ return builtin_type_unsigned_char;
+ }
+ else
+ {
+ /* Invalid register. */
+ return builtin_type_void;
+ }
+}
+
+/* Stores a function return value of type type, where valbuf is the address
+ of the value to be stored. */
+
+/* In the original CRIS ABI, R10 is used to store return values. */
+
+void
+cris_abi_original_store_return_value (struct type *type, char *valbuf)
+{
+ int len = TYPE_LENGTH (type);
+
+ if (len <= REGISTER_SIZE)
+ write_register_bytes (REGISTER_BYTE (RET_REGNUM), valbuf, len);
+ else
+ internal_error (__FILE__, __LINE__, "cris_abi_original_store_return_value: type length too large.");
+}
+
+/* In the CRIS ABI V2, R10 and R11 are used to store return values. */
+
+void
+cris_abi_v2_store_return_value (struct type *type, char *valbuf)
+{
+ int len = TYPE_LENGTH (type);
+
+ if (len <= 2 * REGISTER_SIZE)
+ {
+ /* Note that this works since R10 and R11 are consecutive registers. */
+ write_register_bytes (REGISTER_BYTE (RET_REGNUM), valbuf, len);
+ }
+ else
+ internal_error (__FILE__, __LINE__, "cris_abi_v2_store_return_value: type length too large.");
+}
+
+/* Return the name of register regno as a string. Return NULL for an invalid or
+ unimplemented register. */
+
+const char *
+cris_register_name (int regno)
+{
+ static char *cris_genreg_names[] =
+ { "r0", "r1", "r2", "r3", \
+ "r4", "r5", "r6", "r7", \
+ "r8", "r9", "r10", "r11", \
+ "r12", "r13", "sp", "pc" };
+
+ int i;
+ int spec_regno;
+
+ if (regno >= 0 && regno < NUM_GENREGS)
+ {
+ /* General register. */
+ return cris_genreg_names[regno];
+ }
+ else if (regno >= NUM_GENREGS && regno < NUM_REGS)
+ {
+ /* Special register (R16 - R31). cris_spec_regs is zero-based.
+ Adjust regno accordingly. */
+ spec_regno = regno - NUM_GENREGS;
+
+ /* The entries in cris_spec_regs are stored in register number order,
+ which means we can shortcut into the array when searching it. */
+ for (i = spec_regno; cris_spec_regs[i].name != NULL; i++)
+ {
+ if (cris_spec_regs[i].number == spec_regno
+ && cris_spec_reg_applicable (cris_spec_regs[i]))
+ /* Go with the first applicable register. */
+ return cris_spec_regs[i].name;
+ }
+ /* Special register not applicable to this CRIS version. */
+ return NULL;
+ }
+ else
+ {
+ /* Invalid register. */
+ return NULL;
+ }
+}
+
+int
+cris_register_bytes_ok (long bytes)
+{
+ return (bytes == REGISTER_BYTES);
+}
+
+/* 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 original CRIS ABI, R10 is used to return values. */
+
+void
+cris_abi_original_extract_return_value (struct type *type, char *regbuf,
+ char *valbuf)
+{
+ int len = TYPE_LENGTH (type);
+
+ if (len <= REGISTER_SIZE)
+ memcpy (valbuf, regbuf + REGISTER_BYTE (RET_REGNUM), len);
+ else
+ internal_error (__FILE__, __LINE__, "cris_abi_original_extract_return_value: type length too large");
+}
+
+/* In the CRIS ABI V2, R10 and R11 are used to store return values. */
+
+void
+cris_abi_v2_extract_return_value (struct type *type, char *regbuf,
+ char *valbuf)
+{
+ int len = TYPE_LENGTH (type);
+
+ if (len <= 2 * REGISTER_SIZE)
+ memcpy (valbuf, regbuf + REGISTER_BYTE (RET_REGNUM), len);
+ else
+ internal_error (__FILE__, __LINE__, "cris_abi_v2_extract_return_value: type length too large");
+}
+
+/* Store the address of the place in which to copy the structure the
+ subroutine will return. In the CRIS ABI, R9 is used in order to pass
+ the address of the allocated area where a structure return value must
+ be stored. R9 is call-clobbered, which means we must save it here for
+ later use. */
+
+void
+cris_store_struct_return (CORE_ADDR addr, CORE_ADDR sp)
+{
+ write_register (STR_REGNUM, addr);
+ struct_return_address = addr;
+}
+
+/* Extract from regbuf the address where a function should return a
+ structure value. It's not there in the CRIS ABI, so we must do it another
+ way. */
+
+CORE_ADDR
+cris_extract_struct_value_address (char *regbuf)
+{
+ return struct_return_address;
+}
+
+/* Returns 1 if a value of the given type being returned from a function
+ must have space allocated for it on the stack. gcc_p is true if the
+ function being considered is known to have been compiled by GCC.
+ In the CRIS ABI, structure return values are passed to the called
+ function by reference in register R9 to a caller-allocated area, so
+ this is always true. */
+
+int
+cris_use_struct_convention (int gcc_p, struct type *type)
+{
+ return 1;
+}
+
+/* Returns 1 if the given type will be passed by pointer rather than
+ directly. */
+
+/* In the original CRIS ABI, arguments shorter than or equal to 32 bits are
+ passed by value. */
+
+int
+cris_abi_original_reg_struct_has_addr (int gcc_p, struct type *type)
+{
+ return (TYPE_LENGTH (type) > 4);
+}
+
+/* In the CRIS ABI V2, arguments shorter than or equal to 64 bits are passed
+ by value. */
+
+int
+cris_abi_v2_reg_struct_has_addr (int gcc_p, struct type *type)
+{
+ return (TYPE_LENGTH (type) > 8);
+}
+
+/* Returns 1 if the function invocation represented by fi does not have a
+ stack frame associated with it. Otherwise return 0. */
+
+int
+cris_frameless_function_invocation (struct frame_info *fi)
+{
+ if (fi->signal_handler_caller)
+ return 0;
+ else
+ return frameless_look_for_prologue (fi);
+}
+
+/* See frame.h. Determines the address of all registers in the current stack
+ frame storing each in frame->saved_regs. Space for frame->saved_regs shall
+ be allocated by FRAME_INIT_SAVED_REGS using either frame_saved_regs_zalloc
+ or frame_obstack_alloc. */
+
+void
+cris_frame_init_saved_regs (struct frame_info *fi)
+{
+ CORE_ADDR ip;
+ struct symtab_and_line sal;
+ int best_limit;
+ char *dummy_regs = deprecated_generic_find_dummy_frame (fi->pc, fi->frame);
+
+ /* Examine the entire prologue. */
+ register int frameless_p = 0;
+
+ /* Has this frame's registers already been initialized? */
+ if (fi->saved_regs)
+ return;
+
+ frame_saved_regs_zalloc (fi);
+
+ if (dummy_regs)
+ {
+ /* I don't see this ever happening, considering the context in which
+ cris_frame_init_saved_regs is called (always when we're not in
+ a dummy frame). */
+ memcpy (&fi->saved_regs, dummy_regs, sizeof (fi->saved_regs));
+ }
+ else
+ {
+ ip = get_pc_function_start (fi->pc);
+ sal = find_pc_line (ip, 0);
+
+ /* If there is no symbol information then sal.end == 0, and we end up
+ examining only the first instruction in the function prologue.
+ Exaggerating the limit seems to be harmless. */
+ if (sal.end > 0)
+ best_limit = sal.end;
+ else
+ best_limit = ip + 100;
+
+ cris_examine (ip, best_limit, fi, frameless_p);
+ }
+}
+
+/* Initialises the extra frame information at the creation of a new frame.
+ The inparameter fromleaf is 0 when the call is from create_new_frame.
+ When the call is from get_prev_frame_info, fromleaf is determined by
+ cris_frameless_function_invocation. */
+
+void
+cris_init_extra_frame_info (int fromleaf, struct frame_info *fi)
+{
+ if (fi->next)
+ {
+ /* Called from get_prev_frame. */
+ fi->pc = FRAME_SAVED_PC (fi->next);
+ }
+
+ fi->extra_info = (struct frame_extra_info *)
+ frame_obstack_alloc (sizeof (struct frame_extra_info));
+
+ fi->extra_info->return_pc = 0;
+ fi->extra_info->leaf_function = 0;
+
+ if (PC_IN_CALL_DUMMY (fi->pc, fi->frame, fi->frame))
+ {
+ /* We need to setup fi->frame here because run_stack_dummy gets it wrong
+ by assuming it's always FP. */
+ fi->frame = deprecated_read_register_dummy (fi->pc, fi->frame,
+ SP_REGNUM);
+ fi->extra_info->return_pc =
+ deprecated_read_register_dummy (fi->pc, fi->frame, PC_REGNUM);
+
+ /* FIXME: Is this necessarily true? */
+ fi->extra_info->leaf_function = 0;
+ }
+ else
+ {
+ cris_frame_init_saved_regs (fi);
+
+ /* Check fromleaf/frameless_function_invocation. (FIXME) */
+
+ if (fi->saved_regs[SRP_REGNUM] != 0)
+ {
+ /* SRP was saved on the stack; non-leaf function. */
+ fi->extra_info->return_pc =
+ read_memory_integer (fi->saved_regs[SRP_REGNUM],
+ REGISTER_RAW_SIZE (SRP_REGNUM));
+ }
+ else
+ {
+ /* SRP is still in a register; leaf function. */
+ fi->extra_info->return_pc = read_register (SRP_REGNUM);
+ /* FIXME: Should leaf_function be set to 1 here? */
+ fi->extra_info->leaf_function = 1;
+ }
+ }
+}
+
+/* Return the content of the frame pointer in the present frame. In other
+ words, determine the address of the calling function's frame. */
+
+CORE_ADDR
+cris_frame_chain (struct frame_info *fi)
+{
+ if (PC_IN_CALL_DUMMY (fi->pc, fi->frame, fi->frame))
+ {
+ return fi->frame;
+ }
+ else if (!inside_entry_file (fi->pc))
+ {
+ return read_memory_unsigned_integer (FRAME_FP (fi), 4);
+ }
+ else
+ {
+ return 0;
+ }
+}
+
+/* Return the saved PC (which equals the return address) of this frame. */
+
+CORE_ADDR
+cris_frame_saved_pc (struct frame_info *fi)
+{
+ return fi->extra_info->return_pc;
+}
+
+/* Return the address of the argument block for the frame described
+ by struct frame_info. */
+
+CORE_ADDR
+cris_frame_args_address (struct frame_info *fi)
+{
+ return FRAME_FP (fi);
+}
+
+/* Return the address of the locals block for the frame
+ described by struct frame_info. */
+
+CORE_ADDR
+cris_frame_locals_address (struct frame_info *fi)
+{
+ return FRAME_FP (fi);
+}
+
+/* Setup the function arguments for calling a function in the inferior. */
+
+CORE_ADDR
+cris_abi_original_push_arguments (int nargs, struct value **args,
+ CORE_ADDR sp, int struct_return,
+ CORE_ADDR struct_addr)
+{
+ int stack_alloc;
+ int stack_offset;
+ int argreg;
+ int argnum;
+ struct type *type;
+ int len;
+ CORE_ADDR regval;
+ char *val;
+
+ /* Data and parameters reside in different areas on the stack.
+ Both frame pointers grow toward higher addresses. */
+ CORE_ADDR fp_params;
+ CORE_ADDR fp_data;
+
+ /* 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 (struct_return)
+ {
+ write_register (STR_REGNUM, struct_addr);
+ }
+
+ /* Make sure there's space on the stack. Allocate space for data and a
+ parameter to refer to that data. */
+ for (argnum = 0, stack_alloc = 0; argnum < nargs; argnum++)
+ stack_alloc += (TYPE_LENGTH (VALUE_TYPE (args[argnum])) + REGISTER_SIZE);
+ sp -= stack_alloc;
+ /* We may over-allocate a little here, but that won't hurt anything. */
+
+ /* Initialize stack frame pointers. */
+ fp_params = sp;
+ fp_data = sp + (nargs * REGISTER_SIZE);
+
+ /* Now load as many as possible of the first arguments into
+ registers, and push the rest onto the stack. */
+ argreg = ARG1_REGNUM;
+ stack_offset = 0;
+
+ for (argnum = 0; argnum < nargs; argnum++)
+ {
+ type = VALUE_TYPE (args[argnum]);
+ len = TYPE_LENGTH (type);
+ val = (char *) VALUE_CONTENTS (args[argnum]);
+
+ if (len <= REGISTER_SIZE && argreg <= ARG4_REGNUM)
+ {
+ /* Data fits in a register; put it in the first available
+ register. */
+ write_register (argreg, *(unsigned long *) val);
+ argreg++;
+ }
+ else if (len > REGISTER_SIZE && argreg <= ARG4_REGNUM)
+ {
+ /* Data does not fit in register; pass it on the stack and
+ put its address in the first available register. */
+ write_memory (fp_data, val, len);
+ write_register (argreg, fp_data);
+ fp_data += len;
+ argreg++;
+ }
+ else if (len > REGISTER_SIZE)
+ {
+ /* Data does not fit in register; put both data and
+ parameter on the stack. */
+ write_memory (fp_data, val, len);
+ write_memory (fp_params, (char *) (&fp_data), REGISTER_SIZE);
+ fp_data += len;
+ fp_params += REGISTER_SIZE;
+ }
+ else
+ {
+ /* Data fits in a register, but we are out of registers;
+ put the parameter on the stack. */
+ write_memory (fp_params, val, REGISTER_SIZE);
+ fp_params += REGISTER_SIZE;
+ }
+ }
+
+ return sp;
+}
+
+CORE_ADDR
+cris_abi_v2_push_arguments (int nargs, struct value **args, CORE_ADDR sp,
+ int struct_return, CORE_ADDR struct_addr)
+{
+ int stack_alloc;
+ int stack_offset;
+ int argreg;
+ int argnum;
+
+ CORE_ADDR regval;
+
+ /* The function's arguments and memory allocated by gdb for the arguments to
+ point at reside in separate areas on the stack.
+ Both frame pointers grow toward higher addresses. */
+ CORE_ADDR fp_arg;
+ CORE_ADDR fp_mem;
+
+ /* 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 (struct_return)
+ {
+ write_register (STR_REGNUM, struct_addr);
+ }
+
+ /* Allocate enough to keep things word-aligned on both parts of the
+ stack. */
+ stack_alloc = 0;
+ for (argnum = 0; argnum < nargs; argnum++)
+ {
+ int len;
+ int reg_demand;
+
+ len = TYPE_LENGTH (VALUE_TYPE (args[argnum]));
+ reg_demand = (len / REGISTER_SIZE) + (len % REGISTER_SIZE != 0 ? 1 : 0);
+
+ /* reg_demand * REGISTER_SIZE is the amount of memory we might need to
+ allocate for this argument. 2 * REGISTER_SIZE is the amount of stack
+ space we might need to pass the argument itself (either by value or by
+ reference). */
+ stack_alloc += (reg_demand * REGISTER_SIZE + 2 * REGISTER_SIZE);
+ }
+ sp -= stack_alloc;
+ /* We may over-allocate a little here, but that won't hurt anything. */
+
+ /* Initialize frame pointers. */
+ fp_arg = sp;
+ fp_mem = sp + (nargs * (2 * REGISTER_SIZE));
+
+ /* Now load as many as possible of the first arguments into registers,
+ and push the rest onto the stack. */
+ argreg = ARG1_REGNUM;
+ stack_offset = 0;
+
+ for (argnum = 0; argnum < nargs; argnum++)
+ {
+ int len;
+ char *val;
+ int reg_demand;
+ int i;
+
+ len = TYPE_LENGTH (VALUE_TYPE (args[argnum]));
+ val = (char *) VALUE_CONTENTS (args[argnum]);
+
+ /* How may registers worth of storage do we need for this argument? */
+ reg_demand = (len / REGISTER_SIZE) + (len % REGISTER_SIZE != 0 ? 1 : 0);
+
+ if (len <= (2 * REGISTER_SIZE)
+ && (argreg + reg_demand - 1 <= ARG4_REGNUM))
+ {
+ /* Data passed by value. Fits in available register(s). */
+ for (i = 0; i < reg_demand; i++)
+ {
+ write_register (argreg, *(unsigned long *) val);
+ argreg++;
+ val += REGISTER_SIZE;
+ }
+ }
+ else if (len <= (2 * REGISTER_SIZE) && argreg <= ARG4_REGNUM)
+ {
+ /* 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)
+ {
+ write_register (argreg, *(unsigned long *) val);
+ argreg++;
+ val += REGISTER_SIZE;
+ }
+ else
+ {
+ /* I guess this memory write could write the remaining data
+ all at once instead of in REGISTER_SIZE chunks. */
+ write_memory (fp_arg, val, REGISTER_SIZE);
+ fp_arg += REGISTER_SIZE;
+ val += REGISTER_SIZE;
+ }
+ }
+ }
+ else if (len > (2 * REGISTER_SIZE))
+ {
+ /* Data passed by reference. Put it on the stack. */
+ write_memory (fp_mem, val, len);
+ write_memory (fp_arg, (char *) (&fp_mem), REGISTER_SIZE);
+
+ /* fp_mem need not be word-aligned since it's just a chunk of
+ memory being pointed at. That is, += len would do. */
+ fp_mem += reg_demand * REGISTER_SIZE;
+ fp_arg += REGISTER_SIZE;
+ }
+ else
+ {
+ /* Data passed by value. No available registers. Put it on
+ the stack. */
+ write_memory (fp_arg, val, len);
+
+ /* fp_arg must be word-aligned (i.e., don't += len) to match
+ the function prologue. */
+ fp_arg += reg_demand * REGISTER_SIZE;
+ }
+ }
+
+ return sp;
+}
+
+/* Never put the return address on the stack. The register SRP is pushed
+ by the called function unless it is a leaf-function. Due to the BRP
+ register the PC will change when continue is sent. */
+
+CORE_ADDR
+cris_push_return_address (CORE_ADDR pc, CORE_ADDR sp)
+{
+ write_register (SRP_REGNUM, CALL_DUMMY_ADDRESS ());
+ return sp;
+}
+
+/* Restore the machine to the state it had before the current frame
+ was created. Discard the innermost frame from the stack and restore
+ all saved registers. */
+
+void
+cris_pop_frame (void)
+{
+ register struct frame_info *fi = get_current_frame ();
+ register int regno;
+ register int stack_offset = 0;
+
+ if (PC_IN_CALL_DUMMY (fi->pc, fi->frame, fi->frame))
+ {
+ /* This happens when we hit a breakpoint set at the entry point,
+ when returning from a dummy frame. */
+ generic_pop_dummy_frame ();
+ }
+ else
+ {
+ cris_frame_init_saved_regs (fi);
+
+ /* For each register, the address of where it was saved on entry to
+ the frame now lies in fi->saved_regs[regno], or zero if it was not
+ saved. This includes special registers such as PC and FP saved in
+ special ways in the stack frame. The SP_REGNUM is even more
+ special, the address here is the SP for the next frame, not the
+ address where the SP was saved. */
+
+ /* Restore general registers R0 - R7. They were pushed on the stack
+ after SP was saved. */
+ for (regno = 0; regno < FP_REGNUM; regno++)
+ {
+ if (fi->saved_regs[regno])
+ {
+ write_register (regno,
+ read_memory_integer (fi->saved_regs[regno], 4));
+ }
+ }
+
+ if (fi->saved_regs[FP_REGNUM])
+ {
+ /* Pop the frame pointer (R8). It was pushed before SP
+ was saved. */
+ write_register (FP_REGNUM,
+ read_memory_integer (fi->saved_regs[FP_REGNUM], 4));
+ stack_offset += 4;
+
+ /* Not a leaf function. */
+ if (fi->saved_regs[SRP_REGNUM])
+ {
+ /* SRP was pushed before SP was saved. */
+ stack_offset += 4;
+ }
+
+ /* Restore the SP and adjust for R8 and (possibly) SRP. */
+ write_register (SP_REGNUM, fi->saved_regs[FP_REGNUM] + stack_offset);
+ }
+ else
+ {
+ /* Currently, we can't get the correct info into fi->saved_regs
+ without a frame pointer. */
+ }
+
+ /* Restore the PC. */
+ write_register (PC_REGNUM, fi->extra_info->return_pc);
+ }
+ flush_cached_frames ();
+}
+
+/* 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 signed char *inst_args,
+ inst_env_type *inst_env)
+{
+ int retval = 0;
+ int tmp, i;
+
+ const char *s = inst_args;
+
+ for (; *s; s++)
+ switch (*s)
+ {
+ case 'm':
+ if ((insn & 0x30) == 0x30)
+ return -1;
+ break;
+
+ case 'S':
+ /* 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))
+ {
+ 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 (inst_env_type *inst_env)
+{
+ int i;
+ int offset;
+ unsigned short insn;
+
+ /* Create a local register image and set the initial state. */
+ for (i = 0; i < NUM_GENREGS; i++)
+ {
+ inst_env->reg[i] = (unsigned long) read_register (i);
+ }
+ offset = NUM_GENREGS;
+ for (i = 0; i < NUM_SPECREGS; i++)
+ {
+ inst_env->preg[i] = (unsigned long) read_register (offset + i);
+ }
+ inst_env->branch_found = 0;
+ inst_env->slot_needed = 0;
+ inst_env->delay_slot_pc_active = 0;
+ inst_env->prefix_found = 0;
+ inst_env->invalid = 0;
+ inst_env->xflag_found = 0;
+ inst_env->disable_interrupt = 0;
+
+ /* Look for a step target. */
+ do
+ {
+ /* Read an instruction from the client. */
+ insn = read_memory_unsigned_integer (inst_env->reg[PC_REGNUM], 2);
+
+ /* 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[PC_REGNUM] += 2;
+ }
+ else
+ {
+ inst_env->delay_slot_pc_active = 0;
+ inst_env->reg[PC_REGNUM] = 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 (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. */
+
+void
+cris_software_single_step (enum target_signal ignore, int insert_breakpoints)
+{
+ inst_env_type inst_env;
+
+ if (insert_breakpoints)
+ {
+ /* Analyse the present instruction environment and insert
+ breakpoints. */
+ int status = find_step_target (&inst_env);
+ if (status == -1)
+ {
+ /* Could not find a target. FIXME: Should do something. */
+ }
+ else
+ {
+ /* Insert at most two breakpoints. One for the next PC content
+ and possibly another one for a branch, jump, etc. */
+ next_pc = (CORE_ADDR) inst_env.reg[PC_REGNUM];
+ target_insert_breakpoint (next_pc, break_mem[0]);
+ if (inst_env.branch_found
+ && (CORE_ADDR) inst_env.branch_break_address != next_pc)
+ {
+ branch_target_address =
+ (CORE_ADDR) inst_env.branch_break_address;
+ target_insert_breakpoint (branch_target_address, break_mem[1]);
+ branch_break_inserted = 1;
+ }
+ }
+ }
+ else
+ {
+ /* Remove breakpoints. */
+ target_remove_breakpoint (next_pc, break_mem[0]);
+ if (branch_break_inserted)
+ {
+ target_remove_breakpoint (branch_target_address, break_mem[1]);
+ branch_break_inserted = 0;
+ }
+ }
+}
+
+/* Calculates the prefix value for quick offset addressing mode. */
+
+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. */
+
+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. */
+
+unsigned long
+get_data_from_address (unsigned short *inst, CORE_ADDR address);
+
+/* Calculates the prefix value for the general case of offset addressing
+ mode. */
+
+void
+bdap_prefix (unsigned short inst, inst_env_type *inst_env)
+{
+
+ long offset;
+
+ /* 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)]);
+
+ 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. */
+
+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. */
+
+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);
+
+ /* 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. */
+
+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. */
+
+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);
+
+ /* 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. */
+
+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. */
+
+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. */
+
+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. */
+
+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 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. */
+
+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. */
+
+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. */
+
+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. */
+
+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. */
+
+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. */
+
+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. */
+
+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. */
+
+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. */
+
+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. */
+
+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. */
+
+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. */
+
+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. */
+
+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. */
+
+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 the PC. */
+ newpc =
+ read_memory_unsigned_integer ((CORE_ADDR) inst_env->prefix_value,
+ 4);
+ }
+ 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);
+
+ /* 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. */
+
+void
+move_to_preg_op (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 (cris_get_operand2 (inst)) == 1)
+ {
+ process_autoincrement (INST_BYTE_SIZE, inst, inst_env);
+ }
+ else if (cris_register_size (cris_get_operand2 (inst)) == 2)
+ {
+ process_autoincrement (INST_WORD_SIZE, inst, inst_env);
+ }
+ else
+ {
+ process_autoincrement (INST_DWORD_SIZE, inst, inst_env);
+ }
+ }
+ }
+ inst_env->slot_needed = 0;
+ inst_env->prefix_found = 0;
+ inst_env->xflag_found = 0;
+ inst_env->disable_interrupt = 1;
+}
+
+/* Handles moves from special registers (aka P-register) for all modes
+ except register. */
+
+void
+none_reg_mode_move_from_preg_op (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 (cris_get_operand2 (inst)) == 1)
+ {
+ process_autoincrement (INST_BYTE_SIZE, inst, inst_env);
+ }
+ else if (cris_register_size (cris_get_operand2 (inst)) == 2)
+ {
+ process_autoincrement (INST_WORD_SIZE, inst, inst_env);
+ }
+ else
+ {
+ process_autoincrement (INST_DWORD_SIZE, inst, inst_env);
+ }
+ }
+ }
+ inst_env->slot_needed = 0;
+ inst_env->prefix_found = 0;
+ inst_env->xflag_found = 0;
+ inst_env->disable_interrupt = 1;
+}
+
+/* Handles moves from special registers (aka P-register) when the mode
+ is register. */
+
+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. */
+
+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);
+ }
+ /* 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);
+ }
+ /* 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. */
+
+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 pop instruction to a general register.
+ POP is a assembler macro for MOVE.D [SP+], Rd. */
+
+void
+reg_pop_op (unsigned short inst, inst_env_type *inst_env)
+{
+ /* POP can't have a prefix. */
+ if (inst_env->prefix_found)
+ {
+ inst_env->invalid = 1;
+ return;
+ }
+ 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[REG_SP], 4);
+ }
+ inst_env->slot_needed = 0;
+ inst_env->prefix_found = 0;
+ inst_env->xflag_found = 0;
+ inst_env->disable_interrupt = 0;
+}
+
+/* Handles moves from register to memory. */
+
+void
+move_reg_to_mem_index_inc_op (unsigned short inst, inst_env_type *inst_env)
+{
+ /* Check if we have a prefix. */
+ if (inst_env->prefix_found)
+ {
+ /* The only thing that can change the PC is an assign. */
+ check_assign (inst, inst_env);
+ }
+ else 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;
+ }
+ 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 intructions that's not yet implemented, by setting
+ inst_env->invalid to true. */
+
+void
+not_implemented_op (unsigned short inst, inst_env_type *inst_env)
+{
+ inst_env->invalid = 1;
+}
+
+/* Handles the XOR instruction. */
+
+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. */
+
+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. */
+
+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. */
+
+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. */
+
+unsigned long
+do_sign_or_zero_extend (unsigned long value, unsigned short *inst)
+{
+ /* The size can be either byte or word, check which one it is.
+ Don't check the highest bit, it's indicating if it's a zero
+ or sign extend. */
+ if (cris_get_size (*inst) & INST_WORD_SIZE)
+ {
+ /* Word size. */
+ value &= 0xFFFF;
+
+ /* Check if the instruction is signed extend. If so, check if value has
+ the sign bit on. */
+ if (cris_is_signed_extend_bit_on (*inst) && (value & SIGNED_WORD_MASK))
+ {
+ value |= SIGNED_WORD_EXTEND_MASK;
+ }
+ }
+ else
+ {
+ /* Byte size. */
+ value &= 0xFF;
+
+ /* Check if the instruction is signed extend. If so, check if value has
+ the sign bit on. */
+ if (cris_is_signed_extend_bit_on (*inst) && (value & SIGNED_BYTE_MASK))
+ {
+ value |= SIGNED_BYTE_EXTEND_MASK;
+ }
+ }
+ /* The size should now be dword. */
+ cris_set_size_to_dword (inst);
+ return value;
+}
+
+/* Handles the register mode for the ADD, SUB, CMP, AND, OR and MOVE
+ instruction. The MOVE instruction is the move from source to register. */
+
+void
+reg_mode_add_sub_cmp_and_or_move_op (unsigned short inst,
+ inst_env_type *inst_env)
+{
+ unsigned long operand1;
+ unsigned long operand2;
+
+ /* It's invalid to have a prefix to the instruction. This is a register
+ mode instruction and can't have a prefix. */
+ if (inst_env->prefix_found)
+ {
+ inst_env->invalid = 1;
+ return;
+ }
+ /* Check if the instruction has PC as its target. */
+ if (cris_get_operand2 (inst) == REG_PC)
+ {
+ if (inst_env->slot_needed)
+ {
+ inst_env->invalid = 1;
+ return;
+ }
+ /* The instruction has the PC as its target register. */
+ operand1 = inst_env->reg[cris_get_operand1 (inst)];
+ operand2 = inst_env->reg[REG_PC];
+
+ /* Check if it's a extend, signed or zero instruction. */
+ if (cris_get_opcode (inst) < 4)
+ {
+ operand1 = do_sign_or_zero_extend (operand1, &inst);
+ }
+ /* Calculate the PC value after the instruction, i.e. where the
+ breakpoint should be. The order of the udw_operands is vital. */
+ add_sub_cmp_and_or_move_action (inst, inst_env, operand2, operand1);
+ }
+ inst_env->slot_needed = 0;
+ inst_env->prefix_found = 0;
+ inst_env->xflag_found = 0;
+ inst_env->disable_interrupt = 0;
+}
+
+/* Returns the data contained at address. The size of the data is derived from
+ the size of the operation. If the instruction is a zero or signed
+ extend instruction, the size field is changed in instruction. */
+
+unsigned long
+get_data_from_address (unsigned short *inst, CORE_ADDR address)
+{
+ int size = cris_get_size (*inst);
+ unsigned long value;
+
+ /* If it's an extend instruction we don't want the signed extend bit,
+ because it influences the size. */
+ if (cris_get_opcode (*inst) < 4)
+ {
+ size &= ~SIGNED_EXTEND_BIT_MASK;
+ }
+ /* Is there a need for checking the size? Size should contain the number of
+ bytes to read. */
+ size = 1 << size;
+ value = read_memory_unsigned_integer (address, size);
+
+ /* Check if it's an extend, signed or zero instruction. */
+ if (cris_get_opcode (*inst) < 4)
+ {
+ value = do_sign_or_zero_extend (value, inst);
+ }
+ return value;
+}
+
+/* Handles the assign addresing mode for the ADD, SUB, CMP, AND, OR and MOVE
+ instructions. The MOVE instruction is the move from source to register. */
+
+void
+handle_prefix_assign_mode_for_aritm_op (unsigned short inst,
+ inst_env_type *inst_env)
+{
+ unsigned long operand2;
+ unsigned long operand3;
+
+ check_assign (inst, inst_env);
+ if (cris_get_operand2 (inst) == REG_PC)
+ {
+ operand2 = inst_env->reg[REG_PC];
+
+ /* Get the value of the third operand. */
+ operand3 = get_data_from_address (&inst, inst_env->prefix_value);
+
+ /* Calculate the PC value after the instruction, i.e. where the
+ breakpoint should be. The order of the udw_operands is vital. */
+ add_sub_cmp_and_or_move_action (inst, inst_env, operand2, operand3);
+ }
+ inst_env->slot_needed = 0;
+ inst_env->prefix_found = 0;
+ inst_env->xflag_found = 0;
+ inst_env->disable_interrupt = 0;
+}
+
+/* Handles the three-operand addressing mode for the ADD, SUB, CMP, AND and
+ OR instructions. Note that for this to work as expected, the calling
+ function must have made sure that there is a prefix to this instruction. */
+
+void
+three_operand_add_sub_cmp_and_or_op (unsigned short inst,
+ inst_env_type *inst_env)
+{
+ unsigned long operand2;
+ unsigned long operand3;
+
+ if (cris_get_operand1 (inst) == REG_PC)
+ {
+ /* The PC will be changed by the instruction. */
+ operand2 = inst_env->reg[cris_get_operand2 (inst)];
+
+ /* Get the value of the third operand. */
+ operand3 = get_data_from_address (&inst, inst_env->prefix_value);
+
+ /* Calculate the PC value after the instruction, i.e. where the
+ breakpoint should be. */
+ add_sub_cmp_and_or_move_action (inst, inst_env, operand2, operand3);
+ }
+ inst_env->slot_needed = 0;
+ inst_env->prefix_found = 0;
+ inst_env->xflag_found = 0;
+ inst_env->disable_interrupt = 0;
+}
+
+/* Handles the index addresing mode for the ADD, SUB, CMP, AND, OR and MOVE
+ instructions. The MOVE instruction is the move from source to register. */
+
+void
+handle_prefix_index_mode_for_aritm_op (unsigned short inst,
+ inst_env_type *inst_env)
+{
+ if (cris_get_operand1 (inst) != cris_get_operand2 (inst))
+ {
+ /* If the instruction is MOVE it's invalid. If the instruction is ADD,
+ SUB, AND or OR something weird is going on (if everything works these
+ instructions should end up in the three operand version). */
+ inst_env->invalid = 1;
+ return;
+ }
+ else
+ {
+ /* three_operand_add_sub_cmp_and_or does the same as we should do here
+ so use it. */
+ three_operand_add_sub_cmp_and_or_op (inst, inst_env);
+ }
+ inst_env->slot_needed = 0;
+ inst_env->prefix_found = 0;
+ inst_env->xflag_found = 0;
+ inst_env->disable_interrupt = 0;
+}
+
+/* Handles the autoincrement and indirect addresing mode for the ADD, SUB,
+ CMP, AND OR and MOVE instruction. The MOVE instruction is the move from
+ source to register. */
+
+void
+handle_inc_and_index_mode_for_aritm_op (unsigned short inst,
+ inst_env_type *inst_env)
+{
+ unsigned long operand1;
+ unsigned long operand2;
+ unsigned long operand3;
+ int size;
+
+ /* The instruction is either an indirect or autoincrement addressing mode.
+ Check if the destination register is the PC. */
+ if (cris_get_operand2 (inst) == REG_PC)
+ {
+ /* Must be done here, get_data_from_address may change the size
+ field. */
+ size = cris_get_size (inst);
+ operand2 = inst_env->reg[REG_PC];
+
+ /* Get the value of the third operand, i.e. the indirect operand. */
+ operand1 = inst_env->reg[cris_get_operand1 (inst)];
+ operand3 = get_data_from_address (&inst, operand1);
+
+ /* Calculate the PC value after the instruction, i.e. where the
+ breakpoint should be. The order of the udw_operands is vital. */
+ add_sub_cmp_and_or_move_action (inst, inst_env, operand2, operand3);
+ }
+ /* If this is an autoincrement addressing mode, check if the increment
+ changes the PC. */
+ if ((cris_get_operand1 (inst) == REG_PC) && (cris_get_mode (inst) == AUTOINC_MODE))
+ {
+ /* Get the size field. */
+ size = cris_get_size (inst);
+
+ /* If it's an extend instruction we don't want the signed extend bit,
+ because it influences the size. */
+ if (cris_get_opcode (inst) < 4)
+ {
+ size &= ~SIGNED_EXTEND_BIT_MASK;
+ }
+ process_autoincrement (size, inst, inst_env);
+ }
+ inst_env->slot_needed = 0;
+ inst_env->prefix_found = 0;
+ inst_env->xflag_found = 0;
+ inst_env->disable_interrupt = 0;
+}
+
+/* Handles the two-operand addressing mode, all modes except register, for
+ the ADD, SUB CMP, AND and OR instruction. */
+
+void
+none_reg_mode_add_sub_cmp_and_or_move_op (unsigned short inst,
+ inst_env_type *inst_env)
+{
+ if (inst_env->prefix_found)
+ {
+ if (cris_get_mode (inst) == PREFIX_INDEX_MODE)
+ {
+ handle_prefix_index_mode_for_aritm_op (inst, inst_env);
+ }
+ else if (cris_get_mode (inst) == PREFIX_ASSIGN_MODE)
+ {
+ handle_prefix_assign_mode_for_aritm_op (inst, inst_env);
+ }
+ else
+ {
+ /* The mode is invalid for a prefixed base instruction. */
+ inst_env->invalid = 1;
+ return;
+ }
+ }
+ else
+ {
+ handle_inc_and_index_mode_for_aritm_op (inst, inst_env);
+ }
+}
+
+/* Handles the quick addressing mode for the ADD and SUB instruction. */
+
+void
+quick_mode_add_sub_op (unsigned short inst, inst_env_type *inst_env)
+{
+ unsigned long operand1;
+ unsigned long operand2;
+
+ /* It's a bad idea to be in a prefix instruction now. This is a quick mode
+ instruction and can't have a prefix. */
+ if (inst_env->prefix_found)
+ {
+ inst_env->invalid = 1;
+ return;
+ }
+
+ /* Check if the instruction has PC as its target. */
+ if (cris_get_operand2 (inst) == REG_PC)
+ {
+ if (inst_env->slot_needed)
+ {
+ inst_env->invalid = 1;
+ return;
+ }
+ operand1 = cris_get_quick_value (inst);
+ operand2 = inst_env->reg[REG_PC];
+
+ /* The size should now be dword. */
+ cris_set_size_to_dword (&inst);
+
+ /* Calculate the PC value after the instruction, i.e. where the
+ breakpoint should be. */
+ add_sub_cmp_and_or_move_action (inst, inst_env, operand2, operand1);
+ }
+ inst_env->slot_needed = 0;
+ inst_env->prefix_found = 0;
+ inst_env->xflag_found = 0;
+ inst_env->disable_interrupt = 0;
+}
+
+/* Handles the quick addressing mode for the CMP, AND and OR instruction. */
+
+void
+quick_mode_and_cmp_move_or_op (unsigned short inst, inst_env_type *inst_env)
+{
+ unsigned long operand1;
+ unsigned long operand2;
+
+ /* It's a bad idea to be in a prefix instruction now. This is a quick mode
+ instruction and can't have a prefix. */
+ if (inst_env->prefix_found)
+ {
+ inst_env->invalid = 1;
+ return;
+ }
+ /* Check if the instruction has PC as its target. */
+ if (cris_get_operand2 (inst) == REG_PC)
+ {
+ if (inst_env->slot_needed)
+ {
+ inst_env->invalid = 1;
+ return;
+ }
+ /* The instruction has the PC as its target register. */
+ operand1 = cris_get_quick_value (inst);
+ operand2 = inst_env->reg[REG_PC];
+
+ /* The quick value is signed, so check if we must do a signed extend. */
+ if (operand1 & SIGNED_QUICK_VALUE_MASK)
+ {
+ /* sign extend */
+ operand1 |= SIGNED_QUICK_VALUE_EXTEND_MASK;
+ }
+ /* The size should now be dword. */
+ cris_set_size_to_dword (&inst);
+
+ /* Calculate the PC value after the instruction, i.e. where the
+ breakpoint should be. */
+ add_sub_cmp_and_or_move_action (inst, inst_env, operand2, operand1);
+ }
+ inst_env->slot_needed = 0;
+ inst_env->prefix_found = 0;
+ inst_env->xflag_found = 0;
+ inst_env->disable_interrupt = 0;
+}
+
+/* Translate op_type to a function and call it. */
+
+static void cris_gdb_func (enum cris_op_type op_type, unsigned short inst,
+ inst_env_type *inst_env)
+{
+ switch (op_type)
+ {
+ case cris_not_implemented_op:
+ not_implemented_op (inst, inst_env);
+ break;
+
+ case cris_abs_op:
+ abs_op (inst, inst_env);
+ break;
+
+ case cris_addi_op:
+ addi_op (inst, inst_env);
+ break;
+
+ case cris_asr_op:
+ asr_op (inst, inst_env);
+ break;
+
+ case cris_asrq_op:
+ asrq_op (inst, inst_env);
+ break;
+
+ case cris_ax_ei_setf_op:
+ ax_ei_setf_op (inst, inst_env);
+ break;
+
+ case cris_bdap_prefix:
+ bdap_prefix (inst, inst_env);
+ break;
+
+ case cris_biap_prefix:
+ biap_prefix (inst, inst_env);
+ break;
+
+ case cris_break_op:
+ break_op (inst, inst_env);
+ break;
+
+ case cris_btst_nop_op:
+ btst_nop_op (inst, inst_env);
+ break;
+
+ case cris_clearf_di_op:
+ clearf_di_op (inst, inst_env);
+ break;
+
+ case cris_dip_prefix:
+ dip_prefix (inst, inst_env);
+ break;
+
+ case cris_dstep_logshift_mstep_neg_not_op:
+ dstep_logshift_mstep_neg_not_op (inst, inst_env);
+ break;
+
+ case cris_eight_bit_offset_branch_op:
+ eight_bit_offset_branch_op (inst, inst_env);
+ break;
+
+ case cris_move_mem_to_reg_movem_op:
+ move_mem_to_reg_movem_op (inst, inst_env);
+ break;
+
+ case cris_move_reg_to_mem_movem_op:
+ move_reg_to_mem_movem_op (inst, inst_env);
+ break;
+
+ case cris_move_to_preg_op:
+ move_to_preg_op (inst, inst_env);
+ break;
+
+ case cris_muls_op:
+ muls_op (inst, inst_env);
+ break;
+
+ case cris_mulu_op:
+ mulu_op (inst, inst_env);
+ break;
+
+ case cris_none_reg_mode_add_sub_cmp_and_or_move_op:
+ none_reg_mode_add_sub_cmp_and_or_move_op (inst, inst_env);
+ break;
+
+ case cris_none_reg_mode_clear_test_op:
+ none_reg_mode_clear_test_op (inst, inst_env);
+ break;
+
+ case cris_none_reg_mode_jump_op:
+ none_reg_mode_jump_op (inst, inst_env);
+ break;
+
+ case cris_none_reg_mode_move_from_preg_op:
+ none_reg_mode_move_from_preg_op (inst, inst_env);
+ break;
+
+ case cris_quick_mode_add_sub_op:
+ quick_mode_add_sub_op (inst, inst_env);
+ break;
+
+ case cris_quick_mode_and_cmp_move_or_op:
+ quick_mode_and_cmp_move_or_op (inst, inst_env);
+ break;
+
+ case cris_quick_mode_bdap_prefix:
+ quick_mode_bdap_prefix (inst, inst_env);
+ break;
+
+ case cris_reg_mode_add_sub_cmp_and_or_move_op:
+ reg_mode_add_sub_cmp_and_or_move_op (inst, inst_env);
+ break;
+
+ case cris_reg_mode_clear_op:
+ reg_mode_clear_op (inst, inst_env);
+ break;
+
+ case cris_reg_mode_jump_op:
+ reg_mode_jump_op (inst, inst_env);
+ break;
+
+ case cris_reg_mode_move_from_preg_op:
+ reg_mode_move_from_preg_op (inst, inst_env);
+ break;
+
+ case cris_reg_mode_test_op:
+ reg_mode_test_op (inst, inst_env);
+ break;
+
+ case cris_scc_op:
+ scc_op (inst, inst_env);
+ break;
+
+ case cris_sixteen_bit_offset_branch_op:
+ sixteen_bit_offset_branch_op (inst, inst_env);
+ break;
+
+ case cris_three_operand_add_sub_cmp_and_or_op:
+ three_operand_add_sub_cmp_and_or_op (inst, inst_env);
+ break;
+
+ case cris_three_operand_bound_op:
+ three_operand_bound_op (inst, inst_env);
+ break;
+
+ case cris_two_operand_bound_op:
+ two_operand_bound_op (inst, inst_env);
+ break;
+
+ case cris_xor_op:
+ xor_op (inst, inst_env);
+ break;
+ }
+}
+
+/* This wrapper is to avoid cris_get_assembler being called before
+ exec_bfd has been set. */
+
+static int
+cris_delayed_get_disassembler (bfd_vma addr, disassemble_info *info)
+{
+ tm_print_insn = cris_get_disassembler (exec_bfd);
+ return TARGET_PRINT_INSN (addr, info);
+}
+
+/* Copied from <asm/elf.h>. */
+typedef unsigned long elf_greg_t;
+
+/* Same as user_regs_struct struct in <asm/user.h>. */
+typedef elf_greg_t elf_gregset_t[35];
+
+/* Unpack an elf_gregset_t into GDB's register cache. */
+
+void
+supply_gregset (elf_gregset_t *gregsetp)
+{
+ int i;
+ elf_greg_t *regp = *gregsetp;
+ static char zerobuf[4] = {0};
+
+ /* The kernel dumps all 32 registers as unsigned longs, but supply_register
+ knows about the actual size of each register so that's no problem. */
+ for (i = 0; i < NUM_GENREGS + NUM_SPECREGS; i++)
+ {
+ supply_register (i, (char *)&regp[i]);
+ }
+}
+
+/* Use a local version of this function to get the correct types for
+ regsets, until multi-arch core support is ready. */
+
+static void
+fetch_core_registers (char *core_reg_sect, unsigned core_reg_size,
+ int which, CORE_ADDR reg_addr)
+{
+ elf_gregset_t gregset;
+
+ switch (which)
+ {
+ case 0:
+ if (core_reg_size != sizeof (gregset))
+ {
+ warning ("wrong size gregset struct in core file");
+ }
+ else
+ {
+ memcpy (&gregset, core_reg_sect, sizeof (gregset));
+ supply_gregset (&gregset);
+ }
+
+ default:
+ /* We've covered all the kinds of registers we know about here,
+ so this must be something we wouldn't know what to do with
+ anyway. Just ignore it. */
+ break;
+ }
+}
+
+static struct core_fns cris_elf_core_fns =
+{
+ bfd_target_elf_flavour, /* core_flavour */
+ default_check_format, /* check_format */
+ default_core_sniffer, /* core_sniffer */
+ fetch_core_registers, /* core_read_registers */
+ NULL /* next */
+};
+
+/* Fetch (and possibly build) an appropriate link_map_offsets
+ structure for native GNU/Linux CRIS targets using the struct
+ offsets defined in link.h (but without actual reference to that
+ file).
+
+ This makes it possible to access GNU/Linux CRIS shared libraries
+ from a GDB that was not built on an GNU/Linux CRIS host (for cross
+ debugging).
+
+ See gdb/solib-svr4.h for an explanation of these fields. */
+
+struct link_map_offsets *
+cris_linux_svr4_fetch_link_map_offsets (void)
+{
+ static struct link_map_offsets lmo;
+ static struct link_map_offsets *lmp = NULL;
+
+ if (lmp == NULL)
+ {
+ lmp = &lmo;
+
+ lmo.r_debug_size = 8; /* The actual size is 20 bytes, but
+ this is all we need. */
+ lmo.r_map_offset = 4;
+ lmo.r_map_size = 4;
+
+ lmo.link_map_size = 20;
+
+ lmo.l_addr_offset = 0;
+ lmo.l_addr_size = 4;
+
+ lmo.l_name_offset = 4;
+ lmo.l_name_size = 4;
+
+ lmo.l_next_offset = 12;
+ lmo.l_next_size = 4;
+
+ lmo.l_prev_offset = 16;
+ lmo.l_prev_size = 4;
+ }
+
+ return lmp;
+}
+
+static void
+cris_fpless_backtrace (char *noargs, int from_tty)
+{
+ /* Points at the instruction after the jsr (except when in innermost frame
+ where it points at the original pc). */
+ CORE_ADDR pc = 0;
+
+ /* Temporary variable, used for parsing from the start of the function that
+ the pc is in, up to the pc. */
+ CORE_ADDR tmp_pc = 0;
+ CORE_ADDR sp = 0;
+
+ /* Information about current frame. */
+ struct symtab_and_line sal;
+ char* func_name;
+
+ /* Present instruction. */
+ unsigned short insn;
+
+ /* Next instruction, lookahead. */
+ unsigned short insn_next;
+
+ /* This is to store the offset between sp at start of function and until we
+ reach push srp (if any). */
+ int sp_add_later = 0;
+ int push_srp_found = 0;
+
+ int val = 0;
+
+ /* Frame counter. */
+ int frame = 0;
+
+ /* For the innermost frame, we want to look at srp in case it's a leaf
+ function (since there's no push srp in that case). */
+ int innermost_frame = 1;
+
+ read_register_gen (PC_REGNUM, (char *) &pc);
+ read_register_gen (SP_REGNUM, (char *) &sp);
+
+ /* We make an explicit return when we can't find an outer frame. */
+ while (1)
+ {
+ /* Get file name and line number. */
+ sal = find_pc_line (pc, 0);
+
+ /* Get function name. */
+ find_pc_partial_function (pc, &func_name, (CORE_ADDR *) NULL,
+ (CORE_ADDR *) NULL);
+
+ /* Print information about current frame. */
+ printf_unfiltered ("#%i 0x%08lx in %s", frame++, pc, func_name);
+ if (sal.symtab)
+ {
+ printf_unfiltered (" at %s:%i", sal.symtab->filename, sal.line);
+ }
+ printf_unfiltered ("\n");
+
+ /* Get the start address of this function. */
+ tmp_pc = get_pc_function_start (pc);
+
+ /* Mini parser, only meant to find push sp and sub ...,sp from the start
+ of the function, up to the pc. */
+ while (tmp_pc < pc)
+ {
+ insn = read_memory_unsigned_integer (tmp_pc, sizeof (short));
+ tmp_pc += sizeof (short);
+ if (insn == 0xE1FC)
+ {
+ /* push <reg> 32 bit instruction */
+ insn_next = read_memory_unsigned_integer (tmp_pc,
+ sizeof (short));
+ tmp_pc += sizeof (short);
+
+ /* Recognize srp. */
+ if (insn_next == 0xBE7E)
+ {
+ /* For subsequent (not this one though) push or sub which
+ affects sp, adjust sp immediately. */
+ push_srp_found = 1;
+
+ /* Note: this will break if we ever encounter a
+ push vr (1 byte) or push ccr (2 bytes). */
+ sp_add_later += 4;
+ }
+ else
+ {
+ /* Some other register was pushed. */
+ if (push_srp_found)
+ {
+ sp += 4;
+ }
+ else
+ {
+ sp_add_later += 4;
+ }
+ }
+ }
+ else if (cris_get_operand2 (insn) == SP_REGNUM
+ && cris_get_mode (insn) == 0x0000
+ && cris_get_opcode (insn) == 0x000A)
+ {
+ /* subq <val>,sp */
+ val = cris_get_quick_value (insn);
+
+ if (push_srp_found)
+ {
+ sp += val;
+ }
+ else
+ {
+ sp_add_later += val;
+ }
+
+ }
+ else if (cris_get_operand2 (insn) == SP_REGNUM
+ /* Autoincrement addressing mode. */
+ && cris_get_mode (insn) == 0x0003
+ /* Opcode. */
+ && ((insn) & 0x03E0) >> 5 == 0x0004)
+ {
+ /* subu <val>,sp */
+ val = get_data_from_address (&insn, tmp_pc);
+
+ if (push_srp_found)
+ {
+ sp += val;
+ }
+ else
+ {
+ sp_add_later += val;
+ }
+ }
+ else if (cris_get_operand2 (insn) == SP_REGNUM
+ && ((insn & 0x0F00) >> 8) == 0x0001
+ && (cris_get_signed_offset (insn) < 0))
+ {
+ /* 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>] */
+ val = -cris_get_signed_offset (insn);
+ insn_next = read_memory_unsigned_integer (tmp_pc,
+ sizeof (short));
+ tmp_pc += sizeof (short);
+
+ if (cris_get_mode (insn_next) == PREFIX_ASSIGN_MODE
+ && cris_get_opcode (insn_next) == 0x000F
+ && cris_get_size (insn_next) == 0x0003
+ && cris_get_operand1 (insn_next) == SP_REGNUM)
+ {
+ if (push_srp_found)
+ {
+ sp += val;
+ }
+ else
+ {
+ sp_add_later += val;
+ }
+ }
+ }
+ }
+
+ if (push_srp_found)
+ {
+ /* Reset flag. */
+ push_srp_found = 0;
+
+ /* sp should now point at where srp is stored on the stack. Update
+ the pc to the srp. */
+ pc = read_memory_unsigned_integer (sp, 4);
+ }
+ else if (innermost_frame)
+ {
+ /* We couldn't find a push srp in the prologue, so this must be
+ a leaf function, and thus we use the srp register directly.
+ This should happen at most once, for the innermost function. */
+ read_register_gen (SRP_REGNUM, (char *) &pc);
+ }
+ else
+ {
+ /* Couldn't find an outer frame. */
+ return;
+ }
+
+ /* Reset flag. (In case the innermost frame wasn't a leaf, we don't
+ want to look at the srp register later either). */
+ innermost_frame = 0;
+
+ /* Now, add the offset for everything up to, and including push srp,
+ that was held back during the prologue parsing. */
+ sp += sp_add_later;
+ sp_add_later = 0;
+ }
+}
+
+void
+_initialize_cris_tdep (void)
+{
+ struct cmd_list_element *c;
+
+ gdbarch_register (bfd_arch_cris, cris_gdbarch_init, cris_dump_tdep);
+
+ /* Used in disassembly. */
+ tm_print_insn = cris_delayed_get_disassembler;
+
+ /* CRIS-specific user-commands. */
+ c = add_set_cmd ("cris-version", class_support, var_integer,
+ (char *) &usr_cmd_cris_version,
+ "Set the current CRIS version.", &setlist);
+ set_cmd_sfunc (c, cris_version_update);
+ add_show_from_set (c, &showlist);
+
+ c = add_set_enum_cmd ("cris-mode", class_support, cris_mode_enums,
+ &usr_cmd_cris_mode,
+ "Set the current CRIS mode.", &setlist);
+ set_cmd_sfunc (c, cris_mode_update);
+ add_show_from_set (c, &showlist);
+
+ c = add_set_enum_cmd ("cris-abi", class_support, cris_abi_enums,
+ &usr_cmd_cris_abi,
+ "Set the current CRIS ABI version.", &setlist);
+ set_cmd_sfunc (c, cris_abi_update);
+ add_show_from_set (c, &showlist);
+
+ c = add_cmd ("cris-fpless-backtrace", class_support, cris_fpless_backtrace,
+ "Display call chain using the subroutine return pointer.\n"
+ "Note that this displays the address after the jump to the "
+ "subroutine.", &cmdlist);
+
+ add_core_fns (&cris_elf_core_fns);
+
+}
+
+/* Prints out all target specific values. */
+
+static void
+cris_dump_tdep (struct gdbarch *gdbarch, struct ui_file *file)
+{
+ struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
+ if (tdep != NULL)
+ {
+ fprintf_unfiltered (file, "cris_dump_tdep: tdep->cris_version = %i\n",
+ tdep->cris_version);
+ fprintf_unfiltered (file, "cris_dump_tdep: tdep->cris_mode = %s\n",
+ tdep->cris_mode);
+ fprintf_unfiltered (file, "cris_dump_tdep: tdep->cris_abi = %s\n",
+ tdep->cris_abi);
+
+ }
+}
+
+static void
+cris_version_update (char *ignore_args, int from_tty,
+ struct cmd_list_element *c)
+{
+ struct gdbarch_info info;
+
+ /* NOTE: cagney/2002-03-17: The add_show_from_set() function clones
+ the set command passed as a parameter. The clone operation will
+ include (BUG?) any ``set'' command callback, if present.
+ Commands like ``info set'' call all the ``show'' command
+ callbacks. Unfortunatly, for ``show'' commands cloned from
+ ``set'', this includes callbacks belonging to ``set'' commands.
+ Making this worse, this only occures if add_show_from_set() is
+ called after add_cmd_sfunc() (BUG?). */
+
+ /* From here on, trust the user's CRIS version setting. */
+ if (cmd_type (c) == set_cmd)
+ {
+ usr_cmd_cris_version_valid = 1;
+
+ /* Update the current architecture, if needed. */
+ gdbarch_info_init (&info);
+ if (!gdbarch_update_p (info))
+ internal_error (__FILE__, __LINE__, "cris_gdbarch_update: failed to update architecture.");
+ }
+}
+
+static void
+cris_mode_update (char *ignore_args, int from_tty,
+ struct cmd_list_element *c)
+{
+ struct gdbarch_info info;
+
+ /* NOTE: cagney/2002-03-17: The add_show_from_set() function clones
+ the set command passed as a parameter. The clone operation will
+ include (BUG?) any ``set'' command callback, if present.
+ Commands like ``info set'' call all the ``show'' command
+ callbacks. Unfortunatly, for ``show'' commands cloned from
+ ``set'', this includes callbacks belonging to ``set'' commands.
+ Making this worse, this only occures if add_show_from_set() is
+ called after add_cmd_sfunc() (BUG?). */
+
+ /* From here on, trust the user's CRIS mode setting. */
+ if (cmd_type (c) == set_cmd)
+ {
+ usr_cmd_cris_mode_valid = 1;
+
+ /* Update the current architecture, if needed. */
+ gdbarch_info_init (&info);
+ if (!gdbarch_update_p (info))
+ internal_error (__FILE__, __LINE__, "cris_gdbarch_update: failed to update architecture.");
+ }
+}
+
+static void
+cris_abi_update (char *ignore_args, int from_tty,
+ struct cmd_list_element *c)
+{
+ struct gdbarch_info info;
+
+ /* NOTE: cagney/2002-03-17: The add_show_from_set() function clones
+ the set command passed as a parameter. The clone operation will
+ include (BUG?) any ``set'' command callback, if present.
+ Commands like ``info set'' call all the ``show'' command
+ callbacks. Unfortunatly, for ``show'' commands cloned from
+ ``set'', this includes callbacks belonging to ``set'' commands.
+ Making this worse, this only occures if add_show_from_set() is
+ called after add_cmd_sfunc() (BUG?). */
+
+ /* From here on, trust the user's CRIS ABI setting. */
+ if (cmd_type (c) == set_cmd)
+ {
+ usr_cmd_cris_abi_valid = 1;
+
+ /* Update the current architecture, if needed. */
+ gdbarch_info_init (&info);
+ if (!gdbarch_update_p (info))
+ internal_error (__FILE__, __LINE__, "cris_gdbarch_update: failed to update architecture.");
+ }
+}
+
+/* Copied from pa64solib.c, with a couple of minor changes. */
+
+static CORE_ADDR
+bfd_lookup_symbol (bfd *abfd, const char *symname)
+{
+ unsigned int storage_needed;
+ asymbol *sym;
+ asymbol **symbol_table;
+ unsigned int number_of_symbols;
+ unsigned int i;
+ struct cleanup *back_to;
+ CORE_ADDR symaddr = 0;
+
+ storage_needed = bfd_get_symtab_upper_bound (abfd);
+
+ if (storage_needed > 0)
+ {
+ symbol_table = (asymbol **) xmalloc (storage_needed);
+ back_to = make_cleanup (free, (PTR) symbol_table);
+ number_of_symbols = bfd_canonicalize_symtab (abfd, symbol_table);
+
+ for (i = 0; i < number_of_symbols; i++)
+ {
+ sym = *symbol_table++;
+ if (!strcmp (sym->name, symname))
+ {
+ /* Bfd symbols are section relative. */
+ symaddr = sym->value + sym->section->vma;
+ break;
+ }
+ }
+ do_cleanups (back_to);
+ }
+ return (symaddr);
+}
+
+static struct gdbarch *
+cris_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
+{
+ struct gdbarch *gdbarch;
+ struct gdbarch_tdep *tdep;
+ int cris_version;
+ const char *cris_mode;
+ const char *cris_abi;
+ CORE_ADDR cris_abi_sym = 0;
+ int register_bytes;
+
+ if (usr_cmd_cris_version_valid)
+ {
+ /* Trust the user's CRIS version setting. */
+ cris_version = usr_cmd_cris_version;
+ }
+ else
+ {
+ /* Assume it's CRIS version 10. */
+ cris_version = 10;
+ }
+
+ if (usr_cmd_cris_mode_valid)
+ {
+ /* Trust the user's CRIS mode setting. */
+ cris_mode = usr_cmd_cris_mode;
+ }
+ else if (cris_version == 10)
+ {
+ /* Assume CRIS version 10 is in user mode. */
+ cris_mode = CRIS_MODE_USER;
+ }
+ else
+ {
+ /* Strictly speaking, older CRIS version don't have a supervisor mode,
+ but we regard its only mode as supervisor mode. */
+ cris_mode = CRIS_MODE_SUPERVISOR;
+ }
+
+ if (usr_cmd_cris_abi_valid)
+ {
+ /* Trust the user's ABI setting. */
+ cris_abi = usr_cmd_cris_abi;
+ }
+ else if (info.abfd)
+ {
+ if (bfd_get_flavour (info.abfd) == bfd_target_elf_flavour)
+ {
+ /* An elf target uses the new ABI. */
+ cris_abi = CRIS_ABI_V2;
+ }
+ else if (bfd_get_flavour (info.abfd) == bfd_target_aout_flavour)
+ {
+ /* An a.out target may use either ABI. Look for hints in the
+ symbol table. */
+ cris_abi_sym = bfd_lookup_symbol (info.abfd, CRIS_ABI_SYMBOL);
+ cris_abi = cris_abi_sym ? CRIS_ABI_V2 : CRIS_ABI_ORIGINAL;
+ }
+ else
+ {
+ /* Unknown bfd flavour. Assume it's the new ABI. */
+ cris_abi = CRIS_ABI_V2;
+ }
+ }
+ else if (arches != NULL)
+ {
+ /* No bfd available. Stick with the ABI from the most recently
+ selected architecture of this same family (the head of arches
+ always points to this). (This is to avoid changing the ABI
+ when the user updates the architecture with the 'set
+ cris-version' command.) */
+ cris_abi = gdbarch_tdep (arches->gdbarch)->cris_abi;
+ }
+ else
+ {
+ /* No bfd, and no previously selected architecture available.
+ Assume it's the new ABI. */
+ cris_abi = CRIS_ABI_V2;
+ }
+
+ /* Make the current settings visible to the user. */
+ usr_cmd_cris_version = cris_version;
+ usr_cmd_cris_mode = cris_mode;
+ usr_cmd_cris_abi = cris_abi;
+
+ /* Find a candidate among the list of pre-declared architectures. Both
+ CRIS version and ABI must match. */
+ for (arches = gdbarch_list_lookup_by_info (arches, &info);
+ arches != NULL;
+ arches = gdbarch_list_lookup_by_info (arches->next, &info))
+ {
+ if ((gdbarch_tdep (arches->gdbarch)->cris_version == cris_version)
+ && (gdbarch_tdep (arches->gdbarch)->cris_mode == cris_mode)
+ && (gdbarch_tdep (arches->gdbarch)->cris_abi == cris_abi))
+ return arches->gdbarch;
+ }
+
+ /* No matching architecture was found. Create a new one. */
+ tdep = (struct gdbarch_tdep *) xmalloc (sizeof (struct gdbarch_tdep));
+ gdbarch = gdbarch_alloc (&info, tdep);
+
+ tdep->cris_version = cris_version;
+ tdep->cris_mode = cris_mode;
+ tdep->cris_abi = cris_abi;
+
+ /* INIT shall ensure that the INFO.BYTE_ORDER is non-zero. */
+ switch (info.byte_order)
+ {
+ case BFD_ENDIAN_LITTLE:
+ /* Ok. */
+ break;
+
+ case BFD_ENDIAN_BIG:
+ internal_error (__FILE__, __LINE__, "cris_gdbarch_init: big endian byte order in info");
+ break;
+
+ default:
+ internal_error (__FILE__, __LINE__, "cris_gdbarch_init: unknown byte order in info");
+ }
+
+ /* Initialize the ABI dependent things. */
+ if (tdep->cris_abi == CRIS_ABI_ORIGINAL)
+ {
+ set_gdbarch_double_bit (gdbarch, 32);
+ set_gdbarch_push_arguments (gdbarch, cris_abi_original_push_arguments);
+ set_gdbarch_deprecated_store_return_value (gdbarch,
+ cris_abi_original_store_return_value);
+ set_gdbarch_deprecated_extract_return_value
+ (gdbarch, cris_abi_original_extract_return_value);
+ set_gdbarch_reg_struct_has_addr
+ (gdbarch, cris_abi_original_reg_struct_has_addr);
+ }
+ else if (tdep->cris_abi == CRIS_ABI_V2)
+ {
+ set_gdbarch_double_bit (gdbarch, 64);
+ set_gdbarch_push_arguments (gdbarch, cris_abi_v2_push_arguments);
+ set_gdbarch_deprecated_store_return_value (gdbarch, cris_abi_v2_store_return_value);
+ set_gdbarch_deprecated_extract_return_value
+ (gdbarch, cris_abi_v2_extract_return_value);
+ set_gdbarch_reg_struct_has_addr (gdbarch,
+ cris_abi_v2_reg_struct_has_addr);
+ }
+ else
+ internal_error (__FILE__, __LINE__, "cris_gdbarch_init: unknown CRIS ABI");
+
+ /* The default definition of a long double is 2 * TARGET_DOUBLE_BIT,
+ which means we have to set this explicitly. */
+ set_gdbarch_long_double_bit (gdbarch, 64);
+
+ /* There are 32 registers (some of which may not be implemented). */
+ set_gdbarch_num_regs (gdbarch, 32);
+ set_gdbarch_sp_regnum (gdbarch, 14);
+ set_gdbarch_fp_regnum (gdbarch, 8);
+ set_gdbarch_pc_regnum (gdbarch, 15);
+
+ set_gdbarch_register_name (gdbarch, cris_register_name);
+
+ /* Length of ordinary registers used in push_word and a few other places.
+ REGISTER_RAW_SIZE is the real way to know how big a register is. */
+ set_gdbarch_register_size (gdbarch, 4);
+
+ /* NEW */
+ set_gdbarch_register_bytes_ok (gdbarch, cris_register_bytes_ok);
+ set_gdbarch_software_single_step (gdbarch, cris_software_single_step);
+
+
+ set_gdbarch_cannot_store_register (gdbarch, cris_cannot_store_register);
+ set_gdbarch_cannot_fetch_register (gdbarch, cris_cannot_fetch_register);
+
+
+ /* The total amount of space needed to store (in an array called registers)
+ GDB's copy of the machine's register state. Note: We can not use
+ cris_register_size at this point, since it relies on current_gdbarch
+ being set. */
+ switch (tdep->cris_version)
+ {
+ case 0:
+ case 1:
+ case 2:
+ case 3:
+ /* Support for these may be added later. */
+ internal_error (__FILE__, __LINE__, "cris_gdbarch_init: unsupported CRIS version");
+ break;
+
+ case 8:
+ case 9:
+ /* CRIS v8 and v9, a.k.a. ETRAX 100. General registers R0 - R15
+ (32 bits), special registers P0 - P1 (8 bits), P4 - P5 (16 bits),
+ and P8 - P14 (32 bits). */
+ register_bytes = (16 * 4) + (2 * 1) + (2 * 2) + (7 * 4);
+ break;
+
+ case 10:
+ case 11:
+ /* CRIS v10 and v11, a.k.a. ETRAX 100LX. In addition to ETRAX 100,
+ P7 (32 bits), and P15 (32 bits) have been implemented. */
+ register_bytes = (16 * 4) + (2 * 1) + (2 * 2) + (9 * 4);
+ break;
+
+ default:
+ internal_error (__FILE__, __LINE__, "cris_gdbarch_init: unknown CRIS version");
+ }
+
+ set_gdbarch_register_bytes (gdbarch, register_bytes);
+
+ /* Returns the register offset for the first byte of register regno's space
+ in the saved register state. */
+ set_gdbarch_register_byte (gdbarch, cris_register_offset);
+
+ /* The length of the registers in the actual machine representation. */
+ set_gdbarch_register_raw_size (gdbarch, cris_register_size);
+
+ /* The largest value REGISTER_RAW_SIZE can have. */
+ set_gdbarch_max_register_raw_size (gdbarch, 32);
+
+ /* The length of the registers in the program's representation. */
+ set_gdbarch_register_virtual_size (gdbarch, cris_register_size);
+
+ /* The largest value REGISTER_VIRTUAL_SIZE can have. */
+ set_gdbarch_max_register_virtual_size (gdbarch, 32);
+
+ set_gdbarch_register_virtual_type (gdbarch, cris_register_virtual_type);
+
+ /* Use generic dummy frames. */
+ set_gdbarch_use_generic_dummy_frames (gdbarch, 1);
+
+ /* Where to execute the call in the memory segments. */
+ set_gdbarch_call_dummy_location (gdbarch, AT_ENTRY_POINT);
+ set_gdbarch_call_dummy_address (gdbarch, entry_point_address);
+
+ /* Start execution at the beginning of dummy. */
+ set_gdbarch_call_dummy_start_offset (gdbarch, 0);
+ set_gdbarch_call_dummy_breakpoint_offset (gdbarch, 0);
+
+ /* Set to 1 since call_dummy_breakpoint_offset was defined. */
+ set_gdbarch_call_dummy_breakpoint_offset_p (gdbarch, 1);
+
+ /* Read all about dummy frames in blockframe.c. */
+ set_gdbarch_call_dummy_length (gdbarch, 0);
+ set_gdbarch_pc_in_call_dummy (gdbarch, pc_in_call_dummy_at_entry_point);
+
+ /* Defined to 1 to indicate that the target supports inferior function
+ calls. */
+ set_gdbarch_call_dummy_p (gdbarch, 1);
+ set_gdbarch_call_dummy_words (gdbarch, 0);
+ set_gdbarch_sizeof_call_dummy_words (gdbarch, 0);
+
+ /* No stack adjustment needed when peforming an inferior function call. */
+ set_gdbarch_call_dummy_stack_adjust_p (gdbarch, 0);
+ set_gdbarch_fix_call_dummy (gdbarch, generic_fix_call_dummy);
+
+ set_gdbarch_get_saved_register (gdbarch, generic_get_saved_register);
+
+ /* No register requires conversion from raw format to virtual format. */
+ set_gdbarch_register_convertible (gdbarch, generic_register_convertible_not);
+
+ set_gdbarch_push_dummy_frame (gdbarch, generic_push_dummy_frame);
+ set_gdbarch_push_return_address (gdbarch, cris_push_return_address);
+ set_gdbarch_pop_frame (gdbarch, cris_pop_frame);
+
+ set_gdbarch_store_struct_return (gdbarch, cris_store_struct_return);
+ set_gdbarch_deprecated_extract_struct_value_address
+ (gdbarch, cris_extract_struct_value_address);
+ set_gdbarch_use_struct_convention (gdbarch, cris_use_struct_convention);
+
+ set_gdbarch_frame_init_saved_regs (gdbarch, cris_frame_init_saved_regs);
+ set_gdbarch_init_extra_frame_info (gdbarch, cris_init_extra_frame_info);
+ set_gdbarch_skip_prologue (gdbarch, cris_skip_prologue);
+ set_gdbarch_prologue_frameless_p (gdbarch, generic_prologue_frameless_p);
+
+ /* The stack grows downward. */
+ set_gdbarch_inner_than (gdbarch, core_addr_lessthan);
+
+ set_gdbarch_breakpoint_from_pc (gdbarch, cris_breakpoint_from_pc);
+
+ /* The PC must not be decremented after a breakpoint. (The breakpoint
+ handler takes care of that.) */
+ set_gdbarch_decr_pc_after_break (gdbarch, 0);
+
+ /* Offset from address of function to start of its code. */
+ set_gdbarch_function_start_offset (gdbarch, 0);
+
+ /* The number of bytes at the start of arglist that are not really args,
+ 0 in the CRIS ABI. */
+ set_gdbarch_frame_args_skip (gdbarch, 0);
+ set_gdbarch_frameless_function_invocation
+ (gdbarch, cris_frameless_function_invocation);
+ set_gdbarch_frame_chain (gdbarch, cris_frame_chain);
+ set_gdbarch_frame_chain_valid (gdbarch, generic_file_frame_chain_valid);
+
+ set_gdbarch_frame_saved_pc (gdbarch, cris_frame_saved_pc);
+ set_gdbarch_frame_args_address (gdbarch, cris_frame_args_address);
+ set_gdbarch_frame_locals_address (gdbarch, cris_frame_locals_address);
+ set_gdbarch_saved_pc_after_call (gdbarch, cris_saved_pc_after_call);
+
+ set_gdbarch_frame_num_args (gdbarch, frame_num_args_unknown);
+
+ /* No extra stack alignment needed. Set to 1 by default. */
+ set_gdbarch_extra_stack_alignment_needed (gdbarch, 0);
+
+ /* Helpful for backtracing and returning in a call dummy. */
+ set_gdbarch_save_dummy_frame_tos (gdbarch, generic_save_dummy_frame_tos);
+
+ /* Use target_specific function to define link map offsets. */
+ set_solib_svr4_fetch_link_map_offsets
+ (gdbarch, cris_linux_svr4_fetch_link_map_offsets);
+
+ return gdbarch;
+}
diff --git a/gdb/mcore-tdep.c b/gdb/mcore-tdep.c
new file mode 100644
index 0000000..395bb44
--- /dev/null
+++ b/gdb/mcore-tdep.c
@@ -0,0 +1,1180 @@
+/* Target-machine dependent code for Motorola MCore for GDB, the GNU debugger
+ Copyright 1999, 2000, 2001 Free Software Foundation, Inc.
+
+ 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 2 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, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+#include "defs.h"
+#include "frame.h"
+#include "symtab.h"
+#include "value.h"
+#include "gdbcmd.h"
+#include "regcache.h"
+#include "symfile.h"
+#include "gdbcore.h"
+#include "inferior.h"
+#include "arch-utils.h"
+
+/* Functions declared and used only in this file */
+
+static CORE_ADDR mcore_analyze_prologue (struct frame_info *fi, CORE_ADDR pc, int skip_prologue);
+
+static struct frame_info *analyze_dummy_frame (CORE_ADDR pc, CORE_ADDR frame);
+
+static int get_insn (CORE_ADDR pc);
+
+/* Functions exported from this file */
+
+int mcore_use_struct_convention (int gcc_p, struct type *type);
+
+void _initialize_mcore (void);
+
+void mcore_init_extra_frame_info (int fromleaf, struct frame_info *fi);
+
+CORE_ADDR mcore_frame_saved_pc (struct frame_info *fi);
+
+CORE_ADDR mcore_find_callers_reg (struct frame_info *fi, int regnum);
+
+CORE_ADDR mcore_frame_args_address (struct frame_info *fi);
+
+CORE_ADDR mcore_frame_locals_address (struct frame_info *fi);
+
+CORE_ADDR mcore_push_return_address (CORE_ADDR pc, CORE_ADDR sp);
+
+CORE_ADDR mcore_push_arguments (int nargs, struct value ** args, CORE_ADDR sp,
+ int struct_return, CORE_ADDR struct_addr);
+
+void mcore_pop_frame ();
+
+CORE_ADDR mcore_skip_prologue (CORE_ADDR pc);
+
+CORE_ADDR mcore_frame_chain (struct frame_info *fi);
+
+const unsigned char *mcore_breakpoint_from_pc (CORE_ADDR * bp_addr, int *bp_size);
+
+int mcore_use_struct_convention (int gcc_p, struct type *type);
+
+void mcore_store_return_value (struct type *type, char *valbuf);
+
+CORE_ADDR mcore_extract_struct_value_address (char *regbuf);
+
+void mcore_extract_return_value (struct type *type, char *regbuf, char *valbuf);
+
+#ifdef MCORE_DEBUG
+int mcore_debug = 0;
+#endif
+
+
+/* All registers are 4 bytes long. */
+#define MCORE_REG_SIZE 4
+#define MCORE_NUM_REGS 65
+
+/* Some useful register numbers. */
+#define PR_REGNUM 15
+#define FIRST_ARGREG 2
+#define LAST_ARGREG 7
+#define RETVAL_REGNUM 2
+
+
+/* Additional info that we use for managing frames */
+struct frame_extra_info
+ {
+ /* A generic status word */
+ int status;
+
+ /* Size of this frame */
+ int framesize;
+
+ /* The register that is acting as a frame pointer, if
+ it is being used. This is undefined if status
+ does not contain the flag MY_FRAME_IN_FP. */
+ int fp_regnum;
+ };
+
+/* frame_extra_info status flags */
+
+/* The base of the current frame is actually in the stack pointer.
+ This happens when there is no frame pointer (MCore ABI does not
+ require a frame pointer) or when we're stopped in the prologue or
+ epilogue itself. In these cases, mcore_analyze_prologue will need
+ to update fi->frame before returning or analyzing the register
+ save instructions. */
+#define MY_FRAME_IN_SP 0x1
+
+/* The base of the current frame is in a frame pointer register.
+ This register is noted in frame_extra_info->fp_regnum.
+
+ Note that the existence of an FP might also indicate that the
+ function has called alloca. */
+#define MY_FRAME_IN_FP 0x2
+
+/* This flag is set to indicate that this frame is the top-most
+ frame. This tells frame chain not to bother trying to unwind
+ beyond this frame. */
+#define NO_MORE_FRAMES 0x4
+
+/* Instruction macros used for analyzing the prologue */
+#define IS_SUBI0(x) (((x) & 0xfe0f) == 0x2400) /* subi r0,oimm5 */
+#define IS_STM(x) (((x) & 0xfff0) == 0x0070) /* stm rf-r15,r0 */
+#define IS_STWx0(x) (((x) & 0xf00f) == 0x9000) /* stw rz,(r0,disp) */
+#define IS_STWxy(x) (((x) & 0xf000) == 0x9000) /* stw rx,(ry,disp) */
+#define IS_MOVx0(x) (((x) & 0xfff0) == 0x1200) /* mov rn,r0 */
+#define IS_LRW1(x) (((x) & 0xff00) == 0x7100) /* lrw r1,literal */
+#define IS_MOVI1(x) (((x) & 0xf80f) == 0x6001) /* movi r1,imm7 */
+#define IS_BGENI1(x) (((x) & 0xfe0f) == 0x3201) /* bgeni r1,imm5 */
+#define IS_BMASKI1(x) (((x) & 0xfe0f) == 0x2C01) /* bmaski r1,imm5 */
+#define IS_ADDI1(x) (((x) & 0xfe0f) == 0x2001) /* addi r1,oimm5 */
+#define IS_SUBI1(x) (((x) & 0xfe0f) == 0x2401) /* subi r1,oimm5 */
+#define IS_RSUBI1(x) (((x) & 0xfe0f) == 0x2801) /* rsubi r1,imm5 */
+#define IS_NOT1(x) (((x) & 0xffff) == 0x01f1) /* not r1 */
+#define IS_ROTLI1(x) (((x) & 0xfe0f) == 0x3801) /* rotli r1,imm5 */
+#define IS_BSETI1(x) (((x) & 0xfe0f) == 0x3401) /* bseti r1,imm5 */
+#define IS_BCLRI1(x) (((x) & 0xfe0f) == 0x3001) /* bclri r1,imm5 */
+#define IS_IXH1(x) (((x) & 0xffff) == 0x1d11) /* ixh r1,r1 */
+#define IS_IXW1(x) (((x) & 0xffff) == 0x1511) /* ixw r1,r1 */
+#define IS_SUB01(x) (((x) & 0xffff) == 0x0510) /* subu r0,r1 */
+#define IS_RTS(x) (((x) & 0xffff) == 0x00cf) /* jmp r15 */
+
+#define IS_R1_ADJUSTER(x) \
+ (IS_ADDI1(x) || IS_SUBI1(x) || IS_ROTLI1(x) || IS_BSETI1(x) \
+ || IS_BCLRI1(x) || IS_RSUBI1(x) || IS_NOT1(x) \
+ || IS_IXH1(x) || IS_IXW1(x))
+
+
+#ifdef MCORE_DEBUG
+static void
+mcore_dump_insn (char *commnt, CORE_ADDR pc, int insn)
+{
+ if (mcore_debug)
+ {
+ printf_filtered ("MCORE: %s %08x %08x ",
+ commnt, (unsigned int) pc, (unsigned int) insn);
+ TARGET_PRINT_INSN (pc, &tm_print_insn_info);
+ printf_filtered ("\n");
+ }
+}
+#define mcore_insn_debug(args) { if (mcore_debug) printf_filtered args; }
+#else /* !MCORE_DEBUG */
+#define mcore_dump_insn(a,b,c) {}
+#define mcore_insn_debug(args) {}
+#endif
+
+
+static struct type *
+mcore_register_virtual_type (int regnum)
+{
+ if (regnum < 0 || regnum >= MCORE_NUM_REGS)
+ internal_error (__FILE__, __LINE__,
+ "mcore_register_virtual_type: illegal register number %d",
+ regnum);
+ else
+ return builtin_type_int;
+}
+
+static int
+mcore_register_byte (int regnum)
+{
+ if (regnum < 0 || regnum >= MCORE_NUM_REGS)
+ internal_error (__FILE__, __LINE__,
+ "mcore_register_byte: illegal register number %d",
+ regnum);
+ else
+ return (regnum * MCORE_REG_SIZE);
+}
+
+static int
+mcore_register_size (int regnum)
+{
+
+ if (regnum < 0 || regnum >= MCORE_NUM_REGS)
+ internal_error (__FILE__, __LINE__,
+ "mcore_register_size: illegal register number %d",
+ regnum);
+ else
+ return MCORE_REG_SIZE;
+}
+
+/* The registers of the Motorola MCore processors */
+
+static const char *
+mcore_register_name (int regnum)
+{
+
+ static char *register_names[] = {
+ "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
+ "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
+ "ar0", "ar1", "ar2", "ar3", "ar4", "ar5", "ar6", "ar7",
+ "ar8", "ar9", "ar10", "ar11", "ar12", "ar13", "ar14", "ar15",
+ "psr", "vbr", "epsr", "fpsr", "epc", "fpc", "ss0", "ss1",
+ "ss2", "ss3", "ss4", "gcr", "gsr", "cr13", "cr14", "cr15",
+ "cr16", "cr17", "cr18", "cr19", "cr20", "cr21", "cr22", "cr23",
+ "cr24", "cr25", "cr26", "cr27", "cr28", "cr29", "cr30", "cr31",
+ "pc"
+ };
+
+ if (regnum < 0 ||
+ regnum >= sizeof (register_names) / sizeof (register_names[0]))
+ internal_error (__FILE__, __LINE__,
+ "mcore_register_name: illegal register number %d",
+ regnum);
+ else
+ return register_names[regnum];
+}
+
+/* Given the address at which to insert a breakpoint (BP_ADDR),
+ what will that breakpoint be?
+
+ For MCore, we have a breakpoint instruction. Since all MCore
+ instructions are 16 bits, this is all we need, regardless of
+ address. bpkt = 0x0000 */
+
+const unsigned char *
+mcore_breakpoint_from_pc (CORE_ADDR * bp_addr, int *bp_size)
+{
+ static char breakpoint[] =
+ {0x00, 0x00};
+ *bp_size = 2;
+ return breakpoint;
+}
+
+static CORE_ADDR
+mcore_saved_pc_after_call (struct frame_info *frame)
+{
+ return read_register (PR_REGNUM);
+}
+
+/* This is currently handled by init_extra_frame_info. */
+static void
+mcore_frame_init_saved_regs (struct frame_info *frame)
+{
+
+}
+
+/* This is currently handled by mcore_push_arguments */
+static void
+mcore_store_struct_return (CORE_ADDR addr, CORE_ADDR sp)
+{
+
+}
+
+static int
+mcore_reg_struct_has_addr (int gcc_p, struct type *type)
+{
+ return 0;
+}
+
+
+/* Helper function for several routines below. This funtion simply
+ sets up a fake, aka dummy, frame (not a _call_ dummy frame) that
+ we can analyze with mcore_analyze_prologue. */
+
+static struct frame_info *
+analyze_dummy_frame (CORE_ADDR pc, CORE_ADDR frame)
+{
+ static struct frame_info *dummy = NULL;
+
+ if (dummy == NULL)
+ {
+ dummy = (struct frame_info *) xmalloc (sizeof (struct frame_info));
+ dummy->saved_regs = (CORE_ADDR *) xmalloc (SIZEOF_FRAME_SAVED_REGS);
+ dummy->extra_info =
+ (struct frame_extra_info *) xmalloc (sizeof (struct frame_extra_info));
+ }
+
+ dummy->next = NULL;
+ dummy->prev = NULL;
+ dummy->pc = pc;
+ dummy->frame = frame;
+ dummy->extra_info->status = 0;
+ dummy->extra_info->framesize = 0;
+ memset (dummy->saved_regs, '\000', SIZEOF_FRAME_SAVED_REGS);
+ mcore_analyze_prologue (dummy, 0, 0);
+ return dummy;
+}
+
+/* Function prologues on the Motorola MCore processors consist of:
+
+ - adjustments to the stack pointer (r1 used as scratch register)
+ - store word/multiples that use r0 as the base address
+ - making a copy of r0 into another register (a "frame" pointer)
+
+ Note that the MCore really doesn't have a real frame pointer.
+ Instead, the compiler may copy the SP into a register (usually
+ r8) to act as an arg pointer. For our target-dependent purposes,
+ the frame info's "frame" member will be the beginning of the
+ frame. The SP could, in fact, point below this.
+
+ The prologue ends when an instruction fails to meet either of
+ the first two criteria or when an FP is made. We make a special
+ exception for gcc. When compiling unoptimized code, gcc will
+ setup stack slots. We need to make sure that we skip the filling
+ of these stack slots as much as possible. This is only done
+ when SKIP_PROLOGUE is set, so that it does not mess up
+ backtraces. */
+
+/* Analyze the prologue of frame FI to determine where registers are saved,
+ the end of the prologue, etc. Return the address of the first line
+ of "real" code (i.e., the end of the prologue). */
+
+static CORE_ADDR
+mcore_analyze_prologue (struct frame_info *fi, CORE_ADDR pc, int skip_prologue)
+{
+ CORE_ADDR func_addr, func_end, addr, stop;
+ CORE_ADDR stack_size;
+ int insn, rn;
+ int status;
+ int fp_regnum = 0; /* dummy, valid when (flags & MY_FRAME_IN_FP) */
+ int flags;
+ int framesize;
+ int register_offsets[NUM_REGS];
+ char *name;
+
+ /* If provided, use the PC in the frame to look up the
+ start of this function. */
+ pc = (fi == NULL ? pc : fi->pc);
+
+ /* Find the start of this function. */
+ status = find_pc_partial_function (pc, &name, &func_addr, &func_end);
+
+ /* If the start of this function could not be found or if the debbuger
+ is stopped at the first instruction of the prologue, do nothing. */
+ if (status == 0)
+ return pc;
+
+ /* If the debugger is entry function, give up. */
+ if (func_addr == entry_point_address ())
+ {
+ if (fi != NULL)
+ fi->extra_info->status |= NO_MORE_FRAMES;
+ return pc;
+ }
+
+ /* At the start of a function, our frame is in the stack pointer. */
+ flags = MY_FRAME_IN_SP;
+
+ /* Start decoding the prologue. We start by checking two special cases:
+
+ 1. We're about to return
+ 2. We're at the first insn of the prologue.
+
+ If we're about to return, our frame has already been deallocated.
+ If we are stopped at the first instruction of a prologue,
+ then our frame has not yet been set up. */
+
+ /* Get the first insn from memory (all MCore instructions are 16 bits) */
+ mcore_insn_debug (("MCORE: starting prologue decoding\n"));
+ insn = get_insn (pc);
+ mcore_dump_insn ("got 1: ", pc, insn);
+
+ /* Check for return. */
+ if (fi != NULL && IS_RTS (insn))
+ {
+ mcore_insn_debug (("MCORE: got jmp r15"));
+ if (fi->next == NULL)
+ fi->frame = read_sp ();
+ return fi->pc;
+ }
+
+ /* Check for first insn of prologue */
+ if (fi != NULL && fi->pc == func_addr)
+ {
+ if (fi->next == NULL)
+ fi->frame = read_sp ();
+ return fi->pc;
+ }
+
+ /* Figure out where to stop scanning */
+ stop = (fi ? fi->pc : func_end);
+
+ /* Don't walk off the end of the function */
+ stop = (stop > func_end ? func_end : stop);
+
+ /* REGISTER_OFFSETS will contain offsets, from the top of the frame
+ (NOT the frame pointer), for the various saved registers or -1
+ if the register is not saved. */
+ for (rn = 0; rn < NUM_REGS; rn++)
+ register_offsets[rn] = -1;
+
+ /* Analyze the prologue. Things we determine from analyzing the
+ prologue include:
+ * the size of the frame
+ * where saved registers are located (and which are saved)
+ * FP used? */
+ mcore_insn_debug (("MCORE: Scanning prologue: func_addr=0x%x, stop=0x%x\n",
+ (unsigned int) func_addr, (unsigned int) stop));
+
+ framesize = 0;
+ for (addr = func_addr; addr < stop; addr += 2)
+ {
+ /* Get next insn */
+ insn = get_insn (addr);
+ mcore_dump_insn ("got 2: ", addr, insn);
+
+ if (IS_SUBI0 (insn))
+ {
+ int offset = 1 + ((insn >> 4) & 0x1f);
+ mcore_insn_debug (("MCORE: got subi r0,%d; continuing\n", offset));
+ framesize += offset;
+ continue;
+ }
+ else if (IS_STM (insn))
+ {
+ /* Spill register(s) */
+ int offset;
+ int start_register;
+
+ /* BIG WARNING! The MCore ABI does not restrict functions
+ to taking only one stack allocation. Therefore, when
+ we save a register, we record the offset of where it was
+ saved relative to the current framesize. This will
+ then give an offset from the SP upon entry to our
+ function. Remember, framesize is NOT constant until
+ we're done scanning the prologue. */
+ start_register = (insn & 0xf);
+ mcore_insn_debug (("MCORE: got stm r%d-r15,(r0)\n", start_register));
+
+ for (rn = start_register, offset = 0; rn <= 15; rn++, offset += 4)
+ {
+ register_offsets[rn] = framesize - offset;
+ mcore_insn_debug (("MCORE: r%d saved at 0x%x (offset %d)\n", rn,
+ register_offsets[rn], offset));
+ }
+ mcore_insn_debug (("MCORE: continuing\n"));
+ continue;
+ }
+ else if (IS_STWx0 (insn))
+ {
+ /* Spill register: see note for IS_STM above. */
+ int imm;
+
+ rn = (insn >> 8) & 0xf;
+ imm = (insn >> 4) & 0xf;
+ register_offsets[rn] = framesize - (imm << 2);
+ mcore_insn_debug (("MCORE: r%d saved at offset 0x%x\n", rn, register_offsets[rn]));
+ mcore_insn_debug (("MCORE: continuing\n"));
+ continue;
+ }
+ else if (IS_MOVx0 (insn))
+ {
+ /* We have a frame pointer, so this prologue is over. Note
+ the register which is acting as the frame pointer. */
+ flags |= MY_FRAME_IN_FP;
+ flags &= ~MY_FRAME_IN_SP;
+ fp_regnum = insn & 0xf;
+ mcore_insn_debug (("MCORE: Found a frame pointer: r%d\n", fp_regnum));
+
+ /* If we found an FP, we're at the end of the prologue. */
+ mcore_insn_debug (("MCORE: end of prologue\n"));
+ if (skip_prologue)
+ continue;
+
+ /* If we're decoding prologue, stop here. */
+ addr += 2;
+ break;
+ }
+ else if (IS_STWxy (insn) && (flags & MY_FRAME_IN_FP) && ((insn & 0xf) == fp_regnum))
+ {
+ /* Special case. Skip over stack slot allocs, too. */
+ mcore_insn_debug (("MCORE: push arg onto stack.\n"));
+ continue;
+ }
+ else if (IS_LRW1 (insn) || IS_MOVI1 (insn)
+ || IS_BGENI1 (insn) || IS_BMASKI1 (insn))
+ {
+ int adjust = 0;
+ int offset = 0;
+ int insn2;
+
+ mcore_insn_debug (("MCORE: looking at large frame\n"));
+ if (IS_LRW1 (insn))
+ {
+ adjust =
+ read_memory_integer ((addr + 2 + ((insn & 0xff) << 2)) & 0xfffffffc, 4);
+ }
+ else if (IS_MOVI1 (insn))
+ adjust = (insn >> 4) & 0x7f;
+ else if (IS_BGENI1 (insn))
+ adjust = 1 << ((insn >> 4) & 0x1f);
+ else /* IS_BMASKI (insn) */
+ adjust = (1 << (adjust >> 4) & 0x1f) - 1;
+
+ mcore_insn_debug (("MCORE: base framesize=0x%x\n", adjust));
+
+ /* May have zero or more insns which modify r1 */
+ mcore_insn_debug (("MCORE: looking for r1 adjusters...\n"));
+ offset = 2;
+ insn2 = get_insn (addr + offset);
+ while (IS_R1_ADJUSTER (insn2))
+ {
+ int imm;
+
+ imm = (insn2 >> 4) & 0x1f;
+ mcore_dump_insn ("got 3: ", addr + offset, insn);
+ if (IS_ADDI1 (insn2))
+ {
+ adjust += (imm + 1);
+ mcore_insn_debug (("MCORE: addi r1,%d\n", imm + 1));
+ }
+ else if (IS_SUBI1 (insn2))
+ {
+ adjust -= (imm + 1);
+ mcore_insn_debug (("MCORE: subi r1,%d\n", imm + 1));
+ }
+ else if (IS_RSUBI1 (insn2))
+ {
+ adjust = imm - adjust;
+ mcore_insn_debug (("MCORE: rsubi r1,%d\n", imm + 1));
+ }
+ else if (IS_NOT1 (insn2))
+ {
+ adjust = ~adjust;
+ mcore_insn_debug (("MCORE: not r1\n"));
+ }
+ else if (IS_ROTLI1 (insn2))
+ {
+ adjust <<= imm;
+ mcore_insn_debug (("MCORE: rotli r1,%d\n", imm + 1));
+ }
+ else if (IS_BSETI1 (insn2))
+ {
+ adjust |= (1 << imm);
+ mcore_insn_debug (("MCORE: bseti r1,%d\n", imm));
+ }
+ else if (IS_BCLRI1 (insn2))
+ {
+ adjust &= ~(1 << imm);
+ mcore_insn_debug (("MCORE: bclri r1,%d\n", imm));
+ }
+ else if (IS_IXH1 (insn2))
+ {
+ adjust *= 3;
+ mcore_insn_debug (("MCORE: ix.h r1,r1\n"));
+ }
+ else if (IS_IXW1 (insn2))
+ {
+ adjust *= 5;
+ mcore_insn_debug (("MCORE: ix.w r1,r1\n"));
+ }
+
+ offset += 2;
+ insn2 = get_insn (addr + offset);
+ };
+
+ mcore_insn_debug (("MCORE: done looking for r1 adjusters\n"));
+
+ /* If the next insn adjusts the stack pointer, we keep everything;
+ if not, we scrap it and we've found the end of the prologue. */
+ if (IS_SUB01 (insn2))
+ {
+ addr += offset;
+ framesize += adjust;
+ mcore_insn_debug (("MCORE: found stack adjustment of 0x%x bytes.\n", adjust));
+ mcore_insn_debug (("MCORE: skipping to new address 0x%x\n", addr));
+ mcore_insn_debug (("MCORE: continuing\n"));
+ continue;
+ }
+
+ /* None of these instructions are prologue, so don't touch
+ anything. */
+ mcore_insn_debug (("MCORE: no subu r1,r0, NOT altering framesize.\n"));
+ break;
+ }
+
+ /* This is not a prologue insn, so stop here. */
+ mcore_insn_debug (("MCORE: insn is not a prologue insn -- ending scan\n"));
+ break;
+ }
+
+ mcore_insn_debug (("MCORE: done analyzing prologue\n"));
+ mcore_insn_debug (("MCORE: prologue end = 0x%x\n", addr));
+
+ /* Save everything we have learned about this frame into FI. */
+ if (fi != NULL)
+ {
+ fi->extra_info->framesize = framesize;
+ fi->extra_info->fp_regnum = fp_regnum;
+ fi->extra_info->status = flags;
+
+ /* Fix the frame pointer. When gcc uses r8 as a frame pointer,
+ it is really an arg ptr. We adjust fi->frame to be a "real"
+ frame pointer. */
+ if (fi->next == NULL)
+ {
+ if (fi->extra_info->status & MY_FRAME_IN_SP)
+ fi->frame = read_sp () + framesize;
+ else
+ fi->frame = read_register (fp_regnum) + framesize;
+ }
+
+ /* Note where saved registers are stored. The offsets in REGISTER_OFFSETS
+ are computed relative to the top of the frame. */
+ for (rn = 0; rn < NUM_REGS; rn++)
+ {
+ if (register_offsets[rn] >= 0)
+ {
+ fi->saved_regs[rn] = fi->frame - register_offsets[rn];
+ mcore_insn_debug (("Saved register %s stored at 0x%08x, value=0x%08x\n",
+ mcore_register_names[rn], fi->saved_regs[rn],
+ read_memory_integer (fi->saved_regs[rn], 4)));
+ }
+ }
+ }
+
+ /* Return addr of first non-prologue insn. */
+ return addr;
+}
+
+/* Given a GDB frame, determine the address of the calling function's frame.
+ This will be used to create a new GDB frame struct, and then
+ INIT_EXTRA_FRAME_INFO and INIT_FRAME_PC will be called for the new frame. */
+
+CORE_ADDR
+mcore_frame_chain (struct frame_info * fi)
+{
+ struct frame_info *dummy;
+ CORE_ADDR callers_addr;
+
+ /* Analyze the prologue of this function. */
+ if (fi->extra_info->status == 0)
+ mcore_analyze_prologue (fi, 0, 0);
+
+ /* If mcore_analyze_prologue set NO_MORE_FRAMES, quit now. */
+ if (fi->extra_info->status & NO_MORE_FRAMES)
+ return 0;
+
+ /* Now that we've analyzed our prologue, we can start to ask
+ for information about our caller. The easiest way to do
+ this is to analyze our caller's prologue.
+
+ If our caller has a frame pointer, then we need to find
+ the value of that register upon entry to our frame.
+ This value is either in fi->saved_regs[rn] if it's saved,
+ or it's still in a register.
+
+ If our caller does not have a frame pointer, then his frame base
+ is <our base> + -<caller's frame size>. */
+ dummy = analyze_dummy_frame (FRAME_SAVED_PC (fi), fi->frame);
+
+ if (dummy->extra_info->status & MY_FRAME_IN_FP)
+ {
+ int fp = dummy->extra_info->fp_regnum;
+
+ /* Our caller has a frame pointer. */
+ if (fi->saved_regs[fp] != 0)
+ {
+ /* The "FP" was saved on the stack. Don't forget to adjust
+ the "FP" with the framesize to get a real FP. */
+ callers_addr = read_memory_integer (fi->saved_regs[fp], REGISTER_SIZE)
+ + dummy->extra_info->framesize;
+ }
+ else
+ {
+ /* It's still in the register. Don't forget to adjust
+ the "FP" with the framesize to get a real FP. */
+ callers_addr = read_register (fp) + dummy->extra_info->framesize;
+ }
+ }
+ else
+ {
+ /* Our caller does not have a frame pointer. */
+ callers_addr = fi->frame + dummy->extra_info->framesize;
+ }
+
+ return callers_addr;
+}
+
+/* Skip the prologue of the function at PC. */
+
+CORE_ADDR
+mcore_skip_prologue (CORE_ADDR pc)
+{
+ CORE_ADDR func_addr, func_end;
+ struct symtab_and_line sal;
+
+ /* If we have line debugging information, then the end of the
+ prologue should be 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 && sal.end < func_end)
+ return sal.end;
+ }
+
+ return mcore_analyze_prologue (NULL, pc, 1);
+}
+
+/* Return the address at which function arguments are offset. */
+CORE_ADDR
+mcore_frame_args_address (struct frame_info * fi)
+{
+ return fi->frame - fi->extra_info->framesize;
+}
+
+CORE_ADDR
+mcore_frame_locals_address (struct frame_info * fi)
+{
+ return fi->frame - fi->extra_info->framesize;
+}
+
+/* Return the frame pointer in use at address PC. */
+
+void
+mcore_virtual_frame_pointer (CORE_ADDR pc, int *reg, LONGEST *offset)
+{
+ struct frame_info *dummy = analyze_dummy_frame (pc, 0);
+ if (dummy->extra_info->status & MY_FRAME_IN_SP)
+ {
+ *reg = SP_REGNUM;
+ *offset = 0;
+ }
+ else
+ {
+ *reg = dummy->extra_info->fp_regnum;
+ *offset = 0;
+ }
+}
+
+/* Find the value of register REGNUM in frame FI. */
+
+CORE_ADDR
+mcore_find_callers_reg (struct frame_info *fi, int regnum)
+{
+ for (; fi != NULL; fi = fi->next)
+ {
+ if (PC_IN_CALL_DUMMY (fi->pc, fi->frame, fi->frame))
+ return deprecated_read_register_dummy (fi->pc, fi->frame, regnum);
+ else if (fi->saved_regs[regnum] != 0)
+ return read_memory_integer (fi->saved_regs[regnum],
+ REGISTER_SIZE);
+ }
+
+ return read_register (regnum);
+}
+
+/* Find the saved pc in frame FI. */
+
+CORE_ADDR
+mcore_frame_saved_pc (struct frame_info * fi)
+{
+
+ if (PC_IN_CALL_DUMMY (fi->pc, fi->frame, fi->frame))
+ return deprecated_read_register_dummy (fi->pc, fi->frame, PC_REGNUM);
+ else
+ return mcore_find_callers_reg (fi, PR_REGNUM);
+}
+
+/* INFERIOR FUNCTION CALLS */
+
+/* This routine gets called when either the user uses the "return"
+ command, or the call dummy breakpoint gets hit. */
+
+void
+mcore_pop_frame (void)
+{
+ int rn;
+ struct frame_info *fi = get_current_frame ();
+
+ if (PC_IN_CALL_DUMMY (fi->pc, fi->frame, fi->frame))
+ generic_pop_dummy_frame ();
+ else
+ {
+ /* Write out the PC we saved. */
+ write_register (PC_REGNUM, FRAME_SAVED_PC (fi));
+
+ /* Restore any saved registers. */
+ for (rn = 0; rn < NUM_REGS; rn++)
+ {
+ if (fi->saved_regs[rn] != 0)
+ {
+ ULONGEST value;
+
+ value = read_memory_unsigned_integer (fi->saved_regs[rn],
+ REGISTER_SIZE);
+ write_register (rn, value);
+ }
+ }
+
+ /* Actually cut back the stack. */
+ write_register (SP_REGNUM, FRAME_FP (fi));
+ }
+
+ /* Finally, throw away any cached frame information. */
+ flush_cached_frames ();
+}
+
+/* Setup arguments and PR for a call to the target. First six arguments
+ go in FIRST_ARGREG -> LAST_ARGREG, subsequent args go on to the stack.
+
+ * Types with lengths greater than REGISTER_SIZE may not be split
+ between registers and the stack, and they must start in an even-numbered
+ register. Subsequent args will go onto the stack.
+
+ * Structs may be split between registers and stack, left-aligned.
+
+ * If the function returns a struct which will not fit into registers (it's
+ more than eight bytes), we must allocate for that, too. Gdb will tell
+ us where this buffer is (STRUCT_ADDR), and we simply place it into
+ FIRST_ARGREG, since the MCORE treats struct returns (of less than eight
+ bytes) as hidden first arguments. */
+
+CORE_ADDR
+mcore_push_arguments (int nargs, struct value **args, CORE_ADDR sp,
+ int struct_return, CORE_ADDR struct_addr)
+{
+ int argreg;
+ int argnum;
+ struct stack_arg
+ {
+ int len;
+ char *val;
+ }
+ *stack_args;
+ int nstack_args = 0;
+
+ stack_args = (struct stack_arg *) alloca (nargs * sizeof (struct stack_arg));
+
+ argreg = FIRST_ARGREG;
+
+ /* Align the stack. This is mostly a nop, but not always. It will be needed
+ if we call a function which has argument overflow. */
+ sp &= ~3;
+
+ /* If this function returns a struct which does not fit in the
+ return registers, we must pass a buffer to the function
+ which it can use to save the return value. */
+ if (struct_return)
+ write_register (argreg++, struct_addr);
+
+ /* FIXME: what about unions? */
+ for (argnum = 0; argnum < nargs; argnum++)
+ {
+ char *val = (char *) VALUE_CONTENTS (args[argnum]);
+ int len = TYPE_LENGTH (VALUE_TYPE (args[argnum]));
+ struct type *type = VALUE_TYPE (args[argnum]);
+ int olen;
+
+ mcore_insn_debug (("MCORE PUSH: argreg=%d; len=%d; %s\n",
+ argreg, len, TYPE_CODE (type) == TYPE_CODE_STRUCT ? "struct" : "not struct"));
+ /* Arguments larger than a register must start in an even
+ numbered register. */
+ olen = len;
+
+ if (TYPE_CODE (type) != TYPE_CODE_STRUCT && len > REGISTER_SIZE && argreg % 2)
+ {
+ mcore_insn_debug (("MCORE PUSH: %d > REGISTER_SIZE: and %s is not even\n",
+ len, mcore_register_names[argreg]));
+ argreg++;
+ }
+
+ if ((argreg <= LAST_ARGREG && len <= (LAST_ARGREG - argreg + 1) * REGISTER_SIZE)
+ || (TYPE_CODE (type) == TYPE_CODE_STRUCT))
+ {
+ /* Something that will fit entirely into registers (or a struct
+ which may be split between registers and stack). */
+ mcore_insn_debug (("MCORE PUSH: arg %d going into regs\n", argnum));
+
+ if (TYPE_CODE (type) == TYPE_CODE_STRUCT && olen < REGISTER_SIZE)
+ {
+ /* Small structs must be right aligned within the register,
+ the most significant bits are undefined. */
+ write_register (argreg, extract_unsigned_integer (val, len));
+ argreg++;
+ len = 0;
+ }
+
+ while (len > 0 && argreg <= LAST_ARGREG)
+ {
+ write_register (argreg, extract_unsigned_integer (val, REGISTER_SIZE));
+ argreg++;
+ val += REGISTER_SIZE;
+ len -= REGISTER_SIZE;
+ }
+
+ /* Any remainder for the stack is noted below... */
+ }
+ else if (TYPE_CODE (VALUE_TYPE (args[argnum])) != TYPE_CODE_STRUCT
+ && len > REGISTER_SIZE)
+ {
+ /* All subsequent args go onto the stack. */
+ mcore_insn_debug (("MCORE PUSH: does not fit into regs, going onto stack\n"));
+ argnum = LAST_ARGREG + 1;
+ }
+
+ if (len > 0)
+ {
+ /* Note that this must be saved onto the stack */
+ mcore_insn_debug (("MCORE PUSH: adding arg %d to stack\n", argnum));
+ stack_args[nstack_args].val = val;
+ stack_args[nstack_args].len = len;
+ nstack_args++;
+ }
+
+ }
+
+ /* We're done with registers and stack allocation. Now do the actual
+ stack pushes. */
+ while (nstack_args--)
+ {
+ sp -= stack_args[nstack_args].len;
+ write_memory (sp, stack_args[nstack_args].val, stack_args[nstack_args].len);
+ }
+
+ /* Return adjusted stack pointer. */
+ return sp;
+}
+
+/* Store the return address for the call dummy. For MCore, we've
+ opted to use generic call dummies, so we simply store the
+ CALL_DUMMY_ADDRESS into the PR register (r15). */
+
+CORE_ADDR
+mcore_push_return_address (CORE_ADDR pc, CORE_ADDR sp)
+{
+ write_register (PR_REGNUM, CALL_DUMMY_ADDRESS ());
+ return sp;
+}
+
+/* Setting/getting return values from functions.
+
+ The Motorola MCore processors use r2/r3 to return anything
+ not larger than 32 bits. Everything else goes into a caller-
+ supplied buffer, which is passed in via a hidden first
+ argument.
+
+ For gdb, this leaves us two routes, based on what
+ USE_STRUCT_CONVENTION (mcore_use_struct_convention) returns.
+ If this macro returns 1, gdb will call STORE_STRUCT_RETURN and
+ EXTRACT_STRUCT_VALUE_ADDRESS.
+
+ If USE_STRUCT_CONVENTION retruns 0, then gdb uses STORE_RETURN_VALUE
+ and EXTRACT_RETURN_VALUE to store/fetch the functions return value. */
+
+/* Should we use EXTRACT_STRUCT_VALUE_ADDRESS instead of
+ EXTRACT_RETURN_VALUE? GCC_P is true if compiled with gcc
+ and TYPE is the type (which is known to be struct, union or array). */
+
+int
+mcore_use_struct_convention (int gcc_p, struct type *type)
+{
+ return (TYPE_LENGTH (type) > 8);
+}
+
+/* Where is the return value saved? For MCore, a pointer to
+ this buffer was passed as a hidden first argument, so
+ just return that address. */
+
+CORE_ADDR
+mcore_extract_struct_value_address (char *regbuf)
+{
+ return extract_address (regbuf + REGISTER_BYTE (FIRST_ARGREG), REGISTER_SIZE);
+}
+
+/* Given a function which returns a value of type TYPE, extract the
+ the function's return value and place the result into VALBUF.
+ REGBUF is the register contents of the target. */
+
+void
+mcore_extract_return_value (struct type *type, char *regbuf, char *valbuf)
+{
+ /* Copy the return value (starting) in RETVAL_REGNUM to VALBUF. */
+ /* Only getting the first byte! if len = 1, we need the last byte of
+ the register, not the first. */
+ memcpy (valbuf, regbuf + REGISTER_BYTE (RETVAL_REGNUM) +
+ (TYPE_LENGTH (type) < 4 ? 4 - TYPE_LENGTH (type) : 0), TYPE_LENGTH (type));
+}
+
+/* Store the return value in VALBUF (of type TYPE) where the caller
+ expects to see it.
+
+ Values less than 32 bits are stored in r2, right justified and
+ sign or zero extended.
+
+ Values between 32 and 64 bits are stored in r2 (most
+ significant word) and r3 (least significant word, left justified).
+ Note that this includes structures of less than eight bytes, too. */
+
+void
+mcore_store_return_value (struct type *type, char *valbuf)
+{
+ int value_size;
+ int return_size;
+ int offset;
+ char *zeros;
+
+ value_size = TYPE_LENGTH (type);
+
+ /* Return value fits into registers. */
+ return_size = (value_size + REGISTER_SIZE - 1) & ~(REGISTER_SIZE - 1);
+ offset = REGISTER_BYTE (RETVAL_REGNUM) + (return_size - value_size);
+ zeros = alloca (return_size);
+ memset (zeros, 0, return_size);
+
+ write_register_bytes (REGISTER_BYTE (RETVAL_REGNUM), zeros, return_size);
+ write_register_bytes (offset, valbuf, value_size);
+}
+
+/* Initialize our target-dependent "stuff" for this newly created frame.
+
+ This includes allocating space for saved registers and analyzing
+ the prologue of this frame. */
+
+void
+mcore_init_extra_frame_info (int fromleaf, struct frame_info *fi)
+{
+ if (fi && fi->next)
+ fi->pc = FRAME_SAVED_PC (fi->next);
+
+ frame_saved_regs_zalloc (fi);
+
+ fi->extra_info = (struct frame_extra_info *)
+ frame_obstack_alloc (sizeof (struct frame_extra_info));
+ fi->extra_info->status = 0;
+ fi->extra_info->framesize = 0;
+
+ if (PC_IN_CALL_DUMMY (fi->pc, fi->frame, fi->frame))
+ {
+ /* We need to setup fi->frame here because run_stack_dummy gets it wrong
+ by assuming it's always FP. */
+ fi->frame = deprecated_read_register_dummy (fi->pc, fi->frame, SP_REGNUM);
+ }
+ else
+ mcore_analyze_prologue (fi, 0, 0);
+}
+
+/* Get an insturction from memory. */
+
+static int
+get_insn (CORE_ADDR pc)
+{
+ char buf[4];
+ int status = read_memory_nobpt (pc, buf, 2);
+ if (status != 0)
+ return 0;
+
+ return extract_unsigned_integer (buf, 2);
+}
+
+static struct gdbarch *
+mcore_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
+{
+ static LONGEST call_dummy_words[7] = { };
+ struct gdbarch_tdep *tdep = NULL;
+ struct gdbarch *gdbarch;
+
+ /* find a candidate among the list of pre-declared architectures. */
+ arches = gdbarch_list_lookup_by_info (arches, &info);
+ if (arches != NULL)
+ return (arches->gdbarch);
+
+ gdbarch = gdbarch_alloc (&info, 0);
+
+ /* Registers: */
+
+ /* All registers are 32 bits */
+ set_gdbarch_register_size (gdbarch, MCORE_REG_SIZE);
+ set_gdbarch_max_register_raw_size (gdbarch, MCORE_REG_SIZE);
+ set_gdbarch_max_register_virtual_size (gdbarch, MCORE_REG_SIZE);
+ set_gdbarch_register_name (gdbarch, mcore_register_name);
+ set_gdbarch_register_virtual_type (gdbarch, mcore_register_virtual_type);
+ set_gdbarch_register_virtual_size (gdbarch, mcore_register_size);
+ set_gdbarch_register_raw_size (gdbarch, mcore_register_size);
+ set_gdbarch_register_byte (gdbarch, mcore_register_byte);
+ set_gdbarch_register_bytes (gdbarch, MCORE_REG_SIZE * MCORE_NUM_REGS);
+ set_gdbarch_num_regs (gdbarch, MCORE_NUM_REGS);
+ set_gdbarch_pc_regnum (gdbarch, 64);
+ set_gdbarch_sp_regnum (gdbarch, 0);
+ set_gdbarch_fp_regnum (gdbarch, 0);
+ set_gdbarch_get_saved_register (gdbarch, generic_unwind_get_saved_register);
+
+ /* Call Dummies: */
+
+ set_gdbarch_call_dummy_p (gdbarch, 1);
+ set_gdbarch_use_generic_dummy_frames (gdbarch, 1);
+ set_gdbarch_call_dummy_words (gdbarch, call_dummy_words);
+ set_gdbarch_sizeof_call_dummy_words (gdbarch, 0);
+ set_gdbarch_call_dummy_start_offset (gdbarch, 0);
+ set_gdbarch_call_dummy_breakpoint_offset_p (gdbarch, 1);
+ set_gdbarch_call_dummy_breakpoint_offset (gdbarch, 0);
+ set_gdbarch_call_dummy_location (gdbarch, AT_ENTRY_POINT);
+ set_gdbarch_fix_call_dummy (gdbarch, generic_fix_call_dummy);
+ set_gdbarch_call_dummy_address (gdbarch, entry_point_address);
+ set_gdbarch_save_dummy_frame_tos (gdbarch, generic_save_dummy_frame_tos);
+ set_gdbarch_pc_in_call_dummy (gdbarch, generic_pc_in_call_dummy);
+ set_gdbarch_call_dummy_stack_adjust_p (gdbarch, 0);
+ set_gdbarch_saved_pc_after_call (gdbarch, mcore_saved_pc_after_call);
+ set_gdbarch_function_start_offset (gdbarch, 0);
+ set_gdbarch_decr_pc_after_break (gdbarch, 0);
+ set_gdbarch_breakpoint_from_pc (gdbarch, mcore_breakpoint_from_pc);
+ set_gdbarch_push_return_address (gdbarch, mcore_push_return_address);
+ set_gdbarch_push_dummy_frame (gdbarch, generic_push_dummy_frame);
+ set_gdbarch_push_arguments (gdbarch, mcore_push_arguments);
+ set_gdbarch_call_dummy_length (gdbarch, 0);
+
+ /* Frames: */
+
+ set_gdbarch_init_extra_frame_info (gdbarch, mcore_init_extra_frame_info);
+ set_gdbarch_frame_chain (gdbarch, mcore_frame_chain);
+ set_gdbarch_frame_chain_valid (gdbarch, generic_func_frame_chain_valid);
+ set_gdbarch_frame_init_saved_regs (gdbarch, mcore_frame_init_saved_regs);
+ set_gdbarch_frame_saved_pc (gdbarch, mcore_frame_saved_pc);
+ set_gdbarch_deprecated_store_return_value (gdbarch, mcore_store_return_value);
+ set_gdbarch_deprecated_extract_return_value (gdbarch,
+ mcore_extract_return_value);
+ set_gdbarch_store_struct_return (gdbarch, mcore_store_struct_return);
+ set_gdbarch_deprecated_extract_struct_value_address (gdbarch,
+ mcore_extract_struct_value_address);
+ set_gdbarch_skip_prologue (gdbarch, mcore_skip_prologue);
+ set_gdbarch_frame_args_skip (gdbarch, 0);
+ set_gdbarch_frame_args_address (gdbarch, mcore_frame_args_address);
+ set_gdbarch_frame_locals_address (gdbarch, mcore_frame_locals_address);
+ set_gdbarch_frame_num_args (gdbarch, frame_num_args_unknown);
+ set_gdbarch_pop_frame (gdbarch, mcore_pop_frame);
+ set_gdbarch_virtual_frame_pointer (gdbarch, mcore_virtual_frame_pointer);
+
+ /* Misc.: */
+
+ /* Stack grows down. */
+ set_gdbarch_inner_than (gdbarch, core_addr_lessthan);
+ set_gdbarch_use_struct_convention (gdbarch, mcore_use_struct_convention);
+ set_gdbarch_believe_pcc_promotion (gdbarch, 1);
+ /* MCore will never pass a sturcture by reference. It will always be split
+ between registers and stack. */
+ set_gdbarch_reg_struct_has_addr (gdbarch, mcore_reg_struct_has_addr);
+
+ return gdbarch;
+}
+
+static void
+mcore_dump_tdep (struct gdbarch *current_gdbarch, struct ui_file *file)
+{
+
+}
+
+void
+_initialize_mcore_tdep (void)
+{
+ extern int print_insn_mcore (bfd_vma, disassemble_info *);
+ gdbarch_register (bfd_arch_mcore, mcore_gdbarch_init, mcore_dump_tdep);
+ tm_print_insn = print_insn_mcore;
+
+#ifdef MCORE_DEBUG
+ add_show_from_set (add_set_cmd ("mcoredebug", no_class,
+ var_boolean, (char *) &mcore_debug,
+ "Set mcore debugging.\n", &setlist),
+ &showlist);
+#endif
+}
diff --git a/gdb/ns32k-tdep.c b/gdb/ns32k-tdep.c
new file mode 100644
index 0000000..58c2e13
--- /dev/null
+++ b/gdb/ns32k-tdep.c
@@ -0,0 +1,626 @@
+/* Target dependent code for the NS32000, for GDB.
+ Copyright 1986, 1988, 1991, 1992, 1994, 1995, 1998, 1999, 2000, 2001,
+ 2002 Free Software Foundation, Inc.
+
+ 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 2 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, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include "defs.h"
+#include "frame.h"
+#include "gdbtypes.h"
+#include "gdbcore.h"
+#include "inferior.h"
+#include "regcache.h"
+#include "target.h"
+
+#include "arch-utils.h"
+
+#include "ns32k-tdep.h"
+
+static int sign_extend (int value, int bits);
+static CORE_ADDR ns32k_get_enter_addr (CORE_ADDR);
+static int ns32k_localcount (CORE_ADDR enter_pc);
+static void flip_bytes (void *, int);
+
+static const char *
+ns32k_register_name_32082 (int regno)
+{
+ static char *register_names[] =
+ {
+ "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
+ "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7",
+ "sp", "fp", "pc", "ps",
+ "l0", "l1", "l2", "l3", "xx",
+ };
+
+ if (regno < 0)
+ return NULL;
+ if (regno >= sizeof (register_names) / sizeof (*register_names))
+ return NULL;
+
+ return (register_names[regno]);
+}
+
+static const char *
+ns32k_register_name_32382 (int regno)
+{
+ static char *register_names[] =
+ {
+ "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
+ "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7",
+ "sp", "fp", "pc", "ps",
+ "fsr",
+ "l0", "l1", "l2", "l3", "l4", "l5", "l6", "l7", "xx",
+ };
+
+ if (regno < 0)
+ return NULL;
+ if (regno >= sizeof (register_names) / sizeof (*register_names))
+ return NULL;
+
+ return (register_names[regno]);
+}
+
+static int
+ns32k_register_byte_32082 (int regno)
+{
+ if (regno >= NS32K_LP0_REGNUM)
+ return (NS32K_LP0_REGNUM * 4) + ((regno - NS32K_LP0_REGNUM) * 8);
+
+ return (regno * 4);
+}
+
+static int
+ns32k_register_byte_32382 (int regno)
+{
+ /* This is a bit yuk. The even numbered double precision floating
+ point long registers occupy the same space as the even:odd numbered
+ single precision floating point registers, but the extra 32381 FPU
+ registers are at the end. Doing it this way is compatible for both
+ 32081 and 32381 equipped machines. */
+
+ return ((regno < NS32K_LP0_REGNUM ? regno
+ : (regno - NS32K_LP0_REGNUM) & 1 ? regno - 1
+ : (regno - NS32K_LP0_REGNUM + FP0_REGNUM)) * 4);
+}
+
+static int
+ns32k_register_raw_size (int regno)
+{
+ /* All registers are 4 bytes, except for the doubled floating
+ registers. */
+
+ return ((regno >= NS32K_LP0_REGNUM) ? 8 : 4);
+}
+
+static int
+ns32k_register_virtual_size (int regno)
+{
+ return ((regno >= NS32K_LP0_REGNUM) ? 8 : 4);
+}
+
+static struct type *
+ns32k_register_virtual_type (int regno)
+{
+ if (regno < FP0_REGNUM)
+ return (builtin_type_int);
+
+ if (regno < FP0_REGNUM + 8)
+ return (builtin_type_float);
+
+ if (regno < NS32K_LP0_REGNUM)
+ return (builtin_type_int);
+
+ return (builtin_type_double);
+}
+
+/* Immediately after a function call, return the saved PC. Can't
+ always go through the frames for this because on some systems,
+ the new frame is not set up until the new function executes some
+ instructions. */
+
+static CORE_ADDR
+ns32k_saved_pc_after_call (struct frame_info *frame)
+{
+ return (read_memory_integer (read_register (SP_REGNUM), 4));
+}
+
+/* Advance PC across any function entry prologue instructions
+ to reach some "real" code. */
+
+static CORE_ADDR
+umax_skip_prologue (CORE_ADDR pc)
+{
+ register unsigned char op = read_memory_integer (pc, 1);
+ if (op == 0x82)
+ {
+ op = read_memory_integer (pc + 2, 1);
+ if ((op & 0x80) == 0)
+ pc += 3;
+ else if ((op & 0xc0) == 0x80)
+ pc += 4;
+ else
+ pc += 6;
+ }
+ return pc;
+}
+
+static const unsigned char *
+ns32k_breakpoint_from_pc (CORE_ADDR *pcp, int *lenp)
+{
+ static const unsigned char breakpoint_insn[] = { 0xf2 };
+
+ *lenp = sizeof (breakpoint_insn);
+ return breakpoint_insn;
+}
+
+/* Return number of args passed to a frame.
+ Can return -1, meaning no way to tell.
+ Encore's C compiler often reuses same area on stack for args,
+ so this will often not work properly. If the arg names
+ are known, it's likely most of them will be printed. */
+
+static int
+umax_frame_num_args (struct frame_info *fi)
+{
+ int numargs;
+ CORE_ADDR pc;
+ CORE_ADDR enter_addr;
+ unsigned int insn;
+ unsigned int addr_mode;
+ int width;
+
+ numargs = -1;
+ enter_addr = ns32k_get_enter_addr ((fi)->pc);
+ if (enter_addr > 0)
+ {
+ pc = ((enter_addr == 1)
+ ? SAVED_PC_AFTER_CALL (fi)
+ : FRAME_SAVED_PC (fi));
+ insn = read_memory_integer (pc, 2);
+ addr_mode = (insn >> 11) & 0x1f;
+ insn = insn & 0x7ff;
+ if ((insn & 0x7fc) == 0x57c
+ && addr_mode == 0x14) /* immediate */
+ {
+ if (insn == 0x57c) /* adjspb */
+ width = 1;
+ else if (insn == 0x57d) /* adjspw */
+ width = 2;
+ else if (insn == 0x57f) /* adjspd */
+ width = 4;
+ else
+ internal_error (__FILE__, __LINE__, "bad else");
+ numargs = read_memory_integer (pc + 2, width);
+ if (width > 1)
+ flip_bytes (&numargs, width);
+ numargs = -sign_extend (numargs, width * 8) / 4;
+ }
+ }
+ return numargs;
+}
+
+static int
+sign_extend (int value, int bits)
+{
+ value = value & ((1 << bits) - 1);
+ return (value & (1 << (bits - 1))
+ ? value | (~((1 << bits) - 1))
+ : value);
+}
+
+static void
+flip_bytes (void *p, int count)
+{
+ char tmp;
+ char *ptr = 0;
+
+ while (count > 0)
+ {
+ tmp = *ptr;
+ ptr[0] = ptr[count - 1];
+ ptr[count - 1] = tmp;
+ ptr++;
+ count -= 2;
+ }
+}
+
+/* Return the number of locals in the current frame given a
+ pc pointing to the enter instruction. This is used by
+ ns32k_frame_init_saved_regs. */
+
+static int
+ns32k_localcount (CORE_ADDR enter_pc)
+{
+ unsigned char localtype;
+ int localcount;
+
+ localtype = read_memory_integer (enter_pc + 2, 1);
+ if ((localtype & 0x80) == 0)
+ localcount = localtype;
+ else if ((localtype & 0xc0) == 0x80)
+ localcount = (((localtype & 0x3f) << 8)
+ | (read_memory_integer (enter_pc + 3, 1) & 0xff));
+ else
+ localcount = (((localtype & 0x3f) << 24)
+ | ((read_memory_integer (enter_pc + 3, 1) & 0xff) << 16)
+ | ((read_memory_integer (enter_pc + 4, 1) & 0xff) << 8)
+ | (read_memory_integer (enter_pc + 5, 1) & 0xff));
+ return localcount;
+}
+
+
+/* Nonzero if instruction at PC is a return instruction. */
+
+static int
+ns32k_about_to_return (CORE_ADDR pc)
+{
+ return (read_memory_integer (pc, 1) == 0x12);
+}
+
+/* Get the address of the enter opcode for this function, if it is active.
+ Returns positive address > 1 if pc is between enter/exit,
+ 1 if pc before enter or after exit, 0 otherwise. */
+static CORE_ADDR
+ns32k_get_enter_addr (CORE_ADDR pc)
+{
+ CORE_ADDR enter_addr;
+ unsigned char op;
+
+ if (pc == 0)
+ return 0;
+
+ if (ns32k_about_to_return (pc))
+ return 1; /* after exit */
+
+ enter_addr = get_pc_function_start (pc);
+
+ if (pc == enter_addr)
+ return 1; /* before enter */
+
+ op = read_memory_integer (enter_addr, 1);
+
+ if (op != 0x82)
+ return 0; /* function has no enter/exit */
+
+ return enter_addr; /* pc is between enter and exit */
+}
+
+static CORE_ADDR
+ns32k_frame_chain (struct frame_info *frame)
+{
+ /* In the case of the NS32000 series, the frame's nominal address is the
+ FP value, and that address is saved at the previous FP value as a
+ 4-byte word. */
+
+ if (inside_entry_file (frame->pc))
+ return 0;
+
+ return (read_memory_integer (frame->frame, 4));
+}
+
+static CORE_ADDR
+ns32k_frame_saved_pc (struct frame_info *frame)
+{
+ if (frame->signal_handler_caller)
+ return (sigtramp_saved_pc (frame)); /* XXXJRT */
+
+ return (read_memory_integer (frame->frame + 4, 4));
+}
+
+static CORE_ADDR
+ns32k_frame_args_address (struct frame_info *frame)
+{
+ if (ns32k_get_enter_addr (frame->pc) > 1)
+ return (frame->frame);
+
+ return (read_register (SP_REGNUM) - 4);
+}
+
+static CORE_ADDR
+ns32k_frame_locals_address (struct frame_info *frame)
+{
+ return (frame->frame);
+}
+
+/* Code to initialize 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 void
+ns32k_frame_init_saved_regs (struct frame_info *frame)
+{
+ int regmask, regnum;
+ int localcount;
+ CORE_ADDR enter_addr, next_addr;
+
+ if (frame->saved_regs)
+ return;
+
+ frame_saved_regs_zalloc (frame);
+
+ enter_addr = ns32k_get_enter_addr (frame->pc);
+ if (enter_addr > 1)
+ {
+ regmask = read_memory_integer (enter_addr + 1, 1) & 0xff;
+ localcount = ns32k_localcount (enter_addr);
+ next_addr = frame->frame + localcount;
+
+ for (regnum = 0; regnum < 8; regnum++)
+ {
+ if (regmask & (1 << regnum))
+ frame->saved_regs[regnum] = next_addr -= 4;
+ }
+
+ frame->saved_regs[SP_REGNUM] = frame->frame + 4;
+ frame->saved_regs[PC_REGNUM] = frame->frame + 4;
+ frame->saved_regs[FP_REGNUM] = read_memory_integer (frame->frame, 4);
+ }
+ else if (enter_addr == 1)
+ {
+ CORE_ADDR sp = read_register (SP_REGNUM);
+ frame->saved_regs[PC_REGNUM] = sp;
+ frame->saved_regs[SP_REGNUM] = sp + 4;
+ }
+}
+
+static void
+ns32k_push_dummy_frame (void)
+{
+ CORE_ADDR sp = read_register (SP_REGNUM);
+ int regnum;
+
+ sp = push_word (sp, read_register (PC_REGNUM));
+ sp = push_word (sp, read_register (FP_REGNUM));
+ write_register (FP_REGNUM, sp);
+
+ for (regnum = 0; regnum < 8; regnum++)
+ sp = push_word (sp, read_register (regnum));
+
+ write_register (SP_REGNUM, sp);
+}
+
+static void
+ns32k_pop_frame (void)
+{
+ struct frame_info *frame = get_current_frame ();
+ CORE_ADDR fp;
+ int regnum;
+
+ fp = frame->frame;
+ FRAME_INIT_SAVED_REGS (frame);
+
+ for (regnum = 0; regnum < 8; regnum++)
+ if (frame->saved_regs[regnum])
+ write_register (regnum,
+ read_memory_integer (frame->saved_regs[regnum], 4));
+
+ write_register (FP_REGNUM, read_memory_integer (fp, 4));
+ write_register (PC_REGNUM, read_memory_integer (fp + 4, 4));
+ write_register (SP_REGNUM, fp + 8);
+ flush_cached_frames ();
+}
+
+/* The NS32000 call dummy sequence:
+
+ enter 0xff,0 82 ff 00
+ jsr @0x00010203 7f ae c0 01 02 03
+ adjspd 0x69696969 7f a5 01 02 03 04
+ bpt f2
+
+ It is 16 bytes long. */
+
+static LONGEST ns32k_call_dummy_words[] =
+{
+ 0x7f00ff82,
+ 0x0201c0ae,
+ 0x01a57f03,
+ 0xf2040302
+};
+static int sizeof_ns32k_call_dummy_words = sizeof (ns32k_call_dummy_words);
+
+#define NS32K_CALL_DUMMY_ADDR 5
+#define NS32K_CALL_DUMMY_NARGS 11
+
+static void
+ns32k_fix_call_dummy (char *dummy, CORE_ADDR pc, CORE_ADDR fun, int nargs,
+ struct value **args, struct type *type, int gcc_p)
+{
+ int flipped;
+
+ flipped = fun | 0xc0000000;
+ flip_bytes (&flipped, 4);
+ store_unsigned_integer (dummy + NS32K_CALL_DUMMY_ADDR, 4, flipped);
+
+ flipped = - nargs * 4;
+ flip_bytes (&flipped, 4);
+ store_unsigned_integer (dummy + NS32K_CALL_DUMMY_NARGS, 4, flipped);
+}
+
+static void
+ns32k_store_struct_return (CORE_ADDR addr, CORE_ADDR sp)
+{
+ /* On this machine, this is a no-op (Encore Umax didn't use GCC). */
+}
+
+static void
+ns32k_extract_return_value (struct type *valtype, char *regbuf, char *valbuf)
+{
+ memcpy (valbuf,
+ regbuf + REGISTER_BYTE (TYPE_CODE (valtype) == TYPE_CODE_FLT ?
+ FP0_REGNUM : 0), TYPE_LENGTH (valtype));
+}
+
+static void
+ns32k_store_return_value (struct type *valtype, char *valbuf)
+{
+ write_register_bytes (TYPE_CODE (valtype) == TYPE_CODE_FLT ?
+ FP0_REGNUM : 0, valbuf, TYPE_LENGTH (valtype));
+}
+
+static CORE_ADDR
+ns32k_extract_struct_value_address (char *regbuf)
+{
+ return (extract_address (regbuf + REGISTER_BYTE (0), REGISTER_RAW_SIZE (0)));
+}
+
+void
+ns32k_gdbarch_init_32082 (struct gdbarch *gdbarch)
+{
+ set_gdbarch_num_regs (gdbarch, NS32K_NUM_REGS_32082);
+
+ set_gdbarch_register_name (gdbarch, ns32k_register_name_32082);
+ set_gdbarch_register_bytes (gdbarch, NS32K_REGISTER_BYTES_32082);
+ set_gdbarch_register_byte (gdbarch, ns32k_register_byte_32082);
+}
+
+void
+ns32k_gdbarch_init_32382 (struct gdbarch *gdbarch)
+{
+ set_gdbarch_num_regs (gdbarch, NS32K_NUM_REGS_32382);
+
+ set_gdbarch_register_name (gdbarch, ns32k_register_name_32382);
+ set_gdbarch_register_bytes (gdbarch, NS32K_REGISTER_BYTES_32382);
+ set_gdbarch_register_byte (gdbarch, ns32k_register_byte_32382);
+}
+
+/* Initialize the current architecture based on INFO. If possible, re-use an
+ architecture from ARCHES, which is a list of architectures already created
+ during this debugging session.
+
+ Called e.g. at program startup, when reading a core file, and when reading
+ a binary file. */
+
+static struct gdbarch *
+ns32k_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
+{
+ struct gdbarch_tdep *tdep;
+ struct gdbarch *gdbarch;
+ enum gdb_osabi osabi = GDB_OSABI_UNKNOWN;
+
+ /* Try to determine the OS ABI of the object we are loading. */
+ if (info.abfd != NULL)
+ {
+ osabi = gdbarch_lookup_osabi (info.abfd);
+ }
+
+ /* Find a candidate among extant architectures. */
+ for (arches = gdbarch_list_lookup_by_info (arches, &info);
+ arches != NULL;
+ arches = gdbarch_list_lookup_by_info (arches->next, &info))
+ {
+ /* Make sure the OS ABI selection matches. */
+ tdep = gdbarch_tdep (arches->gdbarch);
+ if (tdep && tdep->osabi == osabi)
+ return arches->gdbarch;
+ }
+
+ tdep = xmalloc (sizeof (struct gdbarch_tdep));
+ gdbarch = gdbarch_alloc (&info, tdep);
+
+ tdep->osabi = osabi;
+
+ /* Register info */
+ ns32k_gdbarch_init_32082 (gdbarch);
+ set_gdbarch_num_regs (gdbarch, NS32K_SP_REGNUM);
+ set_gdbarch_num_regs (gdbarch, NS32K_FP_REGNUM);
+ set_gdbarch_num_regs (gdbarch, NS32K_PC_REGNUM);
+ set_gdbarch_num_regs (gdbarch, NS32K_PS_REGNUM);
+
+ set_gdbarch_register_size (gdbarch, NS32K_REGISTER_SIZE);
+ set_gdbarch_register_raw_size (gdbarch, ns32k_register_raw_size);
+ set_gdbarch_max_register_raw_size (gdbarch, NS32K_MAX_REGISTER_RAW_SIZE);
+ set_gdbarch_register_virtual_size (gdbarch, ns32k_register_virtual_size);
+ set_gdbarch_max_register_virtual_size (gdbarch,
+ NS32K_MAX_REGISTER_VIRTUAL_SIZE);
+ set_gdbarch_register_virtual_type (gdbarch, ns32k_register_virtual_type);
+
+ /* Frame and stack info */
+ set_gdbarch_skip_prologue (gdbarch, umax_skip_prologue);
+ set_gdbarch_saved_pc_after_call (gdbarch, ns32k_saved_pc_after_call);
+
+ set_gdbarch_frame_num_args (gdbarch, umax_frame_num_args);
+ set_gdbarch_frameless_function_invocation (gdbarch,
+ generic_frameless_function_invocation_not);
+
+ set_gdbarch_frame_chain (gdbarch, ns32k_frame_chain);
+ set_gdbarch_frame_chain_valid (gdbarch, func_frame_chain_valid);
+ set_gdbarch_frame_saved_pc (gdbarch, ns32k_frame_saved_pc);
+
+ set_gdbarch_frame_args_address (gdbarch, ns32k_frame_args_address);
+ set_gdbarch_frame_locals_address (gdbarch, ns32k_frame_locals_address);
+
+ set_gdbarch_frame_init_saved_regs (gdbarch, ns32k_frame_init_saved_regs);
+
+ set_gdbarch_frame_args_skip (gdbarch, 8);
+
+ set_gdbarch_inner_than (gdbarch, core_addr_lessthan);
+
+ /* Return value info */
+ set_gdbarch_store_struct_return (gdbarch, ns32k_store_struct_return);
+ set_gdbarch_deprecated_extract_return_value (gdbarch, ns32k_extract_return_value);
+ set_gdbarch_deprecated_store_return_value (gdbarch, ns32k_store_return_value);
+ set_gdbarch_deprecated_extract_struct_value_address (gdbarch,
+ ns32k_extract_struct_value_address);
+
+ /* Call dummy info */
+ set_gdbarch_push_dummy_frame (gdbarch, ns32k_push_dummy_frame);
+ set_gdbarch_pop_frame (gdbarch, ns32k_pop_frame);
+ set_gdbarch_call_dummy_location (gdbarch, ON_STACK);
+ set_gdbarch_call_dummy_p (gdbarch, 1);
+ set_gdbarch_call_dummy_words (gdbarch, ns32k_call_dummy_words);
+ set_gdbarch_sizeof_call_dummy_words (gdbarch, sizeof_ns32k_call_dummy_words);
+ set_gdbarch_fix_call_dummy (gdbarch, ns32k_fix_call_dummy);
+ set_gdbarch_call_dummy_start_offset (gdbarch, 3);
+ set_gdbarch_call_dummy_breakpoint_offset_p (gdbarch, 0);
+ set_gdbarch_use_generic_dummy_frames (gdbarch, 0);
+ set_gdbarch_pc_in_call_dummy (gdbarch, pc_in_call_dummy_on_stack);
+ set_gdbarch_call_dummy_stack_adjust_p (gdbarch, 0);
+
+ /* Breakpoint info */
+ set_gdbarch_decr_pc_after_break (gdbarch, 0);
+ set_gdbarch_breakpoint_from_pc (gdbarch, ns32k_breakpoint_from_pc);
+
+ /* Misc info */
+ set_gdbarch_function_start_offset (gdbarch, 0);
+
+ /* Hook in OS ABI-specific overrides, if they have been registered. */
+ gdbarch_init_osabi (info, gdbarch, osabi);
+
+ return (gdbarch);
+}
+
+static void
+ns32k_dump_tdep (struct gdbarch *current_gdbarch, struct ui_file *file)
+{
+ struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
+
+ if (tdep == NULL)
+ return;
+
+ fprintf_unfiltered (file, "ns32k_dump_tdep: OS ABI = %s\n",
+ gdbarch_osabi_name (tdep->osabi));
+}
+
+void
+_initialize_ns32k_tdep (void)
+{
+ gdbarch_register (bfd_arch_ns32k, ns32k_gdbarch_init, ns32k_dump_tdep);
+
+ tm_print_insn = print_insn_ns32k;
+}
diff --git a/gdb/sh3-rom.c b/gdb/sh3-rom.c
new file mode 100644
index 0000000..f450ac9
--- /dev/null
+++ b/gdb/sh3-rom.c
@@ -0,0 +1,384 @@
+/* Remote target glue for the Hitachi SH-3 ROM monitor.
+ Copyright 1995, 1996, 1997, 1998, 1999, 2000, 2001
+ Free Software Foundation, Inc.
+
+ 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 2 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, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include "defs.h"
+#include "gdbcore.h"
+#include "target.h"
+#include "monitor.h"
+#include "serial.h"
+#include "srec.h"
+#include "arch-utils.h"
+#include "regcache.h"
+
+#include "sh-tdep.h"
+
+static struct serial *parallel;
+static int parallel_in_use;
+
+static void sh3_open (char *args, int from_tty);
+
+static void
+sh3_supply_register (char *regname, int regnamelen, char *val, int vallen)
+{
+ int numregs;
+ int regno;
+
+ numregs = 1;
+ regno = -1;
+
+ if (regnamelen == 2)
+ {
+ switch (regname[0])
+ {
+ case 'S':
+ if (regname[1] == 'R')
+ regno = SR_REGNUM;
+ break;
+ case 'P':
+ if (regname[1] == 'C')
+ regno = PC_REGNUM;
+ else if (regname[1] == 'R')
+ regno = PR_REGNUM;
+ break;
+ }
+ }
+ else if (regnamelen == 3)
+ {
+ switch (regname[0])
+ {
+ case 'G':
+ case 'V':
+ if (regname[1] == 'B' && regname[2] == 'R')
+ {
+ if (regname[0] == 'G')
+ regno = VBR_REGNUM;
+ else
+ regno = GBR_REGNUM;
+ }
+ break;
+ case 'S':
+ if (regname[1] == 'S' && regname[2] == 'R')
+ regno = gdbarch_tdep (current_gdbarch)->SSR_REGNUM;
+ else if (regname[1] == 'P' && regname[2] == 'C')
+ regno = gdbarch_tdep (current_gdbarch)->SPC_REGNUM;
+ break;
+ }
+ }
+ else if (regnamelen == 4)
+ {
+ switch (regname[0])
+ {
+ case 'M':
+ if (regname[1] == 'A' && regname[2] == 'C')
+ {
+ if (regname[3] == 'H')
+ regno = MACH_REGNUM;
+ else if (regname[3] == 'L')
+ regno = MACL_REGNUM;
+ }
+ break;
+ case 'R':
+ if (regname[1] == '0' && regname[2] == '-' && regname[3] == '7')
+ {
+ regno = R0_REGNUM;
+ numregs = 8;
+ }
+ }
+ }
+ else if (regnamelen == 5)
+ {
+ if (regname[1] == '8' && regname[2] == '-' && regname[3] == '1'
+ && regname[4] == '5')
+ {
+ regno = R0_REGNUM + 8;
+ numregs = 8;
+ }
+ }
+ else if (regnamelen == 17)
+ {
+ }
+
+ if (regno >= 0)
+ while (numregs-- > 0)
+ val = monitor_supply_register (regno++, val);
+}
+
+static void
+sh3_load (struct serial *desc, char *file, int hashmark)
+{
+ if (parallel_in_use)
+ {
+ monitor_printf ("pl;s\r");
+ load_srec (parallel, file, 0, 80, SREC_ALL, hashmark, NULL);
+ monitor_expect_prompt (NULL, 0);
+ }
+ else
+ {
+ monitor_printf ("il;s:x\r");
+ monitor_expect ("\005", NULL, 0); /* Look for ENQ */
+ serial_write (desc, "\006", 1); /* Send ACK */
+ monitor_expect ("LO x\r", NULL, 0); /* Look for filename */
+
+ load_srec (desc, file, 0, 80, SREC_ALL, hashmark, NULL);
+
+ monitor_expect ("\005", NULL, 0); /* Look for ENQ */
+ serial_write (desc, "\006", 1); /* Send ACK */
+ monitor_expect_prompt (NULL, 0);
+ }
+}
+
+/* This array of registers need to match the indexes used by GDB.
+ This exists because the various ROM monitors use different strings
+ than does GDB, and don't necessarily support all the registers
+ either. So, typing "info reg sp" becomes a "r30". */
+
+static char *sh3_regnames[] =
+{
+ "R0", "R1", "R2", "R3", "R4", "R5", "R6", "R7",
+ "R8", "R9", "R10", "R11", "R12", "R13", "R14", "R15",
+ "PC", "PR", "GBR", "VBR", "MACH", "MACL", "SR",
+ NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "SSR", "SPC",
+ "R0_BANK0", "R1_BANK0", "R2_BANK0", "R3_BANK0",
+ "R4_BANK0", "R5_BANK0", "R6_BANK0", "R7_BANK0",
+ "R0_BANK1", "R1_BANK1", "R2_BANK1", "R3_BANK1",
+ "R4_BANK1", "R5_BANK1", "R6_BANK1", "R7_BANK1"
+};
+
+static char *sh3e_regnames[] =
+{
+ "R0", "R1", "R2", "R3", "R4", "R5", "R6", "R7",
+ "R8", "R9", "R10", "R11", "R12", "R13", "R14", "R15",
+ "PC", "PR", "GBR", "VBR", "MACH", "MACL", "SR",
+ "FPUL", "FPSCR",
+ "FR0", "FR1", "FR2", "FR3", "FR4", "FR5", "FR6", "FR7",
+ "FR8", "FR9", "FR10", "FR11", "FR12", "FR13", "FR14", "FR15",
+ "SSR", "SPC",
+ "R0_BANK0", "R1_BANK0", "R2_BANK0", "R3_BANK0",
+ "R4_BANK0", "R5_BANK0", "R6_BANK0", "R7_BANK0",
+ "R0_BANK1", "R1_BANK1", "R2_BANK1", "R3_BANK1",
+ "R4_BANK1", "R5_BANK1", "R6_BANK1", "R7_BANK1"
+};
+
+/* Define the monitor command strings. Since these are passed directly
+ through to a printf style function, we may include formatting
+ strings. We also need a CR or LF on the end. */
+
+static struct target_ops sh3_ops, sh3e_ops;
+
+static char *sh3_inits[] =
+{"\003", NULL}; /* Exits sub-command mode & download cmds */
+
+static struct monitor_ops sh3_cmds;
+
+static void
+init_sh3_cmds (void)
+{
+ sh3_cmds.flags = MO_CLR_BREAK_USES_ADDR | MO_GETMEM_READ_SINGLE; /* flags */
+ sh3_cmds.init = sh3_inits; /* monitor init string */
+ sh3_cmds.cont = "g\r"; /* continue command */
+ sh3_cmds.step = "s\r"; /* single step */
+ sh3_cmds.stop = "\003"; /* Interrupt program */
+ sh3_cmds.set_break = "b %x\r"; /* set a breakpoint */
+ sh3_cmds.clr_break = "b -%x\r"; /* clear a breakpoint */
+ sh3_cmds.clr_all_break = "b -\r"; /* clear all breakpoints */
+ sh3_cmds.fill = "f %x @%x %x\r"; /* fill (start len val) */
+ sh3_cmds.setmem.cmdb = "m %x %x\r"; /* setmem.cmdb (addr, value) */
+ sh3_cmds.setmem.cmdw = "m %x %x;w\r"; /* setmem.cmdw (addr, value) */
+ sh3_cmds.setmem.cmdl = "m %x %x;l\r"; /* setmem.cmdl (addr, value) */
+ sh3_cmds.setmem.cmdll = NULL; /* setmem.cmdll (addr, value) */
+ sh3_cmds.setmem.resp_delim = NULL; /* setreg.resp_delim */
+ sh3_cmds.setmem.term = NULL; /* setreg.term */
+ sh3_cmds.setmem.term_cmd = NULL; /* setreg.term_cmd */
+ sh3_cmds.getmem.cmdb = "m %x\r"; /* getmem.cmdb (addr, len) */
+ sh3_cmds.getmem.cmdw = "m %x;w\r"; /* getmem.cmdw (addr, len) */
+ sh3_cmds.getmem.cmdl = "m %x;l\r"; /* getmem.cmdl (addr, len) */
+ sh3_cmds.getmem.cmdll = NULL; /* getmem.cmdll (addr, len) */
+ sh3_cmds.getmem.resp_delim = "^ [0-9A-F]+ "; /* getmem.resp_delim */
+ sh3_cmds.getmem.term = "? "; /* getmem.term */
+ sh3_cmds.getmem.term_cmd = ".\r"; /* getmem.term_cmd */
+ sh3_cmds.setreg.cmd = ".%s %x\r"; /* setreg.cmd (name, value) */
+ sh3_cmds.setreg.resp_delim = NULL; /* setreg.resp_delim */
+ sh3_cmds.setreg.term = NULL; /* setreg.term */
+ sh3_cmds.setreg.term_cmd = NULL; /* setreg.term_cmd */
+ sh3_cmds.getreg.cmd = ".%s\r"; /* getreg.cmd (name) */
+ sh3_cmds.getreg.resp_delim = "="; /* getreg.resp_delim */
+ sh3_cmds.getreg.term = "? "; /* getreg.term */
+ sh3_cmds.getreg.term_cmd = ".\r"; /* getreg.term_cmd */
+ sh3_cmds.dump_registers = "r\r"; /* dump_registers */
+ sh3_cmds.register_pattern = "\\(\\w+\\)=\\([0-9a-fA-F]+\\( +[0-9a-fA-F]+\\b\\)*\\)";
+ sh3_cmds.supply_register = sh3_supply_register; /* supply_register */
+ sh3_cmds.load_routine = sh3_load; /* load_routine */
+ sh3_cmds.load = NULL; /* download command */
+ sh3_cmds.loadresp = NULL; /* Load response */
+ sh3_cmds.prompt = "\n:"; /* monitor command prompt */
+ sh3_cmds.line_term = "\r"; /* end-of-line terminator */
+ sh3_cmds.cmd_end = ".\r"; /* optional command terminator */
+ sh3_cmds.target = &sh3_ops; /* target operations */
+ sh3_cmds.stopbits = SERIAL_1_STOPBITS; /* number of stop bits */
+ sh3_cmds.regnames = sh3_regnames; /* registers names */
+ sh3_cmds.magic = MONITOR_OPS_MAGIC; /* magic */
+} /* init_sh3_cmds */
+
+/* This monitor structure is identical except for a couple slots, so
+ we will fill it in from the base structure when needed. */
+
+static struct monitor_ops sh3e_cmds;
+
+static void
+sh3_open (char *args, int from_tty)
+{
+ char *serial_port_name = args;
+ char *parallel_port_name = 0;
+
+ if (args)
+ {
+ char *cursor = serial_port_name = xstrdup (args);
+
+ while (*cursor && *cursor != ' ')
+ cursor++;
+
+ if (*cursor)
+ *cursor++ = 0;
+
+ while (*cursor == ' ')
+ cursor++;
+
+ if (*cursor)
+ parallel_port_name = cursor;
+ }
+
+ monitor_open (serial_port_name, &sh3_cmds, from_tty);
+
+ if (parallel_port_name)
+ {
+ parallel = serial_open (parallel_port_name);
+
+ if (!parallel)
+ perror_with_name ("Unable to open parallel port.");
+
+ parallel_in_use = 1;
+ }
+
+ /* If we connected successfully, we know the processor is an SH3. */
+ set_architecture_from_arch_mach (bfd_arch_sh, bfd_mach_sh3);
+}
+
+
+static void
+sh3e_open (char *args, int from_tty)
+{
+ char *serial_port_name = args;
+ char *parallel_port_name = 0;
+
+ if (args)
+ {
+ char *cursor = serial_port_name = xstrdup (args);
+
+ while (*cursor && *cursor != ' ')
+ cursor++;
+
+ if (*cursor)
+ *cursor++ = 0;
+
+ while (*cursor == ' ')
+ cursor++;
+
+ if (*cursor)
+ parallel_port_name = cursor;
+ }
+
+ /* Set up the SH-3E monitor commands structure. */
+
+ memcpy (&sh3e_cmds, &sh3_cmds, sizeof (struct monitor_ops));
+
+ sh3e_cmds.target = &sh3e_ops;
+ sh3e_cmds.regnames = sh3e_regnames;
+
+ monitor_open (serial_port_name, &sh3e_cmds, from_tty);
+
+ if (parallel_port_name)
+ {
+ parallel = serial_open (parallel_port_name);
+
+ if (!parallel)
+ perror_with_name ("Unable to open parallel port.");
+
+ parallel_in_use = 1;
+ }
+
+ /* If we connected successfully, we know the processor is an SH3E. */
+ set_architecture_from_arch_mach (bfd_arch_sh, bfd_mach_sh3);
+}
+
+static void
+sh3_close (int quitting)
+{
+ monitor_close (quitting);
+ if (parallel_in_use)
+ {
+ serial_close (parallel);
+ parallel_in_use = 0;
+ }
+}
+
+void
+_initialize_sh3_rom (void)
+{
+ init_sh3_cmds ();
+ init_monitor_ops (&sh3_ops);
+
+ sh3_ops.to_shortname = "sh3";
+ sh3_ops.to_longname = "Hitachi SH-3 rom monitor";
+
+ sh3_ops.to_doc =
+ /* We can download through the parallel port too. */
+ "Debug on a Hitachi eval board running the SH-3E rom monitor.\n"
+ "Specify the serial device it is connected to.\n"
+ "If you want to use the parallel port to download to it, specify that\n"
+ "as an additional second argument.";
+
+ sh3_ops.to_open = sh3_open;
+ sh3_ops.to_close = sh3_close;
+
+ add_target (&sh3_ops);
+
+ /* Setup the SH3e, which has float registers. */
+
+ init_monitor_ops (&sh3e_ops);
+
+ sh3e_ops.to_shortname = "sh3e";
+ sh3e_ops.to_longname = "Hitachi SH-3E rom monitor";
+
+ sh3e_ops.to_doc =
+ /* We can download through the parallel port too. */
+ "Debug on a Hitachi eval board running the SH-3E rom monitor.\n"
+ "Specify the serial device it is connected to.\n"
+ "If you want to use the parallel port to download to it, specify that\n"
+ "as an additional second argument.";
+
+ sh3e_ops.to_open = sh3e_open;
+ sh3e_ops.to_close = sh3_close;
+
+ add_target (&sh3e_ops);
+}
diff --git a/gdb/vax-tdep.c b/gdb/vax-tdep.c
new file mode 100644
index 0000000..709ef38
--- /dev/null
+++ b/gdb/vax-tdep.c
@@ -0,0 +1,702 @@
+/* Print VAX instructions for GDB, the GNU debugger.
+ Copyright 1986, 1989, 1991, 1992, 1995, 1996, 1998, 1999, 2000, 2002
+ Free Software Foundation, Inc.
+
+ 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 2 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, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include "defs.h"
+#include "symtab.h"
+#include "opcode/vax.h"
+#include "gdbcore.h"
+#include "inferior.h"
+#include "regcache.h"
+#include "frame.h"
+#include "value.h"
+#include "arch-utils.h"
+
+#include "vax-tdep.h"
+
+static gdbarch_register_name_ftype vax_register_name;
+static gdbarch_register_byte_ftype vax_register_byte;
+static gdbarch_register_raw_size_ftype vax_register_raw_size;
+static gdbarch_register_virtual_size_ftype vax_register_virtual_size;
+static gdbarch_register_virtual_type_ftype vax_register_virtual_type;
+
+static gdbarch_skip_prologue_ftype vax_skip_prologue;
+static gdbarch_saved_pc_after_call_ftype vax_saved_pc_after_call;
+static gdbarch_frame_num_args_ftype vax_frame_num_args;
+static gdbarch_frame_chain_ftype vax_frame_chain;
+static gdbarch_frame_saved_pc_ftype vax_frame_saved_pc;
+static gdbarch_frame_args_address_ftype vax_frame_args_address;
+static gdbarch_frame_locals_address_ftype vax_frame_locals_address;
+static gdbarch_frame_init_saved_regs_ftype vax_frame_init_saved_regs;
+
+static gdbarch_store_struct_return_ftype vax_store_struct_return;
+static gdbarch_deprecated_extract_return_value_ftype vax_extract_return_value;
+static gdbarch_deprecated_extract_struct_value_address_ftype
+ vax_extract_struct_value_address;
+
+static gdbarch_push_dummy_frame_ftype vax_push_dummy_frame;
+static gdbarch_pop_frame_ftype vax_pop_frame;
+static gdbarch_fix_call_dummy_ftype vax_fix_call_dummy;
+
+/* Return 1 if P points to an invalid floating point value.
+ LEN is the length in bytes -- not relevant on the Vax. */
+
+/* FIXME: cagney/2002-01-19: The macro below was originally defined in
+ tm-vax.h and used in values.c. Two problems. Firstly this is a
+ very non-portable and secondly it is wrong. The VAX should be
+ using floatformat and associated methods to identify and handle
+ invalid floating-point values. Adding to the poor target's woes
+ there is no floatformat_vax_{f,d} and no TARGET_FLOAT_FORMAT
+ et.al.. */
+
+/* FIXME: cagney/2002-01-19: It turns out that the only thing that
+ uses this macro is the vax disassembler code (so how old is this
+ target?). This target should instead be using the opcodes
+ disassembler. That allowing the macro to be eliminated. */
+
+#define INVALID_FLOAT(p, len) ((*(short *) p & 0xff80) == 0x8000)
+
+/* Vax instructions are never longer than this. */
+#define MAXLEN 62
+
+/* Number of elements in the opcode table. */
+#define NOPCODES (sizeof votstrs / sizeof votstrs[0])
+
+static unsigned char *print_insn_arg ();
+
+static const char *
+vax_register_name (int regno)
+{
+ static char *register_names[] =
+ {
+ "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
+ "r8", "r9", "r10", "r11", "ap", "fp", "sp", "pc",
+ "ps",
+ };
+
+ if (regno < 0)
+ return (NULL);
+ if (regno >= (sizeof(register_names) / sizeof(*register_names)))
+ return (NULL);
+ return (register_names[regno]);
+}
+
+static int
+vax_register_byte (int regno)
+{
+ return (regno * 4);
+}
+
+static int
+vax_register_raw_size (int regno)
+{
+ return (4);
+}
+
+static int
+vax_register_virtual_size (int regno)
+{
+ return (4);
+}
+
+static struct type *
+vax_register_virtual_type (int regno)
+{
+ return (builtin_type_int);
+}
+
+static void
+vax_frame_init_saved_regs (struct frame_info *frame)
+{
+ int regnum, regmask;
+ CORE_ADDR next_addr;
+
+ if (frame->saved_regs)
+ return;
+
+ frame_saved_regs_zalloc (frame);
+
+ regmask = read_memory_integer (frame->frame + 4, 4) >> 16;
+
+ next_addr = frame->frame + 16;
+
+ /* regmask's low bit is for register 0, which is the first one
+ what would be pushed. */
+ for (regnum = 0; regnum < VAX_AP_REGNUM; regnum++)
+ {
+ if (regmask & (1 << regnum))
+ frame->saved_regs[regnum] = next_addr += 4;
+ }
+
+ frame->saved_regs[SP_REGNUM] = next_addr + 4;
+ if (regmask & (1 << FP_REGNUM))
+ frame->saved_regs[SP_REGNUM] +=
+ 4 + (4 * read_memory_integer (next_addr + 4, 4));
+
+ frame->saved_regs[PC_REGNUM] = frame->frame + 16;
+ frame->saved_regs[FP_REGNUM] = frame->frame + 12;
+ frame->saved_regs[VAX_AP_REGNUM] = frame->frame + 8;
+ frame->saved_regs[PS_REGNUM] = frame->frame + 4;
+}
+
+static CORE_ADDR
+vax_frame_saved_pc (struct frame_info *frame)
+{
+ if (frame->signal_handler_caller)
+ return (sigtramp_saved_pc (frame)); /* XXXJRT */
+
+ return (read_memory_integer (frame->frame + 16, 4));
+}
+
+CORE_ADDR
+vax_frame_args_address_correct (struct frame_info *frame)
+{
+ /* Cannot find the AP register value directly from the FP value. Must
+ find it saved in the frame called by this one, or in the AP register
+ for the innermost frame. However, there is no way to tell the
+ difference between the innermost frame and a frame for which we
+ just don't know the frame that it called (e.g. "info frame 0x7ffec789").
+ For the sake of argument, suppose that the stack is somewhat trashed
+ (which is one reason that "info frame" exists). So, return 0 (indicating
+ we don't know the address of the arglist) if we don't know what frame
+ this frame calls. */
+ if (frame->next)
+ return (read_memory_integer (frame->next->frame + 8, 4));
+
+ return (0);
+}
+
+static CORE_ADDR
+vax_frame_args_address (struct frame_info *frame)
+{
+ /* In most of GDB, getting the args address is too important to
+ just say "I don't know". This is sometimes wrong for functions
+ that aren't on top of the stack, but c'est la vie. */
+ if (frame->next)
+ return (read_memory_integer (frame->next->frame + 8, 4));
+
+ return (read_register (VAX_AP_REGNUM));
+}
+
+static CORE_ADDR
+vax_frame_locals_address (struct frame_info *frame)
+{
+ return (frame->frame);
+}
+
+static int
+vax_frame_num_args (struct frame_info *fi)
+{
+ return (0xff & read_memory_integer (FRAME_ARGS_ADDRESS (fi), 1));
+}
+
+static CORE_ADDR
+vax_frame_chain (struct frame_info *frame)
+{
+ /* In the case of the VAX, the frame's nominal address is the FP value,
+ and 12 bytes later comes the saved previous FP value as a 4-byte word. */
+ if (inside_entry_file (frame->pc))
+ return (0);
+
+ return (read_memory_integer (frame->frame + 12, 4));
+}
+
+static void
+vax_push_dummy_frame (void)
+{
+ CORE_ADDR sp = read_register (SP_REGNUM);
+ int regnum;
+
+ sp = push_word (sp, 0); /* arglist */
+ for (regnum = 11; regnum >= 0; regnum--)
+ sp = push_word (sp, read_register (regnum));
+ sp = push_word (sp, read_register (PC_REGNUM));
+ sp = push_word (sp, read_register (FP_REGNUM));
+ sp = push_word (sp, read_register (VAX_AP_REGNUM));
+ sp = push_word (sp, (read_register (PS_REGNUM) & 0xffef) + 0x2fff0000);
+ sp = push_word (sp, 0);
+ write_register (SP_REGNUM, sp);
+ write_register (FP_REGNUM, sp);
+ write_register (VAX_AP_REGNUM, sp + (17 * 4));
+}
+
+static void
+vax_pop_frame (void)
+{
+ CORE_ADDR fp = read_register (FP_REGNUM);
+ int regnum;
+ int regmask = read_memory_integer (fp + 4, 4);
+
+ write_register (PS_REGNUM,
+ (regmask & 0xffff)
+ | (read_register (PS_REGNUM) & 0xffff0000));
+ write_register (PC_REGNUM, read_memory_integer (fp + 16, 4));
+ write_register (FP_REGNUM, read_memory_integer (fp + 12, 4));
+ write_register (VAX_AP_REGNUM, read_memory_integer (fp + 8, 4));
+ fp += 16;
+ for (regnum = 0; regnum < 12; regnum++)
+ if (regmask & (0x10000 << regnum))
+ write_register (regnum, read_memory_integer (fp += 4, 4));
+ fp = fp + 4 + ((regmask >> 30) & 3);
+ if (regmask & 0x20000000)
+ {
+ regnum = read_memory_integer (fp, 4);
+ fp += (regnum + 1) * 4;
+ }
+ write_register (SP_REGNUM, fp);
+ flush_cached_frames ();
+}
+
+/* The VAX call dummy sequence:
+
+ calls #69, @#32323232
+ bpt
+
+ It is 8 bytes long. The address and argc are patched by
+ vax_fix_call_dummy(). */
+static LONGEST vax_call_dummy_words[] = { 0x329f69fb, 0x03323232 };
+static int sizeof_vax_call_dummy_words = sizeof(vax_call_dummy_words);
+
+static void
+vax_fix_call_dummy (char *dummy, CORE_ADDR pc, CORE_ADDR fun, int nargs,
+ struct value **args, struct type *type, int gcc_p)
+{
+ dummy[1] = nargs;
+ store_unsigned_integer (dummy + 3, 4, fun);
+}
+
+static void
+vax_store_struct_return (CORE_ADDR addr, CORE_ADDR sp)
+{
+ write_register (1, addr);
+}
+
+static void
+vax_extract_return_value (struct type *valtype, char *regbuf, char *valbuf)
+{
+ memcpy (valbuf, regbuf + REGISTER_BYTE (0), TYPE_LENGTH (valtype));
+}
+
+static void
+vax_store_return_value (struct type *valtype, char *valbuf)
+{
+ write_register_bytes (0, valbuf, TYPE_LENGTH (valtype));
+}
+
+static CORE_ADDR
+vax_extract_struct_value_address (char *regbuf)
+{
+ return (extract_address (regbuf + REGISTER_BYTE (0), REGISTER_RAW_SIZE (0)));
+}
+
+static const unsigned char *
+vax_breakpoint_from_pc (CORE_ADDR *pcptr, int *lenptr)
+{
+ static const unsigned char vax_breakpoint[] = { 3 };
+
+ *lenptr = sizeof(vax_breakpoint);
+ return (vax_breakpoint);
+}
+
+/* Advance PC across any function entry prologue instructions
+ to reach some "real" code. */
+
+static CORE_ADDR
+vax_skip_prologue (CORE_ADDR pc)
+{
+ register int op = (unsigned char) read_memory_integer (pc, 1);
+ if (op == 0x11)
+ pc += 2; /* skip brb */
+ if (op == 0x31)
+ pc += 3; /* skip brw */
+ if (op == 0xC2
+ && ((unsigned char) read_memory_integer (pc + 2, 1)) == 0x5E)
+ pc += 3; /* skip subl2 */
+ if (op == 0x9E
+ && ((unsigned char) read_memory_integer (pc + 1, 1)) == 0xAE
+ && ((unsigned char) read_memory_integer (pc + 3, 1)) == 0x5E)
+ pc += 4; /* skip movab */
+ if (op == 0x9E
+ && ((unsigned char) read_memory_integer (pc + 1, 1)) == 0xCE
+ && ((unsigned char) read_memory_integer (pc + 4, 1)) == 0x5E)
+ pc += 5; /* skip movab */
+ if (op == 0x9E
+ && ((unsigned char) read_memory_integer (pc + 1, 1)) == 0xEE
+ && ((unsigned char) read_memory_integer (pc + 6, 1)) == 0x5E)
+ pc += 7; /* skip movab */
+ return pc;
+}
+
+static CORE_ADDR
+vax_saved_pc_after_call (struct frame_info *frame)
+{
+ return (FRAME_SAVED_PC(frame));
+}
+
+/* Print the vax instruction at address MEMADDR in debugged memory,
+ from disassembler info INFO.
+ Returns length of the instruction, in bytes. */
+
+static int
+vax_print_insn (CORE_ADDR memaddr, disassemble_info *info)
+{
+ unsigned char buffer[MAXLEN];
+ register int i;
+ register unsigned char *p;
+ const char *d;
+
+ int status = (*info->read_memory_func) (memaddr, buffer, MAXLEN, info);
+ if (status != 0)
+ {
+ (*info->memory_error_func) (status, memaddr, info);
+ return -1;
+ }
+
+ for (i = 0; i < NOPCODES; i++)
+ if (votstrs[i].detail.code == buffer[0]
+ || votstrs[i].detail.code == *(unsigned short *) buffer)
+ break;
+
+ /* Handle undefined instructions. */
+ if (i == NOPCODES)
+ {
+ (*info->fprintf_func) (info->stream, "0%o", buffer[0]);
+ return 1;
+ }
+
+ (*info->fprintf_func) (info->stream, "%s", votstrs[i].name);
+
+ /* Point at first byte of argument data,
+ and at descriptor for first argument. */
+ p = buffer + 1 + (votstrs[i].detail.code >= 0x100);
+ d = votstrs[i].detail.args;
+
+ if (*d)
+ (*info->fprintf_func) (info->stream, " ");
+
+ while (*d)
+ {
+ p = print_insn_arg (d, p, memaddr + (p - buffer), info);
+ d += 2;
+ if (*d)
+ (*info->fprintf_func) (info->stream, ",");
+ }
+ return p - buffer;
+}
+
+static unsigned char *
+print_insn_arg (char *d, register char *p, CORE_ADDR addr,
+ disassemble_info *info)
+{
+ register int regnum = *p & 0xf;
+ float floatlitbuf;
+
+ if (*d == 'b')
+ {
+ if (d[1] == 'b')
+ (*info->fprintf_func) (info->stream, "0x%x", addr + *p++ + 1);
+ else
+ {
+ (*info->fprintf_func) (info->stream, "0x%x", addr + *(short *) p + 2);
+ p += 2;
+ }
+ }
+ else
+ switch ((*p++ >> 4) & 0xf)
+ {
+ case 0:
+ case 1:
+ case 2:
+ case 3: /* Literal mode */
+ if (d[1] == 'd' || d[1] == 'f' || d[1] == 'g' || d[1] == 'h')
+ {
+ *(int *) &floatlitbuf = 0x4000 + ((p[-1] & 0x3f) << 4);
+ (*info->fprintf_func) (info->stream, "$%f", floatlitbuf);
+ }
+ else
+ (*info->fprintf_func) (info->stream, "$%d", p[-1] & 0x3f);
+ break;
+
+ case 4: /* Indexed */
+ p = (char *) print_insn_arg (d, p, addr + 1, info);
+ (*info->fprintf_func) (info->stream, "[%s]", REGISTER_NAME (regnum));
+ break;
+
+ case 5: /* Register */
+ (*info->fprintf_func) (info->stream, REGISTER_NAME (regnum));
+ break;
+
+ case 7: /* Autodecrement */
+ (*info->fprintf_func) (info->stream, "-");
+ case 6: /* Register deferred */
+ (*info->fprintf_func) (info->stream, "(%s)", REGISTER_NAME (regnum));
+ break;
+
+ case 9: /* Autoincrement deferred */
+ (*info->fprintf_func) (info->stream, "@");
+ if (regnum == PC_REGNUM)
+ {
+ (*info->fprintf_func) (info->stream, "#");
+ info->target = *(long *) p;
+ (*info->print_address_func) (info->target, info);
+ p += 4;
+ break;
+ }
+ case 8: /* Autoincrement */
+ if (regnum == PC_REGNUM)
+ {
+ (*info->fprintf_func) (info->stream, "#");
+ switch (d[1])
+ {
+ case 'b':
+ (*info->fprintf_func) (info->stream, "%d", *p++);
+ break;
+
+ case 'w':
+ (*info->fprintf_func) (info->stream, "%d", *(short *) p);
+ p += 2;
+ break;
+
+ case 'l':
+ (*info->fprintf_func) (info->stream, "%d", *(long *) p);
+ p += 4;
+ break;
+
+ case 'q':
+ (*info->fprintf_func) (info->stream, "0x%x%08x",
+ ((long *) p)[1], ((long *) p)[0]);
+ p += 8;
+ break;
+
+ case 'o':
+ (*info->fprintf_func) (info->stream, "0x%x%08x%08x%08x",
+ ((long *) p)[3], ((long *) p)[2],
+ ((long *) p)[1], ((long *) p)[0]);
+ p += 16;
+ break;
+
+ case 'f':
+ if (INVALID_FLOAT (p, 4))
+ (*info->fprintf_func) (info->stream,
+ "<<invalid float 0x%x>>",
+ *(int *) p);
+ else
+ (*info->fprintf_func) (info->stream, "%f", *(float *) p);
+ p += 4;
+ break;
+
+ case 'd':
+ if (INVALID_FLOAT (p, 8))
+ (*info->fprintf_func) (info->stream,
+ "<<invalid float 0x%x%08x>>",
+ ((long *) p)[1], ((long *) p)[0]);
+ else
+ (*info->fprintf_func) (info->stream, "%f", *(double *) p);
+ p += 8;
+ break;
+
+ case 'g':
+ (*info->fprintf_func) (info->stream, "g-float");
+ p += 8;
+ break;
+
+ case 'h':
+ (*info->fprintf_func) (info->stream, "h-float");
+ p += 16;
+ break;
+
+ }
+ }
+ else
+ (*info->fprintf_func) (info->stream, "(%s)+", REGISTER_NAME (regnum));
+ break;
+
+ case 11: /* Byte displacement deferred */
+ (*info->fprintf_func) (info->stream, "@");
+ case 10: /* Byte displacement */
+ if (regnum == PC_REGNUM)
+ {
+ info->target = addr + *p + 2;
+ (*info->print_address_func) (info->target, info);
+ }
+ else
+ (*info->fprintf_func) (info->stream, "%d(%s)", *p, REGISTER_NAME (regnum));
+ p += 1;
+ break;
+
+ case 13: /* Word displacement deferred */
+ (*info->fprintf_func) (info->stream, "@");
+ case 12: /* Word displacement */
+ if (regnum == PC_REGNUM)
+ {
+ info->target = addr + *(short *) p + 3;
+ (*info->print_address_func) (info->target, info);
+ }
+ else
+ (*info->fprintf_func) (info->stream, "%d(%s)",
+ *(short *) p, REGISTER_NAME (regnum));
+ p += 2;
+ break;
+
+ case 15: /* Long displacement deferred */
+ (*info->fprintf_func) (info->stream, "@");
+ case 14: /* Long displacement */
+ if (regnum == PC_REGNUM)
+ {
+ info->target = addr + *(short *) p + 5;
+ (*info->print_address_func) (info->target, info);
+ }
+ else
+ (*info->fprintf_func) (info->stream, "%d(%s)",
+ *(long *) p, REGISTER_NAME (regnum));
+ p += 4;
+ }
+
+ return (unsigned char *) p;
+}
+
+/* Initialize the current architecture based on INFO. If possible, re-use an
+ architecture from ARCHES, which is a list of architectures already created
+ during this debugging session.
+
+ Called e.g. at program startup, when reading a core file, and when reading
+ a binary file. */
+
+static struct gdbarch *
+vax_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
+{
+ struct gdbarch_tdep *tdep;
+ struct gdbarch *gdbarch;
+ enum gdb_osabi osabi = GDB_OSABI_UNKNOWN;
+
+ /* Try to determine the ABI of the object we are loading. */
+
+ if (info.abfd != NULL)
+ osabi = gdbarch_lookup_osabi (info.abfd);
+
+ /* Find a candidate among extant architectures. */
+ for (arches = gdbarch_list_lookup_by_info (arches, &info);
+ arches != NULL;
+ arches = gdbarch_list_lookup_by_info (arches->next, &info))
+ {
+ /* Make sure the ABI selection matches. */
+ tdep = gdbarch_tdep (arches->gdbarch);
+ if (tdep && tdep->osabi == osabi)
+ return arches->gdbarch;
+ }
+
+ tdep = xmalloc (sizeof (struct gdbarch_tdep));
+ gdbarch = gdbarch_alloc (&info, tdep);
+
+ tdep->osabi = osabi;
+
+ /* Register info */
+ set_gdbarch_num_regs (gdbarch, VAX_NUM_REGS);
+ set_gdbarch_sp_regnum (gdbarch, VAX_SP_REGNUM);
+ set_gdbarch_fp_regnum (gdbarch, VAX_FP_REGNUM);
+ set_gdbarch_pc_regnum (gdbarch, VAX_PC_REGNUM);
+ set_gdbarch_ps_regnum (gdbarch, VAX_PS_REGNUM);
+
+ set_gdbarch_register_name (gdbarch, vax_register_name);
+ set_gdbarch_register_size (gdbarch, VAX_REGISTER_SIZE);
+ set_gdbarch_register_bytes (gdbarch, VAX_REGISTER_BYTES);
+ set_gdbarch_register_byte (gdbarch, vax_register_byte);
+ set_gdbarch_register_raw_size (gdbarch, vax_register_raw_size);
+ set_gdbarch_max_register_raw_size (gdbarch, VAX_MAX_REGISTER_RAW_SIZE);
+ set_gdbarch_register_virtual_size (gdbarch, vax_register_virtual_size);
+ set_gdbarch_max_register_virtual_size (gdbarch,
+ VAX_MAX_REGISTER_VIRTUAL_SIZE);
+ set_gdbarch_register_virtual_type (gdbarch, vax_register_virtual_type);
+
+ /* Frame and stack info */
+ set_gdbarch_skip_prologue (gdbarch, vax_skip_prologue);
+ set_gdbarch_saved_pc_after_call (gdbarch, vax_saved_pc_after_call);
+
+ set_gdbarch_frame_num_args (gdbarch, vax_frame_num_args);
+ set_gdbarch_frameless_function_invocation (gdbarch,
+ generic_frameless_function_invocation_not);
+
+ set_gdbarch_frame_chain (gdbarch, vax_frame_chain);
+ set_gdbarch_frame_chain_valid (gdbarch, func_frame_chain_valid);
+ set_gdbarch_frame_saved_pc (gdbarch, vax_frame_saved_pc);
+
+ set_gdbarch_frame_args_address (gdbarch, vax_frame_args_address);
+ set_gdbarch_frame_locals_address (gdbarch, vax_frame_locals_address);
+
+ set_gdbarch_frame_init_saved_regs (gdbarch, vax_frame_init_saved_regs);
+
+ set_gdbarch_frame_args_skip (gdbarch, 4);
+
+ set_gdbarch_inner_than (gdbarch, core_addr_lessthan);
+
+ /* Return value info */
+ set_gdbarch_store_struct_return (gdbarch, vax_store_struct_return);
+ set_gdbarch_deprecated_extract_return_value (gdbarch, vax_extract_return_value);
+ set_gdbarch_deprecated_store_return_value (gdbarch, vax_store_return_value);
+ set_gdbarch_deprecated_extract_struct_value_address (gdbarch, vax_extract_struct_value_address);
+
+ /* Call dummy info */
+ set_gdbarch_push_dummy_frame (gdbarch, vax_push_dummy_frame);
+ set_gdbarch_pop_frame (gdbarch, vax_pop_frame);
+ set_gdbarch_call_dummy_location (gdbarch, ON_STACK);
+ set_gdbarch_call_dummy_p (gdbarch, 1);
+ set_gdbarch_call_dummy_words (gdbarch, vax_call_dummy_words);
+ set_gdbarch_sizeof_call_dummy_words (gdbarch, sizeof_vax_call_dummy_words);
+ set_gdbarch_fix_call_dummy (gdbarch, vax_fix_call_dummy);
+ set_gdbarch_call_dummy_start_offset (gdbarch, 0);
+ set_gdbarch_call_dummy_breakpoint_offset_p (gdbarch, 1);
+ set_gdbarch_call_dummy_breakpoint_offset (gdbarch, 7);
+ set_gdbarch_use_generic_dummy_frames (gdbarch, 0);
+ set_gdbarch_pc_in_call_dummy (gdbarch, pc_in_call_dummy_on_stack);
+ set_gdbarch_call_dummy_stack_adjust_p (gdbarch, 0);
+
+ /* Breakpoint info */
+ set_gdbarch_breakpoint_from_pc (gdbarch, vax_breakpoint_from_pc);
+ set_gdbarch_decr_pc_after_break (gdbarch, 0);
+
+ /* Misc info */
+ set_gdbarch_function_start_offset (gdbarch, 2);
+ set_gdbarch_believe_pcc_promotion (gdbarch, 1);
+
+ /* Hook in ABI-specific overrides, if they have been registered. */
+ gdbarch_init_osabi (info, gdbarch, osabi);
+
+ return (gdbarch);
+}
+
+static void
+vax_dump_tdep (struct gdbarch *current_gdbarch, struct ui_file *file)
+{
+ struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
+
+ if (tdep == NULL)
+ return;
+
+ fprintf_unfiltered (file, "vax_dump_tdep: OS ABI = %s\n",
+ gdbarch_osabi_name (tdep->osabi));
+}
+
+void
+_initialize_vax_tdep (void)
+{
+ gdbarch_register (bfd_arch_vax, vax_gdbarch_init, vax_dump_tdep);
+
+ tm_print_insn = vax_print_insn;
+}