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

Annotation of src/usr.bin/pmdb/break.c, Revision 1.1

1.1     ! art         1: /*     $PMDB: break.c,v 1.7 2002/03/12 11:28:28 art Exp $      */
        !             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 "pmdb.h"
        !            40: #include "symbol.h"
        !            41: #include "pmdb_machdep.h"
        !            42: #include "break.h"
        !            43:
        !            44: struct callback {
        !            45:        TAILQ_ENTRY(callback) cb_list;
        !            46:        int (*cb_fun)(struct pstate *, void *);
        !            47:        void *cb_arg;
        !            48: };
        !            49:
        !            50: struct breakpoint {
        !            51:        TAILQ_ENTRY(breakpoint) bkpt_list;
        !            52:        TAILQ_HEAD(,callback) bkpt_cbs;         /* list of all callbacks */
        !            53:        char bkpt_old[BREAKPOINT_LEN];          /* old contents at bkpt */
        !            54:        reg bkpt_pc;
        !            55: };
        !            56:
        !            57: static char bkpt_insn[BREAKPOINT_LEN] = BREAKPOINT;
        !            58:
        !            59: /*
        !            60:  * Find a breakpoint at this address.
        !            61:  */
        !            62: struct breakpoint *
        !            63: bkpt_find_at_pc(struct pstate *ps, reg pc)
        !            64: {
        !            65:        struct breakpoint *bkpt;
        !            66:
        !            67:        TAILQ_FOREACH(bkpt, &ps->ps_bkpts, bkpt_list)
        !            68:                if (bkpt->bkpt_pc == pc)
        !            69:                        break;
        !            70:
        !            71:        return (bkpt);
        !            72: }
        !            73:
        !            74: /*
        !            75:  * Enable this breakpoint.
        !            76:  */
        !            77: static int
        !            78: bkpt_enable(struct pstate *ps, struct breakpoint *bkpt)
        !            79: {
        !            80:        reg pc = bkpt->bkpt_pc;
        !            81:
        !            82:        if (read_from_pid(ps->ps_pid, pc, &bkpt->bkpt_old, BREAKPOINT_LEN)) {
        !            83:                warn("Can't read process contents at 0x%lx", pc);
        !            84:                return (-1);
        !            85:        }
        !            86:        if (write_to_pid(ps->ps_pid, pc, &bkpt_insn, BREAKPOINT_LEN)) {
        !            87:                warn("Can't write breakpoint at 0x%lx, attempting backout.", pc);
        !            88:                if (write_to_pid(ps->ps_pid, pc, &bkpt->bkpt_old,
        !            89:                    BREAKPOINT_LEN))
        !            90:                        warn("Backout failed, process unstable");
        !            91:                return (-1);
        !            92:        }
        !            93:        return (0);
        !            94: }
        !            95:
        !            96: /*
        !            97:  * Create a new breakpoint and enable it.
        !            98:  */
        !            99: int
        !           100: bkpt_add_cb(struct pstate *ps, reg pc, int (*fun)(struct pstate *, void *),
        !           101:     void *arg)
        !           102: {
        !           103:        struct breakpoint *bkpt;
        !           104:        struct callback *cb;
        !           105:
        !           106:        if ((bkpt = bkpt_find_at_pc(ps, pc)) == NULL) {
        !           107:                bkpt = emalloc(sizeof(*bkpt));
        !           108:                TAILQ_INIT(&bkpt->bkpt_cbs);
        !           109:                TAILQ_INSERT_TAIL(&ps->ps_bkpts, bkpt, bkpt_list);
        !           110:                bkpt->bkpt_pc = pc;
        !           111:                if (bkpt_enable(ps, bkpt)) {
        !           112:                        free(bkpt);
        !           113:                        return (-1);
        !           114:                }
        !           115:        }
        !           116:
        !           117:        cb = emalloc(sizeof(*cb));
        !           118:        cb->cb_fun = fun;
        !           119:        cb->cb_arg = arg;
        !           120:        TAILQ_INSERT_TAIL(&bkpt->bkpt_cbs, cb, cb_list);
        !           121:
        !           122:        return (0);
        !           123: }
        !           124:
        !           125: /*
        !           126:  * Disable and delete a breakpoint.
        !           127:  */
        !           128: void
        !           129: bkpt_delete(struct pstate *ps, struct breakpoint *bkpt)
        !           130: {
        !           131:        TAILQ_REMOVE(&ps->ps_bkpts, bkpt, bkpt_list);
        !           132:
        !           133:        if (write_to_pid(ps->ps_pid, bkpt->bkpt_pc, &bkpt->bkpt_old,
        !           134:            BREAKPOINT_LEN))
        !           135:                warn("Breakpoint removal failed, process unstable");
        !           136:
        !           137:        free(bkpt);
        !           138: }
        !           139:
        !           140: /*
        !           141:  * Normal standard breakpoint. Keep it.
        !           142:  */
        !           143: static int
        !           144: bkpt_normal(struct pstate *ps, void *arg)
        !           145: {
        !           146:        return (BKPT_KEEP_STOP);
        !           147: }
        !           148:
        !           149: /*
        !           150:  * Single-step callback for "stepping over" a breakpoint (we restore the
        !           151:  * breakpoint instruction to what it was, single-step over it and then
        !           152:  * call this function).
        !           153:  */
        !           154: static int
        !           155: sstep_bkpt_readd(struct pstate *ps, void *arg)
        !           156: {
        !           157:        reg pc = (reg)arg;
        !           158:
        !           159:        bkpt_add_cb(ps, pc, bkpt_normal, NULL);
        !           160:
        !           161:        return (0);     /* let the process continue */
        !           162: }
        !           163:
        !           164: /*
        !           165:  * Return 0 for stop, 1 for silent continue.
        !           166:  */
        !           167: int
        !           168: bkpt_check(struct pstate *ps)
        !           169: {
        !           170:        struct breakpoint *bkpt;
        !           171:        struct callback *cb;
        !           172:        TAILQ_HEAD(,callback) sstep_cbs;
        !           173:        reg *rg, pc;
        !           174:        int ret;
        !           175:        int didsome = 0;
        !           176:        int stop = 0;
        !           177:
        !           178:        /* Requeue all single-step callbacks because bkpts can add ssteps. */
        !           179:        TAILQ_INIT(&sstep_cbs);
        !           180:        while ((cb = TAILQ_FIRST(&ps->ps_sstep_cbs)) != NULL) {
        !           181:                TAILQ_REMOVE(&ps->ps_sstep_cbs, cb, cb_list);
        !           182:                TAILQ_INSERT_TAIL(&sstep_cbs, cb, cb_list);
        !           183:        }
        !           184:
        !           185:        /*
        !           186:         * The default is to stop. Unless we do some processing and none
        !           187:         * of the callbacks require a stop.
        !           188:         */
        !           189:        rg = alloca(sizeof(*rg) * md_def.nregs);
        !           190:        if (md_getregs(ps, rg))
        !           191:                err(1, "bkpt_check: Can't get registers.");
        !           192:
        !           193:        pc = rg[md_def.pcoff];
        !           194:        pc -= BREAKPOINT_DECR_PC;
        !           195:
        !           196:        bkpt = bkpt_find_at_pc(ps, pc);
        !           197:        if (bkpt == NULL)
        !           198:                goto sstep;
        !           199:
        !           200:        ps->ps_npc = pc;
        !           201:
        !           202:        while ((cb = TAILQ_FIRST(&bkpt->bkpt_cbs)) != NULL) {
        !           203:                didsome = 1;
        !           204:                TAILQ_REMOVE(&bkpt->bkpt_cbs, cb, cb_list);
        !           205:                ret = (*cb->cb_fun)(ps, cb->cb_arg);
        !           206:                free(cb);
        !           207:                switch (ret) {
        !           208:                case BKPT_DEL_STOP:
        !           209:                        stop = 1;
        !           210:                case BKPT_DEL_CONT:
        !           211:                        break;
        !           212:                case BKPT_KEEP_STOP:
        !           213:                        stop = 1;
        !           214:                case BKPT_KEEP_CONT:
        !           215:                        sstep_set(ps, sstep_bkpt_readd, (void *)bkpt->bkpt_pc);
        !           216:                        break;
        !           217:                default:
        !           218:                        errx(1, "unkonwn bkpt_fun return, internal error");
        !           219:                }
        !           220:        }
        !           221:
        !           222:        bkpt_delete(ps, bkpt);
        !           223:
        !           224: sstep:
        !           225:
        !           226:        while ((cb = TAILQ_FIRST(&sstep_cbs)) != NULL) {
        !           227:                didsome = 1;
        !           228:                TAILQ_REMOVE(&sstep_cbs, cb, cb_list);
        !           229:                stop |= (*cb->cb_fun)(ps, cb->cb_arg);
        !           230:                free(cb);
        !           231:        }
        !           232:        ps->ps_flags &= ~PSF_STEP;
        !           233:
        !           234:        return (didsome && !stop);
        !           235: }
        !           236:
        !           237: int
        !           238: cmd_bkpt_add(int argc, char **argv, void *arg)
        !           239: {
        !           240:        struct pstate *ps = arg;
        !           241:        char *ep, *bkpt_name;
        !           242:        reg pc;
        !           243:
        !           244:         if (ps->ps_state != STOPPED && ps->ps_state != LOADED) {
        !           245:                 fprintf(stderr, "Process not loaded and stopped %d\n",
        !           246:                     ps->ps_state);
        !           247:                 return (0);
        !           248:         }
        !           249:
        !           250:        bkpt_name = argv[1];
        !           251:        pc = strtol(bkpt_name, &ep, 0);
        !           252:        if (bkpt_name[0] == '\0' || *ep != '\0' || pc < 1) {
        !           253:                if (sym_lookup(ps, bkpt_name, &pc)) {
        !           254:                        warnx("%s is not a valid pc", bkpt_name);
        !           255:                        return (0);
        !           256:                }
        !           257:        }
        !           258:
        !           259:        if (bkpt_add_cb(ps, pc, bkpt_normal, 0))
        !           260:                warn("Can't set break point");
        !           261:
        !           262:        return (0);
        !           263: }
        !           264:
        !           265: static int
        !           266: sstep_normal(struct pstate *ps, void *arg)
        !           267: {
        !           268:        return (1);     /* stop the command line. */
        !           269: }
        !           270:
        !           271: int
        !           272: cmd_sstep(int argc, char **argv, void *arg)
        !           273: {
        !           274:        struct pstate *ps = arg;
        !           275:
        !           276:         if (ps->ps_state != STOPPED) {
        !           277:                 fprintf(stderr, "Process not loaded and stopped %d\n",
        !           278:                     ps->ps_state);
        !           279:                 return 0;
        !           280:         }
        !           281:
        !           282:        if (sstep_set(ps, sstep_normal, NULL))
        !           283:                warn("Can't set single step");
        !           284:
        !           285:        return (cmd_process_cont(argc, argv, arg));
        !           286: }
        !           287:
        !           288: int
        !           289: sstep_set(struct pstate *ps, int (*fun)(struct pstate *, void *), void *arg)
        !           290: {
        !           291:        struct callback *cb;
        !           292:
        !           293:        cb = emalloc(sizeof(*cb));
        !           294:        cb->cb_fun = fun;
        !           295:        cb->cb_arg = arg;
        !           296:        TAILQ_INSERT_TAIL(&ps->ps_sstep_cbs, cb, cb_list);
        !           297:
        !           298:        ps->ps_flags |= PSF_STEP;
        !           299:
        !           300:        return (0);
        !           301: }