/* Target-dependent code for Renesas M32R, for GDB.
- Copyright 1996, 1998, 1999, 2000, 2001, 2002, 2003 Free Software
- Foundation, Inc.
+ Copyright 1996, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005 Free
+ Software Foundation, Inc.
This file is part of GDB.
#include "inferior.h"
#include "symfile.h"
#include "objfiles.h"
+#include "osabi.h"
#include "language.h"
#include "arch-utils.h"
#include "regcache.h"
#include "gdb_assert.h"
-struct gdbarch_tdep
-{
- /* gdbarch target dependent data here. Currently unused for M32R. */
-};
-
-/* m32r register names. */
-
-enum
-{
- R0_REGNUM = 0,
- R3_REGNUM = 3,
- M32R_FP_REGNUM = 13,
- LR_REGNUM = 14,
- M32R_SP_REGNUM = 15,
- PSW_REGNUM = 16,
- M32R_PC_REGNUM = 21,
- /* m32r calling convention. */
- ARG1_REGNUM = R0_REGNUM,
- ARGN_REGNUM = R3_REGNUM,
- RET1_REGNUM = R0_REGNUM,
-};
+#include "m32r-tdep.h"
/* Local functions */
return sp & ~3;
}
-/* Should we use DEPRECATED_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).
-
- The m32r returns anything less than 8 bytes in size in
- registers. */
-
-static int
-m32r_use_struct_convention (int gcc_p, struct type *type)
-{
- return (TYPE_LENGTH (type) > 8);
-}
-
-/* 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 (CORE_ADDR addr, bfd_byte *contents_cache)
{
int val;
- unsigned char *bp;
- int bplen;
-
- bplen = (addr & 3) ? 2 : 4;
+ char buf[4];
+ char 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 */
/* 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 (CORE_ADDR addr, bfd_byte *contents_cache)
{
int val;
- int bplen;
+ char buf[4];
- /* 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 *
m32r_breakpoint_from_pc (CORE_ADDR *pcptr, int *lenptr)
{
+ static char be_bp_entry[] = { 0x10, 0xf1, 0x70, 0x00 }; /* dpt -> nop */
+ static char le_bp_entry[] = { 0x00, 0x70, 0xf1, 0x10 }; /* dpt -> nop */
unsigned char *bp;
/* Determine appropriate breakpoint. */
{
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;
}
}
"evb"
};
-static int
-m32r_num_regs (void)
-{
- return (sizeof (m32r_register_names) / sizeof (m32r_register_names[0]));
-}
-
static const char *
m32r_register_name (int reg_nr)
{
if (reg_nr < 0)
return NULL;
- if (reg_nr >= m32r_num_regs ())
+ if (reg_nr >= M32R_NUM_REGS)
return NULL;
return m32r_register_names[reg_nr];
}
}
}
-/* Extract from an array REGBUF containing the (raw) register state
- the address in which a function should return its structure value,
- as a CORE_ADDR (or an expression that can be used as one). */
-
-static CORE_ADDR
-m32r_extract_struct_value_address (struct regcache *regcache)
-{
- ULONGEST addr;
- regcache_cooked_read_unsigned (regcache, ARG1_REGNUM, &addr);
- return addr;
-}
-
-
/* 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;
}
}
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;
}
}
/* 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;
static CORE_ADDR
-m32r_push_dummy_call (struct gdbarch *gdbarch, CORE_ADDR func_addr,
+m32r_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
struct regcache *regcache, CORE_ADDR bp_addr, int nargs,
struct value **args, CORE_ADDR sp, int struct_return,
CORE_ADDR struct_addr)
/* 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);
+ (char *) value_contents (args[argnum]), len);
val = valbuf;
}
else
- val = (char *) VALUE_CONTENTS (args[argnum]);
+ val = (char *) 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)
+{
+ if (TYPE_LENGTH (valtype) > 8)
+ return RETURN_VALUE_STRUCT_CONVENTION;
+ else
+ {
+ if (readbuf != NULL)
+ m32r_extract_return_value (valtype, regcache, readbuf);
+ if (writebuf != NULL)
+ m32r_store_return_value (valtype, regcache, writebuf);
+ return RETURN_VALUE_REGISTER_CONVENTION;
+ }
+}
+
+
static CORE_ADDR
m32r_unwind_pc (struct gdbarch *gdbarch, struct frame_info *next_frame)
return;
id = frame_id_build (base, func);
-
- /* Check that we're not going round in circles with the same frame
- ID (but avoid applying the test to sentinel frames which do go
- round in circles). Can't use frame_id_eq() as that doesn't yet
- compare the frame's PC value. */
- if (frame_relative_level (next_frame) >= 0
- && get_frame_type (next_frame) != DUMMY_FRAME
- && frame_id_eq (get_frame_id (next_frame), id))
- return;
-
(*this_id) = id;
}
{
struct m32r_unwind_cache *info
= m32r_frame_unwind_cache (next_frame, this_prologue_cache);
- trad_frame_prev_register (next_frame, info->saved_regs, regnum,
- optimizedp, lvalp, addrp, realnump, bufferp);
+ trad_frame_get_prev_register (next_frame, info->saved_regs, regnum,
+ optimizedp, lvalp, addrp, realnump, bufferp);
}
static const struct frame_unwind m32r_frame_unwind = {
set_gdbarch_write_pc (gdbarch, m32r_write_pc);
set_gdbarch_unwind_sp (gdbarch, m32r_unwind_sp);
- set_gdbarch_num_regs (gdbarch, m32r_num_regs ());
+ set_gdbarch_num_regs (gdbarch, M32R_NUM_REGS);
set_gdbarch_sp_regnum (gdbarch, M32R_SP_REGNUM);
set_gdbarch_register_name (gdbarch, m32r_register_name);
set_gdbarch_register_type (gdbarch, m32r_register_type);
- set_gdbarch_extract_return_value (gdbarch, m32r_extract_return_value);
set_gdbarch_push_dummy_call (gdbarch, m32r_push_dummy_call);
- set_gdbarch_store_return_value (gdbarch, m32r_store_return_value);
- set_gdbarch_deprecated_extract_struct_value_address (gdbarch, m32r_extract_struct_value_address);
- set_gdbarch_use_struct_convention (gdbarch, m32r_use_struct_convention);
+ set_gdbarch_return_value (gdbarch, m32r_return_value);
set_gdbarch_skip_prologue (gdbarch, m32r_skip_prologue);
set_gdbarch_inner_than (gdbarch, core_addr_lessthan);
set_gdbarch_memory_remove_breakpoint (gdbarch,
m32r_memory_remove_breakpoint);
- set_gdbarch_frame_args_skip (gdbarch, 0);
- set_gdbarch_frameless_function_invocation (gdbarch,
- frameless_look_for_prologue);
-
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;
}