This is the mail archive of the gdb-patches@sources.redhat.com mailing list for the GDB project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[patch/rfc] Try to get dummy calls working on hpux again


A lot of the original code to handle dummy calls were ripped out of
hppa-tdep.c in March.  This patch brings back some of that logic so that
we can start to make it work again on hpux.

The PA has "space registers" (like segment registers on x86, sort of).
We don't use this for hppa-linux, so simply using push_dummy_call was
enough. HPUX uses it though....

Because the caller and callee may be in different spaces, we need to go
through some hoops to set/reset the space registers across calls. The
original code had many special cases to handle multiple targets, and
multiple function types. This only brings back some of that logic, and 
it only works for 32-bit SOM at the moment. My plan is to try to fix 
this incrementally rather than get it "perfect" on the first try....

this fixes calling shared library functions from inside gdb, so it
fixes quite a few test failures, but there are many more! :(

comments? ok to check in? 

randolph

2004-06-09  Randolph Chung  <tausq@debian.org>

    * hppa-hpux-tdep.c (hppa_hpux_som_find_global_pointer): New 
    function.
    (hppa_hpux_push_dummy_code): New function.
    (hppa_hpux_init_abi): Set push_dummy_code and call_dummy_location.
    Set find_global_pointer method.

Index: hppa-hpux-tdep.c
===================================================================
RCS file: /cvs/src/src/gdb/hppa-hpux-tdep.c,v
retrieving revision 1.20
diff -u -p -r1.20 hppa-hpux-tdep.c
--- hppa-hpux-tdep.c	7 Jun 2004 02:17:29 -0000	1.20
+++ hppa-hpux-tdep.c	10 Jun 2004 05:30:40 -0000
@@ -1203,6 +1204,152 @@ hppa_hpux_sigtramp_unwind_sniffer (struc
   return NULL;
 }
 
+static CORE_ADDR
+hppa_hpux_som_find_global_pointer (struct value *function)
+{
+  CORE_ADDR faddr;
+  
+  faddr = value_as_address (function);
+
+  /* Is this a plabel? If so, dereference it to get the gp value.  */
+  if (faddr & 2)
+    {
+      int status;
+      char buf[4];
+
+      faddr &= ~3;
+
+      status = target_read_memory (faddr + 4, buf, sizeof (buf));
+      if (status == 0)
+	return extract_unsigned_integer (buf, sizeof (buf));
+    }
+
+  return som_solib_get_got_by_pc (faddr);
+}
+
+static CORE_ADDR
+hppa_hpux_push_dummy_code (struct gdbarch *gdbarch, CORE_ADDR sp,
+			   CORE_ADDR funcaddr, int using_gcc,
+			   struct value **args, int nargs,
+			   struct type *value_type,
+			   CORE_ADDR *real_pc, CORE_ADDR *bp_addr)
+{
+  /* FIXME: tausq/2004-06-09: This needs much more testing.  It is broken
+     for pa64, but we should be able to get it to work with a little bit
+     of work. gdb-6.1 has a lot of code to handle various cases; I've tried to
+     simplify it and avoid compile-time conditionals.  */
+
+  struct minimal_symbol *sym;
+
+  /* Nonzero if we will use GCC's PLT call routine.  This routine must be
+     passed an import stub, not a PLABEL.  It is also necessary to get %r19
+     before performing the call.  (This is done by push_dummy_call.)  */
+  int use_gcc_plt_call = 1;
+
+  /* See if __gcc_plt_call is available; if not we will use the HP version
+     instead.  */
+  sym = lookup_minimal_symbol ("__gcc_plt_call", NULL, NULL);
+  if (sym == NULL)
+    use_gcc_plt_call = 0;
+
+  /* If using __gcc_plt_call, we need to make sure we pass in an import
+     stub.  funcaddr can be pointing to an export stub or a real function,
+     so we try to resolve it to the import stub.  */
+  if (use_gcc_plt_call)
+    {
+      struct objfile *objfile;
+      struct minimal_symbol *funsym, *stubsym;
+      CORE_ADDR stubaddr = 0;
+
+      funsym = lookup_minimal_symbol_by_pc (funcaddr);
+      if (!funsym)
+        error ("Unable to find symbol for target function.\n");
+
+      ALL_OBJFILES (objfile)
+        {
+	  stubsym = lookup_minimal_symbol_solib_trampoline
+	    (SYMBOL_LINKAGE_NAME (funsym), objfile);
+
+          if (stubsym)
+	    {
+	      struct unwind_table_entry *u;
+
+	      u = find_unwind_entry (SYMBOL_VALUE (stubsym));
+	      if (u == NULL 
+	          || (u->stub_unwind.stub_type != IMPORT
+		      && u->stub_unwind.stub_type != IMPORT_SHLIB))
+	        continue;
+
+              stubaddr = SYMBOL_VALUE (stubsym);
+
+	      /* If we found an IMPORT stub, then we can stop searching;
+	         if we found an IMPORT_SHLIB, we want to continue the search
+		 in the hopes that we will find an IMPORT stub.  */
+	      if (u->stub_unwind.stub_type == IMPORT)
+	        break;
+	    }
+	}
+
+      if (stubaddr != 0)
+        {
+          /* Argument to __gcc_plt_call is passed in r22.  */
+          regcache_cooked_write_unsigned (current_regcache, 22, stubaddr);
+        }
+      else
+        {
+	  /* No import stub found; let's synthesize one.  */
+
+	  /* ldsid %r21, %r1 */
+	  write_memory_unsigned_integer (sp, 4, 0x02a010a1);
+	  /* mtsp %r1,%sr0 */
+	  write_memory_unsigned_integer (sp + 4, 4, 0x00011820);
+	  /* be 0(%sr0, %r21) */
+	  write_memory_unsigned_integer (sp + 8, 4, 0xe2a00000);
+          /* nop */
+          write_memory_unsigned_integer (sp + 12, 4, 0x08000240);
+
+          regcache_cooked_write_unsigned (current_regcache, 21, funcaddr);
+          regcache_cooked_write_unsigned (current_regcache, 22, sp);
+	}
+
+      /* We set the breakpoint address and r31 to (close to) where the current
+         pc is; when __gcc_plt_call returns, it will restore pcsqh to the
+	 current value based on this.  The -4 is needed for frame unwinding
+	 to work properly -- we need to land in a different function than
+	 the current function.  */
+      *bp_addr = (read_register (HPPA_PCOQ_HEAD_REGNUM) & ~3) - 4;
+      regcache_cooked_write_unsigned (current_regcache, 31, *bp_addr);
+
+      /* Continue from __gcc_plt_call.  */
+      *real_pc = SYMBOL_VALUE (sym);
+    }
+  else
+    {
+      unsigned int gp;
+
+      /* Use __d_plt_call as a fallback; __d_plt_call expects to be called 
+         with a plabel, so we need to build one.  */
+
+      sym = lookup_minimal_symbol ("__d_plt_call", NULL, NULL);
+      if (sym == NULL)
+        error("Can't find an address for __d_plt_call or __gcc_plt_call "
+	      "trampoline\nSuggest linking executable with -g or compiling "
+	      "with gcc.");
+
+      gp = gdbarch_tdep (gdbarch)->find_global_pointer (funcaddr);
+      write_memory_unsigned_integer (sp, 4, funcaddr);
+      write_memory_unsigned_integer (sp + 4, 4, gp);
+
+      /* plabel is passed in r22 */
+      regcache_cooked_write_unsigned (current_regcache, 22, sp);
+    }
+
+  /* Pushed one stack frame, which has to be 64-byte aligned.  */
+  sp += 64;
+
+  return sp;
+}
+
 static void
 hppa_hpux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
 {
@@ -1219,7 +1375,10 @@ hppa_hpux_init_abi (struct gdbarch_info 
 					  hppa_hpux_in_solib_return_trampoline);
   set_gdbarch_skip_trampoline_code (gdbarch, hppa_hpux_skip_trampoline_code);
 
+  set_gdbarch_push_dummy_code (gdbarch, hppa_hpux_push_dummy_code);
+  set_gdbarch_call_dummy_location (gdbarch, ON_STACK);
+
   frame_unwind_append_sniffer (gdbarch, hppa_hpux_sigtramp_unwind_sniffer);
 }
 
 static void
@@ -1228,6 +1389,8 @@ hppa_hpux_som_init_abi (struct gdbarch_i
   struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
 
   tdep->is_elf = 0;
+
+  tdep->find_global_pointer = hppa_hpux_som_find_global_pointer;
   hppa_hpux_init_abi (info, gdbarch);
 }
 
-- 
Randolph Chung
Debian GNU/Linux Developer, hppa/ia64 ports
http://www.tausq.org/


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]