1130803Smarcel/* file ada-tasks.c: Ada tasking control for GDB 2130803Smarcel Copyright 1997 Free Software Foundation, Inc. 3130803Smarcel Contributed by Ada Core Technologies, Inc 4130803Smarcel. 5130803Smarcel This file is part of GDB. 6130803Smarcel 7130803Smarcel [$Id: ada-tasks.c,v 1.7 2003/06/17 20:58:32 ciceron Exp $] 8130803Smarcel Authors: Roch-Alexandre Nomine Beguin, Arnaud Charlet <charlet@gnat.com> 9130803Smarcel 10130803Smarcel This program is free software; you can redistribute it and/or modify 11130803Smarcel it under the terms of the GNU General Public License as published by 12130803Smarcel the Free Software Foundation; either version 2 of the License, or 13130803Smarcel (at your option) any later version. 14130803Smarcel 15130803Smarcel*/ 16130803Smarcel 17130803Smarcel#include <ctype.h> 18130803Smarcel#include "defs.h" 19130803Smarcel#include "command.h" 20130803Smarcel#include "value.h" 21130803Smarcel#include "language.h" 22130803Smarcel#include "inferior.h" 23130803Smarcel#include "symtab.h" 24130803Smarcel#include "target.h" 25130803Smarcel#include "regcache.h" 26130803Smarcel#include "gdbcore.h" 27130803Smarcel 28130803Smarcel#if (defined(__alpha__) && defined(__osf__) && !defined(__alpha_vxworks)) 29130803Smarcel#include <sys/procfs.h> 30130803Smarcel#endif 31130803Smarcel 32130803Smarcel#if (defined(__alpha__) && defined(__osf__) && !defined(VXWORKS_TARGET)) 33130803Smarcel#include "gregset.h" 34130803Smarcel#endif 35130803Smarcel 36130803Smarcel#include "ada-lang.h" 37130803Smarcel 38130803Smarcel/* FIXME: move all this conditional compilation in description 39130803Smarcel files or in configure.in */ 40130803Smarcel 41130803Smarcel#if defined (VXWORKS_TARGET) 42130803Smarcel#define THREAD_TO_PID(tid,lwpid) (tid) 43130803Smarcel 44130803Smarcel#elif defined (linux) 45130803Smarcel#define THREAD_TO_PID(tid,lwpid) (0) 46130803Smarcel 47130803Smarcel#elif (defined (sun) && defined (__SVR4)) 48130803Smarcel#define THREAD_TO_PID thread_to_pid 49130803Smarcel 50130803Smarcel#elif defined (sgi) || defined (__WIN32__) || defined (hpux) 51130803Smarcel#define THREAD_TO_PID(tid,lwpid) ((int)lwpid) 52130803Smarcel 53130803Smarcel#else 54130803Smarcel#define THREAD_TO_PID(tid,lwpid) (0) 55130803Smarcel#endif 56130803Smarcel 57130803Smarcel#if defined(__alpha__) && defined(__osf__) && !defined(VXWORKS_TARGET) 58130803Smarcel#define THREAD_FETCH_REGISTERS dec_thread_fetch_registers 59130803Smarcel#define GET_CURRENT_THREAD dec_thread_get_current_thread 60130803Smarcelextern int dec_thread_get_registers (gdb_gregset_t *, gdb_fpregset_t *); 61130803Smarcel#endif 62130803Smarcel 63130803Smarcel#if defined (_AIX) 64130803Smarcel#define THREAD_FETCH_REGISTERS aix_thread_fetch_registers 65130803Smarcel#define GET_CURRENT_THREAD aix_thread_get_current_thread 66130803Smarcel#endif 67130803Smarcel 68130803Smarcel#if defined(VXWORKS_TARGET) 69130803Smarcel#define GET_CURRENT_THREAD() ((void*)inferior_pid) 70130803Smarcel#define THREAD_FETCH_REGISTERS() (-1) 71130803Smarcel 72130803Smarcel#elif defined (sun) && defined (__SVR4) 73130803Smarcel#define GET_CURRENT_THREAD solaris_thread_get_current_thread 74130803Smarcel#define THREAD_FETCH_REGISTERS() (-1) 75130803Smarcelextern void *GET_CURRENT_THREAD (); 76130803Smarcel 77130803Smarcel#elif defined (_AIX) || (defined(__alpha__) && defined(__osf__)) 78130803Smarcelextern void *GET_CURRENT_THREAD (); 79130803Smarcel 80130803Smarcel#elif defined (__WIN32__) || defined (hpux) 81130803Smarcel#define GET_CURRENT_THREAD() (inferior_pid) 82130803Smarcel#define THREAD_FETCH_REGISTERS() (-1) 83130803Smarcel 84130803Smarcel#else 85130803Smarcel#define GET_CURRENT_THREAD() (NULL) 86130803Smarcel#define THREAD_FETCH_REGISTERS() (-1) 87130803Smarcel#endif 88130803Smarcel 89130803Smarcel#define KNOWN_TASKS_NAME "system__tasking__debug__known_tasks" 90130803Smarcel 91130803Smarcel#define READ_MEMORY(addr, var) read_memory (addr, (char*) &var, sizeof (var)) 92130803Smarcel/* external declarations */ 93130803Smarcel 94130803Smarcel/* Global visible variables */ 95130803Smarcel 96130803Smarcelstruct task_entry *task_list = NULL; 97130803Smarcelint ada__tasks_check_symbol_table = 1; 98130803Smarcelvoid *pthread_kern_addr = NULL; 99130803Smarcel 100130803Smarcel#if (defined(__alpha__) && defined(__osf__) && !defined(VXWORKS_TARGET)) 101130803Smarcelgdb_gregset_t gregset_saved; 102130803Smarcelgdb_fpregset_t fpregset_saved; 103130803Smarcel#endif 104130803Smarcel 105130803Smarcel/* The maximum number of tasks known to the Ada runtime */ 106130803Smarcelconst int MAX_NUMBER_OF_KNOWN_TASKS = 1000; 107130803Smarcel 108130803Smarcel/* the current task */ 109130803Smarcelint current_task = -1, current_task_id = -1, current_task_index; 110130803Smarcelvoid *current_thread, *current_lwp; 111130803Smarcel 112130803Smarcelchar *ada_task_states[] = { 113130803Smarcel "Unactivated", 114130803Smarcel "Runnable", 115130803Smarcel "Terminated", 116130803Smarcel "Child Activation Wait", 117130803Smarcel "Accept Statement", 118130803Smarcel "Waiting on entry call", 119130803Smarcel "Async Select Wait", 120130803Smarcel "Delay Sleep", 121130803Smarcel "Child Termination Wait", 122130803Smarcel "Wait Child in Term Alt", 123130803Smarcel "", 124130803Smarcel "", 125130803Smarcel "", 126130803Smarcel "", 127130803Smarcel "Asynchronous Hold" 128130803Smarcel}; 129130803Smarcel 130130803Smarcel/* Global internal types */ 131130803Smarcel 132130803Smarcelstatic char *ada_long_task_states[] = { 133130803Smarcel "Unactivated", 134130803Smarcel "Runnable", 135130803Smarcel "Terminated", 136130803Smarcel "Waiting for child activation", 137130803Smarcel "Blocked in accept statement", 138130803Smarcel "Waiting on entry call", 139130803Smarcel "Asynchronous Selective Wait", 140130803Smarcel "Delay Sleep", 141130803Smarcel "Waiting for children termination", 142130803Smarcel "Waiting for children in terminate alternative", 143130803Smarcel "", 144130803Smarcel "", 145130803Smarcel "", 146130803Smarcel "", 147130803Smarcel "Asynchronous Hold" 148130803Smarcel}; 149130803Smarcel 150130803Smarcel/* Global internal variables */ 151130803Smarcel 152130803Smarcelstatic int highest_task_num = 0; 153130803Smarcelint thread_support = 0; /* 1 if the thread library in use is supported */ 154130803Smarcelstatic int gdbtk_task_initialization = 0; 155130803Smarcel 156130803Smarcelstatic int 157130803Smarceladd_task_entry (void *p_task_id, int index) 158130803Smarcel{ 159130803Smarcel struct task_entry *new_task_entry = NULL; 160130803Smarcel struct task_entry *pt; 161130803Smarcel 162130803Smarcel highest_task_num++; 163130803Smarcel new_task_entry = xmalloc (sizeof (struct task_entry)); 164130803Smarcel new_task_entry->task_num = highest_task_num; 165130803Smarcel new_task_entry->task_id = p_task_id; 166130803Smarcel new_task_entry->known_tasks_index = index; 167130803Smarcel new_task_entry->next_task = NULL; 168130803Smarcel pt = task_list; 169130803Smarcel if (pt) 170130803Smarcel { 171130803Smarcel while (pt->next_task) 172130803Smarcel pt = pt->next_task; 173130803Smarcel pt->next_task = new_task_entry; 174130803Smarcel pt->stack_per = 0; 175130803Smarcel } 176130803Smarcel else 177130803Smarcel task_list = new_task_entry; 178130803Smarcel return new_task_entry->task_num; 179130803Smarcel} 180130803Smarcel 181130803Smarcelint 182130803Smarcelget_entry_number (void *p_task_id) 183130803Smarcel{ 184130803Smarcel struct task_entry *pt; 185130803Smarcel 186130803Smarcel pt = task_list; 187130803Smarcel while (pt != NULL) 188130803Smarcel { 189130803Smarcel if (pt->task_id == p_task_id) 190130803Smarcel return pt->task_num; 191130803Smarcel pt = pt->next_task; 192130803Smarcel } 193130803Smarcel return 0; 194130803Smarcel} 195130803Smarcel 196130803Smarcelstatic struct task_entry * 197130803Smarcelget_thread_entry_vptr (void *thread) 198130803Smarcel{ 199130803Smarcel struct task_entry *pt; 200130803Smarcel 201130803Smarcel pt = task_list; 202130803Smarcel while (pt != NULL) 203130803Smarcel { 204130803Smarcel if (pt->thread == thread) 205130803Smarcel return pt; 206130803Smarcel pt = pt->next_task; 207130803Smarcel } 208130803Smarcel return 0; 209130803Smarcel} 210130803Smarcel 211130803Smarcelstatic struct task_entry * 212130803Smarcelget_entry_vptr (int p_task_num) 213130803Smarcel{ 214130803Smarcel struct task_entry *pt; 215130803Smarcel 216130803Smarcel pt = task_list; 217130803Smarcel while (pt) 218130803Smarcel { 219130803Smarcel if (pt->task_num == p_task_num) 220130803Smarcel return pt; 221130803Smarcel pt = pt->next_task; 222130803Smarcel } 223130803Smarcel return NULL; 224130803Smarcel} 225130803Smarcel 226130803Smarcelvoid 227130803Smarcelinit_task_list (void) 228130803Smarcel{ 229130803Smarcel struct task_entry *pt, *old_pt; 230130803Smarcel 231130803Smarcel pt = task_list; 232130803Smarcel while (pt) 233130803Smarcel { 234130803Smarcel old_pt = pt; 235130803Smarcel pt = pt->next_task; 236130803Smarcel xfree (old_pt); 237130803Smarcel }; 238130803Smarcel task_list = NULL; 239130803Smarcel highest_task_num = 0; 240130803Smarcel} 241130803Smarcel 242130803Smarcelint 243130803Smarcelvalid_task_id (int task) 244130803Smarcel{ 245130803Smarcel return get_entry_vptr (task) != NULL; 246130803Smarcel} 247130803Smarcel 248130803Smarcelvoid * 249130803Smarcelget_self_id (void) 250130803Smarcel{ 251130803Smarcel struct value *val; 252130803Smarcel void *self_id; 253130803Smarcel int result; 254130803Smarcel struct task_entry *ent; 255130803Smarcel extern int do_not_insert_breakpoints; 256130803Smarcel 257130803Smarcel#if !((defined(sun) && defined(__SVR4)) || defined(VXWORKS_TARGET) || defined(__WIN32__)) 258130803Smarcel if (thread_support) 259130803Smarcel#endif 260130803Smarcel { 261130803Smarcel ent = get_thread_entry_vptr (GET_CURRENT_THREAD ()); 262130803Smarcel return ent ? ent->task_id : 0; 263130803Smarcel } 264130803Smarcel 265130803Smarcel /* FIXME: calling a function in the inferior with a multithreaded application 266130803Smarcel is not reliable, so return NULL if there is no safe way to get the current 267130803Smarcel task */ 268130803Smarcel return NULL; 269130803Smarcel} 270130803Smarcel 271130803Smarcelint 272130803Smarcelget_current_task (void) 273130803Smarcel{ 274130803Smarcel int result; 275130803Smarcel 276130803Smarcel /* FIXME: language_ada should be defined in defs.h */ 277130803Smarcel /* if (current_language->la_language != language_ada) return -1; */ 278130803Smarcel 279130803Smarcel result = get_entry_number (get_self_id ()); 280130803Smarcel 281130803Smarcel /* return -1 if not found */ 282130803Smarcel return result == 0 ? -1 : result; 283130803Smarcel} 284130803Smarcel 285130803Smarcel/* Print detailed information about specified task */ 286130803Smarcel 287130803Smarcelstatic void 288130803Smarcelinfo_task (char *arg, int from_tty) 289130803Smarcel{ 290130803Smarcel void *temp_task; 291130803Smarcel struct task_entry *pt, *pt2; 292130803Smarcel void *self_id, *caller; 293130803Smarcel struct task_fields atcb, atcb2; 294130803Smarcel struct entry_call call; 295130803Smarcel int bounds[2]; 296130803Smarcel char image[256]; 297130803Smarcel int num; 298130803Smarcel 299130803Smarcel /* FIXME: language_ada should be defined in defs.h */ 300130803Smarcel /* if (current_language->la_language != language_ada) 301130803Smarcel { 302130803Smarcel printf_filtered ("The current language does not support tasks.\n"); 303130803Smarcel return; 304130803Smarcel } 305130803Smarcel */ 306130803Smarcel pt = get_entry_vptr (atoi (arg)); 307130803Smarcel if (pt == NULL) 308130803Smarcel { 309130803Smarcel printf_filtered ("Task %s not found.\n", arg); 310130803Smarcel return; 311130803Smarcel } 312130803Smarcel 313130803Smarcel temp_task = pt->task_id; 314130803Smarcel 315130803Smarcel /* read the atcb in the inferior */ 316130803Smarcel READ_MEMORY ((CORE_ADDR) temp_task, atcb); 317130803Smarcel 318130803Smarcel /* print the Ada task id */ 319130803Smarcel printf_filtered ("Ada Task: %p\n", temp_task); 320130803Smarcel 321130803Smarcel /* print the name of the task */ 322130803Smarcel if (atcb.image.P_ARRAY != NULL) 323130803Smarcel { 324130803Smarcel READ_MEMORY ((CORE_ADDR) EXTRACT_ADDRESS (atcb.image.P_BOUNDS), bounds); 325130803Smarcel bounds[1] = EXTRACT_INT (bounds[1]); 326130803Smarcel read_memory ((CORE_ADDR) EXTRACT_ADDRESS (atcb.image.P_ARRAY), 327130803Smarcel (char *) &image, bounds[1]); 328130803Smarcel printf_filtered ("Name: %.*s\n", bounds[1], image); 329130803Smarcel } 330130803Smarcel else 331130803Smarcel printf_filtered ("<no name>\n"); 332130803Smarcel 333130803Smarcel /* print the thread id */ 334130803Smarcel 335130803Smarcel if ((long) pt->thread < 65536) 336130803Smarcel printf_filtered ("Thread: %ld\n", (long int) pt->thread); 337130803Smarcel else 338130803Smarcel printf_filtered ("Thread: %p\n", pt->thread); 339130803Smarcel 340130803Smarcel if ((long) pt->lwp != 0) 341130803Smarcel { 342130803Smarcel if ((long) pt->lwp < 65536) 343130803Smarcel printf_filtered ("LWP: %ld\n", (long int) pt->lwp); 344130803Smarcel else 345130803Smarcel printf_filtered ("LWP: %p\n", pt->lwp); 346130803Smarcel } 347130803Smarcel 348130803Smarcel /* print the parent gdb task id */ 349130803Smarcel num = get_entry_number (EXTRACT_ADDRESS (atcb.parent)); 350130803Smarcel if (num != 0) 351130803Smarcel { 352130803Smarcel printf_filtered ("Parent: %d", num); 353130803Smarcel pt2 = get_entry_vptr (num); 354130803Smarcel READ_MEMORY ((CORE_ADDR) pt2->task_id, atcb2); 355130803Smarcel 356130803Smarcel /* print the name of the task */ 357130803Smarcel if (atcb2.image.P_ARRAY != NULL) 358130803Smarcel { 359130803Smarcel READ_MEMORY ((CORE_ADDR) EXTRACT_ADDRESS (atcb2.image.P_BOUNDS), 360130803Smarcel bounds); 361130803Smarcel bounds[1] = EXTRACT_INT (bounds[1]); 362130803Smarcel read_memory ((CORE_ADDR) EXTRACT_ADDRESS (atcb2.image.P_ARRAY), 363130803Smarcel (char *) &image, bounds[1]); 364130803Smarcel printf_filtered (" (%.*s)\n", bounds[1], image); 365130803Smarcel } 366130803Smarcel else 367130803Smarcel printf_filtered ("\n"); 368130803Smarcel } 369130803Smarcel else 370130803Smarcel printf_filtered ("No parent\n"); 371130803Smarcel 372130803Smarcel /* print the base priority of the task */ 373130803Smarcel printf_filtered ("Base Priority: %d\n", EXTRACT_INT (atcb.priority)); 374130803Smarcel 375130803Smarcel /* print the current state of the task */ 376130803Smarcel 377130803Smarcel /* check if this task is accepting a rendezvous */ 378130803Smarcel if (atcb.call == NULL) 379130803Smarcel caller = NULL; 380130803Smarcel else 381130803Smarcel { 382130803Smarcel READ_MEMORY ((CORE_ADDR) EXTRACT_ADDRESS (atcb.call), call); 383130803Smarcel caller = EXTRACT_ADDRESS (call.self); 384130803Smarcel } 385130803Smarcel 386130803Smarcel if (caller != NULL) 387130803Smarcel { 388130803Smarcel num = get_entry_number (caller); 389130803Smarcel printf_filtered ("Accepting rendezvous with %d", num); 390130803Smarcel 391130803Smarcel if (num != 0) 392130803Smarcel { 393130803Smarcel pt2 = get_entry_vptr (num); 394130803Smarcel READ_MEMORY ((CORE_ADDR) pt2->task_id, atcb2); 395130803Smarcel 396130803Smarcel /* print the name of the task */ 397130803Smarcel if (atcb2.image.P_ARRAY != NULL) 398130803Smarcel { 399130803Smarcel READ_MEMORY ((CORE_ADDR) EXTRACT_ADDRESS (atcb2.image.P_BOUNDS), 400130803Smarcel bounds); 401130803Smarcel bounds[1] = EXTRACT_INT (bounds[1]); 402130803Smarcel read_memory ((CORE_ADDR) EXTRACT_ADDRESS (atcb2.image.P_ARRAY), 403130803Smarcel (char *) &image, bounds[1]); 404130803Smarcel printf_filtered (" (%.*s)\n", bounds[1], image); 405130803Smarcel } 406130803Smarcel else 407130803Smarcel printf_filtered ("\n"); 408130803Smarcel } 409130803Smarcel else 410130803Smarcel printf_filtered ("\n"); 411130803Smarcel } 412130803Smarcel else 413130803Smarcel printf_filtered ("State: %s\n", ada_long_task_states[atcb.state]); 414130803Smarcel} 415130803Smarcel 416130803Smarcel#if 0 417130803Smarcel 418130803Smarcel/* A useful function that shows the alignment of all the fields in the 419130803Smarcel tasks_fields structure 420130803Smarcel */ 421130803Smarcel 422130803Smarcelprint_align (void) 423130803Smarcel{ 424130803Smarcel struct task_fields tf; 425130803Smarcel void *tf_base = &(tf); 426130803Smarcel void *tf_state = &(tf.state); 427130803Smarcel void *tf_entry_num = &(tf.entry_num); 428130803Smarcel void *tf_parent = &(tf.parent); 429130803Smarcel void *tf_priority = &(tf.priority); 430130803Smarcel void *tf_current_priority = &(tf.current_priority); 431130803Smarcel void *tf_image = &(tf.image); 432130803Smarcel void *tf_call = &(tf.call); 433130803Smarcel void *tf_thread = &(tf.thread); 434130803Smarcel void *tf_lwp = &(tf.lwp); 435130803Smarcel printf_filtered ("\n"); 436130803Smarcel printf_filtered ("(tf_base = 0x%x)\n", tf_base); 437130803Smarcel printf_filtered ("task_fields.entry_num at %3d (0x%x)\n", 438130803Smarcel tf_entry_num - tf_base, tf_entry_num); 439130803Smarcel printf_filtered ("task_fields.state at %3d (0x%x)\n", 440130803Smarcel tf_state - tf_base, tf_state); 441130803Smarcel printf_filtered ("task_fields.parent at %3d (0x%x)\n", 442130803Smarcel tf_parent - tf_base, tf_parent); 443130803Smarcel printf_filtered ("task_fields.priority at %3d (0x%x)\n", 444130803Smarcel tf_priority - tf_base, tf_priority); 445130803Smarcel printf_filtered ("task_fields.current_priority at %3d (0x%x)\n", 446130803Smarcel tf_current_priority - tf_base, tf_current_priority); 447130803Smarcel printf_filtered ("task_fields.image at %3d (0x%x)\n", 448130803Smarcel tf_image - tf_base, tf_image); 449130803Smarcel printf_filtered ("task_fields.call at %3d (0x%x)\n", 450130803Smarcel tf_call - tf_base, tf_call); 451130803Smarcel printf_filtered ("task_fields.thread at %3d (0x%x)\n", 452130803Smarcel tf_thread - tf_base, tf_thread); 453130803Smarcel printf_filtered ("task_fields.lwp at %3d (0x%x)\n", 454130803Smarcel tf_lwp - tf_base, tf_lwp); 455130803Smarcel printf_filtered ("\n"); 456130803Smarcel} 457130803Smarcel#endif 458130803Smarcel 459130803Smarcel/* Print information about currently known tasks */ 460130803Smarcel 461130803Smarcelstatic void 462130803Smarcelinfo_tasks (char *arg, int from_tty) 463130803Smarcel{ 464130803Smarcel struct value *val; 465130803Smarcel int i, task_number, state; 466130803Smarcel void *temp_task, *temp_tasks[MAX_NUMBER_OF_KNOWN_TASKS]; 467130803Smarcel struct task_entry *pt; 468130803Smarcel void *self_id, *caller, *thread_id = NULL; 469130803Smarcel struct task_fields atcb; 470130803Smarcel struct entry_call call; 471130803Smarcel int bounds[2]; 472130803Smarcel char image[256]; 473130803Smarcel int size; 474130803Smarcel char car; 475130803Smarcel 476130803Smarcel#if defined(__alpha__) && defined(__osf__) && !defined(VXWORKS_TARGET) 477130803Smarcel pthreadTeb_t thr; 478130803Smarcel gdb_gregset_t regs; 479130803Smarcel#endif 480130803Smarcel 481130803Smarcel static struct symbol *sym; 482130803Smarcel static struct minimal_symbol *msym; 483130803Smarcel static void *known_tasks_addr = NULL; 484130803Smarcel 485130803Smarcel int init_only = gdbtk_task_initialization; 486130803Smarcel gdbtk_task_initialization = 0; 487130803Smarcel 488130803Smarcel task_number = 0; 489130803Smarcel 490130803Smarcel if (PIDGET (inferior_ptid) == 0) 491130803Smarcel { 492130803Smarcel printf_filtered ("The program is not being run under gdb. "); 493130803Smarcel printf_filtered ("Use 'run' or 'attach' first.\n"); 494130803Smarcel return; 495130803Smarcel } 496130803Smarcel 497130803Smarcel if (ada__tasks_check_symbol_table) 498130803Smarcel { 499130803Smarcel thread_support = 0; 500130803Smarcel#if (defined(__alpha__) && defined(__osf__) & !defined(VXWORKS_TARGET)) || \ 501130803Smarcel defined (_AIX) 502130803Smarcel thread_support = 1; 503130803Smarcel#endif 504130803Smarcel 505130803Smarcel msym = lookup_minimal_symbol (KNOWN_TASKS_NAME, NULL, NULL); 506130803Smarcel if (msym != NULL) 507130803Smarcel known_tasks_addr = (void *) SYMBOL_VALUE_ADDRESS (msym); 508130803Smarcel else 509130803Smarcel#ifndef VXWORKS_TARGET 510130803Smarcel return; 511130803Smarcel#else 512130803Smarcel { 513130803Smarcel if (target_lookup_symbol (KNOWN_TASKS_NAME, &known_tasks_addr) != 0) 514130803Smarcel return; 515130803Smarcel } 516130803Smarcel#endif 517130803Smarcel 518130803Smarcel ada__tasks_check_symbol_table = 0; 519130803Smarcel } 520130803Smarcel 521130803Smarcel if (known_tasks_addr == NULL) 522130803Smarcel return; 523130803Smarcel 524130803Smarcel#if !((defined(sun) && defined(__SVR4)) || defined(VXWORKS_TARGET) || defined(__WIN32__) || defined (hpux)) 525130803Smarcel if (thread_support) 526130803Smarcel#endif 527130803Smarcel thread_id = GET_CURRENT_THREAD (); 528130803Smarcel 529130803Smarcel /* then we get a list of tasks created */ 530130803Smarcel 531130803Smarcel init_task_list (); 532130803Smarcel 533130803Smarcel READ_MEMORY ((CORE_ADDR) known_tasks_addr, temp_tasks); 534130803Smarcel 535130803Smarcel for (i = 0; i < MAX_NUMBER_OF_KNOWN_TASKS; i++) 536130803Smarcel { 537130803Smarcel temp_task = EXTRACT_ADDRESS (temp_tasks[i]); 538130803Smarcel 539130803Smarcel if (temp_task != NULL) 540130803Smarcel { 541130803Smarcel task_number = get_entry_number (temp_task); 542130803Smarcel if (task_number == 0) 543130803Smarcel task_number = add_task_entry (temp_task, i); 544130803Smarcel } 545130803Smarcel } 546130803Smarcel 547130803Smarcel /* Return without printing anything if this function was called in 548130803Smarcel order to init GDBTK tasking. */ 549130803Smarcel 550130803Smarcel if (init_only) 551130803Smarcel return; 552130803Smarcel 553130803Smarcel /* print the header */ 554130803Smarcel 555130803Smarcel#if defined(__alpha__) && defined(__osf__) && !defined(VXWORKS_TARGET) 556130803Smarcel printf_filtered 557130803Smarcel (" ID TID P-ID Pri Stack %% State Name\n"); 558130803Smarcel#else 559130803Smarcel printf_filtered (" ID TID P-ID Pri State Name\n"); 560130803Smarcel#endif 561130803Smarcel 562130803Smarcel /* Now that we have a list of task id's, we can print them */ 563130803Smarcel pt = task_list; 564130803Smarcel while (pt) 565130803Smarcel { 566130803Smarcel temp_task = pt->task_id; 567130803Smarcel 568130803Smarcel /* read the atcb in the inferior */ 569130803Smarcel READ_MEMORY ((CORE_ADDR) temp_task, atcb); 570130803Smarcel 571130803Smarcel /* store the thread id for future use */ 572130803Smarcel pt->thread = EXTRACT_ADDRESS (atcb.thread); 573130803Smarcel 574130803Smarcel#if defined (linux) 575130803Smarcel pt->lwp = (void *) THREAD_TO_PID (atcb.thread, 0); 576130803Smarcel#else 577130803Smarcel pt->lwp = EXTRACT_ADDRESS (atcb.lwp); 578130803Smarcel#endif 579130803Smarcel 580130803Smarcel /* print a star if this task is the current one */ 581130803Smarcel if (thread_id) 582130803Smarcel#if defined (__WIN32__) || defined (SGI) || defined (hpux) 583130803Smarcel printf_filtered (pt->lwp == thread_id ? "*" : " "); 584130803Smarcel#else 585130803Smarcel printf_filtered (pt->thread == thread_id ? "*" : " "); 586130803Smarcel#endif 587130803Smarcel 588130803Smarcel /* print the gdb task id */ 589130803Smarcel printf_filtered ("%3d", pt->task_num); 590130803Smarcel 591130803Smarcel /* print the Ada task id */ 592130803Smarcel#ifndef VXWORKS_TARGET 593130803Smarcel printf_filtered (" %9lx", (long) temp_task); 594130803Smarcel#else 595130803Smarcel#ifdef TARGET_64 596130803Smarcel printf_filtered (" %#9lx", (unsigned long) pt->thread & 0x3ffffffffff); 597130803Smarcel#else 598130803Smarcel printf_filtered (" %#9lx", (long) pt->thread); 599130803Smarcel#endif 600130803Smarcel#endif 601130803Smarcel 602130803Smarcel /* print the parent gdb task id */ 603130803Smarcel printf_filtered 604130803Smarcel (" %4d", get_entry_number (EXTRACT_ADDRESS (atcb.parent))); 605130803Smarcel 606130803Smarcel /* print the base priority of the task */ 607130803Smarcel printf_filtered (" %3d", EXTRACT_INT (atcb.priority)); 608130803Smarcel 609130803Smarcel#if defined(__alpha__) && defined(__osf__) && !defined(VXWORKS_TARGET) 610130803Smarcel if (pt->task_num == 1 || atcb.state == Terminated) 611130803Smarcel { 612130803Smarcel printf_filtered (" Unknown"); 613130803Smarcel goto next; 614130803Smarcel } 615130803Smarcel 616130803Smarcel read_memory ((CORE_ADDR) atcb.thread, &thr, sizeof (thr)); 617130803Smarcel current_thread = atcb.thread; 618130803Smarcel regs.regs[SP_REGNUM] = 0; 619130803Smarcel if (dec_thread_get_registers (®s, NULL) == 0) 620130803Smarcel { 621130803Smarcel pt->stack_per = (100 * ((long) thr.__stack_base - 622130803Smarcel regs.regs[SP_REGNUM])) / thr.__stack_size; 623130803Smarcel /* if the thread is terminated but still there, the 624130803Smarcel stack_base/size values are erroneous. Try to patch it */ 625130803Smarcel if (pt->stack_per < 0 || pt->stack_per > 100) 626130803Smarcel pt->stack_per = 0; 627130803Smarcel } 628130803Smarcel 629130803Smarcel /* print information about stack space used in the thread */ 630130803Smarcel if (thr.__stack_size < 1024 * 1024) 631130803Smarcel { 632130803Smarcel size = thr.__stack_size / 1024; 633130803Smarcel car = 'K'; 634130803Smarcel } 635130803Smarcel else if (thr.__stack_size < 1024 * 1024 * 1024) 636130803Smarcel { 637130803Smarcel size = thr.__stack_size / 1024 / 1024; 638130803Smarcel car = 'M'; 639130803Smarcel } 640130803Smarcel else /* Who knows... */ 641130803Smarcel { 642130803Smarcel size = thr.__stack_size / 1024 / 1024 / 1024; 643130803Smarcel car = 'G'; 644130803Smarcel } 645130803Smarcel printf_filtered (" %4d%c %2d", size, car, pt->stack_per); 646130803Smarcel next: 647130803Smarcel#endif 648130803Smarcel 649130803Smarcel /* print the current state of the task */ 650130803Smarcel 651130803Smarcel /* check if this task is accepting a rendezvous */ 652130803Smarcel if (atcb.call == NULL) 653130803Smarcel caller = NULL; 654130803Smarcel else 655130803Smarcel { 656130803Smarcel READ_MEMORY ((CORE_ADDR) EXTRACT_ADDRESS (atcb.call), call); 657130803Smarcel caller = EXTRACT_ADDRESS (call.self); 658130803Smarcel } 659130803Smarcel 660130803Smarcel if (caller != NULL) 661130803Smarcel printf_filtered (" Accepting RV with %-4d", 662130803Smarcel get_entry_number (caller)); 663130803Smarcel else 664130803Smarcel { 665130803Smarcel state = atcb.state; 666130803Smarcel#if defined (__WIN32__) || defined (SGI) || defined (hpux) 667130803Smarcel if (state == Runnable && (thread_id && pt->lwp == thread_id)) 668130803Smarcel#else 669130803Smarcel if (state == Runnable && (thread_id && pt->thread == thread_id)) 670130803Smarcel#endif 671130803Smarcel /* Replace "Runnable" by "Running" if this is the current task */ 672130803Smarcel printf_filtered (" %-22s", "Running"); 673130803Smarcel else 674130803Smarcel printf_filtered (" %-22s", ada_task_states[state]); 675130803Smarcel } 676130803Smarcel 677130803Smarcel /* finally, print the name of the task */ 678130803Smarcel if (atcb.image.P_ARRAY != NULL) 679130803Smarcel { 680130803Smarcel READ_MEMORY ((CORE_ADDR) EXTRACT_ADDRESS (atcb.image.P_BOUNDS), 681130803Smarcel bounds); 682130803Smarcel bounds[1] = EXTRACT_INT (bounds[1]); 683130803Smarcel read_memory ((CORE_ADDR) EXTRACT_ADDRESS (atcb.image.P_ARRAY), 684130803Smarcel (char *) &image, bounds[1]); 685130803Smarcel printf_filtered (" %.*s\n", bounds[1], image); 686130803Smarcel } 687130803Smarcel else 688130803Smarcel printf_filtered (" <no name>\n"); 689130803Smarcel 690130803Smarcel pt = pt->next_task; 691130803Smarcel } 692130803Smarcel} 693130803Smarcel 694130803Smarcel/* Task list initialization for GDB-Tk. We basically use info_tasks() 695130803Smarcel to initialize our variables, but abort that function before we 696130803Smarcel actually print anything. */ 697130803Smarcel 698130803Smarcelint 699130803Smarcelgdbtk_tcl_tasks_initialize (void) 700130803Smarcel{ 701130803Smarcel gdbtk_task_initialization = 1; 702130803Smarcel info_tasks ("", gdb_stdout); 703130803Smarcel 704130803Smarcel return (task_list != NULL); 705130803Smarcel} 706130803Smarcel 707130803Smarcelstatic void 708130803Smarcelinfo_tasks_command (char *arg, int from_tty) 709130803Smarcel{ 710130803Smarcel if (arg == NULL || *arg == '\000') 711130803Smarcel info_tasks (arg, from_tty); 712130803Smarcel else 713130803Smarcel info_task (arg, from_tty); 714130803Smarcel} 715130803Smarcel 716130803Smarcel/* Switch from one thread to another. */ 717130803Smarcel 718130803Smarcelstatic void 719130803Smarcelswitch_to_thread (ptid_t ptid) 720130803Smarcel{ 721130803Smarcel if (ptid_equal (ptid, inferior_ptid)) 722130803Smarcel return; 723130803Smarcel 724130803Smarcel inferior_ptid = ptid; 725130803Smarcel flush_cached_frames (); 726130803Smarcel registers_changed (); 727130803Smarcel stop_pc = read_pc (); 728130803Smarcel select_frame (get_current_frame ()); 729130803Smarcel} 730130803Smarcel 731130803Smarcel/* Switch to a specified task. */ 732130803Smarcel 733130803Smarcelstatic int 734130803Smarceltask_switch (void *tid, void *lwpid) 735130803Smarcel{ 736130803Smarcel int res = 0, pid; 737130803Smarcel 738130803Smarcel if (thread_support) 739130803Smarcel { 740130803Smarcel flush_cached_frames (); 741130803Smarcel 742130803Smarcel if (current_task != current_task_id) 743130803Smarcel { 744130803Smarcel res = THREAD_FETCH_REGISTERS (); 745130803Smarcel } 746130803Smarcel else 747130803Smarcel { 748130803Smarcel#if (defined(__alpha__) && defined(__osf__) && !defined(VXWORKS_TARGET)) 749130803Smarcel supply_gregset (&gregset_saved); 750130803Smarcel supply_fpregset (&fpregset_saved); 751130803Smarcel#endif 752130803Smarcel } 753130803Smarcel 754130803Smarcel if (res == 0) 755130803Smarcel stop_pc = read_pc (); 756130803Smarcel select_frame (get_current_frame ()); 757130803Smarcel return res; 758130803Smarcel } 759130803Smarcel 760130803Smarcel return -1; 761130803Smarcel} 762130803Smarcel 763130803Smarcelstatic void 764130803Smarceltask_command (char *tidstr, int from_tty) 765130803Smarcel{ 766130803Smarcel int num; 767130803Smarcel struct task_entry *e; 768130803Smarcel 769130803Smarcel if (!tidstr) 770130803Smarcel error ("Please specify a task ID. Use the \"info tasks\" command to\n" 771130803Smarcel "see the IDs of currently known tasks."); 772130803Smarcel 773130803Smarcel num = atoi (tidstr); 774130803Smarcel e = get_entry_vptr (num); 775130803Smarcel 776130803Smarcel if (e == NULL) 777130803Smarcel error ("Task ID %d not known. Use the \"info tasks\" command to\n" 778130803Smarcel "see the IDs of currently known tasks.", num); 779130803Smarcel 780130803Smarcel if (current_task_id == -1) 781130803Smarcel { 782130803Smarcel#if (defined(__alpha__) && defined(__osf__) && !defined(VXWORKS_TARGET)) 783130803Smarcel fill_gregset (&gregset_saved, -1); 784130803Smarcel fill_fpregset (&fpregset_saved, -1); 785130803Smarcel#endif 786130803Smarcel current_task_id = get_current_task (); 787130803Smarcel } 788130803Smarcel 789130803Smarcel current_task = num; 790130803Smarcel current_task_index = e->known_tasks_index; 791130803Smarcel current_thread = e->thread; 792130803Smarcel current_lwp = e->lwp; 793130803Smarcel if (task_switch (e->thread, e->lwp) == 0) 794130803Smarcel { 795130803Smarcel /* FIXME: find_printable_frame should be defined in frame.h, and 796130803Smarcel implemented in ada-lang.c */ 797130803Smarcel /* find_printable_frame (deprecated_selected_frame, frame_relative_level (deprecated_selected_frame)); */ 798130803Smarcel printf_filtered ("[Switching to task %d]\n", num); 799130803Smarcel print_stack_frame (deprecated_selected_frame, 800130803Smarcel frame_relative_level (deprecated_selected_frame), 1); 801130803Smarcel } 802130803Smarcel else 803130803Smarcel printf_filtered ("Unable to switch to task %d\n", num); 804130803Smarcel} 805130803Smarcel 806130803Smarcelvoid 807130803Smarcel_initialize_tasks (void) 808130803Smarcel{ 809130803Smarcel static struct cmd_list_element *task_cmd_list = NULL; 810130803Smarcel extern struct cmd_list_element *cmdlist; 811130803Smarcel 812130803Smarcel add_info ("tasks", info_tasks_command, 813130803Smarcel "Without argument: list all known Ada tasks, with status information.\n" 814130803Smarcel "info tasks n: print detailed information of task n.\n"); 815130803Smarcel 816130803Smarcel add_prefix_cmd ("task", class_run, task_command, 817130803Smarcel "Use this command to switch between tasks.\n\ 818130803Smarcel The new task ID must be currently known.", &task_cmd_list, "task ", 1, &cmdlist); 819130803Smarcel} 820