Add support for FreeBSD/i386 ELF.
[deliverable/binutils-gdb.git] / gdb / hppa-tdep.c
index 25dbcfba3c269f584783ac03431e23203391989e..e7adf10bb814509f73243bf3199ef837e90386c3 100644 (file)
@@ -1,6 +1,5 @@
 /* Target-dependent code for the HP PA architecture, for GDB.
-   Copyright 1986, 87, 89, 90, 91, 92, 93, 94, 95, 96, 1999
-   Free Software Foundation, Inc.
+   Copyright 1986, 1987, 1989-1996, 1999-2000 Free Software Foundation, Inc.
 
    Contributed by the Center for Software Science at the
    University of Utah (pa-gdb-bugs@cs.utah.edu).
@@ -50,7 +49,7 @@
 /*#include <sys/user.h>         After a.out.h  */
 #include <sys/file.h>
 #include "gdb_stat.h"
-#include "wait.h"
+#include "gdb_wait.h"
 
 #include "gdbcore.h"
 #include "gdbcmd.h"
@@ -58,9 +57,6 @@
 #include "symfile.h"
 #include "objfiles.h"
 
-/* To support asking "What CPU is this?" */
-#include <unistd.h>
-
 /* To support detection of the pseudo-initial frame
    that threads have. */
 #define THREAD_INITIAL_FRAME_SYMBOL  "__pthread_exit"
@@ -125,10 +121,11 @@ static void internalize_unwinds PARAMS ((struct objfile *,
                                         asection *, unsigned int,
                                         unsigned int, CORE_ADDR));
 static void pa_print_registers PARAMS ((char *, int, int));
-static void pa_strcat_registers PARAMS ((char *, int, int, GDB_FILE *));
+static void pa_strcat_registers (char *, int, int, struct ui_file *);
 static void pa_register_look_aside PARAMS ((char *, int, long *));
 static void pa_print_fp_reg PARAMS ((int));
-static void pa_strcat_fp_reg PARAMS ((int, GDB_FILE *, enum precision_type));
+static void pa_strcat_fp_reg (int, struct ui_file *, enum precision_type);
+static void record_text_segment_lowaddr PARAMS ((bfd *, asection *, void *));
 
 typedef struct
   {
@@ -158,7 +155,7 @@ hppa_use_struct_convention (gcc_p, type)
      int gcc_p;
      struct type *type;
 {
-  return (TYPE_LENGTH (type) > 8);
+  return (TYPE_LENGTH (type) > 2 * REGISTER_SIZE);
 }
 \f
 
@@ -310,6 +307,20 @@ compare_unwind_entries (arg1, arg2)
     return 0;
 }
 
+static CORE_ADDR low_text_segment_address;
+
+static void
+record_text_segment_lowaddr (abfd, section, ignored)
+     bfd *abfd ATTRIBUTE_UNUSED;
+     asection *section;
+     PTR ignored ATTRIBUTE_UNUSED;
+{
+  if ((section->flags & (SEC_ALLOC | SEC_LOAD | SEC_READONLY)
+       == (SEC_ALLOC | SEC_LOAD | SEC_READONLY))
+      && section->vma < low_text_segment_address)
+    low_text_segment_address = section->vma;
+}
+
 static void
 internalize_unwinds (objfile, table, section, entries, size, text_offset)
      struct objfile *objfile;
@@ -326,6 +337,26 @@ internalize_unwinds (objfile, table, section, entries, size, text_offset)
       unsigned i;
       char *buf = alloca (size);
 
+      low_text_segment_address = -1;
+
+      /* If addresses are 64 bits wide, then unwinds are supposed to
+        be segment relative offsets instead of absolute addresses. 
+
+        Note that when loading a shared library (text_offset != 0) the
+        unwinds are already relative to the text_offset that will be
+        passed in.  */
+      if (TARGET_PTR_BIT == 64 && text_offset == 0)
+       {
+         bfd_map_over_sections (objfile->obfd,
+                                record_text_segment_lowaddr, (PTR) NULL);
+
+         /* ?!? Mask off some low bits.  Should this instead subtract
+            out the lowest section's filepos or something like that?
+            This looks very hokey to me.  */
+         low_text_segment_address &= ~0xfff;
+         text_offset += low_text_segment_address;
+       }
+
       bfd_get_section_contents (objfile->obfd, section, buf, 0, size);
 
       /* Now internalize the information being careful to handle host/target
@@ -391,9 +422,9 @@ static void
 read_unwind_info (objfile)
      struct objfile *objfile;
 {
-  asection *unwind_sec, *elf_unwind_sec, *stub_unwind_sec;
-  unsigned unwind_size, elf_unwind_size, stub_unwind_size, total_size;
-  unsigned index, unwind_entries, elf_unwind_entries;
+  asection *unwind_sec, *stub_unwind_sec;
+  unsigned unwind_size, stub_unwind_size, total_size;
+  unsigned index, unwind_entries;
   unsigned stub_entries, total_entries;
   CORE_ADDR text_offset;
   struct obj_unwind_info *ui;
@@ -407,35 +438,32 @@ read_unwind_info (objfile)
   ui->cache = NULL;
   ui->last = -1;
 
-  /* Get hooks to all unwind sections.   Note there is no linker-stub unwind
-     section in ELF at the moment.  */
-  unwind_sec = bfd_get_section_by_name (objfile->obfd, "$UNWIND_START$");
-  elf_unwind_sec = bfd_get_section_by_name (objfile->obfd, ".PARISC.unwind");
-  stub_unwind_sec = bfd_get_section_by_name (objfile->obfd, "$UNWIND_END$");
-
-  /* Get sizes and unwind counts for all sections.  */
-  if (unwind_sec)
-    {
-      unwind_size = bfd_section_size (objfile->obfd, unwind_sec);
-      unwind_entries = unwind_size / UNWIND_ENTRY_SIZE;
-    }
-  else
+  /* For reasons unknown the HP PA64 tools generate multiple unwinder
+     sections in a single executable.  So we just iterate over every
+     section in the BFD looking for unwinder sections intead of trying
+     to do a lookup with bfd_get_section_by_name. 
+
+     First determine the total size of the unwind tables so that we
+     can allocate memory in a nice big hunk.  */
+  total_entries = 0;
+  for (unwind_sec = objfile->obfd->sections;
+       unwind_sec;
+       unwind_sec = unwind_sec->next)
     {
-      unwind_size = 0;
-      unwind_entries = 0;
-    }
+      if (strcmp (unwind_sec->name, "$UNWIND_START$") == 0
+         || strcmp (unwind_sec->name, ".PARISC.unwind") == 0)
+       {
+         unwind_size = bfd_section_size (objfile->obfd, unwind_sec);
+         unwind_entries = unwind_size / UNWIND_ENTRY_SIZE;
 
-  if (elf_unwind_sec)
-    {
-      elf_unwind_size = bfd_section_size (objfile->obfd, elf_unwind_sec);      /* purecov: deadcode */
-      elf_unwind_entries = elf_unwind_size / UNWIND_ENTRY_SIZE;                /* purecov: deadcode */
-    }
-  else
-    {
-      elf_unwind_size = 0;
-      elf_unwind_entries = 0;
+         total_entries += unwind_entries;
+       }
     }
 
+  /* Now compute the size of the stub unwinds.  Note the ELF tools do not
+     use stub unwinds at the curren time.  */
+  stub_unwind_sec = bfd_get_section_by_name (objfile->obfd, "$UNWIND_END$");
+
   if (stub_unwind_sec)
     {
       stub_unwind_size = bfd_section_size (objfile->obfd, stub_unwind_sec);
@@ -448,7 +476,7 @@ read_unwind_info (objfile)
     }
 
   /* Compute total number of unwind entries and their total size.  */
-  total_entries = unwind_entries + elf_unwind_entries + stub_entries;
+  total_entries += stub_entries;
   total_size = total_entries * sizeof (struct unwind_table_entry);
 
   /* Allocate memory for the unwind table.  */
@@ -456,16 +484,26 @@ read_unwind_info (objfile)
     obstack_alloc (&objfile->psymbol_obstack, total_size);
   ui->last = total_entries - 1;
 
-  /* Internalize the standard unwind entries.  */
+  /* Now read in each unwind section and internalize the standard unwind
+     entries.  */
   index = 0;
-  internalize_unwinds (objfile, &ui->table[index], unwind_sec,
-                      unwind_entries, unwind_size, text_offset);
-  index += unwind_entries;
-  internalize_unwinds (objfile, &ui->table[index], elf_unwind_sec,
-                      elf_unwind_entries, elf_unwind_size, text_offset);
-  index += elf_unwind_entries;
-
-  /* Now internalize the stub unwind entries.  */
+  for (unwind_sec = objfile->obfd->sections;
+       unwind_sec;
+       unwind_sec = unwind_sec->next)
+    {
+      if (strcmp (unwind_sec->name, "$UNWIND_START$") == 0
+         || strcmp (unwind_sec->name, ".PARISC.unwind") == 0)
+       {
+         unwind_size = bfd_section_size (objfile->obfd, unwind_sec);
+         unwind_entries = unwind_size / UNWIND_ENTRY_SIZE;
+
+         internalize_unwinds (objfile, &ui->table[index], unwind_sec,
+                              unwind_entries, unwind_size, text_offset);
+         index += unwind_entries;
+       }
+    }
+
+  /* Now read in and internalize the stub unwind entries.  */
   if (stub_unwind_size > 0)
     {
       unsigned int i;
@@ -510,6 +548,7 @@ read_unwind_info (objfile)
                       sizeof (obj_private_data_t));
       obj_private->unwind_info = NULL;
       obj_private->so_info = NULL;
+      obj_private->dp = 0;
 
       objfile->obj_private = (PTR) obj_private;
     }
@@ -544,7 +583,7 @@ find_unwind_entry (pc)
       {
        read_unwind_info (objfile);
        if (objfile->obj_private == NULL)
-         error ("Internal error reading unwind information.");         /* purecov: deadcode */
+         error ("Internal error reading unwind information.");
        ui = ((obj_private_data_t *) (objfile->obj_private))->unwind_info;
       }
 
@@ -620,7 +659,9 @@ pc_in_interrupt_handler (pc)
 }
 
 /* Called when no unwind descriptor was found for PC.  Returns 1 if it
-   appears that PC is in a linker stub.  */
+   appears that PC is in a linker stub.
+
+   ?!? Need to handle stubs which appear in PA64 code.  */
 
 static int
 pc_in_linker_stub (pc)
@@ -764,7 +805,7 @@ rp_saved (pc)
     }
 
   if (u->Save_RP)
-    return -20;
+    return (TARGET_PTR_BIT == 64 ? -16 : -20);
   else if (u->stub_unwind.stub_type != 0)
     {
       switch (u->stub_unwind.stub_type)
@@ -831,7 +872,29 @@ hppa_frame_saved_pc (frame)
      are saved in the exact same order as GDB numbers registers.  How
      convienent.  */
   if (pc_in_interrupt_handler (pc))
-    return read_memory_integer (frame->frame + PC_REGNUM * 4, 4) & ~0x3;
+    return read_memory_integer (frame->frame + PC_REGNUM * 4,
+                               TARGET_PTR_BIT / 8) & ~0x3;
+
+  if ((frame->pc >= frame->frame
+       && frame->pc <= (frame->frame
+                        /* A call dummy is sized in words, but it is
+                           actually a series of instructions.  Account
+                           for that scaling factor.  */
+                        + ((REGISTER_SIZE / INSTRUCTION_SIZE)
+                           * CALL_DUMMY_LENGTH)
+                        /* Similarly we have to account for 64bit
+                           wide register saves.  */
+                        + (32 * REGISTER_SIZE)
+                        /* We always consider FP regs 8 bytes long.  */
+                        + (NUM_REGS - FP0_REGNUM) * 8
+                        /* Similarly we have to account for 64bit
+                           wide register saves.  */
+                        + (6 * REGISTER_SIZE))))
+    {
+      return read_memory_integer ((frame->frame
+                                  + (TARGET_PTR_BIT == 64 ? -16 : -20)),
+                                 TARGET_PTR_BIT / 8) & ~0x3;
+    }
 
 #ifdef FRAME_SAVED_PC_IN_SIGTRAMP
   /* Deal with signal handler caller frames too.  */
@@ -860,19 +923,23 @@ hppa_frame_saved_pc (frame)
          struct frame_saved_regs saved_regs;
 
          get_frame_saved_regs (frame->next, &saved_regs);
-         if (read_memory_integer (saved_regs.regs[FLAGS_REGNUM], 4) & 0x2)
+         if (read_memory_integer (saved_regs.regs[FLAGS_REGNUM],
+                                  TARGET_PTR_BIT / 8) & 0x2)
            {
-             pc = read_memory_integer (saved_regs.regs[31], 4) & ~0x3;
+             pc = read_memory_integer (saved_regs.regs[31],
+                                       TARGET_PTR_BIT / 8) & ~0x3;
 
              /* Syscalls are really two frames.  The syscall stub itself
                 with a return pointer in %rp and the kernel call with
                 a return pointer in %r31.  We return the %rp variant
                 if %r31 is the same as frame->pc.  */
              if (pc == frame->pc)
-               pc = read_memory_integer (saved_regs.regs[RP_REGNUM], 4) & ~0x3;
+               pc = read_memory_integer (saved_regs.regs[RP_REGNUM],
+                                         TARGET_PTR_BIT / 8) & ~0x3;
            }
          else
-           pc = read_memory_integer (saved_regs.regs[RP_REGNUM], 4) & ~0x3;
+           pc = read_memory_integer (saved_regs.regs[RP_REGNUM],
+                                     TARGET_PTR_BIT / 8) & ~0x3;
        }
       else
        pc = read_register (ret_regnum) & ~0x3;
@@ -896,19 +963,23 @@ hppa_frame_saved_pc (frame)
          struct frame_saved_regs saved_regs;
 
          get_frame_saved_regs (frame->next, &saved_regs);
-         if (read_memory_integer (saved_regs.regs[FLAGS_REGNUM], 4) & 0x2)
+         if (read_memory_integer (saved_regs.regs[FLAGS_REGNUM],
+                                  TARGET_PTR_BIT / 8) & 0x2)
            {
-             pc = read_memory_integer (saved_regs.regs[31], 4) & ~0x3;
+             pc = read_memory_integer (saved_regs.regs[31],
+                                       TARGET_PTR_BIT / 8) & ~0x3;
 
              /* Syscalls are really two frames.  The syscall stub itself
                 with a return pointer in %rp and the kernel call with
                 a return pointer in %r31.  We return the %rp variant
                 if %r31 is the same as frame->pc.  */
              if (pc == frame->pc)
-               pc = read_memory_integer (saved_regs.regs[RP_REGNUM], 4) & ~0x3;
+               pc = read_memory_integer (saved_regs.regs[RP_REGNUM],
+                                         TARGET_PTR_BIT / 8) & ~0x3;
            }
          else
-           pc = read_memory_integer (saved_regs.regs[RP_REGNUM], 4) & ~0x3;
+           pc = read_memory_integer (saved_regs.regs[RP_REGNUM],
+                                     TARGET_PTR_BIT / 8) & ~0x3;
        }
       else if (rp_offset == 0)
        {
@@ -918,7 +989,8 @@ hppa_frame_saved_pc (frame)
       else
        {
          old_pc = pc;
-         pc = read_memory_integer (frame->frame + rp_offset, 4) & ~0x3;
+         pc = read_memory_integer (frame->frame + rp_offset,
+                                   TARGET_PTR_BIT / 8) & ~0x3;
        }
     }
 
@@ -1033,6 +1105,12 @@ frame_chain (frame)
   CORE_ADDR frame_base;
   struct frame_info *tmp_frame;
 
+  /* A frame in the current frame list, or zero.  */
+  struct frame_info *saved_regs_frame = 0;
+  /* Where the registers were saved in saved_regs_frame.
+     If saved_regs_frame is zero, this is garbage.  */
+  struct frame_saved_regs saved_regs;
+
   CORE_ADDR caller_pc;
 
   struct minimal_symbol *min_frame_symbol;
@@ -1073,7 +1151,8 @@ frame_chain (frame)
      pull the old stack pointer from.  Also see frame_saved_pc for
      code to dig a saved PC out of the save state structure.  */
   if (pc_in_interrupt_handler (frame->pc))
-    frame_base = read_memory_integer (frame->frame + SP_REGNUM * 4, 4);
+    frame_base = read_memory_integer (frame->frame + SP_REGNUM * 4,
+                                     TARGET_PTR_BIT / 8);
 #ifdef FRAME_BASE_BEFORE_SIGTRAMP
   else if (frame->signal_handler_caller)
     {
@@ -1107,7 +1186,7 @@ frame_chain (frame)
      The previous frame pointer is found at the top of the current frame.  */
   if (caller_framesize == -1 && my_framesize == -1)
     {
-      return read_memory_integer (frame_base, 4);
+      return read_memory_integer (frame_base, TARGET_PTR_BIT / 8);
     }
   /* Caller has a frame pointer, but callee does not.  This is a little
      more difficult as GCC and HP C lay out locals and callee register save
@@ -1125,8 +1204,7 @@ frame_chain (frame)
      We use information from unwind descriptors to determine if %r3
      is saved into the stack (Entry_GR field has this information).  */
 
-  tmp_frame = frame;
-  while (tmp_frame)
+  for (tmp_frame = frame; tmp_frame; tmp_frame = tmp_frame->next)
     {
       u = find_unwind_entry (tmp_frame->pc);
 
@@ -1146,14 +1224,25 @@ frame_chain (frame)
          return (CORE_ADDR) 0;
        }
 
-      /* Entry_GR specifies the number of callee-saved general registers
-         saved in the stack.  It starts at %r3, so %r3 would be 1.  */
-      if (u->Entry_GR >= 1 || u->Save_SP
+      if (u->Save_SP
          || tmp_frame->signal_handler_caller
          || pc_in_interrupt_handler (tmp_frame->pc))
        break;
-      else
-       tmp_frame = tmp_frame->next;
+
+      /* Entry_GR specifies the number of callee-saved general registers
+         saved in the stack.  It starts at %r3, so %r3 would be 1.  */
+      if (u->Entry_GR >= 1)
+       {
+         /* The unwind entry claims that r3 is saved here.  However,
+            in optimized code, GCC often doesn't actually save r3.
+            We'll discover this if we look at the prologue.  */
+         get_frame_saved_regs (tmp_frame, &saved_regs);
+         saved_regs_frame = tmp_frame;
+
+         /* If we have an address for r3, that's good.  */
+         if (saved_regs.regs[FP_REGNUM])
+           break;
+       }
     }
 
   if (tmp_frame)
@@ -1164,13 +1253,11 @@ frame_chain (frame)
          && !tmp_frame->signal_handler_caller
          && !pc_in_interrupt_handler (tmp_frame->pc))
        {
-         return read_memory_integer (tmp_frame->frame, 4);
+         return read_memory_integer (tmp_frame->frame, TARGET_PTR_BIT / 8);
        }
       /* %r3 was saved somewhere in the stack.  Dig it out.  */
       else
        {
-         struct frame_saved_regs saved_regs;
-
          /* Sick.
 
             For optimization purposes many kernels don't have the
@@ -1197,12 +1284,14 @@ frame_chain (frame)
             fail miserably if the function which performs the
             system call has a variable sized stack frame.  */
 
-         get_frame_saved_regs (tmp_frame, &saved_regs);
+         if (tmp_frame != saved_regs_frame)
+           get_frame_saved_regs (tmp_frame, &saved_regs);
 
          /* Abominable hack.  */
          if (current_target.to_has_execution == 0
              && ((saved_regs.regs[FLAGS_REGNUM]
-                  && (read_memory_integer (saved_regs.regs[FLAGS_REGNUM], 4)
+                  && (read_memory_integer (saved_regs.regs[FLAGS_REGNUM],
+                                           TARGET_PTR_BIT / 8)
                       & 0x2))
                  || (saved_regs.regs[FLAGS_REGNUM] == 0
                      && read_register (FLAGS_REGNUM) & 0x2)))
@@ -1210,7 +1299,8 @@ frame_chain (frame)
              u = find_unwind_entry (FRAME_SAVED_PC (frame));
              if (!u)
                {
-                 return read_memory_integer (saved_regs.regs[FP_REGNUM], 4);
+                 return read_memory_integer (saved_regs.regs[FP_REGNUM],
+                                             TARGET_PTR_BIT / 8);
                }
              else
                {
@@ -1218,23 +1308,25 @@ frame_chain (frame)
                }
            }
 
-         return read_memory_integer (saved_regs.regs[FP_REGNUM], 4);
+         return read_memory_integer (saved_regs.regs[FP_REGNUM],
+                                     TARGET_PTR_BIT / 8);
        }
     }
   else
     {
-      struct frame_saved_regs saved_regs;
-
       /* Get the innermost frame.  */
       tmp_frame = frame;
       while (tmp_frame->next != NULL)
        tmp_frame = tmp_frame->next;
 
-      get_frame_saved_regs (tmp_frame, &saved_regs);
+      if (tmp_frame != saved_regs_frame)
+       get_frame_saved_regs (tmp_frame, &saved_regs);
+
       /* Abominable hack.  See above.  */
       if (current_target.to_has_execution == 0
          && ((saved_regs.regs[FLAGS_REGNUM]
-              && (read_memory_integer (saved_regs.regs[FLAGS_REGNUM], 4)
+              && (read_memory_integer (saved_regs.regs[FLAGS_REGNUM],
+                                       TARGET_PTR_BIT / 8)
                   & 0x2))
              || (saved_regs.regs[FLAGS_REGNUM] == 0
                  && read_register (FLAGS_REGNUM) & 0x2)))
@@ -1242,7 +1334,8 @@ frame_chain (frame)
          u = find_unwind_entry (FRAME_SAVED_PC (frame));
          if (!u)
            {
-             return read_memory_integer (saved_regs.regs[FP_REGNUM], 4);
+             return read_memory_integer (saved_regs.regs[FP_REGNUM],
+                                         TARGET_PTR_BIT / 8);
            }
          else
            {
@@ -1329,7 +1422,7 @@ push_dummy_frame (inf_status)
 {
   CORE_ADDR sp, pc, pcspace;
   register int regnum;
-  int int_buffer;
+  CORE_ADDR int_buffer;
   double freg_buffer;
 
   /* Oh, what a hack.  If we're trying to perform an inferior call
@@ -1364,20 +1457,28 @@ push_dummy_frame (inf_status)
   /* Space for "arguments"; the RP goes in here. */
   sp = read_register (SP_REGNUM) + 48;
   int_buffer = read_register (RP_REGNUM) | 0x3;
-  write_memory (sp - 20, (char *) &int_buffer, 4);
+
+  /* The 32bit and 64bit ABIs save the return pointer into different
+     stack slots.  */
+  if (REGISTER_SIZE == 8)
+    write_memory (sp - 16, (char *) &int_buffer, REGISTER_SIZE);
+  else
+    write_memory (sp - 20, (char *) &int_buffer, REGISTER_SIZE);
 
   int_buffer = TARGET_READ_FP ();
-  write_memory (sp, (char *) &int_buffer, 4);
+  write_memory (sp, (char *) &int_buffer, REGISTER_SIZE);
 
   write_register (FP_REGNUM, sp);
 
-  sp += 8;
+  sp += 2 * REGISTER_SIZE;
 
   for (regnum = 1; regnum < 32; regnum++)
     if (regnum != RP_REGNUM && regnum != FP_REGNUM)
       sp = push_word (sp, read_register (regnum));
 
-  sp += 4;
+  /* This is not necessary for the 64bit ABI.  In fact it is dangerous.  */
+  if (REGISTER_SIZE != 8)
+    sp += 4;
 
   for (regnum = FP0_REGNUM; regnum < NUM_REGS; regnum++)
     {
@@ -1401,29 +1502,38 @@ find_dummy_frame_regs (frame, frame_saved_regs)
   CORE_ADDR fp = frame->frame;
   int i;
 
-  frame_saved_regs->regs[RP_REGNUM] = (fp - 20) & ~0x3;
+  /* The 32bit and 64bit ABIs save RP into different locations.  */
+  if (REGISTER_SIZE == 8)
+    frame_saved_regs->regs[RP_REGNUM] = (fp - 16) & ~0x3;
+  else
+    frame_saved_regs->regs[RP_REGNUM] = (fp - 20) & ~0x3;
+
   frame_saved_regs->regs[FP_REGNUM] = fp;
-  frame_saved_regs->regs[1] = fp + 8;
 
-  for (fp += 12, i = 3; i < 32; i++)
+  frame_saved_regs->regs[1] = fp + (2 * REGISTER_SIZE);
+
+  for (fp += 3 * REGISTER_SIZE, i = 3; i < 32; i++)
     {
       if (i != FP_REGNUM)
        {
          frame_saved_regs->regs[i] = fp;
-         fp += 4;
+         fp += REGISTER_SIZE;
        }
     }
 
-  fp += 4;
+  /* This is not necessary or desirable for the 64bit ABI.  */
+  if (REGISTER_SIZE != 8)
+    fp += 4;
+
   for (i = FP0_REGNUM; i < NUM_REGS; i++, fp += 8)
     frame_saved_regs->regs[i] = fp;
 
   frame_saved_regs->regs[IPSW_REGNUM] = fp;
-  frame_saved_regs->regs[SAR_REGNUM] = fp + 4;
-  frame_saved_regs->regs[PCOQ_HEAD_REGNUM] = fp + 8;
-  frame_saved_regs->regs[PCSQ_HEAD_REGNUM] = fp + 12;
-  frame_saved_regs->regs[PCOQ_TAIL_REGNUM] = fp + 16;
-  frame_saved_regs->regs[PCSQ_TAIL_REGNUM] = fp + 20;
+  frame_saved_regs->regs[SAR_REGNUM] = fp + REGISTER_SIZE;
+  frame_saved_regs->regs[PCOQ_HEAD_REGNUM] = fp + 2 * REGISTER_SIZE;
+  frame_saved_regs->regs[PCSQ_HEAD_REGNUM] = fp + 3 * REGISTER_SIZE;
+  frame_saved_regs->regs[PCOQ_TAIL_REGNUM] = fp + 4 * REGISTER_SIZE;
+  frame_saved_regs->regs[PCSQ_TAIL_REGNUM] = fp + 5 * REGISTER_SIZE;
 }
 
 void
@@ -1445,7 +1555,8 @@ hppa_pop_frame ()
 
   for (regnum = 31; regnum > 0; regnum--)
     if (fsr.regs[regnum])
-      write_register (regnum, read_memory_integer (fsr.regs[regnum], 4));
+      write_register (regnum, read_memory_integer (fsr.regs[regnum],
+                     REGISTER_SIZE));
 
   for (regnum = NUM_REGS - 1; regnum >= FP0_REGNUM; regnum--)
     if (fsr.regs[regnum])
@@ -1456,16 +1567,19 @@ hppa_pop_frame ()
 
   if (fsr.regs[IPSW_REGNUM])
     write_register (IPSW_REGNUM,
-                   read_memory_integer (fsr.regs[IPSW_REGNUM], 4));
+                   read_memory_integer (fsr.regs[IPSW_REGNUM],
+                                        REGISTER_SIZE));
 
   if (fsr.regs[SAR_REGNUM])
     write_register (SAR_REGNUM,
-                   read_memory_integer (fsr.regs[SAR_REGNUM], 4));
+                   read_memory_integer (fsr.regs[SAR_REGNUM],
+                                        REGISTER_SIZE));
 
   /* If the PC was explicitly saved, then just restore it.  */
   if (fsr.regs[PCOQ_TAIL_REGNUM])
     {
-      npc = read_memory_integer (fsr.regs[PCOQ_TAIL_REGNUM], 4);
+      npc = read_memory_integer (fsr.regs[PCOQ_TAIL_REGNUM],
+                                REGISTER_SIZE);
       write_register (PCOQ_TAIL_REGNUM, npc);
     }
   /* Else use the value in %rp to set the new PC.  */
@@ -1475,7 +1589,7 @@ hppa_pop_frame ()
       write_pc (npc);
     }
 
-  write_register (FP_REGNUM, read_memory_integer (fp, 4));
+  write_register (FP_REGNUM, read_memory_integer (fp, REGISTER_SIZE));
 
   if (fsr.regs[IPSW_REGNUM])   /* call dummy */
     write_register (SP_REGNUM, fp - 48);
@@ -1504,12 +1618,12 @@ hppa_pop_frame ()
       breakpoint->silent = 1;
 
       /* So we can clean things up.  */
-      old_chain = make_cleanup ((make_cleanup_func) delete_breakpoint, breakpoint);
+      old_chain = make_cleanup_delete_breakpoint (breakpoint);
 
       /* Start up the inferior.  */
       clear_proceed_status ();
       proceed_to_finish = 1;
-      proceed ((CORE_ADDR) - 1, TARGET_SIGNAL_DEFAULT, 0);
+      proceed ((CORE_ADDR) -1, TARGET_SIGNAL_DEFAULT, 0);
 
       /* Perform our cleanups.  */
       do_cleanups (old_chain);
@@ -1525,7 +1639,8 @@ restore_pc_queue (fsr)
      struct frame_saved_regs *fsr;
 {
   CORE_ADDR pc = read_pc ();
-  CORE_ADDR new_pc = read_memory_integer (fsr->regs[PCOQ_HEAD_REGNUM], 4);
+  CORE_ADDR new_pc = read_memory_integer (fsr->regs[PCOQ_HEAD_REGNUM],
+                                         TARGET_PTR_BIT / 8);
   struct target_waitstatus w;
   int insn_count;
 
@@ -1543,7 +1658,8 @@ restore_pc_queue (fsr)
      So, load up the registers and single step until we are in the
      right place. */
 
-  write_register (21, read_memory_integer (fsr->regs[PCSQ_HEAD_REGNUM], 4));
+  write_register (21, read_memory_integer (fsr->regs[PCSQ_HEAD_REGNUM],
+                                          REGISTER_SIZE));
   write_register (22, new_pc);
 
   for (insn_count = 0; insn_count < 3; insn_count++)
@@ -1572,7 +1688,23 @@ restore_pc_queue (fsr)
   return 1;
 }
 
-#if 0
+
+#ifdef PA20W_CALLING_CONVENTIONS
+
+/* This function pushes a stack frame with arguments as part of the
+   inferior function calling mechanism.
+
+   This is the version for the PA64, in which later arguments appear
+   at higher addresses.  (The stack always grows towards higher
+   addresses.)
+
+   We simply allocate the appropriate amount of stack space and put
+   arguments into their proper slots.  The call dummy code will copy
+   arguments into registers as needed by the ABI.
+
+   This ABI also requires that the caller provide an argument pointer
+   to the callee, so we do that too.  */
+   
 CORE_ADDR
 hppa_push_arguments (nargs, args, sp, struct_return, struct_addr)
      int nargs;
@@ -1583,54 +1715,119 @@ hppa_push_arguments (nargs, args, sp, struct_return, struct_addr)
 {
   /* array of arguments' offsets */
   int *offset = (int *) alloca (nargs * sizeof (int));
-  int cum = 0;
-  int i, alignment;
 
+  /* array of arguments' lengths: real lengths in bytes, not aligned to
+     word size */
+  int *lengths = (int *) alloca (nargs * sizeof (int));
+
+  /* The value of SP as it was passed into this function after
+     aligning.  */
+  CORE_ADDR orig_sp = STACK_ALIGN (sp);
+
+  /* The number of stack bytes occupied by the current argument.  */
+  int bytes_reserved;
+
+  /* The total number of bytes reserved for the arguments.  */
+  int cum_bytes_reserved = 0;
+
+  /* Similarly, but aligned.  */
+  int cum_bytes_aligned = 0;
+  int i;
+
+  /* Iterate over each argument provided by the user.  */
   for (i = 0; i < nargs; i++)
     {
-      int x = 0;
-      /* cum is the sum of the lengths in bytes of
-         the arguments seen so far */
-      cum += TYPE_LENGTH (VALUE_TYPE (args[i]));
+      struct type *arg_type = VALUE_TYPE (args[i]);
 
-      /* value must go at proper alignment. Assume alignment is a
-         power of two. */
-      alignment = hppa_alignof (VALUE_TYPE (args[i]));
+      /* Integral scalar values smaller than a register are padded on
+         the left.  We do this by promoting them to full-width,
+         although the ABI says to pad them with garbage.  */
+      if (is_integral_type (arg_type)
+         && TYPE_LENGTH (arg_type) < REGISTER_SIZE)
+       {
+         args[i] = value_cast ((TYPE_UNSIGNED (arg_type)
+                                ? builtin_type_unsigned_long
+                                : builtin_type_long),
+                               args[i]);
+         arg_type = VALUE_TYPE (args[i]);
+       }
+
+      lengths[i] = TYPE_LENGTH (arg_type);
+
+      /* Align the size of the argument to the word size for this
+        target.  */
+      bytes_reserved = (lengths[i] + REGISTER_SIZE - 1) & -REGISTER_SIZE;
+
+      offset[i] = cum_bytes_reserved;
+
+      /* Aggregates larger than eight bytes (the only types larger
+         than eight bytes we have) are aligned on a 16-byte boundary,
+         possibly padded on the right with garbage.  This may leave an
+         empty word on the stack, and thus an unused register, as per
+         the ABI.  */
+      if (bytes_reserved > 8)
+       {
+         /* Round up the offset to a multiple of two slots.  */
+         int new_offset = ((offset[i] + 2*REGISTER_SIZE-1)
+                           & -(2*REGISTER_SIZE));
 
-      if (cum % alignment)
-       cum = (cum + alignment) & -alignment;
-      offset[i] = -cum;
+         /* Note the space we've wasted, if any.  */
+         bytes_reserved += new_offset - offset[i];
+         offset[i] = new_offset;
+       }
 
+      cum_bytes_reserved += bytes_reserved;
     }
-  sp += max ((cum + 7) & -8, 16);
 
+  /* CUM_BYTES_RESERVED already accounts for all the arguments
+     passed by the user.  However, the ABIs mandate minimum stack space
+     allocations for outgoing arguments.
+
+     The ABIs also mandate minimum stack alignments which we must
+     preserve.  */
+  cum_bytes_aligned = STACK_ALIGN (cum_bytes_reserved);
+  sp += max (cum_bytes_aligned, REG_PARM_STACK_SPACE);
+
+  /* Now write each of the args at the proper offset down the stack.  */
   for (i = 0; i < nargs; i++)
-    write_memory (sp + offset[i], VALUE_CONTENTS (args[i]),
-                 TYPE_LENGTH (VALUE_TYPE (args[i])));
+    write_memory (orig_sp + offset[i], VALUE_CONTENTS (args[i]), lengths[i]);
 
+  /* If a structure has to be returned, set up register 28 to hold its
+     address */
   if (struct_return)
     write_register (28, struct_addr);
-  return sp + 32;
+
+  /* For the PA64 we must pass a pointer to the outgoing argument list.
+     The ABI mandates that the pointer should point to the first byte of
+     storage beyond the register flushback area.
+
+     However, the call dummy expects the outgoing argument pointer to
+     be passed in register %r4.  */
+  write_register (4, orig_sp + REG_PARM_STACK_SPACE);
+
+  /* ?!? This needs further work.  We need to set up the global data
+     pointer for this procedure.  This assumes the same global pointer
+     for every procedure.   The call dummy expects the dp value to
+     be passed in register %r6.  */
+  write_register (6, read_register (27));
+  
+  /* The stack will have 64 bytes of additional space for a frame marker.  */
+  return sp + 64;
 }
-#endif
 
-/* elz: I am rewriting this function, because the one above is a very 
-   obscure piece of code.
-   This function pushes the arguments on the stack. The stack grows up
-   on the PA. 
-   Each argument goes in one (or more) word (4 bytes) on the stack.
-   The first four words for the args must be allocated, even if they 
-   are not used. 
-   The 'topmost' arg is arg0, the 'bottom-most' is arg3. (if you think of 
-   them as 1 word long).
-   Below these there can be any number of arguments, as needed by the function.
-   If an arg is bigger than one word, it will be written on the stack 
-   occupying as many words as needed. Args that are bigger than 64bits
-   are not copied on the stack, a pointer is passed instead.
-
-   On top of the arg0 word there are other 8 words (32bytes) which are used
-   for other purposes */
+#else
+
+/* This function pushes a stack frame with arguments as part of the
+   inferior function calling mechanism.
+
+   This is the version of the function for the 32-bit PA machines, in
+   which later arguments appear at lower addresses.  (The stack always
+   grows towards higher addresses.)
 
+   We simply allocate the appropriate amount of stack space and put
+   arguments into their proper slots.  The call dummy code will copy
+   arguments into registers as needed by the ABI. */
+   
 CORE_ADDR
 hppa_push_arguments (nargs, args, sp, struct_return, struct_addr)
      int nargs;
@@ -1641,57 +1838,50 @@ hppa_push_arguments (nargs, args, sp, struct_return, struct_addr)
 {
   /* array of arguments' offsets */
   int *offset = (int *) alloca (nargs * sizeof (int));
-  /* array of arguments' lengths: real lengths in bytes, not aligned to word size */
+
+  /* array of arguments' lengths: real lengths in bytes, not aligned to
+     word size */
   int *lengths = (int *) alloca (nargs * sizeof (int));
 
-  int bytes_reserved;          /* this is the number of bytes on the stack occupied by an
-                                  argument. This will be always a multiple of 4 */
+  /* The number of stack bytes occupied by the current argument.  */
+  int bytes_reserved;
 
-  int cum_bytes_reserved = 0;  /* this is the total number of bytes reserved by the args
-                                  seen so far. It is a multiple of 4 always */
-  int cum_bytes_aligned = 0;   /* same as above, but aligned on 8 bytes */
-  int i;
+  /* The total number of bytes reserved for the arguments.  */
+  int cum_bytes_reserved = 0;
 
-  /* When an arg does not occupy a whole word, for instance in bitfields:
-     if the arg is x bits (0<x<32), it must be written
-     starting from the (x-1)-th position  down until the 0-th position. 
-     It is enough to align it to the word. */
-  /* if an arg occupies 8 bytes, it must be aligned on the 64-bits 
-     high order word in odd arg word. */
-  /* if an arg is larger than 64 bits, we need to pass a pointer to it, and
-     copy the actual value on the stack, so that the callee can play with it.
-     This is taken care of in valops.c in the call_function_by_hand function.
-     The argument that is received in this function here has already be converted
-     to a pointer to whatever is needed, so that it just can be pushed
-     as a word argument */
+  /* Similarly, but aligned.  */
+  int cum_bytes_aligned = 0;
+  int i;
 
+  /* Iterate over each argument provided by the user.  */
   for (i = 0; i < nargs; i++)
     {
-
       lengths[i] = TYPE_LENGTH (VALUE_TYPE (args[i]));
 
-      if (lengths[i] % 4)
-       bytes_reserved = (lengths[i] / 4) * 4 + 4;
-      else
-       bytes_reserved = lengths[i];
+      /* Align the size of the argument to the word size for this
+        target.  */
+      bytes_reserved = (lengths[i] + REGISTER_SIZE - 1) & -REGISTER_SIZE;
 
       offset[i] = cum_bytes_reserved + lengths[i];
 
-      if ((bytes_reserved == 8) && (offset[i] % 8))    /* if 64-bit arg is not 64 bit aligned */
+      /* If the argument is a double word argument, then it needs to be
+        double word aligned.  */
+      if ((bytes_reserved == 2 * REGISTER_SIZE)
+         && (offset[i] % 2 * REGISTER_SIZE))
        {
          int new_offset = 0;
-         /* bytes_reserved is already aligned to the word, so we put it at one word
-            more down the stack. This will leave one empty word on the
-            stack, and one unused register. This is OK, see the calling
-            convention doc */
-         /* the offset may have to be moved to the corresponding position
-            one word down the stack, to maintain 
-            alignment. */
-         new_offset = (offset[i] / 8) * 8 + 8;
-         if ((new_offset - offset[i]) >= 4)
+         /* BYTES_RESERVED is already aligned to the word, so we put
+            the argument at one word more down the stack.
+
+            This will leave one empty word on the stack, and one unused
+            register as mandated by the ABI.  */
+         new_offset = ((offset[i] + 2 * REGISTER_SIZE - 1)
+                       & -(2 * REGISTER_SIZE));
+
+         if ((new_offset - offset[i]) >= 2 * REGISTER_SIZE)
            {
-             bytes_reserved += 4;
-             offset[i] += 4;
+             bytes_reserved += REGISTER_SIZE;
+             offset[i] += REGISTER_SIZE;
            }
        }
 
@@ -1699,25 +1889,31 @@ hppa_push_arguments (nargs, args, sp, struct_return, struct_addr)
 
     }
 
-  /* now move up the sp to reserve at least 4 words required for the args,
-     or more than this if needed */
-  /* wee also need to keep the sp aligned to 8 bytes */
+  /* CUM_BYTES_RESERVED already accounts for all the arguments passed
+     by the user.  However, the ABI mandates minimum stack space
+     allocations for outgoing arguments.
+
+     The ABI also mandates minimum stack alignments which we must
+     preserve.  */
   cum_bytes_aligned = STACK_ALIGN (cum_bytes_reserved);
-  sp += max (cum_bytes_aligned, 16);
+  sp += max (cum_bytes_aligned, REG_PARM_STACK_SPACE);
 
-  /* now write each of the args at the proper offset down the stack */
+  /* Now write each of the args at the proper offset down the stack.
+     ?!? We need to promote values to a full register instead of skipping
+     words in the stack.  */
   for (i = 0; i < nargs; i++)
     write_memory (sp - offset[i], VALUE_CONTENTS (args[i]), lengths[i]);
 
-
-  /* if a structure has to be returned, set up register 28 to hold its address */
+  /* If a structure has to be returned, set up register 28 to hold its
+     address */
   if (struct_return)
     write_register (28, struct_addr);
 
-  /* the stack will have other 8 words on top of the args */
+  /* The stack will have 32 bytes of additional space for a frame marker.  */
   return sp + 32;
 }
 
+#endif
 
 /* elz: this function returns a value which is built looking at the given address.
    It is called from call_function_by_hand, in case we need to return a 
@@ -1809,11 +2005,11 @@ find_stub_with_shl_get (function, handle)
   /* now prepare the arguments for the call */
 
   args[0] = value_from_longest (TYPE_FIELD_TYPE (ftype, 0), 12);
-  args[1] = value_from_longest (TYPE_FIELD_TYPE (ftype, 1), SYMBOL_VALUE_ADDRESS (msymbol));
-  args[2] = value_from_longest (TYPE_FIELD_TYPE (ftype, 2), endo_buff_addr);
+  args[1] = value_from_pointer (TYPE_FIELD_TYPE (ftype, 1), SYMBOL_VALUE_ADDRESS (msymbol));
+  args[2] = value_from_pointer (TYPE_FIELD_TYPE (ftype, 2), endo_buff_addr);
   args[3] = value_from_longest (TYPE_FIELD_TYPE (ftype, 3), TYPE_PROCEDURE);
-  args[4] = value_from_longest (TYPE_FIELD_TYPE (ftype, 4), value_return_addr);
-  args[5] = value_from_longest (TYPE_FIELD_TYPE (ftype, 5), errno_return_addr);
+  args[4] = value_from_pointer (TYPE_FIELD_TYPE (ftype, 4), value_return_addr);
+  args[5] = value_from_pointer (TYPE_FIELD_TYPE (ftype, 5), errno_return_addr);
 
   /* now call the function */
 
@@ -1825,7 +2021,7 @@ find_stub_with_shl_get (function, handle)
 
   target_read_memory (value_return_addr, (char *) &stub_addr, sizeof (stub_addr));
   if (stub_addr <= 0)
-    error ("call to __d_shl_get failed, error code is %d", err_value); /* purecov: deadcode */
+    error ("call to __d_shl_get failed, error code is %d", err_value);
 
   return (stub_addr);
 }
@@ -1881,14 +2077,111 @@ hppa_fix_call_dummy (dummy, pc, fun, nargs, args, type, gcc_p)
   CORE_ADDR solib_handle = 0;
 
   /* Nonzero if we will use GCC's PLT call routine.  This routine must be
-     passed an import stub, not a PLABEL.  It is also necessary to set %r19     
-     (the PIC register) before performing the call. 
+     passed an import stub, not a PLABEL.  It is also necessary to set %r19
+     (the PIC register) before performing the call.
 
      If zero, then we are using __d_plt_call (HP's PLT call routine) or we
      are calling the target directly.  When using __d_plt_call we want to
      use a PLABEL instead of an import stub.  */
   int using_gcc_plt_call = 1;
 
+#ifdef GDB_TARGET_IS_HPPA_20W
+  /* We currently use completely different code for the PA2.0W inferior
+     function call sequences.  This needs to be cleaned up.  */
+  {
+    CORE_ADDR pcsqh, pcsqt, pcoqh, pcoqt, sr5;
+    struct target_waitstatus w;
+    int inst1, inst2;
+    char buf[4];
+    int status;
+    struct objfile *objfile;
+
+    /* We can not modify the PC space queues directly, so we start
+       up the inferior and execute a couple instructions to set the
+       space queues so that they point to the call dummy in the stack.  */
+    pcsqh = read_register (PCSQ_HEAD_REGNUM);
+    sr5 = read_register (SR5_REGNUM);
+    if (1)
+      {
+        pcoqh = read_register (PCOQ_HEAD_REGNUM);
+        pcoqt = read_register (PCOQ_TAIL_REGNUM);
+        if (target_read_memory (pcoqh, buf, 4) != 0)
+          error ("Couldn't modify space queue\n");
+        inst1 = extract_unsigned_integer (buf, 4);
+
+        if (target_read_memory (pcoqt, buf, 4) != 0)
+          error ("Couldn't modify space queue\n");
+        inst2 = extract_unsigned_integer (buf, 4);
+
+        /* BVE (r1) */
+        *((int *) buf) = 0xe820d000;
+        if (target_write_memory (pcoqh, buf, 4) != 0)
+          error ("Couldn't modify space queue\n");
+
+        /* NOP */
+        *((int *) buf) = 0x08000240;
+        if (target_write_memory (pcoqt, buf, 4) != 0)
+          {
+            *((int *) buf) = inst1;
+            target_write_memory (pcoqh, buf, 4);
+            error ("Couldn't modify space queue\n");
+          }
+
+        write_register (1, pc);
+
+        /* Single step twice, the BVE instruction will set the space queue
+          such that it points to the PC value written immediately above
+          (ie the call dummy).  */
+        resume (1, 0);
+        target_wait (inferior_pid, &w);
+        resume (1, 0);
+        target_wait (inferior_pid, &w);
+
+       /* Restore the two instructions at the old PC locations.  */
+        *((int *) buf) = inst1;
+        target_write_memory (pcoqh, buf, 4);
+        *((int *) buf) = inst2;
+        target_write_memory (pcoqt, buf, 4);
+      }
+
+    /* The call dummy wants the ultimate destination address initially
+       in register %r5.  */
+    write_register (5, fun);
+
+    /* We need to see if this objfile has a different DP value than our
+       own (it could be a shared library for example).  */
+    ALL_OBJFILES (objfile)
+      {
+       struct obj_section *s;
+       obj_private_data_t *obj_private;
+
+       /* See if FUN is in any section within this shared library.  */
+       for (s = objfile->sections; s < objfile->sections_end; s++)
+         if (s->addr <= fun && fun < s->endaddr)
+           break;
+
+        if (s >= objfile->sections_end)
+         continue;
+
+       obj_private = (obj_private_data_t *) objfile->obj_private;
+       
+       /* The DP value may be different for each objfile.  But within an
+          objfile each function uses the same dp value.  Thus we do not need
+          to grope around the opd section looking for dp values.
+
+          ?!? This is not strictly correct since we may be in a shared library
+          and want to call back into the main program.  To make that case
+          work correctly we need to set obj_private->dp for the main program's
+          objfile, then remove this conditional.  */
+       if (obj_private->dp)
+         write_register (27, obj_private->dp);
+       break;
+      }
+    return pc;
+  }
+#endif
+
+#ifndef GDB_TARGET_IS_HPPA_20W
   /* Prefer __gcc_plt_call over the HP supplied routine because
      __gcc_plt_call works for any number of arguments.  */
   trampoline = NULL;
@@ -1909,11 +2202,13 @@ hppa_fix_call_dummy (dummy, pc, fun, nargs, args, type, gcc_p)
       /* Get the GOT/DP value for the target function.  It's
          at *(fun+4).  Note the call dummy is *NOT* allowed to
          trash %r19 before calling the target function.  */
-      write_register (19, read_memory_integer ((fun & ~0x3) + 4, 4));
+      write_register (19, read_memory_integer ((fun & ~0x3) + 4,
+                     REGISTER_SIZE));
 
       /* Now get the real address for the function we are calling, it's
          at *fun.  */
-      fun = (CORE_ADDR) read_memory_integer (fun & ~0x3, 4);
+      fun = (CORE_ADDR) read_memory_integer (fun & ~0x3,
+                                            TARGET_PTR_BIT / 8);
     }
   else
     {
@@ -1934,7 +2229,7 @@ hppa_fix_call_dummy (dummy, pc, fun, nargs, args, type, gcc_p)
 
          funsymbol = lookup_minimal_symbol_by_pc (fun);
          if (!funsymbol)
-           error ("Unable to find minimal symbol for target fucntion.\n");
+           error ("Unable to find minimal symbol for target function.\n");
 
          /* Search all the object files for an import symbol with the
             right name. */
@@ -1958,14 +2253,34 @@ hppa_fix_call_dummy (dummy, pc, fun, nargs, args, type, gcc_p)
 
                /* It must also be an import stub.  */
                u = find_unwind_entry (SYMBOL_VALUE (stub_symbol));
-               if (!u
-                   || (u->stub_unwind.stub_type != IMPORT)
-                   && u->stub_unwind.stub_type != IMPORT_SHLIB)
+               if (u == NULL
+                   || (u->stub_unwind.stub_type != IMPORT
+#ifdef GDB_NATIVE_HPUX_11
+                       /* Sigh.  The hpux 10.20 dynamic linker will blow
+                          chunks if we perform a call to an unbound function
+                          via the IMPORT_SHLIB stub.  The hpux 11.00 dynamic
+                          linker will blow chunks if we do not call the
+                          unbound function via the IMPORT_SHLIB stub.
+
+                          We currently have no way to select bevahior on just
+                          the target.  However, we only support HPUX/SOM in
+                          native mode.  So we conditinalize on a native
+                          #ifdef.  Ugly.  Ugly.  Ugly  */
+                       && u->stub_unwind.stub_type != IMPORT_SHLIB
+#endif
+                       ))
                  continue;
 
                /* OK.  Looks like the correct import stub.  */
                newfun = SYMBOL_VALUE (stub_symbol);
                fun = newfun;
+
+               /* If we found an IMPORT stub, then we want to stop
+                  searching now.  If we found an IMPORT_SHLIB, we want
+                  to continue the search in the hopes that we will find
+                  an IMPORT stub.  */
+               if (u->stub_unwind.stub_type == IMPORT)
+                 break;
              }
          }
 
@@ -2044,7 +2359,6 @@ hppa_fix_call_dummy (dummy, pc, fun, nargs, args, type, gcc_p)
        }
     }
 
-#ifndef GDB_TARGET_IS_HPPA_20W
   /* Store upper 21 bits of function address into ldil.  fun will either be
      the final target (most cases) or __d_plt_call when calling into a shared
      library and __gcc_plt_call is not available.  */
@@ -2062,7 +2376,6 @@ hppa_fix_call_dummy (dummy, pc, fun, nargs, args, type, gcc_p)
      deposit_14 (fun & MASK_11,
                 extract_unsigned_integer (&dummy[FUNC_LDO_OFFSET],
                                           INSTRUCTION_SIZE)));
-#endif /* GDB_TARGET_IS_HPPA_20W */
 #ifdef SR4EXPORT_LDIL_OFFSET
 
   {
@@ -2119,6 +2432,7 @@ hppa_fix_call_dummy (dummy, pc, fun, nargs, args, type, gcc_p)
 #endif
   else
     return dyncall_addr;
+#endif
 }
 
 
@@ -2271,7 +2585,7 @@ void
 pa_do_strcat_registers_info (regnum, fpregs, stream, precision)
      int regnum;
      int fpregs;
-     GDB_FILE *stream;
+     struct ui_file *stream;
      enum precision_type precision;
 {
   char raw_regs[REGISTER_BYTES];
@@ -2486,7 +2800,7 @@ pa_strcat_registers (raw_regs, regnum, fpregs, stream)
      char *raw_regs;
      int regnum;
      int fpregs;
-     GDB_FILE *stream;
+     struct ui_file *stream;
 {
   int i, j;
   long raw_val[2];             /* Alas, we are compiled so that "long long" is 32 bits */
@@ -2579,7 +2893,7 @@ pa_print_fp_reg (i)
 static void
 pa_strcat_fp_reg (i, stream, precision)
      int i;
-     GDB_FILE *stream;
+     struct ui_file *stream;
      enum precision_type precision;
 {
   char raw_buffer[MAX_REGISTER_RAW_SIZE];
@@ -2632,8 +2946,73 @@ in_solib_call_trampoline (pc, name)
   static CORE_ADDR dyncall = 0;
   static CORE_ADDR sr4export = 0;
 
-/* FIXME XXX - dyncall and sr4export must be initialized whenever we get a
-   new exec file */
+#ifdef GDB_TARGET_IS_HPPA_20W
+  /* PA64 has a completely different stub/trampoline scheme.  Is it
+     better?  Maybe.  It's certainly harder to determine with any
+     certainty that we are in a stub because we can not refer to the
+     unwinders to help. 
+
+     The heuristic is simple.  Try to lookup the current PC value in th
+     minimal symbol table.  If that fails, then assume we are not in a
+     stub and return.
+
+     Then see if the PC value falls within the section bounds for the
+     section containing the minimal symbol we found in the first
+     step.  If it does, then assume we are not in a stub and return.
+
+     Finally peek at the instructions to see if they look like a stub.  */
+  {
+    struct minimal_symbol *minsym;
+    asection *sec;
+    CORE_ADDR addr;
+    int insn, i;
+
+    minsym = lookup_minimal_symbol_by_pc (pc);
+    if (! minsym)
+      return 0;
+
+    sec = SYMBOL_BFD_SECTION (minsym);
+
+    if (sec->vma <= pc
+       && sec->vma + sec->_cooked_size < pc)
+      return 0;
+
+    /* We might be in a stub.  Peek at the instructions.  Stubs are 3
+       instructions long. */
+    insn = read_memory_integer (pc, 4);
+
+    /* Find out where we we think we are within the stub.  */
+    if ((insn & 0xffffc00e) == 0x53610000)
+      addr = pc;
+    else if ((insn & 0xffffffff) == 0xe820d000)
+      addr = pc - 4;
+    else if ((insn & 0xffffc00e) == 0x537b0000)
+      addr = pc - 8;
+    else
+      return 0;
+
+    /* Now verify each insn in the range looks like a stub instruction.  */
+    insn = read_memory_integer (addr, 4);
+    if ((insn & 0xffffc00e) != 0x53610000)
+      return 0;
+       
+    /* Now verify each insn in the range looks like a stub instruction.  */
+    insn = read_memory_integer (addr + 4, 4);
+    if ((insn & 0xffffffff) != 0xe820d000)
+      return 0;
+    
+    /* Now verify each insn in the range looks like a stub instruction.  */
+    insn = read_memory_integer (addr + 8, 4);
+    if ((insn & 0xffffc00e) != 0x537b0000)
+      return 0;
+
+    /* Looks like a stub.  */
+    return 1;
+  }
+#endif
+
+  /* FIXME XXX - dyncall and sr4export must be initialized whenever we get a
+     new exec file */
 
   /* First see if PC is in one of the two C-library trampolines.  */
   if (!dyncall)
@@ -2657,6 +3036,10 @@ in_solib_call_trampoline (pc, name)
   if (pc == dyncall || pc == sr4export)
     return 1;
 
+  minsym = lookup_minimal_symbol_by_pc (pc);
+  if (minsym && strcmp (SYMBOL_NAME (minsym), ".stub") == 0)
+    return 1;
+
   /* Get the unwind descriptor corresponding to PC, return zero
      if no unwind was found.  */
   u = find_unwind_entry (pc);
@@ -2702,12 +3085,12 @@ in_solib_call_trampoline (pc, name)
        }
 
       /* Should never happen.  */
-      warning ("Unable to find branch in parameter relocation stub.\n");       /* purecov: deadcode */
-      return 0;                        /* purecov: deadcode */
+      warning ("Unable to find branch in parameter relocation stub.\n");
+      return 0;
     }
 
   /* Unknown stub type.  For now, just return zero.  */
-  return 0;                    /* purecov: deadcode */
+  return 0;
 }
 
 /* Return one if PC is in the return path of a trampoline, else return zero.
@@ -2764,12 +3147,12 @@ in_solib_return_trampoline (pc, name)
        }
 
       /* Should never happen.  */
-      warning ("Unable to find branch in parameter relocation stub.\n");       /* purecov: deadcode */
-      return 0;                        /* purecov: deadcode */
+      warning ("Unable to find branch in parameter relocation stub.\n");
+      return 0;
     }
 
   /* Unknown stub type.  For now, just return zero.  */
-  return 0;                    /* purecov: deadcode */
+  return 0;
 
 }
 
@@ -2790,17 +3173,6 @@ in_solib_return_trampoline (pc, name)
    calling an argument relocation stub.  It even handles some stubs
    used in dynamic executables.  */
 
-#if 0
-CORE_ADDR
-skip_trampoline_code (pc, name)
-     CORE_ADDR pc;
-     char *name;
-{
-  return find_solib_trampoline_target (pc);
-}
-
-#endif
-
 CORE_ADDR
 skip_trampoline_code (pc, name)
      CORE_ADDR pc;
@@ -2814,9 +3186,8 @@ skip_trampoline_code (pc, name)
   struct minimal_symbol *msym;
   struct unwind_table_entry *u;
 
-
-/* FIXME XXX - dyncall and sr4export must be initialized whenever we get a
-   new exec file */
+  /* FIXME XXX - dyncall and sr4export must be initialized whenever we get a
+     new exec file */
 
   if (!dyncall)
     {
@@ -2855,12 +3226,12 @@ skip_trampoline_code (pc, name)
          the PLT entry for this function, not the address of the function
          itself.  Bit 31 has meaning too, but only for MPE.  */
       if (pc & 0x2)
-       pc = (CORE_ADDR) read_memory_integer (pc & ~0x3, 4);
+       pc = (CORE_ADDR) read_memory_integer (pc & ~0x3, TARGET_PTR_BIT / 8);
     }
   if (pc == dyncall_external)
     {
       pc = (CORE_ADDR) read_register (22);
-      pc = (CORE_ADDR) read_memory_integer (pc & ~0x3, 4);
+      pc = (CORE_ADDR) read_memory_integer (pc & ~0x3, TARGET_PTR_BIT / 8);
     }
   else if (pc == sr4export)
     pc = (CORE_ADDR) (read_register (22));
@@ -3052,7 +3423,7 @@ skip_trampoline_code (pc, name)
       else if ((curr_inst & 0xffe0f000) == 0xe840d000)
        {
          return (read_memory_integer
-                 (read_register (SP_REGNUM) - 24, 4)) & ~0x3;
+                 (read_register (SP_REGNUM) - 24, TARGET_PTR_BIT / 8)) & ~0x3;
        }
 
       /* What about be,n 0(sr0,%rp)?  It's just another way we return to
@@ -3064,7 +3435,7 @@ skip_trampoline_code (pc, name)
             I guess we could check for the previous instruction being
             mtsp %r1,%sr0 if we want to do sanity checking.  */
          return (read_memory_integer
-                 (read_register (SP_REGNUM) - 24, 4)) & ~0x3;
+                 (read_register (SP_REGNUM) - 24, TARGET_PTR_BIT / 8)) & ~0x3;
        }
 
       /* Haven't found the branch yet, but we're still in the stub.
@@ -3094,6 +3465,10 @@ prologue_inst_adjust_sp (inst)
   if ((inst & 0xffe00000) == 0x6fc00000)
     return extract_14 (inst);
 
+  /* std,ma X,D(sp) */
+  if ((inst & 0xffe00008) == 0x73c00008)
+    return (inst & 0x1 ? -1 << 13 : 0) | (((inst >> 4) & 0x3ff) << 3);
+
   /* addil high21,%r1; ldo low11,(%r1),%r30)
      save high bits in save_high21 for later use.  */
   if ((inst & 0xffe00000) == 0x28200000)
@@ -3309,11 +3684,21 @@ restart:
       if (inst == 0x6bc23fd9 || inst == 0x0fc212c1)
        save_rp = 0;
 
-      /* This is the only way we save SP into the stack.  At this time
+      /* These are the only ways we save SP into the stack.  At this time
          the HP compilers never bother to save SP into the stack.  */
-      if ((inst & 0xffffc000) == 0x6fc10000)
+      if ((inst & 0xffffc000) == 0x6fc10000
+         || (inst & 0xffffc00c) == 0x73c10008)
        save_sp = 0;
 
+      /* Are we loading some register with an offset from the argument
+         pointer?  */
+      if ((inst & 0xffe00000) == 0x37a00000
+         || (inst & 0xffffffe0) == 0x081d0240)
+       {
+         pc += 4;
+         continue;
+       }
+
       /* Account for general and floating-point register saves.  */
       reg_num = inst_saves_gr (inst);
       save_gr &= ~(1 << reg_num);
@@ -3328,9 +3713,9 @@ restart:
 
          FIXME.  Can still die if we have a mix of GR and FR argument
          stores!  */
-      if (reg_num >= 23 && reg_num <= 26)
+      if (reg_num >= (TARGET_PTR_BIT == 64 ? 19 : 23) && reg_num <= 26)
        {
-         while (reg_num >= 23 && reg_num <= 26)
+         while (reg_num >= (TARGET_PTR_BIT == 64 ? 19 : 23) && reg_num <= 26)
            {
              pc += 4;
              status = target_read_memory (pc, buf, 4);
@@ -3357,7 +3742,7 @@ restart:
          save.  */
       if ((inst & 0xfc000000) == 0x34000000
          && inst_saves_fr (next_inst) >= 4
-         && inst_saves_fr (next_inst) <= 7)
+         && inst_saves_fr (next_inst) <= (TARGET_PTR_BIT == 64 ? 11 : 7))
        {
          /* So we drop into the code below in a reasonable state.  */
          reg_num = inst_saves_fr (next_inst);
@@ -3368,9 +3753,9 @@ restart:
          This is a kludge as on the HP compiler sets this bit and it
          never does prologue scheduling.  So once we see one, skip past
          all of them.  */
-      if (reg_num >= 4 && reg_num <= 7)
+      if (reg_num >= 4 && reg_num <= (TARGET_PTR_BIT == 64 ? 11 : 7))
        {
-         while (reg_num >= 4 && reg_num <= 7)
+         while (reg_num >= 4 && reg_num <= (TARGET_PTR_BIT == 64 ? 11 : 7))
            {
              pc += 8;
              status = target_read_memory (pc, buf, 4);
@@ -3522,6 +3907,7 @@ hppa_frame_find_saved_regs (frame_info, frame_saved_regs)
   int status, i, reg;
   char buf[4];
   int fp_loc = -1;
+  int final_iteration;
 
   /* Zero out everything.  */
   memset (frame_saved_regs, '\0', sizeof (struct frame_saved_regs));
@@ -3531,9 +3917,20 @@ hppa_frame_find_saved_regs (frame_info, frame_saved_regs)
      instead, let find_dummy_frame_regs fill in the correct offsets
      for the saved registers.  */
   if ((frame_info->pc >= frame_info->frame
-       && frame_info->pc <= (frame_info->frame + CALL_DUMMY_LENGTH
-                            + 32 * 4 + (NUM_REGS - FP0_REGNUM) * 8
-                            + 6 * 4)))
+       && frame_info->pc <= (frame_info->frame
+                            /* A call dummy is sized in words, but it is
+                               actually a series of instructions.  Account
+                               for that scaling factor.  */
+                            + ((REGISTER_SIZE / INSTRUCTION_SIZE)
+                               * CALL_DUMMY_LENGTH)
+                            /* Similarly we have to account for 64bit
+                               wide register saves.  */
+                            + (32 * REGISTER_SIZE)
+                            /* We always consider FP regs 8 bytes long.  */
+                            + (NUM_REGS - FP0_REGNUM) * 8
+                            /* Similarly we have to account for 64bit
+                               wide register saves.  */
+                            + (6 * REGISTER_SIZE))))
     find_dummy_frame_regs (frame_info, frame_saved_regs);
 
   /* Interrupt handlers are special too.  They lay out the register
@@ -3545,7 +3942,8 @@ hppa_frame_find_saved_regs (frame_info, frame_saved_regs)
          /* SP is a little special.  */
          if (i == SP_REGNUM)
            frame_saved_regs->regs[SP_REGNUM]
-             = read_memory_integer (frame_info->frame + SP_REGNUM * 4, 4);
+             = read_memory_integer (frame_info->frame + SP_REGNUM * 4,
+                                    TARGET_PTR_BIT / 8);
          else
            frame_saved_regs->regs[i] = frame_info->frame + i * 4;
        }
@@ -3612,7 +4010,9 @@ hppa_frame_find_saved_regs (frame_info, frame_saved_regs)
      Some unexpected things are expected with debugging optimized code, so
      we allow this routine to walk past user instructions in optimized
      GCC code.  */
-  while (save_gr || save_fr || save_rp || save_sp || stack_remaining > 0)
+  final_iteration = 0;
+  while ((save_gr || save_fr || save_rp || save_sp || stack_remaining > 0)
+        && pc <= frame_info->pc)
     {
       status = target_read_memory (pc, buf, 4);
       inst = extract_unsigned_integer (buf, 4);
@@ -3624,17 +4024,27 @@ hppa_frame_find_saved_regs (frame_info, frame_saved_regs)
       /* Note the interesting effects of this instruction.  */
       stack_remaining -= prologue_inst_adjust_sp (inst);
 
-      /* There is only one instruction used for saving RP into the stack.  */
-      if (inst == 0x6bc23fd9)
+      /* There are limited ways to store the return pointer into the
+        stack.  */
+      if (inst == 0x6bc23fd9) /* stw rp,-0x14(sr0,sp) */
        {
          save_rp = 0;
          frame_saved_regs->regs[RP_REGNUM] = frame_info->frame - 20;
        }
+      else if (inst == 0x0fc212c1) /* std rp,-0x10(sr0,sp) */
+       {
+         save_rp = 0;
+         frame_saved_regs->regs[RP_REGNUM] = frame_info->frame - 16;
+       }
 
-      /* Just note that we found the save of SP into the stack.  The
-         value for frame_saved_regs was computed above.  */
-      if ((inst & 0xffffc000) == 0x6fc10000)
-       save_sp = 0;
+      /* Note if we saved SP into the stack.  This also happens to indicate
+        the location of the saved frame pointer.  */
+      if (   (inst & 0xffffc000) == 0x6fc10000  /* stw,ma r1,N(sr0,sp) */
+          || (inst & 0xffffc00c) == 0x73c10008) /* std,ma r1,N(sr0,sp) */
+       {
+         frame_saved_regs->regs[FP_REGNUM] = frame_info->frame;
+         save_sp = 0;
+       }
 
       /* Account for general and floating-point register saves.  */
       reg = inst_saves_gr (inst);
@@ -3647,16 +4057,28 @@ hppa_frame_find_saved_regs (frame_info, frame_saved_regs)
          if ((inst >> 26) == 0x1b
              && extract_14 (inst) >= 0)
            frame_saved_regs->regs[reg] = frame_info->frame;
+         /* A std has explicit post_modify forms.  */
+         else if ((inst & 0xfc00000c0) == 0x70000008)
+           frame_saved_regs->regs[reg] = frame_info->frame;
          else
            {
+             CORE_ADDR offset;
+
+             if ((inst >> 26) == 0x1c)
+               offset = (inst & 0x1 ? -1 << 13 : 0) | (((inst >> 4) & 0x3ff) << 3);
+             else if ((inst >> 26) == 0x03)
+               offset = low_sign_extend (inst & 0x1f, 5);
+             else
+               offset = extract_14 (inst);
+
              /* Handle code with and without frame pointers.  */
              if (u->Save_SP)
                frame_saved_regs->regs[reg]
-                 = frame_info->frame + extract_14 (inst);
+                 = frame_info->frame + offset;
              else
                frame_saved_regs->regs[reg]
-                 = frame_info->frame + (u->Total_frame_size << 3)
-                 + extract_14 (inst);
+                 = (frame_info->frame + (u->Total_frame_size << 3)
+                    + offset);
            }
        }
 
@@ -3698,11 +4120,15 @@ hppa_frame_find_saved_regs (frame_info, frame_saved_regs)
            }
        }
 
-      /* Quit if we hit any kind of branch.  This can happen if a prologue
-         instruction is in the delay slot of the first call/branch.  */
-      if (is_branch (inst))
+      /* Quit if we hit any kind of branch the previous iteration.
+      if (final_iteration)
        break;
 
+      /* We want to look precisely one instruction beyond the branch
+        if we have not found everything yet.  */
+      if (is_branch (inst))
+       final_iteration = 1;
+
       /* Bump the PC.  */
       pc += 4;
     }
@@ -3882,6 +4308,7 @@ initialize_hp_cxx_exception_support ()
       return 0;
     }
 
+#ifndef GDB_TARGET_IS_HPPA_20W
   /* Check whether the executable is dynamically linked or archive bound */
   /* With an archive-bound executable we can use the raw addresses we find
      for the callback function, etc. without modification. For an executable
@@ -3925,6 +4352,7 @@ initialize_hp_cxx_exception_support ()
     }
   else
     exception_catchpoints_are_fragile = 0;
+#endif
 
   /* Now, look for the breakpointable routine in end.o */
   /* This should also be available in the SOM symbol dict. if end.o linked in */
@@ -4053,8 +4481,8 @@ child_enable_exception_callback (kind, enable)
        }
       else
        {
-         warning ("Internal error: Invalid inferior pid?  Cannot intercept exception events.");        /* purecov: deadcode */
-         return (struct symtab_and_line *) -1;         /* purecov: deadcode */
+         warning ("Internal error: Invalid inferior pid?  Cannot intercept exception events.");
+         return (struct symtab_and_line *) -1;
        }
     }
 
@@ -4076,8 +4504,8 @@ child_enable_exception_callback (kind, enable)
          return (struct symtab_and_line *) -1;
        }
       break;
-    default:                   /* purecov: deadcode */
-      error ("Request to enable unknown or unsupported exception event.");     /* purecov: deadcode */
+    default:
+      error ("Request to enable unknown or unsupported exception event.");
     }
 
   /* Copy break address into new sal struct, malloc'ing if needed. */
@@ -4315,6 +4743,30 @@ hppa_prepare_to_proceed ()
 }
 #endif /* PREPARE_TO_PROCEED */
 
+void
+hppa_skip_permanent_breakpoint ()
+{
+  /* To step over a breakpoint instruction on the PA takes some
+     fiddling with the instruction address queue.
+
+     When we stop at a breakpoint, the IA queue front (the instruction
+     we're executing now) points at the breakpoint instruction, and
+     the IA queue back (the next instruction to execute) points to
+     whatever instruction we would execute after the breakpoint, if it
+     were an ordinary instruction.  This is the case even if the
+     breakpoint is in the delay slot of a branch instruction.
+
+     Clearly, to step past the breakpoint, we need to set the queue
+     front to the back.  But what do we put in the back?  What
+     instruction comes after that one?  Because of the branch delay
+     slot, the next insn is always at the back + 4.  */
+  write_register (PCOQ_HEAD_REGNUM, read_register (PCOQ_TAIL_REGNUM));
+  write_register (PCSQ_HEAD_REGNUM, read_register (PCSQ_TAIL_REGNUM));
+
+  write_register (PCOQ_TAIL_REGNUM, read_register (PCOQ_TAIL_REGNUM) + 4);
+  /* We can leave the tail's space the same, since there's no jump.  */
+}
+
 void
 _initialize_hppa_tdep ()
 {
This page took 0.043236 seconds and 4 git commands to generate.