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.
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.
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.)
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. 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.
Additional information on how to debug using the internal debugger can be found in programs/winedbg/README.
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.
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).
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.
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.
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".
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.
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.
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 programto 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 &>relmsgThen 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=01ffIn 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.
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.
Some useful programs:
Simple win32 disassembler that works well with Wine.
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.
Traces DOS calls (Int 21h, DPMI, ...). Use it with Windows to correct file management problems etc.
Dumps the imports and exports of a PE (Portable Executable) DLL.
Dumps the imports and exports of a PE (Portable Executable) DLL.