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

Reply via email to