| <chapter id="debugging"> | |
| <title>Debug Logging</title> | |
| <para> | |
| To better manage the large volume of debugging messages that | |
| Wine can generate, we divide the messages on a component basis, | |
| and classify them based on the severity of the reported problem. | |
| Therefore a message belongs to a <emphasis>channel</emphasis> | |
| and a <emphasis>class</emphasis> respectively. | |
| </para> | |
| <para> | |
| This section will describe the debugging classes, how you can | |
| create a new debugging channel, what the debugging API is, | |
| and how you can control the debugging output. A picture is | |
| worth a thousand words, so here are a few examples of the | |
| debugging API in action: | |
| <screen> | |
| ERR("lock_count == 0 ... please report\n"); | |
| FIXME("Unsupported RTL style!\n"); | |
| WARN(": file seems to be truncated!\n"); | |
| TRACE("[%p]: new horz extent = %d\n", hwnd, extent ); | |
| MESSAGE( "Could not create graphics driver '%s'\n", buffer ); | |
| </screen> | |
| </para> | |
| <sect1 id="dbg-classes"> | |
| <title>Debugging classes</title> | |
| <para> | |
| A debugging class categorizes a message based on the severity | |
| of the reported problem. There is a fixed set of classes, and | |
| you must carefully choose the appropriate one for your messages. | |
| There are five classes of messages: | |
| </para> | |
| <variablelist> | |
| <varlistentry> | |
| <term><literal>FIXME</literal></term> | |
| <listitem> | |
| <para> | |
| Messages in this class are meant to signal unimplemented | |
| features, known bugs, etc. They serve as a constant and | |
| active reminder of what needs to be done. | |
| </para> | |
| </listitem> | |
| </varlistentry> | |
| <varlistentry> | |
| <term><literal>ERR</literal></term> | |
| <listitem> | |
| <para> | |
| Messages in this class indicate serious errors in | |
| Wine, such as as conditions that should never happen | |
| by design. | |
| </para> | |
| </listitem> | |
| </varlistentry> | |
| <varlistentry> | |
| <term><literal>WARN</literal></term> | |
| <listitem> | |
| <para> | |
| These are warning messages. You should report a | |
| warning when something unwanted happens, and the | |
| function can not deal with the condition. This | |
| is seldomly used since proper functions can usually | |
| report failures back to the caller. Think twice before | |
| making the message a warning. | |
| </para> | |
| </listitem> | |
| </varlistentry> | |
| <varlistentry> | |
| <term><literal>TRACE</literal></term> | |
| <listitem> | |
| <para> | |
| These are detailed debugging messages that are mainly | |
| useful to debug a component. These are turned off unless | |
| explicitly enabled. | |
| </para> | |
| </listitem> | |
| </varlistentry> | |
| <varlistentry> | |
| <term><literal>MESSAGE</literal></term> | |
| <listitem> | |
| <para> | |
| There messages are intended for the end user. They do not | |
| belong to any channel. As with warnings, you will seldomly | |
| need to output such messages. | |
| </para> | |
| </listitem> | |
| </varlistentry> | |
| </variablelist> | |
| </sect1> | |
| <sect1 id="dbg-channels"> | |
| <title>Debugging channels</title> | |
| <para> | |
| Each component is assigned a debugging channel. The | |
| identifier of the channel must be a valid C identifier | |
| (reserved word like <type>int</type> or <type>static</type> | |
| are premitted). To use a new channel, simply use it in | |
| your code. It will be picked up automatically by the build process. | |
| </para> | |
| <para> | |
| Typically, a file contains code pertaining to only one component, | |
| and as such, there is only one channel to output to. You can declare | |
| a default chanel for the file using the | |
| <symbol>WINE_DEFAULT_DEBUG_CHANNEL()</symbol> macro: | |
| <programlisting> | |
| #include "wine/debug.h" | |
| WINE_DEFAULT_DEBUG_CHANNEL(xxx); | |
| ... | |
| FIXME("some unimplemented feature", ...); | |
| ... | |
| if (zero != 0) | |
| ERR("This should never be non-null: %d", zero); | |
| ... | |
| </programlisting> | |
| </para> | |
| <para> | |
| In rare situations there is a need to output to more than one | |
| debug channel per file. In such cases, you need to declare | |
| all the additional channels at the top of the file, and | |
| use the _-version of the debugging macros: | |
| <programlisting> | |
| #include "wine/debug.h" | |
| WINE_DEFAULT_DEBUG_CHANNEL(xxx); | |
| WINE_DECLARE_DEBUG_CHANNEL(yyy); | |
| WINE_DECLARE_DEBUG_CHANNEL(zzz); | |
| ... | |
| FIXME("this one goes to xxx channel"); | |
| ... | |
| FIXME_(yyy)("Some other msg for the yyy channel"); | |
| ... | |
| WARN_(zzz)("And yet another msg on another channel!"); | |
| ... | |
| </programlisting> | |
| </para> | |
| </sect1> | |
| <sect1 id="dbg-checking"> | |
| <title>Are we debugging?</title> | |
| <para> | |
| To test whether the debugging channel <literal>xxx</literal> is | |
| enabled, use the <symbol>TRACE_ON</symbol>, <symbol>WARN_ON</symbol>, | |
| <symbol>FIXME_ON</symbol>, or <symbol>ERR_ON</symbol> macros. For | |
| example: | |
| <programlisting> | |
| if(TRACE_ON(atom)){ | |
| ...blah... | |
| } | |
| </programlisting> | |
| You should normally need to test only if <literal>TRACE_ON</literal>, | |
| all the others are very seldomly used. With careful coding, you | |
| can avoid the use of these macros, which is generally desired. | |
| </para> | |
| </sect1> | |
| <sect1 id="dbg-helpers"> | |
| <title>Helper functions</title> | |
| <para> | |
| Resource identifiers can be either strings or numbers. To | |
| make life a bit easier for outputting these beasts (and to | |
| help you avoid the need to build the message in memory), I | |
| introduced a new function called <function>debugres</function>. | |
| </para> | |
| <para> | |
| The function is defined in <filename>wine/debug.h</filename> | |
| and has the following prototype: | |
| </para> | |
| <programlisting> | |
| LPSTR debugres(const void *id); | |
| </programlisting> | |
| <para> | |
| It takes a pointer to the resource id and returns a nicely | |
| formatted string of the identifier (which can be a string or | |
| a number, depending on the value of the high word). | |
| Numbers are formatted as such: | |
| </para> | |
| <programlisting> | |
| #xxxx | |
| </programlisting> | |
| <para> | |
| while strings as: | |
| </para> | |
| <programlisting> | |
| 'some-string' | |
| </programlisting> | |
| <para> | |
| Simply use it in your code like this: | |
| </para> | |
| <programlisting> | |
| #include "wine/debug.h" | |
| ... | |
| TRACE("resource is %s", debugres(myresource)); | |
| </programlisting> | |
| <para> | |
| Many times strings need to be massaged before output: | |
| they may be <literal>NULL</literal>, contain control | |
| characters, or they may be too long. Similarly, Unicode | |
| strings need to be converted to ASCII for usage with | |
| the debugging API. For all this, you can use the | |
| <function>debugstr_[aw]n?</function> familly of functions: | |
| <programlisting> | |
| HANDLE32 WINAPI YourFunc(LPCSTR s) | |
| { | |
| FIXME("(%s): stub\n", debugstr_a(s)); | |
| } | |
| </programlisting> | |
| </para> | |
| </sect1> | |
| <sect1 id="dbg-control"> | |
| <title>Controlling the debugging output</title> | |
| <para> | |
| It is possible to turn on and off debugging output from | |
| within the debugger using the set command. Please see the | |
| WineDbg Command Reference section | |
| (<xref linkend="winedbg-dbg-chan">) for how to do this. | |
| </para> | |
| <para> | |
| You can do the same using the task manager | |
| (<command>taskmgr</command>) and selecting your application in | |
| the application list. Right clicking on the application, and | |
| selecting the debug option in the popup menu, will let you | |
| select the modifications you want on the debug channels. | |
| </para> | |
| <para> | |
| Another way to conditionally log debug output (e.g. in case of | |
| very large installers which may create gigabytes of log | |
| output) is to create a pipe: | |
| </para> | |
| <screen> | |
| <prompt>$</prompt> <userinput>mknod /tmp/debug_pipe p</userinput> | |
| </screen> | |
| <para> | |
| and then to run wine like that: | |
| </para> | |
| <screen> | |
| <prompt>$</prompt> <userinput>WINEDEBUG=+relay,+snoop wine setup.exe &>/tmp/debug_pipe</userinput> | |
| </screen> | |
| <para> | |
| Since the pipe is initially blocking (and thus wine as a whole), | |
| you have to activate it by doing: | |
| </para> | |
| <screen> | |
| <prompt>$</prompt> <userinput>cat /tmp/debug_pipe</userinput> | |
| </screen> | |
| <para> | |
| (press Ctrl-C to stop pasting the pipe content) | |
| </para> | |
| <para> | |
| Once you are about to approach the problematic part of the program, | |
| you just do: | |
| </para> | |
| <screen> | |
| <prompt>$</prompt> <userinput>cat /tmp/debug_pipe >/tmp/wine.log</userinput> | |
| </screen> | |
| <para> | |
| to capture specifically the part that interests you from the | |
| pipe without wasting excessive amounts of HDD space and | |
| slowing down installation considerably. | |
| </para> | |
| <para> | |
| The <parameter>WINEDEBUG</parameter> environment variable | |
| controls the output of the debug messages. | |
| It has the following syntax: | |
| <parameter>WINEDEBUG= [yyy]#xxx[,[yyy1]#xxx1]*</parameter> | |
| </para> | |
| <itemizedlist> | |
| <listitem> | |
| <para> | |
| where | |
| <literal>#</literal> is either <literal>+</literal> or | |
| <literal>-</literal> | |
| </para> | |
| </listitem> | |
| <listitem> | |
| <para> | |
| when the optional class argument (<literal>yyy</literal>) | |
| is not present, then the statement will | |
| enable(<literal>+</literal>)/disable(<literal>-</literal>) | |
| all messages for the given channel (<literal>xxx</literal>) | |
| on all classes. For example: | |
| </para> | |
| <programlisting> | |
| WINEDEBUG=+reg,-file | |
| </programlisting> | |
| <para> | |
| enables all messages on the <literal>reg</literal> | |
| channel and disables all messages on the | |
| <literal>file</literal> channel. | |
| </para> | |
| </listitem> | |
| <listitem> | |
| <para> | |
| when the optional class argument (<literal>yyy</literal>) | |
| is present, then the statement will enable | |
| (<literal>+</literal>)/disable(<literal>-</literal>) | |
| messages for the given channel (<literal>xxx</literal>) | |
| only on the given class. For example: | |
| </para> | |
| <programlisting> | |
| WINEDEBUG=trace+reg,warn-file | |
| </programlisting> | |
| <para> | |
| enables trace messages on the <literal>reg</literal> | |
| channel and disables warning messages on the | |
| <literal>file</literal> channel. | |
| </para> | |
| </listitem> | |
| <listitem> | |
| <para> | |
| also, the pseudo-channel all is also supported and it | |
| has the intuitive semantics: | |
| </para> | |
| <screen> | |
| WINEDEBUG=+all -- enables all debug messages | |
| WINEDEBUG=-all -- disables all debug messages | |
| WINEDEBUG=yyy+all -- enables debug messages for class yyy on all | |
| channels. | |
| WINEDEBUG=yyy-all -- disables debug messages for class yyy on all | |
| channels. | |
| </screen> | |
| <para> | |
| So, for example: | |
| </para> | |
| <screen> | |
| WINEDEBUG=warn-all -- disables all warning messages. | |
| </screen> | |
| </listitem> | |
| </itemizedlist> | |
| <para> | |
| Also, note that at the moment: | |
| </para> | |
| <itemizedlist> | |
| <listitem> | |
| <para> | |
| the <literal>FIXME</literal> and <literal>ERR</literal> | |
| classes are enabled by default | |
| </para> | |
| </listitem> | |
| <listitem> | |
| <para> | |
| the <literal>TRACE</literal> and <literal>WARN</literal> | |
| classes are disabled by default | |
| </para> | |
| </listitem> | |
| </itemizedlist> | |
| </sect1> | |
| <sect1 id="dbg-compiling"> | |
| <title>Compiling Out Debugging Messages</title> | |
| <para> | |
| To compile out the debugging messages, provide | |
| <command>configure</command> with the following options: | |
| </para> | |
| <screen> | |
| --disable-debug -- turns off TRACE, WARN, and FIXME (and DUMP). | |
| --disable-trace -- turns off TRACE only. | |
| </screen> | |
| <para> | |
| This will result in an executable that, when stripped, is | |
| about 15%-20% smaller. Note, however, that you will not be | |
| able to effectively debug Wine without these messages. | |
| </para> | |
| <para> | |
| This feature has not been extensively tested--it may subtly | |
| break some things. | |
| </para> | |
| </sect1> | |
| <sect1 id="dbg-notes"> | |
| <title>A Few Notes on Style</title> | |
| <para> | |
| This new scheme makes certain things more consistent but | |
| there is still room for improvement by using a common style | |
| of debug messages. Before I continue, let me note that the | |
| output format is the following: | |
| </para> | |
| <screen> | |
| yyy:xxx:fff <message> | |
| where: | |
| yyy = the class (fixme, err, warn, trace) | |
| xxx = the channel (atom, win, font, etc) | |
| fff = the function name | |
| </screen> | |
| <para> | |
| these fields are output automatically. All you have to | |
| provide is the <message> part. | |
| </para> | |
| <para> | |
| So here are some ideas: | |
| </para> | |
| <itemizedlist> | |
| <listitem> | |
| <para> | |
| do not include the name of the function: it is included automatically | |
| </para> | |
| </listitem> | |
| <listitem> | |
| <para> | |
| if you want to output the parameters of the function, do | |
| it as the first thing and include them in parentheses, | |
| like this: | |
| <programlisting> | |
| TRACE("(%d, %p, ...)\n", par1, par2, ...); | |
| </programlisting> | |
| </para> | |
| </listitem> | |
| <listitem> | |
| <para> | |
| if you want to name a parameter, use <literal>=</literal> : | |
| <programlisting> | |
| TRACE("(fd=%d, file=%s): stub\n", fd, name); | |
| </programlisting> | |
| </para> | |
| </listitem> | |
| <listitem> | |
| <para> | |
| for stubs, you should output a <literal>FIXME</literal> | |
| message. I suggest this style: | |
| <programlisting> | |
| FIXME("(%x, %d, ...): stub\n", par1, par2, ...); | |
| </programlisting> | |
| </para> | |
| </listitem> | |
| <listitem> | |
| <para> | |
| try to output one line per message. That is, the format | |
| string should contain only one <literal>\n</literal> and it | |
| should always appear at the end of the string. | |
| </para> | |
| </listitem> | |
| <listitem> | |
| <para> | |
| if the output string needs to be dynamically constructed, | |
| render it in memory before outputting it: | |
| <programlisting> | |
| char buffer[128] = ""; | |
| if (flags & FLAG_A) strcat(buffer, "FLAG_A "); | |
| if (flags & FLAG_B) strcat(buffer, "FLAG_B "); | |
| if (flags & FLAG_C) strcat(buffer, "FLAG_C "); | |
| TRACE("flags = %s\n", buffer); | |
| </programlisting> | |
| Most of the time however, it is better to create a helper | |
| function that renders to a temporary buffer: | |
| <programlisting> | |
| static const char *dbgstr_flags(int flags) | |
| { | |
| char buffer[128] = ""; | |
| if (flags & FLAG_A) strcat(buffer, "FLAG_A "); | |
| if (flags & FLAG_B) strcat(buffer, "FLAG_B "); | |
| if (flags & FLAG_C) strcat(buffer, "FLAG_C "); | |
| return wine_dbg_sprintf("flags = %s\n\n", buffer); | |
| } | |
| ... | |
| TRACE("flags = %s\n", dbgstr_flags(flags)); | |
| </programlisting> | |
| </para> | |
| </listitem> | |
| </itemizedlist> | |
| </sect1> | |
| </chapter> | |
| <!-- Keep this comment at the end of the file | |
| Local variables: | |
| mode: sgml | |
| sgml-parent-document:("wine-devel.sgml" "set" "book" "part" "chapter" "") | |
| End: | |
| --> |