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
33 #include "wine/debug.h"
34 #include "wine/exception.h"
36 WINE_DEFAULT_DEBUG_CHANNEL(winedbg);
38 /***********************************************************************
41 * Implementation of the 'help' command.
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:",
52 " break [*<addr>] watch | rwatch *<addr>",
53 " delete break bpnum disable bpnum",
54 " enable bpnum condition <bpnum> [<expr>]",
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>",
64 " list <lines> disassemble [<addr>][,<addr>]",
65 " show dir dir <path>",
66 " set <reg> = <expr> set *<addr> = <expr>",
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.", */
82 while (helptext[i]) dbg_printf("%s\n", helptext[i++]);
86 /***********************************************************************
89 * Implementation of the 'help info' command.
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",
118 while (infotext[i]) dbg_printf("%s\n", infotext[i++]);
121 static const char* get_symtype_str(const IMAGEHLP_MODULE64* mi)
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";
136 case 'S' | ('T' << 8) | ('A' << 16) | ('B' << 24):
138 case 'D' | ('W' << 8) | ('A' << 16) | ('R' << 24):
149 IMAGEHLP_MODULE64* mi;
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;
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)
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]))
196 /***********************************************************************
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;
207 if (!dbg_curr_process)
209 dbg_printf("Cannot get info on module while no process is loaded\n");
214 im.num_alloc = im.num_used = 0;
216 /* this is a wine specific options to return also ELF modules in the
219 SymSetOptions((opt = SymGetOptions()) | 0x40000000);
220 SymEnumerateModules64(dbg_curr_process->handle, info_mod_cb, (void*)&im);
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++)
231 (base < im.mi[i].BaseOfImage || base >= im.mi[i].BaseOfImage + im.mi[i].ImageSize))
233 if (strstr(im.mi[i].ModuleName, "<elf>"))
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);
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]))
255 if (j < im.num_used) continue;
256 if (strstr(im.mi[i].ModuleName, ".so") || strchr(im.mi[i].ModuleName, '<'))
260 module_print_info(&im.mi[i], FALSE);
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);
277 static void class_walker(HWND hWnd, struct class_walker* cw)
284 if (!GetClassNameA(hWnd, clsName, sizeof(clsName)))
286 if ((atom = FindAtomA(clsName)) == 0)
289 for (i = 0; i < cw->used; i++)
291 if (cw->table[i] == atom)
296 if (cw->used >= cw->alloc)
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)
314 HINSTANCE hInst = hWnd ? (HINSTANCE)GetWindowLongPtrW(hWnd, GWLP_HINSTANCE) : 0;
318 struct class_walker cw;
321 cw.used = cw.alloc = 0;
322 class_walker(GetDesktopWindow(), &cw);
323 HeapFree(GetProcessHeap(), 0, cw.table);
327 if (!GetClassInfoExA(hInst, name, &wca))
329 dbg_printf("Cannot find class '%s'\n", name);
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)
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));
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)
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)
394 if (!IsWindow(hWnd)) hWnd = GetDesktopWindow();
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);
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),
423 GetWindow(hWnd, GW_OWNER),
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),
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))
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));
452 struct dump_proc_entry
455 unsigned children; /* index in dump_proc.entries of first child */
456 unsigned sibling; /* index in dump_proc.entries of next sibling */
461 struct dump_proc_entry*entries;
466 static unsigned get_parent(const struct dump_proc* dp, unsigned idx)
470 for (i = 0; i < dp->count; i++)
472 if (i != idx && dp->entries[i].proc.th32ProcessID == dp->entries[idx].proc.th32ParentProcessID)
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);
492 for (i = 3 * (depth - 1); i > 0; i--) 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)
506 unsigned i, first = -1;
511 dp.entries = HeapAlloc(GetProcessHeap(), 0, sizeof(*dp.entries) * dp.alloc);
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) */
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);
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;
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)
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));
564 void info_win32_threads(void)
566 HANDLE snap = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0);
567 if (snap != INVALID_HANDLE_VALUE)
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");
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
586 if (entry.th32OwnerProcessID != lastProcessId)
588 struct dbg_process* p = dbg_get_process(entry.th32OwnerProcessID);
589 PROCESSENTRY32 pcs_entry;
593 exename = dbg_W2A(p->imageName, -1);
594 else if (get_process_name(entry.th32OwnerProcessID, &pcs_entry))
595 exename = pcs_entry.szExeFile;
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);
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;
625 if (!dbg_curr_process || !dbg_curr_thread)
627 dbg_printf("Cannot get info on exceptions while no process is loaded\n");
631 dbg_printf("Exception frames:\n");
633 if (tid == dbg_curr_tid) thread = dbg_curr_thread;
636 thread = dbg_get_thread(dbg_curr_process, tid);
640 dbg_printf("Unknown thread id (%04x) in current process\n", tid);
643 if (SuspendThread(thread->handle) == -1)
645 dbg_printf("Can't suspend thread id (%04x)\n", tid);
650 if (!dbg_read_memory(thread->teb, &next_frame, sizeof(next_frame)))
652 dbg_printf("Can't read TEB:except_frame\n");
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");
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)
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))
686 if (le.HighWord.Bits.Type & 0x08)
688 flags[0] = (le.HighWord.Bits.Type & 0x2) ? 'r' : '-';
695 flags[1] = (le.HighWord.Bits.Type & 0x2) ? 'w' : '-';
698 dbg_printf("%04x: sel=%04x base=%08x limit=%08x %d-bit %c%c%c\n",
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;
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");
725 hProc = dbg_curr_process->handle;
729 hProc = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, pid);
732 dbg_printf("Cannot open process <%04x>\n", pid);
737 dbg_printf("Address End State Type RWX\n");
739 while (VirtualQueryEx(hProc, addr, &mbi, sizeof(mbi)) >= sizeof(mbi))
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)
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))
762 if (mbi.AllocationProtect & (PAGE_READWRITE|PAGE_EXECUTE_READWRITE))
764 if (mbi.AllocationProtect & (PAGE_WRITECOPY|PAGE_EXECUTE_WRITECOPY))
766 if (mbi.AllocationProtect & (PAGE_EXECUTE|PAGE_EXECUTE_READ|PAGE_EXECUTE_READWRITE))
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 ? */
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;
792 if (!dbg_curr_process || !dbg_curr_thread)
794 dbg_printf("Cannot set/get debug channels while no process is loaded\n");
798 if (symbol_get_lvalue("debug_options", -1, &lvalue, FALSE) != sglv_found)
802 addr = memory_to_linear_addr(&lvalue.addr);
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);
811 dbg_printf("Unknown debug class %s\n", cls);
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;
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");
842 rec = &dbg_curr_thread->excpt_record;
843 memory_get_current_pc(&addr);
845 /* print some infos */
847 dbg_curr_thread->first_chance ? "First chance exception" : "Unhandled exception");
848 switch (rec->ExceptionCode)
850 case EXCEPTION_BREAKPOINT:
851 dbg_printf("breakpoint");
853 case EXCEPTION_SINGLE_STEP:
854 dbg_printf("single step");
856 case EXCEPTION_INT_DIVIDE_BY_ZERO:
857 dbg_printf("divide by zero");
859 case EXCEPTION_INT_OVERFLOW:
860 dbg_printf("overflow");
862 case EXCEPTION_ARRAY_BOUNDS_EXCEEDED:
863 dbg_printf("array bounds");
865 case EXCEPTION_ILLEGAL_INSTRUCTION:
866 dbg_printf("illegal instruction");
868 case EXCEPTION_STACK_OVERFLOW:
869 dbg_printf("stack overflow");
871 case EXCEPTION_PRIV_INSTRUCTION:
872 dbg_printf("privileged instruction");
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]);
881 dbg_printf("page fault");
883 case EXCEPTION_DATATYPE_MISALIGNMENT:
884 dbg_printf("Alignment");
892 case STATUS_POSSIBLE_DEADLOCK:
896 recaddr.Mode = AddrModeFlat;
897 recaddr.Offset = rec->ExceptionInformation[0];
899 dbg_printf("wait failed on critical section ");
900 print_address(&recaddr, FALSE);
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,
909 if (HIWORD(rec->ExceptionInformation[1]))
910 memory_get_string(dbg_curr_process,
911 (void*)rec->ExceptionInformation[1], TRUE, FALSE,
914 sprintf( name, "%ld", rec->ExceptionInformation[1] );
915 dbg_printf("unimplemented function %s.%s called", dll, name);
918 case EXCEPTION_WINE_ASSERTION:
919 dbg_printf("assertion failed");
921 case EXCEPTION_VM86_INTx:
922 dbg_printf("interrupt %02lx in vm86 mode", rec->ExceptionInformation[0]);
924 case EXCEPTION_VM86_STI:
925 dbg_printf("sti in vm86 mode");
927 case EXCEPTION_VM86_PICRETURN:
928 dbg_printf("PIC return in vm86 mode");
930 case EXCEPTION_FLT_DENORMAL_OPERAND:
931 dbg_printf("denormal float operand");
933 case EXCEPTION_FLT_DIVIDE_BY_ZERO:
934 dbg_printf("divide by zero");
936 case EXCEPTION_FLT_INEXACT_RESULT:
937 dbg_printf("inexact float result");
939 case EXCEPTION_FLT_INVALID_OPERATION:
940 dbg_printf("invalid float operation");
942 case EXCEPTION_FLT_OVERFLOW:
943 dbg_printf("floating point overflow");
945 case EXCEPTION_FLT_UNDERFLOW:
946 dbg_printf("floating point underflow");
948 case EXCEPTION_FLT_STACK_CHECK:
949 dbg_printf("floating point stack check");
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]);
956 dbg_printf("C++ exception with strange parameter count %d or magic 0x%08lx",
957 rec->NumberParameters, rec->ExceptionInformation[0]);
960 dbg_printf("0x%08x", rec->ExceptionCode);
963 if (rec->ExceptionFlags & EH_STACK_INVALID)
964 dbg_printf(", invalid program stack");
969 dbg_printf(" in %d-bit code (%s)",
970 be_cpu->pointer_size * 8,
971 memory_offset_to_string(hexbuf, addr.Offset, 0));
974 dbg_printf(" in vm86 code (%04x:%04x)", addr.Segment, (unsigned) addr.Offset);
977 dbg_printf(" in 16-bit code (%04x:%04x)", addr.Segment, (unsigned) addr.Offset);
980 dbg_printf(" in segmented 32-bit code (%04x:%08lx)", addr.Segment, (unsigned long) addr.Offset);
982 default: dbg_printf(" bad address");