使用WinDbg+SOS及WinDbg Script寻找内存中DataTable第M行N列的值

DataTable在内存中是如何存储一张表的结构的呢?如何使用Windbg直接在内存中找到一个DataTable里面的第M列第N行的值呢?这的确是一个比较有趣的问题^_^

 

下面的内容,主要是讲如何用windbg+sos来看看一个DataTable在内存中是如何存储的,以及寻找内存中一个DataTable特定的行列的一个单元的值是多少。同时,还有一点Windbg Script的使用。

 

找一个小白鼠先:


   
class Program

    {

        static void Main(string[] args)

        {

            System.Data.DataTable dt = new System.Data.DataTable();

 

            DataColumn dtC1 = new DataColumn();

            dtC1.ColumnName = "Column1";

 

            DataColumn dtC2 = new DataColumn();

            dtC2.ColumnName = "Column2";

 

            dt.Columns.Add(dtC1);

            dt.Columns.Add(dtC2);

 

            DataRow dr1 = dt.NewRow();

            dr1["Column1"] = "aaaa";

            dr1["Column2"] = "bbbb";

            dt.Rows.Add(dr1);

 

            DataRow dr2 = dt.NewRow();

            dr2["Column1"] = "cccc";

            dr2["Column2"] = "dddd";

            dt.Rows.Add(dr2);

 

            pause();

        }

 

        public static void pause()

        {

            System.Console.ReadLine();

        }

}

 

下面就看看DataTable在内存里面是如何存储的,以及在内存里面找到aaaabbbbccccdddd这几个字符串。

首先!threads看看哪几个托管线程,then,切换到主线程上面:~0s

 

0:000> !dumpstackobjects

OS Thread Id: 0x66c (0)

ESP/REG  Object   Name

0012f3b0 013b9830 Microsoft.Win32.SafeHandles.SafeFileHandle

0012f3c0 013b9830 Microsoft.Win32.SafeHandles.SafeFileHandle

0012f3f4 013ba01c System.Byte[]

0012f3f8 013b9844 System.IO.__ConsoleStream

0012f418 013b97c8 System.Data.DataRow

0012f41c 013b9fc4 System.IO.StreamReader

0012f420 013b9fc4 System.IO.StreamReader

0012f424 013b7dac System.Data.DataRowCollection

0012f434 013b9fc4 System.IO.StreamReader

0012f438 013ba338 System.IO.TextReader+SyncTextReader

0012f43c 013b7dac System.Data.DataRowCollection

0012f444 013b97c8 System.Data.DataRow

0012f448 013b9664 System.Data.DataRow

0012f44c 013ba338 System.IO.TextReader+SyncTextReader

0012f450 013b7dac System.Data.DataRowCollection

0012f458 013b6120 System.Data.DataTable

0012f468 013b5b7c System.Object[]    (System.String[])

0012f46c 013b82fc System.Data.DataColumn

0012f470 013b8edc System.Data.DataColumn

0012f534 013b5b7c System.Object[]    (System.String[])

0012f6e0 013b5b7c System.Object[]    (System.String[])

0012f708 013b5b7c System.Object[]    (System.String[])

 

有几个DataColumn和几个DataRow,还有两个DataRowCollection。为了证实猜想,继续查看下去,dump DataTable

0:000> !do 013b6120

Name: System.Data.DataTable

MethodTable: 653c46d8

EEClass: 653c4288

Size: 296(0x128) bytes

Fields:

MT        Type                                 Value                 Name

7a745c0c

...ponentModel.ISite

000000000

site

7a742e54

....EventHandlerList

000000000

events

790f9c18

System.Object

000000000

EventDisposed

653c2e2c

System.Data.DataSet

000000000

dataSet

653c6ce8

System.Data.DataView

000000000

defaultView

653c72cc

...DataRowCollection

0013b7dac

rowCollection

653c33d4

...aColumnCollection

0013b7c5c

columnCollection

653c711c

...straintCollection

0013b7d74

constraintCollection

653d3d0c

...elationCollection

000000000

parentRelationsCollection

653d3d0c

...elationCollection

000000000

childRelationsCollection

653c7080

...ata.RecordManager

0013b7500

recordManager

790fa3e0

System.String

0013b6290

tableName

790fa3e0

System.String

000000000

tableNamespace

790fa3e0

System.String

0013b6290

tablePrefix

653e63bc

...ta.DataExpression

000000000

displayExpression

790ff4c4

...ation.CultureInfo

0013b78dc

_culture

7910feec

...ation.CompareInfo

000000000

_compareInfo

790ffdcc

...m.IFormatProvider

000000000

_formatProvider

79112d98

...em.StringComparer

000000000

_hashCodeProvider

790fa3e0

System.String

000000000

encodedTableName

653c3e94

...m.Data.DataColumn

000000000

xmlText

653c3e94

...m.Data.DataColumn

000000000

_colUnique

79105ba4

System.Decimal

1013b6224

minOccurs

79105ba4

System.Decimal

1013b6234

maxOccurs

790f9c18

System.Object

000000000

typeName

653c9b84

....UniqueConstraint

000000000

primaryKey

653d63ac

...Data.IndexField

0013b6274

_primaryIndex

653c75f8

System.Data.Index

000000000

loadIndexwithOriginalAdded

653c75f8

System.Data.Index

000000000

loadIndexwithCurrentDeleted

79124228

System.Object[]

000000000

EmptyDataRowArray

7a74db40

...criptorCollection

000000000

propertyDescriptorCollectionCache

79124228

System.Object[]

0013b6280

_nestedParentRelations

653dfc68

...hangeEventHandler

000000000

onRowChangedDelegate

653dfc68

...hangeEventHandler

000000000

onRowChangingDelegate

653dfc68

...hangeEventHandler

000000000

onRowDeletingDelegate

653dfc68

...hangeEventHandler

000000000

onRowDeletedDelegate

653dec84

...hangeEventHandler

000000000

onColumnChangedDelegate

653dec84

...hangeEventHandler

000000000

onColumnChangingDelegate

653e039c

...ClearEventHandler

000000000

onTableClearingDelegate

653e039c

...ClearEventHandler

000000000

onTableClearedDelegate

653e042c

...ewRowEventHandler

000000000

onTableNewRowDelegate

7a7638a4

...angedEventHandler

000000000

onPropertyChangingDelegate

7910d61c

System.EventHandler

000000000

onInitialized

653c7730

...ta.DataRowBuilder

0013b82ec

rowBuilder

790fea70

...ections.Hashtable

000000000

rowDiffId

79103b6c

....ReaderWriterLock

0013b6348

indexesLock

791240f0

System.Int32[]

0013b6248

zeroIntegers

79124228

System.Object[]

0013b6254

zeroColumns

79124228

System.Object[]

0013b6264

zeroRows

653d63ac

...Data.IndexField

0013b6274

zeroIndexField

79124228

System.Object[]

0013b6280

EmptyArrayDataRelation

      

       由于DataTable里面的东西太多,就去掉了几列和一些没有太大用处的行。在elementColumnCount属性里面,可以看到DataTable里面有刚才定义的两列。

接着,可以在columnCollection这个field里面找到刚才小白鼠里面的DataTableColumn的集合:


     0:000> !do 013b7c5c

Name: System.Data.DataColumnCollection

MethodTable: 653c33d4

EEClass: 653c3364

Size: 56(0x38) bytes

 (C:\WINDOWS\assembly\GAC_32\System.Data\2.0.0.0__b77a5c561934e089\System.Data.dll)

Fields:

      MT                  Type     Value Name

7a753b14  ...onChangeEventArgs  00000000   RefreshEventArgs

653c46d8  ...em.Data.DataTable   013b6120   table

791036b0  ...ections.ArrayList      013b7c94   _list

790fed1c          System.Int32         1   defaultNameIndex

79124228       System.Object[]  00000000 delayedAddRangeColumns

790fea70  ...ections.Hashtable      013b7cac   columnFromName

7a7504bc  ...hangeEventHandler   00000000   onCollectionChangedDelegate

7a7504bc  ...hangeEventHandler   00000000   onCollectionChangingDelegate

7a7504bc  ...hangeEventHandler   00000000   onColumnPropertyChangedDelegate

79104f64        System.Boolean         0 fInClear

79124228       System.Object[]  013b6254 columnsImplementingIChangeTracking

790fed1c          System.Int32         0 nColumnsImplementingIChangeTracking

790fed1c             System.Int32                       0

nColumnsImplementingIRevertibleChangeTracking

 

在这个结构中,可以看到DataColumn是放过在_list这个ArrayList里面的。继续查看ArrayList里面都有些什么:

0:000> !dumpobj 013b7c94

Name: System.Collections.ArrayList

MethodTable: 791036b0

EEClass: 79103604

Size: 24(0x18) bytes

 (C:\WINDOWS\assembly\GAC_32\mscorlib\2.0.0.0__b77a5c561934e089\mscorlib.dll)

Fields:

      MT    Field   Offset                 Type VT     Attr    Value Name

79124228  40008c0        4      System.Object[]  0 instance 013b8f8c _items

790fed1c  40008c1        c         System.Int32  0 instance        2 _size

790fed1c  40008c2       10         System.Int32  0 instance        2 _version

790f9c18  40008c3        8        System.Object  0 instance 00000000 _syncRoot

79124228  40008c4      1b0      System.Object[]  0   shared   static emptyArray

    >> Domain:Value  00154598:013b1c2c <<

 

恩,快要到达目的地了,接着由于里面只有两个Column,我就在Windbg里面全部给输出出来了:


0:000> !dumparray -details 013b8f8c

Name: System.Object[]

MethodTable: 79124228

EEClass: 7912479c

Size: 32(0x20) bytes

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

Element Methodtable: 790f9c18

[0] 013b82fc

    Name: System.Data.DataColumn

    MethodTable: 653c3e94

    EEClass: 653c3e1c

Size: 148(0x94) bytes

 

对于每个DataColumn的细节,输出很长,这里就截取一个_items里面的DataColumn对象的细节:

          MT                 Type        Value Name

    7a745c0c ...ponentModel.ISiteinstance 00000000 site

    7a742e54 ....EventHandlerListinstance 00000000 events

    790f9c18        System.Object  static 00000000 EventDisposed

    79104f64       System.Booleaninstance        1 allowNull

    79104f64       System.Booleaninstance        0 autoIncrement

    790fcb80         System.Int64instance 1 autoIncrementStep

    790fcb80         System.Int64instance 0 autoIncrementSeed

    790fa3e0        System.Stringinstance 00000000 caption

    790fa3e0        System.Stringinstance 013b6070 _columnName

    79101058          System.Typeinstance 013b8390 dataType

    790f9c18        System.Objectinstance 013b846c defaultValue

    653d4c94         System.Int32instance        3 _dateTimeMode

    653e63bc ...ta.DataExpressioninstance 00000000 expression

    790fed1c         System.Int32instance       -1 maxLength

    790fed1c         System.Int32instance        0 _ordinal

    79104f64       System.Booleaninstance        0 readOnly

    653c75f8    System.Data.Indexinstance 00000000 sortIndex

    653c46d8 ...em.Data.DataTableinstance 013b6120 table

    79104f64       System.Booleaninstance        0 unique

    653d3bfc         System.Int32instance        1 columnMapping

    790fed1c         System.Int32instance        0 _hashCode

    790fed1c         System.Int32instance        0 errors

    79104f64       System.Booleaninstance        0 isSqlType

    79104f64       System.Booleaninstance        0 implementsINullable

    79104f64       System.Booleaninstance        1 defaultValueIsNull

    00000000                     instance 00000000 dependentColumns

    653d4218 ...ropertyCollectioninstance 00000000 extendedProperties

    7a7638a4 ...angedEventHandlerinstance 00000000 onPropertyChangingDelegate

    653c68bc ...ommon.DataStorageinstance 013b8fdc _storage

    790fcb80         System.Int64instance 0 autoIncrementCurrent

    790fa3e0        System.Stringinstance 00000000 _columnUri

    790fa3e0        System.Stringinstance 013b6290 _columnPrefix

    790fa3e0        System.Stringinstance 00000000 encodedColumnName

    790fa3e0        System.Stringinstance 013b6290 description

    790fa3e0        System.Stringinstance 013b6290 dttype

    653c9abc ...m.Data.SimpleTypeinstance 00000000 simpleType

    790fed1c         System.Int32instance        1 _objectID

    790fed1c         System.Int32  static        2 _objectTypeCount

 

啊哈,看到曙光了,Column的内容,看样子就是存储在_storage里面的了,打开看看:


     0:000> !dumpobj 013b8fdc

Name: System.Data.Common.StringStorage

MethodTable: 653cdd38

EEClass: 6540eea4

Size: 44(0x2c) bytes

Fields:

      MT                 Type    Value         Name

653c3e94 ...m.Data.DataColumn         013b82fc       Column

653c46d8 ...em.Data.DataTable          013b6120      Table

79101058          System.Type      013b8390      DataType

653e2d80         System.Int32           18      StorageTypeCode

79166df8 ...lections.BitArray              00000000      dbNullBits

790f9c18        System.Object       790d6584      DefaultValue

790f9c18        System.Object       013b846c      NullValue

79104f64       System.Boolean           0       IsCloneable

79104f64       System.Boolean           0       IsCustomDefinedType

79104f64       System.Boolean           1      IsStringType

79104f64       System.Boolean           0        IsValueType

79124228      System.Object[]       013b8478      StorageClassType

79124228      System.Object[]       013b9008      values

 

看到values数组,应该就在这里了:


     0:000> !dumparray -details 013b9008

Name: System.String[]

MethodTable: 79124228

EEClass: 7912479c

Size: 528(0x210) bytes

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

Element Methodtable: 790fa3e0

 

下面输出的具体的数组里面的每个项,不知道为什么多了几百个null,就选择前两个显示出来:


[0] 013b60b0

    Name: System.String

    MethodTable: 790fa3e0

    EEClass: 790fa340

    Size: 26(0x1a) bytes 

    String:     aaaa   

    Fields:

          MT          Type  Value Name

    790fed1c  System.Int32      5 m_arrayLength

    790fed1c  System.Int32      4 m_stringLength

    790fbefc   System.Char     61 m_firstChar

    790fa3e0 System.String static Empty

    >> Domain:Value  00154598:790d6584 <<

    >> Domain:Value  00154598:013b16e8 <<

[1] 013b60e8

    Name: System.String

    MethodTable: 790fa3e0

    EEClass: 790fa340

    Size: 26(0x1a) bytes

    String:     cccc   

    Fields:

          MT          Type  Value Name

    790fed1c  System.Int32      5 m_arrayLength

    790fed1c  System.Int32      4 m_stringLength

    790fbefc   System.Char     63 m_firstChar

    790fa3e0 System.String static Empty

    >> Domain:Value  00154598:790d6584 <<

>> Domain:Value  00154598:013b16e8 <<

 

呵呵,看到了久违的aaaacccc,在最上面构在的DataTable里面的Column1里面。

 

节目的最后,在网上找到了一个Johan OlofssonWindbg Script直接传递两个参数可以打印出相应的DataTable的第几个第几个Column


.foreach

( value{

!do poi(poi(poi(poi(poi(poi(${$arg1}+0x18)+0x8)+0x4)+0xc+0x4*${$arg2})+0x48)+0x10) -v -short

})

{

!do ${value}

}


     使用的时候很简单:

$$>a< dumptablevalues 0x0a8cdaa8 0

这样就可以了。Dumptablevalues是你保存的windbg.exe相同目录下面的文件名。0x0a8cdaa8DataTableaddress0是你想要显示的第几列。

在快速查看DataTable里面的Column的时候比较有用。
     Script很简单,poi是取值的意思,里面的一系列十六进制的数字,就是在windbg输出的时候的Offset列的东西。每个数字对应者上面的一步一步的对象和层级关系。

另外,文中展示的windbg结果,为了显示排版方便,去掉了一些无关紧要的行和列。

 

Ok,到这里吧,就到这里吧。

 

2008-3-31 21:48:51 post to sscli.cnblogs.com

posted on 2008-03-31 22:03  lbq1221119  阅读(3501)  评论(18编辑  收藏  举报

导航