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