-/* Copyright (C) 1992, 1993, 1994, 1997, 1998, 1999, 2000, 2003, 2004, 2005,
- 2007, 2008, 2009, 2010, 2011 Free Software Foundation, Inc.
+/* Copyright (C) 1992-2015 Free Software Foundation, Inc.
This file is part of GDB.
above. */
CORE_ADDR known_tasks_addr;
+ /* Type of elements of the known task. Usually a pointer. */
+ struct type *known_tasks_element;
+
+ /* Number of elements in the known tasks array. */
+ unsigned int known_tasks_length;
+
/* 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. */
{
struct ada_tasks_pspace_data *data;
- data = program_space_data (pspace, ada_tasks_pspace_data_handle);
+ data = ((struct ada_tasks_pspace_data *)
+ program_space_data (pspace, ada_tasks_pspace_data_handle));
if (data == NULL)
{
- data = XZALLOC (struct ada_tasks_pspace_data);
+ data = XCNEW (struct ada_tasks_pspace_data);
set_program_space_data (pspace, ada_tasks_pspace_data_handle, data);
}
{
struct ada_tasks_inferior_data *data;
- data = inferior_data (inf, ada_tasks_inferior_data_handle);
+ data = ((struct ada_tasks_inferior_data *)
+ inferior_data (inf, ada_tasks_inferior_data_handle));
if (data == NULL)
{
- data = XZALLOC (struct ada_tasks_inferior_data);
+ data = XCNEW (struct ada_tasks_inferior_data);
set_inferior_data (inf, ada_tasks_inferior_data_handle, data);
}
ada_get_task_number (ptid_t ptid)
{
int i;
- struct inferior *inf = find_inferior_pid (ptid_get_pid (ptid));
+ struct inferior *inf = find_inferior_ptid (ptid);
struct ada_tasks_inferior_data *data;
gdb_assert (inf != NULL);
/* Extract LEN characters from the fat string. */
array_val = value_ind (value_field (val, array_fieldno));
- read_memory (value_address (array_val), dest, len);
+ read_memory (value_address (array_val), (gdb_byte *) dest, len);
/* Add the NUL character to close the string. */
dest[len] = '\0';
C-like) lookups to get the first match. */
struct symbol *atcb_sym =
- lookup_symbol_in_language (atcb_name, NULL, VAR_DOMAIN,
- language_c, NULL);
+ lookup_symbol_in_language (atcb_name, NULL, STRUCT_DOMAIN,
+ language_c, NULL).symbol;
const struct symbol *common_atcb_sym =
- lookup_symbol_in_language (common_atcb_name, NULL, VAR_DOMAIN,
- language_c, NULL);
+ lookup_symbol_in_language (common_atcb_name, NULL, STRUCT_DOMAIN,
+ language_c, NULL).symbol;
const struct symbol *private_data_sym =
- lookup_symbol_in_language (private_data_name, NULL, VAR_DOMAIN,
- language_c, NULL);
+ lookup_symbol_in_language (private_data_name, NULL, STRUCT_DOMAIN,
+ language_c, NULL).symbol;
const struct symbol *entry_call_record_sym =
- lookup_symbol_in_language (entry_call_record_name, NULL, VAR_DOMAIN,
- language_c, NULL);
+ lookup_symbol_in_language (entry_call_record_name, NULL, STRUCT_DOMAIN,
+ language_c, NULL).symbol;
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. */
- atcb_sym = lookup_symbol_in_language (atcb_name_fixed, NULL, VAR_DOMAIN,
- language_c, NULL);
+ atcb_sym = lookup_symbol_in_language (atcb_name_fixed, NULL,
+ STRUCT_DOMAIN, language_c,
+ NULL).symbol;
if (atcb_sym == NULL || atcb_sym->type == NULL)
error (_("Cannot find Ada_Task_Control_Block type. Aborting"));
struct value *entry_calls_value;
struct value *entry_calls_value_element;
int called_task_fieldno = -1;
- const char ravenscar_task_name[] = "Ravenscar task";
+ static const char ravenscar_task_name[] = "Ravenscar task";
const struct ada_tasks_pspace_data *pspace_data
= get_ada_tasks_pspace_data (current_program_space);
pspace_data->atcb_fieldno.image),
sizeof (task_info->name) - 1);
else
- strcpy (task_info->name, ravenscar_task_name);
+ {
+ struct bound_minimal_symbol msym;
+
+ msym = lookup_minimal_symbol_by_pc (task_id);
+ if (msym.minsym)
+ {
+ const char *full_name = MSYMBOL_LINKAGE_NAME (msym.minsym);
+ const char *task_name = full_name;
+ const char *p;
+
+ /* Strip the prefix. */
+ for (p = full_name; *p; p++)
+ if (p[0] == '_' && p[1] == '_')
+ task_name = p + 2;
+
+ /* Copy the task name. */
+ strncpy (task_info->name, task_name, sizeof (task_info->name));
+ task_info->name[sizeof (task_info->name) - 1] = 0;
+ }
+ else
+ {
+ /* No symbol found. Use a default name. */
+ strcpy (task_info->name, ravenscar_task_name);
+ }
+ }
}
else
{
it in the current inferior's TASK_LIST. Return non-zero upon success. */
static int
-read_known_tasks_array (CORE_ADDR known_tasks_addr)
+read_known_tasks_array (struct ada_tasks_inferior_data *data)
{
- const int target_ptr_byte =
- gdbarch_ptr_bit (target_gdbarch) / TARGET_CHAR_BIT;
- const int known_tasks_size = target_ptr_byte * MAX_NUMBER_OF_KNOWN_TASKS;
- gdb_byte *known_tasks = alloca (known_tasks_size);
+ const int target_ptr_byte = TYPE_LENGTH (data->known_tasks_element);
+ const int known_tasks_size = target_ptr_byte * data->known_tasks_length;
+ gdb_byte *known_tasks = (gdb_byte *) alloca (known_tasks_size);
int i;
/* Build a new list by reading the ATCBs from the Known_Tasks array
in the Ada runtime. */
- read_memory (known_tasks_addr, known_tasks, known_tasks_size);
- for (i = 0; i < MAX_NUMBER_OF_KNOWN_TASKS; i++)
+ read_memory (data->known_tasks_addr, known_tasks, known_tasks_size);
+ for (i = 0; i < data->known_tasks_length; i++)
{
- struct type *data_ptr_type =
- builtin_type (target_gdbarch)->builtin_data_ptr;
CORE_ADDR task_id =
extract_typed_address (known_tasks + i * target_ptr_byte,
- data_ptr_type);
+ data->known_tasks_element);
if (task_id != 0)
add_ada_task (task_id, current_inferior ());
the current inferior's TASK_LIST. Return non-zero upon success. */
static int
-read_known_tasks_list (CORE_ADDR known_tasks_addr)
+read_known_tasks_list (struct ada_tasks_inferior_data *data)
{
- 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;
+ const int target_ptr_byte = TYPE_LENGTH (data->known_tasks_element);
+ gdb_byte *known_tasks = (gdb_byte *) alloca (target_ptr_byte);
CORE_ADDR task_id;
const struct ada_tasks_pspace_data *pspace_data
= get_ada_tasks_pspace_data (current_program_space);
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);
+ read_memory (data->known_tasks_addr, known_tasks, target_ptr_byte);
+ task_id = extract_typed_address (known_tasks, data->known_tasks_element);
while (task_id != 0)
{
struct value *tcb_value;
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);
-}
-
-/* Assuming DATA is the ada-tasks' data for the current inferior,
- set the known_tasks_kind and known_tasks_addr fields. Do nothing
- if those fields are already set and still up to date. */
+/* Set all fields of the current inferior ada-tasks data pointed by DATA.
+ Do nothing if those fields are already set and still up to date. */
static void
-ada_set_current_inferior_known_tasks_addr (struct ada_tasks_inferior_data *data)
+ada_tasks_inferior_data_sniffer (struct ada_tasks_inferior_data *data)
{
- CORE_ADDR known_tasks_addr;
+ struct bound_minimal_symbol msym;
+ struct symbol *sym;
+ /* Return now if already set. */
if (data->known_tasks_kind != ADA_TASKS_UNKNOWN)
return;
- known_tasks_addr = get_known_tasks_addr (KNOWN_TASKS_NAME);
- if (known_tasks_addr != 0)
+ /* Try array. */
+
+ msym = lookup_minimal_symbol (KNOWN_TASKS_NAME, NULL, NULL);
+ if (msym.minsym != NULL)
{
data->known_tasks_kind = ADA_TASKS_ARRAY;
- data->known_tasks_addr = known_tasks_addr;
+ data->known_tasks_addr = BMSYMBOL_VALUE_ADDRESS (msym);
+
+ /* Try to get pointer type and array length from the symtab. */
+ sym = lookup_symbol_in_language (KNOWN_TASKS_NAME, NULL, VAR_DOMAIN,
+ language_c, NULL).symbol;
+ if (sym != NULL)
+ {
+ /* Validate. */
+ struct type *type = check_typedef (SYMBOL_TYPE (sym));
+ struct type *eltype = NULL;
+ struct type *idxtype = NULL;
+
+ if (TYPE_CODE (type) == 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));
+ if (idxtype != NULL
+ && !TYPE_LOW_BOUND_UNDEFINED (idxtype)
+ && !TYPE_HIGH_BOUND_UNDEFINED (idxtype))
+ {
+ data->known_tasks_element = eltype;
+ data->known_tasks_length =
+ TYPE_HIGH_BOUND (idxtype) - TYPE_LOW_BOUND (idxtype) + 1;
+ return;
+ }
+ }
+
+ /* Fallback to default values. The runtime may have been stripped (as
+ in some distributions), but it is likely that the executable still
+ contains debug information on the task type (due to implicit with of
+ Ada.Tasking). */
+ data->known_tasks_element =
+ builtin_type (target_gdbarch ())->builtin_data_ptr;
+ data->known_tasks_length = MAX_NUMBER_OF_KNOWN_TASKS;
return;
}
- known_tasks_addr = get_known_tasks_addr (KNOWN_TASKS_LIST);
- if (known_tasks_addr != 0)
+
+ /* Try list. */
+
+ msym = lookup_minimal_symbol (KNOWN_TASKS_LIST, NULL, NULL);
+ if (msym.minsym != NULL)
{
data->known_tasks_kind = ADA_TASKS_LIST;
- data->known_tasks_addr = known_tasks_addr;
+ data->known_tasks_addr = BMSYMBOL_VALUE_ADDRESS (msym);
+ data->known_tasks_length = 1;
+
+ sym = lookup_symbol_in_language (KNOWN_TASKS_LIST, NULL, VAR_DOMAIN,
+ language_c, NULL).symbol;
+ if (sym != NULL && SYMBOL_VALUE_ADDRESS (sym) != 0)
+ {
+ /* Validate. */
+ struct type *type = check_typedef (SYMBOL_TYPE (sym));
+
+ if (TYPE_CODE (type) == TYPE_CODE_PTR)
+ {
+ data->known_tasks_element = type;
+ return;
+ }
+ }
+
+ /* Fallback to default values. */
+ data->known_tasks_element =
+ builtin_type (target_gdbarch ())->builtin_data_ptr;
+ data->known_tasks_length = 1;
return;
}
+ /* Can't find tasks. */
+
data->known_tasks_kind = ADA_TASKS_NOT_FOUND;
data->known_tasks_addr = 0;
}
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. */
- ada_set_current_inferior_known_tasks_addr (data);
+ ada_tasks_inferior_data_sniffer (data);
gdb_assert (data->known_tasks_kind != ADA_TASKS_UNKNOWN);
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->known_tasks_addr);
+ return read_known_tasks_array (data);
case ADA_TASKS_LIST:
- return read_known_tasks_list (data->known_tasks_addr);
+ return read_known_tasks_list (data);
}
/* Step 3: Set task_list_valid_p, to avoid re-reading the Known_Tasks
interpreted as a task number, and the table will be limited to
that task only. */
-static void
+void
print_ada_task_info (struct ui_out *uiout,
char *arg_str,
struct inferior *inf)
int taskno, nb_tasks;
int taskno_arg = 0;
struct cleanup *old_chain;
+ int nb_columns;
if (ada_build_task_list () == 0)
{
if (arg_str != NULL && arg_str[0] != '\0')
taskno_arg = value_as_long (parse_and_eval (arg_str));
+ if (ui_out_is_mi_like_p (uiout))
+ /* In GDB/MI mode, we want to provide the thread ID corresponding
+ to each task. This allows clients to quickly find the thread
+ associated to any task, which is helpful for commands that
+ take a --thread argument. However, in order to be able to
+ provide that thread ID, the thread list must be up to date
+ first. */
+ target_update_thread_list ();
+
data = get_ada_tasks_inferior_data (inf);
- nb_tasks = VEC_length (ada_task_info_s, data->task_list);
- old_chain = make_cleanup_ui_out_table_begin_end (uiout, 7, nb_tasks,
- "tasks");
+ /* Compute the number of tasks that are going to be displayed
+ in the output. If an argument was given, there will be
+ at most 1 entry. Otherwise, there will be as many entries
+ as we have tasks. */
+ if (taskno_arg)
+ {
+ if (taskno_arg > 0
+ && taskno_arg <= VEC_length (ada_task_info_s, data->task_list))
+ nb_tasks = 1;
+ else
+ nb_tasks = 0;
+ }
+ else
+ nb_tasks = VEC_length (ada_task_info_s, data->task_list);
+
+ nb_columns = ui_out_is_mi_like_p (uiout) ? 8 : 7;
+ old_chain = make_cleanup_ui_out_table_begin_end (uiout, nb_columns,
+ nb_tasks, "tasks");
ui_out_table_header (uiout, 1, ui_left, "current", "");
ui_out_table_header (uiout, 3, ui_right, "id", "ID");
ui_out_table_header (uiout, 9, 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. */
+ if (ui_out_is_mi_like_p (uiout))
+ ui_out_table_header (uiout, 4, ui_right, "thread-id", "");
ui_out_table_header (uiout, 4, ui_right, "parent-id", "P-ID");
ui_out_table_header (uiout, 3, ui_right, "priority", "Pri");
ui_out_table_header (uiout, 22, ui_left, "state", "State");
ui_out_table_header (uiout, 1, ui_noalign, "name", "Name");
ui_out_table_body (uiout);
- for (taskno = 1; taskno <= nb_tasks; taskno++)
+ for (taskno = 1;
+ taskno <= VEC_length (ada_task_info_s, data->task_list);
+ taskno++)
{
const struct ada_task_info *const task_info =
VEC_index (ada_task_info_s, data->task_list, taskno - 1);
/* Print the Task ID. */
ui_out_field_fmt (uiout, "task-id", "%9lx", (long) task_info->task_id);
+ /* Print the associated Thread ID. */
+ if (ui_out_is_mi_like_p (uiout))
+ {
+ const int thread_id = pid_to_thread_id (task_info->ptid);
+
+ if (thread_id != 0)
+ ui_out_field_int (uiout, "thread-id", thread_id);
+ else
+ /* This should never happen unless there is a bug somewhere,
+ but be resilient when that happens. */
+ ui_out_field_skip (uiout, "thread-id");
+ }
+
/* Print the ID of the parent task. */
parent_id = get_task_number_from_id (task_info->parent, inf);
if (parent_id)
/* Print the Ada task ID. */
printf_filtered (_("Ada Task: %s\n"),
- paddress (target_gdbarch, task_info->task_id));
+ paddress (target_gdbarch (), task_info->task_id));
/* Print the name of the task. */
if (task_info->name[0] != '\0')
to the thread associated to our task if GDB does not know about
that thread, we need to make sure that any new threads gets added
to the thread list. */
- target_find_new_threads ();
+ target_update_thread_list ();
/* Verify that the ptid of the task we want to switch to is valid
(in other words, a ptid that GDB knows about). Otherwise, we will
ada_find_printable_frame (get_selected_frame (NULL));
printf_filtered (_("[Switching to task %d]\n"), taskno);
print_stack_frame (get_selected_frame (NULL),
- frame_relative_level (get_selected_frame (NULL)), 1);
+ frame_relative_level (get_selected_frame (NULL)),
+ SRC_AND_LOC, 1);
}
/* The 'normal_stop' observer notification callback. */
static void
-ada_normal_stop_observer (struct bpstats *unused_args, int unused_args2)
+ada_tasks_normal_stop_observer (struct bpstats *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. */
/* A routine to be called when the objfiles have changed. */
static void
-ada_new_objfile_observer (struct objfile *objfile)
+ada_tasks_new_objfile_observer (struct objfile *objfile)
{
struct inferior *inf;
ada_tasks_inferior_data_handle = register_inferior_data ();
/* Attach various observers. */
- observer_attach_normal_stop (ada_normal_stop_observer);
- observer_attach_new_objfile (ada_new_objfile_observer);
+ observer_attach_normal_stop (ada_tasks_normal_stop_observer);
+ observer_attach_new_objfile (ada_tasks_new_objfile_observer);
/* Some new commands provided by this module. */
add_info ("tasks", info_tasks_command,
Without argument, this command simply prints the current task ID"),
&cmdlist);
}
-