* target.c (target_read_live_memory): New function.
(memory_xfer_live_readonly_partial): New.
(memory_xfer_partial): If reading from a traceframe, fallback to
reading unavailable read-only memory from read-only regions of
live target memory.
* tracepoint.c (disconnect_tracing): Adjust.
(set_current_traceframe): New, factored out from
set_traceframe_number.
(set_traceframe_number): Reimplement to only change the traceframe
number on the GDB side.
(do_restore_current_traceframe_cleanup): Adjust.
(make_cleanup_restore_traceframe_number): New.
(cur_traceframe_number): New global.
(tfile_open): Set cur_traceframe_number to no traceframe.
(set_tfile_traceframe): New function.
(tfile_trace_find): If looking up a traceframe using any method
other than by number, make sure the current tfile traceframe
matches gdb's current traceframe. Update the current tfile
traceframe if the lookup succeeded.
(tfile_fetch_registers, tfile_xfer_partial)
(tfile_get_trace_state_variable_value): Make sure the remote
traceframe matches gdb's current traceframe.
* remote.c (remote_traceframe_number): New global.
(remote_open_1): Set it to -1.
(set_remote_traceframe): New function.
(remote_fetch_registers, remote_store_registers)
(remote_xfer_memory, remote_xfer_partial)
(remote_get_trace_state_variable_value): Make sure the remote
traceframe matches gdb's current traceframe.
(remote_trace_find): If looking up a traceframe using any method
other than by number, make sure the current remote traceframe
matches gdb's current traceframe. Update the current remote
traceframe if the lookup succeeded.
* infrun.c (fetch_inferior_event): Adjust.
* tracepoint.h (set_current_traceframe): Declare.
(get_traceframe_number, set_traceframe_number): Add describing
comments.
+2011-02-14 Pedro Alves <pedro@codesourcery.com>
+
+ * target.c (target_read_live_memory): New function.
+ (memory_xfer_live_readonly_partial): New.
+ (memory_xfer_partial): If reading from a traceframe, fallback to
+ reading unavailable read-only memory from read-only regions of
+ live target memory.
+ * tracepoint.c (disconnect_tracing): Adjust.
+ (set_current_traceframe): New, factored out from
+ set_traceframe_number.
+ (set_traceframe_number): Reimplement to only change the traceframe
+ number on the GDB side.
+ (do_restore_current_traceframe_cleanup): Adjust.
+ (make_cleanup_restore_traceframe_number): New.
+ (cur_traceframe_number): New global.
+ (tfile_open): Set cur_traceframe_number to no traceframe.
+ (set_tfile_traceframe): New function.
+ (tfile_trace_find): If looking up a traceframe using any method
+ other than by number, make sure the current tfile traceframe
+ matches gdb's current traceframe. Update the current tfile
+ traceframe if the lookup succeeded.
+ (tfile_fetch_registers, tfile_xfer_partial)
+ (tfile_get_trace_state_variable_value): Make sure the remote
+ traceframe matches gdb's current traceframe.
+ * remote.c (remote_traceframe_number): New global.
+ (remote_open_1): Set it to -1.
+ (set_remote_traceframe): New function.
+ (remote_fetch_registers, remote_store_registers)
+ (remote_xfer_memory, remote_xfer_partial)
+ (remote_get_trace_state_variable_value): Make sure the remote
+ traceframe matches gdb's current traceframe.
+ (remote_trace_find): If looking up a traceframe using any method
+ other than by number, make sure the current remote traceframe
+ matches gdb's current traceframe. Update the current remote
+ traceframe if the lookup succeeded.
+ * infrun.c (fetch_inferior_event): Adjust.
+ * tracepoint.h (set_current_traceframe): Declare.
+ (get_traceframe_number, set_traceframe_number): Add describing
+ comments.
+
2011-02-14 Pedro Alves <pedro@codesourcery.com>
Mark pieces of values as unavailable if the corresponding memory
if (non_stop)
{
make_cleanup_restore_current_traceframe ();
- set_traceframe_number (-1);
+ set_current_traceframe (-1);
}
if (non_stop)
static ptid_t general_thread;
static ptid_t continue_thread;
+/* This the traceframe which we last selected on the remote system.
+ It will be -1 if no traceframe is selected. */
+static int remote_traceframe_number = -1;
+
/* Find out if the stub attached to PID (and hence GDB should offer to
detach instead of killing it when bailing out). */
general_thread = not_sent_ptid;
continue_thread = not_sent_ptid;
+ remote_traceframe_number = -1;
/* Probe for ability to use "ThreadInfo" query, as required. */
use_threadinfo_query = 1;
process_g_packet (regcache);
}
+/* Make the remote selected traceframe match GDB's selected
+ traceframe. */
+
+static void
+set_remote_traceframe (void)
+{
+ int newnum;
+
+ if (remote_traceframe_number == get_traceframe_number ())
+ return;
+
+ /* Avoid recursion, remote_trace_find calls us again. */
+ remote_traceframe_number = get_traceframe_number ();
+
+ newnum = target_trace_find (tfind_number,
+ get_traceframe_number (), 0, 0, NULL);
+
+ /* Should not happen. If it does, all bets are off. */
+ if (newnum != get_traceframe_number ())
+ warning (_("could not set remote traceframe"));
+}
+
static void
remote_fetch_registers (struct target_ops *ops,
struct regcache *regcache, int regnum)
struct remote_arch_state *rsa = get_remote_arch_state ();
int i;
+ set_remote_traceframe ();
set_general_thread (inferior_ptid);
if (regnum >= 0)
struct remote_arch_state *rsa = get_remote_arch_state ();
int i;
+ set_remote_traceframe ();
set_general_thread (inferior_ptid);
if (regnum >= 0)
{
int res;
+ set_remote_traceframe ();
set_general_thread (inferior_ptid);
if (should_write)
char *p2;
char query_type;
+ set_remote_traceframe ();
set_general_thread (inferior_ptid);
rs = get_remote_state ();
char *p, *reply;
int target_frameno = -1, target_tracept = -1;
+ /* Lookups other than by absolute frame number depend on the current
+ trace selected, so make sure it is correct on the remote end
+ first. */
+ if (type != tfind_number)
+ set_remote_traceframe ();
+
p = rs->buf;
strcpy (p, "QTFrame:");
p = strchr (p, '\0');
target_frameno = (int) strtol (p, &reply, 16);
if (reply == p)
error (_("Unable to parse trace frame number"));
+ /* Don't update our remote traceframe number cache on failure
+ to select a remote traceframe. */
if (target_frameno == -1)
return -1;
break;
}
if (tpp)
*tpp = target_tracept;
+
+ remote_traceframe_number = target_frameno;
return target_frameno;
}
char *reply;
ULONGEST uval;
+ set_remote_traceframe ();
+
sprintf (rs->buf, "qTV:%x", tsvnum);
putpkt (rs->buf);
reply = remote_get_noisy_reply (&target_buf, &target_buf_size);
return NULL;
}
+/* Read memory from the live target, even if currently inspecting a
+ traceframe. The return is the same as that of target_read. */
+
+static LONGEST
+target_read_live_memory (enum target_object object,
+ ULONGEST memaddr, gdb_byte *myaddr, LONGEST len)
+{
+ int ret;
+ struct cleanup *cleanup;
+
+ /* Switch momentarily out of tfind mode so to access live memory.
+ Note that this must not clear global state, such as the frame
+ cache, which must still remain valid for the previous traceframe.
+ We may be _building_ the frame cache at this point. */
+ cleanup = make_cleanup_restore_traceframe_number ();
+ set_traceframe_number (-1);
+
+ ret = target_read (current_target.beneath, object, NULL,
+ myaddr, memaddr, len);
+
+ do_cleanups (cleanup);
+ return ret;
+}
+
+/* Using the set of read-only target sections of OPS, read live
+ read-only memory. Note that the actual reads start from the
+ top-most target again. */
+
+static LONGEST
+memory_xfer_live_readonly_partial (struct target_ops *ops,
+ enum target_object object,
+ gdb_byte *readbuf, ULONGEST memaddr,
+ LONGEST len)
+{
+ struct target_section *secp;
+ struct target_section_table *table;
+
+ secp = target_section_by_addr (ops, memaddr);
+ if (secp != NULL
+ && (bfd_get_section_flags (secp->bfd, secp->the_bfd_section)
+ & SEC_READONLY))
+ {
+ struct target_section *p;
+ ULONGEST memend = memaddr + len;
+
+ table = target_get_section_table (ops);
+
+ for (p = table->sections; p < table->sections_end; p++)
+ {
+ if (memaddr >= p->addr)
+ {
+ if (memend <= p->endaddr)
+ {
+ /* Entire transfer is within this section. */
+ return target_read_live_memory (object, memaddr,
+ readbuf, len);
+ }
+ else if (memaddr >= p->endaddr)
+ {
+ /* This section ends before the transfer starts. */
+ continue;
+ }
+ else
+ {
+ /* This section overlaps the transfer. Just do half. */
+ len = p->endaddr - memaddr;
+ return target_read_live_memory (object, memaddr,
+ readbuf, len);
+ }
+ }
+ }
+ }
+
+ return 0;
+}
+
/* Perform a partial memory transfer.
For docs see target.h, to_xfer_partial. */
}
}
+ /* If reading unavailable memory in the context of traceframes, and
+ this address falls within a read-only section, fallback to
+ reading from live memory. */
+ if (readbuf != NULL && get_traceframe_number () != -1)
+ {
+ VEC(mem_range_s) *available;
+
+ /* If we fail to get the set of available memory, then the
+ target does not support querying traceframe info, and so we
+ attempt reading from the traceframe anyway (assuming the
+ target implements the old QTro packet then). */
+ if (traceframe_available_memory (&available, memaddr, len))
+ {
+ struct cleanup *old_chain;
+
+ old_chain = make_cleanup (VEC_cleanup(mem_range_s), &available);
+
+ if (VEC_empty (mem_range_s, available)
+ || VEC_index (mem_range_s, available, 0)->start != memaddr)
+ {
+ /* Don't read into the traceframe's available
+ memory. */
+ if (!VEC_empty (mem_range_s, available))
+ {
+ LONGEST oldlen = len;
+
+ len = VEC_index (mem_range_s, available, 0)->start - memaddr;
+ gdb_assert (len <= oldlen);
+ }
+
+ do_cleanups (old_chain);
+
+ /* This goes through the topmost target again. */
+ res = memory_xfer_live_readonly_partial (ops, object,
+ readbuf, memaddr, len);
+ if (res > 0)
+ return res;
+
+ /* No use trying further, we know some memory starting
+ at MEMADDR isn't available. */
+ return -1;
+ }
+
+ /* Don't try to read more than how much is available, in
+ case the target implements the deprecated QTro packet to
+ cater for older GDBs (the target's knowledge of read-only
+ sections may be outdated by now). */
+ len = VEC_index (mem_range_s, available, 0)->length;
+
+ do_cleanups (old_chain);
+ }
+ }
+
/* Try GDB's internal data cache. */
region = lookup_mem_region (memaddr);
/* region->hi == 0 means there's no upper bound. */
confusing upon reconnection. Just use these calls instead of
full tfind_1 behavior because we're in the middle of detaching,
and there's no point to updating current stack frame etc. */
- set_traceframe_number (-1);
+ set_current_traceframe (-1);
set_traceframe_context (NULL);
}
if NUM is already current. */
void
-set_traceframe_number (int num)
+set_current_traceframe (int num)
{
int newnum;
clear_traceframe_info ();
}
+/* Make the traceframe NUM be the current trace frame, and do nothing
+ more. */
+
+void
+set_traceframe_number (int num)
+{
+ traceframe_number = num;
+}
+
/* A cleanup used when switching away and back from tfind mode. */
struct current_traceframe_cleanup
{
struct current_traceframe_cleanup *old = arg;
- set_traceframe_number (old->traceframe_number);
+ set_current_traceframe (old->traceframe_number);
}
static void
restore_current_traceframe_cleanup_dtor);
}
+struct cleanup *
+make_cleanup_restore_traceframe_number (void)
+{
+ return make_cleanup_restore_integer (&traceframe_number);
+}
+
/* Given a number and address, return an uploaded tracepoint with that
number, creating if necessary. */
int trace_fd = -1;
off_t trace_frames_offset;
off_t cur_offset;
+int cur_traceframe_number;
int cur_data_size;
int trace_regblock_size;
ts->disconnected_tracing = 0;
ts->circular_buffer = 0;
+ cur_traceframe_number = -1;
+
/* Read through a section of newline-terminated lines that
define things like tracepoints. */
i = 0;
return addr;
}
+/* Make tfile's selected traceframe match GDB's selected
+ traceframe. */
+
+static void
+set_tfile_traceframe (void)
+{
+ int newnum;
+
+ if (cur_traceframe_number == get_traceframe_number ())
+ return;
+
+ /* Avoid recursion, tfile_trace_find calls us again. */
+ cur_traceframe_number = get_traceframe_number ();
+
+ newnum = target_trace_find (tfind_number,
+ get_traceframe_number (), 0, 0, NULL);
+
+ /* Should not happen. If it does, all bets are off. */
+ if (newnum != get_traceframe_number ())
+ warning (_("could not set tfile's traceframe"));
+}
+
/* Given a type of search and some parameters, scan the collection of
traceframes in the file looking for a match. When found, return
both the traceframe and tracepoint number, otherwise -1 for
off_t offset, tframe_offset;
ULONGEST tfaddr;
+ /* Lookups other than by absolute frame number depend on the current
+ trace selected, so make sure it is correct on the tfile end
+ first. */
+ if (type != tfind_number)
+ set_tfile_traceframe ();
+
lseek (trace_fd, trace_frames_offset, SEEK_SET);
offset = trace_frames_offset;
while (1)
*tpp = tpnum;
cur_offset = offset;
cur_data_size = data_size;
+ cur_traceframe_number = tfnum;
return tfnum;
}
/* Skip past the traceframe's data. */
if (!trace_regblock_size)
return;
+ set_tfile_traceframe ();
+
regs = alloca (trace_regblock_size);
if (traceframe_find_block_type ('R', 0) >= 0)
if (readbuf == NULL)
error (_("tfile_xfer_partial: trace file is read-only"));
- if (traceframe_number != -1)
+ set_tfile_traceframe ();
+
+ if (traceframe_number != -1)
{
int pos = 0;
{
int pos;
+ set_tfile_traceframe ();
+
pos = 0;
while ((pos = traceframe_find_block_type ('V', pos)) >= 0)
{
extern void (*deprecated_trace_find_hook) (char *arg, int from_tty);
extern void (*deprecated_trace_start_stop_hook) (int start, int from_tty);
-int get_traceframe_number (void);
-void set_traceframe_number (int);
+/* Returns the current traceframe number. */
+extern int get_traceframe_number (void);
+
+/* Make the traceframe NUM be the current GDB trace frame number, and
+ do nothing more. In particular, this does not flush the
+ register/frame caches or notify the target about the trace frame
+ change, so that is can be used when we need to momentarily access
+ live memory. Targets lazily switch their current traceframe to
+ match GDB's traceframe number, at the appropriate times. */
+extern void set_traceframe_number (int);
+
+/* Make the traceframe NUM be the current trace frame, all the way to
+ the target, and flushes all global state (register/frame caches,
+ etc.). */
+extern void set_current_traceframe (int num);
+
struct cleanup *make_cleanup_restore_current_traceframe (void);
+struct cleanup *make_cleanup_restore_traceframe_number (void);
void free_actions (struct breakpoint *);
extern void validate_actionline (char **, struct breakpoint *);