.NET Zone is brought to you in partnership with:

Sasha Goldshtein is a Senior Consultant for Sela Group, an Israeli company specializing in training, consulting and outsourcing to local and international customers.Sasha's work is divided across these three primary disciplines. He consults for clients on architecture, development, debugging and performance issues; he actively develops code using the latest bits of technology from Microsoft; and he conducts training classes on a variety of topics, from Windows Internals to .NET Performance. You can read more about Sasha's work and his latest ventures at his blog: http://blogs.microsoft.co.il/blogs/sasha. Sasha writes from Herzliya, Israel. Sasha is a DZone MVB and is not an employee of DZone and has posted 204 posts at DZone. You can read more from them at their website. View Full User Profile

Obscure WinDbg Commands, Part 1

08.13.2013
| 2264 views |
  • submit to reddit

I’m starting a short post series today covering some obscure WinDbg commands. Some of these are fairly useful, others are mostly good for extracting “wows” from your coworkers. Still, there’s a lot of ground to cover.

Today’s two commands deal with inspecting thread call stacks. Real-world processes might have hundreds of threads in them, and figuring out who’s who can be pretty time-consuming. This is especially true if you are using the thread pool (.NET, Win32, or even your own), which often means you have dozens of thread pool threads waiting idly for work.

The !uniqstack command can help in these situations. It enumerates all the thread call stacks and eliminates duplicates, so that you can understand at a glance what these hundreds of threads are doing.

0:021> !uniqstack 
Processing 22 threads, please wait 

.  0  Id: 464.ca8 Suspend: 1 Teb: 7f9dd000 Unfrozen 
  Start: SillyThreadPool!ILT+120(_wmainCRTStartup) (00ed107d) 
  Priority: 0  Priority class: 32  Affinity: ff 
ChildEBP RetAddr 
00a6f510 76e0cfb2 ntdll!NtReadFile+0xc 
00a6f578 5285d9de KERNELBASE!ReadFile+0x10e 
00a6f62c 5285d19c MSVCR110D!_read_nolock+0x7be 
00a6f684 527a4246 MSVCR110D!_read+0x24c 
00a6f6b4 527a26b3 MSVCR110D!_filbuf+0x126 
00a6f714 527a2708 MSVCR110D!getc+0x223 
00a6f720 527a2718 MSVCR110D!_fgetchar+0x18 
00a6f728 00ed14ca MSVCR110D!getchar+0x8 
00a6f808 00ed1a49 SillyThreadPool!wmain+0x7a 
00a6f858 00ed1c3d SillyThreadPool!__tmainCRTStartup+0x199 
00a6f860 7755850d SillyThreadPool!wmainCRTStartup+0xd 
00a6f86c 77d1bf39 KERNEL32!BaseThreadInitThunk+0xe 
00a6f8b0 77d1bf0c ntdll!__RtlUserThreadStart+0x72 
00a6f8c8 00000000 ntdll!_RtlUserThreadStart+0x1b

.  1  Id: 464.13d4 Suspend: 1 Teb: 7f9da000 Unfrozen 
  Start: SillyThreadPool!ILT+265(?MyThreadPoolWorkerYGKPAXZ) (00ed110e) 
  Priority: 0  Priority class: 32  Affinity: ff 
ChildEBP RetAddr 
00d3f7b8 76e01129 ntdll!NtWaitForSingleObject+0xc 
00d3f824 76e010b4 KERNELBASE!WaitForSingleObjectEx+0x8f 
00d3f838 00ed141e KERNELBASE!WaitForSingleObject+0x12 
00d3f914 7755850d SillyThreadPool!MyThreadPoolWorker+0x2e 
00d3f920 77d1bf39 KERNEL32!BaseThreadInitThunk+0xe 
00d3f964 77d1bf0c ntdll!__RtlUserThreadStart+0x72 
00d3f97c 00000000 ntdll!_RtlUserThreadStart+0x1b

. 21  Id: 464.1574 Suspend: 1 Teb: 7f879000 Unfrozen 
  Start: ntdll!DbgUiRemoteBreakin (77d5dbeb) 
  Priority: 0  Priority class: 32  Affinity: ff 
ChildEBP RetAddr 
0279faa4 77d5dc24 ntdll!DbgBreakPoint 
0279fad4 7755850d ntdll!DbgUiRemoteBreakin+0x39 
0279fae0 77d1bf39 KERNEL32!BaseThreadInitThunk+0xe 
0279fb24 77d1bf0c ntdll!__RtlUserThreadStart+0x72 
0279fb3c 00000000 ntdll!_RtlUserThreadStart+0x1b

Total threads: 22 
Duplicate callstacks: 19 (windbg thread #s follow): 
2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20

In other cases, you’re specifically looking for one particular thread among many. Of course debugger automation can come handy here – you can dump the call stacks for all the threads (e.g. using the ~* e kncommand), and then parse the output. But there is an easier way: the !findstack command. This command searches thread call stacks for a specific symbol and displays matching threads.

0:021> !findstack kernelbase!WaitForSingleObject 
Thread 001, 2 frame(s) match 
  * 01 00d3f824 76e010b4 KERNELBASE!WaitForSingleObjectEx+0x8f 
  * 02 00d3f838 00ed141e KERNELBASE!WaitForSingleObject+0x12 

... snipped ... 

Thread 020, 2 frame(s) match 
  * 01 0265fac4 76e010b4 KERNELBASE!WaitForSingleObjectEx+0x8f 
  * 02 0265fad8 00ed141e KERNELBASE!WaitForSingleObject+0x12

I am posting short links and updates on Twitter as well as on this blog. You can follow me: @goldshtn

Published at DZone with permission of Sasha Goldshtein, author and DZone MVB. (source)

(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)