wpcap: Implement pcap_set_datalink.
[wine.git] / programs / winedbg / info.c
blob08ac9389360377d5f6a3e030bb1a81db01241825
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 unsigned num_alloc;
152 unsigned num_used;
155 static void module_print_info(const IMAGEHLP_MODULE64* mi, BOOL is_embedded)
157 dbg_printf("%*.*s-%*.*s\t%-16s%s\n",
158 ADDRWIDTH, ADDRWIDTH, wine_dbgstr_longlong(mi->BaseOfImage),
159 ADDRWIDTH, ADDRWIDTH, wine_dbgstr_longlong(mi->BaseOfImage + mi->ImageSize),
160 is_embedded ? "\\" : get_symtype_str(mi), mi->ModuleName);
163 static int module_compare(const void* p1, const void* p2)
165 LONGLONG val = ((const IMAGEHLP_MODULE64*)p1)->BaseOfImage -
166 ((const IMAGEHLP_MODULE64*)p2)->BaseOfImage;
167 if (val < 0) return -1;
168 else if (val > 0) return 1;
169 else return 0;
172 static inline BOOL module_is_container(const IMAGEHLP_MODULE64* wmod_cntnr,
173 const IMAGEHLP_MODULE64* wmod_child)
175 return wmod_cntnr->BaseOfImage <= wmod_child->BaseOfImage &&
176 wmod_cntnr->BaseOfImage + wmod_cntnr->ImageSize >=
177 wmod_child->BaseOfImage + wmod_child->ImageSize;
180 static BOOL CALLBACK info_mod_cb(PCSTR mod_name, DWORD64 base, PVOID ctx)
182 struct info_module* im = ctx;
184 if (im->num_used + 1 > im->num_alloc)
186 im->num_alloc += 16;
187 im->mi = dbg_heap_realloc(im->mi, im->num_alloc * sizeof(*im->mi));
189 im->mi[im->num_used].SizeOfStruct = sizeof(im->mi[im->num_used]);
190 if (SymGetModuleInfo64(dbg_curr_process->handle, base, &im->mi[im->num_used]))
192 im->num_used++;
194 return TRUE;
197 /***********************************************************************
198 * info_win32_module
200 * Display information about a given module (DLL or EXE), or about all modules
202 void info_win32_module(DWORD64 base)
204 struct info_module im;
205 UINT i, j, num_printed = 0;
206 DWORD opt;
208 if (!dbg_curr_process)
210 dbg_printf("Cannot get info on module while no process is loaded\n");
211 return;
214 im.mi = NULL;
215 im.num_alloc = im.num_used = 0;
217 /* this is a wine specific options to return also ELF modules in the
218 * enumeration
220 SymSetOptions((opt = SymGetOptions()) | 0x40000000);
221 SymEnumerateModules64(dbg_curr_process->handle, info_mod_cb, (void*)&im);
222 SymSetOptions(opt);
224 qsort(im.mi, im.num_used, sizeof(im.mi[0]), module_compare);
226 dbg_printf("Module\tAddress\t\t\t%sDebug info\tName (%d modules)\n",
227 ADDRWIDTH == 16 ? "\t\t" : "", im.num_used);
229 for (i = 0; i < im.num_used; i++)
231 if (base &&
232 (base < im.mi[i].BaseOfImage || base >= im.mi[i].BaseOfImage + im.mi[i].ImageSize))
233 continue;
234 if (strstr(im.mi[i].ModuleName, "<elf>"))
236 dbg_printf("ELF\t");
237 module_print_info(&im.mi[i], FALSE);
238 /* print all modules embedded in this one */
239 for (j = 0; j < im.num_used; j++)
241 if (!strstr(im.mi[j].ModuleName, "<elf>") && module_is_container(&im.mi[i], &im.mi[j]))
243 dbg_printf(" \\-PE\t");
244 module_print_info(&im.mi[j], TRUE);
248 else
250 /* check module is not embedded in another module */
251 for (j = 0; j < im.num_used; j++)
253 if (strstr(im.mi[j].ModuleName, "<elf>") && module_is_container(&im.mi[j], &im.mi[i]))
254 break;
256 if (j < im.num_used) continue;
257 if (strstr(im.mi[i].ModuleName, ".so") || strchr(im.mi[i].ModuleName, '<'))
258 dbg_printf("ELF\t");
259 else
260 dbg_printf("PE\t");
261 module_print_info(&im.mi[i], FALSE);
263 num_printed++;
265 HeapFree(GetProcessHeap(), 0, im.mi);
267 if (base && !num_printed)
268 dbg_printf("'0x%x%08x' is not a valid module address\n", (DWORD)(base >> 32), (DWORD)base);
271 struct class_walker
273 ATOM* table;
274 int used;
275 int alloc;
278 static void class_walker(HWND hWnd, struct class_walker* cw)
280 char clsName[128];
281 int i;
282 ATOM atom;
283 HWND child;
285 if (!GetClassNameA(hWnd, clsName, sizeof(clsName)))
286 return;
287 if ((atom = FindAtomA(clsName)) == 0)
288 return;
290 for (i = 0; i < cw->used; i++)
292 if (cw->table[i] == atom)
293 break;
295 if (i == cw->used)
297 if (cw->used >= cw->alloc)
299 cw->alloc += 16;
300 cw->table = dbg_heap_realloc(cw->table, cw->alloc * sizeof(ATOM));
302 cw->table[cw->used++] = atom;
303 info_win32_class(hWnd, clsName);
307 if ((child = GetWindow(hWnd, GW_CHILD)) != 0)
308 class_walker(child, cw);
309 } while ((hWnd = GetWindow(hWnd, GW_HWNDNEXT)) != 0);
312 void info_win32_class(HWND hWnd, const char* name)
314 WNDCLASSEXA wca;
315 HINSTANCE hInst = hWnd ? (HINSTANCE)GetWindowLongPtrW(hWnd, GWLP_HINSTANCE) : 0;
317 if (!name)
319 struct class_walker cw;
321 cw.table = NULL;
322 cw.used = cw.alloc = 0;
323 class_walker(GetDesktopWindow(), &cw);
324 HeapFree(GetProcessHeap(), 0, cw.table);
325 return;
328 if (!GetClassInfoExA(hInst, name, &wca))
330 dbg_printf("Cannot find class '%s'\n", name);
331 return;
334 dbg_printf("Class '%s':\n", name);
335 dbg_printf("style=0x%08x wndProc=%p\n"
336 "inst=%p icon=%p cursor=%p bkgnd=%p\n"
337 "clsExtra=%d winExtra=%d\n",
338 wca.style, wca.lpfnWndProc, wca.hInstance,
339 wca.hIcon, wca.hCursor, wca.hbrBackground,
340 wca.cbClsExtra, wca.cbWndExtra);
342 if (hWnd && wca.cbClsExtra)
344 int i;
345 WORD w;
347 dbg_printf("Extra bytes:");
348 for (i = 0; i < wca.cbClsExtra / 2; i++)
350 w = GetClassWord(hWnd, i * 2);
351 /* FIXME: depends on i386 endian-ity */
352 dbg_printf(" %02x %02x", HIBYTE(w), LOBYTE(w));
354 dbg_printf("\n");
356 dbg_printf("\n");
357 /* FIXME:
358 * + print #windows (or even list of windows...)
359 * + print extra bytes => this requires a window handle on this very class...
363 static void info_window(HWND hWnd, int indent)
365 char clsName[128];
366 char wndName[128];
367 HWND child;
371 if (!GetClassNameA(hWnd, clsName, sizeof(clsName)))
372 strcpy(clsName, "-- Unknown --");
373 if (!GetWindowTextA(hWnd, wndName, sizeof(wndName)))
374 strcpy(wndName, "-- Empty --");
376 dbg_printf("%*s%08lx%*s %-17.17s %08x %0*lx %08x %.14s\n",
377 indent, "", (DWORD_PTR)hWnd, 12 - indent, "",
378 clsName, GetWindowLongW(hWnd, GWL_STYLE),
379 ADDRWIDTH, (ULONG_PTR)GetWindowLongPtrW(hWnd, GWLP_WNDPROC),
380 GetWindowThreadProcessId(hWnd, NULL), wndName);
382 if ((child = GetWindow(hWnd, GW_CHILD)) != 0)
383 info_window(child, indent + 1);
384 } while ((hWnd = GetWindow(hWnd, GW_HWNDNEXT)) != 0);
387 void info_win32_window(HWND hWnd, BOOL detailed)
389 char clsName[128];
390 char wndName[128];
391 RECT clientRect;
392 RECT windowRect;
393 WORD w;
395 if (!IsWindow(hWnd)) hWnd = GetDesktopWindow();
397 if (!detailed)
399 dbg_printf("%-20.20s %-17.17s %-8.8s %-*.*s %-8.8s %s\n",
400 "Window handle", "Class Name", "Style",
401 ADDRWIDTH, ADDRWIDTH, "WndProc", "Thread", "Text");
402 info_window(hWnd, 0);
403 return;
406 if (!GetClassNameA(hWnd, clsName, sizeof(clsName)))
407 strcpy(clsName, "-- Unknown --");
408 if (!GetWindowTextA(hWnd, wndName, sizeof(wndName)))
409 strcpy(wndName, "-- Empty --");
410 if (!GetClientRect(hWnd, &clientRect) ||
411 !MapWindowPoints(hWnd, 0, (LPPOINT) &clientRect, 2))
412 SetRectEmpty(&clientRect);
413 if (!GetWindowRect(hWnd, &windowRect))
414 SetRectEmpty(&windowRect);
416 /* FIXME missing fields: hmemTaskQ, hrgnUpdate, dce, flags, pProp, scroll */
417 dbg_printf("next=%p child=%p parent=%p owner=%p class='%s'\n"
418 "inst=%p active=%p idmenu=%08lx\n"
419 "style=0x%08x exstyle=0x%08x wndproc=%p text='%s'\n"
420 "client=%d,%d-%d,%d window=%d,%d-%d,%d sysmenu=%p\n",
421 GetWindow(hWnd, GW_HWNDNEXT),
422 GetWindow(hWnd, GW_CHILD),
423 GetParent(hWnd),
424 GetWindow(hWnd, GW_OWNER),
425 clsName,
426 (HINSTANCE)GetWindowLongPtrW(hWnd, GWLP_HINSTANCE),
427 GetLastActivePopup(hWnd),
428 (ULONG_PTR)GetWindowLongPtrW(hWnd, GWLP_ID),
429 GetWindowLongW(hWnd, GWL_STYLE),
430 GetWindowLongW(hWnd, GWL_EXSTYLE),
431 (void*)GetWindowLongPtrW(hWnd, GWLP_WNDPROC),
432 wndName,
433 clientRect.left, clientRect.top, clientRect.right, clientRect.bottom,
434 windowRect.left, windowRect.top, windowRect.right, windowRect.bottom,
435 GetSystemMenu(hWnd, FALSE));
437 if (GetClassLongW(hWnd, GCL_CBWNDEXTRA))
439 UINT i;
441 dbg_printf("Extra bytes:");
442 for (i = 0; i < GetClassLongW(hWnd, GCL_CBWNDEXTRA) / 2; i++)
444 w = GetWindowWord(hWnd, i * 2);
445 /* FIXME: depends on i386 endian-ity */
446 dbg_printf(" %02x %02x", HIBYTE(w), LOBYTE(w));
448 dbg_printf("\n");
450 dbg_printf("\n");
453 struct dump_proc_entry
455 PROCESSENTRY32 proc;
456 unsigned children; /* index in dump_proc.entries of first child */
457 unsigned sibling; /* index in dump_proc.entries of next sibling */
460 struct dump_proc
462 struct dump_proc_entry*entries;
463 unsigned count;
464 unsigned alloc;
467 static unsigned get_parent(const struct dump_proc* dp, unsigned idx)
469 unsigned i;
471 for (i = 0; i < dp->count; i++)
473 if (i != idx && dp->entries[i].proc.th32ProcessID == dp->entries[idx].proc.th32ParentProcessID)
474 return i;
476 return -1;
479 static void dump_proc_info(const struct dump_proc* dp, unsigned idx, unsigned depth)
481 struct dump_proc_entry* dpe;
482 for ( ; idx != -1; idx = dp->entries[idx].sibling)
484 assert(idx < dp->count);
485 dpe = &dp->entries[idx];
486 dbg_printf("%c%08x %-8d ",
487 (dpe->proc.th32ProcessID == (dbg_curr_process ?
488 dbg_curr_process->pid : 0)) ? '>' : ' ',
489 dpe->proc.th32ProcessID, dpe->proc.cntThreads);
490 if (depth)
492 unsigned i;
493 for (i = 3 * (depth - 1); i > 0; i--) dbg_printf(" ");
494 dbg_printf("\\_ ");
496 dbg_printf("'%s'\n", dpe->proc.szExeFile);
497 dump_proc_info(dp, dpe->children, depth + 1);
501 void info_win32_processes(void)
503 HANDLE snap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
504 if (snap != INVALID_HANDLE_VALUE)
506 struct dump_proc dp;
507 unsigned i, first = -1;
508 BOOL ok;
510 dp.count = 0;
511 dp.alloc = 16;
512 dp.entries = HeapAlloc(GetProcessHeap(), 0, sizeof(*dp.entries) * dp.alloc);
513 if (!dp.entries)
515 CloseHandle(snap);
516 return;
518 dp.entries[dp.count].proc.dwSize = sizeof(dp.entries[dp.count].proc);
519 ok = Process32First(snap, &dp.entries[dp.count].proc);
521 /* fetch all process information into dp (skipping this debugger) */
522 while (ok)
524 if (dp.entries[dp.count].proc.th32ProcessID != GetCurrentProcessId())
525 dp.entries[dp.count++].children = -1;
526 if (dp.count >= dp.alloc)
528 dp.entries = HeapReAlloc(GetProcessHeap(), 0, dp.entries, sizeof(*dp.entries) * (dp.alloc *= 2));
529 if (!dp.entries) return;
531 dp.entries[dp.count].proc.dwSize = sizeof(dp.entries[dp.count].proc);
532 ok = Process32Next(snap, &dp.entries[dp.count].proc);
534 CloseHandle(snap);
535 /* chain the siblings wrt. their parent */
536 for (i = 0; i < dp.count; i++)
538 unsigned parent = get_parent(&dp, i);
539 unsigned *chain = parent == -1 ? &first : &dp.entries[parent].children;
540 dp.entries[i].sibling = *chain;
541 *chain = i;
543 dbg_printf(" %-8.8s %-8.8s %s (all id:s are in hex)\n", "pid", "threads", "executable");
544 dump_proc_info(&dp, first, 0);
545 HeapFree(GetProcessHeap(), 0, dp.entries);
549 static BOOL get_process_name(DWORD pid, PROCESSENTRY32* entry)
551 BOOL ret = FALSE;
552 HANDLE snap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
554 if (snap != INVALID_HANDLE_VALUE)
556 entry->dwSize = sizeof(*entry);
557 if (Process32First(snap, entry))
558 while (!(ret = (entry->th32ProcessID == pid)) &&
559 Process32Next(snap, entry));
560 CloseHandle(snap);
562 return ret;
565 void info_win32_threads(void)
567 HANDLE snap = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0);
568 if (snap != INVALID_HANDLE_VALUE)
570 THREADENTRY32 entry;
571 BOOL ok;
572 DWORD lastProcessId = 0;
574 entry.dwSize = sizeof(entry);
575 ok = Thread32First(snap, &entry);
577 dbg_printf("%-8.8s %-8.8s %s (all id:s are in hex)\n",
578 "process", "tid", "prio");
579 while (ok)
581 if (entry.th32OwnerProcessID != GetCurrentProcessId())
583 /* FIXME: this assumes that, in the snapshot, all threads of a same process are
584 * listed sequentially, which is not specified in the doc (Wine's implementation
585 * does it)
587 if (entry.th32OwnerProcessID != lastProcessId)
589 struct dbg_process* p = dbg_get_process(entry.th32OwnerProcessID);
590 PROCESSENTRY32 pcs_entry;
591 const char* exename;
593 if (p)
594 exename = dbg_W2A(p->imageName, -1);
595 else if (get_process_name(entry.th32OwnerProcessID, &pcs_entry))
596 exename = pcs_entry.szExeFile;
597 else
598 exename = "";
600 dbg_printf("%08x%s %s\n",
601 entry.th32OwnerProcessID, p ? " (D)" : "", exename);
602 lastProcessId = entry.th32OwnerProcessID;
604 dbg_printf("\t%08x %4d%s\n",
605 entry.th32ThreadID, entry.tpBasePri,
606 (entry.th32ThreadID == dbg_curr_tid) ? " <==" : "");
609 ok = Thread32Next(snap, &entry);
612 CloseHandle(snap);
616 /***********************************************************************
617 * info_win32_frame_exceptions
619 * Get info on the exception frames of a given thread.
621 void info_win32_frame_exceptions(DWORD tid)
623 struct dbg_thread* thread;
624 void* next_frame;
626 if (!dbg_curr_process || !dbg_curr_thread)
628 dbg_printf("Cannot get info on exceptions while no process is loaded\n");
629 return;
632 dbg_printf("Exception frames:\n");
634 if (tid == dbg_curr_tid) thread = dbg_curr_thread;
635 else
637 thread = dbg_get_thread(dbg_curr_process, tid);
639 if (!thread)
641 dbg_printf("Unknown thread id (%04x) in current process\n", tid);
642 return;
644 if (SuspendThread(thread->handle) == -1)
646 dbg_printf("Can't suspend thread id (%04x)\n", tid);
647 return;
651 if (!dbg_read_memory(thread->teb, &next_frame, sizeof(next_frame)))
653 dbg_printf("Can't read TEB:except_frame\n");
654 return;
657 while (next_frame != (void*)-1)
659 EXCEPTION_REGISTRATION_RECORD frame;
661 dbg_printf("%p: ", next_frame);
662 if (!dbg_read_memory(next_frame, &frame, sizeof(frame)))
664 dbg_printf("Invalid frame address\n");
665 break;
667 dbg_printf("prev=%p handler=%p\n", frame.Prev, frame.Handler);
668 next_frame = frame.Prev;
671 if (tid != dbg_curr_tid) ResumeThread(thread->handle);
674 void info_win32_segments(DWORD start, int length)
676 char flags[3];
677 DWORD i;
678 LDT_ENTRY le;
680 if (length == -1) length = (8192 - start);
682 for (i = start; i < start + length; i++)
684 if (!dbg_curr_process->process_io->get_selector(dbg_curr_thread->handle, (i << 3) | 7, &le))
685 continue;
687 if (le.HighWord.Bits.Type & 0x08)
689 flags[0] = (le.HighWord.Bits.Type & 0x2) ? 'r' : '-';
690 flags[1] = '-';
691 flags[2] = 'x';
693 else
695 flags[0] = 'r';
696 flags[1] = (le.HighWord.Bits.Type & 0x2) ? 'w' : '-';
697 flags[2] = '-';
699 dbg_printf("%04x: sel=%04x base=%08x limit=%08x %d-bit %c%c%c\n",
700 i, (i << 3) | 7,
701 (le.HighWord.Bits.BaseHi << 24) +
702 (le.HighWord.Bits.BaseMid << 16) + le.BaseLow,
703 ((le.HighWord.Bits.LimitHi << 8) + le.LimitLow) <<
704 (le.HighWord.Bits.Granularity ? 12 : 0),
705 le.HighWord.Bits.Default_Big ? 32 : 16,
706 flags[0], flags[1], flags[2]);
710 void info_win32_virtual(DWORD pid)
712 MEMORY_BASIC_INFORMATION mbi;
713 char* addr = 0;
714 const char* state;
715 const char* type;
716 char prot[3+1];
717 HANDLE hProc;
719 if (pid == dbg_curr_pid)
721 if (dbg_curr_process == NULL)
723 dbg_printf("Cannot look at mapping of current process, while no process is loaded\n");
724 return;
726 hProc = dbg_curr_process->handle;
728 else
730 hProc = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, pid);
731 if (hProc == NULL)
733 dbg_printf("Cannot open process <%04x>\n", pid);
734 return;
738 dbg_printf("Address End State Type RWX\n");
740 while (VirtualQueryEx(hProc, addr, &mbi, sizeof(mbi)) >= sizeof(mbi))
742 switch (mbi.State)
744 case MEM_COMMIT: state = "commit "; break;
745 case MEM_FREE: state = "free "; break;
746 case MEM_RESERVE: state = "reserve"; break;
747 default: state = "??? "; break;
749 if (mbi.State != MEM_FREE)
751 switch (mbi.Type)
753 case MEM_IMAGE: type = "image "; break;
754 case MEM_MAPPED: type = "mapped "; break;
755 case MEM_PRIVATE: type = "private"; break;
756 case 0: type = " "; break;
757 default: type = "??? "; break;
759 memset(prot, ' ' , sizeof(prot) - 1);
760 prot[sizeof(prot) - 1] = '\0';
761 if (mbi.AllocationProtect & (PAGE_READONLY|PAGE_READWRITE|PAGE_EXECUTE_READ|PAGE_EXECUTE_READWRITE))
762 prot[0] = 'R';
763 if (mbi.AllocationProtect & (PAGE_READWRITE|PAGE_EXECUTE_READWRITE))
764 prot[1] = 'W';
765 if (mbi.AllocationProtect & (PAGE_WRITECOPY|PAGE_EXECUTE_WRITECOPY))
766 prot[1] = 'C';
767 if (mbi.AllocationProtect & (PAGE_EXECUTE|PAGE_EXECUTE_READ|PAGE_EXECUTE_READWRITE))
768 prot[2] = 'X';
770 else
772 type = "";
773 prot[0] = '\0';
775 dbg_printf("%08lx %08lx %s %s %s\n",
776 (DWORD_PTR)addr, (DWORD_PTR)addr + mbi.RegionSize - 1, state, type, prot);
777 if (addr + mbi.RegionSize < addr) /* wrap around ? */
778 break;
779 addr += mbi.RegionSize;
781 if (pid != dbg_curr_pid) CloseHandle(hProc);
784 void info_wine_dbg_channel(BOOL turn_on, const char* cls, const char* name)
786 struct dbg_lvalue lvalue;
787 struct __wine_debug_channel channel;
788 unsigned char mask;
789 int done = 0;
790 BOOL bAll;
791 void* addr;
793 if (!dbg_curr_process || !dbg_curr_thread)
795 dbg_printf("Cannot set/get debug channels while no process is loaded\n");
796 return;
799 if (symbol_get_lvalue("debug_options", -1, &lvalue, FALSE) != sglv_found)
801 return;
803 addr = memory_to_linear_addr(&lvalue.addr);
805 if (!cls) mask = ~0;
806 else if (!strcmp(cls, "fixme")) mask = (1 << __WINE_DBCL_FIXME);
807 else if (!strcmp(cls, "err")) mask = (1 << __WINE_DBCL_ERR);
808 else if (!strcmp(cls, "warn")) mask = (1 << __WINE_DBCL_WARN);
809 else if (!strcmp(cls, "trace")) mask = (1 << __WINE_DBCL_TRACE);
810 else
812 dbg_printf("Unknown debug class %s\n", cls);
813 return;
816 bAll = !strcmp("all", name);
817 while (addr && dbg_read_memory(addr, &channel, sizeof(channel)))
819 if (!channel.name[0]) break;
820 if (bAll || !strcmp( channel.name, name ))
822 if (turn_on) channel.flags |= mask;
823 else channel.flags &= ~mask;
824 if (dbg_write_memory(addr, &channel, sizeof(channel))) done++;
826 addr = (struct __wine_debug_channel *)addr + 1;
828 if (!done) dbg_printf("Unable to find debug channel %s\n", name);
829 else WINE_TRACE("Changed %d channel instances\n", done);
832 void info_win32_exception(void)
834 const EXCEPTION_RECORD* rec;
835 ADDRESS64 addr;
836 char hexbuf[MAX_OFFSET_TO_STR_LEN];
838 if (!dbg_curr_thread->in_exception)
840 dbg_printf("Thread isn't in an exception\n");
841 return;
843 rec = &dbg_curr_thread->excpt_record;
844 memory_get_current_pc(&addr);
846 /* print some infos */
847 dbg_printf("%s: ",
848 dbg_curr_thread->first_chance ? "First chance exception" : "Unhandled exception");
849 switch (rec->ExceptionCode)
851 case EXCEPTION_BREAKPOINT:
852 dbg_printf("breakpoint");
853 break;
854 case EXCEPTION_SINGLE_STEP:
855 dbg_printf("single step");
856 break;
857 case EXCEPTION_INT_DIVIDE_BY_ZERO:
858 dbg_printf("divide by zero");
859 break;
860 case EXCEPTION_INT_OVERFLOW:
861 dbg_printf("overflow");
862 break;
863 case EXCEPTION_ARRAY_BOUNDS_EXCEEDED:
864 dbg_printf("array bounds");
865 break;
866 case EXCEPTION_ILLEGAL_INSTRUCTION:
867 dbg_printf("illegal instruction");
868 break;
869 case EXCEPTION_STACK_OVERFLOW:
870 dbg_printf("stack overflow");
871 break;
872 case EXCEPTION_PRIV_INSTRUCTION:
873 dbg_printf("privileged instruction");
874 break;
875 case EXCEPTION_ACCESS_VIOLATION:
876 if (rec->NumberParameters == 2)
877 dbg_printf("page fault on %s access to 0x%08lx",
878 rec->ExceptionInformation[0] == EXCEPTION_WRITE_FAULT ? "write" :
879 rec->ExceptionInformation[0] == EXCEPTION_EXECUTE_FAULT ? "execute" : "read",
880 rec->ExceptionInformation[1]);
881 else
882 dbg_printf("page fault");
883 break;
884 case EXCEPTION_DATATYPE_MISALIGNMENT:
885 dbg_printf("Alignment");
886 break;
887 case DBG_CONTROL_C:
888 dbg_printf("^C");
889 break;
890 case CONTROL_C_EXIT:
891 dbg_printf("^C");
892 break;
893 case STATUS_POSSIBLE_DEADLOCK:
895 ADDRESS64 recaddr;
897 recaddr.Mode = AddrModeFlat;
898 recaddr.Offset = rec->ExceptionInformation[0];
900 dbg_printf("wait failed on critical section ");
901 print_address(&recaddr, FALSE);
903 break;
904 case EXCEPTION_WINE_STUB:
906 char dll[32], name[256];
907 memory_get_string(dbg_curr_process,
908 (void*)rec->ExceptionInformation[0], TRUE, FALSE,
909 dll, sizeof(dll));
910 if (HIWORD(rec->ExceptionInformation[1]))
911 memory_get_string(dbg_curr_process,
912 (void*)rec->ExceptionInformation[1], TRUE, FALSE,
913 name, sizeof(name));
914 else
915 sprintf( name, "%ld", rec->ExceptionInformation[1] );
916 dbg_printf("unimplemented function %s.%s called", dll, name);
918 break;
919 case EXCEPTION_WINE_ASSERTION:
920 dbg_printf("assertion failed");
921 break;
922 case EXCEPTION_VM86_INTx:
923 dbg_printf("interrupt %02lx in vm86 mode", rec->ExceptionInformation[0]);
924 break;
925 case EXCEPTION_VM86_STI:
926 dbg_printf("sti in vm86 mode");
927 break;
928 case EXCEPTION_VM86_PICRETURN:
929 dbg_printf("PIC return in vm86 mode");
930 break;
931 case EXCEPTION_FLT_DENORMAL_OPERAND:
932 dbg_printf("denormal float operand");
933 break;
934 case EXCEPTION_FLT_DIVIDE_BY_ZERO:
935 dbg_printf("divide by zero");
936 break;
937 case EXCEPTION_FLT_INEXACT_RESULT:
938 dbg_printf("inexact float result");
939 break;
940 case EXCEPTION_FLT_INVALID_OPERATION:
941 dbg_printf("invalid float operation");
942 break;
943 case EXCEPTION_FLT_OVERFLOW:
944 dbg_printf("floating point overflow");
945 break;
946 case EXCEPTION_FLT_UNDERFLOW:
947 dbg_printf("floating point underflow");
948 break;
949 case EXCEPTION_FLT_STACK_CHECK:
950 dbg_printf("floating point stack check");
951 break;
952 case CXX_EXCEPTION:
953 if(rec->NumberParameters == 3 && rec->ExceptionInformation[0] == CXX_FRAME_MAGIC)
954 dbg_printf("C++ exception(object = 0x%08lx, type = 0x%08lx)",
955 rec->ExceptionInformation[1], rec->ExceptionInformation[2]);
956 else
957 dbg_printf("C++ exception with strange parameter count %d or magic 0x%08lx",
958 rec->NumberParameters, rec->ExceptionInformation[0]);
959 break;
960 default:
961 dbg_printf("0x%08x", rec->ExceptionCode);
962 break;
964 if (rec->ExceptionFlags & EH_STACK_INVALID)
965 dbg_printf(", invalid program stack");
967 switch (addr.Mode)
969 case AddrModeFlat:
970 dbg_printf(" in %d-bit code (%s)",
971 be_cpu->pointer_size * 8,
972 memory_offset_to_string(hexbuf, addr.Offset, 0));
973 break;
974 case AddrModeReal:
975 dbg_printf(" in vm86 code (%04x:%04x)", addr.Segment, (unsigned) addr.Offset);
976 break;
977 case AddrMode1616:
978 dbg_printf(" in 16-bit code (%04x:%04x)", addr.Segment, (unsigned) addr.Offset);
979 break;
980 case AddrMode1632:
981 dbg_printf(" in segmented 32-bit code (%04x:%08lx)", addr.Segment, (unsigned long) addr.Offset);
982 break;
983 default: dbg_printf(" bad address");
985 dbg_printf(".\n");