【问题标题】:Play back to the moment of creation of some managed object in WinDbg TTD回放在 WinDbg TTD 中创建某个托管对象的那一刻
【发布时间】:2020-01-08 07:18:29
【问题描述】:

在启用 TTD 的情况下使用 WinDbg,如何回放某些托管对象的创建时刻? 假设我确实使用!clrstack -a!dso 获得了它的地址

【问题讨论】:

    标签: clr windbg historical-debugging


    【解决方案1】:

    有几种方法可以做到这一点。如果您有对象的地址并想返回它的创建,您可以使用 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
    (...)
    

    方法一: 并且您想在创建此对象时停止使用(对于 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
    (...)
    

    您可以简单地在“入口”地址处设置断点(或使用 !sos.bpmd)并返回:

    bp 00007ffb85560090
    g-
    

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

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

    希望它对你有用。

    【讨论】:

      猜你喜欢
      • 2020-08-12
      • 2011-02-07
      • 2010-11-05
      • 1970-01-01
      • 1970-01-01
      • 2018-09-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多