| 	This is the core of the Wine debugger.  The reverse assember | 
 | was stolen from Mach more or less intact.  It turns out that there are | 
 | two variables that are set differently if you are reverse assembling | 
 | 16 bit code, and on the whole it seems to work. | 
 |  | 
 | NEWS: | 
 |  | 
 | 	The internal debugger has *tons* more capability than it did before. | 
 | I have enclosed some examples that show usage at the end of this file. | 
 | New features include: | 
 |  | 
 | 	1) Ability of debugger to read debug information from wine executable | 
 | *and* from Win32 executables.  Local variable and line number information is | 
 | also read and processed. | 
 |  | 
 | 	2) The internal debugger is capable of 'stepping' to the next | 
 | line number, just like gdb.  Examples of the commands are: | 
 |  | 
 | 	step | 
 | 	stepi | 
 | 	si | 
 | 	step 3 | 
 | 	si 5 | 
 | 	next | 
 | 	nexti | 
 | 	cont 4 | 
 | 	finish | 
 |  | 
 | All of these should be exactly like how gdb does things. | 
 |  | 
 | 	3) The internal debugger now has a sense of what source file and line | 
 | number a given PC is at.  New commands to support this are just like gdb, | 
 | and include: | 
 |  | 
 | 	list | 
 | 	dir | 
 | 	show dir | 
 |  | 
 | there are a variety of formats of arguments for the list command.  All | 
 | permutations supported by gdb should also be supported. | 
 |  | 
 | 	4) The internal debugger knows about datatypes of various objects, | 
 | for both Win32 *and* the debugging information in the wine executable itself. | 
 | I have enclosed an example of how this works at the end. | 
 |  | 
 | 	5) There are more ways the 'b' command can be used to set breakpoints. | 
 | Examples are: | 
 |  | 
 | 	b *0x8190000 | 
 | 	b 1100 | 
 | 	b Usage | 
 | 	b | 
 |  | 
 | I don't think this covers all of the permutations that gdb accepts (this should | 
 | be cleaned up someday so that all possibilities are acceptable). | 
 |  | 
 | 	6)  The 'print' and 'x' commands should behave more or less exactly | 
 | as they do under gdb.  The difference is that the way the data is presented | 
 | will be slightly different, but the content should be fundamentally the same. | 
 |  | 
 | 	7) The internal debugger now supports conditional breakpoints, and | 
 | automatic display expressions.  An example is at the end of this file.  The | 
 | syntax and usage should be identical to that of gdb. | 
 |  | 
 | 	8) Type casts can be made from within the debugger, but they currently | 
 | don't work with typedef'ed types.  They only work with builtin types and | 
 | named structures unions, etc.  The problem is that internally we don't always | 
 | record the typedefed names of structures, so we have no guarantee that we | 
 | would know what each type is.  This can be fixed, of course -  it just takes | 
 | more memory.  Note that in some cases, typedefed structures could be cast | 
 | using '(struct typedfname)' instead of '(typedfname)'.   Technically this | 
 | isn't quite correct, but if and when the rest of this stuff gets fixed, | 
 | this would need to get corrected too. | 
 |  | 
 | NOTES: | 
 |  | 
 | 	If it weren't for the fact that gdb doesn't grok the Win32 debug | 
 | information, you could just use gdb.  The internal debugger should be able | 
 | to read and use debugging information for both Win32 and also for the | 
 | Wine executable, making it possible to debug the combination of the two | 
 | together as if it were one large (very large) entity. | 
 |  | 
 | LIMITATIONS AND DIFFERENCES FROM GDB: | 
 |  | 
 | 	You cannot set a breakpoint by file and line number as you can | 
 | with gdb.  Adding support for this wouldn't be all that tough, I guess, but | 
 | it would be a nuisance.   You can set a breakpoint given a function and | 
 | line number, however.  An example would be 'b main:2993'.  It turns out | 
 | that the way the internal data structures are arranged it is a whole lot | 
 | easier to do things in this way than it would be to try and get the | 
 | source:line type of breakpoint working, but it would probably be worth it | 
 | to try. | 
 |  | 
 | 	Getting stack traces through Wine itself can be a bit tricky. | 
 | This is because by default the thing is built with optimization | 
 | enabled, and as a result sometimes functions don't get frames, and | 
 | lots of variables are optimized into registers.  You can turn off | 
 | optimization for a few key source files if it will help you. | 
 |  | 
 | 	Memory consumption is getting to be a real problem.  I think 32Mb is | 
 | no longer sufficient to debug wine - 48 or 64 is probably a whole lot better. | 
 | Unfortunately I cannot shut down X to save memory :-). | 
 |  | 
 | ************************************************************************* | 
 | EXAMPLES: | 
 |  | 
 | 	Here is an example of how I tracked down a bug in Wine.  The program | 
 | is something that just maps and dumps the contents of a Win32 executable. | 
 | It was dying for some reason. | 
 | Note that this example is rather old and does not necessarily use current | 
 | syntax ! | 
 |  | 
 | Start the first time through. | 
 |  | 
 | bash$ ls -l dumpexe.exe  | 
 | -rw-rw-r--   1 eric     devel      168448 Jan  4 13:51 dumpexe.exe | 
 | bash$ ./wine -debug './dumpexe.exe -symbol ./dumpexe.exe' | 
 | Warning: invalid dir 'e:\test' in path, deleting it. | 
 | Win32 task 'W32SXXXX': Breakpoint 1 at 0x081a3450 | 
 | Loading symbols from ELF file ./wine... | 
 | Loading symbols from ELF file /usr/X11R6/lib/libXpm.so.4.6... | 
 | Loading symbols from ELF file /usr/X11R6/lib/libSM.so.6.0... | 
 | Loading symbols from ELF file /usr/X11R6/lib/libICE.so.6.0... | 
 | Loading symbols from ELF file /usr/X11R6/lib/libXext.so.6.0... | 
 | Loading symbols from ELF file /usr/X11R6/lib/libX11.so.6.0... | 
 | Loading symbols from ELF file /lib/libm.so.5.0.5... | 
 | Loading symbols from ELF file /lib/libc.so.5.2.18... | 
 | Loading symbols from ELF file /lib/ld-linux.so.1... | 
 | Loading symbols from Win32 file ./dumpexe.exe... | 
 | Stopped on breakpoint 1 at 0x081a3450 (_mainCRTStartup) | 
 | In 32 bit mode. | 
 | *** Invalid address 0x414c5ff8 (KERNEL32_NULL_THUNK_DATA+0x3930ee6c) | 
 | 0x081a3450 (_mainCRTStartup):  movl	%fs:0,%eax | 
 | Wine-dbg>b DumpFile | 
 | Breakpoint 2 at 0x081a0078 (DumpFile+0x9 [dumpexe.c:2723]) | 
 | Wine-dbg>c | 
 | Dump File: ./dumpexe.exe | 
 | Stopped on breakpoint 2 at 0x081a0078 (DumpFile+0x9 [dumpexe.c:2723]) | 
 | Enter path to file dumpexe.c: ../de | 
 | 2723		HANDLE			  hFile = NULL; | 
 | 0x081a0078 (DumpFile+0x9 [dumpexe.c:2723]):  movl	$0x0,0xfffffff4(%ebp) | 
 | Wine-dbg>list | 
 | 2723		HANDLE			  hFile = NULL; | 
 | 2724		HANDLE			  hMap  = NULL; | 
 | 2725		PSTR			  lpMap = NULL; | 
 | 2726		DWORD			  dwFileSize     = 0; | 
 | 2727		DWORD			  dwFileSizeHigh = 0; | 
 | 2728	 | 
 | 2729		PIMAGE_DOS_HEADER	  lpImageDOS  = NULL; | 
 | 2730		PIMAGE_FILE_HEADER	  lpImageFile = NULL; | 
 | 2731		PIMAGE_NT_HEADERS	  lpImageNT   = NULL; | 
 | 2732	 | 
 | 2733		/* | 
 | Wine-dbg>n 10 | 
 | 2747		dwFileSize = GetFileSize(hFile, &dwFileSizeHigh); | 
 | 0x081a00ea (DumpFile+0x7b [dumpexe.c:2747]):  leal	0xfffffff0(%ebp),%eax | 
 | Wine-dbg>n | 
 | 2749		    && (GetLastError() != NO_ERROR) ) | 
 | 0x081a00fb (DumpFile+0x8c [dumpexe.c:2749]):  cmpl	$-1,0xffffffe8(%ebp) | 
 | Wine-dbg>x/d dwFileSize | 
 | x/d dwFileSize | 
 |  168448 | 
 | Wine-dbg>n | 
 | 2758					 PAGE_READONLY, 0, 0, (LPSTR) NULL); | 
 | 0x081a0124 (DumpFile+0xb5 [dumpexe.c:2758]):  pushl	$0x0 | 
 | Wine-dbg>list 2750 | 
 | list 2750 | 
 | 2750		{ | 
 | 2751			Fatal("Cannot get size of file %s", lpFileName); | 
 | 2752		} | 
 | 2753		 | 
 | 2754		/* | 
 | 2755		 * map the file | 
 | 2756		 */ | 
 | 2757		hMap = CreateFileMapping(hFile, (LPSECURITY_ATTRIBUTES) NULL, | 
 | 2758					 PAGE_READONLY, 0, 0, (LPSTR) NULL); | 
 | 2759		if( hMap == NULL ) | 
 | 2760		{ | 
 | Wine-dbg>n | 
 | 2759		if( hMap == NULL ) | 
 | 0x081a013b (DumpFile+0xcc [dumpexe.c:2759]):  cmpl	$0,0xfffffffc(%ebp) | 
 | Wine-dbg>x hMap | 
 |  08e48c30 | 
 | Wine-dbg>n | 
 | 2767		lpMap = (LPSTR) MapViewOfFile(hMap, FILE_MAP_READ, 0, 0, 0); | 
 | 0x081a0156 (DumpFile+0xe7 [dumpexe.c:2767]):  pushl	$0x0 | 
 | Wine-dbg>n | 
 | 2768		if( lpMap == NULL ) | 
 | 0x081a016b (DumpFile+0xfc [dumpexe.c:2768]):  cmpl	$0,0xffffffe0(%ebp) | 
 | Wine-dbg>print lpMap | 
 | 0x414c5f40 | 
 | Wine-dbg>x lpMap | 
 |  40007000 | 
 | Wine-dbg> x/10x 0x40007000 | 
 |  x/10x 0x40007000 | 
 | 0x40007000 (KERNEL32_NULL_THUNK_DATA+0x37e4fe74): *** Invalid address 0x40007000 (KERNEL32_NULL_THUNK_DATA+0x37e4fe74) | 
 | Wine-dbg>quit | 
 | $ | 
 |  | 
 | ******************************************************************* | 
 | The first time through, we find that MapViewOfFile isn't mapping the file | 
 | correctly into the virtual address space.  Try running again, and step into | 
 | MapViewOfFile to figure out what went wrong. | 
 | ******************************************************************* | 
 |  | 
 |  | 
 | bash$ ./wine -debug './dumpexe.exe -symbol ./dumpexe.exe' | 
 | Warning: invalid dir 'e:\test' in path, deleting it. | 
 | Win32 task 'W32SXXXX': Breakpoint 1 at 0x081a3450 | 
 | Loading symbols from ELF file ./wine... | 
 | Loading symbols from ELF file /usr/X11R6/lib/libXpm.so.4.6... | 
 | Loading symbols from ELF file /usr/X11R6/lib/libSM.so.6.0... | 
 | Loading symbols from ELF file /usr/X11R6/lib/libICE.so.6.0... | 
 | Loading symbols from ELF file /usr/X11R6/lib/libXext.so.6.0... | 
 | Loading symbols from ELF file /usr/X11R6/lib/libX11.so.6.0... | 
 | Loading symbols from ELF file /lib/libm.so.5.0.5... | 
 | Loading symbols from ELF file /lib/libc.so.5.2.18... | 
 | Loading symbols from ELF file /lib/ld-linux.so.1... | 
 | Loading symbols from Win32 file ./dumpexe.exe... | 
 | Stopped on breakpoint 1 at 0x081a3450 (_mainCRTStartup) | 
 | In 32 bit mode. | 
 | *** Invalid address 0x414c5ff8 (KERNEL32_NULL_THUNK_DATA+0x3930ee6c) | 
 | 0x081a3450 (_mainCRTStartup):  movl	%fs:0,%eax | 
 | Wine-dbg>b DumpFile:2767 | 
 | Breakpoint 2 at 0x081a0156 (DumpFile+0xe7 [dumpexe.c:2767]) | 
 | Wine-dbg>c | 
 | Dump File: ./dumpexe.exe | 
 | Stopped on breakpoint 2 at 0x081a0156 (DumpFile+0xe7 [dumpexe.c:2767]) | 
 | Enter path to file dumpexe.c: ../de | 
 | 2767		lpMap = (LPSTR) MapViewOfFile(hMap, FILE_MAP_READ, 0, 0, 0); | 
 | 0x081a0156 (DumpFile+0xe7 [dumpexe.c:2767]):  pushl	$0x0 | 
 | Wine-dbg>step | 
 | 390	0385 stdcall MapViewOfFile(long long long long long) MapViewOfFile | 
 | 0x080d793c (KERNEL32_385 [kernel32.spec:390]):  pushl	%ebp | 
 | Wine-dbg>step | 
 | 223	    if (!debugging_relay) return; | 
 | 0x080c83dc (RELAY_DebugCallFrom32+0xc [relay.c:223]):  cmpw	$0,0x644a | 
 | Wine-dbg> | 
 | 244	} | 
 | 0x080c848e (RELAY_DebugCallFrom32+0xbe [relay.c:244]):  leal	0xfffffff4(%ebp),%esp | 
 | Wine-dbg> | 
 | 103	    return MapViewOfFileEx(handle,access,offhi,offlo,size,0); | 
 | 0x080911a4 (MapViewOfFile+0x14 [file.c:103]):  pushl	$0x0 | 
 | Wine-dbg> | 
 | 113	    FILEMAP_OBJECT *fmap = (FILEMAP_OBJECT*)handle; | 
 | 0x080911cf (MapViewOfFileEx+0xf [file.c:113]):  movl	0x8(%ebp),%esi | 
 | Wine-dbg>n | 
 | 115	    if (!size) size = fmap->size; | 
 | 0x080911d2 (MapViewOfFileEx+0x12 [file.c:115]):  testl	%ebx,%ebx | 
 | Wine-dbg>list | 
 | list | 
 | 115	    if (!size) size = fmap->size; | 
 | 116	    if (!size) size = 1; | 
 | 117	    return mmap ((caddr_t)st, size, fmap->prot,  | 
 | 118	                 MAP_ANON|MAP_PRIVATE,  | 
 | 119			 FILE_GetUnixHandle(fmap->hfile), | 
 | 120			 offlo); | 
 | 121	} | 
 | 122	 | 
 | 123	/*********************************************************************** | 
 | 124	 *           UnmapViewOfFile                  (KERNEL32.385) | 
 | 125	 */ | 
 | Wine-dbg>x size | 
 |  00000000 | 
 | Wine-dbg>n | 
 | 116	    if (!size) size = 1; | 
 | 0x080911d9 (MapViewOfFileEx+0x19 [file.c:116]):  testl	%ebx,%ebx | 
 | Wine-dbg>x size | 
 |  00000000 | 
 | Wine-dbg>n | 
 | 117	    return mmap ((caddr_t)st, size, fmap->prot,  | 
 | 0x080911e2 (MapViewOfFileEx+0x22 [file.c:117]):  pushl	%eax | 
 | Wine-dbg>x size | 
 |  00000000 | 
 | Wine-dbg>info local | 
 | MapViewOfFileEx:handle == 0x08e48c90 | 
 | MapViewOfFileEx:access == 0x00000004 | 
 | MapViewOfFileEx:offhi == 0x00000000 | 
 | MapViewOfFileEx:offlo == 0x00000000 | 
 | MapViewOfFileEx:size == 0x00000000 | 
 | MapViewOfFileEx:st == 0x00000000 | 
 | MapViewOfFileEx:offlo optimized into register $eax  | 
 | MapViewOfFileEx:size optimized into register $ebx  | 
 | MapViewOfFileEx:st optimized into register $edi  | 
 | MapViewOfFileEx:fmap optimized into register $esi  | 
 | Wine-dbg>print $ebx | 
 | 0x0001 | 
 | Wine-dbg>bt | 
 | bt | 
 | Backtrace: | 
 | =>0 0x080911e2 (MapViewOfFileEx+0x22 [file.c:117]) | 
 |   1 0x080911b0 (MapViewOfFile+0x20(handle=0x8e48c90, access=0x4, offhi=0x0, offlo=0x0, size=0x0) [file.c:104]) | 
 |   2 0x08104ab5 (CallFrom32_stdcall_5+0x25 [callfrom32.s]) | 
 |   3 0x081a0168 (DumpFile+0xf9(lpFileName=0x414c61ed) [dumpexe.c:2767]) | 
 |   4 0x081a0c35 (main+0x410(argc=0x3, argv=0x414c61cc) [dumpexe.c:3078]) | 
 |   5 0x081a3514 (_mainCRTStartup+0xc4) | 
 |   6 0x0810549f (Code_Start+0x13 [callto32.s]) | 
 |   7 0x0802fdac (TASK_CallToStart+0x8c [task.c:373]) | 
 |  | 
 | Wine-dbg> | 
 |  | 
 | ******************************************************************* | 
 | Notice that you can step through the thunks into our own transfer | 
 | routines.   You will notice that the source line displays as something | 
 | like: | 
 |  | 
 | 390	0385 stdcall MapViewOfFile(long long long long long) MapViewOfFile | 
 |  | 
 | This is just the source line from the spec file that caused the transfer | 
 | routine to be generated.  From this you can step again, and you step | 
 | into the relay logging code - keep stepping and you eventually step into | 
 | the actual function that does the dirty work. | 
 |  | 
 | 	At this point an examination of the source to the Win32 program | 
 | and an examination of the source to win32/file.s showed where the problem | 
 | was.  When you specify 0 for the size of the object in CreateFileMapping, | 
 | it is supposed to use the entire size of the file as the size of the | 
 | object.  Instead we were just blindly copying the number over. | 
 |  | 
 | ******************************************************************* | 
 |  | 
 | Wine-dbg>b main | 
 | Breakpoint 1 at 0x080108c0 (main [dbgmain.c:213]) | 
 | Wine-dbg>print breakpoints[1] | 
 | {addr={type=0x08043000, seg=0, off=134285504}, addrlen=' ', opcode='U', enabled=1, skipcount=0, in_use=1} | 
 |  | 
 | Wine-dbg> print breakpoints[1].enabled | 
 | 1 | 
 | Wine-dbg>set breakpoints[0].enabled = 0 | 
 | Wine-dbg>print breakpoints[0].enabled | 
 | 0 | 
 |  | 
 | Wine-dbg>print type_hash_table[1]->type | 
 | STRUCT | 
 |  | 
 | Wine-dbg>print type_hash_table[1] | 
 | 0x08072020 | 
 | Wine-dbg>print *type_hash_table[1] | 
 | print *type_hash_table[1] | 
 | {type=STRUCT, next=0x00000000, name="LOGPALETTE", un={basic={basic_type=8, output_format=" V M", basic_size=-128, b_signed=0}, bitfield={bitoff=8, nbits=0, basetype=0x081d56c0}, pointer={pointsto=0x00000008}, funct={rettype=0x00000008}, array={start=8, end=136140480, basictype=0x08043e80}, structure={size=8, members=0x081d56c0}, enumeration={members=0x00000008}}} | 
 | Wine-dbg> | 
 |  | 
 | ******************************************************************* | 
 |  | 
 | 	This example shows how you can print out various data structures. | 
 | Note that enumerated types are displayed in the symbolic form, and strings | 
 | are displayed in the expected manner. | 
 |  | 
 | 	You can use the set command to set more or less anything.  Note | 
 | however that you cannot use enumerated types on the RHS of the expression. | 
 |  | 
 | ******************************************************************* | 
 |  | 
 |  | 
 | Wine-dbg>list | 
 | 2986            if( argc <= 1 ) | 
 | 2987            { | 
 | 2988                    Usage(argv[0]); | 
 | 2989            } | 
 | 2990 | 
 | 2991            for( i = 1; i < argc; i++ ) | 
 | 2992            { | 
 | 2993                    if( strncmp(argv[i], "-dos", sizeof("-dos") - 1) == 0 ) | 
 | 2994                    { | 
 | 2995                            DmpCtrl.bDumpDOSHeader = TRUE; | 
 | 2996                    } | 
 | Wine-dbg>b 2993 | 
 | Breakpoint 3 at 0x081a8861 (main+0x3c [dumpexe.c:2993]) | 
 | Wine-dbg>condition 3 i == 2 | 
 | Wine-dbg>c | 
 | Stopped on breakpoint 3 at 0x081a8861 (main+0x3c [dumpexe.c:2993]) | 
 | 2993                    if( strncmp(argv[i], "-dos", sizeof("-dos") - 1) == 0 ) | 
 | 0x081a8861 (main+0x3c [dumpexe.c:2993]):  pushl $0x4 | 
 | Wine-dbg>print i | 
 | 2 | 
 | Wine-dbg>print argv[i] | 
 | "./dumpexe.exe" | 
 |  | 
 | ******************************************************************* | 
 |  | 
 | 	This example shows how to use conditional breakpoints. | 
 | 	Here is another one that demonstrates another cool feature | 
 | 	conditional breakpoints that involve a function call: | 
 |  | 
 | 		condition 3 strcmp(argv[i], "./dumpexe.exe") == 0 | 
 |  | 
 | ******************************************************************* | 
 |  | 
 |  | 
 | Wine-dbg>list | 
 | 2986            if( argc <= 1 ) | 
 | 2987            { | 
 | 2988                    Usage(argv[0]); | 
 | 2989            } | 
 | 2990 | 
 | 2991            for( i = 1; i < argc; i++ ) | 
 | 2992            { | 
 | 2993                    if( strncmp(argv[i], "-dos", sizeof("-dos") - 1) == 0 ) | 
 | 2994                    { | 
 | 2995                            DmpCtrl.bDumpDOSHeader = TRUE; | 
 | 2996                    } | 
 | Wine-dbg>b 2993 | 
 | Breakpoint 3 at 0x081a8861 (main+0x3c [dumpexe.c:2993]) | 
 | Wine-dbg>condition 3 strcmp(argv[i], "./dumpexe.exe") == 0 | 
 | Wine-dbg>info break | 
 | Breakpoints: | 
 | 1: y 0x081ab450 (_mainCRTStartup) | 
 | 2: y 0x081a882e (main+0x9 [dumpexe.c:2986]) | 
 | 3: y 0x081a8861 (main+0x3c [dumpexe.c:2993]) | 
 |                 stop when  ( strcmp(( argv[i] ), "./dumpexe.exe") == 0 ) | 
 | Wine-dbg>c | 
 | Stopped on breakpoint 3 at 0x081a8861 (main+0x3c [dumpexe.c:2993]) | 
 | 2993                    if( strncmp(argv[i], "-dos", sizeof("-dos") - 1) == 0 ) | 
 | 0x081a8861 (main+0x3c [dumpexe.c:2993]):  pushl $0x4 | 
 | Wine-dbg>print i | 
 | 2 | 
 | Wine-dbg>print argv[i]   | 
 | "./dumpexe.exe" | 
 | Wine-dbg> |