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
)
95 WriteFile(dbg_houtput
, buffer
, len
, NULL
, NULL
);
98 void dbg_outputW(const WCHAR
* buffer
, int len
)
103 /* do a serious Unicode to ANSI conversion
104 * FIXME: should CP_ACP be GetConsoleCP()?
106 newlen
= WideCharToMultiByte(CP_ACP
, 0, buffer
, len
, NULL
, 0, NULL
, NULL
);
109 if (!(ansi
= HeapAlloc(GetProcessHeap(), 0, newlen
))) return;
110 WideCharToMultiByte(CP_ACP
, 0, buffer
, len
, ansi
, newlen
, NULL
, NULL
);
111 dbg_outputA(ansi
, newlen
);
112 HeapFree(GetProcessHeap(), 0, ansi
);
116 int dbg_printf(const char* format
, ...)
118 static char buf
[4*1024];
122 va_start(valist
, format
);
123 len
= vsnprintf(buf
, sizeof(buf
), format
, valist
);
126 if (len
<= -1 || len
>= sizeof(buf
))
128 len
= sizeof(buf
) - 1;
130 buf
[len
- 1] = buf
[len
- 2] = buf
[len
- 3] = '.';
132 dbg_outputA(buf
, len
);
136 static unsigned dbg_load_internal_vars(void)
139 DWORD type
= REG_DWORD
;
141 DWORD count
= sizeof(val
);
143 struct dbg_internal_var
* div
= dbg_internal_vars
;
145 /* initializes internal vars table */
146 #define INTERNAL_VAR(_var,_val,_ref,_tid) \
147 div->val = _val; div->name = #_var; div->pval = _ref; \
148 div->typeid = _tid; div++;
152 if (RegCreateKeyA(HKEY_CURRENT_USER
, "Software\\Wine\\WineDbg", &hkey
))
154 WINE_ERR("Cannot create WineDbg key in registry\n");
158 for (i
= 0; i
< DBG_IV_LAST
; i
++)
160 if (!dbg_internal_vars
[i
].pval
)
162 if (!RegQueryValueEx(hkey
, dbg_internal_vars
[i
].name
, 0,
163 &type
, (LPSTR
)&val
, &count
))
164 dbg_internal_vars
[i
].val
= val
;
165 dbg_internal_vars
[i
].pval
= &dbg_internal_vars
[i
].val
;
169 /* set up the debug variables for the CPU context */
170 dbg_context_vars
= be_cpu
->init_registers(&dbg_context
);
174 static unsigned dbg_save_internal_vars(void)
179 if (RegCreateKeyA(HKEY_CURRENT_USER
, "Software\\Wine\\WineDbg", &hkey
))
181 WINE_ERR("Cannot create WineDbg key in registry\n");
185 for (i
= 0; i
< DBG_IV_LAST
; i
++)
187 /* FIXME: type should be infered from basic type -if any- of intvar */
188 if (dbg_internal_vars
[i
].pval
== &dbg_internal_vars
[i
].val
)
189 RegSetValueEx(hkey
, dbg_internal_vars
[i
].name
, 0,
190 REG_DWORD
, (const void*)dbg_internal_vars
[i
].pval
,
191 sizeof(*dbg_internal_vars
[i
].pval
));
197 const struct dbg_internal_var
* dbg_get_internal_var(const char* name
)
199 const struct dbg_internal_var
* div
;
201 for (div
= &dbg_internal_vars
[DBG_IV_LAST
- 1]; div
>= dbg_internal_vars
; div
--)
203 if (!strcmp(div
->name
, name
)) return div
;
205 for (div
= dbg_context_vars
; div
->name
; div
++)
207 if (!strcasecmp(div
->name
, name
)) return div
;
213 struct dbg_process
* dbg_get_process(DWORD pid
)
215 struct dbg_process
* p
;
217 for (p
= dbg_process_list
; p
; p
= p
->next
)
218 if (p
->pid
== pid
) break;
222 struct dbg_process
* dbg_add_process(DWORD pid
, HANDLE h
, const char* imageName
)
224 struct dbg_process
* p
;
226 if ((p
= dbg_get_process(pid
)))
230 WINE_ERR("Process (%lu) is already defined\n", pid
);
235 p
->imageName
= imageName
? strcpy(HeapAlloc(GetProcessHeap(), 0, strlen(imageName
) + 1), imageName
) : NULL
;
240 if (!(p
= HeapAlloc(GetProcessHeap(), 0, sizeof(struct dbg_process
)))) return NULL
;
243 p
->imageName
= imageName
? strcpy(HeapAlloc(GetProcessHeap(), 0, strlen(imageName
) + 1), imageName
) : NULL
;
245 p
->continue_on_first_exception
= FALSE
;
246 p
->next_bp
= 1; /* breakpoint 0 is reserved for step-over */
247 memset(p
->bp
, 0, sizeof(p
->bp
));
248 p
->delayed_bp
= NULL
;
249 p
->num_delayed_bp
= 0;
251 p
->next
= dbg_process_list
;
253 if (dbg_process_list
) dbg_process_list
->prev
= p
;
254 dbg_process_list
= p
;
258 void dbg_del_process(struct dbg_process
* p
)
262 while (p
->threads
) dbg_del_thread(p
->threads
);
264 for (i
= 0; i
< p
->num_delayed_bp
; i
++)
265 if (p
->delayed_bp
[i
].is_symbol
)
266 HeapFree(GetProcessHeap(), 0, p
->delayed_bp
[i
].u
.symbol
.name
);
268 HeapFree(GetProcessHeap(), 0, p
->delayed_bp
);
269 if (p
->prev
) p
->prev
->next
= p
->next
;
270 if (p
->next
) p
->next
->prev
= p
->prev
;
271 if (p
== dbg_process_list
) dbg_process_list
= p
->next
;
272 if (p
== dbg_curr_process
) dbg_curr_process
= NULL
;
273 HeapFree(GetProcessHeap(), 0, (char*)p
->imageName
);
274 HeapFree(GetProcessHeap(), 0, p
);
277 static void dbg_init_current_process(void)
281 struct mod_loader_info
284 IMAGEHLP_MODULE
* imh_mod
;
287 static BOOL CALLBACK
mod_loader_cb(PSTR mod_name
, DWORD base
, void* ctx
)
289 struct mod_loader_info
* mli
= (struct mod_loader_info
*)ctx
;
291 if (!strcmp(mod_name
, "<wine-loader>"))
293 if (SymGetModuleInfo(mli
->handle
, base
, mli
->imh_mod
))
294 return FALSE
; /* stop enum */
299 BOOL
dbg_get_debuggee_info(HANDLE hProcess
, IMAGEHLP_MODULE
* imh_mod
)
301 struct mod_loader_info mli
;
304 /* this will resynchronize builtin dbghelp's internal ELF module list */
305 SymLoadModule(hProcess
, 0, 0, 0, 0, 0);
306 mli
.handle
= hProcess
;
307 mli
.imh_mod
= imh_mod
;
308 imh_mod
->SizeOfStruct
= sizeof(*imh_mod
);
309 imh_mod
->BaseOfImage
= 0;
310 /* this is a wine specific options to return also ELF modules in the
313 SymSetOptions((opt
= SymGetOptions()) | 0x40000000);
314 SymEnumerateModules(hProcess
, mod_loader_cb
, (void*)&mli
);
317 return imh_mod
->BaseOfImage
!= 0;
320 struct dbg_thread
* dbg_get_thread(struct dbg_process
* p
, DWORD tid
)
322 struct dbg_thread
* t
;
325 for (t
= p
->threads
; t
; t
= t
->next
)
326 if (t
->tid
== tid
) break;
330 struct dbg_thread
* dbg_add_thread(struct dbg_process
* p
, DWORD tid
,
333 struct dbg_thread
* t
= HeapAlloc(GetProcessHeap(), 0, sizeof(struct dbg_thread
));
342 t
->exec_mode
= dbg_exec_cont
;
344 t
->step_over_bp
.enabled
= FALSE
;
345 t
->step_over_bp
.refcount
= 0;
347 snprintf(t
->name
, sizeof(t
->name
), "0x%08lx", tid
);
349 t
->next
= p
->threads
;
351 if (p
->threads
) p
->threads
->prev
= t
;
357 static void dbg_init_current_thread(void* start
)
361 if (dbg_curr_process
->threads
&&
362 !dbg_curr_process
->threads
->next
&& /* first thread ? */
363 DBG_IVAR(BreakAllThreadsStartup
))
367 break_set_xpoints(FALSE
);
368 addr
.Mode
= AddrModeFlat
;
369 addr
.Offset
= (DWORD
)start
;
370 break_add_break(&addr
, TRUE
);
371 break_set_xpoints(TRUE
);
376 void dbg_del_thread(struct dbg_thread
* t
)
378 if (t
->prev
) t
->prev
->next
= t
->next
;
379 if (t
->next
) t
->next
->prev
= t
->prev
;
380 if (t
== t
->process
->threads
) t
->process
->threads
= t
->next
;
381 if (t
== dbg_curr_thread
) dbg_curr_thread
= NULL
;
382 HeapFree(GetProcessHeap(), 0, t
);
385 static unsigned dbg_handle_debug_event(DEBUG_EVENT
* de
);
387 /******************************************************************
388 * dbg_attach_debuggee
390 * Sets the debuggee to <pid>
391 * cofe instructs winedbg what to do when first exception is received
392 * (break=FALSE, continue=TRUE)
393 * wfe is set to TRUE if dbg_attach_debuggee should also proceed with all debug events
394 * until the first exception is received (aka: attach to an already running process)
396 BOOL
dbg_attach_debuggee(DWORD pid
, BOOL cofe
, BOOL wfe
)
400 if (!(dbg_curr_process
= dbg_add_process(pid
, 0, NULL
))) return FALSE
;
402 if (!DebugActiveProcess(pid
))
404 dbg_printf("Can't attach process %lx: error %ld\n", pid
, GetLastError());
405 dbg_del_process(dbg_curr_process
);
408 dbg_curr_process
->continue_on_first_exception
= cofe
;
410 if (wfe
) /* shall we proceed all debug events until we get an exception ? */
412 dbg_interactiveP
= FALSE
;
413 while (dbg_curr_process
&& WaitForDebugEvent(&de
, INFINITE
))
415 if (dbg_handle_debug_event(&de
)) break;
417 if (dbg_curr_process
) dbg_interactiveP
= TRUE
;
422 BOOL
dbg_detach_debuggee(void)
424 /* remove all set breakpoints in debuggee code */
425 break_set_xpoints(FALSE
);
426 /* needed for single stepping (ugly).
427 * should this be handled inside the server ???
429 be_cpu
->single_step(&dbg_context
, FALSE
);
430 SetThreadContext(dbg_curr_thread
->handle
, &dbg_context
);
431 if (dbg_in_exception
)
432 ContinueDebugEvent(dbg_curr_pid
, dbg_curr_tid
, DBG_CONTINUE
);
433 if (!DebugActiveProcessStop(dbg_curr_pid
)) return FALSE
;
434 dbg_del_process(dbg_curr_process
);
439 static unsigned dbg_fetch_context(void)
441 dbg_context
.ContextFlags
= CONTEXT_CONTROL
443 #ifdef CONTEXT_SEGMENTS
446 #ifdef CONTEXT_DEBUG_REGISTERS
447 | CONTEXT_DEBUG_REGISTERS
450 if (!GetThreadContext(dbg_curr_thread
->handle
, &dbg_context
))
452 WINE_WARN("Can't get thread's context\n");
458 static unsigned dbg_exception_prolog(BOOL is_debug
, DWORD code
)
463 dbg_in_exception
= TRUE
;
464 memory_get_current_pc(&addr
);
465 break_suspend_execution();
471 case AddrModeFlat
: dbg_printf(" in 32-bit code (0x%08lx)", addr
.Offset
); break;
472 case AddrModeReal
: dbg_printf(" in vm86 code (%04x:%04lx)", addr
.Segment
, addr
.Offset
); break;
473 case AddrMode1616
: dbg_printf(" in 16-bit code (%04x:%04lx)", addr
.Segment
, addr
.Offset
); break;
474 default: dbg_printf(" bad address");
479 /* this will resynchronize builtin dbghelp's internal ELF module list */
480 SymLoadModule(dbg_curr_process
->handle
, 0, 0, 0, 0, 0);
483 * Do a quiet backtrace so that we have an idea of what the situation
484 * is WRT the source files.
486 stack_backtrace(dbg_curr_tid
, FALSE
);
488 break_should_continue(&addr
, code
, &dbg_curr_thread
->exec_count
, &is_break
))
491 if (addr
.Mode
!= dbg_curr_thread
->addr_mode
)
493 const char* name
= NULL
;
497 case AddrMode1616
: name
= "16 bit"; break;
498 case AddrMode1632
: name
= "X?X??X"; break;
499 case AddrModeReal
: name
= "vm86"; break;
500 case AddrModeFlat
: name
= "32 bit"; break;
503 dbg_printf("In %s mode.\n", name
);
504 dbg_curr_thread
->addr_mode
= addr
.Mode
;
510 /* This is a real crash, dump some info */
511 be_cpu
->print_context(dbg_curr_thread
->handle
, &dbg_context
);
513 be_cpu
->print_segment_info(dbg_curr_thread
->handle
, &dbg_context
);
514 stack_backtrace(dbg_curr_tid
, TRUE
);
516 if (!is_debug
|| is_break
||
517 dbg_curr_thread
->exec_mode
== dbg_exec_step_over_insn
||
518 dbg_curr_thread
->exec_mode
== dbg_exec_step_into_insn
)
521 /* Show where we crashed */
523 memory_disasm_one_insn(&tmp
);
525 source_list_from_addr(&addr
, 0);
530 static void dbg_exception_epilog(void)
532 break_restart_execution(dbg_curr_thread
->exec_count
);
534 * This will have gotten absorbed into the breakpoint info
535 * if it was used. Otherwise it would have been ignored.
536 * In any case, we don't mess with it any more.
538 if (dbg_curr_thread
->exec_mode
== dbg_exec_cont
)
539 dbg_curr_thread
->exec_count
= 0;
540 dbg_in_exception
= FALSE
;
543 static DWORD
dbg_handle_exception(EXCEPTION_RECORD
* rec
, BOOL first_chance
)
545 BOOL is_debug
= FALSE
;
546 THREADNAME_INFO
* pThreadName
;
547 struct dbg_thread
* pThread
;
549 assert(dbg_curr_thread
);
551 WINE_TRACE("exception=%lx first_chance=%c\n",
552 rec
->ExceptionCode
, first_chance
? 'Y' : 'N');
554 switch (rec
->ExceptionCode
)
556 case EXCEPTION_BREAKPOINT
:
557 case EXCEPTION_SINGLE_STEP
:
560 case EXCEPTION_NAME_THREAD
:
561 pThreadName
= (THREADNAME_INFO
*)(rec
->ExceptionInformation
);
562 if (pThreadName
->dwThreadID
== -1)
563 pThread
= dbg_curr_thread
;
565 pThread
= dbg_get_thread(dbg_curr_process
, pThreadName
->dwThreadID
);
567 if (dbg_read_memory(pThreadName
->szName
, pThread
->name
, 9))
568 dbg_printf("Thread ID=0x%lx renamed using MS VC6 extension (name==\"%s\")\n",
569 pThread
->tid
, pThread
->name
);
573 if (first_chance
&& !is_debug
&& !DBG_IVAR(BreakOnFirstChance
))
575 /* pass exception to program except for debug exceptions */
576 return DBG_EXCEPTION_NOT_HANDLED
;
581 /* print some infos */
583 first_chance
? "First chance exception" : "Unhandled exception");
584 switch (rec
->ExceptionCode
)
586 case EXCEPTION_INT_DIVIDE_BY_ZERO
:
587 dbg_printf("divide by zero");
589 case EXCEPTION_INT_OVERFLOW
:
590 dbg_printf("overflow");
592 case EXCEPTION_ARRAY_BOUNDS_EXCEEDED
:
593 dbg_printf("array bounds");
595 case EXCEPTION_ILLEGAL_INSTRUCTION
:
596 dbg_printf("illegal instruction");
598 case EXCEPTION_STACK_OVERFLOW
:
599 dbg_printf("stack overflow");
601 case EXCEPTION_PRIV_INSTRUCTION
:
602 dbg_printf("privileged instruction");
604 case EXCEPTION_ACCESS_VIOLATION
:
605 if (rec
->NumberParameters
== 2)
606 dbg_printf("page fault on %s access to 0x%08lx",
607 rec
->ExceptionInformation
[0] ? "write" : "read",
608 rec
->ExceptionInformation
[1]);
610 dbg_printf("page fault");
612 case EXCEPTION_DATATYPE_MISALIGNMENT
:
613 dbg_printf("Alignment");
621 case STATUS_POSSIBLE_DEADLOCK
:
625 addr
.Mode
= AddrModeFlat
;
626 addr
.Offset
= rec
->ExceptionInformation
[0];
628 dbg_printf("wait failed on critical section ");
629 print_address(&addr
, FALSE
);
631 if (!DBG_IVAR(BreakOnCritSectTimeOut
))
634 return DBG_EXCEPTION_NOT_HANDLED
;
637 case EXCEPTION_WINE_STUB
:
639 char dll
[32], name
[64];
640 memory_get_string(dbg_curr_process
->handle
,
641 (void*)rec
->ExceptionInformation
[0], TRUE
, FALSE
,
643 memory_get_string(dbg_curr_process
->handle
,
644 (void*)rec
->ExceptionInformation
[1], TRUE
, FALSE
,
646 dbg_printf("unimplemented function %s.%s called", dll
, name
);
649 case EXCEPTION_WINE_ASSERTION
:
650 dbg_printf("assertion failed");
652 case EXCEPTION_VM86_INTx
:
653 dbg_printf("interrupt %02lx in vm86 mode", rec
->ExceptionInformation
[0]);
655 case EXCEPTION_VM86_STI
:
656 dbg_printf("sti in vm86 mode");
658 case EXCEPTION_VM86_PICRETURN
:
659 dbg_printf("PIC return in vm86 mode");
661 case EXCEPTION_FLT_DENORMAL_OPERAND
:
662 dbg_printf("denormal float operand");
664 case EXCEPTION_FLT_DIVIDE_BY_ZERO
:
665 dbg_printf("divide by zero");
667 case EXCEPTION_FLT_INEXACT_RESULT
:
668 dbg_printf("inexact float result");
670 case EXCEPTION_FLT_INVALID_OPERATION
:
671 dbg_printf("invalid float operation");
673 case EXCEPTION_FLT_OVERFLOW
:
674 dbg_printf("floating pointer overflow");
676 case EXCEPTION_FLT_UNDERFLOW
:
677 dbg_printf("floating pointer underflow");
679 case EXCEPTION_FLT_STACK_CHECK
:
680 dbg_printf("floating point stack check");
683 dbg_printf("0x%08lx", rec
->ExceptionCode
);
688 if (dbg_action_mode
== automatic_mode
)
690 dbg_exception_prolog(is_debug
, rec
->ExceptionCode
);
691 dbg_exception_epilog();
692 return 0; /* terminate execution */
695 if (dbg_exception_prolog(is_debug
, rec
->ExceptionCode
))
697 dbg_interactiveP
= TRUE
;
700 dbg_exception_epilog();
705 static unsigned dbg_handle_debug_event(DEBUG_EVENT
* de
)
708 DWORD cont
= DBG_CONTINUE
;
710 dbg_curr_pid
= de
->dwProcessId
;
711 dbg_curr_tid
= de
->dwThreadId
;
713 if ((dbg_curr_process
= dbg_get_process(de
->dwProcessId
)) != NULL
)
714 dbg_curr_thread
= dbg_get_thread(dbg_curr_process
, de
->dwThreadId
);
716 dbg_curr_thread
= NULL
;
718 switch (de
->dwDebugEventCode
)
720 case EXCEPTION_DEBUG_EVENT
:
721 if (!dbg_curr_thread
)
723 WINE_ERR("%08lx:%08lx: not a registered process or thread (perhaps a 16 bit one ?)\n",
724 de
->dwProcessId
, de
->dwThreadId
);
728 WINE_TRACE("%08lx:%08lx: exception code=%08lx\n",
729 de
->dwProcessId
, de
->dwThreadId
,
730 de
->u
.Exception
.ExceptionRecord
.ExceptionCode
);
732 if (dbg_curr_process
->continue_on_first_exception
)
734 dbg_curr_process
->continue_on_first_exception
= FALSE
;
735 if (!DBG_IVAR(BreakOnAttach
)) break;
737 if (dbg_fetch_context())
739 cont
= dbg_handle_exception(&de
->u
.Exception
.ExceptionRecord
,
740 de
->u
.Exception
.dwFirstChance
);
741 if (cont
&& dbg_curr_thread
)
743 SetThreadContext(dbg_curr_thread
->handle
, &dbg_context
);
748 case CREATE_PROCESS_DEBUG_EVENT
:
749 memory_get_string_indirect(de
->u
.CreateProcessInfo
.hProcess
,
750 de
->u
.CreateProcessInfo
.lpImageName
,
751 de
->u
.CreateProcessInfo
.fUnicode
,
752 buffer
, sizeof(buffer
));
753 WINE_TRACE("%08lx:%08lx: create process '%s'/%p @%08lx (%ld<%ld>)\n",
754 de
->dwProcessId
, de
->dwThreadId
,
755 buffer
, de
->u
.CreateProcessInfo
.lpImageName
,
756 (unsigned long)(void*)de
->u
.CreateProcessInfo
.lpStartAddress
,
757 de
->u
.CreateProcessInfo
.dwDebugInfoFileOffset
,
758 de
->u
.CreateProcessInfo
.nDebugInfoSize
);
760 dbg_curr_process
= dbg_add_process(de
->dwProcessId
,
761 de
->u
.CreateProcessInfo
.hProcess
,
762 buffer
[0] ? buffer
: "<Debugged Process>");
763 if (dbg_curr_process
== NULL
)
765 WINE_ERR("Couldn't create process\n");
768 if (!SymInitialize(dbg_curr_process
->handle
, NULL
, TRUE
))
769 dbg_printf("Couldn't initiate DbgHelp\n");
771 WINE_TRACE("%08lx:%08lx: create thread I @%08lx\n",
772 de
->dwProcessId
, de
->dwThreadId
,
773 (unsigned long)(void*)de
->u
.CreateProcessInfo
.lpStartAddress
);
775 dbg_curr_thread
= dbg_add_thread(dbg_curr_process
,
777 de
->u
.CreateProcessInfo
.hThread
,
778 de
->u
.CreateProcessInfo
.lpThreadLocalBase
);
779 if (!dbg_curr_thread
)
781 WINE_ERR("Couldn't create thread\n");
784 dbg_init_current_process();
785 dbg_init_current_thread(de
->u
.CreateProcessInfo
.lpStartAddress
);
788 case EXIT_PROCESS_DEBUG_EVENT
:
789 WINE_TRACE("%08lx:%08lx: exit process (%ld)\n",
790 de
->dwProcessId
, de
->dwThreadId
, de
->u
.ExitProcess
.dwExitCode
);
792 if (dbg_curr_process
== NULL
)
794 WINE_ERR("Unknown process\n");
797 if (!SymCleanup(dbg_curr_process
->handle
))
798 dbg_printf("Couldn't initiate DbgHelp\n");
800 break_set_xpoints(FALSE
);
801 /* kill last thread */
802 dbg_del_thread(dbg_curr_process
->threads
);
803 dbg_del_process(dbg_curr_process
);
805 dbg_printf("Process of pid=0x%08lx has terminated\n", dbg_curr_pid
);
808 case CREATE_THREAD_DEBUG_EVENT
:
809 WINE_TRACE("%08lx:%08lx: create thread D @%08lx\n",
810 de
->dwProcessId
, de
->dwThreadId
,
811 (unsigned long)(void*)de
->u
.CreateThread
.lpStartAddress
);
813 if (dbg_curr_process
== NULL
)
815 WINE_ERR("Unknown process\n");
818 if (dbg_get_thread(dbg_curr_process
, de
->dwThreadId
) != NULL
)
820 WINE_TRACE("Thread already listed, skipping\n");
824 dbg_curr_thread
= dbg_add_thread(dbg_curr_process
,
826 de
->u
.CreateThread
.hThread
,
827 de
->u
.CreateThread
.lpThreadLocalBase
);
828 if (!dbg_curr_thread
)
830 WINE_ERR("Couldn't create thread\n");
833 dbg_init_current_thread(de
->u
.CreateThread
.lpStartAddress
);
836 case EXIT_THREAD_DEBUG_EVENT
:
837 WINE_TRACE("%08lx:%08lx: exit thread (%ld)\n",
838 de
->dwProcessId
, de
->dwThreadId
, de
->u
.ExitThread
.dwExitCode
);
840 if (dbg_curr_thread
== NULL
)
842 WINE_ERR("Unknown thread\n");
845 /* FIXME: remove break point set on thread startup */
846 dbg_del_thread(dbg_curr_thread
);
849 case LOAD_DLL_DEBUG_EVENT
:
850 if (dbg_curr_thread
== NULL
)
852 WINE_ERR("Unknown thread\n");
855 memory_get_string_indirect(dbg_curr_process
->handle
,
856 de
->u
.LoadDll
.lpImageName
,
857 de
->u
.LoadDll
.fUnicode
,
858 buffer
, sizeof(buffer
));
860 WINE_TRACE("%08lx:%08lx: loads DLL %s @%08lx (%ld<%ld>)\n",
861 de
->dwProcessId
, de
->dwThreadId
,
862 buffer
, (unsigned long)de
->u
.LoadDll
.lpBaseOfDll
,
863 de
->u
.LoadDll
.dwDebugInfoFileOffset
,
864 de
->u
.LoadDll
.nDebugInfoSize
);
866 SymLoadModule(dbg_curr_process
->handle
, de
->u
.LoadDll
.hFile
, buffer
, NULL
,
867 (unsigned long)de
->u
.LoadDll
.lpBaseOfDll
, 0);
868 break_set_xpoints(FALSE
);
869 break_check_delayed_bp();
870 break_set_xpoints(TRUE
);
871 if (DBG_IVAR(BreakOnDllLoad
))
873 dbg_printf("Stopping on DLL %s loading at 0x%08lx\n",
874 buffer
, (unsigned long)de
->u
.LoadDll
.lpBaseOfDll
);
875 if (dbg_fetch_context()) cont
= 0;
879 case UNLOAD_DLL_DEBUG_EVENT
:
880 WINE_TRACE("%08lx:%08lx: unload DLL @%08lx\n",
881 de
->dwProcessId
, de
->dwThreadId
,
882 (unsigned long)de
->u
.UnloadDll
.lpBaseOfDll
);
883 break_delete_xpoints_from_module((unsigned long)de
->u
.UnloadDll
.lpBaseOfDll
);
884 SymUnloadModule(dbg_curr_process
->handle
,
885 (unsigned long)de
->u
.UnloadDll
.lpBaseOfDll
);
888 case OUTPUT_DEBUG_STRING_EVENT
:
889 if (dbg_curr_thread
== NULL
)
891 WINE_ERR("Unknown thread\n");
895 memory_get_string(dbg_curr_process
->handle
,
896 de
->u
.DebugString
.lpDebugStringData
, TRUE
,
897 de
->u
.DebugString
.fUnicode
, buffer
, sizeof(buffer
));
898 WINE_TRACE("%08lx:%08lx: output debug string (%s)\n",
899 de
->dwProcessId
, de
->dwThreadId
, buffer
);
903 WINE_TRACE("%08lx:%08lx: rip error=%ld type=%ld\n",
904 de
->dwProcessId
, de
->dwThreadId
, de
->u
.RipInfo
.dwError
,
905 de
->u
.RipInfo
.dwType
);
909 WINE_TRACE("%08lx:%08lx: unknown event (%ld)\n",
910 de
->dwProcessId
, de
->dwThreadId
, de
->dwDebugEventCode
);
912 if (!cont
) return TRUE
; /* stop execution */
913 ContinueDebugEvent(de
->dwProcessId
, de
->dwThreadId
, cont
);
914 return FALSE
; /* continue execution */
917 static void dbg_resume_debuggee(DWORD cont
)
919 if (dbg_in_exception
)
923 dbg_exception_epilog();
924 memory_get_current_pc(&addr
);
925 WINE_TRACE("Exiting debugger PC=0x%lx mode=%d count=%d\n",
926 addr
.Offset
, dbg_curr_thread
->exec_mode
,
927 dbg_curr_thread
->exec_count
);
930 if (!SetThreadContext(dbg_curr_thread
->handle
, &dbg_context
))
931 dbg_printf("Cannot set ctx on %lu\n", dbg_curr_tid
);
934 dbg_interactiveP
= FALSE
;
935 if (!ContinueDebugEvent(dbg_curr_pid
, dbg_curr_tid
, cont
))
936 dbg_printf("Cannot continue on %lu (%lu)\n", dbg_curr_tid
, cont
);
939 void dbg_wait_next_exception(DWORD cont
, int count
, int mode
)
944 if (cont
== DBG_CONTINUE
)
946 dbg_curr_thread
->exec_count
= count
;
947 dbg_curr_thread
->exec_mode
= mode
;
949 dbg_resume_debuggee(cont
);
951 while (dbg_curr_process
&& WaitForDebugEvent(&de
, INFINITE
))
953 if (dbg_handle_debug_event(&de
)) break;
955 if (!dbg_curr_process
) return;
956 dbg_interactiveP
= TRUE
;
958 memory_get_current_pc(&addr
);
959 WINE_TRACE("Entering debugger PC=0x%lx mode=%d count=%d\n",
960 addr
.Offset
, dbg_curr_thread
->exec_mode
,
961 dbg_curr_thread
->exec_count
);
964 static unsigned dbg_main_loop(void)
968 if (dbg_curr_process
)
969 dbg_printf("WineDbg starting on pid 0x%lx\n", dbg_curr_pid
);
971 /* wait for first exception */
972 while (WaitForDebugEvent(&de
, INFINITE
))
974 if (dbg_handle_debug_event(&de
)) break;
976 switch (dbg_action_mode
)
979 /* print some extra information */
980 dbg_printf("Modules:\n");
981 info_win32_module(0); /* print all modules */
982 dbg_printf("Threads:\n");
983 info_win32_threads();
986 dbg_interactiveP
= TRUE
;
989 dbg_printf("WineDbg terminated on pid 0x%lx\n", dbg_curr_pid
);
994 static unsigned dbg_start_debuggee(LPSTR cmdLine
)
996 PROCESS_INFORMATION info
;
997 STARTUPINFOA startup
;
999 memset(&startup
, 0, sizeof(startup
));
1000 startup
.cb
= sizeof(startup
);
1001 startup
.dwFlags
= STARTF_USESHOWWINDOW
;
1002 startup
.wShowWindow
= SW_SHOWNORMAL
;
1004 /* FIXME: shouldn't need the CREATE_NEW_CONSOLE, but as usual CUI:s need it
1007 if (!CreateProcess(NULL
, cmdLine
, NULL
, NULL
,
1009 DEBUG_PROCESS
|DEBUG_ONLY_THIS_PROCESS
|CREATE_NEW_CONSOLE
,
1010 NULL
, NULL
, &startup
, &info
))
1012 dbg_printf("Couldn't start process '%s'\n", cmdLine
);
1015 if (!info
.dwProcessId
)
1017 /* this happens when the program being run is not a Wine binary
1018 * (for example, a shell wrapper around a WineLib app)
1020 /* Current fix: list running processes and let the user attach
1021 * to one of them (sic)
1022 * FIXME: implement a real fix => grab the process (from the
1023 * running processes) from its name
1025 dbg_printf("Debuggee has been started (%s)\n"
1026 "But WineDbg isn't attached to it. Maybe you're trying to debug a winelib wrapper ??\n"
1027 "Try to attach to one of those processes:\n", cmdLine
);
1028 /* FIXME: (HACK) we need some time before the wrapper executes the winelib app */
1030 info_win32_processes();
1033 dbg_curr_pid
= info
.dwProcessId
;
1034 if (!(dbg_curr_process
= dbg_add_process(dbg_curr_pid
, 0, NULL
))) return FALSE
;
1039 void dbg_run_debuggee(const char* args
)
1043 WINE_FIXME("Re-running current program with %s as args is broken\n", args
);
1050 if (!dbg_last_cmd_line
)
1052 dbg_printf("Cannot find previously used command line.\n");
1055 dbg_start_debuggee(dbg_last_cmd_line
);
1056 while (dbg_curr_process
&& WaitForDebugEvent(&de
, INFINITE
))
1058 if (dbg_handle_debug_event(&de
)) break;
1060 source_list_from_addr(NULL
, 0);
1064 BOOL
dbg_interrupt_debuggee(void)
1066 if (!dbg_process_list
) return FALSE
;
1067 /* FIXME: since we likely have a single process, signal the first process
1070 if (dbg_process_list
->next
) dbg_printf("Ctrl-C: only stopping the first process\n");
1071 else dbg_printf("Ctrl-C: stopping debuggee\n");
1072 dbg_process_list
->continue_on_first_exception
= FALSE
;
1073 return DebugBreakProcess(dbg_process_list
->handle
);
1076 static BOOL WINAPI
ctrl_c_handler(DWORD dwCtrlType
)
1078 if (dwCtrlType
== CTRL_C_EVENT
)
1080 return dbg_interrupt_debuggee();
1085 static void dbg_init_console(void)
1087 /* set our control-C handler */
1088 SetConsoleCtrlHandler(ctrl_c_handler
, TRUE
);
1090 /* set our own title */
1091 SetConsoleTitle("Wine Debugger");
1094 static int dbg_winedbg_usage(void)
1096 dbg_printf("Usage: winedbg [--auto] [--gdb] cmdline\n");
1100 struct backend_cpu
* be_cpu
;
1102 extern struct backend_cpu be_i386
;
1104 extern struct backend_cpu be_ppc
;
1106 extern struct backend_cpu be_alpha
;
1111 int main(int argc
, char** argv
)
1114 unsigned gdb_flags
= 0;
1125 /* Initialize the output */
1126 dbg_houtput
= GetStdHandle(STD_OUTPUT_HANDLE
);
1128 /* Initialize internal vars */
1129 if (!dbg_load_internal_vars()) return -1;
1132 while (argc
> 1 && argv
[1][0] == '-')
1134 if (!strcmp(argv
[1], "--command"))
1137 arg_command
= HeapAlloc(GetProcessHeap(), 0, strlen(argv
[1])+2);
1138 strcpy(arg_command
, argv
[1]);
1139 strcat(arg_command
, "\n");
1143 if (!strcmp(argv
[1], "--auto"))
1145 if (dbg_action_mode
!= none_mode
) return dbg_winedbg_usage();
1146 dbg_action_mode
= automatic_mode
;
1147 /* force some internal variables */
1148 DBG_IVAR(BreakOnDllLoad
) = 0;
1150 dbg_houtput
= GetStdHandle(STD_ERROR_HANDLE
);
1153 if (!strcmp(argv
[1], "--gdb"))
1155 if (dbg_action_mode
!= none_mode
) return dbg_winedbg_usage();
1156 dbg_action_mode
= gdb_mode
;
1160 if (strcmp(argv
[1], "--no-start") == 0 && dbg_action_mode
== gdb_mode
)
1163 argc
--; argv
++; /* as we don't use argv[0] */
1166 if (strcmp(argv
[1], "--with-xterm") == 0 && dbg_action_mode
== gdb_mode
)
1169 argc
--; argv
++; /* as we don't use argv[0] */
1172 return dbg_winedbg_usage();
1175 if (dbg_action_mode
== none_mode
) dbg_action_mode
= winedbg_mode
;
1177 /* try the form <myself> pid */
1178 if (dbg_curr_pid
== 0 && argc
== 2)
1182 dbg_curr_pid
= strtol(argv
[1], &ptr
, 10);
1183 if (dbg_curr_pid
== 0 || ptr
== NULL
||
1184 !dbg_attach_debuggee(dbg_curr_pid
, dbg_action_mode
!= gdb_mode
, FALSE
))
1188 /* try the form <myself> pid evt (Win32 JIT debugger) */
1189 if (dbg_curr_pid
== 0 && argc
== 3)
1195 if ((pid
= strtol(argv
[1], &ptr
, 10)) != 0 && ptr
!= NULL
&&
1196 (hEvent
= (HANDLE
)strtol(argv
[2], &ptr
, 10)) != 0 && ptr
!= NULL
)
1198 if (!dbg_attach_debuggee(pid
, TRUE
, FALSE
))
1200 /* don't care about result */
1204 if (!SetEvent(hEvent
))
1206 WINE_ERR("Invalid event handle: %p\n", hEvent
);
1209 CloseHandle(hEvent
);
1214 if (dbg_curr_pid
== 0 && argc
> 1)
1219 if (!(cmdLine
= HeapAlloc(GetProcessHeap(), 0, len
= 1))) goto oom_leave
;
1222 for (i
= 1; i
< argc
; i
++)
1224 len
+= strlen(argv
[i
]) + 1;
1225 if (!(cmdLine
= HeapReAlloc(GetProcessHeap(), 0, cmdLine
, len
)))
1227 strcat(cmdLine
, argv
[i
]);
1228 cmdLine
[len
- 2] = ' ';
1229 cmdLine
[len
- 1] = '\0';
1232 if (!dbg_start_debuggee(cmdLine
))
1234 dbg_printf("Couldn't start process '%s'\n", cmdLine
);
1237 dbg_last_cmd_line
= cmdLine
;
1239 /* don't save local vars in gdb mode */
1240 if (dbg_action_mode
== gdb_mode
&& dbg_curr_pid
)
1241 return gdb_remote(gdb_flags
);
1245 SymSetOptions(SymGetOptions() |
1246 SYMOPT_LOAD_LINES
| SYMOPT_DEFERRED_LOADS
| SYMOPT_AUTO_PUBLICS
);
1248 retv
= dbg_main_loop();
1249 /* don't save modified variables in auto mode */
1250 if (dbg_action_mode
!= automatic_mode
) dbg_save_internal_vars();
1256 dbg_printf("Out of memory\n");