Fixed header dependencies to be fully compatible with the Windows
[wine/multimedia.git] / programs / winedbg / info.c
blob40757ac4dfed5e07a0862ad683287caf86b1d9fc
1 /*
2 * Wine debugger utility routines
4 * Copyright 1993 Eric Youngdale
5 * Copyright 1995 Alexandre Julliard
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.
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.
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
22 #include "config.h"
24 #include <stdlib.h>
25 #include <string.h>
26 #include <stdarg.h>
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"
36 /***********************************************************************
37 * DEBUG_PrintBasic
39 * Implementation of the 'print' command.
41 void DEBUG_PrintBasic( const DBG_VALUE* value, int count, char format )
43 char * default_format;
44 long long int res;
46 assert(value->cookie == DV_TARGET || value->cookie == DV_HOST);
47 if (value->type == NULL)
49 DEBUG_Printf(DBG_CHN_MESG, "Unable to evaluate expression\n");
50 return;
53 default_format = NULL;
54 res = DEBUG_GetExprValue(value, &default_format);
56 switch (format)
58 case 'x':
59 if (value->addr.seg)
61 DEBUG_nchar += DEBUG_Printf(DBG_CHN_MESG, "0x%04lx", (long unsigned int)res);
63 else
65 DEBUG_nchar += DEBUG_Printf(DBG_CHN_MESG, "0x%08lx", (long unsigned int)res);
67 break;
69 case 'd':
70 DEBUG_nchar += DEBUG_Printf(DBG_CHN_MESG, "%ld\n", (long int)res);
71 break;
73 case 'c':
74 DEBUG_nchar += DEBUG_Printf(DBG_CHN_MESG, "%d = '%c'",
75 (char)(res & 0xff), (char)(res & 0xff));
76 break;
78 case 'u':
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, "'");
85 break;
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;
95 if (strstr(default_format, "%S") != NULL)
97 char* ptr;
98 int state = 0;
100 /* FIXME: simplistic implementation for default_format being
101 * foo%Sbar => will print foo, then string then bar
103 for (ptr = default_format; *ptr; ptr++)
105 if (*ptr == '%')
107 state++;
109 else if (state == 1)
111 if (*ptr == 'S')
113 DBG_ADDR addr;
115 addr.seg = 0;
116 addr.off = (long)res;
117 DEBUG_nchar += DEBUG_PrintStringA(DBG_CHN_MESG, &addr, -1);
119 else
121 /* shouldn't happen */
122 DEBUG_Printf(DBG_CHN_MESG, "%%%c", *ptr);
123 DEBUG_nchar += 2;
125 state = 0;
127 else
129 DEBUG_OutputA(DBG_CHN_MESG, ptr, 1);
130 DEBUG_nchar++;
134 else if (strcmp(default_format, "%B") == 0)
136 DEBUG_nchar += DEBUG_Printf(DBG_CHN_MESG, "%s", res ? "true" : "false");
138 else if (strcmp(default_format, "%R") == 0)
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;
146 else
148 DEBUG_nchar += DEBUG_Printf(DBG_CHN_MESG, default_format, res);
150 break;
155 /***********************************************************************
156 * DEBUG_PrintAddress
158 * Print an 16- or 32-bit address, with the nearest symbol if any.
160 struct symbol_info
161 DEBUG_PrintAddress( const DBG_ADDR *addr, enum dbg_mode mode, int flag )
163 struct symbol_info rtn;
165 const char *name = DEBUG_FindNearestSymbol( addr, flag, &rtn.sym, 0,
166 &rtn.list );
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;
174 /***********************************************************************
175 * DEBUG_PrintAddressAndArgs
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.
181 struct symbol_info
182 DEBUG_PrintAddressAndArgs( const DBG_ADDR *addr, enum dbg_mode mode,
183 unsigned int ebp, int flag )
185 struct symbol_info rtn;
187 const char *name = DEBUG_FindNearestSymbol( addr, flag, &rtn.sym, ebp,
188 &rtn.list );
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 );
195 return rtn;
199 /***********************************************************************
200 * DEBUG_Help
202 * Implementation of the 'help' command.
204 void DEBUG_Help(void)
206 int i = 0;
207 static const char * const helptext[] =
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)",
231 "The 'x' command accepts repeat counts and formats (including 'i') in the",
232 "same way that gdb does.\n",
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.",
240 NULL
243 while(helptext[i]) DEBUG_Printf(DBG_CHN_MESG,"%s\n", helptext[i++]);
247 /***********************************************************************
248 * DEBUG_HelpInfo
250 * Implementation of the 'help info' command.
252 void DEBUG_HelpInfo(void)
254 int i = 0;
255 static const char * const infotext[] =
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",
269 NULL
272 while(infotext[i]) DEBUG_Printf(DBG_CHN_MESG,"%s\n", infotext[i++]);
275 /* FIXME: merge InfoClass and InfoClass2 */
276 void DEBUG_InfoClass(const char* name)
278 WNDCLASSEXA wca;
280 if (!GetClassInfoEx(0, name, &wca)) {
281 DEBUG_Printf(DBG_CHN_MESG, "Cannot find class '%s'\n", name);
282 return;
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);
294 /* FIXME:
295 * + print #windows (or even list of windows...)
296 * + print extra bytes => this requires a window handle on this very class...
300 static void DEBUG_InfoClass2(HWND hWnd, const char* name)
302 WNDCLASSEXA wca;
304 if (!GetClassInfoEx((HINSTANCE)GetWindowLong(hWnd, GWL_HINSTANCE), name, &wca)) {
305 DEBUG_Printf(DBG_CHN_MESG, "Cannot find class '%s'\n", name);
306 return;
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);
318 if (wca.cbClsExtra) {
319 int i;
320 WORD w;
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));
329 DEBUG_Printf(DBG_CHN_MESG, "\n" );
331 DEBUG_Printf(DBG_CHN_MESG, "\n" );
334 struct class_walker {
335 ATOM* table;
336 int used;
337 int alloc;
340 static void DEBUG_WalkClassesHelper(HWND hWnd, struct class_walker* cw)
342 char clsName[128];
343 int i;
344 ATOM atom;
345 HWND child;
347 if (!GetClassName(hWnd, clsName, sizeof(clsName)))
348 return;
349 if ((atom = FindAtom(clsName)) == 0)
350 return;
352 for (i = 0; i < cw->used; i++) {
353 if (cw->table[i] == atom)
354 break;
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));
361 cw->table[cw->used++] = atom;
362 DEBUG_InfoClass2(hWnd, clsName);
364 do {
365 if ((child = GetWindow(hWnd, GW_CHILD)) != 0)
366 DEBUG_WalkClassesHelper(child, cw);
367 } while ((hWnd = GetWindow(hWnd, GW_HWNDNEXT)) != 0);
370 void DEBUG_WalkClasses(void)
372 struct class_walker cw;
374 cw.table = NULL;
375 cw.used = cw.alloc = 0;
376 DEBUG_WalkClassesHelper(GetDesktopWindow(), &cw);
377 DBG_free(cw.table);
380 void DEBUG_InfoWindow(HWND hWnd)
382 char clsName[128];
383 char wndName[128];
384 RECT clientRect;
385 RECT windowRect;
386 int i;
387 WORD w;
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);
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));
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));
428 DEBUG_Printf(DBG_CHN_MESG, "\n");
430 DEBUG_Printf(DBG_CHN_MESG, "\n");
433 void DEBUG_WalkWindows(HWND hWnd, int indent)
435 char clsName[128];
436 char wndName[128];
437 HWND child;
439 if (!IsWindow(hWnd))
440 hWnd = GetDesktopWindow();
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");
447 do {
448 if (!GetClassName(hWnd, clsName, sizeof(clsName)))
449 strcpy(clsName, "-- Unknown --");
450 if (!GetWindowText(hWnd, wndName, sizeof(wndName)))
451 strcpy(wndName, "-- Empty --");
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);
459 if ((child = GetWindow(hWnd, GW_CHILD)) != 0)
460 DEBUG_WalkWindows(child, indent + 1 );
461 } while ((hWnd = GetWindow(hWnd, GW_HWNDNEXT)) != 0);
464 void DEBUG_WalkProcess(void)
466 HANDLE snap = CreateToolhelp32Snapshot( TH32CS_SNAPPROCESS, 0 );
467 if (snap != INVALID_HANDLE_VALUE)
469 PROCESSENTRY32 entry;
470 DWORD current = DEBUG_CurrProcess ? DEBUG_CurrProcess->pid : 0;
471 BOOL ok;
473 entry.dwSize = sizeof(entry);
474 ok = Process32First( snap, &entry );
476 DEBUG_Printf(DBG_CHN_MESG, " %-8.8s %-8.8s %-8.8s %s\n",
477 "pid", "threads", "parent", "executable" );
478 while (ok)
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 );
487 CloseHandle( snap );
491 void DEBUG_WalkThreads(void)
493 HANDLE snap = CreateToolhelp32Snapshot( TH32CS_SNAPTHREAD, 0 );
494 if (snap != INVALID_HANDLE_VALUE)
496 THREADENTRY32 entry;
497 DWORD current = DEBUG_CurrThread ? DEBUG_CurrThread->tid : 0;
498 BOOL ok;
499 DWORD lastProcessId = 0;
501 entry.dwSize = sizeof(entry);
502 ok = Thread32First( snap, &entry );
504 DEBUG_Printf(DBG_CHN_MESG, "%-8.8s %-8.8s %s\n", "process", "tid", "prio" );
505 while (ok)
507 if (entry.th32OwnerProcessID != GetCurrentProcessId())
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)
513 if (entry.th32OwnerProcessID != lastProcessId)
515 DBG_PROCESS* p = DEBUG_GetProcess(entry.th32OwnerProcessID);
517 DEBUG_Printf(DBG_CHN_MESG, "%08lx%s %s\n",
518 entry.th32OwnerProcessID, p ? " (D)" : "", p ? p->imageName : "");
519 lastProcessId = entry.th32OwnerProcessID;
521 DEBUG_Printf(DBG_CHN_MESG, "\t%08lx %4ld%s\n",
522 entry.th32ThreadID, entry.tpBasePri,
523 (entry.th32ThreadID == current) ? " <==" : "");
526 ok = Thread32Next( snap, &entry );
529 CloseHandle( snap );
533 /***********************************************************************
534 * DEBUG_WalkExceptions
536 * Walk the exception frames of a given thread.
538 void DEBUG_WalkExceptions(DWORD tid)
540 DBG_THREAD * thread;
541 void *next_frame;
543 if (!DEBUG_CurrProcess || !DEBUG_CurrThread)
545 DEBUG_Printf(DBG_CHN_MESG,
546 "Cannot walk exceptions while no process is loaded\n");
547 return;
550 DEBUG_Printf( DBG_CHN_MESG, "Exception frames:\n" );
552 if (tid == DEBUG_CurrTid) thread = DEBUG_CurrThread;
553 else
555 thread = DEBUG_GetThread(DEBUG_CurrProcess, tid);
557 if (!thread)
559 DEBUG_Printf( DBG_CHN_MESG, "Unknown thread id (0x%08lx) in current process\n", tid);
560 return;
562 if (SuspendThread( thread->handle ) == -1)
564 DEBUG_Printf( DBG_CHN_MESG, "Can't suspend thread id (0x%08lx)\n", tid);
565 return;
569 if (!DEBUG_READ_MEM(thread->teb, &next_frame, sizeof(next_frame)))
571 DEBUG_Printf( DBG_CHN_MESG, "Can't read TEB:except_frame\n");
572 return;
575 while (next_frame != (void *)-1)
577 EXCEPTION_REGISTRATION_RECORD frame;
579 DEBUG_Printf( DBG_CHN_MESG, "%p: ", next_frame );
580 if (!DEBUG_READ_MEM(next_frame, &frame, sizeof(frame)))
582 DEBUG_Printf( DBG_CHN_MESG, "Invalid frame address\n" );
583 break;
585 DEBUG_Printf( DBG_CHN_MESG, "prev=%p handler=%p\n", frame.Prev, frame.Handler );
586 next_frame = frame.Prev;
589 if (tid != DEBUG_CurrTid) ResumeThread( thread->handle );
593 void DEBUG_InfoSegments(DWORD start, int length)
595 char flags[3];
596 DWORD i;
597 LDT_ENTRY le;
599 if (length == -1) length = (8192 - start);
601 for (i = start; i < start + length; i++)
603 if (!GetThreadSelectorEntry(DEBUG_CurrThread->handle, (i << 3) | 7, &le))
604 continue;
606 if (le.HighWord.Bits.Type & 0x08)
608 flags[0] = (le.HighWord.Bits.Type & 0x2) ? 'r' : '-';
609 flags[1] = '-';
610 flags[2] = 'x';
612 else
614 flags[0] = 'r';
615 flags[1] = (le.HighWord.Bits.Type & 0x2) ? 'w' : '-';
616 flags[2] = '-';
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] );
630 void DEBUG_InfoVirtual(DWORD pid)
632 MEMORY_BASIC_INFORMATION mbi;
633 char* addr = 0;
634 char* state;
635 char* type;
636 char prot[3+1];
637 HANDLE hProc;
639 if (pid == 0)
641 if (DEBUG_CurrProcess == NULL)
643 DEBUG_Printf(DBG_CHN_MESG,
644 "Cannot look at mapping of current process, while no process is loaded\n");
645 return;
647 hProc = DEBUG_CurrProcess->handle;
649 else
651 hProc = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, pid);
652 if (hProc == NULL)
654 DEBUG_Printf(DBG_CHN_MESG, "Cannot open process <%lu>\n", pid);
655 return;
659 DEBUG_Printf(DBG_CHN_MESG, "Address Size State Type RWX\n");
661 while (VirtualQueryEx(hProc, addr, &mbi, sizeof(mbi)) >= sizeof(mbi))
663 switch (mbi.State)
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;
670 if (mbi.State != MEM_FREE)
672 switch (mbi.Type)
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;
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';
691 else
693 type = "";
694 prot[0] = '\0';
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;
702 if (hProc != DEBUG_CurrProcess->handle) CloseHandle(hProc);
705 struct dll_option_layout
707 void* next;
708 void* prev;
709 char* const* channels;
710 int nb_channels;
713 void DEBUG_DbgChannel(BOOL turn_on, const char* chnl, const char* name)
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;
725 if (DEBUG_GetSymbolValue("first_dll", -1, &val, FALSE) != gsv_found)
727 DEBUG_Printf(DBG_CHN_MESG, "Can't get first_option symbol");
728 return;
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; }
738 bAll = !strcmp("all", name);
739 while (addr && DEBUG_READ_MEM(addr, &dol, sizeof(dol)))
741 for (i = 0; i < dol.nb_channels; i++)
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))
747 if (turn_on) buffer[0] |= mask; else buffer[0] &= ~mask;
748 if (DEBUG_WRITE_MEM(str, buffer, 1)) done++;
751 addr = dol.next;
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);