process.
Copyright (C) 1986, 1987, 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995,
- 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007
- Free Software Foundation, Inc.
+ 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007,
+ 2008 Free Software Foundation, Inc.
This file is part of GDB.
void _initialize_infrun (void);
-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. */
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. */
-
-#ifndef MAY_FOLLOW_EXEC
-#define MAY_FOLLOW_EXEC (0)
-#endif
-
-static int may_follow_exec = MAY_FOLLOW_EXEC;
-
static int debug_infrun = 0;
static void
show_debug_infrun (struct ui_file *file, int from_tty,
int saved_pid = pid;
struct target_ops *tgt;
- if (!may_follow_exec)
- return;
-
/* This is an exec event that we actually wish to pay attention to.
Refresh our symbol table to the newly exec'd program, remove any
momentary bp's, etc.
/* We've followed the inferior through an exec. Therefore, the
inferior has essentially been killed & reborn. */
- /* First collect the run target in effect. */
- tgt = find_run_target ();
- /* If we can't find one, things are in a very strange state... */
- if (tgt == NULL)
- error (_("Could find run target to save before following exec"));
-
gdb_flush (gdb_stdout);
- target_mourn_inferior ();
- inferior_ptid = pid_to_ptid (saved_pid);
+ generic_mourn_inferior ();
/* Because mourn_inferior resets inferior_ptid. */
- push_target (tgt);
+ inferior_ptid = pid_to_ptid (saved_pid);
+
+ if (gdb_sysroot && *gdb_sysroot)
+ {
+ char *name = alloca (strlen (gdb_sysroot)
+ + strlen (execd_pathname)
+ + 1);
+ strcpy (name, gdb_sysroot);
+ strcat (name, execd_pathname);
+ execd_pathname = name;
+ }
/* That a.out is now the one to use. */
exec_file_attach (execd_pathname, 0);
/* Reset the shared library package. This ensures that we get
a shlib event when the child reaches "_start", at which point
the dld will have had a chance to initialize the child. */
-#if defined(SOLIB_RESTART)
- SOLIB_RESTART ();
-#endif
+ no_shared_libraries (NULL, 0);
#ifdef SOLIB_CREATE_INFERIOR_HOOK
SOLIB_CREATE_INFERIOR_HOOK (PIDGET (inferior_ptid));
#else
}
if ((step || singlestep_breakpoints_inserted_p)
- && breakpoint_here_p (read_pc ())
- && !breakpoint_inserted_here_p (read_pc ()))
+ && stepping_over_breakpoint)
{
- /* We're stepping, have breakpoint at PC, and it's
- not inserted. Most likely, proceed has noticed that
- we have breakpoint and tries to single-step over it,
- so that it's not hit. In which case, we need to
- single-step only this thread, and keep others stopped,
- as they can miss this breakpoint if allowed to run.
-
- The current code either has all breakpoints inserted,
- or all removed, so if we let other threads run,
- we can actually miss any breakpoint, not the one at PC. */
+ /* We're allowing a thread to run past a breakpoint it has
+ hit, by single-stepping the thread with the breakpoint
+ removed. In which case, we need to single-step only this
+ thread, and keep others stopped, as they can miss this
+ breakpoint if allowed to run.
+
+ The current code actually removes all breakpoints when
+ doing this, not just the one being stepped over, so if we
+ let other threads run, we can actually miss any
+ breakpoint, not just the one at PC. */
resume_ptid = inferior_ptid;
}
oneproc = 1;
if (oneproc)
- /* We will get a trace trap after one instruction.
- Continue it automatically and insert breakpoints then. */
- stepping_over_breakpoint = 1;
+ {
+ /* We will get a trace trap after one instruction.
+ Continue it automatically and insert breakpoints then. */
+ stepping_over_breakpoint = 1;
+ /* FIXME: if breakpoints are always inserted, we'll trap
+ if trying to single-step over breakpoint. Disable
+ all breakpoints. In future, we'd need to invent some
+ smart way of stepping over breakpoint instruction without
+ hitting breakpoint. */
+ remove_breakpoints ();
+ }
else
insert_breakpoints ();
does not support asynchronous execution. */
if (!target_can_async_p ())
{
- wait_for_inferior ();
+ wait_for_inferior (0);
normal_stop ();
}
}
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 ();
+ wait_for_inferior (0);
/* Now that the inferior has stopped, do any bookkeeping like
loading shared libraries. We want to do this before normal_stop,
int stop_info);
/* Wait for control to return from inferior to debugger.
+
+ If TREAT_EXEC_AS_SIGTRAP is non-zero, then handle EXEC signals
+ as if they were SIGTRAP signals. This can be useful during
+ the startup sequence on some targets such as HP/UX, where
+ we receive an EXEC event instead of the expected SIGTRAP.
+
If inferior gets a signal, we may decide to start it up again
instead of returning. That is why there is a loop in this function.
When this function actually returns it means the inferior
should be left stopped and GDB should read more commands. */
void
-wait_for_inferior (void)
+wait_for_inferior (int treat_exec_as_sigtrap)
{
struct cleanup *old_cleanups;
struct execution_control_state ecss;
struct execution_control_state *ecs;
if (debug_infrun)
- fprintf_unfiltered (gdb_stdlog, "infrun: wait_for_inferior\n");
+ fprintf_unfiltered
+ (gdb_stdlog, "infrun: wait_for_inferior (treat_exec_as_sigtrap=%d)\n",
+ treat_exec_as_sigtrap);
old_cleanups = make_cleanup (delete_step_resume_breakpoint,
&step_resume_breakpoint);
else
ecs->ptid = target_wait (ecs->waiton_ptid, ecs->wp);
+ if (treat_exec_as_sigtrap && ecs->ws.kind == TARGET_WAITKIND_EXECD)
+ {
+ xfree (ecs->ws.value.execd_pathname);
+ ecs->ws.kind = TARGET_WAITKIND_STOPPED;
+ ecs->ws.value.sig = TARGET_SIGNAL_TRAP;
+ }
+
/* Now figure out what to do with the result of the result. */
handle_inferior_event (ecs);
if (!async_ecs->wait_some_more)
{
- old_cleanups = make_exec_cleanup (delete_step_resume_breakpoint,
- &step_resume_breakpoint);
-
/* Fill in with reasonable starting values. */
init_execution_control_state (async_ecs);
if (!async_ecs->wait_some_more)
{
- /* Do only the cleanups that have been added by this
- function. Let the continuations for the commands do the rest,
- if there are any. */
- do_exec_cleanups (old_cleanups);
+ delete_step_resume_breakpoint (&step_resume_breakpoint);
+
normal_stop ();
if (step_multi && stop_step)
inferior_event_handler (INF_EXEC_CONTINUE, NULL);
if (ecs->ws.kind != TARGET_WAITKIND_EXITED
&& ecs->ws.kind != TARGET_WAITKIND_SIGNALLED && ecs->new_thread_event)
- {
- add_thread (ecs->ptid);
-
- ui_out_text (uiout, "[New ");
- ui_out_text (uiout, target_pid_or_tid_to_str (ecs->ptid));
- ui_out_text (uiout, "]\n");
- }
+ add_thread (ecs->ptid);
switch (ecs->ws.kind)
{
established. */
if (stop_soon == NO_STOP_QUIETLY)
{
- /* Remove breakpoints, SOLIB_ADD might adjust
- breakpoint addresses via breakpoint_re_set. */
- remove_breakpoints ();
-
/* Check for any newly added shared libraries if we're
supposed to be adding them automatically. Switch
terminal for any messages produced by
/* NOTE drow/2007-05-11: This might be a good place to check
for "catch load". */
-
- /* Reinsert breakpoints and continue. */
- insert_breakpoints ();
}
/* If we are skipping through a shell, or through shared library
we're attaching or setting up a remote connection. */
if (stop_soon == STOP_QUIETLY || stop_soon == NO_STOP_QUIETLY)
{
+ /* Loading of shared libraries might have changed breakpoint
+ addresses. Make sure new breakpoints are inserted. */
+ if (!breakpoints_always_inserted_mode ())
+ insert_breakpoints ();
resume (0, TARGET_SIGNAL_0);
prepare_to_wait (ecs);
return;
fprintf_unfiltered (gdb_stdlog, "infrun: TARGET_WAITKIND_EXECD\n");
stop_signal = TARGET_SIGNAL_TRAP;
- /* NOTE drow/2002-12-05: This code should be pushed down into the
- target_wait function. Until then following vfork on HP/UX 10.20
- is probably broken by this. Of course, it's broken anyway. */
- /* Is this a target which reports multiple exec events per actual
- call to exec()? (HP-UX using ptrace does, for example.) If so,
- ignore all but the last one. Just resume the exec'r, and wait
- for the next exec event. */
- if (inferior_ignoring_leading_exec_events)
- {
- inferior_ignoring_leading_exec_events--;
- target_resume (ecs->ptid, 0, TARGET_SIGNAL_0);
- 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));
process until the child exits (well, okay, not
then either :-) or execs. */
if (remove_status != 0)
- {
- /* FIXME! This is obviously non-portable! */
- write_pc_pid (stop_pc + 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;
- }
+ error (_("Cannot step over breakpoint hit in wrong thread"));
else
{ /* Single step */
if (!ptid_equal (inferior_ptid, ecs->ptid))
&& gdbarch_single_step_through_delay_p (current_gdbarch)
&& currently_stepping (ecs))
{
- /* We're trying to step of a breakpoint. Turns out that we're
+ /* We're trying to step off a breakpoint. Turns out that we're
also on an instruction that needs to be stepped multiple
times before it's been fully executing. E.g., architectures
with a delay slot. It needs to be stepped twice, once for
stop_signal = TARGET_SIGNAL_0;
if (prev_pc == read_pc ()
- && breakpoint_here_p (read_pc ())
- && !breakpoint_inserted_here_p (read_pc ())
+ && stepping_over_breakpoint
&& step_resume_breakpoint == NULL)
{
/* We were just starting a new sequence, attempting to
return;
case BPSTAT_WHAT_CLEAR_LONGJMP_RESUME:
- case BPSTAT_WHAT_CLEAR_LONGJMP_RESUME_SINGLE:
if (debug_infrun)
fprintf_unfiltered (gdb_stdlog, "infrun: BPSTAT_WHAT_CLEAR_LONGJMP_RESUME\n");
disable_longjmp_breakpoint ();
ecs->handling_longjmp = 0; /* FIXME */
- if (what.main_action == BPSTAT_WHAT_CLEAR_LONGJMP_RESUME)
- break;
- /* else fallthrough */
+ break;
case BPSTAT_WHAT_SINGLE:
if (debug_infrun)
{
if (debug_infrun)
fprintf_unfiltered (gdb_stdlog, "infrun: BPSTAT_WHAT_CHECK_SHLIBS\n");
- /* Remove breakpoints, we eventually want to step over the
- shlib event breakpoint, and SOLIB_ADD might adjust
- breakpoint addresses via breakpoint_re_set. */
- remove_breakpoints ();
/* Check for any newly added shared libraries if we're
supposed to be adding them automatically. Switch
new line in mid-statement, we continue stepping. This makes
things like for(;;) statements work better.) */
- if (ecs->stop_func_end && ecs->sal.end >= ecs->stop_func_end)
- {
- /* If this is the last line of the function, don't keep stepping
- (it would probably step us out of the function).
- This is particularly necessary for a one-line function,
- in which after skipping the prologue we better stop even though
- we will be in mid-line. */
- if (debug_infrun)
- fprintf_unfiltered (gdb_stdlog, "infrun: stepped to a different function\n");
- stop_step = 1;
- print_stop_reason (END_STEPPING_RANGE, 0);
- stop_stepping (ecs);
- return;
- }
step_range_start = ecs->sal.pc;
step_range_end = ecs->sal.end;
step_frame_id = get_frame_id (get_current_frame ());
{
target_terminal_ours_for_output ();
printf_filtered (_("[Switching to %s]\n"),
- target_pid_or_tid_to_str (inferior_ptid));
+ target_pid_to_str (inferior_ptid));
previous_inferior_ptid = inferior_ptid;
}
gdbarch_decr_pc_after_break needs to just go away. */
deprecated_update_frame_pc_hack (get_current_frame (), read_pc ());
- if (target_has_execution)
+ if (!breakpoints_always_inserted_mode () && target_has_execution)
{
if (remove_breakpoints ())
{
}
}
- /* Delete the breakpoint we stopped at, if it wants to be deleted.
- Delete any breakpoint that is to be deleted at the next stop. */
-
- breakpoint_auto_delete (stop_bpstat);
-
/* If an auto-display called a function and that got a signal,
delete that auto-display to avoid an infinite recursion. */
done:
annotate_stopped ();
observer_notify_normal_stop (stop_bpstat);
+ /* Delete the breakpoint we stopped at, if it wants to be deleted.
+ Delete any breakpoint that is to be deleted at the next stop. */
+ breakpoint_auto_delete (stop_bpstat);
}
static int