* hppa-tdep.c (hppa_lookup_stub_minimal_symbol): New function.
[deliverable/binutils-gdb.git] / gdb / hppa-tdep.c
index fb6e7ebea7907c7a4abeccfc2540e3a344914ec9..46a7b080192ea63eebc796efe060d064688f059f 100644 (file)
@@ -338,6 +338,10 @@ internalize_unwinds (struct objfile *objfile, struct unwind_table_entry *table,
 
          text_offset = low_text_segment_address;
        }
+      else if (gdbarch_tdep (current_gdbarch)->solib_get_text_base)
+        {
+         text_offset = gdbarch_tdep (current_gdbarch)->solib_get_text_base (objfile);
+       }
 
       bfd_get_section_contents (objfile->obfd, section, buf, 0, size);
 
@@ -621,6 +625,44 @@ find_unwind_entry (CORE_ADDR pc)
   return NULL;
 }
 
+/* The epilogue is defined here as the area either on the `bv' instruction 
+   itself or an instruction which destroys the function's stack frame. 
+   
+   We do not assume that the epilogue is at the end of a function as we can
+   also have return sequences in the middle of a function.  */
+static int
+hppa_in_function_epilogue_p (struct gdbarch *gdbarch, CORE_ADDR pc)
+{
+  unsigned long status;
+  unsigned int inst;
+  char buf[4];
+  int off;
+
+  status = deprecated_read_memory_nobpt (pc, buf, 4);
+  if (status != 0)
+    return 0;
+
+  inst = extract_unsigned_integer (buf, 4);
+
+  /* The most common way to perform a stack adjustment ldo X(sp),sp 
+     We are destroying a stack frame if the offset is negative.  */
+  if ((inst & 0xffffc000) == 0x37de0000
+      && hppa_extract_14 (inst) < 0)
+    return 1;
+
+  /* ldw,mb D(sp),X or ldd,mb D(sp),X */
+  if (((inst & 0x0fc010e0) == 0x0fc010e0 
+       || (inst & 0x0fc010e0) == 0x0fc010e0)
+      && hppa_extract_14 (inst) < 0)
+    return 1;
+
+  /* bv %r0(%rp) or bv,n %r0(%rp) */
+  if (inst == 0xe840c000 || inst == 0xe840c002)
+    return 1;
+
+  return 0;
+}
+
 static const unsigned char *
 hppa_breakpoint_from_pc (CORE_ADDR *pc, int *len)
 {
@@ -1034,42 +1076,31 @@ hppa64_frame_align (struct gdbarch *gdbarch, CORE_ADDR addr)
   return align_up (addr, 16);
 }
 
-
-/* Get the PC from %r31 if currently in a syscall.  Also mask out privilege
-   bits.  */
-
-static CORE_ADDR
-hppa_target_read_pc (ptid_t ptid)
+CORE_ADDR
+hppa_read_pc (ptid_t ptid)
 {
-  int flags = read_register_pid (HPPA_FLAGS_REGNUM, ptid);
+  ULONGEST ipsw;
+  CORE_ADDR pc;
 
-  /* 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, ptid) & ~0x3;
+  ipsw = read_register_pid (HPPA_IPSW_REGNUM, ptid);
+  pc = read_register_pid (HPPA_PCOQ_HEAD_REGNUM, ptid);
 
-  return read_register_pid (HPPA_PCOQ_HEAD_REGNUM, ptid) & ~0x3;
-}
+  /* If the current instruction is nullified, then we are effectively
+     still executing the previous instruction.  Pretend we are still
+     there.  This is needed when single stepping; if the nullified
+     instruction is on a different line, we don't want GDB to think
+     we've stepped onto that line.  */
+  if (ipsw & 0x00200000)
+    pc -= 4;
 
-/* Write out the PC.  If currently in a syscall, then also write the new
-   PC value into %r31.  */
+  return pc & ~0x3;
+}
 
-static void
-hppa_target_write_pc (CORE_ADDR v, ptid_t ptid)
+void
+hppa_write_pc (CORE_ADDR pc, ptid_t 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.  */
-  /* 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_pid (31, v | 0x3, ptid);
-
-  write_register_pid (HPPA_PCOQ_HEAD_REGNUM, v, ptid);
-  write_register_pid (HPPA_PCOQ_TAIL_REGNUM, v + 4, ptid);
+  write_register_pid (HPPA_PCOQ_HEAD_REGNUM, pc, ptid);
+  write_register_pid (HPPA_PCOQ_TAIL_REGNUM, pc + 4, ptid);
 }
 
 /* return the alignment of a type in bytes. Structures have the maximum
@@ -1916,6 +1947,19 @@ hppa_frame_cache (struct frame_info *next_frame, void **this_cache)
       }
   }
 
+  {
+    struct gdbarch *gdbarch;
+    struct gdbarch_tdep *tdep;
+
+    gdbarch = get_frame_arch (next_frame);
+    tdep = gdbarch_tdep (gdbarch);
+
+    if (tdep->unwind_adjust_stub)
+      {
+        tdep->unwind_adjust_stub (next_frame, cache->base, cache->saved_regs);
+      }
+  }
+
   if (hppa_debug)
     fprintf_unfiltered (gdb_stdlog, "base=0x%s }", 
       paddr_nz (((struct hppa_frame_cache *)*this_cache)->base));
@@ -2137,7 +2181,11 @@ hppa_stub_frame_this_id (struct frame_info *next_frame,
 {
   struct hppa_stub_unwind_cache *info
     = hppa_stub_frame_unwind_cache (next_frame, this_prologue_cache);
-  *this_id = frame_id_build (info->base, frame_pc_unwind (next_frame));
+
+  if (info)
+    *this_id = frame_id_build (info->base, frame_func_unwind (next_frame));
+  else
+    *this_id = null_frame_id;
 }
 
 static void
@@ -2149,8 +2197,13 @@ hppa_stub_frame_prev_register (struct frame_info *next_frame,
 {
   struct hppa_stub_unwind_cache *info
     = hppa_stub_frame_unwind_cache (next_frame, this_prologue_cache);
-  hppa_frame_prev_register_helper (next_frame, info->saved_regs, regnum,
-                                  optimizedp, lvalp, addrp, realnump, valuep);
+
+  if (info)
+    hppa_frame_prev_register_helper (next_frame, info->saved_regs, regnum,
+                                    optimizedp, lvalp, addrp, realnump, 
+                                    valuep);
+  else
+    error ("Requesting registers from null frame.\n");
 }
 
 static const struct frame_unwind hppa_stub_frame_unwind = {
@@ -2182,10 +2235,49 @@ hppa_unwind_dummy_id (struct gdbarch *gdbarch, struct frame_info *next_frame)
                         frame_pc_unwind (next_frame));
 }
 
-static CORE_ADDR
+CORE_ADDR
 hppa_unwind_pc (struct gdbarch *gdbarch, struct frame_info *next_frame)
 {
-  return frame_unwind_register_signed (next_frame, HPPA_PCOQ_HEAD_REGNUM) & ~3;
+  ULONGEST ipsw;
+  CORE_ADDR pc;
+
+  ipsw = frame_unwind_register_unsigned (next_frame, HPPA_IPSW_REGNUM);
+  pc = frame_unwind_register_unsigned (next_frame, HPPA_PCOQ_HEAD_REGNUM);
+
+  /* If the current instruction is nullified, then we are effectively
+     still executing the previous instruction.  Pretend we are still
+     there.  This is needed when single stepping; if the nullified
+     instruction is on a different line, we don't want GDB to think
+     we've stepped onto that line.  */
+  if (ipsw & 0x00200000)
+    pc -= 4;
+
+  return pc & ~0x3;
+}
+
+/* Return the minimal symbol whose name is NAME and stub type is STUB_TYPE.
+   Return NULL if no such symbol was found.  */
+
+struct minimal_symbol *
+hppa_lookup_stub_minimal_symbol (const char *name,
+                                 enum unwind_stub_types stub_type)
+{
+  struct objfile *objfile;
+  struct minimal_symbol *msym;
+
+  ALL_MSYMBOLS (objfile, msym)
+    {
+      if (strcmp (SYMBOL_LINKAGE_NAME (msym), name) == 0)
+        {
+          struct unwind_table_entry *u;
+
+          u = find_unwind_entry (SYMBOL_VALUE (msym));
+          if (u != NULL && u->stub_unwind.stub_type == stub_type)
+            return msym;
+        }
+    }
+
+  return NULL;
 }
 
 /* Instead of this nasty cast, add a method pvoid() that prints out a
@@ -2261,6 +2353,31 @@ unwind_command (char *exp, int from_tty)
   pin (Entry_FR);
   pin (Entry_GR);
   pin (Total_frame_size);
+
+  if (u->stub_unwind.stub_type)
+    {
+      printf_unfiltered ("\tstub type = ");
+      switch (u->stub_unwind.stub_type)
+        {
+         case LONG_BRANCH:
+           printf_unfiltered ("long branch\n");
+           break;
+         case PARAMETER_RELOCATION:
+           printf_unfiltered ("parameter relocation\n");
+           break;
+         case EXPORT:
+           printf_unfiltered ("export\n");
+           break;
+         case IMPORT:
+           printf_unfiltered ("import\n");
+           break;
+         case IMPORT_SHLIB:
+           printf_unfiltered ("import shlib\n");
+           break;
+         default:
+           printf_unfiltered ("unknown (%d)\n", u->stub_unwind.stub_type);
+       }
+    }
 }
 
 int
@@ -2291,22 +2408,6 @@ hppa_pc_requires_run_before_use (CORE_ADDR pc)
   return (!target_has_stack && (pc & 0xFF000000));
 }
 
-static int
-hppa_instruction_nullified (struct gdbarch *gdbarch, struct regcache *regcache)
-{
-  ULONGEST tmp, ipsw, flags;
-
-  regcache_cooked_read (regcache, HPPA_IPSW_REGNUM, &tmp);
-  ipsw = extract_unsigned_integer (&tmp, 
-                                  register_size (gdbarch, HPPA_IPSW_REGNUM));
-
-  regcache_cooked_read (regcache, HPPA_FLAGS_REGNUM, &tmp);
-  flags = extract_unsigned_integer (&tmp, 
-                                   register_size (gdbarch, HPPA_FLAGS_REGNUM));
-
-  return ((ipsw & 0x00200000) && !(flags & 0x2));
-}
-
 /* Return the GDB type object for the "standard" data type of data
    in register N.  */
 
@@ -2414,6 +2515,27 @@ hppa_frame_prev_register_helper (struct frame_info *next_frame,
       return;
     }
 
+  /* Make sure the "flags" register is zero in all unwound frames.
+     The "flags" registers is a HP-UX specific wart, and only the code
+     in hppa-hpux-tdep.c depends on it.  However, it is easier to deal
+     with it here.  This shouldn't affect other systems since those
+     should provide zero for the "flags" register anyway.  */
+  if (regnum == HPPA_FLAGS_REGNUM)
+    {
+      if (valuep)
+       store_unsigned_integer (valuep, 
+                               register_size (get_frame_arch (next_frame), 
+                                              regnum), 
+                               0);
+
+      /* 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);
 }
@@ -2519,6 +2641,8 @@ hppa_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
   /* The following gdbarch vector elements do not depend on the address
      size, or in any other gdbarch element previously set.  */
   set_gdbarch_skip_prologue (gdbarch, hppa_skip_prologue);
+  set_gdbarch_in_function_epilogue_p (gdbarch,
+                                     hppa_in_function_epilogue_p);
   set_gdbarch_inner_than (gdbarch, core_addr_greaterthan);
   set_gdbarch_sp_regnum (gdbarch, HPPA_SP_REGNUM);
   set_gdbarch_fp0_regnum (gdbarch, HPPA_FP0_REGNUM);
@@ -2527,8 +2651,8 @@ hppa_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
   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);
-  set_gdbarch_read_pc (gdbarch, hppa_target_read_pc);
-  set_gdbarch_write_pc (gdbarch, hppa_target_write_pc);
+  set_gdbarch_read_pc (gdbarch, hppa_read_pc);
+  set_gdbarch_write_pc (gdbarch, hppa_write_pc);
 
   /* Helper for function argument information.  */
   set_gdbarch_fetch_pointer_argument (gdbarch, hppa_fetch_pointer_argument);
@@ -2573,7 +2697,6 @@ hppa_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
       
   set_gdbarch_breakpoint_from_pc (gdbarch, hppa_breakpoint_from_pc);
   set_gdbarch_pseudo_register_read (gdbarch, hppa_pseudo_register_read);
-  set_gdbarch_instruction_nullified (gdbarch, hppa_instruction_nullified);
 
   /* Frame unwind methods.  */
   set_gdbarch_unwind_dummy_id (gdbarch, hppa_unwind_dummy_id);
@@ -2604,9 +2727,6 @@ void
 _initialize_hppa_tdep (void)
 {
   struct cmd_list_element *c;
-  void break_at_finish_command (char *arg, int from_tty);
-  void tbreak_at_finish_command (char *arg, int from_tty);
-  void break_at_finish_at_depth_command (char *arg, int from_tty);
 
   gdbarch_register (bfd_arch_hppa, hppa_gdbarch_init, hppa_dump_tdep);
 
@@ -2616,36 +2736,6 @@ _initialize_hppa_tdep (void)
           "Print unwind table entry at given address.",
           &maintenanceprintlist);
 
-  deprecate_cmd (add_com ("xbreak", class_breakpoint, 
-                         break_at_finish_command,
-                         concat ("Set breakpoint at procedure exit. \n\
-Argument may be function name, or \"*\" and an address.\n\
-If function is specified, break at end of code for that function.\n\
-If an address is specified, break at the end of the function that contains \n\
-that exact address.\n",
-                  "With no arg, uses current execution address of selected stack frame.\n\
-This is useful for breaking on return to a stack frame.\n\
-\n\
-Multiple breakpoints at one place are permitted, and useful if conditional.\n\
-\n\
-Do \"help breakpoints\" for info on other commands dealing with breakpoints.", NULL)), NULL);
-  deprecate_cmd (add_com_alias ("xb", "xbreak", class_breakpoint, 1), NULL);
-  deprecate_cmd (add_com_alias ("xbr", "xbreak", class_breakpoint, 1), NULL);
-  deprecate_cmd (add_com_alias ("xbre", "xbreak", class_breakpoint, 1), NULL);
-  deprecate_cmd (add_com_alias ("xbrea", "xbreak", class_breakpoint, 1), NULL);
-
-  deprecate_cmd (c = add_com ("txbreak", class_breakpoint, 
-                             tbreak_at_finish_command,
-"Set temporary breakpoint at procedure exit.  Either there should\n\
-be no argument or the argument must be a depth.\n"), NULL);
-  set_cmd_completer (c, location_completer);
-  
-  if (xdb_commands)
-    deprecate_cmd (add_com ("bx", class_breakpoint, 
-                           break_at_finish_at_depth_command,
-"Set breakpoint at procedure exit.  Either there should\n\
-be no argument or the argument must be a depth.\n"), NULL);
-
   /* Debug this files internals. */
   add_setshow_boolean_cmd ("hppa", class_maintenance, &hppa_debug, "\
 Set whether hppa target specific debugging information should be displayed.", "\
This page took 0.031199 seconds and 4 git commands to generate.