【问题标题】:WinDbg and SoS, how do I print/dump a large string?WinDbg 和 SoS,如何打印/转储大字符串?
【发布时间】:2019-10-15 18:38:30
【问题描述】:

我正在使用带有 SoS 扩展的 WinDbg 调试来自生产服务器的挂起转储。

其中一个堆栈中有一个字符串参数,我需要知道它的值。但是,它是一个相当大的字符串,当我使用DumpObj 时,WinDbg 不会打印它。这是DumpObj 的输出:

0:036> !do 00000001b30d8668
Name: System.String
MethodTable: 0000064278436728
EEClass: 000006427803e520
Size: 5125300(0x4e34b4) bytes
 (C:\WINDOWS\assembly\GAC_64\mscorlib\2.0.0.0__b77a5c561934e089\mscorlib.dll)
String: <String is invalid or too large to print>

Fields:
              MT    Field   Offset                 Type VT     Attr            Value Name
000006427843d998  4000096        8         System.Int32  1 instance          2562638 m_arrayLength
000006427843d998  4000097        c         System.Int32  1 instance          2562637 m_stringLength
0000064278438170  4000098       10          System.Char  1 instance               3c m_firstChar
0000064278436728  4000099       20        System.String  0   shared           static Empty
                                 >> Domain:Value  0000000000163260:000000007fff0370 00000000001a6760:000000007fff0370 <<
0000064278438020  400009a       28        System.Char[]  0   shared           static WhitespaceChars
                                 >> Domain:Value  0000000000163260:000000007fff0b60 00000000001a6760:000000007fff89f0 <<

如何获取此字符串实例的值?最好转储到文件中。

【问题讨论】:

    标签: .net debugging windbg dump sos


    【解决方案1】:

    这是我编写的一个脚本,用于将字符串转储到 windbg 中的文件。

    $$ Dumps the managed strings to a file
    $$ Platform x86
    $$ Usage $$>a<"c:\temp\dumpstringtofolder.txt" 6544f9ac 5000 c:\temp\stringtest
    $$ First argument is the string method table pointer
    $$ Second argument is the Min size of the string that needs to be used filter
    $$ the strings
    $$ Third is the path of the file
    .foreach ($string {!dumpheap -short -mt ${$arg1}  -min ${$arg2}})
    { 
    
      $$ MT        Field      Offset               Type  VT     Attr    Value Name
      $$ 65452978  40000ed        4         System.Int32  1 instance    71117 m_stringLength
      $$ 65451dc8  40000ee        8          System.Char  1 instance       3c m_firstChar
      $$ 6544f9ac  40000ef        8        System.String  0   shared   static Empty
    
      $$ start of string is stored in the 8th offset, which can be inferred from above
      $$ Size of the string which is stored in the 4th offset
      r@$t0=  poi(${$string}+4)*2
      .writemem ${$arg3}${$string}.txt ${$string}+8 ${$string}+8+@$t0
    }
    

    这就是它的使用方式$$&gt;a&lt;”c:\temp\dumpstringtofolder.txt” 6544f9ac 5000 c:\temp\stringtest

    转储的内容将采用 Unicode 格式,要查看其内容,请使用类似 Console.WriteLine(ASCIIEncoding.Unicode.GetString(File.ReadAllBytes(@"c:\temp\stringtest03575270.txt")));

    HTH

    【讨论】:

    • 我无法让脚本为我工作,但 .writemem 函数很简单,根据您的示例,我能够自己工作。
    • @AndrewArnott 我能够使用此脚本转储字符串,并且我经常使用它。你遇到了什么问题?你在 x86/x64 中使用它吗?
    • 不确定我们是否可以依赖 !Name2EE 的输出,但这可用于自动获取方法表指针 (r@$t1),因此我们可以去掉参数 1。.foreach /pS 7 /ps 4 (方法表 {!Name2EE mscorlib.dll System.String}) { r@$t1= ${methodtable} }
    • @ThomasW.我同意。可以使用!Name2EE 自动执行
    • 这里的 *2 r@$t0= poi(${$string}+4)*2 有什么作用?
    【解决方案2】:

    在转储 2562638 个字符的文本之前我会三思而后行,但如果你真的想要,文本存储在字符串实例的字段之后,所以你可以做一个 du &lt;address+offset&gt; &lt;end address&gt; 来转储字符串的实际文本.输出将如下所示:

    00000000`132ab050  "this is an extremely long string"
    00000000`132ab090  " of text, so don't even bother t"
    00000000`132ab0d0  "o try to dump it to the screen -"
    

    通过将会话输出记录到文件中,您可以轻松捕获输出并进行所需的任何后处理。

    【讨论】:

    • 如果字符串很长,由于限制,开始地址/结束地址语法将不起作用。你需要使用du
      L吗? 。对于非常长的字符串,这实际上会花费很长时间并且 WinDbg 不再响应。
    • 我在日志中收到与命令行窗口相同的消息:
    【解决方案3】:

    我已修改 @Naveen 的脚本以在 x64 平台上工作。

    顺便说一句,很棒的脚本!

    $$ Dumps the managed strings to a file
    $$ Platform x64
    $$ Usage $$>a<"c:\temp\dumpstringtofolder.txt" 00007ffa6c509808 5000 c:\temp\stringtest
    $$ First argument is the string method table pointer
    $$ Second argument is the Min size of the string that needs to be used filter
    $$ the strings
    $$ Third is the path of the file
    .foreach ($string {!dumpheap -short -mt ${$arg1}  -min ${$arg2}})
    { 
        $$               MT    Field   Offset                 Type VT     Attr            Value Name
        $$ 00007ffa6c50c158  400027b        8         System.Int32  1 instance               18 m_stringLength
        $$ 00007ffa6c50a9c0  400027c        c          System.Char  1 instance               53 m_firstChar
        $$ 00007ffa6c509808  4000280       c0        System.String  0   shared           static Empty
    
        $$ start of string is stored in the 8th offset, which can be inferred from above
        $$ Size of the string which is stored in the c-th offset
        r@$t0= (poi(${$string}+8) & 00000000FFFFFFFF) *2
        .writemem ${$arg3}${$string}.txt (${$string}+c) (${$string}+c+@$t0)
    }
    

    【讨论】:

    • 超大字符串似乎有问题。 I get this output for the string objects but when I use the script, it stop at the third one 0:000> !dumpheap -mt 00007ff8ca9d10b0 -min 1000000 Address MT Size 000000670d17a4c8 00007ff8ca9d10b0 35377744 0000006717767bd8 00007ff8ca9d10b0 141515814 00000069686a1020 00007ff8ca9d10b0 1132138640 00000068c06a1020 00007ff8ca9d10b0 566068092 00000069d06a1020 00007ff8ca9d10b0 1132138588 统计 MT Count TotalSize 类名 00007ff8ca9d10b0 5 3007238878 System.String 共 5 个对象
    • 我尝试修改 WriteMem 以使用长度范围而不是地址范围,但它似乎也不起作用。 .writemem ${$arg3}${$string}.txt (${$string}+c) L(@$t0)
    • 问题是超过256MB需要L? .writemem ${$arg3}${$string}.txt (${$string}+c) L?(@$t0)
    【解决方案4】:

    如果您赶时间,请在 WinDbg 中启用日志后运行 !do。在日志文件中,您将获得整个字符串。

    在WinDbg菜单中,进入编辑->打开/关闭日志文件,设置日志文件路径。

    【讨论】:

    • 我在日志中收到与命令行窗口相同的消息:
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-09-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-09-29
    • 2021-06-08
    • 2018-07-27
    相关资源
    最近更新 更多