]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blob - gdb/ada-tasks.c
* ada-tasks.c (add_task_entry): replace calls to
[thirdparty/binutils-gdb.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 }