Improve error reporting.
[wine/multimedia.git] / programs / winedbg / info.c
blob33c2cb8e39364fd18420062cde18049b27d430ce
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"
35 #include "wine/debug.h"
37 WINE_DEFAULT_DEBUG_CHANNEL(winedbg);
39 /***********************************************************************
40 * DEBUG_PrintBasic
42 * Implementation of the 'print' command.
44 void DEBUG_PrintBasic( const DBG_VALUE* value, int count, char format )
46 const char * default_format;
47 long long int res;
49 assert(value->cookie == DV_TARGET || value->cookie == DV_HOST);
50 if (value->type == NULL)
52 DEBUG_Printf("Unable to evaluate expression\n");
53 return;
56 default_format = NULL;
57 res = DEBUG_GetExprValue(value, &default_format);
59 switch (format)
61 case 'x':
62 if (value->addr.seg)
64 DEBUG_nchar += DEBUG_Printf("0x%04lx", (long unsigned int)res);
66 else
68 DEBUG_nchar += DEBUG_Printf("0x%08lx", (long unsigned int)res);
70 break;
72 case 'd':
73 DEBUG_nchar += DEBUG_Printf("%ld\n", (long int)res);
74 break;
76 case 'c':
77 DEBUG_nchar += DEBUG_Printf("%d = '%c'",
78 (char)(res & 0xff), (char)(res & 0xff));
79 break;
81 case 'u':
83 WCHAR wch = (WCHAR)(res & 0xFFFF);
84 DEBUG_nchar += DEBUG_Printf("%d = '", (unsigned)(res & 0xffff));
85 DEBUG_OutputW(&wch, 1);
86 DEBUG_Printf("'");
88 break;
90 case 'i':
91 case 's':
92 case 'w':
93 case 'b':
94 DEBUG_Printf("Format specifier '%c' is meaningless in 'print' command\n", format);
95 case 0:
96 if (default_format == NULL) break;
98 if (strstr(default_format, "%S") != NULL)
100 const char* ptr;
101 int state = 0;
103 /* FIXME: simplistic implementation for default_format being
104 * foo%Sbar => will print foo, then string then bar
106 for (ptr = default_format; *ptr; ptr++)
108 if (*ptr == '%')
110 state++;
112 else if (state == 1)
114 if (*ptr == 'S')
116 DBG_ADDR addr;
118 addr.seg = 0;
119 addr.off = (long)res;
120 DEBUG_nchar += DEBUG_PrintStringA(&addr, -1);
122 else
124 /* shouldn't happen */
125 DEBUG_Printf("%%%c", *ptr);
126 DEBUG_nchar += 2;
128 state = 0;
130 else
132 DEBUG_OutputA(ptr, 1);
133 DEBUG_nchar++;
137 else if (strcmp(default_format, "%B") == 0)
139 DEBUG_nchar += DEBUG_Printf("%s", res ? "true" : "false");
141 else if (strcmp(default_format, "%R") == 0)
143 if (value->cookie == DV_HOST)
144 DEBUG_InfoRegisters((CONTEXT*)value->addr.off);
145 else
146 DEBUG_Printf("NIY: info on register struct in debuggee address space\n");
147 DEBUG_nchar = 0;
149 else
151 DEBUG_nchar += DEBUG_Printf(default_format, res);
153 break;
158 /***********************************************************************
159 * DEBUG_PrintAddress
161 * Print an 16- or 32-bit address, with the nearest symbol if any.
163 struct symbol_info
164 DEBUG_PrintAddress( const DBG_ADDR *addr, enum dbg_mode mode, int flag )
166 struct symbol_info rtn;
168 const char *name = DEBUG_FindNearestSymbol( addr, flag, &rtn.sym, 0,
169 &rtn.list );
171 if (addr->seg) DEBUG_Printf("0x%04lx:", addr->seg & 0xFFFF);
172 if (mode != MODE_32) DEBUG_Printf("0x%04lx", addr->off);
173 else DEBUG_Printf("0x%08lx", addr->off);
174 if (name) DEBUG_Printf(" (%s)", name);
175 return rtn;
177 /***********************************************************************
178 * DEBUG_PrintAddressAndArgs
180 * Print an 16- or 32-bit address, with the nearest symbol if any.
181 * Similar to DEBUG_PrintAddress, but we print the arguments to
182 * each function (if known). This is useful in a backtrace.
184 struct symbol_info
185 DEBUG_PrintAddressAndArgs( const DBG_ADDR *addr, enum dbg_mode mode,
186 unsigned int ebp, int flag )
188 struct symbol_info rtn;
190 const char *name = DEBUG_FindNearestSymbol( addr, flag, &rtn.sym, ebp,
191 &rtn.list );
193 if (addr->seg) DEBUG_Printf("0x%04lx:", addr->seg);
194 if (mode != MODE_32) DEBUG_Printf("0x%04lx", addr->off);
195 else DEBUG_Printf("0x%08lx", addr->off);
196 if (name) DEBUG_Printf(" (%s)", name);
198 return rtn;
202 /***********************************************************************
203 * DEBUG_Help
205 * Implementation of the 'help' command.
207 void DEBUG_Help(void)
209 int i = 0;
210 static const char * const helptext[] =
212 "The commands accepted by the Wine debugger are a reasonable",
213 "subset of the commands that gdb accepts.",
214 "The commands currently are:",
215 " help quit",
216 " break [*<addr>] watch *<addr>",
217 " delete break bpnum disable bpnum",
218 " enable bpnum condition <bpnum> [<expr>]",
219 " finish cont [N]",
220 " step [N] next [N]",
221 " stepi [N] nexti [N]",
222 " x <addr> print <expr>",
223 " display <expr> undisplay <disnum>",
224 " local display <expr> delete display <disnum>",
225 " enable display <disnum> disable display <disnum>",
226 " bt frame <n>",
227 " up down",
228 " list <lines> disassemble [<addr>][,<addr>]",
229 " show dir dir <path>",
230 " set <reg> = <expr> set *<addr> = <expr>",
231 " mode [16,32,vm86] pass",
232 " whatis walk [wnd,class,module,maps,",
233 " info (see 'help info' for options) process,thread,exception]",
235 "The 'x' command accepts repeat counts and formats (including 'i') in the",
236 "same way that gdb does.\n",
238 " The following are examples of legal expressions:",
239 " $eax $eax+0x3 0x1000 ($eip + 256) *$eax *($esp + 3)",
240 " Also, a nm format symbol table can be read from a file using the",
241 " symbolfile command.", /* Symbols can also be defined individually with",
242 " the define command.", */
244 NULL
247 while(helptext[i]) DEBUG_Printf("%s\n", helptext[i++]);
251 /***********************************************************************
252 * DEBUG_HelpInfo
254 * Implementation of the 'help info' command.
256 void DEBUG_HelpInfo(void)
258 int i = 0;
259 static const char * const infotext[] =
261 "The info commands allow you to get assorted bits of interesting stuff",
262 "to be displayed. The options are:",
263 " info break Dumps information about breakpoints",
264 " info display Shows auto-display expressions in use",
265 " info locals Displays values of all local vars for current frame",
266 " info module <handle> Displays internal module state",
267 " info reg Displays values in all registers at top of stack",
268 " info segments Dumps information about all known segments",
269 " info share Dumps information about shared libraries",
270 " info stack Dumps information about top of stack",
271 " info wnd <handle> Displays internal window state",
273 NULL
276 while(infotext[i]) DEBUG_Printf("%s\n", infotext[i++]);
279 /* FIXME: merge InfoClass and InfoClass2 */
280 void DEBUG_InfoClass(const char* name)
282 WNDCLASSEXA wca;
284 if (!GetClassInfoEx(0, name, &wca)) {
285 DEBUG_Printf("Cannot find class '%s'\n", name);
286 return;
289 DEBUG_Printf("Class '%s':\n", name);
290 DEBUG_Printf("style=%08x wndProc=%08lx\n"
291 "inst=%p icon=%p cursor=%p bkgnd=%p\n"
292 "clsExtra=%d winExtra=%d\n",
293 wca.style, (DWORD)wca.lpfnWndProc, wca.hInstance,
294 wca.hIcon, wca.hCursor, wca.hbrBackground,
295 wca.cbClsExtra, wca.cbWndExtra);
297 /* FIXME:
298 * + print #windows (or even list of windows...)
299 * + print extra bytes => this requires a window handle on this very class...
303 static void DEBUG_InfoClass2(HWND hWnd, const char* name)
305 WNDCLASSEXA wca;
307 if (!GetClassInfoEx((HINSTANCE)GetWindowLong(hWnd, GWL_HINSTANCE), name, &wca)) {
308 DEBUG_Printf("Cannot find class '%s'\n", name);
309 return;
312 DEBUG_Printf("Class '%s':\n", name);
313 DEBUG_Printf("style=%08x wndProc=%08lx\n"
314 "inst=%p icon=%p cursor=%p bkgnd=%p\n"
315 "clsExtra=%d winExtra=%d\n",
316 wca.style, (DWORD)wca.lpfnWndProc, wca.hInstance,
317 wca.hIcon, wca.hCursor, wca.hbrBackground,
318 wca.cbClsExtra, wca.cbWndExtra);
320 if (wca.cbClsExtra) {
321 int i;
322 WORD w;
324 DEBUG_Printf("Extra bytes:");
325 for (i = 0; i < wca.cbClsExtra / 2; i++) {
326 w = GetClassWord(hWnd, i * 2);
327 /* FIXME: depends on i386 endian-ity */
328 DEBUG_Printf(" %02x %02x", HIBYTE(w), LOBYTE(w));
330 DEBUG_Printf("\n");
332 DEBUG_Printf("\n");
335 struct class_walker {
336 ATOM* table;
337 int used;
338 int alloc;
341 static void DEBUG_WalkClassesHelper(HWND hWnd, struct class_walker* cw)
343 char clsName[128];
344 int i;
345 ATOM atom;
346 HWND child;
348 if (!GetClassName(hWnd, clsName, sizeof(clsName)))
349 return;
350 if ((atom = FindAtom(clsName)) == 0)
351 return;
353 for (i = 0; i < cw->used; i++) {
354 if (cw->table[i] == atom)
355 break;
357 if (i == cw->used) {
358 if (cw->used >= cw->alloc) {
359 cw->alloc += 16;
360 cw->table = DBG_realloc(cw->table, cw->alloc * sizeof(ATOM));
362 cw->table[cw->used++] = atom;
363 DEBUG_InfoClass2(hWnd, clsName);
365 do {
366 if ((child = GetWindow(hWnd, GW_CHILD)) != 0)
367 DEBUG_WalkClassesHelper(child, cw);
368 } while ((hWnd = GetWindow(hWnd, GW_HWNDNEXT)) != 0);
371 void DEBUG_WalkClasses(void)
373 struct class_walker cw;
375 cw.table = NULL;
376 cw.used = cw.alloc = 0;
377 DEBUG_WalkClassesHelper(GetDesktopWindow(), &cw);
378 DBG_free(cw.table);
381 void DEBUG_InfoWindow(HWND hWnd)
383 char clsName[128];
384 char wndName[128];
385 RECT clientRect;
386 RECT windowRect;
387 int i;
388 WORD w;
390 if (!GetClassName(hWnd, clsName, sizeof(clsName)))
391 strcpy(clsName, "-- Unknown --");
392 if (!GetWindowText(hWnd, wndName, sizeof(wndName)))
393 strcpy(wndName, "-- Empty --");
394 if (!GetClientRect(hWnd, &clientRect) ||
395 !MapWindowPoints( hWnd, 0, (LPPOINT) &clientRect, 2))
396 SetRectEmpty(&clientRect);
397 if (!GetWindowRect(hWnd, &windowRect))
398 SetRectEmpty(&windowRect);
400 /* FIXME missing fields: hmemTaskQ, hrgnUpdate, dce, flags, pProp, scroll */
401 DEBUG_Printf("next=%p child=%p parent=%p owner=%p class='%s'\n"
402 "inst=%p active=%p idmenu=%08lx\n"
403 "style=%08lx exstyle=%08lx wndproc=%08lx text='%s'\n"
404 "client=%ld,%ld-%ld,%ld window=%ld,%ld-%ld,%ld sysmenu=%p\n",
405 GetWindow(hWnd, GW_HWNDNEXT),
406 GetWindow(hWnd, GW_CHILD),
407 GetParent(hWnd),
408 GetWindow(hWnd, GW_OWNER),
409 clsName,
410 (HINSTANCE)GetWindowLong(hWnd, GWL_HINSTANCE),
411 GetLastActivePopup(hWnd),
412 GetWindowLong(hWnd, GWL_ID),
413 GetWindowLong(hWnd, GWL_STYLE),
414 GetWindowLong(hWnd, GWL_EXSTYLE),
415 GetWindowLong(hWnd, GWL_WNDPROC),
416 wndName,
417 clientRect.left, clientRect.top, clientRect.right, clientRect.bottom,
418 windowRect.left, windowRect.top, windowRect.right, windowRect.bottom,
419 GetSystemMenu(hWnd, FALSE));
421 if (GetClassLong(hWnd, GCL_CBWNDEXTRA)) {
422 DEBUG_Printf("Extra bytes:" );
423 for (i = 0; i < GetClassLong(hWnd, GCL_CBWNDEXTRA) / 2; i++) {
424 w = GetWindowWord(hWnd, i * 2);
425 /* FIXME: depends on i386 endian-ity */
426 DEBUG_Printf(" %02x %02x", HIBYTE(w), LOBYTE(w));
428 DEBUG_Printf("\n");
430 DEBUG_Printf("\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("%-16.16s %-17.17s %-8.8s %s\n",
444 "hwnd", "Class Name", " Style", " WndProc Text");
446 do {
447 if (!GetClassName(hWnd, clsName, sizeof(clsName)))
448 strcpy(clsName, "-- Unknown --");
449 if (!GetWindowText(hWnd, wndName, sizeof(wndName)))
450 strcpy(wndName, "-- Empty --");
452 /* FIXME: missing hmemTaskQ */
453 DEBUG_Printf("%*s%04x%*s", indent, "", (UINT)hWnd, 13-indent,"");
454 DEBUG_Printf("%-17.17s %08lx %08lx %.14s\n",
455 clsName, GetWindowLong(hWnd, GWL_STYLE),
456 GetWindowLong(hWnd, GWL_WNDPROC), wndName);
458 if ((child = GetWindow(hWnd, GW_CHILD)) != 0)
459 DEBUG_WalkWindows(child, indent + 1 );
460 } while ((hWnd = GetWindow(hWnd, GW_HWNDNEXT)) != 0);
463 void DEBUG_WalkProcess(void)
465 HANDLE snap = CreateToolhelp32Snapshot( TH32CS_SNAPPROCESS, 0 );
466 if (snap != INVALID_HANDLE_VALUE)
468 PROCESSENTRY32 entry;
469 DWORD current = DEBUG_CurrProcess ? DEBUG_CurrProcess->pid : 0;
470 BOOL ok;
472 entry.dwSize = sizeof(entry);
473 ok = Process32First( snap, &entry );
475 DEBUG_Printf(" %-8.8s %-8.8s %-8.8s %s\n",
476 "pid", "threads", "parent", "executable" );
477 while (ok)
479 if (entry.th32ProcessID != GetCurrentProcessId())
480 DEBUG_Printf("%c%08lx %-8ld %08lx '%s'\n",
481 (entry.th32ProcessID == current) ? '>' : ' ',
482 entry.th32ProcessID, entry.cntThreads,
483 entry.th32ParentProcessID, entry.szExeFile);
484 ok = Process32Next( snap, &entry );
486 CloseHandle( snap );
490 void DEBUG_WalkThreads(void)
492 HANDLE snap = CreateToolhelp32Snapshot( TH32CS_SNAPTHREAD, 0 );
493 if (snap != INVALID_HANDLE_VALUE)
495 THREADENTRY32 entry;
496 DWORD current = DEBUG_CurrThread ? DEBUG_CurrThread->tid : 0;
497 BOOL ok;
498 DWORD lastProcessId = 0;
500 entry.dwSize = sizeof(entry);
501 ok = Thread32First( snap, &entry );
503 DEBUG_Printf("%-8.8s %-8.8s %s\n", "process", "tid", "prio" );
504 while (ok)
506 if (entry.th32OwnerProcessID != GetCurrentProcessId())
508 /* FIXME: this assumes that, in the snapshot, all threads of a same process are
509 * listed sequentially, which is not specified in the doc (Wine's implementation
510 * does it)
512 if (entry.th32OwnerProcessID != lastProcessId)
514 DBG_PROCESS* p = DEBUG_GetProcess(entry.th32OwnerProcessID);
516 DEBUG_Printf("%08lx%s %s\n",
517 entry.th32OwnerProcessID, p ? " (D)" : "", p ? p->imageName : "");
518 lastProcessId = entry.th32OwnerProcessID;
520 DEBUG_Printf("\t%08lx %4ld%s\n",
521 entry.th32ThreadID, entry.tpBasePri,
522 (entry.th32ThreadID == current) ? " <==" : "");
525 ok = Thread32Next( snap, &entry );
528 CloseHandle( snap );
532 /***********************************************************************
533 * DEBUG_WalkExceptions
535 * Walk the exception frames of a given thread.
537 void DEBUG_WalkExceptions(DWORD tid)
539 DBG_THREAD * thread;
540 void *next_frame;
542 if (!DEBUG_CurrProcess || !DEBUG_CurrThread)
544 DEBUG_Printf("Cannot walk exceptions while no process is loaded\n");
545 return;
548 DEBUG_Printf("Exception frames:\n");
550 if (tid == DEBUG_CurrTid) thread = DEBUG_CurrThread;
551 else
553 thread = DEBUG_GetThread(DEBUG_CurrProcess, tid);
555 if (!thread)
557 DEBUG_Printf("Unknown thread id (0x%08lx) in current process\n", tid);
558 return;
560 if (SuspendThread( thread->handle ) == -1)
562 DEBUG_Printf("Can't suspend thread id (0x%08lx)\n", tid);
563 return;
567 if (!DEBUG_READ_MEM(thread->teb, &next_frame, sizeof(next_frame)))
569 DEBUG_Printf("Can't read TEB:except_frame\n");
570 return;
573 while (next_frame != (void *)-1)
575 EXCEPTION_REGISTRATION_RECORD frame;
577 DEBUG_Printf("%p: ", next_frame);
578 if (!DEBUG_READ_MEM(next_frame, &frame, sizeof(frame)))
580 DEBUG_Printf("Invalid frame address\n");
581 break;
583 DEBUG_Printf("prev=%p handler=%p\n", frame.Prev, frame.Handler);
584 next_frame = frame.Prev;
587 if (tid != DEBUG_CurrTid) ResumeThread( thread->handle );
591 void DEBUG_InfoSegments(DWORD start, int length)
593 char flags[3];
594 DWORD i;
595 LDT_ENTRY le;
597 if (length == -1) length = (8192 - start);
599 for (i = start; i < start + length; i++)
601 if (!GetThreadSelectorEntry(DEBUG_CurrThread->handle, (i << 3) | 7, &le))
602 continue;
604 if (le.HighWord.Bits.Type & 0x08)
606 flags[0] = (le.HighWord.Bits.Type & 0x2) ? 'r' : '-';
607 flags[1] = '-';
608 flags[2] = 'x';
610 else
612 flags[0] = 'r';
613 flags[1] = (le.HighWord.Bits.Type & 0x2) ? 'w' : '-';
614 flags[2] = '-';
616 DEBUG_Printf("%04lx: sel=%04lx base=%08x limit=%08x %d-bit %c%c%c\n",
617 i, (i<<3)|7,
618 (le.HighWord.Bits.BaseHi << 24) +
619 (le.HighWord.Bits.BaseMid << 16) + le.BaseLow,
620 ((le.HighWord.Bits.LimitHi << 8) + le.LimitLow) <<
621 (le.HighWord.Bits.Granularity ? 12 : 0),
622 le.HighWord.Bits.Default_Big ? 32 : 16,
623 flags[0], flags[1], flags[2] );
627 void DEBUG_InfoVirtual(DWORD pid)
629 MEMORY_BASIC_INFORMATION mbi;
630 char* addr = 0;
631 const char* state;
632 const char* type;
633 char prot[3+1];
634 HANDLE hProc;
636 if (pid == 0)
638 if (DEBUG_CurrProcess == NULL)
640 DEBUG_Printf("Cannot look at mapping of current process, while no process is loaded\n");
641 return;
643 hProc = DEBUG_CurrProcess->handle;
645 else
647 hProc = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, pid);
648 if (hProc == NULL)
650 DEBUG_Printf("Cannot open process <%lu>\n", pid);
651 return;
655 DEBUG_Printf("Address Size State Type RWX\n");
657 while (VirtualQueryEx(hProc, addr, &mbi, sizeof(mbi)) >= sizeof(mbi))
659 switch (mbi.State)
661 case MEM_COMMIT: state = "commit "; break;
662 case MEM_FREE: state = "free "; break;
663 case MEM_RESERVE: state = "reserve"; break;
664 default: state = "??? "; break;
666 if (mbi.State != MEM_FREE)
668 switch (mbi.Type)
670 case MEM_IMAGE: type = "image "; break;
671 case MEM_MAPPED: type = "mapped "; break;
672 case MEM_PRIVATE: type = "private"; break;
673 case 0: type = " "; break;
674 default: type = "??? "; break;
676 memset(prot, ' ' , sizeof(prot)-1);
677 prot[sizeof(prot)-1] = '\0';
678 if (mbi.AllocationProtect & (PAGE_READONLY|PAGE_READWRITE|PAGE_EXECUTE_READ|PAGE_EXECUTE_READWRITE))
679 prot[0] = 'R';
680 if (mbi.AllocationProtect & (PAGE_READWRITE|PAGE_EXECUTE_READWRITE))
681 prot[1] = 'W';
682 if (mbi.AllocationProtect & (PAGE_WRITECOPY|PAGE_EXECUTE_WRITECOPY))
683 prot[1] = 'C';
684 if (mbi.AllocationProtect & (PAGE_EXECUTE|PAGE_EXECUTE_READ|PAGE_EXECUTE_READWRITE))
685 prot[2] = 'X';
687 else
689 type = "";
690 prot[0] = '\0';
692 DEBUG_Printf("%08lx %08lx %s %s %s\n",
693 (DWORD)addr, mbi.RegionSize, state, type, prot);
694 if (addr + mbi.RegionSize < addr) /* wrap around ? */
695 break;
696 addr += mbi.RegionSize;
698 if (hProc != DEBUG_CurrProcess->handle) CloseHandle(hProc);
701 struct dll_option_layout
703 void* next;
704 void* prev;
705 char* const* channels;
706 int nb_channels;
709 void DEBUG_DbgChannel(BOOL turn_on, const char* chnl, const char* name)
711 DBG_VALUE val;
712 struct dll_option_layout dol;
713 int i;
714 char* str;
715 unsigned char buffer[32];
716 unsigned char mask;
717 int done = 0;
718 BOOL bAll;
719 void* addr;
721 if (DEBUG_GetSymbolValue("first_dll", -1, &val, FALSE) != gsv_found)
723 DEBUG_Printf("Can't get first_option symbol");
724 return;
726 addr = (void*)DEBUG_ToLinear(&val.addr);
727 if (!chnl) mask = 15;
728 else if (!strcmp(chnl, "fixme")) mask = 1;
729 else if (!strcmp(chnl, "err")) mask = 2;
730 else if (!strcmp(chnl, "warn")) mask = 4;
731 else if (!strcmp(chnl, "trace")) mask = 8;
732 else { DEBUG_Printf("Unknown channel %s\n", chnl); return; }
734 bAll = !strcmp("all", name);
735 while (addr && DEBUG_READ_MEM(addr, &dol, sizeof(dol)))
737 for (i = 0; i < dol.nb_channels; i++)
739 if (DEBUG_READ_MEM((void*)(dol.channels + i), &str, sizeof(str)) &&
740 DEBUG_READ_MEM(str, buffer, sizeof(buffer)) &&
741 (!strcmp(buffer + 1, name) || bAll))
743 if (turn_on) buffer[0] |= mask; else buffer[0] &= ~mask;
744 if (DEBUG_WRITE_MEM(str, buffer, 1)) done++;
747 addr = dol.next;
749 if (!done) DEBUG_Printf("Unable to find debug channel %s\n", name);
750 else WINE_TRACE("Changed %d channel instances\n", done);