Commit | Line | Data |
---|---|---|
4c4b4cd2 PH |
1 | /* File ada-tasks.c: Ada tasking control for GDB |
2 | Copyright 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004 | |
3 | Free Software Foundation, Inc. | |
4 | Contributed by Ada Core Technologies, Inc. | |
5 | ||
14f9c5c9 AS |
6 | This file is part of GDB. |
7 | ||
14f9c5c9 AS |
8 | Authors: Roch-Alexandre Nomine Beguin, Arnaud Charlet <charlet@gnat.com> |
9 | ||
10 | This program is free software; you can redistribute it and/or modify | |
11 | it under the terms of the GNU General Public License as published by | |
12 | the Free Software Foundation; either version 2 of the License, or | |
13 | (at your option) any later version. | |
14 | ||
15 | */ | |
16 | ||
d2e4a39e | 17 | #include <ctype.h> |
4c4b4cd2 | 18 | #include <gdb_string.h> |
d2e4a39e AS |
19 | #include "defs.h" |
20 | #include "command.h" | |
14f9c5c9 AS |
21 | #include "value.h" |
22 | #include "language.h" | |
23 | #include "inferior.h" | |
24 | #include "symtab.h" | |
25 | #include "target.h" | |
26 | #include "gdbcore.h" | |
4c4b4cd2 PH |
27 | #include "gdbthread.h" |
28 | #include "regcache.h" /* for registers_changed */ | |
14f9c5c9 | 29 | |
4c4b4cd2 PH |
30 | #if defined (__fsu__) || defined (HAVE_SPYTHREAD) \ |
31 | || (defined(__alpha__) && defined(__osf__) && !defined(__alpha_vxworks)) | |
14f9c5c9 AS |
32 | #include <sys/procfs.h> |
33 | #endif | |
34 | ||
4c4b4cd2 PH |
35 | #if defined (__fsu__) || defined (HAVE_SPYTHREAD) \ |
36 | || (defined(__alpha__) && defined(__osf__) && !defined(VXWORKS_TARGET)) | |
14f9c5c9 | 37 | #include "gregset.h" |
d2e4a39e | 38 | #endif |
14f9c5c9 | 39 | |
4c4b4cd2 PH |
40 | #ifdef I386_GNULINUX_TARGET |
41 | #include "gdb_thread_db.h" | |
42 | #endif | |
14f9c5c9 | 43 | |
4c4b4cd2 PH |
44 | #if defined (HAVE_SPYTHREAD) |
45 | #include "irix6-spyThread.h" | |
46 | #endif | |
14f9c5c9 | 47 | |
4c4b4cd2 PH |
48 | #include "ada-lang.h" |
49 | #include "observer.h" | |
14f9c5c9 | 50 | |
4c4b4cd2 PH |
51 | enum task_states |
52 | { | |
53 | Unactivated, | |
54 | Runnable, | |
55 | Terminated, | |
56 | Activator_Sleep, | |
57 | Acceptor_Sleep, | |
58 | Entry_Caller_Sleep, | |
59 | Async_Select_Sleep, | |
60 | Delay_Sleep, | |
61 | Master_Completion_Sleep, | |
62 | Master_Phase_2_Sleep | |
63 | }; | |
14f9c5c9 | 64 | |
4c4b4cd2 PH |
65 | struct task_control_block |
66 | { | |
67 | char state; | |
68 | CORE_ADDR parent; | |
69 | int priority; | |
70 | char image [32]; | |
71 | int image_len; /* This field is not always present in the ATCB. */ | |
72 | CORE_ADDR call; | |
73 | CORE_ADDR thread; | |
74 | CORE_ADDR lwp; /* This field is not always present in the ATCB. */ | |
75 | }; | |
14f9c5c9 | 76 | |
4c4b4cd2 PH |
77 | /* The index of certain important fields in the Ada Task Control Block |
78 | record and sub-records. */ | |
14f9c5c9 | 79 | |
4c4b4cd2 PH |
80 | struct tcb_fieldnos |
81 | { | |
82 | /* Fields in record Ada_Task_Control_Block. */ | |
83 | int common; | |
84 | ||
85 | /* Fields in record Common_ATCB. */ | |
86 | int state; | |
87 | int parent; | |
88 | int priority; | |
89 | int image; | |
90 | int image_len; /* This field may be missing. */ | |
91 | int call; | |
92 | int ll; | |
93 | ||
94 | /* Fields in Task_Primitives.Private_Data. */ | |
95 | int ll_thread; | |
96 | int ll_lwp; /* This field may be missing. */ | |
97 | }; | |
98 | ||
99 | #if defined (linux) | |
100 | #define TASK_LWP(atcb) 0L | |
14f9c5c9 | 101 | #else |
4c4b4cd2 | 102 | #define TASK_LWP(atcb) extract_unsigned_integer (&(atcb).lwp, sizeof ((atcb).lwp)) |
14f9c5c9 AS |
103 | #endif |
104 | ||
4c4b4cd2 PH |
105 | struct task_ptid |
106 | { | |
107 | int pid; /* The Process id */ | |
108 | long lwp; /* The Light Weight Process id */ | |
109 | long tid; /* The Thread id */ | |
110 | }; | |
111 | typedef struct task_ptid task_ptid_t; | |
112 | ||
113 | struct task_entry | |
114 | { | |
115 | CORE_ADDR task_id; | |
116 | struct task_control_block atcb; | |
117 | int task_num; | |
118 | int known_tasks_index; | |
119 | struct task_entry *next_task; | |
120 | task_ptid_t task_ptid; | |
121 | int stack_per; | |
122 | }; | |
123 | ||
124 | /* FIXME: move all this conditional compilation in description | |
125 | files or in configure.in */ | |
126 | ||
14f9c5c9 | 127 | #if defined(__alpha__) && defined(__osf__) && !defined(VXWORKS_TARGET) |
4c4b4cd2 PH |
128 | #define SPECIAL_THREAD_SUPPORT_ACTIVE() thread_support |
129 | #define SAVE_TASK_REGISTERS(task) \ | |
130 | do { fill_gregset (&gregset_saved, -1); \ | |
131 | fill_fpregset (&fpregset_saved, -1); \ | |
132 | } while (0) | |
133 | #define RESTORE_TASK_REGISTERS(task) \ | |
134 | do { supply_gregset (&gregset_saved); \ | |
135 | supply_fpregset (&fpregset_saved); \ | |
136 | } while (0) | |
137 | ||
14f9c5c9 | 138 | #define THREAD_FETCH_REGISTERS dec_thread_fetch_registers |
4c4b4cd2 PH |
139 | #define GET_CURRENT_THREAD(PTID) dec_thread_get_current_thread () |
140 | extern unsigned long dec_thread_get_current_thread (void); | |
14f9c5c9 | 141 | extern int dec_thread_get_registers (gdb_gregset_t *, gdb_fpregset_t *); |
4c4b4cd2 | 142 | extern int dec_thread_fetch_registers (void); |
14f9c5c9 AS |
143 | #endif |
144 | ||
4c4b4cd2 PH |
145 | #ifdef __fsu__ |
146 | #define SPECIAL_THREAD_SUPPORT_ACTIVE() \ | |
147 | (thread_support && pthread_kern_addr != 0) | |
148 | #define SAVE_TASK_REGISTERS(task) \ | |
149 | do { \ | |
150 | if (pthread_kern_addr != 0) \ | |
151 | { \ | |
152 | fill_gregset (&gregset_saved, -1); \ | |
153 | fill_fpregset (&fpregset_saved, -1); \ | |
154 | } \ | |
155 | } while (0) | |
156 | #define RESTORE_TASK_REGISTERS(task) \ | |
157 | do { \ | |
158 | if (pthread_kern_addr != 0) \ | |
159 | { \ | |
160 | supply_gregset (&gregset_saved); \ | |
161 | supply_fpregset (&fpregset_saved); \ | |
162 | } \ | |
163 | } while (0) | |
164 | ||
165 | extern int fsu_thread_fetch_registers (void); | |
166 | extern unsigned long fsu_thread_get_current_thread (void); | |
167 | static int fsu_or_linux_thread_fetch_registers (void); | |
168 | static long fsu_or_linux_thread_get_current_thread (ptid_t); | |
169 | #define THREAD_FETCH_REGISTERS fsu_or_linux_thread_fetch_registers | |
170 | #define GET_CURRENT_THREAD(PTID) fsu_or_linux_thread_get_current_thread (PTID) | |
171 | #define PTHREAD_KERN "pthread_kern" | |
172 | #endif | |
173 | ||
174 | #ifdef I386_GNULINUX_TARGET | |
175 | extern td_thrinfo_t thread_db_pid_to_thread_info (int pid); | |
176 | extern int thread_db_tid_to_pid (void *tid); | |
14f9c5c9 AS |
177 | #endif |
178 | ||
179 | #if defined(VXWORKS_TARGET) | |
4c4b4cd2 | 180 | #define GET_CURRENT_THREAD(PTID) (unsigned long) ptid_get_pid (PTID) |
14f9c5c9 AS |
181 | #define THREAD_FETCH_REGISTERS() (-1) |
182 | ||
4c4b4cd2 PH |
183 | #elif defined (__WIN32__) || defined (__CYGWIN__) || defined (hpux) |
184 | #define GET_CURRENT_THREAD(PTID) ptid_get_pid (PTID) | |
14f9c5c9 | 185 | #define THREAD_FETCH_REGISTERS() (-1) |
4c4b4cd2 | 186 | #endif |
14f9c5c9 | 187 | |
4c4b4cd2 PH |
188 | #if defined (HAVE_SPYTHREAD) |
189 | #define GET_CURRENT_THREAD(PTID) (unsigned long) TIDGET (PTID) | |
190 | #endif | |
14f9c5c9 | 191 | |
4c4b4cd2 PH |
192 | #if !defined(GET_CURRENT_THREAD) |
193 | #define GET_CURRENT_THREAD(PTID) (unsigned long) ptid_get_tid (PTID) | |
194 | #endif | |
14f9c5c9 | 195 | |
4c4b4cd2 PH |
196 | #if !defined(THREAD_FETCH_REGISTERS) |
197 | #define THREAD_FETCH_REGISTERS() (target_fetch_registers (-1), 0) | |
198 | #endif | |
199 | ||
200 | #if !defined(SAVE_TASK_REGISTERS) | |
201 | #define SAVE_TASK_REGISTERS(task) | |
202 | #define RESTORE_TASK_REGISTERS(task) | |
203 | #endif | |
204 | ||
205 | #if !defined(SPECIAL_THREAD_SUPPORT_ACTIVE) | |
206 | #define SPECIAL_THREAD_SUPPORT_ACTIVE() 0 | |
14f9c5c9 AS |
207 | #endif |
208 | ||
209 | #define KNOWN_TASKS_NAME "system__tasking__debug__known_tasks" | |
210 | ||
4c4b4cd2 PH |
211 | #define READ_MEMORY(addr, var) read_memory (addr, (char *) &var, sizeof (var)) |
212 | ||
213 | /* If defined to 1, means that the thread ptids maintained by core GDB | |
214 | follow this format : first field (pid) contains the tid | |
215 | second field (lwp) contains 0 | |
216 | third field (tid) contains 0 */ | |
217 | #ifndef THREAD_PTID_CONTAINS_TID_NULL_NULL | |
218 | #define THREAD_PTID_CONTAINS_TID_NULL_NULL (0) | |
219 | #endif | |
220 | ||
221 | /* If defined to 1, means that the thread ptids maintained by core GDB | |
222 | follow this format: first field (pid) contains the LWP id | |
223 | second field (lwp) contains 0 | |
224 | third field (tid) contains 0 */ | |
225 | #ifndef THREAD_PTID_CONTAINS_LWP_NULL_NULL | |
226 | #define THREAD_PTID_CONTAINS_LWP_NULL_NULL (0) | |
227 | #endif | |
228 | ||
229 | /* If defined to 1, means that the thread ptids maintained by core GDB | |
230 | follow this format: first field (pid) contains the PID | |
231 | second field (lwp) contains 0 | |
232 | third field (tid) contains the TID */ | |
233 | #ifndef THREAD_PTID_CONTAINS_PID_NULL_TID | |
234 | #define THREAD_PTID_CONTAINS_PID_NULL_TID (0) | |
235 | #endif | |
236 | ||
237 | /* If defined to 1, means that the thread ptids maintained by core GDB | |
238 | follow this format: first field (pid) contains the PID | |
239 | second field (lwp) contains the TID | |
240 | third field (tid) contains the 0 */ | |
241 | ||
242 | #ifndef THREAD_PTID_CONTAINS_PID_TID_NULL | |
243 | #define THREAD_PTID_CONTAINS_PID_TID_NULL (0) | |
244 | #endif | |
245 | ||
246 | /* If defined to 1, means that the thread id is not stored in the tid | |
247 | field of the task_ptid, but rather in the lwp field. */ | |
248 | #ifndef ADA_THREAD_ID_IN_LWP | |
249 | #define ADA_THREAD_ID_IN_LWP (0) | |
250 | #endif | |
251 | ||
252 | static int task_ptid_get_pid (task_ptid_t task_ptid); | |
253 | static long task_ptid_get_lwp (task_ptid_t task_ptid); | |
254 | static long task_ptid_get_tid (task_ptid_t task_ptid); | |
255 | static task_ptid_t task_ptid_build (int pid, long lwp, long tid); | |
256 | static ptid_t task_ptid_get_ptid (task_ptid_t task_ptid); | |
257 | static long task_ptid_get_thread_id (task_ptid_t task_ptid); | |
258 | ||
259 | static int task_is_alive (enum task_states state); | |
260 | static CORE_ADDR get_self_id (ptid_t); | |
261 | static int get_entry_number (CORE_ADDR); | |
262 | static void get_tcb_types_info (struct type **atcb_type, | |
263 | struct type **atcb_common_type, | |
264 | struct type **atcb_ll_type, | |
265 | struct tcb_fieldnos *atcb_fieldnos); | |
266 | static void get_tcb_call_type_info (struct type **atcb_call_type, | |
267 | int *atcb_call_self_fieldno); | |
268 | static CORE_ADDR get_known_tasks_addr (void); | |
269 | static int read_known_tasks_array (void); | |
270 | static int build_task_list (void); | |
271 | static void value_as_string (char *dest, struct value *val, int length); | |
272 | static struct task_control_block read_atcb (CORE_ADDR atcb_addr); | |
273 | static CORE_ADDR read_caller (const CORE_ADDR call); | |
274 | static void display_current_task_id (void); | |
275 | static void task_command_1 (char *tidstr, int from_tty); | |
276 | ||
277 | /* Ada-tasks observers. */ | |
278 | ||
279 | static void normal_stop_notification (void); | |
280 | static void ada_tasks_attach_observers (void); | |
14f9c5c9 | 281 | |
14f9c5c9 AS |
282 | /* Global visible variables */ |
283 | ||
14f9c5c9 | 284 | int ada__tasks_check_symbol_table = 1; |
4c4b4cd2 PH |
285 | CORE_ADDR pthread_kern_addr = 0; |
286 | ||
287 | /* Local global variables. */ | |
288 | static struct task_entry *task_list = NULL; | |
14f9c5c9 | 289 | |
4c4b4cd2 PH |
290 | /* When non-zero, this flag indicates that the current task_list |
291 | is obsolete, and should be recomputed before it is accessed. */ | |
292 | static int stale_task_list_p = 1; | |
293 | ||
294 | #if defined (__fsu__) || (defined(__alpha__) && defined(__osf__) && !defined(VXWORKS_TARGET)) | |
14f9c5c9 AS |
295 | gdb_gregset_t gregset_saved; |
296 | gdb_fpregset_t fpregset_saved; | |
297 | #endif | |
298 | ||
299 | /* The maximum number of tasks known to the Ada runtime */ | |
4c4b4cd2 PH |
300 | static const int MAX_NUMBER_OF_KNOWN_TASKS = 1000; |
301 | ||
302 | /* the current task, as seen by the user. Modified everytime the user | |
303 | does a task switch. */ | |
304 | static int current_task = -1; | |
14f9c5c9 | 305 | |
4c4b4cd2 | 306 | unsigned long current_thread; |
14f9c5c9 | 307 | |
4c4b4cd2 PH |
308 | /* The task where the debugger stopped, giving control back to the user. |
309 | Not affected by task switching. Used to restore the registers before | |
310 | continuing the inferior. */ | |
311 | int current_task_id = -1; | |
312 | ||
313 | static char *task_states[] = { | |
14f9c5c9 AS |
314 | "Unactivated", |
315 | "Runnable", | |
316 | "Terminated", | |
317 | "Child Activation Wait", | |
318 | "Accept Statement", | |
319 | "Waiting on entry call", | |
320 | "Async Select Wait", | |
321 | "Delay Sleep", | |
322 | "Child Termination Wait", | |
323 | "Wait Child in Term Alt", | |
324 | "", | |
325 | "", | |
326 | "", | |
327 | "", | |
328 | "Asynchronous Hold" | |
329 | }; | |
330 | ||
331 | /* Global internal types */ | |
332 | ||
4c4b4cd2 | 333 | static char *long_task_states[] = { |
14f9c5c9 AS |
334 | "Unactivated", |
335 | "Runnable", | |
336 | "Terminated", | |
337 | "Waiting for child activation", | |
338 | "Blocked in accept statement", | |
339 | "Waiting on entry call", | |
340 | "Asynchronous Selective Wait", | |
341 | "Delay Sleep", | |
342 | "Waiting for children termination", | |
343 | "Waiting for children in terminate alternative", | |
344 | "", | |
345 | "", | |
346 | "", | |
347 | "", | |
348 | "Asynchronous Hold" | |
349 | }; | |
350 | ||
351 | /* Global internal variables */ | |
352 | ||
353 | static int highest_task_num = 0; | |
4c4b4cd2 PH |
354 | static int thread_support = 0; /* 1 if the thread library in use is |
355 | supported. FIXME: Not reinitialized | |
356 | properly when program reloaded. | |
357 | */ | |
358 | #ifdef __fsu__ | |
359 | static int | |
360 | fsu_or_linux_thread_fetch_registers (void) | |
361 | { | |
362 | if (pthread_kern_addr != 0) | |
363 | return fsu_thread_fetch_registers (); | |
364 | ||
365 | target_fetch_registers (-1); | |
366 | return 0L; | |
367 | } | |
368 | ||
369 | static long | |
370 | fsu_or_linux_thread_get_current_thread (ptid_t ptid) | |
371 | { | |
372 | if (pthread_kern_addr != 0) | |
373 | return fsu_thread_get_current_thread (); | |
374 | ||
375 | return ptid_get_tid (ptid); | |
376 | } | |
377 | ||
378 | #endif /* __fsu__ */ | |
14f9c5c9 | 379 | |
d2e4a39e | 380 | static int |
4c4b4cd2 | 381 | add_task_entry (CORE_ADDR p_task_id, int index) |
14f9c5c9 AS |
382 | { |
383 | struct task_entry *new_task_entry = NULL; | |
384 | struct task_entry *pt; | |
385 | ||
386 | highest_task_num++; | |
aacb1f0a | 387 | new_task_entry = xmalloc (sizeof (struct task_entry)); |
14f9c5c9 AS |
388 | new_task_entry->task_num = highest_task_num; |
389 | new_task_entry->task_id = p_task_id; | |
4c4b4cd2 | 390 | new_task_entry->atcb = read_atcb (p_task_id); |
14f9c5c9 | 391 | new_task_entry->known_tasks_index = index; |
4c4b4cd2 PH |
392 | new_task_entry->task_ptid = |
393 | task_ptid_build (ptid_get_pid (inferior_ptid), /* ? */ | |
394 | TASK_LWP (new_task_entry->atcb), | |
395 | new_task_entry->atcb.thread); | |
14f9c5c9 AS |
396 | new_task_entry->next_task = NULL; |
397 | pt = task_list; | |
398 | if (pt) | |
399 | { | |
400 | while (pt->next_task) | |
4c4b4cd2 | 401 | pt = pt->next_task; |
14f9c5c9 AS |
402 | pt->next_task = new_task_entry; |
403 | pt->stack_per = 0; | |
404 | } | |
d2e4a39e AS |
405 | else |
406 | task_list = new_task_entry; | |
14f9c5c9 AS |
407 | return new_task_entry->task_num; |
408 | } | |
409 | ||
4c4b4cd2 PH |
410 | static int |
411 | get_entry_number (CORE_ADDR p_task_id) | |
14f9c5c9 AS |
412 | { |
413 | struct task_entry *pt; | |
414 | ||
415 | pt = task_list; | |
416 | while (pt != NULL) | |
417 | { | |
418 | if (pt->task_id == p_task_id) | |
4c4b4cd2 | 419 | return pt->task_num; |
14f9c5c9 AS |
420 | pt = pt->next_task; |
421 | } | |
422 | return 0; | |
423 | } | |
424 | ||
80ae6ee2 | 425 | static struct task_entry * |
4c4b4cd2 | 426 | get_thread_entry_vptr (long thread) |
14f9c5c9 AS |
427 | { |
428 | struct task_entry *pt; | |
429 | ||
430 | pt = task_list; | |
431 | while (pt != NULL) | |
432 | { | |
4c4b4cd2 PH |
433 | if (task_ptid_get_thread_id (pt->task_ptid) == thread) |
434 | return pt; | |
14f9c5c9 AS |
435 | pt = pt->next_task; |
436 | } | |
437 | return 0; | |
438 | } | |
439 | ||
80ae6ee2 AS |
440 | static struct task_entry * |
441 | get_entry_vptr (int p_task_num) | |
14f9c5c9 AS |
442 | { |
443 | struct task_entry *pt; | |
444 | ||
445 | pt = task_list; | |
446 | while (pt) | |
447 | { | |
448 | if (pt->task_num == p_task_num) | |
4c4b4cd2 | 449 | return pt; |
14f9c5c9 AS |
450 | pt = pt->next_task; |
451 | } | |
452 | return NULL; | |
453 | } | |
454 | ||
80ae6ee2 AS |
455 | void |
456 | init_task_list (void) | |
14f9c5c9 AS |
457 | { |
458 | struct task_entry *pt, *old_pt; | |
459 | ||
4c4b4cd2 PH |
460 | target_find_new_threads (); |
461 | ||
14f9c5c9 AS |
462 | pt = task_list; |
463 | while (pt) | |
464 | { | |
465 | old_pt = pt; | |
466 | pt = pt->next_task; | |
aacb1f0a | 467 | xfree (old_pt); |
14f9c5c9 AS |
468 | }; |
469 | task_list = NULL; | |
470 | highest_task_num = 0; | |
471 | } | |
472 | ||
80ae6ee2 AS |
473 | int |
474 | valid_task_id (int task) | |
14f9c5c9 AS |
475 | { |
476 | return get_entry_vptr (task) != NULL; | |
477 | } | |
478 | ||
4c4b4cd2 PH |
479 | /* Return the pid of a given task ptid. */ |
480 | ||
481 | static int | |
482 | task_ptid_get_pid (task_ptid_t task_ptid) | |
14f9c5c9 | 483 | { |
4c4b4cd2 PH |
484 | return task_ptid.pid; |
485 | } | |
486 | ||
487 | /* Return the lwp of a given task ptid. */ | |
488 | ||
489 | static long | |
490 | task_ptid_get_lwp (task_ptid_t task_ptid) | |
491 | { | |
492 | return task_ptid.lwp; | |
493 | } | |
494 | ||
495 | /* Return the tid of a given task ptid. */ | |
496 | ||
497 | static long | |
498 | task_ptid_get_tid (task_ptid_t task_ptid) | |
499 | { | |
500 | return task_ptid.tid; | |
501 | } | |
502 | ||
503 | /* Build a task ptid from the associated pid, lwp, and tid. */ | |
504 | ||
505 | static task_ptid_t | |
506 | task_ptid_build (int pid, long lwp, long tid) | |
507 | { | |
508 | task_ptid_t task_ptid; | |
509 | ||
510 | task_ptid.pid = pid; | |
511 | task_ptid.lwp = lwp; | |
512 | task_ptid.tid = tid; | |
513 | return task_ptid; | |
514 | } | |
515 | ||
516 | /* Translate a task ptid into a ptid (the ptid maintained by core GDB). | |
517 | ||
518 | On most platforms, they are equivalent, and this function can be | |
519 | regarded as the identity. However, there are other platforms where | |
520 | the task ptid and the ptid are not equivalent. For instance, the task | |
521 | LWP value is sometimes stored by GDB-core as a pid! This translation | |
522 | therefore becomes necessary before invoking the GDB thread services. */ | |
523 | ||
524 | static ptid_t | |
525 | task_ptid_get_ptid (task_ptid_t task_ptid) | |
526 | { | |
527 | ptid_t ptid; | |
528 | ||
529 | if (THREAD_PTID_CONTAINS_TID_NULL_NULL) | |
530 | ptid = ptid_build (task_ptid_get_tid (task_ptid), 0, 0); | |
531 | else if (THREAD_PTID_CONTAINS_LWP_NULL_NULL) | |
532 | ptid = ptid_build (task_ptid_get_lwp (task_ptid), 0, 0); | |
533 | else if (THREAD_PTID_CONTAINS_PID_NULL_TID) | |
534 | ptid = ptid_build (task_ptid_get_pid (task_ptid), | |
535 | 0, task_ptid_get_tid (task_ptid)); | |
536 | else if (THREAD_PTID_CONTAINS_PID_TID_NULL) | |
537 | ptid = ptid_build (task_ptid_get_pid (task_ptid), | |
538 | task_ptid_get_tid (task_ptid), 0); | |
539 | else | |
540 | ptid = ptid_build (task_ptid_get_pid (task_ptid), | |
541 | task_ptid_get_lwp (task_ptid), | |
542 | task_ptid_get_tid (task_ptid)); | |
543 | ||
544 | return ptid; | |
545 | } | |
546 | ||
547 | /* Extract and return the thread_id for the given TASK_PTID. */ | |
548 | ||
549 | static long | |
550 | task_ptid_get_thread_id (task_ptid_t task_ptid) | |
551 | { | |
552 | /* On most platforms, the thread_id is stored in task_ptid.tid. | |
553 | Unfortunately, some other platforms store it as the task_ptid.lwp... */ | |
554 | ||
555 | if (ADA_THREAD_ID_IN_LWP) | |
556 | return task_ptid_get_lwp (task_ptid); | |
557 | else | |
558 | return task_ptid_get_tid (task_ptid); | |
559 | } | |
560 | ||
561 | /* Return non-zero iff the task STATE corresponds to a non-terminated | |
562 | task state. */ | |
563 | ||
564 | static int | |
565 | task_is_alive (enum task_states state) | |
566 | { | |
567 | return (state != Terminated); | |
568 | } | |
569 | ||
570 | static CORE_ADDR | |
571 | get_self_id (ptid_t ptid) | |
572 | { | |
573 | #ifdef GNAT_GDB | |
14f9c5c9 | 574 | struct task_entry *ent; |
14f9c5c9 AS |
575 | |
576 | #if !((defined(sun) && defined(__SVR4)) || defined(VXWORKS_TARGET) || defined(__WIN32__)) | |
577 | if (thread_support) | |
578 | #endif | |
579 | { | |
4c4b4cd2 | 580 | ent = get_thread_entry_vptr (GET_CURRENT_THREAD (ptid)); |
14f9c5c9 AS |
581 | return ent ? ent->task_id : 0; |
582 | } | |
4c4b4cd2 | 583 | #endif |
14f9c5c9 AS |
584 | |
585 | /* FIXME: calling a function in the inferior with a multithreaded application | |
4c4b4cd2 PH |
586 | is not reliable, so return a null address if there is no safe way to |
587 | get the current task */ | |
588 | return 0; | |
14f9c5c9 AS |
589 | } |
590 | ||
d2e4a39e | 591 | int |
4c4b4cd2 | 592 | ada_get_current_task (ptid_t ptid) |
14f9c5c9 AS |
593 | { |
594 | int result; | |
d2e4a39e | 595 | |
4c4b4cd2 PH |
596 | if (current_language->la_language != language_ada) |
597 | return -1; | |
14f9c5c9 | 598 | |
4c4b4cd2 | 599 | result = get_entry_number (get_self_id (ptid)); |
14f9c5c9 AS |
600 | |
601 | /* return -1 if not found */ | |
602 | return result == 0 ? -1 : result; | |
603 | } | |
604 | ||
4c4b4cd2 PH |
605 | /* Get from the debugging information the type description of all types |
606 | related to the Ada Task Control Block that will be needed in order to | |
607 | read the list of known tasks in the Ada runtime. Also return the | |
608 | associated ATCB_FIELDNOS. | |
609 | ||
610 | Error handling: Any data missing from the debugging info will cause | |
611 | an error to be raised, and none of the return values to be set. | |
612 | Users of this function can depend on the fact that all or none of the | |
613 | return values will be set. */ | |
614 | ||
615 | static void | |
616 | get_tcb_types_info (struct type **atcb_type, | |
617 | struct type **atcb_common_type, | |
618 | struct type **atcb_ll_type, | |
619 | struct tcb_fieldnos *atcb_fieldnos) | |
620 | { | |
621 | struct type *type; | |
622 | struct type *common_type; | |
623 | struct type *ll_type; | |
624 | struct tcb_fieldnos fieldnos; | |
625 | ||
626 | #ifndef ADA_RETAIN_DOTS | |
627 | const char *atcb_name = "system__tasking__ada_task_control_block___XVE"; | |
628 | const char *common_atcb_name = "system__tasking__common_atcb"; | |
629 | const char *private_data_name = "system__task_primitives__private_data"; | |
630 | #else | |
631 | const char *atcb_name = "system.tasking.ada_task_control_block___XVE"; | |
632 | const char *common_atcb_name = "system.tasking.common_atcb"; | |
633 | const char *private_data_name = "system.task_primitives.private_data"; | |
634 | #endif | |
635 | ||
636 | const struct symbol *atcb_sym = | |
637 | lookup_symbol (atcb_name, NULL, VAR_DOMAIN, NULL, NULL); | |
638 | const struct symbol *common_atcb_sym = | |
639 | lookup_symbol (common_atcb_name, NULL, VAR_DOMAIN, NULL, NULL); | |
640 | const struct symbol *private_data_sym = | |
641 | lookup_symbol (private_data_name, NULL, VAR_DOMAIN, NULL, NULL); | |
642 | ||
643 | if (atcb_sym == NULL || atcb_sym->type == NULL) | |
644 | error ("Can not find Ada_Task_Control_Block type. Aborting"); | |
645 | if (common_atcb_sym == NULL || common_atcb_sym->type == NULL) | |
646 | error ("Can not find Common_ATCB type. Aborting"); | |
647 | if (private_data_sym == NULL || private_data_sym->type == NULL) | |
648 | error ("Can not find Private_Data type. Aborting"); | |
649 | ||
650 | /* Get a static representation of the type record Ada_Task_Control_Block. */ | |
651 | type = atcb_sym->type; | |
652 | type = ada_template_to_fixed_record_type_1 (type, NULL, 0, NULL, 0); | |
653 | ||
654 | /* Get the type for Ada_Task_Control_Block.Common. */ | |
655 | common_type = common_atcb_sym->type; | |
656 | ||
657 | /* Get the type for Ada_Task_Control_Bloc.Common.Call.LL. */ | |
658 | ll_type = private_data_sym->type; | |
659 | ||
660 | /* Get the field indices. */ | |
661 | fieldnos.common = ada_get_field_index (type, "common", 0); | |
662 | fieldnos.state = ada_get_field_index (common_type, "state", 0); | |
663 | fieldnos.parent = ada_get_field_index (common_type, "parent", 0); | |
664 | fieldnos.priority = ada_get_field_index (common_type, "base_priority", 0); | |
665 | fieldnos.image = ada_get_field_index (common_type, "task_image", 0); | |
666 | fieldnos.image_len = ada_get_field_index (common_type, "task_image_len", 1); | |
667 | fieldnos.call = ada_get_field_index (common_type, "call", 0); | |
668 | fieldnos.ll = ada_get_field_index (common_type, "ll", 0); | |
669 | fieldnos.ll_thread = ada_get_field_index (ll_type, "thread", 0); | |
670 | fieldnos.ll_lwp = ada_get_field_index (ll_type, "lwp", 1); | |
671 | ||
672 | /* On certain platforms such as x86-windows, the "lwp" field has been | |
673 | named "thread_id". This field will likely be renamed in the future, | |
674 | but we need to support both possibilities to avoid an unnecessary | |
675 | dependency on a recent compiler. We therefore try locating the | |
676 | "thread_id" field in place of the "lwp" field if we did not find | |
677 | the latter. */ | |
678 | if (fieldnos.ll_lwp < 0) | |
679 | fieldnos.ll_lwp = ada_get_field_index (ll_type, "thread_id", 1); | |
680 | ||
681 | /* Set all the out parameters all at once, now that we are certain | |
682 | that there are no potential error() anymore. */ | |
683 | *atcb_type = type; | |
684 | *atcb_common_type = common_type; | |
685 | *atcb_ll_type = ll_type; | |
686 | *atcb_fieldnos = fieldnos; | |
687 | } | |
688 | ||
689 | /* Get from the debugging information the type description of the | |
690 | record type Entry_Call_Record (this is the type of the field | |
691 | Call.all in the Common_ATCB record type). Also return the index | |
692 | of the field "Self" in Entry_Call_Record. | |
693 | ||
694 | Error handling: Any data missing from the debugging info will cause | |
695 | an error to be raised, and none of the return values to be set. | |
696 | Users of this function can depend on the fact that all or none of the | |
697 | return values will be set. */ | |
698 | ||
699 | static void | |
700 | get_tcb_call_type_info (struct type **atcb_call_type, | |
701 | int *atcb_call_self_fieldno) | |
702 | { | |
703 | struct type *call_type; | |
704 | int call_self_fieldno; | |
705 | ||
706 | #ifndef ADA_RETAIN_DOTS | |
707 | const char *entry_call_record_name = "system__tasking__entry_call_record"; | |
708 | #else | |
709 | const char *entry_call_record_name = "system.tasking.entry_call_record"; | |
710 | #endif | |
711 | ||
712 | const struct symbol *entry_call_record_sym = | |
713 | lookup_symbol (entry_call_record_name, NULL, VAR_DOMAIN, NULL, NULL); | |
714 | ||
715 | if (entry_call_record_sym == NULL || entry_call_record_sym->type == NULL) | |
716 | error ("Can not find Entry_Call_Record type. Aborting"); | |
717 | ||
718 | call_type = entry_call_record_sym->type; | |
719 | call_self_fieldno = ada_get_field_index (call_type, "self", 0); | |
720 | ||
721 | /* Set all the out parameters all at once, now that we are certain | |
722 | that there are no potential error() anymore. */ | |
723 | *atcb_call_type = call_type; | |
724 | *atcb_call_self_fieldno = call_self_fieldno; | |
725 | } | |
726 | ||
727 | /* Return the address of the Known_Tasks array maintained in | |
728 | the Ada Runtime. Return NULL if the array could not be found, | |
729 | meaning that the inferior program probably does not use tasking. | |
730 | ||
731 | In order to provide a fast response time, this function caches | |
732 | the Known_Tasks array address after the lookup during the first | |
733 | call. Subsequent calls will simply return this cached address. */ | |
734 | ||
735 | static CORE_ADDR | |
736 | get_known_tasks_addr (void) | |
737 | { | |
738 | static CORE_ADDR known_tasks_addr = 0; | |
739 | ||
740 | if (ada__tasks_check_symbol_table) | |
741 | { | |
742 | struct symbol *sym; | |
743 | struct minimal_symbol *msym; | |
744 | ||
745 | thread_support = 0; | |
746 | #if (defined(__alpha__) && defined(__osf__) & !defined(VXWORKS_TARGET)) \ | |
747 | || defined (_AIX) || defined (__CYGWIN__) | |
748 | thread_support = 1; | |
749 | #elif defined (__fsu__) | |
750 | msym = lookup_minimal_symbol (PTHREAD_KERN, NULL, NULL); | |
751 | if (msym != NULL) | |
752 | { | |
753 | pthread_kern_addr = SYMBOL_VALUE_ADDRESS (msym); | |
754 | thread_support = 1; | |
755 | } | |
756 | #elif defined (HAVE_SPYTHREAD) | |
757 | thread_support = libspy_enabled; | |
758 | #endif | |
759 | ||
760 | #ifdef I386_GNULINUX_TARGET | |
761 | /* We support threads via the Linux Threads... */ | |
762 | thread_support = 1; | |
763 | #endif | |
764 | ||
765 | msym = lookup_minimal_symbol (KNOWN_TASKS_NAME, NULL, NULL); | |
766 | if (msym != NULL) | |
767 | known_tasks_addr = SYMBOL_VALUE_ADDRESS (msym); | |
768 | else | |
769 | #ifndef VXWORKS_TARGET | |
770 | return 0; | |
771 | #else | |
772 | { | |
773 | if (target_lookup_symbol (KNOWN_TASKS_NAME, &known_tasks_addr) != 0) | |
774 | return 0; | |
775 | } | |
776 | #endif | |
777 | ||
778 | /* FIXME: brobecker 2003-03-05: Here would be a much better place | |
779 | to attach the ada-tasks observers, instead of doing this | |
780 | unconditionaly in _initialize_tasks. This would avoid an | |
781 | unecessary notification when the inferior does not use tasking | |
782 | or as long as the user does not use the ada-tasks commands. | |
783 | Unfortunately, this is not possible for the moment: the current | |
784 | code resets ada__tasks_check_symbol_table back to 1 whenever | |
785 | symbols for a new program are being loaded. If we place the | |
786 | observers intialization here, we will end up adding new observers | |
787 | everytime we do the check for Ada tasking-related symbols | |
788 | above. This would currently have benign effects, but is still | |
789 | undesirable. The cleanest approach is probably to create a new | |
790 | observer to notify us when the user is debugging a new program. | |
791 | We would then reset ada__tasks_check_symbol_table back to 1 | |
792 | during the notification, but also detach all observers. | |
793 | BTW: observers are probably not reentrant, so detaching during | |
794 | a notification may not be the safest thing to do... Sigh... | |
795 | But creating the new observer would be a good idea in any case, | |
796 | since this allow us to make ada__tasks_check_symbol_table | |
797 | static, which is a good bonus. */ | |
798 | ada__tasks_check_symbol_table = 0; | |
799 | } | |
800 | ||
801 | return known_tasks_addr; | |
802 | } | |
803 | ||
804 | /* Read the Known_Tasks array from the inferior memory, and store | |
805 | it in task_list. Return non-zero upon success. */ | |
806 | ||
807 | static int | |
808 | read_known_tasks_array (void) | |
809 | { | |
810 | const int target_ptr_byte = TARGET_PTR_BIT / TARGET_CHAR_BIT; | |
811 | const int temp_tasks_size = target_ptr_byte * MAX_NUMBER_OF_KNOWN_TASKS; | |
812 | const CORE_ADDR known_tasks_addr = get_known_tasks_addr (); | |
813 | char *temp_tasks = (char *) alloca (temp_tasks_size); | |
814 | CORE_ADDR temp_task; | |
815 | int i; | |
816 | ||
817 | /* Step 1: Clear the current list, if any. */ | |
818 | init_task_list (); | |
819 | ||
820 | /* If the application does not use task, then no more needs to be done. | |
821 | It is important to have the task list cleared (see above) before we | |
822 | return, as we don't want a stale task list to be used... This can | |
823 | happen for instance when debugging a non-multitasking program after | |
824 | having debugged a multitasking one. */ | |
825 | if (known_tasks_addr == 0) | |
826 | return 0; | |
827 | ||
828 | /* Step 2: Build a new list by reading the ATCBs from the Known_Tasks | |
829 | array in the Ada runtime. */ | |
830 | read_memory (known_tasks_addr, temp_tasks, temp_tasks_size); | |
831 | for (i = 0; i < MAX_NUMBER_OF_KNOWN_TASKS; i++) | |
832 | { | |
833 | temp_task = extract_typed_address (temp_tasks + i * target_ptr_byte, | |
834 | builtin_type_void_data_ptr); | |
835 | ||
836 | if (temp_task != 0) | |
837 | { | |
838 | if (get_entry_number (temp_task) == 0) | |
839 | add_task_entry (temp_task, i); | |
840 | } | |
841 | } | |
842 | ||
843 | /* Step 3: Unset stale_task_list_p, to avoid re-reading the Known_Tasks | |
844 | array unless needed. Then report a success. */ | |
845 | stale_task_list_p = 0; | |
846 | return 1; | |
847 | } | |
848 | ||
849 | /* Builds the task_list by reading the Known_Tasks array from | |
850 | the inferior. Prints an appropriate message and returns non-zero | |
851 | if it failed to build this list. */ | |
852 | ||
853 | static int | |
854 | build_task_list (void) | |
855 | { | |
856 | if (!target_has_stack) | |
857 | error ("No stack"); | |
858 | ||
859 | if (stale_task_list_p) | |
860 | read_known_tasks_array (); | |
861 | ||
862 | if (task_list == NULL) | |
863 | { | |
864 | printf_filtered ("Your application does not use any Ada task.\n"); | |
865 | return 0; | |
866 | } | |
867 | ||
868 | return 1; | |
869 | } | |
870 | ||
871 | /* Extract the contents of the value as a string whose length is LENGTH, | |
872 | and store the result in DEST. */ | |
873 | ||
874 | static void | |
875 | value_as_string (char *dest, struct value *val, int length) | |
876 | { | |
877 | memcpy (dest, VALUE_CONTENTS (val), length); | |
878 | } | |
879 | ||
880 | /* Extract the string image from the fat string corresponding to VAL, | |
881 | and store it in DEST. The length of the string is stored in LEN. If | |
882 | the string length is greater than MAX_LEN, then truncate the result | |
883 | to the first MAX_LEN characters of the fat string. */ | |
884 | ||
885 | static void | |
886 | read_fat_string_value (char *dest, int *len, struct value *val, int max_len) | |
887 | { | |
888 | struct value *array_val; | |
889 | struct value *bounds_val; | |
890 | ||
891 | /* The following variables are made static to avoid recomputing them | |
892 | each time this function is called. */ | |
893 | static int initialize_fieldnos = 1; | |
894 | static int array_fieldno; | |
895 | static int bounds_fieldno; | |
896 | static int upper_bound_fieldno; | |
897 | ||
898 | /* Get the index of the fields that we will need to read in order | |
899 | to extract the string from the fat string. */ | |
900 | if (initialize_fieldnos) | |
901 | { | |
902 | struct type *type = VALUE_TYPE (val); | |
903 | struct type *bounds_type; | |
904 | ||
905 | array_fieldno = ada_get_field_index (type, "P_ARRAY", 0); | |
906 | bounds_fieldno = ada_get_field_index (type, "P_BOUNDS", 0); | |
907 | ||
908 | bounds_type = TYPE_FIELD_TYPE (type, bounds_fieldno); | |
909 | if (TYPE_CODE (bounds_type) == TYPE_CODE_PTR) | |
910 | bounds_type = TYPE_TARGET_TYPE (bounds_type); | |
911 | if (TYPE_CODE (bounds_type) != TYPE_CODE_STRUCT) | |
912 | error ("Unknown task name format. Aborting"); | |
913 | upper_bound_fieldno = ada_get_field_index (bounds_type, "UB0", 0); | |
914 | ||
915 | initialize_fieldnos = 0; | |
916 | } | |
917 | ||
918 | /* Get the size of the task image by checking the value of the bounds. | |
919 | The lower bound is always 1, so we only need to read the upper bound. */ | |
920 | bounds_val = value_ind (value_field (val, bounds_fieldno)); | |
921 | *len = value_as_long (value_field (bounds_val, upper_bound_fieldno)); | |
922 | ||
923 | /* Make sure that we do not read more than max_len characters... */ | |
924 | if (*len > max_len) | |
925 | *len = max_len; | |
926 | ||
927 | /* Extract LEN characters from the fat string. */ | |
928 | array_val = value_ind (value_field (val, array_fieldno)); | |
929 | read_memory (VALUE_ADDRESS (array_val), dest, *len); | |
930 | } | |
931 | ||
932 | /* Read the ATCB stored at ATCB_ADDR from the inferior memory. */ | |
933 | ||
934 | static struct task_control_block | |
935 | read_atcb (CORE_ADDR atcb_addr) | |
936 | { | |
937 | /* The type description for the ATCB record and subrecords, and | |
938 | the associated tcb_fieldnos. For efficiency reasons, these are made | |
939 | static so that we can compute them only once the first time and | |
940 | reuse them later. */ | |
941 | static struct type *atcb_type = NULL; | |
942 | static struct type *atcb_common_type = NULL; | |
943 | static struct type *atcb_ll_type = NULL; | |
944 | static struct tcb_fieldnos fieldno; | |
945 | ||
946 | struct task_control_block result; | |
947 | struct value *tcb_value; | |
948 | struct value *ll_value; | |
949 | ||
950 | if (atcb_type == NULL) | |
951 | get_tcb_types_info (&atcb_type, &atcb_common_type, &atcb_ll_type, &fieldno); | |
952 | ||
953 | tcb_value = value_from_contents_and_address (atcb_type, NULL, atcb_addr); | |
954 | tcb_value = value_field (tcb_value, fieldno.common); | |
955 | ||
956 | result.state = value_as_long (value_field (tcb_value, fieldno.state)); | |
957 | result.parent = value_as_address (value_field (tcb_value, fieldno.parent)); | |
958 | result.priority = value_as_long (value_field (tcb_value, fieldno.priority)); | |
959 | ||
960 | /* Depending on the GNAT version used, the task image is either a fat | |
961 | string, or a thin array of characters. Older versions of GNAT used | |
962 | to use fat strings, and therefore did not need an extra field in | |
963 | the ATCB to store the string length. For efficiency reasons, newer | |
964 | versions of GNAT replaced the fat string by a static buffer, but this | |
965 | also required the addition of a new field named "Image_Len" containing | |
966 | the length of the task name. The method used to extract the task name | |
967 | is selected depending on the existence of this field. */ | |
968 | if (fieldno.image_len == -1) | |
969 | { | |
970 | read_fat_string_value (result.image, &result.image_len, | |
971 | value_field (tcb_value, fieldno.image), | |
972 | sizeof (result.image)); | |
973 | } | |
974 | else | |
975 | { | |
976 | value_as_string (result.image, value_field (tcb_value, fieldno.image), | |
977 | sizeof (result.image)); | |
978 | result.image_len = | |
979 | value_as_long (value_field (tcb_value, fieldno.image_len)); | |
980 | } | |
981 | ||
982 | result.call = value_as_address (value_field (tcb_value, fieldno.call)); | |
983 | ||
984 | ll_value = value_field (tcb_value, fieldno.ll); | |
985 | result.thread = value_as_address (value_field (ll_value, fieldno.ll_thread)); | |
986 | if (fieldno.ll_lwp >= 0) | |
987 | result.lwp = value_as_address (value_field (ll_value, fieldno.ll_lwp)); | |
988 | else | |
989 | result.lwp = 0; | |
990 | ||
991 | return result; | |
992 | } | |
993 | ||
994 | /* Read the ID of the task with which a task is attempting a rendez-vous | |
995 | from the address of its Entry_Call_Record in the Ada TCB. | |
996 | If the address of the Entry_Call_Record is null, then return null. */ | |
997 | ||
998 | static CORE_ADDR | |
999 | read_caller (const CORE_ADDR call) | |
1000 | { | |
1001 | /* The type description for the Entry_Call_Record, and the index of | |
1002 | the field "Self". For efficiency reasons, these are made static | |
1003 | so that we can compute them only once the first time and reuse them | |
1004 | later. */ | |
1005 | static struct type *atcb_call_type; | |
1006 | static int self_fieldno = -1; | |
1007 | ||
1008 | struct value *call_value; | |
1009 | ||
1010 | if (call == 0) | |
1011 | return 0; | |
1012 | ||
1013 | if (atcb_call_type == NULL) | |
1014 | get_tcb_call_type_info (&atcb_call_type, &self_fieldno); | |
1015 | ||
1016 | call_value = value_from_contents_and_address (atcb_call_type, NULL, call); | |
1017 | return value_as_address (value_field (call_value, self_fieldno)); | |
1018 | } | |
1019 | ||
1020 | #if 0 | |
1021 | /* FIXME: Now modified and back in breakpoint.c */ | |
1022 | /* breakpoint_task_match (PC) returns true if the breakpoint at PC | |
1023 | is valid for current task. */ | |
1024 | ||
1025 | int | |
1026 | breakpoint_task_match (CORE_ADDR pc) | |
1027 | { | |
1028 | const int this_task = get_current_task (); | |
1029 | const struct breakpoint *breakpoints = get_breakpoint_chain (); | |
1030 | const struct breakpoint *b; | |
1031 | ||
1032 | for (b = breakpoints; b; b = b->next) | |
1033 | { | |
1034 | if (b->enable_state != bp_disabled | |
1035 | && b->enable_state != bp_shlib_disabled | |
1036 | && (b->address == 0 || b->address == pc) | |
1037 | && (b->task == 0 || b->task == this_task)) | |
1038 | { | |
1039 | return 1; | |
1040 | } | |
1041 | } | |
1042 | ||
1043 | return 0; | |
1044 | } | |
1045 | #endif | |
1046 | ||
14f9c5c9 AS |
1047 | /* Print detailed information about specified task */ |
1048 | ||
1049 | static void | |
80ae6ee2 | 1050 | info_task (char *arg, int from_tty) |
14f9c5c9 | 1051 | { |
4c4b4cd2 | 1052 | #ifdef GNAT_GDB |
14f9c5c9 | 1053 | struct task_entry *pt, *pt2; |
4c4b4cd2 | 1054 | CORE_ADDR caller; |
14f9c5c9 AS |
1055 | int num; |
1056 | ||
4c4b4cd2 PH |
1057 | if (current_language->la_language != language_ada) |
1058 | { | |
1059 | printf_filtered ("The current language does not support tasks.\n"); | |
1060 | return; | |
1061 | } | |
1062 | ||
1063 | target_find_new_threads (); | |
1064 | ||
14f9c5c9 AS |
1065 | pt = get_entry_vptr (atoi (arg)); |
1066 | if (pt == NULL) | |
1067 | { | |
d2e4a39e AS |
1068 | printf_filtered ("Task %s not found.\n", arg); |
1069 | return; | |
14f9c5c9 AS |
1070 | } |
1071 | ||
14f9c5c9 | 1072 | /* print the Ada task id */ |
4c4b4cd2 | 1073 | printf_filtered ("Ada Task: %s\n", paddr_nz (pt->task_id)); |
14f9c5c9 AS |
1074 | |
1075 | /* print the name of the task */ | |
4c4b4cd2 PH |
1076 | if (pt->atcb.image_len != 0) |
1077 | printf_filtered ("Name: %.*s\n", pt->atcb.image_len, pt->atcb.image); | |
d2e4a39e AS |
1078 | else |
1079 | printf_filtered ("<no name>\n"); | |
14f9c5c9 AS |
1080 | |
1081 | /* print the thread id */ | |
1082 | ||
4c4b4cd2 PH |
1083 | if (task_ptid_get_tid (pt->task_ptid) < 65536) |
1084 | printf_filtered | |
1085 | ("Thread: %ld\n", (long int) task_ptid_get_tid (pt->task_ptid)); | |
14f9c5c9 | 1086 | else |
4c4b4cd2 PH |
1087 | printf_filtered |
1088 | ("Thread: %#lx\n", (long int) task_ptid_get_tid (pt->task_ptid)); | |
14f9c5c9 | 1089 | |
4c4b4cd2 | 1090 | if (task_ptid_get_lwp (pt->task_ptid) != 0) |
14f9c5c9 | 1091 | { |
4c4b4cd2 PH |
1092 | if ((long) task_ptid_get_lwp (pt->task_ptid) < 65536) |
1093 | printf_filtered | |
1094 | ("LWP: %ld\n", (long int) task_ptid_get_lwp (pt->task_ptid)); | |
14f9c5c9 | 1095 | else |
4c4b4cd2 PH |
1096 | printf_filtered |
1097 | ("LWP: %#lx\n", (long int) task_ptid_get_lwp (pt->task_ptid)); | |
14f9c5c9 AS |
1098 | } |
1099 | ||
1100 | /* print the parent gdb task id */ | |
4c4b4cd2 | 1101 | num = get_entry_number (pt->atcb.parent); |
14f9c5c9 AS |
1102 | if (num != 0) |
1103 | { | |
1104 | printf_filtered ("Parent: %d", num); | |
1105 | pt2 = get_entry_vptr (num); | |
14f9c5c9 AS |
1106 | |
1107 | /* print the name of the task */ | |
4c4b4cd2 PH |
1108 | if (pt2->atcb.image_len != 0) |
1109 | printf_filtered (" (%.*s)\n", pt2->atcb.image_len, pt2->atcb.image); | |
14f9c5c9 | 1110 | else |
d2e4a39e | 1111 | printf_filtered ("\n"); |
14f9c5c9 AS |
1112 | } |
1113 | else | |
1114 | printf_filtered ("No parent\n"); | |
1115 | ||
1116 | /* print the base priority of the task */ | |
4c4b4cd2 | 1117 | printf_filtered ("Base Priority: %d\n", pt->atcb.priority); |
14f9c5c9 AS |
1118 | |
1119 | /* print the current state of the task */ | |
1120 | ||
1121 | /* check if this task is accepting a rendezvous */ | |
4c4b4cd2 PH |
1122 | caller = read_caller (pt->atcb.call); |
1123 | if (caller != 0) | |
14f9c5c9 AS |
1124 | { |
1125 | num = get_entry_number (caller); | |
1126 | printf_filtered ("Accepting rendezvous with %d", num); | |
1127 | ||
1128 | if (num != 0) | |
1129 | { | |
1130 | pt2 = get_entry_vptr (num); | |
14f9c5c9 AS |
1131 | |
1132 | /* print the name of the task */ | |
4c4b4cd2 PH |
1133 | if (pt2->atcb.image_len != 0) { |
1134 | printf_filtered (" (%.*s)\n", pt2->atcb.image_len, pt2->atcb.image); | |
1135 | } | |
14f9c5c9 AS |
1136 | else |
1137 | printf_filtered ("\n"); | |
1138 | } | |
1139 | else | |
4c4b4cd2 | 1140 | printf_filtered ("\n"); |
14f9c5c9 AS |
1141 | } |
1142 | else | |
4c4b4cd2 | 1143 | printf_filtered ("State: %s\n", long_task_states[pt->atcb.state]); |
14f9c5c9 | 1144 | #endif |
4c4b4cd2 | 1145 | } |
14f9c5c9 AS |
1146 | |
1147 | /* Print information about currently known tasks */ | |
1148 | ||
1149 | static void | |
80ae6ee2 | 1150 | info_tasks (char *arg, int from_tty) |
14f9c5c9 | 1151 | { |
4c4b4cd2 | 1152 | #ifdef GNAT_GDB |
14f9c5c9 | 1153 | struct task_entry *pt; |
4c4b4cd2 PH |
1154 | CORE_ADDR caller; |
1155 | long thread_id = 0L; | |
14f9c5c9 AS |
1156 | int size; |
1157 | char car; | |
4c4b4cd2 | 1158 | ptid_t current_ptid; |
14f9c5c9 AS |
1159 | |
1160 | #if defined(__alpha__) && defined(__osf__) && !defined(VXWORKS_TARGET) | |
1161 | pthreadTeb_t thr; | |
1162 | gdb_gregset_t regs; | |
1163 | #endif | |
1164 | ||
4c4b4cd2 | 1165 | current_ptid = inferior_ptid; |
14f9c5c9 AS |
1166 | |
1167 | #if !((defined(sun) && defined(__SVR4)) || defined(VXWORKS_TARGET) || defined(__WIN32__) || defined (hpux)) | |
1168 | if (thread_support) | |
1169 | #endif | |
4c4b4cd2 | 1170 | thread_id = GET_CURRENT_THREAD (inferior_ptid); |
14f9c5c9 AS |
1171 | |
1172 | /* print the header */ | |
1173 | ||
1174 | #if defined(__alpha__) && defined(__osf__) && !defined(VXWORKS_TARGET) | |
1175 | printf_filtered | |
d2e4a39e | 1176 | (" ID TID P-ID Pri Stack %% State Name\n"); |
14f9c5c9 AS |
1177 | #else |
1178 | printf_filtered (" ID TID P-ID Pri State Name\n"); | |
1179 | #endif | |
1180 | ||
1181 | /* Now that we have a list of task id's, we can print them */ | |
1182 | pt = task_list; | |
1183 | while (pt) | |
1184 | { | |
14f9c5c9 AS |
1185 | /* print a star if this task is the current one */ |
1186 | if (thread_id) | |
1187 | #if defined (__WIN32__) || defined (SGI) || defined (hpux) | |
4c4b4cd2 PH |
1188 | printf_filtered |
1189 | (task_ptid_get_lwp (pt->task_ptid) == thread_id ? "*" : " "); | |
14f9c5c9 | 1190 | #else |
4c4b4cd2 PH |
1191 | printf_filtered |
1192 | (task_ptid_get_thread_id (pt->task_ptid) == thread_id ? "*" : " "); | |
14f9c5c9 AS |
1193 | #endif |
1194 | ||
1195 | /* print the gdb task id */ | |
1196 | printf_filtered ("%3d", pt->task_num); | |
1197 | ||
1198 | /* print the Ada task id */ | |
4c4b4cd2 | 1199 | printf_filtered (" %9lx", (long) pt->task_id); |
14f9c5c9 AS |
1200 | |
1201 | /* print the parent gdb task id */ | |
4c4b4cd2 | 1202 | printf_filtered (" %4d", get_entry_number (pt->atcb.parent)); |
14f9c5c9 AS |
1203 | |
1204 | /* print the base priority of the task */ | |
4c4b4cd2 | 1205 | printf_filtered (" %3d", pt->atcb.priority); |
14f9c5c9 AS |
1206 | |
1207 | #if defined(__alpha__) && defined(__osf__) && !defined(VXWORKS_TARGET) | |
4c4b4cd2 PH |
1208 | if (pt->task_num == 1 || pt->atcb.state == Terminated) |
1209 | { | |
1210 | printf_filtered (" Unknown"); | |
1211 | goto next; | |
1212 | } | |
1213 | ||
1214 | READ_MEMORY (pt->atcb.thread, thr); | |
1215 | switch_to_thread (task_ptid_get_ptid (pt->task_ptid)); | |
1216 | /* ??? Brobecker 2003-03-13: Not sure what the next line is used for. | |
1217 | And even if useful, it should probably be replaced by call to | |
1218 | task_ptid_get_thread_id. */ | |
1219 | current_thread = task_ptid_get_tid (pt->task_ptid); | |
d2e4a39e AS |
1220 | regs.regs[SP_REGNUM] = 0; |
1221 | if (dec_thread_get_registers (®s, NULL) == 0) | |
4c4b4cd2 PH |
1222 | { |
1223 | pt->stack_per = (100 * ((long) thr.__stack_base - | |
1224 | regs.regs[SP_REGNUM])) / thr.__stack_size; | |
1225 | /* if the thread is terminated but still there, the | |
1226 | stack_base/size values are erroneous. Try to patch it */ | |
1227 | if (pt->stack_per < 0 || pt->stack_per > 100) | |
1228 | pt->stack_per = 0; | |
1229 | } | |
1230 | else | |
1231 | { | |
1232 | /* Set stack_per to an invalid value to signal that we did not | |
1233 | manage to compute its value. */ | |
1234 | pt->stack_per = -1; | |
1235 | } | |
14f9c5c9 AS |
1236 | |
1237 | /* print information about stack space used in the thread */ | |
d2e4a39e | 1238 | if (thr.__stack_size < 1024 * 1024) |
4c4b4cd2 PH |
1239 | { |
1240 | size = thr.__stack_size / 1024; | |
1241 | car = 'K'; | |
1242 | } | |
d2e4a39e | 1243 | else if (thr.__stack_size < 1024 * 1024 * 1024) |
4c4b4cd2 PH |
1244 | { |
1245 | size = thr.__stack_size / 1024 / 1024; | |
1246 | car = 'M'; | |
1247 | } | |
1248 | else /* Who knows... */ | |
1249 | { | |
1250 | size = thr.__stack_size / 1024 / 1024 / 1024; | |
1251 | car = 'G'; | |
1252 | } | |
1253 | ||
1254 | /* print the stack usage in percent, if available. */ | |
1255 | if (pt->stack_per != -1) | |
1256 | printf_filtered (" %4d%c %2d", size, car, pt->stack_per); | |
1257 | else | |
1258 | { | |
1259 | /* This error is not serious enough that we should raise | |
1260 | an internal error, but print '???' to make it unambiguous | |
1261 | that we failed to compute this value. */ | |
1262 | printf_filtered (" ???"); | |
1263 | } | |
1264 | ||
d2e4a39e | 1265 | next: |
14f9c5c9 AS |
1266 | #endif |
1267 | ||
1268 | /* print the current state of the task */ | |
1269 | ||
1270 | /* check if this task is accepting a rendezvous */ | |
4c4b4cd2 PH |
1271 | caller = read_caller (pt->atcb.call); |
1272 | if (caller != 0) | |
1273 | printf_filtered (" Accepting RV with %-4d", | |
1274 | get_entry_number (caller)); | |
14f9c5c9 | 1275 | else |
4c4b4cd2 | 1276 | { |
14f9c5c9 | 1277 | #if defined (__WIN32__) || defined (SGI) || defined (hpux) |
4c4b4cd2 PH |
1278 | if (pt->atcb.state == Runnable |
1279 | && (thread_id | |
1280 | && task_ptid_get_lwp (pt->task_ptid) == thread_id)) | |
14f9c5c9 | 1281 | #else |
4c4b4cd2 PH |
1282 | if (pt->atcb.state == Runnable |
1283 | && (thread_id | |
1284 | && task_ptid_get_thread_id (pt->task_ptid) == thread_id)) | |
14f9c5c9 | 1285 | #endif |
4c4b4cd2 PH |
1286 | /* Replace "Runnable" by "Running" if this is the current task */ |
1287 | printf_filtered (" %-22s", "Running"); | |
1288 | else | |
1289 | printf_filtered (" %-22s", task_states[pt->atcb.state]); | |
1290 | } | |
14f9c5c9 AS |
1291 | |
1292 | /* finally, print the name of the task */ | |
4c4b4cd2 PH |
1293 | if (pt->atcb.image_len != 0) { |
1294 | printf_filtered (" %.*s\n", pt->atcb.image_len, pt->atcb.image); | |
1295 | } | |
d2e4a39e AS |
1296 | else |
1297 | printf_filtered (" <no name>\n"); | |
14f9c5c9 AS |
1298 | |
1299 | pt = pt->next_task; | |
1300 | } | |
4c4b4cd2 PH |
1301 | if (!ptid_equal (inferior_ptid, current_ptid)) |
1302 | switch_to_thread (current_ptid); | |
1303 | #endif | |
14f9c5c9 AS |
1304 | } |
1305 | ||
1306 | static void | |
80ae6ee2 | 1307 | info_tasks_command (char *arg, int from_tty) |
14f9c5c9 | 1308 | { |
4c4b4cd2 PH |
1309 | const int task_list_built = build_task_list (); |
1310 | ||
1311 | if (!task_list_built) | |
1312 | return; | |
1313 | ||
d2e4a39e AS |
1314 | if (arg == NULL || *arg == '\000') |
1315 | info_tasks (arg, from_tty); | |
1316 | else | |
1317 | info_task (arg, from_tty); | |
14f9c5c9 AS |
1318 | } |
1319 | ||
4c4b4cd2 | 1320 | /* Switch to task indicated by NEW_TASK. Return 0 iff successful. */ |
14f9c5c9 | 1321 | |
4c4b4cd2 PH |
1322 | static int |
1323 | switch_to_task (struct task_entry *new_task) | |
14f9c5c9 | 1324 | { |
4c4b4cd2 PH |
1325 | #ifdef GNAT_GDB |
1326 | /* Raise an error if task-switching is currently not allowed. */ | |
1327 | if (!THREAD_SWITCH_ALLOWED ()) | |
1328 | error ("Task switching is currently not allowed."); | |
14f9c5c9 | 1329 | |
4c4b4cd2 PH |
1330 | if (!task_is_alive (new_task->atcb.state)) |
1331 | error ("Can not switch to task %d: Task is no longer running", | |
1332 | new_task->task_num); | |
14f9c5c9 | 1333 | |
4c4b4cd2 PH |
1334 | current_task = new_task->task_num; |
1335 | current_thread = task_ptid_get_thread_id (new_task->task_ptid); | |
14f9c5c9 | 1336 | |
4c4b4cd2 PH |
1337 | if (current_task_id == -1) |
1338 | { | |
1339 | SAVE_TASK_REGISTERS (new_task); | |
1340 | current_task_id = ada_get_current_task (inferior_ptid); | |
1341 | } | |
14f9c5c9 | 1342 | |
4c4b4cd2 | 1343 | if (SPECIAL_THREAD_SUPPORT_ACTIVE ()) |
14f9c5c9 | 1344 | { |
4c4b4cd2 PH |
1345 | /* FIXME: Integrate with switch_to_thread */ |
1346 | int ret_code; | |
14f9c5c9 | 1347 | flush_cached_frames (); |
4c4b4cd2 PH |
1348 | registers_changed (); |
1349 | if (current_task == current_task_id) | |
1350 | { | |
1351 | RESTORE_TASK_REGISTERS (new_task); | |
1352 | ret_code = 0; | |
1353 | } | |
14f9c5c9 | 1354 | else |
4c4b4cd2 PH |
1355 | ret_code = THREAD_FETCH_REGISTERS (); |
1356 | if (ret_code == 0) | |
1357 | stop_pc = read_pc (); | |
14f9c5c9 | 1358 | select_frame (get_current_frame ()); |
4c4b4cd2 | 1359 | return ret_code; |
14f9c5c9 | 1360 | } |
4c4b4cd2 PH |
1361 | else if (task_ptid_get_pid (new_task->task_ptid) != 0) /* ?? */ |
1362 | { | |
1363 | switch_to_thread (task_ptid_get_ptid (new_task->task_ptid)); | |
1364 | return 0; | |
1365 | } | |
1366 | #endif | |
14f9c5c9 AS |
1367 | return -1; |
1368 | } | |
1369 | ||
4c4b4cd2 PH |
1370 | /* Print a message telling the user id of the current task. |
1371 | Print an error message if the application does not appear to | |
1372 | be using any Ada task. */ | |
1373 | ||
80ae6ee2 | 1374 | static void |
4c4b4cd2 | 1375 | display_current_task_id (void) |
14f9c5c9 | 1376 | { |
4c4b4cd2 | 1377 | const int current_task = ada_get_current_task (inferior_ptid); |
14f9c5c9 | 1378 | |
4c4b4cd2 PH |
1379 | if (current_task == -1) |
1380 | printf_filtered ("[Current task is unknown]\n"); | |
1381 | else | |
1382 | printf_filtered ("[Current task is %d]\n", current_task); | |
1383 | } | |
1384 | ||
1385 | /* Parse and evaluate TIDSTR into a task id, and try to switch to | |
1386 | that task. Print an error message if the task switch failed. */ | |
14f9c5c9 | 1387 | |
4c4b4cd2 PH |
1388 | static void |
1389 | task_command_1 (char *tidstr, int from_tty) | |
1390 | { | |
1391 | const int num = value_as_long (parse_and_eval (tidstr)); | |
1392 | struct task_entry *e = get_entry_vptr (num); | |
14f9c5c9 AS |
1393 | |
1394 | if (e == NULL) | |
1395 | error ("Task ID %d not known. Use the \"info tasks\" command to\n" | |
4c4b4cd2 | 1396 | "see the IDs of currently known tasks", num); |
14f9c5c9 | 1397 | |
4c4b4cd2 | 1398 | if (switch_to_task (e) == 0) |
14f9c5c9 | 1399 | { |
4c4b4cd2 | 1400 | ada_find_printable_frame (get_selected_frame ()); |
14f9c5c9 | 1401 | printf_filtered ("[Switching to task %d]\n", num); |
4c4b4cd2 PH |
1402 | print_stack_frame (get_selected_frame (), |
1403 | frame_relative_level (get_selected_frame ()), 1); | |
14f9c5c9 AS |
1404 | } |
1405 | else | |
1406 | printf_filtered ("Unable to switch to task %d\n", num); | |
1407 | } | |
1408 | ||
4c4b4cd2 PH |
1409 | /* Switch to task indicated in TIDSTR. Simply print the current task |
1410 | if TIDSTR is empty or NULL. */ | |
1411 | ||
1412 | static void | |
1413 | task_command (char *tidstr, int from_tty) | |
1414 | { | |
1415 | const int task_list_built = build_task_list (); | |
1416 | ||
1417 | if (!task_list_built) | |
1418 | return; | |
1419 | ||
1420 | if (tidstr == NULL || tidstr[0] == '\0') | |
1421 | display_current_task_id (); | |
1422 | else | |
1423 | task_command_1 (tidstr, from_tty); | |
1424 | } | |
1425 | ||
1426 | #if defined (__fsu__) || (defined(__alpha__) && defined(__osf__) && !defined(VXWORKS_TARGET)) | |
1427 | /* Restore saved registers if there was a task switch. */ | |
1428 | void | |
1429 | ada_reset_thread_registers (void) | |
1430 | { | |
1431 | if (current_task_id != -1 && SPECIAL_THREAD_SUPPORT_ACTIVE ()) | |
1432 | { | |
1433 | supply_gregset (&gregset_saved); | |
1434 | supply_fpregset (&fpregset_saved); | |
1435 | reinit_frame_cache (); | |
1436 | stop_pc = read_pc (); | |
1437 | } | |
1438 | current_task_id = -1; | |
1439 | } | |
1440 | #else | |
1441 | void | |
1442 | ada_reset_thread_registers (void) | |
1443 | { | |
1444 | } | |
1445 | #endif | |
1446 | ||
1447 | /* The 'normal_stop' observer notification callback. */ | |
1448 | ||
1449 | static void | |
1450 | normal_stop_notification (void) | |
1451 | { | |
1452 | /* The inferior has been resumed, and just stopped. This means that | |
1453 | our task_list needs to be recomputed before it can be used again. */ | |
1454 | stale_task_list_p = 1; | |
1455 | } | |
1456 | ||
1457 | /* Attach all the observers needed by the ada-tasks module. */ | |
1458 | ||
1459 | static void | |
1460 | ada_tasks_attach_observers (void) | |
1461 | { | |
1462 | observer_attach_normal_stop (&normal_stop_notification); | |
1463 | } | |
1464 | ||
14f9c5c9 | 1465 | void |
80ae6ee2 | 1466 | _initialize_tasks (void) |
14f9c5c9 | 1467 | { |
4c4b4cd2 | 1468 | #ifdef GNAT_GDB |
14f9c5c9 AS |
1469 | extern struct cmd_list_element *cmdlist; |
1470 | ||
4c4b4cd2 PH |
1471 | ada_tasks_attach_observers (); |
1472 | ||
d2e4a39e | 1473 | add_info ("tasks", info_tasks_command, |
4c4b4cd2 PH |
1474 | "Without argument: list all known Ada tasks, with status information.\n" |
1475 | "info tasks n: print detailed information of task n."); | |
14f9c5c9 | 1476 | |
4c4b4cd2 PH |
1477 | add_cmd ("task", class_run, task_command, |
1478 | "Without argument: print the current task ID.\n" | |
1479 | "task n: Use this command to switch to task n.", | |
1480 | &cmdlist); | |
1481 | #endif | |
14f9c5c9 | 1482 | } |