* thread.c (print_thread_info): Eliminate now useless checks
[deliverable/binutils-gdb.git] / gdb / dec-thread.c
CommitLineData
7a052092
JB
1/* Copyright (C) 2008 Free Software Foundation, Inc.
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 ();
432 base_target.to_detach (args, from_tty);
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
456dec_thread_wait (ptid_t ptid, struct target_waitstatus *status)
457{
458 ptid_t active_ptid;
459
460 debug ("dec_thread_wait");
461
462 ptid = base_target.to_wait (ptid, status);
463
464 /* The ptid returned by the base_target is the ptid of the process.
465 We need to find which thread is currently active and return its
466 ptid. */
467 resync_thread_list ();
468 active_ptid = get_active_ptid ();
469 if (ptid_equal (active_ptid, null_ptid))
470 return ptid;
471 return active_ptid;
472}
473
474/* Fetch the general purpose and floating point registers for the given
475 thread TID, and store the result in GREGSET and FPREGSET. Return
476 zero if successful. */
477
478static int
479dec_thread_get_regsets (pthreadDebugId_t tid, gdb_gregset_t *gregset,
480 gdb_fpregset_t *fpregset)
481{
482 int res;
483 pthreadDebugRegs_t regs;
484 pthreadDebugFregs_t fregs;
485
486 res = pthreadDebugThdGetReg (debug_context, tid, &regs);
487 if (res != ESUCCESS)
488 {
489 debug ("dec_thread_fetch_registers: pthreadDebugThdGetReg -> %d", res);
490 return -1;
491 }
492 memcpy (gregset->regs, &regs, sizeof (regs));
493
494 res = pthreadDebugThdGetFreg (debug_context, tid, &fregs);
495 if (res != ESUCCESS)
496 {
497 debug ("dec_thread_fetch_registers: pthreadDebugThdGetFreg -> %d", res);
498 return -1;
499 }
500 memcpy (fpregset->regs, &fregs, sizeof (fregs));
501
502 return 0;
503}
504
505/* The "to_fetch_registers" method of the dec_thread_ops.
506
507 Because the dec-thread debug API doesn't allow us to fetch
508 only one register, we simply ignore regno and fetch+supply all
509 registers. */
510
511static void
512dec_thread_fetch_registers (struct regcache *regcache, int regno)
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 {
524 base_target.to_fetch_registers (regcache, regno);
525 return;
526 }
527
528 res = dec_thread_get_regsets (tid, &gregset, &fpregset);
529 if (res != 0)
530 return;
531
532 supply_gregset (regcache, &gregset);
533 supply_fpregset (regcache, &fpregset);
534}
535
536/* Store the registers given in GREGSET and FPREGSET into the associated
537 general purpose and floating point registers of thread TID. Return
538 zero if successful. */
539
540static int
541dec_thread_set_regsets (pthreadDebugId_t tid, gdb_gregset_t gregset,
542 gdb_fpregset_t fpregset)
543{
544 int res;
545 pthreadDebugRegs_t regs;
546 pthreadDebugFregs_t fregs;
547
548 memcpy (&regs, gregset.regs, sizeof (regs));
549 res = pthreadDebugThdSetReg (debug_context, tid, &regs);
550 if (res != ESUCCESS)
551 {
552 debug ("dec_thread_fetch_registers: pthreadDebugThdSetReg -> %d", res);
553 return -1;
554 }
555
556 memcpy (&fregs, fpregset.regs, sizeof (fregs));
557 res = pthreadDebugThdSetFreg (debug_context, tid, &fregs);
558 if (res != ESUCCESS)
559 {
560 debug ("dec_thread_fetch_registers: pthreadDebugThdSetFreg -> %d", res);
561 return -1;
562 }
563
564 return 0;
565}
566
567/* The "to_store_registers" method of the dec_thread_ops.
568
569 Because the dec-thread debug API doesn't allow us to store
570 just one register, we store all the registers. */
571
572static void
573dec_thread_store_registers (struct regcache *regcache, int regno)
574{
575 pthreadDebugId_t tid = ptid_get_tid (inferior_ptid);
576 gregset_t gregset;
577 fpregset_t fpregset;
578 int res;
579
580 debug ("dec_thread_store_registers (tid=%ld, regno=%d)", tid, regno);
581
582 if (tid == 0 || ptid_equal (inferior_ptid, get_active_ptid ()))
583 {
584 base_target.to_store_registers (regcache, regno);
585 return;
586 }
587
588 /* FIXME: brobecker/2008-05-28: I wonder if we could simply check
589 in which register set the register is and then only store the
590 registers for that register set, instead of storing both register
591 sets. */
592 fill_gregset (regcache, &gregset, -1);
593 fill_fpregset (regcache, &fpregset, -1);
594
595 res = dec_thread_set_regsets (tid, gregset, fpregset);
596 if (res != 0)
597 warning (_("failed to store registers."));
598}
599
600/* The "to_mourn_inferior" method of the dec_thread_ops. */
601
602static void
603dec_thread_mourn_inferior (void)
604{
605 debug ("dec_thread_mourn_inferior");
606
607 disable_dec_thread ();
608 base_target.to_mourn_inferior ();
609}
610
611/* The "to_thread_alive" method of the dec_thread_ops. */
612static int
613dec_thread_thread_alive (ptid_t ptid)
614{
615 debug ("dec_thread_thread_alive (tid=%ld)", ptid_get_tid (ptid));
616
617 /* The thread list maintained by GDB is up to date, since we update
618 it everytime we stop. So check this list. */
619 return in_thread_list (ptid);
620}
621
622/* The "to_pid_to_str" method of the dec_thread_ops. */
623
624static char *
625dec_thread_pid_to_str (ptid_t ptid)
626{
627 static char *ret = NULL;
628
629 if (ptid_get_tid (ptid) == 0)
630 return base_target.to_pid_to_str (ptid);
631
632 /* Free previous return value; a new one will be allocated by
633 xstrprintf(). */
634 xfree (ret);
635
636 ret = xstrprintf (_("Thread %ld"), ptid_get_tid (ptid));
637 return ret;
638}
639
640/* A "new-objfile" observer. Used to activate/deactivate dec-thread
641 support. */
642
643static void
644dec_thread_new_objfile_observer (struct objfile *objfile)
645{
646 if (objfile != NULL)
647 enable_dec_thread ();
648 else
649 disable_dec_thread ();
650}
651
652static void
653init_dec_thread_ops (void)
654{
655 dec_thread_ops.to_shortname = "dec-threads";
656 dec_thread_ops.to_longname = _("DEC threads support");
657 dec_thread_ops.to_doc = _("DEC threads support");
658 dec_thread_ops.to_detach = dec_thread_detach;
659 dec_thread_ops.to_wait = dec_thread_wait;
660 dec_thread_ops.to_fetch_registers = dec_thread_fetch_registers;
661 dec_thread_ops.to_store_registers = dec_thread_store_registers;
662 dec_thread_ops.to_mourn_inferior = dec_thread_mourn_inferior;
663 dec_thread_ops.to_thread_alive = dec_thread_thread_alive;
664 dec_thread_ops.to_pid_to_str = dec_thread_pid_to_str;
665 dec_thread_ops.to_stratum = thread_stratum;
666 dec_thread_ops.to_magic = OPS_MAGIC;
667}
668
669void
670_initialize_dec_thread (void)
671{
672 init_dec_thread_ops ();
673 add_target (&dec_thread_ops);
674
675 observer_attach_new_objfile (dec_thread_new_objfile_observer);
676
677 add_setshow_boolean_cmd ("dec-thread", class_maintenance, &debug_dec_thread,
678 _("Set debugging of DEC threads module."),
679 _("Show debugging of DEC threads module."),
680 _("Enables debugging output (used to debug GDB)."),
681 NULL, NULL,
682 &setdebuglist, &showdebuglist);
683}
This page took 0.047993 seconds and 4 git commands to generate.