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