Skip to content

[lldb] Handle STT_TLS symbol type in ELF parser#178975

Merged
DavidSpickett merged 1 commit intollvm:mainfrom
mugiwaraluffy56:fix-lldb-tls-symbol
Feb 9, 2026
Merged

[lldb] Handle STT_TLS symbol type in ELF parser#178975
DavidSpickett merged 1 commit intollvm:mainfrom
mugiwaraluffy56:fix-lldb-tls-symbol

Conversation

@mugiwaraluffy56
Copy link
Copy Markdown
Contributor

@mugiwaraluffy56 mugiwaraluffy56 commented Jan 30, 2026

Add handling for STT_TLS (thread-local storage) symbols in the ELF symbol parsing code. Previously, TLS symbols like errno from glibc were not recognized because STT_TLS was not handled in the symbol type switch statement.

This treats TLS symbols as data symbols (eSymbolTypeData), similar to STT_OBJECT. The actual TLS address resolution is already implemented in DynamicLoaderPOSIXDYLD::GetThreadLocalData() which uses the DWARF DW_OP_form_tls_address opcode to calculate thread-local addresses.

@llvmbot
Copy link
Copy Markdown
Member

llvmbot commented Jan 30, 2026

@llvm/pr-subscribers-lldb

Author: puneeth_aditya_5656 (mugiwaraluffy56)

Changes

Add handling for STT_TLS (thread-local storage) symbols in the ELF symbol parsing code. Previously, TLS symbols like errno from glibc were not recognized because STT_TLS was not handled in the symbol type switch statement.

This treats TLS symbols as data symbols (eSymbolTypeData), similar to STT_OBJECT. The actual TLS address resolution is already implemented in DynamicLoaderPOSIXDYLD::GetThreadLocalData() which uses the DWARF DW_OP_form_tls_address opcode to calculate thread-local addresses.

Fixes #178953


Full diff: https://github.com/llvm/llvm-project/pull/178975.diff

1 Files Affected:

  • (modified) lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp (+6)
diff --git a/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp b/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp
index 90afd5b2dc93a..0ec135324ea37 100644
--- a/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp
+++ b/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp
@@ -2241,6 +2241,12 @@ ObjectFileELF::ParseSymbols(Symtab *symtab, user_id_t start_id,
         // function will be resolved if it is referenced.
         symbol_type = eSymbolTypeResolver;
         break;
+
+      case STT_TLS:
+        // The symbol is associated with a thread-local data object, such as
+        // a thread-local variable.
+        symbol_type = eSymbolTypeData;
+        break;
       }
     }
 

@mugiwaraluffy56
Copy link
Copy Markdown
Contributor Author

@JDevlieghere , can you review this

@github-actions
Copy link
Copy Markdown

github-actions bot commented Jan 30, 2026

🐧 Linux x64 Test Results

  • 33307 tests passed
  • 508 tests skipped

✅ The build succeeded and all tests passed.

@DavidSpickett
Copy link
Copy Markdown
Collaborator

You need to fix the conflicts with the main branch before the CI can run again (it applies your changes to main to simulate the post-merge situation).

This needs a targeted test case. The ideal for this is to put it in lldb/test/Shell/ObjectFile/ELF and generate the input from a YAML file. LLVM has tools obj2yaml and yaml2obj for this purpose, or you could modify one of the existing yaml files.

If you need to check more than that style of test can, a simple C program can be used. I expect such a test will fail on AArch64 (#83466 / #71666) and probably ARM. We can sort that out with post merge fixes if so.

There is a test for TLS global variables - lldb/test/API/lang/c/tls_globals/TestTlsGlobals.py. This does run on x86 Linux judging by the skip annotations. errno is a "global" so you could check access in that test.

@k4lizen
Copy link
Copy Markdown

k4lizen commented Feb 2, 2026

Thanks for taking a look at this! :D

DWARF DW_OP_form_tls_address opcode to calculate thread-local addresses.

I don't know the details but I'd like to note that, as I said, this symbol is available even on a stripped glibc, i.e. with no dwarf

@DavidSpickett
Copy link
Copy Markdown
Collaborator

DavidSpickett commented Feb 4, 2026

You need to fix the conflicts with the main branch before the CI can run again (it applies your changes to main to simulate the post-merge situation).

Now I think about it, I'm not sure why it's being so picky, it isn't normally. Oh well, since there aren't any outstanding comments on this, feel free to force push updates.

which uses the DWARF DW_OP_form_tls_address opcode to calculate thread-local addresses.

I don't know the details but I'd like to note that, as I said, this symbol is available even on a stripped glibc, i.e. with no dwarf

This makes me worry that this PR is an improvement but not a full fix for the issue as reported. I'd still be happy to accept this PR but we should check before we claim to have fixed the issue. @mugiwaraluffy56 can you reproduce the issue and see what happens?

Other than that, this looks nice, the YAML test in particular is very neat. I'm just holding off approving until we know its exact effects.

@mugiwaraluffy56 mugiwaraluffy56 force-pushed the fix-lldb-tls-symbol branch 2 times, most recently from d83823d to 32d52cd Compare February 5, 2026 17:50
Add handling for STT_TLS (thread-local storage) symbols in the ELF
symbol parsing code. Previously, TLS symbols like errno from glibc
were not recognized because STT_TLS was not handled in the symbol
type switch statement.

This treats TLS symbols as data symbols (eSymbolTypeData), similar
to STT_OBJECT.

Fixes llvm#178953
@mchoo7
Copy link
Copy Markdown
Contributor

mchoo7 commented Feb 5, 2026

Parsing STT_TLS doesn't work on FreeBSD. Is this implementation issue on Process/FreeBSD?

./build/bin/lldb ./build/lldb-test-build.noindex/lang/cpp/thread_local/TestThreadLocal.test_thread_local_dwo/a.out
(lldb) target create "./build/lldb-test-build.noindex/lang/cpp/thread_local/TestThreadLocal.test_thread_local_dwo/a.out"
Current executable set to '/usr/src/llvm/tls/build/lldb-test-build.noindex/lang/cpp/thread_local/TestThreadLocal.test_thread_local_dwo/a.out' (x86_64).
(lldb) b main.cpp:10
Breakpoint 1: where = a.out`main + 76 at main.cpp:10:3, address = 0x00000000002016ec
(lldb) r
Process 24792 launched: '/usr/src/llvm/tls/build/lldb-test-build.noindex/lang/cpp/thread_local/TestThreadLocal.test_thread_local_dwo/a.out' (x86_64)
Process 24792 stopped
* thread #1, name = 'a.out', stop reason = breakpoint 1.1
    frame #0: 0x00000000002016ec a.out`main(argc=1, argv=0x0000000820795330) at main.cpp:10:3
   7      thread_local int *tl_local_ptr = nullptr;
   8      tl_local_ptr = &tl_local_int;
   9      tl_local_int++;
-> 10     return 0; // Set breakpoint here
          ^
   11   }
(lldb) expr tl_local_int + 1

error: Couldn't materialize: couldn't get the value of variable tl_local_int: no TLS data currently exists for this thread
error: errored out in DoExecute, couldn't PrepareToExecuteJITExpression]

@mugiwaraluffy56
Copy link
Copy Markdown
Contributor Author

Parsing STT_TLS doesn't work on FreeBSD. Is this implementation issue on Process/FreeBSD?

➜ ./build/bin/lldb ./build/lldb-test-build.noindex/lang/cpp/thread_local/TestThreadLocal.test_thread_local_dwo/a.out
(lldb) target create "./build/lldb-test-build.noindex/lang/cpp/thread_local/TestThreadLocal.test_thread_local_dwo/a.out"
Current executable set to '/usr/src/llvm/tls/build/lldb-test-build.noindex/lang/cpp/thread_local/TestThreadLocal.test_thread_local_dwo/a.out' (x86_64).
(lldb) b main.cpp:10
Breakpoint 1: where = a.out`main + 76 at main.cpp:10:3, address = 0x00000000002016ec
(lldb) r
Process 24792 launched: '/usr/src/llvm/tls/build/lldb-test-build.noindex/lang/cpp/thread_local/TestThreadLocal.test_thread_local_dwo/a.out' (x86_64)
Process 24792 stopped
* thread #1, name = 'a.out', stop reason = breakpoint 1.1
    frame #0: 0x00000000002016ec a.out`main(argc=1, argv=0x0000000820795330) at main.cpp:10:3
   7      thread_local int *tl_local_ptr = nullptr;
   8      tl_local_ptr = &tl_local_int;
   9      tl_local_int++;
-> 10     return 0; // Set breakpoint here
          ^
   11   }
(lldb) expr tl_local_int + 1

error: Couldn't materialize: couldn't get the value of variable tl_local_int: no TLS data currently exists for this thread
error: errored out in DoExecute, couldn't PrepareToExecuteJITExpression]

This PR only fixes STT_TLS symbol parsing (recognizing the symbol type in the ELF table). The runtime TLS variable evaluation you're showing is a separate issue in the Process plugin .My PR doesn't address that. The yaml test confirms parsing works correctly.

Copy link
Copy Markdown
Contributor

@mchoo7 mchoo7 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll fix FreeBSD issue on my side. At least for FreeBSD, LGTM.

Copy link
Copy Markdown
Collaborator

@DavidSpickett DavidSpickett left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This PR LGTM on the condition that

Fixes #178953

Is either proven to be true, or you remove that claim from the PR description, and the original issue reporter can test it on their own time.

I suggest the latter.

Nothing wrong with either path, just being a pedant about process :)

@mugiwaraluffy56
Copy link
Copy Markdown
Contributor Author

This PR LGTM on the condition that

Fixes #178953

Is either proven to be true, or you remove that claim from the PR description, and the original issue reporter can test it on their own time.

I suggest the latter.

Nothing wrong with either path, just being a pedant about process :)

Done.

@DavidSpickett DavidSpickett merged commit 936ec4e into llvm:main Feb 9, 2026
10 checks passed
@mugiwaraluffy56 mugiwaraluffy56 deleted the fix-lldb-tls-symbol branch February 9, 2026 10:20
rishabhmadan19 pushed a commit to rishabhmadan19/llvm-project that referenced this pull request Feb 9, 2026
Add handling for `STT_TLS` (thread-local storage) symbols in the ELF
symbol parsing code. Previously, TLS symbols like `errno` from glibc
were not recognized because `STT_TLS` was not handled in the symbol type
switch statement.

This treats TLS symbols as data symbols (`eSymbolTypeData`), similar to
`STT_OBJECT`. The actual TLS address resolution is already implemented
in `DynamicLoaderPOSIXDYLD::GetThreadLocalData()` which uses the DWARF
`DW_OP_form_tls_address` opcode to calculate thread-local addresses.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants