/* 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;
+/* Enum strings for "set|show displaced-stepping". */
+
+static const char can_use_displaced_stepping_auto[] = "auto";
+static const char can_use_displaced_stepping_on[] = "on";
+static const char can_use_displaced_stepping_off[] = "off";
+static const char *can_use_displaced_stepping_enum[] =
+{
+ can_use_displaced_stepping_auto,
+ can_use_displaced_stepping_on,
+ can_use_displaced_stepping_off,
+ NULL,
+};
+
+/* If ON, and the architecture supports it, GDB will use displaced
+ stepping to step over breakpoints. If OFF, or if the architecture
+ doesn't support it, GDB will instead use the traditional
+ hold-and-step approach. If AUTO (which is the default), GDB will
+ decide which technique to use to step over breakpoints depending on
+ which of all-stop or non-stop mode is active --- displaced stepping
+ in non-stop mode; hold-and-step in all-stop mode. */
+
+static const char *can_use_displaced_stepping =
+ can_use_displaced_stepping_auto;
+
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);
+ if (can_use_displaced_stepping == can_use_displaced_stepping_auto)
+ fprintf_filtered (file, _("\
+Debugger's willingness to use displaced stepping to step over \
+breakpoints is %s (currently %s).\n"),
+ value, non_stop ? "on" : "off");
+ else
+ 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. */
+/* Return non-zero if displaced stepping can/should be used to step
+ over breakpoints. */
+
static int
use_displaced_stepping (struct gdbarch *gdbarch)
{
- return (can_use_displaced_stepping
+ return (((can_use_displaced_stepping == can_use_displaced_stepping_auto
+ && non_stop)
+ || can_use_displaced_stepping == can_use_displaced_stepping_on)
&& gdbarch_displaced_step_copy_insn_p (gdbarch));
}
tp->step_range_end = 0;
tp->step_frame_id = null_frame_id;
tp->step_over_calls = STEP_OVER_UNDEBUGGABLE;
+ tp->stop_requested = 0;
tp->stop_step = 0;
static void print_stop_reason (enum inferior_stop_reason stop_reason,
int stop_info);
+/* Callback for iterate over threads. If the thread is stopped, but
+ the user/frontend doesn't know about that yet, go through
+ normal_stop, as if the thread had just stopped now. ARG points at
+ a ptid. If PTID is MINUS_ONE_PTID, applies to all threads. If
+ ptid_is_pid(PTID) is true, applies to all threads of the process
+ pointed at by PTID. Otherwise, apply only to the thread pointed by
+ PTID. */
+
+static int
+infrun_thread_stop_requested_callback (struct thread_info *info, void *arg)
+{
+ ptid_t ptid = * (ptid_t *) arg;
+
+ if ((ptid_equal (info->ptid, ptid)
+ || ptid_equal (minus_one_ptid, ptid)
+ || (ptid_is_pid (ptid)
+ && ptid_get_pid (ptid) == ptid_get_pid (info->ptid)))
+ && is_running (info->ptid)
+ && !is_executing (info->ptid))
+ {
+ struct cleanup *old_chain;
+ struct execution_control_state ecss;
+ struct execution_control_state *ecs = &ecss;
+
+ memset (ecs, 0, sizeof (*ecs));
+
+ old_chain = make_cleanup_restore_current_thread ();
+
+ switch_to_thread (info->ptid);
+
+ /* Go through handle_inferior_event/normal_stop, so we always
+ have consistent output as if the stop event had been
+ reported. */
+ ecs->ptid = info->ptid;
+ ecs->event_thread = find_thread_pid (info->ptid);
+ ecs->ws.kind = TARGET_WAITKIND_STOPPED;
+ ecs->ws.value.sig = TARGET_SIGNAL_0;
+
+ handle_inferior_event (ecs);
+
+ if (!ecs->wait_some_more)
+ {
+ struct thread_info *tp;
+
+ normal_stop ();
+
+ /* Finish off the continuations. The continations
+ themselves are responsible for realising the thread
+ didn't finish what it was supposed to do. */
+ tp = inferior_thread ();
+ do_all_intermediate_continuations_thread (tp);
+ do_all_continuations_thread (tp);
+ }
+
+ do_cleanups (old_chain);
+ }
+
+ return 0;
+}
+
+/* This function is attached as a "thread_stop_requested" observer.
+ Cleanup local state that assumed the PTID was to be resumed, and
+ report the stop to the frontend. */
+
+void
+infrun_thread_stop_requested (ptid_t ptid)
+{
+ struct displaced_step_request *it, *next, *prev = NULL;
+
+ /* PTID was requested to stop. Remove it from the displaced
+ stepping queue, so we don't try to resume it automatically. */
+ for (it = displaced_step_request_queue; it; it = next)
+ {
+ next = it->next;
+
+ if (ptid_equal (it->ptid, ptid)
+ || ptid_equal (minus_one_ptid, ptid)
+ || (ptid_is_pid (ptid)
+ && ptid_get_pid (ptid) == ptid_get_pid (it->ptid)))
+ {
+ if (displaced_step_request_queue == it)
+ displaced_step_request_queue = it->next;
+ else
+ prev->next = it->next;
+
+ xfree (it);
+ }
+ else
+ prev = it;
+ }
+
+ iterate_over_threads (infrun_thread_stop_requested_callback, &ptid);
+}
+
/* Callback for iterate_over_threads. */
static int
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.) */
if (ecs->ws.kind == TARGET_WAITKIND_STOPPED)
- displaced_step_fixup (ecs->ptid, ecs->event_thread->stop_signal);
+ {
+ /* 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, ecs->event_thread->stop_signal);
+
+ /* If we either finished a single-step or hit a breakpoint, but
+ the user wanted this thread to be stopped, pretend we got a
+ SIG0 (generic unsignaled stop). */
+
+ if (ecs->event_thread->stop_requested
+ && ecs->event_thread->stop_signal == TARGET_SIGNAL_TRAP)
+ ecs->event_thread->stop_signal = TARGET_SIGNAL_0;
+ }
stop_pc = regcache_read_pc (get_thread_regcache (ecs->ptid));
SIGTRAP. Some systems (e.g. Windows), and stubs supporting
target extended-remote report it instead of a SIGSTOP
(e.g. gdbserver). We already rely on SIGTRAP being our
- signal, so this is no exception. */
+ signal, so this is no exception.
+
+ Also consider that the attach is complete when we see a
+ TARGET_SIGNAL_0. In non-stop mode, GDB will explicitly tell
+ the target to stop all threads of the inferior, in case the
+ low level attach operation doesn't stop them implicitly. If
+ they weren't stopped implicitly, then the stub will report a
+ TARGET_SIGNAL_0, meaning: stopped for no particular reason
+ other than GDB's request. */
if (stop_soon == STOP_QUIETLY_NO_SIGSTOP
&& (ecs->event_thread->stop_signal == TARGET_SIGNAL_STOP
- || ecs->event_thread->stop_signal == TARGET_SIGNAL_TRAP))
+ || ecs->event_thread->stop_signal == TARGET_SIGNAL_TRAP
+ || ecs->event_thread->stop_signal == TARGET_SIGNAL_0))
{
stop_stepping (ecs);
ecs->event_thread->stop_signal = TARGET_SIGNAL_0;
target_terminal_ours_for_output ();
print_stop_reason (SIGNAL_RECEIVED, ecs->event_thread->stop_signal);
}
- /* Always stop on signals if we're just gaining control of the
- program. */
+ /* Always stop on signals if we're either just gaining control
+ of the program, or the user explicitly requested this thread
+ to remain stopped. */
if (stop_soon != NO_STOP_QUIETLY
+ || ecs->event_thread->stop_requested
|| signal_stop_state (ecs->event_thread->stop_signal))
{
stop_stepping (ecs);
stop_stepping (ecs);
return;
}
-
- /* If we stopped due to an explicit catchpoint, then the
- (see above) call to SOLIB_ADD pulled in any symbols
- from a newly-loaded library, if appropriate.
-
- We do want the inferior to stop, but not where it is
- now, which is in the dynamic linker callback. Rather,
- we would like it stop in the user's program, just after
- the call that caused this catchpoint to trigger. That
- gives the user a more useful vantage from which to
- examine their program's state. */
- else if (what.main_action
- == BPSTAT_WHAT_CHECK_SHLIBS_RESUME_FROM_HOOK)
- {
- /* ??rehrauer: If I could figure out how to get the
- right return PC from here, we could just set a temp
- breakpoint and resume. I'm not sure we can without
- cracking open the dld's shared libraries and sniffing
- their unwind tables and text/data ranges, and that's
- not a terribly portable notion.
-
- Until that time, we must step the inferior out of the
- dld callback, and also out of the dld itself (and any
- code or stubs in libdld.sl, such as "shl_load" and
- friends) until we reach non-dld code. At that point,
- we can stop stepping. */
- bpstat_get_triggered_catchpoints (ecs->event_thread->stop_bpstat,
- &ecs->
- event_thread->
- stepping_through_solib_catchpoints);
- ecs->event_thread->stepping_through_solib_after_catch = 1;
-
- /* Be sure to lift all breakpoints, so the inferior does
- actually step past this point... */
- ecs->event_thread->stepping_over_breakpoint = 1;
- break;
- }
else
{
/* We want to step over this breakpoint, then keep going. */
Reverse (backward) execution. set the step-resume
breakpoint at the start of the function that we just
stepped into (backwards), and continue to there. When we
- get there, we'll need to single-step back to the
- caller. */
+ get there, we'll need to single-step back to the caller. */
if (execution_direction == EXEC_REVERSE)
{
struct symtab_and_line sr_sal;
+
+ if (ecs->stop_func_start == 0
+ && in_solib_dynsym_resolve_code (stop_pc))
+ {
+ /* Stepped into runtime loader dynamic symbol
+ resolution code. Since we're in reverse,
+ we have already backed up through the runtime
+ loader and the dynamic function. This is just
+ the trampoline (jump table).
+
+ Just keep stepping, we'll soon be home.
+ */
+ keep_going (ecs);
+ return;
+ }
+ /* Normal (staticly linked) function call return. */
init_sal (&sr_sal);
sr_sal.pc = ecs->stop_func_start;
insert_step_resume_breakpoint_at_sal (sr_sal, null_frame_id);
return_child_result_value = stop_info;
break;
case SIGNAL_RECEIVED:
- /* Signal received. The signal table tells us to print about
- it. */
+ /* Signal received. The signal table tells us to print about
+ it. */
annotate_signal ();
- ui_out_text (uiout, "\nProgram received signal ");
- annotate_signal_name ();
- if (ui_out_is_mi_like_p (uiout))
- ui_out_field_string
- (uiout, "reason", async_reason_lookup (EXEC_ASYNC_SIGNAL_RECEIVED));
- ui_out_field_string (uiout, "signal-name",
- target_signal_to_name (stop_info));
- annotate_signal_name_end ();
- ui_out_text (uiout, ", ");
- annotate_signal_string ();
- ui_out_field_string (uiout, "signal-meaning",
- target_signal_to_string (stop_info));
- annotate_signal_string_end ();
+
+ if (stop_info == TARGET_SIGNAL_0 && !ui_out_is_mi_like_p (uiout))
+ {
+ struct thread_info *t = inferior_thread ();
+
+ ui_out_text (uiout, "\n[");
+ ui_out_field_string (uiout, "thread-name",
+ target_pid_to_str (t->ptid));
+ ui_out_field_fmt (uiout, "thread-id", "] #%d", t->num);
+ ui_out_text (uiout, " stopped");
+ }
+ else
+ {
+ ui_out_text (uiout, "\nProgram received signal ");
+ annotate_signal_name ();
+ if (ui_out_is_mi_like_p (uiout))
+ ui_out_field_string
+ (uiout, "reason", async_reason_lookup (EXEC_ASYNC_SIGNAL_RECEIVED));
+ ui_out_field_string (uiout, "signal-name",
+ target_signal_to_name (stop_info));
+ annotate_signal_name_end ();
+ ui_out_text (uiout, ", ");
+ annotate_signal_string ();
+ ui_out_field_string (uiout, "signal-meaning",
+ target_signal_to_string (stop_info));
+ annotate_signal_string_end ();
+ }
ui_out_text (uiout, ".\n");
break;
case NO_HISTORY:
int proceed_to_finish;
};
-void
-write_inferior_status_register (struct inferior_status *inf_status, int regno,
- LONGEST val)
-{
- int size = register_size (current_gdbarch, regno);
- void *buf = alloca (size);
- store_signed_integer (buf, size, val);
- regcache_raw_write (inf_status->registers, regno, buf);
-}
-
/* Save all of the information associated with the inferior<==>gdb
connection. INF_STATUS is a pointer to a "struct inferior_status"
(defined in inferior.h). */
&& ptid1.tid == ptid2.tid);
}
+/* Returns true if PTID represents a process. */
+
+int
+ptid_is_pid (ptid_t ptid)
+{
+ if (ptid_equal (minus_one_ptid, ptid))
+ return 0;
+ if (ptid_equal (null_ptid, ptid))
+ return 0;
+
+ return (ptid_get_lwp (ptid) == 0 && ptid_get_tid (ptid) == 0);
+}
+
/* restore_inferior_ptid() will be used by the cleanup machinery
to restore the inferior_ptid value saved in a call to
save_inferior_ptid(). */
show_step_stop_if_no_debug,
&setlist, &showlist);
- add_setshow_boolean_cmd ("can-use-displaced-stepping", class_maintenance,
- &can_use_displaced_stepping, _("\
+ add_setshow_enum_cmd ("displaced-stepping", class_run,
+ can_use_displaced_stepping_enum,
+ &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 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);
+If on, gdb will use displaced stepping to step over breakpoints if it is\n\
+supported by the target architecture. If off, gdb will not use displaced\n\
+stepping to step over breakpoints, even if such is supported by the target\n\
+architecture. If auto (which is the default), gdb will use displaced stepping\n\
+if the target architecture supports it and non-stop mode is active, but will not\n\
+use it in all-stop mode (see help set non-stop)."),
+ NULL,
+ show_can_use_displaced_stepping,
+ &setlist, &showlist);
add_setshow_enum_cmd ("exec-direction", class_run, exec_direction_names,
&exec_direction, _("Set direction of execution.\n\
displaced_step_ptid = null_ptid;
observer_attach_thread_ptid_changed (infrun_thread_ptid_changed);
+ observer_attach_thread_stop_requested (infrun_thread_stop_requested);
}