2009-01-08 Kai Tietz <kai.tietz@onevision.com>
[binutils-gdb.git] / gdb / mips-tdep.c
index b6755421ee9b4346238ea12bf0d5ad4498d1a013..fd893486730820b7c908a9efb55add0139ed2638 100644 (file)
@@ -1,7 +1,7 @@
 /* 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
@@ -57,6 +57,7 @@
 #include "target-descriptions.h"
 #include "dwarf2-frame.h"
 #include "user-regs.h"
+#include "valprint.h"
 
 static const struct objfile_data *mips_pdr_data;
 
@@ -253,8 +254,7 @@ 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);
+      MSYMBOL_TARGET_FLAG_1 (msym) = 1;
       SYMBOL_VALUE_ADDRESS (msym) |= 1;
     }
 }
@@ -262,7 +262,7 @@ mips_elf_make_msymbol_special (asymbol * sym, struct minimal_symbol *msym)
 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.
@@ -737,12 +737,13 @@ mips_pseudo_register_type (struct gdbarch *gdbarch, int regnum)
 
   /* 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
@@ -1897,6 +1898,7 @@ mips32_scan_prologue (CORE_ADDR start_pc, CORE_ADDR limit_pc,
   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);
 
@@ -2054,7 +2056,18 @@ restart:
             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)
@@ -2256,6 +2269,7 @@ mips_stub_frame_sniffer (const struct frame_unwind *self,
   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)
@@ -2272,6 +2286,14 @@ mips_stub_frame_sniffer (const struct frame_unwind *self,
                 ".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;
 }
 
@@ -2313,9 +2335,9 @@ mips_stub_frame_base_sniffer (struct frame_info *this_frame)
 /* 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
@@ -2492,6 +2514,7 @@ heuristic_proc_start (struct gdbarch *gdbarch, CORE_ADDR pc)
   CORE_ADDR fence;
   int instlen;
   int seen_adjsp = 0;
+  struct inferior *inf;
 
   pc = gdbarch_addr_bits_remove (gdbarch, pc);
   start_pc = pc;
@@ -2504,6 +2527,8 @@ heuristic_proc_start (struct gdbarch *gdbarch, CORE_ADDR 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)
@@ -2512,7 +2537,7 @@ heuristic_proc_start (struct gdbarch *gdbarch, CORE_ADDR pc)
           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;
 
@@ -3010,7 +3035,7 @@ mips_n32n64_fp_arg_chunk_p (struct gdbarch *gdbarch, struct type *arg_type,
       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;
 
@@ -4354,12 +4379,15 @@ mips_print_fp_register (struct ui_file *file, struct frame_info *frame,
 
   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: ");
@@ -4383,6 +4411,8 @@ mips_print_fp_register (struct ui_file *file, struct frame_info *frame,
     }
   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);
@@ -4390,8 +4420,8 @@ mips_print_fp_register (struct ui_file *file, struct frame_info *frame,
       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: ");
@@ -4415,6 +4445,7 @@ mips_print_register (struct ui_file *file, struct frame_info *frame,
   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)
     {
@@ -4447,8 +4478,9 @@ mips_print_register (struct ui_file *file, struct frame_info *frame,
   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);
 }
 
@@ -4885,11 +4917,12 @@ set_mipsfpu_auto_command (char *args, int from_tty)
 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;
 }
@@ -4907,8 +4940,6 @@ reinit_frame_cache_sfunc (char *args, int from_tty,
 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
@@ -4920,17 +4951,7 @@ gdb_print_insn_mips (bfd_vma memaddr, struct disassemble_info *info)
   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
@@ -4945,6 +4966,28 @@ gdb_print_insn_mips (bfd_vma memaddr, struct disassemble_info *info)
     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
@@ -5031,7 +5074,7 @@ mips_breakpoint_from_pc (struct gdbarch *gdbarch, CORE_ADDR *pcptr, int *lenptr)
    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;
@@ -5110,6 +5153,80 @@ mips_skip_trampoline_code (struct frame_info *frame, CORE_ADDR pc)
   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.  */
 
@@ -5872,7 +5989,12 @@ mips_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
 
   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