* linux-nat.c (linux_nat_wait): Adjust.
[deliverable/binutils-gdb.git] / gdb / dec-thread.c
CommitLineData
0fb0cc75 1/* Copyright (C) 2008, 2009 Free Software Foundation, Inc.
7a052092
JB
2
3 This file is part of GDB.
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 3 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>. */
17
18#include "defs.h"
19#include "command.h"
20#include "gdbcmd.h"
21#include "target.h"
22#include "observer.h"
23#include <sys/procfs.h>
24#include "gregset.h"
25#include "regcache.h"
26#include "inferior.h"
27#include "gdbthread.h"
28
29#include <pthread_debug.h>
30
31/* Print debugging traces if set to non-zero. */
32static int debug_dec_thread = 0;
33
34/* Non-zero if the dec-thread layer is active. */
35static int dec_thread_active = 0;
36
37/* The pthread_debug context. */
38pthreadDebugContext_t debug_context;
39
40/* The dec-thread target_ops structure. */
41static struct target_ops dec_thread_ops;
42
43/* A copy of the target_ops over which our dec_thread_ops is pushed. */
44static struct target_ops base_target;
45
46/* Print a debug trace if DEBUG_DEC_THREAD is set (its value is adjusted
47 by the user using "set debug dec-thread ..."). */
48
49static void
50debug (char *format, ...)
51{
52 if (debug_dec_thread)
53 {
54 va_list args;
55
56 va_start (args, format);
57 printf_unfiltered ("DEC Threads: ");
58 vprintf_unfiltered (format, args);
59 printf_unfiltered ("\n");
60 va_end (args);
61 }
62}
63
64/* pthread debug callbacks. */
65
66static int
67suspend_clbk (void *caller_context)
68{
69 return ESUCCESS;
70}
71
72static int
73resume_clbk (void *caller_context)
74{
75 return ESUCCESS;
76}
77
78static int
79hold_clbk (void *caller_context, pthreadDebugKId_t kernel_tid)
80{
81 return ESUCCESS;
82}
83
84static int
85unhold_clbk (void *caller_context, pthreadDebugKId_t kernel_tid)
86{
87 return ESUCCESS;
88}
89
90static int
91read_clbk (void *caller_context, void *address, void *buffer,
92 unsigned long size)
93{
94 int status = target_read_memory ((CORE_ADDR) address, buffer, size);
95
96 if (status != 0)
97 return EINVAL;
98
99 return ESUCCESS;
100}
101
102static int
103write_clbk (void *caller_context, void *address, void *buffer,
104 unsigned long size)
105{
106 int status = target_write_memory ((CORE_ADDR) address, buffer, size);
107
108 if (status != 0)
109 return EINVAL;
110
111 return ESUCCESS;
112}
113
114/* Get integer regs */
115
116static int
117get_reg_clbk(void *caller_context, pthreadDebugGetRegRtn_t regs,
118 pthreadDebugKId_t kernel_tid)
119{
120 debug ("get_reg_clbk");
121
122 /* Not sure that we actually need to do anything in this callback. */
123 return ESUCCESS;
124}
125
126/* Set integer regs */
127
128static int
129set_reg_clbk(void *caller_context, const pthreadDebugRegs_t *regs,
130 pthreadDebugKId_t kernel_tid)
131{
132 debug ("set_reg_clbk");
133
134 /* Not sure that we actually need to do anything in this callback. */
135 return ESUCCESS;
136}
137
138static int
139output_clbk (void *caller_context, char *line)
140{
141 printf_filtered ("%s\n", line);
142 return ESUCCESS;
143}
144
145static int
146error_clbk (void *caller_context, char *line)
147{
148 fprintf_filtered (gdb_stderr, "%s\n", line);
149 return ESUCCESS;
150}
151
152/* Get floating-point regs. */
153
154static int
155get_fpreg_clbk (void *caller_context, pthreadDebugFregs_p fregs,
156 pthreadDebugKId_t kernel_tid)
157{
158 debug ("get_fpreg_clbk");
159
160 /* Not sure that we actually need to do anything in this callback. */
161 return ESUCCESS;
162}
163
164/* Set floating-point regs. */
165
166static int
167set_fpreg_clbk (void *caller_context, const pthreadDebugFregs_t *fregs,
168 pthreadDebugKId_t kernel_tid)
169{
170 debug ("set_fpreg_clbk");
171
172 /* Not sure that we actually need to do anything in this callback. */
173 return ESUCCESS;
174}
175
176static void *
177malloc_clbk (void *caller_context, size_t size)
178{
179 return xmalloc (size);
180}
181
182static void
183free_clbk (void *caller_context, void *address)
184{
185 xfree (address);
186}
187
188static int
189kthdinfo_clbk (pthreadDebugClient_t caller_context,
190 pthreadDebugKId_t kernel_tid,
191 pthreadDebugKThreadInfo_p thread_info)
192{
193 return ENOTSUP;
194}
195
196static int
197speckthd_clbk (pthreadDebugClient_t caller_context,
198 pthreadDebugSpecialType_t type,
199 pthreadDebugKId_t *kernel_tid)
200{
201 return ENOTSUP;
202}
203
204static pthreadDebugCallbacks_t debug_callbacks =
205{
206 PTHREAD_DEBUG_VERSION,
207 (pthreadDebugGetMemRtn_t) read_clbk,
208 (pthreadDebugSetMemRtn_t) write_clbk,
209 suspend_clbk,
210 resume_clbk,
211 kthdinfo_clbk,
212 hold_clbk,
213 unhold_clbk,
214 (pthreadDebugGetFregRtn_t) get_fpreg_clbk,
215 (pthreadDebugSetFregRtn_t) set_fpreg_clbk,
216 (pthreadDebugGetRegRtn_t) get_reg_clbk,
217 (pthreadDebugSetRegRtn_t) set_reg_clbk,
218 (pthreadDebugOutputRtn_t) output_clbk,
219 (pthreadDebugOutputRtn_t) error_clbk,
220 malloc_clbk,
221 free_clbk,
222 speckthd_clbk
223};
224
225/* Activate thread support if appropriate. Do nothing if thread
226 support is already active. */
227
228static void
229enable_dec_thread (void)
230{
231 struct minimal_symbol *msym;
232 void* caller_context;
233 int status;
234
235 /* If already active, nothing more to do. */
236 if (dec_thread_active)
237 return;
238
239 msym = lookup_minimal_symbol ("__pthread_dbg_symtable", NULL, NULL);
240 if (msym == NULL)
241 {
242 debug ("enable_dec_thread: No __pthread_dbg_symtable");
243 return;
244 }
245
246 status = pthreadDebugContextInit (&caller_context, &debug_callbacks,
247 (void *) SYMBOL_VALUE_ADDRESS (msym),
248 &debug_context);
249 if (status != ESUCCESS)
250 {
251 debug ("enable_dec_thread: pthreadDebugContextInit -> %d",
252 status);
253 return;
254 }
255
256 base_target = current_target;
257 push_target (&dec_thread_ops);
258 dec_thread_active = 1;
259
260 debug ("enable_dec_thread: Thread support enabled.");
261}
262
263/* Deactivate thread support. Do nothing is thread support is
264 already inactive. */
265
266static void
267disable_dec_thread (void)
268{
269 if (!dec_thread_active)
270 return;
271
272 pthreadDebugContextDestroy (debug_context);
273 unpush_target (&dec_thread_ops);
274 dec_thread_active = 0;
275}
276
277/* A structure that contains a thread ID and is associated
278 pthreadDebugThreadInfo_t data. */
279
280struct dec_thread_info
281{
282 pthreadDebugId_t thread;
283 pthreadDebugThreadInfo_t info;
284};
285typedef struct dec_thread_info dec_thread_info_s;
286
287/* The list of user threads. */
288
289DEF_VEC_O (dec_thread_info_s);
290VEC(dec_thread_info_s) *dec_thread_list;
291
292/* Release the memory used by the given VECP thread list pointer.
293 Then set *VECP to NULL. */
294
295static void
296free_dec_thread_info_vec (VEC(dec_thread_info_s) **vecp)
297{
298 int i;
299 struct dec_thread_info *item;
300 VEC(dec_thread_info_s) *vec = *vecp;
301
302 for (i = 0; VEC_iterate (dec_thread_info_s, vec, i, item); i++)
303 xfree (item);
304 VEC_free (dec_thread_info_s, vec);
305 *vecp = NULL;
306}
307
308/* Return a thread's ptid given its associated INFO. */
309
310static ptid_t
311ptid_build_from_info (struct dec_thread_info info)
312{
313 int pid = ptid_get_pid (inferior_ptid);
314
315 return ptid_build (pid, 0, (long) info.thread);
316}
317
318/* Recompute the list of user threads and store the result in
319 DEC_THREAD_LIST. */
320
321static void
322update_dec_thread_list (void)
323{
324 pthreadDebugId_t thread;
325 pthreadDebugThreadInfo_t info;
326 int res;
327
328 free_dec_thread_info_vec (&dec_thread_list);
329 res = pthreadDebugThdSeqInit (debug_context, &thread);
330 while (res == ESUCCESS)
331 {
332
333 res = pthreadDebugThdGetInfo (debug_context, thread, &info);
334 if (res != ESUCCESS)
335 warning (_("unable to get thread info, ignoring thread %ld"),
336 thread);
337 else if (info.kind == PTHREAD_DEBUG_THD_KIND_INITIAL
338 || info.kind == PTHREAD_DEBUG_THD_KIND_NORMAL)
339 {
340 struct dec_thread_info *item =
341 xmalloc (sizeof (struct dec_thread_info));
342
343 item->thread = thread;
344 item->info = info;
345 VEC_safe_push (dec_thread_info_s, dec_thread_list, item);
346 }
347 res = pthreadDebugThdSeqNext (debug_context, &thread);
348 }
349 pthreadDebugThdSeqDestroy (debug_context);
350}
351
352/* A callback to count the number of threads known to GDB. */
353
354static int
355dec_thread_count_gdb_threads (struct thread_info *ignored, void *context)
356{
357 int *count = (int *) context;
358
359 *count++;
360 return 0;
361}
362
363/* A callback that saves the given thread INFO at the end of an
364 array. The end of the array is given in the CONTEXT and is
365 incremented once the info has been added. */
366
367static int
368dec_thread_add_gdb_thread (struct thread_info *info, void *context)
369{
370 struct thread_info ***listp = (struct thread_info ***) context;
371
372 **listp = info;
373 *listp++;
374 return 0;
375}
376
377/* Resynchronize the list of threads known by GDB with the actual
378 list of threads reported by libpthread_debug. */
379
380static void
381resync_thread_list (void)
382{
383 int i;
384 struct dec_thread_info *info;
385 int num_gdb_threads = 0;
386 struct thread_info **gdb_thread_list;
387 struct thread_info **next_thread_info;
388
389 update_dec_thread_list ();
390
391 /* Add new threads. */
392
393 for (i = 0; VEC_iterate (dec_thread_info_s, dec_thread_list, i, info);
394 i++)
395 {
396 ptid_t ptid = ptid_build_from_info (*info);
397
398 if (!in_thread_list (ptid))
399 add_thread (ptid);
400 }
401
402 /* Remove threads that no longer exist. To help with the search,
403 we build an array of GDB threads, and then iterate over this
404 array. */
405
406 iterate_over_threads (dec_thread_count_gdb_threads,
407 (void *) &num_gdb_threads);
408 gdb_thread_list = alloca (num_gdb_threads * sizeof (struct thread_info *));
409 next_thread_info = gdb_thread_list;
410 iterate_over_threads (dec_thread_add_gdb_thread, (void *) &next_thread_info);
411 for (i = 0; i < num_gdb_threads; i++)
412 {
413 int j;
414
415 for (j = 0; VEC_iterate (dec_thread_info_s, dec_thread_list, j, info);
416 j++)
417 if (ptid_equal (gdb_thread_list[i]->ptid,
418 ptid_build_from_info (*info)))
419 break;
420 delete_thread (gdb_thread_list[i]->ptid);
421 }
422}
423
424/* The "to_detach" method of the dec_thread_ops. */
425
426static void
427dec_thread_detach (char *args, int from_tty)
428{
429 debug ("dec_thread_detach");
430
431 disable_dec_thread ();
136d6dae 432 base_target.to_detach (&base_target, args, from_tty);
7a052092
JB
433}
434
435/* Return the ptid of the thread that is currently active. */
436
437static ptid_t
438get_active_ptid (void)
439{
440 int i;
441 struct dec_thread_info *info;
442
443 for (i = 0; VEC_iterate (dec_thread_info_s, dec_thread_list, i, info);
444 i++)
445 if (info->info.state == PTHREAD_DEBUG_STATE_RUNNING)
446 return ptid_build_from_info (*info);
447
448 /* No active thread found. This can happen when the program
449 has just exited. */
450 return null_ptid;
451}
452
453/* The "to_wait" method of the dec_thread_ops. */
454
455static ptid_t
117de6a9
PA
456dec_thread_wait (struct target_ops *ops,
457 ptid_t ptid, struct target_waitstatus *status)
7a052092
JB
458{
459 ptid_t active_ptid;
460
461 debug ("dec_thread_wait");
462
117de6a9 463 ptid = base_target.to_wait (&base_target, ptid, status);
7a052092
JB
464
465 /* The ptid returned by the base_target is the ptid of the process.
466 We need to find which thread is currently active and return its
467 ptid. */
468 resync_thread_list ();
469 active_ptid = get_active_ptid ();
470 if (ptid_equal (active_ptid, null_ptid))
471 return ptid;
472 return active_ptid;
473}
474
475/* Fetch the general purpose and floating point registers for the given
476 thread TID, and store the result in GREGSET and FPREGSET. Return
477 zero if successful. */
478
479static int
480dec_thread_get_regsets (pthreadDebugId_t tid, gdb_gregset_t *gregset,
481 gdb_fpregset_t *fpregset)
482{
483 int res;
484 pthreadDebugRegs_t regs;
485 pthreadDebugFregs_t fregs;
486
487 res = pthreadDebugThdGetReg (debug_context, tid, &regs);
488 if (res != ESUCCESS)
489 {
490 debug ("dec_thread_fetch_registers: pthreadDebugThdGetReg -> %d", res);
491 return -1;
492 }
493 memcpy (gregset->regs, &regs, sizeof (regs));
494
495 res = pthreadDebugThdGetFreg (debug_context, tid, &fregs);
496 if (res != ESUCCESS)
497 {
498 debug ("dec_thread_fetch_registers: pthreadDebugThdGetFreg -> %d", res);
499 return -1;
500 }
501 memcpy (fpregset->regs, &fregs, sizeof (fregs));
502
503 return 0;
504}
505
506/* The "to_fetch_registers" method of the dec_thread_ops.
507
508 Because the dec-thread debug API doesn't allow us to fetch
509 only one register, we simply ignore regno and fetch+supply all
510 registers. */
511
512static void
513dec_thread_fetch_registers (struct regcache *regcache, int regno)
514{
515 pthreadDebugId_t tid = ptid_get_tid (inferior_ptid);
516 gregset_t gregset;
517 fpregset_t fpregset;
518 int res;
519
520 debug ("dec_thread_fetch_registers (tid=%ld, regno=%d)", tid, regno);
521
522
523 if (tid == 0 || ptid_equal (inferior_ptid, get_active_ptid ()))
524 {
525 base_target.to_fetch_registers (regcache, regno);
526 return;
527 }
528
529 res = dec_thread_get_regsets (tid, &gregset, &fpregset);
530 if (res != 0)
531 return;
532
533 supply_gregset (regcache, &gregset);
534 supply_fpregset (regcache, &fpregset);
535}
536
537/* Store the registers given in GREGSET and FPREGSET into the associated
538 general purpose and floating point registers of thread TID. Return
539 zero if successful. */
540
541static int
542dec_thread_set_regsets (pthreadDebugId_t tid, gdb_gregset_t gregset,
543 gdb_fpregset_t fpregset)
544{
545 int res;
546 pthreadDebugRegs_t regs;
547 pthreadDebugFregs_t fregs;
548
549 memcpy (&regs, gregset.regs, sizeof (regs));
550 res = pthreadDebugThdSetReg (debug_context, tid, &regs);
551 if (res != ESUCCESS)
552 {
553 debug ("dec_thread_fetch_registers: pthreadDebugThdSetReg -> %d", res);
554 return -1;
555 }
556
557 memcpy (&fregs, fpregset.regs, sizeof (fregs));
558 res = pthreadDebugThdSetFreg (debug_context, tid, &fregs);
559 if (res != ESUCCESS)
560 {
561 debug ("dec_thread_fetch_registers: pthreadDebugThdSetFreg -> %d", res);
562 return -1;
563 }
564
565 return 0;
566}
567
568/* The "to_store_registers" method of the dec_thread_ops.
569
570 Because the dec-thread debug API doesn't allow us to store
571 just one register, we store all the registers. */
572
573static void
574dec_thread_store_registers (struct regcache *regcache, int regno)
575{
576 pthreadDebugId_t tid = ptid_get_tid (inferior_ptid);
577 gregset_t gregset;
578 fpregset_t fpregset;
579 int res;
580
581 debug ("dec_thread_store_registers (tid=%ld, regno=%d)", tid, regno);
582
583 if (tid == 0 || ptid_equal (inferior_ptid, get_active_ptid ()))
584 {
585 base_target.to_store_registers (regcache, regno);
586 return;
587 }
588
589 /* FIXME: brobecker/2008-05-28: I wonder if we could simply check
590 in which register set the register is and then only store the
591 registers for that register set, instead of storing both register
592 sets. */
593 fill_gregset (regcache, &gregset, -1);
594 fill_fpregset (regcache, &fpregset, -1);
595
596 res = dec_thread_set_regsets (tid, gregset, fpregset);
597 if (res != 0)
598 warning (_("failed to store registers."));
599}
600
601/* The "to_mourn_inferior" method of the dec_thread_ops. */
602
603static void
604dec_thread_mourn_inferior (void)
605{
606 debug ("dec_thread_mourn_inferior");
607
608 disable_dec_thread ();
136d6dae 609 base_target.to_mourn_inferior (&base_target);
7a052092
JB
610}
611
612/* The "to_thread_alive" method of the dec_thread_ops. */
613static int
614dec_thread_thread_alive (ptid_t ptid)
615{
616 debug ("dec_thread_thread_alive (tid=%ld)", ptid_get_tid (ptid));
617
618 /* The thread list maintained by GDB is up to date, since we update
619 it everytime we stop. So check this list. */
620 return in_thread_list (ptid);
621}
622
623/* The "to_pid_to_str" method of the dec_thread_ops. */
624
625static char *
117de6a9 626dec_thread_pid_to_str (struct target_ops *ops, ptid_t ptid)
7a052092
JB
627{
628 static char *ret = NULL;
629
630 if (ptid_get_tid (ptid) == 0)
117de6a9 631 return base_target.to_pid_to_str (&base_target, ptid);
7a052092
JB
632
633 /* Free previous return value; a new one will be allocated by
634 xstrprintf(). */
635 xfree (ret);
636
637 ret = xstrprintf (_("Thread %ld"), ptid_get_tid (ptid));
638 return ret;
639}
640
641/* A "new-objfile" observer. Used to activate/deactivate dec-thread
642 support. */
643
644static void
645dec_thread_new_objfile_observer (struct objfile *objfile)
646{
647 if (objfile != NULL)
648 enable_dec_thread ();
649 else
650 disable_dec_thread ();
651}
652
653static void
654init_dec_thread_ops (void)
655{
656 dec_thread_ops.to_shortname = "dec-threads";
657 dec_thread_ops.to_longname = _("DEC threads support");
658 dec_thread_ops.to_doc = _("DEC threads support");
659 dec_thread_ops.to_detach = dec_thread_detach;
660 dec_thread_ops.to_wait = dec_thread_wait;
661 dec_thread_ops.to_fetch_registers = dec_thread_fetch_registers;
662 dec_thread_ops.to_store_registers = dec_thread_store_registers;
663 dec_thread_ops.to_mourn_inferior = dec_thread_mourn_inferior;
664 dec_thread_ops.to_thread_alive = dec_thread_thread_alive;
665 dec_thread_ops.to_pid_to_str = dec_thread_pid_to_str;
666 dec_thread_ops.to_stratum = thread_stratum;
667 dec_thread_ops.to_magic = OPS_MAGIC;
668}
669
670void
671_initialize_dec_thread (void)
672{
673 init_dec_thread_ops ();
674 add_target (&dec_thread_ops);
675
676 observer_attach_new_objfile (dec_thread_new_objfile_observer);
677
678 add_setshow_boolean_cmd ("dec-thread", class_maintenance, &debug_dec_thread,
679 _("Set debugging of DEC threads module."),
680 _("Show debugging of DEC threads module."),
681 _("Enables debugging output (used to debug GDB)."),
682 NULL, NULL,
683 &setdebuglist, &showdebuglist);
684}
This page took 0.071865 seconds and 4 git commands to generate.