README 16 KB

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