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
> >

Reply via email to