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

1.6     ! fgsch       1: /*     $OpenBSD: pmdb.c,v 1.5 2002/03/19 23:10:57 drahn 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>
                     38:
                     39: #include <sys/endian.h>
                     40:
                     41: #include "pmdb.h"
                     42: #include "symbol.h"
                     43: #include "clit.h"
                     44: #include "break.h"
                     45:
                     46: static int cmd_show_registers(int, char **, void *);
                     47: static int cmd_show_backtrace(int, char **, void *);
                     48: static int cmd_quit(int, char **, void *);
                     49:
                     50: struct clit cmds[] = {
                     51:        /* debugging info commands. */
                     52:        { "regs", "show registers", 0, 0, cmd_show_registers, (void *)-1 },
                     53:        { "trace", "show backtrace", 0, 0, cmd_show_backtrace, (void *)-1 },
                     54:
                     55:        /* Process handling commands. */
                     56:        { "run", "run process", 0, 0, cmd_process_run, (void *)-1 },
                     57:        { "continue", "continue process", 0, 0, cmd_process_cont, (void *)-1 },
                     58:        { "kill", "kill process", 0, 0, cmd_process_kill, (void *)-1 },
                     59:
                     60:        /* signal handling commands. */
                     61:        { "signal", "ignore signal", 2, 2, cmd_signal_ignore, (void *)-1 },
                     62:        { "sigstate", "show signal state", 0, 0, cmd_signal_show, (void *)-1 },
                     63:
                     64:        /* breakpoints */
                     65:        { "break", "set breakpoint", 1, 1, cmd_bkpt_add, (void *)-1 },
                     66:        { "step", "single step one insn", 0, 0, cmd_sstep, (void *)-1 },
1.3       art        67:
                     68:        /* symbols */
                     69:        { "sym_load", "load symbol table", 2, 2, cmd_sym_load, (void *)-1 },
1.1       art        70:
                     71:        /* misc commands. */
                     72:        { "help", "print help", 0, 1, cmd_help, NULL },
                     73:        { "quit", "quit", 0, 0, cmd_quit, (void *)-1 },
                     74:        { "exit", "quit", 0, 0, cmd_quit, (void *)-1 },
                     75: };
                     76:
1.6     ! fgsch      77: #define NCMDS  sizeof(cmds)/sizeof(cmds[0])
        !            78:
1.1       art        79: int
                     80: main(int argc, char **argv)
                     81: {
                     82:        extern const char *__progname;
                     83:        struct pstate ps;
1.6     ! fgsch      84:        int i;
1.1       art        85:        int status;
                     86:        void *cm;
                     87:        char *pmenv;
                     88:        int level;
                     89:
                     90:        if (argc < 2) {
                     91:                fprintf(stderr, "Usage: %s <program> args\n", __progname);
                     92:                exit(1);
                     93:        }
                     94:
                     95:        if ((pmenv = getenv("IN_PMDB")) != NULL) {
                     96:                level = atoi(pmenv);
                     97:                level++;
                     98:        } else
                     99:                level = 0;
                    100:
                    101:        if (level > 0)
                    102:                asprintf(&prompt_add, "(%d)", level);
                    103:        asprintf(&pmenv, "%d", level);
                    104:        setenv("IN_PMDB", pmenv, 1);
                    105:
                    106:        ps.ps_pid = 0;
                    107:        ps.ps_state = NONE;
                    108:        ps.ps_argc = --argc;
                    109:        ps.ps_argv = ++argv;
                    110:        ps.ps_flags = 0;
                    111:        ps.ps_signum = 0;
                    112:        ps.ps_npc = 1;
                    113:        TAILQ_INIT(&ps.ps_bkpts);
                    114:        TAILQ_INIT(&ps.ps_sstep_cbs);
                    115:
                    116:        signal(SIGINT, SIG_IGN);
                    117:
1.6     ! fgsch     118:        for (i = 0; i < NCMDS; i++)
1.1       art       119:                if (cmds[i].arg == (void *)-1)
                    120:                        cmds[i].arg = &ps;
                    121:
                    122:        md_def_init();
                    123:        init_sigstate(&ps);
                    124:
                    125:        process_load(&ps);
                    126:
1.6     ! fgsch     127:        cm = cmdinit(cmds, NCMDS);
1.1       art       128:        while (ps.ps_state != TERMINATED) {
                    129:                int signum;
                    130:                int stopped;
                    131:                int cont;
                    132:
                    133:                if (ps.ps_state == STOPPED) {
                    134:                        sym_update(&ps);
                    135:                }
                    136:
                    137:                if (ps.ps_state != RUNNING && cmdloop(cm) == 0) {
                    138:                        cmd_quit(0, NULL, &ps);
                    139:                }
                    140:
                    141:                if (ps.ps_state == TERMINATED)
                    142:                        break;
                    143:
                    144:                if (wait(&status) == 0)
                    145:                        err(1, "wait");
                    146:                if (WIFEXITED(status)) {
                    147:                        if ((ps.ps_flags & PSF_KILL) == 0) {
                    148:                                ps.ps_state = NONE;
                    149:                        } else {
                    150:                                ps.ps_state = TERMINATED;
                    151:                        }
                    152:                        fprintf(stderr, "process exited with status %d\n",
                    153:                            WEXITSTATUS(status));
                    154:                        continue;
                    155:                }
                    156:                if (WIFSIGNALED(status)) {
                    157:                        signum = WTERMSIG(status);
                    158:                        stopped = 0;
                    159:                } else {
                    160:                        signum = WSTOPSIG(status);
                    161:                        stopped = 1;
                    162:                }
                    163:                cont = 0;
                    164:                if (stopped)
                    165:                        cont = bkpt_check(&ps);
                    166:                process_signal(&ps, signum, stopped, cont);
                    167:        }
                    168:
                    169:        cmdend(cm);
                    170:
                    171:        sym_destroy(&ps);
                    172:
                    173:        return (0);
                    174: }
                    175:
                    176: /* XXX - move to some other file. */
                    177: int
                    178: read_from_pid(pid_t pid, off_t from, void *to, size_t size)
                    179: {
                    180:        struct ptrace_io_desc piod;
                    181:
                    182:        piod.piod_op = PIOD_READ_D;
                    183:        piod.piod_offs = (void *)(long)from;
                    184:        piod.piod_addr = to;
                    185:        piod.piod_len = size;
                    186:
1.4       art       187:        return (ptrace(PT_IO, pid, (caddr_t)&piod, 0));
1.1       art       188: }
                    189:
                    190:
                    191: int
                    192: write_to_pid(pid_t pid, off_t to, void *from, size_t size)
                    193: {
                    194:        struct ptrace_io_desc piod;
                    195:
                    196:        piod.piod_op = PIOD_WRITE_D;
                    197:        piod.piod_offs = (void *)(long)to;
                    198:        piod.piod_addr = from;
                    199:        piod.piod_len = size;
                    200:
1.4       art       201:        return (ptrace(PT_IO, pid, (caddr_t)&piod, 0));
1.1       art       202: }
                    203:
                    204: static int
                    205: cmd_show_registers(int argc, char **argv, void *arg)
                    206: {
                    207:        struct pstate *ps = arg;
                    208:        char buf[256];
                    209:        int i;
                    210:        reg *rg;
                    211:
                    212:        if (ps->ps_state != STOPPED) {
                    213:                fprintf(stderr, "process not stopped\n");
                    214:                return 0;
                    215:        }
                    216:
                    217:        rg = alloca(sizeof(*rg) * md_def.nregs);
                    218:
                    219:        if (md_getregs(ps, rg))
                    220:                err(1, "can't get registers");
                    221:        for (i = 0; i < md_def.nregs; i++)
                    222:                printf("%s:\t0x%.*lx\t%s\n", md_def.md_reg_names[i],
                    223:                    (int)(sizeof(reg) * 2), (long)rg[i],
                    224:                    sym_print(ps, rg[i], buf, sizeof(buf)));
                    225:        return 0;
                    226: }
                    227:
                    228: static int
                    229: cmd_show_backtrace(int argc, char **argv, void *arg)
                    230: {
                    231:        struct pstate *ps = arg;
                    232:        int i;
                    233:
                    234:        if (ps->ps_state != STOPPED) {
                    235:                fprintf(stderr, "process not stopped\n");
                    236:                return 0;
                    237:        }
                    238:
                    239:        /* no more than 100 frames */
                    240:        for (i = 0; i < 100; i++) {
                    241:                struct md_frame mfr;
                    242:                char namebuf[1024], *name;
                    243:                reg offs;
                    244:                int j;
                    245:
                    246:                mfr.nargs = -1;
                    247:
                    248:                if (md_getframe(ps, i, &mfr))
                    249:                        break;
                    250:
                    251:                name = sym_name_and_offset(ps, mfr.pc, namebuf,
                    252:                    sizeof(namebuf), &offs);
                    253:                if (name == NULL) {
                    254:                        snprintf(namebuf, sizeof(namebuf), "0x%lx", mfr.pc);
                    255:                        name = namebuf;
1.5       drahn     256:                        offs = 0;
1.1       art       257:                }
                    258:
                    259:                printf("%s(", name);
                    260:                for (j = 0; j < mfr.nargs; j++) {
                    261:                        printf("0x%lx", mfr.args[j]);
                    262:                        if (j < mfr.nargs - 1)
                    263:                                printf(", ");
                    264:                }
1.5       drahn     265:                if (offs == 0) {
1.6     ! fgsch     266:                        printf(")\n");
1.5       drahn     267:                } else {
                    268:                        printf(")+0x%lx\n", offs);
                    269:                }
1.1       art       270:        }
                    271:        return 0;
                    272: }
                    273:
                    274: static int
                    275: cmd_quit(int argc, char **argv, void *arg)
                    276: {
                    277:        struct pstate *ps = arg;
                    278:
                    279:        ps->ps_flags |= PSF_KILL;
                    280:
                    281:        if (process_kill(ps))
                    282:                return 1;
                    283:
                    284:        ps->ps_state = TERMINATED;
                    285:        return 1;
                    286: }
                    287:
                    288: /*
                    289:  * Perform command completion.
                    290:  * Pretty simple. if there are spaces in "buf", the last string is a symbol
                    291:  * otherwise it's a command.
                    292:  */
                    293: int
                    294: cmd_complt(char *buf, size_t buflen)
                    295: {
                    296:        struct clit *match;
                    297:        char *start;
                    298:        int command;
                    299:        int i, j, len;
                    300:        int onlymatch;
                    301:
                    302:        command = (strchr(buf, ' ') == NULL);
                    303:
                    304:        if (!command) {
                    305:                /* XXX - can't handle symbols yet. */
                    306:                return -1;
                    307:        }
                    308:
                    309:        start = buf;
                    310:        len = strlen(buf);
                    311:
                    312:        match = NULL;
                    313:        for (i = 0; i < sizeof(cmds) / sizeof(cmds[i]); i++) {
                    314:                if (strncmp(start, cmds[i].cmd, len) == 0) {
                    315:                        struct clit *cmdp;
                    316:
                    317:                        cmdp = &cmds[i];
                    318:                        if (match == NULL) {
                    319:                                onlymatch = 1;
                    320:                                match = cmdp;
                    321:                                strlcpy(buf, match->cmd, buflen);
                    322:                                continue;
                    323:                        }
                    324:                        onlymatch = 0;
                    325:                        for (j = len; j < buflen; j++) {
                    326:                                if (buf[j] != cmdp->cmd[j]) {
                    327:                                        buf[j] = '\0';
                    328:                                        break;
                    329:                                }
                    330:                                if (cmdp->cmd[j] == '\0')
                    331:                                        break;
                    332:                        }
                    333:                }
                    334:        }
                    335:
                    336:        /*
                    337:         * Be nice. If there could be arguments for this command and it's
                    338:         * the only match append a space.
                    339:         */
                    340:        if (match && onlymatch /*&& match->maxargc > 0*/)
                    341:                strlcat(buf, " ", buflen);
                    342:
                    343:        return (match && onlymatch) ? 0 : -1;
                    344: }
                    345:
                    346: /*
                    347:  * The "stadard" wrapper
                    348:  */
                    349: void *
                    350: emalloc(size_t sz)
                    351: {
                    352:        void *ret;
                    353:        if ((ret = malloc(sz)) == NULL)
                    354:                err(1, "malloc");
                    355:        return (ret);
                    356: }