[rfc] dummy calls for hppa64-hpux

Randolph Chung randolph@tausq.org
Thu Dec 9 13:31:00 GMT 2004


this patch is not yet ready for inclusion, i'm only posting it for
comments because it's rather unorthodox.

there are two cases that i am trying to address:

1) on 32-bit hpux, we cannot do calls from gdb if the current space is
not the same space as __gcc_plt_call

2) on 64-bit hpux we don't have a suitable implementation of
push_dummy_code (64-bit hpux doesn't have __gcc_plt_call or
__d_plt_call)

the fundamental problem is that gdb cannot set pcsqh directly, the only
way to do it is to do an external branch to the target space. In old
versions of gdb (i.e. 5.x) this was done by temporarily overwriting the
insn at pc with a "bve" instruction, single step the inferior, and then
restoring the original instruction. this has obvious problems with
multithreaded apps. Dan also pointed out to me that the handling of
single stepping (as revived by the code below) will not handle
"unexpected" signals correctly. also there's no guarantee that we can
actually write to the memory space pointed to by pc.

I don't have any other good ideas of how to solve these problems, so
I've tried to reintroduce some of the hacks found in old versions of gdb
in as clean a way as possible. comments? is something like this ok?

randolph

Index: hppa-hpux-tdep.c
===================================================================
RCS file: /cvs/src/src/gdb/hppa-hpux-tdep.c,v
retrieving revision 1.29
diff -u -p -r1.29 hppa-hpux-tdep.c
--- hppa-hpux-tdep.c	8 Dec 2004 01:48:01 -0000	1.29
+++ hppa-hpux-tdep.c	9 Dec 2004 04:57:24 -0000
@@ -33,6 +33,8 @@
 #include "infcall.h"
 #include "observer.h"
 #include "hppa-tdep.h"
+#include "solib-som.h"
+#include "solib-pa64.h"
 
 #include <dl.h>
 #include <machine/save_state.h>
@@ -53,6 +55,20 @@ typedef struct
   }
 args_for_find_stub;
 
+static int
+in_opd_section (CORE_ADDR pc)
+{
+  struct obj_section *s;
+  int retval = 0;
+
+  s = find_pc_section (pc);
+
+  retval = (s != NULL
+	    && s->the_bfd_section->name != NULL
+	    && strcmp (s->the_bfd_section->name, ".opd") == 0);
+  return (retval);
+}
+
 /* Return one if PC is in the call path of a trampoline, else return zero.
 
    Note we return one for *any* call trampoline (long-call, arg-reloc), not
@@ -1228,8 +1246,84 @@ hppa_hpux_sigtramp_unwind_sniffer (struc
   return NULL;
 }
 
+static int
+hppa_hpux_try_to_set_pcsqh (ULONGEST target_addr)
+{
+  /* HACK!  FIXME!  
+     pcsqh cannot be written to directly; the only way to modify it is
+     to do an external branch to the new space.  We do this by doing code
+     modification as well as single-stepping the inferior.  This is 
+     inheritently unsafe against signals and multithreaded applications,
+     but we have little alternative.  */
+
+  unsigned int orig_insn[2];
+  unsigned int new_insn[2];
+  CORE_ADDR pcoqh, pcoqt;
+  ULONGEST r1, space;
+  struct target_waitstatus w;
+  int sid;
+
+  sid = (target_addr >> (register_size (current_gdbarch, 0) * 8 - 2)) & 3;
+
+  if (sid == 0)
+    space = read_register (HPPA_SR4_REGNUM);
+  else
+    space = read_register (HPPA_SR4_REGNUM + 4 + sid);
+
+  /* Don't do all this rather dangerous operation if we don't have to.  */
+  if (space == read_register (HPPA_PCSQ_HEAD_REGNUM))
+    return 0;
+
+  pcoqh = read_register (HPPA_PCOQ_HEAD_REGNUM) & ~0x3;
+  pcoqt = read_register (HPPA_PCOQ_TAIL_REGNUM) & ~0x3;
+  r1 = read_register (1);
+
+  if (target_read_memory (pcoqh, (char *)&orig_insn[0], 4) 
+      || target_read_memory (pcoqt, (char *)&orig_insn[1], 4))
+    return -1;
+
+  new_insn[0] = 0xe0202000 | (sid << 14);	/* be 0(%srN,%r1) */
+  new_insn[1] = 0x08000240;			/* nop */
+
+  if (target_write_memory (pcoqh, (char *)&new_insn[0], 4)
+      || target_write_memory (pcoqt, (char *)&new_insn[1], 4))
+    return -1;	
+
+  write_register (1, target_addr);
+
+  target_resume (inferior_ptid, 1, 0);
+  registers_changed ();
+  target_wait (inferior_ptid, &w);
+  target_resume (inferior_ptid, 1, 0);
+  registers_changed ();
+  target_wait (inferior_ptid, &w);
+
+  if ((space & ~0x3ff) != (read_register (HPPA_PCSQ_HEAD_REGNUM) & ~0x3ff))
+    {
+      error ("Cannot set pcsqh correctly, got 0x%s instead of 0x%s\n", 
+	     paddr_nz (read_register (HPPA_PCSQ_HEAD_REGNUM)), 
+	     paddr_nz (space));
+      return -1;
+    }
+
+  if (target_write_memory (pcoqh, (char *)&orig_insn[0], 4)
+      || target_write_memory (pcoqt, (char *)&orig_insn[1], 4))
+    {
+      /* This error is noisy because we were able to overwrite the values 
+         above, but we can't restore it now.  */
+      error ("Cannot restore insns to pcoqh/pcoqt while setting pcsqh.\n");
+      return -1;
+    }
+
+  write_register (HPPA_PCOQ_HEAD_REGNUM, pcoqh);
+  write_register (HPPA_PCOQ_TAIL_REGNUM, pcoqt);
+  write_register (1, r1);
+
+  return 0;
+}
+
 static CORE_ADDR
-hppa_hpux_som_find_global_pointer (struct value *function)
+hppa32_hpux_find_global_pointer (struct value *function)
 {
   CORE_ADDR faddr;
   
@@ -1248,15 +1342,15 @@ hppa_hpux_som_find_global_pointer (struc
 	return extract_unsigned_integer (buf, sizeof (buf));
     }
 
-  return som_solib_get_got_by_pc (faddr);
+  return gdbarch_tdep (current_gdbarch)->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)
+hppa32_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
@@ -1327,6 +1421,12 @@ hppa_hpux_push_dummy_code (struct gdbarc
       struct minimal_symbol *funsym, *stubsym;
       CORE_ADDR stubaddr = 0;
 
+      if (hppa_hpux_try_to_set_pcsqh (SYMBOL_VALUE (sym)))
+        {
+          error ("Cannot do interspace function call from here.\n");
+          return sp;
+        }
+
       funsym = lookup_minimal_symbol_by_pc (funcaddr);
       if (!funsym)
         error ("Unable to find symbol for target function.\n");
@@ -1415,6 +1515,91 @@ hppa_hpux_push_dummy_code (struct gdbarc
 
   return sp;
 }
+
+static CORE_ADDR
+hppa64_hpux_find_global_pointer (struct value *function)
+{
+  CORE_ADDR faddr;
+  char buf[32];
+  
+  faddr = value_as_address (function);
+
+  if (in_opd_section (faddr))
+    {
+      target_read_memory (faddr, buf, sizeof (buf));
+      return extract_unsigned_integer (&buf[24], 8);
+    }
+  else
+    {
+      return gdbarch_tdep (current_gdbarch)->solib_get_got_by_pc (faddr);
+    }
+}
+
+static CORE_ADDR
+hppa64_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)
+{
+  /* hppa64-hp-hpux does not have __gcc_plt_call; instead we have to do 
+     everything ourselves using a stack trampoline.  */
+
+  /* This is padded so it is a multiple of 8-bytes, so that if we write an
+     opd after the trampoline it will be properly aligned.  */
+  static unsigned int trampoline[] = {
+    0x0fdf12d1, /* std r31,-8(,sp)	*/
+    0x50220020, /* ldd 10(r1),rp	*/
+    0xe840f000, /* bve,l (rp),%r2	*/
+    0x503b0030, /* ldd 18(r1),dp	*/
+    0x0fd110c2, /* ldd -8(,sp),rp	*/
+    0xe840d002, /* bve,n (rp)		*/
+    0x08000240, /* nop			*/
+    0x08000240  /* nop			*/
+  };
+  unsigned long opd[] = { 0, 0, 0, 0 };
+  int opd_on_stack = 0;
+
+  if (hppa_hpux_try_to_set_pcsqh (sp))
+    {
+      error ("Cannot do interspace function call from here.\n");
+      return sp;
+    }
+
+  write_memory (sp, (char *)&trampoline, sizeof (trampoline));
+
+  if (!in_opd_section (funcaddr))
+    {
+      opd[2] = funcaddr;
+      opd[3] = gdbarch_tdep (gdbarch)->solib_get_got_by_pc (funcaddr);
+      if (opd[3] == 0)
+        opd[3] = read_register (27);
+
+      write_memory (sp + sizeof (trampoline), (char *)&opd, sizeof (opd));
+      regcache_cooked_write_unsigned (current_regcache, 1, sp + sizeof (trampoline));
+      opd_on_stack = 1;
+    }
+  else
+    regcache_cooked_write_unsigned (current_regcache, 1, funcaddr);
+
+  /* We set the breakpoint address and r31 to (close to) where the current
+     pc is; when the trampoline 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 the stub.  */
+  *real_pc = sp;
+
+  if (opd_on_stack)
+    sp += sizeof(opd);
+  sp = gdbarch_frame_align (gdbarch, sp + sizeof (trampoline));
+
+  return sp;
+}
+
 
 
 /* Bit in the `ss_flag' member of `struct save_state' that indicates
@@ -1519,15 +1755,13 @@ hppa_hpux_init_abi (struct gdbarch_info 
   else
     tdep->in_solib_call_trampoline = hppa64_hpux_in_solib_call_trampoline;
 
   tdep->unwind_adjust_stub = hppa_hpux_unwind_adjust_stub;
+  tdep->unwind_stub_frame = hppa_hpux_unwind_stub_frame;
 
   set_gdbarch_in_solib_return_trampoline (gdbarch,
 					  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);
-
   set_gdbarch_read_pc (gdbarch, hppa_hpux_read_pc);
   set_gdbarch_write_pc (gdbarch, hppa_hpux_write_pc);
   set_gdbarch_unwind_pc (gdbarch, hppa_hpux_unwind_pc);
@@ -1544,8 +1779,13 @@ hppa_hpux_som_init_abi (struct gdbarch_i
 
   tdep->is_elf = 0;
 
-  tdep->find_global_pointer = hppa_hpux_som_find_global_pointer;
+  tdep->find_global_pointer = hppa32_hpux_find_global_pointer;
+
+  set_gdbarch_push_dummy_code (gdbarch, hppa32_hpux_push_dummy_code);
+  set_gdbarch_call_dummy_location (gdbarch, ON_STACK);
+
   hppa_hpux_init_abi (info, gdbarch);
+  som_solib_select (tdep);
 }
 
 static void
@@ -1554,7 +1794,13 @@ hppa_hpux_elf_init_abi (struct gdbarch_i
   struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
 
   tdep->is_elf = 1;
+  tdep->find_global_pointer = hppa64_hpux_find_global_pointer;
+
+  set_gdbarch_push_dummy_code (gdbarch, hppa64_hpux_push_dummy_code);
+  set_gdbarch_call_dummy_location (gdbarch, ON_STACK);
+
   hppa_hpux_init_abi (info, gdbarch);
+  pa64_solib_select (tdep);
 }
 
 void

-- 
Randolph Chung
Debian GNU/Linux Developer, hppa/ia64 ports
http://www.tausq.org/



More information about the Gdb-patches mailing list