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