+restore_current_thread (ptid_t ptid)
+{
+ switch_to_thread (ptid);
+}
+
+static void
+restore_selected_frame (struct frame_id a_frame_id, int frame_level)
+{
+ struct frame_info *frame = NULL;
+ int count;
+
+ gdb_assert (frame_level >= 0);
+
+ /* Restore by level first, check if the frame id is the same as
+ expected. If that fails, try restoring by frame id. If that
+ fails, nothing to do, just warn the user. */
+
+ count = frame_level;
+ frame = find_relative_frame (get_current_frame (), &count);
+ if (count == 0
+ && frame != NULL
+ /* Either the frame ids match, of they're both invalid. The
+ latter case is not failsafe, but since it's highly unlikely
+ the search by level finds the wrong frame, it's 99.9(9)% of
+ the time (for all practical purposes) safe. */
+ && (frame_id_eq (get_frame_id (frame), a_frame_id)
+ /* Note: could be better to check every frame_id
+ member for equality here. */
+ || (!frame_id_p (get_frame_id (frame))
+ && !frame_id_p (a_frame_id))))
+ {
+ /* Cool, all is fine. */
+ select_frame (frame);
+ return;
+ }
+
+ frame = frame_find_by_id (a_frame_id);
+ if (frame != NULL)
+ {
+ /* Cool, refound it. */
+ select_frame (frame);
+ return;
+ }
+
+ /* Nothing else to do, the frame layout really changed. Select the
+ innermost stack frame. */
+ select_frame (get_current_frame ());
+
+ /* Warn the user. */
+ if (!ui_out_is_mi_like_p (uiout))
+ {
+ warning (_("\
+Couldn't restore frame #%d in current thread, at reparsed frame #0\n"),
+ frame_level);
+ /* For MI, we should probably have a notification about
+ current frame change. But this error is not very
+ likely, so don't bother for now. */
+ print_stack_frame (get_selected_frame (NULL), 1, SRC_LINE);
+ }
+}
+
+struct current_thread_cleanup
+{
+ ptid_t inferior_ptid;
+ struct frame_id selected_frame_id;
+ int selected_frame_level;
+ int was_stopped;
+};
+
+static void
+do_restore_current_thread_cleanup (void *arg)
+{
+ struct thread_info *tp;
+ struct current_thread_cleanup *old = arg;
+
+ tp = find_thread_ptid (old->inferior_ptid);
+
+ /* If the previously selected thread belonged to a process that has
+ in the mean time been deleted (due to normal exit, detach, etc.),
+ then don't revert back to it, but instead simply drop back to no
+ thread selected. */
+ if (tp
+ && find_inferior_pid (ptid_get_pid (tp->ptid)) != NULL)
+ restore_current_thread (old->inferior_ptid);
+ else
+ restore_current_thread (null_ptid);
+
+ /* The running state of the originally selected thread may have
+ changed, so we have to recheck it here. */
+ if (!ptid_equal (inferior_ptid, null_ptid)
+ && old->was_stopped
+ && is_stopped (inferior_ptid)
+ && target_has_registers
+ && target_has_stack
+ && target_has_memory)
+ restore_selected_frame (old->selected_frame_id,
+ old->selected_frame_level);
+}
+
+static void
+restore_current_thread_cleanup_dtor (void *arg)
+{
+ struct current_thread_cleanup *old = arg;
+ struct thread_info *tp;
+ tp = find_thread_ptid (old->inferior_ptid);
+ if (tp)
+ tp->refcount--;
+ xfree (old);
+}
+
+struct cleanup *
+make_cleanup_restore_current_thread (void)
+{
+ struct thread_info *tp;
+ struct frame_info *frame;
+ struct current_thread_cleanup *old;
+
+ old = xmalloc (sizeof (struct current_thread_cleanup));
+ old->inferior_ptid = inferior_ptid;
+
+ if (!ptid_equal (inferior_ptid, null_ptid))
+ {
+ old->was_stopped = is_stopped (inferior_ptid);
+ if (old->was_stopped
+ && target_has_registers
+ && target_has_stack
+ && target_has_memory)
+ frame = get_selected_frame (NULL);
+ else
+ frame = NULL;
+
+ old->selected_frame_id = get_frame_id (frame);
+ old->selected_frame_level = frame_relative_level (frame);
+
+ tp = find_thread_ptid (inferior_ptid);
+ if (tp)
+ tp->refcount++;
+ }
+
+ return make_cleanup_dtor (do_restore_current_thread_cleanup, old,
+ restore_current_thread_cleanup_dtor);
+}
+
+/* Apply a GDB command to a list of threads. List syntax is a whitespace
+ seperated list of numbers, or ranges, or the keyword `all'. Ranges consist
+ of two numbers seperated by a hyphen. Examples:
+
+ thread apply 1 2 7 4 backtrace Apply backtrace cmd to threads 1,2,7,4
+ thread apply 2-7 9 p foo(1) Apply p foo(1) cmd to threads 2->7 & 9
+ thread apply all p x/i $pc Apply x/i $pc cmd to all threads
+ */
+
+static void
+thread_apply_all_command (char *cmd, int from_tty)