* [PATCH 01/18] Some ada-lang/ada-tasks routines needed by the VxWorks target
2011-02-24 17:49 Add support for VxWorks 5.x, 6.x and 653 Joel Brobecker
@ 2011-02-24 17:49 ` Joel Brobecker
2011-02-24 17:50 ` [PATCH 03/18] New general purpose routines in utils.c Joel Brobecker
` (16 subsequent siblings)
17 siblings, 0 replies; 54+ messages in thread
From: Joel Brobecker @ 2011-02-24 17:49 UTC (permalink / raw)
To: gdb-patches; +Cc: Joel Brobecker
We need to add a few routines in the following units...
- ada-lang.c:
After switching to a new partition, if there is an Ada main in there,
and the language is auto, switch the language to Ada (if not already
Ada).
- ada-tasks.c:
The remote-wtx backend needs to know which task is the environment
task (this is the initial/main task). The program dies when this
task dies...
gdb/ChangeLog:
* ada-lang.h (ada_language_auto_set, ada_get_environment_task):
Add declarations.
* ada-lang.c (ada_language_auto_set): New function.
* ada-tasks.c (ada_get_environment_task): New function.
---
gdb/ada-lang.c | 14 ++++++++++++++
gdb/ada-lang.h | 4 ++++
gdb/ada-tasks.c | 16 ++++++++++++++++
3 files changed, 34 insertions(+), 0 deletions(-)
diff --git a/gdb/ada-lang.c b/gdb/ada-lang.c
index 467e4df..a325e81 100644
--- a/gdb/ada-lang.c
+++ b/gdb/ada-lang.c
@@ -740,6 +740,20 @@ ada_update_initial_language (enum language lang)
return lang;
}
+/* If the language mode is auto, and we can find some Ada code
+ in one of the module, then automatically set the language to Ada. */
+
+void
+ada_language_auto_set (void)
+{
+ if (language_mode == language_mode_auto
+ && ada_update_initial_language (language_unknown) == language_ada)
+ {
+ set_language (language_ada);
+ expected_language = current_language;
+ }
+}
+
/* If the main procedure is written in Ada, then return its name.
The result is good until the next call. Return NULL if the main
procedure doesn't appear to be in Ada. */
diff --git a/gdb/ada-lang.h b/gdb/ada-lang.h
index 7902124..9a0e8ed 100644
--- a/gdb/ada-lang.h
+++ b/gdb/ada-lang.h
@@ -215,6 +215,8 @@ extern const char *ada_decode (const char*);
extern enum language ada_update_initial_language (enum language);
+extern void ada_language_auto_set (void);
+
extern void clear_ada_sym_cache (void);
extern int ada_lookup_symbol_list (const char *, const struct block *,
@@ -377,6 +379,8 @@ extern char *ada_main_name (void);
extern int valid_task_id (int);
+extern struct ada_task_info *ada_get_environment_task (void);
+
extern int ada_get_task_number (ptid_t);
typedef void (ada_task_list_iterator_ftype) (struct ada_task_info *task);
diff --git a/gdb/ada-tasks.c b/gdb/ada-tasks.c
index 216902a..d132ec7 100644
--- a/gdb/ada-tasks.c
+++ b/gdb/ada-tasks.c
@@ -212,6 +212,22 @@ ada_task_is_alive (struct ada_task_info *task_info)
return (task_info->state != Terminated);
}
+/* Return the task info associated to the Environment Task.
+ This function assumes that the inferior does in fact use tasking. */
+
+struct ada_task_info *
+ada_get_environment_task (void)
+{
+ ada_build_task_list (0);
+ gdb_assert (VEC_length (ada_task_info_s, task_list) > 0);
+
+ /* We use a little bit of insider knowledge to determine which task
+ is the Environment Task: We know that this task is created first,
+ and thus should always be task #1, which is at index 0 of the
+ TASK_LIST. */
+ return (VEC_index (ada_task_info_s, task_list, 0));
+}
+
/* Call the ITERATOR function once for each Ada task that hasn't been
terminated yet. */
--
1.7.0.4
^ permalink raw reply [flat|nested] 54+ messages in thread
* Add support for VxWorks 5.x, 6.x and 653
@ 2011-02-24 17:49 Joel Brobecker
2011-02-24 17:49 ` [PATCH 01/18] Some ada-lang/ada-tasks routines needed by the VxWorks target Joel Brobecker
` (17 more replies)
0 siblings, 18 replies; 54+ messages in thread
From: Joel Brobecker @ 2011-02-24 17:49 UTC (permalink / raw)
To: gdb-patches
This is mostly a rebase of the previous series, submitted almost
a year ago (already!). We adjusted some of the patches based on
the feedback that we received so far. We also made some corrections
for issues that we discovered since. I've also done another pass
at trying to fix as many obvious coding style issues as I could see.
I have also added full documentation, as well as NEWS entry
(there are two patches with documentation: #04/18, and #18/18).
Please note the introduction of patch #5 since the first series:
new struct bp_target_info target_private_data field
(see patch itself for more info about it)
Pending comments, I would like to commit these patches after
a reasonable wait (say, around the end of next week, for instance).
^ permalink raw reply [flat|nested] 54+ messages in thread
* [PATCH 02/18] New command_post observer
2011-02-24 17:49 Add support for VxWorks 5.x, 6.x and 653 Joel Brobecker
` (2 preceding siblings ...)
2011-02-24 17:50 ` [PATCH 04/18] add new "unload" command (symetry of existing "load" command) Joel Brobecker
@ 2011-02-24 17:50 ` Joel Brobecker
2011-02-24 18:58 ` Tom Tromey
2011-02-24 17:51 ` [PATCH 05/18] new struct bp_target_info target_private_data field Joel Brobecker
` (13 subsequent siblings)
17 siblings, 1 reply; 54+ messages in thread
From: Joel Brobecker @ 2011-02-24 17:50 UTC (permalink / raw)
To: gdb-patches; +Cc: Joel Brobecker
Just as the current language, or current inferior, or current thread,
affect some of the commands being issued by the user to the debugger,
with multi-partition systems, we now have a current partition (formerly
known as a Protection Domain, or PD).
What we are trying to do is to keep the user informed of the current
PD (which is identified by either PD ID or name, but we like to print
both).
The problem is that we cannot just print a message everytime the PD
gets switched, because many commands result in a temporary switch of
partition. For instance, info threads will need to switch to the
associated PDs in order to get the PC and associated symbolic info.
We don't want to write the notification for each switch. However, we
do want to print that notification if we just hit a breakpoint for
some code living in a different partition...
The way we solved this is by remembering the PD ID before we issued
the last command. At the end of a command execution, if the PD ID
changed, then we write a notification...
This patch introduces an observer (command_post) that gets triggered
at the end of a command execution...
gdb/ChangeLog:
* doc/observer.texi (command_post): New observer.
* top.c: #include "observer.h".
(execute_command): Call observer_notify_command_post.
---
gdb/doc/observer.texi | 4 ++++
gdb/top.c | 4 ++++
2 files changed, 8 insertions(+), 0 deletions(-)
diff --git a/gdb/doc/observer.texi b/gdb/doc/observer.texi
index d16c865..f136113 100644
--- a/gdb/doc/observer.texi
+++ b/gdb/doc/observer.texi
@@ -132,6 +132,10 @@ Called with @var{objfile} equal to @code{NULL} to indicate
previously loaded symbol table data has now been invalidated.
@end deftypefun
+@deftypefun void command_post (void)
+The debugger just finished executing a command.
+@end deftypefun
+
@deftypefun void new_thread (struct thread_info *@var{t})
The thread specified by @var{t} has been created.
@end deftypefun
diff --git a/gdb/top.c b/gdb/top.c
index df2b163..a8d2e5a 100644
--- a/gdb/top.c
+++ b/gdb/top.c
@@ -64,6 +64,7 @@
#include <ctype.h>
#include "ui-out.h"
#include "cli-out.h"
+#include "observer.h"
/* Default command line prompt. This is overriden in some configs. */
@@ -462,6 +463,9 @@ execute_command (char *p, int from_tty)
warned = 1;
}
}
+
+ /* Emit the "command_post" notification. */
+ observer_notify_command_post ();
}
/* Run execute_command for P and FROM_TTY. Capture its output into the
--
1.7.0.4
^ permalink raw reply [flat|nested] 54+ messages in thread
* [PATCH 03/18] New general purpose routines in utils.c
2011-02-24 17:49 Add support for VxWorks 5.x, 6.x and 653 Joel Brobecker
2011-02-24 17:49 ` [PATCH 01/18] Some ada-lang/ada-tasks routines needed by the VxWorks target Joel Brobecker
@ 2011-02-24 17:50 ` Joel Brobecker
2011-02-24 19:06 ` Tom Tromey
2011-02-24 17:50 ` [PATCH 04/18] add new "unload" command (symetry of existing "load" command) Joel Brobecker
` (15 subsequent siblings)
17 siblings, 1 reply; 54+ messages in thread
From: Joel Brobecker @ 2011-02-24 17:50 UTC (permalink / raw)
To: gdb-patches; +Cc: Joel Brobecker
These are some general-purpose routines that were added for the VxWorks
port... Hopefully other parts of the GDB code will make use of them.
gdb/ChangeLog:
* utils.c (have_dos_based_filesystem, is_regular_file)
(skip_whitespace, skip_until_character, skip_until_whitespace)
(skip_space_delimited_token, get_space_delimited_token): New functions.
* source.c (is_regular_file): Delete. Moved to utils.c.
* defs.h (have_dos_based_filesystem, is_regular_file)
(skip_whitespace, skip_until_character, skip_space_delimited_token)
(get_space_delimited_token): Add declaration.
---
gdb/defs.h | 12 ++++++
gdb/source.c | 18 ---------
gdb/utils.c | 109 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 121 insertions(+), 18 deletions(-)
diff --git a/gdb/defs.h b/gdb/defs.h
index 9409dde..908d956 100644
--- a/gdb/defs.h
+++ b/gdb/defs.h
@@ -421,6 +421,18 @@ extern const char *gdb_bfd_errmsg (bfd_error_type error_tag, char **matching);
extern int parse_pid_to_attach (char *args);
+extern int have_dos_based_filesystem (void);
+
+extern int is_regular_file (const char *name);
+
+extern char *skip_whitespace (char *str);
+
+extern char *skip_until_character (char *str, char delimiter);
+
+extern char *skip_space_delimited_token (char *str);
+
+extern char *get_space_delimited_token (char *str, char **token);
+
/* From demangle.c */
extern void set_demangling_style (char *);
diff --git a/gdb/source.c b/gdb/source.c
index a14a802..9e35dd9 100644
--- a/gdb/source.c
+++ b/gdb/source.c
@@ -657,24 +657,6 @@ source_info (char *ignore, int from_tty)
}
\f
-/* Return True if the file NAME exists and is a regular file. */
-static int
-is_regular_file (const char *name)
-{
- struct stat st;
- const int status = stat (name, &st);
-
- /* Stat should never fail except when the file does not exist.
- If stat fails, analyze the source of error and return True
- unless the file does not exist, to avoid returning false results
- on obscure systems where stat does not work as expected. */
-
- if (status != 0)
- return (errno != ENOENT);
-
- return S_ISREG (st.st_mode);
-}
-
/* Open a file named STRING, searching path PATH (dir names sep by some char)
using mode MODE in the calls to open. You cannot use this function to
create files (O_CREAT).
diff --git a/gdb/utils.c b/gdb/utils.c
index 82e3adb..6f8926c 100644
--- a/gdb/utils.c
+++ b/gdb/utils.c
@@ -3982,6 +3982,115 @@ parse_pid_to_attach (char *args)
return pid;
}
+/* Return non-zero if the host has a dos-based file system. */
+
+int
+have_dos_based_filesystem (void)
+{
+#ifdef HAVE_DOS_BASED_FILE_SYSTEM
+ return 1;
+#else
+ return 0;
+#endif
+}
+
+/* Return True if the file NAME exists and is a regular file. */
+
+int
+is_regular_file (const char *name)
+{
+ struct stat st;
+ const int status = stat (name, &st);
+
+ /* Stat should never fail except when the file does not exist.
+ If stat fails, analyze the source of error and return True
+ unless the file does not exist, to avoid returning false results
+ on obscure systems where stat does not work as expected. */
+ if (status != 0)
+ return (errno != ENOENT);
+
+ return S_ISREG (st.st_mode);
+}
+
+/* Return a pointer to the first non-whitepace character found
+ in the string. A whitespace is either a space or a tab. */
+
+char *
+skip_whitespace (char *str)
+{
+ char *index = str;
+
+ while (*index == ' ' || *index == '\t')
+ index++;
+
+ return index;
+}
+
+/* Return a pointer to the first DELIMITER character in the given
+ string. Return a pointer to the end-of-line character if
+ DELIMITER was not found. */
+
+char *
+skip_until_character (char *str, char delimiter)
+{
+ char *index = str;
+
+ while (*index != delimiter && *index != '\0')
+ index++;
+
+ return index;
+}
+
+/* return a pointer to the first whitespace character. If no whitespace
+ is found before the end of string, a pointer to the end of string
+ is returned. A whitespace is either a space or a tab. */
+
+static char *
+skip_until_whitespace (char *str)
+{
+ char *index = str;
+
+ while (*index != ' ' && *index != '\t' && *index != '\0')
+ index++;
+
+ return index;
+}
+
+/* Return a pointer to the first white space after the next
+ whitespace-delimited token. */
+
+char *
+skip_space_delimited_token (char *str)
+{
+ char *index = str;
+
+ index = skip_whitespace (index);
+ index = skip_until_whitespace (index);
+
+ return index;
+}
+
+/* Copy the next whitespace token into TOKEN. This string will be
+ allocated using malloc, and must be dealocated later. */
+
+char *
+get_space_delimited_token (char *str, char **token)
+{
+ char *start;
+ char *end;
+ char tmp;
+
+ start = skip_whitespace (str);
+ end = skip_until_whitespace (start);
+
+ tmp = *end;
+ *end = '\0';
+ *token = xstrdup (start);
+ *end = tmp;
+
+ return end;
+}
+
/* Provide a prototype to silence -Wmissing-prototypes. */
extern initialize_file_ftype _initialize_utils;
--
1.7.0.4
^ permalink raw reply [flat|nested] 54+ messages in thread
* [PATCH 04/18] add new "unload" command (symetry of existing "load" command)
2011-02-24 17:49 Add support for VxWorks 5.x, 6.x and 653 Joel Brobecker
2011-02-24 17:49 ` [PATCH 01/18] Some ada-lang/ada-tasks routines needed by the VxWorks target Joel Brobecker
2011-02-24 17:50 ` [PATCH 03/18] New general purpose routines in utils.c Joel Brobecker
@ 2011-02-24 17:50 ` Joel Brobecker
2011-02-24 19:22 ` Eli Zaretskii
2011-02-24 17:50 ` [PATCH 02/18] New command_post observer Joel Brobecker
` (14 subsequent siblings)
17 siblings, 1 reply; 54+ messages in thread
From: Joel Brobecker @ 2011-02-24 17:50 UTC (permalink / raw)
To: gdb-patches; +Cc: Joel Brobecker
As the title suggests, this patch adds a new "unload" command which
is expected to do the opposite of the load command, on the targets
that support it. VxWorks targets allow us to unload modules, and
thus this target method will be used there.
gdb/ChangeLog:
* target.h (struct target_ops): Add "to_unload" field.
(target_unload): Add declaration.
* target.c (debug_to_unload, target_unload): New functions.
(update_current_target): Add support for to_unload method.
(setup_target_debug): Set current_target.to_unload.
* symfile.c (unload_command): New function.
(_initialize_symfile): Add "unload" command.
gdb/doc/ChangeLog:
* gdb.texinfo (Target Commands): Document new "unload" command.
---
gdb/doc/gdb.texinfo | 13 +++++++++++++
gdb/symfile.c | 18 ++++++++++++++++++
gdb/target.c | 22 ++++++++++++++++++++++
gdb/target.h | 10 ++++++++++
4 files changed, 63 insertions(+), 0 deletions(-)
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index c727dc8..32454c3 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -15842,6 +15842,19 @@ Depending on the remote side capabilities, @value{GDBN} may be able to
load programs into flash memory.
@code{load} does not repeat if you press @key{RET} again after using it.
+
+@item unload @var{filename}
+@kindex unload @var{filename}
+@cindex unload object file from target
+Depending on what remote debugging facilities are configured into
+@value{GDBN}, the @code{unload} command may be available. Where it exists,
+it does the opposite of the @code{load} command.
+
+If your @value{GDBN} does not have an @code{unload} command, attempting
+to execute it triggers the error message ``@code{You can't do that when
+your target is @dots{}}''
+
+@code{unload} does not repeat if you press @key{RET} again after using it.
@end table
@node Byte Order
diff --git a/gdb/symfile.c b/gdb/symfile.c
index 579aaa4..2e43e83 100644
--- a/gdb/symfile.c
+++ b/gdb/symfile.c
@@ -1788,6 +1788,20 @@ load_command (char *arg, int from_tty)
overlay_cache_invalid = 1;
}
+/* Implement the "unload" command. */
+
+static void
+unload_command (char *arg, int from_tty)
+{
+ dont_repeat ();
+
+ target_unload (arg, from_tty);
+
+ /* After unloading some object files, we don't really know which
+ overlays are mapped any more. */
+ overlay_cache_invalid = 1;
+}
+
/* This version of "load" should be usable for any target. Currently
it is just used for remote targets, not inftarg.c or core files,
on the theory that only in that case is it useful.
@@ -3672,6 +3686,10 @@ for access from GDB.\n\
A load OFFSET may also be given."), &cmdlist);
set_cmd_completer (c, filename_completer);
+ c = add_cmd ("unload", class_files, unload_command, _("\
+Unload FILE from the target."), &cmdlist);
+ set_cmd_completer (c, filename_completer);
+
add_setshow_boolean_cmd ("symbol-reloading", class_support,
&symbol_reloading, _("\
Set dynamic symbol table reloading multiple times in one run."), _("\
diff --git a/gdb/target.c b/gdb/target.c
index a4e2ae9..959e5ff 100644
--- a/gdb/target.c
+++ b/gdb/target.c
@@ -149,6 +149,8 @@ static void debug_to_terminal_info (char *, int);
static void debug_to_load (char *, int);
+static void debug_to_unload (char *, int);
+
static int debug_to_lookup_symbol (char *, CORE_ADDR *);
static int debug_to_can_run (void);
@@ -468,6 +470,13 @@ target_load (char *arg, int from_tty)
}
void
+target_unload (char *arg, int from_tty)
+{
+ target_dcache_invalidate ();
+ (*current_target.to_unload) (arg, from_tty);
+}
+
+void
target_create_inferior (char *exec_file, char *args,
char **env, int from_tty)
{
@@ -615,6 +624,7 @@ update_current_target (void)
INHERIT (to_terminal_info, t);
/* Do not inherit to_kill. */
INHERIT (to_load, t);
+ INHERIT (to_unload, t);
INHERIT (to_lookup_symbol, t);
/* Do no inherit to_create_inferior. */
INHERIT (to_post_startup_inferior, t);
@@ -768,6 +778,9 @@ update_current_target (void)
de_fault (to_load,
(void (*) (char *, int))
tcomplain);
+ de_fault (to_unload,
+ (void (*) (char *, int))
+ tcomplain);
de_fault (to_lookup_symbol,
(int (*) (char *, CORE_ADDR *))
nosymbol);
@@ -3788,6 +3801,14 @@ debug_to_load (char *args, int from_tty)
fprintf_unfiltered (gdb_stdlog, "target_load (%s, %d)\n", args, from_tty);
}
+static void
+debug_to_unload (char *args, int from_tty)
+{
+ debug_target.to_unload (args, from_tty);
+
+ fprintf_unfiltered (gdb_stdlog, "target_unload (%s, %d)\n", args, from_tty);
+}
+
static int
debug_to_lookup_symbol (char *name, CORE_ADDR *addrp)
{
@@ -3999,6 +4020,7 @@ setup_target_debug (void)
current_target.to_terminal_save_ours = debug_to_terminal_save_ours;
current_target.to_terminal_info = debug_to_terminal_info;
current_target.to_load = debug_to_load;
+ current_target.to_unload = debug_to_unload;
current_target.to_lookup_symbol = debug_to_lookup_symbol;
current_target.to_post_startup_inferior = debug_to_post_startup_inferior;
current_target.to_insert_fork_catchpoint = debug_to_insert_fork_catchpoint;
diff --git a/gdb/target.h b/gdb/target.h
index e856dde..78fccd3 100644
--- a/gdb/target.h
+++ b/gdb/target.h
@@ -479,6 +479,7 @@ struct target_ops
void (*to_terminal_info) (char *, int);
void (*to_kill) (struct target_ops *);
void (*to_load) (char *, int);
+ void (*to_unload) (char *, int);
int (*to_lookup_symbol) (char *, CORE_ADDR *);
void (*to_create_inferior) (struct target_ops *,
char *, char *, char **, int);
@@ -1016,6 +1017,15 @@ extern void target_kill (void);
extern void target_load (char *arg, int from_tty);
+/* Unload an object file.
+
+ ARG contains command-line arguments, to be broken down with buildargv.
+ The first non-switch argument is the object filename to be unloaded.
+ The target may define switches, or other non-switch arguments, as
+ it pleases. */
+
+extern void target_unload (char *arg, int from_tty);
+
/* Look up a symbol in the target's symbol table. NAME is the symbol
name. ADDRP is a CORE_ADDR * pointing to where the value of the
symbol should be returned. The result is 0 if successful, nonzero
--
1.7.0.4
^ permalink raw reply [flat|nested] 54+ messages in thread
* [PATCH 05/18] new struct bp_target_info target_private_data field
2011-02-24 17:49 Add support for VxWorks 5.x, 6.x and 653 Joel Brobecker
` (3 preceding siblings ...)
2011-02-24 17:50 ` [PATCH 02/18] New command_post observer Joel Brobecker
@ 2011-02-24 17:51 ` Joel Brobecker
2011-02-24 17:54 ` [PATCH 09/18] VxWorks breakpoint-handling module Joel Brobecker
` (12 subsequent siblings)
17 siblings, 0 replies; 54+ messages in thread
From: Joel Brobecker @ 2011-02-24 17:51 UTC (permalink / raw)
To: gdb-patches; +Cc: Joel Brobecker
On VxWorks, we let the target do the breakpoint handling: To insert
a breakpoint at a given location, we emit a WTX request to the target,
and we get an "eventpoint ID". To remove that breakpoint, we need
to use that same eventpoint ID as a parameter for the WTX request
that removes breakpoints. So, for every breakpoint that we actually
inserted on the target, we need to remember the associated eventpoint
ID. This new field allows the target to store some target-specific
data associated to each breakpoint location.
Normally, I would attach this patch to the patch that is going to use
this change. But because the patch in question is part of a rather
large series of large-ish patches, I felt that it was best to avoid
drowning this change with the rest, and give this change more visibility.
gdb/ChangeLog:
* breakpoint.h (struct bp_target_info): New "target_private_data"
component.
---
gdb/breakpoint.h | 6 ++++++
1 files changed, 6 insertions(+), 0 deletions(-)
diff --git a/gdb/breakpoint.h b/gdb/breakpoint.h
index a0fea21..6bd58f1 100644
--- a/gdb/breakpoint.h
+++ b/gdb/breakpoint.h
@@ -233,6 +233,12 @@ struct bp_target_info
(e.g. if a remote stub handled the details). We may still need
the size to remove the breakpoint safely. */
int placed_size;
+
+ /* Some private data maintained by the target, if needed.
+ The target is expected to allocate the data when the breakpoint
+ is inserted, and deallocate it when the breakpoint is removed
+ (please also set the pointer to NULL after deallocation). */
+ void *target_private_data;
};
/* GDB maintains two types of information about each breakpoint (or
--
1.7.0.4
^ permalink raw reply [flat|nested] 54+ messages in thread
* [PATCH 08/18] Add options to control Vxworks related settings.
2011-02-24 17:49 Add support for VxWorks 5.x, 6.x and 653 Joel Brobecker
` (6 preceding siblings ...)
2011-02-24 17:54 ` [PATCH 06/18] New module remote-wtx-utils Joel Brobecker
@ 2011-02-24 17:54 ` Joel Brobecker
2011-02-24 17:55 ` [PATCH 10/18] "multi-tasks-mode" support Joel Brobecker
` (9 subsequent siblings)
17 siblings, 0 replies; 54+ messages in thread
From: Joel Brobecker @ 2011-02-24 17:54 UTC (permalink / raw)
To: gdb-patches; +Cc: Joel Brobecker
This is module provides the commands that allow a user to configure
certain settings related to the WTX/VxWorks environment. For instance,
it allows the user to configure the stack size used when "running"
their program (in reality, spawning a new task), or the maximum amount
of time allowed to load a module before a timeout kicks in; etc.
It also provides some set commands that allow the user to turn some
traces on, for bug-hunting purposes...
gdb/ChangeLog:
* remote-wtx-opt.h, remote-wtx-opt.c: New files.
---
gdb/remote-wtx-opt.c | 357 ++++++++++++++++++++++++++++++++++++++++++++++++++
gdb/remote-wtx-opt.h | 49 +++++++
2 files changed, 406 insertions(+), 0 deletions(-)
create mode 100644 gdb/remote-wtx-opt.c
create mode 100644 gdb/remote-wtx-opt.h
diff --git a/gdb/remote-wtx-opt.c b/gdb/remote-wtx-opt.c
new file mode 100644
index 0000000..2c9d712
--- /dev/null
+++ b/gdb/remote-wtx-opt.c
@@ -0,0 +1,357 @@
+/* Support for the WTX protocol.
+
+ This unit provides a user interface to various settings which are
+ related to the WTX protocol. We also provide several debug switches
+ that the user can use to turn on some debugging traces.
+
+ Copyright (C) 2007, 2010, 2011 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#include "defs.h"
+#include "command.h"
+#include "gdbcmd.h"
+#include "remote-wtx-opt.h"
+#include "remote-wtxapi.h"
+
+/* The various settings that affect the the WTX protocol will be
+ accessible through the "set/show wtx" command prefix. The following
+ cmd_list_element variables contain the list of commands accessible
+ under that prefix. */
+
+static struct cmd_list_element *set_wtx_list = NULL;
+static struct cmd_list_element *show_wtx_list = NULL;
+
+/* The various debug switches are accessible through the "set/show wtx
+ debug" command prefix. The following cmd_list_element variables
+ contain the list of commands accessible under that prefix. */
+
+static struct cmd_list_element *set_wtx_debug_list = NULL;
+static struct cmd_list_element *show_wtx_debug_list = NULL;
+
+/* The name we use to identify ourselves when we connect to
+ the target server. The default value is allocated during
+ this file initialization phase. */
+static char *tool_name = NULL;
+
+/* The module load timeout in seconds. */
+static int load_timeout = 30;
+
+/* The stack size in bytes used when spawning a new process. */
+static int stack_size = 0x10000;
+
+/* The options used when spawning a new process. */
+static int task_options = 0;
+
+/* The priority used when spawning a new process. */
+static int task_priority = 100;
+
+/* Set to non-zero to print debug traces of the events received by GDB. */
+static int debug_events_level = 0;
+
+/* Set to non-zero to print debug traces related to break support. */
+static int debug_breakpoints = 0;
+
+/* Set to non-zero to print debug traces related to watchpoint support. */
+static int debug_watchpoints = 0;
+
+/* Set to non-zero to print debug traces of the operations involving
+ objfile manipuations. */
+static int debug_objfiles = 0;
+
+/* If set to non-zero, then the user wants to see more verbose error
+ messages when the TCL interpreter failed to evaluate a command. */
+static int debug_tcl = 0;
+
+/* Accessor for TOOL_NAME. */
+
+char *
+wtx_opt_tool_name (void)
+{
+ return tool_name;
+}
+
+/* Accessor for LOAD_TIMEOUT. */
+
+int
+wtx_opt_load_timeout (void)
+{
+ return load_timeout;
+}
+
+int
+wtx_opt_stack_size (void)
+{
+ return stack_size;
+}
+
+int
+wtx_opt_task_options (void)
+{
+ return task_options;
+}
+
+/* Init task options using the target information. */
+
+void
+wtx_opt_init_task_options (void)
+{
+ const int VX_FP_TASK = wtxapi_vx_fp_task ();
+ const int VX_SPE_TASK = 0x04000000;
+
+ /* If the target has a floating-point processor, then set the
+ floating-point option flag. */
+ if (wtxapi_target_has_fpp_get ())
+ task_options |= VX_FP_TASK;
+
+ /* If the target is e500v2, the SPE APU should be enabled to run
+ floating point programs.
+
+ FIXME: guitton/2009-07-20: In VxWorks 6.6, there is no way to
+ discriminate between e500 and e500v2: both have the same cpu
+ variant "ppc85XX". As we only support e500v2, it is fine to
+ assume that PPC85XX actually means e500v2... For now. But
+ it is not in the general case. The problem is fixed in Vxworks
+ 6.7, so we may get rid of this kludge at some point. */
+ if (wtxapi_has_target_variant ("_e500v2")
+ || wtxapi_has_target_variant ("_ppc85XX"))
+ task_options |= VX_SPE_TASK;
+}
+
+int
+wtx_opt_task_priority (void)
+{
+ return task_priority;
+}
+
+/* Accessor for DEBUG_TCL */
+
+int
+wtx_opt_tcl_verbose_p (void)
+{
+ return debug_tcl;
+}
+
+/* Print a debug message if DEBUG_OBJFILES is non-zero.
+ The message uses the string FORMAT and all the associated parameters,
+ following the printf syntax. */
+
+void
+wtx_opt_objfiles_debug (const char *format, ...)
+{
+ if (debug_objfiles)
+ {
+ va_list args;
+
+ va_start (args, format);
+ printf_filtered ("DEBUG (objfiles): ");
+ vprintf_filtered (format, args);
+ printf_filtered ("\n");
+ va_end (args);
+ }
+}
+
+/* Print a debug message if DEBUG_EVENTS is non-zero.
+ The message uses the string FORMAT and all the associated parameters,
+ following the printf syntax. */
+
+void
+wtx_opt_events_debug (int level, const char *format, ...)
+{
+ if (debug_events_level >= level)
+ {
+ va_list args;
+
+ va_start (args, format);
+ printf_filtered ("DEBUG (events): ");
+ vprintf_filtered (format, args);
+ printf_filtered ("\n");
+ va_end (args);
+ }
+}
+
+/* Print a debug message if DEBUG_BREAKPOINTS is non-zero.
+ The message uses the string FORMAT and all the associated parameters,
+ following the printf syntax. */
+
+void
+wtx_opt_breakpoints_debug (const char *format, ...)
+{
+ if (debug_breakpoints)
+ {
+ va_list args;
+
+ va_start (args, format);
+ printf_filtered ("DEBUG (breakpoints): ");
+ vprintf_filtered (format, args);
+ printf_filtered ("\n");
+ va_end (args);
+ }
+}
+
+/* Print a debug message if DEBUG_WATCHPOINTS is non-zero.
+ The message uses the string FORMAT and all the associated parameters,
+ following the printf syntax. */
+
+void
+wtx_opt_watchpoints_debug (const char *format, ...)
+{
+ if (debug_watchpoints)
+ {
+ va_list args;
+
+ va_start (args, format);
+ printf_filtered ("DEBUG (watchpoints): ");
+ vprintf_filtered (format, args);
+ printf_filtered ("\n");
+ va_end (args);
+ }
+}
+
+/* Implement the "set wtx" command.
+ This is not actually a valid command, so inform the user of that fact,
+ and print the list of valid subcommands to help him. */
+
+static void
+set_wtx_command (char *args, int from_tty)
+{
+ printf_filtered (_("\"set wtx\" must be followed by a subcommand.\n"));
+ help_list (set_wtx_list, "set wtx ", -1, gdb_stdout);
+}
+
+/* Implement the "show wtx" command: Print the value of all settings
+ available through that command prefix. */
+
+static void
+show_wtx_command (char *args, int from_tty)
+{
+ cmd_show_list (show_wtx_list, from_tty, "");
+}
+
+/* Implement the "set wtx debug" command.
+ This is not actually a valid command, so inform the user of that fact,
+ and print the list of valid subcommands to help him. */
+
+static void
+set_wtx_debug_command (char *args, int from_tty)
+{
+ printf_filtered (_("\"set wtx debug\" must be followed by a subcommand.\n"));
+ help_list (set_wtx_debug_list, "set wtx debug", -1, gdb_stdout);
+}
+
+/* Implement the "show wtx" command: Print the value of all settings
+ available through that command prefix. */
+
+static void
+show_wtx_debug_command (char *args, int from_tty)
+{
+ cmd_show_list (show_wtx_debug_list, from_tty, "");
+}
+
+void
+_initialize_remote_wtx_opt (void)
+{
+ tool_name = xstrdup ("gdb");
+
+ /* Various "set/show" switches. */
+ add_prefix_cmd ("wtx", no_class, set_wtx_command, _("\
+Adjust various settings specific to the WTX protocol."), &set_wtx_list,
+ "set wtx ", 0 /* allow_unknown */, &setlist);
+ add_prefix_cmd ("wtx", no_class, show_wtx_command, _("\
+Print various settings specific to the WTX protocol."), &show_wtx_list,
+ "show wtx ", 0 /* allow_unknown */, &showlist);
+
+ add_setshow_string_noescape_cmd ("tool-name", class_support,
+ &tool_name, _("\
+Set the tool name used when connecting to the target server."), _("\
+Show the tool name used when connecting to the target server."), NULL,
+ NULL, NULL,
+ &set_wtx_list, &show_wtx_list);
+
+ add_setshow_integer_cmd ("load-timeout", class_support,
+ &load_timeout, _("\
+Set the timeout in seconds when loading new modules on the target."), _("\
+Show the timeout in seconds when loading new modules on the target."), _("\
+Use this setting to adjust the maximum duration that loading a module\n\
+on the target can take before a timeout aborts the operation."),
+ NULL, NULL, &set_wtx_list, &show_wtx_list);
+
+ add_setshow_zinteger_cmd ("stack-size", class_support,
+ &stack_size, _("\
+Set the stack size in bytes for tasks spawned by the debugger."), _("\
+Show the stack size in bytes for tasks spawned by the debugger.."), _("\
+Use this setting to adjust the stack size of new tasks."),
+ NULL, NULL, &set_wtx_list, &show_wtx_list);
+
+ add_setshow_zinteger_cmd ("task-options", class_support,
+ &task_options, _("\
+Set the options of new tasks spawned by the debugger."), _("\
+Show the options of new tasks spawned by the debugger.."), _("\
+Use this setting to change the options used when spawning new tasks."),
+ NULL, NULL, &set_wtx_list, &show_wtx_list);
+
+ add_setshow_zinteger_cmd ("task-priority", class_support,
+ &task_priority, _("\
+Set the priority of new tasks spawned by the debugger."), _("\
+Show the priority of new tasks spawned by the debugger.."), _("\
+Use this setting to change the priority used when spawning new tasks."),
+ NULL, NULL, &set_wtx_list, &show_wtx_list);
+
+ /* Various debug switches for WTX. */
+ add_prefix_cmd ("debug", no_class, set_wtx_debug_command, _("\
+Adjust various settings specific to the WTX protocol."), &set_wtx_debug_list,
+ "set wtx debug ", 0 /* allow_unknown */, &set_wtx_list);
+ add_prefix_cmd ("debug", no_class, show_wtx_debug_command, _("\
+Print various settings specific to the WTX protocol."), &show_wtx_debug_list,
+ "show wtx debug ", 0 /* allow_unknown */, &show_wtx_list);
+
+ add_setshow_zinteger_cmd ("events", class_maintenance,
+ &debug_events_level, _("\
+Print debug traces related to WTX event handling."), _("\
+Debug traces related to WTX event handling."),
+ NULL, NULL, NULL, &set_wtx_debug_list,
+ &show_wtx_debug_list);
+
+ add_setshow_boolean_cmd ("objfiles", class_maintenance,
+ &debug_objfiles, _("\
+Print debug traces related to objfile handling for WTX."), _("\
+Debug traces related to objfile handling for WTX."),
+ NULL, NULL, NULL, &set_wtx_debug_list,
+ &show_wtx_debug_list);
+
+ add_setshow_boolean_cmd ("breakpoints", class_maintenance,
+ &debug_breakpoints, _("\
+Print debug traces related to WTX breakpoint handling."), _("\
+Debug traces related to WTX breakpoint handling."),
+ NULL, NULL, NULL, &set_wtx_debug_list,
+ &show_wtx_debug_list);
+
+ add_setshow_boolean_cmd ("watchpoints", class_maintenance,
+ &debug_watchpoints, _("\
+Print debug traces related to WTX watchpoint handling."), _("\
+Debug traces related to WTX watchpoint handling."),
+ NULL, NULL, NULL, &set_wtx_debug_list,
+ &show_wtx_debug_list);
+
+ add_setshow_boolean_cmd ("tcl", class_maintenance,
+ &debug_tcl, _("\
+Set the verbosity of the error messages from the TCL interpreter."), _("\
+Show the verbosity of the error messages from the TCL interpreter."), _("\
+When set, the TCL interpreter prints more verbose error messages"),
+ NULL, NULL,
+ &set_wtx_debug_list, &show_wtx_debug_list);
+
+}
diff --git a/gdb/remote-wtx-opt.h b/gdb/remote-wtx-opt.h
new file mode 100644
index 0000000..a786764
--- /dev/null
+++ b/gdb/remote-wtx-opt.h
@@ -0,0 +1,49 @@
+/* Copyright (C) 2007, 2010, 2011 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#ifndef REMOTE_WTX_OPT_H
+#define REMOTE_WTX_OPT_H
+
+char *wtx_opt_tool_name (void);
+
+int wtx_opt_load_timeout (void);
+
+int wtx_opt_stack_size (void);
+
+int wtx_opt_task_options (void);
+
+void wtx_opt_init_task_options (void);
+
+int wtx_opt_task_priority (void);
+
+int wtx_opt_tcl_verbose_p (void);
+
+/* Support for debugging traces. */
+
+void wtx_opt_objfiles_debug (const char *format, ...)
+ ATTRIBUTE_PRINTF (1, 2);
+
+void wtx_opt_events_debug (int level, const char *format, ...)
+ ATTRIBUTE_PRINTF (2, 3);
+
+void wtx_opt_breakpoints_debug (const char *format, ...)
+ ATTRIBUTE_PRINTF (1, 2);
+
+void wtx_opt_watchpoints_debug (const char *format, ...)
+ ATTRIBUTE_PRINTF (1, 2);
+
+#endif
--
1.7.0.4
^ permalink raw reply [flat|nested] 54+ messages in thread
* [PATCH 06/18] New module remote-wtx-utils
2011-02-24 17:49 Add support for VxWorks 5.x, 6.x and 653 Joel Brobecker
` (5 preceding siblings ...)
2011-02-24 17:54 ` [PATCH 09/18] VxWorks breakpoint-handling module Joel Brobecker
@ 2011-02-24 17:54 ` Joel Brobecker
2011-02-24 19:26 ` Tom Tromey
2011-02-24 17:54 ` [PATCH 08/18] Add options to control Vxworks related settings Joel Brobecker
` (10 subsequent siblings)
17 siblings, 1 reply; 54+ messages in thread
From: Joel Brobecker @ 2011-02-24 17:54 UTC (permalink / raw)
To: gdb-patches; +Cc: Joel Brobecker
This module provides a couple of routines to deal with loading the
VxWorks host-side shared libraries, such as the WTX library for instance.
I rewrote a bit the routines to depend on two functions gdb_dlopen and
gdb_dlsym which we could isolate in its own gdb_dlfcn.h/c if we wanted to.
But since this is used only when adding the vxworks target, I kept these
routines local for now - otherwise, it opens the door for questions such
as: What do we do when these are not defined? Should we fail the configure
even though chances are these routines might not be actually needed for
the build? Or do we fail the configure only when they are in fact needed
(ideal, but harder to maintain I believe), or do we just fail at link
time (a bit ugly but much easier to implement)? For now, I don't think
we really need to answer these questions, but I wrote the code in a way
that it makes it easy to extract the code and create the module if we
ever need to.
gdb/ChangeLog:
* remote-wtx-utils.h, remote-wtx-utils.c: New files.
---
gdb/remote-wtx-utils.c | 102 ++++++++++++++++++++++++++++++++++++++++++++++++
gdb/remote-wtx-utils.h | 27 +++++++++++++
2 files changed, 129 insertions(+), 0 deletions(-)
create mode 100644 gdb/remote-wtx-utils.c
create mode 100644 gdb/remote-wtx-utils.h
diff --git a/gdb/remote-wtx-utils.c b/gdb/remote-wtx-utils.c
new file mode 100644
index 0000000..728ff6b
--- /dev/null
+++ b/gdb/remote-wtx-utils.c
@@ -0,0 +1,102 @@
+/* Support for the WTX protocol.
+
+ Copyright (C) 2007, 2010, 2011 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#include "defs.h"
+#include "remote-wtx-utils.h"
+#include "gdb_string.h"
+#include "filenames.h"
+#ifdef HAVE_LIBDL
+#include <dlfcn.h>
+#elif __MINGW32__
+#include <windows.h>
+#else
+/* Unsupported configuration. See load_shared_lib for details. */
+#error
+#endif
+
+/* Load the dynamic library file named FILENAME, and return a handle
+ for that dynamic library. Return NULL if the loading fails for
+ any reason. */
+
+static void *
+gdb_dlopen (const char *filename)
+{
+#ifdef HAVE_LIBDL
+ return dlopen (filename, RTLD_NOW);
+#elif __MINGW32__
+ return (void *) LoadLibrary (filename);
+#endif
+}
+
+/* Return the address of the symbol named SYMBOL inside the shared library
+ whose handle is HANDLE. Return NULL when the symbol could not be found. */
+
+static void *
+gdb_dlsym(void *handle, const char *symbol)
+{
+#ifdef HAVE_LIBDL
+ return dlsym (handle, symbol);
+#elif __MINGW32__
+ return (void *) GetProcAddress (handle, symbol);
+#endif
+}
+
+/* Load the shared library whose name is LIB_NAME and return a handle
+ on it. Return NULL if the library could not be loaded.
+
+ Note that this name correspond to a different file name depending on
+ the host; for example, the name "wtxapi40" would identify libwtxapi40.so
+ on linux and solaris, whereas it would identify wtxapi40.dll. */
+
+void *
+load_shared_lib (char *lib_name)
+{
+ const char dos_suffix [] = ".dll";
+ const char unix_prefix[] = "lib";
+ const char unix_suffix [] = ".so";
+ char *filename;
+
+ if (have_dos_based_filesystem ())
+ {
+ filename = (char *) alloca (strlen (lib_name) + strlen (dos_suffix) + 1);
+ strcpy (filename, lib_name);
+ strcat (filename, dos_suffix);
+ }
+ else
+ {
+ filename = (char *) alloca (strlen (unix_prefix)
+ + strlen (lib_name)
+ + strlen (unix_suffix) + 1);
+ strcpy (filename, unix_prefix);
+ strcat (filename, lib_name);
+ strcat (filename, unix_suffix);
+ }
+
+ return gdb_dlopen (filename);
+}
+
+/* Get the address of SYMBOL in a shared library identified
+ by HANDLE (HANDLE is the value returned by load_shared_lib
+ for this library). */
+
+void *
+get_symbol_from_shared_lib (void *handle, char *symbol)
+{
+ return gdb_dlsym (handle, symbol);
+}
diff --git a/gdb/remote-wtx-utils.h b/gdb/remote-wtx-utils.h
new file mode 100644
index 0000000..0c96e8e
--- /dev/null
+++ b/gdb/remote-wtx-utils.h
@@ -0,0 +1,27 @@
+/* Support for the WTX protocol.
+
+ Copyright (C) 2007, 2010, 2011 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#ifndef REMOTE_WTX_UTILS_H
+#define REMOTE_WTX_UTILS_H
+
+void *load_shared_lib (char *lib_name);
+
+void *get_symbol_from_shared_lib (void *handle, char *symbol);
+
+#endif
--
1.7.0.4
^ permalink raw reply [flat|nested] 54+ messages in thread
* [PATCH 09/18] VxWorks breakpoint-handling module.
2011-02-24 17:49 Add support for VxWorks 5.x, 6.x and 653 Joel Brobecker
` (4 preceding siblings ...)
2011-02-24 17:51 ` [PATCH 05/18] new struct bp_target_info target_private_data field Joel Brobecker
@ 2011-02-24 17:54 ` Joel Brobecker
2011-02-24 17:54 ` [PATCH 06/18] New module remote-wtx-utils Joel Brobecker
` (11 subsequent siblings)
17 siblings, 0 replies; 54+ messages in thread
From: Joel Brobecker @ 2011-02-24 17:54 UTC (permalink / raw)
To: gdb-patches; +Cc: Joel Brobecker
This unit provides a set of routines that allow us to insert/remove
breakpoints and watchpoints on the target. The target takes care of
the insertion/removal, but we need a little bit of glue between
the two.
gdb/ChangeLog:
* remote-wtx-bp.h, remote-wtx-bp.c: New files.
---
gdb/remote-wtx-bp.c | 156 +++++++++++++++++++++++++++++++++++++++++++++++++++
gdb/remote-wtx-bp.h | 141 ++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 297 insertions(+), 0 deletions(-)
create mode 100644 gdb/remote-wtx-bp.c
create mode 100644 gdb/remote-wtx-bp.h
diff --git a/gdb/remote-wtx-bp.c b/gdb/remote-wtx-bp.c
new file mode 100644
index 0000000..2b64f12
--- /dev/null
+++ b/gdb/remote-wtx-bp.c
@@ -0,0 +1,156 @@
+/* WTX backend for GDB.
+
+ Copyright 2007, 2010, 2011 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#include "defs.h"
+#include "remote-wtx-bp.h"
+
+/* --------------------------
+ -- Breakpoint support --
+ -------------------------- */
+
+static enum wtx_breakpoint_action break_command_action = action_task;
+
+void
+set_break_command_action (enum wtx_breakpoint_action action)
+{
+ break_command_action = action;
+}
+
+enum wtx_breakpoint_action
+get_break_command_action (void)
+{
+ return break_command_action;
+}
+
+/* Handling of breakpoint command call routine. */
+
+static CORE_ADDR break_command_call_rtn = 0;
+
+void
+set_break_command_call_rtn (CORE_ADDR call_rtn)
+{
+ break_command_call_rtn = call_rtn;
+}
+
+CORE_ADDR
+get_break_command_call_rtn (void)
+{
+ return break_command_call_rtn;
+}
+
+/* --------------------------
+ -- Watchpoint support --
+ -------------------------- */
+
+/* A structure to do the mapping between a GDB watchpoint and the associated
+ eventpoint ID created by the target. We use this mapping in order to
+ be able to remove a watchpoint. */
+
+struct watchpoint_info
+{
+ CORE_ADDR data_addr;
+ int data_len;
+ int type;
+ evtpt_id_t watchpoint_id;
+
+ struct watchpoint_info *next;
+};
+
+/* The list of watchpoints we inserted in the target. */
+static struct watchpoint_info *watchpoint_list = NULL;
+
+/* Return non-zero if INFO matches (DATA_ADDR, DATA_LEN, TYPE).
+ In other words, return non-zero if INFO is the watchpont_info
+ object that corresponds to a GDB watchpoint. */
+
+static int
+watchpoint_info_matches (struct watchpoint_info *info,
+ CORE_ADDR data_addr, int data_len, int type)
+{
+ return (info->data_addr == data_addr
+ && info->data_len == data_len
+ && info->type == type);
+}
+
+/* Record in our watchpoint list the fact that we just inserted a watchpoint
+ on the target. */
+
+void
+wtx_bp_register_watchpoint_id (evtpt_id_t watchpoint_id, CORE_ADDR data_addr,
+ int data_len, int type)
+{
+ struct watchpoint_info *info = xmalloc (sizeof (struct watchpoint_info));
+
+ info->data_addr = data_addr;
+ info->data_len = data_len;
+ info->type = type;
+ info->watchpoint_id = watchpoint_id;
+
+ /* Now insert this new node at the head. */
+ info->next = watchpoint_list;
+ watchpoint_list = info;
+}
+
+/* Search our list of watchpoint_info objects, and pop the entry
+ that matches the watchpoint corresponding to (DATA_ADDR, DATA_LEN,
+ TYPE). Return the associated eventpoint ID.
+
+ Return invalid_evtpt_id if no match was found. */
+
+evtpt_id_t
+wtx_bp_pop_watchpoint_id (CORE_ADDR data_addr, int data_len, int type)
+{
+ struct watchpoint_info *info = watchpoint_list;
+ evtpt_id_t watchpoint_id;
+
+ /* Check to see if the node at the head of the watchpoint list matches
+ the description. If yes, then destroy that node. Given that on certain
+ architectures, we only have access to one watchpoints, this condition
+ should be true most of the time. */
+
+ if (info != NULL
+ && watchpoint_info_matches (info, data_addr, data_len, type))
+ {
+ watchpoint_id = info->watchpoint_id;
+ watchpoint_list = info->next;
+ free (info);
+ return watchpoint_id;
+ }
+
+ /* If not, then look for the node that is immediately preceding the node
+ we're looking for. Then do the freeing and reconnecting. */
+ while (info != NULL)
+ {
+ if (info->next != NULL
+ && watchpoint_info_matches (info->next, data_addr, data_len, type))
+ {
+ struct watchpoint_info *tmp = info->next;
+
+ watchpoint_id = tmp->watchpoint_id;
+ info->next = tmp->next;
+ free (tmp);
+ return watchpoint_id;
+ }
+ info = info->next;
+ }
+
+ /* No corresponding watchpoint eventpoint found. */
+ return invalid_evtpt_id;
+}
+
diff --git a/gdb/remote-wtx-bp.h b/gdb/remote-wtx-bp.h
new file mode 100644
index 0000000..6be32c7
--- /dev/null
+++ b/gdb/remote-wtx-bp.h
@@ -0,0 +1,141 @@
+/* WTX backend for GDB.
+
+ Copyright 2007, 2010, 2011 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#ifndef REMOTE_WTX_BP_H
+#define REMOTE_WTX_BP_H
+
+#include "remote-wtxapi.h"
+
+/* A note about breakpoint command "scope" and "action" settings:
+ --------------------------------------------------------------
+
+ These as concepts that were introduced in VxWorks AE, but no longer
+ make much sense in VxWorks 653. On 653, the user will debug either:
+
+ 1. A task inside the kernel partition;
+
+ 2. An entire partition, which in pratice is exactly similar to (1),
+ since it is done by debugging the task associated to that partition;
+
+ 3. The entire system in "system-mode".
+
+ This means that there are actually realy only two debugging modes
+ available to the user:
+ a. The single-task mode
+ b. The system-mode.
+
+ In system-mode, the scope and action are, by design from the system,
+ irrelevant. Breakpoints will stop the entire system when any task
+ hits them.
+
+ In single-task mode, the user is debugging his task independently
+ of the rest of the system. This means that the scope of breakpoints
+ in that mode will be that task and only that task. Similarly, we
+ are forcing the action to that task as well.
+
+ As a result, the scope and actions can be implicitly determined
+ from the debugging context, and thus do not require user input.
+ This is why there is no longer a "set" command that allows the
+ user to change it anymore.
+
+ Also, this also means that the context and action can no longer
+ change during a debugging session. As a consequence, although
+ the system does allow tools to use independent scope and action
+ settings for every breakpoints, the debugger will be using
+ consistent settings, thus avoiding the need to track what
+ breakpoint uses what setting. This knowledge is important
+ when resuming breakpoints, because if a breakpoint stopped
+ all tasks, then we need to resume all tasks when doing a
+ "continue" for instance.
+
+ brobecker/2007-09-25: It is conceivable that some users might
+ find that having the choice of setting the action to "all" for
+ their debugging session would be helpful, or even necessary.
+ In that case, the system-mode might be more approriate to their
+ needs. However, the system-mode does have some limitations that
+ might not be acceptable either. This code has been designed in
+ such a way that adding that feature, this extra choice, should
+ just be a matter of adding a "set" command to let the user change
+ the action. */
+
+/* Advance declarations. */
+
+struct bp_target_info;
+
+/* The following enum defines the various actions that can be taken
+ when a breakpoint is hit. */
+
+enum wtx_breakpoint_action
+{
+ action_task, /* Stop the current task. */
+ action_all, /* Stop all breakable tasks in all partitions. */
+ action_call /* Stop the current task and call a stop function on the
+ target, if this function is defined. */
+};
+
+/* Exported routines. */
+
+void set_break_command_call_rtn (CORE_ADDR call_rtn);
+
+CORE_ADDR get_break_command_call_rtn (void);
+
+void set_break_command_action (enum wtx_breakpoint_action);
+
+enum wtx_breakpoint_action get_break_command_action (void);
+
+/* Watchpoint support. */
+
+/* HARDWARE WATCHPOINT SUPPORT:
+ ============================
+
+ Strictly speaking, the only systems that support hardware watchpoints
+ are the targets that implement BoDA (Break on Data Access) events.
+ This functionality was introduced in a limited number of versions
+ of VxWorks 653 which can be identified once we're connected to
+ the system (see wtxapi_target_has_BoDA).
+
+ For systems that do not support BoDA, there is another type of
+ watchpoint event (WTX_EVENT_DATA_ACCESS) which, according to
+ WindRiver is not strictly speaking a hardware watchpoint because
+ it doesn't use the features of the target hardware to implement it.
+ However, from the debugger's perspective, these watchpoint events
+ are still viewed as hardware, because they do not require us to
+ emulate watchpoint support at the debugger level. Although not as
+ fast as strict hardware watchpoint support, these events are still
+ faster than having to emulate them at the debugger level, since it
+ avoids a very large amount of interaction between the debugger and
+ the target. Experimentations on VxWorks 5.5 and VxWorks 653 have
+ revealed that only one such event can be used at the same time:
+ - On VxWorks 5.5, the system lets you insert the events, but
+ somehow then fails to notify the tools for any of the watchpoints
+ - On VxWorks 653, the system returns an error when trying to
+ insert the second data-access event.
+
+ For systems supporting BoDA, there is one and only one watchpoint
+ available. Any other watchpoints must be emulated at the debugger
+ level. */
+
+void wtx_bp_register_watchpoint_id (evtpt_id_t watchpoint_id,
+ CORE_ADDR data_addr,
+ int data_len, int type);
+
+evtpt_id_t wtx_bp_pop_watchpoint_id (CORE_ADDR data_addr, int data_len,
+ int type);
+
+#endif
--
1.7.0.4
^ permalink raw reply [flat|nested] 54+ messages in thread
* [PATCH 10/18] "multi-tasks-mode" support.
2011-02-24 17:49 Add support for VxWorks 5.x, 6.x and 653 Joel Brobecker
` (7 preceding siblings ...)
2011-02-24 17:54 ` [PATCH 08/18] Add options to control Vxworks related settings Joel Brobecker
@ 2011-02-24 17:55 ` Joel Brobecker
2011-02-24 17:56 ` [PATCH 11/18] Add partition support Joel Brobecker
` (8 subsequent siblings)
17 siblings, 0 replies; 54+ messages in thread
From: Joel Brobecker @ 2011-02-24 17:55 UTC (permalink / raw)
To: gdb-patches; +Cc: Joel Brobecker
VxWorks systems do not provide a concept of a process, but some users
would really like to be able to debug all the tasks running in their
"program", and only those. The multi-tasks mode is an answer to that
request, based on the fact that Ada programs maintain a list of known
Ada tasks inside the runtime. The debugger can access it to compute
the current list of Ada tasks, and from there determine the list of
VxWorks threads running as part of the user's application.
Given the fact that this feature relies on a property of the GNAT runtime,
it only works for Ada applications.
Resuming/stopping the relevant threads is done by calls to specialized
routines in the GNAT runtime. This was necessary to avoid loads of
race conditions that we kept facing when doing this with WTX requests
to each and every affected thread. The runtime routines have nice
properties that allow us to avoid the problem entirely.
gdb/ChangeLog:
* remote-wtx-tasks.h, remote-wtx-tasks.c: New files.
---
gdb/remote-wtx-tasks.c | 201 ++++++++++++++++++++++++++++++++++++++++++++++++
gdb/remote-wtx-tasks.h | 53 +++++++++++++
2 files changed, 254 insertions(+), 0 deletions(-)
create mode 100644 gdb/remote-wtx-tasks.c
create mode 100644 gdb/remote-wtx-tasks.h
diff --git a/gdb/remote-wtx-tasks.c b/gdb/remote-wtx-tasks.c
new file mode 100644
index 0000000..c876875
--- /dev/null
+++ b/gdb/remote-wtx-tasks.c
@@ -0,0 +1,201 @@
+/* Ada multi-task functionnalities for VxWorks targets.
+
+ Copyright 2005, 2010, 2011 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+/* Some symbol names embedded in the inferior when it uses tasks. */
+
+#include "defs.h"
+#include "remote-wtxapi.h"
+#include "remote-wtx-bp.h"
+#include "remote-wtx-tasks.h"
+#include "gdbcmd.h"
+#include "target.h"
+
+#define ADA_STOP_ALL_TASKS ("system__tasking__debug__stop_all_tasks")
+#define ADA_STOP_ALL_TASKS_HANDLER ("system__tasking__debug__stop_all_tasks_handler")
+#define ADA_CONTINUE_ALL_TASKS ("system__tasking__debug__continue_all_tasks")
+
+/* Breakpoint scope/action operations for the Ada multitask mode :
+ Ada application scope/Ada application action. */
+
+static int multi_task_mode = 0;
+
+/* The user must not be allowed to change the value of the multitask
+ mode while debugging. Unfortunately, the set/show mechanism does
+ not allow us to add this type of guard directly. So what we do is
+ we let the "set multi-tasks-mode" command update the intermediate
+ variable below, and then let a hook called at each update propagate
+ the new value to MULTI_TASK_MODE if allowed, or report an error
+ if not. */
+static int multi_task_mode_setshow_var = 0;
+
+/* Some variables used to cache the address of functions provided by the
+ inferior to suspend/resume all ada tasks. */
+
+static CORE_ADDR continue_all_tasks_fun_addr = 0;
+static CORE_ADDR stop_all_tasks_handler_fun_addr = 0;
+static CORE_ADDR stop_all_tasks_fun_addr = 0;
+
+/* Return non-zero if the user has selected the multi-tasks mode. */
+
+int
+multi_task_mode_is_on (void)
+{
+ return multi_task_mode;
+}
+
+/* Initialize the breakpoint datas for the multi-tasks mode. */
+
+void
+open_multi_task_mode (void)
+{
+ set_break_command_action (action_call);
+ set_break_command_call_rtn (stop_all_tasks_handler_fun_addr);
+}
+
+/* Initialize the breakpoint datas for the single-tasks mode. */
+
+void
+close_multi_task_mode (void)
+{
+ set_break_command_action (action_task);
+ set_break_command_call_rtn (0);
+}
+
+/* Hook called after the "set multi-tasks-mode" command has been
+ executed. This function verifies that the debugger is not already
+ debugging a process, or else cancels the user request with an
+ error message. Otherwise, the request is processed by setting
+ MULTI_TASK_MODE to the new value. */
+
+static void
+set_multi_tasks_mode_cmd (char *args, int from_tty,
+ struct cmd_list_element *c)
+{
+ /* If we are already debugging a process, reset MULTI_TASK_MODE_SETSHOW_VAR
+ and report an error. */
+ if (target_has_execution)
+ {
+ multi_task_mode_setshow_var = multi_task_mode;
+ error (_("\
+The multi-tasks mode cannot be changed while debugging a process"));
+ }
+
+ multi_task_mode = multi_task_mode_setshow_var;
+}
+
+void
+_initialize_remote_wtx_tasks (void)
+{
+ add_setshow_boolean_cmd ("multi-tasks-mode", no_class,
+ &multi_task_mode_setshow_var,"\
+Set whether gdb is debugging the whole Ada kernel application on VxWorks.", "\
+Show whether gdb is debugging the whole Ada kernel application on VxWorks.", "\
+If set, on VxWorks, gdb debugs the whole Ada kernel application.",
+ set_multi_tasks_mode_cmd, NULL,
+ &setlist, &showlist);
+}
+
+/* Set the multi-tasks mode user setting to off (zero). */
+
+void
+turn_multi_task_mode_off (void)
+{
+ multi_task_mode = 0;
+ multi_task_mode_setshow_var = 0;
+}
+
+/* Close the multi-tasking support. */
+
+void
+stop_multi_task_mode (void)
+{
+ stop_all_tasks_fun_addr = 0;
+ continue_all_tasks_fun_addr = 0;
+ stop_all_tasks_handler_fun_addr = 0;
+
+ set_break_command_action (action_task);
+ set_break_command_call_rtn (0);
+}
+
+/* Set up the multi-tasks mode.
+
+ Automatically deactivate the multi-tasks mode if the inferior
+ is found to not use Ada tasks. */
+
+void
+start_multi_task_mode (void)
+{
+ set_break_command_action (action_call);
+
+ remote_wtxapi_get_symbol_address (ADA_STOP_ALL_TASKS,
+ &stop_all_tasks_fun_addr);
+ remote_wtxapi_get_symbol_address (ADA_CONTINUE_ALL_TASKS,
+ &continue_all_tasks_fun_addr);
+
+ if (stop_all_tasks_fun_addr == 0 || continue_all_tasks_fun_addr == 0)
+ {
+ warning (_("Your application does not use Ada tasking.\n\
+multi-tasks-mode turned off."));
+ turn_multi_task_mode_off ();
+ stop_multi_task_mode ();
+ return;
+ }
+
+ /* Search for ADA_STOP_ALL_TASKS_HANDLER and install it if we can
+ find it. */
+ remote_wtxapi_get_symbol_address (ADA_STOP_ALL_TASKS_HANDLER,
+ &stop_all_tasks_handler_fun_addr);
+ if (stop_all_tasks_handler_fun_addr != 0)
+ set_break_command_call_rtn (stop_all_tasks_handler_fun_addr);
+}
+
+/* Resume all Ada tasks in our inferior. */
+
+int
+continue_all_ada_tasks ()
+{
+ long *ignored_retval;
+
+ if (continue_all_tasks_fun_addr != 0)
+ return wtxapi_direct_call (continue_all_tasks_fun_addr, &ignored_retval,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
+
+ return 0;
+}
+
+/* Stop all Ada tasks in our inferior. After this operation, the Ada tasks
+ can be either suspended, and stopped, depending of the vxWorks version;
+ this information is returned in STATUS. */
+
+int
+stop_all_ada_tasks (enum wtx_task_status *status)
+{
+ long *ignored_retval;
+
+ if (stop_all_tasks_fun_addr != 0)
+ {
+ *status = WTX_TASK_STATUS_STOPPED;
+ return wtxapi_direct_call (stop_all_tasks_fun_addr, &ignored_retval,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
+ }
+
+ *status = WTX_TASK_STATUS_RUNNING;
+ return 0;
+}
+
diff --git a/gdb/remote-wtx-tasks.h b/gdb/remote-wtx-tasks.h
new file mode 100644
index 0000000..116a5f6
--- /dev/null
+++ b/gdb/remote-wtx-tasks.h
@@ -0,0 +1,53 @@
+/* Ada multi-task functionnalities for VxWorks targets.
+
+ Copyright 2005, 2010, 2011 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+/* FIXME: brobecke/2007-10-19: We're introducing a new API which should
+ be simpler to use.
+
+ In order to avoid colliding with the deprecated interface, we will
+ temporarily break the naming scheme and not prepend our function
+ names with "wtx_tasks_" for now. The plan is to rename all the
+ deprecated routines using the "deprecated_" prefix, followed by
+ renaming these new functions. To be done later. */
+
+/* Task status; used to know which routine to use when resuming the
+ inferior. Note that STOPPED and SUSPENDED are actually the same
+ status on VxWorks 5. */
+
+enum wtx_task_status
+ {
+ WTX_TASK_STATUS_CREATED,
+ WTX_TASK_STATUS_RUNNING,
+ WTX_TASK_STATUS_STOPPED,
+ WTX_TASK_STATUS_SUSPENDED,
+ WTX_TASK_STATUS_UNKNOWN
+ };
+
+int multi_task_mode_is_on (void);
+
+void turn_multi_task_mode_off (void);
+
+void start_multi_task_mode (void);
+
+void stop_multi_task_mode (void);
+
+int continue_all_ada_tasks (void);
+
+int stop_all_ada_tasks (enum wtx_task_status *status);
+
--
1.7.0.4
^ permalink raw reply [flat|nested] 54+ messages in thread
* [PATCH 11/18] Add partition support.
2011-02-24 17:49 Add support for VxWorks 5.x, 6.x and 653 Joel Brobecker
` (8 preceding siblings ...)
2011-02-24 17:55 ` [PATCH 10/18] "multi-tasks-mode" support Joel Brobecker
@ 2011-02-24 17:56 ` Joel Brobecker
2011-02-25 16:17 ` Tom Tromey
2011-02-24 17:56 ` [PATCH 07/18] remote-wtxapi: The WTX API abstraction layer Joel Brobecker
` (7 subsequent siblings)
17 siblings, 1 reply; 54+ messages in thread
From: Joel Brobecker @ 2011-02-24 17:56 UTC (permalink / raw)
To: gdb-patches; +Cc: Joel Brobecker
This is the module which is providing partition support. Since our
implementation is not entirely clean (see other message - right now,
we do some nasty swapping of objfiles in and out of the object_files
list), the code that is being provided here has been cleaned up a bit.
All the nasties have been removed, allowing us to keep the interface
and sufficient implementation for partition-less systems (VxWorks 5.x
and 6.x), but leaving out support for VxWorks 653.
I will look at implementing proper partition support independently of
this effort.
gdb/ChangeLog:
* remote-wtx-pd.h, remote-wtx-pd.c: New files.
---
gdb/remote-wtx-pd.c | 348 +++++++++++++++++++++++++++++++++++++++++++++++++++
gdb/remote-wtx-pd.h | 58 +++++++++
2 files changed, 406 insertions(+), 0 deletions(-)
create mode 100644 gdb/remote-wtx-pd.c
create mode 100644 gdb/remote-wtx-pd.h
diff --git a/gdb/remote-wtx-pd.c b/gdb/remote-wtx-pd.c
new file mode 100644
index 0000000..5d58c3c
--- /dev/null
+++ b/gdb/remote-wtx-pd.c
@@ -0,0 +1,348 @@
+/* Support for the WTX protocol.
+
+ Copyright (C) 2007, 2010, 2011 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#include "defs.h"
+#include "gdb_assert.h"
+#include "objfiles.h"
+#include "source.h"
+#include "remote-wtx-pd.h"
+#include "remote-wtx-opt.h"
+#include "ada-lang.h"
+#include "language.h"
+#include "observer.h"
+#include "command.h"
+#include "gdbcmd.h"
+
+#include <ctype.h>
+
+/* We need to keep the symbols in each PD separate from the others.
+ One of the reasons is that 2 symbols with the same name are allowed to
+ coexist in 653 provided that these 2 symbols live in 2 separate PDs.
+ Another important reason is that virtual memory regions can overlap
+ between PDs, and one symbol address in a PD is not suitable in the
+ context of another PD.
+
+ GDB maintains a global list of objfiles where the symbols can be found.
+ To achieve this separation, we simply maintain one such list per PD in
+ this module. At each PD change, we simply save the objfile list for
+ the current PD, and restore it for the new PD. The net effect is that
+ GDB will only recognize symbols in the current PD, and will complain if
+ a user tries to do any operation that needs symbols from other PDs.
+
+ In practice, GDB maintains a few other global variables that also
+ need to be saved/restored, but the principle remains valid.
+
+ If would have been slicker to actually maintain one list of objfiles
+ for all PDs and modify GDB to automatically switch to the right PD
+ when performing an operation such as inserting a BP in some code that's
+ in a different partition. This would probably not be such a great
+ improvment in terms of usability, but this would require a major
+ overall rework. So we dropped this idea. */
+
+/* Return nonzero if the target system supports PDs. */
+
+int
+wtx_pd_system_has_pds ()
+{
+#if WTX_PROT_VERSION > 2
+ return 1;
+#else
+ return 0;
+#endif
+}
+
+/* Return the name of the PD which ID is equal to PD_ID. If the given PD
+ could not be found, then return "<none>". */
+
+char *
+wtx_pd_get_pd_name (pd_id_t pd_id)
+{
+ struct wtxapi_pd_desc_q *pds;
+
+ pds = wtxapi_pd_info_q_get ();
+ make_cleanup (cleanup_wtxapi_pd_desc_q, pds);
+
+ for (; pds != NULL; pds = pds->next)
+ if (pds->pd_desc.pd_id == pd_id)
+ return xstrdup (pds->pd_desc.pd_name);
+
+ /* Fallback, if we did not find the PD, or if the system does not support
+ PDs, then return a string saying that the given PD does not have a name
+ associated to it. */
+ return xstrdup ("<none>");
+}
+
+/* Return the PD ID for the Protection Domain which name is NAME.
+ Raise an error if this PD does not exist. */
+
+static pd_id_t
+wtx_pd_pd_id_from_name (const char *name)
+{
+ struct wtxapi_pd_desc_q *pds;
+
+ pds = wtxapi_pd_info_q_get ();
+ make_cleanup (cleanup_wtxapi_pd_desc_q, pds);
+
+ while (pds != NULL)
+ if (strcmp (pds->pd_desc.pd_name, name) == 0)
+ return pds->pd_desc.pd_id;
+ else
+ pds = pds->next;
+
+ error (_("Unable to find partition: %s.\n"), name);
+}
+
+/* Set the curent Protection Domain to the given PD ID. No-op on less
+ recent versions of Tornado (T2) where the notion of PD is not supported. */
+
+static void
+switch_to_pd_internal (pd_id_t pd_id, int from_tty)
+{
+ pd_id_t current_pd;
+
+ if (!wtxapi_tool_connected ())
+ error (_("Not attached to a target. Use \"target wtx\" first."));
+
+ current_pd = wtxapi_pd_current_get ();
+
+ if (pd_id == current_pd)
+ {
+ /* Emit a warning when the PD switch has been requested explicitely
+ by the user, to make sure he knows the operation was meaningless
+ and has been aborted. */
+ if (from_tty)
+ warning (_("Partition unchanged, as already set to 0x%lx."), pd_id);
+ return;
+ }
+
+ if (wtx_pd_system_has_pds ())
+ error (_("Operation not implemented yet."));
+}
+
+/* Equivalent to switch_to_pd_internal (pd_id, 1). Useful either as a
+ shortcut to switch_to_pd_internal, or in conjunction with the
+ make_cleanup mechanism. */
+
+void
+wtx_pd_switch_to_pd (pd_id_t pd_id)
+{
+ switch_to_pd_internal (pd_id, 1);
+}
+
+/* On systems where Protection Domains are supported, return the ID of
+ the PD where the given module is loaded. Return NULL_PD if the system
+ does not support PD. */
+
+pd_id_t
+wtx_pd_get_module_pd (module_id_t module_id)
+{
+ int i;
+ struct wtxapi_module_list *module_list =
+ wtxapi_obj_module_list_get (WTX_MOD_FIND_IN_ALL_PD);
+
+ if (module_list == NULL)
+ error (_("Failed to get target list of modules: %s"), wtxapi_err_msg_get ());
+ else
+ make_cleanup (cleanup_wtxapi_module_list, module_list);
+
+ for (i = 0; i < module_list->num_obj_mod; i++)
+ if (module_list->mod_id_array [i] == module_id)
+ return module_list->pd_id_array [i];
+
+ /* If we reach this point, it means we did not find the given module. */
+ error (_("Failed to find module by ID: 0x%x"), module_id);
+}
+
+/* Given the name of a module that has just been unloaded, returni
+ the PD ID where it was loaded. The modules loaded on the current PD
+ are searched first.
+
+ The search is not performed by querying the target server as
+ the module has probably already been unloaded. Instead, this function
+ searches the current object_files list first, and then the object_files
+ list that we have saved for each PD.
+
+ On systems that do not support PDs, simply always return NULL_PD.
+ If the module is unknown to GDB, an error will be reported later
+ when searching the module in the list of objfiles. */
+
+pd_id_t
+wtx_pd_get_unloaded_module_pd (const char *module_name)
+{
+ /* FIXME: Not properly implemented for VxWorks 653 systems yet. */
+ return NULL_PD;
+}
+
+static void
+switch_to_pd_stub (void *pd_id)
+{
+ wtx_pd_switch_to_pd ((pd_id_t) pd_id);
+}
+
+struct cleanup *
+wtx_pd_make_switch_to_pd_cleanup (pd_id_t pd_id)
+{
+ return make_cleanup (switch_to_pd_stub, (void *) pd_id);
+}
+
+/* Switch to the partition where the given task is running.
+ This function is a no-op if we are already in the right PD. */
+
+void
+wtx_pd_switch_to_task_pd (int task_id)
+{
+ pd_id_t task_pd;
+ int success;
+
+ /* Try to retrieve ID of the PD inside which the module is running.
+ This operation may fail in normal conditions (eg when the event
+ we just received for this task is a CTX_EXIT), so abort silently
+ if the lookup fails. */
+ success = wtxapi_get_task_pd (task_id, &task_pd);
+ if (!success)
+ return;
+
+ if (task_pd != wtxapi_pd_current_get ())
+ wtx_pd_switch_to_pd (task_pd);
+}
+
+/* Display the list of PDs on the target. */
+
+static void
+info_partitions_command (char *arg, int from_tty)
+{
+ struct wtxapi_pd_desc_q *pds, *iter;
+ pd_id_t current_pd;
+
+ if (arg != NULL && arg[0] != '\000')
+ warning (_("Unexpected arguments at end of command, ignored."));
+
+ if (!wtxapi_tool_connected ())
+ error (_("Not attached to a target. "
+ "Use the \"target wtx\" command first."));
+
+ current_pd = wtxapi_pd_current_get ();
+ pds = wtxapi_pd_info_q_get ();
+ iter = pds;
+
+ printf_filtered (" PD-ID \t Name \n");
+ while (iter != NULL)
+ {
+ printf_filtered ("%s ", iter->pd_desc.pd_id == current_pd ? "*" : " ");
+ printf_filtered ("0x%x \t %s \n",
+ (unsigned int) iter->pd_desc.pd_id,
+ iter->pd_desc.pd_name);
+ iter = iter->next;
+ }
+ free_wtxapi_pd_desc_q (pds);
+}
+
+/* Implement the "pd" command. */
+
+static void
+partition_command (char *arg, int from_tty)
+{
+ pd_id_t pd_id;
+ STATUS result;
+
+ if (arg == NULL || arg[0] == '\000')
+ error (_("Please specify a partition ID. Use \"info partition\" to\n"
+ "see the IDs of the existing partitions."));
+
+ if (!isdigit (arg[0]))
+ pd_id = wtx_pd_pd_id_from_name (arg);
+ else
+ pd_id = strtol (arg, NULL, 0);
+
+ wtx_pd_switch_to_pd (pd_id);
+}
+
+/* Print a notification to the user if the current PD is no longer
+ the same as the PD that was current at the time when this function
+ was last called. */
+
+static void
+wtx_pd_check_pd_change (void)
+{
+ static pd_id_t pd_after_last_command = NULL_PD;
+
+ pd_id_t previous_pd = pd_after_last_command;
+ pd_after_last_command = wtxapi_pd_current_get ();
+
+ if (pd_after_last_command != previous_pd)
+ {
+ char *pd_name = wtx_pd_get_pd_name (pd_after_last_command);
+ printf_filtered ("[Switching to Partition %s (0x%lx)]\n",
+ pd_name, pd_after_last_command);
+ free (pd_name);
+ }
+}
+
+/* Observer for the "command_post" notification. */
+
+static void
+wtx_pd_command_post_notification (void)
+{
+ /* If the current PD has changed as a consequence of the previous command,
+ then we notify the user about the new PD. */
+ wtx_pd_check_pd_change ();
+}
+
+/* Print the Link Path of all PDs. */
+
+static void
+maintenance_info_link_path (char *arg, int from_tty)
+{
+ struct wtxapi_pd_desc_q *pds, *iter;
+
+ pds = wtxapi_pd_info_q_get ();
+ iter = pds;
+
+ printf ("Partition \t Name \t [Link Path]\n");
+ while (iter != NULL)
+ {
+ const struct wtxapi_pd_desc desc = iter->pd_desc;
+ printf (" 0x%lx \t %s \t [%s]\n",
+ iter->pd_desc.pd_id, iter->pd_desc.pd_name,
+ desc.pd_link_path_str ? desc.pd_link_path_str
+ : "(no link path)");
+ iter = iter->next;
+ }
+ free_wtxapi_pd_desc_q (pds);
+}
+
+void
+_initialize_remote_wtx_pd (void)
+{
+ if (!wtx_pd_system_has_pds ())
+ return;
+
+ observer_attach_command_post (wtx_pd_command_post_notification);
+
+ add_info ("partitions", info_partitions_command,
+ _("Display the list of existing partitions."));
+
+ add_com ("partition", class_run, partition_command,
+ _("Set the current partition."));
+
+ add_cmd ("link-path", class_maintenance, maintenance_info_link_path,
+ _("Display the link path of each partition."),
+ &maintenanceinfolist);
+}
+
diff --git a/gdb/remote-wtx-pd.h b/gdb/remote-wtx-pd.h
new file mode 100644
index 0000000..27e813c
--- /dev/null
+++ b/gdb/remote-wtx-pd.h
@@ -0,0 +1,58 @@
+/* Support for the WTX protocol.
+
+ Copyright (C) 2007, 2010, 2011 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#ifndef REMOTE_WTX_PD_H
+#define REMOTE_WTX_PD_H
+
+#include "defs.h"
+#include "remote-wtxapi.h"
+
+/* This unit provides an abstraction layer to Partitions for both
+ Tornado 2.x & Tornado 653. Although only Tornado 653 systems
+ really support the concept of partitions, we can apply the same
+ concept to Tornado 2.x by imagining that these systems are a
+ special case where there is only one (kernel) partition.
+
+ For historical reasons (in the defunct produce Tornado AE), Partitions
+ are also refered as PD, an accronym for Protection Domain, the technical
+ term used to refer to partitions in Tornado AE. This accronym is very
+ short and handy, so we'll use it in place of partition. */
+
+struct cleanup;
+
+/* On Tornado 2.x, we will use the following NULL_PD to emulate the
+ system unique PD ID. On Tornado 653, we will be using the real
+ PD IDs. */
+#define NULL_PD (0)
+
+int wtx_pd_system_has_pds ();
+
+char *wtx_pd_get_pd_name (pd_id_t pd_id);
+
+void wtx_pd_switch_to_pd (pd_id_t pd_id);
+
+pd_id_t wtx_pd_get_module_pd (module_id_t module_id);
+
+pd_id_t wtx_pd_get_unloaded_module_pd (const char *module_name);
+
+struct cleanup *wtx_pd_make_switch_to_pd_cleanup (pd_id_t pd_id);
+
+void wtx_pd_switch_to_task_pd (int task_id);
+
+#endif
--
1.7.0.4
^ permalink raw reply [flat|nested] 54+ messages in thread
* [PATCH 07/18] remote-wtxapi: The WTX API abstraction layer.
2011-02-24 17:49 Add support for VxWorks 5.x, 6.x and 653 Joel Brobecker
` (9 preceding siblings ...)
2011-02-24 17:56 ` [PATCH 11/18] Add partition support Joel Brobecker
@ 2011-02-24 17:56 ` Joel Brobecker
2011-02-24 19:44 ` Tom Tromey
2011-02-24 17:57 ` [PATCH 13/18] Add new "wtx" target Joel Brobecker
` (6 subsequent siblings)
17 siblings, 1 reply; 54+ messages in thread
From: Joel Brobecker @ 2011-02-24 17:56 UTC (permalink / raw)
To: gdb-patches; +Cc: Joel Brobecker
This provides an API torwards for the WTX protocol which is stable
across versions of WTX. The implementation is a thin binding over
the wtx API provided by WindRiver.
gdb/ChangeLog:
* remote-wtxapi.h, remote-wtxapi.c: New files.
---
gdb/remote-wtxapi.c | 3027 +++++++++++++++++++++++++++++++++++++++++++++++++++
gdb/remote-wtxapi.h | 1221 +++++++++++++++++++++
2 files changed, 4248 insertions(+), 0 deletions(-)
create mode 100644 gdb/remote-wtxapi.c
create mode 100644 gdb/remote-wtxapi.h
diff --git a/gdb/remote-wtxapi.c b/gdb/remote-wtxapi.c
new file mode 100644
index 0000000..54e6e4f
--- /dev/null
+++ b/gdb/remote-wtxapi.c
@@ -0,0 +1,3027 @@
+/* Thin binding for the WTX protocol, for GDB.
+
+ Copyright 2004, 2010, 2011 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#include "defs.h"
+#include "command.h"
+#include "gdbcmd.h"
+#include "gdb_string.h"
+#include "remote-wtxapi.h"
+#include "gdb_assert.h"
+#include "remote-wtx-utils.h"
+#include "remote-wtx-opt.h"
+
+/* This layer is only implemented and tested on WTX 2.0, 3.0 and 4.0. */
+
+#if WTX_PROT_VERSION != 2 && WTX_PROT_VERSION != 3 && WTX_PROT_VERSION != 4
+#error
+#endif
+
+/* In WTX 4.0, the context-related functions take a WTX_CONTEXT * as
+ parameter; In previous versions, it was a WTX_CONTEXT_ID_T and a
+ WTX_CONTEXT_TYPE. The following macros are a klugde to fix that.
+ FIXME: The good method is probably to change the specs of the
+ corresponding functions in remote-wtxapi. */
+static void initialize_context (WTX_CONTEXT * context,
+ WTX_CONTEXT_TYPE context_type,
+ WTX_CONTEXT_ID_T context_id);
+
+#if WTX_PROT_VERSION > 3
+#define MARSHALL_WTX_CONTEXT_PARAM(context) &context
+#else
+#define MARSHALL_WTX_CONTEXT_PARAM(context) \
+ context.contextType, context.contextId
+#endif
+
+#if WTX_PROT_VERSION != 2
+typedef WTX_EVTPT_LIST wtx_evtpt_list;
+#else
+typedef WTX_EVTPT_LIST_2 wtx_evtpt_list;
+#endif
+
+#if WTX_PROT_VERSION != 2
+typedef WTX_MODULE_INFO wtx_module_info;
+#else
+typedef WTX_LD_M_FILE_DESC wtx_module_info;
+#endif
+
+static STATUS (*wtx_initialize) ();
+static STATUS (*wtx_terminate) ();
+static WTX_DESC_Q *(*wtx_info_q) ();
+static STATUS (*wtx_tool_attach) ();
+static int (*wtx_tool_connected) ();
+static STATUS (*wtx_tool_detach) ();
+static STATUS (*wtx_err_clear) ();
+static WTX_ERROR_T (*wtx_err_get) ();
+static WTX_HANDLER_T (*wtx_err_handler_add) ();
+static STATUS (*wtx_err_handler_remove) ();
+static char * (*wtx_err_msg_get) ();
+static WTX_AGENT_MODE_TYPE (*wtx_agent_mode_get) ();
+static STATUS (*wtx_agent_mode_set) ();
+static evtpt_id_t (*wtx_breakpoint_add) ();
+static evtpt_id_t (*wtx_eventpoint_add) ();
+static STATUS (*wtx_eventpoint_delete) ();
+static WTX_EVENT_DESC * (*wtx_event_get) ();
+static WTX_CONTEXT_STATUS (*wtx_context_status_get) ();
+static STATUS (*wtx_context_cont) ();
+static WTX_CONTEXT_ID_T (*wtx_context_create) ();
+static STATUS (*wtx_context_resume) ();
+static evtpt_id_t (*wtx_context_exit_notify_add) ();
+static STATUS (*wtx_context_kill) ();
+static STATUS (*wtx_context_step) ();
+static STATUS (*wtx_context_suspend) ();
+static STATUS (*wtx_context_stop) ();
+static wtx_evtpt_list * (*wtx_eventpoint_list_get) ();
+static STATUS (*wtx_result_free) ();
+static WTX_GOPHER_TAPE * (*wtx_gopher_eval) ();
+static WTX_MEM_INFO * (*wtx_mem_info_get) ();
+static wtxapi_tgt_addr_t (*wtx_mem_alloc) ();
+static int (*wtx_mem_checksum) ();
+static STATUS (*wtx_mem_move) ();
+static STATUS (*wtx_mem_free) ();
+static int (*wtx_mem_read) ();
+static int (*wtx_mem_width_read) ();
+static int (*wtx_mem_write) ();
+static int (*wtx_mem_width_write) ();
+static int (*wtx_mem_set) ();
+static STATUS (*wtx_mem_add_to_pool) ();
+static wtxapi_tgt_addr_t (*wtx_mem_realloc) ();
+static wtxapi_tgt_addr_t (*wtx_mem_align) ();
+static STATUS (*wtx_mem_scan) ();
+static STATUS (*wtx_obj_module_checksum) ();
+static module_id_t (*wtx_obj_module_find_id) ();
+static char * (*wtx_obj_module_find_name) ();
+static WTX_MODULE_INFO * (*wtx_obj_module_info_get) ();
+static wtx_module_info * (*wtx_obj_module_load) ();
+static STATUS (*wtx_obj_module_unload) ();
+static STATUS (*wtx_obj_module_by_name_unload) ();
+static STATUS (*wtx_register_for_event) ();
+static STATUS (*wtx_regs_get) ();
+static STATUS (*wtx_regs_set) ();
+static wtxapi_tgt_addr_t (*wtx_str_to_tgt_addr) ();
+static WTX_CONTEXT_ID_T (*wtx_str_to_context_id) ();
+static WTX_CONTEXT_TYPE (*wtx_str_to_context_type) ();
+static int (*wtx_str_to_int32) ();
+static WTX_EVENT_TYPE (*wtx_str_to_event_type) ();
+static STATUS (*wtx_sym_add) ();
+static WTX_SYMBOL * (*wtx_sym_find) ();
+static WTX_SYM_LIST * (*wtx_sym_list_get) ();
+static WTX_SYM_LIST * (*wtx_sym_list_by_module_id_get) ();
+static WTX_SYM_LIST * (*wtx_sym_list_by_module_name_get) ();
+static STATUS (*wtx_sym_remove) ();
+static WTX_SYM_TBL_INFO * (*wtx_sym_tbl_info_get) ();
+static STATUS (*wtx_target_reset) ();
+static char * (*wtx_ts_name_get) ();
+static int (*wtx_target_cpu_type_get) ();
+static int (*wtx_target_has_fpp_get) ();
+static WTX_ENDIAN_T (*wtx_target_endian_get) ();
+static char * (*wtx_target_bootline_get) ();
+static char * (*wtx_tool_name_get) ();
+static char * (*wtx_ts_version_get) ();
+static STATUS (*wtx_unregister_for_event) ();
+static STATUS (*wtx_direct_call) ();
+static WTX_TS_INFO * (*wtx_ts_info_get) ();
+static STATUS (*wtx_target_attach) ();
+static STATUS (*wtx_probe) ();
+static STATUS (*wtx_timeout_set) ();
+static STATUS (*wtx_timeout_get) ();
+
+#if WTX_PROT_VERSION != 2
+static WTX_MODULE_LIST * (*wtx_obj_module_list_get) ();
+static pd_id_t (*wtx_pd_create) ();
+static pd_id_t (*wtx_pd_kernel_get) ();
+static pd_id_t (*wtx_pd_current_get) ();
+static STATUS (*wtx_pd_current_set) ();
+static WTX_PD_DESC_Q * (*wtx_pd_info_q_get) ();
+#else
+static WTX_MODULE_LIST * (*wtx_obj_module_list) ();
+#endif
+
+/* Conversion from an to a BOOL32. */
+
+#define TO_BOOL(b) (b ? TRUE : FALSE)
+
+#ifndef WTX_PD_CURRENT
+const wtxapi_tgt_addr_t WTX_PD_CURRENT;
+#endif
+
+#ifndef WTX_PD_ALL
+const wtxapi_tgt_addr_t WTX_PD_ALL = -1;
+#endif
+
+#ifndef WTX_MOD_FIND_IN_ALL_PD
+const wtxapi_tgt_addr_t WTX_MOD_FIND_IN_ALL_PD = -1;
+#endif
+
+#ifndef WTX_SYM_FIND_IN_ALL_PD
+const int WTX_SYM_FIND_IN_ALL_PD = -1;
+#endif
+
+#if WTX_PROT_VERSION == 2
+const WTX_CONTEXT_TYPE WTX_CONTEXT_PD = WTX_CONTEXT_ANY_TASK;
+const int WTX_ERR_PD_INVALID_PD = WTX_ERROR;
+#endif
+
+#if WTX_PROT_VERSION > 3
+const WTX_ACTION_TYPE WTX_ACTION_STOP_ALL = WTX_ACTION_ALL_STOP;
+#endif
+
+const int wtxapi_symbol_copy_none = 0;
+const int wtxapi_symbol_copy_name = 1 << 0;
+const int wtxapi_symbol_copy_module_name = 1 << 1;
+
+const pd_id_t invalid_pd_id = WTX_ERROR;
+const evtpt_id_t invalid_module_id = WTX_ERROR;
+const evtpt_id_t invalid_evtpt_id = WTX_ERROR;
+const WTX_CONTEXT_ID_T invalid_context_id = WTX_ERROR;
+const WTX_AGENT_MODE_TYPE invalid_agent_mode = WTX_ERROR;
+const WTX_CONTEXT_STATUS invalid_context_status = WTX_ERROR;
+
+/* Only one PD is allowed in WTX 2.0; NULL_PD is the value of this PD
+ ID. */
+
+const pd_id_t NULL_PD = 0;
+
+/* Symbol list: complete declaration. Based on WTX_SYMBOL and
+ WTX_SYMBOL_LIST. */
+
+struct wtxapi_symbol_list
+{
+ /* First element of the list. */
+ WTX_SYMBOL *first;
+
+ /* Current element (when going through the list with the iterator). */
+ WTX_SYMBOL *current;
+
+ /* Pointer to the result of the WTX operation used to get the symbol
+ list. It is used at deallocation time. */
+ void *wtx_result_to_cleanup;
+};
+
+/* Current WTX handle. */
+
+static HWTX current_wtx_handle = 0;
+
+/* Allocate a new wtxapi_symbol_list and initialize it with
+ WTX_SYM. WTX_SYM should not be deallocated directly by the caller,
+ it will be deallocated by free_wtxapi_symbol_list. */
+
+static struct wtxapi_symbol_list
+ *new_wtxapi_symbol_list (WTX_SYM_LIST *wtx_sym);
+
+
+static struct wtxapi_symbol_list
+ *new_wtxapi_symbol_list_from_symbol (WTX_SYMBOL *wtx_sym);
+
+
+/* Allocate a new wtxapi_module_info, and initialize it with
+ WTX_MINFO. The caller can deallocate WTX_MINFO, as it is fully
+ copied. It does not initialize wtx_minfo->undef_list; it should
+ be handled separatly if needed. */
+
+static struct wtxapi_module_info
+ *new_wtxapi_module_info (WTX_MODULE_INFO * wtx_minfo);
+
+static void
+initialize_context (WTX_CONTEXT *context,
+ WTX_CONTEXT_TYPE context_type,
+ WTX_CONTEXT_ID_T context_id)
+{
+ context->contextType = context_type;
+ context->contextId = context_id;
+#if WTX_PROT_VERSION > 3
+ context->contextSubId = 0;
+#endif
+}
+
+/* Build and initialize a WTX client handle. This handle can then be
+ used to connect to a target server. */
+
+int
+wtxapi_initialize ()
+{
+ return wtx_initialize (¤t_wtx_handle) != WTX_ERROR;
+}
+
+/* Return the current WTX handle. */
+
+HWTX
+wtxapi_get_current_wtx_handle ()
+{
+ return current_wtx_handle;
+}
+
+/* Terminate use of WTX client handle. */
+
+int
+wtxapi_terminate ()
+{
+ return wtx_terminate (current_wtx_handle) != WTX_ERROR;
+}
+
+/* Return list of registred services. NAME_PAT is the reg expression
+ to match svc name. TYPE_PAT is the reg expression to match svc
+ type. KEY_PAT is the reg expression to match svc key. */
+
+WTX_DESC_Q *
+wtxapi_info_q (const char *name_pat, const char *type_pat,
+ const char *key_pat)
+{
+ return wtx_info_q (current_wtx_handle, name_pat, type_pat, key_pat);
+}
+
+/* Connect client to the target server. */
+
+int
+wtxapi_tool_attach (const char *target_name, const char *tool_name)
+{
+ return wtx_tool_attach (current_wtx_handle, target_name,
+ tool_name) != WTX_ERROR;
+}
+
+/* Check tool connection to the server. */
+
+int
+wtxapi_tool_connected ()
+{
+ return wtx_tool_connected (current_wtx_handle) == TRUE;
+}
+
+/* Detach from the target server. */
+
+int
+wtxapi_tool_detach ()
+{
+ return wtx_tool_detach (current_wtx_handle) != WTX_ERROR;
+}
+
+/* Clear any error for the tool. */
+
+int
+wtxapi_err_clear ()
+{
+ return wtx_err_clear (current_wtx_handle) != WTX_ERROR;
+}
+
+/* Return the last error for a handle. */
+
+WTX_ERROR_T
+wtxapi_err_get ()
+{
+ return wtx_err_get (current_wtx_handle);
+}
+
+/* Add an error handler. */
+
+WTX_HANDLER_T
+wtxapi_err_handler_add (WTX_HANDLER_FUNC p_func, void *p_client_data)
+{
+ return wtx_err_handler_add (current_wtx_handle, p_func, p_client_data);
+}
+
+/* Remove error handler for WTX handle. */
+
+int
+wtxapi_err_handler_remove (WTX_HANDLER_T p_handler)
+{
+ return wtx_err_handler_remove (current_wtx_handle, p_handler) != WTX_ERROR;
+}
+
+/* Fetch last WTX API error string. */
+
+const char *
+wtxapi_err_msg_get ()
+{
+ if (current_wtx_handle == 0)
+ return "Invalid WTX handle";
+ else
+ return wtx_err_msg_get (current_wtx_handle);
+}
+
+/* Get agent mode. */
+
+WTX_AGENT_MODE_TYPE
+wtxapi_agent_mode_get ()
+{
+ return wtx_agent_mode_get (current_wtx_handle);
+}
+
+/* Set the mode of the target agent. */
+
+int
+wtxapi_agent_mode_set (WTX_AGENT_MODE_TYPE agent_mode)
+{
+ return wtx_agent_mode_set (current_wtx_handle, agent_mode) != WTX_ERROR;
+}
+
+/* Create a new breakpoint. */
+
+evtpt_id_t
+wtxapi_breakpoint_add (WTX_CONTEXT_TYPE context_type,
+ WTX_CONTEXT_ID_T context_id, wtxapi_tgt_addr_t tgt_addr)
+{
+ WTX_CONTEXT context;
+ initialize_context (&context, context_type, context_id);
+ return wtx_breakpoint_add (current_wtx_handle,
+ MARSHALL_WTX_CONTEXT_PARAM (context), tgt_addr);
+}
+
+/* Create a new event point. */
+
+evtpt_id_t
+wtxapi_eventpoint_add (struct wtxapi_evtpt *p_evtpt)
+{
+#if WTX_PROT_VERSION != 2
+ WTX_EVTPT wtx_evtpt;
+#else
+ WTX_EVTPT_2 wtx_evtpt;
+#endif
+ memset (&wtx_evtpt, 0, sizeof (wtx_evtpt));
+ wtx_evtpt.event.eventType = p_evtpt->event.event_type;
+ wtx_evtpt.event.numArgs = p_evtpt->event.num_args;
+ wtx_evtpt.event.args = p_evtpt->event.args;
+ wtx_evtpt.context.contextType = p_evtpt->context.context_type;
+
+ /* In WTX 4.1, WTX_CONTEXT_ANY_TASK does not work if the context ID
+ is not null; in the previous versions, it is simply ignored; so
+ unconditionally set the context ID to zero in the "any task"
+ case. */
+ if (p_evtpt->context.context_type == WTX_CONTEXT_ANY_TASK)
+ wtx_evtpt.context.contextId = 0;
+ else
+ wtx_evtpt.context.contextId = p_evtpt->context.context_id;
+
+ wtx_evtpt.action.actionType = p_evtpt->action.action_type;
+ wtx_evtpt.action.actionArg = p_evtpt->action.action_arg;
+ wtx_evtpt.action.callRtn = p_evtpt->action.call_rtn;
+ wtx_evtpt.action.callArg = p_evtpt->action.call_arg;
+ return wtx_eventpoint_add (current_wtx_handle, &wtx_evtpt);
+}
+
+/* Delete eventpoint from the target. */
+
+int
+wtxapi_eventpoint_delete (evtpt_id_t evtpt_id)
+{
+ return wtx_eventpoint_delete (current_wtx_handle, evtpt_id) != WTX_ERROR;
+}
+
+/* Parse a CTX_EXIT event string, and return the associated EVENT. */
+
+static void
+wtxapi_parse_ctx_exit_event (char *event_str,
+ struct wtxapi_ctx_exit_event *event)
+{
+ char *context_id_str = NULL;
+ char *context_type_str = NULL;
+ char *exit_code_str = NULL;
+
+ if (WTX_PROT_VERSION > 3)
+ {
+ /* Format: "Context_Type Context_ID xxx Exit_Code..."
+ (where "xxx" is a field that we can ignore). */
+ event_str = get_space_delimited_token (event_str, &context_type_str);
+ event_str = get_space_delimited_token (event_str, &context_id_str);
+ event_str = skip_space_delimited_token (event_str);
+ event_str = get_space_delimited_token (event_str, &exit_code_str);
+ }
+ else
+ {
+ /* Format: "Context_Type Context_ID Exit_Code". */
+ event_str = get_space_delimited_token (event_str, &context_type_str);
+ event_str = get_space_delimited_token (event_str, &context_id_str);
+ event_str = get_space_delimited_token (event_str, &exit_code_str);
+ }
+
+ event->context_id = wtxapi_str_to_context_id (context_id_str);
+ event->context_type = wtxapi_str_to_context_type (context_type_str);
+ event->exit_code = wtxapi_str_to_int32 (exit_code_str);
+
+ wtx_opt_events_debug (1, "CTX_EXIT: "
+ "context_id = \"%s\" 0x%lx, "
+ "context_type = \"%s\" %d, "
+ "exit_code = \"%s\" %d",
+ context_id_str, event->context_id,
+ context_type_str, event->context_type,
+ exit_code_str, event->exit_code);
+ xfree (context_id_str);
+ xfree (context_type_str);
+ xfree (exit_code_str);
+
+}
+
+/* Parse a DATA_ACCESS event string, and return the associated EVENT. */
+
+static void
+wtxapi_parse_data_access_event (char *event_str,
+ struct wtxapi_data_access_event *event)
+{
+ char *task_id_str = NULL;
+ char *context_id_str = NULL;
+ char *context_type_str = NULL;
+ char *data_addr_str = NULL;
+
+ /* The formatting of the DATA_ACCESS event depends on the WTX
+ protocol version. Extract each of the appropriate field
+ and discard the others. */
+
+ if (WTX_PROT_VERSION == 2)
+ {
+ /* Format: "Task_ID/Context_ID Context_Type xxx xxx xxx Data_Addr..."
+ (where "xxx" is a field that we can ignore, and the Task_ID and
+ Context_ID are identical). */
+ event_str = get_space_delimited_token (event_str, &task_id_str);
+ event_str = get_space_delimited_token (event_str, &context_type_str);
+ event_str = skip_space_delimited_token (event_str);
+ event_str = skip_space_delimited_token (event_str);
+ event_str = skip_space_delimited_token (event_str);
+ event_str = get_space_delimited_token (event_str, &data_addr_str);
+ context_id_str = xstrdup (task_id_str);
+ }
+ else if (WTX_PROT_VERSION == 3)
+ {
+ /* Format: "Context_ID Context_Type xxx xxx xxx Data_Addr Task_ID ..."
+ (where "xxx" is a field that we can ignore). */
+ event_str = get_space_delimited_token (event_str, &context_id_str);
+ event_str = get_space_delimited_token (event_str, &context_type_str);
+ event_str = skip_space_delimited_token (event_str);
+ event_str = skip_space_delimited_token (event_str);
+ event_str = skip_space_delimited_token (event_str);
+ event_str = get_space_delimited_token (event_str, &data_addr_str);
+ event_str = get_space_delimited_token (event_str, &task_id_str);
+ }
+ else
+ {
+ /* Format: "xxx Context_Type Context_ID xxx xxx Task_ID xxx
+ xxx xxx xxx Data_Addr"
+ (where "xxx" is a field that we can ignore). */
+ event_str = skip_space_delimited_token (event_str);
+ event_str = get_space_delimited_token (event_str, &context_type_str);
+ event_str = get_space_delimited_token (event_str, &context_id_str);
+ event_str = skip_space_delimited_token (event_str);
+ event_str = skip_space_delimited_token (event_str);
+ event_str = get_space_delimited_token (event_str, &task_id_str);
+ event_str = skip_space_delimited_token (event_str);
+ event_str = skip_space_delimited_token (event_str);
+ event_str = skip_space_delimited_token (event_str);
+ event_str = skip_space_delimited_token (event_str);
+ event_str = get_space_delimited_token (event_str, &data_addr_str);
+ }
+
+ event->task_id = wtxapi_str_to_context_id (task_id_str);
+ event->context_id = wtxapi_str_to_context_id (context_id_str);
+ event->context_type = wtxapi_str_to_context_type (context_type_str);
+ event->data_addr = wtxapi_str_to_tgt_addr (data_addr_str);
+
+ wtx_opt_events_debug (1, "DATA_ACCESS: "
+ "task_id = \"%s\" 0x%lx, "
+ "context_id = \"%s\" 0x%lx, "
+ "context_type = \"%s\" %d, "
+ "data_addr = \"%s\" 0x%s",
+ task_id_str, event->task_id,
+ context_id_str, event->context_id,
+ context_type_str, event->context_type,
+ data_addr_str,
+ paddress (target_gdbarch, event->data_addr));
+ xfree (task_id_str);
+ xfree (context_id_str);
+ xfree (context_type_str);
+ xfree (data_addr_str);
+}
+
+/* Parse an EXCEPTION event string, and return the associated EVENT. */
+
+static void
+wtxapi_parse_exception_event (char *event_str,
+ struct wtxapi_exception_event *event)
+{
+ char *context_id_str = NULL;
+ char *context_type_str = NULL;
+ char *exception_value_str = NULL;
+
+ /* The formatting of the EXCEPTION event depends on the WTX
+ protocol version. Extract each of the appropriate field
+ and discard the others. */
+
+ if (WTX_PROT_VERSION < 4)
+ {
+ /* Format: "Context_Type Context_ID ...". */
+ event_str = get_space_delimited_token (event_str, &context_type_str);
+ event_str = get_space_delimited_token (event_str, &context_id_str);
+ event_str = get_space_delimited_token (event_str, &exception_value_str);
+ }
+ else
+ {
+ /* Format: "xxx xxx xxx xxx Context_Type Context_ID xxx Data_Addr ..."
+ (where "xxx" are fields we can ignore). */
+ event_str = skip_space_delimited_token (event_str);
+ event_str = skip_space_delimited_token (event_str);
+ event_str = skip_space_delimited_token (event_str);
+ event_str = skip_space_delimited_token (event_str);
+ event_str = get_space_delimited_token (event_str, &context_type_str);
+ event_str = get_space_delimited_token (event_str, &context_id_str);
+ event_str = skip_space_delimited_token (event_str);
+ event_str = get_space_delimited_token (event_str, &exception_value_str);
+ }
+
+ event->context_id = wtxapi_str_to_context_id (context_id_str);
+ event->context_type = wtxapi_str_to_context_type (context_type_str);
+ event->exception_value = wtxapi_str_to_tgt_addr (exception_value_str);
+
+ wtx_opt_events_debug (1, "EXCEPTION: "
+ "context_id = \"%s\" 0x%lx, "
+ "context_type = \"%s\" %d, "
+ "exception_value = \"%s\" %s",
+ context_id_str, event->context_id,
+ context_type_str, event->context_type,
+ exception_value_str,
+ hex_string (event->exception_value));
+ xfree (context_id_str);
+ xfree (context_type_str);
+}
+
+/* Parse an OBJ_LOADED event string, and return the associated EVENT. */
+
+static void
+wtxapi_parse_obj_loaded_event (char *event_str,
+ struct wtxapi_obj_loaded_event *event)
+{
+ char *module_id_str = NULL;
+
+ /* Format: "Module_Id Module_Name [...]", but we only need
+ the module ID. */
+ event_str = get_space_delimited_token (event_str, &module_id_str);
+ event->module_id = wtxapi_str_to_int32 (module_id_str);
+
+ wtx_opt_events_debug (1, "OBJ_LOADED: module_id_str = \"%s\" 0x%x",
+ module_id_str, event->module_id);
+
+ xfree (module_id_str);
+}
+
+/* Parse an OBJ_UNLOADED event string, and return the associated EVENT. */
+
+static void
+wtxapi_parse_obj_unloaded_event (char *event_str,
+ struct wtxapi_obj_unloaded_event *event)
+{
+ /* Format: "Module_Id Module_Name [...]", but we only need
+ the module filename. */
+ event_str = skip_space_delimited_token (event_str);
+ event_str = get_space_delimited_token (event_str, &event->module_filename);
+
+ wtx_opt_events_debug (1, "OBJ_LOADED: module_filename = \"%s\"",
+ event->module_filename);
+}
+
+/* Parse a TEXT_ACCESS event string, and return the associated EVENT. */
+
+static void
+wtxapi_parse_text_access_event (char *event_str,
+ struct wtxapi_text_access_event *event)
+{
+ char *task_id_str = NULL;
+ char *context_id_str = NULL;
+ char *context_type_str = NULL;
+ char *text_addr_str = NULL;
+
+ /* The formatting of the TEXT_ACCESS event depends on the WTX
+ protocol version. Extract each of the appropriate field
+ and discard the others. */
+
+ if (WTX_PROT_VERSION == 2)
+ {
+ /* Format: "Task_ID/Context_ID Context_Type Text_Addr ..."
+ (the Task_ID and Context_ID are equal). */
+ event_str = get_space_delimited_token (event_str, &task_id_str);
+ event_str = get_space_delimited_token (event_str, &context_type_str);
+ event_str = get_space_delimited_token (event_str, &text_addr_str);
+ context_id_str = xstrdup (task_id_str);
+ }
+ else if (WTX_PROT_VERSION == 3)
+ {
+ /* Format: "Context_ID Context_Type Text_Addr xxx xxx Task_ID ..."
+ (where "xxx" is a field that we can ignore). */
+ event_str = get_space_delimited_token (event_str, &context_id_str);
+ event_str = get_space_delimited_token (event_str, &context_type_str);
+ event_str = get_space_delimited_token (event_str, &text_addr_str);
+ event_str = skip_space_delimited_token (event_str);
+ event_str = skip_space_delimited_token (event_str);
+ event_str = get_space_delimited_token (event_str, &task_id_str);
+ }
+ else
+ {
+ /* Format: "xxx Context_Type Context_ID xxx xxx Task_ID xxx Text_Addr..."
+ (where "xxx" is a field that we can ignore). */
+ event_str = skip_space_delimited_token (event_str);
+ event_str = get_space_delimited_token (event_str, &context_type_str);
+ event_str = get_space_delimited_token (event_str, &context_id_str);
+ event_str = skip_space_delimited_token (event_str);
+ event_str = skip_space_delimited_token (event_str);
+ event_str = get_space_delimited_token (event_str, &task_id_str);
+ event_str = skip_space_delimited_token (event_str);
+ event_str = get_space_delimited_token (event_str, &text_addr_str);
+ }
+
+ /* With WTX version 3 and later and when in system mode, the task ID
+ in the event string is apparently not the ID we are looking for.
+ Get the current task ID differently. */
+ /* brobecker/2007-08-31: Not sure what the wrong task ID could be.
+ So, for now, do nothing special; enhance later if we find some
+ evidence that it is necessary. */
+
+ event->task_id = wtxapi_str_to_context_id (task_id_str);
+ event->context_id = wtxapi_str_to_context_id (context_id_str);
+ event->context_type = wtxapi_str_to_context_type (context_type_str);
+ event->text_addr = wtxapi_str_to_tgt_addr (text_addr_str);
+
+ wtx_opt_events_debug (1, "TEXT_ACCESS: "
+ "task_id = \"%s\" 0x%lx, "
+ "context_id = \"%s\" 0x%lx, "
+ "context_type = \"%s\" %d, "
+ "text_addr = \"%s\" 0x%s",
+ task_id_str, event->task_id,
+ context_id_str, event->context_id,
+ context_type_str, event->context_type,
+ text_addr_str,
+ paddress (target_gdbarch, event->text_addr));
+
+ xfree (task_id_str);
+ xfree (context_id_str);
+ xfree (context_type_str);
+ xfree (text_addr_str);
+}
+
+/* Parse a VIO_WRITE event string, the given DATA and its associated
+ DATA_LEN, and return the corresponding EVENT. */
+
+static void
+wtxapi_parse_vio_write_event (char *event_str, char *data, int data_len,
+ struct wtxapi_vio_write_event *event)
+{
+ char *channel_id_str = NULL;
+
+ /* Format: "Channel_Id". The rest of the information is
+ inside the additional_data. */
+ event_str = get_space_delimited_token (event_str, &channel_id_str);
+
+ event->channel_id = atoi (event_str);
+
+ event->data = xmalloc ((data_len + 1) * sizeof (char));
+ strncpy (event->data, data, data_len);
+ event->data[data_len] = '\0';
+
+ wtx_opt_events_debug (1, "VIO_WRITE: "
+ "channel_id = \"%s\" %d, "
+ "data = \"%s\"",
+ channel_id_str, event->channel_id,
+ event->data);
+
+ xfree (channel_id_str);
+}
+
+
+/* Get the next event from the event queue if one is available.
+ Return NULL otherwise.
+
+ The new event must be deallocated after use. */
+
+struct wtxapi_event_desc *
+wtxapi_event_get (void)
+{
+ WTX_EVENT_DESC *event_desc = wtx_event_get (current_wtx_handle);
+ char *event_str;
+ char *token = NULL;
+ struct wtxapi_event_desc *result;
+
+ if (event_desc == NULL)
+ return NULL;
+ if (event_desc->event == NULL)
+ {
+ /* That's kind of dumb, but it actually happens. */
+ wtx_result_free (current_wtx_handle, event_desc);
+ return NULL;
+ }
+
+ wtx_opt_events_debug (2, "wtxapi_event_get: \"%s\"", event_desc->event);
+
+ result = xmalloc (sizeof (struct wtxapi_event_desc));
+
+ /* Get the event type from the first token in the event string. */
+ event_str = event_desc->event;
+ event_str = get_space_delimited_token (event_str, &token);
+ result->event_type = wtxapi_str_to_event_type (token);
+ xfree (token);
+
+ switch (result->event_type)
+ {
+ case WTX_EVENT_CTX_EXIT:
+ wtxapi_parse_ctx_exit_event (event_str, &result->desc.ctx_exit);
+ break;
+
+ case WTX_EVENT_DATA_ACCESS:
+ wtxapi_parse_data_access_event (event_str, &result->desc.data_access);
+ break;
+
+ case WTX_EVENT_EXCEPTION:
+ wtxapi_parse_exception_event (event_str, &result->desc.exception);
+ break;
+
+ case WTX_EVENT_OBJ_LOADED:
+ wtxapi_parse_obj_loaded_event (event_str, &result->desc.obj_loaded);
+ break;
+
+ case WTX_EVENT_OBJ_UNLOADED:
+ wtxapi_parse_obj_unloaded_event (event_str,
+ &result->desc.obj_unloaded);
+ break;
+
+ case WTX_EVENT_TEXT_ACCESS:
+ wtxapi_parse_text_access_event (event_str, &result->desc.text_access);
+ break;
+
+ case WTX_EVENT_VIO_WRITE:
+ wtxapi_parse_vio_write_event (event_str,
+ event_desc->addlData,
+ event_desc->addlDataLen,
+ &result->desc.vio_write);
+ break;
+
+ case WTX_EVENT_EVTPT_ADDED:
+ case WTX_EVENT_EVTPT_DELETED:
+ /* We do not handle eventpoints added/removed by other tools.
+ So ignore these events by falling back to the "default" case. */
+ default:
+ /* Ignore this event. */
+ xfree (result);
+ result = NULL;
+ break;
+ }
+
+ wtx_result_free (current_wtx_handle, event_desc);
+ return result;
+}
+
+WTX_CONTEXT_STATUS
+wtxapi_context_status_get (WTX_CONTEXT_TYPE context_type,
+ WTX_CONTEXT_ID_T context_id)
+{
+ WTX_CONTEXT context;
+ initialize_context (&context, context_type, context_id);
+ return wtx_context_status_get (current_wtx_handle,
+ MARSHALL_WTX_CONTEXT_PARAM (context));
+}
+
+
+/* Continue execution of target context. */
+
+int
+wtxapi_context_cont (WTX_CONTEXT_TYPE context_type,
+ WTX_CONTEXT_ID_T context_id)
+{
+ WTX_CONTEXT context;
+ initialize_context (&context, context_type, context_id);
+ return wtx_context_cont (current_wtx_handle,
+ MARSHALL_WTX_CONTEXT_PARAM (context)) != WTX_ERROR;
+}
+
+/* Create a context on target. */
+
+WTX_CONTEXT_ID_T
+wtxapi_context_create (struct wtxapi_context_desc *p_context_desc)
+{
+ int ix;
+ WTX_CONTEXT_DESC context_desc;
+ memset (&context_desc, 0, sizeof (context_desc));
+#if WTX_PROT_VERSION != 2
+ context_desc.wtxContextType = p_context_desc->context_type;
+
+ if (p_context_desc->context_type == WTX_CONTEXT_PD)
+ {
+ context_desc.wtxContextDef.wtxPdContextDef.name =
+ p_context_desc->wtx_context_def.pd_context.name;
+ context_desc.wtxContextDef.wtxPdContextDef.options =
+ p_context_desc->wtx_context_def.pd_context.options;
+ context_desc.wtxContextDef.wtxPdContextDef.heapSize =
+ p_context_desc->wtx_context_def.pd_context.heap_size;
+ context_desc.wtxContextDef.wtxPdContextDef.lowPriority =
+ p_context_desc->wtx_context_def.pd_context.low_priority;
+ context_desc.wtxContextDef.wtxPdContextDef.highPriority =
+ p_context_desc->wtx_context_def.pd_context.high_priority;
+ context_desc.wtxContextDef.wtxPdContextDef.pagePoolList =
+ p_context_desc->wtx_context_def.pd_context.page_pool_list;
+ context_desc.wtxContextDef.wtxPdContextDef.destroyRtn =
+ p_context_desc->wtx_context_def.pd_context.destroy_rtn;
+ context_desc.wtxContextDef.wtxPdContextDef.linkPath =
+ p_context_desc->wtx_context_def.pd_context.link_path;
+ context_desc.wtxContextDef.wtxPdContextDef.redirIn =
+ p_context_desc->wtx_context_def.pd_context.redir_in;
+ context_desc.wtxContextDef.wtxPdContextDef.redirOut =
+ p_context_desc->wtx_context_def.pd_context.redir_out;
+ context_desc.wtxContextDef.wtxPdContextDef.redirErr =
+ p_context_desc->wtx_context_def.pd_context.redir_err;
+ context_desc.wtxContextDef.wtxPdContextDef.argc =
+ p_context_desc->wtx_context_def.pd_context.argc;
+ context_desc.wtxContextDef.wtxPdContextDef.argv =
+ p_context_desc->wtx_context_def.pd_context.argv;
+ }
+ else
+ {
+ context_desc.wtxContextDef.wtxTaskContextDef.pdId =
+ p_context_desc->wtx_context_def.task_context.pd_id;
+ context_desc.wtxContextDef.wtxTaskContextDef.returnType =
+ p_context_desc->wtx_context_def.task_context.return_type;
+ context_desc.wtxContextDef.wtxTaskContextDef.name =
+ p_context_desc->wtx_context_def.task_context.name;
+ context_desc.wtxContextDef.wtxTaskContextDef.priority =
+ p_context_desc->wtx_context_def.task_context.priority;
+ context_desc.wtxContextDef.wtxTaskContextDef.options =
+ p_context_desc->wtx_context_def.task_context.options;
+ context_desc.wtxContextDef.wtxTaskContextDef.stackBase =
+ p_context_desc->wtx_context_def.task_context.stack_base;
+ context_desc.wtxContextDef.wtxTaskContextDef.stackSize =
+ p_context_desc->wtx_context_def.task_context.stack_size;
+ context_desc.wtxContextDef.wtxTaskContextDef.entry =
+ p_context_desc->wtx_context_def.task_context.entry;
+ context_desc.wtxContextDef.wtxTaskContextDef.redirIn =
+ p_context_desc->wtx_context_def.task_context.redir_in;
+ context_desc.wtxContextDef.wtxTaskContextDef.redirOut =
+ p_context_desc->wtx_context_def.task_context.redir_out;
+ context_desc.wtxContextDef.wtxTaskContextDef.redirErr =
+ p_context_desc->wtx_context_def.task_context.redir_err;
+ context_desc.wtxContextDef.wtxTaskContextDef.argc =
+ p_context_desc->wtx_context_def.task_context.argc;
+ context_desc.wtxContextDef.wtxTaskContextDef.argv =
+ p_context_desc->wtx_context_def.task_context.argv;
+ }
+
+#else
+
+ /* In WTX 2.0, we cannot create a new PD. */
+
+ if (p_context_desc->context_type == WTX_CONTEXT_PD)
+ return invalid_context_id;
+
+ context_desc.contextType = p_context_desc->context_type;
+ context_desc.returnType =
+ p_context_desc->wtx_context_def.task_context.return_type;
+ context_desc.name = p_context_desc->wtx_context_def.task_context.name;
+ context_desc.priority =
+ p_context_desc->wtx_context_def.task_context.priority;
+ context_desc.options = p_context_desc->wtx_context_def.task_context.options;
+ context_desc.stackBase =
+ p_context_desc->wtx_context_def.task_context.stack_base;
+ context_desc.stackSize =
+ p_context_desc->wtx_context_def.task_context.stack_size;
+ context_desc.entry = p_context_desc->wtx_context_def.task_context.entry;
+ context_desc.redirIn = p_context_desc->wtx_context_def.task_context.redir_in;
+ context_desc.redirOut =
+ p_context_desc->wtx_context_def.task_context.redir_out;
+ for (ix = 0; ix < WTX_MAX_ARG_CNT; ix++)
+ if (ix < p_context_desc->wtx_context_def.task_context.argc)
+ context_desc.args[ix] =
+ p_context_desc->wtx_context_def.task_context.argv[ix];
+ else
+ context_desc.args[ix] = NULL_PD;
+#endif
+ return wtx_context_create (current_wtx_handle, &context_desc);
+}
+
+/* Resume execution of a target context. */
+
+int
+wtxapi_context_resume (WTX_CONTEXT_TYPE context_type,
+ WTX_CONTEXT_ID_T context_id)
+{
+ WTX_CONTEXT context;
+ initialize_context (&context, context_type, context_id);
+ return wtx_context_resume (current_wtx_handle,
+ MARSHALL_WTX_CONTEXT_PARAM (context))
+ != WTX_ERROR;
+}
+
+/* Add exit evpt notification. */
+
+evtpt_id_t
+wtxapi_context_exit_notify_add (WTX_CONTEXT_TYPE context_type,
+ WTX_CONTEXT_ID_T context_id)
+{
+ WTX_CONTEXT context;
+ initialize_context (&context, context_type, context_id);
+ return wtx_context_exit_notify_add (current_wtx_handle,
+ MARSHALL_WTX_CONTEXT_PARAM (context));
+}
+
+/* Kill a target context. */
+
+int
+wtxapi_context_kill (WTX_CONTEXT_TYPE context_type,
+ WTX_CONTEXT_ID_T context_id)
+{
+ WTX_CONTEXT context;
+ initialize_context (&context, context_type, context_id);
+#if WTX_PROT_VERSION != 2
+ return wtx_context_kill (current_wtx_handle,
+ MARSHALL_WTX_CONTEXT_PARAM (context),
+ WTX_PD_DELETE_OPTION_NONE) != WTX_ERROR;
+#else
+ return wtx_context_kill (current_wtx_handle,
+ MARSHALL_WTX_CONTEXT_PARAM (context)) != WTX_ERROR;
+#endif
+}
+
+/* Single step exec of target context. */
+
+int
+wtxapi_context_step (WTX_CONTEXT_TYPE context_type,
+ WTX_CONTEXT_ID_T context_id, wtxapi_tgt_addr_t step_start,
+ wtxapi_tgt_addr_t step_end)
+{
+ WTX_CONTEXT context;
+ initialize_context (&context, context_type, context_id);
+ return wtx_context_step (current_wtx_handle,
+ MARSHALL_WTX_CONTEXT_PARAM (context),
+ step_start, step_end) != WTX_ERROR;
+}
+
+/* Suspend a target context. */
+
+int
+wtxapi_context_suspend (WTX_CONTEXT_TYPE context_type,
+ WTX_CONTEXT_ID_T context_id)
+{
+ WTX_CONTEXT context;
+ initialize_context (&context, context_type, context_id);
+ return wtx_context_suspend (current_wtx_handle,
+ MARSHALL_WTX_CONTEXT_PARAM (context))
+ != WTX_ERROR;
+}
+
+int
+wtxapi_context_stop (WTX_CONTEXT_TYPE context_type,
+ WTX_CONTEXT_ID_T context_id)
+{
+ WTX_CONTEXT context;
+ initialize_context (&context, context_type, context_id);
+
+#if WTX_PROT_VERSION != 2
+ return wtx_context_stop (current_wtx_handle,
+ MARSHALL_WTX_CONTEXT_PARAM (context)) != WTX_ERROR;
+#else
+ /* FIXME : wtxContextStop does not exist on WTX 2.0. For now, use
+ wtxContextSuspend as a workaround. */
+
+ return wtx_context_suspend (current_wtx_handle,
+ MARSHALL_WTX_CONTEXT_PARAM (context))
+ != WTX_ERROR;
+#endif
+}
+
+/* List event points on TS. */
+
+struct wtxapi_evtpt_list *
+wtxapi_eventpoint_list_get ()
+{
+ int ix;
+ struct wtxapi_evtpt_list *evtpt_list;
+ wtx_evtpt_list *wtx_list;
+ wtx_list = wtx_eventpoint_list_get (current_wtx_handle);
+
+ if (!wtx_list)
+ return NULL;
+
+ evtpt_list = (struct wtxapi_evtpt_list *)
+ xmalloc (sizeof (struct wtxapi_evtpt_list));
+ evtpt_list->n_evtpt = wtx_list->nEvtpt;
+ evtpt_list->p_evtpt_info = (struct wtxapi_evtpt_info *)
+ xmalloc (sizeof (struct wtxapi_evtpt_info) * wtx_list->nEvtpt);
+ for (ix = 0; ix < wtx_list->nEvtpt; ix++)
+ {
+ evtpt_list->p_evtpt_info[ix].wtx_evtpt.event.event_type =
+ wtx_list->pEvtptInfo[ix].wtxEvtpt.event.eventType;
+ evtpt_list->p_evtpt_info[ix].wtx_evtpt.event.num_args =
+ wtx_list->pEvtptInfo[ix].wtxEvtpt.event.numArgs;
+ evtpt_list->p_evtpt_info[ix].wtx_evtpt.event.args = (wtxapi_tgt_arg_t *)
+ xmalloc (wtx_list->pEvtptInfo[ix].wtxEvtpt.event.numArgs *
+ sizeof (wtxapi_tgt_arg_t));
+ memcpy (evtpt_list->p_evtpt_info[ix].wtx_evtpt.event.args,
+ wtx_list->pEvtptInfo[ix].wtxEvtpt.event.args,
+ wtx_list->pEvtptInfo[ix].wtxEvtpt.event.numArgs *
+ sizeof (wtxapi_tgt_arg_t));
+ evtpt_list->p_evtpt_info[ix].wtx_evtpt.context.context_type =
+ wtx_list->pEvtptInfo[ix].wtxEvtpt.context.contextType;
+ evtpt_list->p_evtpt_info[ix].wtx_evtpt.context.context_id =
+ wtx_list->pEvtptInfo[ix].wtxEvtpt.context.contextId;
+ evtpt_list->p_evtpt_info[ix].wtx_evtpt.action.action_type =
+ wtx_list->pEvtptInfo[ix].wtxEvtpt.action.actionType;
+ evtpt_list->p_evtpt_info[ix].wtx_evtpt.action.action_arg =
+ wtx_list->pEvtptInfo[ix].wtxEvtpt.action.actionArg;
+ evtpt_list->p_evtpt_info[ix].wtx_evtpt.action.call_rtn =
+ wtx_list->pEvtptInfo[ix].wtxEvtpt.action.callRtn;
+ evtpt_list->p_evtpt_info[ix].wtx_evtpt.action.call_arg =
+ wtx_list->pEvtptInfo[ix].wtxEvtpt.action.callArg;
+ evtpt_list->p_evtpt_info[ix].tool_id = wtx_list->pEvtptInfo[ix].toolId;
+ evtpt_list->p_evtpt_info[ix].evtpt_num =
+ wtx_list->pEvtptInfo[ix].evtptNum;
+ }
+
+ wtx_result_free (current_wtx_handle, wtx_list);
+ return evtpt_list;
+}
+
+/* Free mem allocated by WTX API call. */
+
+int
+wtxapi_result_free (void *p_result)
+{
+ return wtx_result_free (current_wtx_handle, p_result) != WTX_ERROR;
+}
+
+/* Evaluate Gopher string on target. */
+
+WTX_GOPHER_TAPE *
+wtxapi_gopher_eval (pd_id_t pd_id, const char *input_string)
+{
+#if WTX_PROT_VERSION != 2
+ return wtx_gopher_eval (current_wtx_handle, pd_id, input_string);
+#else
+ return wtx_gopher_eval (current_wtx_handle, input_string);
+#endif
+}
+
+/* Get info about memory pool. */
+
+WTX_MEM_INFO *
+wtxapi_mem_info_get (pd_id_t pd_id)
+{
+#if WTX_PROT_VERSION != 2
+ return wtx_mem_info_get (current_wtx_handle, pd_id);
+#else
+ return wtx_mem_info_get (current_wtx_handle);
+#endif
+}
+
+/* Alloc blocks in memory pool. */
+
+wtxapi_tgt_addr_t
+wtxapi_mem_alloc (pd_id_t pd_id, int num_bytes)
+{
+#if WTX_PROT_VERSION != 2
+ return wtx_mem_alloc (current_wtx_handle, pd_id, num_bytes);
+#else
+ return wtx_mem_alloc (current_wtx_handle, num_bytes);
+#endif
+}
+
+/* Perform checksum on target memory. */
+
+int
+wtxapi_mem_checksum (pd_id_t pd_id, wtxapi_tgt_addr_t start_addr,
+ int num_bytes)
+{
+#if WTX_PROT_VERSION != 2
+ return wtx_mem_checksum (current_wtx_handle, pd_id, start_addr, num_bytes);
+#else
+ return wtx_mem_checksum (current_wtx_handle, start_addr, num_bytes);
+#endif
+}
+
+/* Move a block of target memory. */
+
+int
+wtxapi_mem_move (pd_id_t src_pd_id, wtxapi_tgt_addr_t src_addr,
+ pd_id_t dst_pd_id, wtxapi_tgt_addr_t dest_addr, int num_bytes)
+{
+#if WTX_PROT_VERSION != 2
+ return wtx_mem_move (current_wtx_handle, src_pd_id, src_addr, dst_pd_id,
+ dest_addr, num_bytes) != WTX_ERROR;
+#else
+ return wtx_mem_move (current_wtx_handle, src_addr, dest_addr,
+ num_bytes) != WTX_ERROR;
+#endif
+}
+
+/* Free a block of target memory. */
+
+int
+wtxapi_mem_free (pd_id_t pd_id, wtxapi_tgt_addr_t address)
+{
+#if WTX_PROT_VERSION != 2
+ return wtx_mem_free (current_wtx_handle, pd_id, address) != WTX_ERROR;
+#else
+ return wtx_mem_free (current_wtx_handle, address) != WTX_ERROR;
+#endif
+}
+
+/* Read memory from the target. */
+
+int
+wtxapi_mem_read (pd_id_t pd_id, wtxapi_tgt_addr_t from_addr,
+ void *to_addr, int num_bytes)
+{
+#if WTX_PROT_VERSION != 2
+ return wtx_mem_read (current_wtx_handle, pd_id, from_addr, to_addr,
+ num_bytes, 0);
+#else
+ return wtx_mem_read (current_wtx_handle, from_addr, to_addr, num_bytes);
+#endif
+}
+
+/* Read memory on WIDTH bytes. */
+
+int
+wtxapi_mem_width_read (pd_id_t pd_id, wtxapi_tgt_addr_t from_addr,
+ void *to_addr, int num_bytes, int width)
+{
+#if WTX_PROT_VERSION != 2
+ return wtx_mem_width_read (current_wtx_handle, pd_id, from_addr, to_addr,
+ num_bytes, width, 0);
+#else
+ return wtx_mem_width_read (current_wtx_handle, from_addr, to_addr, num_bytes,
+ width);
+#endif
+}
+
+/* Write memory on the target. */
+
+int
+wtxapi_mem_write (pd_id_t pd_id, void *from_addr,
+ wtxapi_tgt_addr_t to_addr, int num_bytes)
+{
+#if WTX_PROT_VERSION != 2
+ return wtx_mem_write (current_wtx_handle, pd_id, from_addr, to_addr,
+ num_bytes, 0);
+#else
+ return wtx_mem_write (current_wtx_handle, from_addr, to_addr, num_bytes);
+#endif
+}
+
+/* Write memory on the target on WIDTH bytes large. */
+
+int
+wtxapi_mem_width_write (pd_id_t pd_id, void *from_addr,
+ wtxapi_tgt_addr_t to_addr, int num_bytes, int width)
+{
+#if WTX_PROT_VERSION != 2
+ return wtx_mem_width_write (current_wtx_handle, pd_id, from_addr, to_addr,
+ num_bytes, width, 0);
+#else
+ return wtx_mem_width_write (current_wtx_handle, from_addr, to_addr,
+ num_bytes, width);
+#endif
+}
+
+/* Set target memory to given value. */
+
+int
+wtxapi_mem_set (pd_id_t pd_id, wtxapi_tgt_addr_t addr, int num_bytes, int val)
+{
+#if WTX_PROT_VERSION != 2
+ return wtx_mem_set (current_wtx_handle, pd_id, addr, num_bytes, val);
+#else
+ return wtx_mem_set (current_wtx_handle, addr, num_bytes, val);
+#endif
+}
+
+/* Add memory to the agent pool. */
+
+int
+wtxapi_mem_add_to_pool (pd_id_t pd_id, wtxapi_tgt_addr_t address, int size)
+{
+#if WTX_PROT_VERSION != 2
+ return wtx_mem_add_to_pool (current_wtx_handle, pd_id, address,
+ size) != WTX_ERROR;
+#else
+ return wtx_mem_add_to_pool (current_wtx_handle, address, size) != WTX_ERROR;
+#endif
+}
+
+/* Reallocate a block of target mem. */
+
+wtxapi_tgt_addr_t
+wtxapi_mem_realloc (pd_id_t pd_id, wtxapi_tgt_addr_t address, int num_bytes)
+{
+#if WTX_PROT_VERSION != 2
+ return wtx_mem_realloc (current_wtx_handle, pd_id, address, num_bytes);
+#else
+ return wtx_mem_realloc (current_wtx_handle, address, num_bytes);
+#endif
+}
+
+/* Allocate aligned target memory. */
+
+wtxapi_tgt_addr_t
+wtxapi_mem_align (pd_id_t pd_id, wtxapi_tgt_addr_t alignment, int num_bytes)
+{
+#if WTX_PROT_VERSION != 2
+ return wtx_mem_align (current_wtx_handle, pd_id, alignment, num_bytes);
+#else
+ return wtx_mem_align (current_wtx_handle, alignment, num_bytes);
+#endif
+}
+
+/* Scan target memory for pattern. */
+
+int
+wtxapi_mem_scan (pd_id_t pd_id, int match, wtxapi_tgt_addr_t start_addr,
+ wtxapi_tgt_addr_t end_addr, int num_bytes, void *pattern,
+ wtxapi_tgt_addr_t * p_result)
+{
+#if WTX_PROT_VERSION != 2
+ return wtx_mem_scan (current_wtx_handle, pd_id, TO_BOOL (match), start_addr,
+ end_addr, num_bytes, pattern, p_result) != WTX_ERROR;
+#else
+ return wtx_mem_scan (current_wtx_handle, TO_BOOL (match), start_addr,
+ end_addr, num_bytes, pattern, p_result) != WTX_ERROR;
+#endif
+}
+
+/* Checks validity of target memory. */
+
+int
+wtxapi_obj_module_checksum (pd_id_t pd_id, module_id_t module_id,
+ char *module_name)
+{
+#if WTX_PROT_VERSION != 2
+ return wtx_obj_module_checksum (current_wtx_handle, pd_id, module_id,
+ module_name) != WTX_ERROR;
+#else
+ return wtx_obj_module_checksum (current_wtx_handle, module_id,
+ module_name) != WTX_ERROR;
+#endif
+}
+
+/* Find obj module ID from name. */
+
+module_id_t
+wtxapi_obj_module_find_id (pd_id_t pd_id, const char *module_name)
+{
+ module_id_t module_id;
+#if WTX_PROT_VERSION != 2
+ module_id = wtx_obj_module_find_id (current_wtx_handle, pd_id, module_name);
+#else
+ module_id = wtx_obj_module_find_id (current_wtx_handle, module_name);
+#endif
+ return module_id;
+}
+
+module_id_t
+wtxapi_obj_module_in_system_find_id (const char *module_name)
+{
+#if WTX_PROT_VERSION != 2
+ const pd_id_t current_pd = wtxapi_pd_current_get (current_wtx_handle);
+ module_id_t module_id;
+
+ module_id = wtx_obj_module_find_id (current_wtx_handle, current_pd, module_name);
+ if (module_id != WTX_ERROR)
+ return module_id;
+
+ return wtx_obj_module_find_id (current_wtx_handle, WTX_PD_ALL, module_name);
+#else
+ return wtx_obj_module_find_id (current_wtx_handle, module_name);
+#endif
+}
+
+/* Find module name given its ID. */
+
+const char *
+wtxapi_obj_module_find_name (pd_id_t pd_id, module_id_t module_id)
+{
+#if WTX_PROT_VERSION != 2
+ return wtx_obj_module_find_name (current_wtx_handle, pd_id, module_id);
+#else
+ return wtx_obj_module_find_name (current_wtx_handle, module_id);
+#endif
+}
+
+/* Allocate a new wtxapi_module_info. */
+
+static struct wtxapi_module_info *
+new_wtxapi_module_info (WTX_MODULE_INFO *wtx_minfo)
+{
+ int i;
+ struct wtxapi_module_info *module_info;
+
+ if (!wtx_minfo)
+ return NULL;
+
+ module_info = (struct wtxapi_module_info *)
+ xzalloc (sizeof (struct wtxapi_module_info));
+#if WTX_PROT_VERSION != 2
+ module_info->pd_id = wtx_minfo->pdId;
+ module_info->section_addrs = alloc_section_addr_info (wtx_minfo->nSections);
+ for (i = 0; i < wtx_minfo->nSections; i++)
+ {
+ struct other_sections *other = module_info->section_addrs->other + i;
+
+ other->name = xstrdup (wtx_minfo->section[i].name);
+ other->addr = wtx_minfo->section[i].baseAddr;
+ /* brobecker/2007-05-14: The sectindex should really be set to
+ the same index as the BFD section index. But accessing the BFD
+ data at this point is not easy, so I am making a bet instead
+ that the BFD index is the same as the WTX section index. If
+ this assertion turns out to be false, then we'll have to add
+ some fixup code in remote-wtx.c that recomputes all section
+ indexes from BFD. */
+ other->sectindex = i;
+ }
+ module_info->segments = NULL;
+#else
+ /* On Tornado 2, the system does not give us access to the section
+ addresses, but 3 segment base addresses instead, from which we
+ need to compute the actual section addresses. Ideally, it would
+ have been nice to compute these addresses at this point, to make
+ the behavior of this function independent of the Tornado version,
+ but the implementation is too awkward (one of the problems we
+ are facing is trying to locate the object file on the host file
+ system, which is something we already do, but sometime later in
+ another part of the code, and using the result from this function).
+ So we just return the segment addresses for now, and let the client
+ deal with the conversion at a more appropriate moment. */
+ gdb_assert (wtx_minfo->nSegments == 3);
+
+ module_info->pd_id = NULL_PD;
+ module_info->section_addrs = NULL;
+ module_info->segments =
+ (struct segment_addresses *) xmalloc (sizeof (struct segment_addresses));
+ module_info->segments->text_addr = wtx_minfo->segment[0].addr;
+ module_info->segments->data_addr = wtx_minfo->segment[1].addr;
+ module_info->segments->bss_addr = wtx_minfo->segment[2].addr;
+#endif
+ module_info->module_id = wtx_minfo->moduleId;
+ if (wtx_minfo->moduleName)
+ module_info->module_name = xstrdup (wtx_minfo->moduleName);
+ module_info->load_flag = wtx_minfo->loadFlag;
+ module_info->undef_list = NULL;
+ return module_info;
+}
+
+/* Give info on obj module. */
+
+struct wtxapi_module_info *
+wtxapi_obj_module_info_get (pd_id_t pd_id, module_id_t module_id)
+{
+ struct wtxapi_module_info *module_info;
+ WTX_MODULE_INFO *wtx_minfo;
+#if WTX_PROT_VERSION != 2
+ wtx_minfo = wtx_obj_module_info_get (current_wtx_handle, pd_id, module_id);
+#else
+ wtx_minfo = wtx_obj_module_info_get (current_wtx_handle, module_id);
+#endif
+ if (!wtx_minfo)
+ return NULL;
+
+ module_info = new_wtxapi_module_info (wtx_minfo);
+ wtx_result_free (current_wtx_handle, wtx_minfo);
+ return module_info;
+}
+
+/* List loaded obj modules. */
+
+struct wtxapi_module_list *
+wtxapi_obj_module_list_get (pd_id_t pd_id)
+{
+ WTX_MODULE_LIST *wtx_mlist;
+ struct wtxapi_module_list *list;
+ int ix = 0;
+#if WTX_PROT_VERSION != 2
+ WTX_MOD_FIND_CRITERIA criteria;
+ WTX_MODULE *current;
+
+ memset (&criteria, 0, sizeof (criteria));
+ criteria.options = WTX_MOD_FIND_ALL;
+ criteria.pdId = pd_id;
+ criteria.moduleId = 0;
+ criteria.moduleName = NULL;
+ criteria.ref = 0;
+
+ wtx_mlist = wtx_obj_module_list_get (current_wtx_handle, &criteria);
+
+ if (!wtx_mlist)
+ return NULL;
+
+ list = (struct wtxapi_module_list *)
+ xmalloc (sizeof (struct wtxapi_module_list));
+
+ /* Note: as the module list is expected to have, say, less than 10
+ elements, the full copy should not take much time. */
+
+ list->num_obj_mod = 0;
+ for (current = wtx_mlist->pModule; current; current = current->next)
+ list->num_obj_mod++;
+
+ list->mod_id_array = (int *) xmalloc (list->num_obj_mod * sizeof (int));
+ list->pd_id_array = (pd_id_t *)
+ xmalloc (list->num_obj_mod * sizeof (pd_id_t));
+ for (current = wtx_mlist->pModule; current; current = current->next)
+ {
+ list->mod_id_array[ix] = current->moduleId;
+ list->pd_id_array[ix] = current->pdId;
+ ix++;
+ }
+
+#else
+ wtx_mlist = wtx_obj_module_list (current_wtx_handle);
+
+ if (!wtx_mlist)
+ return NULL;
+
+ list = (struct wtxapi_module_list *)
+ xmalloc (sizeof (struct wtxapi_module_list));
+ list->num_obj_mod = wtx_mlist->numObjMod;
+ list->mod_id_array = (int *) xmalloc (list->num_obj_mod * sizeof (int));
+ list->pd_id_array = (pd_id_t *)
+ xmalloc (list->num_obj_mod * sizeof (pd_id_t));
+ for (ix = 0; ix < list->num_obj_mod; ix++)
+ list->mod_id_array[ix] = wtx_mlist->modIdList[ix];
+ memset (list->pd_id_array, 0, list->num_obj_mod * sizeof (pd_id_t));
+#endif
+ wtx_result_free (current_wtx_handle, wtx_mlist);
+ return list;
+}
+
+/* Load a new object module. */
+
+struct wtxapi_module_info *
+wtxapi_obj_module_load (pd_id_t pd_id, char *filename, int load_flags)
+{
+ struct wtxapi_module_info *minfo;
+ wtx_module_info * wtx_minfo;
+
+#if WTX_PROT_VERSION != 2
+ WTX_MODULE_FILE_DESC wtx_fdesc;
+
+ memset (&wtx_fdesc, 0, sizeof (wtx_fdesc));
+ wtx_fdesc.filename = filename;
+ wtx_fdesc.loadFlag = load_flags;
+
+ wtx_minfo = wtx_obj_module_load (current_wtx_handle, pd_id, &wtx_fdesc,
+ WTX_LOAD_FROM_TOOL);
+
+ if (!wtx_minfo)
+ return NULL;
+
+ minfo = new_wtxapi_module_info (wtx_minfo);
+ minfo->undef_list =
+ new_wtxapi_symbol_list_from_symbol (wtx_minfo->undefSymList.pSymbol);
+ if (minfo->undef_list)
+ minfo->undef_list->wtx_result_to_cleanup = (void *) wtx_minfo;
+#else
+ WTX_LD_M_FILE_DESC wtx_fdesc;
+
+ memset (&wtx_fdesc, 0, sizeof (wtx_fdesc));
+ wtx_fdesc.filename = filename;
+ wtx_fdesc.loadFlag = load_flags;
+
+ wtx_minfo = wtx_obj_module_load (current_wtx_handle, &wtx_fdesc);
+
+ if (!wtx_minfo)
+ return NULL;
+ minfo = wtxapi_obj_module_info_get (wtxapi_pd_current_get (),
+ wtx_minfo->moduleId);
+ if (minfo->undef_list)
+ minfo->undef_list->wtx_result_to_cleanup = (void *) wtx_minfo;
+#endif
+ return minfo;
+}
+
+/* The same as wtxapi_obj_module_load except that it temporary changes
+ the WTX timeout value to the given TIMEOUT.
+
+ Basically, this function changes the WTX timeout to TIMEOUT,
+ calls wtxapi_obj_module_load, and then restores the old timeout. */
+
+struct wtxapi_module_info *
+wtxapi_module_load (pd_id_t pd_id, char *filename, int load_flag, int timeout)
+{
+ int saved_timeout;
+ struct wtxapi_module_info *module_info;
+
+ wtxapi_timeout_get (&saved_timeout);
+ wtxapi_timeout_set (timeout);
+ module_info = wtxapi_obj_module_load (pd_id, filename, load_flag);
+ wtxapi_timeout_set (saved_timeout);
+
+ return module_info;
+}
+
+/* Unload an obj module from target. */
+
+int
+wtxapi_obj_module_unload (pd_id_t pd_id, module_id_t mod_id)
+{
+#if WTX_PROT_VERSION != 2
+ return wtx_obj_module_unload (current_wtx_handle, pd_id, 0,
+ mod_id) != WTX_ERROR;
+#else
+ return wtx_obj_module_unload (current_wtx_handle, mod_id) != WTX_ERROR;
+#endif
+}
+
+/* Unload an obj. module from target. */
+
+int
+wtxapi_obj_module_by_name_unload (pd_id_t pd_id, char *name)
+{
+#if WTX_PROT_VERSION != 2
+ return wtx_obj_module_by_name_unload (current_wtx_handle, pd_id, 0,
+ name) != WTX_ERROR;
+#else
+ return wtx_obj_module_by_name_unload (current_wtx_handle, name) != WTX_ERROR;
+#endif
+}
+
+/* Send events matching expression. */
+
+int
+wtxapi_register_for_event (const char *reg_exp)
+{
+ return wtx_register_for_event (current_wtx_handle, reg_exp) != WTX_ERROR;
+}
+
+/* Read register data from the target. */
+
+int
+wtxapi_regs_get (WTX_CONTEXT_TYPE context_type,
+ WTX_CONTEXT_ID_T context_id, WTX_REG_SET_TYPE reg_set,
+ int first_byte, int num_bytes, void *reg_memory)
+{
+ WTX_CONTEXT context;
+ initialize_context (&context, context_type, context_id);
+ return wtx_regs_get (current_wtx_handle,
+ MARSHALL_WTX_CONTEXT_PARAM (context), reg_set,
+ first_byte, num_bytes, reg_memory) != WTX_ERROR;
+}
+
+/* Write to registers on the target. */
+
+int
+wtxapi_regs_set (WTX_CONTEXT_TYPE context_type, WTX_CONTEXT_ID_T context_id,
+ WTX_REG_SET_TYPE reg_set, int first_byte, int num_bytes,
+ void *reg_memory)
+{
+ WTX_CONTEXT context;
+ initialize_context (&context, context_type, context_id);
+ return wtx_regs_set (current_wtx_handle,
+ MARSHALL_WTX_CONTEXT_PARAM (context), reg_set,
+ first_byte, num_bytes, reg_memory) != WTX_ERROR;
+}
+
+/* Convert str to a wtxapi_tgt_addr_t. */
+
+wtxapi_tgt_addr_t
+wtxapi_str_to_tgt_addr (const char *str)
+{
+ return wtx_str_to_tgt_addr (current_wtx_handle, str);
+}
+
+/* Convert str to context ID. */
+
+WTX_CONTEXT_ID_T
+wtxapi_str_to_context_id (const char *str)
+{
+ return wtx_str_to_context_id (current_wtx_handle, str);
+}
+
+/* Convert str ton context type. */
+
+WTX_CONTEXT_TYPE
+wtxapi_str_to_context_type (const char *str)
+{
+ return wtx_str_to_context_type (current_wtx_handle, str);
+}
+
+/* Convert str to an int. */
+
+int
+wtxapi_str_to_int32 (const char *str)
+{
+ return wtx_str_to_int32 (current_wtx_handle, str);
+}
+
+/* Convert string to event type. */
+
+WTX_EVENT_TYPE
+wtxapi_str_to_event_type (const char *str)
+{
+ return wtx_str_to_event_type (current_wtx_handle, str);
+}
+
+/* Add symbol with given params. */
+
+int
+wtxapi_sym_add (pd_id_t pd_id, const char *sym_name,
+ wtxapi_tgt_addr_t sym_value, int sym_type)
+{
+#if WTX_PROT_VERSION != 2
+ return wtx_sym_add (current_wtx_handle, pd_id, sym_name, sym_value,
+ sym_type) != WTX_ERROR;
+#else
+ return wtx_sym_add (current_wtx_handle, sym_name, sym_value,
+ (UINT8) sym_type) != WTX_ERROR;
+#endif
+}
+
+static struct wtxapi_symbol_list *
+new_wtxapi_symbol_list (WTX_SYM_LIST *wtx_sym)
+{
+ struct wtxapi_symbol_list *sym_list;
+
+ if (!wtx_sym)
+ return NULL;
+
+ sym_list = (struct wtxapi_symbol_list *)
+ xmalloc (sizeof (struct wtxapi_symbol_list));
+ sym_list->wtx_result_to_cleanup = (void *) wtx_sym;
+ sym_list->first = wtx_sym->pSymbol;
+ sym_list->current = sym_list->first;
+ return sym_list;
+}
+
+static struct wtxapi_symbol_list *
+new_wtxapi_symbol_list_from_symbol (WTX_SYMBOL *wtx_sym)
+{
+ struct wtxapi_symbol_list *sym_list;
+
+ if (!wtx_sym)
+ return NULL;
+
+ sym_list = (struct wtxapi_symbol_list *)
+ xmalloc (sizeof (struct wtxapi_symbol_list));
+ sym_list->wtx_result_to_cleanup = (void *) wtx_sym;
+ sym_list->first = wtx_sym;
+ sym_list->current = wtx_sym;
+ return sym_list;
+}
+
+/* Find info on symbol. Based on wtxSymFind WTX 2.0, with two differences:
+ _ one additional parameter: the protection domain ID (PD_ID);
+ _ no filter on the type. */
+
+struct wtxapi_symbol_list *
+wtxapi_sym_find (pd_id_t pd_id, char *sym_name,
+ wtxapi_tgt_addr_t sym_value, int exact_name)
+{
+#if WTX_PROT_VERSION != 2
+ WTX_SYM_FIND_CRITERIA criteria;
+ memset (&criteria, 0, sizeof (criteria));
+ criteria.pdId = pd_id;
+ criteria.type = 0;
+ criteria.nSymbols = 1;
+ criteria.ref = 0;
+ criteria.moduleId = 0;
+ criteria.moduleName = NULL;
+
+ if (sym_name)
+ {
+ criteria.findName = sym_name;
+ criteria.findValue = 0;
+ criteria.options |= WTX_SYM_FIND_BY_NAME;
+
+ if (exact_name)
+ criteria.options |= WTX_SYM_FIND_BY_EXACT_NAME;
+ }
+ else
+ {
+ criteria.findName = NULL;
+ criteria.findValue = sym_value;
+ criteria.options |= WTX_SYM_FIND_BY_VALUE;
+
+ if (exact_name)
+ criteria.options |= WTX_SYM_FIND_BY_EXACT_VALUE;
+ }
+
+ return new_wtxapi_symbol_list_from_symbol (wtx_sym_find (current_wtx_handle,
+ &criteria));
+#else
+ return new_wtxapi_symbol_list_from_symbol (wtx_sym_find (current_wtx_handle,
+ sym_name,
+ sym_value,
+ exact_name, 0, 0));
+#endif
+}
+
+/* Get list of symbols. Based on wtxSymListGet WTX 2.0, with three differences:
+ - one additional parameter: the protection domain ID (PD_ID);
+ - no filter on the unknown symbols;
+ - no filter on the module name/id. */
+
+struct wtxapi_symbol_list *
+wtxapi_sym_list_get (pd_id_t pd_id, char *substring, wtxapi_tgt_addr_t value)
+{
+ struct wtxapi_symbol_list *sym_list;
+ WTX_SYM_LIST *wtx_sym_list;
+#if WTX_PROT_VERSION != 2
+ WTX_SYM_FIND_CRITERIA criteria;
+ memset (&criteria, 0, sizeof (criteria));
+ criteria.pdId = pd_id;
+ criteria.type = 0;
+ criteria.nSymbols = 0;
+ criteria.ref = 0;
+ criteria.moduleId = 0;
+ criteria.moduleName = NULL;
+
+ if (substring)
+ {
+ criteria.findName = substring;
+ criteria.findValue = 0;
+ criteria.options |= WTX_SYM_FIND_BY_NAME;
+ }
+ else
+ {
+ criteria.findName = NULL;
+ criteria.findValue = value;
+ criteria.options |= WTX_SYM_FIND_BY_VALUE;
+ }
+
+ wtx_sym_list = wtx_sym_list_get (current_wtx_handle, &criteria);
+#else
+ wtx_sym_list =
+ wtx_sym_list_get (current_wtx_handle, substring, NULL, value, FALSE);
+#endif
+ sym_list = new_wtxapi_symbol_list (wtx_sym_list);
+ return sym_list;
+}
+
+/* Get list of symbols. */
+
+struct wtxapi_symbol_list *
+wtxapi_sym_list_by_module_id_get (pd_id_t pd_id, const char *string,
+ module_id_t module_id,
+ wtxapi_tgt_addr_t value,
+ int list_unknown)
+{
+#if WTX_PROT_VERSION != 2
+ return new_wtxapi_symbol_list
+ (wtx_sym_list_by_module_id_get (current_wtx_handle, pd_id, string,
+ module_id, value, TO_BOOL (list_unknown)));
+#else
+ return new_wtxapi_symbol_list
+ (wtx_sym_list_by_module_id_get (current_wtx_handle, string, module_id,
+ value, TO_BOOL (list_unknown)));
+#endif
+}
+
+/* Get list of symbols. */
+
+struct wtxapi_symbol_list *
+wtxapi_sym_list_by_module_name_get (pd_id_t pd_id, const char *string,
+ const char *module_name,
+ wtxapi_tgt_addr_t value,
+ int list_unknown)
+{
+#if WTX_PROT_VERSION != 2
+ return new_wtxapi_symbol_list
+ (wtx_sym_list_by_module_name_get (current_wtx_handle, pd_id, string,
+ module_name, value,
+ TO_BOOL (list_unknown)));
+#else
+ return new_wtxapi_symbol_list
+ (wtx_sym_list_by_module_name_get (current_wtx_handle, string,
+ module_name, value,
+ TO_BOOL (list_unknown)));
+#endif
+}
+
+/* Remove a symbol from sym table. */
+
+int
+wtxapi_sym_remove (pd_id_t pd_id, const char *sym_name, int sym_type)
+{
+#if WTX_PROT_VERSION != 2
+ return wtx_sym_remove (current_wtx_handle, pd_id, sym_name,
+ sym_type) != WTX_ERROR;
+#else
+ return wtx_sym_remove (current_wtx_handle, sym_name, sym_type) != WTX_ERROR;
+#endif
+}
+
+/* Return sym table info. */
+
+struct wtxapi_sym_tbl_info *
+wtxapi_sym_tbl_info_get (pd_id_t pd_id)
+{
+ WTX_SYM_TBL_INFO *wtx_tbl_info;
+ struct wtxapi_sym_tbl_info *tbl_info;
+ pd_id_t current_pd_id;
+#if WTX_PROT_VERSION != 2
+ wtx_tbl_info = wtx_sym_tbl_info_get (current_wtx_handle, pd_id);
+ current_pd_id = wtx_tbl_info->pdId;
+#else
+ wtx_tbl_info = wtx_sym_tbl_info_get (current_wtx_handle);
+ current_pd_id = NULL_PD;
+#endif
+
+ if (!wtx_tbl_info)
+ return NULL;
+
+ tbl_info = (struct wtxapi_sym_tbl_info *)
+ xmalloc (sizeof (struct wtxapi_sym_tbl_info));
+ tbl_info->pd_id = current_pd_id;
+ tbl_info->sym_num = wtx_tbl_info->symNum;
+ tbl_info->same_name_ok = (wtx_tbl_info->sameNameOk == TRUE);
+ wtx_result_free (current_wtx_handle, wtx_tbl_info);
+ return tbl_info;
+}
+
+/* Reset the target. */
+
+int
+wtxapi_target_reset ()
+{
+ return wtx_target_reset (current_wtx_handle) != WTX_ERROR;
+}
+
+/* Get target server name. */
+
+const char *
+wtxapi_ts_name_get ()
+{
+ return wtx_ts_name_get (current_wtx_handle);
+}
+
+/* Get the target CPU type code. */
+
+int
+wtxapi_target_cpu_type_get ()
+{
+ return wtx_target_cpu_type_get (current_wtx_handle);
+}
+
+/* Check for floating point processor. */
+
+int
+wtxapi_target_has_fpp_get ()
+{
+ return wtx_target_has_fpp_get (current_wtx_handle);
+}
+
+/* Get edianness of target. */
+
+WTX_ENDIAN_T
+wtxapi_target_endian_get ()
+{
+ return wtx_target_endian_get (current_wtx_handle);
+}
+
+/* Get target boot line info (or NULL on error).
+
+ The string returned is a pointer to temporary memory, and should
+ be duplicated if it is to be stored. */
+
+const char *
+wtxapi_target_bootline_get ()
+{
+ return wtx_target_bootline_get (current_wtx_handle);
+}
+
+/* Return name of current tool. */
+
+const char *
+wtxapi_tool_name_get ()
+{
+ return wtx_tool_name_get (current_wtx_handle);
+}
+
+/* Return the Tornado version. */
+
+const char *
+wtxapi_ts_version_get ()
+{
+ return wtx_ts_version_get (current_wtx_handle);
+}
+
+/* Return the version of WTX. */
+int
+wtxapi_version_get ()
+{
+ return WTX_PROT_VERSION;
+}
+
+/* Unregister for some events. */
+
+int
+wtxapi_unregister_for_event (char *reg_exp)
+{
+ return wtx_unregister_for_event (current_wtx_handle, reg_exp) != WTX_ERROR;
+}
+
+/* Call func on target within agent. */
+
+int
+wtxapi_direct_call (wtxapi_tgt_addr_t entry, void *p_ret_val,
+ wtxapi_tgt_arg_t arg0, wtxapi_tgt_arg_t arg1,
+ wtxapi_tgt_arg_t arg2, wtxapi_tgt_arg_t arg3,
+ wtxapi_tgt_arg_t arg4, wtxapi_tgt_arg_t arg5,
+ wtxapi_tgt_arg_t arg6, wtxapi_tgt_arg_t arg7,
+ wtxapi_tgt_arg_t arg8, wtxapi_tgt_arg_t arg9)
+{
+#if WTX_PROT_VERSION != 2
+ return wtx_direct_call (current_wtx_handle, entry, p_ret_val, 10, arg0, arg1,
+ arg2, arg3, arg4, arg5, arg6, arg7, arg8,
+ arg9) != WTX_ERROR;
+#else
+ return wtx_direct_call (current_wtx_handle, entry, p_ret_val, arg0, arg1,
+ arg2, arg3, arg4, arg5, arg6, arg7, arg8,
+ arg9) != WTX_ERROR;
+#endif
+}
+
+/* Get info about target and server. */
+
+struct wtxapi_ts_info *
+wtxapi_ts_info_get ()
+{
+ static const char vxworks_prefix[] = "VxWorks";
+ WTX_TS_INFO *wtx_tsinfo = wtx_ts_info_get (current_wtx_handle);
+ struct wtxapi_ts_info *ts_info;
+ char *version;
+ if (!wtx_tsinfo)
+ return NULL;
+
+ ts_info = (struct wtxapi_ts_info *)
+ xmalloc (sizeof (struct wtxapi_ts_info));
+ memset (ts_info, 0, sizeof (struct wtxapi_ts_info));
+ ts_info->tgt_link_desc = wtx_tsinfo->tgtLinkDesc;
+
+#if WTX_PROT_VERSION != 2
+ if (wtx_tsinfo->tgtInfo.rtInfo.rtName)
+ ts_info->tgt_info.rt_info.rt_name =
+ xstrdup (wtx_tsinfo->tgtInfo.rtInfo.rtName);
+ if (wtx_tsinfo->tgtInfo.rtInfo.rtVersion)
+ ts_info->tgt_info.rt_info.rt_version =
+ xstrdup (wtx_tsinfo->tgtInfo.rtInfo.rtVersion);
+#else
+ /* On VxWorks 5, the runtime name is not included into the rt info;
+ instead, the version information is prefixed by "vxWorks".
+ Strip it the prefix, move it to rt_name. */
+ version = wtx_tsinfo->tgtInfo.rtInfo.rtVersion;
+ if (version)
+ {
+ if (strncmp (vxworks_prefix, version, strlen (vxworks_prefix)) == 0)
+ version += strlen (vxworks_prefix);
+ ts_info->tgt_info.rt_info.rt_version = xstrdup (version);
+ }
+ ts_info->tgt_info.rt_info.rt_name = xstrdup (vxworks_prefix);
+#endif
+ ts_info->tgt_info.rt_info.cpu_type =
+ wtx_tsinfo->tgtInfo.rtInfo.cpuType;
+
+#if WTX_PROT_VERSION > 3
+ if (wtx_tsinfo->tgtInfo.rtInfo.cpuVariant)
+ ts_info->tgt_info.rt_info.cpu_variant =
+ xstrdup (wtx_tsinfo->tgtInfo.rtInfo.cpuVariant);
+#endif
+
+ ts_info->tgt_info.rt_info.has_write_protect =
+ wtx_tsinfo->tgtInfo.rtInfo.hasWriteProtect;
+ ts_info->tgt_info.rt_info.page_size =
+ wtx_tsinfo->tgtInfo.rtInfo.pageSize;
+ ts_info->tgt_info.rt_info.endian =
+ wtx_tsinfo->tgtInfo.rtInfo.endian;
+ if (wtx_tsinfo->tgtInfo.rtInfo.bspName)
+ ts_info->tgt_info.rt_info.bsp_name =
+ xstrdup (wtx_tsinfo->tgtInfo.rtInfo.bspName);
+ if (wtx_tsinfo->tgtInfo.rtInfo.bootline)
+ ts_info->tgt_info.rt_info.boot_line =
+ xstrdup (wtx_tsinfo->tgtInfo.rtInfo.bootline);
+ ts_info->tgt_info.rt_info.mem_base =
+ wtx_tsinfo->tgtInfo.rtInfo.memBase;
+ ts_info->tgt_info.rt_info.mem_size =
+ wtx_tsinfo->tgtInfo.rtInfo.memSize;
+ ts_info->tgt_info.rt_info.num_regions =
+ wtx_tsinfo->tgtInfo.rtInfo.numRegions;
+ ts_info->tgt_info.rt_info.host_pool_base =
+ wtx_tsinfo->tgtInfo.rtInfo.hostPoolBase;
+ ts_info->tgt_info.rt_info.host_pool_size =
+ wtx_tsinfo->tgtInfo.rtInfo.hostPoolSize;
+ ts_info->tgt_info.agent_info.agent_version =
+ wtx_tsinfo->tgtInfo.agentInfo.agentVersion;
+ ts_info->tgt_info.agent_info.mtu =
+ wtx_tsinfo->tgtInfo.agentInfo.mtu;
+ ts_info->tgt_info.agent_info.mode =
+ wtx_tsinfo->tgtInfo.agentInfo.mode;
+
+ if (wtx_tsinfo->version)
+ ts_info->version = xstrdup (wtx_tsinfo->version);
+ if (wtx_tsinfo->userName)
+ ts_info->user_name = xstrdup (wtx_tsinfo->userName);
+ if (wtx_tsinfo->lockMsg)
+ ts_info->lock_msg = xstrdup (wtx_tsinfo->lockMsg);
+#if WTX_PROT_VERSION != 2
+ ts_info->pd_initialized = (wtx_tsinfo->pdInitialized == TRUE);
+#else
+ ts_info->pd_initialized = 1;
+#endif
+ return ts_info;
+}
+
+/* Reattach to the target. */
+
+int
+wtxapi_target_attach ()
+{
+ return wtx_target_attach (current_wtx_handle) != WTX_ERROR;
+}
+
+/* Probe to see if registry is running. */
+
+int
+wtxapi_probe ()
+{
+ return wtx_probe (current_wtx_handle) != WTX_ERROR;
+}
+
+/* Set WTX timeout. */
+
+int
+wtxapi_timeout_set (int msec)
+{
+ return wtx_timeout_set (current_wtx_handle, msec) != WTX_ERROR;
+}
+
+/* Get the current timeout. */
+
+int
+wtxapi_timeout_get (int *p_msec)
+{
+ UINT32 wtx_timeout;
+ int result = wtx_timeout_get (current_wtx_handle, &wtx_timeout) != WTX_ERROR;
+ *p_msec = wtx_timeout;
+ return result;
+}
+
+/* Create a new protection domain. */
+
+pd_id_t
+wtxapi_pd_create (const char *name, int options, int heap_size,
+ int low_priority, int high_priority,
+ wtxapi_tgt_addr_t page_pool_list, const char *link_path)
+{
+#if WTX_PROT_VERSION != 2
+ return wtx_pd_create (current_wtx_handle, name, options, heap_size,
+ low_priority, high_priority, page_pool_list,
+ link_path);
+#else
+ return NULL_PD;
+#endif
+}
+
+/* Get kernel Protection Domain ID. */
+
+pd_id_t
+wtxapi_pd_kernel_get ()
+{
+#if WTX_PROT_VERSION != 2
+ return wtx_pd_kernel_get (current_wtx_handle);
+#else
+ return NULL_PD;
+#endif
+}
+
+/* Get the current Protection Domain. */
+
+pd_id_t
+wtxapi_pd_current_get ()
+{
+#if WTX_PROT_VERSION != 2
+ return wtx_pd_current_get (current_wtx_handle);
+#else
+ return NULL_PD;
+#endif
+}
+
+/* Set the current Protection Domain. Return non-zero if the operation
+ was successful. Otherwise, sets the WTX error (to be retrieved using
+ wtx_err_get). */
+
+int
+wtxapi_pd_current_set (pd_id_t pd_id)
+{
+#if WTX_PROT_VERSION != 2
+ return wtx_pd_current_set (current_wtx_handle, pd_id) != WTX_ERROR;
+#else
+ return pd_id == NULL_PD;
+#endif
+}
+
+/* Get the list of allocated PDs. */
+
+/* NOTE: it performs a full copy of the PD description list. It should
+ not be a problem, we should not expect to many PDs. If there are
+ some speed issues, the solution would be to have the same kind of
+ model we use for wtxapi_symbol_list. To be investigated. */
+
+struct wtxapi_pd_desc_q *
+wtxapi_pd_info_q_get ()
+{
+ struct wtxapi_pd_desc_q *pd_desc_list;
+#if WTX_PROT_VERSION != 2
+ WTX_PD_DESC_Q *wtx_pd_desc_q = wtx_pd_info_q_get (current_wtx_handle);
+ WTX_PD_DESC_Q *current_wtx_desc = wtx_pd_desc_q;
+ struct wtxapi_pd_desc_q *current_desc;
+ int ix;
+
+ if (wtx_pd_desc_q == NULL)
+ return NULL;
+
+ pd_desc_list = (struct wtxapi_pd_desc_q *)
+ xmalloc (sizeof (struct wtxapi_pd_desc_q));
+ current_desc = pd_desc_list;
+
+ for (current_wtx_desc = wtx_pd_desc_q;
+ current_wtx_desc != NULL;
+ current_wtx_desc = current_wtx_desc->pNext)
+ {
+ current_desc->pd_desc.pd_id = current_wtx_desc->wtxPdDesc.pdId;
+ if (current_wtx_desc->wtxPdDesc.pdName)
+ current_desc->pd_desc.pd_name =
+ xstrdup (current_wtx_desc->wtxPdDesc.pdName);
+ current_desc->pd_desc.pd_flags = current_wtx_desc->wtxPdDesc.pdFlags;
+ if (current_wtx_desc->wtxPdDesc.pdLinkPathStr)
+ current_desc->pd_desc.pd_link_path_str =
+ xstrdup (current_wtx_desc->wtxPdDesc.pdLinkPathStr);
+ current_desc->pd_desc.pd_link_path_count =
+ current_wtx_desc->wtxPdDesc.pdLinkPathCount;
+ if (current_wtx_desc->wtxPdDesc.pdLinkPathCount)
+ {
+ current_desc->pd_desc.pd_link_path = (pd_id_t *)
+ xmalloc (current_wtx_desc->wtxPdDesc.pdLinkPathCount
+ * sizeof (pd_id_t));
+ for (ix = 0; ix < current_wtx_desc->wtxPdDesc.pdLinkPathCount; ix++)
+ current_desc->pd_desc.pd_link_path[ix]
+ = current_wtx_desc->wtxPdDesc.pdLinkPath[ix];
+
+ }
+ else
+ {
+ current_desc->pd_desc.pd_link_path = NULL;
+ }
+ if (current_wtx_desc->wtxPdDesc.pdAttachToCount)
+ {
+ current_desc->pd_desc.pd_attach_to_count =
+ current_wtx_desc->wtxPdDesc.pdAttachToCount;
+ current_desc->pd_desc.pd_attach_to = (pd_id_t *)
+ xmalloc (current_wtx_desc->wtxPdDesc.pdAttachToCount
+ * sizeof (pd_id_t));
+ for (ix = 0; ix < current_wtx_desc->wtxPdDesc.pdAttachToCount; ix++)
+ current_desc->pd_desc.pd_attach_to[ix]
+ = current_wtx_desc->wtxPdDesc.pdAttachTo[ix];
+ }
+ else
+ {
+ current_desc->pd_desc.pd_attach_to = NULL;
+ }
+
+ if (current_wtx_desc->pNext != NULL)
+ {
+ current_desc->next = (struct wtxapi_pd_desc_q *)
+ xmalloc (sizeof (struct wtxapi_pd_desc_q));
+ current_desc = current_desc->next;
+ }
+ else
+ current_desc->next = NULL;
+ }
+ wtx_result_free (current_wtx_handle, wtx_pd_desc_q);
+#else
+ pd_desc_list = (struct wtxapi_pd_desc_q *)
+ xmalloc (sizeof (struct wtxapi_pd_desc_q));
+ memset (&pd_desc_list, 0, sizeof (pd_desc_list));
+ pd_desc_list->pd_desc.pd_name = xstrdup ("kernel");
+ pd_desc_list->pd_desc.pd_link_path_str = xstrdup ("<none>");
+#endif
+ return pd_desc_list;
+}
+
+/* Return non-zero if the given module has been fully linked,
+ or, in other words, relocation has already been performed. */
+
+int
+wtxapi_load_fully_linked (const struct wtxapi_module_info *module_info)
+{
+ /* The WTX_LOAD_FULLY_LINKED macro has been introduced *after* Vxworks 5.x.
+ For Vxworks 5.x targets, we simply define it ourselves. */
+#ifndef WTX_LOAD_FULLY_LINKED
+#define WTX_LOAD_FULLY_LINKED 0x20
+#endif
+
+ return module_info->load_flag & WTX_LOAD_FULLY_LINKED;
+}
+
+/* Test target server availability. */
+
+int
+wtxapi_target_server_available_p ()
+{
+ WTX_TS_INFO *ts_info = wtx_ts_info_get (current_wtx_handle);
+ return ts_info != NULL;
+}
+
+
+/* Symbol list handling. */
+
+struct wtxapi_symbol *
+get_current_wtxapi_symbol (struct wtxapi_symbol_list *list)
+{
+ struct wtxapi_symbol *sym;
+ if (!list || !list->current)
+ return NULL;
+
+ sym = (struct wtxapi_symbol *) xmalloc (sizeof (struct wtxapi_symbol));
+ copy_current_wtxapi_symbol (list, sym, wtxapi_symbol_copy_full);
+ return sym;
+}
+
+void
+copy_current_wtxapi_symbol (struct wtxapi_symbol_list *list,
+ struct wtxapi_symbol *to, int options)
+{
+ if (!to || !list || !list->current)
+ return;
+
+ to->status = list->current->status;
+#if WTX_PROT_VERSION != 2
+ to->pd_id = list->current->pdId;
+#else
+ to->pd_id = NULL_PD;
+#endif
+ if (options != wtxapi_symbol_copy_dont_copy_name
+ && options != wtxapi_symbol_copy_dont_copy_strings
+ && list->current->name)
+ to->name = xstrdup (list->current->name);
+ else
+ to->name = NULL;
+
+ if (options != wtxapi_symbol_copy_dont_copy_module_name
+ && options != wtxapi_symbol_copy_dont_copy_strings
+ && list->current->moduleName)
+ to->module_name = xstrdup (list->current->moduleName);
+ else
+ to->module_name = NULL;
+
+ to->exact_name = (list->current->exactName == TRUE);
+ to->value = list->current->value;
+ to->type = list->current->type;
+ to->type_mask = list->current->typeMask;
+}
+
+char *
+current_wtxapi_symbol_name (struct wtxapi_symbol_list *list)
+{
+ return xstrdup (list->current->name);
+}
+
+int
+go_to_first_element_in_wtxapi_sym_list (struct wtxapi_symbol_list *list)
+{
+ if (!list || !list->first)
+ return 0;
+
+ list->current = list->first;
+ return 1;
+}
+
+int
+go_to_next_element_in_wtxapi_sym_list (struct wtxapi_symbol_list *list)
+{
+ if (!list->current || !list->current->next)
+ return 0;
+
+ list->current = list->current->next;
+ return 1;
+}
+
+/* Deallocation functions. */
+
+void
+free_wtxapi_evtpt_list (struct wtxapi_evtpt_list *to_free)
+{
+ int ix;
+ for (ix = 0; ix < to_free->n_evtpt; ix++)
+ {
+ xfree (to_free->p_evtpt_info[ix].wtx_evtpt.event.args);
+ }
+ xfree (to_free->p_evtpt_info);
+ xfree (to_free);
+}
+
+void
+free_wtxapi_module_list (struct wtxapi_module_list *to_free)
+{
+ xfree (to_free->mod_id_array);
+ xfree (to_free->pd_id_array);
+ xfree (to_free);
+}
+
+void
+free_wtxapi_pd_desc_q (struct wtxapi_pd_desc_q *to_free)
+{
+ struct wtxapi_pd_desc_q *current;
+ struct wtxapi_pd_desc_q *element_to_deallocate = NULL;
+
+ for (current = to_free; current != NULL; current = current->next)
+ {
+ if (element_to_deallocate)
+ xfree (element_to_deallocate);
+ if (current->pd_desc.pd_name)
+ xfree (current->pd_desc.pd_name);
+ if (current->pd_desc.pd_link_path_str)
+ xfree (current->pd_desc.pd_link_path_str);
+ if (current->pd_desc.pd_link_path)
+ xfree (current->pd_desc.pd_link_path);
+ if (current->pd_desc.pd_attach_to)
+ xfree (current->pd_desc.pd_attach_to);
+ element_to_deallocate = current;
+ }
+}
+
+void
+free_wtxapi_symbol (struct wtxapi_symbol *to_free)
+{
+ if (to_free->name)
+ xfree (to_free->name);
+
+ if (to_free->module_name)
+ xfree (to_free->module_name);
+
+ xfree (to_free);
+}
+
+void
+free_wtxapi_symbol_list (struct wtxapi_symbol_list *to_free)
+{
+ if (to_free->wtx_result_to_cleanup != NULL)
+ wtx_result_free (current_wtx_handle, to_free->wtx_result_to_cleanup);
+
+ xfree (to_free);
+}
+
+void
+free_wtxapi_module_info (struct wtxapi_module_info *to_free)
+{
+ xfree (to_free->module_name);
+ if (to_free->section_addrs != NULL)
+ free_section_addr_info (to_free->section_addrs);
+ if (to_free->segments != NULL)
+ xfree (to_free->segments);
+ if (to_free->undef_list)
+ free_wtxapi_symbol_list (to_free->undef_list);
+ xfree (to_free);
+}
+
+void
+free_wtxapi_ts_info (struct wtxapi_ts_info *to_free)
+{
+ if (to_free->tgt_info.rt_info.rt_name)
+ xfree (to_free->tgt_info.rt_info.rt_name);
+
+ if (to_free->tgt_info.rt_info.cpu_variant)
+ xfree (to_free->tgt_info.rt_info.cpu_variant);
+
+ if (to_free->tgt_info.rt_info.rt_version)
+ xfree (to_free->tgt_info.rt_info.rt_version);
+
+ if (to_free->tgt_info.rt_info.bsp_name)
+ xfree (to_free->tgt_info.rt_info.bsp_name);
+
+ if (to_free->tgt_info.rt_info.boot_line)
+ xfree (to_free->tgt_info.rt_info.boot_line);
+
+ if (to_free->version)
+ xfree (to_free->version);
+
+ if (to_free->user_name)
+ xfree (to_free->user_name);
+
+ if (to_free->lock_msg)
+ xfree (to_free->lock_msg);
+
+ xfree (to_free);
+}
+
+void
+free_wtxapi_event_desc (struct wtxapi_event_desc *to_free)
+{
+ switch (to_free->event_type)
+ {
+ case WTX_EVENT_OBJ_UNLOADED:
+ xfree (to_free->desc.obj_unloaded.module_filename);
+ break;
+ case WTX_EVENT_VIO_WRITE:
+ xfree (to_free->desc.vio_write.data);
+ break;
+ }
+
+ xfree (to_free);
+}
+
+
+/* cleanup functions. */
+
+void
+cleanup_wtxapi_evtpt_list (void *to_free)
+{
+ free_wtxapi_evtpt_list ((struct wtxapi_evtpt_list *) to_free);
+}
+
+void
+cleanup_wtxapi_module_list (void *to_free)
+{
+ free_wtxapi_module_list ((struct wtxapi_module_list *) to_free);
+}
+
+void
+cleanup_wtxapi_pd_desc_q (void *to_free)
+{
+ free_wtxapi_pd_desc_q ((struct wtxapi_pd_desc_q *) to_free);
+}
+
+void
+cleanup_wtxapi_symbol (void *to_free)
+{
+ free_wtxapi_symbol ((struct wtxapi_symbol *) to_free);
+}
+
+void
+cleanup_wtxapi_symbol_list (void *to_free)
+{
+ free_wtxapi_symbol_list ((struct wtxapi_symbol_list *) to_free);
+}
+
+void
+cleanup_wtxapi_module_info (void *to_free)
+{
+ free_wtxapi_module_info ((struct wtxapi_module_info *) to_free);
+}
+
+void
+cleanup_wtxapi_ts_info (void *to_free)
+{
+ free_wtxapi_ts_info ((struct wtxapi_ts_info *) to_free);
+}
+
+void
+cleanup_wtxapi_result_free (void *to_free)
+{
+ wtxapi_result_free (to_free);
+}
+
+
+/* Implements simple symbol lookup. */
+
+int
+remote_wtxapi_get_symbol_address (char *symbol_name, CORE_ADDR *symbol_addr)
+{
+ struct wtxapi_symbol_list *symbol_list;
+ struct wtxapi_symbol *symbol_info;
+
+ symbol_list = wtxapi_sym_find (wtxapi_pd_current_get (), symbol_name, 0, 1);
+ symbol_info = get_current_wtxapi_symbol (symbol_list);
+
+ if (symbol_info != NULL)
+ {
+ *symbol_addr = symbol_info->value;
+
+ free_wtxapi_symbol (symbol_info);
+ free_wtxapi_symbol_list (symbol_list);
+ return 0;
+ }
+ else
+ {
+ *symbol_addr = 0;
+ return -1;
+ }
+}
+
+/* Return non-zero if BoDA support (Breakpoint on Data Access) is available
+ on the system we're connected to. This routine assumes that we are
+ connected to the target server. */
+
+int
+wtxapi_target_has_BoDA (void)
+{
+ /* Will be set to 1 as soon as we've checked whether the system
+ we're running on provides BoDA or not. This is used to determine
+ whether BoDA_supported_p has been set yet, or not. */
+ static int BoDA_support_checked_p = 0;
+
+ /* Set to non-zero if BoDA is supported on the system. Set iff
+ BoDA_support_checked_p is non-zero.
+
+ We're checking the support for BoDA in a lazy fashion, because
+ it's a tiny bit expensive (need to do a symbol lookup), and because
+ we need to be connected to the system before we do so. We could
+ be doing that check after connecting with the target server, but
+ that would be useless during the sessions when watchpoints are
+ not actually used. So we wait until we need to have this info
+ before we actually do the check. */
+ static int BoDA_supported_p = 0;
+
+ if (!BoDA_support_checked_p)
+ {
+ /* BoDA is supported by the target iff the symbol wdbEventClassHwBpVa
+ is defined in the Core OS partition. Instead of trying to find
+ the PD ID of the Core OS partition, we just seach the symbol
+ in all partitions. It's unlikely that any other partition
+ would define a symbol using that name, so accept that risk. */
+ struct wtxapi_symbol_list *symbol_list;
+
+ symbol_list = wtxapi_sym_find (WTX_SYM_FIND_IN_ALL_PD,
+ "wdbEventClassHwBpVa", 0, 1);
+
+ if (symbol_list != NULL)
+ {
+ BoDA_supported_p = 1;
+ free_wtxapi_symbol_list (symbol_list);
+ }
+
+ BoDA_support_checked_p = 1;
+ }
+
+ return BoDA_supported_p;
+}
+
+/* Free the memory allocated by the given THREADS list. */
+
+void
+free_wtxapi_thread_info (struct wtxapi_thread_info *threads)
+{
+ struct wtxapi_thread_info *this = threads;
+ struct wtxapi_thread_info *next;
+
+ while (this != NULL)
+ {
+ next = this->next;
+ xfree (this->name);
+ xfree (this);
+ this = next;
+ }
+}
+
+/* Routines implemented using the support of external modules. */
+
+static struct wtxapi_support_ops *support_ops = NULL;
+
+/* Setup the current wtx_support_ops vector to OPS. */
+
+void
+wtxapi_set_support_ops (struct wtxapi_support_ops *ops)
+{
+ support_ops = ops;
+}
+
+/* Call the wtx_connection_established_callback method of
+ the support_ops vector. */
+
+void
+wtxapi_notify_connection_established (void)
+{
+ /* If the support_ops structure hasn't been set, then simply
+ do nothing. */
+ if (support_ops == NULL)
+ return;
+ gdb_assert (support_ops->wtx_connection_established_callback != NULL);
+
+ support_ops->wtx_connection_established_callback (current_wtx_handle);
+}
+
+/* Return the list of threads currently running on the target.
+
+ This routine is dependent on the support_ops vector being set,
+ or else NULL will be returned. */
+
+struct wtxapi_thread_info *
+wtxapi_get_thread_list (void)
+{
+ /* If the support_ops structure has not be set, then return NULL. */
+ if (support_ops == NULL)
+ return NULL;
+ gdb_assert (support_ops->get_thread_list != NULL);
+
+ return support_ops->get_thread_list ();
+}
+
+/* If TASK_ID is a valid task ID, then save its PD inside TASK_PD,
+ and return non-zero. In case of failure, return zero, and the value
+ of TASK_PD is undefined.
+
+ This function is dependent on the support_ops vector being set,
+ or else zero will be returned. */
+
+int
+wtxapi_get_task_pd (int task_id, pd_id_t *task_pd)
+{
+ /* If the support_ops structure has not be set, then return 0. */
+ if (support_ops == NULL)
+ return 0;
+ gdb_assert (support_ops->get_task_pd != NULL);
+
+ return support_ops->get_task_pd (task_id, task_pd);
+}
+
+/* Execute the system_mode_support_p method of the wtxapi_support_ops
+ vector.
+
+ This function is dependent on the support_ops vector being set,
+ or else zero will be returned. */
+
+int
+wtxapi_system_mode_support_p (void)
+{
+ if (support_ops == NULL)
+ return 0;
+ gdb_assert (support_ops->system_mode_support_p != NULL);
+
+ return support_ops->system_mode_support_p ();
+}
+
+/* Execute the system_mode_get_current_context_id method of the
+ wtxapi_support_ops vector.
+
+ This function is dependent on the support_ops vector being set,
+ or else the SYSTEM_CID will be returned. */
+
+WTX_CONTEXT_ID_T
+wtxapi_system_mode_get_current_context_id (void)
+{
+ /* If the support_ops structure has not be set, then return 0. */
+ if (support_ops == NULL)
+ return SYSTEM_CID;
+ gdb_assert (support_ops->system_mode_get_current_context_id != NULL);
+
+ return support_ops->system_mode_get_current_context_id ();
+}
+
+/* Return the value of VX_FP_TASK for the current target. The value of
+ this option depends on the VxWorks version. */
+
+int
+wtxapi_vx_fp_task ()
+{
+ struct wtxapi_ts_info *ts_info = wtxapi_ts_info_get ();
+ struct cleanup *old_cleanup = make_cleanup (cleanup_wtxapi_ts_info, ts_info);
+ char vx6_pattern[] = "6.";
+
+ if (strncmp (vx6_pattern, ts_info->tgt_info.rt_info.rt_version,
+ strlen (vx6_pattern)) == 0)
+ return 0x1000000;
+ else
+ return 0x8;
+ do_cleanups (old_cleanup);
+}
+
+/* Ask WTX which variant is the target CPU, and compare it against
+ VARIANT. If they match, return 1; otherwise, return 0. */
+
+int
+wtxapi_has_target_variant (const char *variant)
+{
+ int result;
+ struct wtxapi_ts_info *ts_info = wtxapi_ts_info_get ();
+ struct cleanup *old_cleanup = make_cleanup (cleanup_wtxapi_ts_info, ts_info);
+
+ if (ts_info->tgt_info.rt_info.cpu_variant
+ && strcmp (ts_info->tgt_info.rt_info.cpu_variant, variant) == 0)
+ result = 1;
+ else
+ result = 0;
+
+ do_cleanups (old_cleanup);
+ return result;
+}
+
+static struct cmd_list_element *info_wtx_list = NULL;
+
+/* If connected, return the targer server info; othewise, issue an error. */
+
+static struct wtxapi_ts_info *
+get_ts_info ()
+{
+ struct wtxapi_ts_info *ts_info;
+
+ if (current_wtx_handle == NULL
+ || !(ts_info = wtxapi_ts_info_get ()))
+ error (_("Not connected to a VxWorks target."));
+
+ return ts_info;
+}
+
+static void
+info_wtx_version_command (char *args, int from_tty)
+{
+ printf_filtered (_("WTX protocol version %d\n"), wtxapi_version_get ());
+}
+
+/* Print the version of VxWorks running on the target. */
+
+static void
+info_wtx_vxworks_version ()
+{
+ struct wtxapi_ts_info *ts_info = get_ts_info ();
+ struct cleanup *old_cleanup = make_cleanup (cleanup_wtxapi_ts_info, ts_info);
+ char *name;
+ char *version;
+
+ name = ts_info->tgt_info.rt_info.rt_name;
+ version = ts_info->tgt_info.rt_info.rt_version;
+ if (name && version)
+ printf_filtered (_("%s version %s\n"), name, version);
+ do_cleanups (old_cleanup);
+}
+
+static void
+info_wtx_threads_command (char *args, int from_tty)
+{
+ struct wtxapi_thread_info *threads = wtxapi_get_thread_list ();
+ struct wtxapi_thread_info *current_thread = threads;
+
+ if (threads == NULL)
+ {
+ printf_filtered (_("No threads.\n"));
+ return;
+ }
+
+ while (current_thread != NULL)
+ {
+ printf_filtered ("0x%lx\t%s\n", current_thread->id,
+ current_thread->name);
+ current_thread = current_thread->next;
+ }
+ free_wtxapi_thread_info (threads);
+}
+
+/* Helper function for info_wtx_threads_command. If INFO is not-null,
+ print it; otherwise, do nothing. */
+
+static void
+print_info (const char *label, char *info)
+{
+ if (info)
+ printf_filtered ("%s: %s\n", label, info);
+}
+
+/* Print target server information for the current WTX connection. */
+
+static void
+info_wtx_target_server (char *args, int from_tty)
+{
+ struct wtxapi_ts_info *ts_info = get_ts_info ();
+ struct cleanup *old_cleanup = make_cleanup (cleanup_wtxapi_ts_info, ts_info);
+
+ printf_filtered (_("\nTarget agent:\n"));
+ print_info (_("version"),
+ ts_info->tgt_info.agent_info.agent_version);
+ printf_filtered (_("max transfer size in bytes: %d\n"),
+ ts_info->tgt_info.agent_info.mtu);
+ printf_filtered (_("available agent modes: %d\n"),
+ ts_info->tgt_info.agent_info.mode);
+
+ printf_filtered (_("\nRuntime:\n"));
+ print_info (_("name"),
+ ts_info->tgt_info.rt_info.rt_name);
+ print_info (_("version"),
+ ts_info->tgt_info.rt_info.rt_version);
+ printf_filtered (_("target processor type: %d\n"),
+ ts_info->tgt_info.rt_info.cpu_type);
+ print_info (_("target cpu variant"),
+ ts_info->tgt_info.rt_info.cpu_variant);
+ printf_filtered (_("has write protect: %d\n"),
+ ts_info->tgt_info.rt_info.has_write_protect);
+ printf_filtered (_("page size: %d\n"),
+ ts_info->tgt_info.rt_info.page_size);
+ printf_filtered (_("endianness: %d\n"),
+ ts_info->tgt_info.rt_info.endian);
+ print_info (_("BSP"),
+ ts_info->tgt_info.rt_info.bsp_name);
+ print_info (_("boot file"),
+ ts_info->tgt_info.rt_info.boot_line);
+ printf_filtered (_("target main memory base address: %#x\n"),
+ (unsigned int) ts_info->tgt_info.rt_info.mem_base);
+ printf_filtered (_("target memory size: %d\n"),
+ ts_info->tgt_info.rt_info.mem_size);
+ printf_filtered (_("number of memory regions: %d\n"),
+ ts_info->tgt_info.rt_info.num_regions);
+ printf_filtered (_("target server memory pool base: %#x\n"),
+ (unsigned int) ts_info->tgt_info.rt_info.host_pool_base);
+ printf_filtered (_("target server memory pool size: %d\n"),
+ ts_info->tgt_info.rt_info.host_pool_size);
+ do_cleanups (old_cleanup);
+}
+
+static void
+info_wtx_command (char *args, int from_tty)
+{
+ /* brobecker/2007-12-17: Ideally, the "info wtx" command should
+ only be a prefix command. But we have been using it to get
+ the WTX protocol version for the past few years. So keep this
+ command as an alias of "info wtx version" for now. Eventually,
+ when all the GDB versions that didn't support "info wtx version"
+ are no longer supported, we can remove this compatibility hack. */
+ info_wtx_version_command (NULL, from_tty);
+}
+
+/* Load the WTX shared libraries and initialize the pointers to WTX
+ functions. */
+
+static void
+load_wtx_libraries ()
+{
+ void *wtx_lib = NULL;
+
+ if (WTX_PROT_VERSION == 4)
+ {
+ wtx_lib = load_shared_lib ("wtxapi41");
+
+ if (!wtx_lib)
+ wtx_lib = load_shared_lib ("wtxapi40");
+ }
+ else if (WTX_PROT_VERSION == 3)
+ {
+ wtx_lib = load_shared_lib ("wtxapi30");
+ }
+ else if (WTX_PROT_VERSION == 2)
+ {
+ wtx_lib = load_shared_lib ("wtxapi");
+ }
+
+ if (!wtx_lib)
+ error (_("WTX library not found."));
+
+#define resolve(sym, name) \
+ if (!(sym = get_symbol_from_shared_lib (wtx_lib, name))) \
+ error (_("cannot find symbol `%s' in WTX library"), name);
+
+ resolve (wtx_initialize, "wtxInitialize");
+ resolve (wtx_terminate, "wtxTerminate");
+ resolve (wtx_info_q, "wtxInfoQ");
+ resolve (wtx_tool_attach, "wtxToolAttach");
+ resolve (wtx_tool_connected, "wtxToolConnected");
+ resolve (wtx_tool_detach, "wtxToolDetach");
+ resolve (wtx_err_clear, "wtxErrClear");
+ resolve (wtx_err_get, "wtxErrGet");
+ resolve (wtx_err_handler_add, "wtxErrHandlerAdd");
+ resolve (wtx_err_handler_remove, "wtxErrHandlerRemove");
+ resolve (wtx_err_msg_get, "wtxErrMsgGet");
+ resolve (wtx_agent_mode_get, "wtxAgentModeGet");
+ resolve (wtx_agent_mode_set, "wtxAgentModeSet");
+ resolve (wtx_breakpoint_add, "wtxBreakpointAdd");
+ resolve (wtx_eventpoint_add, "wtxEventpointAdd");
+ resolve (wtx_eventpoint_delete, "wtxEventpointDelete");
+ resolve (wtx_event_get, "wtxEventGet");
+ resolve (wtx_context_status_get, "wtxContextStatusGet");
+ resolve (wtx_context_cont, "wtxContextCont");
+ resolve (wtx_context_create, "wtxContextCreate");
+ resolve (wtx_context_resume, "wtxContextResume");
+ resolve (wtx_context_exit_notify_add, "wtxContextExitNotifyAdd");
+ resolve (wtx_context_kill, "wtxContextKill");
+ resolve (wtx_context_step, "wtxContextStep");
+ resolve (wtx_context_suspend, "wtxContextSuspend");
+ resolve (wtx_eventpoint_list_get, "wtxEventpointListGet");
+ resolve (wtx_result_free, "wtxResultFree");
+ resolve (wtx_gopher_eval, "wtxGopherEval");
+ resolve (wtx_mem_info_get, "wtxMemInfoGet");
+ resolve (wtx_mem_alloc, "wtxMemAlloc");
+ resolve (wtx_mem_checksum, "wtxMemChecksum");
+ resolve (wtx_mem_move, "wtxMemMove");
+ resolve (wtx_mem_free, "wtxMemFree");
+ resolve (wtx_mem_read, "wtxMemRead");
+ resolve (wtx_mem_width_read, "wtxMemWidthRead");
+ resolve (wtx_mem_write, "wtxMemWrite");
+ resolve (wtx_mem_width_write, "wtxMemWidthWrite");
+ resolve (wtx_mem_set, "wtxMemSet");
+ resolve (wtx_mem_add_to_pool, "wtxMemAddToPool");
+ resolve (wtx_mem_realloc, "wtxMemRealloc");
+ resolve (wtx_mem_align, "wtxMemAlign");
+ resolve (wtx_mem_scan, "wtxMemScan");
+ resolve (wtx_obj_module_checksum, "wtxObjModuleChecksum");
+ resolve (wtx_obj_module_find_id, "wtxObjModuleFindId");
+ resolve (wtx_obj_module_find_name, "wtxObjModuleFindName");
+ resolve (wtx_obj_module_info_get, "wtxObjModuleInfoGet");
+ resolve (wtx_obj_module_load, "wtxObjModuleLoad");
+ resolve (wtx_obj_module_unload, "wtxObjModuleUnload");
+ resolve (wtx_obj_module_by_name_unload, "wtxObjModuleByNameUnload");
+ resolve (wtx_register_for_event, "wtxRegisterForEvent");
+ resolve (wtx_regs_get, "wtxRegsGet");
+ resolve (wtx_regs_set, "wtxRegsSet");
+ resolve (wtx_str_to_tgt_addr, "wtxStrToTgtAddr");
+ resolve (wtx_str_to_context_id, "wtxStrToContextId");
+ resolve (wtx_str_to_context_type, "wtxStrToContextType");
+ resolve (wtx_str_to_int32, "wtxStrToInt32");
+ resolve (wtx_str_to_event_type, "wtxStrToEventType");
+ resolve (wtx_sym_add, "wtxSymAdd");
+ resolve (wtx_sym_find, "wtxSymFind");
+ resolve (wtx_sym_list_get, "wtxSymListGet");
+ resolve (wtx_sym_list_by_module_id_get, "wtxSymListByModuleIdGet");
+ resolve (wtx_sym_list_by_module_name_get, "wtxSymListByModuleNameGet");
+ resolve (wtx_sym_remove, "wtxSymRemove");
+ resolve (wtx_sym_tbl_info_get, "wtxSymTblInfoGet");
+ resolve (wtx_target_reset, "wtxTargetReset");
+ resolve (wtx_ts_name_get, "wtxTsNameGet");
+ resolve (wtx_target_cpu_type_get, "wtxTargetCpuTypeGet");
+ resolve (wtx_target_has_fpp_get, "wtxTargetHasFppGet");
+ resolve (wtx_target_endian_get, "wtxTargetEndianGet");
+ resolve (wtx_target_bootline_get, "wtxTargetBootlineGet");
+ resolve (wtx_tool_name_get, "wtxToolNameGet");
+ resolve (wtx_ts_version_get, "wtxTsVersionGet");
+ resolve (wtx_unregister_for_event, "wtxUnregisterForEvent");
+ resolve (wtx_direct_call, "wtxDirectCall");
+ resolve (wtx_ts_info_get, "wtxTsInfoGet");
+ resolve (wtx_target_attach, "wtxTargetAttach");
+ resolve (wtx_probe, "wtxProbe");
+ resolve (wtx_timeout_set, "wtxTimeoutSet");
+ resolve (wtx_timeout_get, "wtxTimeoutGet");
+
+#if WTX_PROT_VERSION != 2
+ resolve (wtx_obj_module_list_get, "wtxObjModuleListGet");
+ resolve (wtx_context_stop, "wtxContextStop");
+ resolve (wtx_pd_create, "wtxPdCreate");
+ resolve (wtx_pd_kernel_get, "wtxPdKernelGet");
+ resolve (wtx_pd_current_get, "wtxPdCurrentGet");
+ resolve (wtx_pd_current_set, "wtxPdCurrentSet");
+ resolve (wtx_pd_info_q_get, "wtxPdInfoQGet");
+#else
+ resolve (wtx_obj_module_list, "wtxObjModuleList");
+#endif
+
+}
+
+void
+_initialize_remote_wtxapi ()
+{
+ load_wtx_libraries ();
+
+ add_prefix_cmd ("wtx", no_class, info_wtx_command,
+ _("Display version of WTX protocol for which gdb is built."),
+ &info_wtx_list, "info wtx ", 0, &infolist);
+
+ add_cmd ("threads", class_info, info_wtx_threads_command,
+ _("Display the list of threads running on the target."),
+ &info_wtx_list);
+
+ add_cmd ("version", class_info, info_wtx_version_command,
+ _("Display version of WTX protocol for which gdb is built."),
+ &info_wtx_list);
+
+ add_cmd ("vxworks-version", class_info, info_wtx_vxworks_version,
+ _("Display version of VxWorks for the target."),
+ &info_wtx_list);
+
+ add_cmd ("target-server", class_info, info_wtx_target_server,
+ _("Display target server information for the current connection."),
+ &info_wtx_list);
+}
diff --git a/gdb/remote-wtxapi.h b/gdb/remote-wtxapi.h
new file mode 100644
index 0000000..d719802
--- /dev/null
+++ b/gdb/remote-wtxapi.h
@@ -0,0 +1,1221 @@
+/* Thin binding for the WTX protocol, for GDB.
+
+ Copyright 2004, 2010, 2011 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#ifndef REMOTE_WTXAPI_H
+#define REMOTE_WTXAPI_H
+
+/* For wtx.h : GDB is run on the host. */
+#define HOST
+
+#include "wtx.h"
+#include "symfile.h"
+
+/* When in system-mode, the context ID to use is -1. */
+
+#define SYSTEM_CID (-1)
+
+#ifndef WTX_PROT_VERSION
+#define WTX_PROT_VERSION 2
+#endif
+
+#if WTX_PROT_VERSION == 4
+typedef WTX_TGT_ADDR_T wtxapi_tgt_addr_t;
+typedef WTX_TGT_ARG_T wtxapi_tgt_arg_t;
+#else
+typedef TGT_ADDR_T wtxapi_tgt_addr_t;
+typedef TGT_ARG_T wtxapi_tgt_arg_t;
+#endif
+
+/* Some macros are not defined in WTX 2.0. Define them as constant when
+ possible. */
+
+#ifndef WTX_PD_CURRENT
+extern const wtxapi_tgt_arg_t WTX_PD_CURRENT;
+#endif
+
+#ifndef WTX_PD_ALL
+extern const wtxapi_tgt_addr_t WTX_PD_ALL;
+#endif
+
+#ifndef WTX_MOD_FIND_IN_ALL_PD
+extern const wtxapi_tgt_addr_t WTX_MOD_FIND_IN_ALL_PD;
+#endif
+
+#ifndef WTX_SYM_FIND_IN_ALL_PD
+extern const int WTX_SYM_FIND_IN_ALL_PD;
+#endif
+
+/* On WTX 3.0, some additional values has been added in the enums to
+ deal with the protection domains. Emulate these value in WTX 2.0. */
+
+#if WTX_PROT_VERSION == 2
+extern const WTX_CONTEXT_TYPE WTX_CONTEXT_PD;
+extern const int WTX_ERR_PD_INVALID_PD;
+#endif
+
+#ifndef WTX_LOAD_GLOBAL_SYMBOLS
+#define WTX_LOAD_GLOBAL_SYMBOLS 0x4
+#endif
+
+/* On WTX 4.0, some variables have been renamed. */
+
+#if WTX_PROT_VERSION == 4
+extern const WTX_ACTION_TYPE WTX_ACTION_STOP_ALL;
+#endif
+
+/* The structures defined below are used to resolve differences
+ between version of the WTX protocol.
+
+ Note those differences:
+ - When the WTX structure contains a BOOL32, the WTX API structure uses an
+ int; if it is FALSE in the WTX structure, it is 0 in the WTX API structure;
+ - When the WTX structure contains a UINT32, the WTX API uses an int; the
+ conversion is straightforward. */
+
+/* Protection domain ID. */
+
+typedef wtxapi_tgt_addr_t pd_id_t;
+
+/* Module ID. */
+
+typedef UINT32 module_id_t;
+
+/* Event point id. */
+
+typedef UINT32 evtpt_id_t;
+
+
+/* Invalid identifiers. Equivalent to WTX_ERROR. */
+
+extern const pd_id_t invalid_pd_id;
+extern const evtpt_id_t invalid_module_id;
+extern const evtpt_id_t invalid_evtpt_id;
+extern const WTX_CONTEXT_ID_T invalid_context_id;
+extern const WTX_AGENT_MODE_TYPE invalid_agent_mode;
+extern const WTX_CONTEXT_STATUS invalid_context_status;
+
+/* Event. Same as WTX_EVENT in WTX 3.0, and WTX_EVENT_2 in WTX 2.0. */
+
+struct wtxapi_event
+{
+ WTX_EVENT_TYPE event_type;
+ int num_args;
+ wtxapi_tgt_arg_t *args;
+};
+
+/* Action. Based on WTX_ACTION. */
+
+struct wtxapi_action
+{
+ /* Action type to perform. */
+ WTX_ACTION_TYPE action_type;
+ /* Action dependent argument. */
+ int action_arg;
+ /* Function to ACTION_CALL. */
+ wtxapi_tgt_addr_t call_rtn;
+ /* Function argument. */
+ wtxapi_tgt_arg_t call_arg;
+};
+
+/* Context. Same as WTX_CONTEXT */
+
+struct wtxapi_context
+{
+ WTX_CONTEXT_TYPE context_type;
+ WTX_CONTEXT_ID_T context_id;
+
+ /* WTX 4.0-specific field. */
+ WTX_CONTEXT_ID_T context_sub_id;
+};
+
+/* Eventpoint desc. Same as WTX_EVTPT in WTX 3.0, and WTX_EVTPT_2
+ in WTX 2.0. */
+
+struct wtxapi_evtpt
+{
+ struct wtxapi_event event;
+ struct wtxapi_context context;
+ struct wtxapi_action action;
+};
+
+/* Eventpoint info. Same as WTX_EVTPT_INFO. */
+
+struct wtxapi_evtpt_info
+{
+ /* Eventpoint descriptor. */
+ struct wtxapi_evtpt wtx_evtpt;
+ /* Tool identifier. */
+ int tool_id;
+ /* Eventpoint identifier. */
+ evtpt_id_t evtpt_num;
+};
+
+
+/* Eventpoint list message. Same as WTX_EVTPT_LIST in WTX 3.0,
+ and WTX_EVTPT_LIST_2 in WTX 2.0. */
+
+struct wtxapi_evtpt_list
+{
+ int n_evtpt;
+ struct wtxapi_evtpt_info *p_evtpt_info;
+};
+
+/* Section descriptor. Based on WTX_SECTION_DESC (WTX 3.0)
+ and LD_M_SECTION (WTX 2.0). */
+
+struct wtxapi_section_desc
+{
+ /* Name of the section. */
+ char *name;
+ /* Section flags. */
+ int flags;
+ /* Section base address. */
+ wtxapi_tgt_addr_t base_addr;
+ /* Section length. */
+ int length;
+};
+
+/* Symbol description. Based on WTX_SYMBOL. */
+
+struct wtxapi_symbol
+{
+ /* Returned value for find request. */
+ int status;
+ /* Protection domain ID. */
+ pd_id_t pd_id;
+ /* Symbol name. */
+ char *name;
+ /* 0 iff symbol name prefixed by an underscore. */
+ int exact_name;
+ /* Symbol value. */
+ wtxapi_tgt_addr_t value;
+ /* symbol type. */
+ int type;
+ /* symbol type mask for lookup. */
+ int type_mask;
+ /* Module name. */
+ char *module_name;
+};
+
+/* Symbol copy options for copy_current_symbol. */
+
+extern const int wtxapi_symbol_copy_none;
+extern const int wtxapi_symbol_copy_name;
+extern const int wtxapi_symbol_copy_module_name;
+#define wtxapi_symbol_copy_all (wtxapi_symbol_copy_module_name \
+ | wtxapi_symbol_copy_name)
+
+enum wtxapi_symbol_copy_options
+{
+ wtxapi_symbol_copy_full = 1,
+ wtxapi_symbol_copy_dont_copy_name = 2,
+ wtxapi_symbol_copy_dont_copy_module_name = 3,
+ wtxapi_symbol_copy_dont_copy_strings = 4
+};
+
+/* Symbol list. Based on WTX_SYMBOL and WTX_SYMBOL_LIST. */
+
+struct wtxapi_symbol_list;
+
+struct segment_addresses
+{
+ CORE_ADDR text_addr;
+ CORE_ADDR data_addr;
+ CORE_ADDR bss_addr;
+};
+
+/* Object module information. Based on WTX_MODULE_INFO. */
+
+struct wtxapi_module_info
+{
+ /* Protection domain ID. */
+ pd_id_t pd_id;
+ /* Module ID. */
+ module_id_t module_id;
+ /* Module name (with path). */
+ char *module_name;
+ /* Flags used to load module. */
+ int load_flag;
+ /* Section description. */
+ struct section_addr_info *section_addrs;
+ /* On older systems (Tornado 2), the system does not provide
+ the section addresses, but rather 3 segment addresses.
+ The following field stores these segment addresses to allow
+ us later to compute each section address.
+
+ On targets where the system does provide us with the section
+ addresses, this field should be unused. */
+ struct segment_addresses *segments;
+ /* List of undefined symbols. Only initialized after a 'load' operation. */
+ struct wtxapi_symbol_list *undef_list;
+};
+
+/* Module ID list. Based on WTX_MODULE_LIST (WTX 2.0). */
+
+struct wtxapi_module_list
+{
+ /* Number of module in list. */
+ int num_obj_mod;
+ /* Arrays of object module id and pd id. For one index, you have a
+ couple (module id, pd id). */
+ module_id_t *mod_id_array;
+ pd_id_t *pd_id_array;
+};
+
+/* task context descriptor. Same as WTX_TASK_CONTEXT_DEF (WTX 3.0) and
+ equivalent to WTX_CONTEXT_DESC (WTX 2.0). */
+
+struct wtxapi_task_context_desc
+{
+ /* Context PD ID. */
+ pd_id_t pd_id;
+ /* Integer or double. */
+ WTX_RETURN_TYPE return_type;
+ /* Task name. */
+ char *name;
+ /* Priority. */
+ int priority;
+ /* Options. */
+ int options;
+ /* Base of stack. */
+ wtxapi_tgt_addr_t stack_base;
+ /* Stack size. */
+ int stack_size;
+ /* Context entry point. */
+ wtxapi_tgt_addr_t entry;
+ /* Redirection in file or NULL. */
+ INT32 redir_in;
+ /* Redirection out file or NULL. */
+ INT32 redir_out;
+ /* Redirection error file or NULL. */
+ INT32 redir_err;
+ /* Arguments. */
+ int argc;
+ wtxapi_tgt_arg_t *argv;
+};
+
+/* PD context descriptor. Same on WTX_PD_CONTEXT_DEF (WTX 3.0) and
+ equivalent to WTX_CONTEXT_DESC (WTX 2.0). */
+
+struct wtxapi_pd_context_desc
+{
+ /* PD name. */
+ char *name;
+ /* Options. */
+ int options;
+ /* Size of the PD's heap. */
+ int heap_size;
+ /* Lowest task's priority. */
+ int low_priority;
+ /* Highest task's priority. */
+ int high_priority;
+ /* Page pool list name to use. */
+ wtxapi_tgt_addr_t page_pool_list;
+ /* Return address to call on deletion. */
+ wtxapi_tgt_addr_t destroy_rtn;
+ /* Initial link path for this PD. */
+ char *link_path;
+ /* Redirection in file or NULL. */
+ INT32 redir_in;
+ /* Redirection out file or NULL. */
+ INT32 redir_out;
+ /* Redirection error file or NULL. */
+ INT32 redir_err;
+ /* Extra argument count (in argv). */
+ int argc;
+ /* Extra argument array. */
+ wtxapi_tgt_arg_t *argv;
+};
+
+/* Context descriptor. Based on WTX_CONTEXT_DESC (WTX 3.0). Different
+ from WTX_CONTEXT_DESC in WTX 2.0. */
+
+struct wtxapi_context_desc
+{
+ /* Type of context. */
+ WTX_CONTEXT_TYPE context_type;
+
+ union _wtx_context_def
+ {
+ /* Task context definition. */
+ struct wtxapi_task_context_desc task_context;
+ /* PD context definition. */
+ struct wtxapi_pd_context_desc pd_context;
+ } wtx_context_def;
+};
+
+/* Some macro to access the fields of a wtxapi_context_desc */
+
+#define TASK_CONTEXT_ARGV(context_desc, i) \
+ (context_desc.wtx_context_def.task_context.argv[i])
+#define TASK_CONTEXT_ENTRY(context_desc) \
+ (context_desc.wtx_context_def.task_context.entry)
+#define TASK_CONTEXT_NAME(context_desc) \
+ (context_desc.wtx_context_def.task_context.name)
+#define TASK_CONTEXT_CONTEXT_TYPE(context_desc) \
+ (context_desc.context_type)
+#define TASK_CONTEXT_STACK_SIZE(context_desc) \
+ (context_desc.wtx_context_def.task_context.stack_size)
+#define TASK_CONTEXT_PRIORITY(context_desc) \
+ (context_desc.wtx_context_def.task_context.priority)
+#define TASK_CONTEXT_OPTIONS(context_desc) \
+ (context_desc.wtx_context_def.task_context.options)
+#define TASK_CONTEXT_ARGC(context_desc) \
+ (context_desc.wtx_context_def.task_context.argc)
+#define TASK_CONTEXT_PDID(context_desc) \
+ (context_desc.wtx_context_def.task_context.pd_id)
+
+/* PD descriptor. Same as WTX_PD_DESC (WTX 3.0). */
+
+struct wtxapi_pd_desc
+{
+ /* Protection domain ID. */
+ pd_id_t pd_id;
+ /* Protection domain name. */
+ char *pd_name;
+ /* Protection domain flags. */
+ int pd_flags;
+ /* Link path string. */
+ char *pd_link_path_str;
+ /* Nb of PD in linkpath. */
+ int pd_link_path_count;
+ /* PD ids of the linkpath. */
+ pd_id_t *pd_link_path;
+ int pd_attach_to_count;
+ pd_id_t *pd_attach_to;
+};
+
+/* PD descriptor list. Same as WTX_PD_DESC_Q (WTX 3.0). */
+
+struct wtxapi_pd_desc_q
+{
+ struct wtxapi_pd_desc pd_desc;
+ struct wtxapi_pd_desc_q *next;
+};
+
+/* Symbol table info. Same as WTX_SYM_TBL_INFO (WTX 3.0). */
+
+struct wtxapi_sym_tbl_info
+{
+ /* Protection domain ID. */
+ pd_id_t pd_id;
+ /* Number of symbols. */
+ int sym_num;
+ /* Name clash policy. */
+ int same_name_ok;
+};
+
+/* Target agent info. Based on WTX_AGENT_INFO. */
+
+struct wtxapi_agent_info
+{
+ /* WDB agent version. */
+ char *agent_version;
+ /* Max transfer size (bytes). */
+ int mtu;
+ /* Available agent modes. */
+ int mode;
+};
+
+/* Target runtime information. Based on WTX_RT_INFO. */
+
+struct wtxapi_rt_info
+{
+ /* Runtime name. */
+ char *rt_name;
+ /* Runtime version. */
+ char *rt_version;
+ /* Target processor type. */
+ int cpu_type;
+ /* Target cpu variant. */
+ char *cpu_variant;
+ /* Text write protect available. */
+ int has_write_protect;
+ /* Size of a page. */
+ int page_size;
+ /* Endianness (LITTLE or BIG). */
+ int endian;
+ /* Board support package name. */
+ char *bsp_name;
+ /* Boot file name. */
+ char *boot_line;
+ /* Target main memory base address. */
+ wtxapi_tgt_addr_t mem_base;
+ /* Target main memory size. */
+ int mem_size;
+ /* Number of memory regions. */
+ int num_regions;
+ /* Target server memory pool base. */
+ int host_pool_base;
+ /* Target server memory pool size. */
+ int host_pool_size;
+};
+
+/* Target information. Based on WTX_TGT_INFO. */
+struct wtxapi_tgt_info
+{
+ struct wtxapi_agent_info agent_info;
+ struct wtxapi_rt_info rt_info;
+};
+
+/* Target server information message. Based on WTX_TS_INFO. */
+
+struct wtxapi_ts_info
+{
+ /* Target link descriptor. */
+ WTX_TGT_LINK_DESC tgt_link_desc;
+ /* Info obtained from Target. */
+ struct wtxapi_tgt_info tgt_info;
+ /* Target Server version. */
+ char *version;
+ /* Target server user name. */
+ char *user_name;
+ /* Lock/authorization message. */
+ char *lock_msg;
+ /* 0 iff the PDs are not initialized. */
+ int pd_initialized;
+};
+
+/* The data from a context-exit event. */
+
+struct wtxapi_ctx_exit_event
+{
+ WTX_CONTEXT_ID_T context_id;
+ WTX_CONTEXT_TYPE context_type;
+ int exit_code;
+};
+
+/* The data from a data-access (watchpoint) event. */
+
+struct wtxapi_data_access_event
+{
+ WTX_CONTEXT_ID_T task_id;
+ WTX_CONTEXT_ID_T context_id;
+ WTX_CONTEXT_TYPE context_type;
+
+ /* The address being watched that triggered the DATA_ACCESS event. */
+ CORE_ADDR data_addr;
+};
+
+/* The data from an exception event. */
+
+struct wtxapi_exception_event
+{
+ WTX_CONTEXT_ID_T context_id;
+ WTX_CONTEXT_TYPE context_type;
+ int exception_value;
+};
+
+/* The data from an obj-loaded event. */
+
+struct wtxapi_obj_loaded_event
+{
+ module_id_t module_id;
+};
+
+/* The data from an obj-unloaded event. */
+
+struct wtxapi_obj_unloaded_event
+{
+ char *module_filename;
+};
+
+/* The data from a text-access (breakpoint) event. */
+
+struct wtxapi_text_access_event
+{
+ WTX_CONTEXT_ID_T task_id;
+ WTX_CONTEXT_ID_T context_id;
+ WTX_CONTEXT_TYPE context_type;
+
+ /* The address of the breakpoint that triggered this event. */
+ CORE_ADDR text_addr;
+};
+
+/* The data from the vio-write event. */
+
+struct wtxapi_vio_write_event
+{
+ int channel_id;
+ char *data; /* The contents printed on the virtual IO channel. */
+};
+
+/* A structure representing the contents of an event received from
+ the target server. */
+
+struct wtxapi_event_desc
+{
+ WTX_EVENT_TYPE event_type;
+
+ union
+ {
+ struct wtxapi_ctx_exit_event ctx_exit;
+ struct wtxapi_data_access_event data_access;
+ struct wtxapi_exception_event exception;
+ struct wtxapi_obj_loaded_event obj_loaded;
+ struct wtxapi_obj_unloaded_event obj_unloaded;
+ struct wtxapi_text_access_event text_access;
+ struct wtxapi_vio_write_event vio_write;
+ } desc;
+};
+
+/* The following function are simple wrappers used to resolve the
+ differences between the WTX versions. Unless specified in the
+ comments, the WTX lib C documentation applies. If the return type
+ is a WTX type, it should be deallocated using wtxapi_result_free.
+ If it is a type defined in remote-wtxapi.h, it should be deallocate
+ using one of the deallocation function provided in this file.
+
+ Note those differences:
+
+ - when the return type of the WTX function is a STATUS, the wrapper
+ returns an int; in this case, iff the WTX function returns
+ WTX_ERROR, the wrapper returns 0;
+
+ - when the return type of the WTX function is a BOOL32, the wrapper
+ returns an int; in this case, iff the WTX function returns FALSE,
+ the wrapper returns 0. */
+
+/* Initialize the global WTX client handle. Only one WTX connection is
+ allowed. */
+
+extern int wtxapi_initialize ();
+
+/* Return the WTX handle of the current WTX connection.
+ Valid only after a successful call to wtxapi_initialize. */
+
+extern HWTX wtxapi_get_current_wtx_handle ();
+
+/* Return list of registred services. NAME_PAT is the reg expression
+ to match svc name. TYPE_PAT is the reg expression to match svc
+ type. KEY_PAT is the reg expression to match svc key. */
+
+extern WTX_DESC_Q *wtxapi_info_q (const char *name_pat, const char *type_pat,
+ const char *key_pat);
+
+/* Terminate the use of the global WTX client handle. */
+
+extern int wtxapi_terminate ();
+
+/* Connect the client to the target server. */
+
+extern int wtxapi_tool_attach (const char *target_name,
+ const char *tool_name);
+
+/* Check tool connection to the server. */
+
+extern int wtxapi_tool_connected ();
+
+/* Detach from the target server. */
+
+extern int wtxapi_tool_detach ();
+
+/* Clear any error for the tool. */
+
+extern int wtxapi_err_clear ();
+
+/* Return the version of WTX. */
+
+extern int wtxapi_version_get ();
+
+/* Return the last error for a handle. */
+
+extern WTX_ERROR_T wtxapi_err_get ();
+
+/* Add an error handler. */
+
+extern WTX_HANDLER_T wtxapi_err_handler_add (WTX_HANDLER_FUNC p_func,
+ void *p_client_data);
+
+/* Remove an error handler for WTX handle. */
+
+extern int wtxapi_err_handler_remove (WTX_HANDLER_T p_handler);
+
+/* Fetch the last WTX API error string. */
+
+extern const char *wtxapi_err_msg_get ();
+
+/* Get the agent mode. Return invalid_agent_mode if an error occurs. */
+
+extern WTX_AGENT_MODE_TYPE wtxapi_agent_mode_get ();
+
+/* Set the mode of the target agent. */
+
+extern int wtxapi_agent_mode_set (WTX_AGENT_MODE_TYPE agent_mode);
+
+/* Create a new breakpoint. */
+
+extern evtpt_id_t wtxapi_breakpoint_add (WTX_CONTEXT_TYPE context_type,
+ WTX_CONTEXT_ID_T context_id,
+ wtxapi_tgt_addr_t tgt_addr);
+
+/* Create a new event point. */
+
+extern evtpt_id_t wtxapi_eventpoint_add (struct wtxapi_evtpt *p_evtpt);
+
+/* Delete eventpoint from the target. */
+
+extern int wtxapi_eventpoint_delete (evtpt_id_t evtpt_id);
+
+/* Get the next event in the event queue. */
+
+extern struct wtxapi_event_desc * wtxapi_event_get (void);
+
+/* Get status of a context. Return invalid_context_status if the operation
+ fails. */
+
+extern WTX_CONTEXT_STATUS wtxapi_context_status_get
+ (WTX_CONTEXT_TYPE context_type, WTX_CONTEXT_ID_T context_id);
+
+/* Continue execution of target context. */
+
+extern int wtxapi_context_cont (WTX_CONTEXT_TYPE context_type,
+ WTX_CONTEXT_ID_T context_id);
+
+/* Create a context on target.
+ - if P_CONTEXT_DESC is invalid, generates WTX_ERR_API_INVALID_ARG;
+ - if another unidentified error occurs, return invalid_context_id;
+ e.g if the operation is not permitted by the kernel. */
+
+extern WTX_CONTEXT_ID_T wtxapi_context_create
+ (struct wtxapi_context_desc *p_context_desc);
+
+/* Resume execution of a target context. */
+
+extern int wtxapi_context_resume (WTX_CONTEXT_TYPE context_type,
+ WTX_CONTEXT_ID_T context_id);
+
+/* Add exit evpt notification. */
+
+extern evtpt_id_t wtxapi_context_exit_notify_add
+ (WTX_CONTEXT_TYPE context_type, WTX_CONTEXT_ID_T context_id);
+
+/* Kill a target context. */
+
+extern int wtxapi_context_kill (WTX_CONTEXT_TYPE context_type,
+ WTX_CONTEXT_ID_T context_id);
+
+/* Single step exec of target context. */
+
+extern int wtxapi_context_step (WTX_CONTEXT_TYPE context_type,
+ WTX_CONTEXT_ID_T context_id,
+ wtxapi_tgt_addr_t step_start,
+ wtxapi_tgt_addr_t step_end);
+
+/* Suspend a target context. */
+
+extern int wtxapi_context_suspend (WTX_CONTEXT_TYPE context_type,
+ WTX_CONTEXT_ID_T context_id);
+
+/* Stop (on WTX 3.0) or suspend (on WTX 2.0) a target context. */
+
+extern int wtxapi_context_stop (WTX_CONTEXT_TYPE context_type,
+ WTX_CONTEXT_ID_T context_id);
+
+/* List event points on TS. */
+
+extern struct wtxapi_evtpt_list *wtxapi_eventpoint_list_get ();
+
+/* Free mem allocated by WTX API call. */
+
+extern int wtxapi_result_free (void *p_result);
+
+/* Evaluate Gopher string on target. */
+
+extern WTX_GOPHER_TAPE *wtxapi_gopher_eval (pd_id_t pd_id,
+ const char *input_string);
+
+/* Get info about memory pool. */
+
+extern WTX_MEM_INFO *wtxapi_mem_info_get (pd_id_t pd_id);
+
+/* Alloc blocks in memory pool. */
+
+extern wtxapi_tgt_addr_t wtxapi_mem_alloc (pd_id_t pd_id, int num_bytes);
+
+/* Perform checksum on target memory. */
+
+extern int wtxapi_mem_checksum (pd_id_t pd_id, wtxapi_tgt_addr_t start_addr,
+ int num_bytes);
+
+/* Move a block of target memory. */
+
+extern int wtxapi_mem_move (pd_id_t src_pd_id, wtxapi_tgt_addr_t src_addr,
+ pd_id_t dst_pd_id, wtxapi_tgt_addr_t dest_addr,
+ int num_bytes);
+
+/* Free a block of target memory. */
+
+extern int wtxapi_mem_free (pd_id_t pd_id, wtxapi_tgt_addr_t address);
+
+/* Read memory from the target. */
+
+extern int wtxapi_mem_read (pd_id_t pd_id, wtxapi_tgt_addr_t from_addr,
+ void *to_addr, int num_bytes);
+
+/* Read memory on WIDTH bytes. */
+
+extern int wtxapi_mem_width_read (pd_id_t pd_id, wtxapi_tgt_addr_t from_addr,
+ void *to_addr, int num_bytes, int width);
+
+/* Write memory on the target. */
+
+extern int wtxapi_mem_write (pd_id_t pd_id, void *from_addr,
+ wtxapi_tgt_addr_t to_addr, int num_bytes);
+
+/* Write memory on the target, on WIDTH bytes large. */
+
+extern int wtxapi_mem_width_write (pd_id_t pd_id, void *from_addr,
+ wtxapi_tgt_addr_t to_addr, int num_bytes,
+ int width);
+
+/* Set target memory to given value. */
+
+extern int wtxapi_mem_set (pd_id_t pd_id, wtxapi_tgt_addr_t addr,
+ int num_bytes, int val);
+
+/* Add memory to the agent pool. */
+
+extern int wtxapi_mem_add_to_pool (pd_id_t pd_id, wtxapi_tgt_addr_t address,
+ int size);
+
+/* Reallocate a block of target mem. */
+
+extern wtxapi_tgt_addr_t wtxapi_mem_realloc (pd_id_t pd_id,
+ wtxapi_tgt_addr_t address,
+ int num_bytes);
+
+/* Allocate aligned target memory. */
+
+extern wtxapi_tgt_addr_t wtxapi_mem_align (pd_id_t pd_id,
+ wtxapi_tgt_addr_t alignment,
+ int num_bytes);
+
+/* Scan target memory for pattern. */
+
+extern int wtxapi_mem_scan (pd_id_t pd_id, int match,
+ wtxapi_tgt_addr_t start_addr,
+ wtxapi_tgt_addr_t end_addr,
+ int num_bytes, void *pattern,
+ wtxapi_tgt_addr_t * p_result);
+
+/* Checks validity of target memory. */
+
+extern int wtxapi_obj_module_checksum (pd_id_t pd_id, module_id_t module_id,
+ char *module_name);
+
+/* Find obj module ID from name. */
+
+extern module_id_t wtxapi_obj_module_find_id (pd_id_t pd_id,
+ const char *module_name);
+
+/* Return the ID of the module which basename is equal to MODULE_NAME.
+ Search the current PD first, before extending the search to all PDs. */
+
+extern module_id_t wtxapi_obj_module_in_system_find_id
+ (const char *module_name);
+
+/* Find module name given its ID. */
+
+extern const char *wtxapi_obj_module_find_name (pd_id_t pd_id,
+ module_id_t module_id);
+
+/* Give info on obj module. */
+
+extern struct wtxapi_module_info
+ *wtxapi_obj_module_info_get (pd_id_t pd_id, module_id_t module_id);
+
+/* List loaded obj modules (wrapper around wtxObjModuleList (WTX 2.0)
+ or wtxObjModuleListGet (WTX 3.0)). To search on every PD, pd_id
+ should be set to WTX_MOD_FIND_IN_ALL_PD. */
+
+extern struct wtxapi_module_list *wtxapi_obj_module_list_get (pd_id_t pd_id);
+
+/* Load a new object module. */
+
+extern struct wtxapi_module_info
+ *wtxapi_obj_module_load (pd_id_t pd_id, char *filename, int load_flag);
+
+extern struct wtxapi_module_info *wtxapi_module_load (pd_id_t pd_id,
+ char *filename,
+ int load_flag,
+ int timeout);
+
+/* Unload an obj module from target. */
+
+extern int wtxapi_obj_module_unload (pd_id_t pd_id, module_id_t mod_id);
+
+extern int wtxapi_obj_module_by_name_unload (pd_id_t pd_id, char *name);
+
+/* Send events matching expression. */
+
+extern int wtxapi_register_for_event (const char *reg_exp);
+
+/* Read register data from the target. */
+
+extern int wtxapi_regs_get (WTX_CONTEXT_TYPE context_type,
+ WTX_CONTEXT_ID_T context_id,
+ WTX_REG_SET_TYPE reg_set,
+ int first_byte, int num_bytes, void *reg_memory);
+
+/* Write to registers on the target. */
+
+extern int wtxapi_regs_set (WTX_CONTEXT_TYPE context_type,
+ WTX_CONTEXT_ID_T context_id,
+ WTX_REG_SET_TYPE reg_set,
+ int first_byte, int num_bytes, void *reg_memory);
+
+/* Convert str to a wtxapi_tgt_addr_t. */
+
+extern wtxapi_tgt_addr_t wtxapi_str_to_tgt_addr (const char *str);
+
+/* Convert str to context ID. */
+
+extern WTX_CONTEXT_ID_T wtxapi_str_to_context_id (const char *str);
+
+/* Convert str ton context type. */
+
+extern WTX_CONTEXT_TYPE wtxapi_str_to_context_type (const char *str);
+
+/* Convert str to an INT32. */
+
+extern int wtxapi_str_to_int32 (const char *str);
+
+/* Convert string to event type. */
+
+extern WTX_EVENT_TYPE wtxapi_str_to_event_type (const char *str);
+
+/* Add symbol with given params. */
+
+extern int wtxapi_sym_add (pd_id_t pd_id, const char *sym_name,
+ wtxapi_tgt_addr_t sym_value, int sym_type);
+
+/* Find info on symbol. Based on wtxSymFind WTX 2.0, with two differences:
+ _ one additional parameter: the protection domain ID (PD_ID);
+ _ no filter on the type. */
+
+extern struct wtxapi_symbol_list *wtxapi_sym_find (pd_id_t pd_id,
+ char *sym_name,
+ wtxapi_tgt_addr_t sym_value,
+ int exact_name);
+
+/* Get list of symbols. Based on wtxSymListGet WTX 2.0, with three differences:
+ - one additional parameter: the protection domain ID (PD_ID);
+ - no filter on the unknown symbols;
+ - no filter on the module name/id. */
+
+extern struct wtxapi_symbol_list
+ *wtxapi_sym_list_get (pd_id_t pd_id, char *substring,
+ wtxapi_tgt_addr_t value);
+
+/* Get list of symbols. */
+
+extern struct wtxapi_symbol_list
+ *wtxapi_sym_list_by_module_id_get (pd_id_t pd_id, const char *string,
+ module_id_t module_id,
+ wtxapi_tgt_addr_t value,
+ int list_unknown);
+
+/* Get list of symbols. */
+
+extern struct wtxapi_symbol_list
+ *wtxapi_sym_list_by_module_name_get (pd_id_t pd_id,
+ const char *string,
+ const char *module_name,
+ wtxapi_tgt_addr_t value,
+ int list_unknown);
+
+/* Remove a symbol from sym table. */
+
+extern int wtxapi_sym_remove (pd_id_t pd_id, const char *sym_name,
+ int sym_type);
+
+/* Get the symbol table info. */
+
+extern struct wtxapi_sym_tbl_info *wtxapi_sym_tbl_info_get (pd_id_t pd_id);
+
+/* Reset the target. */
+
+extern int wtxapi_target_reset ();
+
+/* Get target server name. */
+
+extern const char *wtxapi_ts_name_get ();
+
+/* Get target-runtime version. */
+
+extern const char *wtxapi_target_rt_version_get ();
+
+/* Get the target CPU type code. */
+
+extern int wtxapi_target_cpu_type_get ();
+
+/* Check for floating point processor. */
+
+extern int wtxapi_target_has_fpp_get ();
+
+/* Get edianness of target. */
+
+extern WTX_ENDIAN_T wtxapi_target_endian_get ();
+
+/* Get target boot line info. */
+
+extern const char *wtxapi_target_bootline_get ();
+
+/* Return name of current tool. */
+
+extern const char *wtxapi_tool_name_get ();
+
+/* Return the Tornado version. */
+
+extern const char *wtxapi_ts_version_get ();
+
+/* Unregister for some events. */
+
+extern int wtxapi_unregister_for_event (char *reg_exp);
+
+/* Call func on target within agent. */
+
+extern int wtxapi_direct_call (wtxapi_tgt_addr_t entry, void *p_ret_val,
+ wtxapi_tgt_arg_t arg0, wtxapi_tgt_arg_t arg1,
+ wtxapi_tgt_arg_t arg2, wtxapi_tgt_arg_t arg3,
+ wtxapi_tgt_arg_t arg4, wtxapi_tgt_arg_t arg5,
+ wtxapi_tgt_arg_t arg6, wtxapi_tgt_arg_t arg7,
+ wtxapi_tgt_arg_t arg8, wtxapi_tgt_arg_t arg9);
+
+/* Get info about target and server. */
+
+extern struct wtxapi_ts_info *wtxapi_ts_info_get ();
+
+/* Reattach to the target. */
+
+extern int wtxapi_target_attach ();
+
+/* Probe to see if registry is running. */
+
+extern int wtxapi_probe ();
+
+/* Set WTX timeout. */
+
+extern int wtxapi_timeout_set (int msec);
+
+/* Get the current timeout. */
+
+extern int wtxapi_timeout_get (int *p_msec);
+
+/* Create a new protection domain. */
+
+extern wtxapi_tgt_addr_t wtxapi_pd_create (const char *name, int options,
+ int heap_size, int low_priority,
+ int high_priority,
+ wtxapi_tgt_addr_t page_pool_list,
+ const char *link_path);
+
+/* Get kernel Protection Domain ID. */
+
+extern pd_id_t wtxapi_pd_kernel_get ();
+
+/* Get the current Protection Domain. */
+
+extern pd_id_t wtxapi_pd_current_get ();
+
+/* Set the current Protection Domain. */
+
+extern int wtxapi_pd_current_set (pd_id_t pd_id);
+
+/* Get the list of allocated PDs. */
+
+extern struct wtxapi_pd_desc_q *wtxapi_pd_info_q_get ();
+
+/* Check whether the module has been fully linked or not. */
+
+extern int wtxapi_load_fully_linked (const struct wtxapi_module_info
+ *module_info);
+
+/* Simple additional functions. */
+
+/* Test target server availability. */
+
+extern int wtxapi_target_server_available_p ();
+
+/* Symbol list handling. The symbol list contain a 'current symbol'.
+ This current symbol is used to go through the list. */
+
+/* Get a copy of the current symbol. */
+
+extern struct wtxapi_symbol
+ *get_current_wtxapi_symbol (struct wtxapi_symbol_list *list);
+
+
+/* Copy current symbol of LIST into TO.
+
+ OPTIONS is used to avoid uneeded dynamic allocation.
+
+ If OPTIONS is set to wtxapi_symbol_copy_full, the fields name and
+ module_name of TO are null pointers, these string fields of TO are
+ allocated and fully copied from the current symbol, and should be
+ deallocated by the caller.
+
+ If OPTIONS is set to wtxapi_symbol_copy_name (resp.
+ wtxapi_symbol_copy_module_name), the field name (resp. the
+ module_name) of TO is copied. If not, it is is set to NULL.
+
+ If OPTIONS is set to wtxapi_symbol_copy_none, the field name and
+ module_name of TO are not copied and are set to NULL. In this case
+ and only in this case no dynamic allocation is performed by this
+ function. */
+
+extern void copy_current_wtxapi_symbol (struct wtxapi_symbol_list *list,
+ struct wtxapi_symbol *to,
+ int options);
+
+/* Return the name of the current symbol inside LIST.
+ The result must be deallocated after use. */
+
+extern char *current_wtxapi_symbol_name (struct wtxapi_symbol_list *list);
+
+/* Change the current symbol to the first element of the list.If there
+ is no next element, return 0. */
+
+int go_to_first_element_in_wtxapi_sym_list (struct wtxapi_symbol_list *list);
+
+/* Change the current symbol to the next element of the list. If there
+ is no next element, return 0. */
+
+int go_to_next_element_in_wtxapi_sym_list (struct wtxapi_symbol_list *list);
+
+/* Deallocation functions for the structures,lists returned by the
+ function defined in this file. It frees "everything", i.e. it go
+ through every element of the list and deallocate it, and also
+ deallocate strings and arrays referenced by a field. */
+
+extern void free_wtxapi_evtpt_list (struct wtxapi_evtpt_list *to_free);
+
+extern void free_wtxapi_module_list (struct wtxapi_module_list *to_free);
+
+extern void free_wtxapi_pd_desc_q (struct wtxapi_pd_desc_q *to_free);
+
+extern void free_wtxapi_symbol (struct wtxapi_symbol *to_free);
+
+extern void free_wtxapi_symbol_list (struct wtxapi_symbol_list *to_free);
+
+extern void free_wtxapi_module_info (struct wtxapi_module_info *to_free);
+
+extern void free_wtxapi_ts_info (struct wtxapi_ts_info *to_free);
+
+extern void free_wtxapi_event_desc (struct wtxapi_event_desc *to_free);
+
+/* Stubs for GDB cleanup functions. */
+
+extern void cleanup_wtxapi_evtpt_list (void *to_free);
+
+extern void cleanup_wtxapi_module_list (void *to_free);
+
+extern void cleanup_wtxapi_pd_desc_q (void *to_free);
+
+extern void cleanup_wtxapi_symbol (void *to_free);
+
+extern void cleanup_wtxapi_symbol_list (void *to_free);
+
+extern void cleanup_wtxapi_module_info (void *to_free);
+
+extern void cleanup_wtxapi_ts_info (void *to_free);
+
+extern void cleanup_wtxapi_result_free (void *to_free);
+
+/* Helpers. */
+
+int remote_wtxapi_get_symbol_address (char *symbol_name,
+ CORE_ADDR *symbol_addr);
+
+int wtxapi_target_has_BoDA (void);
+
+/* A list of threads running on the target system. */
+
+struct wtxapi_thread_info
+{
+ struct wtxapi_thread_info *next;
+ WTX_CONTEXT_ID_T id;
+ char *name;
+
+ /* The address where the task GP registers are stored when the task
+ is not being executed. This is necessary to retrieve the registers
+ of this task when in system mode, because wtxapi_regs_get/set
+ will only get/set the registers of the current task (ie the
+ task currently being scheduled by the system). */
+ CORE_ADDR regs_addr;
+
+ /* Similarly, we need to store the address where the FP registers
+ are stored. Computing this address requires support from the system,
+ and thus may not be available - in this case, this address should
+ be set to zero. */
+ CORE_ADDR fp_regs_addr;
+};
+
+extern void free_wtxapi_thread_info (struct wtxapi_thread_info *threads);
+
+/* The WTX protocol does not have all the necessary features needed
+ to implement a remote backend. So this module relies on other
+ modules provided by the target system (typically a TCL interpreter,
+ or a DFW server). Unfortunately, which module to use is dependent
+ on the target. So we maintain a vector with pointers to functions
+ that provide the missing features of WTX. */
+
+struct wtxapi_support_ops
+{
+ /* Perform all necessary actions following the establishing of
+ the given WTX connection. */
+ void (*wtx_connection_established_callback) (HWTX wtx_handle);
+
+ /* Get the list of threads currently running on the target system. */
+ struct wtxapi_thread_info * (*get_thread_list) (void);
+
+ /* Find the Partition ID of the given task ID.
+ If successful, then set TASK_PD with the result, and return non-zero.
+ Otherwise, return zero and leave the value of TASK_PD undefined. */
+ int (*get_task_pd) (int task_id, pd_id_t *task_pd);
+
+ /* Return 1 if system-mode is supported, 0 otherwise. Warn if
+ some features are unsupported. */
+ int (*system_mode_support_p) (void);
+
+ /* Find the context id of the task currently being executed
+ by the system. This function assumes that the target is
+ currently running in system mode. */
+ WTX_CONTEXT_ID_T (*system_mode_get_current_context_id) (void);
+};
+
+extern void wtxapi_set_support_ops (struct wtxapi_support_ops *ops);
+
+extern void wtxapi_notify_connection_established (void);
+
+extern struct wtxapi_thread_info *wtxapi_get_thread_list (void);
+
+extern int wtxapi_get_task_pd (int task_id, pd_id_t *task_pd);
+
+extern int wtxapi_system_mode_support_p (void);
+
+extern WTX_CONTEXT_ID_T wtxapi_system_mode_get_current_context_id (void);
+
+extern int wtxapi_vx_fp_task ();
+
+extern int wtxapi_has_target_variant (const char *variant);
+#endif
--
1.7.0.4
^ permalink raw reply [flat|nested] 54+ messages in thread
* [PATCH 13/18] Add new "wtx" target.
2011-02-24 17:49 Add support for VxWorks 5.x, 6.x and 653 Joel Brobecker
` (10 preceding siblings ...)
2011-02-24 17:56 ` [PATCH 07/18] remote-wtxapi: The WTX API abstraction layer Joel Brobecker
@ 2011-02-24 17:57 ` Joel Brobecker
2011-02-25 16:15 ` Tom Tromey
2011-02-24 17:57 ` [PATCH 12/18] remote-wtx-hw: register fetch/store support Joel Brobecker
` (5 subsequent siblings)
17 siblings, 1 reply; 54+ messages in thread
From: Joel Brobecker @ 2011-02-24 17:57 UTC (permalink / raw)
To: gdb-patches; +Cc: Joel Brobecker
This adds the bulk of the support for VxWorks systems through a new
target: wtx.
gdb/ChangeLog:
* remote-wtx.h, remote-wtx.c: New files.
---
gdb/remote-wtx.c | 3278 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
gdb/remote-wtx.h | 25 +
2 files changed, 3303 insertions(+), 0 deletions(-)
create mode 100644 gdb/remote-wtx.c
create mode 100644 gdb/remote-wtx.h
diff --git a/gdb/remote-wtx.c b/gdb/remote-wtx.c
new file mode 100644
index 0000000..95b02ef
--- /dev/null
+++ b/gdb/remote-wtx.c
@@ -0,0 +1,3278 @@
+/* Support for the WTX protocol.
+
+ Copyright (C) 2007, 2008, 2009, 2010, 2011 Free Software Foundation,
+ Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#include "defs.h"
+#include "remote-wtx.h"
+#include "ada-lang.h"
+#include "language.h"
+#include "remote-wtxapi.h"
+#include "remote-wtx-opt.h"
+#include "remote-wtx-pd.h"
+#include "target.h"
+#include "exceptions.h"
+#include "symfile.h"
+#include "filenames.h"
+#include "command.h"
+#include "objfiles.h"
+#include "remote-wtx-utils.h"
+#include "remote-wtx-bp.h"
+#include "remote-wtx-tasks.h"
+#include "inferior.h"
+#include "gdbthread.h"
+#include "remote-wtx-hw.h"
+#include "regcache.h"
+#include "gdb_select.h"
+#include "observer.h"
+#include "gdbcmd.h"
+
+#include <signal.h>
+
+/* The target_ops vectors for the WTX protocol support.
+ There is one vector per mode of operation:
+ - Connected to the target server, but not attached;
+ - Attached to a task ("task" and "multi-tasks" modes);
+ - Attached to the system ("system" mode). */
+
+static struct target_ops wtx_ops;
+static struct target_ops wtx_task_mode_ops;
+static struct target_ops wtx_system_mode_ops;
+
+/* The directory name extracted from from the boot-line info.
+ This directory is initialized when we connect to the target server,
+ and will mosly be used to locate the boot image. */
+static char *kernel_directory = NULL;
+
+/* The PID of the task we are currently attached to. This is used
+ to identify the CTX_EXIT event of the task we are debugging from
+ the same event for other tasks. */
+static int attached_context_id = 0;
+
+/* Set to non-zero if we need to fake an "attach" event in the wait loop. */
+static int fake_attach_event = 0;
+
+/* Status of the inferior after an asynchronous interruption (attach,
+ to_stop...) It is used to determine whether to use the "cont" or
+ the "resume" request to resume the execution of the inferior. */
+static enum wtx_task_status inferior_status = WTX_TASK_STATUS_UNKNOWN;
+
+/* A variable that is set to non-zero when the inferior was stopped
+ by a watchpoint. Contains the address of the data being watched. */
+static CORE_ADDR watchpoint_data_address = 0;
+
+/* Some function advance declarations. */
+
+static void unload_module_symbols (const char *module_filename, int from_tty);
+static int wtx_context_alive (int context_id);
+
+/* Return non-zero if we are currently running in system-mode. */
+
+static int
+system_mode_p (void)
+{
+ return (target_shortname == wtx_system_mode_ops.to_shortname);
+}
+
+/* Build a ptid from the given TASK_ID. */
+
+static ptid_t
+context_id_to_ptid (WTX_CONTEXT_ID_T context_id)
+{
+ /* Build the ptid by using the CONTEXT_ID as the pid, and leave
+ the thread & lwp ids set to 0. However, in system mode, the
+ system context ID is -1, which would normally translate to
+ a ptid that GDB treats specially. So, for the system context id,
+ we use a special PID of 1. */
+ if (context_id == SYSTEM_CID)
+ return ptid_build (1, 0, 1);
+
+ return ptid_build (1, 0, context_id);
+}
+
+/* Return the task context ID of the given PTID. */
+
+static WTX_CONTEXT_ID_T
+ptid_get_context_id (ptid_t ptid)
+{
+ int tid = ptid_get_tid (ptid);
+
+ if (tid == 1)
+ /* This is the special PID we use in system mode for the system ptid
+ (see context_id_to_ptid above). Return the system context ID. */
+ return SYSTEM_CID;
+
+ return tid;
+}
+
+/* Record PTID as a new inferior. ATTACHED should be non-zero if
+ we just attached to this process, as oppposed to creating it. */
+
+static void
+wtx_add_inferior (ptid_t ptid, int attached)
+{
+ struct inferior *inf;
+
+ /* For now, we use a model where we only have one inferior at a time.
+ So we simply bind the inferior to the current inferior. */
+ inf = current_inferior ();
+ inferior_appeared (inf, ptid_get_pid (ptid));
+ inf->attach_flag = attached;
+
+ /* This inferior is also the main thread, so add it as a thread. Reset
+ thread list in order to clean up leftovers from previous attach/detach
+ operations. */
+ init_thread_list ();
+ add_thread_silent (ptid);
+}
+
+/* Add PTID to the thread list (if needed). */
+
+static void
+wtx_add_thread (ptid_t ptid)
+{
+ if (!in_thread_list (ptid))
+ add_thread (ptid);
+}
+
+/* Perform a WTX_CONTEXT_CONT operation for the given context type
+ and ID.
+
+ FIXME: brobecker/2007-07-06: This function is not completely
+ implemented yet. The handling of expected error situations
+ is still missing. See the vxworks-5.3 code, and in particular
+ the little tap-dance with current_wtx_operation, and its use
+ in errorHandler. For now, this function is basically a simple
+ wrapper around wtxapi_context_cont. */
+
+static int
+wtx_context_continue (WTX_CONTEXT_TYPE context_type,
+ WTX_CONTEXT_ID_T context_id)
+{
+ return wtxapi_context_cont (context_type, context_id);
+}
+
+/* Resume the execution of the inferior given its CONTEXT_TYPE and
+ CONTEXT_ID.
+
+ On 653, the system makes the distinction between the STOPPED state
+ which occurs after the thread has hit a breakpoint, and the SUSPEND
+ state, which happens after we attach to the system. As a result,
+ the debugger needs to use either the "cont" or "resume" WTX request
+ to resume the thread execution.
+
+ On Tornado 2, either request will work on all cases, because
+ the system only provides the SUSPEND mode. However, the documentation
+ explains that it is better to use the "cont" request for breakpoint
+ events on T2 as well. This is very convenient as the same code
+ can be shared for all Tornado versions. */
+
+static int
+continue_inferior (WTX_CONTEXT_TYPE context_type, WTX_CONTEXT_ID_T context_id)
+{
+ int result = 0;
+
+ switch (inferior_status)
+ {
+ case WTX_TASK_STATUS_CREATED:
+ result = wtxapi_context_resume (context_type, context_id);
+ break;
+ case WTX_TASK_STATUS_STOPPED:
+ if (multi_task_mode_is_on ())
+ result = continue_all_ada_tasks ();
+ else
+ result = wtx_context_continue (context_type, context_id);
+ break;
+ case WTX_TASK_STATUS_SUSPENDED:
+ if (multi_task_mode_is_on ())
+ result = continue_all_ada_tasks ();
+ else
+ result = wtxapi_context_resume (context_type, context_id);
+ break;
+ default:
+ result = wtxapi_context_resume (context_type, context_id);
+ break;
+ }
+
+ if (!result)
+ inferior_status = WTX_TASK_STATUS_UNKNOWN;
+ else
+ inferior_status = WTX_TASK_STATUS_RUNNING;
+ return result;
+}
+
+/* Perform a "suspend" operation on the inferior, given its
+ CONTEXT_TYPE and its CONTEXT_ID. inferior_status is updated
+ accordingly. */
+
+static int
+suspend_inferior (WTX_CONTEXT_TYPE context_type, WTX_CONTEXT_ID_T context_id)
+{
+ int result = wtxapi_context_suspend (context_type, context_id);
+ if (!result)
+ inferior_status = WTX_TASK_STATUS_UNKNOWN;
+ else
+ inferior_status = WTX_TASK_STATUS_SUSPENDED;
+ return result;
+}
+
+/* Perform a "stop" operation on the inferior, given its
+ CONTEXT_TYPE and its CONTEXT_ID. inferior_status is updated
+ accordingly. */
+
+static int
+stop_inferior (WTX_CONTEXT_TYPE context_type, WTX_CONTEXT_ID_T context_id)
+{
+ int result = wtxapi_context_stop (context_type, context_id);
+ if (!result)
+ inferior_status = WTX_TASK_STATUS_UNKNOWN;
+ else
+ inferior_status = WTX_TASK_STATUS_STOPPED;
+ return result;
+}
+
+/* A function that is meant to be used as the callback function for
+ bfd_map_over_sections, an whose purpose is to make a shallow
+ duplication of the array of sections for the given BFD object. */
+
+static void
+collect_bfd_sections (bfd *abfd, asection *sect, void *ptr)
+{
+ asection **sections = (asection **) ptr;
+
+ sections[sect->index] = sect;
+}
+
+/* Return nonzero if the the given section SECT is "loadable" (as indicated
+ by its section flags). Loadable here means either that the section is
+ loaded in memory, or that it triggers the creation of a memory region. */
+
+static int
+section_is_loadable (asection *sect)
+{
+ flagword flags = bfd_get_section_flags (NULL, sect);
+
+ return ((flags & SEC_ALLOC) || (flags & SEC_LOAD));
+}
+
+/* Remove any section entry in SECTION_ADDRS if the associated section
+ is not "loadable" (see section_is_loadable above). The removal is
+ performend in-pace, and SECTION_ADDRS->NUM_SECTIONS is adjusted to
+ reflect the new number of sections. */
+
+static void
+remove_non_loadable_sections (struct section_addr_info *section_addrs,
+ asection **bfd_sections)
+{
+ int i;
+ int new_num_sections = 0;
+
+ for (i = 0; i < section_addrs->num_sections; i++)
+ if (section_is_loadable (bfd_sections[section_addrs->other[i].sectindex]))
+ {
+ if (i != new_num_sections)
+ section_addrs->other[new_num_sections] = section_addrs->other[i];
+ new_num_sections++;
+ }
+ section_addrs->num_sections = new_num_sections;
+}
+
+/* Build the SECTION_ADDRS field of the give MODULE_INFO using
+ the module segment base addresses.
+
+ We compute the section addresses by:
+ 1. Getting the list of sections and their attribute from
+ the object file (using bfd)
+ 2. Iterate in order over each section and:
+ a. Determine to which segment it belongs
+ b. Compute its address as being just after the previous
+ section that lives in the same segment (modulo alignment)
+
+ This function assumes that MODULE_INFO->SEGMENTS is not NULL,
+ or will abort with a failed assertion. */
+
+static void
+build_module_info_section_addrs (struct wtxapi_module_info *module_info,
+ bfd *abfd)
+{
+ CORE_ADDR text_addr;
+ CORE_ADDR data_addr;
+ CORE_ADDR bss_addr;
+ int num_sections;
+ int i;
+ asection **bfd_sections;
+
+ gdb_assert (module_info->segments != NULL);
+
+ text_addr = module_info->segments->text_addr;
+ data_addr = module_info->segments->data_addr;
+ bss_addr = module_info->segments->bss_addr;
+
+ num_sections = bfd_count_sections (abfd);
+ module_info->section_addrs = alloc_section_addr_info (num_sections);
+
+ bfd_sections = (asection **) xzalloc (num_sections * sizeof (asection *));
+ bfd_map_over_sections (abfd, collect_bfd_sections, (void *) bfd_sections);
+
+ for (i = 0; i < num_sections; i++)
+ {
+ CORE_ADDR *addr_ptr = NULL;
+ asection *sect = bfd_sections[i];
+ flagword flags = bfd_get_section_flags (NULL, sect)
+ & (SEC_ALLOC | SEC_LOAD | SEC_READONLY | SEC_CODE | SEC_DATA);
+
+ switch (flags)
+ {
+ case (SEC_ALLOC | SEC_LOAD | SEC_READONLY | SEC_CODE): /* text */
+ case (SEC_ALLOC | SEC_LOAD | SEC_CODE): /* writable text */
+ addr_ptr = &text_addr;
+ break;
+
+ case (SEC_ALLOC | SEC_LOAD | SEC_READONLY | SEC_DATA): /* rodata */
+ if (strcmp (sect->name, ".rodata") == 0)
+ addr_ptr = &text_addr;
+ break;
+ case (SEC_ALLOC | SEC_LOAD | SEC_DATA): /* data */
+ addr_ptr = &data_addr;
+ break;
+
+ default:
+ if ((flags & SEC_ALLOC) && !(flags & SEC_LOAD)) /* bss */
+ addr_ptr = &bss_addr;
+ break;
+ }
+
+ if (addr_ptr != NULL)
+ {
+ module_info->section_addrs->other[i].addr =
+ align_power (*addr_ptr, bfd_get_section_alignment (abfd, sect));
+ *addr_ptr = module_info->section_addrs->other[i].addr
+ + bfd_section_size (abfd, sect);
+ }
+ module_info->section_addrs->other[i].name =
+ xstrdup (bfd_get_section_name (abfd, sect));
+ module_info->section_addrs->other[i].sectindex = sect->index;
+
+ /* FIMXE:brobecker/2007-05-18: On VxWorks systems, the offset
+ of each section of our object file seems to be set to zero.
+ This isn't a problem when we have one section per segment,
+ but it actually causes trouble when we have more than one
+ section per segment (eg when building with -ffunction-sections).
+ What happens in that case is that the relocation module thinks
+ that all these sections are located at the beginning of the
+ associated segment, and ends up computing wrong addresses.
+ This is particularly visible in the relocation of the debugging
+ info sections.
+
+ In my opinion, this is a linker issue. But we can cover
+ this issue by fixing up the section offsets, at least until
+ the linker is updated. As far as we know, this is only useful
+ for ".text.*" sections, we do the fixup only for these; it just
+ makes it easier because the base address for the offset is
+ always the text segment base address. */
+ if (sect->name != NULL
+ && strncmp (bfd_sections[i]->name, ".text.", 6) == 0)
+ bfd_set_section_vma
+ (abfd, sect,
+ module_info->section_addrs->other[i].addr
+ - module_info->segments->text_addr);
+ }
+
+ /* We only expect to find the sections that have been loaded in memory
+ in MODULE_INFO->SECTION_ADDRS, so remove any section which are not
+ loadable. It seemed easy enough at first to create the array without
+ those sections to start with. But, in practice, the BFD API made it
+ easier to do it this way. */
+ remove_non_loadable_sections (module_info->section_addrs, bfd_sections);
+
+ xfree (bfd_sections);
+}
+
+/* Read the symbols from the given MODULE_FILENAME, using the information
+ available in MODULE_INFO.
+
+ This function assumes that the current PD is equal to the module PD. */
+
+static int
+read_module_symbols_1 (struct wtxapi_module_info *module_info,
+ char *module_filename)
+{
+ struct gdb_exception e;
+
+
+ TRY_CATCH (e, RETURN_MASK_ERROR)
+ {
+ bfd *abfd = symfile_bfd_open (module_filename);
+
+ if (module_info->section_addrs == NULL)
+ build_module_info_section_addrs (module_info, abfd);
+
+ symbol_file_add_from_bfd (abfd, 0, module_info->section_addrs,
+ 0 /* flags */);
+ }
+ if (e.reason < 0)
+ {
+ printf_filtered (_("Unable to load symbols for module %s: %s\n"),
+ module_info->module_name, e.message);
+ return 0;
+ }
+
+ return 1;
+}
+
+/* Load the symbols from the given module (identified by its MODULE_ID).
+
+ This function handles the case when the module PD is different from
+ the current PD by temporarily switching to the module PD during
+ the symbol reading phase. */
+
+static void
+read_module_symbols (module_id_t module_id, int ignored_verbose)
+{
+ const pd_id_t current_pd = wtxapi_pd_current_get ();
+ const pd_id_t module_pd = wtx_pd_get_module_pd (module_id);
+ struct cleanup *old_chain = NULL;
+ struct wtxapi_module_info *module_info;
+ struct gdb_exception e;
+ char *module_filename;
+
+ if (module_pd != current_pd)
+ {
+ wtx_pd_switch_to_pd (module_pd);
+ old_chain = wtx_pd_make_switch_to_pd_cleanup (current_pd);
+ }
+
+ module_info = wtxapi_obj_module_info_get (module_pd, module_id);
+ if (module_info == NULL)
+ error (_("Cannot get info for module 0x%x: %s"),
+ (unsigned int) module_id, wtxapi_err_msg_get ());
+
+ printf_filtered ("\t%s: ", module_info->module_name);
+ gdb_flush (gdb_stdout);
+
+ /* The module name is a basename, not an absolute filename.
+ If this file is not present in the current directory, then
+ try to see if it is in the kernel_directory. */
+
+ module_filename = module_info->module_name;
+ if (!is_regular_file (module_filename) && kernel_directory != NULL)
+ {
+ char *filename = concat (kernel_directory, module_filename, NULL);
+
+ make_cleanup (xfree, filename);
+ if (is_regular_file (filename))
+ module_filename = filename;
+ }
+
+ /* Try reading the symbols from the given module. */
+ if (read_module_symbols_1 (module_info, module_filename))
+ printf_filtered (_("ok\n"));
+
+ free_wtxapi_module_info (module_info);
+ if (old_chain)
+ do_cleanups (old_chain);
+}
+
+/* Query the target about the list of modules currently loaded,
+ and load the symbols from each module. */
+
+static void
+read_symbols_from_all_modules (int from_tty)
+{
+ struct wtxapi_module_list *module_list;
+ int i;
+
+ if (from_tty)
+ printf_filtered (_("Looking for all loaded modules:\n"));
+
+ module_list = wtxapi_obj_module_list_get (WTX_MOD_FIND_IN_ALL_PD);
+ if (module_list == NULL)
+ error (_("Could not get target module list: %s"), wtxapi_err_msg_get ());
+
+ make_cleanup (cleanup_wtxapi_module_list, module_list);
+
+ for (i = 0; i < module_list->num_obj_mod; i++)
+ {
+ read_module_symbols (module_list->mod_id_array[i], from_tty);
+ QUIT;
+ }
+
+ if (from_tty)
+ printf_filtered (_("Done.\n"));
+
+ /* Now that we have some object files, GDB should recompute the gdbarch
+ vector using them. VxWorks does not really have a concept of "the"
+ executable, but we know that all the modules (aka objfiles) are on
+ the same target and are using the same architecture. So we just
+ pick the first objfile we have and use that to recompute the gdbarch
+ vector. */
+ if (object_files != NULL && object_files->obfd != NULL)
+ set_gdbarch_from_file (object_files->obfd);
+}
+
+/* Compute the name of the directory where the boot image was loaded
+ from.
+
+ When successful, save the result in KERNEL_DIRECTORY. When not
+ successful, then KERNEL_DIRECTORY is set to NULL. */
+
+static void
+cache_kernel_directory_name (void)
+{
+ const char *boot_line = wtxapi_target_bootline_get ();
+ char *separator;
+ char *basename = NULL;
+ char *tmp;
+
+ /* If kernel_directory was previous set, free it. We want to recompute it
+ each time, to make sure it's correct (we may have switched from
+ one board to the other, for instance). */
+ if (kernel_directory != NULL)
+ {
+ xfree (kernel_directory);
+ kernel_directory = NULL;
+ }
+
+ if (boot_line == NULL)
+ return; /* No boot-line information, so nothing much we can do. */
+
+ /* The format of the boot path follows the following syntax:
+ [<hostname> ":"]<kernel module full path> */
+
+ /* Skip the hostname if specified, being careful of not stripping
+ the drive letter on Windows hosts... */
+
+ separator = strchr (boot_line, ':');
+ if (separator != NULL
+ && !(have_dos_based_filesystem ()
+ && (separator - boot_line == 1)))
+ boot_line = separator + 1;
+
+ /* wtxapi_target_bootline_get returns a pointer into temporary memory,
+ so we need to duplicate kernel_directory for our own usage. */
+ kernel_directory = xstrdup (boot_line);
+
+ /* Strip the module name from the path.
+
+ Keep the trailing directory separator, as this directory will be
+ concatenated with filenames to form full paths. So no need to strip
+ it here only to add it back later. */
+
+ tmp = kernel_directory;
+ while (*tmp != '\0')
+ {
+ if (IS_DIR_SEPARATOR (*tmp))
+ basename = tmp + 1;
+ tmp++;
+ }
+
+ if (basename != NULL)
+ *basename = '\0';
+}
+
+/* Implement the to_open method of the target_ops structure
+ for the WTX protocol. */
+
+void
+wtx_open (char *args, int from_tty)
+{
+ char **argv = buildargv (args);
+ char *target_server_name;
+ WTX_AGENT_MODE_TYPE target_agent_mode;
+ struct gdb_exception ex;
+
+ make_cleanup_freeargv (argv);
+
+ if (argv[0] == NULL)
+ error (_("target name is missing"));
+ target_server_name = argv[0];
+
+ printf_filtered (_("Connecting to target server: %s...\n"),
+ target_server_name);
+ unpush_target (&wtx_ops);
+
+ if (!wtxapi_tool_attach (target_server_name, wtx_opt_tool_name ()))
+ error (_("Could not connect to target server."));
+
+ push_target (&wtx_ops);
+
+ TRY_CATCH (ex, RETURN_MASK_ERROR)
+ {
+ /* Make sure that we can communicate with the target server.
+ If the attempt failed and WTX reports that the target server
+ is not attached (target server locked by another user, server
+ is up but target rebooted, server is up but not attached to
+ the target agent, ...), then print a warning and try attaching
+ again. */
+ if (!wtxapi_target_server_available_p ()
+ && wtxapi_err_get () == WTX_ERR_SVR_TARGET_NOT_ATTACHED)
+ {
+ warning (_("target not attached to target server, reattaching..."));
+
+ if (!wtxapi_target_attach ())
+ error (_("Failed to attach to target: %s"), wtxapi_err_msg_get ());
+ }
+
+ /* Make sure that we can communicate with the target server now.
+ If all our previous attemps to connect properly failed, then
+ abort. */
+ if (!wtxapi_target_server_available_p ())
+ error (_("Connection to target server is not usable: %s."),
+ wtxapi_err_msg_get ());
+
+ target_agent_mode = wtxapi_agent_mode_get ();
+ if (target_agent_mode == invalid_agent_mode)
+ error (_("Could not get agent mode: %s"), wtxapi_err_msg_get ());
+
+ if (!wtxapi_register_for_event (".*"))
+ error (_("Could not register for target events: %s"),
+ wtxapi_err_msg_get ());
+
+ printf_filtered (_("Connected to %s\n"), wtxapi_ts_name_get ());
+
+ cache_kernel_directory_name ();
+ read_symbols_from_all_modules (from_tty);
+ ada_language_auto_set ();
+
+ wtx_hw_initialize ();
+ wtx_opt_init_task_options ();
+ wtxapi_notify_connection_established ();
+ }
+ if (ex.reason < 0)
+ {
+ printf_filtered ("%s\n", ex.message);
+ unpush_target (&wtx_ops);
+ }
+}
+
+/* Implement the to_close method of the target_ops for the WTX protocol. */
+
+static void
+wtx_close (int quitting)
+{
+ /* We don't need to remove all the breakpoints from the inferior,
+ because GDB is handling their insertion and removal for us. */
+
+ if (!wtxapi_tool_detach ())
+ warning (_("error detected while detaching from target (ignored): %s"),
+ wtxapi_err_msg_get ());
+}
+
+/* Implement the to_close method when in "task" mode. */
+
+static void
+wtx_task_mode_close (int quitting)
+{
+ /* Nothing to do. */
+}
+
+/* Implement the to_close method when in "system" mode. */
+
+static void
+wtx_system_mode_close (int quitting)
+{
+ /* Nothing to do. */
+}
+
+/* Attach to the "system". In other words, start debugging in
+ the target in system mode. */
+
+static void
+wtx_system_mode_attach (int from_tty)
+{
+ if (from_tty)
+ printf_filtered (_("Entering system-mode.\n"));
+
+ if (!wtxapi_system_mode_support_p ())
+ error (_("system-mode not supported."));
+
+ if (!wtxapi_agent_mode_set (WTX_AGENT_MODE_EXTERN))
+ error (_("Failed to enter system mode: %s"), wtxapi_err_msg_get ());
+
+ if (!suspend_inferior (WTX_CONTEXT_SYSTEM, SYSTEM_CID))
+ error (_("Failed to suspend system context: %s"), wtxapi_err_msg_get ());
+
+ push_target (&wtx_system_mode_ops);
+
+ inferior_ptid =
+ context_id_to_ptid (wtxapi_system_mode_get_current_context_id ());
+
+ /* If the user turned the multi-tasks-mode on, then warn the user that
+ we are turning it off now. This mode doesn't make sense in system
+ mode.
+
+ We could silently ignore the multi-task-mode user setting, but
+ it makes the code clearer to turn it off, because it allows us
+ to determine that if we are in multi-tasks mode iff the user
+ setting is non-zero (without having to check which mode (task-mode
+ vs system-mode we are using). */
+ if (multi_task_mode_is_on ())
+ {
+ warning (_("The multi-tasks mode can not be used in system mode.\n\
+multi-tasks mode turned off."));
+ turn_multi_task_mode_off ();
+ }
+}
+
+/* Register for exit notification for the given task ID. */
+
+static int
+register_for_exit_event (int context_id)
+{
+ evtpt_id_t evtpt_id;
+
+ evtpt_id = wtxapi_context_exit_notify_add (WTX_CONTEXT_TASK, context_id);
+ if (evtpt_id == invalid_evtpt_id)
+ return 0;
+
+ attached_context_id = context_id;
+ return 1;
+}
+
+/* If NAME is the name of a task currently running on the system,
+ return its ID. Return zero otherwize. */
+
+static int
+wtx_context_id_from_name (char *name)
+{
+ struct wtxapi_thread_info *threads = wtxapi_get_thread_list ();
+ struct wtxapi_thread_info *this_thread = threads;
+ int pid = 0;
+
+ while (this_thread != NULL)
+ {
+ if (strcmp (this_thread->name, name) == 0)
+ {
+ pid = this_thread->id;
+ break;
+ }
+ this_thread = this_thread->next;
+ }
+
+ free_wtxapi_thread_info (threads);
+ return pid;
+}
+
+/* Implement the "attach" method for the task mode. */
+
+static void
+wtx_task_mode_attach (char *args, int from_tty)
+{
+ int context_id;
+
+ /* Check to see if the argument was a task name. */
+
+ context_id = wtx_context_id_from_name (args);
+
+ /* If not a valid task name, then try parsing the argument as a task ID. */
+ if (context_id == 0)
+ context_id = parse_and_eval_address (args);
+
+ if (from_tty)
+ printf_filtered (_("Attaching to task %#x.\n"), context_id);
+
+ if (multi_task_mode_is_on ())
+ {
+ start_multi_task_mode ();
+ if (!stop_all_ada_tasks (&inferior_status))
+ error (_("Failed to stop task: %s"), wtxapi_err_msg_get ());
+ }
+ else
+ {
+ if (!stop_inferior (WTX_CONTEXT_TASK, context_id))
+ error (_("Failed to stop task: %s"), wtxapi_err_msg_get ());
+ }
+
+ push_target (&wtx_task_mode_ops);
+
+ wtx_pd_switch_to_task_pd (context_id);
+ inferior_ptid = context_id_to_ptid (context_id);
+
+ if (multi_task_mode_is_on ())
+ {
+ /* In multi-tasks mode, we want to receive the EXIT event
+ of the MAIN task, which is not necessarily the task that
+ we attached too. Otherwise, we'll end up reporting that
+ the program exited when in fact it was just one task that
+ exited. So get the main task context ID. */
+ struct ada_task_info *main_task = ada_get_environment_task ();
+
+ context_id = ptid_get_context_id (main_task->ptid);
+ }
+
+ if (!register_for_exit_event (context_id))
+ error (_("Failed to register exit event: %s"), wtxapi_err_msg_get ());
+
+}
+
+/* Implement the "to_attach" target_ops method. */
+
+static void
+wtx_attach (struct target_ops *ops, char *args, int from_tty)
+{
+ dont_repeat ();
+
+ if (args == NULL || args[0] == '\0')
+ error_no_arg ("task-id | task-name | system");
+
+ if (strcasecmp (args, "system") == 0)
+ wtx_system_mode_attach (from_tty);
+ else
+ wtx_task_mode_attach (args, from_tty);
+ wtx_add_inferior (inferior_ptid, 1);
+
+ /* GDB is expecting that attaching to the inferior will cause
+ some event to be generated (most likely a SIGTRAP). To purge
+ that event, GDB will soon call the to_wait target method.
+ Since VxWorks does not generate any event when suspending a task,
+ we need to inform our event loop that the next event-wait should
+ fake a SIGTRAP.
+
+ brobecker/2007-10-12: It is actually possible configure GDB
+ in a way that it will not expect that event, but it involves
+ the definition of the ATTACH_NO_WAIT macro, which we used
+ to do. But doing so deactivates as a side-effect the printing
+ of the current frame that tells the user where his program is.
+ Given that this macro is currently not multiarched either,
+ and only used by one target, it seems clear that it's preferable
+ to just fake the expected event. */
+ fake_attach_event = 1;
+}
+
+/* Implement the "detach" command for the tasks mode. */
+
+static void
+wtx_task_mode_detach (struct target_ops *ops, char *args, int from_tty)
+{
+ int success;
+ WTX_CONTEXT_ID_T context_id = ptid_get_context_id (inferior_ptid);
+
+ printf_filtered (_("Detaching from task 0x%lx...\n"), context_id);
+
+ /* Resume the execution of the inferior. */
+ success = continue_inferior (WTX_CONTEXT_TASK, context_id);
+ if (!success)
+ warning (_("Failed to resume task: %s"), wtxapi_err_msg_get ());
+
+ if (multi_task_mode_is_on ())
+ stop_multi_task_mode ();
+
+ /* And last, revert back to the basic WTX mode. */
+ pop_target ();
+}
+
+/* Implement the "detach" command for the system mode. */
+
+static void
+wtx_system_mode_detach (struct target_ops *ops, char *args, int from_tty)
+{
+ int success;
+
+ printf_filtered (_("Leaving system-mode...\n"));
+
+ /* switch back to task mode. Does this resume the target execution? */
+ success = wtxapi_agent_mode_set (WTX_AGENT_MODE_TASK);
+ if (!success)
+ warning (_("Operation failed, target may still be in EXTERN mode: %s"),
+ wtxapi_err_msg_get ());
+
+ pop_target ();
+}
+
+/* Perform a step operation in the given CONTEXT_ID & CONTEXT_TYPE.
+
+ Whether a single-instruction step of a multi-instruction step
+ is to be done is decided based on the value of the STEP_RANGE_START
+ and STEP_RANGE_END global variables. */
+
+static void
+step_inferior (WTX_CONTEXT_TYPE context_type, WTX_CONTEXT_ID_T context_id)
+{
+ struct thread_info *tp = find_thread_ptid (inferior_ptid);
+
+ gdb_assert (tp);
+
+ if (tp->control.step_range_end
+ && (tp->control.step_range_end > tp->control.step_range_start))
+ wtxapi_context_step (context_type, context_id,
+ tp->control.step_range_start,
+ tp->control.step_range_end);
+ else /* Step only exactly one instruction. */
+ wtxapi_context_step (context_type, context_id, 0, 0);
+ inferior_status = WTX_TASK_STATUS_UNKNOWN;
+}
+
+/* Implement the "to_resume" command in task mode. */
+
+static void
+wtx_task_mode_resume (struct target_ops *ops, ptid_t ptid, int step,
+ enum target_signal signo)
+{
+ WTX_CONTEXT_ID_T context_id;
+ struct thread_info *tp;
+
+ /* Find the context_id of the task to resume. If GDB wants to
+ step a specific task, then it will give us its ptid, but
+ otherwise, we should be resuming the inferior_ptid task. */
+ context_id = ptid_get_context_id (ptid);
+ if (ptid_equal (ptid, minus_one_ptid))
+ {
+ context_id = ptid_get_context_id (inferior_ptid);
+ tp = find_thread_ptid (inferior_ptid);
+ }
+ else
+ {
+ tp = find_thread_ptid (ptid);
+ }
+
+ gdb_assert (tp);
+
+ if (signo != 0 && signo != tp->suspend.stop_signal)
+ error (_("The WTX protocol does not support sending signals"));
+
+ /* Clear any WTX error status before resuming. */
+ wtxapi_err_clear ();
+
+ if (step)
+ step_inferior (WTX_CONTEXT_TASK, context_id);
+ else
+ continue_inferior (WTX_CONTEXT_TASK, context_id);
+
+ /* Make sure that all went well. */
+
+ if (wtxapi_err_get () != WTX_ERR_NONE)
+ error (_("wtx_task_mode_resume (step = %d, context_id = 0x%lx) failed: %s"),
+ step, context_id, wtxapi_err_msg_get ());
+}
+
+/* Implement the "to_resume" command in system mode. */
+
+static void
+wtx_system_mode_resume (struct target_ops *ops,
+ ptid_t ptid, int step, enum target_signal signo)
+{
+ const int resume_all = ptid_equal (ptid, minus_one_ptid);
+ const WTX_CONTEXT_ID_T context_id = ptid_get_context_id (ptid);
+ struct thread_info *tp = find_thread_ptid (ptid);
+
+ /* If GDB wants to step a specific task:
+ - its thread info should be valid (non null);
+ - it won't support sending signals to this specific task.
+
+ In the other case (resume whole system):
+ - the context_id will be 0;
+ - tp will not be valid.
+ */
+
+ gdb_assert (resume_all || tp);
+ if (!resume_all && signo != 0 && signo != tp->suspend.stop_signal)
+ error (_("The WTX protocol does not support sending signals"));
+
+ /* If the debugger asks for a specific task to be stepped, verify
+ that this task is in fact the current task. In system mode,
+ only this task can be stepped (or in other words, one cannot
+ switch to a different task, and step that task). In practice,
+ this is not a real limitation, since other task are usually
+ executing system calls for which there is little need for next/step
+ operations. */
+ if (step && !resume_all)
+ {
+ const WTX_CONTEXT_ID_T current_context_id =
+ wtxapi_system_mode_get_current_context_id ();
+
+ if (context_id != current_context_id)
+ error (_("task 0x%lx cannot be stepped"), context_id);
+ }
+
+ /* Clear any WTX error status before resuming. */
+ wtxapi_err_clear ();
+
+ if (step)
+ step_inferior (WTX_CONTEXT_SYSTEM, SYSTEM_CID);
+ else
+ continue_inferior (WTX_CONTEXT_SYSTEM, SYSTEM_CID);
+
+ /* Make sure that all went well. */
+
+ if (wtxapi_err_get () != WTX_ERR_NONE)
+ error (_("wtx_system_mode_resume (step = %d) failed: %s"),
+ step, wtxapi_err_msg_get ());
+}
+
+static int
+wtx_event_is_foreign (WTX_CONTEXT_ID_T context_id,
+ WTX_CONTEXT_TYPE context_type)
+{
+ /* In system mode, we are debugging the entire system, and we should
+ handle all events. */
+ if (system_mode_p ())
+ return 0;
+
+ /* In multi-tasks mode, we are debugging an application that has
+ more than one task, and we should logically only process the events
+ from one of these tasks. But because we restrict the user to one
+ debugger per partition when debugging in multi-tasks mode, we can
+ simplify this condition by simply verifying that the event was
+ triggered by a task running in the current partition. */
+ if (multi_task_mode_is_on ())
+ {
+ pd_id_t context_pd;
+ int success;
+
+ success = wtxapi_get_task_pd (context_id, &context_pd);
+ if (!success)
+ {
+ /* Probably a CTX_EXIT event from a task we're not watching,
+ maybe in a different partition. Treat as a foreign event. */
+ return 1;
+ }
+
+ return (context_pd != wtxapi_pd_current_get ());
+ }
+
+ /* In single-task mode, we should only handle events triggered
+ inside the task we are debugging. */
+ return (context_id != ptid_get_context_id (inferior_ptid));
+}
+
+/* Interrupt handling during event polling.
+
+ There are two parts involved in interrupt-handling:
+
+ 1. Stopping the inferior:
+ This part is performed by the SIGINT handler that we install
+ during the event queue polling loop.
+
+ 2. Telling GDB that the inferior stopped:
+ This part is handled by the target "wait" routine.
+ On most systems, the interruption performed in (1)
+ will result in an associated event that can be processed.
+ However, this is not the case with WTX, and so we must
+ maintain a global variable that will be set in the SIGINT
+ handler to notify the event polling loop to stop polling,
+ and let the wait routine fake a SIGINT event. */
+
+/* The old SIGINT handler that we save during the period when
+ it is replaced by our own SIGINT handler. */
+static void (*ofunc) (int);
+
+/* Set to non-zero if the inferior has been interrupted while
+ we were polling for events. */
+static int inferior_interrupted = 0;
+
+/* To be called when reiceiving a SIGINT signal while polling for
+ WTX events. This routine interrupts the inferior, and sets
+ TARGET_WAIT_INTERRUPTED to 1. */
+
+static void
+handle_target_wait_interrupt (int signo)
+{
+ target_stop (inferior_ptid);
+ inferior_interrupted = 1;
+}
+
+/* Setup the interrupt-handler to be used during the event polling
+ phase. As soon as we receive an event, the old handler should
+ be restored.
+
+ INFERIOR_INTERRUPTED is also set to zero. */
+
+static void
+set_target_wait_interrupt_handler (void)
+{
+ inferior_interrupted = 0;
+ ofunc = signal (SIGINT, handle_target_wait_interrupt);
+}
+
+/* Restore the old handler set by set_target_wait_interrupt_handler. */
+
+static void
+unset_target_wait_interrupt_handler (void)
+{
+ signal (SIGINT, ofunc);
+}
+
+/* Poll the WTX event queue for event.
+
+ This routine is blocking until either:
+ 1. We receive an event;
+ 2. Or the user requested that the inferior be interrupted.
+
+ In the first case, a non-NULL wtxapi_event_desc object will
+ be returned. In the second case, NULL is returned. */
+
+static struct wtxapi_event_desc *
+wtx_event_poll (void)
+{
+ /* An event that we fetched from the event queue the previous
+ time this function was called, but could not be processed
+ because the user interrupted the inferior at the same time. */
+ static struct wtxapi_event_desc *postponed_event = NULL;
+ struct wtxapi_event_desc *event_desc;
+
+ /* If there is a postponed event, then return it now. */
+ if (postponed_event != NULL)
+ {
+ event_desc = postponed_event;
+ postponed_event = NULL;
+ return event_desc;
+ }
+
+ set_target_wait_interrupt_handler ();
+
+ /* Wait either for the user to interrupt the inferior, or for
+ a WTX event. */
+ while (1)
+ {
+ struct timeval timeout;
+
+ event_desc = wtxapi_event_get ();
+
+ if (inferior_interrupted || event_desc != NULL)
+ break;
+
+ /* There was no event available on the queue. Wait 10ms before
+ each try to avoid eating up all the CPU. Note that we cannot
+ use usleep because it's not portable. */
+ timeout.tv_sec = 0;
+ timeout.tv_usec = 10000;
+ gdb_select (0, 0, 0, 0, &timeout);
+ }
+
+ unset_target_wait_interrupt_handler ();
+
+ if (inferior_interrupted && event_desc != NULL)
+ {
+ /* The user interrupted the inferior, but we also received
+ an event at the same time. Store that event for later
+ processing, and pretend we haven't received it yet. */
+ postponed_event = event_desc;
+ return NULL;
+ }
+
+ return event_desc;
+}
+
+/* Process a TEXT_ACCESS or DATA_ACCESS event triggered by the given
+ TASK_ID, and fill in STATUS appropriately. CONTEXT_ID and CONTEXT_TYPE
+ are the context id & type of the breakpoint that triggered this event.
+
+ This routines assumes that we have already verified that this event
+ was meant for us (ie is not a foreign event).
+
+ Return TASK_ID. */
+
+static int
+handle_access_event (WTX_CONTEXT_ID_T task_id,
+ WTX_CONTEXT_ID_T context_id,
+ WTX_CONTEXT_TYPE context_type,
+ struct target_waitstatus *status)
+{
+ /* Update the status. */
+ status->kind = TARGET_WAITKIND_STOPPED;
+ status->value.sig = TARGET_SIGNAL_TRAP;
+
+ /* When in system-mode, chances are the task_id will be equal to
+ SYSTEM_CID, but this is not precise enough for our needs: We are
+ interested in telling the user which task actually triggered
+ the event. This piece of information is actually not part of
+ the WTX event (at least not with VxWorks 5.5), but since the task
+ that triggered the event is necessarily the current task, we can
+ derive this piece of information from there. */
+ if (context_type == WTX_CONTEXT_SYSTEM)
+ task_id = wtxapi_system_mode_get_current_context_id ();
+
+ /* Switch to the task that triggered that event. */
+ inferior_ptid = context_id_to_ptid (task_id);
+
+ /* If the task is running in a different partition than the current one,
+ automatically switch to the task partition. */
+ wtx_pd_switch_to_task_pd (task_id);
+
+ return task_id;
+}
+
+/* Process the given context-exit EVENT, and fill in STATUS appropriately.
+
+ If the event was not meant for us (the task that exited is not the
+ one we're attached to), then ignore the event and return -1.
+ Otherwise, return the ID of the task that exited. */
+
+static int
+handle_ctx_exit_event (struct wtxapi_ctx_exit_event event,
+ struct target_waitstatus *status)
+{
+ /* If the task that exited is not the main task of our application,
+ then ignore this event. Otherwise, we end up reporting the completion
+ of our program prematurely. */
+ if (event.context_id != attached_context_id)
+ return -1;
+
+ status->kind = TARGET_WAITKIND_EXITED;
+ status->value.integer = event.exit_code;
+
+ return event.context_id;
+}
+
+/* Process the given data-access (watchpoint) EVENT, and fill in
+ STATUS appropriately.
+
+ If the event was not meant for us, then ignore the event and
+ return -1. */
+
+static int
+handle_data_access_event (struct wtxapi_data_access_event event,
+ struct target_waitstatus *status)
+{
+ int pid;
+
+ if (wtx_event_is_foreign (event.context_id, event.context_type))
+ return -1;
+
+ /* Record the location that triggered the watchpoint. */
+ watchpoint_data_address = event.data_addr;
+
+ return handle_access_event (event.task_id, event.context_id,
+ event.context_type, status);
+}
+
+/* Process the given exception EVENT, and fill in STATUS appropriately.
+
+ If the event was not meant for us, then ignore the event and
+ return -1. */
+
+static int
+handle_exception_event (struct wtxapi_exception_event event,
+ struct target_waitstatus *status)
+{
+ WTX_CONTEXT_ID_T context_id = event.context_id;
+
+ if (wtx_event_is_foreign (event.context_id, event.context_type))
+ return -1;
+
+ /* Similarly to when we handle access events in system mode,
+ we need to find the ID of the current task, because the
+ context_id returned by the event is equal to SYSTEM_CID
+ which is not precise enough. We want to tell the user
+ which task is currently executing and triggered that event. */
+ if (context_id == SYSTEM_CID)
+ context_id = wtxapi_system_mode_get_current_context_id ();
+
+ /* FIXME: brobecker/2007-08-31: The current event handling in GDB
+ doesn't really include support for exceptions. For now, treat
+ this as an "unknown signal". Later on, we might want to improve
+ a bit, and in particular display the exception value to the user. */
+ status->kind = TARGET_WAITKIND_STOPPED;
+ status->value.sig = TARGET_SIGNAL_UNKNOWN;
+
+ if (multi_task_mode_is_on ())
+ stop_all_ada_tasks (&inferior_status);
+
+ return context_id;
+}
+
+/* Process the given obj-loaded event by loading the symbols from
+ that new module. */
+
+static void
+handle_obj_loaded_event (struct wtxapi_obj_loaded_event event)
+{
+ printf_filtered ("New module on %s\n", wtxapi_ts_name_get ());
+
+ read_module_symbols (event.module_id, 0);
+}
+
+/* Process the given obj-unloaded event by unloading the symbols from
+ that old module. */
+
+static void
+handle_obj_unloaded_event (struct wtxapi_obj_unloaded_event event)
+{
+ printf_filtered ("Module unloaded on %s\n", wtxapi_ts_name_get ());
+
+ unload_module_symbols (event.module_filename, 0);
+}
+
+/* Process the given text-access (breakpoint) EVENT, and fill in
+ STATUS appropriately.
+
+ If the event was not meant for us, then ignore the event and
+ return -1. */
+
+static int
+handle_text_access_event (struct wtxapi_text_access_event event,
+ struct target_waitstatus *status)
+{
+ if (wtx_event_is_foreign (event.context_id, event.context_type))
+ return -1;
+
+ return handle_access_event (event.task_id, event.context_id,
+ event.context_type, status);
+}
+
+/* Process the given vio-write event. */
+
+static void
+handle_vio_write_event (struct wtxapi_vio_write_event event)
+{
+ /* The DATA field in EVENT contains the output that our inferior
+ just printed, so simply relay it to our standard output. */
+ printf_unfiltered ("%s", event.data);
+}
+
+/* Implement the "to_wait" target_ops method. */
+
+static ptid_t
+wtx_wait (struct target_ops *ops, ptid_t ptid,
+ struct target_waitstatus *status, int options)
+{
+ int event_context_id = -1;
+ int done_waiting = 0;
+
+ /* Reset the WATCHPOINT_DATA_ADDRESS value. Now that the system
+ has been restarted, the watchpoint address is no longer relevant. */
+ watchpoint_data_address = 0;
+
+ if (fake_attach_event)
+ {
+ fake_attach_event = 0;
+ status->kind = TARGET_WAITKIND_STOPPED;
+ status->value.sig = TARGET_SIGNAL_TRAP;
+
+ return inferior_ptid;
+ }
+
+ while (!done_waiting)
+ {
+ struct wtxapi_event_desc *event_desc = wtx_event_poll ();
+
+ if (event_desc == NULL)
+ {
+ /* The event polling was interrupted on user request. The target
+ has already been stopped by the interrupt handler, but there
+ will be no associated WTX event. So we just fake a SIGINT
+ event received from the current inferior. */
+ status->kind = TARGET_WAITKIND_STOPPED;
+ status->value.sig = TARGET_SIGNAL_INT;
+
+ return inferior_ptid;
+ }
+
+ switch (event_desc->event_type)
+ {
+ case WTX_EVENT_CTX_EXIT:
+ event_context_id =
+ handle_ctx_exit_event (event_desc->desc.ctx_exit, status);
+ if (event_context_id != -1)
+ done_waiting = 1;
+ break;
+
+ case WTX_EVENT_DATA_ACCESS:
+ event_context_id =
+ handle_data_access_event (event_desc->desc.data_access, status);
+ if (event_context_id != -1)
+ done_waiting = 1;
+ inferior_status = WTX_TASK_STATUS_STOPPED;
+ break;
+
+ case WTX_EVENT_EXCEPTION:
+ event_context_id =
+ handle_exception_event (event_desc->desc.exception, status);
+ if (event_context_id != -1)
+ done_waiting = 1;
+ inferior_status = WTX_TASK_STATUS_STOPPED;
+ break;
+
+ case WTX_EVENT_OBJ_LOADED:
+ handle_obj_loaded_event (event_desc->desc.obj_loaded);
+ break;
+
+ case WTX_EVENT_OBJ_UNLOADED:
+ handle_obj_unloaded_event (event_desc->desc.obj_unloaded);
+ break;
+
+ case WTX_EVENT_TEXT_ACCESS:
+ event_context_id =
+ handle_text_access_event (event_desc->desc.text_access, status);
+ if (event_context_id != -1)
+ done_waiting = 1;
+ inferior_status = WTX_TASK_STATUS_STOPPED;
+ break;
+
+ case WTX_EVENT_VIO_WRITE:
+ handle_vio_write_event (event_desc->desc.vio_write);
+ break;
+ }
+
+ free_wtxapi_event_desc (event_desc);
+ }
+
+ wtx_add_thread (context_id_to_ptid (event_context_id));
+ return context_id_to_ptid (event_context_id);
+}
+
+/* Fetch the value of one register identified by its register number. */
+
+static void
+wtx_fetch_one_register (struct regcache *regcache,
+ WTX_CONTEXT_TYPE context_type,
+ WTX_CONTEXT_ID_T context_id,
+ int regnum)
+{
+ struct gdbarch *gdbarch = get_regcache_arch (regcache);
+ int result;
+ gdb_byte *buf = alloca (register_size (gdbarch, regnum));
+
+ gdb_assert (regnum != -1);
+
+ memset (buf, 0, sizeof (buf));
+ result = wtx_hw_fetch_register (gdbarch, context_type, context_id,
+ regnum, buf);
+ if (result)
+ regcache_raw_supply (regcache, regnum, buf);
+}
+
+/* Fetch the register REGNUM using the given CONTEXT_TYPE and CONTEXT_ID. */
+
+static
+void
+wtx_fetch_registers (struct regcache *regcache,
+ WTX_CONTEXT_TYPE context_type,
+ WTX_CONTEXT_ID_T context_id,
+ int regnum)
+{
+ struct gdbarch *gdbarch = get_regcache_arch (regcache);
+ int total_regs = gdbarch_num_regs (gdbarch)
+ + gdbarch_num_pseudo_regs (gdbarch);
+ int i;
+
+ if (regnum != -1)
+ wtx_fetch_one_register (regcache, context_type, context_id, regnum);
+ else
+ for (i = 0; i < total_regs; i++)
+ wtx_fetch_one_register (regcache, context_type, context_id, i);
+}
+
+/* Implement the "to_fetch_registers" target_ops method when
+ in "task" or "multi-tasks" mode. */
+
+static void
+wtx_task_mode_fetch_registers (struct target_ops *ops,
+ struct regcache *regcache, int regnum)
+{
+ wtx_fetch_registers (regcache, WTX_CONTEXT_TASK,
+ ptid_get_context_id (inferior_ptid),
+ regnum);
+}
+
+/* Fetch the value of one register identified by its register number.
+
+ REGS_ADDR should be set to the address where the general purpose
+ registers are stored for the task we want to read the registers from.
+
+ FP_REGS_ADDR should be set to the address where the FP registers
+ are stored for the task we want to read the registers from.
+ If this address cannot be computed, then it should be set to zero.
+
+ This function should be called only when currently in system mode. */
+
+static void
+wtx_system_mode_fetch_one_register_in_memory (struct regcache *regcache,
+ CORE_ADDR regs_addr,
+ CORE_ADDR fp_regs_addr,
+ int regnum)
+{
+ struct gdbarch *gdbarch = get_regcache_arch (regcache);
+ int result;
+ gdb_byte *buf = alloca (register_size (gdbarch, regnum));
+ memset (buf, 0, sizeof (buf));
+
+ gdb_assert (regnum != -1);
+
+ result = wtx_hw_fetch_register_in_memory (gdbarch,
+ WTX_CONTEXT_SYSTEM, SYSTEM_CID,
+ regs_addr, fp_regs_addr, regnum,
+ buf);
+ if (result)
+ regcache_raw_supply (regcache, regnum, buf);
+}
+
+/* For the given context ID:
+ - Set REGS_ADDR to the address where the GP registers are stored.
+ - Set FP_REGS_ADDR to the address where the FP registers are stored.
+
+ Any address that could not be computed is set to zero. */
+
+static void
+wtx_get_context_register_block_addrs (WTX_CONTEXT_ID_T context_id,
+ CORE_ADDR *regs_addr,
+ CORE_ADDR *fp_regs_addr)
+{
+ struct wtxapi_thread_info *threads = wtxapi_get_thread_list ();
+ struct wtxapi_thread_info *this_thread = threads;
+
+ *regs_addr = 0;
+ *fp_regs_addr = 0;
+
+ while (this_thread != NULL)
+ {
+ if (this_thread->id == context_id)
+ {
+ *regs_addr = this_thread->regs_addr;
+ *fp_regs_addr = this_thread->fp_regs_addr;
+ break;
+ }
+ this_thread = this_thread->next;
+ }
+
+ free_wtxapi_thread_info (threads);
+}
+
+/* Implement the "to_fetch_registers" target_ops method when
+ in "system" mode. */
+
+static void
+wtx_system_mode_fetch_registers (struct target_ops *ops,
+ struct regcache *regcache, int regnum)
+{
+ const WTX_CONTEXT_ID_T current_system_context_id =
+ wtxapi_system_mode_get_current_context_id ();
+ const WTX_CONTEXT_ID_T gdb_context_id = ptid_get_context_id (inferior_ptid);
+ CORE_ADDR regs_addr;
+ CORE_ADDR fp_regs_addr;
+
+ if (gdb_context_id == SYSTEM_CID
+ || gdb_context_id == current_system_context_id)
+ {
+ wtx_fetch_registers (regcache, WTX_CONTEXT_SYSTEM, SYSTEM_CID, regnum);
+ return;
+ }
+
+ wtx_get_context_register_block_addrs (gdb_context_id, ®s_addr,
+ &fp_regs_addr);
+ gdb_assert (regs_addr != 0); /* But fp_regs_addr may be null. */
+
+ if (regnum != -1)
+ wtx_system_mode_fetch_one_register_in_memory (regcache, regs_addr,
+ fp_regs_addr, regnum);
+ else
+ {
+ struct gdbarch *gdbarch = get_regcache_arch (regcache);
+ const int total_regs = gdbarch_num_regs (gdbarch)
+ + gdbarch_num_pseudo_regs (gdbarch);
+ int i;
+
+ /* Implementation note: The code below causes a succession
+ of small memory reads, which we could optimize by making
+ one large memory read right from the start, and then fetching
+ the register from there. However, this complicates a bit
+ the implementation, so we'll stick to this simple approach
+ for now. The delay should not be noticeable. */
+ for (i = 0; i < total_regs; i++)
+ wtx_system_mode_fetch_one_register_in_memory (regcache, regs_addr,
+ fp_regs_addr, i);
+ }
+}
+
+/* Store the value of one register identified by its register number. */
+
+static void
+wtx_store_one_register (struct regcache *regcache,
+ WTX_CONTEXT_TYPE context_type,
+ WTX_CONTEXT_ID_T context_id,
+ int regnum)
+{
+ struct gdbarch *gdbarch = get_regcache_arch (regcache);
+ gdb_byte *buf = alloca (register_size (gdbarch, regnum));
+
+ regcache_raw_collect (regcache, regnum, buf);
+ wtx_hw_store_register (gdbarch, context_type, context_id, regnum, buf);
+}
+
+static void
+wtx_store_registers (struct regcache *regcache,
+ WTX_CONTEXT_TYPE context_type,
+ WTX_CONTEXT_ID_T context_id,
+ int regnum)
+{
+ struct gdbarch *gdbarch = get_regcache_arch (regcache);
+ int total_regs = gdbarch_num_regs (gdbarch)
+ + gdbarch_num_pseudo_regs (gdbarch);
+ int i;
+
+ if (regnum != -1)
+ wtx_store_one_register (regcache, context_type, context_id, regnum);
+ else
+ for (i = 0; i < total_regs; i++)
+ wtx_store_one_register (regcache, context_type, context_id, i);
+}
+
+/* Implement the "to_store_registers" target_ops method when
+ in "task" or "multi-tasks" mode. */
+
+static void
+wtx_task_mode_store_registers (struct target_ops *ops,
+ struct regcache *regcache, int regnum)
+{
+ wtx_store_registers (regcache, WTX_CONTEXT_TASK,
+ ptid_get_context_id (inferior_ptid),
+ regnum);
+}
+
+/* Store the value of one register identified by its register number.
+
+ REGS_ADDR should be set to the address where the general purpose
+ registers are stored for the task whose register is being written.
+
+ FP_REGS_ADDR should be set to the address where the FP registers
+ are stored for the task we want to read the registers from.
+ If this address cannot be computed, then it should be set to zero.
+
+ This function should be called only when currently in system mode. */
+
+static void
+wtx_system_mode_store_one_register_in_memory (struct regcache *regcache,
+ CORE_ADDR regs_addr,
+ CORE_ADDR fp_regs_addr,
+ int regnum)
+{
+ struct gdbarch *gdbarch = get_regcache_arch (regcache);
+ gdb_byte *buf = alloca (register_size (gdbarch, regnum));
+ memset (buf, 0, sizeof (buf));
+
+ regcache_raw_collect (regcache, regnum, buf);
+ wtx_hw_store_register_in_memory (gdbarch, WTX_CONTEXT_SYSTEM, SYSTEM_CID,
+ regs_addr, fp_regs_addr, regnum, buf);
+}
+
+/* Implement the "to_store_registers" target_ops method when
+ in "system" mode. */
+
+static void
+wtx_system_mode_store_registers (struct target_ops *ops,
+ struct regcache *regcache, int regnum)
+{
+ const WTX_CONTEXT_ID_T current_system_context_id =
+ wtxapi_system_mode_get_current_context_id ();
+ const WTX_CONTEXT_ID_T gdb_context_id = ptid_get_context_id (inferior_ptid);
+ CORE_ADDR regs_addr;
+ CORE_ADDR fp_regs_addr;
+
+ if (gdb_context_id == SYSTEM_CID
+ || gdb_context_id == current_system_context_id)
+ {
+ wtx_store_registers (regcache, WTX_CONTEXT_SYSTEM, SYSTEM_CID, regnum);
+ return;
+ }
+
+ wtx_get_context_register_block_addrs (gdb_context_id, ®s_addr,
+ &fp_regs_addr);
+ gdb_assert (regs_addr != 0); /* But fp_regs_addr may be null. */
+
+ if (regnum != -1)
+ wtx_system_mode_store_one_register_in_memory (regcache, regs_addr,
+ fp_regs_addr, regnum);
+ else
+ {
+ struct gdbarch *gdbarch = get_regcache_arch (regcache);
+ const int total_regs = gdbarch_num_regs (gdbarch)
+ + gdbarch_num_pseudo_regs (gdbarch);
+ int i;
+
+ /* Implementation note: The code below causes a succession
+ of small memory reads, which we could optimize by making
+ one large memory read right from the start, and then fetching
+ the register from there. However, this complicates a bit
+ the implementation, so we'll stick to this simple approach
+ for now. The delay should not be noticeable. */
+ for (i = 0; i < total_regs; i++)
+ wtx_system_mode_store_one_register_in_memory (regcache, regs_addr,
+ fp_regs_addr, i);
+ }
+}
+
+/* Implement the "to_store" method in the target_ops vector. */
+
+static void
+wtx_prepare_to_store (struct regcache *regcache)
+{
+ /* Nothing to do. */
+}
+
+/* If there are any undefined symbols referenced by MODULE_INFO,
+ then print a list containing the name of all such symbols. */
+
+static void
+print_undefined_symbols (struct wtxapi_module_info *module_info)
+{
+ if (module_info->undef_list == NULL)
+ return;
+ if (! go_to_first_element_in_wtxapi_sym_list (module_info->undef_list))
+ return;
+
+ printf_filtered ("\n");
+ warning (_("the module contains some undefined symbols:"));
+ do
+ {
+ char *symbol_name = current_wtxapi_symbol_name (module_info->undef_list);
+ printf_filtered ("\t%s\n", symbol_name);
+ xfree (symbol_name);
+ }
+ while (go_to_next_element_in_wtxapi_sym_list (module_info->undef_list));
+}
+
+/* Kill the task with the given CONTEXT_ID.
+ Print a warning if not successful. */
+
+static void
+wtx_kill_one_task (WTX_CONTEXT_ID_T context_id)
+{
+ const int success = wtxapi_context_kill (WTX_CONTEXT_TASK, context_id);
+
+ /* Print a warning if we failed to kill the target task.
+ Do not throw an error as the failure is not serious enough
+ that we would abort the kill command, especially since one
+ possible reason for failing is if someone alreayd killed
+ the task using a different tool. We just warn the user
+ and proceed as if the killing was successful. The user
+ can then investigate more precisely why it failed and
+ try killing his task manually if necessary. */
+ if (!success)
+ warning (_("Failed to kill task 0x%lx: %s"), context_id,
+ wtxapi_err_msg_get ());
+}
+
+/* Kill the task identified by TASK. */
+
+static void
+wtx_kill_one_task_from_task_info (struct ada_task_info *task)
+{
+ wtx_kill_one_task (ptid_get_context_id (task->ptid));
+}
+
+/* Assuming we are currently debugging in multi-tasks mode,
+ kill all the tasks of inferior. */
+
+static void
+wtx_kill_all_tasks (void)
+{
+ iterate_over_live_ada_tasks (wtx_kill_one_task_from_task_info);
+}
+
+/* Wait for the CTX_EXIT event which is generated by the target server
+ when we kill the inferior. Discard any other events that may be
+ received while waiting for that event.
+
+ The user pressing ctrl-c while waiting for that event will cause
+ the wait to be aborted. Normally, we expect the exit event to be
+ received immediately after the kill, so the user should never really
+ have the time to do that before the event is received. But in case
+ the event is not received for any reason, this allows the user to get
+ out of what could be an infinite loop. */
+
+static void
+wtx_wait_for_exit_event (void)
+{
+ while (1)
+ {
+ struct wtxapi_event_desc *event_desc = wtx_event_poll ();
+
+ if (event_desc == NULL) /* The user pressed Ctrl-c. */
+ return;
+
+ if (event_desc->event_type == WTX_EVENT_CTX_EXIT
+ && event_desc->desc.ctx_exit.context_id == attached_context_id)
+ {
+ free_wtxapi_event_desc (event_desc);
+ return;
+ }
+
+ /* Not the event we were waiting for. Free it, and wait for
+ the next event. */
+ free_wtxapi_event_desc (event_desc);
+ }
+}
+
+/* Implement the "to_kill" method in task mode. */
+
+static void
+wtx_task_mode_kill (struct target_ops *ops)
+{
+ if (ptid_equal (inferior_ptid, null_ptid))
+ {
+ /* brobecker/2007-09-28: Can this really ever happen?
+ Add a warning to help us catch any situation where this
+ actually does happen, and only then return. Eventually,
+ if we find that this has never happened after a few years,
+ then we can remove this entire block. */
+ warning (_("cannot find id of task to kill"));
+ return;
+ }
+
+ if (multi_task_mode_is_on ())
+ wtx_kill_all_tasks ();
+ else
+ wtx_kill_one_task (ptid_get_context_id (inferior_ptid));
+ wtx_wait_for_exit_event ();
+
+ target_mourn_inferior ();
+}
+
+/* Implement the "to_kill" target_ops method when in "system" mode.
+ In pratice, one cannot kill the system task without rebooting it.
+ WindRiver chose to provide that command as a way of rebooting the
+ target, but it really is not that useful. There are enough ways
+ to reboot a system already, no need to provide one extra in GDB.
+ So just tell the user that he cannot "kill" the system. */
+
+static void
+wtx_system_mode_kill (struct target_ops *ops)
+{
+ error (_("The system cannot be killed."));
+}
+
+/* Find a given module using its name and unload it from the target.
+ The module lookup uses the module basename to do the matching. */
+
+static void
+unload_module_from_target (const char *module_name)
+{
+ const char *base_name = lbasename (module_name);
+ const module_id_t module_id = wtxapi_obj_module_in_system_find_id (base_name);
+ pd_id_t module_pd;
+
+ if (module_id == invalid_module_id)
+ {
+ warning (_("could not find %s on target: %s"),
+ base_name, wtxapi_err_msg_get ());
+ return;
+ }
+
+ module_pd = wtx_pd_get_module_pd (module_id);
+
+ /* unload the object module */
+ if (!wtxapi_obj_module_unload (module_pd, module_id))
+ warning (_("could not unload %s from target: %s"),
+ base_name, wtxapi_err_msg_get ());
+
+}
+
+/* Implement the "unload" target_ops method. */
+
+static void
+wtx_unload (char *args, int from_tty)
+{
+ char **argv = buildargv (args);
+
+ if (argv == NULL)
+ error_no_arg (_("module name to unload"));
+ make_cleanup_freeargv (argv);
+
+ unload_module_from_target (argv[0]);
+ unload_module_symbols (argv[0], from_tty);
+}
+
+/* Implement the "load" command for the WTX protocol.
+
+ The usage is as follow:
+
+ load <filename> [remote filename]
+
+ where <filename> is the name of the module as seen from GDB,
+ and [remote filename] should the full path of module given to
+ the target server. */
+
+static void
+wtx_load (char *args, int from_tty)
+{
+ char **argv = buildargv (args);
+ char *module_name = NULL;
+ /* The name/path of the module as seen from the debugger. */
+ char *gdb_path = NULL;
+ /* Same thing but for the target server. */
+ char *target_server_path = NULL;
+ int fd;
+ struct wtxapi_module_info *module_info;
+ struct objfile *objfile;
+
+ dont_repeat ();
+
+ if (argv == NULL)
+ error_no_arg (_("filename of module to load"));
+ make_cleanup_freeargv (argv);
+
+ /* Process the command line arguments, and issue a warning
+ if too many arguments were specified (we know at this point
+ that there is at least one argument so we cannot have too few
+ arguments). */
+
+ module_name = argv[0];
+ target_server_path = argv[1];
+ if (argv[1] != NULL && argv[2] != NULL)
+ warning
+ (_("too many arguments (\"%s ...\"), extra arguments will be ignored"),
+ argv[2]);
+
+ /* Resolve the module_name into a full path name. This allows us
+ to make sure we can open this file for reading (to load the
+ symbols), but more importantly, this allows us to pass an absolute
+ path to the target server if the remote filename was not provided
+ in the load command (TARGET_SERVER_PATH is NULL). */
+
+ fd = openp (source_path, OPF_TRY_CWD_FIRST, module_name,
+ O_RDONLY, &gdb_path);
+ if (fd < 0)
+ error (_("Unable to load %s: %s"), module_name, strerror (errno));
+ close (fd);
+
+ /* If the optional [remote filename] argument was not specified, then
+ use the full path of the module name. */
+
+ if (target_server_path == NULL)
+ target_server_path = gdb_path;
+
+ /* Scan the list of object files; if the module has already been
+ loaded, then unload it first. At reload, the symbols loaded
+ previously are discarded by the target server; so they should
+ also be discarded by the debugger. */
+
+ for (objfile = object_files; objfile; objfile = objfile->next)
+ {
+ if (strcmp (objfile->name, gdb_path) == 0)
+ {
+ wtx_unload (module_name, 0);
+ break;
+ }
+ }
+
+ /* Temporarily switch the timeout value to the load timeout, and
+ attempt to load the module on the board. Error out if we failed. */
+
+ printf_filtered (_("Downloading %s..."), target_server_path);
+ module_info = wtxapi_module_load (wtxapi_pd_current_get (),
+ target_server_path,
+ WTX_LOAD_GLOBAL_SYMBOLS,
+ wtx_opt_load_timeout () * 1000);
+ if (module_info == NULL)
+ error (_("Failed to load module %s: %s"), target_server_path,
+ wtxapi_err_msg_get ());
+
+ print_undefined_symbols (module_info);
+ printf_filtered (_("done.\n"));
+
+ /* Load the module symbols. */
+ read_module_symbols_1 (module_info, gdb_path);
+ ada_language_auto_set ();
+}
+
+/* Implement the "to_create_inferior" target method.
+
+ Implementation Note:
+ We must get the address of the entry point directly from the target,
+ as opposed to from doing a local symbol lookups. This is necessary
+ in order to avoid using an incorrect address if some of our objfiles
+ are not up to date. This can happen for instance in the following
+ scenario:
+ - from GDB: load [app], run [app]
+ - from Windsh: unld "[app]", ld < [app]
+ - from GDB: run [app]
+ What would happen is that GDB would use an obsolete objfile (the
+ one from the previous run) to compute the address of the entry
+ point, thus leading to catastrophic errors...
+
+ Note that it is technically possible to load 2 modules on
+ the target with the same entry point. In this case, it is not
+ clear what would happen. Right now, we just assume that this
+ not going to happen. Anybody trying to do that would just be
+ shooting themselves in the foot... */
+
+static void
+wtx_create_inferior (struct target_ops *ops, char *exec_file, char *args,
+ char **env, int from_tty)
+{
+ struct wtxapi_context_desc context_desc;
+ struct cleanup *old_chain = NULL;
+ char **argv;
+ char *entry_name;
+ int new_context_id;
+
+ memset (&context_desc, 0, sizeof (context_desc));
+
+ /* Parse the arguments. */
+
+ argv = buildargv (args);
+ if (argv == NULL)
+ nomem (0);
+ old_chain = make_cleanup_freeargv (argv);
+
+ /* Get the name of the entry point, which is the first argument. */
+ entry_name = argv[0];
+ if (entry_name == NULL || entry_name[0] == '\0')
+ error_no_arg (_("module entry point"));
+
+ /* FIXME: brobecker/2007-09-26: Add handling of the arguments...
+ For now, pretend there are none. */
+
+ TASK_CONTEXT_ARGC (context_desc) = 0;
+
+ /* Now, fill-in the rest of the CONTEXT_DESC structure. */
+ remote_wtxapi_get_symbol_address
+ (entry_name, &TASK_CONTEXT_ENTRY (context_desc));
+ if (TASK_CONTEXT_ENTRY (context_desc) == 0)
+ error (_("Failed to lookup entry point address"));
+ TASK_CONTEXT_NAME (context_desc) = "tDbgTask";
+ TASK_CONTEXT_CONTEXT_TYPE (context_desc) = WTX_CONTEXT_TASK;
+ TASK_CONTEXT_STACK_SIZE (context_desc) = wtx_opt_stack_size ();
+ TASK_CONTEXT_OPTIONS (context_desc) = wtx_opt_task_options ();
+ TASK_CONTEXT_PRIORITY (context_desc) = wtx_opt_task_priority ();
+ TASK_CONTEXT_PDID (context_desc) = wtxapi_pd_current_get ();
+
+ /* New create a new context for that task. */
+ new_context_id = wtxapi_context_create (&context_desc);
+ if (new_context_id == invalid_context_id)
+ error (_("failed to create task: %s"), wtxapi_err_msg_get ());
+
+ /* FIXME: brobecker/2007-09-26: Perform I/O redirection if necessary. */
+
+ inferior_ptid = context_id_to_ptid (new_context_id);
+ wtx_add_inferior (inferior_ptid, 0);
+ push_target (&wtx_task_mode_ops);
+ register_for_exit_event (new_context_id);
+ inferior_status = WTX_TASK_STATUS_CREATED;
+
+ if (multi_task_mode_is_on ())
+ start_multi_task_mode ();
+
+ /* Do our cleanup actions. */
+ do_cleanups (old_chain);
+}
+
+/* Return True if a module which name is equal to module_name is loaded
+ on the target. */
+
+static int
+module_is_loaded_on_target (const char *module_name)
+{
+ module_id_t module_id;
+
+ module_id = wtxapi_obj_module_in_system_find_id (module_name);
+ return (module_id != invalid_module_id);
+}
+
+/* Search the global object_files list for the objfile associated to
+ the module whose name is BASE_NAME, and free it. */
+
+static void
+free_module_objfile (const char *base_name)
+{
+ struct objfile *objfile;
+ struct objfile *temp;
+
+ /* search for matching objfile known to gdb, and free it */
+ ALL_OBJFILES_SAFE (objfile, temp)
+ {
+ if (!strcmp (lbasename (objfile->name), base_name))
+ {
+ const pd_id_t current_pd = wtxapi_pd_current_get ();
+
+ /* Print a message notifying the user that a module has been
+ unloaded. If the target also supports PDs, then print the
+ PD id and name from which the module has been unloaded. */
+ if (wtx_pd_system_has_pds ())
+ {
+ char *current_pd_name = wtx_pd_get_pd_name (current_pd);
+ printf_filtered (_("Unloaded file %s from PD 0x%lx (%s)\n"),
+ objfile->name, current_pd, current_pd_name);
+ xfree (current_pd_name);
+ }
+ else
+ printf_filtered (_("Unloaded file %s\n"), objfile->name);
+ free_objfile (objfile);
+ return;
+ }
+ }
+ warning (_("could not unload module %s from gdb"), base_name);
+}
+
+/* Given the name of a module that has just been unloaded from
+ the target, discard all the symbols associated to that module. */
+
+static void
+unload_module_symbols (const char *module_filename, int from_tty)
+{
+ const pd_id_t current_pd = wtxapi_pd_current_get ();
+ const char *module_name = lbasename (module_filename);
+ pd_id_t module_pd;
+ struct cleanup *old_chain = NULL;
+
+ /* Ignore this request if it comes from a WTX_EVENT_OBJ_UNLOADED event
+ and the object has been loaded back on the target. We can safely
+ ignore this event because either:
+ - it has been reloaded from this debugger, in which case we
+ already updated our objfile
+ - it has been reloaded from another client (eg windsh), in
+ which case there is necessarily a pending WTX_EVENT_OBJ_LOADED
+ event, which will cause us to update our objfile.
+
+ Not ignoring this event is causing the debugger to destroy the
+ associated objfile in scenarios like this:
+ 1/ from GDB: load <program>
+ (causes GDB to create an associated objfile)
+ 2/ from Windsh: unload <program>
+ 3/ from GDB: load <program>
+ (GDB correctly recreates the associated objfile)
+ 4/ from GDB: run <program>
+ (causes GDB to process the "unloaded" wtx event from step 2,
+ hence destroying our good objfile) */
+ if (!from_tty && module_is_loaded_on_target (module_name))
+ return;
+
+ module_pd = wtx_pd_get_unloaded_module_pd (module_name);
+ if (module_pd != current_pd)
+ {
+ wtx_pd_switch_to_pd (module_pd);
+ old_chain = wtx_pd_make_switch_to_pd_cleanup (current_pd);
+ }
+
+ free_module_objfile (module_name);
+
+ if (old_chain != NULL)
+ do_cleanups (old_chain);
+}
+
+/* Implements the to_xfer_partial method of the target vector for WTX. */
+
+static LONGEST
+wtx_xfer_partial (struct target_ops *ops, enum target_object object,
+ const char *annex, gdb_byte *readbuf,
+ const gdb_byte *writebuf, ULONGEST offset, LONGEST len)
+{
+ int status;
+
+ /* The only object transfer that we support at this moment is memory
+ read/write. */
+ if (object != TARGET_OBJECT_MEMORY)
+ return -1;
+
+ if (readbuf != NULL)
+ status = wtxapi_mem_read (wtxapi_pd_current_get (), offset, readbuf, len);
+ else
+ status = wtxapi_mem_write (wtxapi_pd_current_get (),
+ (gdb_byte *) writebuf, offset, len);
+
+ if (status == WTX_ERROR)
+ return 0; /* No further transfer possible??? */
+
+ return status;
+}
+
+/* Handling of eventpoint IDs.
+
+ VxWorks provides eventpoints for breakpoints and watchpoints. For each
+ inserted breakpoint, the target server returns an evenpoint ID that we
+ need to record, because we will need this ID to remove this breakpoint.
+
+ We store that information as private data in the breakpoint location's
+ target_info. */
+
+struct eventpoint_info
+{
+ evtpt_id_t id;
+ WTX_CONTEXT_TYPE context_type;
+ WTX_CONTEXT_ID_T context_id;
+};
+
+/* Insert a breakpoint eventpoint using the information provided.
+ Return a non-zero errno code when the insertion failed. */
+
+static int
+wtx_insert_breakpoint_1 (struct bp_target_info *target_info,
+ WTX_CONTEXT_TYPE context_type,
+ WTX_CONTEXT_ID_T context_id,
+ WTX_ACTION_TYPE action_type,
+ CORE_ADDR call_rtn)
+{
+ struct wtxapi_evtpt evtpt;
+ evtpt_id_t evtpt_id;
+ struct eventpoint_info *evtpt_info;
+
+ evtpt.context.context_type = context_type;
+ evtpt.context.context_id = context_id;
+ evtpt.action.action_type = action_type | WTX_ACTION_NOTIFY;
+ evtpt.event.event_type = WTX_EVENT_TEXT_ACCESS;
+ evtpt.event.num_args = 1;
+ evtpt.event.args = &target_info->placed_address;
+
+ if (call_rtn != 0)
+ evtpt.action.call_rtn = call_rtn;
+
+ evtpt_id = wtxapi_eventpoint_add (&evtpt);
+ wtx_opt_breakpoints_debug
+ ("wtxapi_eventpoint_add (context_type = 0x%x, context_id = 0x%lx, "
+ "address = 0x%s, target_info = 0x%s) -> 0x%x",
+ context_type, context_id,
+ paddress (target_gdbarch, target_info->placed_address),
+ host_address_to_string (target_info), evtpt_id);
+
+ if (evtpt_id == invalid_evtpt_id)
+ return ENOMEM;
+
+ /* Save the eventpoint info. We will use it later when removing
+ the breakpoint. */
+ evtpt_info = xmalloc (sizeof (struct eventpoint_info));
+ evtpt_info->id = evtpt_id;
+ evtpt_info->context_type = context_type;
+ evtpt_info->context_id = context_id;
+ target_info->target_private_data = evtpt_info;
+
+ return 0;
+}
+
+/* Insert a task-mode breakpoint at the location specified by
+ TARGET_INFO. TARGET_INFO is also used to determine what
+ scope & action to use for that breakpoint.
+
+ Return a non-zero errno code if the insertion failed. */
+
+static int
+wtx_insert_task_mode_breakpoint (struct gdbarch *gdbarch,
+ struct bp_target_info *target_info)
+{
+ const enum wtx_breakpoint_action action = get_break_command_action ();
+ WTX_CONTEXT_TYPE context_type;
+ WTX_CONTEXT_ID_T context_id;
+ WTX_ACTION_TYPE action_type;
+ CORE_ADDR call_rtn = 0;
+
+ context_type = WTX_CONTEXT_TASK;
+ context_id = ptid_get_context_id (inferior_ptid);
+
+ switch (action)
+ {
+ case action_task:
+ action_type = WTX_ACTION_STOP;
+ break;
+
+ case action_all:
+ action_type = WTX_ACTION_STOP_ALL;
+ break;
+
+ case action_call:
+ context_type = WTX_CONTEXT_ANY_TASK;
+ action_type = WTX_ACTION_STOP;
+ call_rtn = get_break_command_call_rtn ();
+ if (call_rtn != 0)
+ action_type |= WTX_ACTION_CALL;
+ break;
+
+ default:
+ internal_error (__FILE__, __LINE__, _("Unexpected action value: %d"),
+ action);
+ }
+
+ return wtx_insert_breakpoint_1 (target_info, context_type, context_id,
+ action_type, call_rtn);
+}
+
+/* On systems that support partitions, we need to record for each
+ breakpoint/watchpoint the associated partition ID, which is
+ the current partition at the time when the breakpoint was
+ created.
+
+ We achieve this by using a couple of observers, one that will
+ notify us of the creation of new breakpoints, and one that will
+ notify us of their destruction. They allow us to maintain a list
+ of (breakpoint, pd) elements that will later allow us to find
+ the PD associated to any breakpoint.
+
+ This is actually only useful when debugging in system mode, because
+ this is the only mode where we debug more than one partition.
+ However, we still need to maintain this information at all times,
+ because the user may be setting breakpoints while not in system
+ mode.
+
+ brobecker/2007-10-26: This is probably not going to be the final
+ implementation for this concept. For instance, it would probably
+ be nicer to have this information embedded directly inside the
+ breakpoint structure as a target-dependent data (like we do in
+ the gdbarch for instance), and avoid the need for the parallel
+ list that we're maintaining.
+
+ brobecker/2007-10-26: Another issue: When we insert breakpoints,
+ we are given a pointer to the target_info data. Not the bp_location.
+ Having the bp_location would allow us to directly find the associated
+ breakpoint, and from there its partition.
+
+ But all this needs to be discussed with the rest of the maintainers.
+ In the meantime, we're trying to make this change as contained as
+ possible. */
+
+struct bp_partition_info
+{
+ struct breakpoint *b;
+ WTX_CONTEXT_ID_T partition_id;
+
+ struct bp_partition_info *next;
+};
+
+static struct bp_partition_info *bp_partition_list = NULL;
+
+/* Add the breakpoint/context-id pair to BP_PARTITION_LIST. */
+
+static void
+add_bp_partition_info (struct breakpoint *b, WTX_CONTEXT_ID_T partition_id)
+{
+ struct bp_partition_info *info = xmalloc (sizeof (struct bp_partition_info));
+
+ info->b = b;
+ info->partition_id = partition_id;
+ info->next = bp_partition_list;
+
+ bp_partition_list = info;
+}
+
+/* Delete the element in BP_PARTITION_LIST corresponding to the given
+ breakpoint. */
+
+static void
+delete_bp_partition_info (struct breakpoint *b)
+{
+ struct bp_partition_info *prev = NULL;
+ struct bp_partition_info *this = bp_partition_list;
+
+ while (this != NULL && this->b != b)
+ {
+ prev = this;
+ this = this->next;
+ }
+
+ if (this == NULL)
+ return;
+
+ if (this == bp_partition_list)
+ bp_partition_list = bp_partition_list->next;
+ else
+ prev->next = this->next;
+
+ xfree (this);
+}
+
+/* Find the breakpoint associated to the given TARGET_INFO and
+ return its corresponding partition ID. */
+
+static WTX_CONTEXT_ID_T
+wtx_partition_id_from_target_info (struct bp_target_info *target_info)
+{
+ struct breakpoint *bp;
+
+ /* Shortcut: If the target system does not support more than one partition,
+ then we know which partition this breakpoint belongs to. */
+ if (!wtx_pd_system_has_pds ())
+ return wtxapi_pd_current_get ();
+
+ /* FIXME: We do not support partition switching just yet. So,
+ the breakpoint is necessarily in the current partition. */
+ return wtxapi_pd_current_get ();
+}
+
+/* Observer for the "breakpoint_created" event. */
+
+static void
+wtx_breakpoint_created_observer (int bpnum)
+{
+ /* FIXME: The observer only passes the bpnum, which forces us
+ to do a reverse search for the associated breakpoint structure.
+ It is silly to have to do so when the observer had in fact
+ the breakpoint structure and had to dereference it in order to
+ pass the bpnum. Propose that the observer be enhanced when
+ submitting this code to the FSF. */
+ struct breakpoint *b = get_breakpoint (bpnum);
+
+ gdb_assert (b != NULL);
+ add_bp_partition_info (b, wtxapi_pd_current_get ());
+}
+
+/* Observer for the "delete_breakpoint" event. */
+
+static void
+wtx_delete_breakpoint_observer (int bpnum)
+{
+ struct breakpoint *b = get_breakpoint (bpnum);
+
+ gdb_assert (b != NULL);
+ delete_bp_partition_info (b);
+}
+
+/* Insert a system-mode breakpoint at the location specified by TARGET_INFO.
+ Return a non-zero errno code if the insertion failed. */
+
+static int
+wtx_insert_system_mode_breakpoint (struct gdbarch *gdbarch,
+ struct bp_target_info *target_info)
+{
+ const WTX_CONTEXT_ID_T breakpoint_pd
+ = wtx_partition_id_from_target_info (target_info);
+
+ return wtx_insert_breakpoint_1 (target_info,
+ WTX_CONTEXT_SYSTEM, /* context_type */
+ breakpoint_pd, /* context_id */
+ WTX_ACTION_STOP, /* action_type */
+ 0); /* call_rtn */
+}
+
+/* Implement the "to_remove_breakpoint" method in the target_ops vector. */
+
+static int
+wtx_remove_breakpoint (struct gdbarch *gdbarch,
+ struct bp_target_info *target_info)
+{
+ struct eventpoint_info *evtpt_info = target_info->target_private_data;
+ evtpt_id_t evtpt_id;
+ WTX_CONTEXT_TYPE context_type;
+ WTX_CONTEXT_ID_T context_id;
+
+ if (evtpt_info == NULL)
+ {
+ /* This is really an internal error, but the user might be able
+ to continue debugging normally if the user is luckly (if his
+ code does not hit the breakpoint). So just report a warning
+ instead of an internal error. */
+ warning (_("Cannot find eventpoint info for breakpoint at 0x%lx"),
+ target_info->placed_address);
+ return EINVAL;
+ }
+
+ /* Free the target_info private data now, after having made a copy
+ of its contents for our use here. It's easier to do it that way,
+ rather than avoiding the copies, because of the multiple returns
+ used in this routine (we would have to be careful to xfree it before
+ each and every return). */
+ evtpt_id = evtpt_info->id;
+ context_type = evtpt_info->context_type;
+ context_id = evtpt_info->context_id;
+ xfree (target_info->target_private_data);
+ target_info->target_private_data = NULL;
+
+ if (evtpt_id == invalid_evtpt_id)
+ {
+ warning (_("Cannot find eventpoint ID for breakpoint at 0x%lx"),
+ target_info->placed_address);
+ return EINVAL;
+ }
+
+ wtx_opt_breakpoints_debug
+ ("wtx_remove_breakpoint (target_info = 0x%s) -> "
+ "evtpt_id = 0x%x, context_type = 0x%x, context_id = 0x%lx",
+ host_address_to_string (target_info), evtpt_id,
+ context_type, context_id);
+
+ if (!wtxapi_eventpoint_delete (evtpt_id))
+ {
+ /* If this eventpoint is a task-specific eventpoint, and if the
+ corresponding task is dead, then this eventpoint has already
+ been deleted. In this case, the error returned by
+ wtxapi_eventpoint_delete is expected. Ignore it. */
+ if (context_type == WTX_CONTEXT_TASK
+ && !wtx_context_alive (context_id))
+ return 0;
+
+ warning (_("Failed to delete eventpoint for breakpoint at 0x%lx"),
+ target_info->placed_address);
+ return EINVAL;
+ }
+
+ return 0;
+}
+
+/* Implement the target_can_use_hw_breakpoint target method for
+ the targets that support BoDA events. */
+
+static int
+can_use_BoDA_breakpoint (int bp_type, int count, int other_type)
+{
+ /* BoDA events provide all types of watchpoints, read, write, access,
+ so it's not necessary to check BP_TYPE. */
+
+ /* The system only provides one BoDA event. */
+ if (count < 2)
+ return 1;
+
+ /* All the conditions to use a hardware watchpoint are not met, so
+ we cannot use one. */
+ return 0;
+}
+
+/* Implement the target_can_use_hw_breakpoint target method for
+ the targets where we use data-access events to implement watchpoints. */
+
+static int
+can_use_data_access_breakpoint (int bp_type, int count, int other_type)
+{
+ /* Data-access events provide all types of watchpoints, read, write,
+ access, so it's not necessary to check BP_TYPE. */
+
+ /* The system only provides one data-access event. */
+ if (count < 2)
+ return 1;
+
+ /* All the conditions to use a hardware watchpoint are not met, so
+ we cannot use one. */
+ return 0;
+}
+
+/* Implement the target_can_use_hw_breakpoint target method for all WTX
+ targets. */
+
+static int
+wtx_can_use_hw_breakpoint (int bp_type, int count, int other_type)
+{
+ /* Tornado systems provide at most one hardware watchpoint,
+ so if another type of watchpoint is already being used,
+ then we have no hardware watchpoint left. Return -1 to
+ signal that the rejection is because of OTHER_TYPE. */
+ if (other_type)
+ return -1;
+
+ if (wtxapi_target_has_BoDA ())
+ return can_use_BoDA_breakpoint (bp_type, count, other_type);
+
+ /* On targets that do not support BoDA, we have access to
+ data-access events. Try using that as a fallback. */
+ if (can_use_data_access_breakpoint (bp_type, count, other_type))
+ return 1;
+
+ /* The system cannot provide hardware watchpoint support for this case. */
+ return 0;
+}
+
+/* Return non-zero if we just stopped after hitting a watchpoint. */
+
+static int
+wtx_stopped_by_watchpoint (void)
+{
+ int result = (watchpoint_data_address != 0);
+
+ wtx_opt_watchpoints_debug ("wtx_stopped_by_watchpoint() -> %d", result);
+
+ return result;
+}
+
+/* Return the address monitored by the watchpoint we just hit. */
+
+static int
+wtx_stopped_data_address (struct target_ops *target, CORE_ADDR *addr_p)
+{
+ const int success = wtx_stopped_by_watchpoint ();
+
+ if (wtx_stopped_by_watchpoint ())
+ {
+ *addr_p = watchpoint_data_address;
+ wtx_opt_watchpoints_debug ("wtx_stopped_data_address(0x%s) -> 1",
+ paddress (target_gdbarch, *addr_p));
+ return 1;
+ }
+
+ wtx_opt_watchpoints_debug ("wtx_stopped_data_address() -> 0");
+ return 0;
+}
+
+/* Implement the region_ok_for_hw_watchpoint target method for
+ targets that support BoDA. */
+
+static int
+region_ok_for_BoDA (CORE_ADDR addr, int len)
+{
+ /* BoDA events only allow us to watch a data that is 4 bytes
+ long. Apparently, there are no constraints in terms of
+ alignment, so we don't need to worry about it. */
+ return (len <= 4);
+}
+
+/* Return non-zero if a WTX_EVENT_DATA_ACCESS event can watch
+ a memory region of LEN bytes. */
+
+static int
+region_ok_for_data_access_event (CORE_ADDR addr, int len)
+{
+ /* brobecker/2006-09-27: As far as I know, DATA_ACCESS events
+ can only monitor 4-byte memory regions. */
+ return (len <= 4);
+}
+
+
+/* Implement the region_ok_for_hw_watchpoint for all tornado targets.
+ Basicallly determines the type of watchpoint the target supports and
+ dispatches to the appropriate function. */
+
+static int
+wtx_region_ok_for_hw_watchpoint (CORE_ADDR addr, int len)
+{
+ if (wtxapi_target_has_BoDA ())
+ return region_ok_for_BoDA (addr, len);
+
+ return (region_ok_for_data_access_event (addr, len));
+}
+
+/* Given the watchpoint type that needs to be inserted (that follows
+ GDB's encoding), return the equivalent value to be used in WTX
+ event insertion requests. */
+
+static wtxapi_tgt_addr_t
+gdb_watchpoint_type_to_wtx_breakpoint_type (int type)
+{
+ switch (type)
+ {
+ case hw_write: return 3; break;
+ case hw_read: return 2; break;
+ case hw_access: return 1; break;
+ case hw_execute: return 0; break;
+ }
+
+ /* We should never reach this code. If we do, print a warning and
+ pretend we were trying to use a read+write=access watchpoint type. */
+ warning (_("unexpected watchpoint type: %d"), type);
+ return gdb_watchpoint_type_to_wtx_breakpoint_type (hw_access);
+}
+
+/* Fill up EVENT with all the necessary information to insert
+ a WTX_EVENT_HW_BP eventpoint.
+
+ Even though this function does not setup EVENT to insert a BoDA,
+ this function assumes that the target does support BoDA. If not,
+ use set_data_access_event below. */
+
+static void
+set_hardware_watchpoint_event_no_value (struct wtxapi_event *event,
+ CORE_ADDR addr,
+ int type)
+{
+ event->event_type = WTX_EVENT_HW_BP;
+
+ /* WTX_EVENT_HW_BP eventpoints have 3 arguments:
+ . args[0] is the address of the data being watched.
+ . args[1] is the watchpoint count (the number of times
+ the watchpoint should be hit before generating
+ an event to the debugger). Unused by us, always
+ set to 0.
+ . args[2] is the type of watchpoint (read/write/access). */
+ event->num_args = 3;
+ event->args[0] = addr;
+ event->args[1] = 0;
+ event->args[2] = gdb_watchpoint_type_to_wtx_breakpoint_type (type);
+
+ wtx_opt_watchpoints_debug
+ ("Using WTX_EVENT_HW_BP event (addr = 0x%s, type = %d)",
+ paddress (target_gdbarch, event->args[0]), (int) event->args[2]);
+}
+
+/* Fill up EVENT with all the necessary information to insert
+ a WTX_EVENT_DATA_ACCESS eventpoint.
+
+ This function should be used with all systems that do NOT support BoDA. */
+
+static void
+set_data_access_event (struct wtxapi_event *event,
+ const CORE_ADDR addr,
+ const int type)
+{
+ event->event_type = WTX_EVENT_DATA_ACCESS;
+
+ /* WTX_EVENT_DATA_ACCESS eventpoints have 3 arguments:
+ . args[0] is the address of the data being watched.
+ . args[1] is the watchpoint count (the number of times
+ the watchpoint should be hit before generating
+ an event to the debugger). Unused by us, always
+ set to 0.
+ . args[2] is the type of watchpoint (read/write/access). */
+ event->num_args = 3;
+ event->args[0] = addr;
+ event->args[1] = 0;
+ event->args[2] = gdb_watchpoint_type_to_wtx_breakpoint_type (type);
+
+ wtx_opt_watchpoints_debug
+ ("Using DATA_ACCESS event (addr = 0x%s, type = %d)",
+ paddress (target_gdbarch, event->args[0]), (int) event->args[2]);
+}
+
+/* Implement the target_insert_watchpoint target method for all WTX
+ targets. */
+
+static int
+wtx_insert_watchpoint (WTX_CONTEXT_TYPE context_type,
+ WTX_CONTEXT_ID_T context_id,
+ WTX_ACTION_TYPE action_type,
+ CORE_ADDR addr, int len, int type)
+{
+ struct wtxapi_evtpt evtpt;
+ wtxapi_tgt_arg_t args[4];
+ evtpt_id_t watchpoint_id;
+
+ /* First, clear the evtpt struture. In other parts of this file,
+ we actually calloc this structure which makes the memset unecessary,
+ but doing it this way avoids the need to free the newly allocated
+ memory. */
+ memset (&evtpt, 0, sizeof (evtpt));
+
+ evtpt.context.context_type = context_type;
+ evtpt.context.context_id = context_id;
+ evtpt.action.action_type = action_type;
+ evtpt.event.args = args;
+
+ /* Tell the target server to notify us when the watchpoint is hit. */
+ evtpt.action.action_type |= WTX_ACTION_NOTIFY;
+
+ /* If the system provides data-matching support with its watchpoints,
+ and the watchpoint has a condition that can be tested using that
+ support, then use it. The data value in BoDA watchpoints will
+ be optional. */
+
+ if (wtxapi_target_has_BoDA ())
+ set_hardware_watchpoint_event_no_value (&evtpt.event, addr, type);
+ else
+ set_data_access_event (&evtpt.event, addr, type);
+
+ /* Insert the eventpoint. */
+ watchpoint_id = wtxapi_eventpoint_add (&evtpt);
+
+ if (watchpoint_id == invalid_evtpt_id)
+ error (_("Failed to insert watchpoint"));
+
+ /* Save the watchpoint_id in our list of eventpoints. Will be needed
+ later to map GDB watchpoints info back into WTX event ids. */
+ wtx_bp_register_watchpoint_id (watchpoint_id, addr, len, type);
+
+ return 0;
+}
+
+/* Implement the task-mode "to_insert_watchpoint" target_ops method. */
+
+static int
+wtx_insert_task_mode_watchpoint (CORE_ADDR addr, int len, int type,
+ struct expression *cond)
+{
+ const enum wtx_breakpoint_action action = get_break_command_action ();
+ WTX_CONTEXT_TYPE context_type;
+ WTX_CONTEXT_ID_T context_id;
+ WTX_ACTION_TYPE action_type;
+ CORE_ADDR call_rtn = 0;
+
+ /* FIXME: We do the exact same thing when inserting a task-mode
+ breakpoint. Put this code inside remote-wtx-bp and then reuse. */
+ context_type = WTX_CONTEXT_TASK;
+ context_id = ptid_get_context_id (inferior_ptid);
+
+ switch (action)
+ {
+ case action_task:
+ action_type = WTX_ACTION_STOP;
+ break;
+
+ case action_all:
+ action_type = WTX_ACTION_STOP_ALL;
+ break;
+
+ case action_call:
+ context_type = WTX_CONTEXT_ANY_TASK;
+ action_type = WTX_ACTION_STOP;
+ call_rtn = get_break_command_call_rtn ();
+ if (call_rtn != 0)
+ action_type |= WTX_ACTION_CALL;
+ break;
+
+ default:
+ internal_error (__FILE__, __LINE__, _("Unexpected action value: %d"),
+ action);
+ }
+
+ return wtx_insert_watchpoint (context_type, context_id,
+ action_type, addr, len, type);
+}
+
+/* Implement the system-mode "to_insert_watchpoint" target_ops method. */
+
+static int
+wtx_insert_system_mode_watchpoint (CORE_ADDR addr, int len, int type,
+ struct expression *cond)
+{
+ return wtx_insert_watchpoint (WTX_CONTEXT_SYSTEM, SYSTEM_CID,
+ WTX_ACTION_STOP, addr, len, type);
+}
+
+/* Implement the "to_remove_watchpoint" target_ops method. */
+
+static int
+wtx_remove_watchpoint (CORE_ADDR addr, int len, int type,
+ struct expression *cond)
+{
+ const evtpt_id_t watchpoint_id = wtx_bp_pop_watchpoint_id (addr, len, type);
+
+ if (watchpoint_id == invalid_evtpt_id)
+ {
+ warning (_("Unknown watchpoint at 0x%s (len = %d, type = %d)"),
+ paddress (target_gdbarch, addr), len, type);
+ return EINVAL;
+ }
+
+ if (!wtxapi_eventpoint_delete (watchpoint_id))
+ {
+ warning (_("Unable to remove watchpoint id 0x%x"), watchpoint_id);
+ return EINVAL;
+ }
+
+ return 0;
+}
+
+/* Implement the "to_mourn_inferior" method of the target_ops vector
+ for the task mode. */
+
+static void
+wtx_task_mode_mourn_inferior (struct target_ops *ops)
+{
+ remove_breakpoints ();
+ if (multi_task_mode_is_on ())
+ stop_multi_task_mode ();
+
+ unpush_target (&wtx_task_mode_ops);
+ generic_mourn_inferior ();
+}
+
+/* Return 1 if the thread whose id is CONTEXT_ID is still alive. */
+
+static int
+wtx_context_alive (int context_id)
+{
+ struct wtxapi_thread_info *thread_list = wtxapi_get_thread_list ();
+ struct wtxapi_thread_info *thread;
+ int is_alive = 0;
+
+ for (thread = thread_list; thread != NULL; thread = thread->next)
+ if (thread->id == context_id)
+ {
+ is_alive = 1;
+ break;
+ }
+ free_wtxapi_thread_info (thread_list);
+
+ return is_alive;
+}
+
+/* Implement the "to_thread_alive" method of the target_ops vector. */
+
+static int
+wtx_thread_alive (struct target_ops *ops, ptid_t ptid)
+{
+ const int context_id = ptid_get_context_id (ptid);
+ return wtx_context_alive (context_id);
+}
+
+/* Implement the "to_find_new_threads" method when in single-task mode. */
+
+static void
+wtx_single_task_mode_find_new_threads (void)
+{
+ /* In this mode, we only debug one thread. */
+ wtx_add_thread (inferior_ptid);
+}
+
+/* Add the thread associated to the given TASK to the thread list.
+ Does nothing if that thread was already added earlier. */
+
+static void
+wtx_multi_task_mode_add_thread_from_task (struct ada_task_info *task)
+{
+ wtx_add_thread (task->ptid);
+}
+
+/* Implement the "to_find_new_threads" method when in multi-tasks mode. */
+
+static void
+wtx_multi_task_mode_find_new_threads (void)
+{
+ iterate_over_live_ada_tasks (wtx_multi_task_mode_add_thread_from_task);
+}
+
+/* Implement the "to_find_new_threads" method of the task-mode target_ops
+ vector. Handles both single-task and multi-tasks modes. */
+
+static void
+wtx_task_mode_find_new_threads (struct target_ops *ops)
+{
+ if (multi_task_mode_is_on ())
+ wtx_multi_task_mode_find_new_threads ();
+ else
+ wtx_single_task_mode_find_new_threads ();
+}
+
+/* Implement the "to_find_new_threads" method of the system-mode
+ target_ops vector. */
+
+static void
+wtx_system_mode_find_new_threads (struct target_ops *ops)
+{
+ struct wtxapi_thread_info *thread_list = wtxapi_get_thread_list ();
+ struct wtxapi_thread_info *thread;
+
+ for (thread = thread_list; thread != NULL; thread = thread->next)
+ {
+ const ptid_t thread_ptid = context_id_to_ptid (thread->id);
+
+ wtx_add_thread (thread_ptid);
+ }
+
+ free_wtxapi_thread_info (thread_list);
+}
+
+/* Suspend the given CONTEXT_TYPE/CONTEXT_ID. */
+
+static void
+wtx_stop (WTX_CONTEXT_TYPE context_type, WTX_CONTEXT_ID_T context_id)
+{
+ if (multi_task_mode_is_on ())
+ stop_all_ada_tasks (&inferior_status);
+ else
+ stop_inferior (context_type, context_id);
+}
+
+/* Implement the task-mode "to_stop" target_ops method. */
+
+static void
+wtx_task_mode_stop (ptid_t ptid)
+{
+ const WTX_CONTEXT_ID_T context_id = ptid_get_context_id (ptid);
+
+ wtx_stop (WTX_CONTEXT_TASK, context_id);
+}
+
+/* Implement the system-mode "to_stop" target_ops method. */
+
+static void
+wtx_system_mode_stop (ptid_t ptid)
+{
+ wtx_stop (WTX_CONTEXT_SYSTEM, SYSTEM_CID);
+ inferior_ptid =
+ context_id_to_ptid (wtxapi_system_mode_get_current_context_id ());
+}
+
+/* Return the name of a task from its CONTEXT_ID, or NULL if the task
+ could not be found.
+
+ The returned string must be deallocated after use. */
+
+static char *
+wtx_name_from_context_id (WTX_CONTEXT_ID_T context_id)
+{
+ struct wtxapi_thread_info *threads = wtxapi_get_thread_list ();
+ struct wtxapi_thread_info *this_thread = threads;
+ char *name = NULL;
+
+ while (this_thread != NULL)
+ {
+ if (this_thread->id == context_id)
+ {
+ name = xstrdup (this_thread->name);
+ break;
+ }
+ this_thread = this_thread->next;
+ }
+
+ free_wtxapi_thread_info (threads);
+ return name;
+}
+
+/* Implement the "to_pid_to_str" target_ops method. */
+
+static char *
+wtx_pid_to_str (struct target_ops *ops, ptid_t ptid)
+{
+ static char *buf = NULL;
+ const WTX_CONTEXT_ID_T context_id = ptid_get_context_id (ptid);
+ char *task_name = wtx_name_from_context_id (context_id);
+
+ if (buf != NULL)
+ xfree (buf);
+ xasprintf (&buf, "task 0x%lx\t(%s)\t", context_id,
+ task_name ? task_name : "[no name]");
+ if (task_name != NULL)
+ xfree (task_name);
+
+ return buf;
+}
+
+/* Implement the to_get_ada_task_ptid function for the WTX targets. */
+
+static ptid_t
+wtx_get_ada_task_ptid (long lwp, long thread)
+{
+ return context_id_to_ptid (thread);
+}
+
+/* Always return zero. */
+
+static int
+wtx_return_zero (struct target_ops *target)
+{
+ return 0;
+}
+
+/* Always return one. */
+
+static int
+wtx_return_one (struct target_ops *target)
+{
+ return 1;
+}
+
+/* Initialize the WTX_OPS target_ops object. */
+
+static void
+init_wtx_ops (void)
+{
+ /* First, clear the structure. This is not strictly necessary provided
+ we make sure to always set all the fields of the our structure.
+ But in the event that we did not, this makes sure that the fields
+ we missed are initialized to something consistent. */
+ memset (&wtx_ops, 0, sizeof (wtx_ops));
+
+ wtx_ops.to_shortname = "wtx";
+ wtx_ops.to_longname = "WTX protocol";
+ wtx_ops.to_doc = "\
+Remote target connected via the WTX protocol.\n\
+Specify the name of the target server as the argument.";
+ wtx_ops.to_open = wtx_open;
+ wtx_ops.to_close = wtx_close;
+ wtx_ops.to_attach = wtx_attach;
+ /* No need to set to_detach, will never be called, because the detach
+ option from a higher stratum will be used instead. */
+ wtx_ops.to_load = wtx_load;
+ wtx_ops.to_unload = wtx_unload;
+ wtx_ops.to_create_inferior = wtx_create_inferior;
+ wtx_ops.to_pid_to_str = wtx_pid_to_str;
+ wtx_ops.to_stratum = file_stratum;
+ wtx_ops.to_has_all_memory = wtx_return_one;
+ wtx_ops.to_has_memory = wtx_return_one;
+ wtx_ops.to_has_stack = wtx_return_zero;
+ wtx_ops.to_has_registers = wtx_return_zero;
+ wtx_ops.to_has_execution = wtx_return_zero;
+ wtx_ops.to_xfer_partial = wtx_xfer_partial;
+ wtx_ops.to_get_ada_task_ptid = wtx_get_ada_task_ptid;
+ wtx_ops.to_magic = OPS_MAGIC;
+}
+
+static void
+init_wtx_task_mode_ops (void)
+{
+ /* First, clear the structure. This is not strictly necessary provided
+ we make sure to always set all the fields of the our structure.
+ But in the event that we did not, this makes sure that the fields
+ we missed are initialized to something consistent. */
+ memset (&wtx_task_mode_ops, 0, sizeof (wtx_task_mode_ops));
+
+ wtx_task_mode_ops.to_shortname = "wtx task mode";
+ wtx_task_mode_ops.to_longname =
+ "Task and Multi-tasks Mode support for the WTX protocol";
+ wtx_task_mode_ops.to_doc =
+ "Debugging a task or a set of tasks using the WTX protocol.";
+ wtx_task_mode_ops.to_open = NULL;
+ wtx_task_mode_ops.to_close = wtx_task_mode_close;
+ wtx_task_mode_ops.to_attach = wtx_attach;
+ wtx_task_mode_ops.to_detach = wtx_task_mode_detach;
+ wtx_task_mode_ops.to_resume = wtx_task_mode_resume;
+ wtx_task_mode_ops.to_wait = wtx_wait;
+ wtx_task_mode_ops.to_fetch_registers = wtx_task_mode_fetch_registers;
+ wtx_task_mode_ops.to_store_registers = wtx_task_mode_store_registers;
+ wtx_task_mode_ops.to_prepare_to_store = wtx_prepare_to_store;
+ wtx_task_mode_ops.to_insert_breakpoint = wtx_insert_task_mode_breakpoint;
+ wtx_task_mode_ops.to_remove_breakpoint = wtx_remove_breakpoint;
+ wtx_task_mode_ops.to_can_use_hw_breakpoint = wtx_can_use_hw_breakpoint;
+ wtx_task_mode_ops.to_remove_watchpoint = wtx_remove_watchpoint;
+ wtx_task_mode_ops.to_insert_watchpoint = wtx_insert_task_mode_watchpoint;
+ wtx_task_mode_ops.to_stopped_by_watchpoint = wtx_stopped_by_watchpoint;
+ wtx_task_mode_ops.to_stopped_data_address = wtx_stopped_data_address;
+ wtx_task_mode_ops.to_region_ok_for_hw_watchpoint =
+ wtx_region_ok_for_hw_watchpoint;
+
+ wtx_task_mode_ops.to_kill = wtx_task_mode_kill;
+ wtx_task_mode_ops.to_load = wtx_load;
+ wtx_task_mode_ops.to_unload = wtx_unload;
+ wtx_task_mode_ops.to_mourn_inferior = wtx_task_mode_mourn_inferior;
+ wtx_task_mode_ops.to_thread_alive = wtx_thread_alive;
+ wtx_task_mode_ops.to_find_new_threads = wtx_task_mode_find_new_threads;
+ wtx_task_mode_ops.to_stop = wtx_task_mode_stop;
+ wtx_task_mode_ops.to_stratum = process_stratum;
+ wtx_task_mode_ops.to_has_all_memory = wtx_return_one;
+ wtx_task_mode_ops.to_has_memory = wtx_return_one;
+ wtx_task_mode_ops.to_has_stack = wtx_return_one;
+ wtx_task_mode_ops.to_has_registers = wtx_return_one;
+ wtx_task_mode_ops.to_has_execution = wtx_return_one;
+ wtx_task_mode_ops.to_xfer_partial = wtx_xfer_partial;
+ wtx_task_mode_ops.to_magic = OPS_MAGIC;
+}
+
+static void
+init_wtx_system_mode_ops (void)
+{
+ /* First, clear the structure. This is not strictly necessary provided
+ we make sure to always set all the fields of the our structure.
+ But in the event that we did not, this makes sure that the fields
+ we missed are initialized to something consistent. */
+ memset (&wtx_system_mode_ops, 0, sizeof (wtx_system_mode_ops));
+
+ wtx_system_mode_ops.to_shortname = "wtx system mode";
+ wtx_system_mode_ops.to_longname =
+ "System Mode support for the WTX protocol";
+ wtx_system_mode_ops.to_doc =
+ "Debugging a target in system mode using the WTX protocol.";
+ wtx_system_mode_ops.to_open = NULL;
+ wtx_system_mode_ops.to_close = wtx_system_mode_close;
+ wtx_system_mode_ops.to_attach = wtx_attach;
+ wtx_system_mode_ops.to_detach = wtx_system_mode_detach;
+ wtx_system_mode_ops.to_resume = wtx_system_mode_resume;
+ wtx_system_mode_ops.to_wait = wtx_wait;
+ wtx_system_mode_ops.to_fetch_registers = wtx_system_mode_fetch_registers;
+ wtx_system_mode_ops.to_store_registers = wtx_system_mode_store_registers;
+ wtx_system_mode_ops.to_prepare_to_store = wtx_prepare_to_store;
+ wtx_system_mode_ops.to_insert_breakpoint = wtx_insert_system_mode_breakpoint;
+ wtx_system_mode_ops.to_remove_breakpoint = wtx_remove_breakpoint;
+ wtx_system_mode_ops.to_can_use_hw_breakpoint = wtx_can_use_hw_breakpoint;
+ wtx_system_mode_ops.to_remove_watchpoint = wtx_remove_watchpoint;
+ wtx_system_mode_ops.to_insert_watchpoint = wtx_insert_system_mode_watchpoint;
+ wtx_system_mode_ops.to_stopped_by_watchpoint = wtx_stopped_by_watchpoint;
+ wtx_system_mode_ops.to_stopped_data_address = wtx_stopped_data_address;
+ wtx_system_mode_ops.to_region_ok_for_hw_watchpoint =
+ wtx_region_ok_for_hw_watchpoint;
+
+ wtx_system_mode_ops.to_kill = wtx_system_mode_kill;
+ wtx_system_mode_ops.to_load = wtx_load;
+ wtx_system_mode_ops.to_unload = wtx_unload;
+ wtx_system_mode_ops.to_thread_alive = wtx_thread_alive;
+ wtx_system_mode_ops.to_find_new_threads = wtx_system_mode_find_new_threads;
+ wtx_system_mode_ops.to_stop = wtx_system_mode_stop;
+ wtx_system_mode_ops.to_stratum = process_stratum;
+ wtx_system_mode_ops.to_has_all_memory = wtx_return_one;
+ wtx_system_mode_ops.to_has_memory = wtx_return_one;
+ wtx_system_mode_ops.to_has_stack = wtx_return_one;
+ wtx_system_mode_ops.to_has_registers = wtx_return_one;
+ wtx_system_mode_ops.to_has_execution = wtx_return_one;
+ wtx_system_mode_ops.to_xfer_partial = wtx_xfer_partial;
+ wtx_system_mode_ops.to_magic = OPS_MAGIC;
+}
+
+static struct cmd_list_element *wtx_list = NULL;
+
+/* Implement the "wtx" command.
+ This is not actually a valid command, so inform the user of that fact,
+ and print the list of valid subcommands to help him. */
+
+static void
+wtx_command (char *args, int from_tty)
+{
+ printf_filtered (_("\"wtx\" must be followed by a subcommand.\n"));
+ help_list (wtx_list, "wtx ", -1, gdb_stdout);
+}
+
+/* Implement the "wtx add-symbol-file" command: same as add-symbol-file,
+ except that the load addresses are not taken from the command
+ line, but from the WTX module info. */
+
+static void
+wtx_add_symbol_file (char *args, int from_tty)
+{
+ char *module_name, *module_filename;
+ module_id_t module_id;
+ pd_id_t module_pd;
+ struct cleanup *old_chain = NULL;
+ struct wtxapi_module_info *module_info;
+
+ if (args == NULL)
+ error (_("wtx add-symbol-file takes a file name"));
+
+ module_filename = args;
+ module_name = (char *) lbasename (module_filename);
+ module_id = wtxapi_obj_module_in_system_find_id (module_name);
+
+ if (module_id == invalid_module_id)
+ {
+ warning (_("could not find %s on target: %s"),
+ module_name, wtxapi_err_msg_get ());
+ return;
+ }
+
+ module_pd = wtx_pd_get_module_pd (module_id);
+ module_info = wtxapi_obj_module_info_get (module_pd, module_id);
+ old_chain = make_cleanup (cleanup_wtxapi_module_info, module_info);
+
+ if (module_info == NULL)
+ error (_("Cannot get info for module 0x%x: %s"),
+ (unsigned int) module_id, wtxapi_err_msg_get ());
+
+ printf_filtered (_("Add symbols from file %s:\n"), module_filename);
+ if (read_module_symbols_1 (module_info, module_filename))
+ printf_filtered (_("ok\n"));
+ else
+ printf_filtered (_("failed\n"));
+
+ if (old_chain)
+ do_cleanups (old_chain);
+}
+
+void
+_initialize_remote_wtx (void)
+{
+ /* Initialize the WTX library. */
+ if (!wtxapi_initialize ())
+ {
+ warning (_("Failed to initialize WTX library:\n\t%s\n\
+(WTX target not activated)."),
+ wtxapi_err_msg_get ());
+
+ /* We cannot use the WTX protocol if for some reason we failed
+ to initialized the WTX API. So abort now, instead of pushing
+ the WTX target ops. */
+ return;
+ }
+
+ init_wtx_ops ();
+ init_wtx_task_mode_ops ();
+ init_wtx_system_mode_ops ();
+
+ add_target (&wtx_ops);
+
+ /* New commands. */
+
+ add_prefix_cmd ("wtx", no_class, wtx_command,
+ _("WTX protocol specific commands\n"),
+ &wtx_list, "wtx ",
+ 0 /* allow-unknown */, &cmdlist);
+
+ add_cmd ("add-symbol-file", no_class, wtx_add_symbol_file, _("\
+WTX specific version of add-symbol-file\n\
+Usage: add-symbol-file FILE\n\
+Load symbols from FILE, assuming that FILE has been dynamically loaded.\n\
+The section addresses for this module are fetched from the target server.\n\
+"), &wtx_list);
+
+ /* Observers. */
+
+ if (wtx_pd_system_has_pds ())
+ {
+ /* The following observers are only useful when the target system
+ supports partitions. */
+ observer_attach_breakpoint_created (wtx_breakpoint_created_observer);
+ observer_attach_breakpoint_deleted (wtx_delete_breakpoint_observer);
+ }
+}
diff --git a/gdb/remote-wtx.h b/gdb/remote-wtx.h
new file mode 100644
index 0000000..a81f55e
--- /dev/null
+++ b/gdb/remote-wtx.h
@@ -0,0 +1,25 @@
+/* WTX backend for GDB.
+
+ Copyright 2007, 2010, 2011 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#ifndef REMOTE_WTX_H
+#define REMOTE_WTX_H
+
+extern void wtx_open (char *args, int from_tty);
+
+#endif
--
1.7.0.4
^ permalink raw reply [flat|nested] 54+ messages in thread
* [PATCH 12/18] remote-wtx-hw: register fetch/store support.
2011-02-24 17:49 Add support for VxWorks 5.x, 6.x and 653 Joel Brobecker
` (11 preceding siblings ...)
2011-02-24 17:57 ` [PATCH 13/18] Add new "wtx" target Joel Brobecker
@ 2011-02-24 17:57 ` Joel Brobecker
2011-02-24 17:57 ` [PATCH 14/18] WTX-TCL support module Joel Brobecker
` (4 subsequent siblings)
17 siblings, 0 replies; 54+ messages in thread
From: Joel Brobecker @ 2011-02-24 17:57 UTC (permalink / raw)
To: gdb-patches; +Cc: Joel Brobecker
This module is in charge of fetching/storing a given register. There
are two issues to consider:
- GDB regno to WTX regno translation;
- determine which register set a given register belongs to.
gdb/ChangeLog:
* remote-wtx-hw.h, remote-wtx-hw.c: New files.
---
gdb/remote-wtx-hw.c | 497 +++++++++++++++++++++++++++++++++++++++++++++++++++
gdb/remote-wtx-hw.h | 56 ++++++
2 files changed, 553 insertions(+), 0 deletions(-)
create mode 100644 gdb/remote-wtx-hw.c
create mode 100644 gdb/remote-wtx-hw.h
diff --git a/gdb/remote-wtx-hw.c b/gdb/remote-wtx-hw.c
new file mode 100644
index 0000000..b5010f7
--- /dev/null
+++ b/gdb/remote-wtx-hw.c
@@ -0,0 +1,497 @@
+/* Support for the WTX protocol.
+
+ Copyright (C) 2007, 2011 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#include "defs.h"
+#include "remote-wtx-hw.h"
+#include "gdb_assert.h"
+#include "regcache.h"
+#include "gdbcmd.h"
+
+/* Registers in WTX are stored consecutively in a series of memory blocks,
+ with one block per register set. The following structure details
+ for a given register its position in the block, and the associated
+ register set. A negative offset means that the register is not
+ accessible with WTX.
+
+ brobecker/2007-06-25: On older versions of this code, we also used
+ to store the register size, but this should not be necessary.
+ GDB already knows the register size, and it should match the size
+ needed by WTX. */
+
+struct wtx_hw_register
+{
+ UINT32 register_offset;
+ WTX_REG_SET_TYPE register_set;
+};
+
+/* i386 registers description, as seen by VxWorks. */
+
+static const struct wtx_hw_register i386_register_map [] =
+{
+ /* Data registers. */
+ {0x1c, WTX_REG_SET_IU}, /* eax */
+ {0x18, WTX_REG_SET_IU}, /* ecx */
+ {0x14, WTX_REG_SET_IU}, /* edx */
+ {0x10, WTX_REG_SET_IU}, /* ebx */
+ {0x0c, WTX_REG_SET_IU}, /* esp */
+ {0x08, WTX_REG_SET_IU}, /* ebp */
+ {0x04, WTX_REG_SET_IU}, /* esi */
+ {0x00, WTX_REG_SET_IU}, /* edi */
+ {0x24, WTX_REG_SET_IU}, /* pc */
+ {0x20, WTX_REG_SET_IU}, /* eflags */
+
+ /* Segment registers (not accessible). */
+
+ {-1, WTX_REG_SET_IU}, /* cs */
+ {-1, WTX_REG_SET_IU}, /* ss */
+ {-1, WTX_REG_SET_IU}, /* ds */
+ {-1, WTX_REG_SET_IU}, /* es */
+ {-1, WTX_REG_SET_IU}, /* fs */
+ {-1, WTX_REG_SET_IU}, /* gs */
+
+ /* Floating Point registers. */
+ {0x1c, WTX_REG_SET_FPU}, /* st0 */
+ {0x16, WTX_REG_SET_FPU}, /* st1 */
+ {0x20, WTX_REG_SET_FPU}, /* st2 */
+ {0x2a, WTX_REG_SET_FPU}, /* st3 */
+ {0x34, WTX_REG_SET_FPU}, /* st4 */
+ {0x3e, WTX_REG_SET_FPU}, /* st5 */
+ {0x48, WTX_REG_SET_FPU}, /* st6 */
+ {0x52, WTX_REG_SET_FPU}, /* st7 */
+ {0x00, WTX_REG_SET_FPU}, /* fpc */
+ {0x04, WTX_REG_SET_FPU}, /* fps */
+ {0x08, WTX_REG_SET_FPU}, /* fpt */
+ {-1, WTX_REG_SET_IU}, /* fiseg */
+ {-1, WTX_REG_SET_IU}, /* fioff */
+ {-1, WTX_REG_SET_IU}, /* foseg */
+ {-1, WTX_REG_SET_IU}, /* fooff */
+ {-1, WTX_REG_SET_IU}, /* fop */
+ {-1, WTX_REG_SET_IU}, /* xmm0 */
+ {-1, WTX_REG_SET_IU}, /* xmm1 */
+ {-1, WTX_REG_SET_IU}, /* xmm2 */
+ {-1, WTX_REG_SET_IU}, /* xmm3 */
+ {-1, WTX_REG_SET_IU}, /* xmm4 */
+ {-1, WTX_REG_SET_IU}, /* xmm5 */
+ {-1, WTX_REG_SET_IU}, /* xmm6 */
+ {-1, WTX_REG_SET_IU}, /* xmm7 */
+ {-1, WTX_REG_SET_IU}, /* mxcsr */
+
+ /* MMX pseudo-registers (not accessible). */
+
+ {-1, WTX_REG_SET_IU}, /* mm0 */
+ {-1, WTX_REG_SET_IU}, /* mm1 */
+ {-1, WTX_REG_SET_IU}, /* mm2 */
+ {-1, WTX_REG_SET_IU}, /* mm3 */
+ {-1, WTX_REG_SET_IU}, /* mm4 */
+ {-1, WTX_REG_SET_IU}, /* mm5 */
+ {-1, WTX_REG_SET_IU}, /* mm6 */
+ {-1, WTX_REG_SET_IU} /* mm7 */
+};
+
+
+static const struct wtx_hw_register ppc_register_map[] =
+{
+ /* General purpose registers. */
+
+ {0x00, WTX_REG_SET_IU}, /* r0 (0) */
+ {0x04, WTX_REG_SET_IU}, /* r1 */
+ {0x08, WTX_REG_SET_IU}, /* r2 */
+ {0x0c, WTX_REG_SET_IU}, /* r3 */
+ {0x10, WTX_REG_SET_IU}, /* r4 */
+ {0x14, WTX_REG_SET_IU}, /* r5 */
+ {0x18, WTX_REG_SET_IU}, /* r6 */
+ {0x1c, WTX_REG_SET_IU}, /* r7 */
+ {0x20, WTX_REG_SET_IU}, /* r8 (8) */
+ {0x24, WTX_REG_SET_IU}, /* r9 */
+ {0x28, WTX_REG_SET_IU}, /* r10 */
+ {0x2c, WTX_REG_SET_IU}, /* r11 */
+ {0x30, WTX_REG_SET_IU}, /* r12 */
+ {0x34, WTX_REG_SET_IU}, /* r13 */
+ {0x38, WTX_REG_SET_IU}, /* r14 */
+ {0x3c, WTX_REG_SET_IU}, /* r15 (16) */
+ {0x40, WTX_REG_SET_IU}, /* r16 */
+ {0x44, WTX_REG_SET_IU}, /* r17 */
+ {0x48, WTX_REG_SET_IU}, /* r18 */
+ {0x4c, WTX_REG_SET_IU}, /* r19 */
+ {0x50, WTX_REG_SET_IU}, /* r20 */
+ {0x54, WTX_REG_SET_IU}, /* r21 */
+ {0x58, WTX_REG_SET_IU}, /* r22 */
+ {0x5c, WTX_REG_SET_IU}, /* r23 */
+ {0x60, WTX_REG_SET_IU}, /* r24 (24) */
+ {0x64, WTX_REG_SET_IU}, /* r25 */
+ {0x68, WTX_REG_SET_IU}, /* r26 */
+ {0x6c, WTX_REG_SET_IU}, /* r27 */
+ {0x70, WTX_REG_SET_IU}, /* r28 */
+ {0x74, WTX_REG_SET_IU}, /* r29 */
+ {0x78, WTX_REG_SET_IU}, /* r30 */
+ {0x7c, WTX_REG_SET_IU}, /* r31 */
+ {0x00, WTX_REG_SET_FPU}, /* f0 (32) */
+ {0x08, WTX_REG_SET_FPU}, /* f1 */
+ {0x10, WTX_REG_SET_FPU}, /* f2 */
+ {0x18, WTX_REG_SET_FPU}, /* f3 */
+ {0x20, WTX_REG_SET_FPU}, /* f4 */
+ {0x28, WTX_REG_SET_FPU}, /* f5 */
+ {0x30, WTX_REG_SET_FPU}, /* f6 */
+ {0x38, WTX_REG_SET_FPU}, /* f7 */
+ {0x40, WTX_REG_SET_FPU}, /* f8 (40) */
+ {0x48, WTX_REG_SET_FPU}, /* f9 */
+ {0x50, WTX_REG_SET_FPU}, /* f10 */
+ {0x58, WTX_REG_SET_FPU}, /* f11 */
+ {0x60, WTX_REG_SET_FPU}, /* f12 */
+ {0x68, WTX_REG_SET_FPU}, /* f13 */
+ {0x70, WTX_REG_SET_FPU}, /* f14 */
+ {0x78, WTX_REG_SET_FPU}, /* f15 */
+ {0x80, WTX_REG_SET_FPU}, /* f16 (48) */
+ {0x88, WTX_REG_SET_FPU}, /* f17 */
+ {0x90, WTX_REG_SET_FPU}, /* f18 */
+ {0x98, WTX_REG_SET_FPU}, /* f19 */
+ {0xa0, WTX_REG_SET_FPU}, /* f20 */
+ {0xa8, WTX_REG_SET_FPU}, /* f21 */
+ {0xb0, WTX_REG_SET_FPU}, /* f22 */
+ {0xb8, WTX_REG_SET_FPU}, /* f23 */
+ {0xc0, WTX_REG_SET_FPU}, /* f24 (56) */
+ {0xc8, WTX_REG_SET_FPU}, /* f25 */
+ {0xd0, WTX_REG_SET_FPU}, /* f26 */
+ {0xd8, WTX_REG_SET_FPU}, /* f27 */
+ {0xe0, WTX_REG_SET_FPU}, /* f28 */
+ {0xe8, WTX_REG_SET_FPU}, /* f29 */
+ {0xf0, WTX_REG_SET_FPU}, /* f30 */
+ {0xf8, WTX_REG_SET_FPU}, /* f31 */
+ {0x8c, WTX_REG_SET_IU}, /* pc (64) */
+ {0x80, WTX_REG_SET_IU}, /* ps/msr */
+
+ /* Special purpose registers. */
+
+ {0x90, WTX_REG_SET_IU}, /* cr (66) */
+ {0x84, WTX_REG_SET_IU}, /* lr */
+ {0x88, WTX_REG_SET_IU}, /* ctr */
+ {0x94, WTX_REG_SET_IU}, /* xer */
+ {0x100, WTX_REG_SET_FPU}, /* fpscr */
+
+ /* Unused register slots (71 - 105). */
+ {-1, WTX_REG_SET_IU}, /* Empty register slot (71). */
+ {-1, WTX_REG_SET_IU}, /* Empty register slot (72). */
+ {-1, WTX_REG_SET_IU}, /* Empty register slot (73). */
+ {-1, WTX_REG_SET_IU}, /* Empty register slot (74). */
+ {-1, WTX_REG_SET_IU}, /* Empty register slot (75). */
+ {-1, WTX_REG_SET_IU}, /* Empty register slot (76). */
+ {-1, WTX_REG_SET_IU}, /* Empty register slot (77). */
+ {-1, WTX_REG_SET_IU}, /* Empty register slot (78). */
+ {-1, WTX_REG_SET_IU}, /* Empty register slot (79). */
+
+ {-1, WTX_REG_SET_IU}, /* Empty register slot (80). */
+ {-1, WTX_REG_SET_IU}, /* Empty register slot (81). */
+ {-1, WTX_REG_SET_IU}, /* Empty register slot (82). */
+ {-1, WTX_REG_SET_IU}, /* Empty register slot (83). */
+ {-1, WTX_REG_SET_IU}, /* Empty register slot (84). */
+ {-1, WTX_REG_SET_IU}, /* Empty register slot (85). */
+ {-1, WTX_REG_SET_IU}, /* Empty register slot (86). */
+ {-1, WTX_REG_SET_IU}, /* Empty register slot (87). */
+ {-1, WTX_REG_SET_IU}, /* Empty register slot (88). */
+ {-1, WTX_REG_SET_IU}, /* Empty register slot (89). */
+
+ {-1, WTX_REG_SET_IU}, /* Empty register slot (90). */
+ {-1, WTX_REG_SET_IU}, /* Empty register slot (91). */
+ {-1, WTX_REG_SET_IU}, /* Empty register slot (92). */
+ {-1, WTX_REG_SET_IU}, /* Empty register slot (93). */
+ {-1, WTX_REG_SET_IU}, /* Empty register slot (94). */
+ {-1, WTX_REG_SET_IU}, /* Empty register slot (95). */
+ {-1, WTX_REG_SET_IU}, /* Empty register slot (96). */
+ {-1, WTX_REG_SET_IU}, /* Empty register slot (97). */
+ {-1, WTX_REG_SET_IU}, /* Empty register slot (98). */
+ {-1, WTX_REG_SET_IU}, /* Empty register slot (99). */
+
+ {-1, WTX_REG_SET_IU}, /* Empty register slot (100). */
+ {-1, WTX_REG_SET_IU}, /* Empty register slot (101). */
+ {-1, WTX_REG_SET_IU}, /* Empty register slot (102). */
+ {-1, WTX_REG_SET_IU}, /* Empty register slot (103). */
+ {-1, WTX_REG_SET_IU}, /* Empty register slot (104). */
+ {-1, WTX_REG_SET_IU}, /* Empty register slot (105). */
+
+ /* AltiVec registers.
+
+ They are only supported starting with VxWorks 5.5 and PSC 2.1.
+ brobecker/2007-11-02: For now, we removed support for these registers
+ regardless of the VxWorks version in order to allow us to build GDB
+ on older versions of VxWorks. We'll investigate conditional support
+ later (note that these registers are part of the WTX_REG_SET_AV
+ register set). */
+
+ {-1, WTX_REG_SET_IU}, /* vr0 (106) */
+ {-1, WTX_REG_SET_IU}, /* vr1 */
+ {-1, WTX_REG_SET_IU}, /* vr2 */
+ {-1, WTX_REG_SET_IU}, /* vr3 */
+ {-1, WTX_REG_SET_IU}, /* vr4 */
+ {-1, WTX_REG_SET_IU}, /* vr5 */
+ {-1, WTX_REG_SET_IU}, /* vr6 */
+ {-1, WTX_REG_SET_IU}, /* vr7 */
+ {-1, WTX_REG_SET_IU}, /* vr8 */
+ {-1, WTX_REG_SET_IU}, /* vr9 */
+ {-1, WTX_REG_SET_IU}, /* vr10 */
+ {-1, WTX_REG_SET_IU}, /* vr11 */
+ {-1, WTX_REG_SET_IU}, /* vr12 */
+ {-1, WTX_REG_SET_IU}, /* vr13 */
+ {-1, WTX_REG_SET_IU}, /* vr14 */
+ {-1, WTX_REG_SET_IU}, /* vr15 */
+ {-1, WTX_REG_SET_IU}, /* vr16 */
+ {-1, WTX_REG_SET_IU}, /* vr17 */
+ {-1, WTX_REG_SET_IU}, /* vr18 */
+ {-1, WTX_REG_SET_IU}, /* vr19 */
+ {-1, WTX_REG_SET_IU}, /* vr20 */
+ {-1, WTX_REG_SET_IU}, /* vr21 */
+ {-1, WTX_REG_SET_IU}, /* vr22 */
+ {-1, WTX_REG_SET_IU}, /* vr23 */
+ {-1, WTX_REG_SET_IU}, /* vr24 */
+ {-1, WTX_REG_SET_IU}, /* vr25 */
+ {-1, WTX_REG_SET_IU}, /* vr26 */
+ {-1, WTX_REG_SET_IU}, /* vr27 */
+ {-1, WTX_REG_SET_IU}, /* vr28 */
+ {-1, WTX_REG_SET_IU}, /* vr29 */
+ {-1, WTX_REG_SET_IU}, /* vr30 */
+ {-1, WTX_REG_SET_IU}, /* vr31 */
+ {-1, WTX_REG_SET_IU}, /* vscr */
+ {-1, WTX_REG_SET_IU}, /* vrsave */
+
+ /* dl registers (not accessible either). */
+ {-1, WTX_REG_SET_IU}, /* dl0 */
+ {-1, WTX_REG_SET_IU}, /* dl1 */
+ {-1, WTX_REG_SET_IU}, /* dl2 */
+ {-1, WTX_REG_SET_IU}, /* dl3 */
+ {-1, WTX_REG_SET_IU}, /* dl4 */
+ {-1, WTX_REG_SET_IU}, /* dl5 */
+ {-1, WTX_REG_SET_IU}, /* dl6 */
+ {-1, WTX_REG_SET_IU}, /* dl7 */
+ {-1, WTX_REG_SET_IU}, /* dl8 */
+ {-1, WTX_REG_SET_IU}, /* dl9 */
+ {-1, WTX_REG_SET_IU}, /* dl10 */
+ {-1, WTX_REG_SET_IU}, /* dl11 */
+ {-1, WTX_REG_SET_IU}, /* dl12 */
+ {-1, WTX_REG_SET_IU}, /* dl13 */
+ {-1, WTX_REG_SET_IU}, /* dl14 */
+ {-1, WTX_REG_SET_IU}, /* dl15 */
+};
+
+/* The following variables point to the appropriate register table
+ depending on the target. These are updated when we connect
+ to the target server. */
+
+static const struct wtx_hw_register *wtx_hw_register_map = NULL;
+static int wtx_hw_register_map_len = 0;
+
+/* Inspect the target gdbarch vector, and initialize the internal
+ state of this module. This include initializing elements such
+ as the register map, for instance.
+
+ This function must be called before any other function is used. */
+
+void
+wtx_hw_initialize (void)
+{
+ const struct bfd_arch_info *arch_info =
+ gdbarch_bfd_arch_info (target_gdbarch);
+
+ gdb_assert (arch_info != NULL);
+
+ switch (arch_info->arch)
+ {
+ case bfd_arch_rs6000:
+ case bfd_arch_powerpc:
+ wtx_hw_register_map = ppc_register_map;
+ wtx_hw_register_map_len =
+ sizeof (ppc_register_map) / sizeof (struct wtx_hw_register);
+ break;
+
+ case bfd_arch_i386:
+ wtx_hw_register_map = i386_register_map;
+ wtx_hw_register_map_len =
+ sizeof (i386_register_map) / sizeof (struct wtx_hw_register);
+ break;
+
+ default:
+ error (_("This architecture is currently not supported"));
+ }
+}
+
+/* Return non-zero if the given register can be fetched & stored. */
+
+static int
+wtx_hw_register_supported_p (int gdb_regnum)
+{
+ gdb_assert (wtx_hw_register_map != NULL);
+ gdb_assert (gdb_regnum <= wtx_hw_register_map_len);
+
+ if (wtx_hw_register_map [gdb_regnum].register_offset == -1)
+ return 0; /* Offset unknown, register is not supported. */
+
+ return 1;
+}
+
+
+/* Fetch the value of a register given its GDB_REGNUM, and store it
+ inside REG_VAL.
+
+ Register numbering in GDB do not necessarily correspond to the
+ numbering used by WTX. This function translates the GDB_REGNUM
+ into a WTX register number before calling the WTX routine. */
+
+int
+wtx_hw_fetch_register (struct gdbarch *gdbarch,
+ WTX_CONTEXT_TYPE context_type,
+ WTX_CONTEXT_ID_T context_id,
+ int gdb_regnum,
+ gdb_byte *reg_val)
+{
+ if (!wtx_hw_register_supported_p (gdb_regnum))
+ return 0;
+
+ return wtxapi_regs_get (context_type, context_id,
+ wtx_hw_register_map [gdb_regnum].register_set,
+ wtx_hw_register_map [gdb_regnum].register_offset,
+ register_size (gdbarch, gdb_regnum),
+ reg_val);
+}
+
+/* Fetch the value of the given register given its GDB_REGNUM,
+ and store it inside REG_VAL. Instead of using WTX to read
+ the register value, read the register value from the memory
+ region where the registers have been saved for this task.
+
+ REGS_ADDR is the base address where the GP registers have been saved.
+ FP_REGS_ADDR, is the base address where the FP registers have been saved.
+
+ GP registers are always supported, and FP registers are supported
+ only if FP_REGS_ADDR is not zero. Other registers (Eg altivec registers)
+ are not supported in this mode. */
+
+int
+wtx_hw_fetch_register_in_memory (struct gdbarch *gdbarch,
+ WTX_CONTEXT_TYPE context_type,
+ WTX_CONTEXT_ID_T context_id,
+ CORE_ADDR regs_addr,
+ CORE_ADDR fp_regs_addr,
+ int gdb_regnum,
+ gdb_byte *reg_val)
+{
+ int reg_offset;
+ CORE_ADDR reg_addr = 0;
+
+ if (!wtx_hw_register_supported_p (gdb_regnum))
+ return 0;
+
+ reg_offset = wtx_hw_register_map [gdb_regnum].register_offset;
+ switch (wtx_hw_register_map [gdb_regnum].register_set)
+ {
+ case WTX_REG_SET_IU:
+ reg_addr = regs_addr + reg_offset;
+ break;
+ case WTX_REG_SET_FPU:
+ if (fp_regs_addr != 0)
+ reg_addr = fp_regs_addr + reg_offset;
+ break;
+ }
+
+ if (reg_addr == 0)
+ /* We couldn't determine the location where the register is stored. */
+ return 0;
+
+ return (wtxapi_mem_read (wtxapi_pd_current_get (), reg_addr, reg_val,
+ register_size (gdbarch, gdb_regnum))
+ != WTX_ERROR);
+}
+
+/* Store the value from REG_VAL into the register identified by
+ GDB_REGNUM.
+
+ Register numbering in GDB do not necessarily correspond to the
+ numbering used by WTX. This function translates the GDB_REGNUM
+ into a WTX register number before calling the WTX routine. */
+
+int
+wtx_hw_store_register (struct gdbarch *gdbarch, WTX_CONTEXT_TYPE context_type,
+ WTX_CONTEXT_ID_T context_id,
+ int gdb_regnum,
+ gdb_byte *reg_val)
+{
+ /* brobecker/2007-10-16: On powerpc targets, there seems to be a bug
+ in the VxWorks system that causes the storing of the msr register
+ to fail. Although the WTX request returns with no error, the actual
+ new value of the msr is often zero instead of the intended value,
+ later causing dramatic issues such as floating-point exceptions or
+ even system-wide crashes. So we simply silently ignore stores to
+ that register for now. */
+ if (wtx_hw_register_map == ppc_register_map
+ && gdb_regnum == 65)
+ return 0;
+
+ if (!wtx_hw_register_supported_p (gdb_regnum))
+ return 0;
+
+ return wtxapi_regs_set (context_type, context_id,
+ wtx_hw_register_map [gdb_regnum].register_set,
+ wtx_hw_register_map [gdb_regnum].register_offset,
+ register_size (gdbarch, gdb_regnum),
+ reg_val);
+}
+
+/* Store the value from REG_VAL into the register identified by
+ GDB_REGNUM. Instead of using WTX to write the register value,
+ we write the new value in the memory region where the register
+ has been saved for this task.
+
+ REGS_ADDR is the base address where the GP registers have been saved.
+ FP_REGS_ADDR, is the base address where the FP registers have been saved.
+
+ GP registers are always supported, and FP registers are supported
+ only if FP_REGS_ADDR is not zero. Other registers (Eg altivec registers)
+ are not supported in this mode. */
+
+int
+wtx_hw_store_register_in_memory (struct gdbarch *gdbarch,
+ WTX_CONTEXT_TYPE context_type,
+ WTX_CONTEXT_ID_T context_id,
+ CORE_ADDR regs_addr,
+ CORE_ADDR fp_regs_addr,
+ int gdb_regnum,
+ gdb_byte *reg_val)
+{
+ int reg_offset;
+ CORE_ADDR reg_addr = 0;
+
+ if (!wtx_hw_register_supported_p (gdb_regnum))
+ return 0;
+
+ reg_offset = wtx_hw_register_map [gdb_regnum].register_offset;
+ switch (wtx_hw_register_map [gdb_regnum].register_set)
+ {
+ case WTX_REG_SET_IU:
+ reg_addr = regs_addr + reg_offset;
+ break;
+ case WTX_REG_SET_FPU:
+ if (fp_regs_addr != 0)
+ reg_addr = fp_regs_addr + reg_offset;
+ break;
+ }
+
+ if (reg_addr == 0)
+ return 0;
+
+ return (wtxapi_mem_write (wtxapi_pd_current_get (), reg_val, reg_addr,
+ register_size (gdbarch, gdb_regnum))
+ != WTX_ERROR);
+}
diff --git a/gdb/remote-wtx-hw.h b/gdb/remote-wtx-hw.h
new file mode 100644
index 0000000..b1c5af4
--- /dev/null
+++ b/gdb/remote-wtx-hw.h
@@ -0,0 +1,56 @@
+/* Support for the WTX protocol.
+
+ Copyright (C) 2007, 2010, 2011 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#ifndef REMOTE_WTX_HW_H
+#define REMOTE_WTX_HW_H
+
+#include "defs.h"
+#include "remote-wtxapi.h"
+
+extern void wtx_hw_initialize (void);
+
+extern int wtx_hw_fetch_register (struct gdbarch *gdbarch,
+ WTX_CONTEXT_TYPE context_type,
+ WTX_CONTEXT_ID_T context_id,
+ int gdb_regnum,
+ gdb_byte *reg_val);
+
+extern int wtx_hw_fetch_register_in_memory (struct gdbarch *gdbarch,
+ WTX_CONTEXT_TYPE context_type,
+ WTX_CONTEXT_ID_T context_id,
+ CORE_ADDR regs_addr,
+ CORE_ADDR fp_regs_addr,
+ int gdb_regnum,
+ gdb_byte *reg_val);
+
+extern int wtx_hw_store_register (struct gdbarch *gdbarch,
+ WTX_CONTEXT_TYPE context_type,
+ WTX_CONTEXT_ID_T context_id,
+ int gdb_regnum,
+ gdb_byte *reg_val);
+
+extern int wtx_hw_store_register_in_memory (struct gdbarch *gdbarch,
+ WTX_CONTEXT_TYPE context_type,
+ WTX_CONTEXT_ID_T context_id,
+ CORE_ADDR regs_addr,
+ CORE_ADDR fp_regs_addr,
+ int gdb_regnum,
+ gdb_byte *reg_val);
+
+#endif
--
1.7.0.4
^ permalink raw reply [flat|nested] 54+ messages in thread
* [PATCH 14/18] WTX-TCL support module
2011-02-24 17:49 Add support for VxWorks 5.x, 6.x and 653 Joel Brobecker
` (12 preceding siblings ...)
2011-02-24 17:57 ` [PATCH 12/18] remote-wtx-hw: register fetch/store support Joel Brobecker
@ 2011-02-24 17:57 ` Joel Brobecker
2011-02-25 15:59 ` Tom Tromey
2011-02-24 17:58 ` [PATCH 15/18] Add support for VxWorks 6 Joel Brobecker
` (3 subsequent siblings)
17 siblings, 1 reply; 54+ messages in thread
From: Joel Brobecker @ 2011-02-24 17:57 UTC (permalink / raw)
To: gdb-patches; +Cc: Joel Brobecker
For VxWorks 5.x and 653, we need to use the TCL extension in order to
access some of the information we are looking for (list of VxWorks
tasks running on the target, for instance). This is only because
the WTX protocol does not provide access to this info.
gdb/ChangeLog:
* remote-wtx-tcl.c: New file.
---
gdb/remote-wtx-tcl.c | 539 ++++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 539 insertions(+), 0 deletions(-)
create mode 100644 gdb/remote-wtx-tcl.c
diff --git a/gdb/remote-wtx-tcl.c b/gdb/remote-wtx-tcl.c
new file mode 100644
index 0000000..e2ca31b
--- /dev/null
+++ b/gdb/remote-wtx-tcl.c
@@ -0,0 +1,539 @@
+/* Access to the TCL module in VxWorks systems.
+
+ Copyright 2007, 2010, 2011 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#include "defs.h"
+#include "command.h"
+#include "gdb_string.h"
+#include "remote-wtx-opt.h"
+#include "remote-wtxapi.h"
+#include "gdb_stat.h"
+#include "gdb_assert.h"
+#include "remote-wtx-pd.h"
+#include "remote-wtx-utils.h"
+
+/* Includes from the VxWorks install. */
+#define HOST
+#include "tcl.h"
+#if WTX_PROT_VERSION != 4
+#include "wtxtcl.h"
+#endif
+
+/* Some functions provided by libwtxtcl that we use. These are resolved
+ during this unit's initialization phase. */
+static char * (*wtx_tcl_handle_grant) (Tcl_Interp *pInterp, HWTX hWtx);
+static int (*wtx_tcl_init) (Tcl_Interp *pInterp);
+static int (*tcl_eval) (Tcl_Interp *interp, const char *script);
+static char * (*tcl_get_var) (Tcl_Interp *interp, const char *var_name,
+ int flags);
+static int (*tcl_find_executable) (const char * argv0);
+static Tcl_Interp * (*tcl_create_interp) ();
+
+/* Non-zero if the system provides support for computing the address
+ of the memory region where the FP registers are saved for each task.
+ Zero otherwise. */
+static int tcb_has_fp_regs_p = 0;
+
+static Tcl_Interp *tcl_handle = NULL;
+
+/* Evaluate the given TCL expression (STR), and return non-zero if
+ successful.
+
+ When successful, then OUTPUT will contain the evaluation output.
+ When the evaluation fails, OUTPUT contains the error message. */
+
+static int
+wtxtcl_eval (char *str, char **output)
+{
+ const int status = tcl_eval (tcl_handle, str);
+
+ if (tcl_handle->result != NULL)
+ *output = tcl_handle->result;
+ else
+ *output = "";
+
+ /* If the evaluation failed, and the user requested verbose TCL error
+ messages, then fetch the error message from the value of the "errorInfo"
+ variable instead of using the standard (short) error message. */
+
+ if (status == TCL_ERROR && wtx_opt_tcl_verbose_p ())
+ *output = (char *) tcl_get_var (tcl_handle, "errorInfo", 0);
+
+ return (status != TCL_ERROR);
+}
+
+/* Evaluate the given TCL expression (STR), and return non-zero if
+ successful.
+
+ When successful, the evaluation output is printed on standard output.
+ Otherwise, the error message is printed on standard output. */
+
+static int
+wtxtcl_eval_verbose (char *str)
+{
+ char *output;
+ const int success = wtxtcl_eval (str, &output);
+
+ if (success)
+ printf_filtered ("%s\n", output);
+ else
+ printf_filtered (_("TCL error: %s\n"), output);
+
+ return success;
+}
+
+/* Implement the "tcl" command. */
+
+static void
+tcl_command (char *args, int from_tty)
+{
+ if (args == NULL)
+ return;
+
+ wtxtcl_eval_verbose (args);
+}
+
+/* Return the full path name of the "shell.tcl" TCL file that should
+ be part of the VxWorks system installation on the host.
+
+ Return NULL if the file could not be found. */
+
+static const char *
+shell_tcl_fullpath (void)
+{
+ const char *base_dir;
+ static char *shell_tcl = NULL;
+ struct stat stat_info;
+
+ if (shell_tcl != NULL)
+ return shell_tcl;
+
+ /* First option: See if we can find the shell.tcl file using
+ the WIND_BASE environment variable. */
+
+ base_dir = getenv ("WIND_BASE");
+ if (base_dir != NULL)
+ {
+ shell_tcl = xstrprintf ("%s%shost%sresource%stcl%sshell.tcl",
+ base_dir, SLASH_STRING, SLASH_STRING,
+ SLASH_STRING, SLASH_STRING);
+
+ if (stat (shell_tcl, &stat_info) == 0) /* Found it! */
+ return shell_tcl;
+
+ xfree (shell_tcl);
+ }
+
+ /* Second option: Try with the WIND_FOUNDATION_PATH environment variable
+ as the root install directory. */
+
+ base_dir = getenv ("WIND_FOUNDATION_PATH");
+ if (base_dir != NULL)
+ {
+ shell_tcl =
+ xstrprintf ("%s%sresource%swindsh%svxWorks653%stcl%sshell.tcl",
+ base_dir, SLASH_STRING, SLASH_STRING, SLASH_STRING,
+ SLASH_STRING, SLASH_STRING);
+
+ if (stat (shell_tcl, &stat_info) == 0) /* Found it! */
+ return shell_tcl;
+
+ xfree (shell_tcl);
+ }
+
+ /* Not found. */
+
+ shell_tcl = NULL;
+ return shell_tcl;
+}
+
+/* Source a TCL script given its full path name. */
+
+static int
+wtxtcl_source_file (const char *fullpath)
+{
+ char *source_expr = xstrprintf ("source %s", fullpath);
+ int success;
+
+ success = wtxtcl_eval_verbose (source_expr);
+ xfree (source_expr);
+ return success;
+}
+
+/* Initialize the TCL engine for use by GDB. This should performed
+ after the debugger is connected to the target server. */
+
+static void
+wtxtcl_initialize (HWTX wtx_handle)
+{
+ const char *shell_tcl = shell_tcl_fullpath ();
+ int success;
+
+ /* shell.tcl and shellInit are defined in every version of VxWorks;
+ so, if it cannot be found, loaded, or initialized, this should return
+ an error, not a warning. */
+
+ if (shell_tcl == NULL)
+ error (_("Could not locate shell.tcl"));
+
+ /* Tell our TCL handle which WTX connection to use. */
+ wtx_tcl_handle_grant (tcl_handle, wtx_handle);
+
+ /* Source shell.tcl. */
+ success = wtxtcl_source_file (shell_tcl);
+ if (!success)
+ error (_("Could not load shell.tcl"));
+
+ /* Evaluate the shellInit function from shell.tcl. */
+ success = wtxtcl_eval_verbose ("shellInit");
+ if (!success)
+ error (_("Could not initialize shell.tcl "));
+}
+
+/* Implement the "get_task_pd" method of the wtxapi_support_ops vector.
+ (see remote-wtxapi.h for more details. */
+
+static int
+wtxtcl_get_task_pd (int task_id, pd_id_t *task_pd)
+{
+ char *tcl_cmd;
+ char *task_info;
+ int success;
+ int j;
+
+ gdb_assert (task_pd != NULL);
+
+ /* If the system does not support partitions, then return the NULL_PD. */
+
+ if (!wtx_pd_system_has_pds ())
+ {
+ *task_pd = NULL_PD;
+ return 1;
+ }
+
+ tcl_cmd = xstrprintf ("taskInfoGet 0x%x", task_id);
+ success = wtxtcl_eval (tcl_cmd, &task_info);
+
+ if (!success) /* The task probably no longer exist... */
+ return 0;
+
+ /* Skip the first 8 tokens and go directly to the 9th, which contains
+ the PD ID. */
+ for (j = 0; j < 8; j++)
+ task_info = skip_space_delimited_token (task_info);
+
+ *task_pd = strtoul (task_info, NULL, 16);
+ return 1;
+}
+
+static struct wtxapi_thread_info *
+wtxtcl_get_thread_list (void)
+{
+ /* The gopher expression to be used on VxWorks 5.x (WTX version 2). */
+ const char *wtx2_gopher_expr =
+ "[shSymAddr activeQHead] *"
+ "{"
+ "<"
+ "-$offset(WIND_TCB,activeNode) !"
+ "<+$offset(WIND_TCB,name) *$>"
+ "<+$offset(WIND_TCB,pStackBase) @>"
+ "<+$offset(WIND_TCB,pStackEnd) @>"
+ "<+$offset(WIND_TCB,regs) !>"
+ "<0 !>" /* FP registers are not accessible on vxWorks 5.x. */
+ ">"
+ "*"
+ "}";
+
+ /* The gopher expression to be used on VxWorks 653 (WTX versions 3 & 4). */
+ const char *wtx3_gopher_expr =
+ "[shSymAddr taskClassId] *"
+ "+$offset(OBJ_CLASS,objList) *"
+ "{"
+ "<"
+ "-$offset(OBJ_CORE,classNode) !"
+ "<$objNameGopherString>"
+ "<+$offset(WIND_TCB,pStackBase) @>"
+ "<+$offset(WIND_TCB,pStackEnd) @>"
+ "<+$offset(WIND_TCB,regs) !>"
+ "<+$offset(WIND_TCB,pFpContext) * +$offset(FP_CONTEXT,fpr) !>"
+ "> "
+ "*"
+ "}";
+
+ /* The following expression is an expression that can be used on old
+ vxWorks 653 systems (WTX version 3 & 4) that do not provide
+ convenient access to the location of the FP registers in the TCB.
+ It is provided to remain compatible with those older systems, and
+ is identical to WTX3_GOPHER_EXPR except that zero is returned in
+ place of the FP register address. */
+ const char *wtx3_gopher_expr_fallback =
+ "[shSymAddr taskClassId] *"
+ "+$offset(OBJ_CLASS,objList) *"
+ "{"
+ "<"
+ "-$offset(OBJ_CORE,classNode) !"
+ "<$objNameGopherString>"
+ "<+$offset(WIND_TCB,pStackBase) @>"
+ "<+$offset(WIND_TCB,pStackEnd) @>"
+ "<+$offset(WIND_TCB,regs) !>"
+ "<0 !>"
+ "> "
+ "*"
+ "}";
+
+ const char *gopher_expr;
+ char *tcl_expr;
+ char *tcl_output;
+ char *current_thread;
+ int success;
+ struct wtxapi_thread_info *thread_list_head = NULL;
+
+ /* Select the gopher expression that is appropriate for our system. */
+
+ if (WTX_PROT_VERSION == 2)
+ gopher_expr = wtx2_gopher_expr;
+ else if (tcb_has_fp_regs_p)
+ gopher_expr = wtx3_gopher_expr;
+ else
+ gopher_expr = wtx3_gopher_expr_fallback;
+
+ /* Evaluate the gopher expression. */
+
+ tcl_expr = xstrprintf ("wtxGopherEval \"%s\"", gopher_expr);
+ success = wtxtcl_eval (tcl_expr, &tcl_output);
+ xfree (tcl_expr);
+
+ if (!success)
+ {
+ warning (_("Failed to get thread list, TCL returned: %s"), tcl_output);
+ return NULL;
+ }
+
+ /* Parse the result. */
+
+ current_thread = skip_whitespace (tcl_output);
+ while (current_thread && *current_thread != '\0')
+ {
+ struct wtxapi_thread_info *new_thread
+ = xmalloc (sizeof (struct wtxapi_thread_info));
+
+ /* Get the thread id. */
+ new_thread->id = strtoul (current_thread, NULL, 0);
+ current_thread = skip_space_delimited_token (current_thread);
+
+ /* Get the thread name. */
+ current_thread = skip_whitespace (current_thread);
+ if (*current_thread == '{')
+ {
+ /* The thread name delimited by curly braces. Find the
+ closing curly brace. */
+ char *start = current_thread + 1; /* skip the '{'... */
+ char *end = skip_until_character (current_thread, '}');
+ char tmp = *end;
+
+ current_thread = end + 1; /* discard the '}' marker. */
+
+ *end = '\0';
+ new_thread->name = strdup (start);
+ *end = tmp;
+ }
+ else
+ current_thread = get_space_delimited_token (current_thread,
+ &new_thread->name);
+
+ /* Skip the stack base and the stack end. */
+ current_thread = skip_space_delimited_token (current_thread);
+ current_thread = skip_space_delimited_token (current_thread);
+
+ /* Get the address where the GP registers are stored. */
+ new_thread->regs_addr = strtoul (current_thread, 0, 16);
+ current_thread = skip_space_delimited_token (current_thread);;
+
+ /* Get the address where the FP registers are stored. */
+ new_thread->fp_regs_addr = strtoul (current_thread, 0, 16);
+ current_thread = skip_space_delimited_token (current_thread);;
+
+ /* Link in the new thread_info to our list. */
+ new_thread->next = thread_list_head;
+ thread_list_head = new_thread;
+
+ /* Advance to the begining of the next thread block. */
+ current_thread = skip_whitespace (current_thread);
+ }
+
+ return thread_list_head;
+}
+
+static WTX_CONTEXT_ID_T
+wtxtcl_system_mode_get_current_context_id (void)
+{
+ int success;
+ char *tcl_output;
+
+ success = wtxtcl_eval ("taskIdCurrent", &tcl_output);
+ if (!success)
+ error (_("taskIdCurrent failed: %s"), tcl_output);
+
+ return strtoul (tcl_output, NULL, 0);
+}
+
+static int
+wtxtcl_system_mode_support_p ()
+{
+ char *ignored;
+
+ /* Check to see if the system TCL script provide a couple of definitions
+ that we need in order to access the FP registers when in system mode.
+ These are not defined in old versions of VxWorks.
+ Warn the user of the consequences if the definitions are missing. */
+ tcb_has_fp_regs_p =
+ (wtxtcl_eval ("return $offset(WIND_TCB,pFpContext)", &ignored)
+ && wtxtcl_eval ("return $offset(FP_CONTEXT,fpr)", &ignored));
+ if (!tcb_has_fp_regs_p)
+ warning (_("\
+system does not support access to the FP registers in system mode"));
+
+ return 1;
+}
+
+static struct wtxapi_support_ops wtxtcl_support_ops;
+
+static void
+initialize_wtx_support_ops ()
+{
+ wtxtcl_support_ops.wtx_connection_established_callback = wtxtcl_initialize;
+ wtxtcl_support_ops.get_thread_list = wtxtcl_get_thread_list;
+ wtxtcl_support_ops.get_task_pd = wtxtcl_get_task_pd;
+ wtxtcl_support_ops.system_mode_support_p = wtxtcl_system_mode_support_p;
+ wtxtcl_support_ops.system_mode_get_current_context_id =
+ wtxtcl_system_mode_get_current_context_id;
+}
+
+/* Search for SYM_NAME in the given library and return its address.
+ Throw an error if the symbol could not be found. LIB is a non-NULL
+ handle on the library, as returned by load_shared_lib. */
+static void *
+wtx_tcl_resolve (void *lib, char *sym_name)
+{
+ void *result = get_symbol_from_shared_lib (lib, sym_name);
+
+ if (!result)
+ error (_("Cannot find `%s' in WTX-TCL library"), sym_name);
+ return result;
+}
+
+/* Load all tcl-related libraries, and resolve all the addresses
+ of the functions we use from these libraries. Throws an error
+ if anything wrong happens. */
+static void
+load_wtx_tcl_libraries (void)
+{
+ void *lib = NULL;
+
+ /* Load tcl libraries. These have a different name on unix and
+ win32; e.g. libtcl8.5 on unix would be libtcl85 on win32. */
+
+ if (WTX_PROT_VERSION == 4)
+ {
+ /* WTX 4.0 uses tcl 8.4; WTX 4.1 uses tcl 8.5. */
+
+ lib = load_shared_lib ("tcl85");
+
+ if (!lib)
+ lib = load_shared_lib ("tcl8.5");
+
+ if (!lib)
+ lib = load_shared_lib ("tcl84");
+
+ if (!lib)
+ lib = load_shared_lib ("tcl8.4");
+ }
+ else
+ {
+ /* WTX 2 and 3 are both based on tcl 8.0. */
+
+ lib = load_shared_lib ("tcl80");
+
+ if (!lib)
+ lib = load_shared_lib ("tcl8.0");
+
+ if (!lib)
+ lib = load_shared_lib ("tcl");
+ }
+
+ if (!lib)
+ error (_("Unable to load the tcl library"));
+
+ tcl_eval = wtx_tcl_resolve (lib, "Tcl_Eval");
+ tcl_get_var = wtx_tcl_resolve (lib, "Tcl_GetVar");
+ tcl_find_executable = wtx_tcl_resolve (lib, "Tcl_FindExecutable");
+ tcl_create_interp = wtx_tcl_resolve (lib, "Tcl_CreateInterp");
+
+ /* Then load WTX Tcl libraries. */
+
+ if (WTX_PROT_VERSION == 4)
+ {
+ lib = load_shared_lib ("wtxtcl41");
+
+ if (!lib)
+ lib = load_shared_lib ("wtxtcl40");
+ }
+ else if (WTX_PROT_VERSION == 3)
+ {
+ lib = load_shared_lib ("wtxtcl30");
+ }
+ else if (WTX_PROT_VERSION == 2)
+ {
+ lib = load_shared_lib ("wtxtcl");
+ }
+
+ if (!lib)
+ error (_("Unable to load the wtxtcl library"));
+
+ wtx_tcl_init = wtx_tcl_resolve (lib, "wtxTclInit");
+ wtx_tcl_handle_grant = wtx_tcl_resolve (lib, "wtxTclHandleGrant");
+}
+
+void
+_initialize_remote_wtx_tcl (void)
+{
+ load_wtx_tcl_libraries ();
+
+ /* There seems to be a bug in the TCL library provided with PSC 2.x
+ which later causes "wtxTclInit" to crash unless we make the following
+ call to "Tcl_FindExecutable". */
+ if (WTX_PROT_VERSION == 4)
+ tcl_find_executable (NULL);
+
+ tcl_handle = tcl_create_interp ();
+ if (tcl_handle == NULL)
+ error (_("Failed to initialize TCL module"));
+
+ /* Make the WTX routines accessible from TCL. This is needed by
+ the TCL resource files that we will source later on, when we are
+ connected to the target server. */
+ wtx_tcl_init (tcl_handle);
+
+ add_com ("tcl", class_obscure, tcl_command,
+ _("Evaluate the arguments with the TCL interpreter"));
+
+ /* Provide TCL-based support routine to the WTX module. */
+ initialize_wtx_support_ops ();
+ wtxapi_set_support_ops (&wtxtcl_support_ops);
+}
+
--
1.7.0.4
^ permalink raw reply [flat|nested] 54+ messages in thread
* [PATCH 15/18] Add support for VxWorks 6
2011-02-24 17:49 Add support for VxWorks 5.x, 6.x and 653 Joel Brobecker
` (13 preceding siblings ...)
2011-02-24 17:57 ` [PATCH 14/18] WTX-TCL support module Joel Brobecker
@ 2011-02-24 17:58 ` Joel Brobecker
2011-02-24 17:59 ` [PATCH 16/18] Add tdep files for x86 and powerpc Joel Brobecker
` (2 subsequent siblings)
17 siblings, 0 replies; 54+ messages in thread
From: Joel Brobecker @ 2011-02-24 17:58 UTC (permalink / raw)
To: gdb-patches; +Cc: Joel Brobecker
gdb/ChangeLog:
* remote-dfw.c, remote-dfwapi.h, remote-dfwapi.c: New files.
---
gdb/remote-dfw.c | 93 ++
gdb/remote-dfwapi.c | 3250 +++++++++++++++++++++++++++++++++++++++++++++++++++
gdb/remote-dfwapi.h | 190 +++
3 files changed, 3533 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..7666729
--- /dev/null
+++ b/gdb/remote-dfw.c
@@ -0,0 +1,93 @@
+/* Remote target communications for VxWorks 6 targets.
+
+ Copyright 2005, 2011 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"
+
+/* 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 (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 = file_stratum;
+ remote_dfw_ops.to_magic = OPS_MAGIC;
+ remote_dfw_ops.to_open = remote_dfw_open;
+ remote_dfw_ops.to_close = remote_dfw_close;
+}
+
+void
+_initialize_remote_dfw (void)
+{
+ struct cmd_list_element *c;
+
+ init_remote_dfw_ops ();
+ add_target (&remote_dfw_ops);
+}
diff --git a/gdb/remote-dfwapi.c b/gdb/remote-dfwapi.c
new file mode 100644
index 0000000..fa068e0
--- /dev/null
+++ b/gdb/remote-dfwapi.c
@@ -0,0 +1,3250 @@
+/* Remote debugging API based on Wind River System's DFW protocol.
+
+ Copyright 2005, 2010, 2011 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+/* GENERAL DESCRIPTION:
+
+ This file implements an debug API based on Wind River System's
+ debugger framework. It is used to know which threads are running
+ on a VxWorks 6 target.
+
+ It uses two protocols:
+ * WTX: we only need one WTX call from the wind registry (to get the
+ connection parameters of the dfwserver).
+ * DFW: to ask the DFW server about threads running on target.
+
+ (X <---Y---> Z means "X communicates with Z using the protocol Y)
+
+ .-----. WTX .---------------.
+ | GDB |<------->| WIND REGISTRY |
+ | | `---------------'
+ | | DFW .------------. WTX .---------------. WDB .--------.
+ | |<------->| DFW SERVER |<------->| TARGET SERVER |<------>| TARGET |
+ `-----' `------------' `---------------' `--------'
+
+ A connection scenario:
+
+ (X --Y-->Z means "X sends the message Y to Z")
+
+ .-----. .---------------. .------------.
+ | GDB | | WIND REGISTRY | | DFW SERVER |
+ `-----' `---------------' `------------'
+ | wtxapi_info_q query | |
+ |------------------------->| |
+ | dfw connection params | |
+ |<-------------------------| |
+ | |
+ | -wrs-info-retrieve /Targets default:* ... |
+ |------------------------------------------->|
+ | list of known targets |
+ |<-------------------------------------------|
+
+ et cetera...
+
+ Here is a general description of the way we call a DFW primitive:
+ 1) we send the request (text format) to the DFW server;
+ 2) we reset the current_result_table and buffer the output in its
+ string_table after a lexical analysis (stored in the dfw_lex_tree);
+ 3) then, we do a syntactic analysis and we save the result on the
+ dfw_ast_tree.
+ 4) finally, we can extract the information from the ast table using the
+ ast_element interface.
+
+ The result of the ast and lex analysis are stored into preallocated
+ integer tables whose sizes are increased if needed. In those tables,
+ can be stored:
+ * lex (resp. ast) 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 ast table would be:
+
+ DFW_AST_RESULT_CLASS
+ done
+ DFW_AST_VARIABLE
+ i
+ DFW_AST_VALUE
+ DFW_AST_BEGIN_LIST
+ DFW_AST_VALUE
+ DFW_AST_BEGIN_LIST
+ DFW_AST_VALUE
+ DFW_AST_CONST
+ defaultTarget
+ DFW_AST_VALUE
+ DFW_AST_CONST
+ tgt_liege@borticado
+ DFW_AST_END_LIST
+ DFW_AST_END_LIST
+
+ (The grammar of the GDB/MI language is defined in the GDB documentation).
+*/
+
+
+#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. */
+
+/* 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 char default_dfw_server_name[] = "dfw";
+static char *dfw_server_name = NULL;
+
+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 dfw_timeout = 30;
+static int current_selected_thread = 0;
+
+/* Index type for tables (lex and ast) and buffer (strings): */
+
+typedef unsigned int index_type;
+
+/* Type of the elements in the lex (resp. ast) tables. */
+
+typedef int dfw_tree_element;
+
+/* Type of description of the lex (or ast) 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 syntactic analysis. */
+
+enum dfw_ast_type
+ {
+ DFW_AST_RESULT_CLASS,
+ DFW_AST_ASYNC_CLASS,
+ DFW_AST_VARIABLE,
+ DFW_AST_VALUE,
+ DFW_AST_RESULT,
+ DFW_AST_CONST,
+ DFW_AST_BEGIN_TUPLE,
+ DFW_AST_END_TUPLE,
+ DFW_AST_BEGIN_LIST,
+ DFW_AST_END_LIST,
+ DFW_AST_LAST
+ };
+
+/* Description record for the syntactic tree elements. */
+
+static const struct dfw_tree_element_desc dfw_ast_list[] =
+{
+ {DFW_AST_RESULT_CLASS, "DFW_AST_RESULT_CLASS", -1},
+ {DFW_AST_ASYNC_CLASS, "DFW_AST_ASYNC_CLASS", -1},
+ {DFW_AST_VARIABLE, "DFW_AST_VARIABLE", 1},
+ {DFW_AST_VALUE, "DFW_AST_VALUE", 0},
+ {DFW_AST_RESULT, "DFW_AST_RESULT", 0},
+ {DFW_AST_CONST, "DFW_AST_CONST", 1},
+ {DFW_AST_BEGIN_TUPLE, "DFW_AST_BEGIN_TUPLE", 0},
+ {DFW_AST_END_TUPLE, "DFW_AST_END_TUPLE", 0},
+ {DFW_AST_BEGIN_LIST, "DFW_AST_BEGIN_LIST", 0},
+ {DFW_AST_END_LIST, "DFW_AST_END_LIST", 0},
+ {DFW_AST_LAST,"DFW_AST_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 ast 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 syntactic 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;
+
+ /* Ast tree of the DFW request result. */
+
+ struct dfw_tree_type dfw_ast_tree;
+};
+
+/* Syntactic 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 ast table:
+
+ DFW_AST_CONST
+ defaultTarget
+
+ would correspond to a syntactic element SE, with:
+ SE.type == DFW_AST_CONST
+ strcmp (SE.value.string_value, "defaultTarget") == 0
+*/
+
+struct dfw_ast_element
+{
+ enum dfw_ast_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 ast 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);
+
+/* Ast 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 ast table and get ast elements from
+ the indices in the ast tree table. */
+
+static struct dfw_ast_element next_ast_element (struct result_table *result,
+ index_type *current_index);
+
+static struct dfw_ast_element next_ast_element_with_check
+(struct result_table *result, index_type *current_index,
+ const char *request_desc, enum dfw_ast_type type);
+
+static struct dfw_ast_element ast_element_process_result_header
+(struct result_table *result, index_type *current_index,
+ const char *request_desc);
+
+static struct dfw_ast_element ast_element_process_wrs_info_header
+(struct result_table *result, index_type *current_index,
+ const char *request_desc);
+
+static struct dfw_ast_element ast_element_process_list_value_header
+(struct result_table *result, index_type *current_index,
+ const char *request_desc);
+
+static struct dfw_ast_element ast_element_process_const_string_value
+(struct result_table *result, index_type *current_index,
+ const char *request_desc, char **string_value);
+
+static struct dfw_ast_element ast_element_process_const_integer_value
+(struct result_table *result, index_type *current_index,
+ const char *request_desc, int *const_value);
+
+static struct dfw_ast_element ast_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);
+
+/* 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;
+}
+
+/* Get the syntactic 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 syntactic element in
+ RESULT. */
+
+static struct dfw_ast_element
+next_ast_element (struct result_table *result, index_type *current_index)
+{
+ enum dfw_ast_type ast;
+ dfw_tree_element item;
+ struct dfw_tree_type *ast_table = &(result->dfw_ast_tree);
+ struct dfw_ast_element element;
+
+ memset (&element, 0, sizeof (element));
+
+ ast = ast_table->beginning_of_table[*current_index];
+ element.type = ast;
+
+ switch (ast)
+ {
+ case DFW_AST_VALUE:
+ case DFW_AST_RESULT:
+ case DFW_AST_BEGIN_TUPLE:
+ case DFW_AST_END_TUPLE:
+ case DFW_AST_BEGIN_LIST:
+ case DFW_AST_END_LIST:
+ case DFW_AST_LAST:
+ /* No parameter, so nothing else to do. */
+ break;
+
+ case DFW_AST_VARIABLE:
+ case DFW_AST_CONST:
+ /* String parameter. */
+ (*current_index)++;
+ item = ast_table->beginning_of_table[*current_index];
+ element.value.string_value =
+ string_buffer_get_string_address (&(result->string_table), item);
+ break;
+
+ case DFW_AST_RESULT_CLASS:
+ (*current_index)++;
+ item = ast_table->beginning_of_table[*current_index];
+ element.value.dfwapi_async_class_value = item;
+ break;
+ case DFW_AST_ASYNC_CLASS:
+ (*current_index)++;
+ item = ast_table->beginning_of_table[*current_index];
+ element.value.result_class_value = item;
+ break;
+ default:
+ error (_("ast %d is not understood"), ast);
+ break;
+ }
+
+ /* Sibling. */
+ (*current_index)++;
+ element.sibling = ast_table->beginning_of_table[*current_index];
+
+ (*current_index)++;
+ return element;
+}
+
+/* Same as next_ast_element, but if the syntactic element pointed by
+ CURRENT_INDEX is not of type TYPE, an error is raised. */
+
+static struct dfw_ast_element
+next_ast_element_with_check (struct result_table *result,
+ index_type *current_index,
+ const char *request_desc,
+ enum dfw_ast_type type)
+{
+ struct dfw_ast_element element = next_ast_element (result, current_index);
+
+ if (element.type != type)
+ error (_("DFW: parse error in %s; waiting %s, got %s"),
+ request_desc, dfw_ast_list [type].name,
+ dfw_ast_list [element.type].name);
+
+ return element;
+}
+
+static int
+test_next_ast_element (struct result_table *result,
+ index_type current_index,
+ enum dfw_ast_type type)
+{
+ index_type tmp_index = current_index;
+ struct dfw_ast_element element = next_ast_element (result, &tmp_index);
+ return element.type == type;
+}
+
+/* Read the result header syntactic 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 syntactic 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 syntactic
+ information:
+
+ DFW_AST_RESULT_CLASS
+ done
+ DFW_AST_VARIABLE
+ i
+ DFW_AST_VALUE
+ [...]
+
+ This function would return a dfw_ast_element containing {DFW_AST_VARIANLE,
+ "i"} and current_index would then point to the DFW_AST_VALUE item. */
+
+static struct dfw_ast_element
+ast_element_process_result_header (struct result_table *result,
+ index_type *current_index,
+ const char *request_desc)
+{
+ struct dfw_ast_element element = next_ast_element (result, current_index);
+ if (element.type != DFW_AST_RESULT_CLASS
+ || element.value.result_class_value == RESULT_CLASS_ERROR)
+ error (_("DFW: error in %s."), request_desc);
+
+ if (*current_index < current_result_record.dfw_ast_tree.table_end)
+ element = next_ast_element_with_check (result, current_index, request_desc,
+ DFW_AST_VARIABLE);
+
+ return element;
+}
+
+static struct dfw_ast_element
+ast_element_process_wrs_info_header (struct result_table *result,
+ index_type *current_index,
+ const char *request_desc)
+{
+ ast_element_process_result_header (result, current_index, request_desc);
+ return ast_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_AST_VALUE
+ DFW_AST_BEGIN_LIST
+ DFW_AST_VARIABLE
+
+ and return the DFW_AST_VARIABLE read.
+*/
+
+static struct dfw_ast_element
+ast_element_process_list_value_header (struct result_table *result,
+ index_type *current_index,
+ const char *request_desc)
+{
+ struct dfw_ast_element element;
+
+ element = next_ast_element_with_check (result, current_index, request_desc,
+ DFW_AST_VALUE);
+ element = next_ast_element_with_check (result, current_index, request_desc,
+ DFW_AST_BEGIN_LIST);
+ element = next_ast_element_with_check (result, current_index, request_desc,
+ DFW_AST_VARIABLE);
+ return element;
+}
+
+
+
+
+/* Read the syntactic info pointed by CURRENT_INDEX into the RESULT table,
+ assuming that it is a pair (value, const). exempli gratia:
+
+ DFW_AST_VALUE
+ DFW_AST_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_AST_CONST element;
+ * the function returns a dfw_ast_element containing the DFW_AST_CONST
+ and its string parameter. */
+
+static struct dfw_ast_element
+ast_element_process_const_string_value (struct result_table *result,
+ index_type *current_index,
+ const char *request_desc,
+ char **string_value)
+{
+ struct dfw_ast_element element =
+ next_ast_element_with_check (result, current_index, request_desc,
+ DFW_AST_VALUE);
+
+ element = next_ast_element_with_check (result, current_index, request_desc,
+ DFW_AST_CONST);
+
+ *string_value = element.value.string_value;
+ return element;
+}
+
+/* Same thing as ast_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_ast_element
+ast_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_ast_element element =
+ ast_element_process_const_string_value (result, current_index,
+ request_desc,
+ &string_value);
+ *const_value = atoi (string_value);
+ return element;
+}
+
+/* Same thing as ast_element_process_const_integer_value, for a CORE_ADDR
+ value in hexademal format (e.g. "0xDEADBEEF"). */
+
+static struct dfw_ast_element
+ast_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_ast_element element =
+ ast_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_ast_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_ast_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_ast_tree),
+ (dfw_tree_element) DFW_AST_RESULT_CLASS);
+ dfw_tree_push (&(current_result_record.dfw_ast_tree),
+ (dfw_tree_element) request_result);
+ sibling_index_location =
+ dfw_tree_push (&(current_result_record.dfw_ast_tree), 0);
+
+ if (current != '\n')
+ read_result_list (¤t_result_record);
+
+ sibling_index = current_result_record.dfw_ast_tree.table_end;
+ dfw_tree_set (&(current_result_record.dfw_ast_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 syntactic 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 syntactic 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 ast 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_AST_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_AST_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_AST_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_AST_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_AST_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"),
+ 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_ast_tree), (dfw_tree_element) DFW_AST_VARIABLE);
+
+ item = table->dfw_lex_tree.beginning_of_table[*current_index];
+ dfw_tree_push (&(table->dfw_ast_tree), item);
+ (*current_index)++;
+ dfw_tree_push (&(table->dfw_ast_tree), table->dfw_ast_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_ast_tree), (dfw_tree_element) DFW_AST_CONST);
+
+ item = table->dfw_lex_tree.beginning_of_table[*current_index];
+ dfw_tree_push (&(table->dfw_ast_tree), item);
+ (*current_index)++;
+ dfw_tree_push (&(table->dfw_ast_tree), table->dfw_ast_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_ast_tree),
+ (dfw_tree_element) DFW_AST_BEGIN_TUPLE);
+ sibling_index_location = dfw_tree_push (&(table->dfw_ast_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_ast_tree), (dfw_tree_element) DFW_AST_END_TUPLE);
+ dfw_tree_push (&(table->dfw_ast_tree), table->dfw_ast_tree.table_end + 1);
+ sibling_index = table->dfw_ast_tree.table_end;
+ dfw_tree_set (&(table->dfw_ast_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_ast_tree),
+ (dfw_tree_element) DFW_AST_BEGIN_LIST);
+ sibling_index_location = dfw_tree_push (&(table->dfw_ast_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"));
+ }
+
+ 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_ast_tree),
+ (dfw_tree_element) DFW_AST_END_LIST);
+ dfw_tree_push (&(table->dfw_ast_tree), table->dfw_ast_tree.table_end + 1);
+ sibling_index = table->dfw_ast_tree.table_end;
+ dfw_tree_set (&(table->dfw_ast_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_ast_tree), (dfw_tree_element) DFW_AST_VALUE);
+ sibling_index_location = dfw_tree_push (&(table->dfw_ast_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_ast_tree.table_end;
+ dfw_tree_set (&(table->dfw_ast_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);
+}
+
+/* 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_ast_element ast_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;
+ ast_element_process_wrs_info_header (¤t_result_record, ¤t_index,
+ new_thread_desc);
+
+ next_ast_element_with_check (¤t_result_record, ¤t_index,
+ new_thread_desc, DFW_AST_VALUE);
+ next_ast_element_with_check (¤t_result_record, ¤t_index,
+ new_thread_desc, DFW_AST_BEGIN_LIST);
+
+ /* Go through the kernel task list: */
+ while (current_index < current_result_record.dfw_ast_tree.table_end)
+ {
+ if (test_next_ast_element (¤t_result_record, current_index,
+ DFW_AST_END_LIST))
+ break;
+
+ /* Id */
+
+ ast_element = next_ast_element_with_check
+ (¤t_result_record, ¤t_index,
+ new_thread_desc, DFW_AST_VARIABLE);
+ ast_element_process_const_integer_value
+ (¤t_result_record, ¤t_index,
+ new_thread_desc, &dfw_id);
+
+ /* ParentId */
+
+ ast_element = next_ast_element_with_check
+ (¤t_result_record, ¤t_index,
+ new_thread_desc, DFW_AST_VARIABLE);
+ ast_element_process_const_integer_value
+ (¤t_result_record, ¤t_index,
+ new_thread_desc, &parent_dfw_id);
+
+ /* TID */
+
+ ast_element = next_ast_element_with_check
+ (¤t_result_record, ¤t_index,
+ new_thread_desc, DFW_AST_VARIABLE);
+ ast_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;
+ ast_element_process_wrs_info_header (¤t_result_record, ¤t_index,
+ new_thread_desc);
+
+ next_ast_element_with_check (¤t_result_record, ¤t_index,
+ new_thread_desc, DFW_AST_VALUE);
+ next_ast_element_with_check (¤t_result_record, ¤t_index,
+ new_thread_desc, DFW_AST_BEGIN_LIST);
+
+ /* Go through the rtp list: */
+ while (current_index < current_result_record.dfw_ast_tree.table_end)
+ {
+ if (test_next_ast_element (¤t_result_record, current_index,
+ DFW_AST_END_LIST))
+ break;
+
+ /* RTP Id */
+
+ ast_element = next_ast_element_with_check
+ (¤t_result_record, ¤t_index,
+ new_thread_desc, DFW_AST_VARIABLE);
+ ast_element_process_const_integer_value
+ (¤t_result_record, ¤t_index,
+ new_thread_desc, &rtp_dfw_id);
+
+ /* RTP parent Id */
+
+ ast_element = next_ast_element_with_check
+ (¤t_result_record, ¤t_index,
+ new_thread_desc, DFW_AST_VARIABLE);
+ ast_element_process_const_integer_value
+ (¤t_result_record, ¤t_index,
+ new_thread_desc, &parent_dfw_id);
+
+ /* RTP TID */
+
+ ast_element = next_ast_element_with_check
+ (¤t_result_record, ¤t_index,
+ new_thread_desc, DFW_AST_VARIABLE);
+ ast_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_ast_element_with_check (¤t_result_record, ¤t_index,
+ new_thread_desc, DFW_AST_VARIABLE);
+ next_ast_element_with_check (¤t_result_record, ¤t_index,
+ new_thread_desc, DFW_AST_VALUE);
+ next_ast_element_with_check (¤t_result_record, ¤t_index,
+ new_thread_desc, DFW_AST_BEGIN_LIST);
+ while (current_index < current_result_record.dfw_ast_tree.table_end)
+ {
+ if (test_next_ast_element (¤t_result_record, current_index,
+ DFW_AST_END_LIST))
+ {
+ next_ast_element_with_check (¤t_result_record,
+ ¤t_index,
+ new_thread_desc,
+ DFW_AST_END_LIST);
+ break;
+ }
+
+ /* RTP task Id */
+
+ ast_element = next_ast_element_with_check
+ (¤t_result_record, ¤t_index,
+ new_thread_desc, DFW_AST_VARIABLE);
+ ast_element_process_const_integer_value
+ (¤t_result_record, ¤t_index,
+ new_thread_desc, &dfw_id);
+
+ /* RTP task parent Id */
+
+ ast_element = next_ast_element_with_check
+ (¤t_result_record, ¤t_index,
+ new_thread_desc, DFW_AST_VARIABLE);
+ ast_element_process_const_integer_value
+ (¤t_result_record, ¤t_index,
+ new_thread_desc, &parent_dfw_id);
+
+ /* RTP task TID */
+
+ ast_element = next_ast_element_with_check
+ (¤t_result_record, ¤t_index,
+ new_thread_desc, DFW_AST_VARIABLE);
+ ast_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;
+}
+
+static void
+init_dfw_server_name ()
+{
+ char *name = getenv ("DFW_SERVER_NAME");
+ if (name && name [0] != '\0')
+ dfw_server_name = xstrdup (name);
+ else
+ dfw_server_name = xstrdup (default_dfw_server_name);
+}
+
+/* (Re-)initialize every information stored in current_connection,
+ except full_target_name. */
+
+static void
+initialize_current_connection_info ()
+{
+ current_connection->system_dfw_id = 0;
+
+ if (current_connection->core_name)
+ {
+ xfree (current_connection->core_name);
+ current_connection->core_name = NULL;
+ }
+
+ if (current_connection->info_retrieval_core_branch)
+ {
+ xfree (current_connection->info_retrieval_core_branch);
+ current_connection->info_retrieval_core_branch = NULL;
+ }
+
+ if (current_connection->thread_id_leaf)
+ {
+ xfree (current_connection->thread_id_leaf);
+ current_connection->thread_id_leaf = NULL;
+ }
+
+ current_connection->info_retrieval_core_branch_len = 0;
+}
+
+/* Fill the current_connection record. Return 1 if everything went fine,
+ 0 otherwise. If 0 is returned, an error message can be found in ERROR_MSG.
+ It assumes that current_connection->target_name has already been set.
+
+ This function is aimed to resolved the incompatibilities in the
+ info retrieval tree between DFW version. It expects to find:
+
+ * the core or system name in
+ + Targets
+ + <target name>
+ + MAIN_INFO_DIRECTORY;
+
+ * the system thread id in
+ + Targets
+ + <target name>
+ + MAIN_INFO_DIRECTORY
+ + <core or system name>
+ + SYSTEM_THREAD_ID_LEAF;
+
+ * kernel task ids in
+ + Targets
+ + <target name>
+ + MAIN_INFO_DIRECTORY
+ + <core or system name>
+ + ObjTypeList
+ + KernelTask
+ + ObjList
+ + <any task>
+ +{THREAD_ID_LEAF}
+
+*/
+
+static int
+get_current_connection_info (char *main_info_directory,
+ char *system_thread_id_leaf,
+ char *thread_id_leaf,
+ char **error_msg)
+{
+ struct cleanup *old_cleanup = make_cleanup (null_cleanup, NULL);
+ const char request_target_branch [] = "/Targets/";
+ const char request_thread_id_branch [] = "/ThreadId";
+ index_type current_index;
+ dfw_tree_element item;
+ struct dfw_ast_element ast_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;
+ ast_element = next_ast_element (¤t_result_record, ¤t_index);
+ if (ast_element.type != DFW_AST_RESULT_CLASS
+ || ast_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. */
+
+ ast_element = next_ast_element (¤t_result_record, ¤t_index);
+ if (ast_element.type != DFW_AST_VARIABLE)
+ {
+ *error_msg = xstrdup ("DFW: unexpected format in output.");
+ do_cleanups (old_cleanup);
+ return 0;
+ }
+
+ for (ast_element = next_ast_element (¤t_result_record, ¤t_index);
+ current_index < current_result_record.dfw_ast_tree.table_end;
+ ast_element = next_ast_element (¤t_result_record, ¤t_index))
+ {
+ if (ast_element.type == DFW_AST_VARIABLE)
+ {
+ if (!current_connection->core_name)
+ {
+ if (ast_element.value.string_value
+ && strcmp (ast_element.value.string_value,
+ main_info_directory) != 0)
+ current_connection->core_name =
+ xstrdup (ast_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;
+ ast_element_process_result_header (¤t_result_record, ¤t_index,
+ "getting system thread id");
+
+ while (current_index < current_result_record.dfw_ast_tree.table_end)
+ {
+ ast_element = next_ast_element (¤t_result_record, ¤t_index);
+
+ if (ast_element.type == DFW_AST_VARIABLE
+ && strcmp (ast_element.value.string_value,
+ system_thread_id_leaf) == 0)
+ {
+ ast_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 (dfw_timeout, current_token);
+}
+
+/* Try to re-connect the dfwserver to the current target. Ignore
+ errors. This feature is only supported by WB > 3.2. */
+
+static void
+dfwapi_wrs_target_connect ()
+{
+ char *target_name = current_connection->full_target_name;
+
+ /* At this point, the full target name should have been initialized
+ (by dfwapi_open). */
+ gdb_assert (current_connection->full_target_name);
+
+ /* From the Workbench logs, it has been infered that these two connection
+ commands are actually needed, starting from WB > 3.2:
+
+ -wrs-target-connect <target name>
+ -wrs-target-connect <target name> -tgt
+
+ ...but disconnect first, and re-synchronize with target before
+ connecting; if it receives the connected and disconnected events
+ at the same time, the dfwserver gets confused. */
+
+ dfwapi_send_simple_command ("-wrs-target-disconnect", target_name, "-tgt");
+ dfwapi_send_simple_command ("-wrs-target-disconnect", target_name, "");
+ wrs_info_retrieve_1 ("/Targets/", current_connection->full_target_name,
+ "{Name,Connected,ThreadId}", dfw_timeout);
+ dfwapi_send_simple_command ("-wrs-target-connect", target_name, "");
+ dfwapi_send_simple_command ("-wrs-target-connect", target_name, "-tgt");
+}
+
+void
+dfwapi_open (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 *ast_table = &(current_result_record.dfw_ast_tree);
+ struct dfw_ast_element ast_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 ());
+
+ if (wtx_desc->pNext)
+ {
+ printf_unfiltered
+ (_("Multiple DFW servers registered under the name '%s'.\n"
+ "Use '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;
+ ast_element =
+ ast_element_process_wrs_info_header (¤t_result_record,
+ ¤t_index,
+ "getting full target name");
+
+ while (current_index < current_result_record.dfw_ast_tree.table_end)
+ {
+ ast_element = next_ast_element (¤t_result_record, ¤t_index);
+
+ if (ast_element.type == DFW_AST_CONST)
+ {
+ if (ast_element.value.string_value
+ && strncmp (ast_element.value.string_value,
+ target_name, strlen (target_name)) == 0)
+ {
+ current_connection->full_target_name =
+ xstrdup (ast_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_ast_element ast_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);
+
+ ast_element = next_ast_element (¤t_result_record, ¤t_index);
+ if (ast_element.type != DFW_AST_RESULT_CLASS)
+ error (_("DFW: error in %s."), request_desc);
+
+ if (ast_element.value.result_class_value == RESULT_CLASS_ERROR)
+ {
+ result = DFWAPI_TASK_STATUS_DEAD;
+ }
+ else
+ {
+ ast_element = next_ast_element_with_check
+ (¤t_result_record, ¤t_index,
+ request_desc, DFW_AST_VARIABLE);
+ ast_element = next_ast_element_with_check
+ (¤t_result_record, ¤t_index,
+ request_desc, DFW_AST_VALUE);
+ ast_element = next_ast_element_with_check
+ (¤t_result_record, ¤t_index,
+ request_desc, DFW_AST_BEGIN_LIST);
+ ast_element = next_ast_element_with_check
+ (¤t_result_record, ¤t_index,
+ request_desc, DFW_AST_VARIABLE);
+ ast_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_ast_element ast_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 (dfw_timeout, current_token);
+
+ /* Check result. */
+ ast_element = next_ast_element (¤t_result_record, ¤t_index);
+ if (ast_element.type != DFW_AST_RESULT_CLASS
+ || ast_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_ast_element ast_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 (dfw_timeout, current_token);
+
+ current_index = 0;
+ ast_element_process_result_header (¤t_result_record,
+ ¤t_index,
+ thread_info_desc);
+
+ next_ast_element_with_check (¤t_result_record, ¤t_index,
+ thread_info_desc, DFW_AST_VALUE);
+ next_ast_element_with_check (¤t_result_record, ¤t_index,
+ thread_info_desc, DFW_AST_BEGIN_LIST);
+ next_ast_element_with_check (¤t_result_record, ¤t_index,
+ thread_info_desc, DFW_AST_VARIABLE);
+ ast_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;
+}
+
+/* The various settings that affect the the DFW protocol will be
+ accessible through the "set/show dfw" command prefix. The following
+ cmd_list_element variables contain the list of commands accessible
+ under that prefix. */
+
+static struct cmd_list_element *set_dfw_list = NULL;
+static struct cmd_list_element *show_dfw_list = NULL;
+
+/* The various debug switches are accessible through the "set/show dfw
+ debug" command prefix. The following cmd_list_element variables
+ contain the list of commands accessible under that prefix. */
+
+static struct cmd_list_element *set_dfw_debug_list = NULL;
+static struct cmd_list_element *show_dfw_debug_list = NULL;
+
+/* Various other DFW-sepcific commands. */
+
+static struct cmd_list_element *dfw_list = NULL;
+
+/* Implement the "dfw" command.
+ This is not actually a valid command, so inform the user of that fact,
+ and print the list of valid subcommands to help him. */
+
+static void
+dfw_command (char *args, int from_tty)
+{
+ printf_filtered (_("\"dfw\" must be followed by a subcommand.\n"));
+ help_list (dfw_list, "dfw ", -1, gdb_stdout);
+}
+
+/* Implement the "set dfw" command.
+ This is not actually a valid command, so inform the user of that fact,
+ and print the list of valid subcommands to help him. */
+
+static void
+set_dfw_command (char *args, int from_tty)
+{
+ printf_filtered (_("\"set dfw\" must be followed by a subcommand.\n"));
+ help_list (set_dfw_list, "set dfw ", -1, gdb_stdout);
+}
+
+/* Implement the "show dfw" command: Print the value of all settings
+ available through that command prefix. */
+
+static void
+show_dfw_command (char *args, int from_tty)
+{
+ cmd_show_list (show_dfw_list, from_tty, "");
+}
+
+/* Implement the "set dfw debug" command.
+ This is not actually a valid command, so inform the user of that fact,
+ and print the list of valid subcommands to help him. */
+
+static void
+set_dfw_debug_command (char *args, int from_tty)
+{
+ printf_filtered (_("\"set dfw debug\" must be followed by a subcommand.\n"));
+ help_list (set_dfw_debug_list, "set dfw debug", -1, gdb_stdout);
+}
+
+/* Implement the "show dfw" command: Print the value of all settings
+ available through that command prefix. */
+
+static void
+show_dfw_debug_command (char *args, int from_tty)
+{
+ cmd_show_list (show_dfw_debug_list, from_tty, "");
+}
+
+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);
+ init_dfw_server_name ();
+
+ /* Various "set/show" switches. */
+
+ add_prefix_cmd ("dfw", no_class, set_dfw_command, _("\
+Adjust various settings specific to the DFW protocol."), &set_dfw_list,
+ "set dfw ", 0 /* allow_unknown */, &setlist);
+ add_prefix_cmd ("dfw", no_class, show_dfw_command, _("\
+Print various settings specific to the DFW protocol."), &show_dfw_list,
+ "show dfw ", 0 /* allow_unknown */, &showlist);
+
+ add_setshow_uinteger_cmd ("timeout", no_class, &dfw_timeout,"\
+Set timeout in seconds used for the DFW connection.\n\
+The default value is 30 seconds.", "\
+Show timeout in seconds used for the DFW connection.\n\
+The default value is 30 seconds.", "\
+Timeout in seconds used for the DFW connection.\n\
+The default value is 30 seconds.",
+ NULL, NULL,
+ &set_dfw_list, &show_dfw_list);
+
+ add_setshow_string_noescape_cmd ("server-name", class_support,
+ &dfw_server_name, _("\
+Set the DFW server name."), _("\
+Show the DFW server name."),
+ NULL, NULL, NULL,
+ &set_dfw_list, &show_dfw_list);
+
+ /* Various debug switches for DFW. */
+
+ add_prefix_cmd ("debug", no_class, set_dfw_debug_command, _("\
+Adjust various settings specific to the DFW protocol."), &set_dfw_debug_list,
+ "set dfw debug ", 0 /* allow_unknown */, &set_dfw_list);
+ add_prefix_cmd ("debug", no_class, show_dfw_debug_command, _("\
+Print various settings specific to the DFW protocol."), &show_dfw_debug_list,
+ "show dfw debug ", 0 /* allow_unknown */, &show_dfw_list);
+
+
+ add_prefix_cmd ("dfw", no_class, dfw_command,
+ _("DFW protocol specific commands\n"),
+ &dfw_list, "dfw ",
+ 0 /* allow-unknown */, &cmdlist);
+
+ add_cmd ("send", no_class, dfwapi_send,
+ "Send a request to the current dfw server.\n", &dfw_list);
+
+ add_setshow_boolean_cmd ("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,
+ &set_dfw_debug_list, &show_dfw_debug_list);
+ add_setshow_boolean_cmd ("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,
+ &set_dfw_debug_list, &show_dfw_debug_list);
+ add_setshow_boolean_cmd ("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,
+ &set_dfw_debug_list, &show_dfw_debug_list);
+}
diff --git a/gdb/remote-dfwapi.h b/gdb/remote-dfwapi.h
new file mode 100644
index 0000000..f8a649e
--- /dev/null
+++ b/gdb/remote-dfwapi.h
@@ -0,0 +1,190 @@
+/* Remote debugging API based on Wind River System's DFW protocol.
+
+ Copyright 2005, 2010, 2011 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+/* Symbols and symbol lists. */
+
+#ifndef REMOTE_DFWAPI_H
+#define REMOTE_DFWAPI_H
+
+/* DFW context types. */
+
+enum dfwapi_context_type
+{
+ DFWAPI_CONTEXT_KERNEL_TASK,
+ DFWAPI_CONTEXT_RTP,
+ DFWAPI_CONTEXT_RTP_TASK,
+ DFWAPI_CONTEXT_LAST
+};
+
+/* Full kernel/RTP task list. */
+
+struct dfwapi_task
+{
+ struct dfwapi_task *next;
+
+ /* Context type. */
+ enum dfwapi_context_type type;
+
+ /* DFW id for this task's RTP. */
+ int rtp_dfw_id;
+
+ /* Task id for this task's RTP. */
+ CORE_ADDR pid;
+
+ /* DFW id for this task. */
+ int dfw_id;
+
+ /* Task id for this task. */
+ CORE_ADDR thread_id;
+
+ /* DFW id for the parent of this task. */
+ int parent_dfw_id;
+
+ /* vxworks task descriptor of the parent. If not initialized yet,
+ set to NULL. */
+ struct dfwapi_task *parent;
+
+ /* If non-null, this vxworks task has been found during the update of
+ the vxworks task list. */
+ int is_valid;
+};
+
+extern struct dfwapi_task dfwapi_system_task;
+
+/* DFW task status. */
+
+enum dfwapi_task_status
+{
+ DFWAPI_TASK_STATUS_STATELESS,
+ DFWAPI_TASK_STATUS_STOPPED,
+ DFWAPI_TASK_STATUS_STOPPED_T,
+ DFWAPI_TASK_STATUS_STOPPED_P,
+ DFWAPI_TASK_STATUS_STOPPED_S,
+ DFWAPI_TASK_STATUS_STOPPED_P_S,
+ DFWAPI_TASK_STATUS_STOPPED_T_S,
+ DFWAPI_TASK_STATUS_STOPPED_P_T,
+ DFWAPI_TASK_STATUS_STOP_P_T_S,
+ DFWAPI_TASK_STATUS_ST_P_T_S,
+ DFWAPI_TASK_STATUS_SUSPEND,
+ DFWAPI_TASK_STATUS_DELAY,
+ DFWAPI_TASK_STATUS_PENDING,
+ DFWAPI_TASK_STATUS_PEND_S,
+ DFWAPI_TASK_STATUS_PEND_T,
+ DFWAPI_TASK_STATUS_PEND_S_T,
+ DFWAPI_TASK_STATUS_READY,
+ DFWAPI_TASK_STATUS_DEAD,
+ DFWAPI_TASK_STATUS_RTP_NORMAL,
+ DFWAPI_TASK_STATUS_LAST
+};
+
+/* tree element code for the asynchronous result class. */
+
+enum dfwapi_async_class_type
+ {
+ /* Target State Change: */
+
+ DFWAPI_ASYNC_CLASS_STATELESS,
+ DFWAPI_ASYNC_CLASS_STOPPED,
+ DFWAPI_ASYNC_CLASS_RUNNING,
+ DFWAPI_ASYNC_CLASS_CONTAINER_STOPPED,
+ DFWAPI_ASYNC_CLASS_INDETERMINATE_STATE,
+
+ /* Target Connection Events: */
+
+ DFWAPI_ASYNC_CLASS_CONNECTED,
+ DFWAPI_ASYNC_CLASS_DISCONNECTED,
+
+ /* Target Data Change: */
+
+ DFWAPI_ASYNC_CLASS_REGISTER_CHANGED,
+ DFWAPI_ASYNC_CLASS_MEMORY_CHANGED,
+
+ /* Download Event Notifications: */
+
+ DFWAPI_ASYNC_CLASS_DOWNLOAD,
+ DFWAPI_ASYNC_CLASS_DOWNLOAD_COMPLETE,
+ DFWAPI_ASYNC_CLASS_DOWNLOAD_FAILED,
+ DFWAPI_ASYNC_CLASS_MODULES_CHANGED,
+
+ /* TOS Event Notifications: */
+
+ DFWAPI_ASYNC_CLASS_CONTEXT_START,
+ DFWAPI_ASYNC_CLASS_CONTEXT_EXIT,
+ DFWAPI_ASYNC_CLASS_TOOL_DETACH,
+ DFWAPI_ASYNC_CLASS_TOOL_ATTACH,
+
+ /* Register Definitions Changed Event Notification: */
+
+ DFWAPI_ASYNC_CLASS_REGDEFCHANGED,
+
+ /* Breakpoint events: */
+
+ DFWAPI_ASYNC_CLASS_BREAKPOINT_CHANGED,
+ DFWAPI_ASYNC_CLASS_EVENTPOINT_CHANGED,
+ DFWAPI_ASYNC_CLASS_EVENTPOINT_DELETED,
+
+ /* Unkwnown: */
+ DFWAPI_ASYNC_CLASS_LAST
+ };
+
+/* Stop reason for the event DFWAPI_ASYNC_CLASS_STOPPED. */
+enum dfwapi_stop_reason
+ {
+ DFWAPI_STOP_REASON_USER_STOPPED,
+ DFWAPI_STOP_REASON_END_STEPPING_RANGE,
+ DFWAPI_STOP_REASON_BREAKPOINT_HIT,
+ DFWAPI_STOP_REASON_LOCATION_REACHED,
+ DFWAPI_STOP_REASON_FUNCTION_FINISHED,
+ DFWAPI_STOP_REASON_SIGNAL_RECEIVED,
+ DFWAPI_STOP_REASON_RUN_FAILED,
+ DFWAPI_STOP_REASON_MODULE_CHANGED,
+ DFWAPI_STOP_REASON_LAST
+ };
+
+/* Full vxworks task list on target. */
+
+extern struct dfwapi_task *dfwapi_task_list;
+
+extern char * dfwapi_get_object_name (long dfw_id);
+extern enum dfwapi_task_status dfwapi_get_task_status (long dfw_id);
+extern char * dfwapi_get_task_status_desc (enum dfwapi_task_status status);
+extern int dfwapi_stopped_status_kind (enum dfwapi_task_status status);
+
+extern void dfwapi_update_task_list ();
+
+extern ptid_t dfwapi_task_ptid_build (struct dfwapi_task *task);
+extern long ptid_get_dfw_id (ptid_t ptid);
+
+extern struct dfwapi_task * dfwapi_lookup_task (CORE_ADDR id);
+extern struct dfwapi_task * dfwapi_lookup_task_by_dfw_id (int dfw_id);
+
+extern void dfwapi_clear_task_list ();
+
+extern ptid_t get_ptid_from_dfw_id (int dfw_id);
+extern struct dfwapi_task * dfwapi_get_task_from_dfw_id (int dfw_id);
+extern struct dfwapi_task* dfwapi_lookup_task_parent
+ (struct dfwapi_task *t);
+
+extern void dfwapi_open (char *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.7.0.4
^ permalink raw reply [flat|nested] 54+ messages in thread
* [PATCH 17/18] Configury and Makefile updates for VxWorks
2011-02-24 17:49 Add support for VxWorks 5.x, 6.x and 653 Joel Brobecker
` (15 preceding siblings ...)
2011-02-24 17:59 ` [PATCH 16/18] Add tdep files for x86 and powerpc Joel Brobecker
@ 2011-02-24 17:59 ` Joel Brobecker
2011-02-24 18:04 ` [PATCH 18/18] document the new VxWorks port Joel Brobecker
17 siblings, 0 replies; 54+ messages in thread
From: Joel Brobecker @ 2011-02-24 17:59 UTC (permalink / raw)
To: gdb-patches; +Cc: Joel Brobecker
This is the last (code) patch! :) Documentation and NEWS entry
will follow.
It contains the changes needed to configure and build the VxWorks
debugger.
gdb/ChangeLog:
* configure.ac: Add support for vxworks targets.
* configure: Regenerate.
* configure.tgt: Add support for vxworks targets.
* Makefile.in (VXWORKS_CFLAGS): New variable.
(INTERNAL_CFLAGS_BASE): Use VXWORKS_CFLAGS.
---
gdb/Makefile.in | 6 +++-
gdb/configure | 101 +++++++++++++++++++++++++++++++++++++++++++++++++++++
gdb/configure.ac | 57 ++++++++++++++++++++++++++++++
gdb/configure.tgt | 41 +++++++++++++++++++++
4 files changed, 204 insertions(+), 1 deletions(-)
diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index fae43b2..3b2333a 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -440,6 +440,9 @@ CFLAGS = @CFLAGS@
# a bit the consequences by putting the Python includes last in the list.
INTERNAL_CPPFLAGS = @CPPFLAGS@ @PYTHON_CPPFLAGS@
+# Set by configure for all CFLAGS related to vxWorks targets.
+VXWORKS_CFLAGS= @VXWORKS_CFLAGS@
+
# Need to pass this to testsuite for "make check". Probably should be
# consistent with top-level Makefile.in and gdb/testsuite/Makefile.in
# so "make check" has the same result no matter where it is run.
@@ -450,7 +453,8 @@ INTERNAL_CFLAGS_BASE = \
$(CFLAGS) $(GLOBAL_CFLAGS) $(PROFILE_CFLAGS) \
$(GDB_CFLAGS) $(OPCODES_CFLAGS) $(READLINE_CFLAGS) \
$(BFD_CFLAGS) $(INCLUDE_CFLAGS) $(LIBDECNUMBER_CFLAGS) \
- $(INTL_CFLAGS) $(INCGNU) $(ENABLE_CFLAGS) $(INTERNAL_CPPFLAGS)
+ $(INTL_CFLAGS) $(INCGNU) $(ENABLE_CFLAGS) $(INTERNAL_CPPFLAGS) \
+ $(VXWORKS_CFLAGS)
INTERNAL_WARN_CFLAGS = $(INTERNAL_CFLAGS_BASE) $(GDB_WARN_CFLAGS)
INTERNAL_CFLAGS = $(INTERNAL_WARN_CFLAGS) $(GDB_WERROR_CFLAGS)
diff --git a/gdb/configure b/gdb/configure
index adf4bef..01d4b1d 100755
--- a/gdb/configure
+++ b/gdb/configure
@@ -599,6 +599,7 @@ gl_LTLIBOBJS
gl_LIBOBJS
LTLIBOBJS
LIBOBJS
+VXWORKS_CFLAGS
GDB_NM_FILE
frags
target_subdir
@@ -15921,6 +15922,106 @@ ac_config_links="$ac_config_links $ac_config_links_1"
$as_echo "#define GDB_DEFAULT_HOST_CHARSET \"UTF-8\"" >>confdefs.h
+# Support for vxWorks targets.
+
+case ${target} in
+ *-*-vxworks*)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -ldl" >&5
+$as_echo_n "checking for dlopen in -ldl... " >&6; }
+if test "${ac_cv_lib_dl_dlopen+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-ldl $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char dlopen ();
+int
+main ()
+{
+return dlopen ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ ac_cv_lib_dl_dlopen=yes
+else
+ ac_cv_lib_dl_dlopen=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dl_dlopen" >&5
+$as_echo "$ac_cv_lib_dl_dlopen" >&6; }
+if test "x$ac_cv_lib_dl_dlopen" = x""yes; then :
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_LIBDL 1
+_ACEOF
+
+ LIBS="-ldl $LIBS"
+
+fi
+
+ ;;
+esac
+
+VXWORKS_CFLAGS=
+case "${target}" in
+
+ # vxWorks 653 targets.
+ *-vxworks653 | *-vxworksae )
+ if test "${WIND_FOUNDATION_PATH}" != ""; then
+ # vxWorks 653 version PSC 2.x
+ VXWORKS_CFLAGS="-I${WIND_FOUNDATION_PATH}/include"
+ vxworks_libdir="${WIND_FOUNDATION_PATH}/${WIND_HOST_TYPE}/lib"
+ elif test "${WIND_BASE}" != ""; then
+ # vxWorks 653 version PSC 1.x
+ VXWORKS_CFLAGS="-I${WIND_BASE}/host/include"
+ vxworks_libdir="${WIND_BASE}/host/${WIND_HOST_TYPE}/lib"
+ else
+ as_fn_error "cannot find vxWorks base installation from environment" "$LINENO" 5
+ fi
+ ;;
+
+ # vxWorks 6.x targets.
+ *-vxworks6 )
+ if test "${WIND_FOUNDATION_PATH}" = ""; then
+ as_fn_error "cannot find vxWorks base installation from environment" "$LINENO" 5
+ fi
+ VXWORKS_CFLAGS="-I${WIND_FOUNDATION_PATH}/include"
+ vxworks_libdir="${WIND_FOUNDATION_PATH}/${WIND_HOST_TYPE}/lib"
+ ;;
+
+ # vxWorks 5.x targets.
+ *-vxworks )
+ if test "${WIND_BASE}" = ""; then
+ as_fn_error "cannot find vxWorks base installation from environment" "$LINENO" 5
+ fi
+ VXWORKS_CFLAGS="-I${WIND_BASE}/host/include"
+ vxworks_libdir="${WIND_BASE}/host/${WIND_HOST_TYPE}/lib"
+ case "${host_os}" in
+ mingw* | *-cygwin* )
+ LIBS="${LIBS} $vxworks_libdir/tcldll.lib"
+ ;;
+ * )
+ LIBS="${LIBS} -L$vxworks_libdir"
+ LIBS="${LIBS} -ltcl"
+ ;;
+ esac
+ ;;
+esac
+
+
+
ac_config_files="$ac_config_files Makefile .gdbinit:gdbinit.in doc/Makefile gnulib/Makefile data-directory/Makefile"
ac_config_commands="$ac_config_commands default"
diff --git a/gdb/configure.ac b/gdb/configure.ac
index f31ef2a..4c0759c 100644
--- a/gdb/configure.ac
+++ b/gdb/configure.ac
@@ -2167,6 +2167,63 @@ dnl At the moment, we just assume it's UTF-8.
AC_DEFINE(GDB_DEFAULT_HOST_CHARSET, "UTF-8",
[Define to be a string naming the default host character set.])
+# Support for vxWorks targets.
+
+dnl The WTX support requires dlopen to load the WTX libraries.
+case ${target} in
+ *-*-vxworks*)
+ AC_CHECK_LIB(dl, dlopen)
+ ;;
+esac
+
+VXWORKS_CFLAGS=
+case "${target}" in
+
+ # vxWorks 653 targets.
+ *-vxworks653 | *-vxworksae )
+ if test "${WIND_FOUNDATION_PATH}" != ""; then
+ # vxWorks 653 version PSC 2.x
+ VXWORKS_CFLAGS="-I${WIND_FOUNDATION_PATH}/include"
+ vxworks_libdir="${WIND_FOUNDATION_PATH}/${WIND_HOST_TYPE}/lib"
+ elif test "${WIND_BASE}" != ""; then
+ # vxWorks 653 version PSC 1.x
+ VXWORKS_CFLAGS="-I${WIND_BASE}/host/include"
+ vxworks_libdir="${WIND_BASE}/host/${WIND_HOST_TYPE}/lib"
+ else
+ AC_ERROR(cannot find vxWorks base installation from environment)
+ fi
+ ;;
+
+ # vxWorks 6.x targets.
+ *-vxworks6 )
+ if test "${WIND_FOUNDATION_PATH}" = ""; then
+ AC_ERROR(cannot find vxWorks base installation from environment)
+ fi
+ VXWORKS_CFLAGS="-I${WIND_FOUNDATION_PATH}/include"
+ vxworks_libdir="${WIND_FOUNDATION_PATH}/${WIND_HOST_TYPE}/lib"
+ ;;
+
+ # vxWorks 5.x targets.
+ *-vxworks )
+ if test "${WIND_BASE}" = ""; then
+ AC_ERROR(cannot find vxWorks base installation from environment)
+ fi
+ VXWORKS_CFLAGS="-I${WIND_BASE}/host/include"
+ vxworks_libdir="${WIND_BASE}/host/${WIND_HOST_TYPE}/lib"
+ case "${host_os}" in
+ mingw* | *-cygwin* )
+ LIBS="${LIBS} $vxworks_libdir/tcldll.lib"
+ ;;
+ * )
+ LIBS="${LIBS} -L$vxworks_libdir"
+ LIBS="${LIBS} -ltcl"
+ ;;
+ esac
+ ;;
+esac
+
+AC_SUBST(VXWORKS_CFLAGS)
+
AC_OUTPUT(Makefile .gdbinit:gdbinit.in doc/Makefile gnulib/Makefile data-directory/Makefile,
[
case x$CONFIG_HEADERS in
diff --git a/gdb/configure.tgt b/gdb/configure.tgt
index 7d017a9..d395668 100644
--- a/gdb/configure.tgt
+++ b/gdb/configure.tgt
@@ -28,6 +28,14 @@ case $targ in
;;
esac
+# The list of common files needed for all vxWorks ports.
+wtx_tdep_files="remote-wtxapi.o remote-wtx-opt.o remote-wtx-pd.o \
+ remote-wtx.o remote-wtx-utils.o remote-wtx-bp.o \
+ remote-wtx-hw.o remote-wtx-tasks.o"
+# The list of common files needed in order to support the DFW protocol
+# in vxWorks 6.x ports.
+dfw_tdep_files="remote-dfwapi.o remote-dfw.o"
+
# map target info into gdb names.
case "${targ}" in
@@ -239,6 +247,21 @@ i[34567]86-*-mingw32*)
solib-target.o corelow.o windows-tdep.o"
build_gdbserver=yes
;;
+i[34567]86-*-vxworks653 | i[34567]86-*-vxworksae )
+ # Target: Intel 386 running vxWorks 653
+ gdb_target_obs="i386-tdep.o i387-tdep.o i386-vxworks-tdep.o \
+ ${wtx_tdep_files} remote-wtx-tcl.o"
+ ;;
+i[34567]86-*-vxworks6* )
+ # Target: Intel 386 running vxWorks 6.x
+ gdb_target_obs="i386-tdep.o i387-tdep.o ${dfw_tdep_files} \
+ ${wtx_tdep_files} "
+ ;;
+i[34567]86-*-vxworks* )
+ # Target: Intel 386 running vxWorks 5.x
+ gdb_target_obs="i386-tdep.o i387-tdep.o i386-vxworks-tdep.o \
+ ${wtx_tdep_files} remote-wtx-tcl.o"
+ ;;
i[34567]86-*-*)
# Target: i386
gdb_target_obs="i386-tdep.o i387-tdep.o"
@@ -417,6 +440,24 @@ powerpc-*-linux* | powerpc64-*-linux*)
gdb_sim=../sim/ppc/libsim.a
build_gdbserver=yes
;;
+powerpc-*-vxworks653 | powerpc-*-vxworksae )
+ # Target: PowerPC running vxWorks 653
+ gdb_target_obs="rs6000-tdep.o rs6000-vxworks-tdep.o ppc-sysv-tdep.o \
+ solib.o solib-svr4.o \
+ ${wtx_tdep_files} remote-wtx-tcl.o"
+ ;;
+powerpc-*-vxworks6* | e500*-*-vxworks6* )
+ # Target: PowerPC running vxWorks 6.x
+ gdb_target_obs="rs6000-tdep.o rs6000-vxworks-tdep.o ppc-sysv-tdep.o \
+ solib.o solib-svr4.o \
+ ${dfw_tdep_files} ${wtx_tdep_files} "
+ ;;
+powerpc-*-vxworks* )
+ # Target: PowerPC running vxWorks 5.x
+ gdb_target_obs="rs6000-tdep.o rs6000-vxworks-tdep.o ppc-sysv-tdep.o \
+ solib.o solib-svr4.o \
+ ${wtx_tdep_files} remote-wtx-tcl.o"
+ ;;
powerpc*-*-*)
# Target: PowerPC running eabi
gdb_target_obs="rs6000-tdep.o monitor.o dsrec.o ppcbug-rom.o \
--
1.7.0.4
^ permalink raw reply [flat|nested] 54+ messages in thread
* [PATCH 16/18] Add tdep files for x86 and powerpc.
2011-02-24 17:49 Add support for VxWorks 5.x, 6.x and 653 Joel Brobecker
` (14 preceding siblings ...)
2011-02-24 17:58 ` [PATCH 15/18] Add support for VxWorks 6 Joel Brobecker
@ 2011-02-24 17:59 ` Joel Brobecker
2011-02-24 18:58 ` Mark Kettenis
2011-02-24 17:59 ` [PATCH 17/18] Configury and Makefile updates for VxWorks Joel Brobecker
2011-02-24 18:04 ` [PATCH 18/18] document the new VxWorks port Joel Brobecker
17 siblings, 1 reply; 54+ messages in thread
From: Joel Brobecker @ 2011-02-24 17:59 UTC (permalink / raw)
To: gdb-patches; +Cc: Joel Brobecker
This patch adds a new GDB_OSABI_VXWORKS for VxWorks targets, and
introduces new VxWorks tdep files for x86 and powerpc. They will
be included in the build by the next patch.
gdb/ChangeLog:
* defs.h (enum gdb_osabi): Add GDB_OSABI_VXWORKS.
* osabi.c (gdb_osabi_names): Add entry for GDB_OSABI_VXWORKS.
* i386-vxworks-tdep.c, rs6000-vxworks-tdep.c: New files.
---
gdb/defs.h | 1 +
gdb/i386-vxworks-tdep.c | 53 +++++++++++++++++++++++
gdb/osabi.c | 1 +
gdb/rs6000-vxworks-tdep.c | 105 +++++++++++++++++++++++++++++++++++++++++++++
4 files changed, 160 insertions(+), 0 deletions(-)
create mode 100644 gdb/i386-vxworks-tdep.c
create mode 100644 gdb/rs6000-vxworks-tdep.c
diff --git a/gdb/defs.h b/gdb/defs.h
index 908d956..c040dc9 100644
--- a/gdb/defs.h
+++ b/gdb/defs.h
@@ -999,6 +999,7 @@ enum gdb_osabi
GDB_OSABI_QNXNTO,
GDB_OSABI_CYGWIN,
GDB_OSABI_AIX,
+ GDB_OSABI_VXWORKS,
GDB_OSABI_DICOS,
GDB_OSABI_DARWIN,
GDB_OSABI_SYMBIAN,
diff --git a/gdb/i386-vxworks-tdep.c b/gdb/i386-vxworks-tdep.c
new file mode 100644
index 0000000..78aaf0f
--- /dev/null
+++ b/gdb/i386-vxworks-tdep.c
@@ -0,0 +1,53 @@
+/* Copyright (C) 2007, 2010, 2011 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#include "defs.h"
+#include "inferior.h"
+#include "osabi.h"
+#include "i386-tdep.h"
+
+static void
+i386_vxworks_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
+{
+ /* The AT_ENTRY_POINT method is not practical on VxWorks systems,
+ because there is no concept of "the" executable. Furthermore,
+ memory space is shared by all processes (and thus someone
+ spawning a new task using the same entry point might interfere
+ with our function call). So we rely on the ON_STACK method
+ instead. */
+ set_gdbarch_call_dummy_location (gdbarch, ON_STACK);
+}
+
+static enum gdb_osabi
+i386_vxworks_osabi_sniffer (bfd * abfd)
+{
+ char *target_name = bfd_get_target (abfd);
+
+ if (strstr (target_name, "vxworks") != NULL)
+ return GDB_OSABI_VXWORKS;
+
+ return GDB_OSABI_UNKNOWN;
+}
+void
+_initialize_vxworks_tdep (void)
+{
+ gdbarch_register_osabi_sniffer (bfd_arch_i386, bfd_target_elf_flavour,
+ i386_vxworks_osabi_sniffer);
+ gdbarch_register_osabi (bfd_arch_i386, 0, GDB_OSABI_VXWORKS,
+ i386_vxworks_init_abi);
+}
+
diff --git a/gdb/osabi.c b/gdb/osabi.c
index a264924..9b29b16 100644
--- a/gdb/osabi.c
+++ b/gdb/osabi.c
@@ -70,6 +70,7 @@ static const char * const gdb_osabi_names[] =
"QNX Neutrino",
"Cygwin",
"AIX",
+ "VxWorks",
"DICOS",
"Darwin",
"Symbian",
diff --git a/gdb/rs6000-vxworks-tdep.c b/gdb/rs6000-vxworks-tdep.c
new file mode 100644
index 0000000..31c2ba7
--- /dev/null
+++ b/gdb/rs6000-vxworks-tdep.c
@@ -0,0 +1,105 @@
+/* Target-dependent code for GDB, the GNU debugger.
+
+ Copyright (C) 2009, 2010, 2011 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#include "defs.h"
+#include "gdbarch.h"
+#include "osabi.h"
+#include "ppc-tdep.h"
+#include "gdb_assert.h"
+#include "inferior.h"
+#include "gdb_string.h"
+
+static CORE_ADDR
+rs6000_vxworks_push_dummy_code (struct gdbarch *gdbarch,
+ CORE_ADDR sp, CORE_ADDR funaddr,
+ struct value **args, int nargs,
+ struct type *value_type,
+ CORE_ADDR *real_pc, CORE_ADDR *bp_addr,
+ struct regcache *regcache)
+{
+ /* Something here to findout the size of a breakpoint and then
+ allocate space for it on the stack. */
+ int bplen;
+ /* This code assumes frame align. */
+ gdb_assert (gdbarch_frame_align_p (gdbarch));
+ /* Force the stack's alignment. The intent is to ensure that the SP
+ is aligned to at least a breakpoint instruction's boundary. */
+ sp = gdbarch_frame_align (gdbarch, sp);
+ /* Allocate space for, and then position the breakpoint on the stack. */
+ if (gdbarch_inner_than (gdbarch, 1, 2))
+ {
+ CORE_ADDR bppc = sp;
+ gdbarch_breakpoint_from_pc (gdbarch, &bppc, &bplen);
+ sp = gdbarch_frame_align (gdbarch, sp - bplen);
+ (*bp_addr) = sp;
+ /* Should the breakpoint size/location be re-computed here? */
+ }
+ else
+ {
+ (*bp_addr) = sp;
+ gdbarch_breakpoint_from_pc (gdbarch, bp_addr, &bplen);
+ sp = gdbarch_frame_align (gdbarch, sp + bplen);
+ }
+ /* Inferior resumes at the function entry point. */
+ (*real_pc) = funaddr;
+ return sp;
+}
+
+static void
+rs6000_vxworks_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
+{
+ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+
+ /* Certain versions of VxWorks do not provide support for Altivec
+ registers. For now, disable support for these registers on all
+ versions of GDB. */
+ tdep->ppc_vr0_regnum = -1;
+ tdep->ppc_vrsave_regnum = -1;
+
+ /* The AT_ENTRY_POINT method is not practical on VxWorks systems,
+ because there is no concept of "the" executable. Furthermore,
+ memory space is shared by all processes (and thus someone
+ spawning a new task using the same entry point might interfere
+ with our function call). So we rely on the ON_STACK method
+ instead. */
+ set_gdbarch_call_dummy_location (gdbarch, ON_STACK);
+ set_gdbarch_push_dummy_code (gdbarch, rs6000_vxworks_push_dummy_code);
+}
+
+static enum gdb_osabi
+rs6000_vxworks_osabi_sniffer (bfd * abfd)
+{
+ char *target_name = bfd_get_target (abfd);
+
+ if (strstr (target_name, "vxworks") != NULL)
+ return GDB_OSABI_VXWORKS;
+
+ return GDB_OSABI_UNKNOWN;
+}
+
+void
+_initialize_rs6000_vxworks_tdep (void)
+{
+ /* Register the sniffer for the VxWorks targets. */
+ gdbarch_register_osabi_sniffer (bfd_arch_powerpc, bfd_target_elf_flavour,
+ rs6000_vxworks_osabi_sniffer);
+ gdbarch_register_osabi (bfd_arch_powerpc, 0, GDB_OSABI_VXWORKS,
+ rs6000_vxworks_init_abi);
+}
+
--
1.7.0.4
^ permalink raw reply [flat|nested] 54+ messages in thread
* [PATCH 18/18] document the new VxWorks port
2011-02-24 17:49 Add support for VxWorks 5.x, 6.x and 653 Joel Brobecker
` (16 preceding siblings ...)
2011-02-24 17:59 ` [PATCH 17/18] Configury and Makefile updates for VxWorks Joel Brobecker
@ 2011-02-24 18:04 ` Joel Brobecker
2011-02-24 20:27 ` Eli Zaretskii
17 siblings, 1 reply; 54+ messages in thread
From: Joel Brobecker @ 2011-02-24 18:04 UTC (permalink / raw)
To: gdb-patches; +Cc: Joel Brobecker
The VxWorks documentation was completely out of date, so I rewrote it
from scratch. I tried to organize it in a logical way, introducing
some of the concepts about VxWorks, to make the port a little alien
to someone who is not familiar with this OS.
I've also included a NEWS entry.
gdb/ChangeLog:
* NEWS: Add entry documenting the new VxWorks ports.
gdb/doc/ChangeLog:
* gdb.texinfo (VxWorks): Rewrite the VxWorks documentation.
---
gdb/NEWS | 8 +
gdb/doc/gdb.texinfo | 554 ++++++++++++++++++++++++++++++++++++++++----------
2 files changed, 451 insertions(+), 111 deletions(-)
diff --git a/gdb/NEWS b/gdb/NEWS
index fb36383..f442d98 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -162,6 +162,14 @@ ia64 HP-UX ia64-*-hpux*
Analog Devices, Inc. Blackfin Processor bfin-*
+VxWorks 653 i[34567]86-*-vxworks653
+ powerpc-*-vxworks653
+VxWorks 6.x i[34567]86-*-vxworks6*
+ powerpc-*-vxworks6*
+ e500*-*-vxworks6*
+VxWorks 5.x (x >= 4) i[34567]86-*-vxworks*
+ powerpc-*-vxworks*
+
* Ada task switching is now supported on sparc-elf targets when
debugging a program using the Ravenscar Profile. For more information,
see the "Tasking Support when using the Ravenscar Profile" section
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index 32454c3..ca2cb18 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -17935,165 +17935,497 @@ various real-time operating systems.
@node VxWorks
@subsection Using @value{GDBN} with VxWorks
-
@cindex VxWorks
-@table @code
+Debugging on VxWorks is supported on VxWorks 5.5, all versions of
+Vworks 6 starting with version 6.4, and VxWorks 653. @value{GDBN}
+does not connect directly to the target running VxWorks, but instead
+relies on the @dfn{Target Server}, which is a process running on the
+host. The debugger establishes a connection with that process, and
+sends all debugging comands (resume task execution, read memory, read
+register, @dots{}) through the Target Server.
-@kindex target vxworks
-@item target vxworks @var{machinename}
-A VxWorks system, attached via TCP/IP. The argument @var{machinename}
-is the target system's machine name or IP address.
+@subsubsection Debugging on VxWorks 5.5
+Debugging a program on VxWorks 5.5 is performed by connecting to
+the Target Server first. To establish this connection, use the
+@code{target wtx} command (@dfn{WTX} is the name of the protocol
+used to communicate with the Target Server):
+
+@table @code
+@kindex target wtx
+@item target wtx @var{target-server-name}
+Connect @value{GDBN} to a Target Server whose name is
+@var{target-server-name}. Once the connection is established,
+@value{GDBN} queries the list of modules loaded on the target, and
+then proceeds to load the symbol table and debugging information
+from these modules.
@end table
-On VxWorks, @code{load} links @var{filename} dynamically on the
-current target system as well as adding its symbols in @value{GDBN}.
+VxWorks does not have a concept of processes, or even programs, like
+most Operating Systems do. Instead of running a program, one spawns
+a @dfn{task} (a.k.a. a thread), usually using a symbol name as the entry
+point for that thread. Every task created can be regarded as a kernel
+thread, since it shares memory and code with the rest of the system.
-@value{GDBN} enables developers to spawn and debug tasks running on networked
-VxWorks targets from a Unix host. Already-running tasks spawned from
-the VxWorks shell can also be debugged. @value{GDBN} uses code that runs on
-both the Unix host and on the VxWorks target. The program
-@code{@value{GDBP}} is installed and executed on the Unix host. (It may be
-installed with the name @code{vxgdb}, to distinguish it from a
-@value{GDBN} for debugging programs on the host itself.)
+To create a new task under debugger control, use the @code{run}
+command, passing as the first parameter the name of the symbol
+to use as the entry point (all other parameters are ignored):
-@table @code
-@item VxWorks-timeout @var{args}
-@kindex vxworks-timeout
-All VxWorks-based targets now support the option @code{vxworks-timeout}.
-This option is set by the user, and @var{args} represents the number of
-seconds @value{GDBN} waits for responses to rpc's. You might use this if
-your VxWorks target is a slow software simulator or is on the far side
-of a thin network line.
-@end table
-
-The following information on connecting to VxWorks was current when
-this manual was produced; newer releases of VxWorks may use revised
-procedures.
-
-@findex INCLUDE_RDB
-To use @value{GDBN} with VxWorks, you must rebuild your VxWorks kernel
-to include the remote debugging interface routines in the VxWorks
-library @file{rdb.a}. To do this, define @code{INCLUDE_RDB} in the
-VxWorks configuration file @file{configAll.h} and rebuild your VxWorks
-kernel. The resulting kernel contains @file{rdb.a}, and spawns the
-source debugging task @code{tRdbTask} when VxWorks is booted. For more
-information on configuring and remaking VxWorks, see the manufacturer's
-manual.
-@c VxWorks, see the @cite{VxWorks Programmer's Guide}.
-
-Once you have included @file{rdb.a} in your VxWorks system image and set
-your Unix execution search path to find @value{GDBN}, you are ready to
-run @value{GDBN}. From your Unix host, run @code{@value{GDBP}} (or
-@code{vxgdb}, depending on your installation).
+@smallexample
+(@value{GDBP}) run simple_main
+[@dots{}]
+@end smallexample
-@value{GDBN} comes up showing the prompt:
+Instead of creating a new task, it is also possible to attach the
+debugger to an already existing task, using the @code{attach} command.
+The equivalent of the Unix process ID is the task ID on VxWorks, and
+these IDs should be used to identify the task that needs to be
+debugged.
@smallexample
-(vxgdb)
+(@value{GDBP}) attach 0xf70b0f0
+Attaching to task 0xf70b0f0.
+[@dots{}]
@end smallexample
-@menu
-* VxWorks Connection:: Connecting to VxWorks
-* VxWorks Download:: VxWorks download
-* VxWorks Attach:: Running tasks
-@end menu
+As a convenience, GDB allows the use of the task name as a parameter
+to the @code{attach} command, in place of the task ID. When a task
+name is specified, the first task whose name matches is selected.
+If there are more than one tasks with the same name, the selection
+process is random.
-@node VxWorks Connection
-@subsubsection Connecting to VxWorks
+A list of all tasks currently running on the target can be obtained
+using the @code{info wtx threads} command.
-The @value{GDBN} command @code{target} lets you connect to a VxWorks target on the
-network. To connect to a target whose host name is ``@code{tt}'', type:
+@table @code
+@kindex info wtx threads
+@item info wtx threads
+Print the list of threads currently running on the target.
+Each line represents a thread, and contains 2 space-separated
+elements. The first element is the task ID, and the second
+is the task name.
@smallexample
-(vxgdb) target vxworks tt
+(@value{GDBP}) info wtx threads
+0xf710190 tShell
+0xf712430 tWdbTask
+0xf715600 tTelnetd
+[@dots{}]
@end smallexample
+@end table
-@need 750
-@value{GDBN} displays messages like these:
+GDB offers several modes for debugging VxWorks tasks:
+
+@table @dfn
+
+@cindex VxWorks, Task Mode Debugging
+@item Task Mode
+In this mode, only a single tasks is being debugged. Any other tasks,
+including new tasks created by the task being debugged, are simply
+ignored (their execution is not controlled by the debugger).
+
+@cindex VxWorks, Multitasks Mode Debugging
+@item Multitasks Mode
+This is a mode specific to Ada programs where the debugger simulates
+the concept of debugging a process. This is useful when trying to debug
+an Ada program that uses the multi-tasking features of Ada.
+
+When debugging in this mode, all Ada tasks controlled by the Ada
+run-time library are under @value{GDBN} control, and their execution
+is automatically stopped or resumed as needed. In particular, when
+attaching to a task, all associated tasks in the same Ada "program"
+are automatically stopped and put under debugger control. New tasks
+being spawned by the Ada "program" are also automatically taken under
+debugger control.
+
+This mode is specific to Ada programs because it, because it relies
+on the Ada runtime in order to extract the list of tasks currently
+running as part of the Ada program.
+
+@cindex VxWorks, System Mode Debugging
+@item The System Mode
+
+In this mode, the debugger controls the entire system as one process,
+including part of the system such as the scheduler, interrupt handlers,
+etc. To enter System Mode, simply use the @code{attach system} command.
+To leave System Mode, use @code{detach}.
+@end table
+
+@table @code
+@kindex set multi-tasks-mode
+@item set multi-tasks-mode [on|off]
+If @code{on}, activate multi-tasks mode. The default is @code{off}.
+This setting should be properly set before using the @code{attach}
+or @code{run} command. As long as GDB controls the execution of one
+or more tasks, attempting to change this setting will result in an
+error.
+
+This setting is ignored when debugging in System Mode.
+@end table
+
+@subsubsection Debugging on VxWorks 653
+
+Debugging on VxWorks 653 is very similar to debugging on VxWorks 5,
+and the commands available for VxWorks 5 are also generally available
+for VxWorks 653.
+
+The one important distinction is the fact that VxWorks 653 provides
+the concept of @dfn{Partitions}, as defined by the ARINC 653
+specification. These partitions usually have their own address space,
+and allow the user to make sure that tasks running in one partition
+cannot affect tasks running on another partition (on VxWorks AE,
+which is an ancestor of VxWorks 653, these partitions were called
+@dfn{Protection Domains}, or @dfn{PD} in short). Please refer to your
+VxWorks 653 manual for more information about the various types of
+partitions and their use.
+
+@table @code
+@kindex info partitions
+@item info partitions
+Print the list of existing partitions on the target system. Each line
+corresponds to a partition, and contains its ID and name. An asterisk
+@samp{*} at the start of one of the lines indicates the current partition.
@smallexample
-Attaching remote machine across net...
-Connected to tt.
+(@value{GDBP}) info partitions
+ PD-ID Name
+* 0x356738 coreOS
+ 0xd799f0 ssl
+ 0xd7ae20 part1
+ 0xd80750 part2
@end smallexample
-@need 1000
-@value{GDBN} then attempts to read the symbol tables of any object modules
-loaded into the VxWorks target since it was last booted. @value{GDBN} locates
-these files by searching the directories listed in the command search
-path (@pxref{Environment, ,Your Program's Environment}); if it fails
-to find an object file, it displays a message such as:
+@kindex partition
+@item partition @var{id-or-name}
+Switch to the given partition. The @var{id-or-name} argument can
+be either the partition ID (an hexadecimal number), or its name.
@smallexample
-prog.o: No such file or directory.
+(@value{GDBP}) partition part1
+[Switching to Partition part1 (0xd7ae20)]
+(@value{GDBP}) partition 0xd80750
+[Switching to Partition part2 (0xd80750)]
@end smallexample
-When this happens, add the appropriate directory to the search path with
-the @value{GDBN} command @code{path}, and execute the @code{target}
-command again.
+@kindex maintenance info link-path
+@item maintenance info link-path
+This is a command mostly aimed at helping GDB maintainers. It prints
+the @dfn{link path} of each partition (the @dfn{Link Path} is a path
+associated to each partition, and is used by the loader to find
+requested symbols - for more information, see your Tornado 653
+Manuals).
+
+@smallexample
+(@value{GDBP}) maintenance info link-path
+Partition Name [Link Path]
+ 0x356738 coreOS [.]
+ 0xd799f0 ssl [.]
+ 0xd7ae20 part1 [.:ssl:ssl]
+ 0xd80750 part2 [.:ssl]
+@end smallexample
+
+@end table
+
+@subsubsection Commands and Settings Related to WTX
+
+The following Settings are provided:
-@node VxWorks Download
-@subsubsection VxWorks Download
+@table @code
+@kindex set wtx tool-name
+@item set wtx tool-name @var{name}
+This command can be used to change the name of the tool given to
+the Target Server when establishing the connection. This is only
+for documentation and logging purposes as this has no effect on
+the debugging session. The default is @code{gdb}.
+
+@kindex show wtx tool-name
+@item show wtx tool-name
+Display the tool name used when establishing a connection with the
+WTX server.
+
+@kindex set wtx load-timeout
+@item set wtx load-timeout @var{timeout}
+Change the timeout (in seconds) used when loading new modules on
+the target. The default is 30 seconds.
+
+@kindex show wtx load-timeout
+@item show wtx load-timeout
+Print the timeout duration used when loading modules on the target.
-@cindex download to VxWorks
-If you have connected to the VxWorks target and you want to debug an
-object that has not yet been loaded, you can use the @value{GDBN}
-@code{load} command to download a file from Unix to VxWorks
-incrementally. The object file given as an argument to the @code{load}
-command is actually opened twice: first by the VxWorks target in order
-to download the code, then by @value{GDBN} in order to read the symbol
-table. This can lead to problems if the current working directories on
-the two systems differ. If both systems have NFS mounted the same
-filesystems, you can avoid these problems by using absolute paths.
-Otherwise, it is simplest to set the working directory on both systems
-to the directory in which the object file resides, and then to reference
-the file by its name, without any path. For instance, a program
-@file{prog.o} may reside in @file{@var{vxpath}/vw/demo/rdb} in VxWorks
-and in @file{@var{hostpath}/vw/demo/rdb} on the host. To load this
-program, type this on VxWorks:
+@kindex set wtx stack-size
+@item set wtx stack-size @var{size}
+Change the stack size (in bytes) of the tasks spawned by the debugger
+(using the @code{run} command). This does not affect the stack size
+of a task spawned by other tasks, even if those tasks are under debugger
+control. The default is 0x10000 bytes.
+
+@kindex show wtx stack-size
+@item show wtx stack-size
+Display the size of the stack allocated when spawning a new task from
+the debugger (using the @code{run} command).
+
+@kindex set wtx task-options
+@item set wtx task-options @var{val}
+Change the options argument used when spawning a new task from
+@value{GDBN}. Bits in this options argument are defined in
+@file{wpwr/target/h/taskLib.h}. The default value is 0.
+
+@kindex show wtx task-options
+@item show wtx task-options
+Show the options argument used when spawning a new task from
+@value{GDBN}.
+
+@kindex set wtx task-priority
+@item set wtx task-priority @var{priority}
+Change the priority of new tasks spawned by the debugger. The default
+is 100.
+
+@kindex show wtx task-priority
+@item show wtx task-priority
+Print the task priority used when spawning new tasks from the debugger.
+
+@end table
+
+Some commands are also available to query the Target Server about
+the system running on the target.
+
+@table @code
+
+@kindex info wtx
+@item info wtx
+@item info wtx version
+Display the version of the WTX protocol in use.
@smallexample
--> cd "@var{vxpath}/vw/demo/rdb"
+(@value{GDBP}) info wtx
+WTX protocol version 2
@end smallexample
-@noindent
-Then, in @value{GDBN}, type:
+@kindex info wtx vxworks-version
+@item info wtx vxworks-version
+Display the version of the VxWorks system running on the target.
@smallexample
-(vxgdb) cd @var{hostpath}/vw/demo/rdb
-(vxgdb) load prog.o
+(@value{GDBP}) info wtx vxworks-version
+VxWorks version 5.5
@end smallexample
-@value{GDBN} displays a response similar to this:
+@kindex info wtx target-server
+@item info wtx target-server
+Display the target specifications provided by the target server.
@smallexample
-Reading symbol data from wherever/vw/demo/rdb/prog.o... done.
+(@value{GDBP}) info wtx target-server
+Target agent:
+version: 2.0
+max transfer size in bytes: 1372
+available agent modes: 3
+
+Runtime:
+name: VxWorks
+version: 5.5
+target processor type: 94
+has write protect: 0
+page size: 4096
+endianness: 1234
+BSP: Motorola MVME5110-2153 - MPC 7410
+boot file: myhost:/path/to/vxWorks
+target main memory base address: 0
+target memory size: 268435456
+number of memory regions: 0
+target server memory pool base: 0x1ff558
+target server memory pool size: 16646314
@end smallexample
-You can also use the @code{load} command to reload an object module
-after editing and recompiling the corresponding source file. Note that
-this makes @value{GDBN} delete all currently-defined breakpoints,
-auto-displays, and convenience variables, and to clear the value
-history. (This is necessary in order to preserve the integrity of
-debugger's data structures that reference the target system's symbol
-table.)
+@end table
-@node VxWorks Attach
-@subsubsection Running Tasks
+Some of the information (such as the list of tasks currently running
+on the system) can only be retrieved by using some of TCL procedures
+provided by VxWorks. A minimal TCL intepreter is therefore included
+in GDB.
-@cindex running VxWorks tasks
-You can also attach to an existing task using the @code{attach} command as
-follows:
+@table @code
+@kindex tcl
+@item tcl @code{tcl-command}
+Use the TCL interpreter to evaluate the @code{tcl-command}.
+@end table
-@smallexample
-(vxgdb) attach @var{task}
-@end smallexample
+Finally, the following commands may be useful to @value{GDBN}
+maintainers wishing to instrument the part of the code in
+@value{GDBN} responsible for supporting the WTX protocol.
-@noindent
-where @var{task} is the VxWorks hexadecimal task ID. The task can be running
-or suspended when you attach to it. Running tasks are suspended at
-the time of attachment.
+@table @code
+@kindex set wtx debug events
+@item set wtx debug events @var{level}
+If @var{level} is nonzero, print debug traces related to WTX event
+handling. The events being traced are all the events that wtxEventGet
+returns (Eg: breakpoint events, watchpoint events, new modules loaded,
+etc@dots{}).
+
+@kindex show wtx debug events
+@item show wtx debug events
+Print the current trace level for WTX event handling.
+
+@kindex set wtx debug objfiles
+@item set wtx debug objfiles @var{level}
+If @var{level} is nonzero, print debug traces related to module
+handling for WTX (modules are stored as @dfn{objfiles} in
+@value{GDBN}).
+
+@kindex show wtx debug objfiles
+@item show wtx debug objfiles
+Print th current trace level for WTX module handling.
+
+@kindex set wtx debug breakpoints
+@item set wtx debug breakpoints @var{level}
+If @var{level} is nonzero, print debug traces related to WTX
+breakpoint handling.
+
+@kindex show wtx debug breakpoints
+@item show wtx debug breakpoints
+Print the current trace level for WTX breakpoint event handling.
+
+@kindex set wtx debug watchpoints
+@item set wtx debug watchpoints @var{level}
+If @var{level} is nonzero, print debug traces related to WTX
+watchpoint handling.
+
+@kindex show wtx debug watchpoints
+@item show wtx debug watchpoints
+Print the current trace level for WTX watchpoint event handling.
+
+@kindex set wtx debug tcl
+@item set wtx debug tcl @var{level}
+Set the verbosity level of error messages from the TCL interpreter.
+
+@kindex show wtx debug tcl
+@item show wtx debug tcl
+Show the verbosity level of error messages from the TCL interpreter.
+
+@end table
+
+@subsubsection Debugging on VxWorks 6
+
+Debugging on VxWorks 6 follows the same principles as those for
+debugging VxWorks 5. The main difference is that @value{GDBN} needs
+to connect to a DFW server in addition to the Target Server. The
+@dfn{DFW server} is another server running on the host (see your
+VxWorks 6 Manuals for more information about this process).
+
+To start a debugging session, use the @code{target dfw} command.
+It will get both DFW and WTX connections established (therefore, do
+not use the @code{target wtx} command with VxWorks 6).
+
+@subsubsection Commands and Settings Related to DFW
+
+The following settings are provided:
+
+@table @code
+
+@kindex set dfw timeout
+@item set dfw timeout @var{duration}
+Change the timeout (in seconds) used when trying to read from the
+connection with the DFW server. The default value is 30 seconds.
+
+@kindex show dfw timeout
+@item show dfw timeout
+Show the duration in seconds before an attempt to read data from
+the DFW server should time out.
+
+@kindex set dfw server-name
+@item set dfw server-name @var{name}
+Set the name of the DFW server as registered in the WIND registry.
+By default, it is set to @code{dfw}; if only one DFW server is
+registered in the registry, GDB will connect to this server by
+default.
+
+@kindex show dfw server-name
+@item show dfw server-name
+Show the name of the DFW server.
+
+@end table
+
+The following commands may be useful to @value{GDBN} maintainers
+wishing to instrument the part of the code in @value{GDBN}
+responsible for supporting the DFW protocol.
+
+@table @code
+
+@kindex dfw send
+@item dfw send
+Send a request to the current DFW server.
+
+@kindex set dfw debug requests
+@item set dfw debug requests
+@item set dfw debug requests on
+Print the requests sent to the DFW server to stdout.
+
+@item set dfw debug requests off
+Do not print the requests sent to the DFW server to stdout.
+
+@kindex show dfw debug requests
+@item show dfw debug requests
+Show whether to show the requests sent to the DFW server.
+
+@kindex set dfw debug responses
+@item set dfw debug responses
+@item set dfw debug responses on
+Print the responses of the DFW server to stdout.
+
+@item set dfw debug responses off
+Do not print the responses of the DFW server to stdout.
+
+@kindex show dfw debug responses
+@item show dfw debug responses
+Show whether to show the responses sent by the DFW server.
+
+@kindex set dfw debug unknown-identifiers
+@item set dfw debug unknown-identifiers
+@item set dfw debug unknown-identifiers on
+Print a warning if the DFW server returns an identifier
+that is not known for task types (e.g. ``RTP''), task states
+(e.g. ``running''), event kinds (e.g. ``download-failed'').
+
+@item set dfw debug unknown-identifiers off
+Disable warnings about unknown task types, task states, event kinds.
+
+@kindex show dfw debug unknown-identifiers
+@item show dfw debug unknown-identifiers
+Show whether to warn about unknown task types, task states, event kinds.
+
+@end table
+
+@subsubsection VxWorks Module Handling
+@cindex VxWorks, Module Handling
+
+Unlike most Operating Systems, the loading of modules in memory has
+to be performed manually by the user. Modules can be a self-contained
+program, or just part of a program consisting of multiple modules
+(this is similar to programs depending on shared libraries).
+
+To load a new module on the target, use the @code{load} command.
+In addition to loading the module on the target, the debugger will
+also load its symbol table and debugging information.
+
+Modules may also be unloaded at any time, using the @code{unload}
+command.
+
+@table @code
+@kindex wtx add-symbol-file
+@item wtx add-symbol-file @var{file}
+This command is similar to the @code{add-symbol-file} command, except
+that it does not require base addresses to be provided. Instead,
+these addresses are automatically computed based on some information
+provided by the Target Server.
+
+This command is normally rarely needed, since GDB should
+automatically load the symbols from all modules either when
+connecting to the target, or when the module is loaded on the
+target. But this may become useful when the module fullpath
+provided by the target server does not correspond to the
+module's fullpath on the host where GDB is running.
+@end table
@node Embedded Processors
@section Embedded Processors
--
1.7.0.4
^ permalink raw reply [flat|nested] 54+ messages in thread
* Re: [PATCH 16/18] Add tdep files for x86 and powerpc.
2011-02-24 17:59 ` [PATCH 16/18] Add tdep files for x86 and powerpc Joel Brobecker
@ 2011-02-24 18:58 ` Mark Kettenis
2011-02-25 8:29 ` Joel Brobecker
0 siblings, 1 reply; 54+ messages in thread
From: Mark Kettenis @ 2011-02-24 18:58 UTC (permalink / raw)
To: brobecker; +Cc: gdb-patches, brobecker
> From: Joel Brobecker <brobecker@adacore.com>
> Cc: Joel Brobecker <brobecker@adacore.com>
>
> This patch adds a new GDB_OSABI_VXWORKS for VxWorks targets, and
> introduces new VxWorks tdep files for x86 and powerpc. They will
> be included in the build by the next patch.
>
> gdb/ChangeLog:
>
> * defs.h (enum gdb_osabi): Add GDB_OSABI_VXWORKS.
> * osabi.c (gdb_osabi_names): Add entry for GDB_OSABI_VXWORKS.
> * i386-vxworks-tdep.c, rs6000-vxworks-tdep.c: New files.
> ---
> gdb/defs.h | 1 +
> gdb/i386-vxworks-tdep.c | 53 +++++++++++++++++++++++
> gdb/osabi.c | 1 +
> gdb/rs6000-vxworks-tdep.c | 105 +++++++++++++++++++++++++++++++++++++++++++++
> 4 files changed, 160 insertions(+), 0 deletions(-)
> create mode 100644 gdb/i386-vxworks-tdep.c
> create mode 100644 gdb/rs6000-vxworks-tdep.c
The i386 bits have my blessing. The powerpc bits look a bit weird though:
> +static CORE_ADDR
> +rs6000_vxworks_push_dummy_code (struct gdbarch *gdbarch,
> + CORE_ADDR sp, CORE_ADDR funaddr,
> + struct value **args, int nargs,
> + struct type *value_type,
> + CORE_ADDR *real_pc, CORE_ADDR *bp_addr,
> + struct regcache *regcache)
> +{
> + /* Something here to findout the size of a breakpoint and then
> + allocate space for it on the stack. */
> + int bplen;
> + /* This code assumes frame align. */
> + gdb_assert (gdbarch_frame_align_p (gdbarch));
> + /* Force the stack's alignment. The intent is to ensure that the SP
> + is aligned to at least a breakpoint instruction's boundary. */
> + sp = gdbarch_frame_align (gdbarch, sp);
> + /* Allocate space for, and then position the breakpoint on the stack. */
> + if (gdbarch_inner_than (gdbarch, 1, 2))
> + {
> + CORE_ADDR bppc = sp;
> + gdbarch_breakpoint_from_pc (gdbarch, &bppc, &bplen);
> + sp = gdbarch_frame_align (gdbarch, sp - bplen);
> + (*bp_addr) = sp;
> + /* Should the breakpoint size/location be re-computed here? */
> + }
> + else
> + {
> + (*bp_addr) = sp;
> + gdbarch_breakpoint_from_pc (gdbarch, bp_addr, &bplen);
> + sp = gdbarch_frame_align (gdbarch, sp + bplen);
> + }
This bit of code looks like it is trying to support both stacks
growing up and stack growing down. Does that really happen on
VxWorks? Your code doesn't call set_gdbarch_inner_than(), so at least
one of these branches must be dead code.
^ permalink raw reply [flat|nested] 54+ messages in thread
* Re: [PATCH 02/18] New command_post observer
2011-02-24 17:50 ` [PATCH 02/18] New command_post observer Joel Brobecker
@ 2011-02-24 18:58 ` Tom Tromey
0 siblings, 0 replies; 54+ messages in thread
From: Tom Tromey @ 2011-02-24 18:58 UTC (permalink / raw)
To: Joel Brobecker; +Cc: gdb-patches
>>>>> "Joel" == Joel Brobecker <brobecker@adacore.com> writes:
Joel> What we are trying to do is to keep the user informed of the current
Joel> PD (which is identified by either PD ID or name, but we like to print
Joel> both).
I have a patch kicking around here to add prompt substitutions to gdb.
This might be a nice fit for this use.
I can try to submit this soon if you think it is worthwhile. I wasn't
really sure.
Joel> This patch introduces an observer (command_post) that gets triggered
Joel> at the end of a command execution...
I think an observer for this is fine...
Joel> (execute_command): Call observer_notify_command_post.
... but putting it here seems a little strange.
I think this will trigger after any command that is executed, including
commands in "command" or in a "define" or via Python's gdb.execute.
I would have thought that a "top-level" notification would have been
more along the lines of what you wanted.
Tom
^ permalink raw reply [flat|nested] 54+ messages in thread
* Re: [PATCH 03/18] New general purpose routines in utils.c
2011-02-24 17:50 ` [PATCH 03/18] New general purpose routines in utils.c Joel Brobecker
@ 2011-02-24 19:06 ` Tom Tromey
0 siblings, 0 replies; 54+ messages in thread
From: Tom Tromey @ 2011-02-24 19:06 UTC (permalink / raw)
To: Joel Brobecker; +Cc: gdb-patches
>>>>> "Joel" == Joel Brobecker <brobecker@adacore.com> writes:
Joel> (skip_whitespace, skip_until_character, skip_until_whitespace)
skip_until_whitespace and skip_until_whitespace (with a different name)
are in cli-utils.c now.
I think the other arg-parsing utility functions from this patch should
go there too.
Tom
^ permalink raw reply [flat|nested] 54+ messages in thread
* Re: [PATCH 04/18] add new "unload" command (symetry of existing "load" command)
2011-02-24 17:50 ` [PATCH 04/18] add new "unload" command (symetry of existing "load" command) Joel Brobecker
@ 2011-02-24 19:22 ` Eli Zaretskii
0 siblings, 0 replies; 54+ messages in thread
From: Eli Zaretskii @ 2011-02-24 19:22 UTC (permalink / raw)
To: Joel Brobecker; +Cc: gdb-patches, brobecker
> From: Joel Brobecker <brobecker@adacore.com>
> Cc: Joel Brobecker <brobecker@adacore.com>
> Date: Thu, 24 Feb 2011 12:49:09 -0500
>
> +If your @value{GDBN} does not have an @code{unload} command, attempting
> +to execute it triggers the error message ``@code{You can't do that when
> +your target is @dots{}}''
``@code{...}'' is wrong, because in Info output, @code adds yet
another quote, which is too much. How about @emph{..} instead, like
so:
@emph{"You can't do that when your target is @dots{}"}
The documentation part is okay with this change.
^ permalink raw reply [flat|nested] 54+ messages in thread
* Re: [PATCH 06/18] New module remote-wtx-utils
2011-02-24 17:54 ` [PATCH 06/18] New module remote-wtx-utils Joel Brobecker
@ 2011-02-24 19:26 ` Tom Tromey
0 siblings, 0 replies; 54+ messages in thread
From: Tom Tromey @ 2011-02-24 19:26 UTC (permalink / raw)
To: Joel Brobecker; +Cc: gdb-patches
>>>>> "Joel" == Joel Brobecker <brobecker@adacore.com> writes:
Joel> I rewrote a bit the routines to depend on two functions gdb_dlopen and
Joel> gdb_dlsym which we could isolate in its own gdb_dlfcn.h/c if we wanted to.
The problem with putting stuff like this into a place like
remote-wtx-utils.c is that if somebody does need it later, they probably
will not know it exists, and will reimplement. This happens with some
of the CLI utility functions.
I think it is somewhat better to pick a generic spot to put the new
functions, and just make the most convenient failure choice -- like, if
they aren't available, have them internal_error or whatever else is
convenient and unambiguous.
That said, it doesn't matter hugely to me.
Joel> +void *
Joel> +load_shared_lib (char *lib_name)
I think the argument could be const.
Joel> +void *
Joel> +get_symbol_from_shared_lib (void *handle, char *symbol)
Likewise.
Tom
^ permalink raw reply [flat|nested] 54+ messages in thread
* Re: [PATCH 07/18] remote-wtxapi: The WTX API abstraction layer.
2011-02-24 17:56 ` [PATCH 07/18] remote-wtxapi: The WTX API abstraction layer Joel Brobecker
@ 2011-02-24 19:44 ` Tom Tromey
0 siblings, 0 replies; 54+ messages in thread
From: Tom Tromey @ 2011-02-24 19:44 UTC (permalink / raw)
To: Joel Brobecker; +Cc: gdb-patches
>>>>> "Joel" == Joel Brobecker <brobecker@adacore.com> writes:
I did not really try to read this patch, but I randomly noticed:
Joel> +static void
Joel> +wtxapi_parse_obj_unloaded_event (char *event_str,
Joel> + struct wtxapi_obj_unloaded_event *event)
[...]
Joel> + wtx_opt_events_debug (1, "OBJ_LOADED: module_filename = \"%s\"",
Joel> + event->module_filename);
I think that should probably say `OBJ_UNLOADED'.
Tom
^ permalink raw reply [flat|nested] 54+ messages in thread
* Re: [PATCH 18/18] document the new VxWorks port
2011-02-24 18:04 ` [PATCH 18/18] document the new VxWorks port Joel Brobecker
@ 2011-02-24 20:27 ` Eli Zaretskii
2011-02-25 11:12 ` Jerome Guitton
2011-03-03 12:16 ` Joel Brobecker
0 siblings, 2 replies; 54+ messages in thread
From: Eli Zaretskii @ 2011-02-24 20:27 UTC (permalink / raw)
To: Joel Brobecker; +Cc: gdb-patches, brobecker
> From: Joel Brobecker <brobecker@adacore.com>
> Cc: Joel Brobecker <brobecker@adacore.com>
> Date: Thu, 24 Feb 2011 12:49:23 -0500
>
> The VxWorks documentation was completely out of date, so I rewrote it
> from scratch. I tried to organize it in a logical way, introducing
> some of the concepts about VxWorks, to make the port a little alien
> to someone who is not familiar with this OS.
>
> I've also included a NEWS entry.
Thanks.
> +VxWorks 653 i[34567]86-*-vxworks653
> + powerpc-*-vxworks653
> +VxWorks 6.x i[34567]86-*-vxworks6*
> + powerpc-*-vxworks6*
> + e500*-*-vxworks6*
> +VxWorks 5.x (x >= 4) i[34567]86-*-vxworks*
> + powerpc-*-vxworks*
This part is okay.
> +a @dfn{task} (a.k.a. a thread), usually using a symbol name as the entry
You need a "@:" after "a.k.a.", to indicate to TeX that the last
period does not end a sentence.
> +To create a new task under debugger control, use the @code{run}
> +command, passing as the first parameter the name of the symbol
> +to use as the entry point (all other parameters are ignored):
This seems to piggy-back the normal "run" command with a slightly
incompatible semantics, is that right? If so, I would mention where
"run" is described that there are additional VxWorks specific features
(imagine a user who debugs VxWorks and needs to consult the
description of "run"), with a cross-reference to here. And I would
also add here a @kindex entry like so:
@kindex run, with VxWorks
> +Instead of creating a new task, it is also possible to attach the
> +debugger to an already existing task, using the @code{attach} command.
> +The equivalent of the Unix process ID is the task ID on VxWorks, and
> +these IDs should be used to identify the task that needs to be
> +debugged.
Same here: add a note where "attach" is described, with reference, and
an index entry he.
> +@kindex info wtx threads
> +@item info wtx threads
Why a separate command? Isn't it possible to use "info threads"?
> +@cindex VxWorks, Multitasks Mode Debugging
> +@item Multitasks Mode
Is this really "Multitasks", with an `s' at the end? That sounds like
a typo to me.
> +This is a mode specific to Ada programs where the debugger simulates
> +the concept of debugging a process. This is useful when trying to debug
^^
Two spaces, please.
> +This mode is specific to Ada programs because it, because it relies
^^^^^^^^^^^^^^^^^^^^^^
Repetition.
> +@kindex set multi-tasks-mode
> +@item set multi-tasks-mode [on|off]
> +If @code{on}, activate multi-tasks mode. The default is @code{off}.
Is "multi-tasks mode" the same as "Multitasks Mode" above? We should
be consistent in how we spell the terminology.
> +This setting should be properly set before using the @code{attach}
> +or @code{run} command.
"setting should be set"? can we do better here?
Also, what does "properly" do here?
> +@subsubsection Debugging on VxWorks 653
A @cindex entry here will help.
> +@table @code
> +@kindex info partitions
> +@item info partitions
Why not "info wtx partitions", or some other variant to make sure this
is VxWorks specific? "info partitions" is too general to reserve for
a niche platform.
> +@kindex partition
> +@item partition @var{id-or-name}
Same here.
> +@kindex show wtx tool-name
> +@item show wtx tool-name
> +Display the tool name used when establishing a connection with the
> +WTX server.
> [...]
> +@kindex show wtx load-timeout
> +@item show wtx load-timeout
> +Print the timeout duration used when loading modules on the target.
Sometimes "display", sometimes "print".
> +handling. The events being traced are all the events that wtxEventGet
> +returns (Eg: breakpoint events, watchpoint events, new modules loaded,
^^^
"e.g.,"
> +etc@dots{}).
Either "etc" or "@dots{}", but not both.
> +to connect to a DFW server in addition to the Target Server. The
> +@dfn{DFW server} is another server running on the host (see your
Please use @dfn the first time you mention the term.
> +that is not known for task types (e.g. ``RTP''), task states
> +(e.g. ``running''), event kinds (e.g. ``download-failed'').
Either "@:" or a comma after each "e.g.".
Thanks.
^ permalink raw reply [flat|nested] 54+ messages in thread
* Re: [PATCH 16/18] Add tdep files for x86 and powerpc.
2011-02-24 18:58 ` Mark Kettenis
@ 2011-02-25 8:29 ` Joel Brobecker
0 siblings, 0 replies; 54+ messages in thread
From: Joel Brobecker @ 2011-02-25 8:29 UTC (permalink / raw)
To: Mark Kettenis; +Cc: gdb-patches
> The i386 bits have my blessing. The powerpc bits look a bit weird though:
Thanks for the review :).
> This bit of code looks like it is trying to support both stacks
> growing up and stack growing down. Does that really happen on
> VxWorks? Your code doesn't call set_gdbarch_inner_than(), so at least
> one of these branches must be dead code.
You are right to be puzzled by this code.
This code is actually a copy of a function that, as luck has it,
you removed a while ago because it was no longer used. It was
called something like generic_push_dummy_code. At the time,
I just copied the old function over.
In any case, I don't believe that I can have both direction on
powerpc-vxworks either, so I will clean it up.
--
Joel
^ permalink raw reply [flat|nested] 54+ messages in thread
* Re: [PATCH 18/18] document the new VxWorks port
2011-02-24 20:27 ` Eli Zaretskii
@ 2011-02-25 11:12 ` Jerome Guitton
2011-02-25 11:27 ` Eli Zaretskii
2011-03-03 12:16 ` Joel Brobecker
1 sibling, 1 reply; 54+ messages in thread
From: Jerome Guitton @ 2011-02-25 11:12 UTC (permalink / raw)
To: Eli Zaretskii; +Cc: Joel Brobecker, gdb-patches
Thank you for your review. I'll let Joel give a complete response;
I'll just answer one of your questions:
> > +@kindex info wtx threads
> > +@item info wtx threads
>
> Why a separate command? Isn't it possible to use "info threads"?
"info threads" lists only the threads of the inferior, whereas
"info wtx threads" lists all threads on target. Typically, to attach
to one. It would be similar to "shell ps" on a native configuration.
The reason why it is not called, say, "info wtx processes", is a
particularity of VxWorks: most applications actually run on kernel
space, and share the same memory area. So they are really threads, not
processes.
^ permalink raw reply [flat|nested] 54+ messages in thread
* Re: [PATCH 18/18] document the new VxWorks port
2011-02-25 11:12 ` Jerome Guitton
@ 2011-02-25 11:27 ` Eli Zaretskii
2011-02-25 11:38 ` Jerome Guitton
0 siblings, 1 reply; 54+ messages in thread
From: Eli Zaretskii @ 2011-02-25 11:27 UTC (permalink / raw)
To: Jerome Guitton; +Cc: brobecker, gdb-patches
> Date: Fri, 25 Feb 2011 11:26:24 +0100
> From: Jerome Guitton <guitton@adacore.com>
> Cc: Joel Brobecker <brobecker@adacore.com>, gdb-patches@sourceware.org
>
>
> Thank you for your review. I'll let Joel give a complete response;
> I'll just answer one of your questions:
>
> > > +@kindex info wtx threads
> > > +@item info wtx threads
> >
> > Why a separate command? Isn't it possible to use "info threads"?
>
> "info threads" lists only the threads of the inferior, whereas
> "info wtx threads" lists all threads on target.
Since there's no "inferior" on this target, is it so bad to show all
the threads?
And what does "info threads" do on that target?
> The reason why it is not called, say, "info wtx processes", is a
> particularity of VxWorks: most applications actually run on kernel
> space, and share the same memory area. So they are really threads, not
> processes.
That's fine, but then why not treat them as threads?
^ permalink raw reply [flat|nested] 54+ messages in thread
* Re: [PATCH 18/18] document the new VxWorks port
2011-02-25 11:38 ` Jerome Guitton
@ 2011-02-25 11:38 ` Joel Brobecker
2011-02-25 12:08 ` Eli Zaretskii
2011-02-25 11:44 ` Eli Zaretskii
1 sibling, 1 reply; 54+ messages in thread
From: Joel Brobecker @ 2011-02-25 11:38 UTC (permalink / raw)
To: Jerome Guitton; +Cc: Eli Zaretskii, gdb-patches
> > And what does "info threads" do on that target?
>
> It depends. In single-task mode, it displays only the thread being
> debugged. In multi-tasks mode, it displays the list of threads that
> have been created by a given kernel module.
>
> In both cases, "info threads" actually displays the threads that we
> are debugging (e.g. that are stopped when a breakpoint is reached);
> whereas "info wtx threads" displays any task running on kernel space
> (even those that that are not being debugged).
To expand a bit on what Jerome is saying, the reason we also do not
want to show all the threads that are not being debugged, is that
we do not want the user to attempt to switch to a thread that he is
currently not debugging.
--
Joel
^ permalink raw reply [flat|nested] 54+ messages in thread
* Re: [PATCH 18/18] document the new VxWorks port
2011-02-25 11:27 ` Eli Zaretskii
@ 2011-02-25 11:38 ` Jerome Guitton
2011-02-25 11:38 ` Joel Brobecker
2011-02-25 11:44 ` Eli Zaretskii
0 siblings, 2 replies; 54+ messages in thread
From: Jerome Guitton @ 2011-02-25 11:38 UTC (permalink / raw)
To: Eli Zaretskii; +Cc: brobecker, gdb-patches
Eli Zaretskii (eliz@gnu.org):
> > > > +@kindex info wtx threads
> > > > +@item info wtx threads
> > >
> > > Why a separate command? Isn't it possible to use "info threads"?
> >
> > "info threads" lists only the threads of the inferior, whereas
> > "info wtx threads" lists all threads on target.
>
> Since there's no "inferior" on this target, is it so bad to show all
> the threads?
>
> And what does "info threads" do on that target?
It depends. In single-task mode, it displays only the thread being
debugged. In multi-tasks mode, it displays the list of threads that
have been created by a given kernel module.
In both cases, "info threads" actually displays the threads that we
are debugging (e.g. that are stopped when a breakpoint is reached);
whereas "info wtx threads" displays any task running on kernel space
(even those that that are not being debugged).
> > The reason why it is not called, say, "info wtx processes", is a
> > particularity of VxWorks: most applications actually run on kernel
> > space, and share the same memory area. So they are really threads, not
> > processes.
>
> That's fine, but then why not treat them as threads?
Well, the thing is that we have a sort of emulation of "processes"
(I'd guess that the concept of "thread group" would actually be a
better fit here) in multi-tasks mode. So we need to have a distinction
between the threads that are of interest for the debugger and the ones
that just happen to run on the same memory space.
^ permalink raw reply [flat|nested] 54+ messages in thread
* Re: [PATCH 18/18] document the new VxWorks port
2011-02-25 11:38 ` Jerome Guitton
2011-02-25 11:38 ` Joel Brobecker
@ 2011-02-25 11:44 ` Eli Zaretskii
2011-02-25 11:49 ` Joel Brobecker
1 sibling, 1 reply; 54+ messages in thread
From: Eli Zaretskii @ 2011-02-25 11:44 UTC (permalink / raw)
To: Jerome Guitton; +Cc: brobecker, gdb-patches
> Date: Fri, 25 Feb 2011 12:26:47 +0100
> From: Jerome Guitton <guitton@adacore.com>
> Cc: brobecker@adacore.com, gdb-patches@sourceware.org
>
> > > The reason why it is not called, say, "info wtx processes", is a
> > > particularity of VxWorks: most applications actually run on kernel
> > > space, and share the same memory area. So they are really threads, not
> > > processes.
> >
> > That's fine, but then why not treat them as threads?
>
> Well, the thing is that we have a sort of emulation of "processes"
> (I'd guess that the concept of "thread group" would actually be a
> better fit here) in multi-tasks mode. So we need to have a distinction
> between the threads that are of interest for the debugger and the ones
> that just happen to run on the same memory space.
The result looks like a bad UI to me, and requires a separate
command. But if that's what VxWorks users prefer, fine.
^ permalink raw reply [flat|nested] 54+ messages in thread
* Re: [PATCH 18/18] document the new VxWorks port
2011-02-25 11:44 ` Eli Zaretskii
@ 2011-02-25 11:49 ` Joel Brobecker
2011-02-25 11:55 ` Jerome Guitton
0 siblings, 1 reply; 54+ messages in thread
From: Joel Brobecker @ 2011-02-25 11:49 UTC (permalink / raw)
To: Eli Zaretskii; +Cc: Jerome Guitton, gdb-patches
> The result looks like a bad UI to me, and requires a separate
> command. But if that's what VxWorks users prefer, fine.
Does it still look bad to you after my explanation?
IMO, I think it's OK. We have several modes:
- single-task debugging: In that case, the task has only 1 thread.
Everything else is irrelevant.
- multi-task debugging: It's close to debugging a program.
We only show the threads running in that program.
- system-mode debugging (we debug the entire system as one giant
program). In that case, we show all the threads.
I think it makes sense. Perhaps, the confusion comes from the
"info wtx threads" command itself, since it is not listing threads,
but rather *tasks* (this is the technical term that WRS uses).
We could change that command to "info wtx tasks"... But if we do,
I'd to request that we also provide an alias to preserve compatibility
with the current users.
--
Joel
^ permalink raw reply [flat|nested] 54+ messages in thread
* Re: [PATCH 18/18] document the new VxWorks port
2011-02-25 11:49 ` Joel Brobecker
@ 2011-02-25 11:55 ` Jerome Guitton
2011-02-25 11:56 ` Joel Brobecker
0 siblings, 1 reply; 54+ messages in thread
From: Jerome Guitton @ 2011-02-25 11:55 UTC (permalink / raw)
To: Joel Brobecker; +Cc: Eli Zaretskii, gdb-patches
Joel Brobecker (brobecker@adacore.com):
> I think it makes sense. Perhaps, the confusion comes from the
> "info wtx threads" command itself, since it is not listing threads,
> but rather *tasks* (this is the technical term that WRS uses).
> We could change that command to "info wtx tasks"... But if we do,
> I'd to request that we also provide an alias to preserve compatibility
> with the current users.
Not sure that it would make this much clearer, as "info tasks" exists
as well. An other source of confusion here is that "task" means
also something different in Ada.
^ permalink raw reply [flat|nested] 54+ messages in thread
* Re: [PATCH 18/18] document the new VxWorks port
2011-02-25 11:55 ` Jerome Guitton
@ 2011-02-25 11:56 ` Joel Brobecker
2011-02-25 12:01 ` Pedro Alves
2011-02-25 12:05 ` Jerome Guitton
0 siblings, 2 replies; 54+ messages in thread
From: Joel Brobecker @ 2011-02-25 11:56 UTC (permalink / raw)
To: Jerome Guitton; +Cc: Eli Zaretskii, gdb-patches
> Not sure that it would make this much clearer, as "info tasks" exists
> as well. An other source of confusion here is that "task" means
> also something different in Ada.
But at the same time, we're saying threads when we really mean
"VxWorks Tasks", no? I think that the "wtx" prefix in the command
might help make things clearer. Otherwise, how about "info wtx
vxworks-tasks"?
--
Joel
^ permalink raw reply [flat|nested] 54+ messages in thread
* Re: [PATCH 18/18] document the new VxWorks port
2011-02-25 11:56 ` Joel Brobecker
@ 2011-02-25 12:01 ` Pedro Alves
2011-02-25 14:21 ` Joel Brobecker
2011-02-25 12:05 ` Jerome Guitton
1 sibling, 1 reply; 54+ messages in thread
From: Pedro Alves @ 2011-02-25 12:01 UTC (permalink / raw)
To: gdb-patches; +Cc: Joel Brobecker, Jerome Guitton, Eli Zaretskii
On Friday 25 February 2011 11:55:39, Joel Brobecker wrote:
> > Not sure that it would make this much clearer, as "info tasks" exists
> > as well. An other source of confusion here is that "task" means
> > also something different in Ada.
>
> But at the same time, we're saying threads when we really mean
> "VxWorks Tasks", no? I think that the "wtx" prefix in the command
> might help make things clearer. Otherwise, how about "info wtx
> vxworks-tasks"?
Of put this under the "info os" mechanism?
--
Pedro Alves
^ permalink raw reply [flat|nested] 54+ messages in thread
* Re: [PATCH 18/18] document the new VxWorks port
2011-02-25 11:56 ` Joel Brobecker
2011-02-25 12:01 ` Pedro Alves
@ 2011-02-25 12:05 ` Jerome Guitton
2011-02-25 12:15 ` Eli Zaretskii
1 sibling, 1 reply; 54+ messages in thread
From: Jerome Guitton @ 2011-02-25 12:05 UTC (permalink / raw)
To: Joel Brobecker; +Cc: Eli Zaretskii, gdb-patches
Joel Brobecker (brobecker@adacore.com):
> > Not sure that it would make this much clearer, as "info tasks" exists
> > as well. An other source of confusion here is that "task" means
> > also something different in Ada.
>
> But at the same time, we're saying threads when we really mean
> "VxWorks Tasks", no? I think that the "wtx" prefix in the command
> might help make things clearer. Otherwise, how about "info wtx
> vxworks-tasks"?
Interesting name. This command used to be called "info vxworks-tasks" :)
^ permalink raw reply [flat|nested] 54+ messages in thread
* Re: [PATCH 18/18] document the new VxWorks port
2011-02-25 11:38 ` Joel Brobecker
@ 2011-02-25 12:08 ` Eli Zaretskii
2011-02-25 13:26 ` Jerome Guitton
0 siblings, 1 reply; 54+ messages in thread
From: Eli Zaretskii @ 2011-02-25 12:08 UTC (permalink / raw)
To: Joel Brobecker; +Cc: guitton, gdb-patches
> Date: Fri, 25 Feb 2011 15:38:15 +0400
> From: Joel Brobecker <brobecker@adacore.com>
> Cc: Eli Zaretskii <eliz@gnu.org>, gdb-patches@sourceware.org
>
> To expand a bit on what Jerome is saying, the reason we also do not
> want to show all the threads that are not being debugged, is that
> we do not want the user to attempt to switch to a thread that he is
> currently not debugging.
But the same danger exists on other systems, and we still show all the
threads in the current inferior.
Maybe it would make sense to show only those that are being debugged,
but do it from "info threads". (Why would a user want to show other
threads, if she isn't debugging them?) But if showing them all is
also important, maybe that alone should be a separate wtx-specific
command?
^ permalink raw reply [flat|nested] 54+ messages in thread
* Re: [PATCH 18/18] document the new VxWorks port
2011-02-25 12:05 ` Jerome Guitton
@ 2011-02-25 12:15 ` Eli Zaretskii
2011-02-25 12:56 ` Joel Brobecker
0 siblings, 1 reply; 54+ messages in thread
From: Eli Zaretskii @ 2011-02-25 12:15 UTC (permalink / raw)
To: Jerome Guitton; +Cc: brobecker, gdb-patches
> Date: Fri, 25 Feb 2011 13:01:15 +0100
> From: Jerome Guitton <guitton@adacore.com>
> Cc: Eli Zaretskii <eliz@gnu.org>, gdb-patches@sourceware.org
>
> Joel Brobecker (brobecker@adacore.com):
>
> > > Not sure that it would make this much clearer, as "info tasks" exists
> > > as well. An other source of confusion here is that "task" means
> > > also something different in Ada.
> >
> > But at the same time, we're saying threads when we really mean
> > "VxWorks Tasks", no? I think that the "wtx" prefix in the command
> > might help make things clearer. Otherwise, how about "info wtx
> > vxworks-tasks"?
>
> Interesting name. This command used to be called "info vxworks-tasks" :)
Well, it sounds like a good name to me ;-)
^ permalink raw reply [flat|nested] 54+ messages in thread
* Re: [PATCH 18/18] document the new VxWorks port
2011-02-25 12:15 ` Eli Zaretskii
@ 2011-02-25 12:56 ` Joel Brobecker
2011-02-25 13:20 ` Eli Zaretskii
0 siblings, 1 reply; 54+ messages in thread
From: Joel Brobecker @ 2011-02-25 12:56 UTC (permalink / raw)
To: Eli Zaretskii; +Cc: Jerome Guitton, gdb-patches
> > Interesting name. This command used to be called "info vxworks-tasks" :)
>
> Well, it sounds like a good name to me ;-)
OK, so it sounds like we are converging (I read your other message,
and it seemed to me that we were saying the same thing). We originally
renamed that command because we didn't want to pollute the "info"
prefix with VxWorks-specific commands - which is why we created
the "info wtx" sub-prefix. So would "info wtx vxworks-tasks" be OK?
--
Joel
^ permalink raw reply [flat|nested] 54+ messages in thread
* Re: [PATCH 18/18] document the new VxWorks port
2011-02-25 12:56 ` Joel Brobecker
@ 2011-02-25 13:20 ` Eli Zaretskii
2011-02-25 14:11 ` Jerome Guitton
0 siblings, 1 reply; 54+ messages in thread
From: Eli Zaretskii @ 2011-02-25 13:20 UTC (permalink / raw)
To: Joel Brobecker; +Cc: guitton, gdb-patches
> Date: Fri, 25 Feb 2011 16:15:27 +0400
> From: Joel Brobecker <brobecker@adacore.com>
> Cc: Jerome Guitton <guitton@adacore.com>, gdb-patches@sourceware.org
>
> So would "info wtx vxworks-tasks" be OK?
Fine with me, thanks.
^ permalink raw reply [flat|nested] 54+ messages in thread
* Re: [PATCH 18/18] document the new VxWorks port
2011-02-25 12:08 ` Eli Zaretskii
@ 2011-02-25 13:26 ` Jerome Guitton
0 siblings, 0 replies; 54+ messages in thread
From: Jerome Guitton @ 2011-02-25 13:26 UTC (permalink / raw)
To: Eli Zaretskii; +Cc: Joel Brobecker, gdb-patches
Eli Zaretskii (eliz@gnu.org):
> Maybe it would make sense to show only those that are being debugged,
> but do it from "info threads". (Why would a user want to show other
> threads, if she isn't debugging them?)
To attach to running thread, actually. It is really similar to "shell ps".
^ permalink raw reply [flat|nested] 54+ messages in thread
* Re: [PATCH 18/18] document the new VxWorks port
2011-02-25 13:20 ` Eli Zaretskii
@ 2011-02-25 14:11 ` Jerome Guitton
0 siblings, 0 replies; 54+ messages in thread
From: Jerome Guitton @ 2011-02-25 14:11 UTC (permalink / raw)
To: Eli Zaretskii; +Cc: Joel Brobecker, gdb-patches
Eli Zaretskii (eliz@gnu.org):
> > Date: Fri, 25 Feb 2011 16:15:27 +0400
> > From: Joel Brobecker <brobecker@adacore.com>
> > Cc: Jerome Guitton <guitton@adacore.com>, gdb-patches@sourceware.org
> >
> > So would "info wtx vxworks-tasks" be OK?
>
> Fine with me, thanks.
OK, thank you.
^ permalink raw reply [flat|nested] 54+ messages in thread
* Re: [PATCH 18/18] document the new VxWorks port
2011-02-25 12:01 ` Pedro Alves
@ 2011-02-25 14:21 ` Joel Brobecker
2011-02-25 14:44 ` Pedro Alves
0 siblings, 1 reply; 54+ messages in thread
From: Joel Brobecker @ 2011-02-25 14:21 UTC (permalink / raw)
To: Pedro Alves; +Cc: gdb-patches, Jerome Guitton, Eli Zaretskii
> Of put this under the "info os" mechanism?
I don't think that we want to print the list of running VxWorks tasks
under "info os", but I think that the suggestion is interesting for
other, more static, things. For instance, VxWorks version, WTX protocol
version, etc. Keeping this in my mind for a rainy day...
--
Joel
^ permalink raw reply [flat|nested] 54+ messages in thread
* Re: [PATCH 18/18] document the new VxWorks port
2011-02-25 14:21 ` Joel Brobecker
@ 2011-02-25 14:44 ` Pedro Alves
2011-02-25 15:15 ` Joel Brobecker
0 siblings, 1 reply; 54+ messages in thread
From: Pedro Alves @ 2011-02-25 14:44 UTC (permalink / raw)
To: gdb-patches; +Cc: Joel Brobecker, Jerome Guitton, Eli Zaretskii
On Friday 25 February 2011 14:11:14, Joel Brobecker wrote:
> > Of put this under the "info os" mechanism?
>
> I don't think that we want to print the list of running VxWorks tasks
> under "info os", but I think that the suggestion is interesting for
> other, more static, things. For instance, VxWorks version, WTX protocol
> version, etc. Keeping this in my mind for a rainy day...
The "os" stands for OS-awareness, not for specific things about
the OS. E.g.,
"info os processes" prints the list of all running processes
under linux. It works like "shell ps" on the target, just
like Jerome mentioned. Here's what we have in one of our
local trees:
(top-gdb) info os
Type Description
processes Listing of all processes
procgroups Listing of all process groups
threads Listing of all threads
files Listing of all file descriptions
sockets Listing of all internet-domain sockets
shm Listing of all shared-memory regions
semaphores Listing of all semaphores
msg Listing of all message queues
modules Listing of all loaded kernel modules
(and a corresponding -info-os MI command, and corresponding
Eclipse/DSF support for listing all these tables, while
being completely agnostic of the tables it is actually
showing.)
--
Pedro Alves
^ permalink raw reply [flat|nested] 54+ messages in thread
* Re: [PATCH 18/18] document the new VxWorks port
2011-02-25 14:44 ` Pedro Alves
@ 2011-02-25 15:15 ` Joel Brobecker
0 siblings, 0 replies; 54+ messages in thread
From: Joel Brobecker @ 2011-02-25 15:15 UTC (permalink / raw)
To: Pedro Alves; +Cc: gdb-patches, Jerome Guitton, Eli Zaretskii
> "info os processes" prints the list of all running processes
> under linux. It works like "shell ps" on the target, just
> like Jerome mentioned. Here's what we have in one of our
> local trees:
Hmmm, you're right! I think "info os processes" and "info os modules"
could be pretty useful commands to have. I'm adding that to my
TODO list.
Thanks for the suggestion!
--
Joel
^ permalink raw reply [flat|nested] 54+ messages in thread
* Re: [PATCH 14/18] WTX-TCL support module
2011-02-24 17:57 ` [PATCH 14/18] WTX-TCL support module Joel Brobecker
@ 2011-02-25 15:59 ` Tom Tromey
2011-02-25 18:58 ` Joel Brobecker
0 siblings, 1 reply; 54+ messages in thread
From: Tom Tromey @ 2011-02-25 15:59 UTC (permalink / raw)
To: Joel Brobecker; +Cc: gdb-patches
>>>>> "Joel" == Joel Brobecker <brobecker@adacore.com> writes:
Joel> For VxWorks 5.x and 653, we need to use the TCL extension in order to
Joel> access some of the information we are looking for (list of VxWorks
Joel> tasks running on the target, for instance). This is only because
Joel> the WTX protocol does not provide access to this info.
Joel> +/* Includes from the VxWorks install. */
Joel> +#define HOST
Joel> +#include "tcl.h"
Joel> +#if WTX_PROT_VERSION != 4
Joel> +#include "wtxtcl.h"
Joel> +#endif
I guess this explains why the new code isn't part of
--enable-targets=all. I am somewhat concerned that this will lead to
bit-rot. I always build using this option in an attempt to avoid
breaking things; but this code will not be included in that.
I don't really see a way around it, though, unless you want to
virtualize all the wtx calls.
I guess I want us to be clear that build breakage for this is expected.
Joel> +static int
Joel> +wtxtcl_eval_verbose (char *str)
Joel> +{
Joel> + char *output;
Joel> + const int success = wtxtcl_eval (str, &output);
Joel> +
Joel> + if (success)
Joel> + printf_filtered ("%s\n", output);
Joel> + else
Joel> + printf_filtered (_("TCL error: %s\n"), output);
Joel> +
Joel> + return success;
Joel> +}
Joel> +
Joel> +/* Implement the "tcl" command. */
Joel> +
Joel> +static void
Joel> +tcl_command (char *args, int from_tty)
Joel> +{
Joel> + if (args == NULL)
Joel> + return;
Joel> +
Joel> + wtxtcl_eval_verbose (args);
Why not call error instead of just printing a message when a Tcl command
fails?
Joel> + tcl_cmd = xstrprintf ("taskInfoGet 0x%x", task_id);
Joel> + success = wtxtcl_eval (tcl_cmd, &task_info);
Nothing ever frees tcl_cmd.
Joel> + /* Skip the first 8 tokens and go directly to the 9th, which contains
Joel> + the PD ID. */
Joel> + for (j = 0; j < 8; j++)
Joel> + task_info = skip_space_delimited_token (task_info);
This is the wrong way to parse a Tcl list. It may work ok for your
purposes, if you know that the result can never include anything "weird".
But it is easy and safer to just use Tcl_SplitList.
Joel> + /* Parse the result. */
Joel> +
Joel> + current_thread = skip_whitespace (tcl_output);
Joel> + while (current_thread && *current_thread != '\0')
Joel> + {
Joel> + struct wtxapi_thread_info *new_thread
Joel> + = xmalloc (sizeof (struct wtxapi_thread_info));
Joel> +
Joel> + /* Get the thread id. */
Joel> + new_thread->id = strtoul (current_thread, NULL, 0);
Joel> + current_thread = skip_space_delimited_token (current_thread);
Joel> +
Joel> + /* Get the thread name. */
Joel> + current_thread = skip_whitespace (current_thread);
Joel> + if (*current_thread == '{')
Joel> + {
Joel> + /* The thread name delimited by curly braces. Find the
Joel> + closing curly brace. */
Joel> + char *start = current_thread + 1; /* skip the '{'... */
Joel> + char *end = skip_until_character (current_thread, '}');
Joel> + char tmp = *end;
Likewise.
Joel> + add_com ("tcl", class_obscure, tcl_command,
Joel> + _("Evaluate the arguments with the TCL interpreter"));
I am not super fond of a top-level command named "tcl".
Tom
^ permalink raw reply [flat|nested] 54+ messages in thread
* Re: [PATCH 13/18] Add new "wtx" target.
2011-02-24 17:57 ` [PATCH 13/18] Add new "wtx" target Joel Brobecker
@ 2011-02-25 16:15 ` Tom Tromey
2011-02-25 17:38 ` Joel Brobecker
0 siblings, 1 reply; 54+ messages in thread
From: Tom Tromey @ 2011-02-25 16:15 UTC (permalink / raw)
To: Joel Brobecker; +Cc: gdb-patches
>>>>> "Joel" == Joel Brobecker <brobecker@adacore.com> writes:
Joel> + /* FIXME: brobecker/2007-08-31: The current event handling in GDB
Joel> + doesn't really include support for exceptions. For now, treat
Joel> + this as an "unknown signal". Later on, we might want to improve
Joel> + a bit, and in particular display the exception value to the user. */
What are "exceptions" in this context?
Joel> + /* FIXME: The observer only passes the bpnum, which forces us
Joel> + to do a reverse search for the associated breakpoint structure.
Joel> + It is silly to have to do so when the observer had in fact
Joel> + the breakpoint structure and had to dereference it in order to
Joel> + pass the bpnum. Propose that the observer be enhanced when
Joel> + submitting this code to the FSF. */
:-)
Volodya has a patch to make exactly this change.
Tom
^ permalink raw reply [flat|nested] 54+ messages in thread
* Re: [PATCH 11/18] Add partition support.
2011-02-24 17:56 ` [PATCH 11/18] Add partition support Joel Brobecker
@ 2011-02-25 16:17 ` Tom Tromey
0 siblings, 0 replies; 54+ messages in thread
From: Tom Tromey @ 2011-02-25 16:17 UTC (permalink / raw)
To: Joel Brobecker; +Cc: gdb-patches
>>>>> "Joel" == Joel Brobecker <brobecker@adacore.com> writes:
Joel> +/* We need to keep the symbols in each PD separate from the others.
Joel> + One of the reasons is that 2 symbols with the same name are allowed to
Joel> + coexist in 653 provided that these 2 symbols live in 2 separate PDs.
Joel> + Another important reason is that virtual memory regions can overlap
Joel> + between PDs, and one symbol address in a PD is not suitable in the
Joel> + context of another PD.
Joel> +
Joel> + GDB maintains a global list of objfiles where the symbols can be found.
Joel> + To achieve this separation, we simply maintain one such list per PD in
Joel> + this module. At each PD change, we simply save the objfile list for
Joel> + the current PD, and restore it for the new PD. The net effect is that
Joel> + GDB will only recognize symbols in the current PD, and will complain if
Joel> + a user tries to do any operation that needs symbols from other PDs.
Joel> +
Joel> + In practice, GDB maintains a few other global variables that also
Joel> + need to be saved/restored, but the principle remains valid.
Joel> +
Joel> + If would have been slicker to actually maintain one list of objfiles
Joel> + for all PDs and modify GDB to automatically switch to the right PD
Joel> + when performing an operation such as inserting a BP in some code that's
Joel> + in a different partition. This would probably not be such a great
Joel> + improvment in terms of usability, but this would require a major
Typo, "improvement". Thanks, Emacs!
More importantly, why can't a PD be modeled using program- and
address-spaces inside GDB?
Tom
^ permalink raw reply [flat|nested] 54+ messages in thread
* Re: [PATCH 13/18] Add new "wtx" target.
2011-02-25 16:15 ` Tom Tromey
@ 2011-02-25 17:38 ` Joel Brobecker
0 siblings, 0 replies; 54+ messages in thread
From: Joel Brobecker @ 2011-02-25 17:38 UTC (permalink / raw)
To: Tom Tromey; +Cc: gdb-patches
> Joel> + /* FIXME: brobecker/2007-08-31: The current event handling in GDB
> Joel> + doesn't really include support for exceptions. For now, treat
> Joel> + this as an "unknown signal". Later on, we might want to improve
> Joel> + a bit, and in particular display the exception value to the user. */
>
> What are "exceptions" in this context?
It's a VxWorks exception. I can't remember completely the details
anymore, but the exception also carries an exception number, which
provides some extra info as to what caused the exception.
> Joel> + /* FIXME: The observer only passes the bpnum, which forces us
> Joel> + to do a reverse search for the associated breakpoint structure.
> Joel> + It is silly to have to do so when the observer had in fact
> Joel> + the breakpoint structure and had to dereference it in order to
> Joel> + pass the bpnum. Propose that the observer be enhanced when
> Joel> + submitting this code to the FSF. */
>
> :-)
>
> Volodya has a patch to make exactly this change.
I'm going to put that in my TODO list, to do ASAP as a followup patch.
It's been bugging me ever since I argued about that when the observer
was initially introduced.
--
Joel
^ permalink raw reply [flat|nested] 54+ messages in thread
* Re: [PATCH 14/18] WTX-TCL support module
2011-02-25 15:59 ` Tom Tromey
@ 2011-02-25 18:58 ` Joel Brobecker
2011-02-28 15:37 ` Tom Tromey
0 siblings, 1 reply; 54+ messages in thread
From: Joel Brobecker @ 2011-02-25 18:58 UTC (permalink / raw)
To: Tom Tromey; +Cc: gdb-patches
Thanks for the review!
(it's really late now, for me, but I wanted to give a brief answer)
> I guess this explains why the new code isn't part of
> --enable-targets=all. I am somewhat concerned that this will lead to
> bit-rot. I always build using this option in an attempt to avoid
> breaking things; but this code will not be included in that.
>
> I don't really see a way around it, though, unless you want to
> virtualize all the wtx calls.
>
> I guess I want us to be clear that build breakage for this is expected.
I think that's fair. I don't see what kind of virtualization you
are proposing that would help with that. Note that we link against
the TCL library provided by WindRiver. In all honesty, I didn't
really think about using a different TCL, since we didn't need to.
The good news is that, in the 5 or 6 years since I wrote the code,
I never experienced any breakage (that I can remember!)
I'll take care of all the other things you pointed out.
> Joel> + add_com ("tcl", class_obscure, tcl_command,
> Joel> + _("Evaluate the arguments with the TCL interpreter"));
>
> I am not super fond of a top-level command named "tcl".
I wasn't sure about that. I don't mind changing it. I thought that,
since it's another intepreter like Python, it might make sense to
put it in the top-level namespace. But I can either make it a subcommand
like "wtx tcl", or if you have another command name in mind, let me
know.
--
Joel
^ permalink raw reply [flat|nested] 54+ messages in thread
* Re: [PATCH 14/18] WTX-TCL support module
2011-02-25 18:58 ` Joel Brobecker
@ 2011-02-28 15:37 ` Tom Tromey
0 siblings, 0 replies; 54+ messages in thread
From: Tom Tromey @ 2011-02-28 15:37 UTC (permalink / raw)
To: Joel Brobecker; +Cc: gdb-patches
Tom> I guess I want us to be clear that build breakage for this is expected.
Joel> I think that's fair. I don't see what kind of virtualization you
Joel> are proposing that would help with that.
You could do it in theory by dlopening all the needed libraries.
This is much more trouble than it is worth.
Tom> I am not super fond of a top-level command named "tcl".
Joel> I wasn't sure about that. I don't mind changing it. I thought that,
Joel> since it's another intepreter like Python, it might make sense to
Joel> put it in the top-level namespace. But I can either make it a subcommand
Joel> like "wtx tcl", or if you have another command name in mind, let me
Joel> know.
wtx is fine by me, or even maint.
Tom
^ permalink raw reply [flat|nested] 54+ messages in thread
* Re: [PATCH 18/18] document the new VxWorks port
2011-02-24 20:27 ` Eli Zaretskii
2011-02-25 11:12 ` Jerome Guitton
@ 2011-03-03 12:16 ` Joel Brobecker
2011-03-03 13:44 ` Eli Zaretskii
1 sibling, 1 reply; 54+ messages in thread
From: Joel Brobecker @ 2011-03-03 12:16 UTC (permalink / raw)
To: Eli Zaretskii; +Cc: gdb-patches
[-- Attachment #1: Type: text/plain, Size: 1450 bytes --]
Eli,
Thanks for the review.
I think I addressed all of your comments, except one, which I will
reply to below. You'll find 2 patches, a first one which just shows
the changes I made on top of the first patch, and then the second
one, which shows the new patch, in its entirety. Hopefully this will
help you find quickly which changes were made, and verify that all
your comments have been addressed correctly.
> > +@table @code
> > +@kindex info partitions
> > +@item info partitions
>
> Why not "info wtx partitions", or some other variant to make sure this
> is VxWorks specific? "info partitions" is too general to reserve for
> a niche platform.
The reason why this hasn't been put under the "wtx" prefix is because
I don't consider partitions to be a VxWorks-specific concept. I don't
know very much about the specifics, but I think that partitions are
defined by ARINC 653. But, beyond ARINC 653, I think that this concept
can be used in many areas, and we might find one day another platform
where the concept of partitions is used as well.
Right now, the implementation we have in GDB is ad hoc, and WTX calls
are hard-coded inside the partition support code. However, my plan,
if I have the courage and enough rainy days, is to make that entirely
generic, so that the code can be shared with other platforms that might
come up which also provides a form of partition support.
I hope that answers your concerns.
Thanks,
--
Joel
[-- Attachment #2: vxworks-doc-updates.diff --]
[-- Type: text/x-diff, Size: 9272 bytes --]
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index 493f338..02189c1 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -1903,7 +1903,9 @@ argument to @value{GDBN} (@pxref{Invocation, ,Getting In and Out of
If you are running your program in an execution environment that
supports processes, @code{run} creates an inferior process and makes
that process run your program. In some environments without processes,
-@code{run} jumps to the start of your program. Other targets,
+@code{run} jumps to the start of your program. On VxWorks, it
+spawns a new VxWorks task which starts executing using the first
+argument as the entry point (@pxref{VxWorks}). Other targets,
like @samp{remote}, are always running. If you get an error
message like this one:
@@ -2322,6 +2324,10 @@ targets.) The command takes as argument a process ID. The usual way to
find out the @var{process-id} of a Unix process is with the @code{ps} utility,
or with the @samp{jobs -l} shell command.
+On VxWorks, where we debug VxWorks tasks rather than processes,
+the Vxworks task ID is used to identify the task that needs to
+be debugged (@pxref{VxWorks}).
+
@code{attach} does not repeat if you press @key{RET} a second time after
executing the command.
@end table
@@ -17946,6 +17952,7 @@ sends all debugging comands (resume task execution, read memory, read
register, @dots{}) through the Target Server.
@subsubsection Debugging on VxWorks 5.5
+@cindex VxWorks 5.5, debugging on
Debugging a program on VxWorks 5.5 is performed by connecting to
the Target Server first. To establish this connection, use the
@@ -17964,10 +17971,12 @@ from these modules.
VxWorks does not have a concept of processes, or even programs, like
most Operating Systems do. Instead of running a program, one spawns
-a @dfn{task} (a.k.a. a thread), usually using a symbol name as the entry
-point for that thread. Every task created can be regarded as a kernel
-thread, since it shares memory and code with the rest of the system.
+a @dfn{task} (a.k.a.@: a thread), usually using a symbol name as
+the entry point for that thread. Every task created can be regarded
+as a kernel thread, since it shares memory and code with the rest of
+the system.
+@kindex run, with VxWorks
To create a new task under debugger control, use the @code{run}
command, passing as the first parameter the name of the symbol
to use as the entry point (all other parameters are ignored):
@@ -17977,6 +17986,7 @@ to use as the entry point (all other parameters are ignored):
[@dots{}]
@end smallexample
+@kindex attach, with VxWorks
Instead of creating a new task, it is also possible to attach the
debugger to an already existing task, using the @code{attach} command.
The equivalent of the Unix process ID is the task ID on VxWorks, and
@@ -17999,15 +18009,15 @@ A list of all tasks currently running on the target can be obtained
using the @code{info wtx threads} command.
@table @code
-@kindex info wtx threads
-@item info wtx threads
-Print the list of threads currently running on the target.
-Each line represents a thread, and contains 2 space-separated
+@kindex info wtx vxworks-tasks
+@item info wtx vxworks-tasks
+Print the list of VxWorks tasks currently running on the target.
+Each line represents a task, and contains 2 space-separated
elements. The first element is the task ID, and the second
is the task name.
@smallexample
-(@value{GDBP}) info wtx threads
+(@value{GDBP}) info wtx vxworks-tasks
0xf710190 tShell
0xf712430 tWdbTask
0xf715600 tTelnetd
@@ -18015,6 +18025,13 @@ is the task name.
@end smallexample
@end table
+@table @code
+@kindex info wtx threads
+@item info wtx threads
+This command is an alias of @code{info wtx vxworks-tasks}, provided
+to help upward-compatibility.
+@end table
+
GDB offers several modes for debugging VxWorks tasks:
@table @dfn
@@ -18025,8 +18042,8 @@ In this mode, only a single tasks is being debugged. Any other tasks,
including new tasks created by the task being debugged, are simply
ignored (their execution is not controlled by the debugger).
-@cindex VxWorks, Multitasks Mode Debugging
-@item Multitasks Mode
+@cindex VxWorks, Multi-tasks Mode Debugging
+@item Multi-tasks Mode
This is a mode specific to Ada programs where the debugger simulates
the concept of debugging a process. This is useful when trying to debug
an Ada program that uses the multi-tasking features of Ada.
@@ -18039,9 +18056,9 @@ are automatically stopped and put under debugger control. New tasks
being spawned by the Ada "program" are also automatically taken under
debugger control.
-This mode is specific to Ada programs because it, because it relies
-on the Ada runtime in order to extract the list of tasks currently
-running as part of the Ada program.
+This mode is specific to Ada programs because it relies on the Ada
+runtime in order to extract the list of tasks currently running
+as part of the Ada program.
@cindex VxWorks, System Mode Debugging
@item The System Mode
@@ -18056,15 +18073,16 @@ To leave System Mode, use @code{detach}.
@kindex set multi-tasks-mode
@item set multi-tasks-mode [on|off]
If @code{on}, activate multi-tasks mode. The default is @code{off}.
-This setting should be properly set before using the @code{attach}
-or @code{run} command. As long as GDB controls the execution of one
-or more tasks, attempting to change this setting will result in an
-error.
+This mode should be set before using the @code{attach} or @code{run}
+command, and it is not possible to change the debugging mode while
+controlling one or more tasks (attempting to do so will result in
+an error).
This setting is ignored when debugging in System Mode.
@end table
@subsubsection Debugging on VxWorks 653
+@cindex VxWorks 653, debugging on
Debugging on VxWorks 653 is very similar to debugging on VxWorks 5,
and the commands available for VxWorks 5 are also generally available
@@ -18117,7 +18135,7 @@ requested symbols - for more information, see your Tornado 653
Manuals).
@smallexample
-(@value{GDBP}) maintenance info link-path
+(@value{GDBP}) maintenance info link-path
Partition Name [Link Path]
0x356738 coreOS [.]
0xd799f0 ssl [.]
@@ -18141,7 +18159,7 @@ the debugging session. The default is @code{gdb}.
@kindex show wtx tool-name
@item show wtx tool-name
-Display the tool name used when establishing a connection with the
+Print the tool name used when establishing a connection with the
WTX server.
@kindex set wtx load-timeout
@@ -18162,7 +18180,7 @@ control. The default is 0x10000 bytes.
@kindex show wtx stack-size
@item show wtx stack-size
-Display the size of the stack allocated when spawning a new task from
+Print the size of the stack allocated when spawning a new task from
the debugger (using the @code{run} command).
@kindex set wtx task-options
@@ -18173,7 +18191,7 @@ Change the options argument used when spawning a new task from
@kindex show wtx task-options
@item show wtx task-options
-Show the options argument used when spawning a new task from
+Print the options argument used when spawning a new task from
@value{GDBN}.
@kindex set wtx task-priority
@@ -18260,8 +18278,8 @@ maintainers wishing to instrument the part of the code in
@item set wtx debug events @var{level}
If @var{level} is nonzero, print debug traces related to WTX event
handling. The events being traced are all the events that wtxEventGet
-returns (Eg: breakpoint events, watchpoint events, new modules loaded,
-etc@dots{}).
+returns (e.g., breakpoint events, watchpoint events, new modules loaded,
+@dots{}).
@kindex show wtx debug events
@item show wtx debug events
@@ -18301,16 +18319,17 @@ Set the verbosity level of error messages from the TCL interpreter.
@kindex show wtx debug tcl
@item show wtx debug tcl
-Show the verbosity level of error messages from the TCL interpreter.
+Print the verbosity level of error messages from the TCL interpreter.
@end table
@subsubsection Debugging on VxWorks 6
+@cindex VxWorks 6, debugging on
Debugging on VxWorks 6 follows the same principles as those for
debugging VxWorks 5. The main difference is that @value{GDBN} needs
-to connect to a DFW server in addition to the Target Server. The
-@dfn{DFW server} is another server running on the host (see your
+to connect to a @dfn{DFW server} in addition to the Target Server.
+The DFW server is another server running on the host (see your
VxWorks 6 Manuals for more information about this process).
To start a debugging session, use the @code{target dfw} command.
@@ -18384,8 +18403,8 @@ Show whether to show the responses sent by the DFW server.
@item set dfw debug unknown-identifiers
@item set dfw debug unknown-identifiers on
Print a warning if the DFW server returns an identifier
-that is not known for task types (e.g. ``RTP''), task states
-(e.g. ``running''), event kinds (e.g. ``download-failed'').
+that is not known for task types (e.g., ``RTP''), task states
+(e.g., ``running''), event kinds (e.g., ``download-failed'').
@item set dfw debug unknown-identifiers off
Disable warnings about unknown task types, task states, event kinds.
[-- Attachment #3: vxworks-doc-v2.diff --]
[-- Type: text/x-diff, Size: 25899 bytes --]
commit 02a260e67a68b8ac8b1a5300e5c1df011e0cd364
Author: Joel Brobecker <brobecker@adacore.com>
Date: Thu Feb 24 12:35:43 2011 -0500
document the new VxWorks port
The VxWorks documentation was completely out of date, so I rewrote it
from scratch. I tried to organize it in a logical way, introducing
some of the concepts about VxWorks, to make the port a little alien
to someone who is not familiar with this OS.
I've also included a NEWS entry.
gdb/ChangeLog:
* NEWS: Add entry documenting the new VxWorks ports.
gdb/doc/ChangeLog:
* gdb.texinfo (Starting): Add reference to VxWorks node.
(Attach): Likewise.
(VxWorks): Rewrite the VxWorks documentation.
diff --git a/gdb/NEWS b/gdb/NEWS
index fb36383..f442d98 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -162,6 +162,14 @@ ia64 HP-UX ia64-*-hpux*
Analog Devices, Inc. Blackfin Processor bfin-*
+VxWorks 653 i[34567]86-*-vxworks653
+ powerpc-*-vxworks653
+VxWorks 6.x i[34567]86-*-vxworks6*
+ powerpc-*-vxworks6*
+ e500*-*-vxworks6*
+VxWorks 5.x (x >= 4) i[34567]86-*-vxworks*
+ powerpc-*-vxworks*
+
* Ada task switching is now supported on sparc-elf targets when
debugging a program using the Ravenscar Profile. For more information,
see the "Tasking Support when using the Ravenscar Profile" section
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index ad6e2f4..02189c1 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -1903,7 +1903,9 @@ argument to @value{GDBN} (@pxref{Invocation, ,Getting In and Out of
If you are running your program in an execution environment that
supports processes, @code{run} creates an inferior process and makes
that process run your program. In some environments without processes,
-@code{run} jumps to the start of your program. Other targets,
+@code{run} jumps to the start of your program. On VxWorks, it
+spawns a new VxWorks task which starts executing using the first
+argument as the entry point (@pxref{VxWorks}). Other targets,
like @samp{remote}, are always running. If you get an error
message like this one:
@@ -2322,6 +2324,10 @@ targets.) The command takes as argument a process ID. The usual way to
find out the @var{process-id} of a Unix process is with the @code{ps} utility,
or with the @samp{jobs -l} shell command.
+On VxWorks, where we debug VxWorks tasks rather than processes,
+the Vxworks task ID is used to identify the task that needs to
+be debugged (@pxref{VxWorks}).
+
@code{attach} does not repeat if you press @key{RET} a second time after
executing the command.
@end table
@@ -17935,165 +17941,510 @@ various real-time operating systems.
@node VxWorks
@subsection Using @value{GDBN} with VxWorks
-
@cindex VxWorks
-@table @code
+Debugging on VxWorks is supported on VxWorks 5.5, all versions of
+Vworks 6 starting with version 6.4, and VxWorks 653. @value{GDBN}
+does not connect directly to the target running VxWorks, but instead
+relies on the @dfn{Target Server}, which is a process running on the
+host. The debugger establishes a connection with that process, and
+sends all debugging comands (resume task execution, read memory, read
+register, @dots{}) through the Target Server.
+
+@subsubsection Debugging on VxWorks 5.5
+@cindex VxWorks 5.5, debugging on
-@kindex target vxworks
-@item target vxworks @var{machinename}
-A VxWorks system, attached via TCP/IP. The argument @var{machinename}
-is the target system's machine name or IP address.
+Debugging a program on VxWorks 5.5 is performed by connecting to
+the Target Server first. To establish this connection, use the
+@code{target wtx} command (@dfn{WTX} is the name of the protocol
+used to communicate with the Target Server):
+@table @code
+@kindex target wtx
+@item target wtx @var{target-server-name}
+Connect @value{GDBN} to a Target Server whose name is
+@var{target-server-name}. Once the connection is established,
+@value{GDBN} queries the list of modules loaded on the target, and
+then proceeds to load the symbol table and debugging information
+from these modules.
@end table
-On VxWorks, @code{load} links @var{filename} dynamically on the
-current target system as well as adding its symbols in @value{GDBN}.
+VxWorks does not have a concept of processes, or even programs, like
+most Operating Systems do. Instead of running a program, one spawns
+a @dfn{task} (a.k.a.@: a thread), usually using a symbol name as
+the entry point for that thread. Every task created can be regarded
+as a kernel thread, since it shares memory and code with the rest of
+the system.
-@value{GDBN} enables developers to spawn and debug tasks running on networked
-VxWorks targets from a Unix host. Already-running tasks spawned from
-the VxWorks shell can also be debugged. @value{GDBN} uses code that runs on
-both the Unix host and on the VxWorks target. The program
-@code{@value{GDBP}} is installed and executed on the Unix host. (It may be
-installed with the name @code{vxgdb}, to distinguish it from a
-@value{GDBN} for debugging programs on the host itself.)
+@kindex run, with VxWorks
+To create a new task under debugger control, use the @code{run}
+command, passing as the first parameter the name of the symbol
+to use as the entry point (all other parameters are ignored):
-@table @code
-@item VxWorks-timeout @var{args}
-@kindex vxworks-timeout
-All VxWorks-based targets now support the option @code{vxworks-timeout}.
-This option is set by the user, and @var{args} represents the number of
-seconds @value{GDBN} waits for responses to rpc's. You might use this if
-your VxWorks target is a slow software simulator or is on the far side
-of a thin network line.
-@end table
-
-The following information on connecting to VxWorks was current when
-this manual was produced; newer releases of VxWorks may use revised
-procedures.
-
-@findex INCLUDE_RDB
-To use @value{GDBN} with VxWorks, you must rebuild your VxWorks kernel
-to include the remote debugging interface routines in the VxWorks
-library @file{rdb.a}. To do this, define @code{INCLUDE_RDB} in the
-VxWorks configuration file @file{configAll.h} and rebuild your VxWorks
-kernel. The resulting kernel contains @file{rdb.a}, and spawns the
-source debugging task @code{tRdbTask} when VxWorks is booted. For more
-information on configuring and remaking VxWorks, see the manufacturer's
-manual.
-@c VxWorks, see the @cite{VxWorks Programmer's Guide}.
-
-Once you have included @file{rdb.a} in your VxWorks system image and set
-your Unix execution search path to find @value{GDBN}, you are ready to
-run @value{GDBN}. From your Unix host, run @code{@value{GDBP}} (or
-@code{vxgdb}, depending on your installation).
+@smallexample
+(@value{GDBP}) run simple_main
+[@dots{}]
+@end smallexample
-@value{GDBN} comes up showing the prompt:
+@kindex attach, with VxWorks
+Instead of creating a new task, it is also possible to attach the
+debugger to an already existing task, using the @code{attach} command.
+The equivalent of the Unix process ID is the task ID on VxWorks, and
+these IDs should be used to identify the task that needs to be
+debugged.
@smallexample
-(vxgdb)
+(@value{GDBP}) attach 0xf70b0f0
+Attaching to task 0xf70b0f0.
+[@dots{}]
@end smallexample
-@menu
-* VxWorks Connection:: Connecting to VxWorks
-* VxWorks Download:: VxWorks download
-* VxWorks Attach:: Running tasks
-@end menu
+As a convenience, GDB allows the use of the task name as a parameter
+to the @code{attach} command, in place of the task ID. When a task
+name is specified, the first task whose name matches is selected.
+If there are more than one tasks with the same name, the selection
+process is random.
-@node VxWorks Connection
-@subsubsection Connecting to VxWorks
+A list of all tasks currently running on the target can be obtained
+using the @code{info wtx threads} command.
-The @value{GDBN} command @code{target} lets you connect to a VxWorks target on the
-network. To connect to a target whose host name is ``@code{tt}'', type:
+@table @code
+@kindex info wtx vxworks-tasks
+@item info wtx vxworks-tasks
+Print the list of VxWorks tasks currently running on the target.
+Each line represents a task, and contains 2 space-separated
+elements. The first element is the task ID, and the second
+is the task name.
@smallexample
-(vxgdb) target vxworks tt
+(@value{GDBP}) info wtx vxworks-tasks
+0xf710190 tShell
+0xf712430 tWdbTask
+0xf715600 tTelnetd
+[@dots{}]
@end smallexample
+@end table
-@need 750
-@value{GDBN} displays messages like these:
+@table @code
+@kindex info wtx threads
+@item info wtx threads
+This command is an alias of @code{info wtx vxworks-tasks}, provided
+to help upward-compatibility.
+@end table
+
+GDB offers several modes for debugging VxWorks tasks:
+
+@table @dfn
+
+@cindex VxWorks, Task Mode Debugging
+@item Task Mode
+In this mode, only a single tasks is being debugged. Any other tasks,
+including new tasks created by the task being debugged, are simply
+ignored (their execution is not controlled by the debugger).
+
+@cindex VxWorks, Multi-tasks Mode Debugging
+@item Multi-tasks Mode
+This is a mode specific to Ada programs where the debugger simulates
+the concept of debugging a process. This is useful when trying to debug
+an Ada program that uses the multi-tasking features of Ada.
+
+When debugging in this mode, all Ada tasks controlled by the Ada
+run-time library are under @value{GDBN} control, and their execution
+is automatically stopped or resumed as needed. In particular, when
+attaching to a task, all associated tasks in the same Ada "program"
+are automatically stopped and put under debugger control. New tasks
+being spawned by the Ada "program" are also automatically taken under
+debugger control.
+
+This mode is specific to Ada programs because it relies on the Ada
+runtime in order to extract the list of tasks currently running
+as part of the Ada program.
+
+@cindex VxWorks, System Mode Debugging
+@item The System Mode
+
+In this mode, the debugger controls the entire system as one process,
+including part of the system such as the scheduler, interrupt handlers,
+etc. To enter System Mode, simply use the @code{attach system} command.
+To leave System Mode, use @code{detach}.
+@end table
+
+@table @code
+@kindex set multi-tasks-mode
+@item set multi-tasks-mode [on|off]
+If @code{on}, activate multi-tasks mode. The default is @code{off}.
+This mode should be set before using the @code{attach} or @code{run}
+command, and it is not possible to change the debugging mode while
+controlling one or more tasks (attempting to do so will result in
+an error).
+
+This setting is ignored when debugging in System Mode.
+@end table
+
+@subsubsection Debugging on VxWorks 653
+@cindex VxWorks 653, debugging on
+
+Debugging on VxWorks 653 is very similar to debugging on VxWorks 5,
+and the commands available for VxWorks 5 are also generally available
+for VxWorks 653.
+
+The one important distinction is the fact that VxWorks 653 provides
+the concept of @dfn{Partitions}, as defined by the ARINC 653
+specification. These partitions usually have their own address space,
+and allow the user to make sure that tasks running in one partition
+cannot affect tasks running on another partition (on VxWorks AE,
+which is an ancestor of VxWorks 653, these partitions were called
+@dfn{Protection Domains}, or @dfn{PD} in short). Please refer to your
+VxWorks 653 manual for more information about the various types of
+partitions and their use.
+
+@table @code
+@kindex info partitions
+@item info partitions
+Print the list of existing partitions on the target system. Each line
+corresponds to a partition, and contains its ID and name. An asterisk
+@samp{*} at the start of one of the lines indicates the current partition.
@smallexample
-Attaching remote machine across net...
-Connected to tt.
+(@value{GDBP}) info partitions
+ PD-ID Name
+* 0x356738 coreOS
+ 0xd799f0 ssl
+ 0xd7ae20 part1
+ 0xd80750 part2
@end smallexample
-@need 1000
-@value{GDBN} then attempts to read the symbol tables of any object modules
-loaded into the VxWorks target since it was last booted. @value{GDBN} locates
-these files by searching the directories listed in the command search
-path (@pxref{Environment, ,Your Program's Environment}); if it fails
-to find an object file, it displays a message such as:
+@kindex partition
+@item partition @var{id-or-name}
+Switch to the given partition. The @var{id-or-name} argument can
+be either the partition ID (an hexadecimal number), or its name.
+
+@smallexample
+(@value{GDBP}) partition part1
+[Switching to Partition part1 (0xd7ae20)]
+(@value{GDBP}) partition 0xd80750
+[Switching to Partition part2 (0xd80750)]
+@end smallexample
+
+@kindex maintenance info link-path
+@item maintenance info link-path
+This is a command mostly aimed at helping GDB maintainers. It prints
+the @dfn{link path} of each partition (the @dfn{Link Path} is a path
+associated to each partition, and is used by the loader to find
+requested symbols - for more information, see your Tornado 653
+Manuals).
@smallexample
-prog.o: No such file or directory.
+(@value{GDBP}) maintenance info link-path
+Partition Name [Link Path]
+ 0x356738 coreOS [.]
+ 0xd799f0 ssl [.]
+ 0xd7ae20 part1 [.:ssl:ssl]
+ 0xd80750 part2 [.:ssl]
@end smallexample
-When this happens, add the appropriate directory to the search path with
-the @value{GDBN} command @code{path}, and execute the @code{target}
-command again.
+@end table
+
+@subsubsection Commands and Settings Related to WTX
+
+The following Settings are provided:
+
+@table @code
+@kindex set wtx tool-name
+@item set wtx tool-name @var{name}
+This command can be used to change the name of the tool given to
+the Target Server when establishing the connection. This is only
+for documentation and logging purposes as this has no effect on
+the debugging session. The default is @code{gdb}.
+
+@kindex show wtx tool-name
+@item show wtx tool-name
+Print the tool name used when establishing a connection with the
+WTX server.
+
+@kindex set wtx load-timeout
+@item set wtx load-timeout @var{timeout}
+Change the timeout (in seconds) used when loading new modules on
+the target. The default is 30 seconds.
+
+@kindex show wtx load-timeout
+@item show wtx load-timeout
+Print the timeout duration used when loading modules on the target.
+
+@kindex set wtx stack-size
+@item set wtx stack-size @var{size}
+Change the stack size (in bytes) of the tasks spawned by the debugger
+(using the @code{run} command). This does not affect the stack size
+of a task spawned by other tasks, even if those tasks are under debugger
+control. The default is 0x10000 bytes.
+
+@kindex show wtx stack-size
+@item show wtx stack-size
+Print the size of the stack allocated when spawning a new task from
+the debugger (using the @code{run} command).
+
+@kindex set wtx task-options
+@item set wtx task-options @var{val}
+Change the options argument used when spawning a new task from
+@value{GDBN}. Bits in this options argument are defined in
+@file{wpwr/target/h/taskLib.h}. The default value is 0.
+
+@kindex show wtx task-options
+@item show wtx task-options
+Print the options argument used when spawning a new task from
+@value{GDBN}.
+
+@kindex set wtx task-priority
+@item set wtx task-priority @var{priority}
+Change the priority of new tasks spawned by the debugger. The default
+is 100.
+
+@kindex show wtx task-priority
+@item show wtx task-priority
+Print the task priority used when spawning new tasks from the debugger.
+
+@end table
+
+Some commands are also available to query the Target Server about
+the system running on the target.
-@node VxWorks Download
-@subsubsection VxWorks Download
+@table @code
-@cindex download to VxWorks
-If you have connected to the VxWorks target and you want to debug an
-object that has not yet been loaded, you can use the @value{GDBN}
-@code{load} command to download a file from Unix to VxWorks
-incrementally. The object file given as an argument to the @code{load}
-command is actually opened twice: first by the VxWorks target in order
-to download the code, then by @value{GDBN} in order to read the symbol
-table. This can lead to problems if the current working directories on
-the two systems differ. If both systems have NFS mounted the same
-filesystems, you can avoid these problems by using absolute paths.
-Otherwise, it is simplest to set the working directory on both systems
-to the directory in which the object file resides, and then to reference
-the file by its name, without any path. For instance, a program
-@file{prog.o} may reside in @file{@var{vxpath}/vw/demo/rdb} in VxWorks
-and in @file{@var{hostpath}/vw/demo/rdb} on the host. To load this
-program, type this on VxWorks:
+@kindex info wtx
+@item info wtx
+@item info wtx version
+Display the version of the WTX protocol in use.
@smallexample
--> cd "@var{vxpath}/vw/demo/rdb"
+(@value{GDBP}) info wtx
+WTX protocol version 2
@end smallexample
-@noindent
-Then, in @value{GDBN}, type:
+@kindex info wtx vxworks-version
+@item info wtx vxworks-version
+Display the version of the VxWorks system running on the target.
@smallexample
-(vxgdb) cd @var{hostpath}/vw/demo/rdb
-(vxgdb) load prog.o
+(@value{GDBP}) info wtx vxworks-version
+VxWorks version 5.5
@end smallexample
-@value{GDBN} displays a response similar to this:
+@kindex info wtx target-server
+@item info wtx target-server
+Display the target specifications provided by the target server.
@smallexample
-Reading symbol data from wherever/vw/demo/rdb/prog.o... done.
+(@value{GDBP}) info wtx target-server
+Target agent:
+version: 2.0
+max transfer size in bytes: 1372
+available agent modes: 3
+
+Runtime:
+name: VxWorks
+version: 5.5
+target processor type: 94
+has write protect: 0
+page size: 4096
+endianness: 1234
+BSP: Motorola MVME5110-2153 - MPC 7410
+boot file: myhost:/path/to/vxWorks
+target main memory base address: 0
+target memory size: 268435456
+number of memory regions: 0
+target server memory pool base: 0x1ff558
+target server memory pool size: 16646314
@end smallexample
-You can also use the @code{load} command to reload an object module
-after editing and recompiling the corresponding source file. Note that
-this makes @value{GDBN} delete all currently-defined breakpoints,
-auto-displays, and convenience variables, and to clear the value
-history. (This is necessary in order to preserve the integrity of
-debugger's data structures that reference the target system's symbol
-table.)
+@end table
-@node VxWorks Attach
-@subsubsection Running Tasks
+Some of the information (such as the list of tasks currently running
+on the system) can only be retrieved by using some of TCL procedures
+provided by VxWorks. A minimal TCL intepreter is therefore included
+in GDB.
-@cindex running VxWorks tasks
-You can also attach to an existing task using the @code{attach} command as
-follows:
+@table @code
+@kindex maintenance tcl
+@item maintenance tcl @code{tcl-command}
+Use the TCL interpreter to evaluate the @code{tcl-command}.
+@end table
-@smallexample
-(vxgdb) attach @var{task}
-@end smallexample
+Finally, the following commands may be useful to @value{GDBN}
+maintainers wishing to instrument the part of the code in
+@value{GDBN} responsible for supporting the WTX protocol.
-@noindent
-where @var{task} is the VxWorks hexadecimal task ID. The task can be running
-or suspended when you attach to it. Running tasks are suspended at
-the time of attachment.
+@table @code
+@kindex set wtx debug events
+@item set wtx debug events @var{level}
+If @var{level} is nonzero, print debug traces related to WTX event
+handling. The events being traced are all the events that wtxEventGet
+returns (e.g., breakpoint events, watchpoint events, new modules loaded,
+@dots{}).
+
+@kindex show wtx debug events
+@item show wtx debug events
+Print the current trace level for WTX event handling.
+
+@kindex set wtx debug objfiles
+@item set wtx debug objfiles @var{level}
+If @var{level} is nonzero, print debug traces related to module
+handling for WTX (modules are stored as @dfn{objfiles} in
+@value{GDBN}).
+
+@kindex show wtx debug objfiles
+@item show wtx debug objfiles
+Print th current trace level for WTX module handling.
+
+@kindex set wtx debug breakpoints
+@item set wtx debug breakpoints @var{level}
+If @var{level} is nonzero, print debug traces related to WTX
+breakpoint handling.
+
+@kindex show wtx debug breakpoints
+@item show wtx debug breakpoints
+Print the current trace level for WTX breakpoint event handling.
+
+@kindex set wtx debug watchpoints
+@item set wtx debug watchpoints @var{level}
+If @var{level} is nonzero, print debug traces related to WTX
+watchpoint handling.
+
+@kindex show wtx debug watchpoints
+@item show wtx debug watchpoints
+Print the current trace level for WTX watchpoint event handling.
+
+@kindex set wtx debug tcl
+@item set wtx debug tcl @var{level}
+Set the verbosity level of error messages from the TCL interpreter.
+
+@kindex show wtx debug tcl
+@item show wtx debug tcl
+Print the verbosity level of error messages from the TCL interpreter.
+
+@end table
+
+@subsubsection Debugging on VxWorks 6
+@cindex VxWorks 6, debugging on
+
+Debugging on VxWorks 6 follows the same principles as those for
+debugging VxWorks 5. The main difference is that @value{GDBN} needs
+to connect to a @dfn{DFW server} in addition to the Target Server.
+The DFW server is another server running on the host (see your
+VxWorks 6 Manuals for more information about this process).
+
+To start a debugging session, use the @code{target dfw} command.
+It will get both DFW and WTX connections established (therefore, do
+not use the @code{target wtx} command with VxWorks 6).
+
+@subsubsection Commands and Settings Related to DFW
+
+The following settings are provided:
+
+@table @code
+
+@kindex set dfw timeout
+@item set dfw timeout @var{duration}
+Change the timeout (in seconds) used when trying to read from the
+connection with the DFW server. The default value is 30 seconds.
+
+@kindex show dfw timeout
+@item show dfw timeout
+Show the duration in seconds before an attempt to read data from
+the DFW server should time out.
+
+@kindex set dfw server-name
+@item set dfw server-name @var{name}
+Set the name of the DFW server as registered in the WIND registry.
+By default, it is set to @code{dfw}; if only one DFW server is
+registered in the registry, GDB will connect to this server by
+default.
+
+@kindex show dfw server-name
+@item show dfw server-name
+Show the name of the DFW server.
+
+@end table
+
+The following commands may be useful to @value{GDBN} maintainers
+wishing to instrument the part of the code in @value{GDBN}
+responsible for supporting the DFW protocol.
+
+@table @code
+
+@kindex dfw send
+@item dfw send
+Send a request to the current DFW server.
+
+@kindex set dfw debug requests
+@item set dfw debug requests
+@item set dfw debug requests on
+Print the requests sent to the DFW server to stdout.
+
+@item set dfw debug requests off
+Do not print the requests sent to the DFW server to stdout.
+
+@kindex show dfw debug requests
+@item show dfw debug requests
+Show whether to show the requests sent to the DFW server.
+
+@kindex set dfw debug responses
+@item set dfw debug responses
+@item set dfw debug responses on
+Print the responses of the DFW server to stdout.
+
+@item set dfw debug responses off
+Do not print the responses of the DFW server to stdout.
+
+@kindex show dfw debug responses
+@item show dfw debug responses
+Show whether to show the responses sent by the DFW server.
+
+@kindex set dfw debug unknown-identifiers
+@item set dfw debug unknown-identifiers
+@item set dfw debug unknown-identifiers on
+Print a warning if the DFW server returns an identifier
+that is not known for task types (e.g., ``RTP''), task states
+(e.g., ``running''), event kinds (e.g., ``download-failed'').
+
+@item set dfw debug unknown-identifiers off
+Disable warnings about unknown task types, task states, event kinds.
+
+@kindex show dfw debug unknown-identifiers
+@item show dfw debug unknown-identifiers
+Show whether to warn about unknown task types, task states, event kinds.
+
+@end table
+
+@subsubsection VxWorks Module Handling
+@cindex VxWorks, Module Handling
+
+Unlike most Operating Systems, the loading of modules in memory has
+to be performed manually by the user. Modules can be a self-contained
+program, or just part of a program consisting of multiple modules
+(this is similar to programs depending on shared libraries).
+
+To load a new module on the target, use the @code{load} command.
+In addition to loading the module on the target, the debugger will
+also load its symbol table and debugging information.
+
+Modules may also be unloaded at any time, using the @code{unload}
+command.
+
+@table @code
+@kindex wtx add-symbol-file
+@item wtx add-symbol-file @var{file}
+This command is similar to the @code{add-symbol-file} command, except
+that it does not require base addresses to be provided. Instead,
+these addresses are automatically computed based on some information
+provided by the Target Server.
+
+This command is normally rarely needed, since GDB should
+automatically load the symbols from all modules either when
+connecting to the target, or when the module is loaded on the
+target. But this may become useful when the module fullpath
+provided by the target server does not correspond to the
+module's fullpath on the host where GDB is running.
+@end table
@node Embedded Processors
@section Embedded Processors
^ permalink raw reply [flat|nested] 54+ messages in thread
* Re: [PATCH 18/18] document the new VxWorks port
2011-03-03 12:16 ` Joel Brobecker
@ 2011-03-03 13:44 ` Eli Zaretskii
0 siblings, 0 replies; 54+ messages in thread
From: Eli Zaretskii @ 2011-03-03 13:44 UTC (permalink / raw)
To: Joel Brobecker; +Cc: gdb-patches
> Date: Thu, 3 Mar 2011 16:16:00 +0400
> From: Joel Brobecker <brobecker@adacore.com>
> Cc: gdb-patches@sourceware.org
>
> > Why not "info wtx partitions", or some other variant to make sure this
> > is VxWorks specific? "info partitions" is too general to reserve for
> > a niche platform.
>
> The reason why this hasn't been put under the "wtx" prefix is because
> I don't consider partitions to be a VxWorks-specific concept. I don't
> know very much about the specifics, but I think that partitions are
> defined by ARINC 653. But, beyond ARINC 653, I think that this concept
> can be used in many areas, and we might find one day another platform
> where the concept of partitions is used as well.
>
> Right now, the implementation we have in GDB is ad hoc, and WTX calls
> are hard-coded inside the partition support code. However, my plan,
> if I have the courage and enough rainy days, is to make that entirely
> generic, so that the code can be shared with other platforms that might
> come up which also provides a form of partition support.
>
> I hope that answers your concerns.
Yes, thanks. The patch is fine to go in.
^ permalink raw reply [flat|nested] 54+ messages in thread
end of thread, other threads:[~2011-03-03 13:44 UTC | newest]
Thread overview: 54+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2011-02-24 17:49 Add support for VxWorks 5.x, 6.x and 653 Joel Brobecker
2011-02-24 17:49 ` [PATCH 01/18] Some ada-lang/ada-tasks routines needed by the VxWorks target Joel Brobecker
2011-02-24 17:50 ` [PATCH 03/18] New general purpose routines in utils.c Joel Brobecker
2011-02-24 19:06 ` Tom Tromey
2011-02-24 17:50 ` [PATCH 04/18] add new "unload" command (symetry of existing "load" command) Joel Brobecker
2011-02-24 19:22 ` Eli Zaretskii
2011-02-24 17:50 ` [PATCH 02/18] New command_post observer Joel Brobecker
2011-02-24 18:58 ` Tom Tromey
2011-02-24 17:51 ` [PATCH 05/18] new struct bp_target_info target_private_data field Joel Brobecker
2011-02-24 17:54 ` [PATCH 09/18] VxWorks breakpoint-handling module Joel Brobecker
2011-02-24 17:54 ` [PATCH 06/18] New module remote-wtx-utils Joel Brobecker
2011-02-24 19:26 ` Tom Tromey
2011-02-24 17:54 ` [PATCH 08/18] Add options to control Vxworks related settings Joel Brobecker
2011-02-24 17:55 ` [PATCH 10/18] "multi-tasks-mode" support Joel Brobecker
2011-02-24 17:56 ` [PATCH 11/18] Add partition support Joel Brobecker
2011-02-25 16:17 ` Tom Tromey
2011-02-24 17:56 ` [PATCH 07/18] remote-wtxapi: The WTX API abstraction layer Joel Brobecker
2011-02-24 19:44 ` Tom Tromey
2011-02-24 17:57 ` [PATCH 13/18] Add new "wtx" target Joel Brobecker
2011-02-25 16:15 ` Tom Tromey
2011-02-25 17:38 ` Joel Brobecker
2011-02-24 17:57 ` [PATCH 12/18] remote-wtx-hw: register fetch/store support Joel Brobecker
2011-02-24 17:57 ` [PATCH 14/18] WTX-TCL support module Joel Brobecker
2011-02-25 15:59 ` Tom Tromey
2011-02-25 18:58 ` Joel Brobecker
2011-02-28 15:37 ` Tom Tromey
2011-02-24 17:58 ` [PATCH 15/18] Add support for VxWorks 6 Joel Brobecker
2011-02-24 17:59 ` [PATCH 16/18] Add tdep files for x86 and powerpc Joel Brobecker
2011-02-24 18:58 ` Mark Kettenis
2011-02-25 8:29 ` Joel Brobecker
2011-02-24 17:59 ` [PATCH 17/18] Configury and Makefile updates for VxWorks Joel Brobecker
2011-02-24 18:04 ` [PATCH 18/18] document the new VxWorks port Joel Brobecker
2011-02-24 20:27 ` Eli Zaretskii
2011-02-25 11:12 ` Jerome Guitton
2011-02-25 11:27 ` Eli Zaretskii
2011-02-25 11:38 ` Jerome Guitton
2011-02-25 11:38 ` Joel Brobecker
2011-02-25 12:08 ` Eli Zaretskii
2011-02-25 13:26 ` Jerome Guitton
2011-02-25 11:44 ` Eli Zaretskii
2011-02-25 11:49 ` Joel Brobecker
2011-02-25 11:55 ` Jerome Guitton
2011-02-25 11:56 ` Joel Brobecker
2011-02-25 12:01 ` Pedro Alves
2011-02-25 14:21 ` Joel Brobecker
2011-02-25 14:44 ` Pedro Alves
2011-02-25 15:15 ` Joel Brobecker
2011-02-25 12:05 ` Jerome Guitton
2011-02-25 12:15 ` Eli Zaretskii
2011-02-25 12:56 ` Joel Brobecker
2011-02-25 13:20 ` Eli Zaretskii
2011-02-25 14:11 ` Jerome Guitton
2011-03-03 12:16 ` Joel Brobecker
2011-03-03 13:44 ` Eli Zaretskii
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox