This is the mail archive of the gdb-patches@sourceware.org mailing list for the GDB project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[vxworks 12/14] Add support for VxWorks 6


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


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]