使用 Windbg 调试器命令转储字符串数组
Dump string array using Windbg debugger commands
我想将托管字符串数组转储到一个文件中,文件中的每一行对应数组中的一个字符串。
我有数组地址,所以我开始:
.foreach (ptr { !da <address> } ) {
}
鉴于 !da
输出如下所示,我如何 .printf
字符串:
[0] 000002104816bf00
[1] 000002104816c220
[2] 000002104816c528
是的,当然,这是可能的 - 如果您喜欢 WinDbg 的语法...
给定一个像
这样的简单程序
using System;
namespace DumpStringArray
{
class Program
{
static void Main()
{
string[] a = new string[1000];
for (int i = 0; i < a.Length; i++)
{
a[i] = "Line "+i;
}
Console.WriteLine("Debug now");
Console.ReadLine();
Console.WriteLine(a[0]);
}
}
}
我们首先使用!clrstack
获取局部变量a
的值:
0:000> !clrstack -a
[...]
0137ecf8 019e0516 *** WARNING: Unable to verify checksum for DumpStringArray.exe
DumpStringArray.Program.Main() [...\DumpStringArray\DumpStringArray\Program.cs @ 16]
LOCALS:
0x0137ed14 = 0x033c241c
0x0137ed20 = 0x000003e8
0x0137ed1c = 0x00000000
0137ee98 5cdaebe6 [GCFrame: 0137ee98]
0:000> !DumpObj /d 033c241c
Name: System.String[]
MethodTable: 5beb08b8
EEClass: 5ba84fc0
Size: 4012(0xfac) bytes
Array: Rank 1, Number of elements 1000, Type CLASS (Print Array)
Fields:
None
0:000>
如果您打印该数组,您会看到它在实际项目列表之前有一堆文本:
0:000> !DumpArray /d 033c241c
Name: System.String[]
MethodTable: 5beb08b8
EEClass: 5ba84fc0
Size: 4012(0xfac) bytes
Array: Rank 1, Number of elements 1000, Type CLASS
Element Methodtable: 5beafd60
[0] 033c4a98
[1] 033c4ad0
[2] 033c4b08
[...]
让我们数一数列表开始前的标记数:
Name:
System.String[]
MethodTable:
5beb08b8
EEClass:
5ba84fc0
Size:
4012(0xfac)
bytes
Array:
Rank
1,
Number
of
elements
1000,
Type
CLASS
Element
Methodtable:
5beafd60
[0]
因此,您需要在 .foreach
循环中 /pS 0n22
才能跳过这些。
接下来,您需要 /ps 0n1
跳过所有其他数组索引。
到目前为止的命令是 .foreach /pS 0n22 /ps 0n1 (str {!da <address>}) { }
。
现在,一个 .NET 字符串有一个 header,所以实际的字符串内容并不是从地址开始的,而是稍晚一些:
0:000> !do 033d42a4
Name: System.String
MethodTable: 5beafd60
EEClass: 5ba84e90
Size: 30(0x1e) bytes
File: C:\Windows\Microsoft.Net\assembly\GAC_32\mscorlib\v4.0_4.0.0.0__b77a5c561934e089\mscorlib.dll
String: Line 999
Fields:
MT Field Offset Type VT Attr Value Name
5beb1bc0 400027b 4 System.Int32 1 instance 8 m_stringLength
5beb07a8 400027c 8 System.Char 1 instance 4c m_firstChar
5beafd60 4000280 60 System.String 0 shared static Empty
>> Domain:Value 01408b18:NotInit <<
可以看到,第一个字符的偏移量是8
.
我们可以使用du
在给定的偏移处显示Unicode字符串,所以命令现在是:
.foreach /pS 0n22 /ps 0n1 (str {!da <address>}) { du ${str}+8 }
不幸的是,这将输出地址和文本:
0:000> .foreach /pS 0n22 /ps 1 (str {!da 033c241c}){du ${str}+8}
033c4aa0 "Line 0"
033c4ad8 "Line 1"
033c4b10 "Line 2"
[...]
所以是的,你需要 .printf
来解决这个问题:
.foreach /pS 0n22 /ps 1 (str {!da 033c241c}){.printf "%mu\n", (${str}+8)}
现在,这适用于 32 位。我将 64 位迁移作为练习留给您。
打开文本文件之前使用.logopen
,之后使用.logclose
。
我想将托管字符串数组转储到一个文件中,文件中的每一行对应数组中的一个字符串。
我有数组地址,所以我开始:
.foreach (ptr { !da <address> } ) {
}
鉴于 !da
输出如下所示,我如何 .printf
字符串:
[0] 000002104816bf00
[1] 000002104816c220
[2] 000002104816c528
是的,当然,这是可能的 - 如果您喜欢 WinDbg 的语法...
给定一个像
这样的简单程序using System;
namespace DumpStringArray
{
class Program
{
static void Main()
{
string[] a = new string[1000];
for (int i = 0; i < a.Length; i++)
{
a[i] = "Line "+i;
}
Console.WriteLine("Debug now");
Console.ReadLine();
Console.WriteLine(a[0]);
}
}
}
我们首先使用!clrstack
获取局部变量a
的值:
0:000> !clrstack -a
[...]
0137ecf8 019e0516 *** WARNING: Unable to verify checksum for DumpStringArray.exe
DumpStringArray.Program.Main() [...\DumpStringArray\DumpStringArray\Program.cs @ 16]
LOCALS:
0x0137ed14 = 0x033c241c
0x0137ed20 = 0x000003e8
0x0137ed1c = 0x00000000
0137ee98 5cdaebe6 [GCFrame: 0137ee98]
0:000> !DumpObj /d 033c241c
Name: System.String[]
MethodTable: 5beb08b8
EEClass: 5ba84fc0
Size: 4012(0xfac) bytes
Array: Rank 1, Number of elements 1000, Type CLASS (Print Array)
Fields:
None
0:000>
如果您打印该数组,您会看到它在实际项目列表之前有一堆文本:
0:000> !DumpArray /d 033c241c
Name: System.String[]
MethodTable: 5beb08b8
EEClass: 5ba84fc0
Size: 4012(0xfac) bytes
Array: Rank 1, Number of elements 1000, Type CLASS
Element Methodtable: 5beafd60
[0] 033c4a98
[1] 033c4ad0
[2] 033c4b08
[...]
让我们数一数列表开始前的标记数:
Name:
System.String[]
MethodTable:
5beb08b8
EEClass:
5ba84fc0
Size:
4012(0xfac)
bytes
Array:
Rank
1,
Number
of
elements
1000,
Type
CLASS
Element
Methodtable:
5beafd60
[0]
因此,您需要在 .foreach
循环中 /pS 0n22
才能跳过这些。
接下来,您需要 /ps 0n1
跳过所有其他数组索引。
到目前为止的命令是 .foreach /pS 0n22 /ps 0n1 (str {!da <address>}) { }
。
现在,一个 .NET 字符串有一个 header,所以实际的字符串内容并不是从地址开始的,而是稍晚一些:
0:000> !do 033d42a4
Name: System.String
MethodTable: 5beafd60
EEClass: 5ba84e90
Size: 30(0x1e) bytes
File: C:\Windows\Microsoft.Net\assembly\GAC_32\mscorlib\v4.0_4.0.0.0__b77a5c561934e089\mscorlib.dll
String: Line 999
Fields:
MT Field Offset Type VT Attr Value Name
5beb1bc0 400027b 4 System.Int32 1 instance 8 m_stringLength
5beb07a8 400027c 8 System.Char 1 instance 4c m_firstChar
5beafd60 4000280 60 System.String 0 shared static Empty
>> Domain:Value 01408b18:NotInit <<
可以看到,第一个字符的偏移量是8
.
我们可以使用du
在给定的偏移处显示Unicode字符串,所以命令现在是:
.foreach /pS 0n22 /ps 0n1 (str {!da <address>}) { du ${str}+8 }
不幸的是,这将输出地址和文本:
0:000> .foreach /pS 0n22 /ps 1 (str {!da 033c241c}){du ${str}+8}
033c4aa0 "Line 0"
033c4ad8 "Line 1"
033c4b10 "Line 2"
[...]
所以是的,你需要 .printf
来解决这个问题:
.foreach /pS 0n22 /ps 1 (str {!da 033c241c}){.printf "%mu\n", (${str}+8)}
现在,这适用于 32 位。我将 64 位迁移作为练习留给您。
打开文本文件之前使用.logopen
,之后使用.logclose
。