* win32-nat.c (safe_symbol_file_add_cleanup): Ensure that gdb_stderr is flushed
authorChristopher Faylor <me+cygwin@cgf.cx>
Sun, 4 Jun 2000 00:28:17 +0000 (00:28 +0000)
committerChristopher Faylor <me+cygwin@cgf.cx>
Sun, 4 Jun 2000 00:28:17 +0000 (00:28 +0000)
before deleting and restoring it.
(safe_symbol_file_add): Ensure that gdb_stderr is flushed before reassigning
it.
(handle_load_dll): Split into two functions so that WFI can handle shared
library events.
(child_solib_loaded_library_pathname): New function.
(child_clear_solibs): New function.  Clears shared library list.
(child_solib_add): New function.  Adds shared library symbols.
(dll_symbol_command): New function.  Handles "dll-symbol" command.
(info_dll_command): New function.  Handles info "sharedlibrary" command.
(handle_exceptions): Eliminate 'ignore_trap' argument.
(get_child_debug_event): Eliminate two arguments.  Return "pid" when
appropriate.  Break out on most events to allow WFI to handle stuff.
(child_wait): Accomodate get_child_debug_event changes.
(child_attach): Clear thread list and list of loaded dlls.
(child_create_inferior): Clear list of loaded dlls.  Use wait_for_inferior in a
loop to look for first "trap".
(child_resume): Avoid accessing a possibly-freed thread pointer.
(_initialize_inftarg): Add "dll-symbols", "sharedlibrary", and "info
dll", and "info sharedlibrary" commands.
* config/i386/tm-cygwin.h: Add some shared library (aka DLL) hooks.

gdb/ChangeLog
gdb/config/i386/tm-cygwin.h
gdb/win32-nat.c
gdb/windows-nat.c

index da0f2369190813c2dc0bcc08c730c7cf9266a919..85cbd2a576cdd6bd4c878030594d31f4fdc1d46b 100644 (file)
@@ -1,3 +1,29 @@
+2000-06-03  Christopher Faylor  <cgf@cygnus.com>
+
+       * win32-nat.c (safe_symbol_file_add_cleanup): Ensure that gdb_stderr is
+       flushed before deleting and restoring it.
+       (safe_symbol_file_add): Ensure that gdb_stderr is flushed before
+       reassigning it.
+       (handle_load_dll): Split into two functions so that WFI can handle
+       shared library events.
+       (child_solib_loaded_library_pathname): New function.
+       (child_clear_solibs): New function.  Clears shared library list.
+       (child_solib_add): New function.  Adds shared library symbols.
+       (dll_symbol_command): New function.  Handles "dll-symbol" command.
+       (info_dll_command): New function.  Handles info
+       "sharedlibrary" command.
+       (handle_exceptions): Eliminate 'ignore_trap' argument.
+       (get_child_debug_event): Eliminate two arguments.  Return "pid" when
+       appropriate.  Break out on most events to allow WFI to handle stuff.
+       (child_wait): Accomodate get_child_debug_event changes.
+       (child_attach): Clear thread list and list of loaded dlls.
+       (child_create_inferior): Clear list of loaded dlls.  Use
+       wait_for_inferior in a loop to look for first "trap".
+       (child_resume): Avoid accessing a possibly-freed thread pointer.
+       (_initialize_inftarg): Add "dll-symbols", "sharedlibrary", and "info
+       sharedlibrary" commands.
+       * config/i386/tm-cygwin.h: Add some shared library (aka DLL) hooks.
+
 2000-06-02  Christopher Faylor  <cgf@cygnus.com>
 
        * win32-nat.c: Fix up gcc warnings throughout.
index 597ea511a5119a41cc57c2b0e1aa785379949c2a..5ae97bbf8722eddd75e0080c20947dbad3fba1c3 100644 (file)
 
 #include "i386/tm-i386v.h"
 
+#if 0
 #define IN_SOLIB_CALL_TRAMPOLINE(pc, name) skip_trampoline_code (pc, name)
 #define SKIP_TRAMPOLINE_CODE(pc)           skip_trampoline_code (pc, 0)
 extern CORE_ADDR skip_trampoline_code (CORE_ADDR pc, char *name);
-
-extern char *cygwin_pid_to_str (int pid);
+#endif
+
+#define SOLIB_ADD(filename, from_tty, targ) child_solib_add(filename, from_tty, targ)
+#define SOLIB_LOADED_LIBRARY_PATHNAME(pid) child_solib_loaded_library_pathname(pid)
+#define CLEAR_SOLIB child_clear_solib
+#define ADD_SHARED_SYMBOL_FILES dll_symbol_command
+
+struct target_ops;
+char *cygwin_pid_to_str (int pid);
+void child_solib_add (char *, int, struct target_ops *);
+char *child_solib_loaded_library_pathname(int);
+void child_clear_solib (void);
+void dll_symbol_command (char *, int);
index e1e2898078aa3e30fe10f54a963a71e04c813759..7f0cb78d6479532e1d5a5fa250ed042904492fc5 100644 (file)
@@ -58,8 +58,6 @@ extern int (*ui_loop_hook) PARAMS ((int signo));
 #define CONTEXT_DEBUGGER (CONTEXT_FULL | CONTEXT_FLOATING_POINT)
 #endif
 
-#define FIRST_EXCEPTION 0xffffffff
-
 /* The string sent by cygwin when it processes a signal.
    FIXME: This should be in a cygwin include file. */
 #define CYGWIN_SIGNAL_STRING "cygwin: signal"
@@ -415,6 +413,8 @@ failed:
   return 0;
 }
 
+/* Encapsulate the information required in a call to
+   symbol_file_add_args */
 struct safe_symbol_file_add_args
 {
   char *name;
@@ -425,6 +425,8 @@ struct safe_symbol_file_add_args
   struct objfile *ret;
 };
 
+/* Call symbol_file_add with stderr redirected.  We don't care if there
+   are errors. */
 static int
 safe_symbol_file_add_stub (void *argv)
 {
@@ -434,13 +436,16 @@ safe_symbol_file_add_stub (void *argv)
 #undef p
 }
 
+/* Restore gdb's stderr after calling symbol_file_add */
 static void
 safe_symbol_file_add_cleanup (void *gdb_stderrv)
 {
+  gdb_flush (gdb_stderr);
   ui_file_delete (gdb_stderr);
   gdb_stderr = (struct ui_file *)gdb_stderrv;
 }
 
+/* symbol_file_add wrapper that prevents errors from being displayed. */
 static struct objfile *
 safe_symbol_file_add (char *name, int from_tty,
                      struct section_addr_info *addrs,
@@ -452,6 +457,7 @@ safe_symbol_file_add (char *name, int from_tty,
 
   cleanup = make_cleanup (safe_symbol_file_add_cleanup, gdb_stderr);
 
+  gdb_flush (gdb_stderr);
   gdb_stderr = ui_file_new ();
   p.name = name;
   p.from_tty = from_tty;
@@ -464,9 +470,19 @@ safe_symbol_file_add (char *name, int from_tty,
   return p.ret;
 }
 
+/* Maintain a linked list of "so" information. */
+struct so_stuff
+{
+  struct so_stuff *next, **last;
+  DWORD load_addr;
+  char name[0];
+} solib_start, *solib_end;
+
+/* Remember the maximum DLL length for printing in info dll command. */
+int max_dll_name_len;
+
 /* Wait for child to do something.  Return pid of child, or -1 in case
    of error; store status through argument pointer OURSTATUS.  */
-
 static int
 handle_load_dll (PTR dummy ATTRIBUTE_UNUSED)
 {
@@ -474,10 +490,12 @@ handle_load_dll (PTR dummy ATTRIBUTE_UNUSED)
   DWORD dll_name_ptr;
   DWORD done;
   char dll_buf[MAX_PATH + 1];
-  char *p, *dll_name = NULL;
-  struct section_addr_info section_addrs;
+  struct so_stuff *so, *solast;
+  char *dll_name = NULL;
+  DWORD dll_base = 0;
+  int len;
+  char *p;
 
-  memset (&section_addrs, 0, sizeof (section_addrs));
   dll_buf[0] = dll_buf[sizeof (dll_buf) - 1] = '\0';
 
   if (!psapi_get_dll_name ((DWORD) (event->lpBaseOfDll), dll_buf))
@@ -549,16 +567,94 @@ handle_load_dll (PTR dummy ATTRIBUTE_UNUSED)
   while ((p = strchr (dll_name, '\\')))
     *p = '/';
 
+  so = (struct so_stuff *) xmalloc (sizeof (struct so_stuff) +  strlen (dll_name) + 8 + 2);
+  so->load_addr = (DWORD) event->lpBaseOfDll + 0x1000;
+  strcpy (so->name, dll_name);
+
+  solib_end->next = so;
+  solib_end = so;
+  so->next = NULL;
+
+  len = strlen (dll_name);
+  if (len > max_dll_name_len)
+    max_dll_name_len = len;
+
+  return 1;
+}
+
+/* Return name of last loaded DLL. */
+char *
+child_solib_loaded_library_pathname (int pid)
+{
+  return !solib_end || !solib_end->name[0]? NULL : solib_end->name;
+}
+
+/* Clear list of loaded DLLs. */
+void
+child_clear_solibs (void)
+{
+  struct so_stuff *so, *so1 = solib_start.next;
+
+  while ((so = so1) != NULL)
+    {
+      so1 = so->next;
+      free (so);
+    }
+
+  solib_start.next = NULL;
+  solib_end = &solib_start;
+  max_dll_name_len = sizeof ("DLL Name") - 1;
+}
+
+/* Add DLL symbol information. */
+void
+child_solib_add (char *filename, int from_tty, struct target_ops *t)
+{
+  struct section_addr_info section_addrs;
+
   /* 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. */
 
+  if (!solib_end || !solib_end->name[0])
+    return;
+
+  memset (&section_addrs, 0, sizeof (section_addrs));
   section_addrs.other[0].name = ".text";
-  section_addrs.other[0].addr = (int) event->lpBaseOfDll + 0x1000;
-  safe_symbol_file_add (dll_name, 0, &section_addrs, 0, OBJF_SHARED);
-  printf_unfiltered ("%lx:%s\n", (DWORD) event->lpBaseOfDll, dll_name);
+  section_addrs.other[0].addr = solib_end->load_addr;
+  safe_symbol_file_add (solib_end->name, 0, &section_addrs, 0, OBJF_SHARED);
 
-  return 1;
+  return;
+}
+
+/* Load DLL symbol info. */
+void
+dll_symbol_command (char *args, int from_tty)
+{
+  struct section_addr_info section_addrs;
+
+  dont_repeat ();
+  
+  if (args == NULL)
+    error ("dll-symbols requires a file name");
+
+  safe_symbol_file_add (args, 0, NULL, 0, OBJF_SHARED);
+} 
+
+/* List currently loaded DLLs. */
+void
+info_dll_command (char *ignore, int from_tty)
+{
+  struct so_stuff *so = &solib_start;
+
+  if (!so->next)
+    return;
+
+  printf ("%*s  Load Address\n", -max_dll_name_len, "DLL Name");
+  while ((so = so->next) != NULL)
+    printf_unfiltered ("%*s  %08lx\n", -max_dll_name_len, so->name, so->load_addr);
+
+  return;
 }
 
 /* Handle DEBUG_STRING output from child process.
@@ -595,14 +691,11 @@ handle_output_debug_string (struct target_waitstatus *ourstatus)
 }
 
 static int
-handle_exception (struct target_waitstatus *ourstatus, int ignore_trap)
+handle_exception (struct target_waitstatus *ourstatus)
 {
   thread_info *th;
   DWORD code = current_event.u.Exception.ExceptionRecord.ExceptionCode;
 
-  if (ignore_trap && code == EXCEPTION_BREAKPOINT)
-    return 0;
-
   ourstatus->kind = TARGET_WAITKIND_STOPPED;
 
   /* Record the context of the current thread */
@@ -696,16 +789,15 @@ child_continue (DWORD continue_status, int id)
    handling by WFI (or whatever).
  */
 static int
-get_child_debug_event (int pid ATTRIBUTE_UNUSED, struct target_waitstatus *ourstatus,
-                      DWORD target_event_code, int *retval)
+get_child_debug_event (int pid ATTRIBUTE_UNUSED, struct target_waitstatus *ourstatus)
 {
   int breakout = 0;
   BOOL debug_event;
   DWORD continue_status, event_code;
   thread_info *th = NULL;
   static thread_info dummy_thread_info;
+  int retval = 0;
 
-  *retval = 0;
   if (!(debug_event = WaitForDebugEvent (&current_event, 1000)))
     goto out;
 
@@ -713,7 +805,7 @@ get_child_debug_event (int pid ATTRIBUTE_UNUSED, struct target_waitstatus *ourst
   continue_status = DBG_CONTINUE;
 
   event_code = current_event.dwDebugEventCode;
-  breakout = event_code == target_event_code;
+  ourstatus->kind = TARGET_WAITKIND_SPURIOUS;
 
   switch (event_code)
     {
@@ -728,6 +820,7 @@ get_child_debug_event (int pid ATTRIBUTE_UNUSED, struct target_waitstatus *ourst
       if (info_verbose)
        printf_unfiltered ("[New %s]\n",
                           target_pid_to_str (current_event.dwThreadId));
+      retval = current_event.dwThreadId;
       break;
 
     case EXIT_THREAD_DEBUG_EVENT:
@@ -748,8 +841,11 @@ get_child_debug_event (int pid ATTRIBUTE_UNUSED, struct target_waitstatus *ourst
 
       main_thread_id = inferior_pid = current_event.dwThreadId;
       /* Add the main thread */
+      th = child_add_thread (current_event.dwProcessId,
+                            current_event.u.CreateProcessInfo.hProcess);
       th = child_add_thread (inferior_pid,
                             current_event.u.CreateProcessInfo.hThread);
+      retval = ourstatus->value.related_pid = current_event.dwProcessId;
       break;
 
     case EXIT_PROCESS_DEBUG_EVENT:
@@ -760,8 +856,7 @@ get_child_debug_event (int pid ATTRIBUTE_UNUSED, struct target_waitstatus *ourst
       ourstatus->kind = TARGET_WAITKIND_EXITED;
       ourstatus->value.integer = current_event.u.ExitProcess.dwExitCode;
       CloseHandle (current_process_handle);
-      *retval = current_event.dwProcessId;
-      breakout = 1;
+      retval = current_event.dwProcessId;
       break;
 
     case LOAD_DLL_DEBUG_EVENT:
@@ -771,6 +866,9 @@ get_child_debug_event (int pid ATTRIBUTE_UNUSED, struct target_waitstatus *ourst
                     "LOAD_DLL_DEBUG_EVENT"));
       catch_errors (handle_load_dll, NULL, (char *) "", RETURN_MASK_ALL);
       registers_changed ();    /* mark all regs invalid */
+      ourstatus->kind = TARGET_WAITKIND_LOADED;
+      ourstatus->value.integer = 0;
+      retval = current_event.dwProcessId;
       break;
 
     case UNLOAD_DLL_DEBUG_EVENT:
@@ -785,10 +883,8 @@ get_child_debug_event (int pid ATTRIBUTE_UNUSED, struct target_waitstatus *ourst
                     (unsigned) current_event.dwProcessId,
                     (unsigned) current_event.dwThreadId,
                     "EXCEPTION_DEBUG_EVENT"));
-      if (handle_exception (ourstatus, target_event_code == FIRST_EXCEPTION))
-       *retval = current_event.dwThreadId;
-      else
-       breakout = -1;
+      handle_exception (ourstatus);
+      retval = current_event.dwThreadId;
       break;
 
     case OUTPUT_DEBUG_STRING_EVENT:    /* message from the kernel */
@@ -796,7 +892,8 @@ get_child_debug_event (int pid ATTRIBUTE_UNUSED, struct target_waitstatus *ourst
                     (unsigned) current_event.dwProcessId,
                     (unsigned) current_event.dwThreadId,
                     "OUTPUT_DEBUG_STRING_EVENT"));
-      handle_output_debug_string ( ourstatus);
+      if (handle_output_debug_string ( ourstatus))
+       retval = current_event.dwProcessId;
       break;
     default:
       printf_unfiltered ("gdb: kernel event for pid=%ld tid=%ld\n",
@@ -807,21 +904,19 @@ get_child_debug_event (int pid ATTRIBUTE_UNUSED, struct target_waitstatus *ourst
       break;
     }
 
-  if (breakout > 0)
-    current_thread = th ?: thread_rec (current_event.dwThreadId, TRUE);
-  else if (!breakout)
+  if (!retval)
     CHECK (child_continue (continue_status, -1));
+  else
+    current_thread = th ?: thread_rec (current_event.dwThreadId, TRUE);
 
 out:
-  return breakout;
+  return retval;
 }
 
 /* Wait for interesting events to occur in the target process. */
 static int
 child_wait (int pid, struct target_waitstatus *ourstatus)
 {
-  int retval;
-
   /* We loop when we get a non-standard exception rather than return
      with a SPURIOUS because resume can try and step or modify things,
      which needs a current_thread->h.  But some of these exceptions mark
@@ -829,18 +924,21 @@ child_wait (int pid, struct target_waitstatus *ourstatus)
      isn't necessarily what you think it is. */
 
   while (1)
-    if (get_child_debug_event (pid, ourstatus, EXCEPTION_DEBUG_EVENT, &retval))
-      return retval;
-    else
-      {
-       int detach = 0;
+    {
+      int retval = get_child_debug_event (pid, ourstatus);
+      if (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.  */
@@ -865,6 +963,9 @@ child_attach (args, from_tty)
   exception_count = 0;
   event_count = 0;
 
+  child_init_thread_list ();
+  child_clear_solibs ();
+
   if (from_tty)
     {
       char *exec_file = (char *) get_exec_file (0);
@@ -936,11 +1037,10 @@ child_create_inferior (exec_file, allargs, env)
   BOOL ret;
   DWORD flags;
   char *args;
+  extern int stop_after_trap;
 
   if (!exec_file)
-    {
-      error ("No executable specified, use `target exec'.\n");
-    }
+    error ("No executable specified, use `target exec'.\n");
 
   memset (&si, 0, sizeof (si));
   si.cb = sizeof (si);
@@ -1057,16 +1157,23 @@ child_create_inferior (exec_file, allargs, env)
   inferior_pid = current_event.dwThreadId = pi.dwThreadId;
   push_target (&child_ops);
   child_init_thread_list ();
-  init_wait_for_inferior ();
+  child_clear_solibs ();
   clear_proceed_status ();
+  init_wait_for_inferior ();
   target_terminal_init ();
   target_terminal_inferior ();
   last_sig = 0;
 
-  /* Run until process and threads are loaded */
-  while (!get_child_debug_event (inferior_pid, &dummy,
-                                FIRST_EXCEPTION, &ret))
-    continue;
+  while (1)
+    {
+      stop_after_trap = 1;
+      wait_for_inferior ();
+      if (stop_signal != TARGET_SIGNAL_TRAP)
+       resume (0, stop_signal);
+      else
+       break;
+    }
+  stop_after_trap = 0;
 
   /* child_continue (DBG_CONTINUE, -1);*/
   proceed ((CORE_ADDR) - 1, TARGET_SIGNAL_0, 0);
@@ -1150,19 +1257,20 @@ child_resume (int pid, int step, enum target_signal sig)
 
   /* Get context for currently selected thread */
   th = thread_rec (current_event.dwThreadId, FALSE);
-  if (step)
+  if (th)
     {
-#ifdef i386
-      /* Single step by setting t bit */
-      child_fetch_inferior_registers (PS_REGNUM);
-      th->context.EFlags |= FLAG_TRACE_BIT;
-#endif
-    }
+      if (step)
+       {
+         /* Single step by setting t bit */
+         child_fetch_inferior_registers (PS_REGNUM);
+         th->context.EFlags |= FLAG_TRACE_BIT;
+       }
 
-  if (th->context.ContextFlags)
-    {
-      CHECK (SetThreadContext (th->h, &th->context));
-      th->context.ContextFlags = 0;
+      if (th->context.ContextFlags)
+       {
+         CHECK (SetThreadContext (th->h, &th->context));
+         th->context.ContextFlags = 0;
+       }
     }
 
   /* Allow continuing with the same signal that interrupted us.
@@ -1242,48 +1350,50 @@ _initialize_inftarg ()
 {
   init_child_ops ();
 
-  add_show_from_set
-    (add_set_cmd ("new-console", class_support, var_boolean,
+  add_com ("dll-symbols", class_files, dll_symbol_command,
+           "Load dll library symbols from FILE.");
+
+  add_com_alias ("sharedlibrary", "dll-symbols", class_alias, 1);
+
+  add_show_from_set (add_set_cmd ("new-console", class_support, var_boolean,
                  (char *) &new_console,
                  "Set creation of new console when creating child process.",
                  &setlist),
      &showlist);
 
-  add_show_from_set
-    (add_set_cmd ("new-group", class_support, var_boolean,
+  add_show_from_set (add_set_cmd ("new-group", class_support, var_boolean,
                  (char *) &new_group,
                  "Set creation of new group when creating child process.",
                  &setlist),
      &showlist);
 
-  add_show_from_set
-    (add_set_cmd ("debugexec", class_support, var_boolean,
+  add_show_from_set (add_set_cmd ("debugexec", class_support, var_boolean,
                  (char *) &debug_exec,
                  "Set whether to display execution in child process.",
                  &setlist),
      &showlist);
 
-  add_show_from_set
-    (add_set_cmd ("debugevents", class_support, var_boolean,
+  add_show_from_set (add_set_cmd ("debugevents", class_support, var_boolean,
                  (char *) &debug_events,
                  "Set whether to display kernel events in child process.",
                  &setlist),
      &showlist);
 
-  add_show_from_set
-    (add_set_cmd ("debugmemory", class_support, var_boolean,
+  add_show_from_set (add_set_cmd ("debugmemory", class_support, var_boolean,
                  (char *) &debug_memory,
                  "Set whether to display memory accesses in child process.",
                  &setlist),
      &showlist);
 
-  add_show_from_set
-    (add_set_cmd ("debugexceptions", class_support, var_boolean,
+  add_show_from_set (add_set_cmd ("debugexceptions", class_support, var_boolean,
                  (char *) &debug_exceptions,
-              "Set whether to display kernel exceptions in child process.",
+                 "Set whether to display kernel exceptions in child process.",
                  &setlist),
      &showlist);
 
+  add_info ("dll", info_dll_command, "Status of loaded DLLs.");
+  add_info_alias ("sharedlibrary", "dll", 1);
+
   add_target (&child_ops);
 }
 
index e1e2898078aa3e30fe10f54a963a71e04c813759..7f0cb78d6479532e1d5a5fa250ed042904492fc5 100644 (file)
@@ -58,8 +58,6 @@ extern int (*ui_loop_hook) PARAMS ((int signo));
 #define CONTEXT_DEBUGGER (CONTEXT_FULL | CONTEXT_FLOATING_POINT)
 #endif
 
-#define FIRST_EXCEPTION 0xffffffff
-
 /* The string sent by cygwin when it processes a signal.
    FIXME: This should be in a cygwin include file. */
 #define CYGWIN_SIGNAL_STRING "cygwin: signal"
@@ -415,6 +413,8 @@ failed:
   return 0;
 }
 
+/* Encapsulate the information required in a call to
+   symbol_file_add_args */
 struct safe_symbol_file_add_args
 {
   char *name;
@@ -425,6 +425,8 @@ struct safe_symbol_file_add_args
   struct objfile *ret;
 };
 
+/* Call symbol_file_add with stderr redirected.  We don't care if there
+   are errors. */
 static int
 safe_symbol_file_add_stub (void *argv)
 {
@@ -434,13 +436,16 @@ safe_symbol_file_add_stub (void *argv)
 #undef p
 }
 
+/* Restore gdb's stderr after calling symbol_file_add */
 static void
 safe_symbol_file_add_cleanup (void *gdb_stderrv)
 {
+  gdb_flush (gdb_stderr);
   ui_file_delete (gdb_stderr);
   gdb_stderr = (struct ui_file *)gdb_stderrv;
 }
 
+/* symbol_file_add wrapper that prevents errors from being displayed. */
 static struct objfile *
 safe_symbol_file_add (char *name, int from_tty,
                      struct section_addr_info *addrs,
@@ -452,6 +457,7 @@ safe_symbol_file_add (char *name, int from_tty,
 
   cleanup = make_cleanup (safe_symbol_file_add_cleanup, gdb_stderr);
 
+  gdb_flush (gdb_stderr);
   gdb_stderr = ui_file_new ();
   p.name = name;
   p.from_tty = from_tty;
@@ -464,9 +470,19 @@ safe_symbol_file_add (char *name, int from_tty,
   return p.ret;
 }
 
+/* Maintain a linked list of "so" information. */
+struct so_stuff
+{
+  struct so_stuff *next, **last;
+  DWORD load_addr;
+  char name[0];
+} solib_start, *solib_end;
+
+/* Remember the maximum DLL length for printing in info dll command. */
+int max_dll_name_len;
+
 /* Wait for child to do something.  Return pid of child, or -1 in case
    of error; store status through argument pointer OURSTATUS.  */
-
 static int
 handle_load_dll (PTR dummy ATTRIBUTE_UNUSED)
 {
@@ -474,10 +490,12 @@ handle_load_dll (PTR dummy ATTRIBUTE_UNUSED)
   DWORD dll_name_ptr;
   DWORD done;
   char dll_buf[MAX_PATH + 1];
-  char *p, *dll_name = NULL;
-  struct section_addr_info section_addrs;
+  struct so_stuff *so, *solast;
+  char *dll_name = NULL;
+  DWORD dll_base = 0;
+  int len;
+  char *p;
 
-  memset (&section_addrs, 0, sizeof (section_addrs));
   dll_buf[0] = dll_buf[sizeof (dll_buf) - 1] = '\0';
 
   if (!psapi_get_dll_name ((DWORD) (event->lpBaseOfDll), dll_buf))
@@ -549,16 +567,94 @@ handle_load_dll (PTR dummy ATTRIBUTE_UNUSED)
   while ((p = strchr (dll_name, '\\')))
     *p = '/';
 
+  so = (struct so_stuff *) xmalloc (sizeof (struct so_stuff) +  strlen (dll_name) + 8 + 2);
+  so->load_addr = (DWORD) event->lpBaseOfDll + 0x1000;
+  strcpy (so->name, dll_name);
+
+  solib_end->next = so;
+  solib_end = so;
+  so->next = NULL;
+
+  len = strlen (dll_name);
+  if (len > max_dll_name_len)
+    max_dll_name_len = len;
+
+  return 1;
+}
+
+/* Return name of last loaded DLL. */
+char *
+child_solib_loaded_library_pathname (int pid)
+{
+  return !solib_end || !solib_end->name[0]? NULL : solib_end->name;
+}
+
+/* Clear list of loaded DLLs. */
+void
+child_clear_solibs (void)
+{
+  struct so_stuff *so, *so1 = solib_start.next;
+
+  while ((so = so1) != NULL)
+    {
+      so1 = so->next;
+      free (so);
+    }
+
+  solib_start.next = NULL;
+  solib_end = &solib_start;
+  max_dll_name_len = sizeof ("DLL Name") - 1;
+}
+
+/* Add DLL symbol information. */
+void
+child_solib_add (char *filename, int from_tty, struct target_ops *t)
+{
+  struct section_addr_info section_addrs;
+
   /* 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. */
 
+  if (!solib_end || !solib_end->name[0])
+    return;
+
+  memset (&section_addrs, 0, sizeof (section_addrs));
   section_addrs.other[0].name = ".text";
-  section_addrs.other[0].addr = (int) event->lpBaseOfDll + 0x1000;
-  safe_symbol_file_add (dll_name, 0, &section_addrs, 0, OBJF_SHARED);
-  printf_unfiltered ("%lx:%s\n", (DWORD) event->lpBaseOfDll, dll_name);
+  section_addrs.other[0].addr = solib_end->load_addr;
+  safe_symbol_file_add (solib_end->name, 0, &section_addrs, 0, OBJF_SHARED);
 
-  return 1;
+  return;
+}
+
+/* Load DLL symbol info. */
+void
+dll_symbol_command (char *args, int from_tty)
+{
+  struct section_addr_info section_addrs;
+
+  dont_repeat ();
+  
+  if (args == NULL)
+    error ("dll-symbols requires a file name");
+
+  safe_symbol_file_add (args, 0, NULL, 0, OBJF_SHARED);
+} 
+
+/* List currently loaded DLLs. */
+void
+info_dll_command (char *ignore, int from_tty)
+{
+  struct so_stuff *so = &solib_start;
+
+  if (!so->next)
+    return;
+
+  printf ("%*s  Load Address\n", -max_dll_name_len, "DLL Name");
+  while ((so = so->next) != NULL)
+    printf_unfiltered ("%*s  %08lx\n", -max_dll_name_len, so->name, so->load_addr);
+
+  return;
 }
 
 /* Handle DEBUG_STRING output from child process.
@@ -595,14 +691,11 @@ handle_output_debug_string (struct target_waitstatus *ourstatus)
 }
 
 static int
-handle_exception (struct target_waitstatus *ourstatus, int ignore_trap)
+handle_exception (struct target_waitstatus *ourstatus)
 {
   thread_info *th;
   DWORD code = current_event.u.Exception.ExceptionRecord.ExceptionCode;
 
-  if (ignore_trap && code == EXCEPTION_BREAKPOINT)
-    return 0;
-
   ourstatus->kind = TARGET_WAITKIND_STOPPED;
 
   /* Record the context of the current thread */
@@ -696,16 +789,15 @@ child_continue (DWORD continue_status, int id)
    handling by WFI (or whatever).
  */
 static int
-get_child_debug_event (int pid ATTRIBUTE_UNUSED, struct target_waitstatus *ourstatus,
-                      DWORD target_event_code, int *retval)
+get_child_debug_event (int pid ATTRIBUTE_UNUSED, struct target_waitstatus *ourstatus)
 {
   int breakout = 0;
   BOOL debug_event;
   DWORD continue_status, event_code;
   thread_info *th = NULL;
   static thread_info dummy_thread_info;
+  int retval = 0;
 
-  *retval = 0;
   if (!(debug_event = WaitForDebugEvent (&current_event, 1000)))
     goto out;
 
@@ -713,7 +805,7 @@ get_child_debug_event (int pid ATTRIBUTE_UNUSED, struct target_waitstatus *ourst
   continue_status = DBG_CONTINUE;
 
   event_code = current_event.dwDebugEventCode;
-  breakout = event_code == target_event_code;
+  ourstatus->kind = TARGET_WAITKIND_SPURIOUS;
 
   switch (event_code)
     {
@@ -728,6 +820,7 @@ get_child_debug_event (int pid ATTRIBUTE_UNUSED, struct target_waitstatus *ourst
       if (info_verbose)
        printf_unfiltered ("[New %s]\n",
                           target_pid_to_str (current_event.dwThreadId));
+      retval = current_event.dwThreadId;
       break;
 
     case EXIT_THREAD_DEBUG_EVENT:
@@ -748,8 +841,11 @@ get_child_debug_event (int pid ATTRIBUTE_UNUSED, struct target_waitstatus *ourst
 
       main_thread_id = inferior_pid = current_event.dwThreadId;
       /* Add the main thread */
+      th = child_add_thread (current_event.dwProcessId,
+                            current_event.u.CreateProcessInfo.hProcess);
       th = child_add_thread (inferior_pid,
                             current_event.u.CreateProcessInfo.hThread);
+      retval = ourstatus->value.related_pid = current_event.dwProcessId;
       break;
 
     case EXIT_PROCESS_DEBUG_EVENT:
@@ -760,8 +856,7 @@ get_child_debug_event (int pid ATTRIBUTE_UNUSED, struct target_waitstatus *ourst
       ourstatus->kind = TARGET_WAITKIND_EXITED;
       ourstatus->value.integer = current_event.u.ExitProcess.dwExitCode;
       CloseHandle (current_process_handle);
-      *retval = current_event.dwProcessId;
-      breakout = 1;
+      retval = current_event.dwProcessId;
       break;
 
     case LOAD_DLL_DEBUG_EVENT:
@@ -771,6 +866,9 @@ get_child_debug_event (int pid ATTRIBUTE_UNUSED, struct target_waitstatus *ourst
                     "LOAD_DLL_DEBUG_EVENT"));
       catch_errors (handle_load_dll, NULL, (char *) "", RETURN_MASK_ALL);
       registers_changed ();    /* mark all regs invalid */
+      ourstatus->kind = TARGET_WAITKIND_LOADED;
+      ourstatus->value.integer = 0;
+      retval = current_event.dwProcessId;
       break;
 
     case UNLOAD_DLL_DEBUG_EVENT:
@@ -785,10 +883,8 @@ get_child_debug_event (int pid ATTRIBUTE_UNUSED, struct target_waitstatus *ourst
                     (unsigned) current_event.dwProcessId,
                     (unsigned) current_event.dwThreadId,
                     "EXCEPTION_DEBUG_EVENT"));
-      if (handle_exception (ourstatus, target_event_code == FIRST_EXCEPTION))
-       *retval = current_event.dwThreadId;
-      else
-       breakout = -1;
+      handle_exception (ourstatus);
+      retval = current_event.dwThreadId;
       break;
 
     case OUTPUT_DEBUG_STRING_EVENT:    /* message from the kernel */
@@ -796,7 +892,8 @@ get_child_debug_event (int pid ATTRIBUTE_UNUSED, struct target_waitstatus *ourst
                     (unsigned) current_event.dwProcessId,
                     (unsigned) current_event.dwThreadId,
                     "OUTPUT_DEBUG_STRING_EVENT"));
-      handle_output_debug_string ( ourstatus);
+      if (handle_output_debug_string ( ourstatus))
+       retval = current_event.dwProcessId;
       break;
     default:
       printf_unfiltered ("gdb: kernel event for pid=%ld tid=%ld\n",
@@ -807,21 +904,19 @@ get_child_debug_event (int pid ATTRIBUTE_UNUSED, struct target_waitstatus *ourst
       break;
     }
 
-  if (breakout > 0)
-    current_thread = th ?: thread_rec (current_event.dwThreadId, TRUE);
-  else if (!breakout)
+  if (!retval)
     CHECK (child_continue (continue_status, -1));
+  else
+    current_thread = th ?: thread_rec (current_event.dwThreadId, TRUE);
 
 out:
-  return breakout;
+  return retval;
 }
 
 /* Wait for interesting events to occur in the target process. */
 static int
 child_wait (int pid, struct target_waitstatus *ourstatus)
 {
-  int retval;
-
   /* We loop when we get a non-standard exception rather than return
      with a SPURIOUS because resume can try and step or modify things,
      which needs a current_thread->h.  But some of these exceptions mark
@@ -829,18 +924,21 @@ child_wait (int pid, struct target_waitstatus *ourstatus)
      isn't necessarily what you think it is. */
 
   while (1)
-    if (get_child_debug_event (pid, ourstatus, EXCEPTION_DEBUG_EVENT, &retval))
-      return retval;
-    else
-      {
-       int detach = 0;
+    {
+      int retval = get_child_debug_event (pid, ourstatus);
+      if (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.  */
@@ -865,6 +963,9 @@ child_attach (args, from_tty)
   exception_count = 0;
   event_count = 0;
 
+  child_init_thread_list ();
+  child_clear_solibs ();
+
   if (from_tty)
     {
       char *exec_file = (char *) get_exec_file (0);
@@ -936,11 +1037,10 @@ child_create_inferior (exec_file, allargs, env)
   BOOL ret;
   DWORD flags;
   char *args;
+  extern int stop_after_trap;
 
   if (!exec_file)
-    {
-      error ("No executable specified, use `target exec'.\n");
-    }
+    error ("No executable specified, use `target exec'.\n");
 
   memset (&si, 0, sizeof (si));
   si.cb = sizeof (si);
@@ -1057,16 +1157,23 @@ child_create_inferior (exec_file, allargs, env)
   inferior_pid = current_event.dwThreadId = pi.dwThreadId;
   push_target (&child_ops);
   child_init_thread_list ();
-  init_wait_for_inferior ();
+  child_clear_solibs ();
   clear_proceed_status ();
+  init_wait_for_inferior ();
   target_terminal_init ();
   target_terminal_inferior ();
   last_sig = 0;
 
-  /* Run until process and threads are loaded */
-  while (!get_child_debug_event (inferior_pid, &dummy,
-                                FIRST_EXCEPTION, &ret))
-    continue;
+  while (1)
+    {
+      stop_after_trap = 1;
+      wait_for_inferior ();
+      if (stop_signal != TARGET_SIGNAL_TRAP)
+       resume (0, stop_signal);
+      else
+       break;
+    }
+  stop_after_trap = 0;
 
   /* child_continue (DBG_CONTINUE, -1);*/
   proceed ((CORE_ADDR) - 1, TARGET_SIGNAL_0, 0);
@@ -1150,19 +1257,20 @@ child_resume (int pid, int step, enum target_signal sig)
 
   /* Get context for currently selected thread */
   th = thread_rec (current_event.dwThreadId, FALSE);
-  if (step)
+  if (th)
     {
-#ifdef i386
-      /* Single step by setting t bit */
-      child_fetch_inferior_registers (PS_REGNUM);
-      th->context.EFlags |= FLAG_TRACE_BIT;
-#endif
-    }
+      if (step)
+       {
+         /* Single step by setting t bit */
+         child_fetch_inferior_registers (PS_REGNUM);
+         th->context.EFlags |= FLAG_TRACE_BIT;
+       }
 
-  if (th->context.ContextFlags)
-    {
-      CHECK (SetThreadContext (th->h, &th->context));
-      th->context.ContextFlags = 0;
+      if (th->context.ContextFlags)
+       {
+         CHECK (SetThreadContext (th->h, &th->context));
+         th->context.ContextFlags = 0;
+       }
     }
 
   /* Allow continuing with the same signal that interrupted us.
@@ -1242,48 +1350,50 @@ _initialize_inftarg ()
 {
   init_child_ops ();
 
-  add_show_from_set
-    (add_set_cmd ("new-console", class_support, var_boolean,
+  add_com ("dll-symbols", class_files, dll_symbol_command,
+           "Load dll library symbols from FILE.");
+
+  add_com_alias ("sharedlibrary", "dll-symbols", class_alias, 1);
+
+  add_show_from_set (add_set_cmd ("new-console", class_support, var_boolean,
                  (char *) &new_console,
                  "Set creation of new console when creating child process.",
                  &setlist),
      &showlist);
 
-  add_show_from_set
-    (add_set_cmd ("new-group", class_support, var_boolean,
+  add_show_from_set (add_set_cmd ("new-group", class_support, var_boolean,
                  (char *) &new_group,
                  "Set creation of new group when creating child process.",
                  &setlist),
      &showlist);
 
-  add_show_from_set
-    (add_set_cmd ("debugexec", class_support, var_boolean,
+  add_show_from_set (add_set_cmd ("debugexec", class_support, var_boolean,
                  (char *) &debug_exec,
                  "Set whether to display execution in child process.",
                  &setlist),
      &showlist);
 
-  add_show_from_set
-    (add_set_cmd ("debugevents", class_support, var_boolean,
+  add_show_from_set (add_set_cmd ("debugevents", class_support, var_boolean,
                  (char *) &debug_events,
                  "Set whether to display kernel events in child process.",
                  &setlist),
      &showlist);
 
-  add_show_from_set
-    (add_set_cmd ("debugmemory", class_support, var_boolean,
+  add_show_from_set (add_set_cmd ("debugmemory", class_support, var_boolean,
                  (char *) &debug_memory,
                  "Set whether to display memory accesses in child process.",
                  &setlist),
      &showlist);
 
-  add_show_from_set
-    (add_set_cmd ("debugexceptions", class_support, var_boolean,
+  add_show_from_set (add_set_cmd ("debugexceptions", class_support, var_boolean,
                  (char *) &debug_exceptions,
-              "Set whether to display kernel exceptions in child process.",
+                 "Set whether to display kernel exceptions in child process.",
                  &setlist),
      &showlist);
 
+  add_info ("dll", info_dll_command, "Status of loaded DLLs.");
+  add_info_alias ("sharedlibrary", "dll", 1);
+
   add_target (&child_ops);
 }