msvcrt: Reuse FILE object in wfreopen function.
[wine/multimedia.git] / programs / winedbg / info.c
blobc0b86ba8b126fcbd93723e4eb4e5fa314d4ba110
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 " break [*<addr>] watch | rwatch *<addr>",
53 " delete break bpnum disable bpnum",
54 " enable bpnum condition <bpnum> [<expr>]",
55 " finish cont [N]",
56 " step [N] next [N]",
57 " stepi [N] nexti [N]",
58 " x <addr> print <expr>",
59 " display <expr> undisplay <disnum>",
60 " local display <expr> delete display <disnum>",
61 " enable display <disnum> disable display <disnum>",
62 " bt [<tid>|all] frame <n>",
63 " up down",
64 " list <lines> disassemble [<addr>][,<addr>]",
65 " show dir dir <path>",
66 " set <reg> = <expr> set *<addr> = <expr>",
67 " pass whatis",
68 " info (see 'help info' for options)",
70 "The 'x' command accepts repeat counts and formats (including 'i') in the",
71 "same way that gdb does.\n",
73 "The following are examples of legal expressions:",
74 " $eax $eax+0x3 0x1000 ($eip + 256) *$eax *($esp + 3)",
75 " Also, a nm format symbol table can be read from a file using the",
76 " symbolfile command.", /* Symbols can also be defined individually with",
77 " the define command.", */
78 "",
79 NULL
82 while (helptext[i]) dbg_printf("%s\n", helptext[i++]);
86 /***********************************************************************
87 * info_help
89 * Implementation of the 'help info' command.
91 void info_help(void)
93 int i = 0;
94 static const char * const infotext[] =
96 "The info commands allow you to get assorted bits of interesting stuff",
97 "to be displayed. The options are:",
98 " info break Displays information about breakpoints",
99 " info class <name> Displays information about window class <name>",
100 " info display Shows auto-display expressions in use",
101 " info except <pid> Shows exception handler chain (in a given process)",
102 " info locals Displays values of all local vars for current frame",
103 " info maps <pid> Shows virtual mappings (in a given process)",
104 " info process Shows all running processes",
105 " info reg Displays values of the general registers at top of stack",
106 " info all-reg Displays the general and floating point registers",
107 " info segments <pid> Displays information about all known segments",
108 " info share Displays all loaded modules",
109 " info share <addr> Displays internal module state",
110 " info stack [<len>] Dumps information about top of stack, up to len words",
111 " info symbol <sym> Displays information about a given symbol",
112 " info thread Shows all running threads",
113 " info wnd <handle> Displays internal window state",
115 NULL
118 while (infotext[i]) dbg_printf("%s\n", infotext[i++]);
121 static const char* get_symtype_str(const IMAGEHLP_MODULE64* mi)
123 switch (mi->SymType)
125 default:
126 case SymNone: return "--none--";
127 case SymCoff: return "COFF";
128 case SymCv: return "CodeView";
129 case SymPdb: return "PDB";
130 case SymExport: return "Export";
131 case SymDeferred: return "Deferred";
132 case SymSym: return "Sym";
133 case SymDia:
134 switch (mi->CVSig)
136 case 'S' | ('T' << 8) | ('A' << 16) | ('B' << 24):
137 return "Stabs";
138 case 'D' | ('W' << 8) | ('A' << 16) | ('R' << 24):
139 return "Dwarf";
140 default:
141 return "DIA";
147 struct info_module
149 IMAGEHLP_MODULE64* mi;
150 unsigned num_alloc;
151 unsigned num_used;
154 static void module_print_info(const IMAGEHLP_MODULE64* mi, BOOL is_embedded)
156 dbg_printf("%*.*s-%*.*s\t%-16s%s\n",
157 ADDRWIDTH, ADDRWIDTH, wine_dbgstr_longlong(mi->BaseOfImage),
158 ADDRWIDTH, ADDRWIDTH, wine_dbgstr_longlong(mi->BaseOfImage + mi->ImageSize),
159 is_embedded ? "\\" : get_symtype_str(mi), mi->ModuleName);
162 static int module_compare(const void* p1, const void* p2)
164 LONGLONG val = ((const IMAGEHLP_MODULE64*)p1)->BaseOfImage -
165 ((const IMAGEHLP_MODULE64*)p2)->BaseOfImage;
166 if (val < 0) return -1;
167 else if (val > 0) return 1;
168 else return 0;
171 static inline BOOL module_is_container(const IMAGEHLP_MODULE64* wmod_cntnr,
172 const IMAGEHLP_MODULE64* wmod_child)
174 return wmod_cntnr->BaseOfImage <= wmod_child->BaseOfImage &&
175 wmod_cntnr->BaseOfImage + wmod_cntnr->ImageSize >=
176 wmod_child->BaseOfImage + wmod_child->ImageSize;
179 static BOOL CALLBACK info_mod_cb(PCSTR mod_name, DWORD64 base, PVOID ctx)
181 struct info_module* im = ctx;
183 if (im->num_used + 1 > im->num_alloc)
185 im->num_alloc += 16;
186 im->mi = dbg_heap_realloc(im->mi, im->num_alloc * sizeof(*im->mi));
188 im->mi[im->num_used].SizeOfStruct = sizeof(im->mi[im->num_used]);
189 if (SymGetModuleInfo64(dbg_curr_process->handle, base, &im->mi[im->num_used]))
191 im->num_used++;
193 return TRUE;
196 /***********************************************************************
197 * info_win32_module
199 * Display information about a given module (DLL or EXE), or about all modules
201 void info_win32_module(DWORD64 base)
203 struct info_module im;
204 UINT i, j, num_printed = 0;
205 DWORD opt;
207 if (!dbg_curr_process)
209 dbg_printf("Cannot get info on module while no process is loaded\n");
210 return;
213 im.mi = NULL;
214 im.num_alloc = im.num_used = 0;
216 /* this is a wine specific options to return also ELF modules in the
217 * enumeration
219 SymSetOptions((opt = SymGetOptions()) | 0x40000000);
220 SymEnumerateModules64(dbg_curr_process->handle, info_mod_cb, (void*)&im);
221 SymSetOptions(opt);
223 qsort(im.mi, im.num_used, sizeof(im.mi[0]), module_compare);
225 dbg_printf("Module\tAddress\t\t\t%sDebug info\tName (%d modules)\n",
226 ADDRWIDTH == 16 ? "\t\t" : "", im.num_used);
228 for (i = 0; i < im.num_used; i++)
230 if (base &&
231 (base < im.mi[i].BaseOfImage || base >= im.mi[i].BaseOfImage + im.mi[i].ImageSize))
232 continue;
233 if (strstr(im.mi[i].ModuleName, "<elf>"))
235 dbg_printf("ELF\t");
236 module_print_info(&im.mi[i], FALSE);
237 /* print all modules embedded in this one */
238 for (j = 0; j < im.num_used; j++)
240 if (!strstr(im.mi[j].ModuleName, "<elf>") && module_is_container(&im.mi[i], &im.mi[j]))
242 dbg_printf(" \\-PE\t");
243 module_print_info(&im.mi[j], TRUE);
247 else
249 /* check module is not embedded in another module */
250 for (j = 0; j < im.num_used; j++)
252 if (strstr(im.mi[j].ModuleName, "<elf>") && module_is_container(&im.mi[j], &im.mi[i]))
253 break;
255 if (j < im.num_used) continue;
256 if (strstr(im.mi[i].ModuleName, ".so") || strchr(im.mi[i].ModuleName, '<'))
257 dbg_printf("ELF\t");
258 else
259 dbg_printf("PE\t");
260 module_print_info(&im.mi[i], FALSE);
262 num_printed++;
264 HeapFree(GetProcessHeap(), 0, im.mi);
266 if (base && !num_printed)
267 dbg_printf("'0x%x%08x' is not a valid module address\n", (DWORD)(base >> 32), (DWORD)base);
270 struct class_walker
272 ATOM* table;
273 int used;
274 int alloc;
277 static void class_walker(HWND hWnd, struct class_walker* cw)
279 char clsName[128];
280 int i;
281 ATOM atom;
282 HWND child;
284 if (!GetClassNameA(hWnd, clsName, sizeof(clsName)))
285 return;
286 if ((atom = FindAtomA(clsName)) == 0)
287 return;
289 for (i = 0; i < cw->used; i++)
291 if (cw->table[i] == atom)
292 break;
294 if (i == cw->used)
296 if (cw->used >= cw->alloc)
298 cw->alloc += 16;
299 cw->table = dbg_heap_realloc(cw->table, cw->alloc * sizeof(ATOM));
301 cw->table[cw->used++] = atom;
302 info_win32_class(hWnd, clsName);
306 if ((child = GetWindow(hWnd, GW_CHILD)) != 0)
307 class_walker(child, cw);
308 } while ((hWnd = GetWindow(hWnd, GW_HWNDNEXT)) != 0);
311 void info_win32_class(HWND hWnd, const char* name)
313 WNDCLASSEXA wca;
314 HINSTANCE hInst = hWnd ? (HINSTANCE)GetWindowLongPtrW(hWnd, GWLP_HINSTANCE) : 0;
316 if (!name)
318 struct class_walker cw;
320 cw.table = NULL;
321 cw.used = cw.alloc = 0;
322 class_walker(GetDesktopWindow(), &cw);
323 HeapFree(GetProcessHeap(), 0, cw.table);
324 return;
327 if (!GetClassInfoExA(hInst, name, &wca))
329 dbg_printf("Cannot find class '%s'\n", name);
330 return;
333 dbg_printf("Class '%s':\n", name);
334 dbg_printf("style=0x%08x wndProc=%p\n"
335 "inst=%p icon=%p cursor=%p bkgnd=%p\n"
336 "clsExtra=%d winExtra=%d\n",
337 wca.style, wca.lpfnWndProc, wca.hInstance,
338 wca.hIcon, wca.hCursor, wca.hbrBackground,
339 wca.cbClsExtra, wca.cbWndExtra);
341 if (hWnd && wca.cbClsExtra)
343 int i;
344 WORD w;
346 dbg_printf("Extra bytes:");
347 for (i = 0; i < wca.cbClsExtra / 2; i++)
349 w = GetClassWord(hWnd, i * 2);
350 /* FIXME: depends on i386 endian-ity */
351 dbg_printf(" %02x %02x", HIBYTE(w), LOBYTE(w));
353 dbg_printf("\n");
355 dbg_printf("\n");
356 /* FIXME:
357 * + print #windows (or even list of windows...)
358 * + print extra bytes => this requires a window handle on this very class...
362 static void info_window(HWND hWnd, int indent)
364 char clsName[128];
365 char wndName[128];
366 HWND child;
370 if (!GetClassNameA(hWnd, clsName, sizeof(clsName)))
371 strcpy(clsName, "-- Unknown --");
372 if (!GetWindowTextA(hWnd, wndName, sizeof(wndName)))
373 strcpy(wndName, "-- Empty --");
375 dbg_printf("%*s%08lx%*s %-17.17s %08x %0*lx %08x %.14s\n",
376 indent, "", (DWORD_PTR)hWnd, 12 - indent, "",
377 clsName, GetWindowLongW(hWnd, GWL_STYLE),
378 ADDRWIDTH, (ULONG_PTR)GetWindowLongPtrW(hWnd, GWLP_WNDPROC),
379 GetWindowThreadProcessId(hWnd, NULL), wndName);
381 if ((child = GetWindow(hWnd, GW_CHILD)) != 0)
382 info_window(child, indent + 1);
383 } while ((hWnd = GetWindow(hWnd, GW_HWNDNEXT)) != 0);
386 void info_win32_window(HWND hWnd, BOOL detailed)
388 char clsName[128];
389 char wndName[128];
390 RECT clientRect;
391 RECT windowRect;
392 WORD w;
394 if (!IsWindow(hWnd)) hWnd = GetDesktopWindow();
396 if (!detailed)
398 dbg_printf("%-20.20s %-17.17s %-8.8s %-*.*s %-8.8s %s\n",
399 "Window handle", "Class Name", "Style",
400 ADDRWIDTH, ADDRWIDTH, "WndProc", "Thread", "Text");
401 info_window(hWnd, 0);
402 return;
405 if (!GetClassNameA(hWnd, clsName, sizeof(clsName)))
406 strcpy(clsName, "-- Unknown --");
407 if (!GetWindowTextA(hWnd, wndName, sizeof(wndName)))
408 strcpy(wndName, "-- Empty --");
409 if (!GetClientRect(hWnd, &clientRect) ||
410 !MapWindowPoints(hWnd, 0, (LPPOINT) &clientRect, 2))
411 SetRectEmpty(&clientRect);
412 if (!GetWindowRect(hWnd, &windowRect))
413 SetRectEmpty(&windowRect);
415 /* FIXME missing fields: hmemTaskQ, hrgnUpdate, dce, flags, pProp, scroll */
416 dbg_printf("next=%p child=%p parent=%p owner=%p class='%s'\n"
417 "inst=%p active=%p idmenu=%08lx\n"
418 "style=0x%08x exstyle=0x%08x wndproc=%p text='%s'\n"
419 "client=%d,%d-%d,%d window=%d,%d-%d,%d sysmenu=%p\n",
420 GetWindow(hWnd, GW_HWNDNEXT),
421 GetWindow(hWnd, GW_CHILD),
422 GetParent(hWnd),
423 GetWindow(hWnd, GW_OWNER),
424 clsName,
425 (HINSTANCE)GetWindowLongPtrW(hWnd, GWLP_HINSTANCE),
426 GetLastActivePopup(hWnd),
427 (ULONG_PTR)GetWindowLongPtrW(hWnd, GWLP_ID),
428 GetWindowLongW(hWnd, GWL_STYLE),
429 GetWindowLongW(hWnd, GWL_EXSTYLE),
430 (void*)GetWindowLongPtrW(hWnd, GWLP_WNDPROC),
431 wndName,
432 clientRect.left, clientRect.top, clientRect.right, clientRect.bottom,
433 windowRect.left, windowRect.top, windowRect.right, windowRect.bottom,
434 GetSystemMenu(hWnd, FALSE));
436 if (GetClassLongW(hWnd, GCL_CBWNDEXTRA))
438 UINT i;
440 dbg_printf("Extra bytes:");
441 for (i = 0; i < GetClassLongW(hWnd, GCL_CBWNDEXTRA) / 2; i++)
443 w = GetWindowWord(hWnd, i * 2);
444 /* FIXME: depends on i386 endian-ity */
445 dbg_printf(" %02x %02x", HIBYTE(w), LOBYTE(w));
447 dbg_printf("\n");
449 dbg_printf("\n");
452 struct dump_proc_entry
454 PROCESSENTRY32 proc;
455 unsigned children; /* index in dump_proc.entries of first child */
456 unsigned sibling; /* index in dump_proc.entries of next sibling */
459 struct dump_proc
461 struct dump_proc_entry*entries;
462 unsigned count;
463 unsigned alloc;
466 static unsigned get_parent(const struct dump_proc* dp, unsigned idx)
468 unsigned i;
470 for (i = 0; i < dp->count; i++)
472 if (i != idx && dp->entries[i].proc.th32ProcessID == dp->entries[idx].proc.th32ParentProcessID)
473 return i;
475 return -1;
478 static void dump_proc_info(const struct dump_proc* dp, unsigned idx, unsigned depth)
480 struct dump_proc_entry* dpe;
481 for ( ; idx != -1; idx = dp->entries[idx].sibling)
483 assert(idx < dp->count);
484 dpe = &dp->entries[idx];
485 dbg_printf("%c%08x %-8d ",
486 (dpe->proc.th32ProcessID == (dbg_curr_process ?
487 dbg_curr_process->pid : 0)) ? '>' : ' ',
488 dpe->proc.th32ProcessID, dpe->proc.cntThreads);
489 if (depth)
491 unsigned i;
492 for (i = 3 * (depth - 1); i > 0; i--) dbg_printf(" ");
493 dbg_printf("\\_ ");
495 dbg_printf("'%s'\n", dpe->proc.szExeFile);
496 dump_proc_info(dp, dpe->children, depth + 1);
500 void info_win32_processes(void)
502 HANDLE snap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
503 if (snap != INVALID_HANDLE_VALUE)
505 struct dump_proc dp;
506 unsigned i, first = -1;
507 BOOL ok;
509 dp.count = 0;
510 dp.alloc = 16;
511 dp.entries = HeapAlloc(GetProcessHeap(), 0, sizeof(*dp.entries) * dp.alloc);
512 if (!dp.entries)
514 CloseHandle(snap);
515 return;
517 dp.entries[dp.count].proc.dwSize = sizeof(dp.entries[dp.count].proc);
518 ok = Process32First(snap, &dp.entries[dp.count].proc);
520 /* fetch all process information into dp (skipping this debugger) */
521 while (ok)
523 if (dp.entries[dp.count].proc.th32ProcessID != GetCurrentProcessId())
524 dp.entries[dp.count++].children = -1;
525 if (dp.count >= dp.alloc)
527 dp.entries = HeapReAlloc(GetProcessHeap(), 0, dp.entries, sizeof(*dp.entries) * (dp.alloc *= 2));
528 if (!dp.entries) return;
530 dp.entries[dp.count].proc.dwSize = sizeof(dp.entries[dp.count].proc);
531 ok = Process32Next(snap, &dp.entries[dp.count].proc);
533 CloseHandle(snap);
534 /* chain the siblings wrt. their parent */
535 for (i = 0; i < dp.count; i++)
537 unsigned parent = get_parent(&dp, i);
538 unsigned *chain = parent == -1 ? &first : &dp.entries[parent].children;
539 dp.entries[i].sibling = *chain;
540 *chain = i;
542 dbg_printf(" %-8.8s %-8.8s %s (all id:s are in hex)\n", "pid", "threads", "executable");
543 dump_proc_info(&dp, first, 0);
544 HeapFree(GetProcessHeap(), 0, dp.entries);
548 static BOOL get_process_name(DWORD pid, PROCESSENTRY32* entry)
550 BOOL ret = FALSE;
551 HANDLE snap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
553 if (snap != INVALID_HANDLE_VALUE)
555 entry->dwSize = sizeof(*entry);
556 if (Process32First(snap, entry))
557 while (!(ret = (entry->th32ProcessID == pid)) &&
558 Process32Next(snap, entry));
559 CloseHandle(snap);
561 return ret;
564 void info_win32_threads(void)
566 HANDLE snap = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0);
567 if (snap != INVALID_HANDLE_VALUE)
569 THREADENTRY32 entry;
570 BOOL ok;
571 DWORD lastProcessId = 0;
573 entry.dwSize = sizeof(entry);
574 ok = Thread32First(snap, &entry);
576 dbg_printf("%-8.8s %-8.8s %s (all id:s are in hex)\n",
577 "process", "tid", "prio");
578 while (ok)
580 if (entry.th32OwnerProcessID != GetCurrentProcessId())
582 /* FIXME: this assumes that, in the snapshot, all threads of a same process are
583 * listed sequentially, which is not specified in the doc (Wine's implementation
584 * does it)
586 if (entry.th32OwnerProcessID != lastProcessId)
588 struct dbg_process* p = dbg_get_process(entry.th32OwnerProcessID);
589 PROCESSENTRY32 pcs_entry;
590 const char* exename;
592 if (p)
593 exename = dbg_W2A(p->imageName, -1);
594 else if (get_process_name(entry.th32OwnerProcessID, &pcs_entry))
595 exename = pcs_entry.szExeFile;
596 else
597 exename = "";
599 dbg_printf("%08x%s %s\n",
600 entry.th32OwnerProcessID, p ? " (D)" : "", exename);
601 lastProcessId = entry.th32OwnerProcessID;
603 dbg_printf("\t%08x %4d%s\n",
604 entry.th32ThreadID, entry.tpBasePri,
605 (entry.th32ThreadID == dbg_curr_tid) ? " <==" : "");
608 ok = Thread32Next(snap, &entry);
611 CloseHandle(snap);
615 /***********************************************************************
616 * info_win32_frame_exceptions
618 * Get info on the exception frames of a given thread.
620 void info_win32_frame_exceptions(DWORD tid)
622 struct dbg_thread* thread;
623 void* next_frame;
625 if (!dbg_curr_process || !dbg_curr_thread)
627 dbg_printf("Cannot get info on exceptions while no process is loaded\n");
628 return;
631 dbg_printf("Exception frames:\n");
633 if (tid == dbg_curr_tid) thread = dbg_curr_thread;
634 else
636 thread = dbg_get_thread(dbg_curr_process, tid);
638 if (!thread)
640 dbg_printf("Unknown thread id (%04x) in current process\n", tid);
641 return;
643 if (SuspendThread(thread->handle) == -1)
645 dbg_printf("Can't suspend thread id (%04x)\n", tid);
646 return;
650 if (!dbg_read_memory(thread->teb, &next_frame, sizeof(next_frame)))
652 dbg_printf("Can't read TEB:except_frame\n");
653 return;
656 while (next_frame != (void*)-1)
658 EXCEPTION_REGISTRATION_RECORD frame;
660 dbg_printf("%p: ", next_frame);
661 if (!dbg_read_memory(next_frame, &frame, sizeof(frame)))
663 dbg_printf("Invalid frame address\n");
664 break;
666 dbg_printf("prev=%p handler=%p\n", frame.Prev, frame.Handler);
667 next_frame = frame.Prev;
670 if (tid != dbg_curr_tid) ResumeThread(thread->handle);
673 void info_win32_segments(DWORD start, int length)
675 char flags[3];
676 DWORD i;
677 LDT_ENTRY le;
679 if (length == -1) length = (8192 - start);
681 for (i = start; i < start + length; i++)
683 if (!dbg_curr_process->process_io->get_selector(dbg_curr_thread->handle, (i << 3) | 7, &le))
684 continue;
686 if (le.HighWord.Bits.Type & 0x08)
688 flags[0] = (le.HighWord.Bits.Type & 0x2) ? 'r' : '-';
689 flags[1] = '-';
690 flags[2] = 'x';
692 else
694 flags[0] = 'r';
695 flags[1] = (le.HighWord.Bits.Type & 0x2) ? 'w' : '-';
696 flags[2] = '-';
698 dbg_printf("%04x: sel=%04x base=%08x limit=%08x %d-bit %c%c%c\n",
699 i, (i << 3) | 7,
700 (le.HighWord.Bits.BaseHi << 24) +
701 (le.HighWord.Bits.BaseMid << 16) + le.BaseLow,
702 ((le.HighWord.Bits.LimitHi << 8) + le.LimitLow) <<
703 (le.HighWord.Bits.Granularity ? 12 : 0),
704 le.HighWord.Bits.Default_Big ? 32 : 16,
705 flags[0], flags[1], flags[2]);
709 void info_win32_virtual(DWORD pid)
711 MEMORY_BASIC_INFORMATION mbi;
712 char* addr = 0;
713 const char* state;
714 const char* type;
715 char prot[3+1];
716 HANDLE hProc;
718 if (pid == dbg_curr_pid)
720 if (dbg_curr_process == NULL)
722 dbg_printf("Cannot look at mapping of current process, while no process is loaded\n");
723 return;
725 hProc = dbg_curr_process->handle;
727 else
729 hProc = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, pid);
730 if (hProc == NULL)
732 dbg_printf("Cannot open process <%04x>\n", pid);
733 return;
737 dbg_printf("Address End State Type RWX\n");
739 while (VirtualQueryEx(hProc, addr, &mbi, sizeof(mbi)) >= sizeof(mbi))
741 switch (mbi.State)
743 case MEM_COMMIT: state = "commit "; break;
744 case MEM_FREE: state = "free "; break;
745 case MEM_RESERVE: state = "reserve"; break;
746 default: state = "??? "; break;
748 if (mbi.State != MEM_FREE)
750 switch (mbi.Type)
752 case MEM_IMAGE: type = "image "; break;
753 case MEM_MAPPED: type = "mapped "; break;
754 case MEM_PRIVATE: type = "private"; break;
755 case 0: type = " "; break;
756 default: type = "??? "; break;
758 memset(prot, ' ' , sizeof(prot) - 1);
759 prot[sizeof(prot) - 1] = '\0';
760 if (mbi.AllocationProtect & (PAGE_READONLY|PAGE_READWRITE|PAGE_EXECUTE_READ|PAGE_EXECUTE_READWRITE))
761 prot[0] = 'R';
762 if (mbi.AllocationProtect & (PAGE_READWRITE|PAGE_EXECUTE_READWRITE))
763 prot[1] = 'W';
764 if (mbi.AllocationProtect & (PAGE_WRITECOPY|PAGE_EXECUTE_WRITECOPY))
765 prot[1] = 'C';
766 if (mbi.AllocationProtect & (PAGE_EXECUTE|PAGE_EXECUTE_READ|PAGE_EXECUTE_READWRITE))
767 prot[2] = 'X';
769 else
771 type = "";
772 prot[0] = '\0';
774 dbg_printf("%08lx %08lx %s %s %s\n",
775 (DWORD_PTR)addr, (DWORD_PTR)addr + mbi.RegionSize - 1, state, type, prot);
776 if (addr + mbi.RegionSize < addr) /* wrap around ? */
777 break;
778 addr += mbi.RegionSize;
780 if (pid != dbg_curr_pid) CloseHandle(hProc);
783 void info_wine_dbg_channel(BOOL turn_on, const char* cls, const char* name)
785 struct dbg_lvalue lvalue;
786 struct __wine_debug_channel channel;
787 unsigned char mask;
788 int done = 0;
789 BOOL bAll;
790 void* addr;
792 if (!dbg_curr_process || !dbg_curr_thread)
794 dbg_printf("Cannot set/get debug channels while no process is loaded\n");
795 return;
798 if (symbol_get_lvalue("debug_options", -1, &lvalue, FALSE) != sglv_found)
800 return;
802 addr = memory_to_linear_addr(&lvalue.addr);
804 if (!cls) mask = ~0;
805 else if (!strcmp(cls, "fixme")) mask = (1 << __WINE_DBCL_FIXME);
806 else if (!strcmp(cls, "err")) mask = (1 << __WINE_DBCL_ERR);
807 else if (!strcmp(cls, "warn")) mask = (1 << __WINE_DBCL_WARN);
808 else if (!strcmp(cls, "trace")) mask = (1 << __WINE_DBCL_TRACE);
809 else
811 dbg_printf("Unknown debug class %s\n", cls);
812 return;
815 bAll = !strcmp("all", name);
816 while (addr && dbg_read_memory(addr, &channel, sizeof(channel)))
818 if (!channel.name[0]) break;
819 if (bAll || !strcmp( channel.name, name ))
821 if (turn_on) channel.flags |= mask;
822 else channel.flags &= ~mask;
823 if (dbg_write_memory(addr, &channel, sizeof(channel))) done++;
825 addr = (struct __wine_debug_channel *)addr + 1;
827 if (!done) dbg_printf("Unable to find debug channel %s\n", name);
828 else WINE_TRACE("Changed %d channel instances\n", done);
831 void info_win32_exception(void)
833 const EXCEPTION_RECORD* rec;
834 ADDRESS64 addr;
835 char hexbuf[MAX_OFFSET_TO_STR_LEN];
837 if (!dbg_curr_thread->in_exception)
839 dbg_printf("Thread isn't in an exception\n");
840 return;
842 rec = &dbg_curr_thread->excpt_record;
843 memory_get_current_pc(&addr);
845 /* print some infos */
846 dbg_printf("%s: ",
847 dbg_curr_thread->first_chance ? "First chance exception" : "Unhandled exception");
848 switch (rec->ExceptionCode)
850 case EXCEPTION_BREAKPOINT:
851 dbg_printf("breakpoint");
852 break;
853 case EXCEPTION_SINGLE_STEP:
854 dbg_printf("single step");
855 break;
856 case EXCEPTION_INT_DIVIDE_BY_ZERO:
857 dbg_printf("divide by zero");
858 break;
859 case EXCEPTION_INT_OVERFLOW:
860 dbg_printf("overflow");
861 break;
862 case EXCEPTION_ARRAY_BOUNDS_EXCEEDED:
863 dbg_printf("array bounds");
864 break;
865 case EXCEPTION_ILLEGAL_INSTRUCTION:
866 dbg_printf("illegal instruction");
867 break;
868 case EXCEPTION_STACK_OVERFLOW:
869 dbg_printf("stack overflow");
870 break;
871 case EXCEPTION_PRIV_INSTRUCTION:
872 dbg_printf("privileged instruction");
873 break;
874 case EXCEPTION_ACCESS_VIOLATION:
875 if (rec->NumberParameters == 2)
876 dbg_printf("page fault on %s access to 0x%08lx",
877 rec->ExceptionInformation[0] == EXCEPTION_WRITE_FAULT ? "write" :
878 rec->ExceptionInformation[0] == EXCEPTION_EXECUTE_FAULT ? "execute" : "read",
879 rec->ExceptionInformation[1]);
880 else
881 dbg_printf("page fault");
882 break;
883 case EXCEPTION_DATATYPE_MISALIGNMENT:
884 dbg_printf("Alignment");
885 break;
886 case DBG_CONTROL_C:
887 dbg_printf("^C");
888 break;
889 case CONTROL_C_EXIT:
890 dbg_printf("^C");
891 break;
892 case STATUS_POSSIBLE_DEADLOCK:
894 ADDRESS64 recaddr;
896 recaddr.Mode = AddrModeFlat;
897 recaddr.Offset = rec->ExceptionInformation[0];
899 dbg_printf("wait failed on critical section ");
900 print_address(&recaddr, FALSE);
902 break;
903 case EXCEPTION_WINE_STUB:
905 char dll[32], name[256];
906 memory_get_string(dbg_curr_process,
907 (void*)rec->ExceptionInformation[0], TRUE, FALSE,
908 dll, sizeof(dll));
909 if (HIWORD(rec->ExceptionInformation[1]))
910 memory_get_string(dbg_curr_process,
911 (void*)rec->ExceptionInformation[1], TRUE, FALSE,
912 name, sizeof(name));
913 else
914 sprintf( name, "%ld", rec->ExceptionInformation[1] );
915 dbg_printf("unimplemented function %s.%s called", dll, name);
917 break;
918 case EXCEPTION_WINE_ASSERTION:
919 dbg_printf("assertion failed");
920 break;
921 case EXCEPTION_VM86_INTx:
922 dbg_printf("interrupt %02lx in vm86 mode", rec->ExceptionInformation[0]);
923 break;
924 case EXCEPTION_VM86_STI:
925 dbg_printf("sti in vm86 mode");
926 break;
927 case EXCEPTION_VM86_PICRETURN:
928 dbg_printf("PIC return in vm86 mode");
929 break;
930 case EXCEPTION_FLT_DENORMAL_OPERAND:
931 dbg_printf("denormal float operand");
932 break;
933 case EXCEPTION_FLT_DIVIDE_BY_ZERO:
934 dbg_printf("divide by zero");
935 break;
936 case EXCEPTION_FLT_INEXACT_RESULT:
937 dbg_printf("inexact float result");
938 break;
939 case EXCEPTION_FLT_INVALID_OPERATION:
940 dbg_printf("invalid float operation");
941 break;
942 case EXCEPTION_FLT_OVERFLOW:
943 dbg_printf("floating point overflow");
944 break;
945 case EXCEPTION_FLT_UNDERFLOW:
946 dbg_printf("floating point underflow");
947 break;
948 case EXCEPTION_FLT_STACK_CHECK:
949 dbg_printf("floating point stack check");
950 break;
951 case CXX_EXCEPTION:
952 if(rec->NumberParameters == 3 && rec->ExceptionInformation[0] == CXX_FRAME_MAGIC)
953 dbg_printf("C++ exception(object = 0x%08lx, type = 0x%08lx)",
954 rec->ExceptionInformation[1], rec->ExceptionInformation[2]);
955 else
956 dbg_printf("C++ exception with strange parameter count %d or magic 0x%08lx",
957 rec->NumberParameters, rec->ExceptionInformation[0]);
958 break;
959 default:
960 dbg_printf("0x%08x", rec->ExceptionCode);
961 break;
963 if (rec->ExceptionFlags & EH_STACK_INVALID)
964 dbg_printf(", invalid program stack");
966 switch (addr.Mode)
968 case AddrModeFlat:
969 dbg_printf(" in %d-bit code (%s)",
970 be_cpu->pointer_size * 8,
971 memory_offset_to_string(hexbuf, addr.Offset, 0));
972 break;
973 case AddrModeReal:
974 dbg_printf(" in vm86 code (%04x:%04x)", addr.Segment, (unsigned) addr.Offset);
975 break;
976 case AddrMode1616:
977 dbg_printf(" in 16-bit code (%04x:%04x)", addr.Segment, (unsigned) addr.Offset);
978 break;
979 case AddrMode1632:
980 dbg_printf(" in segmented 32-bit code (%04x:%08lx)", addr.Segment, (unsigned long) addr.Offset);
981 break;
982 default: dbg_printf(" bad address");
984 dbg_printf(".\n");