2001-10-04 Frank Ch. Eigler <fche@redhat.com>
[binutils-gdb.git] / gdb / rs6000-tdep.c
index f61074ba2fe24f28f719e176cdd956e1588ec619..82c18c1dac2e9210aba04013c97ce9ce07724731 100644 (file)
@@ -1,5 +1,6 @@
 /* Target-dependent code for GDB, the GNU debugger.
-   Copyright 1986, 1987, 1989, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 2000
+   Copyright 1986, 1987, 1989, 1991, 1992, 1993, 1994, 1995, 1996, 1997,
+   1998, 1999, 2000, 2001
    Free Software Foundation, Inc.
 
    This file is part of GDB.
 #include "gdbcmd.h"
 #include "symfile.h"
 #include "objfiles.h"
-#include "xcoffsolib.h"
 #include "arch-utils.h"
+#include "regcache.h"
+#include "doublest.h"
 
 #include "bfd/libbfd.h"                /* for bfd_default_set_arch_mach */
 #include "coff/internal.h"     /* for libcoff.h */
 #include "bfd/libcoff.h"       /* for xcoff_data */
 
-/* Some important register numbers.  Keep these in the same order as in
-   /usr/mstsave.h `mstsave' structure, for easier processing. */
+#include "elf-bfd.h"
 
-#define        GP0_REGNUM 0            /* GPR register 0 */
-#define        TOC_REGNUM 2            /* TOC register */
-#define PS_REGNUM 65           /* Processor (or machine) status (%msr) */
-#define        CR_REGNUM 66            /* Condition register */
-#define        LR_REGNUM 67            /* Link register */
-#define        CTR_REGNUM 68           /* Count register */
+#include "ppc-tdep.h"
 
 /* If the kernel has to deliver a signal, it pushes a sigcontext
    structure on the stack and then calls the signal handler, passing
@@ -56,9 +52,6 @@
 #define SIG_FRAME_LR_OFFSET 108
 #define SIG_FRAME_FP_OFFSET 284
 
-/* Default offset from SP where the LR is stored */
-#define        DEFAULT_LR_SAVE 8
-
 /* To be used by skip_prologue. */
 
 struct rs6000_framedata
@@ -92,6 +85,7 @@ struct reg
 struct gdbarch_tdep
   {
     int wordsize;              /* size in bytes of fixed-point word */
+    int osabi;                 /* OS / ABI from ELF header */
     int *regoff;               /* byte offsets in register arrays */
     const struct reg *regs;    /* from current variant */
   };
@@ -126,7 +120,8 @@ void (*rs6000_set_host_arch_hook) (int) = NULL;
 
 static CORE_ADDR branch_dest (int opcode, int instr, CORE_ADDR pc,
                              CORE_ADDR safety);
-static CORE_ADDR skip_prologue (CORE_ADDR, struct rs6000_framedata *);
+static CORE_ADDR skip_prologue (CORE_ADDR, CORE_ADDR,
+                                struct rs6000_framedata *);
 static void frame_get_saved_regs (struct frame_info * fi,
                                  struct rs6000_framedata * fdatap);
 static CORE_ADDR frame_initial_stack_address (struct frame_info *);
@@ -143,7 +138,7 @@ static CORE_ADDR
 rs6000_skip_prologue (CORE_ADDR pc)
 {
   struct rs6000_framedata frame;
-  pc = skip_prologue (pc, &frame);
+  pc = skip_prologue (pc, 0, &frame);
   return pc;
 }
 
@@ -160,7 +155,7 @@ struct frame_extra_info
   CORE_ADDR initial_sp;                /* initial stack pointer. */
 };
 
-static void
+void
 rs6000_init_extra_frame_info (int fromleaf, struct frame_info *fi)
 {
   fi->extra_info = (struct frame_extra_info *)
@@ -185,7 +180,7 @@ rs6000_init_extra_frame_info (int fromleaf, struct frame_info *fi)
    not sure if it will be needed. The following function takes care of gpr's
    and fpr's only. */
 
-static void
+void
 rs6000_frame_init_saved_regs (struct frame_info *fi)
 {
   frame_get_saved_regs (fi, NULL);
@@ -208,7 +203,7 @@ rs6000_frame_args_address (struct frame_info *fi)
 static CORE_ADDR
 rs6000_saved_pc_after_call (struct frame_info *fi)
 {
-  return read_register (LR_REGNUM);
+  return read_register (PPC_LR_REGNUM);
 }
 
 /* Calculate the destination of a branch/jump.  Return -1 if not a branch.  */
@@ -246,7 +241,7 @@ branch_dest (int opcode, int instr, CORE_ADDR pc, CORE_ADDR safety)
 
       if (ext_op == 16)                /* br conditional register */
        {
-         dest = read_register (LR_REGNUM) & ~3;
+         dest = read_register (PPC_LR_REGNUM) & ~3;
 
          /* If we are about to return from a signal handler, dest is
             something like 0x3c90.  The current frame is a signal handler
@@ -265,13 +260,13 @@ branch_dest (int opcode, int instr, CORE_ADDR pc, CORE_ADDR safety)
 
       else if (ext_op == 528)  /* br cond to count reg */
        {
-         dest = read_register (CTR_REGNUM) & ~3;
+         dest = read_register (PPC_CTR_REGNUM) & ~3;
 
          /* If we are about to execute a system call, dest is something
             like 0x22fc or 0x3b00.  Upon completion the system call
             will return to the address in the link register.  */
          if (dest < TEXT_SEGMENT_BASE)
-           dest = read_register (LR_REGNUM) & ~3;
+           dest = read_register (PPC_LR_REGNUM) & ~3;
        }
       else
        return -1;
@@ -305,7 +300,8 @@ rs6000_breakpoint_from_pc (CORE_ADDR *bp_addr, int *bp_size)
 /* AIX does not support PT_STEP. Simulate it. */
 
 void
-rs6000_software_single_step (unsigned int signal, int insert_breakpoints_p)
+rs6000_software_single_step (enum target_signal signal,
+                            int insert_breakpoints_p)
 {
 #define        INSNLEN(OPCODE)  4
 
@@ -388,11 +384,63 @@ rs6000_software_single_step (unsigned int signal, int insert_breakpoints_p)
 
 #define GET_SRC_REG(x) (((x) >> 21) & 0x1f)
 
+/* Limit the number of skipped non-prologue instructions, as the examining
+   of the prologue is expensive.  */
+static int max_skip_non_prologue_insns = 10;
+
+/* Given PC representing the starting address of a function, and
+   LIM_PC which is the (sloppy) limit to which to scan when looking
+   for a prologue, attempt to further refine this limit by using
+   the line data in the symbol table.  If successful, a better guess
+   on where the prologue ends is returned, otherwise the previous
+   value of lim_pc is returned.  */
 static CORE_ADDR
-skip_prologue (CORE_ADDR pc, struct rs6000_framedata *fdata)
+refine_prologue_limit (CORE_ADDR pc, CORE_ADDR lim_pc)
+{
+  struct symtab_and_line prologue_sal;
+
+  prologue_sal = find_pc_line (pc, 0);
+  if (prologue_sal.line != 0)
+    {
+      int i;
+      CORE_ADDR addr = prologue_sal.end;
+
+      /* Handle the case in which compiler's optimizer/scheduler
+         has moved instructions into the prologue.  We scan ahead
+        in the function looking for address ranges whose corresponding
+        line number is less than or equal to the first one that we
+        found for the function.  (It can be less than when the
+        scheduler puts a body instruction before the first prologue
+        instruction.)  */
+      for (i = 2 * max_skip_non_prologue_insns; 
+           i > 0 && (lim_pc == 0 || addr < lim_pc);
+          i--)
+        {
+         struct symtab_and_line sal;
+
+         sal = find_pc_line (addr, 0);
+         if (sal.line == 0)
+           break;
+         if (sal.line <= prologue_sal.line 
+             && sal.symtab == prologue_sal.symtab)
+           {
+             prologue_sal = sal;
+           }
+         addr = sal.end;
+       }
+
+      if (lim_pc == 0 || prologue_sal.end < lim_pc)
+       lim_pc = prologue_sal.end;
+    }
+  return lim_pc;
+}
+
+
+static CORE_ADDR
+skip_prologue (CORE_ADDR pc, CORE_ADDR lim_pc, struct rs6000_framedata *fdata)
 {
   CORE_ADDR orig_pc = pc;
-  CORE_ADDR last_prologue_pc;
+  CORE_ADDR last_prologue_pc = pc;
   char buf[4];
   unsigned long op;
   long offset = 0;
@@ -402,6 +450,22 @@ skip_prologue (CORE_ADDR pc, struct rs6000_framedata *fdata)
   int framep = 0;
   int minimal_toc_loaded = 0;
   int prev_insn_was_prologue_insn = 1;
+  int num_skip_non_prologue_insns = 0;
+
+  /* Attempt to find the end of the prologue when no limit is specified.
+     Note that refine_prologue_limit() has been written so that it may
+     be used to "refine" the limits of non-zero PC values too, but this
+     is only safe if we 1) trust the line information provided by the
+     compiler and 2) iterate enough to actually find the end of the
+     prologue.  
+     
+     It may become a good idea at some point (for both performance and
+     accuracy) to unconditionally call refine_prologue_limit().  But,
+     until we can make a clear determination that this is beneficial,
+     we'll play it safe and only use it to obtain a limit when none
+     has been specified.  */
+  if (lim_pc == 0)
+    lim_pc = refine_prologue_limit (pc, lim_pc);
 
   memset (fdata, 0, sizeof (struct rs6000_framedata));
   fdata->saved_gpr = -1;
@@ -410,19 +474,22 @@ skip_prologue (CORE_ADDR pc, struct rs6000_framedata *fdata)
   fdata->frameless = 1;
   fdata->nosavedpc = 1;
 
-  pc -= 4;
-  for (;;)
+  for (;; pc += 4)
     {
-      pc += 4;
-
       /* Sometimes it isn't clear if an instruction is a prologue
          instruction or not.  When we encounter one of these ambiguous
         cases, we'll set prev_insn_was_prologue_insn to 0 (false).
         Otherwise, we'll assume that it really is a prologue instruction. */
       if (prev_insn_was_prologue_insn)
        last_prologue_pc = pc;
+
+      /* Stop scanning if we've hit the limit.  */
+      if (lim_pc != 0 && pc >= lim_pc)
+       break;
+
       prev_insn_was_prologue_insn = 1;
 
+      /* Fetch the instruction and convert it to an integer.  */
       if (target_read_memory (pc, buf, 4))
        break;
       op = extract_signed_integer (buf, 4);
@@ -636,7 +703,31 @@ skip_prologue (CORE_ADDR pc, struct rs6000_framedata *fdata)
        }
       else
        {
-         break;
+         /* Not a recognized prologue instruction.
+            Handle optimizer code motions into the prologue by continuing
+            the search if we have no valid frame yet or if the return
+            address is not yet saved in the frame.  */
+         if (fdata->frameless == 0
+             && (lr_reg == -1 || fdata->nosavedpc == 0))
+           break;
+
+         if (op == 0x4e800020          /* blr */
+             || op == 0x4e800420)      /* bctr */
+           /* Do not scan past epilogue in frameless functions or
+              trampolines.  */
+           break;
+         if ((op & 0xf4000000) == 0x40000000) /* bxx */
+           /* Never skip branches. */
+           break;
+
+         if (num_skip_non_prologue_insns++ > max_skip_non_prologue_insns)
+           /* Do not scan too many insns, scanning insns is expensive with
+              remote targets.  */
+           break;
+
+         /* Continue scanning.  */
+         prev_insn_was_prologue_insn = 0;
+         continue;
        }
     }
 
@@ -663,7 +754,7 @@ skip_prologue (CORE_ADDR pc, struct rs6000_framedata *fdata)
             function as well. */
 
          tmp = find_pc_misc_function (pc);
-         if (tmp >= 0 && STREQ (misc_function_vector[tmp].name, "main"))
+         if (tmp >= 0 && STREQ (misc_function_vector[tmp].name, main_name ()))
            return pc + 8;
        }
     }
@@ -679,8 +770,6 @@ skip_prologue (CORE_ADDR pc, struct rs6000_framedata *fdata)
   frames, etc. 
 *************************************************************************/
 
-extern int stop_stack_dummy;
-
 
 /* Pop the innermost frame, go back to the caller. */
 
@@ -695,7 +784,7 @@ rs6000_pop_frame (void)
   pc = read_pc ();
   sp = FRAME_FP (frame);
 
-  if (stop_stack_dummy)
+  if (PC_IN_CALL_DUMMY (frame->pc, frame->frame, frame->frame))
     {
       generic_pop_dummy_frame ();
       flush_cached_frames ();
@@ -710,7 +799,7 @@ rs6000_pop_frame (void)
      saved %pc value in the previous frame. */
 
   addr = get_pc_function_start (frame->pc);
-  (void) skip_prologue (addr, &fdata);
+  (void) skip_prologue (addr, frame->pc, &fdata);
 
   wordsize = TDEP->wordsize;
   if (fdata.frameless)
@@ -718,7 +807,7 @@ rs6000_pop_frame (void)
   else
     prev_sp = read_memory_addr (sp, wordsize);
   if (fdata.lr_offset == 0)
-    lr = read_register (LR_REGNUM);
+    lr = read_register (PPC_LR_REGNUM);
   else
     lr = read_memory_addr (prev_sp + fdata.lr_offset, wordsize);
 
@@ -757,7 +846,7 @@ rs6000_pop_frame (void)
 
 static void
 rs6000_fix_call_dummy (char *dummyname, CORE_ADDR pc, CORE_ADDR fun,
-                      int nargs, value_ptr *args, struct type *type,
+                      int nargs, struct value **args, struct type *type,
                       int gcc_p)
 {
 #define        TOC_ADDR_OFFSET         20
@@ -769,7 +858,7 @@ rs6000_fix_call_dummy (char *dummyname, CORE_ADDR pc, CORE_ADDR fun,
   if (rs6000_find_toc_address_hook != NULL)
     {
       CORE_ADDR tocvalue = (*rs6000_find_toc_address_hook) (fun);
-      write_register (TOC_REGNUM, tocvalue);
+      write_register (PPC_TOC_REGNUM, tocvalue);
     }
 }
 
@@ -790,7 +879,7 @@ rs6000_fix_call_dummy (char *dummyname, CORE_ADDR pc, CORE_ADDR fun,
    starting from r4. */
 
 static CORE_ADDR
-rs6000_push_arguments (int nargs, value_ptr *args, CORE_ADDR sp,
+rs6000_push_arguments (int nargs, struct value **args, CORE_ADDR sp,
                       int struct_return, CORE_ADDR struct_addr)
 {
   int ii;
@@ -801,7 +890,7 @@ rs6000_push_arguments (int nargs, value_ptr *args, CORE_ADDR sp,
   int f_argno = 0;             /* current floating point argno */
   int wordsize = TDEP->wordsize;
 
-  value_ptr arg = 0;
+  struct value *arg = 0;
   struct type *type;
 
   CORE_ADDR saved_sp;
@@ -920,7 +1009,7 @@ ran_out_of_registers_for_arguments:
 
       for (; jj < nargs; ++jj)
        {
-         value_ptr val = args[jj];
+         struct value *val = args[jj];
          space += ((TYPE_LENGTH (VALUE_TYPE (val))) + 3) & -4;
        }
 
@@ -992,7 +1081,7 @@ ran_out_of_registers_for_arguments:
 static CORE_ADDR
 ppc_push_return_address (CORE_ADDR pc, CORE_ADDR sp)
 {
-  write_register (LR_REGNUM, CALL_DUMMY_ADDRESS ());
+  write_register (PPC_LR_REGNUM, CALL_DUMMY_ADDRESS ());
   return sp;
 }
 
@@ -1044,19 +1133,55 @@ rs6000_extract_return_value (struct type *valtype, char *regbuf, char *valbuf)
 
 static CORE_ADDR rs6000_struct_return_address;
 
-/* Indirect function calls use a piece of trampoline code to do context
-   switching, i.e. to set the new TOC table. Skip such code if we are on
-   its first instruction (as when we have single-stepped to here). 
-   Also skip shared library trampoline code (which is different from
+/* Return whether handle_inferior_event() should proceed through code
+   starting at PC in function NAME when stepping.
+
+   The AIX -bbigtoc linker option generates functions @FIX0, @FIX1, etc. to
+   handle memory references that are too distant to fit in instructions
+   generated by the compiler.  For example, if 'foo' in the following
+   instruction:
+
+     lwz r9,foo(r2)
+
+   is greater than 32767, the linker might replace the lwz with a branch to
+   somewhere in @FIX1 that does the load in 2 instructions and then branches
+   back to where execution should continue.
+
+   GDB should silently step over @FIX code, just like AIX dbx does.
+   Unfortunately, the linker uses the "b" instruction for the branches,
+   meaning that the link register doesn't get set.  Therefore, GDB's usual
+   step_over_function() mechanism won't work.
+
+   Instead, use the IN_SOLIB_RETURN_TRAMPOLINE and SKIP_TRAMPOLINE_CODE hooks
+   in handle_inferior_event() to skip past @FIX code.  */
+
+int
+rs6000_in_solib_return_trampoline (CORE_ADDR pc, char *name)
+{
+  return name && !strncmp (name, "@FIX", 4);
+}
+
+/* Skip code that the user doesn't want to see when stepping:
+
+   1. Indirect function calls use a piece of trampoline code to do context
+   switching, i.e. to set the new TOC table.  Skip such code if we are on
+   its first instruction (as when we have single-stepped to here).
+
+   2. Skip shared library trampoline code (which is different from
    indirect function call trampolines).
+
+   3. Skip bigtoc fixup code.
+
    Result is desired PC to step until, or NULL if we are not in
-   trampoline code.  */
+   code that should be skipped.  */
 
 CORE_ADDR
 rs6000_skip_trampoline_code (CORE_ADDR pc)
 {
   register unsigned int ii, op;
+  int rel;
   CORE_ADDR solib_target_pc;
+  struct minimal_symbol *msymbol;
 
   static unsigned trampoline_code[] =
   {
@@ -1070,6 +1195,21 @@ rs6000_skip_trampoline_code (CORE_ADDR pc)
     0
   };
 
+  /* Check for bigtoc fixup code.  */
+  msymbol = lookup_minimal_symbol_by_pc (pc);
+  if (msymbol && rs6000_in_solib_return_trampoline (pc, SYMBOL_NAME (msymbol)))
+    {
+      /* Double-check that the third instruction from PC is relative "b".  */
+      op = read_memory_integer (pc + 8, 4);
+      if ((op & 0xfc000003) == 0x48000000)
+       {
+         /* Extract bits 6-29 as a signed 24-bit relative word address and
+            add it to the containing PC.  */
+         rel = ((int)(op << 6) >> 6);
+         return pc + 8 + rel;
+       }
+    }
+
   /* If pc is in a shared library trampoline, return its target.  */
   solib_target_pc = find_solib_trampoline_target (pc);
   if (solib_target_pc)
@@ -1088,7 +1228,7 @@ rs6000_skip_trampoline_code (CORE_ADDR pc)
 
 /* Determines whether the function FI has a frame on the stack or not.  */
 
-static int
+int
 rs6000_frameless_function_invocation (struct frame_info *fi)
 {
   CORE_ADDR func_start;
@@ -1116,13 +1256,13 @@ rs6000_frameless_function_invocation (struct frame_info *fi)
        return 0;
     }
 
-  (void) skip_prologue (func_start, &fdata);
+  (void) skip_prologue (func_start, fi->pc, &fdata);
   return fdata.frameless;
 }
 
 /* Return the PC saved in a frame */
 
-static CORE_ADDR
+CORE_ADDR
 rs6000_frame_saved_pc (struct frame_info *fi)
 {
   CORE_ADDR func_start;
@@ -1142,7 +1282,7 @@ rs6000_frame_saved_pc (struct frame_info *fi)
   if (!func_start)
     return 0;
 
-  (void) skip_prologue (func_start, &fdata);
+  (void) skip_prologue (func_start, fi->pc, &fdata);
 
   if (fdata.lr_offset == 0 && fi->next != NULL)
     {
@@ -1155,7 +1295,7 @@ rs6000_frame_saved_pc (struct frame_info *fi)
     }
 
   if (fdata.lr_offset == 0)
-    return read_register (LR_REGNUM);
+    return read_register (PPC_LR_REGNUM);
 
   return read_memory_addr (FRAME_CHAIN (fi) + fdata.lr_offset, wordsize);
 }
@@ -1177,7 +1317,7 @@ frame_get_saved_regs (struct frame_info *fi, struct rs6000_framedata *fdatap)
   if (fdatap == NULL)
     {
       fdatap = &work_fdata;
-      (void) skip_prologue (get_pc_function_start (fi->pc), fdatap);
+      (void) skip_prologue (get_pc_function_start (fi->pc), fi->pc, fdatap);
     }
 
   frame_saved_regs_zalloc (fi);
@@ -1226,12 +1366,12 @@ frame_get_saved_regs (struct frame_info *fi, struct rs6000_framedata *fdatap)
   /* If != 0, fdatap->cr_offset is the offset from the frame that holds
      the CR.  */
   if (fdatap->cr_offset != 0)
-    fi->saved_regs[CR_REGNUM] = frame_addr + fdatap->cr_offset;
+    fi->saved_regs[PPC_CR_REGNUM] = frame_addr + fdatap->cr_offset;
 
   /* If != 0, fdatap->lr_offset is the offset from the frame that holds
      the LR.  */
   if (fdatap->lr_offset != 0)
-    fi->saved_regs[LR_REGNUM] = frame_addr + fdatap->lr_offset;
+    fi->saved_regs[PPC_LR_REGNUM] = frame_addr + fdatap->lr_offset;
 }
 
 /* Return the address of a frame. This is the inital %sp value when the frame
@@ -1253,7 +1393,7 @@ frame_initial_stack_address (struct frame_info *fi)
 
   /* find out if this function is using an alloca register.. */
 
-  (void) skip_prologue (get_pc_function_start (fi->pc), &fdata);
+  (void) skip_prologue (get_pc_function_start (fi->pc), fi->pc, &fdata);
 
   /* if saved registers of this frame are not known yet, read and cache them. */
 
@@ -1316,7 +1456,7 @@ frame_initial_stack_address (struct frame_info *fi)
 /* In the case of the RS/6000, the frame's nominal address
    is the address of a 4-byte word containing the calling frame's address.  */
 
-static CORE_ADDR
+CORE_ADDR
 rs6000_frame_chain (struct frame_info *thisframe)
 {
   CORE_ADDR fp, fpp, lr;
@@ -1341,7 +1481,7 @@ rs6000_frame_chain (struct frame_info *thisframe)
   else
     fp = read_memory_addr ((thisframe)->frame, wordsize);
 
-  lr = read_register (LR_REGNUM);
+  lr = read_register (PPC_LR_REGNUM);
   if (lr == entry_point_address ())
     if (fp != 0 && (fpp = read_memory_addr (fp, wordsize)) != 0)
       if (PC_IN_CALL_DUMMY (lr, fpp, fpp))
@@ -1406,7 +1546,7 @@ rs6000_register_virtual_size (int n)
    of data in register N.  */
 
 static struct type *
-rs6000_register_virtual_type (n)
+rs6000_register_virtual_type (int n)
 {
   struct gdbarch_tdep *tdep = TDEP;
   const struct reg *reg = tdep->regs + n;
@@ -1503,7 +1643,7 @@ rs6000_store_return_value (struct type *type, char *valbuf)
                          TYPE_LENGTH (type));
   else
     /* Everything else is returned in GPR3 and up. */
-    write_register_bytes (REGISTER_BYTE (GP0_REGNUM + 3), valbuf,
+    write_register_bytes (REGISTER_BYTE (PPC_GP0_REGNUM + 3), valbuf,
                          TYPE_LENGTH (type));
 }
 
@@ -1550,11 +1690,11 @@ rs6000_create_inferior (int pid)
    a function pointer would require allocation of a TOC 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 macro to get the
+   function pointers), find_function_addr uses this function to get the
    function address from a function pointer.  */
 
-/* Return nonzero if ADDR (a function pointer) is in the data space and
-   is therefore a special function pointer.  */
+/* Return real function address if ADDR (a function pointer) is in the data
+   space and is therefore a special function pointer.  */
 
 CORE_ADDR
 rs6000_convert_from_func_ptr_addr (CORE_ADDR addr)
@@ -1912,6 +2052,85 @@ find_variant_by_arch (enum bfd_architecture arch, unsigned long mach)
   return NULL;
 }
 
+
+
+\f
+static void
+process_note_abi_tag_sections (bfd *abfd, asection *sect, void *obj)
+{
+  int *os_ident_ptr = obj;
+  const char *name;
+  unsigned int sectsize;
+
+  name = bfd_get_section_name (abfd, sect);
+  sectsize = bfd_section_size (abfd, sect);
+  if (strcmp (name, ".note.ABI-tag") == 0 && sectsize > 0)
+    {
+      unsigned int name_length, data_length, note_type;
+      char *note = alloca (sectsize);
+
+      bfd_get_section_contents (abfd, sect, note,
+                                (file_ptr) 0, (bfd_size_type) sectsize);
+
+      name_length = bfd_h_get_32 (abfd, note);
+      data_length = bfd_h_get_32 (abfd, note + 4);
+      note_type   = bfd_h_get_32 (abfd, note + 8);
+
+      if (name_length == 4 && data_length == 16 && note_type == 1
+          && strcmp (note + 12, "GNU") == 0)
+       {
+         int os_number = bfd_h_get_32 (abfd, note + 16);
+
+         /* The case numbers are from abi-tags in glibc */
+         switch (os_number)
+           {
+           case 0 :
+             *os_ident_ptr = ELFOSABI_LINUX;
+             break;
+           case 1 :
+             *os_ident_ptr = ELFOSABI_HURD;
+             break;
+           case 2 :
+             *os_ident_ptr = ELFOSABI_SOLARIS;
+             break;
+           default :
+             internal_error (__FILE__, __LINE__,
+                             "process_note_abi_sections: unknown OS number %d",
+                             os_number);
+             break;
+           }
+       }
+    }
+}
+
+/* Return one of the ELFOSABI_ constants for BFDs representing ELF
+   executables.  If it's not an ELF executable or if the OS/ABI couldn't
+   be determined, simply return -1. */
+
+static int
+get_elfosabi (bfd *abfd)
+{
+  int elfosabi = -1;
+
+  if (abfd != NULL && bfd_get_flavour (abfd) == bfd_target_elf_flavour)
+    {
+      elfosabi = elf_elfheader (abfd)->e_ident[EI_OSABI];
+
+      /* When elfosabi is 0 (ELFOSABI_NONE), this is supposed to indicate
+         that we're on a SYSV system.  However, GNU/Linux uses a note section
+        to record OS/ABI info, but leaves e_ident[EI_OSABI] zero.  So we
+        have to check the note sections too. */
+      if (elfosabi == 0)
+       {
+         bfd_map_over_sections (abfd,
+                                process_note_abi_tag_sections,
+                                &elfosabi);
+       }
+    }
+
+  return elfosabi;
+}
+
 \f
 
 /* Initialize the current architecture based on INFO.  If possible, re-use an
@@ -1926,33 +2145,44 @@ rs6000_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
 {
   struct gdbarch *gdbarch;
   struct gdbarch_tdep *tdep;
-  int wordsize, fromexec, power, i, off;
+  int wordsize, from_xcoff_exec, from_elf_exec, power, i, off;
   struct reg *regs;
   const struct variant *v;
   enum bfd_architecture arch;
   unsigned long mach;
   bfd abfd;
+  int osabi, sysv_abi;
 
-  fromexec = info.abfd && info.abfd->format == bfd_object &&
+  from_xcoff_exec = info.abfd && info.abfd->format == bfd_object &&
     bfd_get_flavour (info.abfd) == bfd_target_xcoff_flavour;
 
-  /* Check word size.  If INFO is from a binary file, infer it from that,
-     else use the previously-inferred size. */
-  if (fromexec)
+  from_elf_exec = info.abfd && info.abfd->format == bfd_object &&
+    bfd_get_flavour (info.abfd) == bfd_target_elf_flavour;
+
+  sysv_abi = info.abfd && bfd_get_flavour (info.abfd) == bfd_target_elf_flavour;
+
+  osabi = get_elfosabi (info.abfd);
+
+  /* Check word size.  If INFO is from a binary file, infer it from
+     that, else choose a likely default. */
+  if (from_xcoff_exec)
     {
       if (xcoff_data (info.abfd)->xcoff64)
        wordsize = 8;
       else
        wordsize = 4;
     }
-  else
+  else if (from_elf_exec)
     {
-      tdep = TDEP;
-      if (tdep)
-       wordsize = tdep->wordsize;
+      if (elf_elfheader (info.abfd)->e_ident[EI_CLASS] == ELFCLASS64)
+       wordsize = 8;
       else
        wordsize = 4;
     }
+  else
+    {
+      wordsize = 4;
+    }
 
   /* Find a candidate among extant architectures. */
   for (arches = gdbarch_list_lookup_by_info (arches, &info);
@@ -1963,7 +2193,7 @@ rs6000_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
          meaningful, because 64-bit CPUs can run in 32-bit mode.  So, perform
          separate word size check. */
       tdep = gdbarch_tdep (arches->gdbarch);
-      if (tdep && tdep->wordsize == wordsize)
+      if (tdep && tdep->wordsize == wordsize && tdep->osabi == osabi)
        return arches->gdbarch;
     }
 
@@ -1975,9 +2205,9 @@ rs6000_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
        - "set arch"            trust blindly
        - GDB startup           useless but harmless */
 
-  if (!fromexec)
+  if (!from_xcoff_exec)
     {
-      arch = info.bfd_architecture;
+      arch = info.bfd_arch_info->arch;
       mach = info.bfd_arch_info->mach;
     }
   else
@@ -1989,6 +2219,7 @@ rs6000_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
     }
   tdep = xmalloc (sizeof (struct gdbarch_tdep));
   tdep->wordsize = wordsize;
+  tdep->osabi = osabi;
   gdbarch = gdbarch_alloc (&info, tdep);
   power = arch == bfd_arch_rs6000;
 
@@ -2048,12 +2279,13 @@ rs6000_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
   set_gdbarch_call_dummy_breakpoint_offset_p (gdbarch, 1);
   set_gdbarch_call_dummy_breakpoint_offset (gdbarch, 0);
   set_gdbarch_call_dummy_start_offset (gdbarch, 0);
-  set_gdbarch_pc_in_call_dummy (gdbarch, rs6000_pc_in_call_dummy);
+  set_gdbarch_pc_in_call_dummy (gdbarch, generic_pc_in_call_dummy);
   set_gdbarch_call_dummy_p (gdbarch, 1);
   set_gdbarch_call_dummy_stack_adjust_p (gdbarch, 0);
   set_gdbarch_get_saved_register (gdbarch, generic_get_saved_register);
   set_gdbarch_fix_call_dummy (gdbarch, rs6000_fix_call_dummy);
   set_gdbarch_push_dummy_frame (gdbarch, generic_push_dummy_frame);
+  set_gdbarch_save_dummy_frame_tos (gdbarch, generic_save_dummy_frame_tos);
   set_gdbarch_push_return_address (gdbarch, ppc_push_return_address);
   set_gdbarch_believe_pcc_promotion (gdbarch, 1);
   set_gdbarch_coerce_float_to_double (gdbarch, rs6000_coerce_float_to_double);
@@ -2063,16 +2295,17 @@ rs6000_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
   set_gdbarch_register_convert_to_raw (gdbarch, rs6000_register_convert_to_raw);
 
   set_gdbarch_extract_return_value (gdbarch, rs6000_extract_return_value);
-  set_gdbarch_push_arguments (gdbarch, rs6000_push_arguments);
+  
+  if (sysv_abi)
+    set_gdbarch_push_arguments (gdbarch, ppc_sysv_abi_push_arguments);
+  else
+    set_gdbarch_push_arguments (gdbarch, rs6000_push_arguments);
 
   set_gdbarch_store_struct_return (gdbarch, rs6000_store_struct_return);
   set_gdbarch_store_return_value (gdbarch, rs6000_store_return_value);
   set_gdbarch_extract_struct_value_address (gdbarch, rs6000_extract_struct_value_address);
   set_gdbarch_use_struct_convention (gdbarch, generic_use_struct_convention);
 
-  set_gdbarch_frame_init_saved_regs (gdbarch, rs6000_frame_init_saved_regs);
-  set_gdbarch_init_extra_frame_info (gdbarch, rs6000_init_extra_frame_info);
-
   set_gdbarch_pop_frame (gdbarch, rs6000_pop_frame);
 
   set_gdbarch_skip_prologue (gdbarch, rs6000_skip_prologue);
@@ -2084,10 +2317,36 @@ rs6000_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
   /* Not sure on this. FIXMEmgo */
   set_gdbarch_frame_args_skip (gdbarch, 8);
 
-  set_gdbarch_frameless_function_invocation (gdbarch, rs6000_frameless_function_invocation);
-  set_gdbarch_frame_chain (gdbarch, rs6000_frame_chain);
   set_gdbarch_frame_chain_valid (gdbarch, file_frame_chain_valid);
-  set_gdbarch_frame_saved_pc (gdbarch, rs6000_frame_saved_pc);
+  if (osabi == ELFOSABI_LINUX)
+    {
+      set_gdbarch_frameless_function_invocation (gdbarch,
+       ppc_linux_frameless_function_invocation);
+      set_gdbarch_frame_chain (gdbarch, ppc_linux_frame_chain);
+      set_gdbarch_frame_saved_pc (gdbarch, ppc_linux_frame_saved_pc);
+
+      set_gdbarch_frame_init_saved_regs (gdbarch,
+                                        ppc_linux_frame_init_saved_regs);
+      set_gdbarch_init_extra_frame_info (gdbarch,
+                                        ppc_linux_init_extra_frame_info);
+
+      set_gdbarch_memory_remove_breakpoint (gdbarch,
+                                           ppc_linux_memory_remove_breakpoint);
+    }
+  else
+    {
+      set_gdbarch_frameless_function_invocation (gdbarch,
+       rs6000_frameless_function_invocation);
+      set_gdbarch_frame_chain (gdbarch, rs6000_frame_chain);
+      set_gdbarch_frame_saved_pc (gdbarch, rs6000_frame_saved_pc);
+
+      set_gdbarch_frame_init_saved_regs (gdbarch, rs6000_frame_init_saved_regs);
+      set_gdbarch_init_extra_frame_info (gdbarch, rs6000_init_extra_frame_info);
+
+      /* Handle RS/6000 function pointers.  */
+      set_gdbarch_convert_from_func_ptr_addr (gdbarch,
+       rs6000_convert_from_func_ptr_addr);
+    }
   set_gdbarch_frame_args_address (gdbarch, rs6000_frame_args_address);
   set_gdbarch_frame_locals_address (gdbarch, rs6000_frame_args_address);
   set_gdbarch_saved_pc_after_call (gdbarch, rs6000_saved_pc_after_call);
@@ -2102,7 +2361,7 @@ rs6000_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
 /* Initialization code.  */
 
 void
-_initialize_rs6000_tdep ()
+_initialize_rs6000_tdep (void)
 {
   register_gdbarch_init (bfd_arch_rs6000, rs6000_gdbarch_init);
   register_gdbarch_init (bfd_arch_powerpc, rs6000_gdbarch_init);