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) thread <tid>",
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
;
156 struct info_module
*modules
;
161 static void module_print_info(const struct info_module
*module
, BOOL is_embedded
)
163 dbg_printf("%*.*s-%*.*s\t%-16s%s\n",
164 ADDRWIDTH
, ADDRWIDTH
, wine_dbgstr_longlong(module
->mi
.BaseOfImage
),
165 ADDRWIDTH
, ADDRWIDTH
, wine_dbgstr_longlong(module
->mi
.BaseOfImage
+ module
->mi
.ImageSize
),
166 is_embedded
? "\\" : get_symtype_str(&module
->mi
), module
->name
);
169 static int module_compare(const void* p1
, const void* p2
)
171 struct info_module
*left
= (struct info_module
*)p1
;
172 struct info_module
*right
= (struct info_module
*)p2
;
173 LONGLONG val
= left
->mi
.BaseOfImage
- right
->mi
.BaseOfImage
;
175 if (val
< 0) return -1;
176 else if (val
> 0) return 1;
180 static inline BOOL
module_is_container(const struct info_module
*wmod_cntnr
,
181 const struct info_module
*wmod_child
)
183 return wmod_cntnr
->mi
.BaseOfImage
<= wmod_child
->mi
.BaseOfImage
&&
184 wmod_cntnr
->mi
.BaseOfImage
+ wmod_cntnr
->mi
.ImageSize
>=
185 wmod_child
->mi
.BaseOfImage
+ wmod_child
->mi
.ImageSize
;
188 static BOOL CALLBACK
info_mod_cb(PCSTR mod_name
, DWORD64 base
, PVOID ctx
)
190 struct info_modules
*im
= ctx
;
192 if (im
->num_used
+ 1 > im
->num_alloc
)
195 im
->modules
= dbg_heap_realloc(im
->modules
, im
->num_alloc
* sizeof(*im
->modules
));
197 im
->modules
[im
->num_used
].mi
.SizeOfStruct
= sizeof(im
->modules
[im
->num_used
].mi
);
198 if (SymGetModuleInfo64(dbg_curr_process
->handle
, base
, &im
->modules
[im
->num_used
].mi
))
200 const int dst_len
= sizeof(im
->modules
[im
->num_used
].name
);
201 lstrcpynA(im
->modules
[im
->num_used
].name
, mod_name
, dst_len
- 1);
202 im
->modules
[im
->num_used
].name
[dst_len
- 1] = 0;
208 /***********************************************************************
211 * Display information about a given module (DLL or EXE), or about all modules
213 void info_win32_module(DWORD64 base
)
215 struct info_modules im
;
216 UINT i
, j
, num_printed
= 0;
219 if (!dbg_curr_process
)
221 dbg_printf("Cannot get info on module while no process is loaded\n");
226 im
.num_alloc
= im
.num_used
= 0;
228 /* this is a wine specific options to return also ELF modules in the
231 opt
= SymSetExtendedOption(SYMOPT_EX_WINE_NATIVE_MODULES
, TRUE
);
232 SymEnumerateModules64(dbg_curr_process
->handle
, info_mod_cb
, &im
);
233 SymSetExtendedOption(SYMOPT_EX_WINE_NATIVE_MODULES
, opt
);
235 qsort(im
.modules
, im
.num_used
, sizeof(im
.modules
[0]), module_compare
);
237 dbg_printf("Module\tAddress\t\t\t%sDebug info\tName (%d modules)\n",
238 ADDRWIDTH
== 16 ? "\t\t" : "", im
.num_used
);
240 for (i
= 0; i
< im
.num_used
; i
++)
243 (base
< im
.modules
[i
].mi
.BaseOfImage
|| base
>= im
.modules
[i
].mi
.BaseOfImage
+ im
.modules
[i
].mi
.ImageSize
))
245 if (strstr(im
.modules
[i
].name
, "<elf>"))
248 module_print_info(&im
.modules
[i
], FALSE
);
249 /* print all modules embedded in this one */
250 for (j
= 0; j
< im
.num_used
; j
++)
252 if (!strstr(im
.modules
[j
].name
, "<elf>") && module_is_container(&im
.modules
[i
], &im
.modules
[j
]))
254 dbg_printf(" \\-PE\t");
255 module_print_info(&im
.modules
[j
], TRUE
);
261 /* check module is not embedded in another module */
262 for (j
= 0; j
< im
.num_used
; j
++)
264 if (strstr(im
.modules
[j
].name
, "<elf>") && module_is_container(&im
.modules
[j
], &im
.modules
[i
]))
267 if (j
< im
.num_used
) continue;
268 if (strstr(im
.modules
[i
].name
, ".so") || strchr(im
.modules
[i
].name
, '<'))
272 module_print_info(&im
.modules
[i
], FALSE
);
276 HeapFree(GetProcessHeap(), 0, im
.modules
);
278 if (base
&& !num_printed
)
279 dbg_printf("'0x%x%08x' is not a valid module address\n", (DWORD
)(base
>> 32), (DWORD
)base
);
289 static void class_walker(HWND hWnd
, struct class_walker
* cw
)
296 if (!GetClassNameA(hWnd
, clsName
, sizeof(clsName
)))
298 if ((atom
= FindAtomA(clsName
)) == 0)
301 for (i
= 0; i
< cw
->used
; i
++)
303 if (cw
->table
[i
] == atom
)
308 if (cw
->used
>= cw
->alloc
)
311 cw
->table
= dbg_heap_realloc(cw
->table
, cw
->alloc
* sizeof(ATOM
));
313 cw
->table
[cw
->used
++] = atom
;
314 info_win32_class(hWnd
, clsName
);
318 if ((child
= GetWindow(hWnd
, GW_CHILD
)) != 0)
319 class_walker(child
, cw
);
320 } while ((hWnd
= GetWindow(hWnd
, GW_HWNDNEXT
)) != 0);
323 void info_win32_class(HWND hWnd
, const char* name
)
326 HINSTANCE hInst
= hWnd
? (HINSTANCE
)GetWindowLongPtrW(hWnd
, GWLP_HINSTANCE
) : 0;
330 struct class_walker cw
;
333 cw
.used
= cw
.alloc
= 0;
334 class_walker(GetDesktopWindow(), &cw
);
335 HeapFree(GetProcessHeap(), 0, cw
.table
);
339 if (!GetClassInfoExA(hInst
, name
, &wca
))
341 dbg_printf("Cannot find class '%s'\n", name
);
345 dbg_printf("Class '%s':\n", name
);
346 dbg_printf("style=0x%08x wndProc=%p\n"
347 "inst=%p icon=%p cursor=%p bkgnd=%p\n"
348 "clsExtra=%d winExtra=%d\n",
349 wca
.style
, wca
.lpfnWndProc
, wca
.hInstance
,
350 wca
.hIcon
, wca
.hCursor
, wca
.hbrBackground
,
351 wca
.cbClsExtra
, wca
.cbWndExtra
);
353 if (hWnd
&& wca
.cbClsExtra
)
358 dbg_printf("Extra bytes:");
359 for (i
= 0; i
< wca
.cbClsExtra
/ 2; i
++)
361 w
= GetClassWord(hWnd
, i
* 2);
362 /* FIXME: depends on i386 endian-ity */
363 dbg_printf(" %02x %02x", HIBYTE(w
), LOBYTE(w
));
369 * + print #windows (or even list of windows...)
370 * + print extra bytes => this requires a window handle on this very class...
374 static void info_window(HWND hWnd
, int indent
)
382 if (!GetClassNameA(hWnd
, clsName
, sizeof(clsName
)))
383 strcpy(clsName
, "-- Unknown --");
384 if (!GetWindowTextA(hWnd
, wndName
, sizeof(wndName
)))
385 strcpy(wndName
, "-- Empty --");
387 dbg_printf("%*s%08lx%*s %-17.17s %08x %0*lx %08x %.14s\n",
388 indent
, "", (DWORD_PTR
)hWnd
, 12 - indent
, "",
389 clsName
, GetWindowLongW(hWnd
, GWL_STYLE
),
390 ADDRWIDTH
, (ULONG_PTR
)GetWindowLongPtrW(hWnd
, GWLP_WNDPROC
),
391 GetWindowThreadProcessId(hWnd
, NULL
), wndName
);
393 if ((child
= GetWindow(hWnd
, GW_CHILD
)) != 0)
394 info_window(child
, indent
+ 1);
395 } while ((hWnd
= GetWindow(hWnd
, GW_HWNDNEXT
)) != 0);
398 void info_win32_window(HWND hWnd
, BOOL detailed
)
406 if (!IsWindow(hWnd
)) hWnd
= GetDesktopWindow();
410 dbg_printf("%-20.20s %-17.17s %-8.8s %-*.*s %-8.8s %s\n",
411 "Window handle", "Class Name", "Style",
412 ADDRWIDTH
, ADDRWIDTH
, "WndProc", "Thread", "Text");
413 info_window(hWnd
, 0);
417 if (!GetClassNameA(hWnd
, clsName
, sizeof(clsName
)))
418 strcpy(clsName
, "-- Unknown --");
419 if (!GetWindowTextA(hWnd
, wndName
, sizeof(wndName
)))
420 strcpy(wndName
, "-- Empty --");
421 if (!GetClientRect(hWnd
, &clientRect
) ||
422 !MapWindowPoints(hWnd
, 0, (LPPOINT
) &clientRect
, 2))
423 SetRectEmpty(&clientRect
);
424 if (!GetWindowRect(hWnd
, &windowRect
))
425 SetRectEmpty(&windowRect
);
427 /* FIXME missing fields: hmemTaskQ, hrgnUpdate, dce, flags, pProp, scroll */
428 dbg_printf("next=%p child=%p parent=%p owner=%p class='%s'\n"
429 "inst=%p active=%p idmenu=%08lx\n"
430 "style=0x%08x exstyle=0x%08x wndproc=%p text='%s'\n"
431 "client=%d,%d-%d,%d window=%d,%d-%d,%d sysmenu=%p\n",
432 GetWindow(hWnd
, GW_HWNDNEXT
),
433 GetWindow(hWnd
, GW_CHILD
),
435 GetWindow(hWnd
, GW_OWNER
),
437 (HINSTANCE
)GetWindowLongPtrW(hWnd
, GWLP_HINSTANCE
),
438 GetLastActivePopup(hWnd
),
439 (ULONG_PTR
)GetWindowLongPtrW(hWnd
, GWLP_ID
),
440 GetWindowLongW(hWnd
, GWL_STYLE
),
441 GetWindowLongW(hWnd
, GWL_EXSTYLE
),
442 (void*)GetWindowLongPtrW(hWnd
, GWLP_WNDPROC
),
444 clientRect
.left
, clientRect
.top
, clientRect
.right
, clientRect
.bottom
,
445 windowRect
.left
, windowRect
.top
, windowRect
.right
, windowRect
.bottom
,
446 GetSystemMenu(hWnd
, FALSE
));
448 if (GetClassLongW(hWnd
, GCL_CBWNDEXTRA
))
452 dbg_printf("Extra bytes:");
453 for (i
= 0; i
< GetClassLongW(hWnd
, GCL_CBWNDEXTRA
) / 2; i
++)
455 w
= GetWindowWord(hWnd
, i
* 2);
456 /* FIXME: depends on i386 endian-ity */
457 dbg_printf(" %02x %02x", HIBYTE(w
), LOBYTE(w
));
464 struct dump_proc_entry
467 unsigned children
; /* index in dump_proc.entries of first child */
468 unsigned sibling
; /* index in dump_proc.entries of next sibling */
473 struct dump_proc_entry
*entries
;
478 static unsigned get_parent(const struct dump_proc
* dp
, unsigned idx
)
482 for (i
= 0; i
< dp
->count
; i
++)
484 if (i
!= idx
&& dp
->entries
[i
].proc
.th32ProcessID
== dp
->entries
[idx
].proc
.th32ParentProcessID
)
490 static void dump_proc_info(const struct dump_proc
* dp
, unsigned idx
, unsigned depth
)
492 struct dump_proc_entry
* dpe
;
493 for ( ; idx
!= -1; idx
= dp
->entries
[idx
].sibling
)
495 assert(idx
< dp
->count
);
496 dpe
= &dp
->entries
[idx
];
497 dbg_printf("%c%08x %-8d ",
498 (dpe
->proc
.th32ProcessID
== (dbg_curr_process
?
499 dbg_curr_process
->pid
: 0)) ? '>' : ' ',
500 dpe
->proc
.th32ProcessID
, dpe
->proc
.cntThreads
);
504 for (i
= 3 * (depth
- 1); i
> 0; i
--) dbg_printf(" ");
507 dbg_printf("'%s'\n", dpe
->proc
.szExeFile
);
508 dump_proc_info(dp
, dpe
->children
, depth
+ 1);
512 void info_win32_processes(void)
514 HANDLE snap
= CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS
, 0);
515 if (snap
!= INVALID_HANDLE_VALUE
)
518 unsigned i
, first
= -1;
523 dp
.entries
= HeapAlloc(GetProcessHeap(), 0, sizeof(*dp
.entries
) * dp
.alloc
);
529 dp
.entries
[dp
.count
].proc
.dwSize
= sizeof(dp
.entries
[dp
.count
].proc
);
530 ok
= Process32First(snap
, &dp
.entries
[dp
.count
].proc
);
532 /* fetch all process information into dp (skipping this debugger) */
535 if (dp
.entries
[dp
.count
].proc
.th32ProcessID
!= GetCurrentProcessId())
536 dp
.entries
[dp
.count
++].children
= -1;
537 if (dp
.count
>= dp
.alloc
)
539 dp
.entries
= HeapReAlloc(GetProcessHeap(), 0, dp
.entries
, sizeof(*dp
.entries
) * (dp
.alloc
*= 2));
540 if (!dp
.entries
) return;
542 dp
.entries
[dp
.count
].proc
.dwSize
= sizeof(dp
.entries
[dp
.count
].proc
);
543 ok
= Process32Next(snap
, &dp
.entries
[dp
.count
].proc
);
546 /* chain the siblings wrt. their parent */
547 for (i
= 0; i
< dp
.count
; i
++)
549 unsigned parent
= get_parent(&dp
, i
);
550 unsigned *chain
= parent
== -1 ? &first
: &dp
.entries
[parent
].children
;
551 dp
.entries
[i
].sibling
= *chain
;
554 dbg_printf(" %-8.8s %-8.8s %s (all id:s are in hex)\n", "pid", "threads", "executable");
555 dump_proc_info(&dp
, first
, 0);
556 HeapFree(GetProcessHeap(), 0, dp
.entries
);
560 static BOOL
get_process_name(DWORD pid
, PROCESSENTRY32
* entry
)
563 HANDLE snap
= CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS
, 0);
565 if (snap
!= INVALID_HANDLE_VALUE
)
567 entry
->dwSize
= sizeof(*entry
);
568 if (Process32First(snap
, entry
))
569 while (!(ret
= (entry
->th32ProcessID
== pid
)) &&
570 Process32Next(snap
, entry
));
576 void info_win32_threads(void)
578 HANDLE snap
= CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD
, 0);
579 if (snap
!= INVALID_HANDLE_VALUE
)
583 DWORD lastProcessId
= 0;
585 entry
.dwSize
= sizeof(entry
);
586 ok
= Thread32First(snap
, &entry
);
588 dbg_printf("%-8.8s %-8.8s %s (all id:s are in hex)\n",
589 "process", "tid", "prio");
592 if (entry
.th32OwnerProcessID
!= GetCurrentProcessId())
594 /* FIXME: this assumes that, in the snapshot, all threads of a same process are
595 * listed sequentially, which is not specified in the doc (Wine's implementation
598 if (entry
.th32OwnerProcessID
!= lastProcessId
)
600 struct dbg_process
* p
= dbg_get_process(entry
.th32OwnerProcessID
);
601 PROCESSENTRY32 pcs_entry
;
605 exename
= dbg_W2A(p
->imageName
, -1);
606 else if (get_process_name(entry
.th32OwnerProcessID
, &pcs_entry
))
607 exename
= pcs_entry
.szExeFile
;
611 dbg_printf("%08x%s %s\n",
612 entry
.th32OwnerProcessID
, p
? " (D)" : "", exename
);
613 lastProcessId
= entry
.th32OwnerProcessID
;
615 dbg_printf("\t%08x %4d%s\n",
616 entry
.th32ThreadID
, entry
.tpBasePri
,
617 (entry
.th32ThreadID
== dbg_curr_tid
) ? " <==" : "");
620 ok
= Thread32Next(snap
, &entry
);
627 /***********************************************************************
628 * info_win32_frame_exceptions
630 * Get info on the exception frames of a given thread.
632 void info_win32_frame_exceptions(DWORD tid
)
634 struct dbg_thread
* thread
;
637 if (!dbg_curr_process
|| !dbg_curr_thread
)
639 dbg_printf("Cannot get info on exceptions while no process is loaded\n");
643 dbg_printf("Exception frames:\n");
645 if (tid
== dbg_curr_tid
) thread
= dbg_curr_thread
;
648 thread
= dbg_get_thread(dbg_curr_process
, tid
);
652 dbg_printf("Unknown thread id (%04x) in current process\n", tid
);
655 if (SuspendThread(thread
->handle
) == -1)
657 dbg_printf("Can't suspend thread id (%04x)\n", tid
);
662 if (!dbg_read_memory(thread
->teb
, &next_frame
, sizeof(next_frame
)))
664 dbg_printf("Can't read TEB:except_frame\n");
668 while (next_frame
!= (void*)-1)
670 EXCEPTION_REGISTRATION_RECORD frame
;
672 dbg_printf("%p: ", next_frame
);
673 if (!dbg_read_memory(next_frame
, &frame
, sizeof(frame
)))
675 dbg_printf("Invalid frame address\n");
678 dbg_printf("prev=%p handler=%p\n", frame
.Prev
, frame
.Handler
);
679 next_frame
= frame
.Prev
;
682 if (tid
!= dbg_curr_tid
) ResumeThread(thread
->handle
);
685 void info_win32_segments(DWORD start
, int length
)
691 if (length
== -1) length
= (8192 - start
);
693 for (i
= start
; i
< start
+ length
; i
++)
695 if (!dbg_curr_process
->process_io
->get_selector(dbg_curr_thread
->handle
, (i
<< 3) | 7, &le
))
698 if (le
.HighWord
.Bits
.Type
& 0x08)
700 flags
[0] = (le
.HighWord
.Bits
.Type
& 0x2) ? 'r' : '-';
707 flags
[1] = (le
.HighWord
.Bits
.Type
& 0x2) ? 'w' : '-';
710 dbg_printf("%04x: sel=%04x base=%08x limit=%08x %d-bit %c%c%c\n",
712 (le
.HighWord
.Bits
.BaseHi
<< 24) +
713 (le
.HighWord
.Bits
.BaseMid
<< 16) + le
.BaseLow
,
714 ((le
.HighWord
.Bits
.LimitHi
<< 8) + le
.LimitLow
) <<
715 (le
.HighWord
.Bits
.Granularity
? 12 : 0),
716 le
.HighWord
.Bits
.Default_Big
? 32 : 16,
717 flags
[0], flags
[1], flags
[2]);
721 void info_win32_virtual(DWORD pid
)
723 MEMORY_BASIC_INFORMATION mbi
;
730 if (pid
== dbg_curr_pid
)
732 if (dbg_curr_process
== NULL
)
734 dbg_printf("Cannot look at mapping of current process, while no process is loaded\n");
737 hProc
= dbg_curr_process
->handle
;
741 hProc
= OpenProcess(PROCESS_QUERY_INFORMATION
| PROCESS_VM_READ
, FALSE
, pid
);
744 dbg_printf("Cannot open process <%04x>\n", pid
);
749 dbg_printf("Address End State Type RWX\n");
751 while (VirtualQueryEx(hProc
, addr
, &mbi
, sizeof(mbi
)) >= sizeof(mbi
))
755 case MEM_COMMIT
: state
= "commit "; break;
756 case MEM_FREE
: state
= "free "; break;
757 case MEM_RESERVE
: state
= "reserve"; break;
758 default: state
= "??? "; break;
760 if (mbi
.State
!= MEM_FREE
)
764 case MEM_IMAGE
: type
= "image "; break;
765 case MEM_MAPPED
: type
= "mapped "; break;
766 case MEM_PRIVATE
: type
= "private"; break;
767 case 0: type
= " "; break;
768 default: type
= "??? "; break;
770 memset(prot
, ' ' , sizeof(prot
) - 1);
771 prot
[sizeof(prot
) - 1] = '\0';
772 if (mbi
.AllocationProtect
& (PAGE_READONLY
|PAGE_READWRITE
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_READWRITE
))
774 if (mbi
.AllocationProtect
& (PAGE_READWRITE
|PAGE_EXECUTE_READWRITE
))
776 if (mbi
.AllocationProtect
& (PAGE_WRITECOPY
|PAGE_EXECUTE_WRITECOPY
))
778 if (mbi
.AllocationProtect
& (PAGE_EXECUTE
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_READWRITE
))
786 dbg_printf("%08lx %08lx %s %s %s\n",
787 (DWORD_PTR
)addr
, (DWORD_PTR
)addr
+ mbi
.RegionSize
- 1, state
, type
, prot
);
788 if (addr
+ mbi
.RegionSize
< addr
) /* wrap around ? */
790 addr
+= mbi
.RegionSize
;
792 if (pid
!= dbg_curr_pid
) CloseHandle(hProc
);
795 void info_wine_dbg_channel(BOOL turn_on
, const char* cls
, const char* name
)
797 struct dbg_lvalue lvalue
;
798 struct __wine_debug_channel channel
;
804 if (!dbg_curr_process
|| !dbg_curr_thread
)
806 dbg_printf("Cannot set/get debug channels while no process is loaded\n");
810 if (symbol_get_lvalue("debug_options", -1, &lvalue
, FALSE
) != sglv_found
)
814 addr
= memory_to_linear_addr(&lvalue
.addr
);
817 else if (!strcmp(cls
, "fixme")) mask
= (1 << __WINE_DBCL_FIXME
);
818 else if (!strcmp(cls
, "err")) mask
= (1 << __WINE_DBCL_ERR
);
819 else if (!strcmp(cls
, "warn")) mask
= (1 << __WINE_DBCL_WARN
);
820 else if (!strcmp(cls
, "trace")) mask
= (1 << __WINE_DBCL_TRACE
);
823 dbg_printf("Unknown debug class %s\n", cls
);
827 bAll
= !strcmp("all", name
);
828 while (addr
&& dbg_read_memory(addr
, &channel
, sizeof(channel
)))
830 if (!channel
.name
[0]) break;
831 if (bAll
|| !strcmp( channel
.name
, name
))
833 if (turn_on
) channel
.flags
|= mask
;
834 else channel
.flags
&= ~mask
;
835 if (dbg_write_memory(addr
, &channel
, sizeof(channel
))) done
++;
837 addr
= (struct __wine_debug_channel
*)addr
+ 1;
839 if (!done
) dbg_printf("Unable to find debug channel %s\n", name
);
840 else WINE_TRACE("Changed %d channel instances\n", done
);
843 void info_win32_exception(void)
845 const EXCEPTION_RECORD
* rec
;
847 char hexbuf
[MAX_OFFSET_TO_STR_LEN
];
849 if (!dbg_curr_thread
->in_exception
)
851 dbg_printf("Thread isn't in an exception\n");
854 rec
= &dbg_curr_thread
->excpt_record
;
855 memory_get_current_pc(&addr
);
857 /* print some infos */
859 dbg_curr_thread
->first_chance
? "First chance exception" : "Unhandled exception");
860 switch (rec
->ExceptionCode
)
862 case EXCEPTION_BREAKPOINT
:
863 dbg_printf("breakpoint");
865 case EXCEPTION_SINGLE_STEP
:
866 dbg_printf("single step");
868 case EXCEPTION_INT_DIVIDE_BY_ZERO
:
869 dbg_printf("divide by zero");
871 case EXCEPTION_INT_OVERFLOW
:
872 dbg_printf("overflow");
874 case EXCEPTION_ARRAY_BOUNDS_EXCEEDED
:
875 dbg_printf("array bounds");
877 case EXCEPTION_ILLEGAL_INSTRUCTION
:
878 dbg_printf("illegal instruction");
880 case EXCEPTION_STACK_OVERFLOW
:
881 dbg_printf("stack overflow");
883 case EXCEPTION_PRIV_INSTRUCTION
:
884 dbg_printf("privileged instruction");
886 case EXCEPTION_ACCESS_VIOLATION
:
887 if (rec
->NumberParameters
== 2)
888 dbg_printf("page fault on %s access to 0x%08lx",
889 rec
->ExceptionInformation
[0] == EXCEPTION_WRITE_FAULT
? "write" :
890 rec
->ExceptionInformation
[0] == EXCEPTION_EXECUTE_FAULT
? "execute" : "read",
891 rec
->ExceptionInformation
[1]);
893 dbg_printf("page fault");
895 case EXCEPTION_DATATYPE_MISALIGNMENT
:
896 dbg_printf("Alignment");
904 case STATUS_POSSIBLE_DEADLOCK
:
908 recaddr
.Mode
= AddrModeFlat
;
909 recaddr
.Offset
= rec
->ExceptionInformation
[0];
911 dbg_printf("wait failed on critical section ");
912 print_address(&recaddr
, FALSE
);
915 case EXCEPTION_WINE_STUB
:
917 char dll
[64], name
[256];
918 memory_get_string(dbg_curr_process
,
919 (void*)rec
->ExceptionInformation
[0], TRUE
, FALSE
,
921 if (HIWORD(rec
->ExceptionInformation
[1]))
922 memory_get_string(dbg_curr_process
,
923 (void*)rec
->ExceptionInformation
[1], TRUE
, FALSE
,
926 sprintf( name
, "%ld", rec
->ExceptionInformation
[1] );
927 dbg_printf("unimplemented function %s.%s called", dll
, name
);
930 case EXCEPTION_WINE_ASSERTION
:
931 dbg_printf("assertion failed");
933 case EXCEPTION_FLT_DENORMAL_OPERAND
:
934 dbg_printf("denormal float operand");
936 case EXCEPTION_FLT_DIVIDE_BY_ZERO
:
937 dbg_printf("divide by zero");
939 case EXCEPTION_FLT_INEXACT_RESULT
:
940 dbg_printf("inexact float result");
942 case EXCEPTION_FLT_INVALID_OPERATION
:
943 dbg_printf("invalid float operation");
945 case EXCEPTION_FLT_OVERFLOW
:
946 dbg_printf("floating point overflow");
948 case EXCEPTION_FLT_UNDERFLOW
:
949 dbg_printf("floating point underflow");
951 case EXCEPTION_FLT_STACK_CHECK
:
952 dbg_printf("floating point stack check");
955 if(rec
->NumberParameters
== 3 && rec
->ExceptionInformation
[0] == CXX_FRAME_MAGIC
)
956 dbg_printf("C++ exception(object = 0x%08lx, type = 0x%08lx)",
957 rec
->ExceptionInformation
[1], rec
->ExceptionInformation
[2]);
958 else if(rec
->NumberParameters
== 4 && rec
->ExceptionInformation
[0] == CXX_FRAME_MAGIC
)
959 dbg_printf("C++ exception(object = %p, type = %p, base = %p)",
960 (void*)rec
->ExceptionInformation
[1], (void*)rec
->ExceptionInformation
[2],
961 (void*)rec
->ExceptionInformation
[3]);
963 dbg_printf("C++ exception with strange parameter count %d or magic 0x%08lx",
964 rec
->NumberParameters
, rec
->ExceptionInformation
[0]);
967 dbg_printf("0x%08x", rec
->ExceptionCode
);
970 if (rec
->ExceptionFlags
& EH_STACK_INVALID
)
971 dbg_printf(", invalid program stack");
976 dbg_printf(" in %d-bit code (%s)",
977 dbg_curr_process
->be_cpu
->pointer_size
* 8,
978 memory_offset_to_string(hexbuf
, addr
.Offset
, 0));
981 dbg_printf(" in vm86 code (%04x:%04x)", addr
.Segment
, (unsigned) addr
.Offset
);
984 dbg_printf(" in 16-bit code (%04x:%04x)", addr
.Segment
, (unsigned) addr
.Offset
);
987 dbg_printf(" in segmented 32-bit code (%04x:%08x)", addr
.Segment
, (unsigned) addr
.Offset
);
989 default: dbg_printf(" bad address");