Welcome to MSDN Blogs Sign in | Join | Help

When debugging sooner or later you will need to disassemble code to get a better understanding of that code.

By disassembling the code, you get the mnemonics translated from the 0s and 1s that constitute the binary code. It is a low level view of the code, but a higher level than seeing just numbers.

 

The commands syntaxes are:

 

u[b] [address]

u[b] [range]

u[b]

 

uf [options] <address>

 

Where options are:

 

/c - Displays only the call instructions in a routine.

/D - Creates linked callee names for navigation of the call graph.

/o - Sorts the display by address instead of by function offset.

/O - Creates linked call lines for accessing call information and creating breakpoints.

/i - Displays the number of instructions in a routine.

 

 

To demonstrate this command, let’s use this simple Visual C++ application that recursively calculates the Fibonacci from a specific number:

 

#include "stdafx.h"

 

using namespace std;

 

// Recursive function.

unsigned FiboRecursive(unsigned n, int nNum = 0)

{       

          if(n <= 1)

          {

                    return n;

          }

                   

          return FiboRecursive(n - 1, 1) + FiboRecursive(n - 2, 2);

}

 

int _tmain(int argc, _TCHAR* argv[])

{

          cout << FiboRecursive(5) << endl;

 

          return 0;

}

 

Let’s break the execution when the line from main() only is being executed, using a breakpoint for that.

 

Now let’s disassemble the eip register.

 

0:000> u @eip

Fibo!wmain+0x1e [c:\development\my tools\fibo\fibo\fibo.cpp @ 21]:

00a7145e 8bf4            mov     esi,esp

00a71460 a19882a700      mov     eax,dword ptr [Fibo!_imp_?endlstdYAAAV?$basic_ostreamDU?$char_traitsDstd (00a78298)]

00a71465 50              push    eax

00a71466 6a00            push    0

00a71468 6a05            push    5

00a7146a e89bfbffff      call    Fibo!ILT+5(?FiboRecursiveYAIIHZ) (00a7100a)

00a7146f 83c408          add     esp,8

00a71472 8bfc            mov     edi,esp

 

Using this approach we see the disassembled code starting from eip.

We can see the disassembled code that comes before eip using this approach:

 

0:000> ub @eip L8

Fibo!wmain+0x3 [c:\development\my tools\fibo\fibo\fibo.cpp @ 20]:

00a71443 81ecc0000000    sub     esp,0C0h

00a71449 53              push    ebx

00a7144a 56              push    esi

00a7144b 57              push    edi

00a7144c 8dbd40ffffff    lea     edi,[ebp-0C0h]

00a71452 b930000000      mov     ecx,30h

00a71457 b8cccccccc      mov     eax,0CCCCCCCCh

00a7145c f3ab            rep stos dword ptr es:[edi]

 

Keep in mind that b is for backward.

 

Let’s suppose you want to disassemble the entire function without having the work of finding the beginning of the function.

To accomplish that you use uf, and it automatically does that for you:

 

0:000> uf @eip

Fibo!wmain [c:\development\my tools\fibo\fibo\fibo.cpp @ 20]:

   20 00a71440 55              push    ebp

   20 00a71441 8bec            mov     ebp,esp

   20 00a71443 81ecc0000000    sub     esp,0C0h

   20 00a71449 53              push    ebx

   20 00a7144a 56              push    esi

   20 00a7144b 57              push    edi

   20 00a7144c 8dbd40ffffff    lea     edi,[ebp-0C0h]

   20 00a71452 b930000000      mov     ecx,30h

   20 00a71457 b8cccccccc      mov     eax,0CCCCCCCCh

   20 00a7145c f3ab            rep stos dword ptr es:[edi]

   21 00a7145e 8bf4            mov     esi,esp

   21 00a71460 a19882a700      mov     eax,dword ptr [Fibo!_imp_?endlstdYAAAV?$basic_ostreamDU?$char_traitsDstd (00a78298)]

   21 00a71465 50              push    eax

   21 00a71466 6a00            push    0

   21 00a71468 6a05            push    5

   21 00a7146a e89bfbffff      call    Fibo!ILT+5(?FiboRecursiveYAIIHZ) (00a7100a)

   21 00a7146f 83c408          add     esp,8

   21 00a71472 8bfc            mov     edi,esp

   21 00a71474 50              push    eax

   21 00a71475 8b0d9082a700    mov     ecx,dword ptr [Fibo!_imp_?coutstd (00a78290)]

   21 00a7147b ff159482a700    call    dword ptr [Fibo!_imp_??6?$basic_ostreamDU?$char_traitsDstdstdQAEAAV01IZ (00a78294)]

   21 00a71481 3bfc            cmp     edi,esp

   21 00a71483 e8d1fcffff      call    Fibo!ILT+340(__RTC_CheckEsp) (00a71159)

   21 00a71488 8bc8            mov     ecx,eax

   21 00a7148a ff159c82a700    call    dword ptr [Fibo!_imp_??6?$basic_ostreamDU?$char_traitsDstdstdQAEAAV01P6AAAV01AAV01ZZ (00a7829c)]

   21 00a71490 3bf4            cmp     esi,esp

   21 00a71492 e8c2fcffff      call    Fibo!ILT+340(__RTC_CheckEsp) (00a71159)

   23 00a71497 33c0            xor     eax,eax

   24 00a71499 5f              pop     edi

   24 00a7149a 5e              pop     esi

   24 00a7149b 5b              pop     ebx

   24 00a7149c 81c4c0000000    add     esp,0C0h

   24 00a714a2 3bec            cmp     ebp,esp

   24 00a714a4 e8b0fcffff      call    Fibo!ILT+340(__RTC_CheckEsp) (00a71159)

   24 00a714a9 8be5            mov     esp,ebp

   24 00a714ab 5d              pop     ebp

   24 00a714ac c3              ret

 

Let’s see just the calls made by this function:

 

0:000> uf /c @eip

Fibo!wmain (00a71440) [c:\development\my tools\fibo\fibo\fibo.cpp @ 20]

  Fibo!wmain+0x2a (00a7146a) [c:\development\my tools\fibo\fibo\fibo.cpp @ 21]:

    call to Fibo!ILT+5(?FiboRecursiveYAIIHZ) (00a7100a)

  Fibo!wmain+0x3b (00a7147b) [c:\development\my tools\fibo\fibo\fibo.cpp @ 21]:

    call to MSVCP90D!std::basic_ostream<char,std::char_traits<char> >::operator<< (690fa700) [f:\dd\vctools\crt_bld\self_x86\crt\src\ostream @ 289]

  Fibo!wmain+0x43 (00a71483) [c:\development\my tools\fibo\fibo\fibo.cpp @ 21]:

    call to Fibo!ILT+340(__RTC_CheckEsp) (00a71159)

  Fibo!wmain+0x4a (00a7148a) [c:\development\my tools\fibo\fibo\fibo.cpp @ 21]:

    call to MSVCP90D!std::basic_ostream<char,std::char_traits<char> >::operator<< (690f9f60) [f:\dd\vctools\crt_bld\self_x86\crt\src\ostream @ 171]

  Fibo!wmain+0x52 (00a71492) [c:\development\my tools\fibo\fibo\fibo.cpp @ 21]:

    call to Fibo!ILT+340(__RTC_CheckEsp) (00a71159)

  Fibo!wmain+0x64 (00a714a4) [c:\development\my tools\fibo\fibo\fibo.cpp @ 24]:

    call to Fibo!ILT+340(__RTC_CheckEsp) (00a71159)

 

 

Creates linked callee names from the same function:

 

0:000> uf /D @eip

Fibo!wmain [c:\development\my tools\fibo\fibo\fibo.cpp @ 20]:

   20 00a71440 55              push    ebp

   20 00a71441 8bec            mov     ebp,esp

   20 00a71443 81ecc0000000    sub     esp,0C0h

   20 00a71449 53              push    ebx

   20 00a7144a 56              push    esi

   20 00a7144b 57              push    edi

   20 00a7144c 8dbd40ffffff    lea     edi,[ebp-0C0h]

   20 00a71452 b930000000      mov     ecx,30h

   20 00a71457 b8cccccccc      mov     eax,0CCCCCCCCh

   20 00a7145c f3ab            rep stos dword ptr es:[edi]

   21 00a7145e 8bf4            mov     esi,esp

   21 00a71460 a19882a700      mov     eax,dword ptr [Fibo!_imp_?endlstdYAAAV?$basic_ostreamDU?$char_traitsDstd (00a78298)]

   21 00a71465 50              push    eax

   21 00a71466 6a00            push    0

   21 00a71468 6a05            push    5

   21 00a7146a e89bfbffff      call    Fibo!ILT+5(?FiboRecursiveYAIIHZ) (00a7100a)

   21 00a7146f 83c408          add     esp,8

   21 00a71472 8bfc            mov     edi,esp

   21 00a71474 50              push    eax

   21 00a71475 8b0d9082a700    mov     ecx,dword ptr [Fibo!_imp_?coutstd (00a78290)]

   21 00a7147b ff159482a700    call    dword ptr [Fibo!_imp_??6?$basic_ostreamDU?$char_traitsDstdstdQAEAAV01IZ (00a78294)]

   21 00a71481 3bfc            cmp     edi,esp

   21 00a71483 e8d1fcffff      call    Fibo!ILT+340(__RTC_CheckEsp) (00a71159)

   21 00a71488 8bc8            mov     ecx,eax

   21 00a7148a ff159c82a700    call    dword ptr [Fibo!_imp_??6?$basic_ostreamDU?$char_traitsDstdstdQAEAAV01P6AAAV01AAV01ZZ (00a7829c)]

   21 00a71490 3bf4            cmp     esi,esp

   21 00a71492 e8c2fcffff      call    Fibo!ILT+340(__RTC_CheckEsp) (00a71159)

   23 00a71497 33c0            xor     eax,eax

   24 00a71499 5f              pop     edi

   24 00a7149a 5e              pop     esi

   24 00a7149b 5b              pop     ebx

   24 00a7149c 81c4c0000000    add     esp,0C0h

   24 00a714a2 3bec            cmp     ebp,esp

   24 00a714a4 e8b0fcffff      call    Fibo!ILT+340(__RTC_CheckEsp) (00a71159)

   24 00a714a9 8be5            mov     esp,ebp

   24 00a714ab 5d              pop     ebp

   24 00a714ac c3              ret

 

 

Sorts the output by address:

 

0:000> uf /o @eip

Fibo!wmain [c:\development\my tools\fibo\fibo\fibo.cpp @ 20]:

   20 00a71440 55              push    ebp

   20 00a71441 8bec            mov     ebp,esp

   20 00a71443 81ecc0000000    sub     esp,0C0h

   20 00a71449 53              push    ebx

   20 00a7144a 56              push    esi

   20 00a7144b 57              push    edi

   20 00a7144c 8dbd40ffffff    lea     edi,[ebp-0C0h]

   20 00a71452 b930000000      mov     ecx,30h

   20 00a71457 b8cccccccc      mov     eax,0CCCCCCCCh

   20 00a7145c f3ab            rep stos dword ptr es:[edi]

   21 00a7145e 8bf4            mov     esi,esp

   21 00a71460 a19882a700      mov     eax,dword ptr [Fibo!_imp_?endlstdYAAAV?$basic_ostreamDU?$char_traitsDstd (00a78298)]

   21 00a71465 50              push    eax

   21 00a71466 6a00            push    0

   21 00a71468 6a05            push    5

   21 00a7146a e89bfbffff      call    Fibo!ILT+5(?FiboRecursiveYAIIHZ) (00a7100a)

   21 00a7146f 83c408          add     esp,8

   21 00a71472 8bfc            mov     edi,esp

   21 00a71474 50              push    eax

   21 00a71475 8b0d9082a700    mov     ecx,dword ptr [Fibo!_imp_?coutstd (00a78290)]

   21 00a7147b ff159482a700    call    dword ptr [Fibo!_imp_??6?$basic_ostreamDU?$char_traitsDstdstdQAEAAV01IZ (00a78294)]

   21 00a71481 3bfc            cmp     edi,esp

   21 00a71483 e8d1fcffff      call    Fibo!ILT+340(__RTC_CheckEsp) (00a71159)

   21 00a71488 8bc8            mov     ecx,eax

   21 00a7148a ff159c82a700    call    dword ptr [Fibo!_imp_??6?$basic_ostreamDU?$char_traitsDstdstdQAEAAV01P6AAAV01AAV01ZZ (00a7829c)]

   21 00a71490 3bf4            cmp     esi,esp

   21 00a71492 e8c2fcffff      call    Fibo!ILT+340(__RTC_CheckEsp) (00a71159)

   23 00a71497 33c0            xor     eax,eax

   24 00a71499 5f              pop     edi

   24 00a7149a 5e              pop     esi

   24 00a7149b 5b              pop     ebx

   24 00a7149c 81c4c0000000    add     esp,0C0h

   24 00a714a2 3bec            cmp     ebp,esp

   24 00a714a4 e8b0fcffff      call    Fibo!ILT+340(__RTC_CheckEsp) (00a71159)

   24 00a714a9 8be5            mov     esp,ebp

   24 00a714ab 5d              pop     ebp

   24 00a714ac c3              ret

 

 

Creates linked call lines for accessing call information and creating breakpoints:

 

0:000> uf /O @eip

Fibo!wmain [c:\development\my tools\fibo\fibo\fibo.cpp @ 20]:

   20 00a71440 55              push    ebp

   20 00a71441 8bec            mov     ebp,esp

   20 00a71443 81ecc0000000    sub     esp,0C0h

   20 00a71449 53              push    ebx

   20 00a7144a 56              push    esi

   20 00a7144b 57              push    edi

   20 00a7144c 8dbd40ffffff    lea     edi,[ebp-0C0h]

   20 00a71452 b930000000      mov     ecx,30h

   20 00a71457 b8cccccccc      mov     eax,0CCCCCCCCh

   20 00a7145c f3ab            rep stos dword ptr es:[edi]

   21 00a7145e 8bf4            mov     esi,esp

   21 00a71460 a19882a700      mov     eax,dword ptr [Fibo!_imp_?endlstdYAAAV?$basic_ostreamDU?$char_traitsDstd (00a78298)]

   21 00a71465 50              push    eax

   21 00a71466 6a00            push    0

   21 00a71468 6a05            push    5

   21 00a7146a e89bfbffff      call    Fibo!ILT+5(?FiboRecursiveYAIIHZ) (00a7100a)

   21 00a7146f 83c408          add     esp,8

   21 00a71472 8bfc            mov     edi,esp

   21 00a71474 50              push    eax

   21 00a71475 8b0d9082a700    mov     ecx,dword ptr [Fibo!_imp_?coutstd (00a78290)]

   21 00a7147b ff159482a700    call    dword ptr [Fibo!_imp_??6?$basic_ostreamDU?$char_traitsDstdstdQAEAAV01IZ (00a78294)]

   21 00a71481 3bfc            cmp     edi,esp

   21 00a71483 e8d1fcffff      call    Fibo!ILT+340(__RTC_CheckEsp) (00a71159)

   21 00a71488 8bc8            mov     ecx,eax

   21 00a7148a ff159c82a700    call    dword ptr [Fibo!_imp_??6?$basic_ostreamDU?$char_traitsDstdstdQAEAAV01P6AAAV01AAV01ZZ (00a7829c)]

   21 00a71490 3bf4            cmp     esi,esp

   21 00a71492 e8c2fcffff      call    Fibo!ILT+340(__RTC_CheckEsp) (00a71159)

   23 00a71497 33c0            xor     eax,eax

   24 00a71499 5f              pop     edi

   24 00a7149a 5e              pop     esi

   24 00a7149b 5b              pop     ebx

   24 00a7149c 81c4c0000000    add     esp,0C0h

   24 00a714a2 3bec            cmp     ebp,esp

   24 00a714a4 e8b0fcffff      call    Fibo!ILT+340(__RTC_CheckEsp) (00a71159)

   24 00a714a9 8be5            mov     esp,ebp

   24 00a714ab 5d              pop     ebp

   24 00a714ac c3              ret

 

 

Displays the number of instructions in a routine:

 

0:000> uf /i @eip

37 instructions scanned

 

Fibo!wmain [c:\development\my tools\fibo\fibo\fibo.cpp @ 20]:

   20 00a71440 55              push    ebp

   20 00a71441 8bec            mov     ebp,esp

   20 00a71443 81ecc0000000    sub     esp,0C0h

   20 00a71449 53              push    ebx

   20 00a7144a 56              push    esi

   20 00a7144b 57              push    edi

   20 00a7144c 8dbd40ffffff    lea     edi,[ebp-0C0h]

   20 00a71452 b930000000      mov     ecx,30h

   20 00a71457 b8cccccccc      mov     eax,0CCCCCCCCh

   20 00a7145c f3ab            rep stos dword ptr es:[edi]

   21 00a7145e 8bf4            mov     esi,esp

   21 00a71460 a19882a700      mov     eax,dword ptr [Fibo!_imp_?endlstdYAAAV?$basic_ostreamDU?$char_traitsDstd (00a78298)]

   21 00a71465 50              push    eax

   21 00a71466 6a00            push    0

   21 00a71468 6a05            push    5

   21 00a7146a e89bfbffff      call    Fibo!ILT+5(?FiboRecursiveYAIIHZ) (00a7100a)

   21 00a7146f 83c408          add     esp,8

   21 00a71472 8bfc            mov     edi,esp

   21 00a71474 50              push    eax

   21 00a71475 8b0d9082a700    mov     ecx,dword ptr [Fibo!_imp_?coutstd (00a78290)]

   21 00a7147b ff159482a700    call    dword ptr [Fibo!_imp_??6?$basic_ostreamDU?$char_traitsDstdstdQAEAAV01IZ (00a78294)]

   21 00a71481 3bfc            cmp     edi,esp

   21 00a71483 e8d1fcffff      call    Fibo!ILT+340(__RTC_CheckEsp) (00a71159)

   21 00a71488 8bc8            mov     ecx,eax

   21 00a7148a ff159c82a700    call    dword ptr [Fibo!_imp_??6?$basic_ostreamDU?$char_traitsDstdstdQAEAAV01P6AAAV01AAV01ZZ (00a7829c)]

   21 00a71490 3bf4            cmp     esi,esp

   21 00a71492 e8c2fcffff      call    Fibo!ILT+340(__RTC_CheckEsp) (00a71159)

   23 00a71497 33c0            xor     eax,eax

   24 00a71499 5f              pop     edi

   24 00a7149a 5e              pop     esi

   24 00a7149b 5b              pop     ebx

   24 00a7149c 81c4c0000000    add     esp,0C0h

   24 00a714a2 3bec            cmp     ebp,esp

   24 00a714a4 e8b0fcffff      call    Fibo!ILT+340(__RTC_CheckEsp) (00a71159)

   24 00a714a9 8be5            mov     esp,ebp

   24 00a714ab 5d              pop     ebp

   24 00a714ac c3              ret

 

 

 

 

Sometimes you need to look for patterns of disassembled code. You can browse the disassembled code and manually look for a specific pattern, or you can use a command to automate it.  The # command does that.

 

# [Pattern] [Address [L Size ]]

 

Parameters:

 

Pattern - Specifies the pattern to search for in the disassembly code. If you have previously used the # command and you omit Pattern, the command reuses the most recently used pattern.

Address - Specifies the address where the search begins.

Size - Specifies the number of instructions to search. If you omit Size, the search continues until the first match occurs.

 

To demonstrate this command, let’s use this simple Visual C++ application that recursively calculates the Fibonacci from a specific number:

 

#include "stdafx.h"

 

using namespace std;

 

// Recursive function.

unsigned FiboRecursive(unsigned n, int nNum = 0)

{       

          if(n <= 1)

          {

                    return n;

          }

                   

          return FiboRecursive(n - 1, 1) + FiboRecursive(n - 2, 2);

}

 

int _tmain(int argc, _TCHAR* argv[])

{

          cout << FiboRecursive(5) << endl;

 

          return 0;

}

 

Let’s break the execution when the only line from main() is being executed, using a breakpoint for that.

 

Now let’s disassemble the eip register.

 

0:000> uf @eip

Fibo!wmain [c:\development\my tools\book\fibo\fibo\fibo.cpp @ 20]:

   20 00a71440 55              push    ebp

   20 00a71441 8bec            mov     ebp,esp

   20 00a71443 81ecc0000000    sub     esp,0C0h

   20 00a71449 53              push    ebx

   20 00a7144a 56              push    esi

   20 00a7144b 57              push    edi

   20 00a7144c 8dbd40ffffff    lea     edi,[ebp-0C0h]

   20 00a71452 b930000000      mov     ecx,30h

   20 00a71457 b8cccccccc      mov     eax,0CCCCCCCCh

   20 00a7145c f3ab            rep stos dword ptr es:[edi]

   21 00a7145e 8bf4            mov     esi,esp

   21 00a71460 a19882a700      mov     eax,dword ptr [Fibo!_imp_?endlstdYAAAV?$basic_ostreamDU?$char_traitsDstd (00a78298)]

   21 00a71465 50              push    eax

   21 00a71466 6a00            push    0

   21 00a71468 6a05            push    5

   21 00a7146a e89bfbffff      call    Fibo!ILT+5(?FiboRecursiveYAIIHZ) (00a7100a)

   21 00a7146f 83c408          add     esp,8

   21 00a71472 8bfc            mov     edi,esp

   21 00a71474 50              push    eax

   21 00a71475 8b0d9082a700    mov     ecx,dword ptr [Fibo!_imp_?coutstd (00a78290)]

   21 00a7147b ff159482a700    call    dword ptr [Fibo!_imp_??6?$basic_ostreamDU?$char_traitsDstdstdQAEAAV01IZ (00a78294)]

   21 00a71481 3bfc            cmp     edi,esp

   21 00a71483 e8d1fcffff      call    Fibo!ILT+340(__RTC_CheckEsp) (00a71159)

   21 00a71488 8bc8            mov     ecx,eax

   21 00a7148a ff159c82a700    call    dword ptr [Fibo!_imp_??6?$basic_ostreamDU?$char_traitsDstdstdQAEAAV01P6AAAV01AAV01ZZ (00a7829c)]

   21 00a71490 3bf4            cmp     esi,esp

   21 00a71492 e8c2fcffff      call    Fibo!ILT+340(__RTC_CheckEsp) (00a71159)

   23 00a71497 33c0            xor     eax,eax

   24 00a71499 5f              pop     edi

   24 00a7149a 5e              pop     esi

   24 00a7149b 5b              pop     ebx

   24 00a7149c 81c4c0000000    add     esp,0C0h

   24 00a714a2 3bec            cmp     ebp,esp

   24 00a714a4 e8b0fcffff      call    Fibo!ILT+340(__RTC_CheckEsp) (00a71159)

   24 00a714a9 8be5            mov     esp,ebp

   24 00a714ab 5d              pop     ebp

   24 00a714ac c3              ret

 

Using the command below we’re going to display the first occurrence of ret.

 

0:000> # ret 00a71440

Fibo!wmain+0x6c [c:\development\my tools\book\fibo\fibo\fibo.cpp @ 24]:

00a714ac c3              ret

 

 

Looking for another pattern:

 

0:000> # call*Fibo!ILT 00a71440

Fibo!wmain+0x2a [c:\development\my tools\book\fibo\fibo\fibo.cpp @ 21]:

00a7146a e89bfbffff      call    Fibo!ILT+5(?FiboRecursiveYAIIHZ) (00a7100a)

 

Now let’s look for push instructions in a specific module/executable:

 

0:000> lm

start    end        module name

00a60000 00a7b000   Fibo     C (private pdb symbols)  C:\development\My Tools\Book\Fibo\Debug\Fibo.pdb

67350000 67473000   MSVCR90D   (deferred)            

690c0000 69197000   MSVCP90D   (private pdb symbols)  c:\publicsymbols\msvcp90d.i386.pdb\7B1C9137C0074A0E921BE874ADF944191\msvcp90d.i386.pdb

75e00000 75e44000   KERNELBASE   (deferred)            

75eb0000 75fb0000   kernel32   (deferred)            

776c0000 77840000   ntdll      (pdb symbols)          c:\publicsymbols\wntdll.pdb\E06BEA155E9748BEA818E2D0DD2FED952\wntdll.pdb

 

 

0:000> # push 00a60000

Fibo!__ImageBase+0x40:

00a60040 0e              push    cs

 

 

As you can see, when looking for patterns in disassembled code “#” is the way to go! Here is an script that automates the process.

 

Tip: Most commands mentioned in the Special Commands section of this blog have a script that uses it and could serve as another example of using the command. Also there’re scripts that use commands from the SOS.DLL extension to debug managed code.

Check out the WinDbg Scripts and PowerDbg Scripts section.

 

 

 

wt [WatchOptions] [= StartAddress] [EndAddress]

 

Transcribing the WinDbg documentation, this command runs through the whole function and then displays statistics when executed at the beginning of a function call. Thus, this command can be used just when doing live debugging, not post mortem debugging (dump analysis).

Think about Watch and Trace.

 

The WinDbg help file describes all options for WatchOptions. Usually we use the simplest form, not these options.

 

To demonstrate this command, let’s use this simple Visual C++ application that recursively calculates the Fibonacci from a specific number:

 

#include "stdafx.h"

 

using namespace std;

 

// Recursive function.

unsigned FiboRecursive(unsigned n, int nNum = 0)

{       

          if(n <= 1)

          {

                    return n;

          }

                   

          return FiboRecursive(n - 1, 1) + FiboRecursive(n - 2, 2);

}

 

int _tmain(int argc, _TCHAR* argv[])

{

          cout << FiboRecursive(5) << endl;

 

          return 0;

}

 

 

Now we run the application from WinDbg and insert a breakpoint in the beginning of _tmain().

After hitting the breakpoint, we disassemble the function:

 

0:000> uf Fibo!wmain

Fibo!wmain [c:\development\my tools\book\fibo\fibo\fibo.cpp @ 20]:

   20 001b1440 55              push    ebp

   20 001b1441 8bec            mov     ebp,esp

   20 001b1443 81ecc0000000    sub     esp,0C0h

   20 001b1449 53              push    ebx

   20 001b144a 56              push    esi

   20 001b144b 57              push    edi

   20 001b144c 8dbd40ffffff    lea     edi,[ebp-0C0h]

   20 001b1452 b930000000      mov     ecx,30h

   20 001b1457 b8cccccccc      mov     eax,0CCCCCCCCh

   20 001b145c f3ab            rep stos dword ptr es:[edi]

   21 001b145e 8bf4            mov     esi,esp

   21 001b1460 a198821b00      mov     eax,dword ptr [Fibo!_imp_?endlstdYAAAV?$basic_ostreamDU?$char_traitsDstd (001b8298)]

   21 001b1465 50              push    eax

   21 001b1466 6a00            push    0

   21 001b1468 6a05            push    5

   21 001b146a e89bfbffff      call    Fibo!ILT+5(?FiboRecursiveYAIIHZ) (001b100a)

   21 001b146f 83c408          add     esp,8

   21 001b1472 8bfc            mov     edi,esp

   21 001b1474 50              push    eax

   21 001b1475 8b0d90821b00    mov     ecx,dword ptr [Fibo!_imp_?coutstd (001b8290)]

   21 001b147b ff1594821b00    call    dword ptr [Fibo!_imp_??6?$basic_ostreamDU?$char_traitsDstdstdQAEAAV01IZ (001b8294)]

   21 001b1481 3bfc            cmp     edi,esp

   21 001b1483 e8d1fcffff      call    Fibo!ILT+340(__RTC_CheckEsp) (001b1159)

   21 001b1488 8bc8            mov     ecx,eax

   21 001b148a ff159c821b00    call    dword ptr [Fibo!_imp_??6?$basic_ostreamDU?$char_traitsDstdstdQAEAAV01P6AAAV01AAV01ZZ (001b829c)]

   21 001b1490 3bf4            cmp     esi,esp

   21 001b1492 e8c2fcffff      call    Fibo!ILT+340(__RTC_CheckEsp) (001b1159)

   23 001b1497 33c0            xor     eax,eax

   24 001b1499 5f              pop     edi

   24 001b149a 5e              pop     esi

   24 001b149b 5b              pop     ebx

   24 001b149c 81c4c0000000    add     esp,0C0h

   24 001b14a2 3bec            cmp     ebp,esp

   24 001b14a4 e8b0fcffff      call    Fibo!ILT+340(__RTC_CheckEsp) (001b1159)

   24 001b14a9 8be5            mov     esp,ebp

   24 001b14ab 5d              pop     ebp

   24 001b14ac c3              ret

 

Let’s use the address right before the recursive function call as the Start address and the address right after it as the End address of wt. Note the “=” right before the first address.

 

0:000> wt =001b1468  001b146f

    2     0 [  0] Fibo!wmain

    1     0 [  1]   Fibo!ILT+5(?FiboRecursiveYAIIHZ)

   64     0 [  1]   Fibo!FiboRecursive

    1     0 [  2]     Fibo!ILT+5(?FiboRecursiveYAIIHZ)

   64     0 [  2]     Fibo!FiboRecursive

    1     0 [  3]       Fibo!ILT+5(?FiboRecursiveYAIIHZ)

   64     0 [  3]       Fibo!FiboRecursive

    1     0 [  4]         Fibo!ILT+5(?FiboRecursiveYAIIHZ)

   64     0 [  4]         Fibo!FiboRecursive

    1     0 [  5]           Fibo!ILT+5(?FiboRecursiveYAIIHZ)

   67     0 [  5]           Fibo!FiboRecursive

    1     0 [  6]             Fibo!ILT+340(__RTC_CheckEsp)

    2     0 [  6]             Fibo!_RTC_CheckEsp

   70     3 [  5]           Fibo!FiboRecursive

   71    74 [  4]         Fibo!FiboRecursive

    1     0 [  5]           Fibo!ILT+5(?FiboRecursiveYAIIHZ)

   67     0 [  5]           Fibo!FiboRecursive

    1     0 [  6]             Fibo!ILT+340(__RTC_CheckEsp)

    2     0 [  6]             Fibo!_RTC_CheckEsp

   70     3 [  5]           Fibo!FiboRecursive

   79   148 [  4]         Fibo!FiboRecursive

    1     0 [  5]           Fibo!ILT+340(__RTC_CheckEsp)

    2     0 [  5]           Fibo!_RTC_CheckEsp

   82   151 [  4]         Fibo!FiboRecursive

   71   234 [  3]       Fibo!FiboRecursive

    1     0 [  4]         Fibo!ILT+5(?FiboRecursiveYAIIHZ)

   67     0 [  4]         Fibo!FiboRecursive

    1     0 [  5]           Fibo!ILT+340(__RTC_CheckEsp)

    2     0 [  5]           Fibo!_RTC_CheckEsp

   70     3 [  4]         Fibo!FiboRecursive

   79   308 [  3]       Fibo!FiboRecursive

    1     0 [  4]         Fibo!ILT+340(__RTC_CheckEsp)

    2     0 [  4]         Fibo!_RTC_CheckEsp

   82   311 [  3]       Fibo!FiboRecursive

   71   394 [  2]     Fibo!FiboRecursive

    1     0 [  3]       Fibo!ILT+5(?FiboRecursiveYAIIHZ)

   64     0 [  3]       Fibo!FiboRecursive

    1     0 [  4]         Fibo!ILT+5(?FiboRecursiveYAIIHZ)

   67     0 [  4]         Fibo!FiboRecursive

    1     0 [  5]           Fibo!ILT+340(__RTC_CheckEsp)

    2     0 [  5]           Fibo!_RTC_CheckEsp

   70     3 [  4]         Fibo!FiboRecursive

   71    74 [  3]       Fibo!FiboRecursive

    1     0 [  4]         Fibo!ILT+5(?FiboRecursiveYAIIHZ)

   67     0 [  4]         Fibo!FiboRecursive

    1     0 [  5]           Fibo!ILT+340(__RTC_CheckEsp)

    2     0 [  5]           Fibo!_RTC_CheckEsp

   70     3 [  4]         Fibo!FiboRecursive

   79   148 [  3]       Fibo!FiboRecursive

    1     0 [  4]         Fibo!ILT+340(__RTC_CheckEsp)

    2     0 [  4]         Fibo!_RTC_CheckEsp

   82   151 [  3]       Fibo!FiboRecursive

   79   628 [  2]     Fibo!FiboRecursive

    1     0 [  3]       Fibo!ILT+340(__RTC_CheckEsp)

    2     0 [  3]       Fibo!_RTC_CheckEsp

   82   631 [  2]     Fibo!FiboRecursive

   71   714 [  1]   Fibo!FiboRecursive

    1     0 [  2]     Fibo!ILT+5(?FiboRecursiveYAIIHZ)

   64     0 [  2]     Fibo!FiboRecursive

    1     0 [  3]       Fibo!ILT+5(?FiboRecursiveYAIIHZ)

   64     0 [  3]       Fibo!FiboRecursive

    1     0 [  4]         Fibo!ILT+5(?FiboRecursiveYAIIHZ)

   67     0 [  4]         Fibo!FiboRecursive

    1     0 [  5]           Fibo!ILT+340(__RTC_CheckEsp)

    2     0 [  5]           Fibo!_RTC_CheckEsp

   70     3 [  4]         Fibo!FiboRecursive

   71    74 [  3]       Fibo!FiboRecursive

    1     0 [  4]         Fibo!ILT+5(?FiboRecursiveYAIIHZ)

   67     0 [  4]         Fibo!FiboRecursive

    1     0 [  5]           Fibo!ILT+340(__RTC_CheckEsp)

    2     0 [  5]           Fibo!_RTC_CheckEsp

   70     3 [  4]         Fibo!FiboRecursive

   79   148 [  3]       Fibo!FiboRecursive

    1     0 [  4]         Fibo!ILT+340(__RTC_CheckEsp)

    2     0 [  4]         Fibo!_RTC_CheckEsp

   82   151 [  3]       Fibo!FiboRecursive

   71   234 [  2]     Fibo!FiboRecursive

    1     0 [  3]       Fibo!ILT+5(?FiboRecursiveYAIIHZ)

   67     0 [  3]       Fibo!FiboRecursive

    1     0 [  4]         Fibo!ILT+340(__RTC_CheckEsp)

    2     0 [  4]         Fibo!_RTC_CheckEsp

   70     3 [  3]       Fibo!FiboRecursive

   79   308 [  2]     Fibo!FiboRecursive

    1     0 [  3]       Fibo!ILT+340(__RTC_CheckEsp)

    2     0 [  3]       Fibo!_RTC_CheckEsp

   82   311 [  2]     Fibo!FiboRecursive

   79  1108 [  1]   Fibo!FiboRecursive

    1     0 [  2]     Fibo!ILT+340(__RTC_CheckEsp)

    2     0 [  2]     Fibo!_RTC_CheckEsp

   82  1111 [  1]   Fibo!FiboRecursive

 

1196 instructions were executed in 1195 events (0 from other threads)

 

Function Name                               Invocations MinInst MaxInst AvgInst

Fibo!FiboRecursive                                   15      70      82      75

Fibo!ILT+340(__RTC_CheckEsp)               15        1        1       1

Fibo!ILT+5(?FiboRecursiveYAIIHZ)            15        1        1       1

Fibo!_RTC_CheckEsp                                15        2       2       2

Fibo!wmain                                               1        2        2       2

 

0 system calls were executed

 

eax=00000005 ebx=7efde000 ecx=00000000 edx=00000001 esi=00000000 edi=00000000

eip=001b146f esp=0045f914 ebp=0045f964 iopl=0         nv up ei pl zr na pe nc

cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000246

Fibo!wmain+0x2f:

001b146f 83c408          add     esp,8

 

 

 

Notice that the first number right below the command specifies the number of instructions that were executed, the second number specifies the number of instructions executed by child calls of the function, and the third number (in brackets) is the depth of the function in the stack.

MinInst, MaxInst and AvgInst mean the number of instructions by call.

 

This command enables you to save memory into a disk file. The cool thing about it is that you can save modules too; however, it is just the raw memory.

The parameters are:

 

.writemem <filename> <range>

 

Here is an example:

 

0:026> lm

start    end        module name

00400000 00427000   mtgdi      (deferred)            

5a700000 5acaf000   mfc90d     (deferred)            

63df0000 63f13000   MSVCR90D   (deferred)            

71270000 71283000   dwmapi     (deferred)            

72cf0000 72d70000   UxTheme    (deferred)            

73470000 73475000   MSIMG32    (deferred)            

73b90000 73b9d000   MFC90ENU   (deferred)            

74fd0000 75053000   COMCTL32   (deferred)            

751d0000 751dc000   CRYPTBASE   (deferred)            

751e0000 75240000   SspiCli    (deferred)            

75240000 75259000   sechost    (deferred)            

75260000 75ea6000   SHELL32    (deferred)            

75ee0000 75f8c000   msvcrt     (deferred)            

75fd0000 76060000   GDI32      (deferred)            

76150000 76250000   kernel32   (deferred)            

76250000 762ed000   USP10      (deferred)            

763b0000 76410000   IMM32      (deferred)            

76410000 7649f000   OLEAUT32   (deferred)            

764a0000 764e4000   KERNELBASE   (deferred)            

765c0000 766b0000   RPCRT4     (deferred)            

766b0000 76733000   CLBCatQ    (deferred)            

76a00000 76aa0000   ADVAPI32   (deferred)            

76ce0000 76d37000   SHLWAPI    (deferred)            

76f40000 77040000   USER32     (deferred)            

77040000 7710c000   MSCTF      (deferred)            

77110000 7726b000   ole32      (deferred)            

77640000 7764a000   LPK        (deferred)            

 

Now let’s save the MFC90ENU.DLL above.

 

0:026> .writemem c:\downloads\MFC90ENU.dll 73b90000 (73b9d000 - 0x1)

Writing d000 bytes..........................

 

Note the “- 0x1” above. If you don’t do that, the command will fail because the debugger will try to write from the base address to and including the end address.

 

Another approach you can use is to get the size of the module and use it as one of the parameters:

 

0:026> ? 73b9d000 - 73b90000

 

Evaluate expression: 53248 = 0000d000

 

0:026> .writemem c:\downloads\MFC90ENU.dll 73b90000 L 0000d000

Writing d000 bytes..........................

 

 

 

Using WinDbg you can create a dump file from an application running, for instance, in a production server. After collecting the dump file, you can load it in another machine and debug it. However, to be more effective during your debugging session you need symbols. Thus, thinking about it, here's the trick to get both dump and symbols.

 

First, to get a dump file with all information use it:

 

0:000> .dump /mfht c:\Test.dmp

Creating c:\Test.dmp - mini user dump

Dump successfully written

 

.dump has several arguments, but if you want a mini-dump with all information you just need to use:

/mfht

Where:

/m – This is to use options.

f – Adds full memory data to the minidump. All accessible committed pages owned by the target application will be included.

h – Adds data about the handles associated with the target application to the minidump.

t – Adds additional thread information to the minidump. This includes thread times, which can be displayed by using the !runaway extension or the .ttime command when debugging the minidump. (now you understand why your !runaway command failed that day, huh? :) )

 

Note: For more arguments check the WinDbg help file.

 

After collecting the dump file, open it from the production server using WinDbg and reload the symbols again.

Go to the command line and use the .dumpcab command.

The arguments for .dumpcab are –a (force all symbols) and the file name itself.

Here is how to do that:

 

0:003> .dumpcab -a c:\fulldump

Creating a cab file can take a VERY VERY long time

.Ctrl-C can only interrupt the command after a file has been added to the cab.

  Adding C:\test.dmp - added

  Adding c:\publicsymbols\wntdll.pdb\E06BEA155E9748BEA818E2D0DD2FED952\wntdll.pdb - added

Wrote c:\downloads\fulldump

 

After doing that the file FullDump.CAB will have the dump file and all related symbols, so you can transport it to your machine, unpack, load the dumps/symbols, and start debugging it!

These are two debugger extensions that are used to see the PDB file that matches a specific module.

Note that !itoldyouso is not documented. The output of both commands is identical.

 

Usage:

 

0:025> !chksym ntdll

 

ntdll.dll

    Timestamp: 49EEA706

  SizeOfImage: 180000

          pdb: wntdll.pdb

      pdb sig: E06BEA15-5E97-48BE-A818-E2D0DD2FED95

          age: 2

 

Loaded pdb is c:\publicsymbols\wntdll.pdb\E06BEA155E9748BEA818E2D0DD2FED952\wntdll.pdb

 

wntdll.pdb

      pdb sig: E06BEA15-5E97-48BE-A818-E2D0DD2FED95

          age: 2

 

MATCH: wntdll.pdb and ntdll.dll

 

0:025> !itoldyouso ntdll

 

ntdll.dll

    Timestamp: 49EEA706

  SizeOfImage: 180000

          pdb: wntdll.pdb

      pdb sig: E06BEA15-5E97-48BE-A818-E2D0DD2FED95

          age: 2

 

Loaded pdb is c:\publicsymbols\wntdll.pdb\E06BEA155E9748BEA818E2D0DD2FED952\wntdll.pdb

 

wntdll.pdb

      pdb sig: E06BEA15-5E97-48BE-A818-E2D0DD2FED95

          age: 2

 

MATCH: wntdll.pdb and ntdll.dll

 

0:025> !chksym mtgdi

 

mtgdi.exe

    Timestamp: 48785A80

  SizeOfImage: 27000

          pdb: c:\DOWNLOADS\mtgdi\Debug\mtgdi.pdb

      pdb sig: EC1B3DB2-25C1-4337-8676-DFB3C5B1C8C9

          age: 3

 

Loaded pdb is C:\development\My Tools\Book\mtgdi\Debug\mtgdi.pdb

 

mtgdi.pdb

      pdb sig: EC1B3DB2-25C1-4337-8676-DFB3C5B1C8C9

          age: 3

 

MATCH: mtgdi.pdb and mtgdi.exe

 

0:025> !itoldyouso mtgdi

 

mtgdi.exe

    Timestamp: 48785A80

  SizeOfImage: 27000

          pdb: c:\DOWNLOADS\mtgdi\Debug\mtgdi.pdb

      pdb sig: EC1B3DB2-25C1-4337-8676-DFB3C5B1C8C9

          age: 3

 

Loaded pdb is C:\development\My Tools\Book\mtgdi\Debug\mtgdi.pdb

 

mtgdi.pdb

      pdb sig: EC1B3DB2-25C1-4337-8676-DFB3C5B1C8C9

          age: 3

 

MATCH: mtgdi.pdb and mtgdi.exe

 

!dlls extension displays the table entries of all loaded modules. You can also use it to display all modules that a specified thread or process is using.

The WinDbg help file describes all parameters. Here we are going to show the most common usage.

 

Displays file headers and section headers:

 

!dlls –a

 

0:801> !dlls –a

 

0x00543598: C:\development\My Tools\Book\mtgdi\Debug\MtGdi.exe

      Base   0x00400000  EntryPoint  0x00411929  Size        0x00027000

      Flags  0x00004000  LoadCount   0x0000ffff  TlsIndex    0x00000000

             LDRP_ENTRY_PROCESSED

File Type: EXECUTABLE IMAGE

FILE HEADER VALUES

     14C machine (i386)

       6 number of sections

48785A80 time date stamp Sat Jul 12 00:17:20 2008

       0 file pointer to symbol table

       0 number of symbols

      E0 size of optional header

     103 characteristics

            Relocations stripped

            Executable

            32 bit word machine

OPTIONAL HEADER VALUES

     10B magic #

    9.00 linker version

    C400 size of code

    7C00 size of initialized data

       0 size of uninitialized data

   11929 address of entry point

    1000 base of code

    1000 base of data

         ----- new -----

00400000 image base

    1000 section alignment

     200 file alignment

       2 subsystem (Windows GUI)

    5.00 operating system version

    0.00 image version

    5.00 subsystem version

   27000 size of image

     400 size of headers

       0 checksum

00100000 size of stack reserve

00001000 size of stack commit

00100000 size of heap reserve

00001000 size of heap commit

00400100 Opt Hdr

       0 [       0] address [size] of Export Directory

   23000 [      8C] address [size] of Import Directory

   25000 [    1E7C] address [size] of Resource Directory

       0 [       0] address [size] of Exception Directory

       0 [       0] address [size] of Security Directory

       0 [     101] address [size] of Base Relocation Directory

   1E940 [      1C] address [size] of Debug Directory

       0 [       0] address [size] of Description Directory

       0 [       0] address [size] of Special Directory

       0 [       0] address [size] of Thread Storage Directory

       0 [       0] address [size] of Load Configuration Directory

       0 [       0] address [size] of Bound Import Directory

   23884 [     7F8] address [size] of Import Address Table Directory

       0 [       0] address [size] of Reserved Directory

       0 [       0] address [size] of Reserved Directory

       0 [       0] address [size] of Reserved Directory

SECTION HEADER #1

         name

       0 virtual size

       0 virtual address

       0 size of raw data

       0 file pointer to raw data

       0 file pointer to relocation table

       0 file pointer to line numbers

       0 number of relocations

       0 number of line numbers

       0 flags

         (no align specified)

SECTION HEADER #2

         name

       0 virtual size

       0 virtual address

       0 size of raw data

       0 file pointer to raw data

       0 file pointer to relocation table

       0 file pointer to line numbers

       0 number of relocations

       0 number of line numbers

       0 flags

         (no align specified)

SECTION HEADER #3

         name

       0 virtual size

       0 virtual address

       0 size of raw data

       0 file pointer to raw data

       0 file pointer to relocation table

       0 file pointer to line numbers

       0 number of relocations

       0 number of line numbers

       0 flags

         (no align specified)

SECTION HEADER #4

         name

       0 virtual size

       0 virtual address

       0 size of raw data

       0 file pointer to raw data

       0 file pointer to relocation table

       0 file pointer to line numbers

       0 number of relocations

       0 number of line numbers

       0 flags

         (no align specified)

SECTION HEADER #5

         name

       0 virtual size

       0 virtual address

       0 size of raw data

       0 file pointer to raw data

       0 file pointer to relocation table

       0 file pointer to line numbers

       0 number of relocations

       0 number of line numbers

       0 flags

         (no align specified)

SECTION HEADER #6

         name

       0 virtual size

       0 virtual address

       0 size of raw data

       0 file pointer to raw data

       0 file pointer to relocation table

       0 file pointer to line numbers

       0 number of relocations

       0 number of line numbers

       0 flags

         (no align specified)

 

 

Displays version numbers:

 

!dlls –v

 

0:801> !dlls -v

 

0x00543598: C:\development\My Tools\Book\mtgdi\Debug\MtGdi.exe

      Base   0x00400000  EntryPoint  0x00411929  Size        0x00027000

      Flags  0x00004000  LoadCount   0x0000ffff  TlsIndex    0x00000000

             LDRP_ENTRY_PROCESSED

      Product Name       MTGDI Application

      Product Version    1, 0, 0, 1

      Original Filename  MTGDI.EXE

      File Description   MTGDI MFC Application

      File Version       1, 0, 0, 1

0x00543628: C:\Windows\SysWOW64\ntdll.dll

      Base   0x77630000  EntryPoint  0x00000000  Size        0x00180000

      Flags  0x80004004  LoadCount   0x0000ffff  TlsIndex    0x00000000

             LDRP_IMAGE_DLL

             LDRP_ENTRY_PROCESSED

      Company Name       Microsoft Corporation

      Product Name       Microsoft® Windows® Operating System

      Product Version    6.1.7100.0

      Original Filename  ntdll.dll

      File Description   NT Layer DLL

      File Version       6.1.7100.0 (winmain_win7rc.090421-1700)

0x005439a8: C:\Windows\syswow64\kernel32.dll

      Base   0x769d0000  EntryPoint  0x769e3e8a  Size        0x00100000

      Flags  0x80084004  LoadCount   0x0000ffff  TlsIndex    0x00000000

             LDRP_IMAGE_DLL

             LDRP_ENTRY_PROCESSED

             LDRP_PROCESS_ATTACH_CALLED

      Company Name       Microsoft Corporation

      Product Name       Microsoft® Windows® Operating System

      Product Version    6.1.7100.0

      Original Filename  kernel32

      File Description   Windows NT BASE API Client DLL

      File Version       6.1.7100.0 (winmain_win7rc.090421-1700)

0x00543ac0: C:\Windows\syswow64\KERNELBASE.dll

      Base   0x76ad0000  EntryPoint  0x76ad563f  Size        0x00044000

      Flags  0x80084004  LoadCount   0x0000ffff  TlsIndex    0x00000000

             LDRP_IMAGE_DLL

             LDRP_ENTRY_PROCESSED

             LDRP_PROCESS_ATTACH_CALLED

      Company Name       Microsoft Corporation

      Product Name       Microsoft® Windows® Operating System

      Product Version    6.1.7100.0

      Original Filename  Kernelbase

      File Description   Windows NT BASE API Client DLL

      File Version       6.1.7100.0 (winmain_win7rc.090421-1700)

 

 

Using Module Address to display information from a specific dll:

 

!dlls –c <moduleAddress>

 

0:801> !dlls -c 63390000

 

Dump dll containing 0x63390000:

0x00544998: C:\Windows\WinSxS\x86_microsoft.vc90.debugcrt_1fc8b3b9a1e18e3b_9.0.30729.1_none_bb1f6aa1308c35eb\MSVCR90D.dll

      Base   0x63390000  EntryPoint  0x633cc6f0  Size        0x00123000

      Flags  0x90084004  LoadCount   0x0000ffff  TlsIndex    0x00000000

             LDRP_IMAGE_DLL

             LDRP_ENTRY_PROCESSED

             LDRP_PROCESS_ATTACH_CALLED

             LDRP_REDIRECTED

 

 

 

!for_each_frame is a favorite among debuggers. It's a very flexible and powerful command that enables you to run commands for each frame of the call stack.

You can use basically any command. 

For instance, let’s say you want to see all local variables from each frame of a specific stack. Of course, to see local variables you must have private symbols.

 

0:025> !for_each_frame dv /i /t /V

_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

00 0532fcd0 776f8edc ntdll!NtWaitForSingleObject+0x15

Unable to enumerate locals, HRESULT 0x80004005

Private symbols (symbols.pri) are required for locals.

Type ".hh dbgerr005" for details.

_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

01 0532fd34 776f8dc0 ntdll!RtlpWaitOnCriticalSection+0x13e

Unable to enumerate locals, HRESULT 0x80004005

Private symbols (symbols.pri) are required for locals.

Type ".hh dbgerr005" for details.

_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

02 0532fd5c 00414ee7 ntdll!RtlEnterCriticalSection+0x150

Unable to enumerate locals, HRESULT 0x80004005

Private symbols (symbols.pri) are required for locals.

Type ".hh dbgerr005" for details.

_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

03 0532fdc8 00414834 mtgdi!CBallThread::SingleStep+0x147 [c:\downloads\mtgdi\threads.cpp @ 180]

prv local  0532fdc4 @ebp-0x04 class CBallThread * this = 0x043349f0

_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

04 0532fe20 00414d8c mtgdi!CGDIThread::InitInstance+0x44 [c:\downloads\mtgdi\threads.cpp @ 65]

prv local  0532fe1c @ebp-0x04 class CGDIThread * this = 0x043349f0

_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

05 0532fe78 5a67d3e3 mtgdi!CBallThread::InitInstance+0x2c [c:\downloads\mtgdi\threads.cpp @ 156]

prv local  0532fe74 @ebp-0x04 class CBallThread * this = 0x043349f0

_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

06 0532ff40 6d97dfd3 mfc90d!_AfxThreadEntry+0x303

Unable to enumerate locals, HRESULT 0x80004005

Private symbols (symbols.pri) are required for locals.

Type ".hh dbgerr005" for details.

_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

07 0532ff7c 6d97df69 MSVCR90D!_callthreadstartex+0x53

Unable to enumerate locals, HRESULT 0x80004005

Private symbols (symbols.pri) are required for locals.

Type ".hh dbgerr005" for details.

_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

08 0532ff88 75ec3f39 MSVCR90D!_threadstartex+0x89

Unable to enumerate locals, HRESULT 0x80004005

Private symbols (symbols.pri) are required for locals.

Type ".hh dbgerr005" for details.

_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

09 0532ff94 77710409 kernel32!BaseThreadInitThunk+0xe

Unable to enumerate locals, HRESULT 0x80004005

Private symbols (symbols.pri) are required for locals.

Type ".hh dbgerr005" for details.

_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

0a 0532ffd4 777103dc ntdll!__RtlUserThreadStart+0x70

Unable to enumerate locals, HRESULT 0x80004005

Private symbols (symbols.pri) are required for locals.

Type ".hh dbgerr005" for details.

_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

0b 0532ffec 00000000 ntdll!_RtlUserThreadStart+0x1b

Unable to enumerate locals, HRESULT 0x80004005

Private symbols (symbols.pri) are required for locals.

Type ".hh dbgerr005" for details.

_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

00 0532fcd0 776f8edc ntdll!NtWaitForSingleObject+0x15

The !dh extension displays the PE header information from a specified module.

 

Usage:

 

!dh [options] <addressOfModule>

 

Options can be:

 

-f Displays file headers.

-s Displays section headers.

-a Displays all header information.

 

Example:

 

0:532> lm

 

start    end        module name

00400000 00427000   mtgdi      (deferred)            

5a700000 5acaf000   mfc90d     (deferred)            

692e0000 69403000   MSVCR90D   (deferred)            

71270000 71283000   dwmapi     (deferred)             

72cf0000 72d70000   UxTheme    (deferred)            

73470000 73475000   MSIMG32    (deferred)            

73b50000 73b5d000   MFC90ENU   (deferred)            

74fd0000 75053000   COMCTL32   (deferred)            

751d0000 751dc000   CRYPTBASE   (deferred)            

751e0000 75240000   SspiCli    (deferred)            

75240000 75259000   sechost    (deferred)            

75260000 75ea6000   SHELL32    (deferred)            

75ee0000 75f8c000   msvcrt     (deferred)            

75fd0000 76060000   GDI32      (deferred)            

76150000 76250000   kernel32   (deferred)            

76250000 762ed000   USP10      (deferred)            

763b0000 76410000   IMM32      (deferred)            

76410000 7649f000   OLEAUT32   (deferred)             

764a0000 764e4000   KERNELBASE   (deferred)            

765c0000 766b0000   RPCRT4     (deferred)            

766b0000 76733000   CLBCatQ    (deferred)            

76a00000 76aa0000   ADVAPI32   (deferred)            

76ce0000 76d37000   SHLWAPI    (deferred)            

76f40000 77040000   USER32     (deferred)            

77040000 7710c000   MSCTF      (deferred)            

77110000 7726b000   ole32      (deferred)            

77640000 7764a000   LPK        (deferred) 

 

Now we use the start address as argument:

 

0:532> !dh -a 5a700000

 

File Type: DLL

FILE HEADER VALUES

     14C machine (i386)

       4 number of sections

488F15C6 time date stamp Tue Jul 29 06:06:14 2008

       0 file pointer to symbol table

       0 number of symbols

      E0 size of optional header

    2102 characteristics

            Executable

            32 bit word machine

            DLL

OPTIONAL HEADER VALUES

     10B magic #

    9.00 linker version

  45B600 size of code

  151A00 size of initialized data

       0 size of uninitialized data

  3F66C0 address of entry point

    1000 base of code

         ----- new -----

5a700000 image base

    1000 section alignment

     200 file alignment

       3 subsystem (Windows CUI)

    5.00 operating system version

    9.00 image version

    5.00 subsystem version

  5AF000 size of image

     400 size of headers

  5B030B checksum

00100000 size of stack reserve

00001000 size of stack commit

00100000 size of heap reserve

00001000 size of heap commit

     140  DLL characteristics

            Dynamic base

            NX compatible

  44D0A0 [    F4A5] address [size] of Export Directory

  448DB8 [      A0] address [size] of Import Directory

  46B000 [  106C18] address [size] of Resource Directory

       0 [       0] address [size] of Exception Directory

  5A7400 [    23F8] address [size] of Security Directory

  572000 [   38D08] address [size] of Base Relocation Directory

    21D0 [      1C] address [size] of Debug Directory

       0 [       0] address [size] of Description Directory

       0 [       0] address [size] of Special Directory

       0 [       0] address [size] of Thread Storage Directory

   59310 [      40] address [size] of Load Configuration Directory

       0 [       0] address [size] of Bound Import Directory

    1000 [     CEC] address [size] of Import Address Table Directory

  4471A4 [     200] address [size] of Delay Import Directory

       0 [       0] address [size] of COR20 Header Directory

       0 [       0] address [size] of Reserved Directory

SECTION HEADER #1

   .text name

  45B545 virtual size

    1000 virtual address

  45B600 size of raw data

     400 file pointer to raw data

       0 file pointer to relocation table

       0 file pointer to line numbers

       0 number of relocations

       0 number of line numbers

60000020 flags

         Code

         (no align specified)

         Execute Read

Debug Directories(1)

          Type       Size     Address  Pointer

          cv           28       59358    58758    Format: RSDS, guid, 17, mfc90d.i386.pdb

SECTION HEADER #2

   .data name

    DC3C virtual size

  45D000 virtual address

    7E00 size of raw data

  45BA00 file pointer to raw data

       0 file pointer to relocation table

       0 file pointer to line numbers

       0 number of relocations

       0 number of line numbers

C0000040 flags

         Initialized Data

         (no align specified)

         Read Write

SECTION HEADER #3

   .rsrc name

  106C18 virtual size

  46B000 virtual address

  106E00 size of raw data

  463800 file pointer to raw data

       0 file pointer to relocation table

       0 file pointer to line numbers

       0 number of relocations

       0 number of line numbers

40000040 flags

         Initialized Data

         (no align specified)

         Read Only

SECTION HEADER #4

  .reloc name

   3CCD4 virtual size

  572000 virtual address

   3CE00 size of raw data

  56A600 file pointer to raw data

       0 file pointer to relocation table

       0 file pointer to line numbers

       0 number of relocations

       0 number of line numbers

42000040 flags

         Initialized Data

         Discardable

         (no align specified)

         Read Only

Like its cousin !dh, the !lmi extension displays the PE header information from a specified module. However, it gives you fewer details than !dh. The output is summarized.

 

Usage:

 

!lmi <moduleName>

 

Examples:

 

0:532> !lmi mtgdi

 

Loaded Module Info: [mtgdi]

         Module: mtgdi

   Base Address: 00400000

     Image Name: mtgdi.exe

   Machine Type: 332 (I386)

     Time Stamp: 48785a80 Sat Jul 12 00:17:20 2008

           Size: 27000

       CheckSum: 0

Characteristics: 103 

Debug Data Dirs: Type  Size     VA  Pointer

             CODEVIEW    3b, 200dc,    e8dc RSDS - GUID: {EC1B3DB2-25C1-4337-8676-DFB3C5B1C8C9}

               Age: 3, Pdb: c:\DOWNLOADS\mtgdi\Debug\mtgdi.pdb

     Image Type: FILE     - Image read successfully from debugger.

                 C:\development\My Tools\Book\mtgdi\Debug\MtGdi.exe

    Symbol Type: PDB      - Symbols loaded successfully from image path.

                 C:\development\My Tools\Book\mtgdi\Debug\mtgdi.pdb

       Compiler: Resource - front end [0.0 bld 0] - back end [9.0 bld 21022]

    Load Report: private symbols & lines, not source indexed

                 C:\development\My Tools\Book\mtgdi\Debug\mtgdi.pdb

 

0:532> !lmi ole32

 

Loaded Module Info: [ole32]

         Module: ole32

   Base Address: 77110000

     Image Name: C:\Windows\syswow64\ole32.dll

   Machine Type: 332 (I386)

     Time Stamp: 49eea66c Tue Apr 21 22:09:00 2009

           Size: 15b000

       CheckSum: 1607b7

Characteristics: 2102  perf

Debug Data Dirs: Type  Size     VA  Pointer

             CODEVIEW    22, 138b1c,  13831c RSDS - GUID: {D66D525C-3DF2-47C7-AB77-594C4E5E2325}

               Age: 2, Pdb: ole32.pdb

                CLSID     4, 138b18,  138318 [Data not mapped]

     Image Type: FILE     - Image read successfully from debugger.

                 C:\Windows\syswow64\ole32.dll

    Symbol Type: PDB      - Symbols loaded successfully from symbol server.

                 c:\publicsymbols\ole32.pdb\D66D525C3DF247C7AB77594C4E5E23252\ole32.pdb

    Load Report: public symbols , not source indexed

                 c:\publicsymbols\ole32.pdb\D66D525C3DF247C7AB77594C4E5E23252\ole32.pdb

 

 

Note the Base Address above. You can get the base address from a module using different commands like lm or even dd.

dd is supposed to Display DWORDs but it solves module names.

 

Look:

 

0:532> dd ole32 L1

77110000  00905a4d

 

0:532> dd mtgdi L1

00400000  00905a4d

 

 

This is one of my favorite commands! !runaway displays information about the CPU time consumed by each thread in User Mode and  Kernel Mode.

It is one of those commands you run when you think the application is hung with low or high CPU or has some kind of performance issue.

 

Parameters:

Bit 0 (0x1)

Causes the debugger to show the amount of user time consumed by each thread.

Bit 1 (0x2)

Causes the debugger to show the amount of kernel time consumed by each thread.

Bit 2 (0x4)

Causes the debugger to show the amount of time that has elapsed since each thread was created.

 

The output is sorted from the thread consuming the most CPU time to the thread consuming the least CPU time.

Example of displaying just the User Time for each thread (no parameters does that):

0:000> !runaway

 User Mode Time

  Thread       Time

  52:33b4      0 days 0:00:01.435

 317:2834      0 days 0:00:00.982

  93:2d60      0 days 0:00:00.936

 479:3858      0 days 0:00:00.842

 266:33b0      0 days 0:00:00.842

 658:23d8      0 days 0:00:00.826

 559:1acc      0 days 0:00:00.826

 299:357c      0 days 0:00:00.826

 279:bf8       0 days 0:00:00.826

 719:39c0      0 days 0:00:00.811

 509:38d0      0 days 0:00:00.811

 376:19a0      0 days 0:00:00.811

 314:3700      0 days 0:00:00.811

  84:338c      0 days 0:00:00.811

 731:2fa0      0 days 0:00:00.795

 691:2070      0 days 0:00:00.795

  24:1b88      0 days 0:00:00.795

 800:3ca4      0 days 0:00:00.780

 761:3c08      0 days 0:00:00.780

 720:3968      0 days 0:00:00.780

. . .

. . .

. . .

For the second time I have had the privilege of being one of the reviewers for another debugging book. This time I’m referring to Mario Hewardt’s new book: Advanced .NET Debugging.

It was a great learning process. After months of reviewing chapters and source code and giving suggestions, I feel my .NET debugging knowledge is not the same. It is much better now!

Let me tell you why I’m so thrilled with this book.

 

First of all, this book discusses in depth several tools used by our product teams when isolating internal bugs from .NET application and also the tools used by CSS (Customer Service and Support). In case you ask, they are all public tools!

 

Also the book gives a deep and clear explanation about the CLR (Common Language Runtime). In my opinion, that is one of the most important parts of the book. If you are starting with .NET Debugging, you may be familiar with some of the SOS commands. That’s the easy part. However, if you want to improve your skills as a debugger you must go deeper and understand the CLR internals, like method table, method descriptor, memory management, etc.  The chapter about CLR explains the internals in a superb way, and it’s my favorite!

 

If you’re new to debugging, you’re going to like the chapter about Basic Debugging Tasks. It’s didactic enough for beginners, demonstrating how to use the most used commands and how to get useful information from basic commands.

 

Another part of the book talks about more complex scenarios and technologies. It’s a deep explanation! You’re going to learn a lot about Managed Heap, Garbage Collection, Thread Synchronization and Interoperability. Based on my experiences helping customers from different countries, I can tell you the number one application problem from .NET applications: memory issues. I know it’s ironic since GC is supposed to manage memory, so let me explain: GC does the job very well. The problem is mixed code: managed and native. The GC only has control of the managed code. The book explains it very well, and there are lots of sample codes reproducing different issues scattered among the chapters. This is cool because you can use the sample code to apply the knowledge while debugging specific scenarios.

 

Like Mario’s previous book, this one is also very pragmatic. You won’t see those situations that are unlikely to happen on a production server, actually the opposite: you’ll see issues that we face on a daily basis with the approaches, techniques and tools we use when debugging these issues. Very helpful!

 

"Fortunately, Mario's book combines just the right amount of explanation of the runtime to help you understand the thought process and the techniques he uses to solve problems with many practical and clever tricks learned from debugging real world applications. So if you want to quickly get up to speed debugging your CLR applications, this is definitely the book to read. It covers many aspects of debugging managed applications—in particular, it gives insights into areas that are hard to diagnose such as thread synchronization problems. The illustration of debugging techniques is largely done with examples which makes it easier to follow." (Excerpted from the Foreword by Patrick Dussud, Technical Fellow, CLR, .NET FX, Microsoft Corporation.)

 

 

Here is the index of the book:

 

 

Part I – Overview

Part I introduces the reader to the basic concepts required to efficiently debug .NET applications using the Debugging Tools for Windows package.

 

1.    Introduction to the Tools

This chapter contains a brief introduction to the tools used throughout the book, including basic usage scenarios, download locations, and installation instructions. Amongst the tools covered are:

 

          Debugging Tools for Windows

          .NET 2.0 redist/SDK

          SOS

          SOSEX

          CLR Profiler

          Performance Counters

          Reflector for .NET

          PowerDBG

          Managed Debugging Assistants

         

2.    CLR Fundamentals

This chapter discusses the core fundamentals of the CLR. The chapter begins with a high level overview of the major runtime components and subsequently drills down into the details and covers topics such as:

 

·         CLR and the Windows Loader. Discusses how .NET applications are natively supported using the PE file format.

·         Application domains (system, shared, default, custom) as well as loader heaps etc.

·         Assembly overview

·         Assembly manifest

·         Type metadata

·         And more…

 

 

3.    Basic Debugging Tasks

Chapter 3 gives hands on examples of the basic .NET debugging tasks such as:

 

·         Thread management

·         Display stack traces

·         Display local variables

·         Breakpoint management

·         Dumping heap based objects

·         .NET exception model and how to analyze in the debuggers

·         Basics of postmortem debugging

·         Remote debugging        

                  

Part II – Applied Debugging

Par t II is a practical approach to debugging common .NET problems encountered in the development process. Each chapter is dedicated to a specific CLR component and/or technology and begins by detailing the inner workings of that component. Subsequently, a number of common problems related to the specific technologies are discussed and how the debuggers and tools can be used for root cause analysis.

 

4.    Assembly Loader

The complexity of .NET applications can range from simple command line applications to complex multi-process/multi machine server applications with a large number of assemblies living in harmony. In order to efficiently debug problems in .NET applications one much be careful to understand the dependencies of .NET assemblies. This chapter takes a look at how the CLR assembly loader does its work and common problems surrounding that area. 

 

5.    Managed Heap and Garbage Collection

While .NET developers can enjoy the luxury of automatic memory management, care must still be taken to avoid costly mistakes. The highly sophisticated CLR garbage collector is an automatic memory manager that allows developers to focus less on memory management and more on application logic. Even though the CLR manages memory for the developer, care must be taken to avoid pitfalls that can wreak havoc in your applications. In this chapter we look at how the garbage collector works, how to peek into the internals of the garbage collector and some common programming mistakes related to automatic garbage collection (non memory resources, memory fragmentation, finalizer problems etc).

 

6.    Synchronization

A multithreaded environment allows for a great deal of flexibility and efficiency. With this flexibility comes a lot of complexity in the form of thread management. To avoid costly mistakes in your application, care must be taken to ensure that threads perform their work in an orchestrated fashion. This chapter introduces the synchronization primitives available in .NET and discusses how the debuggers and tools can be used to debug common thread synchronization problems. Scenarios such as deadlocks, lock contentions, sync blocks, thin locks and thread pool problems are discussed.

 

7.    Interoperability

.NET relies heavily on underlying Windows components. In order to invoke the native Windows components the CLR exposes two primary methods of interoperability:

 

1.    Platform Invocation

2.    COM Interoperability

 

Since the.NET and Win32 programming models are often very different, idiosyncrasies often lead to hard to track down problems. In this chapter we look at some very common mistakes done when working in the Interoperability layer and how to use the debuggers and tools to troubleshoot the problems.

 

Part III – Advanced Topics

 

8.    Postmortem Debugging

Quite often it’s not feasible to expect full access to a failing machine so that a problem can be debugged. Bugs that surface on production machines on customer sites are rarely available for debugging. This chapter outlines the mechanisms for debugging a problem without access to the physical machine. Topics discussed include the basics of crash dumps, generating crash dumps, analyzing crash dumps etc.

 

9.    Power Tools

Introduces the reader to power tools such as Debugging via Powershell , IISDiag and more.

 

10. CLR 4.0

This chapter is reserved for any substantial enhancements coming out while the book is being authored/published.

 

Index

This script is more a template to show you how to use PowerDbg.

I must say the idea is from my teammate Aaron Barth!

This script collects information from all threads running managed code and gives the user statistics by threads like:

 

-      CLR stack.

-      Managed objects from the stack.

-      ASP.NET page.

-      What the thread is doing.

-      Exceptions by threads.

-      Threads running ASP.NET pages.

 

Contrary to what you may think, this script is very simple. It’s very easy to customize or improve it. For example, you may want to display the ASP.NET pages or queries/stored procedures by threads. Or you may want to create a report using HTML. The output from this script is text, simple and straight. Again, the idea is to show you how to use the cmdlets from PowerDbg in order to create scripts that automate the debugging session.

 

Screenshots:

 

 

 

 

 

 

 

 

 

Source code for PowerShellScriptASPXStatistics.ps1:

 

########################################################################################################

# Script:      PowerDbgScriptASPXStatistics

#

# Parameters:  None.

#

# Purpose:     Shows statistics from threads running ASP.NET pages.

#

#              Attention! This script was not tested on Win64.

#

# Changes History: 04/15/2009 – Fixed bug when there’s just one managed thread.

#

# Roberto Alexis Farah

# All my functions are provided "AS IS" with no warranties, and confer no rights.

########################################################################################################

set-psdebug -strict

$ErrorActionPreference = "stop"

trap {"Error message: $_"}

 

write-Host "Scanning all threads and extracting the CLR stack..." -foreground Green -background Black

 

# First, let's scan all threads and identify those running managed code.

Send-PowerDbgCommand "~* e !clrstack"

Parse-PowerDbgCLRSTACK

 

# Get all the stacks running managed code.

$clrStack = Convert-PowerDbgCSVToHashTable

 

write-Host "Done!" -foreground Green -background Black

 

# Sorts the keys by Thread Number and save them into an array.

$arrayOfThreads = @($clrStack.keys | Sort-Object {[int] $_})

 

# Let's consider the situation where the dump has no thread running managed code.

if($arrayOfThreads.Count -eq 0)

{

    write-Host "There are not threads running managed code!" -foreground Red -background Black

    return

}

 

write-Host "Scanning all threads and extracting the managed objects..." -foreground Green -background Black

 

Send-PowerDbgCommand "~* e !dso"

Parse-PowerDbgDSO

 

$dso = Convert-PowerDbgCSVToHashTable

 

write-Host "Done!" -foreground Green -background Black

 

write-Host "Collecting information about each thread..." -foreground Green -background Black

 

Send-PowerDbgCommand "!Threads"

Parse-PowerDbgTHREADS

 

$threads = Convert-PowerDbgCSVToHashTable

 

write-Host "Done!" -foreground Green -background Black

 

write-Host "Collecting information from threads running ASP.NET..." -foreground Green -background Black

 

Send-PowerDbgCommand "!ASPXPages"

Parse-PowerDbgASPXPAGES

 

$aspxPages = Convert-PowerDbgCSVToHashTable

 

write-Host "Done!" -foreground Green -background Black

 

write-Host "Scanning all threads and preparing statistics..." -foreground Green -background Black

 

# Scans all threads running managed code.

for($i = 0; $i -lt $arrayOfThreads.Length; $i++)

{

    # Make sure the content is not null.

    if($arrayOfThreads[$i] -eq "")

    {

        continue;  # Invalid, get next element.

    }

   

    write-Progress -activity "Thread Statistics" -status "Thread number $arrayOfThreads[$i]" -percentComplete ($i / $arrayOfThreads.length * 100)

   

    write-Host "==============================================================" -foreground Green -background Black

   

    write-Host "`nThread number: " -foreground Green -background Black -nonewline

    write-Host $arrayOfThreads[$i] -foreground Red -background Black

   

    write-Host "`nCLR stack:`n" -foreground Green -background Black

   

    [string] $temp = $clrstack[$arrayOfThreads[$i]]

    $temp = $temp.Replace($global:g_frameDelimiter, "`n")

    $temp = $temp.Replace(";", ",")

   

    write-Host $temp -foreground Red -background Black

   

    write-Host "`nManaged objects from the stack:`n" -foreground Green -background Black

   

    $temp = $dso[$arrayOfThreads[$i]]

   

    $temp = $temp.Replace($global:g_frameDelimiter, "`n")

    $temp = $temp.Replace(";", ",")

   

    write-Host $temp -foreground Red -background Black 

 

    write-Host "`nThread Number   ID OSID ThreadOBJ   State   GC       Context           Domain  Count APT Exception`n" -foreground Green -background Black

 

    write-Host "  " $arrayOfThreads[$i] "         " $threads[$arrayOfThreads[$i]] -foreground Red -background Black

   

    $threadNum = $arrayOfThreads[$i]

   

    # Change context to the current thread being analyzed.

    Send-PowerDbgCommand "~ $threadNum s"

   

    # Get exception.

    Send-PowerDbgCommand "!PrintException"

    Parse-PowerDbgPRINTEXCEPTION

   

    $exception = $null

    $exception = Convert-PowerDbgCSVToHashTable

   

    # Makes sure there is an exception coming from that thread.

    if($exception["Message:"] -ne $null)

    {

        write-Host "`nException object:" -foreground Green -background Black    

        write-Host $exception["Exception object:"] -foreground Red -background Black

        write-Host "Exception type:" -foreground Green -background Black           

        write-Host $exception["Exception type:"] -foreground Red -background Black       

        write-Host "Message:" -foreground Green -background Black           

        write-Host $exception["Message:"] -foreground Red -background Black       

        write-Host "Inner Exception:" -foreground Green -background Black           

        write-Host $exception["InnerException:"] -foreground Red -background Black

        write-Host "HRESULT:" -foreground Green -background Black           

        write-Host $exception["HResult:"] -foreground Red -background Black        

    }

 

    # User must press any key to continue after 5 threads were displayed.

    if((($i + 1) % 5) -eq 0)

    {

        write-Host "`n####### Press any key to see 5 more threads... #######"

        $keyboard = $host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown")

    }

}

 

write-Host "Done!" -foreground Green -background Black

 

write-Host "`nASP.NET Pages:`n" -foreground Green -background Black

 

write-Host "HttpContext      Timeout Completed Running ThreadId ReturnCode Verb RequestPath QueryString" -foreground Green -background Black

 

foreach($item in $aspxPages.keys)

{

    write-Host $item  "  " $aspxPages[$item] -foreground Red -background Black

}

 

This version has two improvements and some scripts were changed to be compatible with this new version:

 

-      Starting on version 5.2 the log used to save the command output, enabling the communication between PowerShell and WinDbg is not used anymore. Now all communication uses memory so it’s faster than before.

 

Note: the file POWERDBG-PARSED.LOG continues to exist since it’s useful for troubleshooting purposes and can be used as input for Excel or LogParser.

 

-      Installation is easier now. Just one file has everything.

 

I’ve created a simple PowerDbg script that gives ASPX information. It’s going to be blogged after this article and should be used as reference.

 

Note: It was difficult for me to find some free time and work on PowerDbg. I tested it using all scripts (modified two of them) and using different dumps. However, it may have bugs. If you hunt a bug let me know, please!

 

 

DOWNLOAD POWERDBG

 

Download PowerDbg

 

POWERDBG FILES

 

WinDbg.PSM1  ß Starting with this version this is the only file.

 

INSTALLATION

 

WinDbg.PSM1

 

Goes to %\WindowsPowerShell\Modules\WinDbg

 

Note: PowerDbg assumes the folder c:\debuggers as the default installation folder. This is true for the default installation of our private debugger version (Microsoft) but not for the public version, so, please, change this variable to reflect your installation:

 

param($cdbPath = "C:\debuggers\cdb.exe")

 

In order to know the exact location, use this command from PowerShell:

 

$profile

 

 

 

REQUIREMENT

 

PowerShell v2.0

 

 

USAGE

 

First, make sure you can run scripts:

 

set-executionpolicy remotesigned

 

From the WinDbg window type:

 

.server tcp:port=10456,server=ServerName   ß ServerName is your server name.

 

The command above enables a port communication with the WinDbg instance as the server. You can use other port numbers.

 

From the PowerShell window you must initialize the communication:

 

Import-module WinDbg  ß Imports our module WinDbg.PSM1

 

Connect-Windbg "tcp:Port=10456,Server=SERVER" ß Connects session to WinDbg instance.

 

Or:

 

Connect-Dbg "tcp:Port=10456,Server=SERVER" ß Connects session to WinDbg

 

Note: Don’t forget to load symbols and your extensions!

 

At this point you’re ready to use PowerDbg or PowerDbg scripts.

Example:

 

Analyze-PowerDbgThreads   ß Cmdlet.

 

.\PowerDbgScriptExceptions  ß Script.

 

Example 2:

 

Send-PowerDbgCommand "~* kpn 1000"

Parse-PowerDbgK

$ht = @{}

$ht = Convert-PowerDbgCSVToHashTable

 

Let's display the stack for thread 0:

 

# Replace the internal frame delimiter by new line and displays the stack. 

write-host $ht["0"].Replace($global:g_frameDelimiter, "`n")

 

Example 3:

 

Send-PowerDbgCommand "!DumpObj  027a4c3c"

Parse-PowerDbgDUMPOBJ

$ht = Convert-PowerDbgCSVToHashTable

$ht["Name:"]                 <-- Displays the content of the field Name:

$ht["MethodTable:"]    <-- Displays the content of the field MethodTable: 

 

 

NEW FOR POWERDBG v5.2

 

PowerDbg now uses just one file that has the content of the previous two files and is not the Profile file anymore.

Easier to install and maintain.

 

The information from WinDbg to PowerDbg used a text file, now it’s all memory based.

It’s faster now than before and eliminates timing issues that used to happen when the file was being saved and the next PowerDbg command executed.

As a collateral benefit you don’t need to use Start-Sleep in your scripts anymore to avoid timing issues.

 

Note: The CSV file POWERDBG-PARSED.LOG is still used. It facilitates the troubleshooting and can be used as input for Excel or LogParser.

 

 

NEW FOR POWERDBG v5.1

 

Load-PowerDbgSymbols <$symbolPath>

 

Load symbols.

Usage:  

Load-PowerDbgSymbols “SRV*c:\PUBLICSYMBOLS*http://msdl.microsoft.com/download/symbols"

 

Parse-PowerDbgASPXPAGES

 

Maps the output from the !ASPXPages command and saves it into the CSV file POWERDBG-PARSED.LOG

To convert the CSV file to a Hash Table use Convert-PowerDbgCSVToHashTable.

 

For this version the fields being considered are:

Key: HttpContext

Value: Timeout+Completed+Running+ThreadId+ReturnCode+Verb+RequestPath+QueryString

 

 

Parse-PowerDbgCLRSTACK

 

Maps the output from the !clrstack command or ~* e !clrstack and saves it into the CSV file POWERDBG-PARSED.LOG

To convert the CSV file to a Hash Table use Convert-PowerDbgCSVToHashTable.

 

Attention! The key is the thread number, and the value is the call stack separated by $global:g_frameDelimiter.

Commas "," are replaced for ";" to avoid confusion with the comma used by the CSV file.

If you use this cmdlet to parse the output from ~* e !clrstack, the threads not running managed code are automatically ignored.

 

 

Parse-PowerDbgTHREADS

 

Maps the output from the !threads command and saves it into the CSV file POWERDBG-PARSED.LOG

To convert the CSV file to a Hash Table use Convert-PowerDbgCSVToHashTable.

 

The following fields are extracted:

Thread Number                                                                                       - Key

ID+OSID+ThreadOBJ+State+GC+Context+Domain+Count+APT+Exception - Value

 

 

Parse-PowerDbgDSO

 

Maps the output from the !dso or ~* e !dso command and saves it into the CSV file POWERDBG-PARSED.LOG

To convert the CSV file to a Hash Table use Convert-PowerDbgCSVToHashTable.

 The Thread Number is the key, and the stack is the value, like the way that Parse-PowerDbgK or Parse-PowerDbgCLRSTACK operates.

 

Attention! Commas are replaced by ";" and $global:g_FrameDelimiter is used to separate frames.

 

 

CMDLETS FROM POWERDBG

 

Send-PowerDbgCommand <$command>

 

This was the most complex cmdlet, but now it’s just a wrapper for Invoke-WinDbgCommand.

SendPowerDbgCommand sends commands to WinDbg.

 

 

Parse-PowerDbgDT [$useFieldNames]

 

Parses the output from the dt command and saves it into POWERDBG-PARSED.LOG using a CSV file format.

If $useFieldNames has a value, the cmdlet stores fields from struct/classes and values. Otherwise it stores offsets and values.

To convert the CSV file to a Hash Table use Convert-PowerDbgCSVToHashTable.

 

 

Convert-PowerDbgCSVToHashTable

 

Converts the output from the Parse-PowerDbg* cmdlets to a Hash Table.

 

 

Send-PowerDbgDML <$hyperLinkDML> <$commandDML>

 

Creates a DML command and sends it to WinDbg.

DML stands for Debug Markup Language. Using DML you can create hyperlinks that execute commands.

 

 

Parse-PowerDbgNAME2EE

 

Maps the output from the !name2ee and saves it into the CSV file POWERDBG-PARSED.LOG

Convert-PowerDbgCSVtoHashTable converts the output into a Hash Table.

 

 

Parse-PowerDbgDUMPMD

 

Maps the output from !dumpmd command and saves it into the CSV file POWERDBG-PARSED.LOG.

Convert-PowerDbgCSVToHashTable converts the output into a Hash Table.

 

 

Parse-PowerDbgDUMPMODULE

 

Maps the output from !DumpModule command and saves it into the CSV file POWERDBG-PARSED.LOG

Convert-PowerDbgCSVToHashTable converts the output into a Hash Table.

 

 

 

Parse-PowerDbgDUMPLMI

 

Maps the output from !lmi command and saves it into the CSV file POWERDBG-PARSED.LOG

Convert-PowerDbgCSVToHashTable converts the output into a Hash Table.

 

 

Has-PowerDbgCOMMANDSUCCEEDED

 

Returns $true if the last command succeeded or $false if not.

 

 

Send-PowerDbgComment

 

Sends a comment, a string in bold, to the WinDbg window.

 

 

Parse-PowerDbgVERTARGET

 

Maps the output from vertarget command, either the Kernel Time or the User Time.

The output is saved into the CSV file POWERDBG-PARSED.LOG.

Convert-PowerDbgCSVToHashTable converts the output into a Hash Table.

 

 

Parse-PowerDbgRUNAWAY

 

Maps the output of !runaway 1 or !runaway 2 and stores the results into the CSV file POWERDBG-PARSED.LOG

Convert-PowerDbgCSVToHashTable converts the output into a Hash Table.

 

Attention! If you need to know the top threads consuming CPU time, use Convert-PowerDbgRUNAWAYtoArray. The items will be in the same exact order of the original command.

 

 

Convert-PowerDbgRUNAWAYtoArray

 

Returns an array of two dimensions corresponding to the output of !runaway 1 or !runaway 2.

 

 

Parse-PowerDbgK

 

Maps the output of k command and its variations like kv, kbn, kpn, etc.

The output is saved into the CSV file POWERDBG-PARSED.LOG

Convert-PowerDbgCSVToHashTable converts the output into a Hash Table.

 

Attention! This cmdlet doesn’t work with kPn. Another thing, it replaces “,” with “;” to avoid conflict with the CSV delimiter.

 

 

Parse-PowerDbgSymbolsFromK

 

Maps just the symbols from k command and variations, saving the content into the CSV file POWERDBG-PARSED.LOG

Convert-PowerDbgCSVToHashTable converts the output into a Hash Table.

 

Attention! This cmdlet doesn’t work with kPn. Another thing, it replaces “,” with “;” to avoid conflict with the CSV delimiter.

 

 

 

Parse-PowerDbgLM1M

 

Maps just the output from lm1m and stores it into the CSV file POWERDBG-PARSED.LOG

Convert-PowerDbgCSVToHashTable converts the output into a Hash Table.

 

 

Classify-PowerDbgThreads

 

Returns one array where the index is the thread number and the value is one of these values:

 

0 UNKNOWN_SYMBOL

1 WAITING_FOR_CRITICAL_SECTION

2 DOING_IO

3 WAITING

4 GC_THREAD

5 WAIT_UNTIL_GC_COMPLETE

6 SUSPEND_FOR_GC

7 WAIT_FOR_FINALIZE

8 TRYING_MANAGED_LOCK

9 DATA_FROM_WINSOCK

 

It’s very easy to add more symbols and constants to get a more granular analysis. Look at the source code for details.

             

 

 

Analyze-PowerDbgThreads

 

Analyzes and shows what each thread is doing and its corresponding CPU time, sorted by User Mode time.

This cmdlet is very useful for scenarios like hangs, high CPU, and crashes.

 

Attention! This command requires thread information if debugging a dump file.

 

 

 

Parse-PowerDbgPRINTEXCEPTION

 

Maps the output from  !PrintException command and saves it into the CSV file POWERDBG-PARSED.LOG.

The following fields are considered while others are ignored:

 

Exception object:

Exception type;

Message:

InnerException:

HRESULT:

 

Convert-PowerDbgCSVToHashTable converts the output into a Hash Table.

 

 

Parse-PowerDbgDD-L1

 

Maps the output from dd <address> L1 or dd poi(<address>) L1 and saves the results into the CSV file POWERDBG-PARSED.LOG.

Convert-PowerDbgCSVToHashTable converts the output into a Hash Table.

 

 

Parse-PowerDbgGCHANDLELEAKS

 

Maps the output from  !GCHandleLeaks command and saves it into the CSV file POWERDBG-PARSED.LOG.

Convert-PowerDbgCSVToHashTable converts the output into a Hash Table.

 

 

 

Parse-PowerDbgDUMPOBJ

 

Maps the output from !DumpObj command and saves it into the CSV file POWERDBG-PARSED.LOG.

The assembly path and file name are saved using the key name “Assembly:.”

If the object is invalid, the ‘Name:’ field will have the string “Invalid Object.” You may want to check this string to make sure you have valid data.

The keys are the fields or Method Table, and values are the corresponding value.

Convert-PowerDbgCSVToHashTable converts the output into a Hash Table.

 

Attention! This version maps the fields below “Fields:” using MethodTable as key and Value as value. The problem with this approach is that the same MethodTable may appear more than once. If it happens, the last or most recent MethodTable and value will be considered.

Based on users’ feedback this approach may be changed in the near future.

 

 

POWERDBG SCRIPTS

 

PowerDbgScriptDumpDict.PS1

 

Extracts the key/value pair from a dictionary.

 

 

PowerDbgScriptExceptions.PS1

 

Displays the call stacks that have inner or hidden exceptions.

 

 

PowerDbgScriptGCHandleLeaksChart.PS1

 

Displays statistics and a chart from the top 20 objects leaking.

 

 

PowerDbgScriptHighCPU.PS1

 

Displays all threads consuming high CPU using a specific time as a threshold.

 

 

PowerDbgScriptSaveModule.PS1

 

Saves all modules that have a specific method. You provide the method name, and it gives you the corresponding modules.

 

 

 

So, here we go again. This is a minor version with a few new cmdlets. These new cmdlets are those that we use most of the time.

 

DOWNLOAD POWERDBG

 

Download PowerDbg

 

POWERDBG FILES

 

WinDbg.PSM1  ß Contains cmdlets used to communicate with WinDbg.

 

Microsoft.PowerShell_Profile.PS1 ß Contains cmdlets that parse command output. Uses WinDbg.PSM1 under the hood.

 

 

INSTALLATION

 

 

Goes to %\Documents\WindowsPowerShell\Modules\WinDbg

 

 

Microsoft.PowerShell_Profile.PS1

 

Goes to %\Documents\windowspowershell

 

In order to know the exact location, use this command from PowerShell:

 

$profile

 

 

REQUIREMENT

 

PowerShell v2.0

 

 

USAGE

 

First, make sure you can run scripts:

 

set-executionpolicy remotesigned

 

From the WinDbg window type:

 

.server tcp:port=10456,server=ServerName   ß ServerName is your server name.

 

The command above enables a port communication with the WinDbg instance as the server. You can use other port numbers.

 

From the PowerShell window you must initialize the communication:

 

Import-module WinDbg  ß Importing our module WinDbg.PSM1

 

Connect-Windbg "tcp:Port=10456,Server=SERVER" ß Connects session to WinDbg instance.

 

Note: Don’t forget to load symbols and your extensions!

 

At this point you’re ready to use PowerDbg or PowerDbg scripts.

Example:

 

Analyze-PowerDbgThreads   ß Cmdlet.

 

.\PowerDbgScriptExceptions  ß Script.

 

Example 2:

 

Send-PowerDbgCommand "~* kpn 1000"

Parse-PowerDbgK

$ht = @{}

$ht = Convert-PowerDbgCSVToHashTable

 

Let's display the stack for thread 0:

 

# Replace the internal frame delimiter by new line and displays the stack. 

write-host $ht["0"].Replace($global:g_frameDelimiter, "`n")

 

Example 3:

 

Send-PowerDbgCommand "!DumpObj  027a4c3c"

Parse-PowerDbgDUMPOBJ

$ht = Convert-PowerDbgCSVToHashTable

$ht["Name:"]                 <-- Displays the content of the field Name:

$ht["MethodTable:"]    <-- Displays the content of the field MethodTable: 

 

For more examples see the source code from PowerDbg scripts.

 

 

NEW FOR POWERDBG v5.1

 

Load-PowerDbgSymbols <$symbolPath>

 

Load symbols.

Usage:  

Load-PowerDbgSymbols “SRV*c:\PUBLICSYMBOLS*http://msdl.microsoft.com/download/symbols"

 

Parse-PowerDbgASPXPAGES

 

Maps the output from the !ASPXPages command and saves it into the CSV file POWERDBG-PARSED.LOG

To convert the CSV file to a Hash Table use Convert-PowerDbgCSVToHashTable.

 

For this version the fields being considered are:

Key: HttpContext

Value: Timeout+Completed+Running+ThreadId+ReturnCode+Verb+RequestPath+QueryString

 

 

Parse-PowerDbgCLRSTACK

 

Maps the output from the !clrstack command or ~* e !clrstack and saves it into the CSV file POWERDBG-PARSED.LOG

To convert the CSV file to a Hash Table use Convert-PowerDbgCSVToHashTable.

 

Attention! The key is the thread number, and the value is the call stack separated by $global:g_frameDelimiter.

Commas "," are replaced for ";" to avoid confusion with the comma used by the CSV file.

If you use this cmdlet to parse the output from ~* e !clrstack, the threads not running managed code are automatically ignored.

 

 

Parse-PowerDbgTHREADS

 

Maps the output from the !threads command and saves it into the CSV file POWERDBG-PARSED.LOG

To convert the CSV file to a Hash Table use Convert-PowerDbgCSVToHashTable.

 

The following fields are extracted:

Thread Number                                                                                       - Key

ID+OSID+ThreadOBJ+State+GC+Context+Domain+Count+APT+Exception - Value

 

 

Parse-PowerDbgDSO

 

Maps the output from the !dso or ~* e !dso command and saves it into the CSV file POWERDBG-PARSED.LOG

To convert the CSV file to a Hash Table use Convert-PowerDbgCSVToHashTable.

 The Thread Number is the key, and the stack is the value, like the way that Parse-PowerDbgK or Parse-PowerDbgCLRSTACK operates.

 

Attention! Commas are replaced by ";" and $global:g_FrameDelimiter is used to separate frames.

 

 

CMDLETS FROM POWERDBG

 

Send-PowerDbgCommand <command>

 

This was the most complex cmdlet, but now it’s just a wrapper for Invoke-WinDbgCommand.

SendPowerDbgCommand sends commands to WinDbg.

 

 

Parse-PowerDbgDT [$useFieldNames] 

Parses the output from the dt command and saves it into POWERDBG-PARSED.LOG using a CSV file format.

If $useFieldNames has a value, the cmdlet stores fields from struct/classes and values. Otherwise it stores offsets and values.

To convert the CSV file to a Hash Table use Convert-PowerDbgCSVToHashTable.

 

 

Convert-PowerDbgCSVToHashTable

 

Convert the output from the Parse-PowerDbg* cmdlets to a Hash Table.

 

 

Send-PowerDbgDML <$hyperLinkDML> <$commandDML>

 

Creates a DML command and sends it to WinDbg.

DML stands for Debug Markup Language. Using DML you can create hyperlinks that execute commands.

 

 

Parse-PowerDbgNAME2EE

 

Maps the output from the !name2ee and saves it into the CSV file POWERDBG-PARSED.LOG

Convert-PowerDbgCSVtoHashTable converts the output into a Hash Table.

 

 

Parse-PowerDbgDUMPMD

 

Maps the output from !dumpmd command and saves it into the CSV file POWERDBG-PARSED.LOG.

Convert-PowerDbgCSVtoHashTable converts the output into a Hash Table.

 

 

Parse-PowerDbgDUMPMODULE

 

Maps the output from !DumpModule command and saves it into the CSV file POWERDBG-PARSED.LOG

Convert-PowerDbgCSVtoHashTable converts the output into a Hash Table.

 

  

Parse-PowerDbgLMI

 

Maps the output from lmi command and saves it into the CSV file POWERDBG-PARSED.LOG

Convert-PowerDbgCSVtoHashTable converts the output into a Hash Table.

 

 

Has-PowerDbgCOMMANDSUCCEEDED

 

Returns $true if the last command succeeded or $false if not.

 

 

Send-PowerDbgComment

 

Sends a comment, a string in bold, to the WinDbg window.

 

 

Parse-PowerDbgVERTARGET

 

Maps the output from vertarget command, either the Kernel Time or the User Time.

The output is saved into the CSV file POWERDBG-PARSED.LOG.

Convert-PowerDbgCSVtoHashTable converts the output into a Hash Table.

 

 

Parse-PowerDbgRUNAWAY

 

Maps the output of !runaway 1 or !runaway 2 and stores the results into the CSV file POWERDBG-PARSED.LOG

Convert-PowerDbgCSVtoHashTable converts the output into a Hash Table.

 

Attention! If you need to know the top threads consuming CPU time, use Convert-PowerDbgRUNAWAYtoArray. The items will be in the same exact order of the original command.

 

 

Convert-PowerDbgRUNAWAYtoArray

 

Returns an array of two dimensions corresponding to the output of !runaway 1 or !runaway 2.

 

 

Parse-PowerDbgK

 

Maps the output of k command and its variations like kv, kbn, kpn, etc.

The output is saved into the CSV file POWERDBG-PARSED.LOG

Convert-PowerDbgCSVtoHashTable converts the output into a Hash Table.

 

Attention! This cmdlet doesn't work with kPn. Another thing, it replaces "," with $global:g_frameDelimiter to avoid conflict with the CSV delimiter. 

 

 

Parse-PowerDbgSymbolsFromK

 

Maps just the symbols from k command and variations, saving the content into the CSV file POWERDBG-PARSED.LOG

Convert-PowerDbgCSVtoHashTable converts the output into a Hash Table.

 

Attention! This cmdlet doesn't work with kPn. Another thing, it replaces "," with $global:g_frameDelimiter to avoid conflict with the CSV delimiter. 

 

 

Parse-PowerDbgLM1M

 

Maps just the output from lm1m and stores it into the CSV file POWERDBG-PARSED.LOG

Convert-PowerDbgCSVtoHashTable converts the output into a Hash Table.

 

 

Classify-PowerDbgThreads

 

Returns one array where the index is the thread number and the value is one of these values:

 

0 UNKNOWN_SYMBOL

1 WAITING_FOR_CRITICAL_SECTION

2 DOING_IO

3 WAITING

4 GC_THREAD

5 WAIT_UNTIL_GC_COMPLETE

6 SUSPEND_FOR_GC

7 WAIT_FOR_FINALIZE

8 TRYING_MANAGED_LOCK

9 DATA_FROM_WINSOCK

 

It’s very easy to add more symbols and constants to get a more granular analysis. Look at the source code for details.

             

 

 

Analyze-PowerDbgThreads

 

Analyzes and shows what each thread is doing and its corresponding CPU time, sorted by User Mode time.

This cmdlet is very useful for scenarios like hangs, high CPU, and crashes.

 

Attention! This command requires thread information if debugging a dump file.

 

 

 

Parse-PowerDbgPRINTEXCEPTION

 

Maps the output from  !PrintException command and saves it into the CSV file POWERDBG-PARSED.LOG.

The following fields are considered while others are ignored:

 

Exception object:

Exception type;

Message:

InnerException:

HRESULT:

 

Convert-PowerDbgCSVtoHashTable converts the output into a Hash Table.

 

 

Parse-PowerDbgDD-L1

 

Maps the output from dd <address> L1 or dd poi(<address>) L1 and saves the results into the CSV file POWERDBG-PARSED.LOG.

Convert-PowerDbgCSVtoHashTable converts the output into a Hash Table.

 

 

Parse-PowerDbgGCHANDLELEAKS

 

Maps the output from  !GCHandleLeaks command and saves it into the CSV file POWERDBG-PARSED.LOG.

Convert-PowerDbgCSVtoHashTable converts the output into a Hash Table.

 

 

 

Parse-PowerDbgDUMPOBJ

 

Maps the output from !DumpObj command and saves it indo the CSV file POWERDBG-PARSED.LOG. 

The assembly path and file name are saved using the key name ‘Assembly:’.

If the object is invalid the ‘Name:’ field will have the string “Invalid Object.” You may want to check this string to make sure you’ve got valid data.

The keys are the fields or Method Table, and values are the corresponding value.

Convert-PowerDbgCSVtoHashTable converts the output into a Hash Table.

 

Attention! This version maps the fields below “Fields:” using MethodTable as key and Value as value. The problem with this approach is that the same MethodTable may appear more than once. If it happens, the last or most recent MethodTable and value will be considered.

Based on users’ feedback this approach may be changed in the near future.

 

 

POWERDBG SCRIPTS

 

PowerDbgScriptDumpDict.PS1

 

Extracts the key/value pair from a Dictionary.

 

 

PowerDbgScriptExceptions.PS1

 

Displays the call stacks that have inner or hidden exceptions.

 

 

PowerDbgScriptGCHandleLeaksChart.PS1

 

It displays statistics and a chart from the top 20 objects leaking.

 

 

PowerDbgScriptHighCPU.PS1

 

It displays all threads consuming high CPU using a specific time as a threshold.

 

 

PowerDbgScriptSaveModule.PS1

 

It saves all modules that have a specific method. You provide the method name, and it gives you the corresponding modules.

 

 

More Posts Next page »
 
Page view tracker