* linux-thread-db.c (thread_db_mourn_inferior): Remove breakpoints
[deliverable/binutils-gdb.git] / gdb / rs6000-tdep.c
index fb350effddde2147b1e11e0eb7e605f8777fc18a..1d4a437ac599e18336984cb79aa43bcb46d34951 100644 (file)
@@ -1,8 +1,8 @@
 /* Target-dependent code for GDB, the GNU debugger.
 
-   Copyright 1986, 1987, 1989, 1991, 1992, 1993, 1994, 1995, 1996,
-   1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005 Free Software
-   Foundation, Inc.
+   Copyright (C) 1986, 1987, 1989, 1991, 1992, 1993, 1994, 1995, 1996,
+   1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006
+   Free Software Foundation, Inc.
 
    This file is part of GDB.
 
@@ -18,8 +18,8 @@
 
    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
-   Foundation, Inc., 59 Temple Place - Suite 330,
-   Boston, MA 02111-1307, USA.  */
+   Foundation, Inc., 51 Franklin Street, Fifth Floor,
+   Boston, MA 02110-1301, USA.  */
 
 #include "defs.h"
 #include "frame.h"
@@ -100,8 +100,8 @@ struct rs6000_framedata
 struct reg
   {
     char *name;                        /* name of register */
-    unsigned char sz32;                /* size on 32-bit arch, 0 if nonextant */
-    unsigned char sz64;                /* size on 64-bit arch, 0 if nonextant */
+    unsigned char sz32;                /* size on 32-bit arch, 0 if nonexistent */
+    unsigned char sz64;                /* size on 64-bit arch, 0 if nonexistent */
     unsigned char fpr;         /* whether register is floating-point */
     unsigned char pseudo;       /* whether register is pseudo */
     int spr_num;                /* PowerPC SPR number, or -1 if not an SPR.
@@ -502,6 +502,108 @@ rs6000_skip_prologue (CORE_ADDR pc)
   return pc;
 }
 
+static int
+insn_changes_sp_or_jumps (unsigned long insn)
+{
+  int opcode = (insn >> 26) & 0x03f;
+  int sd = (insn >> 21) & 0x01f;
+  int a = (insn >> 16) & 0x01f;
+  int subcode = (insn >> 1) & 0x3ff;
+
+  /* Changes the stack pointer.  */
+
+  /* NOTE: There are many ways to change the value of a given register.
+           The ways below are those used when the register is R1, the SP,
+           in a funtion's epilogue.  */
+
+  if (opcode == 31 && subcode == 444 && a == 1)
+    return 1;  /* mr R1,Rn */
+  if (opcode == 14 && sd == 1)
+    return 1;  /* addi R1,Rn,simm */
+  if (opcode == 58 && sd == 1)
+    return 1;  /* ld R1,ds(Rn) */
+
+  /* Transfers control.  */
+
+  if (opcode == 18)
+    return 1;  /* b */
+  if (opcode == 16)
+    return 1;  /* bc */
+  if (opcode == 19 && subcode == 16)
+    return 1;  /* bclr */
+  if (opcode == 19 && subcode == 528)
+    return 1;  /* bcctr */
+
+  return 0;
+}
+
+/* Return true if we are in the function's epilogue, i.e. after the
+   instruction that destroyed the function's stack frame.
+
+   1) scan forward from the point of execution:
+       a) If you find an instruction that modifies the stack pointer
+          or transfers control (except a return), execution is not in
+          an epilogue, return.
+       b) Stop scanning if you find a return instruction or reach the
+          end of the function or reach the hard limit for the size of
+          an epilogue.
+   2) scan backward from the point of execution:
+        a) If you find an instruction that modifies the stack pointer,
+            execution *is* in an epilogue, return.
+        b) Stop scanning if you reach an instruction that transfers
+           control or the beginning of the function or reach the hard
+           limit for the size of an epilogue.  */
+
+static int
+rs6000_in_function_epilogue_p (struct gdbarch *gdbarch, CORE_ADDR pc)
+{
+  bfd_byte insn_buf[PPC_INSN_SIZE];
+  CORE_ADDR scan_pc, func_start, func_end, epilogue_start, epilogue_end;
+  unsigned long insn;
+  struct frame_info *curfrm;
+
+  /* Find the search limits based on function boundaries and hard limit.  */
+
+  if (!find_pc_partial_function (pc, NULL, &func_start, &func_end))
+    return 0;
+
+  epilogue_start = pc - PPC_MAX_EPILOGUE_INSTRUCTIONS * PPC_INSN_SIZE;
+  if (epilogue_start < func_start) epilogue_start = func_start;
+
+  epilogue_end = pc + PPC_MAX_EPILOGUE_INSTRUCTIONS * PPC_INSN_SIZE;
+  if (epilogue_end > func_end) epilogue_end = func_end;
+
+  curfrm = get_current_frame ();
+
+  /* Scan forward until next 'blr'.  */
+
+  for (scan_pc = pc; scan_pc < epilogue_end; scan_pc += PPC_INSN_SIZE)
+    {
+      if (!safe_frame_unwind_memory (curfrm, scan_pc, insn_buf, PPC_INSN_SIZE))
+        return 0;
+      insn = extract_signed_integer (insn_buf, PPC_INSN_SIZE);
+      if (insn == 0x4e800020)
+        break;
+      if (insn_changes_sp_or_jumps (insn))
+        return 0;
+    }
+
+  /* Scan backward until adjustment to stack pointer (R1).  */
+
+  for (scan_pc = pc - PPC_INSN_SIZE;
+       scan_pc >= epilogue_start;
+       scan_pc -= PPC_INSN_SIZE)
+    {
+      if (!safe_frame_unwind_memory (curfrm, scan_pc, insn_buf, PPC_INSN_SIZE))
+        return 0;
+      insn = extract_signed_integer (insn_buf, PPC_INSN_SIZE);
+      if (insn_changes_sp_or_jumps (insn))
+        return 1;
+    }
+
+  return 0;
+}
+
 
 /* Fill in fi->saved_regs */
 
@@ -911,7 +1013,7 @@ skip_prologue (CORE_ADDR pc, CORE_ADDR lim_pc, struct rs6000_framedata *fdata)
 
             remember just the first one, but skip over additional
             ones.  */
-         if (lr_reg < 0)
+         if (lr_reg == -1)
            lr_reg = (op & 0x03e00000);
           if (lr_reg == 0)
             r0_contains_arg = 0;
@@ -1024,6 +1126,13 @@ skip_prologue (CORE_ADDR pc, CORE_ADDR lim_pc, struct rs6000_framedata *fdata)
          continue;
 
        }
+      else if ((op & 0xfe80ffff) == 0x42800005 && lr_reg != -1)
+       {
+         /* bcl 20,xx,.+4 is used to get the current PC, with or without
+            prediction bits.  If the LR has already been saved, we can
+            skip it.  */
+         continue;
+       }
       else if (op == 0x48000005)
        {                       /* bl .+4 used in 
                                   -mrelocatable */
@@ -1629,8 +1738,8 @@ ran_out_of_registers_for_arguments:
   regcache_raw_write_signed (regcache, SP_REGNUM, sp);
 
   /* Set back chain properly.  */
-  store_unsigned_integer (tmp_buffer, 4, saved_sp);
-  write_memory (sp, tmp_buffer, 4);
+  store_unsigned_integer (tmp_buffer, wordsize, saved_sp);
+  write_memory (sp, tmp_buffer, wordsize);
 
   /* Point the inferior function call's return address at the dummy's
      breakpoint.  */
@@ -1888,6 +1997,7 @@ rs6000_register_reggroup_p (struct gdbarch *gdbarch, int regnum,
              || (tdep->ppc_ev0_regnum >= 0
                  && regnum >= tdep->ppc_ev0_regnum
                  && regnum < tdep->ppc_ev0_regnum + 32)
+             || regnum == tdep->ppc_vrsave_regnum - 1 /* vscr */
              || regnum == tdep->ppc_vrsave_regnum
              || regnum == tdep->ppc_acc_regnum
              || regnum == tdep->ppc_spefscr_regnum);
@@ -2241,13 +2351,13 @@ rs6000_create_inferior (int pid)
 
    Usually a function pointer's representation is simply the address
    of the function. On the RS/6000 however, a function pointer is
-   represented by a pointer to a TOC entry. This TOC entry contains
+   represented by a pointer to an OPD entry. This OPD entry contains
    three words, the first word is the address of the function, the
    second word is the TOC pointer (r2), and the third word is the
    static chain value.  Throughout GDB it is currently assumed that a
    function pointer contains the address of the function, which is not
    easy to fix.  In addition, the conversion of a function address to
-   a function pointer would require allocation of a TOC entry in the
+   a function pointer would require allocation of an OPD entry in the
    inferior's memory space, with all its drawbacks.  To be able to
    call C++ virtual methods in the inferior (which are called via
    function pointers), find_function_addr uses this function to get the
@@ -2852,6 +2962,7 @@ rs6000_frame_cache (struct frame_info *next_frame, void **this_cache)
   struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
   struct rs6000_framedata fdata;
   int wordsize = tdep->wordsize;
+  CORE_ADDR func, pc;
 
   if ((*this_cache) != NULL)
     return (*this_cache);
@@ -2859,35 +2970,55 @@ rs6000_frame_cache (struct frame_info *next_frame, void **this_cache)
   (*this_cache) = cache;
   cache->saved_regs = trad_frame_alloc_saved_regs (next_frame);
 
-  skip_prologue (frame_func_unwind (next_frame), frame_pc_unwind (next_frame),
-                &fdata);
-
-  /* If there were any saved registers, figure out parent's stack
-     pointer.  */
-  /* The following is true only if the frame doesn't have a call to
-     alloca(), FIXME.  */
-
-  if (fdata.saved_fpr == 0
-      && fdata.saved_gpr == 0
-      && fdata.saved_vr == 0
-      && fdata.saved_ev == 0
-      && fdata.lr_offset == 0
-      && fdata.cr_offset == 0
-      && fdata.vr_offset == 0
-      && fdata.ev_offset == 0)
-    cache->base = frame_unwind_register_unsigned (next_frame, SP_REGNUM);
-  else
+  func = frame_func_unwind (next_frame);
+  pc = frame_pc_unwind (next_frame);
+  skip_prologue (func, pc, &fdata);
+
+  /* Figure out the parent's stack pointer.  */
+
+  /* NOTE: cagney/2002-04-14: The ->frame points to the inner-most
+     address of the current frame.  Things might be easier if the
+     ->frame pointed to the outer-most address of the frame.  In
+     the mean time, the address of the prev frame is used as the
+     base address of this frame.  */
+  cache->base = frame_unwind_register_unsigned (next_frame, SP_REGNUM);
+
+  /* If the function appears to be frameless, check a couple of likely
+     indicators that we have simply failed to find the frame setup.
+     Two common cases of this are missing symbols (i.e.
+     frame_func_unwind returns the wrong address or 0), and assembly
+     stubs which have a fast exit path but set up a frame on the slow
+     path.
+
+     If the LR appears to return to this function, then presume that
+     we have an ABI compliant frame that we failed to find.  */
+  if (fdata.frameless && fdata.lr_offset == 0)
     {
-      /* NOTE: cagney/2002-04-14: The ->frame points to the inner-most
-        address of the current frame.  Things might be easier if the
-        ->frame pointed to the outer-most address of the frame.  In
-        the mean time, the address of the prev frame is used as the
-        base address of this frame.  */
-      cache->base = frame_unwind_register_unsigned (next_frame, SP_REGNUM);
-      if (!fdata.frameless)
-       /* Frameless really means stackless.  */
-       cache->base = read_memory_addr (cache->base, wordsize);
+      CORE_ADDR saved_lr;
+      int make_frame = 0;
+
+      saved_lr = frame_unwind_register_unsigned (next_frame,
+                                                tdep->ppc_lr_regnum);
+      if (func == 0 && saved_lr == pc)
+       make_frame = 1;
+      else if (func != 0)
+       {
+         CORE_ADDR saved_func = get_pc_function_start (saved_lr);
+         if (func == saved_func)
+           make_frame = 1;
+       }
+
+      if (make_frame)
+       {
+         fdata.frameless = 0;
+         fdata.lr_offset = wordsize;
+       }
     }
+
+  if (!fdata.frameless)
+    /* Frameless really means stackless.  */
+    cache->base = read_memory_addr (cache->base, wordsize);
+
   trad_frame_set_value (cache->saved_regs, SP_REGNUM, cache->base);
 
   /* if != -1, fdata.saved_fpr is the smallest number of saved_fpr.
@@ -3320,6 +3451,8 @@ rs6000_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
   set_gdbarch_deprecated_extract_struct_value_address (gdbarch, rs6000_extract_struct_value_address);
 
   set_gdbarch_skip_prologue (gdbarch, rs6000_skip_prologue);
+  set_gdbarch_in_function_epilogue_p (gdbarch, rs6000_in_function_epilogue_p);
+
   set_gdbarch_inner_than (gdbarch, core_addr_lessthan);
   set_gdbarch_breakpoint_from_pc (gdbarch, rs6000_breakpoint_from_pc);
 
@@ -3354,10 +3487,21 @@ rs6000_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
 
   switch (info.osabi)
     {
+    case GDB_OSABI_LINUX:
+      /* FIXME: pgilliam/2005-10-21: Assume all PowerPC 64-bit linux systems
+         have altivec registers.  If not, ptrace will fail the first time it's
+         called to access one and will not be called again.  This wart will
+         be removed when Daniel Jacobowitz's proposal for autodetecting target
+         registers is implemented. */
+      if ((v->arch == bfd_arch_powerpc) && ((v->mach)== bfd_mach_ppc64))
+        {
+          tdep->ppc_vr0_regnum = 71;
+          tdep->ppc_vrsave_regnum = 104;
+        }
+      /* Fall Thru */
     case GDB_OSABI_NETBSD_AOUT:
     case GDB_OSABI_NETBSD_ELF:
     case GDB_OSABI_UNKNOWN:
-    case GDB_OSABI_LINUX:
       set_gdbarch_unwind_pc (gdbarch, rs6000_unwind_pc);
       frame_unwind_append_sniffer (gdbarch, rs6000_frame_sniffer);
       set_gdbarch_unwind_dummy_id (gdbarch, rs6000_unwind_dummy_id);
@@ -3398,14 +3542,6 @@ rs6000_dump_tdep (struct gdbarch *current_gdbarch, struct ui_file *file)
   /* FIXME: Dump gdbarch_tdep.  */
 }
 
-static struct cmd_list_element *info_powerpc_cmdlist = NULL;
-
-static void
-rs6000_info_powerpc_command (char *args, int from_tty)
-{
-  help_list (info_powerpc_cmdlist, "info powerpc ", class_info, gdb_stdout);
-}
-
 /* Initialization code.  */
 
 extern initialize_file_ftype _initialize_rs6000_tdep; /* -Wmissing-prototypes */
@@ -3415,9 +3551,4 @@ _initialize_rs6000_tdep (void)
 {
   gdbarch_register (bfd_arch_rs6000, rs6000_gdbarch_init, rs6000_dump_tdep);
   gdbarch_register (bfd_arch_powerpc, rs6000_gdbarch_init, rs6000_dump_tdep);
-
-  /* Add root prefix command for "info powerpc" commands */
-  add_prefix_cmd ("powerpc", class_info, rs6000_info_powerpc_command,
-                 _("Various POWERPC info specific commands."),
-                 &info_powerpc_cmdlist, "info powerpc ", 0, &infolist);
 }
This page took 0.028337 seconds and 4 git commands to generate.