Set console video mode when loading DOS app. (Eventually, I want to
[wine/multimedia.git] / debugger / README
blob412b7e8c8b12bee526edcbcc19655aea2d002c76
1         This is the core of the Wine debugger.  The reverse assember
2 was stolen from Mach more or less intact.  It turns out that there are
3 two variables that are set differently if you are reverse assembling
4 16 bit code, and on the whole it seems to work.
6 NEWS:
8         The internal debugger has *tons* more capability than it did before.
9 I have enclosed some examples that show usage at the end of this file.
10 New features include:
12         1) Ability of debugger to read debug information from wine executable
13 *and* from Win32 executables.  Local variable and line number information is
14 also read and processed.
16         2) The internal debugger is capable of 'stepping' to the next
17 line number, just like gdb.  Examples of the commands are:
19         step
20         stepi
21         si
22         step 3
23         si 5
24         next
25         nexti
26         cont 4
27         finish
29 All of these should be exactly like how gdb does things.
31         3) The internal debugger now has a sense of what source file and line
32 number a given PC is at.  New commands to support this are just like gdb,
33 and include:
35         list
36         dir
37         show dir
39 there are a variety of formats of arguments for the list command.  All
40 permutations supported by gdb should also be supported.
42         4) The internal debugger knows about datatypes of various objects,
43 for both Win32 *and* the debugging information in the wine executable itself.
44 I have enclosed an example of how this works at the end.
46         5) There are more ways the 'b' command can be used to set breakpoints.
47 Examples are:
49         b *0x8190000
50         b 1100
51         b Usage
52         b
54 I don't think this covers all of the permutations that gdb accepts (this should
55 be cleaned up someday so that all possibilities are acceptable).
57         6)  The 'print' and 'x' commands should behave more or less exactly
58 as they do under gdb.  The difference is that the way the data is presented
59 will be slightly different, but the content should be fundamentally the same.
61         7) The internal debugger now supports conditional breakpoints, and
62 automatic display expressions.  An example is at the end of this file.  The
63 syntax and usage should be identical to that of gdb.
65         8) Type casts can be made from within the debugger, but they currently
66 don't work with typedef'ed types.  They only work with builtin types and
67 named structures unions, etc.  The problem is that internally we don't always
68 record the typedefed names of structures, so we have no guarantee that we
69 would know what each type is.  This can be fixed, of course -  it just takes
70 more memory.  Note that in some cases, typedefed structures could be cast
71 using '(struct typedfname)' instead of '(typedfname)'.   Technically this
72 isn't quite correct, but if and when the rest of this stuff gets fixed,
73 this would need to get corrected too.
75 NOTES:
77         If it weren't for the fact that gdb doesn't grok the Win32 debug
78 information, you could just use gdb.  The internal debugger should be able
79 to read and use debugging information for both Win32 and also for the
80 Wine executable, making it possible to debug the combination of the two
81 together as if it were one large (very large) entity.
83 LIMITATIONS AND DIFFERENCES FROM GDB:
85         You cannot set a breakpoint by file and line number as you can
86 with gdb.  Adding support for this wouldn't be all that tough, I guess, but
87 it would be a nuisance.   You can set a breakpoint given a function and
88 line number, however.  An example would be 'b main:2993'.  It turns out
89 that the way the internal data structures are arranged it is a whole lot
90 easier to do things in this way than it would be to try and get the
91 source:line type of breakpoint working, but it would probably be worth it
92 to try.
94         Getting stack traces through Wine itself can be a bit tricky.
95 This is because by default the thing is built with optimization
96 enabled, and as a result sometimes functions don't get frames, and
97 lots of variables are optimized into registers.  You can turn off
98 optimization for a few key source files if it will help you.
100         Memory consumption is getting to be a real problem.  I think 32Mb is
101 no longer sufficient to debug wine - 48 or 64 is probably a whole lot better.
102 Unfortunately I cannot shut down X to save memory :-).
104 *************************************************************************
105 EXAMPLES:
107         Here is an example of how I tracked down a bug in Wine.  The program
108 is something that just maps and dumps the contents of a Win32 executable.
109 It was dying for some reason.
111 Start the first time through.
113 bash$ ls -l dumpexe.exe 
114 -rw-rw-r--   1 eric     devel      168448 Jan  4 13:51 dumpexe.exe
115 bash$ ./wine -debug './dumpexe.exe -symbol ./dumpexe.exe'
116 Warning: invalid dir 'e:\test' in path, deleting it.
117 Win32 task 'W32SXXXX': Breakpoint 1 at 0x081a3450
118 Loading symbols from ELF file ./wine...
119 Loading symbols from ELF file /usr/X11R6/lib/libXpm.so.4.6...
120 Loading symbols from ELF file /usr/X11R6/lib/libSM.so.6.0...
121 Loading symbols from ELF file /usr/X11R6/lib/libICE.so.6.0...
122 Loading symbols from ELF file /usr/X11R6/lib/libXext.so.6.0...
123 Loading symbols from ELF file /usr/X11R6/lib/libX11.so.6.0...
124 Loading symbols from ELF file /lib/libm.so.5.0.5...
125 Loading symbols from ELF file /lib/libc.so.5.2.18...
126 Loading symbols from ELF file /lib/ld-linux.so.1...
127 Loading symbols from Win32 file ./dumpexe.exe...
128 Stopped on breakpoint 1 at 0x081a3450 (_mainCRTStartup)
129 In 32 bit mode.
130 *** Invalid address 0x414c5ff8 (\x7fKERNEL32_NULL_THUNK_DATA+0x3930ee6c)
131 0x081a3450 (_mainCRTStartup):  movl     %fs:0,%eax
132 Wine-dbg>b DumpFile
133 Breakpoint 2 at 0x081a0078 (DumpFile+0x9 [dumpexe.c:2723])
134 Wine-dbg>c
135 Dump File: ./dumpexe.exe
136 Stopped on breakpoint 2 at 0x081a0078 (DumpFile+0x9 [dumpexe.c:2723])
137 Enter path to file dumpexe.c: ../de
138 2723            HANDLE                    hFile = NULL;
139 0x081a0078 (DumpFile+0x9 [dumpexe.c:2723]):  movl       $0x0,0xfffffff4(%ebp)
140 Wine-dbg>list
141 2723            HANDLE                    hFile = NULL;
142 2724            HANDLE                    hMap  = NULL;
143 2725            PSTR                      lpMap = NULL;
144 2726            DWORD                     dwFileSize     = 0;
145 2727            DWORD                     dwFileSizeHigh = 0;
146 2728    
147 2729            PIMAGE_DOS_HEADER         lpImageDOS  = NULL;
148 2730            PIMAGE_FILE_HEADER        lpImageFile = NULL;
149 2731            PIMAGE_NT_HEADERS         lpImageNT   = NULL;
150 2732    
151 2733            /*
152 Wine-dbg>n 10
153 2747            dwFileSize = GetFileSize(hFile, &dwFileSizeHigh);
154 0x081a00ea (DumpFile+0x7b [dumpexe.c:2747]):  leal      0xfffffff0(%ebp),%eax
155 Wine-dbg>n
156 2749                && (GetLastError() != NO_ERROR) )\r
157 0x081a00fb (DumpFile+0x8c [dumpexe.c:2749]):  cmpl      $-1,0xffffffe8(%ebp)
158 Wine-dbg>x/d dwFileSize
159 x/d dwFileSize\r
160  168448
161 Wine-dbg>n
162 2758                                     PAGE_READONLY, 0, 0, (LPSTR) NULL);
163 0x081a0124 (DumpFile+0xb5 [dumpexe.c:2758]):  pushl     $0x0
164 Wine-dbg>list 2750
165 list 2750\r
166 2750            {
167 2751                    Fatal("Cannot get size of file %s", lpFileName);
168 2752            }
169 2753            
170 2754            /*
171 2755             * map the file
172 2756             */
173 2757            hMap = CreateFileMapping(hFile, (LPSECURITY_ATTRIBUTES) NULL,
174 2758                                     PAGE_READONLY, 0, 0, (LPSTR) NULL);
175 2759            if( hMap == NULL )
176 2760            {
177 Wine-dbg>n
178 2759            if( hMap == NULL )
179 0x081a013b (DumpFile+0xcc [dumpexe.c:2759]):  cmpl      $0,0xfffffffc(%ebp)
180 Wine-dbg>x hMap
181  08e48c30
182 Wine-dbg>n
183 2767            lpMap = (LPSTR) MapViewOfFile(hMap, FILE_MAP_READ, 0, 0, 0);
184 0x081a0156 (DumpFile+0xe7 [dumpexe.c:2767]):  pushl     $0x0
185 Wine-dbg>n
186 2768            if( lpMap == NULL )
187 0x081a016b (DumpFile+0xfc [dumpexe.c:2768]):  cmpl      $0,0xffffffe0(%ebp)
188 Wine-dbg>print lpMap
189 0x414c5f40
190 Wine-dbg>x lpMap
191  40007000
192 Wine-dbg> x/10x 0x40007000
193  x/10x 0x40007000\r
194 0x40007000 (\x7fKERNEL32_NULL_THUNK_DATA+0x37e4fe74): *** Invalid address 0x40007000 (\x7fKERNEL32_NULL_THUNK_DATA+0x37e4fe74)
195 Wine-dbg>quit
198 *******************************************************************
199 The first time through, we find that MapViewOfFile isn't mapping the file
200 correctly into the virtual address space.  Try running again, and step into
201 MapViewOfFile to figure out what went wrong.
202 *******************************************************************
205 bash$ ./wine -debug './dumpexe.exe -symbol ./dumpexe.exe'
206 Warning: invalid dir 'e:\test' in path, deleting it.
207 Win32 task 'W32SXXXX': Breakpoint 1 at 0x081a3450
208 Loading symbols from ELF file ./wine...
209 Loading symbols from ELF file /usr/X11R6/lib/libXpm.so.4.6...
210 Loading symbols from ELF file /usr/X11R6/lib/libSM.so.6.0...
211 Loading symbols from ELF file /usr/X11R6/lib/libICE.so.6.0...
212 Loading symbols from ELF file /usr/X11R6/lib/libXext.so.6.0...
213 Loading symbols from ELF file /usr/X11R6/lib/libX11.so.6.0...
214 Loading symbols from ELF file /lib/libm.so.5.0.5...
215 Loading symbols from ELF file /lib/libc.so.5.2.18...
216 Loading symbols from ELF file /lib/ld-linux.so.1...
217 Loading symbols from Win32 file ./dumpexe.exe...
218 Stopped on breakpoint 1 at 0x081a3450 (_mainCRTStartup)
219 In 32 bit mode.
220 *** Invalid address 0x414c5ff8 (\x7fKERNEL32_NULL_THUNK_DATA+0x3930ee6c)
221 0x081a3450 (_mainCRTStartup):  movl     %fs:0,%eax
222 Wine-dbg>b DumpFile:2767
223 Breakpoint 2 at 0x081a0156 (DumpFile+0xe7 [dumpexe.c:2767])
224 Wine-dbg>c
225 Dump File: ./dumpexe.exe\r
226 Stopped on breakpoint 2 at 0x081a0156 (DumpFile+0xe7 [dumpexe.c:2767])
227 Enter path to file dumpexe.c: ../de
228 2767            lpMap = (LPSTR) MapViewOfFile(hMap, FILE_MAP_READ, 0, 0, 0);
229 0x081a0156 (DumpFile+0xe7 [dumpexe.c:2767]):  pushl     $0x0
230 Wine-dbg>step
231 390     0385 stdcall MapViewOfFile(long long long long long) MapViewOfFile
232 0x080d793c (KERNEL32_385 [kernel32.spec:390]):  pushl   %ebp
233 Wine-dbg>step
234 223         if (!debugging_relay) return;
235 0x080c83dc (RELAY_DebugCallFrom32+0xc [relay.c:223]):  cmpw     $0,0x644a
236 Wine-dbg>
237 244     }
238 0x080c848e (RELAY_DebugCallFrom32+0xbe [relay.c:244]):  leal    0xfffffff4(%ebp),%esp
239 Wine-dbg>
240 103         return MapViewOfFileEx(handle,access,offhi,offlo,size,0);
241 0x080911a4 (MapViewOfFile+0x14 [file.c:103]):  pushl    $0x0
242 Wine-dbg>
243 113         FILEMAP_OBJECT *fmap = (FILEMAP_OBJECT*)handle;
244 0x080911cf (MapViewOfFileEx+0xf [file.c:113]):  movl    0x8(%ebp),%esi
245 Wine-dbg>n
246 115         if (!size) size = fmap->size;
247 0x080911d2 (MapViewOfFileEx+0x12 [file.c:115]):  testl  %ebx,%ebx
248 Wine-dbg>list
249 list\r
250 115         if (!size) size = fmap->size;
251 116         if (!size) size = 1;
252 117         return mmap ((caddr_t)st, size, fmap->prot, 
253 118                      MAP_ANON|MAP_PRIVATE, 
254 119                      FILE_GetUnixHandle(fmap->hfile),
255 120                      offlo);
256 121     }
257 122     
258 123     /***********************************************************************
259 124      *           UnmapViewOfFile                  (KERNEL32.385)
260 125      */
261 Wine-dbg>x size
262  00000000
263 Wine-dbg>n
264 116         if (!size) size = 1;
265 0x080911d9 (MapViewOfFileEx+0x19 [file.c:116]):  testl  %ebx,%ebx
266 Wine-dbg>x size
267  00000000
268 Wine-dbg>n
269 117         return mmap ((caddr_t)st, size, fmap->prot, 
270 0x080911e2 (MapViewOfFileEx+0x22 [file.c:117]):  pushl  %eax
271 Wine-dbg>x size
272  00000000
273 Wine-dbg>info local
274 MapViewOfFileEx:handle == 0x08e48c90
275 MapViewOfFileEx:access == 0x00000004
276 MapViewOfFileEx:offhi == 0x00000000
277 MapViewOfFileEx:offlo == 0x00000000
278 MapViewOfFileEx:size == 0x00000000
279 MapViewOfFileEx:st == 0x00000000
280 MapViewOfFileEx:offlo optimized into register $eax 
281 MapViewOfFileEx:size optimized into register $ebx 
282 MapViewOfFileEx:st optimized into register $edi 
283 MapViewOfFileEx:fmap optimized into register $esi 
284 Wine-dbg>print $ebx
285 0x0001
286 Wine-dbg>bt
287 bt\r
288 Backtrace:
289 =>0 0x080911e2 (MapViewOfFileEx+0x22 [file.c:117])
290   1 0x080911b0 (MapViewOfFile+0x20(handle=0x8e48c90, access=0x4, offhi=0x0, offlo=0x0, size=0x0) [file.c:104])
291   2 0x08104ab5 (CallFrom32_stdcall_5+0x25 [callfrom32.s])
292   3 0x081a0168 (DumpFile+0xf9(lpFileName=0x414c61ed) [dumpexe.c:2767])
293   4 0x081a0c35 (main+0x410(argc=0x3, argv=0x414c61cc) [dumpexe.c:3078])
294   5 0x081a3514 (_mainCRTStartup+0xc4)
295   6 0x0810549f (Code_Start+0x13 [callto32.s])
296   7 0x0802fdac (TASK_CallToStart+0x8c [task.c:373])
298 Wine-dbg>
300 *******************************************************************
301 Notice that you can step through the thunks into our own transfer
302 routines.   You will notice that the source line displays as something
303 like:
305 390     0385 stdcall MapViewOfFile(long long long long long) MapViewOfFile
307 This is just the source line from the spec file that caused the transfer
308 routine to be generated.  From this you can step again, and you step
309 into the relay logging code - keep stepping and you eventually step into
310 the actual function that does the dirty work.
312         At this point an examination of the source to the Win32 program
313 and an examination of the source to win32/file.s showed where the problem
314 was.  When you specify 0 for the size of the object in CreateFileMapping,
315 it is supposed to use the entire size of the file as the size of the
316 object.  Instead we were just blindly copying the number over.
318 *******************************************************************
320 Wine-dbg>b main
321 Breakpoint 1 at 0x080108c0 (main [dbgmain.c:213])
322 Wine-dbg>print breakpoints[1]
323 {addr={type=0x08043000, seg=0, off=134285504}, addrlen=' ', opcode='U', enabled=1, skipcount=0, in_use=1}
325 Wine-dbg> print breakpoints[1].enabled
327 Wine-dbg>set breakpoints[0].enabled = 0
328 Wine-dbg>print breakpoints[0].enabled
331 Wine-dbg>print type_hash_table[1]->type
332 STRUCT
334 Wine-dbg>print type_hash_table[1]
335 0x08072020
336 Wine-dbg>print *type_hash_table[1]
337 print *type_hash_table[1]\r
338 {type=STRUCT, next=0x00000000, name="LOGPALETTE", un={basic={basic_type=8, output_format=" V\x1d\b M\x1d\b", 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}}}
339 Wine-dbg>
341 *******************************************************************
343         This example shows how you can print out various data structures.
344 Note that enumerated types are displayed in the symbolic form, and strings
345 are displayed in the expected manner.
347         You can use the set command to set more or less anything.  Note
348 however that you cannot use enumerated types on the RHS of the expression.
350 *******************************************************************
353 Wine-dbg>list
354 2986            if( argc <= 1 )
355 2987            {
356 2988                    Usage(argv[0]);
357 2989            }
358 2990
359 2991            for( i = 1; i < argc; i++ )
360 2992            {
361 2993                    if( strncmp(argv[i], "-dos", sizeof("-dos") - 1) == 0 )
362 2994                    {
363 2995                            DmpCtrl.bDumpDOSHeader = TRUE;
364 2996                    }
365 Wine-dbg>b 2993
366 Breakpoint 3 at 0x081a8861 (main+0x3c [dumpexe.c:2993])
367 Wine-dbg>condition 3 i == 2
368 Wine-dbg>c
369 Stopped on breakpoint 3 at 0x081a8861 (main+0x3c [dumpexe.c:2993])
370 2993                    if( strncmp(argv[i], "-dos", sizeof("-dos") - 1) == 0 )
371 0x081a8861 (main+0x3c [dumpexe.c:2993]):  pushl $0x4
372 Wine-dbg>print i
374 Wine-dbg>print argv[i]
375 "./dumpexe.exe"
377 *******************************************************************
379         This example shows how to use conditional breakpoints.
380         Here is another one that demonstrates another cool feature
381         conditional breakpoints that involve a function call:
383                 condition 3 strcmp(argv[i], "./dumpexe.exe") == 0
385 *******************************************************************
388 Wine-dbg>list
389 2986            if( argc <= 1 )
390 2987            {
391 2988                    Usage(argv[0]);
392 2989            }
393 2990
394 2991            for( i = 1; i < argc; i++ )
395 2992            {
396 2993                    if( strncmp(argv[i], "-dos", sizeof("-dos") - 1) == 0 )
397 2994                    {
398 2995                            DmpCtrl.bDumpDOSHeader = TRUE;
399 2996                    }
400 Wine-dbg>b 2993
401 Breakpoint 3 at 0x081a8861 (main+0x3c [dumpexe.c:2993])
402 Wine-dbg>condition 3 strcmp(argv[i], "./dumpexe.exe") == 0
403 Wine-dbg>info break
404 Breakpoints:
405 1: y 0x081ab450 (_mainCRTStartup)
406 2: y 0x081a882e (main+0x9 [dumpexe.c:2986])
407 3: y 0x081a8861 (main+0x3c [dumpexe.c:2993])
408                 stop when  ( strcmp(( argv[i] ), "./dumpexe.exe") == 0 )
409 Wine-dbg>c
410 Stopped on breakpoint 3 at 0x081a8861 (main+0x3c [dumpexe.c:2993])
411 2993                    if( strncmp(argv[i], "-dos", sizeof("-dos") - 1) == 0 )
412 0x081a8861 (main+0x3c [dumpexe.c:2993]):  pushl $0x4
413 Wine-dbg>print i
415 Wine-dbg>print argv[i]  
416 "./dumpexe.exe"
417 Wine-dbg>