winedbg: Implement float fetching for x86-64 debugger.
[wine] / programs / winedbg / info.c
1 /*
2  * Wine debugger utility routines
3  *
4  * Copyright 1993 Eric Youngdale
5  * Copyright 1995 Alexandre Julliard
6  *
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.
11  *
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.
16  *
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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20  */
21
22 #include "config.h"
23
24 #include <stdlib.h>
25 #include <stdio.h>
26 #include <string.h>
27 #include <stdarg.h>
28
29 #include "debugger.h"
30 #include "wingdi.h"
31 #include "winuser.h"
32 #include "tlhelp32.h"
33 #include "wine/debug.h"
34
35 WINE_DEFAULT_DEBUG_CHANNEL(winedbg);
36
37 /***********************************************************************
38  *           print_help
39  *
40  * Implementation of the 'help' command.
41  */
42 void print_help(void)
43 {
44     int i = 0;
45     static const char * const helptext[] =
46         {
47             "The commands accepted by the Wine debugger are a reasonable",
48             "subset of the commands that gdb accepts.",
49             "The commands currently are:",
50             "  help                                   quit",
51             "  break [*<addr>]                        watch *<addr>",
52             "  delete break bpnum                     disable bpnum",
53             "  enable bpnum                           condition <bpnum> [<expr>]",
54             "  finish                                 cont [N]",
55             "  step [N]                               next [N]",
56             "  stepi [N]                              nexti [N]",
57             "  x <addr>                               print <expr>",
58             "  display <expr>                         undisplay <disnum>",
59             "  local display <expr>                   delete display <disnum>",                  
60             "  enable display <disnum>                disable display <disnum>",
61             "  bt [<tid>|all]                         frame <n>",
62             "  up                                     down",
63             "  list <lines>                           disassemble [<addr>][,<addr>]",
64             "  show dir                               dir <path>",
65             "  set <reg> = <expr>                     set *<addr> = <expr>",
66             "  pass                                   whatis",
67             "  info (see 'help info' for options)",
68
69             "The 'x' command accepts repeat counts and formats (including 'i') in the",
70             "same way that gdb does.\n",
71
72             "The following are examples of legal expressions:",
73             " $eax     $eax+0x3   0x1000   ($eip + 256)  *$eax   *($esp + 3)",
74             " Also, a nm format symbol table can be read from a file using the",
75             " symbolfile command.", /*  Symbols can also be defined individually with",
76                                         " the define command.", */
77             "",
78             NULL
79         };
80
81     while (helptext[i]) dbg_printf("%s\n", helptext[i++]);
82 }
83
84
85 /***********************************************************************
86  *           info_help
87  *
88  * Implementation of the 'help info' command.
89  */
90 void info_help(void)
91 {
92     int i = 0;
93     static const char * const infotext[] =
94         {
95             "The info commands allow you to get assorted bits of interesting stuff",
96             "to be displayed.  The options are:",
97             "  info break           Displays information about breakpoints",
98             "  info class <name>    Displays information about window class <name>",
99             "  info display         Shows auto-display expressions in use",
100             "  info except <pid>    Shows exception handler chain (in a given process)",
101             "  info locals          Displays values of all local vars for current frame",
102             "  info maps <pid>      Shows virtual mappings (in a given process)",
103             "  info process         Shows all running processes",
104             "  info reg             Displays values of the general registers at top of stack",
105             "  info all-reg         Displays the general and floating point registers",
106             "  info segments <pid>  Displays information about all known segments",
107             "  info share           Displays all loaded modules",
108             "  info share <addr>    Displays internal module state",
109             "  info stack           Dumps information about top of stack",
110             "  info symbol <sym>    Displays information about a given symbol",
111             "  info thread          Shows all running threads",
112             "  info wnd <handle>    Displays internal window state",
113             "",
114             NULL
115         };
116
117     while (infotext[i]) dbg_printf("%s\n", infotext[i++]);
118 }
119
120 static const char* get_symtype_str(const IMAGEHLP_MODULE64* mi)
121 {
122     switch (mi->SymType)
123     {
124     default:
125     case SymNone:       return "--none--";
126     case SymCoff:       return "COFF";
127     case SymCv:         return "CodeView";
128     case SymPdb:        return "PDB";
129     case SymExport:     return "Export";
130     case SymDeferred:   return "Deferred";
131     case SymSym:        return "Sym";
132     case SymDia:
133         switch (mi->CVSig)
134         {
135         case 'S' | ('T' << 8) | ('A' << 16) | ('B' << 24):
136             return "Stabs";
137         case 'D' | ('W' << 8) | ('A' << 16) | ('R' << 24):
138             return "Dwarf";
139         default:
140             return "DIA";
141
142         }
143     }
144 }
145
146 struct info_module
147 {
148     IMAGEHLP_MODULE64*  mi;
149     unsigned            num_alloc;
150     unsigned            num_used;
151 };
152
153 static void module_print_info(const IMAGEHLP_MODULE64* mi, BOOL is_embedded)
154 {
155     dbg_printf("%*.*s-%*.*s\t%-16s%s\n",
156                ADDRWIDTH, ADDRWIDTH, wine_dbgstr_longlong(mi->BaseOfImage),
157                ADDRWIDTH, ADDRWIDTH, wine_dbgstr_longlong(mi->BaseOfImage + mi->ImageSize),
158                is_embedded ? "\\" : get_symtype_str(mi), mi->ModuleName);
159 }
160
161 static int      module_compare(const void* p1, const void* p2)
162 {
163     LONGLONG val = ((const IMAGEHLP_MODULE64*)p1)->BaseOfImage -
164         ((const IMAGEHLP_MODULE64*)p2)->BaseOfImage;
165     if (val < 0) return -1;
166     else if (val > 0) return 1;
167     else return 0;
168 }
169
170 static inline BOOL module_is_container(const IMAGEHLP_MODULE64* wmod_cntnr,
171                                        const IMAGEHLP_MODULE64* wmod_child)
172 {
173     return wmod_cntnr->BaseOfImage <= wmod_child->BaseOfImage &&
174         wmod_cntnr->BaseOfImage + wmod_cntnr->ImageSize >=
175         wmod_child->BaseOfImage + wmod_child->ImageSize;
176 }
177
178 static BOOL CALLBACK info_mod_cb(PCSTR mod_name, DWORD64 base, PVOID ctx)
179 {
180     struct info_module* im = ctx;
181
182     if (im->num_used + 1 > im->num_alloc)
183     {
184         im->num_alloc += 16;
185         im->mi = dbg_heap_realloc(im->mi, im->num_alloc * sizeof(*im->mi));
186     }
187     im->mi[im->num_used].SizeOfStruct = sizeof(im->mi[im->num_used]);
188     if (SymGetModuleInfo64(dbg_curr_process->handle, base, &im->mi[im->num_used]))
189     {
190         im->num_used++;
191     }   
192     return TRUE;
193 }
194
195 /***********************************************************************
196  *           info_win32_module
197  *
198  * Display information about a given module (DLL or EXE), or about all modules
199  */
200 void info_win32_module(DWORD64 base)
201 {
202     struct info_module  im;
203     UINT                i, j, num_printed = 0;
204     DWORD               opt;
205
206     if (!dbg_curr_process)
207     {
208         dbg_printf("Cannot get info on module while no process is loaded\n");
209         return;
210     }
211
212     im.mi = NULL;
213     im.num_alloc = im.num_used = 0;
214
215     /* this is a wine specific options to return also ELF modules in the
216      * enumeration
217      */
218     SymSetOptions((opt = SymGetOptions()) | 0x40000000);
219     SymEnumerateModules64(dbg_curr_process->handle, info_mod_cb, (void*)&im);
220     SymSetOptions(opt);
221
222     qsort(im.mi, im.num_used, sizeof(im.mi[0]), module_compare);
223
224     dbg_printf("Module\tAddress\t\t\t%sDebug info\tName (%d modules)\n",
225                ADDRWIDTH == 16 ? "\t\t" : "", im.num_used);
226
227     for (i = 0; i < im.num_used; i++)
228     {
229         if (base && 
230             (base < im.mi[i].BaseOfImage || base >= im.mi[i].BaseOfImage + im.mi[i].ImageSize))
231             continue;
232         if (strstr(im.mi[i].ModuleName, "<elf>"))
233         {
234             dbg_printf("ELF\t");
235             module_print_info(&im.mi[i], FALSE);
236             /* print all modules embedded in this one */
237             for (j = 0; j < im.num_used; j++)
238             {
239                 if (!strstr(im.mi[j].ModuleName, "<elf>") && module_is_container(&im.mi[i], &im.mi[j]))
240                 {
241                     dbg_printf("  \\-PE\t");
242                     module_print_info(&im.mi[j], TRUE);
243                 }
244             }
245         }
246         else
247         {
248             /* check module is not embedded in another module */
249             for (j = 0; j < im.num_used; j++) 
250             {
251                 if (strstr(im.mi[j].ModuleName, "<elf>") && module_is_container(&im.mi[j], &im.mi[i]))
252                     break;
253             }
254             if (j < im.num_used) continue;
255             if (strstr(im.mi[i].ModuleName, ".so") || strchr(im.mi[i].ModuleName, '<'))
256                 dbg_printf("ELF\t");
257             else
258                 dbg_printf("PE\t");
259             module_print_info(&im.mi[i], FALSE);
260         }
261         num_printed++;
262     }
263     HeapFree(GetProcessHeap(), 0, im.mi);
264
265     if (base && !num_printed)
266         dbg_printf("'0x%x%08x' is not a valid module address\n", (DWORD)(base >> 32), (DWORD)base);
267 }
268
269 struct class_walker
270 {
271     ATOM*       table;
272     int         used;
273     int         alloc;
274 };
275
276 static void class_walker(HWND hWnd, struct class_walker* cw)
277 {
278     char        clsName[128];
279     int         i;
280     ATOM        atom;
281     HWND        child;
282
283     if (!GetClassNameA(hWnd, clsName, sizeof(clsName)))
284         return;
285     if ((atom = FindAtomA(clsName)) == 0)
286         return;
287
288     for (i = 0; i < cw->used; i++)
289     {
290         if (cw->table[i] == atom)
291             break;
292     }
293     if (i == cw->used)
294     {
295         if (cw->used >= cw->alloc)
296         {
297             cw->alloc += 16;
298             cw->table = dbg_heap_realloc(cw->table, cw->alloc * sizeof(ATOM));
299         }
300         cw->table[cw->used++] = atom;
301         info_win32_class(hWnd, clsName);
302     }
303     do
304     {
305         if ((child = GetWindow(hWnd, GW_CHILD)) != 0)
306             class_walker(child, cw);
307     } while ((hWnd = GetWindow(hWnd, GW_HWNDNEXT)) != 0);
308 }
309
310 void info_win32_class(HWND hWnd, const char* name)
311 {
312     WNDCLASSEXA wca;
313     HINSTANCE   hInst = hWnd ? (HINSTANCE)GetWindowLongPtrW(hWnd, GWLP_HINSTANCE) : 0;
314
315     if (!name)
316     {
317         struct class_walker cw;
318
319         cw.table = NULL;
320         cw.used = cw.alloc = 0;
321         class_walker(GetDesktopWindow(), &cw);
322         HeapFree(GetProcessHeap(), 0, cw.table);
323         return;
324     }
325
326     if (!GetClassInfoExA(hInst, name, &wca))
327     {
328         dbg_printf("Cannot find class '%s'\n", name);
329         return;
330     }
331
332     dbg_printf("Class '%s':\n", name);
333     dbg_printf("style=0x%08x  wndProc=%p\n"
334                "inst=%p  icon=%p  cursor=%p  bkgnd=%p\n"
335                "clsExtra=%d  winExtra=%d\n",
336                wca.style, wca.lpfnWndProc, wca.hInstance,
337                wca.hIcon, wca.hCursor, wca.hbrBackground,
338                wca.cbClsExtra, wca.cbWndExtra);
339
340     if (hWnd && wca.cbClsExtra)
341     {
342         int             i;
343         WORD            w;
344
345         dbg_printf("Extra bytes:");
346         for (i = 0; i < wca.cbClsExtra / 2; i++)
347         {
348             w = GetClassWord(hWnd, i * 2);
349             /* FIXME: depends on i386 endian-ity */
350             dbg_printf(" %02x %02x", HIBYTE(w), LOBYTE(w));
351         }
352         dbg_printf("\n");
353     }
354     dbg_printf("\n");
355     /* FIXME:
356      * + print #windows (or even list of windows...)
357      * + print extra bytes => this requires a window handle on this very class...
358      */
359 }
360
361 static void info_window(HWND hWnd, int indent)
362 {
363     char        clsName[128];
364     char        wndName[128];
365     HWND        child;
366
367     do
368     {
369         if (!GetClassNameA(hWnd, clsName, sizeof(clsName)))
370             strcpy(clsName, "-- Unknown --");
371         if (!GetWindowTextA(hWnd, wndName, sizeof(wndName)))
372             strcpy(wndName, "-- Empty --");
373
374         dbg_printf("%*s%08lx%*s %-17.17s %08x %0*lx %08x %.14s\n",
375                    indent, "", (DWORD_PTR)hWnd, 12 - indent, "",
376                    clsName, GetWindowLongW(hWnd, GWL_STYLE),
377                    ADDRWIDTH, (ULONG_PTR)GetWindowLongPtrW(hWnd, GWLP_WNDPROC),
378                    GetWindowThreadProcessId(hWnd, NULL), wndName);
379
380         if ((child = GetWindow(hWnd, GW_CHILD)) != 0)
381             info_window(child, indent + 1);
382     } while ((hWnd = GetWindow(hWnd, GW_HWNDNEXT)) != 0);
383 }
384
385 void info_win32_window(HWND hWnd, BOOL detailed)
386 {
387     char        clsName[128];
388     char        wndName[128];
389     RECT        clientRect;
390     RECT        windowRect;
391     WORD        w;
392
393     if (!IsWindow(hWnd)) hWnd = GetDesktopWindow();
394
395     if (!detailed)
396     {
397         dbg_printf("%-20.20s %-17.17s %-8.8s %-*.*s %-8.8s %s\n",
398                    "Window handle", "Class Name", "Style",
399                    ADDRWIDTH, ADDRWIDTH, "WndProc", "Thread", "Text");
400         info_window(hWnd, 0);
401         return;
402     }
403
404     if (!GetClassNameA(hWnd, clsName, sizeof(clsName)))
405         strcpy(clsName, "-- Unknown --");
406     if (!GetWindowTextA(hWnd, wndName, sizeof(wndName)))
407         strcpy(wndName, "-- Empty --");
408     if (!GetClientRect(hWnd, &clientRect) || 
409         !MapWindowPoints(hWnd, 0, (LPPOINT) &clientRect, 2))
410         SetRectEmpty(&clientRect);
411     if (!GetWindowRect(hWnd, &windowRect))
412         SetRectEmpty(&windowRect);
413
414     /* FIXME missing fields: hmemTaskQ, hrgnUpdate, dce, flags, pProp, scroll */
415     dbg_printf("next=%p  child=%p  parent=%p  owner=%p  class='%s'\n"
416                "inst=%p  active=%p  idmenu=%08lx\n"
417                "style=0x%08x  exstyle=0x%08x  wndproc=%p  text='%s'\n"
418                "client=%d,%d-%d,%d  window=%d,%d-%d,%d sysmenu=%p\n",
419                GetWindow(hWnd, GW_HWNDNEXT),
420                GetWindow(hWnd, GW_CHILD),
421                GetParent(hWnd),
422                GetWindow(hWnd, GW_OWNER),
423                clsName,
424                (HINSTANCE)GetWindowLongPtrW(hWnd, GWLP_HINSTANCE),
425                GetLastActivePopup(hWnd),
426                (ULONG_PTR)GetWindowLongPtrW(hWnd, GWLP_ID),
427                GetWindowLongW(hWnd, GWL_STYLE),
428                GetWindowLongW(hWnd, GWL_EXSTYLE),
429                (void*)GetWindowLongPtrW(hWnd, GWLP_WNDPROC),
430                wndName,
431                clientRect.left, clientRect.top, clientRect.right, clientRect.bottom,
432                windowRect.left, windowRect.top, windowRect.right, windowRect.bottom,
433                GetSystemMenu(hWnd, FALSE));
434
435     if (GetClassLongW(hWnd, GCL_CBWNDEXTRA))
436     {
437         UINT i;
438
439         dbg_printf("Extra bytes:");
440         for (i = 0; i < GetClassLongW(hWnd, GCL_CBWNDEXTRA) / 2; i++)
441         {
442             w = GetWindowWord(hWnd, i * 2);
443             /* FIXME: depends on i386 endian-ity */
444             dbg_printf(" %02x %02x", HIBYTE(w), LOBYTE(w));
445         }
446         dbg_printf("\n");
447     }
448     dbg_printf("\n");
449 }
450
451 void info_win32_processes(void)
452 {
453     HANDLE snap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
454     if (snap != INVALID_HANDLE_VALUE)
455     {
456         PROCESSENTRY32  entry;
457         DWORD           current = dbg_curr_process ? dbg_curr_process->pid : 0;
458         BOOL            ok;
459
460         entry.dwSize = sizeof(entry);
461         ok = Process32First(snap, &entry);
462
463         dbg_printf(" %-8.8s %-8.8s %-8.8s %s (all id:s are in hex)\n",
464                    "pid", "threads", "parent", "executable");
465         while (ok)
466         {
467             if (entry.th32ProcessID != GetCurrentProcessId())
468                 dbg_printf("%c%08x %-8d %08x '%s'\n",
469                            (entry.th32ProcessID == current) ? '>' : ' ',
470                            entry.th32ProcessID, entry.cntThreads,
471                            entry.th32ParentProcessID, entry.szExeFile);
472             ok = Process32Next(snap, &entry);
473         }
474         CloseHandle(snap);
475     }
476 }
477
478 static BOOL get_process_name(DWORD pid, PROCESSENTRY32* entry)
479 {
480     BOOL   ret = FALSE;
481     HANDLE snap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
482
483     if (snap != INVALID_HANDLE_VALUE)
484     {
485         entry->dwSize = sizeof(*entry);
486         if (Process32First(snap, entry))
487             while (!(ret = (entry->th32ProcessID == pid)) &&
488                    Process32Next(snap, entry));
489         CloseHandle(snap);
490     }
491     return ret;
492 }
493
494 void info_win32_threads(void)
495 {
496     HANDLE snap = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0);
497     if (snap != INVALID_HANDLE_VALUE)
498     {
499         THREADENTRY32   entry;
500         BOOL            ok;
501         DWORD           lastProcessId = 0;
502
503         entry.dwSize = sizeof(entry);
504         ok = Thread32First(snap, &entry);
505
506         dbg_printf("%-8.8s %-8.8s %s (all id:s are in hex)\n",
507                    "process", "tid", "prio");
508         while (ok)
509         {
510             if (entry.th32OwnerProcessID != GetCurrentProcessId())
511             {
512                 /* FIXME: this assumes that, in the snapshot, all threads of a same process are
513                  * listed sequentially, which is not specified in the doc (Wine's implementation
514                  * does it)
515                  */
516                 if (entry.th32OwnerProcessID != lastProcessId)
517                 {
518                     struct dbg_process* p = dbg_get_process(entry.th32OwnerProcessID);
519                     PROCESSENTRY32 pcs_entry;
520                     const char* exename;
521
522                     if (p)
523                         exename = dbg_W2A(p->imageName, -1);
524                     else if (get_process_name(entry.th32OwnerProcessID, &pcs_entry))
525                         exename = pcs_entry.szExeFile;
526                     else
527                         exename = "";
528
529                     dbg_printf("%08x%s %s\n",
530                                entry.th32OwnerProcessID, p ? " (D)" : "", exename);
531                     lastProcessId = entry.th32OwnerProcessID;
532                 }
533                 dbg_printf("\t%08x %4d%s\n",
534                            entry.th32ThreadID, entry.tpBasePri,
535                            (entry.th32ThreadID == dbg_curr_tid) ? " <==" : "");
536
537             }
538             ok = Thread32Next(snap, &entry);
539         }
540
541         CloseHandle(snap);
542     }
543 }
544
545 /***********************************************************************
546  *           info_win32_exceptions
547  *
548  * Get info on the exception frames of a given thread.
549  */
550 void info_win32_exceptions(DWORD tid)
551 {
552     struct dbg_thread*  thread;
553     void*               next_frame;
554
555     if (!dbg_curr_process || !dbg_curr_thread)
556     {
557         dbg_printf("Cannot get info on exceptions while no process is loaded\n");
558         return;
559     }
560
561     dbg_printf("Exception frames:\n");
562
563     if (tid == dbg_curr_tid) thread = dbg_curr_thread;
564     else
565     {
566         thread = dbg_get_thread(dbg_curr_process, tid);
567
568         if (!thread)
569         {
570             dbg_printf("Unknown thread id (%04x) in current process\n", tid);
571             return;
572         }
573         if (SuspendThread(thread->handle) == -1)
574         {
575             dbg_printf("Can't suspend thread id (%04x)\n", tid);
576             return;
577         }
578     }
579
580     if (!dbg_read_memory(thread->teb, &next_frame, sizeof(next_frame)))
581     {
582         dbg_printf("Can't read TEB:except_frame\n");
583         return;
584     }
585
586     while (next_frame != (void*)-1)
587     {
588         EXCEPTION_REGISTRATION_RECORD frame;
589
590         dbg_printf("%p: ", next_frame);
591         if (!dbg_read_memory(next_frame, &frame, sizeof(frame)))
592         {
593             dbg_printf("Invalid frame address\n");
594             break;
595         }
596         dbg_printf("prev=%p handler=%p\n", frame.Prev, frame.Handler);
597         next_frame = frame.Prev;
598     }
599
600     if (tid != dbg_curr_tid) ResumeThread(thread->handle);
601 }
602
603 void info_win32_segments(DWORD start, int length)
604 {
605     char        flags[3];
606     DWORD       i;
607     LDT_ENTRY   le;
608
609     if (length == -1) length = (8192 - start);
610
611     for (i = start; i < start + length; i++)
612     {
613         if (!dbg_curr_process->process_io->get_selector(dbg_curr_thread->handle, (i << 3) | 7, &le))
614             continue;
615
616         if (le.HighWord.Bits.Type & 0x08)
617         {
618             flags[0] = (le.HighWord.Bits.Type & 0x2) ? 'r' : '-';
619             flags[1] = '-';
620             flags[2] = 'x';
621         }
622         else
623         {
624             flags[0] = 'r';
625             flags[1] = (le.HighWord.Bits.Type & 0x2) ? 'w' : '-';
626             flags[2] = '-';
627         }
628         dbg_printf("%04x: sel=%04x base=%08x limit=%08x %d-bit %c%c%c\n",
629                    i, (i << 3) | 7,
630                    (le.HighWord.Bits.BaseHi << 24) +
631                    (le.HighWord.Bits.BaseMid << 16) + le.BaseLow,
632                    ((le.HighWord.Bits.LimitHi << 8) + le.LimitLow) <<
633                    (le.HighWord.Bits.Granularity ? 12 : 0),
634                    le.HighWord.Bits.Default_Big ? 32 : 16,
635                    flags[0], flags[1], flags[2]);
636     }
637 }
638
639 void info_win32_virtual(DWORD pid)
640 {
641     MEMORY_BASIC_INFORMATION    mbi;
642     char*                       addr = 0;
643     const char*                 state;
644     const char*                 type;
645     char                        prot[3+1];
646     HANDLE                      hProc;
647
648     if (pid == dbg_curr_pid)
649     {
650         if (dbg_curr_process == NULL)
651         {
652             dbg_printf("Cannot look at mapping of current process, while no process is loaded\n");
653             return;
654         }
655         hProc = dbg_curr_process->handle;
656     }
657     else
658     {
659         hProc = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, pid);
660         if (hProc == NULL)
661         {
662             dbg_printf("Cannot open process <%04x>\n", pid);
663             return;
664         }
665     }
666
667     dbg_printf("Address  End      State   Type    RWX\n");
668
669     while (VirtualQueryEx(hProc, addr, &mbi, sizeof(mbi)) >= sizeof(mbi))
670     {
671         switch (mbi.State)
672         {
673         case MEM_COMMIT:        state = "commit "; break;
674         case MEM_FREE:          state = "free   "; break;
675         case MEM_RESERVE:       state = "reserve"; break;
676         default:                state = "???    "; break;
677         }
678         if (mbi.State != MEM_FREE)
679         {
680             switch (mbi.Type)
681             {
682             case MEM_IMAGE:         type = "image  "; break;
683             case MEM_MAPPED:        type = "mapped "; break;
684             case MEM_PRIVATE:       type = "private"; break;
685             case 0:                 type = "       "; break;
686             default:                type = "???    "; break;
687             }
688             memset(prot, ' ' , sizeof(prot) - 1);
689             prot[sizeof(prot) - 1] = '\0';
690             if (mbi.AllocationProtect & (PAGE_READONLY|PAGE_READWRITE|PAGE_EXECUTE_READ|PAGE_EXECUTE_READWRITE))
691                 prot[0] = 'R';
692             if (mbi.AllocationProtect & (PAGE_READWRITE|PAGE_EXECUTE_READWRITE))
693                 prot[1] = 'W';
694             if (mbi.AllocationProtect & (PAGE_WRITECOPY|PAGE_EXECUTE_WRITECOPY))
695                 prot[1] = 'C';
696             if (mbi.AllocationProtect & (PAGE_EXECUTE|PAGE_EXECUTE_READ|PAGE_EXECUTE_READWRITE))
697                 prot[2] = 'X';
698         }
699         else
700         {
701             type = "";
702             prot[0] = '\0';
703         }
704         dbg_printf("%08lx %08lx %s %s %s\n",
705                    (DWORD_PTR)addr, (DWORD_PTR)addr + mbi.RegionSize - 1, state, type, prot);
706         if (addr + mbi.RegionSize < addr) /* wrap around ? */
707             break;
708         addr += mbi.RegionSize;
709     }
710     if (pid != dbg_curr_pid) CloseHandle(hProc);
711 }
712
713 void info_wine_dbg_channel(BOOL turn_on, const char* cls, const char* name)
714 {
715     struct dbg_lvalue           lvalue;
716     struct __wine_debug_channel channel;
717     unsigned char               mask;
718     int                         done = 0;
719     BOOL                        bAll;
720     void*                       addr;
721
722     if (!dbg_curr_process || !dbg_curr_thread)
723     {
724         dbg_printf("Cannot set/get debug channels while no process is loaded\n");
725         return;
726     }
727
728     if (symbol_get_lvalue("debug_options", -1, &lvalue, FALSE) != sglv_found)
729     {
730         return;
731     }
732     addr = memory_to_linear_addr(&lvalue.addr);
733
734     if (!cls)                          mask = ~0;
735     else if (!strcmp(cls, "fixme"))    mask = (1 << __WINE_DBCL_FIXME);
736     else if (!strcmp(cls, "err"))      mask = (1 << __WINE_DBCL_ERR);
737     else if (!strcmp(cls, "warn"))     mask = (1 << __WINE_DBCL_WARN);
738     else if (!strcmp(cls, "trace"))    mask = (1 << __WINE_DBCL_TRACE);
739     else
740     {
741         dbg_printf("Unknown debug class %s\n", cls);
742         return;
743     }
744
745     bAll = !strcmp("all", name);
746     while (addr && dbg_read_memory(addr, &channel, sizeof(channel)))
747     {
748         if (!channel.name[0]) break;
749         if (bAll || !strcmp( channel.name, name ))
750         {
751             if (turn_on) channel.flags |= mask;
752             else channel.flags &= ~mask;
753             if (dbg_write_memory(addr, &channel, sizeof(channel))) done++;
754         }
755         addr = (struct __wine_debug_channel *)addr + 1;
756     }
757     if (!done) dbg_printf("Unable to find debug channel %s\n", name);
758     else WINE_TRACE("Changed %d channel instances\n", done);
759 }