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
;
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 SymSetOptions((opt
= SymGetOptions()) | 0x40000000);
232 SymEnumerateModules64(dbg_curr_process
->handle
, info_mod_cb
, &im
);
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
[32], 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");