From patchwork Mon Dec 12 20:30:57 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Pedro Alves X-Patchwork-Id: 61840 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 50A27384C930 for ; Mon, 12 Dec 2022 20:33:49 +0000 (GMT) X-Original-To: gdb-patches@sourceware.org Delivered-To: gdb-patches@sourceware.org Received: from mail-wm1-f42.google.com (mail-wm1-f42.google.com [209.85.128.42]) by sourceware.org (Postfix) with ESMTPS id D752938493EF for ; Mon, 12 Dec 2022 20:31:35 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org D752938493EF Authentication-Results: sourceware.org; dmarc=none (p=none dis=none) header.from=palves.net Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=gmail.com Received: by mail-wm1-f42.google.com with SMTP id o15so6594610wmr.4 for ; Mon, 12 Dec 2022 12:31:35 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=6OfaKwDwJiRQ/1hgylfE9XyJSfjJJRjPSeQouADDp0Q=; b=6YiUB8FQUdaHF8yP/4S5zNKzfwNQ6YYX19swqBVlrgpG4d2/Ozp6mRzlweJ4ATTgnb YjqrlKqJ0cF/b44eV/CZ4MpGDai56VqyJRtCpq3zTnnRSMj8koTKStkfxMva/cJtkz1j e9l/w/SJsTOBIW1d5fGmo+MdexUBuPDYAlbesL/bGBGVV802RcPN5hdZNac7v3x9F6/W uiGdSyvm/1V2x5SuHs0qgRCL8419ys9othD3/BzpWSc71QBFCizE9GCeE1BW8f66r/jL hmhg6XtV3QpvnRv/frijqvQ7YsagMhL6ECs6p3SN5hvdUwvhbMMwNwWoKj/bNLgDCkgo SxSw== X-Gm-Message-State: ANoB5pnXgSMxrLq3Mt3I95GyEkmHRyC8MZS7sD1LZzbMeHEBAFKFcbcD OSZ67t3B/VZo1f/yhfp7S0k4RolmuRwHcA== X-Google-Smtp-Source: AA0mqf7yQuoQVi0r8iLx+FvQ/SXZDV5uU9t+nu+FWmg8RnrPJ28PyStkDgCTkmaTMu8v7Nw5s/lc6g== X-Received: by 2002:a1c:cc1a:0:b0:3cf:5e42:de64 with SMTP id h26-20020a1ccc1a000000b003cf5e42de64mr13714540wmb.39.1670877095162; Mon, 12 Dec 2022 12:31:35 -0800 (PST) Received: from localhost ([2001:8a0:f912:6700:afd9:8b6d:223f:6170]) by smtp.gmail.com with ESMTPSA id j13-20020a5d618d000000b002422816aa25sm11322260wru.108.2022.12.12.12.31.34 (version=TLS1_3 cipher=TLS_AES_128_GCM_SHA256 bits=128/128); Mon, 12 Dec 2022 12:31:34 -0800 (PST) From: Pedro Alves To: gdb-patches@sourceware.org Cc: Pedro Alves Subject: [PATCH 27/31] Testcases for stepping over thread exit syscall (PR gdb/27338) Date: Mon, 12 Dec 2022 20:30:57 +0000 Message-Id: <20221212203101.1034916-28-pedro@palves.net> X-Mailer: git-send-email 2.36.0 In-Reply-To: <20221212203101.1034916-1-pedro@palves.net> References: <20221212203101.1034916-1-pedro@palves.net> MIME-Version: 1.0 X-Spam-Status: No, score=-10.5 required=5.0 tests=BAYES_00, FREEMAIL_FORGED_FROMDOMAIN, FREEMAIL_FROM, GIT_PATCH_0, HEADER_FROM_DIFFERENT_DOMAINS, KAM_DMARC_STATUS, KAM_SHORT, RCVD_IN_DNSWL_NONE, RCVD_IN_MSPIKE_H2, SPF_HELO_NONE, SPF_PASS, TXREP autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org X-BeenThere: gdb-patches@sourceware.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Gdb-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: gdb-patches-bounces+patchwork=sourceware.org@sourceware.org Sender: "Gdb-patches" From: Simon Marchi - New in this series version: - gdb.threads/step-over-thread-exit.exp has a couple new testing axes: - non-stop vs all-stop. - in non-stop have the testcase explicitly stop all threads in non-stop mode, vs not doing that. - bail out of gdb.threads/step-over-thread-exit.exp early on FAIL, to avoid cascading timeouts. Add new gdb.threads/step-over-thread-exit.exp and gdb.threads/step-over-thread-exit-while-stop-all-threads.exp testcases, exercising stepping over thread exit syscall. These make use of lib/my-syscalls.S to define the exit syscall. Co-authored-by: Pedro Alves Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=27338 Change-Id: Ie8b2c5747db99b7023463a897a8390d9e814a9c9 Reviewed-By: Andrew Burgess --- ...-over-thread-exit-while-stop-all-threads.c | 77 +++++++++++ ...ver-thread-exit-while-stop-all-threads.exp | 69 ++++++++++ .../gdb.threads/step-over-thread-exit.c | 52 ++++++++ .../gdb.threads/step-over-thread-exit.exp | 126 ++++++++++++++++++ gdb/testsuite/lib/my-syscalls.S | 4 + gdb/testsuite/lib/my-syscalls.h | 5 + 6 files changed, 333 insertions(+) create mode 100644 gdb/testsuite/gdb.threads/step-over-thread-exit-while-stop-all-threads.c create mode 100644 gdb/testsuite/gdb.threads/step-over-thread-exit-while-stop-all-threads.exp create mode 100644 gdb/testsuite/gdb.threads/step-over-thread-exit.c create mode 100644 gdb/testsuite/gdb.threads/step-over-thread-exit.exp diff --git a/gdb/testsuite/gdb.threads/step-over-thread-exit-while-stop-all-threads.c b/gdb/testsuite/gdb.threads/step-over-thread-exit-while-stop-all-threads.c new file mode 100644 index 00000000000..2699ad5d714 --- /dev/null +++ b/gdb/testsuite/gdb.threads/step-over-thread-exit-while-stop-all-threads.c @@ -0,0 +1,77 @@ +/* This testcase is part of GDB, the GNU debugger. + + Copyright 2021-2022 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +#include +#include +#include +#include "../lib/my-syscalls.h" + +#define NUM_THREADS 32 + +static void * +stepper_over_exit_thread (void *v) +{ + my_exit (0); + + /* my_exit above should exit the thread, we don't expect to reach + here. */ + abort (); +} + +static void * +spawner_thread (void *v) +{ + for (;;) + { + pthread_t threads[NUM_THREADS]; + int i; + + for (i = 0; i < NUM_THREADS; i++) + pthread_create (&threads[i], NULL, stepper_over_exit_thread, NULL); + + for (i = 0; i < NUM_THREADS; i++) + pthread_join (threads[i], NULL); + } +} + +static void +break_here (void) +{ +} + +static void * +breakpoint_hitter_thread (void *v) +{ + for (;;) + break_here (); +} + +int +main () +{ + pthread_t breakpoint_hitter; + pthread_t spawner; + + alarm (60); + + pthread_create (&spawner, NULL, spawner_thread, NULL); + pthread_create (&breakpoint_hitter, NULL, breakpoint_hitter_thread, NULL); + + pthread_join (spawner, NULL); + + return 0; +} diff --git a/gdb/testsuite/gdb.threads/step-over-thread-exit-while-stop-all-threads.exp b/gdb/testsuite/gdb.threads/step-over-thread-exit-while-stop-all-threads.exp new file mode 100644 index 00000000000..6a46aff700e --- /dev/null +++ b/gdb/testsuite/gdb.threads/step-over-thread-exit-while-stop-all-threads.exp @@ -0,0 +1,69 @@ +# Copyright 2021-2022 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +# Test stepping over a breakpoint installed on an instruction that +# exits the thread, while another thread is repeatedly hitting a +# breakpoint, causing GDB to stop all threads. + +standard_testfile .c + +set syscalls_src $srcdir/lib/my-syscalls.S + +if { [build_executable "failed to prepare" $testfile \ + [list $srcfile $syscalls_src] {debug pthreads}] == -1 } { + return +} + +proc test {displaced-stepping target-non-stop} { + save_vars ::GDBFLAGS { + append ::GDBFLAGS " -ex \"maintenance set target-non-stop ${target-non-stop}\"" + clean_restart $::binfile + } + + gdb_test_no_output "set displaced-stepping ${displaced-stepping}" + + if { ![runto_main] } { + return + } + + # The "stepper over exit" threads will step over an instruction + # that causes them to exit. + gdb_test "break my_exit_syscall if 0" + + # The "breakpoint hitter" thread will repeatedly hit this + # breakpoint, causing GDB to stop all threads. + gdb_test "break break_here" + + # To avoid flooding the log with thread created/exited messages. + gdb_test_no_output "set print thread-events off" + + # Make sure the target reports the breakpoint stops. + gdb_test_no_output "set breakpoint condition-evaluation host" + + for { set i 0 } { $i < 30 } { incr i } { + with_test_prefix "iter $i" { + if { [gdb_test "continue" "hit Breakpoint $::decimal, break_here .*"] != 0 } { + # Exit if there's a failure to avoid lengthy timeouts. + break + } + } + } +} + +foreach_with_prefix displaced-stepping {off auto} { + foreach_with_prefix target-non-stop {off on} { + test ${displaced-stepping} ${target-non-stop} + } +} diff --git a/gdb/testsuite/gdb.threads/step-over-thread-exit.c b/gdb/testsuite/gdb.threads/step-over-thread-exit.c new file mode 100644 index 00000000000..878e5924c5c --- /dev/null +++ b/gdb/testsuite/gdb.threads/step-over-thread-exit.c @@ -0,0 +1,52 @@ +/* This testcase is part of GDB, the GNU debugger. + + Copyright 2021-2022 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +#include +#include +#include +#include "../lib/my-syscalls.h" + +static void * +thread_func (void *arg) +{ + my_exit (0); + + /* my_exit above should exit the thread, we don't expect to reach + here. */ + abort (); +} + +int +main (void) +{ + int i; + + /* Spawn and join a thread, 100 times. */ + for (i = 0; i < 100; i++) + { + pthread_t thread; + int ret; + + ret = pthread_create (&thread, NULL, thread_func, NULL); + assert (ret == 0); + + ret = pthread_join (thread, NULL); + assert (ret == 0); + } + + return 0; +} diff --git a/gdb/testsuite/gdb.threads/step-over-thread-exit.exp b/gdb/testsuite/gdb.threads/step-over-thread-exit.exp new file mode 100644 index 00000000000..ed8534cf518 --- /dev/null +++ b/gdb/testsuite/gdb.threads/step-over-thread-exit.exp @@ -0,0 +1,126 @@ +# Copyright 2021-2022 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +# Test stepping over a breakpoint installed on an instruction that +# exits the thread. + +standard_testfile .c + +set syscalls_src $srcdir/lib/my-syscalls.S + +if { [build_executable "failed to prepare" $testfile \ + [list $srcfile $syscalls_src] {debug pthreads}] == -1 } { + return +} + +# Each argument is a different testing axis, most of them obvious. +# NS_STOP_ALL is only used if testing "set non-stop on", and indicates +# whether to have GDB explicitly stop all threads before continuing to +# thread exit. +proc test {displaced-stepping non-stop target-non-stop schedlock ns_stop_all} { + if {${non-stop} == "off" && $ns_stop_all} { + error "invalid arguments" + } + + save_vars ::GDBFLAGS { + append ::GDBFLAGS " -ex \"maintenance set target-non-stop ${target-non-stop}\"" + append ::GDBFLAGS " -ex \"set non-stop ${non-stop}\"" + clean_restart $::binfile + } + + gdb_test_no_output "set displaced-stepping ${displaced-stepping}" + + if { ![runto_main] } { + return + } + + gdb_breakpoint "my_exit_syscall" + + if {$schedlock + || (${non-stop} == "on" && $ns_stop_all)} { + gdb_test "continue" \ + "Thread 2 .*hit Breakpoint $::decimal.* my_exit_syscall .*" \ + "continue until syscall" + + if {${non-stop} == "on"} { + # The test only spawns one thread at a time, so this just + # stops the main thread. + gdb_test_multiple "interrupt -a" "" { + -re "$::gdb_prompt " { + gdb_test_multiple "" $gdb_test_name { + -re "Thread 1 \[^\r\n\]*stopped." { + pass $gdb_test_name + } + } + } + } + } + + gdb_test "thread 2" "Switching to thread 2 .*" + + gdb_test_no_output "set scheduler-locking ${schedlock}" + + gdb_test "continue" \ + "No unwaited-for children left." \ + "continue stops when thread exits" + } else { + gdb_test_no_output "set scheduler-locking ${schedlock}" + + for { set i 0 } { $i < 100 } { incr i } { + with_test_prefix "iter $i" { + set ok 0 + set thread "" + gdb_test_multiple "continue" "" { + -re -wrap "Thread ($::decimal) .*hit Breakpoint $::decimal.* my_exit_syscall .*" { + set thread $expect_out(1,string) + set ok 1 + } + } + if {!${ok}} { + # Exit if there's a failure to avoid lengthy + # timeouts. + break + } + + if {${non-stop}} { + gdb_test "thread $thread" "Switching to thread .*" \ + "switch to event thread" + } + } + } + } +} + +foreach_with_prefix displaced-stepping {off auto} { + foreach_with_prefix non-stop {off on} { + foreach_with_prefix target-non-stop {off on} { + if {${non-stop} == "on" && ${target-non-stop} == "off"} { + # Invalid combination. + continue + } + + foreach_with_prefix schedlock {off on} { + if {${non-stop} == "on"} { + foreach_with_prefix ns_stop_all {0 1} { + test ${displaced-stepping} ${non-stop} ${target-non-stop} \ + ${schedlock} ${ns_stop_all} + } + } else { + test ${displaced-stepping} ${non-stop} ${target-non-stop} ${schedlock} 0 + } + } + } + } +} diff --git a/gdb/testsuite/lib/my-syscalls.S b/gdb/testsuite/lib/my-syscalls.S index 6fb53624f31..ff62b5eb4e9 100644 --- a/gdb/testsuite/lib/my-syscalls.S +++ b/gdb/testsuite/lib/my-syscalls.S @@ -69,4 +69,8 @@ NAME ## _syscall: ;\ SYSCALL (my_execve, __NR_execve) +/* void my_exit (int code); */ + +SYSCALL (my_exit, __NR_exit) + .section .note.GNU-stack,"",@progbits diff --git a/gdb/testsuite/lib/my-syscalls.h b/gdb/testsuite/lib/my-syscalls.h index a0c069c58e5..ceaa587b3e6 100644 --- a/gdb/testsuite/lib/my-syscalls.h +++ b/gdb/testsuite/lib/my-syscalls.h @@ -22,4 +22,9 @@ int my_execve (const char *file, char *argv[], char *envp[]); +/* `exit` syscall, which makes the thread exit (as opposed to + `exit_group`, which makes the process exit). */ + +void my_exit (int code); + #endif /* MY_SYSCALLS_H */