gdb/tui: fairer distribution of excess space during apply
[binutils-gdb.git] / gdb / ada-tasks.c
index 67aa0c798890aae65c5bbada9635f157ac040681..5622772b013ed6aa3e0228dd7f3d320f0e9bc5ea 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (C) 1992-2019 Free Software Foundation, Inc.
+/* Copyright (C) 1992-2022 Free Software Foundation, Inc.
 
    This file is part of GDB.
 
@@ -64,7 +64,7 @@ enum task_states
 };
 
 /* A short description corresponding to each possible task state.  */
-static const char *task_states[] = {
+static const char * const task_states[] = {
   N_("Unactivated"),
   N_("Runnable"),
   N_("Terminated"),
@@ -86,7 +86,7 @@ static const char *task_states[] = {
 };
 
 /* A longer description corresponding to each possible task state.  */
-static const char *long_task_states[] = {
+static const char * const long_task_states[] = {
   N_("Unactivated"),
   N_("Runnable"),
   N_("Terminated"),
@@ -159,6 +159,10 @@ struct ada_tasks_pspace_data
 
   /* The index of various fields in the ATCB record and sub-records.  */
   struct atcb_fieldnos atcb_fieldno {};
+
+  /* On some systems, gdbserver applies an offset to the CPU that is
+     reported.  */
+  unsigned int cpu_id_offset = 0;
 };
 
 /* Key to our per-program-space data.  */
@@ -203,9 +207,9 @@ struct ada_tasks_inferior_data
      the list of Ada tasks.  The value of this field influences
      the interpretation of the known_tasks_addr field below:
        - ADA_TASKS_UNKNOWN: The value of known_tasks_addr hasn't
-         been determined yet;
+        been determined yet;
        - ADA_TASKS_NOT_FOUND: The program probably does not use tasking
-         and the known_tasks_addr is irrelevant;
+        and the known_tasks_addr is irrelevant;
        - ADA_TASKS_ARRAY: The known_tasks is an array;
        - ADA_TASKS_LIST: The known_tasks is a list.  */
   enum ada_known_tasks_kind known_tasks_kind = ADA_TASKS_UNKNOWN;
@@ -324,7 +328,7 @@ get_task_number_from_id (CORE_ADDR task_id, struct inferior *inf)
   for (int i = 0; i < data->task_list.size (); i++)
     {
       if (data->task_list[i].task_id == task_id)
-        return i + 1;
+       return i + 1;
     }
 
   /* Task not found.  Return 0.  */
@@ -376,7 +380,7 @@ ada_get_task_info_from_ptid (ptid_t ptid)
    terminated yet.  */
 
 void
-iterate_over_live_ada_tasks (ada_task_list_iterator_ftype *iterator)
+iterate_over_live_ada_tasks (ada_task_list_iterator_ftype iterator)
 {
   struct ada_tasks_inferior_data *data;
 
@@ -386,7 +390,7 @@ iterate_over_live_ada_tasks (ada_task_list_iterator_ftype *iterator)
   for (ada_task_info &task : data->task_list)
     {
       if (!ada_task_is_alive (&task))
-        continue;
+       continue;
       iterator (&task);
     }
 }
@@ -397,7 +401,7 @@ iterate_over_live_ada_tasks (ada_task_list_iterator_ftype *iterator)
 static void
 value_as_string (char *dest, struct value *val, int length)
 {
-  memcpy (dest, value_contents (val), length);
+  memcpy (dest, value_contents (val).data (), length);
   dest[length] = '\0';
 }
 
@@ -430,11 +434,11 @@ read_fat_string_value (char *dest, struct value *val, int max_len)
       array_fieldno = ada_get_field_index (type, "P_ARRAY", 0);
       bounds_fieldno = ada_get_field_index (type, "P_BOUNDS", 0);
 
-      bounds_type = TYPE_FIELD_TYPE (type, bounds_fieldno);
-      if (TYPE_CODE (bounds_type) == TYPE_CODE_PTR)
-        bounds_type = TYPE_TARGET_TYPE (bounds_type);
-      if (TYPE_CODE (bounds_type) != TYPE_CODE_STRUCT)
-        error (_("Unknown task name format. Aborting"));
+      bounds_type = type->field (bounds_fieldno).type ();
+      if (bounds_type->code () == TYPE_CODE_PTR)
+       bounds_type = TYPE_TARGET_TYPE (bounds_type);
+      if (bounds_type->code () != TYPE_CODE_STRUCT)
+       error (_("Unknown task name format. Aborting"));
       upper_bound_fieldno = ada_get_field_index (bounds_type, "UB0", 0);
 
       initialize_fieldnos = 0;
@@ -499,42 +503,42 @@ ada_get_tcb_types_info (void)
     lookup_symbol_in_language (entry_call_record_name, NULL, STRUCT_DOMAIN,
                               language_c, NULL).symbol;
 
-  if (atcb_sym == NULL || atcb_sym->type == 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.  */
+        size, so the symbol name differs.  */
       atcb_sym = lookup_symbol_in_language (atcb_name_fixed, NULL,
                                            STRUCT_DOMAIN, language_c,
                                            NULL).symbol;
 
-      if (atcb_sym == NULL || atcb_sym->type == NULL)
-        return _("Cannot find Ada_Task_Control_Block type");
+      if (atcb_sym == NULL || atcb_sym->type () == NULL)
+       return _("Cannot find Ada_Task_Control_Block type");
 
-      type = atcb_sym->type;
+      type = atcb_sym->type ();
     }
   else
     {
       /* Get a static representation of the type record
-         Ada_Task_Control_Block.  */
-      type = atcb_sym->type;
+        Ada_Task_Control_Block.  */
+      type = atcb_sym->type ();
       type = ada_template_to_fixed_record_type_1 (type, NULL, 0, NULL, 0);
     }
 
-  if (common_atcb_sym == NULL || common_atcb_sym->type == NULL)
+  if (common_atcb_sym == NULL || common_atcb_sym->type () == NULL)
     return _("Cannot find Common_ATCB type");
-  if (private_data_sym == NULL || private_data_sym->type == NULL)
+  if (private_data_sym == NULL || private_data_sym->type ()== NULL)
     return _("Cannot find Private_Data type");
-  if (entry_call_record_sym == NULL || entry_call_record_sym->type == NULL)
+  if (entry_call_record_sym == NULL || entry_call_record_sym->type () == NULL)
     return _("Cannot find Entry_Call_Record type");
 
   /* Get the type for Ada_Task_Control_Block.Common.  */
-  common_type = common_atcb_sym->type;
+  common_type = common_atcb_sym->type ();
 
   /* Get the type for Ada_Task_Control_Bloc.Common.Call.LL.  */
-  ll_type = private_data_sym->type;
+  ll_type = private_data_sym->type ();
 
   /* Get the type for Common_ATCB.Call.all.  */
-  call_type = entry_call_record_sym->type;
+  call_type = entry_call_record_sym->type ();
 
   /* Get the field indices.  */
   fieldnos.common = ada_get_field_index (type, "common", 0);
@@ -547,7 +551,7 @@ ada_get_tcb_types_info (void)
   fieldnos.image = ada_get_field_index (common_type, "task_image", 1);
   fieldnos.image_len = ada_get_field_index (common_type, "task_image_len", 1);
   fieldnos.activation_link = ada_get_field_index (common_type,
-                                                  "activation_link", 1);
+                                                 "activation_link", 1);
   fieldnos.call = ada_get_field_index (common_type, "call", 1);
   fieldnos.ll = ada_get_field_index (common_type, "ll", 0);
   fieldnos.base_cpu = ada_get_field_index (common_type, "base_cpu", 0);
@@ -564,6 +568,18 @@ ada_get_tcb_types_info (void)
   if (fieldnos.ll_lwp < 0)
     fieldnos.ll_lwp = ada_get_field_index (ll_type, "thread_id", 1);
 
+  /* Check for the CPU offset.  */
+  bound_minimal_symbol first_id_sym
+    = lookup_bound_minimal_symbol ("__gnat_gdb_cpu_first_id");
+  unsigned int first_id = 0;
+  if (first_id_sym.minsym != nullptr)
+    {
+      CORE_ADDR addr = BMSYMBOL_VALUE_ADDRESS (first_id_sym);
+      /* This symbol always has type uint32_t.  */
+      struct type *u32type = builtin_type (target_gdbarch ())->builtin_uint32;
+      first_id = value_as_long (value_at (u32type, addr));
+    }
+
   /* Set all the out parameters all at once, now that we are certain
      that there are no potential error() anymore.  */
   pspace_data = get_ada_tasks_pspace_data (current_program_space);
@@ -573,6 +589,7 @@ ada_get_tcb_types_info (void)
   pspace_data->atcb_ll_type = ll_type;
   pspace_data->atcb_call_type = call_type;
   pspace_data->atcb_fieldno = fieldnos;
+  pspace_data->cpu_id_offset = first_id;
   return NULL;
 }
 
@@ -583,7 +600,7 @@ ada_get_tcb_types_info (void)
 static ptid_t
 ptid_from_atcb_common (struct value *common_value)
 {
-  long thread = 0;
+  ULONGEST thread;
   CORE_ADDR lwp = 0;
   struct value *ll_value;
   ptid_t ptid;
@@ -658,10 +675,10 @@ read_atcb (CORE_ADDR task_id, struct ada_task_info *task_info)
   if (pspace_data->atcb_fieldno.image_len == -1)
     {
       if (pspace_data->atcb_fieldno.image >= 0)
-        read_fat_string_value (task_info->name,
-                               value_field (common_value,
+       read_fat_string_value (task_info->name,
+                              value_field (common_value,
                                            pspace_data->atcb_fieldno.image),
-                               sizeof (task_info->name) - 1);
+                              sizeof (task_info->name) - 1);
       else
        {
          struct bound_minimal_symbol msym;
@@ -679,7 +696,8 @@ read_atcb (CORE_ADDR task_id, struct ada_task_info *task_info)
                  task_name = p + 2;
 
              /* Copy the task name.  */
-             strncpy (task_info->name, task_name, sizeof (task_info->name));
+             strncpy (task_info->name, task_name,
+                      sizeof (task_info->name) - 1);
              task_info->name[sizeof (task_info->name) - 1] = 0;
            }
          else
@@ -696,7 +714,7 @@ read_atcb (CORE_ADDR task_id, struct ada_task_info *task_info)
                                pspace_data->atcb_fieldno.image_len));
 
       value_as_string (task_info->name,
-                       value_field (common_value,
+                      value_field (common_value,
                                    pspace_data->atcb_fieldno.image),
                       len);
     }
@@ -726,22 +744,22 @@ read_atcb (CORE_ADDR task_id, struct ada_task_info *task_info)
       && pspace_data->atcb_fieldno.entry_calls > 0)
     {
       /* Let My_ATCB be the Ada task control block of a task calling the
-         entry of another task; then the Task_Id of the called task is
-         in My_ATCB.Entry_Calls (My_ATCB.ATC_Nesting_Level).Called_Task.  */
+        entry of another task; then the Task_Id of the called task is
+        in My_ATCB.Entry_Calls (My_ATCB.ATC_Nesting_Level).Called_Task.  */
       atc_nesting_level_value =
-        value_field (tcb_value, pspace_data->atcb_fieldno.atc_nesting_level);
+       value_field (tcb_value, pspace_data->atcb_fieldno.atc_nesting_level);
       entry_calls_value =
-        ada_coerce_to_simple_array_ptr
+       ada_coerce_to_simple_array_ptr
          (value_field (tcb_value, pspace_data->atcb_fieldno.entry_calls));
       entry_calls_value_element =
-        value_subscript (entry_calls_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);
+       ada_get_field_index (value_type (entry_calls_value_element),
+                            "called_task", 0);
       task_info->called_task =
-        value_as_address (value_field (entry_calls_value_element,
-                                       called_task_fieldno));
+       value_as_address (value_field (entry_calls_value_element,
+                                      called_task_fieldno));
     }
 
   /* If the ATCB contains some information about RV callers, then
@@ -750,26 +768,27 @@ read_atcb (CORE_ADDR task_id, struct ada_task_info *task_info)
   if (pspace_data->atcb_fieldno.call >= 0)
     {
       /* Get the ID of the caller task from Common_ATCB.Call.all.Self.
-         If Common_ATCB.Call is null, then there is no caller.  */
+        If Common_ATCB.Call is null, then there is no caller.  */
       const CORE_ADDR call =
-        value_as_address (value_field (common_value,
+       value_as_address (value_field (common_value,
                                       pspace_data->atcb_fieldno.call));
       struct value *call_val;
 
       if (call != 0)
-        {
-          call_val =
-            value_from_contents_and_address (pspace_data->atcb_call_type,
+       {
+         call_val =
+           value_from_contents_and_address (pspace_data->atcb_call_type,
                                             NULL, call);
-          task_info->caller_task =
-            value_as_address
+         task_info->caller_task =
+           value_as_address
              (value_field (call_val, pspace_data->atcb_fieldno.call_self));
-        }
+       }
     }
 
   task_info->base_cpu
-    = value_as_long (value_field (common_value,
-                                 pspace_data->atcb_fieldno.base_cpu));
+    = (pspace_data->cpu_id_offset
+      + value_as_long (value_field (common_value,
+                                   pspace_data->atcb_fieldno.base_cpu)));
 
   /* And finally, compute the task ptid.  Note that there is not point
      in computing it if the task is no longer alive, in which case
@@ -810,11 +829,11 @@ read_known_tasks_array (struct ada_tasks_inferior_data *data)
   for (i = 0; i < data->known_tasks_length; i++)
     {
       CORE_ADDR task_id =
-        extract_typed_address (known_tasks + i * target_ptr_byte,
+       extract_typed_address (known_tasks + i * target_ptr_byte,
                               data->known_tasks_element);
 
       if (task_id != 0)
-        add_ada_task (task_id, current_inferior ());
+       add_ada_task (task_id, current_inferior ());
     }
 
   return true;
@@ -852,7 +871,7 @@ read_known_tasks_list (struct ada_tasks_inferior_data *data)
       common_value = value_field (tcb_value, pspace_data->atcb_fieldno.common);
       task_id = value_as_address
                  (value_field (common_value,
-                                pspace_data->atcb_fieldno.activation_link));
+                               pspace_data->atcb_fieldno.activation_link));
     }
 
   return true;
@@ -885,22 +904,23 @@ ada_tasks_inferior_data_sniffer (struct ada_tasks_inferior_data *data)
       if (sym != NULL)
        {
          /* Validate.  */
-         struct type *type = check_typedef (SYMBOL_TYPE (sym));
+         struct type *type = check_typedef (sym->type ());
          struct type *eltype = NULL;
          struct type *idxtype = NULL;
 
-         if (TYPE_CODE (type) == TYPE_CODE_ARRAY)
+         if (type->code () == TYPE_CODE_ARRAY)
            eltype = check_typedef (TYPE_TARGET_TYPE (type));
          if (eltype != NULL
-             && TYPE_CODE (eltype) == TYPE_CODE_PTR)
-           idxtype = check_typedef (TYPE_INDEX_TYPE (type));
+             && eltype->code () == TYPE_CODE_PTR)
+           idxtype = check_typedef (type->index_type ());
          if (idxtype != NULL
-             && !TYPE_LOW_BOUND_UNDEFINED (idxtype)
-             && !TYPE_HIGH_BOUND_UNDEFINED (idxtype))
+             && idxtype->bounds ()->low.kind () != PROP_UNDEFINED
+             && idxtype->bounds ()->high.kind () != PROP_UNDEFINED)
            {
              data->known_tasks_element = eltype;
              data->known_tasks_length =
-               TYPE_HIGH_BOUND (idxtype) - TYPE_LOW_BOUND (idxtype) + 1;
+               (idxtype->bounds ()->high.const_val ()
+                - idxtype->bounds ()->low.const_val () + 1);
              return;
            }
        }
@@ -930,9 +950,9 @@ ada_tasks_inferior_data_sniffer (struct ada_tasks_inferior_data *data)
       if (sym != NULL && SYMBOL_VALUE_ADDRESS (sym) != 0)
        {
          /* Validate.  */
-         struct type *type = check_typedef (SYMBOL_TYPE (sym));
+         struct type *type = check_typedef (sym->type ());
 
-         if (TYPE_CODE (type) == TYPE_CODE_PTR)
+         if (type->code () == TYPE_CODE_PTR)
            {
              data->known_tasks_element = type;
              return;
@@ -997,7 +1017,7 @@ ada_build_task_list ()
 {
   struct ada_tasks_inferior_data *data;
 
-  if (!target_has_stack)
+  if (!target_has_stack ())
     error (_("Cannot inspect Ada tasks when program is not running"));
 
   data = get_ada_tasks_inferior_data (current_inferior ());
@@ -1106,12 +1126,12 @@ print_ada_task_info (struct ui_out *uiout,
         to one task only, and this is not the task, skip
         to the next one.  */
       if (taskno_arg && taskno != taskno_arg)
-        continue;
+       continue;
 
       ui_out_emit_tuple tuple_emitter (uiout, NULL);
 
       /* Print a star if this task is the current task (or the task
-         currently selected).  */
+        currently selected).  */
       if (task_info->ptid == inferior_ptid)
        uiout->field_string ("current", "*");
       else
@@ -1126,9 +1146,9 @@ print_ada_task_info (struct ui_out *uiout,
 
       /* Print the associated Thread ID.  */
       if (uiout->is_mi_like_p ())
-        {
+       {
          thread_info *thread = (ada_task_is_alive (task_info)
-                                ? find_thread_ptid (task_info->ptid)
+                                ? find_thread_ptid (inf, task_info->ptid)
                                 : nullptr);
 
          if (thread != NULL)
@@ -1143,9 +1163,9 @@ print_ada_task_info (struct ui_out *uiout,
       /* Print the ID of the parent task.  */
       parent_id = get_task_number_from_id (task_info->parent, inf);
       if (parent_id)
-        uiout->field_signed ("parent-id", parent_id);
+       uiout->field_signed ("parent-id", parent_id);
       else
-        uiout->field_skip ("parent-id");
+       uiout->field_skip ("parent-id");
 
       /* Print the base priority of the task.  */
       uiout->field_signed ("priority", task_info->priority);
@@ -1166,7 +1186,7 @@ print_ada_task_info (struct ui_out *uiout,
 
       /* Finally, print the task name, without quotes around it, as mi like
         is not expecting quotes, and in non mi-like no need for quotes
-         as there is a specific column for the name.  */
+        as there is a specific column for the name.  */
       uiout->field_fmt ("name",
                        (task_info->name[0] != '\0'
                         ? ui_file_style ()
@@ -1199,26 +1219,27 @@ info_task (struct ui_out *uiout, const char *taskno_str, struct inferior *inf)
 
   if (taskno <= 0 || taskno > data->task_list.size ())
     error (_("Task ID %d not known.  Use the \"info tasks\" command to\n"
-             "see the IDs of currently known tasks"), taskno);
+            "see the IDs of currently known tasks"), taskno);
   task_info = &data->task_list[taskno - 1];
 
   /* Print the Ada task ID.  */
-  printf_filtered (_("Ada Task: %s\n"),
-                  paddress (target_gdbarch (), task_info->task_id));
+  gdb_printf (_("Ada Task: %s\n"),
+             paddress (target_gdbarch (), task_info->task_id));
 
   /* Print the name of the task.  */
   if (task_info->name[0] != '\0')
-    printf_filtered (_("Name: %s\n"), task_info->name);
+    gdb_printf (_("Name: %s\n"), task_info->name);
   else
     fprintf_styled (gdb_stdout, metadata_style.style (), _("<no name>\n"));
 
   /* Print the TID and LWP.  */
-  printf_filtered (_("Thread: %#lx\n"), task_info->ptid.tid ());
-  printf_filtered (_("LWP: %#lx\n"), task_info->ptid.lwp ());
+  gdb_printf (_("Thread: 0x%s\n"), phex_nz (task_info->ptid.tid (),
+                                           sizeof (ULONGEST)));
+  gdb_printf (_("LWP: %#lx\n"), task_info->ptid.lwp ());
 
   /* If set, print the base CPU.  */
   if (task_info->base_cpu != 0)
-    printf_filtered (_("Base CPU: %d\n"), task_info->base_cpu);
+    gdb_printf (_("Base CPU: %d\n"), task_info->base_cpu);
 
   /* Print who is the parent (if any).  */
   if (task_info->parent != 0)
@@ -1227,16 +1248,16 @@ info_task (struct ui_out *uiout, const char *taskno_str, struct inferior *inf)
     {
       struct ada_task_info *parent = &data->task_list[parent_taskno - 1];
 
-      printf_filtered (_("Parent: %d"), parent_taskno);
+      gdb_printf (_("Parent: %d"), parent_taskno);
       if (parent->name[0] != '\0')
-        printf_filtered (" (%s)", parent->name);
-      printf_filtered ("\n");
+       gdb_printf (" (%s)", parent->name);
+      gdb_printf ("\n");
     }
   else
-    printf_filtered (_("No parent\n"));
+    gdb_printf (_("No parent\n"));
 
   /* Print the base priority.  */
-  printf_filtered (_("Base Priority: %d\n"), task_info->priority);
+  gdb_printf (_("Base Priority: %d\n"), task_info->priority);
 
   /* print the task current state.  */
   {
@@ -1244,28 +1265,28 @@ info_task (struct ui_out *uiout, const char *taskno_str, struct inferior *inf)
 
     if (task_info->caller_task)
       {
-        target_taskno = get_task_number_from_id (task_info->caller_task, inf);
-        printf_filtered (_("State: Accepting rendezvous with %d"),
-                         target_taskno);
+       target_taskno = get_task_number_from_id (task_info->caller_task, inf);
+       gdb_printf (_("State: Accepting rendezvous with %d"),
+                   target_taskno);
       }
     else if (task_info->called_task)
       {
-        target_taskno = get_task_number_from_id (task_info->called_task, inf);
-        printf_filtered (_("State: Waiting on task %d's entry"),
-                         target_taskno);
+       target_taskno = get_task_number_from_id (task_info->called_task, inf);
+       gdb_printf (_("State: Waiting on task %d's entry"),
+                   target_taskno);
       }
     else
-      printf_filtered (_("State: %s"), _(long_task_states[task_info->state]));
+      gdb_printf (_("State: %s"), _(long_task_states[task_info->state]));
 
     if (target_taskno)
       {
-        ada_task_info *target_task_info = &data->task_list[target_taskno - 1];
+       ada_task_info *target_task_info = &data->task_list[target_taskno - 1];
 
-        if (target_task_info->name[0] != '\0')
-          printf_filtered (" (%s)", target_task_info->name);
+       if (target_task_info->name[0] != '\0')
+         gdb_printf (" (%s)", target_task_info->name);
       }
 
-    printf_filtered ("\n");
+    gdb_printf ("\n");
   }
 }
 
@@ -1295,15 +1316,15 @@ display_current_task_id (void)
   const int current_task = ada_get_task_number (inferior_thread ());
 
   if (current_task == 0)
-    printf_filtered (_("[Current task is unknown]\n"));
+    gdb_printf (_("[Current task is unknown]\n"));
   else
     {
       struct ada_tasks_inferior_data *data
        = get_ada_tasks_inferior_data (current_inferior ());
       struct ada_task_info *task_info = &data->task_list[current_task - 1];
 
-      printf_filtered (_("[Current task is %s]\n"),
-                      task_to_str (current_task, task_info).c_str ());
+      gdb_printf (_("[Current task is %s]\n"),
+                 task_to_str (current_task, task_info).c_str ());
     }
 }
 
@@ -1319,7 +1340,7 @@ task_command_1 (const char *taskno_str, int from_tty, struct inferior *inf)
 
   if (taskno <= 0 || taskno > data->task_list.size ())
     error (_("Task ID %d not known.  Use the \"info tasks\" command to\n"
-             "see the IDs of currently known tasks"), taskno);
+            "see the IDs of currently known tasks"), taskno);
   task_info = &data->task_list[taskno - 1];
 
   if (!ada_task_is_alive (task_info))
@@ -1343,18 +1364,18 @@ task_command_1 (const char *taskno_str, int from_tty, struct inferior *inf)
      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.  */
-  thread_info *tp = find_thread_ptid (task_info->ptid);
+  thread_info *tp = find_thread_ptid (inf, task_info->ptid);
   if (tp == NULL)
     error (_("Unable to compute thread ID for task %s.\n"
-             "Cannot switch to this task."),
-           task_to_str (taskno, task_info).c_str ());
+            "Cannot switch to this task."),
+          task_to_str (taskno, task_info).c_str ());
 
   switch_to_thread (tp);
   ada_find_printable_frame (get_selected_frame (NULL));
-  printf_filtered (_("[Switching to task %s]\n"),
-                  task_to_str (taskno, task_info).c_str ());
+  gdb_printf (_("[Switching to task %s]\n"),
+             task_to_str (taskno, task_info).c_str ());
   print_stack_frame (get_selected_frame (NULL),
-                     frame_relative_level (get_selected_frame (NULL)),
+                    frame_relative_level (get_selected_frame (NULL)),
                     SRC_AND_LOC, 1);
 }
 
@@ -1412,7 +1433,7 @@ ada_tasks_invalidate_inferior_data (struct inferior *inf)
 /* The 'normal_stop' observer notification callback.  */
 
 static void
-ada_tasks_normal_stop_observer (struct bpstats *unused_args, int unused_args2)
+ada_tasks_normal_stop_observer (struct bpstat *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.  */
@@ -1424,18 +1445,14 @@ ada_tasks_normal_stop_observer (struct bpstats *unused_args, int unused_args2)
 static void
 ada_tasks_new_objfile_observer (struct objfile *objfile)
 {
-  struct inferior *inf;
-
   /* Invalidate the relevant data in our program-space data.  */
 
   if (objfile == NULL)
     {
       /* All objfiles are being cleared, so we should clear all
         our caches for all program spaces.  */
-      struct program_space *pspace;
-
-      for (pspace = program_spaces; pspace != NULL; pspace = pspace->next)
-        ada_tasks_invalidate_pspace_data (pspace);
+      for (struct program_space *pspace : program_spaces)
+       ada_tasks_invalidate_pspace_data (pspace);
     }
   else
     {
@@ -1450,23 +1467,224 @@ ada_tasks_new_objfile_observer (struct objfile *objfile)
      If all objfiles are being cleared (OBJFILE is NULL), then
      clear the caches for all inferiors.  */
 
-  for (inf = inferior_list; inf != NULL; inf = inf->next)
+  for (inferior *inf : all_inferiors ())
     if (objfile == NULL || inf->pspace == objfile->pspace)
       ada_tasks_invalidate_inferior_data (inf);
 }
 
+/* The qcs command line flags for the "task apply" commands.  Keep
+   this in sync with the "frame apply" commands.  */
+
+using qcs_flag_option_def
+  = gdb::option::flag_option_def<qcs_flags>;
+
+static const gdb::option::option_def task_qcs_flags_option_defs[] = {
+  qcs_flag_option_def {
+    "q", [] (qcs_flags *opt) { return &opt->quiet; },
+    N_("Disables printing the task information."),
+  },
+
+  qcs_flag_option_def {
+    "c", [] (qcs_flags *opt) { return &opt->cont; },
+    N_("Print any error raised by COMMAND and continue."),
+  },
+
+  qcs_flag_option_def {
+    "s", [] (qcs_flags *opt) { return &opt->silent; },
+    N_("Silently ignore any errors or empty output produced by COMMAND."),
+  },
+};
+
+/* Create an option_def_group for the "task apply all" options, with
+   FLAGS as context.  */
+
+static inline std::array<gdb::option::option_def_group, 1>
+make_task_apply_all_options_def_group (qcs_flags *flags)
+{
+  return {{
+    { {task_qcs_flags_option_defs}, flags },
+  }};
+}
+
+/* Create an option_def_group for the "task apply" options, with
+   FLAGS as context.  */
+
+static inline gdb::option::option_def_group
+make_task_apply_options_def_group (qcs_flags *flags)
+{
+  return {{task_qcs_flags_option_defs}, flags};
+}
+
+/* Implementation of 'task apply all'.  */
+
+static void
+task_apply_all_command (const char *cmd, int from_tty)
+{
+  qcs_flags flags;
+
+  auto group = make_task_apply_all_options_def_group (&flags);
+  gdb::option::process_options
+    (&cmd, gdb::option::PROCESS_OPTIONS_UNKNOWN_IS_OPERAND, group);
+
+  validate_flags_qcs ("task apply all", &flags);
+
+  if (cmd == nullptr || *cmd == '\0')
+    error (_("Please specify a command at the end of 'task apply all'"));
+
+  update_thread_list ();
+  ada_build_task_list ();
+
+  inferior *inf = current_inferior ();
+  struct ada_tasks_inferior_data *data = get_ada_tasks_inferior_data (inf);
+
+  /* Save a copy of the thread list and increment each thread's
+     refcount while executing the command in the context of each
+     thread, in case the command affects this.  */
+  std::vector<std::pair<int, thread_info_ref>> thr_list_cpy;
+
+  for (int i = 1; i <= data->task_list.size (); ++i)
+    {
+      ada_task_info &task = data->task_list[i - 1];
+      if (!ada_task_is_alive (&task))
+       continue;
+
+      thread_info *tp = find_thread_ptid (inf, task.ptid);
+      if (tp == nullptr)
+       warning (_("Unable to compute thread ID for task %s.\n"
+                  "Cannot switch to this task."),
+                task_to_str (i, &task).c_str ());
+      else
+       thr_list_cpy.emplace_back (i, thread_info_ref::new_reference (tp));
+    }
+
+  scoped_restore_current_thread restore_thread;
+
+  for (const auto &info : thr_list_cpy)
+    if (switch_to_thread_if_alive (info.second.get ()))
+      thread_try_catch_cmd (info.second.get (), info.first, cmd,
+                           from_tty, flags);
+}
+
+/* Implementation of 'task apply'.  */
+
+static void
+task_apply_command (const char *tidlist, int from_tty)
+{
+
+  if (tidlist == nullptr || *tidlist == '\0')
+    error (_("Please specify a task ID list"));
+
+  update_thread_list ();
+  ada_build_task_list ();
+
+  inferior *inf = current_inferior ();
+  struct ada_tasks_inferior_data *data = get_ada_tasks_inferior_data (inf);
+
+  /* Save a copy of the thread list and increment each thread's
+     refcount while executing the command in the context of each
+     thread, in case the command affects this.  */
+  std::vector<std::pair<int, thread_info_ref>> thr_list_cpy;
+
+  number_or_range_parser parser (tidlist);
+  while (!parser.finished ())
+    {
+      int num = parser.get_number ();
+
+      if (num < 1 || num - 1 >= data->task_list.size ())
+       warning (_("no Ada Task with number %d"), num);
+      else
+       {
+         ada_task_info &task = data->task_list[num - 1];
+         if (!ada_task_is_alive (&task))
+           continue;
+
+         thread_info *tp = find_thread_ptid (inf, task.ptid);
+         if (tp == nullptr)
+           warning (_("Unable to compute thread ID for task %s.\n"
+                      "Cannot switch to this task."),
+                    task_to_str (num, &task).c_str ());
+         else
+           thr_list_cpy.emplace_back (num,
+                                      thread_info_ref::new_reference (tp));
+       }
+    }
+
+  qcs_flags flags;
+  const char *cmd = parser.cur_tok ();
+
+  auto group = make_task_apply_options_def_group (&flags);
+  gdb::option::process_options
+    (&cmd, gdb::option::PROCESS_OPTIONS_UNKNOWN_IS_OPERAND, group);
+
+  validate_flags_qcs ("task apply", &flags);
+
+  if (*cmd == '\0')
+    error (_("Please specify a command following the task ID list"));
+
+  scoped_restore_current_thread restore_thread;
+
+  for (const auto &info : thr_list_cpy)
+    if (switch_to_thread_if_alive (info.second.get ()))
+      thread_try_catch_cmd (info.second.get (), info.first, cmd,
+                           from_tty, flags);
+}
+
+void _initialize_tasks ();
 void
-_initialize_tasks (void)
+_initialize_tasks ()
 {
   /* Attach various observers.  */
-  gdb::observers::normal_stop.attach (ada_tasks_normal_stop_observer);
-  gdb::observers::new_objfile.attach (ada_tasks_new_objfile_observer);
+  gdb::observers::normal_stop.attach (ada_tasks_normal_stop_observer,
+                                     "ada-tasks");
+  gdb::observers::new_objfile.attach (ada_tasks_new_objfile_observer,
+                                     "ada-tasks");
+
+  static struct cmd_list_element *task_cmd_list;
+  static struct cmd_list_element *task_apply_list;
+
 
   /* Some new commands provided by this module.  */
   add_info ("tasks", info_tasks_command,
-            _("Provide information about all known Ada tasks."));
-  add_cmd ("task", class_run, task_command,
-           _("Use this command to switch between Ada tasks.\n\
+           _("Provide information about all known Ada tasks."));
+
+  add_prefix_cmd ("task", class_run, task_command,
+                 _("Use this command to switch between Ada tasks.\n\
 Without argument, this command simply prints the current task ID."),
-           &cmdlist);
+                 &task_cmd_list, 1, &cmdlist);
+
+#define TASK_APPLY_OPTION_HELP "\
+Prints per-inferior task number followed by COMMAND output.\n\
+\n\
+By default, an error raised during the execution of COMMAND\n\
+aborts \"task apply\".\n\
+\n\
+Options:\n\
+%OPTIONS%"
+
+  static const auto task_apply_opts
+    = make_task_apply_options_def_group (nullptr);
+
+  static std::string task_apply_help = gdb::option::build_help (_("\
+Apply a command to a list of tasks.\n\
+Usage: task apply ID... [OPTION]... COMMAND\n\
+ID is a space-separated list of IDs of tasks to apply COMMAND on.\n"
+TASK_APPLY_OPTION_HELP), task_apply_opts);
+
+  add_prefix_cmd ("apply", class_run,
+                 task_apply_command,
+                 task_apply_help.c_str (),
+                 &task_apply_list, 1,
+                 &task_cmd_list);
+
+  static const auto task_apply_all_opts
+    = make_task_apply_all_options_def_group (nullptr);
+
+  static std::string task_apply_all_help = gdb::option::build_help (_("\
+Apply a command to all tasks in the current inferior.\n\
+\n\
+Usage: task apply all [OPTION]... COMMAND\n"
+TASK_APPLY_OPTION_HELP), task_apply_all_opts);
+
+  add_cmd ("all", class_run, task_apply_all_command,
+          task_apply_all_help.c_str (), &task_apply_list);
 }