X-Git-Url: https://repo.jachan.dev/binutils.git/blobdiff_plain/37c99ddb4ef28794e0f9cc37f02e239a1adaf881..f1619234902c29fefb4badac25714fa9c5f3e606:/gdb/infrun.c diff --git a/gdb/infrun.c b/gdb/infrun.c index 020ef5b47d..f8720c3e14 100644 --- a/gdb/infrun.c +++ b/gdb/infrun.c @@ -18,90 +18,6 @@ You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -/* 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 starts 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. - bug-gdb@prep.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. -*/ - #include "defs.h" #include #include @@ -113,6 +29,7 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include "gdbcore.h" #include "gdbcmd.h" #include "target.h" +#include "thread.h" #include @@ -158,6 +75,13 @@ hook_stop_stub PARAMS ((char *)); #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 to nonzero if we are current stopped in one of these. */ @@ -283,6 +207,14 @@ resume (step, sig) struct cleanup *old_cleanups = make_cleanup (resume_cleanups, 0); QUIT; +#ifdef CANNOT_STEP_BREAKPOINT + /* Most targets can step a breakpoint instruction, thus executing it + normally. But if this one cannot, just continue and we will hit + it anyway. */ + if (step && breakpoints_inserted && breakpoint_here_p (read_pc ())) + step = 0; +#endif + #ifdef NO_SINGLE_STEP if (step) { single_step(sig); /* Do it the hard way, w/temp breakpoints */ @@ -295,7 +227,10 @@ resume (step, sig) DO_DEFERRED_STORES; #endif - target_resume (inferior_pid, step, sig); + /* Install inferior's terminal modes. */ + target_terminal_inferior (); + + target_resume (-1, step, sig); discard_cleanups (old_cleanups); } @@ -383,9 +318,6 @@ The same program may be running in another process."); breakpoints_inserted = 1; } - /* Install inferior's terminal modes. */ - target_terminal_inferior (); - if (siggnal >= 0) stop_signal = siggnal; /* If this signal should not be seen by program, @@ -439,7 +371,7 @@ init_wait_for_inferior () trap_expected_after_continue = 0; breakpoints_inserted = 0; - mark_breakpoints_out (); + breakpoint_init_inferior (); stop_signal = 0; /* Don't confuse first call to proceed(). */ } @@ -472,6 +404,7 @@ wait_for_inferior () struct symtab_and_line sal; int remove_breakpoints_on_following_step = 0; int current_line; + struct symtab *current_symtab; int handling_longjmp = 0; /* FIXME */ struct breakpoint *step_resume_breakpoint = NULL; int pid; @@ -480,6 +413,14 @@ wait_for_inferior () &step_resume_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 ()) while (1) { @@ -487,7 +428,7 @@ wait_for_inferior () flush_cached_frames (); registers_changed (); - pid = target_wait (&w); + pid = target_wait (-1, &w); #ifdef SIGTRAP_STOP_AFTER_LOAD @@ -507,7 +448,7 @@ wait_for_inferior () else if (!batch_mode()) printf_filtered ("\nProgram exited normally.\n"); - fflush (stdout); + gdb_flush (gdb_stdout); target_mourn_inferior (); #ifdef NO_SINGLE_STEP one_stepped = 0; @@ -537,29 +478,78 @@ wait_for_inferior () printf_filtered (", %s\n", safe_strsignal (stop_signal)); #endif printf_filtered ("The program no longer exists.\n"); - fflush (stdout); + gdb_flush (gdb_stdout); #ifdef NO_SINGLE_STEP one_stepped = 0; #endif break; } - + + stop_signal = WSTOPSIG (w); + + if (pid != inferior_pid) + { + int save_pid = inferior_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 (); + + if (stop_signal == SIGTRAP + && breakpoint_here_p (stop_pc - DECR_PC_AFTER_BREAK)) + { + 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, 0); /* Single step */ + /* FIXME: What if a signal arrives instead of the single-step + happening? */ + target_wait (pid, &w); + insert_breakpoints (); + } + target_resume (-1, 0, 0); + continue; + } + else + if (pid != inferior_pid) + goto switch_thread; + } + if (pid != inferior_pid) { int printed = 0; if (!in_thread_list (pid)) { - fprintf (stderr, "[New %s]\n", target_pid_to_str (pid)); + fprintf_unfiltered (gdb_stderr, "[New %s]\n", target_pid_to_str (pid)); add_thread (pid); - target_resume (pid, 0, 0); + target_resume (-1, 0, 0); continue; } else { - stop_signal = WSTOPSIG (w); - if (stop_signal >= NSIG || signal_print[stop_signal]) { char *signame; @@ -574,11 +564,14 @@ wait_for_inferior () printf_filtered ("%s (%d)", signame, stop_signal); printf_filtered (", %s\n", safe_strsignal (stop_signal)); - fflush (stdout); + gdb_flush (gdb_stdout); } - if (stop_signal >= NSIG || signal_stop[stop_signal]) + if (stop_signal == SIGTRAP + || stop_signal >= NSIG + || signal_stop[stop_signal]) { +switch_thread: inferior_pid = pid; printf_filtered ("[Switching to %s]\n", target_pid_to_str (pid)); @@ -628,7 +621,6 @@ wait_for_inferior () continue; } - stop_pc = read_pc (); set_current_frame ( create_new_frame (read_fp (), stop_pc)); stop_frame_address = FRAME_FP (get_current_frame ()); @@ -638,7 +630,7 @@ wait_for_inferior () /* Don't care about return value; stop_func_start and stop_func_name will both be 0 if it doesn't work. */ find_pc_partial_function (stop_pc, &stop_func_name, &stop_func_start, - (CORE_ADDR *)NULL); + NULL); stop_func_start += FUNCTION_START_OFFSET; another_trap = 0; bpstat_clear (&stop_bpstat); @@ -657,8 +649,6 @@ wait_for_inferior () 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 @@ -696,32 +686,33 @@ wait_for_inferior () else { /* See if there is a breakpoint at the current PC. */ + stop_bpstat = bpstat_stop_status + (&stop_pc, stop_frame_address, #if DECR_PC_AFTER_BREAK - /* Notice the case of stepping through a jump - that lands just after a breakpoint. - Don't confuse that with hitting the breakpoint. - What we check for is that 1) stepping is going on - and 2) the pc before the last insn does not match - the address of the breakpoint before the current pc. */ - if (prev_pc == stop_pc - DECR_PC_AFTER_BREAK - || !step_range_end - || step_resume_breakpoint != NULL - || handling_longjmp /* FIXME */) -#endif /* DECR_PC_AFTER_BREAK not zero */ - { - stop_bpstat = - bpstat_stop_status (&stop_pc, stop_frame_address); - /* Following in case break condition called a - function. */ - stop_print_frame = 1; - } + /* Notice the case of stepping through a jump + that lands just after a breakpoint. + Don't confuse that with hitting the breakpoint. + What we check for is that 1) stepping is going on + and 2) the pc before the last insn does not match + the address of the breakpoint before the current pc. */ + (prev_pc != stop_pc - DECR_PC_AFTER_BREAK + && CURRENTLY_STEPPING ()) +#else /* DECR_PC_AFTER_BREAK zero */ + 0 +#endif /* DECR_PC_AFTER_BREAK zero */ + ); + /* Following in case break condition called a + function. */ + stop_print_frame = 1; } if (stop_signal == SIGTRAP) random_signal = !(bpstat_explains_signal (stop_bpstat) || trap_expected +#ifndef CALL_DUMMY_BREAKPOINT_OFFSET || PC_IN_CALL_DUMMY (stop_pc, stop_sp, stop_frame_address) +#endif /* No CALL_DUMMY_BREAKPOINT_OFFSET. */ || (step_range_end && step_resume_breakpoint == NULL)); else { @@ -730,7 +721,9 @@ wait_for_inferior () /* End of a stack dummy. Some systems (e.g. Sony 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) +#endif /* No CALL_DUMMY_BREAKPOINT_OFFSET. */ ); if (!random_signal) stop_signal = SIGTRAP; @@ -767,7 +760,7 @@ wait_for_inferior () printf_filtered ("%s (%d)", signame, stop_signal); printf_filtered (", %s\n", safe_strsignal (stop_signal)); #endif /* PRINT_RANDOM_SIGNAL */ - fflush (stdout); + gdb_flush (gdb_stdout); } if (stop_signal >= NSIG || signal_stop[stop_signal]) @@ -793,6 +786,14 @@ wait_for_inferior () what = bpstat_what (stop_bpstat); + if (what.call_dummy) + { + stop_stack_dummy = 1; +#ifdef HP_OS_BUG + trap_expected_after_continue = 1; +#endif + } + switch (what.main_action) { case BPSTAT_WHAT_SET_LONGJMP_RESUME: @@ -865,6 +866,9 @@ wait_for_inferior () 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. */ + case BPSTAT_WHAT_KEEP_CHECKING: break; } @@ -887,18 +891,28 @@ wait_for_inferior () test for stepping. But, if not stepping, do not stop. */ +#ifndef CALL_DUMMY_BREAKPOINT_OFFSET + /* This is the old way of detecting the end of the stack dummy. + An architecture which defines CALL_DUMMY_BREAKPOINT_OFFSET gets + handled above. As soon as we can test it on all of them, all + architectures should define it. */ + /* If this is the breakpoint at the end of a stack dummy, - just stop silently. */ - if (PC_IN_CALL_DUMMY (stop_pc, stop_sp, stop_frame_address)) - { - stop_print_frame = 0; - stop_stack_dummy = 1; + 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) + && !step_range_end) + { + stop_print_frame = 0; + stop_stack_dummy = 1; #ifdef HP_OS_BUG - trap_expected_after_continue = 1; + trap_expected_after_continue = 1; #endif - break; - } - + break; + } +#endif /* No CALL_DUMMY_BREAKPOINT_OFFSET. */ + if (step_resume_breakpoint) /* Having a step-resume breakpoint overrides anything else having to do with stepping commands until @@ -977,13 +991,51 @@ wait_for_inferior () SKIP_PROLOGUE (prologue_pc); } - /* ==> See comments at top of file on this algorithm. <==*/ + if ((/* Might be a non-recursive call. If the symbols are missing + enough that stop_func_start == prev_func_start even though + they are really two functions, we will treat some calls as + jumps. */ + stop_func_start != prev_func_start + + /* 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) + && (/* 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 - if ((stop_pc == stop_func_start - || IN_SOLIB_TRAMPOLINE (stop_pc, stop_func_name)) - && (stop_func_start != prev_func_start - || prologue_pc != stop_func_start - || stop_sp != prev_sp)) + /* ...except on the Alpha with -O (and also Irix 5 and + perhaps others), in which we might call the address + after the load of gp. Since prologues don't contain + calls, we can't return to within one, and we don't + jump back into them, so this check is OK. */ + + || stop_pc < prologue_pc + + /* 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) + + /* 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. */ + )) { /* It's a subroutine call. */ @@ -1078,8 +1130,7 @@ step_into_function: since on some machines the prologue is where the new fp value is established. */ step_resume_breakpoint = - set_momentary_breakpoint (sr_sal, (CORE_ADDR)0, - bp_step_resume); + set_momentary_breakpoint (sr_sal, NULL, bp_step_resume); if (breakpoints_inserted) insert_breakpoints (); @@ -1089,9 +1140,7 @@ step_into_function: goto keep_going; } - /* We've wandered out of the step range (but haven't done a - subroutine call or return). (Is that true? I think we get - here if we did a return and maybe a longjmp). */ + /* We've wandered out of the step range. */ sal = find_pc_line(stop_pc, 0); @@ -1113,7 +1162,8 @@ step_into_function: break; } - if (stop_pc == sal.pc && current_line != sal.line) + if (stop_pc == sal.pc + && (current_line != sal.line || current_symtab != sal.symtab)) { /* We are at the start of a different line. So stop. Note that we don't stop if we step into the middle of a different line. @@ -1186,10 +1236,7 @@ step_into_function: /* We took a signal (which we are supposed to pass through to the inferior, else we'd have done a break above) and we haven't yet gotten our trap. Simply continue. */ - resume ((step_range_end && step_resume_breakpoint == NULL) - || (trap_expected && step_resume_breakpoint == NULL) - || bpstat_should_step (), - stop_signal); + resume (CURRENTLY_STEPPING (), stop_signal); } else { @@ -1231,27 +1278,16 @@ step_into_function: /* I'm not sure when this following segment applies. I do know, now, that we shouldn't rewrite the regs when we were stopped by a random signal from the inferior process. */ + /* FIXME: Shouldn't this be based on the valid bit of the SXIP? + (this is only used on the 88k). */ if (!bpstat_explains_signal (stop_bpstat) && (stop_signal != SIGCLD) && !stopped_by_random_signal) - { - CORE_ADDR pc_contents = read_register (PC_REGNUM); - CORE_ADDR npc_contents = read_register (NPC_REGNUM); - if (pc_contents != npc_contents) - { - write_register (NNPC_REGNUM, npc_contents); - write_register (NPC_REGNUM, pc_contents); - } - } + SHIFT_INST_REGS(); #endif /* SHIFT_INST_REGS */ - resume ((step_resume_breakpoint == NULL - && !handling_longjmp - && (step_range_end - || trap_expected)) - || bpstat_should_step (), - stop_signal); + resume (CURRENTLY_STEPPING (), stop_signal); } } @@ -1283,7 +1319,7 @@ 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 (target_has_execution) + if (target_has_execution && get_current_frame()) (get_current_frame ())->pc = read_pc (); if (breakpoints_failed) @@ -1559,8 +1595,8 @@ handle_command (args, from_tty) } else { - printf ("Not confirmed, unchanged.\n"); - fflush (stdout); + printf_unfiltered ("Not confirmed, unchanged.\n"); + gdb_flush (gdb_stdout); } } break; @@ -1573,7 +1609,7 @@ handle_command (args, from_tty) argv++; } - target_notice_signals(); + target_notice_signals(inferior_pid); if (from_tty) {