* Bringing over SKY PKE disassembler feature from sky branch.
[deliverable/binutils-gdb.git] / gdb / hppa-tdep.c
index b7711700c34bd7d7dfd8d4a9c1353b5434616a91..0ecbc85647d5e74bbabec79f619f9ac716c2c772 100644 (file)
@@ -1,5 +1,5 @@
 /* Target-dependent code for the HP PA architecture, for GDB.
-   Copyright 1986, 1987, 1989, 1990, 1991, 1992, 1993, 1994, 1995
+   Copyright 1986, 1987, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996
    Free Software Foundation, Inc.
 
    Contributed by the Center for Software Science at the
@@ -19,7 +19,7 @@ GNU General Public License for more details.
 
 You should have received a copy of the GNU General Public License
 along with this program; if not, write to the Free Software
-Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
 
 #include "defs.h"
 #include "frame.h"
@@ -40,13 +40,10 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
 #include "a.out.encap.h"
 #else
 #endif
-#ifndef N_SET_MAGIC
-#define N_SET_MAGIC(exec, val) ((exec).a_magic = (val))
-#endif
 
 /*#include <sys/user.h>                After a.out.h  */
 #include <sys/file.h>
-#include <sys/stat.h>
+#include "gdb_stat.h"
 #include "wait.h"
 
 #include "gdbcore.h"
@@ -55,12 +52,41 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
 #include "symfile.h"
 #include "objfiles.h"
 
+static int extract_5_load PARAMS ((unsigned int));
+
+static unsigned extract_5R_store PARAMS ((unsigned int));
+
+static unsigned extract_5r_store PARAMS ((unsigned int));
+
+static void find_dummy_frame_regs PARAMS ((struct frame_info *,
+                                          struct frame_saved_regs *));
+
+static int find_proc_framesize PARAMS ((CORE_ADDR));
+
+static int find_return_regnum PARAMS ((CORE_ADDR));
+
+struct unwind_table_entry *find_unwind_entry PARAMS ((CORE_ADDR));
+
+static int extract_17 PARAMS ((unsigned int));
+
+static unsigned deposit_21 PARAMS ((unsigned int, unsigned int));
+
+static int extract_21 PARAMS ((unsigned));
+
+static unsigned deposit_14 PARAMS ((int, unsigned int));
+
+static int extract_14 PARAMS ((unsigned));
+
+static void unwind_command PARAMS ((char *, int));
+
+static int low_sign_extend PARAMS ((unsigned int, unsigned int));
+
+static int sign_extend PARAMS ((unsigned int, unsigned int));
+
 static int restore_pc_queue PARAMS ((struct frame_saved_regs *));
 
 static int hppa_alignof PARAMS ((struct type *));
 
-CORE_ADDR frame_saved_pc PARAMS ((struct frame_info *));
-
 static int prologue_inst_adjust_sp PARAMS ((unsigned long));
 
 static int is_branch PARAMS ((unsigned long));
@@ -73,8 +99,7 @@ static int pc_in_interrupt_handler PARAMS ((CORE_ADDR));
 
 static int pc_in_linker_stub PARAMS ((CORE_ADDR));
 
-static int compare_unwind_entries PARAMS ((const struct unwind_table_entry *,
-                                          const struct unwind_table_entry *));
+static int compare_unwind_entries PARAMS ((const void *, const void *));
 
 static void read_unwind_info PARAMS ((struct objfile *));
 
@@ -92,23 +117,26 @@ static void pa_print_fp_reg PARAMS ((int));
 /* This assumes that no garbage lies outside of the lower bits of 
    value. */
 
-int
+static int
 sign_extend (val, bits)
      unsigned val, bits;
 {
-  return (int)(val >> bits - 1 ? (-1 << bits) | val : val);
+  return (int)(val >> (bits - 1) ? (-1 << bits) | val : val);
 }
 
 /* For many immediate values the sign bit is the low bit! */
 
-int
+static int
 low_sign_extend (val, bits)
      unsigned val, bits;
 {
   return (int)((val & 0x1 ? (-1 << (bits - 1)) : 0) | val >> 1);
 }
+
 /* extract the immediate field from a ld{bhw}s instruction */
 
+#if 0
+
 unsigned
 get_field (val, from, to)
      unsigned val, from, to;
@@ -127,18 +155,24 @@ set_field (val, from, to, new_val)
 
 /* extract a 3-bit space register number from a be, ble, mtsp or mfsp */
 
+int
 extract_3 (word)
      unsigned word;
 {
   return GET_FIELD (word, 18, 18) << 2 | GET_FIELD (word, 16, 17);
 }
-       
+
+#endif
+
+static int
 extract_5_load (word)
      unsigned word;
 {
   return low_sign_extend (word >> 16 & MASK_5, 5);
 }
 
+#if 0
+
 /* extract the immediate field from a st{bhw}s instruction */
 
 int
@@ -148,9 +182,11 @@ extract_5_store (word)
   return low_sign_extend (word & MASK_5, 5);
 }
 
+#endif /* 0 */
+       
 /* extract the immediate field from a break instruction */
 
-unsigned
+static unsigned
 extract_5r_store (word)
      unsigned word;
 {
@@ -159,7 +195,7 @@ extract_5r_store (word)
 
 /* extract the immediate field from a {sr}sm instruction */
 
-unsigned
+static unsigned
 extract_5R_store (word)
      unsigned word;
 {
@@ -168,6 +204,8 @@ extract_5R_store (word)
 
 /* extract an 11 bit immediate field */
 
+#if 0
+
 int
 extract_11 (word)
      unsigned word;
@@ -175,9 +213,11 @@ extract_11 (word)
   return low_sign_extend (word & MASK_11, 11);
 }
 
+#endif
+
 /* extract a 14 bit immediate field */
 
-int
+static int
 extract_14 (word)
      unsigned word;
 {
@@ -186,7 +226,7 @@ extract_14 (word)
 
 /* deposit a 14 bit constant in a word */
 
-unsigned
+static unsigned
 deposit_14 (opnd, word)
      int opnd;
      unsigned word;
@@ -198,7 +238,7 @@ deposit_14 (opnd, word)
 
 /* extract a 21 bit constant */
 
-int
+static int
 extract_21 (word)
      unsigned word;
 {
@@ -222,7 +262,7 @@ extract_21 (word)
    usually the top 21 bits of a 32 bit constant, we assume that only
    the low 21 bits of opnd are relevant */
 
-unsigned
+static unsigned
 deposit_21 (opnd, word)
      unsigned opnd, word;
 {
@@ -242,6 +282,8 @@ deposit_21 (opnd, word)
 
 /* extract a 12 bit constant from branch instructions */
 
+#if 0
+
 int
 extract_12 (word)
      unsigned word;
@@ -265,10 +307,12 @@ deposit_17 (opnd, word)
   return word;
 }
 
+#endif
+
 /* extract a 17 bit constant from branch instructions, returning the
    19 bit signed value. */
 
-int
+static int
 extract_17 (word)
      unsigned word;
 {
@@ -284,10 +328,13 @@ extract_17 (word)
    larger than the first, and zero if they are equal.  */
 
 static int
-compare_unwind_entries (a, b)
-     const struct unwind_table_entry *a;
-     const struct unwind_table_entry *b;
+compare_unwind_entries (arg1, arg2)
+     const void *arg1;
+     const void *arg2;
 {
+  const struct unwind_table_entry *a = arg1;
+  const struct unwind_table_entry *b = arg2;
+
   if (a->region_start > b->region_start)
     return 1;
   else if (a->region_start < b->region_start)
@@ -487,7 +534,7 @@ read_unwind_info (objfile)
    contains a sorted list of struct unwind_table_entry.  Since we do a binary
    search of the unwind tables, we depend upon them to be sorted.  */
 
-static struct unwind_table_entry *
+struct unwind_table_entry *
 find_unwind_entry(pc)
      CORE_ADDR pc;
 {
@@ -665,7 +712,7 @@ find_return_regnum(pc)
 }
 
 /* Return size of frame, or -1 if we should use a frame pointer.  */
-int
+static int
 find_proc_framesize (pc)
      CORE_ADDR pc;
 {
@@ -762,13 +809,13 @@ saved_pc_after_call (frame)
      the stub will return to out of the stack.  */
   u = find_unwind_entry (pc);
   if (u && u->stub_type != 0)
-    return frame_saved_pc (frame);
+    return FRAME_SAVED_PC (frame);
   else
     return pc;
 }
 \f
 CORE_ADDR
-frame_saved_pc (frame)
+hppa_frame_saved_pc (frame)
      struct frame_info *frame;
 {
   CORE_ADDR pc = get_frame_pc (frame);
@@ -863,10 +910,29 @@ restart:
     }
 
   /* If PC is inside a linker stub, then dig out the address the stub
-     will return to.  */
+     will return to. 
+
+     Don't do this for long branch stubs.  Why?  For some unknown reason
+     _start is marked as a long branch stub in hpux10.  */
   u = find_unwind_entry (pc);
-  if (u && u->stub_type != 0)
-    goto restart;
+  if (u && u->stub_type != 0
+      && u->stub_type != LONG_BRANCH)
+    {
+      unsigned int insn;
+
+      /* If this is a dynamic executable, and we're in a signal handler,
+        then the call chain will eventually point us into the stub for
+        _sigreturn.  Unlike most cases, we'll be pointed to the branch
+        to the real sigreturn rather than the code after the real branch!. 
+
+        Else, try to dig the address the stub will return to in the normal
+        fashion.  */
+      insn = read_memory_integer (pc, 4);
+      if ((insn & 0xfc00e000) == 0xe8000000)
+       return (pc + extract_17 (insn) + 8) & ~0x3;
+      else
+       goto restart;
+    }
 
   return pc;
 }
@@ -940,6 +1006,7 @@ frame_chain (frame)
   int my_framesize, caller_framesize;
   struct unwind_table_entry *u;
   CORE_ADDR frame_base;
+  struct frame_info *tmp_frame;
 
   /* Handle HPUX, BSD, and OSF1 style interrupt frames first.  These
      are easy; at *sp we have a full save state strucutre which we can
@@ -988,9 +1055,10 @@ frame_chain (frame)
      We use information from unwind descriptors to determine if %r3
      is saved into the stack (Entry_GR field has this information).  */
 
-  while (frame)
+  tmp_frame = frame;
+  while (tmp_frame)
     {
-      u = find_unwind_entry (frame->pc);
+      u = find_unwind_entry (tmp_frame->pc);
 
       if (!u)
        {
@@ -998,39 +1066,104 @@ frame_chain (frame)
             think anyone has actually written any tools (not even "strip")
             which leave them out of an executable, so maybe this is a moot
             point.  */
-         warning ("Unable to find unwind for PC 0x%x -- Help!", frame->pc);
+         warning ("Unable to find unwind for PC 0x%x -- Help!", tmp_frame->pc);
          return 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
-         || frame->signal_handler_caller
-         || pc_in_interrupt_handler (frame->pc))
+         || tmp_frame->signal_handler_caller
+         || pc_in_interrupt_handler (tmp_frame->pc))
        break;
       else
-       frame = frame->next;
+       tmp_frame = tmp_frame->next;
     }
 
-  if (frame)
+  if (tmp_frame)
     {
       /* We may have walked down the chain into a function with a frame
         pointer.  */
       if (u->Save_SP
-         && !frame->signal_handler_caller
-         && !pc_in_interrupt_handler (frame->pc))
-       return read_memory_integer (frame->frame, 4);
+         && !tmp_frame->signal_handler_caller
+         && !pc_in_interrupt_handler (tmp_frame->pc))
+       return read_memory_integer (tmp_frame->frame, 4);
       /* %r3 was saved somewhere in the stack.  Dig it out.  */
       else 
        {
          struct frame_saved_regs saved_regs;
 
-         get_frame_saved_regs (frame, &saved_regs);
+         /* Sick.
+
+            For optimization purposes many kernels don't have the
+            callee saved registers into the save_state structure upon
+            entry into the kernel for a syscall; the optimization
+            is usually turned off if the process is being traced so
+            that the debugger can get full register state for the
+            process.
+             
+            This scheme works well except for two cases:
+
+              * Attaching to a process when the process is in the
+              kernel performing a system call (debugger can't get
+              full register state for the inferior process since
+              the process wasn't being traced when it entered the
+              system call).
+
+              * Register state is not complete if the system call
+              causes the process to core dump.
+
+
+            The following heinous code is an attempt to deal with
+            the lack of register state in a core dump.  It will
+            fail miserably if the function which performs the
+            system call has a variable sized stack 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)
+                      & 0x2))
+                 || (saved_regs.regs[FLAGS_REGNUM] == 0
+                     && read_register (FLAGS_REGNUM) & 0x2)))
+           {
+             u = find_unwind_entry (FRAME_SAVED_PC (frame));
+             if (!u)
+               return read_memory_integer (saved_regs.regs[FP_REGNUM], 4);
+             else
+               return frame_base - (u->Total_frame_size << 3);
+           }
+       
          return read_memory_integer (saved_regs.regs[FP_REGNUM], 4);
        }
     }
   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);
+      /* 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)
+                  & 0x2))
+             || (saved_regs.regs[FLAGS_REGNUM] == 0
+                 && read_register (FLAGS_REGNUM)  & 0x2)))
+       {
+         u = find_unwind_entry (FRAME_SAVED_PC (frame));
+         if (!u)
+           return read_memory_integer (saved_regs.regs[FP_REGNUM], 4);
+          else
+           return frame_base - (u->Total_frame_size << 3);
+       }
+       
       /* The value in %r3 was never saved into the stack (thus %r3 still
         holds the value of the previous frame pointer).  */
       return read_register (FP_REGNUM);
@@ -1072,6 +1205,14 @@ frame_chain_valid (chain, thisframe)
       && SYMBOL_VALUE_ADDRESS (msym_us) == SYMBOL_VALUE_ADDRESS (msym_start))
     return 0;
 
+  /* Grrrr.  Some new idiot decided that they don't want _start for the
+     PRO configurations; $START$ calls main directly....  Deal with it.  */
+  msym_start = lookup_minimal_symbol ("$START$", NULL, NULL);
+  if (msym_us
+      && msym_start
+      && SYMBOL_VALUE_ADDRESS (msym_us) == SYMBOL_VALUE_ADDRESS (msym_start))
+    return 0;
+
   next = get_next_frame (thisframe);
   if (next)
     next_u = find_unwind_entry (next->pc);
@@ -1171,7 +1312,7 @@ push_dummy_frame (inf_status)
   write_register (SP_REGNUM, sp);
 }
 
-void
+static void
 find_dummy_frame_regs (frame, frame_saved_regs)
      struct frame_info *frame;
      struct frame_saved_regs *frame_saved_regs;
@@ -1179,7 +1320,7 @@ find_dummy_frame_regs (frame, frame_saved_regs)
   CORE_ADDR fp = frame->frame;
   int i;
 
-  frame_saved_regs->regs[RP_REGNUM] = fp - 20 & ~0x3;
+  frame_saved_regs->regs[RP_REGNUM] = (fp - 20) & ~0x3;
   frame_saved_regs->regs[FP_REGNUM] = fp;
   frame_saved_regs->regs[1] = fp + 8;
 
@@ -1250,7 +1391,7 @@ hppa_pop_frame ()
   else 
     {
       npc = read_register (RP_REGNUM);
-      target_write_pc (npc, 0);
+      write_pc (npc);
     }
 
   write_register (FP_REGNUM, read_memory_integer (fp, 4));
@@ -1285,6 +1426,7 @@ hppa_pop_frame ()
       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);
 
@@ -1409,9 +1551,11 @@ hppa_fix_call_dummy (dummy, pc, fun, nargs, args, type, gcc_p)
 {
   CORE_ADDR dyncall_addr;
   struct minimal_symbol *msymbol;
+  struct minimal_symbol *trampoline;
   int flags = read_register (FLAGS_REGNUM);
   struct unwind_table_entry *u;
 
+  trampoline = NULL;
   msymbol = lookup_minimal_symbol ("$$dyncall", NULL, NULL);
   if (msymbol == NULL)
     error ("Can't find an address for $$dyncall trampoline");
@@ -1460,7 +1604,7 @@ hppa_fix_call_dummy (dummy, pc, fun, nargs, args, type, gcc_p)
                {
                  struct unwind_table_entry *u;
                  /* It must be a shared library trampoline.  */
-                 if (SYMBOL_TYPE (stub_symbol) != mst_solib_trampoline)
+                 if (MSYMBOL_TYPE (stub_symbol) != mst_solib_trampoline)
                    continue;
 
                  /* It must also be an import stub.  */
@@ -1489,19 +1633,20 @@ hppa_fix_call_dummy (dummy, pc, fun, nargs, args, type, gcc_p)
   if (u && u->stub_type == IMPORT)
     {
       CORE_ADDR new_fun;
-      msymbol = lookup_minimal_symbol ("__d_plt_call", NULL, NULL);
-      if (msymbol == NULL)
-       msymbol = lookup_minimal_symbol ("__gcc_plt_call", NULL, NULL);
 
-      if (msymbol == NULL)
+      /* Prefer __gcc_plt_call over the HP supplied routine because
+        __gcc_plt_call works for any number of arguments.  */
+      trampoline = lookup_minimal_symbol ("__gcc_plt_call", NULL, NULL);
+      if (trampoline == NULL)
+       trampoline = lookup_minimal_symbol ("__d_plt_call", NULL, NULL);
+
+      if (trampoline == NULL)
        error ("Can't find an address for __d_plt_call or __gcc_plt_call trampoline");
 
       /* This is where sr4export will jump to.  */
-      new_fun = SYMBOL_VALUE_ADDRESS (msymbol);
+      new_fun = SYMBOL_VALUE_ADDRESS (trampoline);
 
-      if (strcmp (SYMBOL_NAME (msymbol), "__d_plt_call"))
-       write_register (22, fun);
-      else
+      if (strcmp (SYMBOL_NAME (trampoline), "__d_plt_call") == 0)
        {
          /* We have to store the address of the stub in __shlib_funcptr.  */
          msymbol = lookup_minimal_symbol ("__shlib_funcptr", NULL,
@@ -1510,12 +1655,17 @@ hppa_fix_call_dummy (dummy, pc, fun, nargs, args, type, gcc_p)
            error ("Can't find an address for __shlib_funcptr");
 
          target_write_memory (SYMBOL_VALUE_ADDRESS (msymbol), (char *)&fun, 4);
+
+         /* We want sr4export to call __d_plt_call, so we claim it is
+            the final target.  Clear trampoline.  */
+         fun = new_fun;
+         trampoline = NULL;
        }
-      fun = new_fun;
     }
 
-/* Store upper 21 bits of function address into ldil */
-
+  /* 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.  */
   store_unsigned_integer
     (&dummy[FUNC_LDIL_OFFSET],
      INSTRUCTION_SIZE,
@@ -1523,8 +1673,7 @@ hppa_fix_call_dummy (dummy, pc, fun, nargs, args, type, gcc_p)
                 extract_unsigned_integer (&dummy[FUNC_LDIL_OFFSET],
                                           INSTRUCTION_SIZE)));
 
-/* Store lower 11 bits of function address into ldo */
-
+  /* Store lower 11 bits of function address into ldo */
   store_unsigned_integer
     (&dummy[FUNC_LDO_OFFSET],
      INSTRUCTION_SIZE,
@@ -1534,30 +1683,35 @@ hppa_fix_call_dummy (dummy, pc, fun, nargs, args, type, gcc_p)
 #ifdef SR4EXPORT_LDIL_OFFSET
 
   {
-    CORE_ADDR sr4export_addr;
+    CORE_ADDR trampoline_addr;
 
-    /* We still need sr4export's address too.  */
+    /* We may still need sr4export's address too.  */
 
-    msymbol = lookup_minimal_symbol ("_sr4export", NULL, NULL);
-    if (msymbol == NULL)
-      error ("Can't find an address for _sr4export trampoline");
+    if (trampoline == NULL)
+      {
+       msymbol = lookup_minimal_symbol ("_sr4export", NULL, NULL);
+       if (msymbol == NULL)
+         error ("Can't find an address for _sr4export trampoline");
 
-    sr4export_addr = SYMBOL_VALUE_ADDRESS (msymbol);
+       trampoline_addr = SYMBOL_VALUE_ADDRESS (msymbol);
+      }
+    else
+      trampoline_addr = SYMBOL_VALUE_ADDRESS (trampoline);
 
-/* Store upper 21 bits of sr4export's address into ldil */
 
+    /* Store upper 21 bits of trampoline's address into ldil */
     store_unsigned_integer
       (&dummy[SR4EXPORT_LDIL_OFFSET],
        INSTRUCTION_SIZE,
-       deposit_21 (sr4export_addr >> 11,
+       deposit_21 (trampoline_addr >> 11,
                   extract_unsigned_integer (&dummy[SR4EXPORT_LDIL_OFFSET],
                                             INSTRUCTION_SIZE)));
-/* Store lower 11 bits of sr4export's address into ldo */
 
+    /* Store lower 11 bits of trampoline's address into ldo */
     store_unsigned_integer
       (&dummy[SR4EXPORT_LDO_OFFSET],
        INSTRUCTION_SIZE,
-       deposit_14 (sr4export_addr & MASK_11,
+       deposit_14 (trampoline_addr & MASK_11,
                   extract_unsigned_integer (&dummy[SR4EXPORT_LDO_OFFSET],
                                             INSTRUCTION_SIZE)));
   }
@@ -1592,12 +1746,15 @@ CORE_ADDR
 target_read_pc (pid)
      int pid;
 {
-  int flags = read_register (FLAGS_REGNUM);
+  int flags = read_register_pid (FLAGS_REGNUM, pid);
 
-  if (flags & 2) {
-    return read_register (31) & ~0x3;
-  }
-  return read_register (PC_REGNUM) & ~0x3;
+  /* The following test does not belong here.  It is OS-specific, and belongs
+     in native code.  */
+  /* Test SS_INSYSCALL */
+  if (flags & 2)
+    return read_register_pid (31, pid) & ~0x3;
+
+  return read_register_pid (PC_REGNUM, pid) & ~0x3;
 }
 
 /* Write out the PC.  If currently in a syscall, then also write the new
@@ -1608,42 +1765,46 @@ target_write_pc (v, pid)
      CORE_ADDR v;
      int pid;
 {
-  int flags = read_register (FLAGS_REGNUM);
+  int flags = read_register_pid (FLAGS_REGNUM, pid);
 
+  /* The following test does not belong here.  It is OS-specific, and belongs
+     in native code.  */
   /* If in a syscall, then set %r31.  Also make sure to get the 
      privilege bits set correctly.  */
+  /* Test SS_INSYSCALL */
   if (flags & 2)
-    write_register (31, (long) (v | 0x3));
+    write_register_pid (31, v | 0x3, pid);
 
-  write_register (PC_REGNUM, (long) v);
-  write_register (NPC_REGNUM, (long) v + 4);
+  write_register_pid (PC_REGNUM, v, pid);
+  write_register_pid (NPC_REGNUM, v + 4, pid);
 }
 
 /* return the alignment of a type in bytes. Structures have the maximum
    alignment required by their fields. */
 
 static int
-hppa_alignof (arg)
-     struct type *arg;
+hppa_alignof (type)
+     struct type *type;
 {
   int max_align, align, i;
-  switch (TYPE_CODE (arg))
+  CHECK_TYPEDEF (type);
+  switch (TYPE_CODE (type))
     {
     case TYPE_CODE_PTR:
     case TYPE_CODE_INT:
     case TYPE_CODE_FLT:
-      return TYPE_LENGTH (arg);
+      return TYPE_LENGTH (type);
     case TYPE_CODE_ARRAY:
-      return hppa_alignof (TYPE_FIELD_TYPE (arg, 0));
+      return hppa_alignof (TYPE_FIELD_TYPE (type, 0));
     case TYPE_CODE_STRUCT:
     case TYPE_CODE_UNION:
-      max_align = 2;
-      for (i = 0; i < TYPE_NFIELDS (arg); i++)
+      max_align = 1;
+      for (i = 0; i < TYPE_NFIELDS (type); i++)
        {
          /* Bit fields have no real alignment. */
-         if (!TYPE_FIELD_BITPOS (arg, i))
+         if (!TYPE_FIELD_BITPOS (type, i))
            {
-             align = hppa_alignof (TYPE_FIELD_TYPE (arg, i));
+             align = hppa_alignof (TYPE_FIELD_TYPE (type, i));
              max_align = max (max_align, align);
            }
        }
@@ -2208,10 +2369,15 @@ skip_prologue (pc)
      CORE_ADDR pc;
 {
   char buf[4];
+  CORE_ADDR orig_pc = pc;
   unsigned long inst, stack_remaining, save_gr, save_fr, save_rp, save_sp;
-  unsigned long args_stored, status, i;
+  unsigned long args_stored, status, i, restart_gr, restart_fr;
   struct unwind_table_entry *u;
 
+  restart_gr = 0;
+  restart_fr = 0;
+
+restart:
   u = find_unwind_entry (pc);
   if (!u)
     return pc;
@@ -2230,7 +2396,7 @@ skip_prologue (pc)
   /* An indication that args may be stored into the stack.  Unfortunately
      the HPUX compilers tend to set this in cases where no args were
      stored too!.  */
-  args_stored = u->Args_stored;
+  args_stored = 1;
 
   /* Turn the Entry_GR field into a bitmask.  */
   save_gr = 0;
@@ -2242,11 +2408,13 @@ skip_prologue (pc)
 
       save_gr |= (1 << i);
     }
+  save_gr &= ~restart_gr;
 
   /* Turn the Entry_FR field into a bitmask too.  */
   save_fr = 0;
   for (i = 12; i < u->Entry_FR + 12; i++)
     save_fr |= (1 << i);
+  save_fr &= ~restart_fr;
 
   /* Loop until we find everything of interest or hit a branch.
 
@@ -2396,6 +2564,21 @@ skip_prologue (pc)
       pc += 4;
     }
 
+  /* We've got a tenative location for the end of the prologue.  However
+     because of limitations in the unwind descriptor mechanism we may
+     have went too far into user code looking for the save of a register
+     that does not exist.  So, if there registers we expected to be saved
+     but never were, mask them out and restart.
+
+     This should only happen in optimized code, and should be very rare.  */
+  if (save_gr || (save_fr && ! (restart_fr || restart_gr)))
+    {
+      pc = orig_pc;
+      restart_gr = save_gr;
+      restart_fr = save_fr;
+      goto restart;
+    }
+
   return pc;
 }
 
This page took 0.033568 seconds and 4 git commands to generate.