Re: GDB support for thread-local storage

Jim Blandy
2002-06-21T23:08:18Z

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.