From 5227d625257f3ae52d45d87f2e16954fb5af9349 Mon Sep 17 00:00:00 2001 From: Joel Brobecker Date: Tue, 25 Nov 2014 11:12:10 -0500 Subject: Use PTRACE_SINGLESTEP_ONE when single-stepping one thread. Currently, when we receive a request to single-step one single thread (Eg, when single-stepping out of a breakpoint), we use the PTRACE_SINGLESTEP pthread request, which does single-step the corresponding thread, but also resumes execution of all other threads in the inferior. This causes problems when debugging programs where another thread receives multiple debug events while trying to single-step a specific thread out of a breakpoint (with infrun traces turned on): (gdb) continue Continuing. infrun: clear_proceed_status_thread (Thread 126) [...] infrun: clear_proceed_status_thread (Thread 142) [...] infrun: clear_proceed_status_thread (Thread 146) infrun: clear_proceed_status_thread (Thread 125) infrun: proceed (addr=0xffffffff, signal=GDB_SIGNAL_DEFAULT, step=0) infrun: resume (step=1, signal=GDB_SIGNAL_0), trap_expected=1, current thread [Thread 142] at 0x10684838 infrun: wait_for_inferior () infrun: target_wait (-1, status) = infrun: 42000 [Thread 146], infrun: status->kind = stopped, signal = GDB_SIGNAL_REALTIME_34 infrun: infwait_normal_state infrun: TARGET_WAITKIND_STOPPED infrun: stop_pc = 0x10a187f4 infrun: context switch infrun: Switching context from Thread 142 to Thread 146 infrun: random signal (GDB_SIGNAL_REALTIME_34) infrun: switching back to stepped thread infrun: Switching context from Thread 146 to Thread 142 infrun: resume (step=1, signal=GDB_SIGNAL_0), trap_expected=1, current thread [Thread 142] at 0x10684838 infrun: prepare_to_wait [...handling of similar events for threads 145, 144 and 143 snipped...] infrun: prepare_to_wait infrun: target_wait (-1, status) = infrun: 42000 [Thread 146], infrun: status->kind = stopped, signal = GDB_SIGNAL_REALTIME_34 infrun: infwait_normal_state infrun: TARGET_WAITKIND_STOPPED infrun: stop_pc = 0x10a187f4 infrun: context switch infrun: Switching context from Thread 142 to Thread 146 ../../src/gdb/inline-frame.c:339: internal-error: skip_inline_frames: Assertion `find_inline_frame_state (ptid) == NULL' failed. What happens is that GDB keeps sending requests to resume one specific thread, and keeps receiving debugging events for other threads. Things break down when the one of the other threads receives a debug event for the second time (thread 146 in the example above). This patch fixes the problem by making sure that only one thread gets resumed, thus preventing the other threads from generating an unexpected event. gdb/gdbserver/ChangeLog: * lynx-low.c (lynx_resume): Use PTRACE_SINGLESTEP_ONE if N == 1. Remove FIXME comment about assumption about N. --- gdb/gdbserver/ChangeLog | 5 +++++ gdb/gdbserver/lynx-low.c | 7 ++++--- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/gdb/gdbserver/ChangeLog b/gdb/gdbserver/ChangeLog index 6a5005e..92b213a 100644 --- a/gdb/gdbserver/ChangeLog +++ b/gdb/gdbserver/ChangeLog @@ -1,3 +1,8 @@ +2014-12-15 Joel Brobecker + + * lynx-low.c (lynx_resume): Use PTRACE_SINGLESTEP_ONE if N == 1. + Remove FIXME comment about assumption about N. + 2014-12-13 Joel Brobecker * configure.ac: If large-file support is disabled in GDBserver, diff --git a/gdb/gdbserver/lynx-low.c b/gdb/gdbserver/lynx-low.c index 6178e03..3b83669 100644 --- a/gdb/gdbserver/lynx-low.c +++ b/gdb/gdbserver/lynx-low.c @@ -320,10 +320,11 @@ lynx_attach (unsigned long pid) static void lynx_resume (struct thread_resume *resume_info, size_t n) { - /* FIXME: Assume for now that n == 1. */ ptid_t ptid = resume_info[0].thread; - const int request = (resume_info[0].kind == resume_step - ? PTRACE_SINGLESTEP : PTRACE_CONT); + const int request + = (resume_info[0].kind == resume_step + ? (n == 1 ? PTRACE_SINGLESTEP_ONE : PTRACE_SINGLESTEP) + : PTRACE_CONT); const int signal = resume_info[0].sig; /* If given a minus_one_ptid, then try using the current_process' -- cgit v1.1