Custom DumpArray – Windbg
The sos has !dumparray for getting contents of the array. But it cannot be used for scripting or automation. Here is an example
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;
}
}
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(0×18) bytes
Array: Rank 1, Number of elements 2, Type CLASS
Element Methodtable: 001938b0
[0] 021fbc84
Name: ConsoleApplication.Test
MethodTable: 001938b0
EEClass: 00191488
Size: 16(0×10) bytes
File: C:\Users\naveen\Documents\Visual Studio 2010\Projects\ConsoleApplication9\bin\Debug\ConsoleApplication.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(0×10) bytes
File: C:\Users\naveen\Documents\Visual Studio 2010\Projects\ConsoleApplication9\bin\Debug\ConsoleApplication.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
dd 021fbc6c
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
- 64b56c28 - Array’s Method table pointer
- 00000002 - Array’s length ( this will be used later)
- 001938b0 -Array contents method table pointer ( Test class)
- 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
.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) }
Here is the explanation for the above script
- The .for loop is used to iterate through the contents of the array : “.for (r $t0=0; @$t0 < poi(021fbc6c+0×4); 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+0×4) , the poi(021fbc6c+0×4) 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.
- The next statement is “r$t1 = 0″ is initializing another pseudo register to zero
- 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).
- The “.echo ************” is just for line separation
- The last command is the one which does most of the work
- The command poi((021fbc6c-0×4)+@$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-0×4)+10) which would point 021fbc84 and the next time it would be poi((021fbc6c-0×4)+14) which would be 021fbc94
- The outermost “poi 0×4” 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 +0×4); r$t0=@$t0+1 ) { r$t1 = 0; .if(@$t0 = 0) { r$t1=10} .else { r$t1= 10+ @$t0*4};.echo ************; !do poi(poi((021fbc6c-0×4)+@$t1)+0×4) }
************
Name: System.String
MethodTable: 64b9f9ac
EEClass: 648d8bb0
Size: 20(0×14) bytes
File: C:\Windows\Microsoft.Net\assembly\GAC_32\mscorlib\v4.0_4.0.0.0__b77a5c561934e089\mscorlib.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(0×14) bytes
File: C:\Windows\Microsoft.Net\assembly\GAC_32\mscorlib\v4.0_4.0.0.0__b77a5c561934e089\mscorlib.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 <<
Custom DumpArray – Windbg…
Thank you for submitting this cool story – Trackback from DotNetShoutout…
DotNetShoutout
June 24, 2010 at 9:03 pm
[...] This post was mentioned on Twitter by pj4533, Richard Laksana. Richard Laksana said: Custom DumpArray – Windbg – http://su.pr/2kBZVB [...]
Tweets that mention Custom DumpArray – Windbg « Naveen's Blog -- Topsy.com
June 25, 2010 at 2:38 pm
[...] which is the size of the array and for more information look at the post on custom dump array http://naveensrinivasan.com/2010/06/24/custom-dumparray-windbg/ The first element in the array would be in the 20th offset in x64 and 10th offset in x86 and that [...]
Dumping ASP.NET Session (x86 /x64) within Windbg « Naveen's Blog
October 26, 2010 at 9:18 pm
I think there might be a bug in the code snippet. Shouldn’t you be adding 0×04 to your original address rather than subtracting?
Brenda
August 17, 2012 at 5:09 pm