llvm / llvm/llvm-project

Wrong dwarf debug info for TLS variables on Windows, if built with llvm-mingw

Open
#196,083 3 comments 0 reactions 0 assignees View on GitHub
debuginfo lldb
Dominant language
LLVM
Stars
40.5k
Forks
18.7k
PR merge metrics
PR metrics pending

Description

Consider this simple example:
```c

__thread int tls1 = 11;
__thread int tls2 = 12;

int main()
{
tls1 = 101;
tls2 = 102;

return tls1 + tls2;
}
```
Compiled with: `x86_64-w64-mingw32-gcc.exe -g -o tls-l22.exe tls.c`
When looking at the debug info with llvm-dwarfdump, I get the following for the TLS variables:
```
0x00001696: DW_TAG_variable
DW_AT_name ("tls1")
DW_AT_type (0x000016ac "int")
DW_AT_external (true)
DW_AT_decl_file ("C:/tls\tls.c")
DW_AT_decl_line (2)
DW_AT_location (DW_OP_const8u 0x140007008, DW_OP_GNU_push_tls_address)

0x000016b3: DW_TAG_variable
DW_AT_name ("tls2")
DW_AT_type (0x000016ac "int")
DW_AT_external (true)
DW_AT_decl_file ("C:/tls\tls.c")
DW_AT_decl_line (3)
DW_AT_location (DW_OP_const8u 0x14000700c, DW_OP_GNU_push_tls_address)
```
In both cases DW_AT_location is an absolute address into the .tls section, instead of an offset.

When compiled on Linux, I get this instead (for both clang and gcc):
```
0x00000023: DW_TAG_variable
DW_AT_name ("tls1")
DW_AT_type (0x00000036 "int")
DW_AT_external (true)
DW_AT_decl_file ("tls.c")
DW_AT_decl_line (2)
DW_AT_location (DW_OP_const8u 0x0, DW_OP_GNU_push_tls_address)

0x0000003a: DW_TAG_variable
DW_AT_name ("tls2")
DW_AT_type (0x00000036 "int")
DW_AT_external (true)
DW_AT_decl_file ("tls.c")
DW_AT_decl_line (3)
DW_AT_location (DW_OP_const8u 0x4, DW_OP_GNU_push_tls_address)
```
Here DW_AT_location is an offset which both lldb and gdb interpret correctly when debugging.

As a side not, debugging of TLS variables on Windows doesn't seem to work at all currently with lldb:
```
C:\tls>lldb.exe tls-l22.exe
(lldb) target create "tls-l22.exe"
Current executable set to 'C:\tls\tls-l22.exe' (x86_64).
(lldb) b main
Breakpoint 1: where = tls-l22.exe`main + 22 at tls.c:7:3, address = 0x0000000140001436
(lldb) r
Process 23792 launched: 'C:\tls\tls-l22.exe' (x86_64)
Process 23792 stopped
* thread #1, stop reason = breakpoint 1.1
frame #0: 0x00007ff6b1241436 tls-l22.exe`main at tls.c:7:3
4
5 int main()
6 {
-> 7 tls1 = 101;
8 tls2 = 102;
9
10 return tls1 + tls2;
(lldb) p tls1

error: Couldn't materialize: couldn't get the value of variable tls1: no TLS data currently exists for this thread
error: errored out in DoExecute, couldn't PrepareToExecuteJITExpression
(lldb) c
Process 23792 resuming
Process 23792 exited with status = 203 (0x000000cb)
(lldb) q
```
I guess that's why the wrong TLS debug info wasn't noticed.

Contributor guide

Open the contributing guide

Research direction

Reproduce the example in tls.c with x86_64-w64-mingw32-gcc.exe and inspect the output using llvm-dwarfdump. Compare the Windows DW_AT_location values with the Linux output, then trace the LLVM DWARF emission for Windows TLS variables. Done means the emitted locations use the expected TLS offsets and the result can be verified in the debugger.

Written by the indexing model from the issue text.

Assessment

Tech stack
c
Domain
compilers, devtools, operating-systems
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
45/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.