2 * Wine debugger utility routines
4 * Copyright 1993 Eric Youngdale
5 * Copyright 1995 Alexandre Julliard
19 /***********************************************************************
22 * Implementation of the 'print' command.
24 void DEBUG_PrintBasic( const DBG_VALUE* value, int count, char format )
26 char * default_format;
29 assert(value->cookie == DV_TARGET || value->cookie == DV_HOST);
30 if( value->type == NULL )
32 DEBUG_Printf(DBG_CHN_MESG, "Unable to evaluate expression\n");
36 default_format = NULL;
37 res = DEBUG_GetExprValue(value, &default_format);
44 DEBUG_nchar += DEBUG_Printf( DBG_CHN_MESG, "0x%04lx", (long unsigned int) res );
48 DEBUG_nchar += DEBUG_Printf( DBG_CHN_MESG, "0x%08lx", (long unsigned int) res );
53 DEBUG_nchar += DEBUG_Printf( DBG_CHN_MESG, "%ld\n", (long int) res );
57 DEBUG_nchar += DEBUG_Printf( DBG_CHN_MESG, "%d = '%c'",
58 (char)(res & 0xff), (char)(res & 0xff) );
65 DEBUG_Printf( DBG_CHN_MESG, "Format specifier '%c' is meaningless in 'print' command\n", format );
67 if( default_format != NULL )
69 if (strstr(default_format, "%S") == NULL)
71 DEBUG_nchar += DEBUG_Printf( DBG_CHN_MESG, default_format, res );
78 /* FIXME: simplistic implementation for default_format being
79 * foo%Sbar => will print foo, then string then bar
81 for (ptr = default_format; *ptr; ptr++)
83 if (*ptr == '%') state++;
89 char* str = (char*)(long)res;
91 for (; DEBUG_READ_MEM(str, &ch, 1) && ch; str++) {
92 DEBUG_Output(DBG_CHN_MESG, &ch, 1);
98 /* shouldn't happen */
99 DEBUG_Printf(DBG_CHN_MESG, "%%%c", *ptr);
106 DEBUG_Output(DBG_CHN_MESG, ptr, 1);
117 /***********************************************************************
120 * Print an 16- or 32-bit address, with the nearest symbol if any.
123 DEBUG_PrintAddress( const DBG_ADDR *addr, enum dbg_mode mode, int flag )
125 struct symbol_info rtn;
127 const char *name = DEBUG_FindNearestSymbol( addr, flag, &rtn.sym, 0,
130 if (addr->seg) DEBUG_Printf( DBG_CHN_MESG, "0x%04lx:", addr->seg&0xFFFF );
131 if (mode != MODE_32) DEBUG_Printf( DBG_CHN_MESG, "0x%04lx", addr->off );
132 else DEBUG_Printf( DBG_CHN_MESG, "0x%08lx", addr->off );
133 if (name) DEBUG_Printf( DBG_CHN_MESG, " (%s)", name );
136 /***********************************************************************
137 * DEBUG_PrintAddressAndArgs
139 * Print an 16- or 32-bit address, with the nearest symbol if any.
140 * Similar to DEBUG_PrintAddress, but we print the arguments to
141 * each function (if known). This is useful in a backtrace.
144 DEBUG_PrintAddressAndArgs( const DBG_ADDR *addr, enum dbg_mode mode,
145 unsigned int ebp, int flag )
147 struct symbol_info rtn;
149 const char *name = DEBUG_FindNearestSymbol( addr, flag, &rtn.sym, ebp,
152 if (addr->seg) DEBUG_Printf( DBG_CHN_MESG, "0x%04lx:", addr->seg );
153 if (mode != MODE_32) DEBUG_Printf( DBG_CHN_MESG, "0x%04lx", addr->off );
154 else DEBUG_Printf( DBG_CHN_MESG, "0x%08lx", addr->off );
155 if (name) DEBUG_Printf( DBG_CHN_MESG, " (%s)", name );
161 /***********************************************************************
164 * Implementation of the 'help' command.
166 void DEBUG_Help(void)
169 static const char * const helptext[] =
171 "The commands accepted by the Wine debugger are a reasonable",
172 "subset of the commands that gdb accepts.",
173 "The commands currently are:",
175 " break [*<addr>] delete break bpnum",
176 " disable bpnum enable bpnum",
177 " condition <bpnum> [<expr>] pass",
179 " step [N] next [N]",
180 " stepi [N] nexti [N]",
181 " x <addr> print <expr>",
182 " set <reg> = <expr> set *<addr> = <expr>",
184 " list <lines> disassemble [<addr>][,<addr>]",
186 " show dir dir <path>",
187 " display <expr> undisplay <disnum>",
188 " delete display <disnum> debugmsg <class>[-+]<type>\n",
189 " mode [16,32,vm86] walk [wnd,class,queue,module,",
190 " whatis process,modref <pid>]",
191 " info (see 'help info' for options)\n",
193 "The 'x' command accepts repeat counts and formats (including 'i') in the",
194 "same way that gdb does.\n",
196 " The following are examples of legal expressions:",
197 " $eax $eax+0x3 0x1000 ($eip + 256) *$eax *($esp + 3)",
198 " Also, a nm format symbol table can be read from a file using the",
199 " symbolfile command. Symbols can also be defined individually with",
200 " the define command.",
205 while(helptext[i]) DEBUG_Printf(DBG_CHN_MESG,"%s\n", helptext[i++]);
209 /***********************************************************************
212 * Implementation of the 'help info' command.
214 void DEBUG_HelpInfo(void)
217 static const char * const infotext[] =
219 "The info commands allow you to get assorted bits of interesting stuff",
220 "to be displayed. The options are:",
221 " info break Dumps information about breakpoints",
222 " info display Shows auto-display expressions in use",
223 " info locals Displays values of all local vars for current frame",
224 " info maps Dumps all virtual memory mappings",
225 " info module <handle> Displays internal module state",
226 " info queue <handle> Displays internal queue state",
227 " info reg Displays values in all registers at top of stack",
228 " info segments Dumps information about all known segments",
229 " info share Dumps information about shared libraries",
230 " info stack Dumps information about top of stack",
231 " info wnd <handle> Displays internal window state",
236 while(infotext[i]) DEBUG_Printf(DBG_CHN_MESG,"%s\n", infotext[i++]);
239 /* FIXME: merge InfoClass and InfoClass2 */
240 void DEBUG_InfoClass(const char* name)
244 if (!GetClassInfoEx(0, name, &wca)) {
245 DEBUG_Printf(DBG_CHN_MESG, "Cannot find class '%s'\n", name);
249 DEBUG_Printf(DBG_CHN_MESG, "Class '%s':\n", name);
250 DEBUG_Printf(DBG_CHN_MESG,
251 "style=%08x wndProc=%08lx\n"
252 "inst=%p icon=%p cursor=%p bkgnd=%p\n"
253 "clsExtra=%d winExtra=%d\n",
254 wca.style, (DWORD)wca.lpfnWndProc, wca.hInstance,
255 wca.hIcon, wca.hCursor, wca.hbrBackground,
256 wca.cbClsExtra, wca.cbWndExtra);
259 * + print #windows (or even list of windows...)
260 * + print extra bytes => this requires a window handle on this very class...
264 static void DEBUG_InfoClass2(HWND hWnd, const char* name)
268 if (!GetClassInfoEx((HINSTANCE)GetWindowLong(hWnd, GWL_HINSTANCE), name, &wca)) {
269 DEBUG_Printf(DBG_CHN_MESG, "Cannot find class '%s'\n", name);
273 DEBUG_Printf(DBG_CHN_MESG, "Class '%s':\n", name);
274 DEBUG_Printf(DBG_CHN_MESG,
275 "style=%08x wndProc=%08lx\n"
276 "inst=%p icon=%p cursor=%p bkgnd=%p\n"
277 "clsExtra=%d winExtra=%d\n",
278 wca.style, (DWORD)wca.lpfnWndProc, wca.hInstance,
279 wca.hIcon, wca.hCursor, wca.hbrBackground,
280 wca.cbClsExtra, wca.cbWndExtra);
282 if (wca.cbClsExtra) {
286 DEBUG_Printf(DBG_CHN_MESG, "Extra bytes:" );
287 for (i = 0; i < wca.cbClsExtra / 2; i++) {
288 w = GetClassWord(hWnd, i * 2);
289 /* FIXME: depends on i386 endian-ity */
290 DEBUG_Printf(DBG_CHN_MESG, " %02x", HIBYTE(w));
291 DEBUG_Printf(DBG_CHN_MESG, " %02x", LOBYTE(w));
293 DEBUG_Printf(DBG_CHN_MESG, "\n" );
295 DEBUG_Printf(DBG_CHN_MESG, "\n" );
298 struct class_walker {
304 static void DEBUG_WalkClassesHelper(HWND hWnd, struct class_walker* cw)
311 if (!GetClassName(hWnd, clsName, sizeof(clsName)))
313 if ((atom = FindAtom(clsName)) == 0)
316 for (i = 0; i < cw->used; i++) {
317 if (cw->table[i] == atom)
321 if (cw->used >= cw->alloc) {
323 cw->table = DBG_realloc(cw->table, cw->alloc * sizeof(ATOM));
325 cw->table[cw->used++] = atom;
326 DEBUG_InfoClass2(hWnd, clsName);
329 if ((child = GetWindow(hWnd, GW_CHILD)) != 0)
330 DEBUG_WalkClassesHelper(child, cw);
331 } while ((hWnd = GetWindow(hWnd, GW_HWNDNEXT)) != 0);
334 void DEBUG_WalkClasses(void)
336 struct class_walker cw;
339 cw.used = cw.alloc = 0;
340 DEBUG_WalkClassesHelper(GetDesktopWindow(), &cw);
344 void DEBUG_DumpQueue(DWORD q)
346 DEBUG_Printf(DBG_CHN_MESG, "No longer doing info queue '0x%08lx'\n", q);
349 void DEBUG_WalkQueues(void)
351 DEBUG_Printf(DBG_CHN_MESG, "No longer walking queues list\n");
354 void DEBUG_InfoWindow(HWND hWnd)
363 if (!GetClassName(hWnd, clsName, sizeof(clsName)))
364 strcpy(clsName, "-- Unknown --");
365 if (!GetWindowText(hWnd, wndName, sizeof(wndName)))
366 strcpy(wndName, "-- Empty --");
367 if (!GetClientRect(hWnd, &clientRect))
368 SetRectEmpty(&clientRect);
369 if (!GetWindowRect(hWnd, &windowRect))
370 SetRectEmpty(&windowRect);
372 /* FIXME missing fields: hmemTaskQ, hrgnUpdate, dce, flags, pProp, scroll */
373 DEBUG_Printf(DBG_CHN_MESG,
374 "next=%p child=%p parent=%p owner=%p class='%s'\n"
375 "inst=%p active=%p idmenu=%08lx\n"
376 "style=%08lx exstyle=%08lx wndproc=%08lx text='%s'\n"
377 "client=%d,%d-%d,%d window=%d,%d-%d,%d sysmenu=%p\n",
378 GetWindow(hWnd, GW_HWNDNEXT),
379 GetWindow(hWnd, GW_CHILD),
381 GetWindow(hWnd, GW_OWNER),
383 (HINSTANCE)GetWindowLong(hWnd, GWL_HINSTANCE),
384 GetLastActivePopup(hWnd),
385 GetWindowLong(hWnd, GWL_ID),
386 GetWindowLong(hWnd, GWL_STYLE),
387 GetWindowLong(hWnd, GWL_EXSTYLE),
388 GetWindowLong(hWnd, GWL_WNDPROC),
390 clientRect.left, clientRect.top, clientRect.right, clientRect.bottom,
391 windowRect.left, windowRect.top, windowRect.right, windowRect.bottom,
392 GetSystemMenu(hWnd, FALSE));
394 if (GetClassLong(hWnd, GCL_CBWNDEXTRA)) {
395 DEBUG_Printf(DBG_CHN_MESG, "Extra bytes:" );
396 for (i = 0; i < GetClassLong(hWnd, GCL_CBWNDEXTRA) / 2; i++) {
397 w = GetWindowWord(hWnd, i * 2);
398 /* FIXME: depends on i386 endian-ity */
399 DEBUG_Printf(DBG_CHN_MESG, " %02x", HIBYTE(w));
400 DEBUG_Printf(DBG_CHN_MESG, " %02x", LOBYTE(w));
402 DEBUG_Printf(DBG_CHN_MESG, "\n");
404 DEBUG_Printf(DBG_CHN_MESG, "\n");
407 void DEBUG_WalkWindows(HWND hWnd, int indent)
414 hWnd = GetDesktopWindow();
416 if (!indent) /* first time around */
417 DEBUG_Printf(DBG_CHN_MESG,
418 "%-16.16s %-17.17s %-8.8s %s\n",
419 "hwnd", "Class Name", " Style", " WndProc Text");
422 if (!GetClassName(hWnd, clsName, sizeof(clsName)))
423 strcpy(clsName, "-- Unknown --");
424 if (!GetWindowText(hWnd, wndName, sizeof(wndName)))
425 strcpy(wndName, "-- Empty --");
427 /* FIXME: missing hmemTaskQ */
428 DEBUG_Printf(DBG_CHN_MESG, "%*s%04x%*s", indent, "", (UINT)hWnd, 13-indent,"");
429 DEBUG_Printf(DBG_CHN_MESG, "%-17.17s %08lx %08lx %.14s\n",
430 clsName, GetWindowLong(hWnd, GWL_STYLE),
431 GetWindowLong(hWnd, GWL_WNDPROC), wndName);
433 if ((child = GetWindow(hWnd, GW_CHILD)) != 0)
434 DEBUG_WalkWindows(child, indent + 1 );
435 } while ((hWnd = GetWindow(hWnd, GW_HWNDNEXT)) != 0);
438 void DEBUG_WalkProcess(void)
440 HANDLE snap = CreateToolhelp32Snapshot( TH32CS_SNAPPROCESS, 0 );
441 if (snap != INVALID_HANDLE_VALUE)
443 PROCESSENTRY32 entry;
444 DWORD current = DEBUG_CurrProcess ? DEBUG_CurrProcess->pid : 0;
447 entry.dwSize = sizeof(entry);
448 ok = Process32First( snap, &entry );
450 DEBUG_Printf(DBG_CHN_MESG, "%-8.8s %-8.8s %-8.8s %s\n",
451 "pid", "threads", "parent", "exe" );
454 if (entry.th32ProcessID != GetCurrentProcessId())
455 DEBUG_Printf(DBG_CHN_MESG, "%08lx %8ld %08lx '%s'%s\n",
456 entry.th32ProcessID, entry.cntThreads,
457 entry.th32ParentProcessID, entry.szExeFile,
458 (entry.th32ProcessID == current) ? " <==" : "" );
459 ok = Process32Next( snap, &entry );
465 void DEBUG_WalkThreads(void)
467 HANDLE snap = CreateToolhelp32Snapshot( TH32CS_SNAPTHREAD, 0 );
468 if (snap != INVALID_HANDLE_VALUE)
471 DWORD current = DEBUG_CurrThread ? DEBUG_CurrThread->tid : 0;
474 entry.dwSize = sizeof(entry);
475 ok = Thread32First( snap, &entry );
477 DEBUG_Printf(DBG_CHN_MESG, "%-8.8s %-8.8s %s\n",
478 "tid", "process", "prio" );
481 if (entry.th32OwnerProcessID != GetCurrentProcessId())
482 DEBUG_Printf(DBG_CHN_MESG, "%08lx %08lx %4ld%s\n",
483 entry.th32ThreadID, entry.th32OwnerProcessID,
484 entry.tpBasePri, (entry.th32ThreadID == current) ? " <==" : "" );
485 ok = Thread32Next( snap, &entry );
491 void DEBUG_WalkModref(DWORD p)
493 DEBUG_Printf(DBG_CHN_MESG, "No longer walking module references list\n");
496 void DEBUG_InfoSegments(DWORD start, int length)
502 if (length == -1) length = (8192 - start);
504 for (i = start; i < start + length; i++)
506 if (!GetThreadSelectorEntry(DEBUG_CurrThread->handle, (i << 3)|7, &le))
509 if (le.HighWord.Bits.Type & 0x08)
511 flags[0] = (le.HighWord.Bits.Type & 0x2) ? 'r' : '-';
518 flags[1] = (le.HighWord.Bits.Type & 0x2) ? 'w' : '-';
521 DEBUG_Printf(DBG_CHN_MESG,
522 "%04lx: sel=%04lx base=%08x limit=%08x %d-bit %c%c%c\n",
524 (le.HighWord.Bits.BaseHi << 24) +
525 (le.HighWord.Bits.BaseMid << 16) + le.BaseLow,
526 ((le.HighWord.Bits.LimitHi << 8) + le.LimitLow) <<
527 (le.HighWord.Bits.Granularity ? 12 : 0),
528 le.HighWord.Bits.Default_Big ? 32 : 16,
529 flags[0], flags[1], flags[2] );
533 void DEBUG_InfoVirtual(void)
535 DEBUG_Printf(DBG_CHN_MESG, "No longer providing virtual mapping information\n");