On Fri, May 2, 2025 at 2:14 AM Kyle Huey <m...@kylehuey.com> wrote: > > For a debugger to display statically-allocated[0] TLS variables the compiler > must communicate information[1] that can be used in conjunction with knowledge > of the runtime enviroment[2] to calculate a location for the variable for > each thread. That need gives rise to dw_loc_dtprel in dwarf2out, a flag > tracking > whether the location description is dtprel, or relative to the > "dynamic thread pointer". Location descriptions in the .debug_info section for > TLS variables need to be relocated by the static linker accordingly, and > dw_loc_dtprel controls emission of the needed relocations. > > This is further complicated by -gsplit-dwarf. -gsplit-dwarf is designed to > allow > as much debugging information as possible to bypass the static linker to > improve > linking performance. One of the ways that is done is by introducing a layer of > indirection for relocatable values[3]. That gives rise to addr_index_table > which > ultimately results in the .debug_addr section. > > While the code handling addr_index_table clearly contemplates the existence of > dtprel entries[4] resolve_addr_in_expr does not, and the result is that when > using -gsplit-dwarf the DWARF for TLS variables contains an address[5] rather > than an offset, and debuggers can't work with that. > > This is visible on a trivial example. Compile > > ``` > static __thread int tls_var; > > int main(void) { > tls_var = 42; > return 0; > } > ``` > > with -g and -g -gsplit-dwarf. Run the program under gdb. When examining the > value of tls_var before and after the assignment, -g behaves as one would > expect but -g -gsplit-dwarf does not. If the user is lucky and the > miscalculated > address is not mapped, gdb will print "Cannot access memory at address ...". > If the user is unlucky and the miscalculated address is mapped, gdb will > simply > give the wrong value. You can further confirm that the issue is the address > calculation by asking gdb for the address of tls_var and comparing that to > what > one would expect.[6] > > Thankfully this is trivial to fix by modifying resolve_addr_in_expr to > propagate > the dtprel character of the location where necessary. gdb begins working as > expected and the diff in the generated assembly is clear. > > ``` > .section .debug_addr,"",@progbits > .long 0x14 > .value 0x5 > .byte 0x8 > .byte 0 > .Ldebug_addr0: > - .quad tls_var > + .long tls_var@dtpoff, 0 > .quad .LFB0 > ``` > > [0] Referring to e.g. __thread as statically-allocated vs. e.g. a > dynamically-allocated pthread_key_create() call. > [1] Generally an offset in a TLS block. > [2] With glibc, provided by libthread_db.so. > [3] Relocatable values are moved to a table in the .debug_addr section, those > values in .debug_info are replaced with special values that look up > indexes > in that table, and then the static linker elsewhere assigns a single > per-CU > starting index in the .debug_addr section, allowing those special values > to > remain permanently fixed and the resulting data to be ignored by the > linker. > [4] ate_kind_rtx_dtprel exists, after all, and new_addr_loc_descr does produce > it where appropriate. > [5] e.g. an address in the .tbss/.tdata section. > [6] e.g. on x86-64 by examining %fsbase and the offset in the assembly
OK. Feel free to backport as appropriate. Thanks, Richard. > 2025-05-01 Kyle Huey <kh...@kylehuey.com> > > * dwarf2out.cc (resolve_addr_in_expr): Propagate dtprel into the > address > table when appropriate. > --- > gcc/dwarf2out.cc | 3 ++- > 1 file changed, 2 insertions(+), 1 deletion(-) > > diff --git a/gcc/dwarf2out.cc b/gcc/dwarf2out.cc > index 34ffeed86ff..9aecdb9fd5a 100644 > --- a/gcc/dwarf2out.cc > +++ b/gcc/dwarf2out.cc > @@ -31068,7 +31068,8 @@ resolve_addr_in_expr (dw_attr_node *a, > dw_loc_descr_ref loc) > return false; > remove_addr_table_entry (loc->dw_loc_oprnd1.val_entry); > loc->dw_loc_oprnd1.val_entry > - = add_addr_table_entry (rtl, ate_kind_rtx); > + = add_addr_table_entry (rtl, loc->dw_loc_dtprel > + ? ate_kind_rtx_dtprel : ate_kind_rtx); > } > break; > case DW_OP_const4u: > -- > 2.43.0 >