I have a mini dump that I have attached windbg to. The mini dump is from a .NET 4.6.1 ASP.NET site running on IIS. I would like to get the definition of my enum but whenever I get the MethodTable of the Class I am just getting the following.
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__
I have looked at the values in the appdomains but they are just commas.
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
What do I need to do get how the enum was defined from the object on the heap?
EDIT1: I have access to the PDBs if that makes a difference.
Simple things first:
0:000> !DumpObj /d 0d8e822c
[...]
Content: ,
What you did here is: list the values of enumSeperatorCharArray
. It's not relevant to your enum definition. All enums have it.
SOS IMHO doesn't have a way to list the enum definitions. You need sosex for that.
Here's the debugging session:
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
So there is one object, and it's possible to look at it like you did. At the very end of the output, you can see its decimal value, which is 65 and not very helpful.
0:006> !DumpObj /d 02cf2480
Name: DebuggingEnumDefinition.YourEnum
[...]
61bf42a8 4000001 4 System.Int32 1 instance 65 value__
With SOSEX' !mdt
, you can list the enumeration constants:
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>
Actually I have expected the numerical values as well.
You can also use !mdt
with the object's address, so you get its constant and hexadecimal value (0x41 == 65):
0:006> !mdt 02cf2480
0x41 (EnumVal3) (DebuggingEnumDefinition.YourEnum)
By changing the process memory, you could probably generate a mapping of the enum values.
The following generates a loop from 0 to 127:
.for (r $t0=0; @$t0<0n128; r $t0 = @$t0+1) { }
Inside the loop, you can change the enum's value (I forgot whether +4 is bitness dependent):
ed 03402470+4 @$t0
Next, you could use !mdt
to analyze the modified value
!mdt 03402470
The full command is
.for (r $t0=0; @$t0<0n128; r $t0 = @$t0+1) { ed 03402470+4 @$t0; !mdt 03402470}
and the output will look like
0x0 (EnumVal1) (DebuggingEnumDefinition.YourEnum)
0x1 (EnumVal2) (DebuggingEnumDefinition.YourEnum)
0x2 (DebuggingEnumDefinition.YourEnum)
0x3 (DebuggingEnumDefinition.YourEnum)
[...]
0x7f (DebuggingEnumDefinition.YourEnum)
Next, you probably to filter only the valid cases. Note that we can distinguish valid entries from invalid ones by containing ) (
.
This is where scripting in WinDbg gets a bit ugly...
.echo Just a test
displays something to show the principle.
.shell -ci ".echo Just a test" findstr "Just"
uses the DOS command findstr
to filter lines that contain a specific word.
Next, replace the .echo
with the full command from before and replace "Just" by ) (
. Because findstr
is also a strange program, you actually need ).(
because it would otherwise treat it as two separate search terms.
.shell -ci ".for (r $t0=0; @$t0<0n128; r $t0 = @$t0+1) { ed 03402470+4 @$t0; !mdt 03402470}" findstr ").("
And yippieh, the output is:
0x0 (EnumVal1) (DebuggingEnumDefinition.YourEnum)
0x1 (EnumVal2) (DebuggingEnumDefinition.YourEnum)
0x41 (EnumVal3) (DebuggingEnumDefinition.YourEnum)
.shell: Process exited
What an adventure!
The source code I used, just in case ...
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
}
}