delorie.com/archives/browse.cgi   search  
Mail Archives: cygwin-developers/2000/04/20/21:27:31

Mailing-List: contact cygwin-developers-help AT sourceware DOT cygnus DOT com; run by ezmlm
List-Subscribe: <mailto:cygwin-developers-subscribe AT sourceware DOT cygnus DOT com>
List-Archive: <http://sourceware.cygnus.com/ml/cygwin-developers/>
List-Post: <mailto:cygwin-developers AT sourceware DOT cygnus DOT com>
List-Help: <mailto:cygwin-developers-help AT sourceware DOT cygnus DOT com>, <http://sourceware.cygnus.com/ml/#faqs>
Sender: cygwin-developers-owner AT sourceware DOT cygnus DOT com
Delivered-To: mailing list cygwin-developers AT sourceware DOT cygnus DOT com
Date: Thu, 20 Apr 2000 22:27:10 -0400
From: Chris Faylor <cgf AT cygnus DOT com>
To: cygwin-developers AT sourceware DOT cygnus DOT com
Subject: Re: [PATCH] W2K accomodation and noisy DLL loading suppression
Message-ID: <20000420222710.A4166@cygnus.com>
Reply-To: cygwin-developers AT sourceware DOT cygnus DOT com
Mail-Followup-To: Chris Faylor <cgf AT cygnus DOT com>,
cygwin-developers AT sourceware DOT cygnus DOT com
References: <20000420222540 DOT A4100 AT cygnus DOT com>
Mime-Version: 1.0
User-Agent: Mutt/1.1.8i
In-Reply-To: <20000420222540.A4100@cygnus.com>; from cgf@cygnus.com on Thu, Apr 20, 2000 at 10:25:40PM -0400

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, &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

- Raw text -


  webmaster     delorie software   privacy  
  Copyright 2019   by DJ Delorie     Updated Jul 2019