WinDbg: using several tokens from .foreach for input of a command
Asked Answered
B

3

2

Some background info

Recently I have asked a question and received a great answer using .foreach. Now I have a dump with lots of very large char[] inside. I did

.logopen c:\mychararrays.log
!dumpheap -type System.Char[]
.logclose

I have stripped of all the human readable stuff like summary etc. Now the file has lots of lines with object address, method table and size:

03d74c88 52b8b680  5570670
042c4cf8 52b8b680  5762890     
...
21a1d6e0 52b8b680  6010030

I have already used

.foreach /ps 2 /f (chararray "c:\mychararrays.log") { !do ${chararray} }

to dump out the .NET objects, but this will not dump the complete text of the char[], only the first 128 characters. And unfortunately, the beginning of those char[] is always the same.

The question

I want to do something like

.foreach /f (chararray "c:\mychararrays.log") { du <token 1 of line>+8 L? 0n<token 3 of line> }

for each line in order to print the complete char[]. By default WinDbg will separate tokens within a line and process them one by one, so there's only one token available for the command.

Solving it in Notepad++

I have already solved this by doing a regular expression replacement in Notepad++. I just want to know if there's a "native" WinDbg solution to this.

Find: ([^ ]*) [^ ]*  ([^ ]*).*
Replace: du \1+8 L? 0n\2

And then running the result as a script:

$<c:\mychararrays.log

Note: This took a VERY long time, so I decided to switch to

Find: ([^ ]*) [^ ]*  ([^ ]*).*
Replace: .writemem c:\s\1.txt \1+8 L? 0n\2
Balcom answered 11/12, 2013 at 9:52 Comment(0)
C
0

Try python extension for windbg pykd.codeplex.com. With python you get RE, flexible scripting language and fast solving your problems

Cognation answered 21/12, 2013 at 7:25 Comment(1)
Downloaded and installed. Using !help didn't immediately reveal anything which would be helpful. Any suggestions for a command?Balcom
P
1

If you know the maximum size then you can specify that size to du and it will stop printing at the first null terminator. For example, if I know that the max is 10,000,000 then the following prints correctly even though the length is 320 characters:

0:000> du 00000000033495d8 +10 L?0n10000000
00000000`033495e8  "PermissionSetty.PermissionSeting"
00000000`03349628  "Permission, System.Drawing, Vers"
00000000`03349668  "ion=2.0.0.0, Culture=neutral, Pu"
00000000`033496a8  "blicKeyToken=b03f5f7f11d50a3a619"
00000000`033496e8  "34e0899AD9D5DCC1DD9AD23613210290"
00000000`03349728  "0B723CF980957FC4E177108FC607774F"
00000000`03349768  "29E8320E92EA05ECE4E821C0A5EFE8F1"
00000000`033497a8  "645C4C0C93C1AB99285D622CAA652C1D"
00000000`033497e8  "FAD63D745D6F2DE5F17E5EAF0FC4963D"
00000000`03349828  "261C8A12436518206DC093344D5AD293"
00000000`03349868  ""

And here's the null terminator at 00000000`03349868:

0:000> db 00000000`03349868 l2
00000000`03349868  00 00

So even though I gave a range of 10 million to du, it knew to stop at the first null terminator.

BTW this is a dump of a 64 bit process so that may be why my offset to the char buffer is different than yours.

If you absolutely need the actual size, then we can grab that as an offset from the object address so that you don't need to try to grab that value as another token. But hopefully the max works for you.

Phatic answered 20/12, 2013 at 16:39 Comment(1)
Your answer helps in this particular situation but not in similar situations which needs several tokens.Balcom
C
0

Try python extension for windbg pykd.codeplex.com. With python you get RE, flexible scripting language and fast solving your problems

Cognation answered 21/12, 2013 at 7:25 Comment(1)
Downloaded and installed. Using !help didn't immediately reveal anything which would be helpful. Any suggestions for a command?Balcom
I
0

Though it doesn't depend on any extensions, etc, this may not be the "native" solution you were looking for (5+ years ago, I know - I'll just be posting for reference), but I believe what you're after can be achieved by bit of book-keeping, and careful alias/psudo-register management.

The general idea is that the main block of foreach loop receives every token, and remembers them and uses them when all tokens for the main processing are stored. Something along the lines of the following script that lists the loaded modules starting with "ora*" in the current target, and lists their start address, and size (which is not available in single-line/module lm output):

ad /q startAddress;
ad /q endAddress;
r $t0=0;
.foreach /pS 8 (token {lmn m ora*}) {
    r $t0=@$t0 + 1;
    .if (@$t0 % 4 == 1) { as ${/v:startAddress} ${token}};
    .if (@$t0 % 4 == 2) { as ${/v:endAddress} ${token}};
    .if (@$t0 % 4 == 0) {.printf "${token}=%x,%x\n", ${startAddress}, ${endAddress} - ${startAddress}}; 
}

As you've probably guessed, the main requirement is that there are definitely N tokens (4 in my example) in every line (or if a certain token can be identified as "marker", that may also be used to reset the counter I've done modulus arithmetic with). That is, if lines have different number of tokens (due to spaces in filenames, etc), this will not work w/o a workaround.

Single line copy-paste:

ad /q startAddress; ad /q endAddress; r $t0=0; .foreach /pS 8 (token {lmn m ora*}) {r $t0=@$t0 + 1; .if (@$t0 % 4 == 1) { as ${/v:startAddress} ${token}}; .if (@$t0 % 4 == 2) { as ${/v:endAddress} ${token}}; .if (@$t0 % 4 == 0) {.printf "${token}=%x,%x\n", ${startAddress}, ${endAddress} - ${startAddress}}; }

Also note that, if the tokens to be processed are numeric, using pseudo-registers instead of aliases would make things somewhat easier since you'd be avoiding alias idiosyncracies of WinDbg! Even though my tokens were indeed numeric, I've used aliases here to provide a more generic example/template.

Impatiens answered 27/3, 2019 at 16:51 Comment(1)
Thanks. I can't recall the project I needed this for. I'll need to set up a test program to try this again.Balcom

© 2022 - 2024 — McMap. All rights reserved.