msxml3: Store encoding-codepage mapping in a table.
[wine/multimedia.git] / programs / winedbg / info.c
blobbc59eed1b1620a208d33629af5188437e07efc47
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 void info_win32_processes(void)
454 HANDLE snap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
455 if (snap != INVALID_HANDLE_VALUE)
457 PROCESSENTRY32 entry;
458 DWORD current = dbg_curr_process ? dbg_curr_process->pid : 0;
459 BOOL ok;
461 entry.dwSize = sizeof(entry);
462 ok = Process32First(snap, &entry);
464 dbg_printf(" %-8.8s %-8.8s %-8.8s %s (all id:s are in hex)\n",
465 "pid", "threads", "parent", "executable");
466 while (ok)
468 if (entry.th32ProcessID != GetCurrentProcessId())
469 dbg_printf("%c%08x %-8d %08x '%s'\n",
470 (entry.th32ProcessID == current) ? '>' : ' ',
471 entry.th32ProcessID, entry.cntThreads,
472 entry.th32ParentProcessID, entry.szExeFile);
473 ok = Process32Next(snap, &entry);
475 CloseHandle(snap);
479 static BOOL get_process_name(DWORD pid, PROCESSENTRY32* entry)
481 BOOL ret = FALSE;
482 HANDLE snap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
484 if (snap != INVALID_HANDLE_VALUE)
486 entry->dwSize = sizeof(*entry);
487 if (Process32First(snap, entry))
488 while (!(ret = (entry->th32ProcessID == pid)) &&
489 Process32Next(snap, entry));
490 CloseHandle(snap);
492 return ret;
495 void info_win32_threads(void)
497 HANDLE snap = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0);
498 if (snap != INVALID_HANDLE_VALUE)
500 THREADENTRY32 entry;
501 BOOL ok;
502 DWORD lastProcessId = 0;
504 entry.dwSize = sizeof(entry);
505 ok = Thread32First(snap, &entry);
507 dbg_printf("%-8.8s %-8.8s %s (all id:s are in hex)\n",
508 "process", "tid", "prio");
509 while (ok)
511 if (entry.th32OwnerProcessID != GetCurrentProcessId())
513 /* FIXME: this assumes that, in the snapshot, all threads of a same process are
514 * listed sequentially, which is not specified in the doc (Wine's implementation
515 * does it)
517 if (entry.th32OwnerProcessID != lastProcessId)
519 struct dbg_process* p = dbg_get_process(entry.th32OwnerProcessID);
520 PROCESSENTRY32 pcs_entry;
521 const char* exename;
523 if (p)
524 exename = dbg_W2A(p->imageName, -1);
525 else if (get_process_name(entry.th32OwnerProcessID, &pcs_entry))
526 exename = pcs_entry.szExeFile;
527 else
528 exename = "";
530 dbg_printf("%08x%s %s\n",
531 entry.th32OwnerProcessID, p ? " (D)" : "", exename);
532 lastProcessId = entry.th32OwnerProcessID;
534 dbg_printf("\t%08x %4d%s\n",
535 entry.th32ThreadID, entry.tpBasePri,
536 (entry.th32ThreadID == dbg_curr_tid) ? " <==" : "");
539 ok = Thread32Next(snap, &entry);
542 CloseHandle(snap);
546 /***********************************************************************
547 * info_win32_frame_exceptions
549 * Get info on the exception frames of a given thread.
551 void info_win32_frame_exceptions(DWORD tid)
553 struct dbg_thread* thread;
554 void* next_frame;
556 if (!dbg_curr_process || !dbg_curr_thread)
558 dbg_printf("Cannot get info on exceptions while no process is loaded\n");
559 return;
562 dbg_printf("Exception frames:\n");
564 if (tid == dbg_curr_tid) thread = dbg_curr_thread;
565 else
567 thread = dbg_get_thread(dbg_curr_process, tid);
569 if (!thread)
571 dbg_printf("Unknown thread id (%04x) in current process\n", tid);
572 return;
574 if (SuspendThread(thread->handle) == -1)
576 dbg_printf("Can't suspend thread id (%04x)\n", tid);
577 return;
581 if (!dbg_read_memory(thread->teb, &next_frame, sizeof(next_frame)))
583 dbg_printf("Can't read TEB:except_frame\n");
584 return;
587 while (next_frame != (void*)-1)
589 EXCEPTION_REGISTRATION_RECORD frame;
591 dbg_printf("%p: ", next_frame);
592 if (!dbg_read_memory(next_frame, &frame, sizeof(frame)))
594 dbg_printf("Invalid frame address\n");
595 break;
597 dbg_printf("prev=%p handler=%p\n", frame.Prev, frame.Handler);
598 next_frame = frame.Prev;
601 if (tid != dbg_curr_tid) ResumeThread(thread->handle);
604 void info_win32_segments(DWORD start, int length)
606 char flags[3];
607 DWORD i;
608 LDT_ENTRY le;
610 if (length == -1) length = (8192 - start);
612 for (i = start; i < start + length; i++)
614 if (!dbg_curr_process->process_io->get_selector(dbg_curr_thread->handle, (i << 3) | 7, &le))
615 continue;
617 if (le.HighWord.Bits.Type & 0x08)
619 flags[0] = (le.HighWord.Bits.Type & 0x2) ? 'r' : '-';
620 flags[1] = '-';
621 flags[2] = 'x';
623 else
625 flags[0] = 'r';
626 flags[1] = (le.HighWord.Bits.Type & 0x2) ? 'w' : '-';
627 flags[2] = '-';
629 dbg_printf("%04x: sel=%04x base=%08x limit=%08x %d-bit %c%c%c\n",
630 i, (i << 3) | 7,
631 (le.HighWord.Bits.BaseHi << 24) +
632 (le.HighWord.Bits.BaseMid << 16) + le.BaseLow,
633 ((le.HighWord.Bits.LimitHi << 8) + le.LimitLow) <<
634 (le.HighWord.Bits.Granularity ? 12 : 0),
635 le.HighWord.Bits.Default_Big ? 32 : 16,
636 flags[0], flags[1], flags[2]);
640 void info_win32_virtual(DWORD pid)
642 MEMORY_BASIC_INFORMATION mbi;
643 char* addr = 0;
644 const char* state;
645 const char* type;
646 char prot[3+1];
647 HANDLE hProc;
649 if (pid == dbg_curr_pid)
651 if (dbg_curr_process == NULL)
653 dbg_printf("Cannot look at mapping of current process, while no process is loaded\n");
654 return;
656 hProc = dbg_curr_process->handle;
658 else
660 hProc = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, pid);
661 if (hProc == NULL)
663 dbg_printf("Cannot open process <%04x>\n", pid);
664 return;
668 dbg_printf("Address End State Type RWX\n");
670 while (VirtualQueryEx(hProc, addr, &mbi, sizeof(mbi)) >= sizeof(mbi))
672 switch (mbi.State)
674 case MEM_COMMIT: state = "commit "; break;
675 case MEM_FREE: state = "free "; break;
676 case MEM_RESERVE: state = "reserve"; break;
677 default: state = "??? "; break;
679 if (mbi.State != MEM_FREE)
681 switch (mbi.Type)
683 case MEM_IMAGE: type = "image "; break;
684 case MEM_MAPPED: type = "mapped "; break;
685 case MEM_PRIVATE: type = "private"; break;
686 case 0: type = " "; break;
687 default: type = "??? "; break;
689 memset(prot, ' ' , sizeof(prot) - 1);
690 prot[sizeof(prot) - 1] = '\0';
691 if (mbi.AllocationProtect & (PAGE_READONLY|PAGE_READWRITE|PAGE_EXECUTE_READ|PAGE_EXECUTE_READWRITE))
692 prot[0] = 'R';
693 if (mbi.AllocationProtect & (PAGE_READWRITE|PAGE_EXECUTE_READWRITE))
694 prot[1] = 'W';
695 if (mbi.AllocationProtect & (PAGE_WRITECOPY|PAGE_EXECUTE_WRITECOPY))
696 prot[1] = 'C';
697 if (mbi.AllocationProtect & (PAGE_EXECUTE|PAGE_EXECUTE_READ|PAGE_EXECUTE_READWRITE))
698 prot[2] = 'X';
700 else
702 type = "";
703 prot[0] = '\0';
705 dbg_printf("%08lx %08lx %s %s %s\n",
706 (DWORD_PTR)addr, (DWORD_PTR)addr + mbi.RegionSize - 1, state, type, prot);
707 if (addr + mbi.RegionSize < addr) /* wrap around ? */
708 break;
709 addr += mbi.RegionSize;
711 if (pid != dbg_curr_pid) CloseHandle(hProc);
714 void info_wine_dbg_channel(BOOL turn_on, const char* cls, const char* name)
716 struct dbg_lvalue lvalue;
717 struct __wine_debug_channel channel;
718 unsigned char mask;
719 int done = 0;
720 BOOL bAll;
721 void* addr;
723 if (!dbg_curr_process || !dbg_curr_thread)
725 dbg_printf("Cannot set/get debug channels while no process is loaded\n");
726 return;
729 if (symbol_get_lvalue("debug_options", -1, &lvalue, FALSE) != sglv_found)
731 return;
733 addr = memory_to_linear_addr(&lvalue.addr);
735 if (!cls) mask = ~0;
736 else if (!strcmp(cls, "fixme")) mask = (1 << __WINE_DBCL_FIXME);
737 else if (!strcmp(cls, "err")) mask = (1 << __WINE_DBCL_ERR);
738 else if (!strcmp(cls, "warn")) mask = (1 << __WINE_DBCL_WARN);
739 else if (!strcmp(cls, "trace")) mask = (1 << __WINE_DBCL_TRACE);
740 else
742 dbg_printf("Unknown debug class %s\n", cls);
743 return;
746 bAll = !strcmp("all", name);
747 while (addr && dbg_read_memory(addr, &channel, sizeof(channel)))
749 if (!channel.name[0]) break;
750 if (bAll || !strcmp( channel.name, name ))
752 if (turn_on) channel.flags |= mask;
753 else channel.flags &= ~mask;
754 if (dbg_write_memory(addr, &channel, sizeof(channel))) done++;
756 addr = (struct __wine_debug_channel *)addr + 1;
758 if (!done) dbg_printf("Unable to find debug channel %s\n", name);
759 else WINE_TRACE("Changed %d channel instances\n", done);
762 void info_win32_exception(void)
764 const EXCEPTION_RECORD* rec;
765 ADDRESS64 addr;
766 char hexbuf[MAX_OFFSET_TO_STR_LEN];
768 if (!dbg_curr_thread->in_exception)
770 dbg_printf("Thread isn't in an exception\n");
771 return;
773 rec = &dbg_curr_thread->excpt_record;
774 memory_get_current_pc(&addr);
776 /* print some infos */
777 dbg_printf("%s: ",
778 dbg_curr_thread->first_chance ? "First chance exception" : "Unhandled exception");
779 switch (rec->ExceptionCode)
781 case EXCEPTION_BREAKPOINT:
782 dbg_printf("breakpoint");
783 break;
784 case EXCEPTION_SINGLE_STEP:
785 dbg_printf("single step");
786 break;
787 case EXCEPTION_INT_DIVIDE_BY_ZERO:
788 dbg_printf("divide by zero");
789 break;
790 case EXCEPTION_INT_OVERFLOW:
791 dbg_printf("overflow");
792 break;
793 case EXCEPTION_ARRAY_BOUNDS_EXCEEDED:
794 dbg_printf("array bounds");
795 break;
796 case EXCEPTION_ILLEGAL_INSTRUCTION:
797 dbg_printf("illegal instruction");
798 break;
799 case EXCEPTION_STACK_OVERFLOW:
800 dbg_printf("stack overflow");
801 break;
802 case EXCEPTION_PRIV_INSTRUCTION:
803 dbg_printf("privileged instruction");
804 break;
805 case EXCEPTION_ACCESS_VIOLATION:
806 if (rec->NumberParameters == 2)
807 dbg_printf("page fault on %s access to 0x%08lx",
808 rec->ExceptionInformation[0] == EXCEPTION_WRITE_FAULT ? "write" :
809 rec->ExceptionInformation[0] == EXCEPTION_EXECUTE_FAULT ? "execute" : "read",
810 rec->ExceptionInformation[1]);
811 else
812 dbg_printf("page fault");
813 break;
814 case EXCEPTION_DATATYPE_MISALIGNMENT:
815 dbg_printf("Alignment");
816 break;
817 case DBG_CONTROL_C:
818 dbg_printf("^C");
819 break;
820 case CONTROL_C_EXIT:
821 dbg_printf("^C");
822 break;
823 case STATUS_POSSIBLE_DEADLOCK:
825 ADDRESS64 recaddr;
827 recaddr.Mode = AddrModeFlat;
828 recaddr.Offset = rec->ExceptionInformation[0];
830 dbg_printf("wait failed on critical section ");
831 print_address(&recaddr, FALSE);
833 break;
834 case EXCEPTION_WINE_STUB:
836 char dll[32], name[256];
837 memory_get_string(dbg_curr_process,
838 (void*)rec->ExceptionInformation[0], TRUE, FALSE,
839 dll, sizeof(dll));
840 if (HIWORD(rec->ExceptionInformation[1]))
841 memory_get_string(dbg_curr_process,
842 (void*)rec->ExceptionInformation[1], TRUE, FALSE,
843 name, sizeof(name));
844 else
845 sprintf( name, "%ld", rec->ExceptionInformation[1] );
846 dbg_printf("unimplemented function %s.%s called", dll, name);
848 break;
849 case EXCEPTION_WINE_ASSERTION:
850 dbg_printf("assertion failed");
851 break;
852 case EXCEPTION_VM86_INTx:
853 dbg_printf("interrupt %02lx in vm86 mode", rec->ExceptionInformation[0]);
854 break;
855 case EXCEPTION_VM86_STI:
856 dbg_printf("sti in vm86 mode");
857 break;
858 case EXCEPTION_VM86_PICRETURN:
859 dbg_printf("PIC return in vm86 mode");
860 break;
861 case EXCEPTION_FLT_DENORMAL_OPERAND:
862 dbg_printf("denormal float operand");
863 break;
864 case EXCEPTION_FLT_DIVIDE_BY_ZERO:
865 dbg_printf("divide by zero");
866 break;
867 case EXCEPTION_FLT_INEXACT_RESULT:
868 dbg_printf("inexact float result");
869 break;
870 case EXCEPTION_FLT_INVALID_OPERATION:
871 dbg_printf("invalid float operation");
872 break;
873 case EXCEPTION_FLT_OVERFLOW:
874 dbg_printf("floating point overflow");
875 break;
876 case EXCEPTION_FLT_UNDERFLOW:
877 dbg_printf("floating point underflow");
878 break;
879 case EXCEPTION_FLT_STACK_CHECK:
880 dbg_printf("floating point stack check");
881 break;
882 case CXX_EXCEPTION:
883 if(rec->NumberParameters == 3 && rec->ExceptionInformation[0] == CXX_FRAME_MAGIC)
884 dbg_printf("C++ exception(object = 0x%08lx, type = 0x%08lx)",
885 rec->ExceptionInformation[1], rec->ExceptionInformation[2]);
886 else
887 dbg_printf("C++ exception with strange parameter count %d or magic 0x%08lx",
888 rec->NumberParameters, rec->ExceptionInformation[0]);
889 break;
890 default:
891 dbg_printf("0x%08x", rec->ExceptionCode);
892 break;
894 if (rec->ExceptionFlags & EH_STACK_INVALID)
895 dbg_printf(", invalid program stack");
897 switch (addr.Mode)
899 case AddrModeFlat:
900 dbg_printf(" in %d-bit code (%s)",
901 be_cpu->pointer_size * 8,
902 memory_offset_to_string(hexbuf, addr.Offset, 0));
903 break;
904 case AddrModeReal:
905 dbg_printf(" in vm86 code (%04x:%04x)", addr.Segment, (unsigned) addr.Offset);
906 break;
907 case AddrMode1616:
908 dbg_printf(" in 16-bit code (%04x:%04x)", addr.Segment, (unsigned) addr.Offset);
909 break;
910 case AddrMode1632:
911 dbg_printf(" in segmented 32-bit code (%04x:%08lx)", addr.Segment, (unsigned long) addr.Offset);
912 break;
913 default: dbg_printf(" bad address");
915 dbg_printf(".\n");