aboutsummaryrefslogtreecommitdiff
path: root/gdb/infrun.c
diff options
context:
space:
mode:
Diffstat (limited to 'gdb/infrun.c')
-rw-r--r--gdb/infrun.c984
1 files changed, 592 insertions, 392 deletions
diff --git a/gdb/infrun.c b/gdb/infrun.c
index 67b0c17..d08a1bf 100644
--- a/gdb/infrun.c
+++ b/gdb/infrun.c
@@ -18,8 +18,106 @@ In other words, go ahead and share GDB, but don't try to stop
anyone else from sharing it farther. Help stamp out software hoarding!
*/
+/* Notes on the algorithm used in wait_for_inferior to determine if we
+ just did a subroutine call when stepping. We have the following
+ information at that point:
+
+ Current and previous (just before this step) pc.
+ Current and previous sp.
+ Current and previous start of current function.
+
+ If the start's of the functions don't match, then
+
+ a) We did a subroutine call.
+
+ In this case, the pc will be at the beginning of a function.
+
+ b) We did a subroutine return.
+
+ Otherwise.
+
+ c) We did a longjmp.
+
+ If we did a longjump, we were doing "nexti", since a next would
+ have attempted to skip over the assembly language routine in which
+ the longjmp is coded and would have simply been the equivalent of a
+ continue. I consider this ok behaivior. We'd like one of two
+ things to happen if we are doing a nexti through the longjmp()
+ routine: 1) It behaves as a stepi, or 2) It acts like a continue as
+ above. Given that this is a special case, and that anybody who
+ thinks that the concept of sub calls is meaningful in the context
+ of a longjmp, I'll take either one. Let's see what happens.
+
+ Acts like a subroutine return. I can handle that with no problem
+ at all.
+
+ -->So: If the current and previous beginnings of the current
+ function don't match, *and* the pc is at the start of a function,
+ we've done a subroutine call. If the pc is not at the start of a
+ function, we *didn't* do a subroutine call.
+
+ -->If the beginnings of the current and previous function do match,
+ either:
+
+ a) We just did a recursive call.
+
+ In this case, we would be at the very beginning of a
+ function and 1) it will have a prologue (don't jump to
+ before prologue, or 2) (we assume here that it doesn't have
+ a prologue) there will have been a change in the stack
+ pointer over the last instruction. (Ie. it's got to put
+ the saved pc somewhere. The stack is the usual place. In
+ a recursive call a register is only an option if there's a
+ prologue to do something with it. This is even true on
+ register window machines; the prologue sets up the new
+ window. It might not be true on a register window machine
+ where the call instruction moved the register window
+ itself. Hmmm. One would hope that the stack pointer would
+ also change. If it doesn't, somebody send me a note, and
+ I'll work out a more general theory.
+ randy@wheaties.ai.mit.edu). This is true (albeit slipperly
+ so) on all machines I'm aware of:
+
+ m68k: Call changes stack pointer. Regular jumps don't.
+
+ sparc: Recursive calls must have frames and therefor,
+ prologues.
+
+ vax: All calls have frames and hence change the
+ stack pointer.
+
+ b) We did a return from a recursive call. I don't see that we
+ have either the ability or the need to distinguish this
+ from an ordinary jump. The stack frame will be printed
+ when and if the frame pointer changes; if we are in a
+ function without a frame pointer, it's the users own
+ lookout.
+
+ c) We did a jump within a function. We assume that this is
+ true if we didn't do a recursive call.
+
+ d) We are in no-man's land ("I see no symbols here"). We
+ don't worry about this; it will make calls look like simple
+ jumps (and the stack frames will be printed when the frame
+ pointer moves), which is a reasonably non-violent response.
+
+#if 0
+ We skip this; it causes more problems than it's worth.
+#ifdef SUN4_COMPILER_FEATURE
+ We do a special ifdef for the sun 4, forcing it to single step
+ into calls which don't have prologues. This means that we can't
+ nexti over leaf nodes, we can probably next over them (since they
+ won't have debugging symbols, usually), and we can next out of
+ functions returning structures (with a "call .stret4" at the end).
+#endif
+#endif
+*/
+
+
+
+
+
#include "defs.h"
-#include "initialize.h"
#include "param.h"
#include "symtab.h"
#include "frame.h"
@@ -28,12 +126,23 @@ anyone else from sharing it farther. Help stamp out software hoarding!
#include <stdio.h>
#include <signal.h>
-#include <a.out.h>
+
+/* unistd.h is needed to #define X_OK */
+#ifdef USG
+#include <unistd.h>
+#else
+#include <sys/file.h>
+#endif
+
+/* The idiots at Apple only define X_OK if POSIX is defined. Fuck 'em. */
+#ifndef X_OK
+#define X_OK 1 /* Execute permission for access() */
+#endif
#ifdef UMAX_PTRACE
#include <sys/param.h>
#include <sys/ptrace.h>
-#endif UMAX_PTRACE
+#endif /* UMAX_PTRACE */
extern char *sys_siglist[];
extern int errno;
@@ -56,7 +165,7 @@ static struct symbol *step_start_function;
static char break_insn[] = BREAKPOINT;
-/* Nonzero => address for special breakpoint for resuming stepping. */
+/* Nonzero => address for special breakpoint for resuming stepping. */
static CORE_ADDR step_resume_break_address;
@@ -85,11 +194,11 @@ static int trap_expected_after_continue;
/* Nonzero means expecting a trace trap
and should stop the inferior and return silently when it happens. */
-static int stop_after_trap;
+int stop_after_trap;
/* Nonzero means expecting a trace trap due to attaching to a process. */
-static int stop_after_attach;
+int stop_after_attach;
/* Nonzero if pc has been changed by the debugger
since the inferior stopped. */
@@ -117,11 +226,8 @@ static int running_in_shell;
static int stop_print_frame;
#ifdef NO_SINGLE_STEP
-/* Non-zero if we just simulated a single-step ptrace call. This is
- needed because we cannot remove the breakpoints in the inferior
- process until after the `wait' in `wait_for_inferior'.
- Used for sun4. */
-int one_stepped;
+extern int one_stepped; /* From machine dependent code */
+extern void single_step (); /* Same. */
#endif /* NO_SINGLE_STEP */
static void insert_step_breakpoint ();
@@ -129,7 +235,6 @@ static void remove_step_breakpoint ();
static void wait_for_inferior ();
static void normal_stop ();
-START_FILE
/* Clear out all variables saying what to do when inferior is continued.
First do this, then set the ones you want, then call `proceed'. */
@@ -140,7 +245,7 @@ clear_proceed_status ()
trap_expected = 0;
step_range_start = 0;
step_range_end = 0;
- step_frame = 0;
+ step_frame_address = 0;
step_over_calls = -1;
step_resume_break_address = 0;
stop_after_trap = 0;
@@ -188,7 +293,7 @@ proceed (addr, signal, step)
{
write_register (PC_REGNUM, addr);
#ifdef NPC_REGNUM
- write_register (NPC_REGNUM, addr+4);
+ write_register (NPC_REGNUM, addr + 4);
#endif
}
@@ -241,6 +346,7 @@ The same program may be running in another process.");
/* Writing the inferior pc as a register calls this function
to inform infrun that the pc has been set in the debugger. */
+void
writing_pc (val)
CORE_ADDR val;
{
@@ -253,12 +359,19 @@ writing_pc (val)
but it will have stopped one instruction after execing sh.
Here we must get it up to actual execution of the real program. */
+void
start_inferior ()
{
/* We will get a trace trap after one instruction.
Continue it automatically. Eventually (after shell does an exec)
it will get another trace trap. Then insert breakpoints and continue. */
+
+#ifdef START_INFERIOR_TRAPS_EXPECTED
+ trap_expected = START_INFERIOR_TRAPS_EXPECTED;
+#else
trap_expected = 2;
+#endif
+
running_in_shell = 0; /* Set to 1 at first SIGTRAP, 0 at second. */
trap_expected_after_continue = 0;
breakpoints_inserted = 0;
@@ -275,8 +388,9 @@ start_inferior ()
{
trap_expected = 0;
fetch_inferior_registers();
- set_current_frame (read_register(FP_REGNUM));
- stop_frame = get_current_frame();
+ set_current_frame (create_new_frame (read_register (FP_REGNUM),
+ read_pc ()));
+ stop_frame_address = FRAME_FP (get_current_frame());
inferior_pid = 3;
if (insert_breakpoints())
fatal("Can't insert breakpoints");
@@ -342,18 +456,28 @@ wait_for_inferior ()
int tem;
int another_trap;
int random_signal;
- CORE_ADDR stop_sp;
+ CORE_ADDR stop_sp, prev_sp;
+ CORE_ADDR prev_func_start, stop_func_start;
+ CORE_ADDR prologue_pc;
int stop_step_resume_break;
+ CORE_ADDR step_resume_break_sp;
int newmisc;
int newfun_pc;
struct symbol *newfun;
struct symtab_and_line sal;
int prev_pc;
+ extern CORE_ADDR text_end;
prev_pc = read_pc ();
+ prev_func_start = get_pc_function_start (prev_pc) + FUNCTION_START_OFFSET;
+ prev_sp = read_register (SP_REGNUM);
while (1)
{
+ /* Clean up saved state that will become invalid */
+ pc_changed = 0;
+ flush_cached_frames ();
+
if (remote_debugging)
remote_wait (&w);
else
@@ -363,36 +487,7 @@ wait_for_inferior ()
continue;
}
-#ifdef NO_SINGLE_STEP
- if (one_stepped)
- {
- single_step (0);
- }
-#endif /* NO_SINGLE_STEP */
-
- pc_changed = 0;
- fetch_inferior_registers ();
- stop_pc = read_pc ();
- set_current_frame (read_register (FP_REGNUM));
- stop_frame = get_current_frame ();
- stop_sp = read_register (SP_REGNUM);
- another_trap = 0;
- stop_breakpoint = 0;
- stop_step = 0;
- stop_stack_dummy = 0;
- stop_print_frame = 1;
- stop_step_resume_break = 0;
- random_signal = 0;
- breakpoints_failed = 0;
-
- /* Look at the cause of the stop, and decide what to do.
- The alternatives are:
- 1) break; to really stop and return to the debugger,
- 2) drop through to start up again
- (set another_trap to 1 to single step once)
- 3) set random_signal to 1, and the decision between 1 and 2
- will be made according to the signal handling tables. */
-
+ /* See if the process still exists; clean up if it doesn't. */
if (WIFEXITED (w))
{
terminal_ours_for_output ();
@@ -402,6 +497,9 @@ wait_for_inferior ()
printf ("\nProgram exited normally.\n");
fflush (stdout);
inferior_died ();
+#ifdef NO_SINGLE_STEP
+ one_stepped = 0; /* Clear single_step state since proc gone */
+#endif /* NO_SINGLE_STEP */
stop_print_frame = 0;
break;
}
@@ -418,254 +516,377 @@ wait_for_inferior ()
: "(undocumented)");
printf ("The inferior process no longer exists.\n");
fflush (stdout);
+#ifdef NO_SINGLE_STEP
+ one_stepped = 0; /* Clear single_step state since proc gone */
+#endif /* NO_SINGLE_STEP */
break;
}
- else
+
+#ifdef NO_SINGLE_STEP
+ if (one_stepped)
+ single_step (0); /* This actually cleans up the ss */
+#endif /* NO_SINGLE_STEP */
+
+ fetch_inferior_registers ();
+ stop_pc = read_pc ();
+ set_current_frame ( create_new_frame (read_register (FP_REGNUM),
+ read_pc ()));
+#ifdef CONVEX_PTRACE
+ /* pop frame stored by user-mode trap, if present */
+ if (stop_pc == BREAK_TRAP_ADDR)
+ {
+ POP_FRAME;
+ stop_pc = read_pc () - 2;
+ write_register (PC_REGNUM, stop_pc);
+#ifdef NPC_REGNUM
+ write_register (NPC_REGNUM, stop_pc + 4);
+#endif
+ pc_changed = 0;
+ }
+ else if (stop_pc > STACK_END_ADDR)
+ {
+ POP_FRAME;
+ stop_pc = read_pc ();
+ }
+#endif /* CONVEX_PTRACE */
+ stop_frame_address = FRAME_FP (get_current_frame ());
+ stop_sp = read_register (SP_REGNUM);
+ stop_func_start =
+ get_pc_function_start (stop_pc) + FUNCTION_START_OFFSET;
+ another_trap = 0;
+ stop_breakpoint = 0;
+ stop_step = 0;
+ stop_stack_dummy = 0;
+ stop_print_frame = 1;
+ stop_step_resume_break = 0;
+ random_signal = 0;
+ stopped_by_random_signal = 0;
+ breakpoints_failed = 0;
+
+ /* Look at the cause of the stop, and decide what to do.
+ The alternatives are:
+ 1) break; to really stop and return to the debugger,
+ 2) drop through to start up again
+ (set another_trap to 1 to single step once)
+ 3) set random_signal to 1, and the decision between 1 and 2
+ will be made according to the signal handling tables. */
+
+ stop_signal = WSTOPSIG (w);
+
+ /* First, distinguish signals caused by the debugger from signals
+ that have to do with the program's own actions.
+ Note that breakpoint insns may cause SIGTRAP or SIGILL
+ or SIGEMT, depending on the operating system version.
+ Here we detect when a SIGILL or SIGEMT is really a breakpoint
+ and change it to SIGTRAP. */
+
+ if (stop_signal == SIGTRAP
+#ifndef CONVEX_PTRACE
+ || (breakpoints_inserted &&
+ (stop_signal == SIGILL
+ || stop_signal == SIGEMT))
+#endif /* not CONVEX_PTRACE */
+ || stop_after_attach)
{
- stop_signal = WSTOPSIG (w);
-
- /* First, distinguish signals caused by the debugger from signals
- that have to do with the program's own actions.
- Note that breakpoint insns may cause SIGTRAP or SIGILL
- or SIGEMT, depending on the operating system version.
- Here we detect when a SIGILL or SIGEMT is really a breakpoint
- and change it to SIGTRAP. */
-
- if (stop_signal == SIGTRAP
- || (breakpoints_inserted &&
- (stop_signal == SIGILL
- || stop_signal == SIGEMT))
- || stop_after_attach)
+ if (stop_signal == SIGTRAP && stop_after_trap)
{
- if (stop_signal == SIGTRAP && stop_after_trap)
- {
- stop_print_frame = 0;
- break;
- }
- if (stop_after_attach)
- break;
- /* Don't even think about breakpoints
- if still running the shell that will exec the program
- or if just proceeded over a breakpoint. */
- if (stop_signal == SIGTRAP && trap_expected)
- stop_breakpoint = 0;
- else
- /* See if there is a breakpoint at the current PC. */
+ stop_print_frame = 0;
+ break;
+ }
+ if (stop_after_attach)
+ break;
+ /* Don't even think about breakpoints
+ if still running the shell that will exec the program
+ or if just proceeded over a breakpoint. */
+ if (stop_signal == SIGTRAP && trap_expected)
+ stop_breakpoint = 0;
+ else
+ {
+ /* See if there is a breakpoint at the current PC. */
#if DECR_PC_AFTER_BREAK
- /* Notice the case of stepping through a jump
- that leads 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. */
- if (!(prev_pc != stop_pc - DECR_PC_AFTER_BREAK
- && step_range_end && !step_resume_break_address))
+ /* Notice the case of stepping through a jump
+ that leads 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. */
+ if (!(prev_pc != stop_pc - DECR_PC_AFTER_BREAK
+ && step_range_end && !step_resume_break_address))
#endif /* DECR_PC_AFTER_BREAK not zero */
- {
- select_frame (stop_frame, 0); /* For condition exprs. */
- stop_breakpoint = breakpoint_stop_status (stop_pc, stop_frame);
- /* Following in case break condition called a function. */
- stop_print_frame = 1;
- if (stop_breakpoint && DECR_PC_AFTER_BREAK)
- {
- stop_pc -= DECR_PC_AFTER_BREAK;
- write_register (PC_REGNUM, stop_pc);
+ {
+ /* For condition exprs. */
+ select_frame (get_current_frame (), 0);
+ stop_breakpoint =
+ breakpoint_stop_status (stop_pc, stop_frame_address);
+ /* Following in case break condition called a
+ function. */
+ stop_print_frame = 1;
+ if (stop_breakpoint && DECR_PC_AFTER_BREAK)
+ {
+ stop_pc -= DECR_PC_AFTER_BREAK;
+ write_register (PC_REGNUM, stop_pc);
#ifdef NPC_REGNUM
- write_register (NPC_REGNUM, stop_pc + 4);
+ write_register (NPC_REGNUM, stop_pc + 4);
#endif
- pc_changed = 0;
- }
- }
+ pc_changed = 0;
+ }
+ }
/* See if we stopped at the special breakpoint for
stepping over a subroutine call. */
- if (stop_pc - DECR_PC_AFTER_BREAK == step_resume_break_address)
+ if (stop_pc - DECR_PC_AFTER_BREAK
+ == step_resume_break_address)
{
stop_step_resume_break = 1;
if (DECR_PC_AFTER_BREAK)
{
stop_pc -= DECR_PC_AFTER_BREAK;
write_register (PC_REGNUM, stop_pc);
-#ifdef NPC_REGNUM
- write_register (PC_REGNUM, stop_pc + 4);
-#endif
pc_changed = 0;
}
}
-
- if (stop_signal == SIGTRAP)
- random_signal
- = !(stop_breakpoint || trap_expected
- || stop_step_resume_break
- || (stop_sp INNER_THAN stop_pc && stop_pc INNER_THAN stop_frame)
- || (step_range_end && !step_resume_break_address));
- else
- {
- random_signal
- = !(stop_breakpoint || stop_step_resume_break);
- if (!random_signal)
- stop_signal = SIGTRAP;
- }
}
+
+ if (stop_signal == SIGTRAP)
+ random_signal
+ = !(stop_breakpoint || trap_expected
+ || stop_step_resume_break
+#ifndef CONVEX_PTRACE
+ || (stop_sp INNER_THAN stop_pc
+ && stop_pc INNER_THAN stop_frame_address)
+#else
+ || stop_pc == text_end - 2
+#endif
+ || (step_range_end && !step_resume_break_address));
else
- random_signal = 1;
+ {
+ random_signal
+ = !(stop_breakpoint
+ || stop_step_resume_break
+#ifdef news800
+ || (stop_sp INNER_THAN stop_pc
+ && stop_pc INNER_THAN stop_frame_address)
+#endif
+
+ );
+ if (!random_signal)
+ stop_signal = SIGTRAP;
+ }
+ }
+ else
+ random_signal = 1;
- /* For the program's own signals, act according to
- the signal handling tables. */
+ /* For the program's own signals, act according to
+ the signal handling tables. */
- if (random_signal
- && !(running_in_shell && stop_signal == SIGSEGV))
- {
- /* Signal not for debugging purposes. */
- int printed = 0;
+ if (random_signal
+ && !(running_in_shell && stop_signal == SIGSEGV))
+ {
+ /* Signal not for debugging purposes. */
+ int printed = 0;
- if (stop_signal >= NSIG
- || signal_print[stop_signal])
- {
- printed = 1;
- terminal_ours_for_output ();
- printf ("\nProgram received signal %d, %s\n",
- stop_signal,
- stop_signal < NSIG
- ? sys_siglist[stop_signal]
- : "(undocumented)");
- fflush (stdout);
- }
- if (stop_signal >= NSIG
- || signal_stop[stop_signal])
- break;
- /* If not going to stop, give terminal back
- if we took it away. */
- else if (printed)
- terminal_inferior ();
+ stopped_by_random_signal = 1;
+
+ if (stop_signal >= NSIG
+ || signal_print[stop_signal])
+ {
+ printed = 1;
+ terminal_ours_for_output ();
+ printf ("\nProgram received signal %d, %s\n",
+ stop_signal,
+ stop_signal < NSIG
+ ? sys_siglist[stop_signal]
+ : "(undocumented)");
+ fflush (stdout);
}
+ if (stop_signal >= NSIG
+ || signal_stop[stop_signal])
+ break;
+ /* If not going to stop, give terminal back
+ if we took it away. */
+ else if (printed)
+ terminal_inferior ();
+ }
- /* Handle cases caused by hitting a breakpoint. */
+ /* Handle cases caused by hitting a breakpoint. */
- if (!random_signal
- && (stop_breakpoint || stop_step_resume_break))
+ if (!random_signal
+ && (stop_breakpoint || stop_step_resume_break))
+ {
+ /* Does a breakpoint want us to stop? */
+ if (stop_breakpoint && stop_breakpoint != -1
+ && stop_breakpoint != -0x1000001)
{
- /* Does a breakpoint want us to stop? */
- if (stop_breakpoint && stop_breakpoint != -1)
- {
- /* 0x1000000 is set in stop_breakpoint as returned by
- breakpoint_status_p to indicate a silent breakpoint. */
- if (stop_breakpoint > 0 && stop_breakpoint & 0x1000000)
- {
- stop_breakpoint &= ~0x1000000;
- stop_print_frame = 0;
- }
- break;
- }
- /* But if we have hit the step-resumption breakpoint,
- remove it. It has done its job getting us here. */
- if (stop_step_resume_break
- && (step_frame == 0 || stop_frame == step_frame))
- {
- remove_step_breakpoint ();
- step_resume_break_address = 0;
- }
- /* Otherwise, must remove breakpoints and single-step
- to get us past the one we hit. */
- else
+ /* 0x1000000 is set in stop_breakpoint as returned by
+ breakpoint_stop_status to indicate a silent
+ breakpoint. */
+ if ((stop_breakpoint > 0 ? stop_breakpoint :
+ -stop_breakpoint)
+ & 0x1000000)
{
- remove_breakpoints ();
- remove_step_breakpoint ();
- breakpoints_inserted = 0;
- another_trap = 1;
+ stop_print_frame = 0;
+ if (stop_breakpoint > 0)
+ stop_breakpoint -= 0x1000000;
+ else
+ stop_breakpoint += 0x1000000;
}
-
- /* We come here if we hit a breakpoint but should not
- stop for it. Possibly we also were stepping
- and should stop for that. So fall through and
- test for stepping. But, if not stepping,
- do not stop. */
+ break;
}
-
- /* If this is the breakpoint at the end of a stack dummy,
- just stop silently. */
- if (stop_sp INNER_THAN stop_pc && stop_pc INNER_THAN stop_frame)
+ /* But if we have hit the step-resumption breakpoint,
+ remove it. It has done its job getting us here.
+ The sp test is to make sure that we don't get hung
+ up in recursive calls in functions without frame
+ pointers. If the stack pointer isn't outside of
+ where the breakpoint was set (within a routine to be
+ stepped over), we're in the middle of a recursive
+ call. Not true for reg window machines (sparc)
+ because the must change frames to call things and
+ the stack pointer doesn't have to change if it
+ the bp was set in a routine without a frame (pc can
+ be stored in some other window).
+
+ The removal of the sp test is to allow calls to
+ alloca. Nasty things were happening. Oh, well,
+ gdb can only handle one level deep of lack of
+ frame pointer. */
+ if (stop_step_resume_break
+ && (step_frame_address == 0
+ || (stop_frame_address == step_frame_address
+#if 0
+#ifndef HAVE_REGISTER_WINDOWS
+ && step_resume_break_sp INNER_THAN stop_sp
+#endif
+#endif
+ )))
{
- stop_print_frame = 0;
- stop_stack_dummy = 1;
+ remove_step_breakpoint ();
+ step_resume_break_address = 0;
+ }
+ /* Otherwise, must remove breakpoints and single-step
+ to get us past the one we hit. */
+ else
+ {
+ remove_breakpoints ();
+ remove_step_breakpoint ();
+ breakpoints_inserted = 0;
+ another_trap = 1;
+ }
+
+ /* We come here if we hit a breakpoint but should not
+ stop for it. Possibly we also were stepping
+ and should stop for that. So fall through and
+ test for stepping. But, if not stepping,
+ do not stop. */
+ }
+
+ /* If this is the breakpoint at the end of a stack dummy,
+ just stop silently. */
+#ifndef CONVEX_PTRACE
+ if (stop_sp INNER_THAN stop_pc
+ && stop_pc INNER_THAN stop_frame_address)
+#else
+ /* "stack" dummy must be in text segment for Convex Unix */
+ if (stop_pc == text_end - 2)
+#endif
+ {
+ stop_print_frame = 0;
+ stop_stack_dummy = 1;
#ifdef HP9K320
- trap_expected_after_continue = 1;
+ trap_expected_after_continue = 1;
#endif
+ break;
+ }
+
+ if (step_resume_break_address)
+ /* Having a step-resume breakpoint overrides anything
+ else having to do with stepping commands until
+ that breakpoint is reached. */
+ ;
+ /* If stepping through a line, keep going if still within it. */
+ else if (!random_signal
+ && step_range_end
+ && stop_pc >= step_range_start
+ && stop_pc < step_range_end
+ /* The step range might include the start of the
+ function, so if we are at the start of the
+ step range and either the stack or frame pointers
+ just changed, we've stepped outside */
+ && !(stop_pc == step_range_start
+ && stop_frame_address
+ && (stop_sp != prev_sp
+ || stop_frame_address != step_frame_address)))
+ {
+ /* Don't step through the return from a function
+ unless that is the first instruction stepped through. */
+ if (ABOUT_TO_RETURN (stop_pc))
+ {
+ stop_step = 1;
break;
}
+ }
- if (step_resume_break_address)
- /* Having a step-resume breakpoint overrides anything
- else having to do with stepping commands until
- that breakpoint is reached. */
- ;
- /* If stepping through a line, keep going if still within it. */
- else if (!random_signal
- && step_range_end
- && stop_pc >= step_range_start
- && stop_pc < step_range_end)
+ /* We stepped out of the stepping range. See if that was due
+ to a subroutine call that we should proceed to the end of. */
+ else if (!random_signal && step_range_end)
+ {
+ if (stop_func_start)
{
- /* Don't step through the return from a function
- unless that is the first instruction stepped through. */
- if (ABOUT_TO_RETURN (stop_pc))
- {
- stop_step = 1;
- break;
- }
+ prologue_pc = stop_func_start;
+ SKIP_PROLOGUE (prologue_pc);
}
- /* We stepped out of the stepping range. See if that was due
- to a subroutine call that we should proceed to the end of. */
- else if (!random_signal && step_range_end)
+ /* ==> See comments at top of file on this algorithm. <==*/
+
+ if (stop_pc == stop_func_start
+ && (stop_func_start != prev_func_start
+ || prologue_pc != stop_func_start
+ || stop_sp != prev_sp))
{
newfun = find_pc_function (stop_pc);
- newmisc = -1;
- if (newfun)
- {
- newfun_pc = BLOCK_START (SYMBOL_BLOCK_VALUE (newfun))
- + FUNCTION_START_OFFSET;
- }
- else
- {
- newmisc = find_pc_misc_function (stop_pc);
- if (newmisc >= 0)
- newfun_pc = misc_function_vector[newmisc].address
- + FUNCTION_START_OFFSET;
- else newfun_pc = 0;
- }
- if (stop_pc == newfun_pc
- && (step_over_calls > 0 || (step_over_calls && newfun == 0)))
+ /* It's a subroutine call */
+ if (step_over_calls > 0 || (step_over_calls && newfun == 0))
{
/* A subroutine call has happened. */
/* Set a special breakpoint after the return */
- step_resume_break_address = SAVED_PC_AFTER_CALL (stop_frame);
+ step_resume_break_address =
+ SAVED_PC_AFTER_CALL (get_current_frame ());
step_resume_break_duplicate
= breakpoint_here_p (step_resume_break_address);
+ step_resume_break_sp = stop_sp;
if (breakpoints_inserted)
insert_step_breakpoint ();
}
/* Subroutine call with source code we should not step over.
Do step to the first line of code in it. */
- else if (stop_pc == newfun_pc && step_over_calls)
+ else if (step_over_calls)
{
- SKIP_PROLOGUE (newfun_pc);
- sal = find_pc_line (newfun_pc, 0);
+ SKIP_PROLOGUE (stop_func_start);
+ sal = find_pc_line (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.
Otherwise, just go to end of prologue. */
- if (sal.end && sal.pc != newfun_pc)
- newfun_pc = sal.end;
-
- if (newfun_pc == stop_pc)
- /* We are already there: stop now. */
- stop_step = 1;
+#ifdef convex
+ /* no, don't either. It skips any code that's
+ legitimately on the first line. */
+#else
+ if (sal.end && sal.pc != stop_func_start)
+ stop_func_start = sal.end;
+#endif
+
+ if (stop_func_start == stop_pc)
+ {
+ /* We are already there: stop now. */
+ stop_step = 1;
+ break;
+ }
else
- /* Put the step-breakpoint there and go until there. */
+ /* Put the step-breakpoint there and go until there. */
{
- step_resume_break_address = newfun_pc;
-
+ step_resume_break_address = stop_func_start;
+ step_resume_break_sp = stop_sp;
+
step_resume_break_duplicate
= breakpoint_here_p (step_resume_break_address);
if (breakpoints_inserted)
@@ -673,22 +894,38 @@ wait_for_inferior ()
/* 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. */
- step_frame = 0;
+ step_frame_address = 0;
/* And make sure stepping stops right away then. */
step_range_end = step_range_start;
}
}
- /* No subroutince call; stop now. */
else
{
+ /* We get here only if step_over_calls is 0 and we
+ just stepped into a subroutine. I presume
+ that step_over_calls is only 0 when we're
+ supposed to be stepping at the assembly
+ language level.*/
stop_step = 1;
break;
}
}
+ /* No subroutince call; stop now. */
+ else
+ {
+ stop_step = 1;
+ break;
+ }
}
/* Save the pc before execution, to compare with pc after stop. */
- prev_pc = read_pc ();
+ prev_pc = read_pc (); /* Might have been DECR_AFTER_BREAK */
+ prev_func_start = 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_sp = stop_sp;
/* If we did not do break;, it means we should keep
running the inferior and not return to debugger. */
@@ -748,9 +985,19 @@ wait_for_inferior ()
BREAKPOINTS_FAILED nonzero means stop was due to error
attempting to insert breakpoints. */
+/* FIXME, normal_stop is ALWAYS called immediately after wait_for_inferior.
+ They should probably be merged into a single function, since that
+ would avoid numerous tests (e.g. of inferior_pid). */
+
static void
normal_stop ()
{
+ /* Make sure that the current_frame's pc is correct. This
+ is a correction for setting up the frame info before doing
+ DECR_PC_AFTER_BREAK */
+ if (inferior_pid)
+ (get_current_frame ())->pc = read_pc ();
+
if (breakpoints_failed)
{
terminal_ours_for_output ();
@@ -781,7 +1028,8 @@ Further execution is probably impossible.\n");
/* If an auto-display called a function and that got a signal,
delete that auto-display to avoid an infinite recursion. */
- delete_current_display ();
+ if (stopped_by_random_signal)
+ delete_current_display ();
if (step_multi && stop_step)
return;
@@ -791,7 +1039,13 @@ Further execution is probably impossible.\n");
if (running_in_shell)
{
if (stop_signal == SIGSEGV)
- printf ("\
+ {
+ char *exec_file = (char *) get_exec_file (1);
+
+ if (access (exec_file, X_OK) != 0)
+ printf ("The file \"%s\" is not executable.\n", exec_file);
+ else
+ printf ("\
You have just encountered a bug in \"sh\". GDB starts your program\n\
by running \"sh\" with a command to exec your program.\n\
This is so that \"sh\" will process wildcards and I/O redirection.\n\
@@ -803,6 +1057,7 @@ some variables whose values are large; then do \"run\" again.\n\
\n\
If that works, you might want to put those \"unset-env\" commands\n\
into a \".gdbinit\" file in this directory so they will happen every time.\n");
+ }
/* Don't confuse user with his program's symbols on sh's data. */
stop_print_frame = 0;
}
@@ -814,14 +1069,14 @@ into a \".gdbinit\" file in this directory so they will happen every time.\n");
or if the program has exited. */
if (!stop_stack_dummy)
{
- select_frame (stop_frame, 0);
+ select_frame (get_current_frame (), 0);
if (stop_print_frame)
{
if (stop_breakpoint > 0)
printf ("\nBpt %d, ", stop_breakpoint);
print_sel_frame (stop_step
- && step_frame == stop_frame
+ && step_frame_address == stop_frame_address
&& step_start_function == find_pc_function (stop_pc));
/* Display the auto-display expressions. */
do_displays ();
@@ -834,9 +1089,11 @@ into a \".gdbinit\" file in this directory so they will happen every time.\n");
if (stop_stack_dummy)
{
- /* Pop the empty frame that contains the stack dummy. */
+ /* Pop the empty frame that contains the stack dummy.
+ POP_FRAME ends with a setting of the current frame, so we
+ can use that next. */
POP_FRAME;
- select_frame (read_register (FP_REGNUM), 0);
+ select_frame (get_current_frame (), 0);
}
}
@@ -868,7 +1125,7 @@ handle_command (args, from_tty)
int from_tty;
{
register char *p = args;
- int signum;
+ int signum = 0;
register int digits, wordlen;
if (!args)
@@ -885,6 +1142,11 @@ handle_command (args, from_tty)
if (digits == wordlen)
{
signum = atoi (p);
+ if (signum <= 0 || signum >= NSIG)
+ {
+ p[wordlen] = '\0';
+ error ("Invalid signal %s given as argument to \"handle\".", p);
+ }
if (signum == SIGTRAP || signum == SIGINT)
{
if (!query ("Signal %d is used by the debugger.\nAre you sure you want to change it? ", signum))
@@ -970,7 +1232,7 @@ signals_info (signum_exp)
{
printf ("[Type Return to see more]");
fflush (stdout);
- read_line ();
+ gdb_read_line (0, 0);
}
printf ("%d\t", i);
printf ("%s\t", signal_stop[i] ? "Yes" : "No");
@@ -982,8 +1244,91 @@ signals_info (signum_exp)
printf ("\nUse the \"handle\" command to change these tables.\n");
}
-static
-initialize ()
+/* Save all of the information associated with the inferior<==>gdb
+ connection. INF_STATUS is a pointer to a "struct inferior_status"
+ (defined in inferior.h). */
+
+struct command_line *get_breakpoint_commands ();
+
+void
+save_inferior_status (inf_status, restore_stack_info)
+ struct inferior_status *inf_status;
+ int restore_stack_info;
+{
+ inf_status->pc_changed = pc_changed;
+ inf_status->stop_signal = stop_signal;
+ inf_status->stop_pc = stop_pc;
+ inf_status->stop_frame_address = stop_frame_address;
+ inf_status->stop_breakpoint = stop_breakpoint;
+ inf_status->stop_step = stop_step;
+ inf_status->stop_stack_dummy = stop_stack_dummy;
+ inf_status->stopped_by_random_signal = stopped_by_random_signal;
+ inf_status->trap_expected = trap_expected;
+ inf_status->step_range_start = step_range_start;
+ inf_status->step_range_end = step_range_end;
+ inf_status->step_frame_address = step_frame_address;
+ inf_status->step_over_calls = step_over_calls;
+ inf_status->step_resume_break_address = step_resume_break_address;
+ inf_status->stop_after_trap = stop_after_trap;
+ inf_status->stop_after_attach = stop_after_attach;
+ inf_status->breakpoint_commands = get_breakpoint_commands ();
+ inf_status->restore_stack_info = restore_stack_info;
+
+ bcopy (stop_registers, inf_status->stop_registers, REGISTER_BYTES);
+
+ record_selected_frame (&(inf_status->selected_frame_address),
+ &(inf_status->selected_level));
+ return;
+}
+
+void
+restore_inferior_status (inf_status)
+ struct inferior_status *inf_status;
+{
+ FRAME fid;
+ int level = inf_status->selected_level;
+
+ pc_changed = inf_status->pc_changed;
+ stop_signal = inf_status->stop_signal;
+ stop_pc = inf_status->stop_pc;
+ stop_frame_address = inf_status->stop_frame_address;
+ stop_breakpoint = inf_status->stop_breakpoint;
+ stop_step = inf_status->stop_step;
+ stop_stack_dummy = inf_status->stop_stack_dummy;
+ stopped_by_random_signal = inf_status->stopped_by_random_signal;
+ trap_expected = inf_status->trap_expected;
+ step_range_start = inf_status->step_range_start;
+ step_range_end = inf_status->step_range_end;
+ step_frame_address = inf_status->step_frame_address;
+ step_over_calls = inf_status->step_over_calls;
+ step_resume_break_address = inf_status->step_resume_break_address;
+ stop_after_trap = inf_status->stop_after_trap;
+ stop_after_attach = inf_status->stop_after_attach;
+ set_breakpoint_commands (inf_status->breakpoint_commands);
+
+ bcopy (inf_status->stop_registers, stop_registers, REGISTER_BYTES);
+
+ if (inf_status->restore_stack_info)
+ {
+ fid = find_relative_frame (get_current_frame (),
+ &level);
+
+ if (FRAME_FP (fid) != inf_status->selected_frame_address ||
+ level != 0)
+ {
+ fprintf (stderr, "Unable to restore previously selected frame.\n");
+ select_frame (get_current_frame (), 0);
+ return;
+ }
+
+ select_frame (fid, inf_status->selected_level);
+ }
+ return;
+}
+
+
+void
+_initialize_infrun ()
{
register int i;
@@ -1044,148 +1389,3 @@ Pass and Stop may be combined.");
#endif /* SIGURG */
}
-#ifdef NO_SINGLE_STEP
-/* This code was written by Gary Beihl (beihl@mcc.com).
- It was modified by Michael Tiemann (tiemann@corto.inria.fr). */
-
-/* Simulate single-step ptrace call for sun4. */
-
-typedef enum
-{
- b_error, not_branch, bicc, bicca, ba, baa, ticc, ta,
-} branch_type;
-
-static CORE_ADDR next_pc, pc8, target;
-static int brkpc8, brktrg;
-typedef char binsn_quantum[sizeof break_insn];
-static binsn_quantum break_mem[3];
-
-int
-single_step (signal)
- int signal;
-{
- branch_type br, isabranch();
-
- next_pc = read_register (NPC_REGNUM);
- pc8 = read_register (PC_REGNUM) + 8; /* branch not taken */
-
- if (!one_stepped)
- {
- /* Always set breakpoint for NPC. */
- read_memory (next_pc, break_mem[0], sizeof break_insn);
- write_memory (next_pc, break_insn, sizeof break_insn);
-
- /* printf ("set break at %x\n",next_pc); */
- br = isabranch (pc8 - 8, &target);
- brkpc8 = brktrg = 0;
-
- if (br == bicca && pc8 != next_pc)
- {
- /* Handle branches with care */
- brkpc8 = 1;
- read_memory (pc8, break_mem[1], sizeof break_insn);
- write_memory (pc8, break_insn, sizeof break_insn);
- }
- else if (br == baa && target != next_pc)
- {
- brktrg = 1;
- read_memory (target, break_mem[2], sizeof break_insn);
- write_memory (target, break_insn, sizeof break_insn);
- }
-
- /* Let it go */
- ptrace (7, inferior_pid, 1, signal);
- one_stepped = 1;
- return;
- }
- else
- {
- /* Remove breakpoints */
- write_memory (next_pc, break_mem[0], sizeof break_insn);
-
- if (brkpc8)
- {
- write_memory (pc8, break_mem[1], sizeof break_insn);
- }
- if (brktrg)
- {
- write_memory (target, break_mem[2], sizeof break_insn);
- }
- one_stepped = 0;
- }
-}
-
-#endif /* NO_SINGLE_STEP */
-
-static int save_insn_opcodes[] = { 0x03000000, 0x82007ee0, 0x9de38001, 0x03000000, 0x82007ee0, 0x91d02001, 0x01000000 };
-
-void
-do_save_insn (size)
- int size;
-{
- int g1 = read_register (1);
- CORE_ADDR sp = read_register (SP_REGNUM);
- CORE_ADDR pc = read_register (PC_REGNUM);
-#ifdef NPC_REGNUM
- CORE_ADDR npc = read_register (NPC_REGNUM);
-#endif
- CORE_ADDR fake_pc = sp - sizeof (save_insn_opcodes);
- save_insn_opcodes[0] = 0x03000000 | ((-size >> 12) & 0x3fffff);
- save_insn_opcodes[1] = 0x82006000 | (-size & 0x3ff);
- save_insn_opcodes[3] = 0x03000000 | ((g1 >> 12) & 0x3fffff);
- save_insn_opcodes[4] = 0x82006000 | (g1 & 0x3ff);
- write_memory (fake_pc, save_insn_opcodes, sizeof (save_insn_opcodes));
- clear_proceed_status ();
- stop_after_trap = 1;
-
- proceed (fake_pc, 0, 0);
-
- write_register (PC_REGNUM, pc);
-#ifdef NPC_REGNUM
- write_register (NPC_REGNUM, npc);
-#endif
-}
-
-static int restore_insn_opcodes[] = { 0x81e80000, 0x91d02001, 0x01000000 };
-
-void
-do_restore_insn (raw_buffer)
- char raw_buffer[];
-{
- CORE_ADDR pc = read_memory_integer (*(int *)&raw_buffer[REGISTER_BYTE (PC_REGNUM)], 4);
- CORE_ADDR sp = read_register (SP_REGNUM);
-#ifdef NPC_REGNUM
- CORE_ADDR npc = *(int *)&raw_buffer[REGISTER_BYTE (NPC_REGNUM)] != 0
- ? read_memory_integer (*(int *)&raw_buffer[REGISTER_BYTE (NPC_REGNUM)], 4) : pc + 4;
-#endif
- CORE_ADDR fake_pc = sp - sizeof (restore_insn_opcodes);
- int saved_stop_stack_dummy = stop_stack_dummy;
-
- if (*(int *)&raw_buffer[REGISTER_BYTE (PC_REGNUM)] == 0)
- abort ();
-
- write_memory (fake_pc, restore_insn_opcodes, sizeof (restore_insn_opcodes));
- clear_proceed_status ();
- stop_after_trap = 1;
-
- proceed (fake_pc, 0, 0);
-
- stop_stack_dummy = saved_stop_stack_dummy;
- write_register (PC_REGNUM, pc);
-#ifdef NPC_REGNUM
- write_register (NPC_REGNUM, npc);
-#endif
-
- /* Select innermost stack frame except on return from a stack dummy routine,
- or if the program has exited. */
- if (!stop_stack_dummy)
- {
- select_frame (stop_frame, 0);
- }
- else
- {
- select_frame (read_register (FP_REGNUM), 0);
- }
-}
-
-END_FILE