#include "mi/mi-common.h"
#include "event-top.h"
#include "record.h"
+#include "record-full.h"
#include "inline-frame.h"
#include "jit.h"
#include "tracepoint.h"
static ptid_t previous_inferior_ptid;
-/* Default behavior is to detach newly forked processes (legacy). */
-int detach_fork = 1;
+/* If set (default for legacy reasons), when following a fork, GDB
+ will detach from one of the fork branches, child or parent.
+ Exactly which branch is detached depends on 'set follow-fork-mode'
+ setting. */
+
+static int detach_fork = 1;
int debug_displaced = 0;
static void
"this platform."));
}
+/* User interface for non-stop mode. */
-/* If the program uses ELF-style shared libraries, then calls to
- functions in shared libraries go through stubs, which live in a
- table called the PLT (Procedure Linkage Table). The first time the
- function is called, the stub sends control to the dynamic linker,
- which looks up the function's real address, patches the stub so
- that future calls will go directly to the function, and then passes
- control to the function.
-
- If we are stepping at the source level, we don't want to see any of
- this --- we just want to skip over the stub and the dynamic linker.
- The simple approach is to single-step until control leaves the
- dynamic linker.
-
- However, on some systems (e.g., Red Hat's 5.2 distribution) the
- dynamic linker calls functions in the shared C library, so you
- can't tell from the PC alone whether the dynamic linker is still
- running. In this case, we use a step-resume breakpoint to get us
- past the dynamic linker, as if we were using "next" to step over a
- function call.
-
- in_solib_dynsym_resolve_code() says whether we're in the dynamic
- linker code or not. Normally, this means we single-step. However,
- if SKIP_SOLIB_RESOLVER then returns non-zero, then its value is an
- address where we can place a step-resume breakpoint to get past the
- linker's symbol resolution function.
-
- in_solib_dynsym_resolve_code() can generally be implemented in a
- pretty portable way, by comparing the PC against the address ranges
- of the dynamic linker's sections.
-
- SKIP_SOLIB_RESOLVER is generally going to be system-specific, since
- it depends on internal details of the dynamic linker. It's usually
- not too hard to figure out where to put a breakpoint, but it
- certainly isn't portable. SKIP_SOLIB_RESOLVER should do plenty of
- sanity checking. If it can't figure things out, returning zero and
- getting the (possibly confusing) stepping behavior is better than
- signalling an error, which will obscure the change in the
- inferior's state. */
-
-/* This function returns TRUE if pc is the address of an instruction
- that lies within the dynamic linker (such as the event hook, or the
- dld itself).
-
- This function must be used only when a dynamic linker event has
- been caught, and the inferior is being stepped out of the hook, or
- undefined results are guaranteed. */
-
-#ifndef SOLIB_IN_DYNAMIC_LINKER
-#define SOLIB_IN_DYNAMIC_LINKER(pid,pc) 0
-#endif
+int non_stop = 0;
+static int non_stop_1 = 0;
+
+static void
+set_non_stop (char *args, int from_tty,
+ struct cmd_list_element *c)
+{
+ if (target_has_execution)
+ {
+ non_stop_1 = non_stop;
+ error (_("Cannot change this setting while the inferior is running."));
+ }
+
+ non_stop = non_stop_1;
+}
+
+static void
+show_non_stop (struct ui_file *file, int from_tty,
+ struct cmd_list_element *c, const char *value)
+{
+ fprintf_filtered (file,
+ _("Controlling the inferior in non-stop mode is %s.\n"),
+ value);
+}
/* "Observer mode" is somewhat like a more extreme version of
non-stop, in which all GDB operations that might affect the
target's execution have been disabled. */
-static int non_stop_1 = 0;
-
int observer_mode = 0;
static int observer_mode_1 = 0;
set_observer_mode (char *args, int from_tty,
struct cmd_list_element *c)
{
- extern int pagination_enabled;
-
if (target_has_execution)
{
observer_mode_1 = observer_mode;
/* Nonzero if we want to give control to the user when we're notified
of shared library events by the dynamic linker. */
int stop_on_solib_events;
+
+/* Enable or disable optional shared library event breakpoints
+ as appropriate when the above flag is changed. */
+
+static void
+set_stop_on_solib_events (char *args, int from_tty, struct cmd_list_element *c)
+{
+ update_solib_breakpoints ();
+}
+
static void
show_stop_on_solib_events (struct ui_file *file, int from_tty,
struct cmd_list_element *c, const char *value)
/* Tell the target to do whatever is necessary to follow
either parent or child. */
- if (target_follow_fork (follow_child))
+ if (target_follow_fork (follow_child, detach_fork))
{
/* Target refused to follow, or there's some other reason
we shouldn't resume. */
}
}
-/* Enum strings for "set|show displaced-stepping". */
+/* Enum strings for "set|show follow-exec-mode". */
static const char follow_exec_mode_new[] = "new";
static const char follow_exec_mode_same[] = "same";
registers. */
target_find_description ();
-#ifdef SOLIB_CREATE_INFERIOR_HOOK
- SOLIB_CREATE_INFERIOR_HOOK (PIDGET (inferior_ptid));
-#else
solib_create_inferior_hook (0);
-#endif
jit_inferior_created_hook ();
displaced_step_prepare (ptid_t ptid)
{
struct cleanup *old_cleanups, *ignore_cleanups;
+ struct thread_info *tp = find_thread_ptid (ptid);
struct regcache *regcache = get_thread_regcache (ptid);
struct gdbarch *gdbarch = get_regcache_arch (regcache);
CORE_ADDR original, copy;
support displaced stepping. */
gdb_assert (gdbarch_displaced_step_copy_insn_p (gdbarch));
+ /* Disable range stepping while executing in the scratch pad. We
+ want a single-step even if executing the displaced instruction in
+ the scratch buffer lands within the stepping range (e.g., a
+ jump/branch). */
+ tp->control.may_range_step = 0;
+
/* We have to displaced step one thread at a time, as we only have
access to a single scratch space per inferior. */
a command like `return' or `jump' to continue execution."));
}
+ /* If we have a breakpoint to step over, make sure to do a single
+ step only. Same if we have software watchpoints. */
+ if (tp->control.trap_expected || bpstat_should_step ())
+ tp->control.may_range_step = 0;
+
/* If enabled, step over breakpoints by executing a copy of the
instruction at a different address.
displaced_step_dump_bytes (gdb_stdlog, buf, sizeof (buf));
}
+ if (tp->control.may_range_step)
+ {
+ /* If we're resuming a thread with the PC out of the step
+ range, then we're doing some nested/finer run control
+ operation, like stepping the thread out of the dynamic
+ linker or the displaced stepping scratch pad. We
+ shouldn't have allowed a range step then. */
+ gdb_assert (pc_in_thread_step_range (pc, tp));
+ }
+
/* Install inferior's terminal modes. */
target_terminal_inferior ();
tp->control.trap_expected = 0;
tp->control.step_range_start = 0;
tp->control.step_range_end = 0;
+ tp->control.may_range_step = 0;
tp->control.step_frame_id = null_frame_id;
tp->control.step_stack_frame_id = null_frame_id;
tp->control.step_over_calls = STEP_OVER_UNDEBUGGABLE;
if (software_breakpoint_inserted_here_p (aspace, breakpoint_pc)
|| (non_stop && moribund_breakpoint_here_p (aspace, breakpoint_pc)))
{
- struct cleanup *old_cleanups = NULL;
+ struct cleanup *old_cleanups = make_cleanup (null_cleanup, NULL);
if (RECORD_IS_USED)
- old_cleanups = record_gdb_operation_disable_set ();
+ record_full_gdb_operation_disable_set ();
/* When using hardware single-step, a SIGTRAP is reported for both
a completed single-step and a software breakpoint. Need to
|| ecs->event_thread->prev_pc == breakpoint_pc)
regcache_write_pc (regcache, breakpoint_pc);
- if (RECORD_IS_USED)
- do_cleanups (old_cleanups);
+ do_cleanups (old_cleanups);
}
}
= bpstat_stop_status (get_regcache_aspace (regcache),
stop_pc, ecs->ptid, &ecs->ws);
- sval = bpstat_explains_signal (ecs->event_thread->control.stop_bpstat);
+ sval = bpstat_explains_signal (ecs->event_thread->control.stop_bpstat,
+ GDB_SIGNAL_TRAP);
ecs->random_signal = sval == BPSTAT_SIGNAL_NO;
if (!ecs->random_signal)
/* If it's a new thread, add it to the thread database. */
if (ecs->event_thread == NULL)
ecs->event_thread = add_thread (ecs->ptid);
+
+ /* Disable range stepping. If the next step request could use a
+ range, this will be end up re-enabled then. */
+ ecs->event_thread->control.may_range_step = 0;
}
/* Dependent on valid ECS->EVENT_THREAD. */
stop_pc, ecs->ptid, &ecs->ws);
sval
- = bpstat_explains_signal (ecs->event_thread->control.stop_bpstat);
+ = bpstat_explains_signal (ecs->event_thread->control.stop_bpstat,
+ GDB_SIGNAL_TRAP);
ecs->random_signal = sval == BPSTAT_SIGNAL_NO;
if (!ecs->random_signal)
= bpstat_stop_status (get_regcache_aspace (get_current_regcache ()),
stop_pc, ecs->ptid, &ecs->ws);
ecs->random_signal
- = (bpstat_explains_signal (ecs->event_thread->control.stop_bpstat)
+ = (bpstat_explains_signal (ecs->event_thread->control.stop_bpstat,
+ GDB_SIGNAL_TRAP)
== BPSTAT_SIGNAL_NO);
/* Note that this may be referenced from inside
if (debug_infrun
&& ecs->event_thread->suspend.stop_signal == GDB_SIGNAL_TRAP
- && (bpstat_explains_signal (ecs->event_thread->control.stop_bpstat)
+ && (bpstat_explains_signal (ecs->event_thread->control.stop_bpstat,
+ GDB_SIGNAL_TRAP)
== BPSTAT_SIGNAL_NO)
&& stopped_by_watchpoint)
fprintf_unfiltered (gdb_stdlog,
if (ecs->event_thread->suspend.stop_signal == GDB_SIGNAL_TRAP)
ecs->random_signal
- = !((bpstat_explains_signal (ecs->event_thread->control.stop_bpstat)
+ = !((bpstat_explains_signal (ecs->event_thread->control.stop_bpstat,
+ GDB_SIGNAL_TRAP)
!= BPSTAT_SIGNAL_NO)
|| stopped_by_watchpoint
|| ecs->event_thread->control.trap_expected
{
enum bpstat_signal_value sval;
- sval = bpstat_explains_signal (ecs->event_thread->control.stop_bpstat);
+ sval = bpstat_explains_signal (ecs->event_thread->control.stop_bpstat,
+ ecs->event_thread->suspend.stop_signal);
ecs->random_signal = (sval == BPSTAT_SIGNAL_NO);
if (sval == BPSTAT_SIGNAL_HIDE)
if (ecs->event_thread->control.step_range_end != 0
&& ecs->event_thread->suspend.stop_signal != GDB_SIGNAL_0
- && (ecs->event_thread->control.step_range_start <= stop_pc
- && stop_pc < ecs->event_thread->control.step_range_end)
+ && pc_in_thread_step_range (stop_pc, ecs->event_thread)
&& frame_id_eq (get_stack_frame_id (frame),
ecs->event_thread->control.step_stack_frame_id)
&& ecs->event_thread->control.step_resume_breakpoint == NULL)
through a function epilogue and therefore must detect when
the current-frame changes in the middle of a line. */
- if (stop_pc >= ecs->event_thread->control.step_range_start
- && stop_pc < ecs->event_thread->control.step_range_end
+ if (pc_in_thread_step_range (stop_pc, ecs->event_thread)
&& (execution_direction != EXEC_REVERSE
|| frame_id_eq (get_frame_id (frame),
ecs->event_thread->control.step_frame_id)))
paddress (gdbarch, ecs->event_thread->control.step_range_start),
paddress (gdbarch, ecs->event_thread->control.step_range_end));
+ /* Tentatively re-enable range stepping; `resume' disables it if
+ necessary (e.g., if we're stepping over a breakpoint or we
+ have software watchpoints). */
+ ecs->event_thread->control.may_range_step = 1;
+
/* When stepping backward, stop at beginning of line range
(unless it's the function entry point, in which case
keep going back to the call point). */
or stepped back out of a signal handler to the first instruction
of the function. Just keep going, which will single-step back
to the caller. */
- if (ecs->stop_func_start != stop_pc)
+ if (ecs->stop_func_start != stop_pc && ecs->stop_func_start != 0)
{
struct symtab_and_line sr_sal;
ecs->event_thread->control.step_range_start = stop_pc_sal.pc;
ecs->event_thread->control.step_range_end = stop_pc_sal.end;
+ ecs->event_thread->control.may_range_step = 1;
set_step_info (frame, stop_pc_sal);
if (debug_infrun)
LOCATION: Print only location
SRC_AND_LOC: Print location and source line. */
if (do_frame_printing)
- print_stack_frame (get_selected_frame (NULL), 0, source_flag);
+ print_stack_frame (get_selected_frame (NULL), 0, source_flag, 1);
/* Display the auto-display expressions. */
do_displays ();
static VEC (char_ptr) *
handle_completer (struct cmd_list_element *ignore,
- char *text, char *word)
+ const char *text, const char *word)
{
VEC (char_ptr) *vec_signals, *vec_keywords, *return_val;
static const char * const keywords[] =
}
}
-/* User interface for non-stop mode. */
-
-int non_stop = 0;
-
-static void
-set_non_stop (char *args, int from_tty,
- struct cmd_list_element *c)
-{
- if (target_has_execution)
- {
- non_stop_1 = non_stop;
- error (_("Cannot change this setting while the inferior is running."));
- }
-
- non_stop = non_stop_1;
-}
-
-static void
-show_non_stop (struct ui_file *file, int from_tty,
- struct cmd_list_element *c, const char *value)
-{
- fprintf_filtered (file,
- _("Controlling the inferior in non-stop mode is %s.\n"),
- value);
-}
-
static void
show_schedule_multiple (struct ui_file *file, int from_tty,
struct cmd_list_element *c, const char *value)
If nonzero, gdb will give control to the user when the dynamic linker\n\
notifies gdb of shared library events. The most common event of interest\n\
to the user would be loading/unloading of a new library."),
- NULL,
+ set_stop_on_solib_events,
show_stop_on_solib_events,
&setlist, &showlist);