ntdll: Also ignore missing directories in NtGetNlsSectionPtr().
[wine.git] / programs / winedbg / info.c
blob123cbc934ef0f854b360b2d93f7ee4e9cd24ce3d
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) thread <tid>",
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 BOOL 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 opt = SymSetExtendedOption(SYMOPT_EX_WINE_NATIVE_MODULES, TRUE);
232 SymEnumerateModules64(dbg_curr_process->handle, info_mod_cb, &im);
233 SymSetExtendedOption(SYMOPT_EX_WINE_NATIVE_MODULES, 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 dbg_curr_process->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:%08x)", addr.Segment, (unsigned) addr.Offset);
988 break;
989 default: dbg_printf(" bad address");
991 dbg_printf(".\n");