mirror of
git://source.winehq.org/git/wine.git
synced 2024-10-31 12:19:49 +00:00
495 lines
16 KiB
Text
495 lines
16 KiB
Text
<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 cannot 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:
|
|
-->
|