ntoskrnl.exe: Add ObRegisterCallbacks stub.
[wine.git] / programs / winedbg / info.c
blob83341c0c79e6b3f399d3a8c855ec3e90bc5e3b2d
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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22 #include "config.h"
24 #include <stdlib.h>
25 #include <stdio.h>
26 #include <string.h>
27 #include <stdarg.h>
29 #include "debugger.h"
30 #include "wingdi.h"
31 #include "winuser.h"
32 #include "tlhelp32.h"
33 #include "wine/debug.h"
34 #include "wine/exception.h"
36 WINE_DEFAULT_DEBUG_CHANNEL(winedbg);
38 /***********************************************************************
39 * print_help
41 * Implementation of the 'help' command.
43 void print_help(void)
45 int i = 0;
46 static const char * const helptext[] =
48 "The commands accepted by the Wine debugger are a reasonable",
49 "subset of the commands that gdb accepts.",
50 "The commands currently are:",
51 " help quit",
52 " attach <wpid> detach",
53 " break [*<addr>] watch | rwatch *<addr>",
54 " delete break bpnum disable bpnum",
55 " enable bpnum condition <bpnum> [<expr>]",
56 " finish cont [N]",
57 " step [N] next [N]",
58 " stepi [N] nexti [N]",
59 " x <addr> print <expr>",
60 " display <expr> undisplay <disnum>",
61 " local display <expr> delete display <disnum>",
62 " enable display <disnum> disable display <disnum>",
63 " bt [<tid>|all] frame <n>",
64 " up down",
65 " list <lines> disassemble [<addr>][,<addr>]",
66 " show dir dir <path>",
67 " set <reg> = <expr> set *<addr> = <expr>",
68 " pass whatis",
69 " info (see 'help info' for options)",
71 "The 'x' command accepts repeat counts and formats (including 'i') in the",
72 "same way that gdb does.\n",
74 "The following are examples of legal expressions:",
75 " $eax $eax+0x3 0x1000 ($eip + 256) *$eax *($esp + 3)",
76 " Also, a nm format symbol table can be read from a file using the",
77 " symbolfile command.", /* Symbols can also be defined individually with",
78 " the define command.", */
79 "",
80 NULL
83 while (helptext[i]) dbg_printf("%s\n", helptext[i++]);
87 /***********************************************************************
88 * info_help
90 * Implementation of the 'help info' command.
92 void info_help(void)
94 int i = 0;
95 static const char * const infotext[] =
97 "The info commands allow you to get assorted bits of interesting stuff",
98 "to be displayed. The options are:",
99 " info break Displays information about breakpoints",
100 " info class <name> Displays information about window class <name>",
101 " info display Shows auto-display expressions in use",
102 " info except <pid> Shows exception handler chain (in a given process)",
103 " info locals Displays values of all local vars for current frame",
104 " info maps <pid> Shows virtual mappings (in a given process)",
105 " info process Shows all running processes",
106 " info reg Displays values of the general registers at top of stack",
107 " info all-reg Displays the general and floating point registers",
108 " info segments <pid> Displays information about all known segments",
109 " info share Displays all loaded modules",
110 " info share <addr> Displays internal module state",
111 " info stack [<len>] Dumps information about top of stack, up to len words",
112 " info symbol <sym> Displays information about a given symbol",
113 " info thread Shows all running threads",
114 " info wnd <handle> Displays internal window state",
116 NULL
119 while (infotext[i]) dbg_printf("%s\n", infotext[i++]);
122 static const char* get_symtype_str(const IMAGEHLP_MODULE64* mi)
124 switch (mi->SymType)
126 default:
127 case SymNone: return "--none--";
128 case SymCoff: return "COFF";
129 case SymCv: return "CodeView";
130 case SymPdb: return "PDB";
131 case SymExport: return "Export";
132 case SymDeferred: return "Deferred";
133 case SymSym: return "Sym";
134 case SymDia:
135 switch (mi->CVSig)
137 case 'S' | ('T' << 8) | ('A' << 16) | ('B' << 24):
138 return "Stabs";
139 case 'D' | ('W' << 8) | ('A' << 16) | ('R' << 24):
140 return "Dwarf";
141 default:
142 return "DIA";
148 struct info_module
150 IMAGEHLP_MODULE64 mi;
151 char name[64];
154 struct info_modules
156 struct info_module *modules;
157 unsigned num_alloc;
158 unsigned num_used;
161 static void module_print_info(const struct info_module *module, BOOL is_embedded)
163 dbg_printf("%*.*s-%*.*s\t%-16s%s\n",
164 ADDRWIDTH, ADDRWIDTH, wine_dbgstr_longlong(module->mi.BaseOfImage),
165 ADDRWIDTH, ADDRWIDTH, wine_dbgstr_longlong(module->mi.BaseOfImage + module->mi.ImageSize),
166 is_embedded ? "\\" : get_symtype_str(&module->mi), module->name);
169 static int module_compare(const void* p1, const void* p2)
171 struct info_module *left = (struct info_module *)p1;
172 struct info_module *right = (struct info_module *)p2;
173 LONGLONG val = left->mi.BaseOfImage - right->mi.BaseOfImage;
175 if (val < 0) return -1;
176 else if (val > 0) return 1;
177 else return 0;
180 static inline BOOL module_is_container(const struct info_module *wmod_cntnr,
181 const struct info_module *wmod_child)
183 return wmod_cntnr->mi.BaseOfImage <= wmod_child->mi.BaseOfImage &&
184 wmod_cntnr->mi.BaseOfImage + wmod_cntnr->mi.ImageSize >=
185 wmod_child->mi.BaseOfImage + wmod_child->mi.ImageSize;
188 static BOOL CALLBACK info_mod_cb(PCSTR mod_name, DWORD64 base, PVOID ctx)
190 struct info_modules *im = ctx;
192 if (im->num_used + 1 > im->num_alloc)
194 im->num_alloc += 16;
195 im->modules = dbg_heap_realloc(im->modules, im->num_alloc * sizeof(*im->modules));
197 im->modules[im->num_used].mi.SizeOfStruct = sizeof(im->modules[im->num_used].mi);
198 if (SymGetModuleInfo64(dbg_curr_process->handle, base, &im->modules[im->num_used].mi))
200 const int dst_len = sizeof(im->modules[im->num_used].name);
201 lstrcpynA(im->modules[im->num_used].name, mod_name, dst_len - 1);
202 im->modules[im->num_used].name[dst_len - 1] = 0;
203 im->num_used++;
205 return TRUE;
208 /***********************************************************************
209 * info_win32_module
211 * Display information about a given module (DLL or EXE), or about all modules
213 void info_win32_module(DWORD64 base)
215 struct info_modules im;
216 UINT i, j, num_printed = 0;
217 DWORD opt;
219 if (!dbg_curr_process)
221 dbg_printf("Cannot get info on module while no process is loaded\n");
222 return;
225 im.modules = NULL;
226 im.num_alloc = im.num_used = 0;
228 /* this is a wine specific options to return also ELF modules in the
229 * enumeration
231 SymSetOptions((opt = SymGetOptions()) | 0x40000000);
232 SymEnumerateModules64(dbg_curr_process->handle, info_mod_cb, &im);
233 SymSetOptions(opt);
235 qsort(im.modules, im.num_used, sizeof(im.modules[0]), module_compare);
237 dbg_printf("Module\tAddress\t\t\t%sDebug info\tName (%d modules)\n",
238 ADDRWIDTH == 16 ? "\t\t" : "", im.num_used);
240 for (i = 0; i < im.num_used; i++)
242 if (base &&
243 (base < im.modules[i].mi.BaseOfImage || base >= im.modules[i].mi.BaseOfImage + im.modules[i].mi.ImageSize))
244 continue;
245 if (strstr(im.modules[i].name, "<elf>"))
247 dbg_printf("ELF\t");
248 module_print_info(&im.modules[i], FALSE);
249 /* print all modules embedded in this one */
250 for (j = 0; j < im.num_used; j++)
252 if (!strstr(im.modules[j].name, "<elf>") && module_is_container(&im.modules[i], &im.modules[j]))
254 dbg_printf(" \\-PE\t");
255 module_print_info(&im.modules[j], TRUE);
259 else
261 /* check module is not embedded in another module */
262 for (j = 0; j < im.num_used; j++)
264 if (strstr(im.modules[j].name, "<elf>") && module_is_container(&im.modules[j], &im.modules[i]))
265 break;
267 if (j < im.num_used) continue;
268 if (strstr(im.modules[i].name, ".so") || strchr(im.modules[i].name, '<'))
269 dbg_printf("ELF\t");
270 else
271 dbg_printf("PE\t");
272 module_print_info(&im.modules[i], FALSE);
274 num_printed++;
276 HeapFree(GetProcessHeap(), 0, im.modules);
278 if (base && !num_printed)
279 dbg_printf("'0x%x%08x' is not a valid module address\n", (DWORD)(base >> 32), (DWORD)base);
282 struct class_walker
284 ATOM* table;
285 int used;
286 int alloc;
289 static void class_walker(HWND hWnd, struct class_walker* cw)
291 char clsName[128];
292 int i;
293 ATOM atom;
294 HWND child;
296 if (!GetClassNameA(hWnd, clsName, sizeof(clsName)))
297 return;
298 if ((atom = FindAtomA(clsName)) == 0)
299 return;
301 for (i = 0; i < cw->used; i++)
303 if (cw->table[i] == atom)
304 break;
306 if (i == cw->used)
308 if (cw->used >= cw->alloc)
310 cw->alloc += 16;
311 cw->table = dbg_heap_realloc(cw->table, cw->alloc * sizeof(ATOM));
313 cw->table[cw->used++] = atom;
314 info_win32_class(hWnd, clsName);
318 if ((child = GetWindow(hWnd, GW_CHILD)) != 0)
319 class_walker(child, cw);
320 } while ((hWnd = GetWindow(hWnd, GW_HWNDNEXT)) != 0);
323 void info_win32_class(HWND hWnd, const char* name)
325 WNDCLASSEXA wca;
326 HINSTANCE hInst = hWnd ? (HINSTANCE)GetWindowLongPtrW(hWnd, GWLP_HINSTANCE) : 0;
328 if (!name)
330 struct class_walker cw;
332 cw.table = NULL;
333 cw.used = cw.alloc = 0;
334 class_walker(GetDesktopWindow(), &cw);
335 HeapFree(GetProcessHeap(), 0, cw.table);
336 return;
339 if (!GetClassInfoExA(hInst, name, &wca))
341 dbg_printf("Cannot find class '%s'\n", name);
342 return;
345 dbg_printf("Class '%s':\n", name);
346 dbg_printf("style=0x%08x wndProc=%p\n"
347 "inst=%p icon=%p cursor=%p bkgnd=%p\n"
348 "clsExtra=%d winExtra=%d\n",
349 wca.style, wca.lpfnWndProc, wca.hInstance,
350 wca.hIcon, wca.hCursor, wca.hbrBackground,
351 wca.cbClsExtra, wca.cbWndExtra);
353 if (hWnd && wca.cbClsExtra)
355 int i;
356 WORD w;
358 dbg_printf("Extra bytes:");
359 for (i = 0; i < wca.cbClsExtra / 2; i++)
361 w = GetClassWord(hWnd, i * 2);
362 /* FIXME: depends on i386 endian-ity */
363 dbg_printf(" %02x %02x", HIBYTE(w), LOBYTE(w));
365 dbg_printf("\n");
367 dbg_printf("\n");
368 /* FIXME:
369 * + print #windows (or even list of windows...)
370 * + print extra bytes => this requires a window handle on this very class...
374 static void info_window(HWND hWnd, int indent)
376 char clsName[128];
377 char wndName[128];
378 HWND child;
382 if (!GetClassNameA(hWnd, clsName, sizeof(clsName)))
383 strcpy(clsName, "-- Unknown --");
384 if (!GetWindowTextA(hWnd, wndName, sizeof(wndName)))
385 strcpy(wndName, "-- Empty --");
387 dbg_printf("%*s%08lx%*s %-17.17s %08x %0*lx %08x %.14s\n",
388 indent, "", (DWORD_PTR)hWnd, 12 - indent, "",
389 clsName, GetWindowLongW(hWnd, GWL_STYLE),
390 ADDRWIDTH, (ULONG_PTR)GetWindowLongPtrW(hWnd, GWLP_WNDPROC),
391 GetWindowThreadProcessId(hWnd, NULL), wndName);
393 if ((child = GetWindow(hWnd, GW_CHILD)) != 0)
394 info_window(child, indent + 1);
395 } while ((hWnd = GetWindow(hWnd, GW_HWNDNEXT)) != 0);
398 void info_win32_window(HWND hWnd, BOOL detailed)
400 char clsName[128];
401 char wndName[128];
402 RECT clientRect;
403 RECT windowRect;
404 WORD w;
406 if (!IsWindow(hWnd)) hWnd = GetDesktopWindow();
408 if (!detailed)
410 dbg_printf("%-20.20s %-17.17s %-8.8s %-*.*s %-8.8s %s\n",
411 "Window handle", "Class Name", "Style",
412 ADDRWIDTH, ADDRWIDTH, "WndProc", "Thread", "Text");
413 info_window(hWnd, 0);
414 return;
417 if (!GetClassNameA(hWnd, clsName, sizeof(clsName)))
418 strcpy(clsName, "-- Unknown --");
419 if (!GetWindowTextA(hWnd, wndName, sizeof(wndName)))
420 strcpy(wndName, "-- Empty --");
421 if (!GetClientRect(hWnd, &clientRect) ||
422 !MapWindowPoints(hWnd, 0, (LPPOINT) &clientRect, 2))
423 SetRectEmpty(&clientRect);
424 if (!GetWindowRect(hWnd, &windowRect))
425 SetRectEmpty(&windowRect);
427 /* FIXME missing fields: hmemTaskQ, hrgnUpdate, dce, flags, pProp, scroll */
428 dbg_printf("next=%p child=%p parent=%p owner=%p class='%s'\n"
429 "inst=%p active=%p idmenu=%08lx\n"
430 "style=0x%08x exstyle=0x%08x wndproc=%p text='%s'\n"
431 "client=%d,%d-%d,%d window=%d,%d-%d,%d sysmenu=%p\n",
432 GetWindow(hWnd, GW_HWNDNEXT),
433 GetWindow(hWnd, GW_CHILD),
434 GetParent(hWnd),
435 GetWindow(hWnd, GW_OWNER),
436 clsName,
437 (HINSTANCE)GetWindowLongPtrW(hWnd, GWLP_HINSTANCE),
438 GetLastActivePopup(hWnd),
439 (ULONG_PTR)GetWindowLongPtrW(hWnd, GWLP_ID),
440 GetWindowLongW(hWnd, GWL_STYLE),
441 GetWindowLongW(hWnd, GWL_EXSTYLE),
442 (void*)GetWindowLongPtrW(hWnd, GWLP_WNDPROC),
443 wndName,
444 clientRect.left, clientRect.top, clientRect.right, clientRect.bottom,
445 windowRect.left, windowRect.top, windowRect.right, windowRect.bottom,
446 GetSystemMenu(hWnd, FALSE));
448 if (GetClassLongW(hWnd, GCL_CBWNDEXTRA))
450 UINT i;
452 dbg_printf("Extra bytes:");
453 for (i = 0; i < GetClassLongW(hWnd, GCL_CBWNDEXTRA) / 2; i++)
455 w = GetWindowWord(hWnd, i * 2);
456 /* FIXME: depends on i386 endian-ity */
457 dbg_printf(" %02x %02x", HIBYTE(w), LOBYTE(w));
459 dbg_printf("\n");
461 dbg_printf("\n");
464 struct dump_proc_entry
466 PROCESSENTRY32 proc;
467 unsigned children; /* index in dump_proc.entries of first child */
468 unsigned sibling; /* index in dump_proc.entries of next sibling */
471 struct dump_proc
473 struct dump_proc_entry*entries;
474 unsigned count;
475 unsigned alloc;
478 static unsigned get_parent(const struct dump_proc* dp, unsigned idx)
480 unsigned i;
482 for (i = 0; i < dp->count; i++)
484 if (i != idx && dp->entries[i].proc.th32ProcessID == dp->entries[idx].proc.th32ParentProcessID)
485 return i;
487 return -1;
490 static void dump_proc_info(const struct dump_proc* dp, unsigned idx, unsigned depth)
492 struct dump_proc_entry* dpe;
493 for ( ; idx != -1; idx = dp->entries[idx].sibling)
495 assert(idx < dp->count);
496 dpe = &dp->entries[idx];
497 dbg_printf("%c%08x %-8d ",
498 (dpe->proc.th32ProcessID == (dbg_curr_process ?
499 dbg_curr_process->pid : 0)) ? '>' : ' ',
500 dpe->proc.th32ProcessID, dpe->proc.cntThreads);
501 if (depth)
503 unsigned i;
504 for (i = 3 * (depth - 1); i > 0; i--) dbg_printf(" ");
505 dbg_printf("\\_ ");
507 dbg_printf("'%s'\n", dpe->proc.szExeFile);
508 dump_proc_info(dp, dpe->children, depth + 1);
512 void info_win32_processes(void)
514 HANDLE snap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
515 if (snap != INVALID_HANDLE_VALUE)
517 struct dump_proc dp;
518 unsigned i, first = -1;
519 BOOL ok;
521 dp.count = 0;
522 dp.alloc = 16;
523 dp.entries = HeapAlloc(GetProcessHeap(), 0, sizeof(*dp.entries) * dp.alloc);
524 if (!dp.entries)
526 CloseHandle(snap);
527 return;
529 dp.entries[dp.count].proc.dwSize = sizeof(dp.entries[dp.count].proc);
530 ok = Process32First(snap, &dp.entries[dp.count].proc);
532 /* fetch all process information into dp (skipping this debugger) */
533 while (ok)
535 if (dp.entries[dp.count].proc.th32ProcessID != GetCurrentProcessId())
536 dp.entries[dp.count++].children = -1;
537 if (dp.count >= dp.alloc)
539 dp.entries = HeapReAlloc(GetProcessHeap(), 0, dp.entries, sizeof(*dp.entries) * (dp.alloc *= 2));
540 if (!dp.entries) return;
542 dp.entries[dp.count].proc.dwSize = sizeof(dp.entries[dp.count].proc);
543 ok = Process32Next(snap, &dp.entries[dp.count].proc);
545 CloseHandle(snap);
546 /* chain the siblings wrt. their parent */
547 for (i = 0; i < dp.count; i++)
549 unsigned parent = get_parent(&dp, i);
550 unsigned *chain = parent == -1 ? &first : &dp.entries[parent].children;
551 dp.entries[i].sibling = *chain;
552 *chain = i;
554 dbg_printf(" %-8.8s %-8.8s %s (all id:s are in hex)\n", "pid", "threads", "executable");
555 dump_proc_info(&dp, first, 0);
556 HeapFree(GetProcessHeap(), 0, dp.entries);
560 static BOOL get_process_name(DWORD pid, PROCESSENTRY32* entry)
562 BOOL ret = FALSE;
563 HANDLE snap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
565 if (snap != INVALID_HANDLE_VALUE)
567 entry->dwSize = sizeof(*entry);
568 if (Process32First(snap, entry))
569 while (!(ret = (entry->th32ProcessID == pid)) &&
570 Process32Next(snap, entry));
571 CloseHandle(snap);
573 return ret;
576 void info_win32_threads(void)
578 HANDLE snap = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0);
579 if (snap != INVALID_HANDLE_VALUE)
581 THREADENTRY32 entry;
582 BOOL ok;
583 DWORD lastProcessId = 0;
585 entry.dwSize = sizeof(entry);
586 ok = Thread32First(snap, &entry);
588 dbg_printf("%-8.8s %-8.8s %s (all id:s are in hex)\n",
589 "process", "tid", "prio");
590 while (ok)
592 if (entry.th32OwnerProcessID != GetCurrentProcessId())
594 /* FIXME: this assumes that, in the snapshot, all threads of a same process are
595 * listed sequentially, which is not specified in the doc (Wine's implementation
596 * does it)
598 if (entry.th32OwnerProcessID != lastProcessId)
600 struct dbg_process* p = dbg_get_process(entry.th32OwnerProcessID);
601 PROCESSENTRY32 pcs_entry;
602 const char* exename;
604 if (p)
605 exename = dbg_W2A(p->imageName, -1);
606 else if (get_process_name(entry.th32OwnerProcessID, &pcs_entry))
607 exename = pcs_entry.szExeFile;
608 else
609 exename = "";
611 dbg_printf("%08x%s %s\n",
612 entry.th32OwnerProcessID, p ? " (D)" : "", exename);
613 lastProcessId = entry.th32OwnerProcessID;
615 dbg_printf("\t%08x %4d%s\n",
616 entry.th32ThreadID, entry.tpBasePri,
617 (entry.th32ThreadID == dbg_curr_tid) ? " <==" : "");
620 ok = Thread32Next(snap, &entry);
623 CloseHandle(snap);
627 /***********************************************************************
628 * info_win32_frame_exceptions
630 * Get info on the exception frames of a given thread.
632 void info_win32_frame_exceptions(DWORD tid)
634 struct dbg_thread* thread;
635 void* next_frame;
637 if (!dbg_curr_process || !dbg_curr_thread)
639 dbg_printf("Cannot get info on exceptions while no process is loaded\n");
640 return;
643 dbg_printf("Exception frames:\n");
645 if (tid == dbg_curr_tid) thread = dbg_curr_thread;
646 else
648 thread = dbg_get_thread(dbg_curr_process, tid);
650 if (!thread)
652 dbg_printf("Unknown thread id (%04x) in current process\n", tid);
653 return;
655 if (SuspendThread(thread->handle) == -1)
657 dbg_printf("Can't suspend thread id (%04x)\n", tid);
658 return;
662 if (!dbg_read_memory(thread->teb, &next_frame, sizeof(next_frame)))
664 dbg_printf("Can't read TEB:except_frame\n");
665 return;
668 while (next_frame != (void*)-1)
670 EXCEPTION_REGISTRATION_RECORD frame;
672 dbg_printf("%p: ", next_frame);
673 if (!dbg_read_memory(next_frame, &frame, sizeof(frame)))
675 dbg_printf("Invalid frame address\n");
676 break;
678 dbg_printf("prev=%p handler=%p\n", frame.Prev, frame.Handler);
679 next_frame = frame.Prev;
682 if (tid != dbg_curr_tid) ResumeThread(thread->handle);
685 void info_win32_segments(DWORD start, int length)
687 char flags[3];
688 DWORD i;
689 LDT_ENTRY le;
691 if (length == -1) length = (8192 - start);
693 for (i = start; i < start + length; i++)
695 if (!dbg_curr_process->process_io->get_selector(dbg_curr_thread->handle, (i << 3) | 7, &le))
696 continue;
698 if (le.HighWord.Bits.Type & 0x08)
700 flags[0] = (le.HighWord.Bits.Type & 0x2) ? 'r' : '-';
701 flags[1] = '-';
702 flags[2] = 'x';
704 else
706 flags[0] = 'r';
707 flags[1] = (le.HighWord.Bits.Type & 0x2) ? 'w' : '-';
708 flags[2] = '-';
710 dbg_printf("%04x: sel=%04x base=%08x limit=%08x %d-bit %c%c%c\n",
711 i, (i << 3) | 7,
712 (le.HighWord.Bits.BaseHi << 24) +
713 (le.HighWord.Bits.BaseMid << 16) + le.BaseLow,
714 ((le.HighWord.Bits.LimitHi << 8) + le.LimitLow) <<
715 (le.HighWord.Bits.Granularity ? 12 : 0),
716 le.HighWord.Bits.Default_Big ? 32 : 16,
717 flags[0], flags[1], flags[2]);
721 void info_win32_virtual(DWORD pid)
723 MEMORY_BASIC_INFORMATION mbi;
724 char* addr = 0;
725 const char* state;
726 const char* type;
727 char prot[3+1];
728 HANDLE hProc;
730 if (pid == dbg_curr_pid)
732 if (dbg_curr_process == NULL)
734 dbg_printf("Cannot look at mapping of current process, while no process is loaded\n");
735 return;
737 hProc = dbg_curr_process->handle;
739 else
741 hProc = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, pid);
742 if (hProc == NULL)
744 dbg_printf("Cannot open process <%04x>\n", pid);
745 return;
749 dbg_printf("Address End State Type RWX\n");
751 while (VirtualQueryEx(hProc, addr, &mbi, sizeof(mbi)) >= sizeof(mbi))
753 switch (mbi.State)
755 case MEM_COMMIT: state = "commit "; break;
756 case MEM_FREE: state = "free "; break;
757 case MEM_RESERVE: state = "reserve"; break;
758 default: state = "??? "; break;
760 if (mbi.State != MEM_FREE)
762 switch (mbi.Type)
764 case MEM_IMAGE: type = "image "; break;
765 case MEM_MAPPED: type = "mapped "; break;
766 case MEM_PRIVATE: type = "private"; break;
767 case 0: type = " "; break;
768 default: type = "??? "; break;
770 memset(prot, ' ' , sizeof(prot) - 1);
771 prot[sizeof(prot) - 1] = '\0';
772 if (mbi.AllocationProtect & (PAGE_READONLY|PAGE_READWRITE|PAGE_EXECUTE_READ|PAGE_EXECUTE_READWRITE))
773 prot[0] = 'R';
774 if (mbi.AllocationProtect & (PAGE_READWRITE|PAGE_EXECUTE_READWRITE))
775 prot[1] = 'W';
776 if (mbi.AllocationProtect & (PAGE_WRITECOPY|PAGE_EXECUTE_WRITECOPY))
777 prot[1] = 'C';
778 if (mbi.AllocationProtect & (PAGE_EXECUTE|PAGE_EXECUTE_READ|PAGE_EXECUTE_READWRITE))
779 prot[2] = 'X';
781 else
783 type = "";
784 prot[0] = '\0';
786 dbg_printf("%08lx %08lx %s %s %s\n",
787 (DWORD_PTR)addr, (DWORD_PTR)addr + mbi.RegionSize - 1, state, type, prot);
788 if (addr + mbi.RegionSize < addr) /* wrap around ? */
789 break;
790 addr += mbi.RegionSize;
792 if (pid != dbg_curr_pid) CloseHandle(hProc);
795 void info_wine_dbg_channel(BOOL turn_on, const char* cls, const char* name)
797 struct dbg_lvalue lvalue;
798 struct __wine_debug_channel channel;
799 unsigned char mask;
800 int done = 0;
801 BOOL bAll;
802 void* addr;
804 if (!dbg_curr_process || !dbg_curr_thread)
806 dbg_printf("Cannot set/get debug channels while no process is loaded\n");
807 return;
810 if (symbol_get_lvalue("debug_options", -1, &lvalue, FALSE) != sglv_found)
812 return;
814 addr = memory_to_linear_addr(&lvalue.addr);
816 if (!cls) mask = ~0;
817 else if (!strcmp(cls, "fixme")) mask = (1 << __WINE_DBCL_FIXME);
818 else if (!strcmp(cls, "err")) mask = (1 << __WINE_DBCL_ERR);
819 else if (!strcmp(cls, "warn")) mask = (1 << __WINE_DBCL_WARN);
820 else if (!strcmp(cls, "trace")) mask = (1 << __WINE_DBCL_TRACE);
821 else
823 dbg_printf("Unknown debug class %s\n", cls);
824 return;
827 bAll = !strcmp("all", name);
828 while (addr && dbg_read_memory(addr, &channel, sizeof(channel)))
830 if (!channel.name[0]) break;
831 if (bAll || !strcmp( channel.name, name ))
833 if (turn_on) channel.flags |= mask;
834 else channel.flags &= ~mask;
835 if (dbg_write_memory(addr, &channel, sizeof(channel))) done++;
837 addr = (struct __wine_debug_channel *)addr + 1;
839 if (!done) dbg_printf("Unable to find debug channel %s\n", name);
840 else WINE_TRACE("Changed %d channel instances\n", done);
843 void info_win32_exception(void)
845 const EXCEPTION_RECORD* rec;
846 ADDRESS64 addr;
847 char hexbuf[MAX_OFFSET_TO_STR_LEN];
849 if (!dbg_curr_thread->in_exception)
851 dbg_printf("Thread isn't in an exception\n");
852 return;
854 rec = &dbg_curr_thread->excpt_record;
855 memory_get_current_pc(&addr);
857 /* print some infos */
858 dbg_printf("%s: ",
859 dbg_curr_thread->first_chance ? "First chance exception" : "Unhandled exception");
860 switch (rec->ExceptionCode)
862 case EXCEPTION_BREAKPOINT:
863 dbg_printf("breakpoint");
864 break;
865 case EXCEPTION_SINGLE_STEP:
866 dbg_printf("single step");
867 break;
868 case EXCEPTION_INT_DIVIDE_BY_ZERO:
869 dbg_printf("divide by zero");
870 break;
871 case EXCEPTION_INT_OVERFLOW:
872 dbg_printf("overflow");
873 break;
874 case EXCEPTION_ARRAY_BOUNDS_EXCEEDED:
875 dbg_printf("array bounds");
876 break;
877 case EXCEPTION_ILLEGAL_INSTRUCTION:
878 dbg_printf("illegal instruction");
879 break;
880 case EXCEPTION_STACK_OVERFLOW:
881 dbg_printf("stack overflow");
882 break;
883 case EXCEPTION_PRIV_INSTRUCTION:
884 dbg_printf("privileged instruction");
885 break;
886 case EXCEPTION_ACCESS_VIOLATION:
887 if (rec->NumberParameters == 2)
888 dbg_printf("page fault on %s access to 0x%08lx",
889 rec->ExceptionInformation[0] == EXCEPTION_WRITE_FAULT ? "write" :
890 rec->ExceptionInformation[0] == EXCEPTION_EXECUTE_FAULT ? "execute" : "read",
891 rec->ExceptionInformation[1]);
892 else
893 dbg_printf("page fault");
894 break;
895 case EXCEPTION_DATATYPE_MISALIGNMENT:
896 dbg_printf("Alignment");
897 break;
898 case DBG_CONTROL_C:
899 dbg_printf("^C");
900 break;
901 case CONTROL_C_EXIT:
902 dbg_printf("^C");
903 break;
904 case STATUS_POSSIBLE_DEADLOCK:
906 ADDRESS64 recaddr;
908 recaddr.Mode = AddrModeFlat;
909 recaddr.Offset = rec->ExceptionInformation[0];
911 dbg_printf("wait failed on critical section ");
912 print_address(&recaddr, FALSE);
914 break;
915 case EXCEPTION_WINE_STUB:
917 char dll[32], name[256];
918 memory_get_string(dbg_curr_process,
919 (void*)rec->ExceptionInformation[0], TRUE, FALSE,
920 dll, sizeof(dll));
921 if (HIWORD(rec->ExceptionInformation[1]))
922 memory_get_string(dbg_curr_process,
923 (void*)rec->ExceptionInformation[1], TRUE, FALSE,
924 name, sizeof(name));
925 else
926 sprintf( name, "%ld", rec->ExceptionInformation[1] );
927 dbg_printf("unimplemented function %s.%s called", dll, name);
929 break;
930 case EXCEPTION_WINE_ASSERTION:
931 dbg_printf("assertion failed");
932 break;
933 case EXCEPTION_FLT_DENORMAL_OPERAND:
934 dbg_printf("denormal float operand");
935 break;
936 case EXCEPTION_FLT_DIVIDE_BY_ZERO:
937 dbg_printf("divide by zero");
938 break;
939 case EXCEPTION_FLT_INEXACT_RESULT:
940 dbg_printf("inexact float result");
941 break;
942 case EXCEPTION_FLT_INVALID_OPERATION:
943 dbg_printf("invalid float operation");
944 break;
945 case EXCEPTION_FLT_OVERFLOW:
946 dbg_printf("floating point overflow");
947 break;
948 case EXCEPTION_FLT_UNDERFLOW:
949 dbg_printf("floating point underflow");
950 break;
951 case EXCEPTION_FLT_STACK_CHECK:
952 dbg_printf("floating point stack check");
953 break;
954 case CXX_EXCEPTION:
955 if(rec->NumberParameters == 3 && rec->ExceptionInformation[0] == CXX_FRAME_MAGIC)
956 dbg_printf("C++ exception(object = 0x%08lx, type = 0x%08lx)",
957 rec->ExceptionInformation[1], rec->ExceptionInformation[2]);
958 else if(rec->NumberParameters == 4 && rec->ExceptionInformation[0] == CXX_FRAME_MAGIC)
959 dbg_printf("C++ exception(object = %p, type = %p, base = %p)",
960 (void*)rec->ExceptionInformation[1], (void*)rec->ExceptionInformation[2],
961 (void*)rec->ExceptionInformation[3]);
962 else
963 dbg_printf("C++ exception with strange parameter count %d or magic 0x%08lx",
964 rec->NumberParameters, rec->ExceptionInformation[0]);
965 break;
966 default:
967 dbg_printf("0x%08x", rec->ExceptionCode);
968 break;
970 if (rec->ExceptionFlags & EH_STACK_INVALID)
971 dbg_printf(", invalid program stack");
973 switch (addr.Mode)
975 case AddrModeFlat:
976 dbg_printf(" in %d-bit code (%s)",
977 be_cpu->pointer_size * 8,
978 memory_offset_to_string(hexbuf, addr.Offset, 0));
979 break;
980 case AddrModeReal:
981 dbg_printf(" in vm86 code (%04x:%04x)", addr.Segment, (unsigned) addr.Offset);
982 break;
983 case AddrMode1616:
984 dbg_printf(" in 16-bit code (%04x:%04x)", addr.Segment, (unsigned) addr.Offset);
985 break;
986 case AddrMode1632:
987 dbg_printf(" in segmented 32-bit code (%04x:%08lx)", addr.Segment, (unsigned long) addr.Offset);
988 break;
989 default: dbg_printf(" bad address");
991 dbg_printf(".\n");