Avoid deadlock in VGA_DoSetMode.
[wine/multimedia.git] / debugger / info.c
blob149004959e37ac473df164405e91a71c65cd656e
1 /*
2 * Wine debugger utility routines
4 * Copyright 1993 Eric Youngdale
5 * Copyright 1995 Alexandre Julliard
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.
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.
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
22 #include "config.h"
23 #include <stdlib.h>
24 #include <string.h>
25 #include "winbase.h"
26 #include "wingdi.h"
27 #include "winuser.h"
28 #include "tlhelp32.h"
29 #include "debugger.h"
30 #include "expr.h"
32 /***********************************************************************
33 * DEBUG_PrintBasic
35 * Implementation of the 'print' command.
37 void DEBUG_PrintBasic( const DBG_VALUE* value, int count, char format )
39 char * default_format;
40 long long int res;
42 assert(value->cookie == DV_TARGET || value->cookie == DV_HOST);
43 if( value->type == NULL )
45 DEBUG_Printf(DBG_CHN_MESG, "Unable to evaluate expression\n");
46 return;
49 default_format = NULL;
50 res = DEBUG_GetExprValue(value, &default_format);
52 switch(format)
54 case 'x':
55 if (value->addr.seg)
57 DEBUG_nchar += DEBUG_Printf( DBG_CHN_MESG, "0x%04lx", (long unsigned int) res );
59 else
61 DEBUG_nchar += DEBUG_Printf( DBG_CHN_MESG, "0x%08lx", (long unsigned int) res );
63 break;
65 case 'd':
66 DEBUG_nchar += DEBUG_Printf( DBG_CHN_MESG, "%ld\n", (long int) res );
67 break;
69 case 'c':
70 DEBUG_nchar += DEBUG_Printf( DBG_CHN_MESG, "%d = '%c'",
71 (char)(res & 0xff), (char)(res & 0xff) );
72 break;
74 case 'i':
75 case 's':
76 case 'w':
77 case 'b':
78 DEBUG_Printf( DBG_CHN_MESG, "Format specifier '%c' is meaningless in 'print' command\n", format );
79 case 0:
80 if( default_format != NULL )
82 if (strstr(default_format, "%S") != NULL)
84 char* ptr;
85 int state = 0;
87 /* FIXME: simplistic implementation for default_format being
88 * foo%Sbar => will print foo, then string then bar
90 for (ptr = default_format; *ptr; ptr++)
92 if (*ptr == '%') state++;
93 else if (state == 1)
95 if (*ptr == 'S')
97 char ch;
98 char* str = (char*)(long)res;
100 for (; DEBUG_READ_MEM(str, &ch, 1) && ch; str++) {
101 DEBUG_Output(DBG_CHN_MESG, &ch, 1);
102 DEBUG_nchar++;
105 else
107 /* shouldn't happen */
108 DEBUG_Printf(DBG_CHN_MESG, "%%%c", *ptr);
109 DEBUG_nchar += 2;
111 state = 0;
113 else
115 DEBUG_Output(DBG_CHN_MESG, ptr, 1);
116 DEBUG_nchar++;
120 else if (strcmp(default_format, "%B") == 0)
122 DEBUG_nchar += DEBUG_Printf( DBG_CHN_MESG, "%s", res ? "true" : "false");
124 else
126 DEBUG_nchar += DEBUG_Printf( DBG_CHN_MESG, default_format, res );
129 break;
134 /***********************************************************************
135 * DEBUG_PrintAddress
137 * Print an 16- or 32-bit address, with the nearest symbol if any.
139 struct symbol_info
140 DEBUG_PrintAddress( const DBG_ADDR *addr, enum dbg_mode mode, int flag )
142 struct symbol_info rtn;
144 const char *name = DEBUG_FindNearestSymbol( addr, flag, &rtn.sym, 0,
145 &rtn.list );
147 if (addr->seg) DEBUG_Printf( DBG_CHN_MESG, "0x%04lx:", addr->seg&0xFFFF );
148 if (mode != MODE_32) DEBUG_Printf( DBG_CHN_MESG, "0x%04lx", addr->off );
149 else DEBUG_Printf( DBG_CHN_MESG, "0x%08lx", addr->off );
150 if (name) DEBUG_Printf( DBG_CHN_MESG, " (%s)", name );
151 return rtn;
153 /***********************************************************************
154 * DEBUG_PrintAddressAndArgs
156 * Print an 16- or 32-bit address, with the nearest symbol if any.
157 * Similar to DEBUG_PrintAddress, but we print the arguments to
158 * each function (if known). This is useful in a backtrace.
160 struct symbol_info
161 DEBUG_PrintAddressAndArgs( const DBG_ADDR *addr, enum dbg_mode mode,
162 unsigned int ebp, int flag )
164 struct symbol_info rtn;
166 const char *name = DEBUG_FindNearestSymbol( addr, flag, &rtn.sym, ebp,
167 &rtn.list );
169 if (addr->seg) DEBUG_Printf( DBG_CHN_MESG, "0x%04lx:", addr->seg );
170 if (mode != MODE_32) DEBUG_Printf( DBG_CHN_MESG, "0x%04lx", addr->off );
171 else DEBUG_Printf( DBG_CHN_MESG, "0x%08lx", addr->off );
172 if (name) DEBUG_Printf( DBG_CHN_MESG, " (%s)", name );
174 return rtn;
178 /***********************************************************************
179 * DEBUG_Help
181 * Implementation of the 'help' command.
183 void DEBUG_Help(void)
185 int i = 0;
186 static const char * const helptext[] =
188 "The commands accepted by the Wine debugger are a reasonable",
189 "subset of the commands that gdb accepts.",
190 "The commands currently are:",
191 " help quit",
192 " break [*<addr>] delete break bpnum",
193 " disable bpnum enable bpnum",
194 " condition <bpnum> [<expr>] pass",
195 " bt cont [N]",
196 " step [N] next [N]",
197 " stepi [N] nexti [N]",
198 " x <addr> print <expr>",
199 " set <reg> = <expr> set *<addr> = <expr>",
200 " up down",
201 " list <lines> disassemble [<addr>][,<addr>]",
202 " frame <n> finish",
203 " show dir dir <path>",
204 " display <expr> undisplay <disnum>",
205 " delete display <disnum> debugmsg <class>[-+]<type>\n",
206 " mode [16,32,vm86] walk [wnd,class,queue,module,",
207 " whatis process,modref <pid>]",
208 " info (see 'help info' for options)\n",
210 "The 'x' command accepts repeat counts and formats (including 'i') in the",
211 "same way that gdb does.\n",
213 " The following are examples of legal expressions:",
214 " $eax $eax+0x3 0x1000 ($eip + 256) *$eax *($esp + 3)",
215 " Also, a nm format symbol table can be read from a file using the",
216 " symbolfile command. Symbols can also be defined individually with",
217 " the define command.",
219 NULL
222 while(helptext[i]) DEBUG_Printf(DBG_CHN_MESG,"%s\n", helptext[i++]);
226 /***********************************************************************
227 * DEBUG_HelpInfo
229 * Implementation of the 'help info' command.
231 void DEBUG_HelpInfo(void)
233 int i = 0;
234 static const char * const infotext[] =
236 "The info commands allow you to get assorted bits of interesting stuff",
237 "to be displayed. The options are:",
238 " info break Dumps information about breakpoints",
239 " info display Shows auto-display expressions in use",
240 " info locals Displays values of all local vars for current frame",
241 " info maps Dumps all virtual memory mappings",
242 " info module <handle> Displays internal module state",
243 " info queue <handle> Displays internal queue state",
244 " info reg Displays values in all registers at top of stack",
245 " info segments Dumps information about all known segments",
246 " info share Dumps information about shared libraries",
247 " info stack Dumps information about top of stack",
248 " info wnd <handle> Displays internal window state",
250 NULL
253 while(infotext[i]) DEBUG_Printf(DBG_CHN_MESG,"%s\n", infotext[i++]);
256 /* FIXME: merge InfoClass and InfoClass2 */
257 void DEBUG_InfoClass(const char* name)
259 WNDCLASSEXA wca;
261 if (!GetClassInfoEx(0, name, &wca)) {
262 DEBUG_Printf(DBG_CHN_MESG, "Cannot find class '%s'\n", name);
263 return;
266 DEBUG_Printf(DBG_CHN_MESG, "Class '%s':\n", name);
267 DEBUG_Printf(DBG_CHN_MESG,
268 "style=%08x wndProc=%08lx\n"
269 "inst=%p icon=%p cursor=%p bkgnd=%p\n"
270 "clsExtra=%d winExtra=%d\n",
271 wca.style, (DWORD)wca.lpfnWndProc, wca.hInstance,
272 wca.hIcon, wca.hCursor, wca.hbrBackground,
273 wca.cbClsExtra, wca.cbWndExtra);
275 /* FIXME:
276 * + print #windows (or even list of windows...)
277 * + print extra bytes => this requires a window handle on this very class...
281 static void DEBUG_InfoClass2(HWND hWnd, const char* name)
283 WNDCLASSEXA wca;
285 if (!GetClassInfoEx((HINSTANCE)GetWindowLong(hWnd, GWL_HINSTANCE), name, &wca)) {
286 DEBUG_Printf(DBG_CHN_MESG, "Cannot find class '%s'\n", name);
287 return;
290 DEBUG_Printf(DBG_CHN_MESG, "Class '%s':\n", name);
291 DEBUG_Printf(DBG_CHN_MESG,
292 "style=%08x wndProc=%08lx\n"
293 "inst=%p icon=%p cursor=%p bkgnd=%p\n"
294 "clsExtra=%d winExtra=%d\n",
295 wca.style, (DWORD)wca.lpfnWndProc, wca.hInstance,
296 wca.hIcon, wca.hCursor, wca.hbrBackground,
297 wca.cbClsExtra, wca.cbWndExtra);
299 if (wca.cbClsExtra) {
300 int i;
301 WORD w;
303 DEBUG_Printf(DBG_CHN_MESG, "Extra bytes:" );
304 for (i = 0; i < wca.cbClsExtra / 2; i++) {
305 w = GetClassWord(hWnd, i * 2);
306 /* FIXME: depends on i386 endian-ity */
307 DEBUG_Printf(DBG_CHN_MESG, " %02x", HIBYTE(w));
308 DEBUG_Printf(DBG_CHN_MESG, " %02x", LOBYTE(w));
310 DEBUG_Printf(DBG_CHN_MESG, "\n" );
312 DEBUG_Printf(DBG_CHN_MESG, "\n" );
315 struct class_walker {
316 ATOM* table;
317 int used;
318 int alloc;
321 static void DEBUG_WalkClassesHelper(HWND hWnd, struct class_walker* cw)
323 char clsName[128];
324 int i;
325 ATOM atom;
326 HWND child;
328 if (!GetClassName(hWnd, clsName, sizeof(clsName)))
329 return;
330 if ((atom = FindAtom(clsName)) == 0)
331 return;
333 for (i = 0; i < cw->used; i++) {
334 if (cw->table[i] == atom)
335 break;
337 if (i == cw->used) {
338 if (cw->used >= cw->alloc) {
339 cw->alloc += 16;
340 cw->table = DBG_realloc(cw->table, cw->alloc * sizeof(ATOM));
342 cw->table[cw->used++] = atom;
343 DEBUG_InfoClass2(hWnd, clsName);
345 do {
346 if ((child = GetWindow(hWnd, GW_CHILD)) != 0)
347 DEBUG_WalkClassesHelper(child, cw);
348 } while ((hWnd = GetWindow(hWnd, GW_HWNDNEXT)) != 0);
351 void DEBUG_WalkClasses(void)
353 struct class_walker cw;
355 cw.table = NULL;
356 cw.used = cw.alloc = 0;
357 DEBUG_WalkClassesHelper(GetDesktopWindow(), &cw);
358 DBG_free(cw.table);
361 void DEBUG_DumpQueue(DWORD q)
363 DEBUG_Printf(DBG_CHN_MESG, "No longer doing info queue '0x%08lx'\n", q);
366 void DEBUG_WalkQueues(void)
368 DEBUG_Printf(DBG_CHN_MESG, "No longer walking queues list\n");
371 void DEBUG_InfoWindow(HWND hWnd)
373 char clsName[128];
374 char wndName[128];
375 RECT clientRect;
376 RECT windowRect;
377 int i;
378 WORD w;
380 if (!GetClassName(hWnd, clsName, sizeof(clsName)))
381 strcpy(clsName, "-- Unknown --");
382 if (!GetWindowText(hWnd, wndName, sizeof(wndName)))
383 strcpy(wndName, "-- Empty --");
384 if (!GetClientRect(hWnd, &clientRect))
385 SetRectEmpty(&clientRect);
386 if (!GetWindowRect(hWnd, &windowRect))
387 SetRectEmpty(&windowRect);
389 /* FIXME missing fields: hmemTaskQ, hrgnUpdate, dce, flags, pProp, scroll */
390 DEBUG_Printf(DBG_CHN_MESG,
391 "next=%p child=%p parent=%p owner=%p class='%s'\n"
392 "inst=%p active=%p idmenu=%08lx\n"
393 "style=%08lx exstyle=%08lx wndproc=%08lx text='%s'\n"
394 "client=%d,%d-%d,%d window=%d,%d-%d,%d sysmenu=%p\n",
395 GetWindow(hWnd, GW_HWNDNEXT),
396 GetWindow(hWnd, GW_CHILD),
397 GetParent(hWnd),
398 GetWindow(hWnd, GW_OWNER),
399 clsName,
400 (HINSTANCE)GetWindowLong(hWnd, GWL_HINSTANCE),
401 GetLastActivePopup(hWnd),
402 GetWindowLong(hWnd, GWL_ID),
403 GetWindowLong(hWnd, GWL_STYLE),
404 GetWindowLong(hWnd, GWL_EXSTYLE),
405 GetWindowLong(hWnd, GWL_WNDPROC),
406 wndName,
407 clientRect.left, clientRect.top, clientRect.right, clientRect.bottom,
408 windowRect.left, windowRect.top, windowRect.right, windowRect.bottom,
409 GetSystemMenu(hWnd, FALSE));
411 if (GetClassLong(hWnd, GCL_CBWNDEXTRA)) {
412 DEBUG_Printf(DBG_CHN_MESG, "Extra bytes:" );
413 for (i = 0; i < GetClassLong(hWnd, GCL_CBWNDEXTRA) / 2; i++) {
414 w = GetWindowWord(hWnd, i * 2);
415 /* FIXME: depends on i386 endian-ity */
416 DEBUG_Printf(DBG_CHN_MESG, " %02x", HIBYTE(w));
417 DEBUG_Printf(DBG_CHN_MESG, " %02x", LOBYTE(w));
419 DEBUG_Printf(DBG_CHN_MESG, "\n");
421 DEBUG_Printf(DBG_CHN_MESG, "\n");
424 void DEBUG_WalkWindows(HWND hWnd, int indent)
426 char clsName[128];
427 char wndName[128];
428 HWND child;
430 if (!IsWindow(hWnd))
431 hWnd = GetDesktopWindow();
433 if (!indent) /* first time around */
434 DEBUG_Printf(DBG_CHN_MESG,
435 "%-16.16s %-17.17s %-8.8s %s\n",
436 "hwnd", "Class Name", " Style", " WndProc Text");
438 do {
439 if (!GetClassName(hWnd, clsName, sizeof(clsName)))
440 strcpy(clsName, "-- Unknown --");
441 if (!GetWindowText(hWnd, wndName, sizeof(wndName)))
442 strcpy(wndName, "-- Empty --");
444 /* FIXME: missing hmemTaskQ */
445 DEBUG_Printf(DBG_CHN_MESG, "%*s%04x%*s", indent, "", (UINT)hWnd, 13-indent,"");
446 DEBUG_Printf(DBG_CHN_MESG, "%-17.17s %08lx %08lx %.14s\n",
447 clsName, GetWindowLong(hWnd, GWL_STYLE),
448 GetWindowLong(hWnd, GWL_WNDPROC), wndName);
450 if ((child = GetWindow(hWnd, GW_CHILD)) != 0)
451 DEBUG_WalkWindows(child, indent + 1 );
452 } while ((hWnd = GetWindow(hWnd, GW_HWNDNEXT)) != 0);
455 void DEBUG_WalkProcess(void)
457 HANDLE snap = CreateToolhelp32Snapshot( TH32CS_SNAPPROCESS, 0 );
458 if (snap != INVALID_HANDLE_VALUE)
460 PROCESSENTRY32 entry;
461 DWORD current = DEBUG_CurrProcess ? DEBUG_CurrProcess->pid : 0;
462 BOOL ok;
464 entry.dwSize = sizeof(entry);
465 ok = Process32First( snap, &entry );
467 DEBUG_Printf(DBG_CHN_MESG, " %-8.8s %-8.8s %-8.8s %s\n",
468 "pid", "threads", "parent", "executable" );
469 while (ok)
471 if (entry.th32ProcessID != GetCurrentProcessId())
472 DEBUG_Printf(DBG_CHN_MESG, "%c%08lx %-8ld %08lx '%s'\n",
473 (entry.th32ProcessID == current) ? '>' : ' ',
474 entry.th32ProcessID, entry.cntThreads,
475 entry.th32ParentProcessID, entry.szExeFile);
476 ok = Process32Next( snap, &entry );
478 CloseHandle( snap );
482 void DEBUG_WalkThreads(void)
484 HANDLE snap = CreateToolhelp32Snapshot( TH32CS_SNAPTHREAD, 0 );
485 if (snap != INVALID_HANDLE_VALUE)
487 THREADENTRY32 entry;
488 DWORD current = DEBUG_CurrThread ? DEBUG_CurrThread->tid : 0;
489 BOOL ok;
490 DWORD lastProcessId = 0;
492 entry.dwSize = sizeof(entry);
493 ok = Thread32First( snap, &entry );
495 DEBUG_Printf(DBG_CHN_MESG, "%-8.8s %-8.8s %s\n", "process", "tid", "prio" );
496 while (ok)
498 if (entry.th32OwnerProcessID != GetCurrentProcessId())
500 /* FIXME: this assumes that, in the snapshot, all threads of a same process are
501 * listed sequentially, which is not specified in the doc (Wine's implementation
502 * does it)
504 if (entry.th32OwnerProcessID != lastProcessId)
506 DBG_PROCESS* p = DEBUG_GetProcess(entry.th32OwnerProcessID);
508 DEBUG_Printf(DBG_CHN_MESG, "%08lx%s %s\n",
509 entry.th32OwnerProcessID, p ? " (D)" : "", p ? p->imageName : "");
510 lastProcessId = entry.th32OwnerProcessID;
512 DEBUG_Printf(DBG_CHN_MESG, "\t%08lx %4ld%s\n",
513 entry.th32ThreadID, entry.tpBasePri,
514 (entry.th32ThreadID == current) ? " <==" : "");
517 ok = Thread32Next( snap, &entry );
520 CloseHandle( snap );
524 void DEBUG_WalkModref(DWORD p)
526 DEBUG_Printf(DBG_CHN_MESG, "No longer walking module references list\n");
529 void DEBUG_InfoSegments(DWORD start, int length)
531 char flags[3];
532 DWORD i;
533 LDT_ENTRY le;
535 if (length == -1) length = (8192 - start);
537 for (i = start; i < start + length; i++)
539 if (!GetThreadSelectorEntry(DEBUG_CurrThread->handle, (i << 3)|7, &le))
540 continue;
542 if (le.HighWord.Bits.Type & 0x08)
544 flags[0] = (le.HighWord.Bits.Type & 0x2) ? 'r' : '-';
545 flags[1] = '-';
546 flags[2] = 'x';
548 else
550 flags[0] = 'r';
551 flags[1] = (le.HighWord.Bits.Type & 0x2) ? 'w' : '-';
552 flags[2] = '-';
554 DEBUG_Printf(DBG_CHN_MESG,
555 "%04lx: sel=%04lx base=%08x limit=%08x %d-bit %c%c%c\n",
556 i, (i<<3)|7,
557 (le.HighWord.Bits.BaseHi << 24) +
558 (le.HighWord.Bits.BaseMid << 16) + le.BaseLow,
559 ((le.HighWord.Bits.LimitHi << 8) + le.LimitLow) <<
560 (le.HighWord.Bits.Granularity ? 12 : 0),
561 le.HighWord.Bits.Default_Big ? 32 : 16,
562 flags[0], flags[1], flags[2] );
566 void DEBUG_InfoVirtual(void)
568 DEBUG_Printf(DBG_CHN_MESG, "No longer providing virtual mapping information\n");