blob: 29b3c16da9b7cd2da5e959f51896273c8ecb376e [file] [log] [blame]
Alexandre Julliardf0b23541993-09-29 12:21:49 +00001/*
2 * Wine debugger utility routines
Alexandre Julliard808cb041995-08-17 17:11:36 +00003 *
4 * Copyright 1993 Eric Youngdale
5 * Copyright 1995 Alexandre Julliard
Alexandre Julliard0799c1a2002-03-09 23:29:33 +00006 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Alexandre Julliardf0b23541993-09-29 12:21:49 +000020 */
21
Marcus Meissnerb0d52b01999-02-28 19:59:00 +000022#include "config.h"
Alexandre Julliardecc37121994-11-22 16:31:29 +000023#include <stdlib.h>
Eric Pouechd33bcb62000-03-15 19:57:20 +000024#include <string.h>
Eric Pouech527eea92000-03-08 16:44:54 +000025#include "winbase.h"
26#include "wingdi.h"
27#include "winuser.h"
Alexandre Julliarda6795412000-04-16 19:46:35 +000028#include "tlhelp32.h"
Alexandre Julliardded30381995-07-06 17:18:27 +000029#include "debugger.h"
Alexandre Julliardc6c09441997-01-12 18:32:19 +000030#include "expr.h"
Alexandre Julliardf0b23541993-09-29 12:21:49 +000031
Alexandre Julliard808cb041995-08-17 17:11:36 +000032/***********************************************************************
Eric Pouechb1518651999-02-20 16:39:51 +000033 * DEBUG_PrintBasic
Alexandre Julliard808cb041995-08-17 17:11:36 +000034 *
35 * Implementation of the 'print' command.
36 */
Eric Pouechd33bcb62000-03-15 19:57:20 +000037void DEBUG_PrintBasic( const DBG_VALUE* value, int count, char format )
Alexandre Julliarde2abbb11995-03-19 17:39:39 +000038{
Eric Pouech7bec5c12002-05-25 21:18:34 +000039 char * default_format;
40 long long int res;
Vincent Béron9a624912002-05-31 23:06:46 +000041
Eric Pouech7bec5c12002-05-25 21:18:34 +000042 assert(value->cookie == DV_TARGET || value->cookie == DV_HOST);
Vincent Béron9a624912002-05-31 23:06:46 +000043 if (value->type == NULL)
Alexandre Julliard808cb041995-08-17 17:11:36 +000044 {
Eric Pouech7bec5c12002-05-25 21:18:34 +000045 DEBUG_Printf(DBG_CHN_MESG, "Unable to evaluate expression\n");
46 return;
Alexandre Julliard808cb041995-08-17 17:11:36 +000047 }
Vincent Béron9a624912002-05-31 23:06:46 +000048
Eric Pouech7bec5c12002-05-25 21:18:34 +000049 default_format = NULL;
50 res = DEBUG_GetExprValue(value, &default_format);
Vincent Béron9a624912002-05-31 23:06:46 +000051
Eric Pouech7bec5c12002-05-25 21:18:34 +000052 switch (format)
Alexandre Julliard808cb041995-08-17 17:11:36 +000053 {
54 case 'x':
Vincent Béron9a624912002-05-31 23:06:46 +000055 if (value->addr.seg)
Alexandre Julliard01d63461997-01-20 19:43:45 +000056 {
Eric Pouech7bec5c12002-05-25 21:18:34 +000057 DEBUG_nchar += DEBUG_Printf(DBG_CHN_MESG, "0x%04lx", (long unsigned int)res);
Alexandre Julliard01d63461997-01-20 19:43:45 +000058 }
Vincent Béron9a624912002-05-31 23:06:46 +000059 else
Alexandre Julliard01d63461997-01-20 19:43:45 +000060 {
Eric Pouech7bec5c12002-05-25 21:18:34 +000061 DEBUG_nchar += DEBUG_Printf(DBG_CHN_MESG, "0x%08lx", (long unsigned int)res);
Alexandre Julliard01d63461997-01-20 19:43:45 +000062 }
Eric Pouech7bec5c12002-05-25 21:18:34 +000063 break;
Vincent Béron9a624912002-05-31 23:06:46 +000064
Alexandre Julliard808cb041995-08-17 17:11:36 +000065 case 'd':
Eric Pouech7bec5c12002-05-25 21:18:34 +000066 DEBUG_nchar += DEBUG_Printf(DBG_CHN_MESG, "%ld\n", (long int)res);
67 break;
Vincent Béron9a624912002-05-31 23:06:46 +000068
Alexandre Julliard808cb041995-08-17 17:11:36 +000069 case 'c':
Eric Pouech7bec5c12002-05-25 21:18:34 +000070 DEBUG_nchar += DEBUG_Printf(DBG_CHN_MESG, "%d = '%c'",
71 (char)(res & 0xff), (char)(res & 0xff));
72 break;
Vincent Béron9a624912002-05-31 23:06:46 +000073
Eric Pouech7bec5c12002-05-25 21:18:34 +000074 case 'u':
75 {
76 WCHAR wch = (WCHAR)(res & 0xFFFF);
77 DEBUG_nchar += DEBUG_Printf(DBG_CHN_MESG, "%d = '", (unsigned)(res & 0xffff));
78 DEBUG_OutputW(DBG_CHN_MESG, &wch, 1);
79 DEBUG_Printf(DBG_CHN_MESG, "'");
80 }
81 break;
Vincent Béron9a624912002-05-31 23:06:46 +000082
Alexandre Julliard808cb041995-08-17 17:11:36 +000083 case 'i':
84 case 's':
85 case 'w':
86 case 'b':
Eric Pouech7bec5c12002-05-25 21:18:34 +000087 DEBUG_Printf(DBG_CHN_MESG, "Format specifier '%c' is meaningless in 'print' command\n", format);
Alexandre Julliardc6c09441997-01-12 18:32:19 +000088 case 0:
Eric Pouech10464c82002-08-02 19:00:53 +000089 if (default_format == NULL) break;
Vincent Béron9a624912002-05-31 23:06:46 +000090
Eric Pouech10464c82002-08-02 19:00:53 +000091 if (strstr(default_format, "%S") != NULL)
92 {
93 char* ptr;
94 int state = 0;
Vincent Béron9a624912002-05-31 23:06:46 +000095
Eric Pouech10464c82002-08-02 19:00:53 +000096 /* FIXME: simplistic implementation for default_format being
97 * foo%Sbar => will print foo, then string then bar
98 */
99 for (ptr = default_format; *ptr; ptr++)
Eric Pouech02ecb682001-12-21 20:29:58 +0000100 {
Eric Pouech10464c82002-08-02 19:00:53 +0000101 if (*ptr == '%')
102 {
103 state++;
104 }
105 else if (state == 1)
106 {
107 if (*ptr == 'S')
108 {
109 DBG_ADDR addr;
110
111 addr.seg = 0;
112 addr.off = (long)res;
113 DEBUG_nchar += DEBUG_PrintStringA(DBG_CHN_MESG, &addr, -1);
114 }
115 else
116 {
117 /* shouldn't happen */
118 DEBUG_Printf(DBG_CHN_MESG, "%%%c", *ptr);
119 DEBUG_nchar += 2;
120 }
121 state = 0;
122 }
123 else
124 {
125 DEBUG_OutputA(DBG_CHN_MESG, ptr, 1);
126 DEBUG_nchar++;
127 }
Eric Pouech02ecb682001-12-21 20:29:58 +0000128 }
Eric Pouech10464c82002-08-02 19:00:53 +0000129 }
130 else if (strcmp(default_format, "%B") == 0)
131 {
132 DEBUG_nchar += DEBUG_Printf(DBG_CHN_MESG, "%s", res ? "true" : "false");
133 }
134 else if (strcmp(default_format, "%R") == 0)
135 {
136 if (value->cookie == DV_HOST)
137 DEBUG_InfoRegisters((CONTEXT*)value->addr.off);
Eric Pouech7bec5c12002-05-25 21:18:34 +0000138 else
Eric Pouech10464c82002-08-02 19:00:53 +0000139 DEBUG_Printf(DBG_CHN_MESG, "NIY: info on register struct in debuggee address space\n");
140 DEBUG_nchar = 0;
141 }
142 else
143 {
144 DEBUG_nchar += DEBUG_Printf(DBG_CHN_MESG, default_format, res);
145 }
Eric Pouech7bec5c12002-05-25 21:18:34 +0000146 break;
Alexandre Julliard808cb041995-08-17 17:11:36 +0000147 }
148}
149
150
151/***********************************************************************
152 * DEBUG_PrintAddress
153 *
154 * Print an 16- or 32-bit address, with the nearest symbol if any.
155 */
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000156struct symbol_info
Alexandre Julliard954a4132000-09-24 03:15:50 +0000157DEBUG_PrintAddress( const DBG_ADDR *addr, enum dbg_mode mode, int flag )
Alexandre Julliard808cb041995-08-17 17:11:36 +0000158{
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000159 struct symbol_info rtn;
160
Vincent Béron9a624912002-05-31 23:06:46 +0000161 const char *name = DEBUG_FindNearestSymbol( addr, flag, &rtn.sym, 0,
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000162 &rtn.list );
Alexandre Julliard808cb041995-08-17 17:11:36 +0000163
Eric Poueche5efa0c2000-04-13 19:31:58 +0000164 if (addr->seg) DEBUG_Printf( DBG_CHN_MESG, "0x%04lx:", addr->seg&0xFFFF );
Alexandre Julliard954a4132000-09-24 03:15:50 +0000165 if (mode != MODE_32) DEBUG_Printf( DBG_CHN_MESG, "0x%04lx", addr->off );
Eric Poueche5efa0c2000-04-13 19:31:58 +0000166 else DEBUG_Printf( DBG_CHN_MESG, "0x%08lx", addr->off );
167 if (name) DEBUG_Printf( DBG_CHN_MESG, " (%s)", name );
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000168 return rtn;
Alexandre Julliard7ebe1a41996-12-22 18:27:48 +0000169}
170/***********************************************************************
171 * DEBUG_PrintAddressAndArgs
172 *
173 * Print an 16- or 32-bit address, with the nearest symbol if any.
174 * Similar to DEBUG_PrintAddress, but we print the arguments to
175 * each function (if known). This is useful in a backtrace.
176 */
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000177struct symbol_info
Alexandre Julliard954a4132000-09-24 03:15:50 +0000178DEBUG_PrintAddressAndArgs( const DBG_ADDR *addr, enum dbg_mode mode,
Alexandre Julliard7ebe1a41996-12-22 18:27:48 +0000179 unsigned int ebp, int flag )
180{
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000181 struct symbol_info rtn;
182
Vincent Béron9a624912002-05-31 23:06:46 +0000183 const char *name = DEBUG_FindNearestSymbol( addr, flag, &rtn.sym, ebp,
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000184 &rtn.list );
Alexandre Julliard7ebe1a41996-12-22 18:27:48 +0000185
Eric Poueche5efa0c2000-04-13 19:31:58 +0000186 if (addr->seg) DEBUG_Printf( DBG_CHN_MESG, "0x%04lx:", addr->seg );
Alexandre Julliard954a4132000-09-24 03:15:50 +0000187 if (mode != MODE_32) DEBUG_Printf( DBG_CHN_MESG, "0x%04lx", addr->off );
Eric Poueche5efa0c2000-04-13 19:31:58 +0000188 else DEBUG_Printf( DBG_CHN_MESG, "0x%08lx", addr->off );
189 if (name) DEBUG_Printf( DBG_CHN_MESG, " (%s)", name );
Alexandre Julliard7ebe1a41996-12-22 18:27:48 +0000190
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000191 return rtn;
Alexandre Julliardf0b23541993-09-29 12:21:49 +0000192}
193
194
Alexandre Julliard808cb041995-08-17 17:11:36 +0000195/***********************************************************************
196 * DEBUG_Help
197 *
198 * Implementation of the 'help' command.
199 */
200void DEBUG_Help(void)
Alexandre Julliardbd34d4f1995-06-20 19:08:12 +0000201{
Alexandre Julliard808cb041995-08-17 17:11:36 +0000202 int i = 0;
Alexandre Julliardd90840e1996-06-11 16:02:08 +0000203 static const char * const helptext[] =
Alexandre Julliard808cb041995-08-17 17:11:36 +0000204{
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000205"The commands accepted by the Wine debugger are a reasonable",
Alexandre Julliard21979011997-03-05 08:22:35 +0000206"subset of the commands that gdb accepts.",
Alexandre Julliardb1bac321996-12-15 19:45:59 +0000207"The commands currently are:",
Alexandre Julliard410ae4f1999-06-18 18:23:11 +0000208" help quit",
Alexandre Julliard7ebe1a41996-12-22 18:27:48 +0000209" break [*<addr>] delete break bpnum",
210" disable bpnum enable bpnum",
Alexandre Julliard410ae4f1999-06-18 18:23:11 +0000211" condition <bpnum> [<expr>] pass",
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000212" bt cont [N]",
213" step [N] next [N]",
214" stepi [N] nexti [N]",
Alexandre Julliard7ebe1a41996-12-22 18:27:48 +0000215" x <addr> print <expr>",
216" set <reg> = <expr> set *<addr> = <expr>",
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000217" up down",
Alexandre Julliard21979011997-03-05 08:22:35 +0000218" list <lines> disassemble [<addr>][,<addr>]",
219" frame <n> finish",
220" show dir dir <path>",
221" display <expr> undisplay <disnum>",
Marcus Meissner40c11eb1999-01-24 09:37:33 +0000222" delete display <disnum> debugmsg <class>[-+]<type>\n",
Alexandre Julliard954a4132000-09-24 03:15:50 +0000223" mode [16,32,vm86] walk [wnd,class,queue,module,",
Eric Pouechd33bcb62000-03-15 19:57:20 +0000224" whatis process,modref <pid>]",
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000225" info (see 'help info' for options)\n",
Alexandre Julliardb1bac321996-12-15 19:45:59 +0000226
Alexandre Julliardf0b23541993-09-29 12:21:49 +0000227"The 'x' command accepts repeat counts and formats (including 'i') in the",
Alexandre Julliardb1bac321996-12-15 19:45:59 +0000228"same way that gdb does.\n",
229
Alexandre Julliardf0b23541993-09-29 12:21:49 +0000230" The following are examples of legal expressions:",
231" $eax $eax+0x3 0x1000 ($eip + 256) *$eax *($esp + 3)",
232" Also, a nm format symbol table can be read from a file using the",
233" symbolfile command. Symbols can also be defined individually with",
234" the define command.",
235"",
Alexandre Julliard808cb041995-08-17 17:11:36 +0000236NULL
237};
Alexandre Julliardf0b23541993-09-29 12:21:49 +0000238
Eric Poueche5efa0c2000-04-13 19:31:58 +0000239 while(helptext[i]) DEBUG_Printf(DBG_CHN_MESG,"%s\n", helptext[i++]);
Alexandre Julliardf0b23541993-09-29 12:21:49 +0000240}
Alexandre Julliard902da691995-11-05 14:39:02 +0000241
242
Alexandre Julliard902da691995-11-05 14:39:02 +0000243/***********************************************************************
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000244 * DEBUG_HelpInfo
Alexandre Julliard902da691995-11-05 14:39:02 +0000245 *
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000246 * Implementation of the 'help info' command.
Alexandre Julliard902da691995-11-05 14:39:02 +0000247 */
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000248void DEBUG_HelpInfo(void)
Alexandre Julliard902da691995-11-05 14:39:02 +0000249{
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000250 int i = 0;
251 static const char * const infotext[] =
252{
253"The info commands allow you to get assorted bits of interesting stuff",
254"to be displayed. The options are:",
255" info break Dumps information about breakpoints",
256" info display Shows auto-display expressions in use",
257" info locals Displays values of all local vars for current frame",
Alexandre Julliard889f7421997-04-15 17:19:52 +0000258" info maps Dumps all virtual memory mappings",
Alexandre Julliard44ed71f1997-12-21 19:17:50 +0000259" info module <handle> Displays internal module state",
260" info queue <handle> Displays internal queue state",
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000261" info reg Displays values in all registers at top of stack",
262" info segments Dumps information about all known segments",
263" info share Dumps information about shared libraries",
264" info stack Dumps information about top of stack",
Alexandre Julliard44ed71f1997-12-21 19:17:50 +0000265" info wnd <handle> Displays internal window state",
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000266"",
267NULL
268};
Alexandre Julliard902da691995-11-05 14:39:02 +0000269
Eric Poueche5efa0c2000-04-13 19:31:58 +0000270 while(infotext[i]) DEBUG_Printf(DBG_CHN_MESG,"%s\n", infotext[i++]);
Alexandre Julliard902da691995-11-05 14:39:02 +0000271}
Eric Pouech527eea92000-03-08 16:44:54 +0000272
273/* FIXME: merge InfoClass and InfoClass2 */
274void DEBUG_InfoClass(const char* name)
275{
276 WNDCLASSEXA wca;
277
Eric Poueche5efa0c2000-04-13 19:31:58 +0000278 if (!GetClassInfoEx(0, name, &wca)) {
279 DEBUG_Printf(DBG_CHN_MESG, "Cannot find class '%s'\n", name);
Eric Pouech527eea92000-03-08 16:44:54 +0000280 return;
281 }
282
Eric Poueche5efa0c2000-04-13 19:31:58 +0000283 DEBUG_Printf(DBG_CHN_MESG, "Class '%s':\n", name);
Vincent Béron9a624912002-05-31 23:06:46 +0000284 DEBUG_Printf(DBG_CHN_MESG,
Eric Poueche5efa0c2000-04-13 19:31:58 +0000285 "style=%08x wndProc=%08lx\n"
François Gougetd5042c42000-12-29 05:38:00 +0000286 "inst=%p icon=%p cursor=%p bkgnd=%p\n"
Eric Poueche5efa0c2000-04-13 19:31:58 +0000287 "clsExtra=%d winExtra=%d\n",
288 wca.style, (DWORD)wca.lpfnWndProc, wca.hInstance,
289 wca.hIcon, wca.hCursor, wca.hbrBackground,
290 wca.cbClsExtra, wca.cbWndExtra);
Eric Pouech527eea92000-03-08 16:44:54 +0000291
Vincent Béron9a624912002-05-31 23:06:46 +0000292 /* FIXME:
Eric Pouech527eea92000-03-08 16:44:54 +0000293 * + print #windows (or even list of windows...)
294 * + print extra bytes => this requires a window handle on this very class...
295 */
296}
297
298static void DEBUG_InfoClass2(HWND hWnd, const char* name)
299{
300 WNDCLASSEXA wca;
301
François Gougetd5042c42000-12-29 05:38:00 +0000302 if (!GetClassInfoEx((HINSTANCE)GetWindowLong(hWnd, GWL_HINSTANCE), name, &wca)) {
Eric Poueche5efa0c2000-04-13 19:31:58 +0000303 DEBUG_Printf(DBG_CHN_MESG, "Cannot find class '%s'\n", name);
Eric Pouech527eea92000-03-08 16:44:54 +0000304 return;
305 }
306
Eric Poueche5efa0c2000-04-13 19:31:58 +0000307 DEBUG_Printf(DBG_CHN_MESG, "Class '%s':\n", name);
Vincent Béron9a624912002-05-31 23:06:46 +0000308 DEBUG_Printf(DBG_CHN_MESG,
Eric Poueche5efa0c2000-04-13 19:31:58 +0000309 "style=%08x wndProc=%08lx\n"
François Gougetd5042c42000-12-29 05:38:00 +0000310 "inst=%p icon=%p cursor=%p bkgnd=%p\n"
Eric Poueche5efa0c2000-04-13 19:31:58 +0000311 "clsExtra=%d winExtra=%d\n",
312 wca.style, (DWORD)wca.lpfnWndProc, wca.hInstance,
313 wca.hIcon, wca.hCursor, wca.hbrBackground,
314 wca.cbClsExtra, wca.cbWndExtra);
Eric Pouech527eea92000-03-08 16:44:54 +0000315
316 if (wca.cbClsExtra) {
317 int i;
318 WORD w;
319
Eric Poueche5efa0c2000-04-13 19:31:58 +0000320 DEBUG_Printf(DBG_CHN_MESG, "Extra bytes:" );
Eric Pouech527eea92000-03-08 16:44:54 +0000321 for (i = 0; i < wca.cbClsExtra / 2; i++) {
322 w = GetClassWord(hWnd, i * 2);
323 /* FIXME: depends on i386 endian-ity */
Eric Poueche5efa0c2000-04-13 19:31:58 +0000324 DEBUG_Printf(DBG_CHN_MESG, " %02x", HIBYTE(w));
325 DEBUG_Printf(DBG_CHN_MESG, " %02x", LOBYTE(w));
Eric Pouech527eea92000-03-08 16:44:54 +0000326 }
Eric Poueche5efa0c2000-04-13 19:31:58 +0000327 DEBUG_Printf(DBG_CHN_MESG, "\n" );
Eric Pouech527eea92000-03-08 16:44:54 +0000328 }
Eric Poueche5efa0c2000-04-13 19:31:58 +0000329 DEBUG_Printf(DBG_CHN_MESG, "\n" );
Eric Pouech527eea92000-03-08 16:44:54 +0000330}
331
332struct class_walker {
333 ATOM* table;
334 int used;
335 int alloc;
336};
337
338static void DEBUG_WalkClassesHelper(HWND hWnd, struct class_walker* cw)
339{
340 char clsName[128];
341 int i;
342 ATOM atom;
343 HWND child;
344
Eric Poueche5efa0c2000-04-13 19:31:58 +0000345 if (!GetClassName(hWnd, clsName, sizeof(clsName)))
Eric Pouech527eea92000-03-08 16:44:54 +0000346 return;
Eric Poueche5efa0c2000-04-13 19:31:58 +0000347 if ((atom = FindAtom(clsName)) == 0)
Eric Pouech527eea92000-03-08 16:44:54 +0000348 return;
349
350 for (i = 0; i < cw->used; i++) {
351 if (cw->table[i] == atom)
352 break;
353 }
354 if (i == cw->used) {
355 if (cw->used >= cw->alloc) {
356 cw->alloc += 16;
357 cw->table = DBG_realloc(cw->table, cw->alloc * sizeof(ATOM));
358 }
359 cw->table[cw->used++] = atom;
360 DEBUG_InfoClass2(hWnd, clsName);
361 }
362 do {
363 if ((child = GetWindow(hWnd, GW_CHILD)) != 0)
364 DEBUG_WalkClassesHelper(child, cw);
365 } while ((hWnd = GetWindow(hWnd, GW_HWNDNEXT)) != 0);
366}
367
368void DEBUG_WalkClasses(void)
369{
370 struct class_walker cw;
371
372 cw.table = NULL;
373 cw.used = cw.alloc = 0;
374 DEBUG_WalkClassesHelper(GetDesktopWindow(), &cw);
375 DBG_free(cw.table);
376}
377
Eric Pouech527eea92000-03-08 16:44:54 +0000378void DEBUG_DumpQueue(DWORD q)
379{
Eric Poueche5efa0c2000-04-13 19:31:58 +0000380 DEBUG_Printf(DBG_CHN_MESG, "No longer doing info queue '0x%08lx'\n", q);
Eric Pouech527eea92000-03-08 16:44:54 +0000381}
382
383void DEBUG_WalkQueues(void)
384{
Eric Poueche5efa0c2000-04-13 19:31:58 +0000385 DEBUG_Printf(DBG_CHN_MESG, "No longer walking queues list\n");
Eric Pouech527eea92000-03-08 16:44:54 +0000386}
387
388void DEBUG_InfoWindow(HWND hWnd)
389{
390 char clsName[128];
391 char wndName[128];
392 RECT clientRect;
393 RECT windowRect;
394 int i;
395 WORD w;
396
Eric Poueche5efa0c2000-04-13 19:31:58 +0000397 if (!GetClassName(hWnd, clsName, sizeof(clsName)))
Eric Pouech527eea92000-03-08 16:44:54 +0000398 strcpy(clsName, "-- Unknown --");
Eric Poueche5efa0c2000-04-13 19:31:58 +0000399 if (!GetWindowText(hWnd, wndName, sizeof(wndName)))
Eric Pouech527eea92000-03-08 16:44:54 +0000400 strcpy(wndName, "-- Empty --");
401 if (!GetClientRect(hWnd, &clientRect))
402 SetRectEmpty(&clientRect);
403 if (!GetWindowRect(hWnd, &windowRect))
404 SetRectEmpty(&windowRect);
405
406 /* FIXME missing fields: hmemTaskQ, hrgnUpdate, dce, flags, pProp, scroll */
Eric Poueche5efa0c2000-04-13 19:31:58 +0000407 DEBUG_Printf(DBG_CHN_MESG,
François Gougetd5042c42000-12-29 05:38:00 +0000408 "next=%p child=%p parent=%p owner=%p class='%s'\n"
409 "inst=%p active=%p idmenu=%08lx\n"
Eric Poueche5efa0c2000-04-13 19:31:58 +0000410 "style=%08lx exstyle=%08lx wndproc=%08lx text='%s'\n"
François Gougetd5042c42000-12-29 05:38:00 +0000411 "client=%d,%d-%d,%d window=%d,%d-%d,%d sysmenu=%p\n",
Vincent Béron9a624912002-05-31 23:06:46 +0000412 GetWindow(hWnd, GW_HWNDNEXT),
Eric Poueche5efa0c2000-04-13 19:31:58 +0000413 GetWindow(hWnd, GW_CHILD),
Vincent Béron9a624912002-05-31 23:06:46 +0000414 GetParent(hWnd),
Eric Poueche5efa0c2000-04-13 19:31:58 +0000415 GetWindow(hWnd, GW_OWNER),
416 clsName,
Vincent Béron9a624912002-05-31 23:06:46 +0000417 (HINSTANCE)GetWindowLong(hWnd, GWL_HINSTANCE),
Eric Poueche5efa0c2000-04-13 19:31:58 +0000418 GetLastActivePopup(hWnd),
419 GetWindowLong(hWnd, GWL_ID),
420 GetWindowLong(hWnd, GWL_STYLE),
421 GetWindowLong(hWnd, GWL_EXSTYLE),
422 GetWindowLong(hWnd, GWL_WNDPROC),
Vincent Béron9a624912002-05-31 23:06:46 +0000423 wndName,
424 clientRect.left, clientRect.top, clientRect.right, clientRect.bottom,
425 windowRect.left, windowRect.top, windowRect.right, windowRect.bottom,
Eric Poueche5efa0c2000-04-13 19:31:58 +0000426 GetSystemMenu(hWnd, FALSE));
Eric Pouech527eea92000-03-08 16:44:54 +0000427
Eric Poueche5efa0c2000-04-13 19:31:58 +0000428 if (GetClassLong(hWnd, GCL_CBWNDEXTRA)) {
429 DEBUG_Printf(DBG_CHN_MESG, "Extra bytes:" );
430 for (i = 0; i < GetClassLong(hWnd, GCL_CBWNDEXTRA) / 2; i++) {
Eric Pouech527eea92000-03-08 16:44:54 +0000431 w = GetWindowWord(hWnd, i * 2);
432 /* FIXME: depends on i386 endian-ity */
Eric Pouech66dbcaf2002-02-26 00:36:46 +0000433 DEBUG_Printf(DBG_CHN_MESG, " %02x", HIBYTE(w));
434 DEBUG_Printf(DBG_CHN_MESG, " %02x", LOBYTE(w));
Eric Pouech527eea92000-03-08 16:44:54 +0000435 }
Eric Poueche5efa0c2000-04-13 19:31:58 +0000436 DEBUG_Printf(DBG_CHN_MESG, "\n");
Eric Pouech527eea92000-03-08 16:44:54 +0000437 }
Eric Poueche5efa0c2000-04-13 19:31:58 +0000438 DEBUG_Printf(DBG_CHN_MESG, "\n");
Eric Pouech527eea92000-03-08 16:44:54 +0000439}
440
441void DEBUG_WalkWindows(HWND hWnd, int indent)
442{
443 char clsName[128];
444 char wndName[128];
445 HWND child;
446
447 if (!IsWindow(hWnd))
448 hWnd = GetDesktopWindow();
449
450 if (!indent) /* first time around */
Vincent Béron9a624912002-05-31 23:06:46 +0000451 DEBUG_Printf(DBG_CHN_MESG,
Eric Poueche5efa0c2000-04-13 19:31:58 +0000452 "%-16.16s %-17.17s %-8.8s %s\n",
453 "hwnd", "Class Name", " Style", " WndProc Text");
Eric Pouech527eea92000-03-08 16:44:54 +0000454
455 do {
Eric Poueche5efa0c2000-04-13 19:31:58 +0000456 if (!GetClassName(hWnd, clsName, sizeof(clsName)))
Eric Pouech527eea92000-03-08 16:44:54 +0000457 strcpy(clsName, "-- Unknown --");
Eric Poueche5efa0c2000-04-13 19:31:58 +0000458 if (!GetWindowText(hWnd, wndName, sizeof(wndName)))
Eric Pouech527eea92000-03-08 16:44:54 +0000459 strcpy(wndName, "-- Empty --");
Vincent Béron9a624912002-05-31 23:06:46 +0000460
Eric Pouech527eea92000-03-08 16:44:54 +0000461 /* FIXME: missing hmemTaskQ */
François Gougetd5042c42000-12-29 05:38:00 +0000462 DEBUG_Printf(DBG_CHN_MESG, "%*s%04x%*s", indent, "", (UINT)hWnd, 13-indent,"");
Eric Poueche5efa0c2000-04-13 19:31:58 +0000463 DEBUG_Printf(DBG_CHN_MESG, "%-17.17s %08lx %08lx %.14s\n",
464 clsName, GetWindowLong(hWnd, GWL_STYLE),
465 GetWindowLong(hWnd, GWL_WNDPROC), wndName);
Eric Pouech527eea92000-03-08 16:44:54 +0000466
467 if ((child = GetWindow(hWnd, GW_CHILD)) != 0)
468 DEBUG_WalkWindows(child, indent + 1 );
469 } while ((hWnd = GetWindow(hWnd, GW_HWNDNEXT)) != 0);
470}
471
472void DEBUG_WalkProcess(void)
473{
Alexandre Julliarda6795412000-04-16 19:46:35 +0000474 HANDLE snap = CreateToolhelp32Snapshot( TH32CS_SNAPPROCESS, 0 );
475 if (snap != INVALID_HANDLE_VALUE)
476 {
477 PROCESSENTRY32 entry;
478 DWORD current = DEBUG_CurrProcess ? DEBUG_CurrProcess->pid : 0;
Eric Pouechf1822352000-05-11 21:43:43 +0000479 BOOL ok;
480
Eric Pouech66dbcaf2002-02-26 00:36:46 +0000481 entry.dwSize = sizeof(entry);
482 ok = Process32First( snap, &entry );
Alexandre Julliarda6795412000-04-16 19:46:35 +0000483
Eric Pouech66dbcaf2002-02-26 00:36:46 +0000484 DEBUG_Printf(DBG_CHN_MESG, " %-8.8s %-8.8s %-8.8s %s\n",
485 "pid", "threads", "parent", "executable" );
Alexandre Julliarda6795412000-04-16 19:46:35 +0000486 while (ok)
487 {
488 if (entry.th32ProcessID != GetCurrentProcessId())
Eric Pouech66dbcaf2002-02-26 00:36:46 +0000489 DEBUG_Printf(DBG_CHN_MESG, "%c%08lx %-8ld %08lx '%s'\n",
490 (entry.th32ProcessID == current) ? '>' : ' ',
Alexandre Julliarda6795412000-04-16 19:46:35 +0000491 entry.th32ProcessID, entry.cntThreads,
Eric Pouech66dbcaf2002-02-26 00:36:46 +0000492 entry.th32ParentProcessID, entry.szExeFile);
Alexandre Julliarda6795412000-04-16 19:46:35 +0000493 ok = Process32Next( snap, &entry );
494 }
495 CloseHandle( snap );
496 }
497}
498
499void DEBUG_WalkThreads(void)
500{
501 HANDLE snap = CreateToolhelp32Snapshot( TH32CS_SNAPTHREAD, 0 );
502 if (snap != INVALID_HANDLE_VALUE)
503 {
Eric Pouech800773f2001-08-06 17:51:52 +0000504 THREADENTRY32 entry;
505 DWORD current = DEBUG_CurrThread ? DEBUG_CurrThread->tid : 0;
506 BOOL ok;
507 DWORD lastProcessId = 0;
Eric Pouechf1822352000-05-11 21:43:43 +0000508
Eric Pouech800773f2001-08-06 17:51:52 +0000509 entry.dwSize = sizeof(entry);
510 ok = Thread32First( snap, &entry );
Alexandre Julliarda6795412000-04-16 19:46:35 +0000511
Eric Pouech800773f2001-08-06 17:51:52 +0000512 DEBUG_Printf(DBG_CHN_MESG, "%-8.8s %-8.8s %s\n", "process", "tid", "prio" );
Alexandre Julliarda6795412000-04-16 19:46:35 +0000513 while (ok)
514 {
515 if (entry.th32OwnerProcessID != GetCurrentProcessId())
Eric Pouech800773f2001-08-06 17:51:52 +0000516 {
517 /* FIXME: this assumes that, in the snapshot, all threads of a same process are
518 * listed sequentially, which is not specified in the doc (Wine's implementation
519 * does it)
520 */
521 if (entry.th32OwnerProcessID != lastProcessId)
522 {
523 DBG_PROCESS* p = DEBUG_GetProcess(entry.th32OwnerProcessID);
524
Vincent Béron9a624912002-05-31 23:06:46 +0000525 DEBUG_Printf(DBG_CHN_MESG, "%08lx%s %s\n",
Eric Pouech800773f2001-08-06 17:51:52 +0000526 entry.th32OwnerProcessID, p ? " (D)" : "", p ? p->imageName : "");
527 lastProcessId = entry.th32OwnerProcessID;
528 }
529 DEBUG_Printf(DBG_CHN_MESG, "\t%08lx %4ld%s\n",
Vincent Béron9a624912002-05-31 23:06:46 +0000530 entry.th32ThreadID, entry.tpBasePri,
Eric Pouech800773f2001-08-06 17:51:52 +0000531 (entry.th32ThreadID == current) ? " <==" : "");
532
533 }
Alexandre Julliarda6795412000-04-16 19:46:35 +0000534 ok = Thread32Next( snap, &entry );
535 }
Eric Pouech800773f2001-08-06 17:51:52 +0000536
Alexandre Julliarda6795412000-04-16 19:46:35 +0000537 CloseHandle( snap );
538 }
Eric Pouech527eea92000-03-08 16:44:54 +0000539}
540
541void DEBUG_WalkModref(DWORD p)
542{
Eric Poueche5efa0c2000-04-13 19:31:58 +0000543 DEBUG_Printf(DBG_CHN_MESG, "No longer walking module references list\n");
Eric Pouech527eea92000-03-08 16:44:54 +0000544}
545
Alexandre Julliard3972efa2002-08-13 18:04:01 +0000546/***********************************************************************
547 * DEBUG_WalkExceptions
548 *
549 * Walk the exception frames of a given thread.
550 */
551void DEBUG_WalkExceptions(DWORD tid)
552{
553 DBG_THREAD * thread;
554 void *next_frame;
555
556 DEBUG_Printf( DBG_CHN_MESG, "Exception frames:\n" );
557
558 if (tid == DEBUG_CurrTid) thread = DEBUG_CurrThread;
559 else
560 {
561 thread = DEBUG_GetThread(DEBUG_CurrProcess, tid);
562
563 if (!thread)
564 {
565 DEBUG_Printf( DBG_CHN_MESG, "Unknown thread id (0x%08lx) in current process\n", tid);
566 return;
567 }
568 if (SuspendThread( thread->handle ) == -1)
569 {
570 DEBUG_Printf( DBG_CHN_MESG, "Can't suspend thread id (0x%08lx)\n", tid);
571 return;
572 }
573 }
574
575 if (!DEBUG_READ_MEM(thread->teb, &next_frame, sizeof(next_frame)))
576 {
577 DEBUG_Printf( DBG_CHN_MESG, "Can't read TEB:except_frame\n");
578 return;
579 }
580
581 while (next_frame != (void *)-1)
582 {
583 EXCEPTION_FRAME frame;
584
585 DEBUG_Printf( DBG_CHN_MESG, "%p: ", next_frame );
586 if (!DEBUG_READ_MEM(next_frame, &frame, sizeof(frame)))
587 {
588 DEBUG_Printf( DBG_CHN_MESG, "Invalid frame address\n" );
589 break;
590 }
591 DEBUG_Printf( DBG_CHN_MESG, "prev=%p handler=%p\n", frame.Prev, frame.Handler );
592 next_frame = frame.Prev;
593 }
594
595 if (tid != DEBUG_CurrTid) ResumeThread( thread->handle );
596}
597
598
Eric Pouech527eea92000-03-08 16:44:54 +0000599void DEBUG_InfoSegments(DWORD start, int length)
600{
601 char flags[3];
602 DWORD i;
603 LDT_ENTRY le;
604
605 if (length == -1) length = (8192 - start);
606
607 for (i = start; i < start + length; i++)
608 {
609 if (!GetThreadSelectorEntry(DEBUG_CurrThread->handle, (i << 3)|7, &le))
610 continue;
611
Vincent Béron9a624912002-05-31 23:06:46 +0000612 if (le.HighWord.Bits.Type & 0x08)
Eric Pouech527eea92000-03-08 16:44:54 +0000613 {
614 flags[0] = (le.HighWord.Bits.Type & 0x2) ? 'r' : '-';
615 flags[1] = '-';
616 flags[2] = 'x';
617 }
618 else
619 {
620 flags[0] = 'r';
621 flags[1] = (le.HighWord.Bits.Type & 0x2) ? 'w' : '-';
622 flags[2] = '-';
623 }
Vincent Béron9a624912002-05-31 23:06:46 +0000624 DEBUG_Printf(DBG_CHN_MESG,
Eric Poueche5efa0c2000-04-13 19:31:58 +0000625 "%04lx: sel=%04lx base=%08x limit=%08x %d-bit %c%c%c\n",
Vincent Béron9a624912002-05-31 23:06:46 +0000626 i, (i<<3)|7,
627 (le.HighWord.Bits.BaseHi << 24) +
Eric Poueche5efa0c2000-04-13 19:31:58 +0000628 (le.HighWord.Bits.BaseMid << 16) + le.BaseLow,
Vincent Béron9a624912002-05-31 23:06:46 +0000629 ((le.HighWord.Bits.LimitHi << 8) + le.LimitLow) <<
Eric Poueche5efa0c2000-04-13 19:31:58 +0000630 (le.HighWord.Bits.Granularity ? 12 : 0),
631 le.HighWord.Bits.Default_Big ? 32 : 16,
632 flags[0], flags[1], flags[2] );
Eric Pouech527eea92000-03-08 16:44:54 +0000633 }
634}
635
636void DEBUG_InfoVirtual(void)
637{
Eric Pouech26c1c422002-06-02 21:36:08 +0000638 MEMORY_BASIC_INFORMATION mbi;
639 char* addr = 0;
640 char* state;
641 char* type;
642 char prot[3+1];
643
644 if (DEBUG_CurrProcess == NULL)
645 return;
646
647 DEBUG_Printf(DBG_CHN_MESG, "Address Size State Type RWX\n");
648
649 while (VirtualQueryEx(DEBUG_CurrProcess->handle, addr, &mbi, sizeof(mbi)) >= sizeof(mbi))
650 {
651 switch (mbi.State)
652 {
653 case MEM_COMMIT: state = "commit "; break;
654 case MEM_FREE: state = "free "; break;
655 case MEM_RESERVE: state = "reserve"; break;
656 default: state = "??? "; break;
657 }
658 if (mbi.State != MEM_FREE)
659 {
660 switch (mbi.Type)
661 {
662 case MEM_IMAGE: type = "image "; break;
663 case MEM_MAPPED: type = "mapped "; break;
664 case MEM_PRIVATE: type = "private"; break;
665 case 0: type = " "; break;
666 default: type = "??? "; break;
667 }
668 memset(prot, ' ' , sizeof(prot)-1);
669 prot[sizeof(prot)-1] = '\0';
670 if (mbi.AllocationProtect & (PAGE_READONLY|PAGE_READWRITE|PAGE_EXECUTE_READ|PAGE_EXECUTE_READWRITE))
671 prot[0] = 'R';
672 if (mbi.AllocationProtect & (PAGE_READWRITE|PAGE_EXECUTE_READWRITE))
673 prot[1] = 'W';
674 if (mbi.AllocationProtect & (PAGE_WRITECOPY|PAGE_EXECUTE_WRITECOPY))
675 prot[1] = 'C';
676 if (mbi.AllocationProtect & (PAGE_EXECUTE|PAGE_EXECUTE_READ|PAGE_EXECUTE_READWRITE))
677 prot[2] = 'X';
678 }
679 else
680 {
681 type = "";
682 prot[0] = '\0';
683 }
684 DEBUG_Printf(DBG_CHN_MESG, "%08lx %08lx %s %s %s\n",
685 (DWORD)addr, mbi.RegionSize, state, type, prot);
686 if (addr + mbi.RegionSize < addr) /* wrap around ? */
687 break;
688 addr += mbi.RegionSize;
689 }
Eric Pouech527eea92000-03-08 16:44:54 +0000690}
Eric Pouech26c1c422002-06-02 21:36:08 +0000691
692struct dll_option_layout
693{
694 void* next;
695 void* prev;
696 char* const* channels;
697 int nb_channels;
698};
699
700void DEBUG_DbgChannel(BOOL turn_on, const char* chnl, const char* name)
701{
702 DBG_VALUE val;
703 struct dll_option_layout dol;
704 int i;
705 char* str;
706 unsigned char buffer[32];
707 unsigned char mask;
708 int done = 0;
709 BOOL bAll;
710 void* addr;
711
712 if (!DEBUG_GetSymbolValue("first_dll", -1, &val, FALSE))
713 {
714 DEBUG_Printf(DBG_CHN_MESG, "Can't get first_option symbol");
715 return;
716 }
717 addr = (void*)DEBUG_ToLinear(&val.addr);
718 if (!chnl) mask = 15;
719 else if (!strcmp(chnl, "fixme")) mask = 1;
720 else if (!strcmp(chnl, "err")) mask = 2;
721 else if (!strcmp(chnl, "warn")) mask = 4;
722 else if (!strcmp(chnl, "trace")) mask = 8;
723 else { DEBUG_Printf(DBG_CHN_MESG, "Unknown channel %s\n", chnl); return; }
Eric Pouech10464c82002-08-02 19:00:53 +0000724
Eric Pouech26c1c422002-06-02 21:36:08 +0000725 bAll = !strcmp("all", name);
726 while (addr && DEBUG_READ_MEM(addr, &dol, sizeof(dol)))
727 {
728 for (i = 0; i < dol.nb_channels; i++)
729 {
730 if (DEBUG_READ_MEM((void*)(dol.channels + i), &str, sizeof(str)) &&
731 DEBUG_READ_MEM(str, buffer, sizeof(buffer)) &&
732 (!strcmp(buffer + 1, name) || bAll))
Eric Pouech10464c82002-08-02 19:00:53 +0000733 {
Eric Pouech26c1c422002-06-02 21:36:08 +0000734 if (turn_on) buffer[0] |= mask; else buffer[0] &= ~mask;
735 if (DEBUG_WRITE_MEM(str, buffer, 1)) done++;
736 }
737 }
738 addr = dol.next;
739 }
740 if (!done) DEBUG_Printf(DBG_CHN_MESG, "Unable to find debug channel %s\n", name);
741 else DEBUG_Printf(DBG_CHN_TRACE, "Changed %d channel instances\n", done);
742}