>gd_var1 and gd_var2 are initial exec if the compiler chose R_TLS_IE via compiler options otherwise is local dynamic. >gd_var1, gd_var2 are local dynamic. gd_var1 and gd_var2 are global dynamic actually. The local dynamic in both these lines I need to change to global dynamic. I will git amend the same once I get feedback. Just wanted to let you know. From: Aditya Vidyadhar Kamath Date: Thursday, 3 September 2026 at 2:25 PM To: Ulrich Weigand ; simon.marchi@polymtl.ca ; tom@tromey.com Cc: gdb-patches@sourceware.org ; Aditya Kamath ; SANGAMESH MALLAYYA ; Aditya Kamath Subject: [EXTERNAL] [PATCH v1 3/3] Add test cases for all TLS support in AIX From: Aditya Vidyadhar Kamath This patch adds test cases to all the 4 types of TLS variables in a shared library on AIX. which is 1: local-exec 2: initial-exec 3: global-dynamic 4: local-dynamic le_var1 and le_var2 are local-exec in the main executable. gd_var1 and gd_var2 are initial exec if the compiler chose R_TLS_IE via compiler options otherwise is local dynamic. gd_var1, gd_var2 are local dynamic. ld_only_var is local dynamic since it is used in the shared library only and not in main executable. [See: powerpc-aix-tls-main.c] This test prints all of them and checks if we can access them in AIX. When we run this on AIX we get, gmake check RUNTESTFLAGS='gdb.threads/thread_events.exp CC_FOR_TARGET="/opt/freeware/bin/gcc" CXX_FOR_TARGET="/opt/freeware/bin/g++" CXXFLAGS_FOR_TARGET="-O0 -w -g -gdwarf -maix64" CFLAGS_FOR_TARGET="-O0 -w -g -gdwarf -maix64"' Running target unix Using /opt/freeware/share/dejagnu/baseboards/unix.exp as board description file for target. Using /opt/freeware/share/dejagnu/config/unix.exp as generic interface file for target. Using /current_gdb/binutils-gdb/gdb/testsuite/config/unix.exp as tool-and-target-specific interface file. Running /current_gdb/binutils-gdb/gdb/testsuite/gdb.threads/thread_events.exp ... === gdb Summary === # of expected passes 11 /current_gdb/binutils-gdb/gdb/gdb version 19.0.50.20260819-git -nw -nx -q -iex "set height 0" -iex "set width 0" -data-directory /current_gdb/binutils-gdb/gdb/data-directory -iex "set interactive-mode on" --- gdb/testsuite/gdb.arch/powerpc-aix-tls-lib.c | 66 ++++++++ gdb/testsuite/gdb.arch/powerpc-aix-tls-main.c | 69 ++++++++ gdb/testsuite/gdb.arch/powerpc-aix-tls.exp | 147 ++++++++++++++++++ 3 files changed, 282 insertions(+) create mode 100644 gdb/testsuite/gdb.arch/powerpc-aix-tls-lib.c create mode 100644 gdb/testsuite/gdb.arch/powerpc-aix-tls-main.c create mode 100644 gdb/testsuite/gdb.arch/powerpc-aix-tls.exp diff --git a/gdb/testsuite/gdb.arch/powerpc-aix-tls-lib.c b/gdb/testsuite/gdb.arch/powerpc-aix-tls-lib.c new file mode 100644 index 00000000000..3f34d2e570b --- /dev/null +++ b/gdb/testsuite/gdb.arch/powerpc-aix-tls-lib.c @@ -0,0 +1,66 @@ +/* Copyright (C) 2026 Free Software Foundation, Inc. + + This file is part of GDB. + + 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 . */ + +/* Global-dynamic TLS variables exported from this shared library. + The main executable accesses these (R_TLS + R_TLSM relocs), which means + the TOC slots will be emitted in the main executable's .loader section. + Within this library the compiler may use local-dynamic or initial-exec + depending on flags, but the main exe always uses global-dynamic for + cross-module symbols. */ + +/* gd_var1 and gd_var2 are exported TLS variables that the main executable + imports via global-dynamic. They are also accessed here via local-dynamic + so that R_TLS_LD + R_TLSML relocs appear in this library's .loader. */ +__thread int gd_var1 = 10; +__thread int gd_var2 = 20; + +/* ld_only_var is a local-dynamic variable that is ONLY accessed from within + this shared library (never referenced in the main executable). This + exercises the access-dependency limitation: GDB must be able to resolve it + even though there is no R_TLS/R_TLSM slot for it in the main exe's loader + section. */ +__thread int ld_only_var = 30; + +/* Access gd_var1, gd_var2 and ld_only_var from within the library so that + the compiler emits R_TLS_LD / R_TLSML relocs into this .so's .loader + section. Force local-dynamic model explicitly. */ +int +lib_set_tls_vars (int a, int b, int c) +{ + gd_var1 = a; + gd_var2 = b; + ld_only_var = c; + return gd_var1 + gd_var2 + ld_only_var; +} + +int +lib_get_gd_var1 (void) +{ + return gd_var1; +} + +int +lib_get_gd_var2 (void) +{ + return gd_var2; +} + +int +lib_get_ld_only (void) +{ + return ld_only_var; +} diff --git a/gdb/testsuite/gdb.arch/powerpc-aix-tls-main.c b/gdb/testsuite/gdb.arch/powerpc-aix-tls-main.c new file mode 100644 index 00000000000..1a8a5561e71 --- /dev/null +++ b/gdb/testsuite/gdb.arch/powerpc-aix-tls-main.c @@ -0,0 +1,69 @@ +/* Copyright (C) 2026 Free Software Foundation, Inc. + + This file is part of GDB. + + 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 . */ + +/* This test exercises all four XCOFF TLS models on 64-bit AIX: + - local-exec (variables in the main executable, TP-relative offset) + - initial-exec (R_TLS_IE in which the compiler uses this for extern __thread + variables in the main exe when linked without -brtl) + - global-dynamic (R_TLS + R_TLSM in which cross-module access to variables + in a shared library) + - local-dynamic (R_TLS_LD + R_TLSML The within-module access inside the + shared library; also exercises the access-dependency + case for ld_only_var which is never accessed here) */ + +/* local-exec TLS variables: defined in the main executable. */ +__thread int le_var1 = 100; +__thread int le_var2 = 200; + +/* Declaration of TLS variables from the shared library. + The compiler uses global-dynamic model for these cross-module accesses, + emitting R_TLS + R_TLSM pairs in the .loader section. */ +extern __thread int gd_var1; +extern __thread int gd_var2; +/* ld_only_var is intentionally NOT declared here we only look it up via + GDB's symbol lookup to exercise the access-dependency fallback. This + is an edge case. */ + +extern int lib_set_tls_vars (int, int, int); +extern int lib_get_gd_var1 (void); +extern int lib_get_gd_var2 (void); +extern int lib_get_ld_only (void); + +volatile int sink; + +int +main (void) +{ + /* Set local-exec variables to known values. */ + le_var1 = 11; + le_var2 = 22; + + /* Access cross-module globals -- forces R_TLS + R_TLSM into the main + executable's .loader section for gd_var1 and gd_var2. */ + gd_var1 = 33; + gd_var2 = 44; + + /* Call into the library so the library-side TLS is initialised. This + also exercises the local-dynamic model inside the shared library (the + compiler will use R_TLS_LD for within-module accesses to gd_var1, + gd_var2, and ld_only_var inside the .so). */ + lib_set_tls_vars (33, 44, 55); + + sink = le_var1 + le_var2 + gd_var1 + gd_var2; /* breakpoint here */ + + return sink; +} diff --git a/gdb/testsuite/gdb.arch/powerpc-aix-tls.exp b/gdb/testsuite/gdb.arch/powerpc-aix-tls.exp new file mode 100644 index 00000000000..824884dffc9 --- /dev/null +++ b/gdb/testsuite/gdb.arch/powerpc-aix-tls.exp @@ -0,0 +1,147 @@ +# Copyright (C) 2026 Free Software Foundation, Inc. +# +# This file is part of GDB. +# +# 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 . + +# Test GDB TLS variable access on 64-bit AIX (XCOFF) covering all four +# TLS models: +# +# 1. local-exec [le_var1, le_var2 variables defined in the main executable] +# GDB reads the XCOFF symbol value directly as a TP-relative offset. +# +# 2. initial-exec [gd_var1, gd_var2 accessed from the main executable] +# If the compiler chose R_TLS_IE for cross-module accesses +# GDB reads the TOC slot and adds it to TP. +# +# 3. global-dynamic [gd_var1, gd_var2 via R_TLS + R_TLSM] +# GDB reads the module-id from the R_TLSM slot, looks up +# thread_vector[mod_id] to find the TLS block base, and adds the per-variable +# offset from the R_TLS slot. +# +# 4. local-dynamic [ld_only_var which is only accessed from inside the .so of this test case] +# GDB reads the module-id from the R_TLSML slot in the .so, looks +# up thread_vector[mod_id], and adds the within-module offset from R_TLS_LD. +# ld_only_var is never referenced in the main executable, so there +# is no per-variable TOC slot for it in the main executbale; So GDB must use +# the access-dependency fallback path which is rs6000_aix_compute_tls_address (). + +require {istarget "powerpc*-*-aix*"} + +standard_testfile powerpc-aix-tls-main.c +set srcfile_lib powerpc-aix-tls-lib.c +set binfile_lib [standard_output_file powerpc-aix-tls-lib.so] + +# Build shared library +# On AIX with GCC the standard gdb_compile_shlib helper appends +# "-Wl,-soname," which the AIX ld interprets as an input file +# (COFF mismatch error). Instead we do the two-step compile+link +# manually. First compile the .c to a -fPIC .o, then link it to a .so +# with -shared -Wl,-bexpall -lpthread (needed for __tls_get_addr). +set lib_obj [standard_output_file powerpc-aix-tls-lib.c.o] +if { [gdb_compile "${srcdir}/${subdir}/${srcfile_lib}" \ + "${lib_obj}" \ + object \ + {debug additional_flags=-fPIC}] != "" } { + unsupported "failed to compile shared library object" + return +} +if { [gdb_compile "${lib_obj}" \ + "${binfile_lib}" \ + executable \ + {debug additional_flags=-shared \ + additional_flags=-Wl,-bexpall \ + additional_flags=-lpthread}] != "" } { + unsupported "failed to link shared library" + return +} + +# Build main executable linked against the shared library +# Pass the .so directly to gcc; on AIX with GCC the shared lib goes on +# the link command line as a regular file argument. +if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" \ + "${binfile}" \ + executable \ + [list debug \ + additional_flags=${binfile_lib} \ + additional_flags=-lpthread]] != "" } { + unsupported "failed to compile test executable" + return +} + +# Helper: assert that printing VAR_EXPR from the inferior gives EXPECTED. +proc check_tls_var { var_expr expected test_name } { + gdb_test "print $var_expr" "= $expected" $test_name +} + +clean_restart ${testfile} +gdb_load_shlib ${binfile_lib} + +if {![runto_main]} { + return +} + +# Set breakpoint at the labelled line in main. +set bp_line [gdb_get_line_number "breakpoint here" \ + "${srcdir}/${subdir}/${srcfile}"] +gdb_breakpoint $bp_line +gdb_continue_to_breakpoint "run to breakpoint" + +# local-exec testing +# le_var1 and le_var2 are defined in the main executable. At this point +# they have been set to 11 and 22 respectively. +with_test_prefix "local-exec" { + check_tls_var le_var1 11 "le_var1 == 11" + check_tls_var le_var2 22 "le_var2 == 22" + + gdb_test "info address le_var1" \ + "Symbol \"le_var1\" is a thread-local variable.*" \ + "info address le_var1" +} + +# initial-exec / global-dynamic testing +# gd_var1 and gd_var2 are defined in the shared library and accessed +# from the main executable. Depending on the compiler's TLS dialect +# the main exe will use either R_TLS_IE = initial-exec or R_TLS+R_TLSM +# global-dynamic. Both must produce the correct values 33 and 44. +with_test_prefix "gd-from-main" { + check_tls_var gd_var1 33 "gd_var1 == 33" + check_tls_var gd_var2 44 "gd_var2 == 44" + + gdb_test "info address gd_var1" \ + "Symbol \"gd_var1\" is a thread-local variable.*" \ + "info address gd_var1" +} + +# local-dynamic testing +# ld_only_var is accessed solely from within the shared library using +# local-dynamic model R_TLS_LD + R_TLSML. lib_set_tls_vars set it to +# 55. Because ld_only_var is not referenced in the main executable there +# is no per-variable TOC slot for it in the main exe's .loader section; +# The fallback code must be used here which is rs6000_aix_compute_tls_address () +with_test_prefix "local-dynamic" { + check_tls_var ld_only_var 55 "ld_only_var == 55" + + gdb_test "info address ld_only_var" \ + "Symbol \"ld_only_var\" is a thread-local variable.*" \ + "info address ld_only_var" +} + +# Library-side local-dynamic - verify via library accessor +# Cross-check by calling the library function that reads the same variable. +with_test_prefix "lib-accessor" { + gdb_test "print lib_get_gd_var1()" "= 33" "lib_get_gd_var1" + gdb_test "print lib_get_gd_var2()" "= 44" "lib_get_gd_var2" + gdb_test "print lib_get_ld_only()" "= 55" "lib_get_ld_only" +} -- 2.51.2