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
31 #include "wine/debug.h"
33 WINE_DEFAULT_DEBUG_CHANNEL(winedbg
);
35 /***********************************************************************
38 * Implementation of the 'help' command.
43 static const char * const helptext
[] =
45 "The commands accepted by the Wine debugger are a reasonable",
46 "subset of the commands that gdb accepts.",
47 "The commands currently are:",
49 " attach <wpid> detach",
50 " break [*<addr>] watch | rwatch *<addr>",
51 " delete break bpnum disable bpnum",
52 " enable bpnum condition <bpnum> [<expr>]",
55 " stepi [N] nexti [N]",
56 " x <addr> print <expr>",
57 " display <expr> undisplay <disnum>",
58 " local display <expr> delete display <disnum>",
59 " enable display <disnum> disable display <disnum>",
60 " bt [<tid>|all] frame <n>",
62 " list <lines> disassemble [<addr>][,<addr>]",
63 " show dir dir <path>",
64 " set <reg> = <expr> set *<addr> = <expr>",
66 " info (see 'help info' for options) thread <tid>",
68 "The 'x' command accepts repeat counts and formats (including 'i') in the",
69 "same way that gdb does.\n",
71 "The following are examples of legal expressions:",
72 " $eax $eax+0x3 0x1000 ($eip + 256) *$eax *($esp + 3)",
73 " Also, a nm format symbol table can be read from a file using the",
74 " symbolfile command.", /* Symbols can also be defined individually with",
75 " the define command.", */
80 while (helptext
[i
]) dbg_printf("%s\n", helptext
[i
++]);
84 /***********************************************************************
87 * Implementation of the 'help info' command.
92 static const char * const infotext
[] =
94 "The info commands allow you to get assorted bits of interesting stuff",
95 "to be displayed. The options are:",
96 " info break Displays information about breakpoints",
97 " info class <name> Displays information about window class <name>",
98 " info display Shows auto-display expressions in use",
99 " info except <pid> Shows exception handler chain (in a given process)",
100 " info locals Displays values of all local vars for current frame",
101 " info maps <pid> Shows virtual mappings (in a given process)",
102 " info process Shows all running processes",
103 " info reg Displays values of the general registers at top of stack",
104 " info all-reg Displays the general and floating point registers",
105 " info segments <pid> Displays information about all known segments",
106 " info share Displays all loaded modules",
107 " info share <addr> Displays internal module state",
108 " info stack [<len>] Dumps information about top of stack, up to len words",
109 " info symbol <sym> Displays information about a given symbol",
110 " info thread Shows all running threads",
111 " info wnd <handle> Displays internal window state",
116 while (infotext
[i
]) dbg_printf("%s\n", infotext
[i
++]);
119 static const char* get_symtype_str(const IMAGEHLP_MODULE64
* mi
)
124 case SymNone
: return "--none--";
125 case SymCoff
: return "COFF";
126 case SymCv
: return "CodeView";
127 case SymPdb
: return "PDB";
128 case SymExport
: return "Export";
129 case SymDeferred
: return "Deferred";
130 case SymSym
: return "Sym";
134 case 'S' | ('T' << 8) | ('A' << 16) | ('B' << 24):
136 case 'D' | ('W' << 8) | ('A' << 16) | ('R' << 24):
137 /* previous versions of dbghelp used to report this... */
140 if ((mi
->CVSig
& 0x00FFFFFF) == ('D' | ('W' << 8) | ('F' << 16)))
143 DWORD versbit
= mi
->CVSig
>> 24;
144 strcpy(tmp
, "Dwarf");
145 if (versbit
& 1) strcat(tmp
, "-2");
146 if (versbit
& 2) strcat(tmp
, "-3");
147 if (versbit
& 4) strcat(tmp
, "-4");
148 if (versbit
& 8) strcat(tmp
, "-5");
158 IMAGEHLP_MODULE64 mi
;
164 struct info_module
*modules
;
169 static void module_print_info(const struct info_module
*module
, BOOL is_embedded
)
171 dbg_printf("%*.*I64x-%*.*I64x\t%-16s%s\n",
172 ADDRWIDTH
, ADDRWIDTH
, module
->mi
.BaseOfImage
,
173 ADDRWIDTH
, ADDRWIDTH
, module
->mi
.BaseOfImage
+ module
->mi
.ImageSize
,
174 is_embedded
? "\\" : get_symtype_str(&module
->mi
), module
->name
);
177 static int __cdecl
module_compare(const void* p1
, const void* p2
)
179 struct info_module
*left
= (struct info_module
*)p1
;
180 struct info_module
*right
= (struct info_module
*)p2
;
181 LONGLONG val
= left
->mi
.BaseOfImage
- right
->mi
.BaseOfImage
;
183 if (val
< 0) return -1;
184 else if (val
> 0) return 1;
188 static inline BOOL
module_is_container(const struct info_module
*wmod_cntnr
,
189 const struct info_module
*wmod_child
)
191 return wmod_cntnr
->mi
.BaseOfImage
<= wmod_child
->mi
.BaseOfImage
&&
192 wmod_cntnr
->mi
.BaseOfImage
+ wmod_cntnr
->mi
.ImageSize
>=
193 wmod_child
->mi
.BaseOfImage
+ wmod_child
->mi
.ImageSize
;
196 static BOOL CALLBACK
info_mod_cb(PCSTR mod_name
, DWORD64 base
, PVOID ctx
)
198 struct info_modules
*im
= ctx
;
200 if (im
->num_used
+ 1 > im
->num_alloc
)
203 im
->modules
= dbg_heap_realloc(im
->modules
, im
->num_alloc
* sizeof(*im
->modules
));
205 im
->modules
[im
->num_used
].mi
.SizeOfStruct
= sizeof(im
->modules
[im
->num_used
].mi
);
206 if (SymGetModuleInfo64(dbg_curr_process
->handle
, base
, &im
->modules
[im
->num_used
].mi
))
208 const int dst_len
= sizeof(im
->modules
[im
->num_used
].name
);
209 lstrcpynA(im
->modules
[im
->num_used
].name
, mod_name
, dst_len
- 1);
210 im
->modules
[im
->num_used
].name
[dst_len
- 1] = 0;
216 /***********************************************************************
219 * Display information about a given module (DLL or EXE), or about all modules
221 void info_win32_module(DWORD64 base
)
223 struct info_modules im
;
224 UINT i
, j
, num_printed
= 0;
227 if (!dbg_curr_process
)
229 dbg_printf("Cannot get info on module while no process is loaded\n");
234 im
.num_alloc
= im
.num_used
= 0;
236 /* this is a wine specific options to return also ELF modules in the
239 opt
= SymSetExtendedOption(SYMOPT_EX_WINE_NATIVE_MODULES
, TRUE
);
240 SymEnumerateModules64(dbg_curr_process
->handle
, info_mod_cb
, &im
);
241 SymSetExtendedOption(SYMOPT_EX_WINE_NATIVE_MODULES
, opt
);
243 qsort(im
.modules
, im
.num_used
, sizeof(im
.modules
[0]), module_compare
);
245 dbg_printf("Module\tAddress\t\t\t%sDebug info\tName (%d modules)\n",
246 ADDRWIDTH
== 16 ? "\t\t" : "", im
.num_used
);
248 for (i
= 0; i
< im
.num_used
; i
++)
251 (base
< im
.modules
[i
].mi
.BaseOfImage
|| base
>= im
.modules
[i
].mi
.BaseOfImage
+ im
.modules
[i
].mi
.ImageSize
))
253 if (strstr(im
.modules
[i
].name
, "<elf>"))
256 module_print_info(&im
.modules
[i
], FALSE
);
257 /* print all modules embedded in this one */
258 for (j
= 0; j
< im
.num_used
; j
++)
260 if (!strstr(im
.modules
[j
].name
, "<elf>") && module_is_container(&im
.modules
[i
], &im
.modules
[j
]))
262 dbg_printf(" \\-PE\t");
263 module_print_info(&im
.modules
[j
], TRUE
);
269 /* check module is not embedded in another module */
270 for (j
= 0; j
< im
.num_used
; j
++)
272 if (strstr(im
.modules
[j
].name
, "<elf>") && module_is_container(&im
.modules
[j
], &im
.modules
[i
]))
275 if (j
< im
.num_used
) continue;
276 if (strstr(im
.modules
[i
].name
, ".so") || strchr(im
.modules
[i
].name
, '<'))
280 module_print_info(&im
.modules
[i
], FALSE
);
284 HeapFree(GetProcessHeap(), 0, im
.modules
);
286 if (base
&& !num_printed
)
287 dbg_printf("'0x%0*I64x' is not a valid module address\n", ADDRWIDTH
, base
);
297 static void class_walker(HWND hWnd
, struct class_walker
* cw
)
304 if (!GetClassNameA(hWnd
, clsName
, sizeof(clsName
)))
306 if ((atom
= FindAtomA(clsName
)) == 0)
309 for (i
= 0; i
< cw
->used
; i
++)
311 if (cw
->table
[i
] == atom
)
316 if (cw
->used
>= cw
->alloc
)
319 cw
->table
= dbg_heap_realloc(cw
->table
, cw
->alloc
* sizeof(ATOM
));
321 cw
->table
[cw
->used
++] = atom
;
322 info_win32_class(hWnd
, clsName
);
326 if ((child
= GetWindow(hWnd
, GW_CHILD
)) != 0)
327 class_walker(child
, cw
);
328 } while ((hWnd
= GetWindow(hWnd
, GW_HWNDNEXT
)) != 0);
331 void info_win32_class(HWND hWnd
, const char* name
)
334 HINSTANCE hInst
= hWnd
? (HINSTANCE
)GetWindowLongPtrW(hWnd
, GWLP_HINSTANCE
) : 0;
338 struct class_walker cw
;
341 cw
.used
= cw
.alloc
= 0;
342 class_walker(GetDesktopWindow(), &cw
);
343 HeapFree(GetProcessHeap(), 0, cw
.table
);
347 if (!GetClassInfoExA(hInst
, name
, &wca
))
349 dbg_printf("Cannot find class '%s'\n", name
);
353 dbg_printf("Class '%s':\n", name
);
354 dbg_printf("style=0x%08x wndProc=%p\n"
355 "inst=%p icon=%p cursor=%p bkgnd=%p\n"
356 "clsExtra=%d winExtra=%d\n",
357 wca
.style
, wca
.lpfnWndProc
, wca
.hInstance
,
358 wca
.hIcon
, wca
.hCursor
, wca
.hbrBackground
,
359 wca
.cbClsExtra
, wca
.cbWndExtra
);
361 if (hWnd
&& wca
.cbClsExtra
)
366 dbg_printf("Extra bytes:");
367 for (i
= 0; i
< wca
.cbClsExtra
/ 2; i
++)
369 w
= GetClassWord(hWnd
, i
* 2);
370 /* FIXME: depends on i386 endian-ity */
371 dbg_printf(" %02x %02x", HIBYTE(w
), LOBYTE(w
));
377 * + print #windows (or even list of windows...)
378 * + print extra bytes => this requires a window handle on this very class...
382 static void info_window(HWND hWnd
, int indent
)
390 if (!GetClassNameA(hWnd
, clsName
, sizeof(clsName
)))
391 strcpy(clsName
, "-- Unknown --");
392 if (!GetWindowTextA(hWnd
, wndName
, sizeof(wndName
)))
393 strcpy(wndName
, "-- Empty --");
395 dbg_printf("%*s%08Ix%*s %-17.17s %08lx %0*Ix %08lx %.14s\n",
396 indent
, "", (DWORD_PTR
)hWnd
, 12 - indent
, "",
397 clsName
, GetWindowLongW(hWnd
, GWL_STYLE
),
398 ADDRWIDTH
, (ULONG_PTR
)GetWindowLongPtrW(hWnd
, GWLP_WNDPROC
),
399 GetWindowThreadProcessId(hWnd
, NULL
), wndName
);
401 if ((child
= GetWindow(hWnd
, GW_CHILD
)) != 0)
402 info_window(child
, indent
+ 1);
403 } while ((hWnd
= GetWindow(hWnd
, GW_HWNDNEXT
)) != 0);
406 void info_win32_window(HWND hWnd
, BOOL detailed
)
414 if (!IsWindow(hWnd
)) hWnd
= GetDesktopWindow();
418 dbg_printf("%-20.20s %-17.17s %-8.8s %-*.*s %-8.8s %s\n",
419 "Window handle", "Class Name", "Style",
420 ADDRWIDTH
, ADDRWIDTH
, "WndProc", "Thread", "Text");
421 info_window(hWnd
, 0);
425 if (!GetClassNameA(hWnd
, clsName
, sizeof(clsName
)))
426 strcpy(clsName
, "-- Unknown --");
427 if (!GetWindowTextA(hWnd
, wndName
, sizeof(wndName
)))
428 strcpy(wndName
, "-- Empty --");
429 if (!GetClientRect(hWnd
, &clientRect
) ||
430 !MapWindowPoints(hWnd
, 0, (LPPOINT
) &clientRect
, 2))
431 SetRectEmpty(&clientRect
);
432 if (!GetWindowRect(hWnd
, &windowRect
))
433 SetRectEmpty(&windowRect
);
435 /* FIXME missing fields: hmemTaskQ, hrgnUpdate, dce, flags, pProp, scroll */
436 dbg_printf("next=%p child=%p parent=%p owner=%p class='%s'\n"
437 "inst=%p active=%p idmenu=%08Ix\n"
438 "style=0x%08lx exstyle=0x%08lx wndproc=%p text='%s'\n"
439 "client=%ld,%ld-%ld,%ld window=%ld,%ld-%ld,%ld sysmenu=%p\n",
440 GetWindow(hWnd
, GW_HWNDNEXT
),
441 GetWindow(hWnd
, GW_CHILD
),
443 GetWindow(hWnd
, GW_OWNER
),
445 (HINSTANCE
)GetWindowLongPtrW(hWnd
, GWLP_HINSTANCE
),
446 GetLastActivePopup(hWnd
),
447 (ULONG_PTR
)GetWindowLongPtrW(hWnd
, GWLP_ID
),
448 GetWindowLongW(hWnd
, GWL_STYLE
),
449 GetWindowLongW(hWnd
, GWL_EXSTYLE
),
450 (void*)GetWindowLongPtrW(hWnd
, GWLP_WNDPROC
),
452 clientRect
.left
, clientRect
.top
, clientRect
.right
, clientRect
.bottom
,
453 windowRect
.left
, windowRect
.top
, windowRect
.right
, windowRect
.bottom
,
454 GetSystemMenu(hWnd
, FALSE
));
456 if (GetClassLongW(hWnd
, GCL_CBWNDEXTRA
))
460 dbg_printf("Extra bytes:");
461 for (i
= 0; i
< GetClassLongW(hWnd
, GCL_CBWNDEXTRA
) / 2; i
++)
463 w
= GetWindowWord(hWnd
, i
* 2);
464 /* FIXME: depends on i386 endian-ity */
465 dbg_printf(" %02x %02x", HIBYTE(w
), LOBYTE(w
));
472 struct dump_proc_entry
475 unsigned children
; /* index in dump_proc.entries of first child */
476 unsigned sibling
; /* index in dump_proc.entries of next sibling */
481 struct dump_proc_entry
*entries
;
486 static unsigned get_parent(const struct dump_proc
* dp
, unsigned idx
)
490 for (i
= 0; i
< dp
->count
; i
++)
492 if (i
!= idx
&& dp
->entries
[i
].proc
.th32ProcessID
== dp
->entries
[idx
].proc
.th32ParentProcessID
)
498 static void dump_proc_info(const struct dump_proc
* dp
, unsigned idx
, unsigned depth
)
500 struct dump_proc_entry
* dpe
;
502 for ( ; idx
!= -1; idx
= dp
->entries
[idx
].sibling
)
504 assert(idx
< dp
->count
);
505 dpe
= &dp
->entries
[idx
];
506 if (dbg_curr_process
&& dpe
->proc
.th32ProcessID
== dbg_curr_process
->pid
)
508 else if (dpe
->proc
.th32ProcessID
== GetCurrentProcessId())
512 dbg_printf("%c%08lx %-8ld ", info
, dpe
->proc
.th32ProcessID
, dpe
->proc
.cntThreads
);
516 for (i
= 3 * (depth
- 1); i
> 0; i
--) dbg_printf(" ");
519 dbg_printf("'%s'\n", dpe
->proc
.szExeFile
);
520 dump_proc_info(dp
, dpe
->children
, depth
+ 1);
524 void info_win32_processes(void)
526 HANDLE snap
= CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS
, 0);
527 if (snap
!= INVALID_HANDLE_VALUE
)
530 unsigned i
, first
= -1;
535 dp
.entries
= HeapAlloc(GetProcessHeap(), 0, sizeof(*dp
.entries
) * dp
.alloc
);
541 dp
.entries
[dp
.count
].proc
.dwSize
= sizeof(dp
.entries
[dp
.count
].proc
);
542 ok
= Process32First(snap
, &dp
.entries
[dp
.count
].proc
);
544 /* fetch all process information into dp */
547 dp
.entries
[dp
.count
++].children
= -1;
548 if (dp
.count
>= dp
.alloc
)
550 dp
.entries
= HeapReAlloc(GetProcessHeap(), 0, dp
.entries
, sizeof(*dp
.entries
) * (dp
.alloc
*= 2));
551 if (!dp
.entries
) return;
553 dp
.entries
[dp
.count
].proc
.dwSize
= sizeof(dp
.entries
[dp
.count
].proc
);
554 ok
= Process32Next(snap
, &dp
.entries
[dp
.count
].proc
);
557 /* chain the siblings wrt. their parent */
558 for (i
= 0; i
< dp
.count
; i
++)
560 unsigned parent
= get_parent(&dp
, i
);
561 unsigned *chain
= parent
== -1 ? &first
: &dp
.entries
[parent
].children
;
562 dp
.entries
[i
].sibling
= *chain
;
565 dbg_printf(" %-8.8s %-8.8s %s (all id:s are in hex)\n", "pid", "threads", "executable");
566 dump_proc_info(&dp
, first
, 0);
567 HeapFree(GetProcessHeap(), 0, dp
.entries
);
571 static BOOL
get_process_name(DWORD pid
, PROCESSENTRY32W
* entry
)
574 HANDLE snap
= CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS
, 0);
576 if (snap
!= INVALID_HANDLE_VALUE
)
578 entry
->dwSize
= sizeof(*entry
);
579 if (Process32FirstW(snap
, entry
))
580 while (!(ret
= (entry
->th32ProcessID
== pid
)) &&
581 Process32NextW(snap
, entry
));
587 void info_win32_threads(void)
589 HANDLE snap
= CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD
, 0);
590 if (snap
!= INVALID_HANDLE_VALUE
)
594 DWORD lastProcessId
= 0;
595 struct dbg_process
* p
= NULL
;
596 struct dbg_thread
* t
= NULL
;
598 entry
.dwSize
= sizeof(entry
);
599 ok
= Thread32First(snap
, &entry
);
601 dbg_printf("%-8.8s %-8.8s %s %s (all IDs are in hex)\n",
602 "process", "tid", "prio", "name");
605 if (entry
.th32OwnerProcessID
!= GetCurrentProcessId())
607 /* FIXME: this assumes that, in the snapshot, all threads of a same process are
608 * listed sequentially, which is not specified in the doc (Wine's implementation
611 if (entry
.th32OwnerProcessID
!= lastProcessId
)
613 PROCESSENTRY32W pcs_entry
;
614 const WCHAR
* exename
;
616 p
= dbg_get_process(entry
.th32OwnerProcessID
);
618 exename
= p
->imageName
;
619 else if (get_process_name(entry
.th32OwnerProcessID
, &pcs_entry
))
620 exename
= pcs_entry
.szExeFile
;
624 dbg_printf("%08lx%s %ls\n",
625 entry
.th32OwnerProcessID
, p
? " (D)" : "", exename
);
626 lastProcessId
= entry
.th32OwnerProcessID
;
628 t
= dbg_get_thread(p
, entry
.th32ThreadID
);
629 dbg_printf("\t%08lx %4ld%s %s\n",
630 entry
.th32ThreadID
, entry
.tpBasePri
,
631 (entry
.th32ThreadID
== dbg_curr_tid
) ? " <==" : " ",
635 ok
= Thread32Next(snap
, &entry
);
642 /***********************************************************************
643 * info_win32_frame_exceptions
645 * Get info on the exception frames of a given thread.
647 void info_win32_frame_exceptions(DWORD tid
)
649 struct dbg_thread
* thread
;
652 if (!dbg_curr_process
|| !dbg_curr_thread
)
654 dbg_printf("Cannot get info on exceptions while no process is loaded\n");
658 dbg_printf("Exception frames:\n");
660 if (tid
== dbg_curr_tid
) thread
= dbg_curr_thread
;
663 thread
= dbg_get_thread(dbg_curr_process
, tid
);
667 dbg_printf("Unknown thread id (%04lx) in current process\n", tid
);
670 if (SuspendThread(thread
->handle
) == -1)
672 dbg_printf("Can't suspend thread id (%04lx)\n", tid
);
677 if (!dbg_read_memory(thread
->teb
, &next_frame
, sizeof(next_frame
)))
679 dbg_printf("Can't read TEB:except_frame\n");
683 while (next_frame
!= (void*)-1)
685 EXCEPTION_REGISTRATION_RECORD frame
;
687 dbg_printf("%p: ", next_frame
);
688 if (!dbg_read_memory(next_frame
, &frame
, sizeof(frame
)))
690 dbg_printf("Invalid frame address\n");
693 dbg_printf("prev=%p handler=%p\n", frame
.Prev
, frame
.Handler
);
694 next_frame
= frame
.Prev
;
697 if (tid
!= dbg_curr_tid
) ResumeThread(thread
->handle
);
700 void info_win32_segments(DWORD start
, int length
)
706 if (length
== -1) length
= (8192 - start
);
708 for (i
= start
; i
< start
+ length
; i
++)
710 if (!dbg_curr_process
->process_io
->get_selector(dbg_curr_thread
->handle
, (i
<< 3) | 7, &le
))
713 if (le
.HighWord
.Bits
.Type
& 0x08)
715 flags
[0] = (le
.HighWord
.Bits
.Type
& 0x2) ? 'r' : '-';
722 flags
[1] = (le
.HighWord
.Bits
.Type
& 0x2) ? 'w' : '-';
725 dbg_printf("%04lx: sel=%04lx base=%08x limit=%08x %d-bit %c%c%c\n",
727 (le
.HighWord
.Bits
.BaseHi
<< 24) +
728 (le
.HighWord
.Bits
.BaseMid
<< 16) + le
.BaseLow
,
729 ((le
.HighWord
.Bits
.LimitHi
<< 8) + le
.LimitLow
) <<
730 (le
.HighWord
.Bits
.Granularity
? 12 : 0),
731 le
.HighWord
.Bits
.Default_Big
? 32 : 16,
732 flags
[0], flags
[1], flags
[2]);
736 void info_win32_virtual(DWORD pid
)
738 MEMORY_BASIC_INFORMATION mbi
;
745 if (pid
== dbg_curr_pid
)
747 if (dbg_curr_process
== NULL
)
749 dbg_printf("Cannot look at mapping of current process, while no process is loaded\n");
752 hProc
= dbg_curr_process
->handle
;
756 hProc
= OpenProcess(PROCESS_QUERY_INFORMATION
| PROCESS_VM_READ
, FALSE
, pid
);
759 dbg_printf("Cannot open process <%04lx>\n", pid
);
764 dbg_printf("Address End State Type RWX\n");
766 while (VirtualQueryEx(hProc
, addr
, &mbi
, sizeof(mbi
)) >= sizeof(mbi
))
770 case MEM_COMMIT
: state
= "commit "; break;
771 case MEM_FREE
: state
= "free "; break;
772 case MEM_RESERVE
: state
= "reserve"; break;
773 default: state
= "??? "; break;
775 if (mbi
.State
!= MEM_FREE
)
779 case MEM_IMAGE
: type
= "image "; break;
780 case MEM_MAPPED
: type
= "mapped "; break;
781 case MEM_PRIVATE
: type
= "private"; break;
782 case 0: type
= " "; break;
783 default: type
= "??? "; break;
785 memset(prot
, ' ' , sizeof(prot
) - 1);
786 prot
[sizeof(prot
) - 1] = '\0';
787 if (mbi
.AllocationProtect
& (PAGE_READONLY
|PAGE_READWRITE
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_READWRITE
|PAGE_WRITECOPY
|PAGE_EXECUTE_WRITECOPY
))
789 if (mbi
.AllocationProtect
& (PAGE_READWRITE
|PAGE_EXECUTE_READWRITE
))
791 if (mbi
.AllocationProtect
& (PAGE_WRITECOPY
|PAGE_EXECUTE_WRITECOPY
))
793 if (mbi
.AllocationProtect
& (PAGE_EXECUTE
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_READWRITE
|PAGE_EXECUTE_WRITECOPY
))
801 dbg_printf("%0*Ix %0*Ix %s %s %s\n",
802 ADDRWIDTH
, (DWORD_PTR
)addr
, ADDRWIDTH
, (DWORD_PTR
)addr
+ mbi
.RegionSize
- 1, state
, type
, prot
);
803 if (addr
+ mbi
.RegionSize
< addr
) /* wrap around ? */
805 addr
+= mbi
.RegionSize
;
807 if (pid
!= dbg_curr_pid
) CloseHandle(hProc
);
810 void info_wine_dbg_channel(BOOL turn_on
, const char* cls
, const char* name
)
812 struct dbg_lvalue lvalue
;
813 struct __wine_debug_channel channel
;
819 if (!dbg_curr_process
|| !dbg_curr_thread
)
821 dbg_printf("Cannot set/get debug channels while no process is loaded\n");
825 if (symbol_get_lvalue("debug_options", -1, &lvalue
, FALSE
) != sglv_found
)
829 addr
= memory_to_linear_addr(&lvalue
.addr
);
832 else if (!strcmp(cls
, "fixme")) mask
= (1 << __WINE_DBCL_FIXME
);
833 else if (!strcmp(cls
, "err")) mask
= (1 << __WINE_DBCL_ERR
);
834 else if (!strcmp(cls
, "warn")) mask
= (1 << __WINE_DBCL_WARN
);
835 else if (!strcmp(cls
, "trace")) mask
= (1 << __WINE_DBCL_TRACE
);
838 dbg_printf("Unknown debug class %s\n", cls
);
842 bAll
= !strcmp("all", name
);
843 while (addr
&& dbg_read_memory(addr
, &channel
, sizeof(channel
)))
845 if (!channel
.name
[0]) break;
846 if (bAll
|| !strcmp( channel
.name
, name
))
848 if (turn_on
) channel
.flags
|= mask
;
849 else channel
.flags
&= ~mask
;
850 if (dbg_write_memory(addr
, &channel
, sizeof(channel
))) done
++;
852 addr
= (struct __wine_debug_channel
*)addr
+ 1;
854 if (!done
) dbg_printf("Unable to find debug channel %s\n", name
);
855 else WINE_TRACE("Changed %d channel instances\n", done
);
858 void info_win32_exception(void)
860 const EXCEPTION_RECORD
* rec
;
862 char hexbuf
[MAX_OFFSET_TO_STR_LEN
];
864 if (!dbg_curr_thread
->in_exception
)
866 dbg_printf("Thread isn't in an exception\n");
869 rec
= &dbg_curr_thread
->excpt_record
;
870 memory_get_current_pc(&addr
);
872 /* print some infos */
874 dbg_curr_thread
->first_chance
? "First chance exception" : "Unhandled exception");
875 switch (rec
->ExceptionCode
)
877 case EXCEPTION_BREAKPOINT
:
878 dbg_printf("breakpoint");
880 case EXCEPTION_SINGLE_STEP
:
881 dbg_printf("single step");
883 case EXCEPTION_INT_DIVIDE_BY_ZERO
:
884 dbg_printf("divide by zero");
886 case EXCEPTION_INT_OVERFLOW
:
887 dbg_printf("overflow");
889 case EXCEPTION_ARRAY_BOUNDS_EXCEEDED
:
890 dbg_printf("array bounds");
892 case EXCEPTION_ILLEGAL_INSTRUCTION
:
893 dbg_printf("illegal instruction");
895 case EXCEPTION_STACK_OVERFLOW
:
896 dbg_printf("stack overflow");
898 case EXCEPTION_PRIV_INSTRUCTION
:
899 dbg_printf("privileged instruction");
901 case EXCEPTION_ACCESS_VIOLATION
:
902 if (rec
->NumberParameters
== 2)
903 dbg_printf("page fault on %s access to 0x%0*Ix",
904 rec
->ExceptionInformation
[0] == EXCEPTION_WRITE_FAULT
? "write" :
905 rec
->ExceptionInformation
[0] == EXCEPTION_EXECUTE_FAULT
? "execute" : "read",
906 ADDRWIDTH
, rec
->ExceptionInformation
[1]);
908 dbg_printf("page fault");
910 case EXCEPTION_DATATYPE_MISALIGNMENT
:
911 dbg_printf("Alignment");
919 case STATUS_POSSIBLE_DEADLOCK
:
923 recaddr
.Mode
= AddrModeFlat
;
924 recaddr
.Offset
= rec
->ExceptionInformation
[0];
926 dbg_printf("wait failed on critical section ");
927 print_address(&recaddr
, FALSE
);
930 case EXCEPTION_WINE_STUB
:
932 char dll
[64], name
[256];
933 memory_get_string(dbg_curr_process
,
934 (void*)rec
->ExceptionInformation
[0], TRUE
, FALSE
,
936 if (HIWORD(rec
->ExceptionInformation
[1]))
937 memory_get_string(dbg_curr_process
,
938 (void*)rec
->ExceptionInformation
[1], TRUE
, FALSE
,
941 sprintf( name
, "%Id", rec
->ExceptionInformation
[1] );
942 dbg_printf("unimplemented function %s.%s called", dll
, name
);
945 case EXCEPTION_WINE_ASSERTION
:
946 dbg_printf("assertion failed");
948 case EXCEPTION_FLT_DENORMAL_OPERAND
:
949 dbg_printf("denormal float operand");
951 case EXCEPTION_FLT_DIVIDE_BY_ZERO
:
952 dbg_printf("divide by zero");
954 case EXCEPTION_FLT_INEXACT_RESULT
:
955 dbg_printf("inexact float result");
957 case EXCEPTION_FLT_INVALID_OPERATION
:
958 dbg_printf("invalid float operation");
960 case EXCEPTION_FLT_OVERFLOW
:
961 dbg_printf("floating point overflow");
963 case EXCEPTION_FLT_UNDERFLOW
:
964 dbg_printf("floating point underflow");
966 case EXCEPTION_FLT_STACK_CHECK
:
967 dbg_printf("floating point stack check");
969 case EXCEPTION_WINE_CXX_EXCEPTION
:
970 if(rec
->NumberParameters
== 3 && rec
->ExceptionInformation
[0] == EXCEPTION_WINE_CXX_FRAME_MAGIC
)
971 dbg_printf("C++ exception(object = 0x%0*Ix, type = 0x%0*Ix)",
972 ADDRWIDTH
, rec
->ExceptionInformation
[1], ADDRWIDTH
, rec
->ExceptionInformation
[2]);
973 else if(rec
->NumberParameters
== 4 && rec
->ExceptionInformation
[0] == EXCEPTION_WINE_CXX_FRAME_MAGIC
)
974 dbg_printf("C++ exception(object = %p, type = %p, base = %p)",
975 (void*)rec
->ExceptionInformation
[1], (void*)rec
->ExceptionInformation
[2],
976 (void*)rec
->ExceptionInformation
[3]);
978 dbg_printf("C++ exception with strange parameter count %ld or magic 0x%0*Ix",
979 rec
->NumberParameters
, ADDRWIDTH
, rec
->ExceptionInformation
[0]);
982 dbg_printf("0x%08lx", rec
->ExceptionCode
);
985 if (rec
->ExceptionFlags
& EH_STACK_INVALID
)
986 dbg_printf(", invalid program stack");
991 dbg_printf(" in %ld-bit code (%s)",
992 dbg_curr_process
->be_cpu
->pointer_size
* 8,
993 memory_offset_to_string(hexbuf
, addr
.Offset
, 0));
996 dbg_printf(" in vm86 code (%04x:%04x)", addr
.Segment
, (unsigned) addr
.Offset
);
999 dbg_printf(" in 16-bit code (%04x:%04x)", addr
.Segment
, (unsigned) addr
.Offset
);
1002 dbg_printf(" in segmented 32-bit code (%04x:%08x)", addr
.Segment
, (unsigned) addr
.Offset
);
1004 default: dbg_printf(" bad address");