*** empty log message ***
[deliverable/binutils-gdb.git] / gdb / hppa-tdep.c
index 8aa860d4c4d1294ae116c722f64cf3cfbde12d53..1209584e93e0bb3ccf0c3b8489704e23018c9ec2 100644 (file)
    Boston, MA 02111-1307, USA.  */
 
 #include "defs.h"
-#include "frame.h"
 #include "bfd.h"
 #include "inferior.h"
-#include "value.h"
 #include "regcache.h"
 #include "completer.h"
-#include "language.h"
 #include "osabi.h"
 #include "gdb_assert.h"
-#include "infttrace.h"
 #include "arch-utils.h"
 /* For argument passing to the inferior */
 #include "symtab.h"
-#include "infcall.h"
 #include "dis-asm.h"
 #include "trad-frame.h"
 #include "frame-unwind.h"
 #include "frame-base.h"
 
-#include "gdb_stat.h"
-#include "gdb_wait.h"
-
 #include "gdbcore.h"
 #include "gdbcmd.h"
-#include "target.h"
-#include "symfile.h"
 #include "objfiles.h"
 #include "hppa-tdep.h"
 
@@ -74,41 +64,10 @@ const struct objfile_data *hppa_objfile_priv_data = NULL;
 #define MASK_14 0x3fff
 #define MASK_21 0x1fffff
 
-/* Define offsets into the call dummy for the _sr4export address.
-   See comments related to CALL_DUMMY for more info.  */
-#define SR4EXPORT_LDIL_OFFSET (HPPA_INSTRUCTION_SIZE * 12)
-#define SR4EXPORT_LDO_OFFSET (HPPA_INSTRUCTION_SIZE * 13)
-
-/* To support detection of the pseudo-initial frame
-   that threads have. */
-#define THREAD_INITIAL_FRAME_SYMBOL  "__pthread_exit"
-#define THREAD_INITIAL_FRAME_SYM_LEN  sizeof(THREAD_INITIAL_FRAME_SYMBOL)
-
 /* Sizes (in bytes) of the native unwind entries.  */
 #define UNWIND_ENTRY_SIZE 16
 #define STUB_UNWIND_ENTRY_SIZE 8
 
-static void unwind_command (char *, int);
-
-static int hppa_alignof (struct type *);
-
-static int prologue_inst_adjust_sp (unsigned long);
-
-static int is_branch (unsigned long);
-
-static int inst_saves_gr (unsigned long);
-
-static int inst_saves_fr (unsigned long);
-
-static int compare_unwind_entries (const void *, const void *);
-
-static void read_unwind_info (struct objfile *);
-
-static void internalize_unwinds (struct objfile *,
-                                struct unwind_table_entry *,
-                                asection *, unsigned int,
-                                unsigned int, CORE_ADDR);
-static void record_text_segment_lowaddr (bfd *, asection *, void *);
 /* FIXME: brobecker 2002-11-07: We will likely be able to make the
    following functions static, once we hppa is partially multiarched.  */
 int hppa_pc_requires_run_before_use (CORE_ADDR pc);
@@ -121,22 +80,12 @@ hppa32_return_value (struct gdbarch *gdbarch,
                     struct type *type, struct regcache *regcache,
                     void *readbuf, const void *writebuf)
 {
-  if (TYPE_CODE (type) == TYPE_CODE_FLT)
-    {
-      if (readbuf != NULL)
-       regcache_cooked_read_part (regcache, FP4_REGNUM, 0,
-                                  TYPE_LENGTH (type), readbuf);
-      if (writebuf != NULL)
-       regcache_cooked_write_part (regcache, FP4_REGNUM, 0,
-                                   TYPE_LENGTH (type), writebuf);
-      return RETURN_VALUE_REGISTER_CONVENTION;
-    }
   if (TYPE_LENGTH (type) <= 2 * 4)
     {
       /* The value always lives in the right hand end of the register
         (or register pair)?  */
       int b;
-      int reg = 28;
+      int reg = TYPE_CODE (type) == TYPE_CODE_FLT ? HPPA_FP4_REGNUM : 28;
       int part = TYPE_LENGTH (type) % 4;
       /* The left hand register contains only part of the value,
         transfer that first so that the rest can be xfered as entire
@@ -179,19 +128,19 @@ hppa64_return_value (struct gdbarch *gdbarch,
       && TYPE_LENGTH (type) <= 8)
     {
       /* Floats are right aligned?  */
-      int offset = register_size (gdbarch, FP4_REGNUM) - TYPE_LENGTH (type);
+      int offset = register_size (gdbarch, HPPA_FP4_REGNUM) - TYPE_LENGTH (type);
       if (readbuf != NULL)
-       regcache_cooked_read_part (regcache, FP4_REGNUM, offset,
+       regcache_cooked_read_part (regcache, HPPA_FP4_REGNUM, offset,
                                   TYPE_LENGTH (type), readbuf);
       if (writebuf != NULL)
-       regcache_cooked_write_part (regcache, FP4_REGNUM, offset,
+       regcache_cooked_write_part (regcache, HPPA_FP4_REGNUM, offset,
                                    TYPE_LENGTH (type), writebuf);
       return RETURN_VALUE_REGISTER_CONVENTION;
     }
   else if (TYPE_LENGTH (type) <= 8 && is_integral_type (type))
     {
       /* Integrals are right aligned.  */
-      int offset = register_size (gdbarch, FP4_REGNUM) - TYPE_LENGTH (type);
+      int offset = register_size (gdbarch, HPPA_FP4_REGNUM) - TYPE_LENGTH (type);
       if (readbuf != NULL)
        regcache_cooked_read_part (regcache, 28, offset,
                                   TYPE_LENGTH (type), readbuf);
@@ -313,6 +262,18 @@ hppa_extract_17 (unsigned word)
                      hppa_get_field (word, 11, 15) << 11 |
                      (word & 0x1) << 16, 17) << 2;
 }
+
+CORE_ADDR 
+hppa_symbol_address(const char *sym)
+{
+  struct minimal_symbol *minsym;
+
+  minsym = lookup_minimal_symbol (sym, NULL, NULL);
+  if (minsym)
+    return SYMBOL_VALUE_ADDRESS (minsym);
+  else
+    return (CORE_ADDR)-1;
+}
 \f
 
 /* Compare the start address for two unwind entries returning 1 if 
@@ -760,14 +721,11 @@ hppa64_register_name (int i)
    arguments into their proper slots.  */
    
 CORE_ADDR
-hppa32_push_dummy_call (struct gdbarch *gdbarch, CORE_ADDR func_addr,
+hppa32_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
                        struct regcache *regcache, CORE_ADDR bp_addr,
                        int nargs, struct value **args, CORE_ADDR sp,
                        int struct_return, CORE_ADDR struct_addr)
 {
-  /* NOTE: cagney/2004-02-27: This is a guess - its implemented by
-     reverse engineering testsuite failures.  */
-
   /* Stack base address at which any pass-by-reference parameters are
      stored.  */
   CORE_ADDR struct_end = 0;
@@ -781,12 +739,22 @@ hppa32_push_dummy_call (struct gdbarch *gdbarch, CORE_ADDR func_addr,
   /* Two passes.  First pass computes the location of everything,
      second pass writes the bytes out.  */
   int write_pass;
+
+  /* Global pointer (r19) of the function we are trying to call.  */
+  CORE_ADDR gp;
+
+  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+
   for (write_pass = 0; write_pass < 2; write_pass++)
     {
       CORE_ADDR struct_ptr = 0;
-      CORE_ADDR param_ptr = 0;
-      int reg = 27;          /* NOTE: Registers go down.  */
+      /* The first parameter goes into sp-36, each stack slot is 4-bytes.  
+         struct_ptr is adjusted for each argument below, so the first
+        argument will end up at sp-36.  */
+      CORE_ADDR param_ptr = 32;
       int i;
+      int small_struct = 0;
+
       for (i = 0; i < nargs; i++)
        {
          struct value *arg = args[i];
@@ -817,23 +785,64 @@ hppa32_push_dummy_call (struct gdbarch *gdbarch, CORE_ADDR func_addr,
                                      unpack_long (type,
                                                   VALUE_CONTENTS (arg)));
            }
+         else if (TYPE_CODE (type) == TYPE_CODE_FLT)
+            {
+             /* Floating point value store, right aligned.  */
+             param_len = align_up (TYPE_LENGTH (type), 4);
+             memcpy (param_val, VALUE_CONTENTS (arg), param_len);
+            }
          else
            {
-             /* Small struct value, store right aligned?  */
              param_len = align_up (TYPE_LENGTH (type), 4);
+
+             /* Small struct value are stored right-aligned.  */
              memcpy (param_val + param_len - TYPE_LENGTH (type),
                      VALUE_CONTENTS (arg), TYPE_LENGTH (type));
+
+             /* Structures of size 5, 6 and 7 bytes are special in that
+                the higher-ordered word is stored in the lower-ordered
+                argument, and even though it is a 8-byte quantity the
+                registers need not be 8-byte aligned.  */
+             if (param_len > 4 && param_len < 8)
+               small_struct = 1;
            }
+
          param_ptr += param_len;
-         reg -= param_len / 4;
+         if (param_len == 8 && !small_struct)
+            param_ptr = align_up (param_ptr, 8);
+
+         /* First 4 non-FP arguments are passed in gr26-gr23.
+            First 4 32-bit FP arguments are passed in fr4L-fr7L.
+            First 2 64-bit FP arguments are passed in fr5 and fr7.
+
+            The rest go on the stack, starting at sp-36, towards lower
+            addresses.  8-byte arguments must be aligned to a 8-byte
+            stack boundary.  */
          if (write_pass)
            {
              write_memory (param_end - param_ptr, param_val, param_len);
-             if (reg >= 23)
+
+             /* There are some cases when we don't know the type
+                expected by the callee (e.g. for variadic functions), so 
+                pass the parameters in both general and fp regs.  */
+             if (param_ptr <= 48)
                {
-                 regcache_cooked_write (regcache, reg, param_val);
+                 int grreg = 26 - (param_ptr - 36) / 4;
+                 int fpLreg = 72 + (param_ptr - 36) / 4 * 2;
+                 int fpreg = 74 + (param_ptr - 32) / 8 * 4;
+
+                 regcache_cooked_write (regcache, grreg, param_val);
+                 regcache_cooked_write (regcache, fpLreg, param_val);
+
                  if (param_len > 4)
-                   regcache_cooked_write (regcache, reg + 1, param_val + 4);
+                   {
+                     regcache_cooked_write (regcache, grreg + 1, 
+                                            param_val + 4);
+
+                     regcache_cooked_write (regcache, fpreg, param_val);
+                     regcache_cooked_write (regcache, fpreg + 1, 
+                                            param_val + 4);
+                   }
                }
            }
        }
@@ -841,13 +850,13 @@ hppa32_push_dummy_call (struct gdbarch *gdbarch, CORE_ADDR func_addr,
       /* Update the various stack pointers.  */
       if (!write_pass)
        {
-         struct_end = sp + struct_ptr;
+         struct_end = sp + align_up (struct_ptr, 64);
          /* PARAM_PTR 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.  */
-         param_end = struct_end + max (align_up (param_ptr, 8), 16);
+         param_end = struct_end + align_up (param_ptr, 64);
        }
     }
 
@@ -856,14 +865,18 @@ hppa32_push_dummy_call (struct gdbarch *gdbarch, CORE_ADDR func_addr,
   if (struct_return)
     write_register (28, struct_addr);
 
+  gp = tdep->find_global_pointer (function);
+
+  if (gp != 0)
+    write_register (19, gp);
+
   /* Set the return address.  */
-  regcache_cooked_write_unsigned (regcache, RP_REGNUM, bp_addr);
+  regcache_cooked_write_unsigned (regcache, HPPA_RP_REGNUM, bp_addr);
 
   /* Update the Stack Pointer.  */
-  regcache_cooked_write_unsigned (regcache, SP_REGNUM, param_end + 32);
+  regcache_cooked_write_unsigned (regcache, HPPA_SP_REGNUM, param_end);
 
-  /* The stack will have 32 bytes of additional space for a frame marker.  */
-  return param_end + 32;
+  return param_end;
 }
 
 /* This function pushes a stack frame with arguments as part of the
@@ -880,7 +893,7 @@ hppa32_push_dummy_call (struct gdbarch *gdbarch, CORE_ADDR func_addr,
    to the callee, so we do that too.  */
    
 CORE_ADDR
-hppa64_push_dummy_call (struct gdbarch *gdbarch, CORE_ADDR func_addr,
+hppa64_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
                        struct regcache *regcache, CORE_ADDR bp_addr,
                        int nargs, struct value **args, CORE_ADDR sp,
                        int struct_return, CORE_ADDR struct_addr)
@@ -980,15 +993,31 @@ hppa64_push_dummy_call (struct gdbarch *gdbarch, CORE_ADDR func_addr,
     write_register (28, struct_addr);
 
   /* Set the return address.  */
-  regcache_cooked_write_unsigned (regcache, RP_REGNUM, bp_addr);
+  regcache_cooked_write_unsigned (regcache, HPPA_RP_REGNUM, bp_addr);
 
   /* Update the Stack Pointer.  */
-  regcache_cooked_write_unsigned (regcache, SP_REGNUM, param_end + 64);
+  regcache_cooked_write_unsigned (regcache, HPPA_SP_REGNUM, param_end + 64);
 
   /* The stack will have 32 bytes of additional space for a frame marker.  */
   return param_end + 64;
 }
 
+static CORE_ADDR
+hppa32_convert_from_func_ptr_addr (struct gdbarch *gdbarch,
+                                  CORE_ADDR addr,
+                                  struct target_ops *targ)
+{
+  if (addr & 2)
+    {
+      CORE_ADDR plabel;
+
+      plabel = addr & ~3;
+      target_read_memory(plabel, (char *)&addr, 4);
+    }
+
+  return addr;
+}
+
 static CORE_ADDR
 hppa32_frame_align (struct gdbarch *gdbarch, CORE_ADDR addr)
 {
@@ -1013,7 +1042,7 @@ hppa64_frame_align (struct gdbarch *gdbarch, CORE_ADDR addr)
 static CORE_ADDR
 hppa_target_read_pc (ptid_t ptid)
 {
-  int flags = read_register_pid (FLAGS_REGNUM, ptid);
+  int flags = read_register_pid (HPPA_FLAGS_REGNUM, ptid);
 
   /* The following test does not belong here.  It is OS-specific, and belongs
      in native code.  */
@@ -1021,7 +1050,7 @@ hppa_target_read_pc (ptid_t ptid)
   if (flags & 2)
     return read_register_pid (31, ptid) & ~0x3;
 
-  return read_register_pid (PCOQ_HEAD_REGNUM, ptid) & ~0x3;
+  return read_register_pid (HPPA_PCOQ_HEAD_REGNUM, ptid) & ~0x3;
 }
 
 /* Write out the PC.  If currently in a syscall, then also write the new
@@ -1030,7 +1059,7 @@ hppa_target_read_pc (ptid_t ptid)
 static void
 hppa_target_write_pc (CORE_ADDR v, ptid_t ptid)
 {
-  int flags = read_register_pid (FLAGS_REGNUM, ptid);
+  int flags = read_register_pid (HPPA_FLAGS_REGNUM, ptid);
 
   /* The following test does not belong here.  It is OS-specific, and belongs
      in native code.  */
@@ -1040,8 +1069,8 @@ hppa_target_write_pc (CORE_ADDR v, ptid_t ptid)
   if (flags & 2)
     write_register_pid (31, v | 0x3, ptid);
 
-  write_register_pid (PCOQ_HEAD_REGNUM, v, ptid);
-  write_register_pid (PCOQ_TAIL_REGNUM, v + 4, ptid);
+  write_register_pid (HPPA_PCOQ_HEAD_REGNUM, v, ptid);
+  write_register_pid (HPPA_PCOQ_TAIL_REGNUM, v + 4, ptid);
 }
 
 /* return the alignment of a type in bytes. Structures have the maximum
@@ -1298,7 +1327,7 @@ restart:
       old_save_sp = save_sp;
       old_stack_remaining = stack_remaining;
 
-      status = target_read_memory (pc, buf, 4);
+      status = deprecated_read_memory_nobpt (pc, buf, 4);
       inst = extract_unsigned_integer (buf, 4);
 
       /* Yow! */
@@ -1347,7 +1376,7 @@ restart:
          while (reg_num >= (TARGET_PTR_BIT == 64 ? 19 : 23) && reg_num <= 26)
            {
              pc += 4;
-             status = target_read_memory (pc, buf, 4);
+             status = deprecated_read_memory_nobpt (pc, buf, 4);
              inst = extract_unsigned_integer (buf, 4);
              if (status != 0)
                return pc;
@@ -1360,7 +1389,7 @@ restart:
       reg_num = inst_saves_fr (inst);
       save_fr &= ~(1 << reg_num);
 
-      status = target_read_memory (pc + 4, buf, 4);
+      status = deprecated_read_memory_nobpt (pc + 4, buf, 4);
       next_inst = extract_unsigned_integer (buf, 4);
 
       /* Yow! */
@@ -1387,13 +1416,13 @@ restart:
          while (reg_num >= 4 && reg_num <= (TARGET_PTR_BIT == 64 ? 11 : 7))
            {
              pc += 8;
-             status = target_read_memory (pc, buf, 4);
+             status = deprecated_read_memory_nobpt (pc, buf, 4);
              inst = extract_unsigned_integer (buf, 4);
              if (status != 0)
                return pc;
              if ((inst & 0xfc000000) != 0x34000000)
                break;
-             status = target_read_memory (pc + 4, buf, 4);
+             status = deprecated_read_memory_nobpt (pc + 4, buf, 4);
              next_inst = extract_unsigned_integer (buf, 4);
              if (status != 0)
                return pc;
@@ -1618,7 +1647,7 @@ hppa_frame_cache (struct frame_info *next_frame, void **this_cache)
       {
        int reg;
        char buf4[4];
-       long status = target_read_memory (pc, buf4, sizeof buf4);
+       long status = deprecated_read_memory_nobpt (pc, buf4, sizeof buf4);
        long inst = extract_unsigned_integer (buf4, sizeof buf4);
 
        /* Note the interesting effects of this instruction.  */
@@ -1629,12 +1658,12 @@ hppa_frame_cache (struct frame_info *next_frame, void **this_cache)
        if (inst == 0x6bc23fd9) /* stw rp,-0x14(sr0,sp) */
          {
            looking_for_rp = 0;
-           cache->saved_regs[RP_REGNUM].addr = -20;
+           cache->saved_regs[HPPA_RP_REGNUM].addr = -20;
          }
        else if (inst == 0x0fc212c1) /* std rp,-0x10(sr0,sp) */
          {
            looking_for_rp = 0;
-           cache->saved_regs[RP_REGNUM].addr = -16;
+           cache->saved_regs[HPPA_RP_REGNUM].addr = -16;
          }
        
        /* Check to see if we saved SP into the stack.  This also
@@ -1705,7 +1734,7 @@ hppa_frame_cache (struct frame_info *next_frame, void **this_cache)
                /* 1st HP CC FP register store.  After this
                   instruction we've set enough state that the GCC and
                   HPCC code are both handled in the same manner.  */
-               cache->saved_regs[reg + FP4_REGNUM + 4].addr = 0;
+               cache->saved_regs[reg + HPPA_FP4_REGNUM + 4].addr = 0;
                fp_loc = 8;
              }
            else
@@ -1730,6 +1759,7 @@ hppa_frame_cache (struct frame_info *next_frame, void **this_cache)
        the current function (and is thus equivalent to the "saved"
        stack pointer.  */
     CORE_ADDR this_sp = frame_unwind_register_unsigned (next_frame, HPPA_SP_REGNUM);
+    CORE_ADDR fp;
 
     if (hppa_debug)
       fprintf_unfiltered (gdb_stdlog, " (this_sp=0x%s, pc=0x%s, "
@@ -1738,10 +1768,41 @@ hppa_frame_cache (struct frame_info *next_frame, void **this_cache)
                          paddr_nz (frame_pc_unwind (next_frame)),
                          paddr_nz (prologue_end));
 
-    if (frame_pc_unwind (next_frame) >= prologue_end)
+     /* Check to see if a frame pointer is available, and use it for
+        frame unwinding if it is.
+        There are some situations where we need to rely on the frame
+        pointer to do stack unwinding.  For example, if a function calls
+        alloca (), the stack pointer can get adjusted inside the body of
+        the function.  In this case, the ABI requires that the compiler
+        maintain a frame pointer for the function.
+        The unwind record has a flag (alloca_frame) that indicates that
+        a function has a variable frame; unfortunately, gcc/binutils 
+        does not set this flag.  Instead, whenever a frame pointer is used
+        and saved on the stack, the Save_SP flag is set.  We use this to
+        decide whether to use the frame pointer for unwinding.
+       
+       fp may be zero if it is not available in an inner frame because
+       it has been modified by not yet saved.
+       
+        TODO: For the HP compiler, maybe we should use the alloca_frame flag 
+       instead of Save_SP.  */
+     fp = frame_unwind_register_unsigned (next_frame, HPPA_FP_REGNUM);
+     if (frame_pc_unwind (next_frame) >= prologue_end
+         && u->Save_SP && fp != 0)
+      {
+       cache->base = fp;
+       if (hppa_debug)
+         fprintf_unfiltered (gdb_stdlog, " (base=0x%s) [frame pointer] }",
+           paddr_nz (cache->base));
+      }
+     else if (u->Save_SP 
+             && trad_frame_addr_p (cache->saved_regs, HPPA_SP_REGNUM))
       {
-        if (u->Save_SP && trad_frame_addr_p (cache->saved_regs, HPPA_SP_REGNUM))
-          {
             /* Both we're expecting the SP to be saved and the SP has been
               saved.  The entry SP value is saved at this frame's SP
               address.  */
@@ -1750,29 +1811,17 @@ hppa_frame_cache (struct frame_info *next_frame, void **this_cache)
            if (hppa_debug)
              fprintf_unfiltered (gdb_stdlog, " (base=0x%s) [saved] }",
                                  paddr_nz (cache->base));
-          }
-        else
-          {
-            /* The prologue has been slowly allocating stack space.  Adjust
-            the SP back.  */
-            cache->base = this_sp - frame_size;
-           if (hppa_debug)
-             fprintf_unfiltered (gdb_stdlog, " (base=0x%s) [unwind adjust] } ",
-                                 paddr_nz (cache->base));
-
-          }
       }
     else
       {
-       /* This frame has not yet been created. */
-        cache->base = this_sp;
-
+        /* The prologue has been slowly allocating stack space.  Adjust
+          the SP back.  */
+        cache->base = this_sp - frame_size;
        if (hppa_debug)
-         fprintf_unfiltered (gdb_stdlog, " (base=0x%s) [before prologue] } ",
+         fprintf_unfiltered (gdb_stdlog, " (base=0x%s) [unwind adjust] } ",
                              paddr_nz (cache->base));
 
       }
-
     trad_frame_set_value (cache->saved_regs, HPPA_SP_REGNUM, cache->base);
   }
 
@@ -1780,25 +1829,33 @@ hppa_frame_cache (struct frame_info *next_frame, void **this_cache)
      as the return register while normal code uses "rp".  */
   if (u->Millicode)
     {
-      if (trad_frame_addr_p (cache->saved_regs, RP_REGNUM))
-        cache->saved_regs[PCOQ_HEAD_REGNUM] = cache->saved_regs[31];
+      if (trad_frame_addr_p (cache->saved_regs, 31))
+        cache->saved_regs[HPPA_PCOQ_HEAD_REGNUM] = cache->saved_regs[31];
       else
        {
          ULONGEST r31 = frame_unwind_register_unsigned (next_frame, 31);
-         trad_frame_set_value (cache->saved_regs, PCOQ_HEAD_REGNUM, r31);
+         trad_frame_set_value (cache->saved_regs, HPPA_PCOQ_HEAD_REGNUM, r31);
         }
     }
   else
     {
-      if (trad_frame_addr_p (cache->saved_regs, RP_REGNUM))
-        cache->saved_regs[PCOQ_HEAD_REGNUM] = cache->saved_regs[RP_REGNUM];
+      if (trad_frame_addr_p (cache->saved_regs, HPPA_RP_REGNUM))
+        cache->saved_regs[HPPA_PCOQ_HEAD_REGNUM] = cache->saved_regs[HPPA_RP_REGNUM];
       else
        {
-         ULONGEST rp = frame_unwind_register_unsigned (next_frame, RP_REGNUM);
-         trad_frame_set_value (cache->saved_regs, PCOQ_HEAD_REGNUM, rp);
+         ULONGEST rp = frame_unwind_register_unsigned (next_frame, HPPA_RP_REGNUM);
+         trad_frame_set_value (cache->saved_regs, HPPA_PCOQ_HEAD_REGNUM, rp);
        }
     }
 
+  /* If the frame pointer was not saved in this frame, but we should be saving
+     it, set it to an invalid value so that another frame will not pick up the 
+     wrong frame pointer.  This can happen if we start unwinding after the 
+     frame pointer has been modified, but before we've saved it to the
+     stack.  */
+  if (u->Save_SP && !trad_frame_addr_p (cache->saved_regs, HPPA_FP_REGNUM))
+    trad_frame_set_value (cache->saved_regs, HPPA_FP_REGNUM, 0);
+
   {
     /* Convert all the offsets into addresses.  */
     int reg;
@@ -1825,42 +1882,14 @@ hppa_frame_this_id (struct frame_info *next_frame, void **this_cache,
 
 static void
 hppa_frame_prev_register (struct frame_info *next_frame,
-                                void **this_cache,
-                                int regnum, int *optimizedp,
-                                enum lval_type *lvalp, CORE_ADDR *addrp,
-                                int *realnump, void *valuep)
+                         void **this_cache,
+                         int regnum, int *optimizedp,
+                         enum lval_type *lvalp, CORE_ADDR *addrp,
+                         int *realnump, void *valuep)
 {
   struct hppa_frame_cache *info = hppa_frame_cache (next_frame, this_cache);
-  struct gdbarch *gdbarch = get_frame_arch (next_frame);
-  if (regnum == PCOQ_TAIL_REGNUM)
-    {
-      /* The PCOQ TAIL, or NPC, needs to be computed from the unwound
-        PC register.  */
-      *optimizedp = 0;
-      *lvalp = not_lval;
-      *addrp = 0;
-      *realnump = 0;
-      if (valuep)
-       {
-         int regsize = register_size (gdbarch, PCOQ_HEAD_REGNUM);
-         CORE_ADDR pc;
-         int optimized;
-         enum lval_type lval;
-         CORE_ADDR addr;
-         int realnum;
-         bfd_byte value[MAX_REGISTER_SIZE];
-         trad_frame_prev_register (next_frame, info->saved_regs,
-                                   PCOQ_HEAD_REGNUM, &optimized, &lval, &addr,
-                                   &realnum, &value);
-         pc = extract_unsigned_integer (&value, regsize);
-         store_unsigned_integer (valuep, regsize, pc + 4);
-       }
-    }
-  else
-    {
-      trad_frame_prev_register (next_frame, info->saved_regs, regnum,
-                               optimizedp, lvalp, addrp, realnump, valuep);
-    }
+  hppa_frame_prev_register_helper (next_frame, info->saved_regs, regnum,
+                                  optimizedp, lvalp, addrp, realnump, valuep);
 }
 
 static const struct frame_unwind hppa_frame_unwind =
@@ -1873,29 +1902,115 @@ static const struct frame_unwind hppa_frame_unwind =
 static const struct frame_unwind *
 hppa_frame_unwind_sniffer (struct frame_info *next_frame)
 {
-  return &hppa_frame_unwind;
+  CORE_ADDR pc = frame_pc_unwind (next_frame);
+
+  if (find_unwind_entry (pc))
+    return &hppa_frame_unwind;
+
+  return NULL;
 }
 
-static CORE_ADDR
-hppa_frame_base_address (struct frame_info *next_frame,
-                               void **this_cache)
+/* This is a generic fallback frame unwinder that kicks in if we fail all
+   the other ones.  Normally we would expect the stub and regular unwinder
+   to work, but in some cases we might hit a function that just doesn't
+   have any unwind information available.  In this case we try to do
+   unwinding solely based on code reading.  This is obviously going to be
+   slow, so only use this as a last resort.  Currently this will only
+   identify the stack and pc for the frame.  */
+
+static struct hppa_frame_cache *
+hppa_fallback_frame_cache (struct frame_info *next_frame, void **this_cache)
 {
-  struct hppa_frame_cache *info = hppa_frame_cache (next_frame,
-                                                          this_cache);
-  return info->base;
+  struct hppa_frame_cache *cache;
+  unsigned int frame_size;
+  CORE_ADDR pc, start_pc, end_pc, cur_pc;
+
+  cache = FRAME_OBSTACK_ZALLOC (struct hppa_frame_cache);
+  (*this_cache) = cache;
+  cache->saved_regs = trad_frame_alloc_saved_regs (next_frame);
+
+  pc = frame_func_unwind (next_frame);
+  cur_pc = frame_pc_unwind (next_frame);
+  frame_size = 0;
+
+  find_pc_partial_function (pc, NULL, &start_pc, &end_pc);
+
+  if (start_pc == 0 || end_pc == 0)
+    {
+      error ("Cannot find bounds of current function (@0x%s), unwinding will "
+            "fail.", paddr_nz (pc));
+      return cache;
+    }
+
+  if (end_pc > cur_pc)
+    end_pc = cur_pc;
+
+  for (pc = start_pc; pc < end_pc; pc += 4)
+    {
+      unsigned int insn;
+
+      insn = read_memory_unsigned_integer (pc, 4);
+
+      frame_size += prologue_inst_adjust_sp (insn);
+
+      /* There are limited ways to store the return pointer into the
+        stack.  */
+      if (insn == 0x6bc23fd9) /* stw rp,-0x14(sr0,sp) */
+        cache->saved_regs[HPPA_RP_REGNUM].addr = -20;
+      else if (insn == 0x0fc212c1) /* std rp,-0x10(sr0,sp) */
+        cache->saved_regs[HPPA_RP_REGNUM].addr = -16;
+    }
+
+  cache->base = frame_unwind_register_unsigned (next_frame, HPPA_SP_REGNUM) - frame_size;
+  trad_frame_set_value (cache->saved_regs, HPPA_SP_REGNUM, cache->base);
+
+  if (trad_frame_addr_p (cache->saved_regs, HPPA_RP_REGNUM))
+    {
+      cache->saved_regs[HPPA_RP_REGNUM].addr += cache->base;
+      cache->saved_regs[HPPA_PCOQ_HEAD_REGNUM] = cache->saved_regs[HPPA_RP_REGNUM];
+    }
+  else
+    {
+      ULONGEST rp = frame_unwind_register_unsigned (next_frame, HPPA_RP_REGNUM);
+      trad_frame_set_value (cache->saved_regs, HPPA_PCOQ_HEAD_REGNUM, rp);
+    }
+
+  return cache;
+}
+
+static void
+hppa_fallback_frame_this_id (struct frame_info *next_frame, void **this_cache,
+                            struct frame_id *this_id)
+{
+  struct hppa_frame_cache *info = 
+    hppa_fallback_frame_cache (next_frame, this_cache);
+  (*this_id) = frame_id_build (info->base, frame_func_unwind (next_frame));
+}
+
+static void
+hppa_fallback_frame_prev_register (struct frame_info *next_frame,
+                         void **this_cache,
+                         int regnum, int *optimizedp,
+                         enum lval_type *lvalp, CORE_ADDR *addrp,
+                         int *realnump, void *valuep)
+{
+  struct hppa_frame_cache *info = 
+    hppa_fallback_frame_cache (next_frame, this_cache);
+  hppa_frame_prev_register_helper (next_frame, info->saved_regs, regnum,
+                                  optimizedp, lvalp, addrp, realnump, valuep);
 }
 
-static const struct frame_base hppa_frame_base = {
-  &hppa_frame_unwind,
-  hppa_frame_base_address,
-  hppa_frame_base_address,
-  hppa_frame_base_address
+static const struct frame_unwind hppa_fallback_frame_unwind =
+{
+  NORMAL_FRAME,
+  hppa_fallback_frame_this_id,
+  hppa_fallback_frame_prev_register
 };
 
-static const struct frame_base *
-hppa_frame_base_sniffer (struct frame_info *next_frame)
+static const struct frame_unwind *
+hppa_fallback_unwind_sniffer (struct frame_info *next_frame)
 {
-  return &hppa_frame_base;
+  return &hppa_fallback_frame_unwind;
 }
 
 /* Stub frames, used for all kinds of call stubs.  */
@@ -1911,6 +2026,7 @@ hppa_stub_frame_unwind_cache (struct frame_info *next_frame,
 {
   struct gdbarch *gdbarch = get_frame_arch (next_frame);
   struct hppa_stub_unwind_cache *info;
+  struct unwind_table_entry *u;
 
   if (*this_cache)
     return *this_cache;
@@ -1919,9 +2035,26 @@ hppa_stub_frame_unwind_cache (struct frame_info *next_frame,
   *this_cache = info;
   info->saved_regs = trad_frame_alloc_saved_regs (next_frame);
 
-  info->saved_regs[PCOQ_HEAD_REGNUM].realreg = RP_REGNUM;
   info->base = frame_unwind_register_unsigned (next_frame, HPPA_SP_REGNUM);
 
+  if (gdbarch_osabi (gdbarch) == GDB_OSABI_HPUX_SOM)
+    {
+      /* HPUX uses export stubs in function calls; the export stub clobbers
+         the return value of the caller, and, later restores it from the
+        stack.  */
+      u = find_unwind_entry (frame_pc_unwind (next_frame));
+
+      if (u && u->stub_unwind.stub_type == EXPORT)
+       {
+          info->saved_regs[HPPA_PCOQ_HEAD_REGNUM].addr = info->base - 24;
+
+         return info;
+       }
+    }
+
+  /* By default we assume that stubs do not change the rp.  */
+  info->saved_regs[HPPA_PCOQ_HEAD_REGNUM].realreg = HPPA_RP_REGNUM;
+
   return info;
 }
 
@@ -1940,23 +2073,12 @@ hppa_stub_frame_prev_register (struct frame_info *next_frame,
                               void **this_prologue_cache,
                               int regnum, int *optimizedp,
                               enum lval_type *lvalp, CORE_ADDR *addrp,
-                              int *realnump, void *bufferp)
+                              int *realnump, void *valuep)
 {
   struct hppa_stub_unwind_cache *info
     = hppa_stub_frame_unwind_cache (next_frame, this_prologue_cache);
-  int pcoqt = (regnum == PCOQ_TAIL_REGNUM);
-  struct gdbarch *gdbarch = get_frame_arch (next_frame);
-  int regsize = register_size (gdbarch, PCOQ_HEAD_REGNUM);
-
-  if (pcoqt)
-    regnum = PCOQ_HEAD_REGNUM;
-
-  trad_frame_prev_register (next_frame, info->saved_regs, regnum,
-                            optimizedp, lvalp, addrp, realnump, bufferp);
-
-  if (pcoqt)
-    store_unsigned_integer (bufferp, regsize, 
-                           extract_unsigned_integer (bufferp, regsize) + 4);
+  hppa_frame_prev_register_helper (next_frame, info->saved_regs, regnum,
+                                  optimizedp, lvalp, addrp, realnump, valuep);
 }
 
 static const struct frame_unwind hppa_stub_frame_unwind = {
@@ -1970,7 +2092,8 @@ hppa_stub_unwind_sniffer (struct frame_info *next_frame)
 {
   CORE_ADDR pc = frame_pc_unwind (next_frame);
 
-  if (IN_SOLIB_CALL_TRAMPOLINE (pc, NULL)
+  if (pc == 0
+      || IN_SOLIB_CALL_TRAMPOLINE (pc, NULL)
       || IN_SOLIB_RETURN_TRAMPOLINE (pc, NULL))
     return &hppa_stub_frame_unwind;
   return NULL;
@@ -1987,7 +2110,7 @@ hppa_unwind_dummy_id (struct gdbarch *gdbarch, struct frame_info *next_frame)
 static CORE_ADDR
 hppa_unwind_pc (struct gdbarch *gdbarch, struct frame_info *next_frame)
 {
-  return frame_unwind_register_signed (next_frame, PCOQ_HEAD_REGNUM) & ~3;
+  return frame_unwind_register_signed (next_frame, HPPA_PCOQ_HEAD_REGNUM) & ~3;
 }
 
 /* Instead of this nasty cast, add a method pvoid() that prints out a
@@ -2080,10 +2203,10 @@ hppa_skip_permanent_breakpoint (void)
      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 (HPPA_PCOQ_HEAD_REGNUM, read_register (HPPA_PCOQ_TAIL_REGNUM));
+  write_register (HPPA_PCSQ_HEAD_REGNUM, read_register (HPPA_PCSQ_TAIL_REGNUM));
 
-  write_register (PCOQ_TAIL_REGNUM, read_register (PCOQ_TAIL_REGNUM) + 4);
+  write_register (HPPA_PCOQ_TAIL_REGNUM, read_register (HPPA_PCOQ_TAIL_REGNUM) + 4);
   /* We can leave the tail's space the same, since there's no jump.  */
 }
 
@@ -2121,8 +2244,8 @@ hppa_instruction_nullified (void)
   /* brobecker 2002/11/07: Couldn't we use a ULONGEST here? It would
      avoid the type cast.  I'm leaving it as is for now as I'm doing
      semi-mechanical multiarching-related changes.  */
-  const int ipsw = (int) read_register (IPSW_REGNUM);
-  const int flags = (int) read_register (FLAGS_REGNUM);
+  const int ipsw = (int) read_register (HPPA_IPSW_REGNUM);
+  const int flags = (int) read_register (HPPA_FLAGS_REGNUM);
 
   return ((ipsw & 0x00200000) && !(flags & 0x2));
 }
@@ -2133,7 +2256,7 @@ hppa_instruction_nullified (void)
 static struct type *
 hppa32_register_type (struct gdbarch *gdbarch, int reg_nr)
 {
-   if (reg_nr < FP4_REGNUM)
+   if (reg_nr < HPPA_FP4_REGNUM)
      return builtin_type_uint32;
    else
      return builtin_type_ieee_single_big;
@@ -2145,7 +2268,7 @@ hppa32_register_type (struct gdbarch *gdbarch, int reg_nr)
 static struct type *
 hppa64_register_type (struct gdbarch *gdbarch, int reg_nr)
 {
-   if (reg_nr < FP4_REGNUM)
+   if (reg_nr < HPPA_FP4_REGNUM)
      return builtin_type_uint64;
    else
      return builtin_type_ieee_double_big;
@@ -2158,9 +2281,9 @@ static int
 hppa_cannot_store_register (int regnum)
 {
   return (regnum == 0
-          || regnum == PCSQ_HEAD_REGNUM
-          || (regnum >= PCSQ_TAIL_REGNUM && regnum < IPSW_REGNUM)
-          || (regnum > IPSW_REGNUM && regnum < FP4_REGNUM));
+          || regnum == HPPA_PCSQ_HEAD_REGNUM
+          || (regnum >= HPPA_PCSQ_TAIL_REGNUM && regnum < HPPA_IPSW_REGNUM)
+          || (regnum > HPPA_IPSW_REGNUM && regnum < HPPA_FP4_REGNUM));
 
 }
 
@@ -2183,7 +2306,7 @@ hppa_fetch_pointer_argument (struct frame_info *frame, int argi,
                             struct type *type)
 {
   CORE_ADDR addr;
-  get_frame_register (frame, R0_REGNUM + 26 - argi, &addr);
+  get_frame_register (frame, HPPA_R0_REGNUM + 26 - argi, &addr);
   return addr;
 }
 
@@ -2194,11 +2317,51 @@ hppa_pseudo_register_read (struct gdbarch *gdbarch, struct regcache *regcache,
     ULONGEST tmp;
 
     regcache_raw_read_unsigned (regcache, regnum, &tmp);
-    if (regnum == PCOQ_HEAD_REGNUM || regnum == PCOQ_TAIL_REGNUM)
+    if (regnum == HPPA_PCOQ_HEAD_REGNUM || regnum == HPPA_PCOQ_TAIL_REGNUM)
       tmp &= ~0x3;
     store_unsigned_integer (buf, sizeof(tmp), tmp);
 }
 
+static CORE_ADDR
+hppa_find_global_pointer (struct value *function)
+{
+  return 0;
+}
+
+void
+hppa_frame_prev_register_helper (struct frame_info *next_frame,
+                                struct trad_frame_saved_reg saved_regs[],
+                                int regnum, int *optimizedp,
+                                enum lval_type *lvalp, CORE_ADDR *addrp,
+                                int *realnump, void *valuep)
+{
+  if (regnum == HPPA_PCOQ_TAIL_REGNUM)
+    {
+      if (valuep)
+       {
+         CORE_ADDR pc;
+
+         trad_frame_get_prev_register (next_frame, saved_regs,
+                                       HPPA_PCOQ_HEAD_REGNUM, optimizedp,
+                                       lvalp, addrp, realnump, valuep);
+
+         pc = extract_unsigned_integer (valuep, 4);
+         store_unsigned_integer (valuep, 4, pc + 4);
+       }
+
+      /* It's a computed value.  */
+      *optimizedp = 0;
+      *lvalp = not_lval;
+      *addrp = 0;
+      *realnump = -1;
+      return;
+    }
+
+  trad_frame_get_prev_register (next_frame, saved_regs, regnum,
+                               optimizedp, lvalp, addrp, realnump, valuep);
+}
+\f
+
 /* Here is a table of C type sizes on hppa with various compiles
    and options.  I measured this on PA 9000/800 with HP-UX 11.11
    and these compilers:
@@ -2266,6 +2429,8 @@ hppa_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
   else
     tdep->bytes_per_address = 4;
 
+  tdep->find_global_pointer = hppa_find_global_pointer;
+
   /* Some parts of the gdbarch vector depend on whether we are running
      on a 32 bits or 64 bits target.  */
   switch (tdep->bytes_per_address)
@@ -2301,6 +2466,7 @@ hppa_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
   set_gdbarch_sp_regnum (gdbarch, HPPA_SP_REGNUM);
   set_gdbarch_fp0_regnum (gdbarch, HPPA_FP0_REGNUM);
   set_gdbarch_cannot_store_register (gdbarch, hppa_cannot_store_register);
+  set_gdbarch_cannot_fetch_register (gdbarch, hppa_cannot_store_register);
   set_gdbarch_addr_bits_remove (gdbarch, hppa_smash_text_address);
   set_gdbarch_smash_text_address (gdbarch, hppa_smash_text_address);
   set_gdbarch_believe_pcc_promotion (gdbarch, 1);
@@ -2324,6 +2490,8 @@ hppa_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
     case 4:
       set_gdbarch_push_dummy_call (gdbarch, hppa32_push_dummy_call);
       set_gdbarch_frame_align (gdbarch, hppa32_frame_align);
+      set_gdbarch_convert_from_func_ptr_addr
+        (gdbarch, hppa32_convert_from_func_ptr_addr);
       break;
     case 8:
       set_gdbarch_push_dummy_call (gdbarch, hppa64_push_dummy_call);
@@ -2353,13 +2521,13 @@ hppa_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
   set_gdbarch_unwind_dummy_id (gdbarch, hppa_unwind_dummy_id);
   set_gdbarch_unwind_pc (gdbarch, hppa_unwind_pc);
 
+  /* Hook in ABI-specific overrides, if they have been registered.  */
+  gdbarch_init_osabi (info, gdbarch);
+
   /* Hook in the default unwinders.  */
   frame_unwind_append_sniffer (gdbarch, hppa_stub_unwind_sniffer);
   frame_unwind_append_sniffer (gdbarch, hppa_frame_unwind_sniffer);
-  frame_base_append_sniffer (gdbarch, hppa_frame_base_sniffer);
-
-  /* Hook in ABI-specific overrides, if they have been registered.  */
-  gdbarch_init_osabi (info, gdbarch);
+  frame_unwind_append_sniffer (gdbarch, hppa_fallback_unwind_sniffer);
 
   return gdbarch;
 }
@@ -2421,8 +2589,9 @@ be no argument or the argument must be a depth.\n"), NULL);
 be no argument or the argument must be a depth.\n"), NULL);
 
   /* Debug this files internals. */
-  add_show_from_set (add_set_cmd ("hppa", class_maintenance, var_zinteger,
-                                 &hppa_debug, "Set hppa debugging.\n\
-When non-zero, hppa specific debugging is enabled.", &setdebuglist), &showdebuglist);
+  deprecated_add_show_from_set
+    (add_set_cmd ("hppa", class_maintenance, var_zinteger,
+                 &hppa_debug, "Set hppa debugging.\n\
+When non-zero, hppa specific debugging is enabled.", &setdebuglist),
+     &showdebuglist);
 }
-
This page took 0.037692 seconds and 4 git commands to generate.