#include "top.h"
#include <signal.h>
#include "event-loop.h"
+#include "event-top.h"
/* Prototypes for local functions */
-static void signals_info PARAMS ((char *, int));
+static void signals_info (char *, int);
-static void handle_command PARAMS ((char *, int));
+static void handle_command (char *, int);
-static void sig_print_info PARAMS ((enum target_signal));
+static void sig_print_info (enum target_signal);
-static void sig_print_header PARAMS ((void));
+static void sig_print_header (void);
-static void resume_cleanups PARAMS ((int));
+static void resume_cleanups (int);
-static int hook_stop_stub PARAMS ((PTR));
+static int hook_stop_stub (void *);
-static void delete_breakpoint_current_contents PARAMS ((PTR));
+static void delete_breakpoint_current_contents (void *);
-static void set_follow_fork_mode_command PARAMS ((char *arg, int from_tty, struct cmd_list_element * c));
+static void set_follow_fork_mode_command (char *arg, int from_tty,
+ struct cmd_list_element * c);
-static void complete_execution PARAMS ((void));
+static void complete_execution (void);
+
+static struct inferior_status *xmalloc_inferior_status (void);
+
+static void free_inferior_status (struct inferior_status *);
+
+static int restore_selected_frame (void *);
+
+static void build_infrun (void);
+
+static void follow_inferior_fork (int parent_pid, int child_pid,
+ int has_forked, int has_vforked);
+
+static void follow_fork (int parent_pid, int child_pid);
+
+static void follow_vfork (int parent_pid, int child_pid);
+
+static void set_schedlock_func (char *args, int from_tty,
+ struct cmd_list_element * c);
+
+static int is_internal_shlib_eventpoint (struct breakpoint * ep);
+
+static int stopped_for_internal_shlib_event (bpstat bs);
+
+struct execution_control_state;
+
+static int currently_stepping (struct execution_control_state *ecs);
+
+static void xdb_handle_command (char *args, int from_tty);
+
+void _initialize_infrun (void);
int inferior_ignoring_startup_exec_events = 0;
int inferior_ignoring_leading_exec_events = 0;
/* In asynchronous mode, but simulating synchronous execution. */
+
int sync_execution = 0;
/* wait_for_inferior and normal_stop use this to notify the user
when the inferior stopped in a different thread than it had been
- running in. */
+ running in. */
+
static int switched_from_inferior_pid;
/* This will be true for configurations that may actually report an
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. */
+ 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
static int use_thread_step_needed = USE_THREAD_STEP_NEEDED;
-static void follow_inferior_fork PARAMS ((int parent_pid,
- int child_pid,
- int has_forked,
- int has_vforked));
-
-static void follow_fork PARAMS ((int parent_pid, int child_pid));
-
-static void follow_vfork PARAMS ((int parent_pid, int child_pid));
-
-static void set_schedlock_func PARAMS ((char *args, int from_tty,
- struct cmd_list_element * c));
-
-static int is_internal_shlib_eventpoint PARAMS ((struct breakpoint * ep));
-
-static int stopped_for_internal_shlib_event PARAMS ((bpstat bs));
-
-static int stopped_for_shlib_catchpoint PARAMS ((bpstat bs,
- struct breakpoint ** cp_p));
-
-#if __STDC__
-struct execution_control_state;
-#endif
-static int currently_stepping PARAMS ((struct execution_control_state * ecs));
-
-static void xdb_handle_command PARAMS ((char *args, int from_tty));
-
-void _initialize_infrun PARAMS ((void));
-
/* 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. */
#define DYNAMIC_TRAMPOLINE_NEXTPC(pc) 0
#endif
-/* On SVR4 based systems, determining the callee's address is exceedingly
- difficult and depends on the implementation of the run time loader.
- If we are stepping at the source level, we single step until we exit
- the run time loader code and reach the callee's address. */
+/* 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 Linux 5.2) 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. */
#ifndef IN_SOLIB_DYNSYM_RESOLVE_CODE
#define IN_SOLIB_DYNSYM_RESOLVE_CODE(pc) 0
#endif
+#ifndef SKIP_SOLIB_RESOLVER
+#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. */
#define INSTRUCTION_NULLIFIED 0
#endif
+/* We can't step off a permanent breakpoint in the ordinary way, because we
+ can't remove it. Instead, we have to advance the PC to the next
+ instruction. This macro should expand to a pointer to a function that
+ does that, or zero if we have no such function. If we don't have a
+ definition for it, we have to report an error. */
+#ifndef SKIP_PERMANENT_BREAKPOINT
+#define SKIP_PERMANENT_BREAKPOINT (default_skip_permanent_breakpoint)
+static void
+default_skip_permanent_breakpoint ()
+{
+ error_begin ();
+ fprintf_filtered (gdb_stderr, "\
+The program is stopped at a permanent breakpoint, but GDB does not know\n\
+how to step past a permanent breakpoint on this architecture. Try using\n\
+a command like `return' or `jump' to continue execution.\n");
+ return_to_top_level (RETURN_ERROR);
+}
+#endif
+
+
/* Convert the #defines into values. This is temporary until wfi control
flow is completely sorted out. */
\f
static void
-follow_inferior_fork (parent_pid, child_pid, has_forked, has_vforked)
- int parent_pid;
- int child_pid;
- int has_forked;
- int has_vforked;
+follow_inferior_fork (int parent_pid, int child_pid, int has_forked,
+ int has_vforked)
{
int followed_parent = 0;
int followed_child = 0;
- int ima_clone = 0;
/* Which process did the user want us to follow? */
char *follow_mode =
- savestring (follow_fork_mode_string, strlen (follow_fork_mode_string));
+ savestring (follow_fork_mode_string, strlen (follow_fork_mode_string));
/* Or, did the user not know, and want us to ask? */
if (STREQ (follow_fork_mode_string, "ask"))
}
static void
-follow_fork (parent_pid, child_pid)
- int parent_pid;
- int child_pid;
+follow_fork (int parent_pid, int child_pid)
{
follow_inferior_fork (parent_pid, child_pid, 1, 0);
}
/* Forward declaration. */
-static void follow_exec PARAMS ((int, char *));
+static void follow_exec (int, char *);
static void
-follow_vfork (parent_pid, child_pid)
- int parent_pid;
- int child_pid;
+follow_vfork (int parent_pid, int child_pid)
{
follow_inferior_fork (parent_pid, child_pid, 0, 1);
}
static void
-follow_exec (pid, execd_pathname)
- int pid;
- char *execd_pathname;
+follow_exec (int pid, char *execd_pathname)
{
int saved_pid = pid;
struct target_ops *tgt;
/* Things to clean up if we QUIT out of resume (). */
/* ARGSUSED */
static void
-resume_cleanups (arg)
- int arg;
+resume_cleanups (int arg)
{
normal_stop ();
}
{schedlock_off, schedlock_on, schedlock_step};
static void
-set_schedlock_func (args, from_tty, c)
- char *args;
- int from_tty;
- struct cmd_list_element *c;
+set_schedlock_func (char *args, int from_tty, struct cmd_list_element *c)
{
if (c->type == set_cmd)
if (!target_can_lock_scheduler)
}
+
+
/* 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
STEP nonzero if we should step (zero to continue instead).
SIG is the signal to give the inferior (zero for none). */
void
-resume (step, sig)
- int step;
- enum target_signal sig;
+resume (int step, enum target_signal sig)
{
int should_resume = 1;
struct cleanup *old_cleanups = make_cleanup ((make_cleanup_func)
step = 0;
#endif
+ /* Normally, by the time we reach `resume', the breakpoints are either
+ 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)
+ SKIP_PERMANENT_BREAKPOINT ();
+
if (SOFTWARE_SINGLE_STEP_P && step)
{
/* Do it the hard way, w/temp breakpoints */
First do this, then set the ones you want, then call `proceed'. */
void
-clear_proceed_status ()
+clear_proceed_status (void)
{
trap_expected = 0;
step_range_start = 0;
You should call clear_proceed_status before calling proceed. */
void
-proceed (addr, siggnal, step)
- CORE_ADDR addr;
- enum target_signal siggnal;
- int step;
+proceed (CORE_ADDR addr, enum target_signal siggnal, int step)
{
int oneproc = 0;
and in any case decode why it stopped, and act accordingly. */
/* Do this only if we are not using the event loop, or if the target
does not support asynchronous execution. */
- if (!async_p || !target_has_async)
+ if (!event_loop_p || !target_can_async_p ())
{
wait_for_inferior ();
normal_stop ();
\f
/* Start remote-debugging of a machine over a serial link. */
+
void
-start_remote ()
+start_remote (void)
{
init_thread_list ();
init_wait_for_inferior ();
stop_soon_quietly = 1;
trap_expected = 0;
- /* Go on waiting only in case gdb is not started in async mode, or
- in case the target doesn't support async execution. */
- if (!async_p || !target_has_async)
- {
- wait_for_inferior ();
- normal_stop ();
- }
- else
- {
- /* The 'tar rem' command should always look synchronous,
- i.e. display the prompt only once it has connected and
- started the target. */
- sync_execution = 1;
- push_prompt ("", "", "");
- delete_file_handler (input_fd);
- target_executing = 1;
- }
+ /* Always go on waiting for the target, regardless of the mode. */
+ /* FIXME: cagney/1999-09-23: At present it isn't possible to
+ indicate th wait_for_inferior that a target should timeout if
+ nothing is returned (instead of just blocking). Because of this,
+ targets expecting an immediate response need to, internally, set
+ things up so that the target_wait() is forced to eventually
+ timeout. */
+ /* FIXME: cagney/1999-09-24: It isn't possible for target_open() to
+ differentiate to its caller what the state of the target is after
+ the initial open has been performed. Here we're assuming that
+ the target has stopped. It should be possible to eventually have
+ 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 ();
+ normal_stop ();
}
/* Initialize static vars when a new inferior begins. */
void
-init_wait_for_inferior ()
+init_wait_for_inferior (void)
{
/* These are meaningless until the first time through wait_for_inferior. */
prev_pc = 0;
}
static void
-delete_breakpoint_current_contents (arg)
- PTR arg;
+delete_breakpoint_current_contents (void *arg)
{
struct breakpoint **breakpointp = (struct breakpoint **) arg;
if (*breakpointp != NULL)
int wait_some_more;
};
-void init_execution_control_state PARAMS ((struct execution_control_state * ecs));
+void init_execution_control_state (struct execution_control_state * ecs);
-void handle_inferior_event PARAMS ((struct execution_control_state * ecs));
+void handle_inferior_event (struct execution_control_state * ecs);
+
+static void check_sigtramp2 (struct execution_control_state *ecs);
+static void step_into_function (struct execution_control_state *ecs);
+static void step_over_function (struct execution_control_state *ecs);
+static void stop_stepping (struct execution_control_state *ecs);
+static void prepare_to_wait (struct execution_control_state *ecs);
+static void keep_going (struct execution_control_state *ecs);
/* Wait for control to return from inferior to debugger.
If inferior gets a signal, we may decide to start it up again
should be left stopped and GDB should read more commands. */
void
-wait_for_inferior ()
+wait_for_inferior (void)
{
struct cleanup *old_cleanups;
struct execution_control_state ecss;
struct execution_control_state *async_ecs;
void
-fetch_inferior_event ()
+fetch_inferior_event (client_data)
+ gdb_client_data client_data;
{
static struct cleanup *old_cleanups;
wait_for_inferior-type loop. */
void
-init_execution_control_state (ecs)
- struct execution_control_state *ecs;
+init_execution_control_state (struct execution_control_state *ecs)
{
ecs->random_signal = 0;
ecs->remove_breakpoints_on_following_step = 0;
}
/* Call this function before setting step_resume_breakpoint, as a
- sanity check. We should never be setting a new
- step_resume_breakpoint when we have an old one active. */
+ sanity check. There should never be more than one step-resume
+ breakpoint per thread, so we should never be setting a new
+ step_resume_breakpoint when one is already active. */
static void
-check_for_old_step_resume_breakpoint ()
+check_for_old_step_resume_breakpoint (void)
{
if (step_resume_breakpoint)
warning ("GDB bug: infrun.c (wait_for_inferior): dropping old step_resume breakpoint");
appropriate action. */
void
-handle_inferior_event (ecs)
- struct execution_control_state *ecs;
+handle_inferior_event (struct execution_control_state *ecs)
{
CORE_ADDR tmp;
int stepped_after_stopped_by_watchpoint;
else
target_resume (-1, 0, TARGET_SIGNAL_0);
ecs->infwait_state = infwait_normal_state;
- goto wfi_continue;
+ prepare_to_wait (ecs);
+ return;
case infwait_nullified_state:
break;
make progress. */
target_resume (-1, 0, TARGET_SIGNAL_0);
- goto wfi_continue;
+ prepare_to_wait (ecs);
+ return;
#endif
}
}
#endif
resume (0, TARGET_SIGNAL_0);
- goto wfi_continue;
+ prepare_to_wait (ecs);
+ return;
case TARGET_WAITKIND_SPURIOUS:
resume (0, TARGET_SIGNAL_0);
- goto wfi_continue;
+ prepare_to_wait (ecs);
+ return;
case TARGET_WAITKIND_EXITED:
target_terminal_ours (); /* Must do this before mourn anyway */
target_mourn_inferior ();
singlestep_breakpoints_inserted_p = 0; /*SOFTWARE_SINGLE_STEP_P */
stop_print_frame = 0;
- goto stop_stepping;
+ stop_stepping (ecs);
+ return;
case TARGET_WAITKIND_SIGNALLED:
stop_print_frame = 0;
printf_filtered ("The program no longer exists.\n");
gdb_flush (gdb_stdout);
singlestep_breakpoints_inserted_p = 0; /*SOFTWARE_SINGLE_STEP_P */
- goto stop_stepping;
+ stop_stepping (ecs);
+ return;
/* The following are the only cases in which we keep going;
the above cases end in a continue or goto. */
pending_follow.fork_event.saw_parent_fork = 1;
pending_follow.fork_event.parent_pid = ecs->pid;
pending_follow.fork_event.child_pid = ecs->ws.value.related_pid;
- goto wfi_continue;
+ prepare_to_wait (ecs);
+ return;
}
else
{
stop_pc = read_pc_pid (ecs->pid);
ecs->saved_inferior_pid = inferior_pid;
inferior_pid = ecs->pid;
- stop_bpstat = bpstat_stop_status
- (&stop_pc,
- (DECR_PC_AFTER_BREAK ?
- (prev_pc != stop_pc - DECR_PC_AFTER_BREAK
- && currently_stepping (ecs))
- : 0)
- );
+ stop_bpstat = bpstat_stop_status (&stop_pc, currently_stepping (ecs));
ecs->random_signal = !bpstat_explains_signal (stop_bpstat);
inferior_pid = ecs->saved_inferior_pid;
goto process_event_stop_test;
if (follow_vfork_when_exec)
{
target_resume (ecs->pid, 0, TARGET_SIGNAL_0);
- goto wfi_continue;
+ prepare_to_wait (ecs);
+ return;
}
}
stop_pc = read_pc ();
- stop_bpstat = bpstat_stop_status
- (&stop_pc,
- (DECR_PC_AFTER_BREAK ?
- (prev_pc != stop_pc - DECR_PC_AFTER_BREAK
- && currently_stepping (ecs))
- : 0)
- );
+ stop_bpstat = bpstat_stop_status (&stop_pc, currently_stepping (ecs));
ecs->random_signal = !bpstat_explains_signal (stop_bpstat);
goto process_event_stop_test;
if (pending_follow.kind == TARGET_WAITKIND_VFORKED)
ENSURE_VFORKING_PARENT_REMAINS_STOPPED (pending_follow.fork_event.parent_pid);
target_resume (ecs->pid, 0, TARGET_SIGNAL_0);
- goto wfi_continue;
+ prepare_to_wait (ecs);
+ return;
}
inferior_ignoring_leading_exec_events =
target_reported_exec_events_per_exec_call () - 1;
- pending_follow.execd_pathname = savestring (ecs->ws.value.execd_pathname,
- strlen (ecs->ws.value.execd_pathname));
+ pending_follow.execd_pathname =
+ savestring (ecs->ws.value.execd_pathname,
+ strlen (ecs->ws.value.execd_pathname));
/* Did inferior_pid exec, or did a (possibly not-yet-followed)
child of a vfork exec?
if (RESUME_EXECD_VFORKING_CHILD_TO_GET_PARENT_VFORK ())
target_resume (ecs->pid, 1, TARGET_SIGNAL_0);
/* We expect the parent vfork event to be available now. */
- goto wfi_continue;
+ prepare_to_wait (ecs);
+ return;
}
/* This causes the eventpoints and symbol table to be reset. Must
stop_pc = read_pc_pid (ecs->pid);
ecs->saved_inferior_pid = inferior_pid;
inferior_pid = ecs->pid;
- stop_bpstat = bpstat_stop_status
- (&stop_pc,
- (DECR_PC_AFTER_BREAK ?
- (prev_pc != stop_pc - DECR_PC_AFTER_BREAK
- && currently_stepping (ecs))
- : 0)
- );
+ stop_bpstat = bpstat_stop_status (&stop_pc, currently_stepping (ecs));
ecs->random_signal = !bpstat_explains_signal (stop_bpstat);
inferior_pid = ecs->saved_inferior_pid;
goto process_event_stop_test;
TARGET_DISABLE_HW_WATCHPOINTS (inferior_pid);
}
resume (0, TARGET_SIGNAL_0);
- goto wfi_continue;
+ prepare_to_wait (ecs);
+ return;
/* Before examining the threads further, step this thread to
get it entirely out of the syscall. (We get notice of the
ecs->enable_hw_watchpoints_after_wait =
(number_of_threads_in_syscalls == 0);
}
- goto wfi_continue;
+ prepare_to_wait (ecs);
+ return;
case TARGET_WAITKIND_STOPPED:
stop_signal = ecs->ws.value.sig;
if (ecs->new_thread_event)
{
target_resume (-1, 0, TARGET_SIGNAL_0);
- goto wfi_continue;
+ prepare_to_wait (ecs);
+ return;
}
stop_pc = read_pc_pid (ecs->pid);
ecs->waiton_pid = ecs->pid;
ecs->wp = &(ecs->ws);
ecs->infwait_state = infwait_thread_hop_state;
- goto wfi_continue;
+ prepare_to_wait (ecs);
+ return;
}
/* We need to restart all the threads now,
target_resume (ecs->pid, 0, TARGET_SIGNAL_0);
else
target_resume (-1, 0, TARGET_SIGNAL_0);
- goto wfi_continue;
+ prepare_to_wait (ecs);
+ return;
}
else
{
stop_signal = TARGET_SIGNAL_0;
target_resume (ecs->pid, 0, stop_signal);
- goto wfi_continue;
+ prepare_to_wait (ecs);
+ return;
}
/* It's a SIGTRAP or a signal we're interested in. Switch threads,
ecs->infwait_state = infwait_nullified_state;
ecs->waiton_pid = ecs->pid;
ecs->wp = &(ecs->tmpstatus);
- goto wfi_continue;
+ prepare_to_wait (ecs);
+ return;
}
/* It may not be necessary to disable the watchpoint to stop over
if (HAVE_STEPPABLE_WATCHPOINT && STOPPED_BY_WATCHPOINT (ecs->ws))
{
resume (1, 0);
- goto wfi_continue;
+ prepare_to_wait (ecs);
+ return;
}
/* It is far more common to need to disable a watchpoint to step
ecs->waiton_pid = ecs->pid;
ecs->wp = &(ecs->ws);
ecs->infwait_state = infwait_nonstep_watch_state;
- goto wfi_continue;
+ prepare_to_wait (ecs);
+ return;
}
/* It may be possible to simply continue after a watchpoint. */
if (stop_signal == TARGET_SIGNAL_TRAP && stop_after_trap)
{
stop_print_frame = 0;
- goto wfi_break;
+ stop_stepping (ecs);
+ return;
}
if (stop_soon_quietly)
- goto wfi_break;
+ {
+ stop_stepping (ecs);
+ return;
+ }
/* Don't even think about breakpoints
if just proceeded over a breakpoint.
/* See if there is a breakpoint at the current PC. */
stop_bpstat = bpstat_stop_status
(&stop_pc,
- (DECR_PC_AFTER_BREAK ?
- /* Notice the case of stepping through a jump
- that lands just after a breakpoint.
- Don't confuse that with hitting the breakpoint.
- What we check for is that 1) stepping is going on
- and 2) the pc before the last insn does not match
- the address of the breakpoint before the current pc
- and 3) we didn't hit a breakpoint in a signal handler
- without an intervening stop in sigtramp, which is
- detected by a new stack pointer value below
- any usual function calling stack adjustments. */
+ /* Pass TRUE if our reason for stopping is something other
+ than hitting a breakpoint. We do this by checking that
+ 1) stepping is going on and 2) we didn't hit a breakpoint
+ in a signal handler without an intervening stop in
+ 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)))) :
- 0)
+ && INNER_THAN (read_sp (), (step_sp - 16))))
);
/* Following in case break condition called a
function. */
{
trap_expected = 1;
stop_signal = TARGET_SIGNAL_0;
- goto keep_going;
+ keep_going (ecs);
+ return;
}
}
else if (ecs->ws.kind == TARGET_WAITKIND_VFORKED)
{
if (ecs->random_signal) /* I.e., no catchpoint triggered for this. */
{
- stop_signal = TARGET_SIGNAL_0;
- goto keep_going;
+ stop_signal = TARGET_SIGNAL_0;
+ keep_going (ecs);
+ return;
}
}
else if (ecs->ws.kind == TARGET_WAITKIND_EXECD)
{
trap_expected = 1;
stop_signal = TARGET_SIGNAL_0;
- goto keep_going;
+ keep_going (ecs);
+ return;
}
}
gdb_flush (gdb_stdout);
}
if (signal_stop[stop_signal])
- goto wfi_break;
+ {
+ stop_stepping (ecs);
+ return;
+ }
/* If not going to stop, give terminal back
if we took it away. */
else if (printed)
that case, when we reach this point, there is already a
step-resume breakpoint established, right where it should be:
immediately after the function call the user is "next"-ing
- over. If we jump to step_over_function now, two bad things
+ over. If we call step_over_function now, two bad things
happen:
- we'll create a new breakpoint, at wherever the current
this probably breaks that. As with anything else, it's up to
the HP-UX maintainer to furnish a fix that doesn't break other
platforms. --JimB, 20 May 1999 */
- goto check_sigtramp2;
+ check_sigtramp2 (ecs);
}
/* Handle cases caused by hitting a breakpoint. */
remove_breakpoints ();
breakpoints_inserted = 0;
if (!GET_LONGJMP_TARGET (&jmp_buf_pc))
- goto keep_going;
+ {
+ keep_going (ecs);
+ return;
+ }
/* Need to blow away step-resume breakpoint, as it
interferes with us */
#endif /* 0 */
set_longjmp_resume_breakpoint (jmp_buf_pc, NULL);
ecs->handling_longjmp = 1; /* FIXME */
- goto keep_going;
+ keep_going (ecs);
+ return;
case BPSTAT_WHAT_CLEAR_LONGJMP_RESUME:
case BPSTAT_WHAT_CLEAR_LONGJMP_RESUME_SINGLE:
step_frame_address)))
{
ecs->another_trap = 1;
- goto keep_going;
+ keep_going (ecs);
+ return;
}
#endif /* 0 */
disable_longjmp_breakpoint ();
through_sigtramp_breakpoint via the cleanup chain, so
no need to worry about it here. */
- goto stop_stepping;
+ stop_stepping (ecs);
+ return;
case BPSTAT_WHAT_STOP_SILENT:
stop_print_frame = 0;
through_sigtramp_breakpoint via the cleanup chain, so
no need to worry about it here. */
- goto stop_stepping;
+ stop_stepping (ecs);
+ return;
case BPSTAT_WHAT_STEP_RESUME:
/* This proably demands a more elegant solution, but, yeah
If we reach here and step_resume_breakpoint is already
NULL, then apparently we have multiple active
step-resume bp's. We'll just delete the breakpoint we
- stopped at, and carry on. */
+ stopped at, and carry on.
+
+ Correction: what the code currently does is delete a
+ step-resume bp, but it makes no effort to ensure that
+ the one deleted is the one currently stopped at. MVS */
+
if (step_resume_breakpoint == NULL)
{
step_resume_breakpoint =
if (stop_on_solib_events)
{
stop_print_frame = 0;
- goto stop_stepping;
+ stop_stepping (ecs);
+ return;
}
/* If we stopped due to an explicit catchpoint, then the
if (SOLIB_IN_DYNAMIC_LINKER (ecs->pid, stop_pc))
{
ecs->another_trap = 1;
- goto keep_going;
+ keep_going (ecs);
+ return;
}
#endif
/* Else, stop and report the catchpoint(s) whose triggering
stop_bpstat = bpstat_copy (ecs->stepping_through_solib_catchpoints);
bpstat_clear (&ecs->stepping_through_solib_catchpoints);
stop_print_frame = 1;
- goto stop_stepping;
+ stop_stepping (ecs);
+ return;
}
if (!CALL_DUMMY_BREAKPOINT_OFFSET_P)
#ifdef HP_OS_BUG
trap_expected_after_continue = 1;
#endif
- goto wfi_break;
+ stop_stepping (ecs);
+ return;
}
}
if (step_resume_breakpoint)
- /* Having a step-resume breakpoint overrides anything
- else having to do with stepping commands until
- that breakpoint is reached. */
- /* I'm not sure whether this needs to be check_sigtramp2 or
- whether it could/should be keep_going. */
- goto check_sigtramp2;
-
+ {
+ /* Having a step-resume breakpoint overrides anything
+ else having to do with stepping commands until
+ that breakpoint is reached. */
+ /* I'm not sure whether this needs to be check_sigtramp2 or
+ whether it could/should be keep_going. */
+ check_sigtramp2 (ecs);
+ keep_going (ecs);
+ return;
+ }
+
if (step_range_end == 0)
- /* Likewise if we aren't even stepping. */
- /* I'm not sure whether this needs to be check_sigtramp2 or
- whether it could/should be keep_going. */
- goto check_sigtramp2;
+ {
+ /* Likewise if we aren't even stepping. */
+ /* I'm not sure whether this needs to be check_sigtramp2 or
+ whether it could/should be keep_going. */
+ check_sigtramp2 (ecs);
+ keep_going (ecs);
+ return;
+ }
/* If stepping through a line, keep going if still within it.
{
/* We might be doing a BPSTAT_WHAT_SINGLE and getting a signal.
So definately need to check for sigtramp here. */
- goto check_sigtramp2;
+ check_sigtramp2 (ecs);
+ keep_going (ecs);
+ return;
}
/* We stepped out of the stepping range. */
until we exit the run time loader code and reach the callee's
address. */
if (step_over_calls < 0 && IN_SOLIB_DYNSYM_RESOLVE_CODE (stop_pc))
- goto keep_going;
+ {
+ CORE_ADDR pc_after_resolver = SKIP_SOLIB_RESOLVER (stop_pc);
+
+ if (pc_after_resolver)
+ {
+ /* Set up a step-resume breakpoint at the address
+ indicated by SKIP_SOLIB_RESOLVER. */
+ struct symtab_and_line sr_sal;
+ INIT_SAL (&sr_sal);
+ sr_sal.pc = pc_after_resolver;
+
+ check_for_old_step_resume_breakpoint ();
+ step_resume_breakpoint =
+ set_momentary_breakpoint (sr_sal, NULL, bp_step_resume);
+ if (breakpoints_inserted)
+ insert_breakpoints ();
+ }
+
+ keep_going (ecs);
+ return;
+ }
/* We can't update step_sp every time through the loop, because
reading the stack pointer would slow down stepping too much.
/* We just stepped out of a signal handler and into
its calling trampoline.
- Normally, we'd jump to step_over_function from
+ Normally, we'd call step_over_function from
here, but for some reason GDB can't unwind the
stack correctly to find the real PC for the point
user code where the signal trampoline will return
step_range_end = (step_range_start = prev_pc) + 1;
ecs->remove_breakpoints_on_following_step = 1;
- goto keep_going;
+ keep_going (ecs);
+ return;
}
if (stop_pc == ecs->stop_func_start /* Quick test */
supposed to be stepping at the assembly language level
("stepi"). Just stop. */
stop_step = 1;
- goto wfi_break;
+ stop_stepping (ecs);
+ return;
}
if (step_over_calls > 0 || IGNORE_HELPER_CALL (stop_pc))
- /* We're doing a "next". */
- goto step_over_function;
+ {
+ /* We're doing a "next". */
+ step_over_function (ecs);
+ keep_going (ecs);
+ return;
+ }
/* If we are in a function call trampoline (a stub between
the calling routine and the real function), locate the real
step_resume_breakpoint =
set_momentary_breakpoint (xxx, NULL, bp_step_resume);
insert_breakpoints ();
- goto keep_going;
+ keep_going (ecs);
+ return;
}
}
tmp_sal = find_pc_line (ecs->stop_func_start, 0);
if (tmp_sal.line != 0)
- goto step_into_function;
- }
-
- step_over_function:
- /* A subroutine call has happened. */
- {
- /* We've just entered a callee, and we wish to resume until it
- returns to the caller. Setting a step_resume breakpoint on
- the return address will catch a return from the callee.
-
- However, if the callee is recursing, we want to be careful
- not to catch returns of those recursive calls, but only of
- THIS instance of the call.
-
- To do this, we set the step_resume bp's frame to our current
- caller's frame (step_frame_address, which is set by the "next"
- or "until" command, before execution begins). */
- struct symtab_and_line sr_sal;
-
- INIT_SAL (&sr_sal); /* initialize to zeros */
- sr_sal.pc =
- ADDR_BITS_REMOVE (SAVED_PC_AFTER_CALL (get_current_frame ()));
- sr_sal.section = find_pc_overlay (sr_sal.pc);
-
- check_for_old_step_resume_breakpoint ();
- step_resume_breakpoint =
- set_momentary_breakpoint (sr_sal, get_current_frame (),
- bp_step_resume);
-
- if (!IN_SOLIB_DYNSYM_RESOLVE_CODE (sr_sal.pc))
- step_resume_breakpoint->frame = step_frame_address;
-
- if (breakpoints_inserted)
- insert_breakpoints ();
- }
- goto keep_going;
-
- step_into_function:
- /* Subroutine call with source code we should not step over.
- Do step to the first line of code in it. */
- {
- struct symtab *s;
-
- s = find_pc_symtab (stop_pc);
- if (s && s->language != language_asm)
- ecs->stop_func_start = SKIP_PROLOGUE (ecs->stop_func_start);
+ {
+ step_into_function (ecs);
+ return;
+ }
}
- ecs->sal = find_pc_line (ecs->stop_func_start, 0);
- /* Use the step_resume_break to step until
- the end of the prologue, even if that involves jumps
- (as it seems to on the vax under 4.2). */
- /* If the prologue ends in the middle of a source line,
- continue to the end of that source line (if it is still
- within the function). Otherwise, just go to end of prologue. */
-#ifdef PROLOGUE_FIRSTLINE_OVERLAP
- /* no, don't either. It skips any code that's
- legitimately on the first line. */
-#else
- if (ecs->sal.end && ecs->sal.pc != ecs->stop_func_start && ecs->sal.end < ecs->stop_func_end)
- ecs->stop_func_start = ecs->sal.end;
-#endif
-
- if (ecs->stop_func_start == stop_pc)
- {
- /* We are already there: stop now. */
- stop_step = 1;
- goto wfi_break;
- }
- else
- /* Put the step-breakpoint there and go until there. */
- {
- struct symtab_and_line sr_sal;
-
- INIT_SAL (&sr_sal); /* initialize to zeroes */
- sr_sal.pc = ecs->stop_func_start;
- sr_sal.section = find_pc_overlay (ecs->stop_func_start);
- /* Do not specify what the fp should be when we stop
- since on some machines the prologue
- is where the new fp value is established. */
- check_for_old_step_resume_breakpoint ();
- step_resume_breakpoint =
- set_momentary_breakpoint (sr_sal, NULL, bp_step_resume);
- if (breakpoints_inserted)
- insert_breakpoints ();
+ step_over_function (ecs);
+ keep_going (ecs);
+ return;
- /* And make sure stepping stops right away then. */
- step_range_end = step_range_start;
- }
- goto keep_going;
}
/* We've wandered out of the step range. */
/* It is stepi or nexti. We always want to stop stepping after
one instruction. */
stop_step = 1;
- goto wfi_break;
+ stop_stepping (ecs);
+ return;
}
/* If we're in the return path from a shared library trampoline,
/* Restart without fiddling with the step ranges or
other state. */
- goto keep_going;
+ keep_going (ecs);
+ return;
}
}
when we do "s" in a function with no line numbers,
or can this happen as a result of a return or longjmp?). */
stop_step = 1;
- goto wfi_break;
+ stop_stepping (ecs);
+ return;
}
if ((stop_pc == ecs->sal.pc)
That is said to make things like for (;;) statements work
better. */
stop_step = 1;
- goto wfi_break;
+ stop_stepping (ecs);
+ return;
}
/* We aren't done stepping.
in which after skipping the prologue we better stop even though
we will be in mid-line. */
stop_step = 1;
- goto wfi_break;
+ stop_stepping (ecs);
+ return;
}
step_range_start = ecs->sal.pc;
step_range_end = ecs->sal.end;
step_frame_address = current_frame;
}
+ keep_going (ecs);
- goto keep_going;
-
- check_sigtramp2:
- if (trap_expected
- && IN_SIGTRAMP (stop_pc, ecs->stop_func_name)
- && !IN_SIGTRAMP (prev_pc, prev_func_name)
- && INNER_THAN (read_sp (), step_sp))
- {
- /* What has happened here is that we have just stepped the inferior
- with a signal (because it is a signal which shouldn't make
- us stop), thus stepping into sigtramp.
-
- So we need to set a step_resume_break_address breakpoint
- and continue until we hit it, and then step. FIXME: This should
- be more enduring than a step_resume breakpoint; we should know
- that we will later need to keep going rather than re-hitting
- the breakpoint here (see testsuite/gdb.t06/signals.exp where
- it says "exceedingly difficult"). */
- struct symtab_and_line sr_sal;
-
- INIT_SAL (&sr_sal); /* initialize to zeroes */
- sr_sal.pc = prev_pc;
- sr_sal.section = find_pc_overlay (sr_sal.pc);
- /* We perhaps could set the frame if we kept track of what
- the frame corresponding to prev_pc was. But we don't,
- so don't. */
- through_sigtramp_breakpoint =
- set_momentary_breakpoint (sr_sal, NULL, bp_through_sigtramp);
- if (breakpoints_inserted)
- insert_breakpoints ();
+ } /* extra brace, to preserve old indentation */
+}
- ecs->remove_breakpoints_on_following_step = 1;
- ecs->another_trap = 1;
- }
+/* Are we in the middle of stepping? */
- keep_going:
- /* Come to this label when you need to resume the inferior.
- It's really much cleaner to do a goto than a maze of if-else
- conditions. */
-
- /* ??rehrauer: ttrace on HP-UX theoretically allows one to debug
- a vforked child beetween its creation and subsequent exit or
- call to exec(). However, I had big problems in this rather
- creaky exec engine, getting that to work. The fundamental
- problem is that I'm trying to debug two processes via an
- engine that only understands a single process with possibly
- multiple threads.
-
- Hence, this spot is known to have problems when
- target_can_follow_vfork_prior_to_exec returns 1. */
-
- /* Save the pc before execution, to compare with pc after stop. */
- prev_pc = read_pc (); /* Might have been DECR_AFTER_BREAK */
- prev_func_start = ecs->stop_func_start; /* Ok, since if DECR_PC_AFTER
- BREAK is defined, the
- original pc would not have
- been at the start of a
- function. */
- prev_func_name = ecs->stop_func_name;
+static int
+currently_stepping (struct execution_control_state *ecs)
+{
+ return ((through_sigtramp_breakpoint == NULL
+ && !ecs->handling_longjmp
+ && ((step_range_end && step_resume_breakpoint == NULL)
+ || trap_expected))
+ || ecs->stepping_through_solib_after_catch
+ || bpstat_should_step ());
+}
- if (ecs->update_step_sp)
- step_sp = read_sp ();
- ecs->update_step_sp = 0;
+static void
+check_sigtramp2 (struct execution_control_state *ecs)
+{
+ if (trap_expected
+ && IN_SIGTRAMP (stop_pc, ecs->stop_func_name)
+ && !IN_SIGTRAMP (prev_pc, prev_func_name)
+ && INNER_THAN (read_sp (), step_sp))
+ {
+ /* What has happened here is that we have just stepped the
+ inferior with a signal (because it is a signal which
+ shouldn't make us stop), thus stepping into sigtramp.
+
+ So we need to set a step_resume_break_address breakpoint and
+ continue until we hit it, and then step. FIXME: This should
+ be more enduring than a step_resume breakpoint; we should
+ know that we will later need to keep going rather than
+ re-hitting the breakpoint here (see the testsuite,
+ gdb.base/signals.exp where it says "exceedingly difficult"). */
+
+ struct symtab_and_line sr_sal;
+
+ INIT_SAL (&sr_sal); /* initialize to zeroes */
+ sr_sal.pc = prev_pc;
+ sr_sal.section = find_pc_overlay (sr_sal.pc);
+ /* We perhaps could set the frame if we kept track of what the
+ frame corresponding to prev_pc was. But we don't, so don't. */
+ through_sigtramp_breakpoint =
+ set_momentary_breakpoint (sr_sal, NULL, bp_through_sigtramp);
+ if (breakpoints_inserted)
+ insert_breakpoints ();
- /* If we did not do break;, it means we should keep
- running the inferior and not return to debugger. */
+ ecs->remove_breakpoints_on_following_step = 1;
+ ecs->another_trap = 1;
+ }
+}
- if (trap_expected && stop_signal != TARGET_SIGNAL_TRAP)
- {
- /* We took a signal (which we are supposed to pass through to
- the inferior, else we'd have done a break above) and we
- haven't yet gotten our trap. Simply continue. */
- resume (currently_stepping (ecs), stop_signal);
- }
- else
- {
- /* Either the trap was not expected, but we are continuing
- anyway (the user asked that this signal be passed to the
- child)
- -- or --
- The signal was SIGTRAP, e.g. it was our signal, but we
- decided we should resume from it.
-
- We're going to run this baby now!
-
- Insert breakpoints now, unless we are trying
- to one-proceed past a breakpoint. */
- /* If we've just finished a special step resume and we don't
- want to hit a breakpoint, pull em out. */
- if (step_resume_breakpoint == NULL
- && through_sigtramp_breakpoint == NULL
- && ecs->remove_breakpoints_on_following_step)
- {
- ecs->remove_breakpoints_on_following_step = 0;
- remove_breakpoints ();
- breakpoints_inserted = 0;
- }
- else if (!breakpoints_inserted &&
- (through_sigtramp_breakpoint != NULL || !ecs->another_trap))
- {
- breakpoints_failed = insert_breakpoints ();
- if (breakpoints_failed)
- goto wfi_break;
- breakpoints_inserted = 1;
- }
+/* Subroutine call with source code we should not step over. Do step
+ to the first line of code in it. */
- trap_expected = ecs->another_trap;
+static void
+step_into_function (struct execution_control_state *ecs)
+{
+ struct symtab *s;
+ struct symtab_and_line sr_sal;
+
+ s = find_pc_symtab (stop_pc);
+ if (s && s->language != language_asm)
+ ecs->stop_func_start = SKIP_PROLOGUE (ecs->stop_func_start);
+
+ ecs->sal = find_pc_line (ecs->stop_func_start, 0);
+ /* Use the step_resume_break to step until the end of the prologue,
+ even if that involves jumps (as it seems to on the vax under
+ 4.2). */
+ /* If the prologue ends in the middle of a source line, continue to
+ the end of that source line (if it is still within the function).
+ Otherwise, just go to end of prologue. */
+#ifdef PROLOGUE_FIRSTLINE_OVERLAP
+ /* no, don't either. It skips any code that's legitimately on the
+ first line. */
+#else
+ if (ecs->sal.end
+ && ecs->sal.pc != ecs->stop_func_start
+ && ecs->sal.end < ecs->stop_func_end)
+ ecs->stop_func_start = ecs->sal.end;
+#endif
- /* Do not deliver SIGNAL_TRAP (except when the user
- explicitly specifies that such a signal should be
- delivered to the target program).
+ if (ecs->stop_func_start == stop_pc)
+ {
+ /* We are already there: stop now. */
+ stop_step = 1;
+ stop_stepping (ecs);
+ return;
+ }
+ else
+ {
+ /* Put the step-breakpoint there and go until there. */
+ INIT_SAL (&sr_sal); /* initialize to zeroes */
+ sr_sal.pc = ecs->stop_func_start;
+ sr_sal.section = find_pc_overlay (ecs->stop_func_start);
+ /* Do not specify what the fp should be when we stop since on
+ some machines the prologue is where the new fp value is
+ established. */
+ check_for_old_step_resume_breakpoint ();
+ step_resume_breakpoint =
+ set_momentary_breakpoint (sr_sal, NULL, bp_step_resume);
+ if (breakpoints_inserted)
+ insert_breakpoints ();
- Typically, this would occure when a user is debugging a
- target monitor on a simulator: the target monitor sets a
- breakpoint; the simulator encounters this break-point and
- halts the simulation handing control to GDB; GDB, noteing
- that the break-point isn't valid, returns control back to
- the simulator; the simulator then delivers the hardware
- equivalent of a SIGNAL_TRAP to the program being
- debugged. */
+ /* And make sure stepping stops right away then. */
+ step_range_end = step_range_start;
+ }
+ keep_going (ecs);
+}
- if (stop_signal == TARGET_SIGNAL_TRAP
- && !signal_program[stop_signal])
- stop_signal = TARGET_SIGNAL_0;
+/* We've just entered a callee, and we wish to resume until it returns
+ to the caller. Setting a step_resume breakpoint on the return
+ address will catch a return from the callee.
+
+ However, if the callee is recursing, we want to be careful not to
+ catch returns of those recursive calls, but only of THIS instance
+ of the call.
-#ifdef SHIFT_INST_REGS
- /* I'm not sure when this following segment applies. I do know,
- now, that we shouldn't rewrite the regs when we were stopped
- by a random signal from the inferior process. */
- /* FIXME: Shouldn't this be based on the valid bit of the SXIP?
- (this is only used on the 88k). */
-
- if (!bpstat_explains_signal (stop_bpstat)
- && (stop_signal != TARGET_SIGNAL_CHLD)
- && !stopped_by_random_signal)
- SHIFT_INST_REGS ();
-#endif /* SHIFT_INST_REGS */
+ To do this, we set the step_resume bp's frame to our current
+ caller's frame (step_frame_address, which is set by the "next" or
+ "until" command, before execution begins). */
- resume (currently_stepping (ecs), stop_signal);
- }
+static void
+step_over_function (struct execution_control_state *ecs)
+{
+ struct symtab_and_line sr_sal;
- /* Former continues in the main loop goto here. */
- wfi_continue:
- /* This used to be at the top of the loop. */
- if (ecs->infwait_state == infwait_normal_state)
- {
- overlay_cache_invalid = 1;
+ INIT_SAL (&sr_sal); /* initialize to zeros */
+ sr_sal.pc = ADDR_BITS_REMOVE (SAVED_PC_AFTER_CALL (get_current_frame ()));
+ sr_sal.section = find_pc_overlay (sr_sal.pc);
- /* We have to invalidate the registers BEFORE calling
- target_wait because they can be loaded from the target
- while in target_wait. This makes remote debugging a bit
- more efficient for those targets that provide critical
- registers as part of their normal status mechanism. */
+ check_for_old_step_resume_breakpoint ();
+ step_resume_breakpoint =
+ set_momentary_breakpoint (sr_sal, get_current_frame (), bp_step_resume);
- registers_changed ();
- ecs->waiton_pid = -1;
- ecs->wp = &(ecs->ws);
- }
- /* This is the old end of the while loop. Let everybody know
- we want to wait for the inferior some more and get called
- again soon. */
- ecs->wait_some_more = 1;
- return;
- }
+ if (!IN_SOLIB_DYNSYM_RESOLVE_CODE (sr_sal.pc))
+ step_resume_breakpoint->frame = step_frame_address;
- /* Former breaks in the main loop goto here. */
-wfi_break:
+ if (breakpoints_inserted)
+ insert_breakpoints ();
+}
-stop_stepping:
+static void
+stop_stepping (struct execution_control_state *ecs)
+{
if (target_has_execution)
{
/* Are we stopping for a vfork event? We only stop when we see
the child's event. However, we may not yet have seen the
- parent's event. And, inferior_pid is still set to the parent's
- pid, until we resume again and follow either the parent or child.
+ parent's event. And, inferior_pid is still set to the
+ parent's pid, until we resume again and follow either the
+ parent or child.
To ensure that we can really touch inferior_pid (aka, the
parent process) -- which calls to functions like read_pc
prev_func_start = ecs->stop_func_start;
prev_func_name = ecs->stop_func_name;
}
+
/* Let callers know we don't want to wait for the inferior anymore. */
ecs->wait_some_more = 0;
}
-/* Are we in the middle of stepping? */
+/* This function handles various cases where we need to continue
+ waiting for the inferior. */
+/* (Used to be the keep_going: label in the old wait_for_inferior) */
-static int
-currently_stepping (ecs)
- struct execution_control_state *ecs;
+static void
+keep_going (struct execution_control_state *ecs)
{
- return ((through_sigtramp_breakpoint == NULL
- && !ecs->handling_longjmp
- && ((step_range_end && step_resume_breakpoint == NULL)
- || trap_expected))
- || ecs->stepping_through_solib_after_catch
- || bpstat_should_step ());
+ /* ??rehrauer: ttrace on HP-UX theoretically allows one to debug a
+ vforked child between its creation and subsequent exit or call to
+ exec(). However, I had big problems in this rather creaky exec
+ engine, getting that to work. The fundamental problem is that
+ I'm trying to debug two processes via an engine that only
+ understands a single process with possibly multiple threads.
+
+ Hence, this spot is known to have problems when
+ target_can_follow_vfork_prior_to_exec returns 1. */
+
+ /* Save the pc before execution, to compare with pc after stop. */
+ prev_pc = read_pc (); /* Might have been DECR_AFTER_BREAK */
+ prev_func_start = ecs->stop_func_start; /* Ok, since if DECR_PC_AFTER
+ BREAK is defined, the
+ original pc would not have
+ been at the start of a
+ function. */
+ prev_func_name = ecs->stop_func_name;
+
+ if (ecs->update_step_sp)
+ step_sp = read_sp ();
+ ecs->update_step_sp = 0;
+
+ /* If we did not do break;, it means we should keep running the
+ inferior and not return to debugger. */
+
+ if (trap_expected && stop_signal != TARGET_SIGNAL_TRAP)
+ {
+ /* We took a signal (which we are supposed to pass through to
+ the inferior, else we'd have done a break above) and we
+ haven't yet gotten our trap. Simply continue. */
+ resume (currently_stepping (ecs), stop_signal);
+ }
+ else
+ {
+ /* Either the trap was not expected, but we are continuing
+ anyway (the user asked that this signal be passed to the
+ child)
+ -- or --
+ The signal was SIGTRAP, e.g. it was our signal, but we
+ decided we should resume from it.
+
+ We're going to run this baby now!
+
+ Insert breakpoints now, unless we are trying to one-proceed
+ past a breakpoint. */
+ /* If we've just finished a special step resume and we don't
+ want to hit a breakpoint, pull em out. */
+ if (step_resume_breakpoint == NULL
+ && through_sigtramp_breakpoint == NULL
+ && ecs->remove_breakpoints_on_following_step)
+ {
+ ecs->remove_breakpoints_on_following_step = 0;
+ remove_breakpoints ();
+ breakpoints_inserted = 0;
+ }
+ else if (!breakpoints_inserted &&
+ (through_sigtramp_breakpoint != NULL || !ecs->another_trap))
+ {
+ breakpoints_failed = insert_breakpoints ();
+ if (breakpoints_failed)
+ {
+ stop_stepping (ecs);
+ return;
+ }
+ breakpoints_inserted = 1;
+ }
+
+ trap_expected = ecs->another_trap;
+
+ /* Do not deliver SIGNAL_TRAP (except when the user explicitly
+ specifies that such a signal should be delivered to the
+ target program).
+
+ Typically, this would occure when a user is debugging a
+ target monitor on a simulator: the target monitor sets a
+ breakpoint; the simulator encounters this break-point and
+ halts the simulation handing control to GDB; GDB, noteing
+ that the break-point isn't valid, returns control back to the
+ simulator; the simulator then delivers the hardware
+ equivalent of a SIGNAL_TRAP to the program being debugged. */
+
+ if (stop_signal == TARGET_SIGNAL_TRAP
+ && !signal_program[stop_signal])
+ stop_signal = TARGET_SIGNAL_0;
+
+#ifdef SHIFT_INST_REGS
+ /* I'm not sure when this following segment applies. I do know,
+ now, that we shouldn't rewrite the regs when we were stopped
+ by a random signal from the inferior process. */
+ /* FIXME: Shouldn't this be based on the valid bit of the SXIP?
+ (this is only used on the 88k). */
+
+ if (!bpstat_explains_signal (stop_bpstat)
+ && (stop_signal != TARGET_SIGNAL_CHLD)
+ && !stopped_by_random_signal)
+ SHIFT_INST_REGS ();
+#endif /* SHIFT_INST_REGS */
+
+ resume (currently_stepping (ecs), stop_signal);
+ }
+
+ prepare_to_wait (ecs);
+}
+
+/* This function normally comes after a resume, before
+ handle_inferior_event exits. It takes care of any last bits of
+ housekeeping, and sets the all-important wait_some_more flag. */
+
+static void
+prepare_to_wait (struct execution_control_state *ecs)
+{
+ if (ecs->infwait_state == infwait_normal_state)
+ {
+ overlay_cache_invalid = 1;
+
+ /* We have to invalidate the registers BEFORE calling
+ target_wait because they can be loaded from the target while
+ in target_wait. This makes remote debugging a bit more
+ efficient for those targets that provide critical registers
+ as part of their normal status mechanism. */
+
+ registers_changed ();
+ ecs->waiton_pid = -1;
+ ecs->wp = &(ecs->ws);
+ }
+ /* This is the old end of the while loop. Let everybody know we
+ want to wait for the inferior some more and get called again
+ soon. */
+ ecs->wait_some_more = 1;
}
/* This function returns TRUE if ep is an internal breakpoint
something gdb sets for its own use, and isn't ever shown to a
user.) */
static int
-is_internal_shlib_eventpoint (ep)
- struct breakpoint *ep;
+is_internal_shlib_eventpoint (struct breakpoint *ep)
{
return
(ep->type == bp_shlib_event)
/* This function returns TRUE if bs indicates that the inferior
stopped due to a shared library (aka dynamically-linked library)
event. */
+
static int
-stopped_for_internal_shlib_event (bs)
- bpstat bs;
+stopped_for_internal_shlib_event (bpstat bs)
{
/* Note that multiple eventpoints may've caused the stop. Any
that are associated with shlib events will be accepted. */
/* If we get here, then no candidate was found. */
return 0;
}
-
-/* This function returns TRUE if bs indicates that the inferior
- stopped due to a shared library (aka dynamically-linked library)
- event caught by a catchpoint.
-
- If TRUE, cp_p is set to point to the catchpoint.
-
- Else, the value of cp_p is undefined. */
-static int
-stopped_for_shlib_catchpoint (bs, cp_p)
- bpstat bs;
- struct breakpoint **cp_p;
-{
- /* Note that multiple eventpoints may've caused the stop. Any
- that are associated with shlib events will be accepted. */
- *cp_p = NULL;
-
- for (; bs != NULL; bs = bs->next)
- {
- if ((bs->breakpoint_at != NULL)
- && ep_is_shlib_catchpoint (bs->breakpoint_at))
- {
- *cp_p = bs->breakpoint_at;
- return 1;
- }
- }
-
- /* If we get here, then no candidate was found. */
- return 0;
-}
\f
-
/* Reset proper settings after an asynchronous command has finished.
If the execution command was in synchronous mode, register stdin
with the event loop, and reset the prompt. */
+
static void
-complete_execution ()
+complete_execution (void)
{
- extern cleanup_sigint_signal_handler PARAMS ((void));
-
target_executing = 0;
+
if (sync_execution)
{
- add_file_handler (input_fd, (file_handler_func *) call_readline, 0);
- pop_prompt ();
- sync_execution = 0;
- cleanup_sigint_signal_handler ();
+ do_exec_error_cleanups (ALL_CLEANUPS);
display_gdb_prompt (0);
}
+ else
+ {
+ if (exec_done_display_p)
+ printf_unfiltered ("completed.\n");
+ }
}
/* Here to return control to GDB when the inferior stops for real.
attempting to insert breakpoints. */
void
-normal_stop ()
+normal_stop (void)
{
/* As with the notification of thread events, we want to delay
notifying the user that we've switched thread context until
}
static int
-hook_stop_stub (cmd)
- PTR cmd;
+hook_stop_stub (void *cmd)
{
execute_user_command ((struct cmd_list_element *) cmd, 0);
return (0);
}
\f
int
-signal_stop_state (signo)
- int signo;
+signal_stop_state (int signo)
{
return signal_stop[signo];
}
int
-signal_print_state (signo)
- int signo;
+signal_print_state (int signo)
{
return signal_print[signo];
}
int
-signal_pass_state (signo)
- int signo;
+signal_pass_state (int signo)
{
return signal_program[signo];
}
+int signal_stop_update (signo, state)
+ int signo;
+ int state;
+{
+ int ret = signal_stop[signo];
+ signal_stop[signo] = state;
+ return ret;
+}
+
+int signal_print_update (signo, state)
+ int signo;
+ int state;
+{
+ int ret = signal_print[signo];
+ signal_print[signo] = state;
+ return ret;
+}
+
+int signal_pass_update (signo, state)
+ int signo;
+ int state;
+{
+ int ret = signal_program[signo];
+ signal_program[signo] = state;
+ return ret;
+}
+
static void
-sig_print_header ()
+sig_print_header (void)
{
printf_filtered ("\
Signal Stop\tPrint\tPass to program\tDescription\n");
}
static void
-sig_print_info (oursig)
- enum target_signal oursig;
+sig_print_info (enum target_signal oursig)
{
char *name = target_signal_to_name (oursig);
int name_padding = 13 - strlen (name);
+
if (name_padding <= 0)
name_padding = 0;
/* Specify how various signals in the inferior should be handled. */
static void
-handle_command (args, from_tty)
- char *args;
- int from_tty;
+handle_command (char *args, int from_tty)
{
char **argv;
int digits, wordlen;
}
static void
-xdb_handle_command (args, from_tty)
- char *args;
- int from_tty;
+xdb_handle_command (char *args, int from_tty)
{
char **argv;
struct cleanup *old_chain;
targets, all signals should be in the signal tables). */
static void
-signals_info (signum_exp, from_tty)
- char *signum_exp;
- int from_tty;
+signals_info (char *signum_exp, int from_tty)
{
enum target_signal oursig;
sig_print_header ();
int proceed_to_finish;
};
-
-static struct inferior_status *xmalloc_inferior_status PARAMS ((void));
static struct inferior_status *
-xmalloc_inferior_status ()
+xmalloc_inferior_status (void)
{
struct inferior_status *inf_status;
inf_status = xmalloc (sizeof (struct inferior_status));
return inf_status;
}
-static void free_inferior_status PARAMS ((struct inferior_status *));
static void
-free_inferior_status (inf_status)
- struct inferior_status *inf_status;
+free_inferior_status (struct inferior_status *inf_status)
{
free (inf_status->registers);
free (inf_status->stop_registers);
}
void
-write_inferior_status_register (inf_status, regno, val)
- struct inferior_status *inf_status;
- int regno;
- LONGEST val;
+write_inferior_status_register (struct inferior_status *inf_status, int regno,
+ LONGEST val)
{
int size = REGISTER_RAW_SIZE (regno);
void *buf = alloca (size);
memcpy (&inf_status->registers[REGISTER_BYTE (regno)], buf, size);
}
-
-
/* 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). */
struct inferior_status *
-save_inferior_status (restore_stack_info)
- int restore_stack_info;
+save_inferior_status (int restore_stack_info)
{
struct inferior_status *inf_status = xmalloc_inferior_status ();
int level;
};
-static int restore_selected_frame PARAMS ((PTR));
-
static int
-restore_selected_frame (args)
- PTR args;
+restore_selected_frame (void *args)
{
struct restore_selected_frame_args *fr =
(struct restore_selected_frame_args *) args;
}
void
-restore_inferior_status (inf_status)
- struct inferior_status *inf_status;
+restore_inferior_status (struct inferior_status *inf_status)
{
stop_signal = inf_status->stop_signal;
stop_pc = inf_status->stop_pc;
}
void
-discard_inferior_status (inf_status)
- struct inferior_status *inf_status;
+discard_inferior_status (struct inferior_status *inf_status)
{
/* See save_inferior_status for info on stop_bpstat. */
bpstat_clear (&inf_status->stop_bpstat);
}
static void
-set_follow_fork_mode_command (arg, from_tty, c)
- char *arg;
- int from_tty;
- struct cmd_list_element *c;
+set_follow_fork_mode_command (char *arg, int from_tty,
+ struct cmd_list_element *c)
{
if (!STREQ (arg, "parent") &&
!STREQ (arg, "child") &&
follow_fork_mode_string = savestring (arg, strlen (arg));
}
\f
-
-
-static void build_infrun PARAMS ((void));
static void
-build_infrun ()
+build_infrun (void)
{
stop_registers = xmalloc (REGISTER_BYTES);
}
-
void
-_initialize_infrun ()
+_initialize_infrun (void)
{
register int i;
register int numsigs;