A few weeks back I solicited ideas for posts and the overwhelming favorite was a series of posts on debugging.  While trying to work out some sort of logical way to do this I decided the best way was to start at the beginning and work my way into the deeper stuff.  So, for some you may be further into debugging than others and find these first couple to be of no use.  I am sure that some of you will find this information helpful, and may not have known some of this stuff existed. 

Where to Begin

In order to debug we need a a reason, a broken application, so I have attached an exe with which we can learn how to debug.  For now all I have included is the exe, in future posts I will add more so that we can dive deeper into debugging.  To see this in action, run the dbgexe.exe and you should see something like this:

Now, Let's tryout the application. Select Test 2 - Access Violation from the dropdown. Then click the Invoke button 2 times. The second time the application should crash.

Next Step

Well, not that we have a crashing application we need to try and figure out why it's crashing.  We can start with something that Windows has built right in, Dr. Watson.  If you are unfamiliar with Dr. Watson you can find more information in the  Microsoft Support article "Description of the Dr. Watson for Windows Tool".

Where do you find this mysterious Dr. Watson? Select Start -> Run  and then type in drwtsn32.exe to see the application:

Take note of the two entries inside the red circle as those are the paths to the files of interest. 

Note: If you have installed Visual Studio or even the Windows Debugger package you may no longer have Dr. Watson as your JIT (Just-in-Time) debugger.  If this is the case you would have gotten a Visual Studio dialog when the application crashed, or WinDbg would've popped up.  To reset this execute "drwtsn32 -I" from the Start -> Run dialog.

So, assuming all was setup right we should now be able to look in the folders specified for the Dr. Watson log file and user dump file.

The Log File

The default location for the log file is C:\Documents and Settings\All Users\Application Data\Microsoft\Dr Watson on Windows XP. If you look in the folder you should see a file named drwtsn32.log.  Open this file and scroll to the bottom.

Why the bottom?  We scroll to the bottom because this is a cumulative file and new entries are added to the bottom. From there we search up for the word "FAULT".  This will find the last fault that was captured.  There are a number of sections filled in for each fault in the file.   First is the Header section, which looks like this:

Application exception occurred:
        App: C:\Documents and Settings\jwiese\Desktop\dbgexe.exe (pid=10228)
        When: 3/29/2006 @ 15:41:51.770
        Exception number: c0000005 (access violation)

This information tells me that an Exception has occurred, and what application it occurred in.  The other information about the day and time may also be of use as well as the actual exception number. Next comes the System Information section which contains information about the computer.  This section is usually not very useful, unless you are having multiple machines writing to the same shared drive location. Then we see a Task List, which shows all the running processes on the machine and their ProccessID number. Following he Task List is the Module List.  This section shows all of the modules (DLLs, OCXs, EXEs, etc.) that are loaded into the processes memory space. After this section comes the sections that are of most interest to us. 

The first section of interest is the State Dump. This section contains information about all the CPU registers at the time of the crash and the assembly code that was running when we crashed.  Many times you will need to look at the assembly to try and figure out what was going on when the application crashed, mainly when source is not available or it just isn't adding up (thank you compiler optimizations).  This is the section where we see the "FAULT ->", indicating the exact assembly line that failed. 

FAULT ->77c42a16 803800           cmp     byte ptr [eax],0x0      ds:0023:00000003=??

Hmm, not very helpful is it :)  So we know that we were doing a compare when we failed, doesn't seem like something that should fail...unless the EAX register that we are using as a pointer can't be used as a pointer.  This appears to be the case if we look at the end of the line and see that EAX=0x00000003 which is not a valid memory range.  If I've lost you at this point you may need to brush up on your assembly. Intel has some very large assembly references online if you need a refresher.

Let's check out the next section, Stack Back Trace, to see if we can get a little more info.  This section has the application flow that led to the crash.  The stack is read from the bottom up, and the last thing to happen is on the top of the stack.  Here is the stack I see in my log file:

WARNING: Stack unwind information not available. Following frames may be wrong.
*** WARNING: Unable to verify checksum for C:\Documents and Settings\jwiese\Desktop\dbgexe.exe
*** ERROR: Module load completed but symbols could not be loaded for C:\Documents and Settings\jwiese\Desktop\dbgexe.exe
*** ERROR: Symbol file could not be found.  Defaulted to export symbols for C:\WINDOWS\system32\MFC42.DLL -
*** ERROR: Symbol file could not be found.  Defaulted to export symbols for C:\WINDOWS\system32\USER32.dll -
*** ERROR: Symbol file could not be found.  Defaulted to export symbols for C:\WINDOWS\system32\ntdll.dll -
ChildEBP RetAddr  Args to Child             
0012f478 77c3ffb9 0012f494 004043ac 0012f6ec msvcrt!wscanf+0x750
0012f4b4 0040105e 0012f4dc 00000200 004043ac msvcrt!vsnprintf+0x2f
0012f6e0 004021cd 004043ac 00000003 445c3a43 dbgexe+0x105e
0012f774 00401792 00000001 00000000 0012fe0c dbgexe+0x21cd
0012f790 73dd24c0 00403370 00000111 0012f7d0 dbgexe+0x1792
0012f7a0 73dd23bf 0012fe0c 000003ef 00000000 MFC42!Ordinal567+0xab
0012f7d0 73e3dead 000003ef 00000000 00000000 MFC42!Ordinal4424+0x10a
0012f7f4 73dd3244 000003ef 00000000 00000000 MFC42!Ordinal4431+0x1d
0012f844 73dd1bf1 00000000 002710d0 0012fe0c MFC42!Ordinal4441+0x53
0012f8c4 73dd1b9b 00000111 000003ef 002710d0 MFC42!Ordinal5163+0x2f
0012f8e4 73dd1b05 00000111 000003ef 002710d0 MFC42!Ordinal6374+0x24
0012f944 73dd1a58 0012fe0c 00000000 00000111 MFC42!Ordinal1109+0x91
0012f964 73e6847d 00440700 00000111 000003ef MFC42!Ordinal1578+0x36
0012f990 77d48734 00440700 00000111 000003ef MFC42!Ordinal1579+0x39
0012f9bc 77d48816 73e68444 00440700 00000111 USER32!GetDC+0x6d
0012fa24 77d4b4c0 00000000 73e68444 00440700 USER32!GetDC+0x14f
0012fa78 77d4b50c 0072ca58 00000111 000003ef USER32!DefWindowProcW+0x184
0012faa0 7c90eae3 0012fab0 00000018 0072ca58 USER32!DefWindowProcW+0x1d0
0012fb00 77d4b903 0072ca58 00000111 000003ef ntdll!KiUserCallbackDispatcher+0x13
0012fb20 77d7fc7d 00440700 00000111 000003ef USER32!SendMessageW+0x49
0012fb38 77d764e8 0073b158 00000000 0073b158 USER32!CreateMDIWindowA+0x1bd
0012fb54 77d577de 0014d5b0 00000001 00000000 USER32!DeregisterShellHookWindow+0x6250
0012fbd8 77d6b05a 0073b158 00000202 00000000 USER32!GetCursorFrameInfo+0x1165
0012fbf8 77d48734 002710d0 00000202 00000000 USER32!SoftModalMessageBox+0xda3
0012fc24 77d48816 77d6b00e 002710d0 00000202 USER32!GetDC+0x6d
0012fc8c 77d489cd 00000000 77d6b00e 002710d0 USER32!GetDC+0x14f
0012fcec 77d48a10 004045b4 00000000 0012fd20 USER32!GetWindowLongW+0x127
0012fcfc 77d5e097 004045b4 004045b4 004045bc USER32!DispatchMessageW+0xf
0012fd20 77d6c6ab 00440700 0073b158 004045b4 USER32!IsDialogMessageW+0xdb
0012fd40 73de6795 00440700 004045b4 0012fe0c USER32!IsDialogMessageA+0x4a
004045b4 00000202 00000000 00050042 3e0d26f1 MFC42!Ordinal4047+0x31

So, from this is see that dbgexe.exe called the vsnprintf function within the msvcrt.dll.  That function then called scanf which is where we crashed. Without symbols we don't get line numbers, or even function names in the case of dbgexe so it is hard to get much more out of this. 

Next Steps

The next steps would be to try and trackdown the symbols for all the modules involved and then look at the dump file.  To do this we need more tools that are not included with Windows.  That I will save for another day and another post.

Feel free to comment and ask questions as I will be lurking and responding :)