1130803Smarcel/* file ada-tasks.c: Ada tasking control for GDB
2130803Smarcel   Copyright 1997 Free Software Foundation, Inc.
3130803Smarcel   Contributed by Ada Core Technologies, Inc
4130803Smarcel.
5130803Smarcel   This file is part of GDB.
6130803Smarcel
7130803Smarcel   [$Id: ada-tasks.c,v 1.7 2003/06/17 20:58:32 ciceron Exp $]
8130803Smarcel   Authors: Roch-Alexandre Nomine Beguin, Arnaud Charlet <charlet@gnat.com>
9130803Smarcel
10130803Smarcel   This program is free software; you can redistribute it and/or modify
11130803Smarcel   it under the terms of the GNU General Public License as published by
12130803Smarcel   the Free Software Foundation; either version 2 of the License, or
13130803Smarcel   (at your option) any later version.
14130803Smarcel
15130803Smarcel*/
16130803Smarcel
17130803Smarcel#include <ctype.h>
18130803Smarcel#include "defs.h"
19130803Smarcel#include "command.h"
20130803Smarcel#include "value.h"
21130803Smarcel#include "language.h"
22130803Smarcel#include "inferior.h"
23130803Smarcel#include "symtab.h"
24130803Smarcel#include "target.h"
25130803Smarcel#include "regcache.h"
26130803Smarcel#include "gdbcore.h"
27130803Smarcel
28130803Smarcel#if (defined(__alpha__) && defined(__osf__) && !defined(__alpha_vxworks))
29130803Smarcel#include <sys/procfs.h>
30130803Smarcel#endif
31130803Smarcel
32130803Smarcel#if (defined(__alpha__) && defined(__osf__) && !defined(VXWORKS_TARGET))
33130803Smarcel#include "gregset.h"
34130803Smarcel#endif
35130803Smarcel
36130803Smarcel#include "ada-lang.h"
37130803Smarcel
38130803Smarcel/* FIXME: move all this conditional compilation in description
39130803Smarcel   files or in configure.in */
40130803Smarcel
41130803Smarcel#if defined (VXWORKS_TARGET)
42130803Smarcel#define THREAD_TO_PID(tid,lwpid) (tid)
43130803Smarcel
44130803Smarcel#elif defined (linux)
45130803Smarcel#define THREAD_TO_PID(tid,lwpid) (0)
46130803Smarcel
47130803Smarcel#elif (defined (sun) && defined (__SVR4))
48130803Smarcel#define THREAD_TO_PID thread_to_pid
49130803Smarcel
50130803Smarcel#elif defined (sgi) || defined (__WIN32__) || defined (hpux)
51130803Smarcel#define THREAD_TO_PID(tid,lwpid) ((int)lwpid)
52130803Smarcel
53130803Smarcel#else
54130803Smarcel#define THREAD_TO_PID(tid,lwpid) (0)
55130803Smarcel#endif
56130803Smarcel
57130803Smarcel#if defined(__alpha__) && defined(__osf__) && !defined(VXWORKS_TARGET)
58130803Smarcel#define THREAD_FETCH_REGISTERS dec_thread_fetch_registers
59130803Smarcel#define GET_CURRENT_THREAD dec_thread_get_current_thread
60130803Smarcelextern int dec_thread_get_registers (gdb_gregset_t *, gdb_fpregset_t *);
61130803Smarcel#endif
62130803Smarcel
63130803Smarcel#if defined (_AIX)
64130803Smarcel#define THREAD_FETCH_REGISTERS aix_thread_fetch_registers
65130803Smarcel#define GET_CURRENT_THREAD aix_thread_get_current_thread
66130803Smarcel#endif
67130803Smarcel
68130803Smarcel#if defined(VXWORKS_TARGET)
69130803Smarcel#define GET_CURRENT_THREAD() ((void*)inferior_pid)
70130803Smarcel#define THREAD_FETCH_REGISTERS() (-1)
71130803Smarcel
72130803Smarcel#elif defined (sun) && defined (__SVR4)
73130803Smarcel#define GET_CURRENT_THREAD solaris_thread_get_current_thread
74130803Smarcel#define THREAD_FETCH_REGISTERS() (-1)
75130803Smarcelextern void *GET_CURRENT_THREAD ();
76130803Smarcel
77130803Smarcel#elif defined (_AIX) || (defined(__alpha__) && defined(__osf__))
78130803Smarcelextern void *GET_CURRENT_THREAD ();
79130803Smarcel
80130803Smarcel#elif defined (__WIN32__) || defined (hpux)
81130803Smarcel#define GET_CURRENT_THREAD() (inferior_pid)
82130803Smarcel#define THREAD_FETCH_REGISTERS() (-1)
83130803Smarcel
84130803Smarcel#else
85130803Smarcel#define GET_CURRENT_THREAD() (NULL)
86130803Smarcel#define THREAD_FETCH_REGISTERS() (-1)
87130803Smarcel#endif
88130803Smarcel
89130803Smarcel#define KNOWN_TASKS_NAME "system__tasking__debug__known_tasks"
90130803Smarcel
91130803Smarcel#define READ_MEMORY(addr, var) read_memory (addr, (char*) &var, sizeof (var))
92130803Smarcel/* external declarations */
93130803Smarcel
94130803Smarcel/* Global visible variables */
95130803Smarcel
96130803Smarcelstruct task_entry *task_list = NULL;
97130803Smarcelint ada__tasks_check_symbol_table = 1;
98130803Smarcelvoid *pthread_kern_addr = NULL;
99130803Smarcel
100130803Smarcel#if (defined(__alpha__) && defined(__osf__) && !defined(VXWORKS_TARGET))
101130803Smarcelgdb_gregset_t gregset_saved;
102130803Smarcelgdb_fpregset_t fpregset_saved;
103130803Smarcel#endif
104130803Smarcel
105130803Smarcel/* The maximum number of tasks known to the Ada runtime */
106130803Smarcelconst int MAX_NUMBER_OF_KNOWN_TASKS = 1000;
107130803Smarcel
108130803Smarcel/* the current task */
109130803Smarcelint current_task = -1, current_task_id = -1, current_task_index;
110130803Smarcelvoid *current_thread, *current_lwp;
111130803Smarcel
112130803Smarcelchar *ada_task_states[] = {
113130803Smarcel  "Unactivated",
114130803Smarcel  "Runnable",
115130803Smarcel  "Terminated",
116130803Smarcel  "Child Activation Wait",
117130803Smarcel  "Accept Statement",
118130803Smarcel  "Waiting on entry call",
119130803Smarcel  "Async Select Wait",
120130803Smarcel  "Delay Sleep",
121130803Smarcel  "Child Termination Wait",
122130803Smarcel  "Wait Child in Term Alt",
123130803Smarcel  "",
124130803Smarcel  "",
125130803Smarcel  "",
126130803Smarcel  "",
127130803Smarcel  "Asynchronous Hold"
128130803Smarcel};
129130803Smarcel
130130803Smarcel/* Global internal types */
131130803Smarcel
132130803Smarcelstatic char *ada_long_task_states[] = {
133130803Smarcel  "Unactivated",
134130803Smarcel  "Runnable",
135130803Smarcel  "Terminated",
136130803Smarcel  "Waiting for child activation",
137130803Smarcel  "Blocked in accept statement",
138130803Smarcel  "Waiting on entry call",
139130803Smarcel  "Asynchronous Selective Wait",
140130803Smarcel  "Delay Sleep",
141130803Smarcel  "Waiting for children termination",
142130803Smarcel  "Waiting for children in terminate alternative",
143130803Smarcel  "",
144130803Smarcel  "",
145130803Smarcel  "",
146130803Smarcel  "",
147130803Smarcel  "Asynchronous Hold"
148130803Smarcel};
149130803Smarcel
150130803Smarcel/* Global internal variables */
151130803Smarcel
152130803Smarcelstatic int highest_task_num = 0;
153130803Smarcelint thread_support = 0;		/* 1 if the thread library in use is supported */
154130803Smarcelstatic int gdbtk_task_initialization = 0;
155130803Smarcel
156130803Smarcelstatic int
157130803Smarceladd_task_entry (void *p_task_id, int index)
158130803Smarcel{
159130803Smarcel  struct task_entry *new_task_entry = NULL;
160130803Smarcel  struct task_entry *pt;
161130803Smarcel
162130803Smarcel  highest_task_num++;
163130803Smarcel  new_task_entry = xmalloc (sizeof (struct task_entry));
164130803Smarcel  new_task_entry->task_num = highest_task_num;
165130803Smarcel  new_task_entry->task_id = p_task_id;
166130803Smarcel  new_task_entry->known_tasks_index = index;
167130803Smarcel  new_task_entry->next_task = NULL;
168130803Smarcel  pt = task_list;
169130803Smarcel  if (pt)
170130803Smarcel    {
171130803Smarcel      while (pt->next_task)
172130803Smarcel	pt = pt->next_task;
173130803Smarcel      pt->next_task = new_task_entry;
174130803Smarcel      pt->stack_per = 0;
175130803Smarcel    }
176130803Smarcel  else
177130803Smarcel    task_list = new_task_entry;
178130803Smarcel  return new_task_entry->task_num;
179130803Smarcel}
180130803Smarcel
181130803Smarcelint
182130803Smarcelget_entry_number (void *p_task_id)
183130803Smarcel{
184130803Smarcel  struct task_entry *pt;
185130803Smarcel
186130803Smarcel  pt = task_list;
187130803Smarcel  while (pt != NULL)
188130803Smarcel    {
189130803Smarcel      if (pt->task_id == p_task_id)
190130803Smarcel	return pt->task_num;
191130803Smarcel      pt = pt->next_task;
192130803Smarcel    }
193130803Smarcel  return 0;
194130803Smarcel}
195130803Smarcel
196130803Smarcelstatic struct task_entry *
197130803Smarcelget_thread_entry_vptr (void *thread)
198130803Smarcel{
199130803Smarcel  struct task_entry *pt;
200130803Smarcel
201130803Smarcel  pt = task_list;
202130803Smarcel  while (pt != NULL)
203130803Smarcel    {
204130803Smarcel      if (pt->thread == thread)
205130803Smarcel	return pt;
206130803Smarcel      pt = pt->next_task;
207130803Smarcel    }
208130803Smarcel  return 0;
209130803Smarcel}
210130803Smarcel
211130803Smarcelstatic struct task_entry *
212130803Smarcelget_entry_vptr (int p_task_num)
213130803Smarcel{
214130803Smarcel  struct task_entry *pt;
215130803Smarcel
216130803Smarcel  pt = task_list;
217130803Smarcel  while (pt)
218130803Smarcel    {
219130803Smarcel      if (pt->task_num == p_task_num)
220130803Smarcel	return pt;
221130803Smarcel      pt = pt->next_task;
222130803Smarcel    }
223130803Smarcel  return NULL;
224130803Smarcel}
225130803Smarcel
226130803Smarcelvoid
227130803Smarcelinit_task_list (void)
228130803Smarcel{
229130803Smarcel  struct task_entry *pt, *old_pt;
230130803Smarcel
231130803Smarcel  pt = task_list;
232130803Smarcel  while (pt)
233130803Smarcel    {
234130803Smarcel      old_pt = pt;
235130803Smarcel      pt = pt->next_task;
236130803Smarcel      xfree (old_pt);
237130803Smarcel    };
238130803Smarcel  task_list = NULL;
239130803Smarcel  highest_task_num = 0;
240130803Smarcel}
241130803Smarcel
242130803Smarcelint
243130803Smarcelvalid_task_id (int task)
244130803Smarcel{
245130803Smarcel  return get_entry_vptr (task) != NULL;
246130803Smarcel}
247130803Smarcel
248130803Smarcelvoid *
249130803Smarcelget_self_id (void)
250130803Smarcel{
251130803Smarcel  struct value *val;
252130803Smarcel  void *self_id;
253130803Smarcel  int result;
254130803Smarcel  struct task_entry *ent;
255130803Smarcel  extern int do_not_insert_breakpoints;
256130803Smarcel
257130803Smarcel#if !((defined(sun) && defined(__SVR4)) || defined(VXWORKS_TARGET) || defined(__WIN32__))
258130803Smarcel  if (thread_support)
259130803Smarcel#endif
260130803Smarcel    {
261130803Smarcel      ent = get_thread_entry_vptr (GET_CURRENT_THREAD ());
262130803Smarcel      return ent ? ent->task_id : 0;
263130803Smarcel    }
264130803Smarcel
265130803Smarcel  /* FIXME: calling a function in the inferior with a multithreaded application
266130803Smarcel     is not reliable, so return NULL if there is no safe way to get the current
267130803Smarcel     task */
268130803Smarcel  return NULL;
269130803Smarcel}
270130803Smarcel
271130803Smarcelint
272130803Smarcelget_current_task (void)
273130803Smarcel{
274130803Smarcel  int result;
275130803Smarcel
276130803Smarcel  /* FIXME: language_ada should be defined in defs.h */
277130803Smarcel  /*  if (current_language->la_language != language_ada) return -1; */
278130803Smarcel
279130803Smarcel  result = get_entry_number (get_self_id ());
280130803Smarcel
281130803Smarcel  /* return -1 if not found */
282130803Smarcel  return result == 0 ? -1 : result;
283130803Smarcel}
284130803Smarcel
285130803Smarcel/* Print detailed information about specified task */
286130803Smarcel
287130803Smarcelstatic void
288130803Smarcelinfo_task (char *arg, int from_tty)
289130803Smarcel{
290130803Smarcel  void *temp_task;
291130803Smarcel  struct task_entry *pt, *pt2;
292130803Smarcel  void *self_id, *caller;
293130803Smarcel  struct task_fields atcb, atcb2;
294130803Smarcel  struct entry_call call;
295130803Smarcel  int bounds[2];
296130803Smarcel  char image[256];
297130803Smarcel  int num;
298130803Smarcel
299130803Smarcel  /* FIXME: language_ada should be defined in defs.h */
300130803Smarcel  /*  if (current_language->la_language != language_ada)
301130803Smarcel     {
302130803Smarcel     printf_filtered ("The current language does not support tasks.\n");
303130803Smarcel     return;
304130803Smarcel     }
305130803Smarcel   */
306130803Smarcel  pt = get_entry_vptr (atoi (arg));
307130803Smarcel  if (pt == NULL)
308130803Smarcel    {
309130803Smarcel      printf_filtered ("Task %s not found.\n", arg);
310130803Smarcel      return;
311130803Smarcel    }
312130803Smarcel
313130803Smarcel  temp_task = pt->task_id;
314130803Smarcel
315130803Smarcel  /* read the atcb in the inferior */
316130803Smarcel  READ_MEMORY ((CORE_ADDR) temp_task, atcb);
317130803Smarcel
318130803Smarcel  /* print the Ada task id */
319130803Smarcel  printf_filtered ("Ada Task: %p\n", temp_task);
320130803Smarcel
321130803Smarcel  /* print the name of the task */
322130803Smarcel  if (atcb.image.P_ARRAY != NULL)
323130803Smarcel    {
324130803Smarcel      READ_MEMORY ((CORE_ADDR) EXTRACT_ADDRESS (atcb.image.P_BOUNDS), bounds);
325130803Smarcel      bounds[1] = EXTRACT_INT (bounds[1]);
326130803Smarcel      read_memory ((CORE_ADDR) EXTRACT_ADDRESS (atcb.image.P_ARRAY),
327130803Smarcel		   (char *) &image, bounds[1]);
328130803Smarcel      printf_filtered ("Name: %.*s\n", bounds[1], image);
329130803Smarcel    }
330130803Smarcel  else
331130803Smarcel    printf_filtered ("<no name>\n");
332130803Smarcel
333130803Smarcel  /* print the thread id */
334130803Smarcel
335130803Smarcel  if ((long) pt->thread < 65536)
336130803Smarcel    printf_filtered ("Thread: %ld\n", (long int) pt->thread);
337130803Smarcel  else
338130803Smarcel    printf_filtered ("Thread: %p\n", pt->thread);
339130803Smarcel
340130803Smarcel  if ((long) pt->lwp != 0)
341130803Smarcel    {
342130803Smarcel      if ((long) pt->lwp < 65536)
343130803Smarcel	printf_filtered ("LWP: %ld\n", (long int) pt->lwp);
344130803Smarcel      else
345130803Smarcel	printf_filtered ("LWP: %p\n", pt->lwp);
346130803Smarcel    }
347130803Smarcel
348130803Smarcel  /* print the parent gdb task id */
349130803Smarcel  num = get_entry_number (EXTRACT_ADDRESS (atcb.parent));
350130803Smarcel  if (num != 0)
351130803Smarcel    {
352130803Smarcel      printf_filtered ("Parent: %d", num);
353130803Smarcel      pt2 = get_entry_vptr (num);
354130803Smarcel      READ_MEMORY ((CORE_ADDR) pt2->task_id, atcb2);
355130803Smarcel
356130803Smarcel      /* print the name of the task */
357130803Smarcel      if (atcb2.image.P_ARRAY != NULL)
358130803Smarcel	{
359130803Smarcel	  READ_MEMORY ((CORE_ADDR) EXTRACT_ADDRESS (atcb2.image.P_BOUNDS),
360130803Smarcel		       bounds);
361130803Smarcel	  bounds[1] = EXTRACT_INT (bounds[1]);
362130803Smarcel	  read_memory ((CORE_ADDR) EXTRACT_ADDRESS (atcb2.image.P_ARRAY),
363130803Smarcel		       (char *) &image, bounds[1]);
364130803Smarcel	  printf_filtered (" (%.*s)\n", bounds[1], image);
365130803Smarcel	}
366130803Smarcel      else
367130803Smarcel	printf_filtered ("\n");
368130803Smarcel    }
369130803Smarcel  else
370130803Smarcel    printf_filtered ("No parent\n");
371130803Smarcel
372130803Smarcel  /* print the base priority of the task */
373130803Smarcel  printf_filtered ("Base Priority: %d\n", EXTRACT_INT (atcb.priority));
374130803Smarcel
375130803Smarcel  /* print the current state of the task */
376130803Smarcel
377130803Smarcel  /* check if this task is accepting a rendezvous */
378130803Smarcel  if (atcb.call == NULL)
379130803Smarcel    caller = NULL;
380130803Smarcel  else
381130803Smarcel    {
382130803Smarcel      READ_MEMORY ((CORE_ADDR) EXTRACT_ADDRESS (atcb.call), call);
383130803Smarcel      caller = EXTRACT_ADDRESS (call.self);
384130803Smarcel    }
385130803Smarcel
386130803Smarcel  if (caller != NULL)
387130803Smarcel    {
388130803Smarcel      num = get_entry_number (caller);
389130803Smarcel      printf_filtered ("Accepting rendezvous with %d", num);
390130803Smarcel
391130803Smarcel      if (num != 0)
392130803Smarcel	{
393130803Smarcel	  pt2 = get_entry_vptr (num);
394130803Smarcel	  READ_MEMORY ((CORE_ADDR) pt2->task_id, atcb2);
395130803Smarcel
396130803Smarcel	  /* print the name of the task */
397130803Smarcel	  if (atcb2.image.P_ARRAY != NULL)
398130803Smarcel	    {
399130803Smarcel	      READ_MEMORY ((CORE_ADDR) EXTRACT_ADDRESS (atcb2.image.P_BOUNDS),
400130803Smarcel			   bounds);
401130803Smarcel	      bounds[1] = EXTRACT_INT (bounds[1]);
402130803Smarcel	      read_memory ((CORE_ADDR) EXTRACT_ADDRESS (atcb2.image.P_ARRAY),
403130803Smarcel			   (char *) &image, bounds[1]);
404130803Smarcel	      printf_filtered (" (%.*s)\n", bounds[1], image);
405130803Smarcel	    }
406130803Smarcel	  else
407130803Smarcel	    printf_filtered ("\n");
408130803Smarcel	}
409130803Smarcel      else
410130803Smarcel	printf_filtered ("\n");
411130803Smarcel    }
412130803Smarcel  else
413130803Smarcel    printf_filtered ("State: %s\n", ada_long_task_states[atcb.state]);
414130803Smarcel}
415130803Smarcel
416130803Smarcel#if 0
417130803Smarcel
418130803Smarcel/* A useful function that shows the alignment of all the fields in the
419130803Smarcel   tasks_fields structure
420130803Smarcel */
421130803Smarcel
422130803Smarcelprint_align (void)
423130803Smarcel{
424130803Smarcel  struct task_fields tf;
425130803Smarcel  void *tf_base = &(tf);
426130803Smarcel  void *tf_state = &(tf.state);
427130803Smarcel  void *tf_entry_num = &(tf.entry_num);
428130803Smarcel  void *tf_parent = &(tf.parent);
429130803Smarcel  void *tf_priority = &(tf.priority);
430130803Smarcel  void *tf_current_priority = &(tf.current_priority);
431130803Smarcel  void *tf_image = &(tf.image);
432130803Smarcel  void *tf_call = &(tf.call);
433130803Smarcel  void *tf_thread = &(tf.thread);
434130803Smarcel  void *tf_lwp = &(tf.lwp);
435130803Smarcel  printf_filtered ("\n");
436130803Smarcel  printf_filtered ("(tf_base = 0x%x)\n", tf_base);
437130803Smarcel  printf_filtered ("task_fields.entry_num        at %3d (0x%x)\n",
438130803Smarcel		   tf_entry_num - tf_base, tf_entry_num);
439130803Smarcel  printf_filtered ("task_fields.state            at %3d (0x%x)\n",
440130803Smarcel		   tf_state - tf_base, tf_state);
441130803Smarcel  printf_filtered ("task_fields.parent           at %3d (0x%x)\n",
442130803Smarcel		   tf_parent - tf_base, tf_parent);
443130803Smarcel  printf_filtered ("task_fields.priority         at %3d (0x%x)\n",
444130803Smarcel		   tf_priority - tf_base, tf_priority);
445130803Smarcel  printf_filtered ("task_fields.current_priority at %3d (0x%x)\n",
446130803Smarcel		   tf_current_priority - tf_base, tf_current_priority);
447130803Smarcel  printf_filtered ("task_fields.image            at %3d (0x%x)\n",
448130803Smarcel		   tf_image - tf_base, tf_image);
449130803Smarcel  printf_filtered ("task_fields.call             at %3d (0x%x)\n",
450130803Smarcel		   tf_call - tf_base, tf_call);
451130803Smarcel  printf_filtered ("task_fields.thread           at %3d (0x%x)\n",
452130803Smarcel		   tf_thread - tf_base, tf_thread);
453130803Smarcel  printf_filtered ("task_fields.lwp              at %3d (0x%x)\n",
454130803Smarcel		   tf_lwp - tf_base, tf_lwp);
455130803Smarcel  printf_filtered ("\n");
456130803Smarcel}
457130803Smarcel#endif
458130803Smarcel
459130803Smarcel/* Print information about currently known tasks */
460130803Smarcel
461130803Smarcelstatic void
462130803Smarcelinfo_tasks (char *arg, int from_tty)
463130803Smarcel{
464130803Smarcel  struct value *val;
465130803Smarcel  int i, task_number, state;
466130803Smarcel  void *temp_task, *temp_tasks[MAX_NUMBER_OF_KNOWN_TASKS];
467130803Smarcel  struct task_entry *pt;
468130803Smarcel  void *self_id, *caller, *thread_id = NULL;
469130803Smarcel  struct task_fields atcb;
470130803Smarcel  struct entry_call call;
471130803Smarcel  int bounds[2];
472130803Smarcel  char image[256];
473130803Smarcel  int size;
474130803Smarcel  char car;
475130803Smarcel
476130803Smarcel#if defined(__alpha__) && defined(__osf__) && !defined(VXWORKS_TARGET)
477130803Smarcel  pthreadTeb_t thr;
478130803Smarcel  gdb_gregset_t regs;
479130803Smarcel#endif
480130803Smarcel
481130803Smarcel  static struct symbol *sym;
482130803Smarcel  static struct minimal_symbol *msym;
483130803Smarcel  static void *known_tasks_addr = NULL;
484130803Smarcel
485130803Smarcel  int init_only = gdbtk_task_initialization;
486130803Smarcel  gdbtk_task_initialization = 0;
487130803Smarcel
488130803Smarcel  task_number = 0;
489130803Smarcel
490130803Smarcel  if (PIDGET (inferior_ptid) == 0)
491130803Smarcel    {
492130803Smarcel      printf_filtered ("The program is not being run under gdb. ");
493130803Smarcel      printf_filtered ("Use 'run' or 'attach' first.\n");
494130803Smarcel      return;
495130803Smarcel    }
496130803Smarcel
497130803Smarcel  if (ada__tasks_check_symbol_table)
498130803Smarcel    {
499130803Smarcel      thread_support = 0;
500130803Smarcel#if (defined(__alpha__) && defined(__osf__) & !defined(VXWORKS_TARGET)) || \
501130803Smarcel    defined (_AIX)
502130803Smarcel      thread_support = 1;
503130803Smarcel#endif
504130803Smarcel
505130803Smarcel      msym = lookup_minimal_symbol (KNOWN_TASKS_NAME, NULL, NULL);
506130803Smarcel      if (msym != NULL)
507130803Smarcel	known_tasks_addr = (void *) SYMBOL_VALUE_ADDRESS (msym);
508130803Smarcel      else
509130803Smarcel#ifndef VXWORKS_TARGET
510130803Smarcel	return;
511130803Smarcel#else
512130803Smarcel	{
513130803Smarcel	  if (target_lookup_symbol (KNOWN_TASKS_NAME, &known_tasks_addr) != 0)
514130803Smarcel	    return;
515130803Smarcel	}
516130803Smarcel#endif
517130803Smarcel
518130803Smarcel      ada__tasks_check_symbol_table = 0;
519130803Smarcel    }
520130803Smarcel
521130803Smarcel  if (known_tasks_addr == NULL)
522130803Smarcel    return;
523130803Smarcel
524130803Smarcel#if !((defined(sun) && defined(__SVR4)) || defined(VXWORKS_TARGET) || defined(__WIN32__) || defined (hpux))
525130803Smarcel  if (thread_support)
526130803Smarcel#endif
527130803Smarcel    thread_id = GET_CURRENT_THREAD ();
528130803Smarcel
529130803Smarcel  /* then we get a list of tasks created */
530130803Smarcel
531130803Smarcel  init_task_list ();
532130803Smarcel
533130803Smarcel  READ_MEMORY ((CORE_ADDR) known_tasks_addr, temp_tasks);
534130803Smarcel
535130803Smarcel  for (i = 0; i < MAX_NUMBER_OF_KNOWN_TASKS; i++)
536130803Smarcel    {
537130803Smarcel      temp_task = EXTRACT_ADDRESS (temp_tasks[i]);
538130803Smarcel
539130803Smarcel      if (temp_task != NULL)
540130803Smarcel	{
541130803Smarcel	  task_number = get_entry_number (temp_task);
542130803Smarcel	  if (task_number == 0)
543130803Smarcel	    task_number = add_task_entry (temp_task, i);
544130803Smarcel	}
545130803Smarcel    }
546130803Smarcel
547130803Smarcel  /* Return without printing anything if this function was called in
548130803Smarcel     order to init GDBTK tasking. */
549130803Smarcel
550130803Smarcel  if (init_only)
551130803Smarcel    return;
552130803Smarcel
553130803Smarcel  /* print the header */
554130803Smarcel
555130803Smarcel#if defined(__alpha__) && defined(__osf__) && !defined(VXWORKS_TARGET)
556130803Smarcel  printf_filtered
557130803Smarcel    ("  ID       TID P-ID Pri Stack  %% State                  Name\n");
558130803Smarcel#else
559130803Smarcel  printf_filtered ("  ID       TID P-ID Pri State                  Name\n");
560130803Smarcel#endif
561130803Smarcel
562130803Smarcel  /* Now that we have a list of task id's, we can print them */
563130803Smarcel  pt = task_list;
564130803Smarcel  while (pt)
565130803Smarcel    {
566130803Smarcel      temp_task = pt->task_id;
567130803Smarcel
568130803Smarcel      /* read the atcb in the inferior */
569130803Smarcel      READ_MEMORY ((CORE_ADDR) temp_task, atcb);
570130803Smarcel
571130803Smarcel      /* store the thread id for future use */
572130803Smarcel      pt->thread = EXTRACT_ADDRESS (atcb.thread);
573130803Smarcel
574130803Smarcel#if defined (linux)
575130803Smarcel      pt->lwp = (void *) THREAD_TO_PID (atcb.thread, 0);
576130803Smarcel#else
577130803Smarcel      pt->lwp = EXTRACT_ADDRESS (atcb.lwp);
578130803Smarcel#endif
579130803Smarcel
580130803Smarcel      /* print a star if this task is the current one */
581130803Smarcel      if (thread_id)
582130803Smarcel#if defined (__WIN32__) || defined (SGI) || defined (hpux)
583130803Smarcel	printf_filtered (pt->lwp == thread_id ? "*" : " ");
584130803Smarcel#else
585130803Smarcel	printf_filtered (pt->thread == thread_id ? "*" : " ");
586130803Smarcel#endif
587130803Smarcel
588130803Smarcel      /* print the gdb task id */
589130803Smarcel      printf_filtered ("%3d", pt->task_num);
590130803Smarcel
591130803Smarcel      /* print the Ada task id */
592130803Smarcel#ifndef VXWORKS_TARGET
593130803Smarcel      printf_filtered (" %9lx", (long) temp_task);
594130803Smarcel#else
595130803Smarcel#ifdef TARGET_64
596130803Smarcel      printf_filtered (" %#9lx", (unsigned long) pt->thread & 0x3ffffffffff);
597130803Smarcel#else
598130803Smarcel      printf_filtered (" %#9lx", (long) pt->thread);
599130803Smarcel#endif
600130803Smarcel#endif
601130803Smarcel
602130803Smarcel      /* print the parent gdb task id */
603130803Smarcel      printf_filtered
604130803Smarcel	(" %4d", get_entry_number (EXTRACT_ADDRESS (atcb.parent)));
605130803Smarcel
606130803Smarcel      /* print the base priority of the task */
607130803Smarcel      printf_filtered (" %3d", EXTRACT_INT (atcb.priority));
608130803Smarcel
609130803Smarcel#if defined(__alpha__) && defined(__osf__) && !defined(VXWORKS_TARGET)
610130803Smarcel      if (pt->task_num == 1 || atcb.state == Terminated)
611130803Smarcel	{
612130803Smarcel	  printf_filtered ("  Unknown");
613130803Smarcel	  goto next;
614130803Smarcel	}
615130803Smarcel
616130803Smarcel      read_memory ((CORE_ADDR) atcb.thread, &thr, sizeof (thr));
617130803Smarcel      current_thread = atcb.thread;
618130803Smarcel      regs.regs[SP_REGNUM] = 0;
619130803Smarcel      if (dec_thread_get_registers (&regs, NULL) == 0)
620130803Smarcel	{
621130803Smarcel	  pt->stack_per = (100 * ((long) thr.__stack_base -
622130803Smarcel				  regs.regs[SP_REGNUM])) / thr.__stack_size;
623130803Smarcel	  /* if the thread is terminated but still there, the
624130803Smarcel	     stack_base/size values are erroneous. Try to patch it */
625130803Smarcel	  if (pt->stack_per < 0 || pt->stack_per > 100)
626130803Smarcel	    pt->stack_per = 0;
627130803Smarcel	}
628130803Smarcel
629130803Smarcel      /* print information about stack space used in the thread */
630130803Smarcel      if (thr.__stack_size < 1024 * 1024)
631130803Smarcel	{
632130803Smarcel	  size = thr.__stack_size / 1024;
633130803Smarcel	  car = 'K';
634130803Smarcel	}
635130803Smarcel      else if (thr.__stack_size < 1024 * 1024 * 1024)
636130803Smarcel	{
637130803Smarcel	  size = thr.__stack_size / 1024 / 1024;
638130803Smarcel	  car = 'M';
639130803Smarcel	}
640130803Smarcel      else			/* Who knows... */
641130803Smarcel	{
642130803Smarcel	  size = thr.__stack_size / 1024 / 1024 / 1024;
643130803Smarcel	  car = 'G';
644130803Smarcel	}
645130803Smarcel      printf_filtered (" %4d%c %2d", size, car, pt->stack_per);
646130803Smarcel    next:
647130803Smarcel#endif
648130803Smarcel
649130803Smarcel      /* print the current state of the task */
650130803Smarcel
651130803Smarcel      /* check if this task is accepting a rendezvous */
652130803Smarcel      if (atcb.call == NULL)
653130803Smarcel	caller = NULL;
654130803Smarcel      else
655130803Smarcel	{
656130803Smarcel	  READ_MEMORY ((CORE_ADDR) EXTRACT_ADDRESS (atcb.call), call);
657130803Smarcel	  caller = EXTRACT_ADDRESS (call.self);
658130803Smarcel	}
659130803Smarcel
660130803Smarcel      if (caller != NULL)
661130803Smarcel	printf_filtered (" Accepting RV with %-4d",
662130803Smarcel			 get_entry_number (caller));
663130803Smarcel      else
664130803Smarcel	{
665130803Smarcel	  state = atcb.state;
666130803Smarcel#if defined (__WIN32__) || defined (SGI) || defined (hpux)
667130803Smarcel	  if (state == Runnable && (thread_id && pt->lwp == thread_id))
668130803Smarcel#else
669130803Smarcel	  if (state == Runnable && (thread_id && pt->thread == thread_id))
670130803Smarcel#endif
671130803Smarcel	    /* Replace "Runnable" by "Running" if this is the current task */
672130803Smarcel	    printf_filtered (" %-22s", "Running");
673130803Smarcel	  else
674130803Smarcel	    printf_filtered (" %-22s", ada_task_states[state]);
675130803Smarcel	}
676130803Smarcel
677130803Smarcel      /* finally, print the name of the task */
678130803Smarcel      if (atcb.image.P_ARRAY != NULL)
679130803Smarcel	{
680130803Smarcel	  READ_MEMORY ((CORE_ADDR) EXTRACT_ADDRESS (atcb.image.P_BOUNDS),
681130803Smarcel		       bounds);
682130803Smarcel	  bounds[1] = EXTRACT_INT (bounds[1]);
683130803Smarcel	  read_memory ((CORE_ADDR) EXTRACT_ADDRESS (atcb.image.P_ARRAY),
684130803Smarcel		       (char *) &image, bounds[1]);
685130803Smarcel	  printf_filtered (" %.*s\n", bounds[1], image);
686130803Smarcel	}
687130803Smarcel      else
688130803Smarcel	printf_filtered (" <no name>\n");
689130803Smarcel
690130803Smarcel      pt = pt->next_task;
691130803Smarcel    }
692130803Smarcel}
693130803Smarcel
694130803Smarcel/* Task list initialization for GDB-Tk.  We basically use info_tasks()
695130803Smarcel   to initialize our variables, but abort that function before we
696130803Smarcel   actually print anything. */
697130803Smarcel
698130803Smarcelint
699130803Smarcelgdbtk_tcl_tasks_initialize (void)
700130803Smarcel{
701130803Smarcel  gdbtk_task_initialization = 1;
702130803Smarcel  info_tasks ("", gdb_stdout);
703130803Smarcel
704130803Smarcel  return (task_list != NULL);
705130803Smarcel}
706130803Smarcel
707130803Smarcelstatic void
708130803Smarcelinfo_tasks_command (char *arg, int from_tty)
709130803Smarcel{
710130803Smarcel  if (arg == NULL || *arg == '\000')
711130803Smarcel    info_tasks (arg, from_tty);
712130803Smarcel  else
713130803Smarcel    info_task (arg, from_tty);
714130803Smarcel}
715130803Smarcel
716130803Smarcel/* Switch from one thread to another. */
717130803Smarcel
718130803Smarcelstatic void
719130803Smarcelswitch_to_thread (ptid_t ptid)
720130803Smarcel{
721130803Smarcel  if (ptid_equal (ptid, inferior_ptid))
722130803Smarcel    return;
723130803Smarcel
724130803Smarcel  inferior_ptid = ptid;
725130803Smarcel  flush_cached_frames ();
726130803Smarcel  registers_changed ();
727130803Smarcel  stop_pc = read_pc ();
728130803Smarcel  select_frame (get_current_frame ());
729130803Smarcel}
730130803Smarcel
731130803Smarcel/* Switch to a specified task. */
732130803Smarcel
733130803Smarcelstatic int
734130803Smarceltask_switch (void *tid, void *lwpid)
735130803Smarcel{
736130803Smarcel  int res = 0, pid;
737130803Smarcel
738130803Smarcel  if (thread_support)
739130803Smarcel    {
740130803Smarcel      flush_cached_frames ();
741130803Smarcel
742130803Smarcel      if (current_task != current_task_id)
743130803Smarcel	{
744130803Smarcel	  res = THREAD_FETCH_REGISTERS ();
745130803Smarcel	}
746130803Smarcel      else
747130803Smarcel	{
748130803Smarcel#if (defined(__alpha__) && defined(__osf__) && !defined(VXWORKS_TARGET))
749130803Smarcel	  supply_gregset (&gregset_saved);
750130803Smarcel	  supply_fpregset (&fpregset_saved);
751130803Smarcel#endif
752130803Smarcel	}
753130803Smarcel
754130803Smarcel      if (res == 0)
755130803Smarcel	stop_pc = read_pc ();
756130803Smarcel      select_frame (get_current_frame ());
757130803Smarcel      return res;
758130803Smarcel    }
759130803Smarcel
760130803Smarcel  return -1;
761130803Smarcel}
762130803Smarcel
763130803Smarcelstatic void
764130803Smarceltask_command (char *tidstr, int from_tty)
765130803Smarcel{
766130803Smarcel  int num;
767130803Smarcel  struct task_entry *e;
768130803Smarcel
769130803Smarcel  if (!tidstr)
770130803Smarcel    error ("Please specify a task ID.  Use the \"info tasks\" command to\n"
771130803Smarcel	   "see the IDs of currently known tasks.");
772130803Smarcel
773130803Smarcel  num = atoi (tidstr);
774130803Smarcel  e = get_entry_vptr (num);
775130803Smarcel
776130803Smarcel  if (e == NULL)
777130803Smarcel    error ("Task ID %d not known.  Use the \"info tasks\" command to\n"
778130803Smarcel	   "see the IDs of currently known tasks.", num);
779130803Smarcel
780130803Smarcel  if (current_task_id == -1)
781130803Smarcel    {
782130803Smarcel#if (defined(__alpha__) && defined(__osf__) && !defined(VXWORKS_TARGET))
783130803Smarcel      fill_gregset (&gregset_saved, -1);
784130803Smarcel      fill_fpregset (&fpregset_saved, -1);
785130803Smarcel#endif
786130803Smarcel      current_task_id = get_current_task ();
787130803Smarcel    }
788130803Smarcel
789130803Smarcel  current_task = num;
790130803Smarcel  current_task_index = e->known_tasks_index;
791130803Smarcel  current_thread = e->thread;
792130803Smarcel  current_lwp = e->lwp;
793130803Smarcel  if (task_switch (e->thread, e->lwp) == 0)
794130803Smarcel    {
795130803Smarcel      /* FIXME: find_printable_frame should be defined in frame.h, and
796130803Smarcel         implemented in ada-lang.c */
797130803Smarcel      /*      find_printable_frame (deprecated_selected_frame, frame_relative_level (deprecated_selected_frame)); */
798130803Smarcel      printf_filtered ("[Switching to task %d]\n", num);
799130803Smarcel      print_stack_frame (deprecated_selected_frame,
800130803Smarcel			 frame_relative_level (deprecated_selected_frame), 1);
801130803Smarcel    }
802130803Smarcel  else
803130803Smarcel    printf_filtered ("Unable to switch to task %d\n", num);
804130803Smarcel}
805130803Smarcel
806130803Smarcelvoid
807130803Smarcel_initialize_tasks (void)
808130803Smarcel{
809130803Smarcel  static struct cmd_list_element *task_cmd_list = NULL;
810130803Smarcel  extern struct cmd_list_element *cmdlist;
811130803Smarcel
812130803Smarcel  add_info ("tasks", info_tasks_command,
813130803Smarcel	    "Without argument: list all known Ada tasks, with status information.\n"
814130803Smarcel	    "info tasks n: print detailed information of task n.\n");
815130803Smarcel
816130803Smarcel  add_prefix_cmd ("task", class_run, task_command,
817130803Smarcel		  "Use this command to switch between tasks.\n\
818130803Smarcel The new task ID must be currently known.", &task_cmd_list, "task ", 1, &cmdlist);
819130803Smarcel}
820