/* Target-dependent code for Renesas M32R, for GDB.
- Copyright 1996, 1998, 1999, 2000, 2001, 2002, 2003 Free Software
- Foundation, Inc.
+ Copyright (C) 1996, 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 "frame.h"
#include "inferior.h"
#include "symfile.h"
#include "objfiles.h"
+#include "osabi.h"
#include "language.h"
#include "arch-utils.h"
#include "regcache.h"
}
-/* BREAKPOINT */
-#define M32R_BE_BREAKPOINT32 {0x10, 0xf1, 0x70, 0x00}
-#define M32R_LE_BREAKPOINT32 {0xf1, 0x10, 0x00, 0x70}
-#define M32R_BE_BREAKPOINT16 {0x10, 0xf1}
-#define M32R_LE_BREAKPOINT16 {0xf1, 0x10}
+/* Breakpoints
+
+ The little endian mode of M32R is unique. In most of architectures,
+ two 16-bit instructions, A and B, are placed as the following:
+
+ Big endian:
+ A0 A1 B0 B1
+
+ Little endian:
+ A1 A0 B1 B0
+
+ In M32R, they are placed like this:
+
+ Big endian:
+ A0 A1 B0 B1
+
+ Little endian:
+ B1 B0 A1 A0
+
+ This is because M32R always fetches instructions in 32-bit.
+
+ The following functions take care of this behavior. */
static int
-m32r_memory_insert_breakpoint (CORE_ADDR addr, char *contents_cache)
+m32r_memory_insert_breakpoint (struct bp_target_info *bp_tgt)
{
+ CORE_ADDR addr = bp_tgt->placed_address;
int val;
- unsigned char *bp;
- int bplen;
-
- bplen = (addr & 3) ? 2 : 4;
+ gdb_byte buf[4];
+ gdb_byte *contents_cache = bp_tgt->shadow_contents;
+ gdb_byte bp_entry[] = { 0x10, 0xf1 }; /* dpt */
/* Save the memory contents. */
- val = target_read_memory (addr, contents_cache, bplen);
+ val = target_read_memory (addr & 0xfffffffc, contents_cache, 4);
if (val != 0)
return val; /* return error */
+ bp_tgt->placed_size = bp_tgt->shadow_len = 4;
+
/* Determine appropriate breakpoint contents and size for this address. */
if (TARGET_BYTE_ORDER == BFD_ENDIAN_BIG)
{
- if (((addr & 3) == 0)
- && ((contents_cache[0] & 0x80) || (contents_cache[2] & 0x80)))
+ if ((addr & 3) == 0)
{
- static unsigned char insn[] = M32R_BE_BREAKPOINT32;
- bp = insn;
- bplen = sizeof (insn);
+ buf[0] = bp_entry[0];
+ buf[1] = bp_entry[1];
+ buf[2] = contents_cache[2] & 0x7f;
+ buf[3] = contents_cache[3];
}
else
{
- static unsigned char insn[] = M32R_BE_BREAKPOINT16;
- bp = insn;
- bplen = sizeof (insn);
+ buf[0] = contents_cache[0];
+ buf[1] = contents_cache[1];
+ buf[2] = bp_entry[0];
+ buf[3] = bp_entry[1];
}
}
- else
- { /* little-endian */
- if (((addr & 3) == 0)
- && ((contents_cache[1] & 0x80) || (contents_cache[3] & 0x80)))
+ else /* little-endian */
+ {
+ if ((addr & 3) == 0)
{
- static unsigned char insn[] = M32R_LE_BREAKPOINT32;
- bp = insn;
- bplen = sizeof (insn);
+ buf[0] = contents_cache[0];
+ buf[1] = contents_cache[1] & 0x7f;
+ buf[2] = bp_entry[1];
+ buf[3] = bp_entry[0];
}
else
{
- static unsigned char insn[] = M32R_LE_BREAKPOINT16;
- bp = insn;
- bplen = sizeof (insn);
+ buf[0] = bp_entry[1];
+ buf[1] = bp_entry[0];
+ buf[2] = contents_cache[2];
+ buf[3] = contents_cache[3];
}
}
/* Write the breakpoint. */
- val = target_write_memory (addr, (char *) bp, bplen);
+ val = target_write_memory (addr & 0xfffffffc, buf, 4);
return val;
}
static int
-m32r_memory_remove_breakpoint (CORE_ADDR addr, char *contents_cache)
+m32r_memory_remove_breakpoint (struct bp_target_info *bp_tgt)
{
+ CORE_ADDR addr = bp_tgt->placed_address;
int val;
- int bplen;
+ gdb_byte buf[4];
+ gdb_byte *contents_cache = bp_tgt->shadow_contents;
- /* Determine appropriate breakpoint contents and size for this address. */
+ buf[0] = contents_cache[0];
+ buf[1] = contents_cache[1];
+ buf[2] = contents_cache[2];
+ buf[3] = contents_cache[3];
+
+ /* Remove parallel bit. */
if (TARGET_BYTE_ORDER == BFD_ENDIAN_BIG)
{
- if (((addr & 3) == 0)
- && ((contents_cache[0] & 0x80) || (contents_cache[2] & 0x80)))
- {
- static unsigned char insn[] = M32R_BE_BREAKPOINT32;
- bplen = sizeof (insn);
- }
- else
- {
- static unsigned char insn[] = M32R_BE_BREAKPOINT16;
- bplen = sizeof (insn);
- }
+ if ((buf[0] & 0x80) == 0 && (buf[2] & 0x80) != 0)
+ buf[2] &= 0x7f;
}
- else
+ else /* little-endian */
{
- /* little-endian */
- if (((addr & 3) == 0)
- && ((contents_cache[1] & 0x80) || (contents_cache[3] & 0x80)))
- {
- static unsigned char insn[] = M32R_BE_BREAKPOINT32;
- bplen = sizeof (insn);
- }
- else
- {
- static unsigned char insn[] = M32R_BE_BREAKPOINT16;
- bplen = sizeof (insn);
- }
+ if ((buf[3] & 0x80) == 0 && (buf[1] & 0x80) != 0)
+ buf[1] &= 0x7f;
}
/* Write contents. */
- val = target_write_memory (addr, contents_cache, bplen);
+ val = target_write_memory (addr & 0xfffffffc, buf, 4);
return val;
}
-static const unsigned char *
+static const gdb_byte *
m32r_breakpoint_from_pc (CORE_ADDR *pcptr, int *lenptr)
{
- unsigned char *bp;
+ static gdb_byte be_bp_entry[] = { 0x10, 0xf1, 0x70, 0x00 }; /* dpt -> nop */
+ static gdb_byte le_bp_entry[] = { 0x00, 0x70, 0xf1, 0x10 }; /* dpt -> nop */
+ gdb_byte *bp;
/* Determine appropriate breakpoint. */
if (TARGET_BYTE_ORDER == BFD_ENDIAN_BIG)
{
if ((*pcptr & 3) == 0)
{
- static unsigned char insn[] = M32R_BE_BREAKPOINT32;
- bp = insn;
- *lenptr = sizeof (insn);
+ bp = be_bp_entry;
+ *lenptr = 4;
}
else
{
- static unsigned char insn[] = M32R_BE_BREAKPOINT16;
- bp = insn;
- *lenptr = sizeof (insn);
+ bp = be_bp_entry;
+ *lenptr = 2;
}
}
else
{
if ((*pcptr & 3) == 0)
{
- static unsigned char insn[] = M32R_LE_BREAKPOINT32;
- bp = insn;
- *lenptr = sizeof (insn);
+ bp = le_bp_entry;
+ *lenptr = 4;
}
else
{
- static unsigned char insn[] = M32R_LE_BREAKPOINT16;
- bp = insn;
- *lenptr = sizeof (insn);
+ bp = le_bp_entry + 2;
+ *lenptr = 2;
}
}
if (len > 4)
{
- regval = extract_unsigned_integer ((char *) valbuf + 4, len - 4);
+ regval = extract_unsigned_integer ((gdb_byte *) valbuf + 4, len - 4);
regcache_cooked_write_unsigned (regcache, RET1_REGNUM + 1, regval);
}
}
/* This is required by skip_prologue. The results of decoding a prologue
should be cached because this thrashing is getting nuts. */
-static void
+static int
decode_prologue (CORE_ADDR start_pc, CORE_ADDR scan_limit,
- CORE_ADDR *pl_endptr)
+ CORE_ADDR *pl_endptr, unsigned long *framelength)
{
unsigned long framesize;
int insn;
int op1;
- int maybe_one_more = 0;
CORE_ADDR after_prologue = 0;
+ CORE_ADDR after_push = 0;
CORE_ADDR after_stack_adjust = 0;
CORE_ADDR current_pc;
+ LONGEST return_value;
framesize = 0;
after_prologue = 0;
for (current_pc = start_pc; current_pc < scan_limit; current_pc += 2)
{
+ /* Check if current pc's location is readable. */
+ if (!safe_read_memory_integer (current_pc, 2, &return_value))
+ return -1;
+
insn = read_memory_unsigned_integer (current_pc, 2);
+ if (insn == 0x0000)
+ break;
+
/* If this is a 32 bit instruction, we dont want to examine its
immediate data as though it were an instruction */
if (current_pc & 0x02)
{
- /* Clear the parallel execution bit from 16 bit instruction */
- if (maybe_one_more)
- {
- /* The last instruction was a branch, usually terminates
- the series, but if this is a parallel instruction,
- it may be a stack framing instruction */
- if (!(insn & 0x8000))
- {
- /* nope, we are really done */
- break;
- }
- }
/* decode this instruction further */
insn &= 0x7fff;
}
else
{
- if (maybe_one_more)
- break; /* This isnt the one more */
if (insn & 0x8000)
{
if (current_pc == scan_limit)
scan_limit += 2; /* extend the search */
+
current_pc += 2; /* skip the immediate data */
+
+ /* Check if current pc's location is readable. */
+ if (!safe_read_memory_integer (current_pc, 2, &return_value))
+ return -1;
+
if (insn == 0x8faf) /* add3 sp, sp, xxxx */
/* add 16 bit sign-extended offset */
{
else
{
if (((insn >> 8) == 0xe4) /* ld24 r4, xxxxxx; sub sp, r4 */
+ && safe_read_memory_integer (current_pc + 2, 2,
+ &return_value)
&& read_memory_unsigned_integer (current_pc + 2,
2) == 0x0f24)
/* subtract 24 bit sign-extended negative-offset */
framesize += insn;
}
}
- after_prologue = current_pc;
+ after_push = current_pc + 2;
continue;
}
}
if ((insn >> 8) == 0x4f) /* addi sp, xx */
/* add 8 bit sign-extended offset */
{
- int stack_adjust = (char) (insn & 0xff);
+ int stack_adjust = (gdb_byte) (insn & 0xff);
/* there are probably two of these stack adjustments:
1) A negative one in the prologue, and
after_prologue = current_pc + 2;
break; /* end of stack adjustments */
}
+
/* Nop looks like a branch, continue explicitly */
if (insn == 0x7000)
{
after_prologue = current_pc + 2;
continue; /* nop occurs between pushes */
}
+ /* End of prolog if any of these are trap instructions */
+ if ((insn & 0xfff0) == 0x10f0)
+ {
+ after_prologue = current_pc;
+ break;
+ }
/* End of prolog if any of these are branch instructions */
if ((op1 == 0x7000) || (op1 == 0xb000) || (op1 == 0xf000))
{
after_prologue = current_pc;
- maybe_one_more = 1;
continue;
}
/* Some of the branch instructions are mixed with other types */
if ((subop == 0x0ec0) || (subop == 0x0fc0))
{
after_prologue = current_pc;
- maybe_one_more = 1;
continue; /* jmp , jl */
}
}
}
+ if (framelength)
+ *framelength = framesize;
+
if (current_pc >= scan_limit)
{
if (pl_endptr)
{
*pl_endptr = after_stack_adjust;
}
+ else if (after_push != 0)
+ /* We did not find a "mv fp,sp", but we DID find
+ a push. Is it safe to use that as the
+ end of the prologue? I just don't know. */
+ {
+ *pl_endptr = after_push;
+ }
else
/* We reached the end of the loop without finding the end
of the prologue. No way to win -- we should report failure.
GDB will set a breakpoint at the start of the function (etc.) */
*pl_endptr = start_pc;
}
- return;
+ return 0;
}
+
if (after_prologue == 0)
after_prologue = current_pc;
if (pl_endptr)
*pl_endptr = after_prologue;
+
+ return 0;
} /* decode_prologue */
/* Function: skip_prologue
Find end of function prologue */
-#define DEFAULT_SEARCH_LIMIT 44
+#define DEFAULT_SEARCH_LIMIT 128
CORE_ADDR
m32r_skip_prologue (CORE_ADDR pc)
{
CORE_ADDR func_addr, func_end;
struct symtab_and_line sal;
+ LONGEST return_value;
/* See what the symbol table says */
}
else
func_end = pc + DEFAULT_SEARCH_LIMIT;
- decode_prologue (pc, func_end, &sal.end);
+
+ /* If pc's location is not readable, just quit. */
+ if (!safe_read_memory_integer (pc, 4, &return_value))
+ return pc;
+
+ /* Find the end of prologue. */
+ if (decode_prologue (pc, func_end, &sal.end, NULL) < 0)
+ return pc;
+
return sal.end;
}
-
struct m32r_unwind_cache
{
/* The previous frame's inner most stack address. Used as this
m32r_frame_unwind_cache (struct frame_info *next_frame,
void **this_prologue_cache)
{
- CORE_ADDR pc;
+ CORE_ADDR pc, scan_limit;
ULONGEST prev_sp;
ULONGEST this_base;
- unsigned long op;
+ unsigned long op, op2;
int i;
struct m32r_unwind_cache *info;
+
if ((*this_prologue_cache))
return (*this_prologue_cache);
info->size = 0;
info->sp_offset = 0;
-
info->uses_frame = 0;
+
+ scan_limit = frame_pc_unwind (next_frame);
for (pc = frame_func_unwind (next_frame);
- pc > 0 && pc < frame_pc_unwind (next_frame); pc += 2)
+ pc > 0 && pc < scan_limit; pc += 2)
{
if ((pc & 2) == 0)
{
short n = op & 0xffff;
info->sp_offset += n;
}
- else if (((op >> 8) == 0xe4) /* ld24 r4, xxxxxx; sub sp, r4 */
- && get_frame_memory_unsigned (next_frame, pc + 4,
+ else if (((op >> 8) == 0xe4)
+ && get_frame_memory_unsigned (next_frame, pc + 2,
2) == 0x0f24)
{
+ /* ld24 r4, xxxxxx; sub sp, r4 */
unsigned long n = op & 0xffffff;
info->sp_offset += n;
- pc += 2;
+ pc += 2; /* skip sub instruction */
}
- else
- break;
- pc += 2;
+ if (pc == scan_limit)
+ scan_limit += 2; /* extend the search */
+ pc += 2; /* skip the immediate data */
continue;
}
}
else if ((op & 0xff00) == 0x4f00)
{
/* addi sp, xx */
- int n = (char) (op & 0xff);
+ int n = (gdb_byte) (op & 0xff);
info->sp_offset += n;
}
else if (op == 0x1d8f)
/* mv fp, sp */
info->uses_frame = 1;
info->r13_offset = info->sp_offset;
+ break; /* end of stack adjustments */
+ }
+ else if ((op & 0xfff0) == 0x10f0)
+ {
+ /* end of prologue if this is a trap instruction */
+ break; /* end of stack adjustments */
}
- else if (op == 0x7000)
- /* nop */
- continue;
- else
- break;
}
info->size = -info->sp_offset;
struct type *type;
enum type_code typecode;
CORE_ADDR regval;
- char *val;
- char valbuf[MAX_REGISTER_SIZE];
+ gdb_byte *val;
+ gdb_byte valbuf[MAX_REGISTER_SIZE];
int len;
int odd_sized_struct;
/* Now make sure there's space on the stack */
for (argnum = 0, stack_alloc = 0; argnum < nargs; argnum++)
- stack_alloc += ((TYPE_LENGTH (VALUE_TYPE (args[argnum])) + 3) & ~3);
+ stack_alloc += ((TYPE_LENGTH (value_type (args[argnum])) + 3) & ~3);
sp -= stack_alloc; /* make room on stack for args */
for (argnum = 0, stack_offset = 0; argnum < nargs; argnum++)
{
- type = VALUE_TYPE (args[argnum]);
+ type = value_type (args[argnum]);
typecode = TYPE_CODE (type);
len = TYPE_LENGTH (type);
{
/* value gets right-justified in the register or stack word */
memcpy (valbuf + (register_size (gdbarch, argreg) - len),
- (char *) VALUE_CONTENTS (args[argnum]), len);
+ (gdb_byte *) value_contents (args[argnum]), len);
val = valbuf;
}
else
- val = (char *) VALUE_CONTENTS (args[argnum]);
+ val = (gdb_byte *) value_contents (args[argnum]);
while (len > 0)
{
enum return_value_convention
m32r_return_value (struct gdbarch *gdbarch, struct type *valtype,
- struct regcache *regcache, void *readbuf,
- const void *writebuf)
+ struct regcache *regcache, gdb_byte *readbuf,
+ const gdb_byte *writebuf)
{
if (TYPE_LENGTH (valtype) > 8)
return RETURN_VALUE_STRUCT_CONVENTION;
void **this_prologue_cache,
int regnum, int *optimizedp,
enum lval_type *lvalp, CORE_ADDR *addrp,
- int *realnump, void *bufferp)
+ int *realnump, gdb_byte *bufferp)
{
struct m32r_unwind_cache *info
= m32r_frame_unwind_cache (next_frame, this_prologue_cache);
set_gdbarch_frame_align (gdbarch, m32r_frame_align);
- frame_unwind_append_sniffer (gdbarch, m32r_frame_sniffer);
frame_base_set_default (gdbarch, &m32r_frame_base);
/* Methods for saving / extracting a dummy frame's ID. The ID's
set_gdbarch_print_insn (gdbarch, print_insn_m32r);
+ /* Hook in ABI-specific overrides, if they have been registered. */
+ gdbarch_init_osabi (info, gdbarch);
+
+ /* Hook in the default unwinders. */
+ frame_unwind_append_sniffer (gdbarch, m32r_frame_sniffer);
+
return gdbarch;
}