blob: 02f2ff81219f56eb24bc612131d2c34177d7550f [file] [log] [blame]
# 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.
# Test that the GDB-internal TLS link map to module id mapping code
# works correctly when debugging a program which is linked against
# shared objects and which also loads and unloads other shared objects
# in different orders. For targets which have GDB-internal TLS
# support, it'll check both GDB-internal TLS support as well as that
# provided by a helper library such as libthread_db.
source $srcdir/$subdir/tls-common.exp.tcl
require allow_shlib_tests
standard_testfile
set libsrc "${srcdir}/${subdir}/${testfile}-lib.c"
# These will be dlopen'd:
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"]
set lib4obj [standard_output_file "${testfile}4-lib.so"]
# These will be dynamically linked with the main program:
set lib10obj [standard_output_file "${testfile}10-lib.so"]
set lib11obj [standard_output_file "${testfile}11-lib.so"]
# Due to problems with some versions of glibc, we expect some tests to
# fail due to TLS storage not being allocated/initialized. Test
# command CMD using regular expression RE, and use XFAIL instead of
# FAIL when the relevant RE is matched and COND is true when evaluated
# in the upper level.
proc gdb_test_with_xfail { cmd re cond} {
gdb_test_multiple $cmd $cmd {
-re -wrap $re {
pass $gdb_test_name
}
-re -wrap "The inferior has not yet allocated storage for thread-local variables.*" {
if [ uplevel 1 [list expr $cond]] {
xfail $gdb_test_name
} else {
fail $gdb_test_name
}
}
}
}
proc do_tests {force_internal_tls} {
clean_restart $::binfile
if ![runto_main] {
return
}
if $force_internal_tls {
gdb_test_no_output "maint set force-internal-tls-address-lookup on"
}
gdb_breakpoint [gdb_get_line_number "main-breakpoint-1"]
gdb_continue_to_breakpoint "main-breakpoint-1"
with_test_prefix "before assignments" {
gdb_test "print tls_main_tbss_1" ".* = 0"
gdb_test "print tls_main_tbss_2" ".* = 0"
gdb_test "print tls_main_tdata_1" ".* = 96"
gdb_test "print tls_main_tdata_2" ".* = 97"
# For these tests, where we're attempting to access TLS vars
# in a dlopen'd library, but before assignment to any of the
# vars, so it could happen that storage hasn't been allocated
# yet. But it might also work. (When testing against MUSL,
# things just work; GLIBC ends to produce the TLS error.) So
# accept either the right answer or a TLS error message.
set tlserr "The inferior has not yet allocated storage for thread-local variables.*"
foreach n {1 2 3 4} {
gdb_test "print tls_lib${n}_tbss_1" \
"0|${tlserr}"
gdb_test "print tls_lib${n}_tbss_2" \
"0|${tlserr}"
gdb_test "print tls_lib${n}_tdata_1" \
"96|${tlserr}"
gdb_test "print tls_lib${n}_tdata_2" \
"97|${tlserr}"
}
foreach n {10 11} {
gdb_test "print tls_lib${n}_tbss_1" ".* = 0"
gdb_test "print tls_lib${n}_tbss_2" ".* = 0"
gdb_test "print tls_lib${n}_tdata_1" ".* = ${n}96"
gdb_test "print tls_lib${n}_tdata_2" ".* = ${n}97"
}
}
gdb_breakpoint [gdb_get_line_number "main-breakpoint-2"]
gdb_continue_to_breakpoint "main-breakpoint-2"
with_test_prefix "at main-breakpoint-2" {
gdb_test "print tls_main_tbss_1" ".* = 11"
gdb_test "print tls_main_tbss_2" ".* = 12"
gdb_test "print tls_main_tdata_1" ".* = 13"
gdb_test "print tls_main_tdata_2" ".* = 14"
foreach n {1 2 3 4 10 11} {
gdb_test "print tls_lib${n}_tbss_1" ".* = ${n}11"
gdb_test "print tls_lib${n}_tbss_2" ".* = ${n}12"
gdb_test "print tls_lib${n}_tdata_1" ".* = ${n}13"
gdb_test "print tls_lib${n}_tdata_2" ".* = ${n}14"
}
}
gdb_breakpoint [gdb_get_line_number "main-breakpoint-3"]
gdb_continue_to_breakpoint "main-breakpoint-3"
# At this point lib2 and lib3 have been unloaded. Also, TLS vars
# in remaining libraries have been changed.
with_test_prefix "at main-breakpoint-3" {
gdb_test "print tls_main_tbss_1" ".* = 21"
gdb_test "print tls_main_tbss_2" ".* = 22"
gdb_test "print tls_main_tdata_1" ".* = 23"
gdb_test "print tls_main_tdata_2" ".* = 24"
foreach n {1 4 10 11} {
gdb_test "print tls_lib${n}_tbss_1" ".* = ${n}21"
gdb_test "print tls_lib${n}_tbss_2" ".* = ${n}22"
gdb_test "print tls_lib${n}_tdata_1" ".* = ${n}23"
gdb_test "print tls_lib${n}_tdata_2" ".* = ${n}24"
}
}
gdb_breakpoint [gdb_get_line_number "main-breakpoint-4"]
gdb_continue_to_breakpoint "main-breakpoint-4"
# lib3 has been loaded again; lib2 is the only one not loaded.
with_test_prefix "at main-breakpoint-4" {
gdb_test "print tls_main_tbss_1" ".* = 31"
gdb_test "print tls_main_tbss_2" ".* = 32"
gdb_test "print tls_main_tdata_1" ".* = 33"
gdb_test "print tls_main_tdata_2" ".* = 34"
set cond { $n == 3 }
foreach n {1 3 4 10 11} {
gdb_test_with_xfail "print tls_lib${n}_tbss_1" ".* = ${n}31" $cond
gdb_test_with_xfail "print tls_lib${n}_tbss_2" ".* = ${n}32" $cond
gdb_test_with_xfail "print tls_lib${n}_tdata_1" ".* = ${n}33" $cond
gdb_test_with_xfail "print tls_lib${n}_tdata_2" ".* = ${n}34" $cond
}
}
gdb_breakpoint [gdb_get_line_number "main-breakpoint-5"]
gdb_continue_to_breakpoint "main-breakpoint-5"
# lib2 and lib3 are loaded; lib1 and lib4 are not.
with_test_prefix "at main-breakpoint-5" {
gdb_test "print tls_main_tbss_1" ".* = 41"
gdb_test "print tls_main_tbss_2" ".* = 42"
gdb_test "print tls_main_tdata_1" ".* = 43"
gdb_test "print tls_main_tdata_2" ".* = 44"
set cond { $n == 2 || $n == 3 }
foreach n {2 3 10 11} {
gdb_test_with_xfail "print tls_lib${n}_tbss_1" ".* = ${n}41" $cond
gdb_test_with_xfail "print tls_lib${n}_tbss_2" ".* = ${n}42" $cond
gdb_test_with_xfail "print tls_lib${n}_tdata_1" ".* = ${n}43" $cond
gdb_test_with_xfail "print tls_lib${n}_tdata_2" ".* = ${n}44" $cond
}
}
gdb_breakpoint [gdb_get_line_number "main-breakpoint-6"]
gdb_continue_to_breakpoint "main-breakpoint-6"
# lib1, lib3 and lib4 are loaded; lib2 is not loaded.
with_test_prefix "at main-breakpoint-6" {
gdb_test "print tls_main_tbss_1" ".* = 51"
gdb_test "print tls_main_tbss_2" ".* = 52"
gdb_test "print tls_main_tdata_1" ".* = 53"
gdb_test "print tls_main_tdata_2" ".* = 54"
set cond { $n == 1 || $n == 3 || $n == 4}
foreach n {1 3 4 10 11} {
gdb_test_with_xfail "print tls_lib${n}_tbss_1" ".* = ${n}51" $cond
gdb_test_with_xfail "print tls_lib${n}_tbss_2" ".* = ${n}52" $cond
gdb_test_with_xfail "print tls_lib${n}_tdata_1" ".* = ${n}53" $cond
gdb_test_with_xfail "print tls_lib${n}_tdata_2" ".* = ${n}54" $cond
}
}
gdb_breakpoint [gdb_get_line_number "main-breakpoint-7"]
gdb_continue_to_breakpoint "main-breakpoint-7"
# lib2 and lib3 are loaded; lib1 and lib4 are not.
with_test_prefix "at main-breakpoint-7" {
gdb_test "print tls_main_tbss_1" ".* = 61"
gdb_test "print tls_main_tbss_2" ".* = 62"
gdb_test "print tls_main_tdata_1" ".* = 63"
gdb_test "print tls_main_tdata_2" ".* = 64"
set cond { $n == 2 || $n == 3 }
foreach n {2 3 10 11} {
gdb_test_with_xfail "print tls_lib${n}_tbss_1" ".* = ${n}61" $cond
gdb_test_with_xfail "print tls_lib${n}_tbss_2" ".* = ${n}62" $cond
gdb_test_with_xfail "print tls_lib${n}_tdata_1" ".* = ${n}63" $cond
gdb_test_with_xfail "print tls_lib${n}_tdata_2" ".* = ${n}64" $cond
}
}
gdb_breakpoint [gdb_get_line_number "main-breakpoint-8"]
gdb_continue_to_breakpoint "main-breakpoint-8"
# lib1, lib2, lib3, and lib4 are all loaded.
with_test_prefix "at main-breakpoint-8" {
gdb_test "print tls_main_tbss_1" ".* = 71"
gdb_test "print tls_main_tbss_2" ".* = 72"
gdb_test "print tls_main_tdata_1" ".* = 73"
gdb_test "print tls_main_tdata_2" ".* = 74"
foreach n {1 2 3 4 10 11} {
gdb_test "print tls_lib${n}_tbss_1" ".* = ${n}71"
gdb_test "print tls_lib${n}_tbss_2" ".* = ${n}72"
gdb_test "print tls_lib${n}_tdata_1" ".* = ${n}73"
gdb_test "print tls_lib${n}_tdata_2" ".* = ${n}74"
}
}
gdb_breakpoint [gdb_get_line_number "main-breakpoint-9"]
gdb_continue_to_breakpoint "main-breakpoint-9"
# lib2 is loaded; lib1, lib3, and lib4 are not.
with_test_prefix "at main-breakpoint-9" {
gdb_test "print tls_main_tbss_1" ".* = 81"
gdb_test "print tls_main_tbss_2" ".* = 82"
gdb_test "print tls_main_tdata_1" ".* = 83"
gdb_test "print tls_main_tdata_2" ".* = 84"
foreach n {2 10 11} {
gdb_test "print tls_lib${n}_tbss_1" ".* = ${n}81"
gdb_test "print tls_lib${n}_tbss_2" ".* = ${n}82"
gdb_test "print tls_lib${n}_tdata_1" ".* = ${n}83"
gdb_test "print tls_lib${n}_tdata_2" ".* = ${n}84"
}
}
gdb_breakpoint [gdb_get_line_number "main-breakpoint-10"]
gdb_continue_to_breakpoint "main-breakpoint-10"
# lib3 and lib4 are loaded; lib1 and lib2 are not.
with_test_prefix "at main-breakpoint-10" {
gdb_test "print tls_main_tbss_1" ".* = 91"
gdb_test "print tls_main_tbss_2" ".* = 92"
gdb_test "print tls_main_tdata_1" ".* = 93"
gdb_test "print tls_main_tdata_2" ".* = 94"
set cond { $n == 3 || $n == 4 }
foreach n {3 4 10 11} {
gdb_test_with_xfail "print tls_lib${n}_tbss_1" ".* = ${n}91" $cond
gdb_test_with_xfail "print tls_lib${n}_tbss_2" ".* = ${n}92" $cond
gdb_test_with_xfail "print tls_lib${n}_tdata_1" ".* = ${n}93" $cond
gdb_test_with_xfail "print tls_lib${n}_tdata_2" ".* = ${n}94" $cond
}
}
# gdb_interact
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 "print tls_main_tbss_1" ".* = 91"
gdb_test "print tls_main_tbss_2" ".* = 92"
gdb_test "print tls_main_tdata_1" ".* = 93"
gdb_test "print tls_main_tdata_2" ".* = 94"
set cond { $n == 3 || $n == 4 }
foreach n {3 4 10 11} {
gdb_test_with_xfail "print tls_lib${n}_tbss_1" ".* = ${n}91" $cond
gdb_test_with_xfail "print tls_lib${n}_tbss_2" ".* = ${n}92" $cond
gdb_test_with_xfail "print tls_lib${n}_tdata_1" ".* = ${n}93" $cond
gdb_test_with_xfail "print tls_lib${n}_tdata_2" ".* = ${n}94" $cond
}
}
}
# Build shared objects for dlopen:
if { [gdb_compile_shlib $libsrc $lib1obj [list debug additional_flags=-DN=1]] != "" } {
untested "failed to compile shared object"
return -1
}
if { [gdb_compile_shlib $libsrc $lib2obj [list debug additional_flags=-DN=2]] != "" } {
untested "failed to compile shared object"
return -1
}
if { [gdb_compile_shlib $libsrc $lib3obj [list debug additional_flags=-DN=3]] != "" } {
untested "failed to compile shared object"
return -1
}
if { [gdb_compile_shlib $libsrc $lib4obj [list debug additional_flags=-DN=4]] != "" } {
untested "failed to compile shared object"
return -1
}
# Build shared objects to link against main program:
if { [gdb_compile_shlib $libsrc $lib10obj [list debug additional_flags=-DN=10]] != "" } {
untested "failed to compile shared object"
return -1
}
if { [gdb_compile_shlib $libsrc $lib11obj [list debug additional_flags=-DN=11]] != "" } {
untested "failed to compile shared object"
return -1
}
# Use gdb_compile_pthreads to build and link the main program for
# testing. It's also possible to run the tests using plain old
# gdb_compile, but this adds complexity with setting up additional
# KFAILs. (When run using GLIBC versions earlier than 2.34, a program
# that's not dynamically linked against libpthread will lack a working
# libthread_db, and, therefore, won't be able to access thread local
# storage without GDB-internal TLS support. Additional complications
# arise from when testing on x86_64 with -m32, which tends to work
# okay on GLIBC 2.34 and newer, but not older versions. It gets messy
# to properly sort out all of these cases.)
#
# This test was originally written to do it both ways, i.e. with both
# both gdb_compile and gdb_compile_pthreads, but the point of this
# test is to check that the link map address to TLS module id mapping
# code works correctly in programs which use lots of dlopen and
# dlclose calls in various orders - and that can be done using just
# gdb_compile_pthreads.
if { [gdb_compile_pthreads "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable \
[list debug shlib_load \
shlib=${lib10obj} \
shlib=${lib11obj} \
additional_flags=-DOBJ1=\"${lib1obj}\" \
additional_flags=-DOBJ2=\"${lib2obj}\" \
additional_flags=-DOBJ3=\"${lib3obj}\" \
additional_flags=-DOBJ4=\"${lib4obj}\" \
]] != "" } {
untested "failed to compile"
} else {
foreach_with_prefix force_internal_tls $internal_tls_iters {
do_tests $force_internal_tls
}
}