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