public inbox for gdb-patches@sourceware.org
 help / color / mirror / Atom feed
* [PATCH 4/8] libunwind-frame.c: handle functions with no minimal symbol/debug info.
  2010-12-28  4:43 Porting GDB to ia64-hpux Joel Brobecker
@ 2010-12-28  4:43 ` Joel Brobecker
  2010-12-28  4:43 ` [PATCH 1/8] Add a big-endian version of the ia64-ext floatformat Joel Brobecker
                   ` (7 subsequent siblings)
  8 siblings, 0 replies; 31+ messages in thread
From: Joel Brobecker @ 2010-12-28  4:43 UTC (permalink / raw)
  To: gdb-patches; +Cc: Joel Brobecker

This is something that I am seeing on ia64-hpux while trying to
backtrace from a thread that's doing a wait:

    (gdb) task 2
    [Switching to task 2]
    0x9fffffffef52f590 in __ksleep () from /[...]/libc.so.1
    (gdb) bt
    #0  0x9fffffffef52f590 in __ksleep () from /[...]/libc.so.1
    #1  0x9fffffffef73c870 in __sleep_1x1 () from /[...]/libpthread.so.1
    #2  0x9fffffffef738fe0 in __mxn_sleep () from /[...]/libpthread.so.1
    #3  0x9fffffffef675e90 in ?? () from /[...]/libpthread.so.1

The backtrace is incomplete and stops at frame #3, but there are in fact
a few more frames.

The reason why we stopped the backtrace is related to the fact that
we were not able to determine the start address of the function
corresponding to the frame PC.  This is visible at the user level
thanks to the "??" that GDB displayed for frame 3.

We have the following code in libunwind-frame.c:libunwind_frame_cache
which explicitly returns a NULL cache when we couldn't determine the
frame's function address, immediately triggering an end-of-stack
frame_id, thus terminating the backtrace:

   /* We can assume we are unwinding a normal frame.  Even if this is
      for a signal trampoline, ia64 signal "trampolines" use a normal
      subroutine call to start the signal handler.  */
   cache->func_addr = get_frame_func (this_frame);
   if (cache->func_addr == 0
       && get_next_frame (this_frame)
       && get_frame_type (get_next_frame (this_frame)) == NORMAL_FRAME)
     return NULL;

As explained in the comment, I think we can still go on, and use
the unwind record to do the debugging.  This change imlements this
change, and allows us to get the full backtrace.

gdb/ChangeLog:

        * libunwind-frame.c (libunwind_frame_cache): Do not return NULL
        if we could not determine the frame's function address.  Instead,
        use the frame's PC, and then continue.

---
 gdb/libunwind-frame.c |   20 +++++++++++++-------
 1 files changed, 13 insertions(+), 7 deletions(-)

diff --git a/gdb/libunwind-frame.c b/gdb/libunwind-frame.c
index dc28064..8b712b9 100644
--- a/gdb/libunwind-frame.c
+++ b/gdb/libunwind-frame.c
@@ -157,14 +157,20 @@ libunwind_frame_cache (struct frame_info *this_frame, void **this_cache)
   /* Allocate a new cache.  */
   cache = FRAME_OBSTACK_ZALLOC (struct libunwind_frame_cache);
 
-  /* We can assume we are unwinding a normal frame.  Even if this is
-     for a signal trampoline, ia64 signal "trampolines" use a normal
-     subroutine call to start the signal handler.  */
   cache->func_addr = get_frame_func (this_frame);
-  if (cache->func_addr == 0
-      && get_next_frame (this_frame)
-      && get_frame_type (get_next_frame (this_frame)) == NORMAL_FRAME)
-    return NULL;
+  if (cache->func_addr == 0)
+    /* This can happen when the frame corresponds to a function for which
+       there is no debugging information nor any entry in the symbol table.
+       This is probably a static function for which an entry in the symbol
+       table was not created when the objfile got linked (observed in
+       libpthread.so on ia64-hpux).
+
+       The best we can do, in that case, is use the frame PC as the function
+       address.  We don't need to give up since we still have the unwind
+       record to help us perform the unwinding.  There is also another
+       compelling to continue, because abandonning now means stopping
+       the backtrace, which can never be helpful for the user.  */
+    cache->func_addr = get_frame_pc (this_frame);
 
   /* Get a libunwind cursor to the previous frame.
   
-- 
1.7.1

^ permalink raw reply	[flat|nested] 31+ messages in thread

* [PATCH 1/8] Add a big-endian version of the ia64-ext floatformat
  2010-12-28  4:43 Porting GDB to ia64-hpux Joel Brobecker
  2010-12-28  4:43 ` [PATCH 4/8] libunwind-frame.c: handle functions with no minimal symbol/debug info Joel Brobecker
@ 2010-12-28  4:43 ` Joel Brobecker
  2010-12-28  4:43 ` [PATCH 2/8] small integral parameters and return values Joel Brobecker
                   ` (6 subsequent siblings)
  8 siblings, 0 replies; 31+ messages in thread
From: Joel Brobecker @ 2010-12-28  4:43 UTC (permalink / raw)
  To: gdb-patches; +Cc: Joel Brobecker

ia64-tdep.c defines a floatformats_ia64_ext that should contain
both the little-endian and the big-endian version of the float
format used in the ia64 registers (an 82bit float format).
Right now, both entries point to the same little-endian definition.

A big-endian definition is now necessary for the ia64-hpux port.

gdb/ChangeLog:

        * ia64-tdep.c (floatformat_ia64_ext_little): Renames
        floatformat_ia64_ext.
        (floatformat_ia64_ext_big): New static const.
        (floatformats_ia64_ext): Set first entry to &floatformat_ia64_ext_big.

---
 gdb/ia64-tdep.c |   14 ++++++++++----
 1 files changed, 10 insertions(+), 4 deletions(-)

diff --git a/gdb/ia64-tdep.c b/gdb/ia64-tdep.c
index 3cc0150..6e24c9e 100644
--- a/gdb/ia64-tdep.c
+++ b/gdb/ia64-tdep.c
@@ -285,16 +285,22 @@ floatformat_valid (const struct floatformat *fmt, const void *from)
   return 1;
 }
 
-static const struct floatformat floatformat_ia64_ext =
+static const struct floatformat floatformat_ia64_ext_little =
 {
   floatformat_little, 82, 0, 1, 17, 65535, 0x1ffff, 18, 64,
-  floatformat_intbit_yes, "floatformat_ia64_ext", floatformat_valid, NULL
+  floatformat_intbit_yes, "floatformat_ia64_ext_little", floatformat_valid, NULL
+};
+
+static const struct floatformat floatformat_ia64_ext_big =
+{
+  floatformat_big, 82, 46, 47, 17, 65535, 0x1ffff, 64, 64,
+  floatformat_intbit_yes, "floatformat_ia64_ext_big", floatformat_valid
 };
 
 static const struct floatformat *floatformats_ia64_ext[2] =
 {
-  &floatformat_ia64_ext,
-  &floatformat_ia64_ext
+  &floatformat_ia64_ext_big,
+  &floatformat_ia64_ext_little
 };
 
 static struct type *
-- 
1.7.1

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Porting GDB to ia64-hpux
@ 2010-12-28  4:43 Joel Brobecker
  2010-12-28  4:43 ` [PATCH 4/8] libunwind-frame.c: handle functions with no minimal symbol/debug info Joel Brobecker
                   ` (8 more replies)
  0 siblings, 9 replies; 31+ messages in thread
From: Joel Brobecker @ 2010-12-28  4:43 UTC (permalink / raw)
  To: gdb-patches

At long last, after having promised this a long time ago (this brings
memories of Australia, as I was spending time there when I first started
on this port), I am finally contributing this port.  It took a while,
because the first port I did (against GDB 6.3) had a few hacks in it
that I wasn't happy about.

This port is relatively clean, I believe.  There is one dark spot with
shared library support, which is currently native-only - if you build
GDB as a cross debugger to ia64-hpux, you won't get the shared libraries.
I think that this is an acceptable limitation, since I'm not planning on
supporting gdbserver-style remote debugging capabilities.  I did spend
a couple of hours exploring the idea of using solib-target, but there
were a couple of issues[1].

I was able to build tcl/expect on this platform, and thus was able to
run the testsuite.  Results are not stellar, but to my surprise, already
better than what I get on ia64-linux.  A large portion of the failures
are caused by known limitations / missing features in that port, which
I will detail a little bit below.  Results first:

        # of expected passes            10618
        # of unexpected failures        727
        # of expected failures          50
        # of untested testcases         105
        # of unresolved testcases       12
        # of unsupported tests          61

The entire patch series has also been tested on ia64-linux, with no
observed regression.

I'd like to commit this Thu or Fri in a week from now.

Known problems and missing features that are causing most of the failures:

  - core files are not supported (I know it's easy to add, but I just
    don't know how to!). If someone kindly helped, I would be happy
    to give it a crack - an interesting learning exercise.

  - The kernel on HP-UX does not allow the debugger to change the value
    of the BSP register, which makes it impossible to "pop" a register
    frame at the same time was pop the stack frame during a "return".
    This pretty much guaranties great chaos during a "return" (loss of
    synchronization between the call stack and the register stack).

  - Backtraces through signal handlers.

  - function-call parameter passing / return values: There are still
    some cases where we pass the parameters incorrectly.  But that's
    general to ia64, I think.

-- 
Joel

[1] Issues related to using solib-target with ia64-hpux:

    (a) I need the various hooks to setup the shared-lib notifications;

    (b) And next, it's not obvious how to map the info I get from
        the system back to the way the info is encoded in the
        TARGET_OBJECT_SHARED_LIBRARIES object. In particular, there are
        two segments (data and code) to consider when performing section
        relocation.  The second issue should be workable, but the first
        one is a bit more of an issue.

^ permalink raw reply	[flat|nested] 31+ messages in thread

* [PATCH 2/8] small integral parameters and return values
  2010-12-28  4:43 Porting GDB to ia64-hpux Joel Brobecker
  2010-12-28  4:43 ` [PATCH 4/8] libunwind-frame.c: handle functions with no minimal symbol/debug info Joel Brobecker
  2010-12-28  4:43 ` [PATCH 1/8] Add a big-endian version of the ia64-ext floatformat Joel Brobecker
@ 2010-12-28  4:43 ` Joel Brobecker
  2010-12-28  4:44 ` [PATCH 6/8] port GDB to ia64-hpux (native) Joel Brobecker
                   ` (5 subsequent siblings)
  8 siblings, 0 replies; 31+ messages in thread
From: Joel Brobecker @ 2010-12-28  4:43 UTC (permalink / raw)
  To: gdb-patches; +Cc: Joel Brobecker

This patch fixes a small problem on ia64-hpux when calling functions
whose parameter are small integral values (less than 8 bytes).  In
that case, the parameter value was stored on the wrong side of the
register.  Same problem for return values.

With this patch, the results for gdb.base/callfuncs.exp improve from

        # of expected passes            41
        # of unexpected failures        78

To:

        # of expected passes            95
        # of unexpected failures        24

gdb/ChangeLog:

        * ia64-tdep.c (ia64_struct_type_p): New function.
        (ia64_extract_return_value): Handle integral values that are
        less than 8 bytes long.
        (ia64_push_dummy_call): Likewise.

Tested on both ia64-hpux and ia64-linux.

---
 gdb/ia64-tdep.c |   49 ++++++++++++++++++++++++++++++++++++++++++++++++-
 1 files changed, 48 insertions(+), 1 deletions(-)

diff --git a/gdb/ia64-tdep.c b/gdb/ia64-tdep.c
index 6e24c9e..1cd6a38 100644
--- a/gdb/ia64-tdep.c
+++ b/gdb/ia64-tdep.c
@@ -3143,6 +3143,15 @@ ia64_use_struct_convention (struct type *type)
   return TYPE_LENGTH (type) > 32;
 }
 
+/* Return non-zero if TYPE is a structure or union type.  */
+
+static int
+ia64_struct_type_p (const struct type *type)
+{
+  return (TYPE_CODE (type) == TYPE_CODE_STRUCT
+          || TYPE_CODE (type) == TYPE_CODE_UNION);
+}
+
 static void
 ia64_extract_return_value (struct type *type, struct regcache *regcache,
 			   gdb_byte *valbuf)
@@ -3167,6 +3176,21 @@ ia64_extract_return_value (struct type *type, struct regcache *regcache,
 	  regnum++;
 	}
     }
+  else if (!ia64_struct_type_p (type) && TYPE_LENGTH (type) < 8)
+    {
+      /* This is an integral value, and its size is less than 8 bytes.
+         These values are LSB-aligned, so extract the relevant bytes,
+         and copy them into VALBUF.  */
+      /* brobecker/2005-12-30: Actually, all integral values are LSB aligned,
+	 so I suppose we should also add handling here for integral values
+	 whose size is greater than 8.  But I wasn't able to create such
+	 a type, neither in C nor in Ada, so not worrying about these yet.  */
+      enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+      ULONGEST val;
+
+      regcache_cooked_read_unsigned (regcache, IA64_GR8_REGNUM, &val);
+      store_unsigned_integer (valbuf, TYPE_LENGTH (type), byte_order, val);
+    }
   else
     {
       ULONGEST val;
@@ -3671,7 +3695,30 @@ ia64_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
 	  char val_buf[8];
 
 	  memset (val_buf, 0, 8);
-	  memcpy (val_buf, value_contents (arg) + argoffset, (len > 8) ? 8 : len);
+          if (!ia64_struct_type_p (type) && len < 8)
+            {
+              /* Integral types are LSB-aligned, so we have to be careful
+                 to insert the argument on the correct side of the buffer.
+                 This is why we use store_unsigned_integer.  */
+              store_unsigned_integer
+                (val_buf, 8, byte_order,
+                 extract_unsigned_integer (value_contents (arg), len,
+					   byte_order));
+            }
+          else
+            {
+              /* This is either an 8bit integral type, or an aggregate.
+                 For 8bit integral type, there is no problem, we just
+                 copy the value over.
+
+                 For aggregates, the only potentially tricky portion
+                 is to write the last one if it is less than 8 bytes.
+                 In this case, the data is Byte0-aligned.  Happy news,
+                 this means that we don't need to differentiate the
+                 handling of 8byte blocks and less-than-8bytes blocks.  */
+              memcpy (val_buf, value_contents (arg) + argoffset,
+                      (len > 8) ? 8 : len);
+            }
 
 	  if (slotnum < rseslots)
 	    write_memory (rse_address_add (bsp, slotnum), val_buf, 8);
-- 
1.7.1

^ permalink raw reply	[flat|nested] 31+ messages in thread

* [PATCH 6/8] port GDB to ia64-hpux (native).
  2010-12-28  4:43 Porting GDB to ia64-hpux Joel Brobecker
                   ` (2 preceding siblings ...)
  2010-12-28  4:43 ` [PATCH 2/8] small integral parameters and return values Joel Brobecker
@ 2010-12-28  4:44 ` Joel Brobecker
  2011-01-11 23:26   ` Steve Ellcey
  2011-01-13 18:07   ` Joel Brobecker
  2010-12-28  4:44 ` [PATCH 3/8] Make sure __LITTLE_ENDIAN/__BIG_ENDIAN are defined in libunwind-frame.c Joel Brobecker
                   ` (4 subsequent siblings)
  8 siblings, 2 replies; 31+ messages in thread
From: Joel Brobecker @ 2010-12-28  4:44 UTC (permalink / raw)
  To: gdb-patches; +Cc: Joel Brobecker

This is the patch that really adds support for ia64-hpux.  There is
one part which I extracted out (inferior function calls), because it
required some changes in the ia64-tdep module which I did not want to
be drowned in the size of this patch.

ChangeLog:

        * configure.ac: Remove readline, mmalloc, and gdb from noconfigdirs
        for ia64-hpux.
        * configure: Regenerate.

This part should really be submitted to GCC, I think, but I'm going
to treat this as obvious, and send a commit email when I commit it.

gdb/ChangeLog:

        * config/ia64/hpux.mh, ia64-hpux-nat.c, ia64-hpux-tdep.c,
        ia64-hpux-tdep.h, solib-ia64-hpux.c, solib-ia64-hpux.h: New files.

        * configure.host: Add handling for ia64-hpux hosts.  Add associated
        floatformats.
        * configure.tgt: Add handling for ia64-hpux targets.
        * Makefile.in (ALL_64_TARGET_OBS): Add ia64-hpux-tdep.o.
        (HFILES_NO_SRCDIR): Add ia64-hpux-tdep.h.
        (ALLDEPFILES): Add ia64-hpux-nat.c ia64-hpux-tdep.c.

---
 configure               |    4 +-
 configure.ac            |    4 +-
 gdb/Makefile.in         |    5 +-
 gdb/config/ia64/hpux.mh |    3 +
 gdb/configure.host      |    6 +
 gdb/configure.tgt       |    4 +
 gdb/ia64-hpux-nat.c     |  641 +++++++++++++++++++++++++++++++++++++++++++
 gdb/ia64-hpux-tdep.c    |  101 +++++++
 gdb/ia64-hpux-tdep.h    |   24 ++
 gdb/solib-ia64-hpux.c   |  696 +++++++++++++++++++++++++++++++++++++++++++++++
 gdb/solib-ia64-hpux.h   |   25 ++
 11 files changed, 1507 insertions(+), 6 deletions(-)
 create mode 100644 gdb/config/ia64/hpux.mh
 create mode 100644 gdb/ia64-hpux-nat.c
 create mode 100644 gdb/ia64-hpux-tdep.c
 create mode 100644 gdb/ia64-hpux-tdep.h
 create mode 100644 gdb/solib-ia64-hpux.c
 create mode 100644 gdb/solib-ia64-hpux.h

diff --git a/configure b/configure
index 10beaee..dc52122 100755
--- a/configure
+++ b/configure
@@ -3353,8 +3353,8 @@ case "${target}" in
     noconfigdirs="$noconfigdirs readline mmalloc libgui itcl gdb"
     ;;
   ia64*-**-hpux*)
-    # No gdb or ld support yet.
-    noconfigdirs="$noconfigdirs ${libgcj} readline mmalloc libgui itcl gdb ld"
+    # No ld support yet.
+    noconfigdirs="$noconfigdirs ${libgcj} libgui itcl ld"
     ;;
   ia64*-*-*vms*)
     # No gdb or ld support yet.
diff --git a/configure.ac b/configure.ac
index d66b73c..ecb30d4 100644
--- a/configure.ac
+++ b/configure.ac
@@ -804,8 +804,8 @@ case "${target}" in
     noconfigdirs="$noconfigdirs readline mmalloc libgui itcl gdb"
     ;;
   ia64*-**-hpux*)
-    # No gdb or ld support yet.
-    noconfigdirs="$noconfigdirs ${libgcj} readline mmalloc libgui itcl gdb ld"
+    # No ld support yet.
+    noconfigdirs="$noconfigdirs ${libgcj} libgui itcl ld"
     ;;
   ia64*-*-*vms*)
     # No gdb or ld support yet.
diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index 5d71223..7257094 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -504,7 +504,7 @@ ALL_64_TARGET_OBS = \
 	amd64fbsd-tdep.o amd64-darwin-tdep.o amd64-dicos-tdep.o \
 	amd64-linux-tdep.o amd64nbsd-tdep.o \
 	amd64obsd-tdep.o amd64-sol2-tdep.o amd64-tdep.o amd64-windows-tdep.o \
-	ia64-linux-tdep.o ia64-tdep.o \
+	ia64-hpux-tdep.o ia64-linux-tdep.o ia64-tdep.o \
 	mips64obsd-tdep.o \
 	sparc64fbsd-tdep.o sparc64-linux-tdep.o sparc64nbsd-tdep.o \
 	sparc64obsd-tdep.o sparc64-sol2-tdep.o sparc64-tdep.o
@@ -789,7 +789,7 @@ annotate.h sim-regno.h dictionary.h dfp.h main.h frame-unwind.h	\
 remote-fileio.h i386-linux-tdep.h vax-tdep.h objc-lang.h \
 sentinel-frame.h bcache.h symfile.h windows-tdep.h linux-tdep.h \
 gdb_usleep.h jit.h xml-syscall.h ada-operator.inc microblaze-tdep.h \
-psymtab.h psympriv.h progspace.h
+psymtab.h psympriv.h progspace.h ia64-hpux-tdep.h
 
 # Header files that already have srcdir in them, or which are in objdir.
 
@@ -1446,6 +1446,7 @@ ALLDEPFILES = \
 	i386-linux-tdep.c i386-nat.c \
 	i386-sol2-nat.c i386-sol2-tdep.c \
 	i386gnu-nat.c i386gnu-tdep.c \
+	ia64-hpux-nat.c ia64-hpux-tdep.c \
 	ia64-linux-nat.c ia64-linux-tdep.c ia64-tdep.c \
 	inf-ptrace.c inf-ttrace.c \
 	irix5-nat.c \
diff --git a/gdb/config/ia64/hpux.mh b/gdb/config/ia64/hpux.mh
new file mode 100644
index 0000000..b75763b
--- /dev/null
+++ b/gdb/config/ia64/hpux.mh
@@ -0,0 +1,3 @@
+# Host: ia64 running HP-UX
+NATDEPFILES= fork-child.o inf-ttrace.o corelow.o ia64-hpux-nat.o \
+        solib-ia64-hpux.o
diff --git a/gdb/configure.host b/gdb/configure.host
index ddeae32..deb542e 100644
--- a/gdb/configure.host
+++ b/gdb/configure.host
@@ -105,6 +105,7 @@ i[34567]86-*-solaris2.1[0-9]* | x86_64-*-solaris2.1[0-9]*)
 i[34567]86-*-solaris*)	gdb_host=i386sol2 ;;
 i[34567]86-*-cygwin*)	gdb_host=cygwin ;;
 
+ia64-*-hpux*)		gdb_host=hpux ;;
 ia64-*-linux*)		gdb_host=linux ;;
 
 m68*-*-linux*)		gdb_host=linux ;;
@@ -202,6 +203,11 @@ m68*-*-*)
 	gdb_host_double_format="&floatformat_ieee_double_big"
 	gdb_host_long_double_format="&floatformat_m68881_ext"
 	;;
+ia64-*-hpux*)
+	gdb_host_float_format="&floatformat_ieee_single_big"
+	gdb_host_double_format="&floatformat_ieee_double_big"
+	gdb_host_long_double_format="&floatformat_ia64_quad_big"
+        ;;
 ia64-*-linux*)
 	gdb_host_float_format="&floatformat_ieee_single_little"
 	gdb_host_double_format="&floatformat_ieee_double_little"
diff --git a/gdb/configure.tgt b/gdb/configure.tgt
index b373b81..3090688 100644
--- a/gdb/configure.tgt
+++ b/gdb/configure.tgt
@@ -257,6 +257,10 @@ i[34567]86-*-*)
 	gdb_target_obs="i386-tdep.o i387-tdep.o"
 	;;
 
+ia64-*-hpux*)
+	# Target: Intel IA-64 running HP-UX
+	gdb_target_obs="ia64-tdep.o ia64-hpux-tdep.o"
+	;;
 ia64-*-linux*)
 	# Target: Intel IA-64 running GNU/Linux
 	gdb_target_obs="ia64-tdep.o ia64-linux-tdep.o linux-tdep.o \
diff --git a/gdb/ia64-hpux-nat.c b/gdb/ia64-hpux-nat.c
new file mode 100644
index 0000000..53941a7
--- /dev/null
+++ b/gdb/ia64-hpux-nat.c
@@ -0,0 +1,641 @@
+/* Copyright (C) 2010 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#include "defs.h"
+#include "ia64-tdep.h"
+#include "inferior.h"
+#include "inf-ttrace.h"
+#include "regcache.h"
+#include "solib-ia64-hpux.h"
+
+#include <ia64/sys/uregs.h>
+#include <sys/ttrace.h>
+
+/* The offsets used with ttrace to read the value of the raw registers.  */
+
+static int u_offsets[] =
+{ /* Static General Registers.  */
+  -1,     __r1,   __r2,   __r3,   __r4,   __r5,   __r6,   __r7,
+  __r8,   __r9,   __r10,  __r11,  __r12,  __r13,  __r14,  __r15,
+  __r16,  __r17,  __r18,  __r19,  __r20,  __r21,  __r22,  __r23,
+  __r24,  __r25,  __r26,  __r27,  __r28,  __r29,  __r30,  __r31,
+  -1,     -1,     -1,     -1,     -1,     -1,     -1,     -1,
+  -1,     -1,     -1,     -1,     -1,     -1,     -1,     -1,
+  -1,     -1,     -1,     -1,     -1,     -1,     -1,     -1,
+  -1,     -1,     -1,     -1,     -1,     -1,     -1,     -1,
+  -1,     -1,     -1,     -1,     -1,     -1,     -1,     -1,
+  -1,     -1,     -1,     -1,     -1,     -1,     -1,     -1,
+  -1,     -1,     -1,     -1,     -1,     -1,     -1,     -1,
+  -1,     -1,     -1,     -1,     -1,     -1,     -1,     -1,
+  -1,     -1,     -1,     -1,     -1,     -1,     -1,     -1,
+  -1,     -1,     -1,     -1,     -1,     -1,     -1,     -1,
+  -1,     -1,     -1,     -1,     -1,     -1,     -1,     -1,
+  -1,     -1,     -1,     -1,     -1,     -1,     -1,     -1,
+
+  /* Static Floating-Point Registers.  */
+    -1,     -1,   __f2,   __f3,   __f4,   __f5,   __f6,   __f7,
+  __f8,   __f9,   __f10,  __f11,  __f12,  __f13,  __f14,  __f15,
+  __f16,  __f17,  __f18,  __f19,  __f20,  __f21,  __f22,  __f23,
+  __f24,  __f25,  __f26,  __f27,  __f28,  __f29,  __f30,  __f31,
+  __f32,  __f33,  __f34,  __f35,  __f36,  __f37,  __f38,  __f39,
+  __f40,  __f41,  __f42,  __f43,  __f44,  __f45,  __f46,  __f47,
+  __f48,  __f49,  __f50,  __f51,  __f52,  __f53,  __f54,  __f55,
+  __f56,  __f57,  __f58,  __f59,  __f60,  __f61,  __f62,  __f63,
+  __f64,  __f65,  __f66,  __f67,  __f68,  __f69,  __f70,  __f71,
+  __f72,  __f73,  __f74,  __f75,  __f76,  __f77,  __f78,  __f79,
+  __f80,  __f81,  __f82,  __f83,  __f84,  __f85,  __f86,  __f87,
+  __f88,  __f89,  __f90,  __f91,  __f92,  __f93,  __f94,  __f95,
+  __f96,  __f97,  __f98,  __f99,  __f100, __f101, __f102, __f103,
+  __f104, __f105, __f106, __f107, __f108, __f109, __f110, __f111,
+  __f112, __f113, __f114, __f115, __f116, __f117, __f118, __f119,
+  __f120, __f121, __f122, __f123, __f124, __f125, __f126, __f127,
+
+  -1,     -1,     -1,     -1,     -1,     -1,     -1,     -1,
+  -1,     -1,     -1,     -1,     -1,     -1,     -1,     -1,
+  -1,     -1,     -1,     -1,     -1,     -1,     -1,     -1,
+  -1,     -1,     -1,     -1,     -1,     -1,     -1,     -1,
+  -1,     -1,     -1,     -1,     -1,     -1,     -1,     -1,
+  -1,     -1,     -1,     -1,     -1,     -1,     -1,     -1,
+  -1,     -1,     -1,     -1,     -1,     -1,     -1,     -1,
+  -1,     -1,     -1,     -1,     -1,     -1,     -1,     -1,
+
+  /* Branch Registers.  */
+  __b0,   __b1,   __b2,   __b3,   __b4,   __b5,   __b6,   __b7,
+
+  /* Virtual frame pointer and virtual return address pointer.  */
+  -1, -1,
+
+  /* Other registers.  */
+  __pr, __ip, __cr_ipsr, __cfm,
+
+  /* Kernel registers.  */
+  -1,   -1,   -1,   -1,
+  -1,   -1,   -1,   -1,
+
+  -1, -1, -1, -1, -1, -1, -1, -1,
+
+  /* Some application registers.  */
+  __ar_rsc, __ar_bsp, __ar_bspstore, __ar_rnat,
+
+  -1,
+  -1,  /* Not available: FCR, IA32 floating control register.  */
+  -1, -1,
+
+  -1,         /* Not available: EFLAG.  */
+  -1,         /* Not available: CSD.  */
+  -1,         /* Not available: SSD.  */
+  -1,         /* Not available: CFLG.  */
+  -1,         /* Not available: FSR.  */
+  -1,         /* Not available: FIR.  */
+  -1,         /* Not available: FDR.  */
+  -1,
+  __ar_ccv, -1, -1, -1, __ar_unat, -1, -1, -1,
+  __ar_fpsr, -1, -1, -1,
+  -1,         /* Not available: ITC.  */
+  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+  -1, -1, -1, -1, -1, -1, -1, -1, -1,
+  __ar_pfs, __ar_lc, __ar_ec,
+  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+  -1
+  /* All following registers, starting with nat0, are handled as
+     pseudo registers, and hence are handled separately.  */
+};
+
+/* Some register have a fixed value and can not be modified.
+   Store their value in static constant buffers that can be used
+   later to fill the register cache.  */
+static const char r0_value[8] = {0x00, 0x00, 0x00, 0x00,
+                                 0x00, 0x00, 0x00, 0x00};
+static const char f0_value[16] = {0x00, 0x00, 0x00, 0x00,
+                                  0x00, 0x00, 0x00, 0x00,
+                                  0x00, 0x00, 0x00, 0x00,
+                                  0x00, 0x00, 0x00, 0x00};
+static const char f1_value[16] = {0x00, 0x00, 0x00, 0x00,
+                                  0x00, 0x00, 0xff, 0xff,
+                                  0x80, 0x00, 0x00, 0x00,
+                                  0x00, 0x00, 0x00, 0x00};
+
+/* The "to_wait" routine from the "inf-ttrace" layer.  */
+
+static ptid_t (*super_to_wait) (struct target_ops *, ptid_t,
+				struct target_waitstatus *, int);
+
+/* The "to_wait" target_ops routine routine for ia64-hpux.  */
+
+static ptid_t
+ia64_hpux_wait (struct target_ops *ops, ptid_t ptid,
+		struct target_waitstatus *ourstatus, int options)
+{
+  ptid_t new_ptid;
+
+  new_ptid = super_to_wait (ops, ptid, ourstatus, options);
+
+  /* If this is a DLD event (hard-coded breakpoint instruction
+     that was activated by the solib-ia64-hpux module), we need to
+     process it, and then resume the execution as if the event did
+     not happen.  */
+  if (ourstatus->kind == TARGET_WAITKIND_STOPPED
+      && ourstatus->value.sig == TARGET_SIGNAL_TRAP
+      && ia64_hpux_at_dld_breakpoint_p (new_ptid))
+    {
+      ia64_hpux_handle_dld_breakpoint (new_ptid);
+
+      target_resume (new_ptid, 0, TARGET_SIGNAL_0);
+      ourstatus->kind = TARGET_WAITKIND_IGNORE;
+    }
+
+  return new_ptid;
+}
+
+/* Fetch the RNAT register and supply it to the REGCACHE.  */
+
+static void
+ia64_hpux_fetch_rnat_register (struct regcache *regcache)
+{
+  CORE_ADDR addr;
+  gdb_byte buf[8];
+  int status;
+
+  /* The value of RNAT is stored at bsp|0x1f8, and must be read using
+     TT_LWP_RDRSEBS.  */
+
+  regcache_raw_read_unsigned (regcache, IA64_BSP_REGNUM, &addr);
+  addr |= 0x1f8;
+
+  status = ttrace (TT_LWP_RDRSEBS, ptid_get_pid (inferior_ptid),
+		   ptid_get_lwp (inferior_ptid), addr, sizeof (buf),
+		   (uintptr_t) buf);
+  if (status < 0)
+    error (_("failed to read RNAT register at 0x%lx"), addr);
+
+  regcache_raw_supply (regcache, IA64_RNAT_REGNUM, buf);
+}
+
+/* Read the value of the register saved at OFFSET in the save_state_t
+   structure, and store its value in BUF.  LEN is the size of the register
+   to be read.  */
+
+static int
+ia64_hpux_read_register_from_save_state_t (int offset, gdb_byte *buf, int len)
+{
+  int status;
+
+ status = ttrace (TT_LWP_RUREGS, ptid_get_pid (inferior_ptid),
+		  ptid_get_lwp (inferior_ptid), offset, len, (uintptr_t) buf);
+
+  return status;
+}
+
+/* Fetch register REGNUM from the inferior.  */
+
+static void
+ia64_hpux_fetch_register (struct regcache *regcache, int regnum)
+{
+  struct gdbarch *gdbarch = get_regcache_arch (regcache);
+  int offset, len, status;
+  gdb_byte *buf;
+
+  if (regnum == IA64_GR0_REGNUM)
+    {
+      /* r0 is always 0.  */
+      regcache_raw_supply (regcache, regnum, r0_value);
+      return;
+    }
+
+  if (regnum == IA64_FR0_REGNUM)
+    {
+      /* f0 is always 0.0.  */
+      regcache_raw_supply (regcache, regnum, f0_value);
+      return;
+    }
+
+  if (regnum == IA64_FR1_REGNUM)
+    {
+      /* f1 is always 1.0.  */
+      regcache_raw_supply (regcache, regnum, f1_value);
+      return;
+    }
+
+  if (regnum == IA64_RNAT_REGNUM)
+    {
+      ia64_hpux_fetch_rnat_register (regcache);
+      return;
+    }
+
+  /* Get the register location. If the register can not be fetched,
+     then return now.  */
+  offset = u_offsets[regnum];
+  if (offset == -1)
+    return;
+
+  len = register_size (gdbarch, regnum);
+  buf = alloca (len * sizeof (gdb_byte));
+  status = ia64_hpux_read_register_from_save_state_t (offset, buf, len);
+  if (status < 0)
+    warning (_("Failed to read register value for %s.\n"),
+             gdbarch_register_name (gdbarch, regnum));
+
+  regcache_raw_supply (regcache, regnum, buf);
+}
+
+/* The "to_fetch_registers" target_ops routine for ia64-hpux.  */
+
+static void
+ia64_hpux_fetch_registers (struct target_ops *ops,
+			   struct regcache *regcache, int regnum)
+{
+  if (regnum == -1)
+    for (regnum = 0;
+	 regnum < gdbarch_num_regs (get_regcache_arch (regcache));
+	 regnum++)
+      ia64_hpux_fetch_register (regcache, regnum);
+  else
+    ia64_hpux_fetch_register (regcache, regnum);
+}
+
+/* Save register REGNUM (stored in BUF) in the save_state_t structure.
+   LEN is the size of the register in bytes.
+
+   Return the value from the corresponding ttrace call (a negative value
+   means that the operation failed).  */
+
+static int
+ia64_hpux_write_register_to_saved_state_t (int offset, gdb_byte *buf, int len)
+{
+  return ttrace (TT_LWP_WUREGS, ptid_get_pid (inferior_ptid),
+		 ptid_get_lwp (inferior_ptid), offset, len, (uintptr_t) buf);
+}
+
+/* Store register REGNUM into the inferior.  */
+
+static void
+ia64_hpux_store_register (const struct regcache *regcache, int regnum)
+{
+  struct gdbarch *gdbarch = get_regcache_arch (regcache);
+  int offset = u_offsets[regnum];
+  gdb_byte *buf;
+  int len, status;
+
+  /* If the register can not be stored, then return now.  */
+  if (offset == -1)
+    return;
+
+  /* I don't know how to store that register for now.  So just ignore any
+     request to store it, to avoid an internal error.  */
+  if (regnum == IA64_PSR_REGNUM)
+    return;
+
+  len = register_size (gdbarch, regnum);
+  buf = alloca (len * sizeof (gdb_byte));
+  regcache_raw_collect (regcache, regnum, buf);
+
+  status = ia64_hpux_write_register_to_saved_state_t (offset, buf, len);
+
+  if (status < 0)
+    error (_("failed to write register value for %s.\n"),
+           gdbarch_register_name (gdbarch, regnum));
+}
+
+/* The "to_store_registers" target_ops routine for ia64-hpux.  */
+
+static void
+ia64_hpux_store_registers (struct target_ops *ops,
+			   struct regcache *regcache, int regnum)
+{
+  if (regnum == -1)
+    for (regnum = 0;
+	 regnum < gdbarch_num_regs (get_regcache_arch (regcache));
+	 regnum++)
+      ia64_hpux_store_register (regcache, regnum);
+  else
+    ia64_hpux_store_register (regcache, regnum);
+}
+
+/* The "xfer_partial" routine from the "inf-ttrace" target layer.
+   Ideally, we would like to use this routine for all transfer
+   requests, but this platforms has a lot of special cases that
+   need to be handled manually.  So we override this routine and
+   delegate back if we detect that we are not in a special case.  */
+
+static LONGEST (*super_xfer_partial) (struct target_ops *, enum target_object,
+				      const char *, gdb_byte *,
+				      const gdb_byte *, ULONGEST, LONGEST);
+
+/* The "xfer_partial" routine for a memory region that is completely
+   outside of the backing-store region.  */
+
+static LONGEST
+ia64_hpux_xfer_memory_no_bs (struct target_ops *ops, const char *annex,
+			     gdb_byte *readbuf, const gdb_byte *writebuf,
+			     CORE_ADDR addr, LONGEST len)
+{
+  /* Memory writes need to be aligned on 16byte boundaries, at least
+     when writing in the text section.  On the other hand, the size
+     of the buffer does not need to be a multiple of 16bytes.
+
+     No such restriction when performing memory reads.  */
+
+  if (writebuf && addr & 0x0f)
+    {
+      const CORE_ADDR aligned_addr = addr & ~0x0f;
+      const int aligned_len = len + (addr - aligned_addr);
+      gdb_byte *aligned_buf = alloca (aligned_len * sizeof (gdb_byte));
+      LONGEST status;
+
+      /* Read the portion of memory between ALIGNED_ADDR and ADDR, so
+         that we can write it back during our aligned memory write.  */
+      status = super_xfer_partial (ops, TARGET_OBJECT_MEMORY, annex,
+				   aligned_buf /* read */,
+				   NULL /* write */,
+				   aligned_addr, addr - aligned_addr);
+      if (status <= 0)
+	return 0;
+      memcpy (aligned_buf + (addr - aligned_addr), writebuf, len);
+
+      return super_xfer_partial (ops, TARGET_OBJECT_MEMORY, annex,
+				 NULL /* read */, aligned_buf /* write */,
+				 aligned_addr, aligned_len);
+    }
+  else
+    /* Memory read or properly aligned memory write.  */
+    return super_xfer_partial (ops, TARGET_OBJECT_MEMORY, annex, readbuf,
+			       writebuf, addr, len);
+}
+
+/* Read LEN bytes at ADDR from memory, and store it in BUF.  This memory
+   region is assumed to be inside the backing store.
+
+   Return zero if the operation failed.  */
+
+static int
+ia64_hpux_read_memory_bs (gdb_byte *buf, CORE_ADDR addr, int len)
+{
+  gdb_byte tmp_buf[8];
+  CORE_ADDR tmp_addr = addr & ~0x7;
+
+  while (tmp_addr < addr + len)
+    {
+      int status;
+      int skip_lo = 0;
+      int skip_hi = 0;
+
+      status = ttrace (TT_LWP_RDRSEBS, ptid_get_pid (inferior_ptid),
+		       ptid_get_lwp (inferior_ptid), tmp_addr,
+		       sizeof (tmp_buf), (uintptr_t) tmp_buf);
+      if (status < 0)
+        return 0;
+
+      if (tmp_addr < addr)
+        skip_lo = addr - tmp_addr;
+
+      if (tmp_addr + sizeof (tmp_buf) > addr + len)
+        skip_hi = (tmp_addr + sizeof (tmp_buf)) - (addr + len);
+
+      memcpy (buf + (tmp_addr + skip_lo - addr),
+              tmp_buf + skip_lo,
+              sizeof (tmp_buf) - skip_lo - skip_hi);
+
+      tmp_addr += sizeof (tmp_buf);
+    }
+
+  return 1;
+}
+
+/* Write LEN bytes from BUF in memory at ADDR.  This memory region is assumed
+   to be inside the backing store.
+
+   Return zero if the operation failed.  */
+
+static int
+ia64_hpux_write_memory_bs (const gdb_byte *buf, CORE_ADDR addr, int len)
+{
+  gdb_byte tmp_buf[8];
+  CORE_ADDR tmp_addr = addr & ~0x7;
+
+  while (tmp_addr < addr + len)
+    {
+      int status;
+      int lo = 0;
+      int hi = 7;
+
+      if (tmp_addr < addr || tmp_addr + sizeof (tmp_buf) > addr + len)
+	/* Part of the 8byte region pointed by tmp_addr needs to be preserved.
+	   So read it in before we copy the data that needs to be changed.  */
+	if (!ia64_hpux_read_memory_bs (tmp_buf, tmp_addr, sizeof (tmp_buf)))
+	  return 0;
+
+      if (tmp_addr < addr)
+        lo = addr - tmp_addr;
+
+      if (tmp_addr + sizeof (tmp_buf) > addr + len)
+        hi = addr - tmp_addr + len - 1;
+
+      memcpy (tmp_buf + lo, buf + tmp_addr - addr  + lo, hi - lo + 1);
+
+      status = ttrace (TT_LWP_WRRSEBS, ptid_get_pid (inferior_ptid),
+		       ptid_get_lwp (inferior_ptid), tmp_addr,
+		       sizeof (tmp_buf), (uintptr_t) tmp_buf);
+      if (status < 0)
+        return 0;
+
+      tmp_addr += sizeof (tmp_buf);
+    }
+
+  return 1;
+}
+
+/* The "xfer_partial" routine for a memory region that is completely
+   inside of the backing-store region.  */
+
+static LONGEST
+ia64_hpux_xfer_memory_bs (struct target_ops *ops, const char *annex,
+			  gdb_byte *readbuf, const gdb_byte *writebuf,
+			  CORE_ADDR addr, LONGEST len)
+{
+  int success;
+
+  if (readbuf)
+    success = ia64_hpux_read_memory_bs (readbuf, addr, len);
+  else
+    success = ia64_hpux_write_memory_bs (writebuf, addr, len);
+
+  if (success)
+    return len;
+  else
+    return 0;
+}
+
+/* The "xfer_partial" target_ops routine for ia64-hpux, in the case
+   where the requested object is TARGET_OBJECT_MEMORY.  */
+
+static LONGEST
+ia64_hpux_xfer_memory (struct target_ops *ops, const char *annex,
+		       gdb_byte *readbuf, const gdb_byte *writebuf,
+		       CORE_ADDR addr, LONGEST len)
+{
+  CORE_ADDR bsp, bspstore;
+  CORE_ADDR start_addr, short_len;
+  int status = 0;
+
+  /* The back-store region cannot be read/written by the standard memory
+     read/write operations.  So we handle the memory region piecemeal:
+       (1) and (2) The regions before and after the backing-store region,
+           which can be treated as normal memory;
+       (3) The region inside the backing-store, which needs to be
+           read/written specially.  */
+
+  regcache_raw_read_unsigned (get_current_regcache (), IA64_BSP_REGNUM, &bsp);
+  regcache_raw_read_unsigned (get_current_regcache (), IA64_BSPSTORE_REGNUM,
+                              &bspstore);
+
+  /* 1. Memory region before BSPSTORE.  */
+
+  if (addr < bspstore)
+    {
+      short_len = len;
+      if (addr + len > bspstore)
+        short_len = bspstore - addr;
+
+      status = ia64_hpux_xfer_memory_no_bs (ops, annex, readbuf, writebuf,
+					    addr, short_len);
+      if (status <= 0)
+        return 0;
+    }
+
+  /* 2. Memory region after BSP.  */
+
+  if (addr + len > bsp)
+    {
+      start_addr = addr;
+      if (start_addr < bsp)
+        start_addr = bsp;
+      short_len = len + addr - start_addr;
+
+      status = ia64_hpux_xfer_memory_no_bs
+		(ops, annex,
+		 readbuf ? readbuf + (start_addr - addr) : NULL,
+		 writebuf ? writebuf + (start_addr - addr) : NULL,
+		 start_addr, short_len);
+      if (status <= 0)
+	return 0;
+    }
+
+  /* 3. Memory region between BSPSTORE and BSP.  */
+
+  if (bspstore != bsp
+      && ((addr < bspstore && addr + len > bspstore)
+	  || (addr + len <= bsp && addr + len > bsp)))
+    {
+      start_addr = addr;
+      if (addr < bspstore)
+        start_addr = bspstore;
+      short_len = len + addr - start_addr;
+
+      if (start_addr + short_len > bsp)
+        short_len = bsp - start_addr;
+
+      gdb_assert (short_len > 0);
+
+      status = ia64_hpux_xfer_memory_bs
+		 (ops, annex,
+		  readbuf ? readbuf + (start_addr - addr) : NULL,
+		  writebuf ? writebuf + (start_addr - addr) : NULL,
+		  start_addr, short_len);
+      if (status < 0)
+	return 0;
+    }
+
+  return len;
+}
+
+/* The "to_xfer_partial" target_ops routine for ia64-hpux.  */
+
+static LONGEST
+ia64_hpux_xfer_partial (struct target_ops *ops, enum target_object object,
+			const char *annex, gdb_byte *readbuf,
+			const gdb_byte *writebuf, ULONGEST offset, LONGEST len)
+{
+  LONGEST val;
+
+  if (object == TARGET_OBJECT_MEMORY)
+    val = ia64_hpux_xfer_memory (ops, annex, readbuf, writebuf, offset, len);
+  else
+    val = super_xfer_partial (ops, object, annex, readbuf, writebuf, offset,
+			      len);
+
+  return val;
+}
+
+/* The "to_can_use_hw_breakpoint" target_ops routine for ia64-hpux.  */
+
+static int
+ia64_hpux_can_use_hw_breakpoint (int type, int cnt, int othertype)
+{
+  /* No hardware watchpoint/breakpoint support yet.  */
+  return 0;
+}
+
+/* The "to_mourn_inferior" routine from the "inf-ttrace" target_ops layer.  */
+
+static void (*super_mourn_inferior) (struct target_ops *);
+
+/* The "to_mourn_inferior" target_ops routine for ia64-hpux.  */
+
+static void
+ia64_hpux_mourn_inferior (struct target_ops *ops)
+{
+  const int pid = ptid_get_pid (inferior_ptid);
+  int status;
+
+  super_mourn_inferior (ops);
+
+  /* On this platform, the process still exists even after we received
+     an exit event.  Detaching from the process isn't sufficient either,
+     as it only turns the process into a zombie.  So the only solution
+     we found is to kill it.  */
+  ttrace (TT_PROC_EXIT, pid, 0, 0, 0, 0);
+  wait (&status);
+}
+
+/* Prevent warning from -Wmissing-prototypes.  */
+void _initialize_hppa_hpux_nat (void);
+
+void
+_initialize_hppa_hpux_nat (void)
+{
+  struct target_ops *t;
+
+  t = inf_ttrace_target ();
+  super_to_wait = t->to_wait;
+  super_xfer_partial = t->to_xfer_partial;
+  super_mourn_inferior = t->to_mourn_inferior;
+
+  t->to_wait = ia64_hpux_wait;
+  t->to_fetch_registers = ia64_hpux_fetch_registers;
+  t->to_store_registers = ia64_hpux_store_registers;
+  t->to_xfer_partial = ia64_hpux_xfer_partial;
+  t->to_can_use_hw_breakpoint = ia64_hpux_can_use_hw_breakpoint;
+  t->to_mourn_inferior = ia64_hpux_mourn_inferior;
+  t->to_attach_no_wait = 1;
+
+  add_target (t);
+}
diff --git a/gdb/ia64-hpux-tdep.c b/gdb/ia64-hpux-tdep.c
new file mode 100644
index 0000000..139ff83
--- /dev/null
+++ b/gdb/ia64-hpux-tdep.c
@@ -0,0 +1,101 @@
+/* Target-dependent code for the IA-64 for GDB, the GNU debugger.
+
+   Copyright (C) 2010 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#include "defs.h"
+#include "ia64-tdep.h"
+#include "ia64-hpux-tdep.h"
+#include "osabi.h"
+#include "gdbtypes.h"
+#include "solib.h"
+
+/* Return nonzero if the value of the register identified by REGNUM
+   can be modified.  */
+
+static int
+ia64_hpux_can_store_ar_register (int regnum)
+{
+  switch (regnum)
+    {
+      case IA64_RSC_REGNUM:
+      case IA64_RNAT_REGNUM:
+      case IA64_CSD_REGNUM:
+      case IA64_SSD_REGNUM:
+      case IA64_CCV_REGNUM:
+      case IA64_UNAT_REGNUM:
+      case IA64_FPSR_REGNUM:
+      case IA64_PFS_REGNUM:
+      case IA64_LC_REGNUM:
+      case IA64_EC_REGNUM:
+         return 1;
+         break;
+
+      default:
+         return 0;
+         break;
+    }
+}
+
+/* The "cannot_store_register" target_ops method.  */
+
+static int
+ia64_hpux_cannot_store_register (struct gdbarch *gdbarch, int regnum)
+{
+  /* General registers.  */
+
+  if (regnum == IA64_GR0_REGNUM)
+    return 1;
+
+  /* FP register.  */
+
+  if (regnum == IA64_FR0_REGNUM || regnum == IA64_FR1_REGNUM)
+    return 1;
+
+  /* Application registers.  */
+  if (regnum >= IA64_AR0_REGNUM && regnum <= IA64_AR0_REGNUM + 127)
+    return (!ia64_hpux_can_store_ar_register (regnum));
+
+  /* We can store all other registers.  */
+  return 0;
+}
+
+/* Should be set to non-NULL if the ia64-hpux solib module is linked in.
+   This may not be the case because the shared library support code can
+   only be compiled on ia64-hpux.  */
+
+struct target_so_ops *ia64_hpux_so_ops = NULL;
+
+static void
+ia64_hpux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
+{
+  set_gdbarch_long_double_format (gdbarch, floatformats_ia64_quad);
+  set_gdbarch_cannot_store_register (gdbarch, ia64_hpux_cannot_store_register);
+
+  if (ia64_hpux_so_ops)
+    set_solib_ops (gdbarch, ia64_hpux_so_ops);
+}
+
+/* Provide a prototype to silence -Wmissing-prototypes.  */
+extern initialize_file_ftype _initialize_ia64_hpux_tdep;
+
+void
+_initialize_ia64_hpux_tdep (void)
+{
+  gdbarch_register_osabi (bfd_arch_ia64, 0, GDB_OSABI_HPUX_ELF,
+			  ia64_hpux_init_abi);
+}
diff --git a/gdb/ia64-hpux-tdep.h b/gdb/ia64-hpux-tdep.h
new file mode 100644
index 0000000..9f92a21
--- /dev/null
+++ b/gdb/ia64-hpux-tdep.h
@@ -0,0 +1,24 @@
+/* Copyright (C) 2010 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#ifndef IA64_HPUX_TDEP_H
+#define IA64_HPUX_TDEP_H
+
+struct target_so_ops;
+extern struct target_so_ops *ia64_hpux_so_ops;
+
+#endif
diff --git a/gdb/solib-ia64-hpux.c b/gdb/solib-ia64-hpux.c
new file mode 100644
index 0000000..aec96be
--- /dev/null
+++ b/gdb/solib-ia64-hpux.c
@@ -0,0 +1,696 @@
+/* Copyright (C) 2010 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#include "defs.h"
+#include "ia64-tdep.h"
+#include "ia64-hpux-tdep.h"
+#include "solib-ia64-hpux.h"
+#include "solist.h"
+#include "solib.h"
+#include "target.h"
+#include "gdbtypes.h"
+#include "inferior.h"
+#include "gdbcore.h"
+#include "regcache.h"
+#include "opcode/ia64.h"
+#include "symfile.h"
+#include "objfiles.h"
+#include "elf-bfd.h"
+#include "exceptions.h"
+
+/* Need to define the following macro in order to get the complete
+   load_module_desc struct definition in dlfcn.h  Otherwise, it doesn't
+   match the size of the struct the loader is providing us during load
+   events.  */
+#define _LOAD_MODULE_DESC_EXT
+
+#include <sys/ttrace.h>
+#include <dlfcn.h>
+#include <elf.h>
+#include <service_mgr.h>
+
+/* The following is to have access to the definition of type load_info_t.  */
+#include <crt0.h>
+
+/* The r32 pseudo-register number.
+
+   Like all stacked registers, r32 is treated as a pseudo-register,
+   because it is not always available for read/write via the ttrace
+   interface.  */
+/* This is a bit of a hack, as we duplicate something hidden inside
+   ia64-tdep.c, but oh well...  */
+#define IA64_R32_PSEUDO_REGNUM (IA64_NAT127_REGNUM + 2)
+
+/* Our struct so_list private data structure.  */
+
+struct lm_info
+{
+  /* The shared library module descriptor.  We extract this structure
+     from the loader at the time the shared library gets mapped.  */
+  struct load_module_desc module_desc;
+
+  /* The text segment address as defined in the shared library object
+     (this is not the address where this segment got loaded).  This
+     field is initially set to zero, and computed lazily.  */
+  CORE_ADDR text_start;
+
+  /* The data segment address as defined in the shared library object
+     (this is not the address where this segment got loaded).  This
+     field is initially set to zero, and computed lazily.  */
+  CORE_ADDR data_start;
+};
+
+/* The list of shared libraries currently mapped by the inferior.  */
+
+static struct so_list *so_list_head = NULL;
+
+/* Create a new so_list element.  The result should be deallocated
+   when no longer in use.  */
+
+static struct so_list *
+new_so_list (char *so_name, struct load_module_desc module_desc)
+{
+  struct so_list *new_so;
+
+  new_so = (struct so_list *) XZALLOC (struct so_list);
+  new_so->lm_info = (struct lm_info *) XZALLOC (struct lm_info);
+  new_so->lm_info->module_desc = module_desc;
+
+  strncpy (new_so->so_name, so_name, SO_NAME_MAX_PATH_SIZE - 1);
+  new_so->so_name[SO_NAME_MAX_PATH_SIZE - 1] = '\0';
+  strcpy (new_so->so_original_name, new_so->so_name);
+
+  return new_so;
+}
+
+/* Return non-zero if the instruction at the current PC is a breakpoint
+   part of the dynamic loading process.
+
+   We identify such instructions by checking that the instruction at
+   the current pc is a break insn where no software breakpoint has been
+   inserted by us.  We also verify that the operands have specific
+   known values, to be extra certain.
+
+   PTID is the ptid of the thread that should be checked, but this
+   function also assumes that inferior_ptid is already equal to PTID.
+   Ideally, we would like to avoid the requirement on inferior_ptid,
+   but many routines still use the inferior_ptid global to access
+   the relevant thread's register and memory.  We still have the ptid
+   as parameter to be able to pass it to the routines that do take a ptid
+   - that way we avoid increasing explicit uses of the inferior_ptid
+   global.  */
+
+static int
+ia64_hpux_at_dld_breakpoint_1_p (ptid_t ptid)
+{
+  struct regcache *regcache = get_thread_regcache (ptid);
+  CORE_ADDR pc = regcache_read_pc (regcache);
+  struct address_space *aspace = get_regcache_aspace (regcache);
+  ia64_insn t0, t1, slot[3], template, insn;
+  int slotnum;
+  bfd_byte bundle[16];
+
+  /* If this is a regular breakpoint, then it can not be a dld one.  */
+  if (breakpoint_inserted_here_p (aspace, pc))
+    return 0;
+
+  slotnum = ((long) pc) & 0xf;
+  if (slotnum > 2)
+    internal_error (__FILE__, __LINE__,
+                    "invalid slot (%d) for address 0x%lx", slotnum, pc);
+
+  pc -= (pc & 0xf);
+  read_memory (pc, bundle, sizeof (bundle));
+
+  /* bundles are always in little-endian byte order */
+  t0 = bfd_getl64 (bundle);
+  t1 = bfd_getl64 (bundle + 8);
+  template = (t0 >> 1) & 0xf;
+  slot[0] = (t0 >>  5) & 0x1ffffffffffLL;
+  slot[1] = ((t0 >> 46) & 0x3ffff) | ((t1 & 0x7fffff) << 18);
+  slot[2] = (t1 >> 23) & 0x1ffffffffffLL;
+
+  if (template == 2 && slotnum == 1)
+    {
+      /* skip L slot in MLI template: */
+      slotnum = 2;
+    }
+
+  insn = slot[slotnum];
+
+  return (insn == 0x1c0c9c0       /* break.i 0x070327 */
+          || insn == 0x3c0c9c0);  /* break.i 0x0f0327 */
+}
+
+/* Same as ia64_hpux_at_dld_breakpoint_1_p above, with the following
+   differences: It temporarily sets inferior_ptid to PTID, and also
+   contains any exception being raised.  */
+
+int
+ia64_hpux_at_dld_breakpoint_p (ptid_t ptid)
+{
+  struct gdb_exception e;
+  ptid_t saved_ptid = inferior_ptid;
+  int result = 0;
+
+  inferior_ptid = ptid;
+  TRY_CATCH (e, RETURN_MASK_ALL)
+    {
+      result = ia64_hpux_at_dld_breakpoint_1_p (ptid);
+    }
+  inferior_ptid = saved_ptid;
+  if (e.reason < 0)
+    warning (_("error while checking for dld breakpoint: %s"), e.message);
+
+  return result;
+}
+
+/* Handler for library load event: Read the information provided by
+   the loader, and then use it to read the shared library symbols.  */
+
+static void
+ia64_hpux_handle_load_event (struct regcache *regcache)
+{
+  CORE_ADDR module_desc_addr;
+  ULONGEST module_desc_size;
+  CORE_ADDR so_path_addr;
+  char so_path[MAXPATHLEN];
+  struct load_module_desc module_desc;
+  struct so_list *new_so;
+
+  /* Extract the data provided by the loader as follow:
+       - r33: Address of load_module_desc structure
+       - r34: size of struct load_module_desc
+       - r35: Address of string holding shared library path
+   */
+  regcache_cooked_read_unsigned (regcache, IA64_R32_PSEUDO_REGNUM + 1,
+                                 &module_desc_addr);
+  regcache_cooked_read_unsigned (regcache, IA64_R32_PSEUDO_REGNUM + 2,
+                                 &module_desc_size);
+  regcache_cooked_read_unsigned (regcache, IA64_R32_PSEUDO_REGNUM + 3,
+                                 &so_path_addr);
+
+  if (module_desc_size != sizeof (struct load_module_desc))
+    warning ("load_module_desc size (%ld) != size returned by kernel (%ld)",
+             sizeof (struct load_module_desc), module_desc_size);
+
+  read_memory_string (so_path_addr, so_path, MAXPATHLEN);
+  read_memory (module_desc_addr, (gdb_byte *) &module_desc,
+	       sizeof (module_desc));
+
+  /* Create a new so_list element and insert it at the start of our
+     so_list_head (we insert at the start of the list only because
+     it is less work compared to inserting it elsewhere).  */
+  new_so = new_so_list (so_path, module_desc);
+  new_so->next = so_list_head;
+  so_list_head = new_so;
+}
+
+/* Update the value of the PC to point to the begining of the next
+   instruction bundle.  */
+
+static void
+ia64_hpux_move_pc_to_next_bundle (struct regcache *regcache)
+{
+  CORE_ADDR pc = regcache_read_pc (regcache);
+
+  pc -= pc & 0xf;
+  pc += 16;
+  ia64_write_pc (regcache, pc);
+}
+
+/* Handle loader events.
+
+   PTID is the ptid of the thread corresponding to the event being
+   handled.  Similarly to ia64_hpux_at_dld_breakpoint_1_p, this
+   function assumes that inferior_ptid is set to PTID.  */
+
+static void
+ia64_hpux_handle_dld_breakpoint_1 (ptid_t ptid)
+{
+  struct regcache *regcache = get_thread_regcache (ptid);
+  ULONGEST arg0;
+
+  /* The type of event is provided by the loaded via r32.  */
+  regcache_cooked_read_unsigned (regcache, IA64_R32_PSEUDO_REGNUM, &arg0);
+  switch (arg0)
+    {
+      case BREAK_DE_SVC_LOADED:
+	/* Currently, the only service loads are uld and dld,
+	   so we shouldn't need to do anything.  Just ignore.  */
+	break;
+      case BREAK_DE_LIB_LOADED:
+	ia64_hpux_handle_load_event (regcache);
+	solib_add (NULL, 0, &current_target, auto_solib_add);
+	break;
+      case BREAK_DE_LIB_UNLOADED:
+      case BREAK_DE_LOAD_COMPLETE:
+      case BREAK_DE_BOR:
+	/* Ignore for now.  */
+	break;
+    }
+
+  /* Now that we have handled the event, we can move the PC to
+     the next instruction bundle, past the break instruction.  */
+  ia64_hpux_move_pc_to_next_bundle (regcache);
+}
+
+/* Same as ia64_hpux_handle_dld_breakpoint_1 above, with the following
+   differences: This function temporarily sets inferior_ptid to PTID,
+   and also contains any exception.  */
+
+void
+ia64_hpux_handle_dld_breakpoint (ptid_t ptid)
+{
+  struct gdb_exception e;
+  ptid_t saved_ptid = inferior_ptid;
+
+  inferior_ptid = ptid;
+  TRY_CATCH (e, RETURN_MASK_ALL)
+    {
+      ia64_hpux_handle_dld_breakpoint_1 (ptid);
+    }
+  inferior_ptid = saved_ptid;
+  if (e.reason < 0)
+    warning (_("error detected while handling dld breakpoint: %s"), e.message);
+}
+
+/* Find the address of the code and data segments in ABFD, and update
+   TEXT_START and DATA_START accordingly.  */
+
+static void
+ia64_hpux_find_start_vma (bfd *abfd, CORE_ADDR *text_start,
+                          CORE_ADDR *data_start)
+{
+  Elf_Internal_Ehdr *i_ehdrp = elf_elfheader (abfd);
+  Elf64_Phdr phdr;
+  int i;
+
+  *text_start = 0;
+  *data_start = 0;
+
+  if (bfd_seek (abfd, i_ehdrp->e_phoff, SEEK_SET) == -1)
+    error (_("invalid program header offset in %s"), abfd->filename);
+
+  for (i = 0; i < i_ehdrp->e_phnum; i++)
+    {
+      if (bfd_bread ((PTR) & phdr, sizeof (phdr), abfd) != sizeof (phdr))
+        error (_("failed to read segment %d in %s"), i, abfd->filename);
+
+      if (phdr.p_flags & PF_X
+          && (*text_start == 0 || phdr.p_vaddr < *text_start))
+        *text_start = phdr.p_vaddr;
+
+      if (phdr.p_flags & PF_W
+          && (*data_start == 0 || phdr.p_vaddr < *data_start))
+        *data_start = phdr.p_vaddr;
+    }
+}
+
+/* The "relocate_section_addresses" target_so_ops routine for ia64-hpux.  */
+
+static void
+ia64_hpux_relocate_section_addresses (struct so_list *so,
+				      struct target_section *sec)
+{
+  CORE_ADDR offset = 0;
+
+  /* If we haven't computed the text & data segment addresses, do so now.
+     We do this here, because we now have direct access to the associated
+     bfd, whereas we would have had to open our own if we wanted to do it
+     while processing the library-load event.  */
+  if (so->lm_info->text_start == 0 && so->lm_info->data_start == 0)
+    ia64_hpux_find_start_vma (sec->bfd, &so->lm_info->text_start,
+			      &so->lm_info->data_start);
+
+  /* Determine the relocation offset based on which segment
+     the section belongs to.  */
+  if ((so->lm_info->text_start < so->lm_info->data_start
+       && sec->addr < so->lm_info->data_start)
+      || (so->lm_info->text_start > so->lm_info->data_start
+          && sec->addr >= so->lm_info->text_start))
+    offset = so->lm_info->module_desc.text_base - so->lm_info->text_start;
+  else if ((so->lm_info->text_start < so->lm_info->data_start
+            && sec->addr >= so->lm_info->data_start)
+           || (so->lm_info->text_start > so->lm_info->data_start
+	       && sec->addr < so->lm_info->text_start))
+    offset = so->lm_info->module_desc.data_base - so->lm_info->data_start;
+
+  /* And now apply the relocation.  */
+  sec->addr += offset;
+  sec->endaddr += offset;
+
+  /* Best effort to set addr_high/addr_low.  This is used only by
+     'info sharedlibrary'.  */
+  if (so->addr_low == 0 || sec->addr < so->addr_low)
+    so->addr_low = sec->addr;
+
+  if (so->addr_high == 0 || sec->endaddr > so->addr_high)
+    so->addr_high = sec->endaddr;
+}
+
+/* The "free_so" target_so_ops routine for ia64-hpux.  */
+
+static void
+ia64_hpux_free_so (struct so_list *so)
+{
+  xfree (so->lm_info);
+}
+
+/* The "clear_solib" target_so_ops routine for ia64-hpux.  */
+
+static void
+ia64_hpux_clear_solib (void)
+{
+  struct so_list *so;
+
+  while (so_list_head != NULL)
+    {
+      so = so_list_head;
+      so_list_head = so_list_head->next;
+
+      ia64_hpux_free_so (so);
+      xfree (so);
+    }
+}
+
+/* Assuming the inferior just stopped on an EXEC event, return
+   the address of the load_info_t structure.  */
+
+static CORE_ADDR
+ia64_hpux_get_load_info_addr (void)
+{
+  struct type *data_ptr_type = builtin_type (target_gdbarch)->builtin_data_ptr;
+  CORE_ADDR addr;
+  int status;
+
+  /* The address of the load_info_t structure is stored in the 4th
+     argument passed to the initial thread of the process (in other
+     words, in argv[3]).  So get the address of these arguments,
+     and extract the 4th one.  */
+  status = ttrace (TT_PROC_GET_ARGS, ptid_get_pid (inferior_ptid),
+		   0, (uintptr_t) &addr, sizeof (CORE_ADDR), 0);
+  if (status == -1 && errno)
+    perror_with_name (_("Unable to get argument list"));
+  return (read_memory_typed_address (addr + 3 * 8, data_ptr_type));
+}
+
+/* A structure used to aggregate some information extracted from
+   the dynamic section of the main executable.  */
+
+struct dld_info
+{
+  long long dld_flags;
+  CORE_ADDR load_map;
+};
+
+/* Scan the ".dynamic" section referenced by ABFD and DYN_SECT,
+   and extract the information needed to fill in INFO.  */
+
+static void
+ia64_hpux_read_dynamic_info (bfd *abfd, asection *dyn_sect,
+			     struct dld_info *info)
+{
+  int sect_size;
+  char *buf;
+  char *buf_end;
+
+  /* Make sure that info always has initialized data, even if we fail
+     to read the syn_sect section.  */
+  memset (info, 0, sizeof (struct dld_info));
+
+  sect_size = bfd_section_size (abfd, dyn_sect);
+  buf = alloca (sect_size);
+  buf_end = buf + sect_size;
+
+  if (bfd_seek (abfd, dyn_sect->filepos, SEEK_SET) != 0
+      || bfd_bread (buf, sect_size, abfd) != sect_size)
+    error (_("failed to read contents of .dynamic section"));
+
+  for (; buf < buf_end; buf += sizeof (Elf64_Dyn))
+    {
+      Elf64_Dyn *dynp = (Elf64_Dyn *) buf;
+      Elf64_Sxword d_tag;
+
+      d_tag = bfd_h_get_64 (abfd, &dynp->d_tag);
+      switch (d_tag)
+        {
+          case DT_HP_DLD_FLAGS:
+            info->dld_flags = bfd_h_get_64 (abfd, &dynp->d_un);
+            break;
+
+          case DT_HP_LOAD_MAP:
+            {
+              CORE_ADDR load_map_addr = bfd_h_get_64 (abfd, &dynp->d_un.d_ptr);
+
+              if (target_read_memory (load_map_addr, (char *) &info->load_map,
+                                      sizeof (info->load_map)) != 0)
+                error (_("failed to read load map at 0x%lx"), load_map_addr);
+            }
+            break;
+        }
+    }
+}
+
+/* Wrapper around target_read_memory used with libdl.  */
+
+static void *
+ia64_hpux_read_tgt_mem (void *buffer, uint64_t ptr, size_t bufsiz, int ident)
+{
+  if (target_read_memory (ptr, (gdb_byte *) buffer, bufsiz) != 0)
+    return 0;
+  else
+    return buffer;
+}
+
+/* Create a new so_list object for a shared library, and store that
+   new so_list object in our SO_LIST_HEAD list.
+
+   SO_INDEX is an index specifying the placement of the loaded shared
+   library in the dynamic loader's search list.  Normally, this index
+   is strictly positive, but an index of -1 refers to the loader itself.
+
+   Return nonzero if the so_list object could be created.  A null
+   return value with a positive SO_INDEX normally means that there are
+   no more entries in the dynamic loader's search list at SO_INDEX or
+   beyond.  */
+
+static int
+ia64_hpux_add_so_from_dld_info (struct dld_info info, int so_index)
+{
+  struct load_module_desc module_desc;
+  uint64_t so_handle;
+  char *so_path;
+  struct so_list *so;
+
+  so_handle = dlgetmodinfo (so_index, &module_desc, sizeof (module_desc),
+			    ia64_hpux_read_tgt_mem, 0, info.load_map);
+
+  if (so_handle == 0)
+    /* No such entry.  We probably reached the end of the list.  */
+    return 0;
+
+  so_path = dlgetname (&module_desc, sizeof (module_desc),
+                       ia64_hpux_read_tgt_mem, 0, info.load_map);
+  if (so_path == NULL)
+    {
+      /* Should never happen, but let's not crash if it does.  */
+      warning ("unable to get shared library name, symbols not loaded");
+      return 0;
+    }
+
+  /* Create a new so_list and insert it at the start of our list.
+     The order is not extremely important, but it's less work to do so
+     at the end of the list.  */
+  so = new_so_list (so_path, module_desc);
+  so->next = so_list_head;
+  so_list_head = so;
+
+  return 1;
+}
+
+/* Assuming we just attached to a process, update our list of shared
+   libraries (SO_LIST_HEAD) as well as GDB's list.  */
+
+static void
+ia64_hpux_solib_add_after_attach (void)
+{
+  bfd *abfd;
+  asection *dyn_sect;
+  struct dld_info info;
+  int i;
+
+  if (symfile_objfile == NULL)
+    return;
+
+  abfd = symfile_objfile->obfd;
+  dyn_sect = bfd_get_section_by_name (abfd, ".dynamic");
+
+  if (dyn_sect == NULL || bfd_section_size (abfd, dyn_sect) == 0)
+    return;
+
+  ia64_hpux_read_dynamic_info (abfd, dyn_sect, &info);
+
+  if ((info.dld_flags & DT_HP_DEBUG_PRIVATE) == 0)
+    {
+      warning (_(
+"The shared libraries were not privately mapped; setting a breakpoint\n\
+in a shared library will not work until you rerun the program.\n\
+Use the following command to enable debugging of shared libraries.\n\
+chatr +dbg enable a.out"));
+    }
+
+  /* Read the symbols of the dynamic loader (dld.so).  */
+  ia64_hpux_add_so_from_dld_info (info, -1);
+
+  /* Read the symbols of all the other shared libraries.  */
+  for (i = 1; ; i++)
+    if (!ia64_hpux_add_so_from_dld_info (info, i))
+      break;  /* End of list.  */
+
+  /* Resync the library list at the core level.  */
+  solib_add (NULL, 1, &current_target, auto_solib_add);
+}
+
+/* The "create_inferior_hook" target_so_ops routine for ia64-hpux.  */
+
+static void
+ia64_hpux_solib_create_inferior_hook (int from_tty)
+{
+  CORE_ADDR load_info_addr;
+  load_info_t load_info;
+
+  /* Initially, we were thinking about adding a check that the program
+     (accessible through symfile_objfile) was linked against some shared
+     libraries, by searching for a ".dynamic" section.  However, could
+     this break in the case of a statically linked program that later
+     uses dlopen?  Programs that are fully statically linked are very
+     rare, and we will worry about them when we encounter one that
+     causes trouble.  */
+
+  /* Set the LI_TRACE flag in the load_info_t structure.  This enables
+     notifications when shared libraries are being mapped.  */
+  load_info_addr = ia64_hpux_get_load_info_addr ();
+  read_memory (load_info_addr, (gdb_byte *) &load_info, sizeof (load_info));
+  load_info.li_flags |= LI_TRACE;
+  write_memory (load_info_addr, (gdb_byte *) &load_info, sizeof (load_info));
+
+  /* If we just attached to our process, some shard libraries have
+     already been mapped.  Find which ones they are...  */
+  if (current_inferior ()->attach_flag)
+    ia64_hpux_solib_add_after_attach ();
+}
+
+/* The "special_symbol_handling" target_so_ops routine for ia64-hpux.  */
+
+static void
+ia64_hpux_special_symbol_handling (void)
+{
+  /* Nothing to do.  */
+}
+
+/* The "current_sos" target_so_ops routine for ia64-hpux.  */
+
+static struct so_list *
+ia64_hpux_current_sos (void)
+{
+  /* Return a deep copy of our own list.  */
+  struct so_list *new_head = NULL, *prev_new_so = NULL;
+  struct so_list *our_so;
+
+  for (our_so = so_list_head; our_so != NULL; our_so = our_so->next)
+    {
+      struct so_list *new_so;
+
+      new_so = new_so_list (our_so->so_name, our_so->lm_info->module_desc);
+      if (prev_new_so != NULL)
+        prev_new_so->next = new_so;
+      prev_new_so = new_so;
+      if (new_head == NULL)
+        new_head = new_so;
+    }
+
+  return new_head;
+}
+
+/* The "open_symbol_file_object" target_so_ops routine for ia64-hpux.  */
+
+static int
+ia64_hpux_open_symbol_file_object (void *from_ttyp)
+{
+  return 0;
+}
+
+/* The "in_dynsym_resolve_code" target_so_ops routine for ia64-hpux.  */
+
+static int
+ia64_hpux_in_dynsym_resolve_code (CORE_ADDR pc)
+{
+  return 0;
+}
+
+/* If FADDR is the address of a function inside one of the shared
+   libraries, return the shared library linkage address.  */
+
+CORE_ADDR
+ia64_hpux_get_solib_linkage_addr (CORE_ADDR faddr)
+{
+  struct so_list *so = so_list_head;
+
+  while (so != NULL)
+    {
+      struct load_module_desc module_desc = so->lm_info->module_desc;
+
+      if (module_desc.text_base <= faddr
+          && (module_desc.text_base + module_desc.text_size) > faddr)
+        return module_desc.linkage_ptr;
+
+      so = so->next;
+    }
+
+  return 0;
+}
+
+/* Create a new target_so_ops structure suitable for ia64-hpux, and
+   return its address.  */
+
+static struct target_so_ops *
+ia64_hpux_target_so_ops (void)
+{
+  struct target_so_ops *ops = XZALLOC (struct target_so_ops);
+
+  ops->relocate_section_addresses = ia64_hpux_relocate_section_addresses;
+  ops->free_so = ia64_hpux_free_so;
+  ops->clear_solib = ia64_hpux_clear_solib;
+  ops->solib_create_inferior_hook = ia64_hpux_solib_create_inferior_hook;
+  ops->special_symbol_handling = ia64_hpux_special_symbol_handling;
+  ops->current_sos = ia64_hpux_current_sos;
+  ops->open_symbol_file_object = ia64_hpux_open_symbol_file_object;
+  ops->in_dynsym_resolve_code = ia64_hpux_in_dynsym_resolve_code;
+  ops->bfd_open = solib_bfd_open;
+
+  return ops;
+}
+
+/* Prevent warning from -Wmissing-prototypes.  */
+void _initialize_solib_ia64_hpux (void);
+
+void
+_initialize_solib_ia64_hpux (void)
+{
+  ia64_hpux_so_ops = ia64_hpux_target_so_ops ();
+}
diff --git a/gdb/solib-ia64-hpux.h b/gdb/solib-ia64-hpux.h
new file mode 100644
index 0000000..11b1a90
--- /dev/null
+++ b/gdb/solib-ia64-hpux.h
@@ -0,0 +1,25 @@
+/* Copyright (C) 2010 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#ifndef SOLIB_IA64_HPUX_H
+#define SOLIB_IA64_HPUX_H
+
+int ia64_hpux_at_dld_breakpoint_p (ptid_t ptid);
+void ia64_hpux_handle_dld_breakpoint (ptid_t ptid);
+CORE_ADDR ia64_hpux_get_solib_linkage_addr (CORE_ADDR faddr);
+
+#endif
-- 
1.7.1

^ permalink raw reply	[flat|nested] 31+ messages in thread

* [PATCH 3/8] Make sure __LITTLE_ENDIAN/__BIG_ENDIAN are defined in libunwind-frame.c
  2010-12-28  4:43 Porting GDB to ia64-hpux Joel Brobecker
                   ` (3 preceding siblings ...)
  2010-12-28  4:44 ` [PATCH 6/8] port GDB to ia64-hpux (native) Joel Brobecker
@ 2010-12-28  4:44 ` Joel Brobecker
  2010-12-28  4:44 ` [PATCH 5/8] inf-ttrace: Determine attached process LWP immediately after attaching Joel Brobecker
                   ` (3 subsequent siblings)
  8 siblings, 0 replies; 31+ messages in thread
From: Joel Brobecker @ 2010-12-28  4:44 UTC (permalink / raw)
  To: gdb-patches; +Cc: Joel Brobecker

These macros do not seem to exist on ia64-hpux.

gdb/ChangeLog:

        * libunwind-frame.c (__LITTLE_ENDIAN, __BIG_ENDIAN): Define if
        not already defined.
---
 gdb/libunwind-frame.c |   10 ++++++++++
 1 files changed, 10 insertions(+), 0 deletions(-)

diff --git a/gdb/libunwind-frame.c b/gdb/libunwind-frame.c
index ece93bd..dc28064 100644
--- a/gdb/libunwind-frame.c
+++ b/gdb/libunwind-frame.c
@@ -41,6 +41,16 @@
 
 #include "complaints.h"
 
+/* The following two macros are normally defined in <endian.h>.
+   But systems such as ia64-hpux do not provide such header, so
+   we just define them here if not already defined.  */
+#ifndef __LITTLE_ENDIAN
+#define __LITTLE_ENDIAN 1234
+#endif
+#ifndef __BIG_ENDIAN
+#define __BIG_ENDIAN    4321
+#endif
+
 static int libunwind_initialized;
 static struct gdbarch_data *libunwind_descr_handle;
 
-- 
1.7.1

^ permalink raw reply	[flat|nested] 31+ messages in thread

* [PATCH 5/8] inf-ttrace: Determine attached process LWP immediately after attaching.
  2010-12-28  4:43 Porting GDB to ia64-hpux Joel Brobecker
                   ` (4 preceding siblings ...)
  2010-12-28  4:44 ` [PATCH 3/8] Make sure __LITTLE_ENDIAN/__BIG_ENDIAN are defined in libunwind-frame.c Joel Brobecker
@ 2010-12-28  4:44 ` Joel Brobecker
  2010-12-28 11:04   ` Pedro Alves
  2010-12-28  4:54 ` [PATCH 7/8] ia64-hpux: unwinding bsp value from system call Joel Brobecker
                   ` (2 subsequent siblings)
  8 siblings, 1 reply; 31+ messages in thread
From: Joel Brobecker @ 2010-12-28  4:44 UTC (permalink / raw)
  To: gdb-patches; +Cc: Joel Brobecker

When attaching to a process, the ttrace interface was creating a ptid
with a null LWP, because it did not have it yet.  This LWP was then
set as soon as we received our first event from our inferior, during
our first wait.  Similarly, the allocation of the thread private info
was also defered.

This works on PA/HP-UX, because we immediately perform a wait to pop
the event triggered by the attach.  We can use that event to extract
the thread's LWP.  But this does not work for IA64/HP-UX, because
the attach no longer triggers an event, and thus a wait should NOT
be performed (such a wait would simply block indefinitely).

It is actually possible, however, to determine the thread's LWP.
This change therefore adjusts the attach code to create a thread with
the correct LWP set, as well as with its private info allocated.
Same thing for all the other threads.

gdb/ChangeLog:

        [ttrace] Compute thread list immediately after attach.
        * inf_ttrace_attach (inf_ttrace_create_threads_after_attach):
        New subprogram.
        (inf_ttrace_attach): Use it.

---
 gdb/inf-ttrace.c |   53 ++++++++++++++++++++++++++++++++++++++++++++++++-----
 1 files changed, 48 insertions(+), 5 deletions(-)

diff --git a/gdb/inf-ttrace.c b/gdb/inf-ttrace.c
index fd394c6..24dc0f9 100644
--- a/gdb/inf-ttrace.c
+++ b/gdb/inf-ttrace.c
@@ -688,6 +688,53 @@ inf_ttrace_mourn_inferior (struct target_ops *ops)
   generic_mourn_inferior ();
 }
 
+/* Assuming we just attached the debugger to a new inferior, create
+   a new thread_info structure for each thread, and add it to our
+   list of threads.  */
+
+static void
+inf_ttrace_create_threads_after_attach (int pid)
+{
+  int status;
+  ptid_t ptid;
+  ttstate_t tts;
+  struct thread_info *ti;
+
+  status = ttrace (TT_PROC_GET_FIRST_LWP_STATE, pid, 0,
+		   (uintptr_t) &tts, sizeof (ttstate_t), 0);
+  if (status < 0)
+    perror_with_name (_("TT_PROC_GET_FIRST_LWP_STATE ttrace call failed"));
+  gdb_assert (tts.tts_pid == pid);
+
+  /* Add the stopped thread.  */
+  ptid = ptid_build (pid, tts.tts_lwpid, 0);
+  ti = add_thread (ptid);
+  ti->private = xzalloc (sizeof (struct inf_ttrace_private_thread_info));
+  inf_ttrace_num_lwps++;
+
+  /* We use the "first stopped thread" as the currently active thread.  */
+  inferior_ptid = ptid;
+
+  /* Iterative over all the remaining threads.  */
+
+  for (;;)
+    {
+      ptid_t ptid;
+
+      status = ttrace (TT_PROC_GET_NEXT_LWP_STATE, pid, 0,
+		       (uintptr_t) &tts, sizeof (ttstate_t), 0);
+      if (status < 0)
+	perror_with_name (_("TT_PROC_GET_NEXT_LWP_STATE ttrace call failed"));
+      if (status == 0)
+        break;  /* End of list.  */
+
+      ptid = ptid_build (tts.tts_pid, tts.tts_lwpid, 0);
+      ti = add_thread (ptid);
+      ti->private = xzalloc (sizeof (struct inf_ttrace_private_thread_info));
+      inf_ttrace_num_lwps++;
+    }
+}
+
 static void
 inf_ttrace_attach (struct target_ops *ops, char *args, int from_tty)
 {
@@ -740,11 +787,7 @@ inf_ttrace_attach (struct target_ops *ops, char *args, int from_tty)
 
   push_target (ops);
 
-  /* We'll bump inf_ttrace_num_lwps up and add the private data to the
-     thread as soon as we get to inf_ttrace_wait.  At this point, we
-     don't have lwpid info yet.  */
-  inferior_ptid = pid_to_ptid (pid);
-  add_thread_silent (inferior_ptid);
+  inf_ttrace_create_threads_after_attach (pid);
 }
 
 static void
-- 
1.7.1

^ permalink raw reply	[flat|nested] 31+ messages in thread

* [PATCH 7/8] ia64-hpux: unwinding bsp value from system call
  2010-12-28  4:43 Porting GDB to ia64-hpux Joel Brobecker
                   ` (5 preceding siblings ...)
  2010-12-28  4:44 ` [PATCH 5/8] inf-ttrace: Determine attached process LWP immediately after attaching Joel Brobecker
@ 2010-12-28  4:54 ` Joel Brobecker
  2010-12-28 11:35   ` Pedro Alves
  2010-12-28  5:00 ` [PATCH 8/8] [ia64-hpux] inferior function call support Joel Brobecker
  2011-01-13 16:53 ` Porting GDB to ia64-hpux Joel Brobecker
  8 siblings, 1 reply; 31+ messages in thread
From: Joel Brobecker @ 2010-12-28  4:54 UTC (permalink / raw)
  To: gdb-patches; +Cc: Joel Brobecker

This fixes unwinding from a thread that is stopped inside a system call.
This can be seen when switching to a thread that is stopped doing a
pthread_cond_wait, for instance...

The comments inside the code should explain what is happening in our
case (the HP-UX exception in the case of system calls): Under certain
circumstances (program stopped inside syscall), the offset to apply to
the current BSP in order to compute the previous BSP is not the usual
CFM & 0x7f.

We parts in this patch:

  1. Figuring out that we are stopped inside a syscal: This requires
     a ttrace call, which is not directly possible from ia64-tdep.c.
     So we get the info using a target-read of a TARGET_OBJECT_OSDATA
     object (with the annex set to "ia64.hpux.in_syscall").

  2. Add a gdbarch_tdep method that allows us to change the default
     behavior on ia64-hpux, permitting us to have a different "size of
     register frame" in that one particular case.

gdb/ChangeLog:

        * ia64-tdep.h (struct frame_info): forward declaration.
        (struct gdbarch_tdep): Add field size_of_register_frame.
        * ia64-tdep.c (ia64_access_reg): Use tdep->size_of_register_frame
        to determine the size of the register frame.
        (ia64_size_of_register_frame): New function.
        (ia64_gdbarch_init): Set tdep->size_of_register_frame.
        * ia64-hpux-tdep.c: Include "target.h".
        (ia64_hpux_stopped_in_syscall, ia64_hpux_size_of_register_frame):
        New functions.
        (ia64_hpux_init_abi): Set tdep->size_of_register_frame.
        * ia64-hpux-nat.c (ia64_hpux_xfer_in_syscall): New function.
        (ia64_hpux_xfer_os_data): New function.
        (ia64_hpux_xfer_partial): Add handling of TARGET_OBJECT_OSDATA objects.

---
 gdb/ia64-hpux-nat.c  |   56 ++++++++++++++++++++++++++++++++++++++++++++++++++
 gdb/ia64-hpux-tdep.c |   47 +++++++++++++++++++++++++++++++++++++++++
 gdb/ia64-tdep.c      |   14 ++++++++++-
 gdb/ia64-tdep.h      |    9 ++++++++
 4 files changed, 124 insertions(+), 2 deletions(-)

diff --git a/gdb/ia64-hpux-nat.c b/gdb/ia64-hpux-nat.c
index 53941a7..dfa6b7f 100644
--- a/gdb/ia64-hpux-nat.c
+++ b/gdb/ia64-hpux-nat.c
@@ -567,6 +567,60 @@ ia64_hpux_xfer_memory (struct target_ops *ops, const char *annex,
   return len;
 }
 
+/* Handle the transfer of the "ia64.hpux.in_syscall" TARGET_OBJECT_OSDATA
+   object.  */
+
+static LONGEST
+ia64_hpux_xfer_in_syscall (struct target_ops *ops, gdb_byte *readbuf,
+			   LONGEST len)
+{
+  struct gdbarch *gdbarch = target_gdbarch;
+  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+  gdb_byte buf[8];
+  int status;
+
+  gdb_assert (len > 0); /* We need 1 byte to write the return value.  */
+
+  status = ia64_hpux_read_register_from_save_state_t (__reason, buf, 8);
+  if (status < 0)
+    {
+      /* This should never happen, but if it does, just warn the user
+	 and return -1 (we don't know).  The caller should be able to
+	 handle this condition.  */
+      warning (_("failed to read reason pseudo-register"));
+      return -1;
+    }
+
+  readbuf[0] = (extract_unsigned_integer (buf, 8, byte_order) == 0);
+  return 1;
+}
+
+/* Handle the transfer of TARGET_OBJECT_OSDATA objects on ia64-hpux.
+
+   The type of data being requested depends on the value of ANNEX:
+
+     * "ia64.hpux.in_syscall":
+       Store a 1-byte integer in READBUF.  The value of that integer
+       is nonzero iff the inferior is stopped inside a system call.
+       OFFSET is ignored.
+
+   Any other request is deferred to super_xfer_partial.
+   ANNEX is assumed to never be NULL.  */
+
+static LONGEST
+ia64_hpux_xfer_os_data (struct target_ops *ops, const char *annex,
+			gdb_byte *readbuf, ULONGEST offset, LONGEST len)
+{
+  gdb_assert (annex != NULL);
+
+  if (strcmp (annex, "ia64.hpux.in_syscall") == 0)
+    return ia64_hpux_xfer_in_syscall (ops, readbuf, len);
+  else
+    /* Unknown OSDATA request, delegate to super_xfer_partial.  */
+    return super_xfer_partial (ops, TARGET_OBJECT_OSDATA, annex, readbuf,
+                               NULL, offset, len);
+}
+
 /* The "to_xfer_partial" target_ops routine for ia64-hpux.  */
 
 static LONGEST
@@ -578,6 +632,8 @@ ia64_hpux_xfer_partial (struct target_ops *ops, enum target_object object,
 
   if (object == TARGET_OBJECT_MEMORY)
     val = ia64_hpux_xfer_memory (ops, annex, readbuf, writebuf, offset, len);
+  else if (readbuf && object == TARGET_OBJECT_OSDATA && annex)
+    val = ia64_hpux_xfer_os_data (ops, annex, readbuf, offset, len);
   else
     val = super_xfer_partial (ops, object, annex, readbuf, writebuf, offset,
 			      len);
diff --git a/gdb/ia64-hpux-tdep.c b/gdb/ia64-hpux-tdep.c
index 139ff83..5dd0a4e 100644
--- a/gdb/ia64-hpux-tdep.c
+++ b/gdb/ia64-hpux-tdep.c
@@ -23,6 +23,8 @@
 #include "osabi.h"
 #include "gdbtypes.h"
 #include "solib.h"
+#include "target.h"
+#include "frame.h"
 
 /* Return nonzero if the value of the register identified by REGNUM
    can be modified.  */
@@ -74,6 +76,47 @@ ia64_hpux_cannot_store_register (struct gdbarch *gdbarch, int regnum)
   return 0;
 }
 
+/* Return nonzero if the inferior is stopped inside a system call.  */
+
+static int
+ia64_hpux_stopped_in_syscall (struct gdbarch *gdbarch)
+{
+  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+  struct target_ops *ops = &current_target;
+  gdb_byte buf[1];
+  int len;
+
+  len = target_read (ops, TARGET_OBJECT_OSDATA, "ia64.hpux.in_syscall",
+		     buf, 0, sizeof (buf));
+  if (len == -1)
+    /* The target wasn't able to tell us.  Assume we are not stopped
+       in a system call, which is the normal situation.  */
+    return 0;
+  gdb_assert (len == 1);
+
+  return extract_unsigned_integer (buf, len, byte_order);
+}
+
+/* The "size_of_register_frame" gdbarch_tdep routine for ia64-hpux.  */
+
+static int
+ia64_hpux_size_of_register_frame (struct frame_info *this_frame,
+				  ULONGEST cfm)
+{
+  int sof;
+
+  if (frame_relative_level (this_frame) == 0
+      && ia64_hpux_stopped_in_syscall (get_frame_arch (this_frame)))
+    /* If the inferior stopped in a system call, the base address
+       of the register frame is at BSP - SOL instead of BSP - SOF.
+       This is an HP-UX exception.  */
+    sof = (cfm & 0x3f80) >> 7;
+  else
+    sof = (cfm & 0x7f);
+
+  return sof;
+}
+
 /* Should be set to non-NULL if the ia64-hpux solib module is linked in.
    This may not be the case because the shared library support code can
    only be compiled on ia64-hpux.  */
@@ -83,6 +126,10 @@ struct target_so_ops *ia64_hpux_so_ops = NULL;
 static void
 ia64_hpux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
 {
+  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+
+  tdep->size_of_register_frame = ia64_hpux_size_of_register_frame;
+
   set_gdbarch_long_double_format (gdbarch, floatformats_ia64_quad);
   set_gdbarch_cannot_store_register (gdbarch, ia64_hpux_cannot_store_register);
 
diff --git a/gdb/ia64-tdep.c b/gdb/ia64-tdep.c
index 1cd6a38..1cfffc7 100644
--- a/gdb/ia64-tdep.c
+++ b/gdb/ia64-tdep.c
@@ -2423,7 +2423,7 @@ ia64_is_fpreg (int uw_regnum)
 {
   return unw_is_fpreg (uw_regnum);
 }
-  
+
 /* Libunwind callback accessor function for general registers.  */
 static int
 ia64_access_reg (unw_addr_space_t as, unw_regnum_t uw_regnum, unw_word_t *val, 
@@ -2460,7 +2460,7 @@ ia64_access_reg (unw_addr_space_t as, unw_regnum_t uw_regnum, unw_word_t *val,
 	bsp = extract_unsigned_integer (buf, 8, byte_order);
 	get_frame_register (this_frame, IA64_CFM_REGNUM, buf);
 	cfm = extract_unsigned_integer (buf, 8, byte_order);
-	sof = (cfm & 0x7f);
+	sof = gdbarch_tdep (gdbarch)->size_of_register_frame (this_frame, cfm);
 	*val = ia64_rse_skip_regs (bsp, -sof);
 	break;
 
@@ -3812,6 +3812,14 @@ ia64_print_insn (bfd_vma memaddr, struct disassemble_info *info)
   return print_insn_ia64 (memaddr, info);
 }
 
+/* The default "size_of_register_frame" gdbarch_tdep routine for ia64.  */
+
+static int
+ia64_size_of_register_frame (struct frame_info *this_frame, ULONGEST cfm)
+{
+  return (cfm & 0x7f);
+}
+
 static struct gdbarch *
 ia64_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
 {
@@ -3826,6 +3834,8 @@ ia64_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
   tdep = xzalloc (sizeof (struct gdbarch_tdep));
   gdbarch = gdbarch_alloc (&info, tdep);
 
+  tdep->size_of_register_frame = ia64_size_of_register_frame;
+
   /* According to the ia64 specs, instructions that store long double
      floats in memory use a long-double format different than that
      used in the floating registers.  The memory format matches the
diff --git a/gdb/ia64-tdep.h b/gdb/ia64-tdep.h
index b7a8eaf..b88031e 100644
--- a/gdb/ia64-tdep.h
+++ b/gdb/ia64-tdep.h
@@ -195,11 +195,20 @@
 #define IA64_NAT32_REGNUM	(IA64_NAT0_REGNUM + 32)
 #define IA64_NAT127_REGNUM	(IA64_NAT0_REGNUM + 127)
 
+struct frame_info;
+
 struct gdbarch_tdep
 {
   CORE_ADDR (*sigcontext_register_address) (struct gdbarch *, CORE_ADDR, int);
   int (*pc_in_sigtramp) (CORE_ADDR);
 
+  /* Return the total size of THIS_FRAME's register frame.
+     CFM is THIS_FRAME's cfm register value.
+
+     Normally, the size of the register frame is always obtained by
+     extracting the lowest 7 bits ("cfm & 0x7f").  */
+  int (*size_of_register_frame) (struct frame_info *this_frame, ULONGEST cfm);
+
   /* ISA-specific data types.  */
   struct type *ia64_ext_type;
 };
-- 
1.7.1

^ permalink raw reply	[flat|nested] 31+ messages in thread

* [PATCH 8/8] [ia64-hpux] inferior function call support
  2010-12-28  4:43 Porting GDB to ia64-hpux Joel Brobecker
                   ` (6 preceding siblings ...)
  2010-12-28  4:54 ` [PATCH 7/8] ia64-hpux: unwinding bsp value from system call Joel Brobecker
@ 2010-12-28  5:00 ` Joel Brobecker
  2010-12-31 19:18   ` Joel Brobecker
  2011-01-13 16:53 ` Porting GDB to ia64-hpux Joel Brobecker
  8 siblings, 1 reply; 31+ messages in thread
From: Joel Brobecker @ 2010-12-28  5:00 UTC (permalink / raw)
  To: gdb-patches; +Cc: Joel Brobecker

We have two stacks to deal with on ia64, when making a function call.
The first is the usual stack frame, and the second is the register
stack frame.  On ia64-linux, the register frame is setup by adjusting
the BSP register.  Unfortunately for us, the HP-UX kernel does not allow
the debugger to change the value of the BSP.

To work around that limitation, the method I am using here is to push
some assembly code on the stack. This assembly code contains, among
other things, a call to the alloc insn, which sets up our frame for us.
An extensive comment in ia64-hpux-tdep.c explains the entire procedure.

Despite this approach, most of the code in ia64-tdep.c which sets up
the function call is still applicable - and only a few things need
to be done differently:  For instance, instead of changing the BSP,
we do nothing.  We store the parameters at a different location, etc.
So this patch also adjusts the inf-call code in ia64-tdep.c to make it
a little more extensible: I create a new ia64_infcall_ops structure
which allows an ABI to define how the few things that need to be
differentiated.

Another element that turned out to be necessary but is more of a detail
is that the computation of the linkage pointer needs to be handled
specially for symbols inside shared libraries.  This is especially
visible when calling malloc, which happens everytime memory needs to
be allocated in inferior memory...  The special treatment included
again the necessity to use some routines only available on the host.
So another TARGET_OBJECT_OSDATA annex was created for that:
"ia64.hpux.solib.got".

gdb/ChangeLog:

        * ia64-tdep.h (struct regcache): Forward declare.
        (struct ia64_infcall_ops): New struct type.
        (struct gdbarch_tdep): New fields "find_global_pointer_from_solib"
        and "infcall_ops".
        * ia64-tdep.c (ia64_find_global_pointer_from_dynamic_section):
        Renames ia64_find_global_pointer.
        (ia64_find_global_pointer, ia64_allocate_new_rse_frame)
        (ia64_store_argument_in_slot, ia64_set_function_addr: New function.
        (ia64_push_dummy_call): Adjust to use the new tdep ia64_infocall_ops
        methods.
        (ia64_infcall_ops): New static global constant.
        (ia64_gdbarch_init): Set tdep->infcall_ops.
        * ia64-hpux-nat.c (ia64_hpux_xfer_solib_got): New function.
        (ia64_hpux_xfer_os_data): Add handling of "ia64.hpux.solib.got" annex.
        * ia64-hpux-tdep.c: Include "regcache.h", "gdbcore.h" and "inferior.h".
        (ia64_hpux_dummy_code): New static global constant.
        (ia64_hpux_push_dummy_code, ia64_hpux_allocate_new_rse_frame)
        (ia64_hpux_store_argument_in_slot, ia64_hpux_set_function_addr)
        (ia64_hpux_dummy_id, ia64_hpux_find_global_pointer_from_solib):
        New function.
        (ia64_hpux_infcall_ops): New static global constant.
        (ia64_hpux_init_abi): Install gdbarch and tdep methods needed
        for inferior function calls to work properly on ia64-hpux.
---
 gdb/ia64-hpux-nat.c  |   27 +++++
 gdb/ia64-hpux-tdep.c |  277 ++++++++++++++++++++++++++++++++++++++++++++++++++
 gdb/ia64-tdep.c      |   99 +++++++++++++++---
 gdb/ia64-tdep.h      |   36 +++++++
 4 files changed, 422 insertions(+), 17 deletions(-)

diff --git a/gdb/ia64-hpux-nat.c b/gdb/ia64-hpux-nat.c
index dfa6b7f..8c0bc7b 100644
--- a/gdb/ia64-hpux-nat.c
+++ b/gdb/ia64-hpux-nat.c
@@ -595,6 +595,26 @@ ia64_hpux_xfer_in_syscall (struct target_ops *ops, gdb_byte *readbuf,
   return 1;
 }
 
+/* This is a wrapper around ia64_hpux_get_solib_linkage_addr, which
+   takes FUN_ADDR as the function address, and stores the result in
+   READBUF.  LEN is the size of the READBUF buffer (a failed assertion
+   is raised if the buffer is not large enough to contain the result).
+
+   Return the size of the data written in READBUF.  */
+
+static LONGEST
+ia64_hpux_xfer_solib_got (gdb_byte *readbuf, CORE_ADDR fun_addr, LONGEST len)
+{
+  CORE_ADDR addr;
+
+  /* The buffer should have enough room for us to store a CORE_ADDR.  */
+  gdb_assert (len >= sizeof (addr));
+
+  addr = ia64_hpux_get_solib_linkage_addr (fun_addr);
+  memcpy (readbuf, &addr, sizeof (addr));
+  return sizeof (addr);
+}
+
 /* Handle the transfer of TARGET_OBJECT_OSDATA objects on ia64-hpux.
 
    The type of data being requested depends on the value of ANNEX:
@@ -604,6 +624,11 @@ ia64_hpux_xfer_in_syscall (struct target_ops *ops, gdb_byte *readbuf,
        is nonzero iff the inferior is stopped inside a system call.
        OFFSET is ignored.
 
+     * "ia64.hpux.solib.got":
+       OFFSET is the address of a function.  If that function belongs
+       to one of the shared libraries, store the shared library's global
+       pointer in READBUF.
+
    Any other request is deferred to super_xfer_partial.
    ANNEX is assumed to never be NULL.  */
 
@@ -615,6 +640,8 @@ ia64_hpux_xfer_os_data (struct target_ops *ops, const char *annex,
 
   if (strcmp (annex, "ia64.hpux.in_syscall") == 0)
     return ia64_hpux_xfer_in_syscall (ops, readbuf, len);
+  else if (strcmp (annex, "ia64.hpux.solib.got") == 0)
+    return ia64_hpux_xfer_solib_got (readbuf, offset, len);
   else
     /* Unknown OSDATA request, delegate to super_xfer_partial.  */
     return super_xfer_partial (ops, TARGET_OBJECT_OSDATA, annex, readbuf,
diff --git a/gdb/ia64-hpux-tdep.c b/gdb/ia64-hpux-tdep.c
index 5dd0a4e..1f712a7 100644
--- a/gdb/ia64-hpux-tdep.c
+++ b/gdb/ia64-hpux-tdep.c
@@ -25,6 +25,133 @@
 #include "solib.h"
 #include "target.h"
 #include "frame.h"
+#include "regcache.h"
+#include "gdbcore.h"
+#include "inferior.h"
+
+/* A sequence of instructions pushed on the stack when we want to perform
+   an inferior function call.  The main purpose of this code is to save
+   the output region of the register frame belonging to the function
+   from which we are making the call.  Normally, all registers are saved
+   prior to the call, but this does not include stacked registers because
+   they are seen by GDB as pseudo registers.
+
+   On Linux, these stacked registers can be saved by simply creating
+   a new register frame, or in other words by moving the BSP.  But the
+   HP/UX kernel does not allow this.  So we rely on this code instead,
+   that makes functions calls whose only purpose is to create new
+   register frames.
+
+   The array below is the result obtained after assembling the code
+   shown below. It's an array of bytes in order to make it independent
+   of the host endianess, in case it ends up being used on more than
+   one target.
+
+   start:
+        // Save b0 before using it (into preserved reg: r4).
+        mov r4 = b0
+        ;;
+
+        br.call.dptk.few b0 = stub#
+        ;;
+
+        // Add a nop bundle where we can insert our dummy breakpoint.
+        nop.m 0
+        nop.i 0
+        nop.i 0
+        ;;
+
+   stub:
+        // Alloc a new register stack frame.  Here, we set the size
+        // of all regions to zero.  Eventually, GDB will manually
+        // change the instruction to set the size of the local region
+        // to match size of the output region of the function from
+        // which we are making the function call.  This is to protect
+        // the value of the output registers of the function from
+        // which we are making the call.
+        alloc r6 = ar.pfs, 0, 0, 0, 0
+
+        // Save b0 before using it again (into preserved reg: r5).
+        mov r5 = b0
+        ;;
+
+        //  Now that we have protected the entire output region of the
+        //  register stack frame, we can call our function that will
+        //  setup the arguments, and call our target function.
+        br.call.dptk.few b0 = call_dummy#
+        ;;
+
+        //  Restore b0, ar.pfs, and return
+        mov b0 = r5
+        mov.i ar.pfs = r6
+        ;;
+        br.ret.dptk.few b0
+        ;;
+
+   call_dummy:
+        //  Alloc a new frame, with 2 local registers, and 8 output registers
+        //  (8 output registers for the maximum of 8 slots passed by register).
+        alloc r32 = ar.pfs, 2, 0, 8, 0
+
+        //  Save b0 before using it to call our target function.
+        mov r33 = b0
+
+        // Load the argument values placed by GDB inside r14-r21 in their
+        // proper registers.
+        or r34 = r14, r0
+        or r35 = r15, r0
+        or r36 = r16, r0
+        or r37 = r17, r0
+        or r38 = r18, r0
+        or r39 = r19, r0
+        or r40 = r20, r0
+        or r41 = r21, r0
+        ;;
+
+        // actual call
+        br.call.dptk.few b0 = b1
+        ;;
+
+        mov.i ar.pfs=r32
+        mov b0=r33
+        ;;
+
+        br.ret.dptk.few b0
+        ;;
+
+*/
+
+static const gdb_byte ia64_hpux_dummy_code[] =
+{
+  0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x40, 0x00,
+  0x00, 0x62, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00,
+  0x1d, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+  0x00, 0x02, 0x00, 0x00, 0x20, 0x00, 0x00, 0x52,
+  0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+  0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00,
+  0x02, 0x30, 0x00, 0x00, 0x80, 0x05, 0x50, 0x00,
+  0x00, 0x62, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00,
+  0x1d, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+  0x00, 0x02, 0x00, 0x00, 0x30, 0x00, 0x00, 0x52,
+  0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x28,
+  0x04, 0x80, 0x03, 0x00, 0x60, 0x00, 0xaa, 0x00,
+  0x1d, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+  0x00, 0x02, 0x00, 0x80, 0x00, 0x00, 0x84, 0x02,
+  0x00, 0x00, 0x29, 0x04, 0x80, 0x05, 0x10, 0x02,
+  0x00, 0x62, 0x00, 0x40, 0xe4, 0x00, 0x38, 0x80,
+  0x00, 0x18, 0x3d, 0x00, 0x0e, 0x20, 0x40, 0x82,
+  0x00, 0x1c, 0x40, 0xa0, 0x14, 0x01, 0x38, 0x80,
+  0x00, 0x30, 0x49, 0x00, 0x0e, 0x20, 0x70, 0x9a,
+  0x00, 0x1c, 0x40, 0x00, 0x45, 0x01, 0x38, 0x80,
+  0x0a, 0x48, 0x55, 0x00, 0x0e, 0x20, 0x00, 0x00,
+  0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00,
+  0x1d, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+  0x00, 0x02, 0x00, 0x00, 0x10, 0x00, 0x80, 0x12,
+  0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+  0x01, 0x55, 0x00, 0x00, 0x10, 0x0a, 0x00, 0x07,
+  0x1d, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+  0x00, 0x02, 0x00, 0x80, 0x00, 0x00, 0x84, 0x02
+};
 
 /* Return nonzero if the value of the register identified by REGNUM
    can be modified.  */
@@ -117,12 +244,154 @@ ia64_hpux_size_of_register_frame (struct frame_info *this_frame,
   return sof;
 }
 
+/* Implement the push_dummy_code gdbarch method.
+
+   This function assumes that the SP is already 16-byte-aligned.  */
+
+static CORE_ADDR
+ia64_hpux_push_dummy_code (struct gdbarch *gdbarch, CORE_ADDR sp,
+			   CORE_ADDR funaddr, struct value **args, int nargs,
+			   struct type *value_type, CORE_ADDR *real_pc,
+			   CORE_ADDR *bp_addr, struct regcache *regcache)
+{
+  ULONGEST cfm;
+  int sof, sol, sor, soo;
+  char buf[16];
+
+  regcache_cooked_read_unsigned (regcache, IA64_CFM_REGNUM, &cfm);
+  sof = cfm & 0x7f;
+  sol = (cfm >> 7) & 0x7f;
+  sor = (cfm >> 14) & 0xf;
+  soo = sof - sol - sor;
+
+  /* Reserve some space on the stack to hold the dummy code.  */
+  sp = sp - sizeof (ia64_hpux_dummy_code);
+
+  /* Set the breakpoint address at the first instruction of the bundle
+     in the dummy code that has only nops.  This is where the dummy code
+     expects us to break.  */
+  *bp_addr = sp + 0x20;
+
+  /* Start the inferior function call from the dummy code.  The dummy
+     code will then call our function.  */
+  *real_pc = sp;
+
+  /* Transfer the dummy code to the inferior.  */
+  write_memory (sp, ia64_hpux_dummy_code, sizeof (ia64_hpux_dummy_code));
+
+  /* Update the size of the local portion of the register frame allocated
+     by ``stub'' to match the size of the output region of the current
+     register frame.  This allows us to save the stacked registers.
+
+     The "alloc" instruction is located at slot 0 of the bundle at +0x30.
+     Update the "sof" and "sol" portion of that instruction which are
+     respectively at bits 18-24 and 25-31 of the bundle.  */
+  memcpy (buf, ia64_hpux_dummy_code + 0x30, sizeof (buf));
+
+  buf[2] |= ((soo & 0x3f) << 2);
+  buf[3] |= (soo << 1);
+  if (soo > 63)
+    buf[3] |= 1;
+
+  write_memory (sp + 0x30, buf, sizeof (buf));
+
+  /* Return the new (already properly aligned) SP.  */
+  return sp;
+}
+
+/* The "allocate_new_rse_frame" ia64_infcall_ops routine for ia64-hpux.  */
+
+static void
+ia64_hpux_allocate_new_rse_frame (struct regcache *regcache, ULONGEST bsp,
+				  int sof)
+{
+  /* We cannot change the value of the BSP register on HP-UX,
+     so we can't allocate a new RSE frame.  */
+}
+
+/* The "store_argument_in_slot" ia64_infcall_ops routine for ia64-hpux.  */
+
+static void
+ia64_hpux_store_argument_in_slot (struct regcache *regcache, CORE_ADDR bsp,
+                                  int slotnum, gdb_byte *buf)
+{
+  /* The call sequence on this target expects us to place the arguments
+     inside r14 - r21.  */
+  regcache_cooked_write (regcache, IA64_GR0_REGNUM + 14 + slotnum, buf);
+}
+
+/* The "set_function_addr" ia64_infcall_ops routine for ia64-hpux.  */
+
+static void
+ia64_hpux_set_function_addr (struct regcache *regcache, CORE_ADDR func_addr)
+{
+  /* The calling sequence calls the function whose address is placed
+     in register b1.  */
+  regcache_cooked_write_unsigned (regcache, IA64_BR1_REGNUM, func_addr);
+}
+
+/* The ia64_infcall_ops structure for ia64-hpux.  */
+
+static const struct ia64_infcall_ops ia64_hpux_infcall_ops =
+{
+  ia64_hpux_allocate_new_rse_frame,
+  ia64_hpux_store_argument_in_slot,
+  ia64_hpux_set_function_addr
+};
+
+/* The "dummy_id" gdbarch routine for ia64-hpux.  */
+
+static struct frame_id
+ia64_hpux_dummy_id (struct gdbarch *gdbarch, struct frame_info *this_frame)
+{
+  CORE_ADDR sp, pc, bp_addr, bsp;
+
+  sp = get_frame_register_unsigned (this_frame, IA64_GR12_REGNUM);
+
+  /* Just double-check that the frame PC is within a certain region
+     of the stack that would be plausible for our dummy code (the dummy
+     code was pushed at SP + 16).  If not, then return a null frame ID.
+     This is necessary in our case, because it is possible to produce
+     the same frame ID for a normal frame, if that frame corresponds
+     to the function called by our dummy code, and the function has not
+     modified the registers that we use to build the dummy frame ID.  */
+  pc = get_frame_pc (this_frame);
+  if (pc < sp + 16 || pc >= sp + 16 + sizeof (ia64_hpux_dummy_code))
+    return null_frame_id;
+
+  /* The call sequence is such that the address of the dummy breakpoint
+     we inserted is stored in r5.  */
+  bp_addr = get_frame_register_unsigned (this_frame, IA64_GR5_REGNUM);
+
+  bsp = get_frame_register_unsigned (this_frame, IA64_BSP_REGNUM);
+
+  return frame_id_build_special (sp, bp_addr, bsp);
+}
+
 /* Should be set to non-NULL if the ia64-hpux solib module is linked in.
    This may not be the case because the shared library support code can
    only be compiled on ia64-hpux.  */
 
 struct target_so_ops *ia64_hpux_so_ops = NULL;
 
+/* The "find_global_pointer_from_solib" gdbarch_tdep routine for
+   ia64-hpux.  */
+
+static CORE_ADDR
+ia64_hpux_find_global_pointer_from_solib (struct gdbarch *gdbarch,
+					  CORE_ADDR faddr)
+{
+  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+  struct target_ops *ops = &current_target;
+  gdb_byte buf[8];
+  LONGEST len;
+
+  len = target_read (ops, TARGET_OBJECT_OSDATA, "ia64.hpux.solib.got",
+		     buf, faddr, sizeof (buf));
+
+  return extract_unsigned_integer (buf, len, byte_order);
+}
+
 static void
 ia64_hpux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
 {
@@ -133,6 +402,14 @@ ia64_hpux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
   set_gdbarch_long_double_format (gdbarch, floatformats_ia64_quad);
   set_gdbarch_cannot_store_register (gdbarch, ia64_hpux_cannot_store_register);
 
+  /* Inferior functions must be called from stack. */
+  set_gdbarch_call_dummy_location (gdbarch, ON_STACK);
+  set_gdbarch_push_dummy_code (gdbarch, ia64_hpux_push_dummy_code);
+  tdep->infcall_ops = ia64_hpux_infcall_ops;
+  tdep->find_global_pointer_from_solib
+      = ia64_hpux_find_global_pointer_from_solib;
+  set_gdbarch_dummy_id (gdbarch, ia64_hpux_dummy_id);
+
   if (ia64_hpux_so_ops)
     set_solib_ops (gdbarch, ia64_hpux_so_ops);
 }
diff --git a/gdb/ia64-tdep.c b/gdb/ia64-tdep.c
index 1cfffc7..ac7dd0e 100644
--- a/gdb/ia64-tdep.c
+++ b/gdb/ia64-tdep.c
@@ -3386,7 +3386,8 @@ slot_alignment_is_next_even (struct type *t)
    d_un.d_ptr value is the global pointer.  */
 
 static CORE_ADDR
-ia64_find_global_pointer (struct gdbarch *gdbarch, CORE_ADDR faddr)
+ia64_find_global_pointer_from_dynamic_section (struct gdbarch *gdbarch,
+					       CORE_ADDR faddr)
 {
   enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
   struct obj_section *faddr_sect;
@@ -3444,6 +3445,24 @@ ia64_find_global_pointer (struct gdbarch *gdbarch, CORE_ADDR faddr)
   return 0;
 }
 
+/* Attempt to find (and return) the global pointer for the given
+   function.  We first try the find_global_pointer_from_solib routine
+   from the gdbarch tdep vector, if provided.  And if that does not
+   work, then we try ia64_find_global_pointer_from_dynamic_section.  */
+
+static CORE_ADDR
+ia64_find_global_pointer (struct gdbarch *gdbarch, CORE_ADDR faddr)
+{
+  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+  CORE_ADDR addr = 0;
+
+  if (tdep->find_global_pointer_from_solib)
+    addr = tdep->find_global_pointer_from_solib (gdbarch, faddr);
+  if (addr == 0)
+    addr = ia64_find_global_pointer_from_dynamic_section (gdbarch, faddr);
+  return addr;
+}
+
 /* Given a function's address, attempt to find (and return) the
    corresponding (canonical) function descriptor.  Return 0 if
    not found.  */
@@ -3583,12 +3602,53 @@ ia64_frame_align (struct gdbarch *gdbarch, CORE_ADDR sp)
   return sp & ~0xfLL;
 }
 
+/* The default "allocate_new_rse_frame" ia64_infcall_ops routine for ia64.  */
+
+static void
+ia64_allocate_new_rse_frame (struct regcache *regcache, ULONGEST bsp, int sof)
+{
+  ULONGEST cfm, pfs, new_bsp;
+
+  regcache_cooked_read_unsigned (regcache, IA64_CFM_REGNUM, &cfm);
+
+  new_bsp = rse_address_add (bsp, sof);
+  regcache_cooked_write_unsigned (regcache, IA64_BSP_REGNUM, new_bsp);
+
+  regcache_cooked_read_unsigned (regcache, IA64_PFS_REGNUM, &pfs);
+  pfs &= 0xc000000000000000LL;
+  pfs |= (cfm & 0xffffffffffffLL);
+  regcache_cooked_write_unsigned (regcache, IA64_PFS_REGNUM, pfs);
+
+  cfm &= 0xc000000000000000LL;
+  cfm |= sof;
+  regcache_cooked_write_unsigned (regcache, IA64_CFM_REGNUM, cfm);
+}
+
+/* The default "store_argument_in_slot" ia64_infcall_ops routine for
+   ia64.  */
+
+static void
+ia64_store_argument_in_slot (struct regcache *regcache, CORE_ADDR bsp,
+			     int slotnum, gdb_byte *buf)
+{
+  write_memory (rse_address_add (bsp, slotnum), buf, 8);
+}
+
+/* The default "set_function_addr" ia64_infcall_ops routine for ia64.  */
+
+static void
+ia64_set_function_addr (struct regcache *regcache, CORE_ADDR func_addr)
+{
+  /* Nothing needed.  */
+}
+
 static CORE_ADDR
 ia64_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
 		      struct regcache *regcache, CORE_ADDR bp_addr,
 		      int nargs, struct value **args, CORE_ADDR sp,
 		      int struct_return, CORE_ADDR struct_addr)
 {
+  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
   enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
   int argno;
   struct value *arg;
@@ -3596,7 +3656,7 @@ ia64_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
   int len, argoffset;
   int nslots, rseslots, memslots, slotnum, nfuncargs;
   int floatreg;
-  ULONGEST bsp, cfm, pfs, new_bsp;
+  ULONGEST bsp;
   CORE_ADDR funcdescaddr, pc, global_pointer;
   CORE_ADDR func_addr = find_function_addr (function, NULL);
 
@@ -3623,20 +3683,8 @@ ia64_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
   memslots = nslots - rseslots;
 
   /* Allocate a new RSE frame.  */
-  regcache_cooked_read_unsigned (regcache, IA64_CFM_REGNUM, &cfm);
-
   regcache_cooked_read_unsigned (regcache, IA64_BSP_REGNUM, &bsp);
-  new_bsp = rse_address_add (bsp, rseslots);
-  regcache_cooked_write_unsigned (regcache, IA64_BSP_REGNUM, new_bsp);
-
-  regcache_cooked_read_unsigned (regcache, IA64_PFS_REGNUM, &pfs);
-  pfs &= 0xc000000000000000LL;
-  pfs |= (cfm & 0xffffffffffffLL);
-  regcache_cooked_write_unsigned (regcache, IA64_PFS_REGNUM, pfs);
-
-  cfm &= 0xc000000000000000LL;
-  cfm |= rseslots;
-  regcache_cooked_write_unsigned (regcache, IA64_CFM_REGNUM, cfm);
+  tdep->infcall_ops.allocate_new_rse_frame (regcache, bsp, rseslots);
   
   /* We will attempt to find function descriptors in the .opd segment,
      but if we can't we'll construct them ourselves.  That being the
@@ -3676,7 +3724,8 @@ ia64_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
 				  find_func_descr (regcache, faddr,
 						   &funcdescaddr));
 	  if (slotnum < rseslots)
-	    write_memory (rse_address_add (bsp, slotnum), val_buf, 8);
+	    tdep->infcall_ops.store_argument_in_slot (regcache, bsp,
+						      slotnum, val_buf);
 	  else
 	    write_memory (sp + 16 + 8 * (slotnum - rseslots), val_buf, 8);
 	  slotnum++;
@@ -3721,7 +3770,8 @@ ia64_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
             }
 
 	  if (slotnum < rseslots)
-	    write_memory (rse_address_add (bsp, slotnum), val_buf, 8);
+	    tdep->infcall_ops.store_argument_in_slot (regcache, bsp,
+						      slotnum, val_buf);
 	  else
 	    write_memory (sp + 16 + 8 * (slotnum - rseslots), val_buf, 8);
 
@@ -3760,13 +3810,27 @@ ia64_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
   if (global_pointer != 0)
     regcache_cooked_write_unsigned (regcache, IA64_GR1_REGNUM, global_pointer);
 
+  /* The following is not necessary on HP-UX, because we're using
+     a dummy code sequence pushed on the stack to make the call, and
+     this sequence doesn't need b0 to be set in order for our dummy
+     breakpoint to be hit.  Nonetheless, this doesn't interfere, and
+     it's needed for other OSes, so we do this unconditionaly.  */
   regcache_cooked_write_unsigned (regcache, IA64_BR0_REGNUM, bp_addr);
 
   regcache_cooked_write_unsigned (regcache, sp_regnum, sp);
 
+  tdep->infcall_ops.set_function_addr (regcache, func_addr);
+
   return sp;
 }
 
+static const struct ia64_infcall_ops ia64_infcall_ops =
+{
+  ia64_allocate_new_rse_frame,
+  ia64_store_argument_in_slot,
+  ia64_set_function_addr
+};
+
 static struct frame_id
 ia64_dummy_id (struct gdbarch *gdbarch, struct frame_info *this_frame)
 {
@@ -3883,6 +3947,7 @@ ia64_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
 
   /* Settings for calling functions in the inferior.  */
   set_gdbarch_push_dummy_call (gdbarch, ia64_push_dummy_call);
+  tdep->infcall_ops = ia64_infcall_ops;
   set_gdbarch_frame_align (gdbarch, ia64_frame_align);
   set_gdbarch_dummy_id (gdbarch, ia64_dummy_id);
 
diff --git a/gdb/ia64-tdep.h b/gdb/ia64-tdep.h
index b88031e..99ef368 100644
--- a/gdb/ia64-tdep.h
+++ b/gdb/ia64-tdep.h
@@ -196,6 +196,32 @@
 #define IA64_NAT127_REGNUM	(IA64_NAT0_REGNUM + 127)
 
 struct frame_info;
+struct regcache;
+
+/* A struction containing pointers to all the target-dependent operations
+   performed to setup an inferior function call. */
+
+struct ia64_infcall_ops
+{
+  /* Allocate a new register stack frame starting after the output
+     region of the current frame.  The new frame will contain SOF
+     registers, all in the output region.  This is one way of protecting
+     the stacked registers of the current frame.
+
+     Should do nothing if this operation is not permitted by the OS.  */
+  void (*allocate_new_rse_frame) (struct regcache *regcache, ULONGEST bsp,
+				  int sof);
+
+  /* Store the argument stored in BUF into the appropriate location
+     given the BSP and the SLOTNUM.  */
+  void (*store_argument_in_slot) (struct regcache *regcache, CORE_ADDR bsp,
+                                  int slotnum, gdb_byte *buf);
+
+  /* For targets where we cannot call the function directly, store
+     the address of the function we want to call at the location
+     expected by the calling sequence.  */
+  void (*set_function_addr) (struct regcache *regcache, CORE_ADDR func_addr);
+};
 
 struct gdbarch_tdep
 {
@@ -209,8 +235,18 @@ struct gdbarch_tdep
      extracting the lowest 7 bits ("cfm & 0x7f").  */
   int (*size_of_register_frame) (struct frame_info *this_frame, ULONGEST cfm);
 
+  /* Determine the function address FADDR belongs to a shared library.
+     If it does, then return the associated global pointer.  If no shared
+     library was found to contain that function, then return zero.
+
+     This pointer may be NULL.  */
+  CORE_ADDR (*find_global_pointer_from_solib) (struct gdbarch *gdbarch,
+					       CORE_ADDR faddr);
+
   /* ISA-specific data types.  */
   struct type *ia64_ext_type;
+
+  struct ia64_infcall_ops infcall_ops;
 };
 
 extern void ia64_write_pc (struct regcache *, CORE_ADDR);
-- 
1.7.1

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH 5/8] inf-ttrace: Determine attached process LWP immediately after attaching.
  2010-12-28  4:44 ` [PATCH 5/8] inf-ttrace: Determine attached process LWP immediately after attaching Joel Brobecker
@ 2010-12-28 11:04   ` Pedro Alves
  2010-12-28 11:26     ` Joel Brobecker
  0 siblings, 1 reply; 31+ messages in thread
From: Pedro Alves @ 2010-12-28 11:04 UTC (permalink / raw)
  To: gdb-patches; +Cc: Joel Brobecker

On Tuesday 28 December 2010 04:43:03, Joel Brobecker wrote:
> This works on PA/HP-UX, because we immediately perform a wait to pop
> the event triggered by the attach.  We can use that event to extract
> the thread's LWP.  But this does not work for IA64/HP-UX, because
> the attach no longer triggers an event, and thus a wait should NOT
> be performed (such a wait would simply block indefinitely).

How you can get by without setting target_attach_no_wait then?

-- 
Pedro Alves

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH 5/8] inf-ttrace: Determine attached process LWP immediately after attaching.
  2010-12-28 11:04   ` Pedro Alves
@ 2010-12-28 11:26     ` Joel Brobecker
  0 siblings, 0 replies; 31+ messages in thread
From: Joel Brobecker @ 2010-12-28 11:26 UTC (permalink / raw)
  To: Pedro Alves; +Cc: gdb-patches

> > This works on PA/HP-UX, because we immediately perform a wait to pop
> > the event triggered by the attach.  We can use that event to extract
> > the thread's LWP.  But this does not work for IA64/HP-UX, because
> > the attach no longer triggers an event, and thus a wait should NOT
> > be performed (such a wait would simply block indefinitely).
> 
> How you can get by without setting target_attach_no_wait then?

There is a global variable inf_ttrace_num_lwps that inf_ttrace_wait
checks to see if it needs to set the main thread's tid.  The thread
iteration loop that I'm adding increments that counter every time
I add a new thread, so the code doesn't trigger in the "attach" case.
But it still does when doing a "run".

-- 
Joel

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH 7/8] ia64-hpux: unwinding bsp value from system call
  2010-12-28  4:54 ` [PATCH 7/8] ia64-hpux: unwinding bsp value from system call Joel Brobecker
@ 2010-12-28 11:35   ` Pedro Alves
  2010-12-28 12:01     ` Joel Brobecker
  2010-12-28 15:29     ` [RFA/commit] Add documentation for TARGET_OBJECT_OSDATA Joel Brobecker
  0 siblings, 2 replies; 31+ messages in thread
From: Pedro Alves @ 2010-12-28 11:35 UTC (permalink / raw)
  To: gdb-patches; +Cc: Joel Brobecker

On Tuesday 28 December 2010 04:43:05, Joel Brobecker wrote:
>   1. Figuring out that we are stopped inside a syscal: This requires
>      a ttrace call, which is not directly possible from ia64-tdep.c.
>      So we get the info using a target-read of a TARGET_OBJECT_OSDATA
>      object (with the annex set to "ia64.hpux.in_syscall").

BZZT.  Don't do that.  The return of a TARGET_OBJECT_OSDATA request
should be a table that follows the gdb/features/osdata.dtd dtd.  It
is meant as data to be fed into the "info os" command (and a non-submitted
-info-os MI command).

You need to come up with a new target object.

-- 
Pedro Alves

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH 7/8] ia64-hpux: unwinding bsp value from system call
  2010-12-28 11:35   ` Pedro Alves
@ 2010-12-28 12:01     ` Joel Brobecker
  2010-12-28 16:17       ` Pedro Alves
  2010-12-28 15:29     ` [RFA/commit] Add documentation for TARGET_OBJECT_OSDATA Joel Brobecker
  1 sibling, 1 reply; 31+ messages in thread
From: Joel Brobecker @ 2010-12-28 12:01 UTC (permalink / raw)
  To: Pedro Alves; +Cc: gdb-patches

> BZZT.  Don't do that.  The return of a TARGET_OBJECT_OSDATA request
> should be a table that follows the gdb/features/osdata.dtd dtd.  It
> is meant as data to be fed into the "info os" command (and a non-submitted
> -info-os MI command).

Arg - I thought that using a target-specific annex name would be
sufficient.

I will use a different object kind. I could create our own object kind,
but someone it seems possible to have one that can be re-used by all
targets.

Some proposed names:

  TARGET_OBJECT_OSABI_SPECIFIC_DATA
  TARGET_OBJECT_OSABI_DATA
  TARGET_OBJECT_TARGET_SPECIFIC_DATA
  TARGET_OBJECT_TARGET_DATA

Another option is to create feature-specific objects, but then I'm
afraid the number of objects might steadily grow beyond reasonable
(I need two, right now).

The last option, is to follow the lead of some targets, and create
a CPU-specific target object: TARGET_OBJECT_IA64.

-- 
Joel

^ permalink raw reply	[flat|nested] 31+ messages in thread

* [RFA/commit] Add documentation for TARGET_OBJECT_OSDATA
  2010-12-28 11:35   ` Pedro Alves
  2010-12-28 12:01     ` Joel Brobecker
@ 2010-12-28 15:29     ` Joel Brobecker
  2010-12-28 15:46       ` Pedro Alves
  2010-12-29  3:29       ` Joel Brobecker
  1 sibling, 2 replies; 31+ messages in thread
From: Joel Brobecker @ 2010-12-28 15:29 UTC (permalink / raw)
  To: gdb-patches; +Cc: Joel Brobecker

> BZZT.  Don't do that.  The return of a TARGET_OBJECT_OSDATA request
> should be a table that follows the gdb/features/osdata.dtd dtd.  It
> is meant as data to be fed into the "info os" command (and a non-submitted
> -info-os MI command).

I propose to expand the comment besides TARGET_OBJECT_OSDATA to make it
clear...

gdb/ChangeLog:

        * target.h (enum target_object): Expand the documentation of
        TARGET_OBJECT_OSDATA a bit.

Looks good?

Thanks,
-- 
Joel


---
 gdb/target.h |    3 ++-
 1 files changed, 2 insertions(+), 1 deletions(-)

diff --git a/gdb/target.h b/gdb/target.h
index ea27b2c..6a1ec92 100644
--- a/gdb/target.h
+++ b/gdb/target.h
@@ -256,7 +256,8 @@ enum target_object
   /* Currently loaded libraries, in XML format.  */
   TARGET_OBJECT_LIBRARIES,
   /* Get OS specific data.  The ANNEX specifies the type (running
-     processes, etc.).  */
+     processes, etc.).  The data being transfered is expected to follow
+     the DTD specified in features/osdata.dtd.  */
   TARGET_OBJECT_OSDATA,
   /* Extra signal info.  Usually the contents of `siginfo_t' on unix
      platforms.  */
-- 
1.7.1

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [RFA/commit] Add documentation for TARGET_OBJECT_OSDATA
  2010-12-28 15:29     ` [RFA/commit] Add documentation for TARGET_OBJECT_OSDATA Joel Brobecker
@ 2010-12-28 15:46       ` Pedro Alves
  2010-12-29  3:29       ` Joel Brobecker
  1 sibling, 0 replies; 31+ messages in thread
From: Pedro Alves @ 2010-12-28 15:46 UTC (permalink / raw)
  To: gdb-patches; +Cc: Joel Brobecker

On Tuesday 28 December 2010 14:33:40, Joel Brobecker wrote:

> Looks good?

Yes, thanks.

-- 
Pedro Alves

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH 7/8] ia64-hpux: unwinding bsp value from system call
  2010-12-28 12:01     ` Joel Brobecker
@ 2010-12-28 16:17       ` Pedro Alves
  2010-12-29  5:49         ` Joel Brobecker
  0 siblings, 1 reply; 31+ messages in thread
From: Pedro Alves @ 2010-12-28 16:17 UTC (permalink / raw)
  To: Joel Brobecker; +Cc: gdb-patches

On Tuesday 28 December 2010 11:35:41, Joel Brobecker wrote:
> I will use a different object kind. I could create our own object kind,
> but someone it seems possible to have one that can be re-used by all
> targets.
> 
> Some proposed names:
> 
>   TARGET_OBJECT_OSABI_SPECIFIC_DATA
>   TARGET_OBJECT_OSABI_DATA
>   TARGET_OBJECT_TARGET_SPECIFIC_DATA
>   TARGET_OBJECT_TARGET_DATA
> 
> Another option is to create feature-specific objects, but then I'm
> afraid the number of objects might steadily grow beyond reasonable
> (I need two, right now).
> 
> The last option, is to follow the lead of some targets, and create
> a CPU-specific target object: TARGET_OBJECT_IA64.

What is the underlying object you're getting those values from?
I understood it to be whatever object TT_LWP_RUREGS accesses?
You seem to call it save_state_t?  Why not TARGET_OBJECT_HPUX_RUREGS
or TARGET_OBJECT_HPUX_SAVE_STATE, or something along those lines?
Then, the offset, and length passed to target_xfer would the
the offset and length you're currently passing to
ia64_hpux_read_register_from_save_state_t.  This would allow
(if useful) exporting this object similarly to the $_siginfo and
$_tlb objects.

-- 
Pedro Alves

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [RFA/commit] Add documentation for TARGET_OBJECT_OSDATA
  2010-12-28 15:29     ` [RFA/commit] Add documentation for TARGET_OBJECT_OSDATA Joel Brobecker
  2010-12-28 15:46       ` Pedro Alves
@ 2010-12-29  3:29       ` Joel Brobecker
  1 sibling, 0 replies; 31+ messages in thread
From: Joel Brobecker @ 2010-12-29  3:29 UTC (permalink / raw)
  To: gdb-patches

> gdb/ChangeLog:
> 
>         * target.h (enum target_object): Expand the documentation of
>         TARGET_OBJECT_OSDATA a bit.

Checked in...

-- 
Joel

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH 7/8] ia64-hpux: unwinding bsp value from system call
  2010-12-28 16:17       ` Pedro Alves
@ 2010-12-29  5:49         ` Joel Brobecker
  2010-12-29 12:05           ` Pedro Alves
  0 siblings, 1 reply; 31+ messages in thread
From: Joel Brobecker @ 2010-12-29  5:49 UTC (permalink / raw)
  To: Pedro Alves; +Cc: gdb-patches

> What is the underlying object you're getting those values from?
> I understood it to be whatever object TT_LWP_RUREGS accesses?
> You seem to call it save_state_t?  Why not TARGET_OBJECT_HPUX_RUREGS
> or TARGET_OBJECT_HPUX_SAVE_STATE, or something along those lines?
> Then, the offset, and length passed to target_xfer would the
> the offset and length you're currently passing to
> ia64_hpux_read_register_from_save_state_t.  This would allow
> (if useful) exporting this object similarly to the $_siginfo and
> $_tlb objects.

I cannot determine the offset from the tdep code.  The offset is
is a obtained by including one of the system hearders.

To widen a bit the discussion, I should mention that there is also
another object that I am trying to transfer in this patch set:
During an inferior function call, I need to set the global pointer,
and I can only get that global pointer from the shared-library
code (we extract a structure from memory which is also defined by
system headers). In both cases, I was (ab)-using TARGET_OBJECT_OSDATA.

My initial thoughts on the kind of object to be used were that we could
have one generic object which the targets were free to ues as they see
fit. Right now, we have TARGET_OBJECT_AVR, TARGET_OBJECT_SPU, etc.
It seems unnecessary to have one for each CPU since we can use
namespace conventions to make sure there are no collision.  I'm not
even sure that collisions are really a problem either, in fact.

Depending on which approach we use, I am proposing the following
target objects:

   (a) * TARGET_OBJECT_HPUX_STOP_REASON
         Returns a 1-byte object.
         0 == syscall context, non-zero == interruption context
       * TARGET_OBJECT_HPUX_SOLIB_GOT
         ANNEX contains an image of the PC for which we need the GOT
         Returns a CORE_ADDR that is either 0 if no shared library
         contains that PC, or else the associated SO's GOT.

   (b) One object for both datas:
       TARGET_OBJECT_HPUX, or TARGET_OBJECT_HPUX_DATA, or
       TARGET_OBJECT_TARGET_DATA, or TARGET_OBJECT_TDEP_DATA.

       In that case, the annex is used to determine which specific
       data the tdep code is looking for. I tend to like either
       TARGET_OBJECT_HPUX, or TARGET_OBJECT_TDEP_DATA, with a preference
       for the TARGET_OBJECT_TDEP_DATA.

-- 
Joel

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH 7/8] ia64-hpux: unwinding bsp value from system call
  2010-12-29  5:49         ` Joel Brobecker
@ 2010-12-29 12:05           ` Pedro Alves
  2010-12-29 13:16             ` Joel Brobecker
  2010-12-31 18:15             ` Joel Brobecker
  0 siblings, 2 replies; 31+ messages in thread
From: Pedro Alves @ 2010-12-29 12:05 UTC (permalink / raw)
  To: Joel Brobecker; +Cc: gdb-patches

On Wednesday 29 December 2010 03:28:48, Joel Brobecker wrote:
> > What is the underlying object you're getting those values from?
> > I understood it to be whatever object TT_LWP_RUREGS accesses?
> > You seem to call it save_state_t?  Why not TARGET_OBJECT_HPUX_RUREGS
> > or TARGET_OBJECT_HPUX_SAVE_STATE, or something along those lines?
> > Then, the offset, and length passed to target_xfer would the
> > the offset and length you're currently passing to
> > ia64_hpux_read_register_from_save_state_t.  This would allow
> > (if useful) exporting this object similarly to the $_siginfo and
> > $_tlb objects.
> 
> I cannot determine the offset from the tdep code.  The offset is
> is a obtained by including one of the system hearders.

Before you dismiss this completely on that
ground, looking at hppa-hpux-tdep.c, I see:

 /* Bit in the `ss_flag' member of `struct save_state' that indicates
    that the 64-bit register values are live.  From
    <machine/save_state.h>.  */
 #define HPPA_HPUX_SS_WIDEREGS		0x40

 /* Offsets of various parts of `struct save_state'.  From
    <machine/save_state.h>.  */
 #define HPPA_HPUX_SS_FLAGS_OFFSET	0
 #define HPPA_HPUX_SS_NARROW_OFFSET	4
 #define HPPA_HPUX_SS_FPBLOCK_OFFSET 	256
 #define HPPA_HPUX_SS_WIDE_OFFSET        640

 /* The size of `struct save_state.  */
 #define HPPA_HPUX_SAVE_STATE_SIZE	1152

 /* The size of `struct pa89_save_state', which corresponds to PA-RISC
    1.1, the lowest common denominator that we support.  */
 #define HPPA_HPUX_PA89_SAVE_STATE_SIZE	512

...

 * Bit in the `ss_flag' member of `struct save_state' that indicates
    the state was saved from a system call.  From
    <machine/save_state.h>.  */
 #define HPPA_HPUX_SS_INSYSCALL	0x02


And e.g., see hppa_hpux_supply_save_state.

When you implement core support for ia64-hpux, if done
right (in tdep code, host-independent, supporting cross core
debugging), you'll need to hardcode these offsets anyway.  It
looks like HPUX dumps each LWP's save_save in the cores.  These
offset are usually practically part of the ABI.

Just adding this as a data point.

-- 
Pedro Alves

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH 7/8] ia64-hpux: unwinding bsp value from system call
  2010-12-29 12:05           ` Pedro Alves
@ 2010-12-29 13:16             ` Joel Brobecker
  2010-12-31 18:15             ` Joel Brobecker
  1 sibling, 0 replies; 31+ messages in thread
From: Joel Brobecker @ 2010-12-29 13:16 UTC (permalink / raw)
  To: Pedro Alves; +Cc: gdb-patches

> Before you dismiss this completely on that
> ground, looking at hppa-hpux-tdep.c, I see:
[...]
> When you implement core support for ia64-hpux, if done
> right (in tdep code, host-independent, supporting cross core
> debugging), you'll need to hardcode these offsets anyway.  It
> looks like HPUX dumps each LWP's save_save in the cores.  These
> offset are usually practically part of the ABI.

OK, I think you have a solid point :-).  I will move some of these
constants, and implement your suggestion of a RUREGS object.

Thanks for all the help!
-- 
Joel

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH 7/8] ia64-hpux: unwinding bsp value from system call
  2010-12-29 12:05           ` Pedro Alves
  2010-12-29 13:16             ` Joel Brobecker
@ 2010-12-31 18:15             ` Joel Brobecker
  1 sibling, 0 replies; 31+ messages in thread
From: Joel Brobecker @ 2010-12-31 18:15 UTC (permalink / raw)
  To: gdb-patches

[-- Attachment #1: Type: text/plain, Size: 206 bytes --]

Following Pedro's suggestion, here is a new revised version of this
patch that defines a new TARGET_OBJECT_HPUX_UREGS target object to
get to the __reason pseudo-register...

Thanks again, Pedro.

-- 
Joel

[-- Attachment #2: uregs.diff --]
[-- Type: text/x-diff, Size: 9335 bytes --]

commit e246563d5cc60890c2ceba3d5b85d30e3f1ce5b2
Author: Joel Brobecker <brobecker@adacore.com>
Date:   Tue Dec 21 07:04:13 2010 -0500

    [ia64-hpux] unwinding bsp value from system call
    
    This fixes unwinding from a thread that is stopped inside a system call.
    This can be seen when switching to a thread that is stopped doing a
    pthread_cond_wait, for instance...
    
    The comments inside the code should explain what is happening in our
    case (the HP-UX exception in the case of system calls): Under certain
    circumstances (program stopped inside syscall), the offset to apply to
    the current BSP in order to compute the previous BSP is not the usual
    CFM & 0x7f.
    
    We parts in this patch:
    
      1. Figuring out that we are stopped inside a syscal: This requires
         a TT_LWP_RUREGS ttrace call, which is not directly possible from
         ia64-tdep.c.  So use defined a new TARGET_OBJECT_HPUX_UREGS object
         to request it from the -nat side.
    
      2. Add a gdbarch_tdep method that allows us to change the default
         behavior on ia64-hpux, permitting us to have a different "size of
         register frame" in that one particular case.
    
    gdb/ChangeLog:
    
            * target.h (enum target_object): Add TARGET_OBJECT_HPUX_UREGS.
            * ia64-tdep.h (struct frame_info): forward declaration.
            (struct gdbarch_tdep): Add field size_of_register_frame.
            * ia64-tdep.c (ia64_access_reg): Use tdep->size_of_register_frame
            to determine the size of the register frame.
            (ia64_size_of_register_frame): New function.
            (ia64_gdbarch_init): Set tdep->size_of_register_frame.
            * ia64-hpux-tdep.c: Include "target.h" and "frame.h".
            (IA64_HPUX_UREG_REASON): New macro.
            (ia64_hpux_stopped_in_syscall, ia64_hpux_size_of_register_frame):
            New functions.
            (ia64_hpux_init_abi): Set tdep->size_of_register_frame.
            * ia64-hpux-nat.c (ia64_hpux_xfer_uregs): New function.
            (ia64_hpux_xfer_partial): Add handling of TARGET_OBJECT_HPUX_UREGS
            objects.

diff --git a/gdb/ia64-hpux-nat.c b/gdb/ia64-hpux-nat.c
index 53941a7..80f7d99 100644
--- a/gdb/ia64-hpux-nat.c
+++ b/gdb/ia64-hpux-nat.c
@@ -567,6 +567,28 @@ ia64_hpux_xfer_memory (struct target_ops *ops, const char *annex,
   return len;
 }
 
+/* Handle the transfer of TARGET_OBJECT_HPUX_UREGS objects on ia64-hpux.
+   ANNEX is currently ignored.
+
+   The current implementation does not support write transfers (because
+   we do not currently do not need these transfers), and will raise
+   a failed assertion if WRITEBUF is not NULL.  */
+
+static LONGEST
+ia64_hpux_xfer_uregs (struct target_ops *ops, const char *annex,
+		      gdb_byte *readbuf, const gdb_byte *writebuf,
+		      ULONGEST offset, LONGEST len)
+{
+  int status;
+
+  gdb_assert (writebuf == NULL);
+
+  status = ia64_hpux_read_register_from_save_state_t (offset, readbuf, len);
+  if (status < 0)
+    return -1;
+  return len;
+}
+
 /* The "to_xfer_partial" target_ops routine for ia64-hpux.  */
 
 static LONGEST
@@ -578,6 +600,8 @@ ia64_hpux_xfer_partial (struct target_ops *ops, enum target_object object,
 
   if (object == TARGET_OBJECT_MEMORY)
     val = ia64_hpux_xfer_memory (ops, annex, readbuf, writebuf, offset, len);
+  else if (object == TARGET_OBJECT_HPUX_UREGS)
+    val = ia64_hpux_xfer_uregs (ops, annex, readbuf, writebuf, offset, len);
   else
     val = super_xfer_partial (ops, object, annex, readbuf, writebuf, offset,
 			      len);
diff --git a/gdb/ia64-hpux-tdep.c b/gdb/ia64-hpux-tdep.c
index 139ff83..a4d2fa7 100644
--- a/gdb/ia64-hpux-tdep.c
+++ b/gdb/ia64-hpux-tdep.c
@@ -23,6 +23,17 @@
 #include "osabi.h"
 #include "gdbtypes.h"
 #include "solib.h"
+#include "target.h"
+#include "frame.h"
+
+/* The offset to be used in order to get the __reason pseudo-register
+   when using one of the *UREGS ttrace requests (see system header file
+   /usr/include/ia64/sys/uregs.h for more details).
+
+   The documentation for this pseudo-register says that a nonzero value
+   indicates that the thread stopped due to a fault, trap, or interrupt.
+   A null value indicates a stop inside a syscall.  */
+#define IA64_HPUX_UREG_REASON 0x00070000
 
 /* Return nonzero if the value of the register identified by REGNUM
    can be modified.  */
@@ -74,6 +85,47 @@ ia64_hpux_cannot_store_register (struct gdbarch *gdbarch, int regnum)
   return 0;
 }
 
+/* Return nonzero if the inferior is stopped inside a system call.  */
+
+static int
+ia64_hpux_stopped_in_syscall (struct gdbarch *gdbarch)
+{
+  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+  struct target_ops *ops = &current_target;
+  gdb_byte buf[8];
+  int len;
+
+  len = target_read (ops, TARGET_OBJECT_HPUX_UREGS, NULL,
+		     buf, IA64_HPUX_UREG_REASON, sizeof (buf));
+  if (len == -1)
+    /* The target wasn't able to tell us.  Assume we are not stopped
+       in a system call, which is the normal situation.  */
+    return 0;
+  gdb_assert (len == 8);
+
+  return (extract_unsigned_integer (buf, len, byte_order) == 0);
+}
+
+/* The "size_of_register_frame" gdbarch_tdep routine for ia64-hpux.  */
+
+static int
+ia64_hpux_size_of_register_frame (struct frame_info *this_frame,
+				  ULONGEST cfm)
+{
+  int sof;
+
+  if (frame_relative_level (this_frame) == 0
+      && ia64_hpux_stopped_in_syscall (get_frame_arch (this_frame)))
+    /* If the inferior stopped in a system call, the base address
+       of the register frame is at BSP - SOL instead of BSP - SOF.
+       This is an HP-UX exception.  */
+    sof = (cfm & 0x3f80) >> 7;
+  else
+    sof = (cfm & 0x7f);
+
+  return sof;
+}
+
 /* Should be set to non-NULL if the ia64-hpux solib module is linked in.
    This may not be the case because the shared library support code can
    only be compiled on ia64-hpux.  */
@@ -83,6 +135,10 @@ struct target_so_ops *ia64_hpux_so_ops = NULL;
 static void
 ia64_hpux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
 {
+  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+
+  tdep->size_of_register_frame = ia64_hpux_size_of_register_frame;
+
   set_gdbarch_long_double_format (gdbarch, floatformats_ia64_quad);
   set_gdbarch_cannot_store_register (gdbarch, ia64_hpux_cannot_store_register);
 
diff --git a/gdb/ia64-tdep.c b/gdb/ia64-tdep.c
index 1cd6a38..1cfffc7 100644
--- a/gdb/ia64-tdep.c
+++ b/gdb/ia64-tdep.c
@@ -2423,7 +2423,7 @@ ia64_is_fpreg (int uw_regnum)
 {
   return unw_is_fpreg (uw_regnum);
 }
-  
+
 /* Libunwind callback accessor function for general registers.  */
 static int
 ia64_access_reg (unw_addr_space_t as, unw_regnum_t uw_regnum, unw_word_t *val, 
@@ -2460,7 +2460,7 @@ ia64_access_reg (unw_addr_space_t as, unw_regnum_t uw_regnum, unw_word_t *val,
 	bsp = extract_unsigned_integer (buf, 8, byte_order);
 	get_frame_register (this_frame, IA64_CFM_REGNUM, buf);
 	cfm = extract_unsigned_integer (buf, 8, byte_order);
-	sof = (cfm & 0x7f);
+	sof = gdbarch_tdep (gdbarch)->size_of_register_frame (this_frame, cfm);
 	*val = ia64_rse_skip_regs (bsp, -sof);
 	break;
 
@@ -3812,6 +3812,14 @@ ia64_print_insn (bfd_vma memaddr, struct disassemble_info *info)
   return print_insn_ia64 (memaddr, info);
 }
 
+/* The default "size_of_register_frame" gdbarch_tdep routine for ia64.  */
+
+static int
+ia64_size_of_register_frame (struct frame_info *this_frame, ULONGEST cfm)
+{
+  return (cfm & 0x7f);
+}
+
 static struct gdbarch *
 ia64_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
 {
@@ -3826,6 +3834,8 @@ ia64_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
   tdep = xzalloc (sizeof (struct gdbarch_tdep));
   gdbarch = gdbarch_alloc (&info, tdep);
 
+  tdep->size_of_register_frame = ia64_size_of_register_frame;
+
   /* According to the ia64 specs, instructions that store long double
      floats in memory use a long-double format different than that
      used in the floating registers.  The memory format matches the
diff --git a/gdb/ia64-tdep.h b/gdb/ia64-tdep.h
index b7a8eaf..b88031e 100644
--- a/gdb/ia64-tdep.h
+++ b/gdb/ia64-tdep.h
@@ -195,11 +195,20 @@
 #define IA64_NAT32_REGNUM	(IA64_NAT0_REGNUM + 32)
 #define IA64_NAT127_REGNUM	(IA64_NAT0_REGNUM + 127)
 
+struct frame_info;
+
 struct gdbarch_tdep
 {
   CORE_ADDR (*sigcontext_register_address) (struct gdbarch *, CORE_ADDR, int);
   int (*pc_in_sigtramp) (CORE_ADDR);
 
+  /* Return the total size of THIS_FRAME's register frame.
+     CFM is THIS_FRAME's cfm register value.
+
+     Normally, the size of the register frame is always obtained by
+     extracting the lowest 7 bits ("cfm & 0x7f").  */
+  int (*size_of_register_frame) (struct frame_info *this_frame, ULONGEST cfm);
+
   /* ISA-specific data types.  */
   struct type *ia64_ext_type;
 };
diff --git a/gdb/target.h b/gdb/target.h
index 7290d90..24221ce 100644
--- a/gdb/target.h
+++ b/gdb/target.h
@@ -265,6 +265,9 @@ enum target_object
   TARGET_OBJECT_THREADS,
   /* Collected static trace data.  */
   TARGET_OBJECT_STATIC_TRACE_DATA,
+  /* The HP-UX registers (those that can be obtained or modified by using
+     the TT_LWP_RUREGS/TT_LWP_WUREGS ttrace requests).  */
+  TARGET_OBJECT_HPUX_UREGS,
   /* Possible future objects: TARGET_OBJECT_FILE, ... */
 };
 

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH 8/8] [ia64-hpux] inferior function call support
  2010-12-28  5:00 ` [PATCH 8/8] [ia64-hpux] inferior function call support Joel Brobecker
@ 2010-12-31 19:18   ` Joel Brobecker
  0 siblings, 0 replies; 31+ messages in thread
From: Joel Brobecker @ 2010-12-31 19:18 UTC (permalink / raw)
  To: gdb-patches

[-- Attachment #1: Type: text/plain, Size: 157 bytes --]

This is a revised version of this patch that replaces the abuse of
TARGET_OBJECT_OSDATA by the use of a new TARGET_OBJECT_HPUX_SOLIB_GOT
object...

-- 
Joel

[-- Attachment #2: ia64-hpux-funcall.diff --]
[-- Type: text/x-diff, Size: 25928 bytes --]

commit 2de44e1c828ce8c59431166f330f341874b34d9b
Author: Joel Brobecker <brobecker@adacore.com>
Date:   Thu Dec 23 07:56:03 2010 -0500

    [ia64-hpux] inferior function call support
    
    We have two stacks to deal with on ia64, when making a function call.
    The first is the usual stack frame, and the second is the register
    stack frame.  On ia64-linux, the register frame is setup by adjusting
    the BSP register.  Unfortunately for us, the HP-UX kernel does not allow
    the debugger to change the value of the BSP.
    
    To work around that limitation, the method I am using here is to push
    some assembly code on the stack. This assembly code contains, among
    other things, a call to the alloc insn, which sets up our frame for us.
    An extensive comment in ia64-hpux-tdep.c explains the entire procedure.
    
    Despite this approach, most of the code in ia64-tdep.c which sets up
    the function call is still applicable - and only a few things need
    to be done differently:  For instance, instead of changing the BSP,
    we do nothing.  We store the parameters at a different location, etc.
    So this patch also adjusts the inf-call code in ia64-tdep.c to make it
    a little more extensible: I create a new ia64_infcall_ops structure
    which allows an ABI to define how the few things that need to be
    differentiated.
    
    Another element that turned out to be necessary but is more of a detail
    is that the computation of the linkage pointer needs to be handled
    specially for symbols inside shared libraries.  This is especially
    visible when calling malloc, which happens everytime memory needs to
    be allocated in inferior memory...  The special treatment included
    again the necessity to use some routines only available on the host.
    So another target object TARGET_OBJECT_HPUX_SOLIB_GOT was created for
    that purpose.
    
    gdb/ChangeLog:
    
            * ia64-tdep.h (struct regcache): Forward declare.
            (struct ia64_infcall_ops): New struct type.
            (struct gdbarch_tdep): New fields "find_global_pointer_from_solib"
            and "infcall_ops".
            * ia64-tdep.c (ia64_find_global_pointer_from_dynamic_section):
            Renames ia64_find_global_pointer.
            (ia64_find_global_pointer, ia64_allocate_new_rse_frame)
            (ia64_store_argument_in_slot, ia64_set_function_addr: New function.
            (ia64_push_dummy_call): Adjust to use the new tdep ia64_infocall_ops
            methods.
            (ia64_infcall_ops): New static global constant.
            (ia64_gdbarch_init): Set tdep->infcall_ops.
            * ia64-hpux-nat.c (ia64_hpux_xfer_solib_got): New function.
            (ia64_hpux_xfer_partial): Add TARGET_OBJECT_HPUX_SOLIB_GOT handing.
            * ia64-hpux-tdep.c: Include "regcache.h", "gdbcore.h" and "inferior.h".
            (ia64_hpux_dummy_code): New static global constant.
            (ia64_hpux_push_dummy_code, ia64_hpux_allocate_new_rse_frame)
            (ia64_hpux_store_argument_in_slot, ia64_hpux_set_function_addr)
            (ia64_hpux_dummy_id, ia64_hpux_find_global_pointer_from_solib):
            New function.
            (ia64_hpux_infcall_ops): New static global constant.
            (ia64_hpux_init_abi): Install gdbarch and tdep methods needed
            for inferior function calls to work properly on ia64-hpux.

diff --git a/gdb/ia64-hpux-nat.c b/gdb/ia64-hpux-nat.c
index 80f7d99..53b0ed2 100644
--- a/gdb/ia64-hpux-nat.c
+++ b/gdb/ia64-hpux-nat.c
@@ -589,6 +589,40 @@ ia64_hpux_xfer_uregs (struct target_ops *ops, const char *annex,
   return len;
 }
 
+/* Handle the transfer of TARGET_OBJECT_HPUX_SOLIB_GOT objects on ia64-hpux.
+
+   The current implementation does not support write transfers (because
+   we do not currently do not need these transfers), and will raise
+   a failed assertion if WRITEBUF is not NULL.  */
+
+static LONGEST
+ia64_hpux_xfer_solib_got (struct target_ops *ops, const char *annex,
+			  gdb_byte *readbuf, const gdb_byte *writebuf,
+			  ULONGEST offset, LONGEST len)
+{
+  CORE_ADDR fun_addr;
+  /* The linkage pointer.  We use a uint64_t to make sure that the size
+     of the object we are returning is always 64 bits long, as explained
+     in the description of the TARGET_OBJECT_HPUX_SOLIB_GOT object.
+     This is probably paranoia, but we do not use a CORE_ADDR because
+     it could conceivably be larger than uint64_t.  */
+  uint64_t got;
+
+  gdb_assert (writebuf == NULL);
+
+  if (offset > sizeof (got))
+    return 0;
+
+  fun_addr = string_to_core_addr (annex);
+  got = ia64_hpux_get_solib_linkage_addr (fun_addr);
+
+  if (len > sizeof (got) - offset)
+    len = sizeof (got) - offset;
+  memcpy (readbuf, &got + offset, len);
+
+  return len;
+}
+
 /* The "to_xfer_partial" target_ops routine for ia64-hpux.  */
 
 static LONGEST
@@ -602,6 +636,9 @@ ia64_hpux_xfer_partial (struct target_ops *ops, enum target_object object,
     val = ia64_hpux_xfer_memory (ops, annex, readbuf, writebuf, offset, len);
   else if (object == TARGET_OBJECT_HPUX_UREGS)
     val = ia64_hpux_xfer_uregs (ops, annex, readbuf, writebuf, offset, len);
+  else if (object == TARGET_OBJECT_HPUX_SOLIB_GOT)
+    val = ia64_hpux_xfer_solib_got (ops, annex, readbuf, writebuf, offset,
+				    len);
   else
     val = super_xfer_partial (ops, object, annex, readbuf, writebuf, offset,
 			      len);
diff --git a/gdb/ia64-hpux-tdep.c b/gdb/ia64-hpux-tdep.c
index a4d2fa7..c03a00e 100644
--- a/gdb/ia64-hpux-tdep.c
+++ b/gdb/ia64-hpux-tdep.c
@@ -25,6 +25,133 @@
 #include "solib.h"
 #include "target.h"
 #include "frame.h"
+#include "regcache.h"
+#include "gdbcore.h"
+#include "inferior.h"
+
+/* A sequence of instructions pushed on the stack when we want to perform
+   an inferior function call.  The main purpose of this code is to save
+   the output region of the register frame belonging to the function
+   from which we are making the call.  Normally, all registers are saved
+   prior to the call, but this does not include stacked registers because
+   they are seen by GDB as pseudo registers.
+
+   On Linux, these stacked registers can be saved by simply creating
+   a new register frame, or in other words by moving the BSP.  But the
+   HP/UX kernel does not allow this.  So we rely on this code instead,
+   that makes functions calls whose only purpose is to create new
+   register frames.
+
+   The array below is the result obtained after assembling the code
+   shown below. It's an array of bytes in order to make it independent
+   of the host endianess, in case it ends up being used on more than
+   one target.
+
+   start:
+        // Save b0 before using it (into preserved reg: r4).
+        mov r4 = b0
+        ;;
+
+        br.call.dptk.few b0 = stub#
+        ;;
+
+        // Add a nop bundle where we can insert our dummy breakpoint.
+        nop.m 0
+        nop.i 0
+        nop.i 0
+        ;;
+
+   stub:
+        // Alloc a new register stack frame.  Here, we set the size
+        // of all regions to zero.  Eventually, GDB will manually
+        // change the instruction to set the size of the local region
+        // to match size of the output region of the function from
+        // which we are making the function call.  This is to protect
+        // the value of the output registers of the function from
+        // which we are making the call.
+        alloc r6 = ar.pfs, 0, 0, 0, 0
+
+        // Save b0 before using it again (into preserved reg: r5).
+        mov r5 = b0
+        ;;
+
+        //  Now that we have protected the entire output region of the
+        //  register stack frame, we can call our function that will
+        //  setup the arguments, and call our target function.
+        br.call.dptk.few b0 = call_dummy#
+        ;;
+
+        //  Restore b0, ar.pfs, and return
+        mov b0 = r5
+        mov.i ar.pfs = r6
+        ;;
+        br.ret.dptk.few b0
+        ;;
+
+   call_dummy:
+        //  Alloc a new frame, with 2 local registers, and 8 output registers
+        //  (8 output registers for the maximum of 8 slots passed by register).
+        alloc r32 = ar.pfs, 2, 0, 8, 0
+
+        //  Save b0 before using it to call our target function.
+        mov r33 = b0
+
+        // Load the argument values placed by GDB inside r14-r21 in their
+        // proper registers.
+        or r34 = r14, r0
+        or r35 = r15, r0
+        or r36 = r16, r0
+        or r37 = r17, r0
+        or r38 = r18, r0
+        or r39 = r19, r0
+        or r40 = r20, r0
+        or r41 = r21, r0
+        ;;
+
+        // actual call
+        br.call.dptk.few b0 = b1
+        ;;
+
+        mov.i ar.pfs=r32
+        mov b0=r33
+        ;;
+
+        br.ret.dptk.few b0
+        ;;
+
+*/
+
+static const gdb_byte ia64_hpux_dummy_code[] =
+{
+  0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x40, 0x00,
+  0x00, 0x62, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00,
+  0x1d, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+  0x00, 0x02, 0x00, 0x00, 0x20, 0x00, 0x00, 0x52,
+  0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+  0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00,
+  0x02, 0x30, 0x00, 0x00, 0x80, 0x05, 0x50, 0x00,
+  0x00, 0x62, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00,
+  0x1d, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+  0x00, 0x02, 0x00, 0x00, 0x30, 0x00, 0x00, 0x52,
+  0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x28,
+  0x04, 0x80, 0x03, 0x00, 0x60, 0x00, 0xaa, 0x00,
+  0x1d, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+  0x00, 0x02, 0x00, 0x80, 0x00, 0x00, 0x84, 0x02,
+  0x00, 0x00, 0x29, 0x04, 0x80, 0x05, 0x10, 0x02,
+  0x00, 0x62, 0x00, 0x40, 0xe4, 0x00, 0x38, 0x80,
+  0x00, 0x18, 0x3d, 0x00, 0x0e, 0x20, 0x40, 0x82,
+  0x00, 0x1c, 0x40, 0xa0, 0x14, 0x01, 0x38, 0x80,
+  0x00, 0x30, 0x49, 0x00, 0x0e, 0x20, 0x70, 0x9a,
+  0x00, 0x1c, 0x40, 0x00, 0x45, 0x01, 0x38, 0x80,
+  0x0a, 0x48, 0x55, 0x00, 0x0e, 0x20, 0x00, 0x00,
+  0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00,
+  0x1d, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+  0x00, 0x02, 0x00, 0x00, 0x10, 0x00, 0x80, 0x12,
+  0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+  0x01, 0x55, 0x00, 0x00, 0x10, 0x0a, 0x00, 0x07,
+  0x1d, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+  0x00, 0x02, 0x00, 0x80, 0x00, 0x00, 0x84, 0x02
+};
 
 /* The offset to be used in order to get the __reason pseudo-register
    when using one of the *UREGS ttrace requests (see system header file
@@ -126,12 +253,154 @@ ia64_hpux_size_of_register_frame (struct frame_info *this_frame,
   return sof;
 }
 
+/* Implement the push_dummy_code gdbarch method.
+
+   This function assumes that the SP is already 16-byte-aligned.  */
+
+static CORE_ADDR
+ia64_hpux_push_dummy_code (struct gdbarch *gdbarch, CORE_ADDR sp,
+			   CORE_ADDR funaddr, struct value **args, int nargs,
+			   struct type *value_type, CORE_ADDR *real_pc,
+			   CORE_ADDR *bp_addr, struct regcache *regcache)
+{
+  ULONGEST cfm;
+  int sof, sol, sor, soo;
+  char buf[16];
+
+  regcache_cooked_read_unsigned (regcache, IA64_CFM_REGNUM, &cfm);
+  sof = cfm & 0x7f;
+  sol = (cfm >> 7) & 0x7f;
+  sor = (cfm >> 14) & 0xf;
+  soo = sof - sol - sor;
+
+  /* Reserve some space on the stack to hold the dummy code.  */
+  sp = sp - sizeof (ia64_hpux_dummy_code);
+
+  /* Set the breakpoint address at the first instruction of the bundle
+     in the dummy code that has only nops.  This is where the dummy code
+     expects us to break.  */
+  *bp_addr = sp + 0x20;
+
+  /* Start the inferior function call from the dummy code.  The dummy
+     code will then call our function.  */
+  *real_pc = sp;
+
+  /* Transfer the dummy code to the inferior.  */
+  write_memory (sp, ia64_hpux_dummy_code, sizeof (ia64_hpux_dummy_code));
+
+  /* Update the size of the local portion of the register frame allocated
+     by ``stub'' to match the size of the output region of the current
+     register frame.  This allows us to save the stacked registers.
+
+     The "alloc" instruction is located at slot 0 of the bundle at +0x30.
+     Update the "sof" and "sol" portion of that instruction which are
+     respectively at bits 18-24 and 25-31 of the bundle.  */
+  memcpy (buf, ia64_hpux_dummy_code + 0x30, sizeof (buf));
+
+  buf[2] |= ((soo & 0x3f) << 2);
+  buf[3] |= (soo << 1);
+  if (soo > 63)
+    buf[3] |= 1;
+
+  write_memory (sp + 0x30, buf, sizeof (buf));
+
+  /* Return the new (already properly aligned) SP.  */
+  return sp;
+}
+
+/* The "allocate_new_rse_frame" ia64_infcall_ops routine for ia64-hpux.  */
+
+static void
+ia64_hpux_allocate_new_rse_frame (struct regcache *regcache, ULONGEST bsp,
+				  int sof)
+{
+  /* We cannot change the value of the BSP register on HP-UX,
+     so we can't allocate a new RSE frame.  */
+}
+
+/* The "store_argument_in_slot" ia64_infcall_ops routine for ia64-hpux.  */
+
+static void
+ia64_hpux_store_argument_in_slot (struct regcache *regcache, CORE_ADDR bsp,
+                                  int slotnum, gdb_byte *buf)
+{
+  /* The call sequence on this target expects us to place the arguments
+     inside r14 - r21.  */
+  regcache_cooked_write (regcache, IA64_GR0_REGNUM + 14 + slotnum, buf);
+}
+
+/* The "set_function_addr" ia64_infcall_ops routine for ia64-hpux.  */
+
+static void
+ia64_hpux_set_function_addr (struct regcache *regcache, CORE_ADDR func_addr)
+{
+  /* The calling sequence calls the function whose address is placed
+     in register b1.  */
+  regcache_cooked_write_unsigned (regcache, IA64_BR1_REGNUM, func_addr);
+}
+
+/* The ia64_infcall_ops structure for ia64-hpux.  */
+
+static const struct ia64_infcall_ops ia64_hpux_infcall_ops =
+{
+  ia64_hpux_allocate_new_rse_frame,
+  ia64_hpux_store_argument_in_slot,
+  ia64_hpux_set_function_addr
+};
+
+/* The "dummy_id" gdbarch routine for ia64-hpux.  */
+
+static struct frame_id
+ia64_hpux_dummy_id (struct gdbarch *gdbarch, struct frame_info *this_frame)
+{
+  CORE_ADDR sp, pc, bp_addr, bsp;
+
+  sp = get_frame_register_unsigned (this_frame, IA64_GR12_REGNUM);
+
+  /* Just double-check that the frame PC is within a certain region
+     of the stack that would be plausible for our dummy code (the dummy
+     code was pushed at SP + 16).  If not, then return a null frame ID.
+     This is necessary in our case, because it is possible to produce
+     the same frame ID for a normal frame, if that frame corresponds
+     to the function called by our dummy code, and the function has not
+     modified the registers that we use to build the dummy frame ID.  */
+  pc = get_frame_pc (this_frame);
+  if (pc < sp + 16 || pc >= sp + 16 + sizeof (ia64_hpux_dummy_code))
+    return null_frame_id;
+
+  /* The call sequence is such that the address of the dummy breakpoint
+     we inserted is stored in r5.  */
+  bp_addr = get_frame_register_unsigned (this_frame, IA64_GR5_REGNUM);
+
+  bsp = get_frame_register_unsigned (this_frame, IA64_BSP_REGNUM);
+
+  return frame_id_build_special (sp, bp_addr, bsp);
+}
+
 /* Should be set to non-NULL if the ia64-hpux solib module is linked in.
    This may not be the case because the shared library support code can
    only be compiled on ia64-hpux.  */
 
 struct target_so_ops *ia64_hpux_so_ops = NULL;
 
+/* The "find_global_pointer_from_solib" gdbarch_tdep routine for
+   ia64-hpux.  */
+
+static CORE_ADDR
+ia64_hpux_find_global_pointer_from_solib (struct gdbarch *gdbarch,
+					  CORE_ADDR faddr)
+{
+  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+  struct target_ops *ops = &current_target;
+  gdb_byte buf[8];
+  LONGEST len;
+
+  len = target_read (ops, TARGET_OBJECT_HPUX_SOLIB_GOT,
+		     paddress (gdbarch, faddr), buf, 0, sizeof (buf));
+
+  return extract_unsigned_integer (buf, len, byte_order);
+}
+
 static void
 ia64_hpux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
 {
@@ -142,6 +411,14 @@ ia64_hpux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
   set_gdbarch_long_double_format (gdbarch, floatformats_ia64_quad);
   set_gdbarch_cannot_store_register (gdbarch, ia64_hpux_cannot_store_register);
 
+  /* Inferior functions must be called from stack. */
+  set_gdbarch_call_dummy_location (gdbarch, ON_STACK);
+  set_gdbarch_push_dummy_code (gdbarch, ia64_hpux_push_dummy_code);
+  tdep->infcall_ops = ia64_hpux_infcall_ops;
+  tdep->find_global_pointer_from_solib
+      = ia64_hpux_find_global_pointer_from_solib;
+  set_gdbarch_dummy_id (gdbarch, ia64_hpux_dummy_id);
+
   if (ia64_hpux_so_ops)
     set_solib_ops (gdbarch, ia64_hpux_so_ops);
 }
diff --git a/gdb/ia64-tdep.c b/gdb/ia64-tdep.c
index 1cfffc7..ac7dd0e 100644
--- a/gdb/ia64-tdep.c
+++ b/gdb/ia64-tdep.c
@@ -3386,7 +3386,8 @@ slot_alignment_is_next_even (struct type *t)
    d_un.d_ptr value is the global pointer.  */
 
 static CORE_ADDR
-ia64_find_global_pointer (struct gdbarch *gdbarch, CORE_ADDR faddr)
+ia64_find_global_pointer_from_dynamic_section (struct gdbarch *gdbarch,
+					       CORE_ADDR faddr)
 {
   enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
   struct obj_section *faddr_sect;
@@ -3444,6 +3445,24 @@ ia64_find_global_pointer (struct gdbarch *gdbarch, CORE_ADDR faddr)
   return 0;
 }
 
+/* Attempt to find (and return) the global pointer for the given
+   function.  We first try the find_global_pointer_from_solib routine
+   from the gdbarch tdep vector, if provided.  And if that does not
+   work, then we try ia64_find_global_pointer_from_dynamic_section.  */
+
+static CORE_ADDR
+ia64_find_global_pointer (struct gdbarch *gdbarch, CORE_ADDR faddr)
+{
+  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+  CORE_ADDR addr = 0;
+
+  if (tdep->find_global_pointer_from_solib)
+    addr = tdep->find_global_pointer_from_solib (gdbarch, faddr);
+  if (addr == 0)
+    addr = ia64_find_global_pointer_from_dynamic_section (gdbarch, faddr);
+  return addr;
+}
+
 /* Given a function's address, attempt to find (and return) the
    corresponding (canonical) function descriptor.  Return 0 if
    not found.  */
@@ -3583,12 +3602,53 @@ ia64_frame_align (struct gdbarch *gdbarch, CORE_ADDR sp)
   return sp & ~0xfLL;
 }
 
+/* The default "allocate_new_rse_frame" ia64_infcall_ops routine for ia64.  */
+
+static void
+ia64_allocate_new_rse_frame (struct regcache *regcache, ULONGEST bsp, int sof)
+{
+  ULONGEST cfm, pfs, new_bsp;
+
+  regcache_cooked_read_unsigned (regcache, IA64_CFM_REGNUM, &cfm);
+
+  new_bsp = rse_address_add (bsp, sof);
+  regcache_cooked_write_unsigned (regcache, IA64_BSP_REGNUM, new_bsp);
+
+  regcache_cooked_read_unsigned (regcache, IA64_PFS_REGNUM, &pfs);
+  pfs &= 0xc000000000000000LL;
+  pfs |= (cfm & 0xffffffffffffLL);
+  regcache_cooked_write_unsigned (regcache, IA64_PFS_REGNUM, pfs);
+
+  cfm &= 0xc000000000000000LL;
+  cfm |= sof;
+  regcache_cooked_write_unsigned (regcache, IA64_CFM_REGNUM, cfm);
+}
+
+/* The default "store_argument_in_slot" ia64_infcall_ops routine for
+   ia64.  */
+
+static void
+ia64_store_argument_in_slot (struct regcache *regcache, CORE_ADDR bsp,
+			     int slotnum, gdb_byte *buf)
+{
+  write_memory (rse_address_add (bsp, slotnum), buf, 8);
+}
+
+/* The default "set_function_addr" ia64_infcall_ops routine for ia64.  */
+
+static void
+ia64_set_function_addr (struct regcache *regcache, CORE_ADDR func_addr)
+{
+  /* Nothing needed.  */
+}
+
 static CORE_ADDR
 ia64_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
 		      struct regcache *regcache, CORE_ADDR bp_addr,
 		      int nargs, struct value **args, CORE_ADDR sp,
 		      int struct_return, CORE_ADDR struct_addr)
 {
+  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
   enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
   int argno;
   struct value *arg;
@@ -3596,7 +3656,7 @@ ia64_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
   int len, argoffset;
   int nslots, rseslots, memslots, slotnum, nfuncargs;
   int floatreg;
-  ULONGEST bsp, cfm, pfs, new_bsp;
+  ULONGEST bsp;
   CORE_ADDR funcdescaddr, pc, global_pointer;
   CORE_ADDR func_addr = find_function_addr (function, NULL);
 
@@ -3623,20 +3683,8 @@ ia64_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
   memslots = nslots - rseslots;
 
   /* Allocate a new RSE frame.  */
-  regcache_cooked_read_unsigned (regcache, IA64_CFM_REGNUM, &cfm);
-
   regcache_cooked_read_unsigned (regcache, IA64_BSP_REGNUM, &bsp);
-  new_bsp = rse_address_add (bsp, rseslots);
-  regcache_cooked_write_unsigned (regcache, IA64_BSP_REGNUM, new_bsp);
-
-  regcache_cooked_read_unsigned (regcache, IA64_PFS_REGNUM, &pfs);
-  pfs &= 0xc000000000000000LL;
-  pfs |= (cfm & 0xffffffffffffLL);
-  regcache_cooked_write_unsigned (regcache, IA64_PFS_REGNUM, pfs);
-
-  cfm &= 0xc000000000000000LL;
-  cfm |= rseslots;
-  regcache_cooked_write_unsigned (regcache, IA64_CFM_REGNUM, cfm);
+  tdep->infcall_ops.allocate_new_rse_frame (regcache, bsp, rseslots);
   
   /* We will attempt to find function descriptors in the .opd segment,
      but if we can't we'll construct them ourselves.  That being the
@@ -3676,7 +3724,8 @@ ia64_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
 				  find_func_descr (regcache, faddr,
 						   &funcdescaddr));
 	  if (slotnum < rseslots)
-	    write_memory (rse_address_add (bsp, slotnum), val_buf, 8);
+	    tdep->infcall_ops.store_argument_in_slot (regcache, bsp,
+						      slotnum, val_buf);
 	  else
 	    write_memory (sp + 16 + 8 * (slotnum - rseslots), val_buf, 8);
 	  slotnum++;
@@ -3721,7 +3770,8 @@ ia64_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
             }
 
 	  if (slotnum < rseslots)
-	    write_memory (rse_address_add (bsp, slotnum), val_buf, 8);
+	    tdep->infcall_ops.store_argument_in_slot (regcache, bsp,
+						      slotnum, val_buf);
 	  else
 	    write_memory (sp + 16 + 8 * (slotnum - rseslots), val_buf, 8);
 
@@ -3760,13 +3810,27 @@ ia64_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
   if (global_pointer != 0)
     regcache_cooked_write_unsigned (regcache, IA64_GR1_REGNUM, global_pointer);
 
+  /* The following is not necessary on HP-UX, because we're using
+     a dummy code sequence pushed on the stack to make the call, and
+     this sequence doesn't need b0 to be set in order for our dummy
+     breakpoint to be hit.  Nonetheless, this doesn't interfere, and
+     it's needed for other OSes, so we do this unconditionaly.  */
   regcache_cooked_write_unsigned (regcache, IA64_BR0_REGNUM, bp_addr);
 
   regcache_cooked_write_unsigned (regcache, sp_regnum, sp);
 
+  tdep->infcall_ops.set_function_addr (regcache, func_addr);
+
   return sp;
 }
 
+static const struct ia64_infcall_ops ia64_infcall_ops =
+{
+  ia64_allocate_new_rse_frame,
+  ia64_store_argument_in_slot,
+  ia64_set_function_addr
+};
+
 static struct frame_id
 ia64_dummy_id (struct gdbarch *gdbarch, struct frame_info *this_frame)
 {
@@ -3883,6 +3947,7 @@ ia64_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
 
   /* Settings for calling functions in the inferior.  */
   set_gdbarch_push_dummy_call (gdbarch, ia64_push_dummy_call);
+  tdep->infcall_ops = ia64_infcall_ops;
   set_gdbarch_frame_align (gdbarch, ia64_frame_align);
   set_gdbarch_dummy_id (gdbarch, ia64_dummy_id);
 
diff --git a/gdb/ia64-tdep.h b/gdb/ia64-tdep.h
index b88031e..99ef368 100644
--- a/gdb/ia64-tdep.h
+++ b/gdb/ia64-tdep.h
@@ -196,6 +196,32 @@
 #define IA64_NAT127_REGNUM	(IA64_NAT0_REGNUM + 127)
 
 struct frame_info;
+struct regcache;
+
+/* A struction containing pointers to all the target-dependent operations
+   performed to setup an inferior function call. */
+
+struct ia64_infcall_ops
+{
+  /* Allocate a new register stack frame starting after the output
+     region of the current frame.  The new frame will contain SOF
+     registers, all in the output region.  This is one way of protecting
+     the stacked registers of the current frame.
+
+     Should do nothing if this operation is not permitted by the OS.  */
+  void (*allocate_new_rse_frame) (struct regcache *regcache, ULONGEST bsp,
+				  int sof);
+
+  /* Store the argument stored in BUF into the appropriate location
+     given the BSP and the SLOTNUM.  */
+  void (*store_argument_in_slot) (struct regcache *regcache, CORE_ADDR bsp,
+                                  int slotnum, gdb_byte *buf);
+
+  /* For targets where we cannot call the function directly, store
+     the address of the function we want to call at the location
+     expected by the calling sequence.  */
+  void (*set_function_addr) (struct regcache *regcache, CORE_ADDR func_addr);
+};
 
 struct gdbarch_tdep
 {
@@ -209,8 +235,18 @@ struct gdbarch_tdep
      extracting the lowest 7 bits ("cfm & 0x7f").  */
   int (*size_of_register_frame) (struct frame_info *this_frame, ULONGEST cfm);
 
+  /* Determine the function address FADDR belongs to a shared library.
+     If it does, then return the associated global pointer.  If no shared
+     library was found to contain that function, then return zero.
+
+     This pointer may be NULL.  */
+  CORE_ADDR (*find_global_pointer_from_solib) (struct gdbarch *gdbarch,
+					       CORE_ADDR faddr);
+
   /* ISA-specific data types.  */
   struct type *ia64_ext_type;
+
+  struct ia64_infcall_ops infcall_ops;
 };
 
 extern void ia64_write_pc (struct regcache *, CORE_ADDR);
diff --git a/gdb/target.h b/gdb/target.h
index 24221ce..a0b8f0e 100644
--- a/gdb/target.h
+++ b/gdb/target.h
@@ -268,6 +268,12 @@ enum target_object
   /* The HP-UX registers (those that can be obtained or modified by using
      the TT_LWP_RUREGS/TT_LWP_WUREGS ttrace requests).  */
   TARGET_OBJECT_HPUX_UREGS,
+  /* The HP-UX shared library linkage pointer.  ANNEX should be a string
+     image of the code address whose linkage pointer we are looking for.
+
+     The size of the data transfered is always 8 bytes (the size of an
+     address on ia64).  */
+  TARGET_OBJECT_HPUX_SOLIB_GOT,
   /* Possible future objects: TARGET_OBJECT_FILE, ... */
 };
 

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH 6/8] port GDB to ia64-hpux (native).
  2010-12-28  4:44 ` [PATCH 6/8] port GDB to ia64-hpux (native) Joel Brobecker
@ 2011-01-11 23:26   ` Steve Ellcey
  2011-01-12  1:26     ` Joel Brobecker
  2011-01-13  1:01     ` Joel Brobecker
  2011-01-13 18:07   ` Joel Brobecker
  1 sibling, 2 replies; 31+ messages in thread
From: Steve Ellcey @ 2011-01-11 23:26 UTC (permalink / raw)
  To: Joel Brobecker; +Cc: gdb-patches

Joel,

I tried building a native ia64-hpux gdb using your patches and I got
this failure:

/proj/opensrc/nightly/src/src/gdb/ia64-hpux-nat.c: In function 'ia64_hpux_fetch_rnat_register':
/proj/opensrc/nightly/src/src/gdb/ia64-hpux-nat.c:188:5: error: format '%lx' expects type 'long unsigned int', but argument 2 has type 'CORE_ADDR'

It looks like CORE_ADDR is defined as bfd_vma and bfd_vma is defined as
'unsigned long long' on ia64-hpux.  I changed %lx to %llx and that seems
to have fixed the problem.

After fixing that I get the similar errors at lines 134, 209, and 462 of
solib-ia64-hpux.c and made the same change and was able to do a complete
build of gdb.

I then ran the testsuite and here are the base results.

gdb.base1 results:


                === gdb Summary ===

# of expected passes            3328
# of unexpected failures        455
# of unexpected successes       2
# of expected failures          8
# of known failures             19
# of unresolved testcases       1
# of untested testcases         5
# of unsupported tests          6

gdb.base2 results:

                === gdb Summary ===

# of expected passes            3092
# of unexpected failures        942
# of expected failures          1
# of known failures             4
# of untested testcases         10
# of unsupported tests          3


Steve Ellcey
sje@cup.hp.com

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH 6/8] port GDB to ia64-hpux (native).
  2011-01-11 23:26   ` Steve Ellcey
@ 2011-01-12  1:26     ` Joel Brobecker
  2011-01-12 16:57       ` Steve Ellcey
  2011-01-13  1:01     ` Joel Brobecker
  1 sibling, 1 reply; 31+ messages in thread
From: Joel Brobecker @ 2011-01-12  1:26 UTC (permalink / raw)
  To: Steve Ellcey; +Cc: gdb-patches

> /proj/opensrc/nightly/src/src/gdb/ia64-hpux-nat.c: In function 'ia64_hpux_fetch_rnat_register':
> /proj/opensrc/nightly/src/src/gdb/ia64-hpux-nat.c:188:5: error: format '%lx' expects type 'long unsigned int', but argument 2 has type 'CORE_ADDR'

That is indeed a mistake, and I don't know why I didn't see them.
but I will fix them.

Thanks!

-- 
Joel

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH 6/8] port GDB to ia64-hpux (native).
  2011-01-12  1:26     ` Joel Brobecker
@ 2011-01-12 16:57       ` Steve Ellcey
  2011-01-12 20:11         ` Joel Brobecker
  0 siblings, 1 reply; 31+ messages in thread
From: Steve Ellcey @ 2011-01-12 16:57 UTC (permalink / raw)
  To: Joel Brobecker; +Cc: gdb-patches

On Tue, 2011-01-11 at 19:29 -0500, Joel Brobecker wrote:
> > /proj/opensrc/nightly/src/src/gdb/ia64-hpux-nat.c: In function 'ia64_hpux_fetch_rnat_register':
> > /proj/opensrc/nightly/src/src/gdb/ia64-hpux-nat.c:188:5: error: format '%lx' expects type 'long unsigned int', but argument 2 has type 'CORE_ADDR'
> 
> That is indeed a mistake, and I don't know why I didn't see them.
> but I will fix them.
> 
> Thanks!

Did you do your builds in 32 or 64 bit mode?  I built gdb in 32 bit mode
since that is the default on IA64 HP-UX.

Steve Ellcey
sje@cup.hp.com

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH 6/8] port GDB to ia64-hpux (native).
  2011-01-12 16:57       ` Steve Ellcey
@ 2011-01-12 20:11         ` Joel Brobecker
  0 siblings, 0 replies; 31+ messages in thread
From: Joel Brobecker @ 2011-01-12 20:11 UTC (permalink / raw)
  To: Steve Ellcey; +Cc: gdb-patches

> Did you do your builds in 32 or 64 bit mode?  I built gdb in 32 bit mode
> since that is the default on IA64 HP-UX.

I was building in 64bit mode.

-- 
Joel

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH 6/8] port GDB to ia64-hpux (native).
  2011-01-11 23:26   ` Steve Ellcey
  2011-01-12  1:26     ` Joel Brobecker
@ 2011-01-13  1:01     ` Joel Brobecker
  2011-01-13  5:13       ` Steve Ellcey
       [not found]       ` <1299014508.30497.20.camel@hpsje.cup.hp.com>
  1 sibling, 2 replies; 31+ messages in thread
From: Joel Brobecker @ 2011-01-13  1:01 UTC (permalink / raw)
  To: Steve Ellcey; +Cc: gdb-patches

I'm doing the final checks before committing the corrected version.
But something caught my attention:

> I then ran the testsuite and here are the base results.
> 
> gdb.base1 results:

You are getting considerably more failures than I am. I think
they could be explain by 2 factors (but I am only guessing):
  - I use GNU libunwind (or a modified version of 0.98);
    That makes a real difference in our case, compared to using
    the system libunwind.
  - the 32bit mode might make a difference as well; not sure.

-- 
Joel

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH 6/8] port GDB to ia64-hpux (native).
  2011-01-13  1:01     ` Joel Brobecker
@ 2011-01-13  5:13       ` Steve Ellcey
       [not found]       ` <1299014508.30497.20.camel@hpsje.cup.hp.com>
  1 sibling, 0 replies; 31+ messages in thread
From: Steve Ellcey @ 2011-01-13  5:13 UTC (permalink / raw)
  To: Joel Brobecker; +Cc: gdb-patches

On Wed, 2011-01-12 at 18:16 -0500, Joel Brobecker wrote:
> I'm doing the final checks before committing the corrected version.
> But something caught my attention:
> 
> > I then ran the testsuite and here are the base results.
> > 
> > gdb.base1 results:
> 
> You are getting considerably more failures than I am. I think
> they could be explain by 2 factors (but I am only guessing):
>   - I use GNU libunwind (or a modified version of 0.98);
>     That makes a real difference in our case, compared to using
>     the system libunwind.

I am using the system libunwind.

>   - the 32bit mode might make a difference as well; not sure.

I was wondering if this was an issue or not, I tried debugging the
latest GCC using the GDB I built and I couldn't get decent backtraces.
I thought it might be a 32/64 bit issue, but perhaps it is the
system libunwind.

Steve Ellcey
sje@cup.hp.com


^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: Porting GDB to ia64-hpux
  2010-12-28  4:43 Porting GDB to ia64-hpux Joel Brobecker
                   ` (7 preceding siblings ...)
  2010-12-28  5:00 ` [PATCH 8/8] [ia64-hpux] inferior function call support Joel Brobecker
@ 2011-01-13 16:53 ` Joel Brobecker
  8 siblings, 0 replies; 31+ messages in thread
From: Joel Brobecker @ 2011-01-13 16:53 UTC (permalink / raw)
  To: gdb-patches

FYI: I've checked in the patch series.

I made the changes that should allow Steve to build without having
to tweak.  I will post an updated patch ASAP.

-- 
Joel

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH 6/8] port GDB to ia64-hpux (native).
  2010-12-28  4:44 ` [PATCH 6/8] port GDB to ia64-hpux (native) Joel Brobecker
  2011-01-11 23:26   ` Steve Ellcey
@ 2011-01-13 18:07   ` Joel Brobecker
  1 sibling, 0 replies; 31+ messages in thread
From: Joel Brobecker @ 2011-01-13 18:07 UTC (permalink / raw)
  To: gdb-patches

[-- Attachment #1: Type: text/plain, Size: 73 bytes --]

Here is the version of this patch that I ended up checking in.

-- 
Joel

[-- Attachment #2: 06-add-support-for-ia64-hpux.diff --]
[-- Type: text/x-diff, Size: 55205 bytes --]

commit 3764b95731a868544ee034cb43d0c0f9f3d1b7aa
Author: Joel Brobecker <brobecker@adacore.com>
Date:   Wed Dec 15 07:58:34 2010 -0500

    port GDB to ia64-hpux (native).
    
    ChangeLog:
    
            * configure.ac: Remove readline, mmalloc, and gdb from noconfigdirs
            for ia64-hpux.
            * configure: Regenerate.
    
    gdb/ChangeLog:
    
            * config/ia64/hpux.mh, ia64-hpux-nat.c, ia64-hpux-tdep.c,
            ia64-hpux-tdep.h, solib-ia64-hpux.c, solib-ia64-hpux.h: New files.
    
            * configure.host: Add handling for ia64-hpux hosts.  Add associated
            floatformats.
            * configure.tgt: Add handling for ia64-hpux targets.
            * Makefile.in (ALL_64_TARGET_OBS): Add ia64-hpux-tdep.o.
            (HFILES_NO_SRCDIR): Add ia64-hpux-tdep.h.
            (ALLDEPFILES): Add ia64-hpux-nat.c ia64-hpux-tdep.c.

diff --git a/ChangeLog b/ChangeLog
index 5a48a71..668a60c 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,9 @@
+2011-01-13  Joel Brobecker  <brobecker@adacore.com>
+
+	* configure.ac: Remove readline, mmalloc, and gdb from noconfigdirs
+	for ia64-hpux.
+	* configure: Regenerate.
+
 2011-01-02  Ralf Wildenhues  <Ralf.Wildenhues@gmx.de>
 
 	Sync from GCC:
diff --git a/configure b/configure
index 66ca5d3..5e469f4 100755
--- a/configure
+++ b/configure
@@ -3353,8 +3353,8 @@ case "${target}" in
     noconfigdirs="$noconfigdirs readline mmalloc libgui itcl gdb"
     ;;
   ia64*-**-hpux*)
-    # No gdb or ld support yet.
-    noconfigdirs="$noconfigdirs ${libgcj} readline mmalloc libgui itcl gdb ld"
+    # No ld support yet.
+    noconfigdirs="$noconfigdirs ${libgcj} libgui itcl ld"
     ;;
   ia64*-*-*vms*)
     # No gdb or ld support yet.
diff --git a/configure.ac b/configure.ac
index 4807ffb..c7a86e2 100644
--- a/configure.ac
+++ b/configure.ac
@@ -804,8 +804,8 @@ case "${target}" in
     noconfigdirs="$noconfigdirs readline mmalloc libgui itcl gdb"
     ;;
   ia64*-**-hpux*)
-    # No gdb or ld support yet.
-    noconfigdirs="$noconfigdirs ${libgcj} readline mmalloc libgui itcl gdb ld"
+    # No ld support yet.
+    noconfigdirs="$noconfigdirs ${libgcj} libgui itcl ld"
     ;;
   ia64*-*-*vms*)
     # No gdb or ld support yet.
diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index e8acfd8..814b0dc 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,5 +1,18 @@
 2011-01-13  Joel Brobecker  <brobecker@adacore.com>
 
+	Add support for ia64-hpux.
+	* config/ia64/hpux.mh, ia64-hpux-nat.c, ia64-hpux-tdep.c,
+	ia64-hpux-tdep.h, solib-ia64-hpux.c, solib-ia64-hpux.h: New files.
+
+	* configure.host: Add handling for ia64-hpux hosts.  Add associated
+	floatformats.
+	* configure.tgt: Add handling for ia64-hpux targets.
+	* Makefile.in (ALL_64_TARGET_OBS): Add ia64-hpux-tdep.o.
+	(HFILES_NO_SRCDIR): Add ia64-hpux-tdep.h.
+	(ALLDEPFILES): Add ia64-hpux-nat.c ia64-hpux-tdep.c.
+
+2011-01-13  Joel Brobecker  <brobecker@adacore.com>
+
 	[ttrace] Compute thread list immediately after attach.
 	* inf_ttrace_attach (inf_ttrace_create_threads_after_attach):
 	New subprogram.
diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index 9459de4..fc03b0c 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -497,7 +497,7 @@ ALL_64_TARGET_OBS = \
 	amd64fbsd-tdep.o amd64-darwin-tdep.o amd64-dicos-tdep.o \
 	amd64-linux-tdep.o amd64nbsd-tdep.o \
 	amd64obsd-tdep.o amd64-sol2-tdep.o amd64-tdep.o amd64-windows-tdep.o \
-	ia64-linux-tdep.o ia64-tdep.o \
+	ia64-hpux-tdep.o ia64-linux-tdep.o ia64-tdep.o \
 	mips64obsd-tdep.o \
 	sparc64fbsd-tdep.o sparc64-linux-tdep.o sparc64nbsd-tdep.o \
 	sparc64obsd-tdep.o sparc64-sol2-tdep.o sparc64-tdep.o
@@ -783,7 +783,7 @@ annotate.h sim-regno.h dictionary.h dfp.h main.h frame-unwind.h	\
 remote-fileio.h i386-linux-tdep.h vax-tdep.h objc-lang.h \
 sentinel-frame.h bcache.h symfile.h windows-tdep.h linux-tdep.h \
 gdb_usleep.h jit.h xml-syscall.h ada-operator.inc microblaze-tdep.h \
-psymtab.h psympriv.h progspace.h bfin-tdep.h
+psymtab.h psympriv.h progspace.h bfin-tdep.h ia64-hpux-tdep.h
 
 # Header files that already have srcdir in them, or which are in objdir.
 
@@ -1445,6 +1445,7 @@ ALLDEPFILES = \
 	i386-linux-tdep.c i386-nat.c \
 	i386-sol2-nat.c i386-sol2-tdep.c \
 	i386gnu-nat.c i386gnu-tdep.c \
+	ia64-hpux-nat.c ia64-hpux-tdep.c \
 	ia64-linux-nat.c ia64-linux-tdep.c ia64-tdep.c \
 	inf-ptrace.c inf-ttrace.c \
 	irix5-nat.c \
diff --git a/gdb/config/ia64/hpux.mh b/gdb/config/ia64/hpux.mh
new file mode 100644
index 0000000..b75763b
--- /dev/null
+++ b/gdb/config/ia64/hpux.mh
@@ -0,0 +1,3 @@
+# Host: ia64 running HP-UX
+NATDEPFILES= fork-child.o inf-ttrace.o corelow.o ia64-hpux-nat.o \
+        solib-ia64-hpux.o
diff --git a/gdb/configure.host b/gdb/configure.host
index 794eeee..bcebdaf 100644
--- a/gdb/configure.host
+++ b/gdb/configure.host
@@ -105,6 +105,7 @@ i[34567]86-*-solaris2.1[0-9]* | x86_64-*-solaris2.1[0-9]*)
 i[34567]86-*-solaris*)	gdb_host=i386sol2 ;;
 i[34567]86-*-cygwin*)	gdb_host=cygwin ;;
 
+ia64-*-hpux*)		gdb_host=hpux ;;
 ia64-*-linux*)		gdb_host=linux ;;
 
 m68*-*-linux*)		gdb_host=linux ;;
@@ -202,6 +203,11 @@ m68*-*-*)
 	gdb_host_double_format="&floatformat_ieee_double_big"
 	gdb_host_long_double_format="&floatformat_m68881_ext"
 	;;
+ia64-*-hpux*)
+	gdb_host_float_format="&floatformat_ieee_single_big"
+	gdb_host_double_format="&floatformat_ieee_double_big"
+	gdb_host_long_double_format="&floatformat_ia64_quad_big"
+	;;
 *)
 	gdb_host_float_format=0
 	gdb_host_double_format=0
diff --git a/gdb/configure.tgt b/gdb/configure.tgt
index f2937d8..fd0570b 100644
--- a/gdb/configure.tgt
+++ b/gdb/configure.tgt
@@ -244,6 +244,10 @@ i[34567]86-*-*)
 	gdb_target_obs="i386-tdep.o i387-tdep.o"
 	;;
 
+ia64-*-hpux*)
+	# Target: Intel IA-64 running HP-UX
+	gdb_target_obs="ia64-tdep.o ia64-hpux-tdep.o"
+	;;
 ia64-*-linux*)
 	# Target: Intel IA-64 running GNU/Linux
 	gdb_target_obs="ia64-tdep.o ia64-linux-tdep.o linux-tdep.o \
diff --git a/gdb/ia64-hpux-nat.c b/gdb/ia64-hpux-nat.c
new file mode 100644
index 0000000..ca1c278
--- /dev/null
+++ b/gdb/ia64-hpux-nat.c
@@ -0,0 +1,642 @@
+/* Copyright (C) 2010 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#include "defs.h"
+#include "ia64-tdep.h"
+#include "inferior.h"
+#include "inf-ttrace.h"
+#include "regcache.h"
+#include "solib-ia64-hpux.h"
+
+#include <ia64/sys/uregs.h>
+#include <sys/ttrace.h>
+
+/* The offsets used with ttrace to read the value of the raw registers.  */
+
+static int u_offsets[] =
+{ /* Static General Registers.  */
+  -1,     __r1,   __r2,   __r3,   __r4,   __r5,   __r6,   __r7,
+  __r8,   __r9,   __r10,  __r11,  __r12,  __r13,  __r14,  __r15,
+  __r16,  __r17,  __r18,  __r19,  __r20,  __r21,  __r22,  __r23,
+  __r24,  __r25,  __r26,  __r27,  __r28,  __r29,  __r30,  __r31,
+  -1,     -1,     -1,     -1,     -1,     -1,     -1,     -1,
+  -1,     -1,     -1,     -1,     -1,     -1,     -1,     -1,
+  -1,     -1,     -1,     -1,     -1,     -1,     -1,     -1,
+  -1,     -1,     -1,     -1,     -1,     -1,     -1,     -1,
+  -1,     -1,     -1,     -1,     -1,     -1,     -1,     -1,
+  -1,     -1,     -1,     -1,     -1,     -1,     -1,     -1,
+  -1,     -1,     -1,     -1,     -1,     -1,     -1,     -1,
+  -1,     -1,     -1,     -1,     -1,     -1,     -1,     -1,
+  -1,     -1,     -1,     -1,     -1,     -1,     -1,     -1,
+  -1,     -1,     -1,     -1,     -1,     -1,     -1,     -1,
+  -1,     -1,     -1,     -1,     -1,     -1,     -1,     -1,
+  -1,     -1,     -1,     -1,     -1,     -1,     -1,     -1,
+
+  /* Static Floating-Point Registers.  */
+    -1,     -1,   __f2,   __f3,   __f4,   __f5,   __f6,   __f7,
+  __f8,   __f9,   __f10,  __f11,  __f12,  __f13,  __f14,  __f15,
+  __f16,  __f17,  __f18,  __f19,  __f20,  __f21,  __f22,  __f23,
+  __f24,  __f25,  __f26,  __f27,  __f28,  __f29,  __f30,  __f31,
+  __f32,  __f33,  __f34,  __f35,  __f36,  __f37,  __f38,  __f39,
+  __f40,  __f41,  __f42,  __f43,  __f44,  __f45,  __f46,  __f47,
+  __f48,  __f49,  __f50,  __f51,  __f52,  __f53,  __f54,  __f55,
+  __f56,  __f57,  __f58,  __f59,  __f60,  __f61,  __f62,  __f63,
+  __f64,  __f65,  __f66,  __f67,  __f68,  __f69,  __f70,  __f71,
+  __f72,  __f73,  __f74,  __f75,  __f76,  __f77,  __f78,  __f79,
+  __f80,  __f81,  __f82,  __f83,  __f84,  __f85,  __f86,  __f87,
+  __f88,  __f89,  __f90,  __f91,  __f92,  __f93,  __f94,  __f95,
+  __f96,  __f97,  __f98,  __f99,  __f100, __f101, __f102, __f103,
+  __f104, __f105, __f106, __f107, __f108, __f109, __f110, __f111,
+  __f112, __f113, __f114, __f115, __f116, __f117, __f118, __f119,
+  __f120, __f121, __f122, __f123, __f124, __f125, __f126, __f127,
+
+  -1,     -1,     -1,     -1,     -1,     -1,     -1,     -1,
+  -1,     -1,     -1,     -1,     -1,     -1,     -1,     -1,
+  -1,     -1,     -1,     -1,     -1,     -1,     -1,     -1,
+  -1,     -1,     -1,     -1,     -1,     -1,     -1,     -1,
+  -1,     -1,     -1,     -1,     -1,     -1,     -1,     -1,
+  -1,     -1,     -1,     -1,     -1,     -1,     -1,     -1,
+  -1,     -1,     -1,     -1,     -1,     -1,     -1,     -1,
+  -1,     -1,     -1,     -1,     -1,     -1,     -1,     -1,
+
+  /* Branch Registers.  */
+  __b0,   __b1,   __b2,   __b3,   __b4,   __b5,   __b6,   __b7,
+
+  /* Virtual frame pointer and virtual return address pointer.  */
+  -1, -1,
+
+  /* Other registers.  */
+  __pr, __ip, __cr_ipsr, __cfm,
+
+  /* Kernel registers.  */
+  -1,   -1,   -1,   -1,
+  -1,   -1,   -1,   -1,
+
+  -1, -1, -1, -1, -1, -1, -1, -1,
+
+  /* Some application registers.  */
+  __ar_rsc, __ar_bsp, __ar_bspstore, __ar_rnat,
+
+  -1,
+  -1,  /* Not available: FCR, IA32 floating control register.  */
+  -1, -1,
+
+  -1,         /* Not available: EFLAG.  */
+  -1,         /* Not available: CSD.  */
+  -1,         /* Not available: SSD.  */
+  -1,         /* Not available: CFLG.  */
+  -1,         /* Not available: FSR.  */
+  -1,         /* Not available: FIR.  */
+  -1,         /* Not available: FDR.  */
+  -1,
+  __ar_ccv, -1, -1, -1, __ar_unat, -1, -1, -1,
+  __ar_fpsr, -1, -1, -1,
+  -1,         /* Not available: ITC.  */
+  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+  -1, -1, -1, -1, -1, -1, -1, -1, -1,
+  __ar_pfs, __ar_lc, __ar_ec,
+  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+  -1
+  /* All following registers, starting with nat0, are handled as
+     pseudo registers, and hence are handled separately.  */
+};
+
+/* Some register have a fixed value and can not be modified.
+   Store their value in static constant buffers that can be used
+   later to fill the register cache.  */
+static const char r0_value[8] = {0x00, 0x00, 0x00, 0x00,
+                                 0x00, 0x00, 0x00, 0x00};
+static const char f0_value[16] = {0x00, 0x00, 0x00, 0x00,
+                                  0x00, 0x00, 0x00, 0x00,
+                                  0x00, 0x00, 0x00, 0x00,
+                                  0x00, 0x00, 0x00, 0x00};
+static const char f1_value[16] = {0x00, 0x00, 0x00, 0x00,
+                                  0x00, 0x00, 0xff, 0xff,
+                                  0x80, 0x00, 0x00, 0x00,
+                                  0x00, 0x00, 0x00, 0x00};
+
+/* The "to_wait" routine from the "inf-ttrace" layer.  */
+
+static ptid_t (*super_to_wait) (struct target_ops *, ptid_t,
+				struct target_waitstatus *, int);
+
+/* The "to_wait" target_ops routine routine for ia64-hpux.  */
+
+static ptid_t
+ia64_hpux_wait (struct target_ops *ops, ptid_t ptid,
+		struct target_waitstatus *ourstatus, int options)
+{
+  ptid_t new_ptid;
+
+  new_ptid = super_to_wait (ops, ptid, ourstatus, options);
+
+  /* If this is a DLD event (hard-coded breakpoint instruction
+     that was activated by the solib-ia64-hpux module), we need to
+     process it, and then resume the execution as if the event did
+     not happen.  */
+  if (ourstatus->kind == TARGET_WAITKIND_STOPPED
+      && ourstatus->value.sig == TARGET_SIGNAL_TRAP
+      && ia64_hpux_at_dld_breakpoint_p (new_ptid))
+    {
+      ia64_hpux_handle_dld_breakpoint (new_ptid);
+
+      target_resume (new_ptid, 0, TARGET_SIGNAL_0);
+      ourstatus->kind = TARGET_WAITKIND_IGNORE;
+    }
+
+  return new_ptid;
+}
+
+/* Fetch the RNAT register and supply it to the REGCACHE.  */
+
+static void
+ia64_hpux_fetch_rnat_register (struct regcache *regcache)
+{
+  CORE_ADDR addr;
+  gdb_byte buf[8];
+  int status;
+
+  /* The value of RNAT is stored at bsp|0x1f8, and must be read using
+     TT_LWP_RDRSEBS.  */
+
+  regcache_raw_read_unsigned (regcache, IA64_BSP_REGNUM, &addr);
+  addr |= 0x1f8;
+
+  status = ttrace (TT_LWP_RDRSEBS, ptid_get_pid (inferior_ptid),
+		   ptid_get_lwp (inferior_ptid), addr, sizeof (buf),
+		   (uintptr_t) buf);
+  if (status < 0)
+    error (_("failed to read RNAT register at %s"),
+	   paddress (get_regcache_arch(regcache), addr));
+
+  regcache_raw_supply (regcache, IA64_RNAT_REGNUM, buf);
+}
+
+/* Read the value of the register saved at OFFSET in the save_state_t
+   structure, and store its value in BUF.  LEN is the size of the register
+   to be read.  */
+
+static int
+ia64_hpux_read_register_from_save_state_t (int offset, gdb_byte *buf, int len)
+{
+  int status;
+
+ status = ttrace (TT_LWP_RUREGS, ptid_get_pid (inferior_ptid),
+		  ptid_get_lwp (inferior_ptid), offset, len, (uintptr_t) buf);
+
+  return status;
+}
+
+/* Fetch register REGNUM from the inferior.  */
+
+static void
+ia64_hpux_fetch_register (struct regcache *regcache, int regnum)
+{
+  struct gdbarch *gdbarch = get_regcache_arch (regcache);
+  int offset, len, status;
+  gdb_byte *buf;
+
+  if (regnum == IA64_GR0_REGNUM)
+    {
+      /* r0 is always 0.  */
+      regcache_raw_supply (regcache, regnum, r0_value);
+      return;
+    }
+
+  if (regnum == IA64_FR0_REGNUM)
+    {
+      /* f0 is always 0.0.  */
+      regcache_raw_supply (regcache, regnum, f0_value);
+      return;
+    }
+
+  if (regnum == IA64_FR1_REGNUM)
+    {
+      /* f1 is always 1.0.  */
+      regcache_raw_supply (regcache, regnum, f1_value);
+      return;
+    }
+
+  if (regnum == IA64_RNAT_REGNUM)
+    {
+      ia64_hpux_fetch_rnat_register (regcache);
+      return;
+    }
+
+  /* Get the register location. If the register can not be fetched,
+     then return now.  */
+  offset = u_offsets[regnum];
+  if (offset == -1)
+    return;
+
+  len = register_size (gdbarch, regnum);
+  buf = alloca (len * sizeof (gdb_byte));
+  status = ia64_hpux_read_register_from_save_state_t (offset, buf, len);
+  if (status < 0)
+    warning (_("Failed to read register value for %s.\n"),
+             gdbarch_register_name (gdbarch, regnum));
+
+  regcache_raw_supply (regcache, regnum, buf);
+}
+
+/* The "to_fetch_registers" target_ops routine for ia64-hpux.  */
+
+static void
+ia64_hpux_fetch_registers (struct target_ops *ops,
+			   struct regcache *regcache, int regnum)
+{
+  if (regnum == -1)
+    for (regnum = 0;
+	 regnum < gdbarch_num_regs (get_regcache_arch (regcache));
+	 regnum++)
+      ia64_hpux_fetch_register (regcache, regnum);
+  else
+    ia64_hpux_fetch_register (regcache, regnum);
+}
+
+/* Save register REGNUM (stored in BUF) in the save_state_t structure.
+   LEN is the size of the register in bytes.
+
+   Return the value from the corresponding ttrace call (a negative value
+   means that the operation failed).  */
+
+static int
+ia64_hpux_write_register_to_saved_state_t (int offset, gdb_byte *buf, int len)
+{
+  return ttrace (TT_LWP_WUREGS, ptid_get_pid (inferior_ptid),
+		 ptid_get_lwp (inferior_ptid), offset, len, (uintptr_t) buf);
+}
+
+/* Store register REGNUM into the inferior.  */
+
+static void
+ia64_hpux_store_register (const struct regcache *regcache, int regnum)
+{
+  struct gdbarch *gdbarch = get_regcache_arch (regcache);
+  int offset = u_offsets[regnum];
+  gdb_byte *buf;
+  int len, status;
+
+  /* If the register can not be stored, then return now.  */
+  if (offset == -1)
+    return;
+
+  /* I don't know how to store that register for now.  So just ignore any
+     request to store it, to avoid an internal error.  */
+  if (regnum == IA64_PSR_REGNUM)
+    return;
+
+  len = register_size (gdbarch, regnum);
+  buf = alloca (len * sizeof (gdb_byte));
+  regcache_raw_collect (regcache, regnum, buf);
+
+  status = ia64_hpux_write_register_to_saved_state_t (offset, buf, len);
+
+  if (status < 0)
+    error (_("failed to write register value for %s.\n"),
+           gdbarch_register_name (gdbarch, regnum));
+}
+
+/* The "to_store_registers" target_ops routine for ia64-hpux.  */
+
+static void
+ia64_hpux_store_registers (struct target_ops *ops,
+			   struct regcache *regcache, int regnum)
+{
+  if (regnum == -1)
+    for (regnum = 0;
+	 regnum < gdbarch_num_regs (get_regcache_arch (regcache));
+	 regnum++)
+      ia64_hpux_store_register (regcache, regnum);
+  else
+    ia64_hpux_store_register (regcache, regnum);
+}
+
+/* The "xfer_partial" routine from the "inf-ttrace" target layer.
+   Ideally, we would like to use this routine for all transfer
+   requests, but this platforms has a lot of special cases that
+   need to be handled manually.  So we override this routine and
+   delegate back if we detect that we are not in a special case.  */
+
+static LONGEST (*super_xfer_partial) (struct target_ops *, enum target_object,
+				      const char *, gdb_byte *,
+				      const gdb_byte *, ULONGEST, LONGEST);
+
+/* The "xfer_partial" routine for a memory region that is completely
+   outside of the backing-store region.  */
+
+static LONGEST
+ia64_hpux_xfer_memory_no_bs (struct target_ops *ops, const char *annex,
+			     gdb_byte *readbuf, const gdb_byte *writebuf,
+			     CORE_ADDR addr, LONGEST len)
+{
+  /* Memory writes need to be aligned on 16byte boundaries, at least
+     when writing in the text section.  On the other hand, the size
+     of the buffer does not need to be a multiple of 16bytes.
+
+     No such restriction when performing memory reads.  */
+
+  if (writebuf && addr & 0x0f)
+    {
+      const CORE_ADDR aligned_addr = addr & ~0x0f;
+      const int aligned_len = len + (addr - aligned_addr);
+      gdb_byte *aligned_buf = alloca (aligned_len * sizeof (gdb_byte));
+      LONGEST status;
+
+      /* Read the portion of memory between ALIGNED_ADDR and ADDR, so
+         that we can write it back during our aligned memory write.  */
+      status = super_xfer_partial (ops, TARGET_OBJECT_MEMORY, annex,
+				   aligned_buf /* read */,
+				   NULL /* write */,
+				   aligned_addr, addr - aligned_addr);
+      if (status <= 0)
+	return 0;
+      memcpy (aligned_buf + (addr - aligned_addr), writebuf, len);
+
+      return super_xfer_partial (ops, TARGET_OBJECT_MEMORY, annex,
+				 NULL /* read */, aligned_buf /* write */,
+				 aligned_addr, aligned_len);
+    }
+  else
+    /* Memory read or properly aligned memory write.  */
+    return super_xfer_partial (ops, TARGET_OBJECT_MEMORY, annex, readbuf,
+			       writebuf, addr, len);
+}
+
+/* Read LEN bytes at ADDR from memory, and store it in BUF.  This memory
+   region is assumed to be inside the backing store.
+
+   Return zero if the operation failed.  */
+
+static int
+ia64_hpux_read_memory_bs (gdb_byte *buf, CORE_ADDR addr, int len)
+{
+  gdb_byte tmp_buf[8];
+  CORE_ADDR tmp_addr = addr & ~0x7;
+
+  while (tmp_addr < addr + len)
+    {
+      int status;
+      int skip_lo = 0;
+      int skip_hi = 0;
+
+      status = ttrace (TT_LWP_RDRSEBS, ptid_get_pid (inferior_ptid),
+		       ptid_get_lwp (inferior_ptid), tmp_addr,
+		       sizeof (tmp_buf), (uintptr_t) tmp_buf);
+      if (status < 0)
+        return 0;
+
+      if (tmp_addr < addr)
+        skip_lo = addr - tmp_addr;
+
+      if (tmp_addr + sizeof (tmp_buf) > addr + len)
+        skip_hi = (tmp_addr + sizeof (tmp_buf)) - (addr + len);
+
+      memcpy (buf + (tmp_addr + skip_lo - addr),
+              tmp_buf + skip_lo,
+              sizeof (tmp_buf) - skip_lo - skip_hi);
+
+      tmp_addr += sizeof (tmp_buf);
+    }
+
+  return 1;
+}
+
+/* Write LEN bytes from BUF in memory at ADDR.  This memory region is assumed
+   to be inside the backing store.
+
+   Return zero if the operation failed.  */
+
+static int
+ia64_hpux_write_memory_bs (const gdb_byte *buf, CORE_ADDR addr, int len)
+{
+  gdb_byte tmp_buf[8];
+  CORE_ADDR tmp_addr = addr & ~0x7;
+
+  while (tmp_addr < addr + len)
+    {
+      int status;
+      int lo = 0;
+      int hi = 7;
+
+      if (tmp_addr < addr || tmp_addr + sizeof (tmp_buf) > addr + len)
+	/* Part of the 8byte region pointed by tmp_addr needs to be preserved.
+	   So read it in before we copy the data that needs to be changed.  */
+	if (!ia64_hpux_read_memory_bs (tmp_buf, tmp_addr, sizeof (tmp_buf)))
+	  return 0;
+
+      if (tmp_addr < addr)
+        lo = addr - tmp_addr;
+
+      if (tmp_addr + sizeof (tmp_buf) > addr + len)
+        hi = addr - tmp_addr + len - 1;
+
+      memcpy (tmp_buf + lo, buf + tmp_addr - addr  + lo, hi - lo + 1);
+
+      status = ttrace (TT_LWP_WRRSEBS, ptid_get_pid (inferior_ptid),
+		       ptid_get_lwp (inferior_ptid), tmp_addr,
+		       sizeof (tmp_buf), (uintptr_t) tmp_buf);
+      if (status < 0)
+        return 0;
+
+      tmp_addr += sizeof (tmp_buf);
+    }
+
+  return 1;
+}
+
+/* The "xfer_partial" routine for a memory region that is completely
+   inside of the backing-store region.  */
+
+static LONGEST
+ia64_hpux_xfer_memory_bs (struct target_ops *ops, const char *annex,
+			  gdb_byte *readbuf, const gdb_byte *writebuf,
+			  CORE_ADDR addr, LONGEST len)
+{
+  int success;
+
+  if (readbuf)
+    success = ia64_hpux_read_memory_bs (readbuf, addr, len);
+  else
+    success = ia64_hpux_write_memory_bs (writebuf, addr, len);
+
+  if (success)
+    return len;
+  else
+    return 0;
+}
+
+/* The "xfer_partial" target_ops routine for ia64-hpux, in the case
+   where the requested object is TARGET_OBJECT_MEMORY.  */
+
+static LONGEST
+ia64_hpux_xfer_memory (struct target_ops *ops, const char *annex,
+		       gdb_byte *readbuf, const gdb_byte *writebuf,
+		       CORE_ADDR addr, LONGEST len)
+{
+  CORE_ADDR bsp, bspstore;
+  CORE_ADDR start_addr, short_len;
+  int status = 0;
+
+  /* The back-store region cannot be read/written by the standard memory
+     read/write operations.  So we handle the memory region piecemeal:
+       (1) and (2) The regions before and after the backing-store region,
+           which can be treated as normal memory;
+       (3) The region inside the backing-store, which needs to be
+           read/written specially.  */
+
+  regcache_raw_read_unsigned (get_current_regcache (), IA64_BSP_REGNUM, &bsp);
+  regcache_raw_read_unsigned (get_current_regcache (), IA64_BSPSTORE_REGNUM,
+                              &bspstore);
+
+  /* 1. Memory region before BSPSTORE.  */
+
+  if (addr < bspstore)
+    {
+      short_len = len;
+      if (addr + len > bspstore)
+        short_len = bspstore - addr;
+
+      status = ia64_hpux_xfer_memory_no_bs (ops, annex, readbuf, writebuf,
+					    addr, short_len);
+      if (status <= 0)
+        return 0;
+    }
+
+  /* 2. Memory region after BSP.  */
+
+  if (addr + len > bsp)
+    {
+      start_addr = addr;
+      if (start_addr < bsp)
+        start_addr = bsp;
+      short_len = len + addr - start_addr;
+
+      status = ia64_hpux_xfer_memory_no_bs
+		(ops, annex,
+		 readbuf ? readbuf + (start_addr - addr) : NULL,
+		 writebuf ? writebuf + (start_addr - addr) : NULL,
+		 start_addr, short_len);
+      if (status <= 0)
+	return 0;
+    }
+
+  /* 3. Memory region between BSPSTORE and BSP.  */
+
+  if (bspstore != bsp
+      && ((addr < bspstore && addr + len > bspstore)
+	  || (addr + len <= bsp && addr + len > bsp)))
+    {
+      start_addr = addr;
+      if (addr < bspstore)
+        start_addr = bspstore;
+      short_len = len + addr - start_addr;
+
+      if (start_addr + short_len > bsp)
+        short_len = bsp - start_addr;
+
+      gdb_assert (short_len > 0);
+
+      status = ia64_hpux_xfer_memory_bs
+		 (ops, annex,
+		  readbuf ? readbuf + (start_addr - addr) : NULL,
+		  writebuf ? writebuf + (start_addr - addr) : NULL,
+		  start_addr, short_len);
+      if (status < 0)
+	return 0;
+    }
+
+  return len;
+}
+
+/* The "to_xfer_partial" target_ops routine for ia64-hpux.  */
+
+static LONGEST
+ia64_hpux_xfer_partial (struct target_ops *ops, enum target_object object,
+			const char *annex, gdb_byte *readbuf,
+			const gdb_byte *writebuf, ULONGEST offset, LONGEST len)
+{
+  LONGEST val;
+
+  if (object == TARGET_OBJECT_MEMORY)
+    val = ia64_hpux_xfer_memory (ops, annex, readbuf, writebuf, offset, len);
+  else
+    val = super_xfer_partial (ops, object, annex, readbuf, writebuf, offset,
+			      len);
+
+  return val;
+}
+
+/* The "to_can_use_hw_breakpoint" target_ops routine for ia64-hpux.  */
+
+static int
+ia64_hpux_can_use_hw_breakpoint (int type, int cnt, int othertype)
+{
+  /* No hardware watchpoint/breakpoint support yet.  */
+  return 0;
+}
+
+/* The "to_mourn_inferior" routine from the "inf-ttrace" target_ops layer.  */
+
+static void (*super_mourn_inferior) (struct target_ops *);
+
+/* The "to_mourn_inferior" target_ops routine for ia64-hpux.  */
+
+static void
+ia64_hpux_mourn_inferior (struct target_ops *ops)
+{
+  const int pid = ptid_get_pid (inferior_ptid);
+  int status;
+
+  super_mourn_inferior (ops);
+
+  /* On this platform, the process still exists even after we received
+     an exit event.  Detaching from the process isn't sufficient either,
+     as it only turns the process into a zombie.  So the only solution
+     we found is to kill it.  */
+  ttrace (TT_PROC_EXIT, pid, 0, 0, 0, 0);
+  wait (&status);
+}
+
+/* Prevent warning from -Wmissing-prototypes.  */
+void _initialize_hppa_hpux_nat (void);
+
+void
+_initialize_hppa_hpux_nat (void)
+{
+  struct target_ops *t;
+
+  t = inf_ttrace_target ();
+  super_to_wait = t->to_wait;
+  super_xfer_partial = t->to_xfer_partial;
+  super_mourn_inferior = t->to_mourn_inferior;
+
+  t->to_wait = ia64_hpux_wait;
+  t->to_fetch_registers = ia64_hpux_fetch_registers;
+  t->to_store_registers = ia64_hpux_store_registers;
+  t->to_xfer_partial = ia64_hpux_xfer_partial;
+  t->to_can_use_hw_breakpoint = ia64_hpux_can_use_hw_breakpoint;
+  t->to_mourn_inferior = ia64_hpux_mourn_inferior;
+  t->to_attach_no_wait = 1;
+
+  add_target (t);
+}
diff --git a/gdb/ia64-hpux-tdep.c b/gdb/ia64-hpux-tdep.c
new file mode 100644
index 0000000..139ff83
--- /dev/null
+++ b/gdb/ia64-hpux-tdep.c
@@ -0,0 +1,101 @@
+/* Target-dependent code for the IA-64 for GDB, the GNU debugger.
+
+   Copyright (C) 2010 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#include "defs.h"
+#include "ia64-tdep.h"
+#include "ia64-hpux-tdep.h"
+#include "osabi.h"
+#include "gdbtypes.h"
+#include "solib.h"
+
+/* Return nonzero if the value of the register identified by REGNUM
+   can be modified.  */
+
+static int
+ia64_hpux_can_store_ar_register (int regnum)
+{
+  switch (regnum)
+    {
+      case IA64_RSC_REGNUM:
+      case IA64_RNAT_REGNUM:
+      case IA64_CSD_REGNUM:
+      case IA64_SSD_REGNUM:
+      case IA64_CCV_REGNUM:
+      case IA64_UNAT_REGNUM:
+      case IA64_FPSR_REGNUM:
+      case IA64_PFS_REGNUM:
+      case IA64_LC_REGNUM:
+      case IA64_EC_REGNUM:
+         return 1;
+         break;
+
+      default:
+         return 0;
+         break;
+    }
+}
+
+/* The "cannot_store_register" target_ops method.  */
+
+static int
+ia64_hpux_cannot_store_register (struct gdbarch *gdbarch, int regnum)
+{
+  /* General registers.  */
+
+  if (regnum == IA64_GR0_REGNUM)
+    return 1;
+
+  /* FP register.  */
+
+  if (regnum == IA64_FR0_REGNUM || regnum == IA64_FR1_REGNUM)
+    return 1;
+
+  /* Application registers.  */
+  if (regnum >= IA64_AR0_REGNUM && regnum <= IA64_AR0_REGNUM + 127)
+    return (!ia64_hpux_can_store_ar_register (regnum));
+
+  /* We can store all other registers.  */
+  return 0;
+}
+
+/* Should be set to non-NULL if the ia64-hpux solib module is linked in.
+   This may not be the case because the shared library support code can
+   only be compiled on ia64-hpux.  */
+
+struct target_so_ops *ia64_hpux_so_ops = NULL;
+
+static void
+ia64_hpux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
+{
+  set_gdbarch_long_double_format (gdbarch, floatformats_ia64_quad);
+  set_gdbarch_cannot_store_register (gdbarch, ia64_hpux_cannot_store_register);
+
+  if (ia64_hpux_so_ops)
+    set_solib_ops (gdbarch, ia64_hpux_so_ops);
+}
+
+/* Provide a prototype to silence -Wmissing-prototypes.  */
+extern initialize_file_ftype _initialize_ia64_hpux_tdep;
+
+void
+_initialize_ia64_hpux_tdep (void)
+{
+  gdbarch_register_osabi (bfd_arch_ia64, 0, GDB_OSABI_HPUX_ELF,
+			  ia64_hpux_init_abi);
+}
diff --git a/gdb/ia64-hpux-tdep.h b/gdb/ia64-hpux-tdep.h
new file mode 100644
index 0000000..9f92a21
--- /dev/null
+++ b/gdb/ia64-hpux-tdep.h
@@ -0,0 +1,24 @@
+/* Copyright (C) 2010 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#ifndef IA64_HPUX_TDEP_H
+#define IA64_HPUX_TDEP_H
+
+struct target_so_ops;
+extern struct target_so_ops *ia64_hpux_so_ops;
+
+#endif
diff --git a/gdb/solib-ia64-hpux.c b/gdb/solib-ia64-hpux.c
new file mode 100644
index 0000000..01d44a9
--- /dev/null
+++ b/gdb/solib-ia64-hpux.c
@@ -0,0 +1,700 @@
+/* Copyright (C) 2010 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#include "defs.h"
+#include "ia64-tdep.h"
+#include "ia64-hpux-tdep.h"
+#include "solib-ia64-hpux.h"
+#include "solist.h"
+#include "solib.h"
+#include "target.h"
+#include "gdbtypes.h"
+#include "inferior.h"
+#include "gdbcore.h"
+#include "regcache.h"
+#include "opcode/ia64.h"
+#include "symfile.h"
+#include "objfiles.h"
+#include "elf-bfd.h"
+#include "exceptions.h"
+
+/* Need to define the following macro in order to get the complete
+   load_module_desc struct definition in dlfcn.h  Otherwise, it doesn't
+   match the size of the struct the loader is providing us during load
+   events.  */
+#define _LOAD_MODULE_DESC_EXT
+
+#include <sys/ttrace.h>
+#include <dlfcn.h>
+#include <elf.h>
+#include <service_mgr.h>
+
+/* The following is to have access to the definition of type load_info_t.  */
+#include <crt0.h>
+
+/* The r32 pseudo-register number.
+
+   Like all stacked registers, r32 is treated as a pseudo-register,
+   because it is not always available for read/write via the ttrace
+   interface.  */
+/* This is a bit of a hack, as we duplicate something hidden inside
+   ia64-tdep.c, but oh well...  */
+#define IA64_R32_PSEUDO_REGNUM (IA64_NAT127_REGNUM + 2)
+
+/* Our struct so_list private data structure.  */
+
+struct lm_info
+{
+  /* The shared library module descriptor.  We extract this structure
+     from the loader at the time the shared library gets mapped.  */
+  struct load_module_desc module_desc;
+
+  /* The text segment address as defined in the shared library object
+     (this is not the address where this segment got loaded).  This
+     field is initially set to zero, and computed lazily.  */
+  CORE_ADDR text_start;
+
+  /* The data segment address as defined in the shared library object
+     (this is not the address where this segment got loaded).  This
+     field is initially set to zero, and computed lazily.  */
+  CORE_ADDR data_start;
+};
+
+/* The list of shared libraries currently mapped by the inferior.  */
+
+static struct so_list *so_list_head = NULL;
+
+/* Create a new so_list element.  The result should be deallocated
+   when no longer in use.  */
+
+static struct so_list *
+new_so_list (char *so_name, struct load_module_desc module_desc)
+{
+  struct so_list *new_so;
+
+  new_so = (struct so_list *) XZALLOC (struct so_list);
+  new_so->lm_info = (struct lm_info *) XZALLOC (struct lm_info);
+  new_so->lm_info->module_desc = module_desc;
+
+  strncpy (new_so->so_name, so_name, SO_NAME_MAX_PATH_SIZE - 1);
+  new_so->so_name[SO_NAME_MAX_PATH_SIZE - 1] = '\0';
+  strcpy (new_so->so_original_name, new_so->so_name);
+
+  return new_so;
+}
+
+/* Return non-zero if the instruction at the current PC is a breakpoint
+   part of the dynamic loading process.
+
+   We identify such instructions by checking that the instruction at
+   the current pc is a break insn where no software breakpoint has been
+   inserted by us.  We also verify that the operands have specific
+   known values, to be extra certain.
+
+   PTID is the ptid of the thread that should be checked, but this
+   function also assumes that inferior_ptid is already equal to PTID.
+   Ideally, we would like to avoid the requirement on inferior_ptid,
+   but many routines still use the inferior_ptid global to access
+   the relevant thread's register and memory.  We still have the ptid
+   as parameter to be able to pass it to the routines that do take a ptid
+   - that way we avoid increasing explicit uses of the inferior_ptid
+   global.  */
+
+static int
+ia64_hpux_at_dld_breakpoint_1_p (ptid_t ptid)
+{
+  struct regcache *regcache = get_thread_regcache (ptid);
+  CORE_ADDR pc = regcache_read_pc (regcache);
+  struct address_space *aspace = get_regcache_aspace (regcache);
+  ia64_insn t0, t1, slot[3], template, insn;
+  int slotnum;
+  bfd_byte bundle[16];
+
+  /* If this is a regular breakpoint, then it can not be a dld one.  */
+  if (breakpoint_inserted_here_p (aspace, pc))
+    return 0;
+
+  slotnum = ((long) pc) & 0xf;
+  if (slotnum > 2)
+    internal_error (__FILE__, __LINE__,
+		    "invalid slot (%d) for address %s", slotnum,
+		    paddress (get_regcache_arch (regcache), pc));
+
+  pc -= (pc & 0xf);
+  read_memory (pc, bundle, sizeof (bundle));
+
+  /* bundles are always in little-endian byte order */
+  t0 = bfd_getl64 (bundle);
+  t1 = bfd_getl64 (bundle + 8);
+  template = (t0 >> 1) & 0xf;
+  slot[0] = (t0 >>  5) & 0x1ffffffffffLL;
+  slot[1] = ((t0 >> 46) & 0x3ffff) | ((t1 & 0x7fffff) << 18);
+  slot[2] = (t1 >> 23) & 0x1ffffffffffLL;
+
+  if (template == 2 && slotnum == 1)
+    {
+      /* skip L slot in MLI template: */
+      slotnum = 2;
+    }
+
+  insn = slot[slotnum];
+
+  return (insn == 0x1c0c9c0       /* break.i 0x070327 */
+          || insn == 0x3c0c9c0);  /* break.i 0x0f0327 */
+}
+
+/* Same as ia64_hpux_at_dld_breakpoint_1_p above, with the following
+   differences: It temporarily sets inferior_ptid to PTID, and also
+   contains any exception being raised.  */
+
+int
+ia64_hpux_at_dld_breakpoint_p (ptid_t ptid)
+{
+  struct gdb_exception e;
+  ptid_t saved_ptid = inferior_ptid;
+  int result = 0;
+
+  inferior_ptid = ptid;
+  TRY_CATCH (e, RETURN_MASK_ALL)
+    {
+      result = ia64_hpux_at_dld_breakpoint_1_p (ptid);
+    }
+  inferior_ptid = saved_ptid;
+  if (e.reason < 0)
+    warning (_("error while checking for dld breakpoint: %s"), e.message);
+
+  return result;
+}
+
+/* Handler for library load event: Read the information provided by
+   the loader, and then use it to read the shared library symbols.  */
+
+static void
+ia64_hpux_handle_load_event (struct regcache *regcache)
+{
+  CORE_ADDR module_desc_addr;
+  ULONGEST module_desc_size;
+  CORE_ADDR so_path_addr;
+  char so_path[MAXPATHLEN];
+  struct load_module_desc module_desc;
+  struct so_list *new_so;
+
+  /* Extract the data provided by the loader as follow:
+       - r33: Address of load_module_desc structure
+       - r34: size of struct load_module_desc
+       - r35: Address of string holding shared library path
+   */
+  regcache_cooked_read_unsigned (regcache, IA64_R32_PSEUDO_REGNUM + 1,
+                                 &module_desc_addr);
+  regcache_cooked_read_unsigned (regcache, IA64_R32_PSEUDO_REGNUM + 2,
+                                 &module_desc_size);
+  regcache_cooked_read_unsigned (regcache, IA64_R32_PSEUDO_REGNUM + 3,
+                                 &so_path_addr);
+
+  if (module_desc_size != sizeof (struct load_module_desc))
+    warning (_("load_module_desc size (%ld) != size returned by kernel (%s)"),
+             sizeof (struct load_module_desc),
+	     pulongest (module_desc_size));
+
+  read_memory_string (so_path_addr, so_path, MAXPATHLEN);
+  read_memory (module_desc_addr, (gdb_byte *) &module_desc,
+	       sizeof (module_desc));
+
+  /* Create a new so_list element and insert it at the start of our
+     so_list_head (we insert at the start of the list only because
+     it is less work compared to inserting it elsewhere).  */
+  new_so = new_so_list (so_path, module_desc);
+  new_so->next = so_list_head;
+  so_list_head = new_so;
+}
+
+/* Update the value of the PC to point to the begining of the next
+   instruction bundle.  */
+
+static void
+ia64_hpux_move_pc_to_next_bundle (struct regcache *regcache)
+{
+  CORE_ADDR pc = regcache_read_pc (regcache);
+
+  pc -= pc & 0xf;
+  pc += 16;
+  ia64_write_pc (regcache, pc);
+}
+
+/* Handle loader events.
+
+   PTID is the ptid of the thread corresponding to the event being
+   handled.  Similarly to ia64_hpux_at_dld_breakpoint_1_p, this
+   function assumes that inferior_ptid is set to PTID.  */
+
+static void
+ia64_hpux_handle_dld_breakpoint_1 (ptid_t ptid)
+{
+  struct regcache *regcache = get_thread_regcache (ptid);
+  ULONGEST arg0;
+
+  /* The type of event is provided by the loaded via r32.  */
+  regcache_cooked_read_unsigned (regcache, IA64_R32_PSEUDO_REGNUM, &arg0);
+  switch (arg0)
+    {
+      case BREAK_DE_SVC_LOADED:
+	/* Currently, the only service loads are uld and dld,
+	   so we shouldn't need to do anything.  Just ignore.  */
+	break;
+      case BREAK_DE_LIB_LOADED:
+	ia64_hpux_handle_load_event (regcache);
+	solib_add (NULL, 0, &current_target, auto_solib_add);
+	break;
+      case BREAK_DE_LIB_UNLOADED:
+      case BREAK_DE_LOAD_COMPLETE:
+      case BREAK_DE_BOR:
+	/* Ignore for now.  */
+	break;
+    }
+
+  /* Now that we have handled the event, we can move the PC to
+     the next instruction bundle, past the break instruction.  */
+  ia64_hpux_move_pc_to_next_bundle (regcache);
+}
+
+/* Same as ia64_hpux_handle_dld_breakpoint_1 above, with the following
+   differences: This function temporarily sets inferior_ptid to PTID,
+   and also contains any exception.  */
+
+void
+ia64_hpux_handle_dld_breakpoint (ptid_t ptid)
+{
+  struct gdb_exception e;
+  ptid_t saved_ptid = inferior_ptid;
+
+  inferior_ptid = ptid;
+  TRY_CATCH (e, RETURN_MASK_ALL)
+    {
+      ia64_hpux_handle_dld_breakpoint_1 (ptid);
+    }
+  inferior_ptid = saved_ptid;
+  if (e.reason < 0)
+    warning (_("error detected while handling dld breakpoint: %s"), e.message);
+}
+
+/* Find the address of the code and data segments in ABFD, and update
+   TEXT_START and DATA_START accordingly.  */
+
+static void
+ia64_hpux_find_start_vma (bfd *abfd, CORE_ADDR *text_start,
+                          CORE_ADDR *data_start)
+{
+  Elf_Internal_Ehdr *i_ehdrp = elf_elfheader (abfd);
+  Elf64_Phdr phdr;
+  int i;
+
+  *text_start = 0;
+  *data_start = 0;
+
+  if (bfd_seek (abfd, i_ehdrp->e_phoff, SEEK_SET) == -1)
+    error (_("invalid program header offset in %s"), abfd->filename);
+
+  for (i = 0; i < i_ehdrp->e_phnum; i++)
+    {
+      if (bfd_bread ((PTR) & phdr, sizeof (phdr), abfd) != sizeof (phdr))
+        error (_("failed to read segment %d in %s"), i, abfd->filename);
+
+      if (phdr.p_flags & PF_X
+          && (*text_start == 0 || phdr.p_vaddr < *text_start))
+        *text_start = phdr.p_vaddr;
+
+      if (phdr.p_flags & PF_W
+          && (*data_start == 0 || phdr.p_vaddr < *data_start))
+        *data_start = phdr.p_vaddr;
+    }
+}
+
+/* The "relocate_section_addresses" target_so_ops routine for ia64-hpux.  */
+
+static void
+ia64_hpux_relocate_section_addresses (struct so_list *so,
+				      struct target_section *sec)
+{
+  CORE_ADDR offset = 0;
+
+  /* If we haven't computed the text & data segment addresses, do so now.
+     We do this here, because we now have direct access to the associated
+     bfd, whereas we would have had to open our own if we wanted to do it
+     while processing the library-load event.  */
+  if (so->lm_info->text_start == 0 && so->lm_info->data_start == 0)
+    ia64_hpux_find_start_vma (sec->bfd, &so->lm_info->text_start,
+			      &so->lm_info->data_start);
+
+  /* Determine the relocation offset based on which segment
+     the section belongs to.  */
+  if ((so->lm_info->text_start < so->lm_info->data_start
+       && sec->addr < so->lm_info->data_start)
+      || (so->lm_info->text_start > so->lm_info->data_start
+          && sec->addr >= so->lm_info->text_start))
+    offset = so->lm_info->module_desc.text_base - so->lm_info->text_start;
+  else if ((so->lm_info->text_start < so->lm_info->data_start
+            && sec->addr >= so->lm_info->data_start)
+           || (so->lm_info->text_start > so->lm_info->data_start
+	       && sec->addr < so->lm_info->text_start))
+    offset = so->lm_info->module_desc.data_base - so->lm_info->data_start;
+
+  /* And now apply the relocation.  */
+  sec->addr += offset;
+  sec->endaddr += offset;
+
+  /* Best effort to set addr_high/addr_low.  This is used only by
+     'info sharedlibrary'.  */
+  if (so->addr_low == 0 || sec->addr < so->addr_low)
+    so->addr_low = sec->addr;
+
+  if (so->addr_high == 0 || sec->endaddr > so->addr_high)
+    so->addr_high = sec->endaddr;
+}
+
+/* The "free_so" target_so_ops routine for ia64-hpux.  */
+
+static void
+ia64_hpux_free_so (struct so_list *so)
+{
+  xfree (so->lm_info);
+}
+
+/* The "clear_solib" target_so_ops routine for ia64-hpux.  */
+
+static void
+ia64_hpux_clear_solib (void)
+{
+  struct so_list *so;
+
+  while (so_list_head != NULL)
+    {
+      so = so_list_head;
+      so_list_head = so_list_head->next;
+
+      ia64_hpux_free_so (so);
+      xfree (so);
+    }
+}
+
+/* Assuming the inferior just stopped on an EXEC event, return
+   the address of the load_info_t structure.  */
+
+static CORE_ADDR
+ia64_hpux_get_load_info_addr (void)
+{
+  struct type *data_ptr_type = builtin_type (target_gdbarch)->builtin_data_ptr;
+  CORE_ADDR addr;
+  int status;
+
+  /* The address of the load_info_t structure is stored in the 4th
+     argument passed to the initial thread of the process (in other
+     words, in argv[3]).  So get the address of these arguments,
+     and extract the 4th one.  */
+  status = ttrace (TT_PROC_GET_ARGS, ptid_get_pid (inferior_ptid),
+		   0, (uintptr_t) &addr, sizeof (CORE_ADDR), 0);
+  if (status == -1 && errno)
+    perror_with_name (_("Unable to get argument list"));
+  return (read_memory_typed_address (addr + 3 * 8, data_ptr_type));
+}
+
+/* A structure used to aggregate some information extracted from
+   the dynamic section of the main executable.  */
+
+struct dld_info
+{
+  long long dld_flags;
+  CORE_ADDR load_map;
+};
+
+/* Scan the ".dynamic" section referenced by ABFD and DYN_SECT,
+   and extract the information needed to fill in INFO.  */
+
+static void
+ia64_hpux_read_dynamic_info (struct gdbarch *gdbarch, bfd *abfd,
+			     asection *dyn_sect, struct dld_info *info)
+{
+  int sect_size;
+  char *buf;
+  char *buf_end;
+
+  /* Make sure that info always has initialized data, even if we fail
+     to read the syn_sect section.  */
+  memset (info, 0, sizeof (struct dld_info));
+
+  sect_size = bfd_section_size (abfd, dyn_sect);
+  buf = alloca (sect_size);
+  buf_end = buf + sect_size;
+
+  if (bfd_seek (abfd, dyn_sect->filepos, SEEK_SET) != 0
+      || bfd_bread (buf, sect_size, abfd) != sect_size)
+    error (_("failed to read contents of .dynamic section"));
+
+  for (; buf < buf_end; buf += sizeof (Elf64_Dyn))
+    {
+      Elf64_Dyn *dynp = (Elf64_Dyn *) buf;
+      Elf64_Sxword d_tag;
+
+      d_tag = bfd_h_get_64 (abfd, &dynp->d_tag);
+      switch (d_tag)
+        {
+          case DT_HP_DLD_FLAGS:
+            info->dld_flags = bfd_h_get_64 (abfd, &dynp->d_un);
+            break;
+
+          case DT_HP_LOAD_MAP:
+            {
+              CORE_ADDR load_map_addr = bfd_h_get_64 (abfd, &dynp->d_un.d_ptr);
+
+              if (target_read_memory (load_map_addr, (char *) &info->load_map,
+                                      sizeof (info->load_map)) != 0)
+		error (_("failed to read load map at %s"),
+		       paddress (gdbarch, load_map_addr));
+            }
+            break;
+        }
+    }
+}
+
+/* Wrapper around target_read_memory used with libdl.  */
+
+static void *
+ia64_hpux_read_tgt_mem (void *buffer, uint64_t ptr, size_t bufsiz, int ident)
+{
+  if (target_read_memory (ptr, (gdb_byte *) buffer, bufsiz) != 0)
+    return 0;
+  else
+    return buffer;
+}
+
+/* Create a new so_list object for a shared library, and store that
+   new so_list object in our SO_LIST_HEAD list.
+
+   SO_INDEX is an index specifying the placement of the loaded shared
+   library in the dynamic loader's search list.  Normally, this index
+   is strictly positive, but an index of -1 refers to the loader itself.
+
+   Return nonzero if the so_list object could be created.  A null
+   return value with a positive SO_INDEX normally means that there are
+   no more entries in the dynamic loader's search list at SO_INDEX or
+   beyond.  */
+
+static int
+ia64_hpux_add_so_from_dld_info (struct dld_info info, int so_index)
+{
+  struct load_module_desc module_desc;
+  uint64_t so_handle;
+  char *so_path;
+  struct so_list *so;
+
+  so_handle = dlgetmodinfo (so_index, &module_desc, sizeof (module_desc),
+			    ia64_hpux_read_tgt_mem, 0, info.load_map);
+
+  if (so_handle == 0)
+    /* No such entry.  We probably reached the end of the list.  */
+    return 0;
+
+  so_path = dlgetname (&module_desc, sizeof (module_desc),
+                       ia64_hpux_read_tgt_mem, 0, info.load_map);
+  if (so_path == NULL)
+    {
+      /* Should never happen, but let's not crash if it does.  */
+      warning (_("unable to get shared library name, symbols not loaded"));
+      return 0;
+    }
+
+  /* Create a new so_list and insert it at the start of our list.
+     The order is not extremely important, but it's less work to do so
+     at the end of the list.  */
+  so = new_so_list (so_path, module_desc);
+  so->next = so_list_head;
+  so_list_head = so;
+
+  return 1;
+}
+
+/* Assuming we just attached to a process, update our list of shared
+   libraries (SO_LIST_HEAD) as well as GDB's list.  */
+
+static void
+ia64_hpux_solib_add_after_attach (void)
+{
+  bfd *abfd;
+  asection *dyn_sect;
+  struct dld_info info;
+  int i;
+
+  if (symfile_objfile == NULL)
+    return;
+
+  abfd = symfile_objfile->obfd;
+  dyn_sect = bfd_get_section_by_name (abfd, ".dynamic");
+
+  if (dyn_sect == NULL || bfd_section_size (abfd, dyn_sect) == 0)
+    return;
+
+  ia64_hpux_read_dynamic_info (get_objfile_arch (symfile_objfile), abfd,
+			       dyn_sect, &info);
+
+  if ((info.dld_flags & DT_HP_DEBUG_PRIVATE) == 0)
+    {
+      warning (_(
+"The shared libraries were not privately mapped; setting a breakpoint\n\
+in a shared library will not work until you rerun the program.\n\
+Use the following command to enable debugging of shared libraries.\n\
+chatr +dbg enable a.out"));
+    }
+
+  /* Read the symbols of the dynamic loader (dld.so).  */
+  ia64_hpux_add_so_from_dld_info (info, -1);
+
+  /* Read the symbols of all the other shared libraries.  */
+  for (i = 1; ; i++)
+    if (!ia64_hpux_add_so_from_dld_info (info, i))
+      break;  /* End of list.  */
+
+  /* Resync the library list at the core level.  */
+  solib_add (NULL, 1, &current_target, auto_solib_add);
+}
+
+/* The "create_inferior_hook" target_so_ops routine for ia64-hpux.  */
+
+static void
+ia64_hpux_solib_create_inferior_hook (int from_tty)
+{
+  CORE_ADDR load_info_addr;
+  load_info_t load_info;
+
+  /* Initially, we were thinking about adding a check that the program
+     (accessible through symfile_objfile) was linked against some shared
+     libraries, by searching for a ".dynamic" section.  However, could
+     this break in the case of a statically linked program that later
+     uses dlopen?  Programs that are fully statically linked are very
+     rare, and we will worry about them when we encounter one that
+     causes trouble.  */
+
+  /* Set the LI_TRACE flag in the load_info_t structure.  This enables
+     notifications when shared libraries are being mapped.  */
+  load_info_addr = ia64_hpux_get_load_info_addr ();
+  read_memory (load_info_addr, (gdb_byte *) &load_info, sizeof (load_info));
+  load_info.li_flags |= LI_TRACE;
+  write_memory (load_info_addr, (gdb_byte *) &load_info, sizeof (load_info));
+
+  /* If we just attached to our process, some shard libraries have
+     already been mapped.  Find which ones they are...  */
+  if (current_inferior ()->attach_flag)
+    ia64_hpux_solib_add_after_attach ();
+}
+
+/* The "special_symbol_handling" target_so_ops routine for ia64-hpux.  */
+
+static void
+ia64_hpux_special_symbol_handling (void)
+{
+  /* Nothing to do.  */
+}
+
+/* The "current_sos" target_so_ops routine for ia64-hpux.  */
+
+static struct so_list *
+ia64_hpux_current_sos (void)
+{
+  /* Return a deep copy of our own list.  */
+  struct so_list *new_head = NULL, *prev_new_so = NULL;
+  struct so_list *our_so;
+
+  for (our_so = so_list_head; our_so != NULL; our_so = our_so->next)
+    {
+      struct so_list *new_so;
+
+      new_so = new_so_list (our_so->so_name, our_so->lm_info->module_desc);
+      if (prev_new_so != NULL)
+        prev_new_so->next = new_so;
+      prev_new_so = new_so;
+      if (new_head == NULL)
+        new_head = new_so;
+    }
+
+  return new_head;
+}
+
+/* The "open_symbol_file_object" target_so_ops routine for ia64-hpux.  */
+
+static int
+ia64_hpux_open_symbol_file_object (void *from_ttyp)
+{
+  return 0;
+}
+
+/* The "in_dynsym_resolve_code" target_so_ops routine for ia64-hpux.  */
+
+static int
+ia64_hpux_in_dynsym_resolve_code (CORE_ADDR pc)
+{
+  return 0;
+}
+
+/* If FADDR is the address of a function inside one of the shared
+   libraries, return the shared library linkage address.  */
+
+CORE_ADDR
+ia64_hpux_get_solib_linkage_addr (CORE_ADDR faddr)
+{
+  struct so_list *so = so_list_head;
+
+  while (so != NULL)
+    {
+      struct load_module_desc module_desc = so->lm_info->module_desc;
+
+      if (module_desc.text_base <= faddr
+          && (module_desc.text_base + module_desc.text_size) > faddr)
+        return module_desc.linkage_ptr;
+
+      so = so->next;
+    }
+
+  return 0;
+}
+
+/* Create a new target_so_ops structure suitable for ia64-hpux, and
+   return its address.  */
+
+static struct target_so_ops *
+ia64_hpux_target_so_ops (void)
+{
+  struct target_so_ops *ops = XZALLOC (struct target_so_ops);
+
+  ops->relocate_section_addresses = ia64_hpux_relocate_section_addresses;
+  ops->free_so = ia64_hpux_free_so;
+  ops->clear_solib = ia64_hpux_clear_solib;
+  ops->solib_create_inferior_hook = ia64_hpux_solib_create_inferior_hook;
+  ops->special_symbol_handling = ia64_hpux_special_symbol_handling;
+  ops->current_sos = ia64_hpux_current_sos;
+  ops->open_symbol_file_object = ia64_hpux_open_symbol_file_object;
+  ops->in_dynsym_resolve_code = ia64_hpux_in_dynsym_resolve_code;
+  ops->bfd_open = solib_bfd_open;
+
+  return ops;
+}
+
+/* Prevent warning from -Wmissing-prototypes.  */
+void _initialize_solib_ia64_hpux (void);
+
+void
+_initialize_solib_ia64_hpux (void)
+{
+  ia64_hpux_so_ops = ia64_hpux_target_so_ops ();
+}
diff --git a/gdb/solib-ia64-hpux.h b/gdb/solib-ia64-hpux.h
new file mode 100644
index 0000000..11b1a90
--- /dev/null
+++ b/gdb/solib-ia64-hpux.h
@@ -0,0 +1,25 @@
+/* Copyright (C) 2010 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#ifndef SOLIB_IA64_HPUX_H
+#define SOLIB_IA64_HPUX_H
+
+int ia64_hpux_at_dld_breakpoint_p (ptid_t ptid);
+void ia64_hpux_handle_dld_breakpoint (ptid_t ptid);
+CORE_ADDR ia64_hpux_get_solib_linkage_addr (CORE_ADDR faddr);
+
+#endif

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH 6/8] port GDB to ia64-hpux (native).
       [not found]               ` <1299173882.30497.114.camel@hpsje.cup.hp.com>
@ 2011-06-17 16:30                 ` Joel Brobecker
  0 siblings, 0 replies; 31+ messages in thread
From: Joel Brobecker @ 2011-06-17 16:30 UTC (permalink / raw)
  To: Steve Ellcey; +Cc: gdb-patches

[-- Attachment #1: Type: text/plain, Size: 1332 bytes --]

[putting gdb-patches back, in case it's useful to someone else]

Steve,

> > What I will do as soon as I have a moment is double-check that I didn't
> > make a mistake somewhere, or forgot something. That would definitely
> > explain the problems you are having. We'll get to the bottom of this!

I tried taking a look at what might be causing you some trouble.
I can see some differences between our GDB and the FSF GDB, but
nothing like what you are seeing.

I did have a hard time getting libunwind to be activated, though,
and that failure is silently activated, or not.  That's why I took
the bull by the horn, and decided to make that unconditional:
http://www.sourceware.org/ml/gdb-patches/2011-06/msg00234.html

As I said before, the system libunwind is not performing as well
as GNU libunwind does. I use libunwind-0.98.5, not the latest
version. Either version will need to be patched, but I'm attaching
the patch I use with 0.98.5. I also sent some patches to the
libunwind mailing list for the HEAD, but I haven't had time
to test.

That's really as far as I can spend on this, as I've already spent
8 times the 2 hours I wanted to dedicate.  There are a few fixes
I should track down at some point that will further improve the
results. But at least I'm satisfied that I didn't miss anything
in my patches...

-- 
Joel

[-- Attachment #2: libunwind-0.98.5.tar.gz.diff --]
[-- Type: text/x-diff, Size: 5625 bytes --]

2008-10-02  Joel Brobecker  <brobecker@adacore.com>

        On ia64-hpux version 11.31, there is no <sys/ptrace.h> anymore.

        * configure.in: Add check for sys/ptrace.h.
        * configure, include/config.h.in: Regenerate.
        * src/ptrace/_UPT_internal.h: Include sys/ptrace.h only when
        available. Also, include <sys/ptrace.h> AFTER including
        "internal.h".  Otherwise, "config.h" hasn't been included yet,
        and thus HAVE_SYS_PTRACE_H was not defined.

2005-09-02  Joel Brobecker  <brobecker@adacore.com>

        * Ginit.c (tdep_uc_addr): New function. Needed to avoid a link failure.

2005-09-02  Joel Brobecker  <brobecker@adacore.com>

        This patches fixes a problem on ia64-hpux when trying to build
        this package using GCC 3.4.4. The makefile was incorrectly using
        -lgcc instead of -lgcc_s to build the libunwind shared library.
        libtool noticed that libgcc does not exist in a shared library
        version, and hence removed it from the list of dependencies (after
        printing a warning). This adds the missing dependency back, so
        that another program dlopen()'ing it doesn't fail due to unresolved
        symbols.
        * configure.in (LIBCRTS): Use -lgcc_s instead of -lgcc when needed.
        * configure: Regenerate.

Index: configure
===================================================================
--- configure	(revision 131627)
+++ configure	(revision 131628)
@@ -20870,6 +20870,16 @@ rm -f conftest.err conftest.$ac_objext c
 if test x$GCC = xyes -a x$intel_compiler != xyes; then
   CFLAGS="${CFLAGS} -Wall -Wsign-compare"
   LIBCRTS="-lgcc"
+
+  # What we really want to do is link our libraries against is the shared
+  # version of libgcc.  Unfortunately, this library may either be named
+  # libgcc or libgcc_s.  Try to see if GCC recognizes libgcc_s, in which
+  # case we should be linking against libgcc_s.
+  libgcc_s_so=libgcc_s.so
+  libgcc_s_path=`$CC -print-file-name=$libgcc_s_so`
+  if test x$libgcc_s_path != x$libgcc_s_so; then
+    LIBCRTS="-lgcc_s"
+  fi
 fi
 
 CCASFLAGS="${CCASFLAGS} ${CPPFLAGS}"

Index: configure.in
===================================================================
--- configure.in	(revision 131627)
+++ configure.in	(revision 131628)
@@ -103,6 +103,16 @@ AC_TRY_COMPILE([], [#ifndef __INTEL_COMP
 if test x$GCC = xyes -a x$intel_compiler != xyes; then
   CFLAGS="${CFLAGS} -Wall -Wsign-compare"
   LIBCRTS="-lgcc"
+
+  # What we really want to do is link our libraries against is the shared
+  # version of libgcc.  Unfortunately, this library may either be named
+  # libgcc or libgcc_s.  Try to see if GCC recognizes libgcc_s, in which
+  # case we should be linking against libgcc_s.
+  libgcc_s_so=libgcc_s.so
+  libgcc_s_path=`$CC -print-file-name=$libgcc_s_so`
+  if test x$libgcc_s_path != x$libgcc_s_so; then
+    LIBCRTS="-lgcc_s"
+  fi
 fi
 
 CCASFLAGS="${CCASFLAGS} ${CPPFLAGS}"

Index: src/ia64/Ginit.c
===================================================================
--- src/ia64/Ginit.c	(revision 131628)
+++ src/ia64/Ginit.c	(revision 131629)
@@ -82,6 +82,17 @@ PROTECTED unw_addr_space_t unw_local_add
 
 #ifdef HAVE_SYS_UC_ACCESS_H
 
+void *
+tdep_uc_addr (ucontext_t *uc, int reg, uint8_t *nat_bitnr)
+{
+  /* brobecker/2005-09-01: I couldn't find a way of implementing this
+     on ia64-hpux, as the uc structure is opaque.  The OS provides
+     ways to get the values themselves, but not their address. However,
+     I haven't seen this procedure being used at all so far, so we'll
+     just return NULL for now.  */
+  return NULL;
+}
+
 #else /* !HAVE_SYS_UC_ACCESS_H */
 
 HIDDEN void *

Index: configure
===================================================================
--- configure	(revision 135785)
+++ configure	(revision 136181)
@@ -19740,7 +19740,7 @@ fi
 
 
 for ac_header in asm/ptrace_offsets.h endian.h execinfo.h ia64intrin.h \
-		 sys/uc_access.h unistd.h signal.h
+		 sys/uc_access.h unistd.h signal.h sys/ptrace.h
 do
 as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh`
 if eval "test \"\${$as_ac_Header+set}\" = set"; then
Index: include/config.h.in
===================================================================
--- include/config.h.in	(revision 135785)
+++ include/config.h.in	(revision 136181)
@@ -60,6 +60,9 @@
 /* Define to 1 if `dlpi_subs' is member of `struct dl_phdr_info'. */
 #undef HAVE_STRUCT_DL_PHDR_INFO_DLPI_SUBS
 
+/* Define to 1 if you have the <sys/ptrace.h> header file. */
+#undef HAVE_SYS_PTRACE_H
+
 /* Define to 1 if you have the <sys/stat.h> header file. */
 #undef HAVE_SYS_STAT_H
 
Index: configure.in
===================================================================
--- configure.in	(revision 135785)
+++ configure.in	(revision 136181)
@@ -28,7 +28,7 @@ CHECK_ATOMIC_OPS
 dnl Checks for header files.
 AC_HEADER_STDC
 AC_CHECK_HEADERS(asm/ptrace_offsets.h endian.h execinfo.h ia64intrin.h \
-		 sys/uc_access.h unistd.h signal.h)
+		 sys/uc_access.h unistd.h signal.h sys/ptrace.h)
 
 dnl Checks for typedefs, structures, and compiler characteristics.
 AC_C_CONST
Index: src/ptrace/_UPT_internal.h
===================================================================
--- src/ptrace/_UPT_internal.h	(revision 135785)
+++ src/ptrace/_UPT_internal.h	(revision 136181)
@@ -32,11 +32,13 @@ WITH THE SOFTWARE OR THE USE OR OTHER DE
 #include <stdio.h>
 #include <stdlib.h>
 
-#include <sys/ptrace.h>
-
 #include "internal.h"
 #include "tdep.h"
 
+#ifdef HAVE_SYS_PTRACE_H
+#include <sys/ptrace.h>
+#endif
+
 struct UPT_info
   {
     pid_t pid;		/* the process-id of the child we're unwinding */

^ permalink raw reply	[flat|nested] 31+ messages in thread

end of thread, other threads:[~2011-06-17 16:30 UTC | newest]

Thread overview: 31+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2010-12-28  4:43 Porting GDB to ia64-hpux Joel Brobecker
2010-12-28  4:43 ` [PATCH 4/8] libunwind-frame.c: handle functions with no minimal symbol/debug info Joel Brobecker
2010-12-28  4:43 ` [PATCH 1/8] Add a big-endian version of the ia64-ext floatformat Joel Brobecker
2010-12-28  4:43 ` [PATCH 2/8] small integral parameters and return values Joel Brobecker
2010-12-28  4:44 ` [PATCH 6/8] port GDB to ia64-hpux (native) Joel Brobecker
2011-01-11 23:26   ` Steve Ellcey
2011-01-12  1:26     ` Joel Brobecker
2011-01-12 16:57       ` Steve Ellcey
2011-01-12 20:11         ` Joel Brobecker
2011-01-13  1:01     ` Joel Brobecker
2011-01-13  5:13       ` Steve Ellcey
     [not found]       ` <1299014508.30497.20.camel@hpsje.cup.hp.com>
     [not found]         ` <20110302044549.GU2513@adacore.com>
     [not found]           ` <1299171098.30497.88.camel@hpsje.cup.hp.com>
     [not found]             ` <20110303172717.GJ2513@adacore.com>
     [not found]               ` <1299173882.30497.114.camel@hpsje.cup.hp.com>
2011-06-17 16:30                 ` Joel Brobecker
2011-01-13 18:07   ` Joel Brobecker
2010-12-28  4:44 ` [PATCH 3/8] Make sure __LITTLE_ENDIAN/__BIG_ENDIAN are defined in libunwind-frame.c Joel Brobecker
2010-12-28  4:44 ` [PATCH 5/8] inf-ttrace: Determine attached process LWP immediately after attaching Joel Brobecker
2010-12-28 11:04   ` Pedro Alves
2010-12-28 11:26     ` Joel Brobecker
2010-12-28  4:54 ` [PATCH 7/8] ia64-hpux: unwinding bsp value from system call Joel Brobecker
2010-12-28 11:35   ` Pedro Alves
2010-12-28 12:01     ` Joel Brobecker
2010-12-28 16:17       ` Pedro Alves
2010-12-29  5:49         ` Joel Brobecker
2010-12-29 12:05           ` Pedro Alves
2010-12-29 13:16             ` Joel Brobecker
2010-12-31 18:15             ` Joel Brobecker
2010-12-28 15:29     ` [RFA/commit] Add documentation for TARGET_OBJECT_OSDATA Joel Brobecker
2010-12-28 15:46       ` Pedro Alves
2010-12-29  3:29       ` Joel Brobecker
2010-12-28  5:00 ` [PATCH 8/8] [ia64-hpux] inferior function call support Joel Brobecker
2010-12-31 19:18   ` Joel Brobecker
2011-01-13 16:53 ` Porting GDB to ia64-hpux Joel Brobecker

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).