Multi-target support
[deliverable/binutils-gdb.git] / gdb / ada-tasks.c
index 440e32bf483d79b41944c92a6f34f56021ae7f34..0b7a8eb4ad46378eadea684c679020c3aa1966cf 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (C) 1992-2019 Free Software Foundation, Inc.
+/* Copyright (C) 1992-2020 Free Software Foundation, Inc.
 
    This file is part of GDB.
 
@@ -25,6 +25,9 @@
 #include "gdbthread.h"
 #include "progspace.h"
 #include "objfiles.h"
+#include "cli/cli-style.h"
+
+static int ada_build_task_list ();
 
 /* The name of the array in the GNAT runtime where the Ada Task Control
    Block of each task is stored.  */
@@ -140,35 +143,27 @@ struct ada_tasks_pspace_data
   /* Nonzero if the data has been initialized.  If set to zero,
      it means that the data has either not been initialized, or
      has potentially become stale.  */
-  int initialized_p;
+  int initialized_p = 0;
 
   /* The ATCB record type.  */
-  struct type *atcb_type;
+  struct type *atcb_type = nullptr;
 
   /* The ATCB "Common" component type.  */
-  struct type *atcb_common_type;
+  struct type *atcb_common_type = nullptr;
 
   /* The type of the "ll" field, from the atcb_common_type.  */
-  struct type *atcb_ll_type;
+  struct type *atcb_ll_type = nullptr;
 
   /* The type of the "call" field, from the atcb_common_type.  */
-  struct type *atcb_call_type;
+  struct type *atcb_call_type = nullptr;
 
   /* The index of various fields in the ATCB record and sub-records.  */
-  struct atcb_fieldnos atcb_fieldno;
+  struct atcb_fieldnos atcb_fieldno {};
 };
 
 /* Key to our per-program-space data.  */
-static const struct program_space_data *ada_tasks_pspace_data_handle;
-
-/* A cleanup routine for our per-program-space data.  */
-static void
-ada_tasks_pspace_data_cleanup (struct program_space *pspace, void *arg)
-{
-  struct ada_tasks_pspace_data *data
-    = (struct ada_tasks_pspace_data *) arg;
-  xfree (data);
-}
+static const struct program_space_key<ada_tasks_pspace_data>
+  ada_tasks_pspace_data_handle;
 
 /* The kind of data structure used by the runtime to store the list
    of Ada tasks.  */
@@ -230,7 +225,7 @@ struct ada_tasks_inferior_data
   /* When nonzero, this flag indicates that the task_list field
      below is up to date.  When set to zero, the list has either
      not been initialized, or has potentially become stale.  */
-  int task_list_valid_p = 0;
+  bool task_list_valid_p = false;
 
   /* The list of Ada tasks.
 
@@ -243,7 +238,20 @@ struct ada_tasks_inferior_data
 };
 
 /* Key to our per-inferior data.  */
-static const struct inferior_data *ada_tasks_inferior_data_handle;
+static const struct inferior_key<ada_tasks_inferior_data>
+  ada_tasks_inferior_data_handle;
+
+/* Return a string with TASKNO followed by the task name if TASK_INFO
+   contains a name.  */
+
+static std::string
+task_to_str (int taskno, const ada_task_info *task_info)
+{
+  if (task_info->name[0] == '\0')
+    return string_printf ("%d", taskno);
+  else
+    return string_printf ("%d \"%s\"", taskno, task_info->name);
+}
 
 /* Return the ada-tasks module's data for the given program space (PSPACE).
    If none is found, add a zero'ed one now.
@@ -255,13 +263,9 @@ get_ada_tasks_pspace_data (struct program_space *pspace)
 {
   struct ada_tasks_pspace_data *data;
 
-  data = ((struct ada_tasks_pspace_data *)
-         program_space_data (pspace, ada_tasks_pspace_data_handle));
+  data = ada_tasks_pspace_data_handle.get (pspace);
   if (data == NULL)
-    {
-      data = XCNEW (struct ada_tasks_pspace_data);
-      set_program_space_data (pspace, ada_tasks_pspace_data_handle, data);
-    }
+    data = ada_tasks_pspace_data_handle.emplace (pspace);
 
   return data;
 }
@@ -283,26 +287,13 @@ get_ada_tasks_inferior_data (struct inferior *inf)
 {
   struct ada_tasks_inferior_data *data;
 
-  data = ((struct ada_tasks_inferior_data *)
-         inferior_data (inf, ada_tasks_inferior_data_handle));
+  data = ada_tasks_inferior_data_handle.get (inf);
   if (data == NULL)
-    {
-      data = new ada_tasks_inferior_data;
-      set_inferior_data (inf, ada_tasks_inferior_data_handle, data);
-    }
+    data = ada_tasks_inferior_data_handle.emplace (inf);
 
   return data;
 }
 
-/* A cleanup routine for our per-inferior data.  */
-static void
-ada_tasks_inferior_data_cleanup (struct inferior *inf, void *arg)
-{
-  struct ada_tasks_inferior_data *data
-    = (struct ada_tasks_inferior_data *) arg;
-  delete data;
-}
-
 /* Return the task number of the task whose thread is THREAD, or zero
    if the task could not be found.  */
 
@@ -356,7 +347,7 @@ valid_task_id (int task_num)
    task state.  */
 
 static int
-ada_task_is_alive (struct ada_task_info *task_info)
+ada_task_is_alive (const struct ada_task_info *task_info)
 {
   return (task_info->state != Terminated);
 }
@@ -613,7 +604,7 @@ ptid_from_atcb_common (struct value *common_value)
 }
 
 /* Read the ATCB data of a given task given its TASK_ID (which is in practice
-   the address of its assocated ATCB record), and store the result inside
+   the address of its associated ATCB record), and store the result inside
    TASK_INFO.  */
 
 static void
@@ -678,7 +669,7 @@ read_atcb (CORE_ADDR task_id, struct ada_task_info *task_info)
          msym = lookup_minimal_symbol_by_pc (task_id);
          if (msym.minsym)
            {
-             const char *full_name = MSYMBOL_LINKAGE_NAME (msym.minsym);
+             const char *full_name = msym.minsym->linkage_name ();
              const char *task_name = full_name;
              const char *p;
 
@@ -753,7 +744,7 @@ read_atcb (CORE_ADDR task_id, struct ada_task_info *task_info)
                                        called_task_fieldno));
     }
 
-  /* If the ATCB cotnains some information about RV callers, then
+  /* If the ATCB contains some information about RV callers, then
      compute the "caller_task".  Otherwise, leave it as zero.  */
 
   if (pspace_data->atcb_fieldno.call >= 0)
@@ -803,9 +794,9 @@ add_ada_task (CORE_ADDR task_id, struct inferior *inf)
 }
 
 /* Read the Known_Tasks array from the inferior memory, and store
-   it in the current inferior's TASK_LIST.  Return non-zero upon success.  */
+   it in the current inferior's TASK_LIST.  Return true upon success.  */
 
-static int
+static bool
 read_known_tasks_array (struct ada_tasks_inferior_data *data)
 {
   const int target_ptr_byte = TYPE_LENGTH (data->known_tasks_element);
@@ -826,13 +817,13 @@ read_known_tasks_array (struct ada_tasks_inferior_data *data)
         add_ada_task (task_id, current_inferior ());
     }
 
-  return 1;
+  return true;
 }
 
 /* Read the known tasks from the inferior memory, and store it in
-   the current inferior's TASK_LIST.  Return non-zero upon success.  */
+   the current inferior's TASK_LIST.  Return true upon success.  */
 
-static int
+static bool
 read_known_tasks_list (struct ada_tasks_inferior_data *data)
 {
   const int target_ptr_byte = TYPE_LENGTH (data->known_tasks_element);
@@ -843,7 +834,7 @@ read_known_tasks_list (struct ada_tasks_inferior_data *data)
 
   /* Sanity check.  */
   if (pspace_data->atcb_fieldno.activation_link < 0)
-    return 0;
+    return false;
 
   /* Build a new list by reading the ATCBs.  Read head of the list.  */
   read_memory (data->known_tasks_addr, known_tasks, target_ptr_byte);
@@ -864,7 +855,7 @@ read_known_tasks_list (struct ada_tasks_inferior_data *data)
                                 pspace_data->atcb_fieldno.activation_link));
     }
 
-  return 1;
+  return true;
 }
 
 /* Set all fields of the current inferior ada-tasks data pointed by DATA.
@@ -962,11 +953,10 @@ ada_tasks_inferior_data_sniffer (struct ada_tasks_inferior_data *data)
 }
 
 /* Read the known tasks from the current inferior's memory, and store it
-   in the current inferior's data TASK_LIST.
-   Return non-zero upon success.  */
+   in the current inferior's data TASK_LIST.  */
 
-static int
-read_known_tasks (void)
+static void
+read_known_tasks ()
 {
   struct ada_tasks_inferior_data *data =
     get_ada_tasks_inferior_data (current_inferior ());
@@ -983,29 +973,27 @@ read_known_tasks (void)
   ada_tasks_inferior_data_sniffer (data);
   gdb_assert (data->known_tasks_kind != ADA_TASKS_UNKNOWN);
 
+  /* Step 3: Set task_list_valid_p, to avoid re-reading the Known_Tasks
+     array unless needed.  */
   switch (data->known_tasks_kind)
     {
-      case ADA_TASKS_NOT_FOUND: /* Tasking not in use in inferior.  */
-        return 0;
-      case ADA_TASKS_ARRAY:
-        return read_known_tasks_array (data);
-      case ADA_TASKS_LIST:
-        return read_known_tasks_list (data);
+    case ADA_TASKS_NOT_FOUND: /* Tasking not in use in inferior.  */
+      break;
+    case ADA_TASKS_ARRAY:
+      data->task_list_valid_p = read_known_tasks_array (data);
+      break;
+    case ADA_TASKS_LIST:
+      data->task_list_valid_p = read_known_tasks_list (data);
+      break;
     }
-
-  /* Step 3: Set task_list_valid_p, to avoid re-reading the Known_Tasks
-     array unless needed.  Then report a success.  */
-  data->task_list_valid_p = 1;
-
-  return 1;
 }
 
 /* Build the task_list by reading the Known_Tasks array from
    the inferior, and return the number of tasks in that list
    (zero means that the program is not using tasking at all).  */
 
-int
-ada_build_task_list (void)
+static int
+ada_build_task_list ()
 {
   struct ada_tasks_inferior_data *data;
 
@@ -1026,7 +1014,7 @@ ada_build_task_list (void)
 
 void
 print_ada_task_info (struct ui_out *uiout,
-                    char *arg_str,
+                    const char *arg_str,
                     struct inferior *inf)
 {
   struct ada_tasks_inferior_data *data;
@@ -1072,7 +1060,26 @@ print_ada_task_info (struct ui_out *uiout,
   ui_out_emit_table table_emitter (uiout, nb_columns, nb_tasks, "tasks");
   uiout->table_header (1, ui_left, "current", "");
   uiout->table_header (3, ui_right, "id", "ID");
-  uiout->table_header (9, ui_right, "task-id", "TID");
+  {
+    size_t tid_width = 9;
+    /* Grown below in case the largest entry is bigger.  */
+
+    if (!uiout->is_mi_like_p ())
+      {
+       for (taskno = 1; taskno <= data->task_list.size (); taskno++)
+         {
+           const struct ada_task_info *const task_info
+             = &data->task_list[taskno - 1];
+
+           gdb_assert (task_info != NULL);
+
+           tid_width = std::max (tid_width,
+                                 1 + strlen (phex_nz (task_info->task_id,
+                                                      sizeof (CORE_ADDR))));
+         }
+      }
+    uiout->table_header (tid_width, ui_right, "task-id", "TID");
+  }
   /* The following column is provided in GDB/MI mode only because
      it is only really useful in that mode, and also because it
      allows us to keep the CLI output shorter and more compact.  */
@@ -1111,33 +1118,37 @@ print_ada_task_info (struct ui_out *uiout,
        uiout->field_skip ("current");
 
       /* Print the task number.  */
-      uiout->field_int ("id", taskno);
+      uiout->field_signed ("id", taskno);
 
       /* Print the Task ID.  */
-      uiout->field_fmt ("task-id", "%9lx", (long) task_info->task_id);
+      uiout->field_string ("task-id", phex_nz (task_info->task_id,
+                                              sizeof (CORE_ADDR)));
 
       /* Print the associated Thread ID.  */
       if (uiout->is_mi_like_p ())
         {
-         thread_info *thread = find_thread_ptid (task_info->ptid);
+         thread_info *thread = (ada_task_is_alive (task_info)
+                                ? find_thread_ptid (inf, task_info->ptid)
+                                : nullptr);
 
          if (thread != NULL)
-           uiout->field_int ("thread-id", thread->global_num);
+           uiout->field_signed ("thread-id", thread->global_num);
          else
-           /* This should never happen unless there is a bug somewhere,
-              but be resilient when that happens.  */
-           uiout->field_skip ("thread-id");
+           {
+             /* This can happen if the thread is no longer alive.  */
+             uiout->field_skip ("thread-id");
+           }
        }
 
       /* Print the ID of the parent task.  */
       parent_id = get_task_number_from_id (task_info->parent, inf);
       if (parent_id)
-        uiout->field_int ("parent-id", parent_id);
+        uiout->field_signed ("parent-id", parent_id);
       else
         uiout->field_skip ("parent-id");
 
       /* Print the base priority of the task.  */
-      uiout->field_int ("priority", task_info->priority);
+      uiout->field_signed ("priority", task_info->priority);
 
       /* Print the task current state.  */
       if (task_info->caller_task)
@@ -1153,11 +1164,17 @@ print_ada_task_info (struct ui_out *uiout,
       else
        uiout->field_string ("state", task_states[task_info->state]);
 
-      /* Finally, print the task name.  */
+      /* 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.  */
       uiout->field_fmt ("name",
+                       (task_info->name[0] != '\0'
+                        ? ui_file_style ()
+                        : metadata_style.style ()),
                        "%s",
-                       task_info->name[0] != '\0' ? task_info->name
-                                                  : _("<no name>"));
+                       (task_info->name[0] != '\0'
+                        ? task_info->name
+                        : _("<no name>")));
 
       uiout->text ("\n");
     }
@@ -1193,7 +1210,7 @@ info_task (struct ui_out *uiout, const char *taskno_str, struct inferior *inf)
   if (task_info->name[0] != '\0')
     printf_filtered (_("Name: %s\n"), task_info->name);
   else
-    printf_filtered (_("<no name>\n"));
+    fprintf_styled (gdb_stdout, metadata_style.style (), _("<no name>\n"));
 
   /* Print the TID and LWP.  */
   printf_filtered (_("Thread: %#lx\n"), task_info->ptid.tid ());
@@ -1280,7 +1297,14 @@ display_current_task_id (void)
   if (current_task == 0)
     printf_filtered (_("[Current task is unknown]\n"));
   else
-    printf_filtered (_("[Current task is %d]\n"), current_task);
+    {
+      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 ());
+    }
 }
 
 /* Parse and evaluate TIDSTR into a task id, and try to switch to
@@ -1299,7 +1323,8 @@ task_command_1 (const char *taskno_str, int from_tty, struct inferior *inf)
   task_info = &data->task_list[taskno - 1];
 
   if (!ada_task_is_alive (task_info))
-    error (_("Cannot switch to task %d: Task is no longer running"), taskno);
+    error (_("Cannot switch to task %s: Task is no longer running"),
+          task_to_str (taskno, task_info).c_str ());
    
   /* On some platforms, the thread list is not updated until the user
      performs a thread-related operation (by using the "info threads"
@@ -1318,15 +1343,16 @@ 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 %d.\n"
+    error (_("Unable to compute thread ID for task %s.\n"
              "Cannot switch to this task."),
-           taskno);
+           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 %d]\n"), taskno);
+  printf_filtered (_("[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)),
                     SRC_AND_LOC, 1);
@@ -1361,7 +1387,7 @@ ada_task_list_changed (struct inferior *inf)
 {
   struct ada_tasks_inferior_data *data = get_ada_tasks_inferior_data (inf);
 
-  data->task_list_valid_p = 0;
+  data->task_list_valid_p = false;
 }
 
 /* Invalidate the per-program-space data.  */
@@ -1380,7 +1406,7 @@ ada_tasks_invalidate_inferior_data (struct inferior *inf)
   struct ada_tasks_inferior_data *data = get_ada_tasks_inferior_data (inf);
 
   data->known_tasks_kind = ADA_TASKS_UNKNOWN;
-  data->task_list_valid_p = 0;
+  data->task_list_valid_p = false;
 }
 
 /* The 'normal_stop' observer notification callback.  */
@@ -1432,22 +1458,15 @@ ada_tasks_new_objfile_observer (struct objfile *objfile)
 void
 _initialize_tasks (void)
 {
-  ada_tasks_pspace_data_handle
-    = register_program_space_data_with_cleanup (NULL,
-                                               ada_tasks_pspace_data_cleanup);
-  ada_tasks_inferior_data_handle
-    = register_inferior_data_with_cleanup (NULL,
-                                          ada_tasks_inferior_data_cleanup);
-
   /* Attach various observers.  */
   gdb::observers::normal_stop.attach (ada_tasks_normal_stop_observer);
   gdb::observers::new_objfile.attach (ada_tasks_new_objfile_observer);
 
   /* Some new commands provided by this module.  */
   add_info ("tasks", info_tasks_command,
-            _("Provide information about all known Ada tasks"));
+            _("Provide information about all known Ada tasks."));
   add_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"),
+Without argument, this command simply prints the current task ID."),
            &cmdlist);
 }
This page took 0.043124 seconds and 4 git commands to generate.