/* Target-struct-independent code to start (run) and stop an inferior process.
- Copyright 1986-1989, 1991-2000 Free Software Foundation, Inc.
+ Copyright 1986, 1987, 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995,
+ 1996, 1997, 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
This file is part of GDB.
#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 "symfile.h" /* for overlay functions */
+#include "symfile.h"
#include "top.h"
#include <signal.h>
#include "inf-loop.h"
+#include "regcache.h"
/* Prototypes for local functions */
static void sig_print_header (void);
-static void resume_cleanups (int);
+static void resume_cleanups (void *);
static int hook_stop_stub (void *);
int inferior_ignoring_startup_exec_events = 0;
int inferior_ignoring_leading_exec_events = 0;
+/* 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. */
+int step_stop_if_no_debug = 0;
+
/* In asynchronous mode, but simulating synchronous execution. */
int sync_execution = 0;
when the inferior stopped in a different thread than it had been
running in. */
-static int previous_inferior_pid;
+static ptid_t previous_inferior_ptid;
/* This is true for configurations that may follow through execl() and
similar functions. At present this is only true for HP-UX native. */
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 HAVE_CONTINUABLE_WATCHPOINT 1
#endif
+#ifndef CANNOT_STEP_HW_WATCHPOINTS
+#define CANNOT_STEP_HW_WATCHPOINTS 0
+#else
+#undef CANNOT_STEP_HW_WATCHPOINTS
+#define CANNOT_STEP_HW_WATCHPOINTS 1
+#endif
+
/* Tables of how to react to signals; the user sets them. */
static unsigned char *signal_stop;
(flags)[signum] = 0; \
} while (0)
+/* Value to pass to target_resume() to cause all threads to resume */
+
+#define RESUME_ALL (pid_to_ptid (-1))
/* Command list pointer for the "stop" placeholder. */
currently be running in a syscall. */
static int number_of_threads_in_syscalls;
+/* This is a cached copy of the pid/waitstatus of the last event
+ returned by target_wait()/target_wait_hook(). This information is
+ returned by get_last_target_status(). */
+static ptid_t target_last_wait_ptid;
+static struct target_waitstatus target_last_waitstatus;
+
/* This is used to remember when a fork, vfork or exec event
was caught by a catchpoint, and thus the event is to be
followed at the next resume of the inferior, and not
set to 1, a vfork event has been seen, but cannot be followed
until the exec is seen.
- (In the latter case, inferior_pid is still the parent of the
+ (In the latter case, inferior_ptid is still the parent of the
vfork, and pending_follow.fork_event.child_pid is the child. The
appropriate process is followed, according to the setting of
follow-fork-mode.) */
static int follow_vfork_when_exec;
-static char *follow_fork_mode_kind_names[] =
+static const char follow_fork_mode_ask[] = "ask";
+static const char follow_fork_mode_both[] = "both";
+static const char follow_fork_mode_child[] = "child";
+static const char follow_fork_mode_parent[] = "parent";
+
+static const char *follow_fork_mode_kind_names[] =
{
-/* ??rehrauer: The "both" option is broken, by what may be a 10.20
- kernel problem. It's also not terribly useful without a GUI to
- help the user drive two debuggers. So for now, I'm disabling
- the "both" option.
- "parent", "child", "both", "ask" };
- */
- "parent", "child", "ask"};
+ follow_fork_mode_ask,
+ /* ??rehrauer: The "both" option is broken, by what may be a 10.20
+ kernel problem. It's also not terribly useful without a GUI to
+ help the user drive two debuggers. So for now, I'm disabling the
+ "both" option. */
+ /* follow_fork_mode_both, */
+ follow_fork_mode_child,
+ follow_fork_mode_parent,
+ NULL
+};
-static char *follow_fork_mode_string = NULL;
+static const char *follow_fork_mode_string = follow_fork_mode_parent;
\f
static void
int followed_child = 0;
/* Which process did the user want us to follow? */
- char *follow_mode =
- savestring (follow_fork_mode_string, strlen (follow_fork_mode_string));
+ const char *follow_mode = follow_fork_mode_string;
/* Or, did the user not know, and want us to ask? */
- if (STREQ (follow_fork_mode_string, "ask"))
+ if (follow_fork_mode_string == follow_fork_mode_ask)
{
- char requested_mode[100];
-
- free (follow_mode);
- error ("\"ask\" mode NYI");
- follow_mode = savestring (requested_mode, strlen (requested_mode));
+ internal_error (__FILE__, __LINE__,
+ "follow_inferior_fork: \"ask\" mode not implemented");
+ /* follow_mode = follow_fork_mode_...; */
}
/* If we're to be following the parent, then detach from child_pid.
We're already following the parent, so need do nothing explicit
for it. */
- if (STREQ (follow_mode, "parent"))
+ if (follow_mode == follow_fork_mode_parent)
{
followed_parent = 1;
}
/* If we're to be following the child, then attach to it, detach
- from inferior_pid, and set inferior_pid to child_pid. */
- else if (STREQ (follow_mode, "child"))
+ from inferior_ptid, and set inferior_ptid to child_pid. */
+ else if (follow_mode == follow_fork_mode_child)
{
char child_pid_spelling[100]; /* Arbitrary length. */
/* Also reset the solib inferior hook from the parent. */
#ifdef SOLIB_REMOVE_INFERIOR_HOOK
- SOLIB_REMOVE_INFERIOR_HOOK (inferior_pid);
+ SOLIB_REMOVE_INFERIOR_HOOK (PIDGET (inferior_ptid));
#endif
/* Detach from the parent. */
target_detach (NULL, 1);
/* Attach to the child. */
- inferior_pid = child_pid;
+ inferior_ptid = pid_to_ptid (child_pid);
sprintf (child_pid_spelling, "%d", child_pid);
dont_repeat ();
/* If we're to be following both parent and child, then fork ourselves,
and attach the debugger clone to the child. */
- else if (STREQ (follow_mode, "both"))
+ else if (follow_mode == follow_fork_mode_both)
{
char pid_suffix[100]; /* Arbitrary length. */
/* We continue to follow the parent. To help distinguish the two
debuggers, though, both we and our clone will reset our prompts. */
- sprintf (pid_suffix, "[%d] ", inferior_pid);
+ sprintf (pid_suffix, "[%d] ", PIDGET (inferior_ptid));
set_prompt (strcat (get_prompt (), pid_suffix));
}
pending_follow.fork_event.saw_parent_fork = 0;
pending_follow.fork_event.saw_child_fork = 0;
-
- free (follow_mode);
}
static void
follow_inferior_fork (parent_pid, child_pid, 0, 1);
/* Did we follow the child? Had it exec'd before we saw the parent vfork? */
- if (pending_follow.fork_event.saw_child_exec && (inferior_pid == child_pid))
+ if (pending_follow.fork_event.saw_child_exec
+ && (PIDGET (inferior_ptid) == child_pid))
{
pending_follow.fork_event.saw_child_exec = 0;
pending_follow.kind = TARGET_WAITKIND_SPURIOUS;
- follow_exec (inferior_pid, pending_follow.execd_pathname);
- free (pending_follow.execd_pathname);
+ follow_exec (PIDGET (inferior_ptid), pending_follow.execd_pathname);
+ xfree (pending_follow.execd_pathname);
}
}
+/* EXECD_PATHNAME is assumed to be non-NULL. */
+
static void
follow_exec (int pid, char *execd_pathname)
{
(pending_follow.kind == TARGET_WAITKIND_VFORKED))
{
pending_follow.kind = TARGET_WAITKIND_SPURIOUS;
- follow_vfork (inferior_pid, pending_follow.fork_event.child_pid);
+ follow_vfork (PIDGET (inferior_ptid),
+ pending_follow.fork_event.child_pid);
follow_vfork_when_exec = 0;
- saved_pid = inferior_pid;
+ saved_pid = PIDGET (inferior_ptid);
/* Did we follow the parent? If so, we're done. If we followed
the child then we must also follow its exec(). */
- if (inferior_pid == pending_follow.fork_event.parent_pid)
+ if (PIDGET (inferior_ptid) == pending_follow.fork_event.parent_pid)
return;
}
gdb_flush (gdb_stdout);
target_mourn_inferior ();
- inferior_pid = saved_pid; /* Because mourn_inferior resets inferior_pid. */
+ inferior_ptid = pid_to_ptid (saved_pid);
+ /* Because mourn_inferior resets inferior_ptid. */
push_target (tgt);
/* That a.out is now the one to use. */
exec_file_attach (execd_pathname, 0);
/* And also is where symbols can be found. */
- symbol_file_command (execd_pathname, 0);
+ symbol_file_add_main (execd_pathname, 0);
/* Reset the shared library package. This ensures that we get
a shlib event when the child reaches "_start", at which point
SOLIB_RESTART ();
#endif
#ifdef SOLIB_CREATE_INFERIOR_HOOK
- SOLIB_CREATE_INFERIOR_HOOK (inferior_pid);
+ SOLIB_CREATE_INFERIOR_HOOK (PIDGET (inferior_ptid));
#endif
/* Reinsert all breakpoints. (Those which were symbolic have
/* Things to clean up if we QUIT out of resume (). */
/* ARGSUSED */
static void
-resume_cleanups (int arg)
+resume_cleanups (void *ignore)
{
normal_stop ();
}
-static char schedlock_off[] = "off";
-static char schedlock_on[] = "on";
-static char schedlock_step[] = "step";
-static char *scheduler_mode = schedlock_off;
-static char *scheduler_enums[] =
-{schedlock_off, schedlock_on, schedlock_step};
+static const char schedlock_off[] = "off";
+static const char schedlock_on[] = "on";
+static const char schedlock_step[] = "step";
+static const char *scheduler_mode = schedlock_off;
+static const char *scheduler_enums[] =
+{
+ schedlock_off,
+ schedlock_on,
+ schedlock_step,
+ NULL
+};
static void
set_schedlock_func (char *args, int from_tty, struct cmd_list_element *c)
}
-
-
/* 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
resume (int step, enum target_signal sig)
{
int should_resume = 1;
- struct cleanup *old_cleanups = make_cleanup ((make_cleanup_func)
- resume_cleanups, 0);
+ 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
+ a hardware watchpoint. The kernel properly notices that it shouldn't
+ stop, because the hardware watchpoint is not triggered, but it forgets
+ the step request and continues the program normally.
+ Work around the problem by removing hardware watchpoints if a step is
+ requested, GDB will check for a hardware watchpoint trigger after the
+ step anyway. */
+ if (CANNOT_STEP_HW_WATCHPOINTS && step && breakpoints_inserted)
+ remove_hw_watchpoints ();
+
/* Normally, by the time we reach `resume', the breakpoints are either
removed or inserted, as appropriate. The exception is if we're sitting
if (breakpoint_here_p (read_pc ()) == permanent_breakpoint_here)
SKIP_PERMANENT_BREAKPOINT ();
- if (SOFTWARE_SINGLE_STEP_P && step)
+ if (SOFTWARE_SINGLE_STEP_P () && step)
{
/* Do it the hard way, w/temp breakpoints */
SOFTWARE_SINGLE_STEP (sig, 1 /*insert-breakpoints */ );
{
case (TARGET_WAITKIND_FORKED):
pending_follow.kind = TARGET_WAITKIND_SPURIOUS;
- follow_fork (inferior_pid, pending_follow.fork_event.child_pid);
+ follow_fork (PIDGET (inferior_ptid),
+ pending_follow.fork_event.child_pid);
break;
case (TARGET_WAITKIND_VFORKED):
int saw_child_exec = pending_follow.fork_event.saw_child_exec;
pending_follow.kind = TARGET_WAITKIND_SPURIOUS;
- follow_vfork (inferior_pid, pending_follow.fork_event.child_pid);
+ follow_vfork (PIDGET (inferior_ptid),
+ pending_follow.fork_event.child_pid);
/* Did we follow the child, but not yet see the child's exec event?
If so, then it actually ought to be waiting for us; we respond to
parent vfork events. We don't actually want to resume the child
in this situation; we want to just get its exec event. */
if (!saw_child_exec &&
- (inferior_pid == pending_follow.fork_event.child_pid))
+ (PIDGET (inferior_ptid) == pending_follow.fork_event.child_pid))
should_resume = 0;
}
break;
if (should_resume)
{
- int resume_pid;
+ 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_pid = -1;
- }
- else
- {
- if (!step)
- {
- warning ("Internal error, changing continue to step.");
- remove_breakpoints ();
- breakpoints_inserted = 0;
- trap_expected = 1;
- step = 1;
- }
- resume_pid = inferior_pid;
- }
+ 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))
- resume_pid = inferior_pid;
- else
- resume_pid = -1;
+ /* User-settable 'scheduler' mode requires solo thread resume. */
+ resume_ptid = inferior_ptid;
}
- target_resume (resume_pid, step, sig);
+
+#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);
}
discard_cleanups (old_cleanups);
step_range_start = 0;
step_range_end = 0;
step_frame_address = 0;
- step_over_calls = -1;
+ step_over_calls = STEP_OVER_UNDEBUGGABLE;
stop_after_trap = 0;
stop_soon_quietly = 0;
proceed_to_finish = 0;
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 */
int temp = insert_breakpoints ();
if (temp)
{
- print_sys_errmsg ("ptrace", temp);
+ print_sys_errmsg ("insert_breakpoints", temp);
error ("Cannot insert breakpoints.\n\
-The same program may be running in another process.");
+The same program may be running in another process,\n\
+or you may have requested too many hardware\n\
+breakpoints and/or watchpoints.\n");
}
breakpoints_inserted = 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
+ indicate to 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
int current_line;
struct symtab *current_symtab;
int handling_longjmp; /* FIXME */
- int pid;
- int saved_inferior_pid;
+ ptid_t ptid;
+ ptid_t saved_inferior_ptid;
int update_step_sp;
int stepping_through_solib_after_catch;
bpstat stepping_through_solib_catchpoints;
int new_thread_event;
struct target_waitstatus tmpstatus;
enum infwait_states infwait_state;
- int waiton_pid;
+ ptid_t waiton_ptid;
int wait_some_more;
};
struct execution_control_state ecss;
struct execution_control_state *ecs;
- old_cleanups = make_cleanup (delete_breakpoint_current_contents,
+ old_cleanups = make_cleanup (delete_step_resume_breakpoint,
&step_resume_breakpoint);
make_cleanup (delete_breakpoint_current_contents,
&through_sigtramp_breakpoint);
/* 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_pid = inferior_pid;
+ previous_inferior_ptid = inferior_ptid;
overlay_cache_invalid = 1;
while (1)
{
if (target_wait_hook)
- ecs->pid = target_wait_hook (ecs->waiton_pid, ecs->wp);
+ ecs->ptid = target_wait_hook (ecs->waiton_ptid, ecs->wp);
else
- ecs->pid = target_wait (ecs->waiton_pid, ecs->wp);
+ ecs->ptid = target_wait (ecs->waiton_ptid, ecs->wp);
/* Now figure out what to do with the result of the result. */
handle_inferior_event (ecs);
struct execution_control_state *async_ecs;
void
-fetch_inferior_event (client_data)
- void *client_data;
+fetch_inferior_event (void *client_data)
{
static struct cleanup *old_cleanups;
if (!async_ecs->wait_some_more)
{
- old_cleanups = make_exec_cleanup (delete_breakpoint_current_contents,
+ old_cleanups = make_exec_cleanup (delete_step_resume_breakpoint,
&step_resume_breakpoint);
make_exec_cleanup (delete_breakpoint_current_contents,
&through_sigtramp_breakpoint);
/* 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_pid = inferior_pid;
+ previous_inferior_ptid = inferior_ptid;
overlay_cache_invalid = 1;
}
if (target_wait_hook)
- async_ecs->pid = target_wait_hook (async_ecs->waiton_pid, async_ecs->wp);
+ async_ecs->ptid = target_wait_hook (async_ecs->waiton_ptid, async_ecs->wp);
else
- async_ecs->pid = target_wait (async_ecs->waiton_pid, async_ecs->wp);
+ async_ecs->ptid = target_wait (async_ecs->waiton_ptid, async_ecs->wp);
/* Now figure out what to do with the result of the result. */
handle_inferior_event (async_ecs);
ecs->current_line = ecs->sal.line;
ecs->current_symtab = ecs->sal.symtab;
ecs->infwait_state = infwait_normal_state;
- ecs->waiton_pid = -1;
+ ecs->waiton_ptid = pid_to_ptid (-1);
ecs->wp = &(ecs->ws);
}
warning ("GDB bug: infrun.c (wait_for_inferior): dropping old step_resume breakpoint");
}
+/* Return the cached copy of the last pid/waitstatus returned by
+ target_wait()/target_wait_hook(). The data is actually cached by
+ handle_inferior_event(), which gets called immediately after
+ target_wait()/target_wait_hook(). */
+
+void
+get_last_target_status(ptid_t *ptidp, struct target_waitstatus *status)
+{
+ *ptidp = target_last_wait_ptid;
+ *status = target_last_waitstatus;
+}
+
+/* Switch thread contexts, maintaining "infrun state". */
+
+static void
+context_switch (struct execution_control_state *ecs)
+{
+ /* Caution: it may happen that the new thread (or the old one!)
+ is not in the thread list. In this case we must not attempt
+ to "switch context", or we run the risk that our context may
+ be lost. This may happen as a result of the target module
+ mishandling thread creation. */
+
+ if (in_thread_list (inferior_ptid) && in_thread_list (ecs->ptid))
+ { /* Perform infrun state context switch: */
+ /* Save infrun state for the old thread. */
+ save_infrun_state (inferior_ptid, prev_pc,
+ prev_func_start, prev_func_name,
+ trap_expected, step_resume_breakpoint,
+ through_sigtramp_breakpoint, step_range_start,
+ step_range_end, step_frame_address,
+ ecs->handling_longjmp, ecs->another_trap,
+ ecs->stepping_through_solib_after_catch,
+ ecs->stepping_through_solib_catchpoints,
+ ecs->stepping_through_sigtramp,
+ ecs->current_line, ecs->current_symtab,
+ step_sp);
+
+ /* Load infrun state for the new thread. */
+ load_infrun_state (ecs->ptid, &prev_pc,
+ &prev_func_start, &prev_func_name,
+ &trap_expected, &step_resume_breakpoint,
+ &through_sigtramp_breakpoint, &step_range_start,
+ &step_range_end, &step_frame_address,
+ &ecs->handling_longjmp, &ecs->another_trap,
+ &ecs->stepping_through_solib_after_catch,
+ &ecs->stepping_through_solib_catchpoints,
+ &ecs->stepping_through_sigtramp,
+ &ecs->current_line, &ecs->current_symtab,
+ &step_sp);
+ }
+ inferior_ptid = ecs->ptid;
+}
+
+
/* 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. */
CORE_ADDR tmp;
int stepped_after_stopped_by_watchpoint;
+ /* Cache the last pid/waitstatus. */
+ target_last_wait_ptid = ecs->ptid;
+ target_last_waitstatus = *ecs->wp;
+
/* Keep this extra brace for now, minimizes diffs. */
{
switch (ecs->infwait_state)
{
- 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;
+ case infwait_thread_hop_state:
+ /* Cancel the waiton_ptid. */
+ ecs->waiton_ptid = pid_to_ptid (-1);
+ /* Fall thru to the normal_state case. */
+ case infwait_normal_state:
/* See comments where a TARGET_WAITKIND_SYSCALL_RETURN event
is serviced in this loop, below. */
if (ecs->enable_hw_watchpoints_after_wait)
{
- TARGET_ENABLE_HW_WATCHPOINTS (inferior_pid);
+ TARGET_ENABLE_HW_WATCHPOINTS (PIDGET (inferior_ptid));
ecs->enable_hw_watchpoints_after_wait = 0;
}
stepped_after_stopped_by_watchpoint = 0;
break;
- case infwait_thread_hop_state:
- insert_breakpoints ();
-
- /* We need to restart all the threads now,
- * unles we're running in scheduler-locked mode.
- * FIXME: shouldn't we look at currently_stepping ()?
- */
- if (scheduler_mode == schedlock_on)
- target_resume (ecs->pid, 0, TARGET_SIGNAL_0);
- else
- target_resume (-1, 0, TARGET_SIGNAL_0);
- ecs->infwait_state = infwait_normal_state;
- prepare_to_wait (ecs);
- return;
-
case infwait_nullified_state:
break;
/* If it's a new process, add it to the thread database */
- ecs->new_thread_event = ((ecs->pid != inferior_pid) && !in_thread_list (ecs->pid));
+ ecs->new_thread_event = (! ptid_equal (ecs->ptid, inferior_ptid)
+ && ! in_thread_list (ecs->ptid));
if (ecs->ws.kind != TARGET_WAITKIND_EXITED
&& ecs->ws.kind != TARGET_WAITKIND_SIGNALLED
&& ecs->new_thread_event)
{
- add_thread (ecs->pid);
+ add_thread (ecs->ptid);
#ifdef UI_OUT
ui_out_text (uiout, "[New ");
- ui_out_text (uiout, target_pid_or_tid_to_str (ecs->pid));
+ ui_out_text (uiout, target_pid_or_tid_to_str (ecs->ptid));
ui_out_text (uiout, "]\n");
#else
- printf_filtered ("[New %s]\n", target_pid_or_tid_to_str (ecs->pid));
+ printf_filtered ("[New %s]\n", target_pid_or_tid_to_str (ecs->ptid));
#endif
#if 0
Therefore we need to continue all threads in order to
make progress. */
- target_resume (-1, 0, TARGET_SIGNAL_0);
+ target_resume (RESUME_ALL, 0, TARGET_SIGNAL_0);
prepare_to_wait (ecs);
return;
#endif
(LONGEST) ecs->ws.value.integer));
gdb_flush (gdb_stdout);
target_mourn_inferior ();
- singlestep_breakpoints_inserted_p = 0; /*SOFTWARE_SINGLE_STEP_P */
+ singlestep_breakpoints_inserted_p = 0; /*SOFTWARE_SINGLE_STEP_P() */
stop_print_frame = 0;
stop_stepping (ecs);
return;
stop_signal = ecs->ws.value.sig;
target_terminal_ours (); /* Must do this before mourn anyway */
- /* This looks pretty bogus to me. Doesn't TARGET_WAITKIND_SIGNALLED
- mean it is already dead? This has been here since GDB 2.8, so
- perhaps it means rms didn't understand unix waitstatuses?
- For the moment I'm just kludging around this in remote.c
- rather than trying to change it here --kingdon, 5 Dec 1994. */
- target_kill (); /* kill mourns as well */
+ /* Note: By definition of TARGET_WAITKIND_SIGNALLED, we shouldn't
+ reach here unless the inferior is dead. However, for years
+ target_kill() was called here, which hints that fatal signals aren't
+ really fatal on some systems. If that's true, then some changes
+ may be needed. */
+ target_mourn_inferior ();
print_stop_reason (SIGNAL_EXITED, stop_signal);
- singlestep_breakpoints_inserted_p = 0; /*SOFTWARE_SINGLE_STEP_P */
+ singlestep_breakpoints_inserted_p = 0; /*SOFTWARE_SINGLE_STEP_P() */
stop_stepping (ecs);
return;
interested in reacting to forks of the child. Note that
we expect the child's fork event to be available if we
waited for it now. */
- if (inferior_pid == ecs->pid)
+ if (ptid_equal (inferior_ptid, ecs->ptid))
{
pending_follow.fork_event.saw_parent_fork = 1;
- pending_follow.fork_event.parent_pid = ecs->pid;
+ pending_follow.fork_event.parent_pid = PIDGET (ecs->ptid);
pending_follow.fork_event.child_pid = ecs->ws.value.related_pid;
prepare_to_wait (ecs);
return;
else
{
pending_follow.fork_event.saw_child_fork = 1;
- pending_follow.fork_event.child_pid = ecs->pid;
+ pending_follow.fork_event.child_pid = PIDGET (ecs->ptid);
pending_follow.fork_event.parent_pid = ecs->ws.value.related_pid;
}
- stop_pc = read_pc_pid (ecs->pid);
- ecs->saved_inferior_pid = inferior_pid;
- inferior_pid = ecs->pid;
- stop_bpstat = bpstat_stop_status (&stop_pc, currently_stepping (ecs));
+ stop_pc = read_pc_pid (ecs->ptid);
+ ecs->saved_inferior_ptid = inferior_ptid;
+ inferior_ptid = ecs->ptid;
+ /* 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_pid = ecs->saved_inferior_pid;
+ inferior_ptid = ecs->saved_inferior_ptid;
goto process_event_stop_test;
/* If this a platform which doesn't allow a debugger to touch a
it execs, and the child has not yet exec'd. We probably
should warn the user to that effect when the catchpoint
triggers...) */
- if (ecs->pid == inferior_pid)
+ if (ptid_equal (ecs->ptid, inferior_ptid))
{
pending_follow.fork_event.saw_parent_fork = 1;
- pending_follow.fork_event.parent_pid = ecs->pid;
+ pending_follow.fork_event.parent_pid = PIDGET (ecs->ptid);
pending_follow.fork_event.child_pid = ecs->ws.value.related_pid;
}
else
{
pending_follow.fork_event.saw_child_fork = 1;
- pending_follow.fork_event.child_pid = ecs->pid;
+ pending_follow.fork_event.child_pid = PIDGET (ecs->ptid);
pending_follow.fork_event.parent_pid = ecs->ws.value.related_pid;
- target_post_startup_inferior (pending_follow.fork_event.child_pid);
+ target_post_startup_inferior (
+ pid_to_ptid (pending_follow.fork_event.child_pid));
follow_vfork_when_exec = !target_can_follow_vfork_prior_to_exec ();
if (follow_vfork_when_exec)
{
- target_resume (ecs->pid, 0, TARGET_SIGNAL_0);
+ target_resume (ecs->ptid, 0, TARGET_SIGNAL_0);
prepare_to_wait (ecs);
return;
}
}
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;
inferior_ignoring_leading_exec_events--;
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);
+ target_resume (ecs->ptid, 0, TARGET_SIGNAL_0);
prepare_to_wait (ecs);
return;
}
savestring (ecs->ws.value.execd_pathname,
strlen (ecs->ws.value.execd_pathname));
- /* Did inferior_pid exec, or did a (possibly not-yet-followed)
+ /* Did inferior_ptid exec, or did a (possibly not-yet-followed)
child of a vfork exec?
??rehrauer: This is unabashedly an HP-UX specific thing. On
the parent vfork event is delivered. A single-step
suffices. */
if (RESUME_EXECD_VFORKING_CHILD_TO_GET_PARENT_VFORK ())
- target_resume (ecs->pid, 1, TARGET_SIGNAL_0);
+ target_resume (ecs->ptid, 1, TARGET_SIGNAL_0);
/* We expect the parent vfork event to be available now. */
prepare_to_wait (ecs);
return;
/* This causes the eventpoints and symbol table to be reset. Must
do this now, before trying to determine whether to stop. */
- follow_exec (inferior_pid, pending_follow.execd_pathname);
- free (pending_follow.execd_pathname);
-
- stop_pc = read_pc_pid (ecs->pid);
- ecs->saved_inferior_pid = inferior_pid;
- inferior_pid = ecs->pid;
- stop_bpstat = bpstat_stop_status (&stop_pc, currently_stepping (ecs));
+ follow_exec (PIDGET (inferior_ptid), pending_follow.execd_pathname);
+ xfree (pending_follow.execd_pathname);
+
+ stop_pc = read_pc_pid (ecs->ptid);
+ ecs->saved_inferior_ptid = inferior_ptid;
+ inferior_ptid = ecs->ptid;
+ /* 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_pid = ecs->saved_inferior_pid;
+ inferior_ptid = ecs->saved_inferior_ptid;
goto process_event_stop_test;
/* These syscall events are returned on HP-UX, as part of its
number_of_threads_in_syscalls++;
if (number_of_threads_in_syscalls == 1)
{
- TARGET_DISABLE_HW_WATCHPOINTS (inferior_pid);
+ TARGET_DISABLE_HW_WATCHPOINTS (PIDGET (inferior_ptid));
}
resume (0, TARGET_SIGNAL_0);
prepare_to_wait (ecs);
here, which will be serviced immediately after the target
is waited on. */
case TARGET_WAITKIND_SYSCALL_RETURN:
- target_resume (ecs->pid, 1, TARGET_SIGNAL_0);
+ target_resume (ecs->ptid, 1, TARGET_SIGNAL_0);
if (number_of_threads_in_syscalls > 0)
{
all threads in order to make progress. */
if (ecs->new_thread_event)
{
- target_resume (-1, 0, TARGET_SIGNAL_0);
+ target_resume (RESUME_ALL, 0, TARGET_SIGNAL_0);
prepare_to_wait (ecs);
return;
}
- stop_pc = read_pc_pid (ecs->pid);
+ stop_pc = read_pc_pid (ecs->ptid);
/* See if a thread hit a thread-specific breakpoint that was meant for
another thread. If so, then step that thread past the breakpoint,
if (stop_signal == TARGET_SIGNAL_TRAP)
{
- if (SOFTWARE_SINGLE_STEP_P && singlestep_breakpoints_inserted_p)
+ if (SOFTWARE_SINGLE_STEP_P () && singlestep_breakpoints_inserted_p)
ecs->random_signal = 0;
else if (breakpoints_inserted
&& breakpoint_here_p (stop_pc - DECR_PC_AFTER_BREAK))
{
ecs->random_signal = 0;
if (!breakpoint_thread_match (stop_pc - DECR_PC_AFTER_BREAK,
- ecs->pid))
+ ecs->ptid))
{
int remove_status;
/* Saw a breakpoint, but it was hit by the wrong thread.
Just continue. */
- write_pc_pid (stop_pc - DECR_PC_AFTER_BREAK, ecs->pid);
+ 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->pid);
+ /* 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
+ * step or continue.
+ */
+ /* FIXME MVS: is there any reason not to call resume()? */
+ if (scheduler_mode == schedlock_on)
+ target_resume (ecs->ptid,
+ currently_stepping (ecs),
+ TARGET_SIGNAL_0);
+ else
+ target_resume (RESUME_ALL,
+ currently_stepping (ecs),
+ TARGET_SIGNAL_0);
+ prepare_to_wait (ecs);
+ return;
}
else
{ /* Single step */
- target_resume (ecs->pid, 1, TARGET_SIGNAL_0);
- /* FIXME: What if a signal arrives instead of the
- single-step happening? */
-
- ecs->waiton_pid = ecs->pid;
+ breakpoints_inserted = 0;
+ if (!ptid_equal (inferior_ptid, ecs->ptid))
+ context_switch (ecs);
+ ecs->waiton_ptid = ecs->ptid;
ecs->wp = &(ecs->ws);
+ ecs->another_trap = 1;
+
ecs->infwait_state = infwait_thread_hop_state;
- prepare_to_wait (ecs);
+ keep_going (ecs);
+ registers_changed ();
return;
}
-
- /* We need to restart all the threads now,
- * unles we're running in scheduler-locked mode.
- * FIXME: shouldn't we look at currently_stepping ()?
- */
- if (scheduler_mode == schedlock_on)
- target_resume (ecs->pid, 0, TARGET_SIGNAL_0);
- else
- target_resume (-1, 0, TARGET_SIGNAL_0);
- prepare_to_wait (ecs);
- 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;
}
}
}
Note that if there's any kind of pending follow (i.e., of a fork,
vfork or exec), we don't want to do this now. Rather, we'll let
the next resume handle it. */
- if ((ecs->pid != inferior_pid) &&
+ if (! ptid_equal (ecs->ptid, inferior_ptid) &&
(pending_follow.kind == TARGET_WAITKIND_SPURIOUS))
{
int printed = 0;
if (signal_program[stop_signal] == 0)
stop_signal = TARGET_SIGNAL_0;
- target_resume (ecs->pid, 0, stop_signal);
+ target_resume (ecs->ptid, 0, stop_signal);
prepare_to_wait (ecs);
return;
}
/* It's a SIGTRAP or a signal we're interested in. Switch threads,
and fall into the rest of wait_for_inferior(). */
- /* Caution: it may happen that the new thread (or the old one!)
- is not in the thread list. In this case we must not attempt
- to "switch context", or we run the risk that our context may
- be lost. This may happen as a result of the target module
- mishandling thread creation. */
-
- if (in_thread_list (inferior_pid) && in_thread_list (ecs->pid))
- { /* Perform infrun state context switch: */
- /* Save infrun state for the old thread. */
- save_infrun_state (inferior_pid, prev_pc,
- prev_func_start, prev_func_name,
- trap_expected, step_resume_breakpoint,
- through_sigtramp_breakpoint,
- step_range_start, step_range_end,
- step_frame_address, ecs->handling_longjmp,
- ecs->another_trap,
- ecs->stepping_through_solib_after_catch,
- ecs->stepping_through_solib_catchpoints,
- ecs->stepping_through_sigtramp);
-
- /* Load infrun state for the new thread. */
- load_infrun_state (ecs->pid, &prev_pc,
- &prev_func_start, &prev_func_name,
- &trap_expected, &step_resume_breakpoint,
- &through_sigtramp_breakpoint,
- &step_range_start, &step_range_end,
- &step_frame_address, &ecs->handling_longjmp,
- &ecs->another_trap,
- &ecs->stepping_through_solib_after_catch,
- &ecs->stepping_through_solib_catchpoints,
- &ecs->stepping_through_sigtramp);
- }
-
- inferior_pid = ecs->pid;
+ context_switch (ecs);
if (context_hook)
- context_hook (pid_to_thread_id (ecs->pid));
+ context_hook (pid_to_thread_id (ecs->ptid));
flush_cached_frames ();
}
- if (SOFTWARE_SINGLE_STEP_P && singlestep_breakpoints_inserted_p)
+ if (SOFTWARE_SINGLE_STEP_P () && singlestep_breakpoints_inserted_p)
{
/* Pull the single step breakpoints out of the target. */
SOFTWARE_SINGLE_STEP (0, 0);
if (INSTRUCTION_NULLIFIED)
{
registers_changed ();
- target_resume (ecs->pid, 1, TARGET_SIGNAL_0);
+ target_resume (ecs->ptid, 1, TARGET_SIGNAL_0);
/* We may have received a signal that we want to pass to
the inferior; therefore, we must not clobber the waitstatus
in WS. */
ecs->infwait_state = infwait_nullified_state;
- ecs->waiton_pid = ecs->pid;
+ ecs->waiton_ptid = ecs->ptid;
ecs->wp = &(ecs->tmpstatus);
prepare_to_wait (ecs);
return;
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 ();
- target_resume (ecs->pid, 1, TARGET_SIGNAL_0); /* Single step */
+ target_resume (ecs->ptid, 1, TARGET_SIGNAL_0); /* Single step */
- ecs->waiton_pid = ecs->pid;
+ ecs->waiton_ptid = ecs->ptid;
ecs->wp = &(ecs->ws);
ecs->infwait_state = infwait_nonstep_watch_state;
prepare_to_wait (ecs);
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))))
);
the HP-UX maintainer to furnish a fix that doesn't break other
platforms. --JimB, 20 May 1999 */
check_sigtramp2 (ecs);
+ keep_going (ecs);
+ return;
}
/* Handle cases caused by hitting a breakpoint. */
interferes with us */
if (step_resume_breakpoint != NULL)
{
- delete_breakpoint (step_resume_breakpoint);
- step_resume_breakpoint = NULL;
+ delete_step_resume_breakpoint (&step_resume_breakpoint);
}
/* Not sure whether we need to blow this away too, but probably
it is like the step-resume breakpoint. */
case BPSTAT_WHAT_SINGLE:
if (breakpoints_inserted)
{
- thread_step_needed = 1;
remove_breakpoints ();
}
breakpoints_inserted = 0;
step_resume_breakpoint =
bpstat_find_step_resume_breakpoint (stop_bpstat);
}
- delete_breakpoint (step_resume_breakpoint);
- step_resume_breakpoint = NULL;
+ delete_step_resume_breakpoint (&step_resume_breakpoint);
break;
case BPSTAT_WHAT_THROUGH_SIGTRAMP:
{
#if defined(SOLIB_ADD)
/* Have we reached our destination? If not, keep going. */
- if (SOLIB_IN_DYNAMIC_LINKER (ecs->pid, stop_pc))
+ if (SOLIB_IN_DYNAMIC_LINKER (PIDGET (ecs->ptid), stop_pc))
{
ecs->another_trap = 1;
keep_going (ecs);
loader dynamic symbol resolution code, we keep on single stepping
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))
+ if (step_over_calls == STEP_OVER_UNDEBUGGABLE && IN_SOLIB_DYNSYM_RESOLVE_CODE (stop_pc))
{
CORE_ADDR pc_after_resolver = SKIP_SOLIB_RESOLVER (stop_pc);
{
/* It's a subroutine call. */
- if (step_over_calls == 0)
+ 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);
return;
}
- if (step_over_calls > 0 || IGNORE_HELPER_CALL (stop_pc))
+ if (step_over_calls == STEP_OVER_ALL || IGNORE_HELPER_CALL (stop_pc))
{
/* We're doing a "next". */
+
+ if (IN_SIGTRAMP (stop_pc, ecs->stop_func_name)
+ && INNER_THAN (step_frame_address, read_sp()))
+ /* We stepped out of a signal handler, and into its
+ calling trampoline. This is misdetected as a
+ subroutine call, but stepping over the signal
+ trampoline isn't such a bad idea. In order to do
+ that, we have to ignore the value in
+ step_frame_address, since that doesn't represent the
+ frame that'll reach when we return from the signal
+ trampoline. Otherwise we'll probably continue to the
+ end of the program. */
+ step_frame_address = 0;
+
step_over_function (ecs);
keep_going (ecs);
return;
return;
}
}
+
+ /* If we have no line number and the step-stop-if-no-debug
+ is set, we stop the step so that the user has a chance to
+ switch in assembly mode. */
+ if (step_over_calls == STEP_OVER_UNDEBUGGABLE && step_stop_if_no_debug)
+ {
+ stop_step = 1;
+ print_stop_reason (END_STEPPING_RANGE, 0);
+ stop_stepping (ecs);
+ return;
+ }
+
step_over_function (ecs);
keep_going (ecs);
return;
step_resume_breakpoint =
set_momentary_breakpoint (sr_sal, get_current_frame (), bp_step_resume);
- if (!IN_SOLIB_DYNSYM_RESOLVE_CODE (sr_sal.pc))
+ if (step_frame_address && !IN_SOLIB_DYNSYM_RESOLVE_CODE (sr_sal.pc))
step_resume_breakpoint->frame = step_frame_address;
if (breakpoints_inserted)
{
/* 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 event. And, inferior_ptid 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
+ To ensure that we can really touch inferior_ptid (aka, the
parent process) -- which calls to functions like read_pc
implicitly do -- wait on the parent if necessary. */
if ((pending_follow.kind == TARGET_WAITKIND_VFORKED)
&& !pending_follow.fork_event.saw_parent_fork)
{
- int parent_pid;
+ ptid_t parent_ptid;
do
{
if (target_wait_hook)
- parent_pid = target_wait_hook (-1, &(ecs->ws));
+ parent_ptid = target_wait_hook (pid_to_ptid (-1), &(ecs->ws));
else
- parent_pid = target_wait (-1, &(ecs->ws));
+ parent_ptid = target_wait (pid_to_ptid (-1), &(ecs->ws));
}
- while (parent_pid != inferior_pid);
+ while (! ptid_equal (parent_ptid, inferior_ptid));
}
/* Assuming the inferior still exists, set these up for next
as part of their normal status mechanism. */
registers_changed ();
- ecs->waiton_pid = -1;
+ ecs->waiton_ptid = pid_to_ptid (-1);
ecs->wp = &(ecs->ws);
}
/* This is the old end of the while loop. Let everybody know we
/* 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, ", ");
#endif
break;
default:
- internal_error ("print_stop_reason: unrecognized enum value");
+ internal_error (__FILE__, __LINE__,
+ "print_stop_reason: unrecognized enum value");
break;
}
}
(Note that there's no point in saying anything if the inferior
has exited!) */
- if ((previous_inferior_pid != inferior_pid)
+ if (! ptid_equal (previous_inferior_ptid, inferior_ptid)
&& target_has_execution)
{
target_terminal_ours_for_output ();
printf_filtered ("[Switching to %s]\n",
- target_pid_or_tid_to_str (inferior_pid));
- previous_inferior_pid = inferior_pid;
+ target_pid_or_tid_to_str (inferior_ptid));
+ previous_inferior_ptid = inferior_ptid;
}
/* Make sure that the current_frame's pc is correct. This
if (breakpoints_failed)
{
target_terminal_ours_for_output ();
- print_sys_errmsg ("ptrace", breakpoints_failed);
+ print_sys_errmsg ("While inserting breakpoints", breakpoints_failed);
printf_filtered ("Stopped; cannot insert breakpoints.\n\
-The same program may be running in another process.\n");
+The same program may be running in another process,\n\
+or you may have requested too many hardware breakpoints\n\
+and/or watchpoints.\n");
}
if (target_has_execution && breakpoints_inserted)
/* Look up the hook_stop and run it if it exists. */
- if (stop_command && stop_command->hook)
+ if (stop_command && stop_command->hook_pre)
{
- catch_errors (hook_stop_stub, stop_command->hook,
+ catch_errors (hook_stop_stub, stop_command->hook_pre,
"Error while running hook_stop:\n", RETURN_MASK_ALL);
}
bpstat_print() contains the logic deciding in detail
what to print, based on the event(s) that just occurred. */
- if (stop_print_frame)
+ if (stop_print_frame
+ && selected_frame)
{
int bpstat_ret;
int source_flag;
source_flag = SRC_LINE;
break;
case PRINT_NOTHING:
+ source_flag = SRC_LINE; /* something bogus */
do_frame_printing = 0;
break;
default:
- internal_error ("Unknown value.");
+ internal_error (__FILE__, __LINE__,
+ "Unknown value.");
}
#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)
- ui_out_field_int (uiout, "thread-id", pid_to_thread_id (inferior_pid));
+ if (ui_out_is_mi_like_p (uiout))
+ ui_out_field_int (uiout, "thread-id",
+ pid_to_thread_id (inferior_ptid));
#endif
/* The behavior of this routine with respect to the source
flag is:
select_frame (get_current_frame (), 0);
}
-
- TUIDO (((TuiOpaqueFuncPtr) tui_vCheckDataValues, selected_frame));
-
done:
annotate_stopped ();
}
argv++;
}
- target_notice_signals (inferior_pid);
+ target_notice_signals (inferior_ptid);
if (from_tty)
{
else
printf_filtered ("Invalid signal handling flag.\n");
if (argBuf)
- free (argBuf);
+ xfree (argBuf);
}
}
do_cleanups (old_chain);
{
/* No, try numeric. */
oursig =
- target_signal_from_command (parse_and_eval_address (signum_exp));
+ target_signal_from_command (parse_and_eval_long (signum_exp));
}
sig_print_info (oursig);
return;
CORE_ADDR step_range_start;
CORE_ADDR step_range_end;
CORE_ADDR step_frame_address;
- int step_over_calls;
+ enum step_over_calls_kind step_over_calls;
CORE_ADDR step_resume_break_address;
int stop_after_trap;
int stop_soon_quietly;
static void
free_inferior_status (struct inferior_status *inf_status)
{
- free (inf_status->registers);
- free (inf_status->stop_registers);
- free (inf_status);
+ xfree (inf_status->registers);
+ xfree (inf_status->stop_registers);
+ xfree (inf_status);
}
void
free_inferior_status (inf_status);
}
+static void
+do_restore_inferior_status_cleanup (void *sts)
+{
+ restore_inferior_status (sts);
+}
+
+struct cleanup *
+make_cleanup_restore_inferior_status (struct inferior_status *inf_status)
+{
+ return make_cleanup (do_restore_inferior_status_cleanup, inf_status);
+}
+
void
discard_inferior_status (struct inferior_status *inf_status)
{
free_inferior_status (inf_status);
}
+/* 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);
+}
+
+/* restore_inferior_ptid() will be used by the cleanup machinery
+ to restore the inferior_ptid value saved in a call to
+ save_inferior_ptid(). */
+
static void
-set_follow_fork_mode_command (char *arg, int from_tty,
- struct cmd_list_element *c)
+restore_inferior_ptid (void *arg)
{
- if (!STREQ (arg, "parent") &&
- !STREQ (arg, "child") &&
- !STREQ (arg, "both") &&
- !STREQ (arg, "ask"))
- error ("follow-fork-mode must be one of \"parent\", \"child\", \"both\" or \"ask\".");
-
- if (follow_fork_mode_string != NULL)
- free (follow_fork_mode_string);
- follow_fork_mode_string = savestring (arg, strlen (arg));
+ ptid_t *saved_ptid_ptr = arg;
+ inferior_ptid = *saved_ptid_ptr;
+ xfree (arg);
}
+
+/* Save the value of inferior_ptid so that it may be restored by a
+ later call to do_cleanups(). Returns the struct cleanup pointer
+ needed for later doing the cleanup. */
+
+struct cleanup *
+save_inferior_ptid (void)
+{
+ ptid_t *saved_ptid_ptr;
+
+ saved_ptid_ptr = xmalloc (sizeof (ptid_t));
+ *saved_ptid_ptr = inferior_ptid;
+ return make_cleanup (restore_inferior_ptid, saved_ptid_ptr);
+}
+
\f
static void
build_infrun (void)
c = add_set_enum_cmd ("follow-fork-mode",
class_run,
follow_fork_mode_kind_names,
- (char *) &follow_fork_mode_string,
+ &follow_fork_mode_string,
/* ??rehrauer: The "both" option is broken, by what may be a 10.20
kernel problem. It's also not terribly useful without a GUI to
help the user drive two debuggers. So for now, I'm disabling
/* c->function.sfunc = ; */
add_show_from_set (c, &showlist);
- set_follow_fork_mode_command ("parent", 0, NULL);
-
c = add_set_enum_cmd ("scheduler-locking", class_run,
scheduler_enums, /* array of string names */
- (char *) &scheduler_mode, /* current mode */
+ &scheduler_mode, /* current mode */
"Set mode for locking scheduler during execution.\n\
off == no locking (threads may preempt at any time)\n\
on == full locking (no thread except the current thread may run)\n\
c->function.sfunc = set_schedlock_func; /* traps on target vector */
add_show_from_set (c, &showlist);
+
+ c = add_set_cmd ("step-mode", class_run,
+ var_boolean, (char*) &step_stop_if_no_debug,
+"Set mode of the step operation. When set, doing a step over a\n\
+function without debug line information will stop at the first\n\
+instruction of that function. Otherwise, the function is skipped and\n\
+the step command stops at a different source line.",
+ &setlist);
+ add_show_from_set (c, &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;
}