Annotation of src/lib/libpthread_dbg/pthread_dbg.c, Revision 1.5
1.5 ! lukem 1: /* $NetBSD: pthread_dbg.c,v 1.4 2003/02/27 00:54:07 nathanw Exp $ */
1.2 thorpej 2:
3: /*-
4: * Copyright (c) 2002 Wasabi Systems, Inc.
5: * All rights reserved.
6: *
7: * Written by Nathan J. Williams for Wasabi Systems, Inc.
8: *
9: * Redistribution and use in source and binary forms, with or without
10: * modification, are permitted provided that the following conditions
11: * are met:
12: * 1. Redistributions of source code must retain the above copyright
13: * notice, this list of conditions and the following disclaimer.
14: * 2. Redistributions in binary form must reproduce the above copyright
15: * notice, this list of conditions and the following disclaimer in the
16: * documentation and/or other materials provided with the distribution.
17: * 3. All advertising materials mentioning features or use of this software
18: * must display the following acknowledgement:
19: * This product includes software developed for the NetBSD Project by
20: * Wasabi Systems, Inc.
21: * 4. The name of Wasabi Systems, Inc. may not be used to endorse
22: * or promote products derived from this software without specific
23: * prior written permission.
24: *
25: * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND
26: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
27: * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
28: * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC
29: * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
30: * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
31: * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
32: * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
33: * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
34: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
35: * POSSIBILITY OF SUCH DAMAGE.
36: */
1.5 ! lukem 37:
! 38: #include <sys/cdefs.h>
! 39: __RCSID("$NetBSD$");
1.2 thorpej 40:
41: #include <stddef.h>
42: #include <stdlib.h>
43: #include <string.h>
44: #include <errno.h>
45: #include <sys/types.h>
46: #include <unistd.h>
47:
48: #include <pthread.h>
49: #include <pthread_int.h>
50: #include <pthread_dbg.h>
51: #include <pthread_dbg_int.h>
52: #include <machine/reg.h>
53:
1.4 nathanw 54: #define MIN(a,b) ((a)<(b) ? (a) : (b))
55:
1.2 thorpej 56: static int td__getthread(td_proc_t *proc, caddr_t addr, td_thread_t **threadp);
57: static int td__getsync(td_proc_t *proc, caddr_t addr, td_sync_t **syncp);
58:
59: int
60: td_open(struct td_proc_callbacks_t *cb, void *arg, td_proc_t **procp)
61: {
62: td_proc_t *proc;
63: caddr_t dbgaddr;
64: int dbg;
65: int val;
66:
67: proc = malloc(sizeof(*proc));
68: if (proc == NULL)
69: return TD_ERR_NOMEM;
70:
71: proc->cb = cb;
72: proc->arg = arg;
73:
74: val = LOOKUP(proc, "pthread__dbg", &dbgaddr);
75: if (val != 0) {
76: if (val == TD_ERR_NOSYM)
77: val = TD_ERR_NOLIB;
78: goto error;
79: }
80:
81: val = READ(proc, dbgaddr, &dbg, sizeof(int));
82: if (val != 0)
83: goto error;
84:
85: if (dbg != 0) {
86: /* Another instance of libpthread_dbg is already attached. */
87: val = TD_ERR_INUSE;
88: goto error;
89: }
90:
91: dbg = getpid();
92: /*
93: * If this fails it probably means we're debugging a core file and
94: * can't write to it.
95: * If it's something else we'll lose the next time we hit WRITE,
96: * but not before, and that's OK.
97: */
98: WRITE(proc, dbgaddr, &dbg, sizeof(int));
99:
100: proc->allqueue = 0;
101: PTQ_INIT(&proc->threads);
102: PTQ_INIT(&proc->syncs);
103:
104: *procp = proc;
105:
106: return 0;
107:
108: error:
109: free(proc);
110: return val;
111: }
112:
113: int
114: td_close(td_proc_t *proc)
115: {
116: caddr_t dbgaddr;
117: int dbg;
118: int val;
119: td_thread_t *t, *next;
120: td_sync_t *s, *nexts;
121:
122: val = LOOKUP(proc, "pthread__dbg", &dbgaddr);
123: if (val != 0)
124: return val;
125:
126: dbg = 0;
127: /*
128: * Error returns from this write are mot really a problem;
129: * the process doesn't exist any more.
130: */
131: WRITE(proc, dbgaddr, &dbg, sizeof(int));
132:
133: /* Deallocate the list of thread structures */
134: for (t = PTQ_FIRST(&proc->threads); t; t = next) {
135: next = PTQ_NEXT(t, list);
136: PTQ_REMOVE(&proc->threads, t, list);
137: free(t);
138: }
139: /* Deallocate the list of sync objects */
140: for (s = PTQ_FIRST(&proc->syncs); s; s = nexts) {
141: nexts = PTQ_NEXT(s, list);
142: PTQ_REMOVE(&proc->syncs, s, list);
143: free(s);
144: }
145: free(proc);
146: return 0;
147: }
148:
149:
150: int
151: td_thr_iter(td_proc_t *proc, int (*call)(td_thread_t *, void *), void *callarg)
152: {
153: int val;
154: caddr_t allqaddr, next;
155: struct pthread_queue_t allq;
156: td_thread_t *thread;
157:
158: if (proc->allqueue == 0) {
159: val = LOOKUP(proc, "pthread__allqueue", &allqaddr);
160: if (val != 0)
161: return val;
162: proc->allqueue = allqaddr;
163: } else {
164: allqaddr = proc->allqueue;
165: }
166:
167: val = READ(proc, allqaddr, &allq, sizeof(allq));
168: if (val != 0)
169: return val;
170:
1.3 christos 171: next = (void *)allq.ptqh_first;
172: while (next != NULL) {
1.2 thorpej 173: val = td__getthread(proc, next, &thread);
174: if (val != 0)
175: return val;
176: val = (*call)(thread, callarg);
177: if (val != 0)
178: return 0;
179:
180: val = READ(proc,
181: next + offsetof(struct pthread_st, pt_allq.ptqe_next),
182: &next, sizeof(next));
183: if (val != 0)
184: return val;
185: }
186: return 0;
187: }
188:
189: int
190: td_thr_info(td_thread_t *thread, td_thread_info_t *info)
191: {
192: int val, tmp;
193: struct pthread_queue_t queue;
194:
195: val = READ(thread->proc, thread->addr, &tmp, sizeof(tmp));
196: if (val != 0)
197: return val;
198:
199: if (tmp != PT_MAGIC)
200: return TD_ERR_BADTHREAD;
201:
202: info->thread_addr = thread->addr;
203: if ((val = READ(thread->proc,
204: thread->addr + offsetof(struct pthread_st, pt_state),
205: &tmp, sizeof(int))) != 0)
206: return val;
207: switch (tmp) {
208: case PT_STATE_RUNNING:
209: info->thread_state = TD_STATE_RUNNING;
210: break;
211: case PT_STATE_RUNNABLE:
212: info->thread_state = TD_STATE_RUNNABLE;
213: break;
214: case PT_STATE_BLOCKED_SYS:
215: info->thread_state = TD_STATE_BLOCKED;
216: break;
217: case PT_STATE_BLOCKED_QUEUE:
218: info->thread_state = TD_STATE_SLEEPING;
219: break;
220: case PT_STATE_ZOMBIE:
221: info->thread_state = TD_STATE_ZOMBIE;
222: break;
223: default:
224: info->thread_state = TD_STATE_UNKNOWN;
225: }
226:
227: if ((val = READ(thread->proc,
228: thread->addr + offsetof(struct pthread_st, pt_type),
229: &tmp, sizeof(int))) != 0)
230: return val;
231: switch (tmp) {
232: case PT_THREAD_NORMAL:
233: info->thread_type = TD_TYPE_USER;
234: break;
235: case PT_THREAD_UPCALL:
236: case PT_THREAD_IDLE:
237: info->thread_type = TD_TYPE_SYSTEM;
238: break;
239: default:
240: info->thread_type = TD_TYPE_UNKNOWN;
241: }
242:
243: if ((val = READ(thread->proc,
244: thread->addr + offsetof(struct pthread_st, pt_stack),
245: &info->thread_stack, sizeof(stack_t))) != 0)
246: return val;
247:
248: if ((val = READ(thread->proc,
249: thread->addr + offsetof(struct pthread_st, pt_joiners),
250: &queue, sizeof(struct pthread_queue_t))) != 0)
251: return val;
252:
253: if (PTQ_EMPTY(&queue))
254: info->thread_hasjoiners = 0;
255: else
256: info->thread_hasjoiners = 1;
257:
258: if ((val = READ(thread->proc,
259: thread->addr + offsetof(struct pthread_st, pt_errno),
260: &info->thread_errno, sizeof(info->thread_errno))) != 0)
261: return val;
262:
263: if ((val = READ(thread->proc,
264: thread->addr + offsetof(struct pthread_st, pt_num),
265: &info->thread_id, sizeof(info->thread_errno))) != 0)
266: return val;
267:
268: if ((val = READ(thread->proc,
269: thread->addr + offsetof(struct pthread_st, pt_sigmask),
270: &info->thread_sigmask, sizeof(info->thread_sigmask))) != 0)
271: return val;
272:
273: if ((val = READ(thread->proc,
274: thread->addr + offsetof(struct pthread_st, pt_siglist),
275: &info->thread_sigpending, sizeof(info->thread_sigpending))) != 0)
276: return val;
277:
278: return 0;
279: }
280:
281: int
1.4 nathanw 282: td_thr_getname(td_thread_t *thread, char *name, int len)
283: {
284: int val, tmp;
285: caddr_t nameaddr;
286:
287:
288: val = READ(thread->proc, thread->addr, &tmp, sizeof(tmp));
289: if (val != 0)
290: return val;
291:
292: if (tmp != PT_MAGIC)
293: return TD_ERR_BADTHREAD;
294:
295: if ((val = READ(thread->proc,
296: thread->addr + offsetof(struct pthread_st, pt_name),
297: &nameaddr, sizeof(nameaddr))) != 0)
298: return val;
299:
300: if (nameaddr == 0)
301: name[0] = '\0';
302: else if ((val = READ(thread->proc, nameaddr,
303: name, MIN(PTHREAD_MAX_NAMELEN_NP, len))) != 0)
304: return val;
305:
306: return 0;
307: }
308:
309: int
1.2 thorpej 310: td_thr_getregs(td_thread_t *thread, int regset, void *buf)
311: {
312: int tmp, val;
313: caddr_t addr;
314: ucontext_t uc;
315:
316: val = READ(thread->proc,
317: thread->addr + offsetof(struct pthread_st, pt_state),
318: &tmp, sizeof(int));
319: if (val != 0)
320: return val;
321:
322: switch (tmp) {
323: case PT_STATE_RUNNING:
324: /*
325: * The register state of the thread is live in the
326: * inferior process's register state.
327: */
328: val = GETREGS(thread->proc, regset, thread->lwp, buf);
329: if (val != 0)
330: return val;
331: break;
332: case PT_STATE_RUNNABLE:
333: case PT_STATE_BLOCKED_SYS:
334: case PT_STATE_BLOCKED_QUEUE:
335: /*
336: * The register state of the thread is in the ucontext_t
337: * of the thread structure.
338: */
339: val = READ(thread->proc,
340: thread->addr + offsetof(struct pthread_st, pt_uc),
341: &addr, sizeof(addr));
342: if (val != 0)
343: return val;
344: val = READ(thread->proc,
345: addr, &uc, sizeof(uc));
346: if (val != 0)
347: return val;
348:
349: switch (regset) {
350: case 0:
351: PTHREAD_UCONTEXT_TO_REG((struct reg *)buf, &uc);
352: break;
353: case 1:
354: PTHREAD_UCONTEXT_TO_FPREG((struct fpreg *)buf, &uc);
355: break;
356: case 2:
357: return TD_ERR_INVAL;
358: }
359: break;
360: case PT_STATE_ZOMBIE:
361: default:
362: return TD_ERR_BADTHREAD;
363: }
364:
365: return 0;
366: }
367:
368: int
369: td_thr_setregs(td_thread_t *thread, int regset, void *buf)
370: {
371:
372: int tmp, val;
373: caddr_t addr;
374: ucontext_t uc;
375:
376: val = READ(thread->proc,
377: thread->addr + offsetof(struct pthread_st, pt_state),
378: &tmp, sizeof(int));
379: if (val != 0)
380: return val;
381:
382: switch (tmp) {
383: case PT_STATE_RUNNING:
384: /*
385: * The register state of the thread is live in the
386: * inferior process's register state.
387: */
388: val = SETREGS(thread->proc, regset, thread->lwp, buf);
389: if (val != 0)
390: return val;
391: break;
392: case PT_STATE_RUNNABLE:
393: case PT_STATE_BLOCKED_SYS:
394: case PT_STATE_BLOCKED_QUEUE:
395: /*
396: * The register state of the thread is in the ucontext_t
397: * of the thread structure.
398: *
399: * Fetch the uc first, since there is state in it
400: * besides the registers that should be preserved.
401: */
402: val = READ(thread->proc,
403: thread->addr + offsetof(struct pthread_st, pt_uc),
404: &addr, sizeof(addr));
405: if (val != 0)
406: return val;
407: val = READ(thread->proc,
408: addr, &uc, sizeof(uc));
409: if (val != 0)
410: return val;
411:
412: switch (regset) {
413: case 0:
1.3 christos 414: PTHREAD_REG_TO_UCONTEXT(&uc,
415: (struct reg *)(void *)buf);
1.2 thorpej 416: break;
417: case 1:
1.3 christos 418: PTHREAD_FPREG_TO_UCONTEXT(&uc,
419: (struct fpreg *)(void *)buf);
1.2 thorpej 420: break;
421: case 2:
422: return TD_ERR_INVAL;
423: }
424:
425: val = WRITE(thread->proc,
426: addr, &uc, sizeof(uc));
427: if (val != 0)
428: return val;
429:
430: break;
431: case PT_STATE_ZOMBIE:
432: default:
433: return TD_ERR_BADTHREAD;
434: }
435:
436: return 0;
437: }
438:
439: int
440: td_thr_join_iter(td_thread_t *thread, int (*call)(td_thread_t *, void *),
441: void *arg)
442: {
443: int val;
444: caddr_t next;
445: td_thread_t *thread2;
446: struct pthread_queue_t queue;
447:
448: if ((val = READ(thread->proc,
449: thread->addr + offsetof(struct pthread_st, pt_joiners),
450: &queue, sizeof(struct pthread_queue_t))) != 0)
451: return val;
452:
1.3 christos 453: next = (void *)queue.ptqh_first;
454: while (next != NULL) {
1.2 thorpej 455: val = td__getthread(thread->proc, next, &thread2);
456: if (val != 0)
457: return val;
1.4 nathanw 458: val = (*call)(thread2, arg);
1.2 thorpej 459: if (val != 0)
460: return 0;
461:
462: val = READ(thread->proc,
463: next + offsetof(struct pthread_st, pt_sleep.ptqe_next),
464: &next, sizeof(next));
465: if (val != 0)
466: return val;
467: }
468:
469: return 0;
470: }
471:
472: int
473: td_sync_info(td_sync_t *s, td_sync_info_t *info)
474: {
475: int val, magic, n;
476: struct pthread_queue_t queue;
477: pthread_spin_t slock;
478: pthread_t taddr;
479:
480: val = READ(s->proc, s->addr, &magic, sizeof(magic));
481: if (val != 0)
482: return val;
483:
484: info->sync_type = TD_SYNC_UNKNOWN;
485: info->sync_size = 0;
486: info->sync_haswaiters = 0;
487: switch (magic) {
488: case _PT_MUTEX_MAGIC:
489: info->sync_type = TD_SYNC_MUTEX;
490: info->sync_size = sizeof(struct pthread_mutex_st);
491: if ((val = READ(s->proc,
492: s->addr + offsetof(struct pthread_mutex_st, ptm_blocked),
493: &queue, sizeof(struct pthread_queue_t))) != 0)
494: return val;
495:
496: if (!PTQ_EMPTY(&queue))
497: info->sync_haswaiters = 1;
498: /*
499: * The cast to (void *) is to explicitly throw away the
500: * volatile qualifier on pthread_spin_t,
501: * from __cpu_simple_lock_t.
502: */
503: if ((val = READ(s->proc,
504: s->addr + offsetof(struct pthread_mutex_st, ptm_lock),
505: (void *)&slock, sizeof(struct pthread_spinlock_st))) != 0)
506: return val;
507: if (slock == __SIMPLELOCK_LOCKED) {
508: info->sync_data.mutex.locked = 1;
509: if ((val = READ(s->proc,
510: s->addr + offsetof(struct pthread_mutex_st,
511: ptm_owner),
512: &taddr, sizeof(pthread_t))) != 0)
513: return val;
514: taddr = pthread__id(taddr);
1.3 christos 515: td__getthread(s->proc, (void *)taddr,
1.2 thorpej 516: &info->sync_data.mutex.owner);
517: } else
518: info->sync_data.mutex.locked = 0;
519: break;
520: case _PT_COND_MAGIC:
521: info->sync_type = TD_SYNC_COND;
522: info->sync_size = sizeof(struct pthread_cond_st);
523: if ((val = READ(s->proc,
524: s->addr + offsetof(struct pthread_cond_st, ptc_waiters),
525: &queue, sizeof(struct pthread_queue_t))) != 0)
526: return val;
527: if (!PTQ_EMPTY(&queue))
528: info->sync_haswaiters = 1;
529: break;
530: case _PT_SPINLOCK_MAGIC:
531: info->sync_type = TD_SYNC_SPIN;
532: info->sync_size = sizeof(struct pthread_spinlock_st);
533: if ((val = READ(s->proc,
534: s->addr + offsetof(struct pthread_spinlock_st, pts_spin),
535: (void *)&slock, sizeof(struct pthread_spinlock_st))) != 0)
536: return val;
537: if (slock == __SIMPLELOCK_LOCKED)
538: info->sync_data.spin.locked = 1;
539: break;
540: case PT_MAGIC:
541: info->sync_type = TD_SYNC_JOIN;
542: info->sync_size = sizeof(struct pthread_st);
543: td__getthread(s->proc, s->addr,
544: &info->sync_data.join.thread);
545: if ((val = READ(s->proc,
546: s->addr + offsetof(struct pthread_st, pt_joiners),
547: &queue, sizeof(struct pthread_queue_t))) != 0)
548: return val;
549:
550: if (!PTQ_EMPTY(&queue))
551: info->sync_haswaiters = 1;
552: break;
1.3 christos 553: case (int)_PT_RWLOCK_MAGIC:
1.2 thorpej 554: info->sync_type = TD_SYNC_RWLOCK;
555: info->sync_size = sizeof(struct pthread_rwlock_st);
556: if ((val = READ(s->proc,
557: s->addr + offsetof(struct pthread_rwlock_st, ptr_rblocked),
558: &queue, sizeof(struct pthread_queue_t))) != 0)
559: return val;
560: if (!PTQ_EMPTY(&queue))
561: info->sync_haswaiters = 1;
562:
563: if ((val = READ(s->proc,
564: s->addr + offsetof(struct pthread_rwlock_st, ptr_wblocked),
565: &queue, sizeof(struct pthread_queue_t))) != 0)
566: return val;
567: if (!PTQ_EMPTY(&queue))
568: info->sync_haswaiters = 1;
569:
570:
571: info->sync_data.rwlock.locked = 0;
572: if ((val = READ(s->proc,
573: s->addr + offsetof(struct pthread_rwlock_st, ptr_nreaders),
574: &n, sizeof(int))) != 0)
575: return val;
576: info->sync_data.rwlock.readlocks = n;
577: if (n > 0)
578: info->sync_data.rwlock.locked = 1;
579:
580: if ((val = READ(s->proc,
581: s->addr + offsetof(struct pthread_rwlock_st, ptr_writer),
582: &taddr, sizeof(pthread_t))) != 0)
583: return val;
584: if (taddr != 0) {
585: info->sync_data.rwlock.locked = 1;
1.3 christos 586: td__getthread(s->proc, (void *)taddr,
1.2 thorpej 587: &info->sync_data.rwlock.writeowner);
588: }
1.3 christos 589: /*FALLTHROUGH*/
1.2 thorpej 590: default:
591: return (0);
592: }
593:
594: info->sync_addr = s->addr;
595:
596: return 0;
597: }
598:
599:
600: int
601: td_sync_waiters_iter(td_sync_t *s, int (*call)(td_thread_t *, void *),
602: void *arg)
603: {
604: int val, magic;
605: caddr_t next;
606: struct pthread_queue_t queue;
607: td_thread_t *thread;
608:
609: val = READ(s->proc, s->addr, &magic, sizeof(magic));
610: if (val != 0)
611: return val;
612:
613: switch (magic) {
614: case _PT_MUTEX_MAGIC:
615: if ((val = READ(s->proc,
616: s->addr + offsetof(struct pthread_mutex_st, ptm_blocked),
617: &queue, sizeof(struct pthread_queue_t))) != 0)
618: return val;
619: break;
620: case _PT_COND_MAGIC:
621: if ((val = READ(s->proc,
622: s->addr + offsetof(struct pthread_cond_st, ptc_waiters),
623: &queue, sizeof(struct pthread_queue_t))) != 0)
624: return val;
625: break;
626: case PT_MAGIC:
627: /* Redundant with join_iter, but what the hell... */
628: if ((val = READ(s->proc,
629: s->addr + offsetof(struct pthread_st, pt_joiners),
630: &queue, sizeof(struct pthread_queue_t))) != 0)
631: return val;
632: break;
633: default:
634: return (0);
635: }
636:
1.3 christos 637: next = (void *)queue.ptqh_first;
638: while (next != NULL) {
1.2 thorpej 639: val = td__getthread(s->proc, next, &thread);
640: if (val != 0)
641: return val;
642: val = (*call)(thread, arg);
643: if (val != 0)
644: return 0;
645:
646: val = READ(s->proc,
647: next + offsetof(struct pthread_st, pt_sleep.ptqe_next),
648: &next, sizeof(next));
649: if (val != 0)
650: return val;
651: }
652: return 0;
653: }
654:
655:
656: int
657: td_map_addr2sync(td_proc_t *proc, caddr_t addr, td_sync_t **syncp)
658: {
659: int magic, val;
660:
661: val = READ(proc, addr, &magic, sizeof(magic));
662: if (val != 0)
663: return val;
664:
665: if ((magic != _PT_MUTEX_MAGIC) &&
666: (magic != _PT_COND_MAGIC) &&
667: (magic != _PT_SPINLOCK_MAGIC))
668: return TD_ERR_NOOBJ;
669:
670: val = td__getsync(proc, addr, syncp);
671: if (val != 0)
672: return val;
673:
674: return 0;
675: }
676:
677:
678: int
679: td_map_pth2thr(td_proc_t *proc, pthread_t thread, td_thread_t **threadp)
680: {
681: int magic, val;
682:
1.3 christos 683: val = READ(proc, (void *)thread, &magic, sizeof(magic));
1.2 thorpej 684: if (val != 0)
685: return val;
686:
687: if (magic != PT_MAGIC)
688: return TD_ERR_NOOBJ;
689:
1.3 christos 690: val = td__getthread(proc, (void *)thread, threadp);
1.2 thorpej 691: if (val != 0)
692: return val;
693:
694: return 0;
695: }
696:
697: int
698: td_map_id2thr(td_proc_t *proc, int threadid, td_thread_t **threadp)
699: {
700: int val, num;
701: caddr_t allqaddr, next;
702: struct pthread_queue_t allq;
703: td_thread_t *thread;
704:
705:
706: if (proc->allqueue == 0) {
707: val = LOOKUP(proc, "pthread__allqueue", &allqaddr);
708: if (val != 0)
709: return val;
710: proc->allqueue = allqaddr;
711: } else {
712: allqaddr = proc->allqueue;
713: }
714:
715: val = READ(proc, allqaddr, &allq, sizeof(allq));
716: if (val != 0)
717: return val;
718:
1.3 christos 719: next = (void *)allq.ptqh_first;
720: while (next != NULL) {
1.2 thorpej 721: val = READ(proc,
722: next + offsetof(struct pthread_st, pt_num),
723: &num, sizeof(num));
724:
725: if (num == threadid)
726: break;
727:
728: val = READ(proc,
729: next + offsetof(struct pthread_st, pt_allq.ptqe_next),
730: &next, sizeof(next));
731: if (val != 0)
732: return val;
733: }
734:
735: if (next == 0) {
736: /* A matching thread was not found. */
737: return TD_ERR_NOOBJ;
738: }
739:
740: val = td__getthread(proc, next, &thread);
741: if (val != 0)
742: return val;
743: *threadp = thread;
744:
745: return 0;
746: }
747:
748: /* Return the thread handle of the thread running on the given LWP */
749: int
750: td_map_lwp2thr(td_proc_t *proc, int lwp, td_thread_t **threadp)
751: {
752: int val, magic;
753: struct reg gregs;
754: ucontext_t uc;
1.3 christos 755: void *th;
1.2 thorpej 756:
757: val = GETREGS(proc, 0, lwp, &gregs);
758: if (val != 0)
759: return val;
760:
761: PTHREAD_REG_TO_UCONTEXT(&uc, &gregs);
762:
1.3 christos 763: th = pthread__id(pthread__uc_sp(&uc));
1.2 thorpej 764:
765: val = READ(proc, th, &magic, sizeof(magic));
766: if (val != 0)
767: return val;
768:
769: if (magic != PT_MAGIC)
770: return TD_ERR_NOOBJ;
771:
772: val = td__getthread(proc, th, threadp);
773: if (val != 0)
774: return val;
775:
776: (*threadp)->lwp = lwp;
777:
778: return 0;
779: }
780:
781: int
782: td_map_lwps(td_proc_t *proc)
783: {
784: int i, val, nlwps;
785: caddr_t addr;
786: td_thread_t *thread;
787:
788: val = LOOKUP(proc, "pthread__maxlwps", &addr);
789: if (val != 0)
790: return val;
791:
792: val = READ(proc, addr, &nlwps, sizeof(int));
793: if (val != 0)
794: return val;
795:
796: for (i = 1; i <= nlwps; i++) {
797: /*
798: * Errors are deliberately ignored for the call to
799: * td_map_lwp2thr(); it is entirely likely that not
800: * all LWPs in the range 1..nlwps exist, and that's
801: * not a problem.
802: */
803: td_map_lwp2thr(proc, i, &thread);
804: }
805: return 0;
806: }
807:
808: int
809: td_tsd_iter(td_proc_t *proc,
810: int (*call)(pthread_key_t, void (*)(void *), void *), void *arg)
811: {
812: caddr_t desaddr, allocaddr;
813: int val;
814: int i, allocated;
815: void (*destructor)(void *);
816:
817: val = LOOKUP(proc, "pthread__tsd_alloc", &allocaddr);
818: if (val != 0)
819: return val;
820: val = LOOKUP(proc, "pthread__tsd_destructors", &desaddr);
821: if (val != 0)
822: return val;
823:
824: for (i = 0; i < PTHREAD_KEYS_MAX; i++) {
825: val = READ(proc, allocaddr + i * sizeof(int),
826: &allocated, sizeof(int));
827: if (val != 0)
828: return val;
829:
830: if (allocated) {
831: val = READ(proc, desaddr + i * sizeof(destructor),
832: &destructor, sizeof(destructor));
833: if (val != 0)
834: return val;
835:
836: val = (call)(i, destructor, arg);
837: if (val != 0)
838: return val;
839: }
840: }
841:
842: return 0;
843: }
844:
845: /* Get the synchronization object that the thread is sleeping on */
846: int
847: td_thr_sleepinfo(td_thread_t *thread, td_sync_t **s)
848: {
849: int val;
850: caddr_t addr;
851:
852: if ((val = READ(thread->proc,
853: thread->addr + offsetof(struct pthread_st, pt_sleepobj),
854: &addr, sizeof(caddr_t))) != 0)
855: return val;
856:
857: td__getsync(thread->proc, addr, s);
858:
859: return 0;
860:
861: }
862:
863:
864:
865: static int
866: td__getthread(td_proc_t *proc, caddr_t addr, td_thread_t **threadp)
867: {
868: td_thread_t *thread;
869:
870: /*
871: * Check if we've allocated a descriptor for this thread.
872: * Sadly, this makes iterating over a set of threads O(N^2)
873: * in the number of threads. More sophisticated data structures
874: * can wait.
875: */
876: PTQ_FOREACH(thread, &proc->threads, list) {
877: if (thread->addr == addr)
878: break;
879: }
880: if (thread == NULL) {
881: thread = malloc(sizeof(*thread));
882: if (thread == NULL)
883: return TD_ERR_NOMEM;
884: thread->proc = proc;
885: thread->addr = addr;
886: thread->lwp = 0;
887: PTQ_INSERT_HEAD(&proc->threads, thread, list);
888: }
889:
890: *threadp = thread;
891: return 0;
892: }
893:
894:
895: static int
896: td__getsync(td_proc_t *proc, caddr_t addr, td_sync_t **syncp)
897: {
898: td_sync_t *s;
899:
900: /* Check if we've allocated a descriptor for this object. */
901: PTQ_FOREACH(s, &proc->syncs, list) {
902: if (s->addr == addr)
903: break;
904: }
905: /* Allocate a fresh one */
906: if (s == NULL) {
907: s = malloc(sizeof(*s));
908: if (s == NULL)
909: return TD_ERR_NOMEM;
910: s->proc = proc;
911: s->addr = addr;
912: PTQ_INSERT_HEAD(&proc->syncs, s, list);
913: }
914:
915: *syncp = s;
916: return 0;
917: }
918:
919:
920: int
921: td_thr_tsd(td_thread_t *thread, pthread_key_t key, void **value)
922: {
923: int val;
924:
925: val = READ(thread->proc, thread->addr +
926: offsetof(struct pthread_st, pt_specific) +
927: key * sizeof(void *), &value, sizeof(void *));
928:
929: return val;
930: }
931:
CVSweb <webmaster@jp.NetBSD.org>