blob: 928e71781ab1ffa6eb3b46c4462b92445254c082 [file] [log] [blame]
Alexandre Julliard01d63461997-01-20 19:43:45 +00001 This is the core of the Wine debugger. The reverse assember
2was stolen from Mach more or less intact. It turns out that there are
3two variables that are set differently if you are reverse assembling
416 bit code, and on the whole it seems to work.
Alexandre Julliardf0b23541993-09-29 12:21:49 +00005
Alexandre Julliardc6c09441997-01-12 18:32:19 +00006NEWS:
Alexandre Julliardf0b23541993-09-29 12:21:49 +00007
Alexandre Julliardc6c09441997-01-12 18:32:19 +00008 The internal debugger has *tons* more capability than it did before.
9I have enclosed some examples that show usage at the end of this file.
10New features include:
Alexandre Julliardf0b23541993-09-29 12:21:49 +000011
Alexandre Julliardc6c09441997-01-12 18:32:19 +000012 1) Ability of debugger to read debug information from wine executable
13*and* from Win32 executables. Local variable and line number information is
14also read and processed.
Alexandre Julliardf0b23541993-09-29 12:21:49 +000015
Alexandre Julliardc6c09441997-01-12 18:32:19 +000016 2) The internal debugger is capable of 'stepping' to the next
17line number, just like gdb. Examples of the commands are:
18
19 step
20 stepi
21 si
22 step 3
23 si 5
24 next
25 nexti
26 cont 4
27 finish
28
29All of these should be exactly like how gdb does things.
30
31 3) The internal debugger now has a sense of what source file and line
32number a given PC is at. New commands to support this are just like gdb,
33and include:
34
35 list
36 dir
37 show dir
38
39there are a variety of formats of arguments for the list command. All
40permutations supported by gdb should also be supported.
41
42 4) The internal debugger knows about datatypes of various objects,
43for both Win32 *and* the debugging information in the wine executable itself.
44I have enclosed an example of how this works at the end.
45
46 5) There are more ways the 'b' command can be used to set breakpoints.
47Examples are:
48
49 b *0x8190000
50 b 1100
51 b Usage
52 b
53
54I don't think this covers all of the permutations that gdb accepts (this should
55be cleaned up someday so that all possibilities are acceptable).
56
57 6) The 'print' and 'x' commands should behave more or less exactly
58as they do under gdb. The difference is that the way the data is presented
59will be slightly different, but the content should be fundamentally the same.
60
61 7) The internal debugger now supports conditional breakpoints, and
62automatic display expressions. An example is at the end of this file. The
63syntax and usage should be identical to that of gdb.
64
Alexandre Julliard01d63461997-01-20 19:43:45 +000065 8) Type casts can be made from within the debugger, but they currently
66don't work with typedef'ed types. They only work with builtin types and
67named structures unions, etc. The problem is that internally we don't always
68record the typedefed names of structures, so we have no guarantee that we
69would know what each type is. This can be fixed, of course - it just takes
70more memory. Note that in some cases, typedefed structures could be cast
71using '(struct typedfname)' instead of '(typedfname)'. Technically this
72isn't quite correct, but if and when the rest of this stuff gets fixed,
73this would need to get corrected too.
74
Alexandre Julliardc6c09441997-01-12 18:32:19 +000075NOTES:
76
77 If it weren't for the fact that gdb doesn't grok the Win32 debug
78information, you could just use gdb. The internal debugger should be able
79to read and use debugging information for both Win32 and also for the
80Wine executable, making it possible to debug the combination of the two
81together as if it were one large (very large) entity.
82
83LIMITATIONS AND DIFFERENCES FROM GDB:
84
Alexandre Julliardc6c09441997-01-12 18:32:19 +000085 You cannot set a breakpoint by file and line number as you can
86with gdb. Adding support for this wouldn't be all that tough, I guess, but
87it would be a nuisance. You can set a breakpoint given a function and
88line number, however. An example would be 'b main:2993'. It turns out
89that the way the internal data structures are arranged it is a whole lot
90easier to do things in this way than it would be to try and get the
91source:line type of breakpoint working, but it would probably be worth it
92to try.
93
94 Getting stack traces through Wine itself can be a bit tricky.
95This is because by default the thing is built with optimization
96enabled, and as a result sometimes functions don't get frames, and
97lots of variables are optimized into registers. You can turn off
98optimization for a few key source files if it will help you.
99
100 Memory consumption is getting to be a real problem. I think 32Mb is
101no longer sufficient to debug wine - 48 or 64 is probably a whole lot better.
102Unfortunately I cannot shut down X to save memory :-).
103
104*************************************************************************
105EXAMPLES:
106
107 Here is an example of how I tracked down a bug in Wine. The program
108is something that just maps and dumps the contents of a Win32 executable.
109It was dying for some reason.
Andreas Mohrc9ec8842001-01-24 19:37:13 +0000110Note that this example is rather old and does not necessarily use current
111syntax !
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000112
113Start the first time through.
114
115bash$ ls -l dumpexe.exe
116-rw-rw-r-- 1 eric devel 168448 Jan 4 13:51 dumpexe.exe
117bash$ ./wine -debug './dumpexe.exe -symbol ./dumpexe.exe'
118Warning: invalid dir 'e:\test' in path, deleting it.
119Win32 task 'W32SXXXX': Breakpoint 1 at 0x081a3450
120Loading symbols from ELF file ./wine...
121Loading symbols from ELF file /usr/X11R6/lib/libXpm.so.4.6...
122Loading symbols from ELF file /usr/X11R6/lib/libSM.so.6.0...
123Loading symbols from ELF file /usr/X11R6/lib/libICE.so.6.0...
124Loading symbols from ELF file /usr/X11R6/lib/libXext.so.6.0...
125Loading symbols from ELF file /usr/X11R6/lib/libX11.so.6.0...
126Loading symbols from ELF file /lib/libm.so.5.0.5...
127Loading symbols from ELF file /lib/libc.so.5.2.18...
128Loading symbols from ELF file /lib/ld-linux.so.1...
129Loading symbols from Win32 file ./dumpexe.exe...
130Stopped on breakpoint 1 at 0x081a3450 (_mainCRTStartup)
131In 32 bit mode.
132*** Invalid address 0x414c5ff8 (KERNEL32_NULL_THUNK_DATA+0x3930ee6c)
1330x081a3450 (_mainCRTStartup): movl %fs:0,%eax
134Wine-dbg>b DumpFile
135Breakpoint 2 at 0x081a0078 (DumpFile+0x9 [dumpexe.c:2723])
136Wine-dbg>c
137Dump File: ./dumpexe.exe
138Stopped on breakpoint 2 at 0x081a0078 (DumpFile+0x9 [dumpexe.c:2723])
139Enter path to file dumpexe.c: ../de
1402723 HANDLE hFile = NULL;
1410x081a0078 (DumpFile+0x9 [dumpexe.c:2723]): movl $0x0,0xfffffff4(%ebp)
142Wine-dbg>list
1432723 HANDLE hFile = NULL;
1442724 HANDLE hMap = NULL;
1452725 PSTR lpMap = NULL;
1462726 DWORD dwFileSize = 0;
1472727 DWORD dwFileSizeHigh = 0;
1482728
1492729 PIMAGE_DOS_HEADER lpImageDOS = NULL;
1502730 PIMAGE_FILE_HEADER lpImageFile = NULL;
1512731 PIMAGE_NT_HEADERS lpImageNT = NULL;
1522732
1532733 /*
154Wine-dbg>n 10
1552747 dwFileSize = GetFileSize(hFile, &dwFileSizeHigh);
1560x081a00ea (DumpFile+0x7b [dumpexe.c:2747]): leal 0xfffffff0(%ebp),%eax
157Wine-dbg>n
1582749 && (GetLastError() != NO_ERROR) )
1590x081a00fb (DumpFile+0x8c [dumpexe.c:2749]): cmpl $-1,0xffffffe8(%ebp)
160Wine-dbg>x/d dwFileSize
161x/d dwFileSize
162 168448
163Wine-dbg>n
1642758 PAGE_READONLY, 0, 0, (LPSTR) NULL);
1650x081a0124 (DumpFile+0xb5 [dumpexe.c:2758]): pushl $0x0
166Wine-dbg>list 2750
167list 2750
1682750 {
1692751 Fatal("Cannot get size of file %s", lpFileName);
1702752 }
1712753
1722754 /*
1732755 * map the file
1742756 */
1752757 hMap = CreateFileMapping(hFile, (LPSECURITY_ATTRIBUTES) NULL,
1762758 PAGE_READONLY, 0, 0, (LPSTR) NULL);
1772759 if( hMap == NULL )
1782760 {
179Wine-dbg>n
1802759 if( hMap == NULL )
1810x081a013b (DumpFile+0xcc [dumpexe.c:2759]): cmpl $0,0xfffffffc(%ebp)
182Wine-dbg>x hMap
183 08e48c30
184Wine-dbg>n
1852767 lpMap = (LPSTR) MapViewOfFile(hMap, FILE_MAP_READ, 0, 0, 0);
1860x081a0156 (DumpFile+0xe7 [dumpexe.c:2767]): pushl $0x0
187Wine-dbg>n
1882768 if( lpMap == NULL )
1890x081a016b (DumpFile+0xfc [dumpexe.c:2768]): cmpl $0,0xffffffe0(%ebp)
190Wine-dbg>print lpMap
1910x414c5f40
192Wine-dbg>x lpMap
193 40007000
194Wine-dbg> x/10x 0x40007000
195 x/10x 0x40007000
1960x40007000 (KERNEL32_NULL_THUNK_DATA+0x37e4fe74): *** Invalid address 0x40007000 (KERNEL32_NULL_THUNK_DATA+0x37e4fe74)
197Wine-dbg>quit
198$
199
200*******************************************************************
201The first time through, we find that MapViewOfFile isn't mapping the file
202correctly into the virtual address space. Try running again, and step into
203MapViewOfFile to figure out what went wrong.
204*******************************************************************
205
206
207bash$ ./wine -debug './dumpexe.exe -symbol ./dumpexe.exe'
208Warning: invalid dir 'e:\test' in path, deleting it.
209Win32 task 'W32SXXXX': Breakpoint 1 at 0x081a3450
210Loading symbols from ELF file ./wine...
211Loading symbols from ELF file /usr/X11R6/lib/libXpm.so.4.6...
212Loading symbols from ELF file /usr/X11R6/lib/libSM.so.6.0...
213Loading symbols from ELF file /usr/X11R6/lib/libICE.so.6.0...
214Loading symbols from ELF file /usr/X11R6/lib/libXext.so.6.0...
215Loading symbols from ELF file /usr/X11R6/lib/libX11.so.6.0...
216Loading symbols from ELF file /lib/libm.so.5.0.5...
217Loading symbols from ELF file /lib/libc.so.5.2.18...
218Loading symbols from ELF file /lib/ld-linux.so.1...
219Loading symbols from Win32 file ./dumpexe.exe...
220Stopped on breakpoint 1 at 0x081a3450 (_mainCRTStartup)
221In 32 bit mode.
222*** Invalid address 0x414c5ff8 (KERNEL32_NULL_THUNK_DATA+0x3930ee6c)
2230x081a3450 (_mainCRTStartup): movl %fs:0,%eax
224Wine-dbg>b DumpFile:2767
225Breakpoint 2 at 0x081a0156 (DumpFile+0xe7 [dumpexe.c:2767])
226Wine-dbg>c
227Dump File: ./dumpexe.exe
228Stopped on breakpoint 2 at 0x081a0156 (DumpFile+0xe7 [dumpexe.c:2767])
229Enter path to file dumpexe.c: ../de
2302767 lpMap = (LPSTR) MapViewOfFile(hMap, FILE_MAP_READ, 0, 0, 0);
2310x081a0156 (DumpFile+0xe7 [dumpexe.c:2767]): pushl $0x0
232Wine-dbg>step
233390 0385 stdcall MapViewOfFile(long long long long long) MapViewOfFile
2340x080d793c (KERNEL32_385 [kernel32.spec:390]): pushl %ebp
235Wine-dbg>step
236223 if (!debugging_relay) return;
2370x080c83dc (RELAY_DebugCallFrom32+0xc [relay.c:223]): cmpw $0,0x644a
238Wine-dbg>
239244 }
2400x080c848e (RELAY_DebugCallFrom32+0xbe [relay.c:244]): leal 0xfffffff4(%ebp),%esp
241Wine-dbg>
242103 return MapViewOfFileEx(handle,access,offhi,offlo,size,0);
2430x080911a4 (MapViewOfFile+0x14 [file.c:103]): pushl $0x0
244Wine-dbg>
245113 FILEMAP_OBJECT *fmap = (FILEMAP_OBJECT*)handle;
2460x080911cf (MapViewOfFileEx+0xf [file.c:113]): movl 0x8(%ebp),%esi
247Wine-dbg>n
248115 if (!size) size = fmap->size;
2490x080911d2 (MapViewOfFileEx+0x12 [file.c:115]): testl %ebx,%ebx
250Wine-dbg>list
251list
252115 if (!size) size = fmap->size;
253116 if (!size) size = 1;
254117 return mmap ((caddr_t)st, size, fmap->prot,
255118 MAP_ANON|MAP_PRIVATE,
256119 FILE_GetUnixHandle(fmap->hfile),
257120 offlo);
258121 }
259122
260123 /***********************************************************************
261124 * UnmapViewOfFile (KERNEL32.385)
262125 */
263Wine-dbg>x size
264 00000000
265Wine-dbg>n
266116 if (!size) size = 1;
2670x080911d9 (MapViewOfFileEx+0x19 [file.c:116]): testl %ebx,%ebx
268Wine-dbg>x size
269 00000000
270Wine-dbg>n
271117 return mmap ((caddr_t)st, size, fmap->prot,
2720x080911e2 (MapViewOfFileEx+0x22 [file.c:117]): pushl %eax
273Wine-dbg>x size
274 00000000
275Wine-dbg>info local
276MapViewOfFileEx:handle == 0x08e48c90
277MapViewOfFileEx:access == 0x00000004
278MapViewOfFileEx:offhi == 0x00000000
279MapViewOfFileEx:offlo == 0x00000000
280MapViewOfFileEx:size == 0x00000000
281MapViewOfFileEx:st == 0x00000000
282MapViewOfFileEx:offlo optimized into register $eax
283MapViewOfFileEx:size optimized into register $ebx
284MapViewOfFileEx:st optimized into register $edi
285MapViewOfFileEx:fmap optimized into register $esi
286Wine-dbg>print $ebx
2870x0001
288Wine-dbg>bt
289bt
290Backtrace:
291=>0 0x080911e2 (MapViewOfFileEx+0x22 [file.c:117])
292 1 0x080911b0 (MapViewOfFile+0x20(handle=0x8e48c90, access=0x4, offhi=0x0, offlo=0x0, size=0x0) [file.c:104])
293 2 0x08104ab5 (CallFrom32_stdcall_5+0x25 [callfrom32.s])
294 3 0x081a0168 (DumpFile+0xf9(lpFileName=0x414c61ed) [dumpexe.c:2767])
295 4 0x081a0c35 (main+0x410(argc=0x3, argv=0x414c61cc) [dumpexe.c:3078])
296 5 0x081a3514 (_mainCRTStartup+0xc4)
297 6 0x0810549f (Code_Start+0x13 [callto32.s])
298 7 0x0802fdac (TASK_CallToStart+0x8c [task.c:373])
299
300Wine-dbg>
301
302*******************************************************************
303Notice that you can step through the thunks into our own transfer
304routines. You will notice that the source line displays as something
305like:
306
307390 0385 stdcall MapViewOfFile(long long long long long) MapViewOfFile
308
309This is just the source line from the spec file that caused the transfer
310routine to be generated. From this you can step again, and you step
311into the relay logging code - keep stepping and you eventually step into
312the actual function that does the dirty work.
313
314 At this point an examination of the source to the Win32 program
315and an examination of the source to win32/file.s showed where the problem
316was. When you specify 0 for the size of the object in CreateFileMapping,
317it is supposed to use the entire size of the file as the size of the
318object. Instead we were just blindly copying the number over.
319
320*******************************************************************
321
322Wine-dbg>b main
323Breakpoint 1 at 0x080108c0 (main [dbgmain.c:213])
324Wine-dbg>print breakpoints[1]
325{addr={type=0x08043000, seg=0, off=134285504}, addrlen=' ', opcode='U', enabled=1, skipcount=0, in_use=1}
326
327Wine-dbg> print breakpoints[1].enabled
3281
329Wine-dbg>set breakpoints[0].enabled = 0
330Wine-dbg>print breakpoints[0].enabled
3310
332
333Wine-dbg>print type_hash_table[1]->type
334STRUCT
335
336Wine-dbg>print type_hash_table[1]
3370x08072020
338Wine-dbg>print *type_hash_table[1]
339print *type_hash_table[1]
340{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}}}
341Wine-dbg>
342
343*******************************************************************
344
345 This example shows how you can print out various data structures.
346Note that enumerated types are displayed in the symbolic form, and strings
347are displayed in the expected manner.
348
349 You can use the set command to set more or less anything. Note
350however that you cannot use enumerated types on the RHS of the expression.
351
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000352*******************************************************************
353
354
355Wine-dbg>list
3562986 if( argc <= 1 )
3572987 {
3582988 Usage(argv[0]);
3592989 }
3602990
3612991 for( i = 1; i < argc; i++ )
3622992 {
3632993 if( strncmp(argv[i], "-dos", sizeof("-dos") - 1) == 0 )
3642994 {
3652995 DmpCtrl.bDumpDOSHeader = TRUE;
3662996 }
367Wine-dbg>b 2993
368Breakpoint 3 at 0x081a8861 (main+0x3c [dumpexe.c:2993])
369Wine-dbg>condition 3 i == 2
370Wine-dbg>c
371Stopped on breakpoint 3 at 0x081a8861 (main+0x3c [dumpexe.c:2993])
3722993 if( strncmp(argv[i], "-dos", sizeof("-dos") - 1) == 0 )
3730x081a8861 (main+0x3c [dumpexe.c:2993]): pushl $0x4
374Wine-dbg>print i
3752
376Wine-dbg>print argv[i]
377"./dumpexe.exe"
378
379*******************************************************************
380
381 This example shows how to use conditional breakpoints.
382 Here is another one that demonstrates another cool feature
383 conditional breakpoints that involve a function call:
384
385 condition 3 strcmp(argv[i], "./dumpexe.exe") == 0
386
387*******************************************************************
388
389
390Wine-dbg>list
3912986 if( argc <= 1 )
3922987 {
3932988 Usage(argv[0]);
3942989 }
3952990
3962991 for( i = 1; i < argc; i++ )
3972992 {
3982993 if( strncmp(argv[i], "-dos", sizeof("-dos") - 1) == 0 )
3992994 {
4002995 DmpCtrl.bDumpDOSHeader = TRUE;
4012996 }
402Wine-dbg>b 2993
403Breakpoint 3 at 0x081a8861 (main+0x3c [dumpexe.c:2993])
404Wine-dbg>condition 3 strcmp(argv[i], "./dumpexe.exe") == 0
405Wine-dbg>info break
406Breakpoints:
4071: y 0x081ab450 (_mainCRTStartup)
4082: y 0x081a882e (main+0x9 [dumpexe.c:2986])
4093: y 0x081a8861 (main+0x3c [dumpexe.c:2993])
410 stop when ( strcmp(( argv[i] ), "./dumpexe.exe") == 0 )
411Wine-dbg>c
412Stopped on breakpoint 3 at 0x081a8861 (main+0x3c [dumpexe.c:2993])
4132993 if( strncmp(argv[i], "-dos", sizeof("-dos") - 1) == 0 )
4140x081a8861 (main+0x3c [dumpexe.c:2993]): pushl $0x4
415Wine-dbg>print i
4162
417Wine-dbg>print argv[i]
418"./dumpexe.exe"
419Wine-dbg>