[PATCH] W2K accomodation and noisy DLL loading suppression

Chris Faylor cgf@cygnus.com
Thu Apr 20 19:25:00 GMT 2000


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@cygnus.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, &section_addrs, 0, OBJF_SHARED);
-  printf_unfiltered ("\n");
+  safe_symbol_file_add (dll_name, 0, &section_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 (&current_event, 20)))
+  if (!(debug_event = WaitForDebugEvent (&current_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 (&current_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


More information about the Cygwin-developers mailing list