Mailing-List: contact cygwin-developers-help AT sourceware DOT cygnus DOT com; run by ezmlm List-Subscribe: List-Archive: List-Post: List-Help: , Sender: cygwin-developers-owner AT sourceware DOT cygnus DOT com Delivered-To: mailing list cygwin-developers AT sourceware DOT cygnus DOT com From: Chris Faylor Date: Thu, 20 Apr 2000 22:25:40 -0400 To: cygwin-developers AT sourceware DOT cygnus DOT com Subject: [PATCH] W2K accomodation and noisy DLL loading suppression Message-ID: <20000420222540.A4100@cygnus.com> Reply-To: cygwin-developers AT sourceware DOT cygnus DOT com Mail-Followup-To: cgf AT cygnus DOT com, cygwin-developers AT sourceware DOT cygnus DOT com Mime-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline User-Agent: Mutt/1.1.8i I've just added the following patch to win32-nat.c. It eliminates complaints about Windows system DLLs not having line number information and attempts to work around inexplicably different behavior between W2K and previous WNT versions. In previous versions of Windows NT, gdb always received a bogus "breakpoint exception" that signalled the start of execution of the program. This seems to be missing in some cases under W2K. Coincidentally, Windows CE does things the W2K way (or is it vice versa?), so much of this code is borrowed from wince.c. cgf 2000-04-20 Christopher Faylor * win32-nat.c (thread_rec): Be more defensive about suspending already suspended threads. (safe_symbol_file_add_stub): New function. (safe_symbole_file_add_cleanup): New function. (safe_symbol_file_add): New function. (handle_load_dll): Use wrapper to add DLL symbol information to avoid bogus errors from non-stabs DLLs. (handle_exception): Add work around for detection of first exception breakpoint which does not seem to occur on W2K. Detect more "signals" that can be effectively passed to the debuggee. Reorganize to eliminate continue_status global. (child_continue): Reorganize to eliminate continue_status global. (child_wait): Ditto. (child_resume): Ditto. (get_child_debug_event): Ditto. Recognize when an a breakpoint exception should be ignored. Change method for signalling when an important event has occured to the caller. (child_create_inferior): Use new method for noticing when get_child_debug_event has found something interesting. Index: win32-nat.c =================================================================== RCS file: /cvs/src/src/gdb/win32-nat.c,v retrieving revision 1.5 diff -u -p -r1.5 win32-nat.c --- win32-nat.c 2000/03/25 02:26:21 1.5 +++ win32-nat.c 2000/04/21 02:24:02 @@ -79,6 +79,9 @@ static void child_stop PARAMS ((void)); static int win32_child_thread_alive PARAMS ((int)); void child_kill_inferior PARAMS ((void)); +static int last_sig = 0; /* Set if a signal was received from the + debugged process */ + /* Thread information structure used to track information that is not available in gdb's thread structure. */ typedef struct thread_info_struct @@ -94,9 +97,6 @@ typedef struct thread_info_struct static thread_info thread_head = {NULL}; -/* The saved state for a continue after breaking back to gdb. */ -static DWORD continue_status; - /* The process and thread handles for the above context. */ static DEBUG_EVENT current_event; /* The current debug event from @@ -104,6 +104,8 @@ static DEBUG_EVENT current_event; /* The static HANDLE current_process_handle; /* Currently executing process */ static thread_info *current_thread; /* Info on currently selected thread */ static DWORD main_thread_id; /* Thread ID of the main thread */ +static int ignore_first_first_chance = 0; /* True if we should ignore the + first first chance exception that we get. */ /* Counts of things. */ static int exception_count = 0; @@ -201,7 +203,7 @@ thread_rec (DWORD id, int get_context) { if (!th->suspend_count && get_context) { - if (get_context > 0) + if (get_context > 0 && id != current_event.dwThreadId) th->suspend_count = SuspendThread (th->h) + 1; else if (get_context < 0) th->suspend_count = -1; @@ -418,6 +420,55 @@ failed: return 0; } +struct safe_symbol_file_add_args +{ + char *name; + int from_tty; + struct section_addr_info *addrs; + int mainline; + int flags; + struct objfile *ret; +}; + +static int +safe_symbol_file_add_stub (void *argv) +{ +#define p ((struct safe_symbol_file_add_args *)argv) + p->ret = symbol_file_add (p->name, p->from_tty, p->addrs, p->mainline, p->flags); + return !!p->ret; +#undef p +} + +static void +safe_symbol_file_add_cleanup (void *gdb_stderrv) +{ + ui_file_delete (gdb_stderr); + gdb_stderr = (struct ui_file *)gdb_stderrv; +} + +static struct objfile * +safe_symbol_file_add (char *name, int from_tty, + struct section_addr_info *addrs, + int mainline, int flags) + +{ + struct safe_symbol_file_add_args p; + struct cleanup *cleanup; + + cleanup = make_cleanup (safe_symbol_file_add_cleanup, gdb_stderr); + + gdb_stderr = ui_file_new (); + p.name = name; + p.from_tty = from_tty; + p.addrs = addrs; + p.mainline = mainline; + p.flags = flags; + catch_errors (safe_symbol_file_add_stub, &p, "", RETURN_MASK_ERROR); + + do_cleanups (cleanup); + return p.ret; +} + /* Wait for child to do something. Return pid of child, or -1 in case of error; store status through argument pointer OURSTATUS. */ @@ -505,14 +556,11 @@ handle_load_dll (PTR dummy) /* The symbols in a dll are offset by 0x1000, which is the the offset from 0 of the first byte in an image - because - of the file header and the section alignment. - - FIXME: Is this the real reason that we need the 0x1000 ? */ + of the file header and the section alignment. */ - printf_unfiltered ("%x:%s", event->lpBaseOfDll, dll_name); section_addrs.text_addr = (int) event->lpBaseOfDll + 0x1000; - symbol_file_add (dll_name, 0, §ion_addrs, 0, OBJF_SHARED); - printf_unfiltered ("\n"); + safe_symbol_file_add (dll_name, 0, §ion_addrs, 0, OBJF_SHARED); + printf_unfiltered ("%x:%s\n", event->lpBaseOfDll, dll_name); return 1; } @@ -556,19 +604,24 @@ handle_exception (struct target_waitstat int i; int done = 0; thread_info *th; + int fc = ignore_first_first_chance; ourstatus->kind = TARGET_WAITKIND_STOPPED; + ignore_first_first_chance = 0; + /* Record the context of the current thread */ th = thread_rec (current_event.dwThreadId, -1); + last_sig = 0; + switch (current_event.u.Exception.ExceptionRecord.ExceptionCode) { case EXCEPTION_ACCESS_VIOLATION: DEBUG_EXCEPT (("gdb: Target exception ACCESS_VIOLATION at 0x%08x\n", current_event.u.Exception.ExceptionRecord.ExceptionAddress)); ourstatus->value.sig = TARGET_SIGNAL_SEGV; - continue_status = DBG_EXCEPTION_NOT_HANDLED; + last_sig = SIGSEGV; break; case STATUS_FLOAT_UNDERFLOW: case STATUS_FLOAT_DIVIDE_BY_ZERO: @@ -577,15 +630,19 @@ handle_exception (struct target_waitstat DEBUG_EXCEPT (("gdb: Target exception STACK_OVERFLOW at 0x%08x\n", current_event.u.Exception.ExceptionRecord.ExceptionAddress)); ourstatus->value.sig = TARGET_SIGNAL_FPE; - continue_status = DBG_EXCEPTION_NOT_HANDLED; break; case STATUS_STACK_OVERFLOW: DEBUG_EXCEPT (("gdb: Target exception STACK_OVERFLOW at 0x%08x\n", current_event.u.Exception.ExceptionRecord.ExceptionAddress)); ourstatus->value.sig = TARGET_SIGNAL_SEGV; - continue_status = DBG_EXCEPTION_NOT_HANDLED; break; case EXCEPTION_BREAKPOINT: + if (fc && current_event.u.Exception.dwFirstChance && + ((DWORD) current_event.u.Exception.ExceptionRecord.ExceptionAddress & 0xc0000000)) + { + last_sig = -1; + return 0; + } DEBUG_EXCEPT (("gdb: Target exception BREAKPOINT at 0x%08x\n", current_event.u.Exception.ExceptionRecord.ExceptionAddress)); ourstatus->value.sig = TARGET_SIGNAL_TRAP; @@ -594,7 +651,7 @@ handle_exception (struct target_waitstat DEBUG_EXCEPT (("gdb: Target exception CONTROL_C at 0x%08x\n", current_event.u.Exception.ExceptionRecord.ExceptionAddress)); ourstatus->value.sig = TARGET_SIGNAL_INT; - continue_status = DBG_EXCEPTION_NOT_HANDLED; + last_sig = SIGINT; /* FIXME - should check pass state */ break; case EXCEPTION_SINGLE_STEP: DEBUG_EXCEPT (("gdb: Target exception SINGLE_STEP at 0x%08x\n", @@ -605,21 +662,13 @@ handle_exception (struct target_waitstat DEBUG_EXCEPT (("gdb: Target exception SINGLE_ILL at 0x%08x\n", current_event.u.Exception.ExceptionRecord.ExceptionAddress)); ourstatus->value.sig = TARGET_SIGNAL_ILL; + last_sig = SIGILL; break; default: - /* This may be a structured exception handling exception. In - that case, we want to let the program try to handle it, and - only break if we see the exception a second time. - if (current_event.u.Exception.dwFirstChance) - - return 0; -*/ - printf_unfiltered ("gdb: unknown target exception 0x%08x at 0x%08x\n", current_event.u.Exception.ExceptionRecord.ExceptionCode, current_event.u.Exception.ExceptionRecord.ExceptionAddress); ourstatus->value.sig = TARGET_SIGNAL_UNKNOWN; - continue_status = DBG_EXCEPTION_NOT_HANDLED; break; } exception_count++; @@ -629,7 +678,7 @@ handle_exception (struct target_waitstat /* Resume all artificially suspended threads if we are continuing execution */ static BOOL -child_continue (int id) +child_continue (DWORD continue_status, int id) { int i; thread_info *th; @@ -653,108 +702,118 @@ child_continue (int id) return res; } +/* Get the next event from the child. Return 1 if the event requires + handling by WFI (or whatever). + */ static int get_child_debug_event (int pid, struct target_waitstatus *ourstatus, - DWORD *event_code, int *retval) + DWORD target_event_code, int *retval) { + int breakout = 0; BOOL debug_event; - int breakout = 1; + DWORD continue_status, event_code; + thread_info *th = NULL; + static thread_info dummy_thread_info; - if (!(debug_event = WaitForDebugEvent (¤t_event, 20))) + if (!(debug_event = WaitForDebugEvent (¤t_event, 1000))) { - breakout = *retval = *event_code = 0; + *retval = 0; goto out; } event_count++; continue_status = DBG_CONTINUE; *retval = 0; + + event_code = current_event.dwDebugEventCode; + breakout = event_code == target_event_code; - switch (*event_code = current_event.dwDebugEventCode) + switch (event_code) { case CREATE_THREAD_DEBUG_EVENT: DEBUG_EVENTS (("gdb: kernel event for pid=%d tid=%x code=%s)\n", - (unsigned) current_event.dwProcessId, - (unsigned) current_event.dwThreadId, - "CREATE_THREAD_DEBUG_EVENT")); + (unsigned) current_event.dwProcessId, + (unsigned) current_event.dwThreadId, + "CREATE_THREAD_DEBUG_EVENT")); /* Record the existence of this thread */ - child_add_thread (current_event.dwThreadId, - current_event.u.CreateThread.hThread); + th = child_add_thread (current_event.dwThreadId, + current_event.u.CreateThread.hThread); if (info_verbose) printf_unfiltered ("[New %s]\n", - target_pid_to_str (current_event.dwThreadId)); + target_pid_to_str (current_event.dwThreadId)); break; case EXIT_THREAD_DEBUG_EVENT: DEBUG_EVENTS (("gdb: kernel event for pid=%d tid=%d code=%s)\n", - (unsigned) current_event.dwProcessId, - (unsigned) current_event.dwThreadId, - "EXIT_THREAD_DEBUG_EVENT")); + (unsigned) current_event.dwProcessId, + (unsigned) current_event.dwThreadId, + "EXIT_THREAD_DEBUG_EVENT")); child_delete_thread (current_event.dwThreadId); + th = &dummy_thread_info; break; case CREATE_PROCESS_DEBUG_EVENT: DEBUG_EVENTS (("gdb: kernel event for pid=%d tid=%d code=%s)\n", - (unsigned) current_event.dwProcessId, - (unsigned) current_event.dwThreadId, - "CREATE_PROCESS_DEBUG_EVENT")); + (unsigned) current_event.dwProcessId, + (unsigned) current_event.dwThreadId, + "CREATE_PROCESS_DEBUG_EVENT")); current_process_handle = current_event.u.CreateProcessInfo.hProcess; main_thread_id = inferior_pid = current_event.dwThreadId; /* Add the main thread */ - current_thread = child_add_thread (inferior_pid, - current_event.u.CreateProcessInfo.hThread); + th = child_add_thread (inferior_pid, + current_event.u.CreateProcessInfo.hThread); break; case EXIT_PROCESS_DEBUG_EVENT: DEBUG_EVENTS (("gdb: kernel event for pid=%d tid=%d code=%s)\n", - (unsigned) current_event.dwProcessId, - (unsigned) current_event.dwThreadId, - "EXIT_PROCESS_DEBUG_EVENT")); + (unsigned) current_event.dwProcessId, + (unsigned) current_event.dwThreadId, + "EXIT_PROCESS_DEBUG_EVENT")); ourstatus->kind = TARGET_WAITKIND_EXITED; ourstatus->value.integer = current_event.u.ExitProcess.dwExitCode; CloseHandle (current_process_handle); *retval = current_event.dwProcessId; - goto out; + breakout = 1; + break; case LOAD_DLL_DEBUG_EVENT: DEBUG_EVENTS (("gdb: kernel event for pid=%d tid=%d code=%s)\n", - (unsigned) current_event.dwProcessId, - (unsigned) current_event.dwThreadId, - "LOAD_DLL_DEBUG_EVENT")); - catch_errors (handle_load_dll, NULL, "", RETURN_MASK_ALL); + (unsigned) current_event.dwProcessId, + (unsigned) current_event.dwThreadId, + "LOAD_DLL_DEBUG_EVENT")); + catch_errors (handle_load_dll, NULL, (char *) "", RETURN_MASK_ALL); registers_changed (); /* mark all regs invalid */ break; case UNLOAD_DLL_DEBUG_EVENT: DEBUG_EVENTS (("gdb: kernel event for pid=%d tid=%d code=%s)\n", - (unsigned) current_event.dwProcessId, - (unsigned) current_event.dwThreadId, - "UNLOAD_DLL_DEBUG_EVENT")); - break; /* FIXME: don't know what to do here */ + (unsigned) current_event.dwProcessId, + (unsigned) current_event.dwThreadId, + "UNLOAD_DLL_DEBUG_EVENT")); + break; /* FIXME: don't know what to do here */ case EXCEPTION_DEBUG_EVENT: DEBUG_EVENTS (("gdb: kernel event for pid=%d tid=%d code=%s)\n", - (unsigned) current_event.dwProcessId, - (unsigned) current_event.dwThreadId, - "EXCEPTION_DEBUG_EVENT")); - if (handle_exception (ourstatus)) /* sets continue_status */ + (unsigned) current_event.dwProcessId, + (unsigned) current_event.dwThreadId, + "EXCEPTION_DEBUG_EVENT")); + if (handle_exception (ourstatus)) + *retval = current_event.dwThreadId; + else { - *retval = current_event.dwThreadId; - goto out; + if (last_sig >= 0) + continue_status = DBG_EXCEPTION_NOT_HANDLED; + breakout = 0; } break; - case OUTPUT_DEBUG_STRING_EVENT: + case OUTPUT_DEBUG_STRING_EVENT: /* message from the kernel */ DEBUG_EVENTS (("gdb: kernel event for pid=%d tid=%d code=%s)\n", - (unsigned) current_event.dwProcessId, - (unsigned) current_event.dwThreadId, - "OUTPUT_DEBUG_STRING_EVENT")); - if (handle_output_debug_string (ourstatus)) - { - *retval = main_thread_id; - goto out; - } + (unsigned) current_event.dwProcessId, + (unsigned) current_event.dwThreadId, + "OUTPUT_DEBUG_STRING_EVENT")); + handle_output_debug_string ( ourstatus); break; default: printf_unfiltered ("gdb: kernel event for pid=%d tid=%d\n", @@ -765,15 +824,15 @@ get_child_debug_event (int pid, struct t break; } - breakout = 0; - CHECK (child_continue (-1)); - continue_status = 0; + if (breakout) + current_thread = th ?: thread_rec (current_event.dwThreadId, TRUE); + else + CHECK (child_continue (continue_status, -1)); out: return breakout; } - /* Wait for interesting events to occur in the target process. */ static int child_wait (int pid, struct target_waitstatus *ourstatus) @@ -788,22 +847,18 @@ child_wait (int pid, struct target_waits isn't necessarily what you think it is. */ while (1) - { - if (continue_status != 0) - CHECK (child_continue (-1)); - if (get_child_debug_event (pid, ourstatus, &event_code, &retval)) - return retval; - else - { - int detach = 0; + if (get_child_debug_event (pid, ourstatus, EXCEPTION_DEBUG_EVENT, &retval)) + return retval; + else + { + int detach = 0; - if (ui_loop_hook != NULL) - detach = ui_loop_hook (0); + if (ui_loop_hook != NULL) + detach = ui_loop_hook (0); - if (detach) - child_kill_inferior (); - } - } + if (detach) + child_kill_inferior (); + } } /* Attach to process PID, then initialize for debugging it. */ @@ -1031,22 +1086,21 @@ child_create_inferior (exec_file, allarg target_terminal_init (); target_terminal_inferior (); - /* Run until process and threads are loaded */ - do - get_child_debug_event (inferior_pid, &dummy, &event_code, &ret); - while (event_code != EXCEPTION_DEBUG_EVENT); + ignore_first_first_chance = 1; - SymSetOptions (SYMOPT_DEFERRED_LOADS); - SymInitialize (current_process_handle, NULL, TRUE); + /* Run until process and threads are loaded */ + while (!get_child_debug_event (inferior_pid, &dummy, + CREATE_PROCESS_DEBUG_EVENT, &ret)) + continue; + /* child_continue (DBG_CONTINUE, -1);*/ proceed ((CORE_ADDR) - 1, TARGET_SIGNAL_0, 0); } static void child_mourn_inferior () { - continue_status = DBG_CONTINUE; - (void) child_continue (-1); + (void) child_continue (DBG_CONTINUE, -1); unpush_target (&child_ops); generic_mourn_inferior (); } @@ -1092,8 +1146,7 @@ child_kill_inferior (void) for (;;) { - continue_status = DBG_CONTINUE; - if (!child_continue (-1)) + if (!child_continue (DBG_CONTINUE, -1)) break; if (!WaitForDebugEvent (¤t_event, INFINITE)) break; @@ -1111,8 +1164,11 @@ child_kill_inferior (void) void child_resume (int pid, int step, enum target_signal sig) { - int i; thread_info *th; + DWORD continue_status = last_sig > 0 && last_sig < NSIG ? + DBG_EXCEPTION_NOT_HANDLED : DBG_CONTINUE; + + last_sig = 0; DEBUG_EXEC (("gdb: child_resume (pid=%d, step=%d, sig=%d);\n", pid, step, sig)); @@ -1137,7 +1193,7 @@ child_resume (int pid, int step, enum ta /* Allow continuing with the same signal that interrupted us. Otherwise complain. */ - child_continue (pid); + child_continue (continue_status, pid); } static void @@ -1209,7 +1265,6 @@ init_child_ops (void) void _initialize_inftarg () { - struct cmd_list_element *c; init_child_ops (); add_show_from_set