- fix order of parameters is SendNotify
[wine.git] / debugger / info.c
blobb01bdf484d8efc5fff4710c36048efde25f7a1d2
1 /*
2 * Wine debugger utility routines
4 * Copyright 1993 Eric Youngdale
5 * Copyright 1995 Alexandre Julliard
6 */
8 #include "config.h"
9 #include <stdlib.h>
10 #include <string.h>
11 #include "winbase.h"
12 #include "wingdi.h"
13 #include "winuser.h"
14 #include "tlhelp32.h"
15 #include "debugger.h"
16 #include "expr.h"
18 /***********************************************************************
19 * DEBUG_PrintBasic
21 * Implementation of the 'print' command.
23 void DEBUG_PrintBasic( const DBG_VALUE* value, int count, char format )
25 char * default_format;
26 long long int res;
28 assert(value->cookie == DV_TARGET || value->cookie == DV_HOST);
29 if( value->type == NULL )
31 DEBUG_Printf(DBG_CHN_MESG, "Unable to evaluate expression\n");
32 return;
35 default_format = NULL;
36 res = DEBUG_GetExprValue(value, &default_format);
38 switch(format)
40 case 'x':
41 if (value->addr.seg)
43 DEBUG_nchar += DEBUG_Printf( DBG_CHN_MESG, "0x%04lx", (long unsigned int) res );
45 else
47 DEBUG_nchar += DEBUG_Printf( DBG_CHN_MESG, "0x%08lx", (long unsigned int) res );
49 break;
51 case 'd':
52 DEBUG_nchar += DEBUG_Printf( DBG_CHN_MESG, "%ld\n", (long int) res );
53 break;
55 case 'c':
56 DEBUG_nchar += DEBUG_Printf( DBG_CHN_MESG, "%d = '%c'",
57 (char)(res & 0xff), (char)(res & 0xff) );
58 break;
60 case 'i':
61 case 's':
62 case 'w':
63 case 'b':
64 DEBUG_Printf( DBG_CHN_MESG, "Format specifier '%c' is meaningless in 'print' command\n", format );
65 case 0:
66 if( default_format != NULL )
68 if (strstr(default_format, "%S") != NULL)
70 char* ptr;
71 int state = 0;
73 /* FIXME: simplistic implementation for default_format being
74 * foo%Sbar => will print foo, then string then bar
76 for (ptr = default_format; *ptr; ptr++)
78 if (*ptr == '%') state++;
79 else if (state == 1)
81 if (*ptr == 'S')
83 char ch;
84 char* str = (char*)(long)res;
86 for (; DEBUG_READ_MEM(str, &ch, 1) && ch; str++) {
87 DEBUG_Output(DBG_CHN_MESG, &ch, 1);
88 DEBUG_nchar++;
91 else
93 /* shouldn't happen */
94 DEBUG_Printf(DBG_CHN_MESG, "%%%c", *ptr);
95 DEBUG_nchar += 2;
97 state = 0;
99 else
101 DEBUG_Output(DBG_CHN_MESG, ptr, 1);
102 DEBUG_nchar++;
106 else if (strcmp(default_format, "%B") == 0)
108 DEBUG_nchar += DEBUG_Printf( DBG_CHN_MESG, "%s", res ? "true" : "false");
110 else
112 DEBUG_nchar += DEBUG_Printf( DBG_CHN_MESG, default_format, res );
115 break;
120 /***********************************************************************
121 * DEBUG_PrintAddress
123 * Print an 16- or 32-bit address, with the nearest symbol if any.
125 struct symbol_info
126 DEBUG_PrintAddress( const DBG_ADDR *addr, enum dbg_mode mode, int flag )
128 struct symbol_info rtn;
130 const char *name = DEBUG_FindNearestSymbol( addr, flag, &rtn.sym, 0,
131 &rtn.list );
133 if (addr->seg) DEBUG_Printf( DBG_CHN_MESG, "0x%04lx:", addr->seg&0xFFFF );
134 if (mode != MODE_32) DEBUG_Printf( DBG_CHN_MESG, "0x%04lx", addr->off );
135 else DEBUG_Printf( DBG_CHN_MESG, "0x%08lx", addr->off );
136 if (name) DEBUG_Printf( DBG_CHN_MESG, " (%s)", name );
137 return rtn;
139 /***********************************************************************
140 * DEBUG_PrintAddressAndArgs
142 * Print an 16- or 32-bit address, with the nearest symbol if any.
143 * Similar to DEBUG_PrintAddress, but we print the arguments to
144 * each function (if known). This is useful in a backtrace.
146 struct symbol_info
147 DEBUG_PrintAddressAndArgs( const DBG_ADDR *addr, enum dbg_mode mode,
148 unsigned int ebp, int flag )
150 struct symbol_info rtn;
152 const char *name = DEBUG_FindNearestSymbol( addr, flag, &rtn.sym, ebp,
153 &rtn.list );
155 if (addr->seg) DEBUG_Printf( DBG_CHN_MESG, "0x%04lx:", addr->seg );
156 if (mode != MODE_32) DEBUG_Printf( DBG_CHN_MESG, "0x%04lx", addr->off );
157 else DEBUG_Printf( DBG_CHN_MESG, "0x%08lx", addr->off );
158 if (name) DEBUG_Printf( DBG_CHN_MESG, " (%s)", name );
160 return rtn;
164 /***********************************************************************
165 * DEBUG_Help
167 * Implementation of the 'help' command.
169 void DEBUG_Help(void)
171 int i = 0;
172 static const char * const helptext[] =
174 "The commands accepted by the Wine debugger are a reasonable",
175 "subset of the commands that gdb accepts.",
176 "The commands currently are:",
177 " help quit",
178 " break [*<addr>] delete break bpnum",
179 " disable bpnum enable bpnum",
180 " condition <bpnum> [<expr>] pass",
181 " bt cont [N]",
182 " step [N] next [N]",
183 " stepi [N] nexti [N]",
184 " x <addr> print <expr>",
185 " set <reg> = <expr> set *<addr> = <expr>",
186 " up down",
187 " list <lines> disassemble [<addr>][,<addr>]",
188 " frame <n> finish",
189 " show dir dir <path>",
190 " display <expr> undisplay <disnum>",
191 " delete display <disnum> debugmsg <class>[-+]<type>\n",
192 " mode [16,32,vm86] walk [wnd,class,queue,module,",
193 " whatis process,modref <pid>]",
194 " info (see 'help info' for options)\n",
196 "The 'x' command accepts repeat counts and formats (including 'i') in the",
197 "same way that gdb does.\n",
199 " The following are examples of legal expressions:",
200 " $eax $eax+0x3 0x1000 ($eip + 256) *$eax *($esp + 3)",
201 " Also, a nm format symbol table can be read from a file using the",
202 " symbolfile command. Symbols can also be defined individually with",
203 " the define command.",
205 NULL
208 while(helptext[i]) DEBUG_Printf(DBG_CHN_MESG,"%s\n", helptext[i++]);
212 /***********************************************************************
213 * DEBUG_HelpInfo
215 * Implementation of the 'help info' command.
217 void DEBUG_HelpInfo(void)
219 int i = 0;
220 static const char * const infotext[] =
222 "The info commands allow you to get assorted bits of interesting stuff",
223 "to be displayed. The options are:",
224 " info break Dumps information about breakpoints",
225 " info display Shows auto-display expressions in use",
226 " info locals Displays values of all local vars for current frame",
227 " info maps Dumps all virtual memory mappings",
228 " info module <handle> Displays internal module state",
229 " info queue <handle> Displays internal queue state",
230 " info reg Displays values in all registers at top of stack",
231 " info segments Dumps information about all known segments",
232 " info share Dumps information about shared libraries",
233 " info stack Dumps information about top of stack",
234 " info wnd <handle> Displays internal window state",
236 NULL
239 while(infotext[i]) DEBUG_Printf(DBG_CHN_MESG,"%s\n", infotext[i++]);
242 /* FIXME: merge InfoClass and InfoClass2 */
243 void DEBUG_InfoClass(const char* name)
245 WNDCLASSEXA wca;
247 if (!GetClassInfoEx(0, name, &wca)) {
248 DEBUG_Printf(DBG_CHN_MESG, "Cannot find class '%s'\n", name);
249 return;
252 DEBUG_Printf(DBG_CHN_MESG, "Class '%s':\n", name);
253 DEBUG_Printf(DBG_CHN_MESG,
254 "style=%08x wndProc=%08lx\n"
255 "inst=%p icon=%p cursor=%p bkgnd=%p\n"
256 "clsExtra=%d winExtra=%d\n",
257 wca.style, (DWORD)wca.lpfnWndProc, wca.hInstance,
258 wca.hIcon, wca.hCursor, wca.hbrBackground,
259 wca.cbClsExtra, wca.cbWndExtra);
261 /* FIXME:
262 * + print #windows (or even list of windows...)
263 * + print extra bytes => this requires a window handle on this very class...
267 static void DEBUG_InfoClass2(HWND hWnd, const char* name)
269 WNDCLASSEXA wca;
271 if (!GetClassInfoEx((HINSTANCE)GetWindowLong(hWnd, GWL_HINSTANCE), name, &wca)) {
272 DEBUG_Printf(DBG_CHN_MESG, "Cannot find class '%s'\n", name);
273 return;
276 DEBUG_Printf(DBG_CHN_MESG, "Class '%s':\n", name);
277 DEBUG_Printf(DBG_CHN_MESG,
278 "style=%08x wndProc=%08lx\n"
279 "inst=%p icon=%p cursor=%p bkgnd=%p\n"
280 "clsExtra=%d winExtra=%d\n",
281 wca.style, (DWORD)wca.lpfnWndProc, wca.hInstance,
282 wca.hIcon, wca.hCursor, wca.hbrBackground,
283 wca.cbClsExtra, wca.cbWndExtra);
285 if (wca.cbClsExtra) {
286 int i;
287 WORD w;
289 DEBUG_Printf(DBG_CHN_MESG, "Extra bytes:" );
290 for (i = 0; i < wca.cbClsExtra / 2; i++) {
291 w = GetClassWord(hWnd, i * 2);
292 /* FIXME: depends on i386 endian-ity */
293 DEBUG_Printf(DBG_CHN_MESG, " %02x", HIBYTE(w));
294 DEBUG_Printf(DBG_CHN_MESG, " %02x", LOBYTE(w));
296 DEBUG_Printf(DBG_CHN_MESG, "\n" );
298 DEBUG_Printf(DBG_CHN_MESG, "\n" );
301 struct class_walker {
302 ATOM* table;
303 int used;
304 int alloc;
307 static void DEBUG_WalkClassesHelper(HWND hWnd, struct class_walker* cw)
309 char clsName[128];
310 int i;
311 ATOM atom;
312 HWND child;
314 if (!GetClassName(hWnd, clsName, sizeof(clsName)))
315 return;
316 if ((atom = FindAtom(clsName)) == 0)
317 return;
319 for (i = 0; i < cw->used; i++) {
320 if (cw->table[i] == atom)
321 break;
323 if (i == cw->used) {
324 if (cw->used >= cw->alloc) {
325 cw->alloc += 16;
326 cw->table = DBG_realloc(cw->table, cw->alloc * sizeof(ATOM));
328 cw->table[cw->used++] = atom;
329 DEBUG_InfoClass2(hWnd, clsName);
331 do {
332 if ((child = GetWindow(hWnd, GW_CHILD)) != 0)
333 DEBUG_WalkClassesHelper(child, cw);
334 } while ((hWnd = GetWindow(hWnd, GW_HWNDNEXT)) != 0);
337 void DEBUG_WalkClasses(void)
339 struct class_walker cw;
341 cw.table = NULL;
342 cw.used = cw.alloc = 0;
343 DEBUG_WalkClassesHelper(GetDesktopWindow(), &cw);
344 DBG_free(cw.table);
347 void DEBUG_DumpQueue(DWORD q)
349 DEBUG_Printf(DBG_CHN_MESG, "No longer doing info queue '0x%08lx'\n", q);
352 void DEBUG_WalkQueues(void)
354 DEBUG_Printf(DBG_CHN_MESG, "No longer walking queues list\n");
357 void DEBUG_InfoWindow(HWND hWnd)
359 char clsName[128];
360 char wndName[128];
361 RECT clientRect;
362 RECT windowRect;
363 int i;
364 WORD w;
366 if (!GetClassName(hWnd, clsName, sizeof(clsName)))
367 strcpy(clsName, "-- Unknown --");
368 if (!GetWindowText(hWnd, wndName, sizeof(wndName)))
369 strcpy(wndName, "-- Empty --");
370 if (!GetClientRect(hWnd, &clientRect))
371 SetRectEmpty(&clientRect);
372 if (!GetWindowRect(hWnd, &windowRect))
373 SetRectEmpty(&windowRect);
375 /* FIXME missing fields: hmemTaskQ, hrgnUpdate, dce, flags, pProp, scroll */
376 DEBUG_Printf(DBG_CHN_MESG,
377 "next=%p child=%p parent=%p owner=%p class='%s'\n"
378 "inst=%p active=%p idmenu=%08lx\n"
379 "style=%08lx exstyle=%08lx wndproc=%08lx text='%s'\n"
380 "client=%d,%d-%d,%d window=%d,%d-%d,%d sysmenu=%p\n",
381 GetWindow(hWnd, GW_HWNDNEXT),
382 GetWindow(hWnd, GW_CHILD),
383 GetParent(hWnd),
384 GetWindow(hWnd, GW_OWNER),
385 clsName,
386 (HINSTANCE)GetWindowLong(hWnd, GWL_HINSTANCE),
387 GetLastActivePopup(hWnd),
388 GetWindowLong(hWnd, GWL_ID),
389 GetWindowLong(hWnd, GWL_STYLE),
390 GetWindowLong(hWnd, GWL_EXSTYLE),
391 GetWindowLong(hWnd, GWL_WNDPROC),
392 wndName,
393 clientRect.left, clientRect.top, clientRect.right, clientRect.bottom,
394 windowRect.left, windowRect.top, windowRect.right, windowRect.bottom,
395 GetSystemMenu(hWnd, FALSE));
397 if (GetClassLong(hWnd, GCL_CBWNDEXTRA)) {
398 DEBUG_Printf(DBG_CHN_MESG, "Extra bytes:" );
399 for (i = 0; i < GetClassLong(hWnd, GCL_CBWNDEXTRA) / 2; i++) {
400 w = GetWindowWord(hWnd, i * 2);
401 /* FIXME: depends on i386 endian-ity */
402 DEBUG_Printf(DBG_CHN_MESG, " %02x", HIBYTE(w));
403 DEBUG_Printf(DBG_CHN_MESG, " %02x", LOBYTE(w));
405 DEBUG_Printf(DBG_CHN_MESG, "\n");
407 DEBUG_Printf(DBG_CHN_MESG, "\n");
410 void DEBUG_WalkWindows(HWND hWnd, int indent)
412 char clsName[128];
413 char wndName[128];
414 HWND child;
416 if (!IsWindow(hWnd))
417 hWnd = GetDesktopWindow();
419 if (!indent) /* first time around */
420 DEBUG_Printf(DBG_CHN_MESG,
421 "%-16.16s %-17.17s %-8.8s %s\n",
422 "hwnd", "Class Name", " Style", " WndProc Text");
424 do {
425 if (!GetClassName(hWnd, clsName, sizeof(clsName)))
426 strcpy(clsName, "-- Unknown --");
427 if (!GetWindowText(hWnd, wndName, sizeof(wndName)))
428 strcpy(wndName, "-- Empty --");
430 /* FIXME: missing hmemTaskQ */
431 DEBUG_Printf(DBG_CHN_MESG, "%*s%04x%*s", indent, "", (UINT)hWnd, 13-indent,"");
432 DEBUG_Printf(DBG_CHN_MESG, "%-17.17s %08lx %08lx %.14s\n",
433 clsName, GetWindowLong(hWnd, GWL_STYLE),
434 GetWindowLong(hWnd, GWL_WNDPROC), wndName);
436 if ((child = GetWindow(hWnd, GW_CHILD)) != 0)
437 DEBUG_WalkWindows(child, indent + 1 );
438 } while ((hWnd = GetWindow(hWnd, GW_HWNDNEXT)) != 0);
441 void DEBUG_WalkProcess(void)
443 HANDLE snap = CreateToolhelp32Snapshot( TH32CS_SNAPPROCESS, 0 );
444 if (snap != INVALID_HANDLE_VALUE)
446 PROCESSENTRY32 entry;
447 DWORD current = DEBUG_CurrProcess ? DEBUG_CurrProcess->pid : 0;
448 BOOL ok;
450 entry.dwSize = sizeof(entry);
451 ok = Process32First( snap, &entry );
453 DEBUG_Printf(DBG_CHN_MESG, "%-8.8s %-8.8s %-8.8s %s\n",
454 "pid", "threads", "parent", "exe" );
455 while (ok)
457 if (entry.th32ProcessID != GetCurrentProcessId())
458 DEBUG_Printf(DBG_CHN_MESG, "%08lx %8ld %08lx '%s'%s\n",
459 entry.th32ProcessID, entry.cntThreads,
460 entry.th32ParentProcessID, entry.szExeFile,
461 (entry.th32ProcessID == current) ? " <==" : "" );
462 ok = Process32Next( snap, &entry );
464 CloseHandle( snap );
468 void DEBUG_WalkThreads(void)
470 HANDLE snap = CreateToolhelp32Snapshot( TH32CS_SNAPTHREAD, 0 );
471 if (snap != INVALID_HANDLE_VALUE)
473 THREADENTRY32 entry;
474 DWORD current = DEBUG_CurrThread ? DEBUG_CurrThread->tid : 0;
475 BOOL ok;
476 DWORD lastProcessId = 0;
478 entry.dwSize = sizeof(entry);
479 ok = Thread32First( snap, &entry );
481 DEBUG_Printf(DBG_CHN_MESG, "%-8.8s %-8.8s %s\n", "process", "tid", "prio" );
482 while (ok)
484 if (entry.th32OwnerProcessID != GetCurrentProcessId())
486 /* FIXME: this assumes that, in the snapshot, all threads of a same process are
487 * listed sequentially, which is not specified in the doc (Wine's implementation
488 * does it)
490 if (entry.th32OwnerProcessID != lastProcessId)
492 DBG_PROCESS* p = DEBUG_GetProcess(entry.th32OwnerProcessID);
494 DEBUG_Printf(DBG_CHN_MESG, "%08lx%s %s\n",
495 entry.th32OwnerProcessID, p ? " (D)" : "", p ? p->imageName : "");
496 lastProcessId = entry.th32OwnerProcessID;
498 DEBUG_Printf(DBG_CHN_MESG, "\t%08lx %4ld%s\n",
499 entry.th32ThreadID, entry.tpBasePri,
500 (entry.th32ThreadID == current) ? " <==" : "");
503 ok = Thread32Next( snap, &entry );
506 CloseHandle( snap );
510 void DEBUG_WalkModref(DWORD p)
512 DEBUG_Printf(DBG_CHN_MESG, "No longer walking module references list\n");
515 void DEBUG_InfoSegments(DWORD start, int length)
517 char flags[3];
518 DWORD i;
519 LDT_ENTRY le;
521 if (length == -1) length = (8192 - start);
523 for (i = start; i < start + length; i++)
525 if (!GetThreadSelectorEntry(DEBUG_CurrThread->handle, (i << 3)|7, &le))
526 continue;
528 if (le.HighWord.Bits.Type & 0x08)
530 flags[0] = (le.HighWord.Bits.Type & 0x2) ? 'r' : '-';
531 flags[1] = '-';
532 flags[2] = 'x';
534 else
536 flags[0] = 'r';
537 flags[1] = (le.HighWord.Bits.Type & 0x2) ? 'w' : '-';
538 flags[2] = '-';
540 DEBUG_Printf(DBG_CHN_MESG,
541 "%04lx: sel=%04lx base=%08x limit=%08x %d-bit %c%c%c\n",
542 i, (i<<3)|7,
543 (le.HighWord.Bits.BaseHi << 24) +
544 (le.HighWord.Bits.BaseMid << 16) + le.BaseLow,
545 ((le.HighWord.Bits.LimitHi << 8) + le.LimitLow) <<
546 (le.HighWord.Bits.Granularity ? 12 : 0),
547 le.HighWord.Bits.Default_Big ? 32 : 16,
548 flags[0], flags[1], flags[2] );
552 void DEBUG_InfoVirtual(void)
554 DEBUG_Printf(DBG_CHN_MESG, "No longer providing virtual mapping information\n");