From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 22764 invoked by alias); 21 Jun 2002 23:08:18 -0000 Mailing-List: contact gdb-help@sources.redhat.com; run by ezmlm Precedence: bulk List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-owner@sources.redhat.com Received: (qmail 22754 invoked from network); 21 Jun 2002 23:08:15 -0000 Received: from unknown (HELO zwingli.cygnus.com) (208.245.165.35) by sources.redhat.com with SMTP; 21 Jun 2002 23:08:15 -0000 Received: by zwingli.cygnus.com (Postfix, from userid 442) id A3AA15EA11; Fri, 21 Jun 2002 18:08:14 -0500 (EST) To: Andrew Cagney Cc: gdb@sources.redhat.com Subject: Re: GDB support for thread-local storage References: <20020619160004.38A625EA11@zwingli.cygnus.com> <3D13A2D5.70801@cygnus.com> From: Jim Blandy Date: Fri, 21 Jun 2002 16:08:00 -0000 In-Reply-To: <3D13A2D5.70801@cygnus.com> Message-ID: User-Agent: Gnus/5.09 (Gnus v5.9.0) Emacs/21.1 MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii X-SW-Source: 2002-06/txt/msg00185.txt.bz2 Andrew Cagney 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.