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 " attach <wpid> detach",
53 " break [*<addr>] watch | rwatch *<addr>",
54 " delete break bpnum disable bpnum",
55 " enable bpnum condition <bpnum> [<expr>]",
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>",
65 " list <lines> disassemble [<addr>][,<addr>]",
66 " show dir dir <path>",
67 " set <reg> = <expr> set *<addr> = <expr>",
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.", */
83 while (helptext
[i
]) dbg_printf("%s\n", helptext
[i
++]);
87 /***********************************************************************
90 * Implementation of the 'help info' command.
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",
119 while (infotext
[i
]) dbg_printf("%s\n", infotext
[i
++]);
122 static const char* get_symtype_str(const IMAGEHLP_MODULE64
* mi
)
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";
137 case 'S' | ('T' << 8) | ('A' << 16) | ('B' << 24):
139 case 'D' | ('W' << 8) | ('A' << 16) | ('R' << 24):
150 IMAGEHLP_MODULE64
* mi
;
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;
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
)
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
]))
197 /***********************************************************************
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;
208 if (!dbg_curr_process
)
210 dbg_printf("Cannot get info on module while no process is loaded\n");
215 im
.num_alloc
= im
.num_used
= 0;
217 /* this is a wine specific options to return also ELF modules in the
220 SymSetOptions((opt
= SymGetOptions()) | 0x40000000);
221 SymEnumerateModules64(dbg_curr_process
->handle
, info_mod_cb
, (void*)&im
);
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
++)
232 (base
< im
.mi
[i
].BaseOfImage
|| base
>= im
.mi
[i
].BaseOfImage
+ im
.mi
[i
].ImageSize
))
234 if (strstr(im
.mi
[i
].ModuleName
, "<elf>"))
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
);
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
]))
256 if (j
< im
.num_used
) continue;
257 if (strstr(im
.mi
[i
].ModuleName
, ".so") || strchr(im
.mi
[i
].ModuleName
, '<'))
261 module_print_info(&im
.mi
[i
], FALSE
);
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
);
278 static void class_walker(HWND hWnd
, struct class_walker
* cw
)
285 if (!GetClassNameA(hWnd
, clsName
, sizeof(clsName
)))
287 if ((atom
= FindAtomA(clsName
)) == 0)
290 for (i
= 0; i
< cw
->used
; i
++)
292 if (cw
->table
[i
] == atom
)
297 if (cw
->used
>= cw
->alloc
)
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
)
315 HINSTANCE hInst
= hWnd
? (HINSTANCE
)GetWindowLongPtrW(hWnd
, GWLP_HINSTANCE
) : 0;
319 struct class_walker cw
;
322 cw
.used
= cw
.alloc
= 0;
323 class_walker(GetDesktopWindow(), &cw
);
324 HeapFree(GetProcessHeap(), 0, cw
.table
);
328 if (!GetClassInfoExA(hInst
, name
, &wca
))
330 dbg_printf("Cannot find class '%s'\n", name
);
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
)
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
));
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
)
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
)
395 if (!IsWindow(hWnd
)) hWnd
= GetDesktopWindow();
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);
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
),
424 GetWindow(hWnd
, GW_OWNER
),
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
),
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
))
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
));
453 struct dump_proc_entry
456 unsigned children
; /* index in dump_proc.entries of first child */
457 unsigned sibling
; /* index in dump_proc.entries of next sibling */
462 struct dump_proc_entry
*entries
;
467 static unsigned get_parent(const struct dump_proc
* dp
, unsigned idx
)
471 for (i
= 0; i
< dp
->count
; i
++)
473 if (i
!= idx
&& dp
->entries
[i
].proc
.th32ProcessID
== dp
->entries
[idx
].proc
.th32ParentProcessID
)
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
);
493 for (i
= 3 * (depth
- 1); i
> 0; i
--) 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
)
507 unsigned i
, first
= -1;
512 dp
.entries
= HeapAlloc(GetProcessHeap(), 0, sizeof(*dp
.entries
) * dp
.alloc
);
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) */
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
);
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
;
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
)
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
));
565 void info_win32_threads(void)
567 HANDLE snap
= CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD
, 0);
568 if (snap
!= INVALID_HANDLE_VALUE
)
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");
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
587 if (entry
.th32OwnerProcessID
!= lastProcessId
)
589 struct dbg_process
* p
= dbg_get_process(entry
.th32OwnerProcessID
);
590 PROCESSENTRY32 pcs_entry
;
594 exename
= dbg_W2A(p
->imageName
, -1);
595 else if (get_process_name(entry
.th32OwnerProcessID
, &pcs_entry
))
596 exename
= pcs_entry
.szExeFile
;
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
);
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
;
626 if (!dbg_curr_process
|| !dbg_curr_thread
)
628 dbg_printf("Cannot get info on exceptions while no process is loaded\n");
632 dbg_printf("Exception frames:\n");
634 if (tid
== dbg_curr_tid
) thread
= dbg_curr_thread
;
637 thread
= dbg_get_thread(dbg_curr_process
, tid
);
641 dbg_printf("Unknown thread id (%04x) in current process\n", tid
);
644 if (SuspendThread(thread
->handle
) == -1)
646 dbg_printf("Can't suspend thread id (%04x)\n", tid
);
651 if (!dbg_read_memory(thread
->teb
, &next_frame
, sizeof(next_frame
)))
653 dbg_printf("Can't read TEB:except_frame\n");
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");
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
)
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
))
687 if (le
.HighWord
.Bits
.Type
& 0x08)
689 flags
[0] = (le
.HighWord
.Bits
.Type
& 0x2) ? 'r' : '-';
696 flags
[1] = (le
.HighWord
.Bits
.Type
& 0x2) ? 'w' : '-';
699 dbg_printf("%04x: sel=%04x base=%08x limit=%08x %d-bit %c%c%c\n",
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
;
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");
726 hProc
= dbg_curr_process
->handle
;
730 hProc
= OpenProcess(PROCESS_QUERY_INFORMATION
| PROCESS_VM_READ
, FALSE
, pid
);
733 dbg_printf("Cannot open process <%04x>\n", pid
);
738 dbg_printf("Address End State Type RWX\n");
740 while (VirtualQueryEx(hProc
, addr
, &mbi
, sizeof(mbi
)) >= sizeof(mbi
))
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
)
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
))
763 if (mbi
.AllocationProtect
& (PAGE_READWRITE
|PAGE_EXECUTE_READWRITE
))
765 if (mbi
.AllocationProtect
& (PAGE_WRITECOPY
|PAGE_EXECUTE_WRITECOPY
))
767 if (mbi
.AllocationProtect
& (PAGE_EXECUTE
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_READWRITE
))
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 ? */
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
;
793 if (!dbg_curr_process
|| !dbg_curr_thread
)
795 dbg_printf("Cannot set/get debug channels while no process is loaded\n");
799 if (symbol_get_lvalue("debug_options", -1, &lvalue
, FALSE
) != sglv_found
)
803 addr
= memory_to_linear_addr(&lvalue
.addr
);
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
);
812 dbg_printf("Unknown debug class %s\n", cls
);
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
;
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");
843 rec
= &dbg_curr_thread
->excpt_record
;
844 memory_get_current_pc(&addr
);
846 /* print some infos */
848 dbg_curr_thread
->first_chance
? "First chance exception" : "Unhandled exception");
849 switch (rec
->ExceptionCode
)
851 case EXCEPTION_BREAKPOINT
:
852 dbg_printf("breakpoint");
854 case EXCEPTION_SINGLE_STEP
:
855 dbg_printf("single step");
857 case EXCEPTION_INT_DIVIDE_BY_ZERO
:
858 dbg_printf("divide by zero");
860 case EXCEPTION_INT_OVERFLOW
:
861 dbg_printf("overflow");
863 case EXCEPTION_ARRAY_BOUNDS_EXCEEDED
:
864 dbg_printf("array bounds");
866 case EXCEPTION_ILLEGAL_INSTRUCTION
:
867 dbg_printf("illegal instruction");
869 case EXCEPTION_STACK_OVERFLOW
:
870 dbg_printf("stack overflow");
872 case EXCEPTION_PRIV_INSTRUCTION
:
873 dbg_printf("privileged instruction");
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]);
882 dbg_printf("page fault");
884 case EXCEPTION_DATATYPE_MISALIGNMENT
:
885 dbg_printf("Alignment");
893 case STATUS_POSSIBLE_DEADLOCK
:
897 recaddr
.Mode
= AddrModeFlat
;
898 recaddr
.Offset
= rec
->ExceptionInformation
[0];
900 dbg_printf("wait failed on critical section ");
901 print_address(&recaddr
, FALSE
);
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
,
910 if (HIWORD(rec
->ExceptionInformation
[1]))
911 memory_get_string(dbg_curr_process
,
912 (void*)rec
->ExceptionInformation
[1], TRUE
, FALSE
,
915 sprintf( name
, "%ld", rec
->ExceptionInformation
[1] );
916 dbg_printf("unimplemented function %s.%s called", dll
, name
);
919 case EXCEPTION_WINE_ASSERTION
:
920 dbg_printf("assertion failed");
922 case EXCEPTION_VM86_INTx
:
923 dbg_printf("interrupt %02lx in vm86 mode", rec
->ExceptionInformation
[0]);
925 case EXCEPTION_VM86_STI
:
926 dbg_printf("sti in vm86 mode");
928 case EXCEPTION_VM86_PICRETURN
:
929 dbg_printf("PIC return in vm86 mode");
931 case EXCEPTION_FLT_DENORMAL_OPERAND
:
932 dbg_printf("denormal float operand");
934 case EXCEPTION_FLT_DIVIDE_BY_ZERO
:
935 dbg_printf("divide by zero");
937 case EXCEPTION_FLT_INEXACT_RESULT
:
938 dbg_printf("inexact float result");
940 case EXCEPTION_FLT_INVALID_OPERATION
:
941 dbg_printf("invalid float operation");
943 case EXCEPTION_FLT_OVERFLOW
:
944 dbg_printf("floating point overflow");
946 case EXCEPTION_FLT_UNDERFLOW
:
947 dbg_printf("floating point underflow");
949 case EXCEPTION_FLT_STACK_CHECK
:
950 dbg_printf("floating point stack check");
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]);
957 dbg_printf("C++ exception with strange parameter count %d or magic 0x%08lx",
958 rec
->NumberParameters
, rec
->ExceptionInformation
[0]);
961 dbg_printf("0x%08x", rec
->ExceptionCode
);
964 if (rec
->ExceptionFlags
& EH_STACK_INVALID
)
965 dbg_printf(", invalid program stack");
970 dbg_printf(" in %d-bit code (%s)",
971 be_cpu
->pointer_size
* 8,
972 memory_offset_to_string(hexbuf
, addr
.Offset
, 0));
975 dbg_printf(" in vm86 code (%04x:%04x)", addr
.Segment
, (unsigned) addr
.Offset
);
978 dbg_printf(" in 16-bit code (%04x:%04x)", addr
.Segment
, (unsigned) addr
.Offset
);
981 dbg_printf(" in segmented 32-bit code (%04x:%08lx)", addr
.Segment
, (unsigned long) addr
.Offset
);
983 default: dbg_printf(" bad address");