/* Target-dependent code for the Motorola 68000 series.
Copyright (C) 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1999, 2000, 2001,
- 2002, 2003, 2004, 2005, 2006, 2007 Free Software Foundation, Inc.
+ 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009
+ 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., 51 Franklin Street, Fifth Floor,
- Boston, MA 02110-1301, 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 "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 */
#define SP_ARG0 (1 * 4)
#endif
static const gdb_byte *
-m68k_local_breakpoint_from_pc (CORE_ADDR *pcptr, int *lenptr)
+m68k_local_breakpoint_from_pc (struct gdbarch *gdbarch,
+ CORE_ADDR *pcptr, int *lenptr)
{
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;
+ }
-static int
-m68k_register_bytes_ok (long numbytes)
+ return tdep->m68k_ps_type;
+}
+
+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 >= ARRAY_SIZE (register_names))
+/* 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);
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 != m68881_ext_type (gdbarch));
}
/* Read a value of type TYPE from register REGNUM in frame FRAME, and
struct type *type, gdb_byte *to)
{
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)
return;
}
- /* Convert to TYPE. This should be a no-op if TYPE is equivalent to
- the extended floating-point format used by the FPU. */
+ /* Convert to TYPE. */
get_frame_register (frame, regnum, from);
- convert_typed_floating (from, builtin_type_m68881_ext, to, type);
+ convert_typed_floating (from, fpreg_type, to, type);
}
/* Write the contents FROM of a value of type TYPE into register
struct type *type, const gdb_byte *from)
{
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);
}
{
int len = TYPE_LENGTH (type);
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)
regcache_raw_read (regcache, M68K_A0_REGNUM, 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)
{
+ struct type *fpreg_type = register_type (gdbarch, M68K_FP0_REGNUM);
gdb_byte buf[M68K_MAX_REGISTER_SIZE];
- convert_typed_floating (valbuf, type, buf, builtin_type_m68881_ext);
+ 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)
from WRITEBUF into REGCACHE. */
static enum return_value_convention
-m68k_return_value (struct gdbarch *gdbarch, struct type *type,
- struct regcache *regcache, gdb_byte *readbuf,
- const gdb_byte *writebuf)
+m68k_return_value (struct gdbarch *gdbarch, struct type *func_type,
+ struct type *type, struct regcache *regcache,
+ gdb_byte *readbuf, const gdb_byte *writebuf)
{
enum type_code code = TYPE_CODE (type);
}
static enum return_value_convention
-m68k_svr4_return_value (struct gdbarch *gdbarch, struct type *type,
- struct regcache *regcache, gdb_byte *readbuf,
- const gdb_byte *writebuf)
+m68k_svr4_return_value (struct gdbarch *gdbarch, struct type *func_type,
+ 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 && 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, func_type, type, regcache,
readbuf, writebuf);
}
/* Convert a dwarf or dwarf2 regnumber to a GDB regnum. */
static int
-m68k_dwarf_reg_to_regnum (int num)
+m68k_dwarf_reg_to_regnum (struct gdbarch *gdbarch, int num)
{
if (num < 8)
/* d0..7 */
else if (num < 16)
/* a0..7 */
return (num - 8) + M68K_A0_REGNUM;
- else if (num < 24)
+ 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 NUM_REGS + NUM_PSEUDO_REGS;
+ return gdbarch_num_regs (gdbarch) + gdbarch_num_pseudo_regs (gdbarch);
}
\f
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)
{
if (cache->locals >= 0)
while (pc < current_pc)
{
op = read_memory_unsigned_integer (pc, 2);
- if (op == P_FMOVEMX_SP)
+ if (op == P_FMOVEMX_SP
+ && gdbarch_tdep (gdbarch)->fpregs_present)
{
/* fmovem.x REGS,-(%sp) */
op = read_memory_unsigned_integer (pc + 2, 2);
*/
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)
{
unsigned int op;
pc = m68k_analyze_frame_setup (pc, current_pc, cache);
- pc = m68k_analyze_register_saves (pc, current_pc, cache);
+ pc = m68k_analyze_register_saves (gdbarch, pc, current_pc, cache);
if (pc >= current_pc)
return current_pc;
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;
{
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 m68k_frame_cache *cache;
gdb_byte buf[4];
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);
+ get_frame_register (this_frame, M68K_FP_REGNUM, buf);
cache->base = extract_unsigned_integer (buf, 4);
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);
+ get_frame_register (this_frame, M68K_SP_REGNUM, buf);
cache->base = extract_unsigned_integer (buf, 4) + cache->sp_offset;
}
}
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, gdb_byte *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,
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)
{
- gdb_byte 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
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)
{
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 (get_frame_arch (frame));
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))
+ 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);
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))
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);
return 1;
}
\f
{
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;
- /* find a candidate among the list of pre-declared architectures. */
- arches = gdbarch_list_lookup_by_info (arches, &info);
- if (arches != NULL)
- return (arches->gdbarch);
+ /* 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)
+ /* Do nothing. */
+ ;
+
+ 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;
+ }
tdep = xmalloc (sizeof (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);
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_dwarf_reg_to_regnum (gdbarch, m68k_dwarf_reg_to_regnum);
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, M68K_NUM_REGS);
- set_gdbarch_register_bytes_ok (gdbarch, m68k_register_bytes_ok);
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_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);
+
/* 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;