Check if dialog is visible before setting the focus.
[wine/multimedia.git] / debugger / info.c
blobbd6abee062a1fb2a2f75fda90b9ac45d6e18f8dc
1 /*
2 * Wine debugger utility routines
4 * Copyright 1993 Eric Youngdale
5 * Copyright 1995 Alexandre Julliard
6 */
8 #include "config.h"
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <string.h>
12 #include "winbase.h"
13 #include "wingdi.h"
14 #include "winuser.h"
15 #include "toolhelp.h"
16 #include "tlhelp32.h"
17 #include "debugger.h"
18 #include "expr.h"
20 /***********************************************************************
21 * DEBUG_PrintBasic
23 * Implementation of the 'print' command.
25 void DEBUG_PrintBasic( const DBG_VALUE* value, int count, char format )
27 char * default_format;
28 long long int res;
30 assert(value->cookie == DV_TARGET || value->cookie == DV_HOST);
31 if( value->type == NULL )
33 DEBUG_Printf(DBG_CHN_MESG, "Unable to evaluate expression\n");
34 return;
37 default_format = NULL;
38 res = DEBUG_GetExprValue(value, &default_format);
40 switch(format)
42 case 'x':
43 if (value->addr.seg)
45 DEBUG_nchar += DEBUG_Printf( DBG_CHN_MESG, "0x%04lx", (long unsigned int) res );
47 else
49 DEBUG_nchar += DEBUG_Printf( DBG_CHN_MESG, "0x%08lx", (long unsigned int) res );
51 break;
53 case 'd':
54 DEBUG_nchar += DEBUG_Printf( DBG_CHN_MESG, "%ld\n", (long int) res );
55 break;
57 case 'c':
58 DEBUG_nchar += DEBUG_Printf( DBG_CHN_MESG, "%d = '%c'",
59 (char)(res & 0xff), (char)(res & 0xff) );
60 break;
62 case 'i':
63 case 's':
64 case 'w':
65 case 'b':
66 DEBUG_Printf( DBG_CHN_MESG, "Format specifier '%c' is meaningless in 'print' command\n", format );
67 case 0:
68 if( default_format != NULL )
70 if (strstr(default_format, "%S") == NULL)
72 DEBUG_nchar += DEBUG_Printf( DBG_CHN_MESG, default_format, res );
74 else
76 char* ptr;
77 int state = 0;
79 /* FIXME: simplistic implementation for default_format being
80 * foo%Sbar => will print foo, then string then bar
82 for (ptr = default_format; *ptr; ptr++)
84 DEBUG_Printf(DBG_CHN_MESG, "[%c]", *ptr);
86 if (*ptr == '%') state++;
87 else if (state == 1)
89 if (*ptr == 'S')
91 char ch;
92 char* str = (char*)(long)res;
94 for (; DEBUG_READ_MEM(str, &ch, 1) && ch; str++) {
95 fputc(ch, stderr);
96 DEBUG_nchar++;
99 else
101 /* shouldn't happen */
102 fputc('%', stderr);
103 fputc(*ptr, stderr);
104 DEBUG_nchar += 2;
106 state = 0;
108 else
110 fputc(*ptr, stderr);
111 DEBUG_nchar++;
116 break;
121 /***********************************************************************
122 * DEBUG_PrintAddress
124 * Print an 16- or 32-bit address, with the nearest symbol if any.
126 struct symbol_info
127 DEBUG_PrintAddress( const DBG_ADDR *addr, int addrlen, int flag )
129 struct symbol_info rtn;
131 const char *name = DEBUG_FindNearestSymbol( addr, flag, &rtn.sym, 0,
132 &rtn.list );
134 if (addr->seg) DEBUG_Printf( DBG_CHN_MESG, "0x%04lx:", addr->seg&0xFFFF );
135 if (addrlen == 16) DEBUG_Printf( DBG_CHN_MESG, "0x%04lx", addr->off );
136 else DEBUG_Printf( DBG_CHN_MESG, "0x%08lx", addr->off );
137 if (name) DEBUG_Printf( DBG_CHN_MESG, " (%s)", name );
138 return rtn;
140 /***********************************************************************
141 * DEBUG_PrintAddressAndArgs
143 * Print an 16- or 32-bit address, with the nearest symbol if any.
144 * Similar to DEBUG_PrintAddress, but we print the arguments to
145 * each function (if known). This is useful in a backtrace.
147 struct symbol_info
148 DEBUG_PrintAddressAndArgs( const DBG_ADDR *addr, int addrlen,
149 unsigned int ebp, int flag )
151 struct symbol_info rtn;
153 const char *name = DEBUG_FindNearestSymbol( addr, flag, &rtn.sym, ebp,
154 &rtn.list );
156 if (addr->seg) DEBUG_Printf( DBG_CHN_MESG, "0x%04lx:", addr->seg );
157 if (addrlen == 16) DEBUG_Printf( DBG_CHN_MESG, "0x%04lx", addr->off );
158 else DEBUG_Printf( DBG_CHN_MESG, "0x%08lx", addr->off );
159 if (name) DEBUG_Printf( DBG_CHN_MESG, " (%s)", name );
161 return rtn;
165 /***********************************************************************
166 * DEBUG_Help
168 * Implementation of the 'help' command.
170 void DEBUG_Help(void)
172 int i = 0;
173 static const char * const helptext[] =
175 "The commands accepted by the Wine debugger are a reasonable",
176 "subset of the commands that gdb accepts.",
177 "The commands currently are:",
178 " help quit",
179 " break [*<addr>] delete break bpnum",
180 " disable bpnum enable bpnum",
181 " condition <bpnum> [<expr>] pass",
182 " bt cont [N]",
183 " step [N] next [N]",
184 " stepi [N] nexti [N]",
185 " x <addr> print <expr>",
186 " set <reg> = <expr> set *<addr> = <expr>",
187 " up down",
188 " list <lines> disassemble [<addr>][,<addr>]",
189 " frame <n> finish",
190 " show dir dir <path>",
191 " display <expr> undisplay <disnum>",
192 " delete display <disnum> debugmsg <class>[-+]<type>\n",
193 " mode [16,32] walk [wnd,class,queue,module,",
194 " whatis process,modref <pid>]",
195 " info (see 'help info' for options)\n",
197 "The 'x' command accepts repeat counts and formats (including 'i') in the",
198 "same way that gdb does.\n",
200 " The following are examples of legal expressions:",
201 " $eax $eax+0x3 0x1000 ($eip + 256) *$eax *($esp + 3)",
202 " Also, a nm format symbol table can be read from a file using the",
203 " symbolfile command. Symbols can also be defined individually with",
204 " the define command.",
206 NULL
209 while(helptext[i]) DEBUG_Printf(DBG_CHN_MESG,"%s\n", helptext[i++]);
213 /***********************************************************************
214 * DEBUG_HelpInfo
216 * Implementation of the 'help info' command.
218 void DEBUG_HelpInfo(void)
220 int i = 0;
221 static const char * const infotext[] =
223 "The info commands allow you to get assorted bits of interesting stuff",
224 "to be displayed. The options are:",
225 " info break Dumps information about breakpoints",
226 " info display Shows auto-display expressions in use",
227 " info locals Displays values of all local vars for current frame",
228 " info maps Dumps all virtual memory mappings",
229 " info module <handle> Displays internal module state",
230 " info queue <handle> Displays internal queue state",
231 " info reg Displays values in all registers at top of stack",
232 " info segments Dumps information about all known segments",
233 " info share Dumps information about shared libraries",
234 " info stack Dumps information about top of stack",
235 " info wnd <handle> Displays internal window state",
237 NULL
240 while(infotext[i]) DEBUG_Printf(DBG_CHN_MESG,"%s\n", infotext[i++]);
243 /* FIXME: merge InfoClass and InfoClass2 */
244 void DEBUG_InfoClass(const char* name)
246 WNDCLASSEXA wca;
248 if (!GetClassInfoEx(0, name, &wca)) {
249 DEBUG_Printf(DBG_CHN_MESG, "Cannot find class '%s'\n", name);
250 return;
253 DEBUG_Printf(DBG_CHN_MESG, "Class '%s':\n", name);
254 DEBUG_Printf(DBG_CHN_MESG,
255 "style=%08x wndProc=%08lx\n"
256 "inst=%04x icon=%04x cursor=%04x bkgnd=%04x\n"
257 "clsExtra=%d winExtra=%d\n",
258 wca.style, (DWORD)wca.lpfnWndProc, wca.hInstance,
259 wca.hIcon, wca.hCursor, wca.hbrBackground,
260 wca.cbClsExtra, wca.cbWndExtra);
262 /* FIXME:
263 * + print #windows (or even list of windows...)
264 * + print extra bytes => this requires a window handle on this very class...
268 static void DEBUG_InfoClass2(HWND hWnd, const char* name)
270 WNDCLASSEXA wca;
272 if (!GetClassInfoEx(GetWindowLong(hWnd, GWL_HINSTANCE), name, &wca)) {
273 DEBUG_Printf(DBG_CHN_MESG, "Cannot find class '%s'\n", name);
274 return;
277 DEBUG_Printf(DBG_CHN_MESG, "Class '%s':\n", name);
278 DEBUG_Printf(DBG_CHN_MESG,
279 "style=%08x wndProc=%08lx\n"
280 "inst=%04x icon=%04x cursor=%04x bkgnd=%04x\n"
281 "clsExtra=%d winExtra=%d\n",
282 wca.style, (DWORD)wca.lpfnWndProc, wca.hInstance,
283 wca.hIcon, wca.hCursor, wca.hbrBackground,
284 wca.cbClsExtra, wca.cbWndExtra);
286 if (wca.cbClsExtra) {
287 int i;
288 WORD w;
290 DEBUG_Printf(DBG_CHN_MESG, "Extra bytes:" );
291 for (i = 0; i < wca.cbClsExtra / 2; i++) {
292 w = GetClassWord(hWnd, i * 2);
293 /* FIXME: depends on i386 endian-ity */
294 DEBUG_Printf(DBG_CHN_MESG, " %02x", HIBYTE(w));
295 DEBUG_Printf(DBG_CHN_MESG, " %02x", LOBYTE(w));
297 DEBUG_Printf(DBG_CHN_MESG, "\n" );
299 DEBUG_Printf(DBG_CHN_MESG, "\n" );
302 struct class_walker {
303 ATOM* table;
304 int used;
305 int alloc;
308 static void DEBUG_WalkClassesHelper(HWND hWnd, struct class_walker* cw)
310 char clsName[128];
311 int i;
312 ATOM atom;
313 HWND child;
315 if (!GetClassName(hWnd, clsName, sizeof(clsName)))
316 return;
317 if ((atom = FindAtom(clsName)) == 0)
318 return;
320 for (i = 0; i < cw->used; i++) {
321 if (cw->table[i] == atom)
322 break;
324 if (i == cw->used) {
325 if (cw->used >= cw->alloc) {
326 cw->alloc += 16;
327 cw->table = DBG_realloc(cw->table, cw->alloc * sizeof(ATOM));
329 cw->table[cw->used++] = atom;
330 DEBUG_InfoClass2(hWnd, clsName);
332 do {
333 if ((child = GetWindow(hWnd, GW_CHILD)) != 0)
334 DEBUG_WalkClassesHelper(child, cw);
335 } while ((hWnd = GetWindow(hWnd, GW_HWNDNEXT)) != 0);
338 void DEBUG_WalkClasses(void)
340 struct class_walker cw;
342 cw.table = NULL;
343 cw.used = cw.alloc = 0;
344 DEBUG_WalkClassesHelper(GetDesktopWindow(), &cw);
345 DBG_free(cw.table);
348 void DEBUG_DumpQueue(DWORD q)
350 DEBUG_Printf(DBG_CHN_MESG, "No longer doing info queue '0x%08lx'\n", q);
353 void DEBUG_WalkQueues(void)
355 DEBUG_Printf(DBG_CHN_MESG, "No longer walking queues list\n");
358 void DEBUG_InfoWindow(HWND hWnd)
360 char clsName[128];
361 char wndName[128];
362 RECT clientRect;
363 RECT windowRect;
364 int i;
365 WORD w;
367 if (!GetClassName(hWnd, clsName, sizeof(clsName)))
368 strcpy(clsName, "-- Unknown --");
369 if (!GetWindowText(hWnd, wndName, sizeof(wndName)))
370 strcpy(wndName, "-- Empty --");
371 if (!GetClientRect(hWnd, &clientRect))
372 SetRectEmpty(&clientRect);
373 if (!GetWindowRect(hWnd, &windowRect))
374 SetRectEmpty(&windowRect);
376 /* FIXME missing fields: hmemTaskQ, hrgnUpdate, dce, flags, pProp, scroll */
377 DEBUG_Printf(DBG_CHN_MESG,
378 "next=0x%04x child=0x%04x parent=0x%04x owner=0x%04x class='%s'\n"
379 "inst=%08lx active=%04x idmenu=%08lx\n"
380 "style=%08lx exstyle=%08lx wndproc=%08lx text='%s'\n"
381 "client=%d,%d-%d,%d window=%d,%d-%d,%d sysmenu=%04x\n",
382 GetWindow(hWnd, GW_HWNDNEXT),
383 GetWindow(hWnd, GW_CHILD),
384 GetParent(hWnd),
385 GetWindow(hWnd, GW_OWNER),
386 clsName,
387 GetWindowLong(hWnd, GWL_HINSTANCE),
388 GetLastActivePopup(hWnd),
389 GetWindowLong(hWnd, GWL_ID),
390 GetWindowLong(hWnd, GWL_STYLE),
391 GetWindowLong(hWnd, GWL_EXSTYLE),
392 GetWindowLong(hWnd, GWL_WNDPROC),
393 wndName,
394 clientRect.left, clientRect.top, clientRect.right, clientRect.bottom,
395 windowRect.left, windowRect.top, windowRect.right, windowRect.bottom,
396 GetSystemMenu(hWnd, FALSE));
398 if (GetClassLong(hWnd, GCL_CBWNDEXTRA)) {
399 DEBUG_Printf(DBG_CHN_MESG, "Extra bytes:" );
400 for (i = 0; i < GetClassLong(hWnd, GCL_CBWNDEXTRA) / 2; i++) {
401 w = GetWindowWord(hWnd, i * 2);
402 /* FIXME: depends on i386 endian-ity */
403 DEBUG_Printf(DBG_CHN_MESG, " %02x", HIBYTE(w));
404 DEBUG_Printf(DBG_CHN_MESG, " %02x", LOBYTE(w));
406 DEBUG_Printf(DBG_CHN_MESG, "\n");
408 DEBUG_Printf(DBG_CHN_MESG, "\n");
411 void DEBUG_WalkWindows(HWND hWnd, int indent)
413 char clsName[128];
414 char wndName[128];
415 HWND child;
417 if (!IsWindow(hWnd))
418 hWnd = GetDesktopWindow();
420 if (!indent) /* first time around */
421 DEBUG_Printf(DBG_CHN_MESG,
422 "%-16.16s %-17.17s %-8.8s %s\n",
423 "hwnd", "Class Name", " Style", " WndProc Text");
425 do {
426 if (!GetClassName(hWnd, clsName, sizeof(clsName)))
427 strcpy(clsName, "-- Unknown --");
428 if (!GetWindowText(hWnd, wndName, sizeof(wndName)))
429 strcpy(wndName, "-- Empty --");
431 /* FIXME: missing hmemTaskQ */
432 DEBUG_Printf(DBG_CHN_MESG, "%*s%04x%*s", indent, "", hWnd, 13-indent,"");
433 DEBUG_Printf(DBG_CHN_MESG, "%-17.17s %08lx %08lx %.14s\n",
434 clsName, GetWindowLong(hWnd, GWL_STYLE),
435 GetWindowLong(hWnd, GWL_WNDPROC), wndName);
437 if ((child = GetWindow(hWnd, GW_CHILD)) != 0)
438 DEBUG_WalkWindows(child, indent + 1 );
439 } while ((hWnd = GetWindow(hWnd, GW_HWNDNEXT)) != 0);
442 void DEBUG_WalkProcess(void)
444 HANDLE snap = CreateToolhelp32Snapshot( TH32CS_SNAPPROCESS, 0 );
445 if (snap != INVALID_HANDLE_VALUE)
447 PROCESSENTRY32 entry;
448 DWORD current = DEBUG_CurrProcess ? DEBUG_CurrProcess->pid : 0;
449 BOOL ok = Process32First( snap, &entry );
451 DEBUG_Printf(DBG_CHN_MESG, "%-8.8s %-8.8s %-8.8s %s\n",
452 "pid", "threads", "parent", "exe" );
453 while (ok)
455 if (entry.th32ProcessID != GetCurrentProcessId())
456 DEBUG_Printf(DBG_CHN_MESG, "%08lx %8d %08lx '%s'%s\n",
457 entry.th32ProcessID, entry.cntThreads,
458 entry.th32ParentProcessID, entry.szExeFile,
459 (entry.th32ProcessID == current) ? " <==" : "" );
460 ok = Process32Next( snap, &entry );
462 CloseHandle( snap );
466 void DEBUG_WalkThreads(void)
468 HANDLE snap = CreateToolhelp32Snapshot( TH32CS_SNAPTHREAD, 0 );
469 if (snap != INVALID_HANDLE_VALUE)
471 THREADENTRY32 entry;
472 DWORD current = DEBUG_CurrThread ? DEBUG_CurrThread->tid : 0;
473 BOOL ok = Thread32First( snap, &entry );
475 DEBUG_Printf(DBG_CHN_MESG, "%-8.8s %-8.8s %s\n",
476 "tid", "process", "prio" );
477 while (ok)
479 if (entry.th32OwnerProcessID != GetCurrentProcessId())
480 DEBUG_Printf(DBG_CHN_MESG, "%08lx %08lx %4ld%s\n",
481 entry.th32ThreadID, entry.th32OwnerProcessID,
482 entry.tbBasePri, (entry.th32ThreadID == current) ? " <==" : "" );
483 ok = Thread32Next( snap, &entry );
485 CloseHandle( snap );
489 void DEBUG_WalkModref(DWORD p)
491 DEBUG_Printf(DBG_CHN_MESG, "No longer walking module references list\n");
494 void DEBUG_InfoSegments(DWORD start, int length)
496 char flags[3];
497 DWORD i;
498 LDT_ENTRY le;
500 if (length == -1) length = (8192 - start);
502 for (i = start; i < start + length; i++)
504 if (!GetThreadSelectorEntry(DEBUG_CurrThread->handle, (i << 3)|7, &le))
505 continue;
507 if (le.HighWord.Bits.Type & 0x08)
509 flags[0] = (le.HighWord.Bits.Type & 0x2) ? 'r' : '-';
510 flags[1] = '-';
511 flags[2] = 'x';
513 else
515 flags[0] = 'r';
516 flags[1] = (le.HighWord.Bits.Type & 0x2) ? 'w' : '-';
517 flags[2] = '-';
519 DEBUG_Printf(DBG_CHN_MESG,
520 "%04lx: sel=%04lx base=%08x limit=%08x %d-bit %c%c%c\n",
521 i, (i<<3)|7,
522 (le.HighWord.Bits.BaseHi << 24) +
523 (le.HighWord.Bits.BaseMid << 16) + le.BaseLow,
524 ((le.HighWord.Bits.LimitHi << 8) + le.LimitLow) <<
525 (le.HighWord.Bits.Granularity ? 12 : 0),
526 le.HighWord.Bits.Default_Big ? 32 : 16,
527 flags[0], flags[1], flags[2] );
531 void DEBUG_InfoVirtual(void)
533 DEBUG_Printf(DBG_CHN_MESG, "No longer providing virtual mapping information\n");