#include "inline-frame.h"
#include "jit.h"
#include "tracepoint.h"
+#include "continuations.h"
+#include "interps.h"
/* Prototypes for local functions */
void nullify_last_target_wait_ptid (void);
+static void insert_hp_step_resume_breakpoint_at_frame (struct frame_info *);
+
+static void insert_step_resume_breakpoint_at_caller (struct frame_info *);
+
+static void insert_longjmp_resume_breakpoint (struct gdbarch *, CORE_ADDR);
+
/* When set, stop the 'step' command if we enter a function which has
no line number information. The normal behavior is that we step
over such function. */
static unsigned char *signal_print;
static unsigned char *signal_program;
+/* Table of signals that the target may silently handle.
+ This is automatically determined from the flags above,
+ and simply cached here. */
+static unsigned char *signal_pass;
+
#define SET_SIGS(nsigs,sigs,flags) \
do { \
int signum = (nsigs); \
return hw_step;
}
+/* Return a ptid representing the set of threads that we will proceed,
+ in the perspective of the user/frontend. We may actually resume
+ fewer threads at first, e.g., if a thread is stopped at a
+ breakpoint that needs stepping-off, but that should not be visible
+ to the user/frontend, and neither should the frontend/user be
+ allowed to proceed any of the threads that happen to be stopped for
+ internal run control handling, if a previous command wanted them
+ resumed. */
+
+ptid_t
+user_visible_resume_ptid (int step)
+{
+ /* By default, resume all threads of all processes. */
+ ptid_t resume_ptid = RESUME_ALL;
+
+ /* Maybe resume only all threads of the current process. */
+ if (!sched_multi && target_supports_multi_process ())
+ {
+ resume_ptid = pid_to_ptid (ptid_get_pid (inferior_ptid));
+ }
+
+ /* Maybe resume a single thread after all. */
+ if (non_stop)
+ {
+ /* With non-stop mode on, threads are always handled
+ individually. */
+ resume_ptid = inferior_ptid;
+ }
+ else if ((scheduler_mode == schedlock_on)
+ || (scheduler_mode == schedlock_step
+ && (step || singlestep_breakpoints_inserted_p)))
+ {
+ /* User-settable 'scheduler' mode requires solo thread resume. */
+ resume_ptid = inferior_ptid;
+ }
+
+ return resume_ptid;
+}
+
/* Resume the inferior, but allow a QUIT. This is useful if the user
wants to interrupt some lengthy single-stepping operation
(for child processes, the SIGINT goes to the inferior, and so
if (debug_infrun)
fprintf_unfiltered (gdb_stdlog,
"infrun: resume (step=%d, signal=%d), "
- "trap_expected=%d\n",
- step, sig, tp->control.trap_expected);
+ "trap_expected=%d, current thread [%s] at %s\n",
+ step, sig, tp->control.trap_expected,
+ target_pid_to_str (inferior_ptid),
+ paddress (gdbarch, pc));
/* Normally, by the time we reach `resume', the breakpoints are either
removed or inserted, as appropriate. The exception is if we're sitting
else if (step)
step = maybe_software_singlestep (gdbarch, pc);
+ /* Currently, our software single-step implementation leads to different
+ results than hardware single-stepping in one situation: when stepping
+ into delivering a signal which has an associated signal handler,
+ hardware single-step will stop at the first instruction of the handler,
+ while software single-step will simply skip execution of the handler.
+
+ For now, this difference in behavior is accepted since there is no
+ easy way to actually implement single-stepping into a signal handler
+ without kernel support.
+
+ However, there is one scenario where this difference leads to follow-on
+ problems: if we're stepping off a breakpoint by removing all breakpoints
+ and then single-stepping. In this case, the software single-step
+ behavior means that even if there is a *breakpoint* in the signal
+ handler, GDB still would not stop.
+
+ Fortunately, we can at least fix this particular issue. We detect
+ here the case where we are about to deliver a signal while software
+ single-stepping with breakpoints removed. In this situation, we
+ revert the decisions to remove all breakpoints and insert single-
+ step breakpoints, and instead we install a step-resume breakpoint
+ at the current address, deliver the signal without stepping, and
+ once we arrive back at the step-resume breakpoint, actually step
+ over the breakpoint we originally wanted to step over. */
+ if (singlestep_breakpoints_inserted_p
+ && tp->control.trap_expected && sig != TARGET_SIGNAL_0)
+ {
+ /* If we have nested signals or a pending signal is delivered
+ immediately after a handler returns, might might already have
+ a step-resume breakpoint set on the earlier handler. We cannot
+ set another step-resume breakpoint; just continue on until the
+ original breakpoint is hit. */
+ if (tp->control.step_resume_breakpoint == NULL)
+ {
+ insert_hp_step_resume_breakpoint_at_frame (get_current_frame ());
+ tp->step_after_step_resume_breakpoint = 1;
+ }
+
+ remove_single_step_breakpoints ();
+ singlestep_breakpoints_inserted_p = 0;
+
+ insert_breakpoints ();
+ tp->control.trap_expected = 0;
+ }
+
if (should_resume)
{
ptid_t resume_ptid;
/* Decide the set of threads to ask the target to resume. Start
by assuming everything will be resumed, than narrow the set
by applying increasingly restricting conditions. */
-
- /* By default, resume all threads of all processes. */
- resume_ptid = RESUME_ALL;
-
- /* Maybe resume only all threads of the current process. */
- if (!sched_multi && target_supports_multi_process ())
- {
- resume_ptid = pid_to_ptid (ptid_get_pid (inferior_ptid));
- }
+ resume_ptid = user_visible_resume_ptid (step);
/* Maybe resume a single thread after all. */
if (singlestep_breakpoints_inserted_p
breakpoint, not just the one at PC. */
resume_ptid = inferior_ptid;
}
- else if (non_stop)
- {
- /* With non-stop mode on, threads are always handled
- individually. */
- resume_ptid = inferior_ptid;
- }
- else if ((scheduler_mode == schedlock_on)
- || (scheduler_mode == schedlock_step
- && (step || singlestep_breakpoints_inserted_p)))
- {
- /* User-settable 'scheduler' mode requires solo thread resume. */
- resume_ptid = inferior_ptid;
- }
if (gdbarch_cannot_step_breakpoint (gdbarch))
{
happens to apply to another thread. */
tp->suspend.stop_signal = TARGET_SIGNAL_0;
+ /* Advise target which signals may be handled silently. If we have
+ removed breakpoints because we are stepping over one (which can
+ happen only if we are not using displaced stepping), we need to
+ receive all signals to avoid accidentally skipping a breakpoint
+ during execution of a signal handler. */
+ if ((step || singlestep_breakpoints_inserted_p)
+ && tp->control.trap_expected
+ && !use_displaced_stepping (gdbarch))
+ target_pass_signals (0, NULL);
+ else
+ target_pass_signals ((int) TARGET_SIGNAL_LAST, signal_pass);
+
target_resume (resume_ptid, step, sig);
}
/* Switch back to WAIT_PID thread. */
switch_to_thread (wait_ptid);
+ if (debug_infrun)
+ fprintf_unfiltered (gdb_stdlog,
+ "infrun: prepare_to_proceed (step=%d), "
+ "switched to [%s]\n",
+ step, target_pid_to_str (inferior_ptid));
+
/* We return 1 to indicate that there is a breakpoint here,
so we need to step over it before continuing to avoid
hitting it straight away. */
{
/* The target for some reason decided not to resume. */
normal_stop ();
+ if (target_can_async_p ())
+ inferior_event_handler (INF_EXEC_COMPLETE, NULL);
return;
}
+ /* We'll update this if & when we switch to a new thread. */
+ previous_inferior_ptid = inferior_ptid;
+
regcache = get_current_regcache ();
gdbarch = get_regcache_arch (regcache);
aspace = get_regcache_aspace (regcache);
does not support asynchronous execution. */
if (!target_can_async_p ())
{
- wait_for_inferior (0);
+ wait_for_inferior ();
normal_stop ();
}
}
{
struct inferior *inferior;
- init_wait_for_inferior ();
inferior = current_inferior ();
inferior->control.stop_soon = STOP_QUIETLY_REMOTE;
target_open() return to the caller an indication that the target
is currently running and GDB state should be set to the same as
for an async run. */
- wait_for_inferior (0);
+ wait_for_inferior ();
/* Now that the inferior has stopped, do any bookkeeping like
loading shared libraries. We want to do this before normal_stop,
target_last_wait_ptid = minus_one_ptid;
- previous_inferior_ptid = null_ptid;
+ previous_inferior_ptid = inferior_ptid;
init_infwait_state ();
/* Discard any skipped inlined frames. */
struct target_waitstatus ws;
int random_signal;
+ int stop_func_filled_in;
CORE_ADDR stop_func_start;
CORE_ADDR stop_func_end;
char *stop_func_name;
struct execution_control_state *ecs);
static void handle_step_into_function_backward (struct gdbarch *gdbarch,
struct execution_control_state *ecs);
-static void insert_step_resume_breakpoint_at_frame (struct frame_info *);
-static void insert_step_resume_breakpoint_at_caller (struct frame_info *);
-static void insert_step_resume_breakpoint_at_sal (struct gdbarch *,
- struct symtab_and_line ,
- struct frame_id);
-static void insert_longjmp_resume_breakpoint (struct gdbarch *, CORE_ADDR);
static void check_exception_resume (struct execution_control_state *,
struct frame_info *, struct symbol *);
normal_stop ();
- /* Finish off the continuations. The continations
- themselves are responsible for realising the thread
- didn't finish what it was supposed to do. */
+ /* Finish off the continuations. */
tp = inferior_thread ();
- do_all_intermediate_continuations_thread (tp);
- do_all_continuations_thread (tp);
+ do_all_intermediate_continuations_thread (tp, 1);
+ do_all_continuations_thread (tp, 1);
}
do_cleanups (old_chain);
/* Wait for control to return from inferior to debugger.
- If TREAT_EXEC_AS_SIGTRAP is non-zero, then handle EXEC signals
- as if they were SIGTRAP signals. This can be useful during
- the startup sequence on some targets such as HP/UX, where
- we receive an EXEC event instead of the expected SIGTRAP.
-
If inferior gets a signal, we may decide to start it up again
instead of returning. That is why there is a loop in this function.
When this function actually returns it means the inferior
should be left stopped and GDB should read more commands. */
void
-wait_for_inferior (int treat_exec_as_sigtrap)
+wait_for_inferior (void)
{
struct cleanup *old_cleanups;
struct execution_control_state ecss;
if (debug_infrun)
fprintf_unfiltered
- (gdb_stdlog, "infrun: wait_for_inferior (treat_exec_as_sigtrap=%d)\n",
- treat_exec_as_sigtrap);
+ (gdb_stdlog, "infrun: wait_for_inferior ()\n");
old_cleanups =
make_cleanup (delete_step_thread_step_resume_breakpoint_cleanup, NULL);
ecs = &ecss;
memset (ecs, 0, sizeof (*ecs));
- /* We'll update this if & when we switch to a new thread. */
- previous_inferior_ptid = inferior_ptid;
-
while (1)
{
struct cleanup *old_chain;
if (debug_infrun)
print_target_wait_results (waiton_ptid, ecs->ptid, &ecs->ws);
- if (treat_exec_as_sigtrap && ecs->ws.kind == TARGET_WAITKIND_EXECD)
- {
- xfree (ecs->ws.value.execd_pathname);
- ecs->ws.kind = TARGET_WAITKIND_STOPPED;
- ecs->ws.value.sig = TARGET_SIGNAL_TRAP;
- }
-
/* If an error happens while handling the event, propagate GDB's
knowledge of the executing state to the frontend/user running
state. */
struct cleanup *old_chain = make_cleanup (null_cleanup, NULL);
struct cleanup *ts_old_chain;
int was_sync = sync_execution;
+ int cmd_done = 0;
memset (ecs, 0, sizeof (*ecs));
- /* We'll update this if & when we switch to a new thread. */
- previous_inferior_ptid = inferior_ptid;
-
/* We're handling a live event, so make sure we're doing live
debugging. If we're looking at traceframes while the target is
running, we're going to need to get back to that mode after
status mechanism. */
overlay_cache_invalid = 1;
- registers_changed ();
+
+ /* But don't do it if the current thread is already stopped (hence
+ this is either a delayed event that will result in
+ TARGET_WAITKIND_IGNORE, or it's an event for another thread (and
+ we always clear the register and frame caches when the user
+ switches threads anyway). If we didn't do this, a spurious
+ delayed event in all-stop mode would make the user lose the
+ selected frame. */
+ if (non_stop || is_executing (inferior_ptid))
+ registers_changed ();
+
+ make_cleanup_restore_integer (&execution_direction);
+ execution_direction = target_execution_direction ();
if (deprecated_target_wait_hook)
ecs->ptid =
else
ts_old_chain = make_cleanup (finish_thread_state_cleanup, &ecs->ptid);
+ /* Get executed before make_cleanup_restore_current_thread above to apply
+ still for the thread which has thrown the exception. */
+ make_bpstat_clear_actions_cleanup ();
+
/* Now figure out what to do with the result of the result. */
handle_inferior_event (ecs);
&& ecs->event_thread->control.stop_step)
inferior_event_handler (INF_EXEC_CONTINUE, NULL);
else
- inferior_event_handler (INF_EXEC_COMPLETE, NULL);
+ {
+ inferior_event_handler (INF_EXEC_COMPLETE, NULL);
+ cmd_done = 1;
+ }
}
/* No error, don't finish the thread states yet. */
do_cleanups (old_chain);
/* If the inferior was in sync execution mode, and now isn't,
- restore the prompt. */
- if (was_sync && !sync_execution)
+ restore the prompt (a synchronous execution command has finished,
+ and we're ready for input). */
+ if (interpreter_async && was_sync && !sync_execution)
display_gdb_prompt (0);
+
+ if (cmd_done
+ && !was_sync
+ && exec_done_display_p
+ && (ptid_equal (inferior_ptid, null_ptid)
+ || !is_running (inferior_ptid)))
+ printf_unfiltered (_("completed.\n"));
}
/* Record the frame and location we're currently stepping through. */
return 1;
}
+/* Clear the supplied execution_control_state's stop_func_* fields. */
+
+static void
+clear_stop_func (struct execution_control_state *ecs)
+{
+ ecs->stop_func_filled_in = 0;
+ ecs->stop_func_start = 0;
+ ecs->stop_func_end = 0;
+ ecs->stop_func_name = NULL;
+}
+
+/* Lazily fill in the execution_control_state's stop_func_* fields. */
+
+static void
+fill_in_stop_func (struct gdbarch *gdbarch,
+ struct execution_control_state *ecs)
+{
+ if (!ecs->stop_func_filled_in)
+ {
+ /* Don't care about return value; stop_func_start and stop_func_name
+ will both be 0 if it doesn't work. */
+ find_pc_partial_function (stop_pc, &ecs->stop_func_name,
+ &ecs->stop_func_start, &ecs->stop_func_end);
+ ecs->stop_func_start
+ += gdbarch_deprecated_function_start_offset (gdbarch);
+
+ ecs->stop_func_filled_in = 1;
+ }
+}
+
/* Given an execution control state that has been freshly filled in
by an event from the inferior, figure out what it means and take
appropriate action. */
{
struct frame_info *frame;
struct gdbarch *gdbarch;
- int sw_single_step_trap_p = 0;
int stopped_by_watchpoint;
int stepped_after_stopped_by_watchpoint = 0;
struct symtab_and_line stop_pc_sal;
that the user can inspect this again later. */
set_internalvar_integer (lookup_internalvar ("_exitcode"),
(LONGEST) ecs->ws.value.integer);
+
+ /* Also record this in the inferior itself. */
+ current_inferior ()->has_exit_code = 1;
+ current_inferior ()->exit_code = (LONGEST) ecs->ws.value.integer;
+
gdb_flush (gdb_stdout);
target_mourn_inferior ();
singlestep_breakpoints_inserted_p = 0;
singlestep_breakpoints_inserted_p = 0;
}
+ ecs->event_thread->control.trap_expected = 0;
+
/* Note: We do not call context_switch at this point, as the
context is already set up for stepping the original thread. */
switch_to_thread (deferred_step_ptid);
}
else if (singlestep_breakpoints_inserted_p)
{
- sw_single_step_trap_p = 1;
ecs->random_signal = 0;
}
}
int hw_step = 1;
if (!target_have_steppable_watchpoint)
- remove_breakpoints ();
+ {
+ remove_breakpoints ();
+ /* See comment in resume why we need to stop bypassing signals
+ while breakpoints have been removed. */
+ target_pass_signals (0, NULL);
+ }
/* Single step */
hw_step = maybe_software_singlestep (gdbarch, stop_pc);
target_resume (ecs->ptid, hw_step, TARGET_SIGNAL_0);
return;
}
- ecs->stop_func_start = 0;
- ecs->stop_func_end = 0;
- ecs->stop_func_name = 0;
- /* Don't care about return value; stop_func_start and stop_func_name
- will both be 0 if it doesn't work. */
- find_pc_partial_function (stop_pc, &ecs->stop_func_name,
- &ecs->stop_func_start, &ecs->stop_func_end);
- ecs->stop_func_start
- += gdbarch_deprecated_function_start_offset (gdbarch);
+ clear_stop_func (ecs);
ecs->event_thread->stepping_over_breakpoint = 0;
bpstat_clear (&ecs->event_thread->control.stop_bpstat);
ecs->event_thread->control.stop_step = 0;
"infrun: signal arrived while stepping over "
"breakpoint\n");
- insert_step_resume_breakpoint_at_frame (frame);
+ insert_hp_step_resume_breakpoint_at_frame (frame);
ecs->event_thread->step_after_step_resume_breakpoint = 1;
+ /* Reset trap_expected to ensure breakpoints are re-inserted. */
+ ecs->event_thread->control.trap_expected = 0;
keep_going (ecs);
return;
}
"infrun: signal may take us out of "
"single-step range\n");
- insert_step_resume_breakpoint_at_frame (frame);
+ insert_hp_step_resume_breakpoint_at_frame (frame);
+ /* Reset trap_expected to ensure breakpoints are re-inserted. */
+ ecs->event_thread->control.trap_expected = 0;
keep_going (ecs);
return;
}
where we are stepping and step out of the right range. */
break;
+ case BPSTAT_WHAT_STEP_RESUME:
+ if (debug_infrun)
+ fprintf_unfiltered (gdb_stdlog, "infrun: BPSTAT_WHAT_STEP_RESUME\n");
+
+ delete_step_resume_breakpoint (ecs->event_thread);
+ if (ecs->event_thread->control.proceed_to_finish
+ && execution_direction == EXEC_REVERSE)
+ {
+ struct thread_info *tp = ecs->event_thread;
+
+ /* We are finishing a function in reverse, and just hit
+ the step-resume breakpoint at the start address of the
+ function, and we're almost there -- just need to back
+ up by one more single-step, which should take us back
+ to the function call. */
+ tp->control.step_range_start = tp->control.step_range_end = 1;
+ keep_going (ecs);
+ return;
+ }
+ fill_in_stop_func (gdbarch, ecs);
+ if (stop_pc == ecs->stop_func_start
+ && execution_direction == EXEC_REVERSE)
+ {
+ /* We are stepping over a function call in reverse, and
+ just hit the step-resume breakpoint at the start
+ address of the function. Go back to single-stepping,
+ which should take us back to the function call. */
+ ecs->event_thread->stepping_over_breakpoint = 1;
+ keep_going (ecs);
+ return;
+ }
+ break;
+
case BPSTAT_WHAT_STOP_NOISY:
if (debug_infrun)
fprintf_unfiltered (gdb_stdlog, "infrun: BPSTAT_WHAT_STOP_NOISY\n");
stop_stepping (ecs);
return;
- case BPSTAT_WHAT_STEP_RESUME:
+ case BPSTAT_WHAT_HP_STEP_RESUME:
if (debug_infrun)
- fprintf_unfiltered (gdb_stdlog, "infrun: BPSTAT_WHAT_STEP_RESUME\n");
+ fprintf_unfiltered (gdb_stdlog, "infrun: BPSTAT_WHAT_HP_STEP_RESUME\n");
delete_step_resume_breakpoint (ecs->event_thread);
if (ecs->event_thread->step_after_step_resume_breakpoint)
keep_going (ecs);
return;
}
- if (stop_pc == ecs->stop_func_start
- && execution_direction == EXEC_REVERSE)
- {
- /* We are stepping over a function call in reverse, and
- just hit the step-resume breakpoint at the start
- address of the function. Go back to single-stepping,
- which should take us back to the function call. */
- ecs->event_thread->stepping_over_breakpoint = 1;
- keep_going (ecs);
- return;
- }
break;
case BPSTAT_WHAT_KEEP_CHECKING:
a dangling pointer. */
frame = get_current_frame ();
gdbarch = get_frame_arch (frame);
+ fill_in_stop_func (gdbarch, ecs);
/* If stepping through a line, keep going if still within it.
struct symtab *s;
struct symtab_and_line stop_func_sal, sr_sal;
+ fill_in_stop_func (gdbarch, ecs);
+
s = find_pc_symtab (stop_pc);
if (s && s->language != language_asm)
ecs->stop_func_start = gdbarch_skip_prologue (gdbarch,
struct symtab *s;
struct symtab_and_line stop_func_sal;
+ fill_in_stop_func (gdbarch, ecs);
+
s = find_pc_symtab (stop_pc);
if (s && s->language != language_asm)
ecs->stop_func_start = gdbarch_skip_prologue (gdbarch,
This is used to both functions and to skip over code. */
static void
-insert_step_resume_breakpoint_at_sal (struct gdbarch *gdbarch,
- struct symtab_and_line sr_sal,
- struct frame_id sr_id)
+insert_step_resume_breakpoint_at_sal_1 (struct gdbarch *gdbarch,
+ struct symtab_and_line sr_sal,
+ struct frame_id sr_id,
+ enum bptype sr_type)
{
/* There should never be more than one step-resume or longjmp-resume
breakpoint per thread, so we should never be setting a new
step_resume_breakpoint when one is already active. */
gdb_assert (inferior_thread ()->control.step_resume_breakpoint == NULL);
+ gdb_assert (sr_type == bp_step_resume || sr_type == bp_hp_step_resume);
if (debug_infrun)
fprintf_unfiltered (gdb_stdlog,
paddress (gdbarch, sr_sal.pc));
inferior_thread ()->control.step_resume_breakpoint
- = set_momentary_breakpoint (gdbarch, sr_sal, sr_id, bp_step_resume);
+ = set_momentary_breakpoint (gdbarch, sr_sal, sr_id, sr_type);
+}
+
+void
+insert_step_resume_breakpoint_at_sal (struct gdbarch *gdbarch,
+ struct symtab_and_line sr_sal,
+ struct frame_id sr_id)
+{
+ insert_step_resume_breakpoint_at_sal_1 (gdbarch,
+ sr_sal, sr_id,
+ bp_step_resume);
}
-/* Insert a "step-resume breakpoint" at RETURN_FRAME.pc. This is used
- to skip a potential signal handler.
+/* Insert a "high-priority step-resume breakpoint" at RETURN_FRAME.pc.
+ This is used to skip a potential signal handler.
This is called with the interrupted function's frame. The signal
handler, when it returns, will resume the interrupted function at
RETURN_FRAME.pc. */
static void
-insert_step_resume_breakpoint_at_frame (struct frame_info *return_frame)
+insert_hp_step_resume_breakpoint_at_frame (struct frame_info *return_frame)
{
struct symtab_and_line sr_sal;
struct gdbarch *gdbarch;
sr_sal.section = find_pc_overlay (sr_sal.pc);
sr_sal.pspace = get_frame_program_space (return_frame);
- insert_step_resume_breakpoint_at_sal (gdbarch, sr_sal,
- get_stack_frame_id (return_frame));
+ insert_step_resume_breakpoint_at_sal_1 (gdbarch, sr_sal,
+ get_stack_frame_id (return_frame),
+ bp_hp_step_resume);
}
-/* Similar to insert_step_resume_breakpoint_at_frame, except
- but a breakpoint at the previous frame's PC. This is used to
- skip a function after stepping into it (for "next" or if the called
- function has no debugging information).
+/* Insert a "step-resume breakpoint" at the previous frame's PC. This
+ is used to skip a function after stepping into it (for "next" or if
+ the called function has no debugging information).
The current function has almost always been reached by single
stepping a call or return instruction. NEXT_FRAME belongs to the
resume address.
This is a separate function rather than reusing
- insert_step_resume_breakpoint_at_frame in order to avoid
+ insert_hp_step_resume_breakpoint_at_frame in order to avoid
get_prev_frame, which may stop prematurely (see the implementation
of frame_unwind_caller_id for an example). */
{
if ((!inferior_thread ()->step_multi
|| !inferior_thread ()->control.stop_step)
- && ui_out_is_mi_like_p (uiout))
- ui_out_field_string (uiout, "reason",
+ && ui_out_is_mi_like_p (current_uiout))
+ ui_out_field_string (current_uiout, "reason",
async_reason_lookup (EXEC_ASYNC_END_STEPPING_RANGE));
}
static void
print_signal_exited_reason (enum target_signal siggnal)
{
+ struct ui_out *uiout = current_uiout;
+
annotate_signalled ();
if (ui_out_is_mi_like_p (uiout))
ui_out_field_string
{
struct inferior *inf = current_inferior ();
const char *pidstr = target_pid_to_str (pid_to_ptid (inf->pid));
+ struct ui_out *uiout = current_uiout;
annotate_exited (exitstatus);
if (exitstatus)
static void
print_signal_received_reason (enum target_signal siggnal)
{
+ struct ui_out *uiout = current_uiout;
+
annotate_signal ();
if (siggnal == TARGET_SIGNAL_0 && !ui_out_is_mi_like_p (uiout))
static void
print_no_history_reason (void)
{
- ui_out_text (uiout, "\nNo more reverse-execution history.\n");
+ ui_out_text (current_uiout, "\nNo more reverse-execution history.\n");
}
/* Here to return control to GDB when the inferior stops for real.
goto done;
target_terminal_ours ();
+ async_enable_stdin ();
/* Set the current source location. This will also happen if we
display the frame below, but the current SAL will be incorrect
/* Save the function value return registers, if we care.
We might be about to restore their previous contents. */
- if (inferior_thread ()->control.proceed_to_finish)
+ if (inferior_thread ()->control.proceed_to_finish
+ && execution_direction != EXEC_REVERSE)
{
/* This should not be necessary. */
if (stop_registers)
return signal_program[signo];
}
+static void
+signal_cache_update (int signo)
+{
+ if (signo == -1)
+ {
+ for (signo = 0; signo < (int) TARGET_SIGNAL_LAST; signo++)
+ signal_cache_update (signo);
+
+ return;
+ }
+
+ signal_pass[signo] = (signal_stop[signo] == 0
+ && signal_print[signo] == 0
+ && signal_program[signo] == 1);
+}
+
int
signal_stop_update (int signo, int state)
{
int ret = signal_stop[signo];
signal_stop[signo] = state;
+ signal_cache_update (signo);
return ret;
}
int ret = signal_print[signo];
signal_print[signo] = state;
+ signal_cache_update (signo);
return ret;
}
int ret = signal_program[signo];
signal_program[signo] = state;
+ signal_cache_update (signo);
return ret;
}
for (signum = 0; signum < nsigs; signum++)
if (sigs[signum])
{
- target_notice_signals (inferior_ptid);
+ signal_cache_update (-1);
+ target_pass_signals ((int) TARGET_SIGNAL_LAST, signal_pass);
if (from_tty)
{
"to change these tables.\n"));
}
+/* Check if it makes sense to read $_siginfo from the current thread
+ at this point. If not, throw an error. */
+
+static void
+validate_siginfo_access (void)
+{
+ /* No current inferior, no siginfo. */
+ if (ptid_equal (inferior_ptid, null_ptid))
+ error (_("No thread selected."));
+
+ /* Don't try to read from a dead thread. */
+ if (is_exited (inferior_ptid))
+ error (_("The current thread has terminated"));
+
+ /* ... or from a spinning thread. */
+ if (is_running (inferior_ptid))
+ error (_("Selected thread is running."));
+}
+
/* The $_siginfo convenience variable is a bit special. We don't know
for sure the type of the value until we actually have a chance to
fetch the data. The type can change depending on gdbarch, so it is
{
LONGEST transferred;
+ validate_siginfo_access ();
+
transferred =
target_read (¤t_target, TARGET_OBJECT_SIGNAL_INFO,
NULL,
{
LONGEST transferred;
+ validate_siginfo_access ();
+
transferred = target_write (¤t_target,
TARGET_OBJECT_SIGNAL_INFO,
NULL,
error (_("Unable to write siginfo"));
}
-static struct lval_funcs siginfo_value_funcs =
+static const struct lval_funcs siginfo_value_funcs =
{
siginfo_value_read,
siginfo_value_write
return 1;
}
-/* Oft used ptids */
-ptid_t null_ptid;
-ptid_t minus_one_ptid;
-
-/* Create a ptid given the necessary PID, LWP, and TID components. */
-
-ptid_t
-ptid_build (int pid, long lwp, long tid)
-{
- ptid_t ptid;
-
- ptid.pid = pid;
- ptid.lwp = lwp;
- ptid.tid = tid;
- return ptid;
-}
-
-/* Create a ptid from just a pid. */
-
-ptid_t
-pid_to_ptid (int pid)
-{
- return ptid_build (pid, 0, 0);
-}
-
-/* Fetch the pid (process id) component from a ptid. */
-
-int
-ptid_get_pid (ptid_t ptid)
-{
- return ptid.pid;
-}
-
-/* Fetch the lwp (lightweight process) component from a ptid. */
-
-long
-ptid_get_lwp (ptid_t ptid)
-{
- return ptid.lwp;
-}
-
-/* Fetch the tid (thread id) component from a ptid. */
-
-long
-ptid_get_tid (ptid_t ptid)
-{
- return ptid.tid;
-}
-
-/* ptid_equal() is used to test equality of two ptids. */
-
-int
-ptid_equal (ptid_t ptid1, ptid_t ptid2)
-{
- return (ptid1.pid == ptid2.pid && ptid1.lwp == ptid2.lwp
- && 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);
-}
-
int
ptid_match (ptid_t ptid, ptid_t filter)
{
- /* Since both parameters have the same type, prevent easy mistakes
- from happening. */
- gdb_assert (!ptid_equal (ptid, minus_one_ptid)
- && !ptid_equal (ptid, null_ptid));
-
if (ptid_equal (filter, minus_one_ptid))
return 1;
if (ptid_is_pid (filter)
Set exec-direction / show exec-direction commands
(returns error unless target implements to_set_exec_direction method). */
-enum exec_direction_kind execution_direction = EXEC_FORWARD;
+int execution_direction = EXEC_FORWARD;
static const char exec_forward[] = "forward";
static const char exec_reverse[] = "reverse";
static const char *exec_direction = exec_forward;
case EXEC_REVERSE:
fprintf_filtered (out, _("Reverse.\n"));
break;
- case EXEC_ERROR:
default:
- fprintf_filtered (out, _("Forward (target `%s' does not "
- "support exec-direction).\n"),
- target_shortname);
- break;
+ internal_error (__FILE__, __LINE__,
+ _("bogus execution_direction value: %d"),
+ (int) execution_direction);
}
}
xmalloc (sizeof (signal_print[0]) * numsigs);
signal_program = (unsigned char *)
xmalloc (sizeof (signal_program[0]) * numsigs);
+ signal_pass = (unsigned char *)
+ xmalloc (sizeof (signal_program[0]) * numsigs);
for (i = 0; i < numsigs; i++)
{
signal_stop[i] = 1;
signal_stop[TARGET_SIGNAL_CANCEL] = 0;
signal_print[TARGET_SIGNAL_CANCEL] = 0;
+ /* Update cached state. */
+ signal_cache_update (-1);
+
add_setshow_zinteger_cmd ("stop-on-solib-events", class_support,
&stop_on_solib_events, _("\
Set stopping for shared library events."), _("\
NULL, NULL, &setlist, &showlist);
/* 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;