Archive for May, 2009

Why do I get “No prior disassembly possible”?

Friday, May 29th, 2009

Have you ever scrolled back through the disassembly window (Alt+7) and come across the “No prior disassembly possible” error? Here’s an example, I brought the window up at address 0x8088bd69 and scrolled up until I hit an error, which happened at address 0x8088bd01:

d01

It can be pretty annoying, you know there’s more code there so why can’t WinDBG disassemble it? The problem is going to lie in the fact that the x86 and x64 use a variable length instruction set. WinDBG takes the opcode bytes (second column in the picture above) and uses its built in disassembler to translate those bytes into instructions. For example, in this case the current instruction is 00c0, which we can find in the Intel reference manual under the add documentation:

00 /r ADD r/m8, r8 Valid Valid Add r8 to r/m8.

When scrolling backwards, there’s nothing that tells WinDBG, “the previous instruction is x bytes long”, it just knows how long the current instruction is. Once the current instruction is decoded, WinDBG  starts to look backwards for the previous instruction by decoding bytes and looking for matching instructions in its disassembler. In some cases, WinDBG may get unlucky and find that the tail bytes of the previous instruction decode to a completely different instruction! If that happens, the next set of bytes may not decode into any known instruction and that’s how you end up in, “No prior disassembly” land.

The solution in this case can be quite simple. Let’s just go back one byte at a time by changing the value in the Offset box:

d00

Still nothing…Try the next byte…

cff

Still nothing…Try the next byte…

cfe

Tada! The entire window snapped to life. The current cursor was reset to the middle of the window and we get the nice listing that we were expecting. If you look at address 0x8088bd01, you see that it’s in the middle of the second operand to the cmp instruction (0xC00000FD). WinDBG decoded the 00c0 bytes into an add al,al, then was unable to translate the next bytes into any known instruction.

!running

Thursday, May 21st, 2009

A student last week pointed me to a command that I had never used before, !running. !running allows you to quickly view the thread information from the PRCBs of each processor:

0: kd> !running
System Processors 3 (affinity mask)
  Idle Processors 0
Prcbs  Current   Next
  0    ffdff120  84d68020            ................
  1    f7737120  84da63e8  86392300  ................

Note that there is a formatting bug in the output, the “Prcbs Current Next”  header needs to be tabbed over once,  so that the Prcbs heading is over ffdff120, Current is over 84d68020, etc (I’ve filed a bug so hopefully it will be fixed in a future version).

!running also takes a couple of parameters to control the output:

-i
Causes the display to include idle processors as well.
-t
Causes a stack trace to be displayed for each processor.

This makes executing !running -t on a multi-proc dump a quick way to determine what’s going on on the currently active processors. This can be very useful when debugging a potential race condition, where the other active processors can contain interesting or valuable information.

That’s some ugly formatting

Wednesday, May 20th, 2009

Clearly I need to come up with a better system of posting very wide debugger output (and hopefully by the time we have 128bit pointers we’re all on very high resolution monitors).

What are the “Args to Child” in the kv output?

Wednesday, May 20th, 2009

The “Args to Child” label is one of the most misleading things you’ll come across in a WinDBG session. Here’s a stack from a laptop crash I had:

0: kd> kv
  *** Stack trace for last set context - .thread/.cxr resets it
ChildEBP RetAddr  Args to Child
ba50b8c0 b9e390a8 000335e5 89bc65f4 000000fe nt!ObQueryNameString+0x9b (FPO: [Non-Fpo])
ba50b8e8 b9e2eb4e 000335e5 89bc65e0 00000144 fltmgr!FltpGetObjectName+0x24 (FPO: [2,1,4])
ba50b944 b9e2eddc 8609b718 8055ae90 89aff030 fltmgr!FltpEnumerateFileSystemVolumes+0x138 (FPO: [Non-Fpo])
ba50b998 b9e330eb 89aff030 ba50b9ac 89c4849c fltmgr!FltpAttachToFileSystemDevice+0x142 (FPO: [Non-Fpo])
ba50bac4 b9e334d4 89aff030 00000001 ba50baf0 fltmgr!FltpFsNotificationActual+0x47 (FPO: [2,70,4])
ba50bad4 80574908 89aff030 00000001 84dfe004 fltmgr!FltpFsNotification+0x1c (FPO: [2,0,0])
ba50baf0 b9e3413d 8a6f5850 b9e334b8 b9e2d8e0 nt!IoRegisterFsRegistrationChange+0xcc (FPO: [2,0,4])
ba50bb58 b9e3431e 861eabc8 861eabbc 862ecc08 fltmgr!FltpAttachFrame+0x121 (FPO: [Non-Fpo])
ba50bba4 b9e3b6e1 861eaba8 861eabc8 862ecc08 fltmgr!FltpFindFrameForFilter+0xa8 (FPO: [Non-Fpo])
ba50bc08 990cb284 862ecc08 990ce650 990ceb68 fltmgr!FltRegisterFilter+0x295 (FPO: [Non-Fpo])
WARNING: Stack unwind information not available. Following frames may be wrong.
ba50bc74 990c851f 862ecc08 e13cf65c ba50bd54 PROCMON13+0x3284
ba50bc84 80581377 862ecc08 86106000 00000000 PROCMON13+0x51f
ba50bd54 80581487 80000050 00000001 00000000 nt!IopLoadDriver+0x66d (FPO: [4,45,0])
ba50bd7c 8053877d 80000050 00000000 8a7133c8 nt!IopLoadUnloadDriver+0x45 (FPO: [1,1,4])
ba50bdac 805cff70 98d7fcf4 00000000 00000000 nt!ExpWorkerThread+0xef (FPO: [1,6,0])
ba50bddc 805460ee 8053868e 00000001 00000000 nt!PspSystemThreadStartup+0x34 (FPO: [Non-Fpo])
00000000 00000000 00000000 00000000 00000000 nt!KiThreadStartup+0x16

In this case, I don’t have private PDBs with parameter information. So how does WinDBG know what the arguments to the routines are? Also, to confuse things even more, IoRegisterFsRegistrationChange only takes two parameters:

NTSTATUS
IoRegisterFsRegistrationChange(
IN PDRIVER_OBJECT DriverObject,
IN PDRIVER_FS_NOTIFICATION DriverNotificationRoutine
);

So why does WinDBG show three args?

ba50baf0 b9e3413d 8a6f5850 b9e334b8 b9e2d8e0 nt!IoRegisterFsRegistrationChange+0xcc (FPO: [2,0,4])

The answer is that WinDBG is lying to you, it has no idea if these values are arguments to the routine or not!

On the x86, the “Args to Child” column in the kv output assumes that each routine is using an EBP frame. In an EBP frame, EBP points to the previous EBP, EBP+4 points to the return address, EBP+8 points to the first thing on the stack after the return address, and so on. If the routine isn’t using fastcall, EBP+8 will be the first parameter. If the routine is using fastcall, EBP+8 will be the third parameter to the routine (first parameter will be in ECX and the second in EDX). All “Args to Child” shows is the contents of EBP+8, EBP+C, and EBP+10.

So, in order for this output to be correct three things must be true:

1) The specified routine does indeed use an EBP frame, which can be optimized out of the binary using the /Oy compiler switch.

2) The specified routine actually takes 3 or more parameters and doesn’t use fastcall

3) The specified routine does not reuse the parameter location for some other value. It’s not uncommon for the optimizer to decide to overwrite a parameter if it is of no more use to the routine.

Therefore it is important to be careful before trusting these values in any way!

More details on EBP frames and calling conventions can be found in this great article from long ago:

http://www.microsoft.com/msj/0298/hood0298.aspx

Note that these fields also appear on the x64 platform:

0: kd> kv
  *** Stack trace for last set context - .thread/.cxr resets it
Child-SP          RetAddr           : Args to Child                                                           : Call Site
fffffade`4e4fe8c0 fffff800`01027652 : 00000000`0000000f 00000000`00000000 00000000`000001a4 fffff800`011b3180 : nt!KiSwapContext+0x85
fffffade`4e4fea40 fffff800`01024f20 : 00000000`00000000 00000000`00000001 fffffadf`f845da10 fffff800`011b3180 : nt!KiSwapThread+0x3c9
fffffade`4e4feaa0 fffff800`01282c26 : 00000000`00000000 00000000`00000001 00000000`00000000 00000000`00000000 : nt!KeRemoveQueue+0x656
fffffade`4e4feb20 fffff800`0102e43d : 00000000`00000000 fffffadf`a44e2c68 00000000`000c9f00 fffffade`4e4fecf0 : nt!NtRemoveIoCompletion+0x13c
fffffade`4e4fec00 00000000`77ef0a7a : 00000000`00000000 00000000`00000000 00000000`00000000 00000000`00000000 : nt!KiSystemServiceCopyEnd+0x3 (TrapFrame @ fffffade`4e4fec70)
00000000`01dafce8 00000000`00000000 : 00000000`00000000 00000000`00000000 00000000`00000000 00000000`00000000 : 0x77ef0a7a

In the case of the x64, the output is showing you the first four things on the stack after the return address. This is the start of the “spill” or “home” space for the first four arguments to the routine, so it may contain copies of the first parameters, it may contain non-volatile registers, it may contain neither,  or it may contain both! So again we have to be sure to not trust these fields implicitly.

The x64 ABI is fully documented by MS, but a short and clear description can be found here:

http://uninformed.org/?v=4&a=1

Calling conventions are really just conventions…

Saturday, May 9th, 2009

In doing some work to update IrpTracker for Vista, I noticed something pretty strange.

A new API call was added in the IoCallDriver path. As of Vista, IoCallDriver makes a call to IopPoHandleIrp for any power IRPs that it receives. This API takes care of the work that used to be handled by PoCallDriver/PoStartNextPowerIrp (which is goodness, it was pretty annoying to have to special case the power IRP path). What’s so strange about this, you ask? Well, what’s strange is the calling convention used by IopPoHandleIrp and its helper routines.

Calling conventions on the x86 are pretty well known. In most cases parameters are passed on the stack, with the exception of fastcall where the first two parameters are passed in ECX and EDX (respectively) and the remaining parameters passed on the stack. C++ is actually a special case of fastcall, where the “this” pointer is passed in ECX and the first parameter is in EDX. While if you’re debugging hand written assembly you’re on you’re own, in general the compiler sticks to these conventions and you can count on them when debugging. You can imagine my surprise then when analyzing IopPoHandleIrp:

0:000> uf IopPoHandleIrp
ntkrnlmp!IopPoHandleIrp:
0042b546 mov     edi,edi ; This module was linked with /hotpatch
0042b548 push    ebp
0042b549 mov     ebp,esp ; standard EBP frame
0042b54b push    ecx
0042b54c push    ecx
0042b54d lea     eax,[ebp-4]
0042b550 push    eax
0042b551 mov     eax,esi ; Whoa! This API uses ESI without ever having loaded it!
0042b553 call    ntkrnlmp!PoHandleIrp (0050eea8)

Pretty weird! No documented x86 calling convention loads ESI with a valid value for the called function. So, strange to see a subroutine assume that the contents of ESI are valid within its frame. Clearly the compiler decided that ESI was the best way to pass a parameter to this routine and that makes things difficult for anyone that might want to call this API (it’s going to require hand written assembly to load ESI before making the call).

Digging further here, more results are in PoHandleIrp:

0:000> uf PoHandleIrp
ntkrnlmp!PoHandleIrp:
0050eea8 mov     edi,edi ; /hotpatch
0050eeaa push    ebp
0050eeab mov     ebp,esp ; EBP frame
0050eead sub     esp,18h ; Make room for local variables
0050eeb0 push    ebx
0050eeb1 push    esi
0050eeb2 push    edi
0050eeb3 mov     esi,eax ; Save EAX! Why save it? Must contain something important...
0050eeb5 call    dword ptr [ntkrnlmp!_imp__KeGetCurrentIrql (004011d0)]
0050eebb cmp     al,2 ; EAX is overwritten with the result of the above API call
0050eebd jbe     ntkrnlmp!PoHandleIrp+0x19 (0050eec1)
ntkrnlmp!PoHandleIrp+0x17:
0050eebf int     2Ch ; Assertion failure
ntkrnlmp!PoHandleIrp+0x19:
0050eec1 test    esi,esi ; ESI came from EAX, so EAX assumed to be set up by the caller!
0050eec3 jne     ntkrnlmp!PoHandleIrp+0x1f (0050eec7)

We again have an API that conforms to no known calling convention as it assumes that EAX contains some valid value set up by the caller.

The lesson here? Calling conventions on the x86 are just that, conventions. Keep your head about you when performing an analysis of a function and tracing the arguments!