windbgsossosex

Running a command from the loop


I would like to run !refs command against each address from following command

!dumpgen 2 -type System.DateTime[]

How this could be done.I know a loop can be created as follows

.foreach (myvar {!dumpgen 2 -type System.DateTime[]}) 

But how can I access object address that could be used in loop with !refs?


Solution

  • !dumpgen does not have a -short argument like !dumpheap has and I'd really like to see a simpler answer than this one.

    Approach 1: dump a generation manually

    1. Get the addresses of the heap

      0:003> !eeheap -gc
      Number of GC Heaps: 1
      generation 0 starts at 0x026f1018
      generation 1 starts at 0x026f100c
      generation 2 starts at 0x026f1000
      
    2. Use the addresses to limit the output to the generation you want:

      !dumpheap -type X <start> <end>
      
    3. Use the -short parameter on !dumpheap, which outputs the address only. This address of an object can then be processed by other commands.

    Also note: using -type may result in other types as well. Better use the method table with -mt since only that guarantees the uniqueness of types. Use !name2ee if you don't get that from elsewhere.

    A complete session could look like this:

    0:003> !dumpheap -stat
    total 345 objects
    Statistics:
          MT    Count    TotalSize Class Name
    53ab421c        1           12 System.Text.DecoderExceptionFallback
    [...]
    53ab0d48      135         6640 System.String
    53a84518       26         9452 System.Object[]
    Total 345 objects
    
    0:003> !eeheap -gc
    Number of GC Heaps: 1
    generation 0 starts at 0x026f1018
    generation 1 starts at 0x026f100c
    generation 2 starts at 0x026f1000
    [...]
    
    0:003> !name2ee *!System.String
    Module: 53841000 (mscorlib.dll)
    Token: 0x02000024
    MethodTable: 53ab0d48
    [...]
    
    0:003> !dumpheap -short -mt 53ab0d48 0x026f1000 0x026f100c
    

    (Ok, all my strings seem to be in generation 0, damn :-)

    0:003> .foreach (addr {!dumpheap -short -mt 53ab0d48 0x026f1018}) {!refs ${addr}}
    

    Disadvantage: you need to do that for all GC heaps separately. There could be several of them.

    Approach 2: decide for the generation on each single object

    Another ugly solution is to

    1. Dump all object addresses (!dumpheap -short and -type or -mt)
    2. Query the generation of each object via !gcgen
    3. Depending on the generation, execute a command

    Here's how to do it (formatted for readability, put it all into one line):

    .foreach (addr {!dumpheap -short -mt 53ab0d48}) {
        .foreach /pS 1 (gen {!gcgen ${addr}}) { 
            .if ($scmp("${gen}","2")==0) {
                !refs ${addr}
            }
        }
    }
    

    where 53ab0d48 is the method table of the type you're looking for and "2" is the generation you want. /pS 1 skips the word "Gen" in the output of !gcgen.

    Disadvantage: might be slow since it works on all objects.