rename amd64 architecture to x86_64
[dragonfly.git] / gnu / usr.bin / gdb / libgdb / freebsd-uthread.c
CommitLineData
b6fca148
JS
1/* Low level interface for debugging FreeBSD user threads for GDB, the GNU debugger.
2 Copyright 1996, 1999 Free Software Foundation, Inc.
3
4This file is part of GDB.
5
6This program is free software; you can redistribute it and/or modify
7it under the terms of the GNU General Public License as published by
8the Free Software Foundation; either version 2 of the License, or
9(at your option) any later version.
10
11This program is distributed in the hope that it will be useful,
12but WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14GNU General Public License for more details.
15
16You should have received a copy of the GNU General Public License
17along with this program; if not, write to the Free Software
18Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
19
20/* $FreeBSD: ports/devel/gdb6/files/freebsd-uthread.c,v 1.2 2004/06/20 18:45:36 obrien Exp $ */
b6fca148
JS
21
22/* This module implements a sort of half target that sits between the
23 machine-independent parts of GDB and the ptrace interface (infptrace.c) to
24 provide access to the FreeBSD user-mode thread implementation.
25
26 FreeBSD threads are true user-mode threads, which are invoked via
27 the pthread_* interfaces. These are mostly implemented in
28 user-space, with all thread context kept in various structures that
29 live in the user's heap. For the most part, the kernel has no
30 knowlege of these threads.
31
32 Based largely on hpux-thread.c
33
34 */
35
36
37#include "defs.h"
38#include <sys/queue.h>
39#include <signal.h>
40#include <setjmp.h>
41#include <string.h>
42#include "gdbthread.h"
43#include "target.h"
44#include "inferior.h"
45#include <fcntl.h>
46#include <ucontext.h>
47#include <unistd.h>
48#include <sys/stat.h>
49#include "gdbcore.h"
50#include "regcache.h"
51
52extern int child_suppress_run;
53extern struct target_ops child_ops; /* target vector for inftarg.c */
54
55extern void _initialize_freebsd_uthread PARAMS ((void));
56
57/* Set to true while we are part-way through attaching */
58static int freebsd_uthread_attaching;
59
60static int freebsd_uthread_active = 0;
61static CORE_ADDR P_thread_list;
62static CORE_ADDR P_thread_run;
af94bd7f 63static CORE_ADDR P_thread_kern_thread;
b6fca148
JS
64
65/* Pointer to the next function on the objfile event chain. */
66static void (*target_new_objfile_chain) (struct objfile *objfile);
67
68static void freebsd_uthread_resume PARAMS ((ptid_t pid, int step,
69 enum target_signal signo));
70
71static void init_freebsd_uthread_ops PARAMS ((void));
72
73static struct target_ops freebsd_uthread_ops;
74\f
75static ptid_t find_active_ptid PARAMS ((void));
76
77struct cached_pthread {
78 u_int64_t uniqueid;
79 int state;
80 CORE_ADDR name;
81 union {
82 ucontext_t uc;
83 jmp_buf jb;
84 } ctx;
85};
86
87static ptid_t cached_ptid;
88static struct cached_pthread cached_pthread;
89static CORE_ADDR cached_pthread_addr;
90
91LIST_HEAD(idmaplist, idmap);
92
93struct idmap {
94 LIST_ENTRY(idmap) link;
95 u_int64_t uniqueid;
96 int tid;
97};
98
99#define MAPHASH_SIZE 257
100#define TID_MIN 1
101#define TID_MAX 16383
102
103static int tid_to_hash[TID_MAX + 1]; /* set to map_hash index */
104static struct idmaplist map_hash[MAPHASH_SIZE];
105static int next_free_tid = TID_MIN; /* first available tid */
106static int last_free_tid = TID_MIN; /* first unavailable */
107
108static CORE_ADDR P_thread_next_offset;
109static CORE_ADDR P_thread_uniqueid_offset;
110static CORE_ADDR P_thread_state_offset;
111static CORE_ADDR P_thread_name_offset;
112static CORE_ADDR P_thread_ctx_offset;
113static CORE_ADDR P_thread_PS_RUNNING_value;
114static CORE_ADDR P_thread_PS_DEAD_value;
115
116static int next_offset;
117static int uniqueid_offset;
118static int state_offset;
119static int name_offset;
120static int ctx_offset;
121static int PS_RUNNING_value;
122static int PS_DEAD_value;
123
124#define UNIQUEID_HASH(id) (id % MAPHASH_SIZE)
125#define TID_ADD1(tid) (((tid) + 1) == TID_MAX + 1 \
126 ? TID_MIN : (tid) + 1)
127#define IS_TID_FREE(tid) (tid_to_hash[tid] == -1)
128
129static int
130get_new_tid(int h)
131{
132 int tid = next_free_tid;
133
134 tid_to_hash[tid] = h;
135 next_free_tid = TID_ADD1(next_free_tid);
136 if (next_free_tid == last_free_tid)
137 {
138 int i;
139
140 for (i = last_free_tid; TID_ADD1(i) != last_free_tid; i = TID_ADD1(i))
141 if (IS_TID_FREE(i))
142 break;
143 if (TID_ADD1(i) == last_free_tid)
144 {
145 error("too many threads");
146 return 0;
147 }
148 next_free_tid = i;
149 for (i = TID_ADD1(i); IS_TID_FREE(i); i = TID_ADD1(i))
150 ;
151 last_free_tid = i;
152 }
153
154 return tid;
155}
156
157static ptid_t
158find_ptid(u_int64_t uniqueid)
159{
160 int h = UNIQUEID_HASH(uniqueid);
161 struct idmap *im;
162
163 LIST_FOREACH(im, &map_hash[h], link)
164 if (im->uniqueid == uniqueid)
165 return MERGEPID(PIDGET(inferior_ptid), im->tid);
166
167 im = xmalloc(sizeof(struct idmap));
168 im->uniqueid = uniqueid;
169 im->tid = get_new_tid(h);
170 LIST_INSERT_HEAD(&map_hash[h], im, link);
171
172 return MERGEPID(PIDGET(inferior_ptid), im->tid);
173}
174
175static void
176free_ptid(ptid_t ptid)
177{
178 int tid = TIDGET(ptid);
179 int h = tid_to_hash[tid];
180 struct idmap *im;
181
182 if (!tid) return;
183
184 LIST_FOREACH(im, &map_hash[h], link)
185 if (im->tid == tid)
186 break;
187
188 if (!im) return;
189
190 LIST_REMOVE(im, link);
191 tid_to_hash[tid] = -1;
192 free(im);
193}
194
195#define READ_OFFSET(field) read_memory(P_thread_##field##_offset, \
196 (char *) &field##_offset, \
197 sizeof(field##_offset))
198
199#define READ_VALUE(name) read_memory(P_thread_##name##_value, \
200 (char *) &name##_value, \
201 sizeof(name##_value))
202
203static void
204read_thread_offsets (void)
205{
206 READ_OFFSET(next);
207 READ_OFFSET(uniqueid);
208 READ_OFFSET(state);
209 READ_OFFSET(name);
210 READ_OFFSET(ctx);
211
212 READ_VALUE(PS_RUNNING);
213 READ_VALUE(PS_DEAD);
214}
215
216#define READ_FIELD(ptr, T, field, result) \
217 read_memory ((ptr) + field##_offset, (char *) &(result), sizeof result)
218
219static u_int64_t
220read_pthread_uniqueid (CORE_ADDR ptr)
221{
222 u_int64_t uniqueid;
223 READ_FIELD(ptr, u_int64_t, uniqueid, uniqueid);
224 return uniqueid;
225}
226
227static CORE_ADDR
228read_pthread_next (CORE_ADDR ptr)
229{
230 CORE_ADDR next;
231 READ_FIELD(ptr, CORE_ADDR, next, next);
232 return next;
233}
234
235static void
236read_cached_pthread (CORE_ADDR ptr, struct cached_pthread *cache)
237{
238 READ_FIELD(ptr, u_int64_t, uniqueid, cache->uniqueid);
239 READ_FIELD(ptr, int, state, cache->state);
240 READ_FIELD(ptr, CORE_ADDR, name, cache->name);
241 READ_FIELD(ptr, ucontext_t, ctx, cache->ctx);
242}
243
244static ptid_t
245find_active_ptid (void)
246{
247 CORE_ADDR ptr;
248
249 read_memory ((CORE_ADDR)P_thread_run,
250 (char *)&ptr,
251 sizeof ptr);
252
253 return find_ptid(read_pthread_uniqueid(ptr));
254}
255
256static CORE_ADDR find_pthread_addr PARAMS ((ptid_t ptid));
257static struct cached_pthread * find_pthread PARAMS ((ptid_t ptid));
258
259static CORE_ADDR
260find_pthread_addr (ptid_t ptid)
261{
262 CORE_ADDR ptr;
263
264 if (ptid_equal(ptid, cached_ptid))
265 return cached_pthread_addr;
266
267 read_memory ((CORE_ADDR)P_thread_list,
268 (char *)&ptr,
269 sizeof ptr);
270
271 while (ptr != 0)
272 {
273 if (ptid_equal(find_ptid(read_pthread_uniqueid(ptr)), ptid))
274 {
275 cached_ptid = ptid;
276 cached_pthread_addr = ptr;
277 read_cached_pthread(ptr, &cached_pthread);
278 return ptr;
279 }
280 ptr = read_pthread_next(ptr);
281 }
282
3641b7ca 283 return 0;
b6fca148
JS
284}
285
286static struct cached_pthread *
287find_pthread (ptid_t ptid)
288{
289 CORE_ADDR ptr;
290
291 if (ptid_equal(ptid, cached_ptid))
292 return &cached_pthread;
293
294 read_memory ((CORE_ADDR)P_thread_list,
295 (char *)&ptr,
296 sizeof ptr);
297
af94bd7f
SS
298 /*
299 * uthreads might not be initialized yet, so we have to use the
300 * kernel thread instead.
301 */
302 if (ptr == 0)
303 ptr = P_thread_kern_thread;
304
b6fca148
JS
305 while (ptr != 0)
306 {
307 if (ptid_equal(find_ptid(read_pthread_uniqueid(ptr)), ptid))
308 {
309 cached_ptid = ptid;
310 cached_pthread_addr = ptr;
311 read_cached_pthread(ptr, &cached_pthread);
312 return &cached_pthread;
313 }
314 ptr = read_pthread_next(ptr);
315 }
316
317#if 0
318 error ("Can't find pthread %d,%d", PIDGET(ptid), TIDGET(ptid));
319#endif
320 return NULL;
321}
322
323\f
324/* Most target vector functions from here on actually just pass through to
325 inftarg.c, as they don't need to do anything specific for threads. */
326
327/* ARGSUSED */
328static void
329freebsd_uthread_open (char *arg, int from_tty)
330{
331 child_ops.to_open (arg, from_tty);
332}
333
334/* Attach to process PID, then initialize for debugging it
335 and wait for the trace-trap that results from attaching. */
336
337static void
338freebsd_uthread_attach (char *args, int from_tty)
339{
340 child_ops.to_attach (args, from_tty);
341 push_target (&freebsd_uthread_ops);
342 freebsd_uthread_attaching = 1;
343}
344
345/* After an attach, see if the target is threaded */
346
347static void
348freebsd_uthread_post_attach (int pid)
349{
350 if (freebsd_uthread_active)
351 {
352 read_thread_offsets ();
353 inferior_ptid = find_active_ptid ();
354 add_thread (inferior_ptid);
355 }
356 else
357 {
358 unpush_target (&freebsd_uthread_ops);
359 push_target (&child_ops);
360 }
361
362 freebsd_uthread_attaching = 0;
363}
364
365/* Take a program previously attached to and detaches it.
366 The program resumes execution and will no longer stop
367 on signals, etc. We'd better not have left any breakpoints
368 in the program or it'll die when it hits one. For this
369 to work, it may be necessary for the process to have been
370 previously attached. It *might* work if the program was
371 started via the normal ptrace (PTRACE_TRACEME). */
372
373static void
374freebsd_uthread_detach (char *args, int from_tty)
375{
376 child_ops.to_detach (args, from_tty);
377}
378
379/* Resume execution of process PID. If STEP is nozero, then
380 just single step it. If SIGNAL is nonzero, restart it with that
381 signal activated. We may have to convert pid from a thread-id to an LWP id
382 for procfs. */
383
384static void
385freebsd_uthread_resume (ptid_t ptid, int step, enum target_signal signo)
386{
387 if (freebsd_uthread_attaching)
388 {
389 child_ops.to_resume (ptid, step, signo);
390 return;
391 }
392
393 child_ops.to_resume (ptid, step, signo);
394 cached_ptid = MERGEPID(0, 0);
395}
396
397/* Wait for any threads to stop. We may have to convert PID from a thread id
398 to a LWP id, and vice versa on the way out. */
399
400static ptid_t
401freebsd_uthread_wait (ptid_t ptid, struct target_waitstatus *ourstatus)
402{
403 ptid_t rtnval;
404
405 if (freebsd_uthread_attaching)
406 {
407 return child_ops.to_wait (ptid, ourstatus);
408 }
409
410 rtnval = child_ops.to_wait (ptid, ourstatus);
411
412 if (PIDGET(rtnval) >= 0)
413 {
414 rtnval = find_active_ptid ();
415 if (!in_thread_list (rtnval))
416 add_thread (rtnval);
417 }
418
419 return rtnval;
420}
421
422/* XXX: this needs to be selected by target, not [build] host */
423#ifdef __i386__
424
425#include "i386-tdep.h"
426
427static char sigmap[I386_SSE_NUM_REGS] = /* map reg to sigcontext */
428{
429 12, /* eax */
430 11, /* ecx */
431 10, /* edx */
432 9, /* ebx */
433 8, /* esp */
434 7, /* ebp */
435 6, /* esi */
436 5, /* edi */
437 15, /* eip */
438 17, /* eflags */
439 16, /* cs */
440 19, /* ss */
441 4, /* ds */
442 3, /* es */
443 2, /* fs */
444 1, /* gs */
445 -1, -1, -1, -1, -1, -1, -1, /* st0-st7 */
446 -1, -1, -1, -1, -1, -1, -1, /* fctrl-fop */
447 -1, -1, -1, -1, -1, -1, -1, /* xmm0-xmm7 */
448 -1, /* mxcsr */
449};
450
451static char jmpmap[I386_SSE_NUM_REGS] = /* map reg to jmp_buf */
452{
453 6, /* eax */
454 -1, /* ecx */
455 -1, /* edx */
456 1, /* ebx */
457 2, /* esp */
458 3, /* ebp */
459 4, /* esi */
460 5, /* edi */
461 0, /* eip */
462 -1, /* eflags */
463 -1, /* cs */
464 -1, /* ss */
465 -1, /* ds */
466 -1, /* es */
467 -1, /* fs */
468 -1, /* gs */
469 -1, -1, -1, -1, -1, -1, -1, /* st0-st7 */
470 -1, -1, -1, -1, -1, -1, -1, /* fctrl-fop */
471 -1, -1, -1, -1, -1, -1, -1, /* xmm0-xmm7 */
472 -1, /* mxcsr */
473};
474
475#endif
476
c1543a89 477#ifdef __x86_64__
b6fca148
JS
478
479#include "amd64-tdep.h"
480
481// XXX:DEO not fully ported from i386 yet!!
482
7cb0c677
SS
483
484#define AMD64_NUM_REGS_TOTAL 57
485
b6fca148
JS
486static char sigmap[AMD64_NUM_REGS_TOTAL] = /* map reg to sigcontext */
487{
7cb0c677
SS
488 7, /* %rax */
489 8, /* %rbx */
490 4, /* %rcx */
491 3, /* %rdx */
492 2, /* %rsi */
493 1, /* %rdi */
494 9, /* %rbp */
495 23, /* %rsp */
496 5, /* %r8 */
497 6, /* %r9 */
498 10, /* %r10 */
499 11, /* %r11 */
500 12, /* %r12 */
501 13, /* %r13 */
502 14, /* %r14 */
503 15, /* %r15 */
504 20, /* %rip */
505 18, /* %eflags */
506 21, 24, -1, -1, -1, -1, /* %cs - %gs */
507 -1, -1, -1, -1, -1 -1, -1, -1,/* %st0 - %st7 */
508 -1, -1, -1, -1, -1 -1, -1, -1,/* %fctrl - %fop */
509 -1, -1, -1, -1, -1 -1, -1, -1,/* %xmm0 - %xmm7 */
510 -1, -1, -1, -1, -1 -1, -1, -1,/* %xmm8 - %xmm15 */
511 -1, /* %mxcsr */
b6fca148
JS
512};
513
514static char jmpmap[AMD64_NUM_REGS_TOTAL] = /* map reg to jmp_buf */
515{
7cb0c677
SS
516 -1, /* %rax */
517 1, /* %rbx */
518 -1, /* %rcx */
519 -1, /* %rdx */
520 -1, /* %rsi */
521 -1, /* %rdi */
522 3, /* %rbp */
523 2, /* %rsp */
524 -1, /* %r8 */
525 -1, /* %r9 */
526 -1, /* %r10 */
527 -1, /* %r11 */
528 4, /* %r12 */
529 5, /* %r13 */
530 6, /* %r14 */
531 7, /* %r15 */
532 0, /* %rip */
533 -1, /* %eflags */
534 -1, -1, -1, -1, -1, -1, /* %cs - %gs */
535 -1, -1, -1, -1, -1 -1, -1, -1,/* %st0 - %st7 */
536 -1, -1, -1, -1, -1 -1, -1, -1,/* %fctrl - %fop */
537 -1, -1, -1, -1, -1 -1, -1, -1,/* %xmm0 - %xmm7 */
538 -1, -1, -1, -1, -1 -1, -1, -1,/* %xmm8 - %xmm15 */
539 -1, /* %mxcsr */
b6fca148
JS
540};
541
542#endif
543
544#ifdef __alpha__
545
546#include "alpha-tdep.h"
547
548static char sigmap[ALPHA_NUM_REGS] = /* map reg to sigcontext */
549{
550 1, 2, 3, 4, 5, 6, 7, 8, /* v0 - t6 */
551 9, 10, 11, 12, 13, 14, 15, 16, /* t7 - fp */
552 17, 18, 19, 20, 21, 22, 23, 24, /* a0 - t9 */
553 25, 26, 27, 28, 29, 30, 31, 32, /* t10 - zero */
554 38, 39, 40, 41, 42, 43, 44, 45, /* f0 - f7 */
555 46, 47, 48, 49, 50, 51, 52, 53, /* f8 - f15 */
556 54, 55, 56, 57, 58, 59, 60, 61, /* f16 - f23 */
557 62, 63, 64, 65, 66, 67, 68, 69, /* f24 - f31 */
558 33, -1 /* pc, vfp */
559};
560static char jmpmap[ALPHA_NUM_REGS] = {
561 4, 5, 6, 7, 8, 9, 10, 11, /* v0 - t6 */
562 12, 13, 14, 15, 16, 17, 18, 19, /* t7 - fp */
563 20, 21, 22, 23, 24, 25, 26, 27, /* a0 - t9 */
564 28, 29, 30, 31, 32, 33, 34, 35, /* t10 - zero */
565 37, 38, 39, 40, 41, 42, 43, 44, /* f0 - f7 */
566 45, 46, 47, 48, 49, 50, 51, 52, /* f8 - f15 */
567 53, 54, 55, 56, 57, 58, 59, 60, /* f16 - f23 */
568 61, 62, 63, 64, 65, 66, 67, 68, /* f24 - f31 */
569 2, -1, /* pc, vfp */
570};
571
572#endif
573
574#ifdef __sparc64__
575
576static char sigmap[125] = /* map reg to sigcontext */
577{
578 -1
579};
580static char jmpmap[125] = {
581 -1
582};
583
584#endif
585
586static void
587freebsd_uthread_fetch_registers (int regno)
588{
589 struct cached_pthread *thread;
590 int active;
591 int first_regno, last_regno;
592 register_t *regbase;
593 char *regmap;
594
595 if (freebsd_uthread_attaching || TIDGET(inferior_ptid) == 0)
596 {
597 child_ops.to_fetch_registers (regno);
598 return;
599 }
600
601 thread = find_pthread (inferior_ptid);
602 active = (ptid_equal(inferior_ptid, find_active_ptid()));
603
604 if (active)
605 {
606 child_ops.to_fetch_registers (regno);
607 return;
608 }
609
610 if (regno == -1)
611 {
612 first_regno = 0;
613 last_regno = NUM_REGS - 1;
614 }
615 else
616 {
617 first_regno = regno;
618 last_regno = regno;
619 }
620
621 regbase = (register_t*) &thread->ctx.jb[0];
622 regmap = jmpmap;
623
624 for (regno = first_regno; regno <= last_regno; regno++)
625 {
626 if (regmap[regno] == -1)
627 child_ops.to_fetch_registers (regno);
628 else
629 if (thread)
630 supply_register (regno, (char*) &regbase[regmap[regno]]);
631 else
632 supply_register (regno, NULL);
633 }
634}
635
636static void
637freebsd_uthread_store_registers (int regno)
638{
639 struct cached_pthread *thread;
640 CORE_ADDR ptr;
641 int first_regno, last_regno;
642 u_int32_t *regbase;
643 char *regmap;
644
645 if (freebsd_uthread_attaching)
646 {
647 child_ops.to_store_registers (regno);
648 return;
649 }
650
651 thread = find_pthread (inferior_ptid);
652
653 if (thread->state == PS_RUNNING_value)
654 {
655 child_ops.to_store_registers (regno);
656 return;
657 }
658
659 if (regno == -1)
660 {
661 first_regno = 0;
662 last_regno = NUM_REGS - 1;
663 }
664 else
665 {
666 first_regno = regno;
667 last_regno = regno;
668 }
669
670 regbase = (u_int32_t*) &thread->ctx.jb[0];
671 regmap = jmpmap;
672
673 ptr = find_pthread_addr (inferior_ptid);
674 for (regno = first_regno; regno <= last_regno; regno++)
675 {
676 if (regmap[regno] == -1)
677 child_ops.to_store_registers (regno);
678 else
679 {
680 u_int32_t *reg = &regbase[regmap[regno]];
681 int off;
682
683 /* Hang onto cached value */
684/*DEO:XXX*/
685 memcpy(reg, deprecated_registers /*regcache_collect ()*/+ DEPRECATED_REGISTER_BYTE (regno),
686 DEPRECATED_REGISTER_RAW_SIZE (regno));
687
688 /* And push out to inferior */
689 off = (char *) reg - (char *) thread;
690 write_memory (ptr + off,
691/*DEO:XXX*/
692 deprecated_registers /*regcache_collect ()*/+ DEPRECATED_REGISTER_BYTE (regno),
693 DEPRECATED_REGISTER_RAW_SIZE (regno));
694 }
695 }
696}
697
698/* Get ready to modify the registers array. On machines which store
699 individual registers, this doesn't need to do anything. On machines
700 which store all the registers in one fell swoop, this makes sure
701 that registers contains all the registers from the program being
702 debugged. */
703
704static void
705freebsd_uthread_prepare_to_store (void)
706{
707 child_ops.to_prepare_to_store ();
708}
709
710static int
711freebsd_uthread_xfer_memory (CORE_ADDR memaddr, char *myaddr, int len,
712 int dowrite, struct mem_attrib *attrib,
713 struct target_ops *target)
714{
715 return child_ops.to_xfer_memory (memaddr, myaddr, len, dowrite,
716 attrib, target);
717}
718
719/* Print status information about what we're accessing. */
720
721static void
722freebsd_uthread_files_info (struct target_ops *ignore)
723{
724 child_ops.to_files_info (ignore);
725}
726
727static void
728freebsd_uthread_kill_inferior (void)
729{
730 child_ops.to_kill ();
731}
732
733static void
734freebsd_uthread_notice_signals (ptid_t ptid)
735{
736 child_ops.to_notice_signals (ptid);
737}
738
739/* Fork an inferior process, and start debugging it with /proc. */
740
741static void
742freebsd_uthread_create_inferior (char *exec_file, char *allargs, char **env,
743 int from_tty)
744{
745 child_ops.to_create_inferior (exec_file, allargs, env, from_tty);
746
747 if (PIDGET(inferior_ptid) && freebsd_uthread_active)
748 {
749 read_thread_offsets ();
750 push_target (&freebsd_uthread_ops);
751 inferior_ptid = find_active_ptid ();
752 add_thread (inferior_ptid);
753 }
754}
755
756/* This routine is called to find out if the inferior is using threads.
757 We check for the _thread_run and _thread_list globals. */
758
759void
760freebsd_uthread_new_objfile (struct objfile *objfile)
761{
762 struct minimal_symbol *ms;
763
764 if (!objfile)
765 {
766 freebsd_uthread_active = 0;
767 return;
768 }
769
770 ms = lookup_minimal_symbol ("_thread_run", NULL, objfile);
771
772 if (!ms)
773 return;
774
775 P_thread_run = SYMBOL_VALUE_ADDRESS (ms);
776
777 ms = lookup_minimal_symbol ("_thread_list", NULL, objfile);
778
779 if (!ms)
780 return;
781
782 P_thread_list = SYMBOL_VALUE_ADDRESS (ms);
783
af94bd7f
SS
784 ms = lookup_minimal_symbol ("_thread_kern_thread", NULL, objfile);
785
786 if (!ms)
787 return;
788
789 P_thread_kern_thread = SYMBOL_VALUE_ADDRESS (ms);
790
b6fca148
JS
791#define OFFSET_SYM(field) "_thread_" #field "_offset"
792#define LOOKUP_OFFSET(field) \
793 do { \
794 ms = lookup_minimal_symbol (OFFSET_SYM(field), NULL, objfile); \
795 if (!ms) \
796 return; \
797 P_thread_##field##_offset = SYMBOL_VALUE_ADDRESS (ms); \
798 } while (0);
799
800#define VALUE_SYM(name) "_thread_" #name "_value"
801#define LOOKUP_VALUE(name) \
802 do { \
803 ms = lookup_minimal_symbol (VALUE_SYM(name), NULL, objfile); \
804 if (!ms) \
805 return; \
806 P_thread_##name##_value = SYMBOL_VALUE_ADDRESS (ms); \
807 } while (0);
808
809 LOOKUP_OFFSET(next);
810 LOOKUP_OFFSET(uniqueid);
811 LOOKUP_OFFSET(state);
812 LOOKUP_OFFSET(name);
813 LOOKUP_OFFSET(ctx);
814
815 LOOKUP_VALUE(PS_RUNNING);
816 LOOKUP_VALUE(PS_DEAD);
817
818 freebsd_uthread_active = 1;
819}
820
821/* Clean up after the inferior dies. */
822
823static void
824freebsd_uthread_mourn_inferior ()
825{
826 child_ops.to_mourn_inferior ();
827 unpush_target (&freebsd_uthread_ops);
828}
829
830/* Mark our target-struct as eligible for stray "run" and "attach" commands. */
831
832static int
833freebsd_uthread_can_run ()
834{
835 return child_suppress_run;
836}
837
838static int
839freebsd_uthread_thread_alive (ptid_t ptid)
840{
841 struct cached_pthread *thread;
842 int ret = 0;
843
844 if (freebsd_uthread_attaching)
845 return 1;
846
847 /*
848 * We can get called from child_ops.to_wait() which passes the underlying
849 * pid (without a thread number).
850 */
851 if (TIDGET(ptid) == 0)
852 return 1;
853
854 if (find_pthread_addr (ptid) != 0)
855 {
856 thread = find_pthread (ptid);
857 ret = (thread->state != PS_DEAD_value);
858 }
859
860 if (!ret)
861 free_ptid(ptid);
862
863 return ret;
864}
865
866static void
867freebsd_uthread_stop (void)
868{
869 child_ops.to_stop ();
870}
871
872static void
873freebsd_uthread_find_new_threads (void)
874{
875 CORE_ADDR ptr;
876 int state;
877 u_int64_t uniqueid;
878
879 read_memory ((CORE_ADDR)P_thread_list,
880 (char *)&ptr,
881 sizeof ptr);
882
883 while (ptr != 0)
884 {
885 READ_FIELD(ptr, int, state, state);
886 READ_FIELD(ptr, u_int64_t, uniqueid, uniqueid);
887 if (state != PS_DEAD_value &&
888 !in_thread_list (find_ptid(uniqueid)))
889 add_thread (find_ptid(uniqueid));
890 ptr = read_pthread_next(ptr);
891 }
892}
893
894/* MUST MATCH enum pthread_state */
895static const char *statenames[] = {
896 "RUNNING",
897 "SIGTHREAD",
898 "MUTEX_WAIT",
899 "COND_WAIT",
900 "FDLR_WAIT",
901 "FDLW_WAIT",
902 "FDR_WAIT",
903 "FDW_WAIT",
904 "POLL_WAIT",
905 "FILE_WAIT",
906 "SELECT_WAIT",
907 "SLEEP_WAIT",
908 "WAIT_WAIT",
909 "SIGSUSPEND",
910 "SIGWAIT",
911 "SPINBLOCK",
912 "JOIN",
913 "SUSPENDED",
914 "DEAD",
915 "DEADLOCK",
916};
917
918#if 0
919
920static int
921freebsd_uthread_get_thread_info (ref, selection, info)
922 gdb_threadref *ref;
923 int selection;
924 struct gdb_ext_thread_info *info;
925{
926 int pid = *ref;
927 struct cached_pthread *thread = find_pthread (pid);
928 struct cleanup *old_chain;
929
930 old_chain = save_inferior_pid ();
931 inferior_pid = main_pid;
932
933 memset(&info->threadid, 0, OPAQUETHREADBYTES);
934
935 memcpy(&info->threadid, ref, sizeof *ref);
936 info->active = thread->state == PS_RUNNING_value;
937 strcpy(info->display, statenames[thread->state]);
938 if (thread->name)
939 read_memory ((CORE_ADDR) thread->name, info->shortname, 32);
940 else
941 strcpy(info->shortname, "");
942
943 do_cleanups (old_chain);
944 return (0);
945}
946
947#endif
948
949char *
950freebsd_uthread_pid_to_str (ptid_t ptid)
951{
952 static char buf[30];
953
954 if (DEPRECATED_STREQ (current_target.to_shortname, "freebsd-uthreads"))
955 sprintf (buf, "Process %d, Thread %ld",
956 PIDGET(ptid), TIDGET(ptid));
957 else
958 sprintf (buf, "Process %d", PIDGET(ptid));
959
960 return buf;
961}
962
963\f
964static void
965init_freebsd_uthread_ops ()
966{
967 freebsd_uthread_ops.to_shortname = "freebsd-uthreads";
968 freebsd_uthread_ops.to_longname = "FreeBSD uthreads";
969 freebsd_uthread_ops.to_doc = "FreeBSD user threads support.";
970 freebsd_uthread_ops.to_open = freebsd_uthread_open;
971 freebsd_uthread_ops.to_attach = freebsd_uthread_attach;
972 freebsd_uthread_ops.to_post_attach = freebsd_uthread_post_attach;
973 freebsd_uthread_ops.to_detach = freebsd_uthread_detach;
974 freebsd_uthread_ops.to_resume = freebsd_uthread_resume;
975 freebsd_uthread_ops.to_wait = freebsd_uthread_wait;
976 freebsd_uthread_ops.to_fetch_registers = freebsd_uthread_fetch_registers;
977 freebsd_uthread_ops.to_store_registers = freebsd_uthread_store_registers;
978 freebsd_uthread_ops.to_prepare_to_store = freebsd_uthread_prepare_to_store;
979 freebsd_uthread_ops.to_xfer_memory = freebsd_uthread_xfer_memory;
980 freebsd_uthread_ops.to_files_info = freebsd_uthread_files_info;
981 freebsd_uthread_ops.to_insert_breakpoint = memory_insert_breakpoint;
982 freebsd_uthread_ops.to_remove_breakpoint = memory_remove_breakpoint;
983 freebsd_uthread_ops.to_terminal_init = terminal_init_inferior;
984 freebsd_uthread_ops.to_terminal_inferior = terminal_inferior;
985 freebsd_uthread_ops.to_terminal_ours_for_output = terminal_ours_for_output;
986 freebsd_uthread_ops.to_terminal_ours = terminal_ours;
987 freebsd_uthread_ops.to_terminal_info = child_terminal_info;
988 freebsd_uthread_ops.to_kill = freebsd_uthread_kill_inferior;
989 freebsd_uthread_ops.to_create_inferior = freebsd_uthread_create_inferior;
990 freebsd_uthread_ops.to_mourn_inferior = freebsd_uthread_mourn_inferior;
991 freebsd_uthread_ops.to_can_run = freebsd_uthread_can_run;
992 freebsd_uthread_ops.to_notice_signals = freebsd_uthread_notice_signals;
993 freebsd_uthread_ops.to_thread_alive = freebsd_uthread_thread_alive;
994 freebsd_uthread_ops.to_stop = freebsd_uthread_stop;
995 freebsd_uthread_ops.to_stratum = process_stratum;
996 freebsd_uthread_ops.to_has_all_memory = 1;
997 freebsd_uthread_ops.to_has_memory = 1;
998 freebsd_uthread_ops.to_has_stack = 1;
999 freebsd_uthread_ops.to_has_registers = 1;
1000 freebsd_uthread_ops.to_has_execution = 1;
1001 freebsd_uthread_ops.to_has_thread_control = 0;
1002 freebsd_uthread_ops.to_magic = OPS_MAGIC;
1003 freebsd_uthread_ops.to_find_new_threads = freebsd_uthread_find_new_threads;
1004 freebsd_uthread_ops.to_pid_to_str = freebsd_uthread_pid_to_str;
1005#if 0
1006 freebsd_uthread_vec.get_thread_info = freebsd_uthread_get_thread_info;
1007#endif
1008}
1009
1010void
1011_initialize_freebsd_uthread ()
1012{
1013 init_freebsd_uthread_ops ();
1014 add_target (&freebsd_uthread_ops);
1015
1016 target_new_objfile_chain = deprecated_target_new_objfile_hook;
1017 deprecated_target_new_objfile_hook = freebsd_uthread_new_objfile;
1018
1019 child_suppress_run = 1;
1020}