X-Git-Url: https://repo.jachan.dev/binutils.git/blobdiff_plain/67ac97591175936a06cc1ef1df228746edcdb545..48f4903f369709dde852872db542afbb536acd54:/gdb/infrun.c diff --git a/gdb/infrun.c b/gdb/infrun.c index 8df0248d11..5ad2bfc45d 100644 --- a/gdb/infrun.c +++ b/gdb/infrun.c @@ -1,5 +1,5 @@ /* Target-struct-independent code to start (run) and stop an inferior process. - Copyright 1986, 1987, 1988, 1989, 1991, 1992, 1993 + Copyright 1986, 1987, 1988, 1989, 1991, 1992, 1993, 1994 Free Software Foundation, Inc. This file is part of GDB. @@ -30,6 +30,7 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include "gdbcmd.h" #include "target.h" #include "thread.h" +#include "annotate.h" #include @@ -42,26 +43,22 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ /* Prototypes for local functions */ -static void -signals_info PARAMS ((char *, int)); +static void signals_info PARAMS ((char *, int)); -static void -handle_command PARAMS ((char *, int)); +static void handle_command PARAMS ((char *, int)); static void sig_print_info PARAMS ((enum target_signal)); -static void -sig_print_header PARAMS ((void)); +static void sig_print_header PARAMS ((void)); -static void -resume_cleanups PARAMS ((int)); +static void resume_cleanups PARAMS ((int)); -static int -hook_stop_stub PARAMS ((char *)); +static int hook_stop_stub PARAMS ((char *)); /* GET_LONGJMP_TARGET returns the PC at which longjmp() will resume the program. It needs to examine the jmp_buf argument and extract the PC from it. The return value is non-zero on success, zero otherwise. */ + #ifndef GET_LONGJMP_TARGET #define GET_LONGJMP_TARGET(PC_ADDR) 0 #endif @@ -70,22 +67,24 @@ hook_stop_stub PARAMS ((char *)); /* Some machines have trampoline code that sits between function callers and the actual functions themselves. If this machine doesn't have such things, disable their processing. */ + #ifndef SKIP_TRAMPOLINE_CODE #define SKIP_TRAMPOLINE_CODE(pc) 0 #endif -/* On Irix 5, some function calls automatically skip the first few - instructions, so we need a more complicated test to see if we are - the start of a function. */ -#ifndef AT_FUNCTION_START -#define AT_FUNCTION_START(pc,func_name,func_addr) 0 -#endif - /* For SVR4 shared libraries, each call goes through a small piece of - trampoline code in the ".init" section. IN_SOLIB_TRAMPOLINE evaluates + trampoline code in the ".plt" section. IN_SOLIB_CALL_TRAMPOLINE evaluates to nonzero if we are current stopped in one of these. */ -#ifndef IN_SOLIB_TRAMPOLINE -#define IN_SOLIB_TRAMPOLINE(pc,name) 0 + +#ifndef IN_SOLIB_CALL_TRAMPOLINE +#define IN_SOLIB_CALL_TRAMPOLINE(pc,name) 0 +#endif + +/* In some shared library schemes, the return path from a shared library + call may need to go through a trampoline too. */ + +#ifndef IN_SOLIB_RETURN_TRAMPOLINE +#define IN_SOLIB_RETURN_TRAMPOLINE(pc,name) 0 #endif /* On some systems, the PC may be left pointing at an instruction that won't @@ -137,11 +136,13 @@ static struct symbol *step_start_function; static int trap_expected; +#ifdef HP_OS_BUG /* Nonzero if the next time we try to continue the inferior, it will step one instruction and generate a spurious trace trap. This is used to compensate for a bug in HP-UX. */ static int trap_expected_after_continue; +#endif /* Nonzero means expecting a trace trap and should stop the inferior and return silently when it happens. */ @@ -287,10 +288,38 @@ proceed (addr, siggnal, step) if (breakpoint_here_p (read_pc ())) oneproc = 1; + +#ifdef STEP_SKIPS_DELAY + /* Check breakpoint_here_p first, because breakpoint_here_p is fast + (it just checks internal GDB data structures) and STEP_SKIPS_DELAY + is slow (it needs to read memory from the target). */ + if (breakpoint_here_p (read_pc () + 4) + && STEP_SKIPS_DELAY (read_pc ())) + oneproc = 1; +#endif /* STEP_SKIPS_DELAY */ } else write_pc (addr); +#ifdef PREPARE_TO_PROCEED + /* In a multi-threaded task we may select another thread and then continue. + + In this case the thread that stopped at a breakpoint will immediately + cause another stop, if it is not stepped over first. On the other hand, + if (ADDR != -1) we only want to single step over the breakpoint if we did + switch to another thread. + + If we are single stepping, don't do any of the above. + (Note that in the current implementation single stepping another + thread after a breakpoint and then continuing will cause the original + breakpoint to be hit again, but you can always continue, so it's not + a big deal.) */ + + if (! step && PREPARE_TO_PROCEED (1) && breakpoint_here_p (read_pc ())) + oneproc = 1; +#endif /* PREPARE_TO_PROCEED */ + +#ifdef HP_OS_BUG if (trap_expected_after_continue) { /* If (step == 0), a trap will be automatically generated after @@ -300,6 +329,7 @@ proceed (addr, siggnal, step) oneproc = 1; trap_expected_after_continue = 0; } +#endif /* HP_OS_BUG */ if (oneproc) /* We will get a trace trap after one instruction. @@ -317,12 +347,18 @@ The same program may be running in another process."); breakpoints_inserted = 1; } - if (siggnal >= 0) + if (siggnal != TARGET_SIGNAL_DEFAULT) stop_signal = siggnal; /* If this signal should not be seen by program, give it zero. Used for debugging signals. */ else if (!signal_program[stop_signal]) - stop_signal= 0; + stop_signal = TARGET_SIGNAL_0; + + annotate_starting (); + + /* Make sure that output from GDB appears before output from the + inferior. */ + gdb_flush (gdb_stdout); /* Resume inferior. */ resume (oneproc || step || bpstat_should_step (), stop_signal); @@ -339,7 +375,6 @@ The same program may be running in another process."); to be preserved over calls to it and cleared when the inferior is started. */ static CORE_ADDR prev_pc; -static CORE_ADDR prev_sp; static CORE_ADDR prev_func_start; static char *prev_func_name; @@ -349,6 +384,7 @@ static char *prev_func_name; void start_remote () { + init_thread_list (); init_wait_for_inferior (); clear_proceed_status (); stop_soon_quietly = 1; @@ -364,11 +400,12 @@ init_wait_for_inferior () { /* These are meaningless until the first time through wait_for_inferior. */ prev_pc = 0; - prev_sp = 0; prev_func_start = 0; prev_func_name = NULL; +#ifdef HP_OS_BUG trap_expected_after_continue = 0; +#endif breakpoints_inserted = 0; breakpoint_init_inferior (); @@ -398,7 +435,6 @@ wait_for_inferior () struct target_waitstatus w; int another_trap; int random_signal; - CORE_ADDR stop_sp = 0; CORE_ADDR stop_func_start; CORE_ADDR stop_func_end; char *stop_func_name; @@ -409,189 +445,237 @@ wait_for_inferior () struct symtab *current_symtab; int handling_longjmp = 0; /* FIXME */ struct breakpoint *step_resume_breakpoint = NULL; + struct breakpoint *through_sigtramp_breakpoint = NULL; int pid; + int update_step_sp = 0; old_cleanups = make_cleanup (delete_breakpoint_current_contents, &step_resume_breakpoint); + make_cleanup (delete_breakpoint_current_contents, + &through_sigtramp_breakpoint); sal = find_pc_line(prev_pc, 0); current_line = sal.line; current_symtab = sal.symtab; /* Are we stepping? */ -#define CURRENTLY_STEPPING() ((step_resume_breakpoint == NULL \ - && !handling_longjmp \ - && (step_range_end \ - || trap_expected)) \ - || bpstat_should_step ()) +#define CURRENTLY_STEPPING() \ + ((through_sigtramp_breakpoint == NULL \ + && !handling_longjmp \ + && ((step_range_end && step_resume_breakpoint == NULL) \ + || trap_expected)) \ + || bpstat_should_step ()) while (1) { - /* Clean up saved state that will become invalid. */ - flush_cached_frames (); + /* 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 (); - pid = target_wait (-1, &w); + if (target_wait_hook) + pid = target_wait_hook (-1, &w); + else + pid = target_wait (-1, &w); -#ifdef SIGTRAP_STOP_AFTER_LOAD + have_waited: - /* Somebody called load(2), and it gave us a "trap signal after load". - Ignore it gracefully. */ + flush_cached_frames (); - SIGTRAP_STOP_AFTER_LOAD (w); -#endif + /* If it's a new process, add it to the thread database */ - /* See if the process still exists; clean up if it doesn't. */ - if (w.kind == TARGET_WAITKIND_EXITED) + if (pid != inferior_pid + && !in_thread_list (pid)) { + fprintf_unfiltered (gdb_stderr, "[New %s]\n", target_pid_to_str (pid)); + add_thread (pid); + + /* We may want to consider not doing a resume here in order to give + the user a chance to play with the new thread. It might be good + to make that a user-settable option. */ + + /* At this point, all threads are stopped (happens automatically in + either the OS or the native code). Therefore we need to continue + all threads in order to make progress. */ + + target_resume (-1, 0, TARGET_SIGNAL_0); + continue; + } + + switch (w.kind) + { + case TARGET_WAITKIND_LOADED: + /* Ignore it gracefully. */ + if (breakpoints_inserted) + { + mark_breakpoints_out (); + insert_breakpoints (); + } + resume (0, TARGET_SIGNAL_0); + continue; + + case TARGET_WAITKIND_SPURIOUS: + resume (0, TARGET_SIGNAL_0); + continue; + + case TARGET_WAITKIND_EXITED: target_terminal_ours (); /* Must do this before mourn anyway */ + annotate_exited (w.value.integer); if (w.value.integer) printf_filtered ("\nProgram exited with code 0%o.\n", (unsigned int)w.value.integer); else - if (!batch_mode()) - printf_filtered ("\nProgram exited normally.\n"); + printf_filtered ("\nProgram exited normally.\n"); gdb_flush (gdb_stdout); target_mourn_inferior (); #ifdef NO_SINGLE_STEP one_stepped = 0; #endif stop_print_frame = 0; - break; - } - else if (w.kind == TARGET_WAITKIND_SIGNALLED) - { - char *signame; + goto stop_stepping; + case TARGET_WAITKIND_SIGNALLED: stop_print_frame = 0; stop_signal = w.value.sig; target_terminal_ours (); /* Must do this before mourn anyway */ + annotate_signalled (); + + /* This looks pretty bogus to me. Doesn't TARGET_WAITKIND_SIGNALLED + mean it is already dead? This has been here since GDB 2.8, so + perhaps it means rms didn't understand unix waitstatuses? + For the moment I'm just kludging around this in remote.c + rather than trying to change it here --kingdon, 5 Dec 1994. */ target_kill (); /* kill mourns as well */ - printf_filtered ("\nProgram terminated with signal %s, %s.\n", - target_signal_to_name (stop_signal), - target_signal_to_string (stop_signal)); + + printf_filtered ("\nProgram terminated with signal "); + annotate_signal_name (); + printf_filtered ("%s", target_signal_to_name (stop_signal)); + annotate_signal_name_end (); + printf_filtered (", "); + annotate_signal_string (); + printf_filtered ("%s", target_signal_to_string (stop_signal)); + annotate_signal_string_end (); + printf_filtered (".\n"); printf_filtered ("The program no longer exists.\n"); gdb_flush (gdb_stdout); #ifdef NO_SINGLE_STEP one_stepped = 0; #endif + goto stop_stepping; + + case TARGET_WAITKIND_STOPPED: + /* This is the only case in which we keep going; the above cases + end in a continue or goto. */ break; } stop_signal = w.value.sig; - if (pid != inferior_pid) - { - int save_pid = inferior_pid; + stop_pc = read_pc_pid (pid); - inferior_pid = pid; /* Setup for target memory/regs */ - registers_changed (); - stop_pc = read_pc (); - inferior_pid = save_pid; - registers_changed (); - } - else - stop_pc = read_pc (); + /* See if a thread hit a thread-specific breakpoint that was meant for + another thread. If so, then step that thread past the breakpoint, + and continue it. */ if (stop_signal == TARGET_SIGNAL_TRAP + && breakpoints_inserted && breakpoint_here_p (stop_pc - DECR_PC_AFTER_BREAK)) { + random_signal = 0; if (!breakpoint_thread_match (stop_pc - DECR_PC_AFTER_BREAK, pid)) { /* Saw a breakpoint, but it was hit by the wrong thread. Just continue. */ - if (breakpoints_inserted) - { - if (pid != inferior_pid) - { - int save_pid = inferior_pid; - - inferior_pid = pid; - registers_changed (); - write_pc (stop_pc - DECR_PC_AFTER_BREAK); - inferior_pid = save_pid; - registers_changed (); - } - else - write_pc (stop_pc - DECR_PC_AFTER_BREAK); - - remove_breakpoints (); - target_resume (pid, 1, TARGET_SIGNAL_0); /* Single step */ - /* FIXME: What if a signal arrives instead of the single-step - happening? */ - target_wait (pid, &w); - insert_breakpoints (); - } + write_pc_pid (stop_pc - DECR_PC_AFTER_BREAK, pid); + + remove_breakpoints (); + target_resume (pid, 1, TARGET_SIGNAL_0); /* Single step */ + /* FIXME: What if a signal arrives instead of the single-step + happening? */ + + if (target_wait_hook) + target_wait_hook (pid, &w); + else + target_wait (pid, &w); + insert_breakpoints (); + + /* We need to restart all the threads now. */ target_resume (-1, 0, TARGET_SIGNAL_0); continue; } - else - if (pid != inferior_pid) - goto switch_thread; } + else + random_signal = 1; + + /* See if something interesting happened to the non-current thread. If + so, then switch to that thread, and eventually give control back to + the user. */ if (pid != inferior_pid) { int printed = 0; - if (!in_thread_list (pid)) + /* If it's a random signal for a non-current thread, notify user + if he's expressed an interest. */ + + if (random_signal + && signal_print[stop_signal]) + { + printed = 1; + target_terminal_ours_for_output (); + printf_filtered ("\nProgram received signal %s, %s.\n", + target_signal_to_name (stop_signal), + target_signal_to_string (stop_signal)); + gdb_flush (gdb_stdout); + } + + /* If it's not SIGTRAP and not a signal we want to stop for, then + continue the thread. */ + + if (stop_signal != TARGET_SIGNAL_TRAP + && !signal_stop[stop_signal]) { - fprintf_unfiltered (gdb_stderr, "[New %s]\n", target_pid_to_str (pid)); - add_thread (pid); + if (printed) + target_terminal_inferior (); - target_resume (-1, 0, TARGET_SIGNAL_0); + /* Clear the signal if it should not be passed. */ + if (signal_program[stop_signal] == 0) + stop_signal = TARGET_SIGNAL_0; + + target_resume (pid, 0, stop_signal); continue; } - else - { - if (signal_print[stop_signal]) - { - char *signame; - - printed = 1; - target_terminal_ours_for_output (); - printf_filtered ("\nProgram received signal %s, %s.\n", - target_signal_to_name (stop_signal), - target_signal_to_string (stop_signal)); - gdb_flush (gdb_stdout); - } - - if (stop_signal == TARGET_SIGNAL_TRAP - || signal_stop[stop_signal]) - { -switch_thread: - inferior_pid = pid; - printf_filtered ("[Switching to %s]\n", target_pid_to_str (pid)); - - flush_cached_frames (); - registers_changed (); - trap_expected = 0; - if (step_resume_breakpoint) - { - delete_breakpoint (step_resume_breakpoint); - step_resume_breakpoint = NULL; - } - prev_pc = 0; - prev_sp = 0; - prev_func_name = NULL; - step_range_start = 0; - step_range_end = 0; - step_frame_address = 0; - handling_longjmp = 0; - another_trap = 0; - } - else - { - if (printed) - target_terminal_inferior (); - /* Clear the signal if it should not be passed. */ - if (signal_program[stop_signal] == 0) - stop_signal = TARGET_SIGNAL_0; + /* It's a SIGTRAP or a signal we're interested in. Switch threads, + and fall into the rest of wait_for_inferior(). */ + + inferior_pid = pid; + printf_filtered ("[Switching to %s]\n", target_pid_to_str (pid)); + + flush_cached_frames (); + trap_expected = 0; + if (step_resume_breakpoint) + { + delete_breakpoint (step_resume_breakpoint); + step_resume_breakpoint = NULL; + } - target_resume (pid, 0, stop_signal); - continue; - } + /* Not sure whether we need to blow this away too, + but probably it is like the step-resume + breakpoint. */ + if (through_sigtramp_breakpoint) + { + delete_breakpoint (through_sigtramp_breakpoint); + through_sigtramp_breakpoint = NULL; } + prev_pc = 0; + prev_func_name = NULL; + step_range_start = 0; + step_range_end = 0; + step_frame_address = 0; + handling_longjmp = 0; + another_trap = 0; } #ifdef NO_SINGLE_STEP @@ -599,8 +683,9 @@ switch_thread: single_step (0); /* This actually cleans up the ss */ #endif /* NO_SINGLE_STEP */ -/* If PC is pointing at a nullified instruction, then step beyond it so that - the user won't be confused when GDB appears to be ready to execute it. */ + /* If PC is pointing at a nullified instruction, then step beyond + it so that the user won't be confused when GDB appears to be ready + to execute it. */ if (INSTRUCTION_NULLIFIED) { @@ -608,10 +693,60 @@ switch_thread: continue; } - set_current_frame ( create_new_frame (read_fp (), stop_pc)); +#ifdef HAVE_STEPPABLE_WATCHPOINT + /* It may not be necessary to disable the watchpoint to stop over + it. For example, the PA can (with some kernel cooperation) + single step over a watchpoint without disabling the watchpoint. */ + if (STOPPED_BY_WATCHPOINT (w)) + { + resume (1, 0); + continue; + } +#endif + +#ifdef HAVE_NONSTEPPABLE_WATCHPOINT + /* It is far more common to need to disable a watchpoint + to step the inferior over it. FIXME. What else might + a debug register or page protection watchpoint scheme need + here? */ + if (STOPPED_BY_WATCHPOINT (w)) + { +/* At this point, we are stopped at an instruction which has attempted to write + to a piece of memory under control of a watchpoint. The instruction hasn't + actually executed yet. If we were to evaluate the watchpoint expression + now, we would get the old value, and therefore no change would seem to have + occurred. + + In order to make watchpoints work `right', we really need to complete the + memory write, and then evaluate the watchpoint expression. The following + code does that by removing the watchpoint (actually, all watchpoints and + breakpoints), single-stepping the target, re-inserting watchpoints, and then + falling through to let normal single-step processing handle proceed. Since + this includes evaluating watchpoints, things will come to a stop in the + correct manner. */ + + write_pc (stop_pc - DECR_PC_AFTER_BREAK); + + remove_breakpoints (); + target_resume (pid, 1, TARGET_SIGNAL_0); /* Single step */ + + if (target_wait_hook) + target_wait_hook (pid, &w); + else + target_wait (pid, &w); + insert_breakpoints (); + /* FIXME-maybe: is this cleaner than setting a flag? Does it + handle things like signals arriving and other things happening + in combination correctly? */ + goto have_waited; + } +#endif + +#ifdef HAVE_CONTINUABLE_WATCHPOINT + /* It may be possible to simply continue after a watchpoint. */ + STOPPED_BY_WATCHPOINT (w); +#endif - stop_frame_address = FRAME_FP (get_current_frame ()); - stop_sp = read_sp (); stop_func_start = 0; stop_func_name = 0; /* Don't care about return value; stop_func_start and stop_func_name @@ -662,17 +797,17 @@ switch_thread: if just proceeded over a breakpoint. However, if we are trying to proceed over a breakpoint - and end up in sigtramp, then step_resume_breakpoint + and end up in sigtramp, then through_sigtramp_breakpoint will be set and we should check whether we've hit the step breakpoint. */ if (stop_signal == TARGET_SIGNAL_TRAP && trap_expected - && step_resume_breakpoint == NULL) + && through_sigtramp_breakpoint == NULL) bpstat_clear (&stop_bpstat); else { /* See if there is a breakpoint at the current PC. */ stop_bpstat = bpstat_stop_status - (&stop_pc, stop_frame_address, + (&stop_pc, #if DECR_PC_AFTER_BREAK /* Notice the case of stepping through a jump that lands just after a breakpoint. @@ -696,7 +831,8 @@ switch_thread: = !(bpstat_explains_signal (stop_bpstat) || trap_expected #ifndef CALL_DUMMY_BREAKPOINT_OFFSET - || PC_IN_CALL_DUMMY (stop_pc, stop_sp, stop_frame_address) + || PC_IN_CALL_DUMMY (stop_pc, read_sp (), + FRAME_FP (get_current_frame ())) #endif /* No CALL_DUMMY_BREAKPOINT_OFFSET. */ || (step_range_end && step_resume_breakpoint == NULL)); else @@ -707,7 +843,8 @@ switch_thread: news) give another signal besides SIGTRAP, so check here as well as above. */ #ifndef CALL_DUMMY_BREAKPOINT_OFFSET - || PC_IN_CALL_DUMMY (stop_pc, stop_sp, stop_frame_address) + || PC_IN_CALL_DUMMY (stop_pc, read_sp (), + FRAME_FP (get_current_frame ())) #endif /* No CALL_DUMMY_BREAKPOINT_OFFSET. */ ); if (!random_signal) @@ -729,12 +866,18 @@ switch_thread: if (signal_print[stop_signal]) { - char *signame; printed = 1; target_terminal_ours_for_output (); - printf_filtered ("\nProgram received signal %s, %s.\n", - target_signal_to_name (stop_signal), - target_signal_to_string (stop_signal)); + annotate_signal (); + printf_filtered ("\nProgram received signal "); + annotate_signal_name (); + printf_filtered ("%s", target_signal_to_name (stop_signal)); + annotate_signal_name_end (); + printf_filtered (", "); + annotate_signal_string (); + printf_filtered ("%s", target_signal_to_string (stop_signal)); + annotate_signal_string_end (); + printf_filtered (".\n"); gdb_flush (gdb_stdout); } if (signal_stop[stop_signal]) @@ -785,7 +928,13 @@ switch_thread: { delete_breakpoint (step_resume_breakpoint); step_resume_breakpoint = NULL; - what.step_resume = 0; + } + /* Not sure whether we need to blow this away too, but probably + it is like the step-resume breakpoint. */ + if (through_sigtramp_breakpoint != NULL) + { + delete_breakpoint (through_sigtramp_breakpoint); + through_sigtramp_breakpoint = NULL; } #if 0 @@ -806,7 +955,7 @@ switch_thread: #if 0 /* FIXME - Need to implement nested temporary breakpoints */ if (step_over_calls - && (stop_frame_address + && (FRAME_FP (get_current_frame ()) INNER_THAN step_frame_address)) { another_trap = 1; @@ -830,32 +979,43 @@ switch_thread: case BPSTAT_WHAT_STOP_NOISY: stop_print_frame = 1; - /* We are about to nuke the step_resume_breakpoint via the - cleanup chain, so no need to worry about it here. */ + + /* We are about to nuke the step_resume_breakpoint and + through_sigtramp_breakpoint via the cleanup chain, so + no need to worry about it here. */ + goto stop_stepping; case BPSTAT_WHAT_STOP_SILENT: stop_print_frame = 0; - /* We are about to nuke the step_resume_breakpoint via the - cleanup chain, so no need to worry about it here. */ - goto stop_stepping; - case BPSTAT_WHAT_LAST: - /* Not a real code, but listed here to shut up gcc -Wall. */ + /* We are about to nuke the step_resume_breakpoint and + through_sigtramp_breakpoint via the cleanup chain, so + no need to worry about it here. */ - case BPSTAT_WHAT_KEEP_CHECKING: - break; - } + goto stop_stepping; - if (what.step_resume) - { + case BPSTAT_WHAT_STEP_RESUME: delete_breakpoint (step_resume_breakpoint); step_resume_breakpoint = NULL; + break; + + case BPSTAT_WHAT_THROUGH_SIGTRAMP: + if (through_sigtramp_breakpoint) + delete_breakpoint (through_sigtramp_breakpoint); + through_sigtramp_breakpoint = NULL; /* If were waiting for a trap, hitting the step_resume_break doesn't count as getting it. */ if (trap_expected) another_trap = 1; + break; + + case BPSTAT_WHAT_LAST: + /* Not a real code, but listed here to shut up gcc -Wall. */ + + case BPSTAT_WHAT_KEEP_CHECKING: + break; } } @@ -875,7 +1035,7 @@ switch_thread: just stop silently, unless the user was doing an si/ni, in which case she'd better know what she's doing. */ - if (PC_IN_CALL_DUMMY (stop_pc, stop_sp, stop_frame_address) + if (PC_IN_CALL_DUMMY (stop_pc, read_sp (), FRAME_FP (get_current_frame ())) && !step_range_end) { stop_print_frame = 0; @@ -891,10 +1051,8 @@ switch_thread: /* Having a step-resume breakpoint overrides anything else having to do with stepping commands until that breakpoint is reached. */ - /* I suspect this could/should be keep_going, because if the - check_sigtramp2 check succeeds, then it will put in another - step_resume_breakpoint, and we aren't (yet) prepared to nest - them. */ + /* I'm not sure whether this needs to be check_sigtramp2 or + whether it could/should be keep_going. */ goto check_sigtramp2; if (step_range_end == 0) @@ -911,36 +1069,48 @@ switch_thread: 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 INNER_THAN prev_sp - || stop_frame_address != step_frame_address))) + && FRAME_FP (get_current_frame ()) + && (read_sp () INNER_THAN step_sp + || FRAME_FP (get_current_frame ()) != step_frame_address))) { /* We might be doing a BPSTAT_WHAT_SINGLE and getting a signal. So definately need to check for sigtramp here. */ goto check_sigtramp2; } - /* We stepped out of the stepping range. See if that was due - to a subroutine call that we should proceed to the end of. */ + /* We stepped out of the stepping range. */ + + /* We can't update step_sp every time through the loop, because + reading the stack pointer would slow down stepping too much. + But we can update it every time we leave the step range. */ + update_step_sp = 1; /* Did we just take a signal? */ if (IN_SIGTRAMP (stop_pc, stop_func_name) && !IN_SIGTRAMP (prev_pc, prev_func_name)) { + /* We've just taken a signal; go until we are back to + the point where we took it and one more. */ + /* This code is needed at least in the following case: The user types "next" and then a signal arrives (before the "next" is done). */ - /* We've just taken a signal; go until we are back to - the point where we took it and one more. */ + + /* Note that if we are stopped at a breakpoint, then we need + the step_resume breakpoint to override any breakpoints at + the same location, so that we will still step over the + breakpoint even though the signal happened. */ + { struct symtab_and_line sr_sal; sr_sal.pc = prev_pc; sr_sal.symtab = NULL; sr_sal.line = 0; + /* We could probably be setting the frame to + step_frame_address; I don't think anyone thought to try it. */ step_resume_breakpoint = - set_momentary_breakpoint (sr_sal, get_current_frame (), - bp_step_resume); + set_momentary_breakpoint (sr_sal, NULL, bp_step_resume); if (breakpoints_inserted) insert_breakpoints (); } @@ -957,12 +1127,22 @@ switch_thread: goto keep_going; } +#if 1 + /* See if we left the step range due to a subroutine call that + we should proceed to the end of. */ + if (stop_func_start) { + struct symtab *s; + /* Do this after the IN_SIGTRAMP check; it might give an error. */ prologue_pc = stop_func_start; - SKIP_PROLOGUE (prologue_pc); + + /* Don't skip the prologue if this is assembly source */ + s = find_pc_symtab (stop_pc); + if (s && s->language != language_asm) + SKIP_PROLOGUE (prologue_pc); } if ((/* Might be a non-recursive call. If the symbols are missing @@ -974,22 +1154,13 @@ switch_thread: /* Might be a recursive call if either we have a prologue or the call instruction itself saves the PC on the stack. */ || prologue_pc != stop_func_start - || stop_sp != prev_sp) + || read_sp () != step_sp) && (/* PC is completely out of bounds of any known objfiles. Treat like a subroutine call. */ ! stop_func_start /* If we do a call, we will be at the start of a function... */ || stop_pc == stop_func_start -#if 0 - /* Should be taken care of by the stop_pc < prologue_pc check - below. Also, on irix5 where this checks for stop_pc - equal to stop_func_start plus 12, it would seem to be - wrong for a function with a 4 byte prologue, and an 8 byte - call; a "return" could end up at stop_func_start+12. */ - - || AT_FUNCTION_START (stop_pc, stop_func_name, stop_func_start) -#endif /* ...except on the Alpha with -O (and also Irix 5 and perhaps others), in which we might call the address @@ -999,17 +1170,35 @@ switch_thread: || stop_pc < prologue_pc + /* ...and if it is a leaf function, the prologue might + consist of gp loading only, so the call transfers to + the first instruction after the prologue. */ + || (stop_pc == prologue_pc + + /* Distinguish this from the case where we jump back + to the first instruction after the prologue, + within a function. */ + && stop_func_start != prev_func_start) + /* If we end up in certain places, it means we did a subroutine call. I'm not completely sure this is necessary now that we have the above checks with stop_func_start (and now that find_pc_partial_function is pickier). */ - || IN_SOLIB_TRAMPOLINE (stop_pc, stop_func_name) + || IN_SOLIB_CALL_TRAMPOLINE (stop_pc, stop_func_name) /* If none of the above apply, it is a jump within a function, or a return from a subroutine. The other case is longjmp, which can no longer happen here as long as the handling_longjmp stuff is working. */ )) +#else +/* This is experimental code which greatly simplifies the subroutine call + test. I've actually tested on the Alpha, and it works great. -Stu */ + + if (in_prologue (stop_pc, NULL) + || (prev_func_start != 0 + && stop_func_start == 0)) +#endif { /* It's a subroutine call. */ @@ -1062,6 +1251,7 @@ step_over_function: step_resume_breakpoint = set_momentary_breakpoint (sr_sal, get_current_frame (), bp_step_resume); + step_resume_breakpoint->frame = step_frame_address; if (breakpoints_inserted) insert_breakpoints (); } @@ -1070,7 +1260,13 @@ step_over_function: step_into_function: /* Subroutine call with source code we should not step over. Do step to the first line of code in it. */ - SKIP_PROLOGUE (stop_func_start); + { + struct symtab *s; + + s = find_pc_symtab (stop_pc); + if (s && s->language != language_asm) + 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 @@ -1126,6 +1322,38 @@ step_into_function: break; } + /* If we're in the return path from a shared library trampoline, + we want to proceed through the trampoline when stepping. */ + if (IN_SOLIB_RETURN_TRAMPOLINE(stop_pc, stop_func_name)) + { + CORE_ADDR tmp; + + /* Determine where this trampoline returns. */ + tmp = SKIP_TRAMPOLINE_CODE (stop_pc); + + /* Only proceed through if we know where it's going. */ + if (tmp) + { + /* And put the step-breakpoint there and go until there. */ + struct symtab_and_line sr_sal; + + sr_sal.pc = tmp; + sr_sal.symtab = NULL; + sr_sal.line = 0; + /* 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_resume_breakpoint = + set_momentary_breakpoint (sr_sal, NULL, bp_step_resume); + if (breakpoints_inserted) + insert_breakpoints (); + + /* Restart without fiddling with the step ranges or + other state. */ + goto keep_going; + } + } + if (sal.line == 0) { /* We have no line number information. That means to stop @@ -1188,9 +1416,11 @@ step_into_function: sr_sal.pc = prev_pc; sr_sal.symtab = NULL; sr_sal.line = 0; - step_resume_breakpoint = - set_momentary_breakpoint (sr_sal, get_current_frame (), - bp_step_resume); + /* 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 (); @@ -1211,7 +1441,10 @@ step_into_function: been at the start of a function. */ prev_func_name = stop_func_name; - prev_sp = stop_sp; + + if (update_step_sp) + step_sp = read_sp (); + update_step_sp = 0; /* If we did not do break;, it means we should keep running the inferior and not return to debugger. */ @@ -1238,15 +1471,16 @@ step_into_function: 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 && - remove_breakpoints_on_following_step) + if (step_resume_breakpoint == NULL + && through_sigtramp_breakpoint == NULL + && remove_breakpoints_on_following_step) { remove_breakpoints_on_following_step = 0; remove_breakpoints (); breakpoints_inserted = 0; } else if (!breakpoints_inserted && - (step_resume_breakpoint != NULL || !another_trap)) + (through_sigtramp_breakpoint != NULL || !another_trap)) { breakpoints_failed = insert_breakpoints (); if (breakpoints_failed) @@ -1285,7 +1519,6 @@ step_into_function: prev_pc = read_pc (); prev_func_start = stop_func_start; prev_func_name = stop_func_name; - prev_sp = stop_sp; } do_cleanups (old_cleanups); } @@ -1338,7 +1571,7 @@ Further execution is probably impossible.\n"); disable_current_display (); if (step_multi && stop_step) - return; + goto done; target_terminal_ours (); @@ -1351,7 +1584,7 @@ Further execution is probably impossible.\n"); } if (!target_has_stack) - return; + goto done; /* Select innermost stack frame except on return from a stack dummy routine, or if the program has exited. Print it without a level number if @@ -1368,7 +1601,7 @@ Further execution is probably impossible.\n"); source_only = bpstat_print (stop_bpstat); source_only = source_only || ( stop_step - && step_frame_address == stop_frame_address + && step_frame_address == FRAME_FP (get_current_frame ()) && step_start_function == find_pc_function (stop_pc)); print_stack_frame (selected_frame, -1, source_only? -1: 1); @@ -1389,8 +1622,14 @@ Further execution is probably impossible.\n"); POP_FRAME ends with a setting of the current frame, so we can use that next. */ POP_FRAME; + /* Set stop_pc to what it was before we called the function. Can't rely + on restore_inferior_status because that only gets called if we don't + stop in the called function. */ + stop_pc = read_pc(); select_frame (get_current_frame (), 0); } + done: + annotate_stopped (); } static int @@ -1538,10 +1777,11 @@ handle_command (args, from_tty) anyway, and the common ones like SIGHUP, SIGINT, SIGALRM, etc. will work right anyway. */ - sigfirst = siglast = atoi (*argv); + sigfirst = siglast = (int) target_signal_from_command (atoi (*argv)); if ((*argv)[digits] == '-') { - siglast = atoi ((*argv) + digits + 1); + siglast = + (int) target_signal_from_command (atoi ((*argv) + digits + 1)); } if (sigfirst > siglast) { @@ -1550,25 +1790,20 @@ handle_command (args, from_tty) sigfirst = siglast; siglast = signum; } - if (sigfirst < 0 || sigfirst >= nsigs) + } + else + { + oursig = target_signal_from_name (*argv); + if (oursig != TARGET_SIGNAL_UNKNOWN) { - error ("Signal %d not in range 0-%d", sigfirst, nsigs - 1); + sigfirst = siglast = (int)oursig; } - if (siglast < 0 || siglast >= nsigs) + else { - error ("Signal %d not in range 0-%d", siglast, nsigs - 1); + /* Not a number and not a recognized flag word => complain. */ + error ("Unrecognized or ambiguous flag word: \"%s\".", *argv); } } - else if ((oursig = target_signal_from_name (*argv)) - != TARGET_SIGNAL_UNKNOWN) - { - sigfirst = siglast = (int)oursig; - } - else - { - /* Not a number and not a recognized flag word => complain. */ - error ("Unrecognized or ambiguous flag word: \"%s\".", *argv); - } /* If any signal numbers or symbol names were found, set flags for which signals to apply actions to. */ @@ -1595,6 +1830,11 @@ Are you sure you want to change it? ", } } break; + case TARGET_SIGNAL_0: + case TARGET_SIGNAL_DEFAULT: + case TARGET_SIGNAL_UNKNOWN: + /* Make sure that "all" doesn't print these. */ + break; default: sigs[signum] = 1; break; @@ -1641,30 +1881,25 @@ signals_info (signum_exp, from_tty) oursig = target_signal_from_name (signum_exp); if (oursig == TARGET_SIGNAL_UNKNOWN) { - /* Nope, maybe it's an address which evaluates to a signal - number. */ - /* The numeric signal refers to our own internal - signal numbering from target.h, not to host/target signal number. - This is a feature; users really should be using symbolic names - anyway, and the common ones like SIGHUP, SIGINT, SIGALRM, etc. - will work right anyway. */ - int i = parse_and_eval_address (signum_exp); - if (i >= (int)TARGET_SIGNAL_LAST - || i < 0 - || i == TARGET_SIGNAL_UNKNOWN) - error ("Signal number out of bounds."); - oursig = (enum target_signal)i; + /* No, try numeric. */ + oursig = + target_signal_from_command (parse_and_eval_address (signum_exp)); } sig_print_info (oursig); return; } printf_filtered ("\n"); - for (oursig = 0; oursig < TARGET_SIGNAL_LAST; ++oursig) + /* These ugly casts brought to you by the native VAX compiler. */ + for (oursig = TARGET_SIGNAL_FIRST; + (int)oursig < (int)TARGET_SIGNAL_LAST; + oursig = (enum target_signal)((int)oursig + 1)) { QUIT; - if (oursig != TARGET_SIGNAL_UNKNOWN) + if (oursig != TARGET_SIGNAL_UNKNOWN + && oursig != TARGET_SIGNAL_DEFAULT + && oursig != TARGET_SIGNAL_0) sig_print_info (oursig); } @@ -1682,7 +1917,6 @@ save_inferior_status (inf_status, restore_stack_info) { inf_status->stop_signal = stop_signal; inf_status->stop_pc = stop_pc; - inf_status->stop_frame_address = stop_frame_address; inf_status->stop_step = stop_step; inf_status->stop_stack_dummy = stop_stack_dummy; inf_status->stopped_by_random_signal = stopped_by_random_signal; @@ -1712,7 +1946,7 @@ save_inferior_status (inf_status, restore_stack_info) } struct restore_selected_frame_args { - FRAME_ADDR frame_address; + CORE_ADDR frame_address; int level; }; @@ -1722,27 +1956,28 @@ static int restore_selected_frame PARAMS ((char *)); restore_selected_frame_args * (declared as char * for catch_errors) telling us what frame to restore. Returns 1 for success, or 0 for failure. An error message will have been printed on error. */ + static int restore_selected_frame (args) char *args; { struct restore_selected_frame_args *fr = (struct restore_selected_frame_args *) args; - FRAME fid; + struct frame_info *frame; int level = fr->level; - fid = find_relative_frame (get_current_frame (), &level); + frame = find_relative_frame (get_current_frame (), &level); /* If inf_status->selected_frame_address is NULL, there was no previously selected frame. */ - if (fid == 0 || - FRAME_FP (fid) != fr->frame_address || + if (frame == NULL || + FRAME_FP (frame) != fr->frame_address || level != 0) { warning ("Unable to restore previously selected frame.\n"); return 0; } - select_frame (fid, fr->level); + select_frame (frame, fr->level); return(1); } @@ -1752,7 +1987,6 @@ restore_inferior_status (inf_status) { stop_signal = inf_status->stop_signal; stop_pc = inf_status->stop_pc; - stop_frame_address = inf_status->stop_frame_address; stop_step = inf_status->stop_step; stop_stack_dummy = inf_status->stop_stack_dummy; stopped_by_random_signal = inf_status->stopped_by_random_signal; @@ -1811,23 +2045,24 @@ _initialize_infrun () add_info ("signals", signals_info, "What debugger does when program gets various signals.\n\ -Specify a signal number as argument to print info on that signal only."); +Specify a signal as argument to print info on that signal only."); add_info_alias ("handle", "signals", 0); add_com ("handle", class_run, handle_command, - "Specify how to handle a signal.\n\ -Args are signal numbers and actions to apply to those signals.\n\ -Signal numbers may be numeric (ex. 11) or symbolic (ex. SIGSEGV).\n\ -Numeric ranges may be specified with the form LOW-HIGH (ex. 14-21).\n\ + concat ("Specify how to handle a signal.\n\ +Args are signals and actions to apply to those signals.\n\ +Symbolic signals (e.g. SIGSEGV) are recommended but numeric signals\n\ +from 1-15 are allowed for compatibility with old versions of GDB.\n\ +Numeric ranges may be specified with the form LOW-HIGH (e.g. 1-5).\n\ The special arg \"all\" is recognized to mean all signals except those\n\ -used by the debugger, typically SIGTRAP and SIGINT.\n\ -Recognized actions include \"stop\", \"nostop\", \"print\", \"noprint\",\n\ +used by the debugger, typically SIGTRAP and SIGINT.\n", +"Recognized actions include \"stop\", \"nostop\", \"print\", \"noprint\",\n\ \"pass\", \"nopass\", \"ignore\", or \"noignore\".\n\ Stop means reenter debugger if this signal happens (implies print).\n\ Print means print a message if this signal happens.\n\ Pass means let program see this signal; otherwise program doesn't know.\n\ Ignore is a synonym for nopass and noignore is a synonym for pass.\n\ -Pass and Stop may be combined."); +Pass and Stop may be combined.", NULL)); stop_command = add_cmd ("stop", class_obscure, not_just_help_class_command, "There is no `stop' command, but you can set a hook on `stop'.\n\ @@ -1864,6 +2099,8 @@ of the program stops.", &cmdlist); signal_print[TARGET_SIGNAL_CHLD] = 0; signal_stop[TARGET_SIGNAL_IO] = 0; signal_print[TARGET_SIGNAL_IO] = 0; + signal_stop[TARGET_SIGNAL_POLL] = 0; + signal_print[TARGET_SIGNAL_POLL] = 0; signal_stop[TARGET_SIGNAL_URG] = 0; signal_print[TARGET_SIGNAL_URG] = 0; }