Ref: https://sourceware.org/ml/gdb-patches/2015-07/msg00868.html
This adds a test that has a multithreaded program have several threads
continuously fork, while another thread continuously steps over a
breakpoint.
This exposes several intertwined issues, which this patch addresses:
- When we're stopping and suspending threads, some thread may fork,
and we missed setting its suspend count to 1, like we do when a new
clone/thread is detected. When we next unsuspend threads, the fork
child's suspend count goes below 0, which is bogus and fails an
assertion.
- If a step-over is cancelled because a signal arrives, but then gdb
is not interested in the signal, we pass the signal straight back
to the inferior. However, we miss that we need to re-increment the
suspend counts of all other threads that had been paused for the
step-over. As a result, other threads indefinitely end up stuck
stopped.
- If a detach request comes in just while gdbserver is handling a
step-over (in the test at hand, this is GDB detaching the fork
child), gdbserver internal errors in stabilize_thread's helpers,
which assert that all thread's suspend counts are 0 (otherwise we
wouldn't be able to move threads out of the jump pads). The
suspend counts aren't 0 while a step-over is in progress, because
all threads but the one stepping past the breakpoint must remain
paused until the step-over finishes and the breakpoint can be
reinserted.
- Occasionally, we see "BAD - reinserting but not stepping." being
output (from within linux_resume_one_lwp_throw). That was because
GDB pokes memory while gdbserver is busy with a step-over, and that
suspends threads, and then re-resumes them with proceed_one_lwp,
which missed another reason to tell linux_resume_one_lwp that the
thread should be set back to stepping.
- In a couple places, we were resuming threads that are meant to be
suspended. E.g., when a vCont;c/s request for thread B comes in
just while gdbserver is stepping thread A past a breakpoint. The
resume for thread B must be deferred until the step-over finishes.
- The test runs with both "set detach-on-fork" on and off. When off,
it exercises the case of GDB detaching the fork child explicitly.
When on, it exercises the case of gdb resuming the child
explicitly. In the "off" case, gdb seems to exponentially become
slower as new inferiors are created. This is _very_ noticeable as
with only 100 inferiors gdb is crawling already, which makes the
test take quite a bit to run. For that reason, I've disabled the
"off" variant for now.
gdb/ChangeLog:
2015-08-06 Pedro Alves <palves@redhat.com>
* target/waitstatus.h (enum target_stop_reason)
<TARGET_STOPPED_BY_SINGLE_STEP>: New value.
gdb/gdbserver/ChangeLog:
2015-08-06 Pedro Alves <palves@redhat.com>
* linux-low.c (handle_extended_wait): Set the fork child's suspend
count if stopping and suspending threads.
(check_stopped_by_breakpoint): If stopped by trace, set the LWP's
stop reason to TARGET_STOPPED_BY_SINGLE_STEP.
(linux_detach): Complete an ongoing step-over.
(lwp_suspended_inc, lwp_suspended_decr): New functions. Use
throughout.
(resume_stopped_resumed_lwps): Don't resume a suspended thread.
(linux_wait_1): If passing a signal to the inferior after
finishing a step-over, unsuspend and re-resume all lwps. If we
see a single-step event but the thread should be continuing, don't
pass the trap to gdb.
(stuck_in_jump_pad_callback, move_out_of_jump_pad_callback): Use
internal_error instead of gdb_assert.
(enqueue_pending_signal): New function.
(check_ptrace_stopped_lwp_gone): Add debug output.
(start_step_over): Use internal_error instead of gdb_assert.
(complete_ongoing_step_over): New function.
(linux_resume_one_thread): Don't resume a suspended thread.
(proceed_one_lwp): If the LWP is stepping over a breakpoint, reset
it stepping.
gdb/testsuite/ChangeLog:
2015-08-06 Pedro Alves <palves@redhat.com>
* gdb.threads/forking-threads-plus-breakpoint.exp: New file.
* gdb.threads/forking-threads-plus-breakpoint.c: New file.
This should be just a move with no changes.
gdb/ChangeLog
2015-07-15 Aleksandar Ristovski <aristovski@qnx.com
Jan Kratochvil <jan.kratochvil@redhat.com>
Move linux_find_memory_regions_full & co.
* linux-tdep.c (nat/linux-maps.h): Include.
(gdb_regex.h): Remove the include.
(enum filterflags, struct smaps_vmflags, read_mapping, decode_vmflags)
(mapping_is_anonymous_p, dump_mapping_p): Moved to nat/linux-maps.c.
(linux_find_memory_region_ftype): Moved typedef to nat/linux-maps.h.
(linux_find_memory_regions_full): Moved definition to nat/linux-maps.c.
* nat/linux-maps.c: Include ctype.h, target/target-utils.h, gdb_regex.h
and target/target.h.
(struct smaps_vmflags, read_mapping, decode_vmflags)
(mapping_is_anonymous_p, dump_mapping_p): Move from linux-tdep.c.
(linux_find_memory_regions_full): Move from linux-tdep.c.
* nat/linux-maps.h (read_mapping): New declaration.
(linux_find_memory_region_ftype, enum filterflags): Moved from
linux-tdep.c.
(linux_find_memory_regions_full): New declaration.
* target.c (target/target-utils.h): Include.
(read_alloc_pread_ftype): Moved typedef to target/target-utils.h.
(read_alloc, read_stralloc_func_ftype, read_stralloc): Moved
definitions to target/target-utils.c.
* target.h (target_fileio_read_stralloc): Move it to target/target.h.
* target/target-utils.c (read_alloc, read_stralloc): Move definitions
from target.c.
* target/target-utils.h (read_alloc_pread_ftype): New typedef.
(read_alloc): New declaration.
(read_stralloc_func_ftype): New typedef.
(read_stralloc): New declaration.
* target/target.h (target_fileio_read_stralloc): Move it from target.h.
gdb/gdbserver/ChangeLog
2015-07-15 Aleksandar Ristovski <aristovski@qnx.com
Jan Kratochvil <jan.kratochvil@redhat.com>
* target.c: Include target/target-utils.h and fcntl.h.
(target_fileio_read_stralloc_1_pread, target_fileio_read_stralloc_1)
(target_fileio_read_stralloc): New functions.
stdint.h was added to common-defs.h some months ago and should
no longer be included directly by any file.
gdb_assert.h was added to common-defs.h nearly a year ago, but
three includes have crept in since then.
This commit removes all such redundant include directives.
gdb/ChangeLog:
* common/buffer.c (stdint.h): Do not include.
* common/print-utils.c (stdint.h): Likewise.
* compile/compile-c-symbols.c (gdb_assert.h): Likewise.
* compile/compile-c-types.c (gdb_assert.h): Likewise.
* ft32-tdep.c (gdb_assert.h): Likewise.
* guile/scm-utils.c (stdint.h): Likewise.
* i386-linux-tdep.c (stdint.h): Likewise.
* i386-tdep.c (stdint.h): Likewise.
* nat/linux-btrace.c (stdint.h): Likewise.
* nat/linux-btrace.h (stdint.h): Likewise.
* nat/linux-ptrace.c (stdint.h): Likewise.
* nat/mips-linux-watch.h (stdint.h): Likewise.
* ppc-linux-nat.c (stdint.h): Likewise.
* python/python-internal.h (stdint.h): Likewise.
* stub-termcap.c (stdlib.h): Likewise.
* target/target.h (stdint.h): Likewise.
* xtensa-linux-nat.c (stdint.h): Likewise.
gdb/gdbserver/ChangeLog:
* linux-i386-ipa.c (stdint.h): Do not include.
* lynx-i386-low.c (stdint.h): Likewise.
* lynx-ppc-low.c (stdint.h): Likewise.
* mem-break.c (stdint.h): Likewise.
* thread-db.c (stdint.h): Likewise.
* tracepoint.c (stdint.h): Likewise.
* win32-low.c (stdint.h): Likewise.
This commit renames target_stop_ptid as target_stop_and_wait and
target_continue_ptid as target_continue_no_signal. Comments are
updated to more fully describe the functions' behaviour.
gdb/ChangeLog:
* target/target.h (target_stop_ptid): Renamed as...
(target_stop_and_wait): New function. Updated comment.
All uses updated.
(target_continue_ptid): Renamed as...
(target_continue_no_signal): New function. Updated comment.
All uses updated.
This commit makes 19 of the 22 shared .c files in common, nat and
target include common-defs.h instead of defs.h/server.h. The
remaining three files need slight extra work and are dealt with
in separate commits.
gdb/ChangeLog:
* common/agent.c: Include common-defs.h.
Don't include defs.h or server.h.
* common/buffer.c: Likewise.
* common/common-debug.c: Likewise.
* common/common-utils.c: Likewise.
* common/errors.c: Likewise.
* common/filestuff.c: Likewise.
* common/format.c: Likewise.
* common/gdb_vecs.c: Likewise.
* common/print-utils.c: Likewise.
* common/ptid.c: Likewise.
* common/rsp-low.c: Likewise.
* common/signals.c: Likewise.
* common/vec.c: Likewise.
* common/xml-utils.c: Likewise.
* nat/linux-osdata.c: Likewise.
* nat/linux-procfs.c: Likewise.
* nat/linux-ptrace.c: Likewise.
* nat/mips-linux-watch.c: Likewise.
* target/waitstatus.c: Likewise.
This commit introduces two new functions to stop and restart target
processes that shared code can use and that clients must implement.
It also changes some shared code to use these functions.
gdb/ChangeLog:
* target/target.h (target_stop_ptid, target_continue_ptid):
Declare.
* target.c (target_stop_ptid, target_continue_ptid): New
functions.
* common/agent.c [!GDBSERVER]: Don't include infrun.h.
(agent_run_command): Always use target_stop_ptid and
target_continue_ptid.
gdb/gdbserver/ChangeLog:
* target.c (target_stop_ptid, target_continue_ptid): New
functions.
This introduces target/target.h. This file declares some functions
that the shared code can use and that clients must implement. It also
changes some shared code to use these functions.
gdb/ChangeLog:
* target/target.h: New file.
* Makefile.in (HFILES_NO_SRCDIR): Add target/target.h.
* target.h: Include target/target.h.
(target_read_memory, target_write_memory): Don't declare.
* target.c (target_read_uint32): New function.
* common/agent.c: Include target/target.h.
[!GDBSERVER]: Don't include target.h.
(helper_thread_id): Type changed to uint32_t.
(agent_get_helper_thread_id): Use target_read_uint32.
(agent_run_command): Always use target_read_memory and
target_write_memory.
(agent_capability): Type changed to uint32_t.
(agent_capability_check): Use target_read_uint32.
gdb/gdbserver/ChangeLog:
* target.h: Include target/target.h.
* target.c (target_read_memory, target_read_uint32)
(target_write_memory): New functions.
This commit moves the inclusion of common-utils.h to common-defs.h and
removes all other inclusions.
gdb/
2014-08-07 Gary Benson <gbenson@redhat.com>
* common/common-defs.h: Include common-utils.h.
* defs.h: Do not include common-utils.h.
* common/gdb_assert.h: Likewise.
* darwin-nat.h: Likewise.
* nat/linux-btrace.c: Likewise.
* target/waitstatus.h: Likewise.
gdb/gdbserver/
2014-08-07 Gary Benson <gbenson@redhat.com>
* server.h: Do not include common-utils.h.
This commit moves the inclusion of ptid.h to common-defs.h and removes
all other inclusions.
gdb/
2014-08-07 Gary Benson <gbenson@redhat.com>
* common/common-defs.h: Include ptid.h.
* defs.h: Do not include ptid.h.
* inferior.h: Likewise.
* infrun.h: Likewise.
* nat/linux-btrace.h: Likewise.
* nat/linux-osdata.h: Likewise.
* target/waitstatus.h: Likewise.
gdb/gdbserver/
2014-08-07 Gary Benson <gbenson@redhat.com>
* server.h: Do not include ptid.h.
* notif.h: Likewise.
The other day while debugging something related to random signals, I
got confused with "set debug infrun 1" output, for it said:
infrun: TARGET_WAITKIND_STOPPED
infrun: stop_pc = 0x323d4e8b94
infrun: random signal 20
On GNU/Linux, 20 is SIGTSTP. For some reason, it took me a few
minutes to realize that 20 is actually a GDB signal number, not a
target signal number (duh!). In any case, I propose making GDB's
output clearer here:
One way would be to use gdb_signal_to_name, like already used
elsewhere:
infrun: TARGET_WAITKIND_STOPPED
infrun: stop_pc = 0x323d4e8b94
infrun: random signal SIGCHLD (20)
but I think that might confuse someone too ("20? Why does GDB believe
SIGCHLD is 20?"). So I thought of printing the enum string instead:
infrun: TARGET_WAITKIND_STOPPED
infrun: stop_pc = 0x323d4e8b94
infrun: random signal GDB_SIGNAL_CHLD (20)
Looking at a more complete infrun debug log, we had actually printed
the (POSIX) signal name name a bit before:
infrun: target_wait (-1, status) =
infrun: 9300 [Thread 0x7ffff7fcb740 (LWP 9300)],
infrun: status->kind = stopped, signal = SIGCHLD
...
infrun: TARGET_WAITKIND_STOPPED
infrun: stop_pc = 0x323d4e8b94
infrun: random signal 20
So I'm now thinking that it'd be even better to make infrun output
consistently use the enum symbol string, like so:
infrun: clear_proceed_status_thread (Thread 0x7ffff7fca700 (LWP 25663))
infrun: clear_proceed_status_thread (Thread 0x7ffff7fcb740 (LWP 25659))
- infrun: proceed (addr=0xffffffffffffffff, signal=144, step=1)
+ infrun: proceed (addr=0xffffffffffffffff, signal=GDB_SIGNAL_DEFAULT, step=1)
- infrun: resume (step=1, signal=0), trap_expected=0, current thread [Thread 0x7ffff7fcb740 (LWP 25659)] at 0x400700
+ infrun: resume (step=1, signal=GDB_SIGNAL_0), trap_expected=0, current thread [Thread 0x7ffff7fcb740 (LWP 25659)] at 0x400700
infrun: wait_for_inferior ()
infrun: target_wait (-1, status) =
infrun: 25659 [Thread 0x7ffff7fcb740 (LWP 25659)],
- infrun: status->kind = stopped, signal = SIGCHLD
+ infrun: status->kind = stopped, signal = GDB_SIGNAL_CHLD
infrun: infwait_normal_state
infrun: TARGET_WAITKIND_STOPPED
infrun: stop_pc = 0x400700
- infrun: random signal 20
+ infrun: random signal (GDB_SIGNAL_CHLD)
infrun: random signal, keep going
- infrun: resume (step=1, signal=20), trap_expected=0, current thread [Thread 0x7ffff7fcb740 (LWP 25659)] at 0x400700
+ infrun: resume (step=1, signal=GDB_SIGNAL_CHLD), trap_expected=0, current thread [Thread 0x7ffff7fcb740 (LWP 25659)] at 0x400700
infrun: prepare_to_wait
infrun: target_wait (-1, status) =
infrun: 25659 [Thread 0x7ffff7fcb740 (LWP 25659)],
- infrun: status->kind = stopped, signal = SIGTRAP
+ infrun: status->kind = stopped, signal = GDB_SIGNAL_TRAP
infrun: infwait_normal_state
infrun: TARGET_WAITKIND_STOPPED
infrun: stop_pc = 0x400704
infrun: stepi/nexti
infrun: stop_stepping
GDB's signal numbers are public and hardcoded (see
include/gdb/signals.h), so there's really no need to clutter the
output with numeric values in some places while others not. Replacing
the magic "144" with GDB_SIGNAL_DEFAULT in "proceed"'s debug output
(see above) I think is quite nice.
I posit that all this makes it clearer to newcomers that GDB has its
own signal numbering (and that there must be some mapping going on).
Tested on x86_64 Fedora 17.
gdb/
2013-10-23 Pedro Alves <palves@redhat.com>
* common/gdb_signals.h (gdb_signal_to_symbol_string): Declare.
* common/signals.c: Include "gdb_assert.h".
(signals): New field 'symbol'.
(SET): Use the 'symbol' parameter.
(gdb_signal_to_symbol_string): New function.
* infrun.c (handle_inferior_event) <random signal>: In debug
output, print the random signal enum as string in addition to its
number.
* target/waitstatus.c (target_waitstatus_to_string): Print the
signal's enum value as string instead of the (POSIX) signal name.
* Makefile.in (SFILES): Remove common/target-common.c and
add target/waitstatus.c.
(HFILES_NO_SRCDIR): Remove common/target-common.h and add
target/resume.h, target/wait.h and target/waitstatus.h.
(COMMON_OBS): Remove target-common.o and add
waitstatus.o.
(target-common.o): Remove.
(waitstatus.o): New target object file.
* common/target-common.c: Move contents to
target/waitstatus.c and remove.
* common/target-common.h: Move contents to other files and
remove.
(enum resume_kind: Move to target/resume.h.
(TARGET_WNOHANG): Move to target/wait.h.
(enum target_waitkind): Move to target/waitstatus.h.
(struct target_waitstatus): Likewise.
* target.h: Do not include target-common.h and
include target/resume.h, target/wait.h and
target/waitstatus.h.
* target/resume.h: New file.
* target/wait.h: New file.
* target/waitstatus.h: New file.
* target/waitstatus.c: New file.
gdb/gdbserver/
* Makefile.in (INCLUDE_CFLAGS): Include -I$(srcdir)/../.
(SFILES): Remove $(srcdir)/common/target-common.c and
add $(srcdir)/target/waitstatus.c.
(OBS): Remove target-common.o and add waitstatus.o.
(server_h): Remove $(srcdir)/../common/target-common.h and
add $(srcdir)/../target/resume.h, $(srcdir)/../target/wait.h
and $(srcdir)/../target/waitstatus.h.
(target-common.o): Remove.
(waitstatus.o): New target object file.
* target.h: Do not include target-common.h and
include target/resume.h, target/wait.h and
target/waitstatus.h.