#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)
return break_insn;
}
-
-static int
-m68k_register_bytes_ok (long numbytes)
-{
- return ((numbytes == REGISTER_BYTES_FP)
- || (numbytes == REGISTER_BYTES_NOFP));
-}
-
/* Return the GDB type object for the "standard" data type of data in
register N. This should be int for D0-D7, SR, FPCONTROL and
FPSTATUS, long double for FP0-FP7, and void pointer for all others
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 (current_gdbarch);
- if (regnum == M68K_FPI_REGNUM || regnum == PC_REGNUM)
- return builtin_type_void_func_ptr;
+ if (tdep->fpregs_present)
+ {
+ if (regnum >= gdbarch_fp0_regnum (current_gdbarch)
+ && regnum <= gdbarch_fp0_regnum (current_gdbarch) + 7)
+ {
+ if (tdep->flavour == m68k_coldfire_flavour)
+ return builtin_type (gdbarch)->builtin_double;
+ else
+ return builtin_type_m68881_ext;
+ }
- if (regnum == M68K_FPC_REGNUM || regnum == M68K_FPS_REGNUM
- || regnum == PS_REGNUM)
- return builtin_type_int32;
+ if (regnum == M68K_FPI_REGNUM)
+ return builtin_type_void_func_ptr;
+
+ if (regnum == M68K_FPC_REGNUM || regnum == M68K_FPS_REGNUM)
+ return builtin_type_int32;
+ }
+ else
+ {
+ if (regnum >= M68K_FP0_REGNUM && regnum <= M68K_FPI_REGNUM)
+ return builtin_type_int0;
+ }
+
+ if (regnum == gdbarch_pc_regnum (current_gdbarch))
+ return builtin_type_void_func_ptr;
if (regnum >= M68K_A0_REGNUM && regnum <= M68K_A0_REGNUM + 7)
return builtin_type_void_data_ptr;
return builtin_type_int32;
}
-/* Function: m68k_register_name
- Returns the name of the standard m68k register regnum. */
-
-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 (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
static int
m68k_convert_register_p (int regnum, struct type *type)
{
+ if (!gdbarch_tdep (current_gdbarch)->fpregs_present)
+ return 0;
return (regnum >= M68K_FP0_REGNUM && regnum <= M68K_FP0_REGNUM + 7);
}
struct type *type, gdb_byte *to)
{
gdb_byte from[M68K_MAX_REGISTER_SIZE];
+ struct type *fpreg_type = register_type (current_gdbarch, M68K_FP0_REGNUM);
/* We only support floating-point values. */
if (TYPE_CODE (type) != TYPE_CODE_FLT)
/* 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_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 (current_gdbarch, M68K_FP0_REGNUM);
/* We only support floating-point values. */
if (TYPE_CODE (type) != TYPE_CODE_FLT)
/* 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_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_tdep *tdep = gdbarch_tdep (current_gdbarch);
- if (TYPE_CODE (type) == TYPE_CODE_FLT)
+ if (tdep->float_return && TYPE_CODE (type) == TYPE_CODE_FLT)
{
+ struct type *fpreg_type = register_type
+ (current_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_tdep *tdep = gdbarch_tdep (current_gdbarch);
- if (TYPE_CODE (type) == TYPE_CODE_FLT)
+ if (tdep->float_return && TYPE_CODE (type) == TYPE_CODE_FLT)
{
+ struct type *fpreg_type = register_type
+ (current_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)
else if (num < 16)
/* a0..7 */
return (num - 8) + M68K_A0_REGNUM;
- else if (num < 24)
+ else if (num < 24 && gdbarch_tdep (current_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 (current_gdbarch)
+ + gdbarch_num_pseudo_regs (current_gdbarch);
}
\f
while (pc < current_pc)
{
op = read_memory_unsigned_integer (pc, 2);
- if (op == P_FMOVEMX_SP)
+ if (op == P_FMOVEMX_SP
+ && gdbarch_tdep (current_gdbarch)->fpregs_present)
{
/* fmovem.x REGS,-(%sp) */
op = read_memory_unsigned_integer (pc + 2, 2);
{
gdb_byte buf[8];
- frame_unwind_register (next_frame, PC_REGNUM, buf);
+ frame_unwind_register (next_frame, gdbarch_pc_regnum (current_gdbarch), buf);
return extract_typed_address (buf, builtin_type_void_func_ptr);
}
\f
/* 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 = frame_func_unwind (next_frame, NORMAL_FRAME);
if (cache->pc != 0)
m68k_analyze_prologue (cache->pc, frame_pc_unwind (next_frame), cache);
return frame_id_build (fp + 8, frame_pc_unwind (next_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_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 (current_gdbarch) / TARGET_CHAR_BIT);
+ sp = get_frame_register_unsigned (frame, gdbarch_sp_regnum (current_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 (current_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 (current_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 (current_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 (current_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;
+
+ /* 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;
+ }
- /* 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 (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)
+ {
+ 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, floatformats_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_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);
frame_unwind_append_sniffer (gdbarch, m68k_frame_sniffer);
+ if (tdesc_data)
+ tdesc_use_registers (gdbarch, tdesc_data);
+
return gdbarch;
}