public inbox for gdb-cvs@sourceware.org
help / color / mirror / Atom feed
* [binutils-gdb] [gdb/testsuite] New test: gdb.base/errno.exp
@ 2024-05-31 21:38 Kevin Buettner
  0 siblings, 0 replies; only message in thread
From: Kevin Buettner @ 2024-05-31 21:38 UTC (permalink / raw)
  To: gdb-cvs

https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=7f34450b75b6c4f63565aa06857aa3c824094e4b

commit 7f34450b75b6c4f63565aa06857aa3c824094e4b
Author: Kevin Buettner <kevinb@redhat.com>
Date:   Wed May 1 18:37:58 2024 -0700

    [gdb/testsuite] New test: gdb.base/errno.exp
    
    Printing the value of 'errno' from GDB is sometimes problematic.  The
    situation has improved in recent years, though there are still
    scenarios for which "print errno" doesn't work.
    
    The test, gdb.base/errno.exp, introduced by this commit, tests whether
    or not GDB can print errno using a binary compiled in the following
    different ways:
    
    - default: no switches aside from -g (and whatever else is added by the
      testing framework)
    - macros: macro info is included in the debuginfo; this is enabled by
      using -g3 when using gcc or clang
    - static: statically linked binary
    - static-macros: statically linked binary w/ macro definitions included
      in debuginfo
    - pthreads: libpthread linked binary
    - pthreads-macros: libpthread linked binary w/ macro definitions included
      in debuginfo
    - pthreads-static: Statically linked against libpthread
    - pthreads-static-macros: Statically linked against libpthread w/ macro
      definitions
    
    For each of these, the test also creates a corefile, then loads the
    corefile and attempts to print errno again.
    
    Additionally, the test checks that a "masking" errno declared as a
    local variable will print correctly.
    
    On Linux, if the machine is missing glibc debuginfo (or you have
    debuginfod disabled), it's likely you'll see:
    
        (gdb) print errno
        'errno' has unknown type; cast it to its declared type
    
    But if you add a cast, the value of errno is often available:
    
        (gdb) print (int) errno
        $1 = 42
    
    The test detects this situation along with several others and does
    'setup_xfail' for tests that will almost certainly fail.  It could be
    argued that some of these ought to be KFAILs due to deficiencies in
    GDB, but I'm not entirely certain which, if any, are fixable yet.
    
    On Fedora 39, without glibc debuginfo, there are no failures, but
    I do see the following XFAILS:
    
    XFAIL: gdb.base/errno.exp: default: print errno
    XFAIL: gdb.base/errno.exp: default: check errno value from corefile
    XFAIL: gdb.base/errno.exp: macros: print errno
    XFAIL: gdb.base/errno.exp: macros: print (int) errno
    XFAIL: gdb.base/errno.exp: macros: check errno value from corefile
    XFAIL: gdb.base/errno.exp: static: print errno
    XFAIL: gdb.base/errno.exp: static: print (int) errno
    XFAIL: gdb.base/errno.exp: static: check errno value from corefile
    XFAIL: gdb.base/errno.exp: static-macros: print errno
    XFAIL: gdb.base/errno.exp: static-macros: print (int) errno
    XFAIL: gdb.base/errno.exp: static-macros: check errno value from corefile
    XFAIL: gdb.base/errno.exp: pthreads: print errno
    XFAIL: gdb.base/errno.exp: pthreads: check errno value from corefile
    XFAIL: gdb.base/errno.exp: pthreads-macros: print errno
    XFAIL: gdb.base/errno.exp: pthreads-macros: print (int) errno
    XFAIL: gdb.base/errno.exp: pthreads-macros: check errno value from corefile
    XFAIL: gdb.base/errno.exp: pthreads-static: print errno
    XFAIL: gdb.base/errno.exp: pthreads-static: print (int) errno
    XFAIL: gdb.base/errno.exp: pthreads-static: check errno value from corefile
    XFAIL: gdb.base/errno.exp: pthreads-static-macros: print errno
    XFAIL: gdb.base/errno.exp: pthreads-static-macros: print (int) errno
    XFAIL: gdb.base/errno.exp: pthreads-static-macros: check errno value from corefile
    
    On Fedora 39, with glibc debug info, but without libc.a (for static
    linking), there are 2 XFAILs, 2 UNSUPPORTED tests, and 4 UNTESTED
    tests.
    
    So, even when testing in less than ideal conditions, either due to lack
    of glibc debuginfo or lack of a libc to link against to make a static
    binary, there are no failures.
    
    With glibc debuginfo installed, on Fedora 38, Fedora 39, Fedora 40,
    Fedora rawhide (41), and Ubuntu 22.04.1 LTS, I see these XFAILs:
    
    XFAIL: gdb.base/errno.exp: macros: check errno value from corefile
    XFAIL: gdb.base/errno.exp: static: print errno
    XFAIL: gdb.base/errno.exp: static: print (int) errno
    XFAIL: gdb.base/errno.exp: static: check errno value from corefile
    XFAIL: gdb.base/errno.exp: static-macros: print errno
    XFAIL: gdb.base/errno.exp: static-macros: print (int) errno
    XFAIL: gdb.base/errno.exp: static-macros: check errno value from corefile
    XFAIL: gdb.base/errno.exp: pthreads-macros: check errno value from corefile
    XFAIL: gdb.base/errno.exp: pthreads-static: print errno
    XFAIL: gdb.base/errno.exp: pthreads-static: print (int) errno
    XFAIL: gdb.base/errno.exp: pthreads-static: check errno value from corefile
    XFAIL: gdb.base/errno.exp: pthreads-static-macros: print errno
    XFAIL: gdb.base/errno.exp: pthreads-static-macros: print (int) errno
    XFAIL: gdb.base/errno.exp: pthreads-static-macros: check errno value from corefile
    
    On FreeBSD 13.1, the total number of XFAILs are fewer, and could be
    even better still if it had debug info for glibc:
    
    XFAIL: gdb.base/errno.exp: default: print errno
    XFAIL: gdb.base/errno.exp: default: check errno value from corefile
    XFAIL: gdb.base/errno.exp: macros: print errno
    XFAIL: gdb.base/errno.exp: macros: print (int) errno
    XFAIL: gdb.base/errno.exp: macros: check errno value from corefile
    XFAIL: gdb.base/errno.exp: static-macros: check errno value from corefile
    XFAIL: gdb.base/errno.exp: pthreads: print errno
    XFAIL: gdb.base/errno.exp: pthreads: check errno value from corefile
    XFAIL: gdb.base/errno.exp: pthreads-macros: print errno
    XFAIL: gdb.base/errno.exp: pthreads-macros: print (int) errno
    XFAIL: gdb.base/errno.exp: pthreads-macros: check errno value from corefile
    XFAIL: gdb.base/errno.exp: pthreads-static-macros: check errno value from corefile
    
    Starting with glibc-2.34, most of the pthreads library has been
    incorporated into libc, so finding thread-local variables using
    libthread_db is possible for several scenarios in which it previously
    wasn't.  But, prior to this, accessing errno for the default scenario
    was a problem.  This is borne out by running this new test on Fedora
    34, which uses glibc-2.33:
    
    XFAIL: gdb.base/errno.exp: default: print errno
    XFAIL: gdb.base/errno.exp: default: print (int) errno
    XFAIL: gdb.base/errno.exp: default: check errno value from corefile
    XFAIL: gdb.base/errno.exp: macros: check errno value from corefile
    XFAIL: gdb.base/errno.exp: static: print errno
    XFAIL: gdb.base/errno.exp: static: print (int) errno
    XFAIL: gdb.base/errno.exp: static: check errno value from corefile
    XFAIL: gdb.base/errno.exp: static-macros: print errno
    XFAIL: gdb.base/errno.exp: static-macros: print (int) errno
    XFAIL: gdb.base/errno.exp: static-macros: check errno value from corefile
    XFAIL: gdb.base/errno.exp: pthreads-macros: check errno value from corefile
    XFAIL: gdb.base/errno.exp: pthreads-static: print errno
    XFAIL: gdb.base/errno.exp: pthreads-static: check errno value from corefile
    XFAIL: gdb.base/errno.exp: pthreads-static-macros: print errno
    XFAIL: gdb.base/errno.exp: pthreads-static-macros: print (int) errno
    XFAIL: gdb.base/errno.exp: pthreads-static-macros: check errno value from corefile
    
    In the v3 version of this test, Tom de Vries tested on openSUSE Leap
    15.5 and found a number of cases which showed a FAIL instead of an
    XFAIL.  The v4 version of this test fixed those problems.  On Leap
    15.5, which uses glibc-2.31, with glibc debug info, I now see:
    
    XFAIL: gdb.base/errno.exp: default: print errno
    XFAIL: gdb.base/errno.exp: default: print (int) errno
    XFAIL: gdb.base/errno.exp: default: check errno value from corefile
    XFAIL: gdb.base/errno.exp: macros: check errno value from corefile
    XFAIL: gdb.base/errno.exp: static: print errno
    XFAIL: gdb.base/errno.exp: static: print (int) errno
    XFAIL: gdb.base/errno.exp: static: check errno value from corefile
    XFAIL: gdb.base/errno.exp: static-macros: check errno value from corefile
    XFAIL: gdb.base/errno.exp: pthreads-macros: check errno value from corefile
    XFAIL: gdb.base/errno.exp: pthreads-static: print errno
    XFAIL: gdb.base/errno.exp: pthreads-static: print (int) errno
    XFAIL: gdb.base/errno.exp: pthreads-static: check errno value from corefile
    XFAIL: gdb.base/errno.exp: pthreads-static-macros: check errno value from corefile
    
    On Leap 15.5, with glibc debuginfo missing, the results are a little
    worse:
    
    XFAIL: gdb.base/errno.exp: default: print errno
    XFAIL: gdb.base/errno.exp: default: print (int) errno
    XFAIL: gdb.base/errno.exp: default: check errno value from corefile
    XFAIL: gdb.base/errno.exp: macros: print errno
    XFAIL: gdb.base/errno.exp: macros: print (int) errno
    XFAIL: gdb.base/errno.exp: macros: check errno value from corefile
    XFAIL: gdb.base/errno.exp: static: print errno
    XFAIL: gdb.base/errno.exp: static: print (int) errno
    XFAIL: gdb.base/errno.exp: static: check errno value from corefile
    XFAIL: gdb.base/errno.exp: static-macros: check errno value from corefile
    XFAIL: gdb.base/errno.exp: pthreads: print errno
    XFAIL: gdb.base/errno.exp: pthreads: check errno value from corefile
    XFAIL: gdb.base/errno.exp: pthreads-macros: print errno
    XFAIL: gdb.base/errno.exp: pthreads-macros: print (int) errno
    XFAIL: gdb.base/errno.exp: pthreads-macros: check errno value from corefile
    XFAIL: gdb.base/errno.exp: pthreads-static: print errno
    XFAIL: gdb.base/errno.exp: pthreads-static: print (int) errno
    XFAIL: gdb.base/errno.exp: pthreads-static: check errno value from corefile
    XFAIL: gdb.base/errno.exp: pthreads-static-macros: check errno value from corefile
    
    The v5 version of this test fixed failures when testing with
    check-read1.  (Thanks to Linaro CI for finding these.)  I revised the
    regular expressions being used so that the failures were eliminated,
    but the results mentioned above have not changed.
    
    The v6 version of this test fixes some nits pointed out by both Tom
    de Vries and Pedro Alves.  One of Pedro's suggestions was to rename the
    test from check-errno.exp to errno.exp, so in v5, the name has
    changed.  Tom also noticed that there were failures when using
    --target_board=native-extended-gdbserver.  For v6, I've tested on 10
    different Linux machines (F38, F39, F39 w/o glibc debuginfo, F39 w/o
    static glibc, F40, rawhide, Ubuntu 22.04, Leap 15.5, Leap 15.5 w/o
    glibc debuginfo, and Fedora 34) using "make check" and "make check-read1"
    using target boards "unix", "native-extended-gdbserver", and
    "native-gdbserver", with CC_FOR_TARGET set to both gcc and clang, for
    a total of 12 distinct test runs on each machine.  I've also tested the
    native-only cases on FreeBSD.  (Attempting to test against gdbserver
    on FreeBSD resulted in hangs while running the test suite.)
    
    The v7 version of this test simplifies the REs used in the uses of
    gdb_test_multiple by adding -wrap and removing parts of the REs which
    match the GDB prompt.  In cases where there was a leading '.*', those
    were removed too.  Thanks to Pedro for explaining how to use -wrap.
    
    So, bottom line, this test does not introduce any new failures on the
    platforms on which I've tested, but the XFAILs are certainly unfortunate.
    Some aren't fixable - e.g. when attempting to make a function call while
    debugging a core file - but I think that some of them are.  I'm using
    this new test case as a starting point for investigating problems with
    printing errno.
    
    Co-Authored-By: Jan Kratochvil
    Approved-By: Tom de Vries <tdevries@suse.de>

Diff:
---
 gdb/testsuite/gdb.base/errno.c   |  37 ++++++
 gdb/testsuite/gdb.base/errno.exp | 263 +++++++++++++++++++++++++++++++++++++++
 2 files changed, 300 insertions(+)

diff --git a/gdb/testsuite/gdb.base/errno.c b/gdb/testsuite/gdb.base/errno.c
new file mode 100644
index 00000000000..c6835a866e8
--- /dev/null
+++ b/gdb/testsuite/gdb.base/errno.c
@@ -0,0 +1,37 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+   Copyright 2024 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/>.  */
+
+#include <errno.h>
+
+static void shadow_errno ();
+
+int main ()
+{
+  errno = 42;
+
+  shadow_errno ();	/* main-breakpoint */
+  return 0;
+}
+
+#undef errno
+static void
+shadow_errno ()
+{
+  int errno = 36;
+
+  return;		/* shadow_errno-breakpoint */
+}
diff --git a/gdb/testsuite/gdb.base/errno.exp b/gdb/testsuite/gdb.base/errno.exp
new file mode 100644
index 00000000000..262176e6c36
--- /dev/null
+++ b/gdb/testsuite/gdb.base/errno.exp
@@ -0,0 +1,263 @@
+# Copyright 2024 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.
+
+# Check that errno can be accessed by GDB under a variety of
+# circumstances.
+#
+# The challenge with GDB accessing errno is that, on modern systems,
+# errno is a variable in thread-local storage.  So, if GDB's access to
+# thread local storage is broken or unavailable, some of these tests
+# could fail.  On Linux, this is/was known to happen on systems with
+# older versions of glibc as well as when debugging statically linked
+# binaries.
+#
+# Another possibility is that the environment lacks sufficient
+# type information to print errno.  This can happen for the errno
+# variable itself or when the debuginfo contains a macro for errno
+# which refers to a function lacking type information.
+#
+# When debugging core files, access to errno might not be possible
+# both due to the situations described earlier along with the fact
+# that inferior function calls are not possible (for the cases in
+# which errno is a macro which calls a function returning errno's
+# address).
+#
+# It's also possible for a program to declare errno in an inner scope
+# causing the thread-local errno to be shadowed.  GDB should still
+# correctly print the masking errno for this case.
+#
+# At the time that this test was written, on GNU/Linux and on FreeBSD,
+# there were always scenarios in which printing errno was problematic.
+# This test attempts to identify the problem cases and set up xfails
+# for them.  So, hopefully, there should be no actual failures.  But
+# the "expected" failures encountered by running this test do
+# genuinely illustrate problems that a user might encounter while
+# attempting to print errno.
+
+standard_testfile
+
+proc do_tests {{do_xfail_cast 0} {do_xfail 0} {do_xfail_core_test 0}} {
+    clean_restart $::binfile
+    if ![runto_main] {
+	return
+    }
+
+    gdb_breakpoint [gdb_get_line_number "main-breakpoint"]
+    gdb_continue_to_breakpoint "main-breakpoint"
+
+    # Whether or not "print errno" will work often depends on the
+    # debuginfo available.  We can make some inferences about whether
+    # some of the tests should have xfail set-up by looking at the
+    # output of "ptype errno".  This test is set up to always pass
+    # even for less than ideal outputs, because the point is to set up
+    # the xfail(s).
+    gdb_test_multiple "ptype errno" "check errno type availability" {
+	-re -wrap "type = int" {
+	    pass $gdb_test_name
+	}
+	-re -wrap "type = .*no debug info.*" {
+	    pass $gdb_test_name
+	    set do_xfail 1
+	    set do_xfail_core_test 1
+	}
+	-re -wrap "Cannot find thread-local variables on this target.*" {
+	    pass $gdb_test_name
+	    set do_xfail 1
+	    set do_xfail_core_test 1
+	    set do_xfail_cast 1
+	}
+	-re -wrap "Cannot find thread-local storage.*" {
+	    pass $gdb_test_name
+	    set do_xfail 1
+	    set do_xfail_core_test 1
+	    set do_xfail_cast 1
+	}
+	-re -wrap "has unknown return type; cast the call to its declared return type.*" {
+
+	    # On systems which glibc as the C library, using -g3,
+	    # which causes macro information to be included in the
+	    # debuginfo, errno might be defined as follows:
+	    #
+	    #   #define errno (*__errno_location ())
+	    #
+	    # So, when we do "ptype errno", due to macro expansion,
+	    # this ends up being "ptype (*__errno_location ())".  So
+	    # the call to __errno_location (or something similar on
+	    # other OSes) is the call mentioned in the error message.
+
+	    pass $gdb_test_name
+	    set do_xfail 1
+	    set do_xfail_core_test 1
+	    set do_xfail_cast 1
+	}
+    }
+
+    # If errno is defined as a macro that contains an obvious function
+    # call, it won't work when debugging a core file.
+    gdb_test_multiple "info macro errno" "check if errno is a macro" {
+	-re -wrap "Defined at.*\[\r\n\]#define.*\\\(\\\).*" {
+	    set do_xfail_core_test 1
+	    pass $gdb_test_name
+	}
+	-re -wrap "Defined at.*\[\r\n\]#define.*" {
+	    pass $gdb_test_name
+	}
+	-re -wrap "The symbol .errno. has no definition.*" {
+	    pass $gdb_test_name
+	}
+    }
+
+    # Sometimes, "ptype errno" will ferret out that thread local
+    # variables aren't accessible, but sometimes it won't.  Dig deeper
+    # by trying to access memory using the "x/d" command.  Again, the
+    # point here is to set up an xfail for the later tests, so we pass
+    # this test for other known outputs.
+    gdb_test_multiple "x/d &errno" "attempt to access errno memory" {
+	-re -wrap "Cannot find thread-local variables on this target.*" {
+	    pass $gdb_test_name
+	    set do_xfail 1
+	    set do_xfail_core_test 1
+	    set do_xfail_cast 1
+	}
+	-re -wrap "Cannot find thread-local storage.*" {
+	    pass $gdb_test_name
+	    set do_xfail 1
+	    set do_xfail_core_test 1
+	    set do_xfail_cast 1
+	}
+	-re -wrap "has unknown return type; cast the call to its declared return type.*" {
+	    set do_xfail 1
+	    set do_xfail_core_test 1
+	    set do_xfail_cast 1
+	    pass $gdb_test_name
+	}
+	-re -wrap "$::hex.*?:\[\t \]$::decimal" {
+	    pass $gdb_test_name
+	}
+    }
+
+    if $do_xfail {
+	setup_xfail *-*-*
+    }
+    gdb_test "print errno" ".* = 42"
+
+    if $do_xfail_cast {
+	setup_xfail *-*-*
+    }
+    gdb_test "print (int) errno" ".* = 42"
+
+    set corefile ${::binfile}.core
+    set core_supported 0
+    if { ![is_remote host] } {
+	set core_supported [gdb_gcore_cmd $corefile "save corefile"]
+    }
+    # Normally, we'd check core_supported here and return if it's
+    # not, but we'll defer that until after the shadow test.
+
+    gdb_breakpoint [gdb_get_line_number "shadow_errno-breakpoint"]
+    gdb_continue_to_breakpoint "shadow_errno-breakpoint"
+
+    # This test demonstrates why a simple hack to GDB for printing
+    # errno is a bad idea.  (The hack was to intercept the string
+    # "errno" in process_print_command_args() and replace it with
+    # "*(*(int *(*)(void)) __errno_location) ()".)
+    gdb_test "print errno" ".* = 36" "print masking errno"
+
+    # Finish test early if no core file was made.
+    if !$core_supported {
+	return
+    }
+
+    clean_restart $::binfile
+
+    set core_loaded [gdb_core_cmd $corefile "load corefile"]
+    if { $core_loaded == -1 } {
+	return
+    }
+    if $do_xfail_core_test {
+	setup_xfail *-*-*
+    }
+    gdb_test "print errno" ".* = 42" "check errno value from corefile"
+}
+
+set binprefix $binfile
+
+with_test_prefix "default" {
+    set binfile $binprefix-default
+    if  { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {debug}] != "" } {
+	untested "failed to compile"
+    } else {
+	do_tests
+    }
+}
+
+with_test_prefix "macros" {
+    set binfile $binprefix-macros
+    if  { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {debug macros}] != "" } {
+	untested "failed to compile"
+    } else {
+	do_tests
+    }
+}
+
+with_test_prefix "static" {
+    set binfile $binprefix-static
+    if  { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {debug "additional_flags=-static"}] != "" } {
+	untested "failed to compile"
+    } else {
+	do_tests
+    }
+}
+
+with_test_prefix "static-macros" {
+    set binfile $binprefix-static-macros
+    if  { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {debug macros "additional_flags=-static"}] != "" } {
+	untested "failed to compile"
+    } else {
+	do_tests
+    }
+}
+
+with_test_prefix "pthreads" {
+    set binfile $binprefix-pthreads
+    if  { [gdb_compile_pthreads "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {debug}] != "" } {
+	untested "failed to compile"
+    } else {
+	do_tests
+    }
+}
+
+with_test_prefix "pthreads-macros" {
+    set binfile $binprefix-pthreads-macros
+    if  { [gdb_compile_pthreads "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {debug macros}] != "" } {
+	untested "failed to compile"
+    } else {
+	do_tests
+    }
+}
+
+with_test_prefix "pthreads-static" {
+    set binfile $binprefix-pthreads-static
+    if  { [gdb_compile_pthreads "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {debug "additional_flags=-static"}] != "" } {
+	untested "failed to compile"
+    } else {
+	do_tests
+    }
+}
+
+with_test_prefix "pthreads-static-macros" {
+    set binfile $binprefix-pthreads-static-macros
+    if  { [gdb_compile_pthreads "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {debug macros "additional_flags=-static"}] != "" } {
+	untested "failed to compile"
+    } else {
+	do_tests
+    }
+}

^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2024-05-31 21:38 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2024-05-31 21:38 [binutils-gdb] [gdb/testsuite] New test: gdb.base/errno.exp Kevin Buettner

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).