[BACK]Return to pmdb.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / pmdb

Annotation of src/usr.bin/pmdb/pmdb.c, Revision 1.22

1.22    ! miod        1: /*     $OpenBSD: pmdb.c,v 1.21 2007/08/06 19:16:05 sobrado Exp $       */
1.1       art         2: /*
                      3:  * Copyright (c) 2002 Artur Grabowski <art@openbsd.org>
                      4:  * All rights reserved.
                      5:  *
                      6:  * Redistribution and use in source and binary forms, with or without
                      7:  * modification, are permitted provided that the following conditions
                      8:  * are met:
                      9:  *
                     10:  * 1. Redistributions of source code must retain the above copyright
                     11:  *    notice, this list of conditions and the following disclaimer.
                     12:  * 2. The name of the author may not be used to endorse or promote products
                     13:  *    derived from this software without specific prior written permission.
                     14:  *
                     15:  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
                     16:  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
                     17:  * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
                     18:  * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
                     19:  * EXEMPLARY, OR CONSEQUENTIAL  DAMAGES (INCLUDING, BUT NOT LIMITED TO,
                     20:  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
                     21:  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
                     22:  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
                     23:  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
                     24:  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
                     25:  */
                     26:
                     27: #include <sys/types.h>
                     28: #include <sys/ptrace.h>
                     29: #include <sys/wait.h>
                     30:
                     31: #include <stdlib.h>
                     32: #include <stdio.h>
                     33: #include <unistd.h>
                     34: #include <signal.h>
                     35: #include <err.h>
                     36: #include <errno.h>
                     37: #include <string.h>
1.19      jfb        38: #include <paths.h>
1.1       art        39:
                     40: #include "pmdb.h"
                     41: #include "symbol.h"
                     42: #include "clit.h"
                     43: #include "break.h"
1.7       fgsch      44: #include "core.h"
1.1       art        45:
                     46: static int cmd_show_registers(int, char **, void *);
                     47: static int cmd_show_backtrace(int, char **, void *);
1.14      mickey     48: static int cmd_examine(int, char **, void *);
1.1       art        49: static int cmd_quit(int, char **, void *);
                     50:
                     51: struct clit cmds[] = {
                     52:        /* debugging info commands. */
                     53:        { "regs", "show registers", 0, 0, cmd_show_registers, (void *)-1 },
                     54:        { "trace", "show backtrace", 0, 0, cmd_show_backtrace, (void *)-1 },
1.14      mickey     55:        { "x", "examine memory", 1, 16, cmd_examine, (void *)-1 },
1.1       art        56:
                     57:        /* Process handling commands. */
                     58:        { "run", "run process", 0, 0, cmd_process_run, (void *)-1 },
                     59:        { "continue", "continue process", 0, 0, cmd_process_cont, (void *)-1 },
                     60:        { "kill", "kill process", 0, 0, cmd_process_kill, (void *)-1 },
1.12      art        61:        { "setenv", "set env variables", 2, 2, cmd_process_setenv, (void *)-1 },
1.1       art        62:
                     63:        /* signal handling commands. */
                     64:        { "signal", "ignore signal", 2, 2, cmd_signal_ignore, (void *)-1 },
                     65:        { "sigstate", "show signal state", 0, 0, cmd_signal_show, (void *)-1 },
                     66:
                     67:        /* breakpoints */
                     68:        { "break", "set breakpoint", 1, 1, cmd_bkpt_add, (void *)-1 },
                     69:        { "step", "single step one insn", 0, 0, cmd_sstep, (void *)-1 },
1.3       art        70:
                     71:        /* symbols */
                     72:        { "sym_load", "load symbol table", 2, 2, cmd_sym_load, (void *)-1 },
1.1       art        73:
                     74:        /* misc commands. */
                     75:        { "help", "print help", 0, 1, cmd_help, NULL },
                     76:        { "quit", "quit", 0, 0, cmd_quit, (void *)-1 },
                     77:        { "exit", "quit", 0, 0, cmd_quit, (void *)-1 },
                     78: };
                     79:
1.6       fgsch      80: #define NCMDS  sizeof(cmds)/sizeof(cmds[0])
                     81:
1.7       fgsch      82: void
1.17      deraadt    83: usage(void)
1.7       fgsch      84: {
                     85:        extern char *__progname;
                     86:
1.21      sobrado    87:        fprintf(stderr, "usage: %s [-c core] [-p pid] program ...\n",
1.9       fgsch      88:            __progname);
1.7       fgsch      89:        exit(1);
                     90: }
                     91:
1.1       art        92: int
                     93: main(int argc, char **argv)
                     94: {
                     95:        struct pstate ps;
1.7       fgsch      96:        int i, c;
1.1       art        97:        int status;
                     98:        void *cm;
1.19      jfb        99:        char *pmenv, *core, *perr, execpath[MAXPATHLEN];
1.1       art       100:        int level;
1.8       todd      101:        pid_t pid;
1.1       art       102:
1.7       fgsch     103:        core = NULL;
1.8       todd      104:        pid = 0;
1.7       fgsch     105:
1.9       fgsch     106:        while ((c = getopt(argc, argv, "c:p:")) != -1) {
1.7       fgsch     107:                switch(c) {
                    108:                        case 'c':
                    109:                                core = optarg;
                    110:                                break;
1.8       todd      111:                        case 'p':
                    112:                                pid = (pid_t) strtol(optarg, &perr, 10);
1.9       fgsch     113:                                if (*perr != '\0')
1.8       todd      114:                                        errx(1, "invalid PID");
                    115:                                break;
1.7       fgsch     116:                        case '?':
                    117:                        default:
                    118:                                usage();
                    119:                                /* NOTREACHED */
                    120:                }
                    121:        }
                    122:        argc -= optind;
                    123:        argv += optind;
1.11      fgsch     124:
                    125:        if (argc == 0)
                    126:                usage();
1.7       fgsch     127:
1.1       art       128:        if ((pmenv = getenv("IN_PMDB")) != NULL) {
                    129:                level = atoi(pmenv);
                    130:                level++;
                    131:        } else
                    132:                level = 0;
                    133:
                    134:        if (level > 0)
                    135:                asprintf(&prompt_add, "(%d)", level);
                    136:        asprintf(&pmenv, "%d", level);
                    137:        setenv("IN_PMDB", pmenv, 1);
1.15      pvalchev  138:        if (pmenv)
                    139:                free(pmenv);
1.1       art       140:
1.19      jfb       141:        if (getexecpath(argv[0], execpath, sizeof(execpath)) == -1) {
                    142:                err(1, "cannot find `%s'", argv[0]);
                    143:        }
                    144:        argv[0] = execpath;
                    145:
                    146:        memset(&ps, 0, sizeof(ps));
                    147:        process_setargv(&ps, argc, argv);
                    148:
1.8       todd      149:        ps.ps_pid = pid;
1.1       art       150:        ps.ps_state = NONE;
                    151:        ps.ps_flags = 0;
                    152:        ps.ps_signum = 0;
                    153:        ps.ps_npc = 1;
                    154:        TAILQ_INIT(&ps.ps_bkpts);
                    155:        TAILQ_INIT(&ps.ps_sstep_cbs);
                    156:
                    157:        signal(SIGINT, SIG_IGN);
                    158:
1.6       fgsch     159:        for (i = 0; i < NCMDS; i++)
1.1       art       160:                if (cmds[i].arg == (void *)-1)
                    161:                        cmds[i].arg = &ps;
                    162:
                    163:        md_def_init();
                    164:        init_sigstate(&ps);
                    165:
1.10      art       166:        if ((core != NULL) && (read_core(core, &ps) < 0))
                    167:                warnx("failed to load core file");
1.1       art       168:
1.10      art       169:        if (process_load(&ps) < 0)
                    170:                errx(1, "failed to load process");
1.7       fgsch     171:
1.6       fgsch     172:        cm = cmdinit(cmds, NCMDS);
1.1       art       173:        while (ps.ps_state != TERMINATED) {
                    174:                int signum;
                    175:                int stopped;
                    176:                int cont;
                    177:
                    178:                if (ps.ps_state == STOPPED) {
                    179:                        sym_update(&ps);
                    180:                }
                    181:
                    182:                if (ps.ps_state != RUNNING && cmdloop(cm) == 0) {
                    183:                        cmd_quit(0, NULL, &ps);
                    184:                }
                    185:
                    186:                if (ps.ps_state == TERMINATED)
                    187:                        break;
1.22    ! miod      188:
        !           189:                if (ps.ps_state == NONE || ps.ps_state == LOADED)
        !           190:                        continue;
1.1       art       191:
                    192:                if (wait(&status) == 0)
                    193:                        err(1, "wait");
                    194:                if (WIFEXITED(status)) {
                    195:                        if ((ps.ps_flags & PSF_KILL) == 0) {
                    196:                                ps.ps_state = NONE;
                    197:                        } else {
                    198:                                ps.ps_state = TERMINATED;
                    199:                        }
                    200:                        fprintf(stderr, "process exited with status %d\n",
                    201:                            WEXITSTATUS(status));
                    202:                        continue;
                    203:                }
                    204:                if (WIFSIGNALED(status)) {
                    205:                        signum = WTERMSIG(status);
                    206:                        stopped = 0;
                    207:                } else {
                    208:                        signum = WSTOPSIG(status);
                    209:                        stopped = 1;
                    210:                }
                    211:                cont = 0;
                    212:                if (stopped)
                    213:                        cont = bkpt_check(&ps);
                    214:                process_signal(&ps, signum, stopped, cont);
                    215:        }
                    216:
                    217:        cmdend(cm);
                    218:
                    219:        sym_destroy(&ps);
                    220:
                    221:        return (0);
                    222: }
                    223:
                    224:
                    225: static int
                    226: cmd_show_registers(int argc, char **argv, void *arg)
                    227: {
                    228:        struct pstate *ps = arg;
                    229:        char buf[256];
                    230:        int i;
                    231:        reg *rg;
                    232:
                    233:        if (ps->ps_state != STOPPED) {
1.7       fgsch     234:                if (ps->ps_flags & PSF_CORE) {
                    235:                        /* dump registers from core */
1.13      mickey    236:                        core_printregs(ps);
1.7       fgsch     237:                        return (0);
                    238:                }
1.1       art       239:                fprintf(stderr, "process not stopped\n");
1.7       fgsch     240:                return (0);
1.1       art       241:        }
                    242:
                    243:        rg = alloca(sizeof(*rg) * md_def.nregs);
                    244:
                    245:        if (md_getregs(ps, rg))
                    246:                err(1, "can't get registers");
                    247:        for (i = 0; i < md_def.nregs; i++)
                    248:                printf("%s:\t0x%.*lx\t%s\n", md_def.md_reg_names[i],
                    249:                    (int)(sizeof(reg) * 2), (long)rg[i],
                    250:                    sym_print(ps, rg[i], buf, sizeof(buf)));
1.7       fgsch     251:        return (0);
1.1       art       252: }
                    253:
                    254: static int
                    255: cmd_show_backtrace(int argc, char **argv, void *arg)
                    256: {
                    257:        struct pstate *ps = arg;
                    258:        int i;
                    259:
1.10      art       260:        if (ps->ps_state != STOPPED && !(ps->ps_flags & PSF_CORE)) {
1.1       art       261:                fprintf(stderr, "process not stopped\n");
1.7       fgsch     262:                return (0);
1.1       art       263:        }
                    264:
                    265:        /* no more than 100 frames */
                    266:        for (i = 0; i < 100; i++) {
                    267:                struct md_frame mfr;
                    268:                char namebuf[1024], *name;
                    269:                reg offs;
                    270:                int j;
                    271:
                    272:                mfr.nargs = -1;
                    273:
                    274:                if (md_getframe(ps, i, &mfr))
                    275:                        break;
                    276:
                    277:                name = sym_name_and_offset(ps, mfr.pc, namebuf,
                    278:                    sizeof(namebuf), &offs);
                    279:                if (name == NULL) {
                    280:                        snprintf(namebuf, sizeof(namebuf), "0x%lx", mfr.pc);
                    281:                        name = namebuf;
1.5       drahn     282:                        offs = 0;
1.1       art       283:                }
                    284:
                    285:                printf("%s(", name);
                    286:                for (j = 0; j < mfr.nargs; j++) {
                    287:                        printf("0x%lx", mfr.args[j]);
                    288:                        if (j < mfr.nargs - 1)
                    289:                                printf(", ");
                    290:                }
1.5       drahn     291:                if (offs == 0) {
1.6       fgsch     292:                        printf(")\n");
1.5       drahn     293:                } else {
                    294:                        printf(")+0x%lx\n", offs);
                    295:                }
1.1       art       296:        }
1.7       fgsch     297:
                    298:        return (0);
1.1       art       299: }
                    300:
                    301: static int
                    302: cmd_quit(int argc, char **argv, void *arg)
                    303: {
                    304:        struct pstate *ps = arg;
                    305:
1.8       todd      306:        if ((ps->ps_flags & PSF_ATCH)) {
                    307:                if ((ps->ps_flags & PSF_ATCH) &&
                    308:                    ptrace(PT_DETACH, ps->ps_pid, NULL, 0) < 0)
                    309:                        err(1, "ptrace(PT_DETACH)");
                    310:        } else {
                    311:                ps->ps_flags |= PSF_KILL;
1.1       art       312:
1.8       todd      313:                if (process_kill(ps))
1.9       fgsch     314:                        return (1);
1.8       todd      315:        }
1.1       art       316:
                    317:        ps->ps_state = TERMINATED;
1.9       fgsch     318:        return (1);
1.14      mickey    319: }
                    320:
                    321: static int
                    322: cmd_examine(int argc, char **argv, void *arg)
                    323: {
                    324:        struct pstate *ps = arg;
                    325:        char buf[256];
                    326:        reg addr, val;
                    327:        int i;
                    328:
                    329:        for (i = 1; argv[i]; i++) {
                    330:
                    331:                addr = strtoul(argv[i], NULL, 0);
                    332:                if (!addr) {    /* assume it's a symbol */
                    333:                        if (sym_lookup(ps, argv[i], &addr)) {
                    334:                                warn( "Can't find: %s", argv[i]);
                    335:                                return (0);
                    336:                        }
                    337:                }
                    338:
1.18      mickey    339:                if (process_read(ps, addr, &val, sizeof(val)) < 0) {
1.14      mickey    340:                        warn("Can't read process contents at 0x%lx", addr);
                    341:                        return (0);
                    342:                }
                    343:
                    344:                printf("%s:\t%s\n", argv[i],
                    345:                    sym_print(ps, val, buf, sizeof(buf)));
                    346:        }
                    347:
                    348:        return (0);
1.1       art       349: }
                    350:
                    351: /*
                    352:  * Perform command completion.
                    353:  * Pretty simple. if there are spaces in "buf", the last string is a symbol
                    354:  * otherwise it's a command.
                    355:  */
                    356: int
                    357: cmd_complt(char *buf, size_t buflen)
                    358: {
                    359:        struct clit *match;
                    360:        char *start;
                    361:        int command;
                    362:        int i, j, len;
                    363:        int onlymatch;
                    364:
                    365:        command = (strchr(buf, ' ') == NULL);
                    366:
                    367:        if (!command) {
                    368:                /* XXX - can't handle symbols yet. */
1.9       fgsch     369:                return (-1);
1.1       art       370:        }
                    371:
                    372:        start = buf;
                    373:        len = strlen(buf);
                    374:
                    375:        match = NULL;
                    376:        for (i = 0; i < sizeof(cmds) / sizeof(cmds[i]); i++) {
                    377:                if (strncmp(start, cmds[i].cmd, len) == 0) {
                    378:                        struct clit *cmdp;
                    379:
                    380:                        cmdp = &cmds[i];
                    381:                        if (match == NULL) {
                    382:                                onlymatch = 1;
                    383:                                match = cmdp;
                    384:                                strlcpy(buf, match->cmd, buflen);
                    385:                                continue;
                    386:                        }
                    387:                        onlymatch = 0;
                    388:                        for (j = len; j < buflen; j++) {
                    389:                                if (buf[j] != cmdp->cmd[j]) {
                    390:                                        buf[j] = '\0';
                    391:                                        break;
                    392:                                }
                    393:                                if (cmdp->cmd[j] == '\0')
                    394:                                        break;
                    395:                        }
                    396:                }
                    397:        }
                    398:
                    399:        /*
                    400:         * Be nice. If there could be arguments for this command and it's
                    401:         * the only match append a space.
                    402:         */
                    403:        if (match && onlymatch /*&& match->maxargc > 0*/)
                    404:                strlcat(buf, " ", buflen);
                    405:
                    406:        return (match && onlymatch) ? 0 : -1;
                    407: }
                    408:
                    409: /*
1.7       fgsch     410:  * The "standard" wrapper
1.1       art       411:  */
                    412: void *
                    413: emalloc(size_t sz)
                    414: {
                    415:        void *ret;
                    416:        if ((ret = malloc(sz)) == NULL)
                    417:                err(1, "malloc");
                    418:        return (ret);
1.19      jfb       419: }
                    420:
                    421:
                    422: /*
                    423:  * Find the first valid path to the executable whose name is <ename>.
                    424:  * The resulting path is stored in <dst>, up to <dlen> - 1 bytes, and is
                    425:  * NUL-terminated.  If <dst> is too small, the result will be truncated to
                    426:  * fit, but getexecpath() will return -1.
                    427:  * Returns 0 on success, -1 on failure.
                    428:  */
                    429:
                    430: int
                    431: getexecpath(const char *ename, char *dst, size_t dlen)
                    432: {
                    433:        char *envp, *pathenv, *pp, *pfp;
                    434:        struct stat pstat;
                    435:
                    436:        if (stat(ename, &pstat) == 0) {
                    437:                if (strlcpy(dst, ename, dlen) >= dlen)
                    438:                        return (-1);
                    439:                return (0);
                    440:        }
                    441:
                    442:        if (strchr(ename, '/') != NULL) {
                    443:                /* don't bother looking in PATH */
                    444:                return (-1);
                    445:        }
                    446:
                    447:        envp = getenv("PATH");
                    448:        if (envp == NULL)
                    449:                envp = _PATH_DEFPATH;
                    450:
                    451:        pathenv = strdup(envp);
                    452:        if (pathenv == NULL) {
                    453:                warn("failed to allocate PATH buffer");
                    454:                return (-1);
                    455:        }
                    456:
                    457:        for (pp = pathenv; (pfp = strsep(&pp, ":")) != NULL; ) {
                    458:                /* skip cwd, was already tested */
                    459:                if (*pfp == '\0')
                    460:                        continue;
                    461:
                    462:                if (snprintf(dst, dlen, "%s/%s", pfp, ename) >= (int)dlen)
                    463:                        continue;
                    464:
                    465:                if (stat(dst, &pstat) != -1) {
                    466:                        free(pathenv);
                    467:                        return (0);
                    468:                }
                    469:        }
                    470:
                    471:        free(pathenv);
                    472:        return (-1);
1.1       art       473: }