--- gdb-6.1/gdb/hppa-linux-tdep.c	2003-09-18 23:14:27.000000000 -0700
+++ gdb-6.1/gdb/hppa-linux-tdep.c	2003-09-18 23:14:27.000000000 -0700
@@ -30,6 +30,8 @@ Foundation, Inc., 59 Temple Place - Suit
 #include "dwarf2-frame.h"
 #include "hppa-tdep.h"
 
+#include "elf/common.h"
+
 #if 0
 /* Convert DWARF register number REG to the appropriate register
    number used by GDB.  */
@@ -466,6 +468,77 @@ hppa_linux_sigtramp_unwind_sniffer (stru
   return NULL;
 }
 
+/* Attempt to find (and return) the global pointer for the given
+   function.
+
+   This is a rather nasty bit of code searchs for the .dynamic section
+   in the objfile corresponding to the pc of the function we're trying
+   to call.  Once it finds the addresses at which the .dynamic section
+   lives in the child process, it scans the Elf32_Dyn entries for a
+   DT_PLTGOT tag.  If it finds one of these, the corresponding
+   d_un.d_ptr value is the global pointer.  */
+
+static CORE_ADDR
+hppa_linux_find_global_pointer (CORE_ADDR faddr)
+{
+  struct obj_section *faddr_sect;
+
+  /* If the address is in the plt section, then the real function hasn't 
+     yet been fixed up by the linker so we cannot determine the gp of 
+     that function.  */
+  if (in_plt_section (faddr, NULL))
+    return 0;
+
+  faddr_sect = find_pc_section (faddr);
+  if (faddr_sect != NULL)
+    {
+      struct obj_section *osect;
+
+      ALL_OBJFILE_OSECTIONS (faddr_sect->objfile, osect)
+	{
+	  if (strcmp (osect->the_bfd_section->name, ".dynamic") == 0)
+	    break;
+	}
+
+      if (osect < faddr_sect->objfile->sections_end)
+	{
+	  CORE_ADDR addr;
+
+	  addr = osect->addr;
+	  while (addr < osect->endaddr)
+	    {
+	      int status;
+	      LONGEST tag;
+	      char buf[4];
+
+	      status = target_read_memory (addr, buf, sizeof (buf));
+	      if (status != 0)
+		break;
+	      tag = extract_signed_integer (buf, sizeof (buf));
+
+	      if (tag == DT_PLTGOT)
+		{
+		  CORE_ADDR global_pointer;
+
+		  status = target_read_memory (addr + 4, buf, sizeof (buf));
+		  if (status != 0)
+		    break;
+		  global_pointer = extract_unsigned_integer (buf, sizeof (buf));
+
+		  /* The payoff... */
+		  return global_pointer;
+		}
+
+	      if (tag == DT_NULL)
+		break;
+
+	      addr += 8;
+	    }
+	}
+    }
+  return 0;
+}
+
 /* Forward declarations.  */
 extern initialize_file_ftype _initialize_hppa_linux_tdep;
 
@@ -476,6 +549,8 @@ hppa_linux_init_abi (struct gdbarch_info
 
   /* Linux is always ELF.  */
   tdep->is_elf = 1;
+
+  tdep->find_global_pointer = hppa_linux_find_global_pointer;
 
   set_gdbarch_write_pc (gdbarch, hppa_linux_target_write_pc);
 
--- gdb-6.1/gdb/hppa-tdep.c	8 May 2004 03:59:34 -0000	1.156
+++ gdb-6.1/gdb/hppa-tdep.c	8 May 2004 04:31:05 -0000
@@ -768,6 +772,12 @@ hppa32_push_dummy_call (struct gdbarch *
   /* 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;
@@ -888,6 +898,11 @@ hppa32_push_dummy_call (struct gdbarch *
   if (struct_return)
     write_register (28, struct_addr);
 
+  gp = tdep->find_global_pointer (func_addr);
+
+  if (gp != 0)
+    write_register (19, gp);
+
   /* Set the return address.  */
   regcache_cooked_write_unsigned (regcache, HPPA_RP_REGNUM, bp_addr);
 
@@ -1021,6 +1036,26 @@ hppa64_push_dummy_call (struct gdbarch *
 }
 
 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;
+      unsigned int gp;
+
+      plabel = addr & ~3;
+
+      target_read_memory(plabel + 4, (char *)&gp, 4);
+      write_register (19, gp);
+      target_read_memory(plabel, (char *)&addr, 4);
+    }
+
+  return addr;
+}
+
+static CORE_ADDR
 hppa32_frame_align (struct gdbarch *gdbarch, CORE_ADDR addr)
 {
   /* HP frames are 64-byte (or cache line) aligned (yes that's _byte_
@@ -1535,7 +1570,7 @@ hppa_skip_prologue (CORE_ADDR pc)
      is greater.  */
 
   post_prologue_pc = after_prologue (pc);
-
+ 
   /* If after_prologue returned a useful address, then use it.  Else
      fall back on the instruction skipping code.
 
@@ -1585,6 +1620,8 @@ hppa_frame_cache (struct frame_info *nex
   u = find_unwind_entry (frame_func_unwind (next_frame));
   if (!u)
     {
+      warning ("Cannot find unwind entry for 0x%s\n", 
+		paddr_nz (frame_func_unwind (next_frame)));
       if (hppa_debug)
         fprintf_unfiltered (gdb_stdlog, "base=NULL (no unwind entry) }");
       return (*this_cache);
@@ -2300,6 +2337,12 @@ hppa_pseudo_register_read (struct gdbarc
     store_unsigned_integer (buf, sizeof(tmp), tmp);
 }
 
+static CORE_ADDR
+hppa_find_global_pointer (CORE_ADDR faddr)
+{
+  return 0;
+}
+
 void
 hppa_frame_prev_register_helper (struct frame_info *next_frame,
 			         struct trad_frame_saved_reg saved_regs[],
@@ -2389,6 +2432,8 @@ hppa_gdbarch_init (struct gdbarch_info i
   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)
@@ -2448,6 +2493,8 @@ hppa_gdbarch_init (struct gdbarch_info i
     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);
--- gdb-6.1/gdb/hppa-tdep.h	2003-09-18 23:14:27.000000000 -0700
+++ gdb-6.1/gdb/hppa-tdep.h	2003-09-18 23:14:27.000000000 -0700
@@ -75,6 +75,10 @@ struct gdbarch_tdep
   /* Is this an ELF target? This can be 64-bit HP-UX, or a 32/64-bit GNU/Linux
      system.  */
   int is_elf;
+
+  /* Given a function address, try to find the global pointer for the 
+     corresponding shared object.  */
+  CORE_ADDR (*find_global_pointer) (CORE_ADDR);
 };
 
 /*
