mirror of
https://github.com/espressif/binutils-gdb.git
synced 2025-06-21 02:24:17 +08:00
range stepping: gdbserver (x86 GNU/Linux)
This patch adds support for range stepping to GDBserver, teaching it about vCont;r. It'd be easy to enable this for all hardware single-step targets without needing the linux_target_ops hook, however, at least PPC needs special care, due to the fact that PPC atomic sequences can't be hardware single-stepped through, a thing which GDBserver doesn't know about. So this leaves the support limited to x86/x86_64. gdb/ 2013-05-23 Pedro Alves <palves@redhat.com> * NEWS: Mention GDBserver range stepping support. gdb/gdbserver/ 2013-05-23 Yao Qi <yao@codesourcery.com> Pedro Alves <palves@redhat.com> * linux-low.c (lwp_in_step_range): New function. (linux_wait_1): If the thread was range stepping and stopped outside the stepping range, report the stop to GDB. Otherwise, continue stepping. Add range stepping debug output. (linux_set_resume_request): Copy the step range from the resume request to the lwp. (linux_supports_range_stepping): New. (linux_target_ops) <supports_range_stepping>: Set to linux_supports_range_stepping. * linux-low.h (struct linux_target_ops) <supports_range_stepping>: New field. (struct lwp_info) <step_range_start, step_range_end>: New fields. * linux-x86-low.c (x86_supports_range_stepping): New. (the_low_target) <supports_range_stepping>: Set to x86_supports_range_stepping. * server.c (handle_v_cont): Handle 'r' action. (handle_v_requests): Append ";r" if the target supports range stepping. * target.h (struct thread_resume) <step_range_start, step_range_end>: New fields. (struct target_ops) <supports_range_stepping>: New field. (target_supports_range_stepping): New macro.
This commit is contained in:
@ -1,3 +1,7 @@
|
|||||||
|
2013-05-23 Pedro Alves <palves@redhat.com>
|
||||||
|
|
||||||
|
* NEWS: Mention GDBserver range stepping support.
|
||||||
|
|
||||||
2013-05-23 Yao Qi <yao@codesourcery.com>
|
2013-05-23 Yao Qi <yao@codesourcery.com>
|
||||||
Pedro Alves <palves@redhat.com>
|
Pedro Alves <palves@redhat.com>
|
||||||
|
|
||||||
|
5
gdb/NEWS
5
gdb/NEWS
@ -95,6 +95,11 @@ vCont;r
|
|||||||
stub to step through an address range itself, without GDB
|
stub to step through an address range itself, without GDB
|
||||||
involvemement at each single-step.
|
involvemement at each single-step.
|
||||||
|
|
||||||
|
* New features in the GDB remote stub, GDBserver
|
||||||
|
|
||||||
|
** GDBserver now supports target-assisted range stepping. Currently
|
||||||
|
enabled on x86/x86_64 GNU/Linux targets.
|
||||||
|
|
||||||
*** Changes in GDB 7.6
|
*** Changes in GDB 7.6
|
||||||
|
|
||||||
* Target record has been renamed to record-full.
|
* Target record has been renamed to record-full.
|
||||||
|
@ -1,3 +1,30 @@
|
|||||||
|
2013-05-23 Yao Qi <yao@codesourcery.com>
|
||||||
|
Pedro Alves <palves@redhat.com>
|
||||||
|
|
||||||
|
* linux-low.c (lwp_in_step_range): New function.
|
||||||
|
(linux_wait_1): If the thread was range stepping and stopped
|
||||||
|
outside the stepping range, report the stop to GDB. Otherwise,
|
||||||
|
continue stepping. Add range stepping debug output.
|
||||||
|
(linux_set_resume_request): Copy the step range from the resume
|
||||||
|
request to the lwp.
|
||||||
|
(linux_supports_range_stepping): New.
|
||||||
|
(linux_target_ops) <supports_range_stepping>: Set to
|
||||||
|
linux_supports_range_stepping.
|
||||||
|
* linux-low.h (struct linux_target_ops)
|
||||||
|
<supports_range_stepping>: New field.
|
||||||
|
(struct lwp_info) <step_range_start, step_range_end>: New fields.
|
||||||
|
* linux-x86-low.c (x86_supports_range_stepping): New.
|
||||||
|
(the_low_target) <supports_range_stepping>: Set to
|
||||||
|
x86_supports_range_stepping.
|
||||||
|
* server.c (handle_v_cont): Handle 'r' action.
|
||||||
|
(handle_v_requests): Append ";r" if the target supports range
|
||||||
|
stepping.
|
||||||
|
* target.h (struct thread_resume) <step_range_start,
|
||||||
|
step_range_end>: New fields.
|
||||||
|
(struct target_ops) <supports_range_stepping>:
|
||||||
|
New field.
|
||||||
|
(target_supports_range_stepping): New macro.
|
||||||
|
|
||||||
2013-05-17 Joel Brobecker <brobecker@adacore.com>
|
2013-05-17 Joel Brobecker <brobecker@adacore.com>
|
||||||
|
|
||||||
* lynx-low.c (lynx_resume): Fix null_ptid/minus_one_ptid
|
* lynx-low.c (lynx_resume): Fix null_ptid/minus_one_ptid
|
||||||
|
@ -276,6 +276,16 @@ supports_fast_tracepoints (void)
|
|||||||
return the_low_target.install_fast_tracepoint_jump_pad != NULL;
|
return the_low_target.install_fast_tracepoint_jump_pad != NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* True if LWP is stopped in its stepping range. */
|
||||||
|
|
||||||
|
static int
|
||||||
|
lwp_in_step_range (struct lwp_info *lwp)
|
||||||
|
{
|
||||||
|
CORE_ADDR pc = lwp->stop_pc;
|
||||||
|
|
||||||
|
return (pc >= lwp->step_range_start && pc < lwp->step_range_end);
|
||||||
|
}
|
||||||
|
|
||||||
struct pending_signals
|
struct pending_signals
|
||||||
{
|
{
|
||||||
int signal;
|
int signal;
|
||||||
@ -2337,6 +2347,7 @@ linux_wait_1 (ptid_t ptid,
|
|||||||
int maybe_internal_trap;
|
int maybe_internal_trap;
|
||||||
int report_to_gdb;
|
int report_to_gdb;
|
||||||
int trace_event;
|
int trace_event;
|
||||||
|
int in_step_range;
|
||||||
|
|
||||||
/* Translate generic target options into linux options. */
|
/* Translate generic target options into linux options. */
|
||||||
options = __WALL;
|
options = __WALL;
|
||||||
@ -2346,6 +2357,7 @@ linux_wait_1 (ptid_t ptid,
|
|||||||
retry:
|
retry:
|
||||||
bp_explains_trap = 0;
|
bp_explains_trap = 0;
|
||||||
trace_event = 0;
|
trace_event = 0;
|
||||||
|
in_step_range = 0;
|
||||||
ourstatus->kind = TARGET_WAITKIND_IGNORE;
|
ourstatus->kind = TARGET_WAITKIND_IGNORE;
|
||||||
|
|
||||||
/* If we were only supposed to resume one thread, only wait for
|
/* If we were only supposed to resume one thread, only wait for
|
||||||
@ -2639,18 +2651,24 @@ Check if we're already there.\n",
|
|||||||
goto retry;
|
goto retry;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If GDB wanted this thread to single step, we always want to
|
/* Note that all addresses are always "out of the step range" when
|
||||||
report the SIGTRAP, and let GDB handle it. Watchpoints should
|
there's no range to begin with. */
|
||||||
always be reported. So should signals we can't explain. A
|
in_step_range = lwp_in_step_range (event_child);
|
||||||
SIGTRAP we can't explain could be a GDB breakpoint --- we may or
|
|
||||||
not support Z0 breakpoints. If we do, we're be able to handle
|
/* If GDB wanted this thread to single step, and the thread is out
|
||||||
GDB breakpoints on top of internal breakpoints, by handling the
|
of the step range, we always want to report the SIGTRAP, and let
|
||||||
internal breakpoint and still reporting the event to GDB. If we
|
GDB handle it. Watchpoints should always be reported. So should
|
||||||
don't, we're out of luck, GDB won't see the breakpoint hit. */
|
signals we can't explain. A SIGTRAP we can't explain could be a
|
||||||
|
GDB breakpoint --- we may or not support Z0 breakpoints. If we
|
||||||
|
do, we're be able to handle GDB breakpoints on top of internal
|
||||||
|
breakpoints, by handling the internal breakpoint and still
|
||||||
|
reporting the event to GDB. If we don't, we're out of luck, GDB
|
||||||
|
won't see the breakpoint hit. */
|
||||||
report_to_gdb = (!maybe_internal_trap
|
report_to_gdb = (!maybe_internal_trap
|
||||||
|| current_inferior->last_resume_kind == resume_step
|
|| (current_inferior->last_resume_kind == resume_step
|
||||||
|
&& !in_step_range)
|
||||||
|| event_child->stopped_by_watchpoint
|
|| event_child->stopped_by_watchpoint
|
||||||
|| (!step_over_finished
|
|| (!step_over_finished && !in_step_range
|
||||||
&& !bp_explains_trap && !trace_event)
|
&& !bp_explains_trap && !trace_event)
|
||||||
|| (gdb_breakpoint_here (event_child->stop_pc)
|
|| (gdb_breakpoint_here (event_child->stop_pc)
|
||||||
&& gdb_condition_true_at_breakpoint (event_child->stop_pc)
|
&& gdb_condition_true_at_breakpoint (event_child->stop_pc)
|
||||||
@ -2671,6 +2689,11 @@ Check if we're already there.\n",
|
|||||||
fprintf (stderr, "Step-over finished.\n");
|
fprintf (stderr, "Step-over finished.\n");
|
||||||
if (trace_event)
|
if (trace_event)
|
||||||
fprintf (stderr, "Tracepoint event.\n");
|
fprintf (stderr, "Tracepoint event.\n");
|
||||||
|
if (lwp_in_step_range (event_child))
|
||||||
|
fprintf (stderr, "Range stepping pc 0x%s [0x%s, 0x%s).\n",
|
||||||
|
paddress (event_child->stop_pc),
|
||||||
|
paddress (event_child->step_range_start),
|
||||||
|
paddress (event_child->step_range_end));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* We're not reporting this breakpoint to GDB, so apply the
|
/* We're not reporting this breakpoint to GDB, so apply the
|
||||||
@ -2702,7 +2725,12 @@ Check if we're already there.\n",
|
|||||||
if (debug_threads)
|
if (debug_threads)
|
||||||
{
|
{
|
||||||
if (current_inferior->last_resume_kind == resume_step)
|
if (current_inferior->last_resume_kind == resume_step)
|
||||||
fprintf (stderr, "GDB wanted to single-step, reporting event.\n");
|
{
|
||||||
|
if (event_child->step_range_start == event_child->step_range_end)
|
||||||
|
fprintf (stderr, "GDB wanted to single-step, reporting event.\n");
|
||||||
|
else if (!lwp_in_step_range (event_child))
|
||||||
|
fprintf (stderr, "Out of step range, reporting event.\n");
|
||||||
|
}
|
||||||
if (event_child->stopped_by_watchpoint)
|
if (event_child->stopped_by_watchpoint)
|
||||||
fprintf (stderr, "Stopped by watchpoint.\n");
|
fprintf (stderr, "Stopped by watchpoint.\n");
|
||||||
if (gdb_breakpoint_here (event_child->stop_pc))
|
if (gdb_breakpoint_here (event_child->stop_pc))
|
||||||
@ -3401,6 +3429,9 @@ linux_set_resume_request (struct inferior_list_entry *entry, void *arg)
|
|||||||
lwp->resume = &r->resume[ndx];
|
lwp->resume = &r->resume[ndx];
|
||||||
thread->last_resume_kind = lwp->resume->kind;
|
thread->last_resume_kind = lwp->resume->kind;
|
||||||
|
|
||||||
|
lwp->step_range_start = lwp->resume->step_range_start;
|
||||||
|
lwp->step_range_end = lwp->resume->step_range_end;
|
||||||
|
|
||||||
/* If we had a deferred signal to report, dequeue one now.
|
/* If we had a deferred signal to report, dequeue one now.
|
||||||
This can happen if LWP gets more than one signal while
|
This can happen if LWP gets more than one signal while
|
||||||
trying to get out of a jump pad. */
|
trying to get out of a jump pad. */
|
||||||
@ -5094,6 +5125,15 @@ linux_supports_agent (void)
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
linux_supports_range_stepping (void)
|
||||||
|
{
|
||||||
|
if (*the_low_target.supports_range_stepping == NULL)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return (*the_low_target.supports_range_stepping) ();
|
||||||
|
}
|
||||||
|
|
||||||
/* Enumerate spufs IDs for process PID. */
|
/* Enumerate spufs IDs for process PID. */
|
||||||
static int
|
static int
|
||||||
spu_enumerate_spu_ids (long pid, unsigned char *buf, CORE_ADDR offset, int len)
|
spu_enumerate_spu_ids (long pid, unsigned char *buf, CORE_ADDR offset, int len)
|
||||||
@ -5952,6 +5992,7 @@ static struct target_ops linux_target_ops = {
|
|||||||
NULL,
|
NULL,
|
||||||
NULL,
|
NULL,
|
||||||
#endif
|
#endif
|
||||||
|
linux_supports_range_stepping,
|
||||||
};
|
};
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -166,6 +166,8 @@ struct linux_target_ops
|
|||||||
for use as a fast tracepoint. */
|
for use as a fast tracepoint. */
|
||||||
int (*get_min_fast_tracepoint_insn_len) (void);
|
int (*get_min_fast_tracepoint_insn_len) (void);
|
||||||
|
|
||||||
|
/* Returns true if the low target supports range stepping. */
|
||||||
|
int (*supports_range_stepping) (void);
|
||||||
};
|
};
|
||||||
|
|
||||||
extern struct linux_target_ops the_low_target;
|
extern struct linux_target_ops the_low_target;
|
||||||
@ -235,6 +237,12 @@ struct lwp_info
|
|||||||
level on this process was a single-step. */
|
level on this process was a single-step. */
|
||||||
int stepping;
|
int stepping;
|
||||||
|
|
||||||
|
/* Range to single step within. This is a copy of the step range
|
||||||
|
passed along the last resume request. See 'struct
|
||||||
|
thread_resume'. */
|
||||||
|
CORE_ADDR step_range_start; /* Inclusive */
|
||||||
|
CORE_ADDR step_range_end; /* Exclusive */
|
||||||
|
|
||||||
/* If this flag is set, we need to set the event request flags the
|
/* If this flag is set, we need to set the event request flags the
|
||||||
next time we see this LWP stop. */
|
next time we see this LWP stop. */
|
||||||
int must_set_ptrace_flags;
|
int must_set_ptrace_flags;
|
||||||
|
@ -3175,6 +3175,12 @@ x86_emit_ops (void)
|
|||||||
return &i386_emit_ops;
|
return &i386_emit_ops;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
x86_supports_range_stepping (void)
|
||||||
|
{
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
/* This is initialized assuming an amd64 target.
|
/* This is initialized assuming an amd64 target.
|
||||||
x86_arch_setup will correct it for i386 or amd64 targets. */
|
x86_arch_setup will correct it for i386 or amd64 targets. */
|
||||||
|
|
||||||
@ -3214,4 +3220,5 @@ struct linux_target_ops the_low_target =
|
|||||||
x86_install_fast_tracepoint_jump_pad,
|
x86_install_fast_tracepoint_jump_pad,
|
||||||
x86_emit_ops,
|
x86_emit_ops,
|
||||||
x86_get_min_fast_tracepoint_insn_len,
|
x86_get_min_fast_tracepoint_insn_len,
|
||||||
|
x86_supports_range_stepping,
|
||||||
};
|
};
|
||||||
|
@ -2042,8 +2042,12 @@ handle_v_cont (char *own_buf)
|
|||||||
{
|
{
|
||||||
p++;
|
p++;
|
||||||
|
|
||||||
|
memset (&resume_info[i], 0, sizeof resume_info[i]);
|
||||||
|
|
||||||
if (p[0] == 's' || p[0] == 'S')
|
if (p[0] == 's' || p[0] == 'S')
|
||||||
resume_info[i].kind = resume_step;
|
resume_info[i].kind = resume_step;
|
||||||
|
else if (p[0] == 'r')
|
||||||
|
resume_info[i].kind = resume_step;
|
||||||
else if (p[0] == 'c' || p[0] == 'C')
|
else if (p[0] == 'c' || p[0] == 'C')
|
||||||
resume_info[i].kind = resume_continue;
|
resume_info[i].kind = resume_continue;
|
||||||
else if (p[0] == 't')
|
else if (p[0] == 't')
|
||||||
@ -2063,9 +2067,22 @@ handle_v_cont (char *own_buf)
|
|||||||
goto err;
|
goto err;
|
||||||
resume_info[i].sig = gdb_signal_to_host (sig);
|
resume_info[i].sig = gdb_signal_to_host (sig);
|
||||||
}
|
}
|
||||||
|
else if (p[0] == 'r')
|
||||||
|
{
|
||||||
|
char *p1;
|
||||||
|
|
||||||
|
p = p + 1;
|
||||||
|
p1 = strchr (p, ',');
|
||||||
|
decode_address (&resume_info[i].step_range_start, p, p1 - p);
|
||||||
|
|
||||||
|
p = p1 + 1;
|
||||||
|
p1 = strchr (p, ':');
|
||||||
|
decode_address (&resume_info[i].step_range_end, p, p1 - p);
|
||||||
|
|
||||||
|
p = p1;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
resume_info[i].sig = 0;
|
|
||||||
p = p + 1;
|
p = p + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2311,6 +2328,11 @@ handle_v_requests (char *own_buf, int packet_len, int *new_packet_len)
|
|||||||
if (strncmp (own_buf, "vCont?", 6) == 0)
|
if (strncmp (own_buf, "vCont?", 6) == 0)
|
||||||
{
|
{
|
||||||
strcpy (own_buf, "vCont;c;C;s;S;t");
|
strcpy (own_buf, "vCont;c;C;s;S;t");
|
||||||
|
if (target_supports_range_stepping ())
|
||||||
|
{
|
||||||
|
own_buf = own_buf + strlen (own_buf);
|
||||||
|
strcpy (own_buf, ";r");
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -57,6 +57,15 @@ struct thread_resume
|
|||||||
linux; SuspendThread on win32). This is a host signal value (not
|
linux; SuspendThread on win32). This is a host signal value (not
|
||||||
enum gdb_signal). */
|
enum gdb_signal). */
|
||||||
int sig;
|
int sig;
|
||||||
|
|
||||||
|
/* Range to single step within. Valid only iff KIND is resume_step.
|
||||||
|
|
||||||
|
Single-step once, and then continuing stepping as long as the
|
||||||
|
thread stops in this range. (If the range is empty
|
||||||
|
[STEP_RANGE_START == STEP_RANGE_END], then this is a single-step
|
||||||
|
request.) */
|
||||||
|
CORE_ADDR step_range_start; /* Inclusive */
|
||||||
|
CORE_ADDR step_range_end; /* Exclusive */
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Generally, what has the program done? */
|
/* Generally, what has the program done? */
|
||||||
@ -414,6 +423,8 @@ struct target_ops
|
|||||||
to break a cyclic dependency. */
|
to break a cyclic dependency. */
|
||||||
void (*read_btrace) (struct btrace_target_info *, struct buffer *, int type);
|
void (*read_btrace) (struct btrace_target_info *, struct buffer *, int type);
|
||||||
|
|
||||||
|
/* Return true if target supports range stepping. */
|
||||||
|
int (*supports_range_stepping) (void);
|
||||||
};
|
};
|
||||||
|
|
||||||
extern struct target_ops *the_target;
|
extern struct target_ops *the_target;
|
||||||
@ -549,6 +560,10 @@ int kill_inferior (int);
|
|||||||
#define target_read_btrace(tinfo, buffer, type) \
|
#define target_read_btrace(tinfo, buffer, type) \
|
||||||
(*the_target->read_btrace) (tinfo, buffer, type)
|
(*the_target->read_btrace) (tinfo, buffer, type)
|
||||||
|
|
||||||
|
#define target_supports_range_stepping() \
|
||||||
|
(the_target->supports_range_stepping ? \
|
||||||
|
(*the_target->supports_range_stepping) () : 0)
|
||||||
|
|
||||||
/* Start non-stop mode, returns 0 on success, -1 on failure. */
|
/* Start non-stop mode, returns 0 on success, -1 on failure. */
|
||||||
|
|
||||||
int start_non_stop (int nonstop);
|
int start_non_stop (int nonstop);
|
||||||
|
Reference in New Issue
Block a user