2002-07-20 Aidan Skinner <aidan@velvet.net>
[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 
160 add_task_entry (void *p_task_id, int index)
161 {
162   struct task_entry *new_task_entry = NULL;
163   struct task_entry *pt;
164
165   highest_task_num++;
166   new_task_entry = xmalloc (sizeof (struct task_entry));
167   new_task_entry->task_num = highest_task_num;
168   new_task_entry->task_id = p_task_id;
169   new_task_entry->known_tasks_index = index;
170   new_task_entry->next_task = NULL;
171   pt = task_list;
172   if (pt)
173     {
174       while (pt->next_task)
175         pt = pt->next_task;
176       pt->next_task = new_task_entry;
177       pt->stack_per = 0;
178     }
179   else task_list = new_task_entry;
180   return new_task_entry->task_num;
181 }
182
183 int 
184 get_entry_number (void *p_task_id)
185 {
186   struct task_entry *pt;
187
188   pt = task_list;
189   while (pt != NULL)
190     {
191       if (pt->task_id == p_task_id)
192         return pt->task_num;
193       pt = pt->next_task;
194     }
195   return 0;
196 }
197
198 static struct task_entry *
199 get_thread_entry_vptr (void *thread)
200 {
201   struct task_entry *pt;
202
203   pt = task_list;
204   while (pt != NULL)
205     {
206       if (pt->thread == thread)
207       return pt;
208       pt = pt->next_task;
209     }
210   return 0;
211 }
212
213 static struct task_entry *
214 get_entry_vptr (int p_task_num)
215 {
216   struct task_entry *pt;
217
218   pt = task_list;
219   while (pt)
220     {
221       if (pt->task_num == p_task_num)
222         return pt;
223       pt = pt->next_task;
224     }
225   return NULL;
226 }
227
228 void
229 init_task_list (void)
230 {
231   struct task_entry *pt, *old_pt;
232
233   pt = task_list;
234   while (pt)
235     {
236       old_pt = pt;
237       pt = pt->next_task;
238       xfree (old_pt);
239     };
240   task_list = NULL;
241   highest_task_num = 0;
242 }
243
244 int
245 valid_task_id (int task)
246 {
247   return get_entry_vptr (task) != NULL;
248 }
249
250 void *
251 get_self_id (void)
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 (char *arg, int from_tty)
290 {
291   void *temp_task;
292   struct task_entry *pt, *pt2;
293   void *self_id, *caller;
294   struct task_fields atcb, atcb2;
295   struct entry_call call;
296   int bounds [2];
297   char image [256];
298   int num;
299
300   /* FIXME: language_ada should be defined in defs.h */
301   /*  if (current_language->la_language != language_ada) 
302     { 
303       printf_filtered ("The current language does not support tasks.\n"); 
304       return; 
305     } 
306   */
307   pt = get_entry_vptr (atoi (arg));
308   if (pt == NULL)
309     {
310       printf_filtered ("Task %s not found.\n", arg); 
311       return; 
312     }
313
314   temp_task = pt->task_id;
315
316   /* read the atcb in the inferior */
317   READ_MEMORY ((CORE_ADDR) temp_task, atcb);
318
319   /* print the Ada task id */
320   printf_filtered ("Ada Task: %p\n", temp_task);
321
322   /* print the name of the task */
323   if (atcb.image.P_ARRAY != NULL) {
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 printf_filtered ("<no name>\n");
331
332   /* print the thread id */
333
334   if ((long) pt->thread < 65536)
335     printf_filtered ("Thread: %ld\n", (long int) pt->thread);
336   else
337     printf_filtered ("Thread: %p\n", pt->thread);
338
339   if ((long) pt->lwp != 0)
340     {
341       if ((long) pt->lwp < 65536)
342         printf_filtered ("LWP: %ld\n", (long int) pt->lwp);
343       else
344         printf_filtered ("LWP: %p\n", pt->lwp);
345     }
346
347   /* print the parent gdb task id */
348   num = get_entry_number (EXTRACT_ADDRESS (atcb.parent));
349   if (num != 0)
350     {
351       printf_filtered ("Parent: %d", num);
352       pt2 = get_entry_vptr (num);
353       READ_MEMORY ((CORE_ADDR) pt2->task_id, atcb2);
354
355       /* print the name of the task */
356       if (atcb2.image.P_ARRAY != NULL) {
357         READ_MEMORY ((CORE_ADDR) EXTRACT_ADDRESS (atcb2.image.P_BOUNDS),
358                      bounds);
359         bounds [1] = EXTRACT_INT (bounds [1]);
360         read_memory ((CORE_ADDR) EXTRACT_ADDRESS (atcb2.image.P_ARRAY),
361                      (char*) &image, bounds [1]);
362         printf_filtered (" (%.*s)\n", bounds [1], image);
363       }
364       else
365         printf_filtered ("\n");
366     }
367   else
368     printf_filtered ("No parent\n");
369
370   /* print the base priority of the task */
371   printf_filtered ("Base Priority: %d\n", EXTRACT_INT (atcb.priority));
372
373   /* print the current state of the task */
374
375   /* check if this task is accepting a rendezvous */
376   if (atcb.call == NULL)
377     caller = NULL;
378   else {
379     READ_MEMORY ((CORE_ADDR) EXTRACT_ADDRESS (atcb.call), call);
380     caller = EXTRACT_ADDRESS (call.self);
381   }
382  
383   if (caller != NULL)
384     {
385       num = get_entry_number (caller);
386       printf_filtered ("Accepting rendezvous with %d", num);
387
388       if (num != 0)
389         {
390           pt2 = get_entry_vptr (num);
391           READ_MEMORY ((CORE_ADDR) pt2->task_id, atcb2);
392
393           /* print the name of the task */
394           if (atcb2.image.P_ARRAY != NULL) {
395             READ_MEMORY ((CORE_ADDR) EXTRACT_ADDRESS (atcb2.image.P_BOUNDS),
396                          bounds);
397             bounds [1] = EXTRACT_INT (bounds [1]);
398             read_memory ((CORE_ADDR) EXTRACT_ADDRESS (atcb2.image.P_ARRAY),
399                          (char*) &image, bounds [1]);
400             printf_filtered (" (%.*s)\n", bounds [1], image);
401           }
402           else
403             printf_filtered ("\n");
404         }
405       else
406         printf_filtered ("\n");
407     }
408   else
409     printf_filtered ("State: %s\n", ada_long_task_states [atcb.state]);
410 }
411
412 #if 0
413
414 /* A useful function that shows the alignment of all the fields in the
415    tasks_fields structure
416  */
417
418 print_align (void)
419 {
420   struct task_fields tf;
421   void *tf_base             = &(tf);
422   void *tf_state            = &(tf.state);
423   void *tf_entry_num        = &(tf.entry_num);
424   void *tf_parent           = &(tf.parent);
425   void *tf_priority         = &(tf.priority);
426   void *tf_current_priority = &(tf.current_priority);
427   void *tf_image            = &(tf.image);
428   void *tf_call             = &(tf.call);
429   void *tf_thread           = &(tf.thread);
430   void *tf_lwp              = &(tf.lwp);
431   printf_filtered ("\n");
432   printf_filtered ("(tf_base = 0x%x)\n", tf_base);
433   printf_filtered ("task_fields.entry_num        at %3d (0x%x)\n", tf_entry_num - tf_base, tf_entry_num);
434   printf_filtered ("task_fields.state            at %3d (0x%x)\n", tf_state - tf_base, tf_state);
435   printf_filtered ("task_fields.parent           at %3d (0x%x)\n", tf_parent - tf_base, tf_parent);
436   printf_filtered ("task_fields.priority         at %3d (0x%x)\n", tf_priority - tf_base, tf_priority);
437   printf_filtered ("task_fields.current_priority at %3d (0x%x)\n", tf_current_priority - tf_base, tf_current_priority);
438   printf_filtered ("task_fields.image            at %3d (0x%x)\n", tf_image - tf_base, tf_image);
439   printf_filtered ("task_fields.call             at %3d (0x%x)\n", tf_call - tf_base, tf_call);
440   printf_filtered ("task_fields.thread           at %3d (0x%x)\n", tf_thread - tf_base, tf_thread);
441   printf_filtered ("task_fields.lwp              at %3d (0x%x)\n", tf_lwp - tf_base, tf_lwp);
442   printf_filtered ("\n"); 
443 }
444 #endif
445
446 /* Print information about currently known tasks */
447
448 static void
449 info_tasks (char *arg, int from_tty)
450 {
451   struct value* val;
452   int i, task_number, state;
453   void *temp_task, *temp_tasks [MAX_NUMBER_OF_KNOWN_TASKS];
454   struct task_entry *pt;
455   void *self_id, *caller, *thread_id=NULL;
456   struct task_fields atcb;
457   struct entry_call call;
458   int bounds [2];
459   char image [256];
460   int size;
461   char car;
462
463 #if defined(__alpha__) && defined(__osf__) && !defined(VXWORKS_TARGET)
464   pthreadTeb_t thr;
465   gdb_gregset_t regs;
466 #endif
467
468   static struct symbol *sym;
469   static struct minimal_symbol *msym;
470   static void *known_tasks_addr = NULL;
471
472   int init_only = gdbtk_task_initialization;
473   gdbtk_task_initialization = 0;
474
475   task_number = 0;
476
477   if (PIDGET(inferior_ptid) == 0)
478     {
479       printf_filtered ("The program is not being run under gdb. ");
480       printf_filtered ("Use 'run' or 'attach' first.\n");
481       return;
482     }
483
484   if (ada__tasks_check_symbol_table)
485     {
486       thread_support = 0;
487 #if (defined(__alpha__) && defined(__osf__) & !defined(VXWORKS_TARGET)) || \
488     defined (_AIX)
489       thread_support = 1;
490 #endif
491
492       msym = lookup_minimal_symbol (KNOWN_TASKS_NAME, NULL, NULL);
493       if (msym != NULL)
494         known_tasks_addr = (void *) SYMBOL_VALUE_ADDRESS (msym);
495       else
496 #ifndef VXWORKS_TARGET
497         return; 
498 #else
499         {
500           if (target_lookup_symbol (KNOWN_TASKS_NAME, &known_tasks_addr) != 0)
501             return;
502         }
503 #endif
504
505       ada__tasks_check_symbol_table = 0;
506     }
507
508   if (known_tasks_addr == NULL)
509     return;
510
511 #if !((defined(sun) && defined(__SVR4)) || defined(VXWORKS_TARGET) || defined(__WIN32__) || defined (hpux))
512   if (thread_support)
513 #endif
514     thread_id = GET_CURRENT_THREAD ();
515
516   /* then we get a list of tasks created */
517
518   init_task_list ();
519
520   READ_MEMORY ((CORE_ADDR) known_tasks_addr, temp_tasks);
521
522   for (i=0; i<MAX_NUMBER_OF_KNOWN_TASKS; i++)
523     {
524       temp_task = EXTRACT_ADDRESS (temp_tasks[i]);
525
526       if (temp_task != NULL)
527         {
528           task_number = get_entry_number (temp_task);
529           if (task_number == 0)
530             task_number = add_task_entry (temp_task, i);
531         }
532     }      
533
534   /* Return without printing anything if this function was called in
535      order to init GDBTK tasking. */
536
537   if (init_only) return;
538
539   /* print the header */
540
541 #if defined(__alpha__) && defined(__osf__) && !defined(VXWORKS_TARGET)
542   printf_filtered
543    ("  ID       TID P-ID Pri Stack  %% State                  Name\n");
544 #else
545   printf_filtered ("  ID       TID P-ID Pri State                  Name\n");
546 #endif
547
548   /* Now that we have a list of task id's, we can print them */
549   pt = task_list;
550   while (pt)
551     {
552       temp_task = pt->task_id;
553
554       /* read the atcb in the inferior */
555       READ_MEMORY ((CORE_ADDR) temp_task, atcb);
556
557       /* store the thread id for future use */
558       pt->thread = EXTRACT_ADDRESS (atcb.thread);
559
560 #if defined (linux)
561       pt->lwp = (void *) THREAD_TO_PID (atcb.thread, 0);
562 #else
563       pt->lwp = EXTRACT_ADDRESS (atcb.lwp);
564 #endif
565
566       /* print a star if this task is the current one */
567       if (thread_id)
568 #if defined (__WIN32__) || defined (SGI) || defined (hpux)
569         printf_filtered (pt->lwp == thread_id ? "*" : " ");
570 #else
571         printf_filtered (pt->thread == thread_id ? "*" : " ");
572 #endif
573
574       /* print the gdb task id */
575       printf_filtered ("%3d", pt->task_num);
576
577       /* print the Ada task id */
578 #ifndef VXWORKS_TARGET
579       printf_filtered (" %9lx", (long) temp_task);
580 #else
581 #ifdef TARGET_64
582       printf_filtered (" %#9lx", (unsigned long)pt->thread & 0x3ffffffffff);
583 #else
584       printf_filtered (" %#9lx", (long)pt->thread);
585 #endif
586 #endif
587
588       /* print the parent gdb task id */
589       printf_filtered
590         (" %4d", get_entry_number (EXTRACT_ADDRESS (atcb.parent)));
591
592       /* print the base priority of the task */
593       printf_filtered (" %3d", EXTRACT_INT (atcb.priority));
594
595 #if defined(__alpha__) && defined(__osf__) && !defined(VXWORKS_TARGET)
596       if (pt->task_num == 1 || atcb.state == Terminated)
597         {
598           printf_filtered ("  Unknown");
599           goto next;
600         }
601
602       read_memory ((CORE_ADDR)atcb.thread, &thr, sizeof (thr));
603       current_thread = atcb.thread;
604       regs.regs [SP_REGNUM] = 0;
605       if (dec_thread_get_registers (&regs, NULL) == 0) {
606         pt->stack_per = (100 * ((long)thr.__stack_base -
607         regs.regs [SP_REGNUM])) / thr.__stack_size;
608         /* if the thread is terminated but still there, the
609         stack_base/size values are erroneous. Try to patch it */
610         if (pt->stack_per < 0 || pt->stack_per > 100) pt->stack_per = 0;
611       }
612
613       /* print information about stack space used in the thread */
614       if (thr.__stack_size < 1024*1024)
615         {
616           size = thr.__stack_size / 1024;
617           car = 'K';
618         }
619       else if (thr.__stack_size < 1024*1024*1024)
620         {
621           size = thr.__stack_size / 1024 / 1024;
622           car = 'M';
623         }
624       else /* Who knows... */
625         {
626           size = thr.__stack_size / 1024 / 1024 / 1024;
627           car = 'G';
628         }
629       printf_filtered (" %4d%c %2d", size, car, pt->stack_per);
630 next:
631 #endif
632
633       /* print the current state of the task */
634
635       /* check if this task is accepting a rendezvous */
636       if (atcb.call == NULL)
637         caller = NULL;
638       else {
639         READ_MEMORY ((CORE_ADDR) EXTRACT_ADDRESS (atcb.call), call);
640         caller = EXTRACT_ADDRESS (call.self);
641       }
642  
643       if (caller != NULL)
644         printf_filtered (" Accepting RV with %-4d", get_entry_number (caller));
645       else
646         {
647           state = atcb.state;
648 #if defined (__WIN32__) || defined (SGI) || defined (hpux)
649           if (state == Runnable && (thread_id && pt->lwp == thread_id))
650 #else
651           if (state == Runnable && (thread_id && pt->thread == thread_id))
652 #endif
653             /* Replace "Runnable" by "Running" if this is the current task */
654             printf_filtered (" %-22s", "Running");
655           else
656             printf_filtered (" %-22s", ada_task_states [state]);
657         }
658
659       /* finally, print the name of the task */
660       if (atcb.image.P_ARRAY != NULL) {
661         READ_MEMORY ((CORE_ADDR) EXTRACT_ADDRESS (atcb.image.P_BOUNDS), bounds);
662         bounds [1] = EXTRACT_INT (bounds [1]);
663         read_memory ((CORE_ADDR) EXTRACT_ADDRESS (atcb.image.P_ARRAY),
664                      (char*)&image, bounds [1]);
665         printf_filtered (" %.*s\n", bounds [1], image);
666       }
667       else printf_filtered (" <no name>\n");
668
669       pt = pt->next_task;
670     }
671 }
672
673 /* Task list initialization for GDB-Tk.  We basically use info_tasks()
674    to initialize our variables, but abort that function before we
675    actually print anything. */
676
677 int
678 gdbtk_tcl_tasks_initialize (void)
679 {
680   gdbtk_task_initialization = 1;
681   info_tasks ("", gdb_stdout);
682
683   return (task_list != NULL);
684 }
685
686 static void
687 info_tasks_command (char *arg, int from_tty)
688 {
689    if (arg == NULL || *arg == '\000')
690       info_tasks (arg, from_tty);
691    else
692       info_task (arg, from_tty);
693 }
694
695 /* Switch from one thread to another. */
696
697 static void
698 switch_to_thread (ptid_t ptid)
699 {
700   if (ptid_equal (ptid, inferior_ptid))
701     return;
702
703   inferior_ptid = ptid;
704   flush_cached_frames ();
705   registers_changed ();
706   stop_pc = read_pc ();
707   select_frame (get_current_frame ());
708 }
709
710 /* Switch to a specified task. */
711
712 static int
713 task_switch (void *tid, void *lwpid)
714 {
715   int res = 0, pid;
716
717   if (thread_support)
718     {
719       flush_cached_frames ();
720
721       if (current_task != current_task_id)
722         {
723           res = THREAD_FETCH_REGISTERS ();
724         }
725       else
726         {
727 #if (defined(__alpha__) && defined(__osf__) && !defined(VXWORKS_TARGET))
728           supply_gregset (&gregset_saved);
729           supply_fpregset (&fpregset_saved);
730 #endif
731         }
732
733       if (res == 0) stop_pc = read_pc();
734       select_frame (get_current_frame ());
735       return res;
736     }
737
738   return -1;
739 }
740
741 static void
742 task_command (char *tidstr, int from_tty)
743 {
744   int num;
745   struct task_entry *e;
746
747   if (!tidstr)
748     error ("Please specify a task ID.  Use the \"info tasks\" command to\n"
749            "see the IDs of currently known tasks.");
750
751   num = atoi (tidstr);
752   e = get_entry_vptr (num);
753
754   if (e == NULL)
755     error ("Task ID %d not known.  Use the \"info tasks\" command to\n"
756            "see the IDs of currently known tasks.", num);
757
758   if (current_task_id == -1)
759     {
760 #if (defined(__alpha__) && defined(__osf__) && !defined(VXWORKS_TARGET))
761       fill_gregset (&gregset_saved, -1);
762       fill_fpregset (&fpregset_saved, -1);
763 #endif
764       current_task_id = get_current_task ();
765     }
766
767   current_task = num;
768   current_task_index = e->known_tasks_index;
769   current_thread = e->thread;
770   current_lwp = e->lwp;
771   if (task_switch (e->thread, e->lwp) == 0)
772     {
773       /* FIXME: find_printable_frame should be defined in frame.h, and
774          implemented in ada-lang.c */
775       /*      find_printable_frame (selected_frame, frame_relative_level (selected_frame));*/
776       printf_filtered ("[Switching to task %d]\n", num);
777       print_stack_frame (selected_frame, frame_relative_level (selected_frame), 1);
778     }
779   else
780     printf_filtered ("Unable to switch to task %d\n", num);
781 }
782
783 void
784 _initialize_tasks (void)
785 {
786   static struct cmd_list_element *task_cmd_list = NULL;
787   extern struct cmd_list_element *cmdlist;
788
789   add_info (
790         "tasks", info_tasks_command,
791         "Without argument: list all known Ada tasks, with status information.\n"
792         "info tasks n: print detailed information of task n.\n");
793
794   add_prefix_cmd ("task", class_run, task_command,
795                   "Use this command to switch between tasks.\n\
796  The new task ID must be currently known.", &task_cmd_list, "task ", 1,
797                   &cmdlist);
798 }