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