This is the mail archive of the
gdb-patches@sourceware.org
mailing list for the GDB project.
[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 (¤t_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 (¤t_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, ¤t_index);
+
+ if (current_index < table->dfw_lex_tree.table_end)
+ {
+ check_lex (table, ¤t_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 (¤t_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 (¤t_result_record, ¤t_index,
+ new_thread_desc);
+
+ next_sem_element_with_check (¤t_result_record, ¤t_index,
+ new_thread_desc, DFW_SEM_VALUE);
+ next_sem_element_with_check (¤t_result_record, ¤t_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 (¤t_result_record, current_index,
+ DFW_SEM_END_LIST))
+ break;
+
+ /* Id */
+
+ sem_element = next_sem_element_with_check
+ (¤t_result_record, ¤t_index,
+ new_thread_desc, DFW_SEM_VARIABLE);
+ sem_element_process_const_integer_value
+ (¤t_result_record, ¤t_index,
+ new_thread_desc, &dfw_id);
+
+ /* ParentId */
+
+ sem_element = next_sem_element_with_check
+ (¤t_result_record, ¤t_index,
+ new_thread_desc, DFW_SEM_VARIABLE);
+ sem_element_process_const_integer_value
+ (¤t_result_record, ¤t_index,
+ new_thread_desc, &parent_dfw_id);
+
+ /* TID */
+
+ sem_element = next_sem_element_with_check
+ (¤t_result_record, ¤t_index,
+ new_thread_desc, DFW_SEM_VARIABLE);
+ sem_element_process_const_core_addr_value
+ (¤t_result_record, ¤t_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 (¤t_result_record, ¤t_index,
+ new_thread_desc);
+
+ next_sem_element_with_check (¤t_result_record, ¤t_index,
+ new_thread_desc, DFW_SEM_VALUE);
+ next_sem_element_with_check (¤t_result_record, ¤t_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 (¤t_result_record, current_index,
+ DFW_SEM_END_LIST))
+ break;
+
+ /* RTP Id */
+
+ sem_element = next_sem_element_with_check
+ (¤t_result_record, ¤t_index,
+ new_thread_desc, DFW_SEM_VARIABLE);
+ sem_element_process_const_integer_value
+ (¤t_result_record, ¤t_index,
+ new_thread_desc, &rtp_dfw_id);
+
+ /* RTP parent Id */
+
+ sem_element = next_sem_element_with_check
+ (¤t_result_record, ¤t_index,
+ new_thread_desc, DFW_SEM_VARIABLE);
+ sem_element_process_const_integer_value
+ (¤t_result_record, ¤t_index,
+ new_thread_desc, &parent_dfw_id);
+
+ /* RTP TID */
+
+ sem_element = next_sem_element_with_check
+ (¤t_result_record, ¤t_index,
+ new_thread_desc, DFW_SEM_VARIABLE);
+ sem_element_process_const_core_addr_value
+ (¤t_result_record, ¤t_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 (¤t_result_record, ¤t_index,
+ new_thread_desc, DFW_SEM_VARIABLE);
+ next_sem_element_with_check (¤t_result_record, ¤t_index,
+ new_thread_desc, DFW_SEM_VALUE);
+ next_sem_element_with_check (¤t_result_record, ¤t_index,
+ new_thread_desc, DFW_SEM_BEGIN_LIST);
+ while (current_index < current_result_record.dfw_sem_tree.table_end)
+ {
+ if (test_next_sem_element (¤t_result_record, current_index,
+ DFW_SEM_END_LIST))
+ {
+ next_sem_element_with_check (¤t_result_record,
+ ¤t_index,
+ new_thread_desc,
+ DFW_SEM_END_LIST);
+ break;
+ }
+
+ /* RTP task Id */
+
+ sem_element = next_sem_element_with_check
+ (¤t_result_record, ¤t_index,
+ new_thread_desc, DFW_SEM_VARIABLE);
+ sem_element_process_const_integer_value
+ (¤t_result_record, ¤t_index,
+ new_thread_desc, &dfw_id);
+
+ /* RTP task parent Id */
+
+ sem_element = next_sem_element_with_check
+ (¤t_result_record, ¤t_index,
+ new_thread_desc, DFW_SEM_VARIABLE);
+ sem_element_process_const_integer_value
+ (¤t_result_record, ¤t_index,
+ new_thread_desc, &parent_dfw_id);
+
+ /* RTP task TID */
+
+ sem_element = next_sem_element_with_check
+ (¤t_result_record, ¤t_index,
+ new_thread_desc, DFW_SEM_VARIABLE);
+ sem_element_process_const_core_addr_value
+ (¤t_result_record, ¤t_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 (¤t_result_record, ¤t_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 (¤t_result_record, ¤t_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 (¤t_result_record, ¤t_index);
+ current_index < current_result_record.dfw_sem_tree.table_end;
+ sem_element = next_sem_element (¤t_result_record, ¤t_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 (¤t_result_record, ¤t_index,
+ "getting system thread id");
+
+ while (current_index < current_result_record.dfw_sem_tree.table_end)
+ {
+ sem_element = next_sem_element (¤t_result_record, ¤t_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
+ (¤t_result_record,
+ ¤t_index,
+ "getting system thread id",
+ ¤t_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 (¤t_result_record,
+ ¤t_index,
+ "getting full target name");
+
+ while (current_index < current_result_record.dfw_sem_tree.table_end)
+ {
+ sem_element = next_sem_element (¤t_result_record, ¤t_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 (¤t_result_record, ¤t_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
+ (¤t_result_record, ¤t_index,
+ request_desc, DFW_SEM_VARIABLE);
+ sem_element = next_sem_element_with_check
+ (¤t_result_record, ¤t_index,
+ request_desc, DFW_SEM_VALUE);
+ sem_element = next_sem_element_with_check
+ (¤t_result_record, ¤t_index,
+ request_desc, DFW_SEM_BEGIN_LIST);
+ sem_element = next_sem_element_with_check
+ (¤t_result_record, ¤t_index,
+ request_desc, DFW_SEM_VARIABLE);
+ sem_element_process_const_string_value
+ (¤t_result_record, ¤t_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 (¤t_result_record, ¤t_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 (¤t_result_record,
+ ¤t_index,
+ thread_info_desc);
+
+ next_sem_element_with_check (¤t_result_record, ¤t_index,
+ thread_info_desc, DFW_SEM_VALUE);
+ next_sem_element_with_check (¤t_result_record, ¤t_index,
+ thread_info_desc, DFW_SEM_BEGIN_LIST);
+ next_sem_element_with_check (¤t_result_record, ¤t_index,
+ thread_info_desc, DFW_SEM_VARIABLE);
+ sem_element_process_const_string_value (¤t_result_record,
+ ¤t_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 (¤t_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