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