[BACK]Return to pthread_dbg.c CVS log [TXT][DIR] Up to [cvs.NetBSD.org] / src / lib / libpthread_dbg

Annotation of src/lib/libpthread_dbg/pthread_dbg.c, Revision 1.41

1.41    ! christos    1: /*     $NetBSD: pthread_dbg.c,v 1.40 2008/03/07 22:27:07 ad 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>
1.41    ! christos   39: __RCSID("$NetBSD: pthread_dbg.c,v 1.40 2008/03/07 22:27:07 ad Exp $");
1.2       thorpej    40:
1.29      chs        41: #define __EXPOSE_STACK 1
1.34      ad         42:
1.29      chs        43: #include <sys/param.h>
1.34      ad         44: #include <sys/types.h>
1.38      skrll      45: #include <sys/lock.h>
1.34      ad         46:
1.2       thorpej    47: #include <stddef.h>
                     48: #include <stdlib.h>
                     49: #include <string.h>
                     50: #include <errno.h>
                     51: #include <unistd.h>
1.34      ad         52: #include <lwp.h>
1.2       thorpej    53:
1.24      martin     54: #include <machine/reg.h>
                     55:
1.2       thorpej    56: #include <pthread.h>
                     57: #include <pthread_int.h>
                     58: #include <pthread_dbg.h>
                     59: #include <pthread_dbg_int.h>
                     60:
1.12      nathanw    61: #define PT_STACKMASK (proc->stackmask)
                     62:
1.20      nathanw    63: /* Compensate for debuggers that want a zero ID to be a sentinel */
                     64: #define TN_OFFSET 1
                     65:
1.2       thorpej    66: static int td__getthread(td_proc_t *proc, caddr_t addr, td_thread_t **threadp);
1.10      cl         67:
1.2       thorpej    68: int
                     69: td_open(struct td_proc_callbacks_t *cb, void *arg, td_proc_t **procp)
                     70: {
                     71:        td_proc_t *proc;
1.12      nathanw    72:        caddr_t addr;
1.2       thorpej    73:        int dbg;
                     74:        int val;
                     75:
                     76:        proc = malloc(sizeof(*proc));
                     77:        if (proc == NULL)
                     78:                return TD_ERR_NOMEM;
                     79:        proc->cb = cb;
                     80:        proc->arg = arg;
                     81:
1.12      nathanw    82:        val = LOOKUP(proc, "pthread__dbg", &addr);
                     83:        if (val != 0) {
                     84:                if (val == TD_ERR_NOSYM)
                     85:                        val = TD_ERR_NOLIB;
                     86:                goto error;
                     87:        }
                     88:        proc->dbgaddr = addr;
                     89:
                     90:        val = LOOKUP(proc, "pthread__allqueue", &addr);
                     91:        if (val != 0) {
                     92:                if (val == TD_ERR_NOSYM)
                     93:                        val = TD_ERR_NOLIB;
                     94:                goto error;
                     95:        }
                     96:        proc->allqaddr = addr;
                     97:
1.41    ! christos   98:        val = LOOKUP(proc, "pthread__tsd_list", &addr);
1.2       thorpej    99:        if (val != 0) {
                    100:                if (val == TD_ERR_NOSYM)
                    101:                        val = TD_ERR_NOLIB;
                    102:                goto error;
                    103:        }
1.41    ! christos  104:        proc->tsdlistaddr = addr;
1.2       thorpej   105:
1.12      nathanw   106:        val = LOOKUP(proc, "pthread__tsd_destructors", &addr);
                    107:        if (val != 0) {
                    108:                if (val == TD_ERR_NOSYM)
                    109:                        val = TD_ERR_NOLIB;
                    110:                goto error;
                    111:        }
                    112:        proc->tsddestaddr = addr;
                    113:
1.16      cl        114:        val = READ(proc, proc->dbgaddr, &dbg, sizeof(int));
1.2       thorpej   115:        if (val != 0)
                    116:                goto error;
                    117:
                    118:        if (dbg != 0) {
                    119:                /* Another instance of libpthread_dbg is already attached. */
                    120:                val = TD_ERR_INUSE;
                    121:                goto error;
                    122:        }
                    123:
1.37      ad        124:        val = LOOKUP(proc, "pthread__stacksize_lg", &addr);
1.12      nathanw   125:        if (val == 0)
                    126:                proc->stacksizeaddr = addr;
                    127:        else
                    128:                proc->stacksizeaddr = NULL;
                    129:        proc->stacksizelg = -1;
                    130:        proc->stacksize = 0;
                    131:        proc->stackmask = 0;
                    132:
1.23      nathanw   133:        proc->regbuf = NULL;
                    134:        proc->fpregbuf = NULL;
                    135:
1.2       thorpej   136:        dbg = getpid();
                    137:        /*
                    138:         * If this fails it probably means we're debugging a core file and
                    139:         * can't write to it.
                    140:         * If it's something else we'll lose the next time we hit WRITE,
                    141:         * but not before, and that's OK.
                    142:         */
1.12      nathanw   143:        WRITE(proc, proc->dbgaddr, &dbg, sizeof(int));
1.2       thorpej   144:
                    145:        PTQ_INIT(&proc->threads);
                    146:
                    147:        *procp = proc;
                    148:
                    149:        return 0;
                    150:
                    151:  error:
                    152:        free(proc);
                    153:        return val;
                    154: }
                    155:
                    156: int
                    157: td_close(td_proc_t *proc)
                    158: {
                    159:        int dbg;
                    160:        td_thread_t *t, *next;
                    161:
                    162:        dbg = 0;
                    163:        /*
                    164:         * Error returns from this write are mot really a problem;
                    165:         * the process doesn't exist any more.
                    166:         */
1.12      nathanw   167:        WRITE(proc, proc->dbgaddr, &dbg, sizeof(int));
1.2       thorpej   168:
                    169:        /* Deallocate the list of thread structures */
                    170:        for (t = PTQ_FIRST(&proc->threads); t; t = next) {
                    171:                next = PTQ_NEXT(t, list);
                    172:                PTQ_REMOVE(&proc->threads, t, list);
                    173:                free(t);
                    174:        }
1.23      nathanw   175:        if (proc->regbuf != NULL) {
                    176:                free(proc->regbuf);
                    177:                free(proc->fpregbuf);
                    178:        }
                    179:
1.2       thorpej   180:        free(proc);
                    181:        return 0;
                    182: }
                    183:
                    184:
                    185: int
                    186: td_thr_iter(td_proc_t *proc, int (*call)(td_thread_t *, void *), void *callarg)
                    187: {
                    188:        int val;
1.12      nathanw   189:        caddr_t next;
1.36      ad        190:        pthread_queue_t allq;
1.2       thorpej   191:        td_thread_t *thread;
                    192:
1.12      nathanw   193:        val = READ(proc, proc->allqaddr, &allq, sizeof(allq));
1.2       thorpej   194:        if (val != 0)
                    195:                return val;
                    196:
1.3       christos  197:        next = (void *)allq.ptqh_first;
                    198:        while (next != NULL) {
1.2       thorpej   199:                val = td__getthread(proc, next, &thread);
                    200:                if (val != 0)
                    201:                        return val;
                    202:                val = (*call)(thread, callarg);
                    203:                if (val != 0)
                    204:                        return 0;
                    205:
                    206:                val = READ(proc,
1.8       nathanw   207:                    next + offsetof(struct __pthread_st, pt_allq.ptqe_next),
1.2       thorpej   208:                    &next, sizeof(next));
                    209:                if (val != 0)
                    210:                        return val;
                    211:        }
                    212:        return 0;
                    213: }
                    214:
                    215: int
                    216: td_thr_info(td_thread_t *thread, td_thread_info_t *info)
                    217: {
1.33      ad        218:        int tmp, val;
1.2       thorpej   219:
                    220:        val = READ(thread->proc, thread->addr, &tmp, sizeof(tmp));
                    221:        if (val != 0)
                    222:                return val;
                    223:
                    224:        if (tmp != PT_MAGIC)
                    225:                return TD_ERR_BADTHREAD;
                    226:
                    227:        info->thread_addr = thread->addr;
1.33      ad        228:        if ((val = READ(thread->proc,
1.11      cl        229:                      thread->addr + offsetof(struct __pthread_st, pt_state),
                    230:                      &tmp, sizeof(tmp))) != 0)
                    231:                return val;
1.2       thorpej   232:        switch (tmp) {
                    233:        case PT_STATE_RUNNING:
                    234:                info->thread_state = TD_STATE_RUNNING;
                    235:                break;
1.34      ad        236: #ifdef XXXLWP
1.19      nathanw   237:        case PT_STATE_SUSPENDED:
                    238:                info->thread_state = TD_STATE_SUSPENDED;
                    239:                break;
1.32      christos  240: #endif
1.2       thorpej   241:        case PT_STATE_ZOMBIE:
                    242:                info->thread_state = TD_STATE_ZOMBIE;
                    243:                break;
                    244:        default:
                    245:                info->thread_state = TD_STATE_UNKNOWN;
                    246:        }
                    247:
1.34      ad        248:        info->thread_type = TD_TYPE_USER;
1.2       thorpej   249:
                    250:        if ((val = READ(thread->proc,
1.8       nathanw   251:            thread->addr + offsetof(struct __pthread_st, pt_stack),
1.2       thorpej   252:            &info->thread_stack, sizeof(stack_t))) != 0)
                    253:                return val;
                    254:
                    255:        if ((val = READ(thread->proc,
1.8       nathanw   256:            thread->addr + offsetof(struct __pthread_st, pt_errno),
1.2       thorpej   257:            &info->thread_errno, sizeof(info->thread_errno))) != 0)
                    258:                return val;
                    259:
                    260:        if ((val = READ(thread->proc,
1.39      ad        261:            thread->addr + offsetof(struct __pthread_st, pt_lid),
1.6       nathanw   262:            &info->thread_id, sizeof(info->thread_id))) != 0)
1.2       thorpej   263:                return val;
                    264:
1.20      nathanw   265:        info->thread_id += TN_OFFSET;
1.2       thorpej   266:
                    267:        return 0;
                    268: }
                    269:
                    270: int
1.4       nathanw   271: td_thr_getname(td_thread_t *thread, char *name, int len)
                    272: {
                    273:        int val, tmp;
                    274:        caddr_t nameaddr;
                    275:
                    276:
                    277:        val = READ(thread->proc, thread->addr, &tmp, sizeof(tmp));
                    278:        if (val != 0)
                    279:                return val;
                    280:
                    281:        if (tmp != PT_MAGIC)
                    282:                return TD_ERR_BADTHREAD;
                    283:
                    284:        if ((val = READ(thread->proc,
1.8       nathanw   285:            thread->addr + offsetof(struct __pthread_st, pt_name),
1.4       nathanw   286:            &nameaddr, sizeof(nameaddr))) != 0)
                    287:                return val;
                    288:
                    289:        if (nameaddr == 0)
                    290:                name[0] = '\0';
                    291:        else if ((val = READ(thread->proc, nameaddr,
1.9       christos  292:            name, (size_t)MIN(PTHREAD_MAX_NAMELEN_NP, len))) != 0)
1.4       nathanw   293:                return val;
                    294:
                    295:        return 0;
                    296: }
                    297:
                    298: int
1.2       thorpej   299: td_thr_getregs(td_thread_t *thread, int regset, void *buf)
                    300: {
1.33      ad        301:        int tmp, val;
1.2       thorpej   302:
1.11      cl        303:        if ((val = READ(thread->proc,
                    304:                      thread->addr + offsetof(struct __pthread_st, pt_state),
                    305:                      &tmp, sizeof(tmp))) != 0)
1.2       thorpej   306:                return val;
                    307:
                    308:        switch (tmp) {
                    309:        case PT_STATE_RUNNING:
                    310:                /*
                    311:                 * The register state of the thread is live in the
                    312:                 * inferior process's register state.
                    313:                 */
                    314:                val = GETREGS(thread->proc, regset, thread->lwp, buf);
                    315:                if (val != 0)
                    316:                        return val;
                    317:                break;
                    318:        case PT_STATE_ZOMBIE:
                    319:        default:
                    320:                return TD_ERR_BADTHREAD;
                    321:        }
                    322:
                    323:        return 0;
                    324: }
                    325:
                    326: int
                    327: td_thr_setregs(td_thread_t *thread, int regset, void *buf)
                    328: {
1.33      ad        329:        int val, tmp;
1.2       thorpej   330:
1.11      cl        331:        if ((val = READ(thread->proc,
                    332:                      thread->addr + offsetof(struct __pthread_st, pt_state),
                    333:                      &tmp, sizeof(tmp))) != 0)
1.2       thorpej   334:                return val;
                    335:
                    336:        switch (tmp) {
                    337:        case PT_STATE_RUNNING:
                    338:                /*
                    339:                 * The register state of the thread is live in the
                    340:                 * inferior process's register state.
                    341:                 */
                    342:                val = SETREGS(thread->proc, regset, thread->lwp, buf);
                    343:                if (val != 0)
                    344:                        return val;
                    345:                break;
                    346:        case PT_STATE_ZOMBIE:
                    347:        default:
                    348:                return TD_ERR_BADTHREAD;
                    349:        }
                    350:
                    351:        return 0;
                    352: }
                    353:
                    354: int
                    355: td_map_pth2thr(td_proc_t *proc, pthread_t thread, td_thread_t **threadp)
                    356: {
                    357:        int magic, val;
                    358:
1.3       christos  359:        val = READ(proc, (void *)thread, &magic, sizeof(magic));
1.2       thorpej   360:        if (val != 0)
                    361:                return val;
                    362:
                    363:        if (magic != PT_MAGIC)
                    364:                return TD_ERR_NOOBJ;
                    365:
1.3       christos  366:        val = td__getthread(proc, (void *)thread, threadp);
1.2       thorpej   367:        if (val != 0)
                    368:                return val;
                    369:
                    370:        return 0;
                    371: }
                    372:
                    373: int
                    374: td_map_id2thr(td_proc_t *proc, int threadid, td_thread_t **threadp)
                    375: {
                    376:        int val, num;
1.12      nathanw   377:        caddr_t next;
1.36      ad        378:        pthread_queue_t allq;
1.2       thorpej   379:        td_thread_t *thread;
                    380:
                    381:
1.12      nathanw   382:        val = READ(proc, proc->allqaddr, &allq, sizeof(allq));
1.2       thorpej   383:        if (val != 0)
                    384:                return val;
                    385:
1.20      nathanw   386:        /* Correct for offset */
                    387:        threadid -= TN_OFFSET;
1.3       christos  388:        next = (void *)allq.ptqh_first;
                    389:        while (next != NULL) {
1.2       thorpej   390:                val = READ(proc,
1.39      ad        391:                    next + offsetof(struct __pthread_st, pt_lid),
1.2       thorpej   392:                    &num, sizeof(num));
                    393:
                    394:                if (num == threadid)
                    395:                        break;
                    396:
                    397:                val = READ(proc,
1.8       nathanw   398:                    next + offsetof(struct __pthread_st, pt_allq.ptqe_next),
1.2       thorpej   399:                    &next, sizeof(next));
                    400:                if (val != 0)
                    401:                        return val;
                    402:        }
                    403:
                    404:        if (next == 0) {
                    405:                /* A matching thread was not found. */
                    406:                return TD_ERR_NOOBJ;
                    407:        }
                    408:
                    409:        val = td__getthread(proc, next, &thread);
                    410:        if (val != 0)
                    411:                return val;
                    412:        *threadp = thread;
                    413:
                    414:        return 0;
                    415: }
                    416:
                    417: int
                    418: td_tsd_iter(td_proc_t *proc,
                    419:     int (*call)(pthread_key_t, void (*)(void *), void *), void *arg)
                    420: {
1.41    ! christos  421: #ifdef notyet
1.2       thorpej   422:        int val;
1.40      ad        423:        int i;
                    424:        void *allocated;
1.2       thorpej   425:        void (*destructor)(void *);
                    426:
                    427:        for (i = 0; i < PTHREAD_KEYS_MAX; i++) {
1.41    ! christos  428:                val = READ(proc, proc->tsdlistaddr + i * sizeof(allocated),
1.6       nathanw   429:                    &allocated, sizeof(allocated));
1.2       thorpej   430:                if (val != 0)
                    431:                        return val;
                    432:
1.40      ad        433:                if ((uintptr_t)allocated) {
1.12      nathanw   434:                        val = READ(proc,  proc->tsddestaddr +
                    435:                            i * sizeof(destructor),
1.2       thorpej   436:                            &destructor, sizeof(destructor));
                    437:                        if (val != 0)
                    438:                                return val;
                    439:
                    440:                        val = (call)(i, destructor, arg);
                    441:                        if (val != 0)
                    442:                                return val;
                    443:                }
                    444:        }
1.41    ! christos  445: #else
        !           446:        abort();
        !           447: #endif
1.2       thorpej   448:
                    449:        return 0;
                    450: }
1.17      nathanw   451:
                    452: /* Suspend a thread from running */
                    453: int
                    454: td_thr_suspend(td_thread_t *thread)
                    455: {
1.33      ad        456:        int tmp, val;
1.17      nathanw   457:
                    458:        /* validate the thread */
                    459:        val = READ(thread->proc, thread->addr, &tmp, sizeof(tmp));
                    460:        if (val != 0)
                    461:                return val;
                    462:        if (tmp != PT_MAGIC)
                    463:                return TD_ERR_BADTHREAD;
                    464:
1.39      ad        465:        val = READ(thread->proc, thread->addr +
                    466:            offsetof(struct __pthread_st, pt_lid),
                    467:            &tmp, sizeof(tmp));
                    468:        if (val != 0)
                    469:                return val;
                    470:
                    471:        /* XXXLWP continue the sucker */;
                    472:
1.17      nathanw   473:        return 0;
                    474: }
                    475:
                    476: /* Restore a suspended thread to its previous state */
                    477: int
                    478: td_thr_resume(td_thread_t *thread)
                    479: {
1.33      ad        480:        int tmp, val;
1.17      nathanw   481:
                    482:        /* validate the thread */
                    483:        val = READ(thread->proc, thread->addr, &tmp, sizeof(tmp));
                    484:        if (val != 0)
                    485:                return val;
                    486:        if (tmp != PT_MAGIC)
                    487:                return TD_ERR_BADTHREAD;
                    488:
                    489:        val = READ(thread->proc, thread->addr +
1.39      ad        490:            offsetof(struct __pthread_st, pt_lid),
1.17      nathanw   491:            &tmp, sizeof(tmp));
                    492:        if (val != 0)
                    493:                return val;
                    494:
1.39      ad        495:        /* XXXLWP continue the sucker */;
1.34      ad        496:
1.17      nathanw   497:        return 0;
                    498: }
1.2       thorpej   499:
                    500: static int
                    501: td__getthread(td_proc_t *proc, caddr_t addr, td_thread_t **threadp)
                    502: {
                    503:        td_thread_t *thread;
                    504:
                    505:        /*
                    506:         * Check if we've allocated a descriptor for this thread.
                    507:         * Sadly, this makes iterating over a set of threads O(N^2)
                    508:         * in the number of threads. More sophisticated data structures
                    509:         * can wait.
                    510:                 */
                    511:        PTQ_FOREACH(thread, &proc->threads, list) {
                    512:                if (thread->addr == addr)
                    513:                        break;
                    514:        }
                    515:        if (thread == NULL) {
                    516:                thread = malloc(sizeof(*thread));
                    517:                if (thread == NULL)
                    518:                        return TD_ERR_NOMEM;
                    519:                thread->proc = proc;
                    520:                thread->addr = addr;
                    521:                thread->lwp  = 0;
                    522:                PTQ_INSERT_HEAD(&proc->threads, thread, list);
                    523:        }
                    524:
                    525:        *threadp = thread;
                    526:        return 0;
                    527: }
                    528:
                    529: int
                    530: td_thr_tsd(td_thread_t *thread, pthread_key_t key, void **value)
                    531: {
                    532:        int val;
                    533:
                    534:        val = READ(thread->proc, thread->addr +
1.8       nathanw   535:            offsetof(struct __pthread_st, pt_specific) +
1.6       nathanw   536:            key * sizeof(void *), value, sizeof(*value));
1.2       thorpej   537:
                    538:        return val;
                    539: }

CVSweb <webmaster@jp.NetBSD.org>