On Mon, May 5, 2025 at 6:45 AM Richard Biener
<richard.guent...@gmail.com> wrote:
>
> 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.

Thanks.

It won't work as is on any branches because 1d52798ea907 (which just
missed the 15 branch) renamed the field it checks.

- Kyle

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