public inbox for gdb-patches@sourceware.org
 help / color / mirror / Atom feed
* Adding support for VxWorks target
@ 2010-04-25 15:47 Joel Brobecker
  2010-04-25 15:47 ` [vxworks 01/14] Some ada-lang/ada-tasks routines needed by the " Joel Brobecker
                   ` (15 more replies)
  0 siblings, 16 replies; 27+ messages in thread
From: Joel Brobecker @ 2010-04-25 15:47 UTC (permalink / raw)
  To: gdb-patches

Hello,

The following series of patches adds support for cross debugging
VxWorks targets (version 5.x, 6.x and limited support for VxWorks 653).
It's a lot of code overall, and many patches, but it is almost
completely contained in dedicated files, and we've split the changes
in modules/patches, hoping to make it easier for anyone wanting to
look at them.

With VxWorks systems, we communicate with the target by establishing
a connection with the "target server".  The target server is a server
running on a host which acts as a multiplexer.  The protocol used
between the target server and the target itself is undocumented, and
extremely version/system dependent. The protocol used to talk to the
target server is not documented per se, but WindRiver provides an API
that allows us to do the communication.

What we do, in this port, is use the API to send the various request.
The one problem with the API is that it is not all that stable across
versions - compatibility of the API between WTX versions (we support
versions 2, 3 and 4) is not guaranteed.  As a result, we created a thin
abstraction on top of the WTX API that Wind River provides which allowed
us to have that consistent API, making the real code a *LOT* simpler.

As you will see if you read the description of some of the patches,
there are a couple of things that we implemented one way which is
definitly on the quick-and-dirty how-else-could-I-do-it-without-
making-changes-everywhere side.  I've pulled these changes out for now,
and we intend to discuss those issues separately in order to find
the proper way to fix them.  The only side-effect of pulling these
changes out, as it turns out, is that we are losing support for
partitions in VxWorks 653 systems.

Lastly, these patches were tested on VxWorks 5.x and VxWorks 6.x
using AdaCore's testsuite. We were actually quite surprised at
the almost clean results we got! :)

Documentation will of course follow if the patches make it in the FSF
tree...

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

* [vxworks 01/14] Some ada-lang/ada-tasks routines needed by the VxWorks target.
  2010-04-25 15:47 Adding support for VxWorks target Joel Brobecker
@ 2010-04-25 15:47 ` Joel Brobecker
  2010-04-25 15:48 ` [vxworks 10/14] Add new "wtx" target Joel Brobecker
                   ` (14 subsequent siblings)
  15 siblings, 0 replies; 27+ messages in thread
From: Joel Brobecker @ 2010-04-25 15:47 UTC (permalink / raw)
  To: gdb-patches

We need to add a few routines in the following units...

  - ada-lang.c:

      After switching to a new partition, if there is an Ada main in there,
      and the language is auto, switch the language to Ada (if not already
      Ada).

  - ada-tasks.c:

      The remote-wtx backend needs to access the list of known Ada
      tasks in order to build the associated list of VxWorks threads
      running as part of an Ada "program".  This is for the multi-tasks
      mode.

2010-04-24  Joel Brobecker  <brobecker@adacore.com>

        * ada-lang.c (ada_language_auto_set, clear_ada_sym_cache):
        New functions.
        * ada-tasks.c (ada_get_environment_task, iterate_over_live_ada_tasks):
        New functions.
        * ada-lang.h (ada_language_auto_set, ada_get_environment_task)
        (ada_task_list_iterator_ftype, iterate_over_live_ada_tasks):
        Add declarations.
---
 gdb/ada-lang.c  |   19 +++++++++++++++++++
 gdb/ada-lang.h  |    8 ++++++++
 gdb/ada-tasks.c |   37 +++++++++++++++++++++++++++++++++++++
 3 files changed, 64 insertions(+), 0 deletions(-)

diff --git a/gdb/ada-lang.c b/gdb/ada-lang.c
index 9da0609..5da30f9 100644
--- a/gdb/ada-lang.c
+++ b/gdb/ada-lang.c
@@ -646,6 +646,20 @@ ada_update_initial_language (enum language lang)
   return lang;
 }
 
+/* If the language mode is auto, and we can find some Ada code
+   in one of the module, then automatically set the language to Ada.  */
+
+void
+ada_language_auto_set (void)
+{
+  if (language_mode == language_mode_auto
+      && ada_update_initial_language (language_unknown) == language_ada)
+    {
+      set_language (language_ada);
+      expected_language = current_language;
+    }
+}
+
 /* If the main procedure is written in Ada, then return its name.
    The result is good until the next call.  Return NULL if the main
    procedure doesn't appear to be in Ada.  */
@@ -3940,6 +3954,11 @@ make_array_descriptor (struct type *type, struct value *arr,
 /* Dummy definitions for an experimental caching module that is not
  * used in the public sources. */
 
+void
+clear_ada_sym_cache (void)
+{
+}
+
 static int
 lookup_cached_symbol (const char *name, domain_enum namespace,
                       struct symbol **sym, struct block **block)
diff --git a/gdb/ada-lang.h b/gdb/ada-lang.h
index 3d60f8f..e73e939 100644
--- a/gdb/ada-lang.h
+++ b/gdb/ada-lang.h
@@ -211,6 +211,8 @@ extern const char *ada_decode (const char*);
 
 extern enum language ada_update_initial_language (enum language);
 
+extern void ada_language_auto_set (void);
+
 extern void clear_ada_sym_cache (void);
 
 extern int ada_lookup_symbol_list (const char *, const struct block *,
@@ -373,8 +375,14 @@ extern char *ada_main_name (void);
 
 extern int valid_task_id (int);
 
+extern struct ada_task_info *ada_get_environment_task (void);
+
 extern int ada_get_task_number (ptid_t);
 
+typedef void (ada_task_list_iterator_ftype) (struct ada_task_info *task);
+extern void iterate_over_live_ada_tasks
+  (ada_task_list_iterator_ftype *iterator);
+
 extern int ada_build_task_list (int warn_if_null);
 
 extern int ada_exception_catchpoint_p (struct breakpoint *b);
diff --git a/gdb/ada-tasks.c b/gdb/ada-tasks.c
index 519cfc6..7f0b1c2 100644
--- a/gdb/ada-tasks.c
+++ b/gdb/ada-tasks.c
@@ -212,6 +212,43 @@ ada_task_is_alive (struct ada_task_info *task_info)
   return (task_info->state != Terminated);
 }
 
+/* Return the task info associated to the Environment Task.
+   This function assumes that the inferior does in fact use tasking.  */
+
+struct ada_task_info *
+ada_get_environment_task (void)
+{
+  ada_build_task_list (0);
+  gdb_assert (VEC_length (ada_task_info_s, task_list) > 0);
+
+  /* We use a little bit of insider knowledge to determine which task
+     is the Environment Task:  We know that this task is created first,
+     and thus should always be task #1, which is at index 0 of the
+     TASK_LIST.  */
+  return (VEC_index (ada_task_info_s, task_list, 0));
+}
+
+/* Call the ITERATOR function once for each Ada task that hasn't been
+   terminated yet.  */
+
+void
+iterate_over_live_ada_tasks (ada_task_list_iterator_ftype *iterator)
+{
+  int i, nb_tasks;
+  struct ada_task_info *task;
+
+  ada_build_task_list (0);
+  nb_tasks = VEC_length (ada_task_info_s, task_list);
+
+  for (i = 0; i < nb_tasks; i++)
+    {
+      task = VEC_index (ada_task_info_s, task_list, i);
+      if (!ada_task_is_alive (task))
+        continue;
+      iterator (task);
+    }
+}
+
 /* Extract the contents of the value as a string whose length is LENGTH,
    and store the result in DEST.  */
 
-- 
1.6.3.3

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

* [vxworks 13/14] Add tdep files for x86 and powerpc.
  2010-04-25 15:47 Adding support for VxWorks target Joel Brobecker
                   ` (6 preceding siblings ...)
  2010-04-25 15:48 ` [vxworks 11/14] WTX-TCL support module Joel Brobecker
@ 2010-04-25 15:48 ` Joel Brobecker
  2010-04-25 20:45   ` Mark Kettenis
  2010-04-25 15:48 ` [vxworks 09/14] remote-wtx-hw / register fetch/store support Joel Brobecker
                   ` (7 subsequent siblings)
  15 siblings, 1 reply; 27+ messages in thread
From: Joel Brobecker @ 2010-04-25 15:48 UTC (permalink / raw)
  To: gdb-patches

This patch adds a new GDB_OSABI_VXWORKS for VxWorks targets, and
introduces new VxWorks tdep files for x86 and powerpc.  They will
be included in the build by the next patch.

2010-04-24  Joel Brobecker  <brobecker@adacore.com>

        * defs.h (enum gdb_osabi): Add GDB_OSABI_VXWORKS.
        * osabi.c (gdb_osabi_names): Add entry for GDB_OSABI_VXWORKS.
        * i386-vxworks-tdep.c, rs6000-vxworks-tdep.c: New files.
---
 gdb/defs.h                |    1 +
 gdb/i386-vxworks-tdep.c   |   53 +++++++++++++++++++++++
 gdb/osabi.c               |    1 +
 gdb/rs6000-vxworks-tdep.c |  105 +++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 160 insertions(+), 0 deletions(-)
 create mode 100644 gdb/i386-vxworks-tdep.c
 create mode 100644 gdb/rs6000-vxworks-tdep.c

diff --git a/gdb/defs.h b/gdb/defs.h
index e8a1dd4..a7f69ae 100644
--- a/gdb/defs.h
+++ b/gdb/defs.h
@@ -986,6 +986,7 @@ enum gdb_osabi
   GDB_OSABI_QNXNTO,
   GDB_OSABI_CYGWIN,
   GDB_OSABI_AIX,
+  GDB_OSABI_VXWORKS,
   GDB_OSABI_DICOS,
   GDB_OSABI_DARWIN,
   GDB_OSABI_SYMBIAN,
diff --git a/gdb/i386-vxworks-tdep.c b/gdb/i386-vxworks-tdep.c
new file mode 100644
index 0000000..a2248c8
--- /dev/null
+++ b/gdb/i386-vxworks-tdep.c
@@ -0,0 +1,53 @@
+/* Copyright (C) 2007, 2010 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#include "defs.h"
+#include "inferior.h"
+#include "osabi.h"
+#include "i386-tdep.h"
+
+static void
+i386_vxworks_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
+{
+  /* The AT_ENTRY_POINT method is not practical on VxWorks systems,
+     because there is no concept of "the" executable.  Furthermore,
+     memory space is shared by all processes (and thus someone
+     spawning a new task using the same entry point might interfere
+     with our function call).  So we rely on the ON_STACK method
+     instead.  */
+  set_gdbarch_call_dummy_location (gdbarch, ON_STACK);
+}
+
+static enum gdb_osabi
+i386_vxworks_osabi_sniffer (bfd * abfd)
+{
+  char *target_name = bfd_get_target (abfd);
+
+  if (strstr (target_name, "vxworks") != NULL)
+    return GDB_OSABI_VXWORKS;
+
+  return GDB_OSABI_UNKNOWN;
+}
+void
+_initialize_vxworks_tdep (void)
+{
+  gdbarch_register_osabi_sniffer (bfd_arch_i386, bfd_target_elf_flavour,
+                                  i386_vxworks_osabi_sniffer);
+  gdbarch_register_osabi (bfd_arch_i386, 0, GDB_OSABI_VXWORKS,
+                          i386_vxworks_init_abi);
+}
+
diff --git a/gdb/osabi.c b/gdb/osabi.c
index 84590cd..60171e1 100644
--- a/gdb/osabi.c
+++ b/gdb/osabi.c
@@ -70,6 +70,7 @@ static const char * const gdb_osabi_names[] =
   "QNX Neutrino",
   "Cygwin",
   "AIX",
+  "VxWorks",
   "DICOS",
   "Darwin",
   "Symbian",
diff --git a/gdb/rs6000-vxworks-tdep.c b/gdb/rs6000-vxworks-tdep.c
new file mode 100644
index 0000000..2f10bfd
--- /dev/null
+++ b/gdb/rs6000-vxworks-tdep.c
@@ -0,0 +1,105 @@
+/* Target-dependent code for GDB, the GNU debugger.
+
+   Copyright (C) 2009, 2010 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#include "defs.h"
+#include "gdbarch.h"
+#include "osabi.h"
+#include "ppc-tdep.h"
+#include "gdb_assert.h"
+#include "inferior.h"
+#include "gdb_string.h"
+
+static CORE_ADDR
+rs6000_vxworks_push_dummy_code (struct gdbarch *gdbarch,
+				CORE_ADDR sp, CORE_ADDR funaddr,
+				struct value **args, int nargs,
+				struct type *value_type,
+				CORE_ADDR *real_pc, CORE_ADDR *bp_addr,
+				struct regcache *regcache)
+{
+  /* Something here to findout the size of a breakpoint and then
+     allocate space for it on the stack.  */
+  int bplen;
+  /* This code assumes frame align.  */
+  gdb_assert (gdbarch_frame_align_p (gdbarch));
+  /* Force the stack's alignment.  The intent is to ensure that the SP
+     is aligned to at least a breakpoint instruction's boundary.  */
+  sp = gdbarch_frame_align (gdbarch, sp);
+  /* Allocate space for, and then position the breakpoint on the stack.  */
+  if (gdbarch_inner_than (gdbarch, 1, 2))
+    {
+      CORE_ADDR bppc = sp;
+      gdbarch_breakpoint_from_pc (gdbarch, &bppc, &bplen);
+      sp = gdbarch_frame_align (gdbarch, sp - bplen);
+      (*bp_addr) = sp;
+      /* Should the breakpoint size/location be re-computed here?  */
+    }
+  else
+    {
+      (*bp_addr) = sp;
+      gdbarch_breakpoint_from_pc (gdbarch, bp_addr, &bplen);
+      sp = gdbarch_frame_align (gdbarch, sp + bplen);
+    }
+  /* Inferior resumes at the function entry point.  */
+  (*real_pc) = funaddr;
+  return sp;
+}
+
+static void
+rs6000_vxworks_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
+{
+  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+
+  /* Certain versions of VxWorks do not provide support for Altivec
+     registers.  For now, disable support for these registers on all
+     versions of GDB.  */
+  tdep->ppc_vr0_regnum = -1;
+  tdep->ppc_vrsave_regnum = -1;
+
+  /* The AT_ENTRY_POINT method is not practical on VxWorks systems,
+     because there is no concept of "the" executable.  Furthermore,
+     memory space is shared by all processes (and thus someone
+     spawning a new task using the same entry point might interfere
+     with our function call).  So we rely on the ON_STACK method
+     instead.  */
+  set_gdbarch_call_dummy_location (gdbarch, ON_STACK);
+  set_gdbarch_push_dummy_code (gdbarch, rs6000_vxworks_push_dummy_code);
+}
+
+static enum gdb_osabi
+rs6000_vxworks_osabi_sniffer (bfd * abfd)
+{
+  char *target_name = bfd_get_target (abfd);
+
+  if (strstr (target_name, "vxworks") != NULL)
+    return GDB_OSABI_VXWORKS;
+
+  return GDB_OSABI_UNKNOWN;
+}
+
+void
+_initialize_rs6000_vxworks_tdep (void)
+{
+  /* Register the sniffer for the VxWorks targets.  */
+  gdbarch_register_osabi_sniffer (bfd_arch_powerpc, bfd_target_elf_flavour,
+                                  rs6000_vxworks_osabi_sniffer);
+  gdbarch_register_osabi (bfd_arch_powerpc, 0, GDB_OSABI_VXWORKS,
+                          rs6000_vxworks_init_abi);
+}
+
-- 
1.6.3.3

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

* [vxworks 10/14] Add new "wtx" target.
  2010-04-25 15:47 Adding support for VxWorks target Joel Brobecker
  2010-04-25 15:47 ` [vxworks 01/14] Some ada-lang/ada-tasks routines needed by the " Joel Brobecker
@ 2010-04-25 15:48 ` Joel Brobecker
  2010-04-25 15:48 ` [vxworks 02/14] New command_post observer Joel Brobecker
                   ` (13 subsequent siblings)
  15 siblings, 0 replies; 27+ messages in thread
From: Joel Brobecker @ 2010-04-25 15:48 UTC (permalink / raw)
  To: gdb-patches

This adds the bulk of the support for VxWorks systems through a new
target: wtx.

2010-04-24  Joel Brobecker  <brobecker@adacore.com>

        * remote-wtx.h, remote-wtx.c: New files.
---
 gdb/remote-wtx.c | 3075 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 gdb/remote-wtx.h |   25 +
 2 files changed, 3100 insertions(+), 0 deletions(-)
 create mode 100644 gdb/remote-wtx.c
 create mode 100644 gdb/remote-wtx.h

diff --git a/gdb/remote-wtx.c b/gdb/remote-wtx.c
new file mode 100644
index 0000000..2fde258
--- /dev/null
+++ b/gdb/remote-wtx.c
@@ -0,0 +1,3075 @@
+/* Support for the WTX protocol.
+
+   Copyright (C) 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#include "defs.h"
+#include "remote-wtx.h"
+#include "ada-lang.h"
+#include "language.h"
+#include "remote-wtxapi.h"
+#include "remote-wtx-opt.h"
+#include "remote-wtx-pd.h"
+#include "target.h"
+#include "exceptions.h"
+#include "symfile.h"
+#include "filenames.h"
+#include "command.h"
+#include "objfiles.h"
+#include "remote-wtx-utils.h"
+#include "remote-wtx-bp.h"
+#include "remote-wtx-tasks.h"
+#include "inferior.h"
+#include "gdbthread.h"
+#include "remote-wtx-hw.h"
+#include "regcache.h"
+#include "gdb_select.h"
+#include "observer.h"
+
+#include <signal.h>
+
+/* The target_ops vectors for the WTX protocol support.
+   There is one vector per mode of operation:
+     - Connected to the target server, but not attached;
+     - Attached to a task ("task" and "multi-tasks" modes);
+     - Attached to the system ("system" mode).  */
+
+static struct target_ops wtx_ops;
+static struct target_ops wtx_task_mode_ops;
+static struct target_ops wtx_system_mode_ops;
+
+/* The directory name extracted from from the boot-line info.
+   This directory is initialized when we connect to the target server,
+   and will mosly be used to locate the boot image.  */
+static char *kernel_directory = NULL;
+
+/* The PID of the task we are currently attached to.  This is used
+   to identify the CTX_EXIT event of the task we are debugging from
+   the same event for other tasks.  */
+static int attached_context_id = 0;
+
+/* Set to non-zero if we need to fake an "attach" event in the wait loop.  */
+static int fake_attach_event = 0;
+
+/* Status of the inferior after an asynchronous interruption (attach,
+   to_stop...) It is used to determine whether to use the "cont" or
+   the "resume" request to resume the execution of the inferior.  */
+static enum wtx_task_status inferior_status = WTX_TASK_STATUS_UNKNOWN;
+
+/* A variable that is set to non-zero when the inferior was stopped
+   by a watchpoint.  Contains the address of the data being watched.  */
+static CORE_ADDR watchpoint_data_address = 0;
+
+/* Some function advance declarations.  */
+
+static void unload_module_symbols (const char *module_filename, int from_tty);
+static void unload_command (char *args, int from_tty);
+static int wtx_context_alive (int context_id);
+
+/* Return non-zero if we are currently running in system-mode.  */
+
+static int
+system_mode_p (void)
+{
+  return (target_shortname == wtx_system_mode_ops.to_shortname);
+}
+
+/* Build a ptid from the given TASK_ID.  */
+
+static ptid_t
+context_id_to_ptid (WTX_CONTEXT_ID_T context_id)
+{
+  /* Build the ptid by using the CONTEXT_ID as the pid, and leave
+     the thread & lwp ids set to 0.  However, in system mode, the
+     system context ID is -1, which would normally translate to
+     a ptid that GDB treats specially.  So, for the system context id,
+     we use a special PID of 1.  */
+  if (context_id == SYSTEM_CID)
+    return ptid_build (1, 0, 1);
+
+  return ptid_build (1, 0, context_id);
+}
+
+/* Return the task context ID of the given PTID.  */
+
+static WTX_CONTEXT_ID_T
+ptid_get_context_id (ptid_t ptid)
+{
+  int tid = ptid_get_tid (ptid);
+
+  if (tid == 1)
+    /* This is the special PID we use in system mode for the system ptid
+       (see context_id_to_ptid above).  Return the system context ID.  */
+    return SYSTEM_CID;
+
+  return tid;
+}
+
+/* Record PTID as a new inferior.  ATTACHED should be non-zero if
+   we just attached to this process, as oppposed to creating it.  */
+
+static void
+wtx_add_inferior (ptid_t ptid, int attached)
+{
+  struct inferior *inf;
+
+  /* For now, we use a model where we only have one inferior at a time.
+     So we simply bind the inferior to the current inferior.  */
+  inf = current_inferior ();
+  inferior_appeared (inf, ptid_get_pid (ptid));
+  inf->attach_flag = attached;
+
+  /* This inferior is also the main thread, so add it as a thread. Reset
+     thread list in order to clean up leftovers from previous attach/detach
+     operations.  */
+  init_thread_list ();
+  add_thread_silent (ptid);
+}
+
+/* Add PTID to the thread list (if needed).  */
+
+static void
+wtx_add_thread (ptid_t ptid)
+{
+  if (!in_thread_list (ptid))
+    add_thread (ptid);
+}
+
+/* Perform a WTX_CONTEXT_CONT operation for the given context type
+   and ID.
+
+   FIXME: brobecker/2007-07-06: This function is not completely
+   implemented yet.  The handling of expected error situations
+   is still missing.  See the vxworks-5.3 code, and in particular
+   the little tap-dance with current_wtx_operation, and its use
+   in errorHandler.  For now, this function is basically a simple
+   wrapper around wtxapi_context_cont.  */
+
+static int
+wtx_context_continue (WTX_CONTEXT_TYPE context_type,
+                      WTX_CONTEXT_ID_T context_id)
+{
+  return wtxapi_context_cont (context_type, context_id);
+}
+
+/* Resume the execution of the inferior given its CONTEXT_TYPE and
+   CONTEXT_ID.
+
+   On 653, the system makes the distinction between the STOPPED state
+   which occurs after the thread has hit a breakpoint, and the SUSPEND
+   state, which happens after we attach to the system.  As a result,
+   the debugger needs to use either the "cont" or "resume" WTX request
+   to resume the thread execution.
+
+   On Tornado 2, either request will work on all cases, because
+   the system only provides the SUSPEND mode.  However, the documentation
+   explains that it is better to use the "cont" request for breakpoint
+   events on T2 as well.  This is very convenient as the same code
+   can be shared for all Tornado versions.  */
+
+static int
+continue_inferior (WTX_CONTEXT_TYPE context_type, WTX_CONTEXT_ID_T context_id)
+{
+  int result = 0;
+
+  switch (inferior_status)
+    {
+    case WTX_TASK_STATUS_CREATED:
+      result = wtxapi_context_resume (context_type, context_id);
+      break;
+    case WTX_TASK_STATUS_STOPPED:
+      if (multi_task_mode_is_on ())
+        result = continue_all_ada_tasks ();
+      else
+        result = wtx_context_continue (context_type, context_id);
+      break;
+    case WTX_TASK_STATUS_SUSPENDED:
+      if (multi_task_mode_is_on ())
+        result = continue_all_ada_tasks ();
+      else
+        result = wtxapi_context_resume (context_type, context_id);
+      break;
+    default:
+      result = wtxapi_context_resume (context_type, context_id);
+      break;
+    }
+
+  if (!result)
+    inferior_status = WTX_TASK_STATUS_UNKNOWN;
+  else
+    inferior_status = WTX_TASK_STATUS_RUNNING;
+  return result;
+}
+
+/* Perform a "suspend" operation on the inferior, given its
+   CONTEXT_TYPE and its CONTEXT_ID. inferior_status is updated
+   accordingly.  */
+
+static int
+suspend_inferior  (WTX_CONTEXT_TYPE context_type, WTX_CONTEXT_ID_T context_id)
+{
+  int result = wtxapi_context_suspend (context_type, context_id);
+  if (!result)
+    inferior_status = WTX_TASK_STATUS_UNKNOWN;
+  else
+    inferior_status = WTX_TASK_STATUS_SUSPENDED;
+  return result;
+}
+
+/* Perform a "stop" operation on the inferior, given its
+   CONTEXT_TYPE and its CONTEXT_ID. inferior_status is updated
+   accordingly.  */
+
+static int
+stop_inferior  (WTX_CONTEXT_TYPE context_type, WTX_CONTEXT_ID_T context_id)
+{
+  int result = wtxapi_context_stop (context_type, context_id);
+  if (!result)
+    inferior_status = WTX_TASK_STATUS_UNKNOWN;
+  else
+    inferior_status = WTX_TASK_STATUS_STOPPED;
+  return result;
+}
+
+/* A function that is meant to be used as the callback function for
+   bfd_map_over_sections, an whose purpose is to make a shallow
+   duplication of the array of sections for the given BFD object.  */
+
+static void
+collect_bfd_sections (bfd *abfd, asection *sect, void *ptr)
+{
+  asection **sections = (asection **) ptr;
+
+  sections[sect->index] = sect;
+}
+
+/* Build the SECTION_ADDRS field of the give MODULE_INFO using
+   the module segment base addresses.
+
+   We compute the section addresses by:
+     1. Getting the list of sections and their attribute from
+        the object file (using bfd)
+     2. Iterate in order over each section and:
+          a. Determine to which segment it belongs
+          b. Compute its address as being just after the previous
+             section that lives in the same segment (modulo alignment)
+
+   This function assumes that MODULE_INFO->SEGMENTS is not NULL,
+   or will abort with a failed assertion.  */
+
+static void
+build_module_info_section_addrs (struct wtxapi_module_info *module_info,
+                                 bfd *abfd)
+{
+  CORE_ADDR text_addr;
+  CORE_ADDR data_addr;
+  CORE_ADDR bss_addr;
+  int num_sections;
+  int i;
+  asection **bfd_sections;
+
+  gdb_assert (module_info->segments != NULL);
+
+  text_addr = module_info->segments->text_addr;
+  data_addr = module_info->segments->data_addr;
+  bss_addr = module_info->segments->bss_addr;
+
+  num_sections = bfd_count_sections (abfd);
+  module_info->section_addrs = alloc_section_addr_info (num_sections);
+
+  bfd_sections = (asection **) xzalloc (num_sections * sizeof (asection *));
+  bfd_map_over_sections (abfd, collect_bfd_sections, (void *) bfd_sections);
+
+  for (i = 0; i < num_sections; i++)
+    {
+      CORE_ADDR *addr_ptr = NULL;
+      asection *sect = bfd_sections[i];
+      flagword flags = bfd_get_section_flags (NULL, sect)
+        & (SEC_ALLOC | SEC_LOAD | SEC_READONLY | SEC_CODE | SEC_DATA);
+
+      switch (flags)
+        {
+          case (SEC_ALLOC | SEC_LOAD | SEC_READONLY | SEC_CODE):  /* text */
+          case (SEC_ALLOC | SEC_LOAD | SEC_CODE):         /* writable text */
+            addr_ptr = &text_addr;
+            break;
+
+          case (SEC_ALLOC | SEC_LOAD | SEC_READONLY | SEC_DATA):  /* rodata */
+            if (strcmp (sect->name, ".rodata") == 0)
+              addr_ptr = &text_addr;
+            break;
+          case (SEC_ALLOC | SEC_LOAD | SEC_DATA):                 /* data */
+            addr_ptr = &data_addr;
+            break;
+
+          default:
+            if ((flags & SEC_ALLOC) && !(flags & SEC_LOAD))       /* bss */
+              addr_ptr = &bss_addr;
+            break;
+        }
+
+      if (addr_ptr != NULL)
+        {
+          module_info->section_addrs->other[i].addr =
+            align_power (*addr_ptr, bfd_get_section_alignment (abfd, sect));
+          *addr_ptr = module_info->section_addrs->other[i].addr
+                        + bfd_section_size (abfd, sect);
+        }
+      module_info->section_addrs->other[i].name =
+        xstrdup (bfd_get_section_name (abfd, sect));
+      module_info->section_addrs->other[i].sectindex = sect->index;
+
+      /* FIMXE:brobecker/2007-05-18: On VxWorks systems, the offset
+         of each section of our object file seems to be set to zero.
+         This isn't a problem when we have one section per segment,
+         but it actually causes trouble when we have more than one
+         section per segment (eg when building with -ffunction-sections).
+         What happens in that case is that the relocation module thinks
+         that all these sections are located at the beginning of the
+         associated segment, and ends up computing wrong addresses.
+         This is particularly visible in the relocation of the debugging
+         info sections.
+
+         In my opinion, this is a linker issue.  But we can cover
+         this issue by fixing up the section offsets, at least until
+         the linker is updated.  As far as we know, this is only useful
+         for ".text.*" sections, we do the fixup only for these; it just
+         makes it easier because the base address for the offset is
+         always the text segment base address.  */
+      if (sect->name != NULL
+          && strncmp (bfd_sections[i]->name, ".text.", 6) == 0)
+        bfd_set_section_vma
+          (abfd, sect,
+           module_info->section_addrs->other[i].addr
+           - module_info->segments->text_addr);
+    }
+
+  xfree (bfd_sections);
+}
+
+/* Read the symbols from the given MODULE_FILENAME, using the information
+   available in MODULE_INFO.
+
+   This function assumes that the current PD is equal to the module PD.  */
+
+static int
+read_module_symbols_1 (struct wtxapi_module_info *module_info,
+                       char *module_filename)
+{
+  struct gdb_exception e;
+
+
+  TRY_CATCH (e, RETURN_MASK_ERROR)
+    {
+      bfd *abfd = symfile_bfd_open (module_filename);
+
+      if (module_info->section_addrs == NULL)
+        build_module_info_section_addrs (module_info, abfd);
+
+      symbol_file_add_from_bfd (abfd, 0, module_info->section_addrs,
+				0 /* flags */);
+    }
+  if (e.reason < 0)
+    {
+      printf_filtered (_("Unable to load symbols for module %s: %s\n"),
+                       module_info->module_name, e.message);
+      return 0;
+    }
+
+  return 1;
+}
+
+/* Load the symbols from the given module (identified by its MODULE_ID).
+
+   This function handles the case when the module PD is different from
+   the current PD by temporarily switching to the module PD during
+   the symbol reading phase.  */
+
+static void
+read_module_symbols (module_id_t module_id, int ignored_verbose)
+{
+  const pd_id_t current_pd = wtxapi_pd_current_get ();
+  const pd_id_t module_pd = wtx_pd_get_module_pd (module_id);
+  struct cleanup *old_chain = NULL;
+  struct wtxapi_module_info *module_info;
+  struct gdb_exception e;
+  char *module_filename;
+
+  if (module_pd != current_pd)
+    {
+      wtx_pd_switch_to_pd (module_pd);
+      old_chain = wtx_pd_make_switch_to_pd_cleanup (current_pd);
+    }
+
+  module_info = wtxapi_obj_module_info_get (module_pd, module_id);
+  if (module_info == NULL)
+    error (_("Cannot get info for module 0x%x: %s"),
+           (unsigned int) module_id, wtxapi_err_msg_get ());
+
+  printf_filtered ("\t%s: ", module_info->module_name);
+  gdb_flush (gdb_stdout);
+
+  /* The module name is a basename, not an absolute filename.
+     If this file is not present in the current directory, then
+     try to see if it is in the kernel_directory.  */
+
+  module_filename = module_info->module_name;
+  if (!is_regular_file (module_filename) && kernel_directory != NULL)
+    {
+      char *filename = concat (kernel_directory, module_filename, NULL);
+
+      make_cleanup (xfree, filename);
+      if (is_regular_file (filename))
+        module_filename = filename;
+    }
+
+  /* Try reading the symbols from the given module.  */
+  if (read_module_symbols_1 (module_info, module_filename))
+    printf_filtered (_("ok\n"));
+
+  free_wtxapi_module_info (module_info);
+  if (old_chain)
+    do_cleanups (old_chain);
+}
+
+/* Query the target about the list of modules currently loaded,
+   and load the symbols from each module.  */
+
+static void
+read_symbols_from_all_modules (int from_tty)
+{
+  struct wtxapi_module_list *module_list;
+  int i;
+
+  if (from_tty)
+    printf_filtered (_("Looking for all loaded modules:\n"));
+
+  module_list = wtxapi_obj_module_list_get (WTX_MOD_FIND_IN_ALL_PD);
+  if (module_list == NULL)
+    error (_("Could not get target module list: %s"), wtxapi_err_msg_get ());
+
+  make_cleanup (cleanup_wtxapi_module_list, module_list);
+
+  for (i = 0; i < module_list->num_obj_mod; i++)
+    {
+      read_module_symbols (module_list->mod_id_array[i], from_tty);
+      QUIT;
+    }
+
+  if (from_tty)
+    printf_filtered (_("Done.\n"));
+
+  /* Now that we have some object files, GDB should recompute the gdbarch
+     vector using them.  VxWorks does not really have a concept of "the"
+     executable, but we know that all the modules (aka objfiles) are on
+     the same target and are using the same architecture.  So we just
+     pick the first objfile we have and use that to recompute the gdbarch
+     vector.  */
+  if (object_files != NULL && object_files->obfd != NULL)
+    set_gdbarch_from_file (object_files->obfd);
+}
+
+/* Compute the name of the directory where the boot image was loaded
+   from.
+
+   When successful, save the result in KERNEL_DIRECTORY. When not
+   successful, then KERNEL_DIRECTORY is set to NULL.  */
+
+static void
+cache_kernel_directory_name (void)
+{
+  const char *boot_line = wtxapi_target_bootline_get ();
+  char *separator;
+  char *basename = NULL;
+  char *tmp;
+
+  /* If kernel_directory was previous set, free it.  We want to recompute it
+     each time, to make sure it's correct (we may have switched from
+     one board to the other, for instance).  */
+  if (kernel_directory != NULL)
+    {
+      xfree (kernel_directory);
+      kernel_directory = NULL;
+    }
+
+  if (boot_line == NULL)
+    return;  /* No boot-line information, so nothing much we can do.  */
+
+  /* The format of the boot path follows the following syntax:
+     [<hostname> ":"]<kernel module full path>  */
+
+  /* Skip the hostname if specified, being careful of not stripping
+     the drive letter on Windows hosts...  */
+
+  separator = strchr (boot_line, ':');
+  if (separator != NULL
+      && !(have_dos_based_filesystem ()
+           && (separator - boot_line == 1)))
+    boot_line = separator + 1;
+
+  /* wtxapi_target_bootline_get returns a pointer into temporary memory,
+     so we need to duplicate kernel_directory for our own usage.  */
+  kernel_directory = xstrdup (boot_line);
+
+  /* Strip the module name from the path.
+
+     Keep the trailing directory separator, as this directory will be
+     concatenated with filenames to form full paths.  So no need to strip
+     it here only to add it back later.  */
+
+  tmp = kernel_directory;
+  while (*tmp != '\0')
+    {
+      if (IS_DIR_SEPARATOR (*tmp))
+        basename = tmp + 1;
+      tmp++;
+    }
+
+  if (basename != NULL)
+    *basename = '\0';
+}
+
+/* Implement the to_open method of the target_ops structure
+   for the WTX protocol.  */
+
+void
+wtx_open (char *args, int from_tty)
+{
+  char **argv = buildargv (args);
+  char *target_server_name;
+  WTX_AGENT_MODE_TYPE target_agent_mode;
+  struct gdb_exception ex;
+
+  make_cleanup_freeargv (argv);
+
+  if (argv[0] == NULL)
+    error (_("target name is missing"));
+  target_server_name = argv[0];
+
+  printf_filtered (_("Connecting to target server: %s...\n"),
+                   target_server_name);
+  unpush_target (&wtx_ops);
+
+  if (!wtxapi_tool_attach (target_server_name, wtx_opt_tool_name ()))
+    error (_("Could not connect to target server."));
+
+  push_target (&wtx_ops);
+
+  TRY_CATCH (ex, RETURN_MASK_ERROR)
+    {
+      /* Make sure that we can communicate with the target server.
+         If the attempt failed and WTX reports that the target server
+         is not attached (target server locked by another user, server
+         is up but target rebooted, server is up but not attached to
+         the target agent, ...), then print a warning and try attaching
+         again.  */
+      if (!wtxapi_target_server_available_p ()
+          && wtxapi_err_get () == WTX_ERR_SVR_TARGET_NOT_ATTACHED)
+        {
+          warning (_("target not attached to target server, reattaching..."));
+
+          if (!wtxapi_target_attach ())
+            error (_("Failed to attach to target: %s"), wtxapi_err_msg_get ());
+        }
+
+      /* Make sure that we can communicate with the target server now.
+         If all our previous attemps to connect properly failed, then
+         abort.  */
+      if (!wtxapi_target_server_available_p ())
+        error (_("Connection to target server is not usable: %s."),
+               wtxapi_err_msg_get ());
+
+      target_agent_mode = wtxapi_agent_mode_get ();
+      if (target_agent_mode == invalid_agent_mode)
+        error (_("Could not get agent mode: %s"), wtxapi_err_msg_get ());
+
+      if (!wtxapi_register_for_event (".*"))
+        error (_("Could not register for target events: %s"),
+               wtxapi_err_msg_get ());
+
+      printf_filtered (_("Connected to %s\n"), wtxapi_ts_name_get ());
+
+      cache_kernel_directory_name ();
+      read_symbols_from_all_modules (from_tty);
+      ada_language_auto_set ();
+
+      wtx_hw_initialize ();
+      wtx_opt_init_task_options ();
+      wtxapi_notify_connection_established ();
+    }
+  if (ex.reason < 0)
+    {
+      printf_filtered ("%s\n", ex.message);
+      unpush_target (&wtx_ops);
+    }
+}
+
+/* Implement the to_close method of the target_ops for the WTX protocol.  */
+
+static void
+wtx_close (int quitting)
+{
+  /* We don't need to remove all the breakpoints from the inferior,
+     because GDB is handling their insertion and removal for us.  */
+
+  if (!wtxapi_tool_detach ())
+    warning (_("error detected while detaching from target (ignored): %s"),
+             wtxapi_err_msg_get ());
+}
+
+/* Implement the to_close method when in "task" mode.  */
+
+static void
+wtx_task_mode_close (int quitting)
+{
+  /* Nothing to do.  */
+}
+
+/* Implement the to_close method when in "system" mode.  */
+
+static void
+wtx_system_mode_close (int quitting)
+{
+  /* Nothing to do.  */
+}
+
+/* Attach to the "system".  In other words, start debugging in
+   the target in system mode.  */
+
+static void
+wtx_system_mode_attach (int from_tty)
+{
+  if (from_tty)
+    printf_filtered (_("Entering system-mode.\n"));
+
+  if (!wtxapi_system_mode_support_p ())
+    error (_("system-mode not supported."));
+
+  if (!wtxapi_agent_mode_set (WTX_AGENT_MODE_EXTERN))
+    error (_("Failed to enter system mode: %s"), wtxapi_err_msg_get ());
+
+  if (!suspend_inferior (WTX_CONTEXT_SYSTEM, SYSTEM_CID))
+    error (_("Failed to suspend system context: %s"), wtxapi_err_msg_get ());
+
+  push_target (&wtx_system_mode_ops);
+
+  inferior_ptid =
+    context_id_to_ptid (wtxapi_system_mode_get_current_context_id ());
+
+  /* If the user turned the multi-tasks-mode on, then warn the user that
+     we are turning it off now.  This mode doesn't make sense in system
+     mode.
+
+     We could silently ignore the multi-task-mode user setting, but
+     it makes the code clearer to turn it off, because it allows us
+     to determine that if we are in multi-tasks mode iff the user
+     setting is non-zero (without having to check which mode (task-mode
+     vs system-mode we are using).  */
+  if (multi_task_mode_is_on ())
+    {
+      warning (_("The multi-tasks mode can not be used in system mode.\n\
+multi-tasks mode turned off."));
+      turn_multi_task_mode_off ();
+    }
+}
+
+/* Register for exit notification for the given task ID.  */
+
+static int
+register_for_exit_event (int context_id)
+{
+  evtpt_id_t evtpt_id;
+
+  evtpt_id = wtxapi_context_exit_notify_add (WTX_CONTEXT_TASK, context_id);
+  if (evtpt_id == invalid_evtpt_id)
+    return 0;
+
+  attached_context_id = context_id;
+  return 1;
+}
+
+/* If NAME is the name of a task currently running on the system,
+   return its ID.  Return zero otherwize.  */
+
+static int
+wtx_context_id_from_name (char *name)
+{
+  struct wtxapi_thread_info *threads = wtxapi_get_thread_list ();
+  struct wtxapi_thread_info *this_thread = threads;
+  int pid = 0;
+
+  while (this_thread != NULL)
+    {
+      if (strcmp (this_thread->name, name) == 0)
+        {
+          pid = this_thread->id;
+          break;
+        }
+      this_thread = this_thread->next;
+    }
+
+  free_wtxapi_thread_info (threads);
+  return pid;
+}
+
+/* Implement the "attach" method for the task mode.  */
+
+static void
+wtx_task_mode_attach (char *args, int from_tty)
+{
+  int context_id;
+
+  /* Check to see if the argument was a task name.  */
+
+  context_id = wtx_context_id_from_name (args);
+
+  /* If not a valid task name, then try parsing the argument as a task ID.  */
+  if (context_id == 0)
+    context_id = parse_and_eval_address (args);
+
+  if (from_tty)
+    printf_filtered (_("Attaching to task %#x.\n"), context_id);
+
+  if (multi_task_mode_is_on ())
+    {
+      start_multi_task_mode ();
+      if (!stop_all_ada_tasks (&inferior_status))
+        error (_("Failed to stop task: %s"), wtxapi_err_msg_get ());
+    }
+  else
+    {
+      if (!stop_inferior (WTX_CONTEXT_TASK, context_id))
+        error (_("Failed to stop task: %s"), wtxapi_err_msg_get ());
+    }
+
+  push_target (&wtx_task_mode_ops);
+
+  wtx_pd_switch_to_task_pd (context_id);
+  inferior_ptid = context_id_to_ptid (context_id);
+
+  if (multi_task_mode_is_on ())
+    {
+      /* In multi-tasks mode, we want to receive the EXIT event
+         of the MAIN task, which is not necessarily the task that
+         we attached too.  Otherwise, we'll end up reporting that
+         the program exited when in fact it was just one task that
+         exited.  So get the main task context ID.  */
+      struct ada_task_info *main_task = ada_get_environment_task ();
+
+      context_id = ptid_get_context_id (main_task->ptid);
+    }
+
+  if (!register_for_exit_event (context_id))
+    error (_("Failed to register exit event: %s"), wtxapi_err_msg_get ());
+
+}
+
+/* Implement the "to_attach" target_ops method.  */
+
+static void
+wtx_attach (struct target_ops *ops, char *args, int from_tty)
+{
+  dont_repeat ();
+
+  if (args == NULL || args[0] == '\0')
+    error_no_arg ("task-id | task-name | system");
+
+  if (strcasecmp (args, "system") == 0)
+    wtx_system_mode_attach (from_tty);
+  else
+    wtx_task_mode_attach (args, from_tty);
+  wtx_add_inferior (inferior_ptid, 1);
+
+  /* GDB is expecting that attaching to the inferior will cause
+     some event to be generated (most likely a SIGTRAP).  To purge
+     that event, GDB will soon call the to_wait target method.
+     Since VxWorks does not generate any event when suspending a task,
+     we need to inform our event loop that the next event-wait should
+     fake a SIGTRAP.
+
+     brobecker/2007-10-12: It is actually possible configure GDB
+     in a way that it will not expect that event, but it involves
+     the definition of the ATTACH_NO_WAIT macro, which we used
+     to do.  But doing so deactivates as a side-effect the printing
+     of the current frame that tells the user where his program is.
+     Given that this macro is currently not multiarched either,
+     and only used by one target, it seems clear that it's preferable
+     to just fake the expected event.  */
+  fake_attach_event = 1;
+}
+
+/* Implement the "detach" command for the tasks mode.  */
+
+static void
+wtx_task_mode_detach (struct target_ops *ops, char *args, int from_tty)
+{
+  int success;
+  WTX_CONTEXT_ID_T context_id = ptid_get_context_id (inferior_ptid);
+
+  printf_filtered (_("Detaching from task 0x%lx...\n"), context_id);
+
+  /* Resume the execution of the inferior.  */
+  success = continue_inferior (WTX_CONTEXT_TASK, context_id);
+  if (!success)
+    warning (_("Failed to resume task: %s"), wtxapi_err_msg_get ());
+
+  if (multi_task_mode_is_on ())
+    stop_multi_task_mode ();
+
+  /* And last, revert back to the basic WTX mode.  */
+  pop_target ();
+}
+
+/* Implement the "detach" command for the system mode.  */
+
+static void
+wtx_system_mode_detach (struct target_ops *ops, char *args, int from_tty)
+{
+  int success;
+
+  printf_filtered (_("Leaving system-mode...\n"));
+
+  /* switch back to task mode.  Does this resume the target execution? */
+  success = wtxapi_agent_mode_set (WTX_AGENT_MODE_TASK);
+  if (!success)
+    warning (_("Operation failed, target may still be in EXTERN mode: %s"),
+             wtxapi_err_msg_get ());
+
+  pop_target ();
+}
+
+/* Perform a step operation in the given CONTEXT_ID & CONTEXT_TYPE.
+
+   Whether a single-instruction step of a multi-instruction step
+   is to be done is decided based on the value of the STEP_RANGE_START
+   and STEP_RANGE_END global variables.  */
+
+static void
+step_inferior (WTX_CONTEXT_TYPE context_type, WTX_CONTEXT_ID_T context_id)
+{
+  struct thread_info *tp = find_thread_ptid (inferior_ptid);
+  gdb_assert (tp);
+
+  if (tp->step_range_end && (tp->step_range_end > tp->step_range_start))
+    wtxapi_context_step (context_type, context_id, tp->step_range_start,
+                         tp->step_range_end);
+  else  /* Step only exactly one instruction.  */
+    wtxapi_context_step (context_type, context_id, 0, 0);
+  inferior_status = WTX_TASK_STATUS_UNKNOWN;
+}
+
+/* Implement the "to_resume" command in task mode.  */
+
+static void
+wtx_task_mode_resume (struct target_ops *ops, ptid_t ptid, int step,
+                      enum target_signal signo)
+{
+  WTX_CONTEXT_ID_T context_id;
+  struct thread_info *tp;
+
+  /* Find the context_id of the task to resume.  If GDB wants to
+     step a specific task, then it will give us its ptid, but
+     otherwise, we should be resuming the inferior_ptid task.  */
+  context_id = ptid_get_context_id (ptid);
+  if (ptid_equal (ptid, minus_one_ptid))
+    {
+      context_id = ptid_get_context_id (inferior_ptid);
+      tp = find_thread_ptid (inferior_ptid);
+    }
+  else
+    {
+      tp = find_thread_ptid (ptid);
+    }
+
+  gdb_assert (tp);
+
+  if (signo != 0 && signo != tp->stop_signal)
+    error (_("The WTX protocol does not support sending signals"));
+
+  /* Clear any WTX error status before resuming.  */
+  wtxapi_err_clear ();
+
+  if (step)
+    step_inferior (WTX_CONTEXT_TASK, context_id);
+  else
+    continue_inferior (WTX_CONTEXT_TASK, context_id);
+
+  /* Make sure that all went well.  */
+
+  if (wtxapi_err_get () != WTX_ERR_NONE)
+    error (_("wtx_task_mode_resume (step = %d, context_id = 0x%lx) failed: %s"),
+           step, context_id, wtxapi_err_msg_get ());
+}
+
+/* Implement the "to_resume" command in system mode.  */
+
+static void
+wtx_system_mode_resume (struct target_ops *ops,
+                        ptid_t ptid, int step, enum target_signal signo)
+{
+  const int resume_all = ptid_equal (ptid, minus_one_ptid);
+  const WTX_CONTEXT_ID_T context_id = ptid_get_context_id (ptid);
+  struct thread_info *tp = find_thread_ptid (ptid);
+
+  /* If GDB wants to step a specific task:
+     - its thread info should be valid (non null);
+     - it won't support sending signals to this specific task.
+
+     In the other case (resume whole system):
+     - the context_id will be 0;
+     - tp will not be valid.
+  */
+
+  gdb_assert (resume_all || tp);
+  if (!resume_all && signo != 0 && signo != tp->stop_signal)
+    error (_("The WTX protocol does not support sending signals"));
+
+  /* If the debugger asks for a specific task to be stepped, verify
+     that this task is in fact the current task.  In system mode,
+     only this task can be stepped  (or in other words, one cannot
+     switch to a different task, and step that task).  In practice,
+     this is not a real limitation, since other task are usually
+     executing system calls for which there is little need for next/step
+     operations.  */
+  if (step && !resume_all)
+    {
+      const WTX_CONTEXT_ID_T current_context_id =
+        wtxapi_system_mode_get_current_context_id ();
+
+      if (context_id != current_context_id)
+        error (_("task 0x%lx cannot be stepped"), context_id);
+    }
+
+  /* Clear any WTX error status before resuming.  */
+  wtxapi_err_clear ();
+
+  if (step)
+    step_inferior (WTX_CONTEXT_SYSTEM, SYSTEM_CID);
+  else
+    continue_inferior (WTX_CONTEXT_SYSTEM, SYSTEM_CID);
+
+  /* Make sure that all went well.  */
+
+  if (wtxapi_err_get () != WTX_ERR_NONE)
+    error (_("wtx_system_mode_resume (step = %d) failed: %s"),
+           step, wtxapi_err_msg_get ());
+}
+
+static int
+wtx_event_is_foreign (WTX_CONTEXT_ID_T context_id,
+                      WTX_CONTEXT_TYPE context_type)
+{
+  /* In system mode, we are debugging the entire system, and we should
+     handle all events.  */
+  if (system_mode_p ())
+    return 0;
+
+  /* In multi-tasks mode, we are debugging an application that has
+     more than one task, and we should logically only process the events
+     from one of these tasks.  But because we restrict the user to one
+     debugger per partition when debugging in multi-tasks mode, we can
+     simplify this condition by simply verifying that the event was
+     triggered by a task running in the current partition.  */
+  if (multi_task_mode_is_on ())
+    {
+      pd_id_t context_pd;
+      int success;
+
+      success = wtxapi_get_task_pd (context_id, &context_pd);
+      if (!success)
+        {
+          /* Probably a CTX_EXIT event from a task we're not watching,
+             maybe in a different partition.  Treat as a foreign event.  */
+          return 1;
+        }
+
+      return (context_pd != wtxapi_pd_current_get ());
+    }
+
+  /* In single-task mode, we should only handle events triggered
+     inside the task we are debugging.  */
+  return (context_id != ptid_get_context_id (inferior_ptid));
+}
+
+/* Interrupt handling during event polling.
+
+   There are two parts involved in interrupt-handling:
+
+     1. Stopping the inferior:
+        This part is performed by the SIGINT handler that we install
+        during the event queue polling loop.
+
+     2. Telling GDB that the inferior stopped:
+        This part is handled by the target "wait" routine.
+        On most systems, the interruption performed in (1)
+        will result in an associated event that can be processed.
+        However, this is not the case with WTX, and so we must
+        maintain a global variable that will be set in the SIGINT
+        handler to notify the event polling loop to stop polling,
+        and let the wait routine fake a SIGINT event.  */
+
+/* The old SIGINT handler that we save during the period when
+   it is replaced by our own SIGINT handler.  */
+static void (*ofunc) (int);
+
+/* Set to non-zero if the inferior has been interrupted while
+   we were polling for events.  */
+static int inferior_interrupted = 0;
+
+/* To be called when reiceiving a SIGINT signal while polling for
+   WTX events.  This routine interrupts the inferior, and sets
+   TARGET_WAIT_INTERRUPTED to 1.  */
+
+static void
+handle_target_wait_interrupt (int signo)
+{
+  target_stop (inferior_ptid);
+  inferior_interrupted = 1;
+}
+
+/* Setup the interrupt-handler to be used during the event polling
+   phase.  As soon as we receive an event, the old handler should
+   be restored.
+
+   INFERIOR_INTERRUPTED is also set to zero.  */
+
+static void
+set_target_wait_interrupt_handler (void)
+{
+  inferior_interrupted = 0;
+  ofunc = signal (SIGINT, handle_target_wait_interrupt);
+}
+
+/* Restore the old handler set by set_target_wait_interrupt_handler.  */
+
+static void
+unset_target_wait_interrupt_handler (void)
+{
+  signal (SIGINT, ofunc);
+}
+
+/* Poll the WTX event queue for event.
+
+   This routine is blocking until either:
+     1. We receive an event;
+     2. Or the user requested that the inferior be interrupted.
+
+   In the first case, a non-NULL wtxapi_event_desc object will
+   be returned. In the second case, NULL is returned.  */
+
+static struct wtxapi_event_desc *
+wtx_event_poll (void)
+{
+  /* An event that we fetched from the event queue the previous
+     time this function was called, but could not be processed
+     because the user interrupted the inferior at the same time.  */
+  static struct wtxapi_event_desc *postponed_event = NULL;
+  struct wtxapi_event_desc *event_desc;
+
+  /* If there is a postponed event, then return it now.  */
+  if (postponed_event != NULL)
+     {
+       event_desc = postponed_event;
+       postponed_event = NULL;
+       return event_desc;
+     }
+
+  set_target_wait_interrupt_handler ();
+
+  /* Wait either for the user to interrupt the inferior, or for
+     a WTX event.  */
+  while (1)
+    {
+      struct timeval timeout;
+
+      event_desc = wtxapi_event_get ();
+
+      if (inferior_interrupted || event_desc != NULL)
+        break;
+
+      /* There was no event available on the queue.  Wait 10ms before
+         each try to avoid eating up all the CPU.  Note that we cannot
+         use usleep because it's not portable.  */
+      timeout.tv_sec = 0;
+      timeout.tv_usec = 10000;
+      gdb_select (0, 0, 0, 0, &timeout);
+    }
+
+  unset_target_wait_interrupt_handler ();
+
+  if (inferior_interrupted && event_desc != NULL)
+    {
+      /* The user interrupted the inferior, but we also received
+         an event at the same time.  Store that event for later
+         processing, and pretend we haven't received it yet.  */
+      postponed_event = event_desc;
+      return NULL;
+    }
+
+  return event_desc;
+}
+
+/* Process a TEXT_ACCESS or DATA_ACCESS event triggered by the given
+   TASK_ID, and fill in STATUS appropriately. CONTEXT_ID and CONTEXT_TYPE
+   are the context id & type of the breakpoint that triggered this event.
+
+   This routines assumes that we have already verified that this event
+   was meant for us (ie is not a foreign event).
+
+   Return TASK_ID.  */
+
+static int
+handle_access_event (WTX_CONTEXT_ID_T task_id,
+                     WTX_CONTEXT_ID_T context_id,
+                     WTX_CONTEXT_TYPE context_type,
+                     struct target_waitstatus *status)
+{
+  /* Update the status.  */
+  status->kind = TARGET_WAITKIND_STOPPED;
+  status->value.sig = TARGET_SIGNAL_TRAP;
+
+  /* When in system-mode, chances are the task_id will be equal to
+     SYSTEM_CID, but this is not precise enough for our needs: We are
+     interested in telling the user which task actually triggered
+     the event.  This piece of information is actually not part of
+     the WTX event (at least not with VxWorks 5.5), but since the task
+     that triggered the event is necessarily the current task, we can
+     derive this piece of information from there.  */
+  if (context_type == WTX_CONTEXT_SYSTEM)
+    task_id = wtxapi_system_mode_get_current_context_id ();
+
+  /* Switch to the task that triggered that event.  */
+  inferior_ptid = context_id_to_ptid (task_id);
+
+  /* If the task is running in a different partition than the current one,
+     automatically switch to the task partition.  */
+  wtx_pd_switch_to_task_pd (task_id);
+
+  return task_id;
+}
+
+/* Process the given context-exit EVENT, and fill in STATUS appropriately.
+
+   If the event was not meant for us (the task that exited is not the
+   one we're attached to), then ignore the event and return -1.
+   Otherwise, return the ID of the task that exited.  */
+
+static int
+handle_ctx_exit_event (struct wtxapi_ctx_exit_event event,
+                       struct target_waitstatus *status)
+{
+  /* If the task that exited is not the main task of our application,
+     then ignore this event.  Otherwise, we end up reporting the completion
+     of our program prematurely.  */
+  if (event.context_id != attached_context_id)
+    return -1;
+
+  status->kind = TARGET_WAITKIND_EXITED;
+  status->value.integer = event.exit_code;
+
+  return event.context_id;
+}
+
+/* Process the given data-access (watchpoint) EVENT, and fill in
+   STATUS appropriately.
+
+   If the event was not meant for us, then ignore the event and
+   return -1.  */
+
+static int
+handle_data_access_event (struct wtxapi_data_access_event event,
+                          struct target_waitstatus *status)
+{
+  int pid;
+
+  if (wtx_event_is_foreign (event.context_id, event.context_type))
+    return -1;
+
+  /* Record the location that triggered the watchpoint.  */
+  watchpoint_data_address = event.data_addr;
+
+  return handle_access_event (event.task_id, event.context_id,
+                              event.context_type, status);
+}
+
+/* Process the given exception EVENT, and fill in STATUS appropriately.
+
+   If the event was not meant for us, then ignore the event and
+   return -1.  */
+
+static int
+handle_exception_event (struct wtxapi_exception_event event,
+                        struct target_waitstatus *status)
+{
+  WTX_CONTEXT_ID_T context_id = event.context_id;
+
+  if (wtx_event_is_foreign (event.context_id, event.context_type))
+    return -1;
+
+  /* Similarly to when we handle access events in system mode,
+     we need to find the ID of the current task, because the
+     context_id returned by the event is equal to SYSTEM_CID
+     which is not precise enough.  We want to tell the user
+     which task is currently executing and triggered that event.  */
+  if (context_id == SYSTEM_CID)
+    context_id = wtxapi_system_mode_get_current_context_id ();
+
+  /* FIXME: brobecker/2007-08-31: The current event handling in GDB
+     doesn't really include support for exceptions.  For now, treat
+     this as an "unknown signal".  Later on, we might want to improve
+     a bit, and in particular display the exception value to the user.  */
+  status->kind = TARGET_WAITKIND_STOPPED;
+  status->value.sig = TARGET_SIGNAL_UNKNOWN;
+
+  if (multi_task_mode_is_on ())
+    stop_all_ada_tasks (&inferior_status);
+
+  return context_id;
+}
+
+/* Process the given obj-loaded event by loading the symbols from
+   that new module.  */
+
+static void
+handle_obj_loaded_event (struct wtxapi_obj_loaded_event event)
+{
+  printf_filtered ("New module on %s\n", wtxapi_ts_name_get ());
+
+  read_module_symbols (event.module_id, 0);
+}
+
+/* Process the given obj-unloaded event by unloading the symbols from
+   that old module.  */
+
+static void
+handle_obj_unloaded_event (struct wtxapi_obj_unloaded_event event)
+{
+  printf_filtered ("Module unloaded on %s\n", wtxapi_ts_name_get ());
+
+  unload_module_symbols (event.module_filename, 0);
+}
+
+/* Process the given text-access (breakpoint) EVENT, and fill in
+   STATUS appropriately.
+
+   If the event was not meant for us, then ignore the event and
+   return -1.  */
+
+static int
+handle_text_access_event (struct wtxapi_text_access_event event,
+                          struct target_waitstatus *status)
+{
+  if (wtx_event_is_foreign (event.context_id, event.context_type))
+    return -1;
+
+  return handle_access_event (event.task_id, event.context_id,
+                              event.context_type, status);
+}
+
+/* Process the given vio-write event.  */
+
+static void
+handle_vio_write_event (struct wtxapi_vio_write_event event)
+{
+  /* The DATA field in EVENT contains the output that our inferior
+     just printed, so simply relay it to our standard output.  */
+  printf_unfiltered ("%s", event.data);
+}
+
+/* Implement the "to_wait" target_ops method.  */
+
+static ptid_t
+wtx_wait (struct target_ops *ops, ptid_t ptid,
+	  struct target_waitstatus *status, int options)
+{
+  int event_context_id = -1;
+  int done_waiting = 0;
+
+  /* Reset the WATCHPOINT_DATA_ADDRESS value.  Now that the system
+     has been restarted, the watchpoint address is no longer relevant.  */
+  watchpoint_data_address = 0;
+
+  if (fake_attach_event)
+    {
+      fake_attach_event = 0;
+      status->kind = TARGET_WAITKIND_STOPPED;
+      status->value.sig = TARGET_SIGNAL_TRAP;
+
+      return inferior_ptid;
+    }
+
+  while (!done_waiting)
+    {
+      struct wtxapi_event_desc *event_desc = wtx_event_poll ();
+
+      if (event_desc == NULL)
+        {
+          /* The event polling was interrupted on user request. The target
+             has already been stopped by the interrupt handler, but there
+             will be no associated WTX event.  So we just fake a SIGINT
+             event received from the current inferior.  */
+          status->kind = TARGET_WAITKIND_STOPPED;
+          status->value.sig = TARGET_SIGNAL_INT;
+
+          return inferior_ptid;
+        }
+
+      switch (event_desc->event_type)
+        {
+          case WTX_EVENT_CTX_EXIT:
+            event_context_id =
+              handle_ctx_exit_event (event_desc->desc.ctx_exit, status);
+            if (event_context_id != -1)
+              done_waiting = 1;
+            break;
+
+          case WTX_EVENT_DATA_ACCESS:
+            event_context_id =
+              handle_data_access_event (event_desc->desc.data_access, status);
+            if (event_context_id != -1)
+              done_waiting = 1;
+            inferior_status = WTX_TASK_STATUS_STOPPED;
+            break;
+
+          case WTX_EVENT_EXCEPTION:
+            event_context_id =
+              handle_exception_event (event_desc->desc.exception, status);
+            if (event_context_id != -1)
+              done_waiting = 1;
+            inferior_status = WTX_TASK_STATUS_STOPPED;
+            break;
+
+          case WTX_EVENT_OBJ_LOADED:
+            handle_obj_loaded_event (event_desc->desc.obj_loaded);
+            break;
+
+          case WTX_EVENT_OBJ_UNLOADED:
+            handle_obj_unloaded_event (event_desc->desc.obj_unloaded);
+            break;
+
+          case WTX_EVENT_TEXT_ACCESS:
+            event_context_id =
+              handle_text_access_event (event_desc->desc.text_access, status);
+            if (event_context_id != -1)
+              done_waiting = 1;
+            inferior_status = WTX_TASK_STATUS_STOPPED;
+            break;
+
+          case WTX_EVENT_VIO_WRITE:
+            handle_vio_write_event (event_desc->desc.vio_write);
+            break;
+        }
+
+      free_wtxapi_event_desc (event_desc);
+    }
+
+  wtx_add_thread (context_id_to_ptid (event_context_id));
+  return context_id_to_ptid (event_context_id);
+}
+
+/* Fetch the value of one register identified by its register number.  */
+
+static void
+wtx_fetch_one_register (struct regcache *regcache,
+                        WTX_CONTEXT_TYPE context_type,
+                        WTX_CONTEXT_ID_T context_id,
+                        int regnum)
+{
+  struct gdbarch *gdbarch = get_regcache_arch (regcache);
+  int result;
+  gdb_byte *buf = alloca (register_size (gdbarch, regnum));
+
+  gdb_assert (regnum != -1);
+
+  memset (buf, 0, sizeof (buf));
+  result = wtx_hw_fetch_register (gdbarch, context_type, context_id,
+				  regnum, buf);
+  if (result)
+    regcache_raw_supply (regcache, regnum, buf);
+}
+
+/* Fetch the register REGNUM using the given CONTEXT_TYPE and CONTEXT_ID.  */
+
+static
+void
+wtx_fetch_registers (struct regcache *regcache,
+                     WTX_CONTEXT_TYPE context_type,
+                     WTX_CONTEXT_ID_T context_id,
+                     int regnum)
+{
+  struct gdbarch *gdbarch = get_regcache_arch (regcache);
+  int total_regs = gdbarch_num_regs (gdbarch)
+    + gdbarch_num_pseudo_regs (gdbarch);
+  int i;
+
+  if (regnum != -1)
+    wtx_fetch_one_register (regcache, context_type, context_id, regnum);
+  else
+    for (i = 0; i < total_regs; i++)
+      wtx_fetch_one_register (regcache, context_type, context_id, i);
+}
+
+/* Implement the "to_fetch_registers" target_ops method when
+   in "task" or "multi-tasks" mode.  */
+
+static void
+wtx_task_mode_fetch_registers (struct target_ops *ops,
+                               struct regcache *regcache, int regnum)
+{
+  wtx_fetch_registers (regcache, WTX_CONTEXT_TASK,
+                       ptid_get_context_id (inferior_ptid),
+                       regnum);
+}
+
+/* Fetch the value of one register identified by its register number.
+
+   REGS_ADDR should be set to the address where the general purpose
+   registers are stored for the task we want to read the registers from.
+
+   FP_REGS_ADDR should be set to the address where the FP registers
+   are stored for the task we want to read the registers from.
+   If this address cannot be computed, then it should be set to zero.
+
+   This function should be called only when currently in system mode.  */
+
+static void
+wtx_system_mode_fetch_one_register_in_memory (struct regcache *regcache,
+                                              CORE_ADDR regs_addr,
+                                              CORE_ADDR fp_regs_addr,
+                                              int regnum)
+{
+  struct gdbarch *gdbarch = get_regcache_arch (regcache);
+  int result;
+  gdb_byte *buf = alloca (register_size (gdbarch, regnum));
+  memset (buf, 0, sizeof (buf));
+
+  gdb_assert (regnum != -1);
+
+  result = wtx_hw_fetch_register_in_memory (gdbarch,
+                                            WTX_CONTEXT_SYSTEM, SYSTEM_CID,
+                                            regs_addr, fp_regs_addr, regnum,
+                                            buf);
+  if (result)
+    regcache_raw_supply (regcache, regnum, buf);
+}
+
+/* For the given context ID:
+     - Set REGS_ADDR to the address where the GP registers are stored.
+     - Set FP_REGS_ADDR to the address where the FP registers are stored.
+
+   Any address that could not be computed is set to zero.  */
+
+static void
+wtx_get_context_register_block_addrs (WTX_CONTEXT_ID_T context_id,
+                                      CORE_ADDR *regs_addr,
+                                      CORE_ADDR *fp_regs_addr)
+{
+  struct wtxapi_thread_info *threads = wtxapi_get_thread_list ();
+  struct wtxapi_thread_info *this_thread = threads;
+
+  *regs_addr = 0;
+  *fp_regs_addr = 0;
+
+  while (this_thread != NULL)
+    {
+      if (this_thread->id == context_id)
+        {
+          *regs_addr = this_thread->regs_addr;
+          *fp_regs_addr = this_thread->fp_regs_addr;
+          break;
+        }
+      this_thread = this_thread->next;
+    }
+
+  free_wtxapi_thread_info (threads);
+}
+
+/* Implement the "to_fetch_registers" target_ops method when
+   in "system" mode.  */
+
+static void
+wtx_system_mode_fetch_registers (struct target_ops *ops,
+                                 struct regcache *regcache, int regnum)
+{
+  const WTX_CONTEXT_ID_T current_system_context_id =
+    wtxapi_system_mode_get_current_context_id ();
+  const WTX_CONTEXT_ID_T gdb_context_id = ptid_get_context_id (inferior_ptid);
+  CORE_ADDR regs_addr;
+  CORE_ADDR fp_regs_addr;
+
+  if (gdb_context_id == SYSTEM_CID
+      || gdb_context_id == current_system_context_id)
+    {
+      wtx_fetch_registers (regcache, WTX_CONTEXT_SYSTEM, SYSTEM_CID, regnum);
+      return;
+    }
+
+  wtx_get_context_register_block_addrs (gdb_context_id, &regs_addr,
+                                        &fp_regs_addr);
+  gdb_assert (regs_addr != 0); /* But fp_regs_addr may be null.  */
+
+  if (regnum != -1)
+    wtx_system_mode_fetch_one_register_in_memory (regcache, regs_addr,
+                                                  fp_regs_addr, regnum);
+  else
+    {
+      struct gdbarch *gdbarch = get_regcache_arch (regcache);
+      const int total_regs = gdbarch_num_regs (gdbarch)
+        + gdbarch_num_pseudo_regs (gdbarch);
+      int i;
+
+      /* Implementation note: The code below causes a succession
+         of small memory reads, which we could optimize by making
+         one large memory read right from the start, and then fetching
+         the register from there.  However, this complicates a bit
+         the implementation, so we'll stick to this simple approach
+         for now.  The delay should not be noticeable.  */
+      for (i = 0; i < total_regs; i++)
+        wtx_system_mode_fetch_one_register_in_memory (regcache, regs_addr,
+                                                      fp_regs_addr, i);
+    }
+}
+
+/* Store the value of one register identified by its register number.  */
+
+static void
+wtx_store_one_register (struct regcache *regcache,
+                        WTX_CONTEXT_TYPE context_type,
+                        WTX_CONTEXT_ID_T context_id,
+                        int regnum)
+{
+  struct gdbarch *gdbarch = get_regcache_arch (regcache);
+  gdb_byte *buf = alloca (register_size (gdbarch, regnum));
+
+  regcache_raw_collect (regcache, regnum, buf);
+  wtx_hw_store_register (gdbarch, context_type, context_id, regnum, buf);
+}
+
+static void
+wtx_store_registers (struct regcache *regcache,
+                     WTX_CONTEXT_TYPE context_type,
+                     WTX_CONTEXT_ID_T context_id,
+                     int regnum)
+{
+  struct gdbarch *gdbarch = get_regcache_arch (regcache);
+  int total_regs = gdbarch_num_regs (gdbarch)
+    + gdbarch_num_pseudo_regs (gdbarch);
+  int i;
+
+  if (regnum != -1)
+    wtx_store_one_register (regcache, context_type, context_id, regnum);
+  else
+    for (i = 0; i < total_regs; i++)
+      wtx_store_one_register (regcache, context_type, context_id, i);
+}
+
+/* Implement the "to_store_registers" target_ops method when
+   in "task" or "multi-tasks" mode.  */
+
+static void
+wtx_task_mode_store_registers (struct target_ops *ops,
+                               struct regcache *regcache, int regnum)
+{
+  wtx_store_registers (regcache, WTX_CONTEXT_TASK,
+                       ptid_get_context_id (inferior_ptid),
+                       regnum);
+}
+
+/* Store the value of one register identified by its register number.
+
+   REGS_ADDR should be set to the address where the general purpose
+   registers are stored for the task whose register is being written.
+
+   FP_REGS_ADDR should be set to the address where the FP registers
+   are stored for the task we want to read the registers from.
+   If this address cannot be computed, then it should be set to zero.
+
+   This function should be called only when currently in system mode.  */
+
+static void
+wtx_system_mode_store_one_register_in_memory (struct regcache *regcache,
+                                              CORE_ADDR regs_addr,
+                                              CORE_ADDR fp_regs_addr,
+                                              int regnum)
+{
+  struct gdbarch *gdbarch = get_regcache_arch (regcache);
+  gdb_byte *buf = alloca (register_size (gdbarch, regnum));
+  memset (buf, 0, sizeof (buf));
+
+  regcache_raw_collect (regcache, regnum, buf);
+  wtx_hw_store_register_in_memory (gdbarch, WTX_CONTEXT_SYSTEM, SYSTEM_CID,
+                                   regs_addr, fp_regs_addr, regnum, buf);
+}
+
+/* Implement the "to_store_registers" target_ops method when
+   in "system" mode.  */
+
+static void
+wtx_system_mode_store_registers (struct target_ops *ops,
+                                 struct regcache *regcache, int regnum)
+{
+  const WTX_CONTEXT_ID_T current_system_context_id =
+    wtxapi_system_mode_get_current_context_id ();
+  const WTX_CONTEXT_ID_T gdb_context_id = ptid_get_context_id (inferior_ptid);
+  CORE_ADDR regs_addr;
+  CORE_ADDR fp_regs_addr;
+
+  if (gdb_context_id == SYSTEM_CID
+      || gdb_context_id == current_system_context_id)
+    {
+      wtx_store_registers (regcache, WTX_CONTEXT_SYSTEM, SYSTEM_CID, regnum);
+      return;
+    }
+
+  wtx_get_context_register_block_addrs (gdb_context_id, &regs_addr,
+                                        &fp_regs_addr);
+  gdb_assert (regs_addr != 0); /* But fp_regs_addr may be null.  */
+
+  if (regnum != -1)
+    wtx_system_mode_store_one_register_in_memory (regcache, regs_addr,
+                                                  fp_regs_addr, regnum);
+  else
+    {
+      struct gdbarch *gdbarch = get_regcache_arch (regcache);
+      const int total_regs = gdbarch_num_regs (gdbarch)
+        + gdbarch_num_pseudo_regs (gdbarch);
+      int i;
+
+      /* Implementation note: The code below causes a succession
+         of small memory reads, which we could optimize by making
+         one large memory read right from the start, and then fetching
+         the register from there.  However, this complicates a bit
+         the implementation, so we'll stick to this simple approach
+         for now.  The delay should not be noticeable.  */
+      for (i = 0; i < total_regs; i++)
+        wtx_system_mode_store_one_register_in_memory (regcache, regs_addr,
+                                                      fp_regs_addr, i);
+    }
+}
+
+/* Implement the "to_store" method in the target_ops vector.  */
+
+static void
+wtx_prepare_to_store (struct regcache *regcache)
+{
+  /* Nothing to do.  */
+}
+
+/* If there are any undefined symbols referenced by MODULE_INFO,
+   then print a list containing the name of all such symbols.  */
+
+static void
+print_undefined_symbols (struct wtxapi_module_info *module_info)
+{
+  if (module_info->undef_list == NULL)
+    return;
+  if (! go_to_first_element_in_wtxapi_sym_list (module_info->undef_list))
+    return;
+
+  printf_filtered ("\n");
+  warning (_("the module contains some undefined symbols:"));
+  do
+    {
+      char *symbol_name = current_wtxapi_symbol_name (module_info->undef_list);
+      printf_filtered ("\t%s\n", symbol_name);
+      xfree (symbol_name);
+    }
+  while (go_to_next_element_in_wtxapi_sym_list (module_info->undef_list));
+}
+
+/* Kill the task with the given CONTEXT_ID.
+   Print a warning if not successful.  */
+
+static void
+wtx_kill_one_task (WTX_CONTEXT_ID_T context_id)
+{
+  const int success = wtxapi_context_kill (WTX_CONTEXT_TASK, context_id);
+
+  /* Print a warning if we failed to kill the target task.
+     Do not throw an error as the failure is not serious enough
+     that we would abort the kill command, especially since one
+     possible reason for failing is if someone alreayd killed
+     the task using a different tool.  We just warn the user
+     and proceed as if the killing was successful.  The user
+     can then investigate more precisely why it failed and
+     try killing his task manually if necessary.  */
+  if (!success)
+    warning (_("Failed to kill task 0x%lx: %s"), context_id,
+             wtxapi_err_msg_get ());
+}
+
+/* Kill the task identified by TASK.  */
+
+static void
+wtx_kill_one_task_from_task_info (struct ada_task_info *task)
+{
+  wtx_kill_one_task (ptid_get_context_id (task->ptid));
+}
+
+/* Assuming we are currently debugging in multi-tasks mode,
+   kill all the tasks of inferior.  */
+
+static void
+wtx_kill_all_tasks (void)
+{
+  iterate_over_live_ada_tasks (wtx_kill_one_task_from_task_info);
+}
+
+/* Implement the "to_kill" method in task mode.  */
+
+static void
+wtx_task_mode_kill (struct target_ops *ops)
+{
+  if (ptid_equal (inferior_ptid, null_ptid))
+    {
+      /* brobecker/2007-09-28:  Can this really ever happen?
+         Add a warning to help us catch any situation where this
+         actually does happen, and only then return.  Eventually,
+         if we find that this has never happened after a few years,
+         then we can remove this entire block.  */
+      warning (_("cannot find id of task to kill"));
+      return;
+    }
+
+  if (multi_task_mode_is_on ())
+    wtx_kill_all_tasks ();
+  else
+    wtx_kill_one_task (ptid_get_context_id (inferior_ptid));
+
+  target_mourn_inferior ();
+}
+
+/* Implement the "to_kill" target_ops method when in "system" mode.
+   In pratice, one cannot kill the system task without rebooting it.
+   WindRiver chose to provide that command as a way of rebooting the
+   target, but it really is not that useful.  There are enough ways
+   to reboot a system already, no need to provide one extra in GDB.
+   So just tell the user that he cannot "kill" the system.  */
+
+static void
+wtx_system_mode_kill (struct target_ops *ops)
+{
+  error (_("The system cannot be killed."));
+}
+
+/* Implement the "load" command for the WTX protocol.
+
+   The usage is as follow:
+
+       load <filename> [remote filename]
+
+   where <filename> is the name of the module as seen from GDB,
+   and [remote filename] should the full path of module given to
+   the target server.  */
+
+static void
+wtx_load (char *args, int from_tty)
+{
+  char **argv = buildargv (args);
+  char *module_name = NULL;
+  /*  The name/path of the module as seen from the debugger.  */
+  char *gdb_path = NULL;
+  /*  Same thing but for the target server.  */
+  char *target_server_path = NULL;
+  int fd;
+  struct wtxapi_module_info *module_info;
+  struct objfile *objfile;
+
+  dont_repeat ();
+
+  if (argv == NULL)
+    error_no_arg (_("filename of module to load"));
+  make_cleanup_freeargv (argv);
+
+  /* Process the command line arguments, and issue a warning
+     if too many arguments were specified (we know at this point
+     that there is at least one argument so we cannot have too few
+     arguments).  */
+
+  module_name = argv[0];
+  target_server_path = argv[1];
+  if (argv[1] != NULL && argv[2] != NULL)
+    warning
+      (_("too many arguments (\"%s ...\"), extra arguments will be ignored"),
+       argv[2]);
+
+  /* Resolve the module_name into a full path name.  This allows us
+     to make sure we can open this file for reading (to load the
+     symbols), but more importantly, this allows us to pass an absolute
+     path to the target server if the remote filename was not provided
+     in the load command (TARGET_SERVER_PATH is NULL).  */
+
+  fd = openp (source_path, OPF_TRY_CWD_FIRST, module_name,
+	      O_RDONLY, &gdb_path);
+  if (fd < 0)
+    error (_("Unable to load %s: %s"), module_name, strerror (errno));
+  close (fd);
+
+  /* If the optional [remote filename] argument was not specified, then
+     use the full path of the module name.  */
+
+  if (target_server_path == NULL)
+    target_server_path = gdb_path;
+
+  /* Scan the list of object files; if the module has already been
+     loaded, then unload it first. At reload, the symbols loaded
+     previously are discarded by the target server; so they should
+     also be discarded by the debugger.  */
+
+  for (objfile = object_files; objfile; objfile = objfile->next)
+    {
+      if (strcmp (objfile->name, gdb_path) == 0)
+         {
+           unload_command (module_name, 0);
+           break;
+         }
+    }
+
+  /* Temporarily switch the timeout value to the load timeout, and
+     attempt to load the module on the board.  Error out if we failed.  */
+
+  printf_filtered (_("Downloading %s..."), target_server_path);
+  module_info = wtxapi_module_load (wtxapi_pd_current_get (),
+                                    target_server_path,
+                                    WTX_LOAD_GLOBAL_SYMBOLS,
+                                    wtx_opt_load_timeout () * 1000);
+  if (module_info == NULL)
+    error (_("Failed to load module %s: %s"), target_server_path,
+           wtxapi_err_msg_get ());
+
+  print_undefined_symbols (module_info);
+  printf_filtered (_("done.\n"));
+
+  /* Load the module symbols.  */
+  read_module_symbols_1 (module_info, gdb_path);
+  ada_language_auto_set ();
+}
+
+/* Implement the "to_create_inferior" target method.
+
+   Implementation Note:
+   We must get the address of the entry point directly from the target,
+   as opposed to from doing a local symbol lookups. This is necessary
+   in order to avoid using an incorrect address if some of our objfiles
+   are not up to date. This can happen for instance in the following
+   scenario:
+     - from GDB: load [app], run [app]
+     - from Windsh: unld "[app]", ld < [app]
+     - from GDB: run [app]
+   What would happen is that GDB would use an obsolete objfile (the
+   one from the previous run) to compute the address of the entry
+   point, thus leading to catastrophic errors...
+
+   Note that it is technically possible to load 2 modules on
+   the target with the same entry point. In this case, it is not
+   clear what would happen. Right now, we just assume that this
+   not going to happen. Anybody trying to do that would just be
+   shooting themselves in the foot...  */
+
+static void
+wtx_create_inferior (struct target_ops *ops, char *exec_file, char *args,
+                     char **env, int from_tty)
+{
+  struct wtxapi_context_desc context_desc;
+  struct cleanup *old_chain = NULL;
+  char **argv;
+  char *entry_name;
+  int new_context_id;
+
+  memset (&context_desc, 0, sizeof (context_desc));
+
+  /* Parse the arguments.  */
+
+  argv = buildargv (args);
+  if (argv == NULL)
+    nomem (0);
+  old_chain = make_cleanup_freeargv (argv);
+
+  /* Get the name of the entry point, which is the first argument.  */
+  entry_name = argv[0];
+  if (entry_name == NULL || entry_name[0] == '\0')
+    error_no_arg (_("module entry point"));
+
+  /* FIXME: brobecker/2007-09-26: Add handling of the arguments...
+     For now, pretend there are none.  */
+
+  TASK_CONTEXT_ARGC (context_desc) = 0;
+
+  /* Now, fill-in the rest of the CONTEXT_DESC structure.  */
+  remote_wtxapi_get_symbol_address
+    (entry_name, &TASK_CONTEXT_ENTRY (context_desc));
+  if (TASK_CONTEXT_ENTRY (context_desc) == 0)
+    error ("Failed to lookup entry point address");
+  TASK_CONTEXT_NAME (context_desc) = "tDbgTask";
+  TASK_CONTEXT_CONTEXT_TYPE (context_desc) = WTX_CONTEXT_TASK;
+  TASK_CONTEXT_STACK_SIZE (context_desc) = wtx_opt_stack_size ();
+  TASK_CONTEXT_OPTIONS (context_desc) = wtx_opt_task_options ();
+  TASK_CONTEXT_PRIORITY (context_desc) = wtx_opt_task_priority ();
+  TASK_CONTEXT_PDID (context_desc) = wtxapi_pd_current_get ();
+
+  /* New create a new context for that task.  */
+  new_context_id = wtxapi_context_create (&context_desc);
+  if (new_context_id == invalid_context_id)
+    error (_("failed to create task: %s"), wtxapi_err_msg_get ());
+
+  /* FIXME: brobecker/2007-09-26: Perform I/O redirection if necessary.  */
+
+  inferior_ptid = context_id_to_ptid (new_context_id);
+  wtx_add_inferior (inferior_ptid, 0);
+  push_target (&wtx_task_mode_ops);
+  register_for_exit_event (new_context_id);
+  inferior_status = WTX_TASK_STATUS_CREATED;
+
+  if (multi_task_mode_is_on ())
+    start_multi_task_mode ();
+
+  /* Do our cleanup actions.  */
+  do_cleanups (old_chain);
+}
+
+/* Find a given module using its name and unload it from the target.
+   The module lookup uses the module basename to do the matching.  */
+
+static void
+unload_module_from_target (const char *module_name)
+{
+  const char *base_name = lbasename (module_name);
+  const module_id_t module_id = wtxapi_obj_module_in_system_find_id (base_name);
+  pd_id_t module_pd;
+
+  if (module_id == invalid_module_id)
+    {
+      warning (_("could not find %s on target: %s"),
+               base_name, wtxapi_err_msg_get ());
+      return;
+    }
+
+  module_pd = wtx_pd_get_module_pd (module_id);
+
+  /* unload the object module */
+  if (!wtxapi_obj_module_unload (module_pd, module_id))
+      warning (_("could not unload %s from target: %s"),
+               base_name, wtxapi_err_msg_get ());
+
+}
+
+/* Return True if a module which name is equal to module_name is loaded
+   on the target.  */
+
+static int
+module_is_loaded_on_target (const char *module_name)
+{
+  module_id_t module_id;
+
+  module_id = wtxapi_obj_module_in_system_find_id (module_name);
+  return (module_id != invalid_module_id);
+}
+
+/* Search the global object_files list for the objfile associated to
+   the module whose name is BASE_NAME, and free it.  */
+
+static void
+free_module_objfile (const char *base_name)
+{
+  struct objfile *objfile;
+  struct objfile *temp;
+
+  /* search for matching objfile known to gdb, and free it */
+  ALL_OBJFILES_SAFE (objfile, temp)
+    {
+      if (!strcmp (lbasename (objfile->name), base_name))
+        {
+          const pd_id_t current_pd = wtxapi_pd_current_get ();
+
+          /* Print a message notifying the user that a module has been
+             unloaded.  If the target also supports PDs, then print the
+             PD id and name from which the module has been unloaded.  */
+          if (wtx_pd_system_has_pds ())
+            {
+              char *current_pd_name = wtx_pd_get_pd_name (current_pd);
+              printf_filtered (_("Unloaded file %s from PD 0x%lx (%s)\n"),
+                               objfile->name, current_pd, current_pd_name);
+              xfree (current_pd_name);
+            }
+          else
+            printf_filtered (_("Unloaded file %s\n"), objfile->name);
+          free_objfile (objfile);
+          return;
+        }
+    }
+  warning (_("could not unload module %s from gdb"), base_name);
+}
+
+/* Given the name of a module that has just been unloaded from
+   the target, discard all the symbols associated to that module.  */
+
+static void
+unload_module_symbols (const char *module_filename, int from_tty)
+{
+  const pd_id_t current_pd = wtxapi_pd_current_get ();
+  const char *module_name = lbasename (module_filename);
+  pd_id_t module_pd;
+  struct cleanup *old_chain = NULL;
+
+  /* Ignore this request if it comes from a WTX_EVENT_OBJ_UNLOADED event
+     and the object has been loaded back on the target.  We can safely
+     ignore this event because either:
+       - it has been reloaded from this debugger, in which case we
+         already updated our objfile
+       - it has been reloaded from another client (eg windsh), in
+         which case there is necessarily a pending WTX_EVENT_OBJ_LOADED
+         event, which will cause us to update our objfile.
+
+     Not ignoring this event is causing the debugger to destroy the
+     associated objfile in scenarios like this:
+       1/ from GDB: load <program>
+          (causes GDB to create an associated objfile)
+       2/ from Windsh: unload <program>
+       3/ from GDB: load <program>
+          (GDB correctly recreates the associated objfile)
+       4/ from GDB: run <program>
+          (causes GDB to process the "unloaded" wtx event from step 2,
+          hence destroying our good objfile)  */
+  if (!from_tty && module_is_loaded_on_target (module_name))
+    return;
+
+  module_pd = wtx_pd_get_unloaded_module_pd (module_name);
+  if (module_pd != current_pd)
+    {
+      wtx_pd_switch_to_pd (module_pd);
+      old_chain = wtx_pd_make_switch_to_pd_cleanup (current_pd);
+    }
+
+  free_module_objfile (module_name);
+
+  if (old_chain != NULL)
+    do_cleanups (old_chain);
+}
+
+/* Implement the "unload" command.  */
+
+static void
+unload_command (char *args, int from_tty)
+{
+  char **argv = buildargv (args);
+
+  dont_repeat ();
+
+  if (argv == NULL)
+    error_no_arg (_("module name to unload"));
+  make_cleanup_freeargv (argv);
+
+  unload_module_from_target (argv[0]);
+  unload_module_symbols (argv[0], from_tty);
+
+  /* Clear the Ada symbol cache, because it might contain some symbols
+     from the module we just unloaded.  */
+  clear_ada_sym_cache ();
+}
+
+/* Implements the to_xfer_partial method of the target vector for WTX.  */
+
+static LONGEST
+wtx_xfer_partial (struct target_ops *ops, enum target_object object,
+                  const char *annex, gdb_byte *readbuf,
+                  const gdb_byte *writebuf, ULONGEST offset, LONGEST len)
+{
+  int status;
+
+  /* The only object transfer that we support at this moment is memory
+     read/write.  */
+  if (object != TARGET_OBJECT_MEMORY)
+    return -1;
+
+  if (readbuf != NULL)
+    status = wtxapi_mem_read (wtxapi_pd_current_get (), offset, readbuf, len);
+  else
+    status = wtxapi_mem_write (wtxapi_pd_current_get (),
+                               (gdb_byte *) writebuf, offset, len);
+
+  if (status == WTX_ERROR)
+    return 0;  /* No further transfer possible???  */
+
+  return status;
+}
+
+/* Insert a breakpoint eventpoint using the information provided.
+   Return a non-zero errno code when the insertion failed.  */
+
+static int
+wtx_insert_breakpoint_1 (struct bp_target_info *target_info,
+                         WTX_CONTEXT_TYPE context_type,
+                         WTX_CONTEXT_ID_T context_id,
+                         WTX_ACTION_TYPE action_type,
+			 CORE_ADDR call_rtn)
+{
+  struct wtxapi_evtpt evtpt;
+  evtpt_id_t evtpt_id;
+
+  evtpt.context.context_type = context_type;
+  evtpt.context.context_id = context_id;
+  evtpt.action.action_type = action_type | WTX_ACTION_NOTIFY;
+  evtpt.event.event_type = WTX_EVENT_TEXT_ACCESS;
+  evtpt.event.num_args = 1;
+  evtpt.event.args = &target_info->placed_address;
+
+  if (call_rtn != 0)
+    evtpt.action.call_rtn = call_rtn;
+
+  evtpt_id = wtxapi_eventpoint_add (&evtpt);
+
+  if (evtpt_id == invalid_evtpt_id)
+    return ENOMEM;
+
+  wtx_bp_register_eventpoint_id (evtpt_id, target_info, context_type,
+				 context_id);
+
+  return 0;
+}
+
+/* Insert a task-mode breakpoint at the location specified by
+   TARGET_INFO.  TARGET_INFO is also used to determine what
+   scope & action to use for that breakpoint.
+
+   Return a non-zero errno code if the insertion failed.  */
+
+static int
+wtx_insert_task_mode_breakpoint (struct gdbarch *gdbarch,
+				 struct bp_target_info *target_info)
+{
+  const enum wtx_breakpoint_action action = get_break_command_action ();
+  WTX_CONTEXT_TYPE context_type;
+  WTX_CONTEXT_ID_T context_id;
+  WTX_ACTION_TYPE action_type;
+  CORE_ADDR call_rtn = 0;
+
+  context_type = WTX_CONTEXT_TASK;
+  context_id = ptid_get_context_id (inferior_ptid);
+
+  switch (action)
+    {
+      case action_task:
+        action_type = WTX_ACTION_STOP;
+        break;
+
+      case action_all:
+        action_type = WTX_ACTION_STOP_ALL;
+        break;
+
+      case action_call:
+        context_type = WTX_CONTEXT_ANY_TASK;
+        action_type =  WTX_ACTION_STOP;
+        call_rtn = get_break_command_call_rtn ();
+	if (call_rtn != 0)
+	  action_type |= WTX_ACTION_CALL;
+        break;
+
+      default:
+        internal_error (__FILE__, __LINE__, _("Unexpected action value: %d"),
+                        action);
+    }
+
+  return wtx_insert_breakpoint_1 (target_info, context_type, context_id,
+                                  action_type, call_rtn);
+}
+
+/* On systems that support partitions, we need to record for each
+   breakpoint/watchpoint the associated partition ID, which is
+   the current partition at the time when the breakpoint was
+   created.
+
+   We achieve this by using a couple of observers, one that will
+   notify us of the creation of new breakpoints, and one that will
+   notify us of their destruction.  They allow us to maintain a list
+   of (breakpoint, pd) elements that will later allow us to find
+   the PD associated to any breakpoint.
+
+   This is actually only useful when debugging in system mode, because
+   this is the only mode where we debug more than one partition.
+   However, we still need to maintain this information at all times,
+   because the user may be setting breakpoints while not in system
+   mode.
+
+   brobecker/2007-10-26:  This is probably not going to be the final
+   implementation for this concept.  For instance, it would probably
+   be nicer to have this information embedded directly inside the
+   breakpoint structure as a target-dependent data (like we do in
+   the gdbarch for instance), and avoid the need for the parallel
+   list that we're maintaining.
+
+   brobecker/2007-10-26: Another issue: When we insert breakpoints,
+   we are given a pointer to the target_info data. Not the bp_location.
+   Having the bp_location would allow us to directly find the associated
+   breakpoint, and from there its partition.
+
+   But all this needs to be discussed with the rest of the maintainers.
+   In the meantime, we're trying to make this change as contained as
+   possible.  */
+
+struct bp_partition_info
+{
+  struct breakpoint *b;
+  WTX_CONTEXT_ID_T partition_id;
+
+  struct bp_partition_info *next;
+};
+
+static struct bp_partition_info *bp_partition_list = NULL;
+
+/* Add the breakpoint/context-id pair to BP_PARTITION_LIST.  */
+
+static void
+add_bp_partition_info (struct breakpoint *b, WTX_CONTEXT_ID_T partition_id)
+{
+  struct bp_partition_info *info = xmalloc (sizeof (struct bp_partition_info));
+
+  info->b = b;
+  info->partition_id = partition_id;
+  info->next = bp_partition_list;
+
+  bp_partition_list = info;
+}
+
+/* Delete the element in BP_PARTITION_LIST corresponding to the given
+   breakpoint.  */
+
+static void
+delete_bp_partition_info (struct breakpoint *b)
+{
+  struct bp_partition_info *prev = NULL;
+  struct bp_partition_info *this = bp_partition_list;
+
+  while (this != NULL && this->b != b)
+    {
+      prev = this;
+      this = this->next;
+    }
+
+  if (this == NULL)
+    return;
+
+  if (this == bp_partition_list)
+    bp_partition_list = bp_partition_list->next;
+  else
+    prev->next = this->next;
+
+  xfree (this);
+}
+
+/* Find the breakpoint associated to the given TARGET_INFO and
+   return its corresponding partition ID.  */
+
+static WTX_CONTEXT_ID_T
+wtx_partition_id_from_target_info (struct bp_target_info *target_info)
+{
+  struct breakpoint *bp;
+
+  /* Shortcut: If the target system does not support more than one partition,
+     then we know which partition this breakpoint belongs to.  */
+  if (!wtx_pd_system_has_pds ())
+    return wtxapi_pd_current_get ();
+
+  error (_("Not implemented yet."));
+}
+
+/* Observer for the "breakpoint_created" event.  */
+
+static void
+wtx_breakpoint_created_observer (int bpnum)
+{
+  /* FIXME: The observer only passes the bpnum, which forces us
+     to do a reverse search for the associated breakpoint structure.
+     It is silly to have to do so when the observer had in fact
+     the breakpoint structure and had to dereference it in order to
+     pass the bpnum.  Propose that the observer be enhanced when
+     submitting this code to the FSF.  */
+  struct breakpoint *b = get_breakpoint (bpnum);
+
+  gdb_assert (b != NULL);
+  add_bp_partition_info (b, wtxapi_pd_current_get ());
+}
+
+/* Observer for the "delete_breakpoint" event.  */
+
+static void
+wtx_delete_breakpoint_observer (int bpnum)
+{
+  struct breakpoint *b = get_breakpoint (bpnum);
+
+  gdb_assert (b != NULL);
+  delete_bp_partition_info (b);
+}
+
+/* Insert a system-mode breakpoint at the location specified by TARGET_INFO.
+   Return a non-zero errno code if the insertion failed.  */
+
+static int
+wtx_insert_system_mode_breakpoint (struct gdbarch *gdbarch,
+				   struct bp_target_info *target_info)
+{
+  const WTX_CONTEXT_ID_T breakpoint_pd
+    = wtx_partition_id_from_target_info (target_info);
+
+  return wtx_insert_breakpoint_1 (target_info,
+                                  WTX_CONTEXT_SYSTEM, /* context_type */
+                                  breakpoint_pd,      /* context_id */
+                                  WTX_ACTION_STOP,    /* action_type */
+				  0);                 /* call_rtn */
+}
+
+/* Implement the "to_remove_breakpoint" method in the target_ops vector.  */
+
+static int
+wtx_remove_breakpoint (struct gdbarch *gdbarch,
+		       struct bp_target_info *target_info)
+{
+  WTX_CONTEXT_TYPE context_type;
+  WTX_CONTEXT_ID_T context_id;
+
+  const evtpt_id_t evtpt_id = wtx_bp_pop_eventpoint_id (target_info,
+							&context_type,
+							&context_id);
+
+  if (evtpt_id == invalid_evtpt_id)
+    {
+      warning (_("Cannot find eventpoint ID for breakpoint at 0x%lx"),
+               target_info->placed_address);
+      return EINVAL;
+    }
+
+  if (!wtxapi_eventpoint_delete (evtpt_id))
+    {
+      /* If this eventpoint is a task-specific eventpoint, and if the
+	 corresponding task is dead, then this eventpoint has already
+	 been deleted.  In this case, the error returned by
+	 wtxapi_eventpoint_delete is expected.  Ignore it.*/
+      if (context_type == WTX_CONTEXT_TASK
+	  && !wtx_context_alive (context_id))
+	return 0;
+
+      warning (_("Failed to delete eventpoint for breakpoint at 0x%lx"),
+               target_info->placed_address);
+      return EINVAL;
+    }
+
+  return 0;
+}
+
+/* Implement the target_can_use_hw_breakpoint target method for
+   the targets that support BoDA events.  */
+
+static int
+can_use_BoDA_breakpoint (int bp_type, int count, int other_type)
+{
+  /* BoDA events provide all types of watchpoints, read, write, access,
+     so it's not necessary to check BP_TYPE.  */
+
+  /* The system only provides one BoDA event.  */
+  if (count < 2)
+    return 1;
+
+  /* All the conditions to use a hardware watchpoint are not met, so
+     we cannot use one.  */
+  return 0;
+}
+
+/* Implement the target_can_use_hw_breakpoint target method for
+   the targets where we use data-access events to implement watchpoints.  */
+
+static int
+can_use_data_access_breakpoint (int bp_type, int count, int other_type)
+{
+  /* Data-access events provide all types of watchpoints, read, write,
+     access, so it's not necessary to check BP_TYPE.  */
+
+  /* The system only provides one data-access event.  */
+  if (count < 2)
+    return 1;
+
+  /* All the conditions to use a hardware watchpoint are not met, so
+     we cannot use one.  */
+  return 0;
+}
+
+/* Implement the target_can_use_hw_breakpoint target method for all WTX
+   targets.  */
+
+static int
+wtx_can_use_hw_breakpoint (int bp_type, int count, int other_type)
+{
+  /* Tornado systems provide at most one hardware watchpoint,
+     so if another type of watchpoint is already being used,
+     then we have no hardware watchpoint left.  Return -1 to
+     signal that the rejection is because of OTHER_TYPE.  */
+  if (other_type)
+    return -1;
+
+  if (wtxapi_target_has_BoDA ())
+    return can_use_BoDA_breakpoint (bp_type, count, other_type);
+
+  /* On targets that do not support BoDA, we have access to
+     data-access events.  Try using that as a fallback.  */
+  if (can_use_data_access_breakpoint (bp_type, count, other_type))
+    return 1;
+
+  /* The system cannot provide hardware watchpoint support for this case.  */
+  return 0;
+}
+
+/* Return non-zero if we just stopped after hitting a watchpoint.  */
+
+static int
+wtx_stopped_by_watchpoint (void)
+{
+  int result = (watchpoint_data_address != 0);
+
+  wtx_opt_watchpoints_debug ("wtx_stopped_by_watchpoint() -> %d", result);
+
+  return result;
+}
+
+/* Return the address monitored by the watchpoint we just hit.  */
+
+static int
+wtx_stopped_data_address (struct target_ops *target, CORE_ADDR *addr_p)
+{
+  const int success = wtx_stopped_by_watchpoint ();
+
+  if (wtx_stopped_by_watchpoint ())
+    {
+      *addr_p = watchpoint_data_address;
+      wtx_opt_watchpoints_debug ("wtx_stopped_data_address(0x%s) -> 1",
+                                 paddress (target_gdbarch, *addr_p));
+      return 1;
+    }
+
+  wtx_opt_watchpoints_debug ("wtx_stopped_data_address() -> 0");
+  return 0;
+}
+
+/* Implement the region_ok_for_hw_watchpoint target method for
+   targets that support BoDA.  */
+
+static int
+region_ok_for_BoDA (CORE_ADDR addr, int len)
+{
+  /* BoDA events only allow us to watch a data that is 4 bytes
+     long.  Apparently, there are no constraints in terms of
+     alignment, so we don't need to worry about it.  */
+  return (len <= 4);
+}
+
+/* Return non-zero if a WTX_EVENT_DATA_ACCESS event can watch
+   a memory region of LEN bytes.  */
+
+static int
+region_ok_for_data_access_event (CORE_ADDR addr, int len)
+{
+  /* brobecker/2006-09-27: As far as I know, DATA_ACCESS events
+     can only monitor 4-byte memory regions.  */
+  return (len <= 4);
+}
+
+
+/* Implement the region_ok_for_hw_watchpoint for all tornado targets.
+   Basicallly determines the type of watchpoint the target supports and
+   dispatches to the appropriate function.  */
+
+static int
+wtx_region_ok_for_hw_watchpoint (CORE_ADDR addr, int len)
+{
+  if (wtxapi_target_has_BoDA ())
+    return region_ok_for_BoDA (addr, len);
+
+  return (region_ok_for_data_access_event (addr, len));
+}
+
+/* Given the watchpoint type that needs to be inserted (that follows
+   GDB's encoding), return the equivalent value to be used in WTX
+   event insertion requests.  */
+
+static wtxapi_tgt_addr_t
+gdb_watchpoint_type_to_wtx_breakpoint_type (int type)
+{
+  switch (type)
+    {
+      case hw_write: return 3; break;
+      case hw_read:  return 2; break;
+      case hw_access: return 1; break;
+      case hw_execute: return 0; break;
+    }
+
+  /* We should never reach this code.  If we do, print a warning and
+     pretend we were trying to use a read+write=access watchpoint type.  */
+  warning (_("unexpected watchpoint type: %d"), type);
+  return gdb_watchpoint_type_to_wtx_breakpoint_type (hw_access);
+}
+
+/* Fill up EVENT with all the necessary information to insert
+   a WTX_EVENT_HW_BP eventpoint.
+
+   Even though this function does not setup EVENT to insert a BoDA,
+   this function assumes that the target does support BoDA.  If not,
+   use set_data_access_event below.  */
+
+static void
+set_hardware_watchpoint_event_no_value (struct wtxapi_event *event,
+                                        CORE_ADDR addr,
+                                        int type)
+{
+  event->event_type = WTX_EVENT_HW_BP;
+
+  /* WTX_EVENT_HW_BP eventpoints have 3 arguments:
+       . args[0] is the address of the data being watched.
+       . args[1] is the watchpoint count (the number of times
+                 the watchpoint should be hit before generating
+                 an event to the debugger). Unused by us, always
+                 set to 0.
+       . args[2] is the type of watchpoint (read/write/access).  */
+  event->num_args = 3;
+  event->args[0] = addr;
+  event->args[1] = 0;
+  event->args[2] = gdb_watchpoint_type_to_wtx_breakpoint_type (type);
+
+  wtx_opt_watchpoints_debug
+    ("Using WTX_EVENT_HW_BP event (addr = 0x%s, type = %d)",
+     paddress (target_gdbarch, event->args[0]), (int) event->args[2]);
+}
+
+/* Fill up EVENT with all the necessary information to insert
+   a WTX_EVENT_DATA_ACCESS eventpoint.
+
+   This function should be used with all systems that do NOT support BoDA.  */
+
+static void
+set_data_access_event (struct wtxapi_event *event,
+                       const CORE_ADDR addr,
+                       const int type)
+{
+  event->event_type = WTX_EVENT_DATA_ACCESS;
+
+  /* WTX_EVENT_DATA_ACCESS eventpoints have 3 arguments:
+       . args[0] is the address of the data being watched.
+       . args[1] is the watchpoint count (the number of times
+                 the watchpoint should be hit before generating
+                 an event to the debugger). Unused by us, always
+                 set to 0.
+       . args[2] is the type of watchpoint (read/write/access).  */
+  event->num_args = 3;
+  event->args[0] = addr;
+  event->args[1] = 0;
+  event->args[2] = gdb_watchpoint_type_to_wtx_breakpoint_type (type);
+
+  wtx_opt_watchpoints_debug
+    ("Using DATA_ACCESS event (addr = 0x%s, type = %d)",
+     paddress (target_gdbarch, event->args[0]), (int) event->args[2]);
+}
+
+/* Implement the target_insert_watchpoint target method for all WTX
+   targets.  */
+
+static int
+wtx_insert_watchpoint (WTX_CONTEXT_TYPE context_type,
+                       WTX_CONTEXT_ID_T context_id,
+                       WTX_ACTION_TYPE action_type,
+                       CORE_ADDR addr, int len, int type)
+{
+  struct wtxapi_evtpt evtpt;
+  wtxapi_tgt_arg_t args[4];
+  evtpt_id_t watchpoint_id;
+
+  /* First, clear the evtpt struture.  In other parts of this file,
+     we actually calloc this structure which makes the memset unecessary,
+     but doing it this way avoids the need to free the newly allocated
+     memory.  */
+  memset (&evtpt, 0, sizeof (evtpt));
+
+  evtpt.context.context_type = context_type;
+  evtpt.context.context_id = context_id;
+  evtpt.action.action_type = action_type;
+  evtpt.event.args = args;
+
+  /* Tell the target server to notify us when the watchpoint is hit.  */
+  evtpt.action.action_type |= WTX_ACTION_NOTIFY;
+
+  /* If the system provides data-matching support with its watchpoints,
+     and the watchpoint has a condition that can be tested using that
+     support, then use it.  The data value in BoDA watchpoints will
+     be optional.  */
+
+  if (wtxapi_target_has_BoDA ())
+    set_hardware_watchpoint_event_no_value (&evtpt.event, addr, type);
+  else
+    set_data_access_event (&evtpt.event, addr, type);
+
+  /* Insert the eventpoint.  */
+  watchpoint_id = wtxapi_eventpoint_add (&evtpt);
+
+  if (watchpoint_id == invalid_evtpt_id)
+    error (_("Failed to insert watchpoint"));
+
+  /* Save the watchpoint_id in our list of eventpoints.  Will be needed
+     later to map GDB watchpoints info back into WTX event ids.  */
+  wtx_bp_register_watchpoint_id (watchpoint_id, addr, len, type);
+
+  return 0;
+}
+
+/* Implement the task-mode "to_insert_watchpoint" target_ops method.  */
+
+static int
+wtx_insert_task_mode_watchpoint (CORE_ADDR addr, int len, int type)
+{
+  const enum wtx_breakpoint_action action = get_break_command_action ();
+  WTX_CONTEXT_TYPE context_type;
+  WTX_CONTEXT_ID_T context_id;
+  WTX_ACTION_TYPE action_type;
+  CORE_ADDR call_rtn = 0;
+
+  /* FIXME: We do the exact same thing when inserting a task-mode
+     breakpoint.  Put this code inside remote-wtx-bp and then reuse.  */
+  context_type = WTX_CONTEXT_TASK;
+  context_id = ptid_get_context_id (inferior_ptid);
+
+  switch (action)
+    {
+      case action_task:
+        action_type = WTX_ACTION_STOP;
+        break;
+
+      case action_all:
+        action_type = WTX_ACTION_STOP_ALL;
+        break;
+
+      case action_call:
+        context_type = WTX_CONTEXT_ANY_TASK;
+        action_type =  WTX_ACTION_STOP;
+        call_rtn = get_break_command_call_rtn ();
+	if (call_rtn != 0)
+	  action_type |= WTX_ACTION_CALL;
+        break;
+
+      default:
+        internal_error (__FILE__, __LINE__, _("Unexpected action value: %d"),
+                        action);
+    }
+
+  return wtx_insert_watchpoint (context_type, context_id,
+                                action_type, addr, len, type);
+}
+
+/* Implement the system-mode "to_insert_watchpoint" target_ops method.  */
+
+static int
+wtx_insert_system_mode_watchpoint (CORE_ADDR addr, int len, int type)
+{
+  return wtx_insert_watchpoint (WTX_CONTEXT_SYSTEM, SYSTEM_CID,
+                                WTX_ACTION_STOP, addr, len, type);
+}
+
+/* Implement the "to_remove_watchpoint" target_ops method.  */
+
+static int
+wtx_remove_watchpoint (CORE_ADDR addr, int len, int type)
+{
+  const evtpt_id_t watchpoint_id = wtx_bp_pop_watchpoint_id (addr, len, type);
+
+  if (watchpoint_id == invalid_evtpt_id)
+    {
+      warning (_("Unknown watchpoint at 0x%s (len = %d, type = %d)"),
+               paddress (target_gdbarch, addr), len, type);
+      return EINVAL;
+    }
+
+  if (!wtxapi_eventpoint_delete (watchpoint_id))
+    {
+      warning (_("Unable to remove watchpoint id 0x%x"), watchpoint_id);
+      return EINVAL;
+    }
+
+  return 0;
+}
+
+/* Implement the "to_mourn_inferior" method of the target_ops vector
+   for the task mode.  */
+
+static void
+wtx_task_mode_mourn_inferior (struct target_ops *ops)
+{
+  remove_breakpoints ();
+  if (multi_task_mode_is_on ())
+    stop_multi_task_mode ();
+
+  unpush_target (&wtx_task_mode_ops);
+  generic_mourn_inferior ();
+}
+
+/* Return 1 if the thread whose id is CONTEXT_ID is still alive.  */
+
+static int
+wtx_context_alive (int context_id)
+{
+  struct wtxapi_thread_info *thread_list = wtxapi_get_thread_list ();
+  struct wtxapi_thread_info *thread;
+  int is_alive = 0;
+
+  for (thread = thread_list; thread != NULL; thread = thread->next)
+    if (thread->id == context_id)
+      {
+        is_alive = 1;
+        break;
+      }
+  free_wtxapi_thread_info (thread_list);
+
+  return is_alive;
+}
+
+/* Implement the "to_thread_alive" method of the target_ops vector.  */
+
+static int
+wtx_thread_alive (struct target_ops *ops, ptid_t ptid)
+{
+  const int context_id = ptid_get_context_id (ptid);
+  return wtx_context_alive (context_id);
+}
+
+/* Implement the "to_find_new_threads" method when in single-task mode.  */
+
+static void
+wtx_single_task_mode_find_new_threads (void)
+{
+  /* In this mode, we only debug one thread.  */
+  wtx_add_thread (inferior_ptid);
+}
+
+/* Add the thread associated to the given TASK to the thread list.
+   Does nothing if that thread was already added earlier.  */
+
+static void
+wtx_multi_task_mode_add_thread_from_task (struct ada_task_info *task)
+{
+  wtx_add_thread (task->ptid);
+}
+
+/* Implement the "to_find_new_threads" method when in multi-tasks mode.  */
+
+static void
+wtx_multi_task_mode_find_new_threads (void)
+{
+  iterate_over_live_ada_tasks (wtx_multi_task_mode_add_thread_from_task);
+}
+
+/* Implement the "to_find_new_threads" method of the task-mode target_ops
+   vector.  Handles both single-task and multi-tasks modes.  */
+
+static void
+wtx_task_mode_find_new_threads (struct target_ops *ops)
+{
+  if (multi_task_mode_is_on ())
+    wtx_multi_task_mode_find_new_threads ();
+  else
+    wtx_single_task_mode_find_new_threads ();
+}
+
+/* Implement the "to_find_new_threads" method of the system-mode
+   target_ops vector.  */
+
+static void
+wtx_system_mode_find_new_threads (struct target_ops *ops)
+{
+  struct wtxapi_thread_info *thread_list = wtxapi_get_thread_list ();
+  struct wtxapi_thread_info *thread;
+
+  for (thread = thread_list; thread != NULL; thread = thread->next)
+    {
+      const ptid_t thread_ptid = context_id_to_ptid (thread->id);
+
+      wtx_add_thread (thread_ptid);
+    }
+
+  free_wtxapi_thread_info (thread_list);
+}
+
+/* Suspend the given CONTEXT_TYPE/CONTEXT_ID.  */
+
+static void
+wtx_stop (WTX_CONTEXT_TYPE context_type, WTX_CONTEXT_ID_T context_id)
+{
+  if (multi_task_mode_is_on ())
+    stop_all_ada_tasks (&inferior_status);
+  else
+    stop_inferior (context_type, context_id);
+}
+
+/* Implement the task-mode "to_stop" target_ops method.  */
+
+static void
+wtx_task_mode_stop (ptid_t ptid)
+{
+  const WTX_CONTEXT_ID_T context_id = ptid_get_context_id (ptid);
+
+  wtx_stop (WTX_CONTEXT_TASK, context_id);
+}
+
+/* Implement the system-mode "to_stop" target_ops method.  */
+
+static void
+wtx_system_mode_stop (ptid_t ptid)
+{
+  wtx_stop (WTX_CONTEXT_SYSTEM, SYSTEM_CID);
+  inferior_ptid =
+    context_id_to_ptid (wtxapi_system_mode_get_current_context_id ());
+}
+
+/* Return the name of a task from its CONTEXT_ID, or NULL if the task
+   could not be found.
+
+   The returned string must be deallocated after use.  */
+
+static char *
+wtx_name_from_context_id (WTX_CONTEXT_ID_T context_id)
+{
+  struct wtxapi_thread_info *threads = wtxapi_get_thread_list ();
+  struct wtxapi_thread_info *this_thread = threads;
+  char *name = NULL;
+
+  while (this_thread != NULL)
+    {
+      if (this_thread->id == context_id)
+        {
+	  name = xstrdup (this_thread->name);
+	  break;
+	}
+      this_thread = this_thread->next;
+    }
+
+  free_wtxapi_thread_info (threads);
+  return name;
+}
+
+/* Implement the "to_pid_to_str" target_ops method.  */
+
+static char *
+wtx_pid_to_str (struct target_ops *ops, ptid_t ptid)
+{
+  static char *buf = NULL;
+  const WTX_CONTEXT_ID_T context_id = ptid_get_context_id (ptid);
+  char *task_name = wtx_name_from_context_id (context_id);
+
+  if (buf != NULL)
+    xfree (buf);
+  xasprintf (&buf, "task 0x%lx\t(%s)\t", context_id,
+             task_name ? task_name : "[no name]");
+  if (task_name != NULL)
+    xfree (task_name);
+
+  return buf;
+}
+
+/* Implement the to_get_ada_task_ptid function for the WTX targets.  */
+
+static ptid_t
+wtx_get_ada_task_ptid (long lwp, long thread)
+{
+  return context_id_to_ptid (thread);
+}
+
+/* Always return zero.  */
+
+static int
+wtx_return_zero (struct target_ops *target)
+{
+  return 0;
+}
+
+/* Always return one.  */
+
+static int
+wtx_return_one (struct target_ops *target)
+{
+  return 1;
+}
+
+/* Initialize the WTX_OPS target_ops object.  */
+
+static void
+init_wtx_ops (void)
+{
+  /* First, clear the structure.  This is not strictly necessary provided
+     we make sure to always set all the fields of the our structure.
+     But in the event that we did not, this makes sure that the fields
+     we missed are initialized to something consistent.  */
+  memset (&wtx_ops, 0, sizeof (wtx_ops));
+
+  wtx_ops.to_shortname = "wtx";
+  wtx_ops.to_longname = "WTX protocol";
+  wtx_ops.to_doc = "\
+Remote target connected via the WTX protocol.\n\
+Specify the name of the target server as the argument.";
+  wtx_ops.to_open = wtx_open;
+  wtx_ops.to_close = wtx_close;
+  wtx_ops.to_attach = wtx_attach;
+  /* No need to set to_detach, will never be called, because the detach
+     option from a higher stratum will be used instead.  */
+  wtx_ops.to_load = wtx_load;
+  wtx_ops.to_create_inferior = wtx_create_inferior;
+  wtx_ops.to_pid_to_str = wtx_pid_to_str;
+  wtx_ops.to_stratum = core_stratum;
+  wtx_ops.to_has_all_memory = wtx_return_one;
+  wtx_ops.to_has_memory = wtx_return_one;
+  wtx_ops.to_has_stack = wtx_return_zero;
+  wtx_ops.to_has_registers = wtx_return_zero;
+  wtx_ops.to_has_execution = wtx_return_zero;
+  wtx_ops.to_xfer_partial = wtx_xfer_partial;
+  wtx_ops.to_get_ada_task_ptid = wtx_get_ada_task_ptid;
+  wtx_ops.to_magic = OPS_MAGIC;
+}
+
+static void
+init_wtx_task_mode_ops (void)
+{
+  /* First, clear the structure.  This is not strictly necessary provided
+     we make sure to always set all the fields of the our structure.
+     But in the event that we did not, this makes sure that the fields
+     we missed are initialized to something consistent.  */
+  memset (&wtx_task_mode_ops, 0, sizeof (wtx_task_mode_ops));
+
+  wtx_task_mode_ops.to_shortname = "wtx task mode";
+  wtx_task_mode_ops.to_longname =
+    "Task and Multi-tasks Mode support for the WTX protocol";
+  wtx_task_mode_ops.to_doc =
+    "Debugging a task or a set of tasks using the WTX protocol.";
+  wtx_task_mode_ops.to_open = NULL;
+  wtx_task_mode_ops.to_close = wtx_task_mode_close;
+  wtx_task_mode_ops.to_attach = wtx_attach;
+  wtx_task_mode_ops.to_detach = wtx_task_mode_detach;
+  wtx_task_mode_ops.to_resume = wtx_task_mode_resume;
+  wtx_task_mode_ops.to_wait = wtx_wait;
+  wtx_task_mode_ops.to_fetch_registers = wtx_task_mode_fetch_registers;
+  wtx_task_mode_ops.to_store_registers = wtx_task_mode_store_registers;
+  wtx_task_mode_ops.to_prepare_to_store = wtx_prepare_to_store;
+  wtx_task_mode_ops.to_insert_breakpoint = wtx_insert_task_mode_breakpoint;
+  wtx_task_mode_ops.to_remove_breakpoint = wtx_remove_breakpoint;
+  wtx_task_mode_ops.to_can_use_hw_breakpoint = wtx_can_use_hw_breakpoint;
+  wtx_task_mode_ops.to_remove_watchpoint = wtx_remove_watchpoint;
+  wtx_task_mode_ops.to_insert_watchpoint = wtx_insert_task_mode_watchpoint;
+  wtx_task_mode_ops.to_stopped_by_watchpoint = wtx_stopped_by_watchpoint;
+  wtx_task_mode_ops.to_stopped_data_address = wtx_stopped_data_address;
+  wtx_task_mode_ops.to_region_ok_for_hw_watchpoint =
+    wtx_region_ok_for_hw_watchpoint;
+
+  wtx_task_mode_ops.to_kill = wtx_task_mode_kill;
+  wtx_task_mode_ops.to_load = wtx_load;
+  wtx_task_mode_ops.to_mourn_inferior = wtx_task_mode_mourn_inferior;
+  wtx_task_mode_ops.to_thread_alive = wtx_thread_alive;
+  wtx_task_mode_ops.to_find_new_threads = wtx_task_mode_find_new_threads;
+  wtx_task_mode_ops.to_stop = wtx_task_mode_stop;
+  wtx_task_mode_ops.to_stratum = process_stratum;
+  wtx_task_mode_ops.to_has_all_memory = wtx_return_one;
+  wtx_task_mode_ops.to_has_memory = wtx_return_one;
+  wtx_task_mode_ops.to_has_stack = wtx_return_one;
+  wtx_task_mode_ops.to_has_registers = wtx_return_one;
+  wtx_task_mode_ops.to_has_execution = wtx_return_one;
+  wtx_task_mode_ops.to_xfer_partial = wtx_xfer_partial;
+  wtx_task_mode_ops.to_magic = OPS_MAGIC;
+}
+
+static void
+init_wtx_system_mode_ops (void)
+{
+  /* First, clear the structure.  This is not strictly necessary provided
+     we make sure to always set all the fields of the our structure.
+     But in the event that we did not, this makes sure that the fields
+     we missed are initialized to something consistent.  */
+  memset (&wtx_system_mode_ops, 0, sizeof (wtx_system_mode_ops));
+
+  wtx_system_mode_ops.to_shortname = "wtx system mode";
+  wtx_system_mode_ops.to_longname =
+    "System Mode support for the WTX protocol";
+  wtx_system_mode_ops.to_doc =
+    "Debugging a target in system mode using the WTX protocol.";
+  wtx_system_mode_ops.to_open = NULL;
+  wtx_system_mode_ops.to_close = wtx_system_mode_close;
+  wtx_system_mode_ops.to_attach = wtx_attach;
+  wtx_system_mode_ops.to_detach = wtx_system_mode_detach;
+  wtx_system_mode_ops.to_resume = wtx_system_mode_resume;
+  wtx_system_mode_ops.to_wait = wtx_wait;
+  wtx_system_mode_ops.to_fetch_registers = wtx_system_mode_fetch_registers;
+  wtx_system_mode_ops.to_store_registers = wtx_system_mode_store_registers;
+  wtx_system_mode_ops.to_prepare_to_store = wtx_prepare_to_store;
+  wtx_system_mode_ops.to_insert_breakpoint = wtx_insert_system_mode_breakpoint;
+  wtx_system_mode_ops.to_remove_breakpoint = wtx_remove_breakpoint;
+  wtx_system_mode_ops.to_can_use_hw_breakpoint = wtx_can_use_hw_breakpoint;
+  wtx_system_mode_ops.to_remove_watchpoint = wtx_remove_watchpoint;
+  wtx_system_mode_ops.to_insert_watchpoint = wtx_insert_system_mode_watchpoint;
+  wtx_system_mode_ops.to_stopped_by_watchpoint = wtx_stopped_by_watchpoint;
+  wtx_system_mode_ops.to_stopped_data_address = wtx_stopped_data_address;
+  wtx_system_mode_ops.to_region_ok_for_hw_watchpoint =
+    wtx_region_ok_for_hw_watchpoint;
+
+  wtx_system_mode_ops.to_kill = wtx_system_mode_kill;
+  wtx_system_mode_ops.to_load = wtx_load;
+  wtx_system_mode_ops.to_thread_alive = wtx_thread_alive;
+  wtx_system_mode_ops.to_find_new_threads = wtx_system_mode_find_new_threads;
+  wtx_system_mode_ops.to_stop = wtx_system_mode_stop;
+  wtx_system_mode_ops.to_stratum = process_stratum;
+  wtx_system_mode_ops.to_has_all_memory = wtx_return_one;
+  wtx_system_mode_ops.to_has_memory = wtx_return_one;
+  wtx_system_mode_ops.to_has_stack = wtx_return_one;
+  wtx_system_mode_ops.to_has_registers = wtx_return_one;
+  wtx_system_mode_ops.to_has_execution = wtx_return_one;
+  wtx_system_mode_ops.to_xfer_partial = wtx_xfer_partial;
+  wtx_system_mode_ops.to_magic = OPS_MAGIC;
+}
+
+void
+_initialize_remote_wtx (void)
+{
+  /* Initialize the WTX library.  */
+  if (!wtxapi_initialize ())
+    {
+      warning (_("Failed to initialize WTX library:\n\t%s\n\
+(WTX target not activated)."),
+               wtxapi_err_msg_get ());
+
+      /* We cannot use the WTX protocol if for some reason we failed
+         to initialized the WTX API. So abort now, instead of pushing
+         the WTX target ops.  */
+      return;
+    }
+
+  init_wtx_ops ();
+  init_wtx_task_mode_ops ();
+  init_wtx_system_mode_ops ();
+
+  add_target (&wtx_ops);
+
+  /* New commands.  */
+
+  add_com ("unload", class_files, unload_command,
+           _("Unload the given module from the target"));
+
+  /* Observers.  */
+
+  if (wtx_pd_system_has_pds ())
+    {
+      /* The following observers are only useful when the target system
+         supports partitions.  */
+      observer_attach_breakpoint_created (wtx_breakpoint_created_observer);
+      observer_attach_breakpoint_deleted (wtx_delete_breakpoint_observer);
+    }
+}
diff --git a/gdb/remote-wtx.h b/gdb/remote-wtx.h
new file mode 100644
index 0000000..266369e
--- /dev/null
+++ b/gdb/remote-wtx.h
@@ -0,0 +1,25 @@
+/* WTX backend for GDB.
+
+   Copyright 2007, 2010 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#ifndef REMOTE_WTX_H
+#define REMOTE_WTX_H
+
+extern void wtx_open (char *args, int from_tty);
+
+#endif
-- 
1.6.3.3

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

* [vxworks 02/14] New command_post observer.
  2010-04-25 15:47 Adding support for VxWorks target Joel Brobecker
  2010-04-25 15:47 ` [vxworks 01/14] Some ada-lang/ada-tasks routines needed by the " Joel Brobecker
  2010-04-25 15:48 ` [vxworks 10/14] Add new "wtx" target Joel Brobecker
@ 2010-04-25 15:48 ` Joel Brobecker
  2010-04-26 18:51   ` Tom Tromey
  2010-04-25 15:48 ` [vxworks 14/14] Configury and Makefile updates for VxWorks Joel Brobecker
                   ` (12 subsequent siblings)
  15 siblings, 1 reply; 27+ messages in thread
From: Joel Brobecker @ 2010-04-25 15:48 UTC (permalink / raw)
  To: gdb-patches

Just as the current language, or current inferior, or current thread,
affect some of the commands being issued by the user to the debugger,
with multi-partition systems, we now have a current partition (formerly
known as a Protection Domain, or PD).

What we are trying to do is to keep the user informed of the current
PD (which is identified by either PD ID or name, but we like to print
both).

The problem is that we cannot just print a message everytime the PD
gets switched, because many commands result in a temporary switch of
partition.  For instance, info threads will need to switch to the
associated PDs in order to get the PC and associated symbolic info.
We don't want to write the notification for each switch. However, we
do want to print that notification if we just hit a breakpoint for
some code living in a different partition...

The way we solved this is by remembering the PD ID before we issued
the last command.  At the end of a command execution, if the PD ID
changed, then we write a notification...

This patch introduces an observer (command_post) that gets triggered
at the end of a command execution...

2010-04-24  Joel Brobecker  <brobecker@adacore.com>

        * doc/observer.texi (command_post): New observer.
        * top.c: #include "observer.h".
        (execute_command): Call observer_notify_command_post.
---
 gdb/doc/observer.texi |    4 ++++
 gdb/top.c             |    4 ++++
 2 files changed, 8 insertions(+), 0 deletions(-)

diff --git a/gdb/doc/observer.texi b/gdb/doc/observer.texi
index e19b8ed..ceb5b87 100644
--- a/gdb/doc/observer.texi
+++ b/gdb/doc/observer.texi
@@ -132,6 +132,10 @@ Called with @var{objfile} equal to @code{NULL} to indicate
 previously loaded symbol table data has now been invalidated.
 @end deftypefun
 
+@deftypefun void command_post (void)
+The debugger just finished executing a command.
+@end deftypefun
+
 @deftypefun void new_thread (struct thread_info *@var{t})
 The thread specified by @var{t} has been created.
 @end deftypefun
diff --git a/gdb/top.c b/gdb/top.c
index dc2104c..e7eb4e6 100644
--- a/gdb/top.c
+++ b/gdb/top.c
@@ -63,6 +63,7 @@
 #include <ctype.h>
 #include "ui-out.h"
 #include "cli-out.h"
+#include "observer.h"
 
 /* Default command line prompt.  This is overriden in some configs. */
 
@@ -475,6 +476,9 @@ execute_command (char *p, int from_tty)
 	  warned = 1;
 	}
     }
+
+  /* Emit the "command_post" notification.  */
+  observer_notify_command_post ();
 }
 
 /* Read commands from `instream' and execute them
-- 
1.6.3.3

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

* [vxworks 11/14] WTX-TCL support module.
  2010-04-25 15:47 Adding support for VxWorks target Joel Brobecker
                   ` (5 preceding siblings ...)
  2010-04-25 15:48 ` [vxworks 08/14] Partition support Joel Brobecker
@ 2010-04-25 15:48 ` Joel Brobecker
  2010-04-25 15:48 ` [vxworks 13/14] Add tdep files for x86 and powerpc Joel Brobecker
                   ` (8 subsequent siblings)
  15 siblings, 0 replies; 27+ messages in thread
From: Joel Brobecker @ 2010-04-25 15:48 UTC (permalink / raw)
  To: gdb-patches

For VxWorks 5.x and 653, we need to use the TCL extension in order to
access some of the information we are looking for (list of VxWorks
tasks running on the target, for instance).  This is only because
the WTX protocol does not provide access to this info.

2010-04-24  Joel Brobecker  <brobecker@adacore.com>

        * remote-wtx-tcl.c: New file.
---
 gdb/remote-wtx-tcl.c |  493 ++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 493 insertions(+), 0 deletions(-)
 create mode 100644 gdb/remote-wtx-tcl.c

diff --git a/gdb/remote-wtx-tcl.c b/gdb/remote-wtx-tcl.c
new file mode 100644
index 0000000..760d20c
--- /dev/null
+++ b/gdb/remote-wtx-tcl.c
@@ -0,0 +1,493 @@
+/* Access to the TCL module in VxWorks systems.
+
+   Copyright 2007, 2010 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#include "defs.h"
+#include "command.h"
+#include "gdb_string.h"
+#include "remote-wtx-opt.h"
+#include "remote-wtxapi.h"
+#include "gdb_stat.h"
+#include "gdb_assert.h"
+#include "remote-wtx-pd.h"
+#include "remote-wtx-utils.h"
+
+/* Includes from the VxWorks install.  */
+#define HOST
+#include "tcl.h"
+#if WTX_PROT_VERSION != 4
+#include "wtxtcl.h"
+#endif
+
+/* Some functions provided by libwtxtcl that we use.  These are resolved
+   during this unit's initialization phase.  */
+static char * (*wtx_tcl_handle_grant) (Tcl_Interp *pInterp, HWTX hWtx);
+static int (*wtx_tcl_init) (Tcl_Interp *pInterp);
+
+/* Non-zero if the system provides support for computing the address
+   of the memory region where the FP registers are saved for each task.
+   Zero otherwise.  */
+static int tcb_has_fp_regs_p = 0;
+
+static Tcl_Interp *tcl_handle = NULL;
+
+/* Evaluate the given TCL expression (STR), and return non-zero if
+   successful.
+
+   When successful, then OUTPUT will contain the evaluation output.
+   When the evaluation fails, OUTPUT contains the error message.  */
+
+static int
+wtxtcl_eval (char *str, char **output)
+{
+  const int status = Tcl_Eval (tcl_handle, str);
+
+  if (tcl_handle->result != NULL)
+    *output = tcl_handle->result;
+  else
+    *output = "";
+
+  /* If the evaluation failed, and the user requested verbose TCL error
+     messages, then fetch the error message from the value of the "errorInfo"
+     variable instead of using the standard (short) error message.  */
+
+  if (status == TCL_ERROR && wtx_opt_tcl_verbose_p ())
+    *output = (char *) Tcl_GetVar (tcl_handle, "errorInfo", 0);
+
+  return (status != TCL_ERROR);
+}
+
+/* Evaluate the given TCL expression (STR), and return non-zero if
+   successful.
+
+   When successful, the evaluation output is printed on standard output.
+   Otherwise, the error message is printed on standard output.  */
+
+static int
+wtxtcl_eval_verbose (char *str)
+{
+  char *output;
+  const int success = wtxtcl_eval (str, &output);
+
+  if (success)
+    printf_filtered ("%s\n", output);
+  else
+    printf_filtered (_("TCL error: %s\n"), output);
+
+  return success;
+}
+
+/* Implement the "tcl" command.  */
+
+static void
+tcl_command (char *args, int from_tty)
+{
+  if (args == NULL)
+    return;
+
+  wtxtcl_eval_verbose (args);
+}
+
+/* Return the full path name of the "shell.tcl" TCL file that should
+   be part of the VxWorks system installation on the host.
+
+   Return NULL if the file could not be found.  */
+
+static const char *
+shell_tcl_fullpath (void)
+{
+  const char *base_dir;
+  static char *shell_tcl = NULL;
+  struct stat stat_info;
+
+  if (shell_tcl != NULL)
+    return shell_tcl;
+
+  /* First option:  See if we can find the shell.tcl file using
+     the WIND_BASE environment variable.  */
+
+  base_dir = getenv ("WIND_BASE");
+  if (base_dir != NULL)
+    {
+      shell_tcl = xstrprintf ("%s%shost%sresource%stcl%sshell.tcl",
+                              base_dir, SLASH_STRING, SLASH_STRING,
+                              SLASH_STRING, SLASH_STRING);
+
+      if (stat (shell_tcl, &stat_info) == 0)  /* Found it!  */
+        return shell_tcl;
+
+      xfree (shell_tcl);
+    }
+  
+  /* Second option: Try with the WIND_FOUNDATION_PATH environment variable
+     as the root install directory.  */
+
+  base_dir = getenv ("WIND_FOUNDATION_PATH");
+  if (base_dir != NULL)
+    {
+      shell_tcl =
+        xstrprintf ("%s%sresource%swindsh%svxWorks653%stcl%sshell.tcl",
+                    base_dir, SLASH_STRING, SLASH_STRING, SLASH_STRING,
+                    SLASH_STRING, SLASH_STRING);
+
+      if (stat (shell_tcl, &stat_info) == 0)  /* Found it!  */
+        return shell_tcl;
+
+      xfree (shell_tcl);
+    }
+  
+  /* Not found.  */
+
+  shell_tcl = NULL;
+  return shell_tcl;
+}
+
+/* Source a TCL script given its full path name.  */
+
+static int
+wtxtcl_source_file (const char *fullpath)
+{
+  char *source_expr = xstrprintf ("source %s", fullpath);
+  int success;
+
+  success = wtxtcl_eval_verbose (source_expr);
+  xfree (source_expr);
+  return success;
+}
+
+/* Initialize the TCL engine for use by GDB.  This should performed
+   after the debugger is connected to the target server.  */
+
+static void
+wtxtcl_initialize (HWTX wtx_handle)
+{
+  const char *shell_tcl = shell_tcl_fullpath ();
+  int success;
+
+  /* shell.tcl and shellInit are defined in every version of VxWorks;
+     so, if it cannot be found, loaded, or initialized, this should return
+     an error, not a warning.  */
+
+  if (shell_tcl == NULL)
+    error (_("Could not locate shell.tcl"));
+
+  /* Tell our TCL handle which WTX connection to use.  */
+  wtx_tcl_handle_grant (tcl_handle, wtx_handle);
+  
+  /* Source shell.tcl.  */
+  success = wtxtcl_source_file (shell_tcl);
+  if (!success)
+    error (_("Could not load shell.tcl"));
+
+  /* Evaluate the shellInit function from shell.tcl.  */
+  success = wtxtcl_eval_verbose ("shellInit");
+  if (!success)
+    error (_("Could not initialize shell.tcl "));
+}
+
+/* Implement the "get_task_pd" method of the wtxapi_support_ops vector.
+   (see remote-wtxapi.h for more details.  */
+
+static int
+wtxtcl_get_task_pd (int task_id, pd_id_t *task_pd)
+{
+  char *tcl_cmd;
+  char *task_info;
+  int success;
+  int j;
+
+  gdb_assert (task_pd != NULL);
+
+  /* If the system does not support partitions, then return the NULL_PD.  */
+
+  if (!wtx_pd_system_has_pds ())
+    {
+      *task_pd = NULL_PD;
+      return 1;
+    }
+
+  tcl_cmd = xstrprintf ("taskInfoGet 0x%x", task_id);
+  success = wtxtcl_eval (tcl_cmd, &task_info);
+
+  if (!success)  /* The task probably no longer exist...  */
+    return 0;
+
+  /* Skip the first 8 tokens and go directly to the 9th, which contains
+     the PD ID.  */
+  for (j = 0; j < 8; j++)
+    task_info = skip_space_delimited_token (task_info);
+
+  *task_pd = strtoul (task_info, NULL, 16);
+  return 1;
+}
+
+static struct wtxapi_thread_info *
+wtxtcl_get_thread_list (void)
+{
+  /* The gopher expression to be used on VxWorks 5.x (WTX version 2).  */
+  const char *wtx2_gopher_expr =
+    "[shSymAddr activeQHead] *"
+    "{"
+    "<"
+    "-$offset(WIND_TCB,activeNode) !"
+    "<+$offset(WIND_TCB,name) *$>"
+    "<+$offset(WIND_TCB,pStackBase) @>"
+    "<+$offset(WIND_TCB,pStackEnd) @>"
+    "<+$offset(WIND_TCB,regs) !>"
+    "<0 !>"  /* FP registers are not accessible on vxWorks 5.x.  */
+    ">"
+    "*"
+    "}";
+
+  /* The gopher expression to be used on VxWorks 653 (WTX versions 3 & 4).  */
+  const char *wtx3_gopher_expr =
+    "[shSymAddr taskClassId] *"
+    "+$offset(OBJ_CLASS,objList) *"
+    "{"
+    "<"
+    "-$offset(OBJ_CORE,classNode) !"
+    "<$objNameGopherString>"
+    "<+$offset(WIND_TCB,pStackBase) @>"
+    "<+$offset(WIND_TCB,pStackEnd) @>"
+    "<+$offset(WIND_TCB,regs) !>"
+    "<+$offset(WIND_TCB,pFpContext) * +$offset(FP_CONTEXT,fpr) !>"
+    "> "
+    "*"
+    "}";
+
+  /* The following expression is an expression that can be used on old
+     vxWorks 653 systems (WTX version 3 & 4) that do not provide
+     convenient access to the location of the FP registers in the TCB.
+     It is provided to remain compatible with those older systems, and
+     is identical to WTX3_GOPHER_EXPR except that zero is returned in
+     place of the FP register address.  */
+  const char *wtx3_gopher_expr_fallback =
+    "[shSymAddr taskClassId] *"
+    "+$offset(OBJ_CLASS,objList) *"
+    "{"
+    "<"
+    "-$offset(OBJ_CORE,classNode) !"
+    "<$objNameGopherString>"
+    "<+$offset(WIND_TCB,pStackBase) @>"
+    "<+$offset(WIND_TCB,pStackEnd) @>"
+    "<+$offset(WIND_TCB,regs) !>"
+    "<0 !>"
+    "> "
+    "*"
+    "}";
+
+  const char *gopher_expr;
+  char *tcl_expr;
+  char *tcl_output;
+  char *current_thread;
+  int success;
+  struct wtxapi_thread_info *thread_list_head = NULL;
+
+  /* Select the gopher expression that is appropriate for our system.  */
+
+  if (WTX_PROT_VERSION == 2)
+    gopher_expr = wtx2_gopher_expr;
+  else if (tcb_has_fp_regs_p)
+    gopher_expr = wtx3_gopher_expr;
+  else
+    gopher_expr = wtx3_gopher_expr_fallback;
+
+  /* Evaluate the gopher expression.  */
+
+  tcl_expr = xstrprintf ("wtxGopherEval \"%s\"", gopher_expr);
+  success = wtxtcl_eval (tcl_expr, &tcl_output);
+  xfree (tcl_expr);
+  
+  if (!success)
+    {
+      warning (_("Failed to get thread list, TCL returned: %s"), tcl_output);
+      return NULL;
+    }
+
+  /* Parse the result.  */
+
+  current_thread = skip_whitespaces (tcl_output);
+  while (current_thread && *current_thread != '\0')
+    {
+      struct wtxapi_thread_info *new_thread
+        = xmalloc (sizeof (struct wtxapi_thread_info));
+
+      /* Get the thread id.  */
+      new_thread->id = strtoul (current_thread, NULL, 0);
+      current_thread = skip_space_delimited_token (current_thread);
+
+      /* Get the thread name.  */
+      current_thread = skip_whitespaces (current_thread);
+      if (*current_thread == '{')
+        {
+          /* The thread name delimited by curly braces.  Find the
+             closing curly brace.  */
+          char *start = current_thread + 1;  /* skip the '{'...  */
+          char *end = skip_until_character (current_thread, '}');
+          char tmp = *end;
+
+          current_thread = end + 1;  /* discard the '}' marker.  */
+
+          *end = '\0';
+          new_thread->name = strdup (start);
+          *end = tmp;
+        }
+      else
+        current_thread = get_space_delimited_token (current_thread,
+                                                    &new_thread->name);
+
+      /* Skip the stack base and the stack end.  */
+      current_thread = skip_space_delimited_token (current_thread);
+      current_thread = skip_space_delimited_token (current_thread);
+
+      /* Get the address where the GP registers are stored.  */
+      new_thread->regs_addr = strtoul (current_thread, 0, 16);
+      current_thread = skip_space_delimited_token (current_thread);;
+
+      /* Get the address where the FP registers are stored.  */
+      new_thread->fp_regs_addr = strtoul (current_thread, 0, 16);
+      current_thread = skip_space_delimited_token (current_thread);;
+
+      /* Link in the new thread_info to our list.  */
+      new_thread->next = thread_list_head;
+      thread_list_head = new_thread;
+      
+      /* Advance to the begining of the next thread block.  */
+      current_thread = skip_whitespaces (current_thread);
+    }
+
+  return thread_list_head;
+}
+
+static WTX_CONTEXT_ID_T
+wtxtcl_system_mode_get_current_context_id (void)
+{
+  int success;
+  char *tcl_output;
+
+  success = wtxtcl_eval ("taskIdCurrent", &tcl_output);
+  if (!success)
+    error (_("taskIdCurrent failed: %s"), tcl_output);
+
+  return strtoul (tcl_output, NULL, 0);
+}
+
+static int
+wtxtcl_system_mode_support_p ()
+{
+  char *ignored;
+
+  /* Check to see if the system TCL script provide a couple of definitions
+     that we need in order to access the FP registers when in system mode.
+     These are not defined in old versions of VxWorks.
+     Warn the user of the consequences if the definitions are missing.  */
+  tcb_has_fp_regs_p =
+    (wtxtcl_eval ("return $offset(WIND_TCB,pFpContext)", &ignored)
+     && wtxtcl_eval ("return $offset(FP_CONTEXT,fpr)", &ignored));
+  if (!tcb_has_fp_regs_p)
+    warning (_("\
+system does not support access to the FP registers in system mode"));
+
+  return 1;
+}
+
+static struct wtxapi_support_ops wtxtcl_support_ops;
+
+static void
+initialize_wtx_support_ops ()
+{
+  wtxtcl_support_ops.wtx_connection_established_callback = wtxtcl_initialize;
+  wtxtcl_support_ops.get_thread_list = wtxtcl_get_thread_list;
+  wtxtcl_support_ops.get_task_pd = wtxtcl_get_task_pd;
+  wtxtcl_support_ops.system_mode_support_p = wtxtcl_system_mode_support_p;
+  wtxtcl_support_ops.system_mode_get_current_context_id =
+    wtxtcl_system_mode_get_current_context_id;
+}
+
+/* Search for SYM_NAME in the given library and return its address.
+   Throw an error if the symbol could not be found.  LIB is a non-NULL
+   handle on the library, as returned by load_shared_lib.  */
+static void *
+wtx_tcl_resolve (void *lib, char *sym_name)
+{
+  void *result = get_symbol_from_shared_lib (lib, sym_name);
+
+  if (!result)
+    error (_("Cannot find `%s' in WTX-TCL library"), sym_name);
+  return result;
+}
+
+/* Load all tcl-related libraries, and resolve all the addresses
+   of the functions we use from these libraries.  Throws an error
+   if anything wrong happens.  */
+static void
+load_wtx_tcl_libraries (void)
+{
+  void *lib = NULL;
+
+  if (WTX_PROT_VERSION == 4)
+    {
+      lib = load_shared_lib ("wtxtcl41");
+
+      if (!lib)
+	lib = load_shared_lib ("wtxtcl40");
+    }
+  else if (WTX_PROT_VERSION == 3)
+    {
+      lib = load_shared_lib ("wtxtcl30");
+    }
+  else if (WTX_PROT_VERSION == 2)
+    {
+      lib = load_shared_lib ("wtxtcl");
+    }
+
+  if (!lib)
+    error (_("Unable to load the wtxtcl library"));
+
+  wtx_tcl_init = wtx_tcl_resolve (lib, "wtxTclInit");
+  wtx_tcl_handle_grant = wtx_tcl_resolve (lib, "wtxTclHandleGrant");
+}
+
+void
+_initialize_remote_wtx_tcl (void)
+{
+  load_wtx_tcl_libraries ();
+
+  /* There seems to be a bug in the TCL library provided with PSC 2.x
+     which later causes "wtxTclInit" to crash unless we make the following
+     call to "Tcl_FindExecutable".  */
+  if (WTX_PROT_VERSION == 4)
+    Tcl_FindExecutable (NULL);
+
+  tcl_handle = Tcl_CreateInterp ();
+  if (tcl_handle == NULL)
+    error (_("Failed to initialize TCL module"));
+
+  /* Make the WTX routines accessible from TCL.  This is needed by
+     the TCL resource files that we will source later on, when we are
+     connected to the target server.  */
+  wtx_tcl_init (tcl_handle);
+
+  add_com ("tcl", class_obscure, tcl_command,
+           _("Evaluate the arguments with the TCL interpreter"));
+
+  /* Provide TCL-based support routine to the WTX module.  */
+  initialize_wtx_support_ops ();
+  wtxapi_set_support_ops (&wtxtcl_support_ops);
+}
+
-- 
1.6.3.3

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

* [vxworks 08/14] Partition support.
  2010-04-25 15:47 Adding support for VxWorks target Joel Brobecker
                   ` (4 preceding siblings ...)
  2010-04-25 15:48 ` [vxworks 03/14] New module remote-wtx-utils Joel Brobecker
@ 2010-04-25 15:48 ` Joel Brobecker
  2010-04-25 15:48 ` [vxworks 11/14] WTX-TCL support module Joel Brobecker
                   ` (9 subsequent siblings)
  15 siblings, 0 replies; 27+ messages in thread
From: Joel Brobecker @ 2010-04-25 15:48 UTC (permalink / raw)
  To: gdb-patches

This is the module which is providing partition support.  Since our
implementation is not entirely clean (see other message - right now,
we do some nasty swapping of objfiles in and out of the object_files
list), the code that is being provided here has been cleaned up a bit.
All the nasties have been removed, allowing us to keep the interface
and sufficient implementation for partition-less systems (VxWorks 5.x
and 6.x), but leaving out support for VxWorks 653.

I will look at implementing proper partition support independently of
this effort.

2010-04-24  Joel Brobecker  <brobecker@adacore.com>

        * remote-wtx-pd.h, remote-wtx-pd.c: New files.
---
 gdb/remote-wtx-pd.c |  349 +++++++++++++++++++++++++++++++++++++++++++++++++++
 gdb/remote-wtx-pd.h |   58 +++++++++
 2 files changed, 407 insertions(+), 0 deletions(-)
 create mode 100644 gdb/remote-wtx-pd.c
 create mode 100644 gdb/remote-wtx-pd.h

diff --git a/gdb/remote-wtx-pd.c b/gdb/remote-wtx-pd.c
new file mode 100644
index 0000000..1bf4acd
--- /dev/null
+++ b/gdb/remote-wtx-pd.c
@@ -0,0 +1,349 @@
+/* Support for the WTX protocol.
+
+   Copyright (C) 2007, 2010 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#include "defs.h"
+#include "gdb_assert.h"
+#include "objfiles.h"
+#include "source.h"
+#include "remote-wtx-pd.h"
+#include "remote-wtx-opt.h"
+#include "ada-lang.h"
+#include "language.h"
+#include "observer.h"
+#include "command.h"
+#include "gdbcmd.h"
+
+#include <ctype.h>
+
+/* We need to keep the symbols in each PD separate from the others.
+   One of the reasons is that 2 symbols with the same name are allowed to
+   coexist in 653 provided that these 2 symbols live in 2 separate PDs.
+   Another important reason is that virtual memory regions can overlap
+   between PDs, and one symbol address in a PD is not suitable in the
+   context of another PD.
+   
+   GDB maintains a global list of objfiles where the symbols can be found.
+   To achieve this separation, we simply maintain one such list per PD in
+   this module.  At each PD change, we simply save the objfile list for
+   the current PD, and restore it for the new PD.  The net effect is that
+   GDB will only recognize symbols in the current PD, and will complain if
+   a user tries to do any operation that needs symbols from other PDs.
+
+   In practice, GDB maintains a few other global variables that also
+   need to be saved/restored, but the principle remains valid.
+   
+   If would have been slicker to actually maintain one list of objfiles
+   for all PDs and modify GDB to automatically switch to the right PD
+   when performing an operation such as inserting a BP in some code that's
+   in a different partition.  This would probably not be such a great
+   improvment in terms of usability, but this would require a major
+   overall rework.  So we dropped this idea.  */
+
+/* Return nonzero if the target system supports PDs.  */
+
+int
+wtx_pd_system_has_pds ()
+{
+#if WTX_PROT_VERSION > 2
+  return 1;
+#else
+  return 0;
+#endif
+}
+
+/* Return the name of the PD which ID is equal to PD_ID.  If the given PD
+   could not be found, then return "<none>".  */
+
+char *
+wtx_pd_get_pd_name (pd_id_t pd_id)
+{
+  struct wtxapi_pd_desc_q *pds;
+
+  pds = wtxapi_pd_info_q_get ();
+  make_cleanup (cleanup_wtxapi_pd_desc_q, pds);
+
+  for (; pds != NULL; pds = pds->next)
+    if (pds->pd_desc.pd_id == pd_id)
+      return xstrdup (pds->pd_desc.pd_name);
+
+  /* Fallback, if we did not find the PD, or if the system does not support
+     PDs, then return a string saying that the given PD does not have a name
+     associated to it.  */
+  return xstrdup ("<none>");
+}
+
+/* Return the PD ID for the Protection Domain which name is NAME.
+   Raise an error if this PD does not exist.  */
+
+static pd_id_t
+wtx_pd_pd_id_from_name (const char *name)
+{
+  struct wtxapi_pd_desc_q *pds;
+
+  pds = wtxapi_pd_info_q_get ();
+  make_cleanup (cleanup_wtxapi_pd_desc_q, pds);
+
+  while (pds != NULL)
+    if (strcmp (pds->pd_desc.pd_name, name) == 0)
+      return pds->pd_desc.pd_id;
+    else
+      pds = pds->next;
+
+  error ("Unable to find Protection Domain: %s.\n", name);
+}
+
+/* Set the curent Protection Domain to the given PD ID.  No-op on less
+   recent versions of Tornado (T2) where the notion of PD is not supported.  */
+
+static void
+switch_to_pd_internal (pd_id_t pd_id, int from_tty)
+{
+  STATUS result;
+  pd_id_t current_pd;
+
+  if (!wtxapi_tool_connected ())
+    error (_("Not attached to a target. Use \"target wtx\" first."));
+
+  current_pd = wtxapi_pd_current_get ();
+
+  if (pd_id == current_pd)
+    {
+      /* Emit a warning when the PD switch has been requested explicitely
+         by the user, to make sure he knows the operation was meaningless
+         and has been aborted.  */
+      if (from_tty)
+        warning (_("PD unchanged as already set to 0x%lx."), pd_id);
+      return;
+    }
+
+  if (wtx_pd_system_has_pds ())
+    error (_("Operation not implemented yet."));
+}
+
+/* Equivalent to switch_to_pd_internal (pd_id, 1).  Useful either as a
+   shortcut to switch_to_pd_internal, or in conjunction with the
+   make_cleanup mechanism.  */
+
+void
+wtx_pd_switch_to_pd (pd_id_t pd_id)
+{
+  switch_to_pd_internal (pd_id, 1);
+}
+
+/* On systems where Protection Domains are supported, return the ID of
+   the PD where the given module is loaded.  Return NULL_PD if the system
+   does not support PD.  */
+
+pd_id_t
+wtx_pd_get_module_pd (module_id_t module_id)
+{
+  int i;
+  struct wtxapi_module_list *module_list =
+    wtxapi_obj_module_list_get (WTX_MOD_FIND_IN_ALL_PD);
+
+  if (module_list == NULL)
+    error (_("Failed to get target list of modules: %s"), wtxapi_err_msg_get ());
+  else
+    make_cleanup (cleanup_wtxapi_module_list, module_list);
+
+  for (i = 0; i < module_list->num_obj_mod; i++)
+    if (module_list->mod_id_array [i] == module_id)
+      return module_list->pd_id_array [i];
+
+  /* If we reach this point, it means we did not find the given module.  */
+  error (_("Failed to find module by ID: 0x%x"), module_id);
+}
+
+/* Given the name of a module that has just been unloaded, return
+   the PD ID where it was loaded.  The modules loaded on the current PD
+   are searched first.
+   
+   The search is not performed by querying the target server as
+   the module has probably already been unloaded.  Instead, this function
+   searches the current object_files list first, and then the object_files
+   list that we have saved for each PD.
+   
+   On systems that do not support PDs, simply always return NULL_PD.
+   If the module is unknown to GDB, an error will be reported later
+   when searching the module in the list of objfiles.  */
+
+pd_id_t
+wtx_pd_get_unloaded_module_pd (const char *module_name)
+{
+  /* FIXME: brobecker/2004-04-24: Not properly implemented for VxWorks 653
+     systems yet.  */
+  return NULL_PD;
+}
+
+static void
+switch_to_pd_stub (void *pd_id)
+{
+  wtx_pd_switch_to_pd ((pd_id_t) pd_id);
+}
+
+struct cleanup *
+wtx_pd_make_switch_to_pd_cleanup (pd_id_t pd_id)
+{
+  return make_cleanup (switch_to_pd_stub, (void *) pd_id);
+}
+
+/* Switch to the partition where the given task is running.
+   This function is a no-op if we are already in the right PD.  */
+
+void
+wtx_pd_switch_to_task_pd (int task_id)
+{
+  pd_id_t task_pd;
+  int success;
+
+  /* Try to retrieve ID of the PD inside which the module is running.
+     This operation may fail in normal conditions (eg when the event
+     we just received for this task is a CTX_EXIT), so abort silently
+     if the lookup fails.  */
+  success = wtxapi_get_task_pd (task_id, &task_pd);
+  if (!success)
+    return;
+
+  if (task_pd != wtxapi_pd_current_get ())
+    wtx_pd_switch_to_pd (task_pd);
+}
+
+/* Display the list of PDs on the target.  */
+
+static void
+info_pds_command (char *arg, int from_tty)
+{
+  struct wtxapi_pd_desc_q *pds, *iter;
+  pd_id_t current_pd;
+
+  if (arg != NULL && arg[0] != '\000')
+    warning ("Unexpected arguments at end of command, ignored.");
+
+  if (!wtxapi_tool_connected ())
+    error ("Not attached to a target. Use the \"target wtx\" command first.");
+
+  current_pd  = wtxapi_pd_current_get ();
+  pds = wtxapi_pd_info_q_get ();
+  iter = pds;
+
+  printf_filtered ("   PD-ID \t Name \n");
+  while (iter != NULL)
+    {
+      printf_filtered ("%s  ", iter->pd_desc.pd_id == current_pd ? "*" : " ");
+      printf_filtered ("0x%x \t %s \n",
+                       (unsigned int) iter->pd_desc.pd_id,
+                       iter->pd_desc.pd_name);
+      iter = iter->next;
+    }
+  free_wtxapi_pd_desc_q (pds);
+}
+
+/* Implement the "pd" command.  */
+
+static void
+pd_command (char *arg, int from_tty)
+{
+  pd_id_t pd_id;
+  STATUS result;
+
+  if (arg == NULL || arg[0] == '\000')
+    error ("Please specify a protection domain ID. Use \"info pds\" to\n"
+           "see the IDs of the existing protection domains.");
+
+  if (!isdigit (arg[0]))
+    pd_id = wtx_pd_pd_id_from_name (arg);
+  else
+    pd_id = strtol (arg, NULL, 0);
+
+  wtx_pd_switch_to_pd (pd_id);
+}
+
+/* Print a notification to the user if the current PD is no longer
+   the same as the PD that was current at the time when this function
+   was last called.  */
+
+static void
+wtx_pd_check_pd_change (void)
+{
+  static pd_id_t pd_after_last_command = NULL_PD;
+
+  pd_id_t previous_pd = pd_after_last_command;
+  pd_after_last_command = wtxapi_pd_current_get ();
+
+  if (pd_after_last_command != previous_pd)
+    {
+      char *pd_name = wtx_pd_get_pd_name (pd_after_last_command);
+      printf_filtered ("[Switching to Partition %s (0x%lx)]\n",
+                       pd_name, pd_after_last_command);
+      free (pd_name);
+    }
+}
+
+/* Observer for the "command_post" notification.  */
+
+static void
+wtx_pd_command_post_notification (void)
+{
+  /* If the current PD has changed as a consequence of the previous command,
+     then we notify the user about the new PD.  */
+  wtx_pd_check_pd_change ();
+}
+
+/* Print the Link Path of all PDs.  */
+
+static void
+maintenance_info_link_path (char *arg, int from_tty)
+{
+  struct wtxapi_pd_desc_q *pds, *iter;
+
+  pds = wtxapi_pd_info_q_get ();
+  iter = pds;
+
+  printf ("Partition \t Name \t [Link Path]\n");
+  while (iter != NULL)
+    {
+      const struct wtxapi_pd_desc desc = iter->pd_desc;
+      printf ("   0x%lx \t %s \t [%s]\n",
+              iter->pd_desc.pd_id, iter->pd_desc.pd_name,
+              desc.pd_link_path_str ? desc.pd_link_path_str
+                                    : "(no link path)");
+      iter = iter->next;
+    }
+  free_wtxapi_pd_desc_q (pds);
+}
+
+void
+_initialize_remote_wtx_pd (void)
+{
+  if (!wtx_pd_system_has_pds ())
+    return;
+
+  observer_attach_command_post (wtx_pd_command_post_notification);
+
+  add_info ("pds", info_pds_command,
+            _("Display the list of existing protection domains."));
+
+  add_com ("pd", class_run, pd_command,
+           _("Set the current protection domain."));
+
+  add_cmd ("link-path", class_maintenance, maintenance_info_link_path,
+           _("Display the link path of each partition."),
+           &maintenanceinfolist);
+}
+
diff --git a/gdb/remote-wtx-pd.h b/gdb/remote-wtx-pd.h
new file mode 100644
index 0000000..402be1f
--- /dev/null
+++ b/gdb/remote-wtx-pd.h
@@ -0,0 +1,58 @@
+/* Support for the WTX protocol.
+
+   Copyright (C) 2007, 2010 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#ifndef REMOTE_WTX_PD_H
+#define REMOTE_WTX_PD_H
+
+#include "defs.h"
+#include "remote-wtxapi.h"
+
+/* This unit provides an abstraction layer to Partitions for both
+   Tornado 2.x & Tornado 653.  Although only Tornado 653 systems
+   really support the concept of partitions, we can apply the same
+   concept to Tornado 2.x by imagining that these systems are a
+   special case where there is only one (kernel) partition.
+
+   For historical reasons (in the defunct produce Tornado AE), Partitions
+   are also refered as PD, an accronym for Partition Domain, the technical
+   term used to refer to partitions in Tornado AE.  This accronym is very
+   short and handy, so we'll use it in place of partition.  */
+
+struct cleanup;
+
+/* On Tornado 2.x, we will use the following NULL_PD to emulate the
+   system unique PD ID.  On Tornado 653, we will be using the real
+   PD IDs.  */
+#define NULL_PD (0)
+
+int wtx_pd_system_has_pds ();
+
+char *wtx_pd_get_pd_name (pd_id_t pd_id);
+
+void wtx_pd_switch_to_pd (pd_id_t pd_id);
+
+pd_id_t wtx_pd_get_module_pd (module_id_t module_id);
+
+pd_id_t wtx_pd_get_unloaded_module_pd (const char *module_name);
+
+struct cleanup *wtx_pd_make_switch_to_pd_cleanup (pd_id_t pd_id);
+
+void wtx_pd_switch_to_task_pd (int task_id);
+
+#endif
-- 
1.6.3.3

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

* [vxworks 09/14] remote-wtx-hw / register fetch/store support.
  2010-04-25 15:47 Adding support for VxWorks target Joel Brobecker
                   ` (7 preceding siblings ...)
  2010-04-25 15:48 ` [vxworks 13/14] Add tdep files for x86 and powerpc Joel Brobecker
@ 2010-04-25 15:48 ` Joel Brobecker
  2010-04-25 15:56 ` [vxworks 05/14] Add options to control Vxworks related settings Joel Brobecker
                   ` (6 subsequent siblings)
  15 siblings, 0 replies; 27+ messages in thread
From: Joel Brobecker @ 2010-04-25 15:48 UTC (permalink / raw)
  To: gdb-patches; +Cc: Joel Brobecker

This module is in charge of fetching/storing a given register.  There
are two issues to consider:
  - GDB regno to WTX regno translation;
  - determine which register set a given register belongs to.

2010-04-24  Joel Brobecker  <brobecker@adacore.com>

        * remote-wtx-hw.h, remote-wtx-hw.c: New files.
---
 gdb/remote-wtx-hw.c |  552 +++++++++++++++++++++++++++++++++++++++++++++++++++
 gdb/remote-wtx-hw.h |   56 +++++
 2 files changed, 608 insertions(+), 0 deletions(-)
 create mode 100644 gdb/remote-wtx-hw.c
 create mode 100644 gdb/remote-wtx-hw.h

diff --git a/gdb/remote-wtx-hw.c b/gdb/remote-wtx-hw.c
new file mode 100644
index 0000000..fb87dab
--- /dev/null
+++ b/gdb/remote-wtx-hw.c
@@ -0,0 +1,552 @@
+/* Support for the WTX protocol.
+
+   Copyright (C) 2007 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 "remote-wtx-hw.h"
+#include "gdb_assert.h"
+#include "regcache.h"
+#include "gdbcmd.h"
+
+/* Registers in WTX are stored consecutively in a series of memory blocks,
+   with one block per register set.  The following structure details
+   for a given register its position in the block, and the associated
+   register set.  A negative offset means that the register is not
+   accessible with WTX.
+   
+   brobecker/2007-06-25: On older versions of this code, we also used
+   to store the register size, but this should not be necessary.
+   GDB already knows the register size, and it should match the size
+   needed by WTX.  */
+
+struct wtx_hw_register
+{
+  UINT32 register_offset;
+  WTX_REG_SET_TYPE register_set;
+};
+
+/* i386 registers description, as seen by VxWorks.  */
+    
+static const struct wtx_hw_register i386_register_map [] =
+{   
+  /*  Data registers.  */
+  {0x1c, WTX_REG_SET_IU},   /* eax    */
+  {0x18, WTX_REG_SET_IU},   /* ecx    */
+  {0x14, WTX_REG_SET_IU},   /* edx    */
+  {0x10, WTX_REG_SET_IU},   /* ebx    */
+  {0x0c, WTX_REG_SET_IU},   /* esp    */
+  {0x08, WTX_REG_SET_IU},   /* ebp    */
+  {0x04, WTX_REG_SET_IU},   /* esi    */
+  {0x00, WTX_REG_SET_IU},   /* edi    */
+  {0x24, WTX_REG_SET_IU},   /* pc     */
+  {0x20, WTX_REG_SET_IU},   /* eflags */
+
+  /* Segment registers (not accessible).  */
+
+  {-1, WTX_REG_SET_IU},     /* cs     */
+  {-1, WTX_REG_SET_IU},     /* ss     */
+  {-1, WTX_REG_SET_IU},     /* ds     */
+  {-1, WTX_REG_SET_IU},     /* es     */
+  {-1, WTX_REG_SET_IU},     /* fs     */
+  {-1, WTX_REG_SET_IU},     /* gs     */
+    
+  /* Floating Point registers.  */
+  {0x1c, WTX_REG_SET_FPU},  /* st0    */
+  {0x16, WTX_REG_SET_FPU},  /* st1    */
+  {0x20, WTX_REG_SET_FPU},  /* st2    */
+  {0x2a, WTX_REG_SET_FPU},  /* st3    */
+  {0x34, WTX_REG_SET_FPU},  /* st4    */
+  {0x3e, WTX_REG_SET_FPU},  /* st5    */
+  {0x48, WTX_REG_SET_FPU},  /* st6    */
+  {0x52, WTX_REG_SET_FPU},  /* st7    */
+  {0x00, WTX_REG_SET_FPU},  /* fpc    */
+  {0x04, WTX_REG_SET_FPU},  /* fps    */
+  {0x08, WTX_REG_SET_FPU},  /* fpt    */
+  {-1, WTX_REG_SET_IU},     /* fiseg  */
+  {-1, WTX_REG_SET_IU},     /* fioff  */
+  {-1, WTX_REG_SET_IU},     /* foseg  */
+  {-1, WTX_REG_SET_IU},     /* fooff  */
+  {-1, WTX_REG_SET_IU},     /* fop    */
+  {-1, WTX_REG_SET_IU},     /* xmm0   */
+  {-1, WTX_REG_SET_IU},     /* xmm1   */
+  {-1, WTX_REG_SET_IU},     /* xmm2   */
+  {-1, WTX_REG_SET_IU},     /* xmm3   */
+  {-1, WTX_REG_SET_IU},     /* xmm4   */
+  {-1, WTX_REG_SET_IU},     /* xmm5   */
+  {-1, WTX_REG_SET_IU},     /* xmm6   */
+  {-1, WTX_REG_SET_IU},     /* xmm7   */
+  {-1, WTX_REG_SET_IU},     /* mxcsr  */
+
+  /* MMX pseudo-registers (not accessible).  */
+
+  {-1, WTX_REG_SET_IU},     /* mm0    */
+  {-1, WTX_REG_SET_IU},     /* mm1    */
+  {-1, WTX_REG_SET_IU},     /* mm2    */
+  {-1, WTX_REG_SET_IU},     /* mm3    */
+  {-1, WTX_REG_SET_IU},     /* mm4    */
+  {-1, WTX_REG_SET_IU},     /* mm5    */
+  {-1, WTX_REG_SET_IU},     /* mm6    */
+  {-1, WTX_REG_SET_IU}      /* mm7    */
+};  
+    
+
+static const struct wtx_hw_register ppc_register_map[] =
+{
+  /* General purpose registers.  */
+
+  {0x00, WTX_REG_SET_IU},   /* r0     (0) */
+  {0x04, WTX_REG_SET_IU},   /* r1 */
+  {0x08, WTX_REG_SET_IU},   /* r2 */
+  {0x0c, WTX_REG_SET_IU},   /* r3 */
+  {0x10, WTX_REG_SET_IU},   /* r4 */
+  {0x14, WTX_REG_SET_IU},   /* r5 */
+  {0x18, WTX_REG_SET_IU},   /* r6 */
+  {0x1c, WTX_REG_SET_IU},   /* r7 */
+  {0x20, WTX_REG_SET_IU},   /* r8     (8) */
+  {0x24, WTX_REG_SET_IU},   /* r9 */
+  {0x28, WTX_REG_SET_IU},   /* r10 */
+  {0x2c, WTX_REG_SET_IU},   /* r11 */
+  {0x30, WTX_REG_SET_IU},   /* r12 */
+  {0x34, WTX_REG_SET_IU},   /* r13 */
+  {0x38, WTX_REG_SET_IU},   /* r14 */
+  {0x3c, WTX_REG_SET_IU},   /* r15    (16) */
+  {0x40, WTX_REG_SET_IU},   /* r16 */
+  {0x44, WTX_REG_SET_IU},   /* r17 */
+  {0x48, WTX_REG_SET_IU},   /* r18 */
+  {0x4c, WTX_REG_SET_IU},   /* r19 */
+  {0x50, WTX_REG_SET_IU},   /* r20 */
+  {0x54, WTX_REG_SET_IU},   /* r21 */
+  {0x58, WTX_REG_SET_IU},   /* r22 */
+  {0x5c, WTX_REG_SET_IU},   /* r23 */
+  {0x60, WTX_REG_SET_IU},   /* r24    (24) */
+  {0x64, WTX_REG_SET_IU},   /* r25 */
+  {0x68, WTX_REG_SET_IU},   /* r26 */
+  {0x6c, WTX_REG_SET_IU},   /* r27 */
+  {0x70, WTX_REG_SET_IU},   /* r28 */
+  {0x74, WTX_REG_SET_IU},   /* r29 */
+  {0x78, WTX_REG_SET_IU},   /* r30 */
+  {0x7c, WTX_REG_SET_IU},   /* r31 */ 
+  {0x00, WTX_REG_SET_FPU},  /* f0     (32) */
+  {0x08, WTX_REG_SET_FPU},  /* f1 */
+  {0x10, WTX_REG_SET_FPU},  /* f2 */
+  {0x18, WTX_REG_SET_FPU},  /* f3 */
+  {0x20, WTX_REG_SET_FPU},  /* f4 */
+  {0x28, WTX_REG_SET_FPU},  /* f5 */
+  {0x30, WTX_REG_SET_FPU},  /* f6 */
+  {0x38, WTX_REG_SET_FPU},  /* f7 */
+  {0x40, WTX_REG_SET_FPU},  /* f8     (40) */
+  {0x48, WTX_REG_SET_FPU},  /* f9 */
+  {0x50, WTX_REG_SET_FPU},  /* f10 */
+  {0x58, WTX_REG_SET_FPU},  /* f11 */
+  {0x60, WTX_REG_SET_FPU},  /* f12 */
+  {0x68, WTX_REG_SET_FPU},  /* f13 */
+  {0x70, WTX_REG_SET_FPU},  /* f14 */
+  {0x78, WTX_REG_SET_FPU},  /* f15 */
+  {0x80, WTX_REG_SET_FPU},  /* f16    (48) */
+  {0x88, WTX_REG_SET_FPU},  /* f17 */
+  {0x90, WTX_REG_SET_FPU},  /* f18 */
+  {0x98, WTX_REG_SET_FPU},  /* f19 */
+  {0xa0, WTX_REG_SET_FPU},  /* f20 */
+  {0xa8, WTX_REG_SET_FPU},  /* f21 */
+  {0xb0, WTX_REG_SET_FPU},  /* f22 */
+  {0xb8, WTX_REG_SET_FPU},  /* f23 */
+  {0xc0, WTX_REG_SET_FPU},  /* f24    (56) */
+  {0xc8, WTX_REG_SET_FPU},  /* f25 */
+  {0xd0, WTX_REG_SET_FPU},  /* f26 */
+  {0xd8, WTX_REG_SET_FPU},  /* f27 */
+  {0xe0, WTX_REG_SET_FPU},  /* f28 */
+  {0xe8, WTX_REG_SET_FPU},  /* f29 */
+  {0xf0, WTX_REG_SET_FPU},  /* f30 */
+  {0xf8, WTX_REG_SET_FPU},  /* f31 */
+  {0x8c, WTX_REG_SET_IU},   /* pc     (64) */
+  {0x80, WTX_REG_SET_IU},   /* ps/msr */
+
+  /* Special purpose registers.  */
+
+  {0x90,  WTX_REG_SET_IU},   /* cr     (66) */
+  {0x84,  WTX_REG_SET_IU},   /* lr */
+  {0x88,  WTX_REG_SET_IU},   /* ctr */
+  {0x94,  WTX_REG_SET_IU},   /* xer */
+  {0x100, WTX_REG_SET_FPU}, /* fpscr */
+
+  /* Unused register slots (71 - 105).  */
+  {-1, WTX_REG_SET_IU},  /* Empty register slot (71).  */
+  {-1, WTX_REG_SET_IU},  /* Empty register slot (72).  */
+  {-1, WTX_REG_SET_IU},  /* Empty register slot (73).  */
+  {-1, WTX_REG_SET_IU},  /* Empty register slot (74).  */
+  {-1, WTX_REG_SET_IU},  /* Empty register slot (75).  */
+  {-1, WTX_REG_SET_IU},  /* Empty register slot (76).  */
+  {-1, WTX_REG_SET_IU},  /* Empty register slot (77).  */
+  {-1, WTX_REG_SET_IU},  /* Empty register slot (78).  */
+  {-1, WTX_REG_SET_IU},  /* Empty register slot (79).  */
+
+  {-1, WTX_REG_SET_IU},  /* Empty register slot (80).  */
+  {-1, WTX_REG_SET_IU},  /* Empty register slot (81).  */
+  {-1, WTX_REG_SET_IU},  /* Empty register slot (82).  */
+  {-1, WTX_REG_SET_IU},  /* Empty register slot (83).  */
+  {-1, WTX_REG_SET_IU},  /* Empty register slot (84).  */
+  {-1, WTX_REG_SET_IU},  /* Empty register slot (85).  */
+  {-1, WTX_REG_SET_IU},  /* Empty register slot (86).  */
+  {-1, WTX_REG_SET_IU},  /* Empty register slot (87).  */
+  {-1, WTX_REG_SET_IU},  /* Empty register slot (88).  */
+  {-1, WTX_REG_SET_IU},  /* Empty register slot (89).  */
+
+  {-1, WTX_REG_SET_IU},  /* Empty register slot (90).  */
+  {-1, WTX_REG_SET_IU},  /* Empty register slot (91).  */
+  {-1, WTX_REG_SET_IU},  /* Empty register slot (92).  */
+  {-1, WTX_REG_SET_IU},  /* Empty register slot (93).  */
+  {-1, WTX_REG_SET_IU},  /* Empty register slot (94).  */
+  {-1, WTX_REG_SET_IU},  /* Empty register slot (95).  */
+  {-1, WTX_REG_SET_IU},  /* Empty register slot (96).  */
+  {-1, WTX_REG_SET_IU},  /* Empty register slot (97).  */
+  {-1, WTX_REG_SET_IU},  /* Empty register slot (98).  */
+  {-1, WTX_REG_SET_IU},  /* Empty register slot (99).  */
+
+  {-1, WTX_REG_SET_IU},  /* Empty register slot (100).  */
+  {-1, WTX_REG_SET_IU},  /* Empty register slot (101).  */
+  {-1, WTX_REG_SET_IU},  /* Empty register slot (102).  */
+  {-1, WTX_REG_SET_IU},  /* Empty register slot (103).  */
+  {-1, WTX_REG_SET_IU},  /* Empty register slot (104).  */
+  {-1, WTX_REG_SET_IU},  /* Empty register slot (105).  */
+
+  /* AltiVec registers.
+
+     They are only supported starting with VxWorks 5.5 and PSC 2.1.
+     brobecker/2007-11-02: For now, we removed support for these registers
+     regardless of the VxWorks version in order to allow us to build GDB
+     on older versions of VxWorks.  We'll investigate conditional support
+     later (note that these registers are part of the WTX_REG_SET_AV
+     register set).  */
+
+  {-1, WTX_REG_SET_IU},  /* vr0 (106) */
+  {-1, WTX_REG_SET_IU},  /* vr1 */
+  {-1, WTX_REG_SET_IU},  /* vr2 */
+  {-1, WTX_REG_SET_IU},  /* vr3 */
+  {-1, WTX_REG_SET_IU},  /* vr4 */
+  {-1, WTX_REG_SET_IU},  /* vr5 */
+  {-1, WTX_REG_SET_IU},  /* vr6 */
+  {-1, WTX_REG_SET_IU},  /* vr7 */
+  {-1, WTX_REG_SET_IU},  /* vr8 */
+  {-1, WTX_REG_SET_IU},  /* vr9 */
+  {-1, WTX_REG_SET_IU},  /* vr10 */
+  {-1, WTX_REG_SET_IU},  /* vr11 */
+  {-1, WTX_REG_SET_IU},  /* vr12 */
+  {-1, WTX_REG_SET_IU},  /* vr13 */
+  {-1, WTX_REG_SET_IU},  /* vr14 */
+  {-1, WTX_REG_SET_IU},  /* vr15 */
+  {-1, WTX_REG_SET_IU},  /* vr16 */
+  {-1, WTX_REG_SET_IU},  /* vr17 */
+  {-1, WTX_REG_SET_IU},  /* vr18 */
+  {-1, WTX_REG_SET_IU},  /* vr19 */
+  {-1, WTX_REG_SET_IU},  /* vr20 */
+  {-1, WTX_REG_SET_IU},  /* vr21 */
+  {-1, WTX_REG_SET_IU},  /* vr22 */
+  {-1, WTX_REG_SET_IU},  /* vr23 */
+  {-1, WTX_REG_SET_IU},  /* vr24 */
+  {-1, WTX_REG_SET_IU},  /* vr25 */
+  {-1, WTX_REG_SET_IU},  /* vr26 */
+  {-1, WTX_REG_SET_IU},  /* vr27 */
+  {-1, WTX_REG_SET_IU},  /* vr28 */
+  {-1, WTX_REG_SET_IU},  /* vr29 */
+  {-1, WTX_REG_SET_IU},  /* vr30 */
+  {-1, WTX_REG_SET_IU},  /* vr31 */
+  {-1, WTX_REG_SET_IU},  /* vscr */
+  {-1, WTX_REG_SET_IU},  /* vrsave */  
+
+  /* dl registers (not accessible either).  */
+  {-1, WTX_REG_SET_IU},  /* dl0 */
+  {-1, WTX_REG_SET_IU},  /* dl1 */
+  {-1, WTX_REG_SET_IU},  /* dl2 */
+  {-1, WTX_REG_SET_IU},  /* dl3 */
+  {-1, WTX_REG_SET_IU},  /* dl4 */
+  {-1, WTX_REG_SET_IU},  /* dl5 */
+  {-1, WTX_REG_SET_IU},  /* dl6 */
+  {-1, WTX_REG_SET_IU},  /* dl7 */
+  {-1, WTX_REG_SET_IU},  /* dl8 */
+  {-1, WTX_REG_SET_IU},  /* dl9 */
+  {-1, WTX_REG_SET_IU},  /* dl10 */
+  {-1, WTX_REG_SET_IU},  /* dl11 */
+  {-1, WTX_REG_SET_IU},  /* dl12 */
+  {-1, WTX_REG_SET_IU},  /* dl13 */
+  {-1, WTX_REG_SET_IU},  /* dl14 */
+  {-1, WTX_REG_SET_IU},  /* dl15 */
+};
+
+/* The following variables point to the appropriate register table
+   depending on the target.  These are updated when we connect
+   to the target server.  */
+
+static const struct wtx_hw_register *wtx_hw_register_map = NULL;
+static int wtx_hw_register_map_len = 0;
+
+/* Whether we should complain or not if we are trying to store/fetch a
+   register which is not accessible.  
+
+   FIXME: guitton/2007-11-15: this should not be needed.  We should always
+   have a warning if we are not able to store or fetch a register.  However,
+   for some targets (e.g. x86), this generates a lot of bogus warnings.  So
+   we disable these warnings for now.  */
+
+static int wtx_register_complaints = 0;
+
+/* Inspect the target gdbarch vector, and initialize the internal
+   state of this module.  This include initializing elements such
+   as the register map, for instance.
+
+   This function must be called before any other function is used.  */
+
+void
+wtx_hw_initialize (void)
+{
+  const struct bfd_arch_info *arch_info =
+    gdbarch_bfd_arch_info (target_gdbarch);
+
+  gdb_assert (arch_info != NULL);
+
+  switch (arch_info->arch)
+    {
+      case bfd_arch_rs6000:
+      case bfd_arch_powerpc:
+        wtx_hw_register_map = ppc_register_map;
+        wtx_hw_register_map_len =
+          sizeof (ppc_register_map) / sizeof (struct wtx_hw_register);
+        break;
+
+      case bfd_arch_i386:
+        wtx_hw_register_map = i386_register_map;
+        wtx_hw_register_map_len =
+          sizeof (i386_register_map) / sizeof (struct wtx_hw_register);
+        break;
+
+      default:
+        error (_("This architecture is currently not supported"));
+    }
+}
+
+/* Return non-zero if the given register can be fetched & stored.  */
+
+static int
+wtx_hw_register_supported_p (int gdb_regnum)
+{
+  gdb_assert (wtx_hw_register_map != NULL);
+  gdb_assert (gdb_regnum <= wtx_hw_register_map_len);
+
+  if (wtx_hw_register_map [gdb_regnum].register_offset == -1)
+    return 0;  /* Offset unknown, register is not supported.  */
+
+  return 1;
+}
+
+
+/* Fetch the value of a register given its GDB_REGNUM, and store it
+   inside REG_VAL.
+
+   Register numbering in GDB do not necessarily correspond to the
+   numbering used by WTX.  This function translates the GDB_REGNUM
+   into a WTX register number before calling the WTX routine.  */
+
+int
+wtx_hw_fetch_register (struct gdbarch *gdbarch,
+                       WTX_CONTEXT_TYPE context_type,
+                       WTX_CONTEXT_ID_T context_id,
+                       int gdb_regnum,
+                       gdb_byte *reg_val)
+{
+  if (!wtx_hw_register_supported_p (gdb_regnum))
+    {
+      if (wtx_register_complaints)
+        warning (_("Fetching register %s is not supported"),
+                 gdbarch_register_name (gdbarch, gdb_regnum));
+      return 0;
+    }
+
+  return wtxapi_regs_get (context_type, context_id,
+                          wtx_hw_register_map [gdb_regnum].register_set,
+                          wtx_hw_register_map [gdb_regnum].register_offset,
+                          register_size (gdbarch, gdb_regnum),
+                          reg_val);
+}
+
+/* Fetch the value of the given register given its GDB_REGNUM,
+   and store it inside REG_VAL.  Instead of using WTX to read
+   the register value, read the register value from the memory
+   region where the registers have been saved for this task.
+   
+   REGS_ADDR is the base address where the GP registers have been saved.
+   FP_REGS_ADDR, is the base address where the FP registers have been saved.
+
+   GP registers are always supported, and FP registers are supported
+   only if FP_REGS_ADDR is not zero.  Other registers (Eg altivec registers)
+   are not supported in this mode.  */
+
+int
+wtx_hw_fetch_register_in_memory (struct gdbarch *gdbarch,
+                                 WTX_CONTEXT_TYPE context_type,
+                                 WTX_CONTEXT_ID_T context_id,
+                                 CORE_ADDR regs_addr,
+                                 CORE_ADDR fp_regs_addr,
+                                 int gdb_regnum,
+                                 gdb_byte *reg_val)
+{
+  int reg_offset;
+  CORE_ADDR reg_addr = 0;
+
+  if (!wtx_hw_register_supported_p (gdb_regnum))
+    {
+      if (wtx_register_complaints)
+        warning (_("Fetching register %s is not supported"),
+                 gdbarch_register_name (gdbarch, gdb_regnum));
+      return 0;
+    }
+
+  reg_offset = wtx_hw_register_map [gdb_regnum].register_offset;
+  switch (wtx_hw_register_map [gdb_regnum].register_set)
+    {
+      case WTX_REG_SET_IU:
+        reg_addr = regs_addr + reg_offset;
+        break;
+     case WTX_REG_SET_FPU:
+        if (fp_regs_addr != 0)
+          reg_addr = fp_regs_addr + reg_offset;
+        break;
+    }
+
+  if (reg_addr == 0)
+    {
+      /* We couldn't determine the location where the register is stored.
+         Warn the user and abort.  */
+      if (wtx_register_complaints)
+        warning (_("Cannot fetch register %s in this mode"),
+                 gdbarch_register_name (gdbarch, gdb_regnum));
+      return 0;
+    }
+
+  return (wtxapi_mem_read (wtxapi_pd_current_get (), reg_addr, reg_val,
+                           register_size (gdbarch, gdb_regnum))
+          != WTX_ERROR);
+}
+
+/* Store the value from REG_VAL into the register identified by
+   GDB_REGNUM.  
+   
+   Register numbering in GDB do not necessarily correspond to the
+   numbering used by WTX.  This function translates the GDB_REGNUM
+   into a WTX register number before calling the WTX routine.  */
+
+int
+wtx_hw_store_register (struct gdbarch *gdbarch, WTX_CONTEXT_TYPE context_type,
+                       WTX_CONTEXT_ID_T context_id,
+                       int gdb_regnum,
+                       gdb_byte *reg_val)
+{
+  /* brobecker/2007-10-16: On powerpc targets, there seems to be a bug
+     in the VxWorks system that causes the storing of the msr register
+     to fail.  Although the WTX request returns with no error, the actual
+     new value of the msr is often zero instead of the intended value,
+     later causing dramatic issues such as floating-point exceptions or
+     even system-wide crashes.  So we simply silently ignore stores to
+     that register for now.  */
+  if (wtx_hw_register_map == ppc_register_map
+      && gdb_regnum == 65)
+    return 0;
+
+  if (!wtx_hw_register_supported_p (gdb_regnum))
+    {
+      if (wtx_register_complaints)
+        warning (_("Storing register %s is not supported"),
+                 gdbarch_register_name (gdbarch, gdb_regnum));
+      return 0;
+    }
+
+  return wtxapi_regs_set (context_type, context_id,
+                          wtx_hw_register_map [gdb_regnum].register_set,
+                          wtx_hw_register_map [gdb_regnum].register_offset,
+                          register_size (gdbarch, gdb_regnum),
+                          reg_val);
+}
+
+/* Store the value from REG_VAL into the register identified by
+   GDB_REGNUM.  Instead of using WTX to write the register value,
+   we write the new value in the memory region where the register
+   has been saved for this task.
+
+   REGS_ADDR is the base address where the GP registers have been saved.
+   FP_REGS_ADDR, is the base address where the FP registers have been saved.
+
+   GP registers are always supported, and FP registers are supported
+   only if FP_REGS_ADDR is not zero.  Other registers (Eg altivec registers)
+   are not supported in this mode.  */
+
+int
+wtx_hw_store_register_in_memory (struct gdbarch *gdbarch,
+                                 WTX_CONTEXT_TYPE context_type,
+                                 WTX_CONTEXT_ID_T context_id,
+                                 CORE_ADDR regs_addr,
+                                 CORE_ADDR fp_regs_addr,
+                                 int gdb_regnum,
+                                 gdb_byte *reg_val)
+{
+  int reg_offset;
+  CORE_ADDR reg_addr = 0;
+
+  if (!wtx_hw_register_supported_p (gdb_regnum))
+    {
+      if (wtx_register_complaints)
+        warning (_("Storing register %s is not supported"),
+                 gdbarch_register_name (gdbarch, gdb_regnum));
+      return 0;
+    }
+
+  reg_offset = wtx_hw_register_map [gdb_regnum].register_offset;
+  switch (wtx_hw_register_map [gdb_regnum].register_set)
+    {
+      case WTX_REG_SET_IU:
+        reg_addr = regs_addr + reg_offset;
+        break;
+      case WTX_REG_SET_FPU:
+        if (fp_regs_addr != 0)
+          reg_addr = fp_regs_addr + reg_offset;
+        break;
+    }
+
+  if (reg_addr == 0)
+    {
+      /* We couldn't determine the location where the register is stored.
+         Warn the user and abort.  */
+      if (wtx_register_complaints)
+        warning (_("Cannot store register %s in this mode"),
+                 gdbarch_register_name (gdbarch, gdb_regnum));
+      return 0;
+    }
+
+  return (wtxapi_mem_write (wtxapi_pd_current_get (), reg_val, reg_addr,
+                            register_size (gdbarch, gdb_regnum))
+          != WTX_ERROR);
+}
+
+void
+initialize_remote_wtx_hw ()
+{
+  add_setshow_boolean_cmd ("wtx-register-complaints", no_class,
+                           &wtx_register_complaints,"\
+Set whether to complain if a register is not accessible.", "\
+Show whether to complain if a register is not accessible.", "\
+If set, GDB complains when it cannot store/fetch a register.",
+			   NULL, NULL,
+			   &setlist, &showlist);
+}
diff --git a/gdb/remote-wtx-hw.h b/gdb/remote-wtx-hw.h
new file mode 100644
index 0000000..f5c7813
--- /dev/null
+++ b/gdb/remote-wtx-hw.h
@@ -0,0 +1,56 @@
+/* Support for the WTX protocol.
+
+   Copyright (C) 2007, 2010 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#ifndef REMOTE_WTX_HW_H
+#define REMOTE_WTX_HW_H
+
+#include "defs.h"
+#include "remote-wtxapi.h"
+
+extern void wtx_hw_initialize (void);
+
+extern int wtx_hw_fetch_register (struct gdbarch *gdbarch,
+                                  WTX_CONTEXT_TYPE context_type,
+                                  WTX_CONTEXT_ID_T context_id,
+                                  int gdb_regnum,
+                                  gdb_byte *reg_val);
+
+extern int wtx_hw_fetch_register_in_memory (struct gdbarch *gdbarch,
+                                            WTX_CONTEXT_TYPE context_type,
+                                            WTX_CONTEXT_ID_T context_id,
+                                            CORE_ADDR regs_addr,
+                                            CORE_ADDR fp_regs_addr,
+                                            int gdb_regnum,
+                                            gdb_byte *reg_val);
+
+extern int wtx_hw_store_register (struct gdbarch *gdbarch,
+                                  WTX_CONTEXT_TYPE context_type,
+                                  WTX_CONTEXT_ID_T context_id,
+                                  int gdb_regnum,
+                                  gdb_byte *reg_val);
+
+extern int wtx_hw_store_register_in_memory (struct gdbarch *gdbarch,
+                                            WTX_CONTEXT_TYPE context_type,
+                                            WTX_CONTEXT_ID_T context_id,
+                                            CORE_ADDR regs_addr,
+                                            CORE_ADDR fp_regs_addr,
+                                            int gdb_regnum,
+                                            gdb_byte *reg_val);
+
+#endif
-- 
1.6.3.3

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

* [vxworks 03/14] New module remote-wtx-utils
  2010-04-25 15:47 Adding support for VxWorks target Joel Brobecker
                   ` (3 preceding siblings ...)
  2010-04-25 15:48 ` [vxworks 14/14] Configury and Makefile updates for VxWorks Joel Brobecker
@ 2010-04-25 15:48 ` Joel Brobecker
  2010-04-26 18:55   ` Tom Tromey
  2010-04-25 15:48 ` [vxworks 08/14] Partition support Joel Brobecker
                   ` (10 subsequent siblings)
  15 siblings, 1 reply; 27+ messages in thread
From: Joel Brobecker @ 2010-04-25 15:48 UTC (permalink / raw)
  To: gdb-patches

This module provides some general-purpose routines which might be
better off somewhere else... To be discussed individually for each
routine.

2010-04-24  Joel Brobecker  <brobecker@adacore.com>

        * remote-wtx-utils.h, remote-wtx-utils.c: New files.
---
 gdb/remote-wtx-utils.c |  201 ++++++++++++++++++++++++++++++++++++++++++++++++
 gdb/remote-wtx-utils.h |   47 +++++++++++
 2 files changed, 248 insertions(+), 0 deletions(-)
 create mode 100644 gdb/remote-wtx-utils.c
 create mode 100644 gdb/remote-wtx-utils.h

diff --git a/gdb/remote-wtx-utils.c b/gdb/remote-wtx-utils.c
new file mode 100644
index 0000000..129c8e6
--- /dev/null
+++ b/gdb/remote-wtx-utils.c
@@ -0,0 +1,201 @@
+/* Support for the WTX protocol.
+
+   Copyright (C) 2007, 2010 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#include "defs.h"
+#include "remote-wtx-utils.h"
+#include "gdb_stat.h"
+#include "gdb_string.h"
+#include "filenames.h"
+#ifdef HAVE_LIBDL
+#include <dlfcn.h>
+#elif __MINGW32__
+#include <windows.h>
+#else
+/* Unsupported configuration.  See load_shared_lib for details.  */
+#error
+#endif
+
+/* Return non-zero if the host has a dos-based file system.  */
+
+int
+have_dos_based_filesystem (void)
+{
+#ifdef HAVE_DOS_BASED_FILE_SYSTEM
+  return 1;
+#else
+  return 0;
+#endif
+}
+
+/* Return True if the file NAME exists and is a regular file.
+
+   FIXME: This function was duplicated from source.c.
+   Make sure to share this function when we contribute the WTX port.  */
+
+int
+is_regular_file (const char *name)
+{
+  struct stat st;
+  const int status = stat (name, &st);
+
+  /* Stat should never fail except when the file does not exist.
+     If stat fails, analyze the source of error and return True
+     unless the file does not exist, to avoid returning false results
+     on obscure systems where stat does not work as expected.  */
+  if (status != 0)
+    return (errno != ENOENT);
+
+  return S_ISREG (st.st_mode);
+}
+
+/* Return a pointer to the first non-whitepace character found
+   in the string.  A whitespace is either a space or a tab.  */
+
+char *
+skip_whitespaces (char *str)
+{
+  char *index = str;
+
+  while (*index == ' ' || *index == '\t')
+    index++;
+    
+  return index;
+}
+
+/* Return a pointer to the first DELIMITER character in the given
+   string.  Return a pointer to the end-of-line character if
+   DELIMITER was not found.  */
+
+char *
+skip_until_character (char *str, char delimiter)
+{
+  char *index = str;
+
+  while (*index != delimiter && *index != '\0')
+    index++;
+
+  return index;
+}
+
+/* return a pointer to the first whitespace character.  If no whitespace
+   is found before the end of string, a pointer to the end of string
+   is returned.  A whitespace is either a space or a tab.  */
+
+static char *
+skip_until_whitespace (char *str)
+{
+  char *index = str;
+
+  while (*index != ' ' && *index != '\t' && *index != '\0')
+    index++;
+
+  return index;
+}
+
+/* Return a pointer to the first white space after the next 
+   whitespace-delimited token.  */
+
+char *
+skip_space_delimited_token (char *str)
+{
+  char *index = str;
+
+  index = skip_whitespaces (index);
+  index = skip_until_whitespace (index);
+
+  return index;
+}
+
+/* Copy the next whitespace token into TOKEN.  This string will be
+   allocated using malloc, and must be dealocated later.  */
+
+char *
+get_space_delimited_token (char *str, char **token)
+{
+  char *start;
+  char *end;
+  char tmp;
+
+  start = skip_whitespaces (str);
+  end = skip_until_whitespace (start);
+
+  tmp = *end;
+  *end = '\0';
+  *token = xstrdup (start);
+  *end = tmp;
+  
+  return end;
+}
+
+/* Load the shared library whose name is LIB_NAME and return a handle
+   on it.  Note that this name correspond to a different file name
+   depending on the host; for example, the name "wtxapi40" would
+   identify libwtxapi40.so on linux and solaris, whereas it would
+   identify wtxapi40.dll.  */
+
+void *load_shared_lib (char *lib_name)
+{
+  const char dos_suffix [] = ".dll";
+  const char unix_prefix[] = "lib";
+  const char unix_suffix [] = ".so";
+  char *filename;
+
+  if (have_dos_based_filesystem ())
+    {
+      filename = (char *) alloca (strlen (lib_name) + strlen (dos_suffix) + 1);
+      strcpy (filename, lib_name);
+      strcat (filename, dos_suffix);
+    }
+  else
+    {
+      filename = (char *) alloca (strlen (unix_prefix)
+				  + strlen (lib_name)
+				  + strlen (unix_suffix) + 1);
+      strcpy (filename, unix_prefix);
+      strcat (filename, lib_name);
+      strcat (filename, unix_suffix);
+    }
+
+#ifdef HAVE_LIBDL
+  return dlopen (filename, RTLD_NOW);
+#elif __MINGW32__
+  return (void *) LoadLibrary (filename);
+#else
+/* A dlopen-like API is need to load the WTX libraries.  This
+   implementation supports only libdl and the win32 native API
+   (LoadLibrary).  */
+#error
+#endif
+}
+
+/* Get the address of SYMBOL in a shared library identified
+   by HANDLE (HANDLE is the value returned by load_shared_lib
+   for this library).  */
+
+void *get_symbol_from_shared_lib (void *handle, char *symbol)
+{
+#ifdef HAVE_LIBDL
+  return dlsym (handle, symbol);
+#elif __MINGW32__
+  return (void *) GetProcAddress (handle, symbol);
+#else
+/* Unsupported configuration.  See load_shared_lib for details.  */
+#error
+#endif
+}
diff --git a/gdb/remote-wtx-utils.h b/gdb/remote-wtx-utils.h
new file mode 100644
index 0000000..f60953b
--- /dev/null
+++ b/gdb/remote-wtx-utils.h
@@ -0,0 +1,47 @@
+/* Support for the WTX protocol.
+
+   Copyright (C) 2007, 2010 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#ifndef REMOTE_WTX_UTILS_H
+#define REMOTE_WTX_UTILS_H
+
+/* This unit contains some routines that should really be implemented
+   elsewhere.  Ideally, we'd like to contribute these routines to the FSF,
+   but we currently only have the DFW & WTX backends that use them, so
+   until we contribute either of these ports, there really isn't any
+   reason for the FSF to take our code.  Rather than sprinkle these
+   routines in the GDB core code, we put them here in one central location
+   for now.  */
+
+int have_dos_based_filesystem (void);
+
+int is_regular_file (const char *name);
+
+char *skip_whitespaces (char *str);
+
+char *skip_until_character (char *str, char delimiter);
+
+char *skip_space_delimited_token (char *str);
+
+char *get_space_delimited_token (char *str, char **token);
+
+void *load_shared_lib (char *lib_name);
+
+void *get_symbol_from_shared_lib (void *handle, char *symbol);
+
+#endif
-- 
1.6.3.3

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

* [vxworks 14/14] Configury and Makefile updates for VxWorks.
  2010-04-25 15:47 Adding support for VxWorks target Joel Brobecker
                   ` (2 preceding siblings ...)
  2010-04-25 15:48 ` [vxworks 02/14] New command_post observer Joel Brobecker
@ 2010-04-25 15:48 ` Joel Brobecker
  2010-04-25 15:48 ` [vxworks 03/14] New module remote-wtx-utils Joel Brobecker
                   ` (11 subsequent siblings)
  15 siblings, 0 replies; 27+ messages in thread
From: Joel Brobecker @ 2010-04-25 15:48 UTC (permalink / raw)
  To: gdb-patches

This is the last patch! :)

It contains the changes needed to configure and build the VxWorks
debugger.

2010-04-24  Joel Brobecker  <brobecker@adacore.com>

        * configure.ac: Add support for vxworks targets.
        * configure: Regenerate.
        * configure.tgt: Add support for vxworks targets.
        * Makefile.in (VXWORKS_CFLAGS): New variable.
        (INTERNAL_CFLAGS_BASE): Use VXWORKS_CFLAGS.
---
 gdb/Makefile.in   |    6 ++-
 gdb/configure     |  119 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 gdb/configure.ac  |   75 +++++++++++++++++++++++++++++++++
 gdb/configure.tgt |   41 ++++++++++++++++++
 4 files changed, 240 insertions(+), 1 deletions(-)

diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index d62dc63..da1514b 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -402,6 +402,9 @@ CFLAGS = @CFLAGS@
 # Set by configure, for e.g. expat.
 INTERNAL_CPPFLAGS = @CPPFLAGS@
 
+# Set by configure for all CFLAGS related to vxWorks targets.
+VXWORKS_CFLAGS= @VXWORKS_CFLAGS@
+
 # Need to pass this to testsuite for "make check".  Probably should be
 # consistent with top-level Makefile.in and gdb/testsuite/Makefile.in
 # so "make check" has the same result no matter where it is run.
@@ -412,7 +415,8 @@ INTERNAL_CFLAGS_BASE = \
 	$(CFLAGS) $(GLOBAL_CFLAGS) $(PROFILE_CFLAGS) \
 	$(GDB_CFLAGS) $(OPCODES_CFLAGS) $(READLINE_CFLAGS) \
 	$(BFD_CFLAGS) $(INCLUDE_CFLAGS) $(LIBDECNUMBER_CFLAGS) \
-	$(INTL_CFLAGS) $(INCGNU) $(ENABLE_CFLAGS) $(INTERNAL_CPPFLAGS)
+	$(INTL_CFLAGS) $(INCGNU) $(ENABLE_CFLAGS) $(INTERNAL_CPPFLAGS) \
+	$(VXWORKS_CFLAGS)
 INTERNAL_WARN_CFLAGS = $(INTERNAL_CFLAGS_BASE) $(GDB_WARN_CFLAGS)
 INTERNAL_CFLAGS = $(INTERNAL_WARN_CFLAGS) $(GDB_WERROR_CFLAGS)
 
diff --git a/gdb/configure b/gdb/configure
index 301394f..2345e30 100755
--- a/gdb/configure
+++ b/gdb/configure
@@ -598,6 +598,7 @@ gl_LTLIBOBJS
 gl_LIBOBJS
 LTLIBOBJS
 LIBOBJS
+VXWORKS_CFLAGS
 GDB_NM_FILE
 frags
 target_subdir
@@ -14513,6 +14514,124 @@ ac_config_links="$ac_config_links $ac_config_links_1"
 $as_echo "#define GDB_DEFAULT_HOST_CHARSET \"UTF-8\"" >>confdefs.h
 
 
+# Support for vxWorks targets.
+
+case ${target} in
+   *-*-vxworks*)
+      { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -ldl" >&5
+$as_echo_n "checking for dlopen in -ldl... " >&6; }
+if test "${ac_cv_lib_dl_dlopen+set}" = set; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-ldl  $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char dlopen ();
+int
+main ()
+{
+return dlopen ();
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  ac_cv_lib_dl_dlopen=yes
+else
+  ac_cv_lib_dl_dlopen=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dl_dlopen" >&5
+$as_echo "$ac_cv_lib_dl_dlopen" >&6; }
+if test "x$ac_cv_lib_dl_dlopen" = x""yes; then :
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_LIBDL 1
+_ACEOF
+
+  LIBS="-ldl $LIBS"
+
+fi
+
+      ;;
+esac
+
+VXWORKS_CFLAGS=
+case "${target}" in
+
+  # vxWorks 653 targets.
+  *-vxworks653 | *-vxworksae )
+    if test "${WIND_FOUNDATION_PATH}" != ""; then
+      # vxWorks 653 version PSC 2.x
+      VXWORKS_CFLAGS="-I${WIND_FOUNDATION_PATH}/include"
+      vxworks_libdir="${WIND_FOUNDATION_PATH}/${WIND_HOST_TYPE}/lib"
+      case "${host_os}" in
+        mingw* | *-cygwin* )
+	  LIBS="${LIBS} $vxworks_libdir/tcl84.lib"
+	  ;;
+        * )
+	  LIBS="${LIBS} -L$vxworks_libdir"
+	  LIBS="${LIBS} -ltcl"
+	  ;;
+      esac
+    elif test "${WIND_BASE}" != ""; then
+      # vxWorks 653 version PSC 1.x
+      VXWORKS_CFLAGS="-I${WIND_BASE}/host/include"
+      vxworks_libdir="${WIND_BASE}/host/${WIND_HOST_TYPE}/lib"
+      case "${host_os}" in
+        mingw* | *-cygwin* )
+	  LIBS="${LIBS} $vxworks_libdir/tcldll.lib"
+	  ;;
+        * )
+	  LIBS="${LIBS} -L$vxworks_libdir"
+	  LIBS="${LIBS} -ltcl"
+	  ;;
+      esac
+    else
+      as_fn_error "cannot find vxWorks base installation from environment" "$LINENO" 5
+    fi
+    ;;
+
+  # vxWorks 6.x targets.
+  *-vxworks6 )
+    if test "${WIND_FOUNDATION_PATH}" = ""; then
+      as_fn_error "cannot find vxWorks base installation from environment" "$LINENO" 5
+    fi
+    VXWORKS_CFLAGS="-I${WIND_FOUNDATION_PATH}/include"
+    vxworks_libdir="${WIND_FOUNDATION_PATH}/${WIND_HOST_TYPE}/lib"
+    ;;
+
+  # vxWorks 5.x targets.
+  *-vxworks )
+    if test "${WIND_BASE}" = ""; then
+      as_fn_error "cannot find vxWorks base installation from environment" "$LINENO" 5
+    fi
+    VXWORKS_CFLAGS="-I${WIND_BASE}/host/include"
+    vxworks_libdir="${WIND_BASE}/host/${WIND_HOST_TYPE}/lib"
+    case "${host_os}" in
+      mingw* | *-cygwin* )
+        LIBS="${LIBS} $vxworks_libdir/tcldll.lib"
+        ;;
+      * )
+        LIBS="${LIBS} -L$vxworks_libdir"
+        LIBS="${LIBS} -ltcl"
+        ;;
+    esac
+    ;;
+esac
+
+
+
 ac_config_files="$ac_config_files Makefile .gdbinit:gdbinit.in gnulib/Makefile"
 
 ac_config_commands="$ac_config_commands default"
diff --git a/gdb/configure.ac b/gdb/configure.ac
index 4704a53..84cf1e5 100644
--- a/gdb/configure.ac
+++ b/gdb/configure.ac
@@ -1939,6 +1939,81 @@ dnl  At the moment, we just assume it's UTF-8.
 AC_DEFINE(GDB_DEFAULT_HOST_CHARSET, "UTF-8",
           [Define to be a string naming the default host character set.])
 
+# Support for vxWorks targets.
+
+dnl The WTX support requires dlopen to load the WTX libraries.
+case ${target} in
+   *-*-vxworks*)
+      AC_CHECK_LIB(dl, dlopen)
+      ;;
+esac
+
+VXWORKS_CFLAGS=
+case "${target}" in
+
+  # vxWorks 653 targets.
+  *-vxworks653 | *-vxworksae )
+    if test "${WIND_FOUNDATION_PATH}" != ""; then
+      # vxWorks 653 version PSC 2.x
+      VXWORKS_CFLAGS="-I${WIND_FOUNDATION_PATH}/include"
+      vxworks_libdir="${WIND_FOUNDATION_PATH}/${WIND_HOST_TYPE}/lib"
+      case "${host_os}" in
+        mingw* | *-cygwin* )
+	  LIBS="${LIBS} $vxworks_libdir/tcl84.lib"
+	  ;;
+        * )
+	  LIBS="${LIBS} -L$vxworks_libdir"
+	  LIBS="${LIBS} -ltcl"
+	  ;;
+      esac
+    elif test "${WIND_BASE}" != ""; then
+      # vxWorks 653 version PSC 1.x
+      VXWORKS_CFLAGS="-I${WIND_BASE}/host/include"
+      vxworks_libdir="${WIND_BASE}/host/${WIND_HOST_TYPE}/lib"
+      case "${host_os}" in
+        mingw* | *-cygwin* )
+	  LIBS="${LIBS} $vxworks_libdir/tcldll.lib"
+	  ;;
+        * )
+	  LIBS="${LIBS} -L$vxworks_libdir"
+	  LIBS="${LIBS} -ltcl"
+	  ;;
+      esac
+    else
+      AC_ERROR(cannot find vxWorks base installation from environment)
+    fi
+    ;;
+
+  # vxWorks 6.x targets.
+  *-vxworks6 )
+    if test "${WIND_FOUNDATION_PATH}" = ""; then
+      AC_ERROR(cannot find vxWorks base installation from environment)
+    fi
+    VXWORKS_CFLAGS="-I${WIND_FOUNDATION_PATH}/include"
+    vxworks_libdir="${WIND_FOUNDATION_PATH}/${WIND_HOST_TYPE}/lib"
+    ;;
+
+  # vxWorks 5.x targets.
+  *-vxworks )
+    if test "${WIND_BASE}" = ""; then
+      AC_ERROR(cannot find vxWorks base installation from environment)
+    fi
+    VXWORKS_CFLAGS="-I${WIND_BASE}/host/include"
+    vxworks_libdir="${WIND_BASE}/host/${WIND_HOST_TYPE}/lib"
+    case "${host_os}" in
+      mingw* | *-cygwin* )
+        LIBS="${LIBS} $vxworks_libdir/tcldll.lib"
+        ;;
+      * )
+        LIBS="${LIBS} -L$vxworks_libdir"
+        LIBS="${LIBS} -ltcl"
+        ;;
+    esac
+    ;;
+esac
+
+AC_SUBST(VXWORKS_CFLAGS)
+
 AC_OUTPUT(Makefile .gdbinit:gdbinit.in gnulib/Makefile,
 [
 case x$CONFIG_HEADERS in
diff --git a/gdb/configure.tgt b/gdb/configure.tgt
index ce063ef..a1e4be7 100644
--- a/gdb/configure.tgt
+++ b/gdb/configure.tgt
@@ -29,6 +29,14 @@ case $targ in
     ;;
 esac
 
+# The list of common files needed for all vxWorks ports.
+wtx_tdep_files="remote-wtxapi.o remote-wtx-opt.o remote-wtx-pd.o \
+		remote-wtx.o remote-wtx-utils.o remote-wtx-bp.o \
+		remote-wtx-hw.o remote-wtx-tasks.o"
+# The list of common files needed in order to support the DFW protocol
+# in vxWorks 6.x ports.
+dfw_tdep_files="remote-dfwapi.o remote-dfw.o"
+
 # map target info into gdb names.
 
 case "${targ}" in
@@ -230,6 +238,21 @@ i[34567]86-*-mingw32*)
 			solib-target.o corelow.o windows-tdep.o"
 	build_gdbserver=yes
 	;;
+i[34567]86-*-vxworks653 | [34567]86-*-vxworksae )
+	# Target: Intel 386 running vxWorks 653
+	gdb_target_obs="i386-tdep.o i387-tdep.o i386-vxworks-tdep.o \
+			${wtx_tdep_files} remote-wtx-tcl.o"
+	;;
+i[34567]86-*-vxworks6* )
+	# Target: Intel 386 running vxWorks 6.x
+	gdb_target_obs="i386-tdep.o i387-tdep.o ${dfw_tdep_files} \
+			${wtx_tdep_files} "
+	;;
+i[34567]86-*-vxworks* )
+	# Target: Intel 386 running vxWorks 5.x
+	gdb_target_obs="i386-tdep.o i387-tdep.o i386-vxworks-tdep.o \
+			${wtx_tdep_files} remote-wtx-tcl.o"
+	;;
 i[34567]86-*-*)
 	# Target: i386
 	gdb_target_obs="i386-tdep.o i387-tdep.o"
@@ -397,6 +420,24 @@ powerpc-*-linux* | powerpc64-*-linux*)
 	gdb_sim=../sim/ppc/libsim.a
 	build_gdbserver=yes
 	;;
+powerpc-*-vxworks653 | powerpc-*-vxworksae )
+	# Target: PowerPC running vxWorks 653
+	gdb_target_obs="rs6000-tdep.o rs6000-vxworks-tdep.o ppc-sysv-tdep.o \
+			solib.o solib-svr4.o \
+			${wtx_tdep_files} remote-wtx-tcl.o"
+	;;
+powerpc-*-vxworks6* | e500*-*-vxworks6* )
+	# Target: PowerPC running vxWorks 6.x
+	gdb_target_obs="rs6000-tdep.o rs6000-vxworks-tdep.o ppc-sysv-tdep.o \
+			solib.o solib-svr4.o \
+			${dfw_tdep_files} ${wtx_tdep_files} "
+	;;
+powerpc-*-vxworks* )
+	# Target: PowerPC running vxWorks 5.x
+	gdb_target_obs="rs6000-tdep.o rs6000-vxworks-tdep.o ppc-sysv-tdep.o \
+			solib.o solib-svr4.o \
+			${wtx_tdep_files} remote-wtx-tcl.o"
+	;;
 powerpc*-*-*)
 	# Target: PowerPC running eabi
 	gdb_target_obs="rs6000-tdep.o monitor.o dsrec.o ppcbug-rom.o \
-- 
1.6.3.3

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

* [vxworks 07/14] "multi-tasks-mode" support.
  2010-04-25 15:47 Adding support for VxWorks target Joel Brobecker
                   ` (10 preceding siblings ...)
  2010-04-25 15:56 ` [vxworks 06/14] VxWorks breakpoint-handling module Joel Brobecker
@ 2010-04-25 15:56 ` Joel Brobecker
  2010-04-25 15:56 ` [vxworks 12/14] Add support for VxWorks 6 Joel Brobecker
                   ` (3 subsequent siblings)
  15 siblings, 0 replies; 27+ messages in thread
From: Joel Brobecker @ 2010-04-25 15:56 UTC (permalink / raw)
  To: gdb-patches; +Cc: Joel Brobecker

VxWorks systems do not provide a concept of a process, but some users
would really like to be able to debug all the tasks running in their
"program", and only those.  The multi-tasks mode is an answer to that
request, based on the fact that Ada programs maintain a list of known
Ada tasks inside the runtime.  The debugger can access it to compute
the current list of Ada tasks, and from there determine the list of
VxWorks threads running as part of the user's application.

Given the fact that this feature relies on a property of the GNAT runtime,
it only works for Ada applications.

Resuming/stopping the relevant threads is done by calls to specialized
routines in the GNAT runtime.  This was necessary to avoid loads of
race conditions that we kept facing when doing this with WTX requests
to each and every affected thread.  The runtime routines have nice
properties that allow us to avoid the problem entirely.

2010-04-24  Joel Brobecker  <brobecker@adacore.com>

        * remote-wtx-tasks.h, remote-wtx-tasks.c: New files.
---
 gdb/remote-wtx-tasks.c |  201 ++++++++++++++++++++++++++++++++++++++++++++++++
 gdb/remote-wtx-tasks.h |   53 +++++++++++++
 2 files changed, 254 insertions(+), 0 deletions(-)
 create mode 100644 gdb/remote-wtx-tasks.c
 create mode 100644 gdb/remote-wtx-tasks.h

diff --git a/gdb/remote-wtx-tasks.c b/gdb/remote-wtx-tasks.c
new file mode 100644
index 0000000..b69c107
--- /dev/null
+++ b/gdb/remote-wtx-tasks.c
@@ -0,0 +1,201 @@
+/* Ada multi-task functionnalities for VxWorks targets.
+
+   Copyright 2005, 2010 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+/* Some symbol names embedded in the inferior when it uses tasks.  */
+
+#include "defs.h"
+#include "remote-wtxapi.h"
+#include "remote-wtx-bp.h"
+#include "remote-wtx-tasks.h"
+#include "gdbcmd.h"
+#include "target.h"
+
+#define ADA_STOP_ALL_TASKS ("system__tasking__debug__stop_all_tasks")
+#define ADA_STOP_ALL_TASKS_HANDLER ("system__tasking__debug__stop_all_tasks_handler")
+#define ADA_CONTINUE_ALL_TASKS  ("system__tasking__debug__continue_all_tasks")
+
+/* Breakpoint scope/action operations for the Ada multitask mode :
+   Ada application scope/Ada application action.  */
+
+static int multi_task_mode = 0;
+
+/* The user must not be allowed to change the value of the multitask
+   mode while debugging.  Unfortunately, the set/show mechanism does
+   not allow us to add this type of guard directly.  So what we do is
+   we let the "set multi-tasks-mode" command update the intermediate
+   variable below, and then let a hook called at each update propagate
+   the new value to MULTI_TASK_MODE if allowed, or report an error
+   if not.  */
+static int multi_task_mode_setshow_var = 0;
+
+/* Some variables used to cache the address of functions provided by the
+   inferior to suspend/resume all ada tasks.  */
+
+static CORE_ADDR continue_all_tasks_fun_addr  = 0;
+static CORE_ADDR stop_all_tasks_handler_fun_addr = 0;
+static CORE_ADDR stop_all_tasks_fun_addr = 0;
+
+/* Return non-zero if the user has selected the multi-tasks mode.  */
+
+int
+multi_task_mode_is_on (void)
+{
+  return multi_task_mode;
+}
+
+/* Initialize the breakpoint datas for the multi-tasks mode.  */
+
+void
+open_multi_task_mode (void)
+{
+  set_break_command_action (action_call);
+  set_break_command_call_rtn (stop_all_tasks_handler_fun_addr);
+}
+
+/* Initialize the breakpoint datas for the single-tasks mode.  */
+
+void
+close_multi_task_mode (void)
+{
+  set_break_command_action (action_task);
+  set_break_command_call_rtn (0);
+}
+
+/* Hook called after the "set multi-tasks-mode" command has been
+   executed.  This function verifies that the debugger is not already
+   debugging a process, or else cancels the user request with an
+   error message.  Otherwise, the request is processed by setting
+   MULTI_TASK_MODE to the new value.  */
+
+static void
+set_multi_tasks_mode_cmd (char *args, int from_tty,
+                          struct cmd_list_element *c)
+{
+  /* If we are already debugging a process, reset MULTI_TASK_MODE_SETSHOW_VAR
+     and report an error.  */
+  if (target_has_execution)
+    {
+      multi_task_mode_setshow_var = multi_task_mode;
+      error (_("\
+The multi-tasks mode cannot be changed while debugging a process"));
+    }
+
+  multi_task_mode = multi_task_mode_setshow_var;
+}
+
+void
+_initialize_remote_wtx_tasks (void)
+{
+  add_setshow_boolean_cmd ("multi-tasks-mode", no_class,
+                           &multi_task_mode_setshow_var,"\
+Set whether gdb is debugging the whole Ada kernel application on VxWorks.", "\
+Show whether gdb is debugging the whole Ada kernel application on VxWorks.", "\
+If set, on VxWorks, gdb debugs the whole Ada kernel application.",
+			   set_multi_tasks_mode_cmd, NULL,
+			   &setlist, &showlist);
+}
+
+/* Set the multi-tasks mode user setting to off (zero).  */
+
+void
+turn_multi_task_mode_off (void)
+{
+  multi_task_mode = 0;
+  multi_task_mode_setshow_var = 0;
+}
+
+/* Close the multi-tasking support.  */
+
+void
+stop_multi_task_mode (void)
+{
+  stop_all_tasks_fun_addr = 0;
+  continue_all_tasks_fun_addr = 0;
+  stop_all_tasks_handler_fun_addr = 0;
+
+  set_break_command_action (action_task);
+  set_break_command_call_rtn (0);
+}
+
+/* Set up the multi-tasks mode.
+
+   Automatically deactivate the multi-tasks mode if the inferior
+   is found to not use Ada tasks.  */
+
+void
+start_multi_task_mode (void)
+{
+  set_break_command_action (action_call);
+
+  remote_wtxapi_get_symbol_address (ADA_STOP_ALL_TASKS,
+                                    &stop_all_tasks_fun_addr);
+  remote_wtxapi_get_symbol_address (ADA_CONTINUE_ALL_TASKS,
+                                    &continue_all_tasks_fun_addr);
+
+  if (stop_all_tasks_fun_addr == 0 || continue_all_tasks_fun_addr == 0)
+    {
+      warning (_("Your application does not use Ada tasking.\n\
+multi-tasks-mode turned off."));
+      turn_multi_task_mode_off ();
+      stop_multi_task_mode ();
+      return;
+    }
+
+  /* Search for ADA_STOP_ALL_TASKS_HANDLER and install it if we can
+     find it.  */
+  remote_wtxapi_get_symbol_address (ADA_STOP_ALL_TASKS_HANDLER,
+        			    &stop_all_tasks_handler_fun_addr);
+  if (stop_all_tasks_handler_fun_addr != 0)
+    set_break_command_call_rtn (stop_all_tasks_handler_fun_addr);
+}
+
+/* Resume all Ada tasks in our inferior.  */
+
+int
+continue_all_ada_tasks ()
+{
+  long *ignored_retval;
+
+  if (continue_all_tasks_fun_addr != 0)
+    return wtxapi_direct_call (continue_all_tasks_fun_addr, &ignored_retval,
+                               0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
+  
+  return 0;
+}
+
+/* Stop all Ada tasks in our inferior.  After this operation, the Ada tasks
+   can be either suspended, and stopped, depending of the vxWorks version;
+   this information is returned in STATUS.  */
+
+int
+stop_all_ada_tasks (enum wtx_task_status *status)
+{
+  long *ignored_retval;
+
+  if (stop_all_tasks_fun_addr != 0)
+    {
+      *status = WTX_TASK_STATUS_STOPPED;
+      return wtxapi_direct_call (stop_all_tasks_fun_addr, &ignored_retval,
+                                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
+    }
+
+  *status = WTX_TASK_STATUS_RUNNING;
+  return 0;
+}
+
diff --git a/gdb/remote-wtx-tasks.h b/gdb/remote-wtx-tasks.h
new file mode 100644
index 0000000..d7b6129
--- /dev/null
+++ b/gdb/remote-wtx-tasks.h
@@ -0,0 +1,53 @@
+/* Ada multi-task functionnalities for VxWorks targets.
+
+   Copyright 2005, 2010 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+/*  FIXME: brobecke/2007-10-19: We're introducing a new API which should
+    be simpler to use.
+
+    In order to avoid colliding with the deprecated interface, we will
+    temporarily break the naming scheme and not prepend our function
+    names with "wtx_tasks_" for now.  The plan is to rename all the
+    deprecated routines using the "deprecated_" prefix, followed by
+    renaming these new functions.  To be done later.  */
+
+/* Task status; used to know which routine to use when resuming the
+   inferior.  Note that STOPPED and SUSPENDED are actually the same
+   status on VxWorks 5.  */
+
+enum wtx_task_status
+  {
+    WTX_TASK_STATUS_CREATED,
+    WTX_TASK_STATUS_RUNNING,
+    WTX_TASK_STATUS_STOPPED,
+    WTX_TASK_STATUS_SUSPENDED,
+    WTX_TASK_STATUS_UNKNOWN
+  };
+
+int multi_task_mode_is_on (void);
+
+void turn_multi_task_mode_off (void);
+
+void start_multi_task_mode (void);
+
+void stop_multi_task_mode (void);
+
+int continue_all_ada_tasks (void);
+
+int stop_all_ada_tasks (enum wtx_task_status *status);
+
-- 
1.6.3.3

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

* [vxworks 06/14] VxWorks breakpoint-handling module.
  2010-04-25 15:47 Adding support for VxWorks target Joel Brobecker
                   ` (9 preceding siblings ...)
  2010-04-25 15:56 ` [vxworks 05/14] Add options to control Vxworks related settings Joel Brobecker
@ 2010-04-25 15:56 ` Joel Brobecker
  2010-04-25 15:56 ` [vxworks 07/14] "multi-tasks-mode" support Joel Brobecker
                   ` (4 subsequent siblings)
  15 siblings, 0 replies; 27+ messages in thread
From: Joel Brobecker @ 2010-04-25 15:56 UTC (permalink / raw)
  To: gdb-patches

This unit provides a set of routines that allow us to insert/remove
breakpoints and watchpoints on the target.  The target takes care of
the insertion/removal, but we need to keep track of respective IDs...

2010-04-24  Joel Brobecker  <brobecker@adacore.com>

        * remote-wtx-bp.h, remote-wtx-bp.c: New files.
---
 gdb/remote-wtx-bp.c |  235 +++++++++++++++++++++++++++++++++++++++++++++++++++
 gdb/remote-wtx-bp.h |  159 ++++++++++++++++++++++++++++++++++
 2 files changed, 394 insertions(+), 0 deletions(-)
 create mode 100644 gdb/remote-wtx-bp.c
 create mode 100644 gdb/remote-wtx-bp.h

diff --git a/gdb/remote-wtx-bp.c b/gdb/remote-wtx-bp.c
new file mode 100644
index 0000000..25bb92a
--- /dev/null
+++ b/gdb/remote-wtx-bp.c
@@ -0,0 +1,235 @@
+/* WTX backend for GDB.
+
+   Copyright 2007, 2010 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#include "defs.h"
+#include "remote-wtx-bp.h"
+
+static enum wtx_breakpoint_action break_command_action = action_task;
+
+void
+set_break_command_action (enum wtx_breakpoint_action action)
+{
+  break_command_action = action;
+}
+
+enum wtx_breakpoint_action
+get_break_command_action (void)
+{
+  return break_command_action;
+}
+
+/* Handling of breakpoint command call routine.  */
+
+static CORE_ADDR break_command_call_rtn = 0;
+
+void
+set_break_command_call_rtn (CORE_ADDR call_rtn)
+{
+  break_command_call_rtn = call_rtn;
+}
+
+CORE_ADDR
+get_break_command_call_rtn (void)
+{
+  return break_command_call_rtn;
+}
+
+/* --------------------------
+   --  Breakpoint support  --
+   --------------------------  */
+
+/* Handling of eventpoint IDs.
+
+   VxWorks provides eventpoints for breakpoints and watchpoints.  For each
+   inserted breakpoint, the target server returns an evenpoint ID that we
+   need to record, because we will need this ID to remove this breakpoint.  */
+
+struct eventpoint_info
+{
+  struct bp_target_info *target_info;
+  evtpt_id_t id;
+  WTX_CONTEXT_TYPE context_type;
+  WTX_CONTEXT_ID_T context_id;
+
+  struct eventpoint_info *next;
+};
+
+struct eventpoint_info *eventpoints;
+
+/* Create an new eventpoint_info structure with the given parameters,
+   and insert it at the head of our EVENTPOINTS list.  */
+
+void
+wtx_bp_register_eventpoint_id (evtpt_id_t id,
+                               struct bp_target_info *target_info,
+			       WTX_CONTEXT_TYPE context_type,
+			       WTX_CONTEXT_ID_T context_id)
+{
+  struct eventpoint_info *new_info =
+    xmalloc (sizeof (struct eventpoint_info));
+
+  new_info->target_info = target_info;
+  new_info->id = id;
+  new_info->context_type = context_type;
+  new_info->context_id = context_id;
+
+  /* Insert at the head of our EVENTPOINTS list.  */
+  new_info->next = eventpoints;
+  eventpoints = new_info;
+}
+
+/* Return the eventpoint ID associated to the given TARGET_INFO,
+   and remove its entry in our EVENTPOINTS list.  Return the
+   associated context in CONTEXT_TYPE and CONTEXT_ID.
+
+   Return invalid_evtpt_id if the target_info is unknown to us.  */
+
+evtpt_id_t
+wtx_bp_pop_eventpoint_id (struct bp_target_info *target_info,
+			  WTX_CONTEXT_TYPE *context_type,
+			  WTX_CONTEXT_ID_T *context_id)
+{
+  struct eventpoint_info *info = eventpoints;
+  struct eventpoint_info *prev_info = NULL;
+  evtpt_id_t evtpt_id = invalid_evtpt_id;
+
+  while (info != NULL)
+    {
+      if (info->target_info == target_info)
+        {
+          evtpt_id = info->id;
+	  *context_type = info->context_type;
+	  *context_id = info->context_id;
+
+          /* Delete this node.  */
+          if (prev_info != NULL)
+            prev_info->next = info->next;
+          else
+            eventpoints = info->next;
+          xfree (info);
+
+          break;
+        }
+      prev_info = info;
+      info = info->next;
+    }
+
+  return evtpt_id;
+}
+
+/*  --------------------------
+    --  Watchpoint support  --
+    --------------------------  */
+
+/* A structure to do the mapping between a GDB watchpoint and the associated
+   eventpoint ID created by the target.  We use this mapping in order to
+   be able to remove a watchpoint.  */
+
+struct watchpoint_info
+{
+  CORE_ADDR data_addr;
+  int data_len;
+  int type;
+  evtpt_id_t watchpoint_id;
+  
+  struct watchpoint_info *next;
+};
+
+/* The list of watchpoints we inserted in the target.  */
+static struct watchpoint_info *watchpoint_list = NULL;
+
+/* Return non-zero if INFO matches (DATA_ADDR, DATA_LEN, TYPE).
+   In other words, return non-zero if INFO is the watchpont_info
+   object that corresponds to a GDB watchpoint.  */
+
+static int
+watchpoint_info_matches (struct watchpoint_info *info,
+                         CORE_ADDR data_addr, int data_len, int type)
+{
+  return (info->data_addr == data_addr
+          && info->data_len == data_len
+          && info->type == type);
+}
+
+/* Record in our watchpoint list the fact that we just inserted a watchpoint
+   on the target.  */
+
+void
+wtx_bp_register_watchpoint_id (evtpt_id_t watchpoint_id, CORE_ADDR data_addr,
+                               int data_len, int type)
+{
+  struct watchpoint_info *info = xmalloc (sizeof (struct watchpoint_info));
+
+  info->data_addr = data_addr;
+  info->data_len = data_len;
+  info->type = type;
+  info->watchpoint_id = watchpoint_id;
+
+  /* Now insert this new node at the head.  */
+  info->next = watchpoint_list;
+  watchpoint_list = info;
+}
+
+/* Search our list of watchpoint_info objects, and pop the entry
+   that matches the watchpoint corresponding to (DATA_ADDR, DATA_LEN,
+   TYPE).  Return the associated eventpoint ID.
+
+   Return invalid_evtpt_id if no match was found.  */
+
+evtpt_id_t
+wtx_bp_pop_watchpoint_id (CORE_ADDR data_addr, int data_len, int type)
+{
+  struct watchpoint_info *info = watchpoint_list;
+  evtpt_id_t watchpoint_id;
+
+  /* Check to see if the node at the head of the watchpoint list matches
+     the description.  If yes, then destroy that node.  Given that on certain
+     architectures, we only have access to one watchpoints, this condition
+     should be true most of the time.  */
+
+  if (info != NULL
+      && watchpoint_info_matches (info, data_addr, data_len, type))
+    {
+      watchpoint_id = info->watchpoint_id;
+      watchpoint_list = info->next;
+      free (info);
+      return watchpoint_id;
+    }
+
+  /* If not, then look for the node that is immediately preceding the node
+     we're looking for.  Then do the freeing and reconnecting.  */
+  while (info != NULL)
+    {
+      if (info->next != NULL
+          && watchpoint_info_matches (info->next, data_addr, data_len, type))
+        {
+          struct watchpoint_info *tmp = info->next;
+
+          watchpoint_id = tmp->watchpoint_id;
+          info->next = tmp->next;
+          free (tmp);
+          return watchpoint_id;
+        }
+      info = info->next;
+    }
+
+  /* No corresponding watchpoint eventpoint found.  */
+  return invalid_evtpt_id;
+}
+
diff --git a/gdb/remote-wtx-bp.h b/gdb/remote-wtx-bp.h
new file mode 100644
index 0000000..3e241e0
--- /dev/null
+++ b/gdb/remote-wtx-bp.h
@@ -0,0 +1,159 @@
+/* WTX backend for GDB.
+
+   Copyright 2007, 2010 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#ifndef REMOTE_WTX_BP_H
+#define REMOTE_WTX_BP_H
+
+#include "remote-wtxapi.h"
+
+/* A note about breakpoint command "scope" and "action" settings:
+   --------------------------------------------------------------
+
+   These as concepts that were introduced in VxWorks AE, but no longer
+   make much sense in VxWorks 653.  On 653, the user will debug either:
+
+     1. A task inside the kernel partition;
+
+     2. An entire partition, which in pratice is exactly similar to (1),
+        since it is done by debugging the task associated to that partition;
+
+     3. The entire system in "system-mode".
+
+   This means that are are actually realy only debugging modes available
+   to the user:
+     a. The single-task mode
+     b. The system-mode.
+
+   In system-mode, the scope and action are, by design from the system,
+   irrelevant.  Breakpoints will stop the entire system when any task
+   hits them.
+
+   In single-task mode, we user is debugging his task independently
+   of the rest of the system.  This means that the scope of breakpoints
+   in that mode will be that task and only that task.  Similarly, we
+   are forcing the action to that task as well.
+
+   As a result, the scope and actions can be implicitly determined
+   from the debugging context, and thus do not require user input.
+   This is why there is no longer a "set" command that allows the
+   user to change it anymore.
+
+   Also, this also means that the context and action can no longer
+   change during a debugging session.  As a consequence, although
+   the system does allow tools to use independent scope and action
+   settings for every breakpoints, the debugger will be using
+   consistent settings, thus avoiding the need to track what
+   breakpoint uses what setting.  This knowledge is important
+   when resuming breakpoints, because if a breakpoint stopped
+   all tasks, then we need to resume all tasks when doing a
+   "continue" for instance.  
+
+   brobecker/2007-09-25: It is conceivable that some users might
+   find that have the choice of setting the action to "all" for
+   their debugging session would be helpful, or even necessary.
+   In that case, the system-mode might be more approriate to their
+   needs.  However, the system-mode does have some limitations that
+   might not be acceptable either.  This code has been designed in
+   such a way that adding that feature, this extra choice, should
+   just be a matter of adding a "set" command to let the user change
+   the action.  */
+
+/* Advance declarations.  */
+
+struct bp_target_info;
+
+/* The following enum defines the various actions that can be taken
+   when a breakpoint is hit.  */
+
+enum wtx_breakpoint_action
+{
+  action_task,  /* Stop the current task.  */
+  action_all,   /* Stop all breakable tasks in all partitions.  */
+  action_call   /* Stop the current task and call a stop function on the
+		   target, if this function is defined.  */
+};
+
+/* Exported routines.  */
+
+void wtx_bp_register_eventpoint_id (evtpt_id_t id,
+                                    struct bp_target_info *target_info,
+				    WTX_CONTEXT_TYPE context_type,
+				    WTX_CONTEXT_ID_T context_id);
+
+evtpt_id_t wtx_bp_pop_eventpoint_id (struct bp_target_info *target_info,
+				     WTX_CONTEXT_TYPE *context_type,
+				     WTX_CONTEXT_ID_T *context_id);
+
+void set_break_command_call_rtn (CORE_ADDR call_rtn);
+
+CORE_ADDR get_break_command_call_rtn (void);
+
+void set_break_command_action (enum wtx_breakpoint_action);
+
+enum wtx_breakpoint_action get_break_command_action (void);
+
+/* Watchpoint support.  */
+
+/*  HARDWARE WATCHPOINT SUPPORT:
+    ============================
+
+    Strictly speaking, the only systems that support hardware watchpoints
+    are the targets that implement BoDA (Break on Data Access) events.
+    This functionality was introduced in a limited number of versions
+    of VxWorks 653 which can be identified once we're connected to
+    the system (see wtxapi_target_has_BoDA).
+
+    For systems that do not support BoDA, there is another type of
+    watchpoint event (WTX_EVENT_DATA_ACCESS) which, according to
+    WindRiver is not strictly speaking a hardware watchpoint because
+    it doesn't use the features of the target hardware to implement it.
+    However, from the debugger's perspective, these watchpoint events
+    are still viewed as hardware, because they do not require us to
+    emulate watchpoint support at the debugger level.  Although not as
+    fast as strict hardware watchpoint support, these events are still
+    faster than having to emulate them at the debugger level, since it
+    avoids a very large amount of interaction between the debugger and
+    the target.  Experimentations on VxWorks 5.5 and VxWorks 653 have
+    revealed that only one such event can be used at the same time:
+      - On VxWorks 5.5, the system lets you insert the events, but
+        somehow then fails to notify the tools for any of the watchpoints
+      - On VxWorks 653, the system returns an error when trying to
+        insert the second data-access event.
+
+    For systems supporting BoDA, there is one and only one watchpoint
+    available.  Any other watchpoints must be emulated at the debugger
+    level.  */
+
+/* brobecker/2007-10-05: For some reason, I remembered that hardware-assisted
+   watchpoints do not stop at the instruction that caused the watchpoint
+   trigger, but rather stops at the next instruction.  So single-stepping
+   of one instruction in order to get the new value is not necessary for
+   WTX_EVENT_HW_BP and WTX_EVENT_BODA.  But a previous implementation
+   seems to contradict my memory.  So for now, we do not adjust
+   GDBARCH_HAVE_NONSTEPPABLE_WATCHPOINT.  We will worry about this when
+   we actually encounter a problem.  */
+
+void wtx_bp_register_watchpoint_id (evtpt_id_t watchpoint_id,
+                                    CORE_ADDR data_addr,
+                                    int data_len, int type);
+
+evtpt_id_t wtx_bp_pop_watchpoint_id (CORE_ADDR data_addr, int data_len,
+                                     int type);
+
+#endif
-- 
1.6.3.3

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

* [vxworks 12/14] Add support for VxWorks 6
  2010-04-25 15:47 Adding support for VxWorks target Joel Brobecker
                   ` (11 preceding siblings ...)
  2010-04-25 15:56 ` [vxworks 07/14] "multi-tasks-mode" support Joel Brobecker
@ 2010-04-25 15:56 ` Joel Brobecker
  2010-04-25 16:01 ` [vxworks 04/14] remote-wtxapi: The WTX API abstraction layer Joel Brobecker
                   ` (2 subsequent siblings)
  15 siblings, 0 replies; 27+ messages in thread
From: Joel Brobecker @ 2010-04-25 15:56 UTC (permalink / raw)
  To: gdb-patches

2010-04-24  Jerome Guitton  <guitton@adacore.com>

	* remote-dfw.c, remote-dfwapi.h, remote-dfwapi.c: New files.
---
 gdb/remote-dfw.c    |  132 +++
 gdb/remote-dfwapi.c | 3264 +++++++++++++++++++++++++++++++++++++++++++++++++++
 gdb/remote-dfwapi.h |  191 +++
 3 files changed, 3587 insertions(+), 0 deletions(-)
 create mode 100644 gdb/remote-dfw.c
 create mode 100644 gdb/remote-dfwapi.c
 create mode 100644 gdb/remote-dfwapi.h

diff --git a/gdb/remote-dfw.c b/gdb/remote-dfw.c
new file mode 100644
index 0000000..3bc0206
--- /dev/null
+++ b/gdb/remote-dfw.c
@@ -0,0 +1,132 @@
+/* Remote target communications for VxWorks 6 targets.
+
+   Copyright 2005
+   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 2 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, write to the Free Software
+   Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#include "defs.h"
+#include "target.h"
+#include "gdbcmd.h"
+#include "completer.h"
+
+#include "remote-wtx.h"
+#include "remote-wtxapi.h"
+#include "remote-wtx-tasks.h"
+#include "remote-wtx-hw.h"
+#include "remote-dfwapi.h"
+#define HOST
+#include "wtx.h"
+
+/* DFW connection parameters.  */
+
+static char default_dfw_server_name[] = "dfw";
+static char *dfw_server_name = NULL;
+
+/* This module's target-specific operations.  */
+static struct target_ops remote_dfw_ops;
+
+/* Initialization routines.  */
+
+static void init_remote_dfw_ops (void);
+void _initialize_remote_dfw (void);
+
+/* Target hooks.  */
+
+static void remote_dfw_open (char *name, int from_tty);
+static void remote_dfw_close (int quitting);
+
+/* Open a connection to a dfw target named NAME.  */
+
+static void
+remote_dfw_open (char *name, int from_tty)
+{
+  if (!name)
+    error ("No target name specified.");
+  dfwapi_open (dfw_server_name, name, target_gdbarch);
+
+  push_target (&remote_dfw_ops);
+
+  if (!wtxapi_tool_attach (dfwapi_get_target_name (), "gdbwtx"))
+    error ("Could not reach target server: %s", wtxapi_err_msg_get ());
+
+  wtxapi_tool_detach ();
+  wtx_open (dfwapi_get_target_name (), 0);
+  printf_unfiltered ("done.\n");
+}
+
+/* Clean up connection to a dfw target.  */
+
+static void
+remote_dfw_close (int quitting)
+{
+}
+
+static void
+init_remote_dfw_ops (void)
+{
+  remote_dfw_ops.to_shortname = "dfw";
+  remote_dfw_ops.to_longname = "Wind River System's DFW protocol";
+  remote_dfw_ops.to_doc = "Use Wind River System's DFW protocol";
+  remote_dfw_ops.to_stratum = core_stratum;
+  remote_dfw_ops.to_magic = OPS_MAGIC;
+  remote_dfw_ops.to_open = remote_dfw_open;
+  remote_dfw_ops.to_close = remote_dfw_close;
+}
+
+/* Set the DFW server name.  This name is used as a key for wtxInfoQ,
+   which is the wtx request used to get the dfw server host and port.  */
+
+static void
+set_dfw_server_name (char *arg, int from_tty)
+{
+  if (!arg || *arg == '\0')
+    {
+      if (dfw_server_name)
+	printf_unfiltered ("DFW server name is %s\n", dfw_server_name);
+    }
+  else
+    {
+      if (dfw_server_name)
+	xfree (dfw_server_name);
+      dfw_server_name = xstrdup (arg);
+    }
+}
+
+static void
+init_dfw_server_name ()
+{
+  char *name = getenv ("DFW_SERVER_NAME");
+  if (name && name [0] != '\0')
+    set_dfw_server_name (name, 0);
+  else
+    set_dfw_server_name (default_dfw_server_name, 0);
+}
+
+void
+_initialize_remote_dfw (void)
+{
+  struct cmd_list_element *c;
+
+  init_remote_dfw_ops ();
+  add_target (&remote_dfw_ops);
+  init_dfw_server_name ();
+
+  add_cmd ("dfw-server-name", no_class, set_dfw_server_name,
+	   "Set the dfw server name.\n", &cmdlist);
+}
diff --git a/gdb/remote-dfwapi.c b/gdb/remote-dfwapi.c
new file mode 100644
index 0000000..df424c6
--- /dev/null
+++ b/gdb/remote-dfwapi.c
@@ -0,0 +1,3264 @@
+/* Remote debugging API based on Wind River System's DFW protocol.
+
+   Copyright 2005, 2010 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+/* GENERAL DESCRIPTION:
+
+   This file implements an debug API based on Wind River System's
+   debugger framework.  It is used to know which threads are running
+   on a VxWorks 6 target.
+
+   It uses two protocols:
+   * WTX: we only need one WTX call from the wind registry (to get the
+   connection parameters of the dfwserver).
+   * DFW: to ask the DFW server about threads running on target.
+
+   (X <---Y---> Z means "X communicates with Z using the protocol Y)
+
+   .-----.   WTX   .---------------.
+   | GDB |<------->| WIND REGISTRY |
+   |     |         `---------------'
+   |     |   DFW   .------------.   WTX   .---------------.   WDB  .--------.
+   |     |<------->| DFW SERVER |<------->| TARGET SERVER |<------>| TARGET |
+   `-----'         `------------'         `---------------'        `--------'
+
+   A connection scenario:
+
+   (X --Y-->Z means "X sends the message Y to Z")
+
+   .-----.              .---------------.  .------------.
+   | GDB |              | WIND REGISTRY |  | DFW SERVER |
+   `-----'              `---------------'  `------------'
+      |    wtxapi_info_q query   |                 |
+      |------------------------->|                 |
+      |  dfw connection params   |                 |
+      |<-------------------------|                 |
+      |                                            |
+      | -wrs-info-retrieve /Targets default:* ...  |
+      |------------------------------------------->|
+      |         list of known targets              |
+      |<-------------------------------------------|
+
+   et cetera...
+
+   Here is a general description of the way we call a DFW primitive:
+   1) we send the request (text format) to the DFW server;
+   2) we reset the current_result_table and buffer the output in its
+   string_table after a lexical analysis (stored in the dfw_lex_tree);
+   3) then, we do a semantic analysis and we save the result on the
+   dfw_sem_tree.
+   4) finally, we can extract the information from the sem table using the
+   sem_element interface.
+
+   The result of the sem and lex analysis are stored into preallocated
+   integer tables whose sizes are increased if needed.  In those tables,
+   can be stored:
+   * lex (resp. sem) token types (e.g. DFW_LEX_COMMA);
+   * index in the string buffer (for string params associated to the token
+   type).
+
+   For example, the following  DFW server output:
+
+   ^done,i=[["defaultTarget","tgt_liege@borticado"]]
+
+   would be stored in the lex table of current_result_table as followed:
+
+   DFW_LEX_ITEM
+   i
+   DFW_LEX_EQUALS
+   DFW_LEX_BEGIN_LIST
+   DFW_LEX_BEGIN_LIST
+   DFW_LEX_CSTRING
+   defaultTarget
+   DFW_LEX_COMMA
+   DFW_LEX_CSTRING
+   tgt_liege@borticado
+   DFW_LEX_END_LIST
+   DFW_LEX_END_LIST
+
+   and the sem table would be:
+
+   DFW_SEM_RESULT_CLASS
+   done
+   DFW_SEM_VARIABLE
+   i
+   DFW_SEM_VALUE
+   DFW_SEM_BEGIN_LIST
+   DFW_SEM_VALUE
+   DFW_SEM_BEGIN_LIST
+   DFW_SEM_VALUE
+   DFW_SEM_CONST
+   defaultTarget
+   DFW_SEM_VALUE
+   DFW_SEM_CONST
+   tgt_liege@borticado
+   DFW_SEM_END_LIST
+   DFW_SEM_END_LIST
+
+   (The grammar of the GDB/MI language is defined in the GDB documentation).
+
+   If any asynchronous output is found during the analysis of the result,
+   we analyse it the same way, store the result of the analysis into
+   current_async_record and call the callback which corresponds to this
+   kind and async output.  */
+
+#include "defs.h"
+#include "serial.h"
+#include "gdbcmd.h"
+#include "gdbthread.h"
+#include "remote-wtxapi.h"
+#include "remote-dfwapi.h"
+#include "remote-wtx-pd.h"
+
+struct dfwapi_task dfwapi_system_task = {NULL, DFWAPI_CONTEXT_LAST,
+					 0, 0, 0, 0};
+
+/* DFW connection parameters.  */
+
+struct dfwapi_connection
+{
+  int system_dfw_id;
+  char *full_target_name;
+  char *core_name;
+  char *info_retrieval_core_branch;
+  char *thread_id_leaf;
+  int info_retrieval_core_branch_len;
+  enum bfd_endian byte_order;
+};
+
+static struct dfwapi_connection null_connection =
+  {0, NULL, NULL, NULL, 0, BFD_ENDIAN_UNKNOWN};
+static struct dfwapi_connection *current_connection = &null_connection;
+
+static int load_timeout = 30;
+static int dfw_timeout = 10;
+static int current_selected_thread = 0;
+
+/* Index type for tables (lex and sem) and buffer (strings): */
+
+typedef unsigned int index_type;
+
+/* Type of the elements in the lex (resp. sem) tables.  */
+
+typedef int dfw_tree_element;
+
+/* Type of description of the lex (or sem) tree element.  */
+
+struct dfw_tree_element_desc
+{
+  dfw_tree_element code;
+  /* Code of this tree element.  */
+
+  char *name;
+  /* Tree element name.  */
+
+  int params;
+  /* If 1, a string paramter is expected (i.e. this tree element should be
+     followed, in the table, by an index in the string buffer).
+     If -1, a special integer parameter is expected.
+     If 0, no parameter is expected.  */
+};
+
+struct enum_desc
+{
+  int code;
+  char *name;
+};
+
+/* Tree element codes for the lexical analysis.  */
+
+enum dfw_lex_type
+  {
+    DFW_LEX_COMMA,
+    DFW_LEX_EQUALS,
+    DFW_LEX_BEGIN_TUPLE,
+    DFW_LEX_END_TUPLE,
+    DFW_LEX_BEGIN_LIST,
+    DFW_LEX_END_LIST,
+    DFW_LEX_CSTRING,
+    DFW_LEX_ITEM,
+    DFW_LEX_LAST
+  };
+
+/* Description record for the lexical tree elements.  */
+
+static const struct dfw_tree_element_desc dfw_lex_list[] =
+{
+  {DFW_LEX_COMMA, "DFW_LEX_COMMA", 0},
+  {DFW_LEX_EQUALS, "DFW_LEX_EQUALS", 0},
+  {DFW_LEX_BEGIN_TUPLE, "DFW_LEX_BEGIN_TUPLE", 0},
+  {DFW_LEX_END_TUPLE, "DFW_LEX_END_TUPLE", 0},
+  {DFW_LEX_BEGIN_LIST, "DFW_LEX_BEGIN_LIST", 0},
+  {DFW_LEX_END_LIST, "DFW_LEX_END_LIST", 0},
+  {DFW_LEX_CSTRING, "DFW_LEX_CSTRING", 1},
+  {DFW_LEX_ITEM, "DFW_LEX_ITEM", 1},
+  {DFW_LEX_LAST,"DFW_LEX_UNKNOWN", 0}
+};
+
+/* Tree element codes for the semantic analysis.  */
+
+enum dfw_sem_type
+  {
+    DFW_SEM_RESULT_CLASS,
+    DFW_SEM_ASYNC_CLASS,
+    DFW_SEM_VARIABLE,
+    DFW_SEM_VALUE,
+    DFW_SEM_RESULT,
+    DFW_SEM_CONST,
+    DFW_SEM_BEGIN_TUPLE,
+    DFW_SEM_END_TUPLE,
+    DFW_SEM_BEGIN_LIST,
+    DFW_SEM_END_LIST,
+    DFW_SEM_LAST
+  };
+
+/* Description record for the semantic tree elements.  */
+
+static const struct dfw_tree_element_desc dfw_sem_list[] =
+{
+  {DFW_SEM_RESULT_CLASS, "DFW_SEM_RESULT_CLASS", -1},
+  {DFW_SEM_ASYNC_CLASS, "DFW_SEM_ASYNC_CLASS", -1},
+  {DFW_SEM_VARIABLE, "DFW_SEM_VARIABLE", 1},
+  {DFW_SEM_VALUE, "DFW_SEM_VALUE", 0},
+  {DFW_SEM_RESULT, "DFW_SEM_RESULT", 0},
+  {DFW_SEM_CONST, "DFW_SEM_CONST", 1},
+  {DFW_SEM_BEGIN_TUPLE, "DFW_SEM_BEGIN_TUPLE", 0},
+  {DFW_SEM_END_TUPLE, "DFW_SEM_END_TUPLE", 0},
+  {DFW_SEM_BEGIN_LIST, "DFW_SEM_BEGIN_LIST", 0},
+  {DFW_SEM_END_LIST, "DFW_SEM_END_LIST", 0},
+  {DFW_SEM_LAST,"DFW_SEM_UNKNOWN", 0}
+};
+
+/* tree element code for the result class.  */
+
+enum result_class_type
+  {
+    RESULT_CLASS_DONE,
+    RESULT_CLASS_RUNNING,
+    RESULT_CLASS_CONNECTED,
+    RESULT_CLASS_ERROR,
+    RESULT_CLASS_EXIT,
+    RESULT_CLASS_STOPPED,
+    RESULT_CLASS_LAST
+  };
+
+/* Description record for the result classes.  */
+
+static const struct dfw_tree_element_desc result_class_list[] =
+  {
+    {RESULT_CLASS_DONE, "done", -1},
+    {RESULT_CLASS_RUNNING, "running", -1},
+    {RESULT_CLASS_CONNECTED, "connected", -1},
+    {RESULT_CLASS_ERROR, "error", -1},
+    {RESULT_CLASS_EXIT, "exit", -1},
+    {RESULT_CLASS_STOPPED, "stopped", -1},
+    {RESULT_CLASS_LAST, "unkwown", -1}
+  };
+
+/* Description record for the asynchronous result classes.  */
+
+static const struct dfw_tree_element_desc dfwapi_async_class_list[] =
+  {
+    {DFWAPI_ASYNC_CLASS_STATELESS, "stateless", -1},
+    {DFWAPI_ASYNC_CLASS_STOPPED, "stopped", -1},
+    {DFWAPI_ASYNC_CLASS_RUNNING, "running", -1},
+    {DFWAPI_ASYNC_CLASS_CONTAINER_STOPPED, "container-stopped", -1},
+    {DFWAPI_ASYNC_CLASS_INDETERMINATE_STATE, "indeterminate-state", -1},
+    {DFWAPI_ASYNC_CLASS_CONNECTED, "connected", -1},
+    {DFWAPI_ASYNC_CLASS_DISCONNECTED, "disconnected", -1},
+    {DFWAPI_ASYNC_CLASS_REGISTER_CHANGED, "register-changed", -1},
+    {DFWAPI_ASYNC_CLASS_MEMORY_CHANGED, "memory-changed", -1},
+    {DFWAPI_ASYNC_CLASS_DOWNLOAD, "download", -1},
+    {DFWAPI_ASYNC_CLASS_DOWNLOAD_COMPLETE, "download-complete", -1},
+    {DFWAPI_ASYNC_CLASS_DOWNLOAD_FAILED, "download-failed", -1},
+    {DFWAPI_ASYNC_CLASS_MODULES_CHANGED, "modules-changed", -1},
+    {DFWAPI_ASYNC_CLASS_CONTEXT_START, "context-start", -1},
+    {DFWAPI_ASYNC_CLASS_CONTEXT_EXIT, "context-exit", -1},
+    {DFWAPI_ASYNC_CLASS_TOOL_DETACH, "tool-detach", -1},
+    {DFWAPI_ASYNC_CLASS_TOOL_ATTACH, "tool-attach", -1},
+    {DFWAPI_ASYNC_CLASS_REGDEFCHANGED, "regdefchanged", -1},
+    {DFWAPI_ASYNC_CLASS_BREAKPOINT_CHANGED, "breakpoint-changed", -1},
+    {DFWAPI_ASYNC_CLASS_EVENTPOINT_CHANGED, "eventpoint-changed", -1},
+    {DFWAPI_ASYNC_CLASS_EVENTPOINT_DELETED, "eventpoint-deleted", -1},
+    {DFWAPI_ASYNC_CLASS_LAST, "unknown", -1}
+  };
+
+static const struct enum_desc dfwapi_context_type_desc[] =
+{
+  {DFWAPI_CONTEXT_KERNEL_TASK, "KernelTask"},
+  {DFWAPI_CONTEXT_RTP, "RTP"},
+  {DFWAPI_CONTEXT_RTP_TASK, "Task"},
+  {DFWAPI_CONTEXT_LAST, "Unknown"}
+};
+
+
+/* Description of DFW task status.  */
+static const struct enum_desc dfwapi_task_status_desc[] =
+{
+  {DFWAPI_TASK_STATUS_STATELESS, "stateless"},
+  {DFWAPI_TASK_STATUS_STOPPED, "Stop"},
+  {DFWAPI_TASK_STATUS_STOPPED_T, "Stop+T"},
+  {DFWAPI_TASK_STATUS_STOPPED_P, "Stop+P"},
+  {DFWAPI_TASK_STATUS_STOPPED_S, "Stop+S"},
+  {DFWAPI_TASK_STATUS_STOPPED_P_S, "Stop+P+S"},
+  {DFWAPI_TASK_STATUS_STOPPED_T_S, "Stop+T+S"},
+  {DFWAPI_TASK_STATUS_STOPPED_P_T, "Stop+P+T"},
+  {DFWAPI_TASK_STATUS_STOP_P_T_S, "Stop+P+T+S"},
+  {DFWAPI_TASK_STATUS_ST_P_T_S, "St+P+T+S"},
+  {DFWAPI_TASK_STATUS_SUSPEND, "Suspend"},
+  {DFWAPI_TASK_STATUS_DELAY, "Delay"},
+  {DFWAPI_TASK_STATUS_PENDING, "Pend"},
+  {DFWAPI_TASK_STATUS_PEND_S, "Pend+S"},
+  {DFWAPI_TASK_STATUS_PEND_T, "Pend+T"},
+  {DFWAPI_TASK_STATUS_PEND_S_T, "Pend+S+T"},
+  {DFWAPI_TASK_STATUS_READY, "Ready"},
+  {DFWAPI_TASK_STATUS_DEAD, "Dead"},
+  {DFWAPI_TASK_STATUS_RTP_NORMAL, "RTP_NORMAL"},
+  {DFWAPI_TASK_STATUS_LAST, "Unknown"}
+};
+
+/* Dynamically extensible string buffer type.  */
+
+struct string_buffer
+{
+  char *beginning_of_buffer;
+
+  /* Buffer address.  The buffer is reallocated if needed.  */
+
+  int size;
+
+  /* Size of the buffer, in number of characters.  */
+
+  index_type current_index;
+
+  /* Index of the next free slot in the buffer.  */
+
+};
+
+/* Dynamically extensible integer table, used to store dfw sem or lex
+   trees.  */
+
+struct dfw_tree_type
+{
+  dfw_tree_element *beginning_of_table;
+
+  /* Table address.  The table is represented by a tree element array that
+   we reallocate when needed.  */
+
+  int size;
+
+  /* Size of the table, in number of dfw_tree_elements.  */
+
+  index_type table_end;
+
+  /* Index of the next free slot in the table.  */
+
+};
+
+/* Result table type; used to store lexical and semantical analysis of
+   an result (asynchronous or synchronous).  See an example of its use
+   in the general description.  */
+
+struct result_table
+{
+  /* String buffer.  Used to store the strings (e.g. variable names,
+     constant values) of the request.  */
+
+  struct string_buffer string_table;
+
+  /* Lex tree of the DFW request result.  */
+
+  struct dfw_tree_type dfw_lex_tree;
+
+  /* Sem tree of the DFW request result.  */
+
+  struct dfw_tree_type dfw_sem_tree;
+};
+
+/* Semantic element extracted from the stack.  It should be easier to
+   manipulate when trying to get the result of a DFW request.  It contains
+   a tree element code and its parameter (if any).  For example, the following
+   elements of the sem table:
+
+   DFW_SEM_CONST
+   defaultTarget
+
+   would correspond to a semantic element SE, with:
+   SE.type == DFW_SEM_CONST
+   strcmp (SE.value.string_value, "defaultTarget") == 0
+*/
+
+struct dfw_sem_element
+{
+  enum dfw_sem_type type;
+  union value_union
+  {
+    enum result_class_type result_class_value;
+    enum dfwapi_async_class_type dfwapi_async_class_value;
+    char *string_value;
+  } value;
+  index_type sibling;
+};
+
+/* Module mapping.  */
+
+struct dfw_module_mapping
+{
+  struct dfw_module_mapping *next;
+
+  /* Target name.  */
+
+  char *target_path;
+
+  /* Target path length.  */
+
+  int target_path_len;
+
+  /* Host name.  */
+
+  char *host_path;
+
+  /* Host name length.  */
+
+  int host_path_len;
+};
+
+/* DFW breakpoints list.  */
+
+struct dfw_breakpoint
+{
+  struct dfw_breakpoint *next;
+
+  /* DFW id for this breakpoint.  */
+
+  int bp_number;
+
+  /* Address of the breakpoint.  */
+
+  CORE_ADDR address;
+};
+
+static struct dfw_breakpoint *dfw_breakpoint_list;
+
+/* Initial size of a string buffer.  */
+const static int STRING_BUFFER_INITIAL_SIZE = 1024;
+
+/* Size of the increment of a string buffer when more storage is needed.  */
+
+const static int STRING_BUFFER_INCREMENT = 1024;
+
+/* Ditto for dfw trees.  */
+
+const static int DFW_TREE_INITIAL_SIZE = 1024;
+const static int DFW_TREE_INCREMENT = 1024;
+
+/* Result table for the last synchronous request output.  */
+
+static struct result_table current_result_record;
+static struct result_table current_async_record;
+
+/* Descriptor for I/O to dfwserver.  Initialize it to NULL so that
+   remote_dfw_open knows that we don't have a file open when the program
+   starts.  */
+static struct serial *remote_dfw_desc = NULL;
+
+/* Maintenance stuff.  */
+
+static int dfw_show_requests = 0;
+static int dfw_show_responses = 0;
+static int dfw_warn_unknown_identifiers = 0;
+
+/* Current request token.  */
+typedef unsigned char token_type;
+static token_type current_token = 1;
+
+/* Full vxworks task list on target.  */
+
+struct dfwapi_task *dfwapi_task_list = NULL;
+
+/* Module map.  */
+
+static struct dfw_module_mapping *dfw_module_map = NULL;
+
+/* Connection handling.  */
+
+static int readchar (int timeout);
+static void write_string (const char *buf, int cnt);
+static void write_int (int i);
+static token_type write_token ();
+
+static void wrs_info_retrieve (const char *tree_branch,
+			       const int tree_branch_len,
+			       const char *tree_leaf,
+			       const int tree_leaf_len,
+			       const char *pattern);
+static void wrs_info_retrieve_1 (const char *tree_branch,
+				 const char *tree_leaf,
+				 const char *pattern,
+				 int timeout);
+
+static void skip_line ();
+static void skip_prompt ();
+static char * add_curly_braquets (char *s);
+
+
+/* Output record lexical parsing.  */
+
+static int read_class (int timeout, struct string_buffer *table);
+static int wait_output_record_sequence (int timeout, token_type *token);
+static void read_output_record_sequence (int timeout,
+					 token_type expected_token);
+static void read_result_record (int timeout);
+static void read_async_output (int timeout);
+static void read_target_stream (int timeout);
+static void read_log_stream (int timeout);
+
+/* Test of lex tree elements, used for the sem analysis.  */
+
+static int test_lex (struct result_table *table, index_type current_index,
+		     enum dfw_lex_type lex);
+static int test_const (struct result_table *table, index_type current_index);
+static int test_tuple (struct result_table *table, index_type current_index);
+static int test_list (struct result_table *table, index_type current_index);
+static int test_result (struct result_table *table, index_type current_index);
+static int test_value (struct result_table *table, index_type current_index);
+static int check_lex (struct result_table *table, index_type *current_index,
+		      enum dfw_lex_type lex);
+
+/* Sem analysis of the result sequence.  */
+
+static void read_result_list (struct result_table *table);
+static void read_result (struct result_table *table,
+			 index_type *current_index);
+static void read_variable (struct result_table *table,
+			   index_type *current_index);
+static void read_value (struct result_table *table, index_type *current_index);
+static void read_const (struct result_table *table, index_type *current_index);
+static void read_tuple (struct result_table *table, index_type *current_index);
+static void read_list (struct result_table *table, index_type *current_index);
+
+/* String buffer support.  */
+
+static int string_buffer_allocate (struct string_buffer *buff);
+static int string_buffer_push_char (struct string_buffer *buff, char c);
+static char * string_buffer_get_string_address (struct string_buffer *buff,
+						index_type index);
+static int string_buffer_reset (struct string_buffer * buff);
+static index_type string_buffer_get_index (struct string_buffer * buff);
+
+/* DFW tree table handling.  */
+
+static int dfw_tree_allocate (struct dfw_tree_type *table);
+static index_type dfw_tree_push (struct dfw_tree_type *table,
+			       dfw_tree_element tree);
+static int dfw_tree_reset (struct dfw_tree_type *table);
+static dfw_tree_element lookup_dfw_tree_element
+(const struct dfw_tree_element_desc *desc, char *name, int last);
+static int lookup_enum_code (const struct enum_desc *desc, char *name,
+			     int last);
+
+/* Routines to go through the tree sem table and get sem elements from
+ the indices in the sem tree table.  */
+
+static struct dfw_sem_element next_sem_element (struct result_table *result,
+						index_type *current_index);
+
+static struct dfw_sem_element next_sem_element_with_check
+(struct result_table *result, index_type *current_index,
+ const char *request_desc, enum dfw_sem_type type);
+
+static struct dfw_sem_element sem_element_process_result_header
+(struct result_table *result, index_type *current_index,
+ const char *request_desc);
+
+static struct dfw_sem_element sem_element_process_wrs_info_header
+(struct result_table *result, index_type *current_index,
+ const char *request_desc);
+
+static struct dfw_sem_element sem_element_process_list_value_header
+(struct result_table *result, index_type *current_index,
+ const char *request_desc);
+
+static struct dfw_sem_element sem_element_process_const_string_value
+(struct result_table *result, index_type *current_index,
+ const char *request_desc, char **string_value);
+
+static struct dfw_sem_element sem_element_process_const_integer_value
+(struct result_table *result, index_type *current_index,
+ const char *request_desc, int *const_value);
+
+static struct dfw_sem_element sem_element_process_const_core_addr_value
+(struct result_table *result, index_type *current_index,
+ const char *request_desc, CORE_ADDR *const_value);
+
+/* Result table handling.  */
+
+static int result_table_allocate (struct result_table *table);
+
+/* Debug.  */
+
+static int print_result_record (struct result_table *result);
+static void info_dfw_trees ();
+
+/* Target connection and initialization.  */
+
+static void dfwapi_wrs_target_connect ();
+static int get_current_connection_info (char *main_info_directory,
+					char *system_thread_id_leaf,
+					char *thread_id_leaf,
+					char **error_msg);
+static int get_current_connection (char **error_msg);
+
+/* VxWorks tasks handling.  */
+
+static struct dfwapi_task * dfwapi_task_build (enum dfwapi_context_type type,
+						 int rtp_dfw_id,
+                                                 CORE_ADDR pid,
+						 int dfw_id,
+                                                 CORE_ADDR thread_id,
+						 int parent_dfw_id);
+static void add_vxworks_task (struct dfwapi_task *task);
+
+static void invalidate_dfwapi_task_list ();
+static void prune_dfwapi_task_list ();
+static int dfwapi_thread_select (int dfw_id);
+
+/* Allocate and initialize a string buffer BUFF of
+   STRING_BUFFER_INITIAL_SIZE bytes.  */
+
+static int
+string_buffer_allocate (struct string_buffer *buff)
+{
+  buff->beginning_of_buffer =
+    (char *) (xmalloc (STRING_BUFFER_INITIAL_SIZE * sizeof (char)));
+  if (buff->beginning_of_buffer == NULL)
+    return 0;
+  buff->current_index = 0;
+  buff->size = STRING_BUFFER_INITIAL_SIZE;
+  return 1;
+}
+
+/* Push C into the string buffer.  Return the next index in BUFF.  */
+
+static int
+string_buffer_push_char (struct string_buffer *buff, char c)
+{
+  int char_index = buff->current_index;
+  *(buff->beginning_of_buffer + buff->current_index) = c;
+  buff->current_index++;
+  gdb_assert (buff->current_index != 0);
+  if (buff->current_index > buff->size - 1)
+    {
+      buff->size = buff->size + STRING_BUFFER_INCREMENT;
+      buff->beginning_of_buffer = xrealloc ((void *) buff->beginning_of_buffer,
+					    buff->size * sizeof (char));
+    }
+  return char_index;
+}
+
+/* Return a pointer to the string starting at INDEX in BUFF.  */
+
+static char *
+string_buffer_get_string_address (struct string_buffer *buff, index_type index)
+{
+  return buff->beginning_of_buffer + index;
+}
+
+/* Reset the string buffer.  All strings previously stored in the buffer are
+   lost so that their memory space can be reused.  */
+
+static int
+string_buffer_reset (struct string_buffer * buff)
+{
+  buff->current_index = 0;
+  memset (buff->beginning_of_buffer, 0, buff->size);
+  return 1;
+}
+
+/* Get current index of BUFF.  */
+
+static index_type
+string_buffer_get_index (struct string_buffer * buff)
+{
+  return buff->current_index;
+}
+
+/* Allocate and initialize a table TABLE of DFW_TREE_INITIAL_SIZE bytes.  */
+
+static int
+dfw_tree_allocate (struct dfw_tree_type *table)
+{
+  table->beginning_of_table =
+    (dfw_tree_element *) (xmalloc (DFW_TREE_INITIAL_SIZE
+				    * sizeof (dfw_tree_element)));
+  if (table->beginning_of_table == NULL)
+    return 0;
+  table->table_end = 0;
+  table->size = DFW_TREE_INITIAL_SIZE;
+  return 1;
+}
+
+/* Reset the table.  All elements previously stored in the buffer are
+   lost so that their memory space can be reused.  */
+
+static int
+dfw_tree_reset (struct dfw_tree_type *table)
+{
+  table->table_end = 0;
+  memset (table->beginning_of_table, 0, table->size);
+  return 1;
+}
+
+/* Push TREE into the dfw tree table TABLE.  Return the next index in the
+   table.  */
+
+static index_type
+dfw_tree_push (struct dfw_tree_type *table, dfw_tree_element tree)
+{
+  index_type table_end = table->table_end;
+  *(table->beginning_of_table + table->table_end) = tree;
+  table->table_end ++;
+  if (table->table_end > table->size - 1)
+    {
+      table->size = table->size + DFW_TREE_INCREMENT;
+      table->beginning_of_table =
+	xrealloc ((void *) table->beginning_of_table,
+		  table->size * sizeof (dfw_tree_element));
+    }
+  return table_end;
+}
+
+/* Set TREE into the dfw tree table TABLE, at the index INDEX.  */
+
+static void
+dfw_tree_set (struct dfw_tree_type *table, int index, dfw_tree_element tree)
+{
+  gdb_assert (table);
+  gdb_assert (index < table->table_end);
+  *(table->beginning_of_table + index) = tree;
+}
+
+/* Lookup NAME in DESC, and return its code.  */
+
+static dfw_tree_element
+lookup_dfw_tree_element (const struct dfw_tree_element_desc *desc, char *name,
+			 int last)
+{
+  dfw_tree_element result = last;
+  int i;
+
+  for (i = 0; i < last; i++)
+    {
+      if (strcmp (name, desc[i].name) == 0)
+	{
+	  result = desc[i].code;
+	}
+    }
+  if (result == last && dfw_warn_unknown_identifiers)
+    warning ("DFW: \"%s\" identifier is unknown", name);
+
+  return result;
+}
+
+/* Lookup NAME in DESC, and return its code.  */
+
+static int
+lookup_enum_code (const struct enum_desc *desc, char *name, int last)
+{
+  int result = last;
+  int i;
+
+  for (i = 0; i < last; i++)
+    {
+      if (strcmp (name, desc[i].name) == 0)
+	{
+	  result = desc[i].code;
+	}
+    }
+  if (result == last && dfw_warn_unknown_identifiers)
+    warning ("DFW: \"%s\" identifier is unknown", name);
+
+  return result;
+}
+
+/* Dump the content of RESULT on the standard output.  */
+
+static int
+print_result_record (struct result_table *result)
+{
+  index_type current_index;
+  enum dfw_lex_type lex;
+  enum dfw_sem_type sem;
+  dfw_tree_element item;
+  struct dfw_tree_type *lex_table = &(result->dfw_lex_tree);
+  struct dfw_tree_type *sem_table = &(result->dfw_sem_tree);
+
+  fprintf_unfiltered (gdb_stderr, "\n*** LEX ***\n\n");
+
+  for (current_index = 0;
+       current_index < lex_table->table_end;
+       current_index++)
+    {
+      lex = lex_table->beginning_of_table[current_index];
+      fprintf_unfiltered (gdb_stderr, "%s\n", dfw_lex_list [lex].name);
+      switch (lex)
+	{
+	case DFW_LEX_COMMA:
+	case DFW_LEX_EQUALS:
+	case DFW_LEX_BEGIN_TUPLE:
+	case DFW_LEX_END_TUPLE:
+	case DFW_LEX_BEGIN_LIST:
+	case DFW_LEX_END_LIST:
+	case DFW_LEX_LAST:
+	  /* No parameter, so nothing else to do.  */
+	  break;
+	case DFW_LEX_CSTRING:
+	case DFW_LEX_ITEM:
+	  /* String parameter.  */
+	  current_index++;
+	  item = lex_table->beginning_of_table[current_index];
+	  fprintf_unfiltered (gdb_stderr, "%s\n",
+			      string_buffer_get_string_address (&(result->string_table), item));
+	  break;
+	default:
+	  error ("Displaying of lex %d is not implemented", lex);
+	  break;
+	}
+    }
+
+  fprintf_unfiltered (gdb_stderr, "\n*** SEM ***\n\n");
+
+  for (current_index = 0;
+       current_index < sem_table->table_end;
+       current_index++)
+    {
+      sem = sem_table->beginning_of_table[current_index];
+      fprintf_unfiltered (gdb_stderr, "%d %s ", current_index,
+			  dfw_sem_list [sem].name);
+      switch (sem)
+	{
+	case DFW_SEM_VALUE:
+	case DFW_SEM_RESULT:
+	case DFW_SEM_BEGIN_TUPLE:
+	case DFW_SEM_END_TUPLE:
+	case DFW_SEM_BEGIN_LIST:
+	case DFW_SEM_END_LIST:
+	case DFW_SEM_LAST:
+	  /* No parameter, so nothing else to do.  */
+	  break;
+
+	case DFW_SEM_VARIABLE:
+	case DFW_SEM_CONST:
+	  /* String parameter.  */
+	  current_index++;
+	  item = sem_table->beginning_of_table[current_index];
+	  fprintf_unfiltered
+	    (gdb_stderr, "%s ",
+	     string_buffer_get_string_address (&(result->string_table), item));
+	  break;
+
+	case DFW_SEM_RESULT_CLASS:
+	case DFW_SEM_ASYNC_CLASS:
+	  current_index++;
+	  item = sem_table->beginning_of_table[current_index];
+	  fprintf_unfiltered (gdb_stderr, "%s ",
+			      dfwapi_async_class_list[item].name);
+	  break;
+
+	default:
+	  error ("Displaying of sem %d is not implemented", sem);
+	  break;
+
+	}
+      current_index++;
+      item = sem_table->beginning_of_table[current_index];
+      fprintf_unfiltered (gdb_stderr, "(sibling = %d)\n", item);
+    }
+
+
+  fprintf_unfiltered (gdb_stderr, "\n");
+
+  return 1;
+}
+
+/* Get the semantic element located at CURRENT_INDEX in RESULT.  If
+   this element has a parameter, it is also read and stored into the
+   corresponding value field of the returned value.  Finally,
+   CURRENT_INDEX is updated to point to the next semantic element in
+   RESULT.  */
+
+static struct dfw_sem_element
+next_sem_element (struct result_table *result, index_type *current_index)
+{
+  enum dfw_sem_type sem;
+  dfw_tree_element item;
+  struct dfw_tree_type *sem_table = &(result->dfw_sem_tree);
+  struct dfw_sem_element element;
+
+  memset (&element, 0, sizeof (element));
+
+  sem = sem_table->beginning_of_table[*current_index];
+  element.type = sem;
+
+  switch (sem)
+    {
+    case DFW_SEM_VALUE:
+    case DFW_SEM_RESULT:
+    case DFW_SEM_BEGIN_TUPLE:
+    case DFW_SEM_END_TUPLE:
+    case DFW_SEM_BEGIN_LIST:
+    case DFW_SEM_END_LIST:
+    case DFW_SEM_LAST:
+      /* No parameter, so nothing else to do.  */
+      break;
+
+    case DFW_SEM_VARIABLE:
+    case DFW_SEM_CONST:
+      /* String parameter.  */
+      (*current_index)++;
+      item = sem_table->beginning_of_table[*current_index];
+      element.value.string_value =
+	string_buffer_get_string_address (&(result->string_table), item);
+      break;
+
+    case DFW_SEM_RESULT_CLASS:
+      (*current_index)++;
+      item = sem_table->beginning_of_table[*current_index];
+      element.value.dfwapi_async_class_value = item;
+      break;
+    case DFW_SEM_ASYNC_CLASS:
+      (*current_index)++;
+      item = sem_table->beginning_of_table[*current_index];
+      element.value.result_class_value = item;
+      break;
+    default:
+      error ("sem %d is not understood", sem);
+      break;
+    }
+
+  /* Sibling.  */
+  (*current_index)++;
+  element.sibling = sem_table->beginning_of_table[*current_index];
+
+  (*current_index)++;
+  return element;
+}
+
+/* Same as next_sem_element, but if the semantic element pointed by
+   CURRENT_INDEX is not of type TYPE, an error is raised.  */
+
+static struct dfw_sem_element
+next_sem_element_with_check  (struct result_table *result,
+			      index_type *current_index,
+			      const char *request_desc,
+			      enum dfw_sem_type type)
+{
+  struct dfw_sem_element element = next_sem_element (result, current_index);
+
+  if (element.type != type)
+    error ("DFW: parse error in %s; waiting %s, got %s",
+	   request_desc,
+	   dfw_sem_list [type].name,
+	   dfw_sem_list [element.type].name);
+
+  return element;
+}
+
+static int
+test_next_sem_element  (struct result_table *result,
+			index_type current_index,
+			enum dfw_sem_type type)
+{
+  index_type tmp_index = current_index;
+  struct dfw_sem_element element = next_sem_element (result, &tmp_index);
+  return element.type == type;
+}
+
+/* Read the result header semantic info of the result record stored in
+   RESULT, at index CURRENT_INDEX, that is to say the result class and
+   the first variable name in the output record.  CURRENT_INDEX is
+   updated to point to the next semantic element,
+
+   If, at this location, the header is not found or if result class is
+   not "done", an error is raised.
+
+   Example: if RESULT, at CURRENT_INDEX, contains the following semantic
+   information:
+
+   DFW_SEM_RESULT_CLASS
+   done
+   DFW_SEM_VARIABLE
+   i
+   DFW_SEM_VALUE
+   [...]
+
+   This function would return a dfw_sem_element containing {DFW_SEM_VARIANLE,
+   "i"} and current_index would then point to the DFW_SEM_VALUE item.  */
+
+static struct dfw_sem_element
+sem_element_process_result_header (struct result_table *result,
+				   index_type *current_index,
+				   const char *request_desc)
+{
+  struct dfw_sem_element element = next_sem_element (result, current_index);
+  if (element.type != DFW_SEM_RESULT_CLASS
+      || element.value.result_class_value == RESULT_CLASS_ERROR)
+    error ("DFW: error in %s.", request_desc);
+
+  if (*current_index < current_result_record.dfw_sem_tree.table_end)
+    element = next_sem_element_with_check (result, current_index, request_desc,
+					   DFW_SEM_VARIABLE);
+
+  return element;
+}
+
+static struct dfw_sem_element
+sem_element_process_wrs_info_header (struct result_table *result,
+				     index_type *current_index,
+				     const char *request_desc)
+{
+  sem_element_process_result_header (result, current_index, request_desc);
+  return sem_element_process_list_value_header (result, current_index,
+						request_desc);
+}
+
+/* Read a list value and points to the beginning of it.  id est, it
+   reads:
+
+   DFW_SEM_VALUE
+   DFW_SEM_BEGIN_LIST
+   DFW_SEM_VARIABLE
+
+   and return the DFW_SEM_VARIABLE read.
+*/
+
+static struct dfw_sem_element
+sem_element_process_list_value_header (struct result_table *result,
+				       index_type *current_index,
+				       const char *request_desc)
+{
+  struct dfw_sem_element element;
+  
+  element = next_sem_element_with_check (result, current_index, request_desc,
+					 DFW_SEM_VALUE);
+  element = next_sem_element_with_check (result, current_index, request_desc,
+					 DFW_SEM_BEGIN_LIST);
+  element = next_sem_element_with_check (result, current_index, request_desc,
+					 DFW_SEM_VARIABLE);
+  return element;
+}
+
+
+
+
+/* Read the semantic info pointed by CURRENT_INDEX into the RESULT table,
+   assuming that it is a pair (value, const).  exempli gratia:
+
+   DFW_SEM_VALUE
+   DFW_SEM_CONST
+   "my_const_value"
+
+   If this assumption is not correct, an error is raised.  At the contrary,
+   if it is true:
+   * CURRENT_INDEX is updated to point to the element following this pair
+   in the RESULT table;
+   * string_value is set to the string value of the DFW_SEM_CONST element;
+   * the function returns a dfw_sem_element containing the DFW_SEM_CONST
+   and its string parameter.  */
+
+static struct dfw_sem_element
+sem_element_process_const_string_value (struct result_table *result,
+					index_type *current_index,
+					const char *request_desc,
+					char **string_value)
+{
+  struct dfw_sem_element element =
+    next_sem_element_with_check (result, current_index, request_desc,
+				 DFW_SEM_VALUE);
+
+  element = next_sem_element_with_check (result, current_index, request_desc,
+					 DFW_SEM_CONST);
+
+  *string_value = element.value.string_value;
+  return element;
+}
+
+/* Same thing as sem_element_process_const_string_value, for an integer
+   value instead of a string value.  This integer value is stored into
+   CONST_VALUE.  */
+
+
+static struct dfw_sem_element
+sem_element_process_const_integer_value (struct result_table *result,
+					 index_type *current_index,
+					 const char *request_desc,
+					 int *const_value)
+{
+  char *string_value;
+  struct dfw_sem_element element =
+    sem_element_process_const_string_value (result, current_index,
+					    request_desc,
+					    &string_value);
+  *const_value = atoi (string_value);
+  return element;
+}
+
+/* Same thing as sem_element_process_const_integer_value, for a CORE_ADDR
+   value in hexademal format (e.g. "0xDEADBEEF").  */
+
+static struct dfw_sem_element
+sem_element_process_const_core_addr_value (struct result_table *result,
+					   index_type *current_index,
+					   const char *request_desc,
+					   CORE_ADDR *const_value)
+{
+  char *string_value;
+  char *cptr = 0;
+  struct dfw_sem_element element =
+    sem_element_process_const_string_value (result, current_index,
+					    request_desc,
+					    &string_value);
+  *const_value = (CORE_ADDR) strtoul (string_value, &cptr, 0);
+
+  if ((cptr == string_value) || (*cptr != '\0'))
+    error ("Invalid address value in %s", request_desc);
+  return element;
+}
+
+/* Allocate TABLE.  */
+
+static int
+result_table_allocate (struct result_table *table)
+{
+  return (string_buffer_allocate (&table->string_table))
+    && dfw_tree_allocate (&table->dfw_lex_tree)
+    && dfw_tree_allocate (&table->dfw_sem_tree);
+}
+
+/* Reset TABLE.  */
+
+static int
+result_table_reset (struct result_table *table)
+{
+  return (string_buffer_reset (&table->string_table)
+    && dfw_tree_reset (&table->dfw_lex_tree)
+    && dfw_tree_reset (&table->dfw_sem_tree));
+}
+
+/* Parse the service key returned by the wtx_info_q_get request, and
+   extract from it the connection parameters of the corresponding service.
+   which are:
+   * HOST_NAME_LOC: pointer to the location of the host name in KEY;
+   * HOST_NAME_LEN: length of the host name;
+   * PORT_LOC: pointer to the location of the TCP port in KEY;
+   * PORT_LEN: length of the TCP port.  */
+
+static void
+parse_service_key (char *key, char **host_name_loc,
+		   int *host_name_len, char **port_loc, int *port_len)
+{
+  char *beginning_token, *end_token;
+  char host_name_flag[] = "host;";
+  int  host_name_flag_len = strlen (host_name_flag);
+  char port_flag[] = "dfwserver.miport;";
+  int  port_flag_len = strlen (port_flag);
+
+  for (beginning_token = key, end_token = strchr (key, ';');
+       end_token != NULL;
+       beginning_token = end_token + 1,
+	 end_token = strchr (beginning_token, ';'))
+    {
+      if (strncmp (beginning_token, host_name_flag, host_name_flag_len) == 0)
+	{
+	  beginning_token = end_token + 1;
+	  end_token = strchr (beginning_token, ';');
+	  *host_name_loc = beginning_token;
+	  if (end_token)
+	    {
+	      *host_name_len = strlen (beginning_token) - strlen (end_token);
+	    }
+	  else
+	    {
+	      *host_name_len = strlen (beginning_token);
+	      break;
+	    }
+	}
+      else if (strncmp (beginning_token, port_flag, strlen (port_flag)) == 0)
+	{
+	  beginning_token = end_token + 1;
+	  end_token = strchr (beginning_token, ';');
+	  *port_loc = beginning_token;
+	  if (end_token)
+	    {
+	      *port_len = strlen (beginning_token) - strlen (end_token);
+	    }
+	  else
+	    {
+	      *port_len = strlen (beginning_token);
+	      break;
+	    }
+	}
+    }
+}
+
+/* Read a single character from the dfw end and return it.  */
+
+static int
+readchar (int timeout)
+{
+  int ch;
+
+  ch = serial_readchar (remote_dfw_desc, timeout);
+
+  if (dfw_show_responses)
+    printf_unfiltered ("%c", ch);
+
+  if (ch >= 0)
+    return (ch & 0x7f);
+
+  switch ((enum serial_rc) ch)
+    {
+    case SERIAL_EOF:
+      error ("DFW connection closed");
+      /* no return */
+    case SERIAL_ERROR:
+      perror_with_name ("DFW communication error");
+      /* no return */
+    case SERIAL_TIMEOUT:
+      error ("DFW connection timeout");
+    }
+
+  return ch;
+}
+
+/* Read an DFW output sequence from the connection output.  The syntax rules
+   used are:
+
+   output ==>
+     ( out-of-band-record )* [ result-record ] "(gdb)" nl
+
+   result-record ==>
+     [ token ] "^" result-class ( "," result )* nl
+
+   out-of-band-record ==>
+     async-record | stream-record
+
+   async-record ==>
+     exec-async-output | status-async-output | notify-async-output
+
+   exec-async-output ==>
+     [ token ] "*" async-output
+
+   status-async-output ==>
+     [ token ] "+" async-output
+
+   notify-async-output ==>
+     [ token ] "=" async-output
+
+*/
+
+static void
+read_output_record_sequence (int timeout, token_type expected_token)
+{
+  int output_type = '\0';
+  token_type output_token = 0;
+
+  while (1)
+    {
+      output_type = wait_output_record_sequence (timeout, &output_token);
+  
+      if (output_type == '^'
+	  && (!expected_token || expected_token == output_token))
+	return ;
+    }
+}
+
+/* Read either a result record, or an async record.  Return the caracter
+   which identifies the output types.  */
+
+static int
+wait_output_record_sequence (int timeout, token_type *token)
+{
+  int output_type = '\0';
+
+  *token = 0;
+  while (1)
+    {
+      output_type = readchar (timeout);
+      switch (output_type)
+	{
+	case '(':
+	  /* Prompt */
+	  skip_line ();
+	  goto end_of_read;
+	case '0':
+	case '1':
+	case '2':
+	case '3':
+	case '4':
+	case '5':
+	case '6':
+	case '7':
+	case '8':
+	case '9':
+	  *token *= 10;
+	  *token += output_type - '0';
+	  break;
+	case '=':
+	case '*':
+	case '+':
+	  read_async_output (timeout);
+	  goto end_of_read;
+	case '^':
+	  read_result_record (timeout);
+	  goto end_of_read;
+	case '@':
+	  read_target_stream (timeout);
+	  goto end_of_read;
+	case '&':
+	  read_log_stream (timeout);
+	  goto end_of_read;
+	default:
+	  goto end_of_read;
+	}
+    }
+
+ end_of_read:
+  return output_type;
+}
+
+/* Read a class (result or async) from the DFW connection and
+   buffer it into TABLE.  Return the last character read.  */
+static int
+read_class (int timeout, struct string_buffer *table)
+{
+  int current = '\0';
+
+  while (current != '\n' && current != ',')
+    {
+      current = readchar (timeout);
+      if (current == '\n' || current == ',')
+	{
+	  string_buffer_push_char (table, '\0');
+	}
+      else
+	{
+	  string_buffer_push_char (table, (char) current);
+	}
+    }
+  return current;
+}
+
+/* Read an async output from the DFW connection output.  Syntax rule used:
+
+   async-output ==>
+     async-class ( "," result )* nl
+
+*/
+
+static void
+read_async_output (int timeout)
+{
+  /* Not needed; ignore.  */
+  skip_line ();
+}
+
+/* Read a result record from the DFW connection output.  Syntax rule used:
+
+   result-record ==>
+     [ token ] "^" result-class ( "," result )* nl
+
+*/
+
+static void
+read_result_record (int timeout)
+{
+  int current = '^';
+  dfw_tree_element request_result = RESULT_CLASS_LAST;
+  index_type current_index;
+  char *buf;
+  index_type sibling_index_location, sibling_index;
+
+  result_table_reset (&current_result_record);
+  current_index =
+    string_buffer_get_index (&(current_result_record.string_table));
+
+  /* Bufferise result class.  */
+  current = read_class (timeout, &(current_result_record.string_table));
+  buf =
+    string_buffer_get_string_address (&(current_result_record.string_table),
+				      current_index);
+
+  request_result = lookup_dfw_tree_element (result_class_list, buf,
+					    RESULT_CLASS_LAST);
+  dfw_tree_push (&(current_result_record.dfw_sem_tree),
+		 (dfw_tree_element) DFW_SEM_RESULT_CLASS);
+  dfw_tree_push (&(current_result_record.dfw_sem_tree),
+		 (dfw_tree_element) request_result);
+  sibling_index_location =
+    dfw_tree_push (&(current_result_record.dfw_sem_tree), 0);
+
+  if (current != '\n')
+    read_result_list (&current_result_record);
+
+  sibling_index = current_result_record.dfw_sem_tree.table_end;
+  dfw_tree_set (&(current_result_record.dfw_sem_tree),
+		sibling_index_location,
+		sibling_index);
+}
+
+/* Read the list of result (in a result record) from the DFW connection
+   output and buffer the result of the lexical and semantical analysis in
+   TABLE.  */
+
+static void
+read_result_list (struct result_table *table)
+{
+  int current = '^';
+  char char_to_push;
+  enum dfw_lex_type lex_to_push = DFW_LEX_LAST;
+  int pushing_item = 0;
+  int end_item_reached = 0;
+  index_type string_index, current_index;
+
+  /* Buffer result items into the lex string buffer.  When there is no
+     ambiguity, we resolve it; when there is, we just store a
+     dfw_lex_item ; we will resolve it later, during semantical analysis.  */
+  string_index =
+    string_buffer_get_index (&(table->string_table));
+
+  while (current != '\n')
+    {
+      current = readchar (dfw_timeout);
+      switch (current)
+	{
+	case '{':
+	  lex_to_push = DFW_LEX_BEGIN_TUPLE;
+	  end_item_reached = 1;
+	  break;
+	case '}':
+	  lex_to_push = DFW_LEX_END_TUPLE;
+	  end_item_reached = 1;
+	  break;
+	case '[':
+	  lex_to_push = DFW_LEX_BEGIN_LIST;
+	  end_item_reached = 1;
+	  break;
+	case ']':
+	  lex_to_push = DFW_LEX_END_LIST;
+	  end_item_reached = 1;
+	  break;
+	case '"':
+	  /* C string.  We push the item on the lex table (if any) and we
+	     buffer everything until we see another quote character.  */
+	  if (pushing_item)
+	    {
+	      string_buffer_push_char (&(table->string_table),
+				       (char) '\0');
+	      dfw_tree_push (&(table->dfw_lex_tree),
+			     (dfw_tree_element) DFW_LEX_ITEM);
+	      dfw_tree_push (&(table->dfw_lex_tree),
+			     (dfw_tree_element) string_index);
+	      string_index =
+		string_buffer_get_index (&(table->string_table));
+	      pushing_item = 0;
+	      end_item_reached = 0;
+	    }
+
+	  current = '\0';
+	  while (current != '"')
+	    {
+	      current = readchar (dfw_timeout);
+
+	      if (current != '"')
+		string_buffer_push_char (&(table->string_table),
+					 (char) current);
+	      if (current == '\\')
+	      {
+		current = readchar (dfw_timeout);
+		string_buffer_push_char (&(table->string_table),
+					 (char) current);
+	      }
+	    }
+
+	  string_buffer_push_char (&(table->string_table),
+				   (char) '\0');
+	  dfw_tree_push (&(table->dfw_lex_tree),
+			 (dfw_tree_element) DFW_LEX_CSTRING);
+	  dfw_tree_push (&(table->dfw_lex_tree),
+			 (dfw_tree_element) string_index);
+	  string_index =
+	    string_buffer_get_index (&(table->string_table));
+
+	  /* No lex left to push.  */
+	  lex_to_push = DFW_LEX_LAST;
+	  break;
+	case ',':
+	  lex_to_push = DFW_LEX_COMMA;
+	  end_item_reached = 1;
+	  break;
+	case '=':
+	  lex_to_push = DFW_LEX_EQUALS;
+	  end_item_reached = 1;
+	  break;
+	case '\\':
+	  string_buffer_push_char (&(table->string_table),
+				   (char) current);
+	  current = readchar (dfw_timeout);
+	  char_to_push = current;
+	case '\n':
+	  break;
+	default:
+	  pushing_item = 1;
+	  char_to_push = current;
+	  string_buffer_push_char (&(table->string_table),
+				   (char) current);
+	  break;
+	}
+
+      if (pushing_item && end_item_reached)
+	{
+	  string_buffer_push_char (&(table->string_table),
+				   (char) '\0');
+	  dfw_tree_push (&(table->dfw_lex_tree),
+			 (dfw_tree_element) DFW_LEX_ITEM);
+	  dfw_tree_push (&(table->dfw_lex_tree),
+			 (dfw_tree_element) string_index);
+	  string_index =
+	    string_buffer_get_index (&(table->string_table));
+	  pushing_item = 0;
+	}
+      if (end_item_reached)
+	{
+	  dfw_tree_push (&(table->dfw_lex_tree),
+			 (dfw_tree_element) lex_to_push);
+	  end_item_reached = 0;
+	}
+    }
+
+  /* Now, go through the buffered lex and populate the sem table.  */
+
+  /* result_list ==> (result ",")* */
+  for (current_index = 0;
+       current_index < table->dfw_lex_tree.table_end;
+       )
+    {
+      read_result (table, &current_index);
+
+      if (current_index < table->dfw_lex_tree.table_end)
+	{
+	  check_lex (table, &current_index, DFW_LEX_COMMA);
+	}
+    }
+}
+
+/* Return 1 if the lexical element pointed by CURRENT_INDEX in TABLE is
+   of type LEX; else, return 0.  */
+
+static int
+test_lex (struct result_table *table, index_type current_index,
+	  enum dfw_lex_type lex)
+{
+  return current_index < table->dfw_lex_tree.table_end
+    && table->dfw_lex_tree.beginning_of_table[current_index] == lex;
+}
+
+/* Return 1 if the lexical element pointed by CURRENT_INDEX in TABLE
+   corresponds to a DFW_SEM_CONST.  */
+
+static int
+test_const (struct result_table *table, index_type current_index)
+{
+  return test_lex (table, current_index, DFW_LEX_CSTRING);
+}
+
+/* Return 1 if the lexical element pointed by CURRENT_INDEX in TABLE
+   corresponds to a DFW_SEM_BEGIN_TUPLE; else, return 0.  */
+
+static int
+test_tuple (struct result_table *table, index_type current_index)
+{
+  return test_lex (table, current_index, DFW_LEX_BEGIN_TUPLE);
+}
+
+/* Return 1 if the lexical element pointed by CURRENT_INDEX in TABLE
+   corresponds to a DFW_SEM_LIST; else, return 0.  */
+
+static int
+test_list (struct result_table *table, index_type current_index)
+{
+  return test_lex (table, current_index, DFW_LEX_BEGIN_LIST);
+}
+
+/* Return 1 if the lexical element pointed by CURRENT_INDEX in TABLE
+   corresponds to a DFW_SEM_RESULT; else, return 0.  */
+
+static int
+test_result (struct result_table *table, index_type current_index)
+{
+  return test_lex (table, current_index, DFW_LEX_ITEM)
+    && test_lex (table, current_index + 2, DFW_LEX_EQUALS)
+    && test_value (table, current_index + 3);
+}
+
+/* Return 1 if the lexical element pointed by CURRENT_INDEX in TABLE
+   corresponds to a DFW_SEM_VALUE; else, return 0.  */
+
+static int
+test_value (struct result_table *table, index_type current_index)
+{
+  return test_const (table, current_index)
+    || test_tuple (table, current_index)
+    || test_list (table, current_index);
+}
+
+/* If the lexical element pointed by CURRENT_INDEX in TABLE
+   is not of type LEX, raise an error; else, increment CURRENT_INDEX.  */
+
+static int
+check_lex (struct result_table *table, index_type *current_index,
+	   enum dfw_lex_type lex)
+{
+  if (!test_lex (table, *current_index, lex))
+    {
+      error ("parse error in DFW output: missing %s\n",
+	     dfw_lex_list [lex].name);
+    }
+  else
+    {
+      (*current_index)++;
+    }
+
+  return 0;
+}
+
+/* Read a result from the lex table.  Syntax rule used:
+
+   result ==>
+     variable "=" value
+
+*/
+
+static void
+read_result (struct result_table *table, index_type *current_index)
+{
+  read_variable (table, current_index);
+  check_lex (table, current_index, DFW_LEX_EQUALS);
+  read_value (table, current_index);
+}
+
+/* Read a variable from the lex table.  Syntax rule used:
+
+   variable ==>
+     string
+
+*/
+
+static void
+read_variable (struct result_table *table, index_type *current_index)
+{
+  dfw_tree_element item;
+
+  check_lex (table, current_index, DFW_LEX_ITEM);
+  dfw_tree_push (&(table->dfw_sem_tree), (dfw_tree_element) DFW_SEM_VARIABLE);
+
+  item = table->dfw_lex_tree.beginning_of_table[*current_index];
+  dfw_tree_push (&(table->dfw_sem_tree), item);
+  (*current_index)++;
+  dfw_tree_push (&(table->dfw_sem_tree), table->dfw_sem_tree.table_end + 1);
+}
+
+/* Read a const from the lex table.  Syntax rule used:
+
+   const ==>
+     cstring
+
+*/
+
+static void
+read_const (struct result_table *table, index_type *current_index)
+{
+  dfw_tree_element item;
+
+  check_lex (table, current_index, DFW_LEX_CSTRING);
+  dfw_tree_push (&(table->dfw_sem_tree), (dfw_tree_element) DFW_SEM_CONST);
+
+  item = table->dfw_lex_tree.beginning_of_table[*current_index];
+  dfw_tree_push (&(table->dfw_sem_tree), item);
+  (*current_index)++;
+  dfw_tree_push (&(table->dfw_sem_tree), table->dfw_sem_tree.table_end + 1);
+}
+
+/* Read a tuple from the lex table.  Syntax rule used:
+
+   tuple ==>
+   "{}" | "{" result ( "," result )* "}"
+
+*/
+
+static void
+read_tuple (struct result_table *table, index_type *current_index)
+{
+  index_type sibling_index_location, sibling_index;
+
+  check_lex (table, current_index, DFW_LEX_BEGIN_TUPLE);
+  dfw_tree_push (&(table->dfw_sem_tree),
+		 (dfw_tree_element) DFW_SEM_BEGIN_TUPLE);
+  sibling_index_location = dfw_tree_push (&(table->dfw_sem_tree), 0);
+
+  while (!test_lex (table, *current_index, DFW_LEX_END_TUPLE))
+    {
+      read_result (table, current_index);
+
+      if (!test_lex (table, *current_index, DFW_LEX_END_TUPLE))
+	{
+	  check_lex (table, current_index, DFW_LEX_COMMA);
+	}
+    }
+
+  check_lex (table, current_index, DFW_LEX_END_TUPLE);
+  dfw_tree_push (&(table->dfw_sem_tree), (dfw_tree_element) DFW_SEM_END_TUPLE);
+  dfw_tree_push (&(table->dfw_sem_tree), table->dfw_sem_tree.table_end + 1);
+  sibling_index = table->dfw_sem_tree.table_end;
+  dfw_tree_set (&(table->dfw_sem_tree),
+		sibling_index_location,
+		sibling_index);
+}
+
+/* Read a list from the lex table.  Syntax rule used:
+
+   list ==>
+     "[]"
+     | "[" value ( "," value )* "]"
+     | "[" result ( "," result )* "]"
+
+*/
+
+static void
+read_list (struct result_table *table, index_type *current_index)
+{
+  index_type sibling_index_location, sibling_index;
+
+  check_lex (table, current_index, DFW_LEX_BEGIN_LIST);
+  dfw_tree_push (&(table->dfw_sem_tree),
+		 (dfw_tree_element) DFW_SEM_BEGIN_LIST);
+  sibling_index_location = dfw_tree_push (&(table->dfw_sem_tree), 0);
+
+  while (!test_lex (table, *current_index, DFW_LEX_END_LIST))
+    {
+      if (test_result (table, *current_index))
+	{
+	  read_result (table, current_index);
+	}
+      else if (test_value (table, *current_index))
+	{
+	  read_value (table, current_index);
+	}
+      else
+	{
+	  error ("parse error in DFW output: ambiguous list element\n");
+	}
+
+      if (!test_lex (table, *current_index, DFW_LEX_END_LIST))
+	{
+	  check_lex (table, current_index, DFW_LEX_COMMA);
+	}
+    }
+
+  check_lex (table, current_index, DFW_LEX_END_LIST);
+  dfw_tree_push (&(table->dfw_sem_tree),
+		 (dfw_tree_element) DFW_SEM_END_LIST);
+  dfw_tree_push (&(table->dfw_sem_tree), table->dfw_sem_tree.table_end + 1);
+  sibling_index = table->dfw_sem_tree.table_end;
+  dfw_tree_set (&(table->dfw_sem_tree),
+		sibling_index_location,
+		sibling_index);
+}
+
+/* Read a value from the lex table.  Syntax rule used:
+
+   value ==>
+    const | tuple | list
+
+*/
+
+static void
+read_value (struct result_table *table, index_type *current_index)
+{
+  index_type sibling_index_location, sibling_index;
+
+  dfw_tree_push (&(table->dfw_sem_tree), (dfw_tree_element) DFW_SEM_VALUE);
+  sibling_index_location = dfw_tree_push (&(table->dfw_sem_tree), 0);
+
+  if (test_const (table, *current_index))
+    {
+      read_const (table, current_index);
+    }
+  else if (test_tuple (table, *current_index))
+    {
+      read_tuple (table, current_index);
+    }
+  else if (test_list (table, *current_index))
+    {
+      read_list (table, current_index);
+    }
+  else
+    {
+      error ("parse error in DFW output: ambiguous value.");
+    }
+  
+  sibling_index = table->dfw_sem_tree.table_end;
+  dfw_tree_set (&(table->dfw_sem_tree),
+		sibling_index_location,
+		sibling_index);
+}
+
+/* Read a target stream from the DFW connection output.  Syntax rule used:
+
+   target-stream-output ==>
+     "@" c-string
+
+*/
+
+static void
+read_target_stream (int timeout)
+{
+  /* Not needed; ignore.  */
+  skip_line ();
+}
+
+/* Read a log stream from the DFW connection output.  Syntax rule used:
+
+   log-stream-output ==>
+     "&" c-string
+
+*/
+
+static void
+read_log_stream (int timeout)
+{
+  /* Not needed; ignore.  */
+  skip_line ();
+}
+
+/* Read until PATTERN is found.  If PATTERN is not found after a max number
+   of char (MAX_CHAR) is read, return 0; else, return 1.  */
+
+static void
+skip_string (char *pattern, int max_char)
+{
+  int current;
+  int len = strlen (pattern);
+  int i;
+  char *p;
+
+  for (i = 0; i < max_char; i++)
+    {
+      current = readchar (dfw_timeout);
+      if (current == pattern[0])
+	{
+	  for (p = pattern + 1; *p != '\0'; p++)
+	    {
+	      current = readchar (dfw_timeout);
+	      i++;
+	      if (*p != current)
+		break;
+	    }
+	  if (*p == '\0')
+	    return;
+	}
+    }
+}
+
+static void
+skip_prompt ()
+{
+  skip_string ("(gdb)\n", 10);
+}
+
+static void
+skip_line ()
+{
+  skip_string ("\n", 1024);
+}
+
+static void
+info_dfw_trees ()
+{
+  print_result_record (&current_result_record);
+}
+
+/* Synchronize dfwapi_task_list with the target system.  */
+
+void
+dfwapi_update_task_list ()
+{
+  static const char kernel_task_list_branch [] =
+    "/ObjTypeList/KernelTask/ObjList";
+  static const char rtp_list_branch [] =
+    "/ObjTypeList/RTP/ObjList";
+  static char *kernel_task_list_options = NULL;
+  static const char kernel_task_list_format [] = "*/{%s,ParentId,TID}";
+  static char *rtp_list_options = NULL;
+  static const char rtp_list_format [] =
+    "*/{%s,ParentId,TID,Children/Task/*/{%s,ParentId,TID}}";
+  static int kernel_task_list_branch_len = 0;
+  static int rtp_list_branch_len = 0;
+  index_type current_index;
+  static const char new_thread_desc [] = "finding new threads";
+  struct dfw_sem_element sem_element;
+  int dfw_id, rtp_dfw_id, parent_dfw_id;
+  CORE_ADDR thread_id, pid;
+  struct dfwapi_task* current_task;
+
+  if (!kernel_task_list_options)
+    {
+      kernel_task_list_options =
+	(char *) xmalloc (strlen (kernel_task_list_format)
+			  + strlen (current_connection->thread_id_leaf));
+      sprintf (kernel_task_list_options, kernel_task_list_format,
+	       current_connection->thread_id_leaf);
+    }
+
+  if (!rtp_list_options)
+    {
+      rtp_list_options =
+	(char *) xmalloc (strlen (rtp_list_format)
+			  + 2 * strlen (current_connection->thread_id_leaf));
+      sprintf (rtp_list_options, rtp_list_format,
+	       current_connection->thread_id_leaf,
+	       current_connection->thread_id_leaf);
+    }
+
+  if (!kernel_task_list_branch_len)
+    kernel_task_list_branch_len = strlen (kernel_task_list_branch);
+  if (!rtp_list_branch_len)
+    rtp_list_branch_len = strlen (rtp_list_branch);
+
+  invalidate_dfwapi_task_list ();
+
+  wrs_info_retrieve (current_connection->info_retrieval_core_branch,
+		     current_connection->info_retrieval_core_branch_len,
+		     kernel_task_list_branch,
+		     kernel_task_list_branch_len,
+		     kernel_task_list_options);
+  read_output_record_sequence (dfw_timeout, current_token);
+
+  current_index = 0;
+  sem_element_process_wrs_info_header (&current_result_record, &current_index,
+				     new_thread_desc);
+
+  next_sem_element_with_check (&current_result_record, &current_index,
+			       new_thread_desc, DFW_SEM_VALUE);
+  next_sem_element_with_check (&current_result_record, &current_index,
+			       new_thread_desc, DFW_SEM_BEGIN_LIST);
+
+  /* Go through the kernel task list: */
+  while (current_index < current_result_record.dfw_sem_tree.table_end)
+    {
+      if (test_next_sem_element (&current_result_record, current_index,
+				 DFW_SEM_END_LIST))
+	break;
+
+      /* Id */
+
+      sem_element = next_sem_element_with_check
+	(&current_result_record, &current_index,
+	 new_thread_desc, DFW_SEM_VARIABLE);
+      sem_element_process_const_integer_value
+	(&current_result_record, &current_index,
+	 new_thread_desc, &dfw_id);
+
+      /* ParentId */
+
+      sem_element = next_sem_element_with_check
+	(&current_result_record, &current_index,
+	 new_thread_desc, DFW_SEM_VARIABLE);
+      sem_element_process_const_integer_value
+	(&current_result_record, &current_index,
+	 new_thread_desc, &parent_dfw_id);
+
+      /* TID */
+
+      sem_element = next_sem_element_with_check
+	(&current_result_record, &current_index,
+	 new_thread_desc, DFW_SEM_VARIABLE);
+      sem_element_process_const_core_addr_value
+	(&current_result_record, &current_index,
+	 new_thread_desc, &thread_id);
+
+      current_task = dfwapi_lookup_task_by_dfw_id (dfw_id);
+
+      if (!current_task)
+	{
+	  current_task =
+            dfwapi_task_build (DFWAPI_CONTEXT_KERNEL_TASK,
+                               current_connection->system_dfw_id, thread_id,
+                               dfw_id, thread_id,
+                               parent_dfw_id);
+	  add_vxworks_task (current_task);
+	}
+      current_task->is_valid = 1;
+    }
+
+  wrs_info_retrieve (current_connection->info_retrieval_core_branch,
+		     current_connection->info_retrieval_core_branch_len,
+		     rtp_list_branch,
+		     rtp_list_branch_len,
+		     rtp_list_options);
+  read_output_record_sequence (dfw_timeout, current_token);
+
+  current_index = 0;
+  sem_element_process_wrs_info_header (&current_result_record, &current_index,
+				     new_thread_desc);
+
+  next_sem_element_with_check (&current_result_record, &current_index,
+			       new_thread_desc, DFW_SEM_VALUE);
+  next_sem_element_with_check (&current_result_record, &current_index,
+			       new_thread_desc, DFW_SEM_BEGIN_LIST);
+
+  /* Go through the rtp list: */
+  while (current_index < current_result_record.dfw_sem_tree.table_end)
+    {
+      if (test_next_sem_element (&current_result_record, current_index,
+				 DFW_SEM_END_LIST))
+	break;
+
+      /* RTP Id */
+
+      sem_element = next_sem_element_with_check
+	(&current_result_record, &current_index,
+	 new_thread_desc, DFW_SEM_VARIABLE);
+      sem_element_process_const_integer_value
+	(&current_result_record, &current_index,
+	 new_thread_desc, &rtp_dfw_id);
+
+      /* RTP parent Id */
+
+      sem_element = next_sem_element_with_check
+	(&current_result_record, &current_index,
+	 new_thread_desc, DFW_SEM_VARIABLE);
+      sem_element_process_const_integer_value
+	(&current_result_record, &current_index,
+	 new_thread_desc, &parent_dfw_id);
+
+      /* RTP TID */
+
+      sem_element = next_sem_element_with_check
+	(&current_result_record, &current_index,
+	 new_thread_desc, DFW_SEM_VARIABLE);
+      sem_element_process_const_core_addr_value
+	(&current_result_record, &current_index,
+	 new_thread_desc, &pid);
+
+      current_task = dfwapi_lookup_task_by_dfw_id (rtp_dfw_id);
+
+      if (!current_task)
+	{
+	  current_task = dfwapi_task_build (DFWAPI_CONTEXT_RTP, rtp_dfw_id, pid,
+					     rtp_dfw_id, 0, parent_dfw_id);
+	  add_vxworks_task (current_task);
+	}
+      current_task->is_valid = 1;
+
+      /* Go throught this RTP's task list.  */
+
+      next_sem_element_with_check (&current_result_record, &current_index,
+				   new_thread_desc, DFW_SEM_VARIABLE);
+      next_sem_element_with_check (&current_result_record, &current_index,
+				   new_thread_desc, DFW_SEM_VALUE);
+      next_sem_element_with_check (&current_result_record, &current_index,
+				   new_thread_desc, DFW_SEM_BEGIN_LIST);
+      while (current_index < current_result_record.dfw_sem_tree.table_end)
+	{
+	  if (test_next_sem_element (&current_result_record, current_index,
+				     DFW_SEM_END_LIST))
+	    {
+	      next_sem_element_with_check (&current_result_record,
+					   &current_index,
+					   new_thread_desc,
+					   DFW_SEM_END_LIST);
+	      break;
+	    }
+
+	  /* RTP task Id */
+
+	  sem_element = next_sem_element_with_check
+	    (&current_result_record, &current_index,
+	     new_thread_desc, DFW_SEM_VARIABLE);
+	  sem_element_process_const_integer_value
+	    (&current_result_record, &current_index,
+	     new_thread_desc, &dfw_id);
+
+	  /* RTP task parent Id */
+
+	  sem_element = next_sem_element_with_check
+	    (&current_result_record, &current_index,
+	     new_thread_desc, DFW_SEM_VARIABLE);
+	  sem_element_process_const_integer_value
+	    (&current_result_record, &current_index,
+	     new_thread_desc, &parent_dfw_id);
+
+	  /* RTP task TID */
+
+	  sem_element = next_sem_element_with_check
+	    (&current_result_record, &current_index,
+	     new_thread_desc, DFW_SEM_VARIABLE);
+	  sem_element_process_const_core_addr_value
+	    (&current_result_record, &current_index,
+	     new_thread_desc, &thread_id);
+
+	  current_task = dfwapi_lookup_task_by_dfw_id (dfw_id);
+
+	  if (!current_task)
+	    {
+	      current_task = dfwapi_task_build (DFWAPI_CONTEXT_RTP_TASK,
+						 rtp_dfw_id, pid,
+                                                 dfw_id, thread_id,
+						 parent_dfw_id);
+	      add_vxworks_task (current_task);
+	    }
+	  current_task->is_valid = 1;
+	}
+    }
+  prune_dfwapi_task_list ();
+}
+
+/* Add curly bracket ('{' and '}') around S and return the result.  The
+   result is queued in the cleanup list.  */
+
+static char *
+add_curly_braquets (char *s)
+{
+  int result_len = strlen (s) + 2;
+  char *result = (char *) xmalloc (result_len + 1);
+  make_cleanup (xfree, result);
+  sprintf (result, "{%s}", s);
+  return result;
+}
+
+/* (Re-)initialize every information stored in current_connection,
+   except full_target_name.  */
+
+static void
+initialize_current_connection_info ()
+{
+  current_connection->system_dfw_id = 0;
+
+  if (current_connection->core_name)
+    {
+      xfree (current_connection->core_name);
+      current_connection->core_name = NULL;
+    }
+
+  if (current_connection->info_retrieval_core_branch)
+    {
+      xfree (current_connection->info_retrieval_core_branch);
+      current_connection->info_retrieval_core_branch = NULL;
+    }
+
+  if (current_connection->thread_id_leaf)
+    {
+      xfree (current_connection->thread_id_leaf);
+      current_connection->thread_id_leaf = NULL;
+    }
+
+  current_connection->info_retrieval_core_branch_len = 0;
+}
+
+/* Fill the current_connection record.  Return 1 if everything went fine,
+   0 otherwise.  If 0 is returned, an error message can be found in ERROR_MSG.
+   It assumes that current_connection->target_name has already been set.
+
+   This function is aimed to resolved the incompatibilities in the
+   info retrieval tree between DFW version.  It expects to find:
+
+   * the core or system name in
+     + Targets
+       + <target name>
+         + MAIN_INFO_DIRECTORY;
+
+   * the system thread id in
+     + Targets
+       + <target name>
+         + MAIN_INFO_DIRECTORY
+           + <core or system name>
+             + SYSTEM_THREAD_ID_LEAF;
+
+   * kernel task ids in
+     + Targets
+       + <target name>
+         + MAIN_INFO_DIRECTORY
+           + <core or system name>
+             + ObjTypeList
+               + KernelTask
+                 + ObjList
+                   + <any task>
+                     +{THREAD_ID_LEAF}
+
+*/
+
+static int
+get_current_connection_info (char *main_info_directory,
+			     char *system_thread_id_leaf,
+			     char *thread_id_leaf,
+			     char **error_msg)
+{
+  struct cleanup *old_cleanup = make_cleanup (null_cleanup, NULL);
+  const char request_target_branch [] = "/Targets/";
+  const char request_thread_id_branch [] = "/ThreadId";
+  index_type current_index;
+  dfw_tree_element item;
+  struct dfw_sem_element sem_element;
+
+  int request_len = strlen (request_target_branch)
+    + strlen (current_connection->full_target_name)
+    + 1 + strlen (main_info_directory);
+  char *request = (char *) xmalloc (request_len + 1);
+  make_cleanup (xfree, request);
+
+  initialize_current_connection_info ();
+
+  strcpy (request, request_target_branch);
+  strcat (request, current_connection->full_target_name);
+  strcat (request, "/");
+  strcat (request, main_info_directory);
+  wrs_info_retrieve (request, request_len, NULL, 0, "*");
+  read_output_record_sequence (dfw_timeout, current_token);
+
+  current_index = 0;
+  sem_element = next_sem_element (&current_result_record, &current_index);
+  if (sem_element.type != DFW_SEM_RESULT_CLASS
+      || sem_element.value.result_class_value != RESULT_CLASS_DONE)
+    {
+      *error_msg = xstrdup ("DFW: error while getting the core/system name.");
+      do_cleanups (old_cleanup);
+      return 0;
+    }
+
+  /* Eat the name of the result variable, so that the next variable
+     in the ouput will be the core name.  */
+
+  sem_element = next_sem_element (&current_result_record, &current_index);
+  if (sem_element.type != DFW_SEM_VARIABLE)
+    {
+      *error_msg = xstrdup ("DFW: unexpected format in output.");
+      do_cleanups (old_cleanup);
+      return 0;
+    }
+
+  for (sem_element = next_sem_element (&current_result_record, &current_index);
+       current_index < current_result_record.dfw_sem_tree.table_end;
+       sem_element = next_sem_element (&current_result_record, &current_index))
+    {
+      if (sem_element.type == DFW_SEM_VARIABLE)
+	{
+	  if (!current_connection->core_name)
+	    {
+	      if (sem_element.value.string_value
+		  && strcmp (sem_element.value.string_value,
+			     main_info_directory) != 0)
+		current_connection->core_name =
+                  xstrdup (sem_element.value.string_value);
+	    }
+	  else
+	    {
+	      *error_msg =
+		xstrdup ("DFW: two cores are available for target.");
+	      do_cleanups (old_cleanup);
+	      return 0;
+	    }
+	}
+    }
+
+  if (!current_connection->core_name)
+    {
+      *error_msg = xstrdup ("DFW: no core for target.");
+      do_cleanups (old_cleanup);
+      return 0;
+    }
+
+
+  current_connection->info_retrieval_core_branch_len =
+    strlen (request_target_branch)
+    + strlen (current_connection->full_target_name)
+    + 1 + strlen (main_info_directory) + 1
+    + strlen (current_connection->core_name);
+  current_connection->info_retrieval_core_branch =
+    (char *) xmalloc (current_connection->info_retrieval_core_branch_len
+		      + 1);
+  memset (current_connection->info_retrieval_core_branch, 0,
+	  current_connection->info_retrieval_core_branch_len);
+
+  strcpy (current_connection->info_retrieval_core_branch,
+	  request_target_branch);
+  strcat (current_connection->info_retrieval_core_branch,
+	  current_connection->full_target_name);
+  strcat (current_connection->info_retrieval_core_branch, "/");
+  strcat (current_connection->info_retrieval_core_branch, main_info_directory);
+  strcat (current_connection->info_retrieval_core_branch, "/");
+  strcat (current_connection->info_retrieval_core_branch,
+	  current_connection->core_name);
+
+
+  wrs_info_retrieve (current_connection->info_retrieval_core_branch,
+		     current_connection->info_retrieval_core_branch_len,
+		     request_thread_id_branch,
+		     0,
+		     add_curly_braquets (system_thread_id_leaf));
+  read_output_record_sequence (dfw_timeout, current_token);
+
+  current_connection->system_dfw_id = 0;
+
+  current_index = 0;
+  sem_element_process_result_header (&current_result_record, &current_index,
+				     "getting system thread id");
+
+  while (current_index < current_result_record.dfw_sem_tree.table_end)
+    {
+      sem_element = next_sem_element (&current_result_record, &current_index);
+
+      if (sem_element.type == DFW_SEM_VARIABLE
+	  && strcmp (sem_element.value.string_value,
+		     system_thread_id_leaf) == 0)
+	{
+	  sem_element_process_const_integer_value
+            (&current_result_record,
+             &current_index,
+             "getting system thread id",
+             &current_connection->system_dfw_id);
+	}
+    }
+
+  if (!current_connection->system_dfw_id)
+    {
+      *error_msg = xstrdup ("DFW: No system thread id returned.");
+      do_cleanups (old_cleanup);
+      return 0;
+    }
+
+  current_connection->thread_id_leaf = xstrdup (thread_id_leaf);
+  do_cleanups (old_cleanup);
+  return 1;
+}
+
+/* Initialize current connection record independantly of the version
+   of Workbench.  Return 0 if failed, and an error message in
+   ERROR_MSG.  Otherwise, return 1.  */
+
+static int
+get_current_connection (char **error_msg)
+{
+  /* Starting from Workbench 3.2, an incompatible change has been
+     made in the info-retrieve tree.
+
+     Previously, the hierarchy was:
+
+	  + Target
+	    + Cores
+	      + Os objects
+
+     With WB 3.2, the concept of system has been introduced to
+     represent the OS (basicaly).  So now the hierarchy is:
+
+	  + Target
+	    + Systems
+	      + Cores
+	      + Os objects
+
+     So, if the first possibility failed, try the second one.  */
+
+  return get_current_connection_info ("Cores", "Name", "Id", error_msg)
+    || get_current_connection_info ("Systems", "ThreadId", "ThreadId",
+				    error_msg);
+}
+
+/* Send a DFW command COMMAND with parameters PARAMETERS and options
+   OPTIONS.  */
+static void
+dfwapi_send_simple_command (char *command, char *params, char *options)
+{
+  int command_size = strlen (command);
+  int params_size = strlen (params);
+  int options_size = strlen (options);
+
+  write_token ();
+  write_string (command, command_size);
+  write_string (" ", 1);
+  write_string (params, params_size);
+  write_string (" ", 1);
+  write_string (options, options_size);
+  write_string ("\n", 1);
+  read_output_record_sequence (load_timeout, current_token);
+}
+
+/* Try to re-connect the dfwserver to the current target.  Ignore
+   errors.  This feature is only supported by WB > 3.2.  */
+
+static void
+dfwapi_wrs_target_connect ()
+{
+  char *target_name = current_connection->full_target_name;
+
+  /* At this point, the full target name should have been initialized
+     (by dfwapi_open).  */
+  gdb_assert (current_connection->full_target_name);
+
+  /* From the Workbench logs, it has been infered that these two connection
+     commands are actually needed, starting from WB > 3.2:
+
+     -wrs-target-connect <target name>
+     -wrs-target-connect <target name> -tgt
+
+     ...but disconnect first, and re-synchronize with target before
+     connecting; if it receives the connected and disconnected events
+     at the same time, the dfwserver gets confused.  */
+
+  dfwapi_send_simple_command ("-wrs-target-disconnect", target_name, "-tgt");
+  dfwapi_send_simple_command ("-wrs-target-disconnect", target_name, "");
+  wrs_info_retrieve_1 ("/Targets/", current_connection->full_target_name,
+		       "{Name,Connected,ThreadId}", remote_timeout);
+  dfwapi_send_simple_command ("-wrs-target-connect", target_name, "");
+  dfwapi_send_simple_command ("-wrs-target-connect", target_name, "-tgt");
+}
+
+void
+dfwapi_open (char *dfw_server_name, char *target_name,
+             struct gdbarch *gdbarch)
+{
+  static char match_everything[] = ".*";
+
+  char *host_name_loc = NULL;
+  char *port_loc = NULL;
+  char *port_string = NULL;
+  char *host_name = 0;
+  int host_name_len = 0, port_len = 0;
+  index_type current_index;
+  dfw_tree_element item;
+  struct dfw_tree_type *sem_table = &(current_result_record.dfw_sem_tree);
+  struct dfw_sem_element sem_element;
+  WTX_DESC_Q *wtx_desc;
+  struct cleanup *old_cleanup = make_cleanup (null_cleanup, NULL);
+  char *error_msg;
+
+  if (current_connection->full_target_name)
+    make_cleanup(xfree, current_connection->full_target_name);
+  if (current_connection->core_name)
+    make_cleanup (xfree, current_connection->core_name);
+  if (current_connection->info_retrieval_core_branch)
+    make_cleanup (xfree, current_connection->info_retrieval_core_branch);
+  if (current_connection != &null_connection)
+    make_cleanup (xfree, current_connection);
+  current_connection =
+    (struct dfwapi_connection *) xmalloc (sizeof (struct dfwapi_connection));
+  memcpy (current_connection, &null_connection,
+          sizeof (struct dfwapi_connection));
+  current_connection->byte_order = gdbarch_byte_order (gdbarch);
+
+  if (!wtxapi_initialize ())
+    error ("cannot initialize wtx handler.");
+
+  wtx_desc = wtxapi_info_q (dfw_server_name, match_everything,
+                            match_everything);
+
+  if (!wtx_desc)
+    {
+      error ("Error: %s", wtxapi_err_msg_get ());
+
+      error ("No dfwserver registered under the name %s.\n"
+	     "Do 'wtxInfoQ' in wtxtcl to list the dfwserver names.\n",
+	     dfw_server_name);
+    }
+
+  if (wtx_desc->pNext)
+    {
+      printf_unfiltered
+	("Several dfwserver registered under the name %s.\n"
+	 "Do 'wtxInfoQ' in wtxtcl to list the dfwserver names.\n",
+	 dfw_server_name);
+    }
+
+  printf_unfiltered ("Connecting to %s...\n", wtx_desc->wpwrName);
+
+  parse_service_key (wtx_desc->wpwrKey, &host_name_loc,
+		     &host_name_len, &port_loc, &port_len);
+  make_cleanup (cleanup_wtxapi_result_free, wtx_desc);
+
+  host_name = (char *) xmalloc (host_name_len + port_len + 2);
+  memcpy (host_name, host_name_loc, host_name_len);
+  *(host_name + host_name_len) = ':';
+  memcpy (host_name + host_name_len + 1, port_loc, port_len);
+  *(host_name + host_name_len + port_len + 1) = '\0';
+
+  printf_unfiltered ("Connecting to DFW server %s...", host_name);
+
+  if (remote_dfw_desc)
+    serial_close (remote_dfw_desc);
+  remote_dfw_desc = serial_open (host_name);
+
+  if (!remote_dfw_desc)
+    error ("Not able to connect to DFW server on %s", host_name);
+  skip_prompt ();
+
+  wrs_info_retrieve ("/Targets", 0, NULL, 0, "* -N");
+  read_output_record_sequence (dfw_timeout, current_token);
+
+  current_index = 0;
+  sem_element =
+    sem_element_process_wrs_info_header (&current_result_record,
+					 &current_index,
+					 "getting full target name");
+
+  while (current_index < current_result_record.dfw_sem_tree.table_end)
+    {
+      sem_element = next_sem_element (&current_result_record, &current_index);
+
+      if (sem_element.type == DFW_SEM_CONST)
+	{
+	  if (sem_element.value.string_value
+	      && strncmp (sem_element.value.string_value,
+			  target_name, strlen (target_name)) == 0)
+	    {
+	      current_connection->full_target_name =
+                xstrdup (sem_element.value.string_value);
+	    }
+	}
+    }
+
+  if (!current_connection->full_target_name)
+    error ("target %s not registered in DFW server.", target_name);
+
+  printf_unfiltered ("Connecting to %s...\n",
+                     current_connection->full_target_name);
+  gdb_flush (gdb_stdout);
+
+  if (!get_current_connection (&error_msg))
+    {
+      /* With WB 3.2, the dfwserver sometimes get confused by a disconnect
+	 that does not follow a connect.  e.g.
+
+	 6-wrs-target-disconnect 68@cardhu.act-europe.fr -tgt
+	 (gdb)
+	 6^done
+	 7-wrs-target-disconnect 68@cardhu.act-europe.fr
+	 (gdb)
+	 7^done
+	 8-wrs-info-retrieve -t /Targets/68@cardhu.act-europe.fr
+	    default:{Name,Connected,ThreadId -n
+	 (gdb)
+	 8^done,i=[Name="68@cardhu.act-europe.fr",Connected="false",
+            ThreadId=""]
+	 9-wrs-target-connect 68@cardhu.act-europe.fr
+	 (gdb)
+	 9^done
+	 10-wrs-target-connect 68@cardhu.act-europe.fr -tgt
+	 (gdb)
+	 =disconnected,thread-id="4",def-name="68@cardhu.act-europe.fr"
+	 =connected,thread-id="6",def-name="68@cardhu.act-europe.fr"
+	 =connected,thread-id="7",def-name="68@cardhu.act-europe.fr",
+            system-name="sys-000"
+	 10^done
+	 12-wrs-info-retrieve -t /Targets/68@cardhu.act-europe.fr/Systems
+            default:* -n
+	 (gdb)
+	 12^done,i=[Systems=[]]
+
+	 Notice the disconnected/connected event that are "received"
+	 at the same time; this probably causes the problem.  This
+	 problem has been reported to WRS.  Fortunately, there is a workaround:
+	 the dfwserver handles properly the case when -wrs-target-disconnect
+	 is issued after a -wrs-target-connect: in this case, the disconnected
+	 event is properly "flushed".  To be in this situation, call
+	 dfwapi_wrs_target_connect twice.  */
+
+      dfwapi_wrs_target_connect ();
+      dfwapi_wrs_target_connect ();
+      
+      if (!get_current_connection (&error_msg))
+	error ("%s", error_msg);
+    }
+
+  /* Select the system thread.  */
+  if (!dfwapi_thread_select (current_connection->system_dfw_id))
+    error ("DFW: unable to switch to system thread.");
+
+  dfwapi_system_task.rtp_dfw_id = current_connection->system_dfw_id;
+  dfwapi_system_task.dfw_id = current_connection->system_dfw_id;
+
+  do_cleanups (old_cleanup);
+}
+
+/* Return the task status of the task whose DFW Id is DFW_ID.  */
+
+enum dfwapi_task_status
+dfwapi_get_task_status (long dfw_id)
+{
+  static const char request_desc [] = "getting dfw task status";
+  static const char task_status_branch [] = "/IdInfo";
+  static int task_status_branch_len = 0;
+  static char *options, *status;
+  struct dfw_sem_element sem_element;
+  index_type current_index = 0;
+  enum dfwapi_task_status result = DFWAPI_TASK_STATUS_LAST;
+  int i;
+  struct cleanup *old_cleanup = make_cleanup (xfree, options);
+
+  if (!task_status_branch_len)
+    task_status_branch_len = strlen (task_status_branch);
+
+  options = xstrprintf ("{Status} -id %ld", dfw_id);
+
+  wrs_info_retrieve (task_status_branch, task_status_branch_len,
+		     NULL, 0, options);
+  read_output_record_sequence (dfw_timeout, current_token);
+
+  sem_element = next_sem_element (&current_result_record, &current_index);
+  if (sem_element.type != DFW_SEM_RESULT_CLASS)
+    error ("DFW: error in %s.", request_desc);
+
+  if (sem_element.value.result_class_value == RESULT_CLASS_ERROR)
+    {
+      result = DFWAPI_TASK_STATUS_DEAD;
+    }
+  else
+    {
+      sem_element = next_sem_element_with_check
+	(&current_result_record, &current_index,
+	 request_desc, DFW_SEM_VARIABLE);
+      sem_element = next_sem_element_with_check
+	(&current_result_record, &current_index,
+	 request_desc, DFW_SEM_VALUE);
+      sem_element = next_sem_element_with_check
+	(&current_result_record, &current_index,
+	 request_desc, DFW_SEM_BEGIN_LIST);
+      sem_element = next_sem_element_with_check
+	(&current_result_record, &current_index,
+	 request_desc, DFW_SEM_VARIABLE);
+      sem_element_process_const_string_value
+	(&current_result_record, &current_index,
+	 request_desc, &status);
+      result = lookup_enum_code (dfwapi_task_status_desc, status,
+				 DFWAPI_TASK_STATUS_LAST);
+    }
+
+  do_cleanups (old_cleanup);
+  return result;
+}
+
+char *
+dfwapi_get_task_status_desc (enum dfwapi_task_status status)
+{
+  return dfwapi_task_status_desc [status].name;
+}
+
+
+/* Return non-zero iff STATUS is stopped or stopped+something.  */
+
+int
+dfwapi_stopped_status_kind (enum dfwapi_task_status status)
+{
+  return (status == DFWAPI_TASK_STATUS_STOPPED
+          || status == DFWAPI_TASK_STATUS_STOPPED_T
+          || status == DFWAPI_TASK_STATUS_STOPPED_P
+          || status == DFWAPI_TASK_STATUS_STOPPED_S
+          || status == DFWAPI_TASK_STATUS_STOPPED_P_S
+          || status == DFWAPI_TASK_STATUS_STOPPED_T_S
+          || status == DFWAPI_TASK_STATUS_STOPPED_P_T
+          || status == DFWAPI_TASK_STATUS_STOP_P_T_S
+          || status == DFWAPI_TASK_STATUS_ST_P_T_S);
+}
+
+char *
+dfwapi_get_target_name ()
+{
+  return current_connection->full_target_name;
+}
+
+int
+dfwapi_get_system_id ()
+{
+  return current_connection->system_dfw_id;
+}
+
+char *
+dfwapi_get_core_name ()
+{
+  return current_connection->core_name;
+}
+
+static void
+dfwapi_send (char *arg, int from_tty)
+{
+  int saved_dfw_show_responses = dfw_show_responses;
+  dfw_show_responses = 1;
+  if (arg)
+    {
+      write_token ();
+      write_string (arg, strlen (arg));
+    }
+  write_string ("\n", 1);
+  read_output_record_sequence (dfw_timeout, current_token);
+  dfw_show_responses = saved_dfw_show_responses;
+}
+
+/* Send a -wrs-info-retrieve request on the DFW connection stream.  The
+   command format is:
+   "-wrs-info-retrieve -t " TREE_BRANCH TREE_LEAF " default:" PATTERN " -n"
+*/
+
+static void
+wrs_info_retrieve (const char *tree_branch,
+		   const int tree_branch_len,
+		   const char *tree_leaf,
+		   const int tree_leaf_len,
+		   const char *pattern)
+{
+  static const char command_id[] = "-wrs-info-retrieve -t ";
+  static const char url[] = " default:";
+  static const char option[] = " -n";
+  static int command_id_size = 0;
+  static int url_size = 0;
+  static int option_size = 0;
+  int tree_branch_len0 = 0;
+  int tree_leaf_len0 = 0;
+
+  if (!command_id_size)
+    command_id_size = strlen (command_id);
+  if (!url_size)
+    url_size = strlen (url);
+  if (!option_size)
+    option_size = strlen (option);
+  if (tree_branch)
+    {
+      if (tree_branch_len)
+	tree_branch_len0 = tree_branch_len;
+      else
+	tree_branch_len0 = strlen (tree_branch);
+    }
+  if (tree_leaf)
+    {
+      if (tree_leaf_len)
+	tree_leaf_len0 = tree_leaf_len;
+      else
+	tree_leaf_len0 = strlen (tree_leaf);
+    }
+
+  write_token ();
+  write_string (command_id, command_id_size);
+  if (tree_branch)
+    write_string (tree_branch, tree_branch_len0);
+  if (tree_leaf)
+    write_string (tree_leaf, tree_leaf_len0);
+  write_string (url, url_size);
+  write_string (pattern, strlen (pattern));
+  write_string (option, option_size);
+  write_string ("\n", 1);
+}
+
+/* Same as wrs_info_retrieve, only with a simpler interface; plus, read
+   the command output and fill the output buffer.  */
+
+static void
+wrs_info_retrieve_1 (const char *tree_branch,
+		     const char *tree_leaf,
+		     const char *pattern,
+		     int timeout)
+{
+  wrs_info_retrieve (tree_branch, strlen (tree_branch),
+		     tree_leaf, strlen (tree_leaf), pattern);
+  read_output_record_sequence (timeout, current_token);
+}
+/* Select the thread whose DFW thread id is DFW_ID.  */
+
+static int
+dfwapi_thread_select (int dfw_id)
+{
+  static const char command[] = "-thread-select ";
+  static int command_size = 0;
+  static char thread_id_string [32];
+  struct dfw_sem_element sem_element;
+  index_type current_index = 0;
+
+  if (!command_size)
+    command_size = strlen (command);
+
+  if (dfw_id == current_selected_thread)
+    return 1;
+
+  sprintf (thread_id_string, "%d", dfw_id);
+
+  write_token ();
+  write_string (command, command_size);
+  write_string (thread_id_string, strlen (thread_id_string));
+  write_string ("\n", 1);
+
+  read_output_record_sequence (remote_timeout, current_token);
+
+  /* Check result.  */
+  sem_element = next_sem_element (&current_result_record, &current_index);
+  if (sem_element.type != DFW_SEM_RESULT_CLASS
+      || sem_element.value.result_class_value != RESULT_CLASS_DONE)
+    return 0;
+  else
+    {
+      current_selected_thread = dfw_id;
+      return 1;
+    }
+}
+
+/* Return the name of the object whose dfw id is DFW_ID.  */
+
+char *
+dfwapi_get_object_name (long dfw_id)
+{
+  static const char thread_info_branch [] = "/IdInfo";
+  static int thread_info_branch_len = 0;
+  index_type current_index;
+  static const char thread_info_desc [] = "getting thread info";
+  struct dfw_sem_element sem_element;
+  char buffer [128];
+  char *name;
+
+  if (!thread_info_branch_len)
+    thread_info_branch_len = strlen (thread_info_branch);
+  sprintf (buffer, "{Name} -id %ld", dfw_id);
+
+  wrs_info_retrieve (thread_info_branch, thread_info_branch_len,
+		     NULL, 0, buffer);
+  read_output_record_sequence (remote_timeout, current_token);
+
+  current_index = 0;
+  sem_element_process_result_header (&current_result_record,
+				       &current_index,
+				       thread_info_desc);
+
+  next_sem_element_with_check (&current_result_record, &current_index,
+			       thread_info_desc, DFW_SEM_VALUE);
+  next_sem_element_with_check (&current_result_record, &current_index,
+			       thread_info_desc, DFW_SEM_BEGIN_LIST);
+  next_sem_element_with_check (&current_result_record, &current_index,
+			       thread_info_desc, DFW_SEM_VARIABLE);
+  sem_element_process_const_string_value (&current_result_record,
+					  &current_index,
+					  thread_info_desc,
+					  &name);
+  return name;
+}
+
+static void
+write_string (const char *buf, int cnt)
+{
+  int i;
+  if (serial_write (remote_dfw_desc, buf, cnt))
+    error ("write on dfw server failed.");
+
+  if (dfw_show_requests)
+    for (i = 0; i < cnt; i++)
+      printf_unfiltered ("%c", buf[i]);
+}
+
+static token_type
+write_token ()
+{
+  current_token++;
+  write_int ((int) current_token);
+  return current_token;
+}
+
+static void
+write_int (int i)
+{
+  static char int_string [32];
+  sprintf (int_string, "%d", i);
+  write_string (int_string, strlen (int_string));
+}
+
+
+static struct dfwapi_task *
+dfwapi_task_build (enum dfwapi_context_type type, int rtp_dfw_id,
+                   CORE_ADDR pid, int dfw_id, CORE_ADDR thread_id,
+                   int parent_dfw_id)
+{
+  struct dfwapi_task *t;
+  t = (struct dfwapi_task *) xmalloc (sizeof (struct dfwapi_task));
+  t->type = type;
+  t->rtp_dfw_id = rtp_dfw_id;
+  t->pid = pid;
+  t->dfw_id = dfw_id;
+  t->thread_id = thread_id;
+  t->parent_dfw_id = parent_dfw_id;
+  t->parent = NULL;
+  t->next = NULL;
+  t->is_valid = 0;
+  return t;
+}
+
+static void
+add_vxworks_task (struct dfwapi_task *task)
+{
+  task->next = dfwapi_task_list;
+  dfwapi_task_list = task;
+}
+
+struct dfwapi_task *
+dfwapi_lookup_task (CORE_ADDR id)
+{
+  struct dfwapi_task *current;
+
+  for (current = dfwapi_task_list; current != NULL; current = current->next)
+    {
+      if (current->pid == id || current->thread_id == id)
+	{
+	  return current;
+	}
+    }
+  return NULL;
+}
+
+struct dfwapi_task *
+dfwapi_get_task (CORE_ADDR id)
+{
+  struct dfwapi_task *current = dfwapi_lookup_task (id);
+
+  if (!current)
+    {
+      dfwapi_update_task_list ();
+      current = dfwapi_lookup_task (id);
+    }
+
+  return current;
+}
+
+static void
+invalidate_dfwapi_task_list ()
+{
+  struct dfwapi_task *current;
+
+  for (current = dfwapi_task_list; current != NULL; current = current->next)
+    {
+      current->is_valid = 0;
+    }
+}
+
+static void
+prune_dfwapi_task_list ()
+{
+  struct dfwapi_task *current;
+  struct dfwapi_task *precedent;
+
+  for (precedent = NULL, current = dfwapi_task_list;
+       current != NULL;
+       precedent = current, current = current->next)
+    {
+      if (!current->is_valid)
+	{
+	  if (precedent)
+	    {
+	      precedent->next = current->next;
+	      xfree (current);
+	      current = precedent;
+	    }
+	  else
+	    {
+	      dfwapi_task_list = current->next;
+	      xfree (current);
+	      current = dfwapi_task_list;
+	    }
+	}
+    }
+}
+
+void
+dfwapi_clear_task_list ()
+{
+  struct dfwapi_task *current;
+  struct cleanup *old_cleanup;
+
+  if (dfwapi_task_list == NULL)
+    return;
+  else
+    old_cleanup = make_cleanup (xfree, dfwapi_task_list);
+
+  for (current = dfwapi_task_list->next;
+       current != NULL;
+       current = current->next)
+    {
+      make_cleanup (xfree, current);
+    }
+  do_cleanups (old_cleanup);
+  dfwapi_task_list = NULL;
+}
+
+ptid_t
+dfwapi_task_ptid_build (struct dfwapi_task *task)
+{
+  switch (task->type)
+    {
+    case DFWAPI_CONTEXT_RTP:
+      return ptid_build (task->pid, 0, 0);
+    case DFWAPI_CONTEXT_RTP_TASK:
+      return ptid_build (task->pid, task->thread_id, 0);
+    case DFWAPI_CONTEXT_KERNEL_TASK:
+      return ptid_build (task->pid, 0, 0);
+    }
+  return null_ptid;
+}
+
+ptid_t
+get_ptid_from_dfw_id (int dfw_id)
+{
+  struct dfwapi_task *current = dfwapi_get_task_from_dfw_id (dfw_id);
+  if (current)
+    return dfwapi_task_ptid_build (current);
+  else
+    return null_ptid;
+}
+
+long
+ptid_get_dfw_id (ptid_t ptid)
+{
+  struct dfwapi_task *current;
+  long lwp = ptid_get_lwp (ptid);
+  int pid = ptid_get_pid (ptid);
+
+  /* RTP */
+  if (lwp)
+    {
+      current = dfwapi_get_task (lwp);
+      if (current)
+	return current->dfw_id;
+    }
+
+  /* kernel task */
+  if (pid)
+    {
+      current = dfwapi_get_task (pid);
+      if (current)
+	return current->dfw_id;
+    }
+
+  return 0;
+}
+
+struct dfwapi_task*
+dfwapi_get_task_from_dfw_id (int dfw_id)
+{
+  struct dfwapi_task *current;
+  current = dfwapi_lookup_task_by_dfw_id (dfw_id);
+  if (!current)
+    {
+      dfwapi_update_task_list ();
+      current = dfwapi_lookup_task_by_dfw_id (dfw_id);
+    }
+  return current;
+}
+
+struct dfwapi_task*
+dfwapi_lookup_task_parent (struct dfwapi_task *t)
+{
+  struct dfwapi_task *parent;
+  if (!t)
+    return NULL;
+
+  if (t->parent)
+    {
+      parent = t->parent;
+    }
+  else
+    {
+      parent = dfwapi_lookup_task_by_dfw_id (t->parent_dfw_id);
+      t->parent = parent;
+    }
+
+  return parent;
+}
+
+struct dfwapi_task *
+dfwapi_lookup_task_by_dfw_id (int dfw_id)
+{
+  struct dfwapi_task *current;
+
+  for (current = dfwapi_task_list; current != NULL; current = current->next)
+    {
+      if (current->dfw_id == dfw_id)
+	{
+	  return current;
+	}
+    }
+  return NULL;
+}
+
+/* Initialize the DFW engine for use by GDB, after WTX
+   initialization.  This is for use in the wtxapi_support_ops.  In the
+   DFW case, it just checks that dfwapi_open has already been called,
+   to avoid any invalid use of wtxapi_support_ops vector.  */
+
+static void
+dfwapi_initialize (HWTX wtx_handle)
+{
+  if (!remote_dfw_desc)
+    error (_("No connection to DFW server."));
+}
+
+/* Implement the "get_task_pd" method of the wtxapi_support_ops vector.
+   (see remote-wtxapi.h for more details.  */
+
+static int
+dfwapi_get_task_pd (int task_id, pd_id_t *task_pd)
+{
+  struct dfwapi_task *task = dfwapi_get_task (task_id);
+
+  gdb_assert (task_pd != NULL);
+
+  if (!task)
+    return 0;
+
+  switch (task->type)
+    {
+    case DFWAPI_CONTEXT_KERNEL_TASK:
+      *task_pd = NULL_PD;
+      return 1;
+    case DFWAPI_CONTEXT_RTP:
+    case DFWAPI_CONTEXT_RTP_TASK:
+      *task_pd = task->pid;
+      return 1;
+    default:
+      return 0;
+    }
+}
+
+WTX_CONTEXT_ID_T
+dfwapi_get_wtx_context_id (struct dfwapi_task *task)
+{
+  switch (task->type)
+    {
+    case DFWAPI_CONTEXT_RTP_TASK:
+    case DFWAPI_CONTEXT_KERNEL_TASK:
+      return task->thread_id;
+    case DFWAPI_CONTEXT_RTP:
+      return task->pid;
+    default:
+      return 0;
+    }
+}
+
+static struct wtxapi_thread_info *
+dfwapi_get_thread_list (void)
+{
+  struct dfwapi_task *current;
+  struct wtxapi_thread_info *thread_list_head = NULL;
+
+  dfwapi_update_task_list ();
+  for (current = dfwapi_task_list; current != NULL; current = current->next)
+    {
+      struct wtxapi_thread_info *new_thread
+        = xmalloc (sizeof (struct wtxapi_thread_info));
+
+      new_thread->id = dfwapi_get_wtx_context_id (current);
+      new_thread->name = xstrdup (dfwapi_get_object_name (current->dfw_id));
+      new_thread->regs_addr = 0;
+      new_thread->fp_regs_addr = 0;
+      new_thread->next = thread_list_head;
+      thread_list_head = new_thread;
+    }
+
+  return thread_list_head;
+}
+
+static WTX_CONTEXT_ID_T
+dfwapi_system_mode_get_current_context_id (void)
+{
+  struct dfwapi_task *selected_task =
+    dfwapi_get_task_from_dfw_id (current_selected_thread);
+  return dfwapi_get_wtx_context_id (selected_task);
+}
+
+static int
+dfwapi_system_mode_support_p (void)
+{
+  /* System mode not implemented.  */
+  return 0;
+}
+
+static struct wtxapi_support_ops dfwapi_support_ops;
+
+static void
+initialize_wtx_support_ops ()
+{
+  dfwapi_support_ops.wtx_connection_established_callback = dfwapi_initialize;
+  dfwapi_support_ops.get_thread_list = dfwapi_get_thread_list;
+  dfwapi_support_ops.get_task_pd = dfwapi_get_task_pd;
+  dfwapi_support_ops.system_mode_support_p = dfwapi_system_mode_support_p;
+  dfwapi_support_ops.system_mode_get_current_context_id =
+    dfwapi_system_mode_get_current_context_id;
+}
+
+void
+_initialize_remote_dfwapi ()
+{
+  struct cmd_list_element *c;
+
+  result_table_allocate (&current_result_record);
+
+  /* Provide DFW-based support routine to the WTX module.  */
+  initialize_wtx_support_ops ();
+  wtxapi_set_support_ops (&dfwapi_support_ops);
+
+  add_info ("dfw-sem-trees", info_dfw_trees, "current DFW trees.");
+  add_cmd ("dfw-send", no_class, dfwapi_send,
+           "Send the request to the current dfw server.\n", &cmdlist);
+  add_setshow_boolean_cmd ("dfw-show-requests", no_class, &dfw_show_requests,"\
+Set whether to show the requests sent to the DFW server.", "\
+Show whether to show the requests sent to the DFW server.", "\
+If set, the requests sent to the DFW server are printed to stdout.",
+			   NULL, NULL,
+			   &setlist, &showlist);
+  add_setshow_boolean_cmd ("dfw-show-responses", no_class,
+			   &dfw_show_responses,"\
+Set whether to show the responses sent by the DFW server.", "\
+Show whether to show the responses sent by the DFW server.", "\
+If set, the responses sent to the DFW server are printed to stdout.",
+			   NULL, NULL,
+			   &setlist, &showlist);
+  add_setshow_boolean_cmd ("dfw-warn-unknown-identifiers", no_class,
+			   &dfw_warn_unknown_identifiers,"\
+Set whether to warn when unknown identifiers are found in DFW responses.", "\
+Show whether to warn when unknown identifiers are found in DFW responses.", "\
+If set, when unknown ids are found in DFW responses, a warning is sent.",
+			   NULL, NULL,
+			   &setlist, &showlist);
+  add_setshow_uinteger_cmd ("dfw-load-timeout", no_class, &load_timeout,"\
+Set timeout in seconds used when loading new objects on DFW target.\n\
+The default value is 30 seconds.", "\
+Show timeout in seconds used when loading new objects on DFW target.\n\
+The default value is 30 seconds.", "\
+Timeout in seconds used when loading new objects on DFW target.\n\
+The default value is 30 seconds.",
+                            NULL, NULL,
+                            &setlist, &showlist);
+
+  add_setshow_uinteger_cmd ("dfw-timeout", no_class, &dfw_timeout,"\
+Set timeout in seconds used for the DFW connection.\n\
+The default value is 10 seconds.", "\
+Show timeout in seconds used for the DFW connection.\n\
+The default value is 10 seconds.", "\
+Timeout in seconds used for the DFW connection.\n\
+The default value is 10 seconds.",
+                            NULL, NULL,
+                            &setlist, &showlist);
+}
diff --git a/gdb/remote-dfwapi.h b/gdb/remote-dfwapi.h
new file mode 100644
index 0000000..0d9faa7
--- /dev/null
+++ b/gdb/remote-dfwapi.h
@@ -0,0 +1,191 @@
+/* Remote debugging API based on Wind River System's DFW protocol.
+
+   Copyright 2005, 2010 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+/* Symbols and symbol lists.  */
+
+#ifndef REMOTE_DFWAPI_H
+#define REMOTE_DFWAPI_H
+
+/* DFW context types.  */
+
+enum dfwapi_context_type
+{
+  DFWAPI_CONTEXT_KERNEL_TASK,
+  DFWAPI_CONTEXT_RTP,
+  DFWAPI_CONTEXT_RTP_TASK,
+  DFWAPI_CONTEXT_LAST
+};
+
+/* Full kernel/RTP task list.  */
+
+struct dfwapi_task
+{
+  struct dfwapi_task *next;
+
+  /* Context type.  */
+  enum dfwapi_context_type type;
+
+  /* DFW id for this task's RTP.  */
+  int rtp_dfw_id;
+
+  /* Task id for this task's RTP.  */
+  CORE_ADDR pid;
+
+  /* DFW id for this task.  */
+  int dfw_id;
+
+  /* Task id for this task.  */
+  CORE_ADDR thread_id;
+
+  /* DFW id for the parent of this task.  */
+  int parent_dfw_id;
+
+  /* vxworks task descriptor of the parent.  If not initialized yet,
+     set to NULL.  */
+  struct dfwapi_task *parent;
+
+  /* If non-null, this vxworks task has been found during the update of
+     the vxworks task list.  */
+  int is_valid;
+};
+
+extern struct dfwapi_task dfwapi_system_task;
+
+/* DFW task status.  */
+
+enum dfwapi_task_status
+{
+  DFWAPI_TASK_STATUS_STATELESS,
+  DFWAPI_TASK_STATUS_STOPPED,
+  DFWAPI_TASK_STATUS_STOPPED_T,
+  DFWAPI_TASK_STATUS_STOPPED_P,
+  DFWAPI_TASK_STATUS_STOPPED_S,
+  DFWAPI_TASK_STATUS_STOPPED_P_S,
+  DFWAPI_TASK_STATUS_STOPPED_T_S,
+  DFWAPI_TASK_STATUS_STOPPED_P_T,
+  DFWAPI_TASK_STATUS_STOP_P_T_S,
+  DFWAPI_TASK_STATUS_ST_P_T_S,
+  DFWAPI_TASK_STATUS_SUSPEND,
+  DFWAPI_TASK_STATUS_DELAY,
+  DFWAPI_TASK_STATUS_PENDING,
+  DFWAPI_TASK_STATUS_PEND_S,
+  DFWAPI_TASK_STATUS_PEND_T,
+  DFWAPI_TASK_STATUS_PEND_S_T,
+  DFWAPI_TASK_STATUS_READY,
+  DFWAPI_TASK_STATUS_DEAD,
+  DFWAPI_TASK_STATUS_RTP_NORMAL,
+  DFWAPI_TASK_STATUS_LAST
+};
+
+/* tree element code for the asynchronous result class.  */
+
+enum dfwapi_async_class_type
+  {
+    /* Target State Change: */
+
+    DFWAPI_ASYNC_CLASS_STATELESS,
+    DFWAPI_ASYNC_CLASS_STOPPED,
+    DFWAPI_ASYNC_CLASS_RUNNING,
+    DFWAPI_ASYNC_CLASS_CONTAINER_STOPPED,
+    DFWAPI_ASYNC_CLASS_INDETERMINATE_STATE,
+
+    /* Target Connection Events: */
+
+    DFWAPI_ASYNC_CLASS_CONNECTED,
+    DFWAPI_ASYNC_CLASS_DISCONNECTED,
+
+    /* Target Data Change: */
+
+    DFWAPI_ASYNC_CLASS_REGISTER_CHANGED,
+    DFWAPI_ASYNC_CLASS_MEMORY_CHANGED,
+
+    /* Download Event Notifications: */
+
+    DFWAPI_ASYNC_CLASS_DOWNLOAD,
+    DFWAPI_ASYNC_CLASS_DOWNLOAD_COMPLETE,
+    DFWAPI_ASYNC_CLASS_DOWNLOAD_FAILED,
+    DFWAPI_ASYNC_CLASS_MODULES_CHANGED,
+
+    /* TOS Event Notifications: */
+
+    DFWAPI_ASYNC_CLASS_CONTEXT_START,
+    DFWAPI_ASYNC_CLASS_CONTEXT_EXIT,
+    DFWAPI_ASYNC_CLASS_TOOL_DETACH,
+    DFWAPI_ASYNC_CLASS_TOOL_ATTACH,
+
+    /* Register Definitions Changed Event Notification: */
+
+    DFWAPI_ASYNC_CLASS_REGDEFCHANGED,
+
+    /* Breakpoint events: */
+
+    DFWAPI_ASYNC_CLASS_BREAKPOINT_CHANGED,
+    DFWAPI_ASYNC_CLASS_EVENTPOINT_CHANGED,
+    DFWAPI_ASYNC_CLASS_EVENTPOINT_DELETED,
+
+    /* Unkwnown: */
+    DFWAPI_ASYNC_CLASS_LAST
+  };
+
+/* Stop reason for the event DFWAPI_ASYNC_CLASS_STOPPED.  */
+enum dfwapi_stop_reason
+  {
+    DFWAPI_STOP_REASON_USER_STOPPED,
+    DFWAPI_STOP_REASON_END_STEPPING_RANGE,
+    DFWAPI_STOP_REASON_BREAKPOINT_HIT,
+    DFWAPI_STOP_REASON_LOCATION_REACHED,
+    DFWAPI_STOP_REASON_FUNCTION_FINISHED,
+    DFWAPI_STOP_REASON_SIGNAL_RECEIVED,
+    DFWAPI_STOP_REASON_RUN_FAILED,
+    DFWAPI_STOP_REASON_MODULE_CHANGED,
+    DFWAPI_STOP_REASON_LAST
+  };
+
+/* Full vxworks task list on target.  */
+
+extern struct dfwapi_task *dfwapi_task_list;
+
+extern char * dfwapi_get_object_name (long dfw_id);
+extern enum dfwapi_task_status dfwapi_get_task_status (long dfw_id);
+extern char * dfwapi_get_task_status_desc (enum dfwapi_task_status status);
+extern int dfwapi_stopped_status_kind (enum dfwapi_task_status status);
+
+extern void dfwapi_update_task_list ();
+
+extern ptid_t dfwapi_task_ptid_build (struct dfwapi_task *task);
+extern long ptid_get_dfw_id (ptid_t ptid);
+
+extern struct dfwapi_task * dfwapi_lookup_task (CORE_ADDR id);
+extern struct dfwapi_task * dfwapi_lookup_task_by_dfw_id (int dfw_id);
+
+extern void dfwapi_clear_task_list ();
+
+extern ptid_t get_ptid_from_dfw_id (int dfw_id);
+extern struct dfwapi_task * dfwapi_get_task_from_dfw_id (int dfw_id);
+extern struct dfwapi_task* dfwapi_lookup_task_parent
+ (struct dfwapi_task *t);
+
+extern void dfwapi_open (char *dfw_server_name, char *target_name,
+                         struct gdbarch *gdbarch);
+
+extern char * dfwapi_get_target_name ();
+extern char * dfwapi_get_core_name ();
+extern int dfwapi_get_system_id ();
+
+#endif
-- 
1.6.3.3

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

* [vxworks 05/14] Add options to control Vxworks related settings.
  2010-04-25 15:47 Adding support for VxWorks target Joel Brobecker
                   ` (8 preceding siblings ...)
  2010-04-25 15:48 ` [vxworks 09/14] remote-wtx-hw / register fetch/store support Joel Brobecker
@ 2010-04-25 15:56 ` Joel Brobecker
  2010-05-04 15:25   ` Joel Brobecker
  2010-04-25 15:56 ` [vxworks 06/14] VxWorks breakpoint-handling module Joel Brobecker
                   ` (5 subsequent siblings)
  15 siblings, 1 reply; 27+ messages in thread
From: Joel Brobecker @ 2010-04-25 15:56 UTC (permalink / raw)
  To: gdb-patches

This is module provides the commands that allow a user to configure
certain settings related to the WTX/VxWorks environment.  For instance,
it allows the user to configure the stack size used when "running"
their program (in reality, spawning a new task), or the maximum amount
of time allowed to load a module before a timeout kicks in; etc.

It also provides some set commands that allow the user to turn some
traces on, for bug-hunting purposes...

2010-04-23  Joel Brobecker  <brobecker@adacore.com>

        * remote-wtx-opt.h, remote-wtx-opt.c: New files.
---
 gdb/remote-wtx-opt.c |  323 ++++++++++++++++++++++++++++++++++++++++++++++++++
 gdb/remote-wtx-opt.h |   46 +++++++
 2 files changed, 369 insertions(+), 0 deletions(-)
 create mode 100644 gdb/remote-wtx-opt.c
 create mode 100644 gdb/remote-wtx-opt.h

diff --git a/gdb/remote-wtx-opt.c b/gdb/remote-wtx-opt.c
new file mode 100644
index 0000000..70910b6
--- /dev/null
+++ b/gdb/remote-wtx-opt.c
@@ -0,0 +1,323 @@
+/* Support for the WTX protocol.
+
+   This unit provides a user interface to various settings which are
+   related to the WTX protocol.  We also provide several debug switches
+   that the user can use to turn on some debugging traces.
+
+   Copyright (C) 2007, 2010 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#include "defs.h"
+#include "command.h"
+#include "gdbcmd.h"
+#include "remote-wtx-opt.h"
+#include "remote-wtxapi.h"
+
+/* The various settings that affect the the WTX protocol will be
+   accessible through the "set/show wtx" command prefix.  The following
+   cmd_list_element variables contain the list of commands accessible
+   under that prefix.  */
+
+static struct cmd_list_element *set_wtx_list = NULL;
+static struct cmd_list_element *show_wtx_list = NULL;
+
+/* The various debug switches are accessible through the "set/show wtx
+   debug" command prefix.  The following cmd_list_element variables
+   contain the list of commands accessible under that prefix.  */
+
+static struct cmd_list_element *set_wtx_debug_list = NULL;
+static struct cmd_list_element *show_wtx_debug_list = NULL;
+
+/* The name we use to identify ourselves when we connect to
+   the target server.  The default value is allocated during
+   this file initialization phase.  */
+static char *tool_name = NULL;
+
+/* The module load timeout in seconds.  */
+static int load_timeout = 30;
+
+/* The stack size in bytes used when spawning a new process.  */
+static int stack_size = 0x10000;
+
+/* The options used when spawning a new process.  */
+static int task_options = 0;
+
+/* The priority used when spawning a new process.  */
+static int task_priority = 100;
+
+/* Set to non-zero to print debug traces of the events received by GDB.  */
+static int debug_events_level = 0;
+
+/* Set to non-zero to print debug traces related to watchpoint support.  */
+static int debug_watchpoints = 0;
+
+/* Set to non-zero to print debug traces of the operations involving
+   objfile manipuations.  */
+static int debug_objfiles = 0;
+
+/* If set to non-zero, then the user wants to see more verbose error
+   messages when the TCL interpreter failed to evaluate a command.  */
+static int debug_tcl = 0;
+
+/* Accessor for TOOL_NAME.  */
+
+char *
+wtx_opt_tool_name (void)
+{
+  return tool_name;
+}
+
+/* Accessor for LOAD_TIMEOUT.  */
+
+int
+wtx_opt_load_timeout (void)
+{
+  return load_timeout;
+}
+
+int
+wtx_opt_stack_size (void)
+{
+  return stack_size;
+}
+
+int
+wtx_opt_task_options (void)
+{
+  return task_options;
+}
+
+/* Init task options using the target information.  */
+
+void
+wtx_opt_init_task_options (void)
+{
+  const int VX_FP_TASK = wtxapi_vx_fp_task ();
+  const int VX_SPE_TASK = 0x04000000;
+
+  /* If the target has a floating-point processor, then set the
+     floating-point option flag.  */
+  if (wtxapi_target_has_fpp_get ())
+    task_options |= VX_FP_TASK;
+
+  /* If the target is e500v2, the SPE APU should be enabled to run
+     floating point programs.
+     
+     FIXME: guitton/2009-07-20: In VxWorks 6.6, there is no way to
+     discriminate between e500 and e500v2: both have the same cpu
+     variant "ppc85XX".  As we only support e500v2, it is fine to
+     assume that PPC85XX actually means e500v2...  For now.  But
+     it is not in the general case.  The problem is fixed in Vxworks
+     6.7, so we may get rid of this kludge at some point.  */
+  if (wtxapi_has_target_variant ("_e500v2")
+      || wtxapi_has_target_variant ("_ppc85XX"))
+    task_options |= VX_SPE_TASK;
+}
+
+int
+wtx_opt_task_priority (void)
+{
+  return task_priority;
+}
+
+/* Accessor for DEBUG_TCL  */
+
+int
+wtx_opt_tcl_verbose_p (void)
+{
+  return debug_tcl;
+}
+
+/* Print a debug message if DEBUG_OBJFILES is non-zero.
+   The message uses the string FORMAT and all the associated parameters, 
+   following the printf syntax.  */
+
+void
+wtx_opt_objfiles_debug (const char *format, ...)
+{
+  if (debug_objfiles)
+    {
+      va_list args;
+
+      va_start (args, format);
+      printf_filtered ("DEBUG (objfiles): ");
+      vprintf_filtered (format, args);
+      printf_filtered ("\n");
+      va_end (args);
+    }
+}
+
+/* Print a debug message if DEBUG_EVENTS is non-zero.
+   The message uses the string FORMAT and all the associated parameters, 
+   following the printf syntax.  */
+
+void
+wtx_opt_events_debug (int level, const char *format, ...)
+{
+  if (debug_events_level >= level)
+    {
+      va_list args;
+
+      va_start (args, format);
+      printf_filtered ("DEBUG (events): ");
+      vprintf_filtered (format, args);
+      printf_filtered ("\n");
+      va_end (args);
+    }
+}
+
+void wtx_opt_watchpoints_debug (const char *format, ...)
+{
+  if (debug_watchpoints)
+    {
+      va_list args;
+
+      va_start (args, format);
+      printf_filtered ("DEBUG (watchpoints): ");
+      vprintf_filtered (format, args);
+      printf_filtered ("\n");
+      va_end (args);
+    }
+}
+
+/* Implement the "set wtx" command.
+   This is not actually a valid command, so inform the user of that fact,
+   and print the list of valid subcommands to help him.  */
+
+static void
+set_wtx_command (char *args, int from_tty)
+{
+  printf_filtered (_("\"set wtx\" must be followed by a subcommand.\n"));
+  help_list (set_wtx_list, "set wtx ", -1, gdb_stdout);
+}
+
+/* Implement the "show wtx" command: Print the value of all settings
+   available through that command prefix.  */
+
+static void
+show_wtx_command (char *args, int from_tty)
+{
+  cmd_show_list (show_wtx_list, from_tty, "");
+}
+
+/* Implement the "set wtx debug" command.
+   This is not actually a valid command, so inform the user of that fact,
+   and print the list of valid subcommands to help him.  */
+
+static void
+set_wtx_debug_command (char *args, int from_tty)
+{
+  printf_filtered (_("\"set wtx debug\" must be followed by a subcommand.\n"));
+  help_list (set_wtx_debug_list, "set wtx debug", -1, gdb_stdout);
+}
+
+/* Implement the "show wtx" command: Print the value of all settings
+   available through that command prefix.  */
+
+static void
+show_wtx_debug_command (char *args, int from_tty)
+{
+  cmd_show_list (show_wtx_debug_list, from_tty, "");
+}
+
+void
+_initialize_remote_wtx_opt (void)
+{
+  tool_name = xstrdup ("gdb");
+
+  /* Various "set/show" switches.  */
+  add_prefix_cmd ("wtx", no_class, set_wtx_command, _("\
+Adjust various settings specific to the WTX protocol."), &set_wtx_list,
+                  "set wtx ", 0 /* allow_unknown */, &setlist);
+  add_prefix_cmd ("wtx", no_class, show_wtx_command, _("\
+Print various settings specific to the WTX protocol."), &show_wtx_list,
+                  "show wtx ", 0 /* allow_unknown */, &showlist);
+
+  add_setshow_string_noescape_cmd ("tool-name", class_support,
+                                   &tool_name, _("\
+Set the tool name used when connecting to the target server."), _("\
+Show the tool name used when connecting to the target server."), NULL,
+                                   NULL, NULL,
+                                   &set_wtx_list, &show_wtx_list);
+
+  add_setshow_integer_cmd ("load-timeout", class_support,
+                           &load_timeout, _("\
+Set the timeout in seconds when loading new modules on the target."), _("\
+Show the timeout in seconds when loading new modules on the target."), _("\
+Use this setting to adjust the maximum duration that loading a module\n\
+on the target can take before a timeout aborts the operation."),
+                           NULL, NULL, &set_wtx_list, &show_wtx_list);
+
+  add_setshow_zinteger_cmd ("stack-size", class_support,
+                           &stack_size, _("\
+Set the stack size in bytes for tasks spawned by the debugger."), _("\
+Show the stack size in bytes for tasks spawned by the debugger.."), _("\
+Use this setting to adjust the stack size of new tasks."),
+                           NULL, NULL, &set_wtx_list, &show_wtx_list);
+
+  add_setshow_zinteger_cmd ("task-options", class_support,
+                           &task_options, _("\
+Set the options of new tasks spawned by the debugger."), _("\
+Show the options of new tasks spawned by the debugger.."), _("\
+Use this setting to change the options used when spawning new tasks."),
+                           NULL, NULL, &set_wtx_list, &show_wtx_list);
+
+  add_setshow_zinteger_cmd ("task-priority", class_support,
+                           &task_priority, _("\
+Set the priority of new tasks spawned by the debugger."), _("\
+Show the priority of new tasks spawned by the debugger.."), _("\
+Use this setting to change the priority used when spawning new tasks."),
+                           NULL, NULL, &set_wtx_list, &show_wtx_list);
+
+  /* Various debug switches for WTX.  */
+  add_prefix_cmd ("debug", no_class, set_wtx_debug_command, _("\
+Adjust various settings specific to the WTX protocol."), &set_wtx_debug_list,
+                  "set wtx debug ", 0 /* allow_unknown */, &set_wtx_list);
+  add_prefix_cmd ("debug", no_class, show_wtx_debug_command, _("\
+Print various settings specific to the WTX protocol."), &show_wtx_debug_list,
+                  "show wtx debug ", 0 /* allow_unknown */, &show_wtx_list);
+
+  add_setshow_zinteger_cmd ("events", class_maintenance,
+                            &debug_events_level, _("\
+Print debug traces related to WTX event handling."), _("\
+Debug traces related to WTX event handling."),
+                            NULL, NULL, NULL, &set_wtx_debug_list,
+                            &show_wtx_debug_list);
+
+  add_setshow_boolean_cmd ("objfiles", class_maintenance,
+                           &debug_objfiles, _("\
+Print debug traces related to objfile handling for WTX."), _("\
+Debug traces related to objfile handling for WTX."),
+                           NULL, NULL, NULL, &set_wtx_debug_list,
+                           &show_wtx_debug_list);
+
+  add_setshow_boolean_cmd ("watchpoints", class_maintenance,
+                           &debug_watchpoints, _("\
+Print debug traces related to WTX watchpoint handling."), _("\
+Debug traces related to WTX watchpoint handling."),
+                           NULL, NULL, NULL, &set_wtx_debug_list,
+                           &show_wtx_debug_list);
+
+  add_setshow_boolean_cmd ("tcl", class_maintenance,
+                           &debug_tcl, _("\
+Set the verbosity of the error messages from the TCL interpreter."), _("\
+Show the verbosity of the error messages from the TCL interpreter."), _("\
+When set, the TCL interpreter prints more verbose error messages"),
+                           NULL, NULL,
+                           &set_wtx_debug_list, &show_wtx_debug_list);
+
+}
diff --git a/gdb/remote-wtx-opt.h b/gdb/remote-wtx-opt.h
new file mode 100644
index 0000000..978dffd
--- /dev/null
+++ b/gdb/remote-wtx-opt.h
@@ -0,0 +1,46 @@
+/* Copyright (C) 2007, 2010 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#ifndef REMOTE_WTX_OPT_H
+#define REMOTE_WTX_OPT_H
+
+char *wtx_opt_tool_name (void);
+
+int wtx_opt_load_timeout (void);
+
+int wtx_opt_stack_size (void);
+
+int wtx_opt_task_options (void);
+
+void wtx_opt_init_task_options (void);
+
+int wtx_opt_task_priority (void);
+
+int wtx_opt_tcl_verbose_p (void);
+
+/* Support for debugging traces.  */
+
+void wtx_opt_objfiles_debug (const char *format, ...)
+  ATTR_FORMAT (printf, 1, 2);
+
+void wtx_opt_events_debug (int level, const char *format, ...)
+  ATTR_FORMAT (printf, 2, 3);
+
+void wtx_opt_watchpoints_debug (const char *format, ...)
+  ATTR_FORMAT (printf, 1, 2);
+
+#endif
-- 
1.6.3.3

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

* [vxworks 04/14] remote-wtxapi: The WTX API abstraction layer.
  2010-04-25 15:47 Adding support for VxWorks target Joel Brobecker
                   ` (12 preceding siblings ...)
  2010-04-25 15:56 ` [vxworks 12/14] Add support for VxWorks 6 Joel Brobecker
@ 2010-04-25 16:01 ` Joel Brobecker
  2010-05-04 14:58 ` Adding support for VxWorks target Joel Brobecker
  2010-11-25  0:53 ` Adding support for VxWorks target Joel Brobecker
  15 siblings, 0 replies; 27+ messages in thread
From: Joel Brobecker @ 2010-04-25 16:01 UTC (permalink / raw)
  To: gdb-patches

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

[resending - the first attempt was blocked by the spam filter]

This provides an API torwards for the WTX protocol which is stable
across versions of WTX. The implementation is a thin binding over
the wtx API provided by WindRiver.

2010-04-24  Joel Brobecker  <brobecker@adacore.com>

        * remote-wtxapi.h, remote-wtxapi.c: New files.
---
 gdb/remote-wtxapi.c | 2957 +++++++++++++++++++++++++++++++++++++++++++++++++++
 gdb/remote-wtxapi.h | 1221 +++++++++++++++++++++
 2 files changed, 4178 insertions(+), 0 deletions(-)
 create mode 100644 gdb/remote-wtxapi.c
 create mode 100644 gdb/remote-wtxapi.h


-- 
Joel

[-- Attachment #2: 004-vxworks-remote-wtxapi-The-WTX-API-abstraction-layer.patch --]
[-- Type: text/x-diff, Size: 134250 bytes --]

From cf57f6bcdb5c928b8adf4fbe7c9bdea74b8b764c Mon Sep 17 00:00:00 2001
From: Joel Brobecker <brobecker@adacore.com>
Date: Sat, 24 Apr 2010 11:29:38 -0400
Subject: [PATCH] [vxworks] remote-wtxapi: The WTX API abstraction layer.

This provides an API torwards for the WTX protocol which is stable
across versions of WTX. The implementation is a thin binding over
the wtx API provided by WindRiver.

2010-04-24  Joel Brobecker  <brobecker@adacore.com>

        * remote-wtxapi.h, remote-wtxapi.c: New files.
---
 gdb/remote-wtxapi.c | 2957 +++++++++++++++++++++++++++++++++++++++++++++++++++
 gdb/remote-wtxapi.h | 1221 +++++++++++++++++++++
 2 files changed, 4178 insertions(+), 0 deletions(-)
 create mode 100644 gdb/remote-wtxapi.c
 create mode 100644 gdb/remote-wtxapi.h

diff --git a/gdb/remote-wtxapi.c b/gdb/remote-wtxapi.c
new file mode 100644
index 0000000..2a3d464
--- /dev/null
+++ b/gdb/remote-wtxapi.c
@@ -0,0 +1,2957 @@
+/* Thin binding for the WTX protocol, for GDB.
+
+   Copyright 2004, 2010 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#include "defs.h"
+#include "command.h"
+#include "gdbcmd.h"
+#include "gdb_string.h"
+#include "remote-wtxapi.h"
+#include "gdb_assert.h"
+#include "remote-wtx-utils.h"
+#include "remote-wtx-opt.h"
+
+/* This layer is only implemented and tested on WTX 2.0, 3.0 and 4.0.  */
+
+#if WTX_PROT_VERSION != 2 && WTX_PROT_VERSION != 3 && WTX_PROT_VERSION != 4
+#error
+#endif
+
+/* In WTX 4.0, the context-related functions take a WTX_CONTEXT * as
+   parameter; In previous versions, it was a WTX_CONTEXT_ID_T and a
+   WTX_CONTEXT_TYPE.  The following macros are a klugde to fix that.
+   FIXME: The good method is probably to change the specs of the
+   corresponding functions in remote-wtxapi.  */
+static void initialize_context (WTX_CONTEXT * context,
+                                WTX_CONTEXT_TYPE context_type,
+                                WTX_CONTEXT_ID_T context_id);
+
+#if WTX_PROT_VERSION > 3
+#define MARSHALL_WTX_CONTEXT_PARAM(context) &context
+#else
+#define MARSHALL_WTX_CONTEXT_PARAM(context) \
+  context.contextType, context.contextId
+#endif
+
+#if WTX_PROT_VERSION != 2
+typedef WTX_EVTPT_LIST wtx_evtpt_list;
+#else
+typedef WTX_EVTPT_LIST_2 wtx_evtpt_list;
+#endif
+
+#if WTX_PROT_VERSION != 2
+typedef WTX_MODULE_INFO wtx_module_info;
+#else
+typedef WTX_LD_M_FILE_DESC wtx_module_info;
+#endif
+
+static STATUS (*wtx_initialize) ();
+static STATUS (*wtx_terminate) ();
+static WTX_DESC_Q *(*wtx_info_q) ();
+static STATUS (*wtx_tool_attach) ();
+static int (*wtx_tool_connected) ();
+static STATUS (*wtx_tool_detach) ();
+static STATUS (*wtx_err_clear) ();
+static WTX_ERROR_T (*wtx_err_get) ();
+static WTX_HANDLER_T (*wtx_err_handler_add) ();
+static STATUS (*wtx_err_handler_remove) ();
+static char * (*wtx_err_msg_get) ();
+static WTX_AGENT_MODE_TYPE (*wtx_agent_mode_get) ();
+static STATUS (*wtx_agent_mode_set) ();
+static evtpt_id_t (*wtx_breakpoint_add) ();
+static evtpt_id_t (*wtx_eventpoint_add) ();
+static STATUS (*wtx_eventpoint_delete) ();
+static WTX_EVENT_DESC * (*wtx_event_get) ();
+static WTX_CONTEXT_STATUS (*wtx_context_status_get) ();
+static STATUS (*wtx_context_cont) ();
+static WTX_CONTEXT_ID_T (*wtx_context_create) ();
+static STATUS (*wtx_context_resume) ();
+static evtpt_id_t (*wtx_context_exit_notify_add) ();
+static STATUS (*wtx_context_kill) ();
+static STATUS (*wtx_context_step) ();
+static STATUS (*wtx_context_suspend) ();
+static STATUS (*wtx_context_stop) ();
+static wtx_evtpt_list * (*wtx_eventpoint_list_get) ();
+static STATUS (*wtx_result_free) ();
+static WTX_GOPHER_TAPE * (*wtx_gopher_eval) ();
+static WTX_MEM_INFO * (*wtx_mem_info_get) ();
+static wtxapi_tgt_addr_t (*wtx_mem_alloc) ();
+static int (*wtx_mem_checksum) ();
+static STATUS (*wtx_mem_move) ();
+static STATUS (*wtx_mem_free) ();
+static int (*wtx_mem_read) ();
+static int (*wtx_mem_width_read) ();
+static int (*wtx_mem_write) ();
+static int (*wtx_mem_width_write) ();
+static int (*wtx_mem_set) ();
+static STATUS (*wtx_mem_add_to_pool) ();
+static wtxapi_tgt_addr_t (*wtx_mem_realloc) ();
+static wtxapi_tgt_addr_t (*wtx_mem_align) ();
+static STATUS (*wtx_mem_scan) ();
+static STATUS (*wtx_obj_module_checksum) ();
+static module_id_t (*wtx_obj_module_find_id) ();
+static char * (*wtx_obj_module_find_name) ();
+static WTX_MODULE_INFO * (*wtx_obj_module_info_get) ();
+static wtx_module_info * (*wtx_obj_module_load) ();
+static STATUS (*wtx_obj_module_unload) ();
+static STATUS (*wtx_obj_module_by_name_unload) ();
+static STATUS (*wtx_register_for_event) ();
+static STATUS (*wtx_regs_get) ();
+static STATUS (*wtx_regs_set) ();
+static wtxapi_tgt_addr_t (*wtx_str_to_tgt_addr) ();
+static WTX_CONTEXT_ID_T (*wtx_str_to_context_id) ();
+static WTX_CONTEXT_TYPE (*wtx_str_to_context_type) ();
+static int (*wtx_str_to_int32) ();
+static WTX_EVENT_TYPE (*wtx_str_to_event_type) ();
+static STATUS (*wtx_sym_add) ();
+static WTX_SYMBOL * (*wtx_sym_find) ();
+static WTX_SYM_LIST * (*wtx_sym_list_get) ();
+static WTX_SYM_LIST * (*wtx_sym_list_by_module_id_get) ();
+static WTX_SYM_LIST * (*wtx_sym_list_by_module_name_get) ();
+static STATUS (*wtx_sym_remove) ();
+static WTX_SYM_TBL_INFO * (*wtx_sym_tbl_info_get) ();
+static STATUS (*wtx_target_reset) ();
+static char * (*wtx_ts_name_get) ();
+static int (*wtx_target_cpu_type_get) ();
+static int (*wtx_target_has_fpp_get) ();
+static WTX_ENDIAN_T (*wtx_target_endian_get) ();
+static char * (*wtx_target_bootline_get) ();
+static char * (*wtx_tool_name_get) ();
+static char * (*wtx_ts_version_get) ();
+static STATUS (*wtx_unregister_for_event) ();
+static STATUS (*wtx_direct_call) ();
+static WTX_TS_INFO * (*wtx_ts_info_get) ();
+static STATUS (*wtx_target_attach) ();
+static STATUS (*wtx_probe) ();
+static STATUS (*wtx_timeout_set) ();
+static STATUS (*wtx_timeout_get) ();
+
+#if WTX_PROT_VERSION != 2
+static WTX_MODULE_LIST * (*wtx_obj_module_list_get) ();
+static pd_id_t (*wtx_pd_create) ();
+static pd_id_t (*wtx_pd_kernel_get) ();
+static pd_id_t (*wtx_pd_current_get) ();
+static STATUS (*wtx_pd_current_set) ();
+static WTX_PD_DESC_Q * (*wtx_pd_info_q_get) ();
+#else
+static WTX_MODULE_LIST * (*wtx_obj_module_list) ();
+#endif
+
+/* Conversion from an to a BOOL32.  */
+
+#define TO_BOOL(b) (b ? TRUE : FALSE)
+
+#ifndef WTX_PD_CURRENT
+const wtxapi_tgt_addr_t WTX_PD_CURRENT;
+#endif
+
+#ifndef WTX_PD_ALL
+const wtxapi_tgt_addr_t WTX_PD_ALL = -1;
+#endif
+
+#ifndef WTX_MOD_FIND_IN_ALL_PD
+const wtxapi_tgt_addr_t WTX_MOD_FIND_IN_ALL_PD = -1;
+#endif
+
+#ifndef WTX_SYM_FIND_IN_ALL_PD
+const int WTX_SYM_FIND_IN_ALL_PD = -1;
+#endif
+
+#if WTX_PROT_VERSION == 2
+const WTX_CONTEXT_TYPE WTX_CONTEXT_PD = WTX_CONTEXT_ANY_TASK;
+const int WTX_ERR_PD_INVALID_PD = WTX_ERROR;
+#endif
+
+#if WTX_PROT_VERSION > 3
+const WTX_ACTION_TYPE WTX_ACTION_STOP_ALL = WTX_ACTION_ALL_STOP;
+#endif
+
+const int wtxapi_symbol_copy_none = 0;
+const int wtxapi_symbol_copy_name = 1 << 0;
+const int wtxapi_symbol_copy_module_name = 1 << 1;
+
+const pd_id_t invalid_pd_id = WTX_ERROR;
+const evtpt_id_t invalid_module_id = WTX_ERROR;
+const evtpt_id_t invalid_evtpt_id = WTX_ERROR;
+const WTX_CONTEXT_ID_T invalid_context_id = WTX_ERROR;
+const WTX_AGENT_MODE_TYPE invalid_agent_mode = WTX_ERROR;
+const WTX_CONTEXT_STATUS invalid_context_status = WTX_ERROR;
+
+/* Only one PD is allowed in WTX 2.0; NULL_PD is the value of this PD
+   ID.  */
+
+const pd_id_t NULL_PD = 0;
+
+/* Symbol list: complete declaration.  Based on WTX_SYMBOL and
+   WTX_SYMBOL_LIST.  */
+
+struct wtxapi_symbol_list
+{
+  /* First element of the list.  */
+  WTX_SYMBOL *first;
+
+  /* Current element (when going through the list with the iterator).  */
+  WTX_SYMBOL *current;
+
+  /* Pointer to the result of the WTX operation used to get the symbol
+     list.  It is used at deallocation time.  */
+  void *wtx_result_to_cleanup;
+};
+
+/* Current WTX handle.  */
+
+static HWTX current_wtx_handle = 0;
+
+/* Allocate a new wtxapi_symbol_list and initialize it with
+   WTX_SYM.  WTX_SYM should not be deallocated directly by the caller,
+   it will be deallocated by free_wtxapi_symbol_list.  */
+
+static struct wtxapi_symbol_list
+  *new_wtxapi_symbol_list (WTX_SYM_LIST *wtx_sym);
+
+
+static struct wtxapi_symbol_list
+  *new_wtxapi_symbol_list_from_symbol (WTX_SYMBOL *wtx_sym);
+
+
+/* Allocate a new wtxapi_module_info, and initialize it with
+   WTX_MINFO.  The caller can deallocate WTX_MINFO, as it is fully
+   copied.  It does not initialize wtx_minfo->undef_list; it should
+   be handled separatly if needed.  */
+
+static struct wtxapi_module_info
+  *new_wtxapi_module_info (WTX_MODULE_INFO * wtx_minfo);
+
+static void
+initialize_context (WTX_CONTEXT *context,
+                    WTX_CONTEXT_TYPE context_type,
+                    WTX_CONTEXT_ID_T context_id)
+{
+  context->contextType = context_type;
+  context->contextId = context_id;
+#if WTX_PROT_VERSION > 3
+  context->contextSubId = 0;
+#endif
+}
+
+/* Build and initialize a WTX client handle.  This handle can then be
+   used to connect to a target server.  */
+
+int
+wtxapi_initialize ()
+{
+  return wtx_initialize (&current_wtx_handle) != WTX_ERROR;
+}
+
+/* Return the current WTX handle.  */
+
+HWTX
+wtxapi_get_current_wtx_handle ()
+{
+  return current_wtx_handle;
+}
+
+/* Terminate use of WTX client handle.  */
+
+int
+wtxapi_terminate ()
+{
+  return wtx_terminate (current_wtx_handle) != WTX_ERROR;
+}
+
+/* Return list of registred services.  NAME_PAT is the reg expression
+   to match svc name.  TYPE_PAT is the reg expression to match svc
+   type.  KEY_PAT is the reg expression to match svc key.  */
+
+WTX_DESC_Q *
+wtxapi_info_q (const char *name_pat, const char *type_pat,
+               const char *key_pat)
+{
+  return wtx_info_q (current_wtx_handle, name_pat, type_pat, key_pat);
+}
+
+/* Connect client to the target server.  */
+
+int
+wtxapi_tool_attach (const char *target_name, const char *tool_name)
+{
+  return wtx_tool_attach (current_wtx_handle, target_name,
+                          tool_name) != WTX_ERROR;
+}
+
+/* Check tool connection to the server.  */
+
+int
+wtxapi_tool_connected ()
+{
+  return wtx_tool_connected (current_wtx_handle) == TRUE;
+}
+
+/* Detach from the target server.  */
+
+int
+wtxapi_tool_detach ()
+{
+  return wtx_tool_detach (current_wtx_handle) != WTX_ERROR;
+}
+
+/* Clear any error for the tool.  */
+
+int
+wtxapi_err_clear ()
+{
+  return wtx_err_clear (current_wtx_handle) != WTX_ERROR;
+}
+
+/* Return the last error for a handle.  */
+
+WTX_ERROR_T
+wtxapi_err_get ()
+{
+  return wtx_err_get (current_wtx_handle);
+}
+
+/* Add an error handler.  */
+
+WTX_HANDLER_T
+wtxapi_err_handler_add (WTX_HANDLER_FUNC p_func, void *p_client_data)
+{
+  return wtx_err_handler_add (current_wtx_handle, p_func, p_client_data);
+}
+
+/* Remove error handler for WTX handle.  */
+
+int
+wtxapi_err_handler_remove (WTX_HANDLER_T p_handler)
+{
+  return wtx_err_handler_remove (current_wtx_handle, p_handler) != WTX_ERROR;
+}
+
+/* Fetch last WTX API error string.  */
+
+const char *
+wtxapi_err_msg_get ()
+{
+  if (current_wtx_handle == 0)
+    return "Invalid WTX handle";
+  else
+    return wtx_err_msg_get (current_wtx_handle);
+}
+
+/* Get agent mode.  */
+
+WTX_AGENT_MODE_TYPE
+wtxapi_agent_mode_get ()
+{
+  return wtx_agent_mode_get (current_wtx_handle);
+}
+
+/* Set the mode of the target agent.  */
+
+int
+wtxapi_agent_mode_set (WTX_AGENT_MODE_TYPE agent_mode)
+{
+  return wtx_agent_mode_set (current_wtx_handle, agent_mode) != WTX_ERROR;
+}
+
+/* Create a new breakpoint.  */
+
+evtpt_id_t
+wtxapi_breakpoint_add (WTX_CONTEXT_TYPE context_type,
+                       WTX_CONTEXT_ID_T context_id, wtxapi_tgt_addr_t tgt_addr)
+{
+  WTX_CONTEXT context;
+  initialize_context (&context, context_type, context_id);
+  return wtx_breakpoint_add (current_wtx_handle,
+                             MARSHALL_WTX_CONTEXT_PARAM (context), tgt_addr);
+}
+
+/* Create a new event point.  */
+
+evtpt_id_t
+wtxapi_eventpoint_add (struct wtxapi_evtpt *p_evtpt)
+{
+#if WTX_PROT_VERSION != 2
+  WTX_EVTPT wtx_evtpt;
+#else
+  WTX_EVTPT_2 wtx_evtpt;
+#endif
+  memset (&wtx_evtpt, 0, sizeof (wtx_evtpt));
+  wtx_evtpt.event.eventType = p_evtpt->event.event_type;
+  wtx_evtpt.event.numArgs = p_evtpt->event.num_args;
+  wtx_evtpt.event.args = p_evtpt->event.args;
+  wtx_evtpt.context.contextType = p_evtpt->context.context_type;
+
+  /* In WTX 4.1, WTX_CONTEXT_ANY_TASK does not work if the context ID
+     is not null; in the previous versions, it is simply ignored; so
+     unconditionally set the context ID to zero in the "any task"
+     case.  */
+  if (p_evtpt->context.context_type == WTX_CONTEXT_ANY_TASK)
+    wtx_evtpt.context.contextId = 0;
+  else
+    wtx_evtpt.context.contextId = p_evtpt->context.context_id;
+
+  wtx_evtpt.action.actionType = p_evtpt->action.action_type;
+  wtx_evtpt.action.actionArg = p_evtpt->action.action_arg;
+  wtx_evtpt.action.callRtn = p_evtpt->action.call_rtn;
+  wtx_evtpt.action.callArg = p_evtpt->action.call_arg;
+  return wtx_eventpoint_add (current_wtx_handle, &wtx_evtpt);
+}
+
+/* Delete eventpoint from the target.  */
+
+int
+wtxapi_eventpoint_delete (evtpt_id_t evtpt_id)
+{
+  return wtx_eventpoint_delete (current_wtx_handle, evtpt_id) != WTX_ERROR;
+}
+
+/* Parse a CTX_EXIT event string, and return the associated EVENT.  */
+
+static void
+wtxapi_parse_ctx_exit_event  (char *event_str,
+                              struct wtxapi_ctx_exit_event *event)
+{
+  char *context_id_str = NULL;
+  char *context_type_str = NULL;
+  char *exit_code_str = NULL;
+
+  if (WTX_PROT_VERSION > 3)
+    {
+      /* Format: "Context_Type Context_ID xxx Exit_Code..."
+         (where "xxx" is a field that we can ignore).  */
+      event_str = get_space_delimited_token (event_str, &context_type_str);
+      event_str = get_space_delimited_token (event_str, &context_id_str);
+      event_str = skip_space_delimited_token (event_str);
+      event_str = get_space_delimited_token (event_str, &exit_code_str);
+    }
+  else
+    {
+      /* Format: "Context_Type Context_ID Exit_Code".  */
+      event_str = get_space_delimited_token (event_str, &context_type_str);
+      event_str = get_space_delimited_token (event_str, &context_id_str);
+      event_str = get_space_delimited_token (event_str, &exit_code_str);
+    }
+
+  event->context_id = wtxapi_str_to_context_id (context_id_str);
+  event->context_type = wtxapi_str_to_context_type (context_type_str);
+  event->exit_code = wtxapi_str_to_int32 (exit_code_str);
+
+  wtx_opt_events_debug (1, "CTX_EXIT: "
+                          "context_id = \"%s\" 0x%lx, "
+                          "context_type = \"%s\" %d, "
+                          "exit_code = \"%s\" %d",
+                        context_id_str, event->context_id,
+                        context_type_str, event->context_type,
+                        exit_code_str, event->exit_code);
+  xfree (context_id_str);
+  xfree (context_type_str);
+  xfree (exit_code_str);
+
+}
+
+/* Parse a DATA_ACCESS event string, and return the associated EVENT.  */
+
+static void
+wtxapi_parse_data_access_event (char *event_str,
+                                struct wtxapi_data_access_event *event)
+{
+  char *task_id_str = NULL;
+  char *context_id_str = NULL;
+  char *context_type_str = NULL;
+  char *data_addr_str = NULL;
+
+  /* The formatting of the DATA_ACCESS event depends on the WTX
+     protocol version.  Extract each of the appropriate field
+     and discard the others.  */
+
+  if (WTX_PROT_VERSION == 2)
+    {
+      /* Format: "Task_ID/Context_ID Context_Type xxx xxx xxx Data_Addr..."
+         (where "xxx" is a field that we can ignore, and the Task_ID and
+         Context_ID are identical).  */
+      event_str = get_space_delimited_token (event_str, &task_id_str);
+      event_str = get_space_delimited_token (event_str, &context_type_str);
+      event_str = skip_space_delimited_token (event_str);
+      event_str = skip_space_delimited_token (event_str);
+      event_str = skip_space_delimited_token (event_str);
+      event_str = get_space_delimited_token (event_str, &data_addr_str);
+      context_id_str = xstrdup (task_id_str);
+    }
+  else if (WTX_PROT_VERSION == 3)
+    {
+      /* Format: "Context_ID Context_Type xxx xxx xxx Data_Addr Task_ID ..."
+         (where "xxx" is a field that we can ignore).  */
+      event_str = get_space_delimited_token (event_str, &context_id_str);
+      event_str = get_space_delimited_token (event_str, &context_type_str);
+      event_str = skip_space_delimited_token (event_str);
+      event_str = skip_space_delimited_token (event_str);
+      event_str = skip_space_delimited_token (event_str);
+      event_str = get_space_delimited_token (event_str, &data_addr_str);
+      event_str = get_space_delimited_token (event_str, &task_id_str);
+    }
+  else
+    {
+      /* Format: "xxx Context_Type Context_ID xxx xxx Task_ID xxx
+                 xxx xxx xxx Data_Addr"
+         (where "xxx" is a field that we can ignore).  */
+      event_str = skip_space_delimited_token (event_str);
+      event_str = get_space_delimited_token (event_str, &context_type_str);
+      event_str = get_space_delimited_token (event_str, &context_id_str);
+      event_str = skip_space_delimited_token (event_str);
+      event_str = skip_space_delimited_token (event_str);
+      event_str = get_space_delimited_token (event_str, &task_id_str);
+      event_str = skip_space_delimited_token (event_str);
+      event_str = skip_space_delimited_token (event_str);
+      event_str = skip_space_delimited_token (event_str);
+      event_str = skip_space_delimited_token (event_str);
+      event_str = get_space_delimited_token (event_str, &data_addr_str);
+    }
+
+  event->task_id = wtxapi_str_to_context_id (task_id_str);
+  event->context_id = wtxapi_str_to_context_id (context_id_str);
+  event->context_type = wtxapi_str_to_context_type (context_type_str);
+  event->data_addr = wtxapi_str_to_tgt_addr (data_addr_str);
+
+  wtx_opt_events_debug (1, "DATA_ACCESS: "
+                          "task_id = \"%s\" 0x%lx, "
+                          "context_id = \"%s\" 0x%lx, "
+                          "context_type = \"%s\" %d, "
+                          "data_addr = \"%s\" 0x%s",
+                        task_id_str, event->task_id,
+                        context_id_str, event->context_id,
+                        context_type_str, event->context_type,
+                        data_addr_str,
+                        paddress (target_gdbarch, event->data_addr));
+  xfree (task_id_str);
+  xfree (context_id_str);
+  xfree (context_type_str);
+  xfree (data_addr_str);
+}
+
+/* Parse an EXCEPTION event string, and return the associated EVENT.  */
+
+static void
+wtxapi_parse_exception_event (char *event_str,
+                              struct wtxapi_exception_event *event)
+{
+  char *context_id_str = NULL;
+  char *context_type_str = NULL;
+  char *exception_value_str = NULL;
+
+  /* The formatting of the EXCEPTION event depends on the WTX
+     protocol version.  Extract each of the appropriate field
+     and discard the others.  */
+
+  if (WTX_PROT_VERSION < 4)
+    {
+      /* Format: "Context_Type Context_ID ...".  */
+      event_str = get_space_delimited_token (event_str, &context_type_str);
+      event_str = get_space_delimited_token (event_str, &context_id_str);
+      event_str = get_space_delimited_token (event_str, &exception_value_str);
+    }
+  else
+    {
+      /* Format: "xxx xxx xxx xxx Context_Type Context_ID xxx Data_Addr ..."
+         (where "xxx" are fields we can ignore).  */
+      event_str = skip_space_delimited_token (event_str);
+      event_str = skip_space_delimited_token (event_str);
+      event_str = skip_space_delimited_token (event_str);
+      event_str = skip_space_delimited_token (event_str);
+      event_str = get_space_delimited_token (event_str, &context_type_str);
+      event_str = get_space_delimited_token (event_str, &context_id_str);
+      event_str = skip_space_delimited_token (event_str);
+      event_str = get_space_delimited_token (event_str, &exception_value_str);
+    }
+
+  event->context_id = wtxapi_str_to_context_id (context_id_str);
+  event->context_type = wtxapi_str_to_context_type (context_type_str);
+  event->exception_value = wtxapi_str_to_tgt_addr (exception_value_str);
+  
+  wtx_opt_events_debug (1, "EXCEPTION: "
+                          "context_id = \"%s\" 0x%lx, "
+                          "context_type = \"%s\" %d, "
+                          "exception_value = \"%s\" %s",
+                        context_id_str, event->context_id,
+                        context_type_str, event->context_type,
+                        exception_value_str,
+                        hex_string (event->exception_value));
+  xfree (context_id_str);
+  xfree (context_type_str);
+}
+
+/* Parse an OBJ_LOADED event string, and return the associated EVENT.  */
+
+static void
+wtxapi_parse_obj_loaded_event (char *event_str,
+                               struct wtxapi_obj_loaded_event *event)
+{
+  char *module_id_str = NULL;
+
+  /* Format: "Module_Id Module_Name [...]", but we only need
+     the module ID.  */
+  event_str = get_space_delimited_token (event_str, &module_id_str);
+  event->module_id = wtxapi_str_to_int32 (module_id_str);
+
+  wtx_opt_events_debug (1, "OBJ_LOADED: module_id_str = \"%s\" 0x%x",
+                        module_id_str, event->module_id);
+
+  xfree (module_id_str);
+}
+
+/* Parse an OBJ_UNLOADED event string, and return the associated EVENT.  */
+
+static void
+wtxapi_parse_obj_unloaded_event (char *event_str,
+                                 struct wtxapi_obj_unloaded_event *event)
+{
+  /* Format: "Module_Id Module_Name [...]", but we only need
+     the module filename.  */
+  event_str = skip_space_delimited_token (event_str);
+  event_str = get_space_delimited_token (event_str, &event->module_filename);
+
+  wtx_opt_events_debug (1, "OBJ_LOADED: module_filename = \"%s\"",
+                        event->module_filename);
+}
+
+/* Parse a TEXT_ACCESS event string, and return the associated EVENT.  */
+
+static void
+wtxapi_parse_text_access_event (char *event_str,
+                                struct wtxapi_text_access_event *event)
+{
+  char *task_id_str = NULL;
+  char *context_id_str = NULL;
+  char *context_type_str = NULL;
+  char *text_addr_str = NULL;
+
+  /* The formatting of the TEXT_ACCESS event depends on the WTX
+     protocol version.  Extract each of the appropriate field
+     and discard the others.  */
+
+  if (WTX_PROT_VERSION == 2)
+    {
+      /* Format: "Task_ID/Context_ID Context_Type Text_Addr ..."
+         (the Task_ID and Context_ID are equal).  */
+      event_str = get_space_delimited_token (event_str, &task_id_str);
+      event_str = get_space_delimited_token (event_str, &context_type_str);
+      event_str = get_space_delimited_token (event_str, &text_addr_str);
+      context_id_str = xstrdup (task_id_str);
+    }
+  else if (WTX_PROT_VERSION == 3)
+    {
+      /* Format: "Context_ID Context_Type Text_Addr xxx xxx Task_ID ..."
+         (where "xxx" is a field that we can ignore).  */
+      event_str = get_space_delimited_token (event_str, &context_id_str);
+      event_str = get_space_delimited_token (event_str, &context_type_str);
+      event_str = get_space_delimited_token (event_str, &text_addr_str);
+      event_str = skip_space_delimited_token (event_str);
+      event_str = skip_space_delimited_token (event_str);
+      event_str = get_space_delimited_token (event_str, &task_id_str);
+    }
+  else
+    {
+      /* Format: "xxx Context_Type Context_ID xxx xxx Task_ID xxx Text_Addr..."
+         (where "xxx" is a field that we can ignore).  */
+      event_str = skip_space_delimited_token (event_str);
+      event_str = get_space_delimited_token (event_str, &context_type_str);
+      event_str = get_space_delimited_token (event_str, &context_id_str);
+      event_str = skip_space_delimited_token (event_str);
+      event_str = skip_space_delimited_token (event_str);
+      event_str = get_space_delimited_token (event_str, &task_id_str);
+      event_str = skip_space_delimited_token (event_str);
+      event_str = get_space_delimited_token (event_str, &text_addr_str);
+    }
+
+  /* With WTX version 3 and later and when in system mode, the task ID
+     in the event string is apparently not the ID we are looking for.
+     Get the current task ID differently.  */
+  /* brobecker/2007-08-31: Not sure what the wrong task ID could be.
+     So, for now, do nothing special; enhance later if we find some
+     evidence that it is necessary.  */
+
+  event->task_id = wtxapi_str_to_context_id (task_id_str);
+  event->context_id = wtxapi_str_to_context_id (context_id_str);
+  event->context_type = wtxapi_str_to_context_type (context_type_str);
+  event->text_addr = wtxapi_str_to_tgt_addr (text_addr_str);
+
+  wtx_opt_events_debug (1, "TEXT_ACCESS: "
+                          "task_id = \"%s\" 0x%lx, "
+                          "context_id = \"%s\" 0x%lx, "
+                          "context_type = \"%s\" %d, "
+                          "text_addr = \"%s\" 0x%s",
+                        task_id_str, event->task_id,
+                        context_id_str, event->context_id,
+                        context_type_str, event->context_type,
+                        text_addr_str,
+                        paddress (target_gdbarch, event->text_addr));
+
+  xfree (task_id_str);
+  xfree (context_id_str);
+  xfree (context_type_str);
+  xfree (text_addr_str);
+}
+
+/* Parse a VIO_WRITE event string, the given DATA and its associated
+   DATA_LEN, and return the corresponding EVENT.  */
+
+static void
+wtxapi_parse_vio_write_event (char *event_str, char *data, int data_len,
+                              struct wtxapi_vio_write_event *event)
+{
+  char *channel_id_str = NULL;
+
+  /* Format: "Channel_Id".  The rest of the information is
+     inside the additional_data.  */
+  event_str = get_space_delimited_token (event_str, &channel_id_str);
+
+  event->channel_id = atoi (event_str);
+
+  event->data = xmalloc ((data_len + 1) * sizeof (char));
+  strncpy (event->data, data, data_len);
+  event->data[data_len] = '\0';
+
+  wtx_opt_events_debug (1, "VIO_WRITE: "
+                          "channel_id = \"%s\" %d, "
+                          "data = \"%s\"",
+                        channel_id_str, event->channel_id,
+                        event->data);
+
+  xfree (channel_id_str);
+}
+
+
+/* Get the next event from the event queue if one is available.
+   Return NULL otherwise.
+   
+   The new event must be deallocated after use.  */
+
+struct wtxapi_event_desc *
+wtxapi_event_get (void)
+{
+  WTX_EVENT_DESC *event_desc = wtx_event_get (current_wtx_handle);
+  char *event_str;
+  char *token = NULL;
+  struct wtxapi_event_desc *result;
+
+  if (event_desc == NULL)
+    return NULL;
+  if (event_desc->event == NULL)
+    {
+      /* That's kind of dumb, but it actually happens.  */
+      wtx_result_free (current_wtx_handle, event_desc);
+      return NULL;
+    }
+
+  wtx_opt_events_debug (2, "wtxapi_event_get: \"%s\"", event_desc->event);
+
+  result = xmalloc (sizeof (struct wtxapi_event_desc));
+
+  /* Get the event type from the first token in the event string.  */
+  event_str = event_desc->event;
+  event_str = get_space_delimited_token (event_str, &token);
+  result->event_type = wtxapi_str_to_event_type (token);
+  xfree (token);
+
+  switch (result->event_type)
+    {
+      case WTX_EVENT_CTX_EXIT:
+        wtxapi_parse_ctx_exit_event (event_str, &result->desc.ctx_exit);
+        break;
+
+      case WTX_EVENT_DATA_ACCESS:
+        wtxapi_parse_data_access_event (event_str, &result->desc.data_access);
+        break;
+
+      case WTX_EVENT_EXCEPTION:
+        wtxapi_parse_exception_event (event_str, &result->desc.exception);
+        break;
+
+      case WTX_EVENT_OBJ_LOADED:
+        wtxapi_parse_obj_loaded_event (event_str, &result->desc.obj_loaded);
+        break;
+
+      case WTX_EVENT_OBJ_UNLOADED:
+        wtxapi_parse_obj_unloaded_event (event_str,
+                                         &result->desc.obj_unloaded);
+        break;
+
+      case WTX_EVENT_TEXT_ACCESS:
+        wtxapi_parse_text_access_event (event_str, &result->desc.text_access);
+        break;
+
+      case WTX_EVENT_VIO_WRITE:
+        wtxapi_parse_vio_write_event (event_str,
+                                      event_desc->addlData,
+                                      event_desc->addlDataLen,
+                                      &result->desc.vio_write);
+        break;
+
+      case WTX_EVENT_EVTPT_ADDED:
+      case WTX_EVENT_EVTPT_DELETED:
+        /* We do not handle eventpoints added/removed by other tools.
+           So ignore these events by falling back to the "default" case.  */
+      default:
+        /* Ignore this event.  */
+        xfree (result);
+        result = NULL;
+        break;
+    }
+
+  wtx_result_free (current_wtx_handle, event_desc);
+  return result;
+}
+
+WTX_CONTEXT_STATUS
+wtxapi_context_status_get (WTX_CONTEXT_TYPE context_type,
+                           WTX_CONTEXT_ID_T context_id)
+{
+  WTX_CONTEXT context;
+  initialize_context (&context, context_type, context_id);
+  return wtx_context_status_get (current_wtx_handle,
+                                 MARSHALL_WTX_CONTEXT_PARAM (context));
+}
+
+
+/* Continue execution of target context.  */
+
+int
+wtxapi_context_cont (WTX_CONTEXT_TYPE context_type,
+                     WTX_CONTEXT_ID_T context_id)
+{
+  WTX_CONTEXT context;
+  initialize_context (&context, context_type, context_id);
+  return wtx_context_cont (current_wtx_handle,
+                           MARSHALL_WTX_CONTEXT_PARAM (context)) != WTX_ERROR;
+}
+
+/* Create a context on target.  */
+
+WTX_CONTEXT_ID_T
+wtxapi_context_create (struct wtxapi_context_desc *p_context_desc)
+{
+  int ix;
+  WTX_CONTEXT_DESC context_desc;
+  memset (&context_desc, 0, sizeof (context_desc));
+#if WTX_PROT_VERSION != 2
+  context_desc.wtxContextType = p_context_desc->context_type;
+
+  if (p_context_desc->context_type == WTX_CONTEXT_PD)
+    {
+      context_desc.wtxContextDef.wtxPdContextDef.name =
+        p_context_desc->wtx_context_def.pd_context.name;
+      context_desc.wtxContextDef.wtxPdContextDef.options =
+        p_context_desc->wtx_context_def.pd_context.options;
+      context_desc.wtxContextDef.wtxPdContextDef.heapSize =
+        p_context_desc->wtx_context_def.pd_context.heap_size;
+      context_desc.wtxContextDef.wtxPdContextDef.lowPriority =
+        p_context_desc->wtx_context_def.pd_context.low_priority;
+      context_desc.wtxContextDef.wtxPdContextDef.highPriority =
+        p_context_desc->wtx_context_def.pd_context.high_priority;
+      context_desc.wtxContextDef.wtxPdContextDef.pagePoolList =
+        p_context_desc->wtx_context_def.pd_context.page_pool_list;
+      context_desc.wtxContextDef.wtxPdContextDef.destroyRtn =
+        p_context_desc->wtx_context_def.pd_context.destroy_rtn;
+      context_desc.wtxContextDef.wtxPdContextDef.linkPath =
+        p_context_desc->wtx_context_def.pd_context.link_path;
+      context_desc.wtxContextDef.wtxPdContextDef.redirIn =
+        p_context_desc->wtx_context_def.pd_context.redir_in;
+      context_desc.wtxContextDef.wtxPdContextDef.redirOut =
+        p_context_desc->wtx_context_def.pd_context.redir_out;
+      context_desc.wtxContextDef.wtxPdContextDef.redirErr =
+        p_context_desc->wtx_context_def.pd_context.redir_err;
+      context_desc.wtxContextDef.wtxPdContextDef.argc =
+        p_context_desc->wtx_context_def.pd_context.argc;
+      context_desc.wtxContextDef.wtxPdContextDef.argv =
+        p_context_desc->wtx_context_def.pd_context.argv;
+    }
+  else
+    {
+      context_desc.wtxContextDef.wtxTaskContextDef.pdId =
+        p_context_desc->wtx_context_def.task_context.pd_id;
+      context_desc.wtxContextDef.wtxTaskContextDef.returnType =
+        p_context_desc->wtx_context_def.task_context.return_type;
+      context_desc.wtxContextDef.wtxTaskContextDef.name =
+        p_context_desc->wtx_context_def.task_context.name;
+      context_desc.wtxContextDef.wtxTaskContextDef.priority =
+        p_context_desc->wtx_context_def.task_context.priority;
+      context_desc.wtxContextDef.wtxTaskContextDef.options =
+        p_context_desc->wtx_context_def.task_context.options;
+      context_desc.wtxContextDef.wtxTaskContextDef.stackBase =
+        p_context_desc->wtx_context_def.task_context.stack_base;
+      context_desc.wtxContextDef.wtxTaskContextDef.stackSize =
+        p_context_desc->wtx_context_def.task_context.stack_size;
+      context_desc.wtxContextDef.wtxTaskContextDef.entry =
+        p_context_desc->wtx_context_def.task_context.entry;
+      context_desc.wtxContextDef.wtxTaskContextDef.redirIn =
+        p_context_desc->wtx_context_def.task_context.redir_in;
+      context_desc.wtxContextDef.wtxTaskContextDef.redirOut =
+        p_context_desc->wtx_context_def.task_context.redir_out;
+      context_desc.wtxContextDef.wtxTaskContextDef.redirErr =
+        p_context_desc->wtx_context_def.task_context.redir_err;
+      context_desc.wtxContextDef.wtxTaskContextDef.argc =
+        p_context_desc->wtx_context_def.task_context.argc;
+      context_desc.wtxContextDef.wtxTaskContextDef.argv =
+        p_context_desc->wtx_context_def.task_context.argv;
+    }
+
+#else
+
+  /* In WTX 2.0, we cannot create a new PD.  */
+
+  if (p_context_desc->context_type == WTX_CONTEXT_PD)
+    return invalid_context_id;
+
+  context_desc.contextType = p_context_desc->context_type;
+  context_desc.returnType =
+    p_context_desc->wtx_context_def.task_context.return_type;
+  context_desc.name = p_context_desc->wtx_context_def.task_context.name;
+  context_desc.priority =
+    p_context_desc->wtx_context_def.task_context.priority;
+  context_desc.options = p_context_desc->wtx_context_def.task_context.options;
+  context_desc.stackBase =
+    p_context_desc->wtx_context_def.task_context.stack_base;
+  context_desc.stackSize =
+    p_context_desc->wtx_context_def.task_context.stack_size;
+  context_desc.entry = p_context_desc->wtx_context_def.task_context.entry;
+  context_desc.redirIn = p_context_desc->wtx_context_def.task_context.redir_in;
+  context_desc.redirOut =
+    p_context_desc->wtx_context_def.task_context.redir_out;
+  for (ix = 0; ix < WTX_MAX_ARG_CNT; ix++)
+    if (ix < p_context_desc->wtx_context_def.task_context.argc)
+      context_desc.args[ix] =
+        p_context_desc->wtx_context_def.task_context.argv[ix];
+    else
+      context_desc.args[ix] = NULL_PD;
+#endif
+  return wtx_context_create (current_wtx_handle, &context_desc);
+}
+
+/* Resume execution of a target context.  */
+
+int
+wtxapi_context_resume (WTX_CONTEXT_TYPE context_type,
+                       WTX_CONTEXT_ID_T context_id)
+{
+  WTX_CONTEXT context;
+  initialize_context (&context, context_type, context_id);
+  return wtx_context_resume (current_wtx_handle,
+                             MARSHALL_WTX_CONTEXT_PARAM (context))
+    != WTX_ERROR;
+}
+
+/* Add exit evpt notification.  */
+
+evtpt_id_t
+wtxapi_context_exit_notify_add (WTX_CONTEXT_TYPE context_type,
+                                WTX_CONTEXT_ID_T context_id)
+{
+  WTX_CONTEXT context;
+  initialize_context (&context, context_type, context_id);
+  return wtx_context_exit_notify_add (current_wtx_handle,
+                                      MARSHALL_WTX_CONTEXT_PARAM (context));
+}
+
+/* Kill a target context.  */
+
+int
+wtxapi_context_kill (WTX_CONTEXT_TYPE context_type,
+                     WTX_CONTEXT_ID_T context_id)
+{
+  WTX_CONTEXT context;
+  initialize_context (&context, context_type, context_id);
+#if WTX_PROT_VERSION != 2
+  return wtx_context_kill (current_wtx_handle,
+                           MARSHALL_WTX_CONTEXT_PARAM (context),
+                           WTX_PD_DELETE_OPTION_NONE) != WTX_ERROR;
+#else
+  return wtx_context_kill (current_wtx_handle,
+                           MARSHALL_WTX_CONTEXT_PARAM (context)) != WTX_ERROR;
+#endif
+}
+
+/* Single step exec of target context.  */
+
+int
+wtxapi_context_step (WTX_CONTEXT_TYPE context_type,
+                     WTX_CONTEXT_ID_T context_id, wtxapi_tgt_addr_t step_start,
+                     wtxapi_tgt_addr_t step_end)
+{
+  WTX_CONTEXT context;
+  initialize_context (&context, context_type, context_id);
+  return wtx_context_step (current_wtx_handle,
+                           MARSHALL_WTX_CONTEXT_PARAM (context),
+                           step_start, step_end) != WTX_ERROR;
+}
+
+/* Suspend a target context.  */
+
+int
+wtxapi_context_suspend (WTX_CONTEXT_TYPE context_type,
+                        WTX_CONTEXT_ID_T context_id)
+{
+  WTX_CONTEXT context;
+  initialize_context (&context, context_type, context_id);
+  return wtx_context_suspend (current_wtx_handle,
+                              MARSHALL_WTX_CONTEXT_PARAM (context))
+    != WTX_ERROR;
+}
+
+int
+wtxapi_context_stop (WTX_CONTEXT_TYPE context_type,
+                     WTX_CONTEXT_ID_T context_id)
+{
+  WTX_CONTEXT context;
+  initialize_context (&context, context_type, context_id);
+
+#if WTX_PROT_VERSION != 2
+  return wtx_context_stop (current_wtx_handle,
+                           MARSHALL_WTX_CONTEXT_PARAM (context)) != WTX_ERROR;
+#else
+  /* FIXME : wtxContextStop does not exist on WTX 2.0.  For now, use
+     wtxContextSuspend as a workaround.  */
+
+  return wtx_context_suspend (current_wtx_handle,
+                              MARSHALL_WTX_CONTEXT_PARAM (context))
+    != WTX_ERROR;
+#endif
+}
+
+/* List event points on TS.  */
+
+struct wtxapi_evtpt_list *
+wtxapi_eventpoint_list_get ()
+{
+  int ix;
+  struct wtxapi_evtpt_list *evtpt_list;
+  wtx_evtpt_list *wtx_list;
+  wtx_list = wtx_eventpoint_list_get (current_wtx_handle);
+
+  if (!wtx_list)
+    return NULL;
+
+  evtpt_list = (struct wtxapi_evtpt_list *)
+    xmalloc (sizeof (struct wtxapi_evtpt_list));
+  evtpt_list->n_evtpt = wtx_list->nEvtpt;
+  evtpt_list->p_evtpt_info = (struct wtxapi_evtpt_info *)
+    xmalloc (sizeof (struct wtxapi_evtpt_info) * wtx_list->nEvtpt);
+  for (ix = 0; ix < wtx_list->nEvtpt; ix++)
+    {
+      evtpt_list->p_evtpt_info[ix].wtx_evtpt.event.event_type =
+        wtx_list->pEvtptInfo[ix].wtxEvtpt.event.eventType;
+      evtpt_list->p_evtpt_info[ix].wtx_evtpt.event.num_args =
+        wtx_list->pEvtptInfo[ix].wtxEvtpt.event.numArgs;
+      evtpt_list->p_evtpt_info[ix].wtx_evtpt.event.args = (wtxapi_tgt_arg_t *)
+        xmalloc (wtx_list->pEvtptInfo[ix].wtxEvtpt.event.numArgs *
+                 sizeof (wtxapi_tgt_arg_t));
+      memcpy (evtpt_list->p_evtpt_info[ix].wtx_evtpt.event.args,
+              wtx_list->pEvtptInfo[ix].wtxEvtpt.event.args,
+              wtx_list->pEvtptInfo[ix].wtxEvtpt.event.numArgs *
+              sizeof (wtxapi_tgt_arg_t));
+      evtpt_list->p_evtpt_info[ix].wtx_evtpt.context.context_type =
+        wtx_list->pEvtptInfo[ix].wtxEvtpt.context.contextType;
+      evtpt_list->p_evtpt_info[ix].wtx_evtpt.context.context_id =
+        wtx_list->pEvtptInfo[ix].wtxEvtpt.context.contextId;
+      evtpt_list->p_evtpt_info[ix].wtx_evtpt.action.action_type =
+        wtx_list->pEvtptInfo[ix].wtxEvtpt.action.actionType;
+      evtpt_list->p_evtpt_info[ix].wtx_evtpt.action.action_arg =
+        wtx_list->pEvtptInfo[ix].wtxEvtpt.action.actionArg;
+      evtpt_list->p_evtpt_info[ix].wtx_evtpt.action.call_rtn =
+        wtx_list->pEvtptInfo[ix].wtxEvtpt.action.callRtn;
+      evtpt_list->p_evtpt_info[ix].wtx_evtpt.action.call_arg =
+        wtx_list->pEvtptInfo[ix].wtxEvtpt.action.callArg;
+      evtpt_list->p_evtpt_info[ix].tool_id = wtx_list->pEvtptInfo[ix].toolId;
+      evtpt_list->p_evtpt_info[ix].evtpt_num =
+        wtx_list->pEvtptInfo[ix].evtptNum;
+    }
+
+  wtx_result_free (current_wtx_handle, wtx_list);
+  return evtpt_list;
+}
+
+/* Free mem allocated by WTX API call.  */
+
+int
+wtxapi_result_free (void *p_result)
+{
+  return wtx_result_free (current_wtx_handle, p_result) != WTX_ERROR;
+}
+
+/* Evaluate Gopher string on target.  */
+
+WTX_GOPHER_TAPE *
+wtxapi_gopher_eval (pd_id_t pd_id, const char *input_string)
+{
+#if WTX_PROT_VERSION != 2
+  return wtx_gopher_eval (current_wtx_handle, pd_id, input_string);
+#else
+  return wtx_gopher_eval (current_wtx_handle, input_string);
+#endif
+}
+
+/* Get info about memory pool.  */
+
+WTX_MEM_INFO *
+wtxapi_mem_info_get (pd_id_t pd_id)
+{
+#if WTX_PROT_VERSION != 2
+  return wtx_mem_info_get (current_wtx_handle, pd_id);
+#else
+  return wtx_mem_info_get (current_wtx_handle);
+#endif
+}
+
+/* Alloc blocks in memory pool.  */
+
+wtxapi_tgt_addr_t
+wtxapi_mem_alloc (pd_id_t pd_id, int num_bytes)
+{
+#if WTX_PROT_VERSION != 2
+  return wtx_mem_alloc (current_wtx_handle, pd_id, num_bytes);
+#else
+  return wtx_mem_alloc (current_wtx_handle, num_bytes);
+#endif
+}
+
+/* Perform checksum on target memory.  */
+
+int
+wtxapi_mem_checksum (pd_id_t pd_id, wtxapi_tgt_addr_t start_addr,
+                     int num_bytes)
+{
+#if WTX_PROT_VERSION != 2
+  return wtx_mem_checksum (current_wtx_handle, pd_id, start_addr, num_bytes);
+#else
+  return wtx_mem_checksum (current_wtx_handle, start_addr, num_bytes);
+#endif
+}
+
+/* Move a block of target memory.  */
+
+int
+wtxapi_mem_move (pd_id_t src_pd_id, wtxapi_tgt_addr_t src_addr,
+                 pd_id_t dst_pd_id, wtxapi_tgt_addr_t dest_addr, int num_bytes)
+{
+#if WTX_PROT_VERSION != 2
+  return wtx_mem_move (current_wtx_handle, src_pd_id, src_addr, dst_pd_id,
+                       dest_addr, num_bytes) != WTX_ERROR;
+#else
+  return wtx_mem_move (current_wtx_handle, src_addr, dest_addr,
+                       num_bytes) != WTX_ERROR;
+#endif
+}
+
+/* Free a block of target memory.  */
+
+int
+wtxapi_mem_free (pd_id_t pd_id, wtxapi_tgt_addr_t address)
+{
+#if WTX_PROT_VERSION != 2
+  return wtx_mem_free (current_wtx_handle, pd_id, address) != WTX_ERROR;
+#else
+  return wtx_mem_free (current_wtx_handle, address) != WTX_ERROR;
+#endif
+}
+
+/* Read memory from the target.  */
+
+int
+wtxapi_mem_read (pd_id_t pd_id, wtxapi_tgt_addr_t from_addr,
+                 void *to_addr, int num_bytes)
+{
+#if WTX_PROT_VERSION != 2
+  return wtx_mem_read (current_wtx_handle, pd_id, from_addr, to_addr,
+                       num_bytes, 0);
+#else
+  return wtx_mem_read (current_wtx_handle, from_addr, to_addr, num_bytes);
+#endif
+}
+
+/* Read memory on WIDTH bytes.  */
+
+int
+wtxapi_mem_width_read (pd_id_t pd_id, wtxapi_tgt_addr_t from_addr,
+                       void *to_addr, int num_bytes, int width)
+{
+#if WTX_PROT_VERSION != 2
+  return wtx_mem_width_read (current_wtx_handle, pd_id, from_addr, to_addr,
+                             num_bytes, width, 0);
+#else
+  return wtx_mem_width_read (current_wtx_handle, from_addr, to_addr, num_bytes,
+                             width);
+#endif
+}
+
+/* Write memory on the target.  */
+
+int
+wtxapi_mem_write (pd_id_t pd_id, void *from_addr,
+                  wtxapi_tgt_addr_t to_addr, int num_bytes)
+{
+#if WTX_PROT_VERSION != 2
+  return wtx_mem_write (current_wtx_handle, pd_id, from_addr, to_addr,
+                        num_bytes, 0);
+#else
+  return wtx_mem_write (current_wtx_handle, from_addr, to_addr, num_bytes);
+#endif
+}
+
+/* Write memory on the target on WIDTH bytes large.  */
+
+int
+wtxapi_mem_width_write (pd_id_t pd_id, void *from_addr,
+                        wtxapi_tgt_addr_t to_addr, int num_bytes, int width)
+{
+#if WTX_PROT_VERSION != 2
+  return wtx_mem_width_write (current_wtx_handle, pd_id, from_addr, to_addr,
+                              num_bytes, width, 0);
+#else
+  return wtx_mem_width_write (current_wtx_handle, from_addr, to_addr,
+                              num_bytes, width);
+#endif
+}
+
+/* Set target memory to given value.  */
+
+int
+wtxapi_mem_set (pd_id_t pd_id, wtxapi_tgt_addr_t addr, int num_bytes, int val)
+{
+#if WTX_PROT_VERSION != 2
+  return wtx_mem_set (current_wtx_handle, pd_id, addr, num_bytes, val);
+#else
+  return wtx_mem_set (current_wtx_handle, addr, num_bytes, val);
+#endif
+}
+
+/* Add memory to the agent pool.  */
+
+int
+wtxapi_mem_add_to_pool (pd_id_t pd_id, wtxapi_tgt_addr_t address, int size)
+{
+#if WTX_PROT_VERSION != 2
+  return wtx_mem_add_to_pool (current_wtx_handle, pd_id, address,
+                              size) != WTX_ERROR;
+#else
+  return wtx_mem_add_to_pool (current_wtx_handle, address, size) != WTX_ERROR;
+#endif
+}
+
+/* Reallocate a block of target mem.  */
+
+wtxapi_tgt_addr_t
+wtxapi_mem_realloc (pd_id_t pd_id, wtxapi_tgt_addr_t address, int num_bytes)
+{
+#if WTX_PROT_VERSION != 2
+  return wtx_mem_realloc (current_wtx_handle, pd_id, address, num_bytes);
+#else
+  return wtx_mem_realloc (current_wtx_handle, address, num_bytes);
+#endif
+}
+
+/* Allocate aligned target memory.  */
+
+wtxapi_tgt_addr_t
+wtxapi_mem_align (pd_id_t pd_id, wtxapi_tgt_addr_t alignment, int num_bytes)
+{
+#if WTX_PROT_VERSION != 2
+  return wtx_mem_align (current_wtx_handle, pd_id, alignment, num_bytes);
+#else
+  return wtx_mem_align (current_wtx_handle, alignment, num_bytes);
+#endif
+}
+
+/* Scan target memory for pattern.  */
+
+int
+wtxapi_mem_scan (pd_id_t pd_id, int match, wtxapi_tgt_addr_t start_addr,
+                 wtxapi_tgt_addr_t end_addr, int num_bytes, void *pattern,
+                 wtxapi_tgt_addr_t * p_result)
+{
+#if WTX_PROT_VERSION != 2
+  return wtx_mem_scan (current_wtx_handle, pd_id, TO_BOOL (match), start_addr,
+                       end_addr, num_bytes, pattern, p_result) != WTX_ERROR;
+#else
+  return wtx_mem_scan (current_wtx_handle, TO_BOOL (match), start_addr,
+                       end_addr, num_bytes, pattern, p_result) != WTX_ERROR;
+#endif
+}
+
+/* Checks validity of target memory.  */
+
+int
+wtxapi_obj_module_checksum (pd_id_t pd_id, module_id_t module_id,
+                            char *module_name)
+{
+#if WTX_PROT_VERSION != 2
+  return wtx_obj_module_checksum (current_wtx_handle, pd_id, module_id,
+                                  module_name) != WTX_ERROR;
+#else
+  return wtx_obj_module_checksum (current_wtx_handle, module_id,
+                                  module_name) != WTX_ERROR;
+#endif
+}
+
+/* Find obj module ID from name.  */
+
+module_id_t
+wtxapi_obj_module_find_id (pd_id_t pd_id, const char *module_name)
+{
+  module_id_t module_id;
+#if WTX_PROT_VERSION != 2
+  module_id = wtx_obj_module_find_id (current_wtx_handle, pd_id, module_name);
+#else
+  module_id = wtx_obj_module_find_id (current_wtx_handle, module_name);
+#endif
+  return module_id;
+}
+
+module_id_t
+wtxapi_obj_module_in_system_find_id (const char *module_name)
+{
+#if WTX_PROT_VERSION != 2
+  const pd_id_t current_pd = wtxapi_pd_current_get (current_wtx_handle);
+  module_id_t module_id;
+
+  module_id = wtx_obj_module_find_id (current_wtx_handle, current_pd, module_name);
+  if (module_id != WTX_ERROR)
+    return module_id;
+
+  return wtx_obj_module_find_id (current_wtx_handle, WTX_PD_ALL, module_name);
+#else
+  return wtx_obj_module_find_id (current_wtx_handle, module_name);
+#endif
+}
+
+/* Find module name given its ID.  */
+
+const char *
+wtxapi_obj_module_find_name (pd_id_t pd_id, module_id_t module_id)
+{
+#if WTX_PROT_VERSION != 2
+  return wtx_obj_module_find_name (current_wtx_handle, pd_id, module_id);
+#else
+  return wtx_obj_module_find_name (current_wtx_handle, module_id);
+#endif
+}
+
+/* Allocate a new wtxapi_module_info.  */
+
+static struct wtxapi_module_info *
+new_wtxapi_module_info (WTX_MODULE_INFO *wtx_minfo)
+{
+  int i;
+  struct wtxapi_module_info *module_info;
+
+  if (!wtx_minfo)
+    return NULL;
+
+  module_info = (struct wtxapi_module_info *)
+    xzalloc (sizeof (struct wtxapi_module_info));
+#if WTX_PROT_VERSION != 2
+  module_info->pd_id = wtx_minfo->pdId;
+  module_info->section_addrs = alloc_section_addr_info (wtx_minfo->nSections);
+  for (i = 0; i < wtx_minfo->nSections; i++)
+    {
+      struct other_sections *other = module_info->section_addrs->other + i;
+
+      other->name = xstrdup (wtx_minfo->section[i].name);
+      other->addr = wtx_minfo->section[i].baseAddr;
+      /* brobecker/2007-05-14:  The sectindex should really be set to
+         the same index as the BFD section index.  But accessing the BFD
+         data at this point is not easy, so I am making a bet instead
+         that the BFD index is the same as the WTX section index.  If
+         this assertion turns out to be false, then we'll have to add
+         some fixup code in remote-wtx.c that recomputes all section
+         indexes from BFD.  */
+      other->sectindex = i;
+    }
+  module_info->segments = NULL;
+#else
+  /* On Tornado 2, the system does not give us access to the section
+     addresses, but 3 segment base addresses instead, from which we
+     need to compute the actual section addresses.  Ideally, it would
+     have been nice to compute these addresses at this point, to make
+     the behavior of this function independent of the Tornado version,
+     but the implementation is too awkward (one of the problems we
+     are facing is trying to locate the object file on the host file
+     system, which is something we already do, but sometime later in
+     another part of the code, and using the result from this function).
+     So we just return the segment addresses for now, and let the client
+     deal with the conversion at a more appropriate moment.  */
+  gdb_assert (wtx_minfo->nSegments == 3);
+
+  module_info->pd_id = NULL_PD;
+  module_info->section_addrs = NULL;
+  module_info->segments =
+    (struct segment_addresses *) xmalloc (sizeof (struct segment_addresses));
+  module_info->segments->text_addr = wtx_minfo->segment[0].addr;
+  module_info->segments->data_addr = wtx_minfo->segment[1].addr;
+  module_info->segments->bss_addr = wtx_minfo->segment[2].addr;
+#endif
+  module_info->module_id = wtx_minfo->moduleId;
+  if (wtx_minfo->moduleName)
+    module_info->module_name = xstrdup (wtx_minfo->moduleName);
+  module_info->load_flag = wtx_minfo->loadFlag;
+  module_info->undef_list = NULL;
+  return module_info;
+}
+
+/* Give info on obj module.  */
+
+struct wtxapi_module_info *
+wtxapi_obj_module_info_get (pd_id_t pd_id, module_id_t module_id)
+{
+  struct wtxapi_module_info *module_info;
+  WTX_MODULE_INFO *wtx_minfo;
+#if WTX_PROT_VERSION != 2
+  wtx_minfo = wtx_obj_module_info_get (current_wtx_handle, pd_id, module_id);
+#else
+  wtx_minfo = wtx_obj_module_info_get (current_wtx_handle, module_id);
+#endif
+  if (!wtx_minfo)
+    return NULL;
+
+  module_info = new_wtxapi_module_info (wtx_minfo);
+  wtx_result_free (current_wtx_handle, wtx_minfo);
+  return module_info;
+}
+
+/* List loaded obj modules.  */
+
+struct wtxapi_module_list *
+wtxapi_obj_module_list_get (pd_id_t pd_id)
+{
+  WTX_MODULE_LIST *wtx_mlist;
+  struct wtxapi_module_list *list;
+  int ix = 0;
+#if WTX_PROT_VERSION != 2
+  WTX_MOD_FIND_CRITERIA criteria;
+  WTX_MODULE *current;
+
+  memset (&criteria, 0, sizeof (criteria));
+  criteria.options = WTX_MOD_FIND_ALL;
+  criteria.pdId = pd_id;
+  criteria.moduleId = 0;
+  criteria.moduleName = NULL;
+  criteria.ref = 0;
+
+  wtx_mlist = wtx_obj_module_list_get (current_wtx_handle, &criteria);
+
+  if (!wtx_mlist)
+    return NULL;
+
+  list = (struct wtxapi_module_list *)
+    xmalloc (sizeof (struct wtxapi_module_list));
+
+  /* Note: as the module list is expected to have, say, less than 10
+     elements, the full copy should not take much time.  */
+
+  list->num_obj_mod = 0;
+  for (current = wtx_mlist->pModule; current; current = current->next)
+    list->num_obj_mod++;
+
+  list->mod_id_array = (int *) xmalloc (list->num_obj_mod * sizeof (int));
+  list->pd_id_array = (pd_id_t *)
+    xmalloc (list->num_obj_mod * sizeof (pd_id_t));
+  for (current = wtx_mlist->pModule; current; current = current->next)
+    {
+      list->mod_id_array[ix] = current->moduleId;
+      list->pd_id_array[ix] = current->pdId;
+      ix++;
+    }
+
+#else
+  wtx_mlist = wtx_obj_module_list (current_wtx_handle);
+
+  if (!wtx_mlist)
+    return NULL;
+
+  list = (struct wtxapi_module_list *)
+    xmalloc (sizeof (struct wtxapi_module_list));
+  list->num_obj_mod = wtx_mlist->numObjMod;
+  list->mod_id_array = (int *) xmalloc (list->num_obj_mod * sizeof (int));
+  list->pd_id_array = (pd_id_t *)
+    xmalloc (list->num_obj_mod * sizeof (pd_id_t));
+  for (ix = 0; ix < list->num_obj_mod; ix++)
+    list->mod_id_array[ix] = wtx_mlist->modIdList[ix];
+  memset (list->pd_id_array, 0, list->num_obj_mod * sizeof (pd_id_t));
+#endif
+  wtx_result_free (current_wtx_handle, wtx_mlist);
+  return list;
+}
+
+/* Load a new object module.  */
+
+struct wtxapi_module_info *
+wtxapi_obj_module_load (pd_id_t pd_id, char *filename, int load_flags)
+{
+  struct wtxapi_module_info *minfo;
+  wtx_module_info * wtx_minfo;
+
+#if WTX_PROT_VERSION != 2
+  WTX_MODULE_FILE_DESC wtx_fdesc;
+
+  memset (&wtx_fdesc, 0, sizeof (wtx_fdesc));
+  wtx_fdesc.filename = filename;
+  wtx_fdesc.loadFlag = load_flags;
+
+  wtx_minfo = wtx_obj_module_load (current_wtx_handle, pd_id, &wtx_fdesc,
+                                   WTX_LOAD_FROM_TOOL);
+
+  if (!wtx_minfo)
+    return NULL;
+
+  minfo = new_wtxapi_module_info (wtx_minfo);
+  minfo->undef_list =
+    new_wtxapi_symbol_list_from_symbol (wtx_minfo->undefSymList.pSymbol);
+  if (minfo->undef_list)
+    minfo->undef_list->wtx_result_to_cleanup = (void *) wtx_minfo;
+#else
+  WTX_LD_M_FILE_DESC wtx_fdesc;
+
+  memset (&wtx_fdesc, 0, sizeof (wtx_fdesc));
+  wtx_fdesc.filename = filename;
+  wtx_fdesc.loadFlag = load_flags;
+
+  wtx_minfo = wtx_obj_module_load (current_wtx_handle, &wtx_fdesc);
+
+  if (!wtx_minfo)
+    return NULL;
+  minfo = wtxapi_obj_module_info_get (wtxapi_pd_current_get (),
+                                      wtx_minfo->moduleId);
+  if (minfo->undef_list)
+    minfo->undef_list->wtx_result_to_cleanup = (void *) wtx_minfo;
+#endif
+  return minfo;
+}
+
+/* The same as wtxapi_obj_module_load except that it temporary changes
+   the WTX timeout value to the given TIMEOUT.  
+   
+   Basically, this function changes the WTX timeout to TIMEOUT,
+   calls wtxapi_obj_module_load, and then restores the old timeout.  */
+
+struct wtxapi_module_info *
+wtxapi_module_load (pd_id_t pd_id, char *filename, int load_flag, int timeout)
+{
+  int saved_timeout;
+  struct wtxapi_module_info *module_info;
+
+  wtxapi_timeout_get (&saved_timeout);
+  wtxapi_timeout_set (timeout);
+  module_info = wtxapi_obj_module_load (pd_id, filename, load_flag);
+  wtxapi_timeout_set (saved_timeout);
+
+  return module_info;
+}
+
+/* Unload an obj module from target.  */
+
+int
+wtxapi_obj_module_unload (pd_id_t pd_id, module_id_t mod_id)
+{
+#if WTX_PROT_VERSION != 2
+  return wtx_obj_module_unload (current_wtx_handle, pd_id, 0,
+                                mod_id) != WTX_ERROR;
+#else
+  return wtx_obj_module_unload (current_wtx_handle, mod_id) != WTX_ERROR;
+#endif
+}
+
+/* Unload an obj. module from target.  */
+
+int
+wtxapi_obj_module_by_name_unload (pd_id_t pd_id, char *name)
+{
+#if WTX_PROT_VERSION != 2
+  return wtx_obj_module_by_name_unload (current_wtx_handle, pd_id, 0,
+                                        name) != WTX_ERROR;
+#else
+  return wtx_obj_module_by_name_unload (current_wtx_handle, name) != WTX_ERROR;
+#endif
+}
+
+/* Send events matching expression.  */
+
+int
+wtxapi_register_for_event (const char *reg_exp)
+{
+  return wtx_register_for_event (current_wtx_handle, reg_exp) != WTX_ERROR;
+}
+
+/* Read register data from the target.  */
+
+int
+wtxapi_regs_get (WTX_CONTEXT_TYPE context_type,
+                 WTX_CONTEXT_ID_T context_id, WTX_REG_SET_TYPE reg_set,
+                 int first_byte, int num_bytes, void *reg_memory)
+{
+  WTX_CONTEXT context;
+  initialize_context (&context, context_type, context_id);
+  return wtx_regs_get (current_wtx_handle,
+                       MARSHALL_WTX_CONTEXT_PARAM (context), reg_set,
+                       first_byte, num_bytes, reg_memory) != WTX_ERROR;
+}
+
+/* Write to registers on the target.  */
+
+int
+wtxapi_regs_set (WTX_CONTEXT_TYPE context_type, WTX_CONTEXT_ID_T context_id,
+                 WTX_REG_SET_TYPE reg_set, int first_byte, int num_bytes,
+                 void *reg_memory)
+{
+  WTX_CONTEXT context;
+  initialize_context (&context, context_type, context_id);
+  return wtx_regs_set (current_wtx_handle,
+                       MARSHALL_WTX_CONTEXT_PARAM (context), reg_set,
+                       first_byte, num_bytes, reg_memory) != WTX_ERROR;
+}
+
+/* Convert str to a wtxapi_tgt_addr_t.  */
+
+wtxapi_tgt_addr_t
+wtxapi_str_to_tgt_addr (const char *str)
+{
+  return wtx_str_to_tgt_addr (current_wtx_handle, str);
+}
+
+/* Convert str to context ID.  */
+
+WTX_CONTEXT_ID_T
+wtxapi_str_to_context_id (const char *str)
+{
+  return wtx_str_to_context_id (current_wtx_handle, str);
+}
+
+/* Convert str ton context type.  */
+
+WTX_CONTEXT_TYPE
+wtxapi_str_to_context_type (const char *str)
+{
+  return wtx_str_to_context_type (current_wtx_handle, str);
+}
+
+/* Convert str to an int.  */
+
+int
+wtxapi_str_to_int32 (const char *str)
+{
+  return wtx_str_to_int32 (current_wtx_handle, str);
+}
+
+/* Convert string to event type.  */
+
+WTX_EVENT_TYPE
+wtxapi_str_to_event_type (const char *str)
+{
+  return wtx_str_to_event_type (current_wtx_handle, str);
+}
+
+/* Add symbol with given params.  */
+
+int
+wtxapi_sym_add (pd_id_t pd_id, const char *sym_name,
+                wtxapi_tgt_addr_t sym_value, int sym_type)
+{
+#if WTX_PROT_VERSION != 2
+  return wtx_sym_add (current_wtx_handle, pd_id, sym_name, sym_value,
+                      sym_type) != WTX_ERROR;
+#else
+  return wtx_sym_add (current_wtx_handle, sym_name, sym_value,
+                      (UINT8) sym_type) != WTX_ERROR;
+#endif
+}
+
+static struct wtxapi_symbol_list *
+new_wtxapi_symbol_list (WTX_SYM_LIST *wtx_sym)
+{
+  struct wtxapi_symbol_list *sym_list;
+
+  if (!wtx_sym)
+    return NULL;
+
+  sym_list = (struct wtxapi_symbol_list *)
+    xmalloc (sizeof (struct wtxapi_symbol_list));
+  sym_list->wtx_result_to_cleanup = (void *) wtx_sym;
+  sym_list->first = wtx_sym->pSymbol;
+  sym_list->current = sym_list->first;
+  return sym_list;
+}
+
+static struct wtxapi_symbol_list *
+new_wtxapi_symbol_list_from_symbol (WTX_SYMBOL *wtx_sym)
+{
+  struct wtxapi_symbol_list *sym_list;
+
+  if (!wtx_sym)
+    return NULL;
+
+  sym_list = (struct wtxapi_symbol_list *)
+    xmalloc (sizeof (struct wtxapi_symbol_list));
+  sym_list->wtx_result_to_cleanup = (void *) wtx_sym;
+  sym_list->first = wtx_sym;
+  sym_list->current = wtx_sym;
+  return sym_list;
+}
+
+/* Find info on symbol.  Based on wtxSymFind WTX 2.0, with two differences:
+   _ one additional parameter: the protection domain ID (PD_ID);
+   _ no filter on the type.  */
+
+struct wtxapi_symbol_list *
+wtxapi_sym_find (pd_id_t pd_id, char *sym_name,
+                 wtxapi_tgt_addr_t sym_value, int exact_name)
+{
+#if WTX_PROT_VERSION != 2
+  WTX_SYM_FIND_CRITERIA criteria;
+  memset (&criteria, 0, sizeof (criteria));
+  criteria.pdId = pd_id;
+  criteria.type = 0;
+  criteria.nSymbols = 1;
+  criteria.ref = 0;
+  criteria.moduleId = 0;
+  criteria.moduleName = NULL;
+
+  if (sym_name)
+    {
+      criteria.findName = sym_name;
+      criteria.findValue = 0;
+      criteria.options |= WTX_SYM_FIND_BY_NAME;
+
+      if (exact_name)
+        criteria.options |= WTX_SYM_FIND_BY_EXACT_NAME;
+    }
+  else
+    {
+      criteria.findName = NULL;
+      criteria.findValue = sym_value;
+      criteria.options |= WTX_SYM_FIND_BY_VALUE;
+
+      if (exact_name)
+        criteria.options |= WTX_SYM_FIND_BY_EXACT_VALUE;
+    }
+
+  return new_wtxapi_symbol_list_from_symbol (wtx_sym_find (current_wtx_handle,
+                                                           &criteria));
+#else
+  return new_wtxapi_symbol_list_from_symbol (wtx_sym_find (current_wtx_handle,
+                                                           sym_name,
+                                                           sym_value,
+                                                           exact_name, 0, 0));
+#endif
+}
+
+/* Get list of symbols.  Based on wtxSymListGet WTX 2.0, with three differences:
+   - one additional parameter: the protection domain ID (PD_ID);
+   - no filter on the unknown symbols;
+   - no filter on the module name/id.  */
+
+struct wtxapi_symbol_list *
+wtxapi_sym_list_get (pd_id_t pd_id, char *substring, wtxapi_tgt_addr_t value)
+{
+  struct wtxapi_symbol_list *sym_list;
+  WTX_SYM_LIST *wtx_sym_list;
+#if WTX_PROT_VERSION != 2
+  WTX_SYM_FIND_CRITERIA criteria;
+  memset (&criteria, 0, sizeof (criteria));
+  criteria.pdId = pd_id;
+  criteria.type = 0;
+  criteria.nSymbols = 0;
+  criteria.ref = 0;
+  criteria.moduleId = 0;
+  criteria.moduleName = NULL;
+
+  if (substring)
+    {
+      criteria.findName = substring;
+      criteria.findValue = 0;
+      criteria.options |= WTX_SYM_FIND_BY_NAME;
+    }
+  else
+    {
+      criteria.findName = NULL;
+      criteria.findValue = value;
+      criteria.options |= WTX_SYM_FIND_BY_VALUE;
+    }
+
+  wtx_sym_list = wtx_sym_list_get (current_wtx_handle, &criteria);
+#else
+  wtx_sym_list =
+    wtx_sym_list_get (current_wtx_handle, substring, NULL, value, FALSE);
+#endif
+  sym_list = new_wtxapi_symbol_list (wtx_sym_list);
+  return sym_list;
+}
+
+/* Get list of symbols.  */
+
+struct wtxapi_symbol_list *
+wtxapi_sym_list_by_module_id_get (pd_id_t pd_id, const char *string,
+                                  module_id_t module_id,
+                                  wtxapi_tgt_addr_t value,
+                                  int list_unknown)
+{
+#if WTX_PROT_VERSION != 2
+  return new_wtxapi_symbol_list
+    (wtx_sym_list_by_module_id_get (current_wtx_handle, pd_id, string,
+                                    module_id, value, TO_BOOL (list_unknown)));
+#else
+  return new_wtxapi_symbol_list
+    (wtx_sym_list_by_module_id_get (current_wtx_handle, string, module_id,
+                                    value, TO_BOOL (list_unknown)));
+#endif
+}
+
+/* Get list of symbols.  */
+
+struct wtxapi_symbol_list *
+wtxapi_sym_list_by_module_name_get (pd_id_t pd_id, const char *string,
+                                    const char *module_name,
+                                    wtxapi_tgt_addr_t value,
+                                    int list_unknown)
+{
+#if WTX_PROT_VERSION != 2
+  return new_wtxapi_symbol_list
+    (wtx_sym_list_by_module_name_get (current_wtx_handle, pd_id, string,
+                                      module_name, value,
+                                      TO_BOOL (list_unknown)));
+#else
+  return new_wtxapi_symbol_list
+    (wtx_sym_list_by_module_name_get (current_wtx_handle, string,
+                                      module_name, value,
+                                      TO_BOOL (list_unknown)));
+#endif
+}
+
+/* Remove a symbol from sym table.  */
+
+int
+wtxapi_sym_remove (pd_id_t pd_id, const char *sym_name, int sym_type)
+{
+#if WTX_PROT_VERSION != 2
+  return wtx_sym_remove (current_wtx_handle, pd_id, sym_name,
+                         sym_type) != WTX_ERROR;
+#else
+  return wtx_sym_remove (current_wtx_handle, sym_name, sym_type) != WTX_ERROR;
+#endif
+}
+
+/* Return sym table info.  */
+
+struct wtxapi_sym_tbl_info *
+wtxapi_sym_tbl_info_get (pd_id_t pd_id)
+{
+  WTX_SYM_TBL_INFO *wtx_tbl_info;
+  struct wtxapi_sym_tbl_info *tbl_info;
+  pd_id_t current_pd_id;
+#if WTX_PROT_VERSION != 2
+  wtx_tbl_info = wtx_sym_tbl_info_get (current_wtx_handle, pd_id);
+  current_pd_id = wtx_tbl_info->pdId;
+#else
+  wtx_tbl_info = wtx_sym_tbl_info_get (current_wtx_handle);
+  current_pd_id = NULL_PD;
+#endif
+
+  if (!wtx_tbl_info)
+    return NULL;
+
+  tbl_info = (struct wtxapi_sym_tbl_info *)
+    xmalloc (sizeof (struct wtxapi_sym_tbl_info));
+  tbl_info->pd_id = current_pd_id;
+  tbl_info->sym_num = wtx_tbl_info->symNum;
+  tbl_info->same_name_ok = (wtx_tbl_info->sameNameOk == TRUE);
+  wtx_result_free (current_wtx_handle, wtx_tbl_info);
+  return tbl_info;
+}
+
+/* Reset the target.  */
+
+int
+wtxapi_target_reset ()
+{
+  return wtx_target_reset (current_wtx_handle) != WTX_ERROR;
+}
+
+/* Get target server name.  */
+
+const char *
+wtxapi_ts_name_get ()
+{
+  return wtx_ts_name_get (current_wtx_handle);
+}
+
+/* Get the target CPU type code.  */
+
+int
+wtxapi_target_cpu_type_get ()
+{
+  return wtx_target_cpu_type_get (current_wtx_handle);
+}
+
+/* Check for floating point processor.  */
+
+int
+wtxapi_target_has_fpp_get ()
+{
+  return wtx_target_has_fpp_get (current_wtx_handle);
+}
+
+/* Get edianness of target.  */
+
+WTX_ENDIAN_T
+wtxapi_target_endian_get ()
+{
+  return wtx_target_endian_get (current_wtx_handle);
+}
+
+/* Get target boot line info (or NULL on error).
+ 
+   The string returned is a pointer to temporary memory, and should
+   be duplicated if it is to be stored.  */
+
+const char *
+wtxapi_target_bootline_get ()
+{
+  return wtx_target_bootline_get (current_wtx_handle);
+}
+
+/* Return name of current tool.  */
+
+const char *
+wtxapi_tool_name_get ()
+{
+  return wtx_tool_name_get (current_wtx_handle);
+}
+
+/* Return the Tornado version.  */
+
+const char *
+wtxapi_ts_version_get ()
+{
+  return wtx_ts_version_get (current_wtx_handle);
+}
+
+/* Return the version of WTX.  */
+int
+wtxapi_version_get ()
+{
+  return WTX_PROT_VERSION;
+}
+
+/* Unregister for some events.  */
+
+int
+wtxapi_unregister_for_event (char *reg_exp)
+{
+  return wtx_unregister_for_event (current_wtx_handle, reg_exp) != WTX_ERROR;
+}
+
+/* Call func on target within agent.  */
+
+int
+wtxapi_direct_call (wtxapi_tgt_addr_t entry, void *p_ret_val,
+                    wtxapi_tgt_arg_t arg0, wtxapi_tgt_arg_t arg1,
+                    wtxapi_tgt_arg_t arg2, wtxapi_tgt_arg_t arg3,
+                    wtxapi_tgt_arg_t arg4, wtxapi_tgt_arg_t arg5,
+                    wtxapi_tgt_arg_t arg6, wtxapi_tgt_arg_t arg7,
+                    wtxapi_tgt_arg_t arg8, wtxapi_tgt_arg_t arg9)
+{
+#if WTX_PROT_VERSION != 2
+  return wtx_direct_call (current_wtx_handle, entry, p_ret_val, 10, arg0, arg1,
+                          arg2, arg3, arg4, arg5, arg6, arg7, arg8,
+                          arg9) != WTX_ERROR;
+#else
+  return wtx_direct_call (current_wtx_handle, entry, p_ret_val, arg0, arg1,
+                          arg2, arg3, arg4, arg5, arg6, arg7, arg8,
+                          arg9) != WTX_ERROR;
+#endif
+}
+
+/* Get info about target and server.  */
+
+struct wtxapi_ts_info *
+wtxapi_ts_info_get ()
+{
+  static const char vxworks_prefix[] = "VxWorks";
+  WTX_TS_INFO *wtx_tsinfo = wtx_ts_info_get (current_wtx_handle);
+  struct wtxapi_ts_info *ts_info;
+  char *version;
+  if (!wtx_tsinfo)
+    return NULL;
+
+  ts_info = (struct wtxapi_ts_info *)
+    xmalloc (sizeof (struct wtxapi_ts_info));
+  memset (ts_info, 0, sizeof (struct wtxapi_ts_info));
+  ts_info->tgt_link_desc = wtx_tsinfo->tgtLinkDesc;
+
+#if WTX_PROT_VERSION != 2
+  if (wtx_tsinfo->tgtInfo.rtInfo.rtName)
+    ts_info->tgt_info.rt_info.rt_name =
+      xstrdup (wtx_tsinfo->tgtInfo.rtInfo.rtName);
+  if (wtx_tsinfo->tgtInfo.rtInfo.rtVersion)
+    ts_info->tgt_info.rt_info.rt_version =
+      xstrdup (wtx_tsinfo->tgtInfo.rtInfo.rtVersion);
+#else
+  /* On VxWorks 5, the runtime name is not included into the rt info;
+     instead, the version information is prefixed by "vxWorks".
+     Strip it the prefix, move it to rt_name.  */
+  version = wtx_tsinfo->tgtInfo.rtInfo.rtVersion;
+  if (version)
+    {
+      if (strncmp (vxworks_prefix, version, strlen (vxworks_prefix)) == 0)
+        version += strlen (vxworks_prefix);
+      ts_info->tgt_info.rt_info.rt_version = xstrdup (version);
+    }
+  ts_info->tgt_info.rt_info.rt_name = xstrdup (vxworks_prefix);
+#endif
+  ts_info->tgt_info.rt_info.cpu_type =
+    wtx_tsinfo->tgtInfo.rtInfo.cpuType;
+
+#if WTX_PROT_VERSION > 3
+  if (wtx_tsinfo->tgtInfo.rtInfo.cpuVariant)
+    ts_info->tgt_info.rt_info.cpu_variant =
+      xstrdup (wtx_tsinfo->tgtInfo.rtInfo.cpuVariant);
+#endif
+
+  ts_info->tgt_info.rt_info.has_write_protect =
+    wtx_tsinfo->tgtInfo.rtInfo.hasWriteProtect;
+  ts_info->tgt_info.rt_info.page_size =
+    wtx_tsinfo->tgtInfo.rtInfo.pageSize;
+  ts_info->tgt_info.rt_info.endian =
+    wtx_tsinfo->tgtInfo.rtInfo.endian;
+  if (wtx_tsinfo->tgtInfo.rtInfo.bspName)
+    ts_info->tgt_info.rt_info.bsp_name =
+      xstrdup (wtx_tsinfo->tgtInfo.rtInfo.bspName);
+  if (wtx_tsinfo->tgtInfo.rtInfo.bootline)
+    ts_info->tgt_info.rt_info.boot_line =
+      xstrdup (wtx_tsinfo->tgtInfo.rtInfo.bootline);
+  ts_info->tgt_info.rt_info.mem_base =
+    wtx_tsinfo->tgtInfo.rtInfo.memBase;
+  ts_info->tgt_info.rt_info.mem_size =
+    wtx_tsinfo->tgtInfo.rtInfo.memSize;
+  ts_info->tgt_info.rt_info.num_regions =
+    wtx_tsinfo->tgtInfo.rtInfo.numRegions;
+  ts_info->tgt_info.rt_info.host_pool_base =
+    wtx_tsinfo->tgtInfo.rtInfo.hostPoolBase;
+  ts_info->tgt_info.rt_info.host_pool_size =
+    wtx_tsinfo->tgtInfo.rtInfo.hostPoolSize;
+  ts_info->tgt_info.agent_info.agent_version =
+    wtx_tsinfo->tgtInfo.agentInfo.agentVersion;
+  ts_info->tgt_info.agent_info.mtu =
+    wtx_tsinfo->tgtInfo.agentInfo.mtu;
+  ts_info->tgt_info.agent_info.mode =
+    wtx_tsinfo->tgtInfo.agentInfo.mode;
+
+  if (wtx_tsinfo->version)
+    ts_info->version = xstrdup (wtx_tsinfo->version);
+  if (wtx_tsinfo->userName)
+    ts_info->user_name = xstrdup (wtx_tsinfo->userName);
+  if (wtx_tsinfo->lockMsg)
+    ts_info->lock_msg = xstrdup (wtx_tsinfo->lockMsg);
+#if WTX_PROT_VERSION != 2
+  ts_info->pd_initialized = (wtx_tsinfo->pdInitialized == TRUE);
+#else
+  ts_info->pd_initialized = 1;
+#endif
+  return ts_info;
+}
+
+/* Reattach to the target.  */
+
+int
+wtxapi_target_attach ()
+{
+  return wtx_target_attach (current_wtx_handle) != WTX_ERROR;
+}
+
+/* Probe to see if registry is running.  */
+
+int
+wtxapi_probe ()
+{
+  return wtx_probe (current_wtx_handle) != WTX_ERROR;
+}
+
+/* Set WTX timeout.  */
+
+int
+wtxapi_timeout_set (int msec)
+{
+  return wtx_timeout_set (current_wtx_handle, msec) != WTX_ERROR;
+}
+
+/* Get the current timeout.  */
+
+int
+wtxapi_timeout_get (int *p_msec)
+{
+  UINT32 wtx_timeout;
+  int result = wtx_timeout_get (current_wtx_handle, &wtx_timeout) != WTX_ERROR;
+  *p_msec = wtx_timeout;
+  return result;
+}
+
+/* Create a new protection domain.  */
+
+pd_id_t
+wtxapi_pd_create (const char *name, int options, int heap_size,
+                  int low_priority, int high_priority,
+                  wtxapi_tgt_addr_t page_pool_list, const char *link_path)
+{
+#if WTX_PROT_VERSION != 2
+  return wtx_pd_create (current_wtx_handle, name, options, heap_size,
+                        low_priority, high_priority, page_pool_list,
+                        link_path);
+#else
+  return NULL_PD;
+#endif
+}
+
+/* Get kernel Protection Domain ID.  */
+
+pd_id_t
+wtxapi_pd_kernel_get ()
+{
+#if WTX_PROT_VERSION != 2
+  return wtx_pd_kernel_get (current_wtx_handle);
+#else
+  return NULL_PD;
+#endif
+}
+
+/* Get the current Protection Domain.  */
+
+pd_id_t
+wtxapi_pd_current_get ()
+{
+#if WTX_PROT_VERSION != 2
+  return wtx_pd_current_get (current_wtx_handle);
+#else
+  return NULL_PD;
+#endif
+}
+
+/* Set the current Protection Domain.  */
+
+int
+wtxapi_pd_current_set (pd_id_t pd_id)
+{
+#if WTX_PROT_VERSION != 2
+  return wtx_pd_current_set (current_wtx_handle, pd_id) != WTX_ERROR;
+#else
+  return pd_id == NULL_PD;
+#endif
+}
+
+/* Get the list of allocated PDs.  */
+
+/* NOTE: it performs a full copy of the PD description list.  It should
+   not be a problem, we should not expect to many PDs.  If there are
+   some speed issues, the solution would be to have the same kind of
+   model we use for wtxapi_symbol_list.  To be investigated.  */
+
+struct wtxapi_pd_desc_q *
+wtxapi_pd_info_q_get ()
+{
+  struct wtxapi_pd_desc_q *pd_desc_list;
+#if WTX_PROT_VERSION != 2
+  WTX_PD_DESC_Q *wtx_pd_desc_q = wtx_pd_info_q_get (current_wtx_handle);
+  WTX_PD_DESC_Q *current_wtx_desc = wtx_pd_desc_q;
+  struct wtxapi_pd_desc_q *current_desc;
+  int ix;
+
+  if (wtx_pd_desc_q == NULL)
+    return NULL;
+
+  pd_desc_list = (struct wtxapi_pd_desc_q *)
+    xmalloc (sizeof (struct wtxapi_pd_desc_q));
+  current_desc = pd_desc_list;
+
+  for (current_wtx_desc = wtx_pd_desc_q;
+       current_wtx_desc != NULL;
+       current_wtx_desc = current_wtx_desc->pNext)
+    {
+      current_desc->pd_desc.pd_id = current_wtx_desc->wtxPdDesc.pdId;
+      if (current_wtx_desc->wtxPdDesc.pdName)
+        current_desc->pd_desc.pd_name =
+          xstrdup (current_wtx_desc->wtxPdDesc.pdName);
+      current_desc->pd_desc.pd_flags = current_wtx_desc->wtxPdDesc.pdFlags;
+      if (current_wtx_desc->wtxPdDesc.pdLinkPathStr)
+        current_desc->pd_desc.pd_link_path_str =
+          xstrdup (current_wtx_desc->wtxPdDesc.pdLinkPathStr);
+      current_desc->pd_desc.pd_link_path_count =
+        current_wtx_desc->wtxPdDesc.pdLinkPathCount;
+      if (current_wtx_desc->wtxPdDesc.pdLinkPathCount)
+        {
+          current_desc->pd_desc.pd_link_path = (pd_id_t *)
+            xmalloc (current_wtx_desc->wtxPdDesc.pdLinkPathCount
+                     * sizeof (pd_id_t));
+          for (ix = 0; ix < current_wtx_desc->wtxPdDesc.pdLinkPathCount; ix++)
+            current_desc->pd_desc.pd_link_path[ix]
+              = current_wtx_desc->wtxPdDesc.pdLinkPath[ix];
+
+        }
+      else
+        {
+          current_desc->pd_desc.pd_link_path = NULL;
+        }
+      if (current_wtx_desc->wtxPdDesc.pdAttachToCount)
+        {
+          current_desc->pd_desc.pd_attach_to_count =
+            current_wtx_desc->wtxPdDesc.pdAttachToCount;
+          current_desc->pd_desc.pd_attach_to = (pd_id_t *)
+            xmalloc (current_wtx_desc->wtxPdDesc.pdAttachToCount
+                     * sizeof (pd_id_t));
+          for (ix = 0; ix < current_wtx_desc->wtxPdDesc.pdAttachToCount; ix++)
+            current_desc->pd_desc.pd_attach_to[ix]
+              = current_wtx_desc->wtxPdDesc.pdAttachTo[ix];
+        }
+      else
+        {
+          current_desc->pd_desc.pd_attach_to = NULL;
+        }
+
+      if (current_wtx_desc->pNext != NULL)
+        {
+          current_desc->next = (struct wtxapi_pd_desc_q *)
+            xmalloc (sizeof (struct wtxapi_pd_desc_q));
+          current_desc = current_desc->next;
+        }
+      else
+        current_desc->next = NULL;
+    }
+  wtx_result_free (current_wtx_handle, wtx_pd_desc_q);
+#else
+  pd_desc_list = (struct wtxapi_pd_desc_q *)
+    xmalloc (sizeof (struct wtxapi_pd_desc_q));
+  memset (&pd_desc_list, 0, sizeof (pd_desc_list));
+  pd_desc_list->pd_desc.pd_name = xstrdup ("kernel");
+  pd_desc_list->pd_desc.pd_link_path_str = xstrdup ("<none>");
+#endif
+  return pd_desc_list;
+}
+
+/* Return non-zero if the given module has been fully linked,
+   or, in other words, relocation has already been performed.  */
+
+int
+wtxapi_load_fully_linked (const struct wtxapi_module_info *module_info)
+{
+  /* The WTX_LOAD_FULLY_LINKED macro has been introduced *after* Vxworks 5.x.  
+     For Vxworks 5.x targets, we simply define it ourselves.  */
+#ifndef WTX_LOAD_FULLY_LINKED
+#define WTX_LOAD_FULLY_LINKED 0x20
+#endif
+
+  return module_info->load_flag & WTX_LOAD_FULLY_LINKED;
+}
+
+/* Test target server availability.  */
+
+int
+wtxapi_target_server_available_p ()
+{
+  WTX_TS_INFO *ts_info = wtx_ts_info_get (current_wtx_handle);
+  return ts_info != NULL;
+}
+
+
+/* Symbol list handling.  */
+
+struct wtxapi_symbol *
+get_current_wtxapi_symbol (struct wtxapi_symbol_list *list)
+{
+  struct wtxapi_symbol *sym;
+  if (!list || !list->current)
+    return NULL;
+
+  sym = (struct wtxapi_symbol *) xmalloc (sizeof (struct wtxapi_symbol));
+  copy_current_wtxapi_symbol (list, sym, wtxapi_symbol_copy_full);
+  return sym;
+}
+
+void
+copy_current_wtxapi_symbol (struct wtxapi_symbol_list *list,
+                            struct wtxapi_symbol *to, int options)
+{
+  if (!to || !list || !list->current)
+    return;
+
+  to->status = list->current->status;
+#if WTX_PROT_VERSION != 2
+  to->pd_id = list->current->pdId;
+#else
+  to->pd_id = NULL_PD;
+#endif
+  if (options != wtxapi_symbol_copy_dont_copy_name
+      && options != wtxapi_symbol_copy_dont_copy_strings
+      && list->current->name)
+    to->name = xstrdup (list->current->name);
+  else
+    to->name = NULL;
+
+  if (options != wtxapi_symbol_copy_dont_copy_module_name
+      && options != wtxapi_symbol_copy_dont_copy_strings
+      && list->current->moduleName)
+    to->module_name = xstrdup (list->current->moduleName);
+  else
+    to->module_name = NULL;
+
+  to->exact_name = (list->current->exactName == TRUE);
+  to->value = list->current->value;
+  to->type = list->current->type;
+  to->type_mask = list->current->typeMask;
+}
+
+char *
+current_wtxapi_symbol_name (struct wtxapi_symbol_list *list)
+{
+  return xstrdup (list->current->name);
+}
+
+int
+go_to_first_element_in_wtxapi_sym_list (struct wtxapi_symbol_list *list)
+{
+  if (!list || !list->first)
+    return 0;
+
+  list->current = list->first;
+  return 1;
+}
+
+int
+go_to_next_element_in_wtxapi_sym_list (struct wtxapi_symbol_list *list)
+{
+  if (!list->current || !list->current->next)
+    return 0;
+
+  list->current = list->current->next;
+  return 1;
+}
+
+/* Deallocation functions.  */
+
+void
+free_wtxapi_evtpt_list (struct wtxapi_evtpt_list *to_free)
+{
+  int ix;
+  for (ix = 0; ix < to_free->n_evtpt; ix++)
+    {
+      xfree (to_free->p_evtpt_info[ix].wtx_evtpt.event.args);
+    }
+  xfree (to_free->p_evtpt_info);
+  xfree (to_free);
+}
+
+void
+free_wtxapi_module_list (struct wtxapi_module_list *to_free)
+{
+  xfree (to_free->mod_id_array);
+  xfree (to_free->pd_id_array);
+  xfree (to_free);
+}
+
+void
+free_wtxapi_pd_desc_q (struct wtxapi_pd_desc_q *to_free)
+{
+  struct wtxapi_pd_desc_q *current;
+  struct wtxapi_pd_desc_q *element_to_deallocate = NULL;
+
+  for (current = to_free; current != NULL; current = current->next)
+    {
+      if (element_to_deallocate)
+        xfree (element_to_deallocate);
+      if (current->pd_desc.pd_name)
+        xfree (current->pd_desc.pd_name);
+      if (current->pd_desc.pd_link_path_str)
+        xfree (current->pd_desc.pd_link_path_str);
+      if (current->pd_desc.pd_link_path)
+        xfree (current->pd_desc.pd_link_path);
+      if (current->pd_desc.pd_attach_to)
+        xfree (current->pd_desc.pd_attach_to);
+      element_to_deallocate = current;
+    }
+}
+
+void
+free_wtxapi_symbol (struct wtxapi_symbol *to_free)
+{
+  if (to_free->name)
+    xfree (to_free->name);
+
+  if (to_free->module_name)
+    xfree (to_free->module_name);
+
+  xfree (to_free);
+}
+
+void
+free_wtxapi_symbol_list (struct wtxapi_symbol_list *to_free)
+{
+  if (to_free->wtx_result_to_cleanup != NULL)
+    wtx_result_free (current_wtx_handle, to_free->wtx_result_to_cleanup);
+
+  xfree (to_free);
+}
+
+void
+free_wtxapi_module_info (struct wtxapi_module_info *to_free)
+{
+  xfree (to_free->module_name);
+  if (to_free->section_addrs != NULL)
+    free_section_addr_info (to_free->section_addrs);
+  if (to_free->segments != NULL)
+    xfree (to_free->segments);
+  if (to_free->undef_list)
+    free_wtxapi_symbol_list (to_free->undef_list);
+  xfree (to_free);
+}
+
+void
+free_wtxapi_ts_info (struct wtxapi_ts_info *to_free)
+{
+  if (to_free->tgt_info.rt_info.rt_name)
+    xfree (to_free->tgt_info.rt_info.rt_name);
+
+  if (to_free->tgt_info.rt_info.cpu_variant)
+    xfree (to_free->tgt_info.rt_info.cpu_variant);
+
+  if (to_free->tgt_info.rt_info.rt_version)
+    xfree (to_free->tgt_info.rt_info.rt_version);
+
+  if (to_free->tgt_info.rt_info.bsp_name)
+    xfree (to_free->tgt_info.rt_info.bsp_name);
+
+  if (to_free->tgt_info.rt_info.boot_line)
+    xfree (to_free->tgt_info.rt_info.boot_line);
+
+  if (to_free->version)
+    xfree (to_free->version);
+
+  if (to_free->user_name)
+    xfree (to_free->user_name);
+
+  if (to_free->lock_msg)
+    xfree (to_free->lock_msg);
+
+  xfree (to_free);
+}
+
+void
+free_wtxapi_event_desc (struct wtxapi_event_desc *to_free)
+{
+  switch (to_free->event_type)
+    {
+      case WTX_EVENT_OBJ_UNLOADED:
+        xfree (to_free->desc.obj_unloaded.module_filename);
+        break;
+      case WTX_EVENT_VIO_WRITE:
+        xfree (to_free->desc.vio_write.data);
+        break;
+    }
+
+  xfree (to_free);
+}
+
+
+/* cleanup functions.  */
+
+void
+cleanup_wtxapi_evtpt_list (void *to_free)
+{
+  free_wtxapi_evtpt_list ((struct wtxapi_evtpt_list *) to_free);
+}
+
+void
+cleanup_wtxapi_module_list (void *to_free)
+{
+  free_wtxapi_module_list ((struct wtxapi_module_list *) to_free);
+}
+
+void
+cleanup_wtxapi_pd_desc_q (void *to_free)
+{
+  free_wtxapi_pd_desc_q ((struct wtxapi_pd_desc_q *) to_free);
+}
+
+void
+cleanup_wtxapi_symbol (void *to_free)
+{
+  free_wtxapi_symbol ((struct wtxapi_symbol *) to_free);
+}
+
+void
+cleanup_wtxapi_symbol_list (void *to_free)
+{
+  free_wtxapi_symbol_list ((struct wtxapi_symbol_list *) to_free);
+}
+
+void
+cleanup_wtxapi_module_info (void *to_free)
+{
+  free_wtxapi_module_info ((struct wtxapi_module_info *) to_free);
+}
+
+void
+cleanup_wtxapi_ts_info (void *to_free)
+{
+  free_wtxapi_ts_info ((struct wtxapi_ts_info *) to_free);
+}
+
+void
+cleanup_wtxapi_result_free (void *to_free)
+{
+  wtxapi_result_free (to_free);
+}
+
+
+/* Implements simple symbol lookup.  */
+
+int
+remote_wtxapi_get_symbol_address (char *symbol_name, CORE_ADDR *symbol_addr)
+{
+  struct wtxapi_symbol_list *symbol_list;
+  struct wtxapi_symbol *symbol_info;
+
+  symbol_list = wtxapi_sym_find (wtxapi_pd_current_get (), symbol_name, 0, 1);
+  symbol_info = get_current_wtxapi_symbol (symbol_list);
+
+  if (symbol_info != NULL)
+    {
+      *symbol_addr = symbol_info->value;
+
+      free_wtxapi_symbol (symbol_info);
+      free_wtxapi_symbol_list (symbol_list);
+      return 0;
+    }
+  else
+    {
+      *symbol_addr = 0;
+      return -1;
+    }
+}
+
+/* Return non-zero if BoDA support (Breakpoint on Data Access) is available
+   on the system we're connected to.  This routine assumes that we are
+   connected to the target server.  */
+
+int
+wtxapi_target_has_BoDA (void)
+{
+  /* Will be set to 1 as soon as we've checked whether the system
+     we're running on provides BoDA or not.  This is used to determine
+     whether BoDA_supported_p has been set yet, or not.  */
+  static int BoDA_support_checked_p = 0;
+
+  /* Set to non-zero if BoDA is supported on the system.  Set iff
+     BoDA_support_checked_p is non-zero.
+
+     We're checking the support for BoDA in a lazy fashion, because
+     it's a tiny bit expensive (need to do a symbol lookup), and because
+     we need to be connected to the system before we do so.  We could
+     be doing that check after connecting with the target server, but
+     that would be useless during the sessions when watchpoints are
+     not actually used.  So we wait until we need to have this info
+     before we actually do the check.  */
+  static int BoDA_supported_p = 0;
+
+  if (!BoDA_support_checked_p)
+    {
+      /* BoDA is supported by the target iff the symbol wdbEventClassHwBpVa
+         is defined in the Core OS partition.  Instead of trying to find
+         the PD ID of the Core OS partition, we just seach the symbol
+         in all partitions.  It's unlikely that any other partition
+         would define a symbol using that name, so accept that risk.  */
+      struct wtxapi_symbol_list *symbol_list;
+
+      symbol_list = wtxapi_sym_find (WTX_SYM_FIND_IN_ALL_PD,
+                                     "wdbEventClassHwBpVa", 0, 1);
+
+      if (symbol_list != NULL)
+        {
+          BoDA_supported_p = 1;
+          free_wtxapi_symbol_list (symbol_list);
+        }
+
+      BoDA_support_checked_p = 1;
+    }
+
+  return BoDA_supported_p;
+}
+
+/* Free the memory allocated by the given THREADS list.  */
+
+void
+free_wtxapi_thread_info (struct wtxapi_thread_info *threads)
+{
+  struct wtxapi_thread_info *this = threads;
+  struct wtxapi_thread_info *next;
+
+  while (this != NULL)
+    {
+      next = this->next;
+      xfree (this->name);
+      xfree (this);
+      this = next;
+    }
+}
+
+/* Routines implemented using the support of external modules.  */
+
+static struct wtxapi_support_ops *support_ops = NULL;
+
+/* Setup the current wtx_support_ops vector to OPS.  */
+
+void
+wtxapi_set_support_ops (struct wtxapi_support_ops *ops)
+{
+  support_ops = ops;
+}
+
+/* Call the wtx_connection_established_callback method of
+   the support_ops vector.  */
+
+void
+wtxapi_notify_connection_established (void)
+{
+  /* If the support_ops structure hasn't been set, then simply
+     do nothing.  */
+  if (support_ops == NULL)
+    return;
+  gdb_assert (support_ops->wtx_connection_established_callback != NULL);
+
+  support_ops->wtx_connection_established_callback (current_wtx_handle);
+}
+
+/* Return the list of threads currently running on the target.
+
+   This routine is dependent on the support_ops vector being set,
+   or else NULL will be returned.  */
+
+struct wtxapi_thread_info *
+wtxapi_get_thread_list (void)
+{
+  /* If the support_ops structure has not be set, then return NULL.  */
+  if (support_ops == NULL)
+    return NULL;
+  gdb_assert (support_ops->get_thread_list != NULL);
+
+  return support_ops->get_thread_list ();
+}
+
+/* If TASK_ID is a valid task ID, then save its PD inside TASK_PD,
+   and return non-zero.  In case of failure, return zero, and the value
+   of TASK_PD is undefined.
+   
+   This function is dependent on the support_ops vector being set,
+   or else zero will be returned.  */
+   
+int
+wtxapi_get_task_pd (int task_id, pd_id_t *task_pd)
+{
+  /* If the support_ops structure has not be set, then return 0.  */
+  if (support_ops == NULL)
+    return 0;
+  gdb_assert (support_ops->get_task_pd != NULL);
+
+  return support_ops->get_task_pd (task_id, task_pd);
+}
+
+/* Execute the system_mode_support_p method of the wtxapi_support_ops
+   vector.
+   
+   This function is dependent on the support_ops vector being set,
+   or else zero will be returned.   */
+
+int
+wtxapi_system_mode_support_p (void)
+{
+  if (support_ops == NULL)
+    return 0;
+  gdb_assert (support_ops->system_mode_support_p != NULL);
+
+  return support_ops->system_mode_support_p ();
+}
+
+/* Execute the system_mode_get_current_context_id method of the
+   wtxapi_support_ops vector.
+   
+   This function is dependent on the support_ops vector being set,
+   or else the SYSTEM_CID will be returned.   */
+
+WTX_CONTEXT_ID_T
+wtxapi_system_mode_get_current_context_id (void)
+{
+  /* If the support_ops structure has not be set, then return 0.  */
+  if (support_ops == NULL)
+    return SYSTEM_CID;
+  gdb_assert (support_ops->system_mode_get_current_context_id != NULL);
+
+  return support_ops->system_mode_get_current_context_id ();
+}
+
+/* Return the value of VX_FP_TASK for the current target.  The value of
+   this option depends on the VxWorks version.  */
+
+int
+wtxapi_vx_fp_task ()
+{
+  struct wtxapi_ts_info *ts_info = wtxapi_ts_info_get ();
+  struct cleanup *old_cleanup = make_cleanup (cleanup_wtxapi_ts_info, ts_info);
+  char vx6_pattern[] = "6.";
+  
+  if (strncmp (vx6_pattern, ts_info->tgt_info.rt_info.rt_version,
+               strlen (vx6_pattern)) == 0)
+    return 0x1000000;
+  else
+    return 0x8;
+  do_cleanups (old_cleanup);
+}
+
+/* Ask WTX which variant is the target CPU, and compare it against
+   VARIANT.  If they match, return 1; otherwise, return 0.  */
+
+int
+wtxapi_has_target_variant (const char *variant)
+{
+  int result;
+  struct wtxapi_ts_info *ts_info = wtxapi_ts_info_get ();
+  struct cleanup *old_cleanup = make_cleanup (cleanup_wtxapi_ts_info, ts_info);
+  
+  if (ts_info->tgt_info.rt_info.cpu_variant
+      && strcmp (ts_info->tgt_info.rt_info.cpu_variant, variant) == 0)
+    result = 1;
+  else
+    result = 0;
+
+  do_cleanups (old_cleanup);
+  return result;
+}
+
+static struct cmd_list_element *info_wtx_list = NULL;
+
+static void
+info_wtx_version_command (char *args, int from_tty)
+{
+  printf_filtered (_("WTX protocol version %d\n"), wtxapi_version_get ());
+}
+
+/* Print the version of VxWorks running on the target.  */
+
+static void
+info_wtx_vxworks_version ()
+{
+  struct wtxapi_ts_info *ts_info;
+  struct cleanup *old_cleanup = NULL;
+  char *name;
+  char *version;
+
+  if (current_wtx_handle == NULL
+      || !(ts_info = wtxapi_ts_info_get ()))
+    printf_filtered (_("Not connected to a VxWorks target.\n"));
+  else
+    {
+      old_cleanup = make_cleanup (cleanup_wtxapi_ts_info, ts_info);
+      name = ts_info->tgt_info.rt_info.rt_name;
+      version = ts_info->tgt_info.rt_info.rt_version;
+      printf_filtered (_("%s version %s\n"), name, version);
+    }
+
+  if (old_cleanup)
+    do_cleanups (old_cleanup);
+}
+
+static void
+info_wtx_threads_command (char *args, int from_tty)
+{
+  struct wtxapi_thread_info *threads = wtxapi_get_thread_list ();
+  struct wtxapi_thread_info *current_thread = threads;
+
+  if (threads == NULL)
+    {
+      printf_filtered ("No threads.\n");
+      return;
+    }
+
+  while (current_thread != NULL)
+    {
+      printf_filtered ("0x%lx\t%s\n", current_thread->id,
+                       current_thread->name);
+      current_thread = current_thread->next;
+    }
+  free_wtxapi_thread_info (threads);
+}
+
+static void
+info_wtx_command (char *args, int from_tty)
+{
+  /* brobecker/2007-12-17: Ideally, the "info wtx" command should
+     only be a prefix command.  But we have been using it to get
+     the WTX protocol version for the past few years.  So keep this
+     command as an alias of "info wtx version" for now.  Eventually,
+     when all the GDB versions that didn't support "info wtx version"
+     are no longer supported, we can remove this compatibility hack.  */
+  info_wtx_version_command (NULL, from_tty);
+}
+
+/* Load the WTX shared libraries and initialize the pointers to WTX
+   functions.  */
+
+static void
+load_wtx_libraries ()
+{
+  void *wtx_lib = NULL;
+
+  if (WTX_PROT_VERSION == 4)
+    {
+      wtx_lib = load_shared_lib ("wtxapi41");
+
+      if (!wtx_lib)
+	wtx_lib = load_shared_lib ("wtxapi40");
+    }
+  else if (WTX_PROT_VERSION == 3)
+    {
+      wtx_lib = load_shared_lib ("wtxapi30");
+    }
+  else if (WTX_PROT_VERSION == 2)
+    {
+      wtx_lib = load_shared_lib ("wtxapi");
+    }
+
+  if (!wtx_lib)
+    error ("WTX library not found.");
+
+#define resolve(sym, name) \
+  if (!(sym = get_symbol_from_shared_lib (wtx_lib, name))) \
+      error ("%s not found in WTX library", name);
+
+  resolve (wtx_initialize, "wtxInitialize");
+  resolve (wtx_terminate, "wtxTerminate");
+  resolve (wtx_info_q, "wtxInfoQ");
+  resolve (wtx_tool_attach, "wtxToolAttach");
+  resolve (wtx_tool_connected, "wtxToolConnected");
+  resolve (wtx_tool_detach, "wtxToolDetach");
+  resolve (wtx_err_clear, "wtxErrClear");
+  resolve (wtx_err_get, "wtxErrGet");
+  resolve (wtx_err_handler_add, "wtxErrHandlerAdd");
+  resolve (wtx_err_handler_remove, "wtxErrHandlerRemove");
+  resolve (wtx_err_msg_get, "wtxErrMsgGet");
+  resolve (wtx_agent_mode_get, "wtxAgentModeGet");
+  resolve (wtx_agent_mode_set, "wtxAgentModeSet");
+  resolve (wtx_breakpoint_add, "wtxBreakpointAdd");
+  resolve (wtx_eventpoint_add, "wtxEventpointAdd");
+  resolve (wtx_eventpoint_delete, "wtxEventpointDelete");
+  resolve (wtx_event_get, "wtxEventGet");
+  resolve (wtx_context_status_get, "wtxContextStatusGet");
+  resolve (wtx_context_cont, "wtxContextCont");
+  resolve (wtx_context_create, "wtxContextCreate");
+  resolve (wtx_context_resume, "wtxContextResume");
+  resolve (wtx_context_exit_notify_add, "wtxContextExitNotifyAdd");
+  resolve (wtx_context_kill, "wtxContextKill");
+  resolve (wtx_context_step, "wtxContextStep");
+  resolve (wtx_context_suspend, "wtxContextSuspend");
+  resolve (wtx_eventpoint_list_get, "wtxEventpointListGet");
+  resolve (wtx_result_free, "wtxResultFree");
+  resolve (wtx_gopher_eval, "wtxGopherEval");
+  resolve (wtx_mem_info_get, "wtxMemInfoGet");
+  resolve (wtx_mem_alloc, "wtxMemAlloc");
+  resolve (wtx_mem_checksum, "wtxMemChecksum");
+  resolve (wtx_mem_move, "wtxMemMove");
+  resolve (wtx_mem_free, "wtxMemFree");
+  resolve (wtx_mem_read, "wtxMemRead");
+  resolve (wtx_mem_width_read, "wtxMemWidthRead");
+  resolve (wtx_mem_write, "wtxMemWrite");
+  resolve (wtx_mem_width_write, "wtxMemWidthWrite");
+  resolve (wtx_mem_set, "wtxMemSet");
+  resolve (wtx_mem_add_to_pool, "wtxMemAddToPool");
+  resolve (wtx_mem_realloc, "wtxMemRealloc");
+  resolve (wtx_mem_align, "wtxMemAlign");
+  resolve (wtx_mem_scan, "wtxMemScan");
+  resolve (wtx_obj_module_checksum, "wtxObjModuleChecksum");
+  resolve (wtx_obj_module_find_id, "wtxObjModuleFindId");
+  resolve (wtx_obj_module_find_name, "wtxObjModuleFindName");
+  resolve (wtx_obj_module_info_get, "wtxObjModuleInfoGet");
+  resolve (wtx_obj_module_load, "wtxObjModuleLoad");
+  resolve (wtx_obj_module_unload, "wtxObjModuleUnload");
+  resolve (wtx_obj_module_by_name_unload, "wtxObjModuleByNameUnload");
+  resolve (wtx_register_for_event, "wtxRegisterForEvent");
+  resolve (wtx_regs_get, "wtxRegsGet");
+  resolve (wtx_regs_set, "wtxRegsSet");
+  resolve (wtx_str_to_tgt_addr, "wtxStrToTgtAddr");
+  resolve (wtx_str_to_context_id, "wtxStrToContextId");
+  resolve (wtx_str_to_context_type, "wtxStrToContextType");
+  resolve (wtx_str_to_int32, "wtxStrToInt32");
+  resolve (wtx_str_to_event_type, "wtxStrToEventType");
+  resolve (wtx_sym_add, "wtxSymAdd");
+  resolve (wtx_sym_find, "wtxSymFind");
+  resolve (wtx_sym_list_get, "wtxSymListGet");
+  resolve (wtx_sym_list_by_module_id_get, "wtxSymListByModuleIdGet");
+  resolve (wtx_sym_list_by_module_name_get, "wtxSymListByModuleNameGet");
+  resolve (wtx_sym_remove, "wtxSymRemove");
+  resolve (wtx_sym_tbl_info_get, "wtxSymTblInfoGet");
+  resolve (wtx_target_reset, "wtxTargetReset");
+  resolve (wtx_ts_name_get, "wtxTsNameGet");
+  resolve (wtx_target_cpu_type_get, "wtxTargetCpuTypeGet");
+  resolve (wtx_target_has_fpp_get, "wtxTargetHasFppGet");
+  resolve (wtx_target_endian_get, "wtxTargetEndianGet");
+  resolve (wtx_target_bootline_get, "wtxTargetBootlineGet");
+  resolve (wtx_tool_name_get, "wtxToolNameGet");
+  resolve (wtx_ts_version_get, "wtxTsVersionGet");
+  resolve (wtx_unregister_for_event, "wtxUnregisterForEvent");
+  resolve (wtx_direct_call, "wtxDirectCall");
+  resolve (wtx_ts_info_get, "wtxTsInfoGet");
+  resolve (wtx_target_attach, "wtxTargetAttach");
+  resolve (wtx_probe, "wtxProbe");
+  resolve (wtx_timeout_set, "wtxTimeoutSet");
+  resolve (wtx_timeout_get, "wtxTimeoutGet");
+
+#if WTX_PROT_VERSION != 2
+  resolve (wtx_obj_module_list_get, "wtxObjModuleListGet");
+  resolve (wtx_context_stop, "wtxContextStop");
+  resolve (wtx_pd_create, "wtxPdCreate");
+  resolve (wtx_pd_kernel_get, "wtxPdKernelGet");
+  resolve (wtx_pd_current_get, "wtxPdCurrentGet");
+  resolve (wtx_pd_current_set, "wtxPdCurrentSet");
+  resolve (wtx_pd_info_q_get, "wtxPdInfoQGet");
+#else
+  resolve (wtx_obj_module_list, "wtxObjModuleList");
+#endif
+
+}
+
+void
+_initialize_remote_wtxapi ()
+{
+  load_wtx_libraries ();
+
+  add_prefix_cmd ("wtx", no_class, info_wtx_command,
+                  _("Display version of WTX protocol for which gdb is built."),
+                  &info_wtx_list, "info wtx ", 0, &infolist);
+
+  add_cmd ("threads", class_info, info_wtx_threads_command,
+           _("Display the list of threads running on the target."),
+           &info_wtx_list);
+
+  add_cmd ("version", class_info, info_wtx_version_command,
+           _("Display version of WTX protocol for which gdb is built."),
+           &info_wtx_list);
+
+  add_cmd ("vxworks-version", class_info, info_wtx_vxworks_version,
+           _("Display version of VxWorks for the target."),
+           &info_wtx_list);
+}
diff --git a/gdb/remote-wtxapi.h b/gdb/remote-wtxapi.h
new file mode 100644
index 0000000..fa05061
--- /dev/null
+++ b/gdb/remote-wtxapi.h
@@ -0,0 +1,1221 @@
+/* Thin binding for the WTX protocol, for GDB.
+
+   Copyright 2004, 2010 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#ifndef REMOTE_WTXAPI_H
+#define REMOTE_WTXAPI_H
+
+/* For wtx.h : GDB is run on the host.  */
+#define HOST
+
+#include "wtx.h"
+#include "symfile.h"
+
+/* When in system-mode, the context ID to use is -1.  */
+
+#define SYSTEM_CID (-1)
+
+#ifndef WTX_PROT_VERSION
+#define WTX_PROT_VERSION 2
+#endif
+
+#if WTX_PROT_VERSION == 4
+typedef WTX_TGT_ADDR_T wtxapi_tgt_addr_t;
+typedef WTX_TGT_ARG_T wtxapi_tgt_arg_t;
+#else
+typedef TGT_ADDR_T wtxapi_tgt_addr_t;
+typedef TGT_ARG_T wtxapi_tgt_arg_t;
+#endif
+
+/* Some macros are not defined in WTX 2.0.  Define them as constant when
+   possible.  */
+
+#ifndef WTX_PD_CURRENT
+extern const wtxapi_tgt_arg_t WTX_PD_CURRENT;
+#endif
+
+#ifndef WTX_PD_ALL
+extern const wtxapi_tgt_addr_t WTX_PD_ALL;
+#endif
+
+#ifndef WTX_MOD_FIND_IN_ALL_PD
+extern const wtxapi_tgt_addr_t WTX_MOD_FIND_IN_ALL_PD;
+#endif
+
+#ifndef WTX_SYM_FIND_IN_ALL_PD
+extern const int WTX_SYM_FIND_IN_ALL_PD;
+#endif
+
+/* On WTX 3.0, some additional values has been added in the enums to
+   deal with the protection domains.  Emulate these value in WTX 2.0.  */
+
+#if WTX_PROT_VERSION == 2
+extern const WTX_CONTEXT_TYPE WTX_CONTEXT_PD;
+extern const int WTX_ERR_PD_INVALID_PD;
+#endif
+
+#ifndef WTX_LOAD_GLOBAL_SYMBOLS
+#define WTX_LOAD_GLOBAL_SYMBOLS 0x4
+#endif
+
+/* On WTX 4.0, some variables have been renamed.  */
+
+#if WTX_PROT_VERSION == 4
+extern const WTX_ACTION_TYPE WTX_ACTION_STOP_ALL;
+#endif
+
+/* The structures defined below are used to resolve differences
+   between version of the WTX protocol.
+
+   Note those differences:
+   - When the WTX structure contains a BOOL32, the WTX API structure uses an
+   int; if it is FALSE in the WTX structure, it is 0 in the WTX API structure;
+   - When the WTX structure contains a UINT32, the WTX API uses an int; the
+   conversion is straightforward.  */
+
+/* Protection domain ID.  */
+
+typedef wtxapi_tgt_addr_t pd_id_t;
+
+/* Module ID.  */
+
+typedef UINT32 module_id_t;
+
+/* Event point id.  */
+
+typedef UINT32 evtpt_id_t;
+
+
+/* Invalid identifiers.  Equivalent to WTX_ERROR.  */
+
+extern const pd_id_t invalid_pd_id;
+extern const evtpt_id_t invalid_module_id;
+extern const evtpt_id_t invalid_evtpt_id;
+extern const WTX_CONTEXT_ID_T invalid_context_id;
+extern const WTX_AGENT_MODE_TYPE invalid_agent_mode;
+extern const WTX_CONTEXT_STATUS invalid_context_status;
+
+/* Event.  Same as WTX_EVENT in WTX 3.0, and WTX_EVENT_2 in WTX 2.0.  */
+
+struct wtxapi_event
+{
+  WTX_EVENT_TYPE event_type;
+  int num_args;
+  wtxapi_tgt_arg_t *args;
+};
+
+/* Action.  Based on WTX_ACTION.  */
+
+struct wtxapi_action
+{
+  /* Action type to perform.  */
+  WTX_ACTION_TYPE action_type;
+  /* Action dependent argument.  */
+  int action_arg;
+  /* Function to ACTION_CALL.  */
+  wtxapi_tgt_addr_t call_rtn;
+  /* Function argument.  */
+  wtxapi_tgt_arg_t call_arg;
+};
+
+/* Context.  Same as WTX_CONTEXT */
+
+struct wtxapi_context
+{
+  WTX_CONTEXT_TYPE context_type;
+  WTX_CONTEXT_ID_T context_id;
+
+  /* WTX 4.0-specific field.  */
+  WTX_CONTEXT_ID_T context_sub_id;
+};
+
+/* Eventpoint desc.  Same as WTX_EVTPT in WTX 3.0, and WTX_EVTPT_2
+   in WTX 2.0.  */
+
+struct wtxapi_evtpt
+{
+  struct wtxapi_event event;
+  struct wtxapi_context context;
+  struct wtxapi_action action;
+};
+
+/* Eventpoint info.  Same as WTX_EVTPT_INFO.  */
+
+struct wtxapi_evtpt_info
+{
+  /* Eventpoint descriptor.  */
+  struct wtxapi_evtpt wtx_evtpt;
+  /* Tool identifier.  */
+  int tool_id;
+  /* Eventpoint identifier.  */
+  evtpt_id_t evtpt_num;
+};
+
+
+/* Eventpoint list message.  Same as WTX_EVTPT_LIST in WTX 3.0,
+   and WTX_EVTPT_LIST_2 in WTX 2.0.  */
+
+struct wtxapi_evtpt_list
+{
+  int n_evtpt;
+  struct wtxapi_evtpt_info *p_evtpt_info;
+};
+
+/* Section descriptor.  Based on WTX_SECTION_DESC (WTX 3.0)
+   and LD_M_SECTION (WTX 2.0).  */
+
+struct wtxapi_section_desc
+{
+  /* Name of the section.  */
+  char *name;
+  /* Section flags.  */
+  int flags;
+  /* Section base address.  */
+  wtxapi_tgt_addr_t base_addr;
+  /* Section length.  */
+  int length;
+};
+
+/* Symbol description.  Based on WTX_SYMBOL.  */
+
+struct wtxapi_symbol
+{
+  /* Returned value for find request.  */
+  int status;
+  /* Protection domain ID.  */
+  pd_id_t pd_id;
+  /* Symbol name.  */
+  char *name;
+  /* 0 iff symbol name prefixed by an underscore.  */
+  int exact_name;
+  /* Symbol value.  */
+  wtxapi_tgt_addr_t value;
+  /* symbol type.  */
+  int type;
+  /* symbol type mask for lookup.  */
+  int type_mask;
+  /* Module name.  */
+  char *module_name;
+};
+
+/* Symbol copy options for copy_current_symbol.  */
+
+extern const int wtxapi_symbol_copy_none;
+extern const int wtxapi_symbol_copy_name;
+extern const int wtxapi_symbol_copy_module_name;
+#define wtxapi_symbol_copy_all (wtxapi_symbol_copy_module_name \
+                                  | wtxapi_symbol_copy_name)
+
+enum wtxapi_symbol_copy_options
+{
+  wtxapi_symbol_copy_full = 1,
+  wtxapi_symbol_copy_dont_copy_name = 2,
+  wtxapi_symbol_copy_dont_copy_module_name = 3,
+  wtxapi_symbol_copy_dont_copy_strings = 4
+};
+
+/* Symbol list.  Based on WTX_SYMBOL and WTX_SYMBOL_LIST.  */
+
+struct wtxapi_symbol_list;
+
+struct segment_addresses
+{
+  CORE_ADDR text_addr;
+  CORE_ADDR data_addr;
+  CORE_ADDR bss_addr;
+};
+
+/* Object module information.  Based on WTX_MODULE_INFO.  */
+
+struct wtxapi_module_info
+{
+  /* Protection domain ID.  */
+  pd_id_t pd_id;
+  /* Module ID.  */
+  module_id_t module_id;
+  /* Module name (with path).  */
+  char *module_name;
+  /* Flags used to load module.  */
+  int load_flag;
+  /* Section description.  */
+  struct section_addr_info *section_addrs;
+  /* On older systems (Tornado 2), the system does not provide
+     the section addresses, but rather 3 segment addresses.
+     The following field stores these segment addresses to allow
+     us later to compute each section address.
+
+     On targets where the system does provide us with the section
+     addresses, this field should be unused.  */
+  struct segment_addresses *segments;
+  /* List of undefined symbols.  Only initialized after a 'load' operation.  */
+  struct wtxapi_symbol_list *undef_list;
+};
+
+/* Module ID list.  Based on WTX_MODULE_LIST (WTX 2.0).  */
+
+struct wtxapi_module_list
+{
+  /* Number of module in list.  */
+  int num_obj_mod;
+  /* Arrays of object module id and pd id.  For one index, you have a
+     couple (module id, pd id).  */
+  module_id_t *mod_id_array;
+  pd_id_t *pd_id_array;
+};
+
+/* task context descriptor.  Same as WTX_TASK_CONTEXT_DEF (WTX 3.0) and
+   equivalent to WTX_CONTEXT_DESC (WTX 2.0).  */
+
+struct wtxapi_task_context_desc
+{
+  /* Context PD ID.  */
+  pd_id_t pd_id;
+  /* Integer or double.  */
+  WTX_RETURN_TYPE return_type;
+  /* Task name.  */
+  char *name;
+  /* Priority.  */
+  int priority;
+  /* Options.  */
+  int options;
+  /* Base of stack.  */
+  wtxapi_tgt_addr_t stack_base;
+  /* Stack size.  */
+  int stack_size;
+  /* Context entry point.  */
+  wtxapi_tgt_addr_t entry;
+  /* Redirection in file or NULL.  */
+  INT32 redir_in;
+  /* Redirection out file or NULL.  */
+  INT32 redir_out;
+  /* Redirection error file or NULL.  */
+  INT32 redir_err;
+  /* Arguments.  */
+  int argc;
+  wtxapi_tgt_arg_t *argv;
+};
+
+/* PD context descriptor.  Same on WTX_PD_CONTEXT_DEF (WTX 3.0) and
+   equivalent to WTX_CONTEXT_DESC (WTX 2.0).  */
+
+struct wtxapi_pd_context_desc
+{
+  /* PD name.  */
+  char *name;
+  /* Options.  */
+  int options;
+  /* Size of the PD's heap.  */
+  int heap_size;
+  /* Lowest task's priority.  */
+  int low_priority;
+  /* Highest task's priority.  */
+  int high_priority;
+  /* Page pool list name to use.  */
+  wtxapi_tgt_addr_t page_pool_list;
+  /* Return address to call on deletion.  */
+  wtxapi_tgt_addr_t destroy_rtn;
+  /* Initial link path for this PD.  */
+  char *link_path;
+  /* Redirection in file or NULL.  */
+  INT32 redir_in;
+  /* Redirection out file or NULL.  */
+  INT32 redir_out;
+  /* Redirection error file or NULL.  */
+  INT32 redir_err;
+  /* Extra argument count (in argv).  */
+  int argc;
+  /* Extra argument array.  */
+  wtxapi_tgt_arg_t *argv;
+};
+
+/* Context descriptor.  Based on WTX_CONTEXT_DESC (WTX 3.0).  Different
+   from WTX_CONTEXT_DESC in WTX 2.0.  */
+
+struct wtxapi_context_desc
+{
+  /* Type of context.  */
+  WTX_CONTEXT_TYPE context_type;
+
+  union _wtx_context_def
+  {
+    /* Task context definition.  */
+    struct wtxapi_task_context_desc task_context;
+    /* PD context definition.  */
+    struct wtxapi_pd_context_desc pd_context;
+  } wtx_context_def;
+};
+
+/* Some macro to access the fields of a wtxapi_context_desc */ 
+ 
+#define TASK_CONTEXT_ARGV(context_desc, i) \
+  (context_desc.wtx_context_def.task_context.argv[i]) 
+#define TASK_CONTEXT_ENTRY(context_desc) \
+  (context_desc.wtx_context_def.task_context.entry) 
+#define TASK_CONTEXT_NAME(context_desc) \
+  (context_desc.wtx_context_def.task_context.name) 
+#define TASK_CONTEXT_CONTEXT_TYPE(context_desc) \
+  (context_desc.context_type) 
+#define TASK_CONTEXT_STACK_SIZE(context_desc) \
+  (context_desc.wtx_context_def.task_context.stack_size) 
+#define TASK_CONTEXT_PRIORITY(context_desc) \
+  (context_desc.wtx_context_def.task_context.priority) 
+#define TASK_CONTEXT_OPTIONS(context_desc) \
+  (context_desc.wtx_context_def.task_context.options) 
+#define TASK_CONTEXT_ARGC(context_desc) \
+  (context_desc.wtx_context_def.task_context.argc) 
+#define TASK_CONTEXT_PDID(context_desc) \
+  (context_desc.wtx_context_def.task_context.pd_id) 
+
+/* PD descriptor.  Same as WTX_PD_DESC (WTX 3.0).  */
+
+struct wtxapi_pd_desc
+{
+  /* Protection domain ID.  */
+  pd_id_t pd_id;
+  /* Protection domain name.  */
+  char *pd_name;
+  /* Protection domain flags.  */
+  int pd_flags;
+  /* Link path string.  */
+  char *pd_link_path_str;
+  /* Nb of PD in linkpath.  */
+  int pd_link_path_count;
+  /* PD ids of the linkpath.  */
+  pd_id_t *pd_link_path;
+  int pd_attach_to_count;
+  pd_id_t *pd_attach_to;
+};
+
+/* PD descriptor list.  Same as WTX_PD_DESC_Q (WTX 3.0).  */
+
+struct wtxapi_pd_desc_q
+{
+  struct wtxapi_pd_desc pd_desc;
+  struct wtxapi_pd_desc_q *next;
+};
+
+/* Symbol table info.  Same as WTX_SYM_TBL_INFO (WTX 3.0).  */
+
+struct wtxapi_sym_tbl_info
+{
+  /* Protection domain ID.  */
+  pd_id_t pd_id;
+  /* Number of symbols.  */
+  int sym_num;
+  /* Name clash policy.  */
+  int same_name_ok;
+};
+
+/* Target agent info.  Based on WTX_AGENT_INFO.  */
+
+struct wtxapi_agent_info
+{
+  /* WDB agent version.  */
+  char *agent_version;
+  /* Max transfer size (bytes).  */
+  int mtu;
+  /* Available agent modes.  */
+  int mode;
+};
+
+/* Target runtime information.  Based on WTX_RT_INFO.  */
+
+struct wtxapi_rt_info
+{
+  /* Runtime name.  */
+  char *rt_name;
+  /* Runtime version.  */
+  char *rt_version;
+  /* Target processor type.  */
+  int cpu_type;
+  /* Target cpu variant.  */
+  char *cpu_variant;
+  /* Text write protect available.  */
+  int has_write_protect;
+  /* Size of a page.  */
+  int page_size;
+  /* Endianness (LITTLE or BIG).  */
+  int endian;
+  /* Board support package name.  */
+  char *bsp_name;
+  /* Boot file name.  */
+  char *boot_line;
+  /* Target main memory base address.  */
+  wtxapi_tgt_addr_t mem_base;
+  /* Target main memory size.  */
+  int mem_size;
+  /* Number of memory regions.  */
+  int num_regions;
+  /* Target server memory pool base.  */
+  int host_pool_base;
+  /* Target server memory pool size.  */
+  int host_pool_size;
+};
+
+/* Target information.  Based on WTX_TGT_INFO.  */
+struct wtxapi_tgt_info
+{
+  struct wtxapi_agent_info agent_info;
+  struct wtxapi_rt_info rt_info;
+};
+
+/* Target server information message.  Based on WTX_TS_INFO.  */
+
+struct wtxapi_ts_info
+{
+  /* Target link descriptor.  */
+  WTX_TGT_LINK_DESC tgt_link_desc;
+  /* Info obtained from Target.  */
+  struct wtxapi_tgt_info tgt_info;
+  /* Target Server version.  */
+  char *version;
+  /* Target server user name.  */
+  char *user_name;
+  /* Lock/authorization message.  */
+  char *lock_msg;
+  /* 0 iff the PDs are not initialized.  */
+  int pd_initialized;
+};
+
+/* The data from a context-exit event.  */
+
+struct wtxapi_ctx_exit_event
+{
+  WTX_CONTEXT_ID_T context_id;
+  WTX_CONTEXT_TYPE context_type;
+  int exit_code;
+};
+
+/* The data from a data-access (watchpoint) event.  */
+
+struct wtxapi_data_access_event
+{
+  WTX_CONTEXT_ID_T task_id;
+  WTX_CONTEXT_ID_T context_id;
+  WTX_CONTEXT_TYPE context_type;
+
+  /* The address being watched that triggered the DATA_ACCESS event.  */
+  CORE_ADDR data_addr;
+};
+
+/* The data from an exception event.  */
+
+struct wtxapi_exception_event
+{
+  WTX_CONTEXT_ID_T context_id;
+  WTX_CONTEXT_TYPE context_type;
+  int exception_value;
+};
+
+/* The data from an obj-loaded event.  */
+
+struct wtxapi_obj_loaded_event
+{
+  module_id_t module_id;
+};
+
+/* The data from an obj-unloaded event.  */
+
+struct wtxapi_obj_unloaded_event
+{
+  char *module_filename;
+};
+
+/* The data from a text-access (breakpoint) event.  */
+
+struct wtxapi_text_access_event
+{
+  WTX_CONTEXT_ID_T task_id;
+  WTX_CONTEXT_ID_T context_id;
+  WTX_CONTEXT_TYPE context_type;
+
+  /* The address of the breakpoint that triggered this event.  */
+  CORE_ADDR text_addr;
+};
+
+/* The data from the vio-write event.  */
+
+struct wtxapi_vio_write_event
+{
+  int channel_id;
+  char *data;  /* The contents printed on the virtual IO channel.  */
+};
+
+/* A structure representing the contents of an event received from
+   the target server.  */
+
+struct wtxapi_event_desc
+{
+  WTX_EVENT_TYPE event_type;
+  
+  union
+  {
+    struct wtxapi_ctx_exit_event ctx_exit;
+    struct wtxapi_data_access_event data_access;
+    struct wtxapi_exception_event exception;
+    struct wtxapi_obj_loaded_event obj_loaded;
+    struct wtxapi_obj_unloaded_event obj_unloaded;
+    struct wtxapi_text_access_event text_access;
+    struct wtxapi_vio_write_event vio_write;
+  } desc;
+};
+
+/* The following function are simple wrappers used to resolve the
+   differences between the WTX versions.  Unless specified in the
+   comments, the WTX lib C documentation applies.  If the return type
+   is a WTX type, it should be deallocated using wtxapi_result_free.
+   If it is a type defined in remote-wtxapi.h, it should be deallocate
+   using one of the deallocation function provided in this file.
+
+   Note those differences:
+
+   - when the return type of the WTX function is a STATUS, the wrapper
+   returns an int; in this case, iff the WTX function returns
+   WTX_ERROR, the wrapper returns 0;
+
+   - when the return type of the WTX function is a BOOL32, the wrapper
+   returns an int; in this case, iff the WTX function returns FALSE,
+   the wrapper returns 0.  */
+
+/* Initialize the global WTX client handle.  Only one WTX connection is
+   allowed.  */
+
+extern int wtxapi_initialize ();
+
+/* Return the WTX handle of the current WTX connection.
+   Valid only after a successful call to wtxapi_initialize.  */
+
+extern HWTX wtxapi_get_current_wtx_handle ();
+
+/* Return list of registred services.  NAME_PAT is the reg expression
+   to match svc name.  TYPE_PAT is the reg expression to match svc
+   type.  KEY_PAT is the reg expression to match svc key.  */
+
+extern WTX_DESC_Q *wtxapi_info_q (const char *name_pat, const char *type_pat,
+                                  const char *key_pat);
+
+/* Terminate the use of the global WTX client handle.  */
+
+extern int wtxapi_terminate ();
+
+/* Connect the client to the target server.  */
+
+extern int wtxapi_tool_attach (const char *target_name,
+                               const char *tool_name);
+
+/* Check tool connection to the server.  */
+
+extern int wtxapi_tool_connected ();
+
+/* Detach from the target server.  */
+
+extern int wtxapi_tool_detach ();
+
+/* Clear any error for the tool.  */
+
+extern int wtxapi_err_clear ();
+
+/* Return the version of WTX.  */
+
+extern int wtxapi_version_get ();
+
+/* Return the last error for a handle.  */
+
+extern WTX_ERROR_T wtxapi_err_get ();
+
+/* Add an error handler.  */
+
+extern WTX_HANDLER_T wtxapi_err_handler_add (WTX_HANDLER_FUNC p_func,
+                                             void *p_client_data);
+
+/* Remove an error handler for WTX handle.  */
+
+extern int wtxapi_err_handler_remove (WTX_HANDLER_T p_handler);
+
+/* Fetch the last WTX API error string.  */
+
+extern const char *wtxapi_err_msg_get ();
+
+/* Get the agent mode.  Return invalid_agent_mode if an error occurs.  */
+
+extern WTX_AGENT_MODE_TYPE wtxapi_agent_mode_get ();
+
+/* Set the mode of the target agent.  */
+
+extern int wtxapi_agent_mode_set (WTX_AGENT_MODE_TYPE agent_mode);
+
+/* Create a new breakpoint.  */
+
+extern evtpt_id_t wtxapi_breakpoint_add (WTX_CONTEXT_TYPE context_type,
+                                         WTX_CONTEXT_ID_T context_id,
+                                         wtxapi_tgt_addr_t tgt_addr);
+
+/* Create a new event point.  */
+
+extern evtpt_id_t wtxapi_eventpoint_add (struct wtxapi_evtpt *p_evtpt);
+
+/* Delete eventpoint from the target.  */
+
+extern int wtxapi_eventpoint_delete (evtpt_id_t evtpt_id);
+
+/* Get the next event in the event queue.  */
+
+extern struct wtxapi_event_desc * wtxapi_event_get (void);
+
+/* Get status of a context.  Return invalid_context_status if the operation
+   fails.  */
+
+extern WTX_CONTEXT_STATUS wtxapi_context_status_get
+  (WTX_CONTEXT_TYPE context_type, WTX_CONTEXT_ID_T context_id);
+
+/* Continue execution of target context.  */
+
+extern int wtxapi_context_cont (WTX_CONTEXT_TYPE context_type,
+                                WTX_CONTEXT_ID_T context_id);
+
+/* Create a context on target.
+   - if P_CONTEXT_DESC is invalid, generates WTX_ERR_API_INVALID_ARG;
+   - if another unidentified error occurs, return invalid_context_id;
+   e.g if the operation is not permitted by the kernel.  */
+
+extern WTX_CONTEXT_ID_T wtxapi_context_create
+  (struct wtxapi_context_desc *p_context_desc);
+
+/* Resume execution of a target context.  */
+
+extern int wtxapi_context_resume (WTX_CONTEXT_TYPE context_type,
+                                  WTX_CONTEXT_ID_T context_id);
+
+/* Add exit evpt notification.  */
+
+extern evtpt_id_t wtxapi_context_exit_notify_add
+  (WTX_CONTEXT_TYPE context_type, WTX_CONTEXT_ID_T context_id);
+
+/* Kill a target context.  */
+
+extern int wtxapi_context_kill (WTX_CONTEXT_TYPE context_type,
+                                WTX_CONTEXT_ID_T context_id);
+
+/* Single step exec of target context.  */
+
+extern int wtxapi_context_step (WTX_CONTEXT_TYPE context_type,
+                                WTX_CONTEXT_ID_T context_id,
+                                wtxapi_tgt_addr_t step_start,
+                                wtxapi_tgt_addr_t step_end);
+
+/* Suspend a target context.  */
+
+extern int wtxapi_context_suspend (WTX_CONTEXT_TYPE context_type,
+                                   WTX_CONTEXT_ID_T context_id);
+
+/* Stop (on WTX 3.0) or suspend (on WTX 2.0) a target context.  */
+
+extern int wtxapi_context_stop (WTX_CONTEXT_TYPE context_type,
+                                WTX_CONTEXT_ID_T context_id);
+
+/* List event points on TS.  */
+
+extern struct wtxapi_evtpt_list *wtxapi_eventpoint_list_get ();
+
+/* Free mem allocated by WTX API call.  */
+
+extern int wtxapi_result_free (void *p_result);
+
+/* Evaluate Gopher string on target.  */
+
+extern WTX_GOPHER_TAPE *wtxapi_gopher_eval (pd_id_t pd_id,
+                                            const char *input_string);
+
+/* Get info about memory pool.  */
+
+extern WTX_MEM_INFO *wtxapi_mem_info_get (pd_id_t pd_id);
+
+/* Alloc blocks in memory pool.  */
+
+extern wtxapi_tgt_addr_t wtxapi_mem_alloc (pd_id_t pd_id, int num_bytes);
+
+/* Perform checksum on target memory.  */
+
+extern int wtxapi_mem_checksum (pd_id_t pd_id, wtxapi_tgt_addr_t start_addr,
+                                int num_bytes);
+
+/* Move a block of target memory.  */
+
+extern int wtxapi_mem_move (pd_id_t src_pd_id, wtxapi_tgt_addr_t src_addr,
+                            pd_id_t dst_pd_id, wtxapi_tgt_addr_t dest_addr,
+                            int num_bytes);
+
+/* Free a block of target memory.  */
+
+extern int wtxapi_mem_free (pd_id_t pd_id, wtxapi_tgt_addr_t address);
+
+/* Read memory from the target.  */
+
+extern int wtxapi_mem_read (pd_id_t pd_id, wtxapi_tgt_addr_t from_addr,
+                            void *to_addr, int num_bytes);
+
+/* Read memory on WIDTH bytes.  */
+
+extern int wtxapi_mem_width_read (pd_id_t pd_id, wtxapi_tgt_addr_t from_addr,
+                                  void *to_addr, int num_bytes, int width);
+
+/* Write memory on the target.  */
+
+extern int wtxapi_mem_write (pd_id_t pd_id, void *from_addr,
+                             wtxapi_tgt_addr_t to_addr, int num_bytes);
+
+/* Write memory on the target, on WIDTH bytes large.  */
+
+extern int wtxapi_mem_width_write (pd_id_t pd_id, void *from_addr,
+                                   wtxapi_tgt_addr_t to_addr, int num_bytes,
+                                   int width);
+
+/* Set target memory to given value.  */
+
+extern int wtxapi_mem_set (pd_id_t pd_id, wtxapi_tgt_addr_t addr,
+                           int num_bytes, int val);
+
+/* Add memory to the agent pool.  */
+
+extern int wtxapi_mem_add_to_pool (pd_id_t pd_id, wtxapi_tgt_addr_t address,
+                                   int size);
+
+/* Reallocate a block of target mem.  */
+
+extern wtxapi_tgt_addr_t wtxapi_mem_realloc (pd_id_t pd_id,
+                                             wtxapi_tgt_addr_t address,
+                                             int num_bytes);
+
+/* Allocate aligned target memory.  */
+
+extern wtxapi_tgt_addr_t wtxapi_mem_align (pd_id_t pd_id,
+                                           wtxapi_tgt_addr_t alignment,
+                                           int num_bytes);
+
+/* Scan target memory for pattern.  */
+
+extern int wtxapi_mem_scan (pd_id_t pd_id, int match,
+                            wtxapi_tgt_addr_t start_addr,
+                            wtxapi_tgt_addr_t end_addr,
+                            int num_bytes, void *pattern,
+                            wtxapi_tgt_addr_t * p_result);
+
+/* Checks validity of target memory.  */
+
+extern int wtxapi_obj_module_checksum (pd_id_t pd_id, module_id_t module_id,
+                                       char *module_name);
+
+/* Find obj module ID from name.  */
+
+extern module_id_t wtxapi_obj_module_find_id (pd_id_t pd_id,
+                                              const char *module_name);
+
+/* Return the ID of the module which basename is equal to MODULE_NAME.
+   Search the current PD first, before extending the search to all PDs.  */
+
+extern module_id_t wtxapi_obj_module_in_system_find_id
+  (const char *module_name);
+
+/* Find module name given its ID.  */
+
+extern const char *wtxapi_obj_module_find_name (pd_id_t pd_id,
+                                                module_id_t module_id);
+
+/* Give info on obj module.  */
+
+extern struct wtxapi_module_info
+  *wtxapi_obj_module_info_get (pd_id_t pd_id, module_id_t module_id);
+
+/* List loaded obj modules (wrapper around wtxObjModuleList (WTX 2.0)
+   or wtxObjModuleListGet (WTX 3.0)).  To search on every PD, pd_id
+   should be set to WTX_MOD_FIND_IN_ALL_PD.  */
+
+extern struct wtxapi_module_list *wtxapi_obj_module_list_get (pd_id_t pd_id);
+
+/* Load a new object module.  */
+
+extern struct wtxapi_module_info
+  *wtxapi_obj_module_load (pd_id_t pd_id, char *filename, int load_flag);
+
+extern struct wtxapi_module_info *wtxapi_module_load (pd_id_t pd_id,
+                                                      char *filename,
+                                                      int load_flag,
+                                                      int timeout);
+
+/* Unload an obj module from target.  */
+
+extern int wtxapi_obj_module_unload (pd_id_t pd_id, module_id_t mod_id);
+
+extern int wtxapi_obj_module_by_name_unload (pd_id_t pd_id, char *name);
+
+/* Send events matching expression.  */
+
+extern int wtxapi_register_for_event (const char *reg_exp);
+
+/* Read register data from the target.  */
+
+extern int wtxapi_regs_get (WTX_CONTEXT_TYPE context_type,
+                            WTX_CONTEXT_ID_T context_id,
+                            WTX_REG_SET_TYPE reg_set,
+                            int first_byte, int num_bytes, void *reg_memory);
+
+/* Write to registers on the target.  */
+
+extern int wtxapi_regs_set (WTX_CONTEXT_TYPE context_type,
+                            WTX_CONTEXT_ID_T context_id,
+                            WTX_REG_SET_TYPE reg_set,
+                            int first_byte, int num_bytes, void *reg_memory);
+
+/* Convert str to a wtxapi_tgt_addr_t.  */
+
+extern wtxapi_tgt_addr_t wtxapi_str_to_tgt_addr (const char *str);
+
+/* Convert str to context ID.  */
+
+extern WTX_CONTEXT_ID_T wtxapi_str_to_context_id (const char *str);
+
+/* Convert str ton context type.  */
+
+extern WTX_CONTEXT_TYPE wtxapi_str_to_context_type (const char *str);
+
+/* Convert str to an INT32.  */
+
+extern int wtxapi_str_to_int32 (const char *str);
+
+/* Convert string to event type.  */
+
+extern WTX_EVENT_TYPE wtxapi_str_to_event_type (const char *str);
+
+/* Add symbol with given params.  */
+
+extern int wtxapi_sym_add (pd_id_t pd_id, const char *sym_name,
+                           wtxapi_tgt_addr_t sym_value, int sym_type);
+
+/* Find info on symbol.  Based on wtxSymFind WTX 2.0, with two differences:
+   _ one additional parameter: the protection domain ID (PD_ID);
+   _ no filter on the type.  */
+
+extern struct wtxapi_symbol_list *wtxapi_sym_find (pd_id_t pd_id,
+                                                   char *sym_name,
+                                                   wtxapi_tgt_addr_t sym_value,
+                                                   int exact_name);
+
+/* Get list of symbols.  Based on wtxSymListGet WTX 2.0, with three differences:
+   - one additional parameter: the protection domain ID (PD_ID);
+   - no filter on the unknown symbols;
+   - no filter on the module name/id.  */
+
+extern struct wtxapi_symbol_list
+  *wtxapi_sym_list_get (pd_id_t pd_id, char *substring,
+                        wtxapi_tgt_addr_t value);
+
+/* Get list of symbols.  */
+
+extern struct wtxapi_symbol_list
+  *wtxapi_sym_list_by_module_id_get (pd_id_t pd_id, const char *string,
+                                     module_id_t module_id,
+                                     wtxapi_tgt_addr_t value,
+                                     int list_unknown);
+
+/* Get list of symbols.  */
+
+extern struct wtxapi_symbol_list
+  *wtxapi_sym_list_by_module_name_get (pd_id_t pd_id,
+                                       const char *string,
+                                       const char *module_name,
+                                       wtxapi_tgt_addr_t value,
+                                       int list_unknown);
+
+/* Remove a symbol from sym table.  */
+
+extern int wtxapi_sym_remove (pd_id_t pd_id, const char *sym_name,
+                              int sym_type);
+
+/* Get the symbol table info.  */
+
+extern struct wtxapi_sym_tbl_info *wtxapi_sym_tbl_info_get (pd_id_t pd_id);
+
+/* Reset the target.  */
+
+extern int wtxapi_target_reset ();
+
+/* Get target server name.  */
+
+extern const char *wtxapi_ts_name_get ();
+
+/* Get target-runtime version.  */
+
+extern const char *wtxapi_target_rt_version_get ();
+
+/* Get the target CPU type code.  */
+
+extern int wtxapi_target_cpu_type_get ();
+
+/* Check for floating point processor.  */
+
+extern int wtxapi_target_has_fpp_get ();
+
+/* Get edianness of target.  */
+
+extern WTX_ENDIAN_T wtxapi_target_endian_get ();
+
+/* Get target boot line info.  */
+
+extern const char *wtxapi_target_bootline_get ();
+
+/* Return name of current tool.  */
+
+extern const char *wtxapi_tool_name_get ();
+
+/* Return the Tornado version.  */
+
+extern const char *wtxapi_ts_version_get ();
+
+/* Unregister for some events.  */
+
+extern int wtxapi_unregister_for_event (char *reg_exp);
+
+/* Call func on target within agent.  */
+
+extern int wtxapi_direct_call (wtxapi_tgt_addr_t entry, void *p_ret_val,
+                               wtxapi_tgt_arg_t arg0, wtxapi_tgt_arg_t arg1,
+                               wtxapi_tgt_arg_t arg2, wtxapi_tgt_arg_t arg3,
+                               wtxapi_tgt_arg_t arg4, wtxapi_tgt_arg_t arg5,
+                               wtxapi_tgt_arg_t arg6, wtxapi_tgt_arg_t arg7,
+                               wtxapi_tgt_arg_t arg8, wtxapi_tgt_arg_t arg9);
+
+/* Get info about target and server.  */
+
+extern struct wtxapi_ts_info *wtxapi_ts_info_get ();
+
+/* Reattach to the target.  */
+
+extern int wtxapi_target_attach ();
+
+/* Probe to see if registry is running.  */
+
+extern int wtxapi_probe ();
+
+/* Set WTX timeout.  */
+
+extern int wtxapi_timeout_set (int msec);
+
+/* Get the current timeout.  */
+
+extern int wtxapi_timeout_get (int *p_msec);
+
+/* Create a new protection domain.  */
+
+extern wtxapi_tgt_addr_t wtxapi_pd_create (const char *name, int options,
+                                           int heap_size, int low_priority,
+                                           int high_priority,
+                                           wtxapi_tgt_addr_t page_pool_list,
+                                           const char *link_path);
+
+/* Get kernel Protection Domain ID.  */
+
+extern pd_id_t wtxapi_pd_kernel_get ();
+
+/* Get the current Protection Domain.  */
+
+extern pd_id_t wtxapi_pd_current_get ();
+
+/* Set the current Protection Domain.  */
+
+extern int wtxapi_pd_current_set (pd_id_t pd_id);
+
+/* Get the list of allocated PDs.  */
+
+extern struct wtxapi_pd_desc_q *wtxapi_pd_info_q_get ();
+
+/* Check whether the module has been fully linked or not.  */
+
+extern int wtxapi_load_fully_linked (const struct wtxapi_module_info
+                                     *module_info);
+
+/* Simple additional functions.  */
+
+/* Test target server availability.  */
+
+extern int wtxapi_target_server_available_p ();
+
+/* Symbol list handling.  The symbol list contain a 'current symbol'.
+   This current symbol is used to go through the list.  */
+
+/* Get a copy of the current symbol.  */
+
+extern struct wtxapi_symbol
+  *get_current_wtxapi_symbol (struct wtxapi_symbol_list *list);
+
+
+/* Copy current symbol of LIST into TO.
+
+   OPTIONS is used to avoid uneeded dynamic allocation.
+
+   If OPTIONS is set to wtxapi_symbol_copy_full, the fields name and
+   module_name of TO are null pointers, these string fields of TO are
+   allocated and fully copied from the current symbol, and should be
+   deallocated by the caller.
+
+   If OPTIONS is set to wtxapi_symbol_copy_name (resp.
+   wtxapi_symbol_copy_module_name), the field name (resp. the
+   module_name) of TO is copied.  If not, it is is set to NULL.
+
+   If OPTIONS is set to wtxapi_symbol_copy_none, the field name and
+   module_name of TO are not copied and are set to NULL.  In this case
+   and only in this case no dynamic allocation is performed by this
+   function.  */
+
+extern void copy_current_wtxapi_symbol (struct wtxapi_symbol_list *list,
+                                        struct wtxapi_symbol *to,
+                                        int options);
+
+/* Return the name of the current symbol inside LIST.
+   The result must be deallocated after use.  */
+
+extern char *current_wtxapi_symbol_name (struct wtxapi_symbol_list *list);
+
+/* Change the current symbol to the first element of the list.If there
+   is no next element, return 0.  */
+
+int go_to_first_element_in_wtxapi_sym_list (struct wtxapi_symbol_list *list);
+
+/* Change the current symbol to the next element of the list.  If there
+   is no next element, return 0.  */
+
+int go_to_next_element_in_wtxapi_sym_list (struct wtxapi_symbol_list *list);
+
+/* Deallocation functions for the structures,lists returned by the
+   function defined in this file.  It frees "everything", i.e. it go
+   through every element of the list and deallocate it, and also
+   deallocate strings and arrays referenced by a field.  */
+
+extern void free_wtxapi_evtpt_list (struct wtxapi_evtpt_list *to_free);
+
+extern void free_wtxapi_module_list (struct wtxapi_module_list *to_free);
+
+extern void free_wtxapi_pd_desc_q (struct wtxapi_pd_desc_q *to_free);
+
+extern void free_wtxapi_symbol (struct wtxapi_symbol *to_free);
+
+extern void free_wtxapi_symbol_list (struct wtxapi_symbol_list *to_free);
+
+extern void free_wtxapi_module_info (struct wtxapi_module_info *to_free);
+
+extern void free_wtxapi_ts_info (struct wtxapi_ts_info *to_free);
+
+extern void free_wtxapi_event_desc (struct wtxapi_event_desc *to_free);
+
+/* Stubs for GDB cleanup functions.  */
+
+extern void cleanup_wtxapi_evtpt_list (void *to_free);
+
+extern void cleanup_wtxapi_module_list (void *to_free);
+
+extern void cleanup_wtxapi_pd_desc_q (void *to_free);
+
+extern void cleanup_wtxapi_symbol (void *to_free);
+
+extern void cleanup_wtxapi_symbol_list (void *to_free);
+
+extern void cleanup_wtxapi_module_info (void *to_free);
+
+extern void cleanup_wtxapi_ts_info (void *to_free);
+
+extern void cleanup_wtxapi_result_free (void *to_free);
+
+/* Helpers.  */
+
+int remote_wtxapi_get_symbol_address (char *symbol_name,
+                                      CORE_ADDR *symbol_addr);
+
+int wtxapi_target_has_BoDA (void);
+
+/* A list of threads running on the target system.  */
+
+struct wtxapi_thread_info
+{
+  struct wtxapi_thread_info *next;
+  WTX_CONTEXT_ID_T id;
+  char *name;
+
+  /* The address where the task GP registers are stored when the task
+     is not being executed.  This is necessary to retrieve the registers
+     of this task when in system mode, because wtxapi_regs_get/set
+     will only get/set the registers of the current task (ie the
+     task currently being scheduled by the system).  */
+  CORE_ADDR regs_addr;
+
+  /* Similarly, we need to store the address where the FP registers
+     are stored.  Computing this address requires support from the system,
+     and thus may not be available - in this case, this address should
+     be set to zero.  */
+  CORE_ADDR fp_regs_addr;
+};
+
+extern void free_wtxapi_thread_info (struct wtxapi_thread_info *threads);
+
+/* The WTX protocol does not have all the necessary features needed
+   to implement a remote backend.  So this module relies on other
+   modules provided by the target system (typically a TCL interpreter,
+   or a DFW server).  Unfortunately, which module to use is dependent
+   on the target.  So we maintain a vector with pointers to functions
+   that provide the missing features of WTX.  */
+   
+struct wtxapi_support_ops
+{
+  /* Perform all necessary actions following the establishing of
+     the given WTX connection.  */
+  void (*wtx_connection_established_callback) (HWTX wtx_handle);
+
+  /* Get the list of threads currently running on the target system.  */
+  struct wtxapi_thread_info * (*get_thread_list) (void);
+
+  /* Find the Partition ID of the given task ID.
+     If successful, then set TASK_PD with the result, and return non-zero.
+     Otherwise, return zero and leave the value of TASK_PD undefined.  */
+  int (*get_task_pd) (int task_id, pd_id_t *task_pd);
+
+  /* Return 1 if system-mode is supported, 0 otherwise.  Warn if
+     some features are unsupported.  */
+  int (*system_mode_support_p) (void);
+
+  /* Find the context id of the task currently being executed
+     by the system.  This function assumes that the target is
+     currently running in system mode.  */
+  WTX_CONTEXT_ID_T (*system_mode_get_current_context_id) (void);
+};
+
+extern void wtxapi_set_support_ops (struct wtxapi_support_ops *ops);
+
+extern void wtxapi_notify_connection_established (void);
+
+extern struct wtxapi_thread_info *wtxapi_get_thread_list (void);
+
+extern int wtxapi_get_task_pd (int task_id, pd_id_t *task_pd);
+
+extern int wtxapi_system_mode_support_p (void);
+
+extern WTX_CONTEXT_ID_T wtxapi_system_mode_get_current_context_id (void);
+
+extern int wtxapi_vx_fp_task ();
+
+extern int wtxapi_has_target_variant (const char *variant);
+#endif
-- 
1.6.3.3


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

* Re: [vxworks 13/14] Add tdep files for x86 and powerpc.
  2010-04-25 15:48 ` [vxworks 13/14] Add tdep files for x86 and powerpc Joel Brobecker
@ 2010-04-25 20:45   ` Mark Kettenis
  2010-04-26 16:41     ` Joel Brobecker
  0 siblings, 1 reply; 27+ messages in thread
From: Mark Kettenis @ 2010-04-25 20:45 UTC (permalink / raw)
  To: brobecker; +Cc: gdb-patches

> From: Joel Brobecker <brobecker@adacore.com>
> Date: Sun, 25 Apr 2010 11:47:26 -0400
> 
> 2010-04-24  Joel Brobecker  <brobecker@adacore.com>
> 
>         * defs.h (enum gdb_osabi): Add GDB_OSABI_VXWORKS.
>         * osabi.c (gdb_osabi_names): Add entry for GDB_OSABI_VXWORKS.
>         * i386-vxworks-tdep.c, rs6000-vxworks-tdep.c: New files.
>
> --- /dev/null
> +++ b/gdb/i386-vxworks-tdep.c
> @@ -0,0 +1,53 @@
> +/* Copyright (C) 2007, 2010 Free Software Foundation, Inc.
> +
> +   This file is part of GDB.
> +
> +   This program is free software; you can redistribute it and/or modify
> +   it under the terms of the GNU General Public License as published by
> +   the Free Software Foundation; either version 3 of the License, or
> +   (at your option) any later version.
> +
> +   This program is distributed in the hope that it will be useful,
> +   but WITHOUT ANY WARRANTY; without even the implied warranty of
> +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> +   GNU General Public License for more details.
> +
> +   You should have received a copy of the GNU General Public License
> +   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
> +
> +#include "defs.h"
> +#include "inferior.h"
> +#include "osabi.h"
> +#include "i386-tdep.h"
> +
> +static void
> +i386_vxworks_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
> +{
> +  /* The AT_ENTRY_POINT method is not practical on VxWorks systems,
> +     because there is no concept of "the" executable.  Furthermore,
> +     memory space is shared by all processes (and thus someone
> +     spawning a new task using the same entry point might interfere
> +     with our function call).  So we rely on the ON_STACK method
> +     instead.  */
> +  set_gdbarch_call_dummy_location (gdbarch, ON_STACK);
> +}

Ugh, that means the stack is executable then isn't it?

> +static enum gdb_osabi
> +i386_vxworks_osabi_sniffer (bfd * abfd)
> +{
> +  char *target_name = bfd_get_target (abfd);
> +
> +  if (strstr (target_name, "vxworks") != NULL)
> +    return GDB_OSABI_VXWORKS;
> +
> +  return GDB_OSABI_UNKNOWN;
> +}
> +void
> +_initialize_vxworks_tdep (void)
> +{

Can you insert a blank line between those functions?  With that
change, i386 bits are ok with me.

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

* Re: [vxworks 13/14] Add tdep files for x86 and powerpc.
  2010-04-25 20:45   ` Mark Kettenis
@ 2010-04-26 16:41     ` Joel Brobecker
  0 siblings, 0 replies; 27+ messages in thread
From: Joel Brobecker @ 2010-04-26 16:41 UTC (permalink / raw)
  To: Mark Kettenis; +Cc: gdb-patches

> > +  set_gdbarch_call_dummy_location (gdbarch, ON_STACK);
> > +}
> 
> Ugh, that means the stack is executable then isn't it?

Yep! I see the whole OS as a very bare version of an OS.  There is no
concept of a process, so you just start new threads, and every thread
just happily run without any barrier from the rest of the system (no
virtual memory, no protection from the other threads, etc). It's fine
for certain domains, I suppose, but it's weird when you're not used
to this sort of thing.

> Can you insert a blank line between those functions?  With that
> change, i386 bits are ok with me.

I will do so immediately in the version that we have.

Thanks for the review!

-- 
Joel

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

* Re: [vxworks 02/14] New command_post observer.
  2010-04-25 15:48 ` [vxworks 02/14] New command_post observer Joel Brobecker
@ 2010-04-26 18:51   ` Tom Tromey
  2010-04-27 14:22     ` Joel Brobecker
  0 siblings, 1 reply; 27+ messages in thread
From: Tom Tromey @ 2010-04-26 18:51 UTC (permalink / raw)
  To: Joel Brobecker; +Cc: gdb-patches

>>>>> "Joel" == Joel Brobecker <brobecker@adacore.com> writes:

Joel> The problem is that we cannot just print a message everytime the PD
Joel> gets switched, because many commands result in a temporary switch of
Joel> partition.

Joel> The way we solved this is by remembering the PD ID before we issued
Joel> the last command.  At the end of a command execution, if the PD ID
Joel> changed, then we write a notification...

Joel> This patch introduces an observer (command_post) that gets triggered
Joel> at the end of a command execution...

There are a lot of calls to execute_command that occur in batch-like
places.  For example, this is called from Python, I think it is called
from "commands" scripts and "define" scripts, etc.

So if your goal is to have it just emit info at some stopping point, it
seems to me that it would be better to have an observer just before a
prompt is emitted.

I didn't read every patch in detail, so I didn't see where this is used.
Maybe the above doesn't matter.

Tom

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

* Re: [vxworks 03/14] New module remote-wtx-utils
  2010-04-25 15:48 ` [vxworks 03/14] New module remote-wtx-utils Joel Brobecker
@ 2010-04-26 18:55   ` Tom Tromey
  2010-04-27 16:27     ` Joel Brobecker
  0 siblings, 1 reply; 27+ messages in thread
From: Tom Tromey @ 2010-04-26 18:55 UTC (permalink / raw)
  To: Joel Brobecker; +Cc: gdb-patches

>>>>> "Joel" == Joel Brobecker <brobecker@adacore.com> writes:

Joel> This module provides some general-purpose routines which might be
Joel> better off somewhere else... To be discussed individually for each
Joel> routine.

Joel> +have_dos_based_filesystem (void)
Joel> +is_regular_file (const char *name)
Joel> +skip_whitespaces (char *str)

Just "skip_whitespace" sounds more natural to me.
I think "whitespace" is commonly used for both singular and plural.

I think this particular function has been rewritten (inline) many times
throughout gdb...

Joel> +skip_until_character (char *str, char delimiter)
Joel> +skip_until_whitespace (char *str)
Joel> +skip_space_delimited_token (char *str)
Joel> +get_space_delimited_token (char *str, char **token)

I think all of these (including the others above) could be in util.c.

Joel> +void *load_shared_lib (char *lib_name)

Formatting.

Also, this should mention how errors are to be detected.

Joel> +void *get_symbol_from_shared_lib (void *handle, char *symbol)

Ditto.

Tom

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

* Re: [vxworks 02/14] New command_post observer.
  2010-04-26 18:51   ` Tom Tromey
@ 2010-04-27 14:22     ` Joel Brobecker
  2010-04-27 17:16       ` Tom Tromey
  0 siblings, 1 reply; 27+ messages in thread
From: Joel Brobecker @ 2010-04-27 14:22 UTC (permalink / raw)
  To: Tom Tromey; +Cc: gdb-patches

> There are a lot of calls to execute_command that occur in batch-like
> places.  For example, this is called from Python, I think it is called
> from "commands" scripts and "define" scripts, etc.
> 
> So if your goal is to have it just emit info at some stopping point, it
> seems to me that it would be better to have an observer just before a
> prompt is emitted.
> 
> I didn't read every patch in detail, so I didn't see where this is used.
> Maybe the above doesn't matter.

Either way would work, as far as I am concerned.  The purpose is to
inform the user that the context (partition) has changed.  I have
a tiny preference towards having consistent output, if we can, with
commands executed from the prompt and commands executed from elsewhere
such as user-defined commands for instance. But that preference really
has no additional technical merit that I can think of, so I'm happy to
change the observer to use something triggered just before printing
the command prompt (btw: it does not matter in this case, but I believe
that the prompt also gets printed as "> " while entering a canned
sequence of command).

-- 
Joel

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

* Re: [vxworks 03/14] New module remote-wtx-utils
  2010-04-26 18:55   ` Tom Tromey
@ 2010-04-27 16:27     ` Joel Brobecker
  0 siblings, 0 replies; 27+ messages in thread
From: Joel Brobecker @ 2010-04-27 16:27 UTC (permalink / raw)
  To: Tom Tromey; +Cc: gdb-patches

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

Hi Tom,

Thanks much for the feedback!


> Just "skip_whitespace" sounds more natural to me.
> I think "whitespace" is commonly used for both singular and plural.

Fixed.

> Joel> +skip_until_character (char *str, char delimiter)
> Joel> +skip_until_whitespace (char *str)
> Joel> +skip_space_delimited_token (char *str)
> Joel> +get_space_delimited_token (char *str, char **token)
> 
> I think all of these (including the others above) could be in util.c.

Agreed - moved thusly.

> Joel> +void *load_shared_lib (char *lib_name)
> 
> Formatting.
> 
> Also, this should mention how errors are to be detected.

All fixed.  These two routines are the two left in remote-wtx-utils
after the exercise. I was thinking of moving them to a non-wtx context,
but it turns out I forgot that one of them (load_shared_lib) is more
than just a dlopen wrapper. What I had forgotten is that function takes
a library name (eg: "wtx40", and build the DSO filename depending on
the host filesystem -> either libwtx40.so or wtx40.dll). It would have
been too easy if it was just a matter of using a .so vs .dll extension...
So it really belongs in a vxworks-specific unit.

I thought it might have been useful to have a gdb_dlfcn.h module that
abstracts out shared library support. It's relatively easy to write,
the code itself, but it's the packaging that raises questions. See the
revision history that I wrote for patch 0003.2 (attached).  In any case,
I made it easier for this to happen, when/if we want to.

Here are 2 new patches, replacing patch 0003...

-- 
Joel

[-- Attachment #2: 0003.1-new-general-purpose-routines-in-utils.diff --]
[-- Type: text/x-diff, Size: 5160 bytes --]

commit 6a619bbabb16472cfc4e9ba41758a43cc8bbfd5e
Author: Joel Brobecker <brobecker@adacore.com>
Date:   Tue Apr 27 11:12:43 2010 -0400

    New general purpose routines in utils.c
    
    These are some general-purpose routines that were added for the VxWorks
    port...  Hopefully other parts of the GDB code will make use of them.
    
    2010-04-27  Joel Brobecker  <brobecker@adacore.com>
    
            * utils.c (have_dos_based_filesystem, is_regular_file)
            (skip_whitespace, skip_until_character, skip_until_whitespace)
            (skip_space_delimited_token, get_space_delimited_token): New functions.
            * source.c (is_regular_file): Delete.  Moved to utils.c.
            * defs.h (have_dos_based_filesystem, is_regular_file)
            (skip_whitespace, skip_until_character, skip_space_delimited_token)
            (get_space_delimited_token): Add declaration.

diff --git a/gdb/defs.h b/gdb/defs.h
index e8a1dd4..0d84170 100644
--- a/gdb/defs.h
+++ b/gdb/defs.h
@@ -432,6 +432,18 @@ extern const char *gdb_bfd_errmsg (bfd_error_type error_tag, char **matching);
 
 extern int parse_pid_to_attach (char *args);
 
+extern int have_dos_based_filesystem (void);
+
+extern int is_regular_file (const char *name);
+
+extern char *skip_whitespace (char *str);
+
+extern char *skip_until_character (char *str, char delimiter);
+
+extern char *skip_space_delimited_token (char *str);
+
+extern char *get_space_delimited_token (char *str, char **token);
+
 /* From demangle.c */
 
 extern void set_demangling_style (char *);
diff --git a/gdb/source.c b/gdb/source.c
index 47caa14..1e4107b 100644
--- a/gdb/source.c
+++ b/gdb/source.c
@@ -622,24 +622,6 @@ source_info (char *ignore, int from_tty)
 }
 \f
 
-/* Return True if the file NAME exists and is a regular file */
-static int
-is_regular_file (const char *name)
-{
-  struct stat st;
-  const int status = stat (name, &st);
-
-  /* Stat should never fail except when the file does not exist.
-     If stat fails, analyze the source of error and return True
-     unless the file does not exist, to avoid returning false results
-     on obscure systems where stat does not work as expected.
-   */
-  if (status != 0)
-    return (errno != ENOENT);
-
-  return S_ISREG (st.st_mode);
-}
-
 /* Open a file named STRING, searching path PATH (dir names sep by some char)
    using mode MODE in the calls to open.  You cannot use this function to
    create files (O_CREAT).
diff --git a/gdb/utils.c b/gdb/utils.c
index e225a3f..cac312f 100644
--- a/gdb/utils.c
+++ b/gdb/utils.c
@@ -3673,6 +3673,116 @@ parse_pid_to_attach (char *args)
   return pid;
 }
 
+/* Return non-zero if the host has a dos-based file system.  */
+
+int
+have_dos_based_filesystem (void)
+{
+#ifdef HAVE_DOS_BASED_FILE_SYSTEM
+  return 1;
+#else
+  return 0;
+#endif
+}
+
+/* Return True if the file NAME exists and is a regular file.  */
+
+int
+is_regular_file (const char *name)
+{
+  struct stat st;
+  const int status = stat (name, &st);
+
+  /* Stat should never fail except when the file does not exist.
+     If stat fails, analyze the source of error and return True
+     unless the file does not exist, to avoid returning false results
+     on obscure systems where stat does not work as expected.  */
+  if (status != 0)
+    return (errno != ENOENT);
+
+  return S_ISREG (st.st_mode);
+}
+
+/* Return a pointer to the first non-whitepace character found
+   in the string.  A whitespace is either a space or a tab.  */
+
+char *
+skip_whitespace (char *str)
+{
+  char *index = str;
+
+  while (*index == ' ' || *index == '\t')
+    index++;
+
+  return index;
+}
+
+/* Return a pointer to the first DELIMITER character in the given
+   string.  Return a pointer to the end-of-line character if
+   DELIMITER was not found.  */
+
+char *
+skip_until_character (char *str, char delimiter)
+{
+  char *index = str;
+
+  while (*index != delimiter && *index != '\0')
+    index++;
+
+  return index;
+}
+
+/* return a pointer to the first whitespace character.  If no whitespace
+   is found before the end of string, a pointer to the end of string
+   is returned.  A whitespace is either a space or a tab.  */
+
+static char *
+skip_until_whitespace (char *str)
+{
+  char *index = str;
+
+  while (*index != ' ' && *index != '\t' && *index != '\0')
+    index++;
+
+  return index;
+}
+
+/* Return a pointer to the first white space after the next
+   whitespace-delimited token.  */
+
+char *
+skip_space_delimited_token (char *str)
+{
+  char *index = str;
+
+  index = skip_whitespace (index);
+  index = skip_until_whitespace (index);
+
+  return index;
+}
+
+/* Copy the next whitespace token into TOKEN.  This string will be
+   allocated using malloc, and must be dealocated later.  */
+
+char *
+get_space_delimited_token (char *str, char **token)
+{
+  char *start;
+  char *end;
+  char tmp;
+
+  start = skip_whitespace (str);
+  end = skip_until_whitespace (start);
+
+  tmp = *end;
+  *end = '\0';
+  *token = xstrdup (start);
+  *end = tmp;
+
+  return end;
+}
+
+
 /* Provide a prototype to silence -Wmissing-prototypes.  */
 extern initialize_file_ftype _initialize_utils;
 

[-- Attachment #3: 0003.2-new-module-remote-wtx-utils.diff --]
[-- Type: text/x-diff, Size: 5723 bytes --]

commit ea576c2d84a757e64871bf61b659a1481da100ee
Author: Joel Brobecker <brobecker@adacore.com>
Date:   Sat Apr 24 11:26:24 2010 -0400

    [vxworks] New module remote-wtx-utils
    
    This module provides a couple of routines to deal with loading the
    VxWorks host-side shared libraries, such as the WTX library for instance.
    
    I rewrote a bit the routines to depend on two functions gdb_dlopen and
    gdb_dlsym which we could isolate in its own gdb_dlfcn.h/c if we wanted to.
    But since this is used only when adding the vxworks target, I kept these
    routines local for now - otherwise, it opens the door for questions such
    as: What do we do when these are not defined? Should we fail the configure
    even though chances are these routines might not be actually needed for
    the build? Or do we fail the configure only when they are in fact needed
    (ideal, but harder to maintain I believe), or do we just fail at link
    time (a bit ugly but much easier to implement)?  For now, I don't think
    we really need to answer these questions, but I wrote the code in a way
    that it makes it easy to extract the code and create the module if we
    ever need to.
    
    2010-04-27  Joel Brobecker  <brobecker@adacore.com>
    
            * remote-wtx-utils.h, remote-wtx-utils.c: New files.

diff --git a/gdb/remote-wtx-utils.c b/gdb/remote-wtx-utils.c
new file mode 100644
index 0000000..0a282bc
--- /dev/null
+++ b/gdb/remote-wtx-utils.c
@@ -0,0 +1,101 @@
+/* Support for the WTX protocol.
+
+   Copyright (C) 2007, 2010 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#include "defs.h"
+#include "remote-wtx-utils.h"
+#include "gdb_string.h"
+#ifdef HAVE_LIBDL
+#include <dlfcn.h>
+#elif __MINGW32__
+#include <windows.h>
+#else
+/* Unsupported configuration.  See Eg. gdb_dlopen for details.  */
+#error API to load shared library missing (Eg. libdl)
+#endif
+
+/* Load the dynamic library file named FILENAME, and return a handle
+   for that dynamic library.  Return NULL if the loading fails for
+   any reason.  */
+
+static void *
+gdb_dlopen (const char *filename)
+{
+#ifdef HAVE_LIBDL
+  return dlopen (filename, RTLD_NOW);
+#elif __MINGW32__
+  return (void *) LoadLibrary (filename);
+#endif
+}
+
+/* Return the address of the symbol named SYMBOL inside the shared library
+   whose handle is HANDLE.  Return NULL when the symbol could not be found.  */
+
+static void *
+gdb_dlsym(void *handle, const char *symbol)
+{
+#ifdef HAVE_LIBDL
+  return dlsym (handle, symbol);
+#elif __MINGW32__
+  return (void *) GetProcAddress (handle, symbol);
+#endif
+}
+
+/* Load the shared library whose name is LIB_NAME and return a handle
+   on it.  Return NULL if the library could not be loaded.
+
+   Note that this name correspond to a different file name depending on
+   the host; for example, the name "wtxapi40" would identify libwtxapi40.so
+   on linux and solaris, whereas it would identify wtxapi40.dll.  */
+
+void *
+load_shared_lib (char *lib_name)
+{
+  const char dos_suffix [] = ".dll";
+  const char unix_prefix[] = "lib";
+  const char unix_suffix [] = ".so";
+  char *filename;
+
+  if (have_dos_based_filesystem ())
+    {
+      filename = (char *) alloca (strlen (lib_name) + strlen (dos_suffix) + 1);
+      strcpy (filename, lib_name);
+      strcat (filename, dos_suffix);
+    }
+  else
+    {
+      filename = (char *) alloca (strlen (unix_prefix)
+				  + strlen (lib_name)
+				  + strlen (unix_suffix) + 1);
+      strcpy (filename, unix_prefix);
+      strcat (filename, lib_name);
+      strcat (filename, unix_suffix);
+    }
+
+  return gdb_dlopen (filename);
+}
+
+/* Get the address of SYMBOL in a shared library identified
+   by HANDLE (HANDLE is the value returned by load_shared_lib
+   for this library).  */
+
+void *
+get_symbol_from_shared_lib (void *handle, char *symbol)
+{
+  return gdb_dlsym (handle, symbol);
+}
diff --git a/gdb/remote-wtx-utils.h b/gdb/remote-wtx-utils.h
new file mode 100644
index 0000000..24a03b1
--- /dev/null
+++ b/gdb/remote-wtx-utils.h
@@ -0,0 +1,27 @@
+/* Support for the WTX protocol.
+
+   Copyright (C) 2007, 2010 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#ifndef REMOTE_WTX_UTILS_H
+#define REMOTE_WTX_UTILS_H
+
+extern void *load_shared_lib (char *lib_name);
+
+extern void *get_symbol_from_shared_lib (void *handle, char *symbol);
+
+#endif

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

* Re: [vxworks 02/14] New command_post observer.
  2010-04-27 14:22     ` Joel Brobecker
@ 2010-04-27 17:16       ` Tom Tromey
  0 siblings, 0 replies; 27+ messages in thread
From: Tom Tromey @ 2010-04-27 17:16 UTC (permalink / raw)
  To: Joel Brobecker; +Cc: gdb-patches

>>>>> "Joel" == Joel Brobecker <brobecker@adacore.com> writes:

>> There are a lot of calls to execute_command that occur in batch-like
>> places.  For example, this is called from Python, I think it is called
>> from "commands" scripts and "define" scripts, etc.
>> 
>> So if your goal is to have it just emit info at some stopping point, it
>> seems to me that it would be better to have an observer just before a
>> prompt is emitted.

Joel> Either way would work, as far as I am concerned.  The purpose is to
Joel> inform the user that the context (partition) has changed.  I have
Joel> a tiny preference towards having consistent output, if we can, with
Joel> commands executed from the prompt and commands executed from elsewhere
Joel> such as user-defined commands for instance. But that preference really
Joel> has no additional technical merit that I can think of, so I'm happy to
Joel> change the observer to use something triggered just before printing
Joel> the command prompt (btw: it does not matter in this case, but I believe
Joel> that the prompt also gets printed as "> " while entering a canned
Joel> sequence of command).

I think the ">" thing indicates a misunderstanding.  I was talking about
when various command scripts are executed, not when they are entered.

E.g., suppose there are commands in a "define" that change the
partition, do some work, and then change it back.  With the observer as
it now stands, the user will see multiple notifications.  If the
observer were just before the prompt, only one notification would be
emitted.

Maybe there's no way for user commands to change the partition.  That
would render this consideration irrelevant.

Also, if this doesn't matter to you, then it is also fine by me.

Tom

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

* Re: Adding support for VxWorks target
  2010-04-25 15:47 Adding support for VxWorks target Joel Brobecker
                   ` (13 preceding siblings ...)
  2010-04-25 16:01 ` [vxworks 04/14] remote-wtxapi: The WTX API abstraction layer Joel Brobecker
@ 2010-05-04 14:58 ` Joel Brobecker
  2010-05-04 15:43   ` Stan Shebs
  2010-11-25  0:53 ` Adding support for VxWorks target Joel Brobecker
  15 siblings, 1 reply; 27+ messages in thread
From: Joel Brobecker @ 2010-05-04 14:58 UTC (permalink / raw)
  To: gdb-patches

Hello,

> The following series of patches adds support for cross debugging
> VxWorks targets (version 5.x, 6.x and limited support for VxWorks 653).
> It's a lot of code overall, and many patches, but it is almost
> completely contained in dedicated files, and we've split the changes
> in modules/patches, hoping to make it easier for anyone wanting to
> look at them.

Just wondering what the general sentiment is towards these patches?
I just did a resync at AdaCore, and noticed a break due to the various
attribute changes. It's not big deal to fix those, but now I have to
do keep two sets of patches up to date...

If people are indifferent/interested, then I'd like to look at checking in
the series sometime soonish - and I would work on doco in the meantime.

Cheers!
-- 
Joel

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

* Re: [vxworks 05/14] Add options to control Vxworks related settings.
  2010-04-25 15:56 ` [vxworks 05/14] Add options to control Vxworks related settings Joel Brobecker
@ 2010-05-04 15:25   ` Joel Brobecker
  0 siblings, 0 replies; 27+ messages in thread
From: Joel Brobecker @ 2010-05-04 15:25 UTC (permalink / raw)
  To: gdb-patches

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

Hello,

> 2010-04-23  Joel Brobecker  <brobecker@adacore.com>
> 
>         * remote-wtx-opt.h, remote-wtx-opt.c: New files.

Attached is a new version of this file, following the removal of
ATTR_FORMAT... (a very minimal change compared to the first version).

-- 
Joel

[-- Attachment #2: 0005-vxworks-add-options-to-control-Vxworks-related-set.patch --]
[-- Type: text/x-diff, Size: 13456 bytes --]

2010-04-23  Joel Brobecker  <brobecker@adacore.com>

        * remote-wtx-opt.h, remote-wtx-opt.c: New files.
---
 gdb/remote-wtx-opt.c |  323 ++++++++++++++++++++++++++++++++++++++++++++++++++
 gdb/remote-wtx-opt.h |   46 +++++++
 2 files changed, 369 insertions(+), 0 deletions(-)
 create mode 100644 gdb/remote-wtx-opt.c
 create mode 100644 gdb/remote-wtx-opt.h

diff --git a/gdb/remote-wtx-opt.c b/gdb/remote-wtx-opt.c
new file mode 100644
index 0000000..70910b6
--- /dev/null
+++ b/gdb/remote-wtx-opt.c
@@ -0,0 +1,323 @@
+/* Support for the WTX protocol.
+
+   This unit provides a user interface to various settings which are
+   related to the WTX protocol.  We also provide several debug switches
+   that the user can use to turn on some debugging traces.
+
+   Copyright (C) 2007, 2010 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#include "defs.h"
+#include "command.h"
+#include "gdbcmd.h"
+#include "remote-wtx-opt.h"
+#include "remote-wtxapi.h"
+
+/* The various settings that affect the the WTX protocol will be
+   accessible through the "set/show wtx" command prefix.  The following
+   cmd_list_element variables contain the list of commands accessible
+   under that prefix.  */
+
+static struct cmd_list_element *set_wtx_list = NULL;
+static struct cmd_list_element *show_wtx_list = NULL;
+
+/* The various debug switches are accessible through the "set/show wtx
+   debug" command prefix.  The following cmd_list_element variables
+   contain the list of commands accessible under that prefix.  */
+
+static struct cmd_list_element *set_wtx_debug_list = NULL;
+static struct cmd_list_element *show_wtx_debug_list = NULL;
+
+/* The name we use to identify ourselves when we connect to
+   the target server.  The default value is allocated during
+   this file initialization phase.  */
+static char *tool_name = NULL;
+
+/* The module load timeout in seconds.  */
+static int load_timeout = 30;
+
+/* The stack size in bytes used when spawning a new process.  */
+static int stack_size = 0x10000;
+
+/* The options used when spawning a new process.  */
+static int task_options = 0;
+
+/* The priority used when spawning a new process.  */
+static int task_priority = 100;
+
+/* Set to non-zero to print debug traces of the events received by GDB.  */
+static int debug_events_level = 0;
+
+/* Set to non-zero to print debug traces related to watchpoint support.  */
+static int debug_watchpoints = 0;
+
+/* Set to non-zero to print debug traces of the operations involving
+   objfile manipuations.  */
+static int debug_objfiles = 0;
+
+/* If set to non-zero, then the user wants to see more verbose error
+   messages when the TCL interpreter failed to evaluate a command.  */
+static int debug_tcl = 0;
+
+/* Accessor for TOOL_NAME.  */
+
+char *
+wtx_opt_tool_name (void)
+{
+  return tool_name;
+}
+
+/* Accessor for LOAD_TIMEOUT.  */
+
+int
+wtx_opt_load_timeout (void)
+{
+  return load_timeout;
+}
+
+int
+wtx_opt_stack_size (void)
+{
+  return stack_size;
+}
+
+int
+wtx_opt_task_options (void)
+{
+  return task_options;
+}
+
+/* Init task options using the target information.  */
+
+void
+wtx_opt_init_task_options (void)
+{
+  const int VX_FP_TASK = wtxapi_vx_fp_task ();
+  const int VX_SPE_TASK = 0x04000000;
+
+  /* If the target has a floating-point processor, then set the
+     floating-point option flag.  */
+  if (wtxapi_target_has_fpp_get ())
+    task_options |= VX_FP_TASK;
+
+  /* If the target is e500v2, the SPE APU should be enabled to run
+     floating point programs.
+     
+     FIXME: guitton/2009-07-20: In VxWorks 6.6, there is no way to
+     discriminate between e500 and e500v2: both have the same cpu
+     variant "ppc85XX".  As we only support e500v2, it is fine to
+     assume that PPC85XX actually means e500v2...  For now.  But
+     it is not in the general case.  The problem is fixed in Vxworks
+     6.7, so we may get rid of this kludge at some point.  */
+  if (wtxapi_has_target_variant ("_e500v2")
+      || wtxapi_has_target_variant ("_ppc85XX"))
+    task_options |= VX_SPE_TASK;
+}
+
+int
+wtx_opt_task_priority (void)
+{
+  return task_priority;
+}
+
+/* Accessor for DEBUG_TCL  */
+
+int
+wtx_opt_tcl_verbose_p (void)
+{
+  return debug_tcl;
+}
+
+/* Print a debug message if DEBUG_OBJFILES is non-zero.
+   The message uses the string FORMAT and all the associated parameters, 
+   following the printf syntax.  */
+
+void
+wtx_opt_objfiles_debug (const char *format, ...)
+{
+  if (debug_objfiles)
+    {
+      va_list args;
+
+      va_start (args, format);
+      printf_filtered ("DEBUG (objfiles): ");
+      vprintf_filtered (format, args);
+      printf_filtered ("\n");
+      va_end (args);
+    }
+}
+
+/* Print a debug message if DEBUG_EVENTS is non-zero.
+   The message uses the string FORMAT and all the associated parameters, 
+   following the printf syntax.  */
+
+void
+wtx_opt_events_debug (int level, const char *format, ...)
+{
+  if (debug_events_level >= level)
+    {
+      va_list args;
+
+      va_start (args, format);
+      printf_filtered ("DEBUG (events): ");
+      vprintf_filtered (format, args);
+      printf_filtered ("\n");
+      va_end (args);
+    }
+}
+
+void wtx_opt_watchpoints_debug (const char *format, ...)
+{
+  if (debug_watchpoints)
+    {
+      va_list args;
+
+      va_start (args, format);
+      printf_filtered ("DEBUG (watchpoints): ");
+      vprintf_filtered (format, args);
+      printf_filtered ("\n");
+      va_end (args);
+    }
+}
+
+/* Implement the "set wtx" command.
+   This is not actually a valid command, so inform the user of that fact,
+   and print the list of valid subcommands to help him.  */
+
+static void
+set_wtx_command (char *args, int from_tty)
+{
+  printf_filtered (_("\"set wtx\" must be followed by a subcommand.\n"));
+  help_list (set_wtx_list, "set wtx ", -1, gdb_stdout);
+}
+
+/* Implement the "show wtx" command: Print the value of all settings
+   available through that command prefix.  */
+
+static void
+show_wtx_command (char *args, int from_tty)
+{
+  cmd_show_list (show_wtx_list, from_tty, "");
+}
+
+/* Implement the "set wtx debug" command.
+   This is not actually a valid command, so inform the user of that fact,
+   and print the list of valid subcommands to help him.  */
+
+static void
+set_wtx_debug_command (char *args, int from_tty)
+{
+  printf_filtered (_("\"set wtx debug\" must be followed by a subcommand.\n"));
+  help_list (set_wtx_debug_list, "set wtx debug", -1, gdb_stdout);
+}
+
+/* Implement the "show wtx" command: Print the value of all settings
+   available through that command prefix.  */
+
+static void
+show_wtx_debug_command (char *args, int from_tty)
+{
+  cmd_show_list (show_wtx_debug_list, from_tty, "");
+}
+
+void
+_initialize_remote_wtx_opt (void)
+{
+  tool_name = xstrdup ("gdb");
+
+  /* Various "set/show" switches.  */
+  add_prefix_cmd ("wtx", no_class, set_wtx_command, _("\
+Adjust various settings specific to the WTX protocol."), &set_wtx_list,
+                  "set wtx ", 0 /* allow_unknown */, &setlist);
+  add_prefix_cmd ("wtx", no_class, show_wtx_command, _("\
+Print various settings specific to the WTX protocol."), &show_wtx_list,
+                  "show wtx ", 0 /* allow_unknown */, &showlist);
+
+  add_setshow_string_noescape_cmd ("tool-name", class_support,
+                                   &tool_name, _("\
+Set the tool name used when connecting to the target server."), _("\
+Show the tool name used when connecting to the target server."), NULL,
+                                   NULL, NULL,
+                                   &set_wtx_list, &show_wtx_list);
+
+  add_setshow_integer_cmd ("load-timeout", class_support,
+                           &load_timeout, _("\
+Set the timeout in seconds when loading new modules on the target."), _("\
+Show the timeout in seconds when loading new modules on the target."), _("\
+Use this setting to adjust the maximum duration that loading a module\n\
+on the target can take before a timeout aborts the operation."),
+                           NULL, NULL, &set_wtx_list, &show_wtx_list);
+
+  add_setshow_zinteger_cmd ("stack-size", class_support,
+                           &stack_size, _("\
+Set the stack size in bytes for tasks spawned by the debugger."), _("\
+Show the stack size in bytes for tasks spawned by the debugger.."), _("\
+Use this setting to adjust the stack size of new tasks."),
+                           NULL, NULL, &set_wtx_list, &show_wtx_list);
+
+  add_setshow_zinteger_cmd ("task-options", class_support,
+                           &task_options, _("\
+Set the options of new tasks spawned by the debugger."), _("\
+Show the options of new tasks spawned by the debugger.."), _("\
+Use this setting to change the options used when spawning new tasks."),
+                           NULL, NULL, &set_wtx_list, &show_wtx_list);
+
+  add_setshow_zinteger_cmd ("task-priority", class_support,
+                           &task_priority, _("\
+Set the priority of new tasks spawned by the debugger."), _("\
+Show the priority of new tasks spawned by the debugger.."), _("\
+Use this setting to change the priority used when spawning new tasks."),
+                           NULL, NULL, &set_wtx_list, &show_wtx_list);
+
+  /* Various debug switches for WTX.  */
+  add_prefix_cmd ("debug", no_class, set_wtx_debug_command, _("\
+Adjust various settings specific to the WTX protocol."), &set_wtx_debug_list,
+                  "set wtx debug ", 0 /* allow_unknown */, &set_wtx_list);
+  add_prefix_cmd ("debug", no_class, show_wtx_debug_command, _("\
+Print various settings specific to the WTX protocol."), &show_wtx_debug_list,
+                  "show wtx debug ", 0 /* allow_unknown */, &show_wtx_list);
+
+  add_setshow_zinteger_cmd ("events", class_maintenance,
+                            &debug_events_level, _("\
+Print debug traces related to WTX event handling."), _("\
+Debug traces related to WTX event handling."),
+                            NULL, NULL, NULL, &set_wtx_debug_list,
+                            &show_wtx_debug_list);
+
+  add_setshow_boolean_cmd ("objfiles", class_maintenance,
+                           &debug_objfiles, _("\
+Print debug traces related to objfile handling for WTX."), _("\
+Debug traces related to objfile handling for WTX."),
+                           NULL, NULL, NULL, &set_wtx_debug_list,
+                           &show_wtx_debug_list);
+
+  add_setshow_boolean_cmd ("watchpoints", class_maintenance,
+                           &debug_watchpoints, _("\
+Print debug traces related to WTX watchpoint handling."), _("\
+Debug traces related to WTX watchpoint handling."),
+                           NULL, NULL, NULL, &set_wtx_debug_list,
+                           &show_wtx_debug_list);
+
+  add_setshow_boolean_cmd ("tcl", class_maintenance,
+                           &debug_tcl, _("\
+Set the verbosity of the error messages from the TCL interpreter."), _("\
+Show the verbosity of the error messages from the TCL interpreter."), _("\
+When set, the TCL interpreter prints more verbose error messages"),
+                           NULL, NULL,
+                           &set_wtx_debug_list, &show_wtx_debug_list);
+
+}
diff --git a/gdb/remote-wtx-opt.h b/gdb/remote-wtx-opt.h
new file mode 100644
index 0000000..eff67d4
--- /dev/null
+++ b/gdb/remote-wtx-opt.h
@@ -0,0 +1,46 @@
+/* Copyright (C) 2007, 2010 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#ifndef REMOTE_WTX_OPT_H
+#define REMOTE_WTX_OPT_H
+
+char *wtx_opt_tool_name (void);
+
+int wtx_opt_load_timeout (void);
+
+int wtx_opt_stack_size (void);
+
+int wtx_opt_task_options (void);
+
+void wtx_opt_init_task_options (void);
+
+int wtx_opt_task_priority (void);
+
+int wtx_opt_tcl_verbose_p (void);
+
+/* Support for debugging traces.  */
+
+void wtx_opt_objfiles_debug (const char *format, ...)
+  ATTRIBUTE_PRINTF (1, 2);
+
+void wtx_opt_events_debug (int level, const char *format, ...)
+  ATTRIBUTE_PRINTF (2, 3);
+
+void wtx_opt_watchpoints_debug (const char *format, ...)
+  ATTRIBUTE_PRINTF (1, 2);
+
+#endif
-- 
1.5.4.3


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

* Re: Adding support for VxWorks target
  2010-05-04 14:58 ` Adding support for VxWorks target Joel Brobecker
@ 2010-05-04 15:43   ` Stan Shebs
  2010-05-04 18:30     ` one big unit or several smaller units? (was: "Re: Adding support for VxWorks target") Joel Brobecker
  0 siblings, 1 reply; 27+ messages in thread
From: Stan Shebs @ 2010-05-04 15:43 UTC (permalink / raw)
  To: Joel Brobecker; +Cc: gdb-patches

Joel Brobecker wrote:
> Hello,
>
>   
>> The following series of patches adds support for cross debugging
>> VxWorks targets (version 5.x, 6.x and limited support for VxWorks 653).
>> It's a lot of code overall, and many patches, but it is almost
>> completely contained in dedicated files, and we've split the changes
>> in modules/patches, hoping to make it easier for anyone wanting to
>> look at them.
>>     
>
> Just wondering what the general sentiment is towards these patches?
> I just did a resync at AdaCore, and noticed a break due to the various
> attribute changes. It's not big deal to fix those, but now I have to
> do keep two sets of patches up to date...
>   

I skimmed, and didn't see anything problematic.  Organizationwise, my 
personal preference would to be have fewer files that are "everything 
wtx", which in turns reduces the amount of headers / header files.  It 
also forestalls some grumbles about long filenames from DOS-land. :-)  
But don't feel compelled to glom them together, if you prefer multiple 
files.

Stan


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

* one big unit or several smaller units? (was: "Re: Adding support for VxWorks target")
  2010-05-04 15:43   ` Stan Shebs
@ 2010-05-04 18:30     ` Joel Brobecker
  0 siblings, 0 replies; 27+ messages in thread
From: Joel Brobecker @ 2010-05-04 18:30 UTC (permalink / raw)
  To: Stan Shebs; +Cc: gdb-patches

[changed the subject for this sub-thread]

> I skimmed, and didn't see anything problematic.

Thanks for looking at them!

> Organizationwise, my personal preference would to be have fewer files
> that are "everything wtx", which in turns reduces the amount of
> headers / header files.  It also forestalls some grumbles about long
> filenames from DOS-land. :-)  But don't feel compelled to glom them
> together, if you prefer multiple files.

It's interesting that you'd say that; I am the total opposite. I don't
mind the extra headers - I think it makes the public/private API clearer.

In fact, funny story: Jerome and I were in NY discussing some recent
breakage in the debugger, and we both said that, while GDB's code has
improved tremendously, some areas are still pretty horrible. After
being asked for examples, I mentioned a few areas, but after a couple
of minutes, Jerome said that one of the worst areas has got to be...
ada-lang! And, oh yeah, it has to be one of the worst... ;-)

And that brings me back to the original thought. I have always wanted
to spend the time to break ada-lang into smaller modules. For instance,
one module to deal with the GNAT encoding and provide a layer that
insulates the rest of the code from it. Another module to handle
expression evaluation. etc.  Given that ada-lang is over 10,000 lines
of code (actually 13,000 lines), I think it's pretty much the only way
I can have a full understanding of that code...

-- 
Joel

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

* Re: Adding support for VxWorks target
  2010-04-25 15:47 Adding support for VxWorks target Joel Brobecker
                   ` (14 preceding siblings ...)
  2010-05-04 14:58 ` Adding support for VxWorks target Joel Brobecker
@ 2010-11-25  0:53 ` Joel Brobecker
  15 siblings, 0 replies; 27+ messages in thread
From: Joel Brobecker @ 2010-11-25  0:53 UTC (permalink / raw)
  To: gdb-patches

> The following series of patches adds support for cross debugging
> VxWorks targets (version 5.x, 6.x and limited support for VxWorks 653).

It looks like I might have some time to rebase these patches sooner
rather than later - maybe this month, maybe early Jan 2011. I've had
a few comments so far, and my understanding is that there is no real
opposition to the patches. I'm hoping that this is still the case,
so I can just go ahead, rebase and commit. I'd like to do that because
we've made a few changes since we first submitted, so the two versions
are diverging again, and I'd like to prevent that from happening.
I'll also work on documentation...

Please let me know if this is not OK.

-- 
Joel

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

end of thread, other threads:[~2010-11-25  0:53 UTC | newest]

Thread overview: 27+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2010-04-25 15:47 Adding support for VxWorks target Joel Brobecker
2010-04-25 15:47 ` [vxworks 01/14] Some ada-lang/ada-tasks routines needed by the " Joel Brobecker
2010-04-25 15:48 ` [vxworks 10/14] Add new "wtx" target Joel Brobecker
2010-04-25 15:48 ` [vxworks 02/14] New command_post observer Joel Brobecker
2010-04-26 18:51   ` Tom Tromey
2010-04-27 14:22     ` Joel Brobecker
2010-04-27 17:16       ` Tom Tromey
2010-04-25 15:48 ` [vxworks 14/14] Configury and Makefile updates for VxWorks Joel Brobecker
2010-04-25 15:48 ` [vxworks 03/14] New module remote-wtx-utils Joel Brobecker
2010-04-26 18:55   ` Tom Tromey
2010-04-27 16:27     ` Joel Brobecker
2010-04-25 15:48 ` [vxworks 08/14] Partition support Joel Brobecker
2010-04-25 15:48 ` [vxworks 11/14] WTX-TCL support module Joel Brobecker
2010-04-25 15:48 ` [vxworks 13/14] Add tdep files for x86 and powerpc Joel Brobecker
2010-04-25 20:45   ` Mark Kettenis
2010-04-26 16:41     ` Joel Brobecker
2010-04-25 15:48 ` [vxworks 09/14] remote-wtx-hw / register fetch/store support Joel Brobecker
2010-04-25 15:56 ` [vxworks 05/14] Add options to control Vxworks related settings Joel Brobecker
2010-05-04 15:25   ` Joel Brobecker
2010-04-25 15:56 ` [vxworks 06/14] VxWorks breakpoint-handling module Joel Brobecker
2010-04-25 15:56 ` [vxworks 07/14] "multi-tasks-mode" support Joel Brobecker
2010-04-25 15:56 ` [vxworks 12/14] Add support for VxWorks 6 Joel Brobecker
2010-04-25 16:01 ` [vxworks 04/14] remote-wtxapi: The WTX API abstraction layer Joel Brobecker
2010-05-04 14:58 ` Adding support for VxWorks target Joel Brobecker
2010-05-04 15:43   ` Stan Shebs
2010-05-04 18:30     ` one big unit or several smaller units? (was: "Re: Adding support for VxWorks target") Joel Brobecker
2010-11-25  0:53 ` Adding support for VxWorks target Joel Brobecker

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