diff options
Diffstat (limited to 'gdb/infrun.c')
-rw-r--r-- | gdb/infrun.c | 984 |
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 |