/* Target-dependent code for Hitachi Super-H, for GDB.
- Copyright 1993, 1994, 1995, 1996, 1997, 1998, 2000 Free Software
- Foundation, Inc.
+ Copyright 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001
+ Free Software Foundation, Inc.
This file is part of GDB.
#include "inferior.h" /* for BEFORE_TEXT_END etc. */
#include "gdb_string.h"
#include "arch-utils.h"
+#include "floatformat.h"
+#include "regcache.h"
+
+#include "solib-svr4.h"
#undef XMALLOC
#define XMALLOC(TYPE) ((TYPE*) xmalloc (sizeof (TYPE)))
-
-/* Frame interpretation related functions. */
-static gdbarch_breakpoint_from_pc_ftype sh_breakpoint_from_pc;
-static gdbarch_frame_chain_ftype sh_frame_chain;
-static gdbarch_frame_saved_pc_ftype sh_frame_saved_pc;
-static gdbarch_skip_prologue_ftype sh_skip_prologue;
-
-static gdbarch_frame_init_saved_regs_ftype sh_nofp_frame_init_saved_regs;
-static gdbarch_frame_init_saved_regs_ftype sh_fp_frame_init_saved_regs;
-static gdbarch_init_extra_frame_info_ftype sh_init_extra_frame_info;
-static gdbarch_pop_frame_ftype sh_pop_frame;
-static gdbarch_saved_pc_after_call_ftype sh_saved_pc_after_call;
-static gdbarch_frame_args_address_ftype sh_frame_args_address;
-static gdbarch_frame_locals_address_ftype sh_frame_locals_address;
-
-/* Function call related functions. */
-static gdbarch_extract_return_value_ftype sh_extract_return_value;
-static gdbarch_extract_struct_value_address_ftype sh_extract_struct_value_address;
-static gdbarch_use_struct_convention_ftype sh_use_struct_convention;
-static gdbarch_store_struct_return_ftype sh_store_struct_return;
-static gdbarch_push_arguments_ftype sh_push_arguments;
-static gdbarch_push_return_address_ftype sh_push_return_address;
-static gdbarch_coerce_float_to_double_ftype sh_coerce_float_to_double;
-static gdbarch_store_return_value_ftype sh_default_store_return_value;
-static gdbarch_store_return_value_ftype sh3e_sh4_store_return_value;
-
-static gdbarch_register_name_ftype sh_generic_register_name;
-static gdbarch_register_name_ftype sh_sh_register_name;
-static gdbarch_register_name_ftype sh_sh3_register_name;
-static gdbarch_register_name_ftype sh_sh3e_register_name;
-static gdbarch_register_name_ftype sh_sh_dsp_register_name;
-static gdbarch_register_name_ftype sh_sh3_dsp_register_name;
-
-/* Registers display related functions */
-static gdbarch_register_raw_size_ftype sh_default_register_raw_size;
-static gdbarch_register_raw_size_ftype sh_sh4_register_raw_size;
-
-static gdbarch_register_virtual_size_ftype sh_register_virtual_size;
-
-static gdbarch_register_byte_ftype sh_default_register_byte;
-static gdbarch_register_byte_ftype sh_sh4_register_byte;
-
-static gdbarch_register_virtual_type_ftype sh_sh3e_register_virtual_type;
-static gdbarch_register_virtual_type_ftype sh_sh4_register_virtual_type;
-static gdbarch_register_virtual_type_ftype sh_default_register_virtual_type;
-
-static void sh_generic_show_regs (void);
-static void sh3_show_regs (void);
-static void sh3e_show_regs (void);
-static void sh3_dsp_show_regs (void);
-static void sh_dsp_show_regs (void);
-static void sh4_show_regs (void);
-static void sh_show_regs_command (char *, int);
-
-static struct type *sh_sh4_build_float_register_type (int high);
-
-static gdbarch_fetch_pseudo_register_ftype sh_fetch_pseudo_register;
-static gdbarch_store_pseudo_register_ftype sh_store_pseudo_register;
-static int fv_reg_base_num (int);
-static int dr_reg_base_num (int);
-static void do_fv_register_info (int fv_regnum);
-static void do_dr_register_info (int dr_regnum);
-static void sh_do_pseudo_register (int regnum);
-static void sh_do_fp_register (int regnum);
-static void sh_do_register (int regnum);
-static void sh_print_register (int regnum);
-
void (*sh_show_regs) (void);
-
+int (*print_sh_insn) (bfd_vma, disassemble_info*);
/* Define other aspects of the stack frame.
we keep a copy of the worked out return pc lying around, since it
int f_offset;
};
-#if 0
-#ifdef _WIN32_WCE
-char **sh_register_names = sh3_reg_names;
-#else
-char **sh_register_names = sh_generic_reg_names;
-#endif
-#endif
-
static char *
sh_generic_register_name (int reg_nr)
{
{
static char *register_names[] =
{
+ /* general registers 0-15 */
"r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
"r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
+ /* 16 - 22 */
"pc", "pr", "gbr", "vbr", "mach", "macl", "sr",
+ /* 23, 24 */
"fpul", "fpscr",
+ /* floating point registers 25 - 40 */
"fr0", "fr1", "fr2", "fr3", "fr4", "fr5", "fr6", "fr7",
"fr8", "fr9", "fr10", "fr11", "fr12", "fr13", "fr14", "fr15",
+ /* 41, 42 */
"ssr", "spc",
+ /* bank 0 43 - 50 */
"r0b0", "r1b0", "r2b0", "r3b0", "r4b0", "r5b0", "r6b0", "r7b0",
+ /* bank 1 51 - 58 */
"r0b1", "r1b1", "r2b1", "r3b1", "r4b1", "r5b1", "r6b1", "r7b1",
- "dr0", "dr1", "dr2", "dr3", "dr4", "dr5", "dr6", "dr7",
- "fv0", "fv1", "fv2", "fv3",
+ /* double precision (pseudo) 59 - 66 */
+ "dr0", "dr2", "dr4", "dr6", "dr8", "dr10", "dr12", "dr14",
+ /* vectors (pseudo) 67 - 70 */
+ "fv0", "fv4", "fv8", "fv12",
+ /* FIXME: missing XF 71 - 86 */
+ /* FIXME: missing XD 87 - 94 */
};
if (reg_nr < 0)
return NULL;
}
static unsigned char *
-sh_breakpoint_from_pc (pcptr, lenptr)
- CORE_ADDR *pcptr;
- int *lenptr;
+sh_breakpoint_from_pc (CORE_ADDR *pcptr, int *lenptr)
{
/* 0xc3c3 is trapa #c3, and it works in big and little endian modes */
static unsigned char breakpoint[] = {0xc3, 0xc3};
/* Skip the prologue using the debug information. If this fails we'll
fall back on the 'guess' method below. */
static CORE_ADDR
-after_prologue (pc)
- CORE_ADDR pc;
+after_prologue (CORE_ADDR pc)
{
struct symtab_and_line sal;
CORE_ADDR func_addr, func_end;
where the prologue ends. Unfortunately this is not always
accurate. */
static CORE_ADDR
-skip_prologue_hard_way (start_pc)
- CORE_ADDR start_pc;
+skip_prologue_hard_way (CORE_ADDR start_pc)
{
CORE_ADDR here, end;
int updated_fp = 0;
}
static CORE_ADDR
-sh_skip_prologue (pc)
- CORE_ADDR pc;
+sh_skip_prologue (CORE_ADDR pc)
{
CORE_ADDR post_prologue_pc;
The return address is the value saved in the PR register + 4 */
static CORE_ADDR
-sh_saved_pc_after_call (frame)
- struct frame_info *frame;
+sh_saved_pc_after_call (struct frame_info *frame)
{
return (ADDR_BITS_REMOVE(read_register(PR_REGNUM)));
}
/* Should call_function allocate stack space for a struct return? */
static int
-sh_use_struct_convention (gcc_p, type)
- int gcc_p;
- struct type *type;
+sh_use_struct_convention (int gcc_p, struct type *type)
{
return (TYPE_LENGTH (type) > 1);
}
We store structs through a pointer passed in R0 */
static void
-sh_store_struct_return (addr, sp)
- CORE_ADDR addr;
- CORE_ADDR sp;
+sh_store_struct_return (CORE_ADDR addr, CORE_ADDR sp)
{
write_register (STRUCT_RETURN_REGNUM, (addr));
}
/* Disassemble an instruction. */
static int
-gdb_print_insn_sh (memaddr, info)
- bfd_vma memaddr;
- disassemble_info *info;
+gdb_print_insn_sh (bfd_vma memaddr, disassemble_info *info)
{
if (TARGET_BYTE_ORDER == BIG_ENDIAN)
return print_insn_sh (memaddr, info);
For us, the frame address is its stack pointer value, so we look up
the function prologue to determine the caller's sp value, and return it. */
static CORE_ADDR
-sh_frame_chain (frame)
- struct frame_info *frame;
+sh_frame_chain (struct frame_info *frame)
{
if (PC_IN_CALL_DUMMY (frame->pc, frame->frame, frame->frame))
return frame->frame; /* dummy frame same as caller's frame */
caller-saves registers for an inner frame. */
static CORE_ADDR
-sh_find_callers_reg (fi, regnum)
- struct frame_info *fi;
- int regnum;
+sh_find_callers_reg (struct frame_info *fi, int regnum)
{
for (; fi; fi = fi->next)
if (PC_IN_CALL_DUMMY (fi->pc, fi->frame, fi->frame))
ways in the stack frame. sp is even more special: the address we
return for it IS the sp for the next frame. */
static void
-sh_nofp_frame_init_saved_regs (fi)
- struct frame_info *fi;
+sh_nofp_frame_init_saved_regs (struct frame_info *fi)
{
int where[NUM_REGS];
int rn;
}
static void
-sh_fp_frame_init_saved_regs (fi)
- struct frame_info *fi;
+sh_fp_frame_init_saved_regs (struct frame_info *fi)
{
int where[NUM_REGS];
int rn;
/* Initialize the extra info saved in a FRAME */
static void
-sh_init_extra_frame_info (fromleaf, fi)
- int fromleaf;
- struct frame_info *fi;
+sh_init_extra_frame_info (int fromleaf, struct frame_info *fi)
{
fi->extra_info = (struct frame_extra_info *)
/* 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). */
-CORE_ADDR
-static sh_extract_struct_value_address (regbuf)
- char *regbuf;
+static CORE_ADDR
+sh_extract_struct_value_address (char *regbuf)
{
return (extract_address ((regbuf), REGISTER_RAW_SIZE (0)));
}
static CORE_ADDR
-sh_frame_saved_pc (frame)
- struct frame_info *frame;
+sh_frame_saved_pc (struct frame_info *frame)
{
return ((frame)->extra_info->return_pc);
}
-static CORE_ADDR
-sh_frame_args_address (fi)
- struct frame_info *fi;
-{
- return (fi)->frame;
-}
-
-static CORE_ADDR
-sh_frame_locals_address (fi)
- struct frame_info *fi;
-{
- return (fi)->frame;
-}
-
/* Discard from the stack the innermost frame,
restoring all saved registers. */
static void
-sh_pop_frame ()
+sh_pop_frame (void)
{
register struct frame_info *frame = get_current_frame ();
register CORE_ADDR fp;
to R7. */
static CORE_ADDR
-sh_push_arguments (nargs, args, sp, struct_return, struct_addr)
- int nargs;
- value_ptr *args;
- CORE_ADDR sp;
- unsigned char struct_return;
- CORE_ADDR struct_addr;
+sh_push_arguments (int nargs, struct value **args, CORE_ADDR sp,
+ int struct_return, CORE_ADDR struct_addr)
{
int stack_offset, stack_alloc;
int argreg;
Needed for targets where we don't actually execute a JSR/BSR instruction */
static CORE_ADDR
-sh_push_return_address (pc, sp)
- CORE_ADDR pc;
- CORE_ADDR sp;
+sh_push_return_address (CORE_ADDR pc, CORE_ADDR sp)
{
write_register (PR_REGNUM, CALL_DUMMY_ADDRESS ());
return sp;
#if 0
void
-sh_fix_call_dummy (dummy, pc, fun, nargs, args, type, gcc_p)
- char *dummy;
- CORE_ADDR pc;
- CORE_ADDR fun;
- int nargs;
- value_ptr *args;
- struct type *type;
- int gcc_p;
+sh_fix_call_dummy (char *dummy, CORE_ADDR pc, CORE_ADDR fun, int nargs,
+ value_ptr *args, struct type *type, int gcc_p)
{
*(unsigned long *) (dummy + 8) = fun;
}
containing the (raw) register state a function return value of type
TYPE, and copy that, in virtual format, into VALBUF. */
static void
-sh_extract_return_value (type, regbuf, valbuf)
- struct type *type;
- char *regbuf;
- char *valbuf;
+sh_extract_return_value (struct type *type, char *regbuf, char *valbuf)
{
int len = TYPE_LENGTH (type);
-
+ int return_register = R0_REGNUM;
+ int offset;
+
if (len <= 4)
- memcpy (valbuf, ((char *) regbuf) + 4 - len, len);
+ {
+ if (TARGET_BYTE_ORDER == BIG_ENDIAN)
+ offset = REGISTER_BYTE (return_register) + 4 - len;
+ else
+ offset = REGISTER_BYTE (return_register);
+ memcpy (valbuf, regbuf + offset, len);
+ }
else if (len <= 8)
- memcpy (valbuf, ((char *) regbuf) + 8 - len, len);
+ {
+ if (TARGET_BYTE_ORDER == BIG_ENDIAN)
+ offset = REGISTER_BYTE (return_register) + 8 - len;
+ else
+ offset = REGISTER_BYTE (return_register);
+ memcpy (valbuf, regbuf + offset, len);
+ }
+ else
+ error ("bad size for return value");
+}
+
+static void
+sh3e_sh4_extract_return_value (struct type *type, char *regbuf, char *valbuf)
+{
+ int return_register;
+ int offset;
+ int len = TYPE_LENGTH (type);
+
+ if (TYPE_CODE (type) == TYPE_CODE_FLT)
+ return_register = FP0_REGNUM;
+ else
+ return_register = R0_REGNUM;
+
+ if (len == 8 && TYPE_CODE (type) == TYPE_CODE_FLT)
+ {
+ DOUBLEST val;
+ if (TARGET_BYTE_ORDER == LITTLE_ENDIAN)
+ floatformat_to_doublest (&floatformat_ieee_double_littlebyte_bigword,
+ (char *) regbuf + REGISTER_BYTE (return_register),
+ &val);
+ else
+ floatformat_to_doublest (&floatformat_ieee_double_big,
+ (char *) regbuf + REGISTER_BYTE (return_register),
+ &val);
+ store_floating (valbuf, len, val);
+ }
+ else if (len <= 4)
+ {
+ if (TARGET_BYTE_ORDER == BIG_ENDIAN)
+ offset = REGISTER_BYTE (return_register) + 4 - len;
+ else
+ offset = REGISTER_BYTE (return_register);
+ memcpy (valbuf, regbuf + offset, len);
+ }
+ else if (len <= 8)
+ {
+ if (TARGET_BYTE_ORDER == BIG_ENDIAN)
+ offset = REGISTER_BYTE (return_register) + 8 - len;
+ else
+ offset = REGISTER_BYTE (return_register);
+ memcpy (valbuf, regbuf + offset, len);
+ }
else
error ("bad size for return value");
}
static void
sh_default_store_return_value (struct type *type, char *valbuf)
{
- write_register_bytes (REGISTER_BYTE (0),
- valbuf, TYPE_LENGTH (type));
+ char buf[32]; /* more than enough... */
+
+ if (TYPE_LENGTH (type) < REGISTER_RAW_SIZE (R0_REGNUM))
+ {
+ /* Add leading zeros to the value. */
+ memset (buf, 0, REGISTER_RAW_SIZE (R0_REGNUM));
+ memcpy (buf + REGISTER_RAW_SIZE (R0_REGNUM) - TYPE_LENGTH (type),
+ valbuf, TYPE_LENGTH (type));
+ write_register_bytes (REGISTER_BYTE (R0_REGNUM), buf,
+ REGISTER_RAW_SIZE (R0_REGNUM));
+ }
+ else
+ write_register_bytes (REGISTER_BYTE (R0_REGNUM), valbuf,
+ TYPE_LENGTH (type));
}
static void
write_register_bytes (REGISTER_BYTE (FP0_REGNUM),
valbuf, TYPE_LENGTH (type));
else
- write_register_bytes (REGISTER_BYTE (0),
- valbuf, TYPE_LENGTH (type));
+ sh_default_store_return_value (type, valbuf);
}
/* Print the registers in a form similar to the E7000 */
static void
-sh_generic_show_regs ()
+sh_generic_show_regs (void)
{
printf_filtered ("PC=%s SR=%08lx PR=%08lx MACH=%08lx MACHL=%08lx\n",
paddr (read_register (PC_REGNUM)),
- (long) read_register (SR_REGNUM),
+ (long) read_register (gdbarch_tdep (current_gdbarch)->SR_REGNUM),
(long) read_register (PR_REGNUM),
(long) read_register (MACH_REGNUM),
(long) read_register (MACL_REGNUM));
}
static void
-sh3_show_regs ()
+sh3_show_regs (void)
{
printf_filtered ("PC=%s SR=%08lx PR=%08lx MACH=%08lx MACHL=%08lx\n",
paddr (read_register (PC_REGNUM)),
- (long) read_register (SR_REGNUM),
+ (long) read_register (gdbarch_tdep (current_gdbarch)->SR_REGNUM),
(long) read_register (PR_REGNUM),
(long) read_register (MACH_REGNUM),
(long) read_register (MACL_REGNUM));
static void
-sh3e_show_regs ()
+sh3e_show_regs (void)
{
printf_filtered ("PC=%s SR=%08lx PR=%08lx MACH=%08lx MACHL=%08lx\n",
paddr (read_register (PC_REGNUM)),
- (long) read_register (SR_REGNUM),
+ (long) read_register (gdbarch_tdep (current_gdbarch)->SR_REGNUM),
(long) read_register (PR_REGNUM),
(long) read_register (MACH_REGNUM),
(long) read_register (MACL_REGNUM));
}
static void
-sh3_dsp_show_regs ()
+sh3_dsp_show_regs (void)
{
printf_filtered ("PC=%s SR=%08lx PR=%08lx MACH=%08lx MACHL=%08lx\n",
paddr (read_register (PC_REGNUM)),
- (long) read_register (SR_REGNUM),
+ (long) read_register (gdbarch_tdep (current_gdbarch)->SR_REGNUM),
(long) read_register (PR_REGNUM),
(long) read_register (MACH_REGNUM),
(long) read_register (MACL_REGNUM));
}
static void
-sh4_show_regs ()
+sh4_show_regs (void)
{
int pr = read_register (gdbarch_tdep (current_gdbarch)->FPSCR_REGNUM) & 0x80000;
printf_filtered ("PC=%s SR=%08lx PR=%08lx MACH=%08lx MACHL=%08lx\n",
paddr (read_register (PC_REGNUM)),
- (long) read_register (SR_REGNUM),
+ (long) read_register (gdbarch_tdep (current_gdbarch)->SR_REGNUM),
(long) read_register (PR_REGNUM),
(long) read_register (MACH_REGNUM),
(long) read_register (MACL_REGNUM));
}
static void
-sh_dsp_show_regs ()
+sh_dsp_show_regs (void)
{
printf_filtered ("PC=%s SR=%08lx PR=%08lx MACH=%08lx MACHL=%08lx\n",
paddr (read_register (PC_REGNUM)),
- (long) read_register (SR_REGNUM),
+ (long) read_register (gdbarch_tdep (current_gdbarch)->SR_REGNUM),
(long) read_register (PR_REGNUM),
(long) read_register (MACH_REGNUM),
(long) read_register (MACL_REGNUM));
(*sh_show_regs)();
}
+static int
+fv_reg_base_num (int fv_regnum)
+{
+ int fp_regnum;
+
+ fp_regnum = FP0_REGNUM +
+ (fv_regnum - gdbarch_tdep (current_gdbarch)->FV0_REGNUM) * 4;
+ return fp_regnum;
+}
+
+static int
+dr_reg_base_num (int dr_regnum)
+{
+ int fp_regnum;
+
+ fp_regnum = FP0_REGNUM +
+ (dr_regnum - gdbarch_tdep (current_gdbarch)->DR0_REGNUM) * 2;
+ return fp_regnum;
+}
+
/* Index within `registers' of the first byte of the space for
register N. */
static int
-sh_default_register_byte (reg_nr)
- int reg_nr;
+sh_default_register_byte (int reg_nr)
{
return (reg_nr * 4);
}
static int
-sh_sh4_register_byte (reg_nr)
- int reg_nr;
+sh_sh4_register_byte (int reg_nr)
{
if (reg_nr >= gdbarch_tdep (current_gdbarch)->DR0_REGNUM
- && reg_nr <= gdbarch_tdep (current_gdbarch)->DR7_REGNUM)
+ && reg_nr <= gdbarch_tdep (current_gdbarch)->DR_LAST_REGNUM)
return (dr_reg_base_num (reg_nr) * 4);
else if (reg_nr >= gdbarch_tdep (current_gdbarch)->FV0_REGNUM
- && reg_nr <= gdbarch_tdep (current_gdbarch)->FV3_REGNUM)
+ && reg_nr <= gdbarch_tdep (current_gdbarch)->FV_LAST_REGNUM)
return (fv_reg_base_num (reg_nr) * 4);
else
return (reg_nr * 4);
/* Number of bytes of storage in the actual machine representation for
register REG_NR. */
static int
-sh_default_register_raw_size (reg_nr)
- int reg_nr;
+sh_default_register_raw_size (int reg_nr)
{
return 4;
}
static int
-sh_sh4_register_raw_size (reg_nr)
- int reg_nr;
+sh_sh4_register_raw_size (int reg_nr)
{
if (reg_nr >= gdbarch_tdep (current_gdbarch)->DR0_REGNUM
- && reg_nr <= gdbarch_tdep (current_gdbarch)->DR7_REGNUM)
+ && reg_nr <= gdbarch_tdep (current_gdbarch)->DR_LAST_REGNUM)
return 8;
else if (reg_nr >= gdbarch_tdep (current_gdbarch)->FV0_REGNUM
- && reg_nr <= gdbarch_tdep (current_gdbarch)->FV3_REGNUM)
+ && reg_nr <= gdbarch_tdep (current_gdbarch)->FV_LAST_REGNUM)
return 16;
else
return 4;
/* Number of bytes of storage in the program's representation
for register N. */
static int
-sh_register_virtual_size (reg_nr)
- int reg_nr;
+sh_register_virtual_size (int reg_nr)
{
return 4;
}
of data in register N. */
static struct type *
-sh_sh3e_register_virtual_type (reg_nr)
- int reg_nr;
+sh_sh3e_register_virtual_type (int reg_nr)
{
if ((reg_nr >= FP0_REGNUM
- && (reg_nr <= gdbarch_tdep (current_gdbarch)->FP15_REGNUM))
+ && (reg_nr <= gdbarch_tdep (current_gdbarch)->FP_LAST_REGNUM))
|| (reg_nr == gdbarch_tdep (current_gdbarch)->FPUL_REGNUM))
return builtin_type_float;
else
}
static struct type *
-sh_sh4_register_virtual_type (reg_nr)
- int reg_nr;
+sh_sh4_build_float_register_type (int high)
+{
+ struct type *temp;
+
+ temp = create_range_type (NULL, builtin_type_int, 0, high);
+ return create_array_type (NULL, builtin_type_float, temp);
+}
+
+static struct type *
+sh_sh4_register_virtual_type (int reg_nr)
{
if ((reg_nr >= FP0_REGNUM
- && (reg_nr <= gdbarch_tdep (current_gdbarch)->FP15_REGNUM))
+ && (reg_nr <= gdbarch_tdep (current_gdbarch)->FP_LAST_REGNUM))
|| (reg_nr == gdbarch_tdep (current_gdbarch)->FPUL_REGNUM))
return builtin_type_float;
else if (reg_nr >= gdbarch_tdep (current_gdbarch)->DR0_REGNUM
- && reg_nr <= gdbarch_tdep (current_gdbarch)->DR7_REGNUM)
+ && reg_nr <= gdbarch_tdep (current_gdbarch)->DR_LAST_REGNUM)
return builtin_type_double;
else if (reg_nr >= gdbarch_tdep (current_gdbarch)->FV0_REGNUM
- && reg_nr <= gdbarch_tdep (current_gdbarch)->FV3_REGNUM)
+ && reg_nr <= gdbarch_tdep (current_gdbarch)->FV_LAST_REGNUM)
return sh_sh4_build_float_register_type (3);
else
return builtin_type_int;
}
static struct type *
-sh_sh4_build_float_register_type (int high)
+sh_default_register_virtual_type (int reg_nr)
{
- struct type *temp;
+ return builtin_type_int;
+}
- temp = create_range_type (NULL, builtin_type_int, 0, high);
- return create_array_type (NULL, builtin_type_float, temp);
+/* On the sh4, the DRi pseudo registers are problematic if the target
+ is little endian. When the user writes one of those registers, for
+ instance with 'ser var $dr0=1', we want the double to be stored
+ like this:
+ fr0 = 0x00 0x00 0x00 0x00 0x00 0xf0 0x3f
+ fr1 = 0x00 0x00 0x00 0x00 0x00 0x00 0x00
+
+ This corresponds to little endian byte order & big endian word
+ order. However if we let gdb write the register w/o conversion, it
+ will write fr0 and fr1 this way:
+ fr0 = 0x00 0x00 0x00 0x00 0x00 0x00 0x00
+ fr1 = 0x00 0x00 0x00 0x00 0x00 0xf0 0x3f
+ because it will consider fr0 and fr1 as a single LE stretch of memory.
+
+ To achieve what we want we must force gdb to store things in
+ floatformat_ieee_double_littlebyte_bigword (which is defined in
+ include/floatformat.h and libiberty/floatformat.c.
+
+ In case the target is big endian, there is no problem, the
+ raw bytes will look like:
+ fr0 = 0x3f 0xf0 0x00 0x00 0x00 0x00 0x00
+ fr1 = 0x00 0x00 0x00 0x00 0x00 0x00 0x00
+
+ The other pseudo registers (the FVs) also don't pose a problem
+ because they are stored as 4 individual FP elements. */
+
+int
+sh_sh4_register_convertible (int nr)
+{
+ if (TARGET_BYTE_ORDER == LITTLE_ENDIAN)
+ return (gdbarch_tdep (current_gdbarch)->DR0_REGNUM <= nr
+ && nr <= gdbarch_tdep (current_gdbarch)->DR_LAST_REGNUM);
+ else
+ return 0;
}
-static struct type *
-sh_default_register_virtual_type (reg_nr)
- int reg_nr;
+void
+sh_sh4_register_convert_to_virtual (int regnum, struct type *type,
+ char *from, char *to)
{
- return builtin_type_int;
+ if (regnum >= gdbarch_tdep (current_gdbarch)->DR0_REGNUM
+ && regnum <= gdbarch_tdep (current_gdbarch)->DR_LAST_REGNUM)
+ {
+ DOUBLEST val;
+ floatformat_to_doublest (&floatformat_ieee_double_littlebyte_bigword, from, &val);
+ store_floating(to, TYPE_LENGTH(type), val);
+ }
+ else
+ error("sh_register_convert_to_virtual called with non DR register number");
+}
+
+void
+sh_sh4_register_convert_to_raw (struct type *type, int regnum,
+ char *from, char *to)
+{
+ if (regnum >= gdbarch_tdep (current_gdbarch)->DR0_REGNUM
+ && regnum <= gdbarch_tdep (current_gdbarch)->DR_LAST_REGNUM)
+ {
+ DOUBLEST val = extract_floating (from, TYPE_LENGTH(type));
+ floatformat_from_doublest (&floatformat_ieee_double_littlebyte_bigword, &val, to);
+ }
+ else
+ error("sh_register_convert_to_raw called with non DR register number");
}
void
if (!register_cached (reg_nr))
{
if (reg_nr >= gdbarch_tdep (current_gdbarch)->DR0_REGNUM
- && reg_nr <= gdbarch_tdep (current_gdbarch)->DR7_REGNUM)
+ && reg_nr <= gdbarch_tdep (current_gdbarch)->DR_LAST_REGNUM)
{
base_regnum = dr_reg_base_num (reg_nr);
target_fetch_registers (base_regnum + portion);
}
else if (reg_nr >= gdbarch_tdep (current_gdbarch)->FV0_REGNUM
- && reg_nr <= gdbarch_tdep (current_gdbarch)->FV3_REGNUM)
+ && reg_nr <= gdbarch_tdep (current_gdbarch)->FV_LAST_REGNUM)
{
base_regnum = fv_reg_base_num (reg_nr);
int base_regnum, portion;
if (reg_nr >= gdbarch_tdep (current_gdbarch)->DR0_REGNUM
- && reg_nr <= gdbarch_tdep (current_gdbarch)->DR7_REGNUM)
+ && reg_nr <= gdbarch_tdep (current_gdbarch)->DR_LAST_REGNUM)
{
base_regnum = dr_reg_base_num (reg_nr);
}
}
else if (reg_nr >= gdbarch_tdep (current_gdbarch)->FV0_REGNUM
- && reg_nr <= gdbarch_tdep (current_gdbarch)->FV3_REGNUM)
+ && reg_nr <= gdbarch_tdep (current_gdbarch)->FV_LAST_REGNUM)
{
base_regnum = fv_reg_base_num (reg_nr);
}
}
-static int
-fv_reg_base_num (int fv_regnum)
-{
- int fp_regnum;
-
- fp_regnum = FP0_REGNUM +
- (fv_regnum - gdbarch_tdep (current_gdbarch)->FV0_REGNUM) * 4;
- return fp_regnum;
-}
-
-static int
-dr_reg_base_num (int dr_regnum)
-{
- int fp_regnum;
-
- fp_regnum = FP0_REGNUM +
- (dr_regnum - gdbarch_tdep (current_gdbarch)->DR0_REGNUM) * 2;
- return fp_regnum;
-}
-
static void
do_fv_register_info (int fv_regnum)
{
sh_do_pseudo_register (int regnum)
{
if (regnum < NUM_REGS || regnum >= NUM_REGS + NUM_PSEUDO_REGS)
- internal_error ("Invalid pasudo register number %d\n", regnum);
- else if (regnum >= NUM_REGS &&
- regnum < gdbarch_tdep (current_gdbarch)->FV0_REGNUM)
+ internal_error (__FILE__, __LINE__,
+ "Invalid pseudo register number %d\n", regnum);
+ else if (regnum >= gdbarch_tdep (current_gdbarch)->DR0_REGNUM
+ && regnum < gdbarch_tdep (current_gdbarch)->DR_LAST_REGNUM)
do_dr_register_info (regnum);
- else if (regnum >= gdbarch_tdep (current_gdbarch)->FV0_REGNUM &&
- regnum <= gdbarch_tdep (current_gdbarch)->FV3_REGNUM)
+ else if (regnum >= gdbarch_tdep (current_gdbarch)->FV0_REGNUM
+ && regnum <= gdbarch_tdep (current_gdbarch)->FV_LAST_REGNUM)
do_fv_register_info (regnum);
}
print_spaces_filtered (15 - strlen (REGISTER_NAME (regnum)), gdb_stdout);
/* Print the value. */
- printf_filtered (inv ? "<invalid float>" : "%-10.9g", flt);
+ if (inv)
+ printf_filtered ("<invalid float>");
+ else
+ printf_filtered ("%-10.9g", flt);
/* Print the fp register as hex. */
printf_filtered ("\t(raw 0x");
sh_print_register (int regnum)
{
if (regnum < 0 || regnum >= NUM_REGS + NUM_PSEUDO_REGS)
- internal_error ("Invalid register number %d\n", regnum);
+ internal_error (__FILE__, __LINE__,
+ "Invalid register number %d\n", regnum);
- else if (regnum > 0 && regnum < NUM_REGS)
+ else if (regnum >= 0 && regnum < NUM_REGS)
{
if (TYPE_CODE (REGISTER_VIRTUAL_TYPE (regnum)) == TYPE_CODE_FLT)
sh_do_fp_register (regnum); /* FP regs */
regnum ++;
}
else
- regnum += (gdbarch_tdep (current_gdbarch)->FP15_REGNUM - FP0_REGNUM); /* skip FP regs */
+ regnum += (gdbarch_tdep (current_gdbarch)->FP_LAST_REGNUM - FP0_REGNUM); /* skip FP regs */
}
else
{
}
}
+#ifdef SVR4_SHARED_LIBS
+
+/* Fetch (and possibly build) an appropriate link_map_offsets structure
+ for native i386 linux targets using the struct offsets defined in
+ link.h (but without actual reference to that file).
+
+ This makes it possible to access i386-linux shared libraries from
+ a gdb that was not built on an i386-linux host (for cross debugging).
+ */
+
+struct link_map_offsets *
+sh_linux_svr4_fetch_link_map_offsets (void)
+{
+ static struct link_map_offsets lmo;
+ static struct link_map_offsets *lmp = 0;
+
+ if (lmp == 0)
+ {
+ lmp = &lmo;
+
+ lmo.r_debug_size = 8; /* 20 not actual size but all we need */
+
+ lmo.r_map_offset = 4;
+ lmo.r_map_size = 4;
+
+ lmo.link_map_size = 20; /* 552 not actual size but all we need */
+
+ lmo.l_addr_offset = 0;
+ lmo.l_addr_size = 4;
+
+ lmo.l_name_offset = 4;
+ lmo.l_name_size = 4;
+
+ lmo.l_next_offset = 12;
+ lmo.l_next_size = 4;
+
+ lmo.l_prev_offset = 16;
+ lmo.l_prev_size = 4;
+ }
+
+ return lmp;
+}
+#endif /* SVR4_SHARED_LIBS */
+
static gdbarch_init_ftype sh_gdbarch_init;
static struct gdbarch *
-sh_gdbarch_init (info, arches)
- struct gdbarch_info info;
- struct gdbarch_list *arches;
+sh_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
{
static LONGEST sh_call_dummy_words[] = {0};
struct gdbarch *gdbarch;
statement below. */
tdep->FPUL_REGNUM = -1;
tdep->FPSCR_REGNUM = -1;
+ tdep->SR_REGNUM = 22;
tdep->DSR_REGNUM = -1;
- tdep->FP15_REGNUM = -1;
+ tdep->FP_LAST_REGNUM = -1;
tdep->A0G_REGNUM = -1;
tdep->A0_REGNUM = -1;
tdep->A1G_REGNUM = -1;
tdep->SSR_REGNUM = -1;
tdep->SPC_REGNUM = -1;
tdep->DR0_REGNUM = -1;
- tdep->DR1_REGNUM = -1;
- tdep->DR2_REGNUM = -1;
- tdep->DR3_REGNUM = -1;
- tdep->DR4_REGNUM = -1;
- tdep->DR5_REGNUM = -1;
- tdep->DR6_REGNUM = -1;
- tdep->DR7_REGNUM = -1;
+ tdep->DR_LAST_REGNUM = -1;
tdep->FV0_REGNUM = -1;
- tdep->FV1_REGNUM = -1;
- tdep->FV2_REGNUM = -1;
- tdep->FV3_REGNUM = -1;
+ tdep->FV_LAST_REGNUM = -1;
+
set_gdbarch_fp0_regnum (gdbarch, -1);
set_gdbarch_num_pseudo_regs (gdbarch, 0);
set_gdbarch_max_register_raw_size (gdbarch, 4);
set_gdbarch_max_register_virtual_size (gdbarch, 4);
+ set_gdbarch_ptr_bit (gdbarch, 4 * TARGET_CHAR_BIT);
+ set_gdbarch_num_regs (gdbarch, 59);
+ set_gdbarch_sp_regnum (gdbarch, 15);
+ set_gdbarch_fp_regnum (gdbarch, 14);
+ set_gdbarch_pc_regnum (gdbarch, 16);
+ set_gdbarch_register_size (gdbarch, 4);
+ set_gdbarch_register_bytes (gdbarch, NUM_REGS * 4);
+ set_gdbarch_fetch_pseudo_register (gdbarch, sh_fetch_pseudo_register);
+ set_gdbarch_store_pseudo_register (gdbarch, sh_store_pseudo_register);
+ set_gdbarch_do_registers_info (gdbarch, sh_do_registers_info);
+ set_gdbarch_breakpoint_from_pc (gdbarch, sh_breakpoint_from_pc);
+ set_gdbarch_extract_return_value (gdbarch, sh_extract_return_value);
+ print_sh_insn = gdb_print_insn_sh;
switch (info.bfd_arch_info->mach)
{
sh_show_regs = sh3e_show_regs;
sh_store_return_value = sh3e_sh4_store_return_value;
sh_register_virtual_type = sh_sh3e_register_virtual_type;
+ set_gdbarch_extract_return_value (gdbarch, sh3e_sh4_extract_return_value);
set_gdbarch_frame_init_saved_regs (gdbarch, sh_fp_frame_init_saved_regs);
set_gdbarch_register_raw_size (gdbarch, sh_default_register_raw_size);
set_gdbarch_register_virtual_size (gdbarch, sh_default_register_raw_size);
set_gdbarch_fp0_regnum (gdbarch, 25);
tdep->FPUL_REGNUM = 23;
tdep->FPSCR_REGNUM = 24;
- tdep->FP15_REGNUM = 40;
+ tdep->FP_LAST_REGNUM = 40;
tdep->SSR_REGNUM = 41;
tdep->SPC_REGNUM = 42;
break;
sh_show_regs = sh4_show_regs;
sh_store_return_value = sh3e_sh4_store_return_value;
sh_register_virtual_type = sh_sh4_register_virtual_type;
+ set_gdbarch_extract_return_value (gdbarch, sh3e_sh4_extract_return_value);
set_gdbarch_frame_init_saved_regs (gdbarch, sh_fp_frame_init_saved_regs);
set_gdbarch_fp0_regnum (gdbarch, 25);
set_gdbarch_register_raw_size (gdbarch, sh_sh4_register_raw_size);
set_gdbarch_num_pseudo_regs (gdbarch, 12);
set_gdbarch_max_register_raw_size (gdbarch, 4 * 4);
set_gdbarch_max_register_virtual_size (gdbarch, 4 * 4);
+ set_gdbarch_register_convert_to_raw (gdbarch, sh_sh4_register_convert_to_raw);
+ set_gdbarch_register_convert_to_virtual (gdbarch, sh_sh4_register_convert_to_virtual);
+ set_gdbarch_register_convertible (gdbarch, sh_sh4_register_convertible);
tdep->FPUL_REGNUM = 23;
tdep->FPSCR_REGNUM = 24;
- tdep->FP15_REGNUM = 40;
+ tdep->FP_LAST_REGNUM = 40;
tdep->SSR_REGNUM = 41;
tdep->SPC_REGNUM = 42;
tdep->DR0_REGNUM = 59;
- tdep->DR1_REGNUM = 60;
- tdep->DR2_REGNUM = 61;
- tdep->DR3_REGNUM = 62;
- tdep->DR4_REGNUM = 63;
- tdep->DR5_REGNUM = 64;
- tdep->DR6_REGNUM = 65;
- tdep->DR7_REGNUM = 66;
+ tdep->DR_LAST_REGNUM = 66;
tdep->FV0_REGNUM = 67;
- tdep->FV1_REGNUM = 68;
- tdep->FV2_REGNUM = 69;
- tdep->FV3_REGNUM = 70;
+ tdep->FV_LAST_REGNUM = 70;
break;
default:
sh_register_name = sh_generic_register_name;
set_gdbarch_read_sp (gdbarch, generic_target_read_sp);
set_gdbarch_write_sp (gdbarch, generic_target_write_sp);
- set_gdbarch_num_regs (gdbarch, 59);
- set_gdbarch_sp_regnum (gdbarch, 15);
- set_gdbarch_fp_regnum (gdbarch, 14);
- set_gdbarch_pc_regnum (gdbarch, 16);
set_gdbarch_register_name (gdbarch, sh_register_name);
- set_gdbarch_register_size (gdbarch, 4);
- set_gdbarch_register_bytes (gdbarch, NUM_REGS * 4);
set_gdbarch_register_virtual_type (gdbarch, sh_register_virtual_type);
- set_gdbarch_ptr_bit (gdbarch, 4 * TARGET_CHAR_BIT);
set_gdbarch_short_bit (gdbarch, 2 * TARGET_CHAR_BIT);
set_gdbarch_int_bit (gdbarch, 4 * TARGET_CHAR_BIT);
set_gdbarch_long_bit (gdbarch, 4 * TARGET_CHAR_BIT);
set_gdbarch_long_long_bit (gdbarch, 8 * TARGET_CHAR_BIT);
set_gdbarch_float_bit (gdbarch, 4 * TARGET_CHAR_BIT);
set_gdbarch_double_bit (gdbarch, 8 * TARGET_CHAR_BIT);
- set_gdbarch_long_double_bit (gdbarch, 16 * TARGET_CHAR_BIT);
+ set_gdbarch_long_double_bit (gdbarch, 16 * TARGET_CHAR_BIT);/*??should be 8?*/
set_gdbarch_use_generic_dummy_frames (gdbarch, 1);
set_gdbarch_call_dummy_length (gdbarch, 0);
set_gdbarch_coerce_float_to_double (gdbarch,
sh_coerce_float_to_double);
- set_gdbarch_extract_return_value (gdbarch, sh_extract_return_value);
set_gdbarch_push_arguments (gdbarch, sh_push_arguments);
set_gdbarch_push_dummy_frame (gdbarch, generic_push_dummy_frame);
set_gdbarch_push_return_address (gdbarch, sh_push_return_address);
set_gdbarch_inner_than (gdbarch, core_addr_lessthan);
set_gdbarch_decr_pc_after_break (gdbarch, 0);
set_gdbarch_function_start_offset (gdbarch, 0);
- set_gdbarch_breakpoint_from_pc (gdbarch, sh_breakpoint_from_pc);
- set_gdbarch_fetch_pseudo_register (gdbarch, sh_fetch_pseudo_register);
- set_gdbarch_store_pseudo_register (gdbarch, sh_store_pseudo_register);
set_gdbarch_frame_args_skip (gdbarch, 0);
set_gdbarch_frameless_function_invocation (gdbarch, frameless_look_for_prologue);
set_gdbarch_frame_chain (gdbarch, sh_frame_chain);
set_gdbarch_frame_chain_valid (gdbarch, generic_file_frame_chain_valid);
set_gdbarch_frame_saved_pc (gdbarch, sh_frame_saved_pc);
- set_gdbarch_frame_args_address (gdbarch, sh_frame_args_address);
- set_gdbarch_frame_locals_address (gdbarch, sh_frame_locals_address);
+ set_gdbarch_frame_args_address (gdbarch, default_frame_address);
+ set_gdbarch_frame_locals_address (gdbarch, default_frame_address);
set_gdbarch_saved_pc_after_call (gdbarch, sh_saved_pc_after_call);
set_gdbarch_frame_num_args (gdbarch, frame_num_args_unknown);
set_gdbarch_believe_pcc_promotion (gdbarch, 1);
set_gdbarch_ieee_float (gdbarch, 1);
+ tm_print_insn = print_sh_insn;
return gdbarch;
}
void
-_initialize_sh_tdep ()
+_initialize_sh_tdep (void)
{
struct cmd_list_element *c;
register_gdbarch_init (bfd_arch_sh, sh_gdbarch_init);
- tm_print_insn = gdb_print_insn_sh;
add_com ("regs", class_vars, sh_show_regs_command, "Print all registers");
}