Fixed header dependencies to be fully compatible with the Windows
[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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20  */
21
22 #include "config.h"
23
24 #include <stdlib.h>
25 #include <string.h>
26 #include <stdarg.h>
27
28 #include "windef.h"
29 #include "winbase.h"
30 #include "wingdi.h"
31 #include "winuser.h"
32 #include "tlhelp32.h"
33 #include "debugger.h"
34 #include "expr.h"
35
36 /***********************************************************************
37  *           DEBUG_PrintBasic
38  *
39  * Implementation of the 'print' command.
40  */
41 void DEBUG_PrintBasic( const DBG_VALUE* value, int count, char format )
42 {
43     char        * default_format;
44     long long int res;
45
46     assert(value->cookie == DV_TARGET || value->cookie == DV_HOST);
47     if (value->type == NULL)
48     {
49         DEBUG_Printf(DBG_CHN_MESG, "Unable to evaluate expression\n");
50         return;
51     }
52
53     default_format = NULL;
54     res = DEBUG_GetExprValue(value, &default_format);
55
56     switch (format)
57     {
58     case 'x':
59         if (value->addr.seg)
60         {
61             DEBUG_nchar += DEBUG_Printf(DBG_CHN_MESG, "0x%04lx", (long unsigned int)res);
62         }
63         else
64         {
65             DEBUG_nchar += DEBUG_Printf(DBG_CHN_MESG, "0x%08lx", (long unsigned int)res);
66         }
67         break;
68
69     case 'd':
70         DEBUG_nchar += DEBUG_Printf(DBG_CHN_MESG, "%ld\n", (long int)res);
71         break;
72
73     case 'c':
74         DEBUG_nchar += DEBUG_Printf(DBG_CHN_MESG, "%d = '%c'",
75                                     (char)(res & 0xff), (char)(res & 0xff));
76         break;
77
78     case 'u':
79     {
80         WCHAR wch = (WCHAR)(res & 0xFFFF);
81         DEBUG_nchar += DEBUG_Printf(DBG_CHN_MESG, "%d = '", (unsigned)(res & 0xffff));
82         DEBUG_OutputW(DBG_CHN_MESG, &wch, 1);
83         DEBUG_Printf(DBG_CHN_MESG, "'");
84     }
85     break;
86
87     case 'i':
88     case 's':
89     case 'w':
90     case 'b':
91         DEBUG_Printf(DBG_CHN_MESG, "Format specifier '%c' is meaningless in 'print' command\n", format);
92     case 0:
93         if (default_format == NULL) break;
94
95         if (strstr(default_format, "%S") != NULL)
96         {
97             char*       ptr;
98             int state = 0;
99
100             /* FIXME: simplistic implementation for default_format being
101              * foo%Sbar => will print foo, then string then bar
102              */
103             for (ptr = default_format; *ptr; ptr++)
104             {
105                 if (*ptr == '%')
106                 {
107                     state++;
108                 }
109                 else if (state == 1)
110                 {
111                     if (*ptr == 'S')
112                     {
113                         DBG_ADDR    addr;
114
115                         addr.seg = 0;
116                         addr.off = (long)res;
117                         DEBUG_nchar += DEBUG_PrintStringA(DBG_CHN_MESG, &addr, -1);
118                     }
119                     else
120                     {
121                         /* shouldn't happen */
122                         DEBUG_Printf(DBG_CHN_MESG, "%%%c", *ptr);
123                         DEBUG_nchar += 2;
124                     }
125                     state = 0;
126                 }
127                 else
128                 {
129                     DEBUG_OutputA(DBG_CHN_MESG, ptr, 1);
130                     DEBUG_nchar++;
131                 }
132             }
133         }
134         else if (strcmp(default_format, "%B") == 0)
135         {
136             DEBUG_nchar += DEBUG_Printf(DBG_CHN_MESG, "%s", res ? "true" : "false");
137         }
138         else if (strcmp(default_format, "%R") == 0)
139         {
140             if (value->cookie == DV_HOST)
141                 DEBUG_InfoRegisters((CONTEXT*)value->addr.off);
142             else
143                 DEBUG_Printf(DBG_CHN_MESG, "NIY: info on register struct in debuggee address space\n");
144             DEBUG_nchar = 0;
145         }
146         else
147         {
148             DEBUG_nchar += DEBUG_Printf(DBG_CHN_MESG, default_format, res);
149         }
150         break;
151     }
152 }
153
154
155 /***********************************************************************
156  *           DEBUG_PrintAddress
157  *
158  * Print an 16- or 32-bit address, with the nearest symbol if any.
159  */
160 struct symbol_info
161 DEBUG_PrintAddress( const DBG_ADDR *addr, enum dbg_mode mode, int flag )
162 {
163     struct symbol_info rtn;
164
165     const char *name = DEBUG_FindNearestSymbol( addr, flag, &rtn.sym, 0,
166                                                 &rtn.list );
167
168     if (addr->seg) DEBUG_Printf( DBG_CHN_MESG, "0x%04lx:", addr->seg&0xFFFF );
169     if (mode != MODE_32) DEBUG_Printf( DBG_CHN_MESG, "0x%04lx", addr->off );
170     else DEBUG_Printf( DBG_CHN_MESG, "0x%08lx", addr->off );
171     if (name) DEBUG_Printf( DBG_CHN_MESG, " (%s)", name );
172     return rtn;
173 }
174 /***********************************************************************
175  *           DEBUG_PrintAddressAndArgs
176  *
177  * Print an 16- or 32-bit address, with the nearest symbol if any.
178  * Similar to DEBUG_PrintAddress, but we print the arguments to
179  * each function (if known).  This is useful in a backtrace.
180  */
181 struct symbol_info
182 DEBUG_PrintAddressAndArgs( const DBG_ADDR *addr, enum dbg_mode mode,
183                            unsigned int ebp, int flag )
184 {
185     struct symbol_info rtn;
186
187     const char *name = DEBUG_FindNearestSymbol( addr, flag, &rtn.sym, ebp,
188                                                 &rtn.list );
189
190     if (addr->seg) DEBUG_Printf( DBG_CHN_MESG, "0x%04lx:", addr->seg );
191     if (mode != MODE_32) DEBUG_Printf( DBG_CHN_MESG, "0x%04lx", addr->off );
192     else DEBUG_Printf( DBG_CHN_MESG, "0x%08lx", addr->off );
193     if (name) DEBUG_Printf( DBG_CHN_MESG, " (%s)", name );
194
195     return rtn;
196 }
197
198
199 /***********************************************************************
200  *           DEBUG_Help
201  *
202  * Implementation of the 'help' command.
203  */
204 void DEBUG_Help(void)
205 {
206     int i = 0;
207     static const char * const helptext[] =
208 {
209 "The commands accepted by the Wine debugger are a reasonable",
210 "subset of the commands that gdb accepts.",
211 "The commands currently are:",
212 "  help                                   quit",
213 "  break [*<addr>]                        watch *<addr>",
214 "  delete break bpnum                     disable bpnum",
215 "  enable bpnum                           condition <bpnum> [<expr>]",
216 "  finish                                 cont [N]",
217 "  step [N]                               next [N]",
218 "  stepi [N]                              nexti [N]",
219 "  x <addr>                               print <expr>",
220 "  display <expr>                         undisplay <disnum>",
221 "  delete display <disnum>                pass",
222 "  bt                                     frame <n>",
223 "  up                                     down",
224 "  list <lines>                           disassemble [<addr>][,<addr>]",
225 "  show dir                               dir <path>",
226 "  set <reg> = <expr>                     set *<addr> = <expr>",
227 "  mode [16,32,vm86]                      walk [wnd,class,module,maps,",
228 "  whatis                                       process,thread,exception]",
229 "  info (see 'help info' for options)",
230
231 "The 'x' command accepts repeat counts and formats (including 'i') in the",
232 "same way that gdb does.\n",
233
234 " The following are examples of legal expressions:",
235 " $eax     $eax+0x3   0x1000   ($eip + 256)  *$eax   *($esp + 3)",
236 " Also, a nm format symbol table can be read from a file using the",
237 " symbolfile command.  Symbols can also be defined individually with",
238 " the define command.",
239 "",
240 NULL
241 };
242
243     while(helptext[i]) DEBUG_Printf(DBG_CHN_MESG,"%s\n", helptext[i++]);
244 }
245
246
247 /***********************************************************************
248  *           DEBUG_HelpInfo
249  *
250  * Implementation of the 'help info' command.
251  */
252 void DEBUG_HelpInfo(void)
253 {
254     int i = 0;
255     static const char * const infotext[] =
256 {
257 "The info commands allow you to get assorted bits of interesting stuff",
258 "to be displayed.  The options are:",
259 "  info break           Dumps information about breakpoints",
260 "  info display         Shows auto-display expressions in use",
261 "  info locals          Displays values of all local vars for current frame",
262 "  info module <handle> Displays internal module state",
263 "  info reg             Displays values in all registers at top of stack",
264 "  info segments        Dumps information about all known segments",
265 "  info share           Dumps information about shared libraries",
266 "  info stack           Dumps information about top of stack",
267 "  info wnd <handle>    Displays internal window state",
268 "",
269 NULL
270 };
271
272     while(infotext[i]) DEBUG_Printf(DBG_CHN_MESG,"%s\n", infotext[i++]);
273 }
274
275 /* FIXME: merge InfoClass and InfoClass2 */
276 void DEBUG_InfoClass(const char* name)
277 {
278    WNDCLASSEXA  wca;
279
280    if (!GetClassInfoEx(0, name, &wca)) {
281       DEBUG_Printf(DBG_CHN_MESG, "Cannot find class '%s'\n", name);
282       return;
283    }
284
285    DEBUG_Printf(DBG_CHN_MESG,  "Class '%s':\n", name);
286    DEBUG_Printf(DBG_CHN_MESG,
287                 "style=%08x  wndProc=%08lx\n"
288                 "inst=%p  icon=%p  cursor=%p  bkgnd=%p\n"
289                 "clsExtra=%d  winExtra=%d\n",
290                 wca.style, (DWORD)wca.lpfnWndProc, wca.hInstance,
291                 wca.hIcon, wca.hCursor, wca.hbrBackground,
292                 wca.cbClsExtra, wca.cbWndExtra);
293
294    /* FIXME:
295     * + print #windows (or even list of windows...)
296     * + print extra bytes => this requires a window handle on this very class...
297     */
298 }
299
300 static  void DEBUG_InfoClass2(HWND hWnd, const char* name)
301 {
302    WNDCLASSEXA  wca;
303
304    if (!GetClassInfoEx((HINSTANCE)GetWindowLong(hWnd, GWL_HINSTANCE), name, &wca)) {
305       DEBUG_Printf(DBG_CHN_MESG, "Cannot find class '%s'\n", name);
306       return;
307    }
308
309    DEBUG_Printf(DBG_CHN_MESG,  "Class '%s':\n", name);
310    DEBUG_Printf(DBG_CHN_MESG,
311                 "style=%08x  wndProc=%08lx\n"
312                 "inst=%p  icon=%p  cursor=%p  bkgnd=%p\n"
313                 "clsExtra=%d  winExtra=%d\n",
314                 wca.style, (DWORD)wca.lpfnWndProc, wca.hInstance,
315                 wca.hIcon, wca.hCursor, wca.hbrBackground,
316                 wca.cbClsExtra, wca.cbWndExtra);
317
318    if (wca.cbClsExtra) {
319       int               i;
320       WORD              w;
321
322       DEBUG_Printf(DBG_CHN_MESG,  "Extra bytes:" );
323       for (i = 0; i < wca.cbClsExtra / 2; i++) {
324          w = GetClassWord(hWnd, i * 2);
325          /* FIXME: depends on i386 endian-ity */
326          DEBUG_Printf(DBG_CHN_MESG,  " %02x", HIBYTE(w));
327          DEBUG_Printf(DBG_CHN_MESG,  " %02x", LOBYTE(w));
328       }
329       DEBUG_Printf(DBG_CHN_MESG,  "\n" );
330     }
331     DEBUG_Printf(DBG_CHN_MESG,  "\n" );
332 }
333
334 struct class_walker {
335    ATOM*        table;
336    int          used;
337    int          alloc;
338 };
339
340 static  void DEBUG_WalkClassesHelper(HWND hWnd, struct class_walker* cw)
341 {
342    char clsName[128];
343    int  i;
344    ATOM atom;
345    HWND child;
346
347    if (!GetClassName(hWnd, clsName, sizeof(clsName)))
348       return;
349    if ((atom = FindAtom(clsName)) == 0)
350       return;
351
352    for (i = 0; i < cw->used; i++) {
353       if (cw->table[i] == atom)
354          break;
355    }
356    if (i == cw->used) {
357       if (cw->used >= cw->alloc) {
358          cw->alloc += 16;
359          cw->table = DBG_realloc(cw->table, cw->alloc * sizeof(ATOM));
360       }
361       cw->table[cw->used++] = atom;
362       DEBUG_InfoClass2(hWnd, clsName);
363    }
364    do {
365       if ((child = GetWindow(hWnd, GW_CHILD)) != 0)
366          DEBUG_WalkClassesHelper(child, cw);
367    } while ((hWnd = GetWindow(hWnd, GW_HWNDNEXT)) != 0);
368 }
369
370 void DEBUG_WalkClasses(void)
371 {
372    struct class_walker cw;
373
374    cw.table = NULL;
375    cw.used = cw.alloc = 0;
376    DEBUG_WalkClassesHelper(GetDesktopWindow(), &cw);
377    DBG_free(cw.table);
378 }
379
380 void DEBUG_InfoWindow(HWND hWnd)
381 {
382    char clsName[128];
383    char wndName[128];
384    RECT clientRect;
385    RECT windowRect;
386    int  i;
387    WORD w;
388
389    if (!GetClassName(hWnd, clsName, sizeof(clsName)))
390        strcpy(clsName, "-- Unknown --");
391    if (!GetWindowText(hWnd, wndName, sizeof(wndName)))
392       strcpy(wndName, "-- Empty --");
393    if (!GetClientRect(hWnd, &clientRect))
394       SetRectEmpty(&clientRect);
395    if (!GetWindowRect(hWnd, &windowRect))
396       SetRectEmpty(&windowRect);
397
398    /* FIXME missing fields: hmemTaskQ, hrgnUpdate, dce, flags, pProp, scroll */
399    DEBUG_Printf(DBG_CHN_MESG,
400                 "next=%p  child=%p  parent=%p  owner=%p  class='%s'\n"
401                 "inst=%p  active=%p  idmenu=%08lx\n"
402                 "style=%08lx  exstyle=%08lx  wndproc=%08lx  text='%s'\n"
403                 "client=%ld,%ld-%ld,%ld  window=%ld,%ld-%ld,%ld sysmenu=%p\n",
404                 GetWindow(hWnd, GW_HWNDNEXT),
405                 GetWindow(hWnd, GW_CHILD),
406                 GetParent(hWnd),
407                 GetWindow(hWnd, GW_OWNER),
408                 clsName,
409                 (HINSTANCE)GetWindowLong(hWnd, GWL_HINSTANCE),
410                 GetLastActivePopup(hWnd),
411                 GetWindowLong(hWnd, GWL_ID),
412                 GetWindowLong(hWnd, GWL_STYLE),
413                 GetWindowLong(hWnd, GWL_EXSTYLE),
414                 GetWindowLong(hWnd, GWL_WNDPROC),
415                 wndName,
416                 clientRect.left, clientRect.top, clientRect.right, clientRect.bottom,
417                 windowRect.left, windowRect.top, windowRect.right, windowRect.bottom,
418                 GetSystemMenu(hWnd, FALSE));
419
420     if (GetClassLong(hWnd, GCL_CBWNDEXTRA)) {
421         DEBUG_Printf(DBG_CHN_MESG,  "Extra bytes:" );
422         for (i = 0; i < GetClassLong(hWnd, GCL_CBWNDEXTRA) / 2; i++) {
423            w = GetWindowWord(hWnd, i * 2);
424            /* FIXME: depends on i386 endian-ity */
425            DEBUG_Printf(DBG_CHN_MESG, " %02x", HIBYTE(w));
426            DEBUG_Printf(DBG_CHN_MESG, " %02x", LOBYTE(w));
427         }
428         DEBUG_Printf(DBG_CHN_MESG, "\n");
429     }
430     DEBUG_Printf(DBG_CHN_MESG, "\n");
431 }
432
433 void DEBUG_WalkWindows(HWND hWnd, int indent)
434 {
435    char clsName[128];
436    char wndName[128];
437    HWND child;
438
439    if (!IsWindow(hWnd))
440       hWnd = GetDesktopWindow();
441
442     if (!indent)  /* first time around */
443        DEBUG_Printf(DBG_CHN_MESG,
444                     "%-16.16s %-17.17s %-8.8s %s\n",
445                     "hwnd", "Class Name", " Style", " WndProc Text");
446
447     do {
448        if (!GetClassName(hWnd, clsName, sizeof(clsName)))
449           strcpy(clsName, "-- Unknown --");
450        if (!GetWindowText(hWnd, wndName, sizeof(wndName)))
451           strcpy(wndName, "-- Empty --");
452
453        /* FIXME: missing hmemTaskQ */
454        DEBUG_Printf(DBG_CHN_MESG, "%*s%04x%*s", indent, "", (UINT)hWnd, 13-indent,"");
455        DEBUG_Printf(DBG_CHN_MESG, "%-17.17s %08lx %08lx %.14s\n",
456                     clsName, GetWindowLong(hWnd, GWL_STYLE),
457                     GetWindowLong(hWnd, GWL_WNDPROC), wndName);
458
459        if ((child = GetWindow(hWnd, GW_CHILD)) != 0)
460           DEBUG_WalkWindows(child, indent + 1 );
461     } while ((hWnd = GetWindow(hWnd, GW_HWNDNEXT)) != 0);
462 }
463
464 void DEBUG_WalkProcess(void)
465 {
466     HANDLE snap = CreateToolhelp32Snapshot( TH32CS_SNAPPROCESS, 0 );
467     if (snap != INVALID_HANDLE_VALUE)
468     {
469         PROCESSENTRY32 entry;
470         DWORD current = DEBUG_CurrProcess ? DEBUG_CurrProcess->pid : 0;
471         BOOL ok;
472
473         entry.dwSize = sizeof(entry);
474         ok = Process32First( snap, &entry );
475
476         DEBUG_Printf(DBG_CHN_MESG, " %-8.8s %-8.8s %-8.8s %s\n",
477                      "pid", "threads", "parent", "executable" );
478         while (ok)
479         {
480             if (entry.th32ProcessID != GetCurrentProcessId())
481                 DEBUG_Printf(DBG_CHN_MESG, "%c%08lx %-8ld %08lx '%s'\n",
482                              (entry.th32ProcessID == current) ? '>' : ' ',
483                              entry.th32ProcessID, entry.cntThreads,
484                              entry.th32ParentProcessID, entry.szExeFile);
485             ok = Process32Next( snap, &entry );
486         }
487         CloseHandle( snap );
488     }
489 }
490
491 void DEBUG_WalkThreads(void)
492 {
493     HANDLE snap = CreateToolhelp32Snapshot( TH32CS_SNAPTHREAD, 0 );
494     if (snap != INVALID_HANDLE_VALUE)
495     {
496         THREADENTRY32   entry;
497         DWORD           current = DEBUG_CurrThread ? DEBUG_CurrThread->tid : 0;
498         BOOL            ok;
499         DWORD           lastProcessId = 0;
500
501         entry.dwSize = sizeof(entry);
502         ok = Thread32First( snap, &entry );
503
504         DEBUG_Printf(DBG_CHN_MESG, "%-8.8s %-8.8s %s\n", "process", "tid", "prio" );
505         while (ok)
506         {
507             if (entry.th32OwnerProcessID != GetCurrentProcessId())
508             {
509                 /* FIXME: this assumes that, in the snapshot, all threads of a same process are
510                  * listed sequentially, which is not specified in the doc (Wine's implementation
511                  * does it)
512                  */
513                 if (entry.th32OwnerProcessID != lastProcessId)
514                 {
515                     DBG_PROCESS*        p = DEBUG_GetProcess(entry.th32OwnerProcessID);
516
517                     DEBUG_Printf(DBG_CHN_MESG, "%08lx%s %s\n",
518                                  entry.th32OwnerProcessID,  p ? " (D)" : "", p ? p->imageName : "");
519                     lastProcessId = entry.th32OwnerProcessID;
520                 }
521                 DEBUG_Printf(DBG_CHN_MESG, "\t%08lx %4ld%s\n",
522                              entry.th32ThreadID, entry.tpBasePri,
523                              (entry.th32ThreadID == current) ? " <==" : "");
524
525             }
526             ok = Thread32Next( snap, &entry );
527         }
528
529         CloseHandle( snap );
530     }
531 }
532
533 /***********************************************************************
534  *           DEBUG_WalkExceptions
535  *
536  * Walk the exception frames of a given thread.
537  */
538 void DEBUG_WalkExceptions(DWORD tid)
539 {
540     DBG_THREAD * thread;
541     void *next_frame;
542
543     if (!DEBUG_CurrProcess || !DEBUG_CurrThread)
544     {
545         DEBUG_Printf(DBG_CHN_MESG, 
546                      "Cannot walk exceptions while no process is loaded\n");
547         return;
548     }
549
550     DEBUG_Printf( DBG_CHN_MESG, "Exception frames:\n" );
551
552     if (tid == DEBUG_CurrTid) thread = DEBUG_CurrThread;
553     else
554     {
555          thread = DEBUG_GetThread(DEBUG_CurrProcess, tid);
556
557          if (!thread)
558          {
559               DEBUG_Printf( DBG_CHN_MESG, "Unknown thread id (0x%08lx) in current process\n", tid);
560               return;
561          }
562          if (SuspendThread( thread->handle ) == -1)
563          {
564               DEBUG_Printf( DBG_CHN_MESG, "Can't suspend thread id (0x%08lx)\n", tid);
565               return;
566          }
567     }
568
569     if (!DEBUG_READ_MEM(thread->teb, &next_frame, sizeof(next_frame)))
570     {
571         DEBUG_Printf( DBG_CHN_MESG, "Can't read TEB:except_frame\n");
572         return;
573     }
574
575     while (next_frame != (void *)-1)
576     {
577         EXCEPTION_REGISTRATION_RECORD frame;
578
579         DEBUG_Printf( DBG_CHN_MESG, "%p: ", next_frame );
580         if (!DEBUG_READ_MEM(next_frame, &frame, sizeof(frame)))
581         {
582             DEBUG_Printf( DBG_CHN_MESG, "Invalid frame address\n" );
583             break;
584         }
585         DEBUG_Printf( DBG_CHN_MESG, "prev=%p handler=%p\n", frame.Prev, frame.Handler );
586         next_frame = frame.Prev;
587     }
588
589     if (tid != DEBUG_CurrTid) ResumeThread( thread->handle );
590 }
591
592
593 void DEBUG_InfoSegments(DWORD start, int length)
594 {
595     char        flags[3];
596     DWORD       i;
597     LDT_ENTRY   le;
598
599     if (length == -1) length = (8192 - start);
600
601     for (i = start; i < start + length; i++)
602     {
603         if (!GetThreadSelectorEntry(DEBUG_CurrThread->handle, (i << 3) | 7, &le))
604             continue;
605
606         if (le.HighWord.Bits.Type & 0x08)
607         {
608             flags[0] = (le.HighWord.Bits.Type & 0x2) ? 'r' : '-';
609             flags[1] = '-';
610             flags[2] = 'x';
611         }
612         else
613         {
614             flags[0] = 'r';
615             flags[1] = (le.HighWord.Bits.Type & 0x2) ? 'w' : '-';
616             flags[2] = '-';
617         }
618         DEBUG_Printf(DBG_CHN_MESG,
619                      "%04lx: sel=%04lx base=%08x limit=%08x %d-bit %c%c%c\n",
620                      i, (i<<3)|7,
621                      (le.HighWord.Bits.BaseHi << 24) +
622                      (le.HighWord.Bits.BaseMid << 16) + le.BaseLow,
623                      ((le.HighWord.Bits.LimitHi << 8) + le.LimitLow) <<
624                      (le.HighWord.Bits.Granularity ? 12 : 0),
625                      le.HighWord.Bits.Default_Big ? 32 : 16,
626                      flags[0], flags[1], flags[2] );
627     }
628 }
629
630 void DEBUG_InfoVirtual(DWORD pid)
631 {
632     MEMORY_BASIC_INFORMATION    mbi;
633     char*                       addr = 0;
634     char*                       state;
635     char*                       type;
636     char                        prot[3+1];
637     HANDLE                      hProc;
638
639     if (pid == 0)
640     {
641         if (DEBUG_CurrProcess == NULL)
642         {
643             DEBUG_Printf(DBG_CHN_MESG, 
644                          "Cannot look at mapping of current process, while no process is loaded\n");
645             return;
646         }
647         hProc = DEBUG_CurrProcess->handle;
648     }
649     else
650     {
651         hProc = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, pid);
652         if (hProc == NULL)
653         {
654             DEBUG_Printf(DBG_CHN_MESG, "Cannot open process <%lu>\n", pid);
655             return;
656         }
657     }
658
659     DEBUG_Printf(DBG_CHN_MESG, "Address  Size     State   Type    RWX\n");
660
661     while (VirtualQueryEx(hProc, addr, &mbi, sizeof(mbi)) >= sizeof(mbi))
662     {
663         switch (mbi.State)
664         {
665         case MEM_COMMIT:        state = "commit "; break;
666         case MEM_FREE:          state = "free   "; break;
667         case MEM_RESERVE:       state = "reserve"; break;
668         default:                state = "???    "; break;
669         }
670         if (mbi.State != MEM_FREE)
671         {
672             switch (mbi.Type)
673             {
674             case MEM_IMAGE:         type = "image  "; break;
675             case MEM_MAPPED:        type = "mapped "; break;
676             case MEM_PRIVATE:       type = "private"; break;
677             case 0:                 type = "       "; break;
678             default:                type = "???    "; break;
679             }
680             memset(prot, ' ' , sizeof(prot)-1);
681             prot[sizeof(prot)-1] = '\0';
682             if (mbi.AllocationProtect & (PAGE_READONLY|PAGE_READWRITE|PAGE_EXECUTE_READ|PAGE_EXECUTE_READWRITE))
683                 prot[0] = 'R';
684             if (mbi.AllocationProtect & (PAGE_READWRITE|PAGE_EXECUTE_READWRITE))
685                 prot[1] = 'W';
686             if (mbi.AllocationProtect & (PAGE_WRITECOPY|PAGE_EXECUTE_WRITECOPY))
687                 prot[1] = 'C';
688             if (mbi.AllocationProtect & (PAGE_EXECUTE|PAGE_EXECUTE_READ|PAGE_EXECUTE_READWRITE))
689                 prot[2] = 'X';
690         }
691         else
692         {
693             type = "";
694             prot[0] = '\0';
695         }
696         DEBUG_Printf(DBG_CHN_MESG, "%08lx %08lx %s %s %s\n",
697                      (DWORD)addr, mbi.RegionSize, state, type, prot);
698         if (addr + mbi.RegionSize < addr) /* wrap around ? */
699             break;
700         addr += mbi.RegionSize;
701     }
702     if (hProc != DEBUG_CurrProcess->handle) CloseHandle(hProc);
703 }
704
705 struct dll_option_layout
706 {
707     void*               next;
708     void*               prev;
709     char* const*        channels;
710     int                 nb_channels;
711 };
712
713 void DEBUG_DbgChannel(BOOL turn_on, const char* chnl, const char* name)
714 {
715     DBG_VALUE                   val;
716     struct dll_option_layout    dol;
717     int                         i;
718     char*                       str;
719     unsigned char               buffer[32];
720     unsigned char               mask;
721     int                         done = 0;
722     BOOL                        bAll;
723     void*                       addr;
724
725     if (DEBUG_GetSymbolValue("first_dll", -1, &val, FALSE) != gsv_found)
726     {
727         DEBUG_Printf(DBG_CHN_MESG, "Can't get first_option symbol");
728         return;
729     }
730     addr = (void*)DEBUG_ToLinear(&val.addr);
731     if (!chnl)                          mask = 15;
732     else if (!strcmp(chnl, "fixme"))    mask = 1;
733     else if (!strcmp(chnl, "err"))      mask = 2;
734     else if (!strcmp(chnl, "warn"))     mask = 4;
735     else if (!strcmp(chnl, "trace"))    mask = 8;
736     else { DEBUG_Printf(DBG_CHN_MESG, "Unknown channel %s\n", chnl); return; }
737
738     bAll = !strcmp("all", name);
739     while (addr && DEBUG_READ_MEM(addr, &dol, sizeof(dol)))
740     {
741         for (i = 0; i < dol.nb_channels; i++)
742         {
743             if (DEBUG_READ_MEM((void*)(dol.channels + i), &str, sizeof(str)) &&
744                 DEBUG_READ_MEM(str, buffer, sizeof(buffer)) &&
745                 (!strcmp(buffer + 1, name) || bAll))
746             {
747                 if (turn_on) buffer[0] |= mask; else buffer[0] &= ~mask;
748                 if (DEBUG_WRITE_MEM(str, buffer, 1)) done++;
749             }
750         }
751         addr = dol.next;
752     }
753     if (!done) DEBUG_Printf(DBG_CHN_MESG, "Unable to find debug channel %s\n", name);
754     else DEBUG_Printf(DBG_CHN_TRACE, "Changed %d channel instances\n", done);
755 }