| /* 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 <dlfcn.h> |
| #include <assert.h> |
| #include <stdlib.h> |
| #include <stdio.h> |
| |
| typedef void (*setter_ftype) (int which, int val); |
| |
| __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 void set_tls_lib10_var (int which, int val); |
| extern void set_tls_lib11_var (int which, int val); |
| |
| volatile int data; |
| |
| static void |
| set_tls_main_var (int which, int val) |
| { |
| switch (which) |
| { |
| case 1: |
| tls_main_tbss_1 = val; |
| break; |
| case 2: |
| tls_main_tbss_2 = val; |
| break; |
| case 3: |
| tls_main_tdata_1 = val; |
| break; |
| case 4: |
| tls_main_tdata_2 = val; |
| break; |
| } |
| } |
| |
| void |
| use_it (int a) |
| { |
| data = a; |
| } |
| |
| static void * |
| load_dso (char *dso_name, int n, setter_ftype *setterp) |
| { |
| char buf[80]; |
| void *sym; |
| void *handle = dlopen (dso_name, RTLD_NOW | RTLD_GLOBAL); |
| if (handle == NULL) |
| { |
| fprintf (stderr, "dlopen of DSO '%s' failed: %s\n", dso_name, dlerror ()); |
| exit (1); |
| } |
| sprintf (buf, "set_tls_lib%d_var", n); |
| sym = dlsym (handle, buf); |
| assert (sym != NULL); |
| *setterp = sym; |
| |
| /* Some libc implementations (for some architectures) refuse to |
| initialize TLS data structures (specifically, the DTV) without |
| first calling dlsym on one of the TLS symbols. */ |
| sprintf (buf, "tls_lib%d_tdata_1", n); |
| assert (dlsym (handle, buf) != NULL); |
| |
| return handle; |
| } |
| |
| int |
| main (int argc, char **argv) |
| { |
| int i, status; |
| setter_ftype s0, s1, s2, s3, s4, s10, s11; |
| void *h1 = load_dso (OBJ1, 1, &s1); |
| void *h2 = load_dso (OBJ2, 2, &s2); |
| void *h3 = load_dso (OBJ3, 3, &s3); |
| void *h4 = load_dso (OBJ4, 4, &s4); |
| s0 = set_tls_main_var; |
| s10 = set_tls_lib10_var; |
| s11 = set_tls_lib11_var; |
| |
| use_it (0); /* main-breakpoint-1 */ |
| |
| /* Set TLS variables in main program and all libraries. */ |
| for (i = 1; i <= 4; i++) |
| s0 (i, 10 + i); |
| for (i = 1; i <= 4; i++) |
| s1 (i, 110 + i); |
| for (i = 1; i <= 4; i++) |
| s2 (i, 210 + i); |
| for (i = 1; i <= 4; i++) |
| s3 (i, 310 + i); |
| for (i = 1; i <= 4; i++) |
| s4 (i, 410 + i); |
| for (i = 1; i <= 4; i++) |
| s10 (i, 1010 + i); |
| for (i = 1; i <= 4; i++) |
| s11 (i, 1110 + i); |
| |
| use_it (0); /* main-breakpoint-2 */ |
| |
| /* Unload lib2 and lib3. */ |
| status = dlclose (h2); |
| assert (status == 0); |
| status = dlclose (h3); |
| assert (status == 0); |
| |
| /* Set TLS variables in main program and in libraries which are still |
| loaded. */ |
| for (i = 1; i <= 4; i++) |
| s0 (i, 20 + i); |
| for (i = 1; i <= 4; i++) |
| s1 (i, 120 + i); |
| for (i = 1; i <= 4; i++) |
| s4 (i, 420 + i); |
| for (i = 1; i <= 4; i++) |
| s10 (i, 1020 + i); |
| for (i = 1; i <= 4; i++) |
| s11 (i, 1120 + i); |
| |
| use_it (0); /* main-breakpoint-3 */ |
| |
| /* Load lib3. */ |
| h3 = load_dso (OBJ3, 3, &s3); |
| |
| /* Set TLS vars again; currently, only lib2 is not loaded. */ |
| for (i = 1; i <= 4; i++) |
| s0 (i, 30 + i); |
| for (i = 1; i <= 4; i++) |
| s1 (i, 130 + i); |
| for (i = 1; i <= 4; i++) |
| s3 (i, 330 + i); |
| for (i = 1; i <= 4; i++) |
| s4 (i, 430 + i); |
| for (i = 1; i <= 4; i++) |
| s10 (i, 1030 + i); |
| for (i = 1; i <= 4; i++) |
| s11 (i, 1130 + i); |
| |
| use_it (0); /* main-breakpoint-4 */ |
| |
| /* Unload lib1 and lib4; load lib2. */ |
| status = dlclose (h1); |
| assert (status == 0); |
| status = dlclose (h4); |
| assert (status == 0); |
| h2 = load_dso (OBJ2, 2, &s2); |
| |
| /* Set TLS vars; currently, lib2 and lib3 are loaded, |
| lib1 and lib4 are not. */ |
| for (i = 1; i <= 4; i++) |
| s0 (i, 40 + i); |
| for (i = 1; i <= 4; i++) |
| s2 (i, 240 + i); |
| for (i = 1; i <= 4; i++) |
| s3 (i, 340 + i); |
| for (i = 1; i <= 4; i++) |
| s10 (i, 1040 + i); |
| for (i = 1; i <= 4; i++) |
| s11 (i, 1140 + i); |
| |
| use_it (0); /* main-breakpoint-5 */ |
| |
| /* Load lib4 and lib1. Unload lib2. */ |
| h4 = load_dso (OBJ4, 4, &s4); |
| h1 = load_dso (OBJ1, 1, &s1); |
| status = dlclose (h2); |
| assert (status == 0); |
| |
| /* Set TLS vars; currently, lib1, lib3, and lib4 are loaded; |
| lib2 is not loaded. */ |
| for (i = 1; i <= 4; i++) |
| s0 (i, 50 + i); |
| for (i = 1; i <= 4; i++) |
| s1 (i, 150 + i); |
| for (i = 1; i <= 4; i++) |
| s3 (i, 350 + i); |
| for (i = 1; i <= 4; i++) |
| s4 (i, 450 + i); |
| for (i = 1; i <= 4; i++) |
| s10 (i, 1050 + i); |
| for (i = 1; i <= 4; i++) |
| s11 (i, 1150 + i); |
| |
| use_it (0); /* main-breakpoint-6 */ |
| |
| /* Load lib2, unload lib1, lib3, and lib4; then load lib3 again. */ |
| h2 = load_dso (OBJ2, 2, &s2); |
| status = dlclose (h1); |
| assert (status == 0); |
| status = dlclose (h3); |
| assert (status == 0); |
| status = dlclose (h4); |
| assert (status == 0); |
| h3 = load_dso (OBJ3, 3, &s3); |
| |
| /* Set TLS vars; currently, lib2 and lib3 are loaded; |
| lib1 and lib4 are not loaded. */ |
| for (i = 1; i <= 4; i++) |
| s0 (i, 60 + i); |
| for (i = 1; i <= 4; i++) |
| s2 (i, 260 + i); |
| for (i = 1; i <= 4; i++) |
| s3 (i, 360 + i); |
| for (i = 1; i <= 4; i++) |
| s10 (i, 1060 + i); |
| for (i = 1; i <= 4; i++) |
| s11 (i, 1160 + i); |
| |
| use_it (0); /* main-breakpoint-7 */ |
| |
| /* Unload lib3 and lib2, then (re)load lib4, lib3, lib2, and lib1, |
| in that order. */ |
| status = dlclose (h3); |
| assert (status == 0); |
| status = dlclose (h2); |
| assert (status == 0); |
| h4 = load_dso (OBJ4, 4, &s4); |
| h3 = load_dso (OBJ3, 3, &s3); |
| h2 = load_dso (OBJ2, 2, &s2); |
| h1 = load_dso (OBJ1, 1, &s1); |
| |
| /* Set TLS vars; currently, lib1, lib2, lib3, and lib4 are all |
| loaded. */ |
| for (i = 1; i <= 4; i++) |
| s0 (i, 70 + i); |
| for (i = 1; i <= 4; i++) |
| s1 (i, 170 + i); |
| for (i = 1; i <= 4; i++) |
| s2 (i, 270 + i); |
| for (i = 1; i <= 4; i++) |
| s3 (i, 370 + i); |
| for (i = 1; i <= 4; i++) |
| s4 (i, 470 + i); |
| for (i = 1; i <= 4; i++) |
| s10 (i, 1070 + i); |
| for (i = 1; i <= 4; i++) |
| s11 (i, 1170 + i); |
| |
| use_it (0); /* main-breakpoint-8 */ |
| |
| /* Unload lib3, lib1, and lib4. */ |
| status = dlclose (h3); |
| assert (status == 0); |
| status = dlclose (h1); |
| assert (status == 0); |
| status = dlclose (h4); |
| assert (status == 0); |
| |
| /* Set TLS vars; currently, lib2 is loaded; lib1, lib3, and lib4 are |
| not. */ |
| for (i = 1; i <= 4; i++) |
| s0 (i, 80 + i); |
| for (i = 1; i <= 4; i++) |
| s2 (i, 280 + i); |
| for (i = 1; i <= 4; i++) |
| s10 (i, 1080 + i); |
| for (i = 1; i <= 4; i++) |
| s11 (i, 1180 + i); |
| |
| use_it (0); /* main-breakpoint-9 */ |
| |
| /* Load lib3, unload lib2, load lib4. */ |
| h3 = load_dso (OBJ3, 3, &s3); |
| status = dlclose (h2); |
| assert (status == 0); |
| h4 = load_dso (OBJ4, 4, &s4); |
| |
| /* Set TLS vars; currently, lib3 and lib4 are loaded; lib1 and lib2 |
| are not. */ |
| for (i = 1; i <= 4; i++) |
| s0 (i, 90 + i); |
| for (i = 1; i <= 4; i++) |
| s3 (i, 390 + i); |
| for (i = 1; i <= 4; i++) |
| s4 (i, 490 + i); |
| for (i = 1; i <= 4; i++) |
| s10 (i, 1090 + i); |
| for (i = 1; i <= 4; i++) |
| s11 (i, 1190 + i); |
| |
| use_it (0); /* main-breakpoint-10 */ |
| |
| /* 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-last */ |
| |
| return 0; |
| } |