This is the mail archive of the
gdb-patches@sourceware.org
mailing list for the GDB project.
[PATCH v3 1/4] tracepoint multithread and multiprocess support (GDB)
- From: Hui Zhu <hui_zhu at mentor dot com>
- To: gdb-patches ml <gdb-patches at sourceware dot org>
- Cc: Pedro Alves <palves at redhat dot com>, <lgustavo at codesourcery dot com>
- Date: Tue, 31 Dec 2013 11:29:35 +0800
- Subject: [PATCH v3 1/4] tracepoint multithread and multiprocess support (GDB)
- Authentication-results: sourceware.org; auth=none
This patch add 3 support to GDB:
1. Multithread tracepoint support.
In remote part, if a tracepoint is special for a thread, send P packet
with ptid of this thread to GDBstub.
2. Multiprocess tracepoint support.
This patch is for the gdbserver.
It will send ";MultiProcessTracepoint+" back to GDB if this gdbserver
support tracepoint.zhe
When cmd_qtdp got a "QTDP" packets that have P@var{thread-id}.
1. Get ptid from thread-id.
2. If this ptid's pid is not same with current process, send exx packets
back to GDB.
Hmm. Did you sync with Luis? ISTR he had some multi-process
tracing patches too. IIRC, he just made it so that tracepoints
apply to the current process, and then GDB made sure to set the
general thread/process (Hg) to the current process before setting
each tracepoint. So this error seems to go in that direction,
and the main desire here is to make the tracepoints thread-specific,
not really process-specific. Right?
The v1/v2 patches don't include this part of code. I merged them in these
verson patch. Then in defalut, the tracepoint info will saved in inferior
as trace_state.
When tracepoint.c's code want to access the trace_state, it will call
current_trace_state to get it. current_trace_state will get trace_state
from current_inferior.
This function doesn't need update remote, because a tracepoint is just
for current inferior. The gdbserver need some change, I will introduce
it clear in gdbserver's patch.
3. Multiprocess tracepoint together support.
It bases old design of GDB that control all the tracepoints together.
In current_trace_state, when target support "MultiProcessTracepointTogether",
It will return together_trace_state as current trace_state.
In remote part, when a tracepoint is not for a special thread (because ptid
for of thread already include pid of a inferior) and the gdbstub support
"MultiProcessTracepointTogether", send Pptid to gdbstub.
The import thing of 2 and 3 is current_trace_state need swith mode between
support "MultiProcessTracepointTogether" and not support it.
For example: when GDB is opened, "MultiProcessTracepointTogether" support
is closed, all the set of tracepoint will set to the trace_state of current
inferior. When gdb connect to a gdbstub that support
"MultiProcessTracepointTogether", current_trace_state will return
"together_trace_state" instead of the trace_state of current inferior.
If it is not be handled, all of the trace_state will left in the inferior.
This patch handle it with:
"current_trace_state_together" record the last mode when call current_trace_state.
So when current_trace_state is called next time, if the mode is changed,
trace_state will be copyed from inferior to together_trace_state or from
together_trace_state to inferior.
And I added a function that has relation with multithread and multiprocess
tracepoint.
When traceframe changed (tfind), function traceframe_changed_inferior_thread_select
will be called.
GDB will check if this traceframe has $pid, $lwp, $tid. If so, Try to
select this process and this thread that ptid is $pid, $lwp, $tid.
If not, if this tracepoint has inferior's info or thread's info, try to
select this process and this thread.
Please help me review it.
Thanks,
Hui
2013-12-31 Hui Zhu <hui@codesourcery.com>
Luis Machado <lgustavo@codesourcery.com>
* inferior.c (set_inferior): New function.
(inferior_command): Call set_inferior.
* inferior.h (set_inferior): New extern.
* remote.c (PACKET_MultiThreadTracepoint): New enum value.
(PACKET_MultiProcessTracepointTogether): New enum value.
(remote_protocol_packets): Support MultiThreadTracepoints
and MultiProcessTracepointTogether.
(remote_supports_multi_thread_tracepoint): New function.
(remote_supports_multi_process_tracepoint_together): New function.
(remote_download_tracepoint): Send ptid if need.
(remote_get_tracepoint_status): Ignore a tracepoint if it is not
for current inferior and curent target doesn't support multiprocess
tracepoint together.
(init_remote_ops): Initialize
remote_ops.to_supports_multi_thread_tracepoint and
remote_ops.to_supports_multi_process_tracepoint_together.
(_initialize_remote): Support MultiThreadTracepoints
and MultiProcessTracepointTogether.
* target.c (update_current_target): Initialize
to_supports_multi_thread_tracepoint and
to_supports_multi_process_tracepoint_together.
* target.h (target_ops): Add to_supports_multi_thread_tracepoint
and to_supports_multi_process_tracepoint_together.
(target_supports_multi_thread_tracepoint): New define.
(target_supports_multi_process_tracepoint_together): New define.
* tracepoint.c (tvariables, traceframe_number, tracepoint_number,
traceframe_info, trace_status): Deleted.
(trace_state): New struct.
(current_trace_state_together): New int.
(together_trace_state): New struct.
(current_trace_state): New function.
(current_trace_status): Return trace_status of current
trace_state.
(trace_inferior_data): New pointer.
(trace_inferior_data_cleanup): New function.
(get_trace_inferior_data): New function.
(trace_inferior_exit): New function.
(current_trace_state): New function.
(clear_traceframe_info): Get tstate from current_trace_state.
(set_traceframe_num): Ditto.
(set_tracepoint_num): Ditto.
(set_traceframe_context): Ditto.
(create_trace_state_variable): Ditto.
(find_trace_state_variable): Ditto.
(find_trace_state_variable_by_number): Ditto.
(delete_trace_state_variable): Ditto.
(delete_trace_variable_command): Ditto.
(tvariables_info_1): Ditto.
(save_trace_state_variables): Ditto.
(start_tracing): Ditto.
(trace_status_command): Ditto.
(trace_status_mi): Ditto.
(tfind_1): Ditto.
(trace_find_command): Ditto.
(trace_find_tracepoint_command): Ditto.
(get_traceframe_location): Ditto.
(trace_dump_command): Ditto.
(get_traceframe_number): Ditto.
(get_tracepoint_number): Ditto.
(set_current_traceframe): Ditto.
(set_traceframe_number): Ditto.
(make_cleanup_restore_current_traceframe): Ditto.
(make_cleanup_restore_traceframe_number): Ditto.
(create_tsv_from_upload): Ditto.
(merge_uploaded_trace_state_variables): Ditto.
(tfile_trace_find): Ditto.
(tfile_fetch_registers): Ditto.
(tfile_xfer_partial): Call get_traceframe_number.
(tfile_has_stack): Ditto.
(tfile_has_registers): Ditto.
(get_traceframe_info): Get tstate from current_trace_state.
(get_trace_state_variable_value): New function.
(traceframe_changed_inferior_thread_select): New function.
(_initialize_tracepoint): Initialize together_trace_state.
Register traceframe_changed_inferior_thread_select. Register
trace_inferior_exit. Initialize trace_inferior_data.
--- a/gdb/inferior.c
+++ b/gdb/inferior.c
@@ -688,25 +688,11 @@ kill_inferior_command (char *args, int f
bfd_cache_close_all ();
}
-static void
-inferior_command (char *args, int from_tty)
-{
- struct inferior *inf;
- int num;
-
- num = parse_and_eval_long (args);
-
- inf = find_inferior_id (num);
- if (inf == NULL)
- error (_("Inferior ID %d not known."), num);
-
- printf_filtered (_("[Switching to inferior %d [%s] (%s)]\n"),
- inf->num,
- inferior_pid_to_str (inf->pid),
- (inf->pspace->pspace_exec_filename != NULL
- ? inf->pspace->pspace_exec_filename
- : _("<noexec>")));
+/* Set INF as current inferior. */
+void
+set_inferior (struct inferior *inf)
+{
if (inf->pid != 0)
{
if (inf->pid != ptid_get_pid (inferior_ptid))
@@ -719,20 +705,39 @@ inferior_command (char *args, int from_t
switch_to_thread (tp->ptid);
}
-
- printf_filtered (_("[Switching to thread %d (%s)] "),
- pid_to_thread_id (inferior_ptid),
- target_pid_to_str (inferior_ptid));
}
else
{
- struct inferior *inf;
-
- inf = find_inferior_id (num);
set_current_inferior (inf);
switch_to_thread (null_ptid);
set_current_program_space (inf->pspace);
}
+}
+
+static void
+inferior_command (char *args, int from_tty)
+{
+ struct inferior *inf;
+ int num;
+
+ num = parse_and_eval_long (args);
+
+ inf = find_inferior_id (num);
+ if (inf == NULL)
+ error (_("Inferior ID %d not known."), num);
+
+ printf_filtered (_("[Switching to inferior %d [%s] (%s)]\n"),
+ inf->num,
+ inferior_pid_to_str (inf->pid),
+ (inf->pspace->pspace_exec_filename != NULL
+ ? inf->pspace->pspace_exec_filename
+ : _("<noexec>")));
+
+ set_inferior (inf);
+ if (inf->pid != 0)
+ printf_filtered (_("[Switching to thread %d (%s)] "),
+ pid_to_thread_id (inferior_ptid),
+ target_pid_to_str (inferior_ptid));
if (inf->pid != 0 && is_running (inferior_ptid))
ui_out_text (current_uiout, "(running)\n");
--- a/gdb/inferior.h
+++ b/gdb/inferior.h
@@ -641,6 +641,8 @@ extern void update_signals_program_targe
extern void signal_catch_update (const unsigned int *);
+extern void set_inferior (struct inferior *inf);
+
/* In some circumstances we allow a command to specify a numeric
signal. The idea is to keep these circumstances limited so that
users (and scripts) develop portable habits. For comparison,
--- a/gdb/remote.c
+++ b/gdb/remote.c
@@ -1367,6 +1367,8 @@ enum {
PACKET_Qbtrace_off,
PACKET_Qbtrace_bts,
PACKET_qXfer_btrace,
+ PACKET_MultiThreadTracepoint,
+ PACKET_MultiProcessTracepointTogether,
PACKET_MAX
};
@@ -4063,7 +4065,11 @@ static const struct protocol_feature rem
{ "Qbtrace:off", PACKET_DISABLE, remote_supported_packet, PACKET_Qbtrace_off },
{ "Qbtrace:bts", PACKET_DISABLE, remote_supported_packet, PACKET_Qbtrace_bts },
{ "qXfer:btrace:read", PACKET_DISABLE, remote_supported_packet,
- PACKET_qXfer_btrace }
+ PACKET_qXfer_btrace },
+ { "MultiThreadTracepoint", PACKET_DISABLE,
+ remote_supported_packet, PACKET_MultiThreadTracepoint },
+ { "MultiProcessTracepointTogether", PACKET_DISABLE,
+ remote_supported_packet, PACKET_MultiProcessTracepointTogether },
};
static char *remote_support_xml;
@@ -10437,6 +10443,20 @@ remote_supports_string_tracing (void)
}
static int
+remote_supports_multi_thread_tracepoint (void)
+{
+ return (remote_protocol_packets[PACKET_MultiThreadTracepoint].support
+ == PACKET_ENABLE);
+}
+
+static int
+remote_supports_multi_process_tracepoint_together (void)
+{
+ return (remote_protocol_packets[PACKET_MultiProcessTracepointTogether].support
+ == PACKET_ENABLE);
+}
+
+static int
remote_can_run_breakpoint_commands (void)
{
struct remote_state *rs = get_remote_state ();
@@ -10593,6 +10613,55 @@ remote_download_tracepoint (struct bp_lo
to give up on the trace run. */
error (_("Target does not support static tracepoints"));
}
+
+ /* If target support multiprocess tracepoint together or tracepoint is
+ special a thread, send ptid of the location's program space with
+ packets if need. */
+ if (remote_protocol_packets[PACKET_MultiProcessTracepointTogether].support
+ == PACKET_ENABLE
+ || loc->owner->thread != -1)
+ {
+ ptid_t tracepoint_ptid;
+ struct remote_state *rs = get_remote_state ();
+ int got_tracepoint_ptid = 0;
+
+ if (loc->owner->thread != -1)
+ {
+ if (remote_protocol_packets[PACKET_MultiThreadTracepoint].support
+ != PACKET_ENABLE)
+ error (_("Target does not support multithread tracepoint"));
+ tracepoint_ptid = thread_id_to_pid (loc->owner->thread);
+ if (!in_thread_list (tracepoint_ptid))
+ error (_("Cannot find thread %d for tracepoint %d"),
+ loc->owner->thread, loc->owner->number);
+ got_tracepoint_ptid = 1;
+ }
+ else if (remote_protocol_packets[PACKET_MultiProcessTracepointTogether].support
+ == PACKET_ENABLE
+ && remote_multi_process_p (rs))
+ {
+ struct inferior *inf;
+
+ ALL_INFERIORS (inf)
+ {
+ if (inf->pspace == loc->pspace)
+ {
+ tracepoint_ptid = ptid_build (inf->pid, 0, 0);
+ got_tracepoint_ptid = 1;
+ break;
+ }
+ }
+ if (got_tracepoint_ptid == 0)
+ error (_("Cannot find inferior for tracepoint %d"),
+ loc->owner->number);
+ }
+ if (got_tracepoint_ptid)
+ {
+ strcat (buf, ":P");
+ write_ptid (buf + strlen (buf), buf + BUF_SIZE, tracepoint_ptid);
+ }
+ }
+
/* If the tracepoint has a conditional, make it into an agent
expression and append to the definition. */
if (loc->cond)
@@ -10896,6 +10965,7 @@ remote_get_tracepoint_status (struct bre
struct bp_location *loc;
struct tracepoint *tp = (struct tracepoint *) bp;
size_t size = get_remote_packet_size ();
+ struct inferior *inf = current_inferior ();
if (tp)
{
@@ -10903,6 +10973,11 @@ remote_get_tracepoint_status (struct bre
tp->traceframe_usage = 0;
for (loc = tp->base.loc; loc; loc = loc->next)
{
+ if (remote_protocol_packets[PACKET_MultiProcessTracepointTogether].support
+ != PACKET_ENABLE
+ && inf->pspace != loc->pspace)
+ continue;
+
/* If the tracepoint was never downloaded, don't go asking for
any status. */
if (tp->number_on_target == 0)
@@ -11557,6 +11632,10 @@ Specify the serial device it is connecte
remote_ops.to_fileio_readlink = remote_hostio_readlink;
remote_ops.to_supports_enable_disable_tracepoint = remote_supports_enable_disable_tracepoint;
remote_ops.to_supports_string_tracing = remote_supports_string_tracing;
+ remote_ops.to_supports_multi_thread_tracepoint
+ = remote_supports_multi_thread_tracepoint;
+ remote_ops.to_supports_multi_process_tracepoint_together
+ = remote_supports_multi_process_tracepoint_together;
remote_ops.to_supports_evaluation_of_breakpoint_conditions = remote_supports_cond_breakpoints;
remote_ops.to_can_run_breakpoint_commands = remote_can_run_breakpoint_commands;
remote_ops.to_trace_init = remote_trace_init;
@@ -12183,6 +12262,12 @@ Show the maximum size of the address (in
add_packet_config_cmd (&remote_protocol_packets[PACKET_qXfer_btrace],
"qXfer:btrace", "read-btrace", 0);
+ add_packet_config_cmd (&remote_protocol_packets[PACKET_MultiThreadTracepoint],
+ "MultiThreadTracepoint", "multi-thread-tracepoint", 0);
+
+ add_packet_config_cmd (&remote_protocol_packets[PACKET_MultiProcessTracepointTogether],
+ "MultiProcessTracepointTogether", "multi-process-tracepoint-together", 0);
+
/* Keep the old ``set remote Z-packet ...'' working. Each individual
Z sub-packet has its own set and show commands, but users may
have sets to this variable in their .gdbinit files (or in their
--- a/gdb/target.c
+++ b/gdb/target.c
@@ -657,6 +657,8 @@ update_current_target (void)
INHERIT (to_supports_multi_process, t);
INHERIT (to_supports_enable_disable_tracepoint, t);
INHERIT (to_supports_string_tracing, t);
+ INHERIT (to_supports_multi_thread_tracepoint, t);
+ INHERIT (to_supports_multi_process_tracepoint_together, t);
INHERIT (to_trace_init, t);
INHERIT (to_download_tracepoint, t);
INHERIT (to_can_download_tracepoint, t);
@@ -838,6 +840,12 @@ update_current_target (void)
de_fault (to_supports_string_tracing,
(int (*) (void))
return_zero);
+ de_fault (to_supports_multi_thread_tracepoint,
+ (int (*) (void))
+ return_zero);
+ de_fault (to_supports_multi_process_tracepoint_together,
+ (int (*) (void))
+ return_zero);
de_fault (to_trace_init,
(void (*) (void))
tcomplain);
--- a/gdb/target.h
+++ b/gdb/target.h
@@ -619,6 +619,12 @@ struct target_ops
/* Does this target support the tracenz bytecode for string collection? */
int (*to_supports_string_tracing) (void);
+ /* Does this target support the multithread tracepoint. */
+ int (*to_supports_multi_thread_tracepoint) (void);
+
+ /* Does this target support the multiprocess tracepoint together. */
+ int (*to_supports_multi_process_tracepoint_together) (void);
+
/* Does this target support evaluation of breakpoint conditions on its
end? */
int (*to_supports_evaluation_of_breakpoint_conditions) (void);
@@ -1038,6 +1044,12 @@ int target_supports_disable_randomizatio
#define target_supports_string_tracing() \
(*current_target.to_supports_string_tracing) ()
+#define target_supports_multi_thread_tracepoint() \
+ (*current_target.to_supports_multi_thread_tracepoint) ()
+
+#define target_supports_multi_process_tracepoint_together() \
+ (*current_target.to_supports_multi_process_tracepoint_together) ()
+
/* Returns true if this target can handle breakpoint conditions
on its end. */
--- a/gdb/tracepoint.c
+++ b/gdb/tracepoint.c
@@ -121,23 +121,43 @@ void (*deprecated_trace_start_stop_hook)
typedef struct trace_state_variable tsv_s;
DEF_VEC_O(tsv_s);
-static VEC(tsv_s) *tvariables;
+struct trace_state
+{
+ VEC(tsv_s) *tvariables;
-/* The next integer to assign to a variable. */
+ /* Number of last traceframe collected. */
+ int traceframe_number;
-static int next_tsv_number = 1;
+ /* Tracepoint for last traceframe collected. */
+ int tracepoint_number;
-/* Number of last traceframe collected. */
-static int traceframe_number;
+ /* Symbol for function for last traceframe collected. */
+ struct symbol *traceframe_fun;
-/* Tracepoint for last traceframe collected. */
-static int tracepoint_number;
+ /* Symtab and line for last traceframe collected. */
+ struct symtab_and_line traceframe_sal;
-/* The traceframe info of the current traceframe. NULL if we haven't
- yet attempted to fetch it, or if the target does not support
- fetching this object, or if we're not inspecting a traceframe
- presently. */
-static struct traceframe_info *traceframe_info;
+ /* The traceframe info of the current traceframe. NULL if we haven't
+ yet attempted to fetch it, or if the target does not support
+ fetching this object, or if we're not inspecting a traceframe
+ presently. */
+ struct traceframe_info *traceframe_info;
+
+ /* The load map info for the current process. */
+ struct load_map_info *load_map;
+
+ struct trace_status trace_status;
+};
+
+/* True if current trace state is together_trace_state. */
+static int current_trace_state_together = 0;
+
+/* If current target support multiprocess tracepoint together,
+ use this struct as current trace state. */
+static struct trace_state together_trace_state;
+
+/* The next integer to assign to a variable. */
+static int next_tsv_number = 1;
/* Tracing command lists. */
static struct cmd_list_element *tfindlist;
@@ -196,9 +216,9 @@ static void free_uploaded_tsvs (struct u
static struct command_line *
all_tracepoint_actions_and_cleanup (struct breakpoint *t);
-extern void _initialize_tracepoint (void);
+static struct trace_state *current_trace_state (void);
-static struct trace_status trace_status;
+extern void _initialize_tracepoint (void);
char *stop_reason_names[] = {
"tunknown",
@@ -213,7 +233,88 @@ char *stop_reason_names[] = {
struct trace_status *
current_trace_status (void)
{
- return &trace_status;
+ return ¤t_trace_state ()->trace_status;
+}
+
+/* Per-inferior trace state data key. */
+static const struct inferior_data *trace_inferior_data;
+
+/* Clears the inferior-specific trace state fields. */
+
+static void
+trace_inferior_data_cleanup (struct inferior *inf, void *arg)
+{
+ struct trace_state *tstate;
+
+ tstate = inferior_data (inf, trace_inferior_data);
+ if (tstate != NULL)
+ {
+ xfree (tstate);
+ set_inferior_data (inf, trace_inferior_data, NULL);
+ }
+}
+
+/* Fetch the inferior-specific trace state. */
+
+static struct trace_state *
+get_trace_inferior_data (struct inferior *inf)
+{
+ struct trace_state *tstate;
+
+ tstate = inferior_data (inf, trace_inferior_data);
+ if (tstate == NULL)
+ {
+ tstate = XZALLOC (struct trace_state);
+ set_inferior_data (inf, trace_inferior_data, tstate);
+ tstate->traceframe_number = -1;
+ tstate->tracepoint_number = -1;
+ }
+
+ return tstate;
+}
+
+/* This is a "inferior_exit" observer. Releases the TRACE_STATE member
+ of the inferior structure. This field is private to tracepoint.c, and
+ its type is opaque to the rest of GDB. */
+
+static void
+trace_inferior_exit (struct inferior *inf)
+{
+ struct trace_state *tstate;
+
+ tstate = inferior_data (inf, trace_inferior_data);
+ if (tstate != NULL)
+ {
+ xfree (tstate);
+ set_inferior_data (inf, trace_inferior_data, NULL);
+ }
+}
+
+/* Fetches the trace state for the current inferior. */
+
+static struct trace_state *
+current_trace_state (void)
+{
+ if (target_supports_multi_process_tracepoint_together ())
+ {
+ if (!ptid_equal (inferior_ptid, null_ptid)
+ && current_trace_state_together == 0)
+ {
+ memcpy (&together_trace_state,
+ get_trace_inferior_data (current_inferior ()),
+ sizeof (together_trace_state));
+ current_trace_state_together = 1;
+ }
+ return &together_trace_state;
+ }
+
+ if (current_trace_state_together == 1)
+ {
+ memcpy (get_trace_inferior_data (current_inferior ()),
+ &together_trace_state, sizeof (together_trace_state));
+ current_trace_state_together = 0;
+ }
+ return get_trace_inferior_data (current_inferior ());
}
/* Destroy INFO. */
@@ -236,15 +337,19 @@ free_traceframe_info (struct traceframe_
static void
clear_traceframe_info (void)
{
- free_traceframe_info (traceframe_info);
- traceframe_info = NULL;
+ struct trace_state *tstate = current_trace_state ();
+
+ free_traceframe_info (tstate->traceframe_info);
+ tstate->traceframe_info = NULL;
}
/* Set traceframe number to NUM. */
static void
set_traceframe_num (int num)
{
- traceframe_number = num;
+ struct trace_state *tstate = current_trace_state ();
+
+ tstate->traceframe_number = num;
set_internalvar_integer (lookup_internalvar ("trace_frame"), num);
}
@@ -252,7 +357,9 @@ set_traceframe_num (int num)
static void
set_tracepoint_num (int num)
{
- tracepoint_number = num;
+ struct trace_state *tstate = current_trace_state ();
+
+ tstate->tracepoint_number = num;
set_internalvar_integer (lookup_internalvar ("tracepoint"), num);
}
@@ -265,42 +372,44 @@ set_traceframe_context (struct frame_inf
CORE_ADDR trace_pc;
struct symbol *traceframe_fun;
struct symtab_and_line traceframe_sal;
+ struct trace_state *tstate = current_trace_state ();
/* Save as globals for internal use. */
if (trace_frame != NULL
&& get_frame_pc_if_available (trace_frame, &trace_pc))
{
- traceframe_sal = find_pc_line (trace_pc, 0);
- traceframe_fun = find_pc_function (trace_pc);
+ tstate->traceframe_sal = find_pc_line (trace_pc, 0);
+ tstate->traceframe_fun = find_pc_function (trace_pc);
/* Save linenumber as "$trace_line", a debugger variable visible to
users. */
set_internalvar_integer (lookup_internalvar ("trace_line"),
- traceframe_sal.line);
+ tstate->traceframe_sal.line);
}
else
{
- init_sal (&traceframe_sal);
- traceframe_fun = NULL;
+ init_sal (&tstate->traceframe_sal);
+ tstate->traceframe_fun = NULL;
set_internalvar_integer (lookup_internalvar ("trace_line"), -1);
}
/* Save func name as "$trace_func", a debugger variable visible to
users. */
- if (traceframe_fun == NULL
- || SYMBOL_LINKAGE_NAME (traceframe_fun) == NULL)
+ if (tstate->traceframe_fun == NULL
+ || SYMBOL_LINKAGE_NAME (tstate->traceframe_fun) == NULL)
clear_internalvar (lookup_internalvar ("trace_func"));
else
set_internalvar_string (lookup_internalvar ("trace_func"),
- SYMBOL_LINKAGE_NAME (traceframe_fun));
+ SYMBOL_LINKAGE_NAME (tstate->traceframe_fun));
/* Save file name as "$trace_file", a debugger variable visible to
users. */
- if (traceframe_sal.symtab == NULL)
+ if (tstate->traceframe_sal.symtab == NULL)
clear_internalvar (lookup_internalvar ("trace_file"));
else
set_internalvar_string (lookup_internalvar ("trace_file"),
- symtab_to_filename_for_display (traceframe_sal.symtab));
+ symtab_to_filename_for_display
+ (tstate->traceframe_sal.symtab));
}
/* Create a new trace state variable with the given name. */
@@ -309,11 +418,12 @@ struct trace_state_variable *
create_trace_state_variable (const char *name)
{
struct trace_state_variable tsv;
+ struct trace_state *tstate = current_trace_state ();
memset (&tsv, 0, sizeof (tsv));
tsv.name = xstrdup (name);
tsv.number = next_tsv_number++;
- return VEC_safe_push (tsv_s, tvariables, &tsv);
+ return VEC_safe_push (tsv_s, tstate->tvariables, &tsv);
}
/* Look for a trace state variable of the given name. */
@@ -323,8 +433,9 @@ find_trace_state_variable (const char *n
{
struct trace_state_variable *tsv;
int ix;
+ struct trace_state *tstate = current_trace_state ();
- for (ix = 0; VEC_iterate (tsv_s, tvariables, ix, tsv); ++ix)
+ for (ix = 0; VEC_iterate (tsv_s, tstate->tvariables, ix, tsv); ++ix)
if (strcmp (name, tsv->name) == 0)
return tsv;
@@ -339,8 +450,9 @@ find_trace_state_variable_by_number (int
{
struct trace_state_variable *tsv;
int ix;
+ struct trace_state *tstate = current_trace_state ();
- for (ix = 0; VEC_iterate (tsv_s, tvariables, ix, tsv); ++ix)
+ for (ix = 0; VEC_iterate (tsv_s, tstate->tvariables, ix, tsv); ++ix)
if (tsv->number == number)
return tsv;
@@ -352,14 +464,15 @@ delete_trace_state_variable (const char
{
struct trace_state_variable *tsv;
int ix;
+ struct trace_state *tstate = current_trace_state ();
- for (ix = 0; VEC_iterate (tsv_s, tvariables, ix, tsv); ++ix)
+ for (ix = 0; VEC_iterate (tsv_s, tstate->tvariables, ix, tsv); ++ix)
if (strcmp (name, tsv->name) == 0)
{
observer_notify_tsv_deleted (tsv);
xfree ((void *)tsv->name);
- VEC_unordered_remove (tsv_s, tvariables, ix);
+ VEC_unordered_remove (tsv_s, tstate->tvariables, ix);
return;
}
@@ -461,11 +574,12 @@ delete_trace_variable_command (char *arg
int ix;
char **argv;
struct cleanup *back_to;
+ struct trace_state *tstate = current_trace_state ();
if (args == NULL)
{
if (query (_("Delete all trace state variables? ")))
- VEC_free (tsv_s, tvariables);
+ VEC_free (tsv_s, tstate->tvariables);
dont_repeat ();
observer_notify_tsv_deleted (NULL);
return;
@@ -495,15 +609,17 @@ tvariables_info_1 (void)
int count = 0;
struct cleanup *back_to;
struct ui_out *uiout = current_uiout;
+ struct trace_state *tstate = current_trace_state ();
- if (VEC_length (tsv_s, tvariables) == 0 && !ui_out_is_mi_like_p (uiout))
+ if (VEC_length (tsv_s, tstate->tvariables) == 0
+ && !ui_out_is_mi_like_p (uiout))
{
printf_filtered (_("No trace state variables.\n"));
return;
}
/* Try to acquire values from the target. */
- for (ix = 0; VEC_iterate (tsv_s, tvariables, ix, tsv); ++ix, ++count)
+ for (ix = 0; VEC_iterate (tsv_s, tstate->tvariables, ix, tsv); ++ix, ++count)
tsv->value_known = target_get_trace_state_variable_value (tsv->number,
&(tsv->value));
@@ -515,7 +631,7 @@ tvariables_info_1 (void)
ui_out_table_body (uiout);
- for (ix = 0; VEC_iterate (tsv_s, tvariables, ix, tsv); ++ix)
+ for (ix = 0; VEC_iterate (tsv_s, tstate->tvariables, ix, tsv); ++ix)
{
struct cleanup *back_to2;
char *c;
@@ -535,7 +651,8 @@ tvariables_info_1 (void)
omit the field completely. The difference between unknown and
undefined does not seem important enough to represent. */
c = NULL;
- else if (current_trace_status ()->running || traceframe_number >= 0)
+ else if (current_trace_status ()->running
+ || tstate->traceframe_number >= 0)
/* The value is/was defined, but we don't have it. */
c = "<unknown>";
else
@@ -566,8 +683,9 @@ save_trace_state_variables (struct ui_fi
{
struct trace_state_variable *tsv;
int ix;
+ struct trace_state *tstate = current_trace_state ();
- for (ix = 0; VEC_iterate (tsv_s, tvariables, ix, tsv); ++ix)
+ for (ix = 0; VEC_iterate (tsv_s, tstate->tvariables, ix, tsv); ++ix)
{
fprintf_unfiltered (fp, "tvariable $%s", tsv->name);
if (tsv->initial_value)
@@ -1787,6 +1905,7 @@ start_tracing (char *notes)
struct trace_state_variable *tsv;
int any_enabled = 0, num_to_download = 0;
int ret;
+ struct trace_state *tstate = current_trace_state ();
tp_vec = all_tracepoints ();
@@ -1876,7 +1995,7 @@ start_tracing (char *notes)
VEC_free (breakpoint_p, tp_vec);
/* Send down all the trace state variables too. */
- for (ix = 0; VEC_iterate (tsv_s, tvariables, ix, tsv); ++ix)
+ for (ix = 0; VEC_iterate (tsv_s, tstate->tvariables, ix, tsv); ++ix)
{
target_download_trace_state_variable (tsv);
}
@@ -1990,7 +2109,8 @@ trace_status_command (char *args, int fr
int status, ix;
VEC(breakpoint_p) *tp_vec = NULL;
struct breakpoint *t;
-
+ struct trace_state *tstate = current_trace_state ();
+
status = target_get_trace_status (ts);
if (status == -1)
@@ -2101,9 +2221,9 @@ trace_status_command (char *args, int fr
printf_filtered (_("Trace notes: %s.\n"), ts->notes);
/* Now report on what we're doing with tfind. */
- if (traceframe_number >= 0)
+ if (tstate->traceframe_number >= 0)
printf_filtered (_("Looking at trace frame %d, tracepoint %d.\n"),
- traceframe_number, tracepoint_number);
+ tstate->traceframe_number, tstate->tracepoint_number);
else
printf_filtered (_("Not looking at any trace frame.\n"));
@@ -2152,6 +2272,7 @@ trace_status_mi (int on_stop)
struct ui_out *uiout = current_uiout;
struct trace_status *ts = current_trace_status ();
int status;
+ struct trace_state *tstate = current_trace_state ();
status = target_get_trace_status (ts);
@@ -2321,6 +2442,7 @@ tfind_1 (enum trace_find_type type, int
struct frame_id old_frame_id = null_frame_id;
struct tracepoint *tp;
struct ui_out *uiout = current_uiout;
+ struct trace_state *tstate = current_trace_state ();
/* Only try to get the current stack frame if we have a chance of
succeeding. In particular, if we're trying to get a first trace
@@ -2329,7 +2451,8 @@ tfind_1 (enum trace_find_type type, int
below (correctly) decide to print out the source location of the
trace frame. */
if (!(type == tfind_number && num == -1)
- && (has_stack_frames () || traceframe_number >= 0))
+ && (has_stack_frames ()
+ || tstate->traceframe_number >= 0))
old_frame_id = get_frame_id (get_current_frame ());
target_frameno = target_trace_find (type, num, addr1, addr2,
@@ -2386,7 +2509,8 @@ tfind_1 (enum trace_find_type type, int
set_tracepoint_num (tp ? tp->base.number : target_tracept);
if (target_frameno != get_traceframe_number ())
- observer_notify_traceframe_changed (target_frameno, tracepoint_number);
+ observer_notify_traceframe_changed (target_frameno,
+ tstate->tracepoint_number);
set_current_traceframe (target_frameno);
@@ -2395,20 +2519,21 @@ tfind_1 (enum trace_find_type type, int
else
set_traceframe_context (get_current_frame ());
- if (traceframe_number >= 0)
+ if (tstate->traceframe_number >= 0)
{
/* Use different branches for MI and CLI to make CLI messages
i18n-eable. */
if (ui_out_is_mi_like_p (uiout))
{
ui_out_field_string (uiout, "found", "1");
- ui_out_field_int (uiout, "tracepoint", tracepoint_number);
- ui_out_field_int (uiout, "traceframe", traceframe_number);
+ ui_out_field_int (uiout, "tracepoint", tstate->tracepoint_number);
+ ui_out_field_int (uiout, "traceframe", tstate->traceframe_number);
}
else
{
printf_unfiltered (_("Found trace frame %d, tracepoint %d\n"),
- traceframe_number, tracepoint_number);
+ tstate->traceframe_number,
+ tstate->tracepoint_number);
}
}
else
@@ -2425,7 +2550,8 @@ tfind_1 (enum trace_find_type type, int
frames, there won't be any current frame to go back to and
display. */
if (from_tty
- && (has_stack_frames () || traceframe_number >= 0))
+ && (has_stack_frames ()
+ || tstate->traceframe_number >= 0))
{
enum print_what print_what;
@@ -2465,6 +2591,7 @@ static void
trace_find_command (char *args, int from_tty)
{ /* This should only be called with a numeric argument. */
int frameno = -1;
+ struct trace_state *tstate = current_trace_state ();
if (current_trace_status ()->running
&& current_trace_status ()->filename == NULL)
@@ -2472,20 +2599,20 @@ trace_find_command (char *args, int from
if (args == 0 || *args == 0)
{ /* TFIND with no args means find NEXT trace frame. */
- if (traceframe_number == -1)
+ if (tstate->traceframe_number == -1)
frameno = 0; /* "next" is first one. */
else
- frameno = traceframe_number + 1;
+ frameno = tstate->traceframe_number + 1;
}
else if (0 == strcmp (args, "-"))
{
- if (traceframe_number == -1)
+ if (tstate->traceframe_number == -1)
error (_("not debugging trace buffer"));
- else if (from_tty && traceframe_number == 0)
+ else if (from_tty && tstate->traceframe_number == 0)
error (_("already at start of trace buffer"));
- frameno = traceframe_number - 1;
- }
+ frameno = tstate->traceframe_number - 1;
+ }
/* A hack to work around eval's need for fp to have been collected. */
else if (0 == strcmp (args, "-1"))
frameno = -1;
@@ -2536,6 +2663,7 @@ trace_find_tracepoint_command (char *arg
{
int tdp;
struct tracepoint *tp;
+ struct trace_state *tstate = current_trace_state ();
if (current_trace_status ()->running
&& current_trace_status ()->filename == NULL)
@@ -2543,10 +2671,10 @@ trace_find_tracepoint_command (char *arg
if (args == 0 || *args == 0)
{
- if (tracepoint_number == -1)
+ if (tstate->tracepoint_number == -1)
error (_("No current tracepoint -- please supply an argument."));
else
- tdp = tracepoint_number; /* Default is current TDP. */
+ tdp = tstate->tracepoint_number; /* default is current TDP */
}
else
tdp = parse_and_eval_long (args);
@@ -2978,15 +3106,16 @@ get_traceframe_location (int *stepping_f
struct tracepoint *t;
struct bp_location *tloc;
struct regcache *regcache;
+ struct trace_state *tstate = current_trace_state ();
- if (tracepoint_number == -1)
+ if (tstate->tracepoint_number == -1)
error (_("No current trace frame."));
- t = get_tracepoint (tracepoint_number);
+ t = get_tracepoint (tstate->tracepoint_number);
if (t == NULL)
error (_("No known tracepoint matches 'current' tracepoint #%d."),
- tracepoint_number);
+ tstate->tracepoint_number);
/* The current frame is a trap frame if the frame PC is equal to the
tracepoint PC. If not, then the current frame was collected
@@ -3054,12 +3183,13 @@ trace_dump_command (char *args, int from
struct bp_location *loc;
struct cleanup *old_chain;
struct command_line *actions;
+ struct trace_state *tstate = current_trace_state ();
/* This throws an error is not inspecting a trace frame. */
loc = get_traceframe_location (&stepping_frame);
printf_filtered ("Data collected at tracepoint %d, trace frame %d:\n",
- tracepoint_number, traceframe_number);
+ tstate->tracepoint_number, tstate->traceframe_number);
old_chain = make_cleanup (null_cleanup, NULL);
@@ -3841,13 +3971,13 @@ mem2hex (gdb_byte *mem, char *buf, int c
int
get_traceframe_number (void)
{
- return traceframe_number;
+ return current_trace_state ()->traceframe_number;
}
int
get_tracepoint_number (void)
{
- return tracepoint_number;
+ return current_trace_state ()->tracepoint_number;
}
/* Make the traceframe NUM be the current trace frame. Does nothing
@@ -3857,8 +3987,9 @@ void
set_current_traceframe (int num)
{
int newnum;
+ struct trace_state *tstate = current_trace_state ();
- if (traceframe_number == num)
+ if (tstate->traceframe_number == num)
{
/* Nothing to do. */
return;
@@ -3884,7 +4015,9 @@ set_current_traceframe (int num)
void
set_traceframe_number (int num)
{
- traceframe_number = num;
+ struct trace_state *tstate = current_trace_state ();
+
+ tstate->traceframe_number = num;
}
/* A cleanup used when switching away and back from tfind mode. */
@@ -3915,9 +4048,10 @@ struct cleanup *
make_cleanup_restore_current_traceframe (void)
{
struct current_traceframe_cleanup *old;
+ struct trace_state *tstate = current_trace_state ();
old = xmalloc (sizeof (struct current_traceframe_cleanup));
- old->traceframe_number = traceframe_number;
+ old->traceframe_number = tstate->traceframe_number;
return make_cleanup_dtor (do_restore_current_traceframe_cleanup, old,
restore_current_traceframe_cleanup_dtor);
@@ -3926,7 +4060,9 @@ make_cleanup_restore_current_traceframe
struct cleanup *
make_cleanup_restore_traceframe_number (void)
{
- return make_cleanup_restore_integer (&traceframe_number);
+ struct trace_state *tstate = current_trace_state ();
+
+ return make_cleanup_restore_integer (&tstate->traceframe_number);
}
/* Given a number and address, return an uploaded tracepoint with that
@@ -4143,6 +4279,7 @@ create_tsv_from_upload (struct uploaded_
int try_num = 0;
struct trace_state_variable *tsv;
struct cleanup *old_chain;
+ struct trace_state *tstate = current_trace_state ();
if (utsv->name)
{
@@ -4187,10 +4324,11 @@ merge_uploaded_trace_state_variables (st
struct uploaded_tsv *utsv;
struct trace_state_variable *tsv;
int highest;
+ struct trace_state *tstate = current_trace_state ();
/* Most likely some numbers will have to be reassigned as part of
the merge, so clear them all in anticipation. */
- for (ix = 0; VEC_iterate (tsv_s, tvariables, ix, tsv); ++ix)
+ for (ix = 0; VEC_iterate (tsv_s, tstate->tvariables, ix, tsv); ++ix)
tsv->number = 0;
for (utsv = *uploaded_tsvs; utsv; utsv = utsv->next)
@@ -4218,12 +4356,12 @@ merge_uploaded_trace_state_variables (st
/* Renumber everything that didn't get a target-assigned number. */
highest = 0;
- for (ix = 0; VEC_iterate (tsv_s, tvariables, ix, tsv); ++ix)
+ for (ix = 0; VEC_iterate (tsv_s, tstate->tvariables, ix, tsv); ++ix)
if (tsv->number > highest)
highest = tsv->number;
++highest;
- for (ix = 0; VEC_iterate (tsv_s, tvariables, ix, tsv); ++ix)
+ for (ix = 0; VEC_iterate (tsv_s, tstate->tvariables, ix, tsv); ++ix)
if (tsv->number == 0)
tsv->number = highest++;
@@ -4871,7 +5009,7 @@ tfile_trace_find (enum trace_find_type t
else
{
/* Start from the _next_ trace frame. */
- if (tfnum > traceframe_number)
+ if (tfnum > current_trace_state ()->traceframe_number)
{
switch (type)
{
@@ -5016,6 +5154,7 @@ tfile_fetch_registers (struct target_ops
struct gdbarch *gdbarch = get_regcache_arch (regcache);
int offset, regn, regsize, pc_regno;
gdb_byte *regs;
+ struct trace_state *tstate = current_trace_state ();
/* An uninitialized reg size says we're not going to be
successful at getting register blocks. */
@@ -5064,7 +5203,7 @@ tfile_fetch_registers (struct target_ops
pc_regno = gdbarch_pc_regnum (gdbarch);
if (pc_regno >= 0 && (regno == -1 || regno == pc_regno))
{
- struct tracepoint *tp = get_tracepoint (tracepoint_number);
+ struct tracepoint *tp = get_tracepoint (tstate->tracepoint_number);
if (tp && tp->base.loc)
{
@@ -5105,7 +5244,7 @@ tfile_xfer_partial (struct target_ops *o
if (readbuf == NULL)
error (_("tfile_xfer_partial: trace file is read-only"));
- if (traceframe_number != -1)
+ if (get_traceframe_number () != -1)
{
int pos = 0;
@@ -5233,13 +5372,13 @@ tfile_has_memory (struct target_ops *ops
static int
tfile_has_stack (struct target_ops *ops)
{
- return traceframe_number != -1;
+ return get_traceframe_number () != -1;
}
static int
tfile_has_registers (struct target_ops *ops)
{
- return traceframe_number != -1;
+ return get_traceframe_number () != -1;
}
/* Callback for traceframe_walk_blocks. Builds a traceframe_info
@@ -5726,10 +5865,12 @@ parse_traceframe_info (const char *tfram
struct traceframe_info *
get_traceframe_info (void)
{
- if (traceframe_info == NULL)
- traceframe_info = target_traceframe_info ();
+ struct trace_state *tstate = current_trace_state ();
- return traceframe_info;
+ if (tstate->traceframe_info == NULL)
+ tstate->traceframe_info = target_traceframe_info ();
+
+ return tstate->traceframe_info;
}
/* If the target supports the query, return in RESULT the set of
@@ -5785,20 +5926,179 @@ static const struct internalvar_funcs sd
NULL
};
+/* Get TSV $name's value from target and put it to valp.
+ Return true if success. */
+
+static int
+get_trace_state_variable_value (const char *name, LONGEST *valp)
+{
+ struct trace_state_variable *tsv;
+
+ tsv = find_trace_state_variable ("pid");
+ if (tsv)
+ {
+ tsv->value_known = target_get_trace_state_variable_value (tsv->number,
+ &(tsv->value));
+ if (tsv->value_known)
+ {
+ *valp = tsv->value;
+ return 1;
+ }
+ }
+ return 0;
+}
+
+/* When traceframe changed, select the inferior and thread of this
+ traceframe. */
+
+static void
+traceframe_changed_inferior_thread_select (int tfnum, int tpnum)
+{
+ /* This is for the inferior. */
+ struct inferior *inf;
+ int inf_need_select = 0;
+ /* This is for the thread. */
+ ptid_t ptid;
+ int ptid_need_select = 0;
+ volatile struct gdb_exception e;
+ struct tracepoint *tp;
+ LONGEST val;
+
+ if (tfnum < 0 || tpnum < 0)
+ return;
+
+ /* Maybe got inferior and thread id from $pid and $tid. So didn't
+ check if tp is NULL. */
+ tp = get_tracepoint_by_number_on_target (tpnum);
+
+ /* If this traceframe has $pid, try to find a inf for it. */
+ if (get_trace_state_variable_value ("pid", &val))
+ {
+ int pid = (int) val;
+
+ if (current_inferior ()->pid != pid)
+ {
+ ALL_INFERIORS (inf)
+ {
+ if (inf->pid == pid)
+ {
+ inf_need_select = 1;
+ break;
+ }
+ }
+ }
+ }
+
+ /* If doesn't get inf from $pid and find the tp, try to find inf from
+ tp if need.
+ Just the target that supports multiprocess tracepoint together need
+ select inferior because other target's traceframe is just for current
+ inferior.
+ If the tracepoint's program space is different with current inferior's,
+ select inferior of the tracepoint.*/
+ if (inf_need_select == 0 && tp != NULL
+ && target_supports_multi_process_tracepoint_together ()
+ && current_inferior ()->pspace != tp->base.loc->pspace)
+ {
+ ALL_INFERIORS (inf)
+ {
+ if (inf->pspace == tp->base.loc->pspace)
+ {
+ inf_need_select = 1;
+ break;
+ }
+ }
+ }
+
+ /* If this traceframe has $lwp or $tid, set it to ptid. */
+ if (inf_need_select)
+ ptid = ptid_build (inf->pid, 0, 0);
+ else
+ ptid = ptid_build (ptid_get_pid (inferior_ptid), 0, 0);
+ if (get_trace_state_variable_value ("lwp", &val))
+ {
+ ptid = ptid_build (ptid_get_pid (ptid), (long) val, 0);
+ ptid_need_select = 1;
+ }
+ if (get_trace_state_variable_value ("tid", &val))
+ {
+ ptid = ptid_build (ptid_get_pid (ptid), ptid_get_lwp (ptid),
+ (long) val);
+ ptid_need_select = 1;
+ }
+ /* If ptid_need_select is true, then the traceframe has $lwp or $tid,
+ Check if ptid is not current thread. If so, ptid need to be
+ set as current thread. */
+ if (ptid_need_select && !ptid_equal (ptid, inferior_ptid))
+ ptid_need_select = 1;
+
+ /* If doesn't get a ptid from $lwp and $tid, and tp is not NULL, try
+ to find it from tp->base.thread. */
+ if (ptid_need_select == 0 && tp != NULL
+ && tp->base.thread != -1
+ && target_supports_multi_thread_tracepoint ())
+ {
+ ptid = thread_id_to_pid (tp->base.thread);
+ if (!in_thread_list (ptid))
+ {
+ warning (_("Cannot find thread %d for tracepoint %d"),
+ tp->base.thread, tp->base.number);
+ return;
+ }
+
+ if (!ptid_equal (ptid, inferior_ptid))
+ ptid_need_select = 1;
+ }
+
+ /* Use this TRY_CATCH to let traceframe_changed function will not be
+ interrupted by a error. */
+ TRY_CATCH (e, RETURN_MASK_ERROR)
+ {
+ if (inf_need_select)
+ {
+ set_inferior (inf);
+ printf_filtered (_("[Switching to inferior %d (%s)]\n"),
+ inf->num,
+ target_pid_to_str (pid_to_ptid (inf->pid)));
+ }
+ if (ptid_need_select)
+ {
+ switch_to_thread (ptid);
+ printf_filtered (_("[Switching to thread %d (%s)]\n"),
+ tp->base.thread,
+ target_pid_to_str (inferior_ptid));
+ }
+ }
+ if (e.reason < 0)
+ {
+ warning ("%s", e.message);
+ return;
+ }
+}
+
/* module initialization */
void
_initialize_tracepoint (void)
{
struct cmd_list_element *c;
+ memset (&together_trace_state, 0, sizeof (together_trace_state));
+ together_trace_state.traceframe_number = -1;
+ together_trace_state.tracepoint_number = -1;
+
+ observer_attach_traceframe_changed
+ (traceframe_changed_inferior_thread_select);
+
/* Explicitly create without lookup, since that tries to create a
value with a void typed value, and when we get here, gdbarch
isn't initialized yet. At this point, we're quite sure there
isn't another convenience variable of the same name. */
create_internalvar_type_lazy ("_sdata", &sdata_funcs, NULL);
- traceframe_number = -1;
- tracepoint_number = -1;
+ observer_attach_inferior_exit (trace_inferior_exit);
+
+ trace_inferior_data
+ = register_inferior_data_with_cleanup (NULL, trace_inferior_data_cleanup);
add_info ("scope", scope_info,
_("List the variables local to a scope"));