Mirror of the gdb-patches mailing list
 help / color / mirror / Atom feed
* RFA: New port: ia64-hp-openvms (0/3)
@ 2012-02-10 13:07 Tristan Gingold
  2012-02-10 13:21 ` RFA: New port: ia64-hp-openvms (1/3) - new osabi Tristan Gingold
                   ` (2 more replies)
  0 siblings, 3 replies; 31+ messages in thread
From: Tristan Gingold @ 2012-02-10 13:07 UTC (permalink / raw)
  To: gdb-patches@sourceware.org ml; +Cc: Rupp Douglas

Hi,

this is a set of small patches to add support for cross debugging for ia64-hp-openvms.  Nothing very fancy yet, this is just a variation for ia64.

All the interesting stuff is in the stub, which will be submitted separately.

Tristan.


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

* RFA: New port: ia64-hp-openvms (1/3) - new osabi
  2012-02-10 13:07 RFA: New port: ia64-hp-openvms (0/3) Tristan Gingold
@ 2012-02-10 13:21 ` Tristan Gingold
  2012-02-10 13:27   ` RFA: New port: ia64-hp-openvms (3/3) - ia64-vms-tdep.c Tristan Gingold
  2012-02-12  9:36   ` RFA: New port: ia64-hp-openvms (1/3) - new osabi Mark Kettenis
  2012-02-10 13:23 ` RFA: New port: ia64-hp-openvms (2/3) Tristan Gingold
  2012-02-10 13:44 ` RFA: New port: ia64-hp-openvms - the stub Tristan Gingold
  2 siblings, 2 replies; 31+ messages in thread
From: Tristan Gingold @ 2012-02-10 13:21 UTC (permalink / raw)
  To: gdb-patches@sourceware.org ml; +Cc: Rupp Douglas

OpenVMS has its own ABI…

Tristan.

2012-02-10  Tristan Gingold  <gingold@adacore.com>

	* osabi.c (gdb_osabi_names): Add OpenVMS.
	(generic_elf_osabi_sniffer): Likewise.
	* defs.h (gdb_osabi): Add GDB_OSABI_OPENVMS.


diff --git a/gdb/defs.h b/gdb/defs.h
index a97487a..1075111 100644
--- a/gdb/defs.h
+++ b/gdb/defs.h
@@ -948,6 +948,7 @@ enum gdb_osabi
   GDB_OSABI_DICOS,
   GDB_OSABI_DARWIN,
   GDB_OSABI_SYMBIAN,
+  GDB_OSABI_OPENVMS,
 
   GDB_OSABI_INVALID		/* keep this last */
 };
diff --git a/gdb/osabi.c b/gdb/osabi.c
index aba9842..faffe30 100644
--- a/gdb/osabi.c
+++ b/gdb/osabi.c
@@ -72,6 +72,7 @@ static const char * const gdb_osabi_names[] =
   "DICOS",
   "Darwin",
   "Symbian",
+  "OpenVMS",
 
   "<invalid>"
 };
@@ -549,6 +550,10 @@ generic_elf_osabi_sniffer (bfd *abfd)
 			     generic_elf_osabi_sniff_abi_tag_sections,
 			     &osabi);
       break;
+
+    case ELFOSABI_OPENVMS:
+      osabi = GDB_OSABI_OPENVMS;
+      break;
     }
 
   if (osabi == GDB_OSABI_UNKNOWN)


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

* RFA: New port: ia64-hp-openvms (2/3)
  2012-02-10 13:07 RFA: New port: ia64-hp-openvms (0/3) Tristan Gingold
  2012-02-10 13:21 ` RFA: New port: ia64-hp-openvms (1/3) - new osabi Tristan Gingold
@ 2012-02-10 13:23 ` Tristan Gingold
  2012-02-12  9:39   ` Mark Kettenis
  2012-02-14 17:36   ` Pedro Alves
  2012-02-10 13:44 ` RFA: New port: ia64-hp-openvms - the stub Tristan Gingold
  2 siblings, 2 replies; 31+ messages in thread
From: Tristan Gingold @ 2012-02-10 13:23 UTC (permalink / raw)
  To: gdb-patches@sourceware.org ml; +Cc: Rupp Douglas

The easiest way to get the unwind entry is to ask to the OpenVMS kernel, as this always work.
Might not be optimal for the user application, but it is bullet-proof.

Tristan.

2012-02-10  Tristan Gingold  <gingold@adacore.com>

	* target.h (target_object): Add TARGET_OBJECT_OPENVMS_UIB.
	* remote.c (PACKET_qXfer_uib): New enum value.
	(remote_protocol_features): Add entry for PACKET_qXfer_uib.
	(remote_xfer_partial): Handle TARGET_OBJECT_OPENVMS_UIB.


diff --git a/gdb/remote.c b/gdb/remote.c
index 3187ac0..7787864 100644
--- a/gdb/remote.c
+++ b/gdb/remote.c
@@ -1250,6 +1250,7 @@ enum {
   PACKET_qXfer_threads,
   PACKET_qXfer_statictrace_read,
   PACKET_qXfer_traceframe_info,
+  PACKET_qXfer_uib,
   PACKET_qGetTIBAddr,
   PACKET_qGetTLSAddr,
   PACKET_qSupported,
@@ -3830,6 +3831,8 @@ static struct protocol_feature remote_protocol_features[] = {
     remote_enable_disable_tracepoint_feature, -1 },
   { "qXfer:fdpic:read", PACKET_DISABLE, remote_supported_packet,
     PACKET_qXfer_fdpic },
+  { "qXfer:uib:read", PACKET_DISABLE, remote_supported_packet,
+    PACKET_qXfer_uib },
   { "QDisableRandomization", PACKET_DISABLE, remote_supported_packet,
     PACKET_QDisableRandomization },
   { "tracenz", PACKET_DISABLE,
@@ -8417,6 +8420,12 @@ remote_xfer_partial (struct target_ops *ops, enum target_object object,
     case TARGET_OBJECT_FDPIC:
       return remote_read_qxfer (ops, "fdpic", annex, readbuf, offset, len,
 				&remote_protocol_packets[PACKET_qXfer_fdpic]);
+
+    case TARGET_OBJECT_OPENVMS_UIB:
+      return remote_read_qxfer
+        (ops, "uib", annex, readbuf, offset, len,
+         &remote_protocol_packets[PACKET_qXfer_uib]);
+
     default:
       return -1;
     }
diff --git a/gdb/target.h b/gdb/target.h
index d4605ae..5f642be 100644
--- a/gdb/target.h
+++ b/gdb/target.h
@@ -280,7 +280,9 @@ enum target_object
   /* Load maps for FDPIC systems.  */
   TARGET_OBJECT_FDPIC,
   /* Darwin dynamic linker info data.  */
-  TARGET_OBJECT_DARWIN_DYLD_INFO
+  TARGET_OBJECT_DARWIN_DYLD_INFO,
+  /* OpenVMS Unwind Information Block.  */
+  TARGET_OBJECT_OPENVMS_UIB
   /* Possible future objects: TARGET_OBJECT_FILE, ...  */
 };
 


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

* RFA: New port: ia64-hp-openvms (3/3) - ia64-vms-tdep.c
  2012-02-10 13:21 ` RFA: New port: ia64-hp-openvms (1/3) - new osabi Tristan Gingold
@ 2012-02-10 13:27   ` Tristan Gingold
  2012-02-14 17:50     ` Pedro Alves
  2012-02-12  9:36   ` RFA: New port: ia64-hp-openvms (1/3) - new osabi Mark Kettenis
  1 sibling, 1 reply; 31+ messages in thread
From: Tristan Gingold @ 2012-02-10 13:27 UTC (permalink / raw)
  To: gdb-patches@sourceware.org ml; +Cc: Rupp Douglas

Most of the code of ia64-tdep.c can be reused, except for unwinding.  So I added a ia64-vms-tdep.c.

Tristan.

2012-02-10  Tristan Gingold  <gingold@adacore.com>

        * ia64-tdep.h: Include libunwind-frame.h and libunwind-ia64.h.
        (ia64_unw_accessors, ia64_unw_rse_accessors)
        (ia64_libunwind_descr): Declare.
        * ia64-vms-tdep.c: New file.
        * ia64-tdep.c (ia64_unw_accessors, ia64_unw_rse_accessors)
        (ia64_libunwind_descr): Make them public.
        * configure.tgt: Add ia64-*-*vms*.
        * Makefile.in (ALL_64_TARGET_OBS): Add ia64-vms-tdep.o
        (ALLDEPFILES): Add ia64-vms-tdep.c

diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index 9f30a61..4c67d0d 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -516,7 +516,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-hpux-tdep.o ia64-linux-tdep.o ia64-tdep.o \
+	ia64-hpux-tdep.o ia64-linux-tdep.o ia64-vms-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
@@ -1456,7 +1456,7 @@ ALLDEPFILES = \
 	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 \
+	ia64-linux-nat.c ia64-linux-tdep.c ia64-tdep.c ia64-vms-tdep.c \
 	inf-ptrace.c inf-ttrace.c \
 	irix5-nat.c \
 	libunwind-frame.c \
diff --git a/gdb/configure.tgt b/gdb/configure.tgt
index 5e97ab4..6b4a504 100644
--- a/gdb/configure.tgt
+++ b/gdb/configure.tgt
@@ -246,6 +246,10 @@ ia64-*-linux*)
 			solib-svr4.o symfile-mem.o"
 	build_gdbserver=yes
 	;;
+ia64-*-*vms*)
+	# Target: Intel IA-64 running OpenVMS
+	gdb_target_obs="ia64-tdep.o ia64-vms-tdep.o"
+	;;
 ia64*-*-*)
 	# Target: Intel IA-64
 	gdb_target_obs="ia64-tdep.o"
diff --git a/gdb/ia64-tdep.c b/gdb/ia64-tdep.c
index a36dc22..1c4fa8f 100644
--- a/gdb/ia64-tdep.c
+++ b/gdb/ia64-tdep.c
@@ -3148,7 +3148,7 @@ static const struct frame_unwind ia64_libunwind_sigtramp_frame_unwind =
 };
 
 /* Set of libunwind callback acccessor functions.  */
-static unw_accessors_t ia64_unw_accessors =
+unw_accessors_t ia64_unw_accessors =
 {
   ia64_find_proc_info_x,
   ia64_put_unwind_info,
@@ -3164,7 +3164,7 @@ static unw_accessors_t ia64_unw_accessors =
    the rse registers.  At the top of the stack, we want libunwind to figure out
    how to read r32 - r127.  Though usually they are found sequentially in
    memory starting from $bof, this is not always true.  */
-static unw_accessors_t ia64_unw_rse_accessors =
+unw_accessors_t ia64_unw_rse_accessors =
 {
   ia64_find_proc_info_x,
   ia64_put_unwind_info,
@@ -3178,7 +3178,7 @@ static unw_accessors_t ia64_unw_rse_accessors =
 
 /* Set of ia64 gdb libunwind-frame callbacks and data for generic
    libunwind-frame code to use.  */
-static struct libunwind_descr ia64_libunwind_descr =
+struct libunwind_descr ia64_libunwind_descr =
 {
   ia64_gdb2uw_regnum, 
   ia64_uw2gdb_regnum, 
diff --git a/gdb/ia64-tdep.h b/gdb/ia64-tdep.h
index 48cc3e0..7501eb4 100644
--- a/gdb/ia64-tdep.h
+++ b/gdb/ia64-tdep.h
@@ -20,6 +20,11 @@
 #ifndef IA64_TDEP_H
 #define IA64_TDEP_H
 
+#ifdef HAVE_LIBUNWIND_IA64_H
+#include "libunwind-ia64.h"
+#include "libunwind-frame.h"
+#endif
+
 /* Register numbers of various important registers.  */
 
 /* General registers; there are 128 of these 64 bit wide registers.
@@ -250,4 +255,10 @@ struct gdbarch_tdep
 
 extern void ia64_write_pc (struct regcache *, CORE_ADDR);
 
+#ifdef HAVE_LIBUNWIND_IA64_H
+extern unw_accessors_t ia64_unw_accessors;
+extern unw_accessors_t ia64_unw_rse_accessors;
+extern struct libunwind_descr ia64_libunwind_descr;
+#endif
+
 #endif /* ia64-tdep.h */
diff --git a/gdb/ia64-vms-tdep.c b/gdb/ia64-vms-tdep.c
new file mode 100644
index 0000000..1728ba0
--- /dev/null
+++ b/gdb/ia64-vms-tdep.c
@@ -0,0 +1,165 @@
+/* Target-dependent code for OpenVMS IA-64.
+
+   Copyright (C) 2012 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 "frame-unwind.h"
+#include "ia64-tdep.h"
+#include "osabi.h"
+#include "gdbtypes.h"
+#include "solib.h"
+#include "target.h"
+#include "frame.h"
+#include "regcache.h"
+#include "gdbcore.h"
+#include "inferior.h"
+
+#ifdef HAVE_LIBUNWIND_IA64_H
+
+/* Libunwind callback accessor function to acquire procedure unwind-info.  */
+static int
+ia64_vms_find_proc_info_x (unw_addr_space_t as, unw_word_t ip,
+                           unw_proc_info_t *pi,
+                           int need_unwind_info, void *arg)
+{
+  enum bfd_endian byte_order = gdbarch_byte_order (target_gdbarch);
+  unw_dyn_info_t di;
+  int ret;
+  unsigned char buf[32];
+  const char *annex = core_addr_to_string (ip);
+  LONGEST res;
+  CORE_ADDR table_addr;
+  unsigned int info_len;
+
+  res = target_read (&current_target, TARGET_OBJECT_OPENVMS_UIB,
+                     annex + 2, buf, 0, sizeof (buf));
+
+  if (res != sizeof (buf))
+    return -UNW_ENOINFO;
+
+  pi->format = UNW_INFO_FORMAT_REMOTE_TABLE;
+  pi->start_ip = extract_unsigned_integer (buf + 0, 8, byte_order);
+  pi->end_ip = extract_unsigned_integer (buf + 8, 8, byte_order);
+  pi->gp = extract_unsigned_integer (buf + 24, 8, byte_order);
+  table_addr = extract_unsigned_integer (buf + 16, 8, byte_order);
+
+  if (table_addr == 0)
+    {
+      /* No unwind data.  */
+      pi->unwind_info = NULL;
+      pi->unwind_info_size = 0;
+      return 0;
+    }
+
+  res = target_read_memory (table_addr, buf, 8);
+  if (res != 0)
+    return -UNW_ENOINFO;
+
+  /* Check version.  */
+  if (extract_unsigned_integer (buf + 6, 2, byte_order) != 1)
+      return -UNW_EBADVERSION;
+  info_len = extract_unsigned_integer (buf + 0, 4, byte_order);
+  pi->unwind_info_size = 8 * info_len;
+
+  /* Read info.  */
+  pi->unwind_info = malloc (pi->unwind_info_size);
+  if (!pi->unwind_info)
+    return -UNW_ENOMEM;
+
+  res = target_read_memory (table_addr + 8,
+                            pi->unwind_info, pi->unwind_info_size);
+  if (res != 0)
+    {
+      free (pi->unwind_info);
+      pi->unwind_info = NULL;
+      return -UNW_ENOINFO;
+    }
+
+  /* FIXME: OSSD.  */
+
+  pi->lsda = table_addr + 8 + pi->unwind_info_size;
+  if (extract_unsigned_integer (buf + 4, 2, byte_order) & 3)
+    {
+      pi->lsda += 8;
+      pi->handler = 0; /* FIXME: wrong, but who cares.  */
+    }
+
+  return 0;
+}
+
+/* Libunwind callback accessor function for cleanup.  */
+static void
+ia64_vms_put_unwind_info (unw_addr_space_t as,
+                          unw_proc_info_t *pip, void *arg)
+{
+  /* Nothing required for now.  */
+}
+
+/* Libunwind callback accessor function to get head of the dynamic
+   unwind-info registration list.  */
+static int
+ia64_vms_get_dyn_info_list (unw_addr_space_t as,
+                            unw_word_t *dilap, void *arg)
+{
+  return -UNW_ENOINFO;
+}
+
+/* Set of libunwind callback acccessor functions.  */
+static unw_accessors_t ia64_vms_unw_accessors;
+static unw_accessors_t ia64_vms_unw_rse_accessors;
+
+/* Set of ia64 gdb libunwind-frame callbacks and data for generic
+   libunwind-frame code to use.  */
+static struct libunwind_descr ia64_vms_libunwind_descr;
+
+#endif /* HAVE_LIBUNWIND_IA64_H */
+
+static void
+ia64_openvms_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
+{
+  set_gdbarch_long_double_format (gdbarch, floatformats_ia64_quad);
+
+#ifdef HAVE_LIBUNWIND_IA64_H
+  /* Override the default descriptor.  */
+  ia64_vms_unw_accessors = ia64_unw_accessors;
+  ia64_vms_unw_accessors.find_proc_info = ia64_vms_find_proc_info_x;
+  ia64_vms_unw_accessors.put_unwind_info = ia64_vms_put_unwind_info;
+  ia64_vms_unw_accessors.get_dyn_info_list_addr = ia64_vms_get_dyn_info_list;
+
+  ia64_vms_unw_rse_accessors = ia64_unw_rse_accessors;
+  ia64_vms_unw_rse_accessors.find_proc_info = ia64_vms_find_proc_info_x;
+  ia64_vms_unw_rse_accessors.put_unwind_info = ia64_vms_put_unwind_info;
+  ia64_vms_unw_rse_accessors.get_dyn_info_list_addr = ia64_vms_get_dyn_info_list;
+
+  ia64_vms_libunwind_descr = ia64_libunwind_descr;
+  ia64_vms_libunwind_descr.accessors = &ia64_vms_unw_accessors;
+  ia64_vms_libunwind_descr.special_accessors = &ia64_vms_unw_rse_accessors;
+
+  libunwind_frame_set_descr (gdbarch, &ia64_vms_libunwind_descr);
+#endif
+}
+
+/* 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_OPENVMS,
+			  ia64_openvms_init_abi);
+}


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

* RFA: New port: ia64-hp-openvms - the stub
  2012-02-10 13:07 RFA: New port: ia64-hp-openvms (0/3) Tristan Gingold
  2012-02-10 13:21 ` RFA: New port: ia64-hp-openvms (1/3) - new osabi Tristan Gingold
  2012-02-10 13:23 ` RFA: New port: ia64-hp-openvms (2/3) Tristan Gingold
@ 2012-02-10 13:44 ` Tristan Gingold
  2012-02-10 19:06   ` Douglas Rupp
  2012-02-14 18:09   ` Pedro Alves
  2 siblings, 2 replies; 31+ messages in thread
From: Tristan Gingold @ 2012-02-10 13:44 UTC (permalink / raw)
  To: gdb-patches@sourceware.org ml; +Cc: Rupp Douglas

Hi,

this is the debugger stub for ia64 VMS.
Because it is independent of gdb (not unlike gdbserver) and because it isn't a one file stub, I think it is worth creating a subdirectory.
I think we should also move the existing stubs there.

The interesting part is that on OpenVMS, the debugger is a shared library that is loaded with the application when debugging is needed (either from the start or during the run - like attach).  Just think about catching SIGTRAP, SIGSEGV, SIGBUS,… from a LD_PRELOAD binary.

The stub was written from scratch because it is highly OpenVMS dependent and in particular the standard C library shouldn't be used.

The stub is not complete: some registers are partially or not handled, and inferior procedure call is not yet implemented (will be the funny part).  But it has already be extremely useful to debug some applications.

Tristan.

gdb/stubs:
2012-02-10  Tristan Gingold  <gingold@adacore.com>

	* buildvms.com: New file.
	* ia64vms-stub.c: New file.

diff --git a/gdb/stubs/buildvms.com b/gdb/stubs/buildvms.com
new file mode 100644
index 0000000..5ac2bf9
--- /dev/null
+++ b/gdb/stubs/buildvms.com
@@ -0,0 +1,9 @@
+$! Command to build the gdb stub
+$cc ia64vms-stub +sys$library:sys$lib_c.tlb/lib
+$ link/notraceback/sysexe/map=stub.map/full/share=gdbstub.exe ia64vms-stub,sys$input/opt
+$deck
+cluster=gdbzero
+collect=gdbzero, XFER_PSECT
+$eod
+$! Example of use.
+$ DEFINE /nolog LIB$DEBUG sys$login:gdbstub.exe
diff --git a/gdb/stubs/ia64vms-stub.c b/gdb/stubs/ia64vms-stub.c
new file mode 100644
index 0000000..256b95f
--- /dev/null
+++ b/gdb/stubs/ia64vms-stub.c
@@ -0,0 +1,1583 @@
+/* GDB stub for Itanium OpenVMS
+   Copyright (C) 2012, Free Software Foundation, Inc.
+
+   Contributed by Tristan Gingold, AdaCore.
+
+   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/>.  */
+
+/* On VMS, the debugger (in our case the stub) is loaded in the process and
+   executed (via SYS$IMGSTA) before the main entry point of the executable.
+   In UNIX parlance, this is like using LD_PRELOAD and debug via installing
+   SIGTRAP, SIGSEGV... handlers.
+
+   This is currently a partial implementation.  In particular, modifying
+   registers is currently not implemented, as well as inferior procedure
+   calls.
+
+   This is written in very low-level C, in order not to use the C runtime,
+   because it may have weird consequences on the program being debugged.
+*/
+
+#define __NEW_STARLET 1
+#include <descrip.h>
+#include <iledef.h>
+#include <efndef.h>
+#include <in.h>
+#include <inet.h>
+#include <iodef.h>
+#include <ssdef.h>
+#include <starlet.h>
+#include <stsdef.h>
+#include <tcpip$inetdef.h>
+
+#include <lib$routines.h>
+#include <ots$routines.h>
+#include <str$routines.h>
+#include <libdef.h>
+#include <clidef.h>
+#include <iosbdef.h>
+#include <dvidef.h>
+#include <lnmdef.h>
+#include <builtins.h>
+#include <prtdef.h>
+#include <psldef.h>
+#include <ssdef.h>
+#include <chfdef.h>
+
+#include <lib_c/intstkdef.h>
+#include <lib_c/psrdef.h>
+
+/* Declared in lib$ots.  */
+extern void ots$fill (void *addr, size_t len, unsigned char b);
+extern int ots$strcmp_eql (const void *str1, size_t str1len,
+                           const void *str2, size_t str2len);
+
+/* Stub port number.  */
+static unsigned int serv_port = 1234;
+
+/* If true, display packets exchanged with gdb.  */
+static int trace_pkt = 0;
+
+/* If true, display info about entry point.  */
+static int trace_entry = 0;
+
+/* If true, display all exceptions.  */
+static int trace_excp = 0;
+
+/* Connect inet device I/O channel.  */
+static unsigned short conn_channel;
+
+/* Socket characteristics.  Apparently, there are no declaration for it in
+   standard headers.  */
+struct sockchar
+{
+  unsigned short prot;
+  unsigned char type;
+  unsigned char af;
+};
+
+/* IA64 integer register representation.  */
+union ia64_ireg
+{
+  unsigned __int64 v;
+  unsigned char b[8];
+};
+
+/* IA64 register numbers, as defined by ia64-tdep.h.  */
+#define IA64_GR0_REGNUM		0
+#define IA64_GR32_REGNUM	(IA64_GR0_REGNUM + 32)
+
+/* Floating point registers; 128 82-bit wide registers.  */
+#define IA64_FR0_REGNUM		128
+
+/* Predicate registers; There are 64 of these one bit registers.  It'd
+   be more convenient (implementation-wise) to use a single 64 bit
+   word with all of these register in them.  Note that there's also a
+   IA64_PR_REGNUM below which contains all the bits and is used for
+   communicating the actual values to the target.  */
+#define IA64_PR0_REGNUM		256
+
+/* Branch registers: 8 64-bit registers for holding branch targets.  */
+#define IA64_BR0_REGNUM		320
+
+/* Virtual frame pointer; this matches IA64_FRAME_POINTER_REGNUM in
+   gcc/config/ia64/ia64.h.  */
+#define IA64_VFP_REGNUM		328
+
+/* Virtual return address pointer; this matches
+   IA64_RETURN_ADDRESS_POINTER_REGNUM in gcc/config/ia64/ia64.h.  */
+#define IA64_VRAP_REGNUM	329
+
+/* Predicate registers: There are 64 of these 1-bit registers.  We
+   define a single register which is used to communicate these values
+   to/from the target.  We will somehow contrive to make it appear
+   that IA64_PR0_REGNUM thru IA64_PR63_REGNUM hold the actual values.  */
+#define IA64_PR_REGNUM		330
+
+/* Instruction pointer: 64 bits wide.  */
+#define IA64_IP_REGNUM		331
+
+/* Process Status Register.  */
+#define IA64_PSR_REGNUM		332
+
+/* Current Frame Marker (raw form may be the cr.ifs).  */
+#define IA64_CFM_REGNUM		333
+
+/* Application registers; 128 64-bit wide registers possible, but some
+   of them are reserved.  */
+#define IA64_AR0_REGNUM		334
+#define IA64_KR0_REGNUM		(IA64_AR0_REGNUM + 0)
+#define IA64_KR7_REGNUM		(IA64_KR0_REGNUM + 7)
+
+#define IA64_RSC_REGNUM		(IA64_AR0_REGNUM + 16)
+#define IA64_BSP_REGNUM		(IA64_AR0_REGNUM + 17)
+#define IA64_BSPSTORE_REGNUM	(IA64_AR0_REGNUM + 18)
+#define IA64_RNAT_REGNUM	(IA64_AR0_REGNUM + 19)
+#define IA64_FCR_REGNUM		(IA64_AR0_REGNUM + 21)
+#define IA64_EFLAG_REGNUM	(IA64_AR0_REGNUM + 24)
+#define IA64_CSD_REGNUM		(IA64_AR0_REGNUM + 25)
+#define IA64_SSD_REGNUM		(IA64_AR0_REGNUM + 26)
+#define IA64_CFLG_REGNUM	(IA64_AR0_REGNUM + 27)
+#define IA64_FSR_REGNUM		(IA64_AR0_REGNUM + 28)
+#define IA64_FIR_REGNUM		(IA64_AR0_REGNUM + 29)
+#define IA64_FDR_REGNUM		(IA64_AR0_REGNUM + 30)
+#define IA64_CCV_REGNUM		(IA64_AR0_REGNUM + 32)
+#define IA64_UNAT_REGNUM	(IA64_AR0_REGNUM + 36)
+#define IA64_FPSR_REGNUM	(IA64_AR0_REGNUM + 40)
+#define IA64_ITC_REGNUM		(IA64_AR0_REGNUM + 44)
+#define IA64_PFS_REGNUM		(IA64_AR0_REGNUM + 64)
+#define IA64_LC_REGNUM		(IA64_AR0_REGNUM + 65)
+#define IA64_EC_REGNUM		(IA64_AR0_REGNUM + 66)
+
+/* NAT (Not A Thing) Bits for the general registers; there are 128 of
+   these.  */
+#define IA64_NAT0_REGNUM	462
+
+/* Process registers when a condition is caught.  */
+struct ia64_all_regs
+{
+  union ia64_ireg gr[32];
+  union ia64_ireg br[8];
+  union ia64_ireg ip;
+  union ia64_ireg psr;
+  union ia64_ireg bsp;
+  union ia64_ireg cfm;
+  union ia64_ireg pfs;
+  union ia64_ireg pr;
+};
+
+static struct ia64_all_regs regs;
+
+/* IO channel for the terminal.  */
+static unsigned short term_chan;
+
+/* Output buffer and length.  */
+static char term_buf[128];
+static int term_buf_len;
+
+/* Buffer for communication with gdb.  */
+static unsigned char gdb_buf[sizeof (regs) * 2 + 64];
+static unsigned int gdb_blen;
+
+/* Previous primary handler.  */
+static void *prevhnd;
+
+/* Entry point address and bundle.  */
+static unsigned __int64 entry_pc;
+static unsigned char entry_saved[16];
+
+/* Write on the terminal.  */
+
+static void
+term_raw_write (const char *str, unsigned int len)
+{
+  unsigned short status;
+  struct _iosb iosb;
+
+  status = sys$qiow (EFN$C_ENF,           /* Event flag.  */
+                     term_chan,           /* I/O channel.  */
+                     IO$_WRITEVBLK,       /* I/O function code.  */
+                     &iosb,               /* I/O status block.  */
+                     0,                   /* Ast service routine.  */
+                     0,                   /* Ast parameter.  */
+                     (char *)str,         /* P1 - buffer address.  */
+                     len,                 /* P2 - buffer length.  */
+                     0, 0, 0, 0);
+
+  if (status & STS$M_SUCCESS)
+    status = iosb.iosb$w_status;
+  if (!(status & STS$M_SUCCESS))
+    LIB$SIGNAL (status);
+}
+
+/* Flush ther term buffer.  */
+
+static void
+term_flush (void)
+{
+  if (term_buf_len != 0)
+    {
+      term_raw_write (term_buf, term_buf_len);
+      term_buf_len = 0;
+    }
+}
+
+/* Write a single character, without translation.  */
+
+static void
+term_raw_putchar (char c)
+{
+  if (term_buf_len == sizeof (term_buf))
+    term_flush ();
+  term_buf[term_buf_len++] = c;
+}
+
+/* Write character C.  Translate '\n' to '\n\r'.  */
+
+static void
+term_putc (char c)
+{
+  term_raw_putchar (c);
+  if (c == '\n')
+    {
+      term_raw_putchar ('\r');
+      term_flush ();
+    }
+}
+
+/* Write a C string.  */
+
+static void
+term_puts (const char *str)
+{
+  while (*str)
+    term_putc (*str++);
+}
+
+/* Write LEN bytes from STR.  */
+
+static void
+term_write (const char *str, unsigned int len)
+{
+  for (; len > 0; len--)
+    term_putc (*str++);
+}
+
+static const char hex[] = "0123456789abcdef";
+
+/* Write V as a 16 hexa digits number.  */
+
+static void
+term_puthex8 (unsigned __int64 v)
+{
+  int i;
+
+  for (i = 0; i < 16; i++)
+    {
+      term_putc (hex[(v >> 60) & 0x0f]);
+      v <<= 4;
+    }
+}
+
+/* Write a byte in hexa (two digits).  */
+
+void
+term_puthex1 (unsigned int v)
+{
+  term_putc (hex[v >> 4]);
+  term_putc (hex[v & 0x0f]);
+}
+
+/* Write V in decimal.  */
+
+static void
+term_putdec (unsigned __int64 v)
+{
+  char res[20];
+  int i;
+
+  i = sizeof (res) - 1;
+  while (1)
+    {
+      res[i] = '0' + (v % 10);
+      v /= 10;
+      if (v == 0 || i == 0)
+        break;
+      i--;
+    }
+  term_write (res + i, sizeof (res) - i);
+}
+
+/* Write P in hexa.  */
+
+static void
+term_putp (void *p)
+{
+  term_puthex8 ((unsigned __int64)p);
+}
+
+/* New line.  */
+
+static void
+term_putnl (void)
+{
+  term_putc ('\n');
+}
+
+/* Initialize terminal.  */
+
+static void
+term_init (void)
+{
+  unsigned int status,i;
+  unsigned short len;
+  char resstring[LNM$C_NAMLENGTH];
+  static const $DESCRIPTOR (tabdesc, "LNM$FILE_DEV");
+  static const $DESCRIPTOR (logdesc, "SYS$OUTPUT");
+  $DESCRIPTOR (term_desc, resstring);
+  ILE3 item_lst[2];
+
+  item_lst[0].ile3$w_length = LNM$C_NAMLENGTH;
+  item_lst[0].ile3$w_code = LNM$_STRING;
+  item_lst[0].ile3$ps_bufaddr = resstring;
+  item_lst[0].ile3$ps_retlen_addr = &len;
+  item_lst[1].ile3$w_length = 0;
+  item_lst[1].ile3$w_code = 0;
+
+  /* Translate the logical name.  */
+  status = SYS$TRNLNM (0,          	  /* Attr of the logical name.  */
+                       (void *) &tabdesc, /* Logical name table.  */
+                       (void *) &logdesc, /* Logical name.  */
+                       0,          /* Access mode.  */
+                       item_lst);  /* Item list.  */
+  if (!(status & STS$M_SUCCESS))
+    LIB$SIGNAL (status);
+
+  term_desc.dsc$w_length = len;
+
+  /* Examine 4-byte header.  Skip escape sequence.  */
+  if (resstring[0] == 0x1B)
+    {
+      term_desc.dsc$w_length -= 4;
+      term_desc.dsc$a_pointer += 4;
+    }
+
+  /* Assign a channel.  */
+  status = sys$assign (&term_desc,   /* Device name.  */
+                       &term_chan,   /* I/O channel.  */
+                       0,            /* Access mode.  */
+                       0);
+  if (!(status & STS$M_SUCCESS))
+    LIB$SIGNAL (status);
+}
+
+/* Convert from native endianness to network endianness (and vice-versa).  */
+
+static unsigned int
+wordswap (unsigned int v)
+{
+  return ((v & 0xff) << 8) | ((v >> 8) & 0xff);
+}
+
+/* Initialize the socket connection, and wait for a client.  */
+
+static void
+sock_init (void)
+{
+  struct _iosb iosb;
+  unsigned int status;
+
+  /* Listen channel and characteristics.  */
+  unsigned short listen_channel;
+  struct sockchar listen_sockchar;
+
+  /* Client address.  */
+  unsigned short cli_addrlen;
+  struct sockaddr_in cli_addr;
+  ILE3 cli_itemlst;
+
+  /* Our address.  */
+  struct sockaddr_in serv_addr;
+  ILE2 serv_itemlst;
+
+  /* Reuseaddr option value (on).  */
+  int optval = 1;
+  ILE2 sockopt_itemlst;
+  ILE2 reuseaddr_itemlst;
+
+  /* TCP/IP network pseudodevice.  */
+  static const $DESCRIPTOR (inet_device, "TCPIP$DEVICE:");
+
+  /* Initialize socket characteristics.  */
+  listen_sockchar.prot = TCPIP$C_TCP;
+  listen_sockchar.type = TCPIP$C_STREAM;
+  listen_sockchar.af   = TCPIP$C_AF_INET;
+
+  /* Assign I/O channels to network device.  */
+  status = sys$assign ((void *) &inet_device, &listen_channel, 0, 0);
+  if (status & STS$M_SUCCESS)
+    status = sys$assign ((void *) &inet_device, &conn_channel, 0, 0);
+  if (!(status & STS$M_SUCCESS))
+    {
+      term_puts ("Failed to assign I/O channel(s)\n\r");
+      LIB$SIGNAL (status);
+    }
+
+  /* Create a listen socket.  */
+  status = sys$qiow (EFN$C_ENF,           /* Event flag.  */
+                     listen_channel,      /* I/O channel.  */
+                     IO$_SETMODE,         /* I/O function code.  */
+                     &iosb,               /* I/O status block.  */
+                     0,                   /* Ast service routine.  */
+                     0,                   /* Ast parameter.  */
+                     &listen_sockchar,    /* P1 - socket characteristics.  */
+                     0, 0, 0, 0, 0);
+  if (status & STS$M_SUCCESS)
+    status = iosb.iosb$w_status;
+  if (!(status & STS$M_SUCCESS))
+    {
+      term_puts ("Failed to create socket\n\r");
+      LIB$SIGNAL (status);
+    }
+
+  /* Set reuse address option.  */
+  /* Initialize reuseaddr's item-list element.  */
+  reuseaddr_itemlst.ile2$w_length   = sizeof (optval);
+  reuseaddr_itemlst.ile2$w_code     = TCPIP$C_REUSEADDR;
+  reuseaddr_itemlst.ile2$ps_bufaddr = &optval;
+
+  /* Initialize setsockopt's item-list descriptor.  */
+  sockopt_itemlst.ile2$w_length   = sizeof (reuseaddr_itemlst);
+  sockopt_itemlst.ile2$w_code     = TCPIP$C_SOCKOPT;
+  sockopt_itemlst.ile2$ps_bufaddr = &reuseaddr_itemlst;
+
+  status = sys$qiow (EFN$C_ENF,       /* Event flag.  */
+                     listen_channel,  /* I/O channel.  */
+                     IO$_SETMODE,     /* I/O function code.  */
+                     &iosb,           /* I/O status block.  */
+                     0,               /* Ast service routine.  */
+                     0,               /* Ast parameter.  */
+                     0,               /* P1.  */
+                     0,               /* P2.  */
+                     0,               /* P3.  */
+                     0,               /* P4.  */
+                     (__int64) &sockopt_itemlst, /* P5 - socket options.  */
+                     0);
+  if (status & STS$M_SUCCESS)
+    status = iosb.iosb$w_status;
+  if (!(status & STS$M_SUCCESS))
+    {
+      term_puts ("Failed to set socket option\n\r");
+      LIB$SIGNAL (status);
+    }
+
+  /* Bind server's ip address and port number to listen socket.  */
+  /* Initialize server's socket address structure.  */
+  ots$fill (&serv_addr, sizeof (serv_addr), 0);
+  serv_addr.sin_family = TCPIP$C_AF_INET;
+  serv_addr.sin_port = wordswap (serv_port);
+  serv_addr.sin_addr.s_addr = TCPIP$C_INADDR_ANY;
+
+  /* Initialize server's item-list descriptor.  */
+  serv_itemlst.ile2$w_length   = sizeof (serv_addr);
+  serv_itemlst.ile2$w_code     = TCPIP$C_SOCK_NAME;
+  serv_itemlst.ile2$ps_bufaddr = &serv_addr;
+
+  status = sys$qiow (EFN$C_ENF,           /* Event flag.  */
+                     listen_channel,      /* I/O channel.  */
+                     IO$_SETMODE,         /* I/O function code.  */
+                     &iosb,               /* I/O status block.  */
+                     0,                   /* Ast service routine.  */
+                     0,                   /* Ast parameter.  */
+                     0,                   /* P1.  */
+                     0,                   /* P2.  */
+                     (__int64) &serv_itemlst, /* P3 - local socket name.  */
+                     0, 0, 0);
+  if (status & STS$M_SUCCESS)
+    status = iosb.iosb$w_status;
+  if (!(status & STS$M_SUCCESS))
+    {
+      term_puts ("Failed to bind socket\n\r");
+      LIB$SIGNAL (status);
+    }
+
+  /* Set socket as a listen socket.  */
+  status = sys$qiow (EFN$C_ENF,           /* Event flag.  */
+                     listen_channel,      /* I/O channel.  */
+                     IO$_SETMODE,         /* I/O function code.  */
+                     &iosb,               /* I/O status block.  */
+                     0,                   /* Ast service routine.  */
+                     0,                   /* Ast parameter.  */
+                     0,                   /* P1.  */
+                     0,                   /* P2.  */
+                     0,                   /* P3.  */
+                     1,                   /* P4 - connection backlog.  */
+                     0, 0);
+  if (status & STS$M_SUCCESS)
+    status = iosb.iosb$w_status;
+  if (!(status & STS$M_SUCCESS))
+    {
+      term_puts ("Failed to set socket passive\n\r");
+      LIB$SIGNAL (status);
+    }
+
+  /* Accept connection from a client.  */
+  term_puts ("Waiting for a client connection on port: ");
+  term_putdec (wordswap (serv_addr.sin_port));
+  term_putnl ();
+
+  status = sys$qiow (EFN$C_ENF,              /* Event flag.  */
+                     listen_channel,         /* I/O channel.  */
+                     IO$_ACCESS|IO$M_ACCEPT, /* I/O function code.  */
+                     &iosb,                  /* I/O status block.  */
+                     0,                      /* Ast service routine.  */
+                     0,                      /* Ast parameter.  */
+                     0,                      /* P1.  */
+                     0,                      /* P2.  */
+                     0,                      /* P3.  */
+                     (__int64) &conn_channel, /* P4 - I/O channel for conn.  */
+                     0, 0);
+
+  if (status & STS$M_SUCCESS)
+    status = iosb.iosb$w_status;
+  if (!(status & STS$M_SUCCESS))
+    {
+      term_puts ("Failed to accept client connection\n\r");
+      LIB$SIGNAL (status);
+    }
+
+  /* Log client connection request.  */
+  cli_itemlst.ile3$w_length = sizeof (cli_addr);
+  cli_itemlst.ile3$w_code = TCPIP$C_SOCK_NAME;
+  cli_itemlst.ile3$ps_bufaddr = &cli_addr;
+  cli_itemlst.ile3$ps_retlen_addr = &cli_addrlen;
+  ots$fill (&cli_addr, sizeof(cli_addr), 0);
+  status = sys$qiow (EFN$C_ENF,           /* Event flag.  */
+                     conn_channel,        /* I/O channel.  */
+                     IO$_SENSEMODE,       /* I/O function code.  */
+                     &iosb,               /* I/O status block.  */
+                     0,                   /* Ast service routine.  */
+                     0,                   /* Ast parameter.  */
+                     0,                   /* P1.  */
+                     0,                   /* P2.  */
+                     0,                   /* P3.  */
+                     (__int64) &cli_itemlst,  /* P4 - peer socket name.  */
+                     0, 0);
+  if (status & STS$M_SUCCESS)
+    status = iosb.iosb$w_status;
+  if (!(status & STS$M_SUCCESS))
+    {
+      term_puts ("Failed to get client name\n\r");
+      LIB$SIGNAL (status);
+    }
+
+  term_puts ("Accepted connection from host: ");
+  term_putdec ((cli_addr.sin_addr.s_addr >> 0) & 0xff);
+  term_putc ('.');
+  term_putdec ((cli_addr.sin_addr.s_addr >> 8) & 0xff);
+  term_putc ('.');
+  term_putdec ((cli_addr.sin_addr.s_addr >> 16) & 0xff);
+  term_putc ('.');
+  term_putdec ((cli_addr.sin_addr.s_addr >> 24) & 0xff);
+  term_puts (", port: ");
+  term_putdec (wordswap (cli_addr.sin_port));
+  term_putnl ();
+}
+
+/* Close the socket.  */
+
+static void
+sock_close (void)
+{
+  struct _iosb iosb;
+  unsigned int status;
+
+  /* Close socket.  */
+  status = sys$qiow (EFN$C_ENF,           /* Event flag.  */
+                     conn_channel,        /* I/O channel.  */
+                     IO$_DEACCESS,        /* I/O function code.  */
+                     &iosb,               /* I/O status block.  */
+                     0,                   /* Ast service routine.  */
+                     0,                   /* Ast parameter.  */
+                     0, 0, 0, 0, 0, 0);
+
+  if (status & STS$M_SUCCESS)
+    status = iosb.iosb$w_status;
+  if (!(status & STS$M_SUCCESS))
+    {
+      term_puts ("Failed to close socket\n\r");
+      LIB$SIGNAL (status);
+    }
+
+  /* Deassign I/O channel to network device.  */
+  status = sys$dassgn (conn_channel);
+
+  if (!(status & STS$M_SUCCESS))
+    {
+      term_puts ("Failed to deassign I/O channel\n\r");
+      LIB$SIGNAL (status);
+    }
+}
+
+/* Mark a page as R/W.  Return old rights.  */
+
+static unsigned int
+page_set_rw (unsigned __int64 startva, unsigned __int64 len,
+             unsigned int *oldprot)
+{
+  unsigned int status;
+  unsigned __int64 retva;
+  unsigned __int64 retlen;
+
+  status = SYS$SETPRT_64 ((void *)startva, len, PSL$C_USER, PRT$C_UW,
+                          (void *)&retva, &retlen, oldprot);
+  return status;
+}
+
+/* Restore page rights.  */
+
+static void
+page_restore_rw (unsigned __int64 startva, unsigned __int64 len,
+                unsigned int prot)
+{
+  unsigned int status;
+  unsigned __int64 retva;
+  unsigned __int64 retlen;
+  unsigned int oldprot;
+
+  status = SYS$SETPRT_64 ((void *)startva, len, PSL$C_USER, prot,
+                          (void *)&retva, &retlen, &oldprot);
+  if (!(status & STS$M_SUCCESS))
+    LIB$SIGNAL (status);
+}
+
+/* Convert an hexadecimal character to a nibble.  Return -1 in case of
+   error.  */
+
+static int
+hex2nibble (unsigned char h)
+{
+  if (h >= '0' && h <= '9')
+    return h - '0';
+  if (h >= 'A' && h <= 'F')
+    return h - 'A' + 10;
+  if (h >= 'a' && h <= 'f')
+    return h - 'a' + 10;
+  return -1;
+}
+
+/* Convert an hexadecimal 2 character string to a byte.  Return -1 in case
+   of error.  */
+
+static int
+hex2byte (const unsigned char *p)
+{
+  int h, l;
+
+  h = hex2nibble (p[0]);
+  l = hex2nibble (p[1]);
+  if (h == -1 || l == -1)
+    return -1;
+  return (h << 4) | l;
+}
+
+/* Convert a byte V to a 2 character strings P.  */
+
+static void
+byte2hex (unsigned char *p, unsigned char v)
+{
+  p[0] = hex[v >> 4];
+  p[1] = hex[v & 0xf];
+}
+
+/* Convert a quadword V to a 16 character strings P.  */
+
+static void
+quad2hex (unsigned char *p, unsigned __int64 v)
+{
+  int i;
+  for (i = 0; i < 16; i++)
+    {
+      p[i] = hex[v >> 60];
+      v <<= 4;
+    }
+}
+
+/* Generate an error packet.  */
+
+static void
+packet_error (unsigned int err)
+{
+  gdb_buf[1] = 'E';
+  byte2hex (gdb_buf + 2, err);
+  gdb_blen = 4;
+}
+
+/* Generate an OK packet.  */
+
+static void
+packet_ok (void)
+{
+  gdb_buf[1] = 'O';
+  gdb_buf[2] = 'K';
+  gdb_blen = 3;
+}
+
+/* Append a register to the packet.  */
+
+static void
+ireg2pkt (const unsigned char *p)
+{
+  int i;
+
+  for (i = 0; i < 8; i++)
+    {
+      byte2hex (gdb_buf + gdb_blen, p[i]);
+      gdb_blen += 2;
+    }
+}
+
+/* Extract a number fro the packet.  */
+
+static unsigned __int64
+pkt2val (const unsigned char *pkt, unsigned int *pos)
+{
+  unsigned __int64 res = 0;
+  unsigned int i;
+
+  while (1)
+    {
+      int r = hex2nibble (pkt[*pos]);
+
+      if (r < 0)
+        return res;
+      res = (res << 4) | r;
+      (*pos)++;
+    }
+}
+
+/* Append LEN bytes from B to the current gdb packet (encode in binary).  */
+
+static void
+mem2bin (const unsigned char *b, unsigned int len)
+{
+  unsigned int i;
+  for (i = 0; i < len; i++)
+    switch (b[i])
+      {
+      case '#':
+      case '$':
+      case '}':
+      case '*':
+      case 0:
+        gdb_buf[gdb_blen++] = '}';
+        gdb_buf[gdb_blen++] = b[i] ^ 0x20;
+        break;
+      default:
+        gdb_buf[gdb_blen++] = b[i];
+        break;
+      }
+}
+
+/* Append LEN bytes from B to the current gdb packet (encode in hex).  */
+
+static void
+mem2hex (const unsigned char *b, unsigned int len)
+{
+  unsigned int i;
+  for (i = 0; i < len; i++)
+    {
+      byte2hex (gdb_buf + gdb_blen, b[i]);
+      gdb_blen += 2;
+    }
+}
+
+/* Handle the 'q' packet.  */
+
+static void
+handle_q_packet (const unsigned char *pkt, unsigned int pktlen)
+{
+  static const char xfer_uib[] = "qXfer:uib:read:";
+#define XFER_UIB_LEN (sizeof (xfer_uib) - 1)
+
+  if (pktlen > XFER_UIB_LEN
+      && ots$strcmp_eql (pkt, XFER_UIB_LEN, xfer_uib, XFER_UIB_LEN))
+    {
+      unsigned __int64 pc;
+      unsigned int pos = 24;
+      unsigned int off;
+      unsigned int len;
+      unsigned char blk[32];
+      int res;
+      int i;
+
+      packet_error (0);
+
+      pc = pkt2val (pkt, &pos);
+      if (pkt[pos] != ':')
+        return;
+      pos++;
+      off = pkt2val (pkt, &pos);
+      if (pkt[pos] != ',' || off != 0)
+        return;
+      pos++;
+      len = pkt2val (pkt, &pos);
+      if (pkt[pos] != '#' || len != 0x20)
+        return;
+
+      res = SYS$GET_UNWIND_ENTRY_INFO (pc, blk, 0);
+      if (res == SS$_NODATA || res != SS$_NORMAL)
+        ots$fill (blk, sizeof (blk), 0);
+
+#if 0
+      term_puts ("Got unwind request for ");
+      term_puthex8 (pc);
+      term_puts (", res=");
+      term_puthex8 (res);
+      term_putnl ();
+#endif
+
+      gdb_buf[0] = '$';
+      gdb_buf[1] = 'l';
+      gdb_blen = 2;
+      mem2bin (blk, sizeof (blk));
+    }
+  else
+    return;
+}
+
+/* Return 1 to continue.  */
+
+static int
+handle_packet (const unsigned char *pkt, unsigned int len)
+{
+  unsigned int pos;
+
+  /* By default, reply unsupported.  */
+  gdb_buf[0] = '$';
+  gdb_blen = 1;
+
+  pos = 1;
+  switch (pkt[0])
+    {
+    case '?':
+      if (len == 1)
+        {
+          gdb_buf[1] = 'S';
+          gdb_buf[2] = '0';
+          gdb_buf[3] = '5';
+          gdb_blen += 3;
+          return 0;
+        }
+      break;
+    case 'g':
+      if (len == 1)
+        {
+          unsigned int i;
+          unsigned char *p = regs.gr[0].b;
+
+          for (i = 0; i < 8 * 32; i++)
+            byte2hex (gdb_buf + 1 + 2 * i, p[i]);
+          gdb_blen += 2 * 8 * 32;
+          return 0;
+        }
+      break;
+    case 'p':
+      {
+        unsigned int num = 0;
+        unsigned int i;
+
+        num = pkt2val (pkt, &pos);
+        if (pos != len)
+          {
+            packet_error (0);
+            return 0;
+          }
+
+        switch (num)
+          {
+          case IA64_IP_REGNUM:
+            ireg2pkt (regs.ip.b);
+            break;
+          case IA64_BR0_REGNUM:
+            ireg2pkt (regs.br[0].b);
+            break;
+          case IA64_PSR_REGNUM:
+            ireg2pkt (regs.psr.b);
+            break;
+          case IA64_BSP_REGNUM:
+            ireg2pkt (regs.bsp.b);
+            break;
+          case IA64_CFM_REGNUM:
+            ireg2pkt (regs.cfm.b);
+            break;
+          case IA64_PFS_REGNUM:
+            ireg2pkt (regs.pfs.b);
+            break;
+          case IA64_PR_REGNUM:
+            ireg2pkt (regs.pr.b);
+            break;
+          default:
+            term_puts ("gdbserv: unhandled reg ");
+            term_putdec (num);
+            term_putnl ();
+            packet_error (0);
+            return 0;
+          }
+      }
+      break;
+    case 'q':
+      handle_q_packet (pkt, len);
+      break;
+    case 'k':
+      SYS$EXIT (SS$_NORMAL);
+      break;
+    case 'm':
+      {
+        unsigned __int64 addr;
+        unsigned int l;
+        unsigned int i;
+        addr = pkt2val (pkt, &pos);
+        if (pkt[pos] != ',')
+          {
+            packet_error (0);
+            return 0;
+          }
+        pos++;
+        l = pkt2val (pkt, &pos);
+        if (pkt[pos] != '#')
+          {
+            packet_error (0);
+            return 0;
+          }
+        for (i = 0; i < l; i++)
+          byte2hex (gdb_buf + 1 + 2 * i, ((unsigned char *)addr)[i]);
+        gdb_blen += 2 * l;
+      }
+      break;
+    case 'M':
+      {
+        unsigned __int64 addr;
+        unsigned int l;
+        unsigned int i;
+        unsigned int oldprot;
+
+        addr = pkt2val (pkt, &pos);
+        if (pkt[pos] != ',')
+          {
+            packet_error (0);
+            return 0;
+          }
+        pos++;
+        l = pkt2val (pkt, &pos);
+        if (pkt[pos] != ':')
+          {
+            packet_error (0);
+            return 0;
+          }
+        pos++;
+        page_set_rw (addr, l, &oldprot);
+        for (i = 0; i < l; i++)
+          {
+            int v = hex2byte (pkt + pos);
+            pos += 2;
+            ((unsigned char *)addr)[i] = v;
+          }
+        for (i = 0; i < l; i += 15)
+          __fc (addr + i);
+        __fc (addr + l);
+        page_restore_rw (addr, l, oldprot);
+        packet_ok ();
+      }
+      break;
+    case 'c':
+      if (len == 1)
+        {
+          /* Clear psr.ss.  */
+          regs.psr.v &= ~(unsigned __int64)PSR$M_SS;
+          return 1;
+        }
+      else
+        packet_error (0);
+      break;
+    case 's':
+      if (len == 1)
+        {
+          /* Set psr.ss.  */
+          regs.psr.v |= (unsigned __int64)PSR$M_SS;
+          return 1;
+        }
+      else
+        packet_error (0);
+      break;
+    default:
+      break;
+    }
+  return 0;
+}
+
+/* Raw write to gdb.  */
+
+static void
+sock_write (const unsigned char *buf, int len)
+{
+  struct _iosb iosb;
+  unsigned int status;
+
+  /* Write data to connection.  */
+  status = sys$qiow (EFN$C_ENF,           /* Event flag.  */
+                     conn_channel,        /* I/O channel.  */
+                     IO$_WRITEVBLK,       /* I/O function code.  */
+                     &iosb,               /* I/O status block.  */
+                     0,                   /* Ast service routine.  */
+                     0,                   /* Ast parameter.  */
+                     (char *)buf,         /* P1 - buffer address.  */
+                     len,                 /* P2 - buffer length.  */
+                     0, 0, 0, 0);
+  if (status & STS$M_SUCCESS)
+    status = iosb.iosb$w_status;
+  if (!(status & STS$M_SUCCESS))
+    {
+      term_puts ("Failed to write data to gdb\n\r");
+      LIB$SIGNAL (status);
+    }
+}
+
+/* Compute the cheksum and send the packet.  */
+
+static void
+send_pkt (void)
+{
+  unsigned char chksum = 0;
+  unsigned int i;
+
+  for (i = 1; i < gdb_blen; i++)
+    chksum += gdb_buf[i];
+
+  gdb_buf[gdb_blen] = '#';
+  byte2hex (gdb_buf + gdb_blen + 1, chksum);
+
+  sock_write (gdb_buf, gdb_blen + 3);
+
+  if (trace_pkt)
+    {
+      term_puts (">: ");
+      term_write ((char *)gdb_buf, gdb_blen + 3);
+      term_putnl ();
+    }
+}
+
+/* Read and handle one command.  Return 1 is execution must resume.  */
+
+static int
+one_command (void)
+{
+  struct _iosb iosb;
+  unsigned int status;
+  unsigned int off;
+  unsigned int dollar_off = 0;
+  unsigned int sharp_off = 0;
+  unsigned int cmd_off;
+  unsigned int cmd_len;
+
+  /* Wait for a packet.  */
+  while (1)
+    {
+      off = 0;
+      while (1)
+        {
+          /* Read data from connection.  */
+          status = sys$qiow (EFN$C_ENF,           /* Event flag.  */
+                             conn_channel,        /* I/O channel.  */
+                             IO$_READVBLK,        /* I/O function code.  */
+                             &iosb,               /* I/O status block.  */
+                             0,                   /* Ast service routine.  */
+                             0,                   /* Ast parameter.  */
+                             gdb_buf + off,       /* P1 - buffer address.  */
+                             sizeof (gdb_buf) - off, /* P2 - buffer leng.  */
+                             0, 0, 0, 0);
+          if (status & STS$M_SUCCESS)
+            status = iosb.iosb$w_status;
+          if (!(status & STS$M_SUCCESS))
+            {
+              term_puts ("Failed to read data from connection\n\r" );
+              LIB$SIGNAL (status);
+            }
+
+#ifdef RAW_DUMP
+          term_puts ("{: ");
+          term_write ((char *)gdb_buf + off, iosb.iosb$w_bcnt);
+          term_putnl ();
+#endif
+
+          gdb_blen = off + iosb.iosb$w_bcnt;
+
+          if (off == 0)
+            {
+              /* Search for '$'.  */
+              for (dollar_off = 0; dollar_off < gdb_blen; dollar_off++)
+                if (gdb_buf[dollar_off] == '$')
+                  break;
+              if (dollar_off >= gdb_blen)
+                {
+                  /* Not found, discard the data.  */
+                  off = 0;
+                  continue;
+                }
+              /* Search for '#'.  */
+              for (sharp_off = dollar_off + 1; sharp_off < gdb_blen; sharp_off++)
+                if (gdb_buf[sharp_off] == '#')
+                  break;
+            }
+          else if (sharp_off >= off)
+            {
+              /* Search for '#'.  */
+              for (; sharp_off < gdb_blen; sharp_off++)
+                if (gdb_buf[sharp_off] == '#')
+                  break;
+            }
+
+          /* Got packet with checksum.  */
+          if (sharp_off + 2 <= gdb_blen)
+            break;
+
+          off = gdb_blen;
+          if (gdb_blen == sizeof (gdb_buf))
+            {
+              /* Packet too large, discard.  */
+              off = 0;
+            }
+        }
+
+      /* Validate and acknowledge a packet.  */
+      {
+        unsigned char chksum = 0;
+        unsigned int i;
+        int v;
+
+        for (i = dollar_off + 1; i < sharp_off; i++)
+          chksum += gdb_buf[i];
+        v = hex2byte (gdb_buf + sharp_off + 1);
+        if (v != chksum)
+          {
+            term_puts ("Discard bad checksum packet\n\r");
+            continue;
+          }
+        else
+          {
+            sock_write ((const unsigned char *)"+", 1);
+            break;
+          }
+      }
+    }
+
+  if (trace_pkt)
+    {
+      term_puts ("<: ");
+      term_write ((char *)gdb_buf + dollar_off, sharp_off - dollar_off + 1);
+      term_putnl ();
+    }
+
+  cmd_off = dollar_off + 1;
+  cmd_len = sharp_off - dollar_off - 1;
+
+  if (handle_packet (gdb_buf + dollar_off + 1, sharp_off - dollar_off - 1) == 1)
+    return 1;
+
+  send_pkt ();
+  return 0;
+}
+
+/* Display the condition given by SIG64.  */
+
+static void
+display_excp (struct chf64$signal_array *sig64)
+{
+  unsigned int status;
+  char msg[160];
+  unsigned short msglen;
+  $DESCRIPTOR (msg_desc, msg);
+  unsigned char outadr[4];
+
+  status = SYS$GETMSG (sig64->chf64$q_sig_name, &msglen, &msg_desc, 0, outadr);
+  if (status & STS$M_SUCCESS)
+    {
+      char msg2[160];
+      unsigned short msg2len;
+      struct dsc$descriptor_s msg2_desc =
+        { sizeof (msg2), DSC$K_DTYPE_T, DSC$K_CLASS_S, msg2};
+      msg_desc.dsc$w_length = msglen;
+      status = SYS$FAOL_64 (&msg_desc, &msg2len, &msg2_desc,
+                            &sig64->chf64$q_sig_arg1);
+      if (status & STS$M_SUCCESS)
+        term_write (msg2, msg2len);
+    }
+  else
+    term_puts ("no message");
+  term_putnl ();
+}
+
+/* The condition handler.  That's the core of the stub.  */
+
+static int
+excp_handler (struct chf$signal_array *sig,
+              struct chf$mech_array *mech)
+{
+  unsigned int status;
+  struct chf64$signal_array *sig64 =
+    (struct chf64$signal_array *)mech->chf$ph_mch_sig64_addr;
+  struct _intstk *intstk =
+    (struct _intstk *)mech->chf$q_mch_esf_addr;
+
+  unsigned int code = sig->chf$l_sig_name & STS$M_COND_ID;
+  unsigned int cnt = sig64->chf64$w_sig_arg_count;
+  unsigned __int64 pc = (&sig64->chf64$q_sig_name)[cnt - 2];
+  int i;
+  int ret = SS$_RESIGNAL_64;
+
+  /* Completly ignore some conditions (signaled indirectly by this stub).  */
+  switch (code)
+    {
+    case LIB$_KEYNOTFOU & STS$M_COND_ID:
+      return SS$_RESIGNAL_64;
+    default:
+      break;
+    }
+
+  if (trace_excp)
+    {
+      term_puts ("excp_handler: ");
+      term_puthex8 (code);
+      term_puts (", vec count: ");
+      term_putdec (cnt);
+      term_puts (", pc=");
+      term_puthex8 (pc);
+      term_putnl ();
+    }
+
+  /* If break on the entry point, restore the bundle.  */
+  if (code == (SS$_BREAK & STS$M_COND_ID)
+      && pc == entry_pc
+      && entry_pc != 0)
+    {
+      static unsigned int entry_prot;
+
+      if (trace_entry)
+        term_puts ("initial entry breakpoint\n\r");
+      page_set_rw (entry_pc, 16, &entry_prot);
+
+      ots$move3 (16, entry_saved, (void *)entry_pc);
+      __fc (entry_pc);
+      page_restore_rw (entry_pc, 16, entry_prot);
+
+      ret = SS$_CONTINUE_64;
+    }
+
+  switch (code)
+    {
+    case SS$_ACCVIO & STS$M_COND_ID:
+      if (trace_excp <= 1)
+        display_excp (sig64);
+      /* Fall through.  */
+    case SS$_BREAK & STS$M_COND_ID:
+    case SS$_OPCDEC & STS$M_COND_ID:
+    case SS$_TBIT & STS$M_COND_ID:
+      if (trace_excp > 1)
+        {
+          display_excp (sig64);
+
+          term_puts (" intstk: ");
+          term_putp (intstk);
+          term_putnl ();
+          for (i = 0; i < cnt + 1; i++)
+            {
+              term_puts ("   ");
+              term_puthex8 (((unsigned __int64 *)sig64)[i]);
+              term_putnl ();
+            }
+        }
+      regs.ip.v = pc;
+      regs.psr.v = intstk->intstk$q_ipsr;
+#if 1
+      /* What a mess.  Gdb and linux expects bsp to point after the current
+         register frame.  Adjust.  */
+      {
+        unsigned __int64 bsp = intstk->intstk$q_bsp;
+        unsigned int sof = intstk->intstk$q_ifs & 0x7f;
+        unsigned int delta = ((bsp >> 3) & 0x3f) + sof;
+        regs.bsp.v = bsp + ((sof + delta / 0x3f) << 3);
+      }
+#else
+      regs.bsp.v = intstk->intstk$q_bsp;
+#endif
+      regs.cfm.v = intstk->intstk$q_ifs & 0x3fffffffff;
+      regs.pfs.v = intstk->intstk$q_pfs;
+      regs.pr.v = intstk->intstk$q_preds;
+      regs.gr[0].v = 0;
+      regs.gr[1].v = intstk->intstk$q_gp;
+      regs.gr[2].v = intstk->intstk$q_r2;
+      regs.gr[3].v = intstk->intstk$q_r3;
+      regs.gr[4].v = intstk->intstk$q_r4;
+      regs.gr[5].v = intstk->intstk$q_r5;
+      regs.gr[6].v = intstk->intstk$q_r6;
+      regs.gr[7].v = intstk->intstk$q_r7;
+      regs.gr[8].v = intstk->intstk$q_r8;
+      regs.gr[9].v = intstk->intstk$q_r9;
+      regs.gr[10].v = intstk->intstk$q_r10;
+      regs.gr[11].v = intstk->intstk$q_r11;
+      regs.gr[12].v = (unsigned __int64)intstk + intstk->intstk$l_stkalign;
+      regs.gr[13].v = intstk->intstk$q_r13;
+      regs.gr[14].v = intstk->intstk$q_r14;
+      regs.gr[15].v = intstk->intstk$q_r15;
+      regs.gr[16].v = intstk->intstk$q_r16;
+      regs.gr[17].v = intstk->intstk$q_r17;
+      regs.gr[18].v = intstk->intstk$q_r18;
+      regs.gr[19].v = intstk->intstk$q_r19;
+      regs.gr[20].v = intstk->intstk$q_r20;
+      regs.gr[21].v = intstk->intstk$q_r21;
+      regs.gr[22].v = intstk->intstk$q_r22;
+      regs.gr[23].v = intstk->intstk$q_r23;
+      regs.gr[24].v = intstk->intstk$q_r24;
+      regs.gr[25].v = intstk->intstk$q_r25;
+      regs.gr[26].v = intstk->intstk$q_r26;
+      regs.gr[27].v = intstk->intstk$q_r27;
+      regs.gr[28].v = intstk->intstk$q_r28;
+      regs.gr[29].v = intstk->intstk$q_r29;
+      regs.gr[30].v = intstk->intstk$q_r30;
+      regs.gr[31].v = intstk->intstk$q_r31;
+      regs.br[0].v = intstk->intstk$q_b0;
+      regs.br[1].v = intstk->intstk$q_b1;
+      regs.br[2].v = intstk->intstk$q_b2;
+      regs.br[3].v = intstk->intstk$q_b3;
+      regs.br[4].v = intstk->intstk$q_b4;
+      regs.br[5].v = intstk->intstk$q_b5;
+      regs.br[6].v = intstk->intstk$q_b6;
+      regs.br[7].v = intstk->intstk$q_b7;
+
+      /* Send stop reply packet.  */
+      {
+        gdb_buf[0] = '$';
+        gdb_buf[1] = 'S';
+        gdb_buf[2] = '0';
+        gdb_buf[3] = '5';
+        gdb_blen = 4;
+        send_pkt ();
+      }
+      while (one_command () == 0)
+        ;
+      intstk->intstk$q_ipsr = regs.psr.v;
+      ret = SS$_CONTINUE_64;
+      break;
+
+    default:
+      display_excp (sig64);
+      break;
+    }
+
+  return ret;
+}
+
+/* Setup internal trace flags according to GDBSTUB$TRACE logical.  */
+
+static void
+trace_init (void)
+{
+  unsigned int status, i, start;
+  unsigned short len;
+  char resstring[LNM$C_NAMLENGTH];
+  static const $DESCRIPTOR (tabdesc, "LNM$DCL_LOGICAL");
+  static const $DESCRIPTOR (logdesc, "GDBSTUB$TRACE");
+  static const $DESCRIPTOR (pkt_desc, "packets");
+  static const $DESCRIPTOR (entry_desc, "entry");
+  static const $DESCRIPTOR (except_desc, "except");
+  $DESCRIPTOR (sub_desc, resstring);
+  ILE3 item_lst[2];
+
+  item_lst[0].ile3$w_length = LNM$C_NAMLENGTH;
+  item_lst[0].ile3$w_code = LNM$_STRING;
+  item_lst[0].ile3$ps_bufaddr = resstring;
+  item_lst[0].ile3$ps_retlen_addr = &len;
+  item_lst[1].ile3$w_length = 0;
+  item_lst[1].ile3$w_code = 0;
+
+  /* Translate the logical name.  */
+  status = SYS$TRNLNM (0,   		/* Attributes of the logical name.  */
+                       (void *)&tabdesc,       /* Logical name table.  */
+                       (void *)&logdesc,       /* Logical name.  */
+                       0,              	       /* Access mode.  */
+                       &item_lst);             /* Item list.  */
+  if (status == SS$_NOLOGNAM)
+    return;
+  if (!(status & STS$M_SUCCESS))
+    LIB$SIGNAL (status);
+
+  start = 0;
+  for (i = 0; i <= len; i++)
+    {
+      if ((i == len || resstring[i] == ',') && i != start)
+        {
+          sub_desc.dsc$a_pointer = resstring + start;
+          sub_desc.dsc$w_length = i - start;
+
+          if (str$case_blind_compare (&sub_desc, (void *)&pkt_desc) == 0)
+            trace_pkt++;
+          else if (str$case_blind_compare (&sub_desc, (void *)&entry_desc) == 0)
+            trace_entry++;
+          else if (str$case_blind_compare (&sub_desc, (void *)&except_desc) == 0)
+            trace_excp++;
+          else
+            {
+              term_puts ("GDBSTUB$TRACE: unknown directive ");
+              term_write (sub_desc.dsc$a_pointer, sub_desc.dsc$w_length);
+              term_putnl ();
+            }
+
+          start = i + 1;
+        }
+    }
+}
+
+/* Entry point.  */
+
+static void
+stub_start (unsigned __int64 *progxfer, void *cli_util,
+            void *imghdr, void *imgfile,
+            unsigned int linkflag, unsigned int cliflag)
+{
+  int i;
+
+  term_init ();
+  trace_init ();
+
+  /* Hello banner.  */
+  term_puts ("Hello gdb stub\n\r");
+  if (trace_entry)
+    {
+      term_puts ("xfer: ");
+      term_putp (progxfer);
+      term_putnl ();
+      for (i = -2; i < 8; i++)
+        {
+          term_puthex8 (progxfer[i]);
+          term_putnl ();
+        }
+    }
+
+  /* Search for entry point.  */
+  entry_pc = 0;
+  for (i = 0; progxfer[i]; i++)
+    entry_pc = progxfer[i];
+
+  if (trace_entry)
+    {
+      if (entry_pc == 0)
+        {
+          term_puts ("No entry point\n\r");
+          return;
+        }
+      else
+        {
+          term_puts ("Entry: ");
+          term_puthex8 (entry_pc);
+          term_putnl ();
+        }
+    }
+
+  /* Set primary exception vector.  */
+  {
+    unsigned int status;
+    status = sys$setexv (0, excp_handler, PSL$C_USER, &prevhnd);
+    if (!(status & STS$M_SUCCESS))
+      LIB$SIGNAL (status);
+  }
+
+  /* Change first instruction to set a breakpoint.  */
+  {
+    /*
+  	01 08 00 40 00 00 	[MII]       break.m 0x80001
+   	00 00 00 02 00 00 	            nop.i 0x0
+   	00 00 04 00       	            nop.i 0x0;;
+    */
+    static const unsigned char initbp[16] =
+      { 0x01, 0x08, 0x00, 0x40, 0x00, 0x00,
+        0x00, 0x00, 0x00, 0x02, 0x00, 0x00,
+        0x00, 0x00, 0x04, 0x00 };
+    unsigned int entry_prot;
+    unsigned int status;
+
+    status = page_set_rw (entry_pc, 16, &entry_prot);
+#if 0
+    term_puthex8 (status);
+    term_putnl ();
+    term_puthex8 ((status & STS$M_COND_ID));
+    term_puthex8 (SS$_NOT_PROCESS_VA);
+    term_putnl ();
+#endif
+
+    if (!(status & STS$M_SUCCESS))
+      {
+        if ((status & STS$M_COND_ID) == (SS$_NOT_PROCESS_VA & STS$M_COND_ID))
+          {
+            /* Cannot write here.  This can happen when pthreads are used.  */
+            entry_pc = 0;
+            term_puts ("gdbstub: cannot set breakpoint on entry\n\r");
+          }
+        else
+          LIB$SIGNAL (status);
+      }
+
+    if (entry_pc != 0)
+      {
+        ots$move3 (16, (void *)entry_pc, entry_saved);
+        ots$move3 (16, (void *)initbp, (void *)entry_pc);
+        __fc (entry_pc);
+        page_restore_rw (entry_pc, 16, entry_prot);
+      }
+  }
+
+#if 0
+  term_puts ("sizeof regs: ");
+  term_putdec (sizeof (regs));
+  term_putnl ();
+#endif
+
+  sock_init ();
+
+  /* If it wasn't possible to set a breakpoint on the entry point,
+     accept gdb commands now.  Note that registers are not updated.  */
+  if (entry_pc == 0)
+    {
+      while (one_command () == 0)
+        ;
+    }
+
+  /* We will see!  */
+  return;
+}
+
+/* Declare the entry point of this relocatable module.  */
+
+static void stub_start ();
+
+struct xfer_vector
+{
+  __int64 impure_start;
+  __int64 impure_end;
+  void (*entry) ();
+};
+
+#pragma __extern_model save
+#pragma __extern_model strict_refdef "XFER_PSECT"
+struct xfer_vector xfer_vector = {0, 0, stub_start};
+#pragma __extern_model restore


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

* Re: RFA: New port: ia64-hp-openvms - the stub
  2012-02-10 13:44 ` RFA: New port: ia64-hp-openvms - the stub Tristan Gingold
@ 2012-02-10 19:06   ` Douglas Rupp
  2012-02-13  8:43     ` Tristan Gingold
  2012-02-14 18:09   ` Pedro Alves
  1 sibling, 1 reply; 31+ messages in thread
From: Douglas Rupp @ 2012-02-10 19:06 UTC (permalink / raw)
  To: Tristan Gingold; +Cc: gdb-patches@sourceware.org ml, Rupp Douglas

On 2/10/2012 5:43 AM, Tristan Gingold wrote:
> Hi,
>
> this is the debugger stub for ia64 VMS.
> Because it is independent of gdb (not unlike gdbserver) and because it isn't a one file stub, I think it is worth creating a subdirectory.
> I think we should also move the existing stubs there.
>
> The interesting part is that on OpenVMS, the debugger is a shared library that is loaded with the application when debugging is needed (either from the start or during the run - like attach).  Just think about catching SIGTRAP, SIGSEGV, SIGBUS,Â… from a LD_PRELOAD binary.
>
> The stub was written from scratch because it is highly OpenVMS dependent and in particular the standard C library shouldn't be used.
>
> The stub is not complete: some registers are partially or not handled, and inferior procedure call is not yet implemented (will be the funny part).  But it has already be extremely useful to debug some applications.
>
> Tristan.
>

Would it make sense to factor out the ia64 specific bits, so as to 
facilitate porting to alpha vms?
--Doug


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

* Re: RFA: New port: ia64-hp-openvms (1/3) - new osabi
  2012-02-10 13:21 ` RFA: New port: ia64-hp-openvms (1/3) - new osabi Tristan Gingold
  2012-02-10 13:27   ` RFA: New port: ia64-hp-openvms (3/3) - ia64-vms-tdep.c Tristan Gingold
@ 2012-02-12  9:36   ` Mark Kettenis
  1 sibling, 0 replies; 31+ messages in thread
From: Mark Kettenis @ 2012-02-12  9:36 UTC (permalink / raw)
  To: gingold; +Cc: gdb-patches, rupp

> From: Tristan Gingold <gingold@adacore.com>
> Date: Fri, 10 Feb 2012 14:21:05 +0100
> 
> OpenVMS has its own ABI
> 
> Tristan.
> 
> 2012-02-10  Tristan Gingold  <gingold@adacore.com>
> 
> 	* osabi.c (gdb_osabi_names): Add OpenVMS.
> 	(generic_elf_osabi_sniffer): Likewise.
> 	* defs.h (gdb_osabi): Add GDB_OSABI_OPENVMS.

Looks ok to me.


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

* Re: RFA: New port: ia64-hp-openvms (2/3)
  2012-02-10 13:23 ` RFA: New port: ia64-hp-openvms (2/3) Tristan Gingold
@ 2012-02-12  9:39   ` Mark Kettenis
  2012-02-13  8:45     ` Tristan Gingold
  2012-02-14 17:36   ` Pedro Alves
  1 sibling, 1 reply; 31+ messages in thread
From: Mark Kettenis @ 2012-02-12  9:39 UTC (permalink / raw)
  To: gingold; +Cc: gdb-patches, rupp

> From: Tristan Gingold <gingold@adacore.com>
> Date: Fri, 10 Feb 2012 14:22:56 +0100
> 
> The easiest way to get the unwind entry is to ask to the OpenVMS
> kernel, as this always work.  Might not be optimal for the user
> application, but it is bullet-proof.
> 
> Tristan.
> 
> 2012-02-10  Tristan Gingold  <gingold@adacore.com>
> 
> 	* target.h (target_object): Add TARGET_OBJECT_OPENVMS_UIB.
> 	* remote.c (PACKET_qXfer_uib): New enum value.
> 	(remote_protocol_features): Add entry for PACKET_qXfer_uib.
> 	(remote_xfer_partial): Handle TARGET_OBJECT_OPENVMS_UIB.

Don't know much about (Open)VMS, but...

> diff --git a/gdb/remote.c b/gdb/remote.c
> index 3187ac0..7787864 100644
> --- a/gdb/remote.c
> +++ b/gdb/remote.c
> @@ -8417,6 +8420,12 @@ remote_xfer_partial (struct target_ops *ops, enum target_object object,
>      case TARGET_OBJECT_FDPIC:
>        return remote_read_qxfer (ops, "fdpic", annex, readbuf, offset, len,
>  				&remote_protocol_packets[PACKET_qXfer_fdpic]);
> +
> +    case TARGET_OBJECT_OPENVMS_UIB:
> +      return remote_read_qxfer
> +        (ops, "uib", annex, readbuf, offset, len,
> +         &remote_protocol_packets[PACKET_qXfer_uib]);
> +

Formatting here is different from the TARGET_OBJECT_FDPIC bit just before.


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

* Re: RFA: New port: ia64-hp-openvms - the stub
  2012-02-10 19:06   ` Douglas Rupp
@ 2012-02-13  8:43     ` Tristan Gingold
  0 siblings, 0 replies; 31+ messages in thread
From: Tristan Gingold @ 2012-02-13  8:43 UTC (permalink / raw)
  To: Douglas Rupp; +Cc: gdb-patches@sourceware.org ml, Rupp Douglas


On Feb 10, 2012, at 8:05 PM, Douglas Rupp wrote:

> On 2/10/2012 5:43 AM, Tristan Gingold wrote:
>> Hi,
>> 
>> this is the debugger stub for ia64 VMS.
>> Because it is independent of gdb (not unlike gdbserver) and because it isn't a one file stub, I think it is worth creating a subdirectory.
>> I think we should also move the existing stubs there.
>> 
>> The interesting part is that on OpenVMS, the debugger is a shared library that is loaded with the application when debugging is needed (either from the start or during the run - like attach).  Just think about catching SIGTRAP, SIGSEGV, SIGBUS,… from a LD_PRELOAD binary.
>> 
>> The stub was written from scratch because it is highly OpenVMS dependent and in particular the standard C library shouldn't be used.
>> 
>> The stub is not complete: some registers are partially or not handled, and inferior procedure call is not yet implemented (will be the funny part).  But it has already be extremely useful to debug some applications.
>> 
>> Tristan.
>> 
> 
> Would it make sense to factor out the ia64 specific bits, so as to facilitate porting to alpha vas?

Well, this is too early.  There are higher priorities (such as thread support)

Tristan.


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

* Re: RFA: New port: ia64-hp-openvms (2/3)
  2012-02-12  9:39   ` Mark Kettenis
@ 2012-02-13  8:45     ` Tristan Gingold
  0 siblings, 0 replies; 31+ messages in thread
From: Tristan Gingold @ 2012-02-13  8:45 UTC (permalink / raw)
  To: Mark Kettenis; +Cc: gdb-patches, rupp


On Feb 12, 2012, at 10:39 AM, Mark Kettenis wrote:

>> From: Tristan Gingold <gingold@adacore.com>
>> Date: Fri, 10 Feb 2012 14:22:56 +0100
>> 
>> The easiest way to get the unwind entry is to ask to the OpenVMS
>> kernel, as this always work.  Might not be optimal for the user
>> application, but it is bullet-proof.
>> 
>> Tristan.
>> 
>> 2012-02-10  Tristan Gingold  <gingold@adacore.com>
>> 
>> 	* target.h (target_object): Add TARGET_OBJECT_OPENVMS_UIB.
>> 	* remote.c (PACKET_qXfer_uib): New enum value.
>> 	(remote_protocol_features): Add entry for PACKET_qXfer_uib.
>> 	(remote_xfer_partial): Handle TARGET_OBJECT_OPENVMS_UIB.
> 
> Don't know much about (Open)VMS, but...
> 
>> diff --git a/gdb/remote.c b/gdb/remote.c
>> index 3187ac0..7787864 100644
>> --- a/gdb/remote.c
>> +++ b/gdb/remote.c
>> @@ -8417,6 +8420,12 @@ remote_xfer_partial (struct target_ops *ops, enum target_object object,
>>     case TARGET_OBJECT_FDPIC:
>>       return remote_read_qxfer (ops, "fdpic", annex, readbuf, offset, len,
>> 				&remote_protocol_packets[PACKET_qXfer_fdpic]);
>> +
>> +    case TARGET_OBJECT_OPENVMS_UIB:
>> +      return remote_read_qxfer
>> +        (ops, "uib", annex, readbuf, offset, len,
>> +         &remote_protocol_packets[PACKET_qXfer_uib]);
>> +
> 
> Formatting here is different from the TARGET_OBJECT_FDPIC bit just before.

Right, but it follows the one of TARGET_OBJECT_TRACEFRAME_INFO :-)
Will fix.

Tristan.



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

* Re: RFA: New port: ia64-hp-openvms (2/3)
  2012-02-10 13:23 ` RFA: New port: ia64-hp-openvms (2/3) Tristan Gingold
  2012-02-12  9:39   ` Mark Kettenis
@ 2012-02-14 17:36   ` Pedro Alves
  2012-02-14 17:40     ` Pedro Alves
  2012-02-21 16:08     ` RFA: New port: ia64-hp-openvms (2/3) - v2 Tristan Gingold
  1 sibling, 2 replies; 31+ messages in thread
From: Pedro Alves @ 2012-02-14 17:36 UTC (permalink / raw)
  To: Tristan Gingold; +Cc: gdb-patches@sourceware.org ml, Rupp Douglas

On 02/10/2012 01:22 PM, Tristan Gingold wrote:
> 
> 2012-02-10  Tristan Gingold  <gingold@adacore.com>
> 
> 	* target.h (target_object): Add TARGET_OBJECT_OPENVMS_UIB.
> 	* remote.c (PACKET_qXfer_uib): New enum value.
> 	(remote_protocol_features): Add entry for PACKET_qXfer_uib.
> 	(remote_xfer_partial): Handle TARGET_OBJECT_OPENVMS_UIB.

New packets need new documentation.  There should be a
new call to add_packet_config_cmd call in _initialize_remote.

And ... where's the code that actually reads this new object?

-- 
Pedro Alves


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

* Re: RFA: New port: ia64-hp-openvms (2/3)
  2012-02-14 17:36   ` Pedro Alves
@ 2012-02-14 17:40     ` Pedro Alves
  2012-02-21 16:08     ` RFA: New port: ia64-hp-openvms (2/3) - v2 Tristan Gingold
  1 sibling, 0 replies; 31+ messages in thread
From: Pedro Alves @ 2012-02-14 17:40 UTC (permalink / raw)
  To: Tristan Gingold; +Cc: gdb-patches@sourceware.org ml, Rupp Douglas

On 02/14/2012 05:35 PM, Pedro Alves wrote:

> And ... where's the code that actually reads this new object?

Ah, found it.  Patch 3/3 ended up hidden as a reply to patch 1/3, so I had missed it,
and thought patch 3 was the stub...

-- 
Pedro Alves


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

* Re: RFA: New port: ia64-hp-openvms (3/3) - ia64-vms-tdep.c
  2012-02-10 13:27   ` RFA: New port: ia64-hp-openvms (3/3) - ia64-vms-tdep.c Tristan Gingold
@ 2012-02-14 17:50     ` Pedro Alves
  2012-02-15  9:14       ` Tristan Gingold
  0 siblings, 1 reply; 31+ messages in thread
From: Pedro Alves @ 2012-02-14 17:50 UTC (permalink / raw)
  To: Tristan Gingold; +Cc: gdb-patches@sourceware.org ml, Rupp Douglas

On 02/10/2012 01:27 PM, Tristan Gingold wrote:
> Most of the code of ia64-tdep.c can be reused, except for unwinding.  So I added a ia64-vms-tdep.c.
> 
> Tristan.
> 
> 2012-02-10  Tristan Gingold  <gingold@adacore.com>
> 
>         * ia64-tdep.h: Include libunwind-frame.h and libunwind-ia64.h.
>         (ia64_unw_accessors, ia64_unw_rse_accessors)
>         (ia64_libunwind_descr): Declare.
>         * ia64-vms-tdep.c: New file.
>         * ia64-tdep.c (ia64_unw_accessors, ia64_unw_rse_accessors)
>         (ia64_libunwind_descr): Make them public.
>         * configure.tgt: Add ia64-*-*vms*.
>         * Makefile.in (ALL_64_TARGET_OBS): Add ia64-vms-tdep.o
>         (ALLDEPFILES): Add ia64-vms-tdep.c
> 
> diff --git a/gdb/Makefile.in b/gdb/Makefile.in
> index 9f30a61..4c67d0d 100644
> --- a/gdb/Makefile.in
> +++ b/gdb/Makefile.in
> @@ -516,7 +516,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-hpux-tdep.o ia64-linux-tdep.o ia64-tdep.o \
> +	ia64-hpux-tdep.o ia64-linux-tdep.o ia64-vms-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
> @@ -1456,7 +1456,7 @@ ALLDEPFILES = \
>  	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 \
> +	ia64-linux-nat.c ia64-linux-tdep.c ia64-tdep.c ia64-vms-tdep.c \
>  	inf-ptrace.c inf-ttrace.c \
>  	irix5-nat.c \
>  	libunwind-frame.c \
> diff --git a/gdb/configure.tgt b/gdb/configure.tgt
> index 5e97ab4..6b4a504 100644
> --- a/gdb/configure.tgt
> +++ b/gdb/configure.tgt
> @@ -246,6 +246,10 @@ ia64-*-linux*)
>  			solib-svr4.o symfile-mem.o"
>  	build_gdbserver=yes
>  	;;
> +ia64-*-*vms*)
> +	# Target: Intel IA-64 running OpenVMS
> +	gdb_target_obs="ia64-tdep.o ia64-vms-tdep.o"
> +	;;
>  ia64*-*-*)
>  	# Target: Intel IA-64
>  	gdb_target_obs="ia64-tdep.o"
> diff --git a/gdb/ia64-tdep.c b/gdb/ia64-tdep.c
> index a36dc22..1c4fa8f 100644
> --- a/gdb/ia64-tdep.c
> +++ b/gdb/ia64-tdep.c
> @@ -3148,7 +3148,7 @@ static const struct frame_unwind ia64_libunwind_sigtramp_frame_unwind =
>  };
>  
>  /* Set of libunwind callback acccessor functions.  */
> -static unw_accessors_t ia64_unw_accessors =
> +unw_accessors_t ia64_unw_accessors =
>  {
>    ia64_find_proc_info_x,
>    ia64_put_unwind_info,
> @@ -3164,7 +3164,7 @@ static unw_accessors_t ia64_unw_accessors =
>     the rse registers.  At the top of the stack, we want libunwind to figure out
>     how to read r32 - r127.  Though usually they are found sequentially in
>     memory starting from $bof, this is not always true.  */
> -static unw_accessors_t ia64_unw_rse_accessors =
> +unw_accessors_t ia64_unw_rse_accessors =
>  {
>    ia64_find_proc_info_x,
>    ia64_put_unwind_info,
> @@ -3178,7 +3178,7 @@ static unw_accessors_t ia64_unw_rse_accessors =
>  
>  /* Set of ia64 gdb libunwind-frame callbacks and data for generic
>     libunwind-frame code to use.  */
> -static struct libunwind_descr ia64_libunwind_descr =
> +struct libunwind_descr ia64_libunwind_descr =
>  {
>    ia64_gdb2uw_regnum, 
>    ia64_uw2gdb_regnum, 
> diff --git a/gdb/ia64-tdep.h b/gdb/ia64-tdep.h
> index 48cc3e0..7501eb4 100644
> --- a/gdb/ia64-tdep.h
> +++ b/gdb/ia64-tdep.h
> @@ -20,6 +20,11 @@
>  #ifndef IA64_TDEP_H
>  #define IA64_TDEP_H
>  
> +#ifdef HAVE_LIBUNWIND_IA64_H
> +#include "libunwind-ia64.h"
> +#include "libunwind-frame.h"
> +#endif
> +
>  /* Register numbers of various important registers.  */
>  
>  /* General registers; there are 128 of these 64 bit wide registers.
> @@ -250,4 +255,10 @@ struct gdbarch_tdep
>  
>  extern void ia64_write_pc (struct regcache *, CORE_ADDR);
>  
> +#ifdef HAVE_LIBUNWIND_IA64_H
> +extern unw_accessors_t ia64_unw_accessors;
> +extern unw_accessors_t ia64_unw_rse_accessors;
> +extern struct libunwind_descr ia64_libunwind_descr;
> +#endif
> +
>  #endif /* ia64-tdep.h */
> diff --git a/gdb/ia64-vms-tdep.c b/gdb/ia64-vms-tdep.c
> new file mode 100644
> index 0000000..1728ba0
> --- /dev/null
> +++ b/gdb/ia64-vms-tdep.c
> @@ -0,0 +1,165 @@
> +/* Target-dependent code for OpenVMS IA-64.
> +
> +   Copyright (C) 2012 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 "frame-unwind.h"
> +#include "ia64-tdep.h"
> +#include "osabi.h"
> +#include "gdbtypes.h"
> +#include "solib.h"
> +#include "target.h"
> +#include "frame.h"
> +#include "regcache.h"
> +#include "gdbcore.h"
> +#include "inferior.h"
> +
> +#ifdef HAVE_LIBUNWIND_IA64_H
> +
> +/* Libunwind callback accessor function to acquire procedure unwind-info.  */
> +static int

Empty line between comment and function please.  Here and elsewhere.

> +ia64_vms_find_proc_info_x (unw_addr_space_t as, unw_word_t ip,
> +                           unw_proc_info_t *pi,
> +                           int need_unwind_info, void *arg)
> +{
> +  enum bfd_endian byte_order = gdbarch_byte_order (target_gdbarch);
> +  unw_dyn_info_t di;
> +  int ret;
> +  unsigned char buf[32];

s/unsigned char/gdb_byte/

> +  const char *annex = core_addr_to_string (ip);
> +  LONGEST res;
> +  CORE_ADDR table_addr;
> +  unsigned int info_len;
> +
> +  res = target_read (&current_target, TARGET_OBJECT_OPENVMS_UIB,
> +                     annex + 2, buf, 0, sizeof (buf));
> +
> +  if (res != sizeof (buf))
> +    return -UNW_ENOINFO;
> +
> +  pi->format = UNW_INFO_FORMAT_REMOTE_TABLE;
> +  pi->start_ip = extract_unsigned_integer (buf + 0, 8, byte_order);
> +  pi->end_ip = extract_unsigned_integer (buf + 8, 8, byte_order);
> +  pi->gp = extract_unsigned_integer (buf + 24, 8, byte_order);
> +  table_addr = extract_unsigned_integer (buf + 16, 8, byte_order);
> +
> +  if (table_addr == 0)
> +    {
> +      /* No unwind data.  */
> +      pi->unwind_info = NULL;
> +      pi->unwind_info_size = 0;
> +      return 0;
> +    }
> +
> +  res = target_read_memory (table_addr, buf, 8);
> +  if (res != 0)
> +    return -UNW_ENOINFO;
> +
> +  /* Check version.  */
> +  if (extract_unsigned_integer (buf + 6, 2, byte_order) != 1)
> +      return -UNW_EBADVERSION;

Indentation looks off.

> +  info_len = extract_unsigned_integer (buf + 0, 4, byte_order);
> +  pi->unwind_info_size = 8 * info_len;
> +
> +  /* Read info.  */
> +  pi->unwind_info = malloc (pi->unwind_info_size);

xmalloc

> +  if (!pi->unwind_info)
> +    return -UNW_ENOMEM;
> +
> +  res = target_read_memory (table_addr + 8,
> +                            pi->unwind_info, pi->unwind_info_size);
> +  if (res != 0)
> +    {
> +      free (pi->unwind_info);

xfree

> +      pi->unwind_info = NULL;
> +      return -UNW_ENOINFO;
> +    }
> +
> +  /* FIXME: OSSD.  */

What's this?  What's OSSD?  What's left to fix?  Can we fix it?

> +
> +  pi->lsda = table_addr + 8 + pi->unwind_info_size;
> +  if (extract_unsigned_integer (buf + 4, 2, byte_order) & 3)
> +    {
> +      pi->lsda += 8;
> +      pi->handler = 0; /* FIXME: wrong, but who cares.  */

I don't know.  But I think this needs a better comment.

> +    }
> +
> +  return 0;
> +}
> +
> +/* Libunwind callback accessor function for cleanup.  */
> +static void
> +ia64_vms_put_unwind_info (unw_addr_space_t as,
> +                          unw_proc_info_t *pip, void *arg)
> +{
> +  /* Nothing required for now.  */

s/ for now//

> +}
> +
> +/* Libunwind callback accessor function to get head of the dynamic
> +   unwind-info registration list.  */
> +static int
> +ia64_vms_get_dyn_info_list (unw_addr_space_t as,
> +                            unw_word_t *dilap, void *arg)
> +{
> +  return -UNW_ENOINFO;
> +}
> +
> +/* Set of libunwind callback acccessor functions.  */
> +static unw_accessors_t ia64_vms_unw_accessors;
> +static unw_accessors_t ia64_vms_unw_rse_accessors;
> +
> +/* Set of ia64 gdb libunwind-frame callbacks and data for generic
> +   libunwind-frame code to use.  */
> +static struct libunwind_descr ia64_vms_libunwind_descr;
> +
> +#endif /* HAVE_LIBUNWIND_IA64_H */
> +
> +static void
> +ia64_openvms_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
> +{
> +  set_gdbarch_long_double_format (gdbarch, floatformats_ia64_quad);
> +
> +#ifdef HAVE_LIBUNWIND_IA64_H
> +  /* Override the default descriptor.  */
> +  ia64_vms_unw_accessors = ia64_unw_accessors;
> +  ia64_vms_unw_accessors.find_proc_info = ia64_vms_find_proc_info_x;
> +  ia64_vms_unw_accessors.put_unwind_info = ia64_vms_put_unwind_info;
> +  ia64_vms_unw_accessors.get_dyn_info_list_addr = ia64_vms_get_dyn_info_list;
> +
> +  ia64_vms_unw_rse_accessors = ia64_unw_rse_accessors;
> +  ia64_vms_unw_rse_accessors.find_proc_info = ia64_vms_find_proc_info_x;
> +  ia64_vms_unw_rse_accessors.put_unwind_info = ia64_vms_put_unwind_info;
> +  ia64_vms_unw_rse_accessors.get_dyn_info_list_addr = ia64_vms_get_dyn_info_list;
> +
> +  ia64_vms_libunwind_descr = ia64_libunwind_descr;
> +  ia64_vms_libunwind_descr.accessors = &ia64_vms_unw_accessors;
> +  ia64_vms_libunwind_descr.special_accessors = &ia64_vms_unw_rse_accessors;
> +
> +  libunwind_frame_set_descr (gdbarch, &ia64_vms_libunwind_descr);
> +#endif
> +}
> +
> +/* 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_OPENVMS,
> +			  ia64_openvms_init_abi);
> +}
> 

Otherwise looks fine.  I can't really comment on the vms or ia64 specifics.

Just please make sure an --enable-targets=all build doesn't break
unexpectedly.

-- 
Pedro Alves


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

* Re: RFA: New port: ia64-hp-openvms - the stub
  2012-02-10 13:44 ` RFA: New port: ia64-hp-openvms - the stub Tristan Gingold
  2012-02-10 19:06   ` Douglas Rupp
@ 2012-02-14 18:09   ` Pedro Alves
  2012-02-21 17:08     ` Tristan Gingold
  1 sibling, 1 reply; 31+ messages in thread
From: Pedro Alves @ 2012-02-14 18:09 UTC (permalink / raw)
  To: Tristan Gingold; +Cc: gdb-patches@sourceware.org ml, Rupp Douglas

On 02/10/2012 01:43 PM, Tristan Gingold wrote:
> Hi,
> 
> this is the debugger stub for ia64 VMS.
> Because it is independent of gdb (not unlike gdbserver) and because it isn't a one file stub, I think it is worth creating a subdirectory.

Sounds fine to me.

> I think we should also move the existing stubs there.
> 
> The interesting part is that on OpenVMS, the debugger is a shared library that is loaded with the application when debugging is needed (either from the start or during the run - like attach).  Just think about catching SIGTRAP, SIGSEGV, SIGBUS,Â… from a LD_PRELOAD binary.
> 
> The stub was written from scratch because it is highly OpenVMS dependent and in particular the standard C library shouldn't be used.

> The stub is not complete: some registers are partially or not handled, 

I couldn't really tell, but you may want to consider looking into xml target
descriptions.  At least reporting a description with the openvms osabi would
be good.

and inferior procedure call is not yet implemented (will be the funny part).


But it has already be extremely useful to debug some applications.

It's fine with me to put it in and improve it as we go.  I skimmed
it, but all the dollar signs distract a bit too much.  :-)

OOC,

> +#if 1
> +      /* What a mess.  Gdb and linux expects bsp to point after the current
> +         register frame.  Adjust.  */

What does this mean?  Are we committing to a hack that will make our
lives hard when we want to fix it?

> +      {
> +        unsigned __int64 bsp = intstk->intstk$q_bsp;
> +        unsigned int sof = intstk->intstk$q_ifs & 0x7f;
> +        unsigned int delta = ((bsp >> 3) & 0x3f) + sof;
> +        regs.bsp.v = bsp + ((sof + delta / 0x3f) << 3);
> +      }
> +#else
> +      regs.bsp.v = intstk->intstk$q_bsp;
> +#endif

-- 
Pedro Alves


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

* Re: RFA: New port: ia64-hp-openvms (3/3) - ia64-vms-tdep.c
  2012-02-14 17:50     ` Pedro Alves
@ 2012-02-15  9:14       ` Tristan Gingold
  2012-02-15 12:57         ` Pedro Alves
  0 siblings, 1 reply; 31+ messages in thread
From: Tristan Gingold @ 2012-02-15  9:14 UTC (permalink / raw)
  To: Pedro Alves; +Cc: gdb-patches@sourceware.org ml, Rupp Douglas


On Feb 14, 2012, at 6:50 PM, Pedro Alves wrote:

First, thank you for your review.  I am currently addressing your points.

[…]

> 
>> +  info_len = extract_unsigned_integer (buf + 0, 4, byte_order);
>> +  pi->unwind_info_size = 8 * info_len;
>> +
>> +  /* Read info.  */
>> +  pi->unwind_info = malloc (pi->unwind_info_size);
> 
> xmalloc

Humm, do we want to exit abruptly in case of memory error ?  Note that we test the return status.
(OTOH, if malloc fails here, it is likely that the next xmalloc will too).

> 
>> +  if (!pi->unwind_info)
>> +    return -UNW_ENOMEM;
>> +
>> +  res = target_read_memory (table_addr + 8,
>> +                            pi->unwind_info, pi->unwind_info_size);
>> +  if (res != 0)
>> +    {
>> +      free (pi->unwind_info);
> 
> xfree
> 
>> +      pi->unwind_info = NULL;
>> +      return -UNW_ENOINFO;
>> +    }
>> +
>> +  /* FIXME: OSSD.  */
> 
> What's this?  What's OSSD?  What's left to fix?  Can we fix it?

OS Specific Data.  That's an extension of unwinding info on VMS, that is not handled by libunwind.
OTOH, I haven't seen them currently.  I suppose they are used only in very specific context (kernel ?)

>> +
>> +  pi->lsda = table_addr + 8 + pi->unwind_info_size;
>> +  if (extract_unsigned_integer (buf + 4, 2, byte_order) & 3)
>> +    {
>> +      pi->lsda += 8;
>> +      pi->handler = 0; /* FIXME: wrong, but who cares.  */
> 
> I don't know.  But I think this needs a better comment.

Sure.

[…]

> 
> Otherwise looks fine.  I can't really comment on the vms or ia64 specifics.
> 
> Just please make sure an --enable-targets=all build doesn't break
> unexpectedly.

Will do.

Thanks,
Tristan.


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

* Re: RFA: New port: ia64-hp-openvms (3/3) - ia64-vms-tdep.c
  2012-02-15  9:14       ` Tristan Gingold
@ 2012-02-15 12:57         ` Pedro Alves
  2012-02-21 16:23           ` Tristan Gingold
  0 siblings, 1 reply; 31+ messages in thread
From: Pedro Alves @ 2012-02-15 12:57 UTC (permalink / raw)
  To: Tristan Gingold; +Cc: gdb-patches@sourceware.org ml, Rupp Douglas

On 02/15/2012 08:05 AM, Tristan Gingold wrote:
> 
> On Feb 14, 2012, at 6:50 PM, Pedro Alves wrote:

>>> +  info_len = extract_unsigned_integer (buf + 0, 4, byte_order);
>>> +  pi->unwind_info_size = 8 * info_len;
>>> +
>>> +  /* Read info.  */
>>> +  pi->unwind_info = malloc (pi->unwind_info_size);
>>
>> xmalloc
> 
> Humm, do we want to exit abruptly in case of memory error ?  Note that we test the return status.

Ah, missed that.  Fine with me to stay with malloc.  What does
libunwind do when one returns -UNW_ENOMEM?  Does GDB end up recovering correctly,
or do we end up busted anyway?

> (OTOH, if malloc fails here, it is likely that the next xmalloc will too).

Right...

-- 
Pedro Alves


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

* Re: RFA: New port: ia64-hp-openvms (2/3) - v2
  2012-02-14 17:36   ` Pedro Alves
  2012-02-14 17:40     ` Pedro Alves
@ 2012-02-21 16:08     ` Tristan Gingold
  2012-02-22 19:41       ` Pedro Alves
  1 sibling, 1 reply; 31+ messages in thread
From: Tristan Gingold @ 2012-02-21 16:08 UTC (permalink / raw)
  To: Pedro Alves; +Cc: gdb-patches@sourceware.org ml, Rupp Douglas


On Feb 14, 2012, at 6:35 PM, Pedro Alves wrote:

> On 02/10/2012 01:22 PM, Tristan Gingold wrote:
>> 
>> 2012-02-10  Tristan Gingold  <gingold@adacore.com>
>> 
>> 	* target.h (target_object): Add TARGET_OBJECT_OPENVMS_UIB.
>> 	* remote.c (PACKET_qXfer_uib): New enum value.
>> 	(remote_protocol_features): Add entry for PACKET_qXfer_uib.
>> 	(remote_xfer_partial): Handle TARGET_OBJECT_OPENVMS_UIB.
> 
> New packets need new documentation.  There should be a
> new call to add_packet_config_cmd call in _initialize_remote.

Hi,

here is the new version, with the call to add_packet_config_cmd and the doc added.

> And ... where's the code that actually reads this new object?

[You have found it].

Thanks,
Tristan.

2012-02-10  Tristan Gingold  <gingold@adacore.com>

	* target.h (target_object): Add TARGET_OBJECT_OPENVMS_UIB.
	* remote.c (PACKET_qXfer_uib): New enum value.
	(remote_protocol_features): Add entry for PACKET_qXfer_uib.
	(remote_xfer_partial): Handle TARGET_OBJECT_OPENVMS_UIB.
	(_initialize_remote): Call add_packet_config_cmd for
	xfer:uib packet.

doc/
2012-02-15  Tristan Gingold  <gingold@adacore.com>

	* gdb.texinfo (General Query Packets): Document xfer:uib.


diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index 73779a7..29c539b 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -35063,6 +35063,11 @@ These are the currently defined stub features and their properties:
 @tab @samp{-}
 @tab Yes
 
+@item @samp{qXfer:uib:read}
+@tab No
+@tab @samp{-}
+@tab Yes
+
 @item @samp{qXfer:fdpic:read}
 @tab No
 @tab @samp{-}
@@ -35192,6 +35197,10 @@ The remote stub understands the @samp{qXfer:threads:read} packet
 The remote stub understands the @samp{qXfer:traceframe-info:read}
 packet (@pxref{qXfer traceframe info read}).
 
+@item qXfer:uib:read
+The remote stub understands the @samp{qXfer:uib:read}
+packet (@pxref{qXfer unwind info block}).
+
 @item qXfer:fdpic:read
 The remote stub understands the @samp{qXfer:fdpic:read}
 packet (@pxref{qXfer fdpic loadmap read}).
@@ -35479,6 +35488,14 @@ Return a description of the current traceframe's contents.
 This packet is not probed by default; the remote stub must request it,
 by supplying an appropriate @samp{qSupported} response (@pxref{qSupported}).
 
+@item qXfer:uib:read:@var{pc}:@var{offset},@var{length}
+@anchor{qXfer unwind info block}
+
+Return the unwind information block for @var{pc}.  This packet is used
+on OpenVMS/ia64 to ask the kernel unwind information.
+
+This packet is not probed by default.
+
 @item qXfer:fdpic:read:@var{annex}:@var{offset},@var{length}
 @anchor{qXfer fdpic loadmap read}
 Read contents of @code{loadmap}s on the target system.  The
diff --git a/gdb/remote.c b/gdb/remote.c
index 14c343b..5822376 100644
--- a/gdb/remote.c
+++ b/gdb/remote.c
@@ -1250,6 +1250,7 @@ enum {
   PACKET_qXfer_threads,
   PACKET_qXfer_statictrace_read,
   PACKET_qXfer_traceframe_info,
+  PACKET_qXfer_uib,
   PACKET_qGetTIBAddr,
   PACKET_qGetTLSAddr,
   PACKET_qSupported,
@@ -3830,6 +3831,8 @@ static struct protocol_feature remote_protocol_features[] = {
     remote_enable_disable_tracepoint_feature, -1 },
   { "qXfer:fdpic:read", PACKET_DISABLE, remote_supported_packet,
     PACKET_qXfer_fdpic },
+  { "qXfer:uib:read", PACKET_DISABLE, remote_supported_packet,
+    PACKET_qXfer_uib },
   { "QDisableRandomization", PACKET_DISABLE, remote_supported_packet,
     PACKET_QDisableRandomization },
   { "tracenz", PACKET_DISABLE,
@@ -8426,6 +8429,11 @@ remote_xfer_partial (struct target_ops *ops, enum target_object object,
     case TARGET_OBJECT_FDPIC:
       return remote_read_qxfer (ops, "fdpic", annex, readbuf, offset, len,
 				&remote_protocol_packets[PACKET_qXfer_fdpic]);
+
+    case TARGET_OBJECT_OPENVMS_UIB:
+      return remote_read_qxfer (ops, "uib", annex, readbuf, offset, len,
+				&remote_protocol_packets[PACKET_qXfer_uib]);
+
     default:
       return -1;
     }
@@ -11217,6 +11225,9 @@ Show the maximum size of the address (in bits) in a memory packet."), NULL,
     (&remote_protocol_packets[PACKET_qXfer_traceframe_info],
      "qXfer:trace-frame-info:read", "traceframe-info", 0);
 
+  add_packet_config_cmd (&remote_protocol_packets[PACKET_qXfer_uib],
+			 "qXfer:uib:read", "unwind-info-block", 0);
+
   add_packet_config_cmd (&remote_protocol_packets[PACKET_qGetTLSAddr],
 			 "qGetTLSAddr", "get-thread-local-storage-address",
 			 0);
diff --git a/gdb/target.h b/gdb/target.h
index d4605ae..5f642be 100644
--- a/gdb/target.h
+++ b/gdb/target.h
@@ -280,7 +280,9 @@ enum target_object
   /* Load maps for FDPIC systems.  */
   TARGET_OBJECT_FDPIC,
   /* Darwin dynamic linker info data.  */
-  TARGET_OBJECT_DARWIN_DYLD_INFO
+  TARGET_OBJECT_DARWIN_DYLD_INFO,
+  /* OpenVMS Unwind Information Block.  */
+  TARGET_OBJECT_OPENVMS_UIB
   /* Possible future objects: TARGET_OBJECT_FILE, ...  */
 };
 


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

* Re: RFA: New port: ia64-hp-openvms (3/3) - ia64-vms-tdep.c
  2012-02-15 12:57         ` Pedro Alves
@ 2012-02-21 16:23           ` Tristan Gingold
  2012-02-22 19:39             ` Pedro Alves
  0 siblings, 1 reply; 31+ messages in thread
From: Tristan Gingold @ 2012-02-21 16:23 UTC (permalink / raw)
  To: Pedro Alves; +Cc: gdb-patches@sourceware.org ml, Rupp Douglas


On Feb 15, 2012, at 1:17 PM, Pedro Alves wrote:

> On 02/15/2012 08:05 AM, Tristan Gingold wrote:
>> 
>> On Feb 14, 2012, at 6:50 PM, Pedro Alves wrote:
> 
>>>> +  info_len = extract_unsigned_integer (buf + 0, 4, byte_order);
>>>> +  pi->unwind_info_size = 8 * info_len;
>>>> +
>>>> +  /* Read info.  */
>>>> +  pi->unwind_info = malloc (pi->unwind_info_size);
>>> 
>>> xmalloc
>> 
>> Humm, do we want to exit abruptly in case of memory error ?  Note that we test the return status.

Hi,

this is the new version.

> Ah, missed that.  Fine with me to stay with malloc.  What does
> libunwind do when one returns -UNW_ENOMEM?

My understanding is that libunwind properly propagate the error, and …

>  Does GDB end up recovering correctly,
> or do we end up busted anyway?

… gdb recovers.
But because it is so likely that gdb will fail later, I have switched to xmalloc/xfree.

>> (OTOH, if malloc fails here, it is likely that the next xmalloc will too).
> 
> Right…

Tristan.

2012-02-10  Tristan Gingold  <gingold@adacore.com>

       * ia64-tdep.h: Include libunwind-frame.h and libunwind-ia64.h.
       (ia64_unw_accessors, ia64_unw_rse_accessors)
       (ia64_libunwind_descr): Declare.
       * ia64-vms-tdep.c: New file.
       * ia64-tdep.c (ia64_unw_accessors, ia64_unw_rse_accessors)
       (ia64_libunwind_descr): Make them public.
       * configure.tgt: Add ia64-*-*vms*.
       * Makefile.in (ALL_64_TARGET_OBS): Add ia64-vms-tdep.o
       (ALLDEPFILES): Add ia64-vms-tdep.c

diff --git a/configure.ac b/configure.ac
index 9d48e90..c24fff4 100644
--- a/configure.ac
+++ b/configure.ac
@@ -929,8 +929,8 @@ case "${target}" in
     noconfigdirs="$noconfigdirs libgui itcl ld"
     ;;
   ia64*-*-*vms*)
-    # No gdb or ld support yet.
-    noconfigdirs="$noconfigdirs readline libgui itcl gdb ld"
+    # No ld support yet.
+    noconfigdirs="$noconfigdirs libgui itcl ld"
     ;;
   i[[3456789]]86-w64-mingw*)
     ;;
diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index 3e1b93c..357a6db 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -516,7 +516,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-hpux-tdep.o ia64-linux-tdep.o ia64-tdep.o \
+	ia64-hpux-tdep.o ia64-linux-tdep.o ia64-vms-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
@@ -1458,7 +1458,7 @@ ALLDEPFILES = \
 	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 \
+	ia64-linux-nat.c ia64-linux-tdep.c ia64-tdep.c ia64-vms-tdep.c \
 	inf-ptrace.c inf-ttrace.c \
 	irix5-nat.c \
 	libunwind-frame.c \
diff --git a/gdb/configure.tgt b/gdb/configure.tgt
index 5e97ab4..6b4a504 100644
--- a/gdb/configure.tgt
+++ b/gdb/configure.tgt
@@ -246,6 +246,10 @@ ia64-*-linux*)
 			solib-svr4.o symfile-mem.o"
 	build_gdbserver=yes
 	;;
+ia64-*-*vms*)
+	# Target: Intel IA-64 running OpenVMS
+	gdb_target_obs="ia64-tdep.o ia64-vms-tdep.o"
+	;;
 ia64*-*-*)
 	# Target: Intel IA-64
 	gdb_target_obs="ia64-tdep.o"
diff --git a/gdb/ia64-tdep.c b/gdb/ia64-tdep.c
index a36dc22..1c4fa8f 100644
--- a/gdb/ia64-tdep.c
+++ b/gdb/ia64-tdep.c
@@ -3148,7 +3148,7 @@ static const struct frame_unwind ia64_libunwind_sigtramp_frame_unwind =
 };
 
 /* Set of libunwind callback acccessor functions.  */
-static unw_accessors_t ia64_unw_accessors =
+unw_accessors_t ia64_unw_accessors =
 {
   ia64_find_proc_info_x,
   ia64_put_unwind_info,
@@ -3164,7 +3164,7 @@ static unw_accessors_t ia64_unw_accessors =
    the rse registers.  At the top of the stack, we want libunwind to figure out
    how to read r32 - r127.  Though usually they are found sequentially in
    memory starting from $bof, this is not always true.  */
-static unw_accessors_t ia64_unw_rse_accessors =
+unw_accessors_t ia64_unw_rse_accessors =
 {
   ia64_find_proc_info_x,
   ia64_put_unwind_info,
@@ -3178,7 +3178,7 @@ static unw_accessors_t ia64_unw_rse_accessors =
 
 /* Set of ia64 gdb libunwind-frame callbacks and data for generic
    libunwind-frame code to use.  */
-static struct libunwind_descr ia64_libunwind_descr =
+struct libunwind_descr ia64_libunwind_descr =
 {
   ia64_gdb2uw_regnum, 
   ia64_uw2gdb_regnum, 
diff --git a/gdb/ia64-tdep.h b/gdb/ia64-tdep.h
index 48cc3e0..7501eb4 100644
--- a/gdb/ia64-tdep.h
+++ b/gdb/ia64-tdep.h
@@ -20,6 +20,11 @@
 #ifndef IA64_TDEP_H
 #define IA64_TDEP_H
 
+#ifdef HAVE_LIBUNWIND_IA64_H
+#include "libunwind-ia64.h"
+#include "libunwind-frame.h"
+#endif
+
 /* Register numbers of various important registers.  */
 
 /* General registers; there are 128 of these 64 bit wide registers.
@@ -250,4 +255,10 @@ struct gdbarch_tdep
 
 extern void ia64_write_pc (struct regcache *, CORE_ADDR);
 
+#ifdef HAVE_LIBUNWIND_IA64_H
+extern unw_accessors_t ia64_unw_accessors;
+extern unw_accessors_t ia64_unw_rse_accessors;
+extern struct libunwind_descr ia64_libunwind_descr;
+#endif
+
 #endif /* ia64-tdep.h */
diff --git a/gdb/ia64-vms-tdep.c b/gdb/ia64-vms-tdep.c
new file mode 100644
index 0000000..dec66e1
--- /dev/null
+++ b/gdb/ia64-vms-tdep.c
@@ -0,0 +1,168 @@
+/* Target-dependent code for OpenVMS IA-64.
+
+   Copyright (C) 2012 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 "frame-unwind.h"
+#include "ia64-tdep.h"
+#include "osabi.h"
+#include "gdbtypes.h"
+#include "solib.h"
+#include "target.h"
+#include "frame.h"
+#include "regcache.h"
+#include "gdbcore.h"
+#include "inferior.h"
+
+#ifdef HAVE_LIBUNWIND_IA64_H
+
+/* Libunwind callback accessor function to acquire procedure unwind-info.  */
+
+static int
+ia64_vms_find_proc_info_x (unw_addr_space_t as, unw_word_t ip,
+                           unw_proc_info_t *pi,
+                           int need_unwind_info, void *arg)
+{
+  enum bfd_endian byte_order = gdbarch_byte_order (target_gdbarch);
+  unw_dyn_info_t di;
+  int ret;
+  gdb_byte buf[32];
+  const char *annex = core_addr_to_string (ip);
+  LONGEST res;
+  CORE_ADDR table_addr;
+  unsigned int info_len;
+
+  res = target_read (&current_target, TARGET_OBJECT_OPENVMS_UIB,
+                     annex + 2, buf, 0, sizeof (buf));
+
+  if (res != sizeof (buf))
+    return -UNW_ENOINFO;
+
+  pi->format = UNW_INFO_FORMAT_REMOTE_TABLE;
+  pi->start_ip = extract_unsigned_integer (buf + 0, 8, byte_order);
+  pi->end_ip = extract_unsigned_integer (buf + 8, 8, byte_order);
+  pi->gp = extract_unsigned_integer (buf + 24, 8, byte_order);
+  table_addr = extract_unsigned_integer (buf + 16, 8, byte_order);
+
+  if (table_addr == 0)
+    {
+      /* No unwind data.  */
+      pi->unwind_info = NULL;
+      pi->unwind_info_size = 0;
+      return 0;
+    }
+
+  res = target_read_memory (table_addr, buf, 8);
+  if (res != 0)
+    return -UNW_ENOINFO;
+
+  /* Check version.  */
+  if (extract_unsigned_integer (buf + 6, 2, byte_order) != 1)
+    return -UNW_EBADVERSION;
+  info_len = extract_unsigned_integer (buf + 0, 4, byte_order);
+  pi->unwind_info_size = 8 * info_len;
+
+  /* Read info.  */
+  pi->unwind_info = xmalloc (pi->unwind_info_size);
+
+  res = target_read_memory (table_addr + 8,
+                            pi->unwind_info, pi->unwind_info_size);
+  if (res != 0)
+    {
+      xfree (pi->unwind_info);
+      pi->unwind_info = NULL;
+      return -UNW_ENOINFO;
+    }
+
+  /* FIXME: Handle OSSD (OS Specific Data).  This extension to ia64 unwind
+     information by OpenVMS is currently not handled by libunwind, but
+     looks to be used only in very specific context, and is not generated by
+     GCC.  */
+
+  pi->lsda = table_addr + 8 + pi->unwind_info_size;
+  if (extract_unsigned_integer (buf + 4, 2, byte_order) & 3)
+    {
+      pi->lsda += 8;
+      /* There might be an handler, but this is not used for unwinding.  */
+      pi->handler = 0;
+    }
+
+  return 0;
+}
+
+/* Libunwind callback accessor function for cleanup.  */
+static void
+ia64_vms_put_unwind_info (unw_addr_space_t as,
+                          unw_proc_info_t *pip, void *arg)
+{
+  /* Nothing required for now.  */
+}
+
+/* Libunwind callback accessor function to get head of the dynamic
+   unwind-info registration list.  */
+static int
+ia64_vms_get_dyn_info_list (unw_addr_space_t as,
+                            unw_word_t *dilap, void *arg)
+{
+  return -UNW_ENOINFO;
+}
+
+/* Set of libunwind callback acccessor functions.  */
+static unw_accessors_t ia64_vms_unw_accessors;
+static unw_accessors_t ia64_vms_unw_rse_accessors;
+
+/* Set of ia64 gdb libunwind-frame callbacks and data for generic
+   libunwind-frame code to use.  */
+static struct libunwind_descr ia64_vms_libunwind_descr;
+
+#endif /* HAVE_LIBUNWIND_IA64_H */
+
+static void
+ia64_openvms_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
+{
+  set_gdbarch_long_double_format (gdbarch, floatformats_ia64_quad);
+
+#ifdef HAVE_LIBUNWIND_IA64_H
+  /* Override the default descriptor.  */
+  ia64_vms_unw_accessors = ia64_unw_accessors;
+  ia64_vms_unw_accessors.find_proc_info = ia64_vms_find_proc_info_x;
+  ia64_vms_unw_accessors.put_unwind_info = ia64_vms_put_unwind_info;
+  ia64_vms_unw_accessors.get_dyn_info_list_addr = ia64_vms_get_dyn_info_list;
+
+  ia64_vms_unw_rse_accessors = ia64_unw_rse_accessors;
+  ia64_vms_unw_rse_accessors.find_proc_info = ia64_vms_find_proc_info_x;
+  ia64_vms_unw_rse_accessors.put_unwind_info = ia64_vms_put_unwind_info;
+  ia64_vms_unw_rse_accessors.get_dyn_info_list_addr = ia64_vms_get_dyn_info_list;
+
+  ia64_vms_libunwind_descr = ia64_libunwind_descr;
+  ia64_vms_libunwind_descr.accessors = &ia64_vms_unw_accessors;
+  ia64_vms_libunwind_descr.special_accessors = &ia64_vms_unw_rse_accessors;
+
+  libunwind_frame_set_descr (gdbarch, &ia64_vms_libunwind_descr);
+#endif
+}
+
+/* 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_OPENVMS,
+			  ia64_openvms_init_abi);
+}


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

* Re: RFA: New port: ia64-hp-openvms - the stub
  2012-02-14 18:09   ` Pedro Alves
@ 2012-02-21 17:08     ` Tristan Gingold
  2012-02-22 20:25       ` Pedro Alves
  0 siblings, 1 reply; 31+ messages in thread
From: Tristan Gingold @ 2012-02-21 17:08 UTC (permalink / raw)
  To: Pedro Alves; +Cc: gdb-patches@sourceware.org ml, Rupp Douglas


On Feb 14, 2012, at 7:08 PM, Pedro Alves wrote:

> On 02/10/2012 01:43 PM, Tristan Gingold wrote:
>> Hi,
>> 
>> this is the debugger stub for ia64 VMS.
>> Because it is independent of gdb (not unlike gdbserver) and because it isn't a one file stub, I think it is worth creating a subdirectory.
> 
> Sounds fine to me.
> 
>> I think we should also move the existing stubs there.
>> 
>> The interesting part is that on OpenVMS, the debugger is a shared library that is loaded with the application when debugging is needed (either from the start or during the run - like attach).  Just think about catching SIGTRAP, SIGSEGV, SIGBUS,… from a LD_PRELOAD binary.
>> 
>> The stub was written from scratch because it is highly OpenVMS dependent and in particular the standard C library shouldn't be used.
> 
>> The stub is not complete: some registers are partially or not handled, 
> 
> I couldn't really tell, but you may want to consider looking into xml target
> descriptions.  At least reporting a description with the openvms osabi would
> be good.

I plan to fix the register issue soon, just be patient !

> and inferior procedure call is not yet implemented (will be the funny part).
> 
> 
> But it has already be extremely useful to debug some applications.
> 
> It's fine with me to put it in and improve it as we go.  I skimmed
> it, but all the dollar signs distract a bit too much.  :-)

The dollar is used to separate the name space.  Was a very good idea, as it avoids name clash issues that exits on Unix.

> OOC,
> 
>> +#if 1
>> +      /* What a mess.  Gdb and linux expects bsp to point after the current
>> +         register frame.  Adjust.  */
> 
> What does this mean?  Are we committing to a hack that will make our
> lives hard when we want to fix it?

I have updated the comment.  Currently, ia64-tdep.c follows the Linux convention, and we don't want to change that.  So the BSP has to be adjusted.

>> +      {
>> +        unsigned __int64 bsp = intstk->intstk$q_bsp;
>> +        unsigned int sof = intstk->intstk$q_ifs & 0x7f;
>> +        unsigned int delta = ((bsp >> 3) & 0x3f) + sof;
>> +        regs.bsp.v = bsp + ((sof + delta / 0x3f) << 3);
>> +      }
>> +#else
>> +      regs.bsp.v = intstk->intstk$q_bsp;
>> +#endif

Here is the updated version, if you still like the dollars :-)  I added the support for threads.

Thank you,
Tristan.

gdb/stubs:
2012-02-10  Tristan Gingold  <gingold@adacore.com>

        * buildvms.com: New file.
        * ia64vms-stub.c: New file.


diff --git a/gdb/stubs/buildvms.com b/gdb/stubs/buildvms.com
new file mode 100644
index 0000000..f13b3b5
--- /dev/null
+++ b/gdb/stubs/buildvms.com
@@ -0,0 +1,11 @@
+$! Command to build the gdb stub
+$cc /debug/noopt /pointer=64 gdbstub +sys$library:sys$lib_c.tlb/lib
+$ link/notraceback/sysexe/map=gdbstub.map/full/share=gdbstub.exe gdbstub,sys$input/opt
+$deck
+cluster=gdbzero
+collect=gdbzero, XFER_PSECT
+$eod
+$ search /nowarnings gdbstub.map "DECC$"
+$! Example of use.
+$ DEFINE /nolog LIB$DEBUG sys$login:gdbstub.exe
diff --git a/gdb/stubs/ia64vms-stub.c b/gdb/stubs/ia64vms-stub.c
new file mode 100644
index 0000000..4decece
--- /dev/null
+++ b/gdb/stubs/ia64vms-stub.c
@@ -0,0 +1,2602 @@
+/* GDB stub for Itanium OpenVMS
+   Copyright (C) 2012, Free Software Foundation, Inc.
+
+   Contributed by Tristan Gingold, AdaCore.
+
+   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/>.  */
+
+/* On VMS, the debugger (in our case the stub) is loaded in the process and
+   executed (via SYS$IMGSTA) before the main entry point of the executable.
+   In UNIX parlance, this is like using LD_PRELOAD and debug via installing
+   SIGTRAP, SIGSEGV... handlers.
+
+   This is currently a partial implementation.  In particular, modifying
+   registers is currently not implemented, as well as inferior procedure
+   calls.
+
+   This is written in very low-level C, in order not to use the C runtime,
+   because it may have weird consequences on the program being debugged.
+*/
+
+#if __INITIAL_POINTER_SIZE != 64
+#error "Must be compiled with 64 bit pointers"
+#endif
+
+#define __NEW_STARLET 1
+#include <descrip.h>
+#include <iledef.h>
+#include <efndef.h>
+#include <in.h>
+#include <inet.h>
+#include <iodef.h>
+#include <ssdef.h>
+#include <starlet.h>
+#include <stsdef.h>
+#include <tcpip$inetdef.h>
+
+#include <lib$routines.h>
+#include <ots$routines.h>
+#include <str$routines.h>
+#include <libdef.h>
+#include <clidef.h>
+#include <iosbdef.h>
+#include <dvidef.h>
+#include <lnmdef.h>
+#include <builtins.h>
+#include <prtdef.h>
+#include <psldef.h>
+#include <ssdef.h>
+#include <chfdef.h>
+
+#include <lib_c/imcbdef.h>
+#include <lib_c/ldrimgdef.h>
+#include <lib_c/intstkdef.h>
+#include <lib_c/psrdef.h>
+#include <lib_c/ifddef.h>
+#include <lib_c/eihddef.h>
+
+#include <stdarg.h>
+#include <pthread_debug.h>
+
+#define VMS_PAGE_SIZE 0x2000
+#define VMS_PAGE_MASK (VMS_PAGE_SIZE - 1)
+
+/* Declared in lib$ots.  */
+extern void ots$fill (void *addr, size_t len, unsigned char b);
+extern void ots$move (void *dst, size_t len, const void *src);
+extern int ots$strcmp_eql (const void *str1, size_t str1len,
+                           const void *str2, size_t str2len);
+
+/* Stub port number.  */
+static unsigned int serv_port = 1234;
+
+/* DBGEXT structure.  Not declared in any header.  */
+struct dbgext_control_block
+{
+  unsigned short dbgext$w_function_code;
+#define DBGEXT$K_NEXT_TASK	      3
+#define DBGEXT$K_STOP_ALL_OTHER_TASKS 31
+#define DBGEXT$K_GET_REGS 33
+  unsigned short dbgext$w_facility_id;
+#define CMA$_FACILITY 64
+  unsigned int dbgext$l_status;
+  unsigned int dbgext$l_flags;
+  unsigned int dbgext$l_print_routine;
+  unsigned int dbgext$l_evnt_code;
+  unsigned int dbgext$l_evnt_name;
+  unsigned int dbgext$l_evnt_entry;
+  unsigned int dbgext$l_task_value;
+  unsigned int dbgext$l_task_number;
+  unsigned int dbgext$l_ada_flags;
+  unsigned int dbgext$l_stop_value;
+#define dbgext$l_priority   dbgext$l_stop_value;
+#define dbgext$l_symb_addr  dbgext$l_stop_value;
+#define dbgext$l_time_slice dbgext$l_stop_value;
+  unsigned int dbgext$l_active_registers;
+};
+
+#pragma pointer_size save
+#pragma pointer_size 32
+
+/* Pthread handler.  */
+static int (*dbgext_func) (struct dbgext_control_block *blk);
+
+#pragma pointer_size restore
+
+/* Set to 1 if thread-aware.  */
+static int has_threads;
+
+/* Current thread.  */
+static pthread_t selected_thread;
+static pthreadDebugId_t selected_id;
+
+/* Internal debugging flags.  */
+struct debug_flag
+{
+  /* Name of the flag (as a string descriptor).  */
+  const struct dsc$descriptor_s name;
+  /* Value.  */
+  int val;
+};
+
+/* Macro to define a debugging flag.  */
+#define DEBUG_FLAG_ENTRY(str) \
+  { { sizeof (str) - 1, DSC$K_DTYPE_T, DSC$K_CLASS_S, str }, 0}
+
+static struct debug_flag debug_flags[] =
+{
+  /* Disp packets exchanged with gdb.  */
+  DEBUG_FLAG_ENTRY("packets"),
+#define trace_pkt (debug_flags[0].val)
+  /* Display entry point informations.  */
+  DEBUG_FLAG_ENTRY("entry"),
+#define trace_entry (debug_flags[1].val)
+  /* Be verbose about exceptions.  */
+  DEBUG_FLAG_ENTRY("excp"),
+#define trace_excp (debug_flags[2].val)
+  /* Be verbose about unwinding.  */
+  DEBUG_FLAG_ENTRY("unwind"),
+#define trace_unwind (debug_flags[3].val)
+  /* Display image at startup.  */
+  DEBUG_FLAG_ENTRY("images"),
+#define trace_images (debug_flags[4].val)
+  /* Display pthread_debug info.  */
+  DEBUG_FLAG_ENTRY("pthreaddbg")
+#define trace_pthreaddbg (debug_flags[5].val)
+};
+
+#define NBR_DEBUG_FLAGS (sizeof (debug_flags) / sizeof (debug_flags[0]))
+
+/* Connect inet device I/O channel.  */
+static unsigned short conn_channel;
+
+/* Widely used hex digit to ascii.  */
+static const char hex[] = "0123456789abcdef";
+
+/* Socket characteristics.  Apparently, there are no declaration for it in
+   standard headers.  */
+struct sockchar
+{
+  unsigned short prot;
+  unsigned char type;
+  unsigned char af;
+};
+
+/* Chain of images loaded.  */
+extern IMCB* ctl$gl_imglstptr;
+
+/* IA64 integer register representation.  */
+union ia64_ireg
+{
+  unsigned __int64 v;
+  unsigned char b[8];
+};
+
+/* IA64 register numbers, as defined by ia64-tdep.h.  */
+#define IA64_GR0_REGNUM		0
+#define IA64_GR32_REGNUM	(IA64_GR0_REGNUM + 32)
+
+/* Floating point registers; 128 82-bit wide registers.  */
+#define IA64_FR0_REGNUM		128
+
+/* Predicate registers; There are 64 of these one bit registers.  It'd
+   be more convenient (implementation-wise) to use a single 64 bit
+   word with all of these register in them.  Note that there's also a
+   IA64_PR_REGNUM below which contains all the bits and is used for
+   communicating the actual values to the target.  */
+#define IA64_PR0_REGNUM		256
+
+/* Branch registers: 8 64-bit registers for holding branch targets.  */
+#define IA64_BR0_REGNUM		320
+
+/* Virtual frame pointer; this matches IA64_FRAME_POINTER_REGNUM in
+   gcc/config/ia64/ia64.h.  */
+#define IA64_VFP_REGNUM		328
+
+/* Virtual return address pointer; this matches
+   IA64_RETURN_ADDRESS_POINTER_REGNUM in gcc/config/ia64/ia64.h.  */
+#define IA64_VRAP_REGNUM	329
+
+/* Predicate registers: There are 64 of these 1-bit registers.  We
+   define a single register which is used to communicate these values
+   to/from the target.  We will somehow contrive to make it appear
+   that IA64_PR0_REGNUM thru IA64_PR63_REGNUM hold the actual values.  */
+#define IA64_PR_REGNUM		330
+
+/* Instruction pointer: 64 bits wide.  */
+#define IA64_IP_REGNUM		331
+
+/* Process Status Register.  */
+#define IA64_PSR_REGNUM		332
+
+/* Current Frame Marker (raw form may be the cr.ifs).  */
+#define IA64_CFM_REGNUM		333
+
+/* Application registers; 128 64-bit wide registers possible, but some
+   of them are reserved.  */
+#define IA64_AR0_REGNUM		334
+#define IA64_KR0_REGNUM		(IA64_AR0_REGNUM + 0)
+#define IA64_KR7_REGNUM		(IA64_KR0_REGNUM + 7)
+
+#define IA64_RSC_REGNUM		(IA64_AR0_REGNUM + 16)
+#define IA64_BSP_REGNUM		(IA64_AR0_REGNUM + 17)
+#define IA64_BSPSTORE_REGNUM	(IA64_AR0_REGNUM + 18)
+#define IA64_RNAT_REGNUM	(IA64_AR0_REGNUM + 19)
+#define IA64_FCR_REGNUM		(IA64_AR0_REGNUM + 21)
+#define IA64_EFLAG_REGNUM	(IA64_AR0_REGNUM + 24)
+#define IA64_CSD_REGNUM		(IA64_AR0_REGNUM + 25)
+#define IA64_SSD_REGNUM		(IA64_AR0_REGNUM + 26)
+#define IA64_CFLG_REGNUM	(IA64_AR0_REGNUM + 27)
+#define IA64_FSR_REGNUM		(IA64_AR0_REGNUM + 28)
+#define IA64_FIR_REGNUM		(IA64_AR0_REGNUM + 29)
+#define IA64_FDR_REGNUM		(IA64_AR0_REGNUM + 30)
+#define IA64_CCV_REGNUM		(IA64_AR0_REGNUM + 32)
+#define IA64_UNAT_REGNUM	(IA64_AR0_REGNUM + 36)
+#define IA64_FPSR_REGNUM	(IA64_AR0_REGNUM + 40)
+#define IA64_ITC_REGNUM		(IA64_AR0_REGNUM + 44)
+#define IA64_PFS_REGNUM		(IA64_AR0_REGNUM + 64)
+#define IA64_LC_REGNUM		(IA64_AR0_REGNUM + 65)
+#define IA64_EC_REGNUM		(IA64_AR0_REGNUM + 66)
+
+/* NAT (Not A Thing) Bits for the general registers; there are 128 of
+   these.  */
+#define IA64_NAT0_REGNUM	462
+
+/* Process registers when a condition is caught.  */
+struct ia64_all_regs
+{
+  union ia64_ireg gr[32];
+  union ia64_ireg br[8];
+  union ia64_ireg ip;
+  union ia64_ireg psr;
+  union ia64_ireg bsp;
+  union ia64_ireg cfm;
+  union ia64_ireg pfs;
+  union ia64_ireg pr;
+};
+
+static struct ia64_all_regs excp_regs;
+static struct ia64_all_regs sel_regs;
+static pthread_t sel_regs_pthread;
+
+/* IO channel for the terminal.  */
+static unsigned short term_chan;
+
+/* Output buffer and length.  */
+static char term_buf[128];
+static int term_buf_len;
+
+/* Buffer for communication with gdb.  */
+static unsigned char gdb_buf[sizeof (struct ia64_all_regs) * 2 + 64];
+static unsigned int gdb_blen;
+
+/* Previous primary handler.  */
+static void *prevhnd;
+
+/* Entry point address and bundle.  */
+static unsigned __int64 entry_pc;
+static unsigned char entry_saved[16];
+
+/* Write on the terminal.  */
+
+static void
+term_raw_write (const char *str, unsigned int len)
+{
+  unsigned short status;
+  struct _iosb iosb;
+
+  status = sys$qiow (EFN$C_ENF,           /* Event flag.  */
+                     term_chan,           /* I/O channel.  */
+                     IO$_WRITEVBLK,       /* I/O function code.  */
+                     &iosb,               /* I/O status block.  */
+                     0,                   /* Ast service routine.  */
+                     0,                   /* Ast parameter.  */
+                     (char *)str,         /* P1 - buffer address.  */
+                     len,                 /* P2 - buffer length.  */
+                     0, 0, 0, 0);
+
+  if (status & STS$M_SUCCESS)
+    status = iosb.iosb$w_status;
+  if (!(status & STS$M_SUCCESS))
+    LIB$SIGNAL (status);
+}
+
+/* Flush ther term buffer.  */
+
+static void
+term_flush (void)
+{
+  if (term_buf_len != 0)
+    {
+      term_raw_write (term_buf, term_buf_len);
+      term_buf_len = 0;
+    }
+}
+
+/* Write a single character, without translation.  */
+
+static void
+term_raw_putchar (char c)
+{
+  if (term_buf_len == sizeof (term_buf))
+    term_flush ();
+  term_buf[term_buf_len++] = c;
+}
+
+/* Write character C.  Translate '\n' to '\n\r'.  */
+
+static void
+term_putc (char c)
+{
+  if (c < 32)
+    switch (c)
+      {
+      case '\r':
+      case '\n':
+	break;
+      default:
+	c = '.';
+	break;
+      }
+  term_raw_putchar (c);
+  if (c == '\n')
+    {
+      term_raw_putchar ('\r');
+      term_flush ();
+    }
+}
+
+/* Write a C string.  */
+
+static void
+term_puts (const char *str)
+{
+  while (*str)
+    term_putc (*str++);
+}
+
+/* Write LEN bytes from STR.  */
+
+static void
+term_write (const char *str, unsigned int len)
+{
+  for (; len > 0; len--)
+    term_putc (*str++);
+}
+
+/* Write using FAO formatting.  */
+
+static void
+term_fao (const char *str, unsigned int str_len, ...)
+{
+  int cnt;
+  va_list vargs;
+  int i;
+  __int64 *args;
+  int status;
+  struct dsc$descriptor_s dstr =
+    { str_len, DSC$K_DTYPE_T, DSC$K_CLASS_S, (__char_ptr32)str };
+  char buf[128];
+  $DESCRIPTOR (buf_desc, buf);
+
+  va_start (vargs, str_len);
+  va_count (cnt);
+  args = (__int64 *) __ALLOCA (cnt * sizeof (__int64));
+  cnt -= 2;
+  for (i = 0; i < cnt; i++)
+    args[i] = va_arg (vargs, __int64);
+
+  status = sys$faol_64 (&dstr, &buf_desc.dsc$w_length, &buf_desc, args);
+  if (status & 1)
+    {
+      /* FAO !/ already insert a line feed.  */
+      for (i = 0; i < buf_desc.dsc$w_length; i++)
+	{
+	  term_raw_putchar (buf[i]);
+	  if (buf[i] == '\n')
+	    term_flush ();
+	}
+    }
+      
+  va_end (vargs);
+}
+
+#define TERM_FAO(STR, ...) term_fao (STR, sizeof (STR) - 1, __VA_ARGS__)
+
+/* New line.  */
+
+static void
+term_putnl (void)
+{
+  term_putc ('\n');
+}
+
+/* Initialize terminal.  */
+
+static void
+term_init (void)
+{
+  unsigned int status,i;
+  unsigned short len;
+  char resstring[LNM$C_NAMLENGTH];
+  static const $DESCRIPTOR (tabdesc, "LNM$FILE_DEV");
+  static const $DESCRIPTOR (logdesc, "SYS$OUTPUT");
+  $DESCRIPTOR (term_desc, resstring);
+  ILE3 item_lst[2];
+
+  item_lst[0].ile3$w_length = LNM$C_NAMLENGTH;
+  item_lst[0].ile3$w_code = LNM$_STRING;
+  item_lst[0].ile3$ps_bufaddr = resstring;
+  item_lst[0].ile3$ps_retlen_addr = &len;
+  item_lst[1].ile3$w_length = 0;
+  item_lst[1].ile3$w_code = 0;
+
+  /* Translate the logical name.  */
+  status = SYS$TRNLNM (0,          	  /* Attr of the logical name.  */
+                       (void *) &tabdesc, /* Logical name table.  */
+                       (void *) &logdesc, /* Logical name.  */
+                       0,          /* Access mode.  */
+                       item_lst);  /* Item list.  */
+  if (!(status & STS$M_SUCCESS))
+    LIB$SIGNAL (status);
+
+  term_desc.dsc$w_length = len;
+
+  /* Examine 4-byte header.  Skip escape sequence.  */
+  if (resstring[0] == 0x1B)
+    {
+      term_desc.dsc$w_length -= 4;
+      term_desc.dsc$a_pointer += 4;
+    }
+
+  /* Assign a channel.  */
+  status = sys$assign (&term_desc,   /* Device name.  */
+                       &term_chan,   /* I/O channel.  */
+                       0,            /* Access mode.  */
+                       0);
+  if (!(status & STS$M_SUCCESS))
+    LIB$SIGNAL (status);
+}
+
+/* Convert from native endianness to network endianness (and vice-versa).  */
+
+static unsigned int
+wordswap (unsigned int v)
+{
+  return ((v & 0xff) << 8) | ((v >> 8) & 0xff);
+}
+
+/* Initialize the socket connection, and wait for a client.  */
+
+static void
+sock_init (void)
+{
+  struct _iosb iosb;
+  unsigned int status;
+
+  /* Listen channel and characteristics.  */
+  unsigned short listen_channel;
+  struct sockchar listen_sockchar;
+
+  /* Client address.  */
+  unsigned short cli_addrlen;
+  struct sockaddr_in cli_addr;
+  ILE3 cli_itemlst;
+
+  /* Our address.  */
+  struct sockaddr_in serv_addr;
+  ILE2 serv_itemlst;
+
+  /* Reuseaddr option value (on).  */
+  int optval = 1;
+  ILE2 sockopt_itemlst;
+  ILE2 reuseaddr_itemlst;
+
+  /* TCP/IP network pseudodevice.  */
+  static const $DESCRIPTOR (inet_device, "TCPIP$DEVICE:");
+
+  /* Initialize socket characteristics.  */
+  listen_sockchar.prot = TCPIP$C_TCP;
+  listen_sockchar.type = TCPIP$C_STREAM;
+  listen_sockchar.af   = TCPIP$C_AF_INET;
+
+  /* Assign I/O channels to network device.  */
+  status = sys$assign ((void *) &inet_device, &listen_channel, 0, 0);
+  if (status & STS$M_SUCCESS)
+    status = sys$assign ((void *) &inet_device, &conn_channel, 0, 0);
+  if (!(status & STS$M_SUCCESS))
+    {
+      term_puts ("Failed to assign I/O channel(s)\n");
+      LIB$SIGNAL (status);
+    }
+
+  /* Create a listen socket.  */
+  status = sys$qiow (EFN$C_ENF,           /* Event flag.  */
+                     listen_channel,      /* I/O channel.  */
+                     IO$_SETMODE,         /* I/O function code.  */
+                     &iosb,               /* I/O status block.  */
+                     0,                   /* Ast service routine.  */
+                     0,                   /* Ast parameter.  */
+                     &listen_sockchar,    /* P1 - socket characteristics.  */
+                     0, 0, 0, 0, 0);
+  if (status & STS$M_SUCCESS)
+    status = iosb.iosb$w_status;
+  if (!(status & STS$M_SUCCESS))
+    {
+      term_puts ("Failed to create socket\n");
+      LIB$SIGNAL (status);
+    }
+
+  /* Set reuse address option.  */
+  /* Initialize reuseaddr's item-list element.  */
+  reuseaddr_itemlst.ile2$w_length   = sizeof (optval);
+  reuseaddr_itemlst.ile2$w_code     = TCPIP$C_REUSEADDR;
+  reuseaddr_itemlst.ile2$ps_bufaddr = &optval;
+
+  /* Initialize setsockopt's item-list descriptor.  */
+  sockopt_itemlst.ile2$w_length   = sizeof (reuseaddr_itemlst);
+  sockopt_itemlst.ile2$w_code     = TCPIP$C_SOCKOPT;
+  sockopt_itemlst.ile2$ps_bufaddr = &reuseaddr_itemlst;
+
+  status = sys$qiow (EFN$C_ENF,       /* Event flag.  */
+                     listen_channel,  /* I/O channel.  */
+                     IO$_SETMODE,     /* I/O function code.  */
+                     &iosb,           /* I/O status block.  */
+                     0,               /* Ast service routine.  */
+                     0,               /* Ast parameter.  */
+                     0,               /* P1.  */
+                     0,               /* P2.  */
+                     0,               /* P3.  */
+                     0,               /* P4.  */
+                     (__int64) &sockopt_itemlst, /* P5 - socket options.  */
+                     0);
+  if (status & STS$M_SUCCESS)
+    status = iosb.iosb$w_status;
+  if (!(status & STS$M_SUCCESS))
+    {
+      term_puts ("Failed to set socket option\n");
+      LIB$SIGNAL (status);
+    }
+
+  /* Bind server's ip address and port number to listen socket.  */
+  /* Initialize server's socket address structure.  */
+  ots$fill (&serv_addr, sizeof (serv_addr), 0);
+  serv_addr.sin_family = TCPIP$C_AF_INET;
+  serv_addr.sin_port = wordswap (serv_port);
+  serv_addr.sin_addr.s_addr = TCPIP$C_INADDR_ANY;
+
+  /* Initialize server's item-list descriptor.  */
+  serv_itemlst.ile2$w_length   = sizeof (serv_addr);
+  serv_itemlst.ile2$w_code     = TCPIP$C_SOCK_NAME;
+  serv_itemlst.ile2$ps_bufaddr = &serv_addr;
+
+  status = sys$qiow (EFN$C_ENF,           /* Event flag.  */
+                     listen_channel,      /* I/O channel.  */
+                     IO$_SETMODE,         /* I/O function code.  */
+                     &iosb,               /* I/O status block.  */
+                     0,                   /* Ast service routine.  */
+                     0,                   /* Ast parameter.  */
+                     0,                   /* P1.  */
+                     0,                   /* P2.  */
+                     (__int64) &serv_itemlst, /* P3 - local socket name.  */
+                     0, 0, 0);
+  if (status & STS$M_SUCCESS)
+    status = iosb.iosb$w_status;
+  if (!(status & STS$M_SUCCESS))
+    {
+      term_puts ("Failed to bind socket\n");
+      LIB$SIGNAL (status);
+    }
+
+  /* Set socket as a listen socket.  */
+  status = sys$qiow (EFN$C_ENF,           /* Event flag.  */
+                     listen_channel,      /* I/O channel.  */
+                     IO$_SETMODE,         /* I/O function code.  */
+                     &iosb,               /* I/O status block.  */
+                     0,                   /* Ast service routine.  */
+                     0,                   /* Ast parameter.  */
+                     0,                   /* P1.  */
+                     0,                   /* P2.  */
+                     0,                   /* P3.  */
+                     1,                   /* P4 - connection backlog.  */
+                     0, 0);
+  if (status & STS$M_SUCCESS)
+    status = iosb.iosb$w_status;
+  if (!(status & STS$M_SUCCESS))
+    {
+      term_puts ("Failed to set socket passive\n");
+      LIB$SIGNAL (status);
+    }
+
+  /* Accept connection from a client.  */
+  TERM_FAO ("Waiting for a client connection on port: !ZW!/",
+	    wordswap (serv_addr.sin_port));
+
+  status = sys$qiow (EFN$C_ENF,              /* Event flag.  */
+                     listen_channel,         /* I/O channel.  */
+                     IO$_ACCESS|IO$M_ACCEPT, /* I/O function code.  */
+                     &iosb,                  /* I/O status block.  */
+                     0,                      /* Ast service routine.  */
+                     0,                      /* Ast parameter.  */
+                     0,                      /* P1.  */
+                     0,                      /* P2.  */
+                     0,                      /* P3.  */
+                     (__int64) &conn_channel, /* P4 - I/O channel for conn.  */
+                     0, 0);
+
+  if (status & STS$M_SUCCESS)
+    status = iosb.iosb$w_status;
+  if (!(status & STS$M_SUCCESS))
+    {
+      term_puts ("Failed to accept client connection\n");
+      LIB$SIGNAL (status);
+    }
+
+  /* Log client connection request.  */
+  cli_itemlst.ile3$w_length = sizeof (cli_addr);
+  cli_itemlst.ile3$w_code = TCPIP$C_SOCK_NAME;
+  cli_itemlst.ile3$ps_bufaddr = &cli_addr;
+  cli_itemlst.ile3$ps_retlen_addr = &cli_addrlen;
+  ots$fill (&cli_addr, sizeof(cli_addr), 0);
+  status = sys$qiow (EFN$C_ENF,           /* Event flag.  */
+                     conn_channel,        /* I/O channel.  */
+                     IO$_SENSEMODE,       /* I/O function code.  */
+                     &iosb,               /* I/O status block.  */
+                     0,                   /* Ast service routine.  */
+                     0,                   /* Ast parameter.  */
+                     0,                   /* P1.  */
+                     0,                   /* P2.  */
+                     0,                   /* P3.  */
+                     (__int64) &cli_itemlst,  /* P4 - peer socket name.  */
+                     0, 0);
+  if (status & STS$M_SUCCESS)
+    status = iosb.iosb$w_status;
+  if (!(status & STS$M_SUCCESS))
+    {
+      term_puts ("Failed to get client name\n");
+      LIB$SIGNAL (status);
+    }
+
+  TERM_FAO ("Accepted connection from host: !UB.!UB,!UB.!UB, port: !UW!/",
+	    (cli_addr.sin_addr.s_addr >> 0) & 0xff,
+	    (cli_addr.sin_addr.s_addr >> 8) & 0xff,
+	    (cli_addr.sin_addr.s_addr >> 16) & 0xff,
+	    (cli_addr.sin_addr.s_addr >> 24) & 0xff,
+	    wordswap (cli_addr.sin_port));
+}
+
+/* Close the socket.  */
+
+static void
+sock_close (void)
+{
+  struct _iosb iosb;
+  unsigned int status;
+
+  /* Close socket.  */
+  status = sys$qiow (EFN$C_ENF,           /* Event flag.  */
+                     conn_channel,        /* I/O channel.  */
+                     IO$_DEACCESS,        /* I/O function code.  */
+                     &iosb,               /* I/O status block.  */
+                     0,                   /* Ast service routine.  */
+                     0,                   /* Ast parameter.  */
+                     0, 0, 0, 0, 0, 0);
+
+  if (status & STS$M_SUCCESS)
+    status = iosb.iosb$w_status;
+  if (!(status & STS$M_SUCCESS))
+    {
+      term_puts ("Failed to close socket\n");
+      LIB$SIGNAL (status);
+    }
+
+  /* Deassign I/O channel to network device.  */
+  status = sys$dassgn (conn_channel);
+
+  if (!(status & STS$M_SUCCESS))
+    {
+      term_puts ("Failed to deassign I/O channel\n");
+      LIB$SIGNAL (status);
+    }
+}
+
+/* Mark a page as R/W.  Return old rights.  */
+
+static unsigned int
+page_set_rw (unsigned __int64 startva, unsigned __int64 len,
+             unsigned int *oldprot)
+{
+  unsigned int status;
+  unsigned __int64 retva;
+  unsigned __int64 retlen;
+
+  status = SYS$SETPRT_64 ((void *)startva, len, PSL$C_USER, PRT$C_UW,
+                          (void *)&retva, &retlen, oldprot);
+  return status;
+}
+
+/* Restore page rights.  */
+
+static void
+page_restore_rw (unsigned __int64 startva, unsigned __int64 len,
+                unsigned int prot)
+{
+  unsigned int status;
+  unsigned __int64 retva;
+  unsigned __int64 retlen;
+  unsigned int oldprot;
+
+  status = SYS$SETPRT_64 ((void *)startva, len, PSL$C_USER, prot,
+                          (void *)&retva, &retlen, &oldprot);
+  if (!(status & STS$M_SUCCESS))
+    LIB$SIGNAL (status);
+}
+
+/* Get the TEB (thread environment block).  */
+
+static pthread_t
+get_teb (void)
+{
+  return (pthread_t)__getReg (_IA64_REG_TP);
+}
+
+/* Enable thread scheduling if VAL is true.  */
+
+static unsigned int
+set_thread_scheduling (int val)
+{
+  struct dbgext_control_block blk;
+  unsigned int status;
+
+  if (!dbgext_func)
+    return 0;
+
+  blk.dbgext$w_function_code = DBGEXT$K_STOP_ALL_OTHER_TASKS;
+  blk.dbgext$w_facility_id = CMA$_FACILITY;
+  blk.dbgext$l_stop_value = val;
+
+  status = dbgext_func (&blk);
+  if (!(status & STS$M_SUCCESS))
+    {
+      TERM_FAO ("set_thread_scheduling error, val=!SL, status=!XL!/",
+		val, blk.dbgext$l_status);
+      lib$signal (status);
+    }
+
+  return blk.dbgext$l_stop_value;
+}
+
+/* Get next thead (after THR).  Start with 0.  */
+
+static unsigned int
+thread_next (unsigned int thr)
+{
+  struct dbgext_control_block blk;
+  unsigned int status;
+
+  if (!dbgext_func)
+    return 0;
+
+  blk.dbgext$w_function_code = DBGEXT$K_NEXT_TASK;
+  blk.dbgext$w_facility_id = CMA$_FACILITY;
+  blk.dbgext$l_ada_flags = 0;
+  blk.dbgext$l_task_value = thr;
+
+  status = dbgext_func (&blk);
+  if (!(status & STS$M_SUCCESS))
+    lib$signal (status);
+
+  return blk.dbgext$l_task_value;
+}
+
+/* Pthread Debug callbacks.  */
+
+static int
+read_callback (pthreadDebugClient_t context,
+	       pthreadDebugTargetAddr_t addr,
+	       pthreadDebugAddr_t buf,
+	       size_t size)
+{
+  if (trace_pthreaddbg)
+    TERM_FAO ("read_callback (!XH, !XH, !SL)!/", addr, buf, size);
+  ots$move (buf, size, addr);
+  return 0;
+}
+
+static int
+write_callback (pthreadDebugClient_t context,
+		pthreadDebugTargetAddr_t addr,
+		pthreadDebugLongConstAddr_t buf,
+		size_t size)
+{
+  if (trace_pthreaddbg)
+    TERM_FAO ("write_callback (!XH, !XH, !SL)!/", addr, buf, size);
+  ots$move (addr, size, buf);
+  return 0;
+}
+
+static int
+suspend_callback (pthreadDebugClient_t context)
+{
+  /* Always suspended.  */
+  return 0;
+}
+
+static int
+resume_callback (pthreadDebugClient_t context)
+{
+  /* So no need to resume.  */
+  return 0;
+}
+
+static int
+kthdinfo_callback (pthreadDebugClient_t context,
+		   pthreadDebugKId_t kid,
+		   pthreadDebugKThreadInfo_p thread_info)
+{
+  if (trace_pthreaddbg)
+    term_puts ("kthinfo_callback");
+  return ENOSYS;
+}
+
+static int
+hold_callback (pthreadDebugClient_t context,
+	       pthreadDebugKId_t kid)
+{
+  if (trace_pthreaddbg)
+    term_puts ("hold_callback");
+  return ENOSYS;
+}
+
+static int
+unhold_callback (pthreadDebugClient_t context,
+		 pthreadDebugKId_t kid)
+{
+  if (trace_pthreaddbg)
+    term_puts ("unhold_callback");
+  return ENOSYS;
+}
+
+static int
+getfreg_callback (pthreadDebugClient_t context,
+		  pthreadDebugFregs_t *reg,
+		  pthreadDebugKId_t kid)
+{
+  if (trace_pthreaddbg)
+    term_puts ("getfreg_callback");
+  return ENOSYS;
+}
+
+static int
+setfreg_callback (pthreadDebugClient_t context,
+		  const pthreadDebugFregs_t *reg,
+		  pthreadDebugKId_t kid)
+{
+  if (trace_pthreaddbg)
+    term_puts ("setfreg_callback");
+  return ENOSYS;
+}
+
+static int
+getreg_callback (pthreadDebugClient_t context,
+		 pthreadDebugRegs_t *reg,
+		 pthreadDebugKId_t kid)
+{
+  if (trace_pthreaddbg)
+    term_puts ("getreg_callback");
+  return ENOSYS;
+}
+
+static int
+setreg_callback (pthreadDebugClient_t context,
+		 const pthreadDebugRegs_t *reg,
+		 pthreadDebugKId_t kid)
+{
+  if (trace_pthreaddbg)
+    term_puts ("setreg_callback");
+  return ENOSYS;
+}
+
+static int
+output_callback (pthreadDebugClient_t context, 
+		 pthreadDebugConstString_t line)
+{
+  term_puts (line);
+  term_putnl ();
+  return 0;
+}
+
+static int
+error_callback (pthreadDebugClient_t context, 
+		 pthreadDebugConstString_t line)
+{
+  term_puts (line);
+  term_putnl ();
+  return 0;
+}
+
+static pthreadDebugAddr_t
+malloc_callback (pthreadDebugClient_t caller_context, size_t size)
+{
+  unsigned int status;
+  unsigned int res;
+  int len;
+
+  len = size + 16;
+  status = lib$get_vm (&len, &res, 0);
+  if (!(status & STS$M_SUCCESS))
+    LIB$SIGNAL (status);
+  if (trace_pthreaddbg)
+    TERM_FAO ("malloc_callback (!UL) -> !XA!/", size, res);
+  *(unsigned int *)res = len;
+  return (char *)res + 16;
+}
+
+static void
+free_callback (pthreadDebugClient_t caller_context, pthreadDebugAddr_t address)
+{
+  unsigned int status;
+  unsigned int res;
+  int len;
+
+  res = (unsigned int)address - 16;
+  len = *(unsigned int *)res;
+  if (trace_pthreaddbg)
+    TERM_FAO ("free_callback (!XA)!/", address);
+  status = lib$free_vm (&len, &res, 0);
+  if (!(status & STS$M_SUCCESS))
+    LIB$SIGNAL (status);
+}
+
+static int
+speckthd_callback (pthreadDebugClient_t caller_context,
+		   pthreadDebugSpecialType_t type,
+		   pthreadDebugKId_t *kernel_tid)
+{
+  return ENOTSUP;
+}
+
+static pthreadDebugCallbacks_t pthread_debug_callbacks = {
+  PTHREAD_DEBUG_VERSION,
+  read_callback,
+  write_callback,
+  suspend_callback,
+  resume_callback,
+  kthdinfo_callback,
+  hold_callback,
+  unhold_callback,
+  getfreg_callback,
+  setfreg_callback,
+  getreg_callback,
+  setreg_callback,
+  output_callback,
+  error_callback,
+  malloc_callback,
+  free_callback,
+  speckthd_callback
+};
+
+/* Name of the pthread shared library.  */
+static const $DESCRIPTOR (pthread_rtl_desc, "PTHREAD$RTL");
+
+/* List of symbols to extract from pthread debug library.  */
+struct pthread_debug_entry
+{
+  const unsigned int namelen;
+  const __char_ptr32 name;
+  __void_ptr32 func;
+};
+
+#define DEBUG_ENTRY(str) { sizeof(str) - 1, str, 0 }
+
+static struct pthread_debug_entry pthread_debug_entries[] = {
+  DEBUG_ENTRY("pthreadDebugContextInit"),
+  DEBUG_ENTRY("pthreadDebugThdSeqInit"),
+  DEBUG_ENTRY("pthreadDebugThdSeqNext"),
+  DEBUG_ENTRY("pthreadDebugThdSeqDestroy"),
+  DEBUG_ENTRY("pthreadDebugThdGetInfo"),
+  DEBUG_ENTRY("pthreadDebugThdGetInfoAddr"),
+  DEBUG_ENTRY("pthreadDebugThdGetReg"),
+  DEBUG_ENTRY("pthreadDebugCmd")
+};
+
+/* Pthread debug context.  */
+static pthreadDebugContext_t debug_context;
+
+/* Wrapper around pthread debug entry points.  */
+
+static int
+pthread_debug_thd_seq_init (pthreadDebugId_t *id)
+{
+  return ((int (*)())pthread_debug_entries[1].func)
+    (debug_context, id);
+}
+
+static int
+pthread_debug_thd_seq_next (pthreadDebugId_t *id)
+{
+  return ((int (*)())pthread_debug_entries[2].func)
+    (debug_context, id);
+}
+
+static int
+pthread_debug_thd_seq_destroy (void)
+{
+  return ((int (*)())pthread_debug_entries[3].func)
+    (debug_context);
+}
+
+static int
+pthread_debug_thd_get_info (pthreadDebugId_t id,
+			    pthreadDebugThreadInfo_t *info)
+{
+  return ((int (*)())pthread_debug_entries[4].func)
+    (debug_context, id, info);
+}
+
+static int
+pthread_debug_thd_get_info_addr (pthread_t thr,
+				 pthreadDebugThreadInfo_t *info)
+{
+  return ((int (*)())pthread_debug_entries[5].func)
+    (debug_context, thr, info);
+}
+
+static int
+pthread_debug_thd_get_reg (pthreadDebugId_t thr,
+			   pthreadDebugRegs_t *regs)
+{
+  return ((int (*)())pthread_debug_entries[6].func)
+    (debug_context, thr, regs);
+}
+
+static int
+stub_pthread_debug_cmd (const char *cmd)
+{
+  return ((int (*)())pthread_debug_entries[7].func)
+    (debug_context, cmd);
+}
+
+/* Show all the threads.  */
+
+static void
+threads_show (void)
+{
+  pthreadDebugId_t id;
+  pthreadDebugThreadInfo_t info;
+  int res;
+
+  res = pthread_debug_thd_seq_init (&id);
+  if (res != 0)
+    {
+      TERM_FAO ("seq init failed, res=!SL!/", res);
+      return;
+    }
+  while (1)
+    {
+      if (pthread_debug_thd_get_info (id, &info) != 0)
+	{
+	  TERM_FAO ("thd_get_info !SL failed!/", id);
+	  break;
+	}
+      if (pthread_debug_thd_seq_next (&id) != 0)
+	break;
+    }
+  pthread_debug_thd_seq_destroy ();
+}
+
+/* Initialize pthread support.  */
+
+static void
+threads_init (void)
+{
+  static const $DESCRIPTOR (dbgext_desc, "PTHREAD$DBGEXT");
+  static const $DESCRIPTOR (pthread_debug_desc, "PTHREAD$DBGSHR");
+  static const $DESCRIPTOR (dbgsymtable_desc, "PTHREAD_DBG_SYMTABLE");
+  int pthread_dbgext;
+  int status;
+  void *dbg_symtable;
+  int i;
+  void *caller_context = 0;
+
+  status = lib$find_image_symbol
+    ((void *) &pthread_rtl_desc, (void *) &dbgext_desc,
+     (int *) &dbgext_func);
+  if (!(status & STS$M_SUCCESS))
+    LIB$SIGNAL (status);
+  
+  status = lib$find_image_symbol
+    ((void *) &pthread_rtl_desc, (void *) &dbgsymtable_desc,
+     (int *) &dbg_symtable);
+  if (!(status & STS$M_SUCCESS))
+    LIB$SIGNAL (status);
+
+  /* Find entry points in pthread_debug.  */
+  for (i = 0;
+       i < sizeof (pthread_debug_entries) / sizeof (pthread_debug_entries[0]);
+       i++)
+    {
+      struct dsc$descriptor_s sym =
+	{ pthread_debug_entries[i].namelen,
+	  DSC$K_DTYPE_T, DSC$K_CLASS_S,
+	  pthread_debug_entries[i].name };
+      status = lib$find_image_symbol
+	((void *) &pthread_debug_desc, (void *) &sym,
+	 (int *) &pthread_debug_entries[i].func);
+      if (!(status & STS$M_SUCCESS))
+	lib$signal (status);
+    }
+
+  if (trace_pthreaddbg)
+    TERM_FAO ("debug symtable: !XH!/", dbg_symtable);
+  status = ((int (*)()) pthread_debug_entries[0].func)
+    (&caller_context, &pthread_debug_callbacks, dbg_symtable, &debug_context);
+  if (status != 0)
+    TERM_FAO ("cannot initialize pthread_debug: !UL!/", status);
+  TERM_FAO ("pthread debug done!/", 0);
+}
+
+/* Convert an hexadecimal character to a nibble.  Return -1 in case of
+   error.  */
+
+static int
+hex2nibble (unsigned char h)
+{
+  if (h >= '0' && h <= '9')
+    return h - '0';
+  if (h >= 'A' && h <= 'F')
+    return h - 'A' + 10;
+  if (h >= 'a' && h <= 'f')
+    return h - 'a' + 10;
+  return -1;
+}
+
+/* Convert an hexadecimal 2 character string to a byte.  Return -1 in case
+   of error.  */
+
+static int
+hex2byte (const unsigned char *p)
+{
+  int h, l;
+
+  h = hex2nibble (p[0]);
+  l = hex2nibble (p[1]);
+  if (h == -1 || l == -1)
+    return -1;
+  return (h << 4) | l;
+}
+
+/* Convert a byte V to a 2 character strings P.  */
+
+static void
+byte2hex (unsigned char *p, unsigned char v)
+{
+  p[0] = hex[v >> 4];
+  p[1] = hex[v & 0xf];
+}
+
+/* Convert a quadword V to a 16 character strings P.  */
+
+static void
+quad2hex (unsigned char *p, unsigned __int64 v)
+{
+  int i;
+  for (i = 0; i < 16; i++)
+    {
+      p[i] = hex[v >> 60];
+      v <<= 4;
+    }
+}
+
+static void
+long2pkt (unsigned int v)
+{
+  int i;
+
+  for (i = 0; i < 8; i++)
+    {
+      gdb_buf[gdb_blen + i] = hex[(v >> 28) & 0x0f];
+      v <<= 4;
+    }
+  gdb_blen += 8;
+}
+
+/* Generate an error packet.  */
+
+static void
+packet_error (unsigned int err)
+{
+  gdb_buf[1] = 'E';
+  byte2hex (gdb_buf + 2, err);
+  gdb_blen = 4;
+}
+
+/* Generate an OK packet.  */
+
+static void
+packet_ok (void)
+{
+  gdb_buf[1] = 'O';
+  gdb_buf[2] = 'K';
+  gdb_blen = 3;
+}
+
+/* Append a register to the packet.  */
+
+static void
+ireg2pkt (const unsigned char *p)
+{
+  int i;
+
+  for (i = 0; i < 8; i++)
+    {
+      byte2hex (gdb_buf + gdb_blen, p[i]);
+      gdb_blen += 2;
+    }
+}
+
+/* Append a C string (ASCIZ) to the packet.  */
+
+static void
+str2pkt (const char *str)
+{
+  while (*str)
+    gdb_buf[gdb_blen++] = *str++;
+}
+
+/* Extract a number fro the packet.  */
+
+static unsigned __int64
+pkt2val (const unsigned char *pkt, unsigned int *pos)
+{
+  unsigned __int64 res = 0;
+  unsigned int i;
+
+  while (1)
+    {
+      int r = hex2nibble (pkt[*pos]);
+
+      if (r < 0)
+        return res;
+      res = (res << 4) | r;
+      (*pos)++;
+    }
+}
+
+/* Append LEN bytes from B to the current gdb packet (encode in binary).  */
+
+static void
+mem2bin (const unsigned char *b, unsigned int len)
+{
+  unsigned int i;
+  for (i = 0; i < len; i++)
+    switch (b[i])
+      {
+      case '#':
+      case '$':
+      case '}':
+      case '*':
+      case 0:
+        gdb_buf[gdb_blen++] = '}';
+        gdb_buf[gdb_blen++] = b[i] ^ 0x20;
+        break;
+      default:
+        gdb_buf[gdb_blen++] = b[i];
+        break;
+      }
+}
+
+/* Append LEN bytes from B to the current gdb packet (encode in hex).  */
+
+static void
+mem2hex (const unsigned char *b, unsigned int len)
+{
+  unsigned int i;
+  for (i = 0; i < len; i++)
+    {
+      byte2hex (gdb_buf + gdb_blen, b[i]);
+      gdb_blen += 2;
+    }
+}
+
+/* Handle the 'q' packet.  */
+
+static void
+handle_q_packet (const unsigned char *pkt, unsigned int pktlen)
+{
+  /* For qfThreadInfo and qsThreadInfo.  */
+  static unsigned int first_thread;
+  static unsigned int last_thread;
+
+  static const char xfer_uib[] = "qXfer:uib:read:";
+#define XFER_UIB_LEN (sizeof (xfer_uib) - 1)
+  static const char qfthreadinfo[] = "qfThreadInfo";
+#define QFTHREADINFO_LEN (sizeof (qfthreadinfo) - 1)
+  static const char qsthreadinfo[] = "qsThreadInfo";
+#define QSTHREADINFO_LEN (sizeof (qsthreadinfo) - 1)
+  static const char qthreadextrainfo[] = "qThreadExtraInfo,";
+#define QTHREADEXTRAINFO_LEN (sizeof (qthreadextrainfo) - 1)
+  static const char qsupported[] = "qSupported:";
+#define QSUPPORTED_LEN (sizeof (qsupported) - 1)
+
+  if (pktlen == 2 && pkt[1] == 'C')
+    {
+      /* Current thread.  */
+      gdb_buf[0] = '$';
+      gdb_buf[1] = 'Q';
+      gdb_buf[2] = 'C';
+      gdb_blen = 3;
+      if (has_threads)
+	long2pkt ((unsigned long) get_teb ());
+      return;
+    }
+  else if (pktlen > XFER_UIB_LEN
+      && ots$strcmp_eql (pkt, XFER_UIB_LEN, xfer_uib, XFER_UIB_LEN))
+    {
+      /* Get unwind information block.  */
+      unsigned __int64 pc;
+      unsigned int pos = XFER_UIB_LEN;
+      unsigned int off;
+      unsigned int len;
+      union
+      {
+	unsigned char bytes[32];
+	struct
+	{
+	  unsigned __int64 code_start_va;
+	  unsigned __int64 code_end_va;
+	  unsigned __int64 uib_start_va;
+	  unsigned __int64 gp_value;
+	} data;
+      } uei;
+      int res;
+      int i;
+
+      packet_error (0);
+
+      pc = pkt2val (pkt, &pos);
+      if (pkt[pos] != ':')
+        return;
+      pos++;
+      off = pkt2val (pkt, &pos);
+      if (pkt[pos] != ',' || off != 0)
+        return;
+      pos++;
+      len = pkt2val (pkt, &pos);
+      if (pkt[pos] != '#' || len != 0x20)
+        return;
+
+      res = SYS$GET_UNWIND_ENTRY_INFO (pc, &uei.data, 0);
+      if (res == SS$_NODATA || res != SS$_NORMAL)
+        ots$fill (uei.bytes, sizeof (uei.bytes), 0);
+
+      if (trace_unwind)
+	{
+	  TERM_FAO ("Unwind request for !XH, status=!XL, uib=!XQ, GP=!XQ!/",
+		    pc, res, uei.data.uib_start_va, uei.data.gp_value);
+	}
+
+      gdb_buf[0] = '$';
+      gdb_buf[1] = 'l';
+      gdb_blen = 2;
+      mem2bin (uei.bytes, sizeof (uei.bytes));
+    }
+  else if (pktlen == QFTHREADINFO_LEN
+	   && ots$strcmp_eql (pkt, QFTHREADINFO_LEN,
+			      qfthreadinfo, QFTHREADINFO_LEN))
+    {
+      /* Get first thread(s).  */
+      gdb_buf[0] = '$';
+      gdb_buf[1] = 'm';
+      gdb_blen = 2;
+
+      if (!has_threads)
+	{
+	  gdb_buf[1] = 'l';
+	  return;
+	}
+      first_thread = thread_next (0);
+      last_thread = first_thread;
+      long2pkt (first_thread);
+    }
+  else if (pktlen == QSTHREADINFO_LEN
+	   && ots$strcmp_eql (pkt, QSTHREADINFO_LEN,
+			      qsthreadinfo, QSTHREADINFO_LEN))
+    {
+      /* Get subsequent threads.  */
+      gdb_buf[0] = '$';
+      gdb_buf[1] = 'm';
+      gdb_blen = 2;
+      while (dbgext_func)
+	{
+	  unsigned int res;
+	  res = thread_next (last_thread);
+	  if (res == first_thread)
+	    break;
+	  if (gdb_blen > 2)
+	    gdb_buf[gdb_blen++] = ',';
+	  long2pkt (res);
+	  last_thread = res;
+	  if (gdb_blen > sizeof (gdb_buf) - 16)
+	    break;
+	}
+
+      if (gdb_blen == 2)
+	gdb_buf[1] = 'l';
+    }
+  else if (pktlen > QTHREADEXTRAINFO_LEN
+	   && ots$strcmp_eql (pkt, QTHREADEXTRAINFO_LEN,
+			      qthreadextrainfo, QTHREADEXTRAINFO_LEN))
+    {
+      /* Get extra info about a thread.  */
+      pthread_t thr;
+      unsigned int pos = QTHREADEXTRAINFO_LEN;
+      pthreadDebugThreadInfo_t info;
+      int res;
+
+      packet_error (0);
+      if (!has_threads)
+	return;
+
+      thr = (pthread_t) pkt2val (pkt, &pos);
+      if (pkt[pos] != '#')
+        return;
+      res = pthread_debug_thd_get_info_addr (thr, &info);
+      if (res != 0)
+	{
+	  TERM_FAO ("qThreadExtraInfo (!XH) failed: !SL!/", thr, res);
+	  return;
+	}
+      gdb_buf[0] = '$';
+      gdb_blen = 1;
+      mem2hex ((const unsigned char *)"VMS-thread", 11);
+    }
+  else if (pktlen > QSUPPORTED_LEN
+	   && ots$strcmp_eql (pkt, QSUPPORTED_LEN,
+			      qsupported, QSUPPORTED_LEN))
+    {
+      /* Get supported features.  */
+      pthread_t thr;
+      unsigned int pos = QSUPPORTED_LEN;
+      pthreadDebugThreadInfo_t info;
+      int res;
+      
+      /* Ignore gdb features.  */
+      gdb_buf[0] = '$';
+      gdb_blen = 1;
+
+      str2pkt ("qXfer:uib:read+");
+      return;
+    }
+  else
+    {
+      if (trace_pkt)
+	{
+	  term_puts ("unknown <: ");
+	  term_write ((char *)pkt, pktlen);
+	  term_putnl ();
+	}
+      return;
+    }
+}
+
+/* Handle the 'v' packet.  */
+
+static int
+handle_v_packet (const unsigned char *pkt, unsigned int pktlen)
+{
+  static const char vcontq[] = "vCont?";
+#define VCONTQ_LEN (sizeof (vcontq) - 1)
+
+  if (pktlen == VCONTQ_LEN
+      && ots$strcmp_eql (pkt, VCONTQ_LEN, vcontq, VCONTQ_LEN))
+    {
+      gdb_buf[0] = '$';
+      gdb_blen = 1;
+
+      str2pkt ("vCont;c;s");
+      return 0;
+    }
+  else
+    {
+      if (trace_pkt)
+	{
+	  term_puts ("unknown <: ");
+	  term_write ((char *)pkt, pktlen);
+	  term_putnl ();
+	}
+      return 0;
+    }
+}
+
+/* Get regs for the selected thread.  */
+
+static struct ia64_all_regs *
+get_selected_regs (void)
+{
+  pthreadDebugRegs_t regs;
+  int res;
+
+  if (selected_thread == 0 || selected_thread == get_teb ())
+    return &excp_regs;
+
+  if (selected_thread == sel_regs_pthread)
+    return &sel_regs;
+
+  /* Read registers.  */
+  res = pthread_debug_thd_get_reg (selected_id, &regs);
+  if (res != 0)
+    {
+      /* FIXME: return NULL ?  */
+      return &excp_regs;
+    }
+  sel_regs_pthread = selected_thread;
+  sel_regs.gr[1].v = regs.gp;
+  sel_regs.gr[4].v = regs.r4;
+  sel_regs.gr[5].v = regs.r5;
+  sel_regs.gr[6].v = regs.r6;
+  sel_regs.gr[7].v = regs.r7;
+  sel_regs.gr[12].v = regs.sp;
+  sel_regs.br[0].v = regs.rp;
+  sel_regs.br[1].v = regs.b1;
+  sel_regs.br[2].v = regs.b2;
+  sel_regs.br[3].v = regs.b3;
+  sel_regs.br[4].v = regs.b4;
+  sel_regs.br[5].v = regs.b5;
+  sel_regs.ip.v = regs.ip;
+  sel_regs.bsp.v = regs.bspstore; /* FIXME: it is correct ?  */
+  sel_regs.pfs.v = regs.pfs;
+  sel_regs.pr.v = regs.pr;
+  return &sel_regs;
+}
+
+/* Create a status packet.  */
+
+static void
+packet_status (void)
+{
+  gdb_blen = 0;
+  if (has_threads)
+    {
+      str2pkt ("$T05thread:");
+      long2pkt ((unsigned long) get_teb ());
+      gdb_buf[gdb_blen++] = ';';
+    }
+  else
+    str2pkt ("$S05");
+}
+
+/* Return 1 to continue.  */
+
+static int
+handle_packet (unsigned char *pkt, unsigned int len)
+{
+  unsigned int pos;
+
+  /* By default, reply unsupported.  */
+  gdb_buf[0] = '$';
+  gdb_blen = 1;
+
+  pos = 1;
+  switch (pkt[0])
+    {
+    case '?':
+      if (len == 1)
+        {
+	  packet_status ();
+          return 0;
+        }
+      break;
+    case 'c':
+      if (len == 1)
+        {
+          /* Clear psr.ss.  */
+          excp_regs.psr.v &= ~(unsigned __int64)PSR$M_SS;
+          return 1;
+        }
+      else
+        packet_error (0);
+      break;
+    case 'g':
+      if (len == 1)
+        {
+          unsigned int i;
+	  struct ia64_all_regs *regs = get_selected_regs ();
+          unsigned char *p = regs->gr[0].b;
+
+          for (i = 0; i < 8 * 32; i++)
+            byte2hex (gdb_buf + 1 + 2 * i, p[i]);
+          gdb_blen += 2 * 8 * 32;
+          return 0;
+        }
+      break;
+    case 'H':
+      if (pkt[1] == 'g')
+	{
+	  int res;
+	  unsigned __int64 val;
+	  pthreadDebugThreadInfo_t info;
+	  
+	  pos++;
+	  val = pkt2val (pkt, &pos);
+	  if (pos != len)
+	    {
+	      packet_error (0);
+	      return 0;
+	    }
+	  if (val == 0)
+	    {
+	      /* Default one.  */
+	      selected_thread = get_teb ();
+	      selected_id = 0;
+	    }
+	  else if (!has_threads)
+	    {
+	      packet_error (0);
+	      return 0;
+	    }
+	  else
+	    {
+	      res = pthread_debug_thd_get_info_addr ((pthread_t) val, &info);
+	      if (res != 0)
+		{
+		  TERM_FAO ("qThreadExtraInfo (!XH) failed: !SL!/", val, res);
+		  packet_error (0);
+		  return 0;
+		}
+	      selected_thread = info.teb;
+	      selected_id = info.sequence;
+	    }
+	  packet_ok ();
+	  break;
+	}
+      else if (pkt[1] == 'c'
+	       && ((pkt[2] == '-' && pkt[3] == '1' && len == 4)
+		   || (pkt[2] == '0' && len == 3)))
+	{
+	  /* Silently accept 'Hc0' and 'Hc-1'.  */
+	  packet_ok ();
+	  break;
+	}
+      else
+	{
+	  packet_error (0);
+	  return 0;
+	}
+    case 'k':
+      SYS$EXIT (SS$_NORMAL);
+      break;
+    case 'm':
+      {
+        unsigned __int64 addr;
+	unsigned __int64 paddr;
+        unsigned int l;
+        unsigned int i;
+
+        addr = pkt2val (pkt, &pos);
+        if (pkt[pos] != ',')
+          {
+            packet_error (0);
+            return 0;
+          }
+        pos++;
+        l = pkt2val (pkt, &pos);
+        if (pkt[pos] != '#')
+          {
+            packet_error (0);
+            return 0;
+          }
+
+	/* Check access.  */
+	i = l + (addr & VMS_PAGE_MASK);
+	paddr = addr & ~VMS_PAGE_MASK;
+	while (1)
+	  {
+	    if (__prober (paddr, 0) != 1)
+	      {
+		packet_error (2);
+		return 0;
+	      }
+	    if (i < VMS_PAGE_SIZE)
+	      break;
+	    i -= VMS_PAGE_SIZE;
+	    paddr += VMS_PAGE_SIZE;
+	  }
+
+	/* Transfer.  */
+	for (i = 0; i < l; i++)
+	  byte2hex (gdb_buf + 1 + 2 * i, ((unsigned char *)addr)[i]);
+	gdb_blen += 2 * l;
+      }
+      break;
+    case 'M':
+      {
+        unsigned __int64 addr;
+        unsigned __int64 paddr;
+        unsigned int l;
+        unsigned int i;
+        unsigned int oldprot;
+
+        addr = pkt2val (pkt, &pos);
+        if (pkt[pos] != ',')
+          {
+            packet_error (0);
+            return 0;
+          }
+        pos++;
+        l = pkt2val (pkt, &pos);
+        if (pkt[pos] != ':')
+          {
+            packet_error (0);
+            return 0;
+          }
+        pos++;
+        page_set_rw (addr, l, &oldprot);
+
+	/* Check access.  */
+	i = l + (addr & VMS_PAGE_MASK);
+	paddr = addr & ~VMS_PAGE_MASK;
+	while (1)
+	  {
+	    if (__probew (paddr, 0) != 1)
+	      {
+		page_restore_rw (addr, l, oldprot);
+		return 0;
+	      }
+	    if (i < VMS_PAGE_SIZE)
+	      break;
+	    i -= VMS_PAGE_SIZE;
+	    paddr += VMS_PAGE_SIZE;
+	  }
+
+	/* Write.  */
+        for (i = 0; i < l; i++)
+          {
+            int v = hex2byte (pkt + pos);
+            pos += 2;
+            ((unsigned char *)addr)[i] = v;
+          }
+
+	/* Sync caches.  */
+        for (i = 0; i < l; i += 15)
+          __fc (addr + i);
+        __fc (addr + l);
+
+        page_restore_rw (addr, l, oldprot);
+        packet_ok ();
+      }
+      break;
+    case 'p':
+      {
+        unsigned int num = 0;
+        unsigned int i;
+	struct ia64_all_regs *regs = get_selected_regs ();
+
+        num = pkt2val (pkt, &pos);
+        if (pos != len)
+          {
+            packet_error (0);
+            return 0;
+          }
+
+        switch (num)
+          {
+          case IA64_IP_REGNUM:
+            ireg2pkt (regs->ip.b);
+            break;
+          case IA64_BR0_REGNUM:
+            ireg2pkt (regs->br[0].b);
+            break;
+          case IA64_PSR_REGNUM:
+            ireg2pkt (regs->psr.b);
+            break;
+          case IA64_BSP_REGNUM:
+            ireg2pkt (regs->bsp.b);
+            break;
+          case IA64_CFM_REGNUM:
+            ireg2pkt (regs->cfm.b);
+            break;
+          case IA64_PFS_REGNUM:
+            ireg2pkt (regs->pfs.b);
+            break;
+          case IA64_PR_REGNUM:
+            ireg2pkt (regs->pr.b);
+            break;
+          default:
+            TERM_FAO ("gdbserv: unhandled reg !UW!/", num);
+            packet_error (0);
+            return 0;
+          }
+      }
+      break;
+    case 'q':
+      handle_q_packet (pkt, len);
+      break;
+    case 's':
+      if (len == 1)
+        {
+          /* Set psr.ss.  */
+          excp_regs.psr.v |= (unsigned __int64)PSR$M_SS;
+          return 1;
+        }
+      else
+        packet_error (0);
+      break;
+    case 'T':
+      /* Thread status.  */
+      if (!has_threads)
+	{
+	  packet_ok ();
+	  break;
+	}
+      else
+	{
+	  int res;
+	  unsigned __int64 val;
+	  unsigned int fthr, thr;
+	  
+	  val = pkt2val (pkt, &pos);
+	  /* Default is error (but only after parsing is complete).  */
+	  packet_error (0);
+	  if (pos != len)
+	    break;
+
+	  /* Follow the list.  This makes a O(n2) algorithm, but we don't really
+	     have the choice.  Note that pthread_debug_thd_get_info_addr
+	     doesn't look reliable.  */
+	  fthr = thread_next (0);
+	  thr = fthr;
+	  do
+	    {
+	      if (val == thr)
+		{
+		  packet_ok ();
+		  break;
+		}
+	      thr = thread_next (thr);
+	    }
+	  while (thr != fthr);
+	}
+      break;
+    case 'v':
+      return handle_v_packet (pkt, len);
+      break;
+    case 'V':
+      if (len > 3 && pkt[1] == 'M' && pkt[2] == 'S' && pkt[3] == ' ')
+	{
+	  /* Temporary extension.  */
+	  if (has_threads)
+	    {
+	      pkt[len] = 0;
+	      stub_pthread_debug_cmd ((char *)pkt + 4);
+	      packet_ok ();
+	    }
+	  else
+	    packet_error (0);
+	}
+      break;
+    default:
+      if (trace_pkt)
+	{
+	  term_puts ("unknown <: ");
+	  term_write ((char *)pkt, len);
+	  term_putnl ();
+	}
+      break;
+    }
+  return 0;
+}
+
+/* Raw write to gdb.  */
+
+static void
+sock_write (const unsigned char *buf, int len)
+{
+  struct _iosb iosb;
+  unsigned int status;
+
+  /* Write data to connection.  */
+  status = sys$qiow (EFN$C_ENF,           /* Event flag.  */
+                     conn_channel,        /* I/O channel.  */
+                     IO$_WRITEVBLK,       /* I/O function code.  */
+                     &iosb,               /* I/O status block.  */
+                     0,                   /* Ast service routine.  */
+                     0,                   /* Ast parameter.  */
+                     (char *)buf,         /* P1 - buffer address.  */
+                     len,                 /* P2 - buffer length.  */
+                     0, 0, 0, 0);
+  if (status & STS$M_SUCCESS)
+    status = iosb.iosb$w_status;
+  if (!(status & STS$M_SUCCESS))
+    {
+      term_puts ("Failed to write data to gdb\n");
+      LIB$SIGNAL (status);
+    }
+}
+
+/* Compute the cheksum and send the packet.  */
+
+static void
+send_pkt (void)
+{
+  unsigned char chksum = 0;
+  unsigned int i;
+
+  for (i = 1; i < gdb_blen; i++)
+    chksum += gdb_buf[i];
+
+  gdb_buf[gdb_blen] = '#';
+  byte2hex (gdb_buf + gdb_blen + 1, chksum);
+
+  sock_write (gdb_buf, gdb_blen + 3);
+
+  if (trace_pkt > 1)
+    {
+      term_puts (">: ");
+      term_write ((char *)gdb_buf, gdb_blen + 3);
+      term_putnl ();
+    }
+}
+
+/* Read and handle one command.  Return 1 is execution must resume.  */
+
+static int
+one_command (void)
+{
+  struct _iosb iosb;
+  unsigned int status;
+  unsigned int off;
+  unsigned int dollar_off = 0;
+  unsigned int sharp_off = 0;
+  unsigned int cmd_off;
+  unsigned int cmd_len;
+
+  /* Wait for a packet.  */
+  while (1)
+    {
+      off = 0;
+      while (1)
+        {
+          /* Read data from connection.  */
+          status = sys$qiow (EFN$C_ENF,           /* Event flag.  */
+                             conn_channel,        /* I/O channel.  */
+                             IO$_READVBLK,        /* I/O function code.  */
+                             &iosb,               /* I/O status block.  */
+                             0,                   /* Ast service routine.  */
+                             0,                   /* Ast parameter.  */
+                             gdb_buf + off,       /* P1 - buffer address.  */
+                             sizeof (gdb_buf) - off, /* P2 - buffer leng.  */
+                             0, 0, 0, 0);
+          if (status & STS$M_SUCCESS)
+            status = iosb.iosb$w_status;
+          if (!(status & STS$M_SUCCESS))
+            {
+              term_puts ("Failed to read data from connection\n" );
+              LIB$SIGNAL (status);
+            }
+
+#ifdef RAW_DUMP
+          term_puts ("{: ");
+          term_write ((char *)gdb_buf + off, iosb.iosb$w_bcnt);
+          term_putnl ();
+#endif
+
+          gdb_blen = off + iosb.iosb$w_bcnt;
+
+          if (off == 0)
+            {
+              /* Search for '$'.  */
+              for (dollar_off = 0; dollar_off < gdb_blen; dollar_off++)
+                if (gdb_buf[dollar_off] == '$')
+                  break;
+              if (dollar_off >= gdb_blen)
+                {
+                  /* Not found, discard the data.  */
+                  off = 0;
+                  continue;
+                }
+              /* Search for '#'.  */
+              for (sharp_off = dollar_off + 1;
+		   sharp_off < gdb_blen;
+		   sharp_off++)
+                if (gdb_buf[sharp_off] == '#')
+                  break;
+            }
+          else if (sharp_off >= off)
+            {
+              /* Search for '#'.  */
+              for (; sharp_off < gdb_blen; sharp_off++)
+                if (gdb_buf[sharp_off] == '#')
+                  break;
+            }
+
+          /* Got packet with checksum.  */
+          if (sharp_off + 2 <= gdb_blen)
+            break;
+
+          off = gdb_blen;
+          if (gdb_blen == sizeof (gdb_buf))
+            {
+              /* Packet too large, discard.  */
+              off = 0;
+            }
+        }
+
+      /* Validate and acknowledge a packet.  */
+      {
+        unsigned char chksum = 0;
+        unsigned int i;
+        int v;
+
+        for (i = dollar_off + 1; i < sharp_off; i++)
+          chksum += gdb_buf[i];
+        v = hex2byte (gdb_buf + sharp_off + 1);
+        if (v != chksum)
+          {
+            term_puts ("Discard bad checksum packet\n");
+            continue;
+          }
+        else
+          {
+            sock_write ((const unsigned char *)"+", 1);
+            break;
+          }
+      }
+    }
+
+  if (trace_pkt > 1)
+    {
+      term_puts ("<: ");
+      term_write ((char *)gdb_buf + dollar_off, sharp_off - dollar_off + 1);
+      term_putnl ();
+    }
+
+  cmd_off = dollar_off + 1;
+  cmd_len = sharp_off - dollar_off - 1;
+
+  if (handle_packet (gdb_buf + dollar_off + 1, sharp_off - dollar_off - 1) == 1)
+    return 1;
+
+  send_pkt ();
+  return 0;
+}
+
+/* Display the condition given by SIG64.  */
+
+static void
+display_excp (struct chf64$signal_array *sig64, struct chf$mech_array *mech)
+{
+  unsigned int status;
+  char msg[160];
+  unsigned short msglen;
+  $DESCRIPTOR (msg_desc, msg);
+  unsigned char outadr[4];
+
+  status = SYS$GETMSG (sig64->chf64$q_sig_name, &msglen, &msg_desc, 0, outadr);
+  if (status & STS$M_SUCCESS)
+    {
+      char msg2[160];
+      unsigned short msg2len;
+      struct dsc$descriptor_s msg2_desc =
+        { sizeof (msg2), DSC$K_DTYPE_T, DSC$K_CLASS_S, msg2};
+      msg_desc.dsc$w_length = msglen;
+      status = SYS$FAOL_64 (&msg_desc, &msg2len, &msg2_desc,
+                            &sig64->chf64$q_sig_arg1);
+      if (status & STS$M_SUCCESS)
+        term_write (msg2, msg2len);
+    }
+  else
+    term_puts ("no message");
+  term_putnl ();
+
+  if (trace_excp > 1)
+    {
+      TERM_FAO (" Frame: !XH, Depth: !4SL, Esf: !XH!/",
+		mech->chf$q_mch_frame, mech->chf$q_mch_depth,
+		mech->chf$q_mch_esf_addr);
+    }
+}
+
+/* Get all registers from current thread.  */
+
+static void
+read_all_registers (struct chf$mech_array *mech)
+{
+  struct _intstk *intstk =
+    (struct _intstk *)mech->chf$q_mch_esf_addr;
+  struct chf64$signal_array *sig64 =
+    (struct chf64$signal_array *)mech->chf$ph_mch_sig64_addr;
+  unsigned int cnt = sig64->chf64$w_sig_arg_count;
+  unsigned __int64 pc = (&sig64->chf64$q_sig_name)[cnt - 2];
+
+  excp_regs.ip.v = pc;
+  excp_regs.psr.v = intstk->intstk$q_ipsr;
+  /* GDB and linux expects bsp to point after the current register frame.
+     Adjust.  */
+  {
+    unsigned __int64 bsp = intstk->intstk$q_bsp;
+    unsigned int sof = intstk->intstk$q_ifs & 0x7f;
+    unsigned int delta = ((bsp >> 3) & 0x3f) + sof;
+    excp_regs.bsp.v = bsp + ((sof + delta / 0x3f) << 3);
+  }
+  excp_regs.cfm.v = intstk->intstk$q_ifs & 0x3fffffffff;
+  excp_regs.pfs.v = intstk->intstk$q_pfs;
+  excp_regs.pr.v = intstk->intstk$q_preds;
+  excp_regs.gr[0].v = 0;
+  excp_regs.gr[1].v = intstk->intstk$q_gp;
+  excp_regs.gr[2].v = intstk->intstk$q_r2;
+  excp_regs.gr[3].v = intstk->intstk$q_r3;
+  excp_regs.gr[4].v = intstk->intstk$q_r4;
+  excp_regs.gr[5].v = intstk->intstk$q_r5;
+  excp_regs.gr[6].v = intstk->intstk$q_r6;
+  excp_regs.gr[7].v = intstk->intstk$q_r7;
+  excp_regs.gr[8].v = intstk->intstk$q_r8;
+  excp_regs.gr[9].v = intstk->intstk$q_r9;
+  excp_regs.gr[10].v = intstk->intstk$q_r10;
+  excp_regs.gr[11].v = intstk->intstk$q_r11;
+  excp_regs.gr[12].v = (unsigned __int64)intstk + intstk->intstk$l_stkalign;
+  excp_regs.gr[13].v = intstk->intstk$q_r13;
+  excp_regs.gr[14].v = intstk->intstk$q_r14;
+  excp_regs.gr[15].v = intstk->intstk$q_r15;
+  excp_regs.gr[16].v = intstk->intstk$q_r16;
+  excp_regs.gr[17].v = intstk->intstk$q_r17;
+  excp_regs.gr[18].v = intstk->intstk$q_r18;
+  excp_regs.gr[19].v = intstk->intstk$q_r19;
+  excp_regs.gr[20].v = intstk->intstk$q_r20;
+  excp_regs.gr[21].v = intstk->intstk$q_r21;
+  excp_regs.gr[22].v = intstk->intstk$q_r22;
+  excp_regs.gr[23].v = intstk->intstk$q_r23;
+  excp_regs.gr[24].v = intstk->intstk$q_r24;
+  excp_regs.gr[25].v = intstk->intstk$q_r25;
+  excp_regs.gr[26].v = intstk->intstk$q_r26;
+  excp_regs.gr[27].v = intstk->intstk$q_r27;
+  excp_regs.gr[28].v = intstk->intstk$q_r28;
+  excp_regs.gr[29].v = intstk->intstk$q_r29;
+  excp_regs.gr[30].v = intstk->intstk$q_r30;
+  excp_regs.gr[31].v = intstk->intstk$q_r31;
+  excp_regs.br[0].v = intstk->intstk$q_b0;
+  excp_regs.br[1].v = intstk->intstk$q_b1;
+  excp_regs.br[2].v = intstk->intstk$q_b2;
+  excp_regs.br[3].v = intstk->intstk$q_b3;
+  excp_regs.br[4].v = intstk->intstk$q_b4;
+  excp_regs.br[5].v = intstk->intstk$q_b5;
+  excp_regs.br[6].v = intstk->intstk$q_b6;
+  excp_regs.br[7].v = intstk->intstk$q_b7;
+}
+
+/* Write all registers to current thread.  FIXME: not yet complete.  */
+
+static void
+write_all_registers (struct chf$mech_array *mech)
+{
+  struct _intstk *intstk =
+    (struct _intstk *)mech->chf$q_mch_esf_addr;
+
+  intstk->intstk$q_ipsr = excp_regs.psr.v;
+}
+
+/* Do debugging.  Report status to gdb and execute commands.  */
+
+static void
+do_debug (struct chf$mech_array *mech)
+{
+  struct _intstk *intstk =
+    (struct _intstk *)mech->chf$q_mch_esf_addr;
+  unsigned int old_ast;
+  unsigned int old_sch;
+  unsigned int status;
+
+  /* Disable ast.  */
+  status = sys$setast (0);
+  switch (status)
+    {
+    case SS$_WASCLR:
+      old_ast = 0;
+      break;
+    case SS$_WASSET:
+      old_ast = 1;
+      break;
+    default:
+      /* Should never happen!  */
+      lib$signal (status);
+    }
+
+  /* Disable thread scheduling.  */
+  if (has_threads)
+    old_sch = set_thread_scheduling (0);
+
+  read_all_registers (mech);
+
+  /* Send stop reply packet.  */
+  packet_status ();
+  send_pkt ();
+
+  while (one_command () == 0)
+    ;
+
+  write_all_registers (mech);
+
+  /* Re-enable scheduling.  */
+  if (has_threads)
+    set_thread_scheduling (old_sch);
+
+  /* Re-enable AST.  */
+  status = sys$setast (old_ast);
+  if (!(status & STS$M_SUCCESS))
+    LIB$SIGNAL (status);
+}
+
+/* The condition handler.  That's the core of the stub.  */
+
+static int
+excp_handler (struct chf$signal_array *sig,
+              struct chf$mech_array *mech)
+{
+  struct chf64$signal_array *sig64 =
+    (struct chf64$signal_array *)mech->chf$ph_mch_sig64_addr;
+  unsigned int code = sig->chf$l_sig_name & STS$M_COND_ID;
+  unsigned int cnt = sig64->chf64$w_sig_arg_count;
+  unsigned __int64 pc;
+  unsigned int ret;
+  /* Self protection.  FIXME: Should be per thread ?  */
+  static int in_handler = 0;
+
+  /* Completly ignore some conditions (signaled indirectly by this stub).  */
+  switch (code)
+    {
+    case LIB$_KEYNOTFOU & STS$M_COND_ID:
+      return SS$_RESIGNAL_64;
+    default:
+      break;
+    }
+
+  /* Protect against recursion.  */
+  in_handler++;
+  if (in_handler > 1)
+    {
+      if (in_handler == 2)
+	TERM_FAO ("gdbstub: exception in handler (pc=!XH)!!!/",
+		  (&sig64->chf64$q_sig_name)[cnt - 2]);
+      sys$exit (sig->chf$l_sig_name);
+    }
+
+  pc = (&sig64->chf64$q_sig_name)[cnt - 2];
+  if (trace_excp)
+    TERM_FAO ("excp_handler: code: !XL, pc=!XH!/", code, pc);
+
+  /* If break on the entry point, restore the bundle.  */
+  if (code == (SS$_BREAK & STS$M_COND_ID)
+      && pc == entry_pc
+      && entry_pc != 0)
+    {
+      static unsigned int entry_prot;
+
+      if (trace_entry)
+        term_puts ("initial entry breakpoint\n");
+      page_set_rw (entry_pc, 16, &entry_prot);
+
+      ots$move ((void *)entry_pc, 16, entry_saved);
+      __fc (entry_pc);
+      page_restore_rw (entry_pc, 16, entry_prot);
+    }
+
+  switch (code)
+    {
+    case SS$_ACCVIO & STS$M_COND_ID:
+      if (trace_excp <= 1)
+        display_excp (sig64, mech);
+      /* Fall through.  */
+    case SS$_BREAK  & STS$M_COND_ID:
+    case SS$_OPCDEC & STS$M_COND_ID:
+    case SS$_TBIT   & STS$M_COND_ID:
+    case SS$_DEBUG  & STS$M_COND_ID:
+      if (trace_excp > 1)
+        {
+	  int i;
+	  struct _intstk *intstk =
+	    (struct _intstk *)mech->chf$q_mch_esf_addr;
+
+          display_excp (sig64, mech);
+
+          TERM_FAO (" intstk: !XH!/", intstk);
+          for (i = 0; i < cnt + 1; i++)
+	    TERM_FAO ("   !XH!/", ((unsigned __int64 *)sig64)[i]);
+        }
+      do_debug (mech);
+      ret = SS$_CONTINUE_64;
+      break;
+
+    default:
+      display_excp (sig64, mech);
+      ret = SS$_RESIGNAL_64;
+      break;
+    }
+
+  in_handler--;
+  /* Discard selected thread registers.  */
+  sel_regs_pthread = 0;
+  return ret;
+}
+
+/* Setup internal trace flags according to GDBSTUB$TRACE logical.  */
+
+static void
+trace_init (void)
+{
+  unsigned int status, i, start;
+  unsigned short len;
+  char resstring[LNM$C_NAMLENGTH];
+  static const $DESCRIPTOR (tabdesc, "LNM$DCL_LOGICAL");
+  static const $DESCRIPTOR (logdesc, "GDBSTUB$TRACE");
+  $DESCRIPTOR (sub_desc, resstring);
+  ILE3 item_lst[2];
+
+  item_lst[0].ile3$w_length = LNM$C_NAMLENGTH;
+  item_lst[0].ile3$w_code = LNM$_STRING;
+  item_lst[0].ile3$ps_bufaddr = resstring;
+  item_lst[0].ile3$ps_retlen_addr = &len;
+  item_lst[1].ile3$w_length = 0;
+  item_lst[1].ile3$w_code = 0;
+
+  /* Translate the logical name.  */
+  status = SYS$TRNLNM (0,   		/* Attributes of the logical name.  */
+                       (void *)&tabdesc,       /* Logical name table.  */
+                       (void *)&logdesc,       /* Logical name.  */
+                       0,              	       /* Access mode.  */
+                       &item_lst);             /* Item list.  */
+  if (status == SS$_NOLOGNAM)
+    return;
+  if (!(status & STS$M_SUCCESS))
+    LIB$SIGNAL (status);
+
+  start = 0;
+  for (i = 0; i <= len; i++)
+    {
+      if ((i == len || resstring[i] == ',' || resstring[i] == ';')
+	  && i != start)
+        {
+	  int j;
+
+          sub_desc.dsc$a_pointer = resstring + start;
+          sub_desc.dsc$w_length = i - start;
+
+	  for (j = 0; j < NBR_DEBUG_FLAGS; j++)
+	    if (str$case_blind_compare (&sub_desc, 
+					(void *)&debug_flags[j].name) == 0)
+	      {
+		debug_flags[j].val++;
+		break;
+	      }
+	  if (j == NBR_DEBUG_FLAGS)
+	    TERM_FAO ("GDBSTUB$TRACE: unknown directive !AS!/", &sub_desc);
+
+          start = i + 1;
+        }
+    }
+
+  TERM_FAO ("GDBSTUB$TRACE=!AD ->", len, resstring);
+  for (i = 0; i < NBR_DEBUG_FLAGS; i++)
+    if (debug_flags[i].val > 0)
+      TERM_FAO (" !AS=!ZL", &debug_flags[i].name, debug_flags[i].val);
+  term_putnl ();
+}
+
+
+/* Entry point.  */
+
+static int
+stub_start (unsigned __int64 *progxfer, void *cli_util,
+            EIHD *imghdr, IFD *imgfile,
+            unsigned int linkflag, unsigned int cliflag)
+{
+  static int initialized;
+  int i;
+  int cnt;
+  int is_attached;
+  IMCB *imcb;
+  if (initialized)
+    term_puts ("gdbstub: re-entry\n");
+  else
+    initialized = 1;
+
+  /* When attached (through SS$_DEBUG condition), the number of arguments
+     is 4 and PROGXFER is the PC at interruption.  */
+  va_count (cnt);
+  is_attached = cnt == 4;
+
+  term_init ();
+
+  /* Hello banner.  */
+  term_puts ("Hello from gdb stub\n");
+
+  trace_init ();
+
+  if (trace_entry && !is_attached)
+    {
+      TERM_FAO ("xfer: !XH, imghdr: !XH, ifd: !XH!/",
+		progxfer, imghdr, imgfile);
+      for (i = -2; i < 8; i++)
+	TERM_FAO ("  at !2SW: !XH!/", i, progxfer[i]);
+    }
+
+  /* Search for entry point.  */
+  if (!is_attached)
+    {
+      entry_pc = 0;
+      for (i = 0; progxfer[i]; i++)
+	entry_pc = progxfer[i];
+
+      if (trace_entry)
+	{
+	  if (entry_pc == 0)
+	    {
+	      term_puts ("No entry point\n");
+	      return 0;
+	    }
+	  else
+	    TERM_FAO ("Entry: !XH!/",entry_pc);
+	}
+    }
+  else
+    entry_pc = progxfer[0];
+
+  has_threads = 0;
+  for (imcb = ctl$gl_imglstptr->imcb$l_flink;
+       imcb != ctl$gl_imglstptr;
+       imcb = imcb->imcb$l_flink)
+    {
+      if (ots$strcmp_eql (pthread_rtl_desc.dsc$a_pointer,
+			  pthread_rtl_desc.dsc$w_length,
+			  imcb->imcb$t_log_image_name + 1,
+			  imcb->imcb$t_log_image_name[0]))
+	has_threads = 1;
+			  
+      if (trace_images)
+	{
+	  unsigned int j;
+	  LDRIMG *ldrimg = imcb->imcb$l_ldrimg;
+	  LDRISD *ldrisd;
+
+	  TERM_FAO ("!XA-!XA ",
+		    imcb->imcb$l_starting_address,
+		    imcb->imcb$l_end_address);
+
+	  switch (imcb->imcb$b_act_code)
+	    {
+	    case IMCB$K_MAIN_PROGRAM:
+	      term_puts ("prog");
+	      break;
+	    case IMCB$K_MERGED_IMAGE:
+	      term_puts ("mrge");
+	      break;
+	    case IMCB$K_GLOBAL_IMAGE_SECTION:
+	      term_puts ("glob");
+	      break;
+	    default:
+	      term_puts ("????");
+	    }
+	  TERM_FAO (" !AD !40AC!/",
+		    1, "KESU" + (imcb->imcb$b_access_mode & 3),
+		    imcb->imcb$t_log_image_name);
+
+	  if ((long) ldrimg < 0 || trace_images < 2)
+	    continue;
+	  ldrisd = ldrimg->ldrimg$l_segments;
+	  for (j = 0; j < ldrimg->ldrimg$l_segcount; j++)
+	    {
+	      unsigned int flags = ldrisd[j].ldrisd$i_flags;
+	      term_puts ("   ");
+	      term_putc (flags & 0x04 ? 'R' : '-');
+	      term_putc (flags & 0x02 ? 'W' : '-');
+	      term_putc (flags & 0x01 ? 'X' : '-');
+	      term_puts (flags & 0x01000000 ? " Prot" : "     ");
+	      term_puts (flags & 0x04000000 ? " Shrt" : "     ");
+	      term_puts (flags & 0x08000000 ? " Shrd" : "     ");
+	      TERM_FAO (" !XA-!XA!/",
+			ldrisd[j].ldrisd$p_base,
+			(unsigned __int64) ldrisd[j].ldrisd$p_base 
+			+ ldrisd[j].ldrisd$i_len - 1);
+	    }
+	  ldrisd = ldrimg->ldrimg$l_dyn_seg;
+	  if (ldrisd)
+	    TERM_FAO ("   dynamic            !XA-!XA!/",
+		      ldrisd->ldrisd$p_base,
+		      (unsigned __int64) ldrisd->ldrisd$p_base 
+		      + ldrisd->ldrisd$i_len - 1);
+	}
+    }
+
+  if (has_threads)
+    threads_init ();
+
+  /* Wait for connection.  */
+  sock_init ();
+
+  /* Set primary exception vector.  */
+  {
+    unsigned int status;
+    status = sys$setexv (0, excp_handler, PSL$C_USER, (__void_ptr32) &prevhnd);
+    if (!(status & STS$M_SUCCESS))
+      LIB$SIGNAL (status);
+  }
+
+  if (is_attached)
+    {
+      return excp_handler ((struct chf$signal_array *) progxfer[2],
+			   (struct chf$mech_array *) progxfer[3]);
+    }
+
+  /* Change first instruction to set a breakpoint.  */
+  {
+    /*
+      01 08 00 40 00 00 	[MII]       break.m 0x80001
+      00 00 00 02 00 00 	            nop.i 0x0
+      00 00 04 00       	            nop.i 0x0;;
+    */
+    static const unsigned char initbp[16] =
+      { 0x01, 0x08, 0x00, 0x40, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x02, 0x00, 0x00,
+	0x00, 0x00, 0x04, 0x00 };
+    unsigned int entry_prot;
+    unsigned int status;
+    
+    status = page_set_rw (entry_pc, 16, &entry_prot);
+
+    if (!(status & STS$M_SUCCESS))
+      {
+	if ((status & STS$M_COND_ID) == (SS$_NOT_PROCESS_VA & STS$M_COND_ID))
+	  {
+	    /* Cannot write here.  This can happen when pthreads are
+	       used.  */
+	    entry_pc = 0;
+	    term_puts ("gdbstub: cannot set breakpoint on entry\n");
+	  }
+	else
+	  LIB$SIGNAL (status);
+      }
+    
+    if (entry_pc != 0)
+      {
+	ots$move (entry_saved, 16, (void *)entry_pc);
+	ots$move ((void *)entry_pc, 16, (void *)initbp);
+	__fc (entry_pc);
+	page_restore_rw (entry_pc, 16, entry_prot);
+      }
+  }
+
+  /* If it wasn't possible to set a breakpoint on the entry point,
+     accept gdb commands now.  Note that registers are not updated.  */
+  if (entry_pc == 0)
+    {
+      while (one_command () == 0)
+        ;
+    }
+
+  /* We will see!  */
+  return SS$_CONTINUE;
+}
+
+/* Declare the entry point of this relocatable module.  */
+
+struct xfer_vector
+{
+  __int64 impure_start;
+  __int64 impure_end;
+  int (*entry) ();
+};
+
+#pragma __extern_model save
+#pragma __extern_model strict_refdef "XFER_PSECT"
+struct xfer_vector xfer_vector = {0, 0, stub_start};
+#pragma __extern_model restore


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

* Re: RFA: New port: ia64-hp-openvms (3/3) - ia64-vms-tdep.c
  2012-02-21 16:23           ` Tristan Gingold
@ 2012-02-22 19:39             ` Pedro Alves
  2012-02-22 19:53               ` Douglas Rupp
  2012-02-24 14:16               ` Tristan Gingold
  0 siblings, 2 replies; 31+ messages in thread
From: Pedro Alves @ 2012-02-22 19:39 UTC (permalink / raw)
  To: Tristan Gingold; +Cc: gdb-patches@sourceware.org ml, Rupp Douglas

On 02/21/2012 04:07 PM, Tristan Gingold wrote:
> 
> On Feb 15, 2012, at 1:17 PM, Pedro Alves wrote:

>> Ah, missed that.  Fine with me to stay with malloc.  What does
>> libunwind do when one returns -UNW_ENOMEM?
> 
> My understanding is that libunwind properly propagate the error, and Â…
> 
>>  Does GDB end up recovering correctly,
>> or do we end up busted anyway?
> 
> Â… gdb recovers.

I was hoping you'd quickly just hack an unconditional "return -UNW_ENOMEM;"
to find it out, but ...

> But because it is so likely that gdb will fail later, I have switched to xmalloc/xfree.

... then it doesn't matter.

Okay.  Just some minor nits below.

> diff --git a/configure.ac b/configure.ac
> index 9d48e90..c24fff4 100644
> --- a/configure.ac
> +++ b/configure.ac
> @@ -929,8 +929,8 @@ case "${target}" in
>      noconfigdirs="$noconfigdirs libgui itcl ld"
>      ;;
>    ia64*-*-*vms*)
> -    # No gdb or ld support yet.
> -    noconfigdirs="$noconfigdirs readline libgui itcl gdb ld"
> +    # No ld support yet.
> +    noconfigdirs="$noconfigdirs libgui itcl ld"
>      ;;
>    i[[3456789]]86-w64-mingw*)
>      ;;

Remember this should be synced with gcc. (and needs a ChangeLog entry).

> +ia64-*-*vms*)
> +	# Target: Intel IA-64 running OpenVMS
> +	gdb_target_obs="ia64-tdep.o ia64-vms-tdep.o"
> +	;;

This deserves a NEWS entry (New targets).  (No need to wait for that
to commit this).

> +#include "defs.h"
> +#include "frame-unwind.h"
> +#include "ia64-tdep.h"
> +#include "osabi.h"
> +#include "gdbtypes.h"
> +#include "solib.h"

Interesting dependency.  If not needed, please remove (and all other
unnecessary includes).

> +#include "target.h"
> +#include "frame.h"
> +#include "regcache.h"
> +#include "gdbcore.h"
> +#include "inferior.h"

> +/* Libunwind callback accessor function for cleanup.  */
> +static void

Empty line between comment and function, please.  Here and elsewhere.

> +ia64_vms_put_unwind_info (unw_addr_space_t as,

-- 
Pedro Alves


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

* Re: RFA: New port: ia64-hp-openvms (2/3) - v2
  2012-02-21 16:08     ` RFA: New port: ia64-hp-openvms (2/3) - v2 Tristan Gingold
@ 2012-02-22 19:41       ` Pedro Alves
  0 siblings, 0 replies; 31+ messages in thread
From: Pedro Alves @ 2012-02-22 19:41 UTC (permalink / raw)
  To: Tristan Gingold; +Cc: gdb-patches@sourceware.org ml, Rupp Douglas

On 02/21/2012 04:04 PM, Tristan Gingold wrote:

> 2012-02-10  Tristan Gingold  <gingold@adacore.com>
> 
> 	* target.h (target_object): Add TARGET_OBJECT_OPENVMS_UIB.
> 	* remote.c (PACKET_qXfer_uib): New enum value.
> 	(remote_protocol_features): Add entry for PACKET_qXfer_uib.
> 	(remote_xfer_partial): Handle TARGET_OBJECT_OPENVMS_UIB.
> 	(_initialize_remote): Call add_packet_config_cmd for
> 	xfer:uib packet.

Looks good.  Okay.

> doc/
> 2012-02-15  Tristan Gingold  <gingold@adacore.com>
> 
> 	* gdb.texinfo (General Query Packets): Document xfer:uib.

qXfer:uib:read

-- 
Pedro Alves


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

* Re: RFA: New port: ia64-hp-openvms (3/3) - ia64-vms-tdep.c
  2012-02-22 19:39             ` Pedro Alves
@ 2012-02-22 19:53               ` Douglas Rupp
  2012-02-24 14:17                 ` Tristan Gingold
  2012-02-24 14:16               ` Tristan Gingold
  1 sibling, 1 reply; 31+ messages in thread
From: Douglas Rupp @ 2012-02-22 19:53 UTC (permalink / raw)
  To: Pedro Alves, Tristan Gingold; +Cc: gdb-patches@sourceware.org ml, Rupp Douglas

On 2/22/2012 11:32 AM, Pedro Alves wrote:
> Okay. Just some minor nits below.
>> diff --git a/configure.ac b/configure.ac
>> index 9d48e90..c24fff4 100644
>> --- a/configure.ac
>> +++ b/configure.ac
>> @@ -929,8 +929,8 @@ case "${target}" in
>>       noconfigdirs="$noconfigdirs libgui itcl ld"
>>       ;;
>>     ia64*-*-*vms*)
>> -    # No gdb or ld support yet.
>> -    noconfigdirs="$noconfigdirs readline libgui itcl gdb ld"
>> +    # No ld support yet.
>> +    noconfigdirs="$noconfigdirs libgui itcl ld"
>>       ;;
>>     i[[3456789]]86-w64-mingw*)
>>       ;;
> Remember this should be synced with gcc. (and needs a ChangeLog entry).
>

I believe there is ld support now.


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

* Re: RFA: New port: ia64-hp-openvms - the stub
  2012-02-21 17:08     ` Tristan Gingold
@ 2012-02-22 20:25       ` Pedro Alves
  2012-02-24  9:24         ` Tristan Gingold
  0 siblings, 1 reply; 31+ messages in thread
From: Pedro Alves @ 2012-02-22 20:25 UTC (permalink / raw)
  To: Tristan Gingold; +Cc: gdb-patches@sourceware.org ml, Rupp Douglas

On 02/21/2012 04:30 PM, Tristan Gingold wrote:
> 
> On Feb 14, 2012, at 7:08 PM, Pedro Alves wrote:

>> I couldn't really tell, but you may want to consider looking into xml target
>> descriptions.  At least reporting a description with the openvms osabi would
>> be good.
> 
> I plan to fix the register issue soon, just be patient !

I am.  :-)  A description with at least the osabi is good so that gdb
knows the target's osabi even if the user doesn't supply an executable.

>>> +#if 1
>>> +      /* What a mess.  Gdb and linux expects bsp to point after the current
>>> +         register frame.  Adjust.  */
>>
>> What does this mean?  Are we committing to a hack that will make our
>> lives hard when we want to fix it?
> 
> I have updated the comment.  Currently, ia64-tdep.c follows the Linux convention, and we don't want to change that.  So the BSP has to be adjusted.

Why don't we want to change it?

It'd be good if the basics of using the stub were documented in
the manual.

In any case, this is okay.

-- 
Pedro Alves


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

* Re: RFA: New port: ia64-hp-openvms - the stub
  2012-02-22 20:25       ` Pedro Alves
@ 2012-02-24  9:24         ` Tristan Gingold
  2012-02-24 11:06           ` Pedro Alves
  0 siblings, 1 reply; 31+ messages in thread
From: Tristan Gingold @ 2012-02-24  9:24 UTC (permalink / raw)
  To: Pedro Alves; +Cc: gdb-patches@sourceware.org ml, Rupp Douglas


On Feb 22, 2012, at 8:52 PM, Pedro Alves wrote:

> On 02/21/2012 04:30 PM, Tristan Gingold wrote:
>> 
>> On Feb 14, 2012, at 7:08 PM, Pedro Alves wrote:
> 
>>> I couldn't really tell, but you may want to consider looking into xml target
>>> descriptions.  At least reporting a description with the openvms osabi would
>>> be good.
>> 
>> I plan to fix the register issue soon, just be patient !
> 
> I am.  :-)  A description with at least the osabi is good so that gdb
> knows the target's osabi even if the user doesn't supply an executable.

Ok, shouldn't be hard to do.  Just to implement qXfer:features:read, IIUC.

>>>> +#if 1
>>>> +      /* What a mess.  Gdb and linux expects bsp to point after the current
>>>> +         register frame.  Adjust.  */
>>> 
>>> What does this mean?  Are we committing to a hack that will make our
>>> lives hard when we want to fix it?
>> 
>> I have updated the comment.  Currently, ia64-tdep.c follows the Linux convention, and we don't want to change that.  So the BSP has to be adjusted.
> 
> Why don't we want to change it?

I think it's too late.  That would be a change in gdbserver and other stubs, so it would break compatibility.  The adjustment in the VMS stubs isn't that complex.

> It'd be good if the basics of using the stub were documented in
> the manual.

Sure, I will work on that.

> In any case, this is okay.

Thank you for reviewing,
Tristan.


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

* Re: RFA: New port: ia64-hp-openvms - the stub
  2012-02-24  9:24         ` Tristan Gingold
@ 2012-02-24 11:06           ` Pedro Alves
  2012-02-24 11:24             ` Tristan Gingold
  0 siblings, 1 reply; 31+ messages in thread
From: Pedro Alves @ 2012-02-24 11:06 UTC (permalink / raw)
  To: Tristan Gingold; +Cc: gdb-patches@sourceware.org ml, Rupp Douglas

On 02/24/2012 08:34 AM, Tristan Gingold wrote:
> 
> On Feb 22, 2012, at 8:52 PM, Pedro Alves wrote:
> 
>> On 02/21/2012 04:30 PM, Tristan Gingold wrote:
>>>
>>> On Feb 14, 2012, at 7:08 PM, Pedro Alves wrote:
>>
>>>> I couldn't really tell, but you may want to consider looking into xml target
>>>> descriptions.  At least reporting a description with the openvms osabi would
>>>> be good.
>>>
>>> I plan to fix the register issue soon, just be patient !
>>
>> I am.  :-)  A description with at least the osabi is good so that gdb
>> knows the target's osabi even if the user doesn't supply an executable.
> 
> Ok, shouldn't be hard to do.  Just to implement qXfer:features:read, IIUC.

Yeah.

>>>>> +#if 1
>>>>> +      /* What a mess.  Gdb and linux expects bsp to point after the current
>>>>> +         register frame.  Adjust.  */
>>>>
>>>> What does this mean?  Are we committing to a hack that will make our
>>>> lives hard when we want to fix it?
>>>
>>> I have updated the comment.  Currently, ia64-tdep.c follows the Linux convention, and we don't want to change that.  So the BSP has to be adjusted.
>>
>> Why don't we want to change it?
> 
> I think it's too late.  That would be a change in gdbserver and other stubs, so it would break compatibility.  

We have ways to make it happen without breaking other stubs.  The question is what is the
right thing to do.  Is this really Linux specific?  We have ia64 hpux support as well.
I take it libunwind must follow the same convention as well, and I hope a libunwind
built on a Linux host doesn't behave different from a libunwind built on a
different host.

The adjustment in the VMS stubs isn't that complex.

Hopefully it'll still be simple with infcalls in the game.  :-)  afaics, you're
not undoing the adjustment on writes.

-- 
Pedro Alves


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

* Re: RFA: New port: ia64-hp-openvms - the stub
  2012-02-24 11:06           ` Pedro Alves
@ 2012-02-24 11:24             ` Tristan Gingold
  2012-02-24 12:17               ` Pedro Alves
  0 siblings, 1 reply; 31+ messages in thread
From: Tristan Gingold @ 2012-02-24 11:24 UTC (permalink / raw)
  To: Pedro Alves; +Cc: gdb-patches@sourceware.org ml, Rupp Douglas


On Feb 24, 2012, at 11:46 AM, Pedro Alves wrote:

>>>>>> +#if 1
>>>>>> +      /* What a mess.  Gdb and linux expects bsp to point after the current
>>>>>> +         register frame.  Adjust.  */
>>>>> 
>>>>> What does this mean?  Are we committing to a hack that will make our
>>>>> lives hard when we want to fix it?
>>>> 
>>>> I have updated the comment.  Currently, ia64-tdep.c follows the Linux convention, and we don't want to change that.  So the BSP has to be adjusted.
>>> 
>>> Why don't we want to change it?
>> 
>> I think it's too late.  That would be a change in gdbserver and other stubs, so it would break compatibility.  
> 
> We have ways to make it happen without breaking other stubs.  The question is what is the
> right thing to do.

I am not sure that modifying the convention of BSP is the right thing to do.

> Is this really Linux specific?  We have ia64 hpux support as well.

AFAIU, hpux also follows the Linux convention.

> I take it libunwind must follow the same convention as well, and I hope a libunwind
> built on a Linux host doesn't behave different from a libunwind built on a
> different host.

That's correct.  libunwind convention matches the VMS one, and therefore ia64-tdep.c has to translate the convention.
See for example the case of UNW_IA64_AR_BSP in ia64-tdep.c:ia64_access_reg.

> The adjustment in the VMS stubs isn't that complex.
> 
> Hopefully it'll still be simple with infcalls in the game.  :-)  afaics, you're
> not undoing the adjustment on writes.

Correct. Writing this register is used only to implement inferior call, which is not yet implemented.  The user will never modify it
directly, as this value cannot be changed without modifying other registers.  HPUX even don't allow to modify it (for not so bad reasons).
Welcome in ia64 world!

Tristan.


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

* Re: RFA: New port: ia64-hp-openvms - the stub
  2012-02-24 11:24             ` Tristan Gingold
@ 2012-02-24 12:17               ` Pedro Alves
  0 siblings, 0 replies; 31+ messages in thread
From: Pedro Alves @ 2012-02-24 12:17 UTC (permalink / raw)
  To: Tristan Gingold; +Cc: gdb-patches@sourceware.org ml, Rupp Douglas

On 02/24/2012 11:12 AM, Tristan Gingold wrote:
> 
> On Feb 24, 2012, at 11:46 AM, Pedro Alves wrote:
> 
>>>>>>> +#if 1
>>>>>>> +      /* What a mess.  Gdb and linux expects bsp to point after the current
>>>>>>> +         register frame.  Adjust.  */
>>>>>>
>>>>>> What does this mean?  Are we committing to a hack that will make our
>>>>>> lives hard when we want to fix it?
>>>>>
>>>>> I have updated the comment.  Currently, ia64-tdep.c follows the Linux convention, and we don't want to change that.  So the BSP has to be adjusted.
>>>>
>>>> Why don't we want to change it?
>>>
>>> I think it's too late.  That would be a change in gdbserver and other stubs, so it would break compatibility.  
>>
>> We have ways to make it happen without breaking other stubs.  The question is what is the
>> right thing to do.
> 
> I am not sure that modifying the convention of BSP is the right thing to do.
> 
>> Is this really Linux specific?  We have ia64 hpux support as well.
> 
> AFAIU, hpux also follows the Linux convention.
> 
>> I take it libunwind must follow the same convention as well, and I hope a libunwind
>> built on a Linux host doesn't behave different from a libunwind built on a
>> different host.
> 
> That's correct.  libunwind convention matches the VMS one, and therefore ia64-tdep.c has to translate the convention.
> See for example the case of UNW_IA64_AR_BSP in ia64-tdep.c:ia64_access_reg.

Damn, what a mess...  If we want to fix this, getting rid of the unnecessary conversions
all around, we can do it with a xml target description with a new standard feature
(org.gnu.gdb.ia64.something) so that gdb knows the registers are sent with the
libunwind/vms convention.  Without that, yes, we should feed the raw register set
as gdb has been expecting it.

> 
>> The adjustment in the VMS stubs isn't that complex.
>>
>> Hopefully it'll still be simple with infcalls in the game.  :-)  afaics, you're
>> not undoing the adjustment on writes.
> 
> Correct. Writing this register is used only to implement inferior call, which is not yet implemented.  The user will never modify it
> directly, as this value cannot be changed without modifying other registers.  HPUX even don't allow to modify it (for not so bad reasons).
> Welcome in ia64 world!
> 
> Tristan.
> 


-- 
Pedro Alves


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

* Re: RFA: New port: ia64-hp-openvms (3/3) - ia64-vms-tdep.c
  2012-02-22 19:39             ` Pedro Alves
  2012-02-22 19:53               ` Douglas Rupp
@ 2012-02-24 14:16               ` Tristan Gingold
  2012-02-24 14:29                 ` Pedro Alves
  1 sibling, 1 reply; 31+ messages in thread
From: Tristan Gingold @ 2012-02-24 14:16 UTC (permalink / raw)
  To: Pedro Alves; +Cc: gdb-patches@sourceware.org ml, Rupp Douglas


On Feb 22, 2012, at 8:32 PM, Pedro Alves wrote:

[…]

> Okay.  Just some minor nits below.
> 
>> diff --git a/configure.ac b/configure.ac
>> index 9d48e90..c24fff4 100644
>> --- a/configure.ac
>> +++ b/configure.ac
>> @@ -929,8 +929,8 @@ case "${target}" in
>>     noconfigdirs="$noconfigdirs libgui itcl ld"
>>     ;;
>>   ia64*-*-*vms*)
>> -    # No gdb or ld support yet.
>> -    noconfigdirs="$noconfigdirs readline libgui itcl gdb ld"
>> +    # No ld support yet.
>> +    noconfigdirs="$noconfigdirs libgui itcl ld"
>>     ;;
>>   i[[3456789]]86-w64-mingw*)
>>     ;;
> 
> Remember this should be synced with gcc. (and needs a ChangeLog entry).

Here is my entry:

2012-02-24  Tristan Gingold  <gingold@adacore.com>

        * configure.ac: Enable gdb and readline for ia64*-*-*vms*.
        * configure: Regenerate.

>> +ia64-*-*vms*)
>> +	# Target: Intel IA-64 running OpenVMS
>> +	gdb_target_obs="ia64-tdep.o ia64-vms-tdep.o"
>> +	;;
> 
> This deserves a NEWS entry (New targets).  (No need to wait for that
> to commit this).

Here is the patch:

2012-02-24  Tristan Gingold  <gingold@adacore.com>

        * NEWS: Mention OpenVMS ia64 new target.


diff --git a/gdb/NEWS b/gdb/NEWS
index 6ed8fa7..4fcbfa5 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -55,6 +55,7 @@
 * New targets
 
 Renesas RL78                   rl78-*-elf
+HP OpenVMS ia64                        ia64-hp-openvms*
 
 *** Changes in GDB 7.4
 
> 
>> +#include "defs.h"
>> +#include "frame-unwind.h"
>> +#include "ia64-tdep.h"
>> +#include "osabi.h"
>> +#include "gdbtypes.h"
>> +#include "solib.h"
> 
> Interesting dependency.  If not needed, please remove (and all other
> unnecessary includes).

Indeed, the list could be reduced!

>> +#include "target.h"
>> +#include "frame.h"
>> +#include "regcache.h"
>> +#include "gdbcore.h"
>> +#include "inferior.h"
> 
>> +/* Libunwind callback accessor function for cleanup.  */
>> +static void
> 
> Empty line between comment and function, please.  Here and elsewhere.

Hup, yes.

> 
>> +ia64_vms_put_unwind_info (unw_addr_space_t as,

My understanding is that all the other patches (osabi, remote, and the stub) have been ok'ed, but I am not sure about this one.  Here is my latest version, with the nits fixed.

Thank you again for the review,
Tristan.

2012-02-10  Tristan Gingold  <gingold@adacore.com>

      * ia64-tdep.h: Include libunwind-frame.h and libunwind-ia64.h.
      (ia64_unw_accessors, ia64_unw_rse_accessors)
      (ia64_libunwind_descr): Declare.
      * ia64-vms-tdep.c: New file.
      * ia64-tdep.c (ia64_unw_accessors, ia64_unw_rse_accessors)
      (ia64_libunwind_descr): Make them public.
      * configure.tgt: Add ia64-*-*vms*.
      * Makefile.in (ALL_64_TARGET_OBS): Add ia64-vms-tdep.o
      (ALLDEPFILES): Add ia64-vms-tdep.c


diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index 3e1b93c..357a6db 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -516,7 +516,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-hpux-tdep.o ia64-linux-tdep.o ia64-tdep.o \
+	ia64-hpux-tdep.o ia64-linux-tdep.o ia64-vms-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
@@ -1458,7 +1458,7 @@ ALLDEPFILES = \
 	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 \
+	ia64-linux-nat.c ia64-linux-tdep.c ia64-tdep.c ia64-vms-tdep.c \
 	inf-ptrace.c inf-ttrace.c \
 	irix5-nat.c \
 	libunwind-frame.c \
diff --git a/gdb/configure.tgt b/gdb/configure.tgt
index 5e97ab4..6b4a504 100644
--- a/gdb/configure.tgt
+++ b/gdb/configure.tgt
@@ -246,6 +246,10 @@ ia64-*-linux*)
 			solib-svr4.o symfile-mem.o"
 	build_gdbserver=yes
 	;;
+ia64-*-*vms*)
+	# Target: Intel IA-64 running OpenVMS
+	gdb_target_obs="ia64-tdep.o ia64-vms-tdep.o"
+	;;
 ia64*-*-*)
 	# Target: Intel IA-64
 	gdb_target_obs="ia64-tdep.o"
diff --git a/gdb/ia64-tdep.c b/gdb/ia64-tdep.c
index a36dc22..1c4fa8f 100644
--- a/gdb/ia64-tdep.c
+++ b/gdb/ia64-tdep.c
@@ -3148,7 +3148,7 @@ static const struct frame_unwind ia64_libunwind_sigtramp_frame_unwind =
 };
 
 /* Set of libunwind callback acccessor functions.  */
-static unw_accessors_t ia64_unw_accessors =
+unw_accessors_t ia64_unw_accessors =
 {
   ia64_find_proc_info_x,
   ia64_put_unwind_info,
@@ -3164,7 +3164,7 @@ static unw_accessors_t ia64_unw_accessors =
    the rse registers.  At the top of the stack, we want libunwind to figure out
    how to read r32 - r127.  Though usually they are found sequentially in
    memory starting from $bof, this is not always true.  */
-static unw_accessors_t ia64_unw_rse_accessors =
+unw_accessors_t ia64_unw_rse_accessors =
 {
   ia64_find_proc_info_x,
   ia64_put_unwind_info,
@@ -3178,7 +3178,7 @@ static unw_accessors_t ia64_unw_rse_accessors =
 
 /* Set of ia64 gdb libunwind-frame callbacks and data for generic
    libunwind-frame code to use.  */
-static struct libunwind_descr ia64_libunwind_descr =
+struct libunwind_descr ia64_libunwind_descr =
 {
   ia64_gdb2uw_regnum, 
   ia64_uw2gdb_regnum, 
diff --git a/gdb/ia64-tdep.h b/gdb/ia64-tdep.h
index 48cc3e0..7501eb4 100644
--- a/gdb/ia64-tdep.h
+++ b/gdb/ia64-tdep.h
@@ -20,6 +20,11 @@
 #ifndef IA64_TDEP_H
 #define IA64_TDEP_H
 
+#ifdef HAVE_LIBUNWIND_IA64_H
+#include "libunwind-ia64.h"
+#include "libunwind-frame.h"
+#endif
+
 /* Register numbers of various important registers.  */
 
 /* General registers; there are 128 of these 64 bit wide registers.
@@ -250,4 +255,10 @@ struct gdbarch_tdep
 
 extern void ia64_write_pc (struct regcache *, CORE_ADDR);
 
+#ifdef HAVE_LIBUNWIND_IA64_H
+extern unw_accessors_t ia64_unw_accessors;
+extern unw_accessors_t ia64_unw_rse_accessors;
+extern struct libunwind_descr ia64_libunwind_descr;
+#endif
+
 #endif /* ia64-tdep.h */
diff --git a/gdb/ia64-vms-tdep.c b/gdb/ia64-vms-tdep.c
new file mode 100644
index 0000000..859c0b4
--- /dev/null
+++ b/gdb/ia64-vms-tdep.c
@@ -0,0 +1,165 @@
+/* Target-dependent code for OpenVMS IA-64.
+
+   Copyright (C) 2012 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 "frame-unwind.h"
+#include "ia64-tdep.h"
+#include "osabi.h"
+#include "gdbtypes.h"
+#include "gdbcore.h"
+
+#ifdef HAVE_LIBUNWIND_IA64_H
+
+/* Libunwind callback accessor function to acquire procedure unwind-info.  */
+
+static int
+ia64_vms_find_proc_info_x (unw_addr_space_t as, unw_word_t ip,
+                           unw_proc_info_t *pi,
+                           int need_unwind_info, void *arg)
+{
+  enum bfd_endian byte_order = gdbarch_byte_order (target_gdbarch);
+  unw_dyn_info_t di;
+  int ret;
+  gdb_byte buf[32];
+  const char *annex = core_addr_to_string (ip);
+  LONGEST res;
+  CORE_ADDR table_addr;
+  unsigned int info_len;
+
+  res = target_read (&current_target, TARGET_OBJECT_OPENVMS_UIB,
+                     annex + 2, buf, 0, sizeof (buf));
+
+  if (res != sizeof (buf))
+    return -UNW_ENOINFO;
+
+  pi->format = UNW_INFO_FORMAT_REMOTE_TABLE;
+  pi->start_ip = extract_unsigned_integer (buf + 0, 8, byte_order);
+  pi->end_ip = extract_unsigned_integer (buf + 8, 8, byte_order);
+  pi->gp = extract_unsigned_integer (buf + 24, 8, byte_order);
+  table_addr = extract_unsigned_integer (buf + 16, 8, byte_order);
+
+  if (table_addr == 0)
+    {
+      /* No unwind data.  */
+      pi->unwind_info = NULL;
+      pi->unwind_info_size = 0;
+      return 0;
+    }
+
+  res = target_read_memory (table_addr, buf, 8);
+  if (res != 0)
+    return -UNW_ENOINFO;
+
+  /* Check version.  */
+  if (extract_unsigned_integer (buf + 6, 2, byte_order) != 1)
+    return -UNW_EBADVERSION;
+  info_len = extract_unsigned_integer (buf + 0, 4, byte_order);
+  pi->unwind_info_size = 8 * info_len;
+
+  /* Read info.  */
+  pi->unwind_info = xmalloc (pi->unwind_info_size);
+
+  res = target_read_memory (table_addr + 8,
+                            pi->unwind_info, pi->unwind_info_size);
+  if (res != 0)
+    {
+      xfree (pi->unwind_info);
+      pi->unwind_info = NULL;
+      return -UNW_ENOINFO;
+    }
+
+  /* FIXME: Handle OSSD (OS Specific Data).  This extension to ia64 unwind
+     information by OpenVMS is currently not handled by libunwind, but
+     looks to be used only in very specific context, and is not generated by
+     GCC.  */
+
+  pi->lsda = table_addr + 8 + pi->unwind_info_size;
+  if (extract_unsigned_integer (buf + 4, 2, byte_order) & 3)
+    {
+      pi->lsda += 8;
+      /* There might be an handler, but this is not used for unwinding.  */
+      pi->handler = 0;
+    }
+
+  return 0;
+}
+
+/* Libunwind callback accessor function for cleanup.  */
+
+static void
+ia64_vms_put_unwind_info (unw_addr_space_t as,
+                          unw_proc_info_t *pip, void *arg)
+{
+  /* Nothing required for now.  */
+}
+
+/* Libunwind callback accessor function to get head of the dynamic
+   unwind-info registration list.  */
+
+static int
+ia64_vms_get_dyn_info_list (unw_addr_space_t as,
+                            unw_word_t *dilap, void *arg)
+{
+  return -UNW_ENOINFO;
+}
+
+/* Set of libunwind callback acccessor functions.  */
+static unw_accessors_t ia64_vms_unw_accessors;
+static unw_accessors_t ia64_vms_unw_rse_accessors;
+
+/* Set of ia64 gdb libunwind-frame callbacks and data for generic
+   libunwind-frame code to use.  */
+static struct libunwind_descr ia64_vms_libunwind_descr;
+
+#endif /* HAVE_LIBUNWIND_IA64_H */
+
+static void
+ia64_openvms_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
+{
+  set_gdbarch_long_double_format (gdbarch, floatformats_ia64_quad);
+
+#ifdef HAVE_LIBUNWIND_IA64_H
+  /* Override the default descriptor.  */
+  ia64_vms_unw_accessors = ia64_unw_accessors;
+  ia64_vms_unw_accessors.find_proc_info = ia64_vms_find_proc_info_x;
+  ia64_vms_unw_accessors.put_unwind_info = ia64_vms_put_unwind_info;
+  ia64_vms_unw_accessors.get_dyn_info_list_addr = ia64_vms_get_dyn_info_list;
+
+  ia64_vms_unw_rse_accessors = ia64_unw_rse_accessors;
+  ia64_vms_unw_rse_accessors.find_proc_info = ia64_vms_find_proc_info_x;
+  ia64_vms_unw_rse_accessors.put_unwind_info = ia64_vms_put_unwind_info;
+  ia64_vms_unw_rse_accessors.get_dyn_info_list_addr = ia64_vms_get_dyn_info_list;
+
+  ia64_vms_libunwind_descr = ia64_libunwind_descr;
+  ia64_vms_libunwind_descr.accessors = &ia64_vms_unw_accessors;
+  ia64_vms_libunwind_descr.special_accessors = &ia64_vms_unw_rse_accessors;
+
+  libunwind_frame_set_descr (gdbarch, &ia64_vms_libunwind_descr);
+#endif
+}
+
+/* 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_OPENVMS,
+			  ia64_openvms_init_abi);
+}


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

* Re: RFA: New port: ia64-hp-openvms (3/3) - ia64-vms-tdep.c
  2012-02-22 19:53               ` Douglas Rupp
@ 2012-02-24 14:17                 ` Tristan Gingold
  0 siblings, 0 replies; 31+ messages in thread
From: Tristan Gingold @ 2012-02-24 14:17 UTC (permalink / raw)
  To: Douglas Rupp; +Cc: Pedro Alves, gdb-patches@sourceware.org ml, Rupp Douglas


On Feb 22, 2012, at 8:40 PM, Douglas Rupp wrote:

> On 2/22/2012 11:32 AM, Pedro Alves wrote:
>> Okay. Just some minor nits below.
>>> diff --git a/configure.ac b/configure.ac
>>> index 9d48e90..c24fff4 100644
>>> --- a/configure.ac
>>> +++ b/configure.ac
>>> @@ -929,8 +929,8 @@ case "${target}" in
>>>      noconfigdirs="$noconfigdirs libgui itcl ld"
>>>      ;;
>>>    ia64*-*-*vms*)
>>> -    # No gdb or ld support yet.
>>> -    noconfigdirs="$noconfigdirs readline libgui itcl gdb ld"
>>> +    # No ld support yet.
>>> +    noconfigdirs="$noconfigdirs libgui itcl ld"
>>>      ;;
>>>    i[[3456789]]86-w64-mingw*)
>>>      ;;
>> Remember this should be synced with gcc. (and needs a ChangeLog entry).
>> 
> 
> I believe there is ld support now.

Not yet, only for Alpha VMS.  I haven't yet submitted the bfd+ld change.

Tristan.


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

* Re: RFA: New port: ia64-hp-openvms (3/3) - ia64-vms-tdep.c
  2012-02-24 14:16               ` Tristan Gingold
@ 2012-02-24 14:29                 ` Pedro Alves
  2012-03-05 11:58                   ` Tristan Gingold
  0 siblings, 1 reply; 31+ messages in thread
From: Pedro Alves @ 2012-02-24 14:29 UTC (permalink / raw)
  To: Tristan Gingold; +Cc: gdb-patches@sourceware.org ml, Rupp Douglas

On 02/24/2012 02:15 PM, Tristan Gingold wrote:

> 2012-02-10  Tristan Gingold  <gingold@adacore.com>
> 
>       * ia64-tdep.h: Include libunwind-frame.h and libunwind-ia64.h.
>       (ia64_unw_accessors, ia64_unw_rse_accessors)
>       (ia64_libunwind_descr): Declare.
>       * ia64-vms-tdep.c: New file.
>       * ia64-tdep.c (ia64_unw_accessors, ia64_unw_rse_accessors)
>       (ia64_libunwind_descr): Make them public.
>       * configure.tgt: Add ia64-*-*vms*.
>       * Makefile.in (ALL_64_TARGET_OBS): Add ia64-vms-tdep.o
>       (ALLDEPFILES): Add ia64-vms-tdep.c

FAOD, okay.  You're good to go.

> 2012-02-24  Tristan Gingold  <gingold@adacore.com>
>
>         * NEWS: Mention OpenVMS ia64 new target.

Usually we wait for Eli's ok on docu things, but I think this
one's super obvious, so go ahead.


-- 
Pedro Alves


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

* Re: RFA: New port: ia64-hp-openvms (3/3) - ia64-vms-tdep.c
  2012-02-24 14:29                 ` Pedro Alves
@ 2012-03-05 11:58                   ` Tristan Gingold
  0 siblings, 0 replies; 31+ messages in thread
From: Tristan Gingold @ 2012-03-05 11:58 UTC (permalink / raw)
  To: Pedro Alves; +Cc: gdb-patches@sourceware.org ml, Rupp Douglas


On Feb 24, 2012, at 3:24 PM, Pedro Alves wrote:

> On 02/24/2012 02:15 PM, Tristan Gingold wrote:
> 
>> 2012-02-10  Tristan Gingold  <gingold@adacore.com>
>> 
>>      * ia64-tdep.h: Include libunwind-frame.h and libunwind-ia64.h.
>>      (ia64_unw_accessors, ia64_unw_rse_accessors)
>>      (ia64_libunwind_descr): Declare.
>>      * ia64-vms-tdep.c: New file.
>>      * ia64-tdep.c (ia64_unw_accessors, ia64_unw_rse_accessors)
>>      (ia64_libunwind_descr): Make them public.
>>      * configure.tgt: Add ia64-*-*vms*.
>>      * Makefile.in (ALL_64_TARGET_OBS): Add ia64-vms-tdep.o
>>      (ALLDEPFILES): Add ia64-vms-tdep.c
> 
> FAOD, okay.  You're good to go.
> 
>> 2012-02-24  Tristan Gingold  <gingold@adacore.com>
>> 
>>        * NEWS: Mention OpenVMS ia64 new target.
> 
> Usually we wait for Eli's ok on docu things, but I think this
> one's super obvious, so go ahead.

Thank you, I have just committed the whole set of patches.

Tristan.


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

end of thread, other threads:[~2012-03-05 11:58 UTC | newest]

Thread overview: 31+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2012-02-10 13:07 RFA: New port: ia64-hp-openvms (0/3) Tristan Gingold
2012-02-10 13:21 ` RFA: New port: ia64-hp-openvms (1/3) - new osabi Tristan Gingold
2012-02-10 13:27   ` RFA: New port: ia64-hp-openvms (3/3) - ia64-vms-tdep.c Tristan Gingold
2012-02-14 17:50     ` Pedro Alves
2012-02-15  9:14       ` Tristan Gingold
2012-02-15 12:57         ` Pedro Alves
2012-02-21 16:23           ` Tristan Gingold
2012-02-22 19:39             ` Pedro Alves
2012-02-22 19:53               ` Douglas Rupp
2012-02-24 14:17                 ` Tristan Gingold
2012-02-24 14:16               ` Tristan Gingold
2012-02-24 14:29                 ` Pedro Alves
2012-03-05 11:58                   ` Tristan Gingold
2012-02-12  9:36   ` RFA: New port: ia64-hp-openvms (1/3) - new osabi Mark Kettenis
2012-02-10 13:23 ` RFA: New port: ia64-hp-openvms (2/3) Tristan Gingold
2012-02-12  9:39   ` Mark Kettenis
2012-02-13  8:45     ` Tristan Gingold
2012-02-14 17:36   ` Pedro Alves
2012-02-14 17:40     ` Pedro Alves
2012-02-21 16:08     ` RFA: New port: ia64-hp-openvms (2/3) - v2 Tristan Gingold
2012-02-22 19:41       ` Pedro Alves
2012-02-10 13:44 ` RFA: New port: ia64-hp-openvms - the stub Tristan Gingold
2012-02-10 19:06   ` Douglas Rupp
2012-02-13  8:43     ` Tristan Gingold
2012-02-14 18:09   ` Pedro Alves
2012-02-21 17:08     ` Tristan Gingold
2012-02-22 20:25       ` Pedro Alves
2012-02-24  9:24         ` Tristan Gingold
2012-02-24 11:06           ` Pedro Alves
2012-02-24 11:24             ` Tristan Gingold
2012-02-24 12:17               ` Pedro Alves

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox