/* Target-dependent code for the Matsushita MN10300 for GDB, the GNU debugger.
- Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005
- Free Software Foundation, Inc.
+ Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005,
+ 2007 Free Software Foundation, Inc.
This file is part of GDB.
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. */
+ Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA. */
#include "defs.h"
#include "arch-utils.h"
return register_name (reg, regs, sizeof regs);
}
+static const char *
+am33_2_register_name (int reg)
+{
+ static char *regs[] =
+ {
+ "d0", "d1", "d2", "d3", "a0", "a1", "a2", "a3",
+ "sp", "pc", "mdr", "psw", "lir", "lar", "mdrq", "r0",
+ "r1", "r2", "r3", "r4", "r5", "r6", "r7", "ssp",
+ "msp", "usp", "mcrh", "mcrl", "mcvf", "fpcr", "", "",
+ "fs0", "fs1", "fs2", "fs3", "fs4", "fs5", "fs6", "fs7",
+ "fs8", "fs9", "fs10", "fs11", "fs12", "fs13", "fs14", "fs15",
+ "fs16", "fs17", "fs18", "fs19", "fs20", "fs21", "fs22", "fs23",
+ "fs24", "fs25", "fs26", "fs27", "fs28", "fs29", "fs30", "fs31"
+ };
+ return register_name (reg, regs, sizeof regs);
+}
static struct type *
mn10300_register_type (struct gdbarch *gdbarch, int reg)
}
static CORE_ADDR
-mn10300_read_pc (ptid_t ptid)
+mn10300_read_pc (struct regcache *regcache)
{
- return read_register_pid (E_PC_REGNUM, ptid);
+ ULONGEST val;
+ regcache_cooked_read_unsigned (regcache, E_PC_REGNUM, &val);
+ return val;
}
static void
-mn10300_write_pc (CORE_ADDR val, ptid_t ptid)
+mn10300_write_pc (struct regcache *regcache, CORE_ADDR val)
{
- return write_register_pid (E_PC_REGNUM, val, ptid);
+ regcache_cooked_write_unsigned (regcache, E_PC_REGNUM, val);
}
/* The breakpoint instruction must be the same size as the smallest
return breakpoint;
}
-/*
- * Frame Extra Info:
- *
- * status -- actually frame type (SP, FP, or last frame)
- * stack size -- offset to the next frame
- *
- * The former might ultimately be stored in the frame_base.
- * Seems like there'd be a way to store the later too.
- *
- * Temporarily supply empty stub functions as place holders.
- */
-
-static void
-my_frame_is_in_sp (struct frame_info *fi, void **this_cache)
-{
- struct trad_frame_cache *cache = mn10300_frame_unwind_cache (fi, this_cache);
- trad_frame_set_this_base (cache,
- frame_unwind_register_unsigned (fi,
- E_SP_REGNUM));
-}
-
-static void
-my_frame_is_in_fp (struct frame_info *fi, void **this_cache)
-{
- struct trad_frame_cache *cache = mn10300_frame_unwind_cache (fi, this_cache);
- trad_frame_set_this_base (cache,
- frame_unwind_register_unsigned (fi,
- E_A3_REGNUM));
-}
-
-static void
-my_frame_is_last (struct frame_info *fi)
-{
-}
-
-static void
-set_my_stack_size (struct frame_info *fi, CORE_ADDR size)
-{
-}
-
-
-/* Set offsets of registers saved by movm instruction.
+/* Set offsets of saved registers.
This is a helper function for mn10300_analyze_prologue. */
static void
-set_movm_offsets (struct frame_info *fi,
+set_reg_offsets (struct frame_info *fi,
void **this_cache,
- int movm_args)
+ int movm_args,
+ int fpregmask,
+ int stack_extra_size,
+ int frame_in_fp)
{
struct trad_frame_cache *cache;
int offset = 0;
if (cache == NULL)
return;
- base = trad_frame_get_this_base (cache);
+ if (frame_in_fp)
+ {
+ base = frame_unwind_register_unsigned (fi, E_A3_REGNUM);
+ }
+ else
+ {
+ base = frame_unwind_register_unsigned (fi, E_SP_REGNUM) + stack_extra_size;
+ }
+
+ trad_frame_set_this_base (cache, base);
+
+ if (AM33_MODE == 2)
+ {
+ /* If bit N is set in fpregmask, fsN is saved on the stack.
+ The floating point registers are saved in ascending order.
+ For example: fs16 <- Frame Pointer
+ fs17 Frame Pointer + 4 */
+ if (fpregmask != 0)
+ {
+ int i;
+ for (i = 0; i < 32; i++)
+ {
+ if (fpregmask & (1 << i))
+ {
+ trad_frame_set_reg_addr (cache, E_FS0_REGNUM + i, base + offset);
+ offset += 4;
+ }
+ }
+ }
+ }
+
+
if (movm_args & movm_other_bit)
{
/* The `other' bit leaves a blank area of four bytes at the
CORE_ADDR pc)
{
CORE_ADDR func_addr, func_end, addr, stop;
- long stack_size;
+ long stack_extra_size = 0;
int imm_size;
unsigned char buf[4];
- int status, movm_args = 0;
+ int status;
+ int movm_args = 0;
+ int fpregmask = 0;
char *name;
+ int frame_in_fp = 0;
/* Use the PC in the frame if it's provided to look up the
start of this function.
if (fi)
{
pc = (pc ? pc : get_frame_pc (fi));
- /* At the start of a function our frame is in the stack pointer. */
- my_frame_is_in_sp (fi, this_cache);
}
/* Find the start of this function. */
and I don't want to do that anyway. */
if (status == 0)
{
- return pc;
+ addr = pc;
+ goto finish_prologue;
}
/* If we're in start, then give up. */
if (strcmp (name, "start") == 0)
{
- if (fi != NULL)
- my_frame_is_last (fi);
- return pc;
- }
-
-#if 0
- /* Get the next two bytes into buf, we need two because rets is a two
- byte insn and the first isn't enough to uniquely identify it. */
- status = deprecated_read_memory_nobpt (pc, buf, 2);
- if (status != 0)
- return pc;
-
- /* Note: kevinb/2003-07-16: We shouldn't be making these sorts of
- changes to the frame in prologue examination code. */
- /* If we're physically on an "rets" instruction, then our frame has
- already been deallocated. Note this can also be true for retf
- and ret if they specify a size of zero.
-
- In this case fi->frame is bogus, we need to fix it. */
- if (fi && buf[0] == 0xf0 && buf[1] == 0xfc)
- {
- if (get_next_frame (fi) == NULL)
- deprecated_update_frame_base_hack (fi, read_sp ());
- return get_frame_pc (fi);
- }
-
- /* Similarly if we're stopped on the first insn of a prologue as our
- frame hasn't been allocated yet. */
- if (fi && get_frame_pc (fi) == func_addr)
- {
- if (get_next_frame (fi) == NULL)
- deprecated_update_frame_base_hack (fi, read_sp ());
- return get_frame_pc (fi);
+ addr = pc;
+ goto finish_prologue;
}
-#endif
-
- /* NOTE: from here on, we don't want to return without jumping to
- finish_prologue. */
-
/* Figure out where to stop scanning. */
stop = fi ? pc : func_end;
addr = func_addr;
/* Suck in two bytes. */
- if (addr + 2 >= stop
- || (status = deprecated_read_memory_nobpt (addr, buf, 2)) != 0)
+ if (addr + 2 > stop || !safe_frame_unwind_memory (fi, addr, buf, 2))
goto finish_prologue;
/* First see if this insn sets the stack pointer from a register; if
so mark this as the bottom-most frame. */
if (buf[0] == 0xf2 && (buf[1] & 0xf3) == 0xf0)
{
- if (fi)
- my_frame_is_last (fi);
goto finish_prologue;
}
goto finish_prologue;
/* Get the next two bytes so the prologue scan can continue. */
- status = deprecated_read_memory_nobpt (addr, buf, 2);
- if (status != 0)
+ if (!safe_frame_unwind_memory (fi, addr, buf, 2))
goto finish_prologue;
}
+ if (AM33_MODE == 2)
+ {
+ /* Determine if any floating point registers are to be saved.
+ Look for one of the following three prologue formats:
+
+ [movm [regs],(sp)] [movm [regs],(sp)] [movm [regs],(sp)]
+
+ add -SIZE,sp add -SIZE,sp add -SIZE,sp
+ fmov fs#,(sp) mov sp,a0/a1 mov sp,a0/a1
+ fmov fs#,(#,sp) fmov fs#,(a0/a1+) add SIZE2,a0/a1
+ ... ... fmov fs#,(a0/a1+)
+ ... ... ...
+ fmov fs#,(#,sp) fmov fs#,(a0/a1+) fmov fs#,(a0/a1+)
+
+ [mov sp,a3] [mov sp,a3]
+ [add -SIZE2,sp] [add -SIZE2,sp] */
+
+ /* Remember the address at which we started in the event that we
+ don't ultimately find an fmov instruction. Once we're certain
+ that we matched one of the above patterns, we'll set
+ ``restore_addr'' to the appropriate value. Note: At one time
+ in the past, this code attempted to not adjust ``addr'' until
+ there was a fair degree of certainty that the pattern would be
+ matched. However, that code did not wait until an fmov instruction
+ was actually encountered. As a consequence, ``addr'' would
+ sometimes be advanced even when no fmov instructions were found. */
+ CORE_ADDR restore_addr = addr;
+
+ /* First, look for add -SIZE,sp (i.e. add imm8,sp (0xf8feXX)
+ or add imm16,sp (0xfafeXXXX)
+ or add imm32,sp (0xfcfeXXXXXXXX)) */
+ imm_size = 0;
+ if (buf[0] == 0xf8 && buf[1] == 0xfe)
+ imm_size = 1;
+ else if (buf[0] == 0xfa && buf[1] == 0xfe)
+ imm_size = 2;
+ else if (buf[0] == 0xfc && buf[1] == 0xfe)
+ imm_size = 4;
+ if (imm_size != 0)
+ {
+ /* An "add -#,sp" instruction has been found. "addr + 2 + imm_size"
+ is the address of the next instruction. Don't modify "addr" until
+ the next "floating point prologue" instruction is found. If this
+ is not a prologue that saves floating point registers we need to
+ be able to back out of this bit of code and continue with the
+ prologue analysis. */
+ if (addr + 2 + imm_size < stop)
+ {
+ if (!safe_frame_unwind_memory (fi, addr + 2 + imm_size, buf, 3))
+ goto finish_prologue;
+ if ((buf[0] & 0xfc) == 0x3c)
+ {
+ /* Occasionally, especially with C++ code, the "fmov"
+ instructions will be preceded by "mov sp,aN"
+ (aN => a0, a1, a2, or a3).
+
+ This is a one byte instruction: mov sp,aN = 0011 11XX
+ where XX is the register number.
+
+ Skip this instruction by incrementing addr. The "fmov"
+ instructions will have the form "fmov fs#,(aN+)" in this
+ case, but that will not necessitate a change in the
+ "fmov" parsing logic below. */
+
+ addr++;
+
+ if ((buf[1] & 0xfc) == 0x20)
+ {
+ /* Occasionally, especially with C++ code compiled with
+ the -fomit-frame-pointer or -O3 options, the
+ "mov sp,aN" instruction will be followed by an
+ "add #,aN" instruction. This indicates the
+ "stack_size", the size of the portion of the stack
+ containing the arguments. This instruction format is:
+ add #,aN = 0010 00XX YYYY YYYY
+ where XX is the register number
+ YYYY YYYY is the constant.
+ Note the size of the stack (as a negative number) in
+ the frame info structure. */
+ if (fi)
+ stack_extra_size += -buf[2];
+
+ addr += 2;
+ }
+ }
+
+ if ((buf[0] & 0xfc) == 0x3c ||
+ buf[0] == 0xf9 || buf[0] == 0xfb)
+ {
+ /* An "fmov" instruction has been found indicating that this
+ prologue saves floating point registers (or, as described
+ above, a "mov sp,aN" and possible "add #,aN" have been
+ found and we will assume an "fmov" follows). Process the
+ consecutive "fmov" instructions. */
+ for (addr += 2 + imm_size;;addr += imm_size)
+ {
+ int regnum;
+
+ /* Read the "fmov" instruction. */
+ if (addr >= stop ||
+ !safe_frame_unwind_memory (fi, addr, buf, 4))
+ goto finish_prologue;
+
+ if (buf[0] != 0xf9 && buf[0] != 0xfb)
+ break;
+
+ /* An fmov instruction has just been seen. We can
+ now really commit to the pattern match. Set the
+ address to restore at the end of this speculative
+ bit of code to the actually address that we've
+ been incrementing (or not) throughout the
+ speculation. */
+ restore_addr = addr;
+
+ /* Get the floating point register number from the
+ 2nd and 3rd bytes of the "fmov" instruction:
+ Machine Code: 0000 00X0 YYYY 0000 =>
+ Regnum: 000X YYYY */
+ regnum = (buf[1] & 0x02) << 3;
+ regnum |= ((buf[2] & 0xf0) >> 4) & 0x0f;
+
+ /* Add this register number to the bit mask of floating
+ point registers that have been saved. */
+ fpregmask |= 1 << regnum;
+
+ /* Determine the length of this "fmov" instruction.
+ fmov fs#,(sp) => 3 byte instruction
+ fmov fs#,(#,sp) => 4 byte instruction */
+ imm_size = (buf[0] == 0xf9) ? 3 : 4;
+ }
+ }
+ else
+ {
+ /* No "fmov" was found. Reread the two bytes at the original
+ "addr" to reset the state. */
+ addr = restore_addr;
+ if (!safe_frame_unwind_memory (fi, addr, buf, 2))
+ goto finish_prologue;
+ }
+ }
+ /* else the prologue consists entirely of an "add -SIZE,sp"
+ instruction. Handle this below. */
+ }
+ /* else no "add -SIZE,sp" was found indicating no floating point
+ registers are saved in this prologue. */
+
+ /* In the pattern match code contained within this block, `restore_addr'
+ is set to the starting address at the very beginning and then
+ iteratively to the next address to start scanning at once the
+ pattern match has succeeded. Thus `restore_addr' will contain
+ the address to rewind to if the pattern match failed. If the
+ match succeeded, `restore_addr' and `addr' will already have the
+ same value. */
+ addr = restore_addr;
+ }
+
/* Now see if we set up a frame pointer via "mov sp,a3" */
if (buf[0] == 0x3f)
{
/* The frame pointer is now valid. */
if (fi)
{
- my_frame_is_in_fp (fi, this_cache);
+ frame_in_fp = 1;
}
/* Quit now if we're beyond the stop point. */
goto finish_prologue;
/* Get two more bytes so scanning can continue. */
- status = deprecated_read_memory_nobpt (addr, buf, 2);
- if (status != 0)
+ if (!safe_frame_unwind_memory (fi, addr, buf, 2))
goto finish_prologue;
}
{
/* Suck in imm_size more bytes, they'll hold the size of the
current frame. */
- status = deprecated_read_memory_nobpt (addr + 2, buf, imm_size);
- if (status != 0)
+ if (!safe_frame_unwind_memory (fi, addr + 2, buf, imm_size))
goto finish_prologue;
- /* Note the size of the stack in the frame info structure. */
- stack_size = extract_signed_integer (buf, imm_size);
- if (fi)
- set_my_stack_size (fi, stack_size);
+ /* Note the size of the stack. */
+ stack_extra_size -= extract_signed_integer (buf, imm_size);
/* We just consumed 2 + imm_size bytes. */
addr += 2 + imm_size;
finish_prologue:
/* Note if/where callee saved registers were saved. */
if (fi)
- set_movm_offsets (fi, this_cache, movm_args);
+ set_reg_offsets (fi, this_cache, movm_args, fpregmask, stack_extra_size, frame_in_fp);
return addr;
}
frame_id_build (trad_frame_get_this_base (cache),
start));
else
- trad_frame_set_id (cache,
- frame_id_build (trad_frame_get_this_base (cache),
- frame_func_unwind (next_frame)));
+ {
+ start = frame_func_unwind (next_frame, NORMAL_FRAME);
+ trad_frame_set_id (cache,
+ frame_id_build (trad_frame_get_this_base (cache),
+ start));
+ }
(*this_prologue_cache) = cache;
return cache;
if (struct_return)
{
regs_used = 1;
- write_register (E_D0_REGNUM, struct_addr);
+ regcache_cooked_write_unsigned (regcache, E_D0_REGNUM, struct_addr);
}
else
regs_used = 0;
while (regs_used < 2 && arg_len > 0)
{
- write_register (regs_used,
- extract_unsigned_integer (val, push_size));
+ regcache_cooked_write_unsigned (regcache, regs_used,
+ extract_unsigned_integer (val, push_size));
val += push_size;
arg_len -= push_size;
regs_used++;
/* Push the return address that contains the magic breakpoint. */
sp -= 4;
write_memory_unsigned_integer (sp, push_size, bp_addr);
+
+ /* The CPU also writes the return address always into the
+ MDR register on "call". */
+ regcache_cooked_write_unsigned (regcache, E_MDR_REGNUM, bp_addr);
+
/* Update $sp. */
regcache_cooked_write_unsigned (regcache, E_SP_REGNUM, sp);
return sp;
static int
mn10300_dwarf2_reg_to_regnum (int dwarf2)
{
- /* This table is supposed to be shaped like the REGISTER_NAMES
+ /* This table is supposed to be shaped like the gdbarch_register_name
initializer in gcc/config/mn10300/mn10300.h. Registers which
appear in GCC's numbering, but have no counterpart in GDB's
world, are marked with a -1. */
if (dwarf2 < 0
|| dwarf2 >= ARRAY_SIZE (dwarf2_to_gdb)
|| dwarf2_to_gdb[dwarf2] == -1)
- warning (_("bogus register number in debug info: %d"), dwarf2);
+ {
+ warning (_("Bogus register number in debug info: %d"), dwarf2);
+ return 0;
+ }
return dwarf2_to_gdb[dwarf2];
}
{
struct gdbarch *gdbarch;
struct gdbarch_tdep *tdep;
+ int num_regs;
arches = gdbarch_list_lookup_by_info (arches, &info);
if (arches != NULL)
case bfd_mach_mn10300:
set_gdbarch_register_name (gdbarch, mn10300_generic_register_name);
tdep->am33_mode = 0;
+ num_regs = 32;
break;
case bfd_mach_am33:
set_gdbarch_register_name (gdbarch, am33_register_name);
tdep->am33_mode = 1;
+ num_regs = 32;
+ break;
+ case bfd_mach_am33_2:
+ set_gdbarch_register_name (gdbarch, am33_2_register_name);
+ tdep->am33_mode = 2;
+ num_regs = 64;
+ set_gdbarch_fp0_regnum (gdbarch, 32);
break;
default:
internal_error (__FILE__, __LINE__,
}
/* Registers. */
- set_gdbarch_num_regs (gdbarch, E_NUM_REGS);
+ set_gdbarch_num_regs (gdbarch, num_regs);
set_gdbarch_register_type (gdbarch, mn10300_register_type);
set_gdbarch_skip_prologue (gdbarch, mn10300_skip_prologue);
set_gdbarch_read_pc (gdbarch, mn10300_read_pc);