Как мне перечислить значения перечисления из дампа памяти, используя SOS и Windbg? - PullRequest
4 голосов
/ 13 февраля 2020

У меня есть мини-дамп, к которому я прикрепил windbg. Мини-дамп с сайта. NET 4.6.1 ASP. NET, работающего на IIS. Я хотел бы получить определение моего enum, но всякий раз, когда я получаю MethodTable класса, я просто получаю следующее.

0:000> !DumpMT /d 256db60c
EEClass:         256c773c
Module:          201fcfb0
Name:            MyDll.eDefaultRelatedObjects
mdToken:         02000029
File:            C:\Windows\Microsoft.NET\Framework\v4.0.30319\Temporary ASP.NET Files\root\303e164d\216bec4f\assembly\dl3\bdb2a421\004bd941_fee1d501\MyDll.dll
BaseSize:        0xc
ComponentSize:   0x0
Slots in VTable: 23
Number of IFaces in IFaceMap: 3


0:000> !DumpClass /d 256c773c 
Class Name:      MyDll.eDefaultRelatedObjects 
mdToken:         02000029 
File:            C:\Windows\Microsoft.NET\Framework\v4.0.30319\Temporary ASP.NET Files\root\303e164d\216bec4f\assembly\dl3\bdb2a421\004bd941_fee1d501\MyDll.dll 
Parent Class:    717f17cc 
Module:          201fcfb0 
Method Table:    256db60c 
Vtable Slots:    17 
Total Method Slots:  17 
Class Attributes: 101   
Transparency:        Critical 
NumInstanceFields:   1 
NumStaticFields:     0
      MT    Field   Offset                 Type VT     Attr    Value Name 
71c9f54c  400055f      124        System.Char[]  0   shared   static enumSeperatorCharArray
     >> Domain:Value  09671520:NotInit  306d85b0:0d8e822c 306da248:NotInit  306d98c0:NotInit  306dc868:138690b0 << 
71ca0994  400007d        4         System.Int32  1 instance           value__

Я смотрел на значения в доменах приложений, но они просто запятые.

0:000> !DumpObj /d 0d8e822c
Name:        System.Char[]
MethodTable: 71c9f54c
EEClass:     71874c84
Size:        14(0xe) bytes
Array:       Rank 1, Number of elements 1, Type Char (Print Array)
Content:     ,
Fields:
None

Что мне нужно сделать, чтобы узнать, как перечисление было определено из объекта в куче?

EDIT1: у меня есть доступ к PDB, если это имеет значение.

1 Ответ

4 голосов
/ 14 февраля 2020

Сначала простые вещи:

0:000> !DumpObj /d 0d8e822c
[...]
Content:     ,    

Что вы сделали здесь: перечислите значения enumSeperatorCharArray. Это не относится к вашему определению перечисления. Все перечисления имеют его.

SOS ИМХО не может перечислить определения перечислений. Для этого вам нужно .

Вот сеанс отладки:

0:006> .loadby sos clr
0:006> .load D:\mylongpath\sosex.dll

0:006> !dumpheap -type YourEnum
 Address       MT     Size
02cf2480 01154dc4       12     

Statistics:
      MT    Count    TotalSize Class Name
01154dc4        1           12 DebuggingEnumDefinition.YourEnum
Total 1 objects

Итак, есть один объект, и на него можно смотреть, как вы. В самом конце вывода вы можете увидеть его десятичное значение, которое равно 65 и не очень полезно.

0:006> !DumpObj /d 02cf2480
Name:        DebuggingEnumDefinition.YourEnum
[...]
61bf42a8  4000001        4         System.Int32  1 instance       65 value__

С SOSEX '!mdt вы можете перечислить константы перечисления:

0:006> !mdt DebuggingEnumDefinition.YourEnum
DebuggingEnumDefinition.YourEnum
    [s]enumSeperatorCharArray: char[]
        AppDomain 'DebuggingEnumDefinition.exe' (00c8dc18): <uninitialized>
    [s]enumSeperator: string
        AppDomain 'DebuggingEnumDefinition.exe' (00c8dc18): <Field def not loaded>
    value__: int
    [s]EnumVal1: DebuggingEnumDefinition.YourEnum
        AppDomain 'DebuggingEnumDefinition.exe' (00c8dc18): <Field def not loaded>
    [s]EnumVal2: DebuggingEnumDefinition.YourEnum
        AppDomain 'DebuggingEnumDefinition.exe' (00c8dc18): <Field def not loaded>
    [s]EnumVal3: DebuggingEnumDefinition.YourEnum
        AppDomain 'DebuggingEnumDefinition.exe' (00c8dc18): <Field def not loaded>

На самом деле я ожидал и числовые значения.

Вы также можете использовать !mdt с адресом объекта, чтобы получить его постоянное и шестнадцатеричное значение (0x41 == 65):

0:006> !mdt 02cf2480
0x41 (EnumVal3) (DebuggingEnumDefinition.YourEnum)

Изменяя память процесса, вы, вероятно, можете сгенерировать отображение значений перечисления.

Следующее генерирует al oop от 0 до 127:

.for (r $t0=0; @$t0<0n128; r $t0 = @$t0+1) { }

Внутри l oop вы можете изменить значение перечисления (я забыл, зависит ли +4 от битности):

ed 03402470+4 @$t0

Далее, вы можете использовать !mdt для анализа измененного значения

!mdt 03402470

Полная команда:

.for (r $t0=0; @$t0<0n128; r $t0 = @$t0+1) { ed 03402470+4 @$t0; !mdt 03402470}

, и результат будет выглядеть как

0x0 (EnumVal1) (DebuggingEnumDefinition.YourEnum)
0x1 (EnumVal2) (DebuggingEnumDefinition.YourEnum)
0x2 (DebuggingEnumDefinition.YourEnum)
0x3 (DebuggingEnumDefinition.YourEnum)
[...]
0x7f (DebuggingEnumDefinition.YourEnum)

Далее, вы, вероятно, будете фильтровать только допустимые случаи. Обратите внимание, что мы можем отличить guish допустимых записей от недействительных, если в них содержится ) (.

. Здесь сценарии в WinDbg немного уродливы ...

.echo Just a test

отображает что-то, чтобы показать принцип.

.shell -ci ".echo Just a test" findstr "Just"

использует команду DOS findstr для фильтрации строк, содержащих определенное c слово.

Затем замените .echo на полную команду, указанную ранее, и замените «Just» на ) (. Поскольку findstr также является странной программой, вам на самом деле нужен ).(, потому что в противном случае он будет обрабатывать его как два отдельных условия поиска.

.shell -ci ".for (r $t0=0; @$t0<0n128; r $t0 = @$t0+1) { ed 03402470+4 @$t0; !mdt 03402470}" findstr ").("

И да, вывод:

0x0 (EnumVal1) (DebuggingEnumDefinition.YourEnum)
0x1 (EnumVal2) (DebuggingEnumDefinition.YourEnum)
0x41 (EnumVal3) (DebuggingEnumDefinition.YourEnum)
.shell: Process exited

Какое приключение!


Исходный код, который я использовал, на всякий случай ...

using System;
using System.Collections;

namespace DebuggingEnumDefinition
{
    class Program
    {
        static void Main()
        {
            var somwehere = new ArrayList() { YourEnum.EnumVal3 };
            Console.WriteLine("There should be an enum on the heap now.");
            Console.ReadLine();
            Console.WriteLine(somwehere[0]); // Just fix the unused variable issue
        }
    }

    enum YourEnum
    {
        EnumVal1,
        EnumVal2,
        EnumVal3=65
    }
}
...