1/* file ada-tasks.c: Ada tasking control for GDB
2   Copyright 1997 Free Software Foundation, Inc.
3   Contributed by Ada Core Technologies, Inc
4.
5   This file is part of GDB.
6
7   [$Id: ada-tasks.c,v 1.7 2003/06/17 20:58:32 ciceron Exp $]
8   Authors: Roch-Alexandre Nomine Beguin, Arnaud Charlet <charlet@gnat.com>
9
10   This program is free software; you can redistribute it and/or modify
11   it under the terms of the GNU General Public License as published by
12   the Free Software Foundation; either version 2 of the License, or
13   (at your option) any later version.
14
15*/
16
17#include <ctype.h>
18#include "defs.h"
19#include "command.h"
20#include "value.h"
21#include "language.h"
22#include "inferior.h"
23#include "symtab.h"
24#include "target.h"
25#include "regcache.h"
26#include "gdbcore.h"
27
28#if (defined(__alpha__) && defined(__osf__) && !defined(__alpha_vxworks))
29#include <sys/procfs.h>
30#endif
31
32#if (defined(__alpha__) && defined(__osf__) && !defined(VXWORKS_TARGET))
33#include "gregset.h"
34#endif
35
36#include "ada-lang.h"
37
38/* FIXME: move all this conditional compilation in description
39   files or in configure.in */
40
41#if defined (VXWORKS_TARGET)
42#define THREAD_TO_PID(tid,lwpid) (tid)
43
44#elif defined (linux)
45#define THREAD_TO_PID(tid,lwpid) (0)
46
47#elif (defined (sun) && defined (__SVR4))
48#define THREAD_TO_PID thread_to_pid
49
50#elif defined (sgi) || defined (__WIN32__) || defined (hpux)
51#define THREAD_TO_PID(tid,lwpid) ((int)lwpid)
52
53#else
54#define THREAD_TO_PID(tid,lwpid) (0)
55#endif
56
57#if defined(__alpha__) && defined(__osf__) && !defined(VXWORKS_TARGET)
58#define THREAD_FETCH_REGISTERS dec_thread_fetch_registers
59#define GET_CURRENT_THREAD dec_thread_get_current_thread
60extern int dec_thread_get_registers (gdb_gregset_t *, gdb_fpregset_t *);
61#endif
62
63#if defined (_AIX)
64#define THREAD_FETCH_REGISTERS aix_thread_fetch_registers
65#define GET_CURRENT_THREAD aix_thread_get_current_thread
66#endif
67
68#if defined(VXWORKS_TARGET)
69#define GET_CURRENT_THREAD() ((void*)inferior_pid)
70#define THREAD_FETCH_REGISTERS() (-1)
71
72#elif defined (sun) && defined (__SVR4)
73#define GET_CURRENT_THREAD solaris_thread_get_current_thread
74#define THREAD_FETCH_REGISTERS() (-1)
75extern void *GET_CURRENT_THREAD ();
76
77#elif defined (_AIX) || (defined(__alpha__) && defined(__osf__))
78extern void *GET_CURRENT_THREAD ();
79
80#elif defined (__WIN32__) || defined (hpux)
81#define GET_CURRENT_THREAD() (inferior_pid)
82#define THREAD_FETCH_REGISTERS() (-1)
83
84#else
85#define GET_CURRENT_THREAD() (NULL)
86#define THREAD_FETCH_REGISTERS() (-1)
87#endif
88
89#define KNOWN_TASKS_NAME "system__tasking__debug__known_tasks"
90
91#define READ_MEMORY(addr, var) read_memory (addr, (char*) &var, sizeof (var))
92/* external declarations */
93
94/* Global visible variables */
95
96struct task_entry *task_list = NULL;
97int ada__tasks_check_symbol_table = 1;
98void *pthread_kern_addr = NULL;
99
100#if (defined(__alpha__) && defined(__osf__) && !defined(VXWORKS_TARGET))
101gdb_gregset_t gregset_saved;
102gdb_fpregset_t fpregset_saved;
103#endif
104
105/* The maximum number of tasks known to the Ada runtime */
106const int MAX_NUMBER_OF_KNOWN_TASKS = 1000;
107
108/* the current task */
109int current_task = -1, current_task_id = -1, current_task_index;
110void *current_thread, *current_lwp;
111
112char *ada_task_states[] = {
113  "Unactivated",
114  "Runnable",
115  "Terminated",
116  "Child Activation Wait",
117  "Accept Statement",
118  "Waiting on entry call",
119  "Async Select Wait",
120  "Delay Sleep",
121  "Child Termination Wait",
122  "Wait Child in Term Alt",
123  "",
124  "",
125  "",
126  "",
127  "Asynchronous Hold"
128};
129
130/* Global internal types */
131
132static char *ada_long_task_states[] = {
133  "Unactivated",
134  "Runnable",
135  "Terminated",
136  "Waiting for child activation",
137  "Blocked in accept statement",
138  "Waiting on entry call",
139  "Asynchronous Selective Wait",
140  "Delay Sleep",
141  "Waiting for children termination",
142  "Waiting for children in terminate alternative",
143  "",
144  "",
145  "",
146  "",
147  "Asynchronous Hold"
148};
149
150/* Global internal variables */
151
152static int highest_task_num = 0;
153int thread_support = 0;		/* 1 if the thread library in use is supported */
154static int gdbtk_task_initialization = 0;
155
156static int
157add_task_entry (void *p_task_id, int index)
158{
159  struct task_entry *new_task_entry = NULL;
160  struct task_entry *pt;
161
162  highest_task_num++;
163  new_task_entry = xmalloc (sizeof (struct task_entry));
164  new_task_entry->task_num = highest_task_num;
165  new_task_entry->task_id = p_task_id;
166  new_task_entry->known_tasks_index = index;
167  new_task_entry->next_task = NULL;
168  pt = task_list;
169  if (pt)
170    {
171      while (pt->next_task)
172	pt = pt->next_task;
173      pt->next_task = new_task_entry;
174      pt->stack_per = 0;
175    }
176  else
177    task_list = new_task_entry;
178  return new_task_entry->task_num;
179}
180
181int
182get_entry_number (void *p_task_id)
183{
184  struct task_entry *pt;
185
186  pt = task_list;
187  while (pt != NULL)
188    {
189      if (pt->task_id == p_task_id)
190	return pt->task_num;
191      pt = pt->next_task;
192    }
193  return 0;
194}
195
196static struct task_entry *
197get_thread_entry_vptr (void *thread)
198{
199  struct task_entry *pt;
200
201  pt = task_list;
202  while (pt != NULL)
203    {
204      if (pt->thread == thread)
205	return pt;
206      pt = pt->next_task;
207    }
208  return 0;
209}
210
211static struct task_entry *
212get_entry_vptr (int p_task_num)
213{
214  struct task_entry *pt;
215
216  pt = task_list;
217  while (pt)
218    {
219      if (pt->task_num == p_task_num)
220	return pt;
221      pt = pt->next_task;
222    }
223  return NULL;
224}
225
226void
227init_task_list (void)
228{
229  struct task_entry *pt, *old_pt;
230
231  pt = task_list;
232  while (pt)
233    {
234      old_pt = pt;
235      pt = pt->next_task;
236      xfree (old_pt);
237    };
238  task_list = NULL;
239  highest_task_num = 0;
240}
241
242int
243valid_task_id (int task)
244{
245  return get_entry_vptr (task) != NULL;
246}
247
248void *
249get_self_id (void)
250{
251  struct value *val;
252  void *self_id;
253  int result;
254  struct task_entry *ent;
255  extern int do_not_insert_breakpoints;
256
257#if !((defined(sun) && defined(__SVR4)) || defined(VXWORKS_TARGET) || defined(__WIN32__))
258  if (thread_support)
259#endif
260    {
261      ent = get_thread_entry_vptr (GET_CURRENT_THREAD ());
262      return ent ? ent->task_id : 0;
263    }
264
265  /* FIXME: calling a function in the inferior with a multithreaded application
266     is not reliable, so return NULL if there is no safe way to get the current
267     task */
268  return NULL;
269}
270
271int
272get_current_task (void)
273{
274  int result;
275
276  /* FIXME: language_ada should be defined in defs.h */
277  /*  if (current_language->la_language != language_ada) return -1; */
278
279  result = get_entry_number (get_self_id ());
280
281  /* return -1 if not found */
282  return result == 0 ? -1 : result;
283}
284
285/* Print detailed information about specified task */
286
287static void
288info_task (char *arg, int from_tty)
289{
290  void *temp_task;
291  struct task_entry *pt, *pt2;
292  void *self_id, *caller;
293  struct task_fields atcb, atcb2;
294  struct entry_call call;
295  int bounds[2];
296  char image[256];
297  int num;
298
299  /* FIXME: language_ada should be defined in defs.h */
300  /*  if (current_language->la_language != language_ada)
301     {
302     printf_filtered ("The current language does not support tasks.\n");
303     return;
304     }
305   */
306  pt = get_entry_vptr (atoi (arg));
307  if (pt == NULL)
308    {
309      printf_filtered ("Task %s not found.\n", arg);
310      return;
311    }
312
313  temp_task = pt->task_id;
314
315  /* read the atcb in the inferior */
316  READ_MEMORY ((CORE_ADDR) temp_task, atcb);
317
318  /* print the Ada task id */
319  printf_filtered ("Ada Task: %p\n", temp_task);
320
321  /* print the name of the task */
322  if (atcb.image.P_ARRAY != NULL)
323    {
324      READ_MEMORY ((CORE_ADDR) EXTRACT_ADDRESS (atcb.image.P_BOUNDS), bounds);
325      bounds[1] = EXTRACT_INT (bounds[1]);
326      read_memory ((CORE_ADDR) EXTRACT_ADDRESS (atcb.image.P_ARRAY),
327		   (char *) &image, bounds[1]);
328      printf_filtered ("Name: %.*s\n", bounds[1], image);
329    }
330  else
331    printf_filtered ("<no name>\n");
332
333  /* print the thread id */
334
335  if ((long) pt->thread < 65536)
336    printf_filtered ("Thread: %ld\n", (long int) pt->thread);
337  else
338    printf_filtered ("Thread: %p\n", pt->thread);
339
340  if ((long) pt->lwp != 0)
341    {
342      if ((long) pt->lwp < 65536)
343	printf_filtered ("LWP: %ld\n", (long int) pt->lwp);
344      else
345	printf_filtered ("LWP: %p\n", pt->lwp);
346    }
347
348  /* print the parent gdb task id */
349  num = get_entry_number (EXTRACT_ADDRESS (atcb.parent));
350  if (num != 0)
351    {
352      printf_filtered ("Parent: %d", num);
353      pt2 = get_entry_vptr (num);
354      READ_MEMORY ((CORE_ADDR) pt2->task_id, atcb2);
355
356      /* print the name of the task */
357      if (atcb2.image.P_ARRAY != NULL)
358	{
359	  READ_MEMORY ((CORE_ADDR) EXTRACT_ADDRESS (atcb2.image.P_BOUNDS),
360		       bounds);
361	  bounds[1] = EXTRACT_INT (bounds[1]);
362	  read_memory ((CORE_ADDR) EXTRACT_ADDRESS (atcb2.image.P_ARRAY),
363		       (char *) &image, bounds[1]);
364	  printf_filtered (" (%.*s)\n", bounds[1], image);
365	}
366      else
367	printf_filtered ("\n");
368    }
369  else
370    printf_filtered ("No parent\n");
371
372  /* print the base priority of the task */
373  printf_filtered ("Base Priority: %d\n", EXTRACT_INT (atcb.priority));
374
375  /* print the current state of the task */
376
377  /* check if this task is accepting a rendezvous */
378  if (atcb.call == NULL)
379    caller = NULL;
380  else
381    {
382      READ_MEMORY ((CORE_ADDR) EXTRACT_ADDRESS (atcb.call), call);
383      caller = EXTRACT_ADDRESS (call.self);
384    }
385
386  if (caller != NULL)
387    {
388      num = get_entry_number (caller);
389      printf_filtered ("Accepting rendezvous with %d", num);
390
391      if (num != 0)
392	{
393	  pt2 = get_entry_vptr (num);
394	  READ_MEMORY ((CORE_ADDR) pt2->task_id, atcb2);
395
396	  /* print the name of the task */
397	  if (atcb2.image.P_ARRAY != NULL)
398	    {
399	      READ_MEMORY ((CORE_ADDR) EXTRACT_ADDRESS (atcb2.image.P_BOUNDS),
400			   bounds);
401	      bounds[1] = EXTRACT_INT (bounds[1]);
402	      read_memory ((CORE_ADDR) EXTRACT_ADDRESS (atcb2.image.P_ARRAY),
403			   (char *) &image, bounds[1]);
404	      printf_filtered (" (%.*s)\n", bounds[1], image);
405	    }
406	  else
407	    printf_filtered ("\n");
408	}
409      else
410	printf_filtered ("\n");
411    }
412  else
413    printf_filtered ("State: %s\n", ada_long_task_states[atcb.state]);
414}
415
416#if 0
417
418/* A useful function that shows the alignment of all the fields in the
419   tasks_fields structure
420 */
421
422print_align (void)
423{
424  struct task_fields tf;
425  void *tf_base = &(tf);
426  void *tf_state = &(tf.state);
427  void *tf_entry_num = &(tf.entry_num);
428  void *tf_parent = &(tf.parent);
429  void *tf_priority = &(tf.priority);
430  void *tf_current_priority = &(tf.current_priority);
431  void *tf_image = &(tf.image);
432  void *tf_call = &(tf.call);
433  void *tf_thread = &(tf.thread);
434  void *tf_lwp = &(tf.lwp);
435  printf_filtered ("\n");
436  printf_filtered ("(tf_base = 0x%x)\n", tf_base);
437  printf_filtered ("task_fields.entry_num        at %3d (0x%x)\n",
438		   tf_entry_num - tf_base, tf_entry_num);
439  printf_filtered ("task_fields.state            at %3d (0x%x)\n",
440		   tf_state - tf_base, tf_state);
441  printf_filtered ("task_fields.parent           at %3d (0x%x)\n",
442		   tf_parent - tf_base, tf_parent);
443  printf_filtered ("task_fields.priority         at %3d (0x%x)\n",
444		   tf_priority - tf_base, tf_priority);
445  printf_filtered ("task_fields.current_priority at %3d (0x%x)\n",
446		   tf_current_priority - tf_base, tf_current_priority);
447  printf_filtered ("task_fields.image            at %3d (0x%x)\n",
448		   tf_image - tf_base, tf_image);
449  printf_filtered ("task_fields.call             at %3d (0x%x)\n",
450		   tf_call - tf_base, tf_call);
451  printf_filtered ("task_fields.thread           at %3d (0x%x)\n",
452		   tf_thread - tf_base, tf_thread);
453  printf_filtered ("task_fields.lwp              at %3d (0x%x)\n",
454		   tf_lwp - tf_base, tf_lwp);
455  printf_filtered ("\n");
456}
457#endif
458
459/* Print information about currently known tasks */
460
461static void
462info_tasks (char *arg, int from_tty)
463{
464  struct value *val;
465  int i, task_number, state;
466  void *temp_task, *temp_tasks[MAX_NUMBER_OF_KNOWN_TASKS];
467  struct task_entry *pt;
468  void *self_id, *caller, *thread_id = NULL;
469  struct task_fields atcb;
470  struct entry_call call;
471  int bounds[2];
472  char image[256];
473  int size;
474  char car;
475
476#if defined(__alpha__) && defined(__osf__) && !defined(VXWORKS_TARGET)
477  pthreadTeb_t thr;
478  gdb_gregset_t regs;
479#endif
480
481  static struct symbol *sym;
482  static struct minimal_symbol *msym;
483  static void *known_tasks_addr = NULL;
484
485  int init_only = gdbtk_task_initialization;
486  gdbtk_task_initialization = 0;
487
488  task_number = 0;
489
490  if (PIDGET (inferior_ptid) == 0)
491    {
492      printf_filtered ("The program is not being run under gdb. ");
493      printf_filtered ("Use 'run' or 'attach' first.\n");
494      return;
495    }
496
497  if (ada__tasks_check_symbol_table)
498    {
499      thread_support = 0;
500#if (defined(__alpha__) && defined(__osf__) & !defined(VXWORKS_TARGET)) || \
501    defined (_AIX)
502      thread_support = 1;
503#endif
504
505      msym = lookup_minimal_symbol (KNOWN_TASKS_NAME, NULL, NULL);
506      if (msym != NULL)
507	known_tasks_addr = (void *) SYMBOL_VALUE_ADDRESS (msym);
508      else
509#ifndef VXWORKS_TARGET
510	return;
511#else
512	{
513	  if (target_lookup_symbol (KNOWN_TASKS_NAME, &known_tasks_addr) != 0)
514	    return;
515	}
516#endif
517
518      ada__tasks_check_symbol_table = 0;
519    }
520
521  if (known_tasks_addr == NULL)
522    return;
523
524#if !((defined(sun) && defined(__SVR4)) || defined(VXWORKS_TARGET) || defined(__WIN32__) || defined (hpux))
525  if (thread_support)
526#endif
527    thread_id = GET_CURRENT_THREAD ();
528
529  /* then we get a list of tasks created */
530
531  init_task_list ();
532
533  READ_MEMORY ((CORE_ADDR) known_tasks_addr, temp_tasks);
534
535  for (i = 0; i < MAX_NUMBER_OF_KNOWN_TASKS; i++)
536    {
537      temp_task = EXTRACT_ADDRESS (temp_tasks[i]);
538
539      if (temp_task != NULL)
540	{
541	  task_number = get_entry_number (temp_task);
542	  if (task_number == 0)
543	    task_number = add_task_entry (temp_task, i);
544	}
545    }
546
547  /* Return without printing anything if this function was called in
548     order to init GDBTK tasking. */
549
550  if (init_only)
551    return;
552
553  /* print the header */
554
555#if defined(__alpha__) && defined(__osf__) && !defined(VXWORKS_TARGET)
556  printf_filtered
557    ("  ID       TID P-ID Pri Stack  %% State                  Name\n");
558#else
559  printf_filtered ("  ID       TID P-ID Pri State                  Name\n");
560#endif
561
562  /* Now that we have a list of task id's, we can print them */
563  pt = task_list;
564  while (pt)
565    {
566      temp_task = pt->task_id;
567
568      /* read the atcb in the inferior */
569      READ_MEMORY ((CORE_ADDR) temp_task, atcb);
570
571      /* store the thread id for future use */
572      pt->thread = EXTRACT_ADDRESS (atcb.thread);
573
574#if defined (linux)
575      pt->lwp = (void *) THREAD_TO_PID (atcb.thread, 0);
576#else
577      pt->lwp = EXTRACT_ADDRESS (atcb.lwp);
578#endif
579
580      /* print a star if this task is the current one */
581      if (thread_id)
582#if defined (__WIN32__) || defined (SGI) || defined (hpux)
583	printf_filtered (pt->lwp == thread_id ? "*" : " ");
584#else
585	printf_filtered (pt->thread == thread_id ? "*" : " ");
586#endif
587
588      /* print the gdb task id */
589      printf_filtered ("%3d", pt->task_num);
590
591      /* print the Ada task id */
592#ifndef VXWORKS_TARGET
593      printf_filtered (" %9lx", (long) temp_task);
594#else
595#ifdef TARGET_64
596      printf_filtered (" %#9lx", (unsigned long) pt->thread & 0x3ffffffffff);
597#else
598      printf_filtered (" %#9lx", (long) pt->thread);
599#endif
600#endif
601
602      /* print the parent gdb task id */
603      printf_filtered
604	(" %4d", get_entry_number (EXTRACT_ADDRESS (atcb.parent)));
605
606      /* print the base priority of the task */
607      printf_filtered (" %3d", EXTRACT_INT (atcb.priority));
608
609#if defined(__alpha__) && defined(__osf__) && !defined(VXWORKS_TARGET)
610      if (pt->task_num == 1 || atcb.state == Terminated)
611	{
612	  printf_filtered ("  Unknown");
613	  goto next;
614	}
615
616      read_memory ((CORE_ADDR) atcb.thread, &thr, sizeof (thr));
617      current_thread = atcb.thread;
618      regs.regs[SP_REGNUM] = 0;
619      if (dec_thread_get_registers (&regs, NULL) == 0)
620	{
621	  pt->stack_per = (100 * ((long) thr.__stack_base -
622				  regs.regs[SP_REGNUM])) / thr.__stack_size;
623	  /* if the thread is terminated but still there, the
624	     stack_base/size values are erroneous. Try to patch it */
625	  if (pt->stack_per < 0 || pt->stack_per > 100)
626	    pt->stack_per = 0;
627	}
628
629      /* print information about stack space used in the thread */
630      if (thr.__stack_size < 1024 * 1024)
631	{
632	  size = thr.__stack_size / 1024;
633	  car = 'K';
634	}
635      else if (thr.__stack_size < 1024 * 1024 * 1024)
636	{
637	  size = thr.__stack_size / 1024 / 1024;
638	  car = 'M';
639	}
640      else			/* Who knows... */
641	{
642	  size = thr.__stack_size / 1024 / 1024 / 1024;
643	  car = 'G';
644	}
645      printf_filtered (" %4d%c %2d", size, car, pt->stack_per);
646    next:
647#endif
648
649      /* print the current state of the task */
650
651      /* check if this task is accepting a rendezvous */
652      if (atcb.call == NULL)
653	caller = NULL;
654      else
655	{
656	  READ_MEMORY ((CORE_ADDR) EXTRACT_ADDRESS (atcb.call), call);
657	  caller = EXTRACT_ADDRESS (call.self);
658	}
659
660      if (caller != NULL)
661	printf_filtered (" Accepting RV with %-4d",
662			 get_entry_number (caller));
663      else
664	{
665	  state = atcb.state;
666#if defined (__WIN32__) || defined (SGI) || defined (hpux)
667	  if (state == Runnable && (thread_id && pt->lwp == thread_id))
668#else
669	  if (state == Runnable && (thread_id && pt->thread == thread_id))
670#endif
671	    /* Replace "Runnable" by "Running" if this is the current task */
672	    printf_filtered (" %-22s", "Running");
673	  else
674	    printf_filtered (" %-22s", ada_task_states[state]);
675	}
676
677      /* finally, print the name of the task */
678      if (atcb.image.P_ARRAY != NULL)
679	{
680	  READ_MEMORY ((CORE_ADDR) EXTRACT_ADDRESS (atcb.image.P_BOUNDS),
681		       bounds);
682	  bounds[1] = EXTRACT_INT (bounds[1]);
683	  read_memory ((CORE_ADDR) EXTRACT_ADDRESS (atcb.image.P_ARRAY),
684		       (char *) &image, bounds[1]);
685	  printf_filtered (" %.*s\n", bounds[1], image);
686	}
687      else
688	printf_filtered (" <no name>\n");
689
690      pt = pt->next_task;
691    }
692}
693
694/* Task list initialization for GDB-Tk.  We basically use info_tasks()
695   to initialize our variables, but abort that function before we
696   actually print anything. */
697
698int
699gdbtk_tcl_tasks_initialize (void)
700{
701  gdbtk_task_initialization = 1;
702  info_tasks ("", gdb_stdout);
703
704  return (task_list != NULL);
705}
706
707static void
708info_tasks_command (char *arg, int from_tty)
709{
710  if (arg == NULL || *arg == '\000')
711    info_tasks (arg, from_tty);
712  else
713    info_task (arg, from_tty);
714}
715
716/* Switch from one thread to another. */
717
718static void
719switch_to_thread (ptid_t ptid)
720{
721  if (ptid_equal (ptid, inferior_ptid))
722    return;
723
724  inferior_ptid = ptid;
725  flush_cached_frames ();
726  registers_changed ();
727  stop_pc = read_pc ();
728  select_frame (get_current_frame ());
729}
730
731/* Switch to a specified task. */
732
733static int
734task_switch (void *tid, void *lwpid)
735{
736  int res = 0, pid;
737
738  if (thread_support)
739    {
740      flush_cached_frames ();
741
742      if (current_task != current_task_id)
743	{
744	  res = THREAD_FETCH_REGISTERS ();
745	}
746      else
747	{
748#if (defined(__alpha__) && defined(__osf__) && !defined(VXWORKS_TARGET))
749	  supply_gregset (&gregset_saved);
750	  supply_fpregset (&fpregset_saved);
751#endif
752	}
753
754      if (res == 0)
755	stop_pc = read_pc ();
756      select_frame (get_current_frame ());
757      return res;
758    }
759
760  return -1;
761}
762
763static void
764task_command (char *tidstr, int from_tty)
765{
766  int num;
767  struct task_entry *e;
768
769  if (!tidstr)
770    error ("Please specify a task ID.  Use the \"info tasks\" command to\n"
771	   "see the IDs of currently known tasks.");
772
773  num = atoi (tidstr);
774  e = get_entry_vptr (num);
775
776  if (e == NULL)
777    error ("Task ID %d not known.  Use the \"info tasks\" command to\n"
778	   "see the IDs of currently known tasks.", num);
779
780  if (current_task_id == -1)
781    {
782#if (defined(__alpha__) && defined(__osf__) && !defined(VXWORKS_TARGET))
783      fill_gregset (&gregset_saved, -1);
784      fill_fpregset (&fpregset_saved, -1);
785#endif
786      current_task_id = get_current_task ();
787    }
788
789  current_task = num;
790  current_task_index = e->known_tasks_index;
791  current_thread = e->thread;
792  current_lwp = e->lwp;
793  if (task_switch (e->thread, e->lwp) == 0)
794    {
795      /* FIXME: find_printable_frame should be defined in frame.h, and
796         implemented in ada-lang.c */
797      /*      find_printable_frame (deprecated_selected_frame, frame_relative_level (deprecated_selected_frame)); */
798      printf_filtered ("[Switching to task %d]\n", num);
799      print_stack_frame (deprecated_selected_frame,
800			 frame_relative_level (deprecated_selected_frame), 1);
801    }
802  else
803    printf_filtered ("Unable to switch to task %d\n", num);
804}
805
806void
807_initialize_tasks (void)
808{
809  static struct cmd_list_element *task_cmd_list = NULL;
810  extern struct cmd_list_element *cmdlist;
811
812  add_info ("tasks", info_tasks_command,
813	    "Without argument: list all known Ada tasks, with status information.\n"
814	    "info tasks n: print detailed information of task n.\n");
815
816  add_prefix_cmd ("task", class_run, task_command,
817		  "Use this command to switch between tasks.\n\
818 The new task ID must be currently known.", &task_cmd_list, "task ", 1, &cmdlist);
819}
820