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 <string.h>
#include <ctype.h>
#include "gdbcore.h"
#include "gdbcmd.h"
#include "target.h"
+#include "thread.h"
#include <signal.h>
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 */
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);
}
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,
trap_expected_after_continue = 0;
breakpoints_inserted = 0;
- mark_breakpoints_out ();
+ breakpoint_init_inferior ();
stop_signal = 0; /* Don't confuse first call to proceed(). */
}
int random_signal;
CORE_ADDR stop_sp = 0;
CORE_ADDR stop_func_start;
+ CORE_ADDR stop_func_end;
char *stop_func_name;
CORE_ADDR prologue_pc = 0, tmp;
struct symtab_and_line sal;
flush_cached_frames ();
registers_changed ();
- pid = target_wait (&w);
+ pid = target_wait (-1, &w);
#ifdef SIGTRAP_STOP_AFTER_LOAD
#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)
+ {
+ remove_breakpoints ();
+ target_resume (pid, 1, 0); /* Single step */
+ /* FIXME: What if a signal arrives instead of the single-step
+ happening? */
+ target_wait (pid, NULL);
+ insert_breakpoints ();
+ }
+ target_resume (-1, 0, 0);
+ continue;
+ }
+ else
+ if (pid != inferior_pid)
+ goto switch_thread;
+
if (pid != inferior_pid)
{
int printed = 0;
fprintf (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;
fflush (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));
if (signal_program[stop_signal] == 0)
stop_signal = 0;
- target_resume (pid, 0, stop_signal);
+ target_resume (-1, 0, stop_signal);
continue;
}
}
continue;
}
- stop_pc = read_pc ();
set_current_frame ( create_new_frame (read_fp (), stop_pc));
stop_frame_address = FRAME_FP (get_current_frame ());
stop_sp = read_sp ();
stop_func_start = 0;
+ stop_func_end = 0;
stop_func_name = 0;
/* 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);
+ &stop_func_end);
stop_func_start += FUNCTION_START_OFFSET;
another_trap = 0;
bpstat_clear (&stop_bpstat);
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
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;
}
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)
+ && (/* I think this can only happen if stop_func_start is zero
+ (e.g. stop_pc is in some objfile we don't know about).
+ If the stop_pc does that (ends up someplace unknown), it
+ must be some sort of subroutine call. */
+ stop_pc < stop_func_start
+ || stop_pc >= stop_func_end
+
+ /* If we do a call, we will be at the start of a function. */
+ || stop_pc == stop_func_start
- 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))
+#if 0
+ /* Not conservative enough for 4.11. FIXME: enable this
+ after 4.11. */
+ /* Except on the Alpha with -O (and perhaps other machines
+ with similar calling conventions), 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
+#endif
+
+ /* 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. */
/* 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 (CURRENTLY_STEPPING (), stop_signal);
/* 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)
argv++;
}
- target_notice_signals();
+ target_notice_signals(inferior_pid);
if (from_tty)
{