* 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.
This commit is contained in:
Pedro Alves
2011-02-14 11:22:29 +00:00
parent e6ca34fcfb
commit e6e4e7014d
6 changed files with 287 additions and 7 deletions

View File

@ -1,3 +1,43 @@
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> 2011-02-14 Pedro Alves <pedro@codesourcery.com>
Mark pieces of values as unavailable if the corresponding memory Mark pieces of values as unavailable if the corresponding memory

View File

@ -2631,7 +2631,7 @@ fetch_inferior_event (void *client_data)
if (non_stop) if (non_stop)
{ {
make_cleanup_restore_current_traceframe (); make_cleanup_restore_current_traceframe ();
set_traceframe_number (-1); set_current_traceframe (-1);
} }
if (non_stop) if (non_stop)

View File

@ -1353,6 +1353,10 @@ static ptid_t any_thread_ptid;
static ptid_t general_thread; static ptid_t general_thread;
static ptid_t continue_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 /* Find out if the stub attached to PID (and hence GDB should offer to
detach instead of killing it when bailing out). */ detach instead of killing it when bailing out). */
@ -4002,6 +4006,7 @@ remote_open_1 (char *name, int from_tty,
general_thread = not_sent_ptid; general_thread = not_sent_ptid;
continue_thread = not_sent_ptid; continue_thread = not_sent_ptid;
remote_traceframe_number = -1;
/* Probe for ability to use "ThreadInfo" query, as required. */ /* Probe for ability to use "ThreadInfo" query, as required. */
use_threadinfo_query = 1; use_threadinfo_query = 1;
@ -5770,6 +5775,28 @@ fetch_registers_using_g (struct regcache *regcache)
process_g_packet (regcache); 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 static void
remote_fetch_registers (struct target_ops *ops, remote_fetch_registers (struct target_ops *ops,
struct regcache *regcache, int regnum) struct regcache *regcache, int regnum)
@ -5777,6 +5804,7 @@ remote_fetch_registers (struct target_ops *ops,
struct remote_arch_state *rsa = get_remote_arch_state (); struct remote_arch_state *rsa = get_remote_arch_state ();
int i; int i;
set_remote_traceframe ();
set_general_thread (inferior_ptid); set_general_thread (inferior_ptid);
if (regnum >= 0) if (regnum >= 0)
@ -5934,6 +5962,7 @@ remote_store_registers (struct target_ops *ops,
struct remote_arch_state *rsa = get_remote_arch_state (); struct remote_arch_state *rsa = get_remote_arch_state ();
int i; int i;
set_remote_traceframe ();
set_general_thread (inferior_ptid); set_general_thread (inferior_ptid);
if (regnum >= 0) if (regnum >= 0)
@ -6502,6 +6531,7 @@ remote_xfer_memory (CORE_ADDR mem_addr, gdb_byte *buffer, int mem_len,
{ {
int res; int res;
set_remote_traceframe ();
set_general_thread (inferior_ptid); set_general_thread (inferior_ptid);
if (should_write) if (should_write)
@ -8084,6 +8114,7 @@ remote_xfer_partial (struct target_ops *ops, enum target_object object,
char *p2; char *p2;
char query_type; char query_type;
set_remote_traceframe ();
set_general_thread (inferior_ptid); set_general_thread (inferior_ptid);
rs = get_remote_state (); rs = get_remote_state ();
@ -9972,6 +10003,12 @@ remote_trace_find (enum trace_find_type type, int num,
char *p, *reply; char *p, *reply;
int target_frameno = -1, target_tracept = -1; 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; p = rs->buf;
strcpy (p, "QTFrame:"); strcpy (p, "QTFrame:");
p = strchr (p, '\0'); p = strchr (p, '\0');
@ -10009,6 +10046,8 @@ remote_trace_find (enum trace_find_type type, int num,
target_frameno = (int) strtol (p, &reply, 16); target_frameno = (int) strtol (p, &reply, 16);
if (reply == p) if (reply == p)
error (_("Unable to parse trace frame number")); 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) if (target_frameno == -1)
return -1; return -1;
break; break;
@ -10029,6 +10068,8 @@ remote_trace_find (enum trace_find_type type, int num,
} }
if (tpp) if (tpp)
*tpp = target_tracept; *tpp = target_tracept;
remote_traceframe_number = target_frameno;
return target_frameno; return target_frameno;
} }
@ -10039,6 +10080,8 @@ remote_get_trace_state_variable_value (int tsvnum, LONGEST *val)
char *reply; char *reply;
ULONGEST uval; ULONGEST uval;
set_remote_traceframe ();
sprintf (rs->buf, "qTV:%x", tsvnum); sprintf (rs->buf, "qTV:%x", tsvnum);
putpkt (rs->buf); putpkt (rs->buf);
reply = remote_get_noisy_reply (&target_buf, &target_buf_size); reply = remote_get_noisy_reply (&target_buf, &target_buf_size);

View File

@ -1271,6 +1271,82 @@ target_section_by_addr (struct target_ops *target, CORE_ADDR addr)
return NULL; 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. /* Perform a partial memory transfer.
For docs see target.h, to_xfer_partial. */ For docs see target.h, to_xfer_partial. */
@ -1329,6 +1405,59 @@ memory_xfer_partial (struct target_ops *ops, enum target_object object,
} }
} }
/* 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. */ /* Try GDB's internal data cache. */
region = lookup_mem_region (memaddr); region = lookup_mem_region (memaddr);
/* region->hi == 0 means there's no upper bound. */ /* region->hi == 0 means there's no upper bound. */

View File

@ -1927,7 +1927,7 @@ disconnect_tracing (int from_tty)
confusing upon reconnection. Just use these calls instead of confusing upon reconnection. Just use these calls instead of
full tfind_1 behavior because we're in the middle of detaching, full tfind_1 behavior because we're in the middle of detaching,
and there's no point to updating current stack frame etc. */ and there's no point to updating current stack frame etc. */
set_traceframe_number (-1); set_current_traceframe (-1);
set_traceframe_context (NULL); set_traceframe_context (NULL);
} }
@ -2935,7 +2935,7 @@ get_traceframe_number (void)
if NUM is already current. */ if NUM is already current. */
void void
set_traceframe_number (int num) set_current_traceframe (int num)
{ {
int newnum; int newnum;
@ -2959,6 +2959,15 @@ set_traceframe_number (int num)
clear_traceframe_info (); 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. */ /* A cleanup used when switching away and back from tfind mode. */
struct current_traceframe_cleanup struct current_traceframe_cleanup
@ -2972,7 +2981,7 @@ do_restore_current_traceframe_cleanup (void *arg)
{ {
struct current_traceframe_cleanup *old = arg; struct current_traceframe_cleanup *old = arg;
set_traceframe_number (old->traceframe_number); set_current_traceframe (old->traceframe_number);
} }
static void static void
@ -2995,6 +3004,12 @@ make_cleanup_restore_current_traceframe (void)
restore_current_traceframe_cleanup_dtor); 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 /* Given a number and address, return an uploaded tracepoint with that
number, creating if necessary. */ number, creating if necessary. */
@ -3247,6 +3262,7 @@ char *trace_filename;
int trace_fd = -1; int trace_fd = -1;
off_t trace_frames_offset; off_t trace_frames_offset;
off_t cur_offset; off_t cur_offset;
int cur_traceframe_number;
int cur_data_size; int cur_data_size;
int trace_regblock_size; int trace_regblock_size;
@ -3338,6 +3354,8 @@ tfile_open (char *filename, int from_tty)
ts->disconnected_tracing = 0; ts->disconnected_tracing = 0;
ts->circular_buffer = 0; ts->circular_buffer = 0;
cur_traceframe_number = -1;
/* Read through a section of newline-terminated lines that /* Read through a section of newline-terminated lines that
define things like tracepoints. */ define things like tracepoints. */
i = 0; i = 0;
@ -3752,6 +3770,28 @@ tfile_get_traceframe_address (off_t tframe_offset)
return addr; 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 /* Given a type of search and some parameters, scan the collection of
traceframes in the file looking for a match. When found, return traceframes in the file looking for a match. When found, return
both the traceframe and tracepoint number, otherwise -1 for both the traceframe and tracepoint number, otherwise -1 for
@ -3768,6 +3808,12 @@ tfile_trace_find (enum trace_find_type type, int num,
off_t offset, tframe_offset; off_t offset, tframe_offset;
ULONGEST tfaddr; 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); lseek (trace_fd, trace_frames_offset, SEEK_SET);
offset = trace_frames_offset; offset = trace_frames_offset;
while (1) while (1)
@ -3820,6 +3866,7 @@ tfile_trace_find (enum trace_find_type type, int num,
*tpp = tpnum; *tpp = tpnum;
cur_offset = offset; cur_offset = offset;
cur_data_size = data_size; cur_data_size = data_size;
cur_traceframe_number = tfnum;
return tfnum; return tfnum;
} }
/* Skip past the traceframe's data. */ /* Skip past the traceframe's data. */
@ -3936,6 +3983,8 @@ tfile_fetch_registers (struct target_ops *ops,
if (!trace_regblock_size) if (!trace_regblock_size)
return; return;
set_tfile_traceframe ();
regs = alloca (trace_regblock_size); regs = alloca (trace_regblock_size);
if (traceframe_find_block_type ('R', 0) >= 0) if (traceframe_find_block_type ('R', 0) >= 0)
@ -4019,7 +4068,9 @@ tfile_xfer_partial (struct target_ops *ops, enum target_object object,
if (readbuf == NULL) if (readbuf == NULL)
error (_("tfile_xfer_partial: trace file is read-only")); 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 = 0;
@ -4102,6 +4153,8 @@ tfile_get_trace_state_variable_value (int tsvnum, LONGEST *val)
{ {
int pos; int pos;
set_tfile_traceframe ();
pos = 0; pos = 0;
while ((pos = traceframe_find_block_type ('V', pos)) >= 0) while ((pos = traceframe_find_block_type ('V', pos)) >= 0)
{ {

View File

@ -192,9 +192,24 @@ extern void release_static_tracepoint_marker (struct static_tracepoint_marker *)
extern void (*deprecated_trace_find_hook) (char *arg, int from_tty); extern void (*deprecated_trace_find_hook) (char *arg, int from_tty);
extern void (*deprecated_trace_start_stop_hook) (int start, int from_tty); extern void (*deprecated_trace_start_stop_hook) (int start, int from_tty);
int get_traceframe_number (void); /* Returns the current traceframe number. */
void set_traceframe_number (int); 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_current_traceframe (void);
struct cleanup *make_cleanup_restore_traceframe_number (void);
void free_actions (struct breakpoint *); void free_actions (struct breakpoint *);
extern void validate_actionline (char **, struct breakpoint *); extern void validate_actionline (char **, struct breakpoint *);