2 * Wine debugger utility routines
4 * Copyright 1993 Eric Youngdale
5 * Copyright 1995 Alexandre Julliard
18 /***********************************************************************
21 * Implementation of the 'print' command.
23 void DEBUG_PrintBasic( const DBG_VALUE
* value
, int count
, char format
)
25 char * default_format
;
28 assert(value
->cookie
== DV_TARGET
|| value
->cookie
== DV_HOST
);
29 if( value
->type
== NULL
)
31 DEBUG_Printf(DBG_CHN_MESG
, "Unable to evaluate expression\n");
35 default_format
= NULL
;
36 res
= DEBUG_GetExprValue(value
, &default_format
);
43 DEBUG_nchar
+= DEBUG_Printf( DBG_CHN_MESG
, "0x%04lx", (long unsigned int) res
);
47 DEBUG_nchar
+= DEBUG_Printf( DBG_CHN_MESG
, "0x%08lx", (long unsigned int) res
);
52 DEBUG_nchar
+= DEBUG_Printf( DBG_CHN_MESG
, "%ld\n", (long int) res
);
56 DEBUG_nchar
+= DEBUG_Printf( DBG_CHN_MESG
, "%d = '%c'",
57 (char)(res
& 0xff), (char)(res
& 0xff) );
64 DEBUG_Printf( DBG_CHN_MESG
, "Format specifier '%c' is meaningless in 'print' command\n", format
);
66 if( default_format
!= NULL
)
68 if (strstr(default_format
, "%S") == NULL
)
70 DEBUG_nchar
+= DEBUG_Printf( DBG_CHN_MESG
, default_format
, res
);
77 /* FIXME: simplistic implementation for default_format being
78 * foo%Sbar => will print foo, then string then bar
80 for (ptr
= default_format
; *ptr
; ptr
++)
82 if (*ptr
== '%') state
++;
88 char* str
= (char*)(long)res
;
90 for (; DEBUG_READ_MEM(str
, &ch
, 1) && ch
; str
++) {
91 DEBUG_Output(DBG_CHN_MESG
, &ch
, 1);
97 /* shouldn't happen */
98 DEBUG_Printf(DBG_CHN_MESG
, "%%%c", *ptr
);
105 DEBUG_Output(DBG_CHN_MESG
, ptr
, 1);
116 /***********************************************************************
119 * Print an 16- or 32-bit address, with the nearest symbol if any.
122 DEBUG_PrintAddress( const DBG_ADDR
*addr
, enum dbg_mode mode
, int flag
)
124 struct symbol_info rtn
;
126 const char *name
= DEBUG_FindNearestSymbol( addr
, flag
, &rtn
.sym
, 0,
129 if (addr
->seg
) DEBUG_Printf( DBG_CHN_MESG
, "0x%04lx:", addr
->seg
&0xFFFF );
130 if (mode
!= MODE_32
) DEBUG_Printf( DBG_CHN_MESG
, "0x%04lx", addr
->off
);
131 else DEBUG_Printf( DBG_CHN_MESG
, "0x%08lx", addr
->off
);
132 if (name
) DEBUG_Printf( DBG_CHN_MESG
, " (%s)", name
);
135 /***********************************************************************
136 * DEBUG_PrintAddressAndArgs
138 * Print an 16- or 32-bit address, with the nearest symbol if any.
139 * Similar to DEBUG_PrintAddress, but we print the arguments to
140 * each function (if known). This is useful in a backtrace.
143 DEBUG_PrintAddressAndArgs( const DBG_ADDR
*addr
, enum dbg_mode mode
,
144 unsigned int ebp
, int flag
)
146 struct symbol_info rtn
;
148 const char *name
= DEBUG_FindNearestSymbol( addr
, flag
, &rtn
.sym
, ebp
,
151 if (addr
->seg
) DEBUG_Printf( DBG_CHN_MESG
, "0x%04lx:", addr
->seg
);
152 if (mode
!= MODE_32
) DEBUG_Printf( DBG_CHN_MESG
, "0x%04lx", addr
->off
);
153 else DEBUG_Printf( DBG_CHN_MESG
, "0x%08lx", addr
->off
);
154 if (name
) DEBUG_Printf( DBG_CHN_MESG
, " (%s)", name
);
160 /***********************************************************************
163 * Implementation of the 'help' command.
165 void DEBUG_Help(void)
168 static const char * const helptext
[] =
170 "The commands accepted by the Wine debugger are a reasonable",
171 "subset of the commands that gdb accepts.",
172 "The commands currently are:",
174 " break [*<addr>] delete break bpnum",
175 " disable bpnum enable bpnum",
176 " condition <bpnum> [<expr>] pass",
178 " step [N] next [N]",
179 " stepi [N] nexti [N]",
180 " x <addr> print <expr>",
181 " set <reg> = <expr> set *<addr> = <expr>",
183 " list <lines> disassemble [<addr>][,<addr>]",
185 " show dir dir <path>",
186 " display <expr> undisplay <disnum>",
187 " delete display <disnum> debugmsg <class>[-+]<type>\n",
188 " mode [16,32,vm86] walk [wnd,class,queue,module,",
189 " whatis process,modref <pid>]",
190 " info (see 'help info' for options)\n",
192 "The 'x' command accepts repeat counts and formats (including 'i') in the",
193 "same way that gdb does.\n",
195 " The following are examples of legal expressions:",
196 " $eax $eax+0x3 0x1000 ($eip + 256) *$eax *($esp + 3)",
197 " Also, a nm format symbol table can be read from a file using the",
198 " symbolfile command. Symbols can also be defined individually with",
199 " the define command.",
204 while(helptext
[i
]) DEBUG_Printf(DBG_CHN_MESG
,"%s\n", helptext
[i
++]);
208 /***********************************************************************
211 * Implementation of the 'help info' command.
213 void DEBUG_HelpInfo(void)
216 static const char * const infotext
[] =
218 "The info commands allow you to get assorted bits of interesting stuff",
219 "to be displayed. The options are:",
220 " info break Dumps information about breakpoints",
221 " info display Shows auto-display expressions in use",
222 " info locals Displays values of all local vars for current frame",
223 " info maps Dumps all virtual memory mappings",
224 " info module <handle> Displays internal module state",
225 " info queue <handle> Displays internal queue state",
226 " info reg Displays values in all registers at top of stack",
227 " info segments Dumps information about all known segments",
228 " info share Dumps information about shared libraries",
229 " info stack Dumps information about top of stack",
230 " info wnd <handle> Displays internal window state",
235 while(infotext
[i
]) DEBUG_Printf(DBG_CHN_MESG
,"%s\n", infotext
[i
++]);
238 /* FIXME: merge InfoClass and InfoClass2 */
239 void DEBUG_InfoClass(const char* name
)
243 if (!GetClassInfoEx(0, name
, &wca
)) {
244 DEBUG_Printf(DBG_CHN_MESG
, "Cannot find class '%s'\n", name
);
248 DEBUG_Printf(DBG_CHN_MESG
, "Class '%s':\n", name
);
249 DEBUG_Printf(DBG_CHN_MESG
,
250 "style=%08x wndProc=%08lx\n"
251 "inst=%p icon=%p cursor=%p bkgnd=%p\n"
252 "clsExtra=%d winExtra=%d\n",
253 wca
.style
, (DWORD
)wca
.lpfnWndProc
, wca
.hInstance
,
254 wca
.hIcon
, wca
.hCursor
, wca
.hbrBackground
,
255 wca
.cbClsExtra
, wca
.cbWndExtra
);
258 * + print #windows (or even list of windows...)
259 * + print extra bytes => this requires a window handle on this very class...
263 static void DEBUG_InfoClass2(HWND hWnd
, const char* name
)
267 if (!GetClassInfoEx((HINSTANCE
)GetWindowLong(hWnd
, GWL_HINSTANCE
), name
, &wca
)) {
268 DEBUG_Printf(DBG_CHN_MESG
, "Cannot find class '%s'\n", name
);
272 DEBUG_Printf(DBG_CHN_MESG
, "Class '%s':\n", name
);
273 DEBUG_Printf(DBG_CHN_MESG
,
274 "style=%08x wndProc=%08lx\n"
275 "inst=%p icon=%p cursor=%p bkgnd=%p\n"
276 "clsExtra=%d winExtra=%d\n",
277 wca
.style
, (DWORD
)wca
.lpfnWndProc
, wca
.hInstance
,
278 wca
.hIcon
, wca
.hCursor
, wca
.hbrBackground
,
279 wca
.cbClsExtra
, wca
.cbWndExtra
);
281 if (wca
.cbClsExtra
) {
285 DEBUG_Printf(DBG_CHN_MESG
, "Extra bytes:" );
286 for (i
= 0; i
< wca
.cbClsExtra
/ 2; i
++) {
287 w
= GetClassWord(hWnd
, i
* 2);
288 /* FIXME: depends on i386 endian-ity */
289 DEBUG_Printf(DBG_CHN_MESG
, " %02x", HIBYTE(w
));
290 DEBUG_Printf(DBG_CHN_MESG
, " %02x", LOBYTE(w
));
292 DEBUG_Printf(DBG_CHN_MESG
, "\n" );
294 DEBUG_Printf(DBG_CHN_MESG
, "\n" );
297 struct class_walker
{
303 static void DEBUG_WalkClassesHelper(HWND hWnd
, struct class_walker
* cw
)
310 if (!GetClassName(hWnd
, clsName
, sizeof(clsName
)))
312 if ((atom
= FindAtom(clsName
)) == 0)
315 for (i
= 0; i
< cw
->used
; i
++) {
316 if (cw
->table
[i
] == atom
)
320 if (cw
->used
>= cw
->alloc
) {
322 cw
->table
= DBG_realloc(cw
->table
, cw
->alloc
* sizeof(ATOM
));
324 cw
->table
[cw
->used
++] = atom
;
325 DEBUG_InfoClass2(hWnd
, clsName
);
328 if ((child
= GetWindow(hWnd
, GW_CHILD
)) != 0)
329 DEBUG_WalkClassesHelper(child
, cw
);
330 } while ((hWnd
= GetWindow(hWnd
, GW_HWNDNEXT
)) != 0);
333 void DEBUG_WalkClasses(void)
335 struct class_walker cw
;
338 cw
.used
= cw
.alloc
= 0;
339 DEBUG_WalkClassesHelper(GetDesktopWindow(), &cw
);
343 void DEBUG_DumpQueue(DWORD q
)
345 DEBUG_Printf(DBG_CHN_MESG
, "No longer doing info queue '0x%08lx'\n", q
);
348 void DEBUG_WalkQueues(void)
350 DEBUG_Printf(DBG_CHN_MESG
, "No longer walking queues list\n");
353 void DEBUG_InfoWindow(HWND hWnd
)
362 if (!GetClassName(hWnd
, clsName
, sizeof(clsName
)))
363 strcpy(clsName
, "-- Unknown --");
364 if (!GetWindowText(hWnd
, wndName
, sizeof(wndName
)))
365 strcpy(wndName
, "-- Empty --");
366 if (!GetClientRect(hWnd
, &clientRect
))
367 SetRectEmpty(&clientRect
);
368 if (!GetWindowRect(hWnd
, &windowRect
))
369 SetRectEmpty(&windowRect
);
371 /* FIXME missing fields: hmemTaskQ, hrgnUpdate, dce, flags, pProp, scroll */
372 DEBUG_Printf(DBG_CHN_MESG
,
373 "next=%p child=%p parent=%p owner=%p class='%s'\n"
374 "inst=%p active=%p idmenu=%08lx\n"
375 "style=%08lx exstyle=%08lx wndproc=%08lx text='%s'\n"
376 "client=%d,%d-%d,%d window=%d,%d-%d,%d sysmenu=%p\n",
377 GetWindow(hWnd
, GW_HWNDNEXT
),
378 GetWindow(hWnd
, GW_CHILD
),
380 GetWindow(hWnd
, GW_OWNER
),
382 (HINSTANCE
)GetWindowLong(hWnd
, GWL_HINSTANCE
),
383 GetLastActivePopup(hWnd
),
384 GetWindowLong(hWnd
, GWL_ID
),
385 GetWindowLong(hWnd
, GWL_STYLE
),
386 GetWindowLong(hWnd
, GWL_EXSTYLE
),
387 GetWindowLong(hWnd
, GWL_WNDPROC
),
389 clientRect
.left
, clientRect
.top
, clientRect
.right
, clientRect
.bottom
,
390 windowRect
.left
, windowRect
.top
, windowRect
.right
, windowRect
.bottom
,
391 GetSystemMenu(hWnd
, FALSE
));
393 if (GetClassLong(hWnd
, GCL_CBWNDEXTRA
)) {
394 DEBUG_Printf(DBG_CHN_MESG
, "Extra bytes:" );
395 for (i
= 0; i
< GetClassLong(hWnd
, GCL_CBWNDEXTRA
) / 2; i
++) {
396 w
= GetWindowWord(hWnd
, i
* 2);
397 /* FIXME: depends on i386 endian-ity */
398 DEBUG_Printf(DBG_CHN_MESG
, " %02x", HIBYTE(w
));
399 DEBUG_Printf(DBG_CHN_MESG
, " %02x", LOBYTE(w
));
401 DEBUG_Printf(DBG_CHN_MESG
, "\n");
403 DEBUG_Printf(DBG_CHN_MESG
, "\n");
406 void DEBUG_WalkWindows(HWND hWnd
, int indent
)
413 hWnd
= GetDesktopWindow();
415 if (!indent
) /* first time around */
416 DEBUG_Printf(DBG_CHN_MESG
,
417 "%-16.16s %-17.17s %-8.8s %s\n",
418 "hwnd", "Class Name", " Style", " WndProc Text");
421 if (!GetClassName(hWnd
, clsName
, sizeof(clsName
)))
422 strcpy(clsName
, "-- Unknown --");
423 if (!GetWindowText(hWnd
, wndName
, sizeof(wndName
)))
424 strcpy(wndName
, "-- Empty --");
426 /* FIXME: missing hmemTaskQ */
427 DEBUG_Printf(DBG_CHN_MESG
, "%*s%04x%*s", indent
, "", (UINT
)hWnd
, 13-indent
,"");
428 DEBUG_Printf(DBG_CHN_MESG
, "%-17.17s %08lx %08lx %.14s\n",
429 clsName
, GetWindowLong(hWnd
, GWL_STYLE
),
430 GetWindowLong(hWnd
, GWL_WNDPROC
), wndName
);
432 if ((child
= GetWindow(hWnd
, GW_CHILD
)) != 0)
433 DEBUG_WalkWindows(child
, indent
+ 1 );
434 } while ((hWnd
= GetWindow(hWnd
, GW_HWNDNEXT
)) != 0);
437 void DEBUG_WalkProcess(void)
439 HANDLE snap
= CreateToolhelp32Snapshot( TH32CS_SNAPPROCESS
, 0 );
440 if (snap
!= INVALID_HANDLE_VALUE
)
442 PROCESSENTRY32 entry
;
443 DWORD current
= DEBUG_CurrProcess
? DEBUG_CurrProcess
->pid
: 0;
446 entry
.dwSize
= sizeof(entry
);
447 ok
= Process32First( snap
, &entry
);
449 DEBUG_Printf(DBG_CHN_MESG
, "%-8.8s %-8.8s %-8.8s %s\n",
450 "pid", "threads", "parent", "exe" );
453 if (entry
.th32ProcessID
!= GetCurrentProcessId())
454 DEBUG_Printf(DBG_CHN_MESG
, "%08lx %8ld %08lx '%s'%s\n",
455 entry
.th32ProcessID
, entry
.cntThreads
,
456 entry
.th32ParentProcessID
, entry
.szExeFile
,
457 (entry
.th32ProcessID
== current
) ? " <==" : "" );
458 ok
= Process32Next( snap
, &entry
);
464 void DEBUG_WalkThreads(void)
466 HANDLE snap
= CreateToolhelp32Snapshot( TH32CS_SNAPTHREAD
, 0 );
467 if (snap
!= INVALID_HANDLE_VALUE
)
470 DWORD current
= DEBUG_CurrThread
? DEBUG_CurrThread
->tid
: 0;
472 DWORD lastProcessId
= 0;
474 entry
.dwSize
= sizeof(entry
);
475 ok
= Thread32First( snap
, &entry
);
477 DEBUG_Printf(DBG_CHN_MESG
, "%-8.8s %-8.8s %s\n", "process", "tid", "prio" );
480 if (entry
.th32OwnerProcessID
!= GetCurrentProcessId())
482 /* FIXME: this assumes that, in the snapshot, all threads of a same process are
483 * listed sequentially, which is not specified in the doc (Wine's implementation
486 if (entry
.th32OwnerProcessID
!= lastProcessId
)
488 DBG_PROCESS
* p
= DEBUG_GetProcess(entry
.th32OwnerProcessID
);
490 DEBUG_Printf(DBG_CHN_MESG
, "%08lx%s %s\n",
491 entry
.th32OwnerProcessID
, p
? " (D)" : "", p
? p
->imageName
: "");
492 lastProcessId
= entry
.th32OwnerProcessID
;
494 DEBUG_Printf(DBG_CHN_MESG
, "\t%08lx %4ld%s\n",
495 entry
.th32ThreadID
, entry
.tpBasePri
,
496 (entry
.th32ThreadID
== current
) ? " <==" : "");
499 ok
= Thread32Next( snap
, &entry
);
506 void DEBUG_WalkModref(DWORD p
)
508 DEBUG_Printf(DBG_CHN_MESG
, "No longer walking module references list\n");
511 void DEBUG_InfoSegments(DWORD start
, int length
)
517 if (length
== -1) length
= (8192 - start
);
519 for (i
= start
; i
< start
+ length
; i
++)
521 if (!GetThreadSelectorEntry(DEBUG_CurrThread
->handle
, (i
<< 3)|7, &le
))
524 if (le
.HighWord
.Bits
.Type
& 0x08)
526 flags
[0] = (le
.HighWord
.Bits
.Type
& 0x2) ? 'r' : '-';
533 flags
[1] = (le
.HighWord
.Bits
.Type
& 0x2) ? 'w' : '-';
536 DEBUG_Printf(DBG_CHN_MESG
,
537 "%04lx: sel=%04lx base=%08x limit=%08x %d-bit %c%c%c\n",
539 (le
.HighWord
.Bits
.BaseHi
<< 24) +
540 (le
.HighWord
.Bits
.BaseMid
<< 16) + le
.BaseLow
,
541 ((le
.HighWord
.Bits
.LimitHi
<< 8) + le
.LimitLow
) <<
542 (le
.HighWord
.Bits
.Granularity
? 12 : 0),
543 le
.HighWord
.Bits
.Default_Big
? 32 : 16,
544 flags
[0], flags
[1], flags
[2] );
548 void DEBUG_InfoVirtual(void)
550 DEBUG_Printf(DBG_CHN_MESG
, "No longer providing virtual mapping information\n");