Thursday, December 07, 2006

Scan the stack for an exception record

In a comment of a blog post I found a trick, which I think it worth to mention here:
re: Sucking the exception pointers out of a stack trace which also refers to Finding where unmanaged exceptions came from.

>>
One technique that may be useful is actually searching the stack for the context flags (1003f on x86). It's quick, dirty, and doesn't require symbols, and works 99% of the time on x86.

> s -d esp Lffff 1003f
0535ef48 0001003f 00000000 00000000 00000000 ?...............
> .cxr 0535ef48
<<

Where s -d esp L1000 searches for stack range for the pattern 1003f
There might be one or more matches. Those maches can be passed to '.cxr' which sets the contxt record. Finally a k will dump the stack of the original exception.

Tuesday, October 10, 2006

How to trace function calls with windbg

Have a closer look at the 'wt' command.
When using 'wt' you should not it carefully without specifying any of the -l, -m or -i options. In most cases it makes sense to use the -l option to limit the trace to a certain depth (e.g.: 2 to 5) or to limit it to a certain modult with the -m option.

Output can look like this:

Attach to notepad.exe

Set a break point to...
0:001> bp notepad!FileDragOpen
0:001> g

Now drag a text file into notepad, the breakpoint will hit...

Breakpoint 1 hit
eax=00000000 ebx=00000000 ecx=0007fdb0 edx=7c90eb94 esi=7ca10702 edi=00000000
eip=0100337e esp=0007fdb8 ebp=0007fdc0 iopl=0 nv up ei pl zr na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246
notepad!FileDragOpen:
0100337e 8bff mov edi,edi

0:000> wt -l 2
Tracing notepad!FileDragOpen to return address 01003416
7 0 [ 0] notepad!FileDragOpen
155 0 [ 1] notepad!CheckSave
24 0 [ 2] USER32!SendMessageW
165 24 [ 1] notepad!CheckSave
5 0 [ 2] notepad!__security_check_cookie
167 29 [ 1] notepad!CheckSave
18 196 [ 0] notepad!FileDragOpen
19 0 [ 1] kernel32!CreateFileW
96 0 [ 2] ntdll!RtlInitUnicodeString
33 96 [ 1] kernel32!CreateFileW
32 0 [ 2] kernel32!BaseIsThisAConsoleName
42 128 [ 1] kernel32!CreateFileW
30 0 [ 2] ntdll!RtlDosPathNameToNtPathName_U
133 158 [ 1] kernel32!CreateFileW
4 0 [ 2] ntdll!NtCreateFile
140 162 [ 1] kernel32!CreateFileW
79 0 [ 2] ntdll!RtlFreeHeap
147 241 [ 1] kernel32!CreateFileW
14 0 [ 2] ntdll!RtlFreeHeap
155 255 [ 1] kernel32!CreateFileW
17 0 [ 2] kernel32!SetLastError
163 272 [ 1] kernel32!CreateFileW
24 631 [ 0] notepad!FileDragOpen
3 0 [ 1] notepad!LoadFile
19 0 [ 2] notepad!_SEH_prolog
20 19 [ 1] notepad!LoadFile
91 0 [ 2] kernel32!GetFileInformationByHandle
30 110 [ 1] notepad!LoadFile
4 0 [ 2] USER32!NtUserSetCursor
41 114 [ 1] notepad!LoadFile
67 0 [ 2] kernel32!CreateFileMappingW
50 181 [ 1] notepad!LoadFile
12 0 [ 2] kernel32!MapViewOfFile
53 193 [ 1] notepad!LoadFile
24 0 [ 2] kernel32!CloseHandle
57 217 [ 1] notepad!LoadFile
24 0 [ 2] kernel32!CloseHandle
75 241 [ 1] notepad!LoadFile
12 0 [ 2] notepad!IsInputTextUnicode
81 253 [ 1] notepad!LoadFile
429224 0 [ 2] notepad!IsTextUTF8

430213 instructions were executed in 430212 events (0 from other threads)

Function Name Invocations MinInst MaxInst AvgInst
USER32!NtUserSetCursor 1 4 4 4
USER32!SendMessageW 1 24 24 24
kernel32!BaseIsThisAConsoleName 1 32 32 32
kernel32!CloseHandle 2 24 24 24
kernel32!CreateFileMappingW 1 67 67 67
kernel32!CreateFileW 1 163 163 163
kernel32!GetFileInformationByHandle 1 91 91 91
kernel32!MapViewOfFile 1 12 12 12
kernel32!SetLastError 1 17 17 17
notepad!CheckSave 1 167 167 167
notepad!FileDragOpen 1 24 24 24
notepad!IsInputTextUnicode 1 12 12 12
notepad!IsTextUTF8 1 429224 429224 429224
notepad!LoadFile 1 81 81 81
notepad!_SEH_prolog 1 19 19 19
notepad!__security_check_cookie 1 5 5 5
ntdll!NtCreateFile 1 4 4 4
ntdll!RtlDosPathNameToNtPathName_U 1 30 30 30
ntdll!RtlFreeHeap 2 14 79 46
ntdll!RtlInitUnicodeString 1 96 96 96

0 system calls were executed

ps.: This should hide most of the OS stuff, when you are just interested in your own code:
wt -i MSVCP60 -i OLEAUT32 -i SHLWAPI -i USER32 -i kernel32 -i msvcrt -i msxml4 -i ntdll

How to break on VB6 run time errors

In order to detect VB6 run time errors you need to set a break point to MSVBVM60!EbRaiseExceptionCode and MSVBVM60!EbRaiseException:

bp MSVBVM60!EbRaiseExceptionCode
bp MSVBVM60!EbRaiseException

Or even simpler with e wildcard:
bm /a MSVBVM60!EbRaiseException*

Thursday, September 14, 2006

Tuesday, August 08, 2006

How to write parts of the process memory to a file

In order to write parts of the process memory to a file use the .writemem command.
Syntax is .writemem FileName Address Range

Example:
You want to dump a huge BSTR into a file:
Address of the BSTR: 0x0d900024

Get the size (The DWORD receedig the actual string contains the size):
0:000> dc 0x0d900024 - 4
0d900020 005f7a1c ...


.writemem c:\temp\string_content.txt 0x0d900024 L?005f7a1c

Please note the "?" in the size parameter to avoid build in size checks.

Be aware of using the /b option with .dump!

When using /b with .dump in order to generate a cab file you will get the message:

"Creating a cab file can take a VERY VERY long time"
- and this is VERY VERY (!) true.

".Ctrl-C can only interrupt the command after a file has been added to the cab."
- so all you can do is wait and have one cup of coffe after the other :-(

Friday, August 04, 2006

Scan the stack for strings

It is very easy to find stirngs on the stack of life debugging session or in a crash dump.
Simply set the context you are interested in with ~x s (replace x with the thread you are interested in) or set the excption context with .cxr 'address' or .ecxr (dump contains an excpetion record).

Then type:
0:000> da @ebp

You will likely get lots of trash, like this:
0012bf30 "X.."

then type
0:000> da
0012bf34 ".a.w..."

typing 'enter' repeats the last command, so we will walk down the stack by pressig 'enter'
0:000>
0012bf3c "8"
[...]

0:000>
0012c478 "Runtime Error!..Program: ...X.exe"
0012c4b8 "........................................This app"
0012c4d8 "lication has requested the Runti"
0012c4f8 "me to terminate it in an unusual"
0012c518 " way..Please contact the applica"
0012c538 "tion's support team for more inf"
0012c558 "ormation..."


This of course does not not work with strings on the heap.
Simply use 'dda' (or 'ddu' for unicode) to list those.

Thursday, July 27, 2006

How to get the stack when 'k' tells you 'Stack unwind information not available. Following frames may be wrong.'

Sometimes Windbg is not able to recreate the stack when using the k command.
This problem might come up with frame pointer optimization for example.
In such cases you can easily construct the call stack manually with some usage of your brain:

First execute:
0:000> dps @ebp

This will list the raw contents of the stack along with a matching symbol if available (top down)

then execute 'd' (which repeats the last d* command) as long as you reach the bottom of the stack. Know you need to distinguish between calls on the stack and variables and so forth. With few knowledge of the code executed it is pretty obvious to devide the calls from the rest. I personally copy the calls to the scratch pad not to get lost.

Wednesday, June 07, 2006

How to find out what code modifies memory

You can use 'ba' (Break on Access) to define a breakpoint that hits when the portion of memory is read and/or modified.

ba w4 myPointer will cause the debugger to break, whenever myPointer is modified (assume a 32bit system)

How to debug double deletes / access after delete

It can happen that you come along an access violation but the source of the error has occured long time back in the past, because your code tries to access memory that has alreafy been freed.

I order to debug such a scenario you need to enable full page heap:

gflags -p /enable YourApp.exe /full

Then do the stuff to reproduce the AV. When you get it type this:

!heap -p -a [address of AV]

If you have luck you will get the call call stack of deallocation.

Friday, April 21, 2006

How to find out on which thread a blocked thread is waiting

First get the stack of the blocked thread by

0:002> kb
ChildEBP RetAddr Args to Child
00edfdd8 7c90e9c0 7c8025db 0000026c 00000000 ntdll!KiFastSystemCallRet
00edfddc 7c8025db 0000026c 00000000 00000000 ntdll!ZwWaitForSingleObject+0xc
00edfe40 7c802542 0000026c ffffffff 00000000 kernel32!WaitForSingleObjectEx+0xa8
00edfe54 6640114a 0000026c ffffffff 00813190 kernel32!WaitForSingleObject+0x12
[...]

The first parameter passed to WaitForSingleObject is the handle to the thread this thread is waiting for (Precondition: we are waiting for a thread and not another synchronisation object).


We can get more information about this handle by

0:002> !handle 0000026c f
Handle 0000026c
Type Thread
Attributes 0
GrantedAccess 0x1f03ff:
Delete,ReadControl,WriteDac,WriteOwner,Synch
Terminate,Suspend,Alert,GetContext,SetContext,SetInfo,QueryInfo,SetToken,Impersonate,DirectImpersonate
HandleCount 7
PointerCount 10
Name
Object specific information
Thread Id b94.ff4
Priority 3
Base Priority -16


Now we identified the questionable thread with b94.ff4

Thursday, March 23, 2006

Use !critsec to find out, which thread is waiting for a critical section

If you need to find out which thread is owning a critical section a blocked thread is waiting for you can first get the stack args by

kb

Then you need to get the critical section address from the stack. This is an argument passed to ntdll!RtlEnterCriticalSection API as first parameter.

By typing

!critsec 'address'

You'll get information about the section like: LockCount, RecursionCount, OwningThread, EntryCount, ContentionCount and the Locked state.

CritSec +81347c at 0081347c
LockCount 8
RecursionCount 1
OwningThread c6c
EntryCount 8
ContentionCount 8
*** Locked

Tuesday, March 14, 2006

Debug Tutorial Part 4: Writing WINDBG Extensions

Cool article from Toby Opferman about how extending windbg. Must read:
Debug Tutorial Part 4: Writing WINDBG Extensions

Friday, March 10, 2006

A word for WinDbg (Mike Taulty)

A very good starting point if you are planning to dig a bit into windbg:

W word for WinDbg
W word for WinDbg (2)

Wednesday, March 01, 2006

Starting UltraEdit from WinDbg

By setting follwoing env variable:
WINDBG_INVOKE_EDITOR=C:\PROGRA~1\ULTRAE~1\uedit32.exe %f/%l/1
{you might need to adapt the path}

You get the ability to open a source file from within windbg by simply right clicking on the source window header and then clicking "Edit this file..."

(this works also with other editors ;-) )

use "lmv m " to display detailed information about a specific module

e.g.:

0:003> lmv m actbar2
start end module name
35000000 350d0000 Actbar2 (export symbols) C:\SnapShots\voneinem_view_a0032858_c\VespucciPool\common\bin\debug\Actbar2.ocx
Loaded symbol image file: C:\SnapShots\voneinem_view_a0032858_c\VespucciPool\common\bin\debug\Actbar2.ocx
Image path: C:\SnapShots\voneinem_view_a0032858_c\VespucciPool\common\bin\debug\Actbar2.ocx
Image name: Actbar2.ocx
Timestamp: Wed Oct 27 16:52:02 2004 (417FB612)
CheckSum: 000D7481
ImageSize: 000D0000
File version: 2.5.2.121
Product version: 2.5.2.121
File flags: 0 (Mask 3F)
File OS: 40004 NT Win32
File type: 2.0 Dll
File date: 00000000.00000000
Translations: 0000.04b0 0409.04b0
CompanyName: Data Dynamics
ProductName: Data Dynamics ActiveBar 2.0 Control
InternalName: ActiveBar 2.5
OriginalFilename: ActiveBar2.ocx
ProductVersion: 2, 5, 2, 121
FileVersion: 2, 5, 2, 121
PrivateBuild: 2, 5, 2, 121
SpecialBuild: 2, 5, 2, 121
FileDescription: ActiveBar 2.5 Control
LegalCopyright: Copyright © 1999-2004 Data Dynamics
LegalTrademarks: Copyright © 1999-2004 Data Dynamics
Comments: Copyright © 1999-2004 Data Dynamics


To get a quick list of modules simply type "lm"

Display unicode strings the easy way

Did you ever wonder why windbg does not display unicode strings but simply shows the pointer?

Try ".enable_unicode 1"! This causes all 16-bit (USHORT) arrays and pointers to be displayed as Unicode strings.

(".enable_unicode 0" restores the default)

Monday, February 13, 2006

.NET debugging using WinDbg

This is a very good step by step cook book about .NET debugging using WinDbg

A word for WinDbg (2)