Ah! So that is why ntoskrnl is mentioned often in various dump files.
Yes. To add to what usasma has already said, and to put it a slightly different way, ntoskrnl (or equivalent, e.g. when PAE is enabled) usually gets blamed due to the call stack. I don't know how much you know about programming, but very simply (and this is an extreme oversimplification, but there is plenty of advanced reading on the internet, should you be interested in the advanced details. For example, I am mixing usermode and kernel mode in ways which you can't really, but works for my example) blocks of code are called functions. These blocks of code call other blocks of code, and these call yet more blocks of code, perhaps even in a separate module (file, simplistically), and the end result is a long chain of code calling other code.
Look at this stack excerpt:
nt!KeBugCheckEx
nt!KiBugCheckDispatch+0x69
nt!KiPageFault+0x260
nt!MiInsertPageInFreeOrZeroedList+0x54c
Here,
nt!MiInsertPageInFreeOrZeroedList calls
nt!KiPageFault, which calls
nt!KiBugCheckDispatch, which calls
nt!KeBugCheckEx.
Now look at this ficticious stack
nt!KernelCreateNewThread+0x08
MyProgram!CreateNewThread+0x08
MyProgram!Main+0x08
Main is the name given to the first function called in a new process (well, sometimes at least!). Notice how MyProgram starts off, calls CreateNewThread which decides the settings which the new thread will be created with, and then passes those settings to the kernel to actually create the thread. Basically everything has to go through the kernel at some point, and this means that the kernel almost always ends up on the call stack somewhere.
But why have a stack at all? Well, the kernel has now created this new thread, but it personally doesn't have a use for it. MyProgram is what wants it. And so the kernel must keep a record of who wanted the thread object, so that it can be returned to that bit of code. This is where the stack comes in. Notice how the stack shows that MyProgram!CreateNewThread is who wanted the object? So the kernel beings a
stack unwind, and starts crawling back up the stack, until it gets to the block of code which wants the new thread.
Stacks are kept absolutely up to date. Whenever a function is called, it is
pushed onto the stack. Whenever a function is returned, it is
popped from the stack.
So...
the stack starts off as MyProgram!Main+0x08
When CreateNewThread is called, it is pushed onto the stack, creating
MyProgram!CreateNewThread+0x08
MyProgram!Main+0x08
When CreateNewThread calls KernelCreateNewThread (in ntoskrnl, coincidentally), that is also pushed onto the stack...
nt!KernelCreateNewThread+0x08
MyProgram!CreateNewThread+0x08
MyProgram!Main+0x08
When KernelCreateNewThread is finished, and returns the new thread, it is popped:
MyProgram!CreateNewThread+0x08
MyProgram!Main+0x08
CreateNewThread's job is done, it then immediately returns the new thread also, and so it returns and is popped...
MyProgram!Main+0x08
Now the Main method wants to use the thread object, so it calls and pushes...
MyProgram!UseNewThread+0x08
MyProgram!Main+0x08
which eventually completes, returns, and pops:
MyProgram!Main+0x08
Finally, when the program is ready to quit, Main returns and pops (it returns back to the kernel code which created the new process).
That is the stack...very simplistically.
In this stack:
nt!KernelCreateNewThread+0x08
MyProgram!CreateNewThread+0x08
MyProgram!Main+0x08
!analyze -v will correctly identify MyProgram as the cause of any bugs (which there aren't in this ficticious example)
But now let us assume there is a bug:
nt!KernelCreateNewThread+0x08
MyProgram!CreateNewProcess+0x08
MyProgram!Main+0x08
This is very wrong. Assume here that Main calls CreateNewProcess, expecting a new process to be created. CreateNewProcess sets up all the settings as though it will create a new process. But then, accidentally (read BUG!), it calls nt!KernelCreateNewThread, instead of nt!KernelCreateNewProcess, passing process data to a thread function.
Windows will become really confused here. What is nt!KernelCreateNewThread supposed to do with process data? It has no idea. It crashes = BSOD.
nt!KernelCreateNewThread is not buggy though. It was passed bad data, and didn't know what to do with it. MyProgram!CreateNewProcess is what is buggy, by calling the wrong kernel mode function. MyProgram needs updating, in the hope that this bug has been fixed.
In the above call stack, MyProgram should get the blame.
But now let us assume that there has been a stack trash. This call stack:
nt!KernelCreateNewThread+0x08
MyProgram!CreateNewProcess+0x08
MyProgram!Main+0x08
becomes this:
nt!KernelCreateNewThread+0x08
0x7c90eb94+0x08
What is the only driver remaining? nt (ntoskrnl). Was nt!KernelCreateNewThread really at fault? No. Can analyze -v do anything other than blame ntoskrnl? No. Does it do just that? Yes.
There. Now you see ntoskrnl getting the blame, even though it wasn't buggy, but still for a very good reason.
P.S. There are many other reasons why a driver might not show other than a stack trash. Stack trashes almost always result in 0x1E crashed. I will try to get an example soon. There are a good two pages in Windows Internals on stack trashes if still interested, though.
Hope this helps.
Richard