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 as on 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 char* dbg_last_cmd_line
= NULL
;
85 static struct dbg_process
* dbg_process_list
= NULL
;
86 static enum {none_mode
= 0, winedbg_mode
, automatic_mode
, gdb_mode
} dbg_action_mode
;
88 struct dbg_internal_var dbg_internal_vars
[DBG_IV_LAST
];
89 const struct dbg_internal_var
* dbg_context_vars
;
90 static HANDLE dbg_houtput
;
92 void dbg_outputA(const char* buffer
, int len
)
94 static char line_buff
[4096];
95 static unsigned int line_pos
;
101 unsigned int count
= min( len
, sizeof(line_buff
) - line_pos
);
102 memcpy( line_buff
+ line_pos
, buffer
, count
);
106 for (i
= line_pos
; i
> 0; i
--) if (line_buff
[i
-1] == '\n') break;
107 if (!i
) /* no newline found */
109 if (len
> 0) i
= line_pos
; /* buffer is full, flush anyway */
112 WriteFile(dbg_houtput
, line_buff
, i
, &w
, NULL
);
113 memmove( line_buff
, line_buff
+ i
, line_pos
- i
);
118 void dbg_outputW(const WCHAR
* buffer
, int len
)
123 /* do a serious Unicode to ANSI conversion
124 * FIXME: should CP_ACP be GetConsoleCP()?
126 newlen
= WideCharToMultiByte(CP_ACP
, 0, buffer
, len
, NULL
, 0, NULL
, NULL
);
129 if (!(ansi
= HeapAlloc(GetProcessHeap(), 0, newlen
))) return;
130 WideCharToMultiByte(CP_ACP
, 0, buffer
, len
, ansi
, newlen
, NULL
, NULL
);
131 dbg_outputA(ansi
, newlen
);
132 HeapFree(GetProcessHeap(), 0, ansi
);
136 int dbg_printf(const char* format
, ...)
138 static char buf
[4*1024];
142 va_start(valist
, format
);
143 len
= vsnprintf(buf
, sizeof(buf
), format
, valist
);
146 if (len
<= -1 || len
>= sizeof(buf
))
148 len
= sizeof(buf
) - 1;
150 buf
[len
- 1] = buf
[len
- 2] = buf
[len
- 3] = '.';
152 dbg_outputA(buf
, len
);
156 static unsigned dbg_load_internal_vars(void)
159 DWORD type
= REG_DWORD
;
161 DWORD count
= sizeof(val
);
163 struct dbg_internal_var
* div
= dbg_internal_vars
;
165 /* initializes internal vars table */
166 #define INTERNAL_VAR(_var,_val,_ref,_tid) \
167 div->val = _val; div->name = #_var; div->pval = _ref; \
168 div->typeid = _tid; div++;
172 /* @@ Wine registry key: HKCU\Software\Wine\WineDbg */
173 if (RegCreateKeyA(HKEY_CURRENT_USER
, "Software\\Wine\\WineDbg", &hkey
))
175 WINE_ERR("Cannot create WineDbg key in registry\n");
179 for (i
= 0; i
< DBG_IV_LAST
; i
++)
181 if (!dbg_internal_vars
[i
].pval
)
183 if (!RegQueryValueEx(hkey
, dbg_internal_vars
[i
].name
, 0,
184 &type
, (LPBYTE
)&val
, &count
))
185 dbg_internal_vars
[i
].val
= val
;
186 dbg_internal_vars
[i
].pval
= &dbg_internal_vars
[i
].val
;
190 /* set up the debug variables for the CPU context */
191 dbg_context_vars
= be_cpu
->init_registers(&dbg_context
);
195 static unsigned dbg_save_internal_vars(void)
200 /* @@ Wine registry key: HKCU\Software\Wine\WineDbg */
201 if (RegCreateKeyA(HKEY_CURRENT_USER
, "Software\\Wine\\WineDbg", &hkey
))
203 WINE_ERR("Cannot create WineDbg key in registry\n");
207 for (i
= 0; i
< DBG_IV_LAST
; i
++)
209 /* FIXME: type should be infered from basic type -if any- of intvar */
210 if (dbg_internal_vars
[i
].pval
== &dbg_internal_vars
[i
].val
)
211 RegSetValueEx(hkey
, dbg_internal_vars
[i
].name
, 0,
212 REG_DWORD
, (const void*)dbg_internal_vars
[i
].pval
,
213 sizeof(*dbg_internal_vars
[i
].pval
));
219 const struct dbg_internal_var
* dbg_get_internal_var(const char* name
)
221 const struct dbg_internal_var
* div
;
223 for (div
= &dbg_internal_vars
[DBG_IV_LAST
- 1]; div
>= dbg_internal_vars
; div
--)
225 if (!strcmp(div
->name
, name
)) return div
;
227 for (div
= dbg_context_vars
; div
->name
; div
++)
229 if (!strcasecmp(div
->name
, name
)) return div
;
235 struct dbg_process
* dbg_get_process(DWORD pid
)
237 struct dbg_process
* p
;
239 for (p
= dbg_process_list
; p
; p
= p
->next
)
240 if (p
->pid
== pid
) break;
244 struct dbg_process
* dbg_add_process(DWORD pid
, HANDLE h
)
246 /* FIXME: temporary */
247 extern struct be_process_io be_process_active_io
;
249 struct dbg_process
* p
;
251 if ((p
= dbg_get_process(pid
)))
255 WINE_ERR("Process (%lu) is already defined\n", pid
);
265 if (!(p
= HeapAlloc(GetProcessHeap(), 0, sizeof(struct dbg_process
)))) return NULL
;
268 p
->process_io
= &be_process_active_io
;
271 p
->continue_on_first_exception
= FALSE
;
272 p
->next_bp
= 1; /* breakpoint 0 is reserved for step-over */
273 memset(p
->bp
, 0, sizeof(p
->bp
));
274 p
->delayed_bp
= NULL
;
275 p
->num_delayed_bp
= 0;
277 p
->next
= dbg_process_list
;
279 if (dbg_process_list
) dbg_process_list
->prev
= p
;
280 dbg_process_list
= p
;
284 void dbg_set_process_name(struct dbg_process
* p
, const char* imageName
)
286 assert(p
->imageName
== NULL
);
289 char* tmp
= HeapAlloc(GetProcessHeap(), 0, strlen(imageName
) + 1);
290 if (tmp
) p
->imageName
= strcpy(tmp
, imageName
);
294 void dbg_del_process(struct dbg_process
* p
)
298 while (p
->threads
) dbg_del_thread(p
->threads
);
300 for (i
= 0; i
< p
->num_delayed_bp
; i
++)
301 if (p
->delayed_bp
[i
].is_symbol
)
302 HeapFree(GetProcessHeap(), 0, p
->delayed_bp
[i
].u
.symbol
.name
);
304 HeapFree(GetProcessHeap(), 0, p
->delayed_bp
);
305 if (p
->prev
) p
->prev
->next
= p
->next
;
306 if (p
->next
) p
->next
->prev
= p
->prev
;
307 if (p
== dbg_process_list
) dbg_process_list
= p
->next
;
308 if (p
== dbg_curr_process
) dbg_curr_process
= NULL
;
309 HeapFree(GetProcessHeap(), 0, (char*)p
->imageName
);
310 HeapFree(GetProcessHeap(), 0, p
);
313 static void dbg_init_current_process(void)
317 struct mod_loader_info
320 IMAGEHLP_MODULE
* imh_mod
;
323 static BOOL CALLBACK
mod_loader_cb(PSTR mod_name
, DWORD base
, void* ctx
)
325 struct mod_loader_info
* mli
= (struct mod_loader_info
*)ctx
;
327 if (!strcmp(mod_name
, "<wine-loader>"))
329 if (SymGetModuleInfo(mli
->handle
, base
, mli
->imh_mod
))
330 return FALSE
; /* stop enum */
335 BOOL
dbg_get_debuggee_info(HANDLE hProcess
, IMAGEHLP_MODULE
* imh_mod
)
337 struct mod_loader_info mli
;
340 /* this will resynchronize builtin dbghelp's internal ELF module list */
341 SymLoadModule(hProcess
, 0, 0, 0, 0, 0);
342 mli
.handle
= hProcess
;
343 mli
.imh_mod
= imh_mod
;
344 imh_mod
->SizeOfStruct
= sizeof(*imh_mod
);
345 imh_mod
->BaseOfImage
= 0;
346 /* this is a wine specific options to return also ELF modules in the
349 SymSetOptions((opt
= SymGetOptions()) | 0x40000000);
350 SymEnumerateModules(hProcess
, mod_loader_cb
, (void*)&mli
);
353 return imh_mod
->BaseOfImage
!= 0;
356 struct dbg_thread
* dbg_get_thread(struct dbg_process
* p
, DWORD tid
)
358 struct dbg_thread
* t
;
361 for (t
= p
->threads
; t
; t
= t
->next
)
362 if (t
->tid
== tid
) break;
366 struct dbg_thread
* dbg_add_thread(struct dbg_process
* p
, DWORD tid
,
369 struct dbg_thread
* t
= HeapAlloc(GetProcessHeap(), 0, sizeof(struct dbg_thread
));
378 t
->exec_mode
= dbg_exec_cont
;
380 t
->step_over_bp
.enabled
= FALSE
;
381 t
->step_over_bp
.refcount
= 0;
382 t
->in_exception
= FALSE
;
384 snprintf(t
->name
, sizeof(t
->name
), "0x%08lx", tid
);
386 t
->next
= p
->threads
;
388 if (p
->threads
) p
->threads
->prev
= t
;
394 static void dbg_init_current_thread(void* start
)
398 if (dbg_curr_process
->threads
&&
399 !dbg_curr_process
->threads
->next
&& /* first thread ? */
400 DBG_IVAR(BreakAllThreadsStartup
))
404 break_set_xpoints(FALSE
);
405 addr
.Mode
= AddrModeFlat
;
406 addr
.Offset
= (DWORD
)start
;
407 break_add_break(&addr
, TRUE
);
408 break_set_xpoints(TRUE
);
413 void dbg_del_thread(struct dbg_thread
* t
)
415 if (t
->prev
) t
->prev
->next
= t
->next
;
416 if (t
->next
) t
->next
->prev
= t
->prev
;
417 if (t
== t
->process
->threads
) t
->process
->threads
= t
->next
;
418 if (t
== dbg_curr_thread
) dbg_curr_thread
= NULL
;
419 HeapFree(GetProcessHeap(), 0, t
);
422 static unsigned dbg_handle_debug_event(DEBUG_EVENT
* de
);
424 /******************************************************************
425 * dbg_attach_debuggee
427 * Sets the debuggee to <pid>
428 * cofe instructs winedbg what to do when first exception is received
429 * (break=FALSE, continue=TRUE)
430 * wfe is set to TRUE if dbg_attach_debuggee should also proceed with all debug events
431 * until the first exception is received (aka: attach to an already running process)
433 BOOL
dbg_attach_debuggee(DWORD pid
, BOOL cofe
, BOOL wfe
)
437 if (!(dbg_curr_process
= dbg_add_process(pid
, 0))) return FALSE
;
439 if (!DebugActiveProcess(pid
))
441 dbg_printf("Can't attach process %lx: error %ld\n", pid
, GetLastError());
442 dbg_del_process(dbg_curr_process
);
445 dbg_curr_process
->continue_on_first_exception
= cofe
;
447 if (wfe
) /* shall we proceed all debug events until we get an exception ? */
449 dbg_interactiveP
= FALSE
;
450 while (dbg_curr_process
&& WaitForDebugEvent(&de
, INFINITE
))
452 if (dbg_handle_debug_event(&de
)) break;
454 if (dbg_curr_process
) dbg_interactiveP
= TRUE
;
459 BOOL
dbg_detach_debuggee(void)
461 /* remove all set breakpoints in debuggee code */
462 break_set_xpoints(FALSE
);
463 /* needed for single stepping (ugly).
464 * should this be handled inside the server ???
466 be_cpu
->single_step(&dbg_context
, FALSE
);
467 SetThreadContext(dbg_curr_thread
->handle
, &dbg_context
);
468 if (dbg_curr_thread
->in_exception
)
469 ContinueDebugEvent(dbg_curr_pid
, dbg_curr_tid
, DBG_CONTINUE
);
470 if (!DebugActiveProcessStop(dbg_curr_pid
)) return FALSE
;
471 dbg_del_process(dbg_curr_process
);
476 static unsigned dbg_fetch_context(void)
478 dbg_context
.ContextFlags
= CONTEXT_CONTROL
480 #ifdef CONTEXT_SEGMENTS
483 #ifdef CONTEXT_DEBUG_REGISTERS
484 | CONTEXT_DEBUG_REGISTERS
487 if (!GetThreadContext(dbg_curr_thread
->handle
, &dbg_context
))
489 WINE_WARN("Can't get thread's context\n");
495 static unsigned dbg_exception_prolog(BOOL is_debug
, const EXCEPTION_RECORD
* rec
)
500 memory_get_current_pc(&addr
);
501 break_suspend_execution();
502 dbg_curr_thread
->excpt_record
= *rec
;
503 dbg_curr_thread
->in_exception
= TRUE
;
509 case AddrModeFlat
: dbg_printf(" in 32-bit code (0x%08lx)", addr
.Offset
); break;
510 case AddrModeReal
: dbg_printf(" in vm86 code (%04x:%04lx)", addr
.Segment
, addr
.Offset
); break;
511 case AddrMode1616
: dbg_printf(" in 16-bit code (%04x:%04lx)", addr
.Segment
, addr
.Offset
); break;
512 case AddrMode1632
: dbg_printf(" in 32-bit code (%04x:%08lx)", addr
.Segment
, addr
.Offset
); break;
513 default: dbg_printf(" bad address");
518 /* this will resynchronize builtin dbghelp's internal ELF module list */
519 SymLoadModule(dbg_curr_process
->handle
, 0, 0, 0, 0, 0);
522 * Do a quiet backtrace so that we have an idea of what the situation
523 * is WRT the source files.
525 stack_backtrace(dbg_curr_tid
, FALSE
);
527 break_should_continue(&addr
, rec
->ExceptionCode
, &dbg_curr_thread
->exec_count
, &is_break
))
530 if (addr
.Mode
!= dbg_curr_thread
->addr_mode
)
532 const char* name
= NULL
;
536 case AddrMode1616
: name
= "16 bit"; break;
537 case AddrMode1632
: name
= "32 bit"; break;
538 case AddrModeReal
: name
= "vm86"; break;
539 case AddrModeFlat
: name
= "32 bit"; break;
542 dbg_printf("In %s mode.\n", name
);
543 dbg_curr_thread
->addr_mode
= addr
.Mode
;
549 /* This is a real crash, dump some info */
550 be_cpu
->print_context(dbg_curr_thread
->handle
, &dbg_context
);
552 be_cpu
->print_segment_info(dbg_curr_thread
->handle
, &dbg_context
);
553 stack_backtrace(dbg_curr_tid
, TRUE
);
555 if (!is_debug
|| is_break
||
556 dbg_curr_thread
->exec_mode
== dbg_exec_step_over_insn
||
557 dbg_curr_thread
->exec_mode
== dbg_exec_step_into_insn
)
560 /* Show where we crashed */
562 memory_disasm_one_insn(&tmp
);
564 source_list_from_addr(&addr
, 0);
569 static void dbg_exception_epilog(void)
571 break_restart_execution(dbg_curr_thread
->exec_count
);
573 * This will have gotten absorbed into the breakpoint info
574 * if it was used. Otherwise it would have been ignored.
575 * In any case, we don't mess with it any more.
577 if (dbg_curr_thread
->exec_mode
== dbg_exec_cont
)
578 dbg_curr_thread
->exec_count
= 0;
579 dbg_curr_thread
->in_exception
= FALSE
;
582 static DWORD
dbg_handle_exception(const EXCEPTION_RECORD
* rec
, BOOL first_chance
)
584 BOOL is_debug
= FALSE
;
585 THREADNAME_INFO
* pThreadName
;
586 struct dbg_thread
* pThread
;
588 assert(dbg_curr_thread
);
590 WINE_TRACE("exception=%lx first_chance=%c\n",
591 rec
->ExceptionCode
, first_chance
? 'Y' : 'N');
593 switch (rec
->ExceptionCode
)
595 case EXCEPTION_BREAKPOINT
:
596 case EXCEPTION_SINGLE_STEP
:
599 case EXCEPTION_NAME_THREAD
:
600 pThreadName
= (THREADNAME_INFO
*)(rec
->ExceptionInformation
);
601 if (pThreadName
->dwThreadID
== -1)
602 pThread
= dbg_curr_thread
;
604 pThread
= dbg_get_thread(dbg_curr_process
, pThreadName
->dwThreadID
);
606 if (dbg_read_memory(pThreadName
->szName
, pThread
->name
, 9))
607 dbg_printf("Thread ID=0x%lx renamed using MS VC6 extension (name==\"%s\")\n",
608 pThread
->tid
, pThread
->name
);
612 if (first_chance
&& !is_debug
&& !DBG_IVAR(BreakOnFirstChance
) &&
613 !(rec
->ExceptionFlags
& EH_STACK_INVALID
))
615 /* pass exception to program except for debug exceptions */
616 return DBG_EXCEPTION_NOT_HANDLED
;
621 /* print some infos */
623 first_chance
? "First chance exception" : "Unhandled exception");
624 switch (rec
->ExceptionCode
)
626 case EXCEPTION_INT_DIVIDE_BY_ZERO
:
627 dbg_printf("divide by zero");
629 case EXCEPTION_INT_OVERFLOW
:
630 dbg_printf("overflow");
632 case EXCEPTION_ARRAY_BOUNDS_EXCEEDED
:
633 dbg_printf("array bounds");
635 case EXCEPTION_ILLEGAL_INSTRUCTION
:
636 dbg_printf("illegal instruction");
638 case EXCEPTION_STACK_OVERFLOW
:
639 dbg_printf("stack overflow");
641 case EXCEPTION_PRIV_INSTRUCTION
:
642 dbg_printf("privileged instruction");
644 case EXCEPTION_ACCESS_VIOLATION
:
645 if (rec
->NumberParameters
== 2)
646 dbg_printf("page fault on %s access to 0x%08lx",
647 rec
->ExceptionInformation
[0] ? "write" : "read",
648 rec
->ExceptionInformation
[1]);
650 dbg_printf("page fault");
652 case EXCEPTION_DATATYPE_MISALIGNMENT
:
653 dbg_printf("Alignment");
661 case STATUS_POSSIBLE_DEADLOCK
:
665 addr
.Mode
= AddrModeFlat
;
666 addr
.Offset
= rec
->ExceptionInformation
[0];
668 dbg_printf("wait failed on critical section ");
669 print_address(&addr
, FALSE
);
671 if (!DBG_IVAR(BreakOnCritSectTimeOut
))
674 return DBG_EXCEPTION_NOT_HANDLED
;
677 case EXCEPTION_WINE_STUB
:
679 char dll
[32], name
[64];
680 memory_get_string(dbg_curr_process
,
681 (void*)rec
->ExceptionInformation
[0], TRUE
, FALSE
,
683 if (HIWORD(rec
->ExceptionInformation
[1]))
684 memory_get_string(dbg_curr_process
,
685 (void*)rec
->ExceptionInformation
[1], TRUE
, FALSE
,
688 sprintf( name
, "%ld", rec
->ExceptionInformation
[1] );
689 dbg_printf("unimplemented function %s.%s called", dll
, name
);
692 case EXCEPTION_WINE_ASSERTION
:
693 dbg_printf("assertion failed");
695 case EXCEPTION_VM86_INTx
:
696 dbg_printf("interrupt %02lx in vm86 mode", rec
->ExceptionInformation
[0]);
698 case EXCEPTION_VM86_STI
:
699 dbg_printf("sti in vm86 mode");
701 case EXCEPTION_VM86_PICRETURN
:
702 dbg_printf("PIC return in vm86 mode");
704 case EXCEPTION_FLT_DENORMAL_OPERAND
:
705 dbg_printf("denormal float operand");
707 case EXCEPTION_FLT_DIVIDE_BY_ZERO
:
708 dbg_printf("divide by zero");
710 case EXCEPTION_FLT_INEXACT_RESULT
:
711 dbg_printf("inexact float result");
713 case EXCEPTION_FLT_INVALID_OPERATION
:
714 dbg_printf("invalid float operation");
716 case EXCEPTION_FLT_OVERFLOW
:
717 dbg_printf("floating pointer overflow");
719 case EXCEPTION_FLT_UNDERFLOW
:
720 dbg_printf("floating pointer underflow");
722 case EXCEPTION_FLT_STACK_CHECK
:
723 dbg_printf("floating point stack check");
726 dbg_printf("0x%08lx", rec
->ExceptionCode
);
730 if( (rec
->ExceptionFlags
& EH_STACK_INVALID
) ) {
731 dbg_printf( ", invalid program stack" );
734 if (dbg_action_mode
== automatic_mode
)
736 dbg_exception_prolog(is_debug
, rec
);
737 dbg_exception_epilog();
738 return 0; /* terminate execution */
741 if (dbg_exception_prolog(is_debug
, rec
))
743 dbg_interactiveP
= TRUE
;
746 dbg_exception_epilog();
751 static unsigned dbg_handle_debug_event(DEBUG_EVENT
* de
)
754 DWORD cont
= DBG_CONTINUE
;
756 dbg_curr_pid
= de
->dwProcessId
;
757 dbg_curr_tid
= de
->dwThreadId
;
759 if ((dbg_curr_process
= dbg_get_process(de
->dwProcessId
)) != NULL
)
760 dbg_curr_thread
= dbg_get_thread(dbg_curr_process
, de
->dwThreadId
);
762 dbg_curr_thread
= NULL
;
764 switch (de
->dwDebugEventCode
)
766 case EXCEPTION_DEBUG_EVENT
:
767 if (!dbg_curr_thread
)
769 WINE_ERR("%08lx:%08lx: not a registered process or thread (perhaps a 16 bit one ?)\n",
770 de
->dwProcessId
, de
->dwThreadId
);
774 WINE_TRACE("%08lx:%08lx: exception code=%08lx\n",
775 de
->dwProcessId
, de
->dwThreadId
,
776 de
->u
.Exception
.ExceptionRecord
.ExceptionCode
);
778 if (dbg_curr_process
->continue_on_first_exception
)
780 dbg_curr_process
->continue_on_first_exception
= FALSE
;
781 if (!DBG_IVAR(BreakOnAttach
)) break;
783 if (dbg_fetch_context())
785 cont
= dbg_handle_exception(&de
->u
.Exception
.ExceptionRecord
,
786 de
->u
.Exception
.dwFirstChance
);
787 if (cont
&& dbg_curr_thread
)
789 SetThreadContext(dbg_curr_thread
->handle
, &dbg_context
);
794 case CREATE_PROCESS_DEBUG_EVENT
:
795 dbg_curr_process
= dbg_add_process(de
->dwProcessId
,
796 de
->u
.CreateProcessInfo
.hProcess
);
797 if (dbg_curr_process
== NULL
)
799 WINE_ERR("Couldn't create process\n");
802 memory_get_string_indirect(dbg_curr_process
,
803 de
->u
.CreateProcessInfo
.lpImageName
,
804 de
->u
.CreateProcessInfo
.fUnicode
,
805 buffer
, sizeof(buffer
));
806 if (!buffer
[0]) strcpy(buffer
, "<Debugged Process>");
808 WINE_TRACE("%08lx:%08lx: create process '%s'/%p @%08lx (%ld<%ld>)\n",
809 de
->dwProcessId
, de
->dwThreadId
,
810 buffer
, de
->u
.CreateProcessInfo
.lpImageName
,
811 (unsigned long)(void*)de
->u
.CreateProcessInfo
.lpStartAddress
,
812 de
->u
.CreateProcessInfo
.dwDebugInfoFileOffset
,
813 de
->u
.CreateProcessInfo
.nDebugInfoSize
);
814 dbg_set_process_name(dbg_curr_process
, buffer
);
816 if (!SymInitialize(dbg_curr_process
->handle
, NULL
, TRUE
))
817 dbg_printf("Couldn't initiate DbgHelp\n");
819 WINE_TRACE("%08lx:%08lx: create thread I @%08lx\n",
820 de
->dwProcessId
, de
->dwThreadId
,
821 (unsigned long)(void*)de
->u
.CreateProcessInfo
.lpStartAddress
);
823 dbg_curr_thread
= dbg_add_thread(dbg_curr_process
,
825 de
->u
.CreateProcessInfo
.hThread
,
826 de
->u
.CreateProcessInfo
.lpThreadLocalBase
);
827 if (!dbg_curr_thread
)
829 WINE_ERR("Couldn't create thread\n");
832 dbg_init_current_process();
833 dbg_init_current_thread(de
->u
.CreateProcessInfo
.lpStartAddress
);
836 case EXIT_PROCESS_DEBUG_EVENT
:
837 WINE_TRACE("%08lx:%08lx: exit process (%ld)\n",
838 de
->dwProcessId
, de
->dwThreadId
, de
->u
.ExitProcess
.dwExitCode
);
840 if (dbg_curr_process
== NULL
)
842 WINE_ERR("Unknown process\n");
845 if (!SymCleanup(dbg_curr_process
->handle
))
846 dbg_printf("Couldn't initiate DbgHelp\n");
848 break_set_xpoints(FALSE
);
849 /* kill last thread */
850 dbg_del_thread(dbg_curr_process
->threads
);
851 dbg_del_process(dbg_curr_process
);
853 dbg_printf("Process of pid=0x%08lx has terminated\n", dbg_curr_pid
);
856 case CREATE_THREAD_DEBUG_EVENT
:
857 WINE_TRACE("%08lx:%08lx: create thread D @%08lx\n",
858 de
->dwProcessId
, de
->dwThreadId
,
859 (unsigned long)(void*)de
->u
.CreateThread
.lpStartAddress
);
861 if (dbg_curr_process
== NULL
)
863 WINE_ERR("Unknown process\n");
866 if (dbg_get_thread(dbg_curr_process
, de
->dwThreadId
) != NULL
)
868 WINE_TRACE("Thread already listed, skipping\n");
872 dbg_curr_thread
= dbg_add_thread(dbg_curr_process
,
874 de
->u
.CreateThread
.hThread
,
875 de
->u
.CreateThread
.lpThreadLocalBase
);
876 if (!dbg_curr_thread
)
878 WINE_ERR("Couldn't create thread\n");
881 dbg_init_current_thread(de
->u
.CreateThread
.lpStartAddress
);
884 case EXIT_THREAD_DEBUG_EVENT
:
885 WINE_TRACE("%08lx:%08lx: exit thread (%ld)\n",
886 de
->dwProcessId
, de
->dwThreadId
, de
->u
.ExitThread
.dwExitCode
);
888 if (dbg_curr_thread
== NULL
)
890 WINE_ERR("Unknown thread\n");
893 /* FIXME: remove break point set on thread startup */
894 dbg_del_thread(dbg_curr_thread
);
897 case LOAD_DLL_DEBUG_EVENT
:
898 if (dbg_curr_thread
== NULL
)
900 WINE_ERR("Unknown thread\n");
903 memory_get_string_indirect(dbg_curr_process
,
904 de
->u
.LoadDll
.lpImageName
,
905 de
->u
.LoadDll
.fUnicode
,
906 buffer
, sizeof(buffer
));
908 WINE_TRACE("%08lx:%08lx: loads DLL %s @%08lx (%ld<%ld>)\n",
909 de
->dwProcessId
, de
->dwThreadId
,
910 buffer
, (unsigned long)de
->u
.LoadDll
.lpBaseOfDll
,
911 de
->u
.LoadDll
.dwDebugInfoFileOffset
,
912 de
->u
.LoadDll
.nDebugInfoSize
);
914 SymLoadModule(dbg_curr_process
->handle
, de
->u
.LoadDll
.hFile
, buffer
, NULL
,
915 (unsigned long)de
->u
.LoadDll
.lpBaseOfDll
, 0);
916 break_set_xpoints(FALSE
);
917 break_check_delayed_bp();
918 break_set_xpoints(TRUE
);
919 if (DBG_IVAR(BreakOnDllLoad
))
921 dbg_printf("Stopping on DLL %s loading at 0x%08lx\n",
922 buffer
, (unsigned long)de
->u
.LoadDll
.lpBaseOfDll
);
923 if (dbg_fetch_context()) cont
= 0;
927 case UNLOAD_DLL_DEBUG_EVENT
:
928 WINE_TRACE("%08lx:%08lx: unload DLL @%08lx\n",
929 de
->dwProcessId
, de
->dwThreadId
,
930 (unsigned long)de
->u
.UnloadDll
.lpBaseOfDll
);
931 break_delete_xpoints_from_module((unsigned long)de
->u
.UnloadDll
.lpBaseOfDll
);
932 SymUnloadModule(dbg_curr_process
->handle
,
933 (unsigned long)de
->u
.UnloadDll
.lpBaseOfDll
);
936 case OUTPUT_DEBUG_STRING_EVENT
:
937 if (dbg_curr_thread
== NULL
)
939 WINE_ERR("Unknown thread\n");
943 memory_get_string(dbg_curr_process
,
944 de
->u
.DebugString
.lpDebugStringData
, TRUE
,
945 de
->u
.DebugString
.fUnicode
, buffer
, sizeof(buffer
));
946 WINE_TRACE("%08lx:%08lx: output debug string (%s)\n",
947 de
->dwProcessId
, de
->dwThreadId
, buffer
);
951 WINE_TRACE("%08lx:%08lx: rip error=%ld type=%ld\n",
952 de
->dwProcessId
, de
->dwThreadId
, de
->u
.RipInfo
.dwError
,
953 de
->u
.RipInfo
.dwType
);
957 WINE_TRACE("%08lx:%08lx: unknown event (%ld)\n",
958 de
->dwProcessId
, de
->dwThreadId
, de
->dwDebugEventCode
);
960 if (!cont
) return TRUE
; /* stop execution */
961 ContinueDebugEvent(de
->dwProcessId
, de
->dwThreadId
, cont
);
962 return FALSE
; /* continue execution */
965 static void dbg_resume_debuggee(DWORD cont
)
967 if (dbg_curr_thread
->in_exception
)
971 dbg_exception_epilog();
972 memory_get_current_pc(&addr
);
973 WINE_TRACE("Exiting debugger PC=0x%lx mode=%d count=%d\n",
974 addr
.Offset
, dbg_curr_thread
->exec_mode
,
975 dbg_curr_thread
->exec_count
);
978 if (!SetThreadContext(dbg_curr_thread
->handle
, &dbg_context
))
979 dbg_printf("Cannot set ctx on %lu\n", dbg_curr_tid
);
982 dbg_interactiveP
= FALSE
;
983 if (!ContinueDebugEvent(dbg_curr_pid
, dbg_curr_tid
, cont
))
984 dbg_printf("Cannot continue on %lu (%lu)\n", dbg_curr_tid
, cont
);
987 void dbg_wait_next_exception(DWORD cont
, int count
, int mode
)
992 if (cont
== DBG_CONTINUE
)
994 dbg_curr_thread
->exec_count
= count
;
995 dbg_curr_thread
->exec_mode
= mode
;
997 dbg_resume_debuggee(cont
);
999 while (dbg_curr_process
&& WaitForDebugEvent(&de
, INFINITE
))
1001 if (dbg_handle_debug_event(&de
)) break;
1003 if (!dbg_curr_process
) return;
1004 dbg_interactiveP
= TRUE
;
1006 memory_get_current_pc(&addr
);
1007 WINE_TRACE("Entering debugger PC=0x%lx mode=%d count=%d\n",
1008 addr
.Offset
, dbg_curr_thread
->exec_mode
,
1009 dbg_curr_thread
->exec_count
);
1012 static unsigned dbg_main_loop(void)
1016 if (dbg_curr_process
)
1017 dbg_printf("WineDbg starting on pid 0x%lx\n", dbg_curr_pid
);
1019 /* wait for first exception */
1020 while (WaitForDebugEvent(&de
, INFINITE
))
1022 if (dbg_handle_debug_event(&de
)) break;
1024 switch (dbg_action_mode
)
1026 case automatic_mode
:
1027 /* print some extra information */
1028 dbg_printf("Modules:\n");
1029 info_win32_module(0); /* print all modules */
1030 dbg_printf("Threads:\n");
1031 info_win32_threads();
1034 dbg_interactiveP
= TRUE
;
1037 dbg_printf("WineDbg terminated on pid 0x%lx\n", dbg_curr_pid
);
1042 static unsigned dbg_start_debuggee(LPSTR cmdLine
)
1044 PROCESS_INFORMATION info
;
1045 STARTUPINFOA startup
;
1047 memset(&startup
, 0, sizeof(startup
));
1048 startup
.cb
= sizeof(startup
);
1049 startup
.dwFlags
= STARTF_USESHOWWINDOW
;
1050 startup
.wShowWindow
= SW_SHOWNORMAL
;
1052 /* FIXME: shouldn't need the CREATE_NEW_CONSOLE, but as usual CUI:s need it
1055 if (!CreateProcess(NULL
, cmdLine
, NULL
, NULL
,
1057 DEBUG_PROCESS
|DEBUG_ONLY_THIS_PROCESS
|CREATE_NEW_CONSOLE
,
1058 NULL
, NULL
, &startup
, &info
))
1060 dbg_printf("Couldn't start process '%s'\n", cmdLine
);
1063 if (!info
.dwProcessId
)
1065 /* this happens when the program being run is not a Wine binary
1066 * (for example, a shell wrapper around a WineLib app)
1068 /* Current fix: list running processes and let the user attach
1069 * to one of them (sic)
1070 * FIXME: implement a real fix => grab the process (from the
1071 * running processes) from its name
1073 dbg_printf("Debuggee has been started (%s)\n"
1074 "But WineDbg isn't attached to it. Maybe you're trying to debug a winelib wrapper ??\n"
1075 "Try to attach to one of those processes:\n", cmdLine
);
1076 /* FIXME: (HACK) we need some time before the wrapper executes the winelib app */
1078 info_win32_processes();
1081 dbg_curr_pid
= info
.dwProcessId
;
1082 if (!(dbg_curr_process
= dbg_add_process(dbg_curr_pid
, 0))) return FALSE
;
1087 void dbg_run_debuggee(const char* args
)
1091 WINE_FIXME("Re-running current program with %s as args is broken\n", args
);
1098 if (!dbg_last_cmd_line
)
1100 dbg_printf("Cannot find previously used command line.\n");
1103 dbg_start_debuggee(dbg_last_cmd_line
);
1104 while (dbg_curr_process
&& WaitForDebugEvent(&de
, INFINITE
))
1106 if (dbg_handle_debug_event(&de
)) break;
1108 source_list_from_addr(NULL
, 0);
1112 BOOL
dbg_interrupt_debuggee(void)
1114 if (!dbg_process_list
) return FALSE
;
1115 /* FIXME: since we likely have a single process, signal the first process
1118 if (dbg_process_list
->next
) dbg_printf("Ctrl-C: only stopping the first process\n");
1119 else dbg_printf("Ctrl-C: stopping debuggee\n");
1120 dbg_process_list
->continue_on_first_exception
= FALSE
;
1121 return DebugBreakProcess(dbg_process_list
->handle
);
1124 static BOOL WINAPI
ctrl_c_handler(DWORD dwCtrlType
)
1126 if (dwCtrlType
== CTRL_C_EVENT
)
1128 return dbg_interrupt_debuggee();
1133 static void dbg_init_console(void)
1135 /* set our control-C handler */
1136 SetConsoleCtrlHandler(ctrl_c_handler
, TRUE
);
1138 /* set our own title */
1139 SetConsoleTitle("Wine Debugger");
1142 static int dbg_winedbg_usage(void)
1144 dbg_printf("Usage: winedbg [--command cmd|--auto] [--gdb [--no-start] [--with-xterm]] cmdline\n");
1148 struct backend_cpu
* be_cpu
;
1150 extern struct backend_cpu be_i386
;
1152 extern struct backend_cpu be_ppc
;
1154 extern struct backend_cpu be_alpha
;
1159 int main(int argc
, char** argv
)
1162 unsigned gdb_flags
= 0;
1173 /* Initialize the output */
1174 dbg_houtput
= GetStdHandle(STD_OUTPUT_HANDLE
);
1176 /* Initialize internal vars */
1177 if (!dbg_load_internal_vars()) return -1;
1180 while (argc
> 1 && argv
[1][0] == '-')
1182 if (!strcmp(argv
[1], "--command"))
1185 arg_command
= HeapAlloc(GetProcessHeap(), 0, strlen(argv
[1])+2);
1186 strcpy(arg_command
, argv
[1]);
1187 strcat(arg_command
, "\n");
1191 if (!strcmp(argv
[1], "--auto"))
1193 if (dbg_action_mode
!= none_mode
) return dbg_winedbg_usage();
1194 dbg_action_mode
= automatic_mode
;
1195 /* force some internal variables */
1196 DBG_IVAR(BreakOnDllLoad
) = 0;
1198 dbg_houtput
= GetStdHandle(STD_ERROR_HANDLE
);
1201 if (!strcmp(argv
[1], "--gdb"))
1203 if (dbg_action_mode
!= none_mode
) return dbg_winedbg_usage();
1204 dbg_action_mode
= gdb_mode
;
1208 if (strcmp(argv
[1], "--no-start") == 0 && dbg_action_mode
== gdb_mode
)
1211 argc
--; argv
++; /* as we don't use argv[0] */
1214 if (strcmp(argv
[1], "--with-xterm") == 0 && dbg_action_mode
== gdb_mode
)
1217 argc
--; argv
++; /* as we don't use argv[0] */
1220 return dbg_winedbg_usage();
1223 if (dbg_action_mode
== none_mode
) dbg_action_mode
= winedbg_mode
;
1225 /* try the form <myself> pid */
1226 if (dbg_curr_pid
== 0 && argc
== 2)
1230 dbg_curr_pid
= strtol(argv
[1], &ptr
, 10);
1231 if (dbg_curr_pid
== 0 || ptr
!= argv
[1] + strlen(argv
[1]) ||
1232 !dbg_attach_debuggee(dbg_curr_pid
, dbg_action_mode
!= gdb_mode
, FALSE
))
1236 /* try the form <myself> pid evt (Win32 JIT debugger) */
1237 if (dbg_curr_pid
== 0 && argc
== 3)
1243 if ((pid
= strtol(argv
[1], &ptr
, 10)) != 0 && ptr
!= NULL
&&
1244 (hEvent
= (HANDLE
)strtol(argv
[2], &ptr
, 10)) != 0 && ptr
!= NULL
)
1246 if (!dbg_attach_debuggee(pid
, TRUE
, FALSE
))
1248 /* don't care about result */
1252 if (!SetEvent(hEvent
))
1254 WINE_ERR("Invalid event handle: %p\n", hEvent
);
1257 CloseHandle(hEvent
);
1262 if (dbg_curr_pid
== 0 && argc
> 1)
1267 if (!(cmdLine
= HeapAlloc(GetProcessHeap(), 0, len
= 1))) goto oom_leave
;
1270 for (i
= 1; i
< argc
; i
++)
1272 len
+= strlen(argv
[i
]) + 1;
1273 if (!(cmdLine
= HeapReAlloc(GetProcessHeap(), 0, cmdLine
, len
)))
1275 strcat(cmdLine
, argv
[i
]);
1276 cmdLine
[len
- 2] = ' ';
1277 cmdLine
[len
- 1] = '\0';
1280 if (!dbg_start_debuggee(cmdLine
))
1282 dbg_printf("Couldn't start process '%s'\n", cmdLine
);
1285 dbg_last_cmd_line
= cmdLine
;
1287 /* don't save local vars in gdb mode */
1288 if (dbg_action_mode
== gdb_mode
&& dbg_curr_pid
)
1289 return gdb_remote(gdb_flags
);
1293 SymSetOptions((SymGetOptions() & ~(SYMOPT_UNDNAME
)) |
1294 SYMOPT_LOAD_LINES
| SYMOPT_DEFERRED_LOADS
| SYMOPT_AUTO_PUBLICS
);
1296 retv
= dbg_main_loop();
1297 /* don't save modified variables in auto mode */
1298 if (dbg_action_mode
!= automatic_mode
) dbg_save_internal_vars();
1304 dbg_printf("Out of memory\n");