2000-08-08 03:24:00 +02:00
|
|
|
<chapter id="debugger">
|
|
|
|
<title>The Wine Debugger</title>
|
|
|
|
|
|
|
|
<sect1 id="dbg-intro">
|
|
|
|
<title>I Introduction</title>
|
|
|
|
|
|
|
|
<para>
|
2000-08-15 14:00:52 +02:00
|
|
|
written by Eric Pouech (Last updated: 8/15/2000)
|
2000-08-08 03:24:00 +02:00
|
|
|
</para>
|
|
|
|
<para>
|
|
|
|
(Extracted from <filename>wine/documentation/winedbg</filename>)
|
|
|
|
</para>
|
|
|
|
|
|
|
|
<sect2>
|
|
|
|
<title>I.1 Processes and threads: in underlying OS and in Windows</title>
|
|
|
|
|
|
|
|
<para>
|
|
|
|
Before going into the depths of debugging in Wine, here's
|
|
|
|
a small overview of process and thread handling in Wine.
|
|
|
|
It has to be clear that there are two different beasts:
|
|
|
|
processes/threads from the Unix point of view and
|
|
|
|
processes/threads from a Windows point of view.
|
|
|
|
</para>
|
|
|
|
<para>
|
|
|
|
Each Windows' thread is implemented as a Unix process (under
|
|
|
|
Linux using the <function>clone</function> syscall), meaning
|
|
|
|
that all threads of a same Windows' process share the same
|
|
|
|
(unix) address space.
|
|
|
|
</para>
|
|
|
|
<para>
|
|
|
|
In the following:
|
|
|
|
</para>
|
|
|
|
<itemizedlist>
|
|
|
|
<listitem>
|
|
|
|
<para><varname>W-process</varname> means a process in Windows' terminology</para>
|
|
|
|
</listitem>
|
|
|
|
<listitem>
|
|
|
|
<para><varname>U-process</varname> means a process in Unix' terminology</para>
|
|
|
|
</listitem>
|
|
|
|
<listitem>
|
|
|
|
<para><varname>W-thread</varname> means a thread in Windows' terminology</para>
|
|
|
|
</listitem>
|
|
|
|
</itemizedlist>
|
|
|
|
<para>
|
|
|
|
A <varname>W-process</varname> is made of one or several
|
|
|
|
<varname>W-threads</varname>. Each
|
|
|
|
<varname>W-thread</varname> is mapped to one and only one
|
|
|
|
<varname>U-process</varname>. All
|
|
|
|
<varname>U-processes</varname> of a same
|
|
|
|
<varname>W-process</varname> share the same address space.
|
|
|
|
</para>
|
|
|
|
<para>
|
|
|
|
Each Unix process can be identified by two values:
|
|
|
|
</para>
|
|
|
|
<itemizedlist>
|
|
|
|
<listitem>
|
|
|
|
<para>the Unix process id (<varname>upid</varname> in the following)</para>
|
|
|
|
</listitem>
|
|
|
|
<listitem>
|
|
|
|
<para>the Windows's thread id (<varname>tid</varname>)</para>
|
|
|
|
</listitem>
|
|
|
|
</itemizedlist>
|
|
|
|
<para>
|
|
|
|
Each Windows' process has also a Windows' process id
|
|
|
|
(<varname>wpid</varname> in the following). It must be clear
|
|
|
|
that <varname>upid</varname> and <varname>wpid</varname> are
|
|
|
|
different and shall not be used instead of the other.
|
|
|
|
</para>
|
|
|
|
<para>
|
|
|
|
<varname>Wpid</varname> and <varname>tid</varname> are
|
|
|
|
defined (Windows) system wide. They must not be confused
|
|
|
|
with process or thread handles which, as any handle, is an
|
|
|
|
indirection to a system object (in this case process or
|
|
|
|
thread). A same process can have several different handles
|
|
|
|
on the same kernel object. The handles can be defined as
|
|
|
|
local (the values is only valid in a process), or system
|
|
|
|
wide (the same handle can be used by any
|
|
|
|
<varname>W-process</varname>).
|
|
|
|
</para>
|
|
|
|
</sect2>
|
|
|
|
|
|
|
|
<sect2>
|
|
|
|
<title>I.2 Wine, debugging and WineDbg</title>
|
|
|
|
|
|
|
|
<para>
|
|
|
|
When talking of debugging in Wine, there are at least two
|
|
|
|
levels to think of:
|
|
|
|
</para>
|
|
|
|
<itemizedlist>
|
|
|
|
<listitem>
|
|
|
|
<para>the Windows' debugging API.</para>
|
|
|
|
</listitem>
|
|
|
|
<listitem>
|
|
|
|
<para>the Wine integrated debugger, dubbed
|
|
|
|
<command>WineDbg</command>.</para>
|
|
|
|
</listitem>
|
|
|
|
</itemizedlist>
|
|
|
|
<para>
|
|
|
|
Wine implements most the the Windows' debugging API (the
|
|
|
|
part in KERNEL32, not the one in
|
|
|
|
<filename>IMAGEHLP.DLL</filename>), and allows any program
|
|
|
|
(emulated or WineLib) using that API to debug a
|
|
|
|
<varname>W-process</varname>.
|
|
|
|
</para>
|
|
|
|
<para>
|
|
|
|
<command>WineDbg</command> is a WineLib application making
|
|
|
|
use of this API to allow debugging both any Wine or WineLib
|
|
|
|
applications as well as Wine itself (kernel and all DLLs).
|
|
|
|
</para>
|
2000-08-15 14:00:52 +02:00
|
|
|
<para>
|
|
|
|
<command>WineDbg</command> understands symbolic information
|
|
|
|
from both Unix world (mainly ELF stabs) and from Windows
|
|
|
|
(most Microsoft debugging formats are supported - CodeView,
|
|
|
|
.DBG files...)
|
|
|
|
</para>
|
2000-08-08 03:24:00 +02:00
|
|
|
</sect2>
|
|
|
|
</sect1>
|
|
|
|
|
|
|
|
<sect1 id="dbg-modes">
|
|
|
|
<title>II WineDbg's modes of invocation</title>
|
|
|
|
|
|
|
|
<sect2>
|
|
|
|
<title>II.1 Starting a process</title>
|
|
|
|
|
|
|
|
<para>
|
|
|
|
Any application (either a Windows' native executable, or a
|
|
|
|
WineLib application) can be run through
|
|
|
|
<command>WineDbg</command>. Command line options and tricks
|
|
|
|
are the same as for wine:
|
|
|
|
</para>
|
|
|
|
<screen>
|
|
|
|
winedbg telnet.exe
|
|
|
|
winedbg "hl.exe -windowed"
|
|
|
|
</screen>
|
|
|
|
</sect2>
|
|
|
|
|
|
|
|
<sect2>
|
|
|
|
<title>II.2 Attaching</title>
|
|
|
|
|
|
|
|
<para>
|
|
|
|
<command>WineDbg</command> can also be launched without any
|
|
|
|
command line argument: <command>WineDbg</command> is started
|
|
|
|
without any attached process. You can get a list of running
|
|
|
|
<varname>W-processes</varname> (and their
|
|
|
|
<varname>wpid</varname>'s) using the <command>walk
|
|
|
|
process</command> command, and then, with the
|
|
|
|
<command>attach</command> command, pick up the
|
|
|
|
<varname>wpid</varname> of the <varname>W-process</varname>
|
|
|
|
you want to debug. This is (for now) a neat feature for the
|
|
|
|
following reasons:
|
|
|
|
</para>
|
|
|
|
<itemizedlist>
|
|
|
|
<listitem>
|
|
|
|
<para>you can debug an already started application</para>
|
|
|
|
</listitem>
|
|
|
|
</itemizedlist>
|
|
|
|
</sect2>
|
|
|
|
|
|
|
|
<sect2>
|
|
|
|
<title>II.3 On exception</title>
|
|
|
|
|
|
|
|
<para>
|
|
|
|
When something goes wrong, Windows tracks this as an
|
|
|
|
exception. Exceptions exist for segmentation violation,
|
|
|
|
stack overflow, division by zero...
|
|
|
|
</para>
|
|
|
|
<para>
|
|
|
|
When an exception occurs, Wine checks if the <varname>W-process</varname> is
|
|
|
|
debugged. If so, the exception event is sent to the
|
|
|
|
debugger, which takes care of it: end of the story. This
|
|
|
|
mechanism is part of the standard Windows' debugging API.
|
|
|
|
</para>
|
|
|
|
<para>
|
|
|
|
If the <varname>W-process</varname> is not debugged, Wine
|
|
|
|
tries to launch a debugger. This debugger (normally
|
|
|
|
<command>WineDbg</command>, see III Configuration for more
|
|
|
|
details), at startup, attaches to the
|
|
|
|
<varname>W-process</varname> which generated the exception
|
|
|
|
event. In this case, you are able to look at the causes of
|
|
|
|
the exception, and either fix the causes (and continue
|
|
|
|
further the execution) or dig deeper to understand what went
|
|
|
|
wrong.
|
|
|
|
</para>
|
|
|
|
<para>
|
|
|
|
If <command>WineDbg</command> is the standard debugger, the
|
|
|
|
<command>pass</command> and <command>cont</command> commands
|
|
|
|
are the two ways to let the process go further for the
|
|
|
|
handling of the exception event.
|
|
|
|
</para>
|
|
|
|
<para>
|
|
|
|
To be more precise on the way Wine (and Windows) generates
|
|
|
|
exception events, when a fault occurs (segmentation
|
|
|
|
violation, stack overflow...), the event is first sent to
|
|
|
|
the debugger (this is known as a first chance exception).
|
|
|
|
The debugger can give two answers:
|
|
|
|
</para>
|
|
|
|
|
|
|
|
<variablelist>
|
|
|
|
<varlistentry>
|
|
|
|
<term>continue:</term>
|
|
|
|
<listitem>
|
|
|
|
<para>
|
|
|
|
the debugger had the ability to correct what's
|
|
|
|
generated the exception, and is now able to continue
|
|
|
|
process execution.
|
|
|
|
</para>
|
|
|
|
</listitem>
|
|
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
|
|
<term>pass:</term>
|
|
|
|
<listitem>
|
|
|
|
<para>
|
|
|
|
the debugger couldn't correct the cause of the
|
|
|
|
first chance exception. Wine will now try to walk
|
|
|
|
the list of exception handlers to see if one of them
|
|
|
|
can handle the exception. If no exception handler is
|
|
|
|
found, the exception is sent once again to the
|
|
|
|
debugger to indicate the failure of the exception
|
|
|
|
handling.
|
|
|
|
</para>
|
|
|
|
</listitem>
|
|
|
|
</varlistentry>
|
|
|
|
</variablelist>
|
|
|
|
<note>
|
|
|
|
<para>
|
|
|
|
since some of Wine's code uses exceptions and
|
|
|
|
<function>try/catch</function> blocks to provide some
|
|
|
|
functionality, <command>WineDbg</command> can be entered
|
|
|
|
in such cases with segv exceptions. This happens, for
|
|
|
|
example, with <function>IsBadReadPtr</function> function.
|
|
|
|
In that case, the <command>pass</command> command shall be
|
|
|
|
used, to let the handling of the exception to be done by
|
|
|
|
the <function>catch</function> block in
|
|
|
|
<function>IsBadReadPtr</function>.
|
|
|
|
</para>
|
|
|
|
</note>
|
|
|
|
</sect2>
|
|
|
|
|
|
|
|
<sect2>
|
|
|
|
<title>II.4 Quitting</title>
|
|
|
|
|
|
|
|
<para>
|
|
|
|
Unfortunately, Windows doesn't provide a detach kind of API,
|
|
|
|
meaning that once you started debugging a process, you must
|
|
|
|
do so until the process dies. Killing (or stopping/aborting)
|
|
|
|
the debugger will also kill the debugged process. This will
|
|
|
|
be true for any Windows' debugging API compliant debugger,
|
|
|
|
starting with <command>WineDbg</command>.
|
|
|
|
</para>
|
|
|
|
</sect2>
|
|
|
|
</sect1>
|
|
|
|
|
|
|
|
<sect1 id="dbg-config">
|
|
|
|
<title>III Configuration</title>
|
|
|
|
|
|
|
|
<sect2>
|
|
|
|
<title>III.1 Registry configuration</title>
|
|
|
|
|
|
|
|
<para>
|
|
|
|
The Windows' debugging API uses a registry entry to know
|
|
|
|
with debugger to invoke when an unhandled exception
|
|
|
|
occurs (see II.3 for some details). Two values in key
|
|
|
|
</para>
|
|
|
|
<programlisting>
|
|
|
|
"MACHINE\\Software\\Microsoft\\Windows NT\\CurrentVersion\\AeDebug"
|
|
|
|
</programlisting>
|
|
|
|
<para>
|
|
|
|
Determine the behavior:
|
|
|
|
</para>
|
|
|
|
<variablelist>
|
|
|
|
<varlistentry>
|
|
|
|
<term>Debugger:</term>
|
|
|
|
<listitem>
|
|
|
|
<para>
|
|
|
|
this is the command line used to launch the debugger
|
|
|
|
(it uses two <function>printf</function> formats
|
|
|
|
(<literal>%ld</literal>) to pass context dependent
|
|
|
|
information to the debugger). You should put here a
|
|
|
|
complete path to your debugger
|
|
|
|
(<command>WineDbg</command> can of course be used, but
|
|
|
|
any other Windows' debugging API aware debugger will
|
|
|
|
do).
|
|
|
|
</para>
|
|
|
|
</listitem>
|
|
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
|
|
<term>Auto:</term>
|
|
|
|
<listitem>
|
|
|
|
<para>
|
|
|
|
if this value is zero, a message box will ask the
|
|
|
|
user if he/she wishes to launch the debugger when an
|
|
|
|
unhandled exception occurs. Otherwise, the debugger
|
|
|
|
is automatically started.
|
|
|
|
</para>
|
|
|
|
</listitem>
|
|
|
|
</varlistentry>
|
|
|
|
</variablelist>
|
|
|
|
|
|
|
|
<para>
|
|
|
|
A regular Wine registry looks like:
|
|
|
|
</para>
|
|
|
|
<programlisting>
|
|
|
|
[MACHINE\\Software\\Microsoft\\Windows NT\\CurrentVersion\\AeDebug] 957636538
|
|
|
|
"Auto"=dword:00000001
|
|
|
|
"Debugger"="/usr/local/bin/winedbg %ld %ld"
|
|
|
|
</programlisting>
|
|
|
|
|
|
|
|
<note>
|
|
|
|
<title>Note 1</title>
|
|
|
|
<para>
|
|
|
|
creating this key is mandatory. Not doing so will not
|
|
|
|
fire the debugger when an exception occurs.
|
|
|
|
</para>
|
|
|
|
</note>
|
|
|
|
<note>
|
|
|
|
<title>Note 2</title>
|
|
|
|
<para>
|
|
|
|
<command>wineinstall</command> sets up this correctly.
|
|
|
|
However, due to some limitation of the registry installed,
|
|
|
|
if a previous Wine installation exists, it's safer to
|
|
|
|
remove the whole
|
|
|
|
</para>
|
|
|
|
<programlisting>
|
|
|
|
[MACHINE\\Software\\Microsoft\\Windows NT\\CurrentVersion\\AeDebug]
|
|
|
|
</programlisting>
|
|
|
|
<para>
|
|
|
|
key before running again <command>wineinstall</command> to
|
|
|
|
regenerate this key.
|
|
|
|
</para>
|
|
|
|
</note>
|
|
|
|
</sect2>
|
|
|
|
|
|
|
|
<sect2>
|
|
|
|
<title>III.2 WineDbg configuration</title>
|
|
|
|
|
|
|
|
<para>
|
|
|
|
<command>WineDbg</command> can be configured thru a number
|
|
|
|
of options. Those options are stored in the registry, on a
|
|
|
|
per user basis. The key is (in *my* registry)
|
|
|
|
</para>
|
|
|
|
<programlisting>
|
|
|
|
[eric\\Software\\Wine\\WineDbg]
|
|
|
|
</programlisting>
|
|
|
|
<para>
|
|
|
|
Those options can be read/written while inside
|
|
|
|
<command>WineDbg</command>, as part of the debugger
|
|
|
|
expressions. To refer to one of this option, its name must
|
|
|
|
be prefixed by a <literal>$</literal> sign. For example,
|
|
|
|
</para>
|
|
|
|
<programlisting>
|
|
|
|
set $BreakAllThreadsStartup = 1
|
|
|
|
</programlisting>
|
|
|
|
<para>
|
|
|
|
sets the option <varname>BreakAllThreadsStartup</varname> to
|
|
|
|
<literal>TRUE</literal>.
|
|
|
|
</para>
|
|
|
|
<para>
|
|
|
|
All the options are read from the registry when
|
|
|
|
<command>WineDbg</command> starts (if no corresponding value
|
|
|
|
is found, a default value is used), and are written back to
|
|
|
|
the registry when <command>WineDbg</command> exits (hence,
|
|
|
|
all modifications to those options are automatically saved
|
|
|
|
when <command>WineDbg</command> terminates).
|
|
|
|
</para>
|
|
|
|
<para>
|
|
|
|
Here's the list of all options:
|
|
|
|
</para>
|
|
|
|
|
|
|
|
<sect3>
|
|
|
|
<title>III.2.1 Controling when the debugger is entered</title>
|
|
|
|
|
|
|
|
<variablelist>
|
|
|
|
<varlistentry>
|
|
|
|
<term><varname>BreakAllThreadsStartup</varname></term>
|
|
|
|
<listitem>
|
|
|
|
<para>
|
|
|
|
Set to <literal>TRUE</literal> if at all threads
|
|
|
|
start-up the debugger stops set to
|
|
|
|
<literal>FALSE</literal> if only at the first thread
|
|
|
|
startup of a given process the debugger stops.
|
|
|
|
<literal>FALSE</literal> by default.
|
|
|
|
</para>
|
|
|
|
</listitem>
|
|
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
|
|
<term><varname>BreakOnCritSectTimeOut</varname></term>
|
|
|
|
<listitem>
|
|
|
|
<para>
|
|
|
|
Set to <literal>TRUE</literal> if the debugger stops
|
|
|
|
when a critical section times out (5 minutes);
|
|
|
|
<literal>TRUE</literal> by default.
|
|
|
|
</para>
|
|
|
|
</listitem>
|
|
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
|
|
<term><varname>BreakOnAttach</varname></term>
|
|
|
|
<listitem>
|
|
|
|
<para>
|
|
|
|
Set to <literal>TRUE</literal> if when
|
|
|
|
<command>WineDbg</command> attaches to an existing
|
|
|
|
process after an unhandled exception,
|
|
|
|
<command>WineDbg</command> shall be entered on the
|
|
|
|
first attach event. Since the attach event is
|
|
|
|
meaningless in the context of an exception event
|
|
|
|
(the next event which is the exception event is of
|
|
|
|
course relevant), that option is likely to be
|
|
|
|
<literal>FALSE</literal>.
|
|
|
|
</para>
|
|
|
|
</listitem>
|
|
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
|
|
<term><varname>BreakOnFirstChance</varname></term>
|
|
|
|
<listitem>
|
|
|
|
<para>
|
|
|
|
An exception can generate two debug events. The
|
|
|
|
first one is passed to the debugger (known as a
|
|
|
|
first chance) just after the exception. The debugger
|
|
|
|
can then decides either to resume execution (see
|
|
|
|
<command>WineDbg</command>'s <command>cont</command>
|
|
|
|
command) or pass the exception up to the exception
|
|
|
|
handler chain in the program (if it exists)
|
|
|
|
(<command>WineDbg</command> implements this thru the
|
|
|
|
<command>pass</command> command). If none of the
|
|
|
|
exception handlers takes care of the exception, the
|
|
|
|
exception event is sent again to the debugger (known
|
|
|
|
as last chance exception). You cannot pass on a last
|
|
|
|
exception. When the
|
|
|
|
<varname>BreakOnFirstChance</varname> exception is
|
|
|
|
<literal>TRUE</literal>, then winedbg is entered for
|
|
|
|
both first and last chance execptions (to
|
|
|
|
<literal>FALSE</literal>, it's only entered for last
|
|
|
|
chance exceptions).
|
|
|
|
</para>
|
|
|
|
</listitem>
|
|
|
|
</varlistentry>
|
|
|
|
</variablelist>
|
|
|
|
</sect3>
|
|
|
|
|
|
|
|
<sect3>
|
|
|
|
<title>III.2.2 Output handling</title>
|
|
|
|
|
|
|
|
<variablelist>
|
|
|
|
<varlistentry>
|
|
|
|
<term><varname>ConChannelMask</varname></term>
|
|
|
|
<listitem>
|
|
|
|
<para>
|
|
|
|
Mask of active debugger output channels on console
|
|
|
|
</para>
|
|
|
|
</listitem>
|
|
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
|
|
<term><varname>StdChannelMask</varname></term>
|
|
|
|
<listitem>
|
|
|
|
<para>
|
|
|
|
Mask of active debugger output channels on <filename>stderr</filename>
|
|
|
|
</para>
|
|
|
|
</listitem>
|
|
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
|
|
<term><varname>UseXTerm</varname></term>
|
|
|
|
<listitem>
|
|
|
|
<para>
|
|
|
|
Set to <literal>TRUE</literal> if the debugger uses
|
|
|
|
its own <command>xterm</command> window for console
|
|
|
|
input/output. Set to <literal>FALSE</literal> if
|
|
|
|
the debugger uses the current Unix console for
|
|
|
|
input/output
|
|
|
|
</para>
|
|
|
|
</listitem>
|
|
|
|
</varlistentry>
|
|
|
|
</variablelist>
|
|
|
|
|
|
|
|
<para>
|
|
|
|
Those last 3 variables are jointly used in two generic ways:
|
|
|
|
</para>
|
|
|
|
|
|
|
|
<orderedlist>
|
|
|
|
<listitem>
|
|
|
|
<para>default</para>
|
|
|
|
<programlisting>
|
|
|
|
ConChannelMask = DBG_CHN_MESG (1)
|
|
|
|
StdChannelMask = 0
|
|
|
|
UseXTerm = 1
|
|
|
|
</programlisting>
|
|
|
|
<para>
|
|
|
|
In this case, all input/output goes into a specific
|
|
|
|
<command>xterm</command> window (but all debug
|
|
|
|
messages <function>TRACE</function>,
|
|
|
|
<function>WARN</function>... still goes to tty where
|
|
|
|
wine is run from).
|
|
|
|
</para>
|
|
|
|
</listitem>
|
|
|
|
<listitem>
|
|
|
|
<para>
|
|
|
|
to have all input/output go into the tty where Wine
|
|
|
|
was started from (to be used in a X11-free
|
|
|
|
environment)
|
|
|
|
</para>
|
|
|
|
<screen>
|
|
|
|
ConChannelMask = 0
|
|
|
|
StdChannelMask = DBG_CHN_MESG (1)
|
|
|
|
UseXTerm = 1
|
|
|
|
</screen>
|
|
|
|
</listitem>
|
|
|
|
</orderedlist>
|
|
|
|
<para>
|
|
|
|
Those variables also allow, for example for debugging
|
|
|
|
purposes, to use:
|
|
|
|
</para>
|
|
|
|
<screen>
|
|
|
|
ConChannelMask = 0xfff
|
|
|
|
StdChannelMask = 0xfff
|
|
|
|
UseXTerm = 1
|
|
|
|
</screen>
|
|
|
|
<para>
|
|
|
|
This allows to redirect all <function>WineDbg</function>
|
|
|
|
output to both tty Wine was started from, and
|
|
|
|
<command>xterm</command> debugging window. If Wine (or
|
|
|
|
<command>WineDbg</command>) was started with a redirection
|
|
|
|
of <filename>stdout</filename> and/or
|
|
|
|
<filename>stderr</filename> to a file (with for
|
|
|
|
example >& shell redirect command), you'll get in that
|
|
|
|
file both outputs. It may be interesting to look in the
|
|
|
|
relay trace for specific values which the process segv'ed
|
|
|
|
on.
|
|
|
|
</para>
|
|
|
|
</sect3>
|
|
|
|
|
|
|
|
<sect3>
|
|
|
|
<title>III.2.2 Context information</title>
|
|
|
|
|
|
|
|
<variablelist>
|
|
|
|
<varlistentry>
|
|
|
|
<term><varname>ThreadId</varname></term>
|
|
|
|
<listitem>
|
|
|
|
<para>ID of the <varname>W-thread</varname> currently
|
|
|
|
examined by the debugger</para>
|
|
|
|
</listitem>
|
|
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
|
|
<term><varname>ProcessId</varname></term>
|
|
|
|
<listitem>
|
|
|
|
<para>ID of the <varname>W-thread</varname> currently
|
|
|
|
examined by the debugger</para>
|
|
|
|
</listitem>
|
|
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
|
|
<term><registers></term>
|
|
|
|
<listitem>
|
|
|
|
<para>All CPU registers are also available</para>
|
|
|
|
</listitem>
|
|
|
|
</varlistentry>
|
|
|
|
</variablelist>
|
|
|
|
|
|
|
|
<para>
|
|
|
|
The <varname>ThreadId</varname> and
|
|
|
|
<varname>ProcessId</varname> variables can be handy to set
|
|
|
|
conditional breakpoints on a given thread or process.
|
|
|
|
</para>
|
|
|
|
</sect3>
|
|
|
|
</sect2>
|
2000-08-15 14:00:52 +02:00
|
|
|
<sect2>
|
|
|
|
<title>III.3 Finding files</title>
|
|
|
|
|
|
|
|
<para>
|
|
|
|
WineDbg uses some lookup algorithms to find the files containing
|
|
|
|
the debugging information. For ELF files, the current directory,
|
|
|
|
the list of directories pointed by PATH, LD_LIBRARY_PATH are
|
|
|
|
searched (in that order). For Microsoft debugging files,
|
|
|
|
current directory, and directories pointed by _NT_SYMBOL_PATH and
|
|
|
|
_NT_ALT_SYMBOL_PATH (in that order) are searched.
|
|
|
|
</para>
|
|
|
|
</sect2>
|
2000-08-08 03:24:00 +02:00
|
|
|
</sect1>
|
|
|
|
|
|
|
|
<sect1 id="dbg-commands">
|
|
|
|
<title>IV WineDbg commands</title>
|
|
|
|
|
|
|
|
<sect2>
|
|
|
|
<title>IV.1 Misc</title>
|
|
|
|
|
|
|
|
<screen>
|
|
|
|
abort aborts the debugger
|
|
|
|
quit exits the debugger
|
|
|
|
|
|
|
|
attach N attach to a W-process (N is its ID). IDs can be
|
|
|
|
obtained thru walk process command
|
|
|
|
</screen>
|
|
|
|
<screen>
|
|
|
|
help prints some help on the commands
|
|
|
|
help info prints some help on info commands
|
|
|
|
</screen>
|
|
|
|
<screen>
|
|
|
|
mode 16 switch to 16 bit mode
|
|
|
|
mode 32 switch to 32 bit mode
|
|
|
|
</screen>
|
|
|
|
</sect2>
|
|
|
|
|
|
|
|
<sect2>
|
|
|
|
<title>IV.2 Flow control</title>
|
|
|
|
|
|
|
|
<screen>
|
|
|
|
cont continue execution until next breakpoint or exception.
|
|
|
|
pass pass the exception event up to the filter chain.
|
|
|
|
step continue execution until next C line of code (enters
|
|
|
|
function call)
|
|
|
|
next continue execution until next C line of code (doesn't
|
|
|
|
enter function call)
|
|
|
|
stepi execute next assembly instruction (enters function
|
|
|
|
call)
|
|
|
|
nexti execute next assembly instruction (doesn't enter
|
|
|
|
function call)
|
|
|
|
finish do nexti commands until current function is exited
|
|
|
|
</screen>
|
|
|
|
<para>
|
|
|
|
cont, step, next, stepi, nexti can be postfixed by a
|
|
|
|
number (N), meaning that the command must be executed N
|
|
|
|
times.
|
|
|
|
</para>
|
|
|
|
</sect2>
|
|
|
|
|
|
|
|
<sect2>
|
|
|
|
<title>IV.3 Breakpoints, watch points</title>
|
|
|
|
|
|
|
|
<screen>
|
|
|
|
enable N enables (break|watch)point #N
|
|
|
|
disable N disables (break|watch)point #N
|
|
|
|
delete N deletes (break|watch)point #N
|
|
|
|
cond N removes any a existing condition to (break|watch)point N
|
|
|
|
cond N <expr> adds condition <expr> to (break|watch)point N. <expr>
|
|
|
|
will be evaluated each time the breakpoint is hit. If
|
|
|
|
the result is a zero value, the breakpoint isn't
|
|
|
|
triggered
|
|
|
|
break * N adds a breakpoint at address N
|
|
|
|
break <id> adds a breakpoint at the address of symbol <id>
|
|
|
|
break <id> N adds a breakpoint at the address of symbol <id> (N ?)
|
|
|
|
break N adds a breakpoint at line N of current source file
|
|
|
|
break adds a breakpoint at current $pc address
|
|
|
|
watch * N adds a watch command (on write) at address N (on 4 bytes)
|
|
|
|
watch <id> adds a watch command (on write) at the address of
|
|
|
|
symbol <id>
|
|
|
|
info break lists all (break|watch)points (with state)
|
|
|
|
</screen>
|
|
|
|
</sect2>
|
|
|
|
|
|
|
|
<sect2>
|
|
|
|
<title>IV.4 Stack manipulation</title>
|
|
|
|
|
|
|
|
<screen>
|
|
|
|
bt print calling stack of current thread
|
|
|
|
up goes up one frame in current thread's stack
|
|
|
|
up N goes up N frames in current thread's stack
|
|
|
|
dn goes down one frame in current thread's stack
|
|
|
|
dn N goes down N frames in current thread's stack
|
|
|
|
frame N set N as the current frame
|
|
|
|
info local prints information on local variables for current
|
|
|
|
function
|
|
|
|
</screen>
|
|
|
|
</sect2>
|
|
|
|
|
|
|
|
<sect2>
|
|
|
|
<title>IV.5 Directory & source file manipulation</title>
|
|
|
|
|
|
|
|
<screen>
|
|
|
|
show dir
|
|
|
|
dir <pathname>
|
|
|
|
dir
|
|
|
|
symbolfile <pathname>
|
|
|
|
</screen>
|
|
|
|
<screen>
|
|
|
|
list lists 10 source lines from current position
|
|
|
|
list - lists 10 source lines before current position
|
|
|
|
list N lists 10 source lines from line N in current file
|
|
|
|
list <path>:N lists 10 source lines from line N in file <path>
|
|
|
|
list <id> lists 10 source lines of function <id>
|
|
|
|
list * N lists 10 source lines from address N
|
|
|
|
</screen>
|
|
|
|
<para>
|
|
|
|
You can specify the end target (to change the 10 lines
|
|
|
|
value) using the ','. For example:
|
|
|
|
</para>
|
|
|
|
<screen>
|
|
|
|
list 123, 234 lists source lines from line 123 up to line 234 in
|
|
|
|
current file
|
|
|
|
list foo.c:1,56 lists source lines from line 1 up to 56 in file foo.c
|
|
|
|
</screen>
|
|
|
|
</sect2>
|
|
|
|
|
|
|
|
<sect2>
|
|
|
|
<title>IV.6 Displaying</title>
|
|
|
|
|
|
|
|
<para>
|
|
|
|
A display is an expression that's evaluated and printed
|
|
|
|
after the execution of any <command>WineDbg</command>
|
|
|
|
command.
|
|
|
|
</para>
|
|
|
|
<screen>
|
|
|
|
display lists the active displays
|
|
|
|
info display (same as above command)
|
|
|
|
display <expr> adds a display for expression <expr>
|
|
|
|
display /fmt <expr> adds a display for expression <expr>. Printing
|
|
|
|
evaluated <expr> is done using the given format (see
|
|
|
|
print command for more on formats)
|
|
|
|
del display N deletes display #N
|
|
|
|
undisplay N (same as del display)
|
|
|
|
</screen>
|
|
|
|
</sect2>
|
|
|
|
|
|
|
|
<sect2>
|
|
|
|
<title>IV.7 Disassembly</title>
|
|
|
|
|
|
|
|
<screen>
|
|
|
|
disas disassemble from current position
|
|
|
|
disas <expr> disassemble from address <expr>
|
|
|
|
disas <expr>,<expr>disassembles code between addresses specified by
|
|
|
|
the two <expr>
|
|
|
|
</screen>
|
|
|
|
</sect2>
|
|
|
|
|
|
|
|
<sect2>
|
|
|
|
<title>IV.8 Information on Wine's internals</title>
|
|
|
|
|
|
|
|
<screen>
|
|
|
|
info class <id> prints information on Windows's class <id>
|
|
|
|
walk class lists all Windows' class registered in Wine
|
|
|
|
info share lists all the dynamic libraries loaded the debugged
|
|
|
|
program (including .so files, NE and PE DLLs)
|
|
|
|
info module N prints information on module of handle N
|
|
|
|
walk module lists all modules loaded by debugged program
|
|
|
|
info queue N prints information on Wine's queue N
|
|
|
|
walk queue lists all queues allocated in Wine
|
|
|
|
info regs prints the value of CPU register
|
|
|
|
info segment N prints information on segment N
|
|
|
|
info segment lists all allocated segments
|
|
|
|
info stack prints the values on top of the stack
|
|
|
|
info map lists all virtual mappings used by the debugged
|
|
|
|
program
|
|
|
|
info wnd N prints information of Window of handle N
|
|
|
|
walk wnd lists all the window hierarchy starting from the
|
|
|
|
desktop window
|
|
|
|
walk wnd N lists all the window hierarchy starting from the
|
|
|
|
window of handle N
|
|
|
|
walk process lists all w-processes in Wine session
|
|
|
|
walk thread lists all w-threads in Wine session
|
|
|
|
walk modref (no longer avail)
|
|
|
|
</screen>
|
|
|
|
</sect2>
|
|
|
|
|
|
|
|
<sect2>
|
|
|
|
<title>IV.9 Memory (reading, writing, typing)</title>
|
|
|
|
|
|
|
|
<screen>
|
|
|
|
x <expr> examines memory at <expr> address
|
|
|
|
x /fmt <expr> examines memory at <expr> address using format /fmt
|
|
|
|
print <expr> prints the value of <expr> (possibly using its type)
|
|
|
|
print /fmt <expr> prints the value of <expr> (possibly using its
|
|
|
|
type)
|
|
|
|
set <lval>=<expr> writes the value of <expr> in <lval>
|
|
|
|
whatis <expr> prints the C type of expression <expr>
|
|
|
|
</screen>
|
|
|
|
<para>
|
|
|
|
<filename>/fmt</filename> is either <filename>/<letter></filename> or
|
|
|
|
<filename>/<count><letter></filename> letter can be
|
|
|
|
</para>
|
|
|
|
<screen>
|
|
|
|
s => an ASCII string
|
|
|
|
u => an Unicode UTF16 string
|
|
|
|
i => instructions (disassemble)
|
|
|
|
x => 32 bit unsigned hexadecimal integer
|
|
|
|
d => 32 bit signed decimal integer
|
|
|
|
w => 16 bit unsigned hexadecimal integer
|
|
|
|
c => character (only printable 0x20-0x7f are actually
|
|
|
|
printed)
|
|
|
|
b => 8 bit unsigned hexadecimal integer
|
|
|
|
</screen>
|
|
|
|
</sect2>
|
|
|
|
</sect1>
|
|
|
|
|
|
|
|
<sect1 id="dbg-others">
|
|
|
|
<title>V Other debuggers</title>
|
|
|
|
|
|
|
|
<sect2>
|
|
|
|
<title>V.1 Using other Unix debuggers</title>
|
|
|
|
|
|
|
|
<para>
|
|
|
|
You can also use other debuggers (like
|
|
|
|
<command>gdb</command>), but you must be aware of a few
|
|
|
|
items:
|
|
|
|
</para>
|
|
|
|
<para>
|
|
|
|
You need to attach the unix debugger to the correct unix
|
|
|
|
process (representing the correct windows thread) (you can
|
|
|
|
"guess" it from a <command>ps fax</command> for example:
|
|
|
|
When running the emulator, usually the first two
|
|
|
|
<varname>upids</varname> are for the Windows' application
|
|
|
|
running the desktop, the first thread of the application is
|
|
|
|
generally the third <varname>upid</varname>; when running a
|
|
|
|
WineLib program, the first thread of the application is
|
|
|
|
generally the first <varname>upid</varname>)
|
|
|
|
</para>
|
|
|
|
<note>
|
|
|
|
<para>
|
|
|
|
Even if latest <command>gdb</command> implements the
|
|
|
|
notion of threads, it won't work with Wine because the
|
|
|
|
thread abstraction used for implementing Windows' thread
|
|
|
|
is not 100% mapped onto the linux posix threads
|
|
|
|
implementation. It means that you'll have to spawn a
|
|
|
|
different <command>gdb</command> session for each Windows'
|
|
|
|
thread you wish to debug.
|
|
|
|
</para>
|
|
|
|
</note>
|
|
|
|
</sect2>
|
|
|
|
|
|
|
|
<sect2>
|
|
|
|
<title>V.2 Using other Windows debuggers</title>
|
|
|
|
|
|
|
|
<para>
|
|
|
|
You can use any Windows' debugging API compliant debugger
|
|
|
|
with Wine. Some reports have been made of success with
|
|
|
|
VisualStudio debugger (in remote mode, only the hub runs
|
|
|
|
in Wine). GoVest fully runs in Wine.
|
|
|
|
</para>
|
|
|
|
</sect2>
|
|
|
|
|
|
|
|
<sect2>
|
|
|
|
<title>V.3 Main differences between winedbg and regular Unix debuggers</title>
|
|
|
|
|
|
|
|
<!-- FIXME: convert this into a table -->
|
|
|
|
<screen>
|
|
|
|
+----------------------------------+---------------------------------+
|
|
|
|
| WineDbg | gdb |
|
|
|
|
+----------------------------------+---------------------------------+
|
|
|
|
|WineDbg debugs a Windows' process:|gdb debugs a Windows' thread: |
|
|
|
|
|+ the various threads will be |+ a separate gdb session is |
|
|
|
|
| handled by the same WineDbg | needed for each thread of |
|
|
|
|
| session | Windows' process |
|
|
|
|
|+ a breakpoint will be triggered |+ a breakpoint will be triggered |
|
|
|
|
| for any thread of the w-process | only for the w-thread debugged |
|
|
|
|
+----------------------------------+---------------------------------+
|
|
|
|
|WineDbg supports debug information|gdb supports debug information |
|
|
|
|
|from: |from: |
|
|
|
|
|+ stabs (standard Unix format) |+ stabs (standard Unix format) |
|
|
|
|
|+ Microsoft's C, CodeView, .DBG | |
|
|
|
|
+----------------------------------+---------------------------------+
|
|
|
|
</screen>
|
|
|
|
</sect2>
|
|
|
|
</sect1>
|
|
|
|
|
|
|
|
<sect1 id="dbg-limits">
|
|
|
|
<title>VI Limitations</title>
|
|
|
|
|
|
|
|
<para>
|
|
|
|
16 bit processes are not supported (but calls to 16 bit code
|
|
|
|
in 32 bit applications are).
|
|
|
|
</para>
|
|
|
|
|
|
|
|
</sect1>
|
|
|
|
</chapter>
|
|
|
|
|
|
|
|
<!-- Keep this comment at the end of the file
|
|
|
|
Local variables:
|
|
|
|
mode: sgml
|
|
|
|
sgml-parent-document:("wine-doc.sgml" "book" "part" "chapter" "")
|
|
|
|
End:
|
|
|
|
-->
|