From 48f4903f369709dde852872db542afbb536acd54 Mon Sep 17 00:00:00 2001 From: Jeff Law Date: Tue, 4 Jul 1995 17:40:41 +0000 Subject: [PATCH] * infrun.c (wait_for_inferior): When we hit a breakpoint for the wrong thread, make sure to write the fixed PC value into the thread that stopped. Restart all threads after single stepping over a breakpoint for a different thread. * breakpoint.c (set_momentary_breakpoint): Make momentary breakpoints thread specific in a multi-threaded program. * lynx-nat.c (child_resume): Add some comments. Correctly choose between the single and multi-threaded step and continue ptrace calls. Some of the lynx-6100 single stepping fixes. --- gdb/ChangeLog | 12 ++++++++ gdb/infrun.c | 84 ++++++++++++++++++++++++++++++++++++++------------ gdb/lynx-nat.c | 8 +++-- 3 files changed, 81 insertions(+), 23 deletions(-) diff --git a/gdb/ChangeLog b/gdb/ChangeLog index 1e096fbb6e0..2ff3c3f8aa5 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,15 @@ +Tue Jul 4 10:30:22 1995 Jeffrey A. Law + + * infrun.c (wait_for_inferior): When we hit a breakpoint for the + wrong thread, make sure to write the fixed PC value into the thread + that stopped. Restart all threads after single stepping over a + breakpoint for a different thread. + * breakpoint.c (set_momentary_breakpoint): Make momentary + breakpoints thread specific in a multi-threaded program. + * lynx-nat.c (child_resume): Add some comments. Correctly + choose between the single and multi-threaded step and continue + ptrace calls. + Fri Jun 30 16:15:36 1995 Stan Shebs * config/h8300/h8300.mt: Renamed from h8300hms.mt. diff --git a/gdb/infrun.c b/gdb/infrun.c index cd6962984e0..5ad2bfc45db 100644 --- a/gdb/infrun.c +++ b/gdb/infrun.c @@ -479,6 +479,8 @@ wait_for_inferior () else pid = target_wait (-1, &w); + have_waited: + flush_cached_frames (); /* If it's a new process, add it to the thread database */ @@ -501,24 +503,6 @@ wait_for_inferior () continue; } - stop_signal = w.value.sig; - - stop_pc = read_pc_pid (pid); - - if (STOPPED_BY_WATCHPOINT (w)) - { - 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 (); - } - switch (w.kind) { case TARGET_WAITKIND_LOADED: @@ -587,6 +571,10 @@ wait_for_inferior () break; } + stop_signal = w.value.sig; + + stop_pc = read_pc_pid (pid); + /* 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. */ @@ -599,7 +587,7 @@ wait_for_inferior () if (!breakpoint_thread_match (stop_pc - DECR_PC_AFTER_BREAK, pid)) { /* Saw a breakpoint, but it was hit by the wrong thread. Just continue. */ - write_pc (stop_pc - DECR_PC_AFTER_BREAK); + write_pc_pid (stop_pc - DECR_PC_AFTER_BREAK, pid); remove_breakpoints (); target_resume (pid, 1, TARGET_SIGNAL_0); /* Single step */ @@ -611,7 +599,9 @@ wait_for_inferior () else target_wait (pid, &w); insert_breakpoints (); - target_resume (pid, 0, TARGET_SIGNAL_0); + + /* We need to restart all the threads now. */ + target_resume (-1, 0, TARGET_SIGNAL_0); continue; } } @@ -703,6 +693,60 @@ wait_for_inferior () continue; } +#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_func_start = 0; stop_func_name = 0; /* Don't care about return value; stop_func_start and stop_func_name diff --git a/gdb/lynx-nat.c b/gdb/lynx-nat.c index f0e817e5653..1ab9cc7cc67 100644 --- a/gdb/lynx-nat.c +++ b/gdb/lynx-nat.c @@ -705,14 +705,16 @@ child_resume (pid, step, signal) errno = 0; + /* If pid == -1, then we want to step/continue all threads, else + we only want to step/continue a single thread. */ if (pid == -1) { - /* Resume all threads. */ - pid = inferior_pid; + func = step ? PTRACE_SINGLESTEP : PTRACE_CONT; } + else + func = step ? PTRACE_SINGLESTEP_ONE : PTRACE_CONT_ONE; - func = step ? PTRACE_SINGLESTEP_ONE : PTRACE_CONT; /* An address of (PTRACE_ARG3_TYPE)1 tells ptrace to continue from where it was. (If GDB wanted it to start some other way, we have already