[v6,09/11] New test - gdb.base/tls-multiobj.exp

Message ID 20250404234324.1931302-10-kevinb@redhat.com
State New
Headers
Series GDB-internal TLS support for Linux targets |

Checks

Context Check Description
linaro-tcwg-bot/tcwg_gdb_build--master-aarch64 success Build passed
linaro-tcwg-bot/tcwg_gdb_build--master-arm success Build passed

Commit Message

Kevin Buettner April 4, 2025, 11:37 p.m. UTC
  This test exercises GDB's internal TLS support when both the main
program and several shared libraries have TLS variables.  It also
tests existing (non-internal) TLS support too.

It tests using two compilation scenarios, "default", in which
libpthread is not linked with the program and libraries as well
as one which does use libpthread.

It tests link map address to module id mapping code in GDB
in addition to the ability of GDB to traverse TLS data structures
with several libraries in play.
---
 gdb/testsuite/gdb.base/tls-multiobj.c   |  89 +++++++++
 gdb/testsuite/gdb.base/tls-multiobj.exp | 230 ++++++++++++++++++++++++
 gdb/testsuite/gdb.base/tls-multiobj1.c  |  26 +++
 gdb/testsuite/gdb.base/tls-multiobj2.c  |  26 +++
 gdb/testsuite/gdb.base/tls-multiobj3.c  |  26 +++
 5 files changed, 397 insertions(+)
 create mode 100644 gdb/testsuite/gdb.base/tls-multiobj.c
 create mode 100644 gdb/testsuite/gdb.base/tls-multiobj.exp
 create mode 100644 gdb/testsuite/gdb.base/tls-multiobj1.c
 create mode 100644 gdb/testsuite/gdb.base/tls-multiobj2.c
 create mode 100644 gdb/testsuite/gdb.base/tls-multiobj3.c
  

Patch

diff --git a/gdb/testsuite/gdb.base/tls-multiobj.c b/gdb/testsuite/gdb.base/tls-multiobj.c
new file mode 100644
index 00000000000..10e67da54d8
--- /dev/null
+++ b/gdb/testsuite/gdb.base/tls-multiobj.c
@@ -0,0 +1,89 @@ 
+/* 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/>.  */
+
+__thread int tls_main_tbss_1;
+__thread int tls_main_tbss_2;
+__thread int tls_main_tdata_1 = 96;
+__thread int tls_main_tdata_2 = 97;
+
+extern __thread int tls_lib1_tbss_1;
+extern __thread int tls_lib1_tbss_2;
+extern __thread int tls_lib1_tdata_1;
+extern __thread int tls_lib1_tdata_2;
+
+extern __thread int tls_lib2_tbss_1;
+extern __thread int tls_lib2_tbss_2;
+extern __thread int tls_lib2_tdata_1;
+extern __thread int tls_lib2_tdata_2;
+
+extern __thread int tls_lib3_tbss_1;
+extern __thread int tls_lib3_tbss_2;
+extern __thread int tls_lib3_tdata_1;
+extern __thread int tls_lib3_tdata_2;
+
+extern void lib1_func ();
+extern void lib2_func ();
+extern void lib3_func ();
+
+volatile int data;
+
+void
+use_it (int a)
+{
+  data = a;
+}
+
+int
+main (int argc, char **argv)
+{
+  use_it (-1);
+
+  tls_main_tbss_1 = 51;	/* main-breakpoint-1 */
+  tls_main_tbss_2 = 52;
+  tls_main_tdata_1 = 53;
+  tls_main_tdata_2 = 54;
+
+  tls_lib1_tbss_1 = 151;
+  tls_lib1_tbss_2 = 152;
+  tls_lib1_tdata_1 = 153;
+  tls_lib1_tdata_2 = 154;
+
+  tls_lib2_tbss_1 = 251;
+  tls_lib2_tbss_2 = 252;
+  tls_lib2_tdata_1 = 253;
+  tls_lib2_tdata_2 = 254;
+
+  tls_lib3_tbss_1 = 351;
+  tls_lib3_tbss_2 = 352;
+  tls_lib3_tdata_1 = 353;
+  tls_lib3_tdata_2 = 354;
+
+  lib1_func ();
+  lib2_func ();
+  lib3_func ();
+
+  /* Attempt to keep variables in the main program from being optimized
+     away.  */
+  use_it (tls_main_tbss_1);
+  use_it (tls_main_tbss_2);
+  use_it (tls_main_tdata_1);
+  use_it (tls_main_tdata_2);
+
+  use_it (100);		/* main-breakpoint-2 */
+
+  return 0;
+}
diff --git a/gdb/testsuite/gdb.base/tls-multiobj.exp b/gdb/testsuite/gdb.base/tls-multiobj.exp
new file mode 100644
index 00000000000..a78db1460e9
--- /dev/null
+++ b/gdb/testsuite/gdb.base/tls-multiobj.exp
@@ -0,0 +1,230 @@ 
+# 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.
+
+# Using different compilation/linking scenarios, attempt to access
+# thread-local variables in a non-threaded program using multiple
+# shared objects.
+
+source $srcdir/$subdir/tls-common.exp.tcl
+
+standard_testfile
+
+set lib1src "${srcdir}/${subdir}/${testfile}1.c"
+set lib2src "${srcdir}/${subdir}/${testfile}2.c"
+set lib3src "${srcdir}/${subdir}/${testfile}3.c"
+
+set lib1obj [standard_output_file "${testfile}1-lib.so"]
+set lib2obj [standard_output_file "${testfile}2-lib.so"]
+set lib3obj [standard_output_file "${testfile}3-lib.so"]
+
+proc do_tests {force_internal_tls {do_kfail_tls_access 0}} {
+    clean_restart $::binfile
+    if ![runto_main] {
+	return
+    }
+
+    if $force_internal_tls {
+	gdb_test_no_output "maint set force-internal-tls-address-lookup on"
+    }
+
+    if { $do_kfail_tls_access && [istarget "*-*-linux*"] } {
+	# Turn off do_kfail_tls_access when libthread_db is loaded. 
+	# This can happen for the default case when testing x86_64
+	# w/ -m32 using glibc versions 2.34 or newer.
+	gdb_test_multiple "maint check libthread-db" "Check for loaded libthread_db" {
+	    -re -wrap "libthread_db integrity checks passed." {
+		set do_kfail_tls_access 0
+		pass $gdb_test_name
+	    }
+	    -re -wrap "No libthread_db loaded" {
+		pass $gdb_test_name
+	    }
+	}
+	# Also turn off do_kfail_tls_access when connected to a
+	# gdbserver and we observe that accessing a TLS variable
+	# works.
+	if [target_is_gdbserver] {
+	    gdb_test_multiple "print tls_main_tbss_1" \
+		"Check TLS accessibility when connected to a gdbserver" {
+		-re -wrap "= 0" {
+		    set do_kfail_tls_access 0
+		    pass $gdb_test_name
+		}
+		-re -wrap "Remote target failed to process qGetTLSAddr request" {
+		    pass $gdb_test_name
+		}
+	    }
+	}
+    }
+
+    gdb_breakpoint [gdb_get_line_number "main-breakpoint-1"]
+    gdb_continue_to_breakpoint "main-breakpoint-1"
+
+    set t $do_kfail_tls_access
+    set m "tls not available"
+    with_test_prefix "before assignments" {
+	gdb_test_with_kfail "print tls_main_tbss_1" ".* = 0" $t $m
+	gdb_test_with_kfail "print tls_main_tbss_2" ".* = 0" $t $m
+	gdb_test_with_kfail "print tls_main_tdata_1" ".* = 96" $t $m
+	gdb_test_with_kfail "print tls_main_tdata_2" ".* = 97" $t $m
+
+	gdb_test_with_kfail "print tls_lib1_tbss_1" ".* = 0" $t $m
+	gdb_test_with_kfail "print tls_lib1_tbss_2" ".* = 0" $t $m
+	gdb_test_with_kfail "print tls_lib1_tdata_1" ".* = 196" $t $m
+	gdb_test_with_kfail "print tls_lib1_tdata_2" ".* = 197" $t $m
+
+	gdb_test_with_kfail "print tls_lib2_tbss_1" ".* = 0" $t $m
+	gdb_test_with_kfail "print tls_lib2_tbss_2" ".* = 0" $t $m
+	gdb_test_with_kfail "print tls_lib2_tdata_1" ".* = 296" $t $m
+	gdb_test_with_kfail "print tls_lib2_tdata_2" ".* = 297" $t $m
+
+	gdb_test_with_kfail "print tls_lib3_tbss_1" ".* = 0" $t $m
+	gdb_test_with_kfail "print tls_lib3_tbss_2" ".* = 0" $t $m
+	gdb_test_with_kfail "print tls_lib3_tdata_1" ".* = 396" $t $m
+	gdb_test_with_kfail "print tls_lib3_tdata_2" ".* = 397" $t $m
+    }
+
+    gdb_breakpoint [gdb_get_line_number "main-breakpoint-2"]
+    gdb_continue_to_breakpoint "main-breakpoint-2"
+
+    with_test_prefix "after assignments" {
+	gdb_test_with_kfail "print tls_main_tbss_1" ".* = 51" $t $m
+	gdb_test_with_kfail "print tls_main_tbss_2" ".* = 52" $t $m
+	gdb_test_with_kfail "print tls_main_tdata_1" ".* = 53" $t $m
+	gdb_test_with_kfail "print tls_main_tdata_2" ".* = 54" $t $m
+
+	gdb_test_with_kfail "print tls_lib1_tbss_1" ".* = 151" $t $m
+	gdb_test_with_kfail "print tls_lib1_tbss_2" ".* = 152" $t $m
+	gdb_test_with_kfail "print tls_lib1_tdata_1" ".* = 153" $t $m
+	gdb_test_with_kfail "print tls_lib1_tdata_2" ".* = 154" $t $m
+
+	gdb_test_with_kfail "print tls_lib2_tbss_1" ".* = 251" $t $m
+	gdb_test_with_kfail "print tls_lib2_tbss_2" ".* = 252" $t $m
+	gdb_test_with_kfail "print tls_lib2_tdata_1" ".* = 253" $t $m
+	gdb_test_with_kfail "print tls_lib2_tdata_2" ".* = 254" $t $m
+
+	gdb_test_with_kfail "print tls_lib3_tbss_1" ".* = 351" $t $m
+	gdb_test_with_kfail "print tls_lib3_tbss_2" ".* = 352" $t $m
+	gdb_test_with_kfail "print tls_lib3_tdata_1" ".* = 353" $t $m
+	gdb_test_with_kfail "print tls_lib3_tdata_2" ".* = 354" $t $m
+    }
+
+    set corefile ${::binfile}.core
+    set core_supported 0
+    if { ![is_remote host] } {
+	set core_supported [gdb_gcore_cmd $corefile "save corefile"]
+    }
+
+    # 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
+    }
+
+    with_test_prefix "core file" {
+	if $force_internal_tls {
+	    gdb_test_no_output "maint set force-internal-tls-address-lookup on"
+	}
+
+	gdb_test_with_kfail "print tls_main_tbss_1" ".* = 51" $t $m
+	gdb_test_with_kfail "print tls_main_tbss_2" ".* = 52" $t $m
+	gdb_test_with_kfail "print tls_main_tdata_1" ".* = 53" $t $m
+	gdb_test_with_kfail "print tls_main_tdata_2" ".* = 54" $t $m
+
+	gdb_test_with_kfail "print tls_lib1_tbss_1" ".* = 151" $t $m
+	gdb_test_with_kfail "print tls_lib1_tbss_2" ".* = 152" $t $m
+	gdb_test_with_kfail "print tls_lib1_tdata_1" ".* = 153" $t $m
+	gdb_test_with_kfail "print tls_lib1_tdata_2" ".* = 154" $t $m
+
+	gdb_test_with_kfail "print tls_lib2_tbss_1" ".* = 251" $t $m
+	gdb_test_with_kfail "print tls_lib2_tbss_2" ".* = 252" $t $m
+	gdb_test_with_kfail "print tls_lib2_tdata_1" ".* = 253" $t $m
+	gdb_test_with_kfail "print tls_lib2_tdata_2" ".* = 254" $t $m
+
+	gdb_test_with_kfail "print tls_lib3_tbss_1" ".* = 351" $t $m
+	gdb_test_with_kfail "print tls_lib3_tbss_2" ".* = 352" $t $m
+	gdb_test_with_kfail "print tls_lib3_tdata_1" ".* = 353" $t $m
+	gdb_test_with_kfail "print tls_lib3_tdata_2" ".* = 354" $t $m
+    }
+}
+
+if { [gdb_compile_shlib $lib1src $lib1obj {debug}] != "" } {
+    untested "failed to compile shared object"
+    return -1
+}
+if { [gdb_compile_shlib $lib2src $lib2obj {debug}] != "" } {
+    untested "failed to compile shared object"
+    return -1
+}
+if { [gdb_compile_shlib $lib3src $lib3obj {debug}] != "" } {
+    untested "failed to compile shared object"
+    return -1
+}
+
+# Certain linux target architectures implement support for internal
+# TLS lookup which is used when thread stratum support (via
+# libthread_db) is missing or when the linux-only GDB maintenance
+# setting 'force-internal-tls-address-lookup' is 'on'.  Thus for some
+# of the testing scenarios, such as statically linked executables,
+# this internal support will be used.  Set 'do_kfail_tls_access' to 1
+# for those architectures which don't implement internal tls support.
+if {[istarget *-*-linux*]
+    && ![is_any_target {*}$internal_tls_linux_targets]} {
+    set do_kfail_tls_access 1
+} elseif {[istarget *-*-linux*] && [is_x86_like_target]} {
+    # This covers the case of x86_64 with -m32:
+    set do_kfail_tls_access 1
+} else {
+    set do_kfail_tls_access 0
+}
+
+set binprefix $binfile
+
+with_test_prefix "default" {
+    set binfile $binprefix-default
+    if  { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable \
+                        [list debug shlib=${lib1obj} \
+			            shlib=${lib2obj} \
+				    shlib=${lib3obj}]] != "" } {
+	untested "failed to compile"
+    } else {
+	foreach_with_prefix force_internal_tls $internal_tls_iters {
+	    # Depending on glibc version, it might not be appropriate
+	    # for do_kfail_tls_access to be set here.  That will be
+	    # handled in 'do_tests', disabling it if necessary.
+	    # 
+	    # Specifically, glibc versions 2.34 and later have the
+	    # thread library (and libthread_db availability) in
+	    # programs not linked against libpthread.so
+	    do_tests $force_internal_tls $do_kfail_tls_access
+	}
+    }
+}
+
+with_test_prefix "pthreads" {
+    set binfile $binprefix-pthreads
+    if	{ [gdb_compile_pthreads "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable \
+				 [list debug shlib=${lib1obj} \
+					     shlib=${lib2obj} \
+					     shlib=${lib3obj}]] != "" } {
+	untested "failed to compile"
+    } else {
+	foreach_with_prefix force_internal_tls $internal_tls_iters {
+	    do_tests $force_internal_tls
+	}
+    }
+}
diff --git a/gdb/testsuite/gdb.base/tls-multiobj1.c b/gdb/testsuite/gdb.base/tls-multiobj1.c
new file mode 100644
index 00000000000..86e72228b1b
--- /dev/null
+++ b/gdb/testsuite/gdb.base/tls-multiobj1.c
@@ -0,0 +1,26 @@ 
+/* 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/>.  */
+
+__thread int tls_lib1_tbss_1;
+__thread int tls_lib1_tbss_2;
+__thread int tls_lib1_tdata_1 = 196;
+__thread int tls_lib1_tdata_2 = 197;
+
+void
+lib1_func ()
+{
+}
diff --git a/gdb/testsuite/gdb.base/tls-multiobj2.c b/gdb/testsuite/gdb.base/tls-multiobj2.c
new file mode 100644
index 00000000000..cea07092a5d
--- /dev/null
+++ b/gdb/testsuite/gdb.base/tls-multiobj2.c
@@ -0,0 +1,26 @@ 
+/* 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/>.  */
+
+__thread int tls_lib2_tbss_1;
+__thread int tls_lib2_tbss_2;
+__thread int tls_lib2_tdata_1 = 296;
+__thread int tls_lib2_tdata_2 = 297;
+
+void
+lib2_func ()
+{
+}
diff --git a/gdb/testsuite/gdb.base/tls-multiobj3.c b/gdb/testsuite/gdb.base/tls-multiobj3.c
new file mode 100644
index 00000000000..bb0f2395fbf
--- /dev/null
+++ b/gdb/testsuite/gdb.base/tls-multiobj3.c
@@ -0,0 +1,26 @@ 
+/* 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/>.  */
+
+__thread int tls_lib3_tbss_1;
+__thread int tls_lib3_tbss_2;
+__thread int tls_lib3_tdata_1 = 396;
+__thread int tls_lib3_tdata_2 = 397;
+
+void
+lib3_func ()
+{
+}