Change RECT to use LONG to match win32 standard headers and fix format
[wine.git] / programs / winedbg / info.c
blob4e31e5907b795397ec668c6c154eaf5ff4fa711c
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"
23 #include <stdlib.h>
24 #include <string.h>
25 #include "winbase.h"
26 #include "wingdi.h"
27 #include "winuser.h"
28 #include "tlhelp32.h"
29 #include "debugger.h"
30 #include "expr.h"
32 /***********************************************************************
33 * DEBUG_PrintBasic
35 * Implementation of the 'print' command.
37 void DEBUG_PrintBasic( const DBG_VALUE* value, int count, char format )
39 char * default_format;
40 long long int res;
42 assert(value->cookie == DV_TARGET || value->cookie == DV_HOST);
43 if (value->type == NULL)
45 DEBUG_Printf(DBG_CHN_MESG, "Unable to evaluate expression\n");
46 return;
49 default_format = NULL;
50 res = DEBUG_GetExprValue(value, &default_format);
52 switch (format)
54 case 'x':
55 if (value->addr.seg)
57 DEBUG_nchar += DEBUG_Printf(DBG_CHN_MESG, "0x%04lx", (long unsigned int)res);
59 else
61 DEBUG_nchar += DEBUG_Printf(DBG_CHN_MESG, "0x%08lx", (long unsigned int)res);
63 break;
65 case 'd':
66 DEBUG_nchar += DEBUG_Printf(DBG_CHN_MESG, "%ld\n", (long int)res);
67 break;
69 case 'c':
70 DEBUG_nchar += DEBUG_Printf(DBG_CHN_MESG, "%d = '%c'",
71 (char)(res & 0xff), (char)(res & 0xff));
72 break;
74 case 'u':
76 WCHAR wch = (WCHAR)(res & 0xFFFF);
77 DEBUG_nchar += DEBUG_Printf(DBG_CHN_MESG, "%d = '", (unsigned)(res & 0xffff));
78 DEBUG_OutputW(DBG_CHN_MESG, &wch, 1);
79 DEBUG_Printf(DBG_CHN_MESG, "'");
81 break;
83 case 'i':
84 case 's':
85 case 'w':
86 case 'b':
87 DEBUG_Printf(DBG_CHN_MESG, "Format specifier '%c' is meaningless in 'print' command\n", format);
88 case 0:
89 if (default_format == NULL) break;
91 if (strstr(default_format, "%S") != NULL)
93 char* ptr;
94 int state = 0;
96 /* FIXME: simplistic implementation for default_format being
97 * foo%Sbar => will print foo, then string then bar
99 for (ptr = default_format; *ptr; ptr++)
101 if (*ptr == '%')
103 state++;
105 else if (state == 1)
107 if (*ptr == 'S')
109 DBG_ADDR addr;
111 addr.seg = 0;
112 addr.off = (long)res;
113 DEBUG_nchar += DEBUG_PrintStringA(DBG_CHN_MESG, &addr, -1);
115 else
117 /* shouldn't happen */
118 DEBUG_Printf(DBG_CHN_MESG, "%%%c", *ptr);
119 DEBUG_nchar += 2;
121 state = 0;
123 else
125 DEBUG_OutputA(DBG_CHN_MESG, ptr, 1);
126 DEBUG_nchar++;
130 else if (strcmp(default_format, "%B") == 0)
132 DEBUG_nchar += DEBUG_Printf(DBG_CHN_MESG, "%s", res ? "true" : "false");
134 else if (strcmp(default_format, "%R") == 0)
136 if (value->cookie == DV_HOST)
137 DEBUG_InfoRegisters((CONTEXT*)value->addr.off);
138 else
139 DEBUG_Printf(DBG_CHN_MESG, "NIY: info on register struct in debuggee address space\n");
140 DEBUG_nchar = 0;
142 else
144 DEBUG_nchar += DEBUG_Printf(DBG_CHN_MESG, default_format, res);
146 break;
151 /***********************************************************************
152 * DEBUG_PrintAddress
154 * Print an 16- or 32-bit address, with the nearest symbol if any.
156 struct symbol_info
157 DEBUG_PrintAddress( const DBG_ADDR *addr, enum dbg_mode mode, int flag )
159 struct symbol_info rtn;
161 const char *name = DEBUG_FindNearestSymbol( addr, flag, &rtn.sym, 0,
162 &rtn.list );
164 if (addr->seg) DEBUG_Printf( DBG_CHN_MESG, "0x%04lx:", addr->seg&0xFFFF );
165 if (mode != MODE_32) DEBUG_Printf( DBG_CHN_MESG, "0x%04lx", addr->off );
166 else DEBUG_Printf( DBG_CHN_MESG, "0x%08lx", addr->off );
167 if (name) DEBUG_Printf( DBG_CHN_MESG, " (%s)", name );
168 return rtn;
170 /***********************************************************************
171 * DEBUG_PrintAddressAndArgs
173 * Print an 16- or 32-bit address, with the nearest symbol if any.
174 * Similar to DEBUG_PrintAddress, but we print the arguments to
175 * each function (if known). This is useful in a backtrace.
177 struct symbol_info
178 DEBUG_PrintAddressAndArgs( const DBG_ADDR *addr, enum dbg_mode mode,
179 unsigned int ebp, int flag )
181 struct symbol_info rtn;
183 const char *name = DEBUG_FindNearestSymbol( addr, flag, &rtn.sym, ebp,
184 &rtn.list );
186 if (addr->seg) DEBUG_Printf( DBG_CHN_MESG, "0x%04lx:", addr->seg );
187 if (mode != MODE_32) DEBUG_Printf( DBG_CHN_MESG, "0x%04lx", addr->off );
188 else DEBUG_Printf( DBG_CHN_MESG, "0x%08lx", addr->off );
189 if (name) DEBUG_Printf( DBG_CHN_MESG, " (%s)", name );
191 return rtn;
195 /***********************************************************************
196 * DEBUG_Help
198 * Implementation of the 'help' command.
200 void DEBUG_Help(void)
202 int i = 0;
203 static const char * const helptext[] =
205 "The commands accepted by the Wine debugger are a reasonable",
206 "subset of the commands that gdb accepts.",
207 "The commands currently are:",
208 " help quit",
209 " break [*<addr>] watch *<addr>",
210 " delete break bpnum disable bpnum",
211 " enable bpnum condition <bpnum> [<expr>]",
212 " finish cont [N]",
213 " step [N] next [N]",
214 " stepi [N] nexti [N]",
215 " x <addr> print <expr>",
216 " display <expr> undisplay <disnum>",
217 " delete display <disnum> pass",
218 " bt frame <n>",
219 " up down",
220 " list <lines> disassemble [<addr>][,<addr>]",
221 " show dir dir <path>",
222 " set <reg> = <expr> set *<addr> = <expr>",
223 " mode [16,32,vm86] walk [wnd,class,queue,module,",
224 " whatis process,modref <pid>]",
225 " info (see 'help info' for options) debugmsg <class>[-+]<type>\n",
227 "The 'x' command accepts repeat counts and formats (including 'i') in the",
228 "same way that gdb does.\n",
230 " The following are examples of legal expressions:",
231 " $eax $eax+0x3 0x1000 ($eip + 256) *$eax *($esp + 3)",
232 " Also, a nm format symbol table can be read from a file using the",
233 " symbolfile command. Symbols can also be defined individually with",
234 " the define command.",
236 NULL
239 while(helptext[i]) DEBUG_Printf(DBG_CHN_MESG,"%s\n", helptext[i++]);
243 /***********************************************************************
244 * DEBUG_HelpInfo
246 * Implementation of the 'help info' command.
248 void DEBUG_HelpInfo(void)
250 int i = 0;
251 static const char * const infotext[] =
253 "The info commands allow you to get assorted bits of interesting stuff",
254 "to be displayed. The options are:",
255 " info break Dumps information about breakpoints",
256 " info display Shows auto-display expressions in use",
257 " info locals Displays values of all local vars for current frame",
258 " info maps Dumps all virtual memory mappings",
259 " info module <handle> Displays internal module state",
260 " info queue <handle> Displays internal queue state",
261 " info reg Displays values in all registers at top of stack",
262 " info segments Dumps information about all known segments",
263 " info share Dumps information about shared libraries",
264 " info stack Dumps information about top of stack",
265 " info wnd <handle> Displays internal window state",
267 NULL
270 while(infotext[i]) DEBUG_Printf(DBG_CHN_MESG,"%s\n", infotext[i++]);
273 /* FIXME: merge InfoClass and InfoClass2 */
274 void DEBUG_InfoClass(const char* name)
276 WNDCLASSEXA wca;
278 if (!GetClassInfoEx(0, name, &wca)) {
279 DEBUG_Printf(DBG_CHN_MESG, "Cannot find class '%s'\n", name);
280 return;
283 DEBUG_Printf(DBG_CHN_MESG, "Class '%s':\n", name);
284 DEBUG_Printf(DBG_CHN_MESG,
285 "style=%08x wndProc=%08lx\n"
286 "inst=%p icon=%p cursor=%p bkgnd=%p\n"
287 "clsExtra=%d winExtra=%d\n",
288 wca.style, (DWORD)wca.lpfnWndProc, wca.hInstance,
289 wca.hIcon, wca.hCursor, wca.hbrBackground,
290 wca.cbClsExtra, wca.cbWndExtra);
292 /* FIXME:
293 * + print #windows (or even list of windows...)
294 * + print extra bytes => this requires a window handle on this very class...
298 static void DEBUG_InfoClass2(HWND hWnd, const char* name)
300 WNDCLASSEXA wca;
302 if (!GetClassInfoEx((HINSTANCE)GetWindowLong(hWnd, GWL_HINSTANCE), name, &wca)) {
303 DEBUG_Printf(DBG_CHN_MESG, "Cannot find class '%s'\n", name);
304 return;
307 DEBUG_Printf(DBG_CHN_MESG, "Class '%s':\n", name);
308 DEBUG_Printf(DBG_CHN_MESG,
309 "style=%08x wndProc=%08lx\n"
310 "inst=%p icon=%p cursor=%p bkgnd=%p\n"
311 "clsExtra=%d winExtra=%d\n",
312 wca.style, (DWORD)wca.lpfnWndProc, wca.hInstance,
313 wca.hIcon, wca.hCursor, wca.hbrBackground,
314 wca.cbClsExtra, wca.cbWndExtra);
316 if (wca.cbClsExtra) {
317 int i;
318 WORD w;
320 DEBUG_Printf(DBG_CHN_MESG, "Extra bytes:" );
321 for (i = 0; i < wca.cbClsExtra / 2; i++) {
322 w = GetClassWord(hWnd, i * 2);
323 /* FIXME: depends on i386 endian-ity */
324 DEBUG_Printf(DBG_CHN_MESG, " %02x", HIBYTE(w));
325 DEBUG_Printf(DBG_CHN_MESG, " %02x", LOBYTE(w));
327 DEBUG_Printf(DBG_CHN_MESG, "\n" );
329 DEBUG_Printf(DBG_CHN_MESG, "\n" );
332 struct class_walker {
333 ATOM* table;
334 int used;
335 int alloc;
338 static void DEBUG_WalkClassesHelper(HWND hWnd, struct class_walker* cw)
340 char clsName[128];
341 int i;
342 ATOM atom;
343 HWND child;
345 if (!GetClassName(hWnd, clsName, sizeof(clsName)))
346 return;
347 if ((atom = FindAtom(clsName)) == 0)
348 return;
350 for (i = 0; i < cw->used; i++) {
351 if (cw->table[i] == atom)
352 break;
354 if (i == cw->used) {
355 if (cw->used >= cw->alloc) {
356 cw->alloc += 16;
357 cw->table = DBG_realloc(cw->table, cw->alloc * sizeof(ATOM));
359 cw->table[cw->used++] = atom;
360 DEBUG_InfoClass2(hWnd, clsName);
362 do {
363 if ((child = GetWindow(hWnd, GW_CHILD)) != 0)
364 DEBUG_WalkClassesHelper(child, cw);
365 } while ((hWnd = GetWindow(hWnd, GW_HWNDNEXT)) != 0);
368 void DEBUG_WalkClasses(void)
370 struct class_walker cw;
372 cw.table = NULL;
373 cw.used = cw.alloc = 0;
374 DEBUG_WalkClassesHelper(GetDesktopWindow(), &cw);
375 DBG_free(cw.table);
378 void DEBUG_DumpQueue(DWORD q)
380 DEBUG_Printf(DBG_CHN_MESG, "No longer doing info queue '0x%08lx'\n", q);
383 void DEBUG_WalkQueues(void)
385 DEBUG_Printf(DBG_CHN_MESG, "No longer walking queues list\n");
388 void DEBUG_InfoWindow(HWND hWnd)
390 char clsName[128];
391 char wndName[128];
392 RECT clientRect;
393 RECT windowRect;
394 int i;
395 WORD w;
397 if (!GetClassName(hWnd, clsName, sizeof(clsName)))
398 strcpy(clsName, "-- Unknown --");
399 if (!GetWindowText(hWnd, wndName, sizeof(wndName)))
400 strcpy(wndName, "-- Empty --");
401 if (!GetClientRect(hWnd, &clientRect))
402 SetRectEmpty(&clientRect);
403 if (!GetWindowRect(hWnd, &windowRect))
404 SetRectEmpty(&windowRect);
406 /* FIXME missing fields: hmemTaskQ, hrgnUpdate, dce, flags, pProp, scroll */
407 DEBUG_Printf(DBG_CHN_MESG,
408 "next=%p child=%p parent=%p owner=%p class='%s'\n"
409 "inst=%p active=%p idmenu=%08lx\n"
410 "style=%08lx exstyle=%08lx wndproc=%08lx text='%s'\n"
411 "client=%ld,%ld-%ld,%ld window=%ld,%ld-%ld,%ld sysmenu=%p\n",
412 GetWindow(hWnd, GW_HWNDNEXT),
413 GetWindow(hWnd, GW_CHILD),
414 GetParent(hWnd),
415 GetWindow(hWnd, GW_OWNER),
416 clsName,
417 (HINSTANCE)GetWindowLong(hWnd, GWL_HINSTANCE),
418 GetLastActivePopup(hWnd),
419 GetWindowLong(hWnd, GWL_ID),
420 GetWindowLong(hWnd, GWL_STYLE),
421 GetWindowLong(hWnd, GWL_EXSTYLE),
422 GetWindowLong(hWnd, GWL_WNDPROC),
423 wndName,
424 clientRect.left, clientRect.top, clientRect.right, clientRect.bottom,
425 windowRect.left, windowRect.top, windowRect.right, windowRect.bottom,
426 GetSystemMenu(hWnd, FALSE));
428 if (GetClassLong(hWnd, GCL_CBWNDEXTRA)) {
429 DEBUG_Printf(DBG_CHN_MESG, "Extra bytes:" );
430 for (i = 0; i < GetClassLong(hWnd, GCL_CBWNDEXTRA) / 2; i++) {
431 w = GetWindowWord(hWnd, i * 2);
432 /* FIXME: depends on i386 endian-ity */
433 DEBUG_Printf(DBG_CHN_MESG, " %02x", HIBYTE(w));
434 DEBUG_Printf(DBG_CHN_MESG, " %02x", LOBYTE(w));
436 DEBUG_Printf(DBG_CHN_MESG, "\n");
438 DEBUG_Printf(DBG_CHN_MESG, "\n");
441 void DEBUG_WalkWindows(HWND hWnd, int indent)
443 char clsName[128];
444 char wndName[128];
445 HWND child;
447 if (!IsWindow(hWnd))
448 hWnd = GetDesktopWindow();
450 if (!indent) /* first time around */
451 DEBUG_Printf(DBG_CHN_MESG,
452 "%-16.16s %-17.17s %-8.8s %s\n",
453 "hwnd", "Class Name", " Style", " WndProc Text");
455 do {
456 if (!GetClassName(hWnd, clsName, sizeof(clsName)))
457 strcpy(clsName, "-- Unknown --");
458 if (!GetWindowText(hWnd, wndName, sizeof(wndName)))
459 strcpy(wndName, "-- Empty --");
461 /* FIXME: missing hmemTaskQ */
462 DEBUG_Printf(DBG_CHN_MESG, "%*s%04x%*s", indent, "", (UINT)hWnd, 13-indent,"");
463 DEBUG_Printf(DBG_CHN_MESG, "%-17.17s %08lx %08lx %.14s\n",
464 clsName, GetWindowLong(hWnd, GWL_STYLE),
465 GetWindowLong(hWnd, GWL_WNDPROC), wndName);
467 if ((child = GetWindow(hWnd, GW_CHILD)) != 0)
468 DEBUG_WalkWindows(child, indent + 1 );
469 } while ((hWnd = GetWindow(hWnd, GW_HWNDNEXT)) != 0);
472 void DEBUG_WalkProcess(void)
474 HANDLE snap = CreateToolhelp32Snapshot( TH32CS_SNAPPROCESS, 0 );
475 if (snap != INVALID_HANDLE_VALUE)
477 PROCESSENTRY32 entry;
478 DWORD current = DEBUG_CurrProcess ? DEBUG_CurrProcess->pid : 0;
479 BOOL ok;
481 entry.dwSize = sizeof(entry);
482 ok = Process32First( snap, &entry );
484 DEBUG_Printf(DBG_CHN_MESG, " %-8.8s %-8.8s %-8.8s %s\n",
485 "pid", "threads", "parent", "executable" );
486 while (ok)
488 if (entry.th32ProcessID != GetCurrentProcessId())
489 DEBUG_Printf(DBG_CHN_MESG, "%c%08lx %-8ld %08lx '%s'\n",
490 (entry.th32ProcessID == current) ? '>' : ' ',
491 entry.th32ProcessID, entry.cntThreads,
492 entry.th32ParentProcessID, entry.szExeFile);
493 ok = Process32Next( snap, &entry );
495 CloseHandle( snap );
499 void DEBUG_WalkThreads(void)
501 HANDLE snap = CreateToolhelp32Snapshot( TH32CS_SNAPTHREAD, 0 );
502 if (snap != INVALID_HANDLE_VALUE)
504 THREADENTRY32 entry;
505 DWORD current = DEBUG_CurrThread ? DEBUG_CurrThread->tid : 0;
506 BOOL ok;
507 DWORD lastProcessId = 0;
509 entry.dwSize = sizeof(entry);
510 ok = Thread32First( snap, &entry );
512 DEBUG_Printf(DBG_CHN_MESG, "%-8.8s %-8.8s %s\n", "process", "tid", "prio" );
513 while (ok)
515 if (entry.th32OwnerProcessID != GetCurrentProcessId())
517 /* FIXME: this assumes that, in the snapshot, all threads of a same process are
518 * listed sequentially, which is not specified in the doc (Wine's implementation
519 * does it)
521 if (entry.th32OwnerProcessID != lastProcessId)
523 DBG_PROCESS* p = DEBUG_GetProcess(entry.th32OwnerProcessID);
525 DEBUG_Printf(DBG_CHN_MESG, "%08lx%s %s\n",
526 entry.th32OwnerProcessID, p ? " (D)" : "", p ? p->imageName : "");
527 lastProcessId = entry.th32OwnerProcessID;
529 DEBUG_Printf(DBG_CHN_MESG, "\t%08lx %4ld%s\n",
530 entry.th32ThreadID, entry.tpBasePri,
531 (entry.th32ThreadID == current) ? " <==" : "");
534 ok = Thread32Next( snap, &entry );
537 CloseHandle( snap );
541 void DEBUG_WalkModref(DWORD p)
543 DEBUG_Printf(DBG_CHN_MESG, "No longer walking module references list\n");
546 /***********************************************************************
547 * DEBUG_WalkExceptions
549 * Walk the exception frames of a given thread.
551 void DEBUG_WalkExceptions(DWORD tid)
553 DBG_THREAD * thread;
554 void *next_frame;
556 DEBUG_Printf( DBG_CHN_MESG, "Exception frames:\n" );
558 if (tid == DEBUG_CurrTid) thread = DEBUG_CurrThread;
559 else
561 thread = DEBUG_GetThread(DEBUG_CurrProcess, tid);
563 if (!thread)
565 DEBUG_Printf( DBG_CHN_MESG, "Unknown thread id (0x%08lx) in current process\n", tid);
566 return;
568 if (SuspendThread( thread->handle ) == -1)
570 DEBUG_Printf( DBG_CHN_MESG, "Can't suspend thread id (0x%08lx)\n", tid);
571 return;
575 if (!DEBUG_READ_MEM(thread->teb, &next_frame, sizeof(next_frame)))
577 DEBUG_Printf( DBG_CHN_MESG, "Can't read TEB:except_frame\n");
578 return;
581 while (next_frame != (void *)-1)
583 EXCEPTION_FRAME frame;
585 DEBUG_Printf( DBG_CHN_MESG, "%p: ", next_frame );
586 if (!DEBUG_READ_MEM(next_frame, &frame, sizeof(frame)))
588 DEBUG_Printf( DBG_CHN_MESG, "Invalid frame address\n" );
589 break;
591 DEBUG_Printf( DBG_CHN_MESG, "prev=%p handler=%p\n", frame.Prev, frame.Handler );
592 next_frame = frame.Prev;
595 if (tid != DEBUG_CurrTid) ResumeThread( thread->handle );
599 void DEBUG_InfoSegments(DWORD start, int length)
601 char flags[3];
602 DWORD i;
603 LDT_ENTRY le;
605 if (length == -1) length = (8192 - start);
607 for (i = start; i < start + length; i++)
609 if (!GetThreadSelectorEntry(DEBUG_CurrThread->handle, (i << 3)|7, &le))
610 continue;
612 if (le.HighWord.Bits.Type & 0x08)
614 flags[0] = (le.HighWord.Bits.Type & 0x2) ? 'r' : '-';
615 flags[1] = '-';
616 flags[2] = 'x';
618 else
620 flags[0] = 'r';
621 flags[1] = (le.HighWord.Bits.Type & 0x2) ? 'w' : '-';
622 flags[2] = '-';
624 DEBUG_Printf(DBG_CHN_MESG,
625 "%04lx: sel=%04lx base=%08x limit=%08x %d-bit %c%c%c\n",
626 i, (i<<3)|7,
627 (le.HighWord.Bits.BaseHi << 24) +
628 (le.HighWord.Bits.BaseMid << 16) + le.BaseLow,
629 ((le.HighWord.Bits.LimitHi << 8) + le.LimitLow) <<
630 (le.HighWord.Bits.Granularity ? 12 : 0),
631 le.HighWord.Bits.Default_Big ? 32 : 16,
632 flags[0], flags[1], flags[2] );
636 void DEBUG_InfoVirtual(void)
638 MEMORY_BASIC_INFORMATION mbi;
639 char* addr = 0;
640 char* state;
641 char* type;
642 char prot[3+1];
644 if (DEBUG_CurrProcess == NULL)
645 return;
647 DEBUG_Printf(DBG_CHN_MESG, "Address Size State Type RWX\n");
649 while (VirtualQueryEx(DEBUG_CurrProcess->handle, addr, &mbi, sizeof(mbi)) >= sizeof(mbi))
651 switch (mbi.State)
653 case MEM_COMMIT: state = "commit "; break;
654 case MEM_FREE: state = "free "; break;
655 case MEM_RESERVE: state = "reserve"; break;
656 default: state = "??? "; break;
658 if (mbi.State != MEM_FREE)
660 switch (mbi.Type)
662 case MEM_IMAGE: type = "image "; break;
663 case MEM_MAPPED: type = "mapped "; break;
664 case MEM_PRIVATE: type = "private"; break;
665 case 0: type = " "; break;
666 default: type = "??? "; break;
668 memset(prot, ' ' , sizeof(prot)-1);
669 prot[sizeof(prot)-1] = '\0';
670 if (mbi.AllocationProtect & (PAGE_READONLY|PAGE_READWRITE|PAGE_EXECUTE_READ|PAGE_EXECUTE_READWRITE))
671 prot[0] = 'R';
672 if (mbi.AllocationProtect & (PAGE_READWRITE|PAGE_EXECUTE_READWRITE))
673 prot[1] = 'W';
674 if (mbi.AllocationProtect & (PAGE_WRITECOPY|PAGE_EXECUTE_WRITECOPY))
675 prot[1] = 'C';
676 if (mbi.AllocationProtect & (PAGE_EXECUTE|PAGE_EXECUTE_READ|PAGE_EXECUTE_READWRITE))
677 prot[2] = 'X';
679 else
681 type = "";
682 prot[0] = '\0';
684 DEBUG_Printf(DBG_CHN_MESG, "%08lx %08lx %s %s %s\n",
685 (DWORD)addr, mbi.RegionSize, state, type, prot);
686 if (addr + mbi.RegionSize < addr) /* wrap around ? */
687 break;
688 addr += mbi.RegionSize;
692 struct dll_option_layout
694 void* next;
695 void* prev;
696 char* const* channels;
697 int nb_channels;
700 void DEBUG_DbgChannel(BOOL turn_on, const char* chnl, const char* name)
702 DBG_VALUE val;
703 struct dll_option_layout dol;
704 int i;
705 char* str;
706 unsigned char buffer[32];
707 unsigned char mask;
708 int done = 0;
709 BOOL bAll;
710 void* addr;
712 if (DEBUG_GetSymbolValue("first_dll", -1, &val, FALSE) != gsv_found)
714 DEBUG_Printf(DBG_CHN_MESG, "Can't get first_option symbol");
715 return;
717 addr = (void*)DEBUG_ToLinear(&val.addr);
718 if (!chnl) mask = 15;
719 else if (!strcmp(chnl, "fixme")) mask = 1;
720 else if (!strcmp(chnl, "err")) mask = 2;
721 else if (!strcmp(chnl, "warn")) mask = 4;
722 else if (!strcmp(chnl, "trace")) mask = 8;
723 else { DEBUG_Printf(DBG_CHN_MESG, "Unknown channel %s\n", chnl); return; }
725 bAll = !strcmp("all", name);
726 while (addr && DEBUG_READ_MEM(addr, &dol, sizeof(dol)))
728 for (i = 0; i < dol.nb_channels; i++)
730 if (DEBUG_READ_MEM((void*)(dol.channels + i), &str, sizeof(str)) &&
731 DEBUG_READ_MEM(str, buffer, sizeof(buffer)) &&
732 (!strcmp(buffer + 1, name) || bAll))
734 if (turn_on) buffer[0] |= mask; else buffer[0] &= ~mask;
735 if (DEBUG_WRITE_MEM(str, buffer, 1)) done++;
738 addr = dol.next;
740 if (!done) DEBUG_Printf(DBG_CHN_MESG, "Unable to find debug channel %s\n", name);
741 else DEBUG_Printf(DBG_CHN_TRACE, "Changed %d channel instances\n", done);