|  | I Introduction | 
|  | ============== | 
|  |  | 
|  | I.1 Processes and threads: in underlying OS and in Windows | 
|  | ---------------------------------------------------------- | 
|  | 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. | 
|  |  | 
|  | Each Windows' thread is implemented as a Unix process (under Linux | 
|  | using the clone syscall), meaning that all threads of a same Windows' | 
|  | process share the same (unix) address space. | 
|  |  | 
|  | In the following: | 
|  | + W-process means a process in Windows' terminology | 
|  | + U-process means a process in Unix' terminology | 
|  | + W-thread means a thread in Windows' terminology | 
|  |  | 
|  | A W-process is made of one or several W-threads. | 
|  | Each W-thread is mapped to one and only one U-process. All U-processes | 
|  | of a same W-process share the same address space. | 
|  |  | 
|  | Each Unix process can be identified by two values: | 
|  | - the Unix process id (upid in the following) | 
|  | - the Windows's thread id (tid) | 
|  | Each Windows' process has also a Windows' process (wpid in the | 
|  | following). It must be clear that upid and wpid are different and | 
|  | shall not be used instead of the other. | 
|  |  | 
|  | Wpid and tid 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 | 
|  | W-process). | 
|  |  | 
|  |  | 
|  | I.2 Wine, debugging and WineDbg | 
|  | ------------------------------- | 
|  | When talking of debugging in Wine, there are at least two levels to | 
|  | think of: | 
|  | + the Windows' debugging API. | 
|  | + the Wine integrated debugger, dubbed WineDbg. | 
|  |  | 
|  | Wine implements most the the Windows' debugging API (the part in | 
|  | KERNEL32, not the one in IMAGEHLP.DLL), and allows any program | 
|  | (emulated or WineLib) using that API to debug a W-process. | 
|  |  | 
|  | WineDbg 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). | 
|  |  | 
|  | II WineDbg's modes of invocation | 
|  | ================================ | 
|  |  | 
|  | II.1 Starting a process | 
|  | ----------------------- | 
|  | Any application (either a Windows' native executable, or a WineLib | 
|  | application) can be run through WineDbg. Command line options and | 
|  | tricks are the same than for wine: | 
|  |  | 
|  | winedbg telnet.exe | 
|  | winedbg "hl.exe -windowed" | 
|  |  | 
|  | II.2 Attaching | 
|  | -------------- | 
|  | WineDbg can also launched without any command line argument: | 
|  | - WineDbg is started without any attached process. You can get a list | 
|  | of running W-processes (and their wpid:s) using 'walk process' | 
|  | command, and then, with the attach command, pick up the wpid of the | 
|  | W-process you want to debug. | 
|  |  | 
|  | This is (for now) a neat feature for the following reasons: | 
|  | * debug an already started application | 
|  |  | 
|  | II.3 On exception | 
|  | ----------------- | 
|  | When something goes wrong, Windows track this as an | 
|  | exception. Exceptions exist for segmentation violation, stack | 
|  | overflow, division by zero... | 
|  |  | 
|  | When an exception occurs, Wine checks if the W-process 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. | 
|  |  | 
|  | If the W-process is not debugged, Wine tries to launch a | 
|  | debugger. This debugger (normally WineDbg, see III Configuration for | 
|  | more details), at startup, attaches to the W-process 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. | 
|  |  | 
|  | If WineDbg is the standard debugger, the 'pass' and 'cont' commands | 
|  | are the two ways to let the process go further for the handling of the | 
|  | exception event. | 
|  |  | 
|  | 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 know as | 
|  | a first chance exception). The debugger can give two answers: | 
|  | - continue: the debugger had the ability to correct what's generated | 
|  | the exception, and is now able to continue process execution. | 
|  | - pass: 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. | 
|  |  | 
|  | Note: since some of Wine's code uses exceptions and try/catch blocks | 
|  | to provide some functionality, WineDbg can be entered in such cases | 
|  | with segv exceptions. This happens, for example, with IsBadReadPtr | 
|  | function. In that case, the pass command shall be used, to let the | 
|  | handling of the exception to be done by the catch block in | 
|  | IsBadReadPtr. | 
|  |  | 
|  | II.4 Quitting | 
|  | ------------- | 
|  | Unfortunately, Windows' don'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 WineDbg. | 
|  |  | 
|  | III Configuration | 
|  | ================= | 
|  |  | 
|  | III.1 Registry configuration | 
|  | ---------------------------- | 
|  | 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 | 
|  | "MACHINE\\Software\\Microsoft\\Windows NT\\CurrentVersion\\AeDebug" | 
|  | determine the behavior: | 
|  | + Debugger: this is the command line used to launch the debugger (it | 
|  | uses two printf formats (%ld) to pass context dependent information to | 
|  | the debugger). You should put here a complete path to your debugger | 
|  | (WineDbg can of course be used, but any other Windows' debugging API | 
|  | aware debugger will do). | 
|  | + Auto: 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. | 
|  |  | 
|  | A regular Wine registry looks like: | 
|  | [MACHINE\\Software\\Microsoft\\Windows NT\\CurrentVersion\\AeDebug] 957636538 | 
|  | "Auto"=dword:00000001 | 
|  | "Debugger"="/usr/local/bin/winedbg %ld %ld" | 
|  |  | 
|  | Note 1: creating this key is mandatory. Not doing so will not fire the | 
|  | debugger when an exception occurs. | 
|  |  | 
|  | Note 2: wineinstall 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 | 
|  | [MACHINE\\Software\\Microsoft\\Windows NT\\CurrentVersion\\AeDebug] | 
|  | key before running again wineinstall to regenerate this key. | 
|  |  | 
|  | III.2 WineDbg configuration | 
|  | --------------------------- | 
|  | WineDbg 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) [eric\\Software\\Wine\\WineDbg] | 
|  | Those options can be read/written while inside WineDbg, as part of the | 
|  | debugger expressions. To refer to one of this option, its name must be | 
|  | prefixed by a $ sign. | 
|  | For example, | 
|  | set $BreakAllThreadsStartup = 1 | 
|  | sets the option 'BreakAllThreadsStartup' to TRUE. | 
|  | All the options are read from the registry when WineDbg starts (if no | 
|  | corresponding value is found, a default value is used), and are | 
|  | written back to the registry when WineDbg exits (hence, all | 
|  | modifications to those options are automatically saved when WineDbg | 
|  | terminates). | 
|  |  | 
|  | Here's the list of all options: | 
|  |  | 
|  | III.2.1 Controling when the debugger is entered | 
|  |  | 
|  | BreakAllThreadsStartup  set to TRUE if at all threads start-up the | 
|  | debugger stops | 
|  | set to FALSE if only at the first thread | 
|  | startup of a given process the debugger stops. | 
|  | FALSE by default. | 
|  | BreakOnCritSectTimeOut  set to TRUE if the debugger stops when a | 
|  | critical section times out (5 minutes); | 
|  | TRUE by default. | 
|  | BreakOnAttach,		set to TRUE if when WineDbg attaches to an | 
|  | existing process after an unhandled exception, | 
|  | WineDbg 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 FALSE. | 
|  | BreakOnDllLoad		When set to TRUE, allows the debugger to be | 
|  | entered when a new DLL is loaded into the system. | 
|  | FALSE by default. | 
|  | BreakOnFirstChance	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 winedbg's cont | 
|  | command) or pass the exception up to the | 
|  | exception handler chain in the program (if it | 
|  | exists) (winedbg implements this thru the pass | 
|  | 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 BreakOnFirstChance | 
|  | exception is TRUE, then winedbg is entered for | 
|  | both  first and last chance execptions (to | 
|  | FALSE, it's only entered for last chance exceptions). | 
|  |  | 
|  | III.2.1 Output handling | 
|  |  | 
|  | ConChannelMask          mask of active debugger output channels on | 
|  | console | 
|  | StdChannelMask          mask of active debugger output channels on | 
|  | stderr | 
|  |  | 
|  | UseXTerm                set to TRUE if the debugger uses its own xterm | 
|  | window for console input/output | 
|  | set to FALSE is the debugger uses the current | 
|  | Unix console for input/output | 
|  |  | 
|  | Those last 3 variables are jointly used in two generic ways: | 
|  | 1/ default | 
|  | ConChannelMask = DBG_CHN_MESG (1) | 
|  | StdChannelMask = 0 | 
|  | UseXTerm = 1 | 
|  | In this case, all input/output goes into a specific xterm window (but | 
|  | all debug messages TRACE/WARN... still goes to tty where wine is run | 
|  | from). | 
|  |  | 
|  | 2/ to have all input/output go into the tty where Wine was started | 
|  | from (to be used in a X11-free environment) | 
|  | ConChannelMask = 0 | 
|  | StdChannelMask = DBG_CHN_MESG (1) | 
|  | UseXTerm = 1 | 
|  |  | 
|  | Those variables also allow, for example for debugging purposes, to | 
|  | use: | 
|  | ConChannelMask = 0xfff | 
|  | StdChannelMask = 0xfff | 
|  | UseXTerm = 1 | 
|  | This allows to redirect all WineDbg output to both tty Wine was | 
|  | started from, and xterm debugging window. If Wine (or WineDbg) was | 
|  | started with a redirection of stdout and/or stderr 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. | 
|  |  | 
|  | III.2.3 Context information | 
|  |  | 
|  | ThreadId		ID of the W-thread currently examined by the | 
|  | debugger | 
|  | ProcessId		ID of the W-thread currently examined by the | 
|  | debugger | 
|  | <registers>		All CPU registers are also available | 
|  |  | 
|  | The ThreadId and ProcessId variables can be handy to set conditional | 
|  | breakpoints on a given thread or process. | 
|  |  | 
|  | IV WineDbg commands | 
|  | =================== | 
|  |  | 
|  | IV.1 Misc | 
|  | --------- | 
|  | 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 | 
|  |  | 
|  | help		prints some help on the commands | 
|  | help info	prints some help on info commands | 
|  |  | 
|  | mode 16		switch to 16 bit mode | 
|  | mode 32		switch to 32 bit mode | 
|  |  | 
|  | IV.2 Flow control | 
|  | ----------------- | 
|  | 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 | 
|  |  | 
|  | cont, step, next, stepi, nexti can be postfixed by a number (N), | 
|  | meaning that the command must be executed N times. | 
|  |  | 
|  | IV.3 Breakpoints, watch points | 
|  | ------------------------------ | 
|  | 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) | 
|  |  | 
|  | IV.4 Stack manipulation | 
|  | ----------------------- | 
|  | 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 | 
|  |  | 
|  | IV.5 Directory & source file manipulation | 
|  | ----------------------------------------- | 
|  | show dir | 
|  | dir <pathname> | 
|  | dir | 
|  | symbolfile <pathname> | 
|  |  | 
|  | 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 | 
|  |  | 
|  | You can specify the end target (to change the 10 lines value) using | 
|  | the ','. For example: | 
|  | 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 | 
|  |  | 
|  | IV.6 Displaying | 
|  | --------------- | 
|  | a display is an expression that's evaluated and printed after the | 
|  | execution of any WineDbg command | 
|  |  | 
|  | 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) | 
|  |  | 
|  | IV.7 Disassembly | 
|  | ---------------- | 
|  | disas		disassemble from current position | 
|  | disas <expr>	disassemble from address <expr> | 
|  | disas <expr>,<expr>disassembles code between addresses specified by | 
|  | the two <expr> | 
|  |  | 
|  | IV.8 Information on Wine's internals | 
|  | ------------------------------------ | 
|  | 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) | 
|  |  | 
|  | IV.9 Memory (reading, writing, typing) | 
|  |  | 
|  | 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> | 
|  |  | 
|  | /fmt is either /<letter> or /<count><letter> | 
|  | letter can be | 
|  | 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 | 
|  |  | 
|  | V Other debuggers | 
|  | ================= | 
|  |  | 
|  | V.1 Using other Unix debuggers | 
|  | ------------------------------ | 
|  | You can also use other debuggers (like gdb), but you must be aware of | 
|  | a few items: | 
|  | - you need to attach the unix debugger to the correct unix process | 
|  | (representing the correct windows thread) (you can "guess" it from a | 
|  | 'ps fax' for example: When running the emulator, usually the first | 
|  | two upids are for the Windows' application running the desktop, the | 
|  | first thread of the application is generally the third upid; when | 
|  | running a WineLib program, the first thread of the application is | 
|  | generally the first upid) | 
|  |  | 
|  | Note: even if latest gdb 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 gdb | 
|  | session for each Windows' thread you wish to debug. | 
|  |  | 
|  | V.2 Using other Windows debuggers | 
|  | --------------------------------- | 
|  | 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. | 
|  |  | 
|  | V.3 Main differences between winedbg and regular Unix debuggers | 
|  | --------------------------------------------------------------- | 
|  |  | 
|  | +----------------------------------+---------------------------------+ | 
|  | |             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   |                                 | | 
|  | +----------------------------------+---------------------------------+ | 
|  |  | 
|  | VI Limitations | 
|  | ============== | 
|  |  | 
|  | + 16 bit processes are not supported (but calls to 16 bit code in 32 | 
|  | bit applications is). | 
|  | + there are reports of debugger's freeze when loading large PDB files | 
|  |  | 
|  | Last updated: 6/14/2000 by ericP |