mirror of
https://github.com/bminor/binutils-gdb.git
synced 2025-12-26 17:18:55 +00:00
Add base ada language files
This commit is contained in:
806
gdb/ada-tasks.c
Normal file
806
gdb/ada-tasks.c
Normal file
@@ -0,0 +1,806 @@
|
||||
/* file ada-tasks.c: Ada tasking control for GDB
|
||||
Copyright 1997 Free Software Foundation, Inc.
|
||||
Contributed by Ada Core Technologies, Inc
|
||||
.
|
||||
This file is part of GDB.
|
||||
|
||||
[$Id$]
|
||||
Authors: Roch-Alexandre Nomine Beguin, Arnaud Charlet <charlet@gnat.com>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
*/
|
||||
|
||||
#include <ctype.h>
|
||||
#include "defs.h"
|
||||
#include "command.h"
|
||||
#include "value.h"
|
||||
#include "language.h"
|
||||
#include "inferior.h"
|
||||
#include "symtab.h"
|
||||
#include "target.h"
|
||||
#include "gdbcore.h"
|
||||
|
||||
#if (defined(__alpha__) && defined(__osf__) && !defined(__alpha_vxworks))
|
||||
#include <sys/procfs.h>
|
||||
#endif
|
||||
|
||||
#if (defined(__alpha__) && defined(__osf__) && !defined(VXWORKS_TARGET))
|
||||
#include "gregset.h"
|
||||
#endif
|
||||
|
||||
#include "ada-lang.h"
|
||||
|
||||
/* FIXME: move all this conditional compilation in description
|
||||
files or in configure.in */
|
||||
|
||||
#if defined (VXWORKS_TARGET)
|
||||
#define THREAD_TO_PID(tid,lwpid) (tid)
|
||||
|
||||
#elif defined (linux)
|
||||
#define THREAD_TO_PID(tid,lwpid) (0)
|
||||
|
||||
#elif (defined (sun) && defined (__SVR4))
|
||||
#define THREAD_TO_PID thread_to_pid
|
||||
|
||||
#elif defined (sgi) || defined (__WIN32__) || defined (hpux)
|
||||
#define THREAD_TO_PID(tid,lwpid) ((int)lwpid)
|
||||
|
||||
#else
|
||||
#define THREAD_TO_PID(tid,lwpid) (0)
|
||||
#endif
|
||||
|
||||
#if defined(__alpha__) && defined(__osf__) && !defined(VXWORKS_TARGET)
|
||||
#define THREAD_FETCH_REGISTERS dec_thread_fetch_registers
|
||||
#define GET_CURRENT_THREAD dec_thread_get_current_thread
|
||||
extern int dec_thread_get_registers (gdb_gregset_t *, gdb_fpregset_t *);
|
||||
#endif
|
||||
|
||||
#if defined (_AIX)
|
||||
#define THREAD_FETCH_REGISTERS aix_thread_fetch_registers
|
||||
#define GET_CURRENT_THREAD aix_thread_get_current_thread
|
||||
#endif
|
||||
|
||||
#if defined(VXWORKS_TARGET)
|
||||
#define GET_CURRENT_THREAD() ((void*)inferior_pid)
|
||||
#define THREAD_FETCH_REGISTERS() (-1)
|
||||
|
||||
#elif defined (sun) && defined (__SVR4)
|
||||
#define GET_CURRENT_THREAD solaris_thread_get_current_thread
|
||||
#define THREAD_FETCH_REGISTERS() (-1)
|
||||
extern void *GET_CURRENT_THREAD();
|
||||
|
||||
#elif defined (_AIX) || (defined(__alpha__) && defined(__osf__))
|
||||
extern void *GET_CURRENT_THREAD();
|
||||
|
||||
#elif defined (__WIN32__) || defined (hpux)
|
||||
#define GET_CURRENT_THREAD() (inferior_pid)
|
||||
#define THREAD_FETCH_REGISTERS() (-1)
|
||||
|
||||
#else
|
||||
#define GET_CURRENT_THREAD() (NULL)
|
||||
#define THREAD_FETCH_REGISTERS() (-1)
|
||||
#endif
|
||||
|
||||
#define KNOWN_TASKS_NAME "system__tasking__debug__known_tasks"
|
||||
|
||||
#define READ_MEMORY(addr, var) read_memory (addr, (char*) &var, sizeof (var))
|
||||
/* external declarations */
|
||||
|
||||
extern struct value* find_function_in_inferior (char *);
|
||||
|
||||
/* Global visible variables */
|
||||
|
||||
struct task_entry *task_list = NULL;
|
||||
int ada__tasks_check_symbol_table = 1;
|
||||
void *pthread_kern_addr = NULL;
|
||||
|
||||
#if (defined(__alpha__) && defined(__osf__) && !defined(VXWORKS_TARGET))
|
||||
gdb_gregset_t gregset_saved;
|
||||
gdb_fpregset_t fpregset_saved;
|
||||
#endif
|
||||
|
||||
/* The maximum number of tasks known to the Ada runtime */
|
||||
const int MAX_NUMBER_OF_KNOWN_TASKS = 1000;
|
||||
|
||||
/* the current task */
|
||||
int current_task = -1, current_task_id = -1, current_task_index;
|
||||
void *current_thread, *current_lwp;
|
||||
|
||||
char *ada_task_states[] =
|
||||
{
|
||||
"Unactivated",
|
||||
"Runnable",
|
||||
"Terminated",
|
||||
"Child Activation Wait",
|
||||
"Accept Statement",
|
||||
"Waiting on entry call",
|
||||
"Async Select Wait",
|
||||
"Delay Sleep",
|
||||
"Child Termination Wait",
|
||||
"Wait Child in Term Alt",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"Asynchronous Hold"
|
||||
};
|
||||
|
||||
/* Global internal types */
|
||||
|
||||
static char *ada_long_task_states[] =
|
||||
{
|
||||
"Unactivated",
|
||||
"Runnable",
|
||||
"Terminated",
|
||||
"Waiting for child activation",
|
||||
"Blocked in accept statement",
|
||||
"Waiting on entry call",
|
||||
"Asynchronous Selective Wait",
|
||||
"Delay Sleep",
|
||||
"Waiting for children termination",
|
||||
"Waiting for children in terminate alternative",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"Asynchronous Hold"
|
||||
};
|
||||
|
||||
/* Global internal variables */
|
||||
|
||||
static int highest_task_num = 0;
|
||||
int thread_support = 0; /* 1 if the thread library in use is supported */
|
||||
static int gdbtk_task_initialization = 0;
|
||||
|
||||
static int add_task_entry (p_task_id, index)
|
||||
void *p_task_id;
|
||||
int index;
|
||||
{
|
||||
struct task_entry *new_task_entry = NULL;
|
||||
struct task_entry *pt;
|
||||
|
||||
highest_task_num++;
|
||||
new_task_entry = malloc (sizeof (struct task_entry));
|
||||
new_task_entry->task_num = highest_task_num;
|
||||
new_task_entry->task_id = p_task_id;
|
||||
new_task_entry->known_tasks_index = index;
|
||||
new_task_entry->next_task = NULL;
|
||||
pt = task_list;
|
||||
if (pt)
|
||||
{
|
||||
while (pt->next_task)
|
||||
pt = pt->next_task;
|
||||
pt->next_task = new_task_entry;
|
||||
pt->stack_per = 0;
|
||||
}
|
||||
else task_list = new_task_entry;
|
||||
return new_task_entry->task_num;
|
||||
}
|
||||
|
||||
int
|
||||
get_entry_number (p_task_id)
|
||||
void *p_task_id;
|
||||
{
|
||||
struct task_entry *pt;
|
||||
|
||||
pt = task_list;
|
||||
while (pt != NULL)
|
||||
{
|
||||
if (pt->task_id == p_task_id)
|
||||
return pt->task_num;
|
||||
pt = pt->next_task;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct task_entry *get_thread_entry_vptr (thread)
|
||||
void *thread;
|
||||
{
|
||||
struct task_entry *pt;
|
||||
|
||||
pt = task_list;
|
||||
while (pt != NULL)
|
||||
{
|
||||
if (pt->thread == thread)
|
||||
return pt;
|
||||
pt = pt->next_task;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct task_entry *get_entry_vptr (p_task_num)
|
||||
int p_task_num;
|
||||
{
|
||||
struct task_entry *pt;
|
||||
|
||||
pt = task_list;
|
||||
while (pt)
|
||||
{
|
||||
if (pt->task_num == p_task_num)
|
||||
return pt;
|
||||
pt = pt->next_task;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void init_task_list ()
|
||||
{
|
||||
struct task_entry *pt, *old_pt;
|
||||
|
||||
pt = task_list;
|
||||
while (pt)
|
||||
{
|
||||
old_pt = pt;
|
||||
pt = pt->next_task;
|
||||
free (old_pt);
|
||||
};
|
||||
task_list = NULL;
|
||||
highest_task_num = 0;
|
||||
}
|
||||
|
||||
int valid_task_id (task)
|
||||
int task;
|
||||
{
|
||||
return get_entry_vptr (task) != NULL;
|
||||
}
|
||||
|
||||
void *get_self_id ()
|
||||
{
|
||||
struct value* val;
|
||||
void *self_id;
|
||||
int result;
|
||||
struct task_entry *ent;
|
||||
extern int do_not_insert_breakpoints;
|
||||
|
||||
#if !((defined(sun) && defined(__SVR4)) || defined(VXWORKS_TARGET) || defined(__WIN32__))
|
||||
if (thread_support)
|
||||
#endif
|
||||
{
|
||||
ent = get_thread_entry_vptr (GET_CURRENT_THREAD ());
|
||||
return ent ? ent->task_id : 0;
|
||||
}
|
||||
|
||||
/* FIXME: calling a function in the inferior with a multithreaded application
|
||||
is not reliable, so return NULL if there is no safe way to get the current
|
||||
task */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int get_current_task ()
|
||||
{
|
||||
int result;
|
||||
|
||||
/* FIXME: language_ada should be defined in defs.h */
|
||||
/* if (current_language->la_language != language_ada) return -1; */
|
||||
|
||||
result = get_entry_number (get_self_id ());
|
||||
|
||||
/* return -1 if not found */
|
||||
return result == 0 ? -1 : result;
|
||||
}
|
||||
|
||||
/* Print detailed information about specified task */
|
||||
|
||||
static void
|
||||
info_task (arg, from_tty)
|
||||
char *arg;
|
||||
int from_tty;
|
||||
{
|
||||
void *temp_task;
|
||||
struct task_entry *pt, *pt2;
|
||||
void *self_id, *caller;
|
||||
struct task_fields atcb, atcb2;
|
||||
struct entry_call call;
|
||||
int bounds [2];
|
||||
char image [256];
|
||||
int num;
|
||||
|
||||
/* FIXME: language_ada should be defined in defs.h */
|
||||
/* if (current_language->la_language != language_ada)
|
||||
{
|
||||
printf_filtered ("The current language does not support tasks.\n");
|
||||
return;
|
||||
}
|
||||
*/
|
||||
pt = get_entry_vptr (atoi (arg));
|
||||
if (pt == NULL)
|
||||
{
|
||||
printf_filtered ("Task %s not found.\n", arg);
|
||||
return;
|
||||
}
|
||||
|
||||
temp_task = pt->task_id;
|
||||
|
||||
/* read the atcb in the inferior */
|
||||
READ_MEMORY ((CORE_ADDR) temp_task, atcb);
|
||||
|
||||
/* print the Ada task id */
|
||||
printf_filtered ("Ada Task: %p\n", temp_task);
|
||||
|
||||
/* print the name of the task */
|
||||
if (atcb.image.P_ARRAY != NULL) {
|
||||
READ_MEMORY ((CORE_ADDR) EXTRACT_ADDRESS (atcb.image.P_BOUNDS), bounds);
|
||||
bounds [1] = EXTRACT_INT (bounds [1]);
|
||||
read_memory ((CORE_ADDR) EXTRACT_ADDRESS (atcb.image.P_ARRAY),
|
||||
(char*) &image, bounds [1]);
|
||||
printf_filtered ("Name: %.*s\n", bounds [1], image);
|
||||
}
|
||||
else printf_filtered ("<no name>\n");
|
||||
|
||||
/* print the thread id */
|
||||
|
||||
if ((long) pt->thread < 65536)
|
||||
printf_filtered ("Thread: %ld\n", (long int) pt->thread);
|
||||
else
|
||||
printf_filtered ("Thread: %p\n", pt->thread);
|
||||
|
||||
if ((long) pt->lwp != 0)
|
||||
{
|
||||
if ((long) pt->lwp < 65536)
|
||||
printf_filtered ("LWP: %ld\n", (long int) pt->lwp);
|
||||
else
|
||||
printf_filtered ("LWP: %p\n", pt->lwp);
|
||||
}
|
||||
|
||||
/* print the parent gdb task id */
|
||||
num = get_entry_number (EXTRACT_ADDRESS (atcb.parent));
|
||||
if (num != 0)
|
||||
{
|
||||
printf_filtered ("Parent: %d", num);
|
||||
pt2 = get_entry_vptr (num);
|
||||
READ_MEMORY ((CORE_ADDR) pt2->task_id, atcb2);
|
||||
|
||||
/* print the name of the task */
|
||||
if (atcb2.image.P_ARRAY != NULL) {
|
||||
READ_MEMORY ((CORE_ADDR) EXTRACT_ADDRESS (atcb2.image.P_BOUNDS),
|
||||
bounds);
|
||||
bounds [1] = EXTRACT_INT (bounds [1]);
|
||||
read_memory ((CORE_ADDR) EXTRACT_ADDRESS (atcb2.image.P_ARRAY),
|
||||
(char*) &image, bounds [1]);
|
||||
printf_filtered (" (%.*s)\n", bounds [1], image);
|
||||
}
|
||||
else
|
||||
printf_filtered ("\n");
|
||||
}
|
||||
else
|
||||
printf_filtered ("No parent\n");
|
||||
|
||||
/* print the base priority of the task */
|
||||
printf_filtered ("Base Priority: %d\n", EXTRACT_INT (atcb.priority));
|
||||
|
||||
/* print the current state of the task */
|
||||
|
||||
/* check if this task is accepting a rendezvous */
|
||||
if (atcb.call == NULL)
|
||||
caller = NULL;
|
||||
else {
|
||||
READ_MEMORY ((CORE_ADDR) EXTRACT_ADDRESS (atcb.call), call);
|
||||
caller = EXTRACT_ADDRESS (call.self);
|
||||
}
|
||||
|
||||
if (caller != NULL)
|
||||
{
|
||||
num = get_entry_number (caller);
|
||||
printf_filtered ("Accepting rendezvous with %d", num);
|
||||
|
||||
if (num != 0)
|
||||
{
|
||||
pt2 = get_entry_vptr (num);
|
||||
READ_MEMORY ((CORE_ADDR) pt2->task_id, atcb2);
|
||||
|
||||
/* print the name of the task */
|
||||
if (atcb2.image.P_ARRAY != NULL) {
|
||||
READ_MEMORY ((CORE_ADDR) EXTRACT_ADDRESS (atcb2.image.P_BOUNDS),
|
||||
bounds);
|
||||
bounds [1] = EXTRACT_INT (bounds [1]);
|
||||
read_memory ((CORE_ADDR) EXTRACT_ADDRESS (atcb2.image.P_ARRAY),
|
||||
(char*) &image, bounds [1]);
|
||||
printf_filtered (" (%.*s)\n", bounds [1], image);
|
||||
}
|
||||
else
|
||||
printf_filtered ("\n");
|
||||
}
|
||||
else
|
||||
printf_filtered ("\n");
|
||||
}
|
||||
else
|
||||
printf_filtered ("State: %s\n", ada_long_task_states [atcb.state]);
|
||||
}
|
||||
|
||||
#if 0
|
||||
|
||||
/* A useful function that shows the alignment of all the fields in the
|
||||
tasks_fields structure
|
||||
*/
|
||||
|
||||
print_align ()
|
||||
{
|
||||
struct task_fields tf;
|
||||
void *tf_base = &(tf);
|
||||
void *tf_state = &(tf.state);
|
||||
void *tf_entry_num = &(tf.entry_num);
|
||||
void *tf_parent = &(tf.parent);
|
||||
void *tf_priority = &(tf.priority);
|
||||
void *tf_current_priority = &(tf.current_priority);
|
||||
void *tf_image = &(tf.image);
|
||||
void *tf_call = &(tf.call);
|
||||
void *tf_thread = &(tf.thread);
|
||||
void *tf_lwp = &(tf.lwp);
|
||||
printf_filtered ("\n");
|
||||
printf_filtered ("(tf_base = 0x%x)\n", tf_base);
|
||||
printf_filtered ("task_fields.entry_num at %3d (0x%x)\n", tf_entry_num - tf_base, tf_entry_num);
|
||||
printf_filtered ("task_fields.state at %3d (0x%x)\n", tf_state - tf_base, tf_state);
|
||||
printf_filtered ("task_fields.parent at %3d (0x%x)\n", tf_parent - tf_base, tf_parent);
|
||||
printf_filtered ("task_fields.priority at %3d (0x%x)\n", tf_priority - tf_base, tf_priority);
|
||||
printf_filtered ("task_fields.current_priority at %3d (0x%x)\n", tf_current_priority - tf_base, tf_current_priority);
|
||||
printf_filtered ("task_fields.image at %3d (0x%x)\n", tf_image - tf_base, tf_image);
|
||||
printf_filtered ("task_fields.call at %3d (0x%x)\n", tf_call - tf_base, tf_call);
|
||||
printf_filtered ("task_fields.thread at %3d (0x%x)\n", tf_thread - tf_base, tf_thread);
|
||||
printf_filtered ("task_fields.lwp at %3d (0x%x)\n", tf_lwp - tf_base, tf_lwp);
|
||||
printf_filtered ("\n");
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Print information about currently known tasks */
|
||||
|
||||
static void
|
||||
info_tasks (arg, from_tty)
|
||||
char *arg;
|
||||
int from_tty;
|
||||
{
|
||||
struct value* val;
|
||||
int i, task_number, state;
|
||||
void *temp_task, *temp_tasks [MAX_NUMBER_OF_KNOWN_TASKS];
|
||||
struct task_entry *pt;
|
||||
void *self_id, *caller, *thread_id=NULL;
|
||||
struct task_fields atcb;
|
||||
struct entry_call call;
|
||||
int bounds [2];
|
||||
char image [256];
|
||||
int size;
|
||||
char car;
|
||||
|
||||
#if defined(__alpha__) && defined(__osf__) && !defined(VXWORKS_TARGET)
|
||||
pthreadTeb_t thr;
|
||||
gdb_gregset_t regs;
|
||||
#endif
|
||||
|
||||
static struct symbol *sym;
|
||||
static struct minimal_symbol *msym;
|
||||
static void *known_tasks_addr = NULL;
|
||||
|
||||
int init_only = gdbtk_task_initialization;
|
||||
gdbtk_task_initialization = 0;
|
||||
|
||||
task_number = 0;
|
||||
|
||||
if (PIDGET(inferior_ptid) == 0)
|
||||
{
|
||||
printf_filtered ("The program is not being run under gdb. ");
|
||||
printf_filtered ("Use 'run' or 'attach' first.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (ada__tasks_check_symbol_table)
|
||||
{
|
||||
thread_support = 0;
|
||||
#if (defined(__alpha__) && defined(__osf__) & !defined(VXWORKS_TARGET)) || \
|
||||
defined (_AIX)
|
||||
thread_support = 1;
|
||||
#endif
|
||||
|
||||
msym = lookup_minimal_symbol (KNOWN_TASKS_NAME, NULL, NULL);
|
||||
if (msym != NULL)
|
||||
known_tasks_addr = (void *) SYMBOL_VALUE_ADDRESS (msym);
|
||||
else
|
||||
#ifndef VXWORKS_TARGET
|
||||
return;
|
||||
#else
|
||||
{
|
||||
if (target_lookup_symbol (KNOWN_TASKS_NAME, &known_tasks_addr) != 0)
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
ada__tasks_check_symbol_table = 0;
|
||||
}
|
||||
|
||||
if (known_tasks_addr == NULL)
|
||||
return;
|
||||
|
||||
#if !((defined(sun) && defined(__SVR4)) || defined(VXWORKS_TARGET) || defined(__WIN32__) || defined (hpux))
|
||||
if (thread_support)
|
||||
#endif
|
||||
thread_id = GET_CURRENT_THREAD ();
|
||||
|
||||
/* then we get a list of tasks created */
|
||||
|
||||
init_task_list ();
|
||||
|
||||
READ_MEMORY ((CORE_ADDR) known_tasks_addr, temp_tasks);
|
||||
|
||||
for (i=0; i<MAX_NUMBER_OF_KNOWN_TASKS; i++)
|
||||
{
|
||||
temp_task = EXTRACT_ADDRESS (temp_tasks[i]);
|
||||
|
||||
if (temp_task != NULL)
|
||||
{
|
||||
task_number = get_entry_number (temp_task);
|
||||
if (task_number == 0)
|
||||
task_number = add_task_entry (temp_task, i);
|
||||
}
|
||||
}
|
||||
|
||||
/* Return without printing anything if this function was called in
|
||||
order to init GDBTK tasking. */
|
||||
|
||||
if (init_only) return;
|
||||
|
||||
/* print the header */
|
||||
|
||||
#if defined(__alpha__) && defined(__osf__) && !defined(VXWORKS_TARGET)
|
||||
printf_filtered
|
||||
(" ID TID P-ID Pri Stack %% State Name\n");
|
||||
#else
|
||||
printf_filtered (" ID TID P-ID Pri State Name\n");
|
||||
#endif
|
||||
|
||||
/* Now that we have a list of task id's, we can print them */
|
||||
pt = task_list;
|
||||
while (pt)
|
||||
{
|
||||
temp_task = pt->task_id;
|
||||
|
||||
/* read the atcb in the inferior */
|
||||
READ_MEMORY ((CORE_ADDR) temp_task, atcb);
|
||||
|
||||
/* store the thread id for future use */
|
||||
pt->thread = EXTRACT_ADDRESS (atcb.thread);
|
||||
|
||||
#if defined (linux)
|
||||
pt->lwp = (void *) THREAD_TO_PID (atcb.thread, 0);
|
||||
#else
|
||||
pt->lwp = EXTRACT_ADDRESS (atcb.lwp);
|
||||
#endif
|
||||
|
||||
/* print a star if this task is the current one */
|
||||
if (thread_id)
|
||||
#if defined (__WIN32__) || defined (SGI) || defined (hpux)
|
||||
printf_filtered (pt->lwp == thread_id ? "*" : " ");
|
||||
#else
|
||||
printf_filtered (pt->thread == thread_id ? "*" : " ");
|
||||
#endif
|
||||
|
||||
/* print the gdb task id */
|
||||
printf_filtered ("%3d", pt->task_num);
|
||||
|
||||
/* print the Ada task id */
|
||||
#ifndef VXWORKS_TARGET
|
||||
printf_filtered (" %9lx", (long) temp_task);
|
||||
#else
|
||||
#ifdef TARGET_64
|
||||
printf_filtered (" %#9lx", (unsigned long)pt->thread & 0x3ffffffffff);
|
||||
#else
|
||||
printf_filtered (" %#9lx", (long)pt->thread);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* print the parent gdb task id */
|
||||
printf_filtered
|
||||
(" %4d", get_entry_number (EXTRACT_ADDRESS (atcb.parent)));
|
||||
|
||||
/* print the base priority of the task */
|
||||
printf_filtered (" %3d", EXTRACT_INT (atcb.priority));
|
||||
|
||||
#if defined(__alpha__) && defined(__osf__) && !defined(VXWORKS_TARGET)
|
||||
if (pt->task_num == 1 || atcb.state == Terminated)
|
||||
{
|
||||
printf_filtered (" Unknown");
|
||||
goto next;
|
||||
}
|
||||
|
||||
read_memory ((CORE_ADDR)atcb.thread, &thr, sizeof (thr));
|
||||
current_thread = atcb.thread;
|
||||
regs.regs [SP_REGNUM] = 0;
|
||||
if (dec_thread_get_registers (®s, NULL) == 0) {
|
||||
pt->stack_per = (100 * ((long)thr.__stack_base -
|
||||
regs.regs [SP_REGNUM])) / thr.__stack_size;
|
||||
/* if the thread is terminated but still there, the
|
||||
stack_base/size values are erroneous. Try to patch it */
|
||||
if (pt->stack_per < 0 || pt->stack_per > 100) pt->stack_per = 0;
|
||||
}
|
||||
|
||||
/* print information about stack space used in the thread */
|
||||
if (thr.__stack_size < 1024*1024)
|
||||
{
|
||||
size = thr.__stack_size / 1024;
|
||||
car = 'K';
|
||||
}
|
||||
else if (thr.__stack_size < 1024*1024*1024)
|
||||
{
|
||||
size = thr.__stack_size / 1024 / 1024;
|
||||
car = 'M';
|
||||
}
|
||||
else /* Who knows... */
|
||||
{
|
||||
size = thr.__stack_size / 1024 / 1024 / 1024;
|
||||
car = 'G';
|
||||
}
|
||||
printf_filtered (" %4d%c %2d", size, car, pt->stack_per);
|
||||
next:
|
||||
#endif
|
||||
|
||||
/* print the current state of the task */
|
||||
|
||||
/* check if this task is accepting a rendezvous */
|
||||
if (atcb.call == NULL)
|
||||
caller = NULL;
|
||||
else {
|
||||
READ_MEMORY ((CORE_ADDR) EXTRACT_ADDRESS (atcb.call), call);
|
||||
caller = EXTRACT_ADDRESS (call.self);
|
||||
}
|
||||
|
||||
if (caller != NULL)
|
||||
printf_filtered (" Accepting RV with %-4d", get_entry_number (caller));
|
||||
else
|
||||
{
|
||||
state = atcb.state;
|
||||
#if defined (__WIN32__) || defined (SGI) || defined (hpux)
|
||||
if (state == Runnable && (thread_id && pt->lwp == thread_id))
|
||||
#else
|
||||
if (state == Runnable && (thread_id && pt->thread == thread_id))
|
||||
#endif
|
||||
/* Replace "Runnable" by "Running" if this is the current task */
|
||||
printf_filtered (" %-22s", "Running");
|
||||
else
|
||||
printf_filtered (" %-22s", ada_task_states [state]);
|
||||
}
|
||||
|
||||
/* finally, print the name of the task */
|
||||
if (atcb.image.P_ARRAY != NULL) {
|
||||
READ_MEMORY ((CORE_ADDR) EXTRACT_ADDRESS (atcb.image.P_BOUNDS), bounds);
|
||||
bounds [1] = EXTRACT_INT (bounds [1]);
|
||||
read_memory ((CORE_ADDR) EXTRACT_ADDRESS (atcb.image.P_ARRAY),
|
||||
(char*)&image, bounds [1]);
|
||||
printf_filtered (" %.*s\n", bounds [1], image);
|
||||
}
|
||||
else printf_filtered (" <no name>\n");
|
||||
|
||||
pt = pt->next_task;
|
||||
}
|
||||
}
|
||||
|
||||
/* Task list initialization for GDB-Tk. We basically use info_tasks()
|
||||
to initialize our variables, but abort that function before we
|
||||
actually print anything. */
|
||||
|
||||
int
|
||||
gdbtk_tcl_tasks_initialize ()
|
||||
{
|
||||
gdbtk_task_initialization = 1;
|
||||
info_tasks ("", gdb_stdout);
|
||||
|
||||
return (task_list != NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
info_tasks_command (arg, from_tty)
|
||||
char *arg;
|
||||
int from_tty;
|
||||
{
|
||||
if (arg == NULL || *arg == '\000')
|
||||
info_tasks (arg, from_tty);
|
||||
else
|
||||
info_task (arg, from_tty);
|
||||
}
|
||||
|
||||
/* Switch from one thread to another. */
|
||||
|
||||
static void
|
||||
switch_to_thread (ptid_t ptid)
|
||||
|
||||
{
|
||||
if (ptid_equal (ptid, inferior_ptid))
|
||||
return;
|
||||
|
||||
inferior_ptid = ptid;
|
||||
flush_cached_frames ();
|
||||
registers_changed ();
|
||||
stop_pc = read_pc ();
|
||||
select_frame (get_current_frame ());
|
||||
}
|
||||
|
||||
/* Switch to a specified task. */
|
||||
|
||||
static int task_switch (tid, lwpid)
|
||||
void *tid, *lwpid;
|
||||
{
|
||||
int res = 0, pid;
|
||||
|
||||
if (thread_support)
|
||||
{
|
||||
flush_cached_frames ();
|
||||
|
||||
if (current_task != current_task_id)
|
||||
{
|
||||
res = THREAD_FETCH_REGISTERS ();
|
||||
}
|
||||
else
|
||||
{
|
||||
#if (defined(__alpha__) && defined(__osf__) && !defined(VXWORKS_TARGET))
|
||||
supply_gregset (&gregset_saved);
|
||||
supply_fpregset (&fpregset_saved);
|
||||
#endif
|
||||
}
|
||||
|
||||
if (res == 0) stop_pc = read_pc();
|
||||
select_frame (get_current_frame ());
|
||||
return res;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void task_command (tidstr, from_tty)
|
||||
char *tidstr;
|
||||
int from_tty;
|
||||
{
|
||||
int num;
|
||||
struct task_entry *e;
|
||||
|
||||
if (!tidstr)
|
||||
error ("Please specify a task ID. Use the \"info tasks\" command to\n"
|
||||
"see the IDs of currently known tasks.");
|
||||
|
||||
num = atoi (tidstr);
|
||||
e = get_entry_vptr (num);
|
||||
|
||||
if (e == NULL)
|
||||
error ("Task ID %d not known. Use the \"info tasks\" command to\n"
|
||||
"see the IDs of currently known tasks.", num);
|
||||
|
||||
if (current_task_id == -1)
|
||||
{
|
||||
#if (defined(__alpha__) && defined(__osf__) && !defined(VXWORKS_TARGET))
|
||||
fill_gregset (&gregset_saved, -1);
|
||||
fill_fpregset (&fpregset_saved, -1);
|
||||
#endif
|
||||
current_task_id = get_current_task ();
|
||||
}
|
||||
|
||||
current_task = num;
|
||||
current_task_index = e->known_tasks_index;
|
||||
current_thread = e->thread;
|
||||
current_lwp = e->lwp;
|
||||
if (task_switch (e->thread, e->lwp) == 0)
|
||||
{
|
||||
/* FIXME: find_printable_frame should be defined in frame.h, and
|
||||
implemented in ada-lang.c */
|
||||
/* find_printable_frame (selected_frame, frame_relative_level (selected_frame));*/
|
||||
printf_filtered ("[Switching to task %d]\n", num);
|
||||
print_stack_frame (selected_frame, frame_relative_level (selected_frame), 1);
|
||||
}
|
||||
else
|
||||
printf_filtered ("Unable to switch to task %d\n", num);
|
||||
}
|
||||
|
||||
void
|
||||
_initialize_tasks ()
|
||||
{
|
||||
static struct cmd_list_element *task_cmd_list = NULL;
|
||||
extern struct cmd_list_element *cmdlist;
|
||||
|
||||
add_info (
|
||||
"tasks", info_tasks_command,
|
||||
"Without argument: list all known Ada tasks, with status information.\n"
|
||||
"info tasks n: print detailed information of task n.\n");
|
||||
|
||||
add_prefix_cmd ("task", class_run, task_command,
|
||||
"Use this command to switch between tasks.\n\
|
||||
The new task ID must be currently known.", &task_cmd_list, "task ", 1,
|
||||
&cmdlist);
|
||||
}
|
||||
Reference in New Issue
Block a user