119370Spst/* Multi-process/thread control for GDB, the GNU debugger.
219370Spst
398948Sobrien   Copyright 1986, 1987, 1988, 1993, 1994, 1995, 1996, 1997, 1998,
4130809Smarcel   1999, 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
598948Sobrien
619370Spst   Contributed by Lynx Real-Time Systems, Inc.  Los Gatos, CA.
719370Spst
898948Sobrien   This file is part of GDB.
919370Spst
1098948Sobrien   This program is free software; you can redistribute it and/or modify
1198948Sobrien   it under the terms of the GNU General Public License as published by
1298948Sobrien   the Free Software Foundation; either version 2 of the License, or
1398948Sobrien   (at your option) any later version.
1419370Spst
1598948Sobrien   This program is distributed in the hope that it will be useful,
1698948Sobrien   but WITHOUT ANY WARRANTY; without even the implied warranty of
1798948Sobrien   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1898948Sobrien   GNU General Public License for more details.
1919370Spst
2098948Sobrien   You should have received a copy of the GNU General Public License
2198948Sobrien   along with this program; if not, write to the Free Software
2298948Sobrien   Foundation, Inc., 59 Temple Place - Suite 330,
2398948Sobrien   Boston, MA 02111-1307, USA.  */
2419370Spst
2519370Spst#include "defs.h"
2619370Spst#include "symtab.h"
2719370Spst#include "frame.h"
2819370Spst#include "inferior.h"
2919370Spst#include "environ.h"
3019370Spst#include "value.h"
3119370Spst#include "target.h"
3246283Sdfr#include "gdbthread.h"
3319370Spst#include "command.h"
3419370Spst#include "gdbcmd.h"
3598948Sobrien#include "regcache.h"
3698948Sobrien#include "gdb.h"
37130809Smarcel#include "gdb_string.h"
3819370Spst
3919370Spst#include <ctype.h>
4019370Spst#include <sys/types.h>
4119370Spst#include <signal.h>
4298948Sobrien#include "ui-out.h"
4319370Spst
4498948Sobrien/*#include "lynxos-core.h" */
4519370Spst
4698948Sobrien/* Definition of struct thread_info exported to gdbthread.h */
4746283Sdfr
4846283Sdfr/* Prototypes for exported functions. */
4946283Sdfr
5098948Sobrienvoid _initialize_thread (void);
5146283Sdfr
5246283Sdfr/* Prototypes for local functions. */
5346283Sdfr
5419370Spststatic struct thread_info *thread_list = NULL;
5519370Spststatic int highest_thread_num;
5619370Spst
5798948Sobrienstatic struct thread_info *find_thread_id (int num);
5846283Sdfr
5998948Sobrienstatic void thread_command (char *tidstr, int from_tty);
6098948Sobrienstatic void thread_apply_all_command (char *, int);
6198948Sobrienstatic int thread_alive (struct thread_info *);
6298948Sobrienstatic void info_threads_command (char *, int);
6398948Sobrienstatic void thread_apply_command (char *, int);
6498948Sobrienstatic void restore_current_thread (ptid_t);
6598948Sobrienstatic void switch_to_thread (ptid_t ptid);
6698948Sobrienstatic void prune_threads (void);
6719370Spst
6898948Sobrienvoid
6998948Sobriendelete_step_resume_breakpoint (void *arg)
7098948Sobrien{
7198948Sobrien  struct breakpoint **breakpointp = (struct breakpoint **) arg;
7298948Sobrien  struct thread_info *tp;
7319370Spst
7498948Sobrien  if (*breakpointp != NULL)
7598948Sobrien    {
7698948Sobrien      delete_breakpoint (*breakpointp);
7798948Sobrien      for (tp = thread_list; tp; tp = tp->next)
7898948Sobrien	if (tp->step_resume_breakpoint == *breakpointp)
7998948Sobrien	  tp->step_resume_breakpoint = NULL;
8019370Spst
8198948Sobrien      *breakpointp = NULL;
8298948Sobrien    }
8346283Sdfr}
8446283Sdfr
8598948Sobrienstatic void
8698948Sobrienfree_thread (struct thread_info *tp)
8746283Sdfr{
8898948Sobrien  /* NOTE: this will take care of any left-over step_resume breakpoints,
8998948Sobrien     but not any user-specified thread-specific breakpoints. */
9098948Sobrien  if (tp->step_resume_breakpoint)
9198948Sobrien    delete_breakpoint (tp->step_resume_breakpoint);
9246283Sdfr
9398948Sobrien  /* FIXME: do I ever need to call the back-end to give it a
9498948Sobrien     chance at this private data before deleting the thread?  */
9598948Sobrien  if (tp->private)
9698948Sobrien    xfree (tp->private);
9746283Sdfr
9898948Sobrien  xfree (tp);
9946283Sdfr}
10046283Sdfr
10146283Sdfrvoid
10298948Sobrieninit_thread_list (void)
10319370Spst{
10419370Spst  struct thread_info *tp, *tpnext;
10519370Spst
10698948Sobrien  highest_thread_num = 0;
10719370Spst  if (!thread_list)
10819370Spst    return;
10919370Spst
11019370Spst  for (tp = thread_list; tp; tp = tpnext)
11119370Spst    {
11219370Spst      tpnext = tp->next;
11398948Sobrien      free_thread (tp);
11419370Spst    }
11519370Spst
11619370Spst  thread_list = NULL;
11719370Spst}
11819370Spst
11998948Sobrien/* add_thread now returns a pointer to the new thread_info,
12098948Sobrien   so that back_ends can initialize their private data.  */
12198948Sobrien
12298948Sobrienstruct thread_info *
12398948Sobrienadd_thread (ptid_t ptid)
12419370Spst{
12519370Spst  struct thread_info *tp;
12619370Spst
12798948Sobrien  tp = (struct thread_info *) xmalloc (sizeof (*tp));
12898948Sobrien  memset (tp, 0, sizeof (*tp));
12998948Sobrien  tp->ptid = ptid;
13019370Spst  tp->num = ++highest_thread_num;
13119370Spst  tp->next = thread_list;
13219370Spst  thread_list = tp;
13398948Sobrien  return tp;
13419370Spst}
13519370Spst
13646283Sdfrvoid
13798948Sobriendelete_thread (ptid_t ptid)
13846283Sdfr{
13946283Sdfr  struct thread_info *tp, *tpprev;
14046283Sdfr
14146283Sdfr  tpprev = NULL;
14246283Sdfr
14346283Sdfr  for (tp = thread_list; tp; tpprev = tp, tp = tp->next)
14498948Sobrien    if (ptid_equal (tp->ptid, ptid))
14546283Sdfr      break;
14646283Sdfr
14746283Sdfr  if (!tp)
14846283Sdfr    return;
14946283Sdfr
15046283Sdfr  if (tpprev)
15146283Sdfr    tpprev->next = tp->next;
15246283Sdfr  else
15346283Sdfr    thread_list = tp->next;
15446283Sdfr
15598948Sobrien  free_thread (tp);
15646283Sdfr}
15746283Sdfr
15819370Spststatic struct thread_info *
15998948Sobrienfind_thread_id (int num)
16019370Spst{
16119370Spst  struct thread_info *tp;
16219370Spst
16319370Spst  for (tp = thread_list; tp; tp = tp->next)
16419370Spst    if (tp->num == num)
16519370Spst      return tp;
16619370Spst
16719370Spst  return NULL;
16819370Spst}
16919370Spst
17098948Sobrien/* Find a thread_info by matching PTID.  */
17198948Sobrienstruct thread_info *
17298948Sobrienfind_thread_pid (ptid_t ptid)
17398948Sobrien{
17498948Sobrien  struct thread_info *tp;
17598948Sobrien
17698948Sobrien  for (tp = thread_list; tp; tp = tp->next)
17798948Sobrien    if (ptid_equal (tp->ptid, ptid))
17898948Sobrien      return tp;
17998948Sobrien
18098948Sobrien  return NULL;
18198948Sobrien}
18298948Sobrien
18398948Sobrien/*
18498948Sobrien * Thread iterator function.
18598948Sobrien *
18698948Sobrien * Calls a callback function once for each thread, so long as
18798948Sobrien * the callback function returns false.  If the callback function
18898948Sobrien * returns true, the iteration will end and the current thread
18998948Sobrien * will be returned.  This can be useful for implementing a
19098948Sobrien * search for a thread with arbitrary attributes, or for applying
19198948Sobrien * some operation to every thread.
19298948Sobrien *
19398948Sobrien * FIXME: some of the existing functionality, such as
19498948Sobrien * "Thread apply all", might be rewritten using this functionality.
19598948Sobrien */
19698948Sobrien
19798948Sobrienstruct thread_info *
19898948Sobrieniterate_over_threads (int (*callback) (struct thread_info *, void *),
19998948Sobrien		      void *data)
20098948Sobrien{
20198948Sobrien  struct thread_info *tp;
20298948Sobrien
20398948Sobrien  for (tp = thread_list; tp; tp = tp->next)
20498948Sobrien    if ((*callback) (tp, data))
20598948Sobrien      return tp;
20698948Sobrien
20798948Sobrien  return NULL;
20898948Sobrien}
20998948Sobrien
21019370Spstint
21198948Sobrienvalid_thread_id (int num)
21219370Spst{
21319370Spst  struct thread_info *tp;
21419370Spst
21519370Spst  for (tp = thread_list; tp; tp = tp->next)
21619370Spst    if (tp->num == num)
21719370Spst      return 1;
21819370Spst
21919370Spst  return 0;
22019370Spst}
22119370Spst
22219370Spstint
22398948Sobrienpid_to_thread_id (ptid_t ptid)
22419370Spst{
22519370Spst  struct thread_info *tp;
22619370Spst
22719370Spst  for (tp = thread_list; tp; tp = tp->next)
22898948Sobrien    if (ptid_equal (tp->ptid, ptid))
22919370Spst      return tp->num;
23019370Spst
23119370Spst  return 0;
23219370Spst}
23319370Spst
23498948Sobrienptid_t
23598948Sobrienthread_id_to_pid (int num)
23646283Sdfr{
23746283Sdfr  struct thread_info *thread = find_thread_id (num);
23846283Sdfr  if (thread)
23998948Sobrien    return thread->ptid;
24046283Sdfr  else
24198948Sobrien    return pid_to_ptid (-1);
24246283Sdfr}
24346283Sdfr
24446283Sdfrint
24598948Sobrienin_thread_list (ptid_t ptid)
24619370Spst{
24719370Spst  struct thread_info *tp;
24819370Spst
24919370Spst  for (tp = thread_list; tp; tp = tp->next)
25098948Sobrien    if (ptid_equal (tp->ptid, ptid))
25119370Spst      return 1;
25219370Spst
25319370Spst  return 0;			/* Never heard of 'im */
25419370Spst}
25519370Spst
25698948Sobrien/* Print a list of thread ids currently known, and the total number of
25798948Sobrien   threads. To be used from within catch_errors. */
258130809Smarcelstatic int
259130809Smarceldo_captured_list_thread_ids (struct ui_out *uiout, void *arg)
26098948Sobrien{
26198948Sobrien  struct thread_info *tp;
26298948Sobrien  int num = 0;
263130809Smarcel  struct cleanup *cleanup_chain;
26498948Sobrien
265130809Smarcel  prune_threads ();
266130809Smarcel  target_find_new_threads ();
26798948Sobrien
268130809Smarcel  cleanup_chain = make_cleanup_ui_out_tuple_begin_end (uiout, "thread-ids");
269130809Smarcel
27098948Sobrien  for (tp = thread_list; tp; tp = tp->next)
27198948Sobrien    {
27298948Sobrien      num++;
27398948Sobrien      ui_out_field_int (uiout, "thread-id", tp->num);
27498948Sobrien    }
27598948Sobrien
276130809Smarcel  do_cleanups (cleanup_chain);
27798948Sobrien  ui_out_field_int (uiout, "number-of-threads", num);
27898948Sobrien  return GDB_RC_OK;
27998948Sobrien}
28098948Sobrien
28198948Sobrien/* Official gdblib interface function to get a list of thread ids and
28298948Sobrien   the total number. */
28398948Sobrienenum gdb_rc
28498948Sobriengdb_list_thread_ids (struct ui_out *uiout)
28598948Sobrien{
28698948Sobrien  return catch_exceptions (uiout, do_captured_list_thread_ids, NULL,
28798948Sobrien			   NULL, RETURN_MASK_ALL);
28898948Sobrien}
28998948Sobrien
29019370Spst/* Load infrun state for the thread PID.  */
29119370Spst
29298948Sobrienvoid
293130809Smarcelload_infrun_state (ptid_t ptid,
294130809Smarcel		   CORE_ADDR *prev_pc,
29598948Sobrien		   int *trap_expected,
29698948Sobrien		   struct breakpoint **step_resume_breakpoint,
29798948Sobrien		   struct breakpoint **through_sigtramp_breakpoint,
298130809Smarcel		   CORE_ADDR *step_range_start,
29998948Sobrien		   CORE_ADDR *step_range_end,
300130809Smarcel		   struct frame_id *step_frame_id,
30198948Sobrien		   int *handling_longjmp,
302130809Smarcel		   int *another_trap,
30398948Sobrien		   int *stepping_through_solib_after_catch,
30498948Sobrien		   bpstat *stepping_through_solib_catchpoints,
30598948Sobrien		   int *stepping_through_sigtramp,
306130809Smarcel		   int *current_line,
307130809Smarcel		   struct symtab **current_symtab, CORE_ADDR *step_sp)
30819370Spst{
30919370Spst  struct thread_info *tp;
31019370Spst
31119370Spst  /* If we can't find the thread, then we're debugging a single threaded
31219370Spst     process.  No need to do anything in that case.  */
31398948Sobrien  tp = find_thread_id (pid_to_thread_id (ptid));
31419370Spst  if (tp == NULL)
31519370Spst    return;
31619370Spst
31719370Spst  *prev_pc = tp->prev_pc;
31898948Sobrien  *trap_expected = tp->trap_expected;
31919370Spst  *step_resume_breakpoint = tp->step_resume_breakpoint;
32098948Sobrien  *through_sigtramp_breakpoint = tp->through_sigtramp_breakpoint;
32119370Spst  *step_range_start = tp->step_range_start;
32219370Spst  *step_range_end = tp->step_range_end;
323130809Smarcel  *step_frame_id = tp->step_frame_id;
32419370Spst  *handling_longjmp = tp->handling_longjmp;
32519370Spst  *another_trap = tp->another_trap;
326130809Smarcel  *stepping_through_solib_after_catch =
327130809Smarcel    tp->stepping_through_solib_after_catch;
328130809Smarcel  *stepping_through_solib_catchpoints =
329130809Smarcel    tp->stepping_through_solib_catchpoints;
33046283Sdfr  *stepping_through_sigtramp = tp->stepping_through_sigtramp;
33198948Sobrien  *current_line = tp->current_line;
33298948Sobrien  *current_symtab = tp->current_symtab;
33398948Sobrien  *step_sp = tp->step_sp;
33419370Spst}
33519370Spst
33619370Spst/* Save infrun state for the thread PID.  */
33719370Spst
33898948Sobrienvoid
339130809Smarcelsave_infrun_state (ptid_t ptid,
340130809Smarcel		   CORE_ADDR prev_pc,
34198948Sobrien		   int trap_expected,
34298948Sobrien		   struct breakpoint *step_resume_breakpoint,
34398948Sobrien		   struct breakpoint *through_sigtramp_breakpoint,
344130809Smarcel		   CORE_ADDR step_range_start,
34598948Sobrien		   CORE_ADDR step_range_end,
346130809Smarcel		   const struct frame_id *step_frame_id,
34798948Sobrien		   int handling_longjmp,
348130809Smarcel		   int another_trap,
34998948Sobrien		   int stepping_through_solib_after_catch,
35098948Sobrien		   bpstat stepping_through_solib_catchpoints,
351130809Smarcel		   int stepping_through_sigtramp,
35298948Sobrien		   int current_line,
353130809Smarcel		   struct symtab *current_symtab, CORE_ADDR step_sp)
35419370Spst{
35519370Spst  struct thread_info *tp;
35619370Spst
35719370Spst  /* If we can't find the thread, then we're debugging a single-threaded
35819370Spst     process.  Nothing to do in that case.  */
35998948Sobrien  tp = find_thread_id (pid_to_thread_id (ptid));
36019370Spst  if (tp == NULL)
36119370Spst    return;
36219370Spst
36319370Spst  tp->prev_pc = prev_pc;
36498948Sobrien  tp->trap_expected = trap_expected;
36519370Spst  tp->step_resume_breakpoint = step_resume_breakpoint;
36698948Sobrien  tp->through_sigtramp_breakpoint = through_sigtramp_breakpoint;
36719370Spst  tp->step_range_start = step_range_start;
36819370Spst  tp->step_range_end = step_range_end;
369130809Smarcel  tp->step_frame_id = (*step_frame_id);
37019370Spst  tp->handling_longjmp = handling_longjmp;
37119370Spst  tp->another_trap = another_trap;
37246283Sdfr  tp->stepping_through_solib_after_catch = stepping_through_solib_after_catch;
37346283Sdfr  tp->stepping_through_solib_catchpoints = stepping_through_solib_catchpoints;
37446283Sdfr  tp->stepping_through_sigtramp = stepping_through_sigtramp;
37598948Sobrien  tp->current_line = current_line;
37698948Sobrien  tp->current_symtab = current_symtab;
37798948Sobrien  tp->step_sp = step_sp;
37819370Spst}
37919370Spst
38046283Sdfr/* Return true if TP is an active thread. */
38146283Sdfrstatic int
38298948Sobrienthread_alive (struct thread_info *tp)
38346283Sdfr{
38498948Sobrien  if (PIDGET (tp->ptid) == -1)
38546283Sdfr    return 0;
38698948Sobrien  if (!target_thread_alive (tp->ptid))
38746283Sdfr    {
38898948Sobrien      tp->ptid = pid_to_ptid (-1);	/* Mark it as dead */
38946283Sdfr      return 0;
39046283Sdfr    }
39146283Sdfr  return 1;
39246283Sdfr}
39346283Sdfr
39419370Spststatic void
39598948Sobrienprune_threads (void)
39619370Spst{
39798948Sobrien  struct thread_info *tp, *next;
39819370Spst
39946283Sdfr  for (tp = thread_list; tp; tp = next)
40046283Sdfr    {
40146283Sdfr      next = tp->next;
40246283Sdfr      if (!thread_alive (tp))
40398948Sobrien	delete_thread (tp->ptid);
40446283Sdfr    }
40519370Spst}
40619370Spst
40746283Sdfr/* Print information about currently known threads
40898948Sobrien
40946283Sdfr * Note: this has the drawback that it _really_ switches
41046283Sdfr *       threads, which frees the frame cache.  A no-side
41146283Sdfr *       effects info-threads command would be nicer.
41246283Sdfr */
41319370Spst
41419370Spststatic void
41598948Sobrieninfo_threads_command (char *arg, int from_tty)
41619370Spst{
41719370Spst  struct thread_info *tp;
41898948Sobrien  ptid_t current_ptid;
41998948Sobrien  struct frame_info *cur_frame;
420130809Smarcel  int saved_frame_level = frame_relative_level (get_selected_frame ());
42198948Sobrien  int counter;
42298948Sobrien  char *extra_info;
42319370Spst
424130809Smarcel  /* Check that there really is a frame.  This happens when a simulator
425130809Smarcel     is connected but not loaded or running, for instance.  */
426130809Smarcel  if (legacy_frame_p (current_gdbarch) && saved_frame_level < 0)
427130809Smarcel    error ("No frame.");
42819370Spst
42946283Sdfr  prune_threads ();
43098948Sobrien  target_find_new_threads ();
43198948Sobrien  current_ptid = inferior_ptid;
43219370Spst  for (tp = thread_list; tp; tp = tp->next)
43319370Spst    {
43498948Sobrien      if (ptid_equal (tp->ptid, current_ptid))
43519370Spst	printf_filtered ("* ");
43619370Spst      else
43719370Spst	printf_filtered ("  ");
43819370Spst
43946283Sdfr#ifdef HPUXHPPA
44098948Sobrien      printf_filtered ("%d %s", tp->num, target_tid_to_str (tp->ptid));
44146283Sdfr#else
44298948Sobrien      printf_filtered ("%d %s", tp->num, target_pid_to_str (tp->ptid));
44346283Sdfr#endif
44498948Sobrien
44598948Sobrien      extra_info = target_extra_thread_info (tp);
44698948Sobrien      if (extra_info)
44798948Sobrien	printf_filtered (" (%s)", extra_info);
44898948Sobrien      puts_filtered ("  ");
44998948Sobrien
45098948Sobrien      switch_to_thread (tp->ptid);
451130809Smarcel      print_stack_frame (get_selected_frame (), -1, 0);
45246283Sdfr    }
45319370Spst
45498948Sobrien  switch_to_thread (current_ptid);
45546283Sdfr
45646283Sdfr  /* Code below copied from "up_silently_base" in "stack.c".
45746283Sdfr   * It restores the frame set by the user before the "info threads"
45846283Sdfr   * command.  We have finished the info-threads display by switching
45946283Sdfr   * back to the current thread.  That switch has put us at the top
46046283Sdfr   * of the stack (leaf frame).
46146283Sdfr   */
46298948Sobrien  counter = saved_frame_level;
463130809Smarcel  cur_frame = find_relative_frame (get_selected_frame (), &counter);
46446283Sdfr  if (counter != 0)
46546283Sdfr    {
46646283Sdfr      /* Ooops, can't restore, tell user where we are. */
46746283Sdfr      warning ("Couldn't restore frame in current thread, at frame 0");
468130809Smarcel      print_stack_frame (get_selected_frame (), -1, 0);
46919370Spst    }
47046283Sdfr  else
47146283Sdfr    {
472130809Smarcel      select_frame (cur_frame);
47346283Sdfr    }
47419370Spst
47546283Sdfr  /* re-show current frame. */
47698948Sobrien  show_stack_frame (cur_frame);
47719370Spst}
47819370Spst
47919370Spst/* Switch from one thread to another. */
48019370Spst
48119370Spststatic void
48298948Sobrienswitch_to_thread (ptid_t ptid)
48319370Spst{
48498948Sobrien  if (ptid_equal (ptid, inferior_ptid))
48519370Spst    return;
48619370Spst
48798948Sobrien  inferior_ptid = ptid;
48819370Spst  flush_cached_frames ();
48919370Spst  registers_changed ();
49098948Sobrien  stop_pc = read_pc ();
491130809Smarcel  select_frame (get_current_frame ());
49219370Spst}
49319370Spst
49419370Spststatic void
49598948Sobrienrestore_current_thread (ptid_t ptid)
49619370Spst{
497130809Smarcel  if (!ptid_equal (ptid, inferior_ptid))
49846283Sdfr    {
49998948Sobrien      switch_to_thread (ptid);
50098948Sobrien      print_stack_frame (get_current_frame (), 0, -1);
50146283Sdfr    }
50219370Spst}
50319370Spst
50498948Sobrienstruct current_thread_cleanup
50598948Sobrien{
50698948Sobrien  ptid_t inferior_ptid;
50798948Sobrien};
50898948Sobrien
50998948Sobrienstatic void
51098948Sobriendo_restore_current_thread_cleanup (void *arg)
51198948Sobrien{
51298948Sobrien  struct current_thread_cleanup *old = arg;
51398948Sobrien  restore_current_thread (old->inferior_ptid);
51498948Sobrien  xfree (old);
51598948Sobrien}
51698948Sobrien
51798948Sobrienstatic struct cleanup *
51898948Sobrienmake_cleanup_restore_current_thread (ptid_t inferior_ptid)
51998948Sobrien{
52098948Sobrien  struct current_thread_cleanup *old
52198948Sobrien    = xmalloc (sizeof (struct current_thread_cleanup));
52298948Sobrien  old->inferior_ptid = inferior_ptid;
52398948Sobrien  return make_cleanup (do_restore_current_thread_cleanup, old);
52498948Sobrien}
52598948Sobrien
52619370Spst/* Apply a GDB command to a list of threads.  List syntax is a whitespace
52719370Spst   seperated list of numbers, or ranges, or the keyword `all'.  Ranges consist
52819370Spst   of two numbers seperated by a hyphen.  Examples:
52919370Spst
53098948Sobrien   thread apply 1 2 7 4 backtrace       Apply backtrace cmd to threads 1,2,7,4
53198948Sobrien   thread apply 2-7 9 p foo(1)  Apply p foo(1) cmd to threads 2->7 & 9
53298948Sobrien   thread apply all p x/i $pc   Apply x/i $pc cmd to all threads
53398948Sobrien */
53419370Spst
53519370Spststatic void
53698948Sobrienthread_apply_all_command (char *cmd, int from_tty)
53719370Spst{
53819370Spst  struct thread_info *tp;
53919370Spst  struct cleanup *old_chain;
54098948Sobrien  struct cleanup *saved_cmd_cleanup_chain;
54198948Sobrien  char *saved_cmd;
54219370Spst
54319370Spst  if (cmd == NULL || *cmd == '\000')
54419370Spst    error ("Please specify a command following the thread ID list");
54519370Spst
54698948Sobrien  old_chain = make_cleanup_restore_current_thread (inferior_ptid);
54719370Spst
54898948Sobrien  /* It is safe to update the thread list now, before
54998948Sobrien     traversing it for "thread apply all".  MVS */
55098948Sobrien  target_find_new_threads ();
55198948Sobrien
55298948Sobrien  /* Save a copy of the command in case it is clobbered by
55398948Sobrien     execute_command */
55498948Sobrien  saved_cmd = xstrdup (cmd);
55598948Sobrien  saved_cmd_cleanup_chain = make_cleanup (xfree, (void *) saved_cmd);
55619370Spst  for (tp = thread_list; tp; tp = tp->next)
55746283Sdfr    if (thread_alive (tp))
55846283Sdfr      {
55998948Sobrien	switch_to_thread (tp->ptid);
56046283Sdfr#ifdef HPUXHPPA
56146283Sdfr	printf_filtered ("\nThread %d (%s):\n",
562130809Smarcel			 tp->num, target_tid_to_str (inferior_ptid));
56346283Sdfr#else
56446283Sdfr	printf_filtered ("\nThread %d (%s):\n", tp->num,
56598948Sobrien			 target_pid_to_str (inferior_ptid));
56646283Sdfr#endif
56746283Sdfr	execute_command (cmd, from_tty);
568130809Smarcel	strcpy (cmd, saved_cmd);	/* Restore exact command used previously */
56946283Sdfr      }
57098948Sobrien
57198948Sobrien  do_cleanups (saved_cmd_cleanup_chain);
57298948Sobrien  do_cleanups (old_chain);
57319370Spst}
57419370Spst
57519370Spststatic void
57698948Sobrienthread_apply_command (char *tidlist, int from_tty)
57719370Spst{
57819370Spst  char *cmd;
57919370Spst  char *p;
58019370Spst  struct cleanup *old_chain;
58198948Sobrien  struct cleanup *saved_cmd_cleanup_chain;
58298948Sobrien  char *saved_cmd;
58319370Spst
58419370Spst  if (tidlist == NULL || *tidlist == '\000')
58519370Spst    error ("Please specify a thread ID list");
58619370Spst
58798948Sobrien  for (cmd = tidlist; *cmd != '\000' && !isalpha (*cmd); cmd++);
58819370Spst
58919370Spst  if (*cmd == '\000')
59019370Spst    error ("Please specify a command following the thread ID list");
59119370Spst
59298948Sobrien  old_chain = make_cleanup_restore_current_thread (inferior_ptid);
59319370Spst
59498948Sobrien  /* Save a copy of the command in case it is clobbered by
59598948Sobrien     execute_command */
59698948Sobrien  saved_cmd = xstrdup (cmd);
59798948Sobrien  saved_cmd_cleanup_chain = make_cleanup (xfree, (void *) saved_cmd);
59819370Spst  while (tidlist < cmd)
59919370Spst    {
60019370Spst      struct thread_info *tp;
60119370Spst      int start, end;
60219370Spst
60319370Spst      start = strtol (tidlist, &p, 10);
60419370Spst      if (p == tidlist)
60519370Spst	error ("Error parsing %s", tidlist);
60619370Spst      tidlist = p;
60719370Spst
60819370Spst      while (*tidlist == ' ' || *tidlist == '\t')
60919370Spst	tidlist++;
61019370Spst
61119370Spst      if (*tidlist == '-')	/* Got a range of IDs? */
61219370Spst	{
61398948Sobrien	  tidlist++;		/* Skip the - */
61419370Spst	  end = strtol (tidlist, &p, 10);
61519370Spst	  if (p == tidlist)
61619370Spst	    error ("Error parsing %s", tidlist);
61719370Spst	  tidlist = p;
61819370Spst
61919370Spst	  while (*tidlist == ' ' || *tidlist == '\t')
62019370Spst	    tidlist++;
62119370Spst	}
62219370Spst      else
62319370Spst	end = start;
62419370Spst
62519370Spst      for (; start <= end; start++)
62619370Spst	{
62719370Spst	  tp = find_thread_id (start);
62819370Spst
62919370Spst	  if (!tp)
63046283Sdfr	    warning ("Unknown thread %d.", start);
63146283Sdfr	  else if (!thread_alive (tp))
63246283Sdfr	    warning ("Thread %d has terminated.", start);
63346283Sdfr	  else
63419370Spst	    {
63598948Sobrien	      switch_to_thread (tp->ptid);
63646283Sdfr#ifdef HPUXHPPA
63746283Sdfr	      printf_filtered ("\nThread %d (%s):\n", tp->num,
63898948Sobrien			       target_tid_to_str (inferior_ptid));
63946283Sdfr#else
64046283Sdfr	      printf_filtered ("\nThread %d (%s):\n", tp->num,
64198948Sobrien			       target_pid_to_str (inferior_ptid));
64246283Sdfr#endif
64346283Sdfr	      execute_command (cmd, from_tty);
64498948Sobrien	      strcpy (cmd, saved_cmd);	/* Restore exact command used previously */
64519370Spst	    }
64619370Spst	}
64719370Spst    }
64898948Sobrien
64998948Sobrien  do_cleanups (saved_cmd_cleanup_chain);
65098948Sobrien  do_cleanups (old_chain);
65119370Spst}
65219370Spst
65319370Spst/* Switch to the specified thread.  Will dispatch off to thread_apply_command
65419370Spst   if prefix of arg is `apply'.  */
65519370Spst
65619370Spststatic void
65798948Sobrienthread_command (char *tidstr, int from_tty)
65819370Spst{
65919370Spst  if (!tidstr)
66046283Sdfr    {
66146283Sdfr      /* Don't generate an error, just say which thread is current. */
66246283Sdfr      if (target_has_stack)
66346283Sdfr	printf_filtered ("[Current thread is %d (%s)]\n",
66498948Sobrien			 pid_to_thread_id (inferior_ptid),
66546283Sdfr#if defined(HPUXHPPA)
66698948Sobrien			 target_tid_to_str (inferior_ptid)
66746283Sdfr#else
66898948Sobrien			 target_pid_to_str (inferior_ptid)
66946283Sdfr#endif
67098948Sobrien	  );
67146283Sdfr      else
67246283Sdfr	error ("No stack.");
67346283Sdfr      return;
67446283Sdfr    }
67519370Spst
67698948Sobrien  gdb_thread_select (uiout, tidstr);
67798948Sobrien}
67898948Sobrien
67998948Sobrienstatic int
680130809Smarceldo_captured_thread_select (struct ui_out *uiout, void *tidstr)
68198948Sobrien{
68298948Sobrien  int num;
68398948Sobrien  struct thread_info *tp;
68498948Sobrien
68598948Sobrien  num = value_as_long (parse_and_eval (tidstr));
68698948Sobrien
68719370Spst  tp = find_thread_id (num);
68819370Spst
68919370Spst  if (!tp)
69098948Sobrien    error ("Thread ID %d not known.", num);
69119370Spst
69246283Sdfr  if (!thread_alive (tp))
69346283Sdfr    error ("Thread ID %d has terminated.\n", num);
69419370Spst
69598948Sobrien  switch_to_thread (tp->ptid);
69646283Sdfr
69798948Sobrien  ui_out_text (uiout, "[Switching to thread ");
69898948Sobrien  ui_out_field_int (uiout, "new-thread-id", pid_to_thread_id (inferior_ptid));
69998948Sobrien  ui_out_text (uiout, " (");
70046283Sdfr#if defined(HPUXHPPA)
70198948Sobrien  ui_out_text (uiout, target_tid_to_str (inferior_ptid));
70246283Sdfr#else
70398948Sobrien  ui_out_text (uiout, target_pid_to_str (inferior_ptid));
70446283Sdfr#endif
70598948Sobrien  ui_out_text (uiout, ")]");
70698948Sobrien
707130809Smarcel  print_stack_frame (deprecated_selected_frame,
708130809Smarcel		     frame_relative_level (deprecated_selected_frame), 1);
70998948Sobrien  return GDB_RC_OK;
71019370Spst}
71119370Spst
71298948Sobrienenum gdb_rc
713130809Smarcelgdb_thread_select (struct ui_out *uiout, char *tidstr)
71498948Sobrien{
71598948Sobrien  return catch_exceptions (uiout, do_captured_thread_select, tidstr,
71698948Sobrien			   NULL, RETURN_MASK_ALL);
71798948Sobrien}
71898948Sobrien
71946283Sdfr/* Commands with a prefix of `thread'.  */
72046283Sdfrstruct cmd_list_element *thread_cmd_list = NULL;
72146283Sdfr
72219370Spstvoid
72398948Sobrien_initialize_thread (void)
72419370Spst{
72519370Spst  static struct cmd_list_element *thread_apply_list = NULL;
72619370Spst
72719370Spst  add_info ("threads", info_threads_command,
72819370Spst	    "IDs of currently known threads.");
72919370Spst
73019370Spst  add_prefix_cmd ("thread", class_run, thread_command,
73119370Spst		  "Use this command to switch between threads.\n\
732130809SmarcelThe new thread ID must be currently known.", &thread_cmd_list, "thread ", 1, &cmdlist);
73319370Spst
73419370Spst  add_prefix_cmd ("apply", class_run, thread_apply_command,
73519370Spst		  "Apply a command to a list of threads.",
73619370Spst		  &thread_apply_list, "apply ", 1, &thread_cmd_list);
73719370Spst
73819370Spst  add_cmd ("all", class_run, thread_apply_all_command,
739130809Smarcel	   "Apply a command to all threads.", &thread_apply_list);
74019370Spst
74146283Sdfr  if (!xdb_commands)
74246283Sdfr    add_com_alias ("t", "thread", class_run, 1);
74319370Spst}
744