mirror of
https://github.com/darlinghq/darling-gdb.git
synced 2025-02-22 02:21:19 +00:00
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:
parent
33da3f1cb5
commit
219f2f2398
@ -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>
|
||||
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
};
|
||||
|
@ -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 ();
|
||||
|
@ -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);
|
||||
|
@ -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");
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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[];
|
||||
|
@ -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
3398
gdb/gdbserver/tracepoint.c
Normal file
File diff suppressed because it is too large
Load Diff
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
|
Loading…
x
Reference in New Issue
Block a user