WinDbg and SoS, how do I print/dump a large string?
Asked Answered
F

4

17

I am debugging a hangdump coming from a production server using WinDbg with the SoS extension.

There is a string parameter in one of the stacks, that I need to know the value of. However, it is a rather large string, and WinDbg won't print it when I am using DumpObj. This is the output from 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 <<

How can I get the value of this string instance ? Preferably dumped to a file.

Fates answered 18/3, 2011 at 9:9 Comment(0)
B
9

I would think twice before dumping 2562638 characters worth of text, but if you really want to, the text is stored following the fields of the string instance, so you can do a du <address+offset> <end address> to dump the actual text of the string. The output will look something like this:

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 -"

By logging the session output to a file, you can easily capture the output and do whatever post-processing you need.

Buxom answered 18/3, 2011 at 9:37 Comment(3)
In case of really long strings, the start address / end address syntax won't work due to limits. You need to use du <address+offset> L? <length in bytes>. For really long strings, this will actually take too long and WinDbg is not responding any more.Seritaserjeant
I get the same message in the log as in the Command Window: <String is invalid or too large to print>Livre
An example of how I used it: du 0x181B4C71020+10 L? 10000. Not sure why but I had to offset it from 10 to make it worked.Shout
B
15

Here is a script I wrote to dump strings to a file within 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
}

and this is how it can be used$$>a<”c:\temp\dumpstringtofolder.txt” 6544f9ac 5000 c:\temp\stringtest

The dumped contents would be in Unicode format and to view its contents use something like this Console.WriteLine(ASCIIEncoding.Unicode.GetString(File.ReadAllBytes(@"c:\temp\stringtest03575270.txt")));

HTH

Bosley answered 18/3, 2011 at 12:53 Comment(6)
I couldn't get the script to work for me, but the .writemem function is simple enough based on your sample I was able to get it to work myself.Airdry
@AndrewArnott I was able to dump string using this script and I use it often. What was the issue you were running into? Are you using it in x86/x64?Bosley
Not sure if we can rely on the output of !Name2EE but this can be used to get the method table pointer automatically (r@$t1), so we could get rid of parameter 1. .foreach /pS 7 /ps 4 (methodtable {!Name2EE mscorlib.dll System.String}) { r@$t1= ${methodtable} }Seritaserjeant
@ThomasW.I agree. It could be automated using !Name2EEBosley
What does the *2 accomplish here r@$t0= poi(${$string}+4)*2?Zero
Sorry, I think I know why now, the char is 2 bytesZero
B
9

I would think twice before dumping 2562638 characters worth of text, but if you really want to, the text is stored following the fields of the string instance, so you can do a du <address+offset> <end address> to dump the actual text of the string. The output will look something like this:

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 -"

By logging the session output to a file, you can easily capture the output and do whatever post-processing you need.

Buxom answered 18/3, 2011 at 9:37 Comment(3)
In case of really long strings, the start address / end address syntax won't work due to limits. You need to use du <address+offset> L? <length in bytes>. For really long strings, this will actually take too long and WinDbg is not responding any more.Seritaserjeant
I get the same message in the log as in the Command Window: <String is invalid or too large to print>Livre
An example of how I used it: du 0x181B4C71020+10 L? 10000. Not sure why but I had to offset it from 10 to make it worked.Shout
B
3

I have modified @Naveen's script to work on x64 platforms.

Great script btw!

$$ 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)
}
Bailiff answered 15/10, 2019 at 10:38 Comment(3)
There seems to be a problem with very large string. 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 Statistics MT Count TotalSize Class Name 00007ff8ca9d10b0 5 3007238878 System.String Total 5 objectsLargescale
I tried modifying the WriteMem to use a Length range instead of Address range but it doesn't seem to work either. .writemem ${$arg3}${$string}.txt (${$string}+c) L(@$t0)Largescale
The problem was that it was over 256MB and needed L? .writemem ${$arg3}${$string}.txt (${$string}+c) L?(@$t0)Largescale
A
0

If you are in a hurry, run the !do after enabling logs in WinDbg. In the log file, you will get the entire string.

In WinDbg menu, go to Edit-> Open/Close log file, to set log file path.

Awoke answered 7/6, 2013 at 2:54 Comment(1)
I get the same message in the log as in the Command Window: <String is invalid or too large to print>Livre

© 2022 - 2024 — McMap. All rights reserved.