I'm a bit confused about the use of .foreach
together with ~e
, because that's somehow duplicate (just the fact that you're limiting ~e
to one thread doesn't result in a nested loop).
Is the command
~*e .logopen /t d:\debug\log.txt; !dumpstack; !clrstack; !dso; kb 200; .logclose
sufficient for you? The log file name will not have the thread ID.
Regarding your skip tokens of .foreach
, I think you can only use /pS
and /ps
once. Your statement is equivalent to
.foreach /pS 5 /ps 3 (l {!runaway}) { ... }
If the thread ID really matters
It seems that the OS thread IDs are really important.
As using .foreach
directly on any command like !threads
, ~
or !runaway
seems not flexible and reliable enough, I propose to use .shell find
to get at least some consistency in output.
I'll use !teb
to get the thread ID, because it is separated by a space and therefore the output of .shell find
can be used as input for .foreach
.
The complete command I come up with:
~*e .foreach /pS 3 /ps 20 (tid {.shell -ci "!teb" find "ClientId"}) { .logopen d:\debug\logs\log${tid}.txt; !dumpstack; !clrstack; !dso; kb 200; .logclose}
Using pykd as an extension
Using PyKd - Python extension for WinDbg, the result can be achieved like this:
Create a file tid.py, put it next to the pykd.pyd extension and give it the following content:
from pykd import *
threads = getProcessThreads()
for t in threads:
print(hex(ptrPtr(t+0x24))[2:-1])
getProcessThreads()
gives you the addresses of the TEBs. At offset 0x24 you can find the thread ID. ptrPtr()
reads a memory address, hex()
is self-explaining, [2:
removes the 0x head and :-1]
removes the trailing L (don't ask me why it has a trailing L).
In WinDbg
.load pykd.pyd
!py tid.py; *** Gives one thread ID per line, nice for .foreach
.foreach (tid {!py tid.py}) { .logopen d:\debug\logs\log_${tid}.txt; ~~[${tid}]s; !dumpstack; !clrstack; !dso; kb 200; .logclose}