[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.50

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

CVSweb <webmaster@jp.NetBSD.org>