From 1e256e426df84b6ba00a4c360f355b3809a72b9f Mon Sep 17 00:00:00 2001 From: =?utf8?q?Miko=C5=82aj=20Zalewski?= Date: Sun, 21 Dec 2008 22:28:32 +0100 Subject: [PATCH] winedbg: Add a crash dialog for --auto mode. --- dlls/kernel32/tests/debugger.c | 97 ++++++++++++++--------- programs/winedbg/Makefile.in | 5 +- programs/winedbg/crashdlg.c | 173 +++++++++++++++++++++++++++++++++++++++++ programs/winedbg/debugger.h | 6 ++ programs/winedbg/intvar.h | 3 + programs/winedbg/resource.h | 34 ++++++++ programs/winedbg/rsrc.rc | 26 +++++++ programs/winedbg/rsrc_En.rc | 53 +++++++++++++ programs/winedbg/tgt_active.c | 16 +++- programs/winedbg/winedbg.c | 36 +++++---- 10 files changed, 394 insertions(+), 55 deletions(-) create mode 100644 programs/winedbg/crashdlg.c create mode 100644 programs/winedbg/resource.h create mode 100644 programs/winedbg/rsrc.rc create mode 100644 programs/winedbg/rsrc_En.rc diff --git a/dlls/kernel32/tests/debugger.c b/dlls/kernel32/tests/debugger.c index 6245d60f142..9b849b026fe 100644 --- a/dlls/kernel32/tests/debugger.c +++ b/dlls/kernel32/tests/debugger.c @@ -45,6 +45,40 @@ static void get_file_name(char* buf) GetTempFileNameA(path, "wt", 0, buf); } +typedef struct tag_reg_save_value +{ + const char *name; + DWORD type; + BYTE *data; + DWORD size; +} reg_save_value; + +static DWORD save_value(HKEY hkey, const char *value, reg_save_value *saved) +{ + DWORD ret; + saved->name=value; + saved->data=0; + saved->size=0; + ret=RegQueryValueExA(hkey, value, NULL, &saved->type, NULL, &saved->size); + if (ret == ERROR_SUCCESS) + { + saved->data=HeapAlloc(GetProcessHeap(), 0, saved->size); + RegQueryValueExA(hkey, value, NULL, &saved->type, saved->data, &saved->size); + } + return ret; +} + +static void restore_value(HKEY hkey, reg_save_value *saved) +{ + if (saved->data) + { + RegSetValueExA(hkey, saved->name, 0, saved->type, saved->data, saved->size); + HeapFree(GetProcessHeap(), 0, saved->data); + } + else + RegDeleteValueA(hkey, saved->name); +} + static void get_events(const char* name, HANDLE *start_event, HANDLE *done_event) { const char* basename; @@ -311,14 +345,13 @@ static void crash_and_winedbg(HKEY hkey, const char* argv0) static void test_ExitCode(void) { static const char* AeDebug="Software\\Microsoft\\Windows NT\\CurrentVersion\\AeDebug"; + static const char* WineDbg="Software\\Wine\\WineDbg"; char test_exe[MAX_PATH]; DWORD ret; HKEY hkey; DWORD disposition; - LPBYTE auto_val=NULL; - DWORD auto_size, auto_type; - LPBYTE debugger_val=NULL; - DWORD debugger_size, debugger_type; + reg_save_value auto_value; + reg_save_value debugger_value; GetModuleFileNameA(GetModuleHandle(NULL), test_exe, sizeof(test_exe)); if (GetFileAttributes(test_exe) == INVALID_FILE_ATTRIBUTES) @@ -332,22 +365,9 @@ static void test_ExitCode(void) ret=RegCreateKeyExA(HKEY_LOCAL_MACHINE, AeDebug, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hkey, &disposition); if (ret == ERROR_SUCCESS) { - auto_size=0; - ret=RegQueryValueExA(hkey, "auto", NULL, &auto_type, NULL, &auto_size); - if (ret == ERROR_SUCCESS) - { - auto_val=HeapAlloc(GetProcessHeap(), 0, auto_size); - RegQueryValueExA(hkey, "auto", NULL, &auto_type, auto_val, &auto_size); - } - - debugger_size=0; - ret=RegQueryValueExA(hkey, "debugger", NULL, &debugger_type, NULL, &debugger_size); - if (ret == ERROR_SUCCESS) - { - debugger_val=HeapAlloc(GetProcessHeap(), 0, debugger_size); - RegQueryValueExA(hkey, "debugger", NULL, &debugger_type, debugger_val, &debugger_size); - trace("HKLM\\%s\\debugger is set to '%s'\n", AeDebug, debugger_val); - } + save_value(hkey, "auto", &auto_value); + save_value(hkey, "debugger", &debugger_value); + trace("HKLM\\%s\\debugger is set to '%s'\n", AeDebug, debugger_value.data); } else if (ret == ERROR_ACCESS_DENIED) { @@ -360,9 +380,24 @@ static void test_ExitCode(void) return; } - if (debugger_val && debugger_type == REG_SZ && - strstr((char*)debugger_val, "winedbg --auto")) - crash_and_winedbg(hkey, test_exe); + if (debugger_value.data && debugger_value.type == REG_SZ && + strstr((char*)debugger_value.data, "winedbg --auto")) + { + HKEY hkeyWinedbg; + ret=RegCreateKeyA(HKEY_CURRENT_USER, WineDbg, &hkeyWinedbg); + if (ret == ERROR_SUCCESS) + { + static DWORD zero; + reg_save_value crash_dlg_value; + save_value(hkeyWinedbg, "ShowCrashDialog", &crash_dlg_value); + RegSetValueExA(hkeyWinedbg, "ShowCrashDialog", 0, REG_DWORD, (BYTE *)&zero, sizeof(DWORD)); + crash_and_winedbg(hkey, test_exe); + restore_value(hkeyWinedbg, &crash_dlg_value); + RegCloseKey(hkeyWinedbg); + } + else + ok(0, "Couldn't access WineDbg Key - error %u\n", ret); + } if (winetest_interactive) /* Since the debugging process never sets the debug event, it isn't recognized @@ -385,20 +420,8 @@ static void test_ExitCode(void) } else { - if (auto_val) - { - RegSetValueExA(hkey, "auto", 0, auto_type, auto_val, auto_size); - HeapFree(GetProcessHeap(), 0, auto_val); - } - else - RegDeleteValueA(hkey, "auto"); - if (debugger_val) - { - RegSetValueExA(hkey, "debugger", 0, debugger_type, debugger_val, debugger_size); - HeapFree(GetProcessHeap(), 0, debugger_val); - } - else - RegDeleteValueA(hkey, "debugger"); + restore_value(hkey, &auto_value); + restore_value(hkey, &debugger_value); RegCloseKey(hkey); } } diff --git a/programs/winedbg/Makefile.in b/programs/winedbg/Makefile.in index 395869e1ba3..b4dd150e1e3 100644 --- a/programs/winedbg/Makefile.in +++ b/programs/winedbg/Makefile.in @@ -5,7 +5,7 @@ VPATH = @srcdir@ MODULE = winedbg.exe APPMODE = -mconsole IMPORTS = psapi dbghelp advapi32 kernel32 ntdll -DELAYIMPORTS = user32 +DELAYIMPORTS = user32 gdi32 EXTRALIBS = @LIBPOLL@ C_SRCS = \ @@ -14,6 +14,7 @@ C_SRCS = \ be_ppc.c \ be_x86_64.c \ break.c \ + crashdlg.c \ db_disasm.c \ display.c \ expr.c \ @@ -29,6 +30,8 @@ C_SRCS = \ types.c \ winedbg.c +RC_SRCS = rsrc.rc + LEX_SRCS = debug.l BISON_SRCS = dbg.y diff --git a/programs/winedbg/crashdlg.c b/programs/winedbg/crashdlg.c new file mode 100644 index 00000000000..9abd5b75be9 --- /dev/null +++ b/programs/winedbg/crashdlg.c @@ -0,0 +1,173 @@ +/* + * The dialog that displays after a crash + * + * Copyright 2008 Mikolaj Zalewski + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include "resource.h" +#include "debugger.h" +#include "wingdi.h" +#include "winuser.h" +#include "psapi.h" + +#include "wine/debug.h" +#include "wine/unicode.h" + +WINE_DEFAULT_DEBUG_CHANNEL(winedbg); + +#define MAX_PROGRAM_NAME_LENGTH 80 + +int msgbox_res_id(HWND hwnd, UINT textId, UINT captionId, UINT uType) +{ + WCHAR caption[256]; + WCHAR text[256]; + LoadStringW(GetModuleHandleW(NULL), captionId, caption, sizeof(caption)/sizeof(caption[0])); + LoadStringW(GetModuleHandleW(NULL), textId, text, sizeof(text)/sizeof(text[0])); + return MessageBoxW(hwnd, text, caption, uType); +} + +static WCHAR *get_program_name(HANDLE hProcess) +{ + WCHAR image_name[MAX_PATH]; + WCHAR *programname; + WCHAR *output; + + /* GetProcessImageFileNameW gives no way to query the correct buffer size, + * but programs with a path longer than MAX_PATH can't be started by the + * shell, so we expect they don't happen often */ + if (!GetProcessImageFileNameW(hProcess, image_name, MAX_PATH)) + { + static WCHAR unidentified[MAX_PROGRAM_NAME_LENGTH]; + LoadStringW(GetModuleHandleW(NULL), IDS_UNIDENTIFIED, + unidentified, MAX_PROGRAM_NAME_LENGTH); + return unidentified; + } + + programname = strrchrW(image_name, '\\'); + if (programname != NULL) + programname++; + else + programname = image_name; + + /* TODO: if the image has a VERSIONINFO, we could try to find there a more + * user-friendly program name */ + + /* don't display a too long string to the user */ + if (strlenW(programname) >= MAX_PROGRAM_NAME_LENGTH) + { + programname[MAX_PROGRAM_NAME_LENGTH - 4] = '.'; + programname[MAX_PROGRAM_NAME_LENGTH - 3] = '.'; + programname[MAX_PROGRAM_NAME_LENGTH - 2] = '.'; + programname[MAX_PROGRAM_NAME_LENGTH - 1] = 0; + } + + output = HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR)*(lstrlenW(programname) + 1)); + lstrcpyW(output, programname); + + return output; +} + +static LPWSTR g_ProgramName; +static HFONT g_hBoldFont; +static HMENU g_hDebugMenu = NULL; + +static void set_bold_font(HWND hDlg) +{ + HFONT hNormalFont = (HFONT)SendDlgItemMessageW(hDlg, IDC_STATIC_TXT1, + WM_GETFONT, 0, 0); + LOGFONTW font; + GetObjectW(hNormalFont, sizeof(LOGFONTW), &font); + font.lfWeight = FW_BOLD; + g_hBoldFont = CreateFontIndirectW(&font); + SendDlgItemMessageW(hDlg, IDC_STATIC_TXT1, WM_SETFONT, (WPARAM)g_hBoldFont, TRUE); +} + +static void set_message_with_filename(HWND hDlg) +{ + WCHAR originalText[1000]; + WCHAR newText[1000 + MAX_PROGRAM_NAME_LENGTH]; + + GetDlgItemTextW(hDlg, IDC_STATIC_TXT1, originalText, + sizeof(originalText)/sizeof(originalText[0])); + wsprintfW(newText, originalText, g_ProgramName); + SetDlgItemTextW(hDlg, IDC_STATIC_TXT1, newText); +} + +static INT_PTR WINAPI DlgProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) +{ + switch (msg) + { + case WM_INITDIALOG: + { + set_bold_font(hwnd); + set_message_with_filename(hwnd); + return TRUE; + } + case WM_CTLCOLORSTATIC: + { + /* WM_CTLCOLOR* don't use DWLP_MSGRESULT */ + INT_PTR id = GetDlgCtrlID((HWND)lParam); + if (id == IDC_STATIC_BG || id == IDC_STATIC_TXT1) + return (LONG_PTR)GetSysColorBrush(COLOR_WINDOW); + + return FALSE; + } + case WM_RBUTTONDOWN: + { + POINT mousePos; + if (!(wParam & MK_SHIFT)) + return FALSE; + if (g_hDebugMenu == NULL) + g_hDebugMenu = LoadMenuW(GetModuleHandleW(NULL), MAKEINTRESOURCEW(IDM_DEBUG_POPUP)); + GetCursorPos(&mousePos); + TrackPopupMenu(GetSubMenu(g_hDebugMenu, 0), TPM_RIGHTBUTTON, mousePos.x, mousePos.y, + 0, hwnd, NULL); + return TRUE; + } + case WM_COMMAND: + switch (LOWORD(wParam)) + { + case IDOK: + case IDCANCEL: + case ID_DEBUG: + EndDialog(hwnd, LOWORD(wParam)); + return TRUE; + } + return TRUE; + } + return FALSE; +} + +BOOL display_crash_dialog(void) +{ + INT_PTR result; + /* dbg_curr_process->handle is not set */ + HANDLE hProcess; + + if (!DBG_IVAR(ShowCrashDialog)) + return TRUE; + + hProcess = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, dbg_curr_pid); + g_ProgramName = get_program_name(hProcess); + CloseHandle(hProcess); + result = DialogBoxW(GetModuleHandleW(NULL), MAKEINTRESOURCEW(IDD_CRASH_DLG), NULL, DlgProc); + if (result == ID_DEBUG) { + AllocConsole(); + return FALSE; + } + return TRUE; +} diff --git a/programs/winedbg/debugger.h b/programs/winedbg/debugger.h index 0d34ddfdc2e..e79354353ea 100644 --- a/programs/winedbg/debugger.h +++ b/programs/winedbg/debugger.h @@ -300,6 +300,10 @@ extern void break_suspend_execution(void); extern void break_restart_execution(int count); extern int break_add_condition(int bpnum, struct expr* exp); + /* crashdlg.c */ +extern BOOL display_crash_dialog(void); +extern int msgbox_res_id(HWND hwnd, UINT textId, UINT captionId, UINT uType); + /* dbg.y */ extern void parser_handle(HANDLE); extern int input_read_line(const char* pfx, char* buffer, int size); @@ -456,6 +460,8 @@ extern BOOL dbg_init(HANDLE hProc, const WCHAR* in, BOOL invade); extern BOOL dbg_load_module(HANDLE hProc, HANDLE hFile, const WCHAR* name, DWORD base, DWORD size); extern BOOL dbg_get_debuggee_info(HANDLE hProcess, IMAGEHLP_MODULE* imh_mod); extern void dbg_set_option(const char*, const char*); +extern void dbg_start_interactive(HANDLE hFile); +extern void dbg_init_console(void); /* gdbproxy.c */ extern int gdb_main(int argc, char* argv[]); diff --git a/programs/winedbg/intvar.h b/programs/winedbg/intvar.h index a9c335ea5e3..2771f23fd7c 100644 --- a/programs/winedbg/intvar.h +++ b/programs/winedbg/intvar.h @@ -36,3 +36,6 @@ INTERNAL_VAR(AlwaysShowThunks, FALSE, NULL, /* process manipulation */ INTERNAL_VAR(AlsoDebugProcChild, FALSE, NULL, dbg_itype_unsigned_int) + + /* automatic invocation on failure */ +INTERNAL_VAR(ShowCrashDialog, TRUE, NULL, dbg_itype_unsigned_int) diff --git a/programs/winedbg/resource.h b/programs/winedbg/resource.h new file mode 100644 index 00000000000..49d19ef364c --- /dev/null +++ b/programs/winedbg/resource.h @@ -0,0 +1,34 @@ +/* + * Resource IDs (resource.h) + * + * Copyright 2008 Mikolaj Zalewski + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + + +#define IDD_CRASH_DLG 100 + +#define IDC_STATIC_BG 100 +#define IDC_STATIC_TXT1 101 +#define IDC_STATIC_TXT2 102 + +#define IDM_DEBUG_POPUP 100 + +#define ID_DEBUG 200 + +#define IDS_AUTO_CAPTION 16 +#define IDS_INVALID_PARAMS 17 +#define IDS_UNIDENTIFIED 18 diff --git a/programs/winedbg/rsrc.rc b/programs/winedbg/rsrc.rc new file mode 100644 index 00000000000..1c202a9ed81 --- /dev/null +++ b/programs/winedbg/rsrc.rc @@ -0,0 +1,26 @@ +/* + * Resources (rsrc.rc) + * + * Copyright 2008 Mikolaj Zalewski + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include +#include + +#include "resource.h" + +#include "rsrc_En.rc" diff --git a/programs/winedbg/rsrc_En.rc b/programs/winedbg/rsrc_En.rc new file mode 100644 index 00000000000..f50e51bcba4 --- /dev/null +++ b/programs/winedbg/rsrc_En.rc @@ -0,0 +1,53 @@ +/* + * English Language Support + * + * Copyright 2008 Mikolaj Zalewski + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +LANGUAGE LANG_ENGLISH, SUBLANG_DEFAULT + +IDM_DEBUG_POPUP MENU +BEGIN + POPUP "" + BEGIN + MENUITEM "&Debug", ID_DEBUG + END +END + +IDD_CRASH_DLG DIALOGEX 100, 100, 273, 175 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Program Error" +FONT 8, "Tahoma" +BEGIN + LTEXT "",IDC_STATIC_BG,0,0,273,52,WS_BORDER,0 + LTEXT "The program %s has encountered a serious problem and needs \ + to close. We are sorry for the inconvenience.", + IDC_STATIC_TXT1,27,10,224,30 + LTEXT "This can be caused by a problem in the program or a deficiency in Wine. \ + You may want to check http:/*appdb.winehq.org for tips about running \ + this application.\n\n\ + If this problem is not present under Windows and has not been reported \ + yet, you can report it at http://bugs.winehq.org.",IDC_STATIC_TXT2,27,60,224,100 + DEFPUSHBUTTON "Close", IDOK, 205, 151, 60, 16, WS_TABSTOP +END + +STRINGTABLE +BEGIN + IDS_AUTO_CAPTION "Wine program crash" + IDS_INVALID_PARAMS "Internal errors - invalid parameters received" + IDS_UNIDENTIFIED "(unidentified)" +END diff --git a/programs/winedbg/tgt_active.c b/programs/winedbg/tgt_active.c index 2ff7ea5fa65..2b8002b96ca 100644 --- a/programs/winedbg/tgt_active.c +++ b/programs/winedbg/tgt_active.c @@ -27,6 +27,7 @@ #include "debugger.h" #include "psapi.h" +#include "resource.h" #include "winternl.h" #include "wine/debug.h" #include "wine/exception.h" @@ -45,9 +46,9 @@ static void dbg_init_current_thread(void* start) { if (start) { - if (dbg_curr_process->threads && + if (dbg_curr_process->threads && !dbg_curr_process->threads->next && /* first thread ? */ - DBG_IVAR(BreakAllThreadsStartup)) + DBG_IVAR(BreakAllThreadsStartup)) { ADDRESS64 addr; @@ -898,7 +899,16 @@ enum dbg_start dbg_active_auto(int argc, char* argv[]) /* auto mode */ argc--; argv++; ds = dbg_active_attach(argc, argv); - if (ds != start_ok) return ds; + if (ds != start_ok) { + msgbox_res_id(NULL, IDS_INVALID_PARAMS, IDS_AUTO_CAPTION, MB_OK); + return ds; + } + if (!display_crash_dialog()) { + dbg_init_console(); + dbg_start_interactive(INVALID_HANDLE_VALUE); + return start_ok; + } + hFile = parser_generate_command_file("echo Modules:", "info share", "echo Threads:", "info threads", "backtrace", "detach", NULL); diff --git a/programs/winedbg/winedbg.c b/programs/winedbg/winedbg.c index ec9bdf1a3db..a75e54803f1 100644 --- a/programs/winedbg/winedbg.c +++ b/programs/winedbg/winedbg.c @@ -556,8 +556,11 @@ static BOOL WINAPI ctrl_c_handler(DWORD dwCtrlType) return FALSE; } -static void dbg_init_console(void) +void dbg_init_console(void) { + /* set the output handle */ + dbg_houtput = GetStdHandle(STD_OUTPUT_HANDLE); + /* set our control-C handler */ SetConsoleCtrlHandler(ctrl_c_handler, TRUE); @@ -587,6 +590,23 @@ static int dbg_winedbg_usage(BOOL advanced) return -1; } +void dbg_start_interactive(HANDLE hFile) +{ + if (dbg_curr_process) + { + dbg_printf("WineDbg starting on pid %04x\n", dbg_curr_pid); + if (dbg_curr_process->active_debuggee) dbg_active_wait_for_first_exception(); + } + + dbg_interactiveP = TRUE; + parser_handle(hFile); + + while (dbg_process_list) + dbg_process_list->process_io->close_process(dbg_process_list, FALSE); + + dbg_save_internal_vars(); +} + struct backend_cpu* be_cpu; #ifdef __i386__ extern struct backend_cpu be_i386; @@ -698,19 +718,7 @@ int main(int argc, char** argv) case start_error_init: return -1; } - if (dbg_curr_process) - { - dbg_printf("WineDbg starting on pid %04x\n", dbg_curr_pid); - if (dbg_curr_process->active_debuggee) dbg_active_wait_for_first_exception(); - } - - dbg_interactiveP = TRUE; - parser_handle(hFile); - - while (dbg_process_list) - dbg_process_list->process_io->close_process(dbg_process_list, FALSE); - - dbg_save_internal_vars(); + dbg_start_interactive(hFile); return 0; } -- 2.11.4.GIT