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