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
36 /***********************************************************************
39 * Implementation of the 'print' command.
41 void DEBUG_PrintBasic( const DBG_VALUE
* value
, int count
, char format
)
43 const char * default_format
;
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");
53 default_format
= NULL
;
54 res
= DEBUG_GetExprValue(value
, &default_format
);
61 DEBUG_nchar
+= DEBUG_Printf(DBG_CHN_MESG
, "0x%04lx", (long unsigned int)res
);
65 DEBUG_nchar
+= DEBUG_Printf(DBG_CHN_MESG
, "0x%08lx", (long unsigned int)res
);
70 DEBUG_nchar
+= DEBUG_Printf(DBG_CHN_MESG
, "%ld\n", (long int)res
);
74 DEBUG_nchar
+= DEBUG_Printf(DBG_CHN_MESG
, "%d = '%c'",
75 (char)(res
& 0xff), (char)(res
& 0xff));
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
, "'");
91 DEBUG_Printf(DBG_CHN_MESG
, "Format specifier '%c' is meaningless in 'print' command\n", format
);
93 if (default_format
== NULL
) break;
95 if (strstr(default_format
, "%S") != NULL
)
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
++)
116 addr
.off
= (long)res
;
117 DEBUG_nchar
+= DEBUG_PrintStringA(DBG_CHN_MESG
, &addr
, -1);
121 /* shouldn't happen */
122 DEBUG_Printf(DBG_CHN_MESG
, "%%%c", *ptr
);
129 DEBUG_OutputA(DBG_CHN_MESG
, ptr
, 1);
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
);
143 DEBUG_Printf(DBG_CHN_MESG
, "NIY: info on register struct in debuggee address space\n");
148 DEBUG_nchar
+= DEBUG_Printf(DBG_CHN_MESG
, default_format
, res
);
155 /***********************************************************************
158 * Print an 16- or 32-bit address, with the nearest symbol if any.
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,
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
);
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.
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
,
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
);
199 /***********************************************************************
202 * Implementation of the 'help' command.
204 void DEBUG_Help(void)
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:",
213 " break [*<addr>] watch *<addr>",
214 " delete break bpnum disable bpnum",
215 " enable bpnum condition <bpnum> [<expr>]",
217 " step [N] next [N]",
218 " stepi [N] nexti [N]",
219 " x <addr> print <expr>",
220 " display <expr> undisplay <disnum>",
221 " local display <expr> delete display <disnum>",
222 " enable display <disnum> disable display <disnum>",
225 " list <lines> disassemble [<addr>][,<addr>]",
226 " show dir dir <path>",
227 " set <reg> = <expr> set *<addr> = <expr>",
228 " mode [16,32,vm86] pass",
229 " whatis walk [wnd,class,module,maps,",
230 " info (see 'help info' for options) process,thread,exception]",
232 "The 'x' command accepts repeat counts and formats (including 'i') in the",
233 "same way that gdb does.\n",
235 " The following are examples of legal expressions:",
236 " $eax $eax+0x3 0x1000 ($eip + 256) *$eax *($esp + 3)",
237 " Also, a nm format symbol table can be read from a file using the",
238 " symbolfile command.", /* Symbols can also be defined individually with",
239 " the define command.", */
244 while(helptext
[i
]) DEBUG_Printf(DBG_CHN_MESG
,"%s\n", helptext
[i
++]);
248 /***********************************************************************
251 * Implementation of the 'help info' command.
253 void DEBUG_HelpInfo(void)
256 static const char * const infotext
[] =
258 "The info commands allow you to get assorted bits of interesting stuff",
259 "to be displayed. The options are:",
260 " info break Dumps information about breakpoints",
261 " info display Shows auto-display expressions in use",
262 " info locals Displays values of all local vars for current frame",
263 " info module <handle> Displays internal module state",
264 " info reg Displays values in all registers at top of stack",
265 " info segments Dumps information about all known segments",
266 " info share Dumps information about shared libraries",
267 " info stack Dumps information about top of stack",
268 " info wnd <handle> Displays internal window state",
273 while(infotext
[i
]) DEBUG_Printf(DBG_CHN_MESG
,"%s\n", infotext
[i
++]);
276 /* FIXME: merge InfoClass and InfoClass2 */
277 void DEBUG_InfoClass(const char* name
)
281 if (!GetClassInfoEx(0, name
, &wca
)) {
282 DEBUG_Printf(DBG_CHN_MESG
, "Cannot find class '%s'\n", name
);
286 DEBUG_Printf(DBG_CHN_MESG
, "Class '%s':\n", name
);
287 DEBUG_Printf(DBG_CHN_MESG
,
288 "style=%08x wndProc=%08lx\n"
289 "inst=%p icon=%p cursor=%p bkgnd=%p\n"
290 "clsExtra=%d winExtra=%d\n",
291 wca
.style
, (DWORD
)wca
.lpfnWndProc
, wca
.hInstance
,
292 wca
.hIcon
, wca
.hCursor
, wca
.hbrBackground
,
293 wca
.cbClsExtra
, wca
.cbWndExtra
);
296 * + print #windows (or even list of windows...)
297 * + print extra bytes => this requires a window handle on this very class...
301 static void DEBUG_InfoClass2(HWND hWnd
, const char* name
)
305 if (!GetClassInfoEx((HINSTANCE
)GetWindowLong(hWnd
, GWL_HINSTANCE
), name
, &wca
)) {
306 DEBUG_Printf(DBG_CHN_MESG
, "Cannot find class '%s'\n", name
);
310 DEBUG_Printf(DBG_CHN_MESG
, "Class '%s':\n", name
);
311 DEBUG_Printf(DBG_CHN_MESG
,
312 "style=%08x wndProc=%08lx\n"
313 "inst=%p icon=%p cursor=%p bkgnd=%p\n"
314 "clsExtra=%d winExtra=%d\n",
315 wca
.style
, (DWORD
)wca
.lpfnWndProc
, wca
.hInstance
,
316 wca
.hIcon
, wca
.hCursor
, wca
.hbrBackground
,
317 wca
.cbClsExtra
, wca
.cbWndExtra
);
319 if (wca
.cbClsExtra
) {
323 DEBUG_Printf(DBG_CHN_MESG
, "Extra bytes:" );
324 for (i
= 0; i
< wca
.cbClsExtra
/ 2; i
++) {
325 w
= GetClassWord(hWnd
, i
* 2);
326 /* FIXME: depends on i386 endian-ity */
327 DEBUG_Printf(DBG_CHN_MESG
, " %02x", HIBYTE(w
));
328 DEBUG_Printf(DBG_CHN_MESG
, " %02x", LOBYTE(w
));
330 DEBUG_Printf(DBG_CHN_MESG
, "\n" );
332 DEBUG_Printf(DBG_CHN_MESG
, "\n" );
335 struct class_walker
{
341 static void DEBUG_WalkClassesHelper(HWND hWnd
, struct class_walker
* cw
)
348 if (!GetClassName(hWnd
, clsName
, sizeof(clsName
)))
350 if ((atom
= FindAtom(clsName
)) == 0)
353 for (i
= 0; i
< cw
->used
; i
++) {
354 if (cw
->table
[i
] == atom
)
358 if (cw
->used
>= cw
->alloc
) {
360 cw
->table
= DBG_realloc(cw
->table
, cw
->alloc
* sizeof(ATOM
));
362 cw
->table
[cw
->used
++] = atom
;
363 DEBUG_InfoClass2(hWnd
, clsName
);
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
;
376 cw
.used
= cw
.alloc
= 0;
377 DEBUG_WalkClassesHelper(GetDesktopWindow(), &cw
);
381 void DEBUG_InfoWindow(HWND hWnd
)
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(DBG_CHN_MESG
,
402 "next=%p child=%p parent=%p owner=%p class='%s'\n"
403 "inst=%p active=%p idmenu=%08lx\n"
404 "style=%08lx exstyle=%08lx wndproc=%08lx text='%s'\n"
405 "client=%ld,%ld-%ld,%ld window=%ld,%ld-%ld,%ld sysmenu=%p\n",
406 GetWindow(hWnd
, GW_HWNDNEXT
),
407 GetWindow(hWnd
, GW_CHILD
),
409 GetWindow(hWnd
, GW_OWNER
),
411 (HINSTANCE
)GetWindowLong(hWnd
, GWL_HINSTANCE
),
412 GetLastActivePopup(hWnd
),
413 GetWindowLong(hWnd
, GWL_ID
),
414 GetWindowLong(hWnd
, GWL_STYLE
),
415 GetWindowLong(hWnd
, GWL_EXSTYLE
),
416 GetWindowLong(hWnd
, GWL_WNDPROC
),
418 clientRect
.left
, clientRect
.top
, clientRect
.right
, clientRect
.bottom
,
419 windowRect
.left
, windowRect
.top
, windowRect
.right
, windowRect
.bottom
,
420 GetSystemMenu(hWnd
, FALSE
));
422 if (GetClassLong(hWnd
, GCL_CBWNDEXTRA
)) {
423 DEBUG_Printf(DBG_CHN_MESG
, "Extra bytes:" );
424 for (i
= 0; i
< GetClassLong(hWnd
, GCL_CBWNDEXTRA
) / 2; i
++) {
425 w
= GetWindowWord(hWnd
, i
* 2);
426 /* FIXME: depends on i386 endian-ity */
427 DEBUG_Printf(DBG_CHN_MESG
, " %02x", HIBYTE(w
));
428 DEBUG_Printf(DBG_CHN_MESG
, " %02x", LOBYTE(w
));
430 DEBUG_Printf(DBG_CHN_MESG
, "\n");
432 DEBUG_Printf(DBG_CHN_MESG
, "\n");
435 void DEBUG_WalkWindows(HWND hWnd
, int indent
)
442 hWnd
= GetDesktopWindow();
444 if (!indent
) /* first time around */
445 DEBUG_Printf(DBG_CHN_MESG
,
446 "%-16.16s %-17.17s %-8.8s %s\n",
447 "hwnd", "Class Name", " Style", " WndProc Text");
450 if (!GetClassName(hWnd
, clsName
, sizeof(clsName
)))
451 strcpy(clsName
, "-- Unknown --");
452 if (!GetWindowText(hWnd
, wndName
, sizeof(wndName
)))
453 strcpy(wndName
, "-- Empty --");
455 /* FIXME: missing hmemTaskQ */
456 DEBUG_Printf(DBG_CHN_MESG
, "%*s%04x%*s", indent
, "", (UINT
)hWnd
, 13-indent
,"");
457 DEBUG_Printf(DBG_CHN_MESG
, "%-17.17s %08lx %08lx %.14s\n",
458 clsName
, GetWindowLong(hWnd
, GWL_STYLE
),
459 GetWindowLong(hWnd
, GWL_WNDPROC
), wndName
);
461 if ((child
= GetWindow(hWnd
, GW_CHILD
)) != 0)
462 DEBUG_WalkWindows(child
, indent
+ 1 );
463 } while ((hWnd
= GetWindow(hWnd
, GW_HWNDNEXT
)) != 0);
466 void DEBUG_WalkProcess(void)
468 HANDLE snap
= CreateToolhelp32Snapshot( TH32CS_SNAPPROCESS
, 0 );
469 if (snap
!= INVALID_HANDLE_VALUE
)
471 PROCESSENTRY32 entry
;
472 DWORD current
= DEBUG_CurrProcess
? DEBUG_CurrProcess
->pid
: 0;
475 entry
.dwSize
= sizeof(entry
);
476 ok
= Process32First( snap
, &entry
);
478 DEBUG_Printf(DBG_CHN_MESG
, " %-8.8s %-8.8s %-8.8s %s\n",
479 "pid", "threads", "parent", "executable" );
482 if (entry
.th32ProcessID
!= GetCurrentProcessId())
483 DEBUG_Printf(DBG_CHN_MESG
, "%c%08lx %-8ld %08lx '%s'\n",
484 (entry
.th32ProcessID
== current
) ? '>' : ' ',
485 entry
.th32ProcessID
, entry
.cntThreads
,
486 entry
.th32ParentProcessID
, entry
.szExeFile
);
487 ok
= Process32Next( snap
, &entry
);
493 void DEBUG_WalkThreads(void)
495 HANDLE snap
= CreateToolhelp32Snapshot( TH32CS_SNAPTHREAD
, 0 );
496 if (snap
!= INVALID_HANDLE_VALUE
)
499 DWORD current
= DEBUG_CurrThread
? DEBUG_CurrThread
->tid
: 0;
501 DWORD lastProcessId
= 0;
503 entry
.dwSize
= sizeof(entry
);
504 ok
= Thread32First( snap
, &entry
);
506 DEBUG_Printf(DBG_CHN_MESG
, "%-8.8s %-8.8s %s\n", "process", "tid", "prio" );
509 if (entry
.th32OwnerProcessID
!= GetCurrentProcessId())
511 /* FIXME: this assumes that, in the snapshot, all threads of a same process are
512 * listed sequentially, which is not specified in the doc (Wine's implementation
515 if (entry
.th32OwnerProcessID
!= lastProcessId
)
517 DBG_PROCESS
* p
= DEBUG_GetProcess(entry
.th32OwnerProcessID
);
519 DEBUG_Printf(DBG_CHN_MESG
, "%08lx%s %s\n",
520 entry
.th32OwnerProcessID
, p
? " (D)" : "", p
? p
->imageName
: "");
521 lastProcessId
= entry
.th32OwnerProcessID
;
523 DEBUG_Printf(DBG_CHN_MESG
, "\t%08lx %4ld%s\n",
524 entry
.th32ThreadID
, entry
.tpBasePri
,
525 (entry
.th32ThreadID
== current
) ? " <==" : "");
528 ok
= Thread32Next( snap
, &entry
);
535 /***********************************************************************
536 * DEBUG_WalkExceptions
538 * Walk the exception frames of a given thread.
540 void DEBUG_WalkExceptions(DWORD tid
)
545 if (!DEBUG_CurrProcess
|| !DEBUG_CurrThread
)
547 DEBUG_Printf(DBG_CHN_MESG
,
548 "Cannot walk exceptions while no process is loaded\n");
552 DEBUG_Printf( DBG_CHN_MESG
, "Exception frames:\n" );
554 if (tid
== DEBUG_CurrTid
) thread
= DEBUG_CurrThread
;
557 thread
= DEBUG_GetThread(DEBUG_CurrProcess
, tid
);
561 DEBUG_Printf( DBG_CHN_MESG
, "Unknown thread id (0x%08lx) in current process\n", tid
);
564 if (SuspendThread( thread
->handle
) == -1)
566 DEBUG_Printf( DBG_CHN_MESG
, "Can't suspend thread id (0x%08lx)\n", tid
);
571 if (!DEBUG_READ_MEM(thread
->teb
, &next_frame
, sizeof(next_frame
)))
573 DEBUG_Printf( DBG_CHN_MESG
, "Can't read TEB:except_frame\n");
577 while (next_frame
!= (void *)-1)
579 EXCEPTION_REGISTRATION_RECORD frame
;
581 DEBUG_Printf( DBG_CHN_MESG
, "%p: ", next_frame
);
582 if (!DEBUG_READ_MEM(next_frame
, &frame
, sizeof(frame
)))
584 DEBUG_Printf( DBG_CHN_MESG
, "Invalid frame address\n" );
587 DEBUG_Printf( DBG_CHN_MESG
, "prev=%p handler=%p\n", frame
.Prev
, frame
.Handler
);
588 next_frame
= frame
.Prev
;
591 if (tid
!= DEBUG_CurrTid
) ResumeThread( thread
->handle
);
595 void DEBUG_InfoSegments(DWORD start
, int length
)
601 if (length
== -1) length
= (8192 - start
);
603 for (i
= start
; i
< start
+ length
; i
++)
605 if (!GetThreadSelectorEntry(DEBUG_CurrThread
->handle
, (i
<< 3) | 7, &le
))
608 if (le
.HighWord
.Bits
.Type
& 0x08)
610 flags
[0] = (le
.HighWord
.Bits
.Type
& 0x2) ? 'r' : '-';
617 flags
[1] = (le
.HighWord
.Bits
.Type
& 0x2) ? 'w' : '-';
620 DEBUG_Printf(DBG_CHN_MESG
,
621 "%04lx: sel=%04lx base=%08x limit=%08x %d-bit %c%c%c\n",
623 (le
.HighWord
.Bits
.BaseHi
<< 24) +
624 (le
.HighWord
.Bits
.BaseMid
<< 16) + le
.BaseLow
,
625 ((le
.HighWord
.Bits
.LimitHi
<< 8) + le
.LimitLow
) <<
626 (le
.HighWord
.Bits
.Granularity
? 12 : 0),
627 le
.HighWord
.Bits
.Default_Big
? 32 : 16,
628 flags
[0], flags
[1], flags
[2] );
632 void DEBUG_InfoVirtual(DWORD pid
)
634 MEMORY_BASIC_INFORMATION mbi
;
643 if (DEBUG_CurrProcess
== NULL
)
645 DEBUG_Printf(DBG_CHN_MESG
,
646 "Cannot look at mapping of current process, while no process is loaded\n");
649 hProc
= DEBUG_CurrProcess
->handle
;
653 hProc
= OpenProcess(PROCESS_QUERY_INFORMATION
| PROCESS_VM_READ
, FALSE
, pid
);
656 DEBUG_Printf(DBG_CHN_MESG
, "Cannot open process <%lu>\n", pid
);
661 DEBUG_Printf(DBG_CHN_MESG
, "Address Size State Type RWX\n");
663 while (VirtualQueryEx(hProc
, addr
, &mbi
, sizeof(mbi
)) >= sizeof(mbi
))
667 case MEM_COMMIT
: state
= "commit "; break;
668 case MEM_FREE
: state
= "free "; break;
669 case MEM_RESERVE
: state
= "reserve"; break;
670 default: state
= "??? "; break;
672 if (mbi
.State
!= MEM_FREE
)
676 case MEM_IMAGE
: type
= "image "; break;
677 case MEM_MAPPED
: type
= "mapped "; break;
678 case MEM_PRIVATE
: type
= "private"; break;
679 case 0: type
= " "; break;
680 default: type
= "??? "; break;
682 memset(prot
, ' ' , sizeof(prot
)-1);
683 prot
[sizeof(prot
)-1] = '\0';
684 if (mbi
.AllocationProtect
& (PAGE_READONLY
|PAGE_READWRITE
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_READWRITE
))
686 if (mbi
.AllocationProtect
& (PAGE_READWRITE
|PAGE_EXECUTE_READWRITE
))
688 if (mbi
.AllocationProtect
& (PAGE_WRITECOPY
|PAGE_EXECUTE_WRITECOPY
))
690 if (mbi
.AllocationProtect
& (PAGE_EXECUTE
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_READWRITE
))
698 DEBUG_Printf(DBG_CHN_MESG
, "%08lx %08lx %s %s %s\n",
699 (DWORD
)addr
, mbi
.RegionSize
, state
, type
, prot
);
700 if (addr
+ mbi
.RegionSize
< addr
) /* wrap around ? */
702 addr
+= mbi
.RegionSize
;
704 if (hProc
!= DEBUG_CurrProcess
->handle
) CloseHandle(hProc
);
707 struct dll_option_layout
711 char* const* channels
;
715 void DEBUG_DbgChannel(BOOL turn_on
, const char* chnl
, const char* name
)
718 struct dll_option_layout dol
;
721 unsigned char buffer
[32];
727 if (DEBUG_GetSymbolValue("first_dll", -1, &val
, FALSE
) != gsv_found
)
729 DEBUG_Printf(DBG_CHN_MESG
, "Can't get first_option symbol");
732 addr
= (void*)DEBUG_ToLinear(&val
.addr
);
733 if (!chnl
) mask
= 15;
734 else if (!strcmp(chnl
, "fixme")) mask
= 1;
735 else if (!strcmp(chnl
, "err")) mask
= 2;
736 else if (!strcmp(chnl
, "warn")) mask
= 4;
737 else if (!strcmp(chnl
, "trace")) mask
= 8;
738 else { DEBUG_Printf(DBG_CHN_MESG
, "Unknown channel %s\n", chnl
); return; }
740 bAll
= !strcmp("all", name
);
741 while (addr
&& DEBUG_READ_MEM(addr
, &dol
, sizeof(dol
)))
743 for (i
= 0; i
< dol
.nb_channels
; i
++)
745 if (DEBUG_READ_MEM((void*)(dol
.channels
+ i
), &str
, sizeof(str
)) &&
746 DEBUG_READ_MEM(str
, buffer
, sizeof(buffer
)) &&
747 (!strcmp(buffer
+ 1, name
) || bAll
))
749 if (turn_on
) buffer
[0] |= mask
; else buffer
[0] &= ~mask
;
750 if (DEBUG_WRITE_MEM(str
, buffer
, 1)) done
++;
755 if (!done
) DEBUG_Printf(DBG_CHN_MESG
, "Unable to find debug channel %s\n", name
);
756 else DEBUG_Printf(DBG_CHN_TRACE
, "Changed %d channel instances\n", done
);