1

使用启用 TTD 的 WinDbg,如何回放创建某个托管对象的时刻?可以说我确实使用!clrstack -a或获得了它的地址!dso

4

1 回答 1

2

有几种方法可以做到这一点。如果您有对象的地址并想返回到它的创建,您可以使用 ba(访问中断)。创建对象时,方法表地址被写入第一个字(32 位为 4 个字节,64 位为 8 个字节)。因此,为每个写访问添加断点并返回将在对象创建时停止。另一种方法是添加指向对象的所有构造函数的断点,并且还向后。另请注意,所有这些也可以通过“dx”命令通过断点地址或构造函数调用过滤来完成。

想象一下你有这个输出:

0:016> !dso
OS Thread Id: 0x2f54 (16)
RSP/REG          Object           Name
000000A2CD5FC770 000001e9849cd4b8 ConceptNetConsole1.SampleClass1
(...)

0:016> !DumpObj /d 000001e9849cd4b8
Name:        ConceptNetConsole1.SampleClass1
MethodTable: 00007ffb85545ef8 <<< This is the method table
EEClass:     00007ffb85542d68
Size:        136(0x88) bytes
File:        C:\Projects\ConceptNetConsole1\ConceptNetConsole1\bin\x64\Release\ConceptNetConsole1.exe
Fields:
              MT    Field   Offset                 Type VT     Attr            Value Name
00007ffbe38e70b0  40005a8        8        System.Object  0 instance 000001e9849cd718 __identity
(...)

方法 1:并且您想在创建此对象时停止您可以使用(对于 32 位使用 w4):

ba w8 000001e9849cd4b8
g-

使用“dx”(注意地址必须是 C++ 格式,以“0x”开头):

dx -g @$cursession.TTD.Memory(0x00001e9849cd4b8,0x00001e9849cd4b8+8,"w")

同样,对于 32 位,在第二个参数上使用 address+4。选项 -g 将以网格格式显示。

方法二:

通过列出类的方法表来获取构造函数的地址:

0:016> !dumpmt -md 00007ffb85545ef8
EEClass:         00007ffb85542d68
Module:          00007ffb85545408
Name:            ConceptNetConsole1.SampleClass1
mdToken:         0000000002000005
File:            C:\Projects\ConceptNetConsole1\ConceptNetConsole1\bin\x64\Release\ConceptNetConsole1.exe
BaseSize:        0x88
ComponentSize:   0x0
Slots in VTable: 23
Number of IFaces in IFaceMap: 0
--------------------------------------
MethodDesc Table
           Entry       MethodDesc    JIT Name
00007ffbe36fb1f0 00007ffbe3257538 PreJIT System.Object.ToString()
00007ffbe36ffd90 00007ffbe3257540 PreJIT System.Object.Equals(System.Object)
00007ffbe3721dc0 00007ffbe3257568 PreJIT System.Object.GetHashCode()
00007ffbe36fce50 00007ffbe3257580 PreJIT System.Object.Finalize()
00007ffbe37d8f40 00007ffbe333cfd0 PreJIT System.MarshalByRefObject.GetLifetimeService()
00007ffbe36f8b10 00007ffbe333cfd8 PreJIT System.MarshalByRefObject.InitializeLifetimeService()
00007ffbe37cbd80 00007ffbe333cfe0 PreJIT System.MarshalByRefObject.CreateObjRef(System.Type)
00007ffb85560090 00007ffb85545d58    JIT ConceptNetConsole1.SampleClass1..ctor()  <<< This is the constructor
(...)

您可以简单地在 'Entry' 地址设置断点(或使用 !sos.bpmd)并返回:

bp 00007ffb85560090
g-

或者使用 'dx' 显示调用代码的所有场合(请注意,代码再次调整为看起来像 C++ '0x' 并且也在引号中):

dx -g @$cursession.TTD.Calls("0x00007ffb85560090")

希望对你有效。

于 2019-09-05T20:07:20.323 回答