On Thu, May 1, 2025 at 11:22 PM Richard Biener <richard.guent...@gmail.com> wrote: > > 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.
Thanks. I don't have write access so it would be great if you or someone else could commit this for me. I'll send a patch that's rebased for 13/14/15 later today. - Kyle > > 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 > >