gdb/gdbserver/

* server.h (LONGEST): New.
	(struct thread_info) <while_stepping>: New field.
	(unpack_varlen_hex, xrealloc, pulongest, plongest, phex_nz):
	Declare.
	(initialize_tracepoint, handle_tracepoint_general_set)
	(handle_tracepoint_query, tracepoint_finished_step)
	(tracepoint_was_hit, release_while_stepping_state_list):
	(current_traceframe): Declare.
	* server.c (handle_general_set): Handle tracepoint packets.
	(read_memory): New.
	(write_memory): New.
	(handle_search_memory_1): Use read_memory.
	(handle_query): Report support for conditional tracepoints, trace
	state variables, and tracepoint sources.  Handle tracepoint
	queries.
	(main): Initialize the tracepoints module.
	(process_serial_event): Handle traceframe reads/writes.

	* linux-low.c (handle_tracepoints): New.
	(linux_wait_1): Call it.
	(linux_resume_one_lwp): Handle while-stepping.
	(linux_supports_tracepoints, linux_read_pc, linux_write_pc): New.
	(linux_target_ops): Install them.
	* linux-low.h (struct linux_target_ops) <supports_tracepoints>:
	New field.
	* linux-x86-low.c (x86_supports_tracepoints): New.
	(the_low_target). Install it.

	* mem-break.h (delete_breakpoint): Declare.
	* mem-break.c (delete_breakpoint): Make external.

	* target.h (struct target_ops): Add `supports_tracepoints',
	`read_pc', and `write_pc' fields.
	(target_supports_tracepoints): Define.
	* utils.c (xrealloc, decimal2str, pulongest, plongest, thirty_two)
	(phex_nz): New.

	* regcache.h (struct regcache) <registers_owned>: New field.
	(init_register_cache, regcache_cpy): Declare.
	(regcache_read_pc, regcache_write_pc): Declare.
	(register_cache_size): Declare.
	(supply_regblock): Declare.
	* regcache.c (init_register_cache): New.
	(new_register_cache): Use it.
	(regcache_cpy): New.
	(register_cache_size): New.
	(supply_regblock): New.
	(regcache_read_pc, regcache_write_pc): New.

	* tracepoint.c: New.

	* Makefile.in (OBS): Add tracepoint.o.
	(tracepoint.o): New rule.

	gdb/
	* regformats/regdat.sh: Include server.h.  Don't include
	regcache.h.
This commit is contained in:
Pedro Alves 2010-04-09 03:40:00 +00:00
parent 33da3f1cb5
commit 219f2f2398
16 changed files with 3942 additions and 32 deletions

View File

@ -1,3 +1,8 @@
2010-04-09 Pedro Alves <pedro@codesourcery.com>
* regformats/regdat.sh: Include server.h. Don't include
regcache.h.
2010-04-08 Stan Shebs <stan@codesourcery.com>
Pedro Alves <pedro@codesourcery.com>

View File

@ -1,3 +1,60 @@
2010-04-09 Stan Shebs <stan@codesourcery.com>
Pedro Alves <pedro@codesourcery.com>
* server.h (LONGEST): New.
(struct thread_info) <while_stepping>: New field.
(unpack_varlen_hex, xrealloc, pulongest, plongest, phex_nz):
Declare.
(initialize_tracepoint, handle_tracepoint_general_set)
(handle_tracepoint_query, tracepoint_finished_step)
(tracepoint_was_hit, release_while_stepping_state_list):
(current_traceframe): Declare.
* server.c (handle_general_set): Handle tracepoint packets.
(read_memory): New.
(write_memory): New.
(handle_search_memory_1): Use read_memory.
(handle_query): Report support for conditional tracepoints, trace
state variables, and tracepoint sources. Handle tracepoint
queries.
(main): Initialize the tracepoints module.
(process_serial_event): Handle traceframe reads/writes.
* linux-low.c (handle_tracepoints): New.
(linux_wait_1): Call it.
(linux_resume_one_lwp): Handle while-stepping.
(linux_supports_tracepoints, linux_read_pc, linux_write_pc): New.
(linux_target_ops): Install them.
* linux-low.h (struct linux_target_ops) <supports_tracepoints>:
New field.
* linux-x86-low.c (x86_supports_tracepoints): New.
(the_low_target). Install it.
* mem-break.h (delete_breakpoint): Declare.
* mem-break.c (delete_breakpoint): Make external.
* target.h (struct target_ops): Add `supports_tracepoints',
`read_pc', and `write_pc' fields.
(target_supports_tracepoints): Define.
* utils.c (xrealloc, decimal2str, pulongest, plongest, thirty_two)
(phex_nz): New.
* regcache.h (struct regcache) <registers_owned>: New field.
(init_register_cache, regcache_cpy): Declare.
(regcache_read_pc, regcache_write_pc): Declare.
(register_cache_size): Declare.
(supply_regblock): Declare.
* regcache.c (init_register_cache): New.
(new_register_cache): Use it.
(regcache_cpy): New.
(register_cache_size): New.
(supply_regblock): New.
(regcache_read_pc, regcache_write_pc): New.
* tracepoint.c: New.
* Makefile.in (OBS): Add tracepoint.o.
(tracepoint.o): New rule.
2010-04-08 H.J. Lu <hongjiu.lu@intel.com>
* Makefile.in (clean): Also remove i386-mmx.c i386-mmx-linux.c.

View File

@ -127,7 +127,7 @@ TAGFILES = $(SOURCES) ${HFILES} ${ALLPARAM} ${POSSLIBS}
OBS = inferiors.o regcache.o remote-utils.o server.o signals.o target.o \
utils.o version.o \
mem-break.o hostio.o event-loop.o \
mem-break.o hostio.o event-loop.o tracepoint.o \
$(XML_BUILTIN) \
$(DEPFILES) $(LIBOBJS)
GDBREPLAY_OBS = gdbreplay.o version.o
@ -285,6 +285,7 @@ remote-utils.o: remote-utils.c terminal.h $(server_h)
server.o: server.c $(server_h)
target.o: target.c $(server_h)
thread-db.o: thread-db.c $(server_h) $(linux_low_h) $(gdb_proc_service_h)
tracepoint.o: tracepoint.c $(server_h)
utils.o: utils.c $(server_h)
gdbreplay.o: gdbreplay.c config.h

View File

@ -1117,6 +1117,39 @@ retry:
return child;
}
/* This function should only be called if the LWP got a SIGTRAP.
Handle any tracepoint steps or hits. Return true if a tracepoint
event was handled, 0 otherwise. */
static int
handle_tracepoints (struct lwp_info *lwp)
{
struct thread_info *tinfo = get_lwp_thread (lwp);
int tpoint_related_event = 0;
/* And we need to be sure that any all-threads-stopping doesn't try
to move threads out of the jump pads, as it could deadlock the
inferior (LWP could be in the jump pad, maybe even holding the
lock.) */
/* Do any necessary step collect actions. */
tpoint_related_event |= tracepoint_finished_step (tinfo, lwp->stop_pc);
/* See if we just hit a tracepoint and do its main collect
actions. */
tpoint_related_event |= tracepoint_was_hit (tinfo, lwp->stop_pc);
if (tpoint_related_event)
{
if (debug_threads)
fprintf (stderr, "got a tracepoint event\n");
return 1;
}
return 0;
}
/* Arrange for a breakpoint to be hit again later. We don't keep the
SIGTRAP status and don't forward the SIGTRAP signal to the LWP. We
will handle the current event, eventually we will resume this LWP,
@ -1589,6 +1622,7 @@ linux_wait_1 (ptid_t ptid,
int bp_explains_trap;
int maybe_internal_trap;
int report_to_gdb;
int trace_event;
/* Translate generic target options into linux options. */
options = __WALL;
@ -1727,6 +1761,11 @@ retry:
/* Now invoke the callbacks of any internal breakpoints there. */
check_breakpoints (event_child->stop_pc);
/* Handle tracepoint data collecting. This may overflow the
trace buffer, and cause a tracing stop, removing
breakpoints. */
trace_event = handle_tracepoints (event_child);
if (bp_explains_trap)
{
/* If we stepped or ran into an internal breakpoint, we've
@ -1744,6 +1783,8 @@ retry:
/* We have some other signal, possibly a step-over dance was in
progress, and it should be cancelled too. */
step_over_finished = finish_step_over (event_child);
trace_event = 0;
}
/* We have all the data we need. Either report the event to GDB, or
@ -1761,7 +1802,7 @@ retry:
report_to_gdb = (!maybe_internal_trap
|| event_child->last_resume_kind == resume_step
|| event_child->stopped_by_watchpoint
|| (!step_over_finished && !bp_explains_trap)
|| (!step_over_finished && !bp_explains_trap && !trace_event)
|| gdb_breakpoint_here (event_child->stop_pc));
/* We found no reason GDB would want us to stop. We either hit one
@ -1775,6 +1816,8 @@ retry:
fprintf (stderr, "Hit a gdbserver breakpoint.\n");
if (step_over_finished)
fprintf (stderr, "Step-over finished.\n");
if (trace_event)
fprintf (stderr, "Tracepoint event.\n");
}
/* We're not reporting this breakpoint to GDB, so apply the
@ -2135,6 +2178,15 @@ linux_resume_one_lwp (struct lwp_info *lwp,
if (lwp->stopped == 0)
return;
/* Cancel actions that rely on GDB not changing the PC (e.g., the
user used the "jump" command, or "set $pc = foo"). */
if (lwp->stop_pc != get_pc (lwp))
{
/* Collecting 'while-stepping' actions doesn't make sense
anymore. */
release_while_stepping_state_list (get_lwp_thread (lwp));
}
/* If we have pending signals or status, and a new signal, enqueue the
signal. Also enqueue the signal if we are waiting to reinsert a
breakpoint; it will be picked up again below. */
@ -2199,6 +2251,24 @@ linux_resume_one_lwp (struct lwp_info *lwp,
signal = 0;
}
/* If we have while-stepping actions in this thread set it stepping.
If we have a signal to deliver, it may or may not be set to
SIG_IGN, we don't know. Assume so, and allow collecting
while-stepping into a signal handler. A possible smart thing to
do would be to set an internal breakpoint at the signal return
address, continue, and carry on catching this while-stepping
action only when that breakpoint is hit. A future
enhancement. */
if (get_lwp_thread (lwp)->while_stepping != NULL
&& can_hardware_single_step ())
{
if (debug_threads)
fprintf (stderr,
"lwp %ld has a while-stepping action -> forcing step.\n",
lwpid_of (lwp));
step = 1;
}
if (debug_threads && the_low_target.get_pc != NULL)
{
struct regcache *regcache = get_thread_regcache (current_inferior, 1);
@ -4165,6 +4235,32 @@ linux_process_qsupported (const char *query)
the_low_target.process_qsupported (query);
}
static int
linux_supports_tracepoints (void)
{
if (*the_low_target.supports_tracepoints == NULL)
return 0;
return (*the_low_target.supports_tracepoints) ();
}
static CORE_ADDR
linux_read_pc (struct regcache *regcache)
{
if (the_low_target.get_pc == NULL)
return 0;
return (*the_low_target.get_pc) (regcache);
}
static void
linux_write_pc (struct regcache *regcache, CORE_ADDR pc)
{
gdb_assert (the_low_target.set_pc != NULL);
(*the_low_target.set_pc) (regcache, pc);
}
static struct target_ops linux_target_ops = {
linux_create_inferior,
linux_attach,
@ -4209,7 +4305,10 @@ static struct target_ops linux_target_ops = {
NULL,
#endif
linux_core_of_thread,
linux_process_qsupported
linux_process_qsupported,
linux_supports_tracepoints,
linux_read_pc,
linux_write_pc
};
static void

View File

@ -117,6 +117,9 @@ struct linux_target_ops
/* Hook to support target specific qSupported. */
void (*process_qsupported) (const char *);
/* Returns true if the low target supports tracepoints. */
int (*supports_tracepoints) (void);
};
extern struct linux_target_ops the_low_target;

View File

@ -1027,6 +1027,12 @@ x86_arch_setup (void)
x86_linux_update_xmltarget ();
}
static int
x86_supports_tracepoints (void)
{
return 1;
}
/* This is initialized assuming an amd64 target.
x86_arch_setup will correct it for i386 or amd64 targets. */
@ -1058,5 +1064,6 @@ struct linux_target_ops the_low_target =
x86_linux_new_process,
x86_linux_new_thread,
x86_linux_prepare_to_resume,
x86_linux_process_qsupported
x86_linux_process_qsupported,
x86_supports_tracepoints
};

View File

@ -302,7 +302,7 @@ delete_breakpoint_1 (struct process_info *proc, struct breakpoint *todel)
return ENOENT;
}
static int
int
delete_breakpoint (struct breakpoint *todel)
{
struct process_info *proc = current_process ();

View File

@ -55,6 +55,10 @@ struct breakpoint *set_breakpoint_at (CORE_ADDR where,
int delete_gdb_breakpoint_at (CORE_ADDR addr);
/* Delete a breakpoint. */
int delete_breakpoint (struct breakpoint *bkpt);
/* Set a reinsert breakpoint at STOP_AT. */
void set_reinsert_breakpoint (CORE_ADDR stop_at);

View File

@ -79,6 +79,29 @@ regcache_invalidate (void)
for_each_inferior (&all_threads, regcache_invalidate_one);
}
struct regcache *
init_register_cache (struct regcache *regcache, unsigned char *regbuf)
{
if (regbuf == NULL)
{
/* Make sure to zero-initialize the register cache when it is
created, in case there are registers the target never
fetches. This way they'll read as zero instead of
garbage. */
regcache->registers = xcalloc (1, register_bytes);
regcache->registers_owned = 1;
}
else
{
regcache->registers = regbuf;
regcache->registers_owned = 0;
}
regcache->registers_valid = 0;
return regcache;
}
struct regcache *
new_register_cache (void)
{
@ -88,16 +111,7 @@ new_register_cache (void)
return NULL; /* The architecture hasn't been initialized yet. */
regcache = xmalloc (sizeof (*regcache));
/* Make sure to zero-initialize the register cache when it is
created, in case there are registers the target never
fetches. This way they'll read as zero instead of
garbage. */
regcache->registers = xcalloc (1, register_bytes);
regcache->registers_valid = 0;
return regcache;
return init_register_cache (regcache, NULL);
}
void
@ -110,6 +124,13 @@ free_register_cache (struct regcache *regcache)
}
}
void
regcache_cpy (struct regcache *dst, struct regcache *src)
{
memcpy (dst->registers, src->registers, register_bytes);
dst->registers_valid = src->registers_valid;
}
static void
realloc_register_cache (struct inferior_list_entry *thread_p)
{
@ -146,6 +167,12 @@ set_register_cache (struct reg *regs, int n)
for_each_inferior (&all_threads, realloc_register_cache);
}
int
register_cache_size (void)
{
return register_bytes;
}
void
registers_to_string (struct regcache *regcache, char *buf)
{
@ -221,6 +248,15 @@ supply_register (struct regcache *regcache, int n, const void *buf)
memset (register_data (regcache, n, 0), 0, register_size (n));
}
void
supply_regblock (struct regcache *regcache, const void *buf)
{
if (buf)
memcpy (regcache->registers, buf, register_bytes);
else
memset (regcache->registers, 0, register_bytes);
}
void
supply_register_by_name (struct regcache *regcache,
const char *name, const void *buf)
@ -247,3 +283,29 @@ collect_register_by_name (struct regcache *regcache,
{
collect_register (regcache, find_regno (name), buf);
}
/* Special handling for register PC. */
CORE_ADDR
regcache_read_pc (struct regcache *regcache)
{
CORE_ADDR pc_val;
if (the_target->read_pc)
pc_val = the_target->read_pc (regcache);
else
internal_error (__FILE__, __LINE__,
"regcache_read_pc: Unable to find PC");
return pc_val;
}
void
regcache_write_pc (struct regcache *regcache, CORE_ADDR pc)
{
if (the_target->write_pc)
the_target->write_pc (regcache, pc);
else
internal_error (__FILE__, __LINE__,
"regcache_write_pc: Unable to update PC");
}

View File

@ -30,9 +30,15 @@ struct thread_info;
struct regcache
{
int registers_valid;
int registers_owned;
unsigned char *registers;
};
struct regcache *init_register_cache (struct regcache *regcache,
unsigned char *regbuf);
void regcache_cpy (struct regcache *dst, struct regcache *src);
/* Create a new register cache for INFERIOR. */
struct regcache *new_register_cache (void);
@ -57,12 +63,18 @@ void registers_to_string (struct regcache *regcache, char *buf);
void registers_from_string (struct regcache *regcache, char *buf);
CORE_ADDR regcache_read_pc (struct regcache *regcache);
void regcache_write_pc (struct regcache *regcache, CORE_ADDR pc);
/* Return a pointer to the description of register ``n''. */
struct reg *find_register_by_number (int n);
int register_size (int n);
int register_cache_size (void);
int find_regno (const char *name);
/* The following two variables are set by auto-generated
@ -75,6 +87,8 @@ void supply_register (struct regcache *regcache, int n, const void *buf);
void supply_register_by_name (struct regcache *regcache,
const char *name, const void *buf);
void supply_regblock (struct regcache *regcache, const void *buf);
void collect_register (struct regcache *regcache, int n, void *buf);
void collect_register_as_string (struct regcache *regcache, int n, char *buf);

View File

@ -449,6 +449,10 @@ handle_general_set (char *own_buf)
return;
}
if (target_supports_tracepoints ()
&& handle_tracepoint_general_set (own_buf))
return;
/* Otherwise we didn't know what packet it was. Say we didn't
understand it. */
own_buf[0] = 0;
@ -506,6 +510,43 @@ monitor_show_help (void)
monitor_output (" Quit GDBserver\n");
}
/* Read trace frame or inferior memory. */
static int
read_memory (CORE_ADDR memaddr, unsigned char *myaddr, int len)
{
if (current_traceframe >= 0)
{
ULONGEST nbytes;
ULONGEST length = len;
if (traceframe_read_mem (current_traceframe,
memaddr, myaddr, len, &nbytes))
return EIO;
/* Data read from trace buffer, we're done. */
if (nbytes == length)
return 0;
if (!in_readonly_region (memaddr, length))
return EIO;
/* Otherwise we have a valid readonly case, fall through. */
/* (assume no half-trace half-real blocks for now) */
}
return read_inferior_memory (memaddr, myaddr, len);
}
/* Write trace frame or inferior memory. Actually, writing to trace
frames is forbidden. */
static int
write_memory (CORE_ADDR memaddr, const unsigned char *myaddr, int len)
{
if (current_traceframe >= 0)
return EIO;
else
return write_inferior_memory (memaddr, myaddr, len);
}
/* Subroutine of handle_search_memory to simplify it. */
static int
@ -517,7 +558,7 @@ handle_search_memory_1 (CORE_ADDR start_addr, CORE_ADDR search_space_len,
{
/* Prime the search buffer. */
if (read_inferior_memory (start_addr, search_buf, search_buf_size) != 0)
if (read_memory (start_addr, search_buf, search_buf_size) != 0)
{
warning ("Unable to access target memory at 0x%lx, halting search.",
(long) start_addr);
@ -568,7 +609,7 @@ handle_search_memory_1 (CORE_ADDR start_addr, CORE_ADDR search_space_len,
? search_space_len - keep_len
: chunk_size);
if (read_inferior_memory (read_addr, search_buf + keep_len,
if (read_memory (read_addr, search_buf + keep_len,
nr_to_read) != 0)
{
warning ("Unable to access target memory at 0x%lx, halting search.",
@ -1346,6 +1387,13 @@ handle_query (char *own_buf, int packet_len, int *new_packet_len_p)
strcat (own_buf, ";qXfer:threads:read+");
if (target_supports_tracepoints ())
{
strcat (own_buf, ";ConditionalTracepoints+");
strcat (own_buf, ";TraceStateVariables+");
strcat (own_buf, ";TracepointSource+");
}
return;
}
@ -1506,6 +1554,9 @@ handle_query (char *own_buf, int packet_len, int *new_packet_len_p)
return;
}
if (target_supports_tracepoints () && handle_tracepoint_query (own_buf))
return;
/* Otherwise we didn't know what packet it was. Say we didn't
understand it. */
own_buf[0] = 0;
@ -2275,6 +2326,8 @@ main (int argc, char *argv[])
initialize_inferiors ();
initialize_async_io ();
initialize_low ();
if (target_supports_tracepoints ())
initialize_tracepoint ();
own_buf = xmalloc (PBUFSIZ + 1);
mem_buf = xmalloc (PBUFSIZ);
@ -2541,20 +2594,35 @@ process_serial_event (void)
}
break;
case 'g':
{
struct regcache *regcache;
require_running (own_buf);
if (current_traceframe >= 0)
{
struct regcache *regcache = new_register_cache ();
require_running (own_buf);
set_desired_inferior (1);
regcache = get_thread_regcache (current_inferior, 1);
registers_to_string (regcache, own_buf);
}
break;
case 'G':
{
if (fetch_traceframe_registers (current_traceframe,
regcache, -1) == 0)
registers_to_string (regcache, own_buf);
else
write_enn (own_buf);
free_register_cache (regcache);
}
else
{
struct regcache *regcache;
set_desired_inferior (1);
regcache = get_thread_regcache (current_inferior, 1);
registers_to_string (regcache, own_buf);
}
break;
case 'G':
require_running (own_buf);
if (current_traceframe >= 0)
write_enn (own_buf);
else
{
struct regcache *regcache;
require_running (own_buf);
set_desired_inferior (1);
regcache = get_thread_regcache (current_inferior, 1);
registers_from_string (regcache, &own_buf[1]);
@ -2564,7 +2632,7 @@ process_serial_event (void)
case 'm':
require_running (own_buf);
decode_m_packet (&own_buf[1], &mem_addr, &len);
if (read_inferior_memory (mem_addr, mem_buf, len) == 0)
if (read_memory (mem_addr, mem_buf, len) == 0)
convert_int_to_ascii (mem_buf, own_buf, len);
else
write_enn (own_buf);
@ -2572,7 +2640,7 @@ process_serial_event (void)
case 'M':
require_running (own_buf);
decode_M_packet (&own_buf[1], &mem_addr, &len, mem_buf);
if (write_inferior_memory (mem_addr, mem_buf, len) == 0)
if (write_memory (mem_addr, mem_buf, len) == 0)
write_ok (own_buf);
else
write_enn (own_buf);
@ -2581,7 +2649,7 @@ process_serial_event (void)
require_running (own_buf);
if (decode_X_packet (&own_buf[1], packet_len - 1,
&mem_addr, &len, mem_buf) < 0
|| write_inferior_memory (mem_addr, mem_buf, len) != 0)
|| write_memory (mem_addr, mem_buf, len) != 0)
write_enn (own_buf);
else
write_ok (own_buf);

View File

@ -85,6 +85,7 @@ typedef unsigned char gdb_byte;
least the size of a (void *). */
typedef long long CORE_ADDR;
typedef long long LONGEST;
typedef unsigned long long ULONGEST;
/* The ptid struct is a collection of the various "ids" necessary
@ -180,6 +181,31 @@ struct thread_info
/* The last wait status reported for this thread. */
struct target_waitstatus last_status;
/* Given `while-stepping', a thread may be collecting data for more
than one tracepoint simultaneously. E.g.:
ff0001 INSN1 <-- TP1, while-stepping 10 collect $regs
ff0002 INSN2
ff0003 INSN3 <-- TP2, collect $regs
ff0004 INSN4 <-- TP3, while-stepping 10 collect $regs
ff0005 INSN5
Notice that when instruction INSN5 is reached, the while-stepping
actions of both TP1 and TP3 are still being collected, and that TP2
had been collected meanwhile. The whole range of ff0001-ff0005
should be single-stepped, due to at least TP1's while-stepping
action covering the whole range.
On the other hand, the same tracepoint with a while-stepping action
may be hit by more than one thread simultaneously, hence we can't
keep the current step count in the tracepoint itself.
This is the head of the list of the states of `while-stepping'
tracepoint actions this thread is now collecting; NULL if empty.
Each item in the list holds the current step of the while-stepping
action. */
struct wstep_state *while_stepping;
};
struct dll_info
@ -371,6 +397,7 @@ int hexify (char *hex, const char *bin, int count);
int remote_escape_output (const gdb_byte *buffer, int len,
gdb_byte *out_buf, int *out_len,
int out_maxlen);
char *unpack_varlen_hex (char *buff, ULONGEST *result);
void clear_symbol_cache (struct sym_cache **symcache_p);
int look_up_one_symbol (const char *name, CORE_ADDR *addrp);
@ -416,6 +443,7 @@ void buffer_xml_printf (struct buffer *buffer, const char *format, ...)
/* Functions from utils.c */
void *xmalloc (size_t) ATTR_MALLOC;
void *xrealloc (void *, size_t);
void *xcalloc (size_t, size_t) ATTR_MALLOC;
char *xstrdup (const char *) ATTR_MALLOC;
void freeargv (char **argv);
@ -426,6 +454,9 @@ void internal_error (const char *file, int line, const char *, ...)
ATTR_NORETURN ATTR_FORMAT (printf, 3, 4);
void warning (const char *string,...) ATTR_FORMAT (printf, 1, 2);
char *paddress (CORE_ADDR addr);
char *pulongest (ULONGEST u);
char *plongest (LONGEST l);
char *phex_nz (ULONGEST l, int sizeof_l);
#define gdb_assert(expr) \
((void) ((expr) ? 0 : \
@ -464,6 +495,28 @@ char *paddress (CORE_ADDR addr);
as large as the largest register set supported by gdbserver. */
#define PBUFSIZ 16384
/* Functions from tracepoint.c */
void initialize_tracepoint (void);
int handle_tracepoint_general_set (char *own_buf);
int handle_tracepoint_query (char *own_buf);
int tracepoint_finished_step (struct thread_info *tinfo, CORE_ADDR stop_pc);
int tracepoint_was_hit (struct thread_info *tinfo, CORE_ADDR stop_pc);
void release_while_stepping_state_list (struct thread_info *tinfo);
extern int current_traceframe;
int in_readonly_region (CORE_ADDR addr, ULONGEST length);
int traceframe_read_mem (int tfnum, CORE_ADDR addr,
unsigned char *buf, ULONGEST length,
ULONGEST *nbytes);
int fetch_traceframe_registers (int tfnum,
struct regcache *regcache,
int regnum);
/* Version information, from version.c. */
extern const char version[];
extern const char host_name[];

View File

@ -289,6 +289,16 @@ struct target_ops
/* Target specific qSupported support. */
void (*process_qsupported) (const char *);
/* Return 1 if the target supports tracepoints, 0 (or leave the
callback NULL) otherwise. */
int (*supports_tracepoints) (void);
/* Read PC from REGCACHE. */
CORE_ADDR (*read_pc) (struct regcache *regcache);
/* Write PC to REGCACHE. */
void (*write_pc) (struct regcache *regcache, CORE_ADDR pc);
};
extern struct target_ops *the_target;
@ -333,6 +343,10 @@ void set_target_ops (struct target_ops *);
if (the_target->process_qsupported) \
the_target->process_qsupported (query)
#define target_supports_tracepoints() \
(the_target->supports_tracepoints \
? (*the_target->supports_tracepoints) () : 0)
/* Start non-stop mode, returns 0 on success, -1 on failure. */
int start_non_stop (int nonstop);

3398
gdb/gdbserver/tracepoint.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -57,6 +57,26 @@ xmalloc (size_t size)
return newmem;
}
/* Reallocate memory without fail. This works like xmalloc. */
void *
xrealloc (void *ptr, size_t size)
{
void *val;
if (size == 0)
size = 1;
if (ptr != NULL)
val = realloc (ptr, size); /* OK: realloc */
else
val = malloc (size); /* OK: malloc */
if (val == NULL)
malloc_failure (size);
return val;
}
/* Allocate memory without fail and set it to zero.
If malloc fails, this will print a message to stderr and exit. */
@ -229,3 +249,108 @@ paddress (CORE_ADDR addr)
xsnprintf (str, CELLSIZE, "%lx", (long) addr);
return str;
}
static char *
decimal2str (char *sign, ULONGEST addr, int width)
{
/* Steal code from valprint.c:print_decimal(). Should this worry
about the real size of addr as the above does? */
unsigned long temp[3];
char *str = get_cell ();
int i = 0;
do
{
temp[i] = addr % (1000 * 1000 * 1000);
addr /= (1000 * 1000 * 1000);
i++;
width -= 9;
}
while (addr != 0 && i < (sizeof (temp) / sizeof (temp[0])));
width = 9;
if (width < 0)
width = 0;
switch (i)
{
case 1:
xsnprintf (str, CELLSIZE, "%s%0*lu", sign, width, temp[0]);
break;
case 2:
xsnprintf (str, CELLSIZE, "%s%0*lu%09lu", sign, width,
temp[1], temp[0]);
break;
case 3:
xsnprintf (str, CELLSIZE, "%s%0*lu%09lu%09lu", sign, width,
temp[2], temp[1], temp[0]);
break;
default:
internal_error (__FILE__, __LINE__,
"failed internal consistency check");
}
return str;
}
/* %u for ULONGEST. The result is stored in a circular static buffer,
NUMCELLS deep. */
char *
pulongest (ULONGEST u)
{
return decimal2str ("", u, 0);
}
/* %d for LONGEST. The result is stored in a circular static buffer,
NUMCELLS deep. */
char *
plongest (LONGEST l)
{
if (l < 0)
return decimal2str ("-", -l, 0);
else
return decimal2str ("", l, 0);
}
/* Eliminate warning from compiler on 32-bit systems. */
static int thirty_two = 32;
/* Convert a ULONGEST into a HEX string, like %lx. The result is
stored in a circular static buffer, NUMCELLS deep. */
char *
phex_nz (ULONGEST l, int sizeof_l)
{
char *str;
switch (sizeof_l)
{
case 8:
{
unsigned long high = (unsigned long) (l >> thirty_two);
str = get_cell ();
if (high == 0)
xsnprintf (str, CELLSIZE, "%lx",
(unsigned long) (l & 0xffffffff));
else
xsnprintf (str, CELLSIZE, "%lx%08lx", high,
(unsigned long) (l & 0xffffffff));
break;
}
case 4:
str = get_cell ();
xsnprintf (str, CELLSIZE, "%lx", (unsigned long) l);
break;
case 2:
str = get_cell ();
xsnprintf (str, CELLSIZE, "%x", (unsigned short) (l & 0xffff));
break;
default:
str = phex_nz (l, sizeof (l));
break;
}
return str;
}

View File

@ -119,8 +119,8 @@ EOF
exec > new-$2
copyright $1
echo '#include "server.h"'
echo '#include "regdef.h"'
echo '#include "regcache.h"'
echo
offset=0
i=0