Skip to content

lldb on AArch64 Linux cannot read thread local variables #71666

@DavidSpickett

Description

@DavidSpickett

Since e8ea476 we have support for TLS on x86 Linux, but this does not work on AArch64.

For AArch64 we do now have the tpidr register accessible, which is one piece of the puzzle.

The other part is that the compiler does not emit any TLS hint in the DWARF. Example code:

#include <pthread.h>

__thread int tls1=10;
void *start(void* ptr) {
  int a=10+tls1;
  return NULL;
}

int main() {
  pthread_t t1;
  pthread_create(&t1, NULL, start, NULL);
  void* r;
  pthread_join(t1, &r);
  return 0;
}

Compiled with clang for AArch64 we get this description:

0x00000023:   DW_TAG_variable
                DW_AT_name      ("tls1")
                DW_AT_type      (0x0000002b "int")
                DW_AT_external  (true)
                DW_AT_decl_file ("/tmp/test.c")
                DW_AT_decl_line (3)

For x86 you get:

0x000000e6:   DW_TAG_variable
                DW_AT_name      ("tls1")
                DW_AT_decl_file ("/tmp/test.c")
                DW_AT_decl_line (3)
                DW_AT_decl_column       (0x0e)
                DW_AT_type      (0x00000057 "int")
                DW_AT_external  (true)
                DW_AT_location  (DW_OP_const8u 0x0, DW_OP_GNU_push_tls_address)

Arm has not decided on a way to represent TLS variables in this same way (see AArch64_ELFTargetObjectFile::Initialize).

I briefly tried flipping that boolean so AArch64 did emit it, then using tpidr as the thread pointer. However the existing calculations do not work and I don't have time right now to see what the data structures are supposed to be.

My hacks aside, a vanilla LLDB doesn't see the variable at all:

(lldb) p tls1
error: <user expression 0>:1:1: use of undeclared identifier 'tls1'
    1 | tls1
      | ^

GDB can read it:

(gdb) p tls1
$1 = 10

Apparently GDB is using thread_db from glibc to work this out, but I don't have the details.

We would I think have to:

  • Mark tpidr as the thread pointer register.
  • Pass this information to glibc somehow, using the symbol's address as the offset.
  • Read the resulting location.

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions