Wrong dwarf debug info for TLS variables on Windows, if built with llvm-mingw
- 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
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