Difference between revisions of "Debug Channels"

From WineHQ Wiki
Jump to: navigation, search
(See Also: fix wiki link)
(more improvements)
 
(4 intermediate revisions by 3 users not shown)
Line 1: Line 1:
 
'''''Translations of this page:''''' not yet ported. Translators, please see the discussion page.  
 
'''''Translations of this page:''''' not yet ported. Translators, please see the discussion page.  
 
  
 
'''WINEDEBUG''' is an environment variable that turns debugging messages on or off.
 
'''WINEDEBUG''' is an environment variable that turns debugging messages on or off.
Line 8: Line 7:
 
  WINEDEBUG=[class][+/-]channel[,[class2][+/-]channel2]
 
  WINEDEBUG=[class][+/-]channel[,[class2][+/-]channel2]
  
'''class''' is optional and can be one of the following: '''err''', '''warn''', '''fixme''', or '''trace'''. If class is not specified, all debugging messages for the specified channel are turned on. Each channel will print messages about a particular component of Wine. The following character can be either + or - to switch the specified channel on or off respectively. If there is no class part before it, a leading + can be omitted. Note that __spaces are not allowed any where in the string__.
+
'''class''' is optional and can be one of the following: '''trace''', '''warn''', '''err''', or '''fixme'''. These are ordered roughly from least to most severe. '''trace''' is used for code paths that occur as part of normal operation. '''warn''' is generally used for code paths that may cause failures, but are likely to be well-handled by a higher-level component. '''err''' is used for code paths that are likely to cause failures. '''fixme''' is used for code paths that are unimplemented in Wine. By default, only '''err''' and '''fixme''' are enabled. If a channel is specified without a class, all classes are enabled.
  
'''channel''' specifies which debug channel to turn on or off. For complete list of channels run this command in the source dir
+
Each channel will print messages about a particular component of Wine. The following character can be either + or - to switch the specified channel on or off respectively. If there is no class part before it, a leading + can be omitted. Note that spaces are not allowed any where in the string.
  
 +
'''channel''' specifies which debug channel to turn on or off. For complete list of channels run this command in the source directory:
  
 
  grep -r --include='*.c' --include='*.h' 'WINE_\(DEFAULT\|DECLARE\)_DEBUG_CHANNEL' dlls/ programs/
 
  grep -r --include='*.c' --include='*.h' 'WINE_\(DEFAULT\|DECLARE\)_DEBUG_CHANNEL' dlls/ programs/
Line 27: Line 27:
 
== Examples ==
 
== Examples ==
 
; WINEDEBUG=warn+all
 
; WINEDEBUG=warn+all
: will turn on all warning messages.
+
: will turn on WARN messages for all channels, in addition to already enabled ERR and FIXME messages.
; WINEDEBUG=warn+dll,+heap
+
: will turn on DLL warning messages and all heap messages.
+
 
; WINEDEBUG=fixme-all,warn+cursor,+relay
 
; WINEDEBUG=fixme-all,warn+cursor,+relay
: will turn off all FIXME messages, turn on cursor warning messages, and turn on all relay messages (API calls).
+
: will turn off all FIXME messages, turn on cursor WARN messages (in addition to ERR and FIXME messages), and turn on all relay messages (API calls).
 
; WINEDEBUG=+relay
 
; WINEDEBUG=+relay
 
: will turn on all relay messages. For more control on including or excluding functions and dlls from the relay trace look into the [HKCU\Software\Wine\Debug] registry key (See [[Useful Registry Keys]] and the example below).
 
: will turn on all relay messages. For more control on including or excluding functions and dlls from the relay trace look into the [HKCU\Software\Wine\Debug] registry key (See [[Useful Registry Keys]] and the example below).
 
+
; WINEDEBUG=-d3d
== List of Debug Channels ==
+
: will turn off all d3d messages, and additionally disable checking for GL errors after operations. This may improve performance.
{|class="wikitable"
+
||accel ||acledit ||actctx ||activeds ||actxprxy ||adpcm ||advapi ||advpack ||alsa ||amstream
+
|-
+
||animate ||appbar ||appwizcpl ||aspi ||atl ||atom ||avicap ||avifile ||bidi ||bitblt
+
|-
+
||bitmap ||browseui ||button ||cabinet ||capi ||cards ||caret ||cdrom ||class ||clipboard
+
|-
+
||clipping ||clusapi ||cmd ||cmdlgtst ||combo ||comboex ||comm ||commctrl ||commdlg ||compstui
+
|-
+
||computername ||console ||coreaudio ||cred ||credui ||crtdll ||crypt ||cryptasn ||cryptdlg ||cryptdll
+
|-
+
||cryptnet ||cryptui ||ctapi32 ||curses ||cursor ||d3d ||d3d10 ||d3d11 ||d3d7 ||d3d8
+
|-
+
||d3d9 ||d3d_caps ||d3d_constants ||d3d_decl ||d3d_draw ||d3drm ||d3d_shader ||d3d_surface ||d3d_texture ||d3dx
+
|-
+
||d3dx8 ||d3dxof ||datetime ||dbghelp ||dbghelp_coff ||dbghelp_dwarf ||dbghelp_msc ||dbghelp_stabs ||dbghelp_symt ||dc
+
|-
+
||dciman ||ddeml ||ddraw ||ddraw_thunk ||debug_buffer ||debugstr ||devenum ||dialog ||dinput ||dll
+
|-
+
||dma ||dmband ||dmcompos ||dmdump ||dmfile ||dmfileraw ||dmime ||dmloader ||dmscript ||dmstyle
+
|-
+
||dmsynth ||dmusic ||dmusic32 ||dnsapi ||dosmem ||dpa ||dplay ||dpnet ||dpnhpast ||dpvoice
+
|-
+
||driver ||ds ||dsa ||dsalsa ||dscapture ||dsound ||dsound3d ||dssenh ||dswave ||dwmapi
+
|-
+
||dxdiag ||edit ||eject ||enhmetafile ||environ ||event ||eventlog ||exec ||explorer ||faultrep
+
|-
+
||fiber ||file ||fixup ||font ||fps ||fusion ||g711 ||gdi ||gdiplus ||global
+
|-
+
||glu ||gpkcsp ||graphics ||handle ||header ||heap ||hid ||hlink ||hnetcfg ||hook
+
|-
+
||hotkey ||htmlhelp ||iccvid ||icm ||icmp ||icon ||imagehlp ||imagelist ||imm ||imports
+
|-
+
||inetcomm ||inetmib1 ||infosoft ||initpki ||inkobj ||inseng ||int ||int21 ||int31 ||io
+
|-
+
||ipaddress ||iphlpapi ||itircl ||itss ||jack ||joystick ||jscript ||key ||keyboard ||listbox
+
|-
+
||listview ||loaddll ||local ||localspl ||localui ||lsa ||mapi ||mci ||mciavi ||mcicda
+
|-
+
||mcimidi ||mciwave ||mdi ||menu ||menubuilder ||message ||metafile ||midi ||mixer ||mlang
+
|-
+
||mmaux ||mmio ||mmsys ||mmtime ||module ||monthcal ||mountmgr ||mpeg3 ||mpr ||mprapi
+
|-
+
||msacm ||mscat ||mscms ||mscoree ||msdmo ||msftedit ||msg ||msgbox ||mshtml ||msi
+
|-
+
||msidb ||msiexec ||msimg32 ||msimtf ||msisip ||msisys ||msnet ||msrle32 ||mssip32 ||mstask
+
|-
+
||msvcirt ||msvcr71 ||msvcrt ||msvcrt40 ||msvidc32 ||msvideo ||mswsock ||msxml ||nativefont ||nddeapi
+
|-
+
||netapi32 ||netbios ||newdev ||nls ||nonclient ||ntdll ||ntdsapi ||ntlm ||ntoskrnl ||ntprint
+
|-
+
||objsel ||odbc ||ole ||oleacc ||oledlg ||olemalloc ||olerelay ||olethk32 ||oleview ||opengl
+
|-
+
||openal32 ||pager ||palette ||pdh ||pidl ||powermgnt ||powrprof ||print ||printui ||process
+
|-
+
||profile ||progress ||propsheet ||propsys ||psapi ||psdrv ||pstores ||qcap ||qcap_v4l ||qedit
+
|-
+
||qmgr ||quartz ||query ||ras ||rebar ||recyclebin ||reg ||regedit ||region ||relay
+
|-
+
||resource ||resutils ||richedit ||richedit_check ||richedit_lists ||richedit_style ||rpc ||rpcss ||rundll32 ||sblaster
+
|-
+
||sccbase ||schannel ||scroll ||secur32 ||seh ||selector ||sensapi ||server ||service ||setupapi
+
|-
+
||sfc ||share ||shdocvw ||shell ||shlctrl ||slbcsp ||slc ||snmpapi ||snoop ||sound
+
|-
+
||spoolss ||spoolsv ||start ||static ||statusbar ||storage ||stress ||string ||svchost ||svrapi
+
|-
+
||sxs ||sync ||synchronous ||syslevel ||system ||systray ||tab ||tape ||tapi ||task
+
|-
+
||text ||theming ||themingcombo ||thread ||threadpool ||thunk ||tid ||time ||timestamp ||toolbar
+
|-
+
||toolhelp ||tooltips ||trackbar ||trash ||treeview ||twain ||typelib ||typelib2 ||uninstaller ||uniscribe
+
|-
+
||updown ||url ||urlmon ||user ||userenv ||uxtheme ||variant ||vdmdbg ||ver ||virtual
+
|-
+
||volume ||vxd ||wave ||wavemap ||wc_font ||wgl ||win ||wineboot ||winebrowser ||winecfg
+
|-
+
||wineconsole ||wine_d3d ||winedbg ||winedevice ||winemine ||winevdm ||wing ||winhelp ||winhttp ||wininet
+
|-
+
||winmm ||winscard ||winsock ||winspool ||winstation ||wintab ||wintab32 ||wintrust ||wldap32 ||wnet
+
|-
+
||wtsapi ||x11drv ||x11settings ||xcopy ||xdg ||xdnd ||xrandr ||xrender ||xvidmode
+
|}
+
  
 
== Useful Channels ==
 
== Useful Channels ==
Line 124: Line 39:
 
*+all : logs everything, probably gives too much information in most cases, but may come in handy for subtle issues
 
*+all : logs everything, probably gives too much information in most cases, but may come in handy for subtle issues
  
*+heap : traces all heap activity in the program and switches on constant integrity checks. If an app is trashing the heap, doing a +relay,+heap trace will let you narrow down exactly where it's happening. If an inconsistency is detected, Wine will dump the contents of the heap and terminate the program. Although many things can lead to trashing the heap, the most common is Wine overrunning an internal buffer. Be sure to remember this channel; most new Wine code uses the !HeapAlloc/HeapFree APIs internally, and a primary reason is that Wine's built in heap debugging is so useful.
+
*+heap : traces all heap activity in the program and switches on constant integrity checks. If an app is trashing the heap, doing a +relay,+heap trace will let you narrow down exactly where it's happening. If an inconsistency is detected, Wine will dump the contents of the heap and terminate the program. Although many things can lead to trashing the heap, the most common is Wine overrunning an internal buffer. Be sure to remember this channel; all Wine code uses the HeapAlloc/HeapFree APIs internally, and a primary reason is that Wine's built in heap debugging is so useful. Be warned that +heap can make a program extremely slow, and generate very large log files. If you're concerned that Wine may be corrupting the heap but are not sure, warn+heap will enable heap validation but will not trace every allocation and free.
  
*+loaddll : reports each DLL as it's loaded. This is a good, lightwei-ght alternative if you don't have the Windows program [http://www.dependencywalker.com Dependency Walker] available.
+
*+loaddll : reports each DLL as it is loaded.
  
*+message : logs Windows messages
+
*+message : logs all window messages dispatched to the window procedure, in a manner similar to +relay. Use +msg to trace calls to individual messaging-related APIs.
  
*+msgbox : logs when message boxes are displayed
+
*+msgbox : logs the contents of any calls to MessageBox(). Many programs display crash information using MessageBox(), so this can be a quick way to gather that information in a usable form.
  
*+olerelay : dumps calls made through the typelibrary marshaller. It's a bit like +relay but works for a certain class of DCOM calls that wouldn't normally show up. Unfortunately, while this can be useful especially for debugging InstallShield or DCOM issues, this isn't a general COM relay mechanism. Since InstallShield/DCOM issues are quite advanced, it's recommended you ask for help if you want to try using this channel.
+
*+pid : prefixes each debug output line with the ID of the process that generated it. This can be helpful when debugging multiprocess applications.
  
*+relay : logs every call that crosses the DLL boundary of Wine's built-in modules, including calls between (non-native) DLLs. This channel is often the first port of call when you have no idea what's going wrong. It shows you each call into and out of Wine modules at the DLL boundaries. If you're being overwhelmed by certain functions, look into setting the RelayInclude and RelayExclude strings in the Wine registry (under [HKCU\Software\Wine\Debug]). A good initial value for !RelayExclude is:
+
*+relay : logs every call that crosses the DLL boundary of Wine's built-in modules, including calls between (non-native) DLLs. This channel is often the first port of call when you have no idea what's going wrong. It shows you each call into and out of Wine modules at the DLL boundaries. If you're being overwhelmed by certain functions, look into setting the RelayInclude and RelayExclude strings in the Wine registry (under [HKCU\Software\Wine\Debug]). Note that this string is already pre-populated with some functions which are frequently called but don't usually give any clues as to why a program might be failing. '''Never use +relay or +snoop with native DLLs!''' This will show you the implementation of those DLLs, which means that any code you write to implement them violates our clean room reverse-engineering rules.
  
  RtlEnterCriticalSection;RtlLeaveCriticalSection;_EnterSysLevel;_LeaveSysLevel;
+
*+seh : logs Windows exceptions (Structured Exception Handling). These are invoked either when an application performs an illegal operation (i.e. crashes), or if a program throws its own exceptions. Wine converts UNIX signals into SEH exceptions and outputs them using this channel. This can be useful because applications will often trap their own crash, in order to perform an emergency save for instance. The most common exception to watch for is STATUS_ACCESS_VIOLATION or '''0xC0000005''' which is the closest equivalent in Win32 to a segfault. You may also see codes which don't appear in the headers; these are typically language-specific exceptions used by whichever compiler was used to produce the EXE. E.g. '''0xEEDFADE''' is the code for a Delphi internal exception, and '''0xE06D7363''' is a Microsoft Visual C++ exception, which has a magic value (info[0]) of '''0x19930520''', which is easy to remember because it looks like a date (and probably is). If you see any of these exceptions, it may mean a Win32 API call returned a non-zero error code somewhere.
  _CheckNotSysLevel;RtlAllocateHeap;RtlFreeHeap;LOCAL_Lock;LOCAL_Unlock
+
 
+
These functions are called a lot, but don't usually give any clues as to why a program might be failing.
+
 
+
*+seh : logs Windows exceptions (Structured Exception Handling). These are invoked either when an application performs an illegal operation (i.e. crashes), or if a program throws its own exceptions. Wine converts UNIX signals into SEH exceptions and outputs them using this channel. This can be useful because applications will often trap their own crash, in order to perform an emergency save for instance. The most common exception to watch for is STATUS_ACCESS_VIOLATION or '''0xC0000005''' which is the closest equivalent in Win32 to a segfault. You may also see codes which don't appear in the headers; these are typically language-specific exceptions used by whichever compiler was used to produce the EXE. E.g. '''0xEEDFADE''' is the code for a Delphi internal exception, and '''0xE06D7363''' is a Microsoft Visual C++ exception, which has a magic value ({{{info[0]}}}) of '''0x19930520''', which is easy to remember because it looks like a date (and probably is). If you see any of these exceptions, it probably means a Win32 API call returned a non-zero error code somewhere.
+
  
 
*+server : shows each wineserver RPC. You don't normally need this but it may prove helpful when debugging wineserver issues.
 
*+server : shows each wineserver RPC. You don't normally need this but it may prove helpful when debugging wineserver issues.
  
*+snoop : logs every function call between native DLLs. This is similar to +relay but works between two native DLLs, although this channel provides poorer information because parameters aren't reported. +snoop may also break or destabilize an application as it inspects the stack and disassembles function prologues to try and guess parameters.
+
*+snoop : logs every function call between native DLLs. This is similar to +relay but works between two native DLLs, although this channel provides poorer information because parameters aren't reported. +snoop may also break or destabilize an application as it inspects the stack and disassembles function prologues to try and guess parameters. '''Never use +relay or +snoop with native DLLs!''' This will show you the implementation of those DLLs, which means that any code you write to implement them violates our clean room reverse-engineering rules.
  
 
*+synchronous : forces X11 into synchronous mode
 
*+synchronous : forces X11 into synchronous mode
*+tid : prefixes each debug output line with the ID of the thread that generated it. This is invaluable for debugging multithreaded applications since a context switch can occur at any time and without it, there's often no way to tell exactly what's going on inside the program. If you aren't sure if a program is concurrent, enable it anyway. Although no channel is free, this one has a very cheap processing cost, and you can always disable it if you're only seeing one thread.
+
 
 
*+timestamp: prefixes each debug output line with the timestamp when that line executed. This is invaluable for debugging performance issue.
 
*+timestamp: prefixes each debug output line with the timestamp when that line executed. This is invaluable for debugging performance issue.
 +
 +
*+fps: prints the number of frames per second in the terminal for OpenGL, D3D, or Vulkan applications.
  
 
== Other Debugging Tips ==
 
== Other Debugging Tips ==
 
* If a program is displaying a message box when it fails, and you don't know what is causing the problem, try performing a +relay,+msgbox trace. Then open the debug log in your favourite editor or text viewer (less is quite good) and search for trace:msgbox. Look at the relay data before the MessageBox API call, although the problem may not be caused by a call that happens ''immediately'' before the error. Keep an eye out for failing API calls in particular, and remember that there's little consistency in the Windows API as to what return codes mean. You just have to get used to what the specific API uses, and while many return non-zero for success and zero for fail, some use the opposite convention.
 
* If a program is displaying a message box when it fails, and you don't know what is causing the problem, try performing a +relay,+msgbox trace. Then open the debug log in your favourite editor or text viewer (less is quite good) and search for trace:msgbox. Look at the relay data before the MessageBox API call, although the problem may not be caused by a call that happens ''immediately'' before the error. Keep an eye out for failing API calls in particular, and remember that there's little consistency in the Windows API as to what return codes mean. You just have to get used to what the specific API uses, and while many return non-zero for success and zero for fail, some use the opposite convention.
  
* If a program fails at startup with nothing to suggest why, you can use an +all trace. If your program seems to be failing a long way from an API call, you might also try [:Disassembly: disassembling] it to see if it's accessing some of the parameters passed in to !WinMain (for instance, [http://bugs.winehq.org/show_bug.cgi?id=3542 Dungeon Keeper crashes] if you run it without an absolute path for argv[0]).
+
* If a program fails at startup with nothing to suggest why, you can use an +all trace. If your program seems to be failing a long way from an API call, you might also try [Disassembly disassembling] it to see if it's accessing some of the parameters passed in to its entry point (for instance, [http://bugs.winehq.org/show_bug.cgi?id=3542 Dungeon Keeper crashes] if you run it without an absolute path for argv[0]).
 
+
* If your logs are becoming too big to work with, try applying the [:Debug_trace_toggle_key: debug delay patch]. It lets you toggle logging on and off with the F12 key and also control the debug channels from within the source by using the libwine APIs.
+
  
 
=== Making +relay less verbose ===
 
=== Making +relay less verbose ===
Line 170: Line 80:
  
 
[HKEY_CURRENT_USER\Software\Wine\Debug]
 
[HKEY_CURRENT_USER\Software\Wine\Debug]
"RelayExclude"="ntdll.RtlEnterCriticalSection;ntdll.RtlLeaveCriticalSection;kernel32.48;kernel32.49;kernel32.94;kernel32.95;kernel32.96;kernel32.97;kernel32.98;$freq"
+
"RelayExclude"="ntdll.RtlEnterCriticalSection;ntdll.RtlTryEnterCriticalSection;ntdll.RtlLeaveCriticalSection;kernel32.48;kernel32.49;kernel32.94;kernel32.95;kernel32.96;kernel32.97;kernel32.98;kernel32.TlsGetValue;kernel32.TlsSetValue;kernel32.FlsGetValue;kernel32.FlsSetValue;kernel32.SetLastError;$freq"
  
 
_EOF
 
_EOF
Line 181: Line 91:
 
* [[Wine_User's_Guide#WINEDEBUG=channels|Environment Variables: WINEDEBUG]] - chapter of the [[Wine User's Guide]]
 
* [[Wine_User's_Guide#WINEDEBUG=channels|Environment Variables: WINEDEBUG]] - chapter of the [[Wine User's Guide]]
 
* [http://source.winehq.org/WineAPI/ WineAPI documentation] - For each function the used debug channels are listed.
 
* [http://source.winehq.org/WineAPI/ WineAPI documentation] - For each function the used debug channels are listed.
* [http://bugs.winehq.org/show_bug.cgi?id=638 Bug 638] - Bug tracking documenting the debugging channel. Has a perl script to list all channels in a function.
 
 
----
 
----
 
[[Category:Quality Assurance]]  
 
[[Category:Quality Assurance]]  
  
 
[[Category:Development]]
 
[[Category:Development]]

Latest revision as of 16:11, 15 June 2019

Translations of this page: not yet ported. Translators, please see the discussion page.

WINEDEBUG is an environment variable that turns debugging messages on or off.

Syntax

WINEDEBUG=[class][+/-]channel[,[class2][+/-]channel2]

class is optional and can be one of the following: trace, warn, err, or fixme. These are ordered roughly from least to most severe. trace is used for code paths that occur as part of normal operation. warn is generally used for code paths that may cause failures, but are likely to be well-handled by a higher-level component. err is used for code paths that are likely to cause failures. fixme is used for code paths that are unimplemented in Wine. By default, only err and fixme are enabled. If a channel is specified without a class, all classes are enabled.

Each channel will print messages about a particular component of Wine. The following character can be either + or - to switch the specified channel on or off respectively. If there is no class part before it, a leading + can be omitted. Note that spaces are not allowed any where in the string.

channel specifies which debug channel to turn on or off. For complete list of channels run this command in the source directory:

grep -r --include='*.c' --include='*.h' 'WINE_\(DEFAULT\|DECLARE\)_DEBUG_CHANNEL' dlls/ programs/

And with some more work we have sorted and formatted list in BASH (you may want to adjust number 26 near the end of this composite to match your indentation taste):

for modname in $(find dlls/ programs/ -mindepth 1 -type d | sort); do
  echo $(grep -rE --include='*.[ch]' '^WINE_(DEFAULT|DECLARE)_DEBUG_CHANNEL' $modname \
         | awk -F "[()]" '{print $2}' | sort | uniq) \
         | awk -v modname=$modname '{if (NF>0) printf("%-*s%s\n", 26, modname": ", $0)}';
done

Examples

WINEDEBUG=warn+all
will turn on WARN messages for all channels, in addition to already enabled ERR and FIXME messages.
WINEDEBUG=fixme-all,warn+cursor,+relay
will turn off all FIXME messages, turn on cursor WARN messages (in addition to ERR and FIXME messages), and turn on all relay messages (API calls).
WINEDEBUG=+relay
will turn on all relay messages. For more control on including or excluding functions and dlls from the relay trace look into the [HKCU\Software\Wine\Debug] registry key (See Useful Registry Keys and the example below).
WINEDEBUG=-d3d
will turn off all d3d messages, and additionally disable checking for GL errors after operations. This may improve performance.

Useful Channels

Some of the debug channels can be particularly useful:

  • +all : logs everything, probably gives too much information in most cases, but may come in handy for subtle issues
  • +heap : traces all heap activity in the program and switches on constant integrity checks. If an app is trashing the heap, doing a +relay,+heap trace will let you narrow down exactly where it's happening. If an inconsistency is detected, Wine will dump the contents of the heap and terminate the program. Although many things can lead to trashing the heap, the most common is Wine overrunning an internal buffer. Be sure to remember this channel; all Wine code uses the HeapAlloc/HeapFree APIs internally, and a primary reason is that Wine's built in heap debugging is so useful. Be warned that +heap can make a program extremely slow, and generate very large log files. If you're concerned that Wine may be corrupting the heap but are not sure, warn+heap will enable heap validation but will not trace every allocation and free.
  • +loaddll : reports each DLL as it is loaded.
  • +message : logs all window messages dispatched to the window procedure, in a manner similar to +relay. Use +msg to trace calls to individual messaging-related APIs.
  • +msgbox : logs the contents of any calls to MessageBox(). Many programs display crash information using MessageBox(), so this can be a quick way to gather that information in a usable form.
  • +pid : prefixes each debug output line with the ID of the process that generated it. This can be helpful when debugging multiprocess applications.
  • +relay : logs every call that crosses the DLL boundary of Wine's built-in modules, including calls between (non-native) DLLs. This channel is often the first port of call when you have no idea what's going wrong. It shows you each call into and out of Wine modules at the DLL boundaries. If you're being overwhelmed by certain functions, look into setting the RelayInclude and RelayExclude strings in the Wine registry (under [HKCU\Software\Wine\Debug]). Note that this string is already pre-populated with some functions which are frequently called but don't usually give any clues as to why a program might be failing. Never use +relay or +snoop with native DLLs! This will show you the implementation of those DLLs, which means that any code you write to implement them violates our clean room reverse-engineering rules.
  • +seh : logs Windows exceptions (Structured Exception Handling). These are invoked either when an application performs an illegal operation (i.e. crashes), or if a program throws its own exceptions. Wine converts UNIX signals into SEH exceptions and outputs them using this channel. This can be useful because applications will often trap their own crash, in order to perform an emergency save for instance. The most common exception to watch for is STATUS_ACCESS_VIOLATION or 0xC0000005 which is the closest equivalent in Win32 to a segfault. You may also see codes which don't appear in the headers; these are typically language-specific exceptions used by whichever compiler was used to produce the EXE. E.g. 0xEEDFADE is the code for a Delphi internal exception, and 0xE06D7363 is a Microsoft Visual C++ exception, which has a magic value (info[0]) of 0x19930520, which is easy to remember because it looks like a date (and probably is). If you see any of these exceptions, it may mean a Win32 API call returned a non-zero error code somewhere.
  • +server : shows each wineserver RPC. You don't normally need this but it may prove helpful when debugging wineserver issues.
  • +snoop : logs every function call between native DLLs. This is similar to +relay but works between two native DLLs, although this channel provides poorer information because parameters aren't reported. +snoop may also break or destabilize an application as it inspects the stack and disassembles function prologues to try and guess parameters. Never use +relay or +snoop with native DLLs! This will show you the implementation of those DLLs, which means that any code you write to implement them violates our clean room reverse-engineering rules.
  • +synchronous : forces X11 into synchronous mode
  • +timestamp: prefixes each debug output line with the timestamp when that line executed. This is invaluable for debugging performance issue.
  • +fps: prints the number of frames per second in the terminal for OpenGL, D3D, or Vulkan applications.

Other Debugging Tips

  • If a program is displaying a message box when it fails, and you don't know what is causing the problem, try performing a +relay,+msgbox trace. Then open the debug log in your favourite editor or text viewer (less is quite good) and search for trace:msgbox. Look at the relay data before the MessageBox API call, although the problem may not be caused by a call that happens immediately before the error. Keep an eye out for failing API calls in particular, and remember that there's little consistency in the Windows API as to what return codes mean. You just have to get used to what the specific API uses, and while many return non-zero for success and zero for fail, some use the opposite convention.
  • If a program fails at startup with nothing to suggest why, you can use an +all trace. If your program seems to be failing a long way from an API call, you might also try [Disassembly disassembling] it to see if it's accessing some of the parameters passed in to its entry point (for instance, Dungeon Keeper crashes if you run it without an absolute path for argv[0]).

Making +relay less verbose

If you're looking for a problem that happens a couple minutes into the run of an app, +relay can be too verbose. In that case, run it once, then send the log through a script like

# Make grep go fast
LANG=C
# Find top ten calls
freq=`grep ':Ret ' | sed 's/(.*//;s/.* //' | sort | uniq -c | sort -n | tail | awk '{print $2}' | tr '\012' ';'`
cat > quiet.reg << _EOF
REGEDIT4

[HKEY_CURRENT_USER\Software\Wine\Debug]
"RelayExclude"="ntdll.RtlEnterCriticalSection;ntdll.RtlTryEnterCriticalSection;ntdll.RtlLeaveCriticalSection;kernel32.48;kernel32.49;kernel32.94;kernel32.95;kernel32.96;kernel32.97;kernel32.98;kernel32.TlsGetValue;kernel32.TlsSetValue;kernel32.FlsGetValue;kernel32.FlsSetValue;kernel32.SetLastError;$freq"

_EOF

wine regedit quiet.reg

This will tell Wine to not log the ten most frequent calls in your app, which should make your +relay log much more managable in size.

See Also