OSDN Git Service

include/elf/
[pf3gnuchains/sourceware.git] / gdb / utils.c
index 2b34d3e..d14009f 100644 (file)
@@ -25,6 +25,7 @@
 #include "gdb_string.h"
 #include "event-top.h"
 #include "exceptions.h"
+#include "gdbthread.h"
 
 #ifdef TUI
 #include "tui/tui.h"           /* For tui_get_command_dimension.   */
@@ -105,13 +106,6 @@ static int debug_timestamp = 0;
 static struct cleanup *cleanup_chain;  /* cleaned up after a failed command */
 static struct cleanup *final_cleanup_chain;    /* cleaned up when gdb exits */
 
-/* Pointer to what is left to do for an execution command after the
-   target stops. Used only in asynchronous mode, by targets that
-   support async execution.  The finish and until commands use it. So
-   does the target extended-remote command. */
-struct continuation *cmd_continuation;
-struct continuation *intermediate_continuation;
-
 /* Nonzero if we have job control. */
 
 int job_control;
@@ -250,7 +244,6 @@ do_close_cleanup (void *arg)
 {
   int *fd = arg;
   close (*fd);
-  xfree (fd);
 }
 
 struct cleanup *
@@ -258,7 +251,24 @@ make_cleanup_close (int fd)
 {
   int *saved_fd = xmalloc (sizeof (fd));
   *saved_fd = fd;
-  return make_cleanup (do_close_cleanup, saved_fd);
+  return make_cleanup_dtor (do_close_cleanup, saved_fd, xfree);
+}
+
+/* Helper function which does the work for make_cleanup_fclose.  */
+
+static void
+do_fclose_cleanup (void *arg)
+{
+  FILE *file = arg;
+  fclose (arg);
+}
+
+/* Return a new cleanup that closes FILE.  */
+
+struct cleanup *
+make_cleanup_fclose (FILE *file)
+{
+  return make_cleanup (do_fclose_cleanup, file);
 }
 
 static void
@@ -470,70 +480,205 @@ null_cleanup (void *arg)
 {
 }
 
-/* Add a continuation to the continuation list, the global list
-   cmd_continuation. The new continuation will be added at the front.*/
+/* Continuations are implemented as cleanups internally.  Inherit from
+   cleanups.  */
+struct continuation
+{
+  struct cleanup base;
+};
+
+/* Add a continuation to the continuation list of THREAD.  The new
+   continuation will be added at the front.  */
 void
-add_continuation (void (*continuation_hook) (void *), void *args,
+add_continuation (struct thread_info *thread,
+                 void (*continuation_hook) (void *), void *args,
                  void (*continuation_free_args) (void *))
 {
-  struct cleanup **as_cleanup_p = (struct cleanup **) &cmd_continuation;
+  struct cleanup *as_cleanup = &thread->continuations->base;
   make_cleanup_ftype *continuation_hook_fn = continuation_hook;
 
-  make_my_cleanup2 (as_cleanup_p,
+  make_my_cleanup2 (&as_cleanup,
                    continuation_hook_fn,
                    args,
                    continuation_free_args);
+
+  thread->continuations = (struct continuation *) as_cleanup;
 }
 
-/* Walk down the cmd_continuation list, and execute all the
-   continuations. There is a problem though. In some cases new
-   continuations may be added while we are in the middle of this
-   loop. If this happens they will be added in the front, and done
-   before we have a chance of exhausting those that were already
-   there. We need to then save the beginning of the list in a pointer
-   and do the continuations from there on, instead of using the
-   global beginning of list as our iteration pointer.  */
+/* Add a continuation to the continuation list of INFERIOR.  The new
+   continuation will be added at the front.  */
+
 void
-do_all_continuations (void)
+add_inferior_continuation (void (*continuation_hook) (void *), void *args,
+                          void (*continuation_free_args) (void *))
 {
-  struct cleanup *continuation_ptr;
+  struct inferior *inf = current_inferior ();
+  struct cleanup *as_cleanup = &inf->continuations->base;
+  make_cleanup_ftype *continuation_hook_fn = continuation_hook;
+
+  make_my_cleanup2 (&as_cleanup,
+                   continuation_hook_fn,
+                   args,
+                   continuation_free_args);
+
+  inf->continuations = (struct continuation *) as_cleanup;
+}
+
+/* Do all continuations of the current inferior.  */
+
+void
+do_all_inferior_continuations (void)
+{
+  struct cleanup *old_chain;
+  struct cleanup *as_cleanup;
+  struct inferior *inf = current_inferior ();
+
+  if (inf->continuations == NULL)
+    return;
 
   /* Copy the list header into another pointer, and set the global
      list header to null, so that the global list can change as a side
      effect of invoking the continuations and the processing of the
      preexisting continuations will not be affected.  */
 
-  continuation_ptr = (struct cleanup *) cmd_continuation;
-  cmd_continuation = NULL;
+  as_cleanup = &inf->continuations->base;
+  inf->continuations = NULL;
 
   /* Work now on the list we have set aside.  */
-  do_my_cleanups (&continuation_ptr, NULL);
+  do_my_cleanups (&as_cleanup, NULL);
 }
 
-/* Walk down the cmd_continuation list, and get rid of all the
-   continuations. */
+/* Get rid of all the inferior-wide continuations of INF.  */
+
+void
+discard_all_inferior_continuations (struct inferior *inf)
+{
+  struct cleanup *continuation_ptr = &inf->continuations->base;
+  discard_my_cleanups (&continuation_ptr, NULL);
+  inf->continuations = NULL;
+}
+
+static void
+restore_thread_cleanup (void *arg)
+{
+  ptid_t *ptid_p = arg;
+  switch_to_thread (*ptid_p);
+}
+
+/* Walk down the continuation list of PTID, and execute all the
+   continuations.  There is a problem though.  In some cases new
+   continuations may be added while we are in the middle of this loop.
+   If this happens they will be added in the front, and done before we
+   have a chance of exhausting those that were already there.  We need
+   to then save the beginning of the list in a pointer and do the
+   continuations from there on, instead of using the global beginning
+   of list as our iteration pointer.  */
+static void
+do_all_continuations_ptid (ptid_t ptid,
+                          struct continuation **continuations_p)
+{
+  struct cleanup *old_chain;
+  ptid_t current_thread;
+  struct cleanup *as_cleanup;
+
+  if (*continuations_p == NULL)
+    return;
+
+  current_thread = inferior_ptid;
+
+  /* Restore selected thread on exit.  Don't try to restore the frame
+     as well, because:
+
+    - When running continuations, the selected frame is always #0.
+
+    - The continuations may trigger symbol file loads, which may
+      change the frame layout (frame ids change), which would trigger
+      a warning if we used make_cleanup_restore_current_thread.  */
+
+  old_chain = make_cleanup (restore_thread_cleanup, &current_thread);
+
+  /* Let the continuation see this thread as selected.  */
+  switch_to_thread (ptid);
+
+  /* Copy the list header into another pointer, and set the global
+     list header to null, so that the global list can change as a side
+     effect of invoking the continuations and the processing of the
+     preexisting continuations will not be affected.  */
+
+  as_cleanup = &(*continuations_p)->base;
+  *continuations_p = NULL;
+
+  /* Work now on the list we have set aside.  */
+  do_my_cleanups (&as_cleanup, NULL);
+
+  do_cleanups (old_chain);
+}
+
+/* Callback for iterate over threads.  */
+static int
+do_all_continuations_thread_callback (struct thread_info *thread, void *data)
+{
+  do_all_continuations_ptid (thread->ptid, &thread->continuations);
+  return 0;
+}
+
+/* Do all continuations of thread THREAD.  */
+void
+do_all_continuations_thread (struct thread_info *thread)
+{
+  do_all_continuations_thread_callback (thread, NULL);
+}
+
+/* Do all continuations of all threads.  */
+void
+do_all_continuations (void)
+{
+  iterate_over_threads (do_all_continuations_thread_callback, NULL);
+}
+
+/* Callback for iterate over threads.  */
+static int
+discard_all_continuations_thread_callback (struct thread_info *thread,
+                                          void *data)
+{
+  struct cleanup *continuation_ptr = &thread->continuations->base;
+  discard_my_cleanups (&continuation_ptr, NULL);
+  thread->continuations = NULL;
+  return 0;
+}
+
+/* Get rid of all the continuations of THREAD.  */
+void
+discard_all_continuations_thread (struct thread_info *thread)
+{
+  discard_all_continuations_thread_callback (thread, NULL);
+}
+
+/* Get rid of all the continuations of all threads.  */
 void
 discard_all_continuations (void)
 {
-  struct cleanup **continuation_ptr = (struct cleanup **) &cmd_continuation;
-  discard_my_cleanups (continuation_ptr, NULL);
+  iterate_over_threads (discard_all_continuations_thread_callback, NULL);
 }
 
-/* Add a continuation to the continuation list, the global list
-   intermediate_continuation.  The new continuation will be added at
-   the front.  */
+
+/* Add a continuation to the intermediate continuation list of THREAD.
+   The new continuation will be added at the front.  */
 void
-add_intermediate_continuation (void (*continuation_hook)
+add_intermediate_continuation (struct thread_info *thread,
+                              void (*continuation_hook)
                               (void *), void *args,
                               void (*continuation_free_args) (void *))
 {
-  struct cleanup **as_cleanup_p = (struct cleanup **) &intermediate_continuation;
+  struct cleanup *as_cleanup = &thread->intermediate_continuations->base;
   make_cleanup_ftype *continuation_hook_fn = continuation_hook;
 
-  make_my_cleanup2 (as_cleanup_p,
+  make_my_cleanup2 (&as_cleanup,
                    continuation_hook_fn,
                    args,
                    continuation_free_args);
+
+  thread->intermediate_continuations = (struct continuation *) as_cleanup;
 }
 
 /* Walk down the cmd_continuation list, and execute all the
@@ -544,31 +689,52 @@ add_intermediate_continuation (void (*continuation_hook)
    there. We need to then save the beginning of the list in a pointer
    and do the continuations from there on, instead of using the
    global beginning of list as our iteration pointer.*/
+static int
+do_all_intermediate_continuations_thread_callback (struct thread_info *thread,
+                                                  void *data)
+{
+  do_all_continuations_ptid (thread->ptid,
+                            &thread->intermediate_continuations);
+  return 0;
+}
+
+/* Do all intermediate continuations of thread THREAD.  */
 void
-do_all_intermediate_continuations (void)
+do_all_intermediate_continuations_thread (struct thread_info *thread)
 {
-  struct cleanup *continuation_ptr;
+  do_all_intermediate_continuations_thread_callback (thread, NULL);
+}
 
-  /* Copy the list header into another pointer, and set the global
-     list header to null, so that the global list can change as a side
-     effect of invoking the continuations and the processing of the
-     preexisting continuations will not be affected.  */
+/* Do all intermediate continuations of all threads.  */
+void
+do_all_intermediate_continuations (void)
+{
+  iterate_over_threads (do_all_intermediate_continuations_thread_callback, NULL);
+}
 
-  continuation_ptr = (struct cleanup *) intermediate_continuation;
-  intermediate_continuation = NULL;
+/* Callback for iterate over threads.  */
+static int
+discard_all_intermediate_continuations_thread_callback (struct thread_info *thread,
+                                                       void *data)
+{
+  struct cleanup *continuation_ptr = &thread->intermediate_continuations->base;
+  discard_my_cleanups (&continuation_ptr, NULL);
+  thread->intermediate_continuations = NULL;
+  return 0;
+}
 
-  /* Work now on the list we have set aside.  */
-  do_my_cleanups (&continuation_ptr, NULL);
+/* Get rid of all the intermediate continuations of THREAD.  */
+void
+discard_all_intermediate_continuations_thread (struct thread_info *thread)
+{
+  discard_all_intermediate_continuations_thread_callback (thread, NULL);
 }
 
-/* Walk down the cmd_continuation list, and get rid of all the
-   continuations. */
+/* Get rid of all the intermediate continuations of all threads.  */
 void
 discard_all_intermediate_continuations (void)
 {
-  struct cleanup **continuation_ptr
-    = (struct cleanup **) &intermediate_continuation;
-  discard_my_cleanups (continuation_ptr, NULL);
+  iterate_over_threads (discard_all_intermediate_continuations_thread_callback, NULL);
 }
 \f
 
@@ -2120,13 +2286,22 @@ vfprintf_unfiltered (struct ui_file *stream, const char *format, va_list args)
     {
       struct timeval tm;
       char *timestamp;
+      int len, need_nl;
 
       gettimeofday (&tm, NULL);
-      timestamp = xstrprintf ("%ld:%ld ", (long) tm.tv_sec, (long) tm.tv_usec);
+
+      len = strlen (linebuffer);
+      need_nl = (len > 0 && linebuffer[len - 1] != '\n');
+
+      timestamp = xstrprintf ("%ld:%ld %s%s",
+                             (long) tm.tv_sec, (long) tm.tv_usec,
+                             linebuffer,
+                             need_nl ? "\n": "");
       make_cleanup (xfree, timestamp);
       fputs_unfiltered (timestamp, stream);
     }
-  fputs_unfiltered (linebuffer, stream);
+  else
+    fputs_unfiltered (linebuffer, stream);
   do_cleanups (old_cleanups);
 }
 
@@ -2663,18 +2838,18 @@ octal2str (ULONGEST addr, int width)
 }
 
 char *
-paddr_u (CORE_ADDR addr)
+pulongest (ULONGEST u)
 {
-  return decimal2str ("", addr, 0);
+  return decimal2str ("", u, 0);
 }
 
 char *
-paddr_d (LONGEST addr)
+plongest (LONGEST l)
 {
-  if (addr < 0)
-    return decimal2str ("-", -addr, 0);
+  if (l < 0)
+    return decimal2str ("-", -l, 0);
   else
-    return decimal2str ("", addr, 0);
+    return decimal2str ("", l, 0);
 }
 
 /* Eliminate warning from compiler on 32-bit systems.  */
@@ -3252,3 +3427,17 @@ ldirname (const char *filename)
   dirname[base - filename] = '\0';
   return dirname;
 }
+
+/* Call libiberty's buildargv, and return the result.
+   If buildargv fails due to out-of-memory, call nomem.
+   Therefore, the returned value is guaranteed to be non-NULL,
+   unless the parameter itself is NULL.  */
+
+char **
+gdb_buildargv (const char *s)
+{
+  char **argv = buildargv (s);
+  if (s != NULL && argv == NULL)
+    nomem (0);
+  return argv;
+}