Воспроизвести до момента создания некоторого управляемого объекта в WinDbg TTD
Используя WinDbg с включенным TTD, как воспроизвести момент создания какого-либо управляемого объекта? Допустим, у меня есть его адрес, полученный с помощью!clrstack -a
или !dso
1 ответ
Есть несколько способов сделать это. Если у вас есть адрес объекта и вы хотите вернуться к его созданию, вы можете использовать ba (прерывание при доступе). При создании объекта адрес таблицы методов записывается в первое слово (4 байта для 32-битных, 8 байтов для 64-битных). Таким образом, добавление точки останова для каждого доступа на запись и движение назад остановятся при создании объекта. Другой способ - добавить точки останова, указывающие на все конструкторы объекта, а также в обратном направлении. Также обратите внимание, что все это также может быть выполнено с помощью фильтрации команды '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-битного используйте адрес +4 во втором параметре. Параметр -g будет отображаться в формате сетки.
Подход 2:
Получите адрес (а) конструкторов, перечислив таблицу методов класса:
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")
Надеюсь, это сработает для вас.