gdb
[deliverable/binutils-gdb.git] / gdb / mips-tdep.c
index 1cc34489d3f5ff3b70aaebf63395c2cd3b2537e4..07742668dfdbfe6873aa8e9e65a2a003e2a84373 100644 (file)
@@ -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.
@@ -1898,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);
 
@@ -2055,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)
@@ -2257,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)
@@ -2273,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;
 }
 
@@ -2493,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;
@@ -2505,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)
@@ -2513,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;
 
@@ -3011,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;
 
@@ -4355,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: ");
@@ -4384,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);
@@ -4391,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: ");
@@ -4416,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)
     {
@@ -4448,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);
 }
 
@@ -5043,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;
@@ -5122,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.  */
 
This page took 0.026894 seconds and 4 git commands to generate.