From 829e002c3f254f4e55b3c15a2f3480aca809351a Mon Sep 17 00:00:00 2001 From: Eric Pouech Date: Fri, 24 Feb 2006 22:12:59 +0100 Subject: [PATCH] winedbg: Active targets Move all code related to an 'active' target (ie a running process) from winedbg.c to tgt_active.c. --- 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 89ff56f86b5..3c4acbf939b 100644 --- a/programs/winedbg/debugger.h +++ b/programs/winedbg/debugger.h @@ -365,6 +365,15 @@ extern void symbol_info(const char* str); 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* dbg_get_internal_var(const char*); 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_process* p); 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 964498731ee..5c7dfbe9f54 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 + * 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, ""); + + 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 fae7a4298af..7ed14100132 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* p) 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 dbg_process* p, DWORD tid, 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 - * 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, ""); - - 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;