-/* Copyright (C) 1992-2017 Free Software Foundation, Inc.
+/* Copyright (C) 1992-2018 Free Software Foundation, Inc.
This file is part of GDB.
along with this program. If not, see <http://www.gnu.org/licenses/>. */
#include "defs.h"
-#include "observer.h"
+#include "observable.h"
#include "gdbcmd.h"
#include "target.h"
#include "ada-lang.h"
int activation_link;
int call;
int ll;
+ int base_cpu;
/* Fields in Task_Primitives.Private_Data. */
int ll_thread;
return data;
}
-/* Return the task number of the task whose ptid is PTID, or zero
+/* Return the task number of the task whose thread is THREAD, or zero
if the task could not be found. */
int
-ada_get_task_number (ptid_t ptid)
+ada_get_task_number (thread_info *thread)
{
int i;
- struct inferior *inf = find_inferior_ptid (ptid);
+ struct inferior *inf = thread->inf;
struct ada_tasks_inferior_data *data;
gdb_assert (inf != NULL);
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,
- ptid))
+ thread->ptid))
return i + 1;
return 0; /* No matching task found. */
return (task_info->state != Terminated);
}
+/* Search through the list of known tasks for the one whose ptid is
+ PTID, and return it. Return NULL if the task was not found. */
+
+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++)
+ {
+ task = VEC_index (ada_task_info_s, data->task_list, i);
+ if (ptid_equal (task->ptid, ptid))
+ return task;
+ }
+
+ return NULL;
+}
+
/* Call the ITERATOR function once for each Ada task that hasn't been
terminated yet. */
dest[len] = '\0';
}
-/* Get from the debugging information the type description of all types
- related to the Ada Task Control Block that will be needed in order to
- read the list of known tasks in the Ada runtime. Also return the
- associated ATCB_FIELDNOS.
-
- Error handling: Any data missing from the debugging info will cause
- an error to be raised, and none of the return values to be set.
- Users of this function can depend on the fact that all or none of the
- return values will be set. */
-
-static void
-get_tcb_types_info (void)
+/* Get, from the debugging information, the type description of all types
+ related to the Ada Task Control Block that are needed in order to
+ read the list of known tasks in the Ada runtime. If all of the info
+ needed to do so is found, then save that info in the module's per-
+ program-space data, and return NULL. Otherwise, if any information
+ cannot be found, leave the per-program-space data untouched, and
+ return an error message explaining what was missing (that error
+ message does NOT need to be deallocated). */
+
+const char *
+ada_get_tcb_types_info (void)
{
struct type *type;
struct type *common_type;
NULL).symbol;
if (atcb_sym == NULL || atcb_sym->type == NULL)
- error (_("Cannot find Ada_Task_Control_Block type. Aborting"));
+ return _("Cannot find Ada_Task_Control_Block type");
type = atcb_sym->type;
}
}
if (common_atcb_sym == NULL || common_atcb_sym->type == NULL)
- error (_("Cannot find Common_ATCB type. Aborting"));
+ return _("Cannot find Common_ATCB type");
if (private_data_sym == NULL || private_data_sym->type == NULL)
- error (_("Cannot find Private_Data type. Aborting"));
+ return _("Cannot find Private_Data type");
if (entry_call_record_sym == NULL || entry_call_record_sym->type == NULL)
- error (_("Cannot find Entry_Call_Record type. Aborting"));
+ return _("Cannot find Entry_Call_Record type");
/* Get the type for Ada_Task_Control_Block.Common. */
common_type = common_atcb_sym->type;
"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);
fieldnos.ll_thread = ada_get_field_index (ll_type, "thread", 0);
fieldnos.ll_lwp = ada_get_field_index (ll_type, "lwp", 1);
fieldnos.call_self = ada_get_field_index (call_type, "self", 0);
pspace_data->atcb_ll_type = ll_type;
pspace_data->atcb_call_type = call_type;
pspace_data->atcb_fieldno = fieldnos;
+ return NULL;
}
/* Build the PTID of the task from its COMMON_VALUE, which is the "Common"
= get_ada_tasks_pspace_data (current_program_space);
if (!pspace_data->initialized_p)
- get_tcb_types_info ();
+ {
+ const char *err_msg = ada_get_tcb_types_info ();
+
+ if (err_msg != NULL)
+ error (_("%s. Aborting"), err_msg);
+ }
tcb_value = value_from_contents_and_address (pspace_data->atcb_type,
NULL, task_id);
}
}
- /* 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->base_cpu
+ = 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
+ it is good enough to set its ptid to the null_ptid. */
+ if (ada_task_is_alive (task_info))
task_info->ptid = ptid_from_atcb_common (common_value);
else
task_info->ptid = null_ptid;
struct ada_tasks_inferior_data *data;
int taskno, nb_tasks;
int taskno_arg = 0;
- struct cleanup *old_chain;
int nb_columns;
if (ada_build_task_list () == 0)
nb_tasks = VEC_length (ada_task_info_s, data->task_list);
nb_columns = uiout->is_mi_like_p () ? 8 : 7;
- old_chain = make_cleanup_ui_out_table_begin_end (uiout, nb_columns,
- nb_tasks, "tasks");
+ 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");
/* Print the associated Thread ID. */
if (uiout->is_mi_like_p ())
{
- const int thread_id = ptid_to_global_thread_id (task_info->ptid);
+ thread_info *thread = find_thread_ptid (task_info->ptid);
- if (thread_id != 0)
- uiout->field_int ("thread-id", thread_id);
+ if (thread != NULL)
+ uiout->field_int ("thread-id", thread->global_num);
else
/* This should never happen unless there is a bug somewhere,
but be resilient when that happens. */
uiout->text ("\n");
}
-
- do_cleanups (old_chain);
}
/* Print a detailed description of the Ada task whose ID is TASKNO_STR
for the given inferior (INF). */
static void
-info_task (struct ui_out *uiout, char *taskno_str, struct inferior *inf)
+info_task (struct ui_out *uiout, const char *taskno_str, struct inferior *inf)
{
const int taskno = value_as_long (parse_and_eval (taskno_str));
struct ada_task_info *task_info;
printf_filtered (_("Thread: %#lx\n"), ptid_get_tid (task_info->ptid));
printf_filtered (_("LWP: %#lx\n"), ptid_get_lwp (task_info->ptid));
+ /* If set, print the base CPU. */
+ if (task_info->base_cpu != 0)
+ printf_filtered (_("Base CPU: %d\n"), task_info->base_cpu);
+
/* Print who is the parent (if any). */
if (task_info->parent != 0)
parent_taskno = get_task_number_from_id (task_info->parent, inf);
Does nothing if the program doesn't use Ada tasking. */
static void
-info_tasks_command (char *arg, int from_tty)
+info_tasks_command (const char *arg, int from_tty)
{
struct ui_out *uiout = current_uiout;
static void
display_current_task_id (void)
{
- const int current_task = ada_get_task_number (inferior_ptid);
+ const int current_task = ada_get_task_number (inferior_thread ());
if (current_task == 0)
printf_filtered (_("[Current task is unknown]\n"));
that task. Print an error message if the task switch failed. */
static void
-task_command_1 (char *taskno_str, int from_tty, struct inferior *inf)
+task_command_1 (const char *taskno_str, int from_tty, struct inferior *inf)
{
const int taskno = value_as_long (parse_and_eval (taskno_str));
struct ada_task_info *task_info;
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))
+ thread_info *tp = find_thread_ptid (task_info->ptid);
+ if (tp == NULL)
error (_("Unable to compute thread ID for task %d.\n"
"Cannot switch to this task."),
taskno);
- switch_to_thread (task_info->ptid);
+ switch_to_thread (tp);
ada_find_printable_frame (get_selected_frame (NULL));
printf_filtered (_("[Switching to task %d]\n"), taskno);
print_stack_frame (get_selected_frame (NULL),
Otherwise, switch to the task indicated by TASKNO_STR. */
static void
-task_command (char *taskno_str, int from_tty)
+task_command (const char *taskno_str, int from_tty)
{
struct ui_out *uiout = current_uiout;
if (taskno_str == NULL || taskno_str[0] == '\0')
display_current_task_id ();
else
- {
- /* Task switching in core files doesn't work, either because:
- 1. Thread support is not implemented with core files
- 2. Thread support is implemented, but the thread IDs created
- after having read the core file are not the same as the ones
- that were used during the program life, before the crash.
- As a consequence, there is no longer a way for the debugger
- to find the associated thead ID of any given Ada task.
- So, instead of attempting a task switch without giving the user
- any clue as to what might have happened, just error-out with
- a message explaining that this feature is not supported. */
- if (!target_has_execution)
- error (_("\
-Task switching not supported when debugging from core files\n\
-(use thread support instead)"));
- task_command_1 (taskno_str, from_tty, current_inferior ());
- }
+ task_command_1 (taskno_str, from_tty, current_inferior ());
}
/* Indicate that the given inferior's task list may have changed,
ada_tasks_invalidate_inferior_data (inf);
}
-/* Provide a prototype to silence -Wmissing-prototypes. */
-extern initialize_file_ftype _initialize_tasks;
-
void
_initialize_tasks (void)
{
ada_tasks_inferior_data_handle = register_inferior_data ();
/* Attach various observers. */
- observer_attach_normal_stop (ada_tasks_normal_stop_observer);
- observer_attach_new_objfile (ada_tasks_new_objfile_observer);
+ 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,