#include "gdb_wait.h"
#include "gdbcore.h"
#include "gdbcmd.h"
+#include "cli/cli-script.h"
#include "target.h"
#include "gdbthread.h"
#include "annotate.h"
#include <signal.h>
#include "inf-loop.h"
#include "regcache.h"
+#include "value.h"
/* Prototypes for local functions */
static int may_follow_exec = MAY_FOLLOW_EXEC;
-/* resume and wait_for_inferior use this to ensure that when
- stepping over a hit breakpoint in a threaded application
- only the thread that hit the breakpoint is stepped and the
- other threads don't continue. This prevents having another
- thread run past the breakpoint while it is temporarily
- removed.
-
- This is not thread-specific, so it isn't saved as part of
- the infrun state.
-
- Versions of gdb which don't use the "step == this thread steps
- and others continue" model but instead use the "step == this
- thread steps and others wait" shouldn't do this. */
-
-static int thread_step_needed = 0;
-
-/* This is true if thread_step_needed should actually be used. At
- present this is only true for HP-UX native. */
-
-#ifndef USE_THREAD_STEP_NEEDED
-#define USE_THREAD_STEP_NEEDED (0)
-#endif
-
-static int use_thread_step_needed = USE_THREAD_STEP_NEEDED;
-
/* GET_LONGJMP_TARGET returns the PC at which longjmp() will resume the
program. It needs to examine the jmp_buf argument and extract the PC
from it. The return value is non-zero on success, zero otherwise. */
#endif
-/* Some machines have trampoline code that sits between function callers
- and the actual functions themselves. If this machine doesn't have
- such things, disable their processing. */
-
-#ifndef SKIP_TRAMPOLINE_CODE
-#define SKIP_TRAMPOLINE_CODE(pc) 0
-#endif
-
/* Dynamic function trampolines are similar to solib trampolines in that they
are between the caller and the callee. The difference is that when you
enter a dynamic trampoline, you can't determine the callee's address. Some
#define SKIP_SOLIB_RESOLVER(pc) 0
#endif
-/* For SVR4 shared libraries, each call goes through a small piece of
- trampoline code in the ".plt" section. IN_SOLIB_CALL_TRAMPOLINE evaluates
- to nonzero if we are current stopped in one of these. */
-
-#ifndef IN_SOLIB_CALL_TRAMPOLINE
-#define IN_SOLIB_CALL_TRAMPOLINE(pc,name) 0
-#endif
-
/* In some shared library schemes, the return path from a shared library
call may need to go through a trampoline too. */
struct cleanup *old_cleanups = make_cleanup (resume_cleanups, 0);
QUIT;
-#ifdef CANNOT_STEP_BREAKPOINT
- /* 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 && breakpoints_inserted && breakpoint_here_p (read_pc ()))
- step = 0;
-#endif
+ /* FIXME: calling breakpoint_here_p (read_pc ()) three times! */
+
/* Some targets (e.g. Solaris x86) have a kernel bug when stepping
over an instruction that causes a page fault without triggering
{
ptid_t resume_ptid;
- if (use_thread_step_needed && thread_step_needed)
+ resume_ptid = RESUME_ALL; /* Default */
+
+ if ((step || singlestep_breakpoints_inserted_p) &&
+ !breakpoints_inserted && breakpoint_here_p (read_pc ()))
{
- /* We stopped on a BPT instruction;
- don't continue other threads and
- just step this thread. */
- thread_step_needed = 0;
+ /* Stepping past a breakpoint without inserting breakpoints.
+ Make sure only the current thread gets to step, so that
+ other threads don't sneak past breakpoints while they are
+ not inserted. */
- if (!breakpoint_here_p (read_pc ()))
- {
- /* Breakpoint deleted: ok to do regular resume
- where all the threads either step or continue. */
- resume_ptid = RESUME_ALL;
- }
- else
- {
- if (!step)
- {
- warning ("Internal error, changing continue to step.");
- remove_breakpoints ();
- breakpoints_inserted = 0;
- trap_expected = 1;
- step = 1;
- }
- resume_ptid = inferior_ptid;
- }
+ resume_ptid = inferior_ptid;
}
- else
+
+ if ((scheduler_mode == schedlock_on) ||
+ (scheduler_mode == schedlock_step &&
+ (step || singlestep_breakpoints_inserted_p)))
{
- /* Vanilla resume. */
- if ((scheduler_mode == schedlock_on) ||
- (scheduler_mode == schedlock_step && step != 0))
+ /* User-settable 'scheduler' mode requires solo thread resume. */
resume_ptid = inferior_ptid;
- else
- resume_ptid = RESUME_ALL;
}
+
+#ifdef CANNOT_STEP_BREAKPOINT
+ /* 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 && breakpoints_inserted && breakpoint_here_p (read_pc ()))
+ step = 0;
+#endif
target_resume (resume_ptid, step, sig);
}
else
{
write_pc (addr);
-
- /* New address; we don't need to single-step a thread
- over a breakpoint we just hit, 'cause we aren't
- continuing from there.
-
- It's not worth worrying about the case where a user
- asks for a "jump" at the current PC--if they get the
- hiccup of re-hiting a hit breakpoint, what else do
- they expect? */
- thread_step_needed = 0;
}
#ifdef PREPARE_TO_PROCEED
if (PREPARE_TO_PROCEED (1) && breakpoint_here_p (read_pc ()))
{
oneproc = 1;
- thread_step_needed = 1;
}
#endif /* PREPARE_TO_PROCEED */
/* Fill in with reasonable starting values. */
init_execution_control_state (ecs);
- thread_step_needed = 0;
-
/* We'll update this if & when we switch to a new thread. */
previous_inferior_ptid = inferior_ptid;
/* Fill in with reasonable starting values. */
init_execution_control_state (async_ecs);
- thread_step_needed = 0;
-
/* We'll update this if & when we switch to a new thread. */
previous_inferior_ptid = inferior_ptid;
/* Fall thru to the normal_state case. */
case infwait_normal_state:
- /* Since we've done a wait, we have a new event. Don't
- carry over any expectations about needing to step over a
- breakpoint. */
- thread_step_needed = 0;
-
/* See comments where a TARGET_WAITKIND_SYSCALL_RETURN event
is serviced in this loop, below. */
if (ecs->enable_hw_watchpoints_after_wait)
remove_breakpoints ();
/* Check for any newly added shared libraries if we're
- supposed to be adding them automatically. */
- if (auto_solib_add)
- {
- /* Switch terminal for any messages produced by
- breakpoint_re_set. */
- target_terminal_ours_for_output ();
- SOLIB_ADD (NULL, 0, NULL);
- target_terminal_inferior ();
- }
+ supposed to be adding them automatically. Switch
+ terminal for any messages produced by
+ breakpoint_re_set. */
+ target_terminal_ours_for_output ();
+ SOLIB_ADD (NULL, 0, NULL, auto_solib_add);
+ target_terminal_inferior ();
/* Reinsert breakpoints and continue. */
if (breakpoints_inserted)
stop_pc = read_pc_pid (ecs->ptid);
ecs->saved_inferior_ptid = inferior_ptid;
inferior_ptid = ecs->ptid;
- stop_bpstat = bpstat_stop_status (&stop_pc, currently_stepping (ecs));
+ /* The second argument of bpstat_stop_status is meant to help
+ distinguish between a breakpoint trap and a singlestep trap.
+ This is only important on targets where DECR_PC_AFTER_BREAK
+ is non-zero. The prev_pc test is meant to distinguish between
+ singlestepping a trap instruction, and singlestepping thru a
+ jump to the instruction following a trap instruction. */
+
+ stop_bpstat = bpstat_stop_status (&stop_pc,
+ currently_stepping (ecs) &&
+ prev_pc !=
+ stop_pc - DECR_PC_AFTER_BREAK);
ecs->random_signal = !bpstat_explains_signal (stop_bpstat);
inferior_ptid = ecs->saved_inferior_ptid;
goto process_event_stop_test;
}
stop_pc = read_pc ();
- stop_bpstat = bpstat_stop_status (&stop_pc, currently_stepping (ecs));
+ /* The second argument of bpstat_stop_status is meant to help
+ distinguish between a breakpoint trap and a singlestep trap.
+ This is only important on targets where DECR_PC_AFTER_BREAK
+ is non-zero. The prev_pc test is meant to distinguish between
+ singlestepping a trap instruction, and singlestepping thru a
+ jump to the instruction following a trap instruction. */
+
+ stop_bpstat = bpstat_stop_status (&stop_pc,
+ currently_stepping (ecs) &&
+ prev_pc !=
+ stop_pc - DECR_PC_AFTER_BREAK);
ecs->random_signal = !bpstat_explains_signal (stop_bpstat);
goto process_event_stop_test;
stop_pc = read_pc_pid (ecs->ptid);
ecs->saved_inferior_ptid = inferior_ptid;
inferior_ptid = ecs->ptid;
- stop_bpstat = bpstat_stop_status (&stop_pc, currently_stepping (ecs));
+ /* The second argument of bpstat_stop_status is meant to help
+ distinguish between a breakpoint trap and a singlestep trap.
+ This is only important on targets where DECR_PC_AFTER_BREAK
+ is non-zero. The prev_pc test is meant to distinguish between
+ singlestepping a trap instruction, and singlestepping thru a
+ jump to the instruction following a trap instruction. */
+
+ stop_bpstat = bpstat_stop_status (&stop_pc,
+ currently_stepping (ecs) &&
+ prev_pc !=
+ stop_pc - DECR_PC_AFTER_BREAK);
ecs->random_signal = !bpstat_explains_signal (stop_bpstat);
inferior_ptid = ecs->saved_inferior_ptid;
goto process_event_stop_test;
/* Saw a breakpoint, but it was hit by the wrong thread.
Just continue. */
- write_pc_pid (stop_pc - DECR_PC_AFTER_BREAK, ecs->ptid);
+ if (DECR_PC_AFTER_BREAK)
+ write_pc_pid (stop_pc - DECR_PC_AFTER_BREAK, ecs->ptid);
remove_status = remove_breakpoints ();
/* Did we fail to remove breakpoints? If so, try
then either :-) or execs. */
if (remove_status != 0)
{
- write_pc_pid (stop_pc - DECR_PC_AFTER_BREAK + 4, ecs->ptid);
+ /* FIXME! This is obviously non-portable! */
+ write_pc_pid (stop_pc - DECR_PC_AFTER_BREAK + 4,
+ ecs->ptid);
/* We need to restart all the threads now,
* unles we're running in scheduler-locked mode.
* Use currently_stepping to determine whether to
context_switch (ecs);
ecs->waiton_ptid = ecs->ptid;
ecs->wp = &(ecs->ws);
- thread_step_needed = 1;
ecs->another_trap = 1;
- /* keep_stepping will call resume, and the
- combination of "thread_step_needed" and
- "ecs->another_trap" will cause resume to
- solo-step the thread. The subsequent trap
- event will be handled like any other singlestep
- event. */
-
ecs->infwait_state = infwait_thread_hop_state;
keep_going (ecs);
registers_changed ();
return;
}
}
- else
- {
- /* This breakpoint matches--either it is the right
- thread or it's a generic breakpoint for all threads.
- Remember that we'll need to step just _this_ thread
- on any following user continuation! */
- thread_step_needed = 1;
- }
}
}
else
includes evaluating watchpoints, things will come to a
stop in the correct manner. */
- write_pc (stop_pc - DECR_PC_AFTER_BREAK);
+ if (DECR_PC_AFTER_BREAK)
+ write_pc (stop_pc - DECR_PC_AFTER_BREAK);
remove_breakpoints ();
registers_changed ();
else
{
/* See if there is a breakpoint at the current PC. */
+
+ /* The second argument of bpstat_stop_status is meant to help
+ distinguish between a breakpoint trap and a singlestep trap.
+ This is only important on targets where DECR_PC_AFTER_BREAK
+ is non-zero. The prev_pc test is meant to distinguish between
+ singlestepping a trap instruction, and singlestepping thru a
+ jump to the instruction following a trap instruction. */
+
stop_bpstat = bpstat_stop_status
(&stop_pc,
/* Pass TRUE if our reason for stopping is something other
sigtramp, which is detected by a new stack pointer value
below any usual function calling stack adjustments. */
(currently_stepping (ecs)
+ && prev_pc != stop_pc - DECR_PC_AFTER_BREAK
&& !(step_range_end
&& INNER_THAN (read_sp (), (step_sp - 16))))
);
case BPSTAT_WHAT_SINGLE:
if (breakpoints_inserted)
{
- thread_step_needed = 1;
remove_breakpoints ();
}
breakpoints_inserted = 0;
breakpoints_inserted = 0;
/* Check for any newly added shared libraries if we're
- supposed to be adding them automatically. */
- if (auto_solib_add)
- {
- /* Switch terminal for any messages produced by
- breakpoint_re_set. */
- target_terminal_ours_for_output ();
- SOLIB_ADD (NULL, 0, NULL);
- target_terminal_inferior ();
- }
+ supposed to be adding them automatically. Switch
+ terminal for any messages produced by
+ breakpoint_re_set. */
+ target_terminal_ours_for_output ();
+ SOLIB_ADD (NULL, 0, NULL, auto_solib_add);
+ target_terminal_inferior ();
/* Try to reenable shared library breakpoints, additional
code segments in shared libraries might be mapped in now. */
{
/* It's a subroutine call. */
- if (step_over_calls == STEP_OVER_NONE)
+ if ((step_over_calls == STEP_OVER_NONE)
+ || ((step_range_end == 1)
+ && in_prologue (prev_pc, ecs->stop_func_start)))
{
/* I presume that step_over_calls is only 0 when we're
supposed to be stepping at the assembly language level
("stepi"). Just stop. */
+ /* Also, maybe we just did a "nexti" inside a prolog,
+ so we thought it was a subroutine call but it was not.
+ Stop as well. FENN */
stop_step = 1;
print_stop_reason (END_STEPPING_RANGE, 0);
stop_stepping (ecs);
/* Print a message only if not in the middle of doing a "step n"
operation for n > 1 */
if (!step_multi || !stop_step)
- if (interpreter_p && strcmp (interpreter_p, "mi") == 0)
+ if (ui_out_is_mi_like_p (uiout))
ui_out_field_string (uiout, "reason", "end-stepping-range");
#endif
break;
/* The inferior was terminated by a signal. */
#ifdef UI_OUT
annotate_signalled ();
- if (interpreter_p && strcmp (interpreter_p, "mi") == 0)
+ if (ui_out_is_mi_like_p (uiout))
ui_out_field_string (uiout, "reason", "exited-signalled");
ui_out_text (uiout, "\nProgram terminated with signal ");
annotate_signal_name ();
annotate_exited (stop_info);
if (stop_info)
{
- if (interpreter_p && strcmp (interpreter_p, "mi") == 0)
+ if (ui_out_is_mi_like_p (uiout))
ui_out_field_string (uiout, "reason", "exited");
ui_out_text (uiout, "\nProgram exited with code ");
ui_out_field_fmt (uiout, "exit-code", "0%o", (unsigned int) stop_info);
}
else
{
- if (interpreter_p && strcmp (interpreter_p, "mi") == 0)
+ if (ui_out_is_mi_like_p (uiout))
ui_out_field_string (uiout, "reason", "exited-normally");
ui_out_text (uiout, "\nProgram exited normally.\n");
}
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", "signal-received");
ui_out_field_string (uiout, "signal-name", target_signal_to_name (stop_info));
annotate_signal_name_end ();
ui_out_text (uiout, ", ");
#ifdef UI_OUT
/* For mi, have the same behavior every time we stop:
print everything but the source line. */
- if (interpreter_p && strcmp (interpreter_p, "mi") == 0)
+ if (ui_out_is_mi_like_p (uiout))
source_flag = LOC_AND_ADDRESS;
#endif
#ifdef UI_OUT
- if (interpreter_p && strcmp (interpreter_p, "mi") == 0)
+ if (ui_out_is_mi_like_p (uiout))
ui_out_field_int (uiout, "thread-id",
pid_to_thread_id (inferior_ptid));
#endif
select_frame (get_current_frame (), 0);
}
-
- TUIDO (((TuiOpaqueFuncPtr) tui_vCheckDataValues, selected_frame));
-
done:
annotate_stopped ();
}