Debugging Hints

From WineHQ Wiki
Revision as of 21:35, 19 January 2016 by RosanneDiMesio (talk | contribs) (Initial import; some markup fixes)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to: navigation, search

Certain types of bugs that pop up in Wine follow a pattern. This is a collection of tips that different developers have found effective in problems they've run across:

DLL Issues

  • If you have a Windows license (i.e. if you ever bought a PC from a high street store) you can go grab native DLLs from This can also be handy if you're missing various runtime DLLs smaller apps often assume are present. Using native DLLs is a good way to check how an API behaves without doing a full blown crosscompile.
  • The contents of ntdll are undocumented so don't bother attempting to find out what they do from MSDN. Our current code represents a best guess so when working on code inside kernel32 or ntdll itself, you should use our APIs. Most are self-explanatory but a few are not so don't be afraid to ask for help if you get stuck.
  • Anything related to DCOM/marshalling is quite tricky and unlikely to be a quick fix. There are several hacks in our builtin DLLs to satisfy InstallShield as that is the most common program which needs DCOM functionality. If you modify things there, make sure to test it against some InstallShields first.
  • When a program crashes with the builtin ["Comctl32"] but works with the native one, this can often indicate a missing notification/callback or an out of order message stream. Most GUI apps are very sensitive to callback ordering and if a callback is not run, or run out of sequence, some software won't initialize internal structures properly leading to a crash at some unspecified future time. The solution? Write test cases to show we have the message ordering right (or wrong). There are examples of how to do this in the user32 tests.


  • Windows that don't accept keyboard focus (typical symptom: what you type goes to the terminal) have been made unmanaged for some reason. Each WM can treat this differently but the most common response is that the window becomes always on top, appears on every desktop and cannot accept focus. Sometimes this is desirable: for menus and tooltips it's what you want. Often it isn't. Managed vs unmanaged is a rather difficult problem, ask on the wine-devel list for help if you wish to change the mode heuristics.
  • Visual glitches are best debugged by looking at the styles given by the application to the offending control, then simply reading the widget code by hand. There are no fancy tricks you can use here, you just have to play with the drawing code and see if you can figure out where the problem is. Fortunately, native Windows 98 ["Comctl32"] works well, so you can always use that as a reference.

Thrown Errors

  • There are several sets of error codes used throughout Windows, in particular the NT "native" APIs use the values in ntstatus.h which look like STATUS_ACCESS_DENIED - when passing these results back up to the standard Windows functions they must be converted to error codes in winerror.h. This conversion is done by RtlNtStatusToDosError(). Others may return HRESULTS, which is used throughout the COM APIs. For HRESULTs you can use the SUCCEEDED/FAILED macros to test them.
  • Be careful with error codes. Unfortunately, while MSDN documents what error codes a function can return, this information is often wrong, and even when correct, it rarely says exactly what each error code means. Many apps rely on particular codes being returned in particular scenarios so the best way to be sure is to write a test case.
  • An error printed to stderr by Wine which mentions !RtlpWaitForCriticalSection indicates a deadlock. Occasionally this can be a bug in the app, more often it's a bug in Wine. If a program is deadlocking on a critical section, a good place to start is by attaching to it with winedbg and getting a backtrace of all the threads. If you don't have any idea what I'm on about, read the threading section of the Wine developer guide.


  • If a program is complaining about a debugger being present, you need to find out why it thinks that and fix it. Wine does not report a debugger by default, but unfortunately as IsDebuggerPresent() is so easy to work around, many programs, especially games, use more devious techniques. Some contain anti-disassembly code. You can find common anti-debugger techniques by reading blackhat/warez cracking sites. Just don't do it at work! If you see attempts to load SICE.VXD or NTICE.VXD, you're seeing a check for the popular !SoftIce debugger and should be able to ignore it.
  • If a crash is being intercepted by a custom crash handler, or you cannot retrieve the backtrace, you may need to attach using a debugger to get a log. The following command can help get a backtrace if that is impossible. Note dtrace may not be available on your distribution/operating system.
# Get all signal traces.
sudo dtrace -n 'proc:::signal-handle /pid == $target/ { ustack(); }' -p <process ID>

# Filter out signals, in this example SIGUSR1. Also print it's number.
sudo dtrace -n 'proc:::signal-handle /pid == $target && args[0] != SIGUSR1/ { printf("signal %d\n", args[0]); ustack(); }' -p <process ID>
  • Win32 code uses HeapAlloc(GetProcessHeap(), 0, allocsize) instead of malloc(allocsize), and therefore so does Wine. In practice this rule isn't strictly enforced so you may see both.

See Also