The The has !dumparray for getting contents of the array. But it cannot be used for scripting or automation. Here is an example

[sourcecode language=”csharp”]

using System;

namespace ConsoleApplication

{

class Program

{

Test[] arr = new[] { new Test() { ID = 1, Name = “Foo” }, new Test() { ID = 2, Name = “Bar” } };

static void Main(string[] args)

{

var p = new Program();

Console.WriteLine(p.arr);

Console.Read();

}

}

class Test

{

public int ID;

public string Name;

}

}

[/sourcecode]

And here is the output of the arr variable within the debugger

0:000> !da -details 021fbc6c

Name:        ConsoleApplication.Test[]

MethodTable: 64b56c28

EEClass:     648d9698

Size:        24(0x18) bytes

Array:       Rank 1, Number of elements 2, Type CLASS

Element Methodtable: 001938b0

[0] 021fbc84

Name:        ConsoleApplication.Test

MethodTable: 001938b0

EEClass:     00191488

Size:        16(0x10) bytes

File:        C:UsersnaveenDocumentsVisual Studio 2010ProjectsConsoleApplication9binDebugConsoleApplication.exe

Fields:

MT    Field   Offset                 Type VT     Attr    Value Name

64ba2978  4000002        8             System.Int32      1     instance            1     ID

64b9f9ac  4000003        4            System.String      0     instance     021fbc44     Name

1 021fbc94

Name:        ConsoleApplication.Test

MethodTable: 001938b0

EEClass:     00191488

Size:        16(0x10) bytes

File:        C:UsersnaveenDocumentsVisual Studio 2010ProjectsConsoleApplication9binDebugConsoleApplication.exe

Fields:

MT    Field   Offset                 Type VT     Attr    Value Name

64ba2978  4000002        8             System.Int32      1     instance            2     ID

64b9f9ac  4000003        4            System.String      0     instance     021fbc58     Name

From the output  we cannot see the values of the  Name variable within the Test class. To get the value we would have manually issue a !dumpobj on each one of these. In this post I will demonstrate how to automate this. In doing so we will also explore the array internals from raw memory perspective.

To start of lets dump the raw memory of the array. The  array address is 021fbc6c

[sourcecode]

dd 021fbc6c

[/sourcecode]

0:000> dd 021fbc6c

021fbc6c  64b56c28 00000002 001938b0 021fbc84

021fbc7c  021fbc94 00000000 001938b0 021fbc44

021fbc8c  00000001 00000000 001938b0 021fbc58

021fbc9c  00000002 00000000 64ba7490 00000000

021fbcac  00000000 00000000 00000000 00000000

021fbcbc  00000000 64b9f5e8 00000000 40010000

021fbccc  64ba6034 00000007 00000004 00000100

021fbcdc  00000000 64ba6f40 00000000 00000000

Fields

  1. 64b56c28 – Array’s Method table pointer
  2. 00000002 – Array’s length ( this will be used later)
  3. 001938b0 Array contents method table pointer ( Test class)
  4. 021fbc84, 021fbc94 – Contents of the array( 2 instances of the Test class)

I would be using  $t0, $t1   User-Defined Pseudo-Registers within my script  as local variables to maintain state. Think of them as predefined variables that we can use. Here is the script to get just the Name from the array

[sourcecode]

.for (r $t0=0; @$t0 < poi(021fbc6c+0x4); r$t0=@$t0+1 ) { r$t1 = 0; .if(@$t0 = 0) { r$t1=10} .else { r$t1= 10+ @$t0*4};.echo ********;!do poi(poi((021fbc6c-0x4)+@$t1)+0x4) }

[/sourcecode]

Here is the explanation for the above script

  1. The [The The has !dumparray for getting contents of the array. But it cannot be used for scripting or automation. Here is an example

[sourcecode language=”csharp”]

using System;

namespace ConsoleApplication

{

class Program

{

Test[] arr = new[] { new Test() { ID = 1, Name = “Foo” }, new Test() { ID = 2, Name = “Bar” } };

static void Main(string[] args)

{

var p = new Program();

Console.WriteLine(p.arr);

Console.Read();

}

}

class Test

{

public int ID;

public string Name;

}

}

[/sourcecode]

And here is the output of the arr variable within the debugger

0:000> !da -details 021fbc6c

Name:        ConsoleApplication.Test[]

MethodTable: 64b56c28

EEClass:     648d9698

Size:        24(0x18) bytes

Array:       Rank 1, Number of elements 2, Type CLASS

Element Methodtable: 001938b0

[0] 021fbc84

Name:        ConsoleApplication.Test

MethodTable: 001938b0

EEClass:     00191488

Size:        16(0x10) bytes

File:        C:UsersnaveenDocumentsVisual Studio 2010ProjectsConsoleApplication9binDebugConsoleApplication.exe

Fields:

MT    Field   Offset                 Type VT     Attr    Value Name

64ba2978  4000002        8             System.Int32      1     instance            1     ID

64b9f9ac  4000003        4            System.String      0     instance     021fbc44     Name

1 021fbc94

Name:        ConsoleApplication.Test

MethodTable: 001938b0

EEClass:     00191488

Size:        16(0x10) bytes

File:        C:UsersnaveenDocumentsVisual Studio 2010ProjectsConsoleApplication9binDebugConsoleApplication.exe

Fields:

MT    Field   Offset                 Type VT     Attr    Value Name

64ba2978  4000002        8             System.Int32      1     instance            2     ID

64b9f9ac  4000003        4            System.String      0     instance     021fbc58     Name

From the output  we cannot see the values of the  Name variable within the Test class. To get the value we would have manually issue a !dumpobj on each one of these. In this post I will demonstrate how to automate this. In doing so we will also explore the array internals from raw memory perspective.

To start of lets dump the raw memory of the array. The  array address is 021fbc6c

[sourcecode]

dd 021fbc6c

[/sourcecode]

0:000> dd 021fbc6c

021fbc6c  64b56c28 00000002 001938b0 021fbc84

021fbc7c  021fbc94 00000000 001938b0 021fbc44

021fbc8c  00000001 00000000 001938b0 021fbc58

021fbc9c  00000002 00000000 64ba7490 00000000

021fbcac  00000000 00000000 00000000 00000000

021fbcbc  00000000 64b9f5e8 00000000 40010000

021fbccc  64ba6034 00000007 00000004 00000100

021fbcdc  00000000 64ba6f40 00000000 00000000

Fields

  1. 64b56c28 – Array’s Method table pointer
  2. 00000002 – Array’s length ( this will be used later)
  3. 001938b0 Array contents method table pointer ( Test class)
  4. 021fbc84, 021fbc94 – Contents of the array( 2 instances of the Test class)

I would be using  $t0, $t1   User-Defined Pseudo-Registers within my script  as local variables to maintain state. Think of them as predefined variables that we can use. Here is the script to get just the Name from the array

[sourcecode]

.for (r $t0=0; @$t0 < poi(021fbc6c+0x4); r$t0=@$t0+1 ) { r$t1 = 0; .if(@$t0 = 0) { r$t1=10} .else { r$t1= 10+ @$t0*4};.echo ********;!do poi(poi((021fbc6c-0x4)+@$t1)+0x4) }

[/sourcecode]

Here is the explanation for the above script

  1. The]3 loop is used to iterate through the contents of the array :  “.for (r $t0=0; @$t0 < poi(021fbc6c+0x4); r$t0=@$t0+1 ) ”
    • The loop variable is $t0, which is initialized to zero  “r $t0=0;”,
    • Next is the loop condition check @$to < poi(021fbc6c+0x4) , the poi(021fbc6c+0x4) is the pointer deference to array length which is 00000002
    • And the last statement is the increment command of the loop variable r$t0=@$t0+1
    • Tip :- I am using “@” before the “$” for increased speed within the debugger when accessing registers.
  2. The next statement is “r$t1 = 0” is initializing another pseudo register to zero
  3. After which the command “if(@$t0 = 0) { r$t1=10} .else { r$t1= 10+ @$t0*4}” resets the value of $t1 register either “10” or $t0 * 4, where $to is loop variable. I do this because the first instance of the Test class within the array is in the 10th offset and the rest of them would be on the next 4th offset. So for example the first time loop ,$t1 would be 10 , the second time  $t1 would 14 (10 + 1*4).
  4. The “.echo ****” is just for line separation
  5. The last command is the one which does most of the work
    • The command poi((021fbc6c-0x4)+@$t1) would return the pointer of the each element in the array which is instance of Test class . The first time it would be poi((021fbc6c-0x4)+10) which would point 021fbc84 and the next time it would be poi((021fbc6c-0x4)+14) which would be 021fbc94
    • The outermost “poi 0x4” is to get pointer of the member variable Name and dump its content using !do

And here is the output from the script

0:000> .for (r $t0=0; @$t0 < poi(021fbc6c   +0x4); r$t0=@$t0+1 ) { r$t1 = 0; .if(@$t0 = 0) { r$t1=10} .else { r$t1= 10+ @$t0*4};.echo ********;  !do poi(poi((021fbc6c-0x4)+@$t1)+0x4) }

****

Name:        System.String

MethodTable: 64b9f9ac

EEClass:     648d8bb0

Size:        20(0x14) bytes

File:        C:WindowsMicrosoft.NetassemblyGAC_32mscorlibv4.0_4.0.0.0__b77a5c561934e089mscorlib.dll

String:      Foo

Fields:

MT    Field   Offset                 Type VT     Attr    Value Name

64ba2978  40000ed        4         System.Int32  1 instance        3 m_stringLength

64ba1dc8  40000ee        8          System.Char  1 instance       46 m_firstChar

64b9f9ac  40000ef        8        System.String  0   shared   static Empty

Domain:Value  00745c28:021f1228 <<

****

Name:        System.String

MethodTable: 64b9f9ac

EEClass:     648d8bb0

Size:        20(0x14) bytes

File:        C:WindowsMicrosoft.NetassemblyGAC_32mscorlibv4.0_4.0.0.0__b77a5c561934e089mscorlib.dll

String:      Bar

Fields:

MT    Field   Offset                 Type VT     Attr    Value Name

64ba2978  40000ed        4         System.Int32  1 instance        3 m_stringLength

64ba1dc8  40000ee        8          System.Char  1 instance       42 m_firstChar

64b9f9ac  40000ef        8        System.String  0   shared   static Empty

Domain:Value  00745c28:021f1228 <<