[PATCH 01/12] [WineDbg]: active targets
Eric Pouech
eric.pouech at wanadoo.fr
Fri Feb 24 15:12:59 CST 2006
Move all code related to an 'active' target (ie a running process)
from winedbg.c to tgt_active.c
This patch is a no-op (apart from moving, it exports a couple of
static vars/funcs, that will handled with in next patches)
A+
---
programs/winedbg/debugger.h | 13 +
programs/winedbg/tgt_active.c | 746 +++++++++++++++++++++++++++++++++++++++++
programs/winedbg/winedbg.c | 742 -----------------------------------------
3 files changed, 755 insertions(+), 746 deletions(-)
diff --git a/programs/winedbg/debugger.h b/programs/winedbg/debugger.h
index 89ff56f..3c4acbf 100644
--- a/programs/winedbg/debugger.h
+++ b/programs/winedbg/debugger.h
@@ -365,6 +365,15 @@ extern void symbol_info(cons
extern int symbol_info_locals(void);
extern BOOL symbol_is_local(const char* name);
+ /* tgt_active.c */
+extern void dbg_run_debuggee(const char* args);
+extern void dbg_wait_next_exception(DWORD cont, int count, int mode);
+ /* temporary for tgt_active.c */
+extern enum dbg_action_mode {none_mode = 0, winedbg_mode, automatic_mode, gdb_mode} dbg_action_mode;
+extern char* dbg_last_cmd_line;
+extern unsigned dbg_main_loop(HANDLE);
+extern unsigned dbg_start_debuggee(LPSTR cmdLine);
+
/* tgt_minidump.c */
extern void minidump_write(const char*, const EXCEPTION_RECORD*);
@@ -393,7 +402,6 @@ extern const struct dbg_internal_var* db
extern BOOL dbg_attach_debuggee(DWORD pid, BOOL cofe, BOOL wfe);
extern BOOL dbg_detach_debuggee(void);
extern BOOL dbg_interrupt_debuggee(void);
-extern void dbg_run_debuggee(const char* args);
extern struct dbg_process* dbg_add_process(DWORD pid, HANDLE h);
extern void dbg_set_process_name(struct dbg_process* p, const char* name);
extern struct dbg_process* dbg_get_process(DWORD pid);
@@ -401,10 +409,9 @@ extern void dbg_del_process(
struct dbg_thread* dbg_add_thread(struct dbg_process* p, DWORD tid, HANDLE h, void* teb);
extern struct dbg_thread* dbg_get_thread(struct dbg_process* p, DWORD tid);
extern void dbg_del_thread(struct dbg_thread* t);
-extern void dbg_wait_next_exception(DWORD cont, int count, int mode);
extern BOOL dbg_get_debuggee_info(HANDLE hProcess, IMAGEHLP_MODULE* imh_mod);
-/* gdbproxy.c */
+ /* gdbproxy.c */
extern BOOL gdb_remote(unsigned int);
static inline BOOL dbg_read_memory(const void* addr, void* buffer, size_t len)
diff --git a/programs/winedbg/tgt_active.c b/programs/winedbg/tgt_active.c
index 9644987..5c7dfbe 100644
--- a/programs/winedbg/tgt_active.c
+++ b/programs/winedbg/tgt_active.c
@@ -1,7 +1,7 @@
/*
* Wine debugger - back-end for an active target
*
- * Copyright 2005 Eric Pouech
+ * Copyright 2000-2006 Eric Pouech
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -32,8 +32,752 @@
WINE_DEFAULT_DEBUG_CHANNEL(winedbg);
+/*static*/ char* dbg_last_cmd_line = NULL;
+/*static*/ enum dbg_action_mode dbg_action_mode;
+
struct be_process_io be_process_active_io =
{
ReadProcessMemory,
WriteProcessMemory,
};
+
+static void dbg_init_current_process(void)
+{
+}
+
+static void dbg_init_current_thread(void* start)
+{
+ if (start)
+ {
+ if (dbg_curr_process->threads &&
+ !dbg_curr_process->threads->next && /* first thread ? */
+ DBG_IVAR(BreakAllThreadsStartup))
+ {
+ ADDRESS addr;
+
+ break_set_xpoints(FALSE);
+ addr.Mode = AddrModeFlat;
+ addr.Offset = (DWORD)start;
+ break_add_break(&addr, TRUE, TRUE);
+ break_set_xpoints(TRUE);
+ }
+ }
+}
+
+static unsigned dbg_handle_debug_event(DEBUG_EVENT* de);
+
+/******************************************************************
+ * dbg_attach_debuggee
+ *
+ * Sets the debuggee to <pid>
+ * cofe instructs winedbg what to do when first exception is received
+ * (break=FALSE, continue=TRUE)
+ * wfe is set to TRUE if dbg_attach_debuggee should also proceed with all debug events
+ * until the first exception is received (aka: attach to an already running process)
+ */
+BOOL dbg_attach_debuggee(DWORD pid, BOOL cofe, BOOL wfe)
+{
+ DEBUG_EVENT de;
+
+ if (!(dbg_curr_process = dbg_add_process(pid, 0))) return FALSE;
+
+ if (!DebugActiveProcess(pid))
+ {
+ dbg_printf("Can't attach process %lx: error %ld\n", pid, GetLastError());
+ dbg_del_process(dbg_curr_process);
+ return FALSE;
+ }
+ dbg_curr_process->continue_on_first_exception = cofe;
+
+ if (wfe) /* shall we proceed all debug events until we get an exception ? */
+ {
+ dbg_interactiveP = FALSE;
+ while (dbg_curr_process && WaitForDebugEvent(&de, INFINITE))
+ {
+ if (dbg_handle_debug_event(&de)) break;
+ }
+ if (dbg_curr_process) dbg_interactiveP = TRUE;
+ }
+ return TRUE;
+}
+
+BOOL dbg_detach_debuggee(void)
+{
+ /* remove all set breakpoints in debuggee code */
+ break_set_xpoints(FALSE);
+ /* needed for single stepping (ugly).
+ * should this be handled inside the server ???
+ */
+ be_cpu->single_step(&dbg_context, FALSE);
+ SetThreadContext(dbg_curr_thread->handle, &dbg_context);
+ if (dbg_curr_thread->in_exception)
+ ContinueDebugEvent(dbg_curr_pid, dbg_curr_tid, DBG_CONTINUE);
+ if (!DebugActiveProcessStop(dbg_curr_pid)) return FALSE;
+ dbg_del_process(dbg_curr_process);
+
+ return TRUE;
+}
+
+static unsigned dbg_fetch_context(void)
+{
+ dbg_context.ContextFlags = CONTEXT_CONTROL
+ | CONTEXT_INTEGER
+#ifdef CONTEXT_SEGMENTS
+ | CONTEXT_SEGMENTS
+#endif
+#ifdef CONTEXT_DEBUG_REGISTERS
+ | CONTEXT_DEBUG_REGISTERS
+#endif
+ ;
+ if (!GetThreadContext(dbg_curr_thread->handle, &dbg_context))
+ {
+ WINE_WARN("Can't get thread's context\n");
+ return FALSE;
+ }
+ return TRUE;
+}
+
+static unsigned dbg_exception_prolog(BOOL is_debug, const EXCEPTION_RECORD* rec)
+{
+ ADDRESS addr;
+ BOOL is_break;
+
+ memory_get_current_pc(&addr);
+ break_suspend_execution();
+ dbg_curr_thread->excpt_record = *rec;
+ dbg_curr_thread->in_exception = TRUE;
+
+ if (!is_debug)
+ {
+ switch (addr.Mode)
+ {
+ case AddrModeFlat: dbg_printf(" in 32-bit code (0x%08lx)", addr.Offset); break;
+ case AddrModeReal: dbg_printf(" in vm86 code (%04x:%04lx)", addr.Segment, addr.Offset); break;
+ case AddrMode1616: dbg_printf(" in 16-bit code (%04x:%04lx)", addr.Segment, addr.Offset); break;
+ case AddrMode1632: dbg_printf(" in 32-bit code (%04x:%08lx)", addr.Segment, addr.Offset); break;
+ default: dbg_printf(" bad address");
+ }
+ dbg_printf(".\n");
+ }
+
+ /* this will resynchronize builtin dbghelp's internal ELF module list */
+ SymLoadModule(dbg_curr_process->handle, 0, 0, 0, 0, 0);
+
+ /*
+ * Do a quiet backtrace so that we have an idea of what the situation
+ * is WRT the source files.
+ */
+ stack_fetch_frames();
+ if (is_debug &&
+ break_should_continue(&addr, rec->ExceptionCode, &dbg_curr_thread->exec_count, &is_break))
+ return FALSE;
+
+ if (addr.Mode != dbg_curr_thread->addr_mode)
+ {
+ const char* name = NULL;
+
+ switch (addr.Mode)
+ {
+ case AddrMode1616: name = "16 bit"; break;
+ case AddrMode1632: name = "32 bit"; break;
+ case AddrModeReal: name = "vm86"; break;
+ case AddrModeFlat: name = "32 bit"; break;
+ }
+
+ dbg_printf("In %s mode.\n", name);
+ dbg_curr_thread->addr_mode = addr.Mode;
+ }
+ display_print();
+
+ if (!is_debug)
+ {
+ /* This is a real crash, dump some info */
+ be_cpu->print_context(dbg_curr_thread->handle, &dbg_context);
+ stack_info();
+ be_cpu->print_segment_info(dbg_curr_thread->handle, &dbg_context);
+ stack_backtrace(dbg_curr_tid);
+ }
+ else
+ {
+ static char* last_name;
+ static char* last_file;
+
+ char buffer[sizeof(SYMBOL_INFO) + 256];
+ SYMBOL_INFO* si = (SYMBOL_INFO*)buffer;
+ void* lin = memory_to_linear_addr(&addr);
+ DWORD64 disp64;
+ IMAGEHLP_LINE il;
+ DWORD disp;
+
+ si->SizeOfStruct = sizeof(*si);
+ si->MaxNameLen = 256;
+ il.SizeOfStruct = sizeof(il);
+ if (SymFromAddr(dbg_curr_process->handle, (DWORD_PTR)lin, &disp64, si) &&
+ SymGetLineFromAddr(dbg_curr_process->handle, (DWORD_PTR)lin, &disp, &il))
+ {
+ if ((!last_name || strcmp(last_name, si->Name)) ||
+ (!last_file || strcmp(last_file, il.FileName)))
+ {
+ HeapFree(GetProcessHeap(), 0, last_name);
+ HeapFree(GetProcessHeap(), 0, last_file);
+ last_name = strcpy(HeapAlloc(GetProcessHeap(), 0, strlen(si->Name) + 1), si->Name);
+ last_file = strcpy(HeapAlloc(GetProcessHeap(), 0, strlen(il.FileName) + 1), il.FileName);
+ dbg_printf("%s () at %s:%ld\n", last_name, last_file, il.LineNumber);
+ }
+ }
+ }
+ if (!is_debug || is_break ||
+ dbg_curr_thread->exec_mode == dbg_exec_step_over_insn ||
+ dbg_curr_thread->exec_mode == dbg_exec_step_into_insn)
+ {
+ ADDRESS tmp = addr;
+ /* Show where we crashed */
+ memory_disasm_one_insn(&tmp);
+ }
+ source_list_from_addr(&addr, 0);
+
+ return TRUE;
+}
+
+static void dbg_exception_epilog(void)
+{
+ break_restart_execution(dbg_curr_thread->exec_count);
+ /*
+ * This will have gotten absorbed into the breakpoint info
+ * if it was used. Otherwise it would have been ignored.
+ * In any case, we don't mess with it any more.
+ */
+ if (dbg_curr_thread->exec_mode == dbg_exec_cont)
+ dbg_curr_thread->exec_count = 0;
+ dbg_curr_thread->in_exception = FALSE;
+}
+
+static DWORD dbg_handle_exception(const EXCEPTION_RECORD* rec, BOOL first_chance)
+{
+ BOOL is_debug = FALSE;
+ THREADNAME_INFO* pThreadName;
+ struct dbg_thread* pThread;
+
+ assert(dbg_curr_thread);
+
+ WINE_TRACE("exception=%lx first_chance=%c\n",
+ rec->ExceptionCode, first_chance ? 'Y' : 'N');
+
+ switch (rec->ExceptionCode)
+ {
+ case EXCEPTION_BREAKPOINT:
+ case EXCEPTION_SINGLE_STEP:
+ is_debug = TRUE;
+ break;
+ case EXCEPTION_NAME_THREAD:
+ pThreadName = (THREADNAME_INFO*)(rec->ExceptionInformation);
+ if (pThreadName->dwThreadID == -1)
+ pThread = dbg_curr_thread;
+ else
+ pThread = dbg_get_thread(dbg_curr_process, pThreadName->dwThreadID);
+
+ if (dbg_read_memory(pThreadName->szName, pThread->name, 9))
+ dbg_printf("Thread ID=0x%lx renamed using MS VC6 extension (name==\"%s\")\n",
+ pThread->tid, pThread->name);
+ return DBG_CONTINUE;
+ }
+
+ if (first_chance && !is_debug && !DBG_IVAR(BreakOnFirstChance) &&
+ !(rec->ExceptionFlags & EH_STACK_INVALID))
+ {
+ /* pass exception to program except for debug exceptions */
+ return DBG_EXCEPTION_NOT_HANDLED;
+ }
+
+ if (!is_debug)
+ {
+ /* print some infos */
+ dbg_printf("%s: ",
+ first_chance ? "First chance exception" : "Unhandled exception");
+ switch (rec->ExceptionCode)
+ {
+ case EXCEPTION_INT_DIVIDE_BY_ZERO:
+ dbg_printf("divide by zero");
+ break;
+ case EXCEPTION_INT_OVERFLOW:
+ dbg_printf("overflow");
+ break;
+ case EXCEPTION_ARRAY_BOUNDS_EXCEEDED:
+ dbg_printf("array bounds");
+ break;
+ case EXCEPTION_ILLEGAL_INSTRUCTION:
+ dbg_printf("illegal instruction");
+ break;
+ case EXCEPTION_STACK_OVERFLOW:
+ dbg_printf("stack overflow");
+ break;
+ case EXCEPTION_PRIV_INSTRUCTION:
+ dbg_printf("privileged instruction");
+ break;
+ case EXCEPTION_ACCESS_VIOLATION:
+ if (rec->NumberParameters == 2)
+ dbg_printf("page fault on %s access to 0x%08lx",
+ rec->ExceptionInformation[0] ? "write" : "read",
+ rec->ExceptionInformation[1]);
+ else
+ dbg_printf("page fault");
+ break;
+ case EXCEPTION_DATATYPE_MISALIGNMENT:
+ dbg_printf("Alignment");
+ break;
+ case DBG_CONTROL_C:
+ dbg_printf("^C");
+ break;
+ case CONTROL_C_EXIT:
+ dbg_printf("^C");
+ break;
+ case STATUS_POSSIBLE_DEADLOCK:
+ {
+ ADDRESS addr;
+
+ addr.Mode = AddrModeFlat;
+ addr.Offset = rec->ExceptionInformation[0];
+
+ dbg_printf("wait failed on critical section ");
+ print_address(&addr, FALSE);
+ }
+ if (!DBG_IVAR(BreakOnCritSectTimeOut))
+ {
+ dbg_printf("\n");
+ return DBG_EXCEPTION_NOT_HANDLED;
+ }
+ break;
+ case EXCEPTION_WINE_STUB:
+ {
+ char dll[32], name[64];
+ memory_get_string(dbg_curr_process,
+ (void*)rec->ExceptionInformation[0], TRUE, FALSE,
+ dll, sizeof(dll));
+ if (HIWORD(rec->ExceptionInformation[1]))
+ memory_get_string(dbg_curr_process,
+ (void*)rec->ExceptionInformation[1], TRUE, FALSE,
+ name, sizeof(name));
+ else
+ sprintf( name, "%ld", rec->ExceptionInformation[1] );
+ dbg_printf("unimplemented function %s.%s called", dll, name);
+ }
+ break;
+ case EXCEPTION_WINE_ASSERTION:
+ dbg_printf("assertion failed");
+ break;
+ case EXCEPTION_VM86_INTx:
+ dbg_printf("interrupt %02lx in vm86 mode", rec->ExceptionInformation[0]);
+ break;
+ case EXCEPTION_VM86_STI:
+ dbg_printf("sti in vm86 mode");
+ break;
+ case EXCEPTION_VM86_PICRETURN:
+ dbg_printf("PIC return in vm86 mode");
+ break;
+ case EXCEPTION_FLT_DENORMAL_OPERAND:
+ dbg_printf("denormal float operand");
+ break;
+ case EXCEPTION_FLT_DIVIDE_BY_ZERO:
+ dbg_printf("divide by zero");
+ break;
+ case EXCEPTION_FLT_INEXACT_RESULT:
+ dbg_printf("inexact float result");
+ break;
+ case EXCEPTION_FLT_INVALID_OPERATION:
+ dbg_printf("invalid float operation");
+ break;
+ case EXCEPTION_FLT_OVERFLOW:
+ dbg_printf("floating pointer overflow");
+ break;
+ case EXCEPTION_FLT_UNDERFLOW:
+ dbg_printf("floating pointer underflow");
+ break;
+ case EXCEPTION_FLT_STACK_CHECK:
+ dbg_printf("floating point stack check");
+ break;
+ default:
+ dbg_printf("0x%08lx", rec->ExceptionCode);
+ break;
+ }
+ }
+ if( (rec->ExceptionFlags & EH_STACK_INVALID) ) {
+ dbg_printf( ", invalid program stack" );
+ }
+
+ if (dbg_action_mode == automatic_mode)
+ {
+ dbg_exception_prolog(is_debug, rec);
+ dbg_exception_epilog();
+ return 0; /* terminate execution */
+ }
+
+ if (dbg_exception_prolog(is_debug, rec))
+ {
+ dbg_interactiveP = TRUE;
+ return 0;
+ }
+ dbg_exception_epilog();
+
+ return DBG_CONTINUE;
+}
+
+static unsigned dbg_handle_debug_event(DEBUG_EVENT* de)
+{
+ char buffer[256];
+ DWORD cont = DBG_CONTINUE;
+
+ dbg_curr_pid = de->dwProcessId;
+ dbg_curr_tid = de->dwThreadId;
+
+ if ((dbg_curr_process = dbg_get_process(de->dwProcessId)) != NULL)
+ dbg_curr_thread = dbg_get_thread(dbg_curr_process, de->dwThreadId);
+ else
+ dbg_curr_thread = NULL;
+
+ switch (de->dwDebugEventCode)
+ {
+ case EXCEPTION_DEBUG_EVENT:
+ if (!dbg_curr_thread)
+ {
+ WINE_ERR("%08lx:%08lx: not a registered process or thread (perhaps a 16 bit one ?)\n",
+ de->dwProcessId, de->dwThreadId);
+ break;
+ }
+
+ WINE_TRACE("%08lx:%08lx: exception code=%08lx\n",
+ de->dwProcessId, de->dwThreadId,
+ de->u.Exception.ExceptionRecord.ExceptionCode);
+
+ if (dbg_curr_process->continue_on_first_exception)
+ {
+ dbg_curr_process->continue_on_first_exception = FALSE;
+ if (!DBG_IVAR(BreakOnAttach)) break;
+ }
+ if (dbg_fetch_context())
+ {
+ cont = dbg_handle_exception(&de->u.Exception.ExceptionRecord,
+ de->u.Exception.dwFirstChance);
+ if (cont && dbg_curr_thread)
+ {
+ SetThreadContext(dbg_curr_thread->handle, &dbg_context);
+ }
+ }
+ break;
+
+ case CREATE_PROCESS_DEBUG_EVENT:
+ dbg_curr_process = dbg_add_process(de->dwProcessId,
+ de->u.CreateProcessInfo.hProcess);
+ if (dbg_curr_process == NULL)
+ {
+ WINE_ERR("Couldn't create process\n");
+ break;
+ }
+ memory_get_string_indirect(dbg_curr_process,
+ de->u.CreateProcessInfo.lpImageName,
+ de->u.CreateProcessInfo.fUnicode,
+ buffer, sizeof(buffer));
+ if (!buffer[0]) strcpy(buffer, "<Debugged Process>");
+
+ WINE_TRACE("%08lx:%08lx: create process '%s'/%p @%08lx (%ld<%ld>)\n",
+ de->dwProcessId, de->dwThreadId,
+ buffer, de->u.CreateProcessInfo.lpImageName,
+ (unsigned long)(void*)de->u.CreateProcessInfo.lpStartAddress,
+ de->u.CreateProcessInfo.dwDebugInfoFileOffset,
+ de->u.CreateProcessInfo.nDebugInfoSize);
+ dbg_set_process_name(dbg_curr_process, buffer);
+
+ if (!SymInitialize(dbg_curr_process->handle, NULL, TRUE))
+ dbg_printf("Couldn't initiate DbgHelp\n");
+
+ WINE_TRACE("%08lx:%08lx: create thread I @%08lx\n",
+ de->dwProcessId, de->dwThreadId,
+ (unsigned long)(void*)de->u.CreateProcessInfo.lpStartAddress);
+
+ dbg_curr_thread = dbg_add_thread(dbg_curr_process,
+ de->dwThreadId,
+ de->u.CreateProcessInfo.hThread,
+ de->u.CreateProcessInfo.lpThreadLocalBase);
+ if (!dbg_curr_thread)
+ {
+ WINE_ERR("Couldn't create thread\n");
+ break;
+ }
+ dbg_init_current_process();
+ dbg_init_current_thread(de->u.CreateProcessInfo.lpStartAddress);
+ break;
+
+ case EXIT_PROCESS_DEBUG_EVENT:
+ WINE_TRACE("%08lx:%08lx: exit process (%ld)\n",
+ de->dwProcessId, de->dwThreadId, de->u.ExitProcess.dwExitCode);
+
+ if (dbg_curr_process == NULL)
+ {
+ WINE_ERR("Unknown process\n");
+ break;
+ }
+ if (!SymCleanup(dbg_curr_process->handle))
+ dbg_printf("Couldn't initiate DbgHelp\n");
+ /* just in case */
+ break_set_xpoints(FALSE);
+ /* kill last thread */
+ dbg_del_thread(dbg_curr_process->threads);
+ dbg_del_process(dbg_curr_process);
+
+ dbg_printf("Process of pid=0x%08lx has terminated\n", dbg_curr_pid);
+ break;
+
+ case CREATE_THREAD_DEBUG_EVENT:
+ WINE_TRACE("%08lx:%08lx: create thread D @%08lx\n",
+ de->dwProcessId, de->dwThreadId,
+ (unsigned long)(void*)de->u.CreateThread.lpStartAddress);
+
+ if (dbg_curr_process == NULL)
+ {
+ WINE_ERR("Unknown process\n");
+ break;
+ }
+ if (dbg_get_thread(dbg_curr_process, de->dwThreadId) != NULL)
+ {
+ WINE_TRACE("Thread already listed, skipping\n");
+ break;
+ }
+
+ dbg_curr_thread = dbg_add_thread(dbg_curr_process,
+ de->dwThreadId,
+ de->u.CreateThread.hThread,
+ de->u.CreateThread.lpThreadLocalBase);
+ if (!dbg_curr_thread)
+ {
+ WINE_ERR("Couldn't create thread\n");
+ break;
+ }
+ dbg_init_current_thread(de->u.CreateThread.lpStartAddress);
+ break;
+
+ case EXIT_THREAD_DEBUG_EVENT:
+ WINE_TRACE("%08lx:%08lx: exit thread (%ld)\n",
+ de->dwProcessId, de->dwThreadId, de->u.ExitThread.dwExitCode);
+
+ if (dbg_curr_thread == NULL)
+ {
+ WINE_ERR("Unknown thread\n");
+ break;
+ }
+ /* FIXME: remove break point set on thread startup */
+ dbg_del_thread(dbg_curr_thread);
+ break;
+
+ case LOAD_DLL_DEBUG_EVENT:
+ if (dbg_curr_thread == NULL)
+ {
+ WINE_ERR("Unknown thread\n");
+ break;
+ }
+ memory_get_string_indirect(dbg_curr_process,
+ de->u.LoadDll.lpImageName,
+ de->u.LoadDll.fUnicode,
+ buffer, sizeof(buffer));
+
+ WINE_TRACE("%08lx:%08lx: loads DLL %s @%08lx (%ld<%ld>)\n",
+ de->dwProcessId, de->dwThreadId,
+ buffer, (unsigned long)de->u.LoadDll.lpBaseOfDll,
+ de->u.LoadDll.dwDebugInfoFileOffset,
+ de->u.LoadDll.nDebugInfoSize);
+ SymLoadModule(dbg_curr_process->handle, de->u.LoadDll.hFile, buffer, NULL,
+ (unsigned long)de->u.LoadDll.lpBaseOfDll, 0);
+ break_set_xpoints(FALSE);
+ break_check_delayed_bp();
+ break_set_xpoints(TRUE);
+ if (DBG_IVAR(BreakOnDllLoad))
+ {
+ dbg_printf("Stopping on DLL %s loading at 0x%08lx\n",
+ buffer, (unsigned long)de->u.LoadDll.lpBaseOfDll);
+ if (dbg_fetch_context()) cont = 0;
+ }
+ break;
+
+ case UNLOAD_DLL_DEBUG_EVENT:
+ WINE_TRACE("%08lx:%08lx: unload DLL @%08lx\n",
+ de->dwProcessId, de->dwThreadId,
+ (unsigned long)de->u.UnloadDll.lpBaseOfDll);
+ break_delete_xpoints_from_module((unsigned long)de->u.UnloadDll.lpBaseOfDll);
+ SymUnloadModule(dbg_curr_process->handle,
+ (unsigned long)de->u.UnloadDll.lpBaseOfDll);
+ break;
+
+ case OUTPUT_DEBUG_STRING_EVENT:
+ if (dbg_curr_thread == NULL)
+ {
+ WINE_ERR("Unknown thread\n");
+ break;
+ }
+
+ memory_get_string(dbg_curr_process,
+ de->u.DebugString.lpDebugStringData, TRUE,
+ de->u.DebugString.fUnicode, buffer, sizeof(buffer));
+ WINE_TRACE("%08lx:%08lx: output debug string (%s)\n",
+ de->dwProcessId, de->dwThreadId, buffer);
+ break;
+
+ case RIP_EVENT:
+ WINE_TRACE("%08lx:%08lx: rip error=%ld type=%ld\n",
+ de->dwProcessId, de->dwThreadId, de->u.RipInfo.dwError,
+ de->u.RipInfo.dwType);
+ break;
+
+ default:
+ WINE_TRACE("%08lx:%08lx: unknown event (%ld)\n",
+ de->dwProcessId, de->dwThreadId, de->dwDebugEventCode);
+ }
+ if (!cont) return TRUE; /* stop execution */
+ ContinueDebugEvent(de->dwProcessId, de->dwThreadId, cont);
+ return FALSE; /* continue execution */
+}
+
+static void dbg_resume_debuggee(DWORD cont)
+{
+ if (dbg_curr_thread->in_exception)
+ {
+ ADDRESS addr;
+
+ dbg_exception_epilog();
+ memory_get_current_pc(&addr);
+ WINE_TRACE("Exiting debugger PC=0x%lx mode=%d count=%d\n",
+ addr.Offset, dbg_curr_thread->exec_mode,
+ dbg_curr_thread->exec_count);
+ if (dbg_curr_thread)
+ {
+ if (!SetThreadContext(dbg_curr_thread->handle, &dbg_context))
+ dbg_printf("Cannot set ctx on %lu\n", dbg_curr_tid);
+ }
+ }
+ dbg_interactiveP = FALSE;
+ if (!ContinueDebugEvent(dbg_curr_pid, dbg_curr_tid, cont))
+ dbg_printf("Cannot continue on %lu (%lu)\n", dbg_curr_tid, cont);
+}
+
+void dbg_wait_next_exception(DWORD cont, int count, int mode)
+{
+ DEBUG_EVENT de;
+ ADDRESS addr;
+
+ if (cont == DBG_CONTINUE)
+ {
+ dbg_curr_thread->exec_count = count;
+ dbg_curr_thread->exec_mode = mode;
+ }
+ dbg_resume_debuggee(cont);
+
+ while (dbg_curr_process && WaitForDebugEvent(&de, INFINITE))
+ {
+ if (dbg_handle_debug_event(&de)) break;
+ }
+ if (!dbg_curr_process) return;
+ dbg_interactiveP = TRUE;
+
+ memory_get_current_pc(&addr);
+ WINE_TRACE("Entering debugger PC=0x%lx mode=%d count=%d\n",
+ addr.Offset, dbg_curr_thread->exec_mode,
+ dbg_curr_thread->exec_count);
+}
+
+/*static*/ unsigned dbg_main_loop(HANDLE hFile)
+{
+ DEBUG_EVENT de;
+
+ if (dbg_curr_process)
+ dbg_printf("WineDbg starting on pid 0x%lx\n", dbg_curr_pid);
+
+ /* wait for first exception */
+ while (WaitForDebugEvent(&de, INFINITE))
+ {
+ if (dbg_handle_debug_event(&de)) break;
+ }
+ switch (dbg_action_mode)
+ {
+ case automatic_mode:
+ /* print some extra information */
+ dbg_printf("Modules:\n");
+ info_win32_module(0); /* print all modules */
+ dbg_printf("Threads:\n");
+ info_win32_threads();
+ break;
+ default:
+ dbg_interactiveP = TRUE;
+ parser_handle(hFile);
+ }
+ dbg_printf("WineDbg terminated on pid 0x%lx\n", dbg_curr_pid);
+
+ return 0;
+}
+
+/*static*/ unsigned dbg_start_debuggee(LPSTR cmdLine)
+{
+ PROCESS_INFORMATION info;
+ STARTUPINFOA startup;
+
+ memset(&startup, 0, sizeof(startup));
+ startup.cb = sizeof(startup);
+ startup.dwFlags = STARTF_USESHOWWINDOW;
+ startup.wShowWindow = SW_SHOWNORMAL;
+
+ /* FIXME: shouldn't need the CREATE_NEW_CONSOLE, but as usual CUI:s need it
+ * while GUI:s don't
+ */
+ if (!CreateProcess(NULL, cmdLine, NULL, NULL,
+ FALSE,
+ DEBUG_PROCESS|DEBUG_ONLY_THIS_PROCESS|CREATE_NEW_CONSOLE,
+ NULL, NULL, &startup, &info))
+ {
+ dbg_printf("Couldn't start process '%s'\n", cmdLine);
+ return FALSE;
+ }
+ if (!info.dwProcessId)
+ {
+ /* this happens when the program being run is not a Wine binary
+ * (for example, a shell wrapper around a WineLib app)
+ */
+ /* Current fix: list running processes and let the user attach
+ * to one of them (sic)
+ * FIXME: implement a real fix => grab the process (from the
+ * running processes) from its name
+ */
+ dbg_printf("Debuggee has been started (%s)\n"
+ "But WineDbg isn't attached to it. Maybe you're trying to debug a winelib wrapper ??\n"
+ "Try to attach to one of those processes:\n", cmdLine);
+ /* FIXME: (HACK) we need some time before the wrapper executes the winelib app */
+ Sleep(100);
+ info_win32_processes();
+ return TRUE;
+ }
+ dbg_curr_pid = info.dwProcessId;
+ if (!(dbg_curr_process = dbg_add_process(dbg_curr_pid, 0))) return FALSE;
+
+ return TRUE;
+}
+
+void dbg_run_debuggee(const char* args)
+{
+ if (args)
+ {
+ WINE_FIXME("Re-running current program with %s as args is broken\n", args);
+ return;
+ }
+ else
+ {
+ DEBUG_EVENT de;
+
+ if (!dbg_last_cmd_line)
+ {
+ dbg_printf("Cannot find previously used command line.\n");
+ return;
+ }
+ dbg_start_debuggee(dbg_last_cmd_line);
+ while (dbg_curr_process && WaitForDebugEvent(&de, INFINITE))
+ {
+ if (dbg_handle_debug_event(&de)) break;
+ }
+ source_list_from_addr(NULL, 0);
+ }
+}
+
diff --git a/programs/winedbg/winedbg.c b/programs/winedbg/winedbg.c
index fae7a42..7ed1410 100644
--- a/programs/winedbg/winedbg.c
+++ b/programs/winedbg/winedbg.c
@@ -93,10 +93,8 @@ DWORD dbg_curr_tid;
DWORD dbg_curr_pid;
CONTEXT dbg_context;
BOOL dbg_interactiveP = FALSE;
-static char* dbg_last_cmd_line = NULL;
static struct dbg_process* dbg_process_list = NULL;
-static enum {none_mode = 0, winedbg_mode, automatic_mode, gdb_mode} dbg_action_mode;
struct dbg_internal_var dbg_internal_vars[DBG_IV_LAST];
const struct dbg_internal_var* dbg_context_vars;
@@ -323,10 +321,6 @@ void dbg_del_process(struct dbg_process*
HeapFree(GetProcessHeap(), 0, p);
}
-static void dbg_init_current_process(void)
-{
-}
-
struct mod_loader_info
{
HANDLE handle;
@@ -409,25 +403,6 @@ struct dbg_thread* dbg_add_thread(struct
return t;
}
-static void dbg_init_current_thread(void* start)
-{
- if (start)
- {
- if (dbg_curr_process->threads &&
- !dbg_curr_process->threads->next && /* first thread ? */
- DBG_IVAR(BreakAllThreadsStartup))
- {
- ADDRESS addr;
-
- break_set_xpoints(FALSE);
- addr.Mode = AddrModeFlat;
- addr.Offset = (DWORD)start;
- break_add_break(&addr, TRUE, TRUE);
- break_set_xpoints(TRUE);
- }
- }
-}
-
void dbg_del_thread(struct dbg_thread* t)
{
HeapFree(GetProcessHeap(), 0, t->frames);
@@ -438,723 +413,6 @@ void dbg_del_thread(struct dbg_thread* t
HeapFree(GetProcessHeap(), 0, t);
}
-static unsigned dbg_handle_debug_event(DEBUG_EVENT* de);
-
-/******************************************************************
- * dbg_attach_debuggee
- *
- * Sets the debuggee to <pid>
- * cofe instructs winedbg what to do when first exception is received
- * (break=FALSE, continue=TRUE)
- * wfe is set to TRUE if dbg_attach_debuggee should also proceed with all debug events
- * until the first exception is received (aka: attach to an already running process)
- */
-BOOL dbg_attach_debuggee(DWORD pid, BOOL cofe, BOOL wfe)
-{
- DEBUG_EVENT de;
-
- if (!(dbg_curr_process = dbg_add_process(pid, 0))) return FALSE;
-
- if (!DebugActiveProcess(pid))
- {
- dbg_printf("Can't attach process %lx: error %ld\n", pid, GetLastError());
- dbg_del_process(dbg_curr_process);
- return FALSE;
- }
- dbg_curr_process->continue_on_first_exception = cofe;
-
- if (wfe) /* shall we proceed all debug events until we get an exception ? */
- {
- dbg_interactiveP = FALSE;
- while (dbg_curr_process && WaitForDebugEvent(&de, INFINITE))
- {
- if (dbg_handle_debug_event(&de)) break;
- }
- if (dbg_curr_process) dbg_interactiveP = TRUE;
- }
- return TRUE;
-}
-
-BOOL dbg_detach_debuggee(void)
-{
- /* remove all set breakpoints in debuggee code */
- break_set_xpoints(FALSE);
- /* needed for single stepping (ugly).
- * should this be handled inside the server ???
- */
- be_cpu->single_step(&dbg_context, FALSE);
- SetThreadContext(dbg_curr_thread->handle, &dbg_context);
- if (dbg_curr_thread->in_exception)
- ContinueDebugEvent(dbg_curr_pid, dbg_curr_tid, DBG_CONTINUE);
- if (!DebugActiveProcessStop(dbg_curr_pid)) return FALSE;
- dbg_del_process(dbg_curr_process);
-
- return TRUE;
-}
-
-static unsigned dbg_fetch_context(void)
-{
- dbg_context.ContextFlags = CONTEXT_CONTROL
- | CONTEXT_INTEGER
-#ifdef CONTEXT_SEGMENTS
- | CONTEXT_SEGMENTS
-#endif
-#ifdef CONTEXT_DEBUG_REGISTERS
- | CONTEXT_DEBUG_REGISTERS
-#endif
- ;
- if (!GetThreadContext(dbg_curr_thread->handle, &dbg_context))
- {
- WINE_WARN("Can't get thread's context\n");
- return FALSE;
- }
- return TRUE;
-}
-
-static unsigned dbg_exception_prolog(BOOL is_debug, const EXCEPTION_RECORD* rec)
-{
- ADDRESS addr;
- BOOL is_break;
-
- memory_get_current_pc(&addr);
- break_suspend_execution();
- dbg_curr_thread->excpt_record = *rec;
- dbg_curr_thread->in_exception = TRUE;
-
- if (!is_debug)
- {
- switch (addr.Mode)
- {
- case AddrModeFlat: dbg_printf(" in 32-bit code (0x%08lx)", addr.Offset); break;
- case AddrModeReal: dbg_printf(" in vm86 code (%04x:%04lx)", addr.Segment, addr.Offset); break;
- case AddrMode1616: dbg_printf(" in 16-bit code (%04x:%04lx)", addr.Segment, addr.Offset); break;
- case AddrMode1632: dbg_printf(" in 32-bit code (%04x:%08lx)", addr.Segment, addr.Offset); break;
- default: dbg_printf(" bad address");
- }
- dbg_printf(".\n");
- }
-
- /* this will resynchronize builtin dbghelp's internal ELF module list */
- SymLoadModule(dbg_curr_process->handle, 0, 0, 0, 0, 0);
-
- /*
- * Do a quiet backtrace so that we have an idea of what the situation
- * is WRT the source files.
- */
- stack_fetch_frames();
- if (is_debug &&
- break_should_continue(&addr, rec->ExceptionCode, &dbg_curr_thread->exec_count, &is_break))
- return FALSE;
-
- if (addr.Mode != dbg_curr_thread->addr_mode)
- {
- const char* name = NULL;
-
- switch (addr.Mode)
- {
- case AddrMode1616: name = "16 bit"; break;
- case AddrMode1632: name = "32 bit"; break;
- case AddrModeReal: name = "vm86"; break;
- case AddrModeFlat: name = "32 bit"; break;
- }
-
- dbg_printf("In %s mode.\n", name);
- dbg_curr_thread->addr_mode = addr.Mode;
- }
- display_print();
-
- if (!is_debug)
- {
- /* This is a real crash, dump some info */
- be_cpu->print_context(dbg_curr_thread->handle, &dbg_context);
- stack_info();
- be_cpu->print_segment_info(dbg_curr_thread->handle, &dbg_context);
- stack_backtrace(dbg_curr_tid);
- }
- else
- {
- static char* last_name;
- static char* last_file;
-
- char buffer[sizeof(SYMBOL_INFO) + 256];
- SYMBOL_INFO* si = (SYMBOL_INFO*)buffer;
- void* lin = memory_to_linear_addr(&addr);
- DWORD64 disp64;
- IMAGEHLP_LINE il;
- DWORD disp;
-
- si->SizeOfStruct = sizeof(*si);
- si->MaxNameLen = 256;
- il.SizeOfStruct = sizeof(il);
- if (SymFromAddr(dbg_curr_process->handle, (DWORD_PTR)lin, &disp64, si) &&
- SymGetLineFromAddr(dbg_curr_process->handle, (DWORD_PTR)lin, &disp, &il))
- {
- if ((!last_name || strcmp(last_name, si->Name)) ||
- (!last_file || strcmp(last_file, il.FileName)))
- {
- HeapFree(GetProcessHeap(), 0, last_name);
- HeapFree(GetProcessHeap(), 0, last_file);
- last_name = strcpy(HeapAlloc(GetProcessHeap(), 0, strlen(si->Name) + 1), si->Name);
- last_file = strcpy(HeapAlloc(GetProcessHeap(), 0, strlen(il.FileName) + 1), il.FileName);
- dbg_printf("%s () at %s:%ld\n", last_name, last_file, il.LineNumber);
- }
- }
- }
- if (!is_debug || is_break ||
- dbg_curr_thread->exec_mode == dbg_exec_step_over_insn ||
- dbg_curr_thread->exec_mode == dbg_exec_step_into_insn)
- {
- ADDRESS tmp = addr;
- /* Show where we crashed */
- memory_disasm_one_insn(&tmp);
- }
- source_list_from_addr(&addr, 0);
-
- return TRUE;
-}
-
-static void dbg_exception_epilog(void)
-{
- break_restart_execution(dbg_curr_thread->exec_count);
- /*
- * This will have gotten absorbed into the breakpoint info
- * if it was used. Otherwise it would have been ignored.
- * In any case, we don't mess with it any more.
- */
- if (dbg_curr_thread->exec_mode == dbg_exec_cont)
- dbg_curr_thread->exec_count = 0;
- dbg_curr_thread->in_exception = FALSE;
-}
-
-static DWORD dbg_handle_exception(const EXCEPTION_RECORD* rec, BOOL first_chance)
-{
- BOOL is_debug = FALSE;
- THREADNAME_INFO* pThreadName;
- struct dbg_thread* pThread;
-
- assert(dbg_curr_thread);
-
- WINE_TRACE("exception=%lx first_chance=%c\n",
- rec->ExceptionCode, first_chance ? 'Y' : 'N');
-
- switch (rec->ExceptionCode)
- {
- case EXCEPTION_BREAKPOINT:
- case EXCEPTION_SINGLE_STEP:
- is_debug = TRUE;
- break;
- case EXCEPTION_NAME_THREAD:
- pThreadName = (THREADNAME_INFO*)(rec->ExceptionInformation);
- if (pThreadName->dwThreadID == -1)
- pThread = dbg_curr_thread;
- else
- pThread = dbg_get_thread(dbg_curr_process, pThreadName->dwThreadID);
-
- if (dbg_read_memory(pThreadName->szName, pThread->name, 9))
- dbg_printf("Thread ID=0x%lx renamed using MS VC6 extension (name==\"%s\")\n",
- pThread->tid, pThread->name);
- return DBG_CONTINUE;
- }
-
- if (first_chance && !is_debug && !DBG_IVAR(BreakOnFirstChance) &&
- !(rec->ExceptionFlags & EH_STACK_INVALID))
- {
- /* pass exception to program except for debug exceptions */
- return DBG_EXCEPTION_NOT_HANDLED;
- }
-
- if (!is_debug)
- {
- /* print some infos */
- dbg_printf("%s: ",
- first_chance ? "First chance exception" : "Unhandled exception");
- switch (rec->ExceptionCode)
- {
- case EXCEPTION_INT_DIVIDE_BY_ZERO:
- dbg_printf("divide by zero");
- break;
- case EXCEPTION_INT_OVERFLOW:
- dbg_printf("overflow");
- break;
- case EXCEPTION_ARRAY_BOUNDS_EXCEEDED:
- dbg_printf("array bounds");
- break;
- case EXCEPTION_ILLEGAL_INSTRUCTION:
- dbg_printf("illegal instruction");
- break;
- case EXCEPTION_STACK_OVERFLOW:
- dbg_printf("stack overflow");
- break;
- case EXCEPTION_PRIV_INSTRUCTION:
- dbg_printf("privileged instruction");
- break;
- case EXCEPTION_ACCESS_VIOLATION:
- if (rec->NumberParameters == 2)
- dbg_printf("page fault on %s access to 0x%08lx",
- rec->ExceptionInformation[0] ? "write" : "read",
- rec->ExceptionInformation[1]);
- else
- dbg_printf("page fault");
- break;
- case EXCEPTION_DATATYPE_MISALIGNMENT:
- dbg_printf("Alignment");
- break;
- case DBG_CONTROL_C:
- dbg_printf("^C");
- break;
- case CONTROL_C_EXIT:
- dbg_printf("^C");
- break;
- case STATUS_POSSIBLE_DEADLOCK:
- {
- ADDRESS addr;
-
- addr.Mode = AddrModeFlat;
- addr.Offset = rec->ExceptionInformation[0];
-
- dbg_printf("wait failed on critical section ");
- print_address(&addr, FALSE);
- }
- if (!DBG_IVAR(BreakOnCritSectTimeOut))
- {
- dbg_printf("\n");
- return DBG_EXCEPTION_NOT_HANDLED;
- }
- break;
- case EXCEPTION_WINE_STUB:
- {
- char dll[32], name[64];
- memory_get_string(dbg_curr_process,
- (void*)rec->ExceptionInformation[0], TRUE, FALSE,
- dll, sizeof(dll));
- if (HIWORD(rec->ExceptionInformation[1]))
- memory_get_string(dbg_curr_process,
- (void*)rec->ExceptionInformation[1], TRUE, FALSE,
- name, sizeof(name));
- else
- sprintf( name, "%ld", rec->ExceptionInformation[1] );
- dbg_printf("unimplemented function %s.%s called", dll, name);
- }
- break;
- case EXCEPTION_WINE_ASSERTION:
- dbg_printf("assertion failed");
- break;
- case EXCEPTION_VM86_INTx:
- dbg_printf("interrupt %02lx in vm86 mode", rec->ExceptionInformation[0]);
- break;
- case EXCEPTION_VM86_STI:
- dbg_printf("sti in vm86 mode");
- break;
- case EXCEPTION_VM86_PICRETURN:
- dbg_printf("PIC return in vm86 mode");
- break;
- case EXCEPTION_FLT_DENORMAL_OPERAND:
- dbg_printf("denormal float operand");
- break;
- case EXCEPTION_FLT_DIVIDE_BY_ZERO:
- dbg_printf("divide by zero");
- break;
- case EXCEPTION_FLT_INEXACT_RESULT:
- dbg_printf("inexact float result");
- break;
- case EXCEPTION_FLT_INVALID_OPERATION:
- dbg_printf("invalid float operation");
- break;
- case EXCEPTION_FLT_OVERFLOW:
- dbg_printf("floating pointer overflow");
- break;
- case EXCEPTION_FLT_UNDERFLOW:
- dbg_printf("floating pointer underflow");
- break;
- case EXCEPTION_FLT_STACK_CHECK:
- dbg_printf("floating point stack check");
- break;
- default:
- dbg_printf("0x%08lx", rec->ExceptionCode);
- break;
- }
- }
- if( (rec->ExceptionFlags & EH_STACK_INVALID) ) {
- dbg_printf( ", invalid program stack" );
- }
-
- if (dbg_action_mode == automatic_mode)
- {
- dbg_exception_prolog(is_debug, rec);
- dbg_exception_epilog();
- return 0; /* terminate execution */
- }
-
- if (dbg_exception_prolog(is_debug, rec))
- {
- dbg_interactiveP = TRUE;
- return 0;
- }
- dbg_exception_epilog();
-
- return DBG_CONTINUE;
-}
-
-static unsigned dbg_handle_debug_event(DEBUG_EVENT* de)
-{
- char buffer[256];
- DWORD cont = DBG_CONTINUE;
-
- dbg_curr_pid = de->dwProcessId;
- dbg_curr_tid = de->dwThreadId;
-
- if ((dbg_curr_process = dbg_get_process(de->dwProcessId)) != NULL)
- dbg_curr_thread = dbg_get_thread(dbg_curr_process, de->dwThreadId);
- else
- dbg_curr_thread = NULL;
-
- switch (de->dwDebugEventCode)
- {
- case EXCEPTION_DEBUG_EVENT:
- if (!dbg_curr_thread)
- {
- WINE_ERR("%08lx:%08lx: not a registered process or thread (perhaps a 16 bit one ?)\n",
- de->dwProcessId, de->dwThreadId);
- break;
- }
-
- WINE_TRACE("%08lx:%08lx: exception code=%08lx\n",
- de->dwProcessId, de->dwThreadId,
- de->u.Exception.ExceptionRecord.ExceptionCode);
-
- if (dbg_curr_process->continue_on_first_exception)
- {
- dbg_curr_process->continue_on_first_exception = FALSE;
- if (!DBG_IVAR(BreakOnAttach)) break;
- }
- if (dbg_fetch_context())
- {
- cont = dbg_handle_exception(&de->u.Exception.ExceptionRecord,
- de->u.Exception.dwFirstChance);
- if (cont && dbg_curr_thread)
- {
- SetThreadContext(dbg_curr_thread->handle, &dbg_context);
- }
- }
- break;
-
- case CREATE_PROCESS_DEBUG_EVENT:
- dbg_curr_process = dbg_add_process(de->dwProcessId,
- de->u.CreateProcessInfo.hProcess);
- if (dbg_curr_process == NULL)
- {
- WINE_ERR("Couldn't create process\n");
- break;
- }
- memory_get_string_indirect(dbg_curr_process,
- de->u.CreateProcessInfo.lpImageName,
- de->u.CreateProcessInfo.fUnicode,
- buffer, sizeof(buffer));
- if (!buffer[0]) strcpy(buffer, "<Debugged Process>");
-
- WINE_TRACE("%08lx:%08lx: create process '%s'/%p @%08lx (%ld<%ld>)\n",
- de->dwProcessId, de->dwThreadId,
- buffer, de->u.CreateProcessInfo.lpImageName,
- (unsigned long)(void*)de->u.CreateProcessInfo.lpStartAddress,
- de->u.CreateProcessInfo.dwDebugInfoFileOffset,
- de->u.CreateProcessInfo.nDebugInfoSize);
- dbg_set_process_name(dbg_curr_process, buffer);
-
- if (!SymInitialize(dbg_curr_process->handle, NULL, TRUE))
- dbg_printf("Couldn't initiate DbgHelp\n");
-
- WINE_TRACE("%08lx:%08lx: create thread I @%08lx\n",
- de->dwProcessId, de->dwThreadId,
- (unsigned long)(void*)de->u.CreateProcessInfo.lpStartAddress);
-
- dbg_curr_thread = dbg_add_thread(dbg_curr_process,
- de->dwThreadId,
- de->u.CreateProcessInfo.hThread,
- de->u.CreateProcessInfo.lpThreadLocalBase);
- if (!dbg_curr_thread)
- {
- WINE_ERR("Couldn't create thread\n");
- break;
- }
- dbg_init_current_process();
- dbg_init_current_thread(de->u.CreateProcessInfo.lpStartAddress);
- break;
-
- case EXIT_PROCESS_DEBUG_EVENT:
- WINE_TRACE("%08lx:%08lx: exit process (%ld)\n",
- de->dwProcessId, de->dwThreadId, de->u.ExitProcess.dwExitCode);
-
- if (dbg_curr_process == NULL)
- {
- WINE_ERR("Unknown process\n");
- break;
- }
- if (!SymCleanup(dbg_curr_process->handle))
- dbg_printf("Couldn't initiate DbgHelp\n");
- /* just in case */
- break_set_xpoints(FALSE);
- /* kill last thread */
- dbg_del_thread(dbg_curr_process->threads);
- dbg_del_process(dbg_curr_process);
-
- dbg_printf("Process of pid=0x%08lx has terminated\n", dbg_curr_pid);
- break;
-
- case CREATE_THREAD_DEBUG_EVENT:
- WINE_TRACE("%08lx:%08lx: create thread D @%08lx\n",
- de->dwProcessId, de->dwThreadId,
- (unsigned long)(void*)de->u.CreateThread.lpStartAddress);
-
- if (dbg_curr_process == NULL)
- {
- WINE_ERR("Unknown process\n");
- break;
- }
- if (dbg_get_thread(dbg_curr_process, de->dwThreadId) != NULL)
- {
- WINE_TRACE("Thread already listed, skipping\n");
- break;
- }
-
- dbg_curr_thread = dbg_add_thread(dbg_curr_process,
- de->dwThreadId,
- de->u.CreateThread.hThread,
- de->u.CreateThread.lpThreadLocalBase);
- if (!dbg_curr_thread)
- {
- WINE_ERR("Couldn't create thread\n");
- break;
- }
- dbg_init_current_thread(de->u.CreateThread.lpStartAddress);
- break;
-
- case EXIT_THREAD_DEBUG_EVENT:
- WINE_TRACE("%08lx:%08lx: exit thread (%ld)\n",
- de->dwProcessId, de->dwThreadId, de->u.ExitThread.dwExitCode);
-
- if (dbg_curr_thread == NULL)
- {
- WINE_ERR("Unknown thread\n");
- break;
- }
- /* FIXME: remove break point set on thread startup */
- dbg_del_thread(dbg_curr_thread);
- break;
-
- case LOAD_DLL_DEBUG_EVENT:
- if (dbg_curr_thread == NULL)
- {
- WINE_ERR("Unknown thread\n");
- break;
- }
- memory_get_string_indirect(dbg_curr_process,
- de->u.LoadDll.lpImageName,
- de->u.LoadDll.fUnicode,
- buffer, sizeof(buffer));
-
- WINE_TRACE("%08lx:%08lx: loads DLL %s @%08lx (%ld<%ld>)\n",
- de->dwProcessId, de->dwThreadId,
- buffer, (unsigned long)de->u.LoadDll.lpBaseOfDll,
- de->u.LoadDll.dwDebugInfoFileOffset,
- de->u.LoadDll.nDebugInfoSize);
- SymLoadModule(dbg_curr_process->handle, de->u.LoadDll.hFile, buffer, NULL,
- (unsigned long)de->u.LoadDll.lpBaseOfDll, 0);
- break_set_xpoints(FALSE);
- break_check_delayed_bp();
- break_set_xpoints(TRUE);
- if (DBG_IVAR(BreakOnDllLoad))
- {
- dbg_printf("Stopping on DLL %s loading at 0x%08lx\n",
- buffer, (unsigned long)de->u.LoadDll.lpBaseOfDll);
- if (dbg_fetch_context()) cont = 0;
- }
- break;
-
- case UNLOAD_DLL_DEBUG_EVENT:
- WINE_TRACE("%08lx:%08lx: unload DLL @%08lx\n",
- de->dwProcessId, de->dwThreadId,
- (unsigned long)de->u.UnloadDll.lpBaseOfDll);
- break_delete_xpoints_from_module((unsigned long)de->u.UnloadDll.lpBaseOfDll);
- SymUnloadModule(dbg_curr_process->handle,
- (unsigned long)de->u.UnloadDll.lpBaseOfDll);
- break;
-
- case OUTPUT_DEBUG_STRING_EVENT:
- if (dbg_curr_thread == NULL)
- {
- WINE_ERR("Unknown thread\n");
- break;
- }
-
- memory_get_string(dbg_curr_process,
- de->u.DebugString.lpDebugStringData, TRUE,
- de->u.DebugString.fUnicode, buffer, sizeof(buffer));
- WINE_TRACE("%08lx:%08lx: output debug string (%s)\n",
- de->dwProcessId, de->dwThreadId, buffer);
- break;
-
- case RIP_EVENT:
- WINE_TRACE("%08lx:%08lx: rip error=%ld type=%ld\n",
- de->dwProcessId, de->dwThreadId, de->u.RipInfo.dwError,
- de->u.RipInfo.dwType);
- break;
-
- default:
- WINE_TRACE("%08lx:%08lx: unknown event (%ld)\n",
- de->dwProcessId, de->dwThreadId, de->dwDebugEventCode);
- }
- if (!cont) return TRUE; /* stop execution */
- ContinueDebugEvent(de->dwProcessId, de->dwThreadId, cont);
- return FALSE; /* continue execution */
-}
-
-static void dbg_resume_debuggee(DWORD cont)
-{
- if (dbg_curr_thread->in_exception)
- {
- ADDRESS addr;
-
- dbg_exception_epilog();
- memory_get_current_pc(&addr);
- WINE_TRACE("Exiting debugger PC=0x%lx mode=%d count=%d\n",
- addr.Offset, dbg_curr_thread->exec_mode,
- dbg_curr_thread->exec_count);
- if (dbg_curr_thread)
- {
- if (!SetThreadContext(dbg_curr_thread->handle, &dbg_context))
- dbg_printf("Cannot set ctx on %lu\n", dbg_curr_tid);
- }
- }
- dbg_interactiveP = FALSE;
- if (!ContinueDebugEvent(dbg_curr_pid, dbg_curr_tid, cont))
- dbg_printf("Cannot continue on %lu (%lu)\n", dbg_curr_tid, cont);
-}
-
-void dbg_wait_next_exception(DWORD cont, int count, int mode)
-{
- DEBUG_EVENT de;
- ADDRESS addr;
-
- if (cont == DBG_CONTINUE)
- {
- dbg_curr_thread->exec_count = count;
- dbg_curr_thread->exec_mode = mode;
- }
- dbg_resume_debuggee(cont);
-
- while (dbg_curr_process && WaitForDebugEvent(&de, INFINITE))
- {
- if (dbg_handle_debug_event(&de)) break;
- }
- if (!dbg_curr_process) return;
- dbg_interactiveP = TRUE;
-
- memory_get_current_pc(&addr);
- WINE_TRACE("Entering debugger PC=0x%lx mode=%d count=%d\n",
- addr.Offset, dbg_curr_thread->exec_mode,
- dbg_curr_thread->exec_count);
-}
-
-static unsigned dbg_main_loop(HANDLE hFile)
-{
- DEBUG_EVENT de;
-
- if (dbg_curr_process)
- dbg_printf("WineDbg starting on pid 0x%lx\n", dbg_curr_pid);
-
- /* wait for first exception */
- while (WaitForDebugEvent(&de, INFINITE))
- {
- if (dbg_handle_debug_event(&de)) break;
- }
- switch (dbg_action_mode)
- {
- case automatic_mode:
- /* print some extra information */
- dbg_printf("Modules:\n");
- info_win32_module(0); /* print all modules */
- dbg_printf("Threads:\n");
- info_win32_threads();
- break;
- default:
- dbg_interactiveP = TRUE;
- parser_handle(hFile);
- }
- dbg_printf("WineDbg terminated on pid 0x%lx\n", dbg_curr_pid);
-
- return 0;
-}
-
-static unsigned dbg_start_debuggee(LPSTR cmdLine)
-{
- PROCESS_INFORMATION info;
- STARTUPINFOA startup;
-
- memset(&startup, 0, sizeof(startup));
- startup.cb = sizeof(startup);
- startup.dwFlags = STARTF_USESHOWWINDOW;
- startup.wShowWindow = SW_SHOWNORMAL;
-
- /* FIXME: shouldn't need the CREATE_NEW_CONSOLE, but as usual CUI:s need it
- * while GUI:s don't
- */
- if (!CreateProcess(NULL, cmdLine, NULL, NULL,
- FALSE,
- DEBUG_PROCESS|DEBUG_ONLY_THIS_PROCESS|CREATE_NEW_CONSOLE,
- NULL, NULL, &startup, &info))
- {
- dbg_printf("Couldn't start process '%s'\n", cmdLine);
- return FALSE;
- }
- if (!info.dwProcessId)
- {
- /* this happens when the program being run is not a Wine binary
- * (for example, a shell wrapper around a WineLib app)
- */
- /* Current fix: list running processes and let the user attach
- * to one of them (sic)
- * FIXME: implement a real fix => grab the process (from the
- * running processes) from its name
- */
- dbg_printf("Debuggee has been started (%s)\n"
- "But WineDbg isn't attached to it. Maybe you're trying to debug a winelib wrapper ??\n"
- "Try to attach to one of those processes:\n", cmdLine);
- /* FIXME: (HACK) we need some time before the wrapper executes the winelib app */
- Sleep(100);
- info_win32_processes();
- return TRUE;
- }
- dbg_curr_pid = info.dwProcessId;
- if (!(dbg_curr_process = dbg_add_process(dbg_curr_pid, 0))) return FALSE;
-
- return TRUE;
-}
-
-void dbg_run_debuggee(const char* args)
-{
- if (args)
- {
- WINE_FIXME("Re-running current program with %s as args is broken\n", args);
- return;
- }
- else
- {
- DEBUG_EVENT de;
-
- if (!dbg_last_cmd_line)
- {
- dbg_printf("Cannot find previously used command line.\n");
- return;
- }
- dbg_start_debuggee(dbg_last_cmd_line);
- while (dbg_curr_process && WaitForDebugEvent(&de, INFINITE))
- {
- if (dbg_handle_debug_event(&de)) break;
- }
- source_list_from_addr(NULL, 0);
- }
-}
-
BOOL dbg_interrupt_debuggee(void)
{
if (!dbg_process_list) return FALSE;
More information about the wine-patches
mailing list