#include "defs.h"
#include "gdb_string.h"
#include "gdb_assert.h"
#include "frame.h"
#include "inferior.h"
#include "symtab.h"
#include "value.h"
#include "gdbcmd.h"
#include "language.h"
#include "gdbcore.h"
#include "symfile.h"
#include "objfiles.h"
#include "gdbtypes.h"
#include "target.h"
#include "arch-utils.h"
#include "regcache.h"
#include "osabi.h"
#include "mips-tdep.h"
#include "block.h"
#include "reggroups.h"
#include "opcode/mips.h"
#include "elf/mips.h"
#include "elf-bfd.h"
#include "symcat.h"
#include "sim-regno.h"
#include "dis-asm.h"
#include "frame-unwind.h"
#include "frame-base.h"
#include "trad-frame.h"
#include "infcall.h"
#include "floatformat.h"
static const struct objfile_data *mips_pdr_data;
static struct type *mips_register_type (struct gdbarch *gdbarch, int regnum);
#define ST0_FR (1 << 26)
enum
{
MIPS_FPU_SINGLE_REGSIZE = 4,
MIPS_FPU_DOUBLE_REGSIZE = 8
};
static const char *mips_abi_string;
static const char *mips_abi_strings[] = {
"auto",
"n32",
"o32",
"n64",
"o64",
"eabi32",
"eabi64",
NULL
};
static const char size_auto[] = "auto";
static const char size_32[] = "32";
static const char size_64[] = "64";
static const char *size_enums[] = {
size_auto,
size_32,
size_64,
0
};
enum mips_fpu_type
{
MIPS_FPU_DOUBLE,
MIPS_FPU_SINGLE,
MIPS_FPU_NONE
};
#ifndef MIPS_DEFAULT_FPU_TYPE
#define MIPS_DEFAULT_FPU_TYPE MIPS_FPU_DOUBLE
#endif
static int mips_fpu_type_auto = 1;
static enum mips_fpu_type mips_fpu_type = MIPS_DEFAULT_FPU_TYPE;
static int mips_debug = 0;
struct gdbarch_tdep
{
int elf_flags;
enum mips_abi mips_abi;
enum mips_abi found_abi;
enum mips_fpu_type mips_fpu_type;
int mips_last_arg_regnum;
int mips_last_fp_arg_regnum;
int default_mask_address_p;
int mips64_transfers_32bit_regs_p;
const struct mips_regnum *regnum;
const char **mips_processor_reg_names;
};
static int
n32n64_floatformat_always_valid (const struct floatformat *fmt,
const char *from)
{
return 1;
}
static const struct floatformat floatformat_n32n64_long_double_big =
{
floatformat_big, 128, 0, 1, 11, 1023, 2047, 12, 52,
floatformat_intbit_no,
"floatformat_ieee_double_big",
n32n64_floatformat_always_valid
};
const struct mips_regnum *
mips_regnum (struct gdbarch *gdbarch)
{
return gdbarch_tdep (gdbarch)->regnum;
}
static int
mips_fpa0_regnum (struct gdbarch *gdbarch)
{
return mips_regnum (gdbarch)->fp0 + 12;
}
#define MIPS_EABI (gdbarch_tdep (current_gdbarch)->mips_abi == MIPS_ABI_EABI32 \
|| gdbarch_tdep (current_gdbarch)->mips_abi == MIPS_ABI_EABI64)
#define MIPS_LAST_FP_ARG_REGNUM (gdbarch_tdep (current_gdbarch)->mips_last_fp_arg_regnum)
#define MIPS_LAST_ARG_REGNUM (gdbarch_tdep (current_gdbarch)->mips_last_arg_regnum)
#define MIPS_FPU_TYPE (gdbarch_tdep (current_gdbarch)->mips_fpu_type)
static CORE_ADDR
is_mips16_addr (CORE_ADDR addr)
{
return ((addr) & 1);
}
static CORE_ADDR
unmake_mips16_addr (CORE_ADDR addr)
{
return ((addr) & ~1);
}
static LONGEST
read_signed_register (int regnum)
{
LONGEST val;
regcache_cooked_read_signed (current_regcache, regnum, &val);
return val;
}
static LONGEST
read_signed_register_pid (int regnum, ptid_t ptid)
{
ptid_t save_ptid;
LONGEST retval;
if (ptid_equal (ptid, inferior_ptid))
return read_signed_register (regnum);
save_ptid = inferior_ptid;
inferior_ptid = ptid;
retval = read_signed_register (regnum);
inferior_ptid = save_ptid;
return retval;
}
enum mips_abi
mips_abi (struct gdbarch *gdbarch)
{
return gdbarch_tdep (gdbarch)->mips_abi;
}
int
mips_isa_regsize (struct gdbarch *gdbarch)
{
return (gdbarch_bfd_arch_info (gdbarch)->bits_per_word
/ gdbarch_bfd_arch_info (gdbarch)->bits_per_byte);
}
static const char *mips_abi_regsize_string = size_auto;
unsigned int
mips_abi_regsize (struct gdbarch *gdbarch)
{
if (mips_abi_regsize_string == size_auto)
switch (mips_abi (gdbarch))
{
case MIPS_ABI_EABI32:
case MIPS_ABI_O32:
return 4;
case MIPS_ABI_N32:
case MIPS_ABI_N64:
case MIPS_ABI_O64:
case MIPS_ABI_EABI64:
return 8;
case MIPS_ABI_UNKNOWN:
case MIPS_ABI_LAST:
default:
internal_error (__FILE__, __LINE__, _("bad switch"));
}
else if (mips_abi_regsize_string == size_64)
return 8;
else
return 4;
}
static void
mips_elf_make_msymbol_special (asymbol * sym, struct minimal_symbol *msym)
{
if (((elf_symbol_type *) (sym))->internal_elf_sym.st_other == STO_MIPS16)
{
MSYMBOL_INFO (msym) = (char *)
(((long) MSYMBOL_INFO (msym)) | 0x80000000);
SYMBOL_VALUE_ADDRESS (msym) |= 1;
}
}
static int
msymbol_is_special (struct minimal_symbol *msym)
{
return (((long) MSYMBOL_INFO (msym) & 0x80000000) != 0);
}
static void
mips_xfer_register (struct regcache *regcache, int reg_num, int length,
enum bfd_endian endian, gdb_byte *in,
const gdb_byte *out, int buf_offset)
{
int reg_offset = 0;
gdb_assert (reg_num >= NUM_REGS);
switch (endian)
{
case BFD_ENDIAN_BIG:
reg_offset = register_size (current_gdbarch, reg_num) - length;
break;
case BFD_ENDIAN_LITTLE:
reg_offset = 0;
break;
case BFD_ENDIAN_UNKNOWN:
reg_offset = 0;
break;
default:
internal_error (__FILE__, __LINE__, _("bad switch"));
}
if (mips_debug)
fprintf_unfiltered (gdb_stderr,
"xfer $%d, reg offset %d, buf offset %d, length %d, ",
reg_num, reg_offset, buf_offset, length);
if (mips_debug && out != NULL)
{
int i;
fprintf_unfiltered (gdb_stdlog, "out ");
for (i = 0; i < length; i++)
fprintf_unfiltered (gdb_stdlog, "%02x", out[buf_offset + i]);
}
if (in != NULL)
regcache_cooked_read_part (regcache, reg_num, reg_offset, length,
in + buf_offset);
if (out != NULL)
regcache_cooked_write_part (regcache, reg_num, reg_offset, length,
out + buf_offset);
if (mips_debug && in != NULL)
{
int i;
fprintf_unfiltered (gdb_stdlog, "in ");
for (i = 0; i < length; i++)
fprintf_unfiltered (gdb_stdlog, "%02x", in[buf_offset + i]);
}
if (mips_debug)
fprintf_unfiltered (gdb_stdlog, "\n");
}
static int
mips2_fp_compat (void)
{
if (register_size (current_gdbarch, mips_regnum (current_gdbarch)->fp0) ==
4)
return 0;
#if 0
if ((read_register (MIPS_PS_REGNUM) & ST0_FR) == 0)
return 1;
#endif
return 0;
}
static const char *mips_stack_argsize_string = size_auto;
static unsigned int
mips_stack_argsize (struct gdbarch *gdbarch)
{
if (mips_stack_argsize_string == size_auto)
return mips_abi_regsize (gdbarch);
else if (mips_stack_argsize_string == size_64)
return 8;
else
return 4;
}
#define VM_MIN_ADDRESS (CORE_ADDR)0x400000
static CORE_ADDR heuristic_proc_start (CORE_ADDR);
static CORE_ADDR read_next_frame_reg (struct frame_info *, int);
static void reinit_frame_cache_sfunc (char *, int, struct cmd_list_element *);
static struct type *mips_float_register_type (void);
static struct type *mips_double_register_type (void);
static struct cmd_list_element *setmipscmdlist = NULL;
static struct cmd_list_element *showmipscmdlist = NULL;
enum
{ NUM_MIPS_PROCESSOR_REGS = (90 - 32) };
static const char *mips_generic_reg_names[NUM_MIPS_PROCESSOR_REGS] = {
"sr", "lo", "hi", "bad", "cause", "pc",
"f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7",
"f8", "f9", "f10", "f11", "f12", "f13", "f14", "f15",
"f16", "f17", "f18", "f19", "f20", "f21", "f22", "f23",
"f24", "f25", "f26", "f27", "f28", "f29", "f30", "f31",
"fsr", "fir", "" , "",
"", "", "", "", "", "", "", "",
"", "", "", "", "", "", "", "",
};
static const char *mips_r3041_reg_names[] = {
"sr", "lo", "hi", "bad", "cause", "pc",
"f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7",
"f8", "f9", "f10", "f11", "f12", "f13", "f14", "f15",
"f16", "f17", "f18", "f19", "f20", "f21", "f22", "f23",
"f24", "f25", "f26", "f27", "f28", "f29", "f30", "f31",
"fsr", "fir", "", "",
"", "", "bus", "ccfg", "", "", "", "",
"", "", "port", "cmp", "", "", "epc", "prid",
};
static const char *mips_tx39_reg_names[NUM_MIPS_PROCESSOR_REGS] = {
"sr", "lo", "hi", "bad", "cause", "pc",
"", "", "", "", "", "", "", "",
"", "", "", "", "", "", "", "",
"", "", "", "", "", "", "", "",
"", "", "", "", "", "", "", "",
"", "", "", "",
"", "", "", "", "", "", "", "",
"", "", "config", "cache", "debug", "depc", "epc", ""
};
static const char *mips_irix_reg_names[NUM_MIPS_PROCESSOR_REGS] = {
"f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7",
"f8", "f9", "f10", "f11", "f12", "f13", "f14", "f15",
"f16", "f17", "f18", "f19", "f20", "f21", "f22", "f23",
"f24", "f25", "f26", "f27", "f28", "f29", "f30", "f31",
"pc", "cause", "bad", "hi", "lo", "fsr", "fir"
};
static const char *
mips_register_name (int regno)
{
struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
static char *mips_gpr_names[] = {
"zero", "at", "v0", "v1", "a0", "a1", "a2", "a3",
"t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7",
"s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7",
"t8", "t9", "k0", "k1", "gp", "sp", "s8", "ra",
};
static char *mips_n32_n64_gpr_names[] = {
"zero", "at", "v0", "v1", "a0", "a1", "a2", "a3",
"a4", "a5", "a6", "a7", "t0", "t1", "t2", "t3",
"s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7",
"t8", "t9", "k0", "k1", "gp", "sp", "s8", "ra"
};
enum mips_abi abi = mips_abi (current_gdbarch);
int rawnum = regno % NUM_REGS;
if (regno < NUM_REGS)
return "";
if (0 <= rawnum && rawnum < 32)
{
if (abi == MIPS_ABI_N32 || abi == MIPS_ABI_N64)
return mips_n32_n64_gpr_names[rawnum];
else
return mips_gpr_names[rawnum];
}
else if (32 <= rawnum && rawnum < NUM_REGS)
{
gdb_assert (rawnum - 32 < NUM_MIPS_PROCESSOR_REGS);
return tdep->mips_processor_reg_names[rawnum - 32];
}
else
internal_error (__FILE__, __LINE__,
_("mips_register_name: bad register number %d"), rawnum);
}
static int
mips_register_reggroup_p (struct gdbarch *gdbarch, int regnum,
struct reggroup *reggroup)
{
int vector_p;
int float_p;
int raw_p;
int rawnum = regnum % NUM_REGS;
int pseudo = regnum / NUM_REGS;
if (reggroup == all_reggroup)
return pseudo;
vector_p = TYPE_VECTOR (register_type (gdbarch, regnum));
float_p = TYPE_CODE (register_type (gdbarch, regnum)) == TYPE_CODE_FLT;
raw_p = rawnum < NUM_REGS;
if (REGISTER_NAME (regnum) == NULL || REGISTER_NAME (regnum)[0] == '\0')
return 0;
if (reggroup == float_reggroup)
return float_p && pseudo;
if (reggroup == vector_reggroup)
return vector_p && pseudo;
if (reggroup == general_reggroup)
return (!vector_p && !float_p) && pseudo;
if (reggroup == save_reggroup)
return raw_p && pseudo;
if (reggroup == restore_reggroup)
return raw_p && pseudo;
return 0;
}
static void
mips_pseudo_register_read (struct gdbarch *gdbarch, struct regcache *regcache,
int cookednum, gdb_byte *buf)
{
int rawnum = cookednum % NUM_REGS;
gdb_assert (cookednum >= NUM_REGS && cookednum < 2 * NUM_REGS);
if (register_size (gdbarch, rawnum) == register_size (gdbarch, cookednum))
regcache_raw_read (regcache, rawnum, buf);
else if (register_size (gdbarch, rawnum) >
register_size (gdbarch, cookednum))
{
if (gdbarch_tdep (gdbarch)->mips64_transfers_32bit_regs_p
|| TARGET_BYTE_ORDER == BFD_ENDIAN_LITTLE)
regcache_raw_read_part (regcache, rawnum, 0, 4, buf);
else
regcache_raw_read_part (regcache, rawnum, 4, 4, buf);
}
else
internal_error (__FILE__, __LINE__, _("bad register size"));
}
static void
mips_pseudo_register_write (struct gdbarch *gdbarch,
struct regcache *regcache, int cookednum,
const gdb_byte *buf)
{
int rawnum = cookednum % NUM_REGS;
gdb_assert (cookednum >= NUM_REGS && cookednum < 2 * NUM_REGS);
if (register_size (gdbarch, rawnum) == register_size (gdbarch, cookednum))
regcache_raw_write (regcache, rawnum, buf);
else if (register_size (gdbarch, rawnum) >
register_size (gdbarch, cookednum))
{
if (gdbarch_tdep (gdbarch)->mips64_transfers_32bit_regs_p
|| TARGET_BYTE_ORDER == BFD_ENDIAN_LITTLE)
regcache_raw_write_part (regcache, rawnum, 0, 4, buf);
else
regcache_raw_write_part (regcache, rawnum, 4, 4, buf);
}
else
internal_error (__FILE__, __LINE__, _("bad register size"));
}
static int mips16_to_32_reg[8] = { 16, 17, 2, 3, 4, 5, 6, 7 };
static unsigned int heuristic_fence_post = 0;
static int mips64_transfers_32bit_regs_p = 0;
static void
set_mips64_transfers_32bit_regs (char *args, int from_tty,
struct cmd_list_element *c)
{
struct gdbarch_info info;
gdbarch_info_init (&info);
if (!gdbarch_update_p (info))
{
mips64_transfers_32bit_regs_p = 0;
error (_("32-bit compatibility mode not supported"));
}
}
static int
mips_convert_register_p (int regnum, struct type *type)
{
return (TARGET_BYTE_ORDER == BFD_ENDIAN_BIG
&& register_size (current_gdbarch, regnum) == 4
&& (regnum % NUM_REGS) >= mips_regnum (current_gdbarch)->fp0
&& (regnum % NUM_REGS) < mips_regnum (current_gdbarch)->fp0 + 32
&& TYPE_CODE (type) == TYPE_CODE_FLT && TYPE_LENGTH (type) == 8);
}
static void
mips_register_to_value (struct frame_info *frame, int regnum,
struct type *type, gdb_byte *to)
{
get_frame_register (frame, regnum + 0, to + 4);
get_frame_register (frame, regnum + 1, to + 0);
}
static void
mips_value_to_register (struct frame_info *frame, int regnum,
struct type *type, const gdb_byte *from)
{
put_frame_register (frame, regnum + 0, from + 4);
put_frame_register (frame, regnum + 1, from + 0);
}
static struct type *
mips_register_type (struct gdbarch *gdbarch, int regnum)
{
gdb_assert (regnum >= 0 && regnum < 2 * NUM_REGS);
if ((regnum % NUM_REGS) >= mips_regnum (current_gdbarch)->fp0
&& (regnum % NUM_REGS) < mips_regnum (current_gdbarch)->fp0 + 32)
{
switch (gdbarch_byte_order (gdbarch))
{
case BFD_ENDIAN_BIG:
if (mips_isa_regsize (gdbarch) == 4)
return builtin_type_ieee_single_big;
else
return builtin_type_ieee_double_big;
case BFD_ENDIAN_LITTLE:
if (mips_isa_regsize (gdbarch) == 4)
return builtin_type_ieee_single_little;
else
return builtin_type_ieee_double_little;
case BFD_ENDIAN_UNKNOWN:
default:
internal_error (__FILE__, __LINE__, _("bad switch"));
}
}
else if (regnum < NUM_REGS)
{
if (mips_isa_regsize (gdbarch) == 4)
return builtin_type_int32;
else
return builtin_type_int64;
}
else
{
if (regnum >= (NUM_REGS
+ mips_regnum (current_gdbarch)->fp_control_status)
&& regnum <= NUM_REGS + MIPS_LAST_EMBED_REGNUM)
return builtin_type_int32;
else if (gdbarch_tdep (gdbarch)->mips64_transfers_32bit_regs_p)
return builtin_type_int32;
else if (mips_abi_regsize (gdbarch) == 4)
return builtin_type_int32;
else
return builtin_type_int64;
}
}
static CORE_ADDR
mips_read_sp (void)
{
return read_signed_register (MIPS_SP_REGNUM);
}
enum auto_boolean mask_address_var = AUTO_BOOLEAN_AUTO;
static int
mips_mask_address_p (struct gdbarch_tdep *tdep)
{
switch (mask_address_var)
{
case AUTO_BOOLEAN_TRUE:
return 1;
case AUTO_BOOLEAN_FALSE:
return 0;
break;
case AUTO_BOOLEAN_AUTO:
return tdep->default_mask_address_p;
default:
internal_error (__FILE__, __LINE__, _("mips_mask_address_p: bad switch"));
return -1;
}
}
static void
show_mask_address (struct ui_file *file, int from_tty,
struct cmd_list_element *c, const char *value)
{
struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
deprecated_show_value_hack (file, from_tty, c, value);
switch (mask_address_var)
{
case AUTO_BOOLEAN_TRUE:
printf_filtered ("The 32 bit mips address mask is enabled\n");
break;
case AUTO_BOOLEAN_FALSE:
printf_filtered ("The 32 bit mips address mask is disabled\n");
break;
case AUTO_BOOLEAN_AUTO:
printf_filtered
("The 32 bit address mask is set automatically. Currently %s\n",
mips_mask_address_p (tdep) ? "enabled" : "disabled");
break;
default:
internal_error (__FILE__, __LINE__, _("show_mask_address: bad switch"));
break;
}
}
int
mips_pc_is_mips16 (CORE_ADDR memaddr)
{
struct minimal_symbol *sym;
if (is_mips16_addr (memaddr))
return 1;
sym = lookup_minimal_symbol_by_pc (memaddr);
if (sym)
return msymbol_is_special (sym);
else
return 0;
}
static CORE_ADDR
mips_read_pc (ptid_t ptid)
{
return read_signed_register_pid (mips_regnum (current_gdbarch)->pc, ptid);
}
static CORE_ADDR
mips_unwind_pc (struct gdbarch *gdbarch, struct frame_info *next_frame)
{
return frame_unwind_register_signed (next_frame,
NUM_REGS + mips_regnum (gdbarch)->pc);
}
static struct frame_id
mips_unwind_dummy_id (struct gdbarch *gdbarch, struct frame_info *next_frame)
{
return frame_id_build (frame_unwind_register_signed (next_frame, NUM_REGS + MIPS_SP_REGNUM),
frame_pc_unwind (next_frame));
}
static void
mips_write_pc (CORE_ADDR pc, ptid_t ptid)
{
write_register_pid (mips_regnum (current_gdbarch)->pc, pc, ptid);
}
static ULONGEST
mips_fetch_instruction (CORE_ADDR addr)
{
gdb_byte buf[MIPS_INSN32_SIZE];
int instlen;
int status;
if (mips_pc_is_mips16 (addr))
{
instlen = MIPS_INSN16_SIZE;
addr = unmake_mips16_addr (addr);
}
else
instlen = MIPS_INSN32_SIZE;
status = deprecated_read_memory_nobpt (addr, buf, instlen);
if (status)
memory_error (status, addr);
return extract_unsigned_integer (buf, instlen);
}
#define mips32_op(x) (x >> 26)
#define itype_op(x) (x >> 26)
#define itype_rs(x) ((x >> 21) & 0x1f)
#define itype_rt(x) ((x >> 16) & 0x1f)
#define itype_immediate(x) (x & 0xffff)
#define jtype_op(x) (x >> 26)
#define jtype_target(x) (x & 0x03ffffff)
#define rtype_op(x) (x >> 26)
#define rtype_rs(x) ((x >> 21) & 0x1f)
#define rtype_rt(x) ((x >> 16) & 0x1f)
#define rtype_rd(x) ((x >> 11) & 0x1f)
#define rtype_shamt(x) ((x >> 6) & 0x1f)
#define rtype_funct(x) (x & 0x3f)
static LONGEST
mips32_relative_offset (ULONGEST inst)
{
return ((itype_immediate (inst) ^ 0x8000) - 0x8000) << 2;
}
static CORE_ADDR
mips32_next_pc (CORE_ADDR pc)
{
unsigned long inst;
int op;
inst = mips_fetch_instruction (pc);
if ((inst & 0xe0000000) != 0)
{
if (itype_op (inst) >> 2 == 5)
{
op = (itype_op (inst) & 0x03);
switch (op)
{
case 0:
goto equal_branch;
case 1:
goto neq_branch;
case 2:
goto less_branch;
case 3:
goto greater_branch;
default:
pc += 4;
}
}
else if (itype_op (inst) == 17 && itype_rs (inst) == 8)
{
int tf = itype_rt (inst) & 0x01;
int cnum = itype_rt (inst) >> 2;
int fcrcs =
read_signed_register (mips_regnum (current_gdbarch)->
fp_control_status);
int cond = ((fcrcs >> 24) & 0x0e) | ((fcrcs >> 23) & 0x01);
if (((cond >> cnum) & 0x01) == tf)
pc += mips32_relative_offset (inst) + 4;
else
pc += 8;
}
else
pc += 4;
}
else
{
switch (op = itype_op (inst) & 0x07)
{
case 0:
op = rtype_funct (inst);
switch (op)
{
case 8:
case 9:
pc = read_signed_register (rtype_rs (inst));
break;
default:
pc += 4;
}
break;
case 1:
{
op = itype_rt (inst);
switch (op)
{
case 0:
case 2:
case 16:
case 18:
less_branch:
if (read_signed_register (itype_rs (inst)) < 0)
pc += mips32_relative_offset (inst) + 4;
else
pc += 8;
break;
case 1:
case 3:
case 17:
case 19:
if (read_signed_register (itype_rs (inst)) >= 0)
pc += mips32_relative_offset (inst) + 4;
else
pc += 8;
break;
default:
pc += 4;
}
}
break;
case 2:
case 3:
{
unsigned long reg;
reg = jtype_target (inst) << 2;
pc = reg + ((pc + 4) & 0xf0000000);
}
break;
{
unsigned long reg;
reg = jtype_target (inst) << 2;
pc = reg + ((pc + 4) & 0xf0000000) + 1;
}
break;
case 4:
equal_branch:
if (read_signed_register (itype_rs (inst)) ==
read_signed_register (itype_rt (inst)))
pc += mips32_relative_offset (inst) + 4;
else
pc += 8;
break;
case 5:
neq_branch:
if (read_signed_register (itype_rs (inst)) !=
read_signed_register (itype_rt (inst)))
pc += mips32_relative_offset (inst) + 4;
else
pc += 8;
break;
case 6:
if (read_signed_register (itype_rs (inst)) <= 0)
pc += mips32_relative_offset (inst) + 4;
else
pc += 8;
break;
case 7:
default:
greater_branch:
if (read_signed_register (itype_rs (inst)) > 0)
pc += mips32_relative_offset (inst) + 4;
else
pc += 8;
break;
}
}
return pc;
}
enum mips16_inst_fmts
{
itype,
ritype,
rrtype,
rritype,
rrrtype,
rriatype,
shifttype,
i8type,
i8movtype,
i8mov32rtype,
i64type,
ri64type,
jalxtype,
exiItype,
extRitype,
extRRItype,
extRRIAtype,
EXTshifttype,
extI8type,
extI64type,
extRi64type,
extshift64type
};
struct upk_mips16
{
CORE_ADDR offset;
unsigned int regx;
unsigned int regy;
};
static CORE_ADDR
extended_offset (unsigned int extension)
{
CORE_ADDR value;
value = (extension >> 21) & 0x3f;
value = value << 6;
value |= (extension >> 16) & 0x1f;
value = value << 5;
value |= extension & 0x01f;
return value;
}
static unsigned int
fetch_mips_16 (CORE_ADDR pc)
{
gdb_byte buf[8];
pc &= 0xfffffffe;
target_read_memory (pc, buf, 2);
return extract_unsigned_integer (buf, 2);
}
static void
unpack_mips16 (CORE_ADDR pc,
unsigned int extension,
unsigned int inst,
enum mips16_inst_fmts insn_format, struct upk_mips16 *upk)
{
CORE_ADDR offset;
int regx;
int regy;
switch (insn_format)
{
case itype:
{
CORE_ADDR value;
if (extension)
{
value = extended_offset (extension);
value = value << 11;
value |= inst & 0x7ff;
}
else
{
value = inst & 0x7ff;
}
offset = value;
regx = -1;
regy = -1;
}
break;
case ritype:
case i8type:
{
CORE_ADDR value;
if (extension)
{
value = extended_offset (extension);
value = value << 8;
value |= inst & 0xff;
regx = (extension >> 8) & 0x07;
if (value & 0x4000)
{
value &= ~0x3fff;
value = -value;
}
}
else
{
value = inst & 0xff;
regx = (inst >> 8) & 0x07;
if (value & 0x80)
{
value &= 0xef;
value = -value;
}
}
offset = value;
regy = -1;
break;
}
case jalxtype:
{
unsigned long value;
unsigned int nexthalf;
value = ((inst & 0x1f) << 5) | ((inst >> 5) & 0x1f);
value = value << 16;
nexthalf = mips_fetch_instruction (pc + 2);
value |= nexthalf;
offset = value;
regx = -1;
regy = -1;
break;
}
default:
internal_error (__FILE__, __LINE__, _("bad switch"));
}
upk->offset = offset;
upk->regx = regx;
upk->regy = regy;
}
static CORE_ADDR
add_offset_16 (CORE_ADDR pc, int offset)
{
return ((offset << 2) | ((pc + 2) & (0xf0000000)));
}
static CORE_ADDR
extended_mips16_next_pc (CORE_ADDR pc,
unsigned int extension, unsigned int insn)
{
int op = (insn >> 11);
switch (op)
{
case 2:
{
CORE_ADDR offset;
struct upk_mips16 upk;
unpack_mips16 (pc, extension, insn, itype, &upk);
offset = upk.offset;
if (offset & 0x800)
{
offset &= 0xeff;
offset = -offset;
}
pc += (offset << 1) + 2;
break;
}
case 3:
{
struct upk_mips16 upk;
unpack_mips16 (pc, extension, insn, jalxtype, &upk);
pc = add_offset_16 (pc, upk.offset);
if ((insn >> 10) & 0x01)
pc = pc & ~0x01;
else
pc |= 0x01;
break;
}
case 4:
{
struct upk_mips16 upk;
int reg;
unpack_mips16 (pc, extension, insn, ritype, &upk);
reg = read_signed_register (upk.regx);
if (reg == 0)
pc += (upk.offset << 1) + 2;
else
pc += 2;
break;
}
case 5:
{
struct upk_mips16 upk;
int reg;
unpack_mips16 (pc, extension, insn, ritype, &upk);
reg = read_signed_register (upk.regx);
if (reg != 0)
pc += (upk.offset << 1) + 2;
else
pc += 2;
break;
}
case 12:
{
struct upk_mips16 upk;
int reg;
unpack_mips16 (pc, extension, insn, i8type, &upk);
reg = read_signed_register (24);
if (((upk.regx == 0) && (reg == 0))
|| ((upk.regx == 1) && (reg != 0)))
pc += (upk.offset << 1) + 2;
else
pc += 2;
break;
}
case 29:
{
struct upk_mips16 upk;
op = insn & 0x1f;
if (op == 0)
{
int reg;
upk.regx = (insn >> 8) & 0x07;
upk.regy = (insn >> 5) & 0x07;
switch (upk.regy)
{
case 0:
reg = upk.regx;
break;
case 1:
reg = 31;
break;
case 2:
reg = upk.regx;
break;
default:
reg = 31;
break;
}
pc = read_signed_register (reg);
}
else
pc += 2;
break;
}
case 30:
{
pc += 2;
pc = extended_mips16_next_pc (pc, insn, fetch_mips_16 (pc));
break;
}
default:
{
pc += 2;
break;
}
}
return pc;
}
static CORE_ADDR
mips16_next_pc (CORE_ADDR pc)
{
unsigned int insn = fetch_mips_16 (pc);
return extended_mips16_next_pc (pc, 0, insn);
}
CORE_ADDR
mips_next_pc (CORE_ADDR pc)
{
if (pc & 0x01)
return mips16_next_pc (pc);
else
return mips32_next_pc (pc);
}
struct mips_frame_cache
{
CORE_ADDR base;
struct trad_frame_saved_reg *saved_regs;
};
static void
set_reg_offset (struct mips_frame_cache *this_cache, int regnum,
CORE_ADDR offset)
{
if (this_cache != NULL
&& this_cache->saved_regs[regnum].addr == -1)
{
this_cache->saved_regs[regnum + 0 * NUM_REGS].addr = offset;
this_cache->saved_regs[regnum + 1 * NUM_REGS].addr = offset;
}
}
static int
mips16_get_imm (unsigned short prev_inst,
unsigned short inst,
int nbits,
int scale,
int is_signed)
{
int offset;
if ((prev_inst & 0xf800) == 0xf000)
{
offset = ((prev_inst & 0x1f) << 11) | (prev_inst & 0x7e0);
if (offset & 0x8000)
offset = 0 - (0x10000 - (offset & 0xffff));
return offset | (inst & 0x1f);
}
else
{
int max_imm = 1 << nbits;
int mask = max_imm - 1;
int sign_bit = max_imm >> 1;
offset = inst & mask;
if (is_signed && (offset & sign_bit))
offset = 0 - (max_imm - offset);
return offset * scale;
}
}
static CORE_ADDR
mips16_scan_prologue (CORE_ADDR start_pc, CORE_ADDR limit_pc,
struct frame_info *next_frame,
struct mips_frame_cache *this_cache)
{
CORE_ADDR cur_pc;
CORE_ADDR frame_addr = 0;
CORE_ADDR sp;
long frame_offset = 0;
long frame_adjust = 0;
int frame_reg = MIPS_SP_REGNUM;
unsigned short prev_inst = 0;
unsigned inst = 0;
unsigned entry_inst = 0;
int reg, offset;
int extend_bytes = 0;
int prev_extend_bytes;
CORE_ADDR end_prologue_addr = 0;
if (next_frame != NULL)
sp = read_next_frame_reg (next_frame, NUM_REGS + MIPS_SP_REGNUM);
else
sp = 0;
if (limit_pc > start_pc + 200)
limit_pc = start_pc + 200;
for (cur_pc = start_pc; cur_pc < limit_pc; cur_pc += MIPS_INSN16_SIZE)
{
prev_inst = inst;
inst = (unsigned short) mips_fetch_instruction (cur_pc);
if ((inst & 0xf800) == 0xf000)
{
extend_bytes = MIPS_INSN16_SIZE;
continue;
}
prev_extend_bytes = extend_bytes;
extend_bytes = 0;
if ((inst & 0xff00) == 0x6300
|| (inst & 0xff00) == 0xfb00)
{
offset = mips16_get_imm (prev_inst, inst, 8, 8, 1);
if (offset < 0)
frame_offset -= offset;
else
break;
}
else if ((inst & 0xf800) == 0xd000)
{
offset = mips16_get_imm (prev_inst, inst, 8, 4, 0);
reg = mips16_to_32_reg[(inst & 0x700) >> 8];
set_reg_offset (this_cache, reg, sp + offset);
}
else if ((inst & 0xff00) == 0xf900)
{
offset = mips16_get_imm (prev_inst, inst, 5, 8, 0);
reg = mips16_to_32_reg[(inst & 0xe0) >> 5];
set_reg_offset (this_cache, reg, sp + offset);
}
else if ((inst & 0xff00) == 0x6200)
{
offset = mips16_get_imm (prev_inst, inst, 8, 4, 0);
set_reg_offset (this_cache, MIPS_RA_REGNUM, sp + offset);
}
else if ((inst & 0xff00) == 0xfa00)
{
offset = mips16_get_imm (prev_inst, inst, 8, 8, 0);
set_reg_offset (this_cache, MIPS_RA_REGNUM, sp + offset);
}
else if (inst == 0x673d)
{
frame_addr = sp;
frame_reg = 17;
}
else if ((inst & 0xff00) == 0x0100)
{
offset = mips16_get_imm (prev_inst, inst, 8, 4, 0);
frame_addr = sp + offset;
frame_reg = 17;
frame_adjust = offset;
}
else if ((inst & 0xFF00) == 0xd900)
{
offset = mips16_get_imm (prev_inst, inst, 5, 4, 0);
reg = mips16_to_32_reg[(inst & 0xe0) >> 5];
set_reg_offset (this_cache, reg, frame_addr + offset);
}
else if ((inst & 0xFF00) == 0x7900)
{
offset = mips16_get_imm (prev_inst, inst, 5, 8, 0);
reg = mips16_to_32_reg[(inst & 0xe0) >> 5];
set_reg_offset (this_cache, reg, frame_addr + offset);
}
else if ((inst & 0xf81f) == 0xe809
&& (inst & 0x700) != 0x700)
entry_inst = inst;
else if ((inst & 0xf800) == 0x1800)
cur_pc += MIPS_INSN16_SIZE;
else if ((inst & 0xff1c) == 0x6704)
{
}
else
{
if (end_prologue_addr == 0)
end_prologue_addr = cur_pc - prev_extend_bytes;
}
}
if (entry_inst != 0)
{
int areg_count = (entry_inst >> 8) & 7;
int sreg_count = (entry_inst >> 6) & 3;
frame_offset += 32;
sp += frame_offset;
for (reg = 4, offset = 0; reg < areg_count + 4; reg++)
{
set_reg_offset (this_cache, reg, sp + offset);
offset += mips_abi_regsize (current_gdbarch);
}
offset = -4;
if (entry_inst & 0x20)
{
set_reg_offset (this_cache, MIPS_RA_REGNUM, sp + offset);
offset -= mips_abi_regsize (current_gdbarch);
}
for (reg = 16; reg < sreg_count + 16; reg++)
{
set_reg_offset (this_cache, reg, sp + offset);
offset -= mips_abi_regsize (current_gdbarch);
}
}
if (this_cache != NULL)
{
this_cache->base =
(frame_unwind_register_signed (next_frame, NUM_REGS + frame_reg)
+ frame_offset - frame_adjust);
this_cache->saved_regs[NUM_REGS + mips_regnum (current_gdbarch)->pc]
= this_cache->saved_regs[NUM_REGS + MIPS_RA_REGNUM];
}
if (end_prologue_addr == 0)
end_prologue_addr = cur_pc;
return end_prologue_addr;
}
static struct mips_frame_cache *
mips_insn16_frame_cache (struct frame_info *next_frame, void **this_cache)
{
struct mips_frame_cache *cache;
if ((*this_cache) != NULL)
return (*this_cache);
cache = FRAME_OBSTACK_ZALLOC (struct mips_frame_cache);
(*this_cache) = cache;
cache->saved_regs = trad_frame_alloc_saved_regs (next_frame);
{
const CORE_ADDR pc = frame_pc_unwind (next_frame);
CORE_ADDR start_addr;
find_pc_partial_function (pc, NULL, &start_addr, NULL);
if (start_addr == 0)
start_addr = heuristic_proc_start (pc);
if (start_addr == 0)
return cache;
mips16_scan_prologue (start_addr, pc, next_frame, *this_cache);
}
trad_frame_set_value (cache->saved_regs, NUM_REGS + MIPS_SP_REGNUM, cache->base);
return (*this_cache);
}
static void
mips_insn16_frame_this_id (struct frame_info *next_frame, void **this_cache,
struct frame_id *this_id)
{
struct mips_frame_cache *info = mips_insn16_frame_cache (next_frame,
this_cache);
(*this_id) = frame_id_build (info->base, frame_func_unwind (next_frame));
}
static void
mips_insn16_frame_prev_register (struct frame_info *next_frame,
void **this_cache,
int regnum, enum opt_state *optimizedp,
enum lval_type *lvalp, CORE_ADDR *addrp,
int *realnump, gdb_byte *valuep)
{
struct mips_frame_cache *info = mips_insn16_frame_cache (next_frame,
this_cache);
trad_frame_get_prev_register (next_frame, info->saved_regs, regnum,
optimizedp, lvalp, addrp, realnump, valuep);
}
static const struct frame_unwind mips_insn16_frame_unwind =
{
NORMAL_FRAME,
mips_insn16_frame_this_id,
mips_insn16_frame_prev_register
};
static const struct frame_unwind *
mips_insn16_frame_sniffer (struct frame_info *next_frame)
{
CORE_ADDR pc = frame_pc_unwind (next_frame);
if (mips_pc_is_mips16 (pc))
return &mips_insn16_frame_unwind;
return NULL;
}
static CORE_ADDR
mips_insn16_frame_base_address (struct frame_info *next_frame,
void **this_cache)
{
struct mips_frame_cache *info = mips_insn16_frame_cache (next_frame,
this_cache);
return info->base;
}
static const struct frame_base mips_insn16_frame_base =
{
&mips_insn16_frame_unwind,
mips_insn16_frame_base_address,
mips_insn16_frame_base_address,
mips_insn16_frame_base_address
};
static const struct frame_base *
mips_insn16_frame_base_sniffer (struct frame_info *next_frame)
{
if (mips_insn16_frame_sniffer (next_frame) != NULL)
return &mips_insn16_frame_base;
else
return NULL;
}
void
reset_saved_regs (struct mips_frame_cache *this_cache)
{
if (this_cache == NULL || this_cache->saved_regs == NULL)
return;
{
const int num_regs = NUM_REGS;
int i;
for (i = 0; i < num_regs; i++)
{
this_cache->saved_regs[i].addr = -1;
}
}
}
static CORE_ADDR
mips32_scan_prologue (CORE_ADDR start_pc, CORE_ADDR limit_pc,
struct frame_info *next_frame,
struct mips_frame_cache *this_cache)
{
CORE_ADDR cur_pc;
CORE_ADDR frame_addr = 0;
CORE_ADDR sp;
long frame_offset;
int frame_reg = MIPS_SP_REGNUM;
CORE_ADDR end_prologue_addr = 0;
int seen_sp_adjust = 0;
int load_immediate_bytes = 0;
if (next_frame != NULL)
sp = read_next_frame_reg (next_frame, NUM_REGS + MIPS_SP_REGNUM);
else
sp = 0;
if (limit_pc > start_pc + 200)
limit_pc = start_pc + 200;
restart:
frame_offset = 0;
for (cur_pc = start_pc; cur_pc < limit_pc; cur_pc += MIPS_INSN32_SIZE)
{
unsigned long inst, high_word, low_word;
int reg;
inst = (unsigned long) mips_fetch_instruction (cur_pc);
high_word = (inst >> 16) & 0xffff;
low_word = inst & 0xffff;
reg = high_word & 0x1f;
if (high_word == 0x27bd
|| high_word == 0x23bd
|| high_word == 0x67bd)
{
if (low_word & 0x8000)
frame_offset += 0x10000 - low_word;
else
break;
seen_sp_adjust = 1;
}
else if ((high_word & 0xFFE0) == 0xafa0)
{
set_reg_offset (this_cache, reg, sp + low_word);
}
else if ((high_word & 0xFFE0) == 0xffa0)
{
set_reg_offset (this_cache, reg, sp + low_word);
}
else if (high_word == 0x27be)
{
if ((long) low_word != frame_offset)
frame_addr = sp + low_word;
else if (frame_reg == MIPS_SP_REGNUM)
{
unsigned alloca_adjust;
frame_reg = 30;
frame_addr = read_next_frame_reg (next_frame, NUM_REGS + 30);
alloca_adjust = (unsigned) (frame_addr - (sp + low_word));
if (alloca_adjust > 0)
{
sp += alloca_adjust;
reset_saved_regs (this_cache);
goto restart;
}
}
}
else if (inst == 0x03A0F021 || inst == 0x03a0f025 || inst == 0x03a0f02d)
{
if (frame_reg == MIPS_SP_REGNUM)
{
unsigned alloca_adjust;
frame_reg = 30;
frame_addr = read_next_frame_reg (next_frame, NUM_REGS + 30);
alloca_adjust = (unsigned) (frame_addr - sp);
if (alloca_adjust > 0)
{
sp = frame_addr;
reset_saved_regs (this_cache);
goto restart;
}
}
}
else if ((high_word & 0xFFE0) == 0xafc0)
{
set_reg_offset (this_cache, reg, frame_addr + low_word);
}
else if ((high_word & 0xFFE0) == 0xE7A0
|| (high_word & 0xF3E0) == 0xA3C0
|| (inst & 0xFF9F07FF) == 0x00800021
|| high_word == 0x3c1c
|| high_word == 0x279c
|| inst == 0x0399e021
|| inst == 0x033ce021
)
{
}
else if (!seen_sp_adjust
&& (high_word == 0x3c01
|| high_word == 0x3c08
|| high_word == 0x3421
|| high_word == 0x3508
|| high_word == 0x3401
|| high_word == 0x3408
))
{
load_immediate_bytes += MIPS_INSN32_SIZE;
}
else
{
if (end_prologue_addr == 0)
end_prologue_addr = cur_pc;
}
}
if (this_cache != NULL)
{
this_cache->base =
(frame_unwind_register_signed (next_frame, NUM_REGS + frame_reg)
+ frame_offset);
this_cache->saved_regs[NUM_REGS + mips_regnum (current_gdbarch)->pc]
= this_cache->saved_regs[NUM_REGS + MIPS_RA_REGNUM];
}
if (end_prologue_addr == 0)
end_prologue_addr = cur_pc;
if (load_immediate_bytes && !seen_sp_adjust)
end_prologue_addr -= load_immediate_bytes;
return end_prologue_addr;
}
static struct mips_frame_cache *
mips_insn32_frame_cache (struct frame_info *next_frame, void **this_cache)
{
struct mips_frame_cache *cache;
if ((*this_cache) != NULL)
return (*this_cache);
cache = FRAME_OBSTACK_ZALLOC (struct mips_frame_cache);
(*this_cache) = cache;
cache->saved_regs = trad_frame_alloc_saved_regs (next_frame);
{
const CORE_ADDR pc = frame_pc_unwind (next_frame);
CORE_ADDR start_addr;
find_pc_partial_function (pc, NULL, &start_addr, NULL);
if (start_addr == 0)
start_addr = heuristic_proc_start (pc);
if (start_addr == 0)
return cache;
mips32_scan_prologue (start_addr, pc, next_frame, *this_cache);
}
trad_frame_set_value (cache->saved_regs, NUM_REGS + MIPS_SP_REGNUM, cache->base);
return (*this_cache);
}
static void
mips_insn32_frame_this_id (struct frame_info *next_frame, void **this_cache,
struct frame_id *this_id)
{
struct mips_frame_cache *info = mips_insn32_frame_cache (next_frame,
this_cache);
(*this_id) = frame_id_build (info->base, frame_func_unwind (next_frame));
}
static void
mips_insn32_frame_prev_register (struct frame_info *next_frame,
void **this_cache,
int regnum, enum opt_state *optimizedp,
enum lval_type *lvalp, CORE_ADDR *addrp,
int *realnump, gdb_byte *valuep)
{
struct mips_frame_cache *info = mips_insn32_frame_cache (next_frame,
this_cache);
trad_frame_get_prev_register (next_frame, info->saved_regs, regnum,
optimizedp, lvalp, addrp, realnump, valuep);
}
static const struct frame_unwind mips_insn32_frame_unwind =
{
NORMAL_FRAME,
mips_insn32_frame_this_id,
mips_insn32_frame_prev_register
};
static const struct frame_unwind *
mips_insn32_frame_sniffer (struct frame_info *next_frame)
{
CORE_ADDR pc = frame_pc_unwind (next_frame);
if (! mips_pc_is_mips16 (pc))
return &mips_insn32_frame_unwind;
return NULL;
}
static CORE_ADDR
mips_insn32_frame_base_address (struct frame_info *next_frame,
void **this_cache)
{
struct mips_frame_cache *info = mips_insn32_frame_cache (next_frame,
this_cache);
return info->base;
}
static const struct frame_base mips_insn32_frame_base =
{
&mips_insn32_frame_unwind,
mips_insn32_frame_base_address,
mips_insn32_frame_base_address,
mips_insn32_frame_base_address
};
static const struct frame_base *
mips_insn32_frame_base_sniffer (struct frame_info *next_frame)
{
if (mips_insn32_frame_sniffer (next_frame) != NULL)
return &mips_insn32_frame_base;
else
return NULL;
}
static struct trad_frame_cache *
mips_stub_frame_cache (struct frame_info *next_frame, void **this_cache)
{
CORE_ADDR pc;
CORE_ADDR start_addr;
CORE_ADDR stack_addr;
struct trad_frame_cache *this_trad_cache;
if ((*this_cache) != NULL)
return (*this_cache);
this_trad_cache = trad_frame_cache_zalloc (next_frame);
(*this_cache) = this_trad_cache;
trad_frame_set_reg_realreg (this_trad_cache, PC_REGNUM, MIPS_RA_REGNUM);
pc = frame_pc_unwind (next_frame);
find_pc_partial_function (pc, NULL, &start_addr, NULL);
stack_addr = frame_unwind_register_signed (next_frame, MIPS_SP_REGNUM);
trad_frame_set_id (this_trad_cache, frame_id_build (start_addr, stack_addr));
trad_frame_set_this_base (this_trad_cache, stack_addr);
return this_trad_cache;
}
static void
mips_stub_frame_this_id (struct frame_info *next_frame, void **this_cache,
struct frame_id *this_id)
{
struct trad_frame_cache *this_trad_cache
= mips_stub_frame_cache (next_frame, this_cache);
trad_frame_get_id (this_trad_cache, this_id);
}
static void
mips_stub_frame_prev_register (struct frame_info *next_frame,
void **this_cache,
int regnum, enum opt_state *optimizedp,
enum lval_type *lvalp, CORE_ADDR *addrp,
int *realnump, gdb_byte *valuep)
{
struct trad_frame_cache *this_trad_cache
= mips_stub_frame_cache (next_frame, this_cache);
trad_frame_get_register (this_trad_cache, next_frame, regnum, optimizedp,
lvalp, addrp, realnump, valuep);
}
static const struct frame_unwind mips_stub_frame_unwind =
{
NORMAL_FRAME,
mips_stub_frame_this_id,
mips_stub_frame_prev_register
};
static const struct frame_unwind *
mips_stub_frame_sniffer (struct frame_info *next_frame)
{
struct obj_section *s;
CORE_ADDR pc = frame_pc_unwind (next_frame);
if (in_plt_section (pc, NULL))
return &mips_stub_frame_unwind;
s = find_pc_section (pc);
if (s != NULL
&& strcmp (bfd_get_section_name (s->objfile->obfd, s->the_bfd_section),
".MIPS.stubs") == 0)
return &mips_stub_frame_unwind;
return NULL;
}
static CORE_ADDR
mips_stub_frame_base_address (struct frame_info *next_frame,
void **this_cache)
{
struct trad_frame_cache *this_trad_cache
= mips_stub_frame_cache (next_frame, this_cache);
return trad_frame_get_this_base (this_trad_cache);
}
static const struct frame_base mips_stub_frame_base =
{
&mips_stub_frame_unwind,
mips_stub_frame_base_address,
mips_stub_frame_base_address,
mips_stub_frame_base_address
};
static const struct frame_base *
mips_stub_frame_base_sniffer (struct frame_info *next_frame)
{
if (mips_stub_frame_sniffer (next_frame) != NULL)
return &mips_stub_frame_base;
else
return NULL;
}
static CORE_ADDR
read_next_frame_reg (struct frame_info *fi, int regno)
{
gdb_assert (regno >= NUM_REGS);
if (fi == NULL)
{
LONGEST val;
regcache_cooked_read_signed (current_regcache, regno, &val);
return val;
}
else
return frame_unwind_register_signed (fi, regno);
}
static CORE_ADDR
mips_addr_bits_remove (CORE_ADDR addr)
{
struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
if (mips_mask_address_p (tdep) && (((ULONGEST) addr) >> 32 == 0xffffffffUL))
return addr &= 0xffffffffUL;
else
return addr;
}
void
mips_software_single_step (enum target_signal sig, int insert_breakpoints_p)
{
static CORE_ADDR next_pc;
typedef char binsn_quantum[BREAKPOINT_MAX];
static binsn_quantum break_mem;
CORE_ADDR pc;
if (insert_breakpoints_p)
{
pc = read_register (mips_regnum (current_gdbarch)->pc);
next_pc = mips_next_pc (pc);
target_insert_breakpoint (next_pc, break_mem);
}
else
target_remove_breakpoint (next_pc, break_mem);
}
static int
mips_about_to_return (CORE_ADDR pc)
{
if (mips_pc_is_mips16 (pc))
return mips_fetch_instruction (pc) == 0xe820;
else
return mips_fetch_instruction (pc) == 0x3e00008;
}
static CORE_ADDR
heuristic_proc_start (CORE_ADDR pc)
{
CORE_ADDR start_pc;
CORE_ADDR fence;
int instlen;
int seen_adjsp = 0;
pc = ADDR_BITS_REMOVE (pc);
start_pc = pc;
fence = start_pc - heuristic_fence_post;
if (start_pc == 0)
return 0;
if (heuristic_fence_post == UINT_MAX || fence < VM_MIN_ADDRESS)
fence = VM_MIN_ADDRESS;
instlen = mips_pc_is_mips16 (pc) ? MIPS_INSN16_SIZE : MIPS_INSN32_SIZE;
for (start_pc -= instlen;; start_pc -= instlen)
if (start_pc < fence)
{
if (stop_soon == NO_STOP_QUIETLY)
{
static int blurb_printed = 0;
warning (_("GDB can't find the start of the function at 0x%s."),
paddr_nz (pc));
if (!blurb_printed)
{
printf_filtered ("\n\
GDB is unable to find the start of the function at 0x%s\n\
and thus can't determine the size of that function's stack frame.\n\
This means that GDB may be unable to access that stack frame, or\n\
the frames below it.\n\
This problem is most likely caused by an invalid program counter or\n\
stack pointer.\n\
However, if you think GDB should simply search farther back\n\
from 0x%s for code which looks like the beginning of a\n\
function, you can increase the range of the search using the `set\n\
heuristic-fence-post' command.\n", paddr_nz (pc), paddr_nz (pc));
blurb_printed = 1;
}
}
return 0;
}
else if (mips_pc_is_mips16 (start_pc))
{
unsigned short inst;
inst = mips_fetch_instruction (start_pc);
if (((inst & 0xf81f) == 0xe809 && (inst & 0x700) != 0x700)
|| (inst & 0xff80) == 0x6380
|| (inst & 0xff80) == 0xfb80
|| ((inst & 0xf810) == 0xf010 && seen_adjsp))
break;
else if ((inst & 0xff00) == 0x6300
|| (inst & 0xff00) == 0xfb00)
seen_adjsp = 1;
else
seen_adjsp = 0;
}
else if (mips_about_to_return (start_pc))
{
start_pc += 2 * MIPS_INSN32_SIZE;
break;
}
return start_pc;
}
struct mips_objfile_private
{
bfd_size_type size;
char *contents;
};
static int
fp_register_arg_p (enum type_code typecode, struct type *arg_type)
{
return ((typecode == TYPE_CODE_FLT
|| (MIPS_EABI
&& (typecode == TYPE_CODE_STRUCT
|| typecode == TYPE_CODE_UNION)
&& TYPE_NFIELDS (arg_type) == 1
&& TYPE_CODE (TYPE_FIELD_TYPE (arg_type, 0)) == TYPE_CODE_FLT))
&& MIPS_FPU_TYPE != MIPS_FPU_NONE);
}
static int
mips_type_needs_double_align (struct type *type)
{
enum type_code typecode = TYPE_CODE (type);
if (typecode == TYPE_CODE_FLT && TYPE_LENGTH (type) == 8)
return 1;
else if (typecode == TYPE_CODE_STRUCT)
{
if (TYPE_NFIELDS (type) < 1)
return 0;
return mips_type_needs_double_align (TYPE_FIELD_TYPE (type, 0));
}
else if (typecode == TYPE_CODE_UNION)
{
int i, n;
n = TYPE_NFIELDS (type);
for (i = 0; i < n; i++)
if (mips_type_needs_double_align (TYPE_FIELD_TYPE (type, i)))
return 1;
return 0;
}
return 0;
}
static CORE_ADDR
mips_frame_align (struct gdbarch *gdbarch, CORE_ADDR addr)
{
return align_down (addr, 16);
}
static CORE_ADDR
mips_eabi_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
struct regcache *regcache, CORE_ADDR bp_addr,
int nargs, struct value **args, CORE_ADDR sp,
int struct_return, CORE_ADDR struct_addr)
{
int argreg;
int float_argreg;
int argnum;
int len = 0;
int stack_offset = 0;
struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
CORE_ADDR func_addr = find_function_addr (function, NULL);
regcache_cooked_write_signed (regcache, MIPS_T9_REGNUM, func_addr);
regcache_cooked_write_signed (regcache, MIPS_RA_REGNUM, bp_addr);
sp = align_down (sp, 16);
struct_addr = align_down (struct_addr, 16);
for (argnum = 0; argnum < nargs; argnum++)
len += align_up (TYPE_LENGTH (value_type (args[argnum])),
mips_stack_argsize (gdbarch));
sp -= align_up (len, 16);
if (mips_debug)
fprintf_unfiltered (gdb_stdlog,
"mips_eabi_push_dummy_call: sp=0x%s allocated %ld\n",
paddr_nz (sp), (long) align_up (len, 16));
argreg = MIPS_A0_REGNUM;
float_argreg = mips_fpa0_regnum (current_gdbarch);
if (struct_return)
{
if (mips_debug)
fprintf_unfiltered (gdb_stdlog,
"mips_eabi_push_dummy_call: struct_return reg=%d 0x%s\n",
argreg, paddr_nz (struct_addr));
write_register (argreg++, struct_addr);
}
for (argnum = 0; argnum < nargs; argnum++)
{
const gdb_byte *val;
gdb_byte valbuf[MAX_REGISTER_SIZE];
struct value *arg = args[argnum];
struct type *arg_type = check_typedef (value_type (arg));
int len = TYPE_LENGTH (arg_type);
enum type_code typecode = TYPE_CODE (arg_type);
if (mips_debug)
fprintf_unfiltered (gdb_stdlog,
"mips_eabi_push_dummy_call: %d len=%d type=%d",
argnum + 1, len, (int) typecode);
if (len > mips_abi_regsize (gdbarch)
&& (typecode == TYPE_CODE_STRUCT || typecode == TYPE_CODE_UNION))
{
store_unsigned_integer (valbuf, mips_abi_regsize (gdbarch),
VALUE_ADDRESS (arg));
typecode = TYPE_CODE_PTR;
len = mips_abi_regsize (gdbarch);
val = valbuf;
if (mips_debug)
fprintf_unfiltered (gdb_stdlog, " push");
}
else
val = value_contents (arg);
if (mips_abi_regsize (gdbarch) < 8
&& fp_register_arg_p (typecode, arg_type))
{
if ((float_argreg & 1))
float_argreg++;
}
if (fp_register_arg_p (typecode, arg_type)
&& float_argreg <= MIPS_LAST_FP_ARG_REGNUM)
{
if (mips_abi_regsize (gdbarch) < 8 && len == 8)
{
int low_offset = TARGET_BYTE_ORDER == BFD_ENDIAN_BIG ? 4 : 0;
unsigned long regval;
regval = extract_unsigned_integer (val + low_offset, 4);
if (mips_debug)
fprintf_unfiltered (gdb_stdlog, " - fpreg=%d val=%s",
float_argreg, phex (regval, 4));
write_register (float_argreg++, regval);
regval = extract_unsigned_integer (val + 4 - low_offset, 4);
if (mips_debug)
fprintf_unfiltered (gdb_stdlog, " - fpreg=%d val=%s",
float_argreg, phex (regval, 4));
write_register (float_argreg++, regval);
}
else
{
LONGEST regval = extract_unsigned_integer (val, len);
if (mips_debug)
fprintf_unfiltered (gdb_stdlog, " - fpreg=%d val=%s",
float_argreg, phex (regval, len));
write_register (float_argreg++, regval);
}
}
else
{
int odd_sized_struct = ((len > mips_abi_regsize (gdbarch))
&& (len % mips_abi_regsize (gdbarch) != 0));
while (len > 0)
{
int stack_used_p = 0;
int partial_len = (len < mips_abi_regsize (gdbarch)
? len : mips_abi_regsize (gdbarch));
if (mips_debug)
fprintf_unfiltered (gdb_stdlog, " -- partial=%d",
partial_len);
if (argreg > MIPS_LAST_ARG_REGNUM
|| odd_sized_struct
|| fp_register_arg_p (typecode, arg_type))
{
int longword_offset = 0;
CORE_ADDR addr;
stack_used_p = 1;
if (TARGET_BYTE_ORDER == BFD_ENDIAN_BIG)
{
if (mips_stack_argsize (gdbarch) == 8
&& (typecode == TYPE_CODE_INT
|| typecode == TYPE_CODE_PTR
|| typecode == TYPE_CODE_FLT) && len <= 4)
longword_offset = mips_stack_argsize (gdbarch) - len;
else if ((typecode == TYPE_CODE_STRUCT
|| typecode == TYPE_CODE_UNION)
&& (TYPE_LENGTH (arg_type)
< mips_stack_argsize (gdbarch)))
longword_offset = mips_stack_argsize (gdbarch) - len;
}
if (mips_debug)
{
fprintf_unfiltered (gdb_stdlog, " - stack_offset=0x%s",
paddr_nz (stack_offset));
fprintf_unfiltered (gdb_stdlog, " longword_offset=0x%s",
paddr_nz (longword_offset));
}
addr = sp + stack_offset + longword_offset;
if (mips_debug)
{
int i;
fprintf_unfiltered (gdb_stdlog, " @0x%s ",
paddr_nz (addr));
for (i = 0; i < partial_len; i++)
{
fprintf_unfiltered (gdb_stdlog, "%02x",
val[i] & 0xff);
}
}
write_memory (addr, val, partial_len);
}
if (argreg <= MIPS_LAST_ARG_REGNUM
&& !fp_register_arg_p (typecode, arg_type))
{
LONGEST regval =
extract_unsigned_integer (val, partial_len);
if (mips_debug)
fprintf_filtered (gdb_stdlog, " - reg=%d val=%s",
argreg,
phex (regval,
mips_abi_regsize (gdbarch)));
write_register (argreg, regval);
argreg++;
}
len -= partial_len;
val += partial_len;
if (stack_used_p)
stack_offset += align_up (partial_len,
mips_stack_argsize (gdbarch));
}
}
if (mips_debug)
fprintf_unfiltered (gdb_stdlog, "\n");
}
regcache_cooked_write_signed (regcache, MIPS_SP_REGNUM, sp);
return sp;
}
static enum return_value_convention
mips_eabi_return_value (struct gdbarch *gdbarch,
struct type *type, struct regcache *regcache,
gdb_byte *readbuf, const gdb_byte *writebuf)
{
if (TYPE_LENGTH (type) > 2 * mips_abi_regsize (gdbarch))
return RETURN_VALUE_STRUCT_CONVENTION;
if (readbuf)
memset (readbuf, 0, TYPE_LENGTH (type));
return RETURN_VALUE_REGISTER_CONVENTION;
}
static CORE_ADDR
mips_n32n64_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
struct regcache *regcache, CORE_ADDR bp_addr,
int nargs, struct value **args, CORE_ADDR sp,
int struct_return, CORE_ADDR struct_addr)
{
int argreg;
int float_argreg;
int argnum;
int len = 0;
int stack_offset = 0;
struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
CORE_ADDR func_addr = find_function_addr (function, NULL);
regcache_cooked_write_signed (regcache, MIPS_T9_REGNUM, func_addr);
regcache_cooked_write_signed (regcache, MIPS_RA_REGNUM, bp_addr);
sp = align_down (sp, 16);
struct_addr = align_down (struct_addr, 16);
for (argnum = 0; argnum < nargs; argnum++)
len += align_up (TYPE_LENGTH (value_type (args[argnum])),
mips_stack_argsize (gdbarch));
sp -= align_up (len, 16);
if (mips_debug)
fprintf_unfiltered (gdb_stdlog,
"mips_n32n64_push_dummy_call: sp=0x%s allocated %ld\n",
paddr_nz (sp), (long) align_up (len, 16));
argreg = MIPS_A0_REGNUM;
float_argreg = mips_fpa0_regnum (current_gdbarch);
if (struct_return)
{
if (mips_debug)
fprintf_unfiltered (gdb_stdlog,
"mips_n32n64_push_dummy_call: struct_return reg=%d 0x%s\n",
argreg, paddr_nz (struct_addr));
write_register (argreg++, struct_addr);
}
for (argnum = 0; argnum < nargs; argnum++)
{
const gdb_byte *val;
struct value *arg = args[argnum];
struct type *arg_type = check_typedef (value_type (arg));
int len = TYPE_LENGTH (arg_type);
enum type_code typecode = TYPE_CODE (arg_type);
if (mips_debug)
fprintf_unfiltered (gdb_stdlog,
"mips_n32n64_push_dummy_call: %d len=%d type=%d",
argnum + 1, len, (int) typecode);
val = value_contents (arg);
if (fp_register_arg_p (typecode, arg_type)
&& float_argreg <= MIPS_LAST_FP_ARG_REGNUM)
{
LONGEST regval = extract_unsigned_integer (val, len);
if (mips_debug)
fprintf_unfiltered (gdb_stdlog, " - fpreg=%d val=%s",
float_argreg, phex (regval, len));
write_register (float_argreg++, regval);
if (mips_debug)
fprintf_unfiltered (gdb_stdlog, " - reg=%d val=%s",
argreg, phex (regval, len));
write_register (argreg, regval);
argreg += 1;
}
else
{
int odd_sized_struct = ((len > mips_abi_regsize (gdbarch))
&& (len % mips_abi_regsize (gdbarch) != 0));
while (len > 0)
{
int stack_used_p = 0;
int partial_len = (len < mips_abi_regsize (gdbarch)
? len : mips_abi_regsize (gdbarch));
if (mips_debug)
fprintf_unfiltered (gdb_stdlog, " -- partial=%d",
partial_len);
if (argreg > MIPS_LAST_ARG_REGNUM
|| odd_sized_struct
|| fp_register_arg_p (typecode, arg_type))
{
int longword_offset = 0;
CORE_ADDR addr;
stack_used_p = 1;
if (TARGET_BYTE_ORDER == BFD_ENDIAN_BIG)
{
if (mips_stack_argsize (gdbarch) == 8
&& (typecode == TYPE_CODE_INT
|| typecode == TYPE_CODE_PTR
|| typecode == TYPE_CODE_FLT) && len <= 4)
longword_offset = mips_stack_argsize (gdbarch) - len;
}
if (mips_debug)
{
fprintf_unfiltered (gdb_stdlog, " - stack_offset=0x%s",
paddr_nz (stack_offset));
fprintf_unfiltered (gdb_stdlog, " longword_offset=0x%s",
paddr_nz (longword_offset));
}
addr = sp + stack_offset + longword_offset;
if (mips_debug)
{
int i;
fprintf_unfiltered (gdb_stdlog, " @0x%s ",
paddr_nz (addr));
for (i = 0; i < partial_len; i++)
{
fprintf_unfiltered (gdb_stdlog, "%02x",
val[i] & 0xff);
}
}
write_memory (addr, val, partial_len);
}
if (argreg <= MIPS_LAST_ARG_REGNUM
&& !fp_register_arg_p (typecode, arg_type))
{
LONGEST regval =
extract_unsigned_integer (val, partial_len);
if (TARGET_BYTE_ORDER == BFD_ENDIAN_BIG
&& partial_len < mips_abi_regsize (gdbarch)
&& (typecode == TYPE_CODE_STRUCT ||
typecode == TYPE_CODE_UNION))
regval <<= ((mips_abi_regsize (gdbarch) - partial_len) *
TARGET_CHAR_BIT);
if (mips_debug)
fprintf_filtered (gdb_stdlog, " - reg=%d val=%s",
argreg,
phex (regval,
mips_abi_regsize (gdbarch)));
write_register (argreg, regval);
argreg++;
}
len -= partial_len;
val += partial_len;
if (stack_used_p)
stack_offset += align_up (partial_len,
mips_stack_argsize (gdbarch));
}
}
if (mips_debug)
fprintf_unfiltered (gdb_stdlog, "\n");
}
regcache_cooked_write_signed (regcache, MIPS_SP_REGNUM, sp);
return sp;
}
static enum return_value_convention
mips_n32n64_return_value (struct gdbarch *gdbarch,
struct type *type, struct regcache *regcache,
gdb_byte *readbuf, const gdb_byte *writebuf)
{
struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
if (TYPE_CODE (type) == TYPE_CODE_STRUCT
|| TYPE_CODE (type) == TYPE_CODE_UNION
|| TYPE_CODE (type) == TYPE_CODE_ARRAY
|| TYPE_LENGTH (type) > 2 * mips_abi_regsize (gdbarch))
return RETURN_VALUE_STRUCT_CONVENTION;
else if (TYPE_CODE (type) == TYPE_CODE_FLT
&& tdep->mips_fpu_type != MIPS_FPU_NONE)
{
if (mips_debug)
fprintf_unfiltered (gdb_stderr, "Return float in $fp0\n");
mips_xfer_register (regcache,
NUM_REGS + mips_regnum (current_gdbarch)->fp0,
TYPE_LENGTH (type),
TARGET_BYTE_ORDER, readbuf, writebuf, 0);
return RETURN_VALUE_REGISTER_CONVENTION;
}
else if (TYPE_CODE (type) == TYPE_CODE_STRUCT
&& TYPE_NFIELDS (type) <= 2
&& TYPE_NFIELDS (type) >= 1
&& ((TYPE_NFIELDS (type) == 1
&& (TYPE_CODE (TYPE_FIELD_TYPE (type, 0))
== TYPE_CODE_FLT))
|| (TYPE_NFIELDS (type) == 2
&& (TYPE_CODE (TYPE_FIELD_TYPE (type, 0))
== TYPE_CODE_FLT)
&& (TYPE_CODE (TYPE_FIELD_TYPE (type, 1))
== TYPE_CODE_FLT)))
&& tdep->mips_fpu_type != MIPS_FPU_NONE)
{
int regnum;
int field;
for (field = 0, regnum = mips_regnum (current_gdbarch)->fp0;
field < TYPE_NFIELDS (type); field++, regnum += 2)
{
int offset = (FIELD_BITPOS (TYPE_FIELDS (type)[field])
/ TARGET_CHAR_BIT);
if (mips_debug)
fprintf_unfiltered (gdb_stderr, "Return float struct+%d\n",
offset);
mips_xfer_register (regcache, NUM_REGS + regnum,
TYPE_LENGTH (TYPE_FIELD_TYPE (type, field)),
TARGET_BYTE_ORDER, readbuf, writebuf, offset);
}
return RETURN_VALUE_REGISTER_CONVENTION;
}
else if (TYPE_CODE (type) == TYPE_CODE_STRUCT
|| TYPE_CODE (type) == TYPE_CODE_UNION)
{
int offset;
int regnum;
for (offset = 0, regnum = MIPS_V0_REGNUM;
offset < TYPE_LENGTH (type);
offset += register_size (current_gdbarch, regnum), regnum++)
{
int xfer = register_size (current_gdbarch, regnum);
if (offset + xfer > TYPE_LENGTH (type))
xfer = TYPE_LENGTH (type) - offset;
if (mips_debug)
fprintf_unfiltered (gdb_stderr, "Return struct+%d:%d in $%d\n",
offset, xfer, regnum);
mips_xfer_register (regcache, NUM_REGS + regnum, xfer,
BFD_ENDIAN_UNKNOWN, readbuf, writebuf, offset);
}
return RETURN_VALUE_REGISTER_CONVENTION;
}
else
{
int offset;
int regnum;
for (offset = 0, regnum = MIPS_V0_REGNUM;
offset < TYPE_LENGTH (type);
offset += register_size (current_gdbarch, regnum), regnum++)
{
int xfer = register_size (current_gdbarch, regnum);
if (offset + xfer > TYPE_LENGTH (type))
xfer = TYPE_LENGTH (type) - offset;
if (mips_debug)
fprintf_unfiltered (gdb_stderr, "Return scalar+%d:%d in $%d\n",
offset, xfer, regnum);
mips_xfer_register (regcache, NUM_REGS + regnum, xfer,
TARGET_BYTE_ORDER, readbuf, writebuf, offset);
}
return RETURN_VALUE_REGISTER_CONVENTION;
}
}
static CORE_ADDR
mips_o32_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
struct regcache *regcache, CORE_ADDR bp_addr,
int nargs, struct value **args, CORE_ADDR sp,
int struct_return, CORE_ADDR struct_addr)
{
int argreg;
int float_argreg;
int argnum;
int len = 0;
int stack_offset = 0;
struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
CORE_ADDR func_addr = find_function_addr (function, NULL);
regcache_cooked_write_signed (regcache, MIPS_T9_REGNUM, func_addr);
regcache_cooked_write_signed (regcache, MIPS_RA_REGNUM, bp_addr);
sp = align_down (sp, 16);
struct_addr = align_down (struct_addr, 16);
for (argnum = 0; argnum < nargs; argnum++)
len += align_up (TYPE_LENGTH (value_type (args[argnum])),
mips_stack_argsize (gdbarch));
sp -= align_up (len, 16);
if (mips_debug)
fprintf_unfiltered (gdb_stdlog,
"mips_o32_push_dummy_call: sp=0x%s allocated %ld\n",
paddr_nz (sp), (long) align_up (len, 16));
argreg = MIPS_A0_REGNUM;
float_argreg = mips_fpa0_regnum (current_gdbarch);
if (struct_return)
{
if (mips_debug)
fprintf_unfiltered (gdb_stdlog,
"mips_o32_push_dummy_call: struct_return reg=%d 0x%s\n",
argreg, paddr_nz (struct_addr));
write_register (argreg++, struct_addr);
stack_offset += mips_stack_argsize (gdbarch);
}
for (argnum = 0; argnum < nargs; argnum++)
{
const gdb_byte *val;
struct value *arg = args[argnum];
struct type *arg_type = check_typedef (value_type (arg));
int len = TYPE_LENGTH (arg_type);
enum type_code typecode = TYPE_CODE (arg_type);
if (mips_debug)
fprintf_unfiltered (gdb_stdlog,
"mips_o32_push_dummy_call: %d len=%d type=%d",
argnum + 1, len, (int) typecode);
val = value_contents (arg);
if (mips_abi_regsize (gdbarch) < 8
&& fp_register_arg_p (typecode, arg_type))
{
if ((float_argreg & 1))
float_argreg++;
}
if (fp_register_arg_p (typecode, arg_type)
&& float_argreg <= MIPS_LAST_FP_ARG_REGNUM)
{
if (mips_abi_regsize (gdbarch) < 8 && len == 8)
{
int low_offset = TARGET_BYTE_ORDER == BFD_ENDIAN_BIG ? 4 : 0;
unsigned long regval;
regval = extract_unsigned_integer (val + low_offset, 4);
if (mips_debug)
fprintf_unfiltered (gdb_stdlog, " - fpreg=%d val=%s",
float_argreg, phex (regval, 4));
write_register (float_argreg++, regval);
if (mips_debug)
fprintf_unfiltered (gdb_stdlog, " - reg=%d val=%s",
argreg, phex (regval, 4));
write_register (argreg++, regval);
regval = extract_unsigned_integer (val + 4 - low_offset, 4);
if (mips_debug)
fprintf_unfiltered (gdb_stdlog, " - fpreg=%d val=%s",
float_argreg, phex (regval, 4));
write_register (float_argreg++, regval);
if (mips_debug)
fprintf_unfiltered (gdb_stdlog, " - reg=%d val=%s",
argreg, phex (regval, 4));
write_register (argreg++, regval);
}
else
{
LONGEST regval = extract_unsigned_integer (val, len);
if (mips_debug)
fprintf_unfiltered (gdb_stdlog, " - fpreg=%d val=%s",
float_argreg, phex (regval, len));
write_register (float_argreg++, regval);
if (mips_debug)
fprintf_unfiltered (gdb_stdlog, " - reg=%d val=%s",
argreg, phex (regval, len));
write_register (argreg, regval);
argreg += (mips_abi_regsize (gdbarch) == 8) ? 1 : 2;
}
stack_offset += align_up (len, mips_stack_argsize (gdbarch));
}
else
{
int odd_sized_struct = ((len > mips_abi_regsize (gdbarch))
&& (len % mips_abi_regsize (gdbarch) != 0));
if (mips_abi_regsize (gdbarch) < 8
&& mips_type_needs_double_align (arg_type))
{
if ((argreg & 1))
argreg++;
}
while (len > 0)
{
int stack_used_p = 0;
int partial_len = (len < mips_abi_regsize (gdbarch)
? len : mips_abi_regsize (gdbarch));
if (mips_debug)
fprintf_unfiltered (gdb_stdlog, " -- partial=%d",
partial_len);
if (argreg > MIPS_LAST_ARG_REGNUM
|| odd_sized_struct
|| fp_register_arg_p (typecode, arg_type))
{
int longword_offset = 0;
CORE_ADDR addr;
stack_used_p = 1;
if (TARGET_BYTE_ORDER == BFD_ENDIAN_BIG)
{
if (mips_stack_argsize (gdbarch) == 8
&& (typecode == TYPE_CODE_INT
|| typecode == TYPE_CODE_PTR
|| typecode == TYPE_CODE_FLT) && len <= 4)
longword_offset = mips_stack_argsize (gdbarch) - len;
}
if (mips_debug)
{
fprintf_unfiltered (gdb_stdlog, " - stack_offset=0x%s",
paddr_nz (stack_offset));
fprintf_unfiltered (gdb_stdlog, " longword_offset=0x%s",
paddr_nz (longword_offset));
}
addr = sp + stack_offset + longword_offset;
if (mips_debug)
{
int i;
fprintf_unfiltered (gdb_stdlog, " @0x%s ",
paddr_nz (addr));
for (i = 0; i < partial_len; i++)
{
fprintf_unfiltered (gdb_stdlog, "%02x",
val[i] & 0xff);
}
}
write_memory (addr, val, partial_len);
}
if (argreg <= MIPS_LAST_ARG_REGNUM
&& !fp_register_arg_p (typecode, arg_type))
{
LONGEST regval = extract_signed_integer (val, partial_len);
if (mips_abi_regsize (gdbarch) < 8
&& TARGET_BYTE_ORDER == BFD_ENDIAN_BIG
&& partial_len < mips_abi_regsize (gdbarch)
&& (typecode == TYPE_CODE_STRUCT ||
typecode == TYPE_CODE_UNION))
regval <<= ((mips_abi_regsize (gdbarch) - partial_len) *
TARGET_CHAR_BIT);
if (mips_debug)
fprintf_filtered (gdb_stdlog, " - reg=%d val=%s",
argreg,
phex (regval,
mips_abi_regsize (gdbarch)));
write_register (argreg, regval);
argreg++;
float_argreg = MIPS_LAST_FP_ARG_REGNUM + 1;
}
len -= partial_len;
val += partial_len;
stack_offset += align_up (partial_len,
mips_stack_argsize (gdbarch));
}
}
if (mips_debug)
fprintf_unfiltered (gdb_stdlog, "\n");
}
regcache_cooked_write_signed (regcache, MIPS_SP_REGNUM, sp);
return sp;
}
static enum return_value_convention
mips_o32_return_value (struct gdbarch *gdbarch, struct type *type,
struct regcache *regcache,
gdb_byte *readbuf, const gdb_byte *writebuf)
{
struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
if (TYPE_CODE (type) == TYPE_CODE_STRUCT
|| TYPE_CODE (type) == TYPE_CODE_UNION
|| TYPE_CODE (type) == TYPE_CODE_ARRAY)
return RETURN_VALUE_STRUCT_CONVENTION;
else if (TYPE_CODE (type) == TYPE_CODE_FLT
&& TYPE_LENGTH (type) == 4 && tdep->mips_fpu_type != MIPS_FPU_NONE)
{
if (mips_debug)
fprintf_unfiltered (gdb_stderr, "Return float in $fp0\n");
mips_xfer_register (regcache,
NUM_REGS + mips_regnum (current_gdbarch)->fp0,
TYPE_LENGTH (type),
TARGET_BYTE_ORDER, readbuf, writebuf, 0);
return RETURN_VALUE_REGISTER_CONVENTION;
}
else if (TYPE_CODE (type) == TYPE_CODE_FLT
&& TYPE_LENGTH (type) == 8 && tdep->mips_fpu_type != MIPS_FPU_NONE)
{
if (mips_debug)
fprintf_unfiltered (gdb_stderr, "Return float in $fp1/$fp0\n");
switch (TARGET_BYTE_ORDER)
{
case BFD_ENDIAN_LITTLE:
mips_xfer_register (regcache,
NUM_REGS + mips_regnum (current_gdbarch)->fp0 +
0, 4, TARGET_BYTE_ORDER, readbuf, writebuf, 0);
mips_xfer_register (regcache,
NUM_REGS + mips_regnum (current_gdbarch)->fp0 +
1, 4, TARGET_BYTE_ORDER, readbuf, writebuf, 4);
break;
case BFD_ENDIAN_BIG:
mips_xfer_register (regcache,
NUM_REGS + mips_regnum (current_gdbarch)->fp0 +
1, 4, TARGET_BYTE_ORDER, readbuf, writebuf, 0);
mips_xfer_register (regcache,
NUM_REGS + mips_regnum (current_gdbarch)->fp0 +
0, 4, TARGET_BYTE_ORDER, readbuf, writebuf, 4);
break;
default:
internal_error (__FILE__, __LINE__, _("bad switch"));
}
return RETURN_VALUE_REGISTER_CONVENTION;
}
#if 0
else if (TYPE_CODE (type) == TYPE_CODE_STRUCT
&& TYPE_NFIELDS (type) <= 2
&& TYPE_NFIELDS (type) >= 1
&& ((TYPE_NFIELDS (type) == 1
&& (TYPE_CODE (TYPE_FIELD_TYPE (type, 0))
== TYPE_CODE_FLT))
|| (TYPE_NFIELDS (type) == 2
&& (TYPE_CODE (TYPE_FIELD_TYPE (type, 0))
== TYPE_CODE_FLT)
&& (TYPE_CODE (TYPE_FIELD_TYPE (type, 1))
== TYPE_CODE_FLT)))
&& tdep->mips_fpu_type != MIPS_FPU_NONE)
{
gdb_byte reg[MAX_REGISTER_SIZE];
int regnum;
int field;
for (field = 0, regnum = mips_regnum (current_gdbarch)->fp0;
field < TYPE_NFIELDS (type); field++, regnum += 2)
{
int offset = (FIELD_BITPOS (TYPE_FIELDS (type)[field])
/ TARGET_CHAR_BIT);
if (mips_debug)
fprintf_unfiltered (gdb_stderr, "Return float struct+%d\n",
offset);
mips_xfer_register (regcache, NUM_REGS + regnum,
TYPE_LENGTH (TYPE_FIELD_TYPE (type, field)),
TARGET_BYTE_ORDER, readbuf, writebuf, offset);
}
return RETURN_VALUE_REGISTER_CONVENTION;
}
#endif
#if 0
else if (TYPE_CODE (type) == TYPE_CODE_STRUCT
|| TYPE_CODE (type) == TYPE_CODE_UNION)
{
int offset;
int regnum;
for (offset = 0, regnum = MIPS_V0_REGNUM;
offset < TYPE_LENGTH (type);
offset += register_size (current_gdbarch, regnum), regnum++)
{
int xfer = register_size (current_gdbarch, regnum);
if (offset + xfer > TYPE_LENGTH (type))
xfer = TYPE_LENGTH (type) - offset;
if (mips_debug)
fprintf_unfiltered (gdb_stderr, "Return struct+%d:%d in $%d\n",
offset, xfer, regnum);
mips_xfer_register (regcache, NUM_REGS + regnum, xfer,
BFD_ENDIAN_UNKNOWN, readbuf, writebuf, offset);
}
return RETURN_VALUE_REGISTER_CONVENTION;
}
#endif
else
{
int offset;
int regnum;
for (offset = 0, regnum = MIPS_V0_REGNUM;
offset < TYPE_LENGTH (type);
offset += mips_stack_argsize (gdbarch), regnum++)
{
int xfer = mips_stack_argsize (gdbarch);
if (offset + xfer > TYPE_LENGTH (type))
xfer = TYPE_LENGTH (type) - offset;
if (mips_debug)
fprintf_unfiltered (gdb_stderr, "Return scalar+%d:%d in $%d\n",
offset, xfer, regnum);
mips_xfer_register (regcache, NUM_REGS + regnum, xfer,
TARGET_BYTE_ORDER, readbuf, writebuf, offset);
}
return RETURN_VALUE_REGISTER_CONVENTION;
}
}
static CORE_ADDR
mips_o64_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
struct regcache *regcache, CORE_ADDR bp_addr,
int nargs,
struct value **args, CORE_ADDR sp,
int struct_return, CORE_ADDR struct_addr)
{
int argreg;
int float_argreg;
int argnum;
int len = 0;
int stack_offset = 0;
struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
CORE_ADDR func_addr = find_function_addr (function, NULL);
regcache_cooked_write_signed (regcache, MIPS_T9_REGNUM, func_addr);
regcache_cooked_write_signed (regcache, MIPS_RA_REGNUM, bp_addr);
sp = align_down (sp, 16);
struct_addr = align_down (struct_addr, 16);
for (argnum = 0; argnum < nargs; argnum++)
len += align_up (TYPE_LENGTH (value_type (args[argnum])),
mips_stack_argsize (gdbarch));
sp -= align_up (len, 16);
if (mips_debug)
fprintf_unfiltered (gdb_stdlog,
"mips_o64_push_dummy_call: sp=0x%s allocated %ld\n",
paddr_nz (sp), (long) align_up (len, 16));
argreg = MIPS_A0_REGNUM;
float_argreg = mips_fpa0_regnum (current_gdbarch);
if (struct_return)
{
if (mips_debug)
fprintf_unfiltered (gdb_stdlog,
"mips_o64_push_dummy_call: struct_return reg=%d 0x%s\n",
argreg, paddr_nz (struct_addr));
write_register (argreg++, struct_addr);
stack_offset += mips_stack_argsize (gdbarch);
}
for (argnum = 0; argnum < nargs; argnum++)
{
const gdb_byte *val;
struct value *arg = args[argnum];
struct type *arg_type = check_typedef (value_type (arg));
int len = TYPE_LENGTH (arg_type);
enum type_code typecode = TYPE_CODE (arg_type);
if (mips_debug)
fprintf_unfiltered (gdb_stdlog,
"mips_o64_push_dummy_call: %d len=%d type=%d",
argnum + 1, len, (int) typecode);
val = value_contents (arg);
if (mips_abi_regsize (gdbarch) < 8
&& fp_register_arg_p (typecode, arg_type))
{
if ((float_argreg & 1))
float_argreg++;
}
if (fp_register_arg_p (typecode, arg_type)
&& float_argreg <= MIPS_LAST_FP_ARG_REGNUM)
{
if (mips_abi_regsize (gdbarch) < 8 && len == 8)
{
int low_offset = TARGET_BYTE_ORDER == BFD_ENDIAN_BIG ? 4 : 0;
unsigned long regval;
regval = extract_unsigned_integer (val + low_offset, 4);
if (mips_debug)
fprintf_unfiltered (gdb_stdlog, " - fpreg=%d val=%s",
float_argreg, phex (regval, 4));
write_register (float_argreg++, regval);
if (mips_debug)
fprintf_unfiltered (gdb_stdlog, " - reg=%d val=%s",
argreg, phex (regval, 4));
write_register (argreg++, regval);
regval = extract_unsigned_integer (val + 4 - low_offset, 4);
if (mips_debug)
fprintf_unfiltered (gdb_stdlog, " - fpreg=%d val=%s",
float_argreg, phex (regval, 4));
write_register (float_argreg++, regval);
if (mips_debug)
fprintf_unfiltered (gdb_stdlog, " - reg=%d val=%s",
argreg, phex (regval, 4));
write_register (argreg++, regval);
}
else
{
LONGEST regval = extract_unsigned_integer (val, len);
if (mips_debug)
fprintf_unfiltered (gdb_stdlog, " - fpreg=%d val=%s",
float_argreg, phex (regval, len));
write_register (float_argreg++, regval);
if (mips_debug)
fprintf_unfiltered (gdb_stdlog, " - reg=%d val=%s",
argreg, phex (regval, len));
write_register (argreg, regval);
argreg += (mips_abi_regsize (gdbarch) == 8) ? 1 : 2;
}
stack_offset += align_up (len, mips_stack_argsize (gdbarch));
}
else
{
int odd_sized_struct = ((len > mips_abi_regsize (gdbarch))
&& (len % mips_abi_regsize (gdbarch) != 0));
if (mips_abi_regsize (gdbarch) < 8
&& mips_type_needs_double_align (arg_type))
{
if ((argreg & 1))
argreg++;
}
while (len > 0)
{
int stack_used_p = 0;
int partial_len = (len < mips_abi_regsize (gdbarch)
? len : mips_abi_regsize (gdbarch));
if (mips_debug)
fprintf_unfiltered (gdb_stdlog, " -- partial=%d",
partial_len);
if (argreg > MIPS_LAST_ARG_REGNUM
|| odd_sized_struct
|| fp_register_arg_p (typecode, arg_type))
{
int longword_offset = 0;
CORE_ADDR addr;
stack_used_p = 1;
if (TARGET_BYTE_ORDER == BFD_ENDIAN_BIG)
{
if (mips_stack_argsize (gdbarch) == 8
&& (typecode == TYPE_CODE_INT
|| typecode == TYPE_CODE_PTR
|| typecode == TYPE_CODE_FLT) && len <= 4)
longword_offset = mips_stack_argsize (gdbarch) - len;
}
if (mips_debug)
{
fprintf_unfiltered (gdb_stdlog, " - stack_offset=0x%s",
paddr_nz (stack_offset));
fprintf_unfiltered (gdb_stdlog, " longword_offset=0x%s",
paddr_nz (longword_offset));
}
addr = sp + stack_offset + longword_offset;
if (mips_debug)
{
int i;
fprintf_unfiltered (gdb_stdlog, " @0x%s ",
paddr_nz (addr));
for (i = 0; i < partial_len; i++)
{
fprintf_unfiltered (gdb_stdlog, "%02x",
val[i] & 0xff);
}
}
write_memory (addr, val, partial_len);
}
if (argreg <= MIPS_LAST_ARG_REGNUM
&& !fp_register_arg_p (typecode, arg_type))
{
LONGEST regval = extract_signed_integer (val, partial_len);
if (mips_abi_regsize (gdbarch) < 8
&& TARGET_BYTE_ORDER == BFD_ENDIAN_BIG
&& partial_len < mips_abi_regsize (gdbarch)
&& (typecode == TYPE_CODE_STRUCT ||
typecode == TYPE_CODE_UNION))
regval <<= ((mips_abi_regsize (gdbarch) - partial_len) *
TARGET_CHAR_BIT);
if (mips_debug)
fprintf_filtered (gdb_stdlog, " - reg=%d val=%s",
argreg,
phex (regval,
mips_abi_regsize (gdbarch)));
write_register (argreg, regval);
argreg++;
float_argreg = MIPS_LAST_FP_ARG_REGNUM + 1;
}
len -= partial_len;
val += partial_len;
stack_offset += align_up (partial_len,
mips_stack_argsize (gdbarch));
}
}
if (mips_debug)
fprintf_unfiltered (gdb_stdlog, "\n");
}
regcache_cooked_write_signed (regcache, MIPS_SP_REGNUM, sp);
return sp;
}
static enum return_value_convention
mips_o64_return_value (struct gdbarch *gdbarch,
struct type *type, struct regcache *regcache,
gdb_byte *readbuf, const gdb_byte *writebuf)
{
return RETURN_VALUE_STRUCT_CONVENTION;
}
static struct type *
mips_float_register_type (void)
{
if (TARGET_BYTE_ORDER == BFD_ENDIAN_BIG)
return builtin_type_ieee_single_big;
else
return builtin_type_ieee_single_little;
}
static struct type *
mips_double_register_type (void)
{
if (TARGET_BYTE_ORDER == BFD_ENDIAN_BIG)
return builtin_type_ieee_double_big;
else
return builtin_type_ieee_double_little;
}
static void
mips_read_fp_register_single (struct frame_info *frame, int regno,
gdb_byte *rare_buffer)
{
int raw_size = register_size (current_gdbarch, regno);
gdb_byte *raw_buffer = alloca (raw_size);
if (!frame_register_read (frame, regno, raw_buffer))
error (_("can't read register %d (%s)"), regno, REGISTER_NAME (regno));
if (raw_size == 8)
{
int offset;
if (TARGET_BYTE_ORDER == BFD_ENDIAN_BIG)
offset = 4;
else
offset = 0;
memcpy (rare_buffer, raw_buffer + offset, 4);
}
else
{
memcpy (rare_buffer, raw_buffer, 4);
}
}
static void
mips_read_fp_register_double (struct frame_info *frame, int regno,
gdb_byte *rare_buffer)
{
int raw_size = register_size (current_gdbarch, regno);
if (raw_size == 8 && !mips2_fp_compat ())
{
if (!frame_register_read (frame, regno, rare_buffer))
error (_("can't read register %d (%s)"), regno, REGISTER_NAME (regno));
}
else
{
if ((regno - mips_regnum (current_gdbarch)->fp0) & 1)
internal_error (__FILE__, __LINE__,
_("mips_read_fp_register_double: bad access to "
"odd-numbered FP register"));
if (TARGET_BYTE_ORDER == BFD_ENDIAN_BIG)
{
mips_read_fp_register_single (frame, regno, rare_buffer + 4);
mips_read_fp_register_single (frame, regno + 1, rare_buffer);
}
else
{
mips_read_fp_register_single (frame, regno, rare_buffer);
mips_read_fp_register_single (frame, regno + 1, rare_buffer + 4);
}
}
}
static void
mips_print_fp_register (struct ui_file *file, struct frame_info *frame,
int regnum)
{
gdb_byte *raw_buffer;
double doub, flt1;
int inv1, inv2;
raw_buffer = alloca (2 * register_size (current_gdbarch,
mips_regnum (current_gdbarch)->fp0));
fprintf_filtered (file, "%s:", REGISTER_NAME (regnum));
fprintf_filtered (file, "%*s", 4 - (int) strlen (REGISTER_NAME (regnum)),
"");
if (register_size (current_gdbarch, regnum) == 4 || mips2_fp_compat ())
{
mips_read_fp_register_single (frame, regnum, raw_buffer);
flt1 = unpack_double (mips_float_register_type (), raw_buffer, &inv1);
print_scalar_formatted (raw_buffer, builtin_type_uint32, 'x', 'w',
file);
fprintf_filtered (file, " flt: ");
if (inv1)
fprintf_filtered (file, " <invalid float> ");
else
fprintf_filtered (file, "%-17.9g", flt1);
if (regnum % 2 == 0)
{
mips_read_fp_register_double (frame, regnum, raw_buffer);
doub = unpack_double (mips_double_register_type (), raw_buffer,
&inv2);
fprintf_filtered (file, " dbl: ");
if (inv2)
fprintf_filtered (file, "<invalid double>");
else
fprintf_filtered (file, "%-24.17g", doub);
}
}
else
{
mips_read_fp_register_single (frame, regnum, raw_buffer);
flt1 = unpack_double (mips_float_register_type (), raw_buffer, &inv1);
mips_read_fp_register_double (frame, regnum, raw_buffer);
doub = unpack_double (mips_double_register_type (), raw_buffer, &inv2);
print_scalar_formatted (raw_buffer, builtin_type_uint64, 'x', 'g',
file);
fprintf_filtered (file, " flt: ");
if (inv1)
fprintf_filtered (file, "<invalid float>");
else
fprintf_filtered (file, "%-17.9g", flt1);
fprintf_filtered (file, " dbl: ");
if (inv2)
fprintf_filtered (file, "<invalid double>");
else
fprintf_filtered (file, "%-24.17g", doub);
}
}
static void
mips_print_register (struct ui_file *file, struct frame_info *frame,
int regnum, int all)
{
struct gdbarch *gdbarch = get_frame_arch (frame);
gdb_byte raw_buffer[MAX_REGISTER_SIZE];
int offset;
if (TYPE_CODE (gdbarch_register_type (gdbarch, regnum)) == TYPE_CODE_FLT)
{
mips_print_fp_register (file, frame, regnum);
return;
}
if (!frame_register_read (frame, regnum, raw_buffer))
{
fprintf_filtered (file, "%s: [Invalid]", REGISTER_NAME (regnum));
return;
}
fputs_filtered (REGISTER_NAME (regnum), file);
if (regnum < MIPS_NUMREGS)
fprintf_filtered (file, "(r%d): ", regnum);
else
fprintf_filtered (file, ": ");
if (TARGET_BYTE_ORDER == BFD_ENDIAN_BIG)
offset =
register_size (current_gdbarch,
regnum) - register_size (current_gdbarch, regnum);
else
offset = 0;
print_scalar_formatted (raw_buffer + offset,
gdbarch_register_type (gdbarch, regnum), 'x', 0,
file);
}
static int
print_fp_register_row (struct ui_file *file, struct frame_info *frame,
int regnum)
{
fprintf_filtered (file, " ");
mips_print_fp_register (file, frame, regnum);
fprintf_filtered (file, "\n");
return regnum + 1;
}
static int
print_gp_register_row (struct ui_file *file, struct frame_info *frame,
int start_regnum)
{
struct gdbarch *gdbarch = get_frame_arch (frame);
gdb_byte raw_buffer[MAX_REGISTER_SIZE];
int ncols = (mips_abi_regsize (gdbarch) == 8 ? 4 : 8);
int col, byte;
int regnum;
fprintf_filtered (file, " ");
for (col = 0, regnum = start_regnum;
col < ncols && regnum < NUM_REGS + NUM_PSEUDO_REGS; regnum++)
{
if (*REGISTER_NAME (regnum) == '\0')
continue;
if (TYPE_CODE (gdbarch_register_type (gdbarch, regnum)) ==
TYPE_CODE_FLT)
break;
fprintf_filtered (file,
mips_abi_regsize (current_gdbarch) == 8 ? "%17s" : "%9s",
REGISTER_NAME (regnum));
col++;
}
if ((start_regnum % NUM_REGS) < MIPS_NUMREGS)
fprintf_filtered (file, "\n R%-4d", start_regnum % NUM_REGS);
else
fprintf_filtered (file, "\n ");
for (col = 0, regnum = start_regnum;
col < ncols && regnum < NUM_REGS + NUM_PSEUDO_REGS; regnum++)
{
if (*REGISTER_NAME (regnum) == '\0')
continue;
if (TYPE_CODE (gdbarch_register_type (gdbarch, regnum)) ==
TYPE_CODE_FLT)
break;
if (!frame_register_read (frame, regnum, raw_buffer))
error (_("can't read register %d (%s)"), regnum, REGISTER_NAME (regnum));
for (byte = 0;
byte < (mips_abi_regsize (current_gdbarch)
- register_size (current_gdbarch, regnum)); byte++)
printf_filtered (" ");
if (TARGET_BYTE_ORDER == BFD_ENDIAN_BIG)
for (byte =
register_size (current_gdbarch,
regnum) - register_size (current_gdbarch, regnum);
byte < register_size (current_gdbarch, regnum); byte++)
fprintf_filtered (file, "%02x", raw_buffer[byte]);
else
for (byte = register_size (current_gdbarch, regnum) - 1;
byte >= 0; byte--)
fprintf_filtered (file, "%02x", raw_buffer[byte]);
fprintf_filtered (file, " ");
col++;
}
if (col > 0)
fprintf_filtered (file, "\n");
return regnum;
}
static void
mips_print_registers_info (struct gdbarch *gdbarch, struct ui_file *file,
struct frame_info *frame, int regnum, int all)
{
if (regnum != -1)
{
gdb_assert (regnum >= NUM_REGS);
if (*(REGISTER_NAME (regnum)) == '\0')
error (_("Not a valid register for the current processor type"));
mips_print_register (file, frame, regnum, 0);
fprintf_filtered (file, "\n");
}
else
{
regnum = NUM_REGS;
while (regnum < NUM_REGS + NUM_PSEUDO_REGS)
{
if (TYPE_CODE (gdbarch_register_type (gdbarch, regnum)) ==
TYPE_CODE_FLT)
{
if (all)
regnum = print_fp_register_row (file, frame, regnum);
else
regnum += MIPS_NUMREGS;
}
else
regnum = print_gp_register_row (file, frame, regnum);
}
}
}
static int
is_delayed (unsigned long insn)
{
int i;
for (i = 0; i < NUMOPCODES; ++i)
if (mips_opcodes[i].pinfo != INSN_MACRO
&& (insn & mips_opcodes[i].mask) == mips_opcodes[i].match)
break;
return (i < NUMOPCODES
&& (mips_opcodes[i].pinfo & (INSN_UNCOND_BRANCH_DELAY
| INSN_COND_BRANCH_DELAY
| INSN_COND_BRANCH_LIKELY)));
}
int
mips_single_step_through_delay (struct gdbarch *gdbarch,
struct frame_info *frame)
{
CORE_ADDR pc = get_frame_pc (frame);
gdb_byte buf[MIPS_INSN32_SIZE];
if (mips_pc_is_mips16 (pc))
return 0;
if (!breakpoint_here_p (pc + 4))
return 0;
if (!safe_frame_unwind_memory (frame, pc, buf, sizeof buf))
return 0;
return is_delayed (extract_unsigned_integer (buf, sizeof buf));
}
static CORE_ADDR
mips_skip_prologue (CORE_ADDR pc)
{
CORE_ADDR limit_pc;
CORE_ADDR func_addr;
if (find_pc_partial_function (pc, NULL, &func_addr, NULL))
{
CORE_ADDR post_prologue_pc = skip_prologue_using_sal (func_addr);
if (post_prologue_pc != 0)
return max (pc, post_prologue_pc);
}
limit_pc = skip_prologue_using_sal (pc);
if (limit_pc == 0)
limit_pc = pc + 100;
if (mips_pc_is_mips16 (pc))
return mips16_scan_prologue (pc, limit_pc, NULL, NULL);
else
return mips32_scan_prologue (pc, limit_pc, NULL, NULL);
}
static void
show_mips_command (char *args, int from_tty)
{
help_list (showmipscmdlist, "show mips ", all_commands, gdb_stdout);
}
static void
set_mips_command (char *args, int from_tty)
{
printf_unfiltered
("\"set mips\" must be followed by an appropriate subcommand.\n");
help_list (setmipscmdlist, "set mips ", all_commands, gdb_stdout);
}
static void
show_mipsfpu_command (char *args, int from_tty)
{
char *fpu;
switch (MIPS_FPU_TYPE)
{
case MIPS_FPU_SINGLE:
fpu = "single-precision";
break;
case MIPS_FPU_DOUBLE:
fpu = "double-precision";
break;
case MIPS_FPU_NONE:
fpu = "absent (none)";
break;
default:
internal_error (__FILE__, __LINE__, _("bad switch"));
}
if (mips_fpu_type_auto)
printf_unfiltered
("The MIPS floating-point coprocessor is set automatically (currently %s)\n",
fpu);
else
printf_unfiltered
("The MIPS floating-point coprocessor is assumed to be %s\n", fpu);
}
static void
set_mipsfpu_command (char *args, int from_tty)
{
printf_unfiltered
("\"set mipsfpu\" must be followed by \"double\", \"single\",\"none\" or \"auto\".\n");
show_mipsfpu_command (args, from_tty);
}
static void
set_mipsfpu_single_command (char *args, int from_tty)
{
struct gdbarch_info info;
gdbarch_info_init (&info);
mips_fpu_type = MIPS_FPU_SINGLE;
mips_fpu_type_auto = 0;
if (!gdbarch_update_p (info))
internal_error (__FILE__, __LINE__, _("set mipsfpu failed"));
}
static void
set_mipsfpu_double_command (char *args, int from_tty)
{
struct gdbarch_info info;
gdbarch_info_init (&info);
mips_fpu_type = MIPS_FPU_DOUBLE;
mips_fpu_type_auto = 0;
if (!gdbarch_update_p (info))
internal_error (__FILE__, __LINE__, _("set mipsfpu failed"));
}
static void
set_mipsfpu_none_command (char *args, int from_tty)
{
struct gdbarch_info info;
gdbarch_info_init (&info);
mips_fpu_type = MIPS_FPU_NONE;
mips_fpu_type_auto = 0;
if (!gdbarch_update_p (info))
internal_error (__FILE__, __LINE__, _("set mipsfpu failed"));
}
static void
set_mipsfpu_auto_command (char *args, int from_tty)
{
mips_fpu_type_auto = 1;
}
void
deprecated_mips_set_processor_regs_hack (void)
{
struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
CORE_ADDR prid;
prid = read_register (MIPS_PRID_REGNUM);
if ((prid & ~0xf) == 0x700)
tdep->mips_processor_reg_names = mips_r3041_reg_names;
}
static void
reinit_frame_cache_sfunc (char *args, int from_tty,
struct cmd_list_element *c)
{
reinit_frame_cache ();
}
static int
gdb_print_insn_mips (bfd_vma memaddr, struct disassemble_info *info)
{
struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
if (mips_pc_is_mips16 (memaddr))
info->mach = bfd_mach_mips16;
memaddr &= (info->mach == bfd_mach_mips16 ? ~1 : ~3);
if (tdep->mips_abi == MIPS_ABI_N32 || tdep->mips_abi == MIPS_ABI_N64)
{
if (tdep->mips_abi == MIPS_ABI_N32)
info->disassembler_options = "gpr-names=n32";
else
info->disassembler_options = "gpr-names=64";
info->flavour = bfd_target_elf_flavour;
}
else
info->disassembler_options = "gpr-names=32";
if (TARGET_BYTE_ORDER == BFD_ENDIAN_BIG)
return print_insn_big_mips (memaddr, info);
else
return print_insn_little_mips (memaddr, info);
}
static const gdb_byte *
mips_breakpoint_from_pc (CORE_ADDR *pcptr, int *lenptr)
{
if (TARGET_BYTE_ORDER == BFD_ENDIAN_BIG)
{
if (mips_pc_is_mips16 (*pcptr))
{
static gdb_byte mips16_big_breakpoint[] = { 0xe8, 0xa5 };
*pcptr = unmake_mips16_addr (*pcptr);
*lenptr = sizeof (mips16_big_breakpoint);
return mips16_big_breakpoint;
}
else
{
static gdb_byte big_breakpoint[] = { 0, 0x5, 0, 0xd };
static gdb_byte pmon_big_breakpoint[] = { 0, 0, 0, 0xd };
static gdb_byte idt_big_breakpoint[] = { 0, 0, 0x0a, 0xd };
*lenptr = sizeof (big_breakpoint);
if (strcmp (target_shortname, "mips") == 0)
return idt_big_breakpoint;
else if (strcmp (target_shortname, "ddb") == 0
|| strcmp (target_shortname, "pmon") == 0
|| strcmp (target_shortname, "lsi") == 0)
return pmon_big_breakpoint;
else
return big_breakpoint;
}
}
else
{
if (mips_pc_is_mips16 (*pcptr))
{
static gdb_byte mips16_little_breakpoint[] = { 0xa5, 0xe8 };
*pcptr = unmake_mips16_addr (*pcptr);
*lenptr = sizeof (mips16_little_breakpoint);
return mips16_little_breakpoint;
}
else
{
static gdb_byte little_breakpoint[] = { 0xd, 0, 0x5, 0 };
static gdb_byte pmon_little_breakpoint[] = { 0xd, 0, 0, 0 };
static gdb_byte idt_little_breakpoint[] = { 0xd, 0x0a, 0, 0 };
*lenptr = sizeof (little_breakpoint);
if (strcmp (target_shortname, "mips") == 0)
return idt_little_breakpoint;
else if (strcmp (target_shortname, "ddb") == 0
|| strcmp (target_shortname, "pmon") == 0
|| strcmp (target_shortname, "lsi") == 0)
return pmon_little_breakpoint;
else
return little_breakpoint;
}
}
}
static CORE_ADDR
mips_skip_trampoline_code (CORE_ADDR pc)
{
char *name;
CORE_ADDR start_addr;
if (find_pc_partial_function (pc, &name, &start_addr, NULL) == 0)
return 0;
if (strcmp (name, "__mips16_ret_sf") == 0
|| strcmp (name, "__mips16_ret_df") == 0)
return read_signed_register (MIPS_RA_REGNUM);
if (strncmp (name, "__mips16_call_stub_", 19) == 0)
{
if (name[19] >= '0' && name[19] <= '9')
return read_signed_register (2);
else if (name[19] == 's' || name[19] == 'd')
{
if (pc == start_addr)
{
CORE_ADDR target_pc = read_signed_register (2);
ULONGEST inst;
int i;
if (find_pc_partial_function (target_pc, &name, NULL, NULL) ==
0)
return target_pc;
if (strncmp (name, "__fn_stub_", 10) != 0
&& strcmp (name, "etext") != 0
&& strcmp (name, "_etext") != 0)
return target_pc;
for (i = 0, pc = 0; i < 20; i++, target_pc += MIPS_INSN32_SIZE)
{
inst = mips_fetch_instruction (target_pc);
if ((inst & 0xffff0000) == 0x3c010000)
pc = (inst << 16) & 0xffff0000;
else if ((inst & 0xffff0000) == 0x24210000)
return pc | (inst & 0xffff);
}
return target_pc;
}
else
return read_signed_register (18);
}
}
return 0;
}
static int
mips_stab_reg_to_regnum (int num)
{
int regnum;
if (num >= 0 && num < 32)
regnum = num;
else if (num >= 38 && num < 70)
regnum = num + mips_regnum (current_gdbarch)->fp0 - 38;
else if (num == 70)
regnum = mips_regnum (current_gdbarch)->hi;
else if (num == 71)
regnum = mips_regnum (current_gdbarch)->lo;
else
return NUM_REGS + NUM_PSEUDO_REGS;
return NUM_REGS + regnum;
}
static int
mips_dwarf_dwarf2_ecoff_reg_to_regnum (int num)
{
int regnum;
if (num >= 0 && num < 32)
regnum = num;
else if (num >= 32 && num < 64)
regnum = num + mips_regnum (current_gdbarch)->fp0 - 32;
else if (num == 64)
regnum = mips_regnum (current_gdbarch)->hi;
else if (num == 65)
regnum = mips_regnum (current_gdbarch)->lo;
else
return NUM_REGS + NUM_PSEUDO_REGS;
return NUM_REGS + regnum;
}
static int
mips_register_sim_regno (int regnum)
{
gdb_assert (regnum >= 0 && regnum < NUM_REGS);
if (REGISTER_NAME (NUM_REGS + regnum) != NULL
&& REGISTER_NAME (NUM_REGS + regnum)[0] != '\0')
return regnum;
else
return LEGACY_SIM_REGNO_IGNORE;
}
static CORE_ADDR
mips_integer_to_address (struct gdbarch *gdbarch,
struct type *type, const gdb_byte *buf)
{
gdb_byte *tmp = alloca (TYPE_LENGTH (builtin_type_void_data_ptr));
LONGEST val = unpack_long (type, buf);
store_signed_integer (tmp, TYPE_LENGTH (builtin_type_void_data_ptr), val);
return extract_signed_integer (tmp,
TYPE_LENGTH (builtin_type_void_data_ptr));
}
static void
mips_find_abi_section (bfd *abfd, asection *sect, void *obj)
{
enum mips_abi *abip = (enum mips_abi *) obj;
const char *name = bfd_get_section_name (abfd, sect);
if (*abip != MIPS_ABI_UNKNOWN)
return;
if (strncmp (name, ".mdebug.", 8) != 0)
return;
if (strcmp (name, ".mdebug.abi32") == 0)
*abip = MIPS_ABI_O32;
else if (strcmp (name, ".mdebug.abiN32") == 0)
*abip = MIPS_ABI_N32;
else if (strcmp (name, ".mdebug.abi64") == 0)
*abip = MIPS_ABI_N64;
else if (strcmp (name, ".mdebug.abiO64") == 0)
*abip = MIPS_ABI_O64;
else if (strcmp (name, ".mdebug.eabi32") == 0)
*abip = MIPS_ABI_EABI32;
else if (strcmp (name, ".mdebug.eabi64") == 0)
*abip = MIPS_ABI_EABI64;
else
warning (_("unsupported ABI %s."), name + 8);
}
static enum mips_abi
global_mips_abi (void)
{
int i;
for (i = 0; mips_abi_strings[i] != NULL; i++)
if (mips_abi_strings[i] == mips_abi_string)
return (enum mips_abi) i;
internal_error (__FILE__, __LINE__, _("unknown ABI string"));
}
static struct gdbarch *
mips_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
{
struct gdbarch *gdbarch;
struct gdbarch_tdep *tdep;
int elf_flags;
enum mips_abi mips_abi, found_abi, wanted_abi;
int num_regs;
enum mips_fpu_type fpu_type;
if (info.abfd && bfd_get_flavour (info.abfd) == bfd_target_elf_flavour)
elf_flags = elf_elfheader (info.abfd)->e_flags;
else if (arches != NULL)
elf_flags = gdbarch_tdep (arches->gdbarch)->elf_flags;
else
elf_flags = 0;
if (gdbarch_debug)
fprintf_unfiltered (gdb_stdlog,
"mips_gdbarch_init: elf_flags = 0x%08x\n", elf_flags);
switch ((elf_flags & EF_MIPS_ABI))
{
case E_MIPS_ABI_O32:
found_abi = MIPS_ABI_O32;
break;
case E_MIPS_ABI_O64:
found_abi = MIPS_ABI_O64;
break;
case E_MIPS_ABI_EABI32:
found_abi = MIPS_ABI_EABI32;
break;
case E_MIPS_ABI_EABI64:
found_abi = MIPS_ABI_EABI64;
break;
default:
if ((elf_flags & EF_MIPS_ABI2))
found_abi = MIPS_ABI_N32;
else
found_abi = MIPS_ABI_UNKNOWN;
break;
}
if (found_abi == MIPS_ABI_UNKNOWN && info.abfd != NULL)
bfd_map_over_sections (info.abfd, mips_find_abi_section, &found_abi);
if (found_abi == MIPS_ABI_UNKNOWN && info.abfd == NULL && arches != NULL)
found_abi = gdbarch_tdep (arches->gdbarch)->found_abi;
if (found_abi == MIPS_ABI_UNKNOWN
&& info.bfd_arch_info != NULL
&& info.bfd_arch_info->arch == bfd_arch_mips)
{
switch (info.bfd_arch_info->mach)
{
case bfd_mach_mips3900:
found_abi = MIPS_ABI_EABI32;
break;
case bfd_mach_mips4100:
case bfd_mach_mips5000:
found_abi = MIPS_ABI_EABI64;
break;
case bfd_mach_mips8000:
case bfd_mach_mips10000:
if (bfd_get_flavour (info.abfd) == bfd_target_elf_flavour
&& elf_elfheader (info.abfd)->e_ident[EI_CLASS] == ELFCLASS64)
found_abi = MIPS_ABI_N64;
else
found_abi = MIPS_ABI_N32;
break;
}
}
if (gdbarch_debug)
fprintf_unfiltered (gdb_stdlog, "mips_gdbarch_init: found_abi = %d\n",
found_abi);
wanted_abi = global_mips_abi ();
if (gdbarch_debug)
fprintf_unfiltered (gdb_stdlog, "mips_gdbarch_init: wanted_abi = %d\n",
wanted_abi);
if (wanted_abi != MIPS_ABI_UNKNOWN)
mips_abi = wanted_abi;
else if (found_abi != MIPS_ABI_UNKNOWN)
mips_abi = found_abi;
else
mips_abi = MIPS_ABI_O32;
if (gdbarch_debug)
fprintf_unfiltered (gdb_stdlog, "mips_gdbarch_init: mips_abi = %d\n",
mips_abi);
if (gdbarch_debug)
fprintf_unfiltered (gdb_stdlog,
"mips_gdbarch_init: mips64_transfers_32bit_regs_p = %d\n",
mips64_transfers_32bit_regs_p);
if (!mips_fpu_type_auto)
fpu_type = mips_fpu_type;
else if (info.bfd_arch_info != NULL
&& info.bfd_arch_info->arch == bfd_arch_mips)
switch (info.bfd_arch_info->mach)
{
case bfd_mach_mips3900:
case bfd_mach_mips4100:
case bfd_mach_mips4111:
case bfd_mach_mips4120:
fpu_type = MIPS_FPU_NONE;
break;
case bfd_mach_mips4650:
fpu_type = MIPS_FPU_SINGLE;
break;
default:
fpu_type = MIPS_FPU_DOUBLE;
break;
}
else if (arches != NULL)
fpu_type = gdbarch_tdep (arches->gdbarch)->mips_fpu_type;
else
fpu_type = MIPS_FPU_DOUBLE;
if (gdbarch_debug)
fprintf_unfiltered (gdb_stdlog,
"mips_gdbarch_init: fpu_type = %d\n", fpu_type);
for (arches = gdbarch_list_lookup_by_info (arches, &info);
arches != NULL;
arches = gdbarch_list_lookup_by_info (arches->next, &info))
{
if (gdbarch_tdep (arches->gdbarch)->elf_flags != elf_flags)
continue;
if (gdbarch_tdep (arches->gdbarch)->mips_abi != mips_abi)
continue;
if (gdbarch_tdep (arches->gdbarch)->mips64_transfers_32bit_regs_p
!= mips64_transfers_32bit_regs_p)
continue;
if (gdbarch_tdep (arches->gdbarch)->mips_fpu_type != fpu_type)
continue;
return arches->gdbarch;
}
tdep = (struct gdbarch_tdep *) xmalloc (sizeof (struct gdbarch_tdep));
gdbarch = gdbarch_alloc (&info, tdep);
tdep->elf_flags = elf_flags;
tdep->mips64_transfers_32bit_regs_p = mips64_transfers_32bit_regs_p;
tdep->found_abi = found_abi;
tdep->mips_abi = mips_abi;
tdep->mips_fpu_type = fpu_type;
set_gdbarch_short_bit (gdbarch, 16);
set_gdbarch_int_bit (gdbarch, 32);
set_gdbarch_float_bit (gdbarch, 32);
set_gdbarch_double_bit (gdbarch, 64);
set_gdbarch_long_double_bit (gdbarch, 64);
set_gdbarch_register_reggroup_p (gdbarch, mips_register_reggroup_p);
set_gdbarch_pseudo_register_read (gdbarch, mips_pseudo_register_read);
set_gdbarch_pseudo_register_write (gdbarch, mips_pseudo_register_write);
set_gdbarch_elf_make_msymbol_special (gdbarch,
mips_elf_make_msymbol_special);
{
const char **reg_names;
struct mips_regnum *regnum = GDBARCH_OBSTACK_ZALLOC (gdbarch,
struct mips_regnum);
if (info.osabi == GDB_OSABI_IRIX)
{
regnum->fp0 = 32;
regnum->pc = 64;
regnum->cause = 65;
regnum->badvaddr = 66;
regnum->hi = 67;
regnum->lo = 68;
regnum->fp_control_status = 69;
regnum->fp_implementation_revision = 70;
num_regs = 71;
reg_names = mips_irix_reg_names;
}
else
{
regnum->lo = MIPS_EMBED_LO_REGNUM;
regnum->hi = MIPS_EMBED_HI_REGNUM;
regnum->badvaddr = MIPS_EMBED_BADVADDR_REGNUM;
regnum->cause = MIPS_EMBED_CAUSE_REGNUM;
regnum->pc = MIPS_EMBED_PC_REGNUM;
regnum->fp0 = MIPS_EMBED_FP0_REGNUM;
regnum->fp_control_status = 70;
regnum->fp_implementation_revision = 71;
num_regs = 90;
if (info.bfd_arch_info != NULL
&& info.bfd_arch_info->mach == bfd_mach_mips3900)
reg_names = mips_tx39_reg_names;
else
reg_names = mips_generic_reg_names;
}
set_gdbarch_pc_regnum (gdbarch, regnum->pc + num_regs);
set_gdbarch_sp_regnum (gdbarch, MIPS_SP_REGNUM + num_regs);
set_gdbarch_fp0_regnum (gdbarch, regnum->fp0);
set_gdbarch_num_regs (gdbarch, num_regs);
set_gdbarch_num_pseudo_regs (gdbarch, num_regs);
set_gdbarch_register_name (gdbarch, mips_register_name);
tdep->mips_processor_reg_names = reg_names;
tdep->regnum = regnum;
}
switch (mips_abi)
{
case MIPS_ABI_O32:
set_gdbarch_push_dummy_call (gdbarch, mips_o32_push_dummy_call);
set_gdbarch_return_value (gdbarch, mips_o32_return_value);
tdep->mips_last_arg_regnum = MIPS_A0_REGNUM + 4 - 1;
tdep->mips_last_fp_arg_regnum = tdep->regnum->fp0 + 12 + 4 - 1;
tdep->default_mask_address_p = 0;
set_gdbarch_long_bit (gdbarch, 32);
set_gdbarch_ptr_bit (gdbarch, 32);
set_gdbarch_long_long_bit (gdbarch, 64);
break;
case MIPS_ABI_O64:
set_gdbarch_push_dummy_call (gdbarch, mips_o64_push_dummy_call);
set_gdbarch_return_value (gdbarch, mips_o64_return_value);
tdep->mips_last_arg_regnum = MIPS_A0_REGNUM + 4 - 1;
tdep->mips_last_fp_arg_regnum = tdep->regnum->fp0 + 12 + 4 - 1;
tdep->default_mask_address_p = 0;
set_gdbarch_long_bit (gdbarch, 32);
set_gdbarch_ptr_bit (gdbarch, 32);
set_gdbarch_long_long_bit (gdbarch, 64);
break;
case MIPS_ABI_EABI32:
set_gdbarch_push_dummy_call (gdbarch, mips_eabi_push_dummy_call);
set_gdbarch_return_value (gdbarch, mips_eabi_return_value);
tdep->mips_last_arg_regnum = MIPS_A0_REGNUM + 8 - 1;
tdep->mips_last_fp_arg_regnum = tdep->regnum->fp0 + 12 + 8 - 1;
tdep->default_mask_address_p = 0;
set_gdbarch_long_bit (gdbarch, 32);
set_gdbarch_ptr_bit (gdbarch, 32);
set_gdbarch_long_long_bit (gdbarch, 64);
break;
case MIPS_ABI_EABI64:
set_gdbarch_push_dummy_call (gdbarch, mips_eabi_push_dummy_call);
set_gdbarch_return_value (gdbarch, mips_eabi_return_value);
tdep->mips_last_arg_regnum = MIPS_A0_REGNUM + 8 - 1;
tdep->mips_last_fp_arg_regnum = tdep->regnum->fp0 + 12 + 8 - 1;
tdep->default_mask_address_p = 0;
set_gdbarch_long_bit (gdbarch, 64);
set_gdbarch_ptr_bit (gdbarch, 64);
set_gdbarch_long_long_bit (gdbarch, 64);
break;
case MIPS_ABI_N32:
set_gdbarch_push_dummy_call (gdbarch, mips_n32n64_push_dummy_call);
set_gdbarch_return_value (gdbarch, mips_n32n64_return_value);
tdep->mips_last_arg_regnum = MIPS_A0_REGNUM + 8 - 1;
tdep->mips_last_fp_arg_regnum = tdep->regnum->fp0 + 12 + 8 - 1;
tdep->default_mask_address_p = 0;
set_gdbarch_long_bit (gdbarch, 32);
set_gdbarch_ptr_bit (gdbarch, 32);
set_gdbarch_long_long_bit (gdbarch, 64);
set_gdbarch_long_double_bit (gdbarch, 128);
set_gdbarch_long_double_format (gdbarch,
&floatformat_n32n64_long_double_big);
break;
case MIPS_ABI_N64:
set_gdbarch_push_dummy_call (gdbarch, mips_n32n64_push_dummy_call);
set_gdbarch_return_value (gdbarch, mips_n32n64_return_value);
tdep->mips_last_arg_regnum = MIPS_A0_REGNUM + 8 - 1;
tdep->mips_last_fp_arg_regnum = tdep->regnum->fp0 + 12 + 8 - 1;
tdep->default_mask_address_p = 0;
set_gdbarch_long_bit (gdbarch, 64);
set_gdbarch_ptr_bit (gdbarch, 64);
set_gdbarch_long_long_bit (gdbarch, 64);
set_gdbarch_long_double_bit (gdbarch, 128);
set_gdbarch_long_double_format (gdbarch,
&floatformat_n32n64_long_double_big);
break;
default:
internal_error (__FILE__, __LINE__, _("unknown ABI in switch"));
}
set_gdbarch_read_pc (gdbarch, mips_read_pc);
set_gdbarch_write_pc (gdbarch, mips_write_pc);
set_gdbarch_read_sp (gdbarch, mips_read_sp);
set_gdbarch_addr_bits_remove (gdbarch, mips_addr_bits_remove);
set_gdbarch_unwind_pc (gdbarch, mips_unwind_pc);
set_gdbarch_unwind_dummy_id (gdbarch, mips_unwind_dummy_id);
set_gdbarch_stab_reg_to_regnum (gdbarch, mips_stab_reg_to_regnum);
set_gdbarch_ecoff_reg_to_regnum (gdbarch,
mips_dwarf_dwarf2_ecoff_reg_to_regnum);
set_gdbarch_dwarf_reg_to_regnum (gdbarch,
mips_dwarf_dwarf2_ecoff_reg_to_regnum);
set_gdbarch_dwarf2_reg_to_regnum (gdbarch,
mips_dwarf_dwarf2_ecoff_reg_to_regnum);
set_gdbarch_register_sim_regno (gdbarch, mips_register_sim_regno);
set_gdbarch_call_dummy_location (gdbarch, AT_SYMBOL);
set_gdbarch_frame_align (gdbarch, mips_frame_align);
set_gdbarch_convert_register_p (gdbarch, mips_convert_register_p);
set_gdbarch_register_to_value (gdbarch, mips_register_to_value);
set_gdbarch_value_to_register (gdbarch, mips_value_to_register);
set_gdbarch_inner_than (gdbarch, core_addr_lessthan);
set_gdbarch_breakpoint_from_pc (gdbarch, mips_breakpoint_from_pc);
set_gdbarch_skip_prologue (gdbarch, mips_skip_prologue);
set_gdbarch_pointer_to_address (gdbarch, signed_pointer_to_address);
set_gdbarch_address_to_pointer (gdbarch, address_to_signed_pointer);
set_gdbarch_integer_to_address (gdbarch, mips_integer_to_address);
set_gdbarch_register_type (gdbarch, mips_register_type);
set_gdbarch_print_registers_info (gdbarch, mips_print_registers_info);
set_gdbarch_print_insn (gdbarch, gdb_print_insn_mips);
set_gdbarch_have_nonsteppable_watchpoint (gdbarch, 1);
set_gdbarch_skip_trampoline_code (gdbarch, mips_skip_trampoline_code);
set_gdbarch_single_step_through_delay (gdbarch, mips_single_step_through_delay);
gdbarch_init_osabi (info, gdbarch);
frame_unwind_append_sniffer (gdbarch, mips_stub_frame_sniffer);
frame_unwind_append_sniffer (gdbarch, mips_insn16_frame_sniffer);
frame_unwind_append_sniffer (gdbarch, mips_insn32_frame_sniffer);
frame_base_append_sniffer (gdbarch, mips_stub_frame_base_sniffer);
frame_base_append_sniffer (gdbarch, mips_insn16_frame_base_sniffer);
frame_base_append_sniffer (gdbarch, mips_insn32_frame_base_sniffer);
return gdbarch;
}
static void
mips_abi_update (char *ignore_args, int from_tty, struct cmd_list_element *c)
{
struct gdbarch_info info;
gdbarch_info_init (&info);
gdbarch_update_p (info);
}
static void
show_mips_abi (struct ui_file *file,
int from_tty,
struct cmd_list_element *ignored_cmd,
const char *ignored_value)
{
if (gdbarch_bfd_arch_info (current_gdbarch)->arch != bfd_arch_mips)
fprintf_filtered
(file,
"The MIPS ABI is unknown because the current architecture "
"is not MIPS.\n");
else
{
enum mips_abi global_abi = global_mips_abi ();
enum mips_abi actual_abi = mips_abi (current_gdbarch);
const char *actual_abi_str = mips_abi_strings[actual_abi];
if (global_abi == MIPS_ABI_UNKNOWN)
fprintf_filtered
(file,
"The MIPS ABI is set automatically (currently \"%s\").\n",
actual_abi_str);
else if (global_abi == actual_abi)
fprintf_filtered
(file,
"The MIPS ABI is assumed to be \"%s\" (due to user setting).\n",
actual_abi_str);
else
{
fprintf_filtered
(file,
"The (auto detected) MIPS ABI \"%s\" is in use even though the user setting was \"%s\".\n",
actual_abi_str, mips_abi_strings[global_abi]);
}
}
}
static void
mips_dump_tdep (struct gdbarch *current_gdbarch, struct ui_file *file)
{
struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
if (tdep != NULL)
{
int ef_mips_arch;
int ef_mips_32bitmode;
switch (tdep->elf_flags & EF_MIPS_ARCH)
{
case E_MIPS_ARCH_1:
ef_mips_arch = 1;
break;
case E_MIPS_ARCH_2:
ef_mips_arch = 2;
break;
case E_MIPS_ARCH_3:
ef_mips_arch = 3;
break;
case E_MIPS_ARCH_4:
ef_mips_arch = 4;
break;
default:
ef_mips_arch = 0;
break;
}
ef_mips_32bitmode = (tdep->elf_flags & EF_MIPS_32BITMODE);
fprintf_unfiltered (file,
"mips_dump_tdep: tdep->elf_flags = 0x%x\n",
tdep->elf_flags);
fprintf_unfiltered (file,
"mips_dump_tdep: ef_mips_32bitmode = %d\n",
ef_mips_32bitmode);
fprintf_unfiltered (file,
"mips_dump_tdep: ef_mips_arch = %d\n",
ef_mips_arch);
fprintf_unfiltered (file,
"mips_dump_tdep: tdep->mips_abi = %d (%s)\n",
tdep->mips_abi, mips_abi_strings[tdep->mips_abi]);
fprintf_unfiltered (file,
"mips_dump_tdep: mips_mask_address_p() %d (default %d)\n",
mips_mask_address_p (tdep),
tdep->default_mask_address_p);
}
fprintf_unfiltered (file,
"mips_dump_tdep: MIPS_DEFAULT_FPU_TYPE = %d (%s)\n",
MIPS_DEFAULT_FPU_TYPE,
(MIPS_DEFAULT_FPU_TYPE == MIPS_FPU_NONE ? "none"
: MIPS_DEFAULT_FPU_TYPE == MIPS_FPU_SINGLE ? "single"
: MIPS_DEFAULT_FPU_TYPE == MIPS_FPU_DOUBLE ? "double"
: "???"));
fprintf_unfiltered (file, "mips_dump_tdep: MIPS_EABI = %d\n", MIPS_EABI);
fprintf_unfiltered (file,
"mips_dump_tdep: MIPS_FPU_TYPE = %d (%s)\n",
MIPS_FPU_TYPE,
(MIPS_FPU_TYPE == MIPS_FPU_NONE ? "none"
: MIPS_FPU_TYPE == MIPS_FPU_SINGLE ? "single"
: MIPS_FPU_TYPE == MIPS_FPU_DOUBLE ? "double"
: "???"));
fprintf_unfiltered (file,
"mips_dump_tdep: mips_stack_argsize() = %d\n",
mips_stack_argsize (current_gdbarch));
}
extern initialize_file_ftype _initialize_mips_tdep;
void
_initialize_mips_tdep (void)
{
static struct cmd_list_element *mipsfpulist = NULL;
struct cmd_list_element *c;
mips_abi_string = mips_abi_strings[MIPS_ABI_UNKNOWN];
if (MIPS_ABI_LAST + 1
!= sizeof (mips_abi_strings) / sizeof (mips_abi_strings[0]))
internal_error (__FILE__, __LINE__, _("mips_abi_strings out of sync"));
gdbarch_register (bfd_arch_mips, mips_gdbarch_init, mips_dump_tdep);
mips_pdr_data = register_objfile_data ();
add_prefix_cmd ("mips", no_class, set_mips_command,
_("Various MIPS specific commands."),
&setmipscmdlist, "set mips ", 0, &setlist);
add_prefix_cmd ("mips", no_class, show_mips_command,
_("Various MIPS specific commands."),
&showmipscmdlist, "show mips ", 0, &showlist);
add_setshow_enum_cmd ("saved-gpreg-size", class_obscure,
size_enums, &mips_abi_regsize_string, _("\
Set size of general purpose registers saved on the stack."), _("\
Show size of general purpose registers saved on the stack."), _("\
This option can be set to one of:\n\
32 - Force GDB to treat saved GP registers as 32-bit\n\
64 - Force GDB to treat saved GP registers as 64-bit\n\
auto - Allow GDB to use the target's default setting or autodetect the\n\
saved GP register size from information contained in the\n\
executable (default)."),
NULL,
NULL,
&setmipscmdlist, &showmipscmdlist);
add_setshow_enum_cmd ("stack-arg-size", class_obscure,
size_enums, &mips_stack_argsize_string, _("\
Set the amount of stack space reserved for each argument."), _("\
Show the amount of stack space reserved for each argument."), _("\
This option can be set to one of:\n\
32 - Force GDB to allocate 32-bit chunks per argument\n\
64 - Force GDB to allocate 64-bit chunks per argument\n\
auto - Allow GDB to determine the correct setting from the current\n\
target and executable (default)"),
NULL,
NULL,
&setmipscmdlist, &showmipscmdlist);
add_setshow_enum_cmd ("abi", class_obscure, mips_abi_strings,
&mips_abi_string, _("\
Set the MIPS ABI used by this program."), _("\
Show the MIPS ABI used by this program."), _("\
This option can be set to one of:\n\
auto - the default ABI associated with the current binary\n\
o32\n\
o64\n\
n32\n\
n64\n\
eabi32\n\
eabi64"),
mips_abi_update,
show_mips_abi,
&setmipscmdlist, &showmipscmdlist);
add_prefix_cmd ("mipsfpu", class_support, set_mipsfpu_command,
_("Set use of MIPS floating-point coprocessor."),
&mipsfpulist, "set mipsfpu ", 0, &setlist);
add_cmd ("single", class_support, set_mipsfpu_single_command,
_("Select single-precision MIPS floating-point coprocessor."),
&mipsfpulist);
add_cmd ("double", class_support, set_mipsfpu_double_command,
_("Select double-precision MIPS floating-point coprocessor."),
&mipsfpulist);
add_alias_cmd ("on", "double", class_support, 1, &mipsfpulist);
add_alias_cmd ("yes", "double", class_support, 1, &mipsfpulist);
add_alias_cmd ("1", "double", class_support, 1, &mipsfpulist);
add_cmd ("none", class_support, set_mipsfpu_none_command,
_("Select no MIPS floating-point coprocessor."), &mipsfpulist);
add_alias_cmd ("off", "none", class_support, 1, &mipsfpulist);
add_alias_cmd ("no", "none", class_support, 1, &mipsfpulist);
add_alias_cmd ("0", "none", class_support, 1, &mipsfpulist);
add_cmd ("auto", class_support, set_mipsfpu_auto_command,
_("Select MIPS floating-point coprocessor automatically."),
&mipsfpulist);
add_cmd ("mipsfpu", class_support, show_mipsfpu_command,
_("Show current use of MIPS floating-point coprocessor target."),
&showlist);
add_setshow_zinteger_cmd ("heuristic-fence-post", class_support,
&heuristic_fence_post, _("\
Set the distance searched for the start of a function."), _("\
Show the distance searched for the start of a function."), _("\
If you are debugging a stripped executable, GDB needs to search through the\n\
program for the start of a function. This command sets the distance of the\n\
search. The only need to set it is when debugging a stripped executable."),
reinit_frame_cache_sfunc,
NULL,
&setlist, &showlist);
add_setshow_auto_boolean_cmd ("mask-address", no_class,
&mask_address_var, _("\
Set zeroing of upper 32 bits of 64-bit addresses."), _("\
Show zeroing of upper 32 bits of 64-bit addresses."), _("\
Use \"on\" to enable the masking, \"off\" to disable it and \"auto\" to \n\
allow GDB to determine the correct value."),
NULL, show_mask_address,
&setmipscmdlist, &showmipscmdlist);
add_setshow_boolean_cmd ("remote-mips64-transfers-32bit-regs", class_obscure,
&mips64_transfers_32bit_regs_p, _("\
Set compatibility with 64-bit MIPS target that transfers 32-bit quantities."),
_("\
Show compatibility with 64-bit MIPS target that transfers 32-bit quantities."),
_("\
Use \"on\" to enable backward compatibility with older MIPS 64 GDB+target\n\
that would transfer 32 bits for some registers (e.g. SR, FSR) and\n\
64 bits for others. Use \"off\" to disable compatibility mode"),
set_mips64_transfers_32bit_regs,
NULL,
&setlist, &showlist);
add_setshow_zinteger_cmd ("mips", class_maintenance,
&mips_debug, _("\
Set mips debugging."), _("\
Show mips debugging."), _("\
When non-zero, mips specific debugging is enabled."),
NULL,
NULL,
&setdebuglist, &showdebuglist);
}