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