WineHQ
WineHQ

1.3. Using the Wine Debugger

This section describes where to start debugging Wine. If at any point you get stuck and want to ask for help, please read the How to Report A Bug section of the Wine Users Guide for information on how to write useful bug reports.

1.3.1. Crashes

These usually show up like this:

Unhandled exception: page fault on write access to 0x00000000 in 32-bit code (0x0043369e).
Register dump:
 CS:0023 SS:002b DS:002b ES:002b FS:0063 GS:006b
 EIP:0043369e ESP:0b3ee90c EBP:0b3ee938 EFLAGS:00010246(  R- --  I  Z- -P- )
 EAX:00000072 EBX:7b8acff4 ECX:00000000 EDX:6f727265
 ESI:7ba3b37c EDI:7ffa0000
Stack dump:
0x0b3ee90c:  7b82ced8 00000000 7ba3b348 7b884401
0x0b3ee91c:  7b883cdc 00000008 00000000 7bc36e7b
0x0b3ee92c:  7b8acff4 7b82ceb9 7b8acff4 0b3eea18
0x0b3ee93c:  7b82ce82 00000000 00000000 00000000
0x0b3ee94c:  00000000 0b3ee968 70d7ed7b 70c50000
0x0b3ee95c:  00000000 0b3eea40 7b87fd40 7b82d0d0
Backtrace:
=>0 0x0043369e in elementclient (+0x3369e) (0x0b3ee938)
  1 0x7b82ce82 CONSOLE_SendEventThread+0xe1(pmt=0x0(nil)) [/usr/src/debug/wine-1.5.14/dlls/kernel32/console.c:1989] in kernel32 (0x0b3eea18)
  2 0x7bc76320 call_thread_func_wrapper+0xb() in ntdll (0x0b3eea28)
  3 0x7bc7916e call_thread_func+0x7d(entry=0x7b82cda0, arg=0x0(nil), frame=0xb3eeb18) [/usr/src/debug/wine-1.5.14/dlls/ntdll/signal_i386.c:2522] in ntdll (0x0b3eeaf8)
  4 0x7bc762fe RtlRaiseException+0x21() in ntdll (0x0b3eeb18)
  5 0x7bc7f3da start_thread+0xe9(info=0x7ffa0fb8) [/usr/src/debug/wine-1.5.14/dlls/ntdll/thread.c:408] in ntdll (0x0b3ef368)
  6 0xf7597adf start_thread+0xce() in libpthread.so.0 (0x0b3ef468)
0x0043369e: movl	%edx,0x0(%ecx)
Modules:
Module	Address			Debug info	Name (143 modules)
PE	  340000-  3af000	Deferred        speedtreert
PE	  3b0000-  3d6000	Deferred        ftdriver
PE	  3e0000-  3e6000	Deferred        immwrapper
PE	  400000-  b87000	Export          elementclient
PE	  b90000-  e04000	Deferred        elementskill
PE	  e10000-  e42000	Deferred        ifc22
PE	10000000-10016000	Deferred        zlibwapi
ELF	41f75000-41f7e000	Deferred        librt.so.1
ELF	41ff9000-42012000	Deferred        libresolv.so.2
PE	48080000-480a8000	Deferred        msls31
PE	65340000-653d2000	Deferred        oleaut32
PE	70200000-70294000	Deferred        wininet
PE	702b0000-70328000	Deferred        urlmon
PE	70440000-704cf000	Deferred        mlang
PE	70bd0000-70c34000	Deferred        shlwapi
PE	70c50000-70ef3000	Deferred        mshtml
PE	71930000-719b8000	Deferred        shdoclc
PE	78130000-781cb000	Deferred        msvcr80
ELF	79afb000-7b800000	Deferred        libnvidia-glcore.so.304.51
ELF	7b800000-7ba3d000	Dwarf           kernel32<elf>
  \-PE	7b810000-7ba3d000	\               kernel32
ELF	7bc00000-7bcd5000	Dwarf           ntdll<elf>
  \-PE	7bc10000-7bcd5000	\               ntdll
ELF	7bf00000-7bf04000	Deferred        <wine-loader>
ELF	7c288000-7c400000	Deferred        libvorbisenc.so.2
PE	7c420000-7c4a7000	Deferred        msvcp80
ELF	7c56d000-7c5b6000	Deferred        dinput<elf>
  \-PE	7c570000-7c5b6000	\               dinput
ELF	7c5b6000-7c600000	Deferred        libdbus-1.so.3
ELF	7c70e000-7c715000	Deferred        libasyncns.so.0
ELF	7c715000-7c77e000	Deferred        libsndfile.so.1
ELF	7c77e000-7c7e5000	Deferred        libpulsecommon-1.1.so
ELF	7c7e5000-7c890000	Deferred        krnl386.exe16.so
PE	7c7f0000-7c890000	Deferred        krnl386.exe16
ELF	7c890000-7c900000	Deferred        ieframe<elf>
  \-PE	7c8a0000-7c900000	\               ieframe
ELF	7ca00000-7ca1a000	Deferred        rasapi32<elf>
  \-PE	7ca10000-7ca1a000	\               rasapi32
ELF	7ca1a000-7ca21000	Deferred        libnss_dns.so.2
ELF	7ca21000-7ca25000	Deferred        libnss_mdns4_minimal.so.2
ELF	7ca25000-7ca2d000	Deferred        libogg.so.0
ELF	7ca2d000-7ca5a000	Deferred        libvorbis.so.0
ELF	7cd5d000-7cd9c000	Deferred        libflac.so.8
ELF	7cd9c000-7cdea000	Deferred        libpulse.so.0
ELF	7cdfe000-7ce23000	Deferred        iphlpapi<elf>
  \-PE	7ce00000-7ce23000	\               iphlpapi
ELF	7cff1000-7cffd000	Deferred        libnss_nis.so.2
ELF	7d60d000-7d629000	Deferred        wsock32<elf>
  \-PE	7d610000-7d629000	\               wsock32
ELF	7d80d000-7d828000	Deferred        libnsl.so.1
ELF	7d8cf000-7d8db000	Deferred        libgsm.so.1
ELF	7d8db000-7d903000	Deferred        winepulse<elf>
  \-PE	7d8e0000-7d903000	\               winepulse
ELF	7d95c000-7d966000	Deferred        libwrap.so.0
ELF	7d966000-7d96d000	Deferred        libxtst.so.6
ELF	7d96d000-7d992000	Deferred        mmdevapi<elf>
  \-PE	7d970000-7d992000	\               mmdevapi
ELF	7d9b3000-7d9d0000	Deferred        msimtf<elf>
  \-PE	7d9c0000-7d9d0000	\               msimtf
ELF	7d9d0000-7d9e5000	Deferred        comm.drv16.so
PE	7d9e0000-7d9e5000	Deferred        comm.drv16
ELF	7da83000-7db5f000	Deferred        libgl.so.1
ELF	7db60000-7db63000	Deferred        libx11-xcb.so.1
ELF	7db63000-7db78000	Deferred        system.drv16.so
PE	7db70000-7db78000	Deferred        system.drv16
ELF	7db98000-7dca1000	Deferred        opengl32<elf>
  \-PE	7dbb0000-7dca1000	\               opengl32
ELF	7dca1000-7dcb6000	Deferred        vdmdbg<elf>
  \-PE	7dcb0000-7dcb6000	\               vdmdbg
ELF	7dcce000-7dd04000	Deferred        uxtheme<elf>
  \-PE	7dcd0000-7dd04000	\               uxtheme
ELF	7dd04000-7dd0a000	Deferred        libxfixes.so.3
ELF	7dd0a000-7dd15000	Deferred        libxcursor.so.1
ELF	7dd16000-7dd1f000	Deferred        libjson.so.0
ELF	7dd24000-7dd38000	Deferred        psapi<elf>
  \-PE	7dd30000-7dd38000	\               psapi
ELF	7dd78000-7dda1000	Deferred        libexpat.so.1
ELF	7dda1000-7ddd6000	Deferred        libfontconfig.so.1
ELF	7ddd6000-7dde6000	Deferred        libxi.so.6
ELF	7dde6000-7ddef000	Deferred        libxrandr.so.2
ELF	7ddef000-7de11000	Deferred        libxcb.so.1
ELF	7de11000-7df49000	Deferred        libx11.so.6
ELF	7df49000-7df5b000	Deferred        libxext.so.6
ELF	7df5b000-7df75000	Deferred        libice.so.6
ELF	7df75000-7e005000	Deferred        winex11<elf>
  \-PE	7df80000-7e005000	\               winex11
ELF	7e005000-7e0a5000	Deferred        libfreetype.so.6
ELF	7e0a5000-7e0c5000	Deferred        libtinfo.so.5
ELF	7e0c5000-7e0ea000	Deferred        libncurses.so.5
ELF	7e123000-7e1eb000	Deferred        crypt32<elf>
  \-PE	7e130000-7e1eb000	\               crypt32
ELF	7e1eb000-7e235000	Deferred        dsound<elf>
  \-PE	7e1f0000-7e235000	\               dsound
ELF	7e235000-7e2a7000	Deferred        ddraw<elf>
  \-PE	7e240000-7e2a7000	\               ddraw
ELF	7e2a7000-7e3e3000	Deferred        wined3d<elf>
  \-PE	7e2b0000-7e3e3000	\               wined3d
ELF	7e3e3000-7e417000	Deferred        d3d8<elf>
  \-PE	7e3f0000-7e417000	\               d3d8
ELF	7e417000-7e43b000	Deferred        imm32<elf>
  \-PE	7e420000-7e43b000	\               imm32
ELF	7e43b000-7e46f000	Deferred        ws2_32<elf>
  \-PE	7e440000-7e46f000	\               ws2_32
ELF	7e46f000-7e49a000	Deferred        msacm32<elf>
  \-PE	7e470000-7e49a000	\               msacm32
ELF	7e49a000-7e519000	Deferred        rpcrt4<elf>
  \-PE	7e4b0000-7e519000	\               rpcrt4
ELF	7e519000-7e644000	Deferred        ole32<elf>
  \-PE	7e530000-7e644000	\               ole32
ELF	7e644000-7e6f7000	Deferred        winmm<elf>
  \-PE	7e650000-7e6f7000	\               winmm
ELF	7e6f7000-7e7fa000	Deferred        comctl32<elf>
  \-PE	7e700000-7e7fa000	\               comctl32
ELF	7e7fa000-7ea23000	Deferred        shell32<elf>
  \-PE	7e810000-7ea23000	\               shell32
ELF	7ea23000-7eaf9000	Deferred        gdi32<elf>
  \-PE	7ea30000-7eaf9000	\               gdi32
ELF	7eafb000-7eaff000	Deferred        libnvidia-tls.so.304.51
ELF	7eaff000-7eb09000	Deferred        libxrender.so.1
ELF	7eb09000-7eb0f000	Deferred        libxxf86vm.so.1
ELF	7eb0f000-7eb18000	Deferred        libsm.so.6
ELF	7eb18000-7eb32000	Deferred        version<elf>
  \-PE	7eb20000-7eb32000	\               version
ELF	7eb32000-7ec87000	Deferred        user32<elf>
  \-PE	7eb40000-7ec87000	\               user32
ELF	7ec87000-7ecf1000	Deferred        advapi32<elf>
  \-PE	7ec90000-7ecf1000	\               advapi32
ELF	7ecf1000-7ed8f000	Deferred        msvcrt<elf>
  \-PE	7ed00000-7ed8f000	\               msvcrt
ELF	7ef8f000-7ef9c000	Deferred        libnss_files.so.2
ELF	7ef9c000-7efc7000	Deferred        libm.so.6
ELF	7efc8000-7efe5000	Deferred        libgcc_s.so.1
ELF	7efe5000-7f000000	Deferred        crtdll<elf>
  \-PE	7eff0000-7f000000	\               crtdll
ELF	f73d0000-f73d4000	Deferred        libxinerama.so.1
ELF	f73d4000-f73d8000	Deferred        libxau.so.6
ELF	f73da000-f73df000	Deferred        libdl.so.2
ELF	f73df000-f7591000	Dwarf           libc.so.6
ELF	f7591000-f75ab000	Dwarf           libpthread.so.0
ELF	f75ab000-f76ef000	Dwarf           libwine.so.1
ELF	f7722000-f7728000	Deferred        libuuid.so.1
ELF	f7729000-f774a000	Deferred        ld-linux.so.2
ELF	f774a000-f774b000	Deferred        [vdso].so
Threads:
process  tid      prio (all id:s are in hex)
00000008 (D) C:\Perfect World Entertainment\Perfect World International\element\elementclient.exe
	00000031    0 <==
	00000035   15
	00000012    0
	00000021    0
	00000045    0
	00000044    0
	00000043    0
	00000038   15
	00000037    0
	00000036   15
	00000034    0
	00000033    0
	00000032    0
	00000027    0
	00000009    0
0000000e services.exe
	0000000b    0
	00000020    0
	00000017    0
	00000010    0
	0000000f    0
00000014 winedevice.exe
	0000001e    0
	0000001b    0
	00000016    0
	00000015    0
0000001c plugplay.exe
	00000022    0
	0000001f    0
	0000001d    0
00000023 explorer.exe
	00000024    0

Steps to debug a crash. You may stop at any step, but please report the bug and provide as much of the information gathered to the bug report as feasible.

  1. Get the reason for the crash. This is usually a page fault, an unimplemented function in Wine, or the like. When reporting a crash, report this whole crashdump even if it doesn't make sense to you.

    (In this case it is page fault on write access to 0x00000000. Most likely Wine passed NULL to the application or the like.)

  2. Determine the cause of the crash. Since this is usually a primary/secondary reaction to a failed or misbehaving Wine function, rerun Wine with the WINEDEBUG=+relay environment variable set. This will generate quite a lot of output, but usually the reason is located in the last calls. Those lines usually look like this:

    000d:Call advapi32.RegOpenKeyExW(00000090,7eb94da0 L"Patterns",00000000,00020019,0033f968) ret=7eb39af8
    ^^^^      ^^^^^^^^ ^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^  ^^^^^^^^^^^^
    |         |        |             |                 |           |                           |Return address.
    |         |        |             |                 |           |More arguments.
    |         |        |             |                 |Textual parameter.
    |         |        |             |Arguments.
    |         |        |Function called.
    |         |The module of the called function.
    |The thread in which the call was made.
    
    000d:Ret  advapi32.RegOpenKeyExW() retval=00000000 ret=7eb39af8
                                       ^^^^^^^^^^^^^^^
                                       |Return value is 32-bit and has the value 0.
  3. If you have found a misbehaving Wine function, try to find out why it misbehaves. Find the function in the source code. Try to make sense of the arguments passed. Usually there is a WINE_DEFAULT_DEBUG_CHANNEL(channel); at the beginning of the source file. Rerun wine with the WINEDEBUG=+xyz,+relay environment variable set.

    Occasionally there are additional debug channels defined at the beginning of the source file in the form WINE_DECLARE_DEBUG_CHANNEL(channel); if so the offending function may also use one of these alternate channels. Look through the the function for TRACE_(channel)(" ... /n"); and add any additional channels to the command line.

  4. Additional information on how to debug using the internal debugger can be found in programs/winedbg/README.

  5. If this information isn't clear enough or if you want to know more about what's happening in the function itself, try running wine with WINEDEBUG=+all, which dumps ALL included debug information in wine. It is often necessary to limit the debug output produced. That can be done by piping the output through grep, or alternatively with registry keys. See Section 1.5.3 for more information.

  6. If even that isn't enough, add more debug output for yourself into the functions you find relevant. See The section on Debug Logging in this guide for more information. You might also try to run the program in gdb instead of using the Wine debugger. If you do that, use handle SIGSEGV nostop noprint to disable the handling of seg faults inside gdb (needed for Win16).

  7. You can also set a breakpoint for that function. Start wine using winedbg instead of wine. Once the debugger is running enter break RegOpenKeyExW (replace by function you want to debug, case is relevant) to set a breakpoint. Then use continue to start normal program-execution. Wine will stop if it reaches the breakpoint. If the program isn't yet at the crashing call of that function, use continue again until you are about to enter that function. You may now proceed with single-stepping the function until you reach the point of crash. Use the other debugger commands to print registers and the like.

1.3.2. Program hangs, nothing happens

Start the program with winedbg instead of wine. When the program locks up switch to the winedbg terminal and press Ctrl-C. This will stop the program and let you debug the program as you would for a crash.

1.3.3. Program reports an error with a message box

Sometimes programs are reporting failure using more or less nondescript message boxes. We can debug this using the same method as Crashes, but there is one problem... For setting up a message box the program also calls Wine producing huge chunks of debug code.

Since the failure happens usually directly before setting up the message box you can start winedbg and set a breakpoint at MessageBoxA (called by win16 and win32 programs) and proceed with continue. With WINEDEBUG=+all Wine will now stop directly before setting up the message box. Proceed as explained above.

You can also run wine using WINEDEBUG=+relay wine program.exe 2>&1 | less -i and in less search for "MessageBox".

1.3.4. Disassembling programs

You may also try to disassemble the offending program to check for undocumented features and/or use of them.

The best, freely available, disassembler for Win16 programs is Windows Codeback, archive name wcbxxx.zip (e.g. wcb105a.zip).

Disassembling win32 programs is possible using e.g. GoVest by Ansgar Trimborn. It can be found here.

You can also use the newer and better Interactive Disassembler (IDA) from DataRescue. Take a look in the AppDB for links to various versions of IDA.

Another popular disassembler is Windows Disassembler 32 from URSoft. Look for a file called w32dsm87.zip (or similar) on winsite.com or softpedia.com. It seems that Windows Disassembler 32 currently has problems working correctly under Wine, so use IDA or GoVest.

Also of considerable fame amongst disassemblers is SoftIce from NuMega. That software has since been acquired by CompuWare and made part of their Windows driver development suite. Newer versions of SoftIce needs to run as a Windows Service and therefore won't currently work under Wine.

If nothing works for you, you might try one of the disassemblers found in Google directory.

Understanding disassembled code is mostly a question of exercise. Most code out there uses standard C function entries (for it is usually written in C). Win16 function entries usually look like that:

push bp
mov bp, sp
... function code ..
retf XXXX 	<--------- XXXX is number of bytes of arguments

This is a FAR function with no local storage. The arguments usually start at [bp+6] with increasing offsets. Note, that [bp+6] belongs to the rightmost argument, for exported win16 functions use the PASCAL calling convention. So, if we use strcmp(a,b) with a and b both 32-bit variables b would be at [bp+6] and a at [bp+10].

Most functions make also use of local storage in the stackframe:

enter 0086, 00
... function code ...
leave
retf XXXX

This does mostly the same as above, but also adds 0x86 bytes of stackstorage, which is accessed using [bp-xx]. Before calling a function, arguments are pushed on the stack using something like this:

push word ptr [bp-02]   <- will be at [bp+8]
push di                 <- will be at [bp+6]
call KERNEL.LSTRLEN

Here first the selector and then the offset to the passed string are pushed.

1.3.5. Sample debugging session

Let's debug the infamous Word SHARE.EXE message box:

|marcus@jet $ wine winword.exe
|            +---------------------------------------------+
|            | !  You must leave Windows and load SHARE.EXE|
|            |    before starting Word.                    |
|            +---------------------------------------------+
|marcus@jet $ WINEDEBUG=+relay,-debug wine winword.exe
|CallTo32(wndproc=0x40065bc0,hwnd=000001ac,msg=00000081,wp=00000000,lp=00000000)
|Win16 task 'winword': Breakpoint 1 at 0x01d7:0x001a
|CallTo16(func=0127:0070,ds=0927)
|Call WPROCS.24: TASK_RESCHEDULE() ret=00b7:1456 ds=0927
|Ret  WPROCS.24: TASK_RESCHEDULE() retval=0x8672 ret=00b7:1456 ds=0927
|CallTo16(func=01d7:001a,ds=0927)
|     AX=0000 BX=3cb4 CX=1f40 DX=0000 SI=0000 DI=0927 BP=0000 ES=11f7
|Loading symbols: /home/marcus/wine/wine...
|Stopped on breakpoint 1 at 0x01d7:0x001a
|In 16 bit mode.
|Wine-dbg>break MessageBoxA                          <---- Set Breakpoint
|Breakpoint 2 at 0x40189100 (MessageBoxA [msgbox.c:190])
|Wine-dbg>c                                            <---- Continue
|Call KERNEL.91: INITTASK() ret=0157:0022 ds=08a7
|     AX=0000 BX=3cb4 CX=1f40 DX=0000 SI=0000 DI=08a7 ES=11d7 EFL=00000286
|CallTo16(func=090f:085c,ds=0dcf,0x0000,0x0000,0x0000,0x0000,0x0800,0x0000,0x0000,0x0dcf)
|...                                                   <----- Much debug output
|Call KERNEL.136: GETDRIVETYPE(0x0000) ret=060f:097b ds=0927
                               ^^^^^^ Drive 0 (A:)
|Ret  KERNEL.136: GETDRIVETYPE() retval=0x0002 ret=060f:097b ds=0927
                                        ^^^^^^  DRIVE_REMOVEABLE
						(It is a floppy diskdrive.)

|Call KERNEL.136: GETDRIVETYPE(0x0001) ret=060f:097b ds=0927
                               ^^^^^^ Drive 1 (B:)
|Ret  KERNEL.136: GETDRIVETYPE() retval=0x0000 ret=060f:097b ds=0927
                                        ^^^^^^  DRIVE_CANNOTDETERMINE
						(I don't have drive B: assigned)

|Call KERNEL.136: GETDRIVETYPE(0x0002) ret=060f:097b ds=0927
                               ^^^^^^^ Drive 2 (C:)
|Ret  KERNEL.136: GETDRIVETYPE() retval=0x0003 ret=060f:097b ds=0927
                                        ^^^^^^ DRIVE_FIXED
                                               (specified as a hard disk)

|Call KERNEL.97: GETTEMPFILENAME(0x00c3,0x09278364"doc",0x0000,0927:8248) ret=060f:09b1 ds=0927
                                 ^^^^^^           ^^^^^        ^^^^^^^^^
                                 |                |            |buffer for fname
                                 |                |temporary name ~docXXXX.tmp
                                 |Force use of Drive C:.

|Warning: GetTempFileName returns 'C:~doc9281.tmp', which doesn't seem to be writable.
|Please check your configuration file if this generates a failure.

Whoops, it even detects that something is wrong!

|Ret  KERNEL.97: GETTEMPFILENAME() retval=0x9281 ret=060f:09b1 ds=0927
                                          ^^^^^^ Temporary storage ID

|Call KERNEL.74: OPENFILE(0x09278248"C:~doc9281.tmp",0927:82da,0x1012) ret=060f:09d8 ds=0927
                                    ^^^^^^^^^^^^^^^^ ^^^^^^^^^ ^^^^^^^
                                    |filename        |OFSTRUCT |open mode:

                                       OF_CREATE|OF_SHARE_EXCLUSIVE|OF_READWRITE

This fails, since my C: drive is in this case mounted readonly.

|Ret  KERNEL.74: OPENFILE() retval=0xffff ret=060f:09d8 ds=0927
                                   ^^^^^^ HFILE_ERROR16, yes, it failed.

|Call USER.1: MESSAGEBOX(0x0000,0x09278376"You must close Windows and load SHARE.EXE before you start Word.",0x00000000,0x1030) ret=060f:084f ds=0927

And MessageBox'ed.

|Stopped on breakpoint 2 at 0x40189100 (MessageBoxA [msgbox.c:190])
|190     {		<- the sourceline
In 32 bit mode.
Wine-dbg>

The code seems to find a writable harddisk and tries to create a file there. To work around this bug, you can define C: as a network drive, which is ignored by the code above.

1.3.6. Debugging Tips

Here are some additional debugging tips:

  • If you have a program crashing at such an early loader phase that you can't use the Wine debugger normally, but Wine already executes the program's start code, then you may use a special trick. You should do a

    WINEDEBUG=+relay wine program
    to get a listing of the functions the program calls in its start function. Now you do a
    winedbg winfile.exe

    This way, you get into winedbg. Now you can set a breakpoint on any function the program calls in the start function and just type c to bypass the eventual calls of Winfile to this function until you are finally at the place where this function gets called by the crashing start function. Now you can proceed with your debugging as usual.

  • If you try to run a program and it quits after showing an error message box, the problem can usually be identified in the return value of one of the functions executed before MessageBox(). That's why you should re-run the program with e.g.

    WINEDEBUG=+relay wine program_name &>relmsg
    Then do a more relmsg and search for the last occurrence of a call to the string "MESSAGEBOX". This is a line like
    Call USER.1: MESSAGEBOX(0x0000,0x01ff1246 "Runtime error 219 at 0004:1056.",0x00000000,0x1010) ret=01f7:2160 ds=01ff
    In my example the lines before the call to MessageBox() look like that:
    Call KERNEL.96: FREELIBRARY(0x0347) ret=01cf:1033 ds=01ff
    CallTo16(func=033f:0072,ds=01ff,0x0000)
    Ret  KERNEL.96: FREELIBRARY() retval=0x0001 ret=01cf:1033 ds=01ff
    Call KERNEL.96: FREELIBRARY(0x036f) ret=01cf:1043 ds=01ff
    CallTo16(func=0367:0072,ds=01ff,0x0000)
    Ret  KERNEL.96: FREELIBRARY() retval=0x0001 ret=01cf:1043 ds=01ff
    Call KERNEL.96: FREELIBRARY(0x031f) ret=01cf:105c ds=01ff
    CallTo16(func=0317:0072,ds=01ff,0x0000)
    Ret  KERNEL.96: FREELIBRARY() retval=0x0001 ret=01cf:105c ds=01ff
    Call USER.171: WINHELP(0x02ac,0x01ff05b4 "COMET.HLP",0x0002,0x00000000) ret=01cf:1070 ds=01ff
    CallTo16(func=0117:0080,ds=01ff)
    Call WPROCS.24: TASK_RESCHEDULE() ret=00a7:0a2d ds=002b
    Ret  WPROCS.24: TASK_RESCHEDULE() retval=0x0000 ret=00a7:0a2d ds=002b
    Ret  USER.171: WINHELP() retval=0x0001 ret=01cf:1070 ds=01ff
    Call KERNEL.96: FREELIBRARY(0x01be) ret=01df:3e29 ds=01ff
    Ret  KERNEL.96: FREELIBRARY() retval=0x0000 ret=01df:3e29 ds=01ff
    Call KERNEL.52: FREEPROCINSTANCE(0x02cf00ba) ret=01f7:1460 ds=01ff
    Ret  KERNEL.52: FREEPROCINSTANCE() retval=0x0001 ret=01f7:1460 ds=01ff
    Call USER.1: MESSAGEBOX(0x0000,0x01ff1246 "Runtime error 219 at 0004:1056.",0x00000000,0x1010) ret=01f7:2160 ds=01ff

    I think that the call to MessageBox() in this example is not caused by a wrong result value of some previously executed function (it's happening quite often like that), but instead the message box complains about a runtime error at 0x0004:0x1056.

    As the segment value of the address is only 4, I think that that is only an internal program value. But the offset address reveals something quite interesting: offset 1056 is very close to the return address of FREELIBRARY():

    Call KERNEL.96: FREELIBRARY(0x031f) ret=01cf:105c ds=01ff
                                                 ^^^^
    Provided that segment 0x0004 is indeed segment 0x1cf, we now we can use IDA to disassemble the part that caused the error. We just have to find the address of the call to FreeLibrary(). Some lines before that the runtime error occurred. But be careful! In some cases you don't have to disassemble the main program, but instead some DLL called by it in order to find the correct place where the runtime error occurred. That can be determined by finding the origin of the segment value (in this case 0x1cf).

  • If you have created a relay file of some crashing program and want to set a breakpoint at a certain location which is not yet available as the program loads the breakpoint segment during execution, you may set a breakpoint to GetVersion16/32 as those functions are called very often.

    Then do a c until you are able to set this breakpoint without error message.

1.3.7. Some basic debugger usages

After starting your program with

winedbg myprog.exe

the program loads and you get a prompt at the program starting point. Then you can set breakpoints:

b RoutineName      (by routine name) OR
b *0x812575        (by address)

Then you hit c (continue) to run the program. It stops at the breakpoint. You can type

step               (to step one line) OR
stepi              (to step one machine instruction at a time;
                    here, it helps to know the basic 386
                    instruction set)
info reg           (to see registers)
info stack         (to see hex values in the stack)
info local         (to see local variables)
list line number   (to list source code)
x variable name    (to examine a variable; only works if code
                    is not compiled with optimization)
x 0x4269978        (to examine a memory location)
?                  (help)
q                  (quit)

By hitting Enter, you repeat the last command.

1.3.8. Useful programs

Some useful programs:

GoVest: govest.zip is available from http://www.oocities.com/govest/.

Simple win32 disassembler that works well with Wine.

IDA:

IDA Pro is highly recommended, but is not free. DataRescue does however make trial versions available.

Take a look in the AppDB for links to various versions of IDA.

XRAY: http://garbo.uwasa.fi/pub/pc/sysinfo/xray15.zip

Traces DOS calls (Int 21h, DPMI, ...). Use it with Windows to correct file management problems etc.

pedump: ftp://ftp.simtel.net/pub/simtelnet/win95/prog/pedump.zip

Dumps the imports and exports of a PE (Portable Executable) DLL.

winedump: (included in wine tree)

Dumps the imports and exports of a PE (Portable Executable) DLL.