/* Target-dependent code for the Motorola 68000 series.
- Copyright 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1999, 2000,
- 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
+ Copyright (C) 1990-2015 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
+ the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
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. */
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
#include "defs.h"
#include "dwarf2-frame.h"
#include "frame.h"
#include "frame-base.h"
#include "frame-unwind.h"
-#include "floatformat.h"
+#include "gdbtypes.h"
#include "symtab.h"
#include "gdbcore.h"
#include "value.h"
-#include "gdb_string.h"
-#include "gdb_assert.h"
#include "inferior.h"
#include "regcache.h"
#include "arch-utils.h"
#include "osabi.h"
#include "dis-asm.h"
+#include "target-descriptions.h"
#include "m68k-tdep.h"
\f
#define P_MOVEL_SP 0x2f00
#define P_MOVEML_SP 0x48e7
-
-#define REGISTER_BYTES_FP (16*4 + 8 + 8*12 + 3*4)
-#define REGISTER_BYTES_NOFP (16*4 + 8)
-
-/* Offset from SP to first arg on stack at first instruction of a function */
+/* Offset from SP to first arg on stack at first instruction of a function. */
#define SP_ARG0 (1 * 4)
#if !defined (BPT_VECTOR)
#define BPT_VECTOR 0xf
#endif
-static const unsigned char *
-m68k_local_breakpoint_from_pc (CORE_ADDR *pcptr, int *lenptr)
+static const gdb_byte *
+m68k_local_breakpoint_from_pc (struct gdbarch *gdbarch,
+ CORE_ADDR *pcptr, int *lenptr)
{
- static unsigned char break_insn[] = {0x4e, (0x40 | BPT_VECTOR)};
+ static gdb_byte break_insn[] = {0x4e, (0x40 | BPT_VECTOR)};
*lenptr = sizeof (break_insn);
return break_insn;
}
+\f
+
+/* Construct types for ISA-specific registers. */
+static struct type *
+m68k_ps_type (struct gdbarch *gdbarch)
+{
+ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+
+ if (!tdep->m68k_ps_type)
+ {
+ struct type *type;
+
+ type = arch_flags_type (gdbarch, "builtin_type_m68k_ps", 4);
+ append_flags_type_flag (type, 0, "C");
+ append_flags_type_flag (type, 1, "V");
+ append_flags_type_flag (type, 2, "Z");
+ append_flags_type_flag (type, 3, "N");
+ append_flags_type_flag (type, 4, "X");
+ append_flags_type_flag (type, 8, "I0");
+ append_flags_type_flag (type, 9, "I1");
+ append_flags_type_flag (type, 10, "I2");
+ append_flags_type_flag (type, 12, "M");
+ append_flags_type_flag (type, 13, "S");
+ append_flags_type_flag (type, 14, "T0");
+ append_flags_type_flag (type, 15, "T1");
+
+ tdep->m68k_ps_type = type;
+ }
+ return tdep->m68k_ps_type;
+}
-static int
-m68k_register_bytes_ok (long numbytes)
+static struct type *
+m68881_ext_type (struct gdbarch *gdbarch)
{
- return ((numbytes == REGISTER_BYTES_FP)
- || (numbytes == REGISTER_BYTES_NOFP));
+ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+
+ if (!tdep->m68881_ext_type)
+ tdep->m68881_ext_type
+ = arch_float_type (gdbarch, -1, "builtin_type_m68881_ext",
+ floatformats_m68881_ext);
+
+ return tdep->m68881_ext_type;
}
/* Return the GDB type object for the "standard" data type of data in
static struct type *
m68k_register_type (struct gdbarch *gdbarch, int regnum)
{
- if (regnum >= FP0_REGNUM && regnum <= FP0_REGNUM + 7)
- return builtin_type_m68881_ext;
+ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
- if (regnum == M68K_FPI_REGNUM || regnum == PC_REGNUM)
- return builtin_type_void_func_ptr;
+ if (tdep->fpregs_present)
+ {
+ if (regnum >= gdbarch_fp0_regnum (gdbarch)
+ && regnum <= gdbarch_fp0_regnum (gdbarch) + 7)
+ {
+ if (tdep->flavour == m68k_coldfire_flavour)
+ return builtin_type (gdbarch)->builtin_double;
+ else
+ return m68881_ext_type (gdbarch);
+ }
- if (regnum == M68K_FPC_REGNUM || regnum == M68K_FPS_REGNUM
- || regnum == PS_REGNUM)
- return builtin_type_int32;
+ if (regnum == M68K_FPI_REGNUM)
+ return builtin_type (gdbarch)->builtin_func_ptr;
+
+ if (regnum == M68K_FPC_REGNUM || regnum == M68K_FPS_REGNUM)
+ return builtin_type (gdbarch)->builtin_int32;
+ }
+ else
+ {
+ if (regnum >= M68K_FP0_REGNUM && regnum <= M68K_FPI_REGNUM)
+ return builtin_type (gdbarch)->builtin_int0;
+ }
+
+ if (regnum == gdbarch_pc_regnum (gdbarch))
+ return builtin_type (gdbarch)->builtin_func_ptr;
if (regnum >= M68K_A0_REGNUM && regnum <= M68K_A0_REGNUM + 7)
- return builtin_type_void_data_ptr;
+ return builtin_type (gdbarch)->builtin_data_ptr;
- return builtin_type_int32;
-}
+ if (regnum == M68K_PS_REGNUM)
+ return m68k_ps_type (gdbarch);
-/* Function: m68k_register_name
- Returns the name of the standard m68k register regnum. */
+ return builtin_type (gdbarch)->builtin_int32;
+}
-static const char *
-m68k_register_name (int regnum)
-{
- static char *register_names[] = {
+static const char *m68k_register_names[] = {
"d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7",
"a0", "a1", "a2", "a3", "a4", "a5", "fp", "sp",
"ps", "pc",
"fp0", "fp1", "fp2", "fp3", "fp4", "fp5", "fp6", "fp7",
- "fpcontrol", "fpstatus", "fpiaddr", "fpcode", "fpflags"
+ "fpcontrol", "fpstatus", "fpiaddr"
};
- if (regnum < 0 ||
- regnum >= sizeof (register_names) / sizeof (register_names[0]))
+/* Function: m68k_register_name
+ Returns the name of the standard m68k register regnum. */
+
+static const char *
+m68k_register_name (struct gdbarch *gdbarch, int regnum)
+{
+ if (regnum < 0 || regnum >= ARRAY_SIZE (m68k_register_names))
internal_error (__FILE__, __LINE__,
- _("m68k_register_name: illegal register number %d"), regnum);
+ _("m68k_register_name: illegal register number %d"),
+ regnum);
+ else if (regnum >= M68K_FP0_REGNUM && regnum <= M68K_FPI_REGNUM
+ && gdbarch_tdep (gdbarch)->fpregs_present == 0)
+ return "";
else
- return register_names[regnum];
+ return m68k_register_names[regnum];
}
\f
/* Return nonzero if a value of type TYPE stored in register REGNUM
needs any special handling. */
static int
-m68k_convert_register_p (int regnum, struct type *type)
+m68k_convert_register_p (struct gdbarch *gdbarch,
+ int regnum, struct type *type)
{
- return (regnum >= M68K_FP0_REGNUM && regnum <= M68K_FP0_REGNUM + 7);
+ if (!gdbarch_tdep (gdbarch)->fpregs_present)
+ return 0;
+ return (regnum >= M68K_FP0_REGNUM && regnum <= M68K_FP0_REGNUM + 7
+ && type != register_type (gdbarch, M68K_FP0_REGNUM));
}
/* Read a value of type TYPE from register REGNUM in frame FRAME, and
return its contents in TO. */
-static void
+static int
m68k_register_to_value (struct frame_info *frame, int regnum,
- struct type *type, void *to)
+ struct type *type, gdb_byte *to,
+ int *optimizedp, int *unavailablep)
{
- char from[M68K_MAX_REGISTER_SIZE];
+ gdb_byte from[M68K_MAX_REGISTER_SIZE];
+ struct type *fpreg_type = register_type (get_frame_arch (frame),
+ M68K_FP0_REGNUM);
/* We only support floating-point values. */
if (TYPE_CODE (type) != TYPE_CODE_FLT)
{
warning (_("Cannot convert floating-point register value "
"to non-floating-point type."));
- return;
+ *optimizedp = *unavailablep = 0;
+ return 0;
}
- /* Convert to TYPE. This should be a no-op if TYPE is equivalent to
- the extended floating-point format used by the FPU. */
- get_frame_register (frame, regnum, from);
- convert_typed_floating (from, builtin_type_m68881_ext, to, type);
+ /* Convert to TYPE. */
+
+ /* Convert to TYPE. */
+ if (!get_frame_register_bytes (frame, regnum, 0, TYPE_LENGTH (type),
+ from, optimizedp, unavailablep))
+ return 0;
+
+ convert_typed_floating (from, fpreg_type, to, type);
+ *optimizedp = *unavailablep = 0;
+ return 1;
}
/* Write the contents FROM of a value of type TYPE into register
static void
m68k_value_to_register (struct frame_info *frame, int regnum,
- struct type *type, const void *from)
+ struct type *type, const gdb_byte *from)
{
- char to[M68K_MAX_REGISTER_SIZE];
+ gdb_byte to[M68K_MAX_REGISTER_SIZE];
+ struct type *fpreg_type = register_type (get_frame_arch (frame),
+ M68K_FP0_REGNUM);
/* We only support floating-point values. */
if (TYPE_CODE (type) != TYPE_CODE_FLT)
return;
}
- /* Convert from TYPE. This should be a no-op if TYPE is equivalent
- to the extended floating-point format used by the FPU. */
- convert_typed_floating (from, type, to, builtin_type_m68881_ext);
+ /* Convert from TYPE. */
+ convert_typed_floating (from, type, to, fpreg_type);
put_frame_register (frame, regnum, to);
}
static void
m68k_extract_return_value (struct type *type, struct regcache *regcache,
- void *valbuf)
+ gdb_byte *valbuf)
{
int len = TYPE_LENGTH (type);
- char buf[M68K_MAX_REGISTER_SIZE];
+ gdb_byte buf[M68K_MAX_REGISTER_SIZE];
if (len <= 4)
{
{
regcache_raw_read (regcache, M68K_D0_REGNUM, buf);
memcpy (valbuf, buf + (8 - len), len - 4);
- regcache_raw_read (regcache, M68K_D1_REGNUM,
- (char *) valbuf + (len - 4));
+ regcache_raw_read (regcache, M68K_D1_REGNUM, valbuf + (len - 4));
}
else
internal_error (__FILE__, __LINE__,
static void
m68k_svr4_extract_return_value (struct type *type, struct regcache *regcache,
- void *valbuf)
+ gdb_byte *valbuf)
{
- int len = TYPE_LENGTH (type);
- char buf[M68K_MAX_REGISTER_SIZE];
+ gdb_byte buf[M68K_MAX_REGISTER_SIZE];
+ struct gdbarch *gdbarch = get_regcache_arch (regcache);
+ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
- if (TYPE_CODE (type) == TYPE_CODE_FLT)
+ if (tdep->float_return && TYPE_CODE (type) == TYPE_CODE_FLT)
{
+ struct type *fpreg_type = register_type (gdbarch, M68K_FP0_REGNUM);
regcache_raw_read (regcache, M68K_FP0_REGNUM, buf);
- convert_typed_floating (buf, builtin_type_m68881_ext, valbuf, type);
+ convert_typed_floating (buf, fpreg_type, valbuf, type);
}
- else if (TYPE_CODE (type) == TYPE_CODE_PTR && len == 4)
+ else if (TYPE_CODE (type) == TYPE_CODE_PTR && TYPE_LENGTH (type) == 4)
regcache_raw_read (regcache, M68K_A0_REGNUM, valbuf);
else
m68k_extract_return_value (type, regcache, valbuf);
static void
m68k_store_return_value (struct type *type, struct regcache *regcache,
- const void *valbuf)
+ const gdb_byte *valbuf)
{
int len = TYPE_LENGTH (type);
{
regcache_raw_write_part (regcache, M68K_D0_REGNUM, 8 - len,
len - 4, valbuf);
- regcache_raw_write (regcache, M68K_D1_REGNUM,
- (char *) valbuf + (len - 4));
+ regcache_raw_write (regcache, M68K_D1_REGNUM, valbuf + (len - 4));
}
else
internal_error (__FILE__, __LINE__,
static void
m68k_svr4_store_return_value (struct type *type, struct regcache *regcache,
- const void *valbuf)
+ const gdb_byte *valbuf)
{
- int len = TYPE_LENGTH (type);
+ struct gdbarch *gdbarch = get_regcache_arch (regcache);
+ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
- if (TYPE_CODE (type) == TYPE_CODE_FLT)
+ if (tdep->float_return && TYPE_CODE (type) == TYPE_CODE_FLT)
{
- char buf[M68K_MAX_REGISTER_SIZE];
- convert_typed_floating (valbuf, type, buf, builtin_type_m68881_ext);
+ struct type *fpreg_type = register_type (gdbarch, M68K_FP0_REGNUM);
+ gdb_byte buf[M68K_MAX_REGISTER_SIZE];
+ convert_typed_floating (valbuf, type, buf, fpreg_type);
regcache_raw_write (regcache, M68K_FP0_REGNUM, buf);
}
- else if (TYPE_CODE (type) == TYPE_CODE_PTR && len == 4)
+ else if (TYPE_CODE (type) == TYPE_CODE_PTR && TYPE_LENGTH (type) == 4)
{
regcache_raw_write (regcache, M68K_A0_REGNUM, valbuf);
regcache_raw_write (regcache, M68K_D0_REGNUM, valbuf);
m68k_store_return_value (type, regcache, valbuf);
}
-/* Return non-zero if TYPE, which is assumed to be a structure or
- union type, should be returned in registers for architecture
+/* Return non-zero if TYPE, which is assumed to be a structure, union or
+ complex type, should be returned in registers for architecture
GDBARCH. */
static int
enum type_code code = TYPE_CODE (type);
int len = TYPE_LENGTH (type);
- gdb_assert (code == TYPE_CODE_STRUCT || code == TYPE_CODE_UNION);
+ gdb_assert (code == TYPE_CODE_STRUCT || code == TYPE_CODE_UNION
+ || code == TYPE_CODE_COMPLEX);
if (tdep->struct_return == pcc_struct_return)
return 0;
from WRITEBUF into REGCACHE. */
static enum return_value_convention
-m68k_return_value (struct gdbarch *gdbarch, struct type *type,
- struct regcache *regcache, void *readbuf,
- const void *writebuf)
+m68k_return_value (struct gdbarch *gdbarch, struct value *function,
+ struct type *type, struct regcache *regcache,
+ gdb_byte *readbuf, const gdb_byte *writebuf)
{
enum type_code code = TYPE_CODE (type);
- if ((code == TYPE_CODE_STRUCT || code == TYPE_CODE_UNION)
- && !m68k_reg_struct_return_p (gdbarch, type))
- return RETURN_VALUE_STRUCT_CONVENTION;
+ /* GCC returns a `long double' in memory too. */
+ if (((code == TYPE_CODE_STRUCT || code == TYPE_CODE_UNION
+ || code == TYPE_CODE_COMPLEX)
+ && !m68k_reg_struct_return_p (gdbarch, type))
+ || (code == TYPE_CODE_FLT && TYPE_LENGTH (type) == 12))
+ {
+ /* The default on m68k is to return structures in static memory.
+ Consequently a function must return the address where we can
+ find the return value. */
+
+ if (readbuf)
+ {
+ ULONGEST addr;
+
+ regcache_raw_read_unsigned (regcache, M68K_D0_REGNUM, &addr);
+ read_memory (addr, readbuf, TYPE_LENGTH (type));
+ }
- /* GCC returns a `long double' in memory. */
- if (code == TYPE_CODE_FLT && TYPE_LENGTH (type) == 12)
- return RETURN_VALUE_STRUCT_CONVENTION;
+ return RETURN_VALUE_ABI_RETURNS_ADDRESS;
+ }
if (readbuf)
m68k_extract_return_value (type, regcache, readbuf);
}
static enum return_value_convention
-m68k_svr4_return_value (struct gdbarch *gdbarch, struct type *type,
- struct regcache *regcache, void *readbuf,
- const void *writebuf)
+m68k_svr4_return_value (struct gdbarch *gdbarch, struct value *function,
+ struct type *type, struct regcache *regcache,
+ gdb_byte *readbuf, const gdb_byte *writebuf)
{
enum type_code code = TYPE_CODE (type);
- if ((code == TYPE_CODE_STRUCT || code == TYPE_CODE_UNION)
+ if ((code == TYPE_CODE_STRUCT || code == TYPE_CODE_UNION
+ || code == TYPE_CODE_COMPLEX)
&& !m68k_reg_struct_return_p (gdbarch, type))
{
/* The System V ABI says that:
if (code == TYPE_CODE_STRUCT && TYPE_NFIELDS (type) == 1)
{
type = check_typedef (TYPE_FIELD_TYPE (type, 0));
- return m68k_svr4_return_value (gdbarch, type, regcache,
+ return m68k_svr4_return_value (gdbarch, function, type, regcache,
readbuf, writebuf);
}
}
\f
+/* Always align the frame to a 4-byte boundary. This is required on
+ coldfire and harmless on the rest. */
+
+static CORE_ADDR
+m68k_frame_align (struct gdbarch *gdbarch, CORE_ADDR sp)
+{
+ /* Align the stack to four bytes. */
+ return sp & ~3;
+}
+
static CORE_ADDR
m68k_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
struct regcache *regcache, CORE_ADDR bp_addr, int nargs,
CORE_ADDR struct_addr)
{
struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
- char buf[4];
+ enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+ gdb_byte buf[4];
int i;
/* Push arguments in reverse order. */
/* Store struct value address. */
if (struct_return)
{
- store_unsigned_integer (buf, 4, struct_addr);
+ store_unsigned_integer (buf, 4, byte_order, struct_addr);
regcache_cooked_write (regcache, tdep->struct_value_regnum, buf);
}
/* Store return address. */
sp -= 4;
- store_unsigned_integer (buf, 4, bp_addr);
+ store_unsigned_integer (buf, 4, byte_order, bp_addr);
write_memory (sp, buf, 4);
/* Finally, update the stack pointer... */
- store_unsigned_integer (buf, 4, sp);
+ store_unsigned_integer (buf, 4, byte_order, sp);
regcache_cooked_write (regcache, M68K_SP_REGNUM, buf);
/* ...and fake a frame pointer. */
frame's CFA. */
return sp + 8;
}
+
+/* Convert a dwarf or dwarf2 regnumber to a GDB regnum. */
+
+static int
+m68k_dwarf_reg_to_regnum (struct gdbarch *gdbarch, int num)
+{
+ if (num < 8)
+ /* d0..7 */
+ return (num - 0) + M68K_D0_REGNUM;
+ else if (num < 16)
+ /* a0..7 */
+ return (num - 8) + M68K_A0_REGNUM;
+ else if (num < 24 && gdbarch_tdep (gdbarch)->fpregs_present)
+ /* fp0..7 */
+ return (num - 16) + M68K_FP0_REGNUM;
+ else if (num == 25)
+ /* pc */
+ return M68K_PC_REGNUM;
+ else
+ return gdbarch_num_regs (gdbarch) + gdbarch_num_pseudo_regs (gdbarch);
+}
+
\f
struct m68k_frame_cache
{
Otherwise, return PC. */
static CORE_ADDR
-m68k_analyze_frame_setup (CORE_ADDR pc, CORE_ADDR current_pc,
+m68k_analyze_frame_setup (struct gdbarch *gdbarch,
+ CORE_ADDR pc, CORE_ADDR current_pc,
struct m68k_frame_cache *cache)
{
+ enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
int op;
if (pc >= current_pc)
return current_pc;
- op = read_memory_unsigned_integer (pc, 2);
+ op = read_memory_unsigned_integer (pc, 2, byte_order);
if (op == P_LINKW_FP || op == P_LINKL_FP || op == P_PEA_FP)
{
{
/* link.w %fp, #-N */
/* link.w %fp, #0; adda.l #-N, %sp */
- cache->locals = -read_memory_integer (pc + 2, 2);
+ cache->locals = -read_memory_integer (pc + 2, 2, byte_order);
if (pc + 4 < current_pc && cache->locals == 0)
{
- op = read_memory_unsigned_integer (pc + 4, 2);
+ op = read_memory_unsigned_integer (pc + 4, 2, byte_order);
if (op == P_ADDAL_SP)
{
- cache->locals = read_memory_integer (pc + 6, 4);
+ cache->locals = read_memory_integer (pc + 6, 4, byte_order);
return pc + 10;
}
}
else if (op == P_LINKL_FP)
{
/* link.l %fp, #-N */
- cache->locals = -read_memory_integer (pc + 2, 4);
+ cache->locals = -read_memory_integer (pc + 2, 4, byte_order);
return pc + 6;
}
else
if (pc + 2 < current_pc)
{
- op = read_memory_unsigned_integer (pc + 2, 2);
+ op = read_memory_unsigned_integer (pc + 2, 2, byte_order);
if (op == P_MOVEAL_SP_FP)
{
cache->locals = (op & 07000) == 0 ? 8 : (op & 07000) >> 9;
if (pc + 2 < current_pc)
{
- op = read_memory_unsigned_integer (pc + 2, 2);
+ op = read_memory_unsigned_integer (pc + 2, 2, byte_order);
if ((op & 0170777) == P_SUBQW_SP || (op & 0170777) == P_SUBQL_SP)
{
cache->locals += (op & 07000) == 0 ? 8 : (op & 07000) >> 9;
{
/* adda.w #-N,%sp */
/* lea (-N,%sp),%sp */
- cache->locals = -read_memory_integer (pc + 2, 2);
+ cache->locals = -read_memory_integer (pc + 2, 2, byte_order);
return pc + 4;
}
else if (op == P_ADDAL_SP)
{
/* adda.l #-N,%sp */
- cache->locals = -read_memory_integer (pc + 2, 4);
+ cache->locals = -read_memory_integer (pc + 2, 4, byte_order);
return pc + 6;
}
smaller. Otherwise, return PC. */
static CORE_ADDR
-m68k_analyze_register_saves (CORE_ADDR pc, CORE_ADDR current_pc,
+m68k_analyze_register_saves (struct gdbarch *gdbarch, CORE_ADDR pc,
+ CORE_ADDR current_pc,
struct m68k_frame_cache *cache)
{
+ enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+
if (cache->locals >= 0)
{
CORE_ADDR offset;
offset = -4 - cache->locals;
while (pc < current_pc)
{
- op = read_memory_unsigned_integer (pc, 2);
- if (op == P_FMOVEMX_SP)
+ op = read_memory_unsigned_integer (pc, 2, byte_order);
+ if (op == P_FMOVEMX_SP
+ && gdbarch_tdep (gdbarch)->fpregs_present)
{
/* fmovem.x REGS,-(%sp) */
- op = read_memory_unsigned_integer (pc + 2, 2);
+ op = read_memory_unsigned_integer (pc + 2, 2, byte_order);
if ((op & 0xff00) == 0xe000)
{
mask = op & 0xff;
else
break;
}
- else if ((op & 0170677) == P_MOVEL_SP)
+ else if ((op & 0177760) == P_MOVEL_SP)
{
/* move.l %R,-(%sp) */
- regno = ((op & 07000) >> 9) | ((op & 0100) >> 3);
+ regno = op & 017;
cache->saved_regs[regno] = offset;
offset -= 4;
pc += 2;
else if (op == P_MOVEML_SP)
{
/* movem.l REGS,-(%sp) */
- mask = read_memory_unsigned_integer (pc + 2, 2);
+ mask = read_memory_unsigned_integer (pc + 2, 2, byte_order);
for (i = 0; i < 16; i++, mask >>= 1)
{
if (mask & 1)
*/
static CORE_ADDR
-m68k_analyze_prologue (CORE_ADDR pc, CORE_ADDR current_pc,
- struct m68k_frame_cache *cache)
+m68k_analyze_prologue (struct gdbarch *gdbarch, CORE_ADDR pc,
+ CORE_ADDR current_pc, struct m68k_frame_cache *cache)
{
+ enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
unsigned int op;
- pc = m68k_analyze_frame_setup (pc, current_pc, cache);
- pc = m68k_analyze_register_saves (pc, current_pc, cache);
+ pc = m68k_analyze_frame_setup (gdbarch, pc, current_pc, cache);
+ pc = m68k_analyze_register_saves (gdbarch, pc, current_pc, cache);
if (pc >= current_pc)
return current_pc;
/* Check for GOT setup. */
- op = read_memory_unsigned_integer (pc, 4);
+ op = read_memory_unsigned_integer (pc, 4, byte_order);
if (op == P_LEA_PC_A5)
{
/* lea (%pc,N),%a5 */
- return pc + 6;
+ return pc + 8;
}
return pc;
/* Return PC of first real instruction. */
static CORE_ADDR
-m68k_skip_prologue (CORE_ADDR start_pc)
+m68k_skip_prologue (struct gdbarch *gdbarch, CORE_ADDR start_pc)
{
struct m68k_frame_cache cache;
CORE_ADDR pc;
- int op;
cache.locals = -1;
- pc = m68k_analyze_prologue (start_pc, (CORE_ADDR) -1, &cache);
+ pc = m68k_analyze_prologue (gdbarch, start_pc, (CORE_ADDR) -1, &cache);
if (cache.locals < 0)
return start_pc;
return pc;
static CORE_ADDR
m68k_unwind_pc (struct gdbarch *gdbarch, struct frame_info *next_frame)
{
- char buf[8];
+ gdb_byte buf[8];
- frame_unwind_register (next_frame, PC_REGNUM, buf);
- return extract_typed_address (buf, builtin_type_void_func_ptr);
+ frame_unwind_register (next_frame, gdbarch_pc_regnum (gdbarch), buf);
+ return extract_typed_address (buf, builtin_type (gdbarch)->builtin_func_ptr);
}
\f
/* Normal frames. */
static struct m68k_frame_cache *
-m68k_frame_cache (struct frame_info *next_frame, void **this_cache)
+m68k_frame_cache (struct frame_info *this_frame, void **this_cache)
{
+ struct gdbarch *gdbarch = get_frame_arch (this_frame);
+ enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
struct m68k_frame_cache *cache;
- char buf[4];
+ gdb_byte buf[4];
int i;
if (*this_cache)
They (usually) share their frame pointer with the frame that was
in progress when the signal occurred. */
- frame_unwind_register (next_frame, M68K_FP_REGNUM, buf);
- cache->base = extract_unsigned_integer (buf, 4);
+ get_frame_register (this_frame, M68K_FP_REGNUM, buf);
+ cache->base = extract_unsigned_integer (buf, 4, byte_order);
if (cache->base == 0)
return cache;
/* For normal frames, %pc is stored at 4(%fp). */
cache->saved_regs[M68K_PC_REGNUM] = 4;
- cache->pc = frame_func_unwind (next_frame);
+ cache->pc = get_frame_func (this_frame);
if (cache->pc != 0)
- m68k_analyze_prologue (cache->pc, frame_pc_unwind (next_frame), cache);
+ m68k_analyze_prologue (get_frame_arch (this_frame), cache->pc,
+ get_frame_pc (this_frame), cache);
if (cache->locals < 0)
{
frame by looking at the stack pointer. For truly "frameless"
functions this might work too. */
- frame_unwind_register (next_frame, M68K_SP_REGNUM, buf);
- cache->base = extract_unsigned_integer (buf, 4) + cache->sp_offset;
+ get_frame_register (this_frame, M68K_SP_REGNUM, buf);
+ cache->base = extract_unsigned_integer (buf, 4, byte_order)
+ + cache->sp_offset;
}
/* Now that we have the base address for the stack frame we can
}
static void
-m68k_frame_this_id (struct frame_info *next_frame, void **this_cache,
+m68k_frame_this_id (struct frame_info *this_frame, void **this_cache,
struct frame_id *this_id)
{
- struct m68k_frame_cache *cache = m68k_frame_cache (next_frame, this_cache);
+ struct m68k_frame_cache *cache = m68k_frame_cache (this_frame, this_cache);
/* This marks the outermost frame. */
if (cache->base == 0)
*this_id = frame_id_build (cache->base + 8, cache->pc);
}
-static void
-m68k_frame_prev_register (struct frame_info *next_frame, void **this_cache,
- int regnum, int *optimizedp,
- enum lval_type *lvalp, CORE_ADDR *addrp,
- int *realnump, void *valuep)
+static struct value *
+m68k_frame_prev_register (struct frame_info *this_frame, void **this_cache,
+ int regnum)
{
- struct m68k_frame_cache *cache = m68k_frame_cache (next_frame, this_cache);
+ struct m68k_frame_cache *cache = m68k_frame_cache (this_frame, this_cache);
gdb_assert (regnum >= 0);
if (regnum == M68K_SP_REGNUM && cache->saved_sp)
- {
- *optimizedp = 0;
- *lvalp = not_lval;
- *addrp = 0;
- *realnump = -1;
- if (valuep)
- {
- /* Store the value. */
- store_unsigned_integer (valuep, 4, cache->saved_sp);
- }
- return;
- }
+ return frame_unwind_got_constant (this_frame, regnum, cache->saved_sp);
if (regnum < M68K_NUM_REGS && cache->saved_regs[regnum] != -1)
- {
- *optimizedp = 0;
- *lvalp = lval_memory;
- *addrp = cache->saved_regs[regnum];
- *realnump = -1;
- if (valuep)
- {
- /* Read the value in from memory. */
- read_memory (*addrp, valuep,
- register_size (current_gdbarch, regnum));
- }
- return;
- }
+ return frame_unwind_got_memory (this_frame, regnum,
+ cache->saved_regs[regnum]);
- *optimizedp = 0;
- *lvalp = lval_register;
- *addrp = 0;
- *realnump = regnum;
- if (valuep)
- frame_unwind_register (next_frame, (*realnump), valuep);
+ return frame_unwind_got_register (this_frame, regnum, regnum);
}
static const struct frame_unwind m68k_frame_unwind =
{
NORMAL_FRAME,
+ default_frame_unwind_stop_reason,
m68k_frame_this_id,
- m68k_frame_prev_register
+ m68k_frame_prev_register,
+ NULL,
+ default_frame_sniffer
};
-
-static const struct frame_unwind *
-m68k_frame_sniffer (struct frame_info *next_frame)
-{
- return &m68k_frame_unwind;
-}
\f
static CORE_ADDR
-m68k_frame_base_address (struct frame_info *next_frame, void **this_cache)
+m68k_frame_base_address (struct frame_info *this_frame, void **this_cache)
{
- struct m68k_frame_cache *cache = m68k_frame_cache (next_frame, this_cache);
+ struct m68k_frame_cache *cache = m68k_frame_cache (this_frame, this_cache);
return cache->base;
}
};
static struct frame_id
-m68k_unwind_dummy_id (struct gdbarch *gdbarch, struct frame_info *next_frame)
+m68k_dummy_id (struct gdbarch *gdbarch, struct frame_info *this_frame)
{
- char buf[4];
CORE_ADDR fp;
- frame_unwind_register (next_frame, M68K_FP_REGNUM, buf);
- fp = extract_unsigned_integer (buf, 4);
+ fp = get_frame_register_unsigned (this_frame, M68K_FP_REGNUM);
/* See the end of m68k_push_dummy_call. */
- return frame_id_build (fp + 8, frame_pc_unwind (next_frame));
+ return frame_id_build (fp + 8, get_frame_pc (this_frame));
}
\f
-#ifdef USE_PROC_FS /* Target dependent support for /proc */
-
-#include <sys/procfs.h>
-
-/* Prototypes for supply_gregset etc. */
-#include "gregset.h"
-
-/* The /proc interface divides the target machine's register set up into
- two different sets, the general register set (gregset) and the floating
- point register set (fpregset). For each set, there is an ioctl to get
- the current register set and another ioctl to set the current values.
-
- The actual structure passed through the ioctl interface is, of course,
- naturally machine dependent, and is different for each set of registers.
- For the m68k for example, the general register set is typically defined
- by:
-
- typedef int gregset_t[18];
-
- #define R_D0 0
- ...
- #define R_PS 17
-
- and the floating point set by:
-
- typedef struct fpregset {
- int f_pcr;
- int f_psr;
- int f_fpiaddr;
- int f_fpregs[8][3]; (8 regs, 96 bits each)
- } fpregset_t;
-
- These routines provide the packing and unpacking of gregset_t and
- fpregset_t formatted data.
-
- */
-
-/* Atari SVR4 has R_SR but not R_PS */
-
-#if !defined (R_PS) && defined (R_SR)
-#define R_PS R_SR
-#endif
-
-/* Given a pointer to a general register set in /proc format (gregset_t *),
- unpack the register contents and supply them as gdb's idea of the current
- register values. */
-
-void
-supply_gregset (gregset_t *gregsetp)
-{
- int regi;
- greg_t *regp = (greg_t *) gregsetp;
-
- for (regi = 0; regi < R_PC; regi++)
- {
- regcache_raw_supply (current_regcache, regi, (char *) (regp + regi));
- }
- regcache_raw_supply (current_regcache, PS_REGNUM, (char *) (regp + R_PS));
- regcache_raw_supply (current_regcache, PC_REGNUM, (char *) (regp + R_PC));
-}
-
-void
-fill_gregset (gregset_t *gregsetp, int regno)
-{
- int regi;
- greg_t *regp = (greg_t *) gregsetp;
-
- for (regi = 0; regi < R_PC; regi++)
- {
- if (regno == -1 || regno == regi)
- regcache_raw_collect (current_regcache, regi, regp + regi);
- }
- if (regno == -1 || regno == PS_REGNUM)
- regcache_raw_collect (current_regcache, PS_REGNUM, regp + R_PS);
- if (regno == -1 || regno == PC_REGNUM)
- regcache_raw_collect (current_regcache, PC_REGNUM, regp + R_PC);
-}
-
-#if defined (FP0_REGNUM)
-
-/* Given a pointer to a floating point register set in /proc format
- (fpregset_t *), unpack the register contents and supply them as gdb's
- idea of the current floating point register values. */
-
-void
-supply_fpregset (fpregset_t *fpregsetp)
-{
- int regi;
- char *from;
-
- for (regi = FP0_REGNUM; regi < M68K_FPC_REGNUM; regi++)
- {
- from = (char *) &(fpregsetp->f_fpregs[regi - FP0_REGNUM][0]);
- regcache_raw_supply (current_regcache, regi, from);
- }
- regcache_raw_supply (current_regcache, M68K_FPC_REGNUM,
- (char *) &(fpregsetp->f_pcr));
- regcache_raw_supply (current_regcache, M68K_FPS_REGNUM,
- (char *) &(fpregsetp->f_psr));
- regcache_raw_supply (current_regcache, M68K_FPI_REGNUM,
- (char *) &(fpregsetp->f_fpiaddr));
-}
-
-/* Given a pointer to a floating point register set in /proc format
- (fpregset_t *), update the register specified by REGNO from gdb's idea
- of the current floating point register set. If REGNO is -1, update
- them all. */
-
-void
-fill_fpregset (fpregset_t *fpregsetp, int regno)
-{
- int regi;
-
- for (regi = FP0_REGNUM; regi < M68K_FPC_REGNUM; regi++)
- {
- if (regno == -1 || regno == regi)
- regcache_raw_collect (current_regcache, regi,
- &fpregsetp->f_fpregs[regi - FP0_REGNUM][0]);
- }
- if (regno == -1 || regno == M68K_FPC_REGNUM)
- regcache_raw_collect (current_regcache, M68K_FPC_REGNUM,
- &fpregsetp->f_pcr);
- if (regno == -1 || regno == M68K_FPS_REGNUM)
- regcache_raw_collect (current_regcache, M68K_FPS_REGNUM,
- &fpregsetp->f_psr);
- if (regno == -1 || regno == M68K_FPI_REGNUM)
- regcache_raw_collect (current_regcache, M68K_FPI_REGNUM,
- &fpregsetp->f_fpiaddr);
-}
-
-#endif /* defined (FP0_REGNUM) */
-
-#endif /* USE_PROC_FS */
/* Figure out where the longjmp will land. Slurp the args out of the stack.
We expect the first arg to be a pointer to the jmp_buf structure from which
we extract the pc (JB_PC) that we will land at. The pc is copied into PC.
- This routine returns true on success. */
+ This routine returns true on success. */
static int
-m68k_get_longjmp_target (CORE_ADDR *pc)
+m68k_get_longjmp_target (struct frame_info *frame, CORE_ADDR *pc)
{
- char *buf;
+ gdb_byte *buf;
CORE_ADDR sp, jb_addr;
- struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
+ struct gdbarch *gdbarch = get_frame_arch (frame);
+ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+ enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
if (tdep->jb_pc < 0)
{
return 0;
}
- buf = alloca (TARGET_PTR_BIT / TARGET_CHAR_BIT);
- sp = read_register (SP_REGNUM);
+ buf = alloca (gdbarch_ptr_bit (gdbarch) / TARGET_CHAR_BIT);
+ sp = get_frame_register_unsigned (frame, gdbarch_sp_regnum (gdbarch));
- if (target_read_memory (sp + SP_ARG0, /* Offset of first arg on stack */
- buf, TARGET_PTR_BIT / TARGET_CHAR_BIT))
+ if (target_read_memory (sp + SP_ARG0, /* Offset of first arg on stack. */
+ buf, gdbarch_ptr_bit (gdbarch) / TARGET_CHAR_BIT))
return 0;
- jb_addr = extract_unsigned_integer (buf, TARGET_PTR_BIT / TARGET_CHAR_BIT);
+ jb_addr = extract_unsigned_integer (buf, gdbarch_ptr_bit (gdbarch)
+ / TARGET_CHAR_BIT, byte_order);
if (target_read_memory (jb_addr + tdep->jb_pc * tdep->jb_elt_size, buf,
- TARGET_PTR_BIT / TARGET_CHAR_BIT))
+ gdbarch_ptr_bit (gdbarch) / TARGET_CHAR_BIT),
+ byte_order)
return 0;
- *pc = extract_unsigned_integer (buf, TARGET_PTR_BIT / TARGET_CHAR_BIT);
+ *pc = extract_unsigned_integer (buf, gdbarch_ptr_bit (gdbarch)
+ / TARGET_CHAR_BIT, byte_order);
return 1;
}
\f
+/* This is the implementation of gdbarch method
+ return_in_first_hidden_param_p. */
+
+static int
+m68k_return_in_first_hidden_param_p (struct gdbarch *gdbarch,
+ struct type *type)
+{
+ return 0;
+}
+
/* System V Release 4 (SVR4). */
void
/* Function: m68k_gdbarch_init
Initializer function for the m68k gdbarch vector.
- Called by gdbarch. Sets up the gdbarch vector(s) for this target. */
+ Called by gdbarch. Sets up the gdbarch vector(s) for this target. */
static struct gdbarch *
m68k_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
{
struct gdbarch_tdep *tdep = NULL;
struct gdbarch *gdbarch;
+ struct gdbarch_list *best_arch;
+ struct tdesc_arch_data *tdesc_data = NULL;
+ int i;
+ enum m68k_flavour flavour = m68k_no_flavour;
+ int has_fp = 1;
+ const struct floatformat **long_double_format = floatformats_m68881_ext;
+
+ /* Check any target description for validity. */
+ if (tdesc_has_registers (info.target_desc))
+ {
+ const struct tdesc_feature *feature;
+ int valid_p;
+
+ feature = tdesc_find_feature (info.target_desc,
+ "org.gnu.gdb.m68k.core");
+
+ if (feature == NULL)
+ {
+ feature = tdesc_find_feature (info.target_desc,
+ "org.gnu.gdb.coldfire.core");
+ if (feature != NULL)
+ flavour = m68k_coldfire_flavour;
+ }
+
+ if (feature == NULL)
+ {
+ feature = tdesc_find_feature (info.target_desc,
+ "org.gnu.gdb.fido.core");
+ if (feature != NULL)
+ flavour = m68k_fido_flavour;
+ }
+
+ if (feature == NULL)
+ return NULL;
+
+ tdesc_data = tdesc_data_alloc ();
+
+ valid_p = 1;
+ for (i = 0; i <= M68K_PC_REGNUM; i++)
+ valid_p &= tdesc_numbered_register (feature, tdesc_data, i,
+ m68k_register_names[i]);
+
+ if (!valid_p)
+ {
+ tdesc_data_cleanup (tdesc_data);
+ return NULL;
+ }
+
+ feature = tdesc_find_feature (info.target_desc,
+ "org.gnu.gdb.coldfire.fp");
+ if (feature != NULL)
+ {
+ valid_p = 1;
+ for (i = M68K_FP0_REGNUM; i <= M68K_FPI_REGNUM; i++)
+ valid_p &= tdesc_numbered_register (feature, tdesc_data, i,
+ m68k_register_names[i]);
+ if (!valid_p)
+ {
+ tdesc_data_cleanup (tdesc_data);
+ return NULL;
+ }
+ }
+ else
+ has_fp = 0;
+ }
+
+ /* The mechanism for returning floating values from function
+ and the type of long double depend on whether we're
+ on ColdFire or standard m68k. */
+
+ if (info.bfd_arch_info && info.bfd_arch_info->mach != 0)
+ {
+ const bfd_arch_info_type *coldfire_arch =
+ bfd_lookup_arch (bfd_arch_m68k, bfd_mach_mcf_isa_a_nodiv);
+
+ if (coldfire_arch
+ && ((*info.bfd_arch_info->compatible)
+ (info.bfd_arch_info, coldfire_arch)))
+ flavour = m68k_coldfire_flavour;
+ }
+
+ /* If there is already a candidate, use it. */
+ for (best_arch = gdbarch_list_lookup_by_info (arches, &info);
+ best_arch != NULL;
+ best_arch = gdbarch_list_lookup_by_info (best_arch->next, &info))
+ {
+ if (flavour != gdbarch_tdep (best_arch->gdbarch)->flavour)
+ continue;
+
+ if (has_fp != gdbarch_tdep (best_arch->gdbarch)->fpregs_present)
+ continue;
+
+ break;
+ }
- /* find a candidate among the list of pre-declared architectures. */
- arches = gdbarch_list_lookup_by_info (arches, &info);
- if (arches != NULL)
- return (arches->gdbarch);
+ if (best_arch != NULL)
+ {
+ if (tdesc_data != NULL)
+ tdesc_data_cleanup (tdesc_data);
+ return best_arch->gdbarch;
+ }
- tdep = xmalloc (sizeof (struct gdbarch_tdep));
+ tdep = XCNEW (struct gdbarch_tdep);
gdbarch = gdbarch_alloc (&info, tdep);
+ tdep->fpregs_present = has_fp;
+ tdep->flavour = flavour;
- set_gdbarch_long_double_format (gdbarch, &floatformat_m68881_ext);
- set_gdbarch_long_double_bit (gdbarch, 96);
+ if (flavour == m68k_coldfire_flavour || flavour == m68k_fido_flavour)
+ long_double_format = floatformats_ieee_double;
+ set_gdbarch_long_double_format (gdbarch, long_double_format);
+ set_gdbarch_long_double_bit (gdbarch, long_double_format[0]->totalsize);
set_gdbarch_skip_prologue (gdbarch, m68k_skip_prologue);
set_gdbarch_breakpoint_from_pc (gdbarch, m68k_local_breakpoint_from_pc);
- /* Stack grows down. */
+ /* Stack grows down. */
set_gdbarch_inner_than (gdbarch, core_addr_lessthan);
+ set_gdbarch_frame_align (gdbarch, m68k_frame_align);
set_gdbarch_believe_pcc_promotion (gdbarch, 1);
- set_gdbarch_decr_pc_after_break (gdbarch, 2);
+ if (flavour == m68k_coldfire_flavour || flavour == m68k_fido_flavour)
+ set_gdbarch_decr_pc_after_break (gdbarch, 2);
set_gdbarch_frame_args_skip (gdbarch, 8);
+ set_gdbarch_dwarf2_reg_to_regnum (gdbarch, m68k_dwarf_reg_to_regnum);
set_gdbarch_register_type (gdbarch, m68k_register_type);
set_gdbarch_register_name (gdbarch, m68k_register_name);
- set_gdbarch_num_regs (gdbarch, 29);
- set_gdbarch_register_bytes_ok (gdbarch, m68k_register_bytes_ok);
+ set_gdbarch_num_regs (gdbarch, M68K_NUM_REGS);
set_gdbarch_sp_regnum (gdbarch, M68K_SP_REGNUM);
set_gdbarch_pc_regnum (gdbarch, M68K_PC_REGNUM);
set_gdbarch_ps_regnum (gdbarch, M68K_PS_REGNUM);
- set_gdbarch_fp0_regnum (gdbarch, M68K_FP0_REGNUM);
set_gdbarch_convert_register_p (gdbarch, m68k_convert_register_p);
set_gdbarch_register_to_value (gdbarch, m68k_register_to_value);
set_gdbarch_value_to_register (gdbarch, m68k_value_to_register);
+ if (has_fp)
+ set_gdbarch_fp0_regnum (gdbarch, M68K_FP0_REGNUM);
+
+ /* Try to figure out if the arch uses floating registers to return
+ floating point values from functions. */
+ if (has_fp)
+ {
+ /* On ColdFire, floating point values are returned in D0. */
+ if (flavour == m68k_coldfire_flavour)
+ tdep->float_return = 0;
+ else
+ tdep->float_return = 1;
+ }
+ else
+ {
+ /* No floating registers, so can't use them for returning values. */
+ tdep->float_return = 0;
+ }
+
+ /* Function call & return. */
set_gdbarch_push_dummy_call (gdbarch, m68k_push_dummy_call);
set_gdbarch_return_value (gdbarch, m68k_return_value);
+ set_gdbarch_return_in_first_hidden_param_p (gdbarch,
+ m68k_return_in_first_hidden_param_p);
+
/* Disassembler. */
set_gdbarch_print_insn (gdbarch, print_insn_m68k);
tdep->struct_return = reg_struct_return;
/* Frame unwinder. */
- set_gdbarch_unwind_dummy_id (gdbarch, m68k_unwind_dummy_id);
+ set_gdbarch_dummy_id (gdbarch, m68k_dummy_id);
set_gdbarch_unwind_pc (gdbarch, m68k_unwind_pc);
/* Hook in the DWARF CFI frame unwinder. */
- frame_unwind_append_sniffer (gdbarch, dwarf2_frame_sniffer);
+ dwarf2_append_unwinders (gdbarch);
frame_base_set_default (gdbarch, &m68k_frame_base);
if (tdep->jb_pc >= 0)
set_gdbarch_get_longjmp_target (gdbarch, m68k_get_longjmp_target);
- frame_unwind_append_sniffer (gdbarch, m68k_frame_sniffer);
+ frame_unwind_append_unwinder (gdbarch, &m68k_frame_unwind);
+
+ if (tdesc_data)
+ tdesc_use_registers (gdbarch, info.target_desc, tdesc_data);
return gdbarch;
}
static void
-m68k_dump_tdep (struct gdbarch *current_gdbarch, struct ui_file *file)
+m68k_dump_tdep (struct gdbarch *gdbarch, struct ui_file *file)
{
- struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
+ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
if (tdep == NULL)
return;