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