MANAGED DEBUGGING with WINDBG. Call Stacks. Part 3

Hi all,

This post is a continuation of MANAGED DEBUGGING with WINDBG. Call Stacks. Part 2.

CALL STACKS. Part 3

· Let's review previous commands:

Let’s see a sample where the debugger broke when “PlayWithArray” raised an exception. We can use the return address of the function it called, “mscorwks!JIT_RngChkFail”, to see where in “PlayWithArray” we were when the exception happened:

0:000> kL

ChildEBP RetAddr

0027e600 79f071ac KERNEL32!RaiseException+0x58

0027e660 79f9293a mscorwks!RaiseTheExceptionInternalOnly+0x2a8

0027e698 7a129a34 mscorwks!UnwindAndContinueRethrowHelperAfterCatch+0x70

0027e738 00371aad mscorwks!JIT_RngChkFail+0xb0

0027e780 003719fe WindowsApplication1!WindowsApplication1.Form1.PlayWithArray(Int32[])+0x55

...

0:000> !u 00371aad

Normal JIT generated code

WindowsApplication1.Form1.PlayWithArray(Int32[])

Begin 00371a58, size c0

00371a58 55 push ebp

...

00371aa0 8b4dc8 mov ecx,dword ptr [ebp-38h]

00371aa3 3b5104 cmp edx,dword ptr [ecx+4]

00371aa6 7205 jb WindowsApplication1!WindowsApplication1.Form1.PlayWithArray(Int32[])+0x55 (00371aad)

00371aa8 e8d67edb79 call mscorwks!JIT_RngChkFail (7a129983)

>>> 00371aad 03449108 add eax,dword ptr [ecx+edx*4+8]

00371ab1 7105 jno WindowsApplication1!WindowsApplication1.Form1.PlayWithArray(Int32[])+0x60 (00371ab8)

00371ab3 e8837fdb79 call mscorwks!JIT_Overflow (7a129a3b)

...

00371b16 5d pop ebp

00371b17 c3 ret

0:000> u 00371aa8

WindowsApplication1!WindowsApplication1.Form1.PlayWithArray(Int32[])+0x50 [C:\__WORKSHOP\Demos\BuggyNETApp\Form1.vb @ 135]:

...

Note how we used the unmanaged version of this command, u, to find out the source code line.

That line corresponds to the following VB.NET statement in “PlayWithArray”:

result += array(i)

It seems we got some exception when accessing the array... Can we tell why? Let’s give it a try:

0:000> !CLRStack -a

OS Thread Id: 0x1f3c (0)

ESP EIP

0027e6f0 77a1b09e [HelperMethodFrame: 0027e6f0]

0027e740 00371aad WindowsApplication1.Form1.PlayWithArray(Int32[])

PARAMETERS:

this = 0x0192f338

array = 0x01983d38

LOCALS:

0x0027e758 = 0x00000000

0x0027e754 = 0x00000006

0x0027e750 = 0x00000003

0x0027e744 = 0x00000000

0x0027e74c = 0x00000003

...

0:000> !da 0x01983d38

Name: System.Int32[]

MethodTable: 7912d7c0

EEClass: 7912d878

Size: 24(0x18) bytes

Array: Rank 1, Number of elements 3, Type Int32

Element Methodtable: 79102290

[0] 00000001

[1] 00000002

[2] 00000003

It seems we tried to access the element at index 3 of the array (the 4th element), but the array only has 3 elements.

How do I know which local corresponds to “i”? ILDASM may help here, because the locals it shows are in the same order as in !CLRStack. In our case, “i” is in the 3rd position:

// Code size 49 (0x31)

.maxstack 3

.locals init ([0] int32 PlayWithArray,

[1] int32 result,

[2] int32 i,

[3] class [mscorlib]System.Exception ex,

[4] int32 VB$CG$t_i4$S0)

· We can use registers to check parameters of a method in the call stack:

When we are at the beginning of a function, we must take into consideration that JIT compiler uses _fastcall calling convention. This means that the first two parameters will be passed in the ecx and edx registers. Ecx is used to hold the “this” pointer. We can use those registers to inspect the parameters:

0:000> g

Breakpoint 0 hit

eax=001a6e28 ebx=01ad8880 ecx=01a9f338 edx=01ada608 esi=01ada608 edi=01a9f338

eip=008f1a58 esp=002fe8a4 ebp=00000000 iopl=0 nv up ei ng nz na pe cy

cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000287

WindowsApplication1!WindowsApplication1.Form1.PlayWithArray(Int32[]):

008f1a58 55 push ebp

0:000> !CLRStack -p

OS Thread Id: 0x17fc (0)

ESP EIP

002fe8a4 008f1a58 WindowsApplication1.Form1.PlayWithArray(Int32[] )

PARAMETERS:

this = 0x01a9f338

array = 0x01ada608

...

002ff044 79e7c74b [GCFrame: 002ff044]

0:000> !do @ecx

Name: WindowsApplication1.Form1

...

0:000> !da @edx

Name: System.Int32[]

...

Array: Rank 1, Number of elements 3, Type Int32

...

Note that later in the function, esi is typically used to hold the “this” pointer (gotten from ecx).

Next post: MANAGED DEBUGGING with WINDBG. Threads. Part 1.

Index: MANAGED DEBUGGING with WINDBG. Introduction and Index.

Regards,

Alex (Alejandro Campos Magencio)