X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=gdb%2Fwindows-nat.c;h=c6a809b0b2f54ace8d39dd5859c721ace0aaf772;hb=9eee20eb5400345cab1952cbfc0426035ddf1140;hp=cce10f8818edead664a7b714c493175a73bdcd35;hpb=56db1d676cf48a3d90174f212379679d84bc3118;p=deliverable%2Fbinutils-gdb.git diff --git a/gdb/windows-nat.c b/gdb/windows-nat.c index cce10f8818..c6a809b0b2 100644 --- a/gdb/windows-nat.c +++ b/gdb/windows-nat.c @@ -1,6 +1,6 @@ /* Target-vector operations for controlling windows child processes, for GDB. - Copyright (C) 1995-2015 Free Software Foundation, Inc. + Copyright (C) 1995-2016 Free Software Foundation, Inc. Contributed by Cygnus Solutions, A Red Hat Company. @@ -56,6 +56,7 @@ #include "solist.h" #include "solib.h" #include "xml-support.h" +#include "inttypes.h" #include "i386-tdep.h" #include "i387-tdep.h" @@ -173,6 +174,19 @@ static int debug_registers_used; static int windows_initialization_done; #define DR6_CLEAR_VALUE 0xffff0ff0 +/* The exception thrown by a program to tell the debugger the name of + a thread. The exception record contains an ID of a thread and a + name to give it. This exception has no documented name, but MSDN + dubs it "MS_VC_EXCEPTION" in one code example. */ +#define MS_VC_EXCEPTION 0x406d1388 + +typedef enum +{ + HANDLE_EXCEPTION_UNHANDLED = 0, + HANDLE_EXCEPTION_HANDLED, + HANDLE_EXCEPTION_IGNORED +} handle_exception_result; + /* The string sent by cygwin when it processes a signal. FIXME: This should be in a cygwin include file. */ #ifndef _CYGWIN_SIGNAL_STRING @@ -440,6 +454,7 @@ windows_delete_thread (ptid_t ptid, DWORD exit_code) { windows_thread_info *here = th->next; th->next = here->next; + xfree (here->name); xfree (here); } } @@ -825,6 +840,25 @@ windows_clear_solib (void) solib_end = &solib_start; } +static void +signal_event_command (char *args, int from_tty) +{ + uintptr_t event_id = 0; + char *endargs = NULL; + + if (args == NULL) + error (_("signal-event requires an argument (integer event id)")); + + event_id = strtoumax (args, &endargs, 10); + + if ((errno == ERANGE) || (event_id == 0) || (event_id > UINTPTR_MAX) || + ((HANDLE) event_id == INVALID_HANDLE_VALUE)) + error (_("Failed to convert `%s' to event id"), args); + + SetEvent ((HANDLE) event_id); + CloseHandle ((HANDLE) event_id); +} + /* Handle DEBUG_STRING output from child process. Cygwin prepends its messages with a "cygwin:". Interpret this as a Cygwin signal. Otherwise just print the string as a warning. */ @@ -864,7 +898,7 @@ handle_output_debug_string (struct target_waitstatus *ourstatus) to treat this like a real signal. */ char *p; int sig = strtol (s + sizeof (_CYGWIN_SIGNAL_STRING) - 1, &p, 0); - int gotasig = gdb_signal_from_host (sig); + gdb_signal gotasig = gdb_signal_from_host (sig); ourstatus->value.sig = gotasig; if (gotasig) @@ -1011,16 +1045,17 @@ display_selectors (char * args, int from_tty) host_address_to_string (\ current_event.u.Exception.ExceptionRecord.ExceptionAddress)) -static int +static handle_exception_result handle_exception (struct target_waitstatus *ourstatus) { - windows_thread_info *th; - DWORD code = current_event.u.Exception.ExceptionRecord.ExceptionCode; + EXCEPTION_RECORD *rec = ¤t_event.u.Exception.ExceptionRecord; + DWORD code = rec->ExceptionCode; + handle_exception_result result = HANDLE_EXCEPTION_HANDLED; ourstatus->kind = TARGET_WAITKIND_STOPPED; /* Record the context of the current thread. */ - th = thread_rec (current_event.dwThreadId, -1); + thread_rec (current_event.dwThreadId, -1); switch (code) { @@ -1038,14 +1073,13 @@ handle_exception (struct target_waitstatus *ourstatus) cygwin-specific-signal. So, ignore SEGVs if they show up within the text segment of the DLL itself. */ const char *fn; - CORE_ADDR addr = (CORE_ADDR) (uintptr_t) - current_event.u.Exception.ExceptionRecord.ExceptionAddress; + CORE_ADDR addr = (CORE_ADDR) (uintptr_t) rec->ExceptionAddress; if ((!cygwin_exceptions && (addr >= cygwin_load_start && addr < cygwin_load_end)) || (find_pc_partial_function (addr, &fn, NULL, NULL) && startswith (fn, "KERNEL32!IsBad"))) - return 0; + return HANDLE_EXCEPTION_UNHANDLED; } #endif break; @@ -1121,10 +1155,48 @@ handle_exception (struct target_waitstatus *ourstatus) DEBUG_EXCEPTION_SIMPLE ("EXCEPTION_NONCONTINUABLE_EXCEPTION"); ourstatus->value.sig = GDB_SIGNAL_ILL; break; + case MS_VC_EXCEPTION: + if (rec->NumberParameters >= 3 + && (rec->ExceptionInformation[0] & 0xffffffff) == 0x1000) + { + DWORD named_thread_id; + windows_thread_info *named_thread; + CORE_ADDR thread_name_target; + + DEBUG_EXCEPTION_SIMPLE ("MS_VC_EXCEPTION"); + + thread_name_target = rec->ExceptionInformation[1]; + named_thread_id = (DWORD) (0xffffffff & rec->ExceptionInformation[2]); + + if (named_thread_id == (DWORD) -1) + named_thread_id = current_event.dwThreadId; + + named_thread = thread_rec (named_thread_id, 0); + if (named_thread != NULL) + { + int thread_name_len; + char *thread_name; + + thread_name_len = target_read_string (thread_name_target, + &thread_name, 1025, NULL); + if (thread_name_len > 0) + { + thread_name[thread_name_len - 1] = '\0'; + xfree (named_thread->name); + named_thread->name = thread_name; + } + else + xfree (thread_name); + } + ourstatus->value.sig = GDB_SIGNAL_TRAP; + result = HANDLE_EXCEPTION_IGNORED; + break; + } + /* treat improperly formed exception as unknown, fallthrough */ default: /* Treat unhandled first chance exceptions specially. */ if (current_event.u.Exception.dwFirstChance) - return -1; + return HANDLE_EXCEPTION_UNHANDLED; printf_unfiltered ("gdb: unknown target exception 0x%08x at %s\n", (unsigned) current_event.u.Exception.ExceptionRecord.ExceptionCode, host_address_to_string ( @@ -1134,7 +1206,7 @@ handle_exception (struct target_waitstatus *ourstatus) } exception_count++; last_sig = ourstatus->value.sig; - return 1; + return result; } /* Resume thread specified by ID, or all artificially suspended @@ -1445,7 +1517,7 @@ get_windows_debug_event (struct target_ops *ops, if (!windows_initialization_done) { target_terminal_ours (); - target_mourn_inferior (); + target_mourn_inferior (inferior_ptid); error (_("During startup program exited with code 0x%x."), (unsigned int) current_event.u.ExitProcess.dwExitCode); } @@ -1493,15 +1565,15 @@ get_windows_debug_event (struct target_ops *ops, break; switch (handle_exception (ourstatus)) { - case 0: + case HANDLE_EXCEPTION_UNHANDLED: + default: continue_status = DBG_EXCEPTION_NOT_HANDLED; break; - case 1: + case HANDLE_EXCEPTION_HANDLED: thread_id = current_event.dwThreadId; break; - case -1: - last_sig = 1; - continue_status = -1; + case HANDLE_EXCEPTION_IGNORED: + continue_status = DBG_CONTINUE; break; } break; @@ -1529,10 +1601,7 @@ get_windows_debug_event (struct target_ops *ops, if (!thread_id || saw_create != 1) { - if (continue_status == -1) - windows_resume (ops, minus_one_ptid, 0, 1); - else - CHECK (windows_continue (continue_status, -1, 0)); + CHECK (windows_continue (continue_status, -1, 0)); } else { @@ -1906,7 +1975,7 @@ windows_get_exec_module_filename (char *exe_name_ret, size_t exe_name_max_len) /* Cygwin prefers that the path be in /x/y/z format, so extract the filename into a temporary buffer first, and then convert it to POSIX format into the destination buffer. */ - cygwin_buf_t *pathbuf = alloca (exe_name_max_len * sizeof (cygwin_buf_t)); + cygwin_buf_t *pathbuf = (cygwin_buf_t *) alloca (exe_name_max_len * sizeof (cygwin_buf_t)); len = GetModuleFileNameEx (current_process_handle, dh_buf, pathbuf, exe_name_max_len); @@ -2395,7 +2464,7 @@ windows_kill_inferior (struct target_ops *ops) break; } - target_mourn_inferior (); /* Or just windows_mourn_inferior? */ + target_mourn_inferior (inferior_ptid); /* Or just windows_mourn_inferior? */ } static void @@ -2507,6 +2576,14 @@ windows_get_ada_task_ptid (struct target_ops *self, long lwp, long thread) return ptid_build (ptid_get_pid (inferior_ptid), 0, lwp); } +/* Implementation of the to_thread_name method. */ + +static const char * +windows_thread_name (struct target_ops *self, struct thread_info *thr) +{ + return thread_rec (ptid_get_tid (thr->ptid), 0)->name; +} + static struct target_ops * windows_target (void) { @@ -2531,6 +2608,7 @@ windows_target (void) t->to_pid_to_exec_file = windows_pid_to_exec_file; t->to_get_ada_task_ptid = windows_get_ada_task_ptid; t->to_get_tib_address = windows_get_tib_address; + t->to_thread_name = windows_thread_name; return t; } @@ -2563,6 +2641,13 @@ _initialize_windows_nat (void) cygwin_internal (CW_SET_DOS_FILE_WARNING, 0); #endif + add_com ("signal-event", class_run, signal_event_command, _("\ +Signal a crashed process with event ID, to allow its debugging.\n\ +This command is needed in support of setting up GDB as JIT debugger on \ +MS-Windows. The command should be invoked from the GDB command line using \ +the '-ex' command-line option. The ID of the event that blocks the \ +crashed process will be supplied by the Windows JIT debugging mechanism.")); + #ifdef __CYGWIN__ add_setshow_boolean_cmd ("shell", class_support, &useshell, _("\ Set use of shell to start subprocess."), _("\ @@ -2714,7 +2799,7 @@ _initialize_check_for_gdb_ini (void) { char *p; char *oldini = (char *) alloca (strlen (homedir) + - sizeof ("/gdb.ini")); + sizeof ("gdb.ini") + 1); strcpy (oldini, homedir); p = strchr (oldini, '\0'); if (p > oldini && !IS_DIR_SEPARATOR (p[-1])) @@ -2723,9 +2808,9 @@ _initialize_check_for_gdb_ini (void) if (access (oldini, 0) == 0) { int len = strlen (oldini); - char *newini = (char *) alloca (len + 1); + char *newini = (char *) alloca (len + 2); - xsnprintf (newini, len + 1, "%.*s.gdbinit", + xsnprintf (newini, len + 2, "%.*s.gdbinit", (int) (len - (sizeof ("gdb.ini") - 1)), oldini); warning (_("obsolete '%s' found. Rename to '%s'."), oldini, newini); } @@ -2842,7 +2927,8 @@ _initialize_loadable (void) { GPA (hm, EnumProcessModules); GPA (hm, GetModuleInformation); - GPA (hm, GetModuleFileNameEx); + GetModuleFileNameEx = (GetModuleFileNameEx_ftype *) + GetProcAddress (hm, GetModuleFileNameEx_name); } if (!EnumProcessModules || !GetModuleInformation || !GetModuleFileNameEx)