Export stack_used as __stack_used

Message ID 1466163476-10459-1-git-send-email-gbenson@redhat.com
State New, archived
Headers

Commit Message

Gary Benson June 17, 2016, 11:37 a.m. UTC
  Hi all,

This commit renames "stack_used" as "__stack_used" and changes it from
a static variable in allocatestack.c to an internally exported symbol
available to all nptl source files.  This fixes bug 17629 (and thus
GDB PR 9635).

Is this ok to commit?

Cheers,
Gary

---

	[BZ #17629]
	* nptl/allocatestack.c (stack_used): Rename as...
	(__stack_used): Renamed from stack_used and made non-static.
	All uses updated.
	* nptl/nptl-init.c: Initialize __stack_used.
	* nptl/pthreadP.h (__stack_used): New declaration.
	* nptl_db/td_ta_thr_iter.c (iterate_thread_list): Cope with
	__stack_used == NULL.
---
 ChangeLog                 |   11 +++++++++++
 nptl/allocatestack.c      |   33 +++++++++++++++++----------------
 nptl/descr.h              |    2 +-
 nptl/nptl-init.c          |    1 +
 nptl/pthreadP.h           |    2 ++
 nptl/pthread_create.c     |    2 +-
 nptl_db/structs.def       |    2 +-
 nptl_db/td_ta_thr_iter.c  |   15 +++++++++++----
 nptl_db/td_thr_validate.c |    2 +-
 9 files changed, 46 insertions(+), 24 deletions(-)
  

Comments

Pedro Alves June 17, 2016, 11:51 a.m. UTC | #1
On 06/17/2016 12:37 PM, Gary Benson wrote:
> Hi all,
> 
> This commit renames "stack_used" as "__stack_used" and changes it from
> a static variable in allocatestack.c to an internally exported symbol
> available to all nptl source files.  This fixes bug 17629 (and thus
> GDB PR 9635).

Thanks!

> 
> Is this ok to commit?

I'd have preferred to split the renaming bits out, alone, as that's
the part that actually fixes the bug, and leave the (internally) exporting
the symbol and the iterate_thread_list hunk as a patch of the Infinity
series, where it's needed.
  
Florian Weimer June 17, 2016, 12:33 p.m. UTC | #2
On 06/17/2016 01:37 PM, Gary Benson wrote:
> Hi all,
>
> This commit renames "stack_used" as "__stack_used" and changes it from
> a static variable in allocatestack.c to an internally exported symbol
> available to all nptl source files.  This fixes bug 17629 (and thus
> GDB PR 9635).

What do you mean by “export”?  The __ prefix suggests that you want to 
export it as a symbol (probably GLIBC_PRIVATE), but I think you'd need 
to update nptl/Versions in this case.

If the variable remains nptl-internal, I expect that you could turn it 
into a hidden symbol, and keep its current name.

Thanks,
Florian
  
Gary Benson June 17, 2016, 7:50 p.m. UTC | #3
Florian Weimer wrote:
> On 06/17/2016 01:37 PM, Gary Benson wrote:
> > This commit renames "stack_used" as "__stack_used" and changes it
> > from a static variable in allocatestack.c to an internally
> > exported symbol available to all nptl source files.  This fixes
> > bug 17629 (and thus GDB PR 9635).
> 
> What do you mean by “export”?  The __ prefix suggests that you want
> to export it as a symbol (probably GLIBC_PRIVATE), but I think you'd
> need to update nptl/Versions in this case.

No, I don't need that, it needs to be visible outside allocatestack.c
but it doesn't need to be visible in, e.g., the output of "objdump -T".

> If the variable remains nptl-internal, I expect that you could turn
> it into a hidden symbol, and keep its current name.

I may be wrong but I think its the rename that fixes the GDB bug.

If it's visible outside of allocatestack.c (i.e. it's not "static")
then it should be named with a double-underscore, no?

Thanks,
Gary
  
Florian Weimer June 17, 2016, 8:17 p.m. UTC | #4
On 06/17/2016 09:50 PM, Gary Benson wrote:
> Florian Weimer wrote:
>> On 06/17/2016 01:37 PM, Gary Benson wrote:
>>> This commit renames "stack_used" as "__stack_used" and changes it
>>> from a static variable in allocatestack.c to an internally
>>> exported symbol available to all nptl source files.  This fixes
>>> bug 17629 (and thus GDB PR 9635).
>>
>> What do you mean by “export”?  The __ prefix suggests that you want
>> to export it as a symbol (probably GLIBC_PRIVATE), but I think you'd
>> need to update nptl/Versions in this case.
>
> No, I don't need that, it needs to be visible outside allocatestack.c
> but it doesn't need to be visible in, e.g., the output of "objdump -T".

Okay, then please declare it attribute_hidden.

>> If the variable remains nptl-internal, I expect that you could turn
>> it into a hidden symbol, and keep its current name.
>
> I may be wrong but I think its the rename that fixes the GDB bug.

Only if GDB explicitly searches for __stack_used (and that with the help 
of debugging information because it's not exported).

There isn't even a reference from libthread_db.

> If it's visible outside of allocatestack.c (i.e. it's not "static")
> then it should be named with a double-underscore, no?

Hmm, yes for the benefit of static linking and namespace cleanliness. 
So perhaps keep __stack_used, but make it hidden as well.  (I don't 
understand the nocommon business and what this addresses.)

Florian
  
Gary Benson June 17, 2016, 8:17 p.m. UTC | #5
Gary Benson wrote:
> Florian Weimer wrote:
> > On 06/17/2016 01:37 PM, Gary Benson wrote:
> > > This commit renames "stack_used" as "__stack_used" and changes it
> > > from a static variable in allocatestack.c to an internally
> > > exported symbol available to all nptl source files.  This fixes
> > > bug 17629 (and thus GDB PR 9635).
> > 
> > What do you mean by “export”?  The __ prefix suggests that you want
> > to export it as a symbol (probably GLIBC_PRIVATE), but I think you'd
> > need to update nptl/Versions in this case.
> 
> No, I don't need that, it needs to be visible outside allocatestack.c
> but it doesn't need to be visible in, e.g., the output of "objdump -T".
> 
> > If the variable remains nptl-internal, I expect that you could turn
> > it into a hidden symbol, and keep its current name.
> 
> I may be wrong but I think its the rename that fixes the GDB bug.
> 
> If it's visible outside of allocatestack.c (i.e. it's not "static")
> then it should be named with a double-underscore, no?

Oh, hang on, libthread_db looks it up _by_name_.  How is that working
currently?

Cheers,
Gary
  
Florian Weimer June 17, 2016, 8:31 p.m. UTC | #6
On 06/17/2016 10:17 PM, Gary Benson wrote:
> Gary Benson wrote:
>> Florian Weimer wrote:
>>> On 06/17/2016 01:37 PM, Gary Benson wrote:
>>>> This commit renames "stack_used" as "__stack_used" and changes it
>>>> from a static variable in allocatestack.c to an internally
>>>> exported symbol available to all nptl source files.  This fixes
>>>> bug 17629 (and thus GDB PR 9635).
>>>
>>> What do you mean by “export”?  The __ prefix suggests that you want
>>> to export it as a symbol (probably GLIBC_PRIVATE), but I think you'd
>>> need to update nptl/Versions in this case.
>>
>> No, I don't need that, it needs to be visible outside allocatestack.c
>> but it doesn't need to be visible in, e.g., the output of "objdump -T".
>>
>>> If the variable remains nptl-internal, I expect that you could turn
>>> it into a hidden symbol, and keep its current name.
>>
>> I may be wrong but I think its the rename that fixes the GDB bug.
>>
>> If it's visible outside of allocatestack.c (i.e. it's not "static")
>> then it should be named with a double-underscore, no?
>
> Oh, hang on, libthread_db looks it up _by_name_.  How is that working
> currently?

It seems that libpthread_db calls ps_pglobal_lookup, which is provided 
by the “application” (so GDB).  The mechanism is a bit weird: it almost 
looks as if someone thought about caching the name-based lookups in an 
array (with an index known at compile-time), but then never wrote the 
code to use a cache.

We check that the symbols can be found in the .symtab section (so via 
debugging information, I assume, not .dynsym).

Florian
  
Pedro Alves June 17, 2016, 10:01 p.m. UTC | #7
On 06/17/2016 09:31 PM, Florian Weimer wrote:
> On 06/17/2016 10:17 PM, Gary Benson wrote:
>> Gary Benson wrote:
>>> Florian Weimer wrote:
>>>> On 06/17/2016 01:37 PM, Gary Benson wrote:
>>>>> This commit renames "stack_used" as "__stack_used" and changes it
>>>>> from a static variable in allocatestack.c to an internally
>>>>> exported symbol available to all nptl source files.  This fixes
>>>>> bug 17629 (and thus GDB PR 9635).
>>>>
>>>> What do you mean by “export”?  The __ prefix suggests that you want
>>>> to export it as a symbol (probably GLIBC_PRIVATE), but I think you'd
>>>> need to update nptl/Versions in this case.
>>>
>>> No, I don't need that, it needs to be visible outside allocatestack.c
>>> but it doesn't need to be visible in, e.g., the output of "objdump -T".
>>>
>>>> If the variable remains nptl-internal, I expect that you could turn
>>>> it into a hidden symbol, and keep its current name.
>>>
>>> I may be wrong but I think its the rename that fixes the GDB bug.

Yes it is.

Should be trivial to reproduce.  Simply write a test program that has
a global named "stack_used".  The program is totally free to do that,
because that is a symbol name not in the implementation namespace.

See:
 https://sourceware.org/bugzilla/show_bug.cgi?id=9635
And the small reproducer:
 https://sourceware.org/bugzilla/attachment.cgi?id=5756

>>>
>>> If it's visible outside of allocatestack.c (i.e. it's not "static")
>>> then it should be named with a double-underscore, no?
>>
>> Oh, hang on, libthread_db looks it up _by_name_.  How is that working
>> currently?
> 
> It seems that libpthread_db calls ps_pglobal_lookup, which is provided
> by the “application” (so GDB).  

Right.  libthread_db.so is loaded as a plugin inside gdb's address
space.  That library knows the layouts of the target's libpthread's
internals, but doesn't know where the addresses of the inferior's globals
are.  So when libthread_db.so needs to know the address of
the target inferior's libpthread's "stack_used" symbol, it asks gdb,
via the proc-service interface.

The problem is that if the program being debugged defines its own
unrelated "stack_used" symbol, gdb can well return the address of
that unrelated global to libthread_db.so.

My initial attempt was to try to fix this in gdb, by restricting gdb's global
lookup to symbols defined in libpthread.so.  However, it turned out that
that doesn't work when the inferior being debugged has been statically
linked, because in that case, libpthread is really linked inside 
the main program, and thus there's no separate "libpthread.so" gdb can
restrict the symbol lookup in.  So we're back to the same problem.

The solution I suggested in the PR then, is to rename the libpthread's
"stack_used" symbol, giving it a name that is in the implementation namespace.

I think it'd be reasonable if libthread_db's DB_GET_SYMBOL macro
had an assert that ensured that only symbols in the implementation
name space are looked up, even.

(Note that most of the libpthread symbols that libthread_db looks up
are prefixed "__nptl_"; such a prefix makes it even less likely to trip
on a conflict -- there's a remote but non-zero change that libgcc or
some other library part of the implementation has another symbol
named "__stack_used".)


> The mechanism is a bit weird: it almost
> looks as if someone thought about caching the name-based lookups in an
> array (with an index known at compile-time), but then never wrote the
> code to use a cache.
> 
> We check that the symbols can be found in the .symtab section (so via
> debugging information, I assume, not .dynsym).

Here I'm afraid you lost me.

Thanks,
Pedro Alves
  
Pedro Alves June 17, 2016, 10:15 p.m. UTC | #8
On 06/17/2016 09:17 PM, Florian Weimer wrote:
> 
>>> If the variable remains nptl-internal, I expect that you could turn
>>> it into a hidden symbol, and keep its current name.
>>
>> I may be wrong but I think its the rename that fixes the GDB bug.
> 
> Only if GDB explicitly searches for __stack_used (and that with the help
> of debugging information because it's not exported).

Note that it's not GDB that _wants_ to search for the symbol, it's
libthread_db.so itself.  GDB just serves libthread_db.so's request,
through the proc_service [1] interface (nptl_db/proc_service.h).  That is,
through callbacks that serve as interface between libthread_db and
the debugger that loads it.

[1] based on Solaris's interface of the same name:
 http://docs.oracle.com/cd/E26505_01/html/816-5171/proc-service-3proc.html

> 
> There isn't even a reference from libthread_db.

AFAICS, the look ups in question are here:

 nptl_db/td_thr_validate.c:73:      err = DB_GET_SYMBOL (list, th->th_ta_p, stack_used);
 nptl_db/td_ta_thr_iter.c:164:    err = DB_GET_SYMBOL (list, ta, stack_used);

I think that nptl_version is another symbol that can potentially
cause the same problem:

 nptl_db/structs.def:51:DB_SYMBOL (stack_used)
 nptl_db/structs.def:52:DB_SYMBOL (__stack_user)
 nptl_db/structs.def:53:DB_SYMBOL (nptl_version)
 nptl_db/structs.def:56:DB_SYMBOL (__nptl_threads_events)

(Obviously it's less likely, given the "nptl" prefix, but still...)

Thanks,
Pedro Alves
  
Andreas Schwab June 18, 2016, 6:52 a.m. UTC | #9
Pedro Alves <palves@redhat.com> writes:

> I think that nptl_version is another symbol that can potentially
> cause the same problem:
>
>  nptl_db/structs.def:51:DB_SYMBOL (stack_used)
>  nptl_db/structs.def:52:DB_SYMBOL (__stack_user)
>  nptl_db/structs.def:53:DB_SYMBOL (nptl_version)
>  nptl_db/structs.def:56:DB_SYMBOL (__nptl_threads_events)

I think that DB_SYMBOL should use aliases with a unique prefix instead
of the variable names directly, and those aliases should be put in the
dynamic symbol table so that lookup still works if libthread is
stripped.

Andreas.
  
Pedro Alves June 18, 2016, 11:08 a.m. UTC | #10
On 06/18/2016 07:52 AM, Andreas Schwab wrote:
> Pedro Alves <palves@redhat.com> writes:
> 
>> I think that nptl_version is another symbol that can potentially
>> cause the same problem:
>>
>>  nptl_db/structs.def:51:DB_SYMBOL (stack_used)
>>  nptl_db/structs.def:52:DB_SYMBOL (__stack_user)
>>  nptl_db/structs.def:53:DB_SYMBOL (nptl_version)
>>  nptl_db/structs.def:56:DB_SYMBOL (__nptl_threads_events)
> 
> I think that DB_SYMBOL should use aliases with a unique prefix instead
> of the variable names directly, and those aliases should be put in the
> dynamic symbol table so that lookup still works if libthread is
> stripped.

Agreed.  Requiring not-stripped libpthread used to
be a constant source of trouble for integrators, enough that gdb has a
FAQ entry about it:
 https://sourceware.org/gdb/wiki/FAQ#GDB_does_not_see_any_threads_besides_the_one_in_which_crash_occurred.3B_or_SIGTRAP_kills_my_program_when_I_set_a_breakpoint
We don't hear about this problem a lot anymore though, I believe because
gdb nowadays does not rely on libthread_db for so many things as it used to.

I seem to remember this having been proposed in the past, but there having
been pushback against putting these symbols in the dynamic symbol table,
because that increases the dynamic symbol table size just for debugging...
If this is no longer a concern, I'm all for it.

Thanks,
Pedro Alves
  
Florian Weimer June 20, 2016, 8:53 a.m. UTC | #11
On 06/18/2016 01:08 PM, Pedro Alves wrote:

> Agreed.  Requiring not-stripped libpthread used to
> be a constant source of trouble for integrators, enough that gdb has a
> FAQ entry about it:
>  https://sourceware.org/gdb/wiki/FAQ#GDB_does_not_see_any_threads_besides_the_one_in_which_crash_occurred.3B_or_SIGTRAP_kills_my_program_when_I_set_a_breakpoint

Uh-oh.

> I seem to remember this having been proposed in the past, but there having
> been pushback against putting these symbols in the dynamic symbol table,
> because that increases the dynamic symbol table size just for debugging...
> If this is no longer a concern, I'm all for it.

Could we export a single symbol which is a struct and contains all the 
data we need?  Then the impact on dynamic symbol table size would be 
minimal.

Florian
  
Andreas Schwab June 20, 2016, 9:04 a.m. UTC | #12
Florian Weimer <fweimer@redhat.com> writes:

> Could we export a single symbol which is a struct and contains all the
> data we need?  Then the impact on dynamic symbol table size would be
> minimal.

That would raise the issue of compatibility. Probing each symbol
separately is much easier than trying to extend the struct.  What
exactly _is_ the impact of making the dynamic symtab a few entries
bigger?

Andreas.
  
Pedro Alves June 20, 2016, 5:54 p.m. UTC | #13
On 06/20/2016 10:04 AM, Andreas Schwab wrote:
> Florian Weimer <fweimer@redhat.com> writes:
> 
>> Could we export a single symbol which is a struct and contains all the
>> data we need?  Then the impact on dynamic symbol table size would be
>> minimal.
> 
> That would raise the issue of compatibility. Probing each symbol
> separately is much easier than trying to extend the struct.  What
> exactly _is_ the impact of making the dynamic symtab a few entries
> bigger?

I think this is what I was remembering:

 https://sourceware.org/ml/libc-alpha/2003-11/msg00007.html

Thanks,
Pedro Alves
  
Florian Weimer June 21, 2016, 9:15 a.m. UTC | #14
On 06/20/2016 11:04 AM, Andreas Schwab wrote:
> Florian Weimer <fweimer@redhat.com> writes:
>
>> Could we export a single symbol which is a struct and contains all the
>> data we need?  Then the impact on dynamic symbol table size would be
>> minimal.
>
> That would raise the issue of compatibility. Probing each symbol
> separately is much easier than trying to extend the struct.  What
> exactly _is_ the impact of making the dynamic symtab a few entries
> bigger?

Does compatibility really matter?  I thought you need exactly matching 
libpthread and libthread_db versions anyway.  I suppose we could even 
compile the offsets into libthread_db.

I assume that for compatibility across multiple versions, we will need 
something like Infinity.

Thanks,
Florian
  
Andreas Schwab June 21, 2016, 5:31 p.m. UTC | #15
Florian Weimer <fweimer@redhat.com> writes:

> Does compatibility really matter?  I thought you need exactly matching
> libpthread and libthread_db versions anyway.  I suppose we could even
> compile the offsets into libthread_db.

The thread_db interface appears to be generic enough to be able to cope
with different versions.

Andreas.
  
Mike Frysinger June 22, 2016, 10:57 a.m. UTC | #16
On 21 Jun 2016 19:31, Andreas Schwab wrote:
> Florian Weimer <fweimer@redhat.com> writes:
> > Does compatibility really matter?  I thought you need exactly matching
> > libpthread and libthread_db versions anyway.  I suppose we could even
> > compile the offsets into libthread_db.
> 
> The thread_db interface appears to be generic enough to be able to cope
> with different versions.

while true, i don't think that means you can mix & match.  we've always
said glibc libs must be coherent (can't mix 2.15 libpthread with a 2.17
libc), so i'm not sure why thread_db is any different.  they're shipped
together by distros too.
-mike
  
Pedro Alves June 22, 2016, 2:30 p.m. UTC | #17
On 06/22/2016 11:57 AM, Mike Frysinger wrote:
> On 21 Jun 2016 19:31, Andreas Schwab wrote:
>> Florian Weimer <fweimer@redhat.com> writes:
>>> Does compatibility really matter?  I thought you need exactly matching
>>> libpthread and libthread_db versions anyway.  I suppose we could even
>>> compile the offsets into libthread_db.
>>
>> The thread_db interface appears to be generic enough to be able to cope
>> with different versions.
> 
> while true, i don't think that means you can mix & match.  we've always
> said glibc libs must be coherent (can't mix 2.15 libpthread with a 2.17
> libc), so i'm not sure why thread_db is any different.  

Yeah, I don't think it's any different.

Making libthread_db cope with multiple versions would be a bad design decision, IMO.
It'd be easy-ish to make it cope if just some constant offsets in data structures
change (e.g., to cope with new fields in structures) between glibc versions, but
if the data structures themselves change, like moving from linked lists to vectors
to hash tables, etc. things get complicated.

Sorting all that out, along with debugger x debuggee arch- and ABI-independence,
is the whole point of Infinity.

Thanks,
Pedro Alves
  

Patch

diff --git a/nptl/allocatestack.c b/nptl/allocatestack.c
index c044b20..d384397 100644
--- a/nptl/allocatestack.c
+++ b/nptl/allocatestack.c
@@ -113,7 +113,8 @@  static int stack_cache_lock = LLL_LOCK_INITIALIZER;
 static LIST_HEAD (stack_cache);
 
 /* List of the stacks in use.  */
-static LIST_HEAD (stack_used);
+list_t (__stack_used) __attribute__ ((nocommon));
+hidden_data_def (__stack_used)
 
 /* We need to record what list operations we are going to do so that,
    in case of an asynchronous interruption due to a fork() call, we
@@ -223,7 +224,7 @@  get_cached_stack (size_t *sizep, void **memp)
   stack_list_del (&result->list);
 
   /* And add to the list of stacks in use.  */
-  stack_list_add (&result->list, &stack_used);
+  stack_list_add (&result->list, &__stack_used);
 
   /* And decrease the cache size.  */
   stack_cache_actsize -= result->stackblock_size;
@@ -592,7 +593,7 @@  allocate_stack (const struct pthread_attr *attr, struct pthread **pdp,
 	  lll_lock (stack_cache_lock, LLL_PRIVATE);
 
 	  /* And add to the list of stacks in use.  */
-	  stack_list_add (&pd->list, &stack_used);
+	  stack_list_add (&pd->list, &__stack_used);
 
 	  lll_unlock (stack_cache_lock, LLL_PRIVATE);
 
@@ -781,7 +782,7 @@  __make_stacks_executable (void **stack_endp)
   lll_lock (stack_cache_lock, LLL_PRIVATE);
 
   list_t *runp;
-  list_for_each (runp, &stack_used)
+  list_for_each (runp, &__stack_used)
     {
       err = change_stack_perm (list_entry (runp, struct pthread, list)
 #ifdef NEED_SEPARATE_REGISTER_STACK
@@ -838,8 +839,8 @@  __reclaim_stacks (void)
 	     pointers at the head of the list are inconsistent.  */
 	  list_t *l = NULL;
 
-	  if (stack_used.next->prev != &stack_used)
-	    l = &stack_used;
+	  if (__stack_used.next->prev != &__stack_used)
+	    l = &__stack_used;
 	  else if (stack_cache.next->prev != &stack_cache)
 	    l = &stack_cache;
 
@@ -861,7 +862,7 @@  __reclaim_stacks (void)
 
   /* Mark all stacks except the still running one as free.  */
   list_t *runp;
-  list_for_each (runp, &stack_used)
+  list_for_each (runp, &__stack_used)
     {
       struct pthread *curp = list_entry (runp, struct pthread, list);
       if (curp != self)
@@ -905,7 +906,7 @@  __reclaim_stacks (void)
     }
 
   /* Add the stack of all running threads to the cache.  */
-  list_splice (&stack_used, &stack_cache);
+  list_splice (&__stack_used, &stack_cache);
 
   /* Remove the entry for the current thread to from the cache list
      and add it to the list of running threads.  Which of the two
@@ -913,13 +914,13 @@  __reclaim_stacks (void)
   stack_list_del (&self->list);
 
   /* Re-initialize the lists for all the threads.  */
-  INIT_LIST_HEAD (&stack_used);
+  INIT_LIST_HEAD (&__stack_used);
   INIT_LIST_HEAD (&__stack_user);
 
   if (__glibc_unlikely (THREAD_GETMEM (self, user_stack)))
     list_add (&self->list, &__stack_user);
   else
-    list_add (&self->list, &stack_used);
+    list_add (&self->list, &__stack_used);
 
   /* There is one thread running.  */
   __nptl_nthreads = 1;
@@ -945,7 +946,7 @@  __find_thread_by_id (pid_t tid)
 
   /* Iterate over the list with system-allocated threads first.  */
   list_t *runp;
-  list_for_each (runp, &stack_used)
+  list_for_each (runp, &__stack_used)
     {
       struct pthread *curp;
 
@@ -1098,7 +1099,7 @@  __nptl_setxid (struct xid_command *cmdp)
 
   /* Iterate over the list with system-allocated threads first.  */
   list_t *runp;
-  list_for_each (runp, &stack_used)
+  list_for_each (runp, &__stack_used)
     {
       struct pthread *t = list_entry (runp, struct pthread, list);
       if (t == self)
@@ -1124,7 +1125,7 @@  __nptl_setxid (struct xid_command *cmdp)
     {
       signalled = 0;
 
-      list_for_each (runp, &stack_used)
+      list_for_each (runp, &__stack_used)
 	{
 	  struct pthread *t = list_entry (runp, struct pthread, list);
 	  if (t == self)
@@ -1154,7 +1155,7 @@  __nptl_setxid (struct xid_command *cmdp)
 
   /* Clean up flags, so that no thread blocks during exit waiting
      for a signal which will never come.  */
-  list_for_each (runp, &stack_used)
+  list_for_each (runp, &__stack_used)
     {
       struct pthread *t = list_entry (runp, struct pthread, list);
       if (t == self)
@@ -1218,7 +1219,7 @@  __pthread_init_static_tls (struct link_map *map)
 
   /* Iterate over the list with system-allocated threads first.  */
   list_t *runp;
-  list_for_each (runp, &stack_used)
+  list_for_each (runp, &__stack_used)
     init_one_static_tls (list_entry (runp, struct pthread, list), map);
 
   /* Now the list with threads using user-allocated stacks.  */
@@ -1239,7 +1240,7 @@  __wait_lookup_done (void)
 
   /* Iterate over the list with system-allocated threads first.  */
   list_t *runp;
-  list_for_each (runp, &stack_used)
+  list_for_each (runp, &__stack_used)
     {
       struct pthread *t = list_entry (runp, struct pthread, list);
       if (t == self || t->header.gscope_flag == THREAD_GSCOPE_FLAG_UNUSED)
diff --git a/nptl/descr.h b/nptl/descr.h
index 8e4938d..87c5354 100644
--- a/nptl/descr.h
+++ b/nptl/descr.h
@@ -160,7 +160,7 @@  struct pthread
     void *__padding[24];
   };
 
-  /* This descriptor's link on the `stack_used' or `__stack_user' list.  */
+  /* This descriptor's link on the `__stack_used' or `__stack_user' list.  */
   list_t list;
 
   /* Thread ID - which is also a 'is this thread descriptor (and
diff --git a/nptl/nptl-init.c b/nptl/nptl-init.c
index bdbdfed..9bde618 100644
--- a/nptl/nptl-init.c
+++ b/nptl/nptl-init.c
@@ -384,6 +384,7 @@  __pthread_initialize_minimal_internal (void)
   THREAD_SETMEM (pd, stackblock_size, (size_t) __libc_stack_end);
 
   /* Initialize the list of all running threads with the main thread.  */
+  INIT_LIST_HEAD (&__stack_used);
   INIT_LIST_HEAD (&__stack_user);
   list_add (&pd->list, &__stack_user);
 
diff --git a/nptl/pthreadP.h b/nptl/pthreadP.h
index 4edc74b..e762f94 100644
--- a/nptl/pthreadP.h
+++ b/nptl/pthreadP.h
@@ -183,7 +183,9 @@  extern int __is_smp attribute_hidden;
 
 /* Thread descriptor handling.  */
 extern list_t __stack_user;
+extern list_t __stack_used;
 hidden_proto (__stack_user)
+hidden_proto (__stack_used)
 
 /* Attribute handling.  */
 extern struct pthread_attr *__attr_list attribute_hidden;
diff --git a/nptl/pthread_create.c b/nptl/pthread_create.c
index 5216041..ec49b15 100644
--- a/nptl/pthread_create.c
+++ b/nptl/pthread_create.c
@@ -87,7 +87,7 @@  __find_in_stack_list (struct pthread *pd)
 
   lll_lock (stack_cache_lock, LLL_PRIVATE);
 
-  list_for_each (entry, &stack_used)
+  list_for_each (entry, &__stack_used)
     {
       struct pthread *curp;
 
diff --git a/nptl_db/structs.def b/nptl_db/structs.def
index a9b621b..ebcc065 100644
--- a/nptl_db/structs.def
+++ b/nptl_db/structs.def
@@ -70,7 +70,7 @@  DB_STRUCT (td_eventbuf_t)
 DB_STRUCT_FIELD (td_eventbuf_t, eventnum)
 DB_STRUCT_FIELD (td_eventbuf_t, eventdata)
 
-DB_SYMBOL (stack_used)
+DB_SYMBOL (__stack_used)
 DB_SYMBOL (__stack_user)
 DB_SYMBOL (nptl_version)
 DB_FUNCTION (__nptl_create_event)
diff --git a/nptl_db/td_ta_thr_iter.c b/nptl_db/td_ta_thr_iter.c
index a990fed..aae4dd2 100644
--- a/nptl_db/td_ta_thr_iter.c
+++ b/nptl_db/td_ta_thr_iter.c
@@ -38,15 +38,22 @@  iterate_thread_list (td_thragent_t *ta, td_thr_iter_f *callback,
   if (err != TD_OK)
     return err;
 
-  if (next == 0 && fake_empty)
+  if (next == 0)
     {
       /* __pthread_initialize_minimal has not run.  There is just the main
 	 thread to return.  We cannot rely on its thread register.  They
 	 sometimes contain garbage that would confuse us, left by the
 	 kernel at exec.  So if it looks like initialization is incomplete,
 	 we only fake a special descriptor for the initial thread.  */
-      td_thrhandle_t th = { ta, 0 };
-      return callback (&th, cbdata_p) != 0 ? TD_DBERR : TD_OK;
+      if (fake_empty)
+	{
+	  td_thrhandle_t th = { ta, 0 };
+
+	  if (callback (&th, cbdata_p) != 0)
+	    return TD_DBERR;
+	}
+
+      return TD_OK;
     }
 
   /* Cache the offset from struct pthread to its list_t member.  */
@@ -161,7 +168,7 @@  td_ta_thr_iter (const td_thragent_t *ta_arg, td_thr_iter_f *callback,
 
   /* And the threads with stacks allocated by the implementation.  */
   if (err == TD_OK)
-    err = DB_GET_SYMBOL (list, ta, stack_used);
+    err = DB_GET_SYMBOL (list, ta, __stack_used);
   if (err == TD_OK)
     err = iterate_thread_list (ta, callback, cbdata_p, state, ti_pri,
 			       list, false, pid);
diff --git a/nptl_db/td_thr_validate.c b/nptl_db/td_thr_validate.c
index f3c8a7b..34b6112 100644
--- a/nptl_db/td_thr_validate.c
+++ b/nptl_db/td_thr_validate.c
@@ -70,7 +70,7 @@  td_thr_validate (const td_thrhandle_t *th)
      using implementation allocated stacks.  */
   if (err == TD_NOTHR)
     {
-      err = DB_GET_SYMBOL (list, th->th_ta_p, stack_used);
+      err = DB_GET_SYMBOL (list, th->th_ta_p, __stack_used);
       if (err == TD_OK)
 	err = check_thread_list (th, list, &uninit);