This is the mail archive of the mailing list for the GDB project.

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: Getting offset of inital-exec TLS variables on GNU/Linux

* Simon Marchi:

> On 2019-05-17 10:34 a.m., Florian Weimer wrote:
>> * Simon Marchi:
>>> On 2019-05-17 6:21 a.m., Florian Weimer wrote:
>>>> Is it possible to obtain the offset of initial-exec TLS variable on
>>>> GNU/Linux?
>>>> It doesn't seem so because GDB executes the DWARF to access the TLS
>>>> variable, so the offset is an implementation detail.  Although it is
>>>> often visible at the ELF layer.
>>>> Thanks,
>>>> Florian
>>> Can you clarify a little bit?
>>> You are looking for the offset the variable from which point of reference:
>>> - The start of the TLS area of this module?
>>> - The start of the TLS area of the current thread?
>> The offset from something related to the thread pointer to the variable,
>> for cases where this is constant (specifically, initial-exec TLS
>> variables).
>>> Also, are you looking for something you can find statically, with just the
>>> executable, or are you working in the context of the live process?
>> I have a live process, and it would be best if the information matched
>> that process (even if it uses different libraries than those currently
>> installed in the file system).
> Hi Florian,
> I am still a bit unsure of what you are looking for concretely.  Are
> you looking for a GDB command to print this offset?  Do you need to
> compute the offset in an external tool?  what information are you
> starting with? I think that a bit more context would help us help you.

I had hoped to get this offset so that I can access the TLS variable
without loading libthread_db.

I'd be fine with getting the module TLS offset from internal data

> GDB uses libthread_db to get the location of TLS variables, which
> leaves all implementation details about this to glibc.  And since you
> are a glibc maintainer, I am not too sure what I can teach you about
> this, as you probably know more about this than I do.

If I have libpthread_db loaded and can somehow get the thread pointer
(e.g., $fs_base on x86-64), then I can get the constant I want just by
computing the different between the two, like this:

(gdb) print (void *)&tcache  - (void *)$fs_base
$9 = -80

Going back a bit, I'm not sure what the API contract is for
DW_OP_GNU_push_tls_address.  It's not really clear to me if under the
ELF TLS ABI, there is an expectation that the dynamic linker always
allocates the TLS space for a DSO as a single block.  I've perused the
two documents for the GNU ELF TLS ABI, and this is never spelled out

Outside debugging information, a TLS relocation for non-initial-exec TLS
always consists of a pair of a module ID and an offset.  Therefore, it
should be possible to lazily allocate individual TLS variables within a
DSO, by assigning them separate module IDs.

But what seems to happen in practice is that there is just one TLS block
per DSO, which is allocated at once once the first TLS variable is
accessed.  Furthermore, the entire TLS block is allocated non-lazily if
there is a single initial-exec TLS variable in a DSO.  Based on that, I
conclude that the module IDs are used only to share TLS variables for
the same symbol across multiple modules.  Due to this restriction, the
module ID for a TLS variable can be inferred from the object that
contains the DW_OP_GNU_push_tls_address opcode (and hopefully locating
the object based on symbol name in the debugger matches the way dynamic
linker search symbols).

I wonder if all this implicitly but firmly encodes a correspondence
between the argument to DW_OP_GNU_push_tls_address and the offset of a
TLS variable, within the TLS block for a DSO—if the DSO has the
DF_STATIC_TLS flag set.  Asumming this is indeed true, we could add the
TLS offset of a DSO to the public part of the link map in the glibc
dynamic loader to help debuggers.  For TLS variables defined in
DF_STATIC_TLS DSOs, it should then be possible to access the TLS
variable without the help of libthread_db, assuming that we teach GDB
how to compute the TLS variable address from the thread pointer, DSO TLS
offset, and variable offset (something binutils seems to know for
several targets already, to implement relaxations).

Would this be a reasonable thing to do?

(Cc:ing Carlos, who probably knows what is really going on here.)


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]