xref: /dflybsd-src/contrib/gdb-7/gdb/ada-tasks.c (revision de8e141f24382815c10a4012d209bbbf7abf1112)
1*ef5ccd6cSJohn Marino /* Copyright (C) 1992-2013 Free Software Foundation, Inc.
25796c8dcSSimon Schubert 
35796c8dcSSimon Schubert    This file is part of GDB.
45796c8dcSSimon Schubert 
55796c8dcSSimon Schubert    This program is free software; you can redistribute it and/or modify
65796c8dcSSimon Schubert    it under the terms of the GNU General Public License as published by
75796c8dcSSimon Schubert    the Free Software Foundation; either version 3 of the License, or
85796c8dcSSimon Schubert    (at your option) any later version.
95796c8dcSSimon Schubert 
105796c8dcSSimon Schubert    This program is distributed in the hope that it will be useful,
115796c8dcSSimon Schubert    but WITHOUT ANY WARRANTY; without even the implied warranty of
125796c8dcSSimon Schubert    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
135796c8dcSSimon Schubert    GNU General Public License for more details.
145796c8dcSSimon Schubert 
155796c8dcSSimon Schubert    You should have received a copy of the GNU General Public License
165796c8dcSSimon Schubert    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
175796c8dcSSimon Schubert 
185796c8dcSSimon Schubert #include "defs.h"
195796c8dcSSimon Schubert #include "observer.h"
205796c8dcSSimon Schubert #include "gdbcmd.h"
215796c8dcSSimon Schubert #include "target.h"
225796c8dcSSimon Schubert #include "ada-lang.h"
235796c8dcSSimon Schubert #include "gdbcore.h"
245796c8dcSSimon Schubert #include "inferior.h"
255796c8dcSSimon Schubert #include "gdbthread.h"
26a45ae5f8SJohn Marino #include "progspace.h"
27a45ae5f8SJohn Marino #include "objfiles.h"
285796c8dcSSimon Schubert 
295796c8dcSSimon Schubert /* The name of the array in the GNAT runtime where the Ada Task Control
305796c8dcSSimon Schubert    Block of each task is stored.  */
315796c8dcSSimon Schubert #define KNOWN_TASKS_NAME "system__tasking__debug__known_tasks"
325796c8dcSSimon Schubert 
33c50c785cSJohn Marino /* The maximum number of tasks known to the Ada runtime.  */
345796c8dcSSimon Schubert static const int MAX_NUMBER_OF_KNOWN_TASKS = 1000;
355796c8dcSSimon Schubert 
36a45ae5f8SJohn Marino /* The name of the variable in the GNAT runtime where the head of a task
37a45ae5f8SJohn Marino    chain is saved.  This is an alternate mechanism to find the list of known
38a45ae5f8SJohn Marino    tasks.  */
39a45ae5f8SJohn Marino #define KNOWN_TASKS_LIST "system__tasking__debug__first_task"
40a45ae5f8SJohn Marino 
415796c8dcSSimon Schubert enum task_states
425796c8dcSSimon Schubert {
435796c8dcSSimon Schubert   Unactivated,
445796c8dcSSimon Schubert   Runnable,
455796c8dcSSimon Schubert   Terminated,
465796c8dcSSimon Schubert   Activator_Sleep,
475796c8dcSSimon Schubert   Acceptor_Sleep,
485796c8dcSSimon Schubert   Entry_Caller_Sleep,
495796c8dcSSimon Schubert   Async_Select_Sleep,
505796c8dcSSimon Schubert   Delay_Sleep,
515796c8dcSSimon Schubert   Master_Completion_Sleep,
525796c8dcSSimon Schubert   Master_Phase_2_Sleep,
535796c8dcSSimon Schubert   Interrupt_Server_Idle_Sleep,
545796c8dcSSimon Schubert   Interrupt_Server_Blocked_Interrupt_Sleep,
555796c8dcSSimon Schubert   Timer_Server_Sleep,
565796c8dcSSimon Schubert   AST_Server_Sleep,
575796c8dcSSimon Schubert   Asynchronous_Hold,
585796c8dcSSimon Schubert   Interrupt_Server_Blocked_On_Event_Flag,
595796c8dcSSimon Schubert   Activating,
605796c8dcSSimon Schubert   Acceptor_Delay_Sleep
615796c8dcSSimon Schubert };
625796c8dcSSimon Schubert 
635796c8dcSSimon Schubert /* A short description corresponding to each possible task state.  */
645796c8dcSSimon Schubert static const char *task_states[] = {
655796c8dcSSimon Schubert   N_("Unactivated"),
665796c8dcSSimon Schubert   N_("Runnable"),
675796c8dcSSimon Schubert   N_("Terminated"),
685796c8dcSSimon Schubert   N_("Child Activation Wait"),
695796c8dcSSimon Schubert   N_("Accept or Select Term"),
705796c8dcSSimon Schubert   N_("Waiting on entry call"),
715796c8dcSSimon Schubert   N_("Async Select Wait"),
725796c8dcSSimon Schubert   N_("Delay Sleep"),
735796c8dcSSimon Schubert   N_("Child Termination Wait"),
745796c8dcSSimon Schubert   N_("Wait Child in Term Alt"),
755796c8dcSSimon Schubert   "",
765796c8dcSSimon Schubert   "",
775796c8dcSSimon Schubert   "",
785796c8dcSSimon Schubert   "",
795796c8dcSSimon Schubert   N_("Asynchronous Hold"),
805796c8dcSSimon Schubert   "",
815796c8dcSSimon Schubert   N_("Activating"),
825796c8dcSSimon Schubert   N_("Selective Wait")
835796c8dcSSimon Schubert };
845796c8dcSSimon Schubert 
855796c8dcSSimon Schubert /* A longer description corresponding to each possible task state.  */
865796c8dcSSimon Schubert static const char *long_task_states[] = {
875796c8dcSSimon Schubert   N_("Unactivated"),
885796c8dcSSimon Schubert   N_("Runnable"),
895796c8dcSSimon Schubert   N_("Terminated"),
905796c8dcSSimon Schubert   N_("Waiting for child activation"),
915796c8dcSSimon Schubert   N_("Blocked in accept or select with terminate"),
925796c8dcSSimon Schubert   N_("Waiting on entry call"),
935796c8dcSSimon Schubert   N_("Asynchronous Selective Wait"),
945796c8dcSSimon Schubert   N_("Delay Sleep"),
955796c8dcSSimon Schubert   N_("Waiting for children termination"),
965796c8dcSSimon Schubert   N_("Waiting for children in terminate alternative"),
975796c8dcSSimon Schubert   "",
985796c8dcSSimon Schubert   "",
995796c8dcSSimon Schubert   "",
1005796c8dcSSimon Schubert   "",
1015796c8dcSSimon Schubert   N_("Asynchronous Hold"),
1025796c8dcSSimon Schubert   "",
1035796c8dcSSimon Schubert   N_("Activating"),
1045796c8dcSSimon Schubert   N_("Blocked in selective wait statement")
1055796c8dcSSimon Schubert };
1065796c8dcSSimon Schubert 
1075796c8dcSSimon Schubert /* The index of certain important fields in the Ada Task Control Block
1085796c8dcSSimon Schubert    record and sub-records.  */
1095796c8dcSSimon Schubert 
110a45ae5f8SJohn Marino struct atcb_fieldnos
1115796c8dcSSimon Schubert {
1125796c8dcSSimon Schubert   /* Fields in record Ada_Task_Control_Block.  */
1135796c8dcSSimon Schubert   int common;
1145796c8dcSSimon Schubert   int entry_calls;
1155796c8dcSSimon Schubert   int atc_nesting_level;
1165796c8dcSSimon Schubert 
1175796c8dcSSimon Schubert   /* Fields in record Common_ATCB.  */
1185796c8dcSSimon Schubert   int state;
1195796c8dcSSimon Schubert   int parent;
1205796c8dcSSimon Schubert   int priority;
1215796c8dcSSimon Schubert   int image;
1225796c8dcSSimon Schubert   int image_len;     /* This field may be missing.  */
123a45ae5f8SJohn Marino   int activation_link;
1245796c8dcSSimon Schubert   int call;
1255796c8dcSSimon Schubert   int ll;
1265796c8dcSSimon Schubert 
1275796c8dcSSimon Schubert   /* Fields in Task_Primitives.Private_Data.  */
1285796c8dcSSimon Schubert   int ll_thread;
1295796c8dcSSimon Schubert   int ll_lwp;        /* This field may be missing.  */
1305796c8dcSSimon Schubert 
1315796c8dcSSimon Schubert   /* Fields in Common_ATCB.Call.all.  */
1325796c8dcSSimon Schubert   int call_self;
1335796c8dcSSimon Schubert };
1345796c8dcSSimon Schubert 
135a45ae5f8SJohn Marino /* This module's per-program-space data.  */
1365796c8dcSSimon Schubert 
137a45ae5f8SJohn Marino struct ada_tasks_pspace_data
138a45ae5f8SJohn Marino {
139a45ae5f8SJohn Marino   /* Nonzero if the data has been initialized.  If set to zero,
140a45ae5f8SJohn Marino      it means that the data has either not been initialized, or
141a45ae5f8SJohn Marino      has potentially become stale.  */
142a45ae5f8SJohn Marino   int initialized_p;
1435796c8dcSSimon Schubert 
144a45ae5f8SJohn Marino   /* The ATCB record type.  */
145a45ae5f8SJohn Marino   struct type *atcb_type;
146a45ae5f8SJohn Marino 
147a45ae5f8SJohn Marino   /* The ATCB "Common" component type.  */
148a45ae5f8SJohn Marino   struct type *atcb_common_type;
149a45ae5f8SJohn Marino 
150a45ae5f8SJohn Marino   /* The type of the "ll" field, from the atcb_common_type.  */
151a45ae5f8SJohn Marino   struct type *atcb_ll_type;
152a45ae5f8SJohn Marino 
153a45ae5f8SJohn Marino   /* The type of the "call" field, from the atcb_common_type.  */
154a45ae5f8SJohn Marino   struct type *atcb_call_type;
155a45ae5f8SJohn Marino 
156a45ae5f8SJohn Marino   /* The index of various fields in the ATCB record and sub-records.  */
157a45ae5f8SJohn Marino   struct atcb_fieldnos atcb_fieldno;
158a45ae5f8SJohn Marino };
159a45ae5f8SJohn Marino 
160a45ae5f8SJohn Marino /* Key to our per-program-space data.  */
161a45ae5f8SJohn Marino static const struct program_space_data *ada_tasks_pspace_data_handle;
162a45ae5f8SJohn Marino 
163a45ae5f8SJohn Marino typedef struct ada_task_info ada_task_info_s;
164a45ae5f8SJohn Marino DEF_VEC_O(ada_task_info_s);
165a45ae5f8SJohn Marino 
166a45ae5f8SJohn Marino /* The kind of data structure used by the runtime to store the list
167a45ae5f8SJohn Marino    of Ada tasks.  */
168a45ae5f8SJohn Marino 
169a45ae5f8SJohn Marino enum ada_known_tasks_kind
170a45ae5f8SJohn Marino {
171a45ae5f8SJohn Marino   /* Use this value when we haven't determined which kind of structure
172a45ae5f8SJohn Marino      is being used, or when we need to recompute it.
173a45ae5f8SJohn Marino 
174a45ae5f8SJohn Marino      We set the value of this enumerate to zero on purpose: This allows
175a45ae5f8SJohn Marino      us to use this enumerate in a structure where setting all fields
176a45ae5f8SJohn Marino      to zero will result in this kind being set to unknown.  */
177a45ae5f8SJohn Marino   ADA_TASKS_UNKNOWN = 0,
178a45ae5f8SJohn Marino 
179a45ae5f8SJohn Marino   /* This value means that we did not find any task list.  Unless
180a45ae5f8SJohn Marino      there is a bug somewhere, this means that the inferior does not
181a45ae5f8SJohn Marino      use tasking.  */
182a45ae5f8SJohn Marino   ADA_TASKS_NOT_FOUND,
183a45ae5f8SJohn Marino 
184a45ae5f8SJohn Marino   /* This value means that the task list is stored as an array.
185a45ae5f8SJohn Marino      This is the usual method, as it causes very little overhead.
186a45ae5f8SJohn Marino      But this method is not always used, as it does use a certain
187a45ae5f8SJohn Marino      amount of memory, which might be scarse in certain environments.  */
188a45ae5f8SJohn Marino   ADA_TASKS_ARRAY,
189a45ae5f8SJohn Marino 
190a45ae5f8SJohn Marino   /* This value means that the task list is stored as a linked list.
191a45ae5f8SJohn Marino      This has more runtime overhead than the array approach, but
192a45ae5f8SJohn Marino      also require less memory when the number of tasks is small.  */
193a45ae5f8SJohn Marino   ADA_TASKS_LIST,
194a45ae5f8SJohn Marino };
195a45ae5f8SJohn Marino 
196a45ae5f8SJohn Marino /* This module's per-inferior data.  */
197a45ae5f8SJohn Marino 
198a45ae5f8SJohn Marino struct ada_tasks_inferior_data
199a45ae5f8SJohn Marino {
200a45ae5f8SJohn Marino   /* The type of data structure used by the runtime to store
201a45ae5f8SJohn Marino      the list of Ada tasks.  The value of this field influences
202a45ae5f8SJohn Marino      the interpretation of the known_tasks_addr field below:
203a45ae5f8SJohn Marino        - ADA_TASKS_UNKNOWN: The value of known_tasks_addr hasn't
204a45ae5f8SJohn Marino          been determined yet;
205a45ae5f8SJohn Marino        - ADA_TASKS_NOT_FOUND: The program probably does not use tasking
206a45ae5f8SJohn Marino          and the known_tasks_addr is irrelevant;
207a45ae5f8SJohn Marino        - ADA_TASKS_ARRAY: The known_tasks is an array;
208a45ae5f8SJohn Marino        - ADA_TASKS_LIST: The known_tasks is a list.  */
209a45ae5f8SJohn Marino   enum ada_known_tasks_kind known_tasks_kind;
210a45ae5f8SJohn Marino 
211a45ae5f8SJohn Marino   /* The address of the known_tasks structure.  This is where
212a45ae5f8SJohn Marino      the runtime stores the information for all Ada tasks.
213a45ae5f8SJohn Marino      The interpretation of this field depends on KNOWN_TASKS_KIND
214a45ae5f8SJohn Marino      above.  */
215a45ae5f8SJohn Marino   CORE_ADDR known_tasks_addr;
216a45ae5f8SJohn Marino 
217*ef5ccd6cSJohn Marino   /* Type of elements of the known task.  Usually a pointer.  */
218*ef5ccd6cSJohn Marino   struct type *known_tasks_element;
219*ef5ccd6cSJohn Marino 
220*ef5ccd6cSJohn Marino   /* Number of elements in the known tasks array.  */
221*ef5ccd6cSJohn Marino   unsigned int known_tasks_length;
222*ef5ccd6cSJohn Marino 
223a45ae5f8SJohn Marino   /* When nonzero, this flag indicates that the task_list field
224a45ae5f8SJohn Marino      below is up to date.  When set to zero, the list has either
225a45ae5f8SJohn Marino      not been initialized, or has potentially become stale.  */
226a45ae5f8SJohn Marino   int task_list_valid_p;
2275796c8dcSSimon Schubert 
2285796c8dcSSimon Schubert   /* The list of Ada tasks.
2295796c8dcSSimon Schubert 
2305796c8dcSSimon Schubert      Note: To each task we associate a number that the user can use to
2315796c8dcSSimon Schubert      reference it - this number is printed beside each task in the tasks
2325796c8dcSSimon Schubert      info listing displayed by "info tasks".  This number is equal to
2335796c8dcSSimon Schubert      its index in the vector + 1.  Reciprocally, to compute the index
2345796c8dcSSimon Schubert      of a task in the vector, we need to substract 1 from its number.  */
235a45ae5f8SJohn Marino   VEC(ada_task_info_s) *task_list;
236a45ae5f8SJohn Marino };
2375796c8dcSSimon Schubert 
238a45ae5f8SJohn Marino /* Key to our per-inferior data.  */
239a45ae5f8SJohn Marino static const struct inferior_data *ada_tasks_inferior_data_handle;
240a45ae5f8SJohn Marino 
241a45ae5f8SJohn Marino /* Return the ada-tasks module's data for the given program space (PSPACE).
242a45ae5f8SJohn Marino    If none is found, add a zero'ed one now.
243a45ae5f8SJohn Marino 
244a45ae5f8SJohn Marino    This function always returns a valid object.  */
245a45ae5f8SJohn Marino 
246a45ae5f8SJohn Marino static struct ada_tasks_pspace_data *
get_ada_tasks_pspace_data(struct program_space * pspace)247a45ae5f8SJohn Marino get_ada_tasks_pspace_data (struct program_space *pspace)
248a45ae5f8SJohn Marino {
249a45ae5f8SJohn Marino   struct ada_tasks_pspace_data *data;
250a45ae5f8SJohn Marino 
251a45ae5f8SJohn Marino   data = program_space_data (pspace, ada_tasks_pspace_data_handle);
252a45ae5f8SJohn Marino   if (data == NULL)
253a45ae5f8SJohn Marino     {
254a45ae5f8SJohn Marino       data = XZALLOC (struct ada_tasks_pspace_data);
255a45ae5f8SJohn Marino       set_program_space_data (pspace, ada_tasks_pspace_data_handle, data);
256a45ae5f8SJohn Marino     }
257a45ae5f8SJohn Marino 
258a45ae5f8SJohn Marino   return data;
259a45ae5f8SJohn Marino }
260a45ae5f8SJohn Marino 
261a45ae5f8SJohn Marino /* Return the ada-tasks module's data for the given inferior (INF).
262a45ae5f8SJohn Marino    If none is found, add a zero'ed one now.
263a45ae5f8SJohn Marino 
264a45ae5f8SJohn Marino    This function always returns a valid object.
265a45ae5f8SJohn Marino 
266a45ae5f8SJohn Marino    Note that we could use an observer of the inferior-created event
267a45ae5f8SJohn Marino    to make sure that the ada-tasks per-inferior data always exists.
268a45ae5f8SJohn Marino    But we prefered this approach, as it avoids this entirely as long
269a45ae5f8SJohn Marino    as the user does not use any of the tasking features.  This is
270a45ae5f8SJohn Marino    quite possible, particularly in the case where the inferior does
271a45ae5f8SJohn Marino    not use tasking.  */
272a45ae5f8SJohn Marino 
273a45ae5f8SJohn Marino static struct ada_tasks_inferior_data *
get_ada_tasks_inferior_data(struct inferior * inf)274a45ae5f8SJohn Marino get_ada_tasks_inferior_data (struct inferior *inf)
275a45ae5f8SJohn Marino {
276a45ae5f8SJohn Marino   struct ada_tasks_inferior_data *data;
277a45ae5f8SJohn Marino 
278a45ae5f8SJohn Marino   data = inferior_data (inf, ada_tasks_inferior_data_handle);
279a45ae5f8SJohn Marino   if (data == NULL)
280a45ae5f8SJohn Marino     {
281a45ae5f8SJohn Marino       data = XZALLOC (struct ada_tasks_inferior_data);
282a45ae5f8SJohn Marino       set_inferior_data (inf, ada_tasks_inferior_data_handle, data);
283a45ae5f8SJohn Marino     }
284a45ae5f8SJohn Marino 
285a45ae5f8SJohn Marino   return data;
286a45ae5f8SJohn Marino }
2875796c8dcSSimon Schubert 
2885796c8dcSSimon Schubert /* Return the task number of the task whose ptid is PTID, or zero
2895796c8dcSSimon Schubert    if the task could not be found.  */
2905796c8dcSSimon Schubert 
2915796c8dcSSimon Schubert int
ada_get_task_number(ptid_t ptid)2925796c8dcSSimon Schubert ada_get_task_number (ptid_t ptid)
2935796c8dcSSimon Schubert {
2945796c8dcSSimon Schubert   int i;
295a45ae5f8SJohn Marino   struct inferior *inf = find_inferior_pid (ptid_get_pid (ptid));
296a45ae5f8SJohn Marino   struct ada_tasks_inferior_data *data;
2975796c8dcSSimon Schubert 
298a45ae5f8SJohn Marino   gdb_assert (inf != NULL);
299a45ae5f8SJohn Marino   data = get_ada_tasks_inferior_data (inf);
300a45ae5f8SJohn Marino 
301a45ae5f8SJohn Marino   for (i = 0; i < VEC_length (ada_task_info_s, data->task_list); i++)
302a45ae5f8SJohn Marino     if (ptid_equal (VEC_index (ada_task_info_s, data->task_list, i)->ptid,
303a45ae5f8SJohn Marino 		    ptid))
3045796c8dcSSimon Schubert       return i + 1;
3055796c8dcSSimon Schubert 
3065796c8dcSSimon Schubert   return 0;  /* No matching task found.  */
3075796c8dcSSimon Schubert }
3085796c8dcSSimon Schubert 
309a45ae5f8SJohn Marino /* Return the task number of the task running in inferior INF which
310a45ae5f8SJohn Marino    matches TASK_ID , or zero if the task could not be found.  */
3115796c8dcSSimon Schubert 
3125796c8dcSSimon Schubert static int
get_task_number_from_id(CORE_ADDR task_id,struct inferior * inf)313a45ae5f8SJohn Marino get_task_number_from_id (CORE_ADDR task_id, struct inferior *inf)
3145796c8dcSSimon Schubert {
315a45ae5f8SJohn Marino   struct ada_tasks_inferior_data *data = get_ada_tasks_inferior_data (inf);
3165796c8dcSSimon Schubert   int i;
3175796c8dcSSimon Schubert 
318a45ae5f8SJohn Marino   for (i = 0; i < VEC_length (ada_task_info_s, data->task_list); i++)
3195796c8dcSSimon Schubert     {
3205796c8dcSSimon Schubert       struct ada_task_info *task_info =
321a45ae5f8SJohn Marino         VEC_index (ada_task_info_s, data->task_list, i);
3225796c8dcSSimon Schubert 
3235796c8dcSSimon Schubert       if (task_info->task_id == task_id)
3245796c8dcSSimon Schubert         return i + 1;
3255796c8dcSSimon Schubert     }
3265796c8dcSSimon Schubert 
3275796c8dcSSimon Schubert   /* Task not found.  Return 0.  */
3285796c8dcSSimon Schubert   return 0;
3295796c8dcSSimon Schubert }
3305796c8dcSSimon Schubert 
3315796c8dcSSimon Schubert /* Return non-zero if TASK_NUM is a valid task number.  */
3325796c8dcSSimon Schubert 
3335796c8dcSSimon Schubert int
valid_task_id(int task_num)3345796c8dcSSimon Schubert valid_task_id (int task_num)
3355796c8dcSSimon Schubert {
336a45ae5f8SJohn Marino   struct ada_tasks_inferior_data *data;
337a45ae5f8SJohn Marino 
338a45ae5f8SJohn Marino   ada_build_task_list ();
339a45ae5f8SJohn Marino   data = get_ada_tasks_inferior_data (current_inferior ());
3405796c8dcSSimon Schubert   return (task_num > 0
341a45ae5f8SJohn Marino           && task_num <= VEC_length (ada_task_info_s, data->task_list));
3425796c8dcSSimon Schubert }
3435796c8dcSSimon Schubert 
3445796c8dcSSimon Schubert /* Return non-zero iff the task STATE corresponds to a non-terminated
3455796c8dcSSimon Schubert    task state.  */
3465796c8dcSSimon Schubert 
3475796c8dcSSimon Schubert static int
ada_task_is_alive(struct ada_task_info * task_info)3485796c8dcSSimon Schubert ada_task_is_alive (struct ada_task_info *task_info)
3495796c8dcSSimon Schubert {
3505796c8dcSSimon Schubert   return (task_info->state != Terminated);
3515796c8dcSSimon Schubert }
3525796c8dcSSimon Schubert 
353c50c785cSJohn Marino /* Call the ITERATOR function once for each Ada task that hasn't been
354c50c785cSJohn Marino    terminated yet.  */
355c50c785cSJohn Marino 
356c50c785cSJohn Marino void
iterate_over_live_ada_tasks(ada_task_list_iterator_ftype * iterator)357c50c785cSJohn Marino iterate_over_live_ada_tasks (ada_task_list_iterator_ftype *iterator)
358c50c785cSJohn Marino {
359c50c785cSJohn Marino   int i, nb_tasks;
360c50c785cSJohn Marino   struct ada_task_info *task;
361a45ae5f8SJohn Marino   struct ada_tasks_inferior_data *data;
362c50c785cSJohn Marino 
363a45ae5f8SJohn Marino   ada_build_task_list ();
364a45ae5f8SJohn Marino   data = get_ada_tasks_inferior_data (current_inferior ());
365a45ae5f8SJohn Marino   nb_tasks = VEC_length (ada_task_info_s, data->task_list);
366c50c785cSJohn Marino 
367c50c785cSJohn Marino   for (i = 0; i < nb_tasks; i++)
368c50c785cSJohn Marino     {
369a45ae5f8SJohn Marino       task = VEC_index (ada_task_info_s, data->task_list, i);
370c50c785cSJohn Marino       if (!ada_task_is_alive (task))
371c50c785cSJohn Marino         continue;
372c50c785cSJohn Marino       iterator (task);
373c50c785cSJohn Marino     }
374c50c785cSJohn Marino }
375c50c785cSJohn Marino 
3765796c8dcSSimon Schubert /* Extract the contents of the value as a string whose length is LENGTH,
3775796c8dcSSimon Schubert    and store the result in DEST.  */
3785796c8dcSSimon Schubert 
3795796c8dcSSimon Schubert static void
value_as_string(char * dest,struct value * val,int length)3805796c8dcSSimon Schubert value_as_string (char *dest, struct value *val, int length)
3815796c8dcSSimon Schubert {
3825796c8dcSSimon Schubert   memcpy (dest, value_contents (val), length);
3835796c8dcSSimon Schubert   dest[length] = '\0';
3845796c8dcSSimon Schubert }
3855796c8dcSSimon Schubert 
3865796c8dcSSimon Schubert /* Extract the string image from the fat string corresponding to VAL,
3875796c8dcSSimon Schubert    and store it in DEST.  If the string length is greater than MAX_LEN,
3885796c8dcSSimon Schubert    then truncate the result to the first MAX_LEN characters of the fat
3895796c8dcSSimon Schubert    string.  */
3905796c8dcSSimon Schubert 
3915796c8dcSSimon Schubert static void
read_fat_string_value(char * dest,struct value * val,int max_len)3925796c8dcSSimon Schubert read_fat_string_value (char *dest, struct value *val, int max_len)
3935796c8dcSSimon Schubert {
3945796c8dcSSimon Schubert   struct value *array_val;
3955796c8dcSSimon Schubert   struct value *bounds_val;
3965796c8dcSSimon Schubert   int len;
3975796c8dcSSimon Schubert 
3985796c8dcSSimon Schubert   /* The following variables are made static to avoid recomputing them
3995796c8dcSSimon Schubert      each time this function is called.  */
4005796c8dcSSimon Schubert   static int initialize_fieldnos = 1;
4015796c8dcSSimon Schubert   static int array_fieldno;
4025796c8dcSSimon Schubert   static int bounds_fieldno;
4035796c8dcSSimon Schubert   static int upper_bound_fieldno;
4045796c8dcSSimon Schubert 
4055796c8dcSSimon Schubert   /* Get the index of the fields that we will need to read in order
4065796c8dcSSimon Schubert      to extract the string from the fat string.  */
4075796c8dcSSimon Schubert   if (initialize_fieldnos)
4085796c8dcSSimon Schubert     {
4095796c8dcSSimon Schubert       struct type *type = value_type (val);
4105796c8dcSSimon Schubert       struct type *bounds_type;
4115796c8dcSSimon Schubert 
4125796c8dcSSimon Schubert       array_fieldno = ada_get_field_index (type, "P_ARRAY", 0);
4135796c8dcSSimon Schubert       bounds_fieldno = ada_get_field_index (type, "P_BOUNDS", 0);
4145796c8dcSSimon Schubert 
4155796c8dcSSimon Schubert       bounds_type = TYPE_FIELD_TYPE (type, bounds_fieldno);
4165796c8dcSSimon Schubert       if (TYPE_CODE (bounds_type) == TYPE_CODE_PTR)
4175796c8dcSSimon Schubert         bounds_type = TYPE_TARGET_TYPE (bounds_type);
4185796c8dcSSimon Schubert       if (TYPE_CODE (bounds_type) != TYPE_CODE_STRUCT)
4195796c8dcSSimon Schubert         error (_("Unknown task name format. Aborting"));
4205796c8dcSSimon Schubert       upper_bound_fieldno = ada_get_field_index (bounds_type, "UB0", 0);
4215796c8dcSSimon Schubert 
4225796c8dcSSimon Schubert       initialize_fieldnos = 0;
4235796c8dcSSimon Schubert     }
4245796c8dcSSimon Schubert 
4255796c8dcSSimon Schubert   /* Get the size of the task image by checking the value of the bounds.
4265796c8dcSSimon Schubert      The lower bound is always 1, so we only need to read the upper bound.  */
4275796c8dcSSimon Schubert   bounds_val = value_ind (value_field (val, bounds_fieldno));
4285796c8dcSSimon Schubert   len = value_as_long (value_field (bounds_val, upper_bound_fieldno));
4295796c8dcSSimon Schubert 
4305796c8dcSSimon Schubert   /* Make sure that we do not read more than max_len characters...  */
4315796c8dcSSimon Schubert   if (len > max_len)
4325796c8dcSSimon Schubert     len = max_len;
4335796c8dcSSimon Schubert 
4345796c8dcSSimon Schubert   /* Extract LEN characters from the fat string.  */
4355796c8dcSSimon Schubert   array_val = value_ind (value_field (val, array_fieldno));
4365796c8dcSSimon Schubert   read_memory (value_address (array_val), dest, len);
4375796c8dcSSimon Schubert 
4385796c8dcSSimon Schubert   /* Add the NUL character to close the string.  */
4395796c8dcSSimon Schubert   dest[len] = '\0';
4405796c8dcSSimon Schubert }
4415796c8dcSSimon Schubert 
4425796c8dcSSimon Schubert /* Get from the debugging information the type description of all types
4435796c8dcSSimon Schubert    related to the Ada Task Control Block that will be needed in order to
4445796c8dcSSimon Schubert    read the list of known tasks in the Ada runtime.  Also return the
4455796c8dcSSimon Schubert    associated ATCB_FIELDNOS.
4465796c8dcSSimon Schubert 
4475796c8dcSSimon Schubert    Error handling:  Any data missing from the debugging info will cause
4485796c8dcSSimon Schubert    an error to be raised, and none of the return values to be set.
4495796c8dcSSimon Schubert    Users of this function can depend on the fact that all or none of the
4505796c8dcSSimon Schubert    return values will be set.  */
4515796c8dcSSimon Schubert 
4525796c8dcSSimon Schubert static void
get_tcb_types_info(void)453a45ae5f8SJohn Marino get_tcb_types_info (void)
4545796c8dcSSimon Schubert {
4555796c8dcSSimon Schubert   struct type *type;
4565796c8dcSSimon Schubert   struct type *common_type;
4575796c8dcSSimon Schubert   struct type *ll_type;
4585796c8dcSSimon Schubert   struct type *call_type;
459a45ae5f8SJohn Marino   struct atcb_fieldnos fieldnos;
460a45ae5f8SJohn Marino   struct ada_tasks_pspace_data *pspace_data;
4615796c8dcSSimon Schubert 
4625796c8dcSSimon Schubert   const char *atcb_name = "system__tasking__ada_task_control_block___XVE";
4635796c8dcSSimon Schubert   const char *atcb_name_fixed = "system__tasking__ada_task_control_block";
4645796c8dcSSimon Schubert   const char *common_atcb_name = "system__tasking__common_atcb";
4655796c8dcSSimon Schubert   const char *private_data_name = "system__task_primitives__private_data";
4665796c8dcSSimon Schubert   const char *entry_call_record_name = "system__tasking__entry_call_record";
4675796c8dcSSimon Schubert 
468c50c785cSJohn Marino   /* ATCB symbols may be found in several compilation units.  As we
469c50c785cSJohn Marino      are only interested in one instance, use standard (literal,
470c50c785cSJohn Marino      C-like) lookups to get the first match.  */
471c50c785cSJohn Marino 
4725796c8dcSSimon Schubert   struct symbol *atcb_sym =
473c50c785cSJohn Marino     lookup_symbol_in_language (atcb_name, NULL, VAR_DOMAIN,
474c50c785cSJohn Marino 			       language_c, NULL);
4755796c8dcSSimon Schubert   const struct symbol *common_atcb_sym =
476c50c785cSJohn Marino     lookup_symbol_in_language (common_atcb_name, NULL, VAR_DOMAIN,
477c50c785cSJohn Marino 			       language_c, NULL);
4785796c8dcSSimon Schubert   const struct symbol *private_data_sym =
479c50c785cSJohn Marino     lookup_symbol_in_language (private_data_name, NULL, VAR_DOMAIN,
480c50c785cSJohn Marino 			       language_c, NULL);
4815796c8dcSSimon Schubert   const struct symbol *entry_call_record_sym =
482c50c785cSJohn Marino     lookup_symbol_in_language (entry_call_record_name, NULL, VAR_DOMAIN,
483c50c785cSJohn Marino 			       language_c, NULL);
4845796c8dcSSimon Schubert 
4855796c8dcSSimon Schubert   if (atcb_sym == NULL || atcb_sym->type == NULL)
4865796c8dcSSimon Schubert     {
4875796c8dcSSimon Schubert       /* In Ravenscar run-time libs, the  ATCB does not have a dynamic
4885796c8dcSSimon Schubert          size, so the symbol name differs.  */
489c50c785cSJohn Marino       atcb_sym = lookup_symbol_in_language (atcb_name_fixed, NULL, VAR_DOMAIN,
490c50c785cSJohn Marino 					    language_c, NULL);
4915796c8dcSSimon Schubert 
4925796c8dcSSimon Schubert       if (atcb_sym == NULL || atcb_sym->type == NULL)
4935796c8dcSSimon Schubert         error (_("Cannot find Ada_Task_Control_Block type. Aborting"));
4945796c8dcSSimon Schubert 
4955796c8dcSSimon Schubert       type = atcb_sym->type;
4965796c8dcSSimon Schubert     }
4975796c8dcSSimon Schubert   else
4985796c8dcSSimon Schubert     {
4995796c8dcSSimon Schubert       /* Get a static representation of the type record
5005796c8dcSSimon Schubert          Ada_Task_Control_Block.  */
5015796c8dcSSimon Schubert       type = atcb_sym->type;
5025796c8dcSSimon Schubert       type = ada_template_to_fixed_record_type_1 (type, NULL, 0, NULL, 0);
5035796c8dcSSimon Schubert     }
5045796c8dcSSimon Schubert 
5055796c8dcSSimon Schubert   if (common_atcb_sym == NULL || common_atcb_sym->type == NULL)
5065796c8dcSSimon Schubert     error (_("Cannot find Common_ATCB type. Aborting"));
5075796c8dcSSimon Schubert   if (private_data_sym == NULL || private_data_sym->type == NULL)
5085796c8dcSSimon Schubert     error (_("Cannot find Private_Data type. Aborting"));
5095796c8dcSSimon Schubert   if (entry_call_record_sym == NULL || entry_call_record_sym->type == NULL)
5105796c8dcSSimon Schubert     error (_("Cannot find Entry_Call_Record type. Aborting"));
5115796c8dcSSimon Schubert 
5125796c8dcSSimon Schubert   /* Get the type for Ada_Task_Control_Block.Common.  */
5135796c8dcSSimon Schubert   common_type = common_atcb_sym->type;
5145796c8dcSSimon Schubert 
5155796c8dcSSimon Schubert   /* Get the type for Ada_Task_Control_Bloc.Common.Call.LL.  */
5165796c8dcSSimon Schubert   ll_type = private_data_sym->type;
5175796c8dcSSimon Schubert 
5185796c8dcSSimon Schubert   /* Get the type for Common_ATCB.Call.all.  */
5195796c8dcSSimon Schubert   call_type = entry_call_record_sym->type;
5205796c8dcSSimon Schubert 
5215796c8dcSSimon Schubert   /* Get the field indices.  */
5225796c8dcSSimon Schubert   fieldnos.common = ada_get_field_index (type, "common", 0);
5235796c8dcSSimon Schubert   fieldnos.entry_calls = ada_get_field_index (type, "entry_calls", 1);
5245796c8dcSSimon Schubert   fieldnos.atc_nesting_level =
5255796c8dcSSimon Schubert     ada_get_field_index (type, "atc_nesting_level", 1);
5265796c8dcSSimon Schubert   fieldnos.state = ada_get_field_index (common_type, "state", 0);
5275796c8dcSSimon Schubert   fieldnos.parent = ada_get_field_index (common_type, "parent", 1);
5285796c8dcSSimon Schubert   fieldnos.priority = ada_get_field_index (common_type, "base_priority", 0);
5295796c8dcSSimon Schubert   fieldnos.image = ada_get_field_index (common_type, "task_image", 1);
5305796c8dcSSimon Schubert   fieldnos.image_len = ada_get_field_index (common_type, "task_image_len", 1);
531a45ae5f8SJohn Marino   fieldnos.activation_link = ada_get_field_index (common_type,
532a45ae5f8SJohn Marino                                                   "activation_link", 1);
5335796c8dcSSimon Schubert   fieldnos.call = ada_get_field_index (common_type, "call", 1);
5345796c8dcSSimon Schubert   fieldnos.ll = ada_get_field_index (common_type, "ll", 0);
5355796c8dcSSimon Schubert   fieldnos.ll_thread = ada_get_field_index (ll_type, "thread", 0);
5365796c8dcSSimon Schubert   fieldnos.ll_lwp = ada_get_field_index (ll_type, "lwp", 1);
5375796c8dcSSimon Schubert   fieldnos.call_self = ada_get_field_index (call_type, "self", 0);
5385796c8dcSSimon Schubert 
5395796c8dcSSimon Schubert   /* On certain platforms such as x86-windows, the "lwp" field has been
5405796c8dcSSimon Schubert      named "thread_id".  This field will likely be renamed in the future,
5415796c8dcSSimon Schubert      but we need to support both possibilities to avoid an unnecessary
5425796c8dcSSimon Schubert      dependency on a recent compiler.  We therefore try locating the
5435796c8dcSSimon Schubert      "thread_id" field in place of the "lwp" field if we did not find
5445796c8dcSSimon Schubert      the latter.  */
5455796c8dcSSimon Schubert   if (fieldnos.ll_lwp < 0)
5465796c8dcSSimon Schubert     fieldnos.ll_lwp = ada_get_field_index (ll_type, "thread_id", 1);
5475796c8dcSSimon Schubert 
5485796c8dcSSimon Schubert   /* Set all the out parameters all at once, now that we are certain
5495796c8dcSSimon Schubert      that there are no potential error() anymore.  */
550a45ae5f8SJohn Marino   pspace_data = get_ada_tasks_pspace_data (current_program_space);
551a45ae5f8SJohn Marino   pspace_data->initialized_p = 1;
552a45ae5f8SJohn Marino   pspace_data->atcb_type = type;
553a45ae5f8SJohn Marino   pspace_data->atcb_common_type = common_type;
554a45ae5f8SJohn Marino   pspace_data->atcb_ll_type = ll_type;
555a45ae5f8SJohn Marino   pspace_data->atcb_call_type = call_type;
556a45ae5f8SJohn Marino   pspace_data->atcb_fieldno = fieldnos;
5575796c8dcSSimon Schubert }
5585796c8dcSSimon Schubert 
5595796c8dcSSimon Schubert /* Build the PTID of the task from its COMMON_VALUE, which is the "Common"
5605796c8dcSSimon Schubert    component of its ATCB record.  This PTID needs to match the PTID used
5615796c8dcSSimon Schubert    by the thread layer.  */
5625796c8dcSSimon Schubert 
5635796c8dcSSimon Schubert static ptid_t
ptid_from_atcb_common(struct value * common_value)5645796c8dcSSimon Schubert ptid_from_atcb_common (struct value *common_value)
5655796c8dcSSimon Schubert {
5665796c8dcSSimon Schubert   long thread = 0;
5675796c8dcSSimon Schubert   CORE_ADDR lwp = 0;
5685796c8dcSSimon Schubert   struct value *ll_value;
5695796c8dcSSimon Schubert   ptid_t ptid;
570a45ae5f8SJohn Marino   const struct ada_tasks_pspace_data *pspace_data
571a45ae5f8SJohn Marino     = get_ada_tasks_pspace_data (current_program_space);
5725796c8dcSSimon Schubert 
573a45ae5f8SJohn Marino   ll_value = value_field (common_value, pspace_data->atcb_fieldno.ll);
5745796c8dcSSimon Schubert 
575a45ae5f8SJohn Marino   if (pspace_data->atcb_fieldno.ll_lwp >= 0)
576a45ae5f8SJohn Marino     lwp = value_as_address (value_field (ll_value,
577a45ae5f8SJohn Marino 					 pspace_data->atcb_fieldno.ll_lwp));
578a45ae5f8SJohn Marino   thread = value_as_long (value_field (ll_value,
579a45ae5f8SJohn Marino 				       pspace_data->atcb_fieldno.ll_thread));
5805796c8dcSSimon Schubert 
5815796c8dcSSimon Schubert   ptid = target_get_ada_task_ptid (lwp, thread);
5825796c8dcSSimon Schubert 
5835796c8dcSSimon Schubert   return ptid;
5845796c8dcSSimon Schubert }
5855796c8dcSSimon Schubert 
5865796c8dcSSimon Schubert /* Read the ATCB data of a given task given its TASK_ID (which is in practice
5875796c8dcSSimon Schubert    the address of its assocated ATCB record), and store the result inside
5885796c8dcSSimon Schubert    TASK_INFO.  */
5895796c8dcSSimon Schubert 
5905796c8dcSSimon Schubert static void
read_atcb(CORE_ADDR task_id,struct ada_task_info * task_info)5915796c8dcSSimon Schubert read_atcb (CORE_ADDR task_id, struct ada_task_info *task_info)
5925796c8dcSSimon Schubert {
5935796c8dcSSimon Schubert   struct value *tcb_value;
5945796c8dcSSimon Schubert   struct value *common_value;
5955796c8dcSSimon Schubert   struct value *atc_nesting_level_value;
5965796c8dcSSimon Schubert   struct value *entry_calls_value;
5975796c8dcSSimon Schubert   struct value *entry_calls_value_element;
5985796c8dcSSimon Schubert   int called_task_fieldno = -1;
599a45ae5f8SJohn Marino   static const char ravenscar_task_name[] = "Ravenscar task";
600a45ae5f8SJohn Marino   const struct ada_tasks_pspace_data *pspace_data
601a45ae5f8SJohn Marino     = get_ada_tasks_pspace_data (current_program_space);
6025796c8dcSSimon Schubert 
603a45ae5f8SJohn Marino   if (!pspace_data->initialized_p)
604a45ae5f8SJohn Marino     get_tcb_types_info ();
6055796c8dcSSimon Schubert 
606a45ae5f8SJohn Marino   tcb_value = value_from_contents_and_address (pspace_data->atcb_type,
607a45ae5f8SJohn Marino 					       NULL, task_id);
608a45ae5f8SJohn Marino   common_value = value_field (tcb_value, pspace_data->atcb_fieldno.common);
6095796c8dcSSimon Schubert 
6105796c8dcSSimon Schubert   /* Fill in the task_id.  */
6115796c8dcSSimon Schubert 
6125796c8dcSSimon Schubert   task_info->task_id = task_id;
6135796c8dcSSimon Schubert 
6145796c8dcSSimon Schubert   /* Compute the name of the task.
6155796c8dcSSimon Schubert 
6165796c8dcSSimon Schubert      Depending on the GNAT version used, the task image is either a fat
6175796c8dcSSimon Schubert      string, or a thin array of characters.  Older versions of GNAT used
6185796c8dcSSimon Schubert      to use fat strings, and therefore did not need an extra field in
6195796c8dcSSimon Schubert      the ATCB to store the string length.  For efficiency reasons, newer
6205796c8dcSSimon Schubert      versions of GNAT replaced the fat string by a static buffer, but this
6215796c8dcSSimon Schubert      also required the addition of a new field named "Image_Len" containing
6225796c8dcSSimon Schubert      the length of the task name.  The method used to extract the task name
6235796c8dcSSimon Schubert      is selected depending on the existence of this field.
6245796c8dcSSimon Schubert 
6255796c8dcSSimon Schubert      In some run-time libs (e.g. Ravenscar), the name is not in the ATCB;
6265796c8dcSSimon Schubert      we may want to get it from the first user frame of the stack.  For now,
6275796c8dcSSimon Schubert      we just give a dummy name.  */
6285796c8dcSSimon Schubert 
629a45ae5f8SJohn Marino   if (pspace_data->atcb_fieldno.image_len == -1)
6305796c8dcSSimon Schubert     {
631a45ae5f8SJohn Marino       if (pspace_data->atcb_fieldno.image >= 0)
6325796c8dcSSimon Schubert         read_fat_string_value (task_info->name,
633a45ae5f8SJohn Marino                                value_field (common_value,
634a45ae5f8SJohn Marino 					    pspace_data->atcb_fieldno.image),
6355796c8dcSSimon Schubert                                sizeof (task_info->name) - 1);
6365796c8dcSSimon Schubert       else
637a45ae5f8SJohn Marino 	{
638a45ae5f8SJohn Marino 	  struct minimal_symbol *msym;
639a45ae5f8SJohn Marino 
640a45ae5f8SJohn Marino 	  msym = lookup_minimal_symbol_by_pc (task_id);
641a45ae5f8SJohn Marino 	  if (msym)
642a45ae5f8SJohn Marino 	    {
643a45ae5f8SJohn Marino 	      const char *full_name = SYMBOL_LINKAGE_NAME (msym);
644a45ae5f8SJohn Marino 	      const char *task_name = full_name;
645a45ae5f8SJohn Marino 	      const char *p;
646a45ae5f8SJohn Marino 
647a45ae5f8SJohn Marino 	      /* Strip the prefix.  */
648a45ae5f8SJohn Marino 	      for (p = full_name; *p; p++)
649a45ae5f8SJohn Marino 		if (p[0] == '_' && p[1] == '_')
650a45ae5f8SJohn Marino 		  task_name = p + 2;
651a45ae5f8SJohn Marino 
652a45ae5f8SJohn Marino 	      /* Copy the task name.  */
653a45ae5f8SJohn Marino 	      strncpy (task_info->name, task_name, sizeof (task_info->name));
654a45ae5f8SJohn Marino 	      task_info->name[sizeof (task_info->name) - 1] = 0;
6555796c8dcSSimon Schubert 	    }
6565796c8dcSSimon Schubert 	  else
6575796c8dcSSimon Schubert 	    {
658a45ae5f8SJohn Marino 	      /* No symbol found.  Use a default name.  */
659a45ae5f8SJohn Marino 	      strcpy (task_info->name, ravenscar_task_name);
660a45ae5f8SJohn Marino 	    }
661a45ae5f8SJohn Marino 	}
662a45ae5f8SJohn Marino     }
663a45ae5f8SJohn Marino   else
664a45ae5f8SJohn Marino     {
665a45ae5f8SJohn Marino       int len = value_as_long
666a45ae5f8SJohn Marino 		  (value_field (common_value,
667a45ae5f8SJohn Marino 				pspace_data->atcb_fieldno.image_len));
6685796c8dcSSimon Schubert 
6695796c8dcSSimon Schubert       value_as_string (task_info->name,
670a45ae5f8SJohn Marino                        value_field (common_value,
671a45ae5f8SJohn Marino 				    pspace_data->atcb_fieldno.image),
672a45ae5f8SJohn Marino 		       len);
6735796c8dcSSimon Schubert     }
6745796c8dcSSimon Schubert 
6755796c8dcSSimon Schubert   /* Compute the task state and priority.  */
6765796c8dcSSimon Schubert 
677a45ae5f8SJohn Marino   task_info->state =
678a45ae5f8SJohn Marino     value_as_long (value_field (common_value,
679a45ae5f8SJohn Marino 				pspace_data->atcb_fieldno.state));
6805796c8dcSSimon Schubert   task_info->priority =
681a45ae5f8SJohn Marino     value_as_long (value_field (common_value,
682a45ae5f8SJohn Marino 				pspace_data->atcb_fieldno.priority));
6835796c8dcSSimon Schubert 
6845796c8dcSSimon Schubert   /* If the ATCB contains some information about the parent task,
6855796c8dcSSimon Schubert      then compute it as well.  Otherwise, zero.  */
6865796c8dcSSimon Schubert 
687a45ae5f8SJohn Marino   if (pspace_data->atcb_fieldno.parent >= 0)
6885796c8dcSSimon Schubert     task_info->parent =
689a45ae5f8SJohn Marino       value_as_address (value_field (common_value,
690a45ae5f8SJohn Marino 				     pspace_data->atcb_fieldno.parent));
6915796c8dcSSimon Schubert   else
6925796c8dcSSimon Schubert     task_info->parent = 0;
6935796c8dcSSimon Schubert 
6945796c8dcSSimon Schubert 
6955796c8dcSSimon Schubert   /* If the ATCB contains some information about entry calls, then
6965796c8dcSSimon Schubert      compute the "called_task" as well.  Otherwise, zero.  */
6975796c8dcSSimon Schubert 
698a45ae5f8SJohn Marino   if (pspace_data->atcb_fieldno.atc_nesting_level > 0
699a45ae5f8SJohn Marino       && pspace_data->atcb_fieldno.entry_calls > 0)
7005796c8dcSSimon Schubert     {
7015796c8dcSSimon Schubert       /* Let My_ATCB be the Ada task control block of a task calling the
7025796c8dcSSimon Schubert          entry of another task; then the Task_Id of the called task is
7035796c8dcSSimon Schubert          in My_ATCB.Entry_Calls (My_ATCB.ATC_Nesting_Level).Called_Task.  */
704a45ae5f8SJohn Marino       atc_nesting_level_value =
705a45ae5f8SJohn Marino         value_field (tcb_value, pspace_data->atcb_fieldno.atc_nesting_level);
7065796c8dcSSimon Schubert       entry_calls_value =
707a45ae5f8SJohn Marino         ada_coerce_to_simple_array_ptr
708a45ae5f8SJohn Marino 	  (value_field (tcb_value, pspace_data->atcb_fieldno.entry_calls));
7095796c8dcSSimon Schubert       entry_calls_value_element =
7105796c8dcSSimon Schubert         value_subscript (entry_calls_value,
7115796c8dcSSimon Schubert 			 value_as_long (atc_nesting_level_value));
7125796c8dcSSimon Schubert       called_task_fieldno =
7135796c8dcSSimon Schubert         ada_get_field_index (value_type (entry_calls_value_element),
7145796c8dcSSimon Schubert                              "called_task", 0);
7155796c8dcSSimon Schubert       task_info->called_task =
7165796c8dcSSimon Schubert         value_as_address (value_field (entry_calls_value_element,
7175796c8dcSSimon Schubert                                        called_task_fieldno));
7185796c8dcSSimon Schubert     }
7195796c8dcSSimon Schubert   else
7205796c8dcSSimon Schubert     {
7215796c8dcSSimon Schubert       task_info->called_task = 0;
7225796c8dcSSimon Schubert     }
7235796c8dcSSimon Schubert 
7245796c8dcSSimon Schubert   /* If the ATCB cotnains some information about RV callers,
7255796c8dcSSimon Schubert      then compute the "caller_task".  Otherwise, zero.  */
7265796c8dcSSimon Schubert 
7275796c8dcSSimon Schubert   task_info->caller_task = 0;
728a45ae5f8SJohn Marino   if (pspace_data->atcb_fieldno.call >= 0)
7295796c8dcSSimon Schubert     {
7305796c8dcSSimon Schubert       /* Get the ID of the caller task from Common_ATCB.Call.all.Self.
7315796c8dcSSimon Schubert          If Common_ATCB.Call is null, then there is no caller.  */
7325796c8dcSSimon Schubert       const CORE_ADDR call =
733a45ae5f8SJohn Marino         value_as_address (value_field (common_value,
734a45ae5f8SJohn Marino 				       pspace_data->atcb_fieldno.call));
7355796c8dcSSimon Schubert       struct value *call_val;
7365796c8dcSSimon Schubert 
7375796c8dcSSimon Schubert       if (call != 0)
7385796c8dcSSimon Schubert         {
7395796c8dcSSimon Schubert           call_val =
740a45ae5f8SJohn Marino             value_from_contents_and_address (pspace_data->atcb_call_type,
741a45ae5f8SJohn Marino 					     NULL, call);
7425796c8dcSSimon Schubert           task_info->caller_task =
743a45ae5f8SJohn Marino             value_as_address
744a45ae5f8SJohn Marino 	      (value_field (call_val, pspace_data->atcb_fieldno.call_self));
7455796c8dcSSimon Schubert         }
7465796c8dcSSimon Schubert     }
7475796c8dcSSimon Schubert 
748c50c785cSJohn Marino   /* And finally, compute the task ptid.  Note that there are situations
749c50c785cSJohn Marino      where this cannot be determined:
750c50c785cSJohn Marino        - The task is no longer alive - the ptid is irrelevant;
751c50c785cSJohn Marino        - We are debugging a core file - the thread is not always
752c50c785cSJohn Marino          completely preserved for us to link back a task to its
753c50c785cSJohn Marino          underlying thread.  Since we do not support task switching
754c50c785cSJohn Marino          when debugging core files anyway, we don't need to compute
755c50c785cSJohn Marino          that task ptid.
756c50c785cSJohn Marino      In either case, we don't need that ptid, and it is just good enough
757c50c785cSJohn Marino      to set it to null_ptid.  */
7585796c8dcSSimon Schubert 
759c50c785cSJohn Marino   if (target_has_execution && ada_task_is_alive (task_info))
7605796c8dcSSimon Schubert     task_info->ptid = ptid_from_atcb_common (common_value);
7615796c8dcSSimon Schubert   else
7625796c8dcSSimon Schubert     task_info->ptid = null_ptid;
7635796c8dcSSimon Schubert }
7645796c8dcSSimon Schubert 
7655796c8dcSSimon Schubert /* Read the ATCB info of the given task (identified by TASK_ID), and
766a45ae5f8SJohn Marino    add the result to the given inferior's TASK_LIST.  */
7675796c8dcSSimon Schubert 
7685796c8dcSSimon Schubert static void
add_ada_task(CORE_ADDR task_id,struct inferior * inf)769a45ae5f8SJohn Marino add_ada_task (CORE_ADDR task_id, struct inferior *inf)
7705796c8dcSSimon Schubert {
7715796c8dcSSimon Schubert   struct ada_task_info task_info;
772a45ae5f8SJohn Marino   struct ada_tasks_inferior_data *data = get_ada_tasks_inferior_data (inf);
7735796c8dcSSimon Schubert 
7745796c8dcSSimon Schubert   read_atcb (task_id, &task_info);
775a45ae5f8SJohn Marino   VEC_safe_push (ada_task_info_s, data->task_list, &task_info);
7765796c8dcSSimon Schubert }
7775796c8dcSSimon Schubert 
7785796c8dcSSimon Schubert /* Read the Known_Tasks array from the inferior memory, and store
779a45ae5f8SJohn Marino    it in the current inferior's TASK_LIST.  Return non-zero upon success.  */
7805796c8dcSSimon Schubert 
7815796c8dcSSimon Schubert static int
read_known_tasks_array(struct ada_tasks_inferior_data * data)782*ef5ccd6cSJohn Marino read_known_tasks_array (struct ada_tasks_inferior_data *data)
7835796c8dcSSimon Schubert {
784*ef5ccd6cSJohn Marino   const int target_ptr_byte = TYPE_LENGTH (data->known_tasks_element);
785*ef5ccd6cSJohn Marino   const int known_tasks_size = target_ptr_byte * data->known_tasks_length;
7865796c8dcSSimon Schubert   gdb_byte *known_tasks = alloca (known_tasks_size);
7875796c8dcSSimon Schubert   int i;
7885796c8dcSSimon Schubert 
789a45ae5f8SJohn Marino   /* Build a new list by reading the ATCBs from the Known_Tasks array
790a45ae5f8SJohn Marino      in the Ada runtime.  */
791*ef5ccd6cSJohn Marino   read_memory (data->known_tasks_addr, known_tasks, known_tasks_size);
792*ef5ccd6cSJohn Marino   for (i = 0; i < data->known_tasks_length; i++)
7935796c8dcSSimon Schubert     {
7945796c8dcSSimon Schubert       CORE_ADDR task_id =
7955796c8dcSSimon Schubert         extract_typed_address (known_tasks + i * target_ptr_byte,
796*ef5ccd6cSJohn Marino 			       data->known_tasks_element);
7975796c8dcSSimon Schubert 
7985796c8dcSSimon Schubert       if (task_id != 0)
799a45ae5f8SJohn Marino         add_ada_task (task_id, current_inferior ());
8005796c8dcSSimon Schubert     }
8015796c8dcSSimon Schubert 
8025796c8dcSSimon Schubert   return 1;
8035796c8dcSSimon Schubert }
8045796c8dcSSimon Schubert 
805a45ae5f8SJohn Marino /* Read the known tasks from the inferior memory, and store it in
806a45ae5f8SJohn Marino    the current inferior's TASK_LIST.  Return non-zero upon success.  */
807a45ae5f8SJohn Marino 
808a45ae5f8SJohn Marino static int
read_known_tasks_list(struct ada_tasks_inferior_data * data)809*ef5ccd6cSJohn Marino read_known_tasks_list (struct ada_tasks_inferior_data *data)
810a45ae5f8SJohn Marino {
811*ef5ccd6cSJohn Marino   const int target_ptr_byte = TYPE_LENGTH (data->known_tasks_element);
812a45ae5f8SJohn Marino   gdb_byte *known_tasks = alloca (target_ptr_byte);
813a45ae5f8SJohn Marino   CORE_ADDR task_id;
814a45ae5f8SJohn Marino   const struct ada_tasks_pspace_data *pspace_data
815a45ae5f8SJohn Marino     = get_ada_tasks_pspace_data (current_program_space);
816a45ae5f8SJohn Marino 
817a45ae5f8SJohn Marino   /* Sanity check.  */
818a45ae5f8SJohn Marino   if (pspace_data->atcb_fieldno.activation_link < 0)
819a45ae5f8SJohn Marino     return 0;
820a45ae5f8SJohn Marino 
821a45ae5f8SJohn Marino   /* Build a new list by reading the ATCBs.  Read head of the list.  */
822*ef5ccd6cSJohn Marino   read_memory (data->known_tasks_addr, known_tasks, target_ptr_byte);
823*ef5ccd6cSJohn Marino   task_id = extract_typed_address (known_tasks, data->known_tasks_element);
824a45ae5f8SJohn Marino   while (task_id != 0)
825a45ae5f8SJohn Marino     {
826a45ae5f8SJohn Marino       struct value *tcb_value;
827a45ae5f8SJohn Marino       struct value *common_value;
828a45ae5f8SJohn Marino 
829a45ae5f8SJohn Marino       add_ada_task (task_id, current_inferior ());
830a45ae5f8SJohn Marino 
831a45ae5f8SJohn Marino       /* Read the chain.  */
832a45ae5f8SJohn Marino       tcb_value = value_from_contents_and_address (pspace_data->atcb_type,
833a45ae5f8SJohn Marino 						   NULL, task_id);
834a45ae5f8SJohn Marino       common_value = value_field (tcb_value, pspace_data->atcb_fieldno.common);
835a45ae5f8SJohn Marino       task_id = value_as_address
836a45ae5f8SJohn Marino 		  (value_field (common_value,
837a45ae5f8SJohn Marino                                 pspace_data->atcb_fieldno.activation_link));
838a45ae5f8SJohn Marino     }
839a45ae5f8SJohn Marino 
840a45ae5f8SJohn Marino   return 1;
841a45ae5f8SJohn Marino }
842a45ae5f8SJohn Marino 
843*ef5ccd6cSJohn Marino /* Set all fields of the current inferior ada-tasks data pointed by DATA.
844*ef5ccd6cSJohn Marino    Do nothing if those fields are already set and still up to date.  */
845a45ae5f8SJohn Marino 
846a45ae5f8SJohn Marino static void
ada_tasks_inferior_data_sniffer(struct ada_tasks_inferior_data * data)847*ef5ccd6cSJohn Marino ada_tasks_inferior_data_sniffer (struct ada_tasks_inferior_data *data)
848a45ae5f8SJohn Marino {
849*ef5ccd6cSJohn Marino   struct minimal_symbol *msym;
850*ef5ccd6cSJohn Marino   struct symbol *sym;
851a45ae5f8SJohn Marino 
852*ef5ccd6cSJohn Marino   /* Return now if already set.  */
853a45ae5f8SJohn Marino   if (data->known_tasks_kind != ADA_TASKS_UNKNOWN)
854a45ae5f8SJohn Marino     return;
855a45ae5f8SJohn Marino 
856*ef5ccd6cSJohn Marino   /* Try array.  */
857*ef5ccd6cSJohn Marino 
858*ef5ccd6cSJohn Marino   msym = lookup_minimal_symbol (KNOWN_TASKS_NAME, NULL, NULL);
859*ef5ccd6cSJohn Marino   if (msym != NULL)
860a45ae5f8SJohn Marino     {
861a45ae5f8SJohn Marino       data->known_tasks_kind = ADA_TASKS_ARRAY;
862*ef5ccd6cSJohn Marino       data->known_tasks_addr = SYMBOL_VALUE_ADDRESS (msym);
863*ef5ccd6cSJohn Marino 
864*ef5ccd6cSJohn Marino       /* Try to get pointer type and array length from the symtab.  */
865*ef5ccd6cSJohn Marino       sym = lookup_symbol_in_language (KNOWN_TASKS_NAME, NULL, VAR_DOMAIN,
866*ef5ccd6cSJohn Marino 				       language_c, NULL);
867*ef5ccd6cSJohn Marino       if (sym != NULL)
868*ef5ccd6cSJohn Marino 	{
869*ef5ccd6cSJohn Marino 	  /* Validate.  */
870*ef5ccd6cSJohn Marino 	  struct type *type = check_typedef (SYMBOL_TYPE (sym));
871*ef5ccd6cSJohn Marino 	  struct type *eltype = NULL;
872*ef5ccd6cSJohn Marino 	  struct type *idxtype = NULL;
873*ef5ccd6cSJohn Marino 
874*ef5ccd6cSJohn Marino 	  if (TYPE_CODE (type) == TYPE_CODE_ARRAY)
875*ef5ccd6cSJohn Marino 	    eltype = check_typedef (TYPE_TARGET_TYPE (type));
876*ef5ccd6cSJohn Marino 	  if (eltype != NULL
877*ef5ccd6cSJohn Marino 	      && TYPE_CODE (eltype) == TYPE_CODE_PTR)
878*ef5ccd6cSJohn Marino 	    idxtype = check_typedef (TYPE_INDEX_TYPE (type));
879*ef5ccd6cSJohn Marino 	  if (idxtype != NULL
880*ef5ccd6cSJohn Marino 	      && !TYPE_LOW_BOUND_UNDEFINED (idxtype)
881*ef5ccd6cSJohn Marino 	      && !TYPE_HIGH_BOUND_UNDEFINED (idxtype))
882*ef5ccd6cSJohn Marino 	    {
883*ef5ccd6cSJohn Marino 	      data->known_tasks_element = eltype;
884*ef5ccd6cSJohn Marino 	      data->known_tasks_length =
885*ef5ccd6cSJohn Marino 		TYPE_HIGH_BOUND (idxtype) - TYPE_LOW_BOUND (idxtype) + 1;
886*ef5ccd6cSJohn Marino 	      return;
887*ef5ccd6cSJohn Marino 	    }
888*ef5ccd6cSJohn Marino 	}
889*ef5ccd6cSJohn Marino 
890*ef5ccd6cSJohn Marino       /* Fallback to default values.  The runtime may have been stripped (as
891*ef5ccd6cSJohn Marino 	 in some distributions), but it is likely that the executable still
892*ef5ccd6cSJohn Marino 	 contains debug information on the task type (due to implicit with of
893*ef5ccd6cSJohn Marino 	 Ada.Tasking).  */
894*ef5ccd6cSJohn Marino       data->known_tasks_element =
895*ef5ccd6cSJohn Marino 	builtin_type (target_gdbarch ())->builtin_data_ptr;
896*ef5ccd6cSJohn Marino       data->known_tasks_length = MAX_NUMBER_OF_KNOWN_TASKS;
897a45ae5f8SJohn Marino       return;
898a45ae5f8SJohn Marino     }
899a45ae5f8SJohn Marino 
900*ef5ccd6cSJohn Marino 
901*ef5ccd6cSJohn Marino   /* Try list.  */
902*ef5ccd6cSJohn Marino 
903*ef5ccd6cSJohn Marino   msym = lookup_minimal_symbol (KNOWN_TASKS_LIST, NULL, NULL);
904*ef5ccd6cSJohn Marino   if (msym != NULL)
905a45ae5f8SJohn Marino     {
906a45ae5f8SJohn Marino       data->known_tasks_kind = ADA_TASKS_LIST;
907*ef5ccd6cSJohn Marino       data->known_tasks_addr = SYMBOL_VALUE_ADDRESS (msym);
908*ef5ccd6cSJohn Marino       data->known_tasks_length = 1;
909*ef5ccd6cSJohn Marino 
910*ef5ccd6cSJohn Marino       sym = lookup_symbol_in_language (KNOWN_TASKS_LIST, NULL, VAR_DOMAIN,
911*ef5ccd6cSJohn Marino 				       language_c, NULL);
912*ef5ccd6cSJohn Marino       if (sym != NULL && SYMBOL_VALUE_ADDRESS (sym) != 0)
913*ef5ccd6cSJohn Marino 	{
914*ef5ccd6cSJohn Marino 	  /* Validate.  */
915*ef5ccd6cSJohn Marino 	  struct type *type = check_typedef (SYMBOL_TYPE (sym));
916*ef5ccd6cSJohn Marino 
917*ef5ccd6cSJohn Marino 	  if (TYPE_CODE (type) == TYPE_CODE_PTR)
918*ef5ccd6cSJohn Marino 	    {
919*ef5ccd6cSJohn Marino 	      data->known_tasks_element = type;
920a45ae5f8SJohn Marino 	      return;
921a45ae5f8SJohn Marino 	    }
922*ef5ccd6cSJohn Marino 	}
923*ef5ccd6cSJohn Marino 
924*ef5ccd6cSJohn Marino       /* Fallback to default values.  */
925*ef5ccd6cSJohn Marino       data->known_tasks_element =
926*ef5ccd6cSJohn Marino 	builtin_type (target_gdbarch ())->builtin_data_ptr;
927*ef5ccd6cSJohn Marino       data->known_tasks_length = 1;
928*ef5ccd6cSJohn Marino       return;
929*ef5ccd6cSJohn Marino     }
930*ef5ccd6cSJohn Marino 
931*ef5ccd6cSJohn Marino   /* Can't find tasks.  */
932a45ae5f8SJohn Marino 
933a45ae5f8SJohn Marino   data->known_tasks_kind = ADA_TASKS_NOT_FOUND;
934a45ae5f8SJohn Marino   data->known_tasks_addr = 0;
935a45ae5f8SJohn Marino }
936a45ae5f8SJohn Marino 
937a45ae5f8SJohn Marino /* Read the known tasks from the current inferior's memory, and store it
938a45ae5f8SJohn Marino    in the current inferior's data TASK_LIST.
939a45ae5f8SJohn Marino    Return non-zero upon success.  */
940a45ae5f8SJohn Marino 
941a45ae5f8SJohn Marino static int
read_known_tasks(void)942a45ae5f8SJohn Marino read_known_tasks (void)
943a45ae5f8SJohn Marino {
944a45ae5f8SJohn Marino   struct ada_tasks_inferior_data *data =
945a45ae5f8SJohn Marino     get_ada_tasks_inferior_data (current_inferior ());
946a45ae5f8SJohn Marino 
947a45ae5f8SJohn Marino   /* Step 1: Clear the current list, if necessary.  */
948a45ae5f8SJohn Marino   VEC_truncate (ada_task_info_s, data->task_list, 0);
949a45ae5f8SJohn Marino 
950a45ae5f8SJohn Marino   /* Step 2: do the real work.
951a45ae5f8SJohn Marino      If the application does not use task, then no more needs to be done.
952a45ae5f8SJohn Marino      It is important to have the task list cleared (see above) before we
953a45ae5f8SJohn Marino      return, as we don't want a stale task list to be used...  This can
954a45ae5f8SJohn Marino      happen for instance when debugging a non-multitasking program after
955a45ae5f8SJohn Marino      having debugged a multitasking one.  */
956*ef5ccd6cSJohn Marino   ada_tasks_inferior_data_sniffer (data);
957a45ae5f8SJohn Marino   gdb_assert (data->known_tasks_kind != ADA_TASKS_UNKNOWN);
958a45ae5f8SJohn Marino 
959a45ae5f8SJohn Marino   switch (data->known_tasks_kind)
960a45ae5f8SJohn Marino     {
961a45ae5f8SJohn Marino       case ADA_TASKS_NOT_FOUND: /* Tasking not in use in inferior.  */
962a45ae5f8SJohn Marino         return 0;
963a45ae5f8SJohn Marino       case ADA_TASKS_ARRAY:
964*ef5ccd6cSJohn Marino         return read_known_tasks_array (data);
965a45ae5f8SJohn Marino       case ADA_TASKS_LIST:
966*ef5ccd6cSJohn Marino         return read_known_tasks_list (data);
967a45ae5f8SJohn Marino     }
968a45ae5f8SJohn Marino 
969a45ae5f8SJohn Marino   /* Step 3: Set task_list_valid_p, to avoid re-reading the Known_Tasks
970a45ae5f8SJohn Marino      array unless needed.  Then report a success.  */
971a45ae5f8SJohn Marino   data->task_list_valid_p = 1;
972a45ae5f8SJohn Marino 
973a45ae5f8SJohn Marino   return 1;
974a45ae5f8SJohn Marino }
975a45ae5f8SJohn Marino 
976a45ae5f8SJohn Marino /* Build the task_list by reading the Known_Tasks array from
977a45ae5f8SJohn Marino    the inferior, and return the number of tasks in that list
978a45ae5f8SJohn Marino    (zero means that the program is not using tasking at all).  */
9795796c8dcSSimon Schubert 
9805796c8dcSSimon Schubert int
ada_build_task_list(void)981a45ae5f8SJohn Marino ada_build_task_list (void)
9825796c8dcSSimon Schubert {
983a45ae5f8SJohn Marino   struct ada_tasks_inferior_data *data;
984a45ae5f8SJohn Marino 
9855796c8dcSSimon Schubert   if (!target_has_stack)
9865796c8dcSSimon Schubert     error (_("Cannot inspect Ada tasks when program is not running"));
9875796c8dcSSimon Schubert 
988a45ae5f8SJohn Marino   data = get_ada_tasks_inferior_data (current_inferior ());
989a45ae5f8SJohn Marino   if (!data->task_list_valid_p)
990a45ae5f8SJohn Marino     read_known_tasks ();
9915796c8dcSSimon Schubert 
992a45ae5f8SJohn Marino   return VEC_length (ada_task_info_s, data->task_list);
993a45ae5f8SJohn Marino }
994a45ae5f8SJohn Marino 
995a45ae5f8SJohn Marino /* Print a table providing a short description of all Ada tasks
996a45ae5f8SJohn Marino    running inside inferior INF.  If ARG_STR is set, it will be
997a45ae5f8SJohn Marino    interpreted as a task number, and the table will be limited to
998a45ae5f8SJohn Marino    that task only.  */
999a45ae5f8SJohn Marino 
1000a45ae5f8SJohn Marino void
print_ada_task_info(struct ui_out * uiout,char * arg_str,struct inferior * inf)1001a45ae5f8SJohn Marino print_ada_task_info (struct ui_out *uiout,
1002a45ae5f8SJohn Marino 		     char *arg_str,
1003a45ae5f8SJohn Marino 		     struct inferior *inf)
10045796c8dcSSimon Schubert {
1005a45ae5f8SJohn Marino   struct ada_tasks_inferior_data *data;
1006a45ae5f8SJohn Marino   int taskno, nb_tasks;
1007a45ae5f8SJohn Marino   int taskno_arg = 0;
1008a45ae5f8SJohn Marino   struct cleanup *old_chain;
1009a45ae5f8SJohn Marino   int nb_columns;
1010a45ae5f8SJohn Marino 
1011a45ae5f8SJohn Marino   if (ada_build_task_list () == 0)
1012a45ae5f8SJohn Marino     {
1013a45ae5f8SJohn Marino       ui_out_message (uiout, 0,
1014a45ae5f8SJohn Marino 		      _("Your application does not use any Ada tasks.\n"));
1015a45ae5f8SJohn Marino       return;
10165796c8dcSSimon Schubert     }
10175796c8dcSSimon Schubert 
1018a45ae5f8SJohn Marino   if (arg_str != NULL && arg_str[0] != '\0')
1019a45ae5f8SJohn Marino     taskno_arg = value_as_long (parse_and_eval (arg_str));
1020a45ae5f8SJohn Marino 
1021a45ae5f8SJohn Marino   if (ui_out_is_mi_like_p (uiout))
1022a45ae5f8SJohn Marino     /* In GDB/MI mode, we want to provide the thread ID corresponding
1023a45ae5f8SJohn Marino        to each task.  This allows clients to quickly find the thread
1024a45ae5f8SJohn Marino        associated to any task, which is helpful for commands that
1025a45ae5f8SJohn Marino        take a --thread argument.  However, in order to be able to
1026a45ae5f8SJohn Marino        provide that thread ID, the thread list must be up to date
1027a45ae5f8SJohn Marino        first.  */
1028a45ae5f8SJohn Marino     target_find_new_threads ();
1029a45ae5f8SJohn Marino 
1030a45ae5f8SJohn Marino   data = get_ada_tasks_inferior_data (inf);
1031a45ae5f8SJohn Marino 
1032a45ae5f8SJohn Marino   /* Compute the number of tasks that are going to be displayed
1033a45ae5f8SJohn Marino      in the output.  If an argument was given, there will be
1034a45ae5f8SJohn Marino      at most 1 entry.  Otherwise, there will be as many entries
1035a45ae5f8SJohn Marino      as we have tasks.  */
1036a45ae5f8SJohn Marino   if (taskno_arg)
1037a45ae5f8SJohn Marino     {
1038a45ae5f8SJohn Marino       if (taskno_arg > 0
1039a45ae5f8SJohn Marino 	  && taskno_arg <= VEC_length (ada_task_info_s, data->task_list))
1040a45ae5f8SJohn Marino 	nb_tasks = 1;
1041a45ae5f8SJohn Marino       else
1042a45ae5f8SJohn Marino 	nb_tasks = 0;
10435796c8dcSSimon Schubert     }
1044a45ae5f8SJohn Marino   else
1045a45ae5f8SJohn Marino     nb_tasks = VEC_length (ada_task_info_s, data->task_list);
10465796c8dcSSimon Schubert 
1047a45ae5f8SJohn Marino   nb_columns = ui_out_is_mi_like_p (uiout) ? 8 : 7;
1048a45ae5f8SJohn Marino   old_chain = make_cleanup_ui_out_table_begin_end (uiout, nb_columns,
1049a45ae5f8SJohn Marino 						   nb_tasks, "tasks");
1050a45ae5f8SJohn Marino   ui_out_table_header (uiout, 1, ui_left, "current", "");
1051a45ae5f8SJohn Marino   ui_out_table_header (uiout, 3, ui_right, "id", "ID");
1052a45ae5f8SJohn Marino   ui_out_table_header (uiout, 9, ui_right, "task-id", "TID");
1053a45ae5f8SJohn Marino   /* The following column is provided in GDB/MI mode only because
1054a45ae5f8SJohn Marino      it is only really useful in that mode, and also because it
1055a45ae5f8SJohn Marino      allows us to keep the CLI output shorter and more compact.  */
1056a45ae5f8SJohn Marino   if (ui_out_is_mi_like_p (uiout))
1057a45ae5f8SJohn Marino     ui_out_table_header (uiout, 4, ui_right, "thread-id", "");
1058a45ae5f8SJohn Marino   ui_out_table_header (uiout, 4, ui_right, "parent-id", "P-ID");
1059a45ae5f8SJohn Marino   ui_out_table_header (uiout, 3, ui_right, "priority", "Pri");
1060a45ae5f8SJohn Marino   ui_out_table_header (uiout, 22, ui_left, "state", "State");
1061a45ae5f8SJohn Marino   /* Use ui_noalign for the last column, to prevent the CLI uiout
1062a45ae5f8SJohn Marino      from printing an extra space at the end of each row.  This
1063a45ae5f8SJohn Marino      is a bit of a hack, but does get the job done.  */
1064a45ae5f8SJohn Marino   ui_out_table_header (uiout, 1, ui_noalign, "name", "Name");
1065a45ae5f8SJohn Marino   ui_out_table_body (uiout);
10665796c8dcSSimon Schubert 
1067a45ae5f8SJohn Marino   for (taskno = 1;
1068a45ae5f8SJohn Marino        taskno <= VEC_length (ada_task_info_s, data->task_list);
1069a45ae5f8SJohn Marino        taskno++)
10705796c8dcSSimon Schubert     {
10715796c8dcSSimon Schubert       const struct ada_task_info *const task_info =
1072a45ae5f8SJohn Marino 	VEC_index (ada_task_info_s, data->task_list, taskno - 1);
1073a45ae5f8SJohn Marino       int parent_id;
1074a45ae5f8SJohn Marino       struct cleanup *chain2;
10755796c8dcSSimon Schubert 
10765796c8dcSSimon Schubert       gdb_assert (task_info != NULL);
10775796c8dcSSimon Schubert 
1078a45ae5f8SJohn Marino       /* If the user asked for the output to be restricted
1079a45ae5f8SJohn Marino 	 to one task only, and this is not the task, skip
1080a45ae5f8SJohn Marino 	 to the next one.  */
1081a45ae5f8SJohn Marino       if (taskno_arg && taskno != taskno_arg)
1082a45ae5f8SJohn Marino         continue;
10835796c8dcSSimon Schubert 
1084a45ae5f8SJohn Marino       chain2 = make_cleanup_ui_out_tuple_begin_end (uiout, NULL);
1085a45ae5f8SJohn Marino 
1086a45ae5f8SJohn Marino       /* Print a star if this task is the current task (or the task
1087a45ae5f8SJohn Marino          currently selected).  */
1088a45ae5f8SJohn Marino       if (ptid_equal (task_info->ptid, inferior_ptid))
1089a45ae5f8SJohn Marino 	ui_out_field_string (uiout, "current", "*");
10905796c8dcSSimon Schubert       else
1091a45ae5f8SJohn Marino 	ui_out_field_skip (uiout, "current");
10925796c8dcSSimon Schubert 
10935796c8dcSSimon Schubert       /* Print the task number.  */
1094a45ae5f8SJohn Marino       ui_out_field_int (uiout, "id", taskno);
10955796c8dcSSimon Schubert 
10965796c8dcSSimon Schubert       /* Print the Task ID.  */
1097a45ae5f8SJohn Marino       ui_out_field_fmt (uiout, "task-id", "%9lx", (long) task_info->task_id);
10985796c8dcSSimon Schubert 
1099a45ae5f8SJohn Marino       /* Print the associated Thread ID.  */
1100a45ae5f8SJohn Marino       if (ui_out_is_mi_like_p (uiout))
1101a45ae5f8SJohn Marino         {
1102a45ae5f8SJohn Marino 	  const int thread_id = pid_to_thread_id (task_info->ptid);
1103a45ae5f8SJohn Marino 
1104a45ae5f8SJohn Marino 	  if (thread_id != 0)
1105a45ae5f8SJohn Marino 	    ui_out_field_int (uiout, "thread-id", thread_id);
1106a45ae5f8SJohn Marino 	  else
1107a45ae5f8SJohn Marino 	    /* This should never happen unless there is a bug somewhere,
1108a45ae5f8SJohn Marino 	       but be resilient when that happens.  */
1109a45ae5f8SJohn Marino 	    ui_out_field_skip (uiout, "thread-id");
1110a45ae5f8SJohn Marino 	}
1111a45ae5f8SJohn Marino 
1112a45ae5f8SJohn Marino       /* Print the ID of the parent task.  */
1113a45ae5f8SJohn Marino       parent_id = get_task_number_from_id (task_info->parent, inf);
1114a45ae5f8SJohn Marino       if (parent_id)
1115a45ae5f8SJohn Marino         ui_out_field_int (uiout, "parent-id", parent_id);
1116a45ae5f8SJohn Marino       else
1117a45ae5f8SJohn Marino         ui_out_field_skip (uiout, "parent-id");
11185796c8dcSSimon Schubert 
11195796c8dcSSimon Schubert       /* Print the base priority of the task.  */
1120a45ae5f8SJohn Marino       ui_out_field_int (uiout, "priority", task_info->priority);
11215796c8dcSSimon Schubert 
11225796c8dcSSimon Schubert       /* Print the task current state.  */
11235796c8dcSSimon Schubert       if (task_info->caller_task)
1124a45ae5f8SJohn Marino 	ui_out_field_fmt (uiout, "state",
1125a45ae5f8SJohn Marino 			  _("Accepting RV with %-4d"),
1126a45ae5f8SJohn Marino 			  get_task_number_from_id (task_info->caller_task,
1127a45ae5f8SJohn Marino 						   inf));
1128a45ae5f8SJohn Marino       else if (task_info->state == Entry_Caller_Sleep
1129a45ae5f8SJohn Marino 	       && task_info->called_task)
1130a45ae5f8SJohn Marino 	ui_out_field_fmt (uiout, "state",
1131a45ae5f8SJohn Marino 			  _("Waiting on RV with %-3d"),
1132a45ae5f8SJohn Marino 			  get_task_number_from_id (task_info->called_task,
1133a45ae5f8SJohn Marino 						   inf));
11345796c8dcSSimon Schubert       else
1135a45ae5f8SJohn Marino 	ui_out_field_string (uiout, "state", task_states[task_info->state]);
11365796c8dcSSimon Schubert 
11375796c8dcSSimon Schubert       /* Finally, print the task name.  */
1138a45ae5f8SJohn Marino       ui_out_field_fmt (uiout, "name",
1139a45ae5f8SJohn Marino 			"%s",
1140a45ae5f8SJohn Marino 			task_info->name[0] != '\0' ? task_info->name
1141a45ae5f8SJohn Marino 						   : _("<no name>"));
1142a45ae5f8SJohn Marino 
1143a45ae5f8SJohn Marino       ui_out_text (uiout, "\n");
1144a45ae5f8SJohn Marino       do_cleanups (chain2);
11455796c8dcSSimon Schubert     }
11465796c8dcSSimon Schubert 
1147a45ae5f8SJohn Marino   do_cleanups (old_chain);
11485796c8dcSSimon Schubert }
11495796c8dcSSimon Schubert 
1150a45ae5f8SJohn Marino /* Print a detailed description of the Ada task whose ID is TASKNO_STR
1151a45ae5f8SJohn Marino    for the given inferior (INF).  */
11525796c8dcSSimon Schubert 
11535796c8dcSSimon Schubert static void
info_task(struct ui_out * uiout,char * taskno_str,struct inferior * inf)1154a45ae5f8SJohn Marino info_task (struct ui_out *uiout, char *taskno_str, struct inferior *inf)
11555796c8dcSSimon Schubert {
11565796c8dcSSimon Schubert   const int taskno = value_as_long (parse_and_eval (taskno_str));
11575796c8dcSSimon Schubert   struct ada_task_info *task_info;
11585796c8dcSSimon Schubert   int parent_taskno = 0;
1159a45ae5f8SJohn Marino   struct ada_tasks_inferior_data *data = get_ada_tasks_inferior_data (inf);
11605796c8dcSSimon Schubert 
1161a45ae5f8SJohn Marino   if (ada_build_task_list () == 0)
1162a45ae5f8SJohn Marino     {
1163a45ae5f8SJohn Marino       ui_out_message (uiout, 0,
1164a45ae5f8SJohn Marino 		      _("Your application does not use any Ada tasks.\n"));
1165a45ae5f8SJohn Marino       return;
1166a45ae5f8SJohn Marino     }
1167a45ae5f8SJohn Marino 
1168a45ae5f8SJohn Marino   if (taskno <= 0 || taskno > VEC_length (ada_task_info_s, data->task_list))
11695796c8dcSSimon Schubert     error (_("Task ID %d not known.  Use the \"info tasks\" command to\n"
11705796c8dcSSimon Schubert              "see the IDs of currently known tasks"), taskno);
1171a45ae5f8SJohn Marino   task_info = VEC_index (ada_task_info_s, data->task_list, taskno - 1);
11725796c8dcSSimon Schubert 
11735796c8dcSSimon Schubert   /* Print the Ada task ID.  */
11745796c8dcSSimon Schubert   printf_filtered (_("Ada Task: %s\n"),
1175*ef5ccd6cSJohn Marino 		   paddress (target_gdbarch (), task_info->task_id));
11765796c8dcSSimon Schubert 
11775796c8dcSSimon Schubert   /* Print the name of the task.  */
11785796c8dcSSimon Schubert   if (task_info->name[0] != '\0')
11795796c8dcSSimon Schubert     printf_filtered (_("Name: %s\n"), task_info->name);
11805796c8dcSSimon Schubert   else
11815796c8dcSSimon Schubert     printf_filtered (_("<no name>\n"));
11825796c8dcSSimon Schubert 
11835796c8dcSSimon Schubert   /* Print the TID and LWP.  */
11845796c8dcSSimon Schubert   printf_filtered (_("Thread: %#lx\n"), ptid_get_tid (task_info->ptid));
11855796c8dcSSimon Schubert   printf_filtered (_("LWP: %#lx\n"), ptid_get_lwp (task_info->ptid));
11865796c8dcSSimon Schubert 
11875796c8dcSSimon Schubert   /* Print who is the parent (if any).  */
11885796c8dcSSimon Schubert   if (task_info->parent != 0)
1189a45ae5f8SJohn Marino     parent_taskno = get_task_number_from_id (task_info->parent, inf);
11905796c8dcSSimon Schubert   if (parent_taskno)
11915796c8dcSSimon Schubert     {
11925796c8dcSSimon Schubert       struct ada_task_info *parent =
1193a45ae5f8SJohn Marino         VEC_index (ada_task_info_s, data->task_list, parent_taskno - 1);
11945796c8dcSSimon Schubert 
11955796c8dcSSimon Schubert       printf_filtered (_("Parent: %d"), parent_taskno);
11965796c8dcSSimon Schubert       if (parent->name[0] != '\0')
11975796c8dcSSimon Schubert         printf_filtered (" (%s)", parent->name);
11985796c8dcSSimon Schubert       printf_filtered ("\n");
11995796c8dcSSimon Schubert     }
12005796c8dcSSimon Schubert   else
12015796c8dcSSimon Schubert     printf_filtered (_("No parent\n"));
12025796c8dcSSimon Schubert 
12035796c8dcSSimon Schubert   /* Print the base priority.  */
12045796c8dcSSimon Schubert   printf_filtered (_("Base Priority: %d\n"), task_info->priority);
12055796c8dcSSimon Schubert 
12065796c8dcSSimon Schubert   /* print the task current state.  */
12075796c8dcSSimon Schubert   {
12085796c8dcSSimon Schubert     int target_taskno = 0;
12095796c8dcSSimon Schubert 
12105796c8dcSSimon Schubert     if (task_info->caller_task)
12115796c8dcSSimon Schubert       {
1212a45ae5f8SJohn Marino         target_taskno = get_task_number_from_id (task_info->caller_task, inf);
12135796c8dcSSimon Schubert         printf_filtered (_("State: Accepting rendezvous with %d"),
12145796c8dcSSimon Schubert                          target_taskno);
12155796c8dcSSimon Schubert       }
12165796c8dcSSimon Schubert     else if (task_info->state == Entry_Caller_Sleep && task_info->called_task)
12175796c8dcSSimon Schubert       {
1218a45ae5f8SJohn Marino         target_taskno = get_task_number_from_id (task_info->called_task, inf);
12195796c8dcSSimon Schubert         printf_filtered (_("State: Waiting on task %d's entry"),
12205796c8dcSSimon Schubert                          target_taskno);
12215796c8dcSSimon Schubert       }
12225796c8dcSSimon Schubert     else
12235796c8dcSSimon Schubert       printf_filtered (_("State: %s"), _(long_task_states[task_info->state]));
12245796c8dcSSimon Schubert 
12255796c8dcSSimon Schubert     if (target_taskno)
12265796c8dcSSimon Schubert       {
12275796c8dcSSimon Schubert         struct ada_task_info *target_task_info =
1228a45ae5f8SJohn Marino           VEC_index (ada_task_info_s, data->task_list, target_taskno - 1);
12295796c8dcSSimon Schubert 
12305796c8dcSSimon Schubert         if (target_task_info->name[0] != '\0')
12315796c8dcSSimon Schubert           printf_filtered (" (%s)", target_task_info->name);
12325796c8dcSSimon Schubert       }
12335796c8dcSSimon Schubert 
12345796c8dcSSimon Schubert     printf_filtered ("\n");
12355796c8dcSSimon Schubert   }
12365796c8dcSSimon Schubert }
12375796c8dcSSimon Schubert 
12385796c8dcSSimon Schubert /* If ARG is empty or null, then print a list of all Ada tasks.
12395796c8dcSSimon Schubert    Otherwise, print detailed information about the task whose ID
12405796c8dcSSimon Schubert    is ARG.
12415796c8dcSSimon Schubert 
12425796c8dcSSimon Schubert    Does nothing if the program doesn't use Ada tasking.  */
12435796c8dcSSimon Schubert 
12445796c8dcSSimon Schubert static void
info_tasks_command(char * arg,int from_tty)12455796c8dcSSimon Schubert info_tasks_command (char *arg, int from_tty)
12465796c8dcSSimon Schubert {
1247a45ae5f8SJohn Marino   struct ui_out *uiout = current_uiout;
12485796c8dcSSimon Schubert 
12495796c8dcSSimon Schubert   if (arg == NULL || *arg == '\0')
1250a45ae5f8SJohn Marino     print_ada_task_info (uiout, NULL, current_inferior ());
12515796c8dcSSimon Schubert   else
1252a45ae5f8SJohn Marino     info_task (uiout, arg, current_inferior ());
12535796c8dcSSimon Schubert }
12545796c8dcSSimon Schubert 
12555796c8dcSSimon Schubert /* Print a message telling the user id of the current task.
12565796c8dcSSimon Schubert    This function assumes that tasking is in use in the inferior.  */
12575796c8dcSSimon Schubert 
12585796c8dcSSimon Schubert static void
display_current_task_id(void)12595796c8dcSSimon Schubert display_current_task_id (void)
12605796c8dcSSimon Schubert {
12615796c8dcSSimon Schubert   const int current_task = ada_get_task_number (inferior_ptid);
12625796c8dcSSimon Schubert 
12635796c8dcSSimon Schubert   if (current_task == 0)
12645796c8dcSSimon Schubert     printf_filtered (_("[Current task is unknown]\n"));
12655796c8dcSSimon Schubert   else
12665796c8dcSSimon Schubert     printf_filtered (_("[Current task is %d]\n"), current_task);
12675796c8dcSSimon Schubert }
12685796c8dcSSimon Schubert 
12695796c8dcSSimon Schubert /* Parse and evaluate TIDSTR into a task id, and try to switch to
12705796c8dcSSimon Schubert    that task.  Print an error message if the task switch failed.  */
12715796c8dcSSimon Schubert 
12725796c8dcSSimon Schubert static void
task_command_1(char * taskno_str,int from_tty,struct inferior * inf)1273a45ae5f8SJohn Marino task_command_1 (char *taskno_str, int from_tty, struct inferior *inf)
12745796c8dcSSimon Schubert {
12755796c8dcSSimon Schubert   const int taskno = value_as_long (parse_and_eval (taskno_str));
12765796c8dcSSimon Schubert   struct ada_task_info *task_info;
1277a45ae5f8SJohn Marino   struct ada_tasks_inferior_data *data = get_ada_tasks_inferior_data (inf);
12785796c8dcSSimon Schubert 
1279a45ae5f8SJohn Marino   if (taskno <= 0 || taskno > VEC_length (ada_task_info_s, data->task_list))
12805796c8dcSSimon Schubert     error (_("Task ID %d not known.  Use the \"info tasks\" command to\n"
12815796c8dcSSimon Schubert              "see the IDs of currently known tasks"), taskno);
1282a45ae5f8SJohn Marino   task_info = VEC_index (ada_task_info_s, data->task_list, taskno - 1);
12835796c8dcSSimon Schubert 
12845796c8dcSSimon Schubert   if (!ada_task_is_alive (task_info))
12855796c8dcSSimon Schubert     error (_("Cannot switch to task %d: Task is no longer running"), taskno);
12865796c8dcSSimon Schubert 
12875796c8dcSSimon Schubert   /* On some platforms, the thread list is not updated until the user
12885796c8dcSSimon Schubert      performs a thread-related operation (by using the "info threads"
12895796c8dcSSimon Schubert      command, for instance).  So this thread list may not be up to date
12905796c8dcSSimon Schubert      when the user attempts this task switch.  Since we cannot switch
12915796c8dcSSimon Schubert      to the thread associated to our task if GDB does not know about
12925796c8dcSSimon Schubert      that thread, we need to make sure that any new threads gets added
12935796c8dcSSimon Schubert      to the thread list.  */
12945796c8dcSSimon Schubert   target_find_new_threads ();
12955796c8dcSSimon Schubert 
1296cf7f2e2dSJohn Marino   /* Verify that the ptid of the task we want to switch to is valid
1297cf7f2e2dSJohn Marino      (in other words, a ptid that GDB knows about).  Otherwise, we will
1298cf7f2e2dSJohn Marino      cause an assertion failure later on, when we try to determine
1299cf7f2e2dSJohn Marino      the ptid associated thread_info data.  We should normally never
1300cf7f2e2dSJohn Marino      encounter such an error, but the wrong ptid can actually easily be
1301cf7f2e2dSJohn Marino      computed if target_get_ada_task_ptid has not been implemented for
1302cf7f2e2dSJohn Marino      our target (yet).  Rather than cause an assertion error in that case,
1303cf7f2e2dSJohn Marino      it's nicer for the user to just refuse to perform the task switch.  */
1304cf7f2e2dSJohn Marino   if (!find_thread_ptid (task_info->ptid))
1305cf7f2e2dSJohn Marino     error (_("Unable to compute thread ID for task %d.\n"
1306cf7f2e2dSJohn Marino              "Cannot switch to this task."),
1307cf7f2e2dSJohn Marino            taskno);
1308cf7f2e2dSJohn Marino 
13095796c8dcSSimon Schubert   switch_to_thread (task_info->ptid);
13105796c8dcSSimon Schubert   ada_find_printable_frame (get_selected_frame (NULL));
13115796c8dcSSimon Schubert   printf_filtered (_("[Switching to task %d]\n"), taskno);
13125796c8dcSSimon Schubert   print_stack_frame (get_selected_frame (NULL),
13135796c8dcSSimon Schubert                      frame_relative_level (get_selected_frame (NULL)), 1);
13145796c8dcSSimon Schubert }
13155796c8dcSSimon Schubert 
13165796c8dcSSimon Schubert 
13175796c8dcSSimon Schubert /* Print the ID of the current task if TASKNO_STR is empty or NULL.
13185796c8dcSSimon Schubert    Otherwise, switch to the task indicated by TASKNO_STR.  */
13195796c8dcSSimon Schubert 
13205796c8dcSSimon Schubert static void
task_command(char * taskno_str,int from_tty)13215796c8dcSSimon Schubert task_command (char *taskno_str, int from_tty)
13225796c8dcSSimon Schubert {
1323a45ae5f8SJohn Marino   struct ui_out *uiout = current_uiout;
13245796c8dcSSimon Schubert 
1325a45ae5f8SJohn Marino   if (ada_build_task_list () == 0)
1326a45ae5f8SJohn Marino     {
1327a45ae5f8SJohn Marino       ui_out_message (uiout, 0,
1328a45ae5f8SJohn Marino 		      _("Your application does not use any Ada tasks.\n"));
13295796c8dcSSimon Schubert       return;
1330a45ae5f8SJohn Marino     }
13315796c8dcSSimon Schubert 
13325796c8dcSSimon Schubert   if (taskno_str == NULL || taskno_str[0] == '\0')
13335796c8dcSSimon Schubert     display_current_task_id ();
13345796c8dcSSimon Schubert   else
13355796c8dcSSimon Schubert     {
13365796c8dcSSimon Schubert       /* Task switching in core files doesn't work, either because:
13375796c8dcSSimon Schubert            1. Thread support is not implemented with core files
13385796c8dcSSimon Schubert            2. Thread support is implemented, but the thread IDs created
13395796c8dcSSimon Schubert               after having read the core file are not the same as the ones
13405796c8dcSSimon Schubert               that were used during the program life, before the crash.
13415796c8dcSSimon Schubert               As a consequence, there is no longer a way for the debugger
13425796c8dcSSimon Schubert               to find the associated thead ID of any given Ada task.
13435796c8dcSSimon Schubert          So, instead of attempting a task switch without giving the user
13445796c8dcSSimon Schubert          any clue as to what might have happened, just error-out with
13455796c8dcSSimon Schubert          a message explaining that this feature is not supported.  */
13465796c8dcSSimon Schubert       if (!target_has_execution)
13475796c8dcSSimon Schubert         error (_("\
13485796c8dcSSimon Schubert Task switching not supported when debugging from core files\n\
13495796c8dcSSimon Schubert (use thread support instead)"));
1350a45ae5f8SJohn Marino       task_command_1 (taskno_str, from_tty, current_inferior ());
13515796c8dcSSimon Schubert     }
13525796c8dcSSimon Schubert }
13535796c8dcSSimon Schubert 
1354a45ae5f8SJohn Marino /* Indicate that the given inferior's task list may have changed,
1355a45ae5f8SJohn Marino    so invalidate the cache.  */
13565796c8dcSSimon Schubert 
13575796c8dcSSimon Schubert static void
ada_task_list_changed(struct inferior * inf)1358a45ae5f8SJohn Marino ada_task_list_changed (struct inferior *inf)
13595796c8dcSSimon Schubert {
1360a45ae5f8SJohn Marino   struct ada_tasks_inferior_data *data = get_ada_tasks_inferior_data (inf);
1361a45ae5f8SJohn Marino 
1362a45ae5f8SJohn Marino   data->task_list_valid_p = 0;
1363a45ae5f8SJohn Marino }
1364a45ae5f8SJohn Marino 
1365a45ae5f8SJohn Marino /* Invalidate the per-program-space data.  */
1366a45ae5f8SJohn Marino 
1367a45ae5f8SJohn Marino static void
ada_tasks_invalidate_pspace_data(struct program_space * pspace)1368a45ae5f8SJohn Marino ada_tasks_invalidate_pspace_data (struct program_space *pspace)
1369a45ae5f8SJohn Marino {
1370a45ae5f8SJohn Marino   get_ada_tasks_pspace_data (pspace)->initialized_p = 0;
1371a45ae5f8SJohn Marino }
1372a45ae5f8SJohn Marino 
1373a45ae5f8SJohn Marino /* Invalidate the per-inferior data.  */
1374a45ae5f8SJohn Marino 
1375a45ae5f8SJohn Marino static void
ada_tasks_invalidate_inferior_data(struct inferior * inf)1376a45ae5f8SJohn Marino ada_tasks_invalidate_inferior_data (struct inferior *inf)
1377a45ae5f8SJohn Marino {
1378a45ae5f8SJohn Marino   struct ada_tasks_inferior_data *data = get_ada_tasks_inferior_data (inf);
1379a45ae5f8SJohn Marino 
1380a45ae5f8SJohn Marino   data->known_tasks_kind = ADA_TASKS_UNKNOWN;
1381a45ae5f8SJohn Marino   data->task_list_valid_p = 0;
13825796c8dcSSimon Schubert }
13835796c8dcSSimon Schubert 
13845796c8dcSSimon Schubert /* The 'normal_stop' observer notification callback.  */
13855796c8dcSSimon Schubert 
13865796c8dcSSimon Schubert static void
ada_normal_stop_observer(struct bpstats * unused_args,int unused_args2)13875796c8dcSSimon Schubert ada_normal_stop_observer (struct bpstats *unused_args, int unused_args2)
13885796c8dcSSimon Schubert {
13895796c8dcSSimon Schubert   /* The inferior has been resumed, and just stopped. This means that
13905796c8dcSSimon Schubert      our task_list needs to be recomputed before it can be used again.  */
1391a45ae5f8SJohn Marino   ada_task_list_changed (current_inferior ());
13925796c8dcSSimon Schubert }
13935796c8dcSSimon Schubert 
13945796c8dcSSimon Schubert /* A routine to be called when the objfiles have changed.  */
13955796c8dcSSimon Schubert 
13965796c8dcSSimon Schubert static void
ada_new_objfile_observer(struct objfile * objfile)13975796c8dcSSimon Schubert ada_new_objfile_observer (struct objfile *objfile)
13985796c8dcSSimon Schubert {
1399a45ae5f8SJohn Marino   struct inferior *inf;
14005796c8dcSSimon Schubert 
1401a45ae5f8SJohn Marino   /* Invalidate the relevant data in our program-space data.  */
14025796c8dcSSimon Schubert 
1403a45ae5f8SJohn Marino   if (objfile == NULL)
1404a45ae5f8SJohn Marino     {
1405a45ae5f8SJohn Marino       /* All objfiles are being cleared, so we should clear all
1406a45ae5f8SJohn Marino 	 our caches for all program spaces.  */
1407a45ae5f8SJohn Marino       struct program_space *pspace;
1408a45ae5f8SJohn Marino 
1409a45ae5f8SJohn Marino       for (pspace = program_spaces; pspace != NULL; pspace = pspace->next)
1410a45ae5f8SJohn Marino         ada_tasks_invalidate_pspace_data (pspace);
1411a45ae5f8SJohn Marino     }
1412a45ae5f8SJohn Marino   else
1413a45ae5f8SJohn Marino     {
1414a45ae5f8SJohn Marino       /* The associated program-space data might have changed after
1415a45ae5f8SJohn Marino 	 this objfile was added.  Invalidate all cached data.  */
1416a45ae5f8SJohn Marino       ada_tasks_invalidate_pspace_data (objfile->pspace);
1417a45ae5f8SJohn Marino     }
1418a45ae5f8SJohn Marino 
1419a45ae5f8SJohn Marino   /* Invalidate the per-inferior cache for all inferiors using
1420a45ae5f8SJohn Marino      this objfile (or, in other words, for all inferiors who have
1421a45ae5f8SJohn Marino      the same program-space as the objfile's program space).
1422a45ae5f8SJohn Marino      If all objfiles are being cleared (OBJFILE is NULL), then
1423a45ae5f8SJohn Marino      clear the caches for all inferiors.  */
1424a45ae5f8SJohn Marino 
1425a45ae5f8SJohn Marino   for (inf = inferior_list; inf != NULL; inf = inf->next)
1426a45ae5f8SJohn Marino     if (objfile == NULL || inf->pspace == objfile->pspace)
1427a45ae5f8SJohn Marino       ada_tasks_invalidate_inferior_data (inf);
14285796c8dcSSimon Schubert }
14295796c8dcSSimon Schubert 
14305796c8dcSSimon Schubert /* Provide a prototype to silence -Wmissing-prototypes.  */
14315796c8dcSSimon Schubert extern initialize_file_ftype _initialize_tasks;
14325796c8dcSSimon Schubert 
14335796c8dcSSimon Schubert void
_initialize_tasks(void)14345796c8dcSSimon Schubert _initialize_tasks (void)
14355796c8dcSSimon Schubert {
1436a45ae5f8SJohn Marino   ada_tasks_pspace_data_handle = register_program_space_data ();
1437a45ae5f8SJohn Marino   ada_tasks_inferior_data_handle = register_inferior_data ();
1438a45ae5f8SJohn Marino 
14395796c8dcSSimon Schubert   /* Attach various observers.  */
14405796c8dcSSimon Schubert   observer_attach_normal_stop (ada_normal_stop_observer);
14415796c8dcSSimon Schubert   observer_attach_new_objfile (ada_new_objfile_observer);
14425796c8dcSSimon Schubert 
14435796c8dcSSimon Schubert   /* Some new commands provided by this module.  */
14445796c8dcSSimon Schubert   add_info ("tasks", info_tasks_command,
14455796c8dcSSimon Schubert             _("Provide information about all known Ada tasks"));
14465796c8dcSSimon Schubert   add_cmd ("task", class_run, task_command,
14475796c8dcSSimon Schubert            _("Use this command to switch between Ada tasks.\n\
14485796c8dcSSimon Schubert Without argument, this command simply prints the current task ID"),
14495796c8dcSSimon Schubert            &cmdlist);
14505796c8dcSSimon Schubert }
14515796c8dcSSimon Schubert 
1452