/* Target-dependent code for the MIPS architecture, for GDB, the GNU Debugger.
Copyright (C) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997,
- 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008
+ 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009
Free Software Foundation, Inc.
Contributed by Alessandro Forin(af@cs.cmu.edu) at CMU
#include "target-descriptions.h"
#include "dwarf2-frame.h"
#include "user-regs.h"
+#include "valprint.h"
static const struct objfile_data *mips_pdr_data;
{ "fsr", MIPS_EMBED_FP0_REGNUM + 32 }
};
+const struct register_alias mips_numeric_register_aliases[] = {
+#define R(n) { #n, n }
+ R(0), R(1), R(2), R(3), R(4), R(5), R(6), R(7),
+ R(8), R(9), R(10), R(11), R(12), R(13), R(14), R(15),
+ R(16), R(17), R(18), R(19), R(20), R(21), R(22), R(23),
+ R(24), R(25), R(26), R(27), R(28), R(29), R(30), R(31),
+#undef R
+};
+
#ifndef MIPS_DEFAULT_FPU_TYPE
#define MIPS_DEFAULT_FPU_TYPE MIPS_FPU_DOUBLE
#endif
{
if (((elf_symbol_type *) (sym))->internal_elf_sym.st_other == STO_MIPS16)
{
- MSYMBOL_INFO (msym) = (char *)
- (((long) MSYMBOL_INFO (msym)) | 0x80000000);
+ MSYMBOL_TARGET_FLAG_1 (msym) = 1;
SYMBOL_VALUE_ADDRESS (msym) |= 1;
}
}
static int
msymbol_is_special (struct minimal_symbol *msym)
{
- return (((long) MSYMBOL_INFO (msym) & 0x80000000) != 0);
+ return MSYMBOL_TARGET_FLAG_1 (msym);
}
/* XFER a value from the big/little/left end of the register.
/* Use pointer types for registers if we can. For n32 we can not,
since we do not have a 64-bit pointer type. */
- if (mips_abi_regsize (gdbarch) == TYPE_LENGTH (builtin_type_void_data_ptr))
+ if (mips_abi_regsize (gdbarch)
+ == TYPE_LENGTH (builtin_type (gdbarch)->builtin_data_ptr))
{
if (rawnum == MIPS_SP_REGNUM || rawnum == MIPS_EMBED_BADVADDR_REGNUM)
- return builtin_type_void_data_ptr;
+ return builtin_type (gdbarch)->builtin_data_ptr;
else if (rawnum == MIPS_EMBED_PC_REGNUM)
- return builtin_type_void_func_ptr;
+ return builtin_type (gdbarch)->builtin_func_ptr;
}
if (mips_abi_regsize (gdbarch) == 4 && TYPE_LENGTH (rawtype) == 8
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);
+ struct gdbarch_tdep *tdep = gdbarch_tdep (target_gdbarch);
deprecated_show_value_hack (file, from_tty, c, value);
switch (mask_address_var)
CORE_ADDR end_prologue_addr = 0;
int seen_sp_adjust = 0;
int load_immediate_bytes = 0;
+ int in_delay_slot = 0;
struct gdbarch *gdbarch = get_frame_arch (this_frame);
int regsize_is_64_bits = (mips_abi_regsize (gdbarch) == 8);
instructions? */
if (end_prologue_addr == 0)
end_prologue_addr = cur_pc;
+
+ /* Check for branches and jumps. For now, only jump to
+ register are caught (i.e. returns). */
+ if ((itype_op (inst) & 0x07) == 0 && rtype_funct (inst) == 8)
+ in_delay_slot = 1;
}
+
+ /* If the previous instruction was a jump, we must have reached
+ the end of the prologue by now. Stop scanning so that we do
+ not go past the function return. */
+ if (in_delay_slot)
+ break;
}
if (this_cache != NULL)
gdb_byte dummy[4];
struct obj_section *s;
CORE_ADDR pc = get_frame_address_in_block (this_frame);
+ struct minimal_symbol *msym;
/* Use the stub unwinder for unreadable code. */
if (target_read_memory (get_frame_pc (this_frame), dummy, 4) != 0)
".MIPS.stubs") == 0)
return 1;
+ /* Calling a PIC function from a non-PIC function passes through a
+ stub. The stub for foo is named ".pic.foo". */
+ msym = lookup_minimal_symbol_by_pc (pc);
+ if (msym != NULL
+ && SYMBOL_LINKAGE_NAME (msym) != NULL
+ && strncmp (SYMBOL_LINKAGE_NAME (msym), ".pic.", 5) == 0)
+ return 1;
+
return 0;
}
/* mips_addr_bits_remove - remove useless address bits */
static CORE_ADDR
-mips_addr_bits_remove (CORE_ADDR addr)
+mips_addr_bits_remove (struct gdbarch *gdbarch, CORE_ADDR addr)
{
- struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
+ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
if (mips_mask_address_p (tdep) && (((ULONGEST) addr) >> 32 == 0xffffffffUL))
/* This hack is a work-around for existing boards using PMON, the
simulator, and any other 64-bit targets that doesn't have true
CORE_ADDR fence;
int instlen;
int seen_adjsp = 0;
+ struct inferior *inf;
pc = gdbarch_addr_bits_remove (gdbarch, pc);
start_pc = pc;
instlen = mips_pc_is_mips16 (pc) ? MIPS_INSN16_SIZE : MIPS_INSN32_SIZE;
+ inf = current_inferior ();
+
/* search back for previous return */
for (start_pc -= instlen;; start_pc -= instlen)
if (start_pc < fence)
stop_soon, but with this test, at least we
don't print out warnings for every child forked (eg, on
decstation). 22apr93 rich@cygnus.com. */
- if (stop_soon == NO_STOP_QUIETLY)
+ if (inf->stop_soon == NO_STOP_QUIETLY)
{
static int blurb_printed = 0;
struct type *field_type;
/* We're only looking at normal fields. */
- if (TYPE_FIELD_STATIC (arg_type, i)
+ if (field_is_static (&TYPE_FIELD (arg_type, i))
|| (TYPE_FIELD_BITPOS (arg_type, i) % 8) != 0)
continue;
if (register_size (gdbarch, regnum) == 4 || mips2_fp_compat (frame))
{
+ struct value_print_options opts;
+
/* 4-byte registers: Print hex and floating. Also print even
numbered registers as doubles. */
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',
+ get_formatted_print_options (&opts, 'x');
+ print_scalar_formatted (raw_buffer, builtin_type_uint32, &opts, 'w',
file);
fprintf_filtered (file, " flt: ");
}
else
{
+ struct value_print_options opts;
+
/* Eight byte registers: print each one as hex, float and double. */
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',
+ get_formatted_print_options (&opts, 'x');
+ print_scalar_formatted (raw_buffer, builtin_type_uint64, &opts, 'g',
file);
fprintf_filtered (file, " flt: ");
struct gdbarch *gdbarch = get_frame_arch (frame);
gdb_byte raw_buffer[MAX_REGISTER_SIZE];
int offset;
+ struct value_print_options opts;
if (TYPE_CODE (register_type (gdbarch, regnum)) == TYPE_CODE_FLT)
{
else
offset = 0;
+ get_formatted_print_options (&opts, 'x');
print_scalar_formatted (raw_buffer + offset,
- register_type (gdbarch, regnum), 'x', 0,
+ register_type (gdbarch, regnum), &opts, 0,
file);
}
| INSN_COND_BRANCH_LIKELY)));
}
-int
+static int
mips_single_step_through_delay (struct gdbarch *gdbarch,
struct frame_info *frame)
{
{
char *fpu;
- if (gdbarch_bfd_arch_info (current_gdbarch)->arch != bfd_arch_mips)
+ if (gdbarch_bfd_arch_info (target_gdbarch)->arch != bfd_arch_mips)
{
printf_unfiltered
("The MIPS floating-point coprocessor is unknown "
return;
}
- switch (MIPS_FPU_TYPE (current_gdbarch))
+ switch (MIPS_FPU_TYPE (target_gdbarch))
{
case MIPS_FPU_SINGLE:
fpu = "single-precision";
void
deprecated_mips_set_processor_regs_hack (void)
{
- struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
+ struct regcache *regcache = get_current_regcache ();
+ struct gdbarch *gdbarch = get_regcache_arch (regcache);
+ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
ULONGEST prid;
- regcache_cooked_read_unsigned (get_current_regcache (),
- MIPS_PRID_REGNUM, &prid);
+ regcache_cooked_read_unsigned (regcache, MIPS_PRID_REGNUM, &prid);
if ((prid & ~0xf) == 0x700)
tdep->mips_processor_reg_names = mips_r3041_reg_names;
}
static int
gdb_print_insn_mips (bfd_vma memaddr, struct disassemble_info *info)
{
- struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
-
/* FIXME: cagney/2003-06-26: Is this even necessary? The
disassembler needs to be able to locally determine the ISA, and
not rely on GDB. Otherwize the stand-alone 'objdump -d' will not
memaddr &= (info->mach == bfd_mach_mips16 ? ~1 : ~3);
/* Set the disassembler options. */
- if (tdep->mips_abi == MIPS_ABI_N32 || tdep->mips_abi == MIPS_ABI_N64)
- {
- /* Set up the disassembler info, so that we get the right
- register names from libopcodes. */
- 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
+ if (!info->disassembler_options)
/* This string is not recognized explicitly by the disassembler,
but it tells the disassembler to not try to guess the ABI from
the bfd elf headers, such that, if the user overrides the ABI
return print_insn_little_mips (memaddr, info);
}
+static int
+gdb_print_insn_mips_n32 (bfd_vma memaddr, struct disassemble_info *info)
+{
+ /* Set up the disassembler info, so that we get the right
+ register names from libopcodes. */
+ info->disassembler_options = "gpr-names=n32";
+ info->flavour = bfd_target_elf_flavour;
+
+ return gdb_print_insn_mips (memaddr, info);
+}
+
+static int
+gdb_print_insn_mips_n64 (bfd_vma memaddr, struct disassemble_info *info)
+{
+ /* Set up the disassembler info, so that we get the right
+ register names from libopcodes. */
+ info->disassembler_options = "gpr-names=64";
+ info->flavour = bfd_target_elf_flavour;
+
+ return gdb_print_insn_mips (memaddr, info);
+}
+
/* This function implements gdbarch_breakpoint_from_pc. It uses the program
counter value to determine whether a 16- or 32-bit breakpoint should be used.
It returns a pointer to a string of bytes that encode a breakpoint
gory details. */
static CORE_ADDR
-mips_skip_trampoline_code (struct frame_info *frame, CORE_ADDR pc)
+mips_skip_mips16_trampoline_code (struct frame_info *frame, CORE_ADDR pc)
{
char *name;
CORE_ADDR start_addr;
return 0; /* not a stub */
}
+/* If the current PC is the start of a non-PIC-to-PIC stub, return the
+ PC of the stub target. The stub just loads $t9 and jumps to it,
+ so that $t9 has the correct value at function entry. */
+
+static CORE_ADDR
+mips_skip_pic_trampoline_code (struct frame_info *frame, CORE_ADDR pc)
+{
+ struct minimal_symbol *msym;
+ int i;
+ gdb_byte stub_code[16];
+ int32_t stub_words[4];
+
+ /* The stub for foo is named ".pic.foo", and is either two
+ instructions inserted before foo or a three instruction sequence
+ which jumps to foo. */
+ msym = lookup_minimal_symbol_by_pc (pc);
+ if (msym == NULL
+ || SYMBOL_VALUE_ADDRESS (msym) != pc
+ || SYMBOL_LINKAGE_NAME (msym) == NULL
+ || strncmp (SYMBOL_LINKAGE_NAME (msym), ".pic.", 5) != 0)
+ return 0;
+
+ /* A two-instruction header. */
+ if (MSYMBOL_SIZE (msym) == 8)
+ return pc + 8;
+
+ /* A three-instruction (plus delay slot) trampoline. */
+ if (MSYMBOL_SIZE (msym) == 16)
+ {
+ if (target_read_memory (pc, stub_code, 16) != 0)
+ return 0;
+ for (i = 0; i < 4; i++)
+ stub_words[i] = extract_unsigned_integer (stub_code + i * 4, 4);
+
+ /* A stub contains these instructions:
+ lui t9, %hi(target)
+ j target
+ addiu t9, t9, %lo(target)
+ nop
+
+ This works even for N64, since stubs are only generated with
+ -msym32. */
+ if ((stub_words[0] & 0xffff0000U) == 0x3c190000
+ && (stub_words[1] & 0xfc000000U) == 0x08000000
+ && (stub_words[2] & 0xffff0000U) == 0x27390000
+ && stub_words[3] == 0x00000000)
+ return (((stub_words[0] & 0x0000ffff) << 16)
+ + (stub_words[2] & 0x0000ffff));
+ }
+
+ /* Not a recognized stub. */
+ return 0;
+}
+
+static CORE_ADDR
+mips_skip_trampoline_code (struct frame_info *frame, CORE_ADDR pc)
+{
+ CORE_ADDR target_pc;
+
+ target_pc = mips_skip_mips16_trampoline_code (frame, pc);
+ if (target_pc)
+ return target_pc;
+
+ target_pc = find_solib_trampoline_target (frame, pc);
+ if (target_pc)
+ return target_pc;
+
+ target_pc = mips_skip_pic_trampoline_code (frame, pc);
+ if (target_pc)
+ return target_pc;
+
+ return 0;
+}
+
/* Convert a dbx stab register number (from `r' declaration) to a GDB
[1 * gdbarch_num_regs .. 2 * gdbarch_num_regs) REGNUM. */
reg_names = mips_generic_reg_names;
}
/* FIXME: cagney/2003-11-15: For MIPS, hasn't gdbarch_pc_regnum been
- replaced by read_pc? */
+ replaced by gdbarch_read_pc? */
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_print_registers_info (gdbarch, mips_print_registers_info);
- set_gdbarch_print_insn (gdbarch, gdb_print_insn_mips);
+ if (mips_abi == MIPS_ABI_N32)
+ set_gdbarch_print_insn (gdbarch, gdb_print_insn_mips_n32);
+ else if (mips_abi == MIPS_ABI_N64)
+ set_gdbarch_print_insn (gdbarch, gdb_print_insn_mips_n64);
+ else
+ set_gdbarch_print_insn (gdbarch, gdb_print_insn_mips);
- /* FIXME: cagney/2003-08-29: The macros HAVE_STEPPABLE_WATCHPOINT,
- HAVE_NONSTEPPABLE_WATCHPOINT, and HAVE_CONTINUABLE_WATCHPOINT
+ /* FIXME: cagney/2003-08-29: The macros target_have_steppable_watchpoint,
+ HAVE_NONSTEPPABLE_WATCHPOINT, and target_have_continuable_watchpoint
need to all be folded into the target vector. Since they are
- being used as guards for STOPPED_BY_WATCHPOINT, why not have
- STOPPED_BY_WATCHPOINT return the type of watchpoint that the code
+ being used as guards for target_stopped_by_watchpoint, why not have
+ target_stopped_by_watchpoint return the type of watchpoint that the code
is sitting on? */
set_gdbarch_have_nonsteppable_watchpoint (gdbarch, 1);
user_reg_add (gdbarch, mips_register_aliases[i].name,
value_of_mips_user_reg, &mips_register_aliases[i].regnum);
+ for (i = 0; i < ARRAY_SIZE (mips_numeric_register_aliases); i++)
+ user_reg_add (gdbarch, mips_numeric_register_aliases[i].name,
+ value_of_mips_user_reg,
+ &mips_numeric_register_aliases[i].regnum);
+
return gdbarch;
}
struct cmd_list_element *ignored_cmd,
const char *ignored_value)
{
- if (gdbarch_bfd_arch_info (current_gdbarch)->arch != bfd_arch_mips)
+ if (gdbarch_bfd_arch_info (target_gdbarch)->arch != bfd_arch_mips)
fprintf_filtered
(file,
"The MIPS ABI is unknown because the current architecture "
else
{
enum mips_abi global_abi = global_mips_abi ();
- enum mips_abi actual_abi = mips_abi (current_gdbarch);
+ enum mips_abi actual_abi = mips_abi (target_gdbarch);
const char *actual_abi_str = mips_abi_strings[actual_abi];
if (global_abi == MIPS_ABI_UNKNOWN)