On Mon, May 5, 2025 at 3:37 PM Kyle Huey <m...@kylehuey.com> wrote: > > 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.
I pushed it to trunk and expect it will cherry-pick to branches, so no need to send additional patches. But a remainder in a week or so to pick the change would be nice. Richard. > - 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 > > >