+ return 1;
+}
+
+/* Read the known tasks from the inferior memory, and store it in
+ TASK_LIST. Return non-zero upon success. */
+
+static int
+read_known_tasks_list (CORE_ADDR known_tasks_addr)
+{
+ const int target_ptr_byte =
+ gdbarch_ptr_bit (target_gdbarch) / TARGET_CHAR_BIT;
+ gdb_byte *known_tasks = alloca (target_ptr_byte);
+ struct type *data_ptr_type =
+ builtin_type (target_gdbarch)->builtin_data_ptr;
+ CORE_ADDR task_id;
+
+ /* Sanity check. */
+ if (atcb_fieldno.activation_link < 0)
+ return 0;
+
+ /* Build a new list by reading the ATCBs. Read head of the list. */
+ read_memory (known_tasks_addr, known_tasks, target_ptr_byte);
+ task_id = extract_typed_address (known_tasks, data_ptr_type);
+ while (task_id != 0)
+ {
+ struct value *tcb_value;
+ struct value *common_value;
+
+ add_ada_task (task_id);
+
+ /* Read the chain. */
+ tcb_value = value_from_contents_and_address (atcb_type, NULL, task_id);
+ common_value = value_field (tcb_value, atcb_fieldno.common);
+ task_id = value_as_address (value_field (common_value,
+ atcb_fieldno.activation_link));
+ }
+
+ return 1;
+}
+
+/* Return the address of the variable NAME that contains all the known
+ tasks maintained in the Ada Runtime. Return NULL if the variable
+ could not be found, meaning that the inferior program probably does
+ not use tasking. */
+
+static CORE_ADDR
+get_known_tasks_addr (const char *name)
+{
+ struct minimal_symbol *msym;
+
+ msym = lookup_minimal_symbol (name, NULL, NULL);
+ if (msym == NULL)
+ return 0;
+
+ return SYMBOL_VALUE_ADDRESS (msym);
+}
+
+/* Read the known tasks from the inferior memory, and store it in
+ TASK_LIST. Return non-zero upon success. */
+
+static int
+read_known_tasks (void)
+{
+ /* In order to provide a fast response time, this function caches the
+ known tasks addresses after the lookup during the first call. */
+ static CORE_ADDR known_tasks_array_addr;
+ static CORE_ADDR known_tasks_list_addr;
+
+ /* Step 1: Clear the current list, if necessary. */
+ VEC_truncate (ada_task_info_s, task_list, 0);
+
+ /* Step 2: do the real work.
+ If the application does not use task, then no more needs to be done.
+ It is important to have the task list cleared (see above) before we
+ return, as we don't want a stale task list to be used... This can
+ happen for instance when debugging a non-multitasking program after
+ having debugged a multitasking one. */
+ if (ada_tasks_check_symbol_table)
+ {
+ known_tasks_array_addr = get_known_tasks_addr (KNOWN_TASKS_NAME);
+ known_tasks_list_addr = get_known_tasks_addr (KNOWN_TASKS_LIST);
+
+ /* 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
+ 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
+ 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
+ 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...
+ 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. */
+ ada_tasks_check_symbol_table = 0;
+ }
+
+ /* Try both mechanisms. */
+ if ((known_tasks_array_addr == 0
+ || read_known_tasks_array (known_tasks_array_addr) == 0)
+ && (known_tasks_list_addr == 0
+ || read_known_tasks_list (known_tasks_list_addr) == 0))
+ return 0;
+