You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

173 lines
4.3 KiB

/* This is part of GDB, the GNU debugger.
Copyright 2011-2021 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 <http://www.gnu.org/licenses/>.
*/
#define _GNU_SOURCE 1
#include <dlfcn.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdlib.h>
[gdb/testsuite] Add check-readmore Consider the gdb output: ... 27 return SYSCALL_CANCEL (nanosleep, requested_time, remaining);^M (gdb) ^M Thread 2 "run-attach-whil" stopped.^M ... When trying to match the gdb prompt using gdb_test which uses '$gdb_prompt $', it may pass or fail. This sort of thing needs to be fixed (see commit b0e2f96b56b), but there's currently no way to reliably find this type of FAILs. We have check-read1, but that one actually make the test pass reliably. We need something like the opposite of check-read1: something that makes expect read a bit slower, or more exhaustively. Add a new test target check-readmore that implements this. There are two methods of implementing this in read1.c: - the first method waits a bit before doing a read - the second method does a read and then decides whether to return or to wait a bit and do another read, and so on. The second method is potentially faster, has less risc of timeout and could potentially detect more problems. The first method has a simpler implementation. The second method is enabled by default. The default waiting period is 10 miliseconds. The first method can be enabled using: ... $ export READMORE_METHOD=1 ... and the waiting period can be specified in miliseconds using: ... $ export READMORE_SLEEP=9 ... Also a log file can be specified using: ... $ export READMORE_LOG=$(pwd -P)/LOG ... Tested on x86_64-linux. Testing with check-readmore showed these regressions: ... FAIL: gdb.base/bp-cmds-continue-ctrl-c.exp: run: stop with control-c (continue) FAIL: gdb.base/bp-cmds-continue-ctrl-c.exp: attach: stop with control-c (continue) ... I have not been able to find a problem in the test-case, and I think it's the nature of both the test-case and readmore that makes it run longer. Make these pass by increasing the alarm timeout from 60 to 120 seconds. Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=27957
5 years ago
#include <string.h>
#include <errno.h>
#include <stdio.h>
[gdb/testsuite] Add check-readmore Consider the gdb output: ... 27 return SYSCALL_CANCEL (nanosleep, requested_time, remaining);^M (gdb) ^M Thread 2 "run-attach-whil" stopped.^M ... When trying to match the gdb prompt using gdb_test which uses '$gdb_prompt $', it may pass or fail. This sort of thing needs to be fixed (see commit b0e2f96b56b), but there's currently no way to reliably find this type of FAILs. We have check-read1, but that one actually make the test pass reliably. We need something like the opposite of check-read1: something that makes expect read a bit slower, or more exhaustively. Add a new test target check-readmore that implements this. There are two methods of implementing this in read1.c: - the first method waits a bit before doing a read - the second method does a read and then decides whether to return or to wait a bit and do another read, and so on. The second method is potentially faster, has less risc of timeout and could potentially detect more problems. The first method has a simpler implementation. The second method is enabled by default. The default waiting period is 10 miliseconds. The first method can be enabled using: ... $ export READMORE_METHOD=1 ... and the waiting period can be specified in miliseconds using: ... $ export READMORE_SLEEP=9 ... Also a log file can be specified using: ... $ export READMORE_LOG=$(pwd -P)/LOG ... Tested on x86_64-linux. Testing with check-readmore showed these regressions: ... FAIL: gdb.base/bp-cmds-continue-ctrl-c.exp: run: stop with control-c (continue) FAIL: gdb.base/bp-cmds-continue-ctrl-c.exp: attach: stop with control-c (continue) ... I have not been able to find a problem in the test-case, and I think it's the nature of both the test-case and readmore that makes it run longer. Make these pass by increasing the alarm timeout from 60 to 120 seconds. Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=27957
5 years ago
/* Default READMORE method. */
#define READMORE_METHOD_DEFAULT 2
/* Default READMORE sleep time in miliseconds. */
#define READMORE_SLEEP_DEFAULT 10
/* Helper function. Intialize *METHOD according to environment variable
READMORE_METHOD, and *SLEEP according to environment variable
READMORE_SLEEP. */
static void
init_readmore (int *method, unsigned int *sleep, FILE **log)
{
char *env = getenv ("READMORE_METHOD");
if (env == NULL)
*method = READMORE_METHOD_DEFAULT;
else if (strcmp (env, "1") == 0)
*method = 1;
else if (strcmp (env, "2") == 0)
*method = 2;
else
/* Default. */
*method = READMORE_METHOD_DEFAULT;
env = getenv ("READMORE_SLEEP");
if (env == NULL)
*sleep = READMORE_SLEEP_DEFAULT;
else
*sleep = atoi (env);
env = getenv ("READMORE_LOG");
if (env == NULL)
*log = NULL;
else
*log = fopen (env, "w");
}
/* Wrap 'read', and modify it's behaviour using READ1 or READMORE style. */
ssize_t
read (int fd, void *buf, size_t count)
{
static ssize_t (*read2) (int fd, void *buf, size_t count) = NULL;
[gdb/testsuite] Add check-readmore Consider the gdb output: ... 27 return SYSCALL_CANCEL (nanosleep, requested_time, remaining);^M (gdb) ^M Thread 2 "run-attach-whil" stopped.^M ... When trying to match the gdb prompt using gdb_test which uses '$gdb_prompt $', it may pass or fail. This sort of thing needs to be fixed (see commit b0e2f96b56b), but there's currently no way to reliably find this type of FAILs. We have check-read1, but that one actually make the test pass reliably. We need something like the opposite of check-read1: something that makes expect read a bit slower, or more exhaustively. Add a new test target check-readmore that implements this. There are two methods of implementing this in read1.c: - the first method waits a bit before doing a read - the second method does a read and then decides whether to return or to wait a bit and do another read, and so on. The second method is potentially faster, has less risc of timeout and could potentially detect more problems. The first method has a simpler implementation. The second method is enabled by default. The default waiting period is 10 miliseconds. The first method can be enabled using: ... $ export READMORE_METHOD=1 ... and the waiting period can be specified in miliseconds using: ... $ export READMORE_SLEEP=9 ... Also a log file can be specified using: ... $ export READMORE_LOG=$(pwd -P)/LOG ... Tested on x86_64-linux. Testing with check-readmore showed these regressions: ... FAIL: gdb.base/bp-cmds-continue-ctrl-c.exp: run: stop with control-c (continue) FAIL: gdb.base/bp-cmds-continue-ctrl-c.exp: attach: stop with control-c (continue) ... I have not been able to find a problem in the test-case, and I think it's the nature of both the test-case and readmore that makes it run longer. Make these pass by increasing the alarm timeout from 60 to 120 seconds. Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=27957
5 years ago
static FILE *log;
int readmore;
#ifdef READMORE
readmore = 1;
#else
readmore = 0;
#endif
static int readmore_method;
static unsigned int readmore_sleep;
if (read2 == NULL)
{
[gdb/testsuite] Work around tcl bug in libsegfault.exp with check-read1 When running libsegfault.exp with check-read1, I get: ... Running gdb/testsuite/gdb.base/libsegfault.exp ... ERROR: tcl error sourcing gdb/testsuite/gdb.base/libsegfault.exp. ERROR: no such variable (read trace on "env(LD_PRELOAD)") invoked from within "set env(LD_PRELOAD)" ("uplevel" body line 1) invoked from within "uplevel 1 [list set $var]" invoked from within "if [uplevel 1 [list array exists $var]] { set saved_arrays($var) [uplevel 1 [list array get $var]] } else { set saved_scalars($var) [uplevel ..." invoked from within "if [uplevel 1 [list info exists $var]] { if [uplevel 1 [list array exists $var]] { set saved_arrays($var) [uplevel 1 [list array get $var]] ..." (procedure "save_vars" line 11) invoked from within "save_vars { env(LD_PRELOAD) } { if { ![info exists env(LD_PRELOAD) ] || $env(LD_PRELOAD) == "" } { set env(LD_PRELOAD) "$lib" } else { ..." (procedure "gdb_spawn_with_ld_preload" line 4) invoked from within "gdb_spawn_with_ld_preload $libsegfault """ ... There are several things here interacting with environment variable LD_PRELOAD: - the expect "binary" build/gdb/testsuite/expect-read1 with does export LD_PRELOAD=build/gdb/testsuite/read1.so before calling native expect - read1.so which does unsetenv ("LD_PRELOAD") upon first call to read - the test-case, which wants to set or append libSegFault.so to LD_PRELOAD The error occurs when accessing $env(LD_PRELOAD), in a branch where "info exists env(LD_PRELOAD)" returns true. AFAIU, this is https://core.tcl-lang.org/tcl/tktview?name=67fd4f973a "incorrect results of 'info exists' when unset env var in one interp and check for existence from another interp". Work around the tcl bug by not unsetting the variable, but setting it to "" instead: ... - unsetenv ("LD_PRELOAD"); + setenv ("LD_PRELOAD", "", 1); ... Verified that reverting commit de28a3b72e "[gdb/testsuite, 2/2] Fix gdb.linespec/explicit.exp with check-read1" reintroduced the check-read1 failure in gdb.linespec/explicit.exp. This fixes a similar error in attach-slow-waitpid.exp, which also sets LD_PRELOAD. Tested on x86_64-linux with check-read1. gdb/testsuite/ChangeLog: 2019-07-30 Tom de Vries <tdevries@suse.de> * lib/read1.c (read): Don't use unsetenv (v), use setenv (v, "", 1) instead.
7 years ago
/* Use setenv (v, "", 1) rather than unsetenv (v) to work around
https://core.tcl-lang.org/tcl/tktview?name=67fd4f973a "incorrect
results of 'info exists' when unset env var in one interp and check
for existence from another interp". */
setenv ("LD_PRELOAD", "", 1);
read2 = dlsym (RTLD_NEXT, "read");
[gdb/testsuite] Add check-readmore Consider the gdb output: ... 27 return SYSCALL_CANCEL (nanosleep, requested_time, remaining);^M (gdb) ^M Thread 2 "run-attach-whil" stopped.^M ... When trying to match the gdb prompt using gdb_test which uses '$gdb_prompt $', it may pass or fail. This sort of thing needs to be fixed (see commit b0e2f96b56b), but there's currently no way to reliably find this type of FAILs. We have check-read1, but that one actually make the test pass reliably. We need something like the opposite of check-read1: something that makes expect read a bit slower, or more exhaustively. Add a new test target check-readmore that implements this. There are two methods of implementing this in read1.c: - the first method waits a bit before doing a read - the second method does a read and then decides whether to return or to wait a bit and do another read, and so on. The second method is potentially faster, has less risc of timeout and could potentially detect more problems. The first method has a simpler implementation. The second method is enabled by default. The default waiting period is 10 miliseconds. The first method can be enabled using: ... $ export READMORE_METHOD=1 ... and the waiting period can be specified in miliseconds using: ... $ export READMORE_SLEEP=9 ... Also a log file can be specified using: ... $ export READMORE_LOG=$(pwd -P)/LOG ... Tested on x86_64-linux. Testing with check-readmore showed these regressions: ... FAIL: gdb.base/bp-cmds-continue-ctrl-c.exp: run: stop with control-c (continue) FAIL: gdb.base/bp-cmds-continue-ctrl-c.exp: attach: stop with control-c (continue) ... I have not been able to find a problem in the test-case, and I think it's the nature of both the test-case and readmore that makes it run longer. Make these pass by increasing the alarm timeout from 60 to 120 seconds. Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=27957
5 years ago
if (readmore)
init_readmore (&readmore_method, &readmore_sleep, &log);
}
[gdb/testsuite] Add check-readmore Consider the gdb output: ... 27 return SYSCALL_CANCEL (nanosleep, requested_time, remaining);^M (gdb) ^M Thread 2 "run-attach-whil" stopped.^M ... When trying to match the gdb prompt using gdb_test which uses '$gdb_prompt $', it may pass or fail. This sort of thing needs to be fixed (see commit b0e2f96b56b), but there's currently no way to reliably find this type of FAILs. We have check-read1, but that one actually make the test pass reliably. We need something like the opposite of check-read1: something that makes expect read a bit slower, or more exhaustively. Add a new test target check-readmore that implements this. There are two methods of implementing this in read1.c: - the first method waits a bit before doing a read - the second method does a read and then decides whether to return or to wait a bit and do another read, and so on. The second method is potentially faster, has less risc of timeout and could potentially detect more problems. The first method has a simpler implementation. The second method is enabled by default. The default waiting period is 10 miliseconds. The first method can be enabled using: ... $ export READMORE_METHOD=1 ... and the waiting period can be specified in miliseconds using: ... $ export READMORE_SLEEP=9 ... Also a log file can be specified using: ... $ export READMORE_LOG=$(pwd -P)/LOG ... Tested on x86_64-linux. Testing with check-readmore showed these regressions: ... FAIL: gdb.base/bp-cmds-continue-ctrl-c.exp: run: stop with control-c (continue) FAIL: gdb.base/bp-cmds-continue-ctrl-c.exp: attach: stop with control-c (continue) ... I have not been able to find a problem in the test-case, and I think it's the nature of both the test-case and readmore that makes it run longer. Make these pass by increasing the alarm timeout from 60 to 120 seconds. Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=27957
5 years ago
/* Only modify 'read' behaviour when reading from the terminal. */
if (isatty (fd) == 0)
goto fallback;
if (!readmore)
{
/* READ1. Force read to return only one byte at a time. */
return read2 (fd, buf, 1);
}
if (readmore_method == 1)
{
/* READMORE, method 1. Wait a little before doing a read. */
usleep (readmore_sleep * 1000);
return read2 (fd, buf, count);
}
if (readmore_method == 2)
{
/* READMORE, method 2. After doing a read, either return or wait
a little and do another read, and so on. */
ssize_t res, total;
int iteration;
int max_iterations = -1;
total = 0;
for (iteration = 1; ; iteration++)
{
res = read2 (fd, (char *)buf + total, count - total);
if (log != NULL)
fprintf (log,
"READ (%d): fd: %d, COUNT: %zd, RES: %zd, ERRNO: %s\n",
iteration, fd, count - total, res,
res == -1 ? strerror (errno) : "none");
if (res == -1)
{
if (iteration == 1)
{
/* Error on first read, report. */
total = -1;
break;
}
if (total > 0
&& (errno == EAGAIN || errno == EWOULDBLOCK || errno == EIO))
{
/* Ignore error, but don't try anymore reading. */
errno = 0;
break;
}
/* Other error, report back. */
total = -1;
break;
}
total += res;
if (total == count)
/* Buf full, no need to do any more reading. */
break;
/* Handle end-of-file. */
if (res == 0)
break;
if (iteration == max_iterations)
break;
usleep (readmore_sleep * 1000);
}
if (log)
fprintf (log, "READ returning: RES: %zd, ERRNO: %s\n",
total, total == -1 ? strerror (errno) : "none");
return total;
}
fallback:
/* Fallback, regular read. */
return read2 (fd, buf, count);
}