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