Process Hacker Discussion Forum

User avatar
Posts: 948
Joined: 17 Jan 2011 05:19
OS: Windows

Thread stacks reference

17 Jan 2011 11:18

Threads can be examined in Process Hacker by double-clicking them or right-clicking and selecting "Inspect". This opens a new window showing you the thread's stack trace, call stack, or whatever else you want to call it. The stack trace is a powerful tool you can use to tell what a thread is doing at a moment in time.


Functions are essential to programmers, and one of the reasons is because they provide a way of re-using and structuring code. For example, I might write some mathematical code which uses the sin function. In some other code I might use sin again. But I only have to write the sin calculation code once.

Look at the following stack trace:
Each line has three parts:

module!function+displacement (e.g. ntdll.dll!NtWaitForMultipleObjects+0xc)

The stack trace works bottom-up; so BaseThreadInitThunk decided to call mainCRTStartup, which called another function which eventually called the TestHang function. Note that the displacement values (0xe, 0xf, 0x117, etc.) indicate the return address, not the point at which the function was called. so TestHang will jump back to main plus 44 bytes when it finishes running. That's also why you see KiFastSystemCallRet at the top of the user-mode stack trace.

Note that you'll often see these other lines:

module+offset (e.g. somedll.dll+0x1234) address (e.g. 0x12345678)

This usually indicates symbols are missing or something unusual (like .NET's JIT).

Kernel-mode vs. user-mode

In most versions of Windows Process Hacker will show you the kernel-mode stack trace as well. This is not usually very important, but can be useful sometimes. The kernel-mode part of the stack trace usually begins with the module being the kernel; in this case it's ntkrnlpx.exe. On most machines look for ntkrnlpa.exe and ntoskrnl.exe.

Most of the time you will see names such as KeWaitForSingleObject or KeWaitForMultipleObjects in the kernel-mode stack trace. This indicates that the thread is waiting for something to happen and is not running anything. The reason it is common to see this is simply because most threads running in most proceses simply don't do very much; they wait for some external event, process it, and get back to waiting. It's most likely you'll catch the thread while it's sleeping.

Here's what it looks like when a thread is doing some heavy processing in user-mode:
Compare this with the first stack trace. You'll see that there's no ntdll.dll stack frame because the thread isn't making a system call (or calling any of ntdll.dll's functions). The first kernel-mode frame has HalpIpiHandler. The reason this appears is due to the way in which Process Hacker gets kernel-mode stack traces: it queues a special kernel-mode APC to the thread which performs a stack trace inside the thread itself. So in this case you can see Process Hacker had to interrupt this particular program (which the kernel did with an interrupt) to get its kernel-mode stack trace. This type of stack trace indicates that the program (which is eating away at your available CPU time) is some kind of infinite loop or is simply taking a very long time to do whatever it's doing (e.g. audio/video encoding).