From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 19463 invoked by alias); 25 Apr 2010 15:56:42 -0000 Received: (qmail 19447 invoked by uid 22791); 25 Apr 2010 15:56:38 -0000 X-SWARE-Spam-Status: No, hits=1.0 required=5.0 tests=BAYES_50,TW_CP,TW_FW,TW_WT,T_RP_MATCHES_RCVD X-Spam-Check-By: sourceware.org Received: from rock.gnat.com (HELO rock.gnat.com) (205.232.38.15) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Sun, 25 Apr 2010 15:56:00 +0000 Received: from localhost (localhost.localdomain [127.0.0.1]) by filtered-rock.gnat.com (Postfix) with ESMTP id B655D2BAC96 for ; Sun, 25 Apr 2010 11:47:51 -0400 (EDT) Received: from rock.gnat.com ([127.0.0.1]) by localhost (rock.gnat.com [127.0.0.1]) (amavisd-new, port 10024) with LMTP id Zi3oeo+vN7h2 for ; Sun, 25 Apr 2010 11:47:51 -0400 (EDT) Received: from joel.gnat.com (localhost.localdomain [127.0.0.1]) by rock.gnat.com (Postfix) with ESMTP id 76E952BAC9A for ; Sun, 25 Apr 2010 11:47:51 -0400 (EDT) Received: by joel.gnat.com (Postfix, from userid 1000) id 17B8FF5896; Sun, 25 Apr 2010 11:47:51 -0400 (EDT) From: Joel Brobecker To: gdb-patches@sourceware.org Subject: [vxworks 12/14] Add support for VxWorks 6 Date: Sun, 25 Apr 2010 15:56:00 -0000 Message-Id: <1272210447-13895-13-git-send-email-brobecker@adacore.com> In-Reply-To: <1272210447-13895-1-git-send-email-brobecker@adacore.com> References: <1272210447-13895-1-git-send-email-brobecker@adacore.com> Mailing-List: contact gdb-patches-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-patches-owner@sourceware.org X-SW-Source: 2010-04/txt/msg00851.txt.bz2 2010-04-24 Jerome Guitton * 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 . */ + +/* 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 + + + + MAIN_INFO_DIRECTORY; + + * the system thread id in + + Targets + + + + MAIN_INFO_DIRECTORY + + + + SYSTEM_THREAD_ID_LEAF; + + * kernel task ids in + + Targets + + + + MAIN_INFO_DIRECTORY + + + + ObjTypeList + + KernelTask + + ObjList + + + +{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 + -wrs-target-connect -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 . */ + +/* 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