This is the mail archive of the gdb@sources.redhat.com 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: GDB support for thread-local storage


Andrew Cagney <ac131313@cygnus.com> writes:
> > /* Get address of thread local variable.  */
> > extern td_err_e td_thr_tls_get_addr (const td_thrhandle_t *__th,
> >                                      struct link_map *__map, size_t __offset,
> >                                      void **__address);
> > This takes a thread handle, an entry from the dynamic linker's link
> > map, and an offset, and sets *__address to point to the base of that
> > thread and module's thread-local storage, plus the offset.  It returns
> > an error code if the space hasn't been allocated yet.
> 
> What does GDB do if there isn't [yet] any allocated local storage?

Oh, sorry --- what does *GDB* do?

It depends.  For the first cut, it returns an error:

    (gdb) print i
    Storage for the thread-local variable `i' has not been allocated in
    this thread yet.
    (gdb)

But there are ways we could do better than that.

It's tempting to suggest that referring to unallocated thread-local
storage should cause the storage to be allocated.  This emulates the
way variable references in the actual program behave most closely.

However, this is a pretty heavy-duty operation.  It involves calling a
function in the inferior, which will do a malloc, copy in the
initialization image, update thread structures, and so on.  I don't
think simply trying to print a variable should cause that kind of
disturbance in the inferior.

Instead, I think trying to print an unallocated __thread variable
should cause an error, which suggests that the user try a command
`thread allocate VAR', which will do the right inferior-disturbing
magic to make VAR exist.  That way, the user has control over the
process, and GDB doesn't munge her inferior in unexpected ways.

There is a middle ground.  Initializing a thread-local storage block
is simply a memcpy of the initialization image.  There are no relocs
to apply --- stuff like this:

        __thread int i;
        __thread int *pi = &i;

is forbidden.  This means that there's an exact copy of all the bits
each variable *would* have, if it *were* allocated --- they're just
immutable, and at the wrong address.

So a really clever implementation could actually give you the value of
a thread-local variable like `i' even when it hasn't been allocated
yet.  It would be a non-lazy value, not an lvalue, and have no
address, but at least `print i' would give you the right answer.  We
could even set a bit on the value so that an attempt to assign to it
would give a helpful error message:

    (gdb) set var i = 2
    Storage for the thread-local variable `i' has not been allocated
    in this thread yet.  Type `thread allocate i' to allocate it.
    (gdb)

Or something like that.

Anyway, that's why the gdbarch and target methods I proposed are
producing `struct value' objects, and not something more low-level ---
to leave open the option of handling unallocated values this way.


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