Index: ChangeLog
authorAndrew Cagney <cagney@redhat.com>
Sun, 22 Feb 2004 17:34:17 +0000 (17:34 +0000)
committerAndrew Cagney <cagney@redhat.com>
Sun, 22 Feb 2004 17:34:17 +0000 (17:34 +0000)
2004-02-22  Andrew Cagney  <cagney@redhat.com>

* hppa-tdep.c: Include "trad-frame.h", "frame-unwind.h", and
"frame-base.h".
(struct hppa_frame_cache): Define.
(hppa_frame_cache, hppa_frame_this_id): New functions.
(hppa_frame_prev_register): New function.
(hppa_frame_unwind, hppa_frame_base): New variables.
(hppa_frame_unwind_sniffer): New function.
(hppa_frame_base_address, hppa_unwind_pc): New function.
(hppa_gdbarch_init): Set unwind_dummy_id, unwind_pc, frame unwind
sniffer, and frame base sniffer; keep disabled.
(hppa_frame_base_sniffer, hppa_unwind_dummy_id): New functions.
* Makefile.in: Update dependencies, fix s/nbsd/obsd/ typo.

gdb/ChangeLog
gdb/Makefile.in
gdb/hppa-tdep.c

index ce4a621c065c232110e742cc38d21516e69c4993..15e1089a500a7b9fefc0e464ff46c9ac7d836e1c 100644 (file)
@@ -1,5 +1,18 @@
 2004-02-22  Andrew Cagney  <cagney@redhat.com>
 
+       * hppa-tdep.c: Include "trad-frame.h", "frame-unwind.h", and
+       "frame-base.h".
+       (struct hppa_frame_cache): Define.
+       (hppa_frame_cache, hppa_frame_this_id): New functions.
+       (hppa_frame_prev_register): New function.
+       (hppa_frame_unwind, hppa_frame_base): New variables.
+       (hppa_frame_unwind_sniffer): New function.
+       (hppa_frame_base_address, hppa_unwind_pc): New function.
+       (hppa_gdbarch_init): Set unwind_dummy_id, unwind_pc, frame unwind
+       sniffer, and frame base sniffer; keep disabled.
+       (hppa_frame_base_sniffer, hppa_unwind_dummy_id): New functions.
+       * Makefile.in: Update dependencies, fix s/nbsd/obsd/ typo.
+
        * frame-unwind.c (frame_unwind_find_by_frame): Add legacy_frame_p
        to predicates for "seriously old code".
 
index 5665885d6337b60bd2e79645598863b57444941a..5deb7a524b5fb36e4f45510e5bbc5cd83ac13aee 100644 (file)
@@ -1524,7 +1524,7 @@ amd64fbsd-nat.o: amd64fbsd-nat.c $(defs_h) $(inferior_h) $(regcache_h) \
        $(gdb_assert_h) $(gregset_h) $(x86_64_tdep_h) $(amd64_nat_h)
 amd64fbsd-tdep.o: amd64fbsd-tdep.c $(defs_h) $(arch_utils_h) $(frame_h) \
        $(gdbcore_h) $(regcache_h) $(osabi_h) $(gdb_string_h) \
-       $(x86_64_tdep_h)  $(solib_svr4_h)
+       $(x86_64_tdep_h) $(solib_svr4_h)
 amd64-nat.o: amd64-nat.c $(defs_h) $(gdbarch_h) $(regcache_h) \
        $(gdb_assert_h) $(i386_tdep_h) $(x86_64_tdep_h)
 amd64nbsd-nat.o: amd64nbsd-nat.c $(defs_h) $(gdb_assert_h) $(x86_64_tdep_h) \
@@ -1532,11 +1532,11 @@ amd64nbsd-nat.o: amd64nbsd-nat.c $(defs_h) $(gdb_assert_h) $(x86_64_tdep_h) \
 amd64nbsd-tdep.o: amd64nbsd-tdep.c $(defs_h) $(arch_utils_h) $(frame_h) \
        $(gdbcore_h) $(osabi_h) $(gdb_assert_h) $(x86_64_tdep_h) \
        $(nbsd_tdep_h) $(solib_svr4_h)
-amd64obsd-nat.o: amd64nbsd-nat.c $(defs_h) $(gdb_assert_h) $(x86_64_tdep_h) \
+amd64obsd-nat.o: amd64obsd-nat.c $(defs_h) $(gdb_assert_h) $(x86_64_tdep_h) \
        $(amd64_nat_h)
-amd64obsd-tdep.o: amd64nbsd-tdep.c $(defs_h) $(arch_utils_h) $(frame_h) \
-       $(gdbcore_h) $(osabi_h) $(regset_h) $(target_h) $(gdb_assert_h) \
-       $(gdb_string_h) $(x86_64_tdep_h) $(i387_tdep_h) $(solib_svr4_h)
+amd64obsd-tdep.o: amd64obsd-tdep.c $(defs_h) $(frame_h) $(gdbcore_h) \
+       $(osabi_h) $(regset_h) $(target_h) $(gdb_assert_h) $(gdb_string_h) \
+       $(x86_64_tdep_h) $(i387_tdep_h) $(solib_svr4_h)
 annotate.o: annotate.c $(defs_h) $(annotate_h) $(value_h) $(target_h) \
        $(gdbtypes_h) $(breakpoint_h)
 arch-utils.o: arch-utils.c $(defs_h) $(arch_utils_h) $(buildsym_h) \
@@ -1800,9 +1800,11 @@ hppa-hpux-tdep.o: hppa-hpux-tdep.c $(defs_h) $(arch_utils_h) $(gdbcore_h) \
        $(osabi_h) $(gdb_string_h) $(frame_h)
 hppa-tdep.o: hppa-tdep.c $(defs_h) $(frame_h) $(bfd_h) $(inferior_h) \
        $(value_h) $(regcache_h) $(completer_h) $(language_h) $(osabi_h) \
-       $(gdb_assert_h) $(infttrace_h) $(symtab_h) $(infcall_h) $(dis_asm_h) \
-       $(a_out_encap_h) $(gdb_stat_h) $(gdb_wait_h) $(gdbcore_h) \
-       $(gdbcmd_h) $(target_h) $(symfile_h) $(objfiles_h) $(hppa_tdep_h)
+       $(gdb_assert_h) $(infttrace_h) $(arch_utils_h) $(symtab_h) \
+       $(infcall_h) $(dis_asm_h) $(trad_frame_h) $(frame_unwind_h) \
+       $(frame_base_h) $(a_out_encap_h) $(gdb_stat_h) $(gdb_wait_h) \
+       $(gdbcore_h) $(gdbcmd_h) $(target_h) $(symfile_h) $(objfiles_h) \
+       $(hppa_tdep_h)
 hpread.o: hpread.c $(defs_h) $(bfd_h) $(gdb_string_h) $(hp_symtab_h) \
        $(syms_h) $(symtab_h) $(symfile_h) $(objfiles_h) $(buildsym_h) \
        $(complaints_h) $(gdb_stabs_h) $(gdbtypes_h) $(demangle_h) \
index 61cfd57f72cfdb1fb5401350bf9b9f169c1f0960..340bc475aff79a7f547bf9e3a5b1f55150975ff5 100644 (file)
@@ -40,6 +40,9 @@
 #include "symtab.h"
 #include "infcall.h"
 #include "dis-asm.h"
+#include "trad-frame.h"
+#include "frame-unwind.h"
+#include "frame-base.h"
 
 #ifdef USG
 #include <sys/types.h>
@@ -4237,6 +4240,297 @@ hppa_frame_init_saved_regs (struct frame_info *frame)
   hppa_frame_find_saved_regs (frame, deprecated_get_frame_saved_regs (frame));
 }
 
+struct hppa_frame_cache
+{
+  CORE_ADDR base;
+  struct trad_frame_saved_reg *saved_regs;
+};
+
+static struct hppa_frame_cache *
+hppa_frame_cache (struct frame_info *next_frame, void **this_cache)
+{
+  struct hppa_frame_cache *cache;
+  long saved_gr_mask;
+  long saved_fr_mask;
+  CORE_ADDR this_sp;
+  long frame_size;
+  struct unwind_table_entry *u;
+  int i;
+
+  if ((*this_cache) != NULL)
+    return (*this_cache);
+  cache = FRAME_OBSTACK_ZALLOC (struct hppa_frame_cache);
+  (*this_cache) = cache;
+  cache->saved_regs = trad_frame_alloc_saved_regs (next_frame);
+
+  /* Yow! */
+  u = find_unwind_entry (frame_func_unwind (next_frame));
+  if (!u)
+    return;
+
+  /* Turn the Entry_GR field into a bitmask.  */
+  saved_gr_mask = 0;
+  for (i = 3; i < u->Entry_GR + 3; i++)
+    {
+      /* Frame pointer gets saved into a special location.  */
+      if (u->Save_SP && i == DEPRECATED_FP_REGNUM)
+       continue;
+       
+      saved_gr_mask |= (1 << i);
+    }
+
+  /* Turn the Entry_FR field into a bitmask too.  */
+  saved_fr_mask = 0;
+  for (i = 12; i < u->Entry_FR + 12; i++)
+    saved_fr_mask |= (1 << i);
+
+  /* Loop until we find everything of interest or hit a branch.
+
+     For unoptimized GCC code and for any HP CC code this will never ever
+     examine any user instructions.
+
+     For optimized GCC code we're faced with problems.  GCC will schedule
+     its prologue and make prologue instructions available for delay slot
+     filling.  The end result is user code gets mixed in with the prologue
+     and a prologue instruction may be in the delay slot of the first branch
+     or call.
+
+     Some unexpected things are expected with debugging optimized code, so
+     we allow this routine to walk past user instructions in optimized
+     GCC code.  */
+  {
+    int final_iteration = 0;
+    CORE_ADDR pc;
+    CORE_ADDR end_pc = skip_prologue_using_sal (pc);
+    int looking_for_sp = u->Save_SP;
+    int looking_for_rp = u->Save_RP;
+    int fp_loc = -1;
+    if (end_pc == 0)
+      end_pc = frame_pc_unwind (next_frame);
+    frame_size = 0;
+    for (pc = frame_func_unwind (next_frame);
+        ((saved_gr_mask || saved_fr_mask
+          || looking_for_sp || looking_for_rp
+          || frame_size < (u->Total_frame_size << 3))
+         && pc <= end_pc);
+        pc += 4)
+      {
+       int reg;
+       char buf4[4];
+       long status = target_read_memory (pc, buf4, sizeof buf4);
+       long inst = extract_unsigned_integer (buf4, sizeof buf4);
+       
+       /* Note the interesting effects of this instruction.  */
+       frame_size += prologue_inst_adjust_sp (inst);
+       
+       /* There are limited ways to store the return pointer into the
+          stack.  */
+       if (inst == 0x6bc23fd9) /* stw rp,-0x14(sr0,sp) */
+         {
+           looking_for_rp = 0;
+           cache->saved_regs[RP_REGNUM].addr = -20;
+         }
+       else if (inst == 0x0fc212c1) /* std rp,-0x10(sr0,sp) */
+         {
+           looking_for_rp = 0;
+           cache->saved_regs[RP_REGNUM].addr = -16;
+         }
+       
+       /* Check to see 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) */
+         {
+           looking_for_sp = 0;
+           cache->saved_regs[DEPRECATED_FP_REGNUM].addr = 0;
+         }
+       
+       /* Account for general and floating-point register saves.  */
+       reg = inst_saves_gr (inst);
+       if (reg >= 3 && reg <= 18
+           && (!u->Save_SP || reg != DEPRECATED_FP_REGNUM))
+         {
+           saved_gr_mask &= ~(1 << reg);
+           if ((inst >> 26) == 0x1b && extract_14 (inst) >= 0)
+             /* stwm with a positive displacement is a _post_
+                _modify_.  */
+             cache->saved_regs[reg].addr = 0;
+           else if ((inst & 0xfc00000c) == 0x70000008)
+             /* A std has explicit post_modify forms.  */
+             cache->saved_regs[reg].addr = 0;
+           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)
+                 cache->saved_regs[reg].addr = offset;
+               else
+                 cache->saved_regs[reg].addr = (u->Total_frame_size << 3) + offset;
+             }
+         }
+
+       /* GCC handles callee saved FP regs a little differently.  
+          
+          It emits an instruction to put the value of the start of
+          the FP store area into %r1.  It then uses fstds,ma with a
+          basereg of %r1 for the stores.
+
+          HP CC emits them at the current stack pointer modifying the
+          stack pointer as it stores each register.  */
+       
+       /* ldo X(%r3),%r1 or ldo X(%r30),%r1.  */
+       if ((inst & 0xffffc000) == 0x34610000
+           || (inst & 0xffffc000) == 0x37c10000)
+         fp_loc = extract_14 (inst);
+       
+       reg = inst_saves_fr (inst);
+       if (reg >= 12 && reg <= 21)
+         {
+           /* Note +4 braindamage below is necessary because the FP
+              status registers are internally 8 registers rather than
+              the expected 4 registers.  */
+           saved_fr_mask &= ~(1 << reg);
+           if (fp_loc == -1)
+             {
+               /* 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;
+               fp_loc = 8;
+             }
+           else
+             {
+               cache->saved_regs[reg + FP0_REGNUM + 4].addr = fp_loc;
+               fp_loc += 8;
+             }
+         }
+       
+       /* 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;
+      }
+  }
+
+  {
+    /* The frame base always represents the value of %sp at entry to
+       the current function (and is thus equivalent to the "saved"
+       stack pointer.  */
+    CORE_ADDR this_sp = frame_unwind_register_unsigned (next_frame, SP_REGNUM);
+    /* FIXME: cagney/2004-02-22: This assumes that the frame has been
+       created.  If it hasn't everything will be out-of-wack.  */
+    if (u->Save_SP && trad_frame_addr_p (cache->saved_regs, 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.  */
+      cache->base = read_memory_integer (this_sp, TARGET_PTR_BIT / 8);
+    else
+      /* The prologue has been slowly allocating stack space.  Adjust
+        the SP back.  */
+      cache->base = this_sp - frame_size;
+    trad_frame_set_value (cache->saved_regs, SP_REGNUM, cache->base);
+  }
+
+  /* The PC is found in the "return register".  */
+  if (u->Millicode)
+    cache->saved_regs[PC_REGNUM] = cache->saved_regs[31];
+  else
+    cache->saved_regs[PC_REGNUM] = cache->saved_regs[RP_REGNUM];
+
+  {
+    /* Convert all the offsets into addresses.  */
+    int reg;
+    for (reg = 0; reg < NUM_REGS; reg++)
+      {
+       if (trad_frame_addr_p (cache->saved_regs, reg))
+         cache->saved_regs[reg].addr += cache->base;
+      }
+  }
+
+  return (*this_cache);
+}
+
+static void
+hppa_frame_this_id (struct frame_info *next_frame, void **this_cache,
+                          struct frame_id *this_id)
+{
+  struct hppa_frame_cache *info = hppa_frame_cache (next_frame, this_cache);
+  (*this_id) = frame_id_build (info->base, frame_func_unwind (next_frame));
+}
+
+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)
+{
+  struct hppa_frame_cache *info = hppa_frame_cache (next_frame, this_cache);
+  trad_frame_prev_register (next_frame, info->saved_regs, regnum,
+                           optimizedp, lvalp, addrp, realnump, valuep);
+}
+
+static const struct frame_unwind hppa_frame_unwind =
+{
+  NORMAL_FRAME,
+  hppa_frame_this_id,
+  hppa_frame_prev_register
+};
+
+static const struct frame_unwind *
+hppa_frame_unwind_sniffer (struct frame_info *next_frame)
+{
+  return &hppa_frame_unwind;
+}
+
+static CORE_ADDR
+hppa_frame_base_address (struct frame_info *next_frame,
+                               void **this_cache)
+{
+  struct hppa_frame_cache *info = hppa_frame_cache (next_frame,
+                                                          this_cache);
+  return info->base;
+}
+
+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_base *
+hppa_frame_base_sniffer (struct frame_info *next_frame)
+{
+  return &hppa_frame_base;
+}
+
+static struct frame_id
+hppa_unwind_dummy_id (struct gdbarch *gdbarch, struct frame_info *next_frame)
+{
+  return frame_id_build (frame_unwind_register_unsigned (next_frame,
+                                                        SP_REGNUM),
+                        frame_pc_unwind (next_frame));
+}
+
+static CORE_ADDR
+hppa_unwind_pc (struct gdbarch *gdbarch, struct frame_info *next_frame)
+{
+  return frame_unwind_register_signed (next_frame, PC_REGNUM) & ~3;
+}
+
 /* Exception handling support for the HP-UX ANSI C++ compiler.
    The compiler (aCC) provides a callback for exception events;
    GDB can set a breakpoint on this callback and find out what
@@ -5219,6 +5513,10 @@ hppa_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
   /* Frame unwind methods.  */
   if (0)
     {
+      set_gdbarch_unwind_dummy_id (gdbarch, hppa_unwind_dummy_id);
+      set_gdbarch_unwind_pc (gdbarch, hppa_unwind_pc);
+      frame_unwind_append_sniffer (gdbarch, hppa_frame_unwind_sniffer);
+      frame_base_append_sniffer (gdbarch, hppa_frame_base_sniffer);
     }
   else
     {