-/* Copyright (C) 1992, 1993, 1994, 1997, 1998, 1999, 2000, 2003, 2004,
- 2005, 2007, 2008 Free Software Foundation, Inc.
+/* Copyright (C) 1992, 1993, 1994, 1997, 1998, 1999, 2000, 2003, 2004, 2005,
+ 2007, 2008, 2009, 2010, 2011 Free Software Foundation, Inc.
This file is part of GDB.
Block of each task is stored. */
#define KNOWN_TASKS_NAME "system__tasking__debug__known_tasks"
-/* The maximum number of tasks known to the Ada runtime */
+/* The maximum number of tasks known to the Ada runtime. */
static const int MAX_NUMBER_OF_KNOWN_TASKS = 1000;
enum task_states
Timer_Server_Sleep,
AST_Server_Sleep,
Asynchronous_Hold,
- Interrupt_Server_Blocked_On_Event_Flag
+ Interrupt_Server_Blocked_On_Event_Flag,
+ Activating,
+ Acceptor_Delay_Sleep
};
/* A short description corresponding to each possible task state. */
N_("Runnable"),
N_("Terminated"),
N_("Child Activation Wait"),
- N_("Accept Statement"),
+ N_("Accept or Select Term"),
N_("Waiting on entry call"),
N_("Async Select Wait"),
N_("Delay Sleep"),
"",
"",
N_("Asynchronous Hold"),
- ""
+ "",
+ N_("Activating"),
+ N_("Selective Wait")
};
/* A longer description corresponding to each possible task state. */
N_("Runnable"),
N_("Terminated"),
N_("Waiting for child activation"),
- N_("Blocked in accept statement"),
+ N_("Blocked in accept or select with terminate"),
N_("Waiting on entry call"),
N_("Asynchronous Selective Wait"),
N_("Delay Sleep"),
"",
"",
N_("Asynchronous Hold"),
- ""
+ "",
+ N_("Activating"),
+ N_("Blocked in selective wait statement")
};
/* The index of certain important fields in the Ada Task Control Block
};
/* The type description for the ATCB record and subrecords, and
- the associated tcb_fieldnos. For efficiency reasons, these are made
+ the associated tcb_fieldnos. For efficiency reasons, these are made
static globals so that we can compute them only once the first time
and reuse them later. Set to NULL if the types haven't been computed
yet, or if they may be obsolete (for instance after having loaded
int
valid_task_id (int task_num)
{
+ ada_build_task_list (0);
return (task_num > 0
&& task_num <= VEC_length (ada_task_info_s, task_list));
}
-/* Return the task info associated to the Environment Task.
- This function assumes that the inferior does in fact use tasking. */
+/* Return non-zero iff the task STATE corresponds to a non-terminated
+ task state. */
-struct ada_task_info *
-ada_get_environment_task (void)
+static int
+ada_task_is_alive (struct ada_task_info *task_info)
{
- ada_build_task_list (0);
- gdb_assert (VEC_length (ada_task_info_s, task_list) > 0);
-
- /* We use a little bit of insider knowledge to determine which task
- is the Environment Task: We know that this task is created first,
- and thus should always be task #1, which is at index 0 of the
- TASK_LIST. */
- return (VEC_index (ada_task_info_s, task_list, 0));
+ return (task_info->state != Terminated);
}
/* Call the ITERATOR function once for each Ada task that hasn't been
/* Extract LEN characters from the fat string. */
array_val = value_ind (value_field (val, array_fieldno));
- read_memory (VALUE_ADDRESS (array_val), dest, len);
+ read_memory (value_address (array_val), dest, len);
/* Add the NUL character to close the string. */
dest[len] = '\0';
In order to provide a fast response time, this function caches
the Known_Tasks array address after the lookup during the first
- call. Subsequent calls will simply return this cached address. */
+ call. Subsequent calls will simply return this cached address. */
static CORE_ADDR
get_known_tasks_addr (void)
if (ada_tasks_check_symbol_table)
{
- struct symbol *sym;
struct minimal_symbol *msym;
msym = lookup_minimal_symbol (KNOWN_TASKS_NAME, NULL, NULL);
/* FIXME: brobecker 2003-03-05: Here would be a much better place
to attach the ada-tasks observers, instead of doing this
- unconditionaly in _initialize_tasks. This would avoid an
+ unconditionaly in _initialize_tasks. This would avoid an
unecessary notification when the inferior does not use tasking
or as long as the user does not use the ada-tasks commands.
Unfortunately, this is not possible for the moment: the current
code resets ada__tasks_check_symbol_table back to 1 whenever
- symbols for a new program are being loaded. If we place the
+ symbols for a new program are being loaded. If we place the
observers intialization here, we will end up adding new observers
everytime we do the check for Ada tasking-related symbols
- above. This would currently have benign effects, but is still
- undesirable. The cleanest approach is probably to create a new
+ above. This would currently have benign effects, but is still
+ undesirable. The cleanest approach is probably to create a new
observer to notify us when the user is debugging a new program.
We would then reset ada__tasks_check_symbol_table back to 1
during the notification, but also detach all observers.
BTW: observers are probably not reentrant, so detaching during
- a notification may not be the safest thing to do... Sigh...
+ a notification may not be the safest thing to do... Sigh...
But creating the new observer would be a good idea in any case,
since this allow us to make ada__tasks_check_symbol_table
static, which is a good bonus. */
const char *private_data_name = "system__task_primitives__private_data";
const char *entry_call_record_name = "system__tasking__entry_call_record";
+ /* ATCB symbols may be found in several compilation units. As we
+ are only interested in one instance, use standard (literal,
+ C-like) lookups to get the first match. */
+
struct symbol *atcb_sym =
- lookup_symbol (atcb_name, NULL, VAR_DOMAIN, NULL);
+ lookup_symbol_in_language (atcb_name, NULL, VAR_DOMAIN,
+ language_c, NULL);
const struct symbol *common_atcb_sym =
- lookup_symbol (common_atcb_name, NULL, VAR_DOMAIN, NULL);
+ lookup_symbol_in_language (common_atcb_name, NULL, VAR_DOMAIN,
+ language_c, NULL);
const struct symbol *private_data_sym =
- lookup_symbol (private_data_name, NULL, VAR_DOMAIN, NULL);
+ lookup_symbol_in_language (private_data_name, NULL, VAR_DOMAIN,
+ language_c, NULL);
const struct symbol *entry_call_record_sym =
- lookup_symbol (entry_call_record_name, NULL, VAR_DOMAIN, NULL);
+ lookup_symbol_in_language (entry_call_record_name, NULL, VAR_DOMAIN,
+ language_c, NULL);
if (atcb_sym == NULL || atcb_sym->type == NULL)
{
/* In Ravenscar run-time libs, the ATCB does not have a dynamic
size, so the symbol name differs. */
- atcb_sym = lookup_symbol (atcb_name_fixed, NULL, VAR_DOMAIN, NULL);
+ atcb_sym = lookup_symbol_in_language (atcb_name_fixed, NULL, VAR_DOMAIN,
+ language_c, NULL);
if (atcb_sym == NULL || atcb_sym->type == NULL)
error (_("Cannot find Ada_Task_Control_Block type. Aborting"));
Depending on the GNAT version used, the task image is either a fat
string, or a thin array of characters. Older versions of GNAT used
to use fat strings, and therefore did not need an extra field in
- the ATCB to store the string length. For efficiency reasons, newer
+ the ATCB to store the string length. For efficiency reasons, newer
versions of GNAT replaced the fat string by a static buffer, but this
also required the addition of a new field named "Image_Len" containing
- the length of the task name. The method used to extract the task name
+ the length of the task name. The method used to extract the task name
is selected depending on the existence of this field.
In some run-time libs (e.g. Ravenscar), the name is not in the ATCB;
- we may want to get it from the first user frame of the stack. For now,
+ we may want to get it from the first user frame of the stack. For now,
we just give a dummy name. */
if (fieldno.image_len == -1)
ada_coerce_to_simple_array_ptr (value_field (tcb_value,
fieldno.entry_calls));
entry_calls_value_element =
- value_subscript (entry_calls_value, atc_nesting_level_value);
+ value_subscript (entry_calls_value,
+ value_as_long (atc_nesting_level_value));
called_task_fieldno =
ada_get_field_index (value_type (entry_calls_value_element),
"called_task", 0);
}
}
- /* And finally, compute the task ptid. */
-
- if (ada_task_is_alive (task_info))
+ /* And finally, compute the task ptid. Note that there are situations
+ where this cannot be determined:
+ - The task is no longer alive - the ptid is irrelevant;
+ - We are debugging a core file - the thread is not always
+ completely preserved for us to link back a task to its
+ underlying thread. Since we do not support task switching
+ when debugging core files anyway, we don't need to compute
+ that task ptid.
+ In either case, we don't need that ptid, and it is just good enough
+ to set it to null_ptid. */
+
+ if (target_has_execution && ada_task_is_alive (task_info))
task_info->ptid = ptid_from_atcb_common (common_value);
else
task_info->ptid = null_ptid;
read_known_tasks_array (void)
{
const int target_ptr_byte =
- gdbarch_ptr_bit (current_gdbarch) / TARGET_CHAR_BIT;
+ gdbarch_ptr_bit (target_gdbarch) / TARGET_CHAR_BIT;
const CORE_ADDR known_tasks_addr = get_known_tasks_addr ();
const int known_tasks_size = target_ptr_byte * MAX_NUMBER_OF_KNOWN_TASKS;
gdb_byte *known_tasks = alloca (known_tasks_size);
for (i = 0; i < MAX_NUMBER_OF_KNOWN_TASKS; i++)
{
struct type *data_ptr_type =
- builtin_type (current_gdbarch)->builtin_data_ptr;
+ builtin_type (target_gdbarch)->builtin_data_ptr;
CORE_ADDR task_id =
extract_typed_address (known_tasks + i * target_ptr_byte,
data_ptr_type);
return 1;
}
-/* Return non-zero iff the task STATE corresponds to a non-terminated
- task state. */
-
-int
-ada_task_is_alive (struct ada_task_info *task_info)
-{
- return (task_info->state != Terminated);
-}
-
/* Print a one-line description of the task whose number is TASKNO.
The formatting should fit the "info tasks" array. */
else if (task_info->state == Entry_Caller_Sleep && task_info->called_task)
printf_filtered (_(" Waiting on RV with %-3d"),
get_task_number_from_id (task_info->called_task));
- else if (task_info->state == Runnable && active_task_p)
- /* Replace "Runnable" by "Running" since this is the active task. */
- printf_filtered (" %-22s", _("Running"));
else
printf_filtered (" %-22s", _(task_states[task_info->state]));
}
/* Print a list containing a short description of all Ada tasks. */
-/* FIXME: Shouldn't we be using ui_out??? */
+/* FIXME: Shouldn't we be using ui_out??? */
static void
info_tasks (int from_tty)
task_info = VEC_index (ada_task_info_s, task_list, taskno - 1);
/* Print the Ada task ID. */
- printf_filtered (_("Ada Task: %s\n"), paddr_nz (task_info->task_id));
+ printf_filtered (_("Ada Task: %s\n"),
+ paddress (target_gdbarch, task_info->task_id));
/* Print the name of the task. */
if (task_info->name[0] != '\0')
if (!ada_task_is_alive (task_info))
error (_("Cannot switch to task %d: Task is no longer running"), taskno);
+ /* On some platforms, the thread list is not updated until the user
+ performs a thread-related operation (by using the "info threads"
+ command, for instance). So this thread list may not be up to date
+ when the user attempts this task switch. Since we cannot switch
+ to the thread associated to our task if GDB does not know about
+ that thread, we need to make sure that any new threads gets added
+ to the thread list. */
+ target_find_new_threads ();
+
+ /* Verify that the ptid of the task we want to switch to is valid
+ (in other words, a ptid that GDB knows about). Otherwise, we will
+ cause an assertion failure later on, when we try to determine
+ the ptid associated thread_info data. We should normally never
+ encounter such an error, but the wrong ptid can actually easily be
+ computed if target_get_ada_task_ptid has not been implemented for
+ our target (yet). Rather than cause an assertion error in that case,
+ it's nicer for the user to just refuse to perform the task switch. */
+ if (!find_thread_ptid (task_info->ptid))
+ error (_("Unable to compute thread ID for task %d.\n"
+ "Cannot switch to this task."),
+ taskno);
+
switch_to_thread (task_info->ptid);
ada_find_printable_frame (get_selected_frame (NULL));
printf_filtered (_("[Switching to task %d]\n"), taskno);
/* Indicate that the task list may have changed, so invalidate the cache. */
-void
+static void
ada_task_list_changed (void)
{
stale_task_list_p = 1;
/* The 'normal_stop' observer notification callback. */
static void
-ada_normal_stop_observer (struct bpstats *unused_args)
+ada_normal_stop_observer (struct bpstats *unused_args, int unused_args2)
{
/* The inferior has been resumed, and just stopped. This means that
our task_list needs to be recomputed before it can be used again. */
/* A routine to be called when the objfiles have changed. */
-void
+static void
ada_new_objfile_observer (struct objfile *objfile)
{
/* Invalidate all cached data that were extracted from an objfile. */
ada_tasks_check_symbol_table = 1;
}
+/* Provide a prototype to silence -Wmissing-prototypes. */
+extern initialize_file_ftype _initialize_tasks;
+
void
_initialize_tasks (void)
{