Annotation of src/usr.bin/pmdb/pmdb.c, Revision 1.2
1.2 ! jason 1: /* $OpenBSD: pmdb.c,v 1.41 2002/03/12 14:24:30 art 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 },
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: }