1 /* Wine internal debugger
2 * Interface to Windows debugger API
3 * Copyright 2000-2004 Eric Pouech
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 #include "wine/port.h"
29 #include "wine/exception.h"
30 #include "wine/library.h"
32 #include "wine/debug.h"
37 * + allow winedbg in automatic mode to create a minidump (or add another option
39 * + set a mode where winedbg would start (postmortem debugging) from a minidump
41 * + we always assume the stack grows has an i386 (ie downwards)
43 * + enable back the limited output (depth of structure printing and number of
45 * + make the output as close as possible to what gdb does
46 * - symbol management:
47 * + symbol table loading is broken
48 * + in symbol_get_lvalue, we don't do any scoping (as C does) between local and
49 * global vars (we may need this to force some display for example). A solution
50 * would be always to return arrays with: local vars, global vars, thunks
52 * + some bits of internal types are missing (like type casts and the address
54 * + the type for an enum's value is always inferred as int (winedbg & dbghelp)
55 * + most of the code implies that sizeof(void*) = sizeof(int)
56 * + all computations should be made on long long
57 * o expr computations are in int:s
58 * o bitfield size is on a 4-bytes
60 * + set a better fix for gdb (proxy mode) than the step-mode hack
61 * + implement function call in debuggee
62 * + trampoline management is broken when getting 16 <=> 32 thunk destination
64 * + thunking of delayed imports doesn't work as expected (ie, when stepping,
65 * it currently stops at first insn with line number during the library
66 * loading). We should identify this (__wine_delay_import) and set a
67 * breakpoint instead of single stepping the library loading.
68 * + it's wrong to copy thread->step_over_bp into process->bp[0] (when
69 * we have a multi-thread debuggee). complete fix must include storing all
70 * thread's step-over bp in process-wide bp array, and not to handle bp
71 * when we have the wrong thread running into that bp
74 WINE_DEFAULT_DEBUG_CHANNEL(winedbg
);
76 struct dbg_process
* dbg_curr_process
= NULL
;
77 struct dbg_thread
* dbg_curr_thread
= NULL
;
81 int dbg_curr_frame
= 0;
82 BOOL dbg_interactiveP
= FALSE
;
83 static unsigned dbg_in_exception
= FALSE
;
84 static char* dbg_last_cmd_line
= NULL
;
86 static struct dbg_process
* dbg_process_list
= NULL
;
87 static enum {none_mode
= 0, winedbg_mode
, automatic_mode
, gdb_mode
} dbg_action_mode
;
89 struct dbg_internal_var dbg_internal_vars
[DBG_IV_LAST
];
90 const struct dbg_internal_var
* dbg_context_vars
;
91 static HANDLE dbg_houtput
;
93 void dbg_outputA(const char* buffer
, int len
)
96 WriteFile(dbg_houtput
, buffer
, len
, &w
, NULL
);
99 void dbg_outputW(const WCHAR
* buffer
, int len
)
104 /* do a serious Unicode to ANSI conversion
105 * FIXME: should CP_ACP be GetConsoleCP()?
107 newlen
= WideCharToMultiByte(CP_ACP
, 0, buffer
, len
, NULL
, 0, NULL
, NULL
);
110 if (!(ansi
= HeapAlloc(GetProcessHeap(), 0, newlen
))) return;
111 WideCharToMultiByte(CP_ACP
, 0, buffer
, len
, ansi
, newlen
, NULL
, NULL
);
112 dbg_outputA(ansi
, newlen
);
113 HeapFree(GetProcessHeap(), 0, ansi
);
117 int dbg_printf(const char* format
, ...)
119 static char buf
[4*1024];
123 va_start(valist
, format
);
124 len
= vsnprintf(buf
, sizeof(buf
), format
, valist
);
127 if (len
<= -1 || len
>= sizeof(buf
))
129 len
= sizeof(buf
) - 1;
131 buf
[len
- 1] = buf
[len
- 2] = buf
[len
- 3] = '.';
133 dbg_outputA(buf
, len
);
137 static unsigned dbg_load_internal_vars(void)
140 DWORD type
= REG_DWORD
;
142 DWORD count
= sizeof(val
);
144 struct dbg_internal_var
* div
= dbg_internal_vars
;
146 /* initializes internal vars table */
147 #define INTERNAL_VAR(_var,_val,_ref,_tid) \
148 div->val = _val; div->name = #_var; div->pval = _ref; \
149 div->typeid = _tid; div++;
153 if (RegCreateKeyA(HKEY_CURRENT_USER
, "Software\\Wine\\WineDbg", &hkey
))
155 WINE_ERR("Cannot create WineDbg key in registry\n");
159 for (i
= 0; i
< DBG_IV_LAST
; i
++)
161 if (!dbg_internal_vars
[i
].pval
)
163 if (!RegQueryValueEx(hkey
, dbg_internal_vars
[i
].name
, 0,
164 &type
, (LPSTR
)&val
, &count
))
165 dbg_internal_vars
[i
].val
= val
;
166 dbg_internal_vars
[i
].pval
= &dbg_internal_vars
[i
].val
;
170 /* set up the debug variables for the CPU context */
171 dbg_context_vars
= be_cpu
->init_registers(&dbg_context
);
175 static unsigned dbg_save_internal_vars(void)
180 if (RegCreateKeyA(HKEY_CURRENT_USER
, "Software\\Wine\\WineDbg", &hkey
))
182 WINE_ERR("Cannot create WineDbg key in registry\n");
186 for (i
= 0; i
< DBG_IV_LAST
; i
++)
188 /* FIXME: type should be infered from basic type -if any- of intvar */
189 if (dbg_internal_vars
[i
].pval
== &dbg_internal_vars
[i
].val
)
190 RegSetValueEx(hkey
, dbg_internal_vars
[i
].name
, 0,
191 REG_DWORD
, (const void*)dbg_internal_vars
[i
].pval
,
192 sizeof(*dbg_internal_vars
[i
].pval
));
198 const struct dbg_internal_var
* dbg_get_internal_var(const char* name
)
200 const struct dbg_internal_var
* div
;
202 for (div
= &dbg_internal_vars
[DBG_IV_LAST
- 1]; div
>= dbg_internal_vars
; div
--)
204 if (!strcmp(div
->name
, name
)) return div
;
206 for (div
= dbg_context_vars
; div
->name
; div
++)
208 if (!strcasecmp(div
->name
, name
)) return div
;
214 struct dbg_process
* dbg_get_process(DWORD pid
)
216 struct dbg_process
* p
;
218 for (p
= dbg_process_list
; p
; p
= p
->next
)
219 if (p
->pid
== pid
) break;
223 struct dbg_process
* dbg_add_process(DWORD pid
, HANDLE h
, const char* imageName
)
225 struct dbg_process
* p
;
227 if ((p
= dbg_get_process(pid
)))
231 WINE_ERR("Process (%lu) is already defined\n", pid
);
236 p
->imageName
= imageName
? strcpy(HeapAlloc(GetProcessHeap(), 0, strlen(imageName
) + 1), imageName
) : NULL
;
241 if (!(p
= HeapAlloc(GetProcessHeap(), 0, sizeof(struct dbg_process
)))) return NULL
;
244 p
->imageName
= imageName
? strcpy(HeapAlloc(GetProcessHeap(), 0, strlen(imageName
) + 1), imageName
) : NULL
;
246 p
->continue_on_first_exception
= FALSE
;
247 p
->next_bp
= 1; /* breakpoint 0 is reserved for step-over */
248 memset(p
->bp
, 0, sizeof(p
->bp
));
249 p
->delayed_bp
= NULL
;
250 p
->num_delayed_bp
= 0;
252 p
->next
= dbg_process_list
;
254 if (dbg_process_list
) dbg_process_list
->prev
= p
;
255 dbg_process_list
= p
;
259 void dbg_del_process(struct dbg_process
* p
)
263 while (p
->threads
) dbg_del_thread(p
->threads
);
265 for (i
= 0; i
< p
->num_delayed_bp
; i
++)
266 if (p
->delayed_bp
[i
].is_symbol
)
267 HeapFree(GetProcessHeap(), 0, p
->delayed_bp
[i
].u
.symbol
.name
);
269 HeapFree(GetProcessHeap(), 0, p
->delayed_bp
);
270 if (p
->prev
) p
->prev
->next
= p
->next
;
271 if (p
->next
) p
->next
->prev
= p
->prev
;
272 if (p
== dbg_process_list
) dbg_process_list
= p
->next
;
273 if (p
== dbg_curr_process
) dbg_curr_process
= NULL
;
274 HeapFree(GetProcessHeap(), 0, (char*)p
->imageName
);
275 HeapFree(GetProcessHeap(), 0, p
);
278 static void dbg_init_current_process(void)
282 struct mod_loader_info
285 IMAGEHLP_MODULE
* imh_mod
;
288 static BOOL CALLBACK
mod_loader_cb(PSTR mod_name
, DWORD base
, void* ctx
)
290 struct mod_loader_info
* mli
= (struct mod_loader_info
*)ctx
;
292 if (!strcmp(mod_name
, "<wine-loader>"))
294 if (SymGetModuleInfo(mli
->handle
, base
, mli
->imh_mod
))
295 return FALSE
; /* stop enum */
300 BOOL
dbg_get_debuggee_info(HANDLE hProcess
, IMAGEHLP_MODULE
* imh_mod
)
302 struct mod_loader_info mli
;
305 /* this will resynchronize builtin dbghelp's internal ELF module list */
306 SymLoadModule(hProcess
, 0, 0, 0, 0, 0);
307 mli
.handle
= hProcess
;
308 mli
.imh_mod
= imh_mod
;
309 imh_mod
->SizeOfStruct
= sizeof(*imh_mod
);
310 imh_mod
->BaseOfImage
= 0;
311 /* this is a wine specific options to return also ELF modules in the
314 SymSetOptions((opt
= SymGetOptions()) | 0x40000000);
315 SymEnumerateModules(hProcess
, mod_loader_cb
, (void*)&mli
);
318 return imh_mod
->BaseOfImage
!= 0;
321 struct dbg_thread
* dbg_get_thread(struct dbg_process
* p
, DWORD tid
)
323 struct dbg_thread
* t
;
326 for (t
= p
->threads
; t
; t
= t
->next
)
327 if (t
->tid
== tid
) break;
331 struct dbg_thread
* dbg_add_thread(struct dbg_process
* p
, DWORD tid
,
334 struct dbg_thread
* t
= HeapAlloc(GetProcessHeap(), 0, sizeof(struct dbg_thread
));
343 t
->exec_mode
= dbg_exec_cont
;
345 t
->step_over_bp
.enabled
= FALSE
;
346 t
->step_over_bp
.refcount
= 0;
348 snprintf(t
->name
, sizeof(t
->name
), "0x%08lx", tid
);
350 t
->next
= p
->threads
;
352 if (p
->threads
) p
->threads
->prev
= t
;
358 static void dbg_init_current_thread(void* start
)
362 if (dbg_curr_process
->threads
&&
363 !dbg_curr_process
->threads
->next
&& /* first thread ? */
364 DBG_IVAR(BreakAllThreadsStartup
))
368 break_set_xpoints(FALSE
);
369 addr
.Mode
= AddrModeFlat
;
370 addr
.Offset
= (DWORD
)start
;
371 break_add_break(&addr
, TRUE
);
372 break_set_xpoints(TRUE
);
377 void dbg_del_thread(struct dbg_thread
* t
)
379 if (t
->prev
) t
->prev
->next
= t
->next
;
380 if (t
->next
) t
->next
->prev
= t
->prev
;
381 if (t
== t
->process
->threads
) t
->process
->threads
= t
->next
;
382 if (t
== dbg_curr_thread
) dbg_curr_thread
= NULL
;
383 HeapFree(GetProcessHeap(), 0, t
);
386 static unsigned dbg_handle_debug_event(DEBUG_EVENT
* de
);
388 /******************************************************************
389 * dbg_attach_debuggee
391 * Sets the debuggee to <pid>
392 * cofe instructs winedbg what to do when first exception is received
393 * (break=FALSE, continue=TRUE)
394 * wfe is set to TRUE if dbg_attach_debuggee should also proceed with all debug events
395 * until the first exception is received (aka: attach to an already running process)
397 BOOL
dbg_attach_debuggee(DWORD pid
, BOOL cofe
, BOOL wfe
)
401 if (!(dbg_curr_process
= dbg_add_process(pid
, 0, NULL
))) return FALSE
;
403 if (!DebugActiveProcess(pid
))
405 dbg_printf("Can't attach process %lx: error %ld\n", pid
, GetLastError());
406 dbg_del_process(dbg_curr_process
);
409 dbg_curr_process
->continue_on_first_exception
= cofe
;
411 if (wfe
) /* shall we proceed all debug events until we get an exception ? */
413 dbg_interactiveP
= FALSE
;
414 while (dbg_curr_process
&& WaitForDebugEvent(&de
, INFINITE
))
416 if (dbg_handle_debug_event(&de
)) break;
418 if (dbg_curr_process
) dbg_interactiveP
= TRUE
;
423 BOOL
dbg_detach_debuggee(void)
425 /* remove all set breakpoints in debuggee code */
426 break_set_xpoints(FALSE
);
427 /* needed for single stepping (ugly).
428 * should this be handled inside the server ???
430 be_cpu
->single_step(&dbg_context
, FALSE
);
431 SetThreadContext(dbg_curr_thread
->handle
, &dbg_context
);
432 if (dbg_in_exception
)
433 ContinueDebugEvent(dbg_curr_pid
, dbg_curr_tid
, DBG_CONTINUE
);
434 if (!DebugActiveProcessStop(dbg_curr_pid
)) return FALSE
;
435 dbg_del_process(dbg_curr_process
);
440 static unsigned dbg_fetch_context(void)
442 dbg_context
.ContextFlags
= CONTEXT_CONTROL
444 #ifdef CONTEXT_SEGMENTS
447 #ifdef CONTEXT_DEBUG_REGISTERS
448 | CONTEXT_DEBUG_REGISTERS
451 if (!GetThreadContext(dbg_curr_thread
->handle
, &dbg_context
))
453 WINE_WARN("Can't get thread's context\n");
459 static unsigned dbg_exception_prolog(BOOL is_debug
, DWORD code
)
464 dbg_in_exception
= TRUE
;
465 memory_get_current_pc(&addr
);
466 break_suspend_execution();
472 case AddrModeFlat
: dbg_printf(" in 32-bit code (0x%08lx)", addr
.Offset
); break;
473 case AddrModeReal
: dbg_printf(" in vm86 code (%04x:%04lx)", addr
.Segment
, addr
.Offset
); break;
474 case AddrMode1616
: dbg_printf(" in 16-bit code (%04x:%04lx)", addr
.Segment
, addr
.Offset
); break;
475 default: dbg_printf(" bad address");
480 /* this will resynchronize builtin dbghelp's internal ELF module list */
481 SymLoadModule(dbg_curr_process
->handle
, 0, 0, 0, 0, 0);
484 * Do a quiet backtrace so that we have an idea of what the situation
485 * is WRT the source files.
487 stack_backtrace(dbg_curr_tid
, FALSE
);
489 break_should_continue(&addr
, code
, &dbg_curr_thread
->exec_count
, &is_break
))
492 if (addr
.Mode
!= dbg_curr_thread
->addr_mode
)
494 const char* name
= NULL
;
498 case AddrMode1616
: name
= "16 bit"; break;
499 case AddrMode1632
: name
= "X?X??X"; break;
500 case AddrModeReal
: name
= "vm86"; break;
501 case AddrModeFlat
: name
= "32 bit"; break;
504 dbg_printf("In %s mode.\n", name
);
505 dbg_curr_thread
->addr_mode
= addr
.Mode
;
511 /* This is a real crash, dump some info */
512 be_cpu
->print_context(dbg_curr_thread
->handle
, &dbg_context
);
514 be_cpu
->print_segment_info(dbg_curr_thread
->handle
, &dbg_context
);
515 stack_backtrace(dbg_curr_tid
, TRUE
);
517 if (!is_debug
|| is_break
||
518 dbg_curr_thread
->exec_mode
== dbg_exec_step_over_insn
||
519 dbg_curr_thread
->exec_mode
== dbg_exec_step_into_insn
)
522 /* Show where we crashed */
524 memory_disasm_one_insn(&tmp
);
526 source_list_from_addr(&addr
, 0);
531 static void dbg_exception_epilog(void)
533 break_restart_execution(dbg_curr_thread
->exec_count
);
535 * This will have gotten absorbed into the breakpoint info
536 * if it was used. Otherwise it would have been ignored.
537 * In any case, we don't mess with it any more.
539 if (dbg_curr_thread
->exec_mode
== dbg_exec_cont
)
540 dbg_curr_thread
->exec_count
= 0;
541 dbg_in_exception
= FALSE
;
544 static DWORD
dbg_handle_exception(EXCEPTION_RECORD
* rec
, BOOL first_chance
)
546 BOOL is_debug
= FALSE
;
547 THREADNAME_INFO
* pThreadName
;
548 struct dbg_thread
* pThread
;
550 assert(dbg_curr_thread
);
552 WINE_TRACE("exception=%lx first_chance=%c\n",
553 rec
->ExceptionCode
, first_chance
? 'Y' : 'N');
555 switch (rec
->ExceptionCode
)
557 case EXCEPTION_BREAKPOINT
:
558 case EXCEPTION_SINGLE_STEP
:
561 case EXCEPTION_NAME_THREAD
:
562 pThreadName
= (THREADNAME_INFO
*)(rec
->ExceptionInformation
);
563 if (pThreadName
->dwThreadID
== -1)
564 pThread
= dbg_curr_thread
;
566 pThread
= dbg_get_thread(dbg_curr_process
, pThreadName
->dwThreadID
);
568 if (dbg_read_memory(pThreadName
->szName
, pThread
->name
, 9))
569 dbg_printf("Thread ID=0x%lx renamed using MS VC6 extension (name==\"%s\")\n",
570 pThread
->tid
, pThread
->name
);
574 if (first_chance
&& !is_debug
&& !DBG_IVAR(BreakOnFirstChance
))
576 /* pass exception to program except for debug exceptions */
577 return DBG_EXCEPTION_NOT_HANDLED
;
582 /* print some infos */
584 first_chance
? "First chance exception" : "Unhandled exception");
585 switch (rec
->ExceptionCode
)
587 case EXCEPTION_INT_DIVIDE_BY_ZERO
:
588 dbg_printf("divide by zero");
590 case EXCEPTION_INT_OVERFLOW
:
591 dbg_printf("overflow");
593 case EXCEPTION_ARRAY_BOUNDS_EXCEEDED
:
594 dbg_printf("array bounds");
596 case EXCEPTION_ILLEGAL_INSTRUCTION
:
597 dbg_printf("illegal instruction");
599 case EXCEPTION_STACK_OVERFLOW
:
600 dbg_printf("stack overflow");
602 case EXCEPTION_PRIV_INSTRUCTION
:
603 dbg_printf("privileged instruction");
605 case EXCEPTION_ACCESS_VIOLATION
:
606 if (rec
->NumberParameters
== 2)
607 dbg_printf("page fault on %s access to 0x%08lx",
608 rec
->ExceptionInformation
[0] ? "write" : "read",
609 rec
->ExceptionInformation
[1]);
611 dbg_printf("page fault");
613 case EXCEPTION_DATATYPE_MISALIGNMENT
:
614 dbg_printf("Alignment");
622 case STATUS_POSSIBLE_DEADLOCK
:
626 addr
.Mode
= AddrModeFlat
;
627 addr
.Offset
= rec
->ExceptionInformation
[0];
629 dbg_printf("wait failed on critical section ");
630 print_address(&addr
, FALSE
);
632 if (!DBG_IVAR(BreakOnCritSectTimeOut
))
635 return DBG_EXCEPTION_NOT_HANDLED
;
638 case EXCEPTION_WINE_STUB
:
640 char dll
[32], name
[64];
641 memory_get_string(dbg_curr_process
->handle
,
642 (void*)rec
->ExceptionInformation
[0], TRUE
, FALSE
,
644 if (HIWORD(rec
->ExceptionInformation
[1]))
645 memory_get_string(dbg_curr_process
->handle
,
646 (void*)rec
->ExceptionInformation
[1], TRUE
, FALSE
,
649 sprintf( name
, "%ld", rec
->ExceptionInformation
[1] );
650 dbg_printf("unimplemented function %s.%s called", dll
, name
);
653 case EXCEPTION_WINE_ASSERTION
:
654 dbg_printf("assertion failed");
656 case EXCEPTION_VM86_INTx
:
657 dbg_printf("interrupt %02lx in vm86 mode", rec
->ExceptionInformation
[0]);
659 case EXCEPTION_VM86_STI
:
660 dbg_printf("sti in vm86 mode");
662 case EXCEPTION_VM86_PICRETURN
:
663 dbg_printf("PIC return in vm86 mode");
665 case EXCEPTION_FLT_DENORMAL_OPERAND
:
666 dbg_printf("denormal float operand");
668 case EXCEPTION_FLT_DIVIDE_BY_ZERO
:
669 dbg_printf("divide by zero");
671 case EXCEPTION_FLT_INEXACT_RESULT
:
672 dbg_printf("inexact float result");
674 case EXCEPTION_FLT_INVALID_OPERATION
:
675 dbg_printf("invalid float operation");
677 case EXCEPTION_FLT_OVERFLOW
:
678 dbg_printf("floating pointer overflow");
680 case EXCEPTION_FLT_UNDERFLOW
:
681 dbg_printf("floating pointer underflow");
683 case EXCEPTION_FLT_STACK_CHECK
:
684 dbg_printf("floating point stack check");
687 dbg_printf("0x%08lx", rec
->ExceptionCode
);
692 if (dbg_action_mode
== automatic_mode
)
694 dbg_exception_prolog(is_debug
, rec
->ExceptionCode
);
695 dbg_exception_epilog();
696 return 0; /* terminate execution */
699 if (dbg_exception_prolog(is_debug
, rec
->ExceptionCode
))
701 dbg_interactiveP
= TRUE
;
704 dbg_exception_epilog();
709 static unsigned dbg_handle_debug_event(DEBUG_EVENT
* de
)
712 DWORD cont
= DBG_CONTINUE
;
714 dbg_curr_pid
= de
->dwProcessId
;
715 dbg_curr_tid
= de
->dwThreadId
;
717 if ((dbg_curr_process
= dbg_get_process(de
->dwProcessId
)) != NULL
)
718 dbg_curr_thread
= dbg_get_thread(dbg_curr_process
, de
->dwThreadId
);
720 dbg_curr_thread
= NULL
;
722 switch (de
->dwDebugEventCode
)
724 case EXCEPTION_DEBUG_EVENT
:
725 if (!dbg_curr_thread
)
727 WINE_ERR("%08lx:%08lx: not a registered process or thread (perhaps a 16 bit one ?)\n",
728 de
->dwProcessId
, de
->dwThreadId
);
732 WINE_TRACE("%08lx:%08lx: exception code=%08lx\n",
733 de
->dwProcessId
, de
->dwThreadId
,
734 de
->u
.Exception
.ExceptionRecord
.ExceptionCode
);
736 if (dbg_curr_process
->continue_on_first_exception
)
738 dbg_curr_process
->continue_on_first_exception
= FALSE
;
739 if (!DBG_IVAR(BreakOnAttach
)) break;
741 if (dbg_fetch_context())
743 cont
= dbg_handle_exception(&de
->u
.Exception
.ExceptionRecord
,
744 de
->u
.Exception
.dwFirstChance
);
745 if (cont
&& dbg_curr_thread
)
747 SetThreadContext(dbg_curr_thread
->handle
, &dbg_context
);
752 case CREATE_PROCESS_DEBUG_EVENT
:
753 memory_get_string_indirect(de
->u
.CreateProcessInfo
.hProcess
,
754 de
->u
.CreateProcessInfo
.lpImageName
,
755 de
->u
.CreateProcessInfo
.fUnicode
,
756 buffer
, sizeof(buffer
));
757 WINE_TRACE("%08lx:%08lx: create process '%s'/%p @%08lx (%ld<%ld>)\n",
758 de
->dwProcessId
, de
->dwThreadId
,
759 buffer
, de
->u
.CreateProcessInfo
.lpImageName
,
760 (unsigned long)(void*)de
->u
.CreateProcessInfo
.lpStartAddress
,
761 de
->u
.CreateProcessInfo
.dwDebugInfoFileOffset
,
762 de
->u
.CreateProcessInfo
.nDebugInfoSize
);
764 dbg_curr_process
= dbg_add_process(de
->dwProcessId
,
765 de
->u
.CreateProcessInfo
.hProcess
,
766 buffer
[0] ? buffer
: "<Debugged Process>");
767 if (dbg_curr_process
== NULL
)
769 WINE_ERR("Couldn't create process\n");
772 if (!SymInitialize(dbg_curr_process
->handle
, NULL
, TRUE
))
773 dbg_printf("Couldn't initiate DbgHelp\n");
775 WINE_TRACE("%08lx:%08lx: create thread I @%08lx\n",
776 de
->dwProcessId
, de
->dwThreadId
,
777 (unsigned long)(void*)de
->u
.CreateProcessInfo
.lpStartAddress
);
779 dbg_curr_thread
= dbg_add_thread(dbg_curr_process
,
781 de
->u
.CreateProcessInfo
.hThread
,
782 de
->u
.CreateProcessInfo
.lpThreadLocalBase
);
783 if (!dbg_curr_thread
)
785 WINE_ERR("Couldn't create thread\n");
788 dbg_init_current_process();
789 dbg_init_current_thread(de
->u
.CreateProcessInfo
.lpStartAddress
);
792 case EXIT_PROCESS_DEBUG_EVENT
:
793 WINE_TRACE("%08lx:%08lx: exit process (%ld)\n",
794 de
->dwProcessId
, de
->dwThreadId
, de
->u
.ExitProcess
.dwExitCode
);
796 if (dbg_curr_process
== NULL
)
798 WINE_ERR("Unknown process\n");
801 if (!SymCleanup(dbg_curr_process
->handle
))
802 dbg_printf("Couldn't initiate DbgHelp\n");
804 break_set_xpoints(FALSE
);
805 /* kill last thread */
806 dbg_del_thread(dbg_curr_process
->threads
);
807 dbg_del_process(dbg_curr_process
);
809 dbg_printf("Process of pid=0x%08lx has terminated\n", dbg_curr_pid
);
812 case CREATE_THREAD_DEBUG_EVENT
:
813 WINE_TRACE("%08lx:%08lx: create thread D @%08lx\n",
814 de
->dwProcessId
, de
->dwThreadId
,
815 (unsigned long)(void*)de
->u
.CreateThread
.lpStartAddress
);
817 if (dbg_curr_process
== NULL
)
819 WINE_ERR("Unknown process\n");
822 if (dbg_get_thread(dbg_curr_process
, de
->dwThreadId
) != NULL
)
824 WINE_TRACE("Thread already listed, skipping\n");
828 dbg_curr_thread
= dbg_add_thread(dbg_curr_process
,
830 de
->u
.CreateThread
.hThread
,
831 de
->u
.CreateThread
.lpThreadLocalBase
);
832 if (!dbg_curr_thread
)
834 WINE_ERR("Couldn't create thread\n");
837 dbg_init_current_thread(de
->u
.CreateThread
.lpStartAddress
);
840 case EXIT_THREAD_DEBUG_EVENT
:
841 WINE_TRACE("%08lx:%08lx: exit thread (%ld)\n",
842 de
->dwProcessId
, de
->dwThreadId
, de
->u
.ExitThread
.dwExitCode
);
844 if (dbg_curr_thread
== NULL
)
846 WINE_ERR("Unknown thread\n");
849 /* FIXME: remove break point set on thread startup */
850 dbg_del_thread(dbg_curr_thread
);
853 case LOAD_DLL_DEBUG_EVENT
:
854 if (dbg_curr_thread
== NULL
)
856 WINE_ERR("Unknown thread\n");
859 memory_get_string_indirect(dbg_curr_process
->handle
,
860 de
->u
.LoadDll
.lpImageName
,
861 de
->u
.LoadDll
.fUnicode
,
862 buffer
, sizeof(buffer
));
864 WINE_TRACE("%08lx:%08lx: loads DLL %s @%08lx (%ld<%ld>)\n",
865 de
->dwProcessId
, de
->dwThreadId
,
866 buffer
, (unsigned long)de
->u
.LoadDll
.lpBaseOfDll
,
867 de
->u
.LoadDll
.dwDebugInfoFileOffset
,
868 de
->u
.LoadDll
.nDebugInfoSize
);
870 SymLoadModule(dbg_curr_process
->handle
, de
->u
.LoadDll
.hFile
, buffer
, NULL
,
871 (unsigned long)de
->u
.LoadDll
.lpBaseOfDll
, 0);
872 break_set_xpoints(FALSE
);
873 break_check_delayed_bp();
874 break_set_xpoints(TRUE
);
875 if (DBG_IVAR(BreakOnDllLoad
))
877 dbg_printf("Stopping on DLL %s loading at 0x%08lx\n",
878 buffer
, (unsigned long)de
->u
.LoadDll
.lpBaseOfDll
);
879 if (dbg_fetch_context()) cont
= 0;
883 case UNLOAD_DLL_DEBUG_EVENT
:
884 WINE_TRACE("%08lx:%08lx: unload DLL @%08lx\n",
885 de
->dwProcessId
, de
->dwThreadId
,
886 (unsigned long)de
->u
.UnloadDll
.lpBaseOfDll
);
887 break_delete_xpoints_from_module((unsigned long)de
->u
.UnloadDll
.lpBaseOfDll
);
888 SymUnloadModule(dbg_curr_process
->handle
,
889 (unsigned long)de
->u
.UnloadDll
.lpBaseOfDll
);
892 case OUTPUT_DEBUG_STRING_EVENT
:
893 if (dbg_curr_thread
== NULL
)
895 WINE_ERR("Unknown thread\n");
899 memory_get_string(dbg_curr_process
->handle
,
900 de
->u
.DebugString
.lpDebugStringData
, TRUE
,
901 de
->u
.DebugString
.fUnicode
, buffer
, sizeof(buffer
));
902 WINE_TRACE("%08lx:%08lx: output debug string (%s)\n",
903 de
->dwProcessId
, de
->dwThreadId
, buffer
);
907 WINE_TRACE("%08lx:%08lx: rip error=%ld type=%ld\n",
908 de
->dwProcessId
, de
->dwThreadId
, de
->u
.RipInfo
.dwError
,
909 de
->u
.RipInfo
.dwType
);
913 WINE_TRACE("%08lx:%08lx: unknown event (%ld)\n",
914 de
->dwProcessId
, de
->dwThreadId
, de
->dwDebugEventCode
);
916 if (!cont
) return TRUE
; /* stop execution */
917 ContinueDebugEvent(de
->dwProcessId
, de
->dwThreadId
, cont
);
918 return FALSE
; /* continue execution */
921 static void dbg_resume_debuggee(DWORD cont
)
923 if (dbg_in_exception
)
927 dbg_exception_epilog();
928 memory_get_current_pc(&addr
);
929 WINE_TRACE("Exiting debugger PC=0x%lx mode=%d count=%d\n",
930 addr
.Offset
, dbg_curr_thread
->exec_mode
,
931 dbg_curr_thread
->exec_count
);
934 if (!SetThreadContext(dbg_curr_thread
->handle
, &dbg_context
))
935 dbg_printf("Cannot set ctx on %lu\n", dbg_curr_tid
);
938 dbg_interactiveP
= FALSE
;
939 if (!ContinueDebugEvent(dbg_curr_pid
, dbg_curr_tid
, cont
))
940 dbg_printf("Cannot continue on %lu (%lu)\n", dbg_curr_tid
, cont
);
943 void dbg_wait_next_exception(DWORD cont
, int count
, int mode
)
948 if (cont
== DBG_CONTINUE
)
950 dbg_curr_thread
->exec_count
= count
;
951 dbg_curr_thread
->exec_mode
= mode
;
953 dbg_resume_debuggee(cont
);
955 while (dbg_curr_process
&& WaitForDebugEvent(&de
, INFINITE
))
957 if (dbg_handle_debug_event(&de
)) break;
959 if (!dbg_curr_process
) return;
960 dbg_interactiveP
= TRUE
;
962 memory_get_current_pc(&addr
);
963 WINE_TRACE("Entering debugger PC=0x%lx mode=%d count=%d\n",
964 addr
.Offset
, dbg_curr_thread
->exec_mode
,
965 dbg_curr_thread
->exec_count
);
968 static unsigned dbg_main_loop(void)
972 if (dbg_curr_process
)
973 dbg_printf("WineDbg starting on pid 0x%lx\n", dbg_curr_pid
);
975 /* wait for first exception */
976 while (WaitForDebugEvent(&de
, INFINITE
))
978 if (dbg_handle_debug_event(&de
)) break;
980 switch (dbg_action_mode
)
983 /* print some extra information */
984 dbg_printf("Modules:\n");
985 info_win32_module(0); /* print all modules */
986 dbg_printf("Threads:\n");
987 info_win32_threads();
990 dbg_interactiveP
= TRUE
;
993 dbg_printf("WineDbg terminated on pid 0x%lx\n", dbg_curr_pid
);
998 static unsigned dbg_start_debuggee(LPSTR cmdLine
)
1000 PROCESS_INFORMATION info
;
1001 STARTUPINFOA startup
;
1003 memset(&startup
, 0, sizeof(startup
));
1004 startup
.cb
= sizeof(startup
);
1005 startup
.dwFlags
= STARTF_USESHOWWINDOW
;
1006 startup
.wShowWindow
= SW_SHOWNORMAL
;
1008 /* FIXME: shouldn't need the CREATE_NEW_CONSOLE, but as usual CUI:s need it
1011 if (!CreateProcess(NULL
, cmdLine
, NULL
, NULL
,
1013 DEBUG_PROCESS
|DEBUG_ONLY_THIS_PROCESS
|CREATE_NEW_CONSOLE
,
1014 NULL
, NULL
, &startup
, &info
))
1016 dbg_printf("Couldn't start process '%s'\n", cmdLine
);
1019 if (!info
.dwProcessId
)
1021 /* this happens when the program being run is not a Wine binary
1022 * (for example, a shell wrapper around a WineLib app)
1024 /* Current fix: list running processes and let the user attach
1025 * to one of them (sic)
1026 * FIXME: implement a real fix => grab the process (from the
1027 * running processes) from its name
1029 dbg_printf("Debuggee has been started (%s)\n"
1030 "But WineDbg isn't attached to it. Maybe you're trying to debug a winelib wrapper ??\n"
1031 "Try to attach to one of those processes:\n", cmdLine
);
1032 /* FIXME: (HACK) we need some time before the wrapper executes the winelib app */
1034 info_win32_processes();
1037 dbg_curr_pid
= info
.dwProcessId
;
1038 if (!(dbg_curr_process
= dbg_add_process(dbg_curr_pid
, 0, NULL
))) return FALSE
;
1043 void dbg_run_debuggee(const char* args
)
1047 WINE_FIXME("Re-running current program with %s as args is broken\n", args
);
1054 if (!dbg_last_cmd_line
)
1056 dbg_printf("Cannot find previously used command line.\n");
1059 dbg_start_debuggee(dbg_last_cmd_line
);
1060 while (dbg_curr_process
&& WaitForDebugEvent(&de
, INFINITE
))
1062 if (dbg_handle_debug_event(&de
)) break;
1064 source_list_from_addr(NULL
, 0);
1068 BOOL
dbg_interrupt_debuggee(void)
1070 if (!dbg_process_list
) return FALSE
;
1071 /* FIXME: since we likely have a single process, signal the first process
1074 if (dbg_process_list
->next
) dbg_printf("Ctrl-C: only stopping the first process\n");
1075 else dbg_printf("Ctrl-C: stopping debuggee\n");
1076 dbg_process_list
->continue_on_first_exception
= FALSE
;
1077 return DebugBreakProcess(dbg_process_list
->handle
);
1080 static BOOL WINAPI
ctrl_c_handler(DWORD dwCtrlType
)
1082 if (dwCtrlType
== CTRL_C_EVENT
)
1084 return dbg_interrupt_debuggee();
1089 static void dbg_init_console(void)
1091 /* set our control-C handler */
1092 SetConsoleCtrlHandler(ctrl_c_handler
, TRUE
);
1094 /* set our own title */
1095 SetConsoleTitle("Wine Debugger");
1098 static int dbg_winedbg_usage(void)
1100 dbg_printf("Usage: winedbg [--auto] [--gdb] cmdline\n");
1104 struct backend_cpu
* be_cpu
;
1106 extern struct backend_cpu be_i386
;
1108 extern struct backend_cpu be_ppc
;
1110 extern struct backend_cpu be_alpha
;
1115 int main(int argc
, char** argv
)
1118 unsigned gdb_flags
= 0;
1129 /* Initialize the output */
1130 dbg_houtput
= GetStdHandle(STD_OUTPUT_HANDLE
);
1132 /* Initialize internal vars */
1133 if (!dbg_load_internal_vars()) return -1;
1136 while (argc
> 1 && argv
[1][0] == '-')
1138 if (!strcmp(argv
[1], "--command"))
1141 arg_command
= HeapAlloc(GetProcessHeap(), 0, strlen(argv
[1])+2);
1142 strcpy(arg_command
, argv
[1]);
1143 strcat(arg_command
, "\n");
1147 if (!strcmp(argv
[1], "--auto"))
1149 if (dbg_action_mode
!= none_mode
) return dbg_winedbg_usage();
1150 dbg_action_mode
= automatic_mode
;
1151 /* force some internal variables */
1152 DBG_IVAR(BreakOnDllLoad
) = 0;
1154 dbg_houtput
= GetStdHandle(STD_ERROR_HANDLE
);
1157 if (!strcmp(argv
[1], "--gdb"))
1159 if (dbg_action_mode
!= none_mode
) return dbg_winedbg_usage();
1160 dbg_action_mode
= gdb_mode
;
1164 if (strcmp(argv
[1], "--no-start") == 0 && dbg_action_mode
== gdb_mode
)
1167 argc
--; argv
++; /* as we don't use argv[0] */
1170 if (strcmp(argv
[1], "--with-xterm") == 0 && dbg_action_mode
== gdb_mode
)
1173 argc
--; argv
++; /* as we don't use argv[0] */
1176 return dbg_winedbg_usage();
1179 if (dbg_action_mode
== none_mode
) dbg_action_mode
= winedbg_mode
;
1181 /* try the form <myself> pid */
1182 if (dbg_curr_pid
== 0 && argc
== 2)
1186 dbg_curr_pid
= strtol(argv
[1], &ptr
, 10);
1187 if (dbg_curr_pid
== 0 || ptr
!= argv
[1] + strlen(argv
[1]) ||
1188 !dbg_attach_debuggee(dbg_curr_pid
, dbg_action_mode
!= gdb_mode
, FALSE
))
1192 /* try the form <myself> pid evt (Win32 JIT debugger) */
1193 if (dbg_curr_pid
== 0 && argc
== 3)
1199 if ((pid
= strtol(argv
[1], &ptr
, 10)) != 0 && ptr
!= NULL
&&
1200 (hEvent
= (HANDLE
)strtol(argv
[2], &ptr
, 10)) != 0 && ptr
!= NULL
)
1202 if (!dbg_attach_debuggee(pid
, TRUE
, FALSE
))
1204 /* don't care about result */
1208 if (!SetEvent(hEvent
))
1210 WINE_ERR("Invalid event handle: %p\n", hEvent
);
1213 CloseHandle(hEvent
);
1218 if (dbg_curr_pid
== 0 && argc
> 1)
1223 if (!(cmdLine
= HeapAlloc(GetProcessHeap(), 0, len
= 1))) goto oom_leave
;
1226 for (i
= 1; i
< argc
; i
++)
1228 len
+= strlen(argv
[i
]) + 1;
1229 if (!(cmdLine
= HeapReAlloc(GetProcessHeap(), 0, cmdLine
, len
)))
1231 strcat(cmdLine
, argv
[i
]);
1232 cmdLine
[len
- 2] = ' ';
1233 cmdLine
[len
- 1] = '\0';
1236 if (!dbg_start_debuggee(cmdLine
))
1238 dbg_printf("Couldn't start process '%s'\n", cmdLine
);
1241 dbg_last_cmd_line
= cmdLine
;
1243 /* don't save local vars in gdb mode */
1244 if (dbg_action_mode
== gdb_mode
&& dbg_curr_pid
)
1245 return gdb_remote(gdb_flags
);
1249 SymSetOptions(SymGetOptions() |
1250 SYMOPT_LOAD_LINES
| SYMOPT_DEFERRED_LOADS
| SYMOPT_AUTO_PUBLICS
);
1252 retv
= dbg_main_loop();
1253 /* don't save modified variables in auto mode */
1254 if (dbg_action_mode
!= automatic_mode
) dbg_save_internal_vars();
1260 dbg_printf("Out of memory\n");