Bug 238485 - Failed to read TLS variables for -static -lpthread executables
Summary: Failed to read TLS variables for -static -lpthread executables
Status: New
Alias: None
Product: Base System
Classification: Unclassified
Component: threads (show other bugs)
Version: 12.0-RELEASE
Hardware: Any Any
: --- Affects Many People
Assignee: freebsd-threads mailing list
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2019-06-11 06:55 UTC by Rajendra
Modified: 2019-06-11 06:55 UTC (History)
0 users

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Rajendra 2019-06-11 06:55:30 UTC
On any platform build test app as below & print a TLS variable to see the error message.
 
$ clang -static -g -o tls src/tls.c -lpthread

ADM64: FreeBSD-12
-----
[amd64-fbsd12] #  lldb ./tls
(lldb) target create "./tls"
Current executable set to './tls' (x86_64).
(lldb) b 12
Breakpoint 1: where = tls`start_thread + 97 at tls.c:13, address = 0x0000000000222341
(lldb) r
Process 84810 launching
Process 84810 launched: './tls' (x86_64)
foo is 0xbad1 boo is 0xcab1 thread sleeping for 5 seconds
Process 84810 stopped
* thread #2, name = 'tls', stop reason = breakpoint 1.1
    frame #0: 0x0000000000222341 tls`start_thread(in=0x00000000004c9ed0) at tls.c:13
   10       boo = (*(int *)in)+51888; // 0xcab_
   11       printf("foo is 0x%x boo is 0x%x thread sleeping for 5 seconds\n", foo, boo);
   12       while (1) {
-> 13           sleep(5);
   14           break;
   15       }
   16       return NULL;
(lldb) p foo
error: Couldn't materialize: couldn't get the value of variable foo: No TLS data currently exists for this thread.
error: errored out in DoExecute, couldn't PrepareToExecuteJITExpression

RPI-2: FreeBSD-11
-----
rpi2-fbsd11] # /usr/bin/gdb ./tls
GNU gdb 6.1.1 [FreeBSD]
(gdb) b 12
Breakpoint 1 at 0x84e0: file src/tls.c, line 12.
(gdb) r
(gdb) p foo
Cannot find executable file `/b/syrajendra/test/lldb/test-prgms/step/tls' link_map in dynamic linker's module list

[rpi2-fbsd11] # /usr/local/bin/gdb ./tls
GNU gdb (GDB) 8.2.1 [GDB v8.2.1 for FreeBSD]
(gdb) b 12
Breakpoint 1 at 0x84e0: file src/tls.c, line 12.
(gdb) r
(gdb) p foo
Cannot find thread-local variables on this target

ADM64: FreeBSD-11
------
[amd64-fbsd11] # /usr/local/bin/gdb ./tls
GNU gdb (GDB) 8.1 [GDB v8.1 for FreeBSD]
(gdb) b 12
Breakpoint 1 at 0x400521: file src/tls.c, line 12.
(gdb) r
(gdb) p foo
Cannot find thread-local variables on this target

******
On Linux: debuggers use these below 2 API's from "thread_db.h" to fetch TLS var address.
1. For executables with shared libs: td_thr_tls_get_addr()
2. For executables with static libs: td_thr_tlsbase()

On FreeBSD, I see only td_thr_tls_get_addr() API.

Is possible to add td_thr_tlsbase() API?
Or 
How to get TLS variable address without td_thr_tlsbase() API from a static executable?

Here is the tls.c code:

#include <stdio.h>
#include <pthread.h>
#include <unistd.h>

#define MAX_THREADS 5
int __thread foo;
int __thread boo;
void* start_thread(void *in) {
    foo = (*(int *)in)+47824; // 0xbad_
    boo = (*(int *)in)+51888; // 0xcab_
    printf("foo is 0x%x boo is 0x%x thread sleeping for 5 seconds\n", foo, boo);
    while (1) {
        sleep(5);
        break;
    }
    return NULL;
}

int main(void) {
    pthread_t threads[MAX_THREADS];
    int i;
    static int count[MAX_THREADS];
    for (i=0; i<MAX_THREADS; i++) {
        count[i] = i + 1;
        pthread_create(&threads[i], NULL, start_thread, (void *)&count[i]);
    }
    for (i=0; i<MAX_THREADS; i++) {
        pthread_join(threads[i], NULL);
    }
    return 0;
}