For .NET threads, the following works for "normal" Thread
s (manually created threads, since I don't know a way to name threadpool threads):
A Thread
is a class and thus can be found in the .NET managed heap:
0:000>.loadby sos clr
0:000> !dumpheap -stat -type Thread
MT Count TotalSize Class Name
...
725e4960 11 572 System.Threading.Thread
Note that there is other output as well, since !dumpheap
looks for parts of class names. The Method Table (MT) however, identifies a class uniquely, so that's what we use from now on:
0:000> !dumpheap -short -mt 725e4960
023123d0
02312464
02313c80
...
These are the addresses of Thread
objects. Since it is clean output, we can use it in a loop:
0:000> .foreach (address {!dumpheap -short -mt 725e4960}) {.echo ${address} }
023123d0
02312464
02313c80
...
Inside the loop, we can use the address to get more information about the thread. First, let's find out how a Thread looks like internally:
0:000> !do 023123d0
Name: System.Threading.Thread
...
Fields:
MT Field Offset Type VT Attr Value Name
...
725e3e18 400076e c System.String 0 instance 02313c0c m_Name
...
At offset +0xC
(depending on the bitness!), there's the m_Name
member. That's a string. Let's find out how a string looks like:
0:000> !do poi(023123d0+c)
Name: System.String
...
Fields:
MT Field Offset Type VT Attr Value Name
...
725e4810 40000ac 8 System.Char 1 instance 4d m_firstChar
So, the first character of the string is at offset +0x08
. Strings in .NET are Unicode, so we can view it with du
:
0:000> du poi(023123d0+c)+8
02313c14 "My named thread 0"
Combine all this knowledge into a single command:
.foreach (address {!dumpheap -short -mt 725e4960})
{
du poi(${address}+c)+8
}
(formatted for readability, put it all in one line)
If you try that, you'll find that it may output something like
00000008 "????????????????????????????????"
This happens when m_Name
is null
. If you care about that, you can add a check for null:
.foreach (address {!dumpheap -short -mt 725e4960})
{
.if (poi(${address}+c) != 0) {
du poi(${address}+c)+8
}
}
(formatted for readability, put it all in one line)
Other improvements:
- do the same for the thread ID
- prettify output (use
.printf
instead of dd
and du
)
Final result:
.foreach (address {!dumpheap -short -mt 725e4960})
{
.if (poi(${address}+c) != 0)
{
.printf "%d ",poi(${address}+28);
.printf "%mu\r\n", poi(${address}+c)+8
}
}