From 83c24e31df6932a6d4fced179050c6d8d8c6f3b5 Mon Sep 17 00:00:00 2001
From: Philippe Waroquiers <philippe.waroquiers@skynet.be>
Date: Sun, 7 Mar 2021 22:29:27 +0100
Subject: [PATCH] Fix nlcontrolc.vgtest hanging on newer glibc and/or arm64

This test verifies that GDB can interrupt a process with all threads
blocked in a long select syscall.
The test used to terminate by having GDB modifying the select argument.
However, modifying the select argument works only for specific arch
and/or specific versions of glibc.
The test then blocks on other architectures/glibc versions.

The previous version of the test was:
  * first launching sleepers so as to have all threads blocked in long select
  * interrupting these threads
  * changing the select time arg so that the threads burn cpu
  * and then change variables to have the program exit.

The new version does:
  * first launches sleepers so that all threads are burning cpu.
  * interrupting these threads
  * change the local variables of sleepers so that the threads will
    block in a long select syscall
  * interrupt these threads
  * kill the program.

With this new version, we still check the behaviour of gdb+vgdbserver
for both burning and sleep threads, but without having the termination
depending on modifying select syscall argument.

Tested on debian amd64 and on ubuntu arm64 (to check the test does not hang
on an arm64 platform).

Upstream-Status: Backport

From commit on master:
c79180a3afcf65902e578646c3b716cc749db406

Signed-off-by: Yi Fan Yu <yifan.yu@windriver.com>
---
 gdbserver_tests/nlcontrolc.stderr.exp  |  4 +-
 gdbserver_tests/nlcontrolc.stdinB.gdb  | 57 +++++++++++++++-----------
 gdbserver_tests/nlcontrolc.stdoutB.exp | 25 ++++++-----
 gdbserver_tests/nlcontrolc.vgtest      | 12 +++---
 4 files changed, 56 insertions(+), 42 deletions(-)

diff --git a/gdbserver_tests/nlcontrolc.stderr.exp b/gdbserver_tests/nlcontrolc.stderr.exp
index ac75bb3da..b63a9a988 100644
--- a/gdbserver_tests/nlcontrolc.stderr.exp
+++ b/gdbserver_tests/nlcontrolc.stderr.exp
@@ -3,9 +3,9 @@ Nulgrind, the minimal Valgrind tool
 (action at startup) vgdb me ... 
 
 
-loops/sleep_ms/burn/threads_spec/affinity:  1000000000 1000000000 1000000000 BSBSBSBS 1
+loops/sleep_ms/burn/threads_spec/affinity:  1000000000 0 100000 BSBSBSBS 1
 Brussels ready to sleep and/or burn
 London ready to sleep and/or burn
 Petaouchnok ready to sleep and/or burn
 main ready to sleep and/or burn
-
+Gdb request to kill this process
diff --git a/gdbserver_tests/nlcontrolc.stdinB.gdb b/gdbserver_tests/nlcontrolc.stdinB.gdb
index 667ece18d..ea4fcd530 100644
--- a/gdbserver_tests/nlcontrolc.stdinB.gdb
+++ b/gdbserver_tests/nlcontrolc.stdinB.gdb
@@ -9,32 +9,43 @@ shell ./simulate_control_c --vgdb-prefix=./vgdb-prefix-nlcontrolc 1 grep main nl
 #
 continue
 #
-# Here, all tasks should be blocked in a loooonnnng select, all in WaitSys
-info threads
-# We will unblock them by changing their timeout argument
-# To avoid going into the frame where the timeval arg is,
-# it has been defined as global variables, as the nr
-# of calls on the stack differs between 32bits and 64bits,
-# and/or between OS.
-# ensure select finishes in a few milliseconds max:
-p t[0].tv_sec = 0
-p t[1].tv_sec = 0
-p t[2].tv_sec = 0
-p t[3].tv_sec = 0
-#
-# We will change the burning parameters in a few  seconds
+# Threads are burning cpu now
+# We would like to fully test info threads here, but which thread are Runnable
+# or Yielding is unpredictable. With a recent enough gdb, check the nr of
+# threads by state using pipe commands and grep/wc.
+init-if-undefined $_gdb_major = 0
+init-if-undefined $_gdb_minor = 0
+if $_gdb_major >= 9
+  | info threads | grep VgTs_Runnable | wc -l
+  | info threads | grep VgTs_Yielding | wc -l
+else
+  echo 1\n
+  echo 3\n
+end
+# We change the variables so that all the threads are blocked in a syscall
+p burn = 0
+p sleepms = 1000000
+#
+#
 shell ./simulate_control_c --vgdb-prefix=./vgdb-prefix-nlcontrolc 1 grep changed nlcontrolc.stdoutB.out
 #
-echo changed burning parameters\n
+echo changed burning parameters to sleeping parameters\n
 continue
+# Here, all tasks should be blocked in a loooonnnng select, all in WaitSys
+info threads
+# We reset the sleepms to 0. The threads should still be blocked in the syscall
+p sleepms = 0
+shell ./simulate_control_c --vgdb-prefix=./vgdb-prefix-nlcontrolc 1 grep reset nlcontrolc.stdoutB.out
 #
-# Threads are burning cpu now
-# We would like to test info threads here, but which thread are Runnable or Yielding
-# is unpredictable.
-# info threads
-p burn = 0
-p loops = 0
-p report_finished = 0
+echo reset to sleeping parameters\n
 continue
-# and the process should stop very quickly now
+# threads should still be blocked in a loooonnnng select, all in WaitSys
+info threads
+if $_gdb_major >= 9
+  | info threads | grep VgTs_WaitSys | wc -l
+else
+  echo 4\n
+end
+# Make the process die.
+kill
 quit
diff --git a/gdbserver_tests/nlcontrolc.stdoutB.exp b/gdbserver_tests/nlcontrolc.stdoutB.exp
index e8a5ff8ba..2e8dc8498 100644
--- a/gdbserver_tests/nlcontrolc.stdoutB.exp
+++ b/gdbserver_tests/nlcontrolc.stdoutB.exp
@@ -1,18 +1,21 @@
 Continuing.
 Program received signal SIGTRAP, Trace/breakpoint trap.
+do_burn () at sleepers.c:41
+41	   for (i = 0; i < burn; i++) loopnr++;
+ > > > > > >1
+3
+$1 = 0
+$2 = 1000000
+changed burning parameters to sleeping parameters
+Continuing.
+Program received signal SIGTRAP, Trace/breakpoint trap.
 0x........ in syscall ...
 * 1 Thread .... (tid 1 VgTs_WaitSys)  0x........ in syscall ...
-$1 = 0
-$2 = 0
 $3 = 0
-$4 = 0
-changed burning parameters
+reset to sleeping parameters
 Continuing.
 Program received signal SIGTRAP, Trace/breakpoint trap.
-do_burn () at sleepers.c:41
-41	   for (i = 0; i < burn; i++) loopnr++;
-$5 = 0
-$6 = 0
-$7 = 0
-Continuing.
-Program exited normally.
+0x........ in syscall ...
+* 1 Thread .... (tid 1 VgTs_WaitSys)  0x........ in syscall ...
+ > > > >4
+Kill the program being debugged? (y or n) [answered Y; input not from terminal]
diff --git a/gdbserver_tests/nlcontrolc.vgtest b/gdbserver_tests/nlcontrolc.vgtest
index bb5308403..09edfcaba 100644
--- a/gdbserver_tests/nlcontrolc.vgtest
+++ b/gdbserver_tests/nlcontrolc.vgtest
@@ -4,16 +4,16 @@
 #          and modify some variables
 #   the user can control-c an process with all threads in Running/Yielding
 #          and modify some variables
-# sleepers is started with argument so that it will compute during ages.
-# The variable modifications means it will exit in a reasonable time.
-# This test is disabled on Solaris because modifying select/poll/ppoll timeout
-# has no effect if a thread is already blocked in that syscall.
+# sleepers is started so that it burns CPU.
+# We then interrupt the process.
+# We modify variables so that instead of burning cpu, sleepers blocks
+# all threads in a select syscall.
 prog: sleepers
-args: 1000000000 1000000000 1000000000 BSBSBSBS 1
+args: 1000000000 0 100000 BSBSBSBS 1
 vgopts: --tool=none --vgdb=yes --vgdb-error=0 --vgdb-prefix=./vgdb-prefix-nlcontrolc
 stderr_filter: filter_stderr
 # Bug 338633 nlcontrol hangs on arm64 currently.
-prereq: test -e gdb -a -f vgdb.invoker && ! ../tests/arch_test arm64 && ! ../tests/os_test solaris
+prereq: test -e gdb -a -f vgdb.invoker && ! ../tests/os_test solaris
 progB: gdb
 argsB: --quiet -l 60 --nx ./sleepers
 stdinB: nlcontrolc.stdinB.gdb
-- 
2.29.2

