-/* Copyright (C) 1992-2018 Free Software Foundation, Inc.
+/* Copyright (C) 1992-2020 Free Software Foundation, Inc.
This file is part of GDB.
#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. */
/* 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;
-
-typedef struct ada_task_info ada_task_info_s;
-DEF_VEC_O(ada_task_info_s);
+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. */
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;
+ enum ada_known_tasks_kind known_tasks_kind = ADA_TASKS_UNKNOWN;
/* The address of the known_tasks structure. This is where
the runtime stores the information for all Ada tasks.
The interpretation of this field depends on KNOWN_TASKS_KIND
above. */
- CORE_ADDR known_tasks_addr;
+ CORE_ADDR known_tasks_addr = 0;
/* Type of elements of the known task. Usually a pointer. */
- struct type *known_tasks_element;
+ struct type *known_tasks_element = nullptr;
/* Number of elements in the known tasks array. */
- unsigned int known_tasks_length;
+ unsigned int known_tasks_length = 0;
/* 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;
+ bool task_list_valid_p = false;
/* The list of Ada tasks.
info listing displayed by "info tasks". This number is equal to
its index in the vector + 1. Reciprocally, to compute the index
of a task in the vector, we need to substract 1 from its number. */
- VEC(ada_task_info_s) *task_list;
+ std::vector<ada_task_info> task_list;
};
/* 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.
{
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;
}
{
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 = XCNEW (struct ada_tasks_inferior_data);
- set_inferior_data (inf, ada_tasks_inferior_data_handle, data);
- }
+ data = ada_tasks_inferior_data_handle.emplace (inf);
return data;
}
int
ada_get_task_number (thread_info *thread)
{
- int i;
struct inferior *inf = thread->inf;
struct ada_tasks_inferior_data *data;
gdb_assert (inf != NULL);
data = get_ada_tasks_inferior_data (inf);
- for (i = 0; i < VEC_length (ada_task_info_s, data->task_list); i++)
- if (ptid_equal (VEC_index (ada_task_info_s, data->task_list, i)->ptid,
- thread->ptid))
+ for (int i = 0; i < data->task_list.size (); i++)
+ if (data->task_list[i].ptid == thread->ptid)
return i + 1;
return 0; /* No matching task found. */
get_task_number_from_id (CORE_ADDR task_id, struct inferior *inf)
{
struct ada_tasks_inferior_data *data = get_ada_tasks_inferior_data (inf);
- int i;
- for (i = 0; i < VEC_length (ada_task_info_s, data->task_list); i++)
+ for (int i = 0; i < data->task_list.size (); i++)
{
- struct ada_task_info *task_info =
- VEC_index (ada_task_info_s, data->task_list, i);
-
- if (task_info->task_id == task_id)
+ if (data->task_list[i].task_id == task_id)
return i + 1;
}
ada_build_task_list ();
data = get_ada_tasks_inferior_data (current_inferior ());
- return (task_num > 0
- && task_num <= VEC_length (ada_task_info_s, data->task_list));
+ return task_num > 0 && task_num <= data->task_list.size ();
}
/* Return non-zero iff the task STATE corresponds to a non-terminated
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);
}
struct ada_task_info *
ada_get_task_info_from_ptid (ptid_t ptid)
{
- int i, nb_tasks;
- struct ada_task_info *task;
struct ada_tasks_inferior_data *data;
ada_build_task_list ();
data = get_ada_tasks_inferior_data (current_inferior ());
- nb_tasks = VEC_length (ada_task_info_s, data->task_list);
- for (i = 0; i < nb_tasks; i++)
+ for (ada_task_info &task : data->task_list)
{
- task = VEC_index (ada_task_info_s, data->task_list, i);
- if (ptid_equal (task->ptid, ptid))
- return task;
+ if (task.ptid == ptid)
+ return &task;
}
return NULL;
void
iterate_over_live_ada_tasks (ada_task_list_iterator_ftype *iterator)
{
- int i, nb_tasks;
- struct ada_task_info *task;
struct ada_tasks_inferior_data *data;
ada_build_task_list ();
data = get_ada_tasks_inferior_data (current_inferior ());
- nb_tasks = VEC_length (ada_task_info_s, data->task_list);
- for (i = 0; i < nb_tasks; i++)
+ for (ada_task_info &task : data->task_list)
{
- task = VEC_index (ada_task_info_s, data->task_list, i);
- if (!ada_task_is_alive (task))
+ if (!ada_task_is_alive (&task))
continue;
- iterator (task);
+ iterator (&task);
}
}
}
/* 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
const struct ada_tasks_pspace_data *pspace_data
= get_ada_tasks_pspace_data (current_program_space);
+ /* Clear the whole structure to start with, so that everything
+ is always initialized the same. */
+ memset (task_info, 0, sizeof (struct ada_task_info));
+
if (!pspace_data->initialized_p)
{
const char *err_msg = ada_get_tcb_types_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;
task_info->parent =
value_as_address (value_field (common_value,
pspace_data->atcb_fieldno.parent));
- else
- task_info->parent = 0;
-
- /* If the ATCB contains some information about entry calls, then
- compute the "called_task" as well. Otherwise, zero. */
+ /* If the task is in an entry call waiting for another task,
+ then determine which task it is. */
- if (pspace_data->atcb_fieldno.atc_nesting_level > 0
+ if (task_info->state == Entry_Caller_Sleep
+ && pspace_data->atcb_fieldno.atc_nesting_level > 0
&& pspace_data->atcb_fieldno.entry_calls > 0)
{
/* Let My_ATCB be the Ada task control block of a task calling the
value_as_address (value_field (entry_calls_value_element,
called_task_fieldno));
}
- else
- {
- task_info->called_task = 0;
- }
- /* If the ATCB cotnains some information about RV callers,
- then compute the "caller_task". Otherwise, zero. */
+ /* If the ATCB contains some information about RV callers, then
+ compute the "caller_task". Otherwise, leave it as zero. */
- task_info->caller_task = 0;
if (pspace_data->atcb_fieldno.call >= 0)
{
/* Get the ID of the caller task from Common_ATCB.Call.all.Self.
struct ada_tasks_inferior_data *data = get_ada_tasks_inferior_data (inf);
read_atcb (task_id, &task_info);
- VEC_safe_push (ada_task_info_s, data->task_list, &task_info);
+ data->task_list.push_back (task_info);
}
/* 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);
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);
/* 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);
pspace_data->atcb_fieldno.activation_link));
}
- return 1;
+ return true;
}
/* Set all fields of the current inferior ada-tasks data pointed by 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 ());
/* Step 1: Clear the current list, if necessary. */
- VEC_truncate (ada_task_info_s, data->task_list, 0);
+ data->task_list.clear ();
/* Step 2: do the real work.
If the application does not use task, then no more needs to be done.
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;
if (!data->task_list_valid_p)
read_known_tasks ();
- return VEC_length (ada_task_info_s, data->task_list);
+ return data->task_list.size ();
}
/* Print a table providing a short description of all Ada tasks
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;
as we have tasks. */
if (taskno_arg)
{
- if (taskno_arg > 0
- && taskno_arg <= VEC_length (ada_task_info_s, data->task_list))
+ if (taskno_arg > 0 && taskno_arg <= data->task_list.size ())
nb_tasks = 1;
else
nb_tasks = 0;
}
else
- nb_tasks = VEC_length (ada_task_info_s, data->task_list);
+ nb_tasks = data->task_list.size ();
nb_columns = uiout->is_mi_like_p () ? 8 : 7;
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. */
uiout->table_header (1, ui_noalign, "name", "Name");
uiout->table_body ();
- for (taskno = 1;
- taskno <= VEC_length (ada_task_info_s, data->task_list);
- taskno++)
+ for (taskno = 1; taskno <= data->task_list.size (); taskno++)
{
const struct ada_task_info *const task_info =
- VEC_index (ada_task_info_s, data->task_list, taskno - 1);
+ &data->task_list[taskno - 1];
int parent_id;
gdb_assert (task_info != NULL);
/* Print a star if this task is the current task (or the task
currently selected). */
- if (ptid_equal (task_info->ptid, inferior_ptid))
+ if (task_info->ptid == inferior_ptid)
uiout->field_string ("current", "*");
else
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 (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)
_("Accepting RV with %-4d"),
get_task_number_from_id (task_info->caller_task,
inf));
- else if (task_info->state == Entry_Caller_Sleep
- && task_info->called_task)
+ else if (task_info->called_task)
uiout->field_fmt ("state",
_("Waiting on RV with %-3d"),
get_task_number_from_id (task_info->called_task,
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");
}
return;
}
- if (taskno <= 0 || taskno > VEC_length (ada_task_info_s, data->task_list))
+ 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);
- task_info = VEC_index (ada_task_info_s, data->task_list, taskno - 1);
+ task_info = &data->task_list[taskno - 1];
/* Print the Ada task ID. */
printf_filtered (_("Ada Task: %s\n"),
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"), ptid_get_tid (task_info->ptid));
+ printf_filtered (_("Thread: %#lx\n"), task_info->ptid.tid ());
printf_filtered (_("LWP: %#lx\n"), task_info->ptid.lwp ());
/* If set, print the base CPU. */
parent_taskno = get_task_number_from_id (task_info->parent, inf);
if (parent_taskno)
{
- struct ada_task_info *parent =
- VEC_index (ada_task_info_s, data->task_list, parent_taskno - 1);
+ struct ada_task_info *parent = &data->task_list[parent_taskno - 1];
printf_filtered (_("Parent: %d"), parent_taskno);
if (parent->name[0] != '\0')
printf_filtered (_("State: Accepting rendezvous with %d"),
target_taskno);
}
- else if (task_info->state == Entry_Caller_Sleep && task_info->called_task)
+ 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"),
if (target_taskno)
{
- struct ada_task_info *target_task_info =
- VEC_index (ada_task_info_s, 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 (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
struct ada_task_info *task_info;
struct ada_tasks_inferior_data *data = get_ada_tasks_inferior_data (inf);
- if (taskno <= 0 || taskno > VEC_length (ada_task_info_s, data->task_list))
+ 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);
- task_info = VEC_index (ada_task_info_s, data->task_list, taskno - 1);
+ 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"
it's nicer for the user to just refuse to perform the task switch. */
thread_info *tp = find_thread_ptid (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);
{
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. */
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. */
void
_initialize_tasks (void)
{
- ada_tasks_pspace_data_handle = register_program_space_data ();
- ada_tasks_inferior_data_handle = register_inferior_data ();
-
/* 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);
}