From: Simon Marchi <simark@simark.ca>
To: John Baldwin <jhb@freebsd.org>
Cc: gdb-patches@sourceware.org
Subject: Re: [PATCH v2 04/11] Add a new gdbarch method to resolve the address of TLS variables.
Date: Fri, 08 Mar 2019 02:55:00 -0000 [thread overview]
Message-ID: <4a8bfa95b84386b3a76a37113495b7bc@simark.ca> (raw)
In-Reply-To: <2c282f52-0269-d6a8-8533-4c00b1a4ee8d@FreeBSD.org>
On 2019-03-07 18:50, John Baldwin wrote:
> On 3/7/19 8:08 AM, Simon Marchi wrote:
>> On 2019-02-08 7:40 p.m., John Baldwin wrote:
>>> Permit TLS variable addresses to be resolved purely by an ABI rather
>>> than requiring a target method. This doesn't try the target method
>>> if
>>> the ABI function is present (even if the ABI function fails) to
>>> simplify error handling.
>>
>> I don't see anything wrong with the patch (and the comment you removed
>> in target_translate_tls_address hints it is right), but again I am not
>> very familiar with how TLS works, so I wouldn't spot if anything was
>> conceptually wrong with this approach. I would appreciate if another
>> maintainer could take a look and give their opinion.
>
> Ok. FWIW, the reason for target vs gdbarch has to do with the
> different ways one can
> resolve a TLS variable. Some background:
>
> In ELF relocations, a TLS variable is identified by an offset in a
> special TLS section
> of an ELF file, similar to global symbols being an offset relative to
> .data or .bss.
> However, TLS variables are duplicated for each thread. To support
> this, the runtime
> linker allocates an array of pointers for each thread called the DTV
> array. The runtime
> linker also assigns an array index to each ELF object, so the
> executable is assigned array
> index 1, and other shared libraries that use TLS are assigned indices
> as they are mapped
> by the runtime linker. The pointers in each thread's array point to
> the per-thread blocks
> of TLS variables for a given ELF object. Thus, if index 1 is for my
> program and index 2
> was assigned to libc, then DTV[1] contains a pointer to all of the TLS
> variables in my
> main program and DTV[2] contains a pointer to all of the TLS variables
> in libc.
>
> Thus, if libc has two TLS integers 'foo' and 'bar', they might be
> assigned offsets of
> 0 and 4. To read the value of 'foo' one uses the expression '*(int
> *)(DTV[1])'. To
> read 'bar' you would use '*(int *)(DTV[1] + 4)'.
>
> There are some extra optimizations in the compiler-generated code
> (there's something
> called static TLS that can be at a fixed offset from the per-thread
> TCB pointer IIRC,
> but there are also valid DTV[] pointers that can get to the same
> variables just via
> more indirection. Compiled code is also allowed to fetch the 'base'
> of a TLS block
> for a given shared object and then save that 'base' and use offsets
> from it to access
> different variables. Put another way, the compiler can assume that
> &bar - &foo is
> always '4' and just add the relative offset to '&foo' to compute
> '&bar' without going
> through the DTV array every time).
>
> In target_translate_tls_address() we are given the 'struct objfile' of
> the ELF object
> and the offset of the TLS variable we are trying to find. The
> gdbarch_fetch_tls_load_module_address function fetches the pointer to
> the runtime
> linker's data structure describing that ELF object.
>
> The target version (target::get_thread_local_address) expects to use
> some target
> specific method to turn a (thread, linker_module_addr, offset) tuple
> into the
> address of a TLS variable. On Linux and other systems using
> libthread_db for this,
> it calls a libthread_db function. Internally that libthread_db
> function looks at
> the runtime linker's structure to extract the TLS index of the ELF
> object. It
> then looks in the thread library's per-thread data structure to find a
> pointer
> to the DTV array. It then uses 'DTV[index] + offset' to compute the
> final address.
> Note that this is all done in libthread_db rather than in gdb itself.
>
> The gdbarch method I'm using for FreeBSD doesn't use libthread_db.
> Instead, it
> more closely mimics what the compiler-generated code does. Many
> architectures use
> some sort of register to point to a per-thread Thread Control Block
> (TCB), and they
> store a pointer to the DTV array either in the TCB or at a fixed
> offset relative to
> the TCB. For example, 64-bit x86 uses the %fs segment prefix to access
> the TCB,
> and the %fs_base register is thus a pointer to the TCB. 32-bit x86
> uses %gs and
> %gs_base instead. RISC-V has a 'tp' register for this purpose, etc.
> The approach
> I'm using for FreeBSD is to provide an architecture-specific function
> that uses the
> relevant register to locate the pointer to the DTV array. It then
> calls a shared
> function (patch 7) that extracts the TLS index from the runtime
> linker's data
> structure and computes the final address via 'DTV[index] + offset'.
>
> Mostly I did this because I don't like libthread_db, but using a
> gdbarch method
> should also be a bit more cross-debugger friendly (you don't have to
> have a libthread_db
> on a FreeBSD host that understands the Linux runtime linker or thread
> library or
> vice versa, and similar concerns with 32-bit vs 64-bit and x86 vs ARM,
> etc.).
Ok, thanks to your explanation I think I understand better the need to
have an arch-specific way of doing it.
>>> diff --git a/gdb/gdbarch.sh b/gdb/gdbarch.sh
>>> index afc4da7cdd..09097bcbaf 100755
>>> --- a/gdb/gdbarch.sh
>>> +++ b/gdb/gdbarch.sh
>>> @@ -602,6 +602,7 @@ m;int;remote_register_number;int
>>> regno;regno;;default_remote_register_number;;0
>>>
>>> # Fetch the target specific address used to represent a load
>>> module.
>>> F;CORE_ADDR;fetch_tls_load_module_address;struct objfile
>>> *objfile;objfile
>>> +M;CORE_ADDR;get_thread_local_address;ptid_t ptid, CORE_ADDR lm_addr,
>>> CORE_ADDR offset;ptid, lm_addr, offset
>>
>> Could you document the method, especially the meaning of the
>> parameters?
>
> Sure. I used a variant of the comment from the target method:
>
> diff --git a/gdb/gdbarch.sh b/gdb/gdbarch.sh
> index 48fcebd19a..d15b6aa794 100755
> --- a/gdb/gdbarch.sh
> +++ b/gdb/gdbarch.sh
> @@ -602,6 +602,14 @@ m;int;remote_register_number;int
> regno;regno;;default_remote_register_number;;0
>
> # Fetch the target specific address used to represent a load module.
> F;CORE_ADDR;fetch_tls_load_module_address;struct objfile
> *objfile;objfile
> +
> +# Return the thread-local address at OFFSET in the thread-local
> +# storage for the thread PTID and the shared library or executable
> +# file given by LM_ADDR. If that block of thread-local storage hasn't
> +# been allocated yet, this function may return an error. LM_ADDR may
> +# be zero for statically linked multithreaded inferiors.
What does "may return an error" mean? A special CORE_ADDR value, or it
throws an error?
Simon
next prev parent reply other threads:[~2019-03-08 2:55 UTC|newest]
Thread overview: 28+ messages / expand[flat|nested] mbox.gz Atom feed top
2019-02-09 0:42 [PATCH v2 00/11] Support for thread-local variables on FreeBSD John Baldwin
2019-02-09 0:42 ` [PATCH v2 08/11] Support TLS variables on FreeBSD/amd64 John Baldwin
2019-02-09 0:42 ` [PATCH v2 01/11] Support the fs_base and gs_base registers on i386 John Baldwin
2019-02-09 0:42 ` [PATCH v2 07/11] Add a helper function to resolve TLS variable addresses for FreeBSD John Baldwin
2019-03-07 16:18 ` Simon Marchi
2019-02-09 0:42 ` [PATCH v2 09/11] Support TLS variables on FreeBSD/i386 John Baldwin
2019-02-09 0:42 ` [PATCH v2 03/11] Handle an edge case for minisym TLS variable lookups John Baldwin
2019-02-09 0:42 ` [PATCH v2 11/11] Support TLS variables on FreeBSD/powerpc John Baldwin
2019-03-07 16:26 ` Simon Marchi
2019-02-09 0:42 ` [PATCH v2 06/11] Add a more general version of lookup_struct_elt_type John Baldwin
2019-02-09 1:08 ` John Baldwin
2019-02-11 10:27 ` Philipp Rudo
2019-02-11 17:44 ` John Baldwin
2019-03-07 15:53 ` Simon Marchi
2019-03-08 0:04 ` John Baldwin
2019-03-08 0:32 ` Pedro Alves
2019-03-08 18:39 ` John Baldwin
2019-02-09 0:42 ` [PATCH v2 02/11] Support fs_base and gs_base on FreeBSD/i386 John Baldwin
2019-02-09 0:50 ` [PATCH v2 05/11] Remove code disabled since at least 1999 from lookup_struct_elt_type John Baldwin
2019-03-07 16:25 ` Simon Marchi
2019-02-09 0:50 ` [PATCH v2 04/11] Add a new gdbarch method to resolve the address of TLS variables John Baldwin
2019-03-07 16:08 ` Simon Marchi
2019-03-07 23:50 ` John Baldwin
2019-03-08 2:55 ` Simon Marchi [this message]
2019-03-08 18:39 ` John Baldwin
2019-02-09 0:50 ` [PATCH v2 10/11] Support TLS variables on FreeBSD/riscv John Baldwin
2019-02-22 17:22 ` [PING][PATCH v2 00/11] Support for thread-local variables on FreeBSD John Baldwin
2019-03-12 20:21 ` Simon Marchi
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=4a8bfa95b84386b3a76a37113495b7bc@simark.ca \
--to=simark@simark.ca \
--cc=gdb-patches@sourceware.org \
--cc=jhb@freebsd.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox