用WINDBG查看托管堆栈函数参数的值

我们在使用WINDBG 做LIVE debug时,经常需要在想停下来的函数上打个断点(打断点的方法我就不在这里说了,可以参看我以前的一些windbg随笔),然后用!clrstack -p 来看看调用堆栈和调用参数。但是如果函数的参数中如有泛型参数的时候,这种方法就有问题了。clrstack 的结果大致如下:

0:004> !clrstack -p
OS Thread Id: 0x1728 (4)
ESP       EIP     
0129e310 04f8d240 SystemService.CreateTCX12A.CreateTCSerials(ServiceInterface.Serials)
    PARAMETERS:
        this = 0x014e0088
        sourceSerials = 0x0142accc

0129e314 04f8d21c SystemService.PreDataHandle.GetTCSerials(ServiceInterface.Serials)
    PARAMETERS:
        this = 0x014e0158
        sourceSerials = 0x0142accc

0129e328 04f8d120 SystemService.WorkSheet.PreDataHandle()
    PARAMETERS:
        this = 0x014dfed0
。。。。。。
在我们可以很清楚的看到CreateTCSerials函数的参数,sourceSerials ,然后用!do 0x0142accc 指令看到参数的全貌。这是不包含泛型参数的函数堆栈信息。那么如果参数有泛型呢,那就不一样了。接下来用个例子来讲述。我有我的函数原型为:
public List<Serials> CalculateDISerials(List<Serials> SourceSerials, string CriterionSerialsName)
我在CalculateDISerials函数上打了一个断点,然后断下来后,我查看了一下堆栈信息,如下

0:009> !clrstack -p
OS Thread Id: 0xe34 (9)
ESP       EIP     
0391ec84 04f88647 SystemService.MainServiceProcess.CalculateDISerials(System.Collections.Generic.List`1<ServiceInterface.Serials>, System.String)
    PARAMETERS:
        this = 0x013165e4

0391ecd0 04f885ee SystemService.MainService.CalculateDISerials(System.Collections.Generic.List`1<ServiceInterface.Serials>, System.String)
    PARAMETERS:
        this = 0x01409c60

我很惊奇的发现,只要是泛型的参数这里就看不到了。那么怎么办呢?
我们知道C++和C#,在编译时,会默认把第一个this指针作为函数的第一个参数,同时在函数压栈时,参数是从左边到右,或者从右到左边依次入栈。函数的第一个参数地址入栈时,是被压入到ECX寄存器上,第二个参数是EDX寄存器上。那么我们找第一个参数和第二个参数的地址就容易了是吧。
0:009> !do edx
Name: System.Collections.Generic.List`1[[ServiceInterface.Serials, ServiceInterface]]
MethodTable: 03d64d04
EEClass: 7912f680
Size: 24(0x18) bytes
 (C:\WINDOWS\assembly\GAC_32\mscorlib\2.0.0.0__b77a5c561934e089\mscorlib.dll)
Fields:
      MT    Field   Offset                 Type VT     Attr    Value Name
7912d8f8  40009c7        4      System.Object[]  0 instance 01370164 _items
79102290  40009c8        c         System.Int32  1 instance       20 _size
79102290  40009c9       10         System.Int32  1 instance       20 _version
790fd0f0  40009ca        8        System.Object  0 instance 00000000 _syncRoot
7912d8f8  40009cb        0      System.Object[]  0   shared   static _emptyArray

ok,我们就很容易找到第一个参数的。那么如果要找接下来的参数怎么办呢?

0:009> ? edx
Evaluate expression: 20381948 = 013700fc
我们看到EDX的地址为013700fc

0:009> !dso
OS Thread Id: 0xe34 (9)
ESP/REG  Object   Name
ebx      013700fc System.Collections.Generic.List`1[[ServiceInterface.Serials, ServiceInterface]]
ecx      01315f74 SystemService.MainServiceProcess
edx      013700fc System.Collections.Generic.List`1[[ServiceInterface.Serials, ServiceInterface]]
0391eccc 0136f9cc System.String    工业增加值(当期)
0391ecd0 014182fc SystemService.MainService

我们看到EDX 的下一个地址 是 0136f9cc
0136f9cc 就是第二个参数的地址了。值都已经显示出来了,就不用Do了。如果为多个参数,那就依次类推了。
posted @ 2009-09-09 17:48  启点  阅读(4441)  评论(1编辑  收藏  举报