#include "top.h"
#include <signal.h>
#include "event-loop.h"
+#include "event-top.h"
/* Prototypes for local functions */
#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. */
}
+
+
/* 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 = 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 */
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 ();
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 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
instead of returning. That is why there is a loop in this function.
struct execution_control_state *async_ecs;
void
-fetch_inferior_event (void)
+fetch_inferior_event (client_data)
+ gdb_client_data client_data;
{
static struct cleanup *old_cleanups;
}
/* 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 (void)
{
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;
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 (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
static void
complete_execution (void)
{
- extern int cleanup_sigint_signal_handler (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.
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 (void)
{