Mail Archives: cygwin-developers/2000/04/20/21:27:31
Sigh. Wrong mailing list.
cgf
On Thu, Apr 20, 2000 at 10:25:40PM -0400, Chris Faylor wrote:
>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 <cgf AT cygnus DOT com>
>
> * 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
- Raw text -