Implement displaced stepping.

gdb/
	* gdbarch.sh (max_insn_length): New 'variable'.
	(displaced_step_copy, displaced_step_fixup)
	(displaced_step_free_closure, displaced_step_location): New
	functions.
	(struct displaced_step_closure): Add forward declaration.
	* gdbarch.c, gdbarch.h: Regenerated.

	* arch-utils.c: #include "objfiles.h".
	(simple_displaced_step_copy_insn)
	(simple_displaced_step_free_closure)
	(displaced_step_at_entry_point): New functions.
	* arch-utils.h (simple_displaced_step_copy_insn)
	(simple_displaced_step_free_closure)
	(displaced_step_at_entry_point): New prototypes.

	* i386-tdep.c (I386_MAX_INSN_LEN): Rename to...
	(I386_MAX_MATCHED_INSN_LEN): ... this.
	(i386_absolute_jmp_p, i386_absolute_call_p)
	(i386_ret_p, i386_call_p, i386_breakpoint_p, i386_syscall_p)
	(i386_displaced_step_fixup): New functions.
	(struct i386_insn, i386_match_insn): Update.
	(i386_gdbarch_init): Set gdbarch_max_insn_length.
	* i386-tdep.h (I386_MAX_INSN_LEN): New.
	(i386_displaced_step_fixup): New prototype.
	* i386-linux-tdep.c (i386_linux_init_abi): Include "arch-utils.h".
	Register gdbarch_displaced_step_copy,
	gdbarch_displaced_step_fixup, gdbarch_displaced_step_free_closure,
	and gdbarch_displaced_step_location functions.

	* infrun.c (debug_displaced): New variable.
	(show_debug_displaced): New function.
	(struct displaced_step_request): New struct.
	(displaced_step_request_queue, displaced_step_ptid)
	(displaced_step_gdbarch, displaced_step_closure)
	(displaced_step_original, displaced_step_copy)
	(displaced_step_saved_copy, can_use_displaced_stepping): New
	variables.
	(show_can_use_displaced_stepping, use_displaced_stepping)
	(displaced_step_clear, cleanup_displaced_step_closure)
	(displaced_step_dump_bytes, displaced_step_prepare)
	(displaced_step_clear_cleanup, write_memory_ptid)
	(displaced_step_fixup): New functions.
	(resume): Call displaced_step_prepare.
	(proceed): Call read_pc once, and remember the value.  If using
	displaced stepping, don't remove breakpoints.
	(handle_inferior_event): Call displaced_step_fixup.  Add some
	debugging output.  When we try to step over a breakpoint, but get
	a signal to deliver to the thread instead, ensure the step-resume
	breakpoint is actually inserted.  If a thread hop is needed, and
	displaced stepping is enabled, don't remove breakpoints.
	(init_wait_for_inferior): Call displaced_step_clear.
	(_initialize_infrun): Add "set debug displaced" command.  Add
	"maint set can-use-displaced-stepping" command.  Clear
	displaced_step_ptid.
	* inferior.h (debug_displaced): Declare variable.
	(displaced_step_dump_bytes): Declare function.

	* Makefile.in (arch-utils.o, i386-linux-tdep.o): Update
	dependencies.

	gdb/testsuite/
	* gdb.asm/asmsrc1.s: Add scratch space.

	gdb/doc/
	* gdb.texinfo (Debugging Output): Document "set/show debug
	displaced".
	(Maintenance Commands): Document "maint set/show
	can-use-displaced-stepping".
This commit is contained in:
Pedro Alves
2008-05-02 16:49:54 +00:00
parent 0428b8f567
commit 237fc4c9cd
16 changed files with 1257 additions and 34 deletions

View File

@ -103,6 +103,14 @@ int sync_execution = 0;
static ptid_t previous_inferior_ptid;
int debug_displaced = 0;
static void
show_debug_displaced (struct ui_file *file, int from_tty,
struct cmd_list_element *c, const char *value)
{
fprintf_filtered (file, _("Displace stepping debugging is %s.\n"), value);
}
static int debug_infrun = 0;
static void
show_debug_infrun (struct ui_file *file, int from_tty,
@ -459,6 +467,377 @@ static int stepping_past_singlestep_breakpoint;
stepping the thread user has selected. */
static ptid_t deferred_step_ptid;
/* Displaced stepping. */
/* In non-stop debugging mode, we must take special care to manage
breakpoints properly; in particular, the traditional strategy for
stepping a thread past a breakpoint it has hit is unsuitable.
'Displaced stepping' is a tactic for stepping one thread past a
breakpoint it has hit while ensuring that other threads running
concurrently will hit the breakpoint as they should.
The traditional way to step a thread T off a breakpoint in a
multi-threaded program in all-stop mode is as follows:
a0) Initially, all threads are stopped, and breakpoints are not
inserted.
a1) We single-step T, leaving breakpoints uninserted.
a2) We insert breakpoints, and resume all threads.
In non-stop debugging, however, this strategy is unsuitable: we
don't want to have to stop all threads in the system in order to
continue or step T past a breakpoint. Instead, we use displaced
stepping:
n0) Initially, T is stopped, other threads are running, and
breakpoints are inserted.
n1) We copy the instruction "under" the breakpoint to a separate
location, outside the main code stream, making any adjustments
to the instruction, register, and memory state as directed by
T's architecture.
n2) We single-step T over the instruction at its new location.
n3) We adjust the resulting register and memory state as directed
by T's architecture. This includes resetting T's PC to point
back into the main instruction stream.
n4) We resume T.
This approach depends on the following gdbarch methods:
- gdbarch_max_insn_length and gdbarch_displaced_step_location
indicate where to copy the instruction, and how much space must
be reserved there. We use these in step n1.
- gdbarch_displaced_step_copy_insn copies a instruction to a new
address, and makes any necessary adjustments to the instruction,
register contents, and memory. We use this in step n1.
- gdbarch_displaced_step_fixup adjusts registers and memory after
we have successfuly single-stepped the instruction, to yield the
same effect the instruction would have had if we had executed it
at its original address. We use this in step n3.
- gdbarch_displaced_step_free_closure provides cleanup.
The gdbarch_displaced_step_copy_insn and
gdbarch_displaced_step_fixup functions must be written so that
copying an instruction with gdbarch_displaced_step_copy_insn,
single-stepping across the copied instruction, and then applying
gdbarch_displaced_insn_fixup should have the same effects on the
thread's memory and registers as stepping the instruction in place
would have. Exactly which responsibilities fall to the copy and
which fall to the fixup is up to the author of those functions.
See the comments in gdbarch.sh for details.
Note that displaced stepping and software single-step cannot
currently be used in combination, although with some care I think
they could be made to. Software single-step works by placing
breakpoints on all possible subsequent instructions; if the
displaced instruction is a PC-relative jump, those breakpoints
could fall in very strange places --- on pages that aren't
executable, or at addresses that are not proper instruction
boundaries. (We do generally let other threads run while we wait
to hit the software single-step breakpoint, and they might
encounter such a corrupted instruction.) One way to work around
this would be to have gdbarch_displaced_step_copy_insn fully
simulate the effect of PC-relative instructions (and return NULL)
on architectures that use software single-stepping.
In non-stop mode, we can have independent and simultaneous step
requests, so more than one thread may need to simultaneously step
over a breakpoint. The current implementation assumes there is
only one scratch space per process. In this case, we have to
serialize access to the scratch space. If thread A wants to step
over a breakpoint, but we are currently waiting for some other
thread to complete a displaced step, we leave thread A stopped and
place it in the displaced_step_request_queue. Whenever a displaced
step finishes, we pick the next thread in the queue and start a new
displaced step operation on it. See displaced_step_prepare and
displaced_step_fixup for details. */
/* If this is not null_ptid, this is the thread carrying out a
displaced single-step. This thread's state will require fixing up
once it has completed its step. */
static ptid_t displaced_step_ptid;
struct displaced_step_request
{
ptid_t ptid;
struct displaced_step_request *next;
};
/* A queue of pending displaced stepping requests. */
struct displaced_step_request *displaced_step_request_queue;
/* The architecture the thread had when we stepped it. */
static struct gdbarch *displaced_step_gdbarch;
/* The closure provided gdbarch_displaced_step_copy_insn, to be used
for post-step cleanup. */
static struct displaced_step_closure *displaced_step_closure;
/* The address of the original instruction, and the copy we made. */
static CORE_ADDR displaced_step_original, displaced_step_copy;
/* Saved contents of copy area. */
static gdb_byte *displaced_step_saved_copy;
/* When this is non-zero, we are allowed to use displaced stepping, if
the architecture supports it. When this is zero, we use
traditional the hold-and-step approach. */
int can_use_displaced_stepping = 1;
static void
show_can_use_displaced_stepping (struct ui_file *file, int from_tty,
struct cmd_list_element *c,
const char *value)
{
fprintf_filtered (file, _("\
Debugger's willingness to use displaced stepping to step over "
"breakpoints is %s.\n"), value);
}
/* Return non-zero if displaced stepping is enabled, and can be used
with GDBARCH. */
static int
use_displaced_stepping (struct gdbarch *gdbarch)
{
return (can_use_displaced_stepping
&& gdbarch_displaced_step_copy_insn_p (gdbarch));
}
/* Clean out any stray displaced stepping state. */
static void
displaced_step_clear (void)
{
/* Indicate that there is no cleanup pending. */
displaced_step_ptid = null_ptid;
if (displaced_step_closure)
{
gdbarch_displaced_step_free_closure (displaced_step_gdbarch,
displaced_step_closure);
displaced_step_closure = NULL;
}
}
static void
cleanup_displaced_step_closure (void *ptr)
{
struct displaced_step_closure *closure = ptr;
gdbarch_displaced_step_free_closure (current_gdbarch, closure);
}
/* Dump LEN bytes at BUF in hex to FILE, followed by a newline. */
void
displaced_step_dump_bytes (struct ui_file *file,
const gdb_byte *buf,
size_t len)
{
int i;
for (i = 0; i < len; i++)
fprintf_unfiltered (file, "%02x ", buf[i]);
fputs_unfiltered ("\n", file);
}
/* Prepare to single-step, using displaced stepping.
Note that we cannot use displaced stepping when we have a signal to
deliver. If we have a signal to deliver and an instruction to step
over, then after the step, there will be no indication from the
target whether the thread entered a signal handler or ignored the
signal and stepped over the instruction successfully --- both cases
result in a simple SIGTRAP. In the first case we mustn't do a
fixup, and in the second case we must --- but we can't tell which.
Comments in the code for 'random signals' in handle_inferior_event
explain how we handle this case instead.
Returns 1 if preparing was successful -- this thread is going to be
stepped now; or 0 if displaced stepping this thread got queued. */
static int
displaced_step_prepare (ptid_t ptid)
{
struct cleanup *old_cleanups;
struct regcache *regcache = get_thread_regcache (ptid);
struct gdbarch *gdbarch = get_regcache_arch (regcache);
CORE_ADDR original, copy;
ULONGEST len;
struct displaced_step_closure *closure;
/* We should never reach this function if the architecture does not
support displaced stepping. */
gdb_assert (gdbarch_displaced_step_copy_insn_p (gdbarch));
/* For the first cut, we're displaced stepping one thread at a
time. */
if (!ptid_equal (displaced_step_ptid, null_ptid))
{
/* Already waiting for a displaced step to finish. Defer this
request and place in queue. */
struct displaced_step_request *req, *new_req;
if (debug_displaced)
fprintf_unfiltered (gdb_stdlog,
"displaced: defering step of %s\n",
target_pid_to_str (ptid));
new_req = xmalloc (sizeof (*new_req));
new_req->ptid = ptid;
new_req->next = NULL;
if (displaced_step_request_queue)
{
for (req = displaced_step_request_queue;
req && req->next;
req = req->next)
;
req->next = new_req;
}
else
displaced_step_request_queue = new_req;
return 0;
}
else
{
if (debug_displaced)
fprintf_unfiltered (gdb_stdlog,
"displaced: stepping %s now\n",
target_pid_to_str (ptid));
}
displaced_step_clear ();
original = read_pc_pid (ptid);
copy = gdbarch_displaced_step_location (gdbarch);
len = gdbarch_max_insn_length (gdbarch);
/* Save the original contents of the copy area. */
displaced_step_saved_copy = xmalloc (len);
old_cleanups = make_cleanup (free_current_contents,
&displaced_step_saved_copy);
read_memory (copy, displaced_step_saved_copy, len);
if (debug_displaced)
{
fprintf_unfiltered (gdb_stdlog, "displaced: saved 0x%s: ",
paddr_nz (copy));
displaced_step_dump_bytes (gdb_stdlog, displaced_step_saved_copy, len);
};
closure = gdbarch_displaced_step_copy_insn (gdbarch,
original, copy, regcache);
/* We don't support the fully-simulated case at present. */
gdb_assert (closure);
make_cleanup (cleanup_displaced_step_closure, closure);
/* Resume execution at the copy. */
write_pc_pid (copy, ptid);
discard_cleanups (old_cleanups);
if (debug_displaced)
fprintf_unfiltered (gdb_stdlog, "displaced: displaced pc to 0x%s\n",
paddr_nz (copy));
/* Save the information we need to fix things up if the step
succeeds. */
displaced_step_ptid = ptid;
displaced_step_gdbarch = gdbarch;
displaced_step_closure = closure;
displaced_step_original = original;
displaced_step_copy = copy;
return 1;
}
static void
displaced_step_clear_cleanup (void *ignore)
{
displaced_step_clear ();
}
static void
write_memory_ptid (ptid_t ptid, CORE_ADDR memaddr, const gdb_byte *myaddr, int len)
{
struct cleanup *ptid_cleanup = save_inferior_ptid ();
inferior_ptid = ptid;
write_memory (memaddr, myaddr, len);
do_cleanups (ptid_cleanup);
}
static void
displaced_step_fixup (ptid_t event_ptid, enum target_signal signal)
{
struct cleanup *old_cleanups;
/* Was this event for the pid we displaced? */
if (ptid_equal (displaced_step_ptid, null_ptid)
|| ! ptid_equal (displaced_step_ptid, event_ptid))
return;
old_cleanups = make_cleanup (displaced_step_clear_cleanup, 0);
/* Restore the contents of the copy area. */
{
ULONGEST len = gdbarch_max_insn_length (displaced_step_gdbarch);
write_memory_ptid (displaced_step_ptid, displaced_step_copy,
displaced_step_saved_copy, len);
if (debug_displaced)
fprintf_unfiltered (gdb_stdlog, "displaced: restored 0x%s\n",
paddr_nz (displaced_step_copy));
}
/* Did the instruction complete successfully? */
if (signal == TARGET_SIGNAL_TRAP)
{
/* Fix up the resulting state. */
gdbarch_displaced_step_fixup (displaced_step_gdbarch,
displaced_step_closure,
displaced_step_original,
displaced_step_copy,
get_thread_regcache (displaced_step_ptid));
}
else
{
/* Since the instruction didn't complete, all we can do is
relocate the PC. */
CORE_ADDR pc = read_pc_pid (event_ptid);
pc = displaced_step_original + (pc - displaced_step_copy);
write_pc_pid (pc, event_ptid);
}
do_cleanups (old_cleanups);
/* Are there any pending displaced stepping requests? If so, run
one now. */
if (displaced_step_request_queue)
{
struct displaced_step_request *head;
ptid_t ptid;
head = displaced_step_request_queue;
ptid = head->ptid;
displaced_step_request_queue = head->next;
xfree (head);
if (debug_displaced)
fprintf_unfiltered (gdb_stdlog,
"displaced: stepping queued %s now\n",
target_pid_to_str (ptid));
displaced_step_ptid = null_ptid;
displaced_step_prepare (ptid);
target_resume (ptid, 1, TARGET_SIGNAL_0);
}
}
/* Resuming. */
/* Things to clean up if we QUIT out of resume (). */
static void
@ -510,14 +889,14 @@ resume (int step, enum target_signal sig)
{
int should_resume = 1;
struct cleanup *old_cleanups = make_cleanup (resume_cleanups, 0);
CORE_ADDR pc = read_pc ();
QUIT;
if (debug_infrun)
fprintf_unfiltered (gdb_stdlog, "infrun: resume (step=%d, signal=%d)\n",
step, sig);
/* FIXME: calling breakpoint_here_p (read_pc ()) three times! */
fprintf_unfiltered (gdb_stdlog,
"infrun: resume (step=%d, signal=%d), "
"stepping_over_breakpoint=%d\n",
step, sig, stepping_over_breakpoint);
/* Some targets (e.g. Solaris x86) have a kernel bug when stepping
over an instruction that causes a page fault without triggering
@ -535,7 +914,7 @@ resume (int step, enum target_signal sig)
removed or inserted, as appropriate. The exception is if we're sitting
at a permanent breakpoint; we need to step over it, but permanent
breakpoints can't be removed. So we have to test for it here. */
if (breakpoint_here_p (read_pc ()) == permanent_breakpoint_here)
if (breakpoint_here_p (pc) == permanent_breakpoint_here)
{
if (gdbarch_skip_permanent_breakpoint_p (current_gdbarch))
gdbarch_skip_permanent_breakpoint (current_gdbarch,
@ -547,6 +926,24 @@ how to step past a permanent breakpoint on this architecture. Try using\n\
a command like `return' or `jump' to continue execution."));
}
/* If enabled, step over breakpoints by executing a copy of the
instruction at a different address.
We can't use displaced stepping when we have a signal to deliver;
the comments for displaced_step_prepare explain why. The
comments in the handle_inferior event for dealing with 'random
signals' explain what we do instead. */
if (use_displaced_stepping (current_gdbarch)
&& stepping_over_breakpoint
&& sig == TARGET_SIGNAL_0)
{
if (!displaced_step_prepare (inferior_ptid))
/* Got placed in displaced stepping queue. Will be resumed
later when all the currently queued displaced stepping
requests finish. */
return;
}
if (step && gdbarch_software_single_step_p (current_gdbarch))
{
/* Do it the hard way, w/temp breakpoints */
@ -558,7 +955,7 @@ a command like `return' or `jump' to continue execution."));
`wait_for_inferior' */
singlestep_breakpoints_inserted_p = 1;
singlestep_ptid = inferior_ptid;
singlestep_pc = read_pc ();
singlestep_pc = pc;
}
}
@ -642,15 +1039,30 @@ a command like `return' or `jump' to continue execution."));
/* Most targets can step a breakpoint instruction, thus
executing it normally. But if this one cannot, just
continue and we will hit it anyway. */
if (step && breakpoint_inserted_here_p (read_pc ()))
if (step && breakpoint_inserted_here_p (pc))
step = 0;
}
if (debug_displaced
&& use_displaced_stepping (current_gdbarch)
&& stepping_over_breakpoint)
{
CORE_ADDR actual_pc = read_pc_pid (resume_ptid);
gdb_byte buf[4];
fprintf_unfiltered (gdb_stdlog, "displaced: run 0x%s: ",
paddr_nz (actual_pc));
read_memory (actual_pc, buf, sizeof (buf));
displaced_step_dump_bytes (gdb_stdlog, buf, sizeof (buf));
}
target_resume (resume_ptid, step, sig);
}
discard_cleanups (old_cleanups);
}
/* Proceeding. */
/* Clear out all variables saying what to do when inferior is continued.
First do this, then set the ones you want, then call `proceed'. */
@ -787,17 +1199,20 @@ proceed (CORE_ADDR addr, enum target_signal siggnal, int step)
if (oneproc)
{
/* We will get a trace trap after one instruction.
Continue it automatically and insert breakpoints then. */
stepping_over_breakpoint = 1;
/* FIXME: if breakpoints are always inserted, we'll trap
if trying to single-step over breakpoint. Disable
all breakpoints. In future, we'd need to invent some
smart way of stepping over breakpoint instruction without
hitting breakpoint. */
remove_breakpoints ();
/* If displaced stepping is enabled, we can step over the
breakpoint without hitting it, so leave all breakpoints
inserted. Otherwise we need to disable all breakpoints, step
one instruction, and then re-add them when that step is
finished. */
if (!use_displaced_stepping (current_gdbarch))
remove_breakpoints ();
}
else
/* We can insert breakpoints if we're not trying to step over one,
or if we are stepping over one but we're using displaced stepping
to do so. */
if (! stepping_over_breakpoint || use_displaced_stepping (current_gdbarch))
insert_breakpoints ();
if (siggnal != TARGET_SIGNAL_DEFAULT)
@ -908,7 +1323,10 @@ init_wait_for_inferior (void)
deferred_step_ptid = null_ptid;
target_last_wait_ptid = minus_one_ptid;
displaced_step_clear ();
}
/* This enum encodes possible reasons for doing a target_wait, so that
wfi can call target_wait in one place. (Ultimately the call will be
@ -1580,10 +1998,31 @@ handle_inferior_event (struct execution_control_state *ecs)
return;
}
/* Do we need to clean up the state of a thread that has completed a
displaced single-step? (Doing so usually affects the PC, so do
it here, before we set stop_pc.) */
displaced_step_fixup (ecs->ptid, stop_signal);
stop_pc = read_pc_pid (ecs->ptid);
if (debug_infrun)
fprintf_unfiltered (gdb_stdlog, "infrun: stop_pc = 0x%s\n", paddr_nz (stop_pc));
{
fprintf_unfiltered (gdb_stdlog, "infrun: stop_pc = 0x%s\n",
paddr_nz (stop_pc));
if (STOPPED_BY_WATCHPOINT (&ecs->ws))
{
CORE_ADDR addr;
fprintf_unfiltered (gdb_stdlog, "infrun: stopped by watchpoint\n");
if (target_stopped_data_address (&current_target, &addr))
fprintf_unfiltered (gdb_stdlog,
"infrun: stopped data address = 0x%s\n",
paddr_nz (addr));
else
fprintf_unfiltered (gdb_stdlog,
"infrun: (no data address available)\n");
}
}
if (stepping_past_singlestep_breakpoint)
{
@ -1731,7 +2170,7 @@ handle_inferior_event (struct execution_control_state *ecs)
if (thread_hop_needed)
{
int remove_status;
int remove_status = 0;
if (debug_infrun)
fprintf_unfiltered (gdb_stdlog, "infrun: thread_hop_needed\n");
@ -1746,7 +2185,11 @@ handle_inferior_event (struct execution_control_state *ecs)
singlestep_breakpoints_inserted_p = 0;
}
remove_status = remove_breakpoints ();
/* If the arch can displace step, don't remove the
breakpoints. */
if (!use_displaced_stepping (current_gdbarch))
remove_status = remove_breakpoints ();
/* Did we fail to remove breakpoints? If so, try
to set the PC past the bp. (There's at least
one situation in which we can fail to remove
@ -1810,9 +2253,6 @@ handle_inferior_event (struct execution_control_state *ecs)
&& (HAVE_STEPPABLE_WATCHPOINT
|| gdbarch_have_nonsteppable_watchpoint (current_gdbarch)))
{
if (debug_infrun)
fprintf_unfiltered (gdb_stdlog, "infrun: STOPPED_BY_WATCHPOINT\n");
/* At this point, we are stopped at an instruction which has
attempted to write to a piece of memory under control of
a watchpoint. The instruction hasn't actually executed
@ -1915,10 +2355,14 @@ handle_inferior_event (struct execution_control_state *ecs)
when we're trying to execute a breakpoint instruction on a
non-executable stack. This happens for call dummy breakpoints
for architectures like SPARC that place call dummies on the
stack. */
stack.
If we're doing a displaced step past a breakpoint, then the
breakpoint is always inserted at the original instruction;
non-standard signals can't be explained by the breakpoint. */
if (stop_signal == TARGET_SIGNAL_TRAP
|| (breakpoint_inserted_here_p (stop_pc)
|| (! stepping_over_breakpoint
&& breakpoint_inserted_here_p (stop_pc)
&& (stop_signal == TARGET_SIGNAL_ILL
|| stop_signal == TARGET_SIGNAL_SEGV
|| stop_signal == TARGET_SIGNAL_EMT))
@ -2045,7 +2489,7 @@ process_event_stop_test:
{
/* We were just starting a new sequence, attempting to
single-step off of a breakpoint and expecting a SIGTRAP.
Intead this signal arrives. This signal will take us out
Instead this signal arrives. This signal will take us out
of the stepping range so GDB needs to remember to, when
the signal handler returns, resume stepping off that
breakpoint. */
@ -2053,6 +2497,10 @@ process_event_stop_test:
code paths as single-step - set a breakpoint at the
signal return address and then, once hit, step off that
breakpoint. */
if (debug_infrun)
fprintf_unfiltered (gdb_stdlog,
"infrun: signal arrived while stepping over "
"breakpoint\n");
insert_step_resume_breakpoint_at_frame (get_current_frame ());
ecs->step_after_step_resume_breakpoint = 1;
@ -2076,6 +2524,11 @@ process_event_stop_test:
Note that this is only needed for a signal delivered
while in the single-step range. Nested signals aren't a
problem as they eventually all return. */
if (debug_infrun)
fprintf_unfiltered (gdb_stdlog,
"infrun: signal may take us out of "
"single-step range\n");
insert_step_resume_breakpoint_at_frame (get_current_frame ());
keep_going (ecs);
return;
@ -2905,7 +3358,11 @@ keep_going (struct execution_control_state *ecs)
if (ecs->stepping_over_breakpoint)
{
remove_breakpoints ();
if (! use_displaced_stepping (current_gdbarch))
/* Since we can't do a displaced step, we have to remove
the breakpoint while we step it. To keep things
simple, we remove them all. */
remove_breakpoints ();
}
else
{
@ -4011,6 +4468,14 @@ When non-zero, inferior specific debugging is enabled."),
show_debug_infrun,
&setdebuglist, &showdebuglist);
add_setshow_boolean_cmd ("displaced", class_maintenance, &debug_displaced, _("\
Set displaced stepping debugging."), _("\
Show displaced stepping debugging."), _("\
When non-zero, displaced stepping specific debugging is enabled."),
NULL,
show_debug_displaced,
&setdebuglist, &showdebuglist);
numsigs = (int) TARGET_SIGNAL_LAST;
signal_stop = (unsigned char *) xmalloc (sizeof (signal_stop[0]) * numsigs);
signal_print = (unsigned char *)
@ -4106,9 +4571,22 @@ function is skipped and the step command stops at a different source line."),
show_step_stop_if_no_debug,
&setlist, &showlist);
add_setshow_boolean_cmd ("can-use-displaced-stepping", class_maintenance,
&can_use_displaced_stepping, _("\
Set debugger's willingness to use displaced stepping."), _("\
Show debugger's willingness to use displaced stepping."), _("\
If zero, gdb will not use to use displaced stepping to step over\n\
breakpoints, even if such is supported by the target."),
NULL,
show_can_use_displaced_stepping,
&maintenance_set_cmdlist,
&maintenance_show_cmdlist);
/* ptid initializations */
null_ptid = ptid_build (0, 0, 0);
minus_one_ptid = ptid_build (-1, 0, 0);
inferior_ptid = null_ptid;
target_last_wait_ptid = minus_one_ptid;
displaced_step_ptid = null_ptid;
}